Chapter 15
Files and Directories

   15.1 Environment File (tex4ht.env)
      General
      For Dos
      Get Script
      Search Env File
   15.2 Locating the TFM Fonts
      Command Line Options
      The Search
      Get Font Env Variables
      Cache Directories
      Default Built-In During Compilation
   15.3 Htf Font Files
   15.4 External File Cache
      Search File in Aux Cache from dot directories
      Store New Auxiliary Cache
   15.5 Export TEX4HTFONTSET for kpathsea
      Background
      Collect Information
      Appending a Segment
      Recording TEX4HTFONTSET
      Debugging info
   15.6 Searching with KPATHSEA
      kpathsea vs kpse-find-file
      HTF Fonts
   15.7 Searching Utilities
      Search Files Listed in Environment File
      Search in Current Directory and Specified Directory
      Search in SubDirectories
      dirent
      Try to Open Path-Named File

15.1 Environment File (tex4ht.env)

  1. Try the file given by the -e switch of tex4ht command.
  2. Search the current directory for one (i.e., open ”tex4ht.env”).
  3. Search the program’s directory (dos/w32)
  4. Home directory (‘~‘ unix; \‘’C:’ dos/w32)
  5. Compiled directory within ENVFILE

First character is a flag character to be consistent with command line options. Undefined flags signal comment lines.

Search along the path: command line file work directory home directory system file.

<..get .env directory from com ln..>
 tex4ht_env_file = p+2;
 -_-_-

<..main’s vars..>+
 char* tex4ht_env_file = (char *) 0;
 char* dos_env_file =
 #if defined(__MSDOS__)
   <.get dos env file.>;
 #endif
 #if !defined(__MSDOS__)
   (char *) 0;
 #endif
 
 -_-_-

In dos we can’t have file names consisted only of the extension ‘.tex4ht’, let alone the length of the extension.

General

<..vars..>+
 static BOOL dump_env_search = FALSE;
 -_-_-

<..trace env search..>
 dump_env_search = TRUE;
 -_-_-

<..find tex4ht.env..>
 {                              U_CHAR  str[PATH_MAX],  *TEX4HTENV;
    <.env file from command switch.>
    <.env file at work dir.>
    if( !dot_file ){
      <.TEX4HTENV env.>
    }
    <.env file at root dir.>
    <.ENVFILE env.>
    <.env from prog dir.>
    <.kpathsea env file.>
    if( !dot_file ) { bad_in_file(<.warn 1.>); } /* give up if no tex4ht.env */
 }
 -_-_-

<..env file from command switch..>
 if( dump_env_search && tex4ht_env_file ){
    (IGNORED) printf("-e: %s?\n", tex4ht_env_file);
 }
 dot_file = tex4ht_env_file?
    f_open_pathed_filename( tex4ht_env_file, READ_TEXT_FLAGS ) : NULL;
 -_-_-

<..env file at root dir..>
 if( !dot_file ){
    if( HOME_DIR ){
       (IGNORED) sprintf(str,<."s/tex4ht.env".>, HOME_DIR);
       if( dump_env_search ){ (IGNORED) printf("%s?\n", str); }
       dot_file = f_open(str,READ_TEXT_FLAGS);
 }  }
 #ifndef DOS_WIN32
    if( !dot_file ){
      if( HOME_DIR ){
         (IGNORED) sprintf(str,"%s/.tex4ht", HOME_DIR);
         if( dump_env_search ){ (IGNORED) printf("%s?\n", str); }
         dot_file = f_open(str,READ_TEXT_FLAGS);
    } }
 #endif
 #if defined(__MSDOS__)
    if( !dot_file ){
       if( dump_env_search ){ (IGNORED) printf("%s?\n", "C:/tex4ht.env"); }
       dot_file = f_open("C:/tex4ht.env",READ_TEXT_FLAGS);
    }
 #endif
 -_-_-

<..env from prog dir..>
 if( !dot_file && dos_env_file){
    if( dump_env_search ){ (IGNORED) printf("%s?\n", dos_env_file); }
    dot_file = f_open( dos_env_file, READ_TEXT_FLAGS );
 }
 -_-_-

<..env file at work dir..>
 if( !dot_file ){
    if( dump_env_search ){ (IGNORED) printf("%s?\n", "tex4ht.env"); }
    dot_file = f_open("tex4ht.env", READ_TEXT_FLAGS);
 }
 #ifndef DOS_WIN32
    if( !dot_file ){
       if( dump_env_search ){ (IGNORED) printf("%s?\n", ".tex4ht"); }
       dot_file = f_open(".tex4ht", READ_TEXT_FLAGS);
       if( dot_file ){
          printf("(%s)\n", ".tex4ht");
    }  }
 #endif
 -_-_-

<..ENVFILE env..>
 #ifdef ENVFILE
    if( !dot_file ){
       if( dump_env_search ){ (IGNORED) printf("ENVFILE: %s?\n", ENVFILE); }
       dot_file = f_open_pathed_filename( ENVFILE,READ_TEXT_FLAGS);
    }
 #else
    if( dump_env_search ){
         (IGNORED) printf("tex4ht compiled without ENVFILE\n");
    }
 #endif
 -_-_-

<..TEX4HTENV env..>
 TEX4HTENV = getenv("TEX4HTENV");
 if( TEX4HTENV ){
    if( dump_env_search ){
         (IGNORED) printf("TEX4HTENV: %s?\n", TEX4HTENV); }
    dot_file = f_open_pathed_filename(TEX4HTENV,READ_TEXT_FLAGS);
 } else {
    if( dump_env_search ){
         (IGNORED) printf("getenv(\"TEX4HTENV\")=\n");
 }  }
 -_-_-

<..h-defines..>+
 #ifndef ENVFILE
 
 #endif
 -_-_-

<.."s/tex4ht.env"..>
 #if defined(__DJGPP__)
   is_forward_slash(HOME_DIR)?  "%s/tex4ht.env" :  "%s\\tex4ht.env"
 #else
   "%s/tex4ht.env"
 #endif
 -_-_-

<..warn 1..>
 #ifdef  DOS_WIN32
    "tex4ht.env"
 #else
    "tex4ht.env | .tex4ht"
 #endif
 -_-_-

For Dos

One last remark about the source: I have implemented a routine that changes the functionality of searching for tex4ht.env a bit. DOS organises programs differently than Unix; it is convention to place the program and all related files, including configuration files, in a dedicated directory. In addition, DOS (being single-user) doesn’t have home directories. Knowing this, the best way to find the tex4ht.env file is:

  1. Search the current directory for one (i.e., open ”tex4ht.env”).
  2. Search the program’s directory
  3. Give up (no point in checking the root directory).

Under DOS, argv[0] usually includes the full path to the program - even if it wasn’t typed in. This can be used to find the program’s own directory, and hence the configuration file. I’ve implemented this already as follows:

<..get dos env file..>
 get_env_dir(argv[0])
 -_-_-

<..functions..>+
 #if defined(__MSDOS__)
 <.get tex4ht.env in dos.>
 #endif
 -_-_-

<..get tex4ht.env in dos..>
 
 static char *get_env_dir(progname)
       U_CHAR *progname
 
 ;{    int  i;
       U_CHAR *p;
   if(! progname || ! *progname)  return NULL;                Safety 
   i = (int) strlen((char *) progname);
   while( (progname[--i] != (int) dir_path_slash(progname) )
           && (i > 0) ) ;                              Search for dir
   if(i == 0)  return NULL;                        Not found? Give up
   p = (char *) malloc(i+12);
   if(p == NULL)  return NULL;      Space for new extention after dot
   strncpy(p, progname, i+1);                        Copy up to slash
   (IGNORED) strcpy((char *) &p[i+1], "tex4ht.env"); Append new extention
   return p;
 }
 -_-_-

The 12 above is for accomodating tex4ht.env.

Get Script

Options

s
Block of lines starting with the same character: s (set format of script commands), e.g., ‘s--- needs --- %%1.idv[%%2] ==> %%3 ---
b
Begin-of-characters/end-of-figures comment, e.g., ‘b--- characters ---
g
Gif extension, e.g., ‘g.gif
a
Font alias, e.g., ‘acmtex cmtt
t
Directory of tfm fonts, e.g., ‘t/n/candy/0/tex/teTeX/texmf/fonts/tfm/!
i
Directory of htf fonts, e.g., ‘i/n/gold/5/gurari/tex4ht.dir/ i/n/gold/5/gurari/tex4ht.dir/ht-fonts/iso88591/!’.

Priority (the easier to change, the higher in priority).

<..header functions..>+
 static char* get_script( ARG_III(char *, const U_CHAR *, int) );
 -_-_-

