Back to index

tetex-bin  3.0
t1base.c
Go to the documentation of this file.
00001 /*--------------------------------------------------------------------------
00002   ----- File:        t1base.c 
00003   ----- Author:      Rainer Menzner (Rainer.Menzner@web.de)
00004   ----- Date:        2004-03-04
00005   ----- Description: This file is part of the t1-library. It contains basic
00006                      routines to initialize the data structures used
00007                    by the t1-library.
00008   ----- Copyright:   t1lib is copyrighted (c) Rainer Menzner, 1996-2004.
00009                      As of version 0.5, t1lib is distributed under the
00010                    GNU General Public Library Lincense. The
00011                    conditions can be found in the files LICENSE and
00012                    LGPL, which should reside in the toplevel
00013                    directory of the distribution.  Please note that 
00014                    there are parts of t1lib that are subject to
00015                    other licenses:
00016                    The parseAFM-package is copyrighted by Adobe Systems
00017                    Inc.
00018                    The type1 rasterizer is copyrighted by IBM and the
00019                    X11-consortium.
00020   ----- Warranties:  Of course, there's NO WARRANTY OF ANY KIND :-)
00021   ----- Credits:     I want to thank IBM and the X11-consortium for making
00022                      their rasterizer freely available.
00023                    Also thanks to Piet Tutelaers for his ps2pk, from
00024                    which I took the rasterizer sources in a format
00025                    independ from X11.
00026                      Thanks to all people who make free software living!
00027 --------------------------------------------------------------------------*/
00028 
00029 
00030 #define T1BASE_C
00031 
00032 
00033 #include <stdio.h>
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <fcntl.h>
00037 #if defined(_MSC_VER)
00038 # include <io.h>
00039 # include <sys/types.h>
00040 # include <sys/stat.h>
00041 #else
00042 # include <unistd.h>
00043 #endif
00044 #include <stdlib.h>
00045 #include <math.h>
00046 #include <time.h>
00047 #include <string.h>
00048 #include <ctype.h>
00049 #include <stdarg.h>
00050 
00051 #include "../type1/ffilest.h" 
00052 #include "../type1/types.h"
00053 #include "parseAFM.h"
00054 #include "../type1/objects.h"
00055 #include "../type1/spaces.h"
00056 #include "../type1/util.h"
00057 #include "../type1/fontfcn.h"
00058 #include "../type1/regions.h"
00059 
00060 
00061 #include "sysconf.h"
00062 #include "t1base.h"
00063 #include "t1types.h"
00064 #include "t1global.h"
00065 #include "t1env.h"
00066 #include "t1delete.h"
00067 
00068 
00069 static int test_for_t1_file( char *buffer );
00070 static int T1_pad=0;
00071 
00072 /* A fix for Encoding Vector problem. Initialization / Deinitialization
00073    is now done in T1_InitLib() / T1-CloseLib. */
00074 extern boolean Init_BuiltInEncoding( void);
00075 extern psobj *StdEncArrayP;
00076 
00077 static const char* T1errmsg[] = {
00078   "",                                                          /*                              -10 */
00079   "",                                                          /*                              -9  */
00080   "",                                                          /*                              -8  */
00081   "",                                                          /*                              -7  */
00082   "",                                                          /*                              -6  */
00083   "Attempt to Load Multiple Master Font",                      /* T1ERR_SCAN_FONT_FORMAT       -5  */
00084   "Type 1 Font File Open Error",                               /* T1ERR_SCAN_FILE_OPEN_ERR     -4  */
00085   "Virtual Memory Exceeded",                                   /* T1ERR_SCAN_OUT_OF_MEMORY     -3  */
00086   "Syntactical Error Scanning Font File",                      /* T1ERR_SCAN_ERROR             -2  */
00087   "Premature End of Font File Encountered",                    /* T1ERR_SCAN_FILE_EOF          -1  */
00088   "",                                                          /*                               0  */
00089   "Path Construction Error",                                   /* T1ERR_PATH_ERROR              1  */
00090   "Font is Corrupt",                                           /* T1ERR_PARSE_ERROR             2  */
00091   "Rasterization Aborted",                                     /* T1ERR_TYPE1_ABORT             3  */
00092   "",                                                          /*                               4  */
00093   "",                                                          /*                               5  */
00094   "",                                                          /*                               6  */
00095   "",                                                          /*                               7  */
00096   "",                                                          /*                               8  */
00097   "",                                                          /*                               9  */
00098   "Font ID Invalid in this Context",                           /* T1ERR_INVALID_FONTID          10 */
00099   "Invalid Argument in Function Call",                         /* T1ERR_INVALID_PARAMETER       11 */
00100   "Operation not Permitted",                                   /* T1ERR_OP_NOT_PERMITTED        12 */
00101   "Memory Allocation Error",                                   /* T1ERR_ALLOC_MEM               13 */
00102   "Error Opening File",                                        /* T1ERR_FILE_OPEN_ERR           14 */
00103   "Unspecified T1Lib Error",                                   /* T1ERR_UNSPECIFIED             15 */
00104   "Missing AFM Data",                                          /* T1ERR_NO_AFM_DATA             16 */
00105   "X11 Interface Error",                                       /* T1ERR_X11                     17 */
00106   "Missing Component of Composite Character"                   /* T1ERR_COMPOSITE_CHAR          18 */
00107   "Error Scanning Encoding File",                              /* T1ERR_SCAN_ENCODING           19 */
00108   "",                                                          /*                               20 */
00109 };
00110 
00111 
00112 /* T1_StrError(): Return an error message corresponding to the value of
00113    t1err. */
00114 const char *T1_StrError( int t1err) 
00115 {
00116   int errind;
00117 
00118   errind = t1err + 10;
00119 
00120   if ( errind < 0 )
00121     errind = 0;
00122   if ( errind > 29 )
00123     errind = 0;
00124   
00125   return T1errmsg[errind];
00126 }
00127 
00128 
00129 
00130 /* This function is to be called by the user to initialize
00131    the font mechanism */
00132 void *T1_InitLib( int log)
00133 {
00134   int result;
00135   int i;
00136   
00137   char *usershome=NULL;
00138   char *logfilepath=NULL;
00139   char *envlogreq=NULL;
00140   int  usrforcelog=0;
00141   
00142   
00143   
00144   /* Reset T1_errno */
00145   T1_errno=0;
00146   
00147   /* Assign pointer to global struct and set entry padding: */
00148   pFontBase=&FontBase;
00149   if (T1_pad)
00150     pFontBase->bitmap_pad=T1_pad;
00151   else
00152     pFontBase->bitmap_pad=T1GLYPH_PAD;
00153 
00154   pFontBase->pFontArray = NULL;
00155   pFontBase->t1lib_flags=0;
00156   /* Check for AA-caching */
00157   if ((log & T1_AA_CACHING)){
00158     pFontBase->t1lib_flags |= T1_AA_CACHING;
00159   }
00160   /* Check for AFM disable */
00161   if ((log & T1_NO_AFM)) {
00162     pFontBase->t1lib_flags |= T1_NO_AFM;
00163   }
00164 
00165   /* Check environment variable ENV_LOG_STRING. By this means, a user may
00166      generate a log file even if at compile time log file creation has
00167      been suppressed. Of course, if the loglevel is reduced after
00168      initialization by the programmer, this environment variable takes
00169      no effect! */
00170   if ((envlogreq=getenv(ENV_LOG_STRING))!=NULL) {
00171     if (strcmp( envlogreq, "logDebug")==0)
00172       T1_SetLogLevel( T1LOG_DEBUG);
00173     else if (strcmp( envlogreq, "logStatistic")==0)
00174       T1_SetLogLevel( T1LOG_STATISTIC);
00175     else if (strcmp( envlogreq, "logWarning")==0)
00176       T1_SetLogLevel( T1LOG_WARNING);
00177     else if (strcmp( envlogreq, "logError")==0)
00178       T1_SetLogLevel( T1LOG_ERROR);
00179     usrforcelog=1;
00180   }
00181   
00182   /* Open log-file: */
00183   t1lib_log_file=NULL;
00184   if ((log & LOGFILE) || (usrforcelog!=0)) {
00185     pFontBase->t1lib_flags |= LOGFILE;
00186     /* Try first opening in current directory: */
00187     if ((t1lib_log_file=fopen( T1_LOG_FILE, "wb"))==NULL) {
00188       if ((usershome=getenv("HOME"))!=NULL) {
00189        logfilepath=(char *)malloc((strlen(usershome) +
00190                                 strlen(T1_LOG_FILE) + 2
00191                                 ) * sizeof(char));
00192        strcpy( logfilepath, usershome);
00193        strcat( logfilepath, DIRECTORY_SEP);
00194        strcat( logfilepath, T1_LOG_FILE);
00195        if ((t1lib_log_file=fopen( logfilepath, "wb"))==NULL){
00196          t1lib_log_file=stderr;
00197        }
00198        free( logfilepath);
00199       }
00200       else {
00201        t1lib_log_file=stderr;
00202       }
00203     }
00204     if (t1lib_log_file==stderr) {
00205       T1_PrintLog( "T1_InitLib()", "Unable to open a logfile, using stderr",
00206                  T1LOG_ERROR);
00207     }
00208   }
00209   
00210   T1_PrintLog( "T1_InitLib()", "Initialization started",
00211               T1LOG_STATISTIC);
00212   /* Check for representation of data in memory: */
00213   if ((pFontBase->endian=T1_CheckEndian())){
00214     T1_PrintLog( "T1_InitLib()", "Using Big Endian data presentation (MSBFirst)",
00215                T1LOG_DEBUG);
00216     pFontBase->endian=1;
00217   }
00218   else{
00219     T1_PrintLog( "T1_InitLib()", "Using Little Endian data presentation (LSBFirst)",
00220                T1LOG_DEBUG);
00221     pFontBase->endian=0;
00222   }
00223 
00224   /* Save version identifier */
00225   sprintf( err_warn_msg_buf, "Version Identifier: %s", T1LIB_IDENT);
00226   T1_PrintLog( "T1_InitLib()", err_warn_msg_buf,
00227               T1LOG_DEBUG);
00228   /* Save how t1lib is initialized */
00229   sprintf( err_warn_msg_buf, "Initialization flags: 0x%X", log);
00230   T1_PrintLog( "T1_InitLib()", err_warn_msg_buf,
00231               T1LOG_DEBUG);
00232   /* Save padding value in log file */
00233   sprintf( err_warn_msg_buf, "Glyphs are padded to %d bits",
00234           pFontBase->bitmap_pad);
00235   T1_PrintLog( "T1_InitLib()", err_warn_msg_buf,
00236               T1LOG_DEBUG);
00237 #ifdef __CHAR_UNSIGNED__
00238   T1_PrintLog( "T1_InitLib()", "System-Info: char is unsigned",
00239               T1LOG_DEBUG);
00240 #else
00241   T1_PrintLog( "T1_InitLib()", "System-Info: char is signed",
00242               T1LOG_DEBUG);
00243 #endif
00244   sprintf( err_warn_msg_buf, "System-Info: sizeof(char):         %d",
00245           SIZEOF_CHAR);
00246   T1_PrintLog( "T1_InitLib()", err_warn_msg_buf, T1LOG_DEBUG);
00247   sprintf( err_warn_msg_buf, "System-Info: sizeof(short):        %d",
00248           SIZEOF_SHORT);
00249   T1_PrintLog( "T1_InitLib()", err_warn_msg_buf, T1LOG_DEBUG);
00250   sprintf( err_warn_msg_buf, "System-Info: sizeof(int):          %d",
00251           SIZEOF_INT);
00252   T1_PrintLog( "T1_InitLib()", err_warn_msg_buf, T1LOG_DEBUG);
00253   sprintf( err_warn_msg_buf, "System-Info: sizeof(long):         %d",
00254           SIZEOF_LONG);
00255   T1_PrintLog( "T1_InitLib()", err_warn_msg_buf, T1LOG_DEBUG);
00256   sprintf( err_warn_msg_buf, "System-Info: sizeof(long long):    %d",
00257           SIZEOF_LONG_LONG);
00258   T1_PrintLog( "T1_InitLib()", err_warn_msg_buf, T1LOG_DEBUG);
00259   sprintf( err_warn_msg_buf, "System-Info: sizeof(float):        %d",
00260           SIZEOF_FLOAT);
00261   T1_PrintLog( "T1_InitLib()", err_warn_msg_buf, T1LOG_DEBUG);
00262   sprintf( err_warn_msg_buf, "System-Info: sizeof(double):       %d",
00263           SIZEOF_DOUBLE);
00264   T1_PrintLog( "T1_InitLib()", err_warn_msg_buf, T1LOG_DEBUG);
00265   sprintf( err_warn_msg_buf, "System-Info: sizeof(long double):  %d",
00266           SIZEOF_LONG_DOUBLE);
00267   T1_PrintLog( "T1_InitLib()", err_warn_msg_buf, T1LOG_DEBUG);
00268   sprintf( err_warn_msg_buf, "System-Info: sizeof(void *):       %d",
00269           SIZEOF_VOID_P);
00270   T1_PrintLog( "T1_InitLib()", err_warn_msg_buf, T1LOG_DEBUG);
00271   
00272   intT1_SetupDefaultSearchPaths();
00273   if (log & IGNORE_CONFIGFILE) {
00274     pFontBase->t1lib_flags |= IGNORE_CONFIGFILE;
00275     T1_PrintLog( "T1_InitLib()", "Skipping configuration file search!",
00276                T1LOG_STATISTIC);
00277   }
00278   else {
00279     if ((result=intT1_ScanConfigFile())==0)
00280       T1_PrintLog( "T1_InitLib()", "Warning t1lib configuration file not found!",
00281                  T1LOG_WARNING);
00282   }
00283   
00284   /* Initialize builtin Standard Encoding */
00285   if ( !(Init_BuiltInEncoding()) ) {
00286       T1_PrintLog( "T1_InitLib()", "Unable initialize internal StandardEncoding!",
00287                  T1LOG_ERROR);
00288   }
00289   
00290   /* Set the default encoding to the fonts' internal encoding */
00291   pFontBase->default_enc=NULL;
00292   
00293   /* Initialize the no_fonts... values */
00294   pFontBase->no_fonts=0;
00295   pFontBase->no_fonts_ini=pFontBase->no_fonts;
00296   pFontBase->no_fonts_limit=pFontBase->no_fonts;
00297 
00298   
00299   /* Check whether to read font database */
00300   if ((log & IGNORE_FONTDATABASE)){
00301     pFontBase->t1lib_flags |= IGNORE_FONTDATABASE;
00302 
00303     T1_Up=1;         /* System has been initialized ! */
00304     T1_PrintLog( "T1_InitLib()", "Initialization successfully finished (Database empty)",
00305                T1LOG_STATISTIC);
00306     
00307     return((void *) pFontBase);
00308   }
00309 
00310   result=0;
00311   /* Read fontdatabase(s) */
00312   i=0;
00313   while (T1_FDB_ptr[i]!=NULL) {
00314     if ((result=intT1_scanFontDBase(T1_FDB_ptr[i]))==-1){
00315       T1_PrintLog( "T1_InitLib()", "Fatal error scanning Font Database File %s",
00316                  T1LOG_WARNING, T1_FDB_ptr[i]);
00317     }
00318     if (result>-1)
00319       pFontBase->no_fonts+=result;
00320     i++;
00321     
00322   }
00323   if (result == 0){
00324     T1_PrintLog( "T1_InitLib()", "No fonts from Font Database File(s) found (T1_errno=%d)",
00325                T1LOG_ERROR, T1_errno);
00326     return(NULL);
00327   }
00328 
00329   /* Initialize the no_fonts... values */
00330   pFontBase->no_fonts_ini=pFontBase->no_fonts;
00331   pFontBase->no_fonts_limit=pFontBase->no_fonts;
00332 
00333   T1_Up=1;         /* System has been initialized ! */
00334   T1_PrintLog( "T1_InitLib()", "Initialization successfully finished",
00335             T1LOG_STATISTIC);
00336 
00337   return((void *) pFontBase);
00338 }
00339 
00340 
00341 
00342 /* intT1_scanFontDBase():
00343    - opens the file with the font definitions,
00344    - reads the number of fonts defined and saves this in FontBase,
00345    - allocates memory for all the filenames of the Type1 files
00346    - tests for .pfa und .pfb files and saves the name found
00347    - initializes an array that allows to acces these names by an
00348      index number, the font_ID
00349    - returns -1 on fatal error and the number of fonts located
00350      successfullly
00351    */
00352 int intT1_scanFontDBase( char *filename)
00353 {
00354   int fd;
00355   int filesize, i, j, k, m;
00356   int found=0, located=0;
00357   char *filebuffer;
00358   int nofonts=0;
00359   FONTPRIVATE* fontarrayP=NULL;
00360   
00361 #ifndef O_BINARY
00362 #  define O_BINARY 0x0
00363 #endif
00364 
00365   if ((fd=open( filename, O_RDONLY | O_BINARY))<3){
00366     T1_PrintLog( "intT1_scanFontDBase()", "Font Database File %s not found!",
00367                T1LOG_WARNING, filename);
00368     T1_errno=T1ERR_FILE_OPEN_ERR;
00369     return(-1);
00370   }
00371 
00372   /* Get the file size */
00373   filesize=lseek( fd, 0, 2);
00374   /* Reset fileposition to start */
00375   lseek (fd, 0, 0); 
00376 
00377   if ((filebuffer=(char *)malloc(filesize*sizeof(char)
00378                              )) == NULL){
00379     T1_PrintLog(  "intT1_scanFontDBase()",
00380                 "Couldn't allocate memory for loading font database file %s",
00381                 T1LOG_ERROR, filename);
00382     T1_errno=T1ERR_ALLOC_MEM;
00383     return(-1);
00384   }
00385   
00386   i=read( fd, filebuffer, filesize);
00387   close(fd);   /* Close font database file */
00388    
00389   i=j=m=0;
00390   
00391   while (i<filesize) {
00392     if (filebuffer[i]=='\n'){ /* We are at the end of line */
00393       if (j==0) {  /* Read the first line as the number of fonts */
00394        filebuffer[i]=0;
00395        sscanf( &filebuffer[0], "%d", &nofonts);
00396        filebuffer[i]='\n';  /* Because it gives a better feeling */
00397        /* (Re)Allocate memory for 'no_fonts' structures: */ 
00398        if ((FontBase.pFontArray=(FONTPRIVATE *)
00399             realloc( FontBase.pFontArray, (FontBase.no_fonts+nofonts)*sizeof(FONTPRIVATE))) == NULL) {
00400          T1_PrintLog( "inT1_scanFontDBase()",
00401                      "Failed to allocate memory for FONTPRIVATE-area while scanning %s",
00402                      T1LOG_ERROR, filename);
00403          T1_errno=T1ERR_ALLOC_MEM;
00404          return(-1);
00405        }
00406        /* setup pointer to newly allocated area and do a reset */
00407        fontarrayP=&(FontBase.pFontArray[FontBase.no_fonts]);
00408        memset(fontarrayP, 0, nofonts*sizeof(FONTPRIVATE));
00409        located=1; /* In  order to increment m */
00410       }
00411       else {       /* We are in the second or higher line */
00412        k=i;
00413        while (isspace((int)filebuffer[k])){
00414          k--;
00415        }
00416        /* We are at the last printable character of a line; let's 
00417           step back (over the [afm/sfm]) to the period and replace it
00418           by an ASCII 0 */
00419        while ((filebuffer[k]!='.') && (!isspace((int)filebuffer[k])) ){
00420          k--;
00421        }
00422        if (filebuffer[k]=='.'){ /* We have a name terminated with . */
00423          filebuffer[k]=0; /* termination for string reading */
00424          while (!isspace((int)filebuffer[k])){
00425            k--;
00426          }
00427        }
00428        else { /* The filename was without . and / or the first on the line */ 
00429          ;
00430        }
00431        sscanf( &(filebuffer[k+1]), "%s", &(linebuf[0]));
00432        /* We print error string before testing because after the call
00433           to test_for_t1_file() filename is substituted by an emty
00434           string if the file was not found: */
00435        sprintf( err_warn_msg_buf, "Type 1 Font file %s.[pfa/pfb] not found (FontID=%d, SearchPath=%s)",
00436                linebuf, m-1, T1_GetFileSearchPath(T1_PFAB_PATH));
00437        if ((test_for_t1_file( &linebuf[0]))){
00438          T1_PrintLog( "intT1_scanFontDBase()", err_warn_msg_buf, T1LOG_WARNING);
00439          located=0;
00440        }
00441        else{
00442          /* linebuf contains now the valid Type1 filename; let's
00443             now copy this string into the appropriate place in the
00444             FONTPRIVATE-struct: */
00445          found++;
00446          located=1;
00447          if ((fontarrayP[m-1].pFontFileName=(char *)
00448               calloc( strlen( &linebuf[0])+1, sizeof(char))) == NULL){
00449            T1_PrintLog( "intT1_scanFontDBase()",
00450                       "Failed to allocate memory for Filename %s (FontID=%d)",
00451                       T1LOG_ERROR, &linebuf[0], m-1);
00452            T1_errno=T1ERR_ALLOC_MEM;
00453            return(-1);
00454          }
00455          strcpy( fontarrayP[m-1].pFontFileName, &linebuf[0]);
00456        }
00457       }
00458       j++; /* Advance line counter */
00459       if ((located))
00460        m++;
00461     }
00462     if (j>nofonts) /* to ignore especially white space at end */
00463       break;
00464     i++;   /* Step further in file position */
00465   }
00466   /* Return the memory for file reading */
00467   free(filebuffer); 
00468   
00469   return( found);
00470 }
00471 
00472 
00473 /* T1_CloseLib(): Close the library and free all associated memory */
00474 int T1_CloseLib( void)
00475 {
00476 
00477   int i, j, error=0;
00478 
00479   if (T1_Up){
00480     for (i=pFontBase->no_fonts; i; i--){
00481       /* Free filename only if not NULL and if the font is physical!
00482         Do it before removing the font since the physical information
00483         is no more available afterwards. If necessary, an explicitly
00484         specified AFM filename is also freed.
00485         */
00486       if ((pFontBase->pFontArray[i-1].pFontFileName!=NULL)
00487          && (pFontBase->pFontArray[i-1].physical==1)){
00488        free( pFontBase->pFontArray[i-1].pFontFileName);
00489        pFontBase->pFontArray[i-1].pFontFileName=NULL;
00490        if (pFontBase->pFontArray[i-1].pAfmFileName!=NULL){
00491          free( pFontBase->pFontArray[i-1].pAfmFileName);
00492          pFontBase->pFontArray[i-1].pAfmFileName=NULL;
00493        }
00494       }
00495       
00496       /* Now, remove font: */
00497       if ((j=T1_DeleteFont( i-1))){
00498        error=1;
00499        sprintf( err_warn_msg_buf, "T1_DeleteFont() returned %d for Font %d",
00500                j, i-1);
00501        T1_PrintLog( "T1_CloseLib()", err_warn_msg_buf, T1LOG_ERROR);
00502       }
00503     }
00504     /* Free the FONTPRIVATE area */
00505     if (pFontBase->pFontArray)
00506       free( pFontBase->pFontArray);
00507     else
00508       error=1;
00509 
00510     /* Get rid of internal StandardEncoding vector */
00511     if ( StdEncArrayP != NULL ) {
00512       free( StdEncArrayP);
00513       StdEncArrayP = NULL;
00514     }
00515 
00516     /* Free search paths */
00517     intT1_FreeSearchPaths();
00518 
00519     /* Reset the flags */
00520     pFontBase->t1lib_flags=0;
00521     
00522     /* Indicate Library is no longer initialized */
00523     pFontBase=NULL;
00524     T1_Up=0;
00525     T1_PrintLog( "T1_CloseLib()", "Library closed", T1LOG_STATISTIC);
00526     if ((t1lib_log_file!=NULL) && (t1lib_log_file!=stderr))
00527       fclose(t1lib_log_file);
00528     t1lib_log_file=NULL;
00529   }
00530   
00531   return( error);
00532 }
00533 
00534 
00535 /* T1_AddFont(): Add a new fontfile to the fontdatabase.
00536    Return values: >0: Assigned FontID
00537                   -1: Fontfile not found
00538                 -2: Error allocating memory for FONTPRIVATE-area
00539                 -3: No memory for saving font filename
00540                 */
00541 int T1_AddFont( char *fontfilename)
00542 {
00543   
00544   char *FullName;
00545   FONTPRIVATE *save_ptr;
00546   int i;
00547   int new_ID;
00548   
00549   
00550   if (fontfilename==NULL){
00551     T1_errno=T1ERR_INVALID_PARAMETER;
00552     return(-1);
00553   }
00554   
00555   /* Check for existence of fontfile */
00556   if ((FullName=intT1_Env_GetCompletePath(fontfilename,T1_PFAB_ptr))==NULL) {
00557     T1_errno=T1ERR_FILE_OPEN_ERR;
00558     return(-1);
00559   }
00560   free(FullName);
00561 
00562   /* Check if free space for a new FONTPRIVATE is available; if not,
00563      realloc memory some amount larger */
00564   save_ptr=pFontBase->pFontArray;
00565   if (pFontBase->no_fonts==pFontBase->no_fonts_limit){
00566     if (pFontBase->pFontArray == NULL) {
00567       /* In case this is the first font */
00568       pFontBase->pFontArray=(FONTPRIVATE *)calloc(pFontBase->no_fonts_limit 
00569                                             + ADVANCE_FONTPRIVATE,
00570                                             sizeof(FONTPRIVATE));
00571     }
00572     else {
00573       /* We already have some fonts */
00574       pFontBase->pFontArray=(FONTPRIVATE *)realloc(pFontBase->pFontArray,
00575                                              (pFontBase->no_fonts_limit
00576                                               + ADVANCE_FONTPRIVATE)
00577                                              * sizeof(FONTPRIVATE));
00578       if (pFontBase->pFontArray==NULL){
00579        /* Restore pointer */
00580        pFontBase->pFontArray=save_ptr;
00581        T1_errno=T1ERR_ALLOC_MEM;
00582        return(-2); /* No memory available */
00583       }
00584     }
00585     pFontBase->no_fonts_limit += ADVANCE_FONTPRIVATE;
00586     /* First, initialize newly allocated to be not used */
00587     for ( i=pFontBase->no_fonts;
00588          i<pFontBase->no_fonts+ADVANCE_FONTPRIVATE; i++){
00589       pFontBase->pFontArray[i].pFontFileName=NULL;
00590       pFontBase->pFontArray[i].pAfmFileName=NULL;
00591       pFontBase->pFontArray[i].pAFMData=NULL;
00592       pFontBase->pFontArray[i].pType1Data=NULL;
00593       pFontBase->pFontArray[i].pEncMap=NULL;
00594       pFontBase->pFontArray[i].pKernMap=NULL;
00595       pFontBase->pFontArray[i].pFontEnc=NULL;
00596       pFontBase->pFontArray[i].pFontSizeDeps=NULL;
00597       pFontBase->pFontArray[i].vm_base=NULL;
00598       pFontBase->pFontArray[i].FontMatrix[0]=0.0;
00599       pFontBase->pFontArray[i].FontMatrix[1]=0.0;
00600       pFontBase->pFontArray[i].FontMatrix[2]=0.0;
00601       pFontBase->pFontArray[i].FontMatrix[3]=0.0;
00602       pFontBase->pFontArray[i].FontTransform[0]=0.0;
00603       pFontBase->pFontArray[i].FontTransform[1]=0.0;
00604       pFontBase->pFontArray[i].FontTransform[2]=0.0;
00605       pFontBase->pFontArray[i].FontTransform[3]=0.0;
00606       pFontBase->pFontArray[i].slant=0.0;
00607       pFontBase->pFontArray[i].extend=0.0;
00608       pFontBase->pFontArray[i].physical=0;
00609       pFontBase->pFontArray[i].refcount=0; 
00610       pFontBase->pFontArray[i].space_position=0; 
00611       pFontBase->pFontArray[i].info_flags=0; 
00612     }
00613   }
00614   /* no_fonts-1 was the largest allowed font ID */
00615   new_ID=pFontBase->no_fonts;
00616   pFontBase->no_fonts++;
00617 
00618   if ((FontBase.pFontArray[new_ID].pFontFileName=(char *)
00619        calloc( strlen( fontfilename)+1, sizeof(char))) == NULL){
00620     T1_PrintLog( "T1_AddFont()",
00621                "Failed to allocate memory for Filename %s (FontID=%d)",
00622                T1LOG_ERROR, fontfilename, new_ID);
00623     T1_errno=T1ERR_ALLOC_MEM;
00624     return(-3);
00625   }
00626   strcpy( FontBase.pFontArray[new_ID].pFontFileName, fontfilename);
00627 
00628   /* Generate logfile entry */
00629   sprintf( err_warn_msg_buf, "Assigned FontID %d to fontfile %s",
00630           new_ID, FontBase.pFontArray[new_ID].pFontFileName);
00631   T1_PrintLog( "T1_AddFont()", err_warn_msg_buf,
00632               T1LOG_STATISTIC);
00633   /* Return FontID of newly declared font */
00634   return( new_ID);
00635   
00636 }
00637 
00638 
00639 /* T1_PrintLog() generates entries in the log file. msg_txt is subject to scan
00640    conversion and ... signifies a accordingly lrge variable list. */
00641 void T1_PrintLog( char *func_ident, char *msg_txt, int level, ...)
00642 {
00643   va_list vararg;
00644   static char levelid[4]={ 'E', 'W', 'S', 'D'};
00645   time_t s_clock, *tp;
00646   
00647   if (t1lib_log_file==NULL)
00648     return;
00649   if ((level>t1lib_log_level) || (level<1)){
00650     return;
00651   }
00652   else{
00653     /* initialize argument list */
00654     va_start( vararg, level);
00655     
00656     tp=&s_clock;
00657     s_clock=time( tp);
00658     /*
00659     fprintf( t1lib_log_file, "(%c) (%.24s) %s: ",
00660             levelid[level-1], ctime(&s_clock), func_ident);
00661             */
00662     /* Don't print the time stamp */
00663     fprintf( t1lib_log_file, "(%c) %s: ", levelid[level-1], func_ident );
00664     vfprintf( t1lib_log_file, msg_txt, vararg );
00665     fprintf( t1lib_log_file, "\n");
00666     fflush( t1lib_log_file);
00667 
00668     /* cleanup variable list */
00669     va_end( vararg);
00670     
00671     return;
00672   }
00673 }
00674 
00675 
00676 /* T1_SetLogLevel(): Set the level which a message must have so
00677    that it is printed into the logfile. This function may be called
00678    before T1_InitLib(). */
00679 void T1_SetLogLevel( int level)
00680 {
00681   if ((level>0) && (level<5))
00682     t1lib_log_level=level;
00683   return;
00684 }
00685 
00686 
00687 
00688 /* T1_CheckForInit(): If no initialization of font mechanism has been
00689    done, return -1, indicating an error. */
00690 int T1_CheckForInit(void)
00691 {
00692   if(T1_Up)
00693     return(0);
00694   else
00695     return(-1);
00696   
00697 }
00698 
00699 
00700 
00701 /* T1_CheckForFontID(): Checks the font mechanism concerning the specified
00702    ID. It returns:
00703                    0  if font belonging to FontID has not yet been loaded
00704                  1  if font belonging to FontID has already been loaded
00705                  -1 if FontID is an invalid specification or t1lib not
00706                     initialized
00707                  */
00708 int T1_CheckForFontID( int FontID)
00709 {
00710 
00711   /* FontID is invalid */
00712   if ((FontID<0)||(FontID>(pFontBase->no_fonts - 1))||(T1_Up==0))
00713     return(-1);
00714   
00715   if (pFontBase->pFontArray[FontID].pType1Data==NULL)
00716     return(0);     /* has not yet been loaded */
00717   else
00718     return(1);     /* has already been loaded */
00719 }
00720 
00721  
00722 
00723 
00724 /* test_for_t1_file returns 0 if a file "name.pfa" or "name.pfb"
00725    was found. Else, -1 is returned. If successful, buffer contains the
00726    found filename string */
00727 static int test_for_t1_file( char *buffer )
00728 {
00729   int i=0;
00730   char *FullName;
00731   
00732   /* First case: A PostScript Font ASCII File without extension
00733      (according to some UNIX-conventions) */
00734   if ((FullName=intT1_Env_GetCompletePath(buffer,T1_PFAB_ptr))!=NULL) {
00735     free(FullName);
00736     return(0);
00737   }
00738 
00739   while (buffer[i]!=0){
00740     i++;
00741   }
00742   buffer[i]='.';
00743   buffer[i+1]='p';
00744   buffer[i+2]='f';
00745   buffer[i+4]=0;
00746 
00747   
00748   /* Second case: A PostScript Font ASCII File */
00749   buffer[i+3]='a';
00750   if ((FullName=intT1_Env_GetCompletePath(buffer,T1_PFAB_ptr))!=NULL) {
00751     free(FullName);
00752     return(0);
00753   }
00754   /* Third case: A PostScript Font Binary File */
00755   buffer[i+3]='b';
00756   if ((FullName=intT1_Env_GetCompletePath(buffer,T1_PFAB_ptr))!=NULL) {
00757     free(FullName);
00758     return(0);
00759   }
00760   
00761   /* If we get here no file was found => Set buffer
00762      to an empty string and return -1 */
00763   
00764   buffer[0]=0;
00765   return(-1);
00766 }
00767 
00768 
00769 /* T1_GetFontFileName() returns a pointer to the filename of the font,
00770    associated with FontID. This filename does not contain a full path.
00771    */
00772 char *T1_GetFontFileName( int FontID)
00773 {
00774 
00775   static char filename[MAXPATHLEN+1];
00776   
00777   if (T1_CheckForInit())return(NULL);
00778 
00779   /* Check first for valid FontID */
00780   if ((FontID<0) || (FontID>FontBase.no_fonts)){
00781     T1_errno=T1ERR_INVALID_FONTID;
00782     return(NULL);
00783   }
00784   
00785   strcpy( filename, pFontBase->pFontArray[FontID].pFontFileName);
00786   
00787   return( filename);
00788   
00789 }
00790 
00791 
00792 
00793 /* As suggested by Nicolai Langfeldt, we make it possible to specify
00794    a completely independent path for the afm filename. This should
00795    make t1lib usable in context with using the kpathsearch-library.
00796    We allow setting those path´s after initialization, but before a
00797    font is loaded.
00798    returns  0:   OK
00799            -1:   Operation could not be performed
00800 */
00801 int T1_SetAfmFileName( int FontID, char *afm_name)
00802 {
00803 
00804   if (T1_CheckForFontID(FontID)!=0){
00805     /* Operation may not be applied because FontID is invalid
00806        or font is loaded */
00807     T1_errno=T1ERR_INVALID_FONTID;
00808     return(-1);
00809   }
00810   if (afm_name==NULL) {
00811     T1_errno=T1ERR_INVALID_PARAMETER;
00812     return(-1);
00813   }
00814   if (pFontBase->pFontArray[FontID].pAfmFileName!=NULL){
00815     /* we first free the current name */
00816     free( pFontBase->pFontArray[FontID].pAfmFileName);
00817     pFontBase->pFontArray[FontID].pAfmFileName=NULL;
00818   }
00819   
00820   if ((pFontBase->pFontArray[FontID].pAfmFileName=
00821        (char *)malloc( (strlen(afm_name)+1)*sizeof( char)))==NULL) {
00822     T1_errno=T1ERR_ALLOC_MEM;
00823     return( -1);
00824   }
00825   strcpy( pFontBase->pFontArray[FontID].pAfmFileName, afm_name);
00826          
00827   return(0);
00828   
00829 }
00830 
00831                 
00832  
00833 /* We have a function for querying the name. Returns a pointer
00834    to the string or NULL if name was not explicitly set .*/
00835 char *T1_GetAfmFileName( int FontID)
00836 {
00837 
00838   static char filename[MAXPATHLEN+1];
00839   
00840   if (T1_CheckForInit())return(NULL);
00841 
00842   /* Check first for valid FontID */
00843   if ((FontID<0) || (FontID>FontBase.no_fonts)){
00844     T1_errno=T1ERR_INVALID_FONTID;
00845     return(NULL);
00846   }
00847 
00848   if (pFontBase->pFontArray[FontID].pAfmFileName==NULL) {
00849     return( NULL);
00850   }
00851   
00852   strcpy( filename, pFontBase->pFontArray[FontID].pAfmFileName);
00853   return( filename);
00854   
00855 }
00856 
00857 
00858   
00859 /* T1_GetNoFonts(): Return the number of declared fonts */
00860 int  T1_GetNoFonts(void)
00861 {
00862   if (T1_CheckForInit())
00863     return(-1);
00864   return(FontBase.no_fonts);
00865 }
00866 
00867        
00868 
00869 /* T1_SetDeviceResolutions( x_res, y_res): Set the device's physical
00870    resolution in horizontal and vertical direction, mesured in DPI
00871    (Dots Per Inch). This should be done before the first font is
00872    loaded! */
00873 int T1_SetDeviceResolutions( float x_res, float y_res)
00874 {
00875 
00876   int i;
00877   
00878   if (T1_CheckForInit())
00879     ;   /* Not initialized -> no size dependent data -> OK */
00880   else
00881     /* Check if size-dependent data is existent */
00882     for ( i=T1_GetNoFonts(); i; i--)
00883       if (pFontBase->pFontArray[i-1].pFontSizeDeps!=NULL){
00884        T1_errno=T1ERR_OP_NOT_PERMITTED;
00885        return(-1); /* There's is size dependent data for a font */
00886       }
00887   
00888   /* Save resolutions and calculate horizontal and vertical
00889      scale factors to map desired bp to device pixel */
00890   DeviceSpecifics.x_resolution=(float) x_res;
00891   DeviceSpecifics.y_resolution=(float) y_res;
00892   DeviceSpecifics.scale_x=(float)(((float)x_res)/BIGPOINTSPERINCH);
00893   DeviceSpecifics.scale_y=(float)(((float)y_res)/BIGPOINTSPERINCH);
00894   return(0);
00895 }
00896 
00897 
00898 /* T1_QueryX11Support(): Check at runtime to see if t1lib was compiled
00899    with X11 interface: */
00900 int T1_QueryX11Support( void)
00901 {
00902 #ifndef T1LIB_NO_X11_SUPPORT
00903   return(1);
00904 #else
00905   return(0);
00906 #endif
00907 }
00908 
00909 
00910 
00911 
00912 /* int T1_CopyFont(): Copies the font associated with FontID to another
00913    location. The pointers to type1- , afm- and encoding data as well as
00914    the matrices remain completely untouched. However, size dependent data
00915    is not copied. The produced font is marked as a "logical" font.
00916    If no memory is available in the FONTPRIVATE-array, there's realloc'ed
00917    some more memory. The FontID which is assigned to the newly generated
00918    font is given as the return value, or < 0 if an error occurs. Also,
00919    the refcount entry of the source font is incremented by one.
00920 
00921    Return value -1: invalid FontID specified
00922                 -2: source font is not a "physical" font
00923               -3: no memory for reallocation of FONTPRIVATEs
00924               -4: no memory for one of the mapping tables
00925               */
00926 int T1_CopyFont( int FontID)
00927 {
00928   FONTPRIVATE *save_ptr;
00929   int k;
00930   int new_ID;
00931   
00932   
00933   /* Check for a valid source font */
00934   if (T1_CheckForFontID(FontID)!=1){
00935     T1_errno=T1ERR_INVALID_FONTID;
00936     return(-1);
00937   }
00938 
00939 
00940   /* Check if the font in question is a "physical" font, otherwise it may
00941      not be copied */
00942   if (pFontBase->pFontArray[FontID].physical==0){
00943     T1_errno=T1ERR_OP_NOT_PERMITTED;
00944     return(-2);
00945   }
00946   
00947   
00948   /* Check if free space for a new FONTPRIVATE is available; if not,
00949      realloc memory some amount larger */
00950   save_ptr=pFontBase->pFontArray;
00951   if (pFontBase->no_fonts==pFontBase->no_fonts_limit){
00952     pFontBase->pFontArray=(FONTPRIVATE *)realloc(pFontBase->pFontArray,
00953                                            (pFontBase->no_fonts_limit
00954                                             + ADVANCE_FONTPRIVATE)
00955                                            * sizeof(FONTPRIVATE));
00956     if (pFontBase->pFontArray==NULL){
00957       /* Restore pointer */
00958       pFontBase->pFontArray=save_ptr;
00959       T1_errno=T1ERR_ALLOC_MEM;
00960       return(-3);
00961     }
00962     /* We zero the newly allocated memory */
00963     if (pFontBase->pFontArray != NULL) {
00964       memset( pFontBase->pFontArray + pFontBase->no_fonts_limit, 0,
00965              ADVANCE_FONTPRIVATE * sizeof(FONTPRIVATE));
00966     }
00967     pFontBase->no_fonts_limit += ADVANCE_FONTPRIVATE;
00968   }
00969   /* no_fonts-1 was the largest allowed font ID */
00970   new_ID=pFontBase->no_fonts;
00971   /* Copy FONTPRIVATE-structure: */
00972   pFontBase->pFontArray[new_ID]=pFontBase->pFontArray[FontID];
00973   /* (Re)Set some values explicitly, others remain untouched: */  
00974   pFontBase->pFontArray[new_ID].pFontSizeDeps=NULL;
00975   pFontBase->pFontArray[new_ID].physical=0;
00976   /* AFM-mapping tables are to be setup for logical fonts separately
00977    (if AFM data is there) */
00978   /* first, kerning map */
00979   if (pFontBase->pFontArray[new_ID].pAFMData) {
00980     k=pFontBase->pFontArray[new_ID].pAFMData->numOfPairs;
00981     if (k>0){ /* kern map exists only if kerning pairs exist! */
00982       if ((pFontBase->pFontArray[new_ID].pKernMap=
00983           (METRICS_ENTRY *)malloc( k*sizeof( METRICS_ENTRY)))==NULL){
00984        sprintf( err_warn_msg_buf, "Error allocating memory for kerning map (new_ID=%d)",
00985                new_ID);
00986        T1_PrintLog( "T1_CopyFont()", err_warn_msg_buf,
00987                    T1LOG_WARNING);
00988        T1_errno=T1ERR_ALLOC_MEM;
00989        return(-4);
00990       }
00991       memcpy( pFontBase->pFontArray[new_ID].pKernMap,
00992              pFontBase->pFontArray[FontID].pKernMap,
00993              k*sizeof( METRICS_ENTRY));
00994     } 
00995     else { /* no kerning pairs, bu AFM data present */
00996       pFontBase->pFontArray[new_ID].pKernMap=NULL;
00997     }
00998   } 
00999   else { /* AFM data not present at all */
01000     pFontBase->pFontArray[new_ID].pKernMap=NULL;
01001   }
01002 
01003   /* second, encoding map */
01004   if (pFontBase->pFontArray[FontID].pEncMap!=NULL) {
01005     if ((pFontBase->pFontArray[new_ID].pEncMap=
01006         (int *)calloc(256,sizeof(int)))==NULL){
01007       sprintf( err_warn_msg_buf,
01008               "Error allocating memory for encoding map (new_ID=%d)",
01009               new_ID);
01010       T1_PrintLog( "T1_CopyFont()", err_warn_msg_buf,
01011                  T1LOG_WARNING);
01012       T1_errno=T1ERR_ALLOC_MEM;
01013       return(-4);
01014     }
01015     memcpy( pFontBase->pFontArray[new_ID].pEncMap,
01016            pFontBase->pFontArray[FontID].pEncMap,
01017            256*sizeof( int));
01018   }
01019   
01020   /* New font is logical --> indicate to which physical font it
01021      refers by setting refcount: */
01022   pFontBase->pFontArray[new_ID].refcount=FontID;
01023   
01024   /* Now the struct is setup; increment no_fonts by 1 because
01025      new_ID is a valid font specification from now on. */
01026   pFontBase->no_fonts++;
01027   /* Increment refcount in source font */
01028   pFontBase->pFontArray[FontID].refcount++;
01029 
01030   /* Generate logfile entry */
01031   sprintf( err_warn_msg_buf, "Assigned FontID %d to fontfile %s",
01032           new_ID, FontBase.pFontArray[new_ID].pFontFileName);
01033   T1_PrintLog( "T1_CopyFont()", err_warn_msg_buf,
01034               T1LOG_STATISTIC);
01035   return(new_ID);
01036 }
01037 
01038 
01039 
01040 /* T1_SetBitmapPad(): Set the value to which bitmap-scanlines are padded.
01041    This has to be done before initialization because it is a very
01042    rudimentary operation.
01043    */
01044 int T1_SetBitmapPad( int pad)
01045 {
01046   if (T1_Up){
01047     /* Library is initialized --> return error */
01048     T1_errno=T1ERR_OP_NOT_PERMITTED;
01049     return(-1);
01050   }
01051   else{
01052     switch (pad){
01053     case 8: 
01054       T1_pad=8;
01055       return(0);
01056     case 16:
01057       T1_pad=16;
01058       return(0);
01059 #ifdef T1_AA_TYPE64
01060     case 32:
01061       T1_pad=32;
01062       return(0);
01063 #endif
01064     default:
01065       T1_errno=T1ERR_INVALID_PARAMETER;
01066       return(-1);
01067     }
01068   }
01069 }
01070 
01071 
01072 
01073 /* T1_GetBitmapPad(): Read the value to which scanlines of bitmap are
01074    padded. This can be done before or after initialization. */
01075 int T1_GetBitmapPad( void)
01076 {
01077   if (pFontBase) /* T1lib initialized --> return value from struct */
01078     return( pFontBase->bitmap_pad);
01079   else{
01080     if (T1_pad) 
01081       return(T1_pad);  /* pad is explicitly set --> return that value */
01082     else
01083       return( T1GLYPH_PAD); /* not expl. set --> return compilation default */
01084   }
01085 }
01086 
01087 
01088 
01089 /* CheckEndian(): Checks whether the current machine is of little or big
01090    endian architecture. This is important for concatenating bitmaps.
01091    Function returns 0 if LittleEndian and 1 if BigEndian representation
01092    is used  on the current hardware.
01093    */
01094 int T1_CheckEndian()
01095 {
01096   unsigned char *charptr;
01097 
01098   /* Generate test value */
01099   unsigned short test=0x0001;
01100 
01101   /* Read out memory as unsigned char */
01102   charptr=(unsigned char *)(&test)+1;
01103 
01104   /* Return value will be 1 if Big- and 0 if Little Endian */
01105   return((int) *charptr);
01106   
01107 }
01108 
01109 
01110 
01111 /* T1_GetLibIdent(): Return the identifier string for the current version
01112    of t1lib */
01113 char *T1_GetLibIdent( void)
01114 {
01115   static char buf[15];
01116 
01117   sprintf( buf, "%s", T1LIB_IDENT);
01118   
01119   return( (char *)buf);
01120 }
01121 
01122 
01123 
01124 /* T1_SetRasterFlags(): Enable/Disable certain features in
01125    the rasterizer */
01126 extern void T1_SetRasterFlags( int flags)
01127 { 
01128   
01129   T1_Type1OperatorFlags=flags;
01130   return;
01131   
01132 }
01133 
01134 
01135 
01136 /* T1_GetFontFileName(): returns a pointer to the complete path filename
01137    of the font, associated with FontID as it is in use by t1lib.
01138    */
01139 char *T1_GetFontFilePath( int FontID)
01140 {
01141 
01142   static char filepath[MAXPATHLEN+1];
01143   char *FileNamePath=NULL;
01144   
01145   /* is initialzed? */
01146   if (T1_CheckForInit()) {
01147     T1_errno=T1ERR_INVALID_FONTID;
01148     return(NULL);
01149   }
01150   
01151   /* Check first for valid FontID */
01152   if ((FontID<0) || (FontID>FontBase.no_fonts)){
01153     T1_errno=T1ERR_INVALID_FONTID;
01154     return(NULL);
01155   }
01156 
01157   /* lib is initialized and FontID is valid ->
01158      we can really expect a name */
01159   if ((FileNamePath=intT1_Env_GetCompletePath( pFontBase->pFontArray[FontID].pFontFileName, 
01160                                           T1_PFAB_ptr))==NULL) { 
01161     T1_PrintLog( "T1_GetFontFilePath()", "Couldn't locate font file for font %d in %s", 
01162                T1LOG_WARNING, FontID, T1_GetFileSearchPath(T1_PFAB_PATH)); 
01163     T1_errno=T1ERR_FILE_OPEN_ERR; 
01164     return(NULL); 
01165   } 
01166   
01167   strcpy( filepath, FileNamePath);
01168   free( FileNamePath);
01169   
01170   return( filepath);
01171   
01172 }
01173 
01174 
01175 
01176 /* We have a function for querying the name. Returns a pointer
01177    to the string or NULL if name was not explicitly set .*/
01178 char *T1_GetAfmFilePath( int FontID)
01179 {
01180   
01181   static char filepath[MAXPATHLEN+1];
01182   char *FontFileName;
01183   char *AFMFilePath;
01184   int i, j;
01185   
01186   /* is initialized? */
01187   if ((T1_CheckForInit())) {
01188     T1_errno=T1ERR_INVALID_FONTID;
01189     return(NULL);
01190   }
01191   
01192   /* Check first for valid FontID */
01193   if ((FontID<0) || (FontID>FontBase.no_fonts)){
01194     T1_errno=T1ERR_INVALID_FONTID;
01195     return(NULL);
01196   }
01197 
01198   /* Check wether AFM-file loading was suppressed on user's request */
01199   if ((pFontBase->t1lib_flags & T1_NO_AFM)!=0) {
01200     /* this is no error condition, we simply return (NULL) */
01201     return( NULL);
01202   }
01203   
01204   /* Check for explicitly associated metrics filename (via
01205      "T1_SetAfmFileName()"). If it exists, we return it! */
01206   if (pFontBase->pFontArray[FontID].pAfmFileName!=NULL) {
01207     strcpy( filepath, pFontBase->pFontArray[FontID].pAfmFileName);
01208     sprintf( err_warn_msg_buf, "Returning explicitly specified path %s for Font %d",
01209             filepath, FontID);
01210     T1_PrintLog( "T1_GetAfmFilePath()", err_warn_msg_buf, T1LOG_DEBUG);
01211     return( filepath);
01212   }
01213   
01214   /* we have the usual case that the name of the metrics file has to be
01215      deduced from the font file name */
01216   FontFileName=T1_GetFontFileName( FontID);
01217   i=strlen(FontFileName);
01218   j=i;
01219   strcpy( filepath, FontFileName);
01220   while ( filepath[i] != '.'){
01221     if (i==0) break;
01222     else i--;
01223   }
01224   if (i==0){
01225     /* We have a filename without extension -> append extension */
01226     filepath[j]='.';
01227     filepath[j+1]='a'; 
01228     filepath[j+2]='f'; 
01229     filepath[j+3]='m'; 
01230     filepath[j+4]='\0'; 
01231   }
01232   else{
01233     /* we found a '.' -> replace extension */
01234     filepath[i+1]='a';
01235     filepath[i+2]='f';
01236     filepath[i+3]='m';
01237     filepath[i+4]='\0';
01238   }
01239   /* Get full path of the afm file (The case of a full path name
01240      name specification is valid) */
01241   if ((AFMFilePath=intT1_Env_GetCompletePath( filepath, T1_AFM_ptr)) == NULL) {
01242     return NULL;
01243   }
01244   
01245   strcpy( filepath, AFMFilePath);
01246   free( AFMFilePath);
01247   
01248   return( filepath);
01249   
01250 }
01251 
01252