1 /*--------------------------------------------------------------------------
2   ----- File:        t1env.c
3   ----- Author:      Rainer Menzner (Rainer.Menzner@web.de)
4   ----- Date:        2007-12-22
5   ----- Description: This file is part of the t1-library. It implements
6                      the reading of a configuration file and path-searching
7 		     of type1-, afm- and encoding files.
8   ----- Copyright:   t1lib is copyrighted (c) Rainer Menzner, 1996-2007.
9                      As of version 0.5, t1lib is distributed under the
10 		     GNU General Public Library Lincense. The
11 		     conditions can be found in the files LICENSE and
12 		     LGPL, which should reside in the toplevel
13 		     directory of the distribution.  Please note that
14 		     there are parts of t1lib that are subject to
15 		     other licenses:
16 		     The parseAFM-package is copyrighted by Adobe Systems
17 		     Inc.
18 		     The type1 rasterizer is copyrighted by IBM and the
19 		     X11-consortium.
20   ----- Warranties:  Of course, there's NO WARRANTY OF ANY KIND :-)
21   ----- Credits:     I want to thank IBM and the X11-consortium for making
22                      their rasterizer freely available.
23 		     Also thanks to Piet Tutelaers for his ps2pk, from
24 		     which I took the rasterizer sources in a format
25 		     independ from X11.
26                      Thanks to all people who make free software living!
27 --------------------------------------------------------------------------*/
28 
29 
30 #define T1ENV_C
31 
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #if defined(_MSC_VER)
37 # include <io.h>
38 # include <sys/types.h>
39 # include <sys/stat.h>
40 #else
41 # include <unistd.h>
42 #endif
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <ctype.h>
46 
47 
48 #include "../type1/types.h"
49 #include "parseAFM.h"
50 #include "../type1/objects.h"
51 #include "../type1/spaces.h"
52 #include "../type1/util.h"
53 #include "../type1/fontfcn.h"
54 #include "../type1/fontmisc.h"
55 
56 #include "sysconf.h"
57 #include "t1types.h"
58 #include "t1extern.h"
59 #include "t1env.h"
60 #include "t1misc.h"
61 #include "t1base.h"
62 
63 
64 /* The following static variables are used to store information on the distinct
65    file search paths:
66 
67    -1         t1lib has not yet been initialized!
68     0         t1lib has been initialized and default paths have been setup
69     n (>0)    there are n path elements for current search path type, either built
70               from a FontDataBase file or from explicit fucntion calls.
71 */
72 
73 static int pfab_no=-1;
74 static int afm_no=-1;
75 static int enc_no=-1;
76 static int fdb_no=-1;
77 static int fdbxlfd_no=-1;
78 
79 static char path_sep_char='\0';
80 static char path_sep_string[2];
81 
82 static char pathbuf[2048];
83 
84 /* Define some default search paths */
85 #ifndef VMS
86 static char T1_pfab[]=".";
87 static char T1_afm[]=".";
88 static char T1_enc[]=".";
89 #else
90 static char T1_pfab[]="sys$disk:[]";
91 static char T1_afm[]="sys$disk:[]";
92 static char T1_enc[]="sys$disk:[]";
93 #endif
94 char T1_fdb[]="FontDataBase";
95 char T1_fdbxlfd[]="";  /* By default, we do not search XLFD databases. */
96 
97 
98 /* keywords recognized in config file */
99 static const char enc_key[]="ENCODING";
100 static const char pfab_key[]="TYPE1";
101 static const char afm_key[]="AFM";
102 static const char fdb_key[]="FONTDATABASE";
103 static const char fdbxlfd_key[]="FONTDATABASEXLFD";
104 
105 
106 /* qstrncpy(): Copy bytes from srcP to to destP. srcP is count bytes long
107    and destP is the number of quoted characters shorter. That is, count
108    refers to the number of characters including the escapement chars in
109    srcP! */
qstrncpy(char * destP,const char * srcP,long nochars)110 static void qstrncpy( char *destP, const char *srcP, long nochars)
111 {
112   long i;
113   long j;
114 
115   i=0;  /* dest-index */
116   j=0;  /* src-index */
117 
118   while (j<nochars) {
119     if (srcP[j]=='\\') {
120       if (srcP[j+1]=='"') {
121 	j++;                /* escaped quotation character --> omit escape char. */
122       }
123     }
124     else {                  /* normal character */
125       destP[i++]=srcP[j++];
126     }
127   }
128 }
129 
130 
131 
132 
133 /* Setup the default paths for searching the distinct file types. If
134    paths have been setup explicitly, skip the step of setting up a default path. */
intT1_SetupDefaultSearchPaths(void)135 void intT1_SetupDefaultSearchPaths( void)
136 {
137 
138   path_sep_char=PATH_SEP_CHAR;
139   sprintf( path_sep_string, "%c", path_sep_char);
140 
141   /* We set the number of stored path elements 0 so that we can distiguish
142      between explicitly setup paths and default paths in intT1_ScanConfigFile(). */
143   if (pfab_no==-1) {
144     T1_PFAB_ptr=(char**) calloc( 2, sizeof(char*));
145     T1_PFAB_ptr[0]=(char*)malloc(strlen(T1_pfab)+1);
146     strcpy(T1_PFAB_ptr[0],T1_pfab);
147     pfab_no=0;
148   }
149 
150   if (afm_no==-1) {
151     T1_AFM_ptr=(char**) calloc( 2, sizeof(char*));
152     T1_AFM_ptr[0]=(char*)malloc(strlen(T1_afm)+1);
153     strcpy(T1_AFM_ptr[0],T1_afm);
154     afm_no=0;
155   }
156 
157   if (enc_no==-1) {
158     T1_ENC_ptr=(char**) calloc( 2, sizeof(char*));
159     T1_ENC_ptr[0]=(char*)malloc(strlen(T1_enc)+1);
160     strcpy(T1_ENC_ptr[0],T1_enc);
161     enc_no=0;
162   }
163 
164   if (fdb_no==-1) {
165     T1_FDB_ptr=(char**) calloc( 2, sizeof(char*));
166     T1_FDB_ptr[0]=(char*)malloc(strlen(T1_fdb)+1);
167     strcpy(T1_FDB_ptr[0],T1_fdb);
168     fdb_no=0;
169   }
170 
171   if (fdbxlfd_no==-1) {
172     /* The XLFD font data base defaults to be empty */
173     T1_FDBXLFD_ptr=(char**) calloc( 1, sizeof(char*));
174     fdbxlfd_no=0;
175   }
176 }
177 
178 
179 /* This function is called from T1_CloseLib(). We have to indicate the state
180    of a non-initialzed t1lib! */
intT1_FreeSearchPaths(void)181 void intT1_FreeSearchPaths( void)
182 {
183   int i;
184 
185   i=0;
186   if (T1_PFAB_ptr!=NULL) {
187     while (T1_PFAB_ptr[i]!=NULL) {
188       free(T1_PFAB_ptr[i]);
189       T1_PFAB_ptr[i++]=NULL;
190     }
191     free( T1_PFAB_ptr);
192     T1_PFAB_ptr=NULL;
193   }
194   i=0;
195   if (T1_AFM_ptr!=NULL) {
196     while (T1_AFM_ptr[i]!=NULL) {
197       free(T1_AFM_ptr[i]);
198       T1_AFM_ptr[i++]=NULL;
199     }
200     free( T1_AFM_ptr);
201     T1_AFM_ptr=NULL;
202   }
203   i=0;
204   if (T1_ENC_ptr!=NULL) {
205     while (T1_ENC_ptr[i]!=NULL) {
206       free(T1_ENC_ptr[i]);
207       T1_ENC_ptr[i++]=NULL;
208     }
209     free( T1_ENC_ptr);
210     T1_ENC_ptr=NULL;
211   }
212   i=0;
213   if (T1_FDB_ptr!=NULL) {
214     while (T1_FDB_ptr[i]!=NULL) {
215       free(T1_FDB_ptr[i]);
216       T1_FDB_ptr[i++]=NULL;
217     }
218     free( T1_FDB_ptr);
219     T1_FDB_ptr=NULL;
220   }
221   i=0;
222   if (T1_FDBXLFD_ptr!=NULL) {
223     while (T1_FDBXLFD_ptr[i]!=NULL) {
224       free(T1_FDBXLFD_ptr[i]);
225       T1_FDBXLFD_ptr[i++]=NULL;
226     }
227     free( T1_FDBXLFD_ptr);
228     T1_FDBXLFD_ptr=NULL;
229   }
230   /* indicate t1lib non-initialized */
231   pfab_no=-1;
232   afm_no=-1;
233   enc_no=-1;
234   fdb_no=-1;
235   fdbxlfd_no=-1;
236 
237   return;
238 }
239 
240 
241 /* ScanConfigFile(): Read a configuration file and scan and save the
242    environment strings used for searching pfa/pfb-, afm- and encoding
243    files as well as the name of the font database file. */
intT1_ScanConfigFile(void)244 int intT1_ScanConfigFile( void)
245 {
246 
247   char *env_str;
248   char *linebuf;
249   char *usershome;
250   char *cnffilepath;
251   char *globalcnffilepath;
252   static int linecnt;
253   char local_path_sep_char;
254   int quoted=0;
255   int quotecnt=0;
256   FILE *cfg_fp;
257   int filesize, i, j, k;
258   int ignoreline=0;
259 
260   char*** destP=NULL;
261   int *idestP=NULL;
262   char* curr_key=NULL;
263 
264   /* First, get the string stored in the environment variable: */
265   env_str=getenv(ENV_CONF_STRING);
266   linecnt=1;
267 
268   if (!env_str) {
269     /* environment variable not set, try to open default file
270        in user's home directory and afterwards global config file */
271     if ((usershome=getenv("HOME"))!=NULL) {
272       cnffilepath=(char *)malloc((strlen(usershome) +
273 				  strlen(T1_CONFIGFILENAME) + 2
274 				  ) * sizeof(char));
275       if (cnffilepath==NULL){
276 	T1_errno=T1ERR_ALLOC_MEM;
277 	return(-1);
278       }
279       strcpy( cnffilepath, usershome);
280     }
281     else {
282       cnffilepath=(char *)malloc((strlen(T1_CONFIGFILENAME) + 2
283 				  ) * sizeof(char));
284     }
285     strcat( cnffilepath, DIRECTORY_SEP);
286     strcat( cnffilepath, T1_CONFIGFILENAME);
287 
288     globalcnffilepath=(char*)malloc((strlen(GLOBAL_CONFIG_DIR) +
289 				     strlen(GLOBAL_CONFIG_FILE) + 2
290 				     ) * sizeof(char));
291     if (globalcnffilepath==NULL){
292       T1_errno=T1ERR_ALLOC_MEM;
293       return(-1);
294     }
295     strcpy( globalcnffilepath, GLOBAL_CONFIG_DIR);
296     strcat( globalcnffilepath, DIRECTORY_SEP);
297     strcat( globalcnffilepath, GLOBAL_CONFIG_FILE);
298 
299     if ((cfg_fp=fopen( cnffilepath, "rb"))==NULL){
300       sprintf( err_warn_msg_buf, "Could not open configfile %s",
301 	       cnffilepath);
302       T1_PrintLog( "ScanConfigFile()", err_warn_msg_buf, T1LOG_STATISTIC);
303       /* Try global config file */
304       if ((cfg_fp=fopen( globalcnffilepath, "rb"))==NULL){
305 	sprintf( err_warn_msg_buf, "Could not open global configfile %s",
306 		 globalcnffilepath);
307 	T1_PrintLog( "ScanConfigFile()", err_warn_msg_buf, T1LOG_WARNING);
308       }
309       else{
310 	sprintf( err_warn_msg_buf, "Using %s as Configfile (global)",
311 		 globalcnffilepath);
312 	T1_PrintLog( "ScanConfigFile()", err_warn_msg_buf, T1LOG_STATISTIC);
313       }
314     }
315     else{
316       sprintf( err_warn_msg_buf, "Using %s as Configfile (user's)",
317 	       cnffilepath);
318       T1_PrintLog( "ScanConfigFile()", err_warn_msg_buf, T1LOG_STATISTIC);
319     }
320     free( cnffilepath);
321     free( globalcnffilepath);
322     if (cfg_fp==NULL){
323       T1_PrintLog( "ScanConfigFile()",
324 		   "Neither user's nor global Configfile has been found",
325 		   T1LOG_WARNING);
326       return(0);
327     }
328   }
329   else {
330     /* open specified file for reading the configuration */
331     if ((cfg_fp=fopen(env_str,"rb"))==NULL){
332       T1_PrintLog( "ScanConfigFile()",
333 		   "Configfile as specified by Environment has not been found",
334 		   T1LOG_WARNING);
335       return(0);  /* specified file could not be openend
336 		     => no config paths read */
337     }
338     else {
339       sprintf( err_warn_msg_buf, "Using %s as Configfile (environment)",
340 	       env_str);
341       T1_PrintLog( "ScanConfigFile()", err_warn_msg_buf, T1LOG_STATISTIC);
342     }
343   }
344 
345 
346   /* cfg_fp points now to a valid config file */
347   /* Get the file size */
348   fseek( cfg_fp, 0, SEEK_END);
349   filesize=ftell(cfg_fp);
350   /* Reset fileposition to start */
351   fseek( cfg_fp, 0, SEEK_SET);
352 
353   if ((linebuf=(char *)calloc( filesize+1,
354 			       sizeof(char)))==NULL){
355     T1_errno=T1ERR_ALLOC_MEM;
356     return(-1);
357   }
358 
359   fread((char *)linebuf, sizeof(char), filesize, cfg_fp);
360   fclose(cfg_fp);
361 
362   i=0;
363 
364   /* this might be overwritten on a per file basis */
365   local_path_sep_char=path_sep_char;
366 
367   while(i<filesize) {
368     ignoreline=0;
369     j=i;     /* Save index of beginning of line */
370     while ((linebuf[i]!='=') && (linebuf[i]!='\n') && (i<filesize)) {
371       i++;
372     }
373     if (i==filesize) {
374       free( linebuf);
375       return(i);
376     }
377 
378     if (strncmp( enc_key, &linebuf[j], 8)==0) {
379       /* setup target */
380       destP=&T1_ENC_ptr;
381       idestP=&enc_no;
382       curr_key=(char*)enc_key;
383     }
384     else if (strncmp( pfab_key, &linebuf[j], 5)==0) {
385       /* setup target */
386       destP=&T1_PFAB_ptr;
387       idestP=&pfab_no;
388       curr_key=(char*)pfab_key;
389     }
390     else if (strncmp( afm_key, &linebuf[j], 3)==0) {
391       /* setup target */
392       destP=&T1_AFM_ptr;
393       idestP=&afm_no;
394       curr_key=(char*)afm_key;
395     }
396     else if (strncmp( fdbxlfd_key, &linebuf[j], 16)==0) {
397       /* The handling here is somewhat specific. XLFD font database
398 	 specifications may coexist with standard font database
399 	 specification. However, if the standard font database is
400 	 the default value, an existing XLFD specification clears
401 	 this default value. Let this precede the standard fdb because
402 	 otherwise, this code would never be reached. */
403       if (fdb_no==0) { /* default paths are currently setup, get rid of them */
404 	free(T1_FDB_ptr[0]);
405 	T1_FDB_ptr[0]=NULL;
406       }
407 
408       /* setup target */
409       destP=&T1_FDBXLFD_ptr;
410       idestP=&fdbxlfd_no;
411       curr_key=(char*)fdbxlfd_key;
412     }
413     else if (strncmp( fdb_key, &linebuf[j], 12)==0) {
414       /* setup target */
415       destP=&T1_FDB_ptr;
416       idestP=&fdb_no;
417       curr_key=(char*)fdb_key;
418     }
419     else {
420       ignoreline=1;
421       T1_PrintLog( "ScanConfigFile()", "Ignoring line %d",
422 		   T1LOG_DEBUG, linecnt);
423     }
424 
425     /* If appropriate, scan this line. */
426     if (ignoreline==0) {
427       /* Check for an explicitly assigned value */
428       if (*idestP==0) { /* default paths are currently setup, get rid of them */
429 	if ((*destP)[0]!=NULL) {
430 	  free((*destP)[0]);
431 	  (*destP)[0]=NULL;
432 	}
433       }
434       else { /* append to existing paths */
435 	T1_PrintLog( "ScanConfigFile()",
436 		     "Appending to existing %s search path",
437 		     T1LOG_DEBUG, curr_key);
438       }
439       while ( (!isspace((int)linebuf[i])) && (i<filesize) ) {
440 	k=++i;      /* index to current path element */
441 	(*idestP)++;
442 	quotecnt=0;
443 	if (linebuf[i]=='"') { /* We have a quoted string */
444 	  quoted=1;
445 	  k=++i;
446 	  while ( 1) {
447 	    if ( linebuf[i]=='"' ) {    /* we find a quote-char */
448 	      if ( linebuf[i-1]!='\\' )
449 		break;                     /* not escaped --> end of path specification */
450 	      else
451 		quotecnt++;
452 	    }                           /* some other char */
453 	    if (linebuf[i]=='\n') { /* a newline in a quoted string? Perhabs, quotes do not match! */
454 	      T1_PrintLog( "ScanConfigFile()",
455 			   "Newline in quoted %s-string in line %d, column %d, of config file! Closing quote missing?",
456 			   T1LOG_WARNING, curr_key, linecnt, i-j+1);
457 	      j=i+1;                /* resynchronize linecount */
458 	      linecnt++;
459 	    }
460 	    if (i<filesize) {            /* filesize not exceeded? */
461 	      i++;
462 	    }
463 	    else {                       /* issue error msg because end of quotation is missing */
464 	      T1_PrintLog( "ScanConfigFile()", "Unterminated quoted string in config file",
465 			   T1LOG_ERROR);
466 	      return -1;
467 	    }
468 	  }
469 	}
470 	else {
471 	  quoted=0;
472 	  while ( (linebuf[i]!=local_path_sep_char) && (!isspace((int)linebuf[i])) && (i<filesize) )
473 	    i++;
474 	}
475 	if (((*destP)=(char**)realloc( (*destP), ((*idestP)+1)*sizeof(char*)))==NULL) {
476 	  T1_errno=T1ERR_ALLOC_MEM;
477 	  return(-1);
478 	}
479 	if (((*destP)[(*idestP)-1]=(char*)malloc((i-k-quotecnt+1)*sizeof(char)))==NULL) {
480 	  T1_errno=T1ERR_ALLOC_MEM;
481 	  return(-1);
482 	}
483 	if (quoted==0) {
484 	  strncpy( (*destP)[*idestP-1], &(linebuf[k]), i-k);
485 	  (*destP)[(*idestP)-1][i-k]='\0';
486 	}
487 	else {
488 	  qstrncpy( (*destP)[(*idestP)-1], &(linebuf[k]), i-k);
489 	  (*destP)[(*idestP)-1][i-k-quotecnt]='\0';
490 	  i++;         /* step over closing quote */
491 	}
492 	(*destP)[(*idestP)]=NULL;     /* indicate end of string list */
493       }
494     }
495 
496     /* skip remaining of line or file */
497     while ((linebuf[i]!='\n')&&(i<filesize))
498       i++;
499     i++;
500     linecnt++;
501   }
502   /* file should now be read in */
503   free( linebuf);
504 
505   return(i);
506 
507 }
508 
509 
510 
511 /* intT1_Env_GetCompletePath( ): Get a full path name from the file specified by
512    argument 1 in the environment specified by argument 2. Return the pointer
513    to the path string or NULL if no file was found.*/
intT1_Env_GetCompletePath(char * FileName,char ** env_ptr)514 char *intT1_Env_GetCompletePath( char *FileName,
515 				 char **env_ptr )
516 {
517   struct stat filestats;    /* A structure where fileinfo is stored */
518   int fnamelen, i, j;
519   char *FullPathName;
520   char *StrippedName;
521 
522 
523   if (FileName==NULL)
524     return(NULL);
525   fnamelen=strlen(FileName);
526 
527   /* We check whether absolute or relative pathname is given. If so,
528      stat() it and if appropriate, return that string immediately. */
529   if ( (FileName[0]==DIRECTORY_SEP_CHAR)
530        ||
531        ((fnamelen>1) && (FileName[0]=='.') &&
532 	(FileName[1]==DIRECTORY_SEP_CHAR))
533        ||
534        ((fnamelen>2) && (FileName[0]=='.') &&
535 	(FileName[1]=='.') && (FileName[2]==DIRECTORY_SEP_CHAR))
536 #if defined(MSDOS) | defined(_WIN32) | defined (__EMX__)
537        ||
538        ((isalpha(FileName[0])) && (FileName[1]==':'))
539 #endif
540 #ifdef VMS
541        || (strchr(FileName,':') != NULL)
542 #endif
543        )
544     {
545     /* Check for existence of the path: */
546     if (!stat( FileName, &filestats)) {
547       if (t1lib_log_file!=NULL) {
548 	sprintf( err_warn_msg_buf, "stat()'ing complete path %s successful",
549 		 FileName);
550 	T1_PrintLog( "intT1_Env_GetCompletePath()", err_warn_msg_buf,
551 		     T1LOG_DEBUG);
552       }
553       /* Return a copy of the string */
554       if ((FullPathName=(char *)malloc( fnamelen + 1))==NULL) {
555 	T1_errno=T1ERR_ALLOC_MEM;
556 	return(NULL);
557       }
558       strcpy( FullPathName, FileName);
559       return(FullPathName);
560     }
561     if (t1lib_log_file!=NULL){
562       sprintf( err_warn_msg_buf, "stat()'ing complete path %s failed",
563 	       FileName);
564       T1_PrintLog( "intT1_Env_GetCompletePath()", err_warn_msg_buf,
565 		   T1LOG_DEBUG);
566     }
567     /* Trying to locate absolute path spec. failed. We try to recover
568        by removing the path component and searching in the remaining search
569        path entries. This depends on the OS. */
570     i=fnamelen-1;
571     StrippedName=&(FileName[i]);
572     while ( FileName[i]!=DIRECTORY_SEP_CHAR
573 #if defined(VMS)
574 	    /* What exactly to do for VMS? */
575 #elif defined(MSDOS) | defined(_WIN32) | defined (__EMX__) | defined(_MSC_VER)
576 	    /* We take a drive specification into account. This means we
577 	       step back until the directory separator or a drive specifier
578 	       appears! */
579 	    && FileName[i]!=':'
580 #endif
581 	    ) {
582       i--;
583     }
584     i++;
585     StrippedName=&FileName[i];
586     if (t1lib_log_file!=NULL){
587       sprintf( err_warn_msg_buf, "path %s stripped to %s",
588 	       FileName, StrippedName);
589       T1_PrintLog( "intT1_Env_GetCompletePath()", err_warn_msg_buf,
590 		   T1LOG_DEBUG);
591     }
592   }
593   else{ /* We have a relative path name */
594     StrippedName=&FileName[0];
595   }
596 
597   i=0;
598   while (env_ptr[i]!=NULL) {
599     /* Copy current path element: */
600     strcpy( pathbuf, env_ptr[i]);
601     /* cut a trailing directory separator */
602     j=strlen(pathbuf);
603     if (pathbuf[j-1]==DIRECTORY_SEP_CHAR)
604       pathbuf[--j]='\0';
605     /* Add the directory separator: */
606 #ifdef VMS
607     { char *p= strrchr(pathbuf, DIRECTORY_SEP_CHAR);
608       if (p && *(p+1) ==  '\0')
609        *p = '\0';
610     }
611 #endif
612     strcat( pathbuf, DIRECTORY_SEP);
613     /* And finally the filename.
614        The following is fix against a vulnerability given by passing in
615        large filenames, cf.:
616 
617            http://www.securityfocus.com/bid/25079
618 
619        or
620 
621            http://packetstormsecurity.nl/0707-advisories/t1lib.txt
622 
623        If current pathbuf + StrippedName + 1 byte for NULL is bigger than
624        pathbuf log a warning and try next pathbuf */
625     if ( strlen(pathbuf) + strlen(StrippedName) + 1 > sizeof(pathbuf) ) {
626       T1_PrintLog( "intT1_Env_GetCompletePath()", "Omitting suspicious long candidate path in order to prevent buffer overflow.",
627 		   T1LOG_WARNING);
628       i++;
629       continue;
630     }
631     strcat( pathbuf, StrippedName);
632 
633     /* Check for existence of the path: */
634     if (!stat( pathbuf, &filestats)) {
635       if ((FullPathName=(char*)malloc( (j+fnamelen+2)*sizeof(char)))==NULL) {
636 	T1_errno=T1ERR_ALLOC_MEM;
637 	return(NULL);
638       }
639       strcpy( FullPathName, pathbuf);
640       if (t1lib_log_file!=NULL){
641 	sprintf( err_warn_msg_buf, "stat()'ing %s successful",
642 		 FullPathName);
643 	T1_PrintLog( "intT1_Env_GetCompletePath()", err_warn_msg_buf,
644 		     T1LOG_DEBUG);
645       }
646       return(FullPathName);
647     }
648     if (t1lib_log_file!=NULL){
649       sprintf( err_warn_msg_buf, "stat()'ing %s failed",
650 	       pathbuf);
651       T1_PrintLog( "intT1_Env_GetCompletePath()", err_warn_msg_buf,
652 		   T1LOG_DEBUG);
653     }
654     /* We didn't find the file --> try next path entry */
655     i++;
656   }
657   /* If we get here, no file was found at all, so return a NULL-pointer */
658   return(NULL);
659 }
660 
661 
662 
663 /* T1_SetFileSearchPath(): Set the search path to find files of the
664    specified type and return 0 if successful and -1 otherwise. An existing
665    path is overwritten rigorously, unless the database already contains fonts.
666    In the latter case the function returns with an error status.
667    Multiple path types may be specified as a bitmask!
668 */
T1_SetFileSearchPath(int type,char * pathname)669 int T1_SetFileSearchPath( int type, char *pathname)
670 {
671 
672   int i;
673   int pathlen;
674 
675 
676   if (pathname==NULL){
677     T1_errno=T1ERR_INVALID_PARAMETER;
678     return(-1);
679   }
680 
681   /* We do not allow to change the searchpath if the database already
682      contains one or more entries. */
683   if (T1_GetNoFonts()>0){
684     sprintf( err_warn_msg_buf, "Path %s not set, database is not empty",
685 	     pathname);
686     T1_PrintLog( "T1_SetFileSearchPath()", err_warn_msg_buf,
687 		 T1LOG_STATISTIC);
688     T1_errno=T1ERR_OP_NOT_PERMITTED;
689     return(-1);
690   }
691 
692   pathlen=strlen(pathname)+1;
693   /* Throw away a possibly existing path */
694   if (type & T1_PFAB_PATH){
695     if (pfab_no==-1) {
696       T1_PFAB_ptr=NULL; /* realloc() will do a malloc() */
697     }
698     else {
699       /* throw away current paths */
700       i=0;
701       while (T1_PFAB_ptr[i]!=NULL) {
702 	free (T1_PFAB_ptr[i++]);
703       }
704     }
705     if ((T1_PFAB_ptr=(char**)realloc( T1_PFAB_ptr, 2*sizeof(char*)))==NULL) {
706       T1_errno=T1ERR_ALLOC_MEM;
707       return(-1);
708     }
709     if ((T1_PFAB_ptr[0]=(char*)malloc(pathlen*sizeof(char)))==NULL) {
710       T1_errno=T1ERR_ALLOC_MEM;
711       return(-1);
712     }
713     strcpy( T1_PFAB_ptr[0], pathname);
714     T1_PFAB_ptr[1]=NULL;
715     pfab_no=1;
716   }
717   if (type & T1_AFM_PATH){
718     if (afm_no==-1) {
719       T1_AFM_ptr=NULL; /* realloc() will do a malloc() */
720     }
721     else {
722       /* throw away current paths */
723       i=0;
724       while (T1_AFM_ptr[i]!=NULL) {
725 	free (T1_AFM_ptr[i++]);
726       }
727     }
728     if ((T1_AFM_ptr=(char**)realloc( T1_AFM_ptr, 2*sizeof(char*)))==NULL) {
729       T1_errno=T1ERR_ALLOC_MEM;
730       return(-1);
731     }
732     if ((T1_AFM_ptr[0]=(char*)malloc(pathlen*sizeof(char)))==NULL) {
733       T1_errno=T1ERR_ALLOC_MEM;
734       return(-1);
735     }
736     strcpy( T1_AFM_ptr[0], pathname);
737     T1_AFM_ptr[1]=NULL;
738     afm_no=1;
739   }
740   if (type & T1_ENC_PATH){
741     if (enc_no==-1) {
742       T1_ENC_ptr=NULL; /* realloc() will do a malloc() */
743     }
744     else {
745       /* throw away current paths */
746       i=0;
747       while (T1_ENC_ptr[i]!=NULL) {
748 	free (T1_ENC_ptr[i++]);
749       }
750     }
751     if ((T1_ENC_ptr=(char**)realloc( T1_ENC_ptr, 2*sizeof(char*)))==NULL) {
752       T1_errno=T1ERR_ALLOC_MEM;
753       return(-1);
754     }
755     if ((T1_ENC_ptr[0]=(char*)malloc(pathlen*sizeof(char)))==NULL) {
756       T1_errno=T1ERR_ALLOC_MEM;
757       return(-1);
758     }
759     strcpy( T1_ENC_ptr[0], pathname);
760     T1_ENC_ptr[1]=NULL;
761     enc_no=1;
762   }
763 
764   return(0);
765 
766 }
767 
768 
769 
770 /* T1_GetFileSearchPath(): Return the specified file search path
771    or NULL if an error occurred. Note: We do only one path at a
772    time, so that if a bitmask is specified, the first match wins.
773    The returned path is formatted using the actual PATH_SEP_CHAR. */
T1_GetFileSearchPath(int type)774 char *T1_GetFileSearchPath( int type)
775 {
776   static char *out_ptr;
777   int i;
778   int pathlen;
779   char **src_ptr=NULL;
780 
781 
782   if (out_ptr!=NULL)
783     free( out_ptr);
784   out_ptr=NULL;
785 
786   if (type & T1_PFAB_PATH) {
787     src_ptr=T1_PFAB_ptr;
788   }
789   else  if (type & T1_AFM_PATH) {
790     src_ptr=T1_AFM_ptr;
791   }
792   else if (type & T1_ENC_PATH) {
793     src_ptr=T1_ENC_ptr;
794   }
795   else if (type & T1_FDB_PATH) {
796     src_ptr=T1_FDB_ptr;
797   }
798 
799 
800   i=0;
801   pathlen=0;
802   while (src_ptr[i]!=NULL) {
803     pathlen +=strlen( src_ptr[i++]);
804     pathlen+=1; /* path separator */
805   }
806   if ((out_ptr=(char *)malloc(pathlen+1))==NULL) {
807     T1_errno=T1ERR_ALLOC_MEM;
808     return( NULL);
809   }
810   strcpy( out_ptr, src_ptr[0]);
811   i=1;
812   while (src_ptr[i]!=NULL) {
813     strcat( out_ptr, path_sep_string);
814     strcat( out_ptr, src_ptr[i++]);
815   }
816 
817   return( out_ptr);
818 
819 }
820 
821 
822 /* T1_AddToFileSearchPath(): Add the specified path element to
823    the specified search path. If the existing path is the default path,
824    it will not be replaced by the new path element. Since this function might
825    be called before initialization, we have to be aware that even the default
826    path could be missing. Multiple path types may be specified as a bitmask!
827    Return value is 0 if successful and -1 otherwise */
T1_AddToFileSearchPath(int pathtype,int mode,char * pathname)828 int T1_AddToFileSearchPath( int pathtype, int mode, char *pathname)
829 {
830   int i;
831   int pathlen;
832   char* newpath = NULL;
833   int nofonts;
834 
835 
836   if (pathname==NULL)
837     return(-1);
838 
839   nofonts=T1_GetNoFonts();
840 
841   pathlen=strlen(pathname);
842 
843   if (pathtype & T1_PFAB_PATH){
844     /* Allocate meory for string */
845     if ((newpath=(char*)malloc( (pathlen+1)*sizeof(char)))==NULL)  {
846       T1_errno=T1ERR_ALLOC_MEM;
847       return(-1);
848     }
849     /* Check for and handle the existing path configuration */
850     if (pfab_no==0) {   /* do not free the default path but establish it
851 			   as a regularly setup path, if database not empty! */
852       if (nofonts>0) {
853 	pfab_no++;
854       }
855       else {
856 	free( T1_AFM_ptr[0]);
857       }
858     }
859     if (pfab_no==-1) {  /* not initialized! */
860       pfab_no=0;
861       T1_PFAB_ptr=NULL; /* realloc() will do the malloc()! */
862     }
863     if ((T1_PFAB_ptr=(char**)realloc( T1_PFAB_ptr, (++pfab_no+1)*sizeof(char*)))==NULL) {
864       T1_errno=T1ERR_ALLOC_MEM;
865       return(-1);
866     }
867     /* Insert the new path element: */
868     if (mode & T1_PREPEND_PATH){ /* prepend */
869       i=pfab_no-2;
870       while (i>=0) {
871 	T1_PFAB_ptr[i+1]=T1_PFAB_ptr[i];
872 	i--;
873       }
874       T1_PFAB_ptr[0]=newpath;
875     }
876     else{ /* append */
877       T1_PFAB_ptr[pfab_no-1]=newpath;
878     }
879     T1_PFAB_ptr[pfab_no]=NULL;
880   }
881   if (pathtype & T1_AFM_PATH){
882     /* Allocate meory for string */
883     if ((newpath=(char*)malloc( (pathlen+1)*sizeof(char)))==NULL)  {
884       T1_errno=T1ERR_ALLOC_MEM;
885       return(-1);
886     }
887     /* Check for and handle the existing path configuration */
888     if (afm_no==0) {   /* do not free the default path but establish it
889 			  as a regularly setup path, if database not empty! */
890       if (nofonts>0) {
891 	afm_no++;
892       }
893       else {
894 	free( T1_AFM_ptr[0]);
895       }
896     }
897     if (afm_no==-1) {  /* not initialized! */
898       afm_no=0;
899       T1_AFM_ptr=NULL; /* realloc() will do the malloc()! */
900     }
901     if ((T1_AFM_ptr=(char**)realloc( T1_AFM_ptr, (++afm_no+1)*sizeof(char*)))==NULL) {
902       T1_errno=T1ERR_ALLOC_MEM;
903       return(-1);
904     }
905     /* Insert the new path element */
906     if (mode & T1_PREPEND_PATH){ /* prepend */
907       i=afm_no-2;
908       while (i>=0) {
909 	T1_AFM_ptr[i+1]=T1_AFM_ptr[i];
910 	i--;
911       }
912       T1_AFM_ptr[0]=newpath;
913     }
914     else{ /* append */
915       T1_AFM_ptr[afm_no-1]=newpath;
916     }
917     T1_AFM_ptr[afm_no]=NULL;
918   }
919   if (pathtype & T1_ENC_PATH){
920     /* Allocate meory for string */
921     if ((newpath=(char*)malloc( (pathlen+1)*sizeof(char)))==NULL)  {
922       T1_errno=T1ERR_ALLOC_MEM;
923       return(-1);
924     }
925     /* Check for and handle the existing path configuration */
926     if (enc_no==0) {    /* do not free the default path but establish it
927 			   as a regularly setup path, if database not empty! */
928       if (nofonts>0) {
929 	enc_no++;
930       }
931       else {
932 	free( T1_ENC_ptr[0]);
933       }
934     }
935     if (enc_no==-1) {  /* not initialized! */
936       enc_no=0;
937       T1_ENC_ptr=NULL; /* realloc() will do the malloc()! */
938     }
939     if ((T1_ENC_ptr=(char**)realloc( T1_ENC_ptr, (++enc_no+1)*sizeof(char*)))==NULL) {
940       T1_errno=T1ERR_ALLOC_MEM;
941       return(-1);
942     }
943     /* Insert the new path element: */
944     if (mode & T1_PREPEND_PATH){ /* prepend */
945       i=enc_no-2;
946       while (i>=0) {
947 	T1_ENC_ptr[i+1]=T1_ENC_ptr[i];
948 	i--;
949       }
950       T1_ENC_ptr[0]=newpath;
951     }
952     else{ /* append */
953       T1_ENC_ptr[enc_no-1]=newpath;
954     }
955     T1_ENC_ptr[enc_no]=NULL;
956   }
957 
958   /* Copy new path to where it belongs ... */
959   if (newpath)
960     strcpy(newpath, pathname);
961 
962   return(0);
963 
964 }
965 
966 
967 
968 /* T1_SetFontDataBase(): Set a new name for the font database. It replaces the default
969    name and any names specified previously with this function.
970    Return value: 0 if OK, and -1 if filename not valid or an allocation
971    error occurred */
T1_SetFontDataBase(char * filename)972 int T1_SetFontDataBase( char *filename)
973 {
974   int pathlen;
975   int i;
976   int result=0;
977 
978 
979   /* chekc filename */
980   if (filename==NULL) {
981     T1_errno=T1ERR_INVALID_PARAMETER;
982     return -1;
983   }
984 
985   /* this function must be called before any font is in the database, that is, usually,
986      before initialization! */
987   if ( pFontBase!=NULL && pFontBase->no_fonts>0) {
988     T1_errno=T1ERR_OP_NOT_PERMITTED;
989     return -1;
990   }
991 
992 
993   pathlen=strlen(filename)+1;
994   /* Throw away a possibly existing font database-statement */
995   if (fdb_no==-1) {
996     T1_FDB_ptr=NULL; /* realloc() will do a malloc() */
997   }
998   else {
999     /* throw away current paths */
1000     i=0;
1001     while (T1_FDB_ptr[i]!=NULL) {
1002       free (T1_FDB_ptr[i++]);
1003     }
1004   }
1005 
1006   if ((T1_FDB_ptr=(char**)realloc( T1_FDB_ptr, 2*sizeof(char*)))==NULL) {
1007     T1_errno=T1ERR_ALLOC_MEM;
1008     return -1;
1009   }
1010 
1011   if ((T1_FDB_ptr[0]=(char*)malloc(pathlen*sizeof(char)))==NULL) {
1012     T1_errno=T1ERR_ALLOC_MEM;
1013     return -1;
1014   }
1015   strcpy( T1_FDB_ptr[0], filename);
1016   T1_FDB_ptr[1]=NULL;
1017   fdb_no=1;
1018 
1019   /* Load database immediately if t1lib already is initailzed */
1020   if (T1_CheckForInit()==0) {
1021     if ((result=intT1_scanFontDBase(T1_FDB_ptr[0]))==-1) {
1022       T1_PrintLog( "T1_AddFontDataBase()", "Fatal error scanning Font Database File %s (T1_errno=%d)",
1023 		   T1LOG_WARNING, T1_FDB_ptr[0], T1_errno);
1024     }
1025     if (result>-1)
1026       pFontBase->no_fonts+=result;
1027     result=pFontBase->no_fonts;
1028   }
1029   return result;
1030 
1031 }
1032 
1033 
1034 /* T1_AddFontDataBase(): Add a new font database file to the list. If the
1035    lib is already initialzed, then the new database is immediately loaded.
1036    Otherwise it is simply appended to the list and loaded at the time of
1037    initialization.
1038    Returns: -1    an error occured
1039              0    successfully inserted but not loaded because lib not initilized
1040 	     n>0  the highest defined FontID
1041 */
T1_AddFontDataBase(int mode,char * filename)1042 int T1_AddFontDataBase( int mode, char *filename)
1043 {
1044   int i;
1045   int pathlen;
1046   int result=0;
1047   char* newpath;
1048 
1049 
1050   if (filename==NULL) {
1051     T1_errno=T1ERR_INVALID_PARAMETER;
1052     return(-1);
1053   }
1054 
1055   pathlen=strlen(filename);
1056 
1057   /* Allocate memory for string */
1058   if ((newpath=(char*)malloc( (pathlen+1)*sizeof(char)))==NULL)  {
1059     T1_errno=T1ERR_ALLOC_MEM;
1060     return(-1);
1061   }
1062   strcpy( newpath, filename);
1063   /* Check for and handle the existing path configuration */
1064   if (fdb_no==0) {   /* defauls setup, free the path */
1065     free( T1_FDB_ptr[0]);
1066   }
1067   if (fdb_no==-1) {  /* not initialized! */
1068     fdb_no=0;
1069     T1_FDB_ptr=NULL; /* realloc() will do the malloc()! */
1070   }
1071 
1072   if ((T1_FDB_ptr=(char**)realloc( T1_FDB_ptr, (++fdb_no+1)*sizeof(char*)))==NULL) {
1073     T1_errno=T1ERR_ALLOC_MEM;
1074     return(-1);
1075   }
1076   /* Insert the new database. If t1lib is already initialzed, the database can only
1077      be appended. Otherwise. prepending is also possible.*/
1078   if ((mode & T1_PREPEND_PATH) && (T1_CheckForInit()!=0) ) { /* prepend */
1079     i=fdb_no-2;
1080     while (i>=0) {
1081       T1_FDB_ptr[i+1]=T1_FDB_ptr[i];
1082       i--;
1083     }
1084     T1_FDB_ptr[0]=newpath;
1085     result=0;
1086   }
1087   else { /* append */
1088     T1_FDB_ptr[fdb_no-1]=newpath;
1089     if (T1_CheckForInit()==0) {
1090       if ((result=intT1_scanFontDBase(T1_FDB_ptr[fdb_no-1]))==-1) {
1091 	T1_PrintLog( "T1_AddFontDataBase()", "Fatal error scanning Font Database File %s (T1_errno=%d)",
1092 		     T1LOG_WARNING, T1_FDB_ptr[fdb_no-1], T1_errno);
1093       }
1094       if (result>-1)
1095 	pFontBase->no_fonts+=result;
1096       result=pFontBase->no_fonts;
1097     }
1098   }
1099   T1_FDB_ptr[fdb_no]=NULL;
1100   return result;
1101 
1102 }
1103 
1104 
1105 
1106 /* T1_SetFontDataBaseXLFD(): Set a new name for the XLFD font database. It
1107    replaces the default name (which is empty and any names specified
1108    previously with this function.
1109    Return value: 0 if OK, and -1 if filename not valid or an allocation
1110    error occurred */
T1_SetFontDataBaseXLFD(char * filename)1111 int T1_SetFontDataBaseXLFD( char *filename)
1112 {
1113   int pathlen;
1114   int i;
1115   int result=0;
1116 
1117 
1118   /* check filename */
1119   if (filename==NULL) {
1120     T1_errno=T1ERR_INVALID_PARAMETER;
1121     return -1;
1122   }
1123 
1124   /* this function must be called before any font is in the database, that is, usually,
1125      before initialization! */
1126   if ( pFontBase!=NULL && pFontBase->no_fonts>0) {
1127     T1_errno=T1ERR_OP_NOT_PERMITTED;
1128     return -1;
1129   }
1130 
1131 
1132   pathlen=strlen(filename)+1;
1133   /* Throw away a possibly existing font database-statement */
1134   if (fdbxlfd_no==-1) {
1135     T1_FDBXLFD_ptr=NULL; /* realloc() will do a malloc() */
1136   }
1137   else {
1138     /* throw away current paths */
1139     i=0;
1140     while (T1_FDBXLFD_ptr[i]!=NULL) {
1141       free (T1_FDBXLFD_ptr[i++]);
1142     }
1143   }
1144 
1145   if ((T1_FDBXLFD_ptr=(char**)realloc( T1_FDBXLFD_ptr, 2*sizeof(char*)))==NULL) {
1146     T1_errno=T1ERR_ALLOC_MEM;
1147     return -1;
1148   }
1149 
1150   if ((T1_FDBXLFD_ptr[0]=(char*)malloc(pathlen*sizeof(char)))==NULL) {
1151     T1_errno=T1ERR_ALLOC_MEM;
1152     return -1;
1153   }
1154   strcpy( T1_FDBXLFD_ptr[0], filename);
1155   T1_FDBXLFD_ptr[1]=NULL;
1156   fdb_no=1;
1157 
1158   /* Load XLFD database immediately if t1lib already is initailzed */
1159   if (T1_CheckForInit()==0) {
1160     if ((result=intT1_scanFontDBaseXLFD(T1_FDBXLFD_ptr[0]))==-1) {
1161       T1_PrintLog( "T1_AddFontDataBaseXLFD()", "Fatal error scanning XLFD Font Database File %s (T1_errno=%d)",
1162 		   T1LOG_WARNING, T1_FDBXLFD_ptr[0], T1_errno);
1163     }
1164     if (result>-1)
1165       pFontBase->no_fonts+=result;
1166     result=pFontBase->no_fonts;
1167   }
1168   return result;
1169 
1170 }
1171 
1172 
1173 /* T1_AddFontDataBaseXLFD(): Add a new XLFD font database file to the list. If
1174    the lib is already initialzed, then the new database is immediately loaded.
1175    Otherwise it is simply appended to the list and loaded at the time of
1176    initialization.
1177    Returns: -1    an error occured
1178              0    successfully inserted but not loaded because lib not initilized
1179 	     n>0  the highest defined FontID
1180 */
T1_AddFontDataBaseXLFD(int mode,char * filename)1181 int T1_AddFontDataBaseXLFD( int mode, char *filename)
1182 {
1183   int i;
1184   int pathlen;
1185   int result=0;
1186   char* newpath;
1187 
1188 
1189   if (filename==NULL) {
1190     T1_errno=T1ERR_INVALID_PARAMETER;
1191     return(-1);
1192   }
1193 
1194   pathlen=strlen(filename);
1195 
1196   /* Allocate memory for string */
1197   if ((newpath=(char*)malloc( (pathlen+1)*sizeof(char)))==NULL)  {
1198     T1_errno=T1ERR_ALLOC_MEM;
1199     return(-1);
1200   }
1201   strcpy( newpath, filename);
1202   /* Check for and handle the existing path configuration */
1203   if (fdb_no==0) {   /* defauls setup, free the path */
1204     free( T1_FDB_ptr[0]);
1205   }
1206   if (fdbxlfd_no==-1) {  /* not initialized! */
1207     fdbxlfd_no=0;
1208     T1_FDBXLFD_ptr=NULL; /* realloc() will do the malloc()! */
1209   }
1210 
1211   if ((T1_FDBXLFD_ptr=(char**)realloc( T1_FDBXLFD_ptr, (++fdbxlfd_no+1)*sizeof(char*)))==NULL) {
1212     T1_errno=T1ERR_ALLOC_MEM;
1213     return(-1);
1214   }
1215   /* Insert the new database. If t1lib is already initialzed, the database can only
1216      be appended. Otherwise. prepending is also possible.*/
1217   if ((mode & T1_PREPEND_PATH) && (T1_CheckForInit()!=0) ) { /* prepend */
1218     i=fdbxlfd_no-2;
1219     while (i>=0) {
1220       T1_FDBXLFD_ptr[i+1]=T1_FDBXLFD_ptr[i];
1221       i--;
1222     }
1223     T1_FDBXLFD_ptr[0]=newpath;
1224     result=0;
1225   }
1226   else { /* append */
1227     T1_FDBXLFD_ptr[fdbxlfd_no-1]=newpath;
1228     if (T1_CheckForInit()==0) {
1229       if ((result=intT1_scanFontDBaseXLFD(T1_FDBXLFD_ptr[fdbxlfd_no-1]))==-1) {
1230 	T1_PrintLog( "T1_AddFontDataBase()", "Fatal error scanning Font Database File %s (T1_errno=%d)",
1231 		     T1LOG_WARNING, T1_FDBXLFD_ptr[fdbxlfd_no-1], T1_errno);
1232       }
1233       if (result>-1)
1234 	pFontBase->no_fonts+=result;
1235       result=pFontBase->no_fonts;
1236     }
1237   }
1238   T1_FDBXLFD_ptr[fdbxlfd_no]=NULL;
1239   return result;
1240 
1241 }
1242 
1243 
1244