<..functions..>+
 
 static char* get_script(name, inln,x)
      char * name;
      const U_CHAR * inln;
      int x
 
 ;{
    if( !name )
    {                U_CHAR  str[256], *ch;
       (IGNORED) fseek(dot_file, 0L, <.abs file addr.>);
       if( search_dot_file( x ) ){
            <.read x-script from dot file.>
       } else  {(IGNORED)  strcpy((char *) str, inln); }
       ch = m_alloc(char, (int) strlen((char *) str)+2);
       (IGNORED) strcpy((char *) ch, (char *) str);
       return ch;
    }else return name;
 }
 -_-_-

We allocate extra character for possible addition of ‘%’ at end of string.

<..read x-script from dot file..>
 ch = str;  str[254] = ’\0’;
 do{                                       int int_ch;
   while((*(ch++) = (char)
                         (int_ch = (int) getc(dot_file))
         )       != ’\n’){
     if( int_ch == EOF ){ *(ch-1)=’\n’;  break; }
     if( str[254] ){ warn_i_int(33, x);  break; }
   }
 }while( (int) getc(dot_file) == x );
 *ch = ’\0’;
 -_-_-

The ‘if( *(ch-1) == EOF ){...}’ is for the case that the last line not terminates with a return.

Search Env File

<..header functions..>+
 static BOOL search_dot_file( ARG_I( int) );
 -_-_-

<..functions..>+
 
 static BOOL search_dot_file( ch )
     int ch
 ;{  int chr;
 
   while( TRUE ){
     chr = getc(dot_file);
     if( chr == ch ){ return TRUE; }
     if( chr == ’<’ ) {
       <.skip non -c env segments.>
       continue;
     }
     if( chr == ’\n’ ){ continue; }
     do
        if( chr == EOF ) return FALSE;
     while( (chr = getc(dot_file)) != ’\n’ );
 } }
 -_-_-

<..skip non -c env segments..>
                          U_CHAR match[256];
                          int i;
 for( i = 0; (chr != ’\n’) && (chr != EOF ) ; i++){
   chr = (int) getc(dot_file);
   match[i] = (U_CHAR) chr;
 }
 match[i-1] = ’\0’;
 if( match[0] != ’/’ ){
                          BOOL env_skip;
   for( i = 0;
        (match[i] != ’>’) && (match[i] != ’\n’) && (match[i] != EOF );
        i++){}
   if( match[i] == ’>’ ){  match[i] = ’\0’; }
   <.env-skip = skip segment match[1].>
   if( env_skip ){
      <.skip env segment.>
 } }
 -_-_-

<..skip env segment..>
                          U_CHAR cur_block[90];
                          BOOL status;
 (IGNORED) strcpy((char *)  cur_block, (char *) match);
 status = FALSE;
 while( !status && (chr != EOF) ){
   chr = ’x’;
   for( i = 0; (chr != ’\n’) && (chr != EOF ) ; i++){
     chr = (int) getc(dot_file);
     match[i] = (U_CHAR) chr;
   }
   match[i-1] = ’\0’;
   for(i=0; match[i]!=’\0’; i++){
     if( match[i] == ’>’ ){ break; }
   }
   if( (match[0] == ’<’) && (match[1] == ’/’)
                         && (match[i] == ’>’) ){
     match[i]=’\0’;
     status = eq_str(match+2, cur_block);
   } else { status = FALSE; }
 }
 -_-_-

<..defines..>+
 struct env_c_rec{
   char *option;
   struct env_c_rec  *next;
 };
 -_-_-

<..vars..>+
 static struct env_c_rec *envChoice
        = (struct env_c_rec*) 0;
 -_-_-

<..env blocks selector..>
 struct env_c_rec *temp = (struct env_c_rec*)
                    m_alloc(struct env_c_rec, (int) 1);
 temp->option = p+2;
 temp->next = envChoice;
 envChoice = temp;
 -_-_-

<..env-skip = skip segment match[1]..>
 if( envChoice == (struct env_c_rec*) 0  ){
   env_skip = !eq_str(match, "default" );
 } else {
                struct env_c_rec *p;
   env_skip = TRUE;
   for( p=envChoice; p!=(struct env_c_rec*) 0 ; p = p->next ){
     if( eq_str(match, p->option ) ){ env_skip = FALSE; }
 } }
 -_-_-

15.2 Locating the TFM Fonts

Flag ‘t’ identifies font directories. Command line (can be multiple) work directory dot file system directory.

Command Line Options

<..get tfm font dir from com ln..>
 com_dir(p);  fontdir[fontdir_count++] = p+2;
 -_-_-

The ‘access’ function returns 0 if the path is fine; -1 for error.

<..vars..>+
 static U_CHAR  *fontdir[MAXFDIRS];
 static int fontdir_count = 0;
 -_-_-

What the use of the following? Do we wants to make it h-defines.

<..defines..>+
 #ifndef MAXFDIRS
 #define MAXFDIRS 100
 #endif
 -_-_-

Also, check how many directories and fonts are used. ‘tex4ht.log’ claims 55 fonts with 255 as limit.

The Search

struct cache_font_rec *cur_cache_font; ?

<..search dirs for font..>
 {                           int  i; 
    font_file = NULL;
    (IGNORED) sprintf(file_name, "%s.tfm", new_font_name);
    <.if kpathsea tfm files else.>
       <.search font in cache dirs.>
       if( !font_file ){                                     int  i;
          for( i = fontdir_count; i--; ){
            if( (font_file =  search_file_base(file_name, fontdir[i],
                                          READ_BIN_FLAGS, tfm_dirs))
                != NULL )  break;  }
       }
       if( !font_file ) font_file = f_open(file_name, READ_BIN_FLAGS);
       if( !font_file && dot_file )
           font_file = search_in_dot_file( ’t’, file_name,
                         READ_BIN_FLAGS, tfm_dirs);
       <.search TFMDIR.>
    <.endif kpathsea tfm files.>
 }
 -_-_-

KPATHSEA has a database LS-R which corresponds to a ‘ls -R *’ listing of files and the directories including them. This allow for a quick search of files within the image of the directory stored within the database, instead of live search in the directories themselve which consume disk access time.

<..search TFMDIR..>
 #ifdef TFMDIR
    if( !font_file )
       font_file = search_file_base(file_name, TFMDIR,
                                READ_BIN_FLAGS, tfm_dirs);
 #endif
 -_-_-

<..h-defines..>+
 #ifndef TFMDIR
 
 #endif
 -_-_-

Get Font Env Variables

The environment variables, if defined, hold a sequence of directory names. Each directory name can be an absolute address, or relative to the home directory (signaled by the prefix ‘~’). The directories must be separated by a distinguished character, which must also act as delimiter at the start and the end of the string.

<..check env font variables..>
 #ifndef KPATHSEA
 tfm_dirs = get_env_var("TEX4HTTFM");
 #endif
 htf_dirs = get_env_var("TEX4HTHTF");
 -_-_-

<..header functions..>+
 static struct env_var_rec * get_env_var( ARG_I(const char *) );
 -_-_-

<..functions..>+
 
 static struct env_var_rec * get_env_var( env_var )
     const char *env_var
 ;{                U_CHAR   *TEX4HTTFM,  *from;
                   struct env_var_rec *tfm_dirs, *p;
                   int env_var_len;
    tfm_dirs = (struct  env_var_rec *) 0;
    TEX4HTTFM = getenv( env_var );
    if( TEX4HTTFM ){
       env_var_len = (int) strlen((char *) TEX4HTTFM);
       if ( *TEX4HTTFM == *(TEX4HTTFM + env_var_len - 1 ) ){
          from = TEX4HTTFM + env_var_len - 1;
          *from = ’\0’;
          do{
            from--;
            if( *from == *TEX4HTTFM ){   char * base;
               *from = ’\0’;
               base = from + 1;
              <.verify env var dir.>
              if( base ){
                <.add env var dir.>
            } }
          } while (from > TEX4HTTFM );
       } else {  warn_i_str2( 49, env_var, TEX4HTTFM); }
     }
     return tfm_dirs;
 }
 -_-_-

We preseve the order of the directories founnd in the environment variables.

<..add env var dir..>
 p = m_alloc(struct env_var_rec, 1);
 p->next = tfm_dirs;
 p->base = base;
 tfm_dirs = p;
 -_-_-

<..verify env var dir..>
 {                         U_CHAR *str;
   if( *(from+1) == ’~’ ){
      if( HOME_DIR ){
          str = m_alloc(char, strlen((char *) HOME_DIR)+strlen((char *) base));
          (IGNORED) sprintf(str,"%s%s", HOME_DIR, base+1);
          if( access(str,F_OK) ) {
             warn_i_str2(49, env_var, str); base = NULL; }
          free((void *)  str);
      } else {
          if( access(base,F_OK) ) {
             warn_i_str2(49, env_var, base); base = NULL; }
      }
    } else {
      if( access(base,F_OK) )  {
         warn_i_str2(49, env_var, base); base = NULL; }
 }  }
 -_-_-

<..scan fonts vars..>+
 #ifndef KPATHSEA
 struct env_var_rec *tfm_dirs;
 #endif
 struct env_var_rec *htf_dirs;
 -_-_-

<..types..>+
 struct env_var_rec{  char* base;
                      struct env_var_rec *next;     };
 -_-_-

Cache Directories

<..search font in cache dirs..>
 for( cur_cache_font = cache_font;
      cur_cache_font;
      cur_cache_font = cur_cache_font->next )
   if( (font_file = search_file(file_name,
                                cur_cache_font->dir,
                                READ_BIN_FLAGS))
       != NULL)  break;
 -_-_-

<..put dir in cache..>
 {     int found;
    found = FALSE;
    for( cur_cache_font = cache_font;
         cur_cache_font;
         cur_cache_font = cur_cache_font->next )
    { found = found || eq_str(cur_cache_font->dir, dir ) ;
      if( found ) break;  }
    if( !found ){
       cur_cache_font = m_alloc(struct cache_font_rec, 1);
       <.init new cache list.>
       cur_cache_font->dir = m_alloc(char, n+1);
       (IGNORED) strcpy((char *) cur_cache_font->dir, dir);
       if( !cache_font ){
          cur_cache_font->next = cache_font;
          cache_font = cur_cache_font;
       } else if ( gt_str(cache_font->dir, dir) ) {
          cur_cache_font->next = cache_font;
          cache_font = cur_cache_font;
       } else {
                             struct cache_font_rec *  after_cache_font;
          after_cache_font = cache_font;
          while( after_cache_font->next ){
            if ( gt_str(after_cache_font->next->dir, dir) ) { break; }
            after_cache_font = after_cache_font->next;
          }
          cur_cache_font->next = after_cache_font->next;
          after_cache_font->next = cur_cache_font;
 }  }  }
 -_-_-

<..free html font memory..>+
 while( (cur_cache_font = cache_font) != (struct cache_font_rec *)0 ){
    cache_font = cache_font->next;
    free((void *) cur_cache_font->dir );
    free((void *) cur_cache_font );        }
 -_-_-

<..vars..>+
 static struct cache_font_rec *cache_font,  *cur_cache_font;
 -_-_-

<..init scan fonts vars..>+
 cache_font = (struct cache_font_rec *) 0;
 cur_cache_font = (struct cache_font_rec *) 0;
 -_-_-

<..types..>+
 struct cache_font_rec{  char* dir;
                         struct cache_file_rec * cache_file;
                         struct cache_font_rec* next;     };
 struct cache_file_rec{  struct cache_file_rec* next;
                         U_CHAR *                 file;     };
 -_-_-

Default Built-In During Compilation

On my HP the standard TeX fonts are in the directory /usr/local/tex/lib/texmf/fonts/public/cm/tfm/, and the standard latex fonts are in /usr/local/tex/lib/texmf/fonts/public/latex/tfm/, on my SUN the directory is ???.

We also might want to put the current directory in.

The function ‘int access(const U_CHAR *pathname, int mode)’, and the mode ‘F_OK’ that tests for the existence of file, are defined in the following directory. The function returns 0 if ok and -1 on error .

Where access comes from in dos? in <io.h>

<..h-include..>+
 #ifndef F_OK
 #ifdef DOS_WIN32
 #define  F_OK 0                does file exist 
 #endif
 #ifndef KPATHSEA
 #ifndef DOS_WIN32
 #define HAVE_UNISTD_H
 #endif
 #endif
 #endif
 #ifdef HAVE_IO_H
 #include <io.h>
 #endif
 #ifndef KPATHSEA
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 #endif
 -_-_-

15.3 Htf Font Files

Search along the path: command line switch ’i’ directory work directory directories specified in tex4ht.env (switch ’i’ and aliased ’a’) system directory specified in HTFDIR. [more]

<..file = .htf file..>
 {                              U_CHAR name[256];
    (IGNORED) sprintf(name, "%s.htf", new_font_name);
    <.search file in htf locations.>
    if( file ){ <.check name decomposition.> }
 }
 -_-_-

<..search file in htf locations..>
    file = NULL;
    <.search htf font along cmd switches.>
    if( !file ){
       if( ((file = f_open(name, READ_TEXT_FLAGS)) == NULL) && dot_file )
          file = search_in_dot_file( ’i’, name, READ_TEXT_FLAGS, htf_dirs);
 #ifdef HTFDIR
       if( !file )  file = search_file_base(name, HTFDIR,
                                                READ_TEXT_FLAGS, htf_dirs);
 #endif
       <.file = kpathsea .htf file.>
    }
 -_-_-

<..types..>+
 struct htf_com_rec{  char* name;
                      struct htf_com_rec* next;     };
 -_-_-

<..main’s vars..>+
 struct htf_com_rec* htf_font_dir = (struct htf_com_rec *) 0;
 -_-_-

<..get htf font dir from com ln..>
    com_dir(p);
    {
                          struct htf_com_rec *q, *t;
    q = m_alloc( struct htf_com_rec, 1);
    q->name = p+2;
    q->next = (struct htf_com_rec *) 0;
    if(  htf_font_dir ){
      t = htf_font_dir;
      while( t->next ){ t = t->next; }
      t->next = q;
    } else {
      htf_font_dir = q;
    }
 }
 -_-_-

<..header functions..>+
 static void com_dir( ARG_I(char*) );
 -_-_-

<..functions..>+
 
 static void com_dir(p)
      char* p
 ;{   int i;   U_CHAR   str[256];
   (IGNORED) strcpy((char *)  str, (char *) p+2 );
   i = (int) strlen((char *) str) - 1;
   if( str[i] == ’!’ )  str[i] = ’\0’;
 }
 -_-_-

<..search htf font along cmd switches..>
 {
                                struct htf_com_rec *p;
    p = htf_font_dir;
    while( p ){
       file =  search_file_base(name, p->name, READ_TEXT_FLAGS, htf_dirs);
       if( file ){
 #ifndef KPATHSEA
          tex4ht_fls = TRUE;
 #endif
          break;
       }
       p = p->next;
    }
 }
 -_-_-

<..h-defines..>+
 #ifndef HTFDIR
 
 #endif
 -_-_-

Example ‘ #define HTFDIR "/n/gold/5/gurari/tex4ht-fonts.dir/"

15.4 External File Cache

<..init new cache list..>
 cur_cache_font->cache_file = (struct cache_file_rec *) 0;
 -_-_-

<..store filename in cache..>
 {
              struct cache_file_rec *file_rec, *prev_file_rec;
   prev_file_rec = (struct cache_file_rec *) 0;
   file_rec = cur_cache_font->cache_file;
   while( file_rec ) {
     if( !gt_str(name,file_rec->file) ) break;
     prev_file_rec = file_rec;
     file_rec = file_rec->next;
   }
   {
                          struct cache_file_rec * file_entry;
                          BOOL flag;
     flag = TRUE;
     if( file_rec ) {
       if( eq_str(name,file_rec->file) ){ flag = FALSE; }
     }
     if( flag ) {
       <.insert file name.>
     }
   }
 }
 -_-_-

<..insert file name..>
 file_entry = m_alloc(struct cache_file_rec, 1);
 file_entry->file = m_alloc(char, strlen(name)+1);
 (IGNORED) strcpy((char *) file_entry->file, name);
 if( ! cur_cache_font->cache_file ){
   cur_cache_font->cache_file = file_entry;
  file_entry->next = (struct cache_file_rec *) 0;
 } else if( !prev_file_rec ){
    file_entry->next = cur_cache_font->cache_file;
    cur_cache_font->cache_file = file_entry;
 } else {
    file_entry->next = prev_file_rec->next;
    prev_file_rec->next = file_entry;
 }
 -_-_-

Search File in Aux Cache from dot directories

The cache file holds directory names and file names. Directory names are preceded by a space, and file names start at column one.

 /usr/local/share/texmf/tex4ht/ht-fonts/iso8859/1/ae 
ae.htf 
aecsc.htf 
 /usr/local/share/texmf/tex4ht/ht-fonts/iso8859/1/cm 
cmcsc.htf 
cmr.htf 
 /usr/local/share/texmf/tex4ht/ht-fonts/unicode/cm 
cmmi.htf 

We traverse the auxiliary cache file, recording on the way the last found directory. Upon finding a match on file name, we check the last recorded directory against the directories mentioned in the environment file. If a match is found also there, we open the appropriate file.

<..search font in cache files..>
                  U_CHAR cache_dir[256], dot_dir[256], *p, *q;
                  BOOL flag;
                  int  n,  ch;
 (IGNORED) fseek(cache_files, 0L, <.abs file addr.>);
 ch = (int) getc(cache_files);
 while ( ch != EOF ){
   if ( ch ==   ) { <.cache-dir = cache record.> }
   else { <.flag = (file == cache record).>
     if( flag ){
        <.flag = (cache-dir == env-dir).>
        if( flag ){ <.open file and, if success, return.> }
   } }
   if ( ch != EOF ){ ch = (int) getc(cache_files); }
 }
 -_-_-

<..cache-dir = cache record..>
 q = cache_dir;
 do
   *(q++) = ch = (int) getc(cache_files);
 while( (ch !=’\n’) && (ch != EOF) );
 *(q-1 - (*(q-2) == <.directory ’/’.>)
 #ifdef DOS_WIN32
       - (*(q-2) == ’/’)
 #endif
  ) = ’\0’;
 -_-_-

<..flag = (file == cache record)..>
 p = name;  flag = FALSE;
 while( *(p++) == ch ){
   ch = (int) getc(cache_files);
 }
 if( (*(p-1) == ’\0’) && ((ch == ’\n’) || (ch == EOF)) ){ flag = TRUE; }
 else{
   while( (ch != ’\n’) && (ch != EOF) ) {  ch = (int) getc(cache_files); }
 }
 -_-_-

<..flag = (cache-dir == env-dir)..>
 flag = FALSE;
 (IGNORED) fseek(dot_file, 0L, <.abs file addr.>);
 while( search_dot_file( typ ) && !flag ){        U_CHAR *q, save_ch;
                                                  int  n, m;
   q = dot_dir;
   do
      *(q++) = ch = (int) getc(dot_file);
   while( (ch !=’\n’) && (ch != EOF) );
   flag = *(q - 2) = ’!’;
   q -= (flag? 2 : 1);
   *(q - (*(q-1) == <.directory ’/’.>)
 #ifdef DOS_WIN32
       - (*(q-1) == ’/’)
 #endif
    ) = ’\0’;
   if( (n = strlen((char *) dot_dir)) > (m = strlen((char *) cache_dir)) ){ flag = FALSE; }
   else {
     save_ch = *(cache_dir + n);
     *(cache_dir + n) = ’\0’;
     flag = eq_str(dot_dir,cache_dir) && ( flag || (m == n) );
     *(cache_dir + n) = save_ch;
   }
 }
 -_-_-

<..open file and, if success, return..>
 n = (int) strlen((char *) cache_dir);
 cache_dir[n] = dir_path_slash(cache_dir);
 cache_dir[n+1] = ’\0’;
 (IGNORED) strcat((char *) cache_dir, (char *) name);
 -_-_-

<..BROKEN..>
 if( (file = f_open(cache_dir,flags)) == NULL ) {
    warn_i_str( 47, cache_dir);
 } else {
    return file;
 }
 -_-_-

Store New Auxiliary Cache

<..set new cache file..>
 if( tex4ht_fls ){
                FILE *in_file, *out_file;
                U_CHAR temp_file[256];
    <.set temp file.>
    <.backup cache file.>
    if( (out_file = fopen(tex4ht_fls_name, WRITE_TEXT_FLAGS)) == NULL )
    {  bad_in_file(tex4ht_fls_name);
    } else {
       if( (in_file = fopen(temp_file, READ_TEXT_FLAGS)) != NULL ){
         <.output into new cache.>
         (IGNORED) fclose(in_file);
       }
       (IGNORED) fclose(out_file);
 }  }
 -_-_-

<..set temp file..>
 (IGNORED) strcpy((char *) temp_file, (char *) job_name);
 temp_file[job_name_n] = ’\0’;
 temp_file[job_name_n-1] = ’p’;
 temp_file[job_name_n-2] = ’m’;
 temp_file[job_name_n-3] = ’t’;
 -_-_-

<..vars..>+
 #ifndef KPATHSEA
 static BOOL tex4ht_fls = FALSE;
 static char *tex4ht_fls_name = (char *) 0;
 #endif
 -_-_-

<..cat /..>
 #if defined(DOS_WIN32) || defined(__DJGPP__)
   (is_forward_slash(files_cache)?  "/" : "\\" )
 #else
   "/"
 #endif
 -_-_-

<..get dir of tex4ht.fls..>
 {                    U_CHAR *p;
    if( !tex4ht_fls_name ){
       tex4ht_fls_name = p = files_cache;
       (IGNORED) fseek(dot_file, 0L, <.abs file addr.>);
       if ( search_dot_file( ’l’ ) ){
         do
            *(p++) = ch = (int) getc(dot_file);
         while( (ch !=’\n’) && (ch != EOF) );
         p--;       *p = ’\0’;
       } else { (IGNORED) strcpy((char *) p,
 (char *)           getenv("TEX4HTWR")?  "~~/tex4ht.fls" : "tex4ht.fls");
       }
    }
    <.relative tex4ht.fls addr.>
 }
 -_-_-

<..relative tex4ht.fls addr..>
 if( *tex4ht_fls_name == ’~’ ){
    tex4ht_fls_name = abs_addr(tex4ht_fls_name,getenv("TEX4HTWR"));
 }
 -_-_-

<..relative tex4ht.fls addrNO..>
 if( *tex4ht_fls_name == ’~’ ){
                   <.fls temp var.>
    if( HOME_DIR ){
       (IGNORED) strcpy((char *) p, (char *) tex4ht_fls_name+1);
       (IGNORED) sprintf(files_cache,"%s%s", HOME_DIR, p);
    } else {
       (IGNORED) strcpy((char *) files_cache, "tex4ht.fls");
    }
    tex4ht_fls_name = files_cache;
 }
 -_-_-

<..fls var..>
 U_CHAR files_cache[PATH_MAX];
 -_-_-

<..fls temp var..>
 U_CHAR p[PATH_MAX];
 -_-_-

<..vars..>+
 static U_CHAR *HOME_DIR;
 -_-_-

<..main’s init..>+
 HOME_DIR = getenv("HOME");
 -_-_-

We might want more than one version of ‘tex4ht.fls’, for different combinations of subtrees of htf fonts.

<..get tex4ht.fls from com ln..>
 #ifndef KPATHSEA
 tex4ht_fls_name = p+2;
 #endif
 -_-_-

<..backup cache file..>
 if( (out_file = fopen(temp_file, WRITE_TEXT_FLAGS)) == NULL )
 {   bad_in_file(temp_file);
 } else {
    if( (in_file = fopen(tex4ht_fls_name, READ_TEXT_FLAGS)) != NULL ){
                                                       int ch;
       while( (ch = getc(in_file)) != EOF ) {
          (IGNORED) putc( ch, out_file );
       }
       (IGNORED) fclose(in_file);
    }
    (IGNORED) fclose(out_file);
 }
 -_-_-

<..output into new cache..>
               U_CHAR dir[255], prev_dir[255], file[255], *p;
               int ch;
               BOOL is_dir;
               struct cache_file_rec *file_rec, *prev_file_rec;
 cur_cache_font = cache_font;
 ch = ’n’;  prev_dir[0] = ’\0’;
 while( ch != EOF ){
    ch = getc(in_file);
    is_dir = (ch ==  ’);
    p = is_dir? dir : file;
    while( ch != ’\n’ ) {
      if( ch == EOF ) break;
      if( ch !=   ) { *p++ = ch; }
      ch = getc(in_file);
    }
    *p = ’\0’;
    if( is_dir && (dir[0] != ’\0’) ){
       <.output smaller internal directories.>
       (IGNORED) fprintf(out_file," %s\n", dir);
       (IGNORED) strcpy((char *) prev_dir, (char *) dir);
    } else if( !is_dir && (file[0] != ’\0’) ){
       <.output smaller internal files.>
       (IGNORED) fprintf(out_file,"%s\n", file);
    }
 }
 <.output remainder of internal cache.>
 -_-_-

<..output smaller internal directories..>
 while( cur_cache_font != (struct cache_font_rec *)0 ){
  if( gt_str(dir,cur_cache_font->dir) ){
     <.cache directory in external memory.>
  } else break;
  cur_cache_font = cur_cache_font->next;
 }
 -_-_-

<..cache directory in external memory..>
 file_rec = cur_cache_font->cache_file;
 if( file_rec ){
    if( !eq_str( prev_dir, cur_cache_font->dir) ){
       (IGNORED) fprintf(out_file, " %s\n", cur_cache_font->dir);
       (IGNORED) strcpy((char *) prev_dir, (char *) dir);
    }
    cur_cache_font->cache_file = (struct cache_file_rec *) 0;
    while( file_rec ) {
      prev_file_rec = file_rec;
      file_rec = file_rec->next;
      (IGNORED) fprintf(out_file, "%s\n",  prev_file_rec->file);
      free((void *) prev_file_rec );
    }
 }
 -_-_-

<..output smaller internal files..>
 if( cur_cache_font != (struct cache_font_rec *)0 ){
  if( eq_str(dir,cur_cache_font->dir) ){
     file_rec = cur_cache_font->cache_file;
     while( file_rec ) {
       if( gt_str(file_rec->file,file) ){ break; }
       else if( gt_str(file,file_rec->file) ){
           (IGNORED) fprintf(out_file, "%s\n", file_rec->file);
       }
       prev_file_rec = file_rec;
       file_rec = file_rec->next;
       free((void *) prev_file_rec );
     }
     cur_cache_font->cache_file = file_rec;
  }
 }
 -_-_-

<..output remainder of internal cache..>
 while( cur_cache_font != (struct cache_font_rec *)0 ){
    <.cache directory in external memory.>
    cur_cache_font = cur_cache_font->next;
 }
 -_-_-

<..vars..>+
 #ifndef KPATHSEA
 static FILE* cache_files;
 #endif
 -_-_-

<..open old cache file..>
 cache_files = f_open(tex4ht_fls_name, READ_BIN_FLAGS);
 -_-_-

<..close old cache file..>
 if( cache_files != (FILE *) 0 ){  (IGNORED) fclose(cache_files); }
 -_-_-

15.5 Export TEX4HTFONTSET for kpathsea

Background

A system call similar to ‘TEX4HTFONTSET={...}; export TEX4HTFONTSET’ is issued for ordering searches of htf fonts by kpathsea.

The system call assumes a pattern of the form ‘.....%%12...’ in the argument -DTEX4HTFONTSET provided to the compilation of tex4ht. If none is provided, a default pattern is assumed.

To allow also opposite order of search, the code should modify to answer also for patterns of the form ‘.....%%21...’.

The i-records (provided e.g., in tex4ht.env) are assumed to refer to 
paths relative to the ht-fonts directory.  If a record happens to 
include the substring ‘/ht-fonts/’, then only the portion that follows 
that substring is considered. 
 
For instance, the records 
 
   i~/tex4ht.dir/ht-fonts/iso8859/1/! 
   i~/tex4ht.dir/ht-fonts/alias/! 
 
are equivalent to 
 
   iiso8859/1 
   ialias 
 
 
 
If i-records are not provided, a ht-like script may contain 
a call similar to 
 
   test -z "$3" || TEX4HTFONTSET=$3;export TEX4HTFONTSET 
on unix and 
 
   set TEX4HTFONTSET={%%12} 
 
on windows. 
 
In texmf.cnf:  TEX4HTFONTSET=iso8859/1,alias 
 
 
   TEX4HTFONTSET={iso8859/1,alias}; export TEX4HTFONTSET 
   set TEX4HTFONTSET={iso8859/1,alias} 

The user has two options of hand-made entries: i-records and exportation. Tex4ht assumes the following priority schema:

  1. Entries provided in i-records (e.g., within tex4ht.env)
  2. Entries exported by TEX4HTFONTSET from scripts (e.g., in htlatex)
  3. Entries hard wired in TEX4HTFONTSET within texmf.cnf (In such a case, i-records should not be provided. That is, in the default setting, i-records should not be provided in tex4ht.env, within tex4ht.c, or over tex4ht.c (in the ht... scripts). Users may add such records, but the default installations should not contain i-records.)

xputenv() is a kpathsea routine for writing environment variables

Collect Information

<..export TEX4HTFONTSET..>
 #ifdef KPATHSEA
 {           char str [256], *export_str, *postfix;
    export_str = m_alloc(char, 1);
    *export_str = ’\0’;
    <.set the exported list.>
    if( (int) strlen((char *) export_str) > 0 ){
       (IGNORED) strcpy((char *) str, "%%12");
       export_str = (char *) r_alloc((void *) export_str,
           (int) strlen((char *) export_str) + (int) strlen((char *) str) +  1 );
       postfix = str - 1;
       while( *(++postfix) != ’\0’ ){
         if( (*postfix==’%’)     && (*(postfix+1)==’%’) &&
             (*(postfix+2)==’1’) && (*(postfix+3)==’2’) ){
           *postfix=’\0’; postfix += 4; break;
       } }
       if( (int) strlen((char *) export_str) != 0 ){
         <.insert export into pattern.>
         <.system call for export.>
       }
    }
    <.recording TEX4HTFONTSET.>
    free((void *) export_str);
    <.debug info about TEX4HTFONTSET.>
 }
 #endif
 -_-_-

<..insert export into pattern..>
 {                       char *from_ch;
                         int i, n, m;
   n = (int) strlen((char *) str);
   m = (int) strlen((char *) export_str);
   from_ch = export_str + m;
   for( i = 0; i<=m; i++){
     *(from_ch + n) = *(from_ch);
     from_ch--;
   }
   for( i = 0; i<n; i++){
     export_str[i] = str[i];
   }
   (IGNORED) strcat((char *) export_str, (char *) postfix);
 }
 -_-_-

An entry similar to the following one is assumed in texmf.cnf.

TEX4HTINPUTS=.;$TEXMF/tex4ht/base//;$TEXMF/tex4ht/ht-fonts/{$TEX4HTFONTSET}// 

<..system call for export..>
 {                     U_CHAR * q;
   if( dump_htf_search ) {                       U_CHAR *p, *q;
      <.trace TEX4HTFONTSET.>
   }
   q = (U_CHAR *) kpse_var_value( "TEX4HTFONTSET" );
   if( q ){
      xputenv("TEX4HTFONTSET", export_str);
      if( dump_htf_search ){
         (IGNORED) printf("setting TEX4HTFONTSET={%s}\n", export_str);
      }
   } else if( dump_htf_search ) {
      warn_i_str( 50, "TEX4HTFONTSET for kpathsea" );
   }
 }
 -_-_-

<..set the exported list..>
 {
       struct htf_com_rec *q;
   q = htf_font_dir;
   while( q != (struct htf_com_rec *) 0 ){
     (IGNORED) strcpy((char *) str, (char *) q->name);
     export_htf( &export_str, str );
     q = q->next;
 } }
 (IGNORED) fseek(dot_file, 0L, <.abs file addr.>);
 while ( search_dot_file( ’i’ ) ){
            int ch;
            char* p;
   p = str;
   do {
      ch = (int) getc(dot_file);
      if( ch != EOF) { *(p++) = ch;}
   } while( (ch !=’\n’) && (ch != EOF) );
   *p = ’\0’;
   export_htf( &export_str, str );
 }
 #ifdef HTFDIR
   (IGNORED) strcpy((char *) str, (char *) HTFDIR);
     export_htf( &export_str, str );
 #endif
 <.pre assigned TEX4HTFONTSET.>
 -_-_-

<..pre assigned TEX4HTFONTSET..>
 {                    U_CHAR * q;
   q = (U_CHAR *) kpse_var_value( "TEX4HTFONTSET" );
   if( q ){
     if( (int) strlen((char *) q) > 0 ){
         export_str = (char *) r_alloc((void *) export_str,
             (int) strlen((char *) export_str) + (int) strlen((char *) q) +  2);
         if( (int) strlen((char *) export_str) > 0 ){
              (IGNORED) strcat((char *) export_str, ",");
         }
         (IGNORED) strcat((char *) export_str, (char *)  q);
 } } }
 -_-_-

Appending a Segment

<..header functions..>+
 #ifdef KPATHSEA
 static void export_htf( ARG_II(char**, char[]) );
 #endif
 -_-_-

<..functions..>+
 #ifdef KPATHSEA
 
 static void export_htf(export_str, str)
      char** export_str ;
      char str[]
 ;{        int i;
           char* p;
           BOOL found;
   i = (int) strlen((char *) str) - 1;
   while( (i>=0) && (str[i] == ’\n’) ){  str[i--] = ’\0’;  }
   while( (i>=0) && (str[i] ==  ’) ) {  str[i--] = ’\0’;  }
   if( (i>=0) && (str[i] == ’!’) ){      str[i--] = ’\0’;  }
   if( (i>=0) && ((str[i] == ’/’) || (str[i] == ’\\’)) ){
                                         str[i--] = ’\0’;  }
   i -= 8; found = FALSE;
   while( --i>=0 ){
     if( ((str[i] == ’/’) || (str[i] == ’\\’)) && (str[i+1]== ’h’)
         && (str[i+2]==’t’) && (str[i+3]==’-’)
         && (str[i+4]==’f’) && (str[i+5]==’o’)
         && (str[i+6]==’n’) && (str[i+7]==’t’)
         && (str[i+8]==’s’)
         && ((str[i+9] == ’/’) || (str[i+9] == ’\\’))
       ){
          p = str + i + 10; i=0;
          while( *p ){ str[i++] = *(p++); }
          str[i] = ’\0’;
          found = TRUE;   break;
   } }
   if( found ){
      *export_str = (char *) r_alloc((void *) *export_str,
      (int) strlen((char *) *export_str) + (int) strlen((char *) str) +  2 );
      if( (int) strlen((char *) *export_str) > 0 ){
         (IGNORED) strcat((char *) *export_str, ",");
      }
      (IGNORED) strcat((char *) *export_str, (char *) str);
   }
 }
 #endif
 -_-_-

Recording TEX4HTFONTSET

Kpathsea ignores the under ht-fonts paths requests coming from tex4ht.c, exported like in ‘TEX4HTFONTSET={mozilla,iso8859/1,alias,unicode}’. So tex4ht.c lets kpathsea find whatever path it likes, such as

/n/gold/5/gurari/tex4ht.dir/texmf/tex4ht/ht-fonts/iso8859/1/cm/cmr.htf 

and then tex4ht.c tries to fix the path based on the information it collected for TEX4HTFONTSET,

/n/gold/5/gurari/tex4ht.dir/texmf/tex4ht/ht-fonts/unicode/cm/cmr.htf 

To that end, tex4ht.c breaks the first approximation to head ‘.../ht-fonts/’ and tail ‘....htf’, while removing the path segment ‘iso8859’ just after ‘ht-fonts/’.

Then, tex4ht.c tries the intermediate path segments from ‘TEX4HTFONTSET={mozilla,iso8859/1,alias,unicode}’, possibly with removing prefixes from tail.

<..vars..>+
 
 #ifdef KPATHSEA
 static char * export_str_chars = (char *) 0;
 #endif
 -_-_-

<..scan fonts vars..>+
 
 #ifdef KPATHSEA
 <.scan kpathsea vars.>
 #endif
 -_-_-

<..recording TEX4HTFONTSET..>
 {                                  int n;
    n = (int) strlen((char *) export_str);
    if( n > 0 ){
       export_str_chars = m_alloc(char, n+1);
       (IGNORED) strcpy((char *) export_str_chars, (char *) export_str);
 }  }
 -_-_-

<..scan kpathsea vars..>
 int cardinality=0;
 char ** fontset=0;
 -_-_-

<..start loading fonts..>
 
 #ifdef KPATHSEA
 if( export_str_chars ){
   <.decompose TEX4HTFONTSET.>
 }
 #endif
 -_-_-

<..end loading fonts..>+
 
 #ifdef KPATHSEA
 if( export_str_chars ){
    free((void *) export_str_chars);
    free((void *) fontset);
 }
 #endif
 -_-_-

<..decompose TEX4HTFONTSET..>
 {                   U_CHAR   *p;
                     int n;
    cardinality = 1;
    p = (U_CHAR *) export_str_chars;
    while( *p != ’\0’ ){
      if( *p == ’,’ ){ cardinality++; }
      p++;
    }
    fontset = m_alloc(char *, cardinality);
    p = (U_CHAR *) export_str_chars;
    fontset[0] = p;
    n=1;
    while( *p != ’\0’ ){
       if( *p == ’,’ ){ fontset[n++] = p+1; *p = ’\0’;  }
       p++;
 }  }
 -_-_-

<..correct htfname..>
 {                    U_CHAR  * head, * tail, *p;
                      int n;
    <.decompose htfname.>
    htfname =  (U_CHAR *) 0;
    <.try alternative htfname.>
 }
 -_-_-

<..decompose htfname..>
 n = (int) strlen((char *) htfname);
 tail = head = m_alloc(char, n+1);
 (IGNORED) strcpy((char *) head, (char *) htfname);
 while( n>11 ){
   if( (*tail==’\\’) || (*tail==’/’) ){
      if( (*tail == *(tail+9)) && (*(tail+1) == ’h’)
          && (*(tail+2) == ’t’) && (*(tail+3) == ’-’)
          && (*(tail+4) == ’f’) && (*(tail+5) == ’o’)
          && (*(tail+6) == ’n’) && (*(tail+7) == ’t’)
          && (*(tail+8) == ’s’) ){
         p = tail + 9;  *(tail + 10) = ’\0’;  tail += 11;
         while( (*tail != *p) && (*tail != ’\0’) ){  tail++; }
         break;
   }  }
   tail++; n--;
 }
 -_-_-

<..try alternative htfname..>
 for( n = 0 ; (n < cardinality) && !htfname ; n++){
   p = tail;
   while( *p != ’\0’ ){
                                char * s, *nm;
      s = m_alloc(char, (int) strlen((char *)  head )       +
                        (int) strlen((char *)  fontset[n] ) +
                        (int) strlen((char *)  p )          + 1);
      (IGNORED) strcpy((char *) s, (char *) head);
      (IGNORED) strcat((char *) s, (char *) fontset[n]);
      (IGNORED) strcat((char *) s, (char *) p);
      nm = kpse_find_file (s, kpse_program_text_format, 0);
      free((void *) s);
      if ( nm ){
         htfname = nm; break;
      }
      p++;
      while( (*p != ’\\’) && (*p != ’/’)  && (*p != ’\0’) ){ p++; }
 } }
 -_-_-

Debugging info

<..debug info about TEX4HTFONTSET..>
 if( dump_htf_search || dump_env_search ) {
                                 U_CHAR *p, *q;
    <.trace TEX4HTINPUTS.>
 }
 -_-_-

NOTE: The following code, activated by -hV or -hF, stops tex4ht.c with and error under miktex/kpathse. The execution arrives to ‘kpse_find_file ( "texmf.cnf", kpse_cnf_format, 0);’ but does not print a message in the line that follows. The problem probably was in warn_i_str. The code was modified from

     static U_CHAR warning[] = "--- warning --- "; 
     .... 
     fprintf(stderr,"--- warning --- "); 

to

     fprintf(stderr,"--- warning --- "); 

with the assumption/hope that it will take care of the problem.

<..trace TEX4HTINPUTS..>
 p = kpse_find_file ( "texmf.cnf", kpse_cnf_format, 0);
 if( p ){
    (IGNORED) printf( "texmf.cnf = %s\n", p);
 } else { warn_i_str(1, "texmf.cnf" ); }
 p = (U_CHAR *) kpse_var_value( "TEX4HTINPUTS" );
 if( p ){
    (IGNORED) printf("TEX4HTINPUTS = %s\n", p);
 }
 q = getenv("TEX4HTINPUTS");
 if( q ){  (IGNORED) printf(
    "Environment var TEX4HTINPUTS:  %s\n", q);
 }
 if( !p && !q ){
    (IGNORED) printf( "Missing TEX4HTINPUTS for kpathsea\n" );
 }
 -_-_-

<..trace TEX4HTFONTSET..>
 p = (U_CHAR *) kpse_var_value( "TEX4HTFONTSET" );
 if( p ){
    (IGNORED) printf("given TEX4HTFONTSET = %s\n", p);
 }
 q = getenv("TEX4HTFONTSET");
 if( q ){  (IGNORED) printf(
    "Environmet var TEX4HTFONTSET:  %s\n", q);
 }
 if( !p && !q ){
    (IGNORED) printf( "Missing TEX4HTFONTSET for kpathsea\n" );
 }
 -_-_-

15.6 Searching with KPATHSEA

Kpathsea manual

<..h-include..>+
 <.KPATHSEA h-include.>
 -_-_-

<..kpathsea arg 0..>
 
 #ifdef KPATHSEA
    kpse_set_program_name (argv[0], "tex4ht");
 #endif
 -_-_-

<..kpathsea env file..>
 
 #ifdef KPATHSEA
 if( !dot_file ) {                    U_CHAR * envfile;
                              char *arch, *p, str[256];
   <.arch = tail of SELFAUTOLOC.>
   envfile = (char *) 0;
   <.envfile = kpse-find-file architecture/tex4ht.env.>
   if ( !envfile ){ <.envfile = kpse-find-file tex4ht.env.> }
   if ( !envfile ){ <.envfile = kpathsea tex4ht.env.> }
   if ( envfile ){
     dot_file = kpse_open_file (envfile,
                               kpse_program_text_format);
     (IGNORED) printf("(%s)\n",  envfile);
   } else if( dump_env_search ){
     p = (char *) kpse_var_value( "TEX4HTINPUTS" );
     if( p ){
        (IGNORED)  printf( "TEX4HTINPUTS = %s\n", p );
     } else {  warn_i_str( 50, "kpathsea variable TEX4HTINPUTS"); }
   }
 }
 #endif
 -_-_-

The location of tex4ht.c can be found from the kpathsea variable ‘SELFAUTOLOC = /n/gold/5/gurari/tex4ht.dir/bin/solaris’, from which one can determine the architecture in use.

 > I still cannot catch why you need to determine the architecture, since 
 > all stuff belongs to texmf tree which is always the same for all systems, 
 > and tex4ht.env is found without problem. 
 > And T4HTINPUTS=  should be set in texmf.cnf 
 
In case we have different tex4ht.env files for different architectures 
 
  /usr/TeX/texmf/tex4ht/base/i386-linux/tex4ht.env 
  /usr/TeX/texmf/tex4ht/base/win32/tex4ht.env 
 
the SELFAUTOLOC provides us information about the architecture in use 
by inspecting from what branch tex4ht.c comes 
 
  /usr/TeX/bin/i386-linux 
  /usr/TeX/bin/win32 
 
Seems to me that this problem is solved now. 
 

<..arch = tail of SELFAUTOLOC..>
 p = arch = (char *) kpse_var_value( "SELFAUTOLOC" );
 while( *p != ’\0’ ){
    if( (*p ==   ’/’) || (*p == ’\\’) ){
       arch = p;
    }
    p++;
 }
 -_-_-

<..envfile = kpse-find-file architecture/tex4ht.env..>
 if( arch ){
   (IGNORED) sprintf(str,"%s%ctex4ht.env", arch+1, *arch);
   if( dump_env_search ){
     (IGNORED) printf("kpse_open_file (\"%s\", ...)?\n", str );
   }
   envfile= kpse_find_file (str, kpse_program_text_format, 0);
 }
 -_-_-

<..envfile = kpse-find-file tex4ht.env..>
 if( dump_env_search ){
   (IGNORED) printf("kpse_open_file (\"tex4ht.env\", ...)?\n");
 }
 envfile= kpse_find_file ("tex4ht.env", kpse_program_text_format, 0);
 -_-_-

<..if kpathsea tfm files else..>
 #ifdef KPATHSEA
 {
      U_CHAR * tfmfile;
   tfmfile = kpse_find_file (file_name, kpse_tfm_format, 0);
   if( !tfmfile ){ <.tfmfile = kpathsea tfm file.> }
   if ( tfmfile ){
        (IGNORED) printf("(%s)\n",  tfmfile);
        font_file = kpse_open_file (tfmfile, kpse_tfm_format);
   }
 }
 #else
 -_-_-

<..endif kpathsea tfm files..>
 #endif
 -_-_-

kpathsea vs kpse-find-file

The ‘kpsewhich’ utility can succeed where the kpse_find_file function fails, if the program is named something other than ‘tex4ht’. Otherwise, we don’t find the ‘TEX4HTINPUTS’ definition in ‘texmf.cnf’.

However, this is not yet enough to actually make the program work under an arbitrary name, because the ‘.htf’ lookups fail; we need to reset the Kpathsea progname. Other things to do, so let it stand. Bottom line is that the program must be invoked as ‘tex4ht’.

<..envfile = kpathsea tex4ht.env..>
 #define KPSEWHICH_CMD "kpsewhich --progname=tex4ht --format=othertext tex4ht.env"
 if( dump_env_search ){
   (IGNORED) printf("system(" KPSEWHICH_CMD ")?\n"); /* cpp concatenation */
 }
 if( system(KPSEWHICH_CMD ">tex4ht.tmp") == 0 ){
    <.fileaddr = read tex4ht.tmp.>
    envfile= kpse_find_file (fileaddr, kpse_program_text_format, 0);
    if( envfile ){
       warn_i_str( 50,
           "search support for kpse_find_file--using kpsewhich calls instead");
 }  }
 -_-_-

<..tfmfile = kpathsea tfm file..>
 char s [256];
 (IGNORED) strcpy(s, "kpsewhich ");
 (IGNORED) strcat(s, file_name);
 (IGNORED) strcat(s, " > tex4ht.tmp ");
 if( system(s) == 0 ){
    <.fileaddr = read tex4ht.tmp.>
    tfmfile = kpse_find_file (fileaddr, kpse_program_text_format, 0);
 }
 -_-_-

Don’t know how to avoid the use of intermediate file: popen(...) and fork() are not stadard utilities. Also the redirection > might need to be changed, e.g., to >&.

<..fileaddr = read tex4ht.tmp..>
 char fileaddr [256];
 int loc = 0;
 FILE* file =  f_open("tex4ht.tmp", READ_TEXT_FLAGS);
 if( file ){
   while( (fileaddr[loc] = getc(file)) >=0  ){
     if( fileaddr[loc] == ’\n’ ){ fileaddr[loc] = ’\0’; break; }
     loc++;
   }
   (IGNORED) fclose(file);
 }
 -_-_-

HTF Fonts

<..vars..>+
 static BOOL dump_htf_search = FALSE;
 -_-_-

<..trace htf search..>
 dump_htf_search = TRUE;
 -_-_-

<..file = kpathsea .htf file..>
 
 #ifdef KPATHSEA
   if( !file ){ U_CHAR * htfname;
      htfname= kpse_find_file (name, kpse_program_text_format, 0);
      if ( htfname ){
          <.correct htfname.>
          if ( htfname ){
             (IGNORED) printf("(%s)\n",  htfname);
             file= fopen(htfname,READ_TEXT_FLAGS);
      }   }
   }
 #endif
 -_-_-

web2c/kpathsea version uses texmf.cnf with the following:

TEX4HTFONTSET=alias,iso8859 
TEX4HTINPUTS=.;$TEXMF/tex4ht/base//;$TEXMF/tex4ht/ht-fonts/{$TEX4HTFONTSET}// 
T4HTINPUTS=.;$TEXMF/tex4ht/base// 

We can check values of variables of kpathsea with code fragments of the following form.

if( q = (U_CHAR *) kpse_var_value( "TEX4HTINPUTS" ) ){ 
  (IGNORED) printf( "%s\n", q ); 
} 

[more][kpathsea note] [more]

[more][more][more][more][more]

15.7 Searching Utilities

Search Files Listed in Environment File

The following is used for start searching files from directories mentioned in the dot file.

<..header functions..>+
 static FILE*  search_in_dot_file( ARG_IV( int, const U_CHAR *, const U_CHAR *,
                                     struct env_var_rec *) );
 -_-_-

<..functions..>+
 
 static FILE*  search_in_dot_file( typ, name, flags, env_dirs)
                                                  int   typ;
                                                  const U_CHAR  *name;
                                                  const U_CHAR  *flags;
                                       struct env_var_rec *env_dirs
 
 ;{                                         U_CHAR  *ch, dir[256];
                                           FILE* file;
 #ifndef KPATHSEA
    if( cache_files != (FILE *) 0 ){
       <.search font in cache files.>
    }
 #endif
    (IGNORED) fseek(dot_file, 0L, <.abs file addr.>);
    while( search_dot_file( typ ) ){
       ch = dir;
       while((*(ch++) = (int) getc(dot_file)) >  ’);
       while(*(ch-1) !=  ’\n’){
           *(ch-1) = (int) getc(dot_file);
       }
       *(ch-1) = ’\0’;
       file = search_file_base(name, dir, flags, env_dirs);
       if( file != NULL ){
 #ifndef KPATHSEA
         tex4ht_fls = TRUE;
 #endif
         return file;
    }  }
    return NULL;
 }
 -_-_-

<..header functions..>+
 static FILE*  search_file_base( ARG_IV( const U_CHAR *, const U_CHAR *, const U_CHAR *,
                                     struct env_var_rec *) );
 -_-_-

<..functions..>+
 
 static FILE*  search_file_base( name, dir, flags, env_dirs)
                                                  const U_CHAR  *name;
                                                  const U_CHAR  *dir;
                                                  const U_CHAR  *flags;
                                       struct env_var_rec *env_dirs
 
 ;{                                         U_CHAR  *p;
                                           FILE* file;
    if( *dir == ’~’ ){
      while( TRUE ){
         p = abs_addr(dir, env_dirs? env_dirs->base : NULL);
         file = search_file(name, p, flags);
         free((void *) p);
         if( file || !env_dirs ){  return file; }
         env_dirs = env_dirs->next;
      }
    } else {
      file = search_file(name, dir, flags);
    }
    return file;
 }
 -_-_-

<..header functions..>+
 static char *  abs_addr( ARG_II( const U_CHAR *, const U_CHAR *) );
 -_-_-

<..functions..>+
 
 static char *  abs_addr( dir, base)
                                                  const U_CHAR  *dir;
                                                  const U_CHAR  *base
 
 ;{                                         U_CHAR  *p;
    p = m_alloc(char, (int) strlen( dir )            +
                      (base? (int) strlen( base ):0) +
                      (int) strlen((char *)  HOME_DIR  )      + 1 );
    *p = ’\0’;
    if( (*(dir+1) == ’~’) && base ){
      if( *base == ’~’ ){
        (IGNORED) strct(p, HOME_DIR);
        (IGNORED) strct(p, base+1);
      } else {
        (IGNORED) strct(p, base);
      }
      (IGNORED) strct(p, dir+2);
    } else {
      (IGNORED) strct(p, HOME_DIR);
      (IGNORED) strct(p, dir+1);
    }
    return p;
 }
 -_-_-

Search in Current Directory and Specified Directory

If a path specification ends in a ’!’, it’s subdirectories are searched too, else only the specified dir is searched. (This is the way many TeX installations seem to do it, too).

<..header functions..>+
 static FILE* search_file( ARG_III(const char *, const U_CHAR *, const U_CHAR *) );
 -_-_-

<..functions..>+
 
 static FILE* search_file( name, dir, flags )
      const char     *name;
      const U_CHAR   *dir;
      const U_CHAR   *flags
 
 ;{   FILE*  file;
      U_CHAR     str[256];
      int i;
      BOOL subs;
   <.search file in cur dir.>
       (IGNORED) strcpy((char *) str, dir);
       i = (int) strlen((char *) str) - 1;
       subs = str[i] == ’!’;
       if( subs )  str[i] = ’\0’;  else i++;
       <.cat / if needed.>
 
   <.search file in named dir.>
   str[i] = ’\0’;
   return  subs?  search_file_ext( name, str, flags):
                 FALSE;
 }
 -_-_-

<..cat / if needed..>
 (IGNORED) strct(str,
 #if defined(__DJGPP__)
  (( dir[i-1] == ’/’) ||  ( dir[i-1] == ’\\’))
  ?  ""
  :  (is_forward_slash(dir)?  "/" : "\\" )
 #else
  (dir[i-1] == ’/’)? "" : "/"
 #endif
   );
 -_-_-

<..search file in cur dir..>
 if( (file = f_open(name, flags)) != NULL ){
    return file; }
 -_-_-

<..search file in named dir..>
 (IGNORED) strct(str,name);
 if( (file = f_open(str, flags)) != NULL ){
    str[i] = ’\0’; add_to_cache(str,name,i);
    return file; }
 -_-_-

<..header functions..>+
 static void add_to_cache( ARG_III(const char*,const char*,int) );
 -_-_-

<..functions..>+
 
 static void add_to_cache(dir,name,n)
                          const char*  dir; const char* name; int n
 
 ;{
                          struct cache_font_rec *cur_cache_font;
 
    <.put dir in cache.>
    <.store filename in cache.>
 }
 -_-_-

Search in SubDirectories

<..header functions..>+
 static FILE* search_file_ext( ARG_III(const char *, const U_CHAR *, const U_CHAR *) );
 -_-_-

<..functions..>+
 
 static FILE* search_file_ext( name, dir, flags )
     const char     *name;
     const U_CHAR   *dir;
     const U_CHAR   *flags
 
 ;{  U_CHAR   str[256];
     FILE*  file;
     int    n;
   n = (int) strlen(dir);
   (IGNORED) sprintf(str,
 #if defined(__DJGPP__)
  (( dir[n-1] == ’/’) ||  ( dir[n-1] == ’\\’))
  ?  "%s%s"
  :  (is_forward_slash(dir)?  "%s/%s" : "%s\\%s" )
 #else
    (dir[n-1] == ’/’)? "%s%s" : "%s/%s"
 #endif
    , dir, name);
   if( (file = f_open(str,flags)) != NULL ){
      add_to_cache(dir,name,n);
      return file;
   }
   if( (str[n] == <.directory ’/’.>)
 #ifdef DOS_WIN32
     ||  (str[n] == ’/’ )
 #endif
     ) n++;
   str[n-1] = ’\0’;
 #ifndef NOSUBDIR
 #ifdef WIN32
   <.file = search WIN32 subdir (name,str).>
 #else
   <.file = search subdir (name,str).>
 #endif
 #endif
   return NULL;
 }
 -_-_-

Searches in subdirectories require opendir, closedir, readir. I can’t find them for dos, so I disabled them there.

On Windows/dos, both forward slash (/) and backslash (\) are used as path separator characters. In other environments, it is the forward slash (/).

<..directory ’/’..>
 #if defined(__DJGPP__)
  ’\\’
 #else
  ’/’
 #endif
 -_-_-

<..defines..>+
 #if defined(__DJGPP__)
 #define dir_path_slash(str) (is_forward_slash(str)? ’/’ : ’\\’)
 #else
 #define dir_path_slash(str)  ’/’
 #endif
 -_-_-

<..header functions..>+
 #if defined(__DJGPP__)
    static BOOL is_forward_slash( ARG_I(const char*) );
 #endif
 -_-_-

<..functions..>+
 #if defined(__DJGPP__)
 
 static BOOL is_forward_slash(str)
                                     const char* str
 ;{
    while( *str ){  if( *(str++) == ’/’ ) { return TRUE; } }
    return FALSE;
 }
 #endif
 -_-_-

<..file = search subdir (name,str)..>
 {      DIR             *dp;
        <.struct dirent.>   *dirp;
        struct STSTAT     buf;
   if( (dp = opendir( str )) != NULL ){
     while( (dirp = readdir(dp)) != NULL ){
       if( !eq_str(dirp->d_name, ".")  &&
           !eq_str(dirp->d_name, "..") )
       { <.reach into the subdirectory.>
     } }
     (void) closedir(dp);
 } }
 -_-_-

<..reach into the subdirectory..>
 (IGNORED) strcpy((char *)  str+n, (char *) dirp->d_name );
 str[n-1] = dir_path_slash(str);
 if( LSTAT(str, &buf) >= 0 )
    if( S_ISDIR( buf.st_mode ) )
       if( (file = search_file_ext(name, str, flags)) != NULL ){
          (void) closedir(dp);
          return file; }
 -_-_-

<..h-include..>+
 #ifdef DOS_WIN32
 #include <io.h>
 #endif
 -_-_-

<..defines..>+
 #ifndef  S_ISDIR
 #define S_ISDIR(M)  (((M) & _S_IFMT)==_S_IFDIR)    test for directory 
 #endif
 
 #ifndef _S_IFDIR
 #define _S_IFDIR S_IFDIR
 #endif
 
 #ifndef _S_IFMT
 #define _S_IFMT S_IFMT
 #endif
 -_-_-

‘lstat’ returns info about the symbolic link, not the file referenced by the symbolic link as ‘stat’ does

STSTAT is for ‘struct stat’, LSTAT is for the function. Don’t define STAT, aix’s <sys/dir.h> defines it as 1 (Peter Breitenlohner).

1998-10-22  Eli Zaretskii  <[email protected]>  DJGPP: 
        (LSTAT): Define to stat for every system that doesn’t define 
        S_ISLNK. 

<..defines..>+
 #if defined(DOS_WIN32) || !defined(S_ISLNK)
 #define LSTAT stat
 #else
 #define LSTAT lstat
 #endif
 #define STSTAT stat
 -_-_-

<..h-include..>+
 #include <sys/stat.h>
                           stat _IF_DIR
 

 -_-_-

dirent

readdir, opendir, closedir

<..h-defines DOS-WIN32..>
 #ifdef DOS_WIN32
 #define STRUCT_DIRENT
 #endif
 -_-_-

<..h-include..>+
 #ifdef HAVE_DIRENT_H
 <.needs dirent.h.>
 #else
 #ifndef STRUCT_DIRENT
 #define STRUCT_DIRECT
 #endif
 <.needs simulated dirent.h.>
 #endif
 -_-_-

<..needs dirent.h..>
 #include <dirent.h>
 -_-_-

<..needs simulated dirent.h..>
 #ifdef HAVE_SYS_NDIR_H
 #include <sys/ndir.h>
 #endif
 #ifdef HAVE_SYS_DIR_H
 #include <sys/dir.h>
 #endif
 #ifdef HAVE_NDIR_H
 #include <ndir.h>
 #endif
 -_-_-

<..struct dirent..>
 
 #ifdef STRUCT_DIRECT
    struct direct
 #else
    struct dirent
 #endif
 -_-_-

[more]

Try to Open Path-Named File

<..header functions..>+
 static FILE* f_open_pathed_filename( ARG_II(const char*,const char*) );
 -_-_-

<..functions..>+
 
 static FILE* f_open_pathed_filename( name, flags )
                           const char*  name ;
                           const char*  flags
 ;{                        FILE* file;
                           U_CHAR *str;
   file = NULL;
   if( *name == ’~’ ){
      if( HOME_DIR ){
          str = m_alloc(char, strlen((char *) HOME_DIR)+strlen(name));
          (IGNORED) sprintf(str,"%s%s", HOME_DIR, name+1);
          file = f_open(str,flags);
          free((void *)  str);
      }
   } else {  file = f_open( name, flags );   }
   return file;
 }
 -_-_-