14 Utilities

      Error and Warning Messages
      Signals
      System Calls
      Strings Concat and compare
      String into Int
      Dynamic Memory Alloc
      myfseek
      Pattern Recognition Functions
      Shorthands and Mnemonics

Error and Warning Messages

<..signals messages: 2--4..>
 "Illegal storage address\n", 2 segmentation
 "Floating-point\n",          3 
 "Interrupt with Cntr-C\n",   4 
 -_-_-

<..warn and err messages..>
 <.command line options.>,                            0
 "Insufficient memory\n",                                1
 <.signals messages: 2--4.>
 "Can’t find/open file ‘%s’\n",                         5
 -_-_-

<..defines..>+
 #define bad_arg            err_arg(0)
 #define bad_mem             err_i(1)
 -_-_-

<..header functions..>+
 static void err_i( ARG_I(int) );
 -_-_-

<..functions..>+
 
 static void err_i(n)      int  n
 
 ;{  (IGNORED) fprintf(stderr,"--- error --- ");
    (IGNORED) fprintf(stderr, "%s", warn_err_mssg[n]);
    exit(EXIT_FAILURE);
 }
 -_-_-

<..header functions..>+
 static void err_arg( ARG_I(int) );
 -_-_-

<..functions..>+
 
 static void err_arg(n)      int  n
 
 ;{  (IGNORED) fprintf(stderr,"--- error --- ");
    (IGNORED) fprintf(stderr, "%s", warn_err_mssg[n]);
    exit(EXIT_FAILURE);
 }
 -_-_-

<..header functions..>+
 static void warn_i_str( ARG_II(int,const Q_CHAR *) );
 -_-_-

<..functions..>+
 
 static void warn_i_str(n,str)
     int  n;
     const Q_CHAR *str
 
 ;{  (IGNORED) fprintf(stderr,"--- warning --- ");
    (IGNORED) fprintf(stderr,warn_err_mssg[n], str);
 }
 -_-_-

<..vars..>+
 static const C_CHAR *warn_err_mssg[]={ <.warn and err messages.> "" };
 -_-_-

<..resplit argv for windows..>
 #ifdef WIN32
   /* See comments in tex4ht */
   if (argc > 2) {
     int  i, nargc;
     char **nargv, **pnargv, **pargv;
 
     nargv = (char **) xmalloc (2 * argc * sizeof (char *));
     pnargv = nargv;
     pargv = argv;
     *pnargv++ = xstrdup (*pargv++);
     *pnargv++ = xstrdup (*pargv++);
     nargc = 2;
 
     for (i=2; i < argc; i++) {
       char *p, *q, *r;
       p = q = *pargv++;
       while (*p ==   || *p == ’\t’) {
         p++;
         q++;
       }
       while (*p !=   && *p != ’\t’ && *p) {
         p++;
         if (*p == ’\0’) {
           *pnargv++ = xstrdup(q);
           nargc++;
         } else if (*p ==   || *p == ’\t’) {
           r = p;
           while (*p ==   || *p == ’\t’)
             p++;
           if (*p == ’-’ || *p == ’\0’) {
             *r = ’\0’;
             *pnargv++ = xstrdup(q);
             nargc++;
             q = p;
           }
         }
       }
     }
 
     nargv[nargc] = NULL;
     argv = nargv;
     argc = nargc;
   }
 #endif
 -_-_-

Signals

<..h-include..>+
 #include <signal.h>
 -_-_-

<..header functions..>+
 static void
 <.CDECL.>
 sig_err(ARG_I(int));
 -_-_-

<..functions..>+
 
 static void
 <.CDECL.>
 sig_err(s)  int s
 ;{
   (void) signal(s,SIG_IGN);  ignore the signal
   switch( s ){
 #ifdef SIGSEGV
     case SIGSEGV: err_i(2);
 #endif
     case SIGFPE : err_i(3);
 #if defined(SIGINT) && !defined(WIN32)
     case SIGINT : err_i(4);
 #endif
   }
   <.DJGPP signals.>
 }
 -_-_-

Forgetting ‘_pascal’ and ‘_cdecl’ modifiers: Each C function may be either ‘_pascal’ or ‘_cdecl’. This modifier defines how parameters are passed to it. Default for Smalltalk definition is ‘_cdecl’. Default for C functions depends on compiler settings, and you can use other types uncompatible with Smalltalk. In Windows API 16-bit functions are ‘_pascal’ and 32-bit ‘_cdecl’.

<..CDECL..>
 #ifdef CDECL
 CDECL
 #endif
 -_-_-

<..set signals..>
 
 #ifdef SIGSEGV
   (void) signal(SIGSEGV,sig_err);
 #endif
   (void) signal(SIGFPE,sig_err);
 #ifdef KWIN32
   <.KWIN32 signals.>
 #else
 #ifdef SIGINT
   (void) signal(SIGINT,sig_err);    Control-c, user interrupt
 #endif
 #endif
 -_-_-

SIGFPE is handled by the C library, SIGSEGV too but not generated by the system, so it does nothing but is harmless

SetConsoleCtrlHandler is need to catch Ctrl+C and Ctrl+Break under Windows, SIGINT is not generated by the system.

<..KWIN32 signals..>
 SetConsoleCtrlHandler((PHANDLER_ROUTINE)sigint_handler, TRUE);
 -_-_-

SIGSEGV, SIGILL, SIGTERM not implemented in MS-DOS. They are supplied just for compatibility. Looks like that SIGINT is defined for windows but not for dos. [more]

Msvc recommends not using printf, but we ignoring this recommendation here with the assumption that the recommendation relates to I/O interrupts that are not considered here.

<..header functions..>+
 #ifdef KWIN32
 static BOOL sigint_handler(ARG_I(DWORD));
 #endif
 -_-_-

<..functions..>+
 #ifdef KWIN32
 
 static BOOL sigint_handler(dwCtrlType)     DWORD dwCtrlType
 ;{
   err_i(32);
   return FALSE;       return value obligatory 
 }
 #endif
 -_-_-

System Calls

<..vars..>+
 static Q_CHAR command[255];
 static int system_return;
 -_-_-

The library ‘<stdlib.h>’ includes a function ‘int system(const char *cmdstring);’. When cmdstring is NULL, the return value is 0 iff the platform does not support system calls.

<..vars..>+
 static BOOL system_yes;
 -_-_-

<..main’s init..>+
 {                   C_CHAR   *yes = NULL;
   system_yes = (<.system exist?.>);
 }
 -_-_-

Solaris-? issues the command ‘-c: bad option(s)’ if we check for the presence of the system function.

<..system exist?..>
 #ifdef SYSTEM_FUNCTION_OK
 0
 #else
 system( yes ) != 0
 #endif
 -_-_-

<..execute system command..>
 (IGNORED) call_sys(command);
 -_-_-

<..header functions..>+
 static void call_sys(ARG_I(Q_CHAR *));
 -_-_-

<..functions..>+
 
 static void call_sys(command)  Q_CHAR * command
 ;{
    if( *command ){
       (IGNORED) printf("System call: %s\n", command);
       system_return = system_yes?  (int) system(command) : -1;
       (IGNORED) printf("%sSystem return: %d\n",
             system_return? "--- Warning --- " : "", system_return );
       if( always_call_sys ){ system_return = 0; }
    }
 }
 -_-_-

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

Strings Concat and compare

<..defines..>+
 #define eq_str(x,y) (!strcmp(x,y))
 -_-_-

strcat should be in string.h, but c++ doesn’t find it there. We use it just for concatenating an extension of file name. Should have the interface ‘char *strcat( ARG_II(C_CHAR *, const Q_CHAR *) );’.

<..header functions..>+
 static void strct( ARG_II(C_CHAR *, const C_CHAR *) );
 -_-_-

<..functions..>+
 
 static void strct( str1, str2 )
      C_CHAR * str1;
      const C_CHAR * str2
 
 ;{   Q_CHAR * ch;
    ch = str1 + (int) strlen((char *) str1);
    (IGNORED) strcpy((char *)  ch, str2 );
 }
 -_-_-

String into Int

<..header functions..>+
 static long int get_long_int( ARG_I(Q_CHAR *) );
 -_-_-

<..functions..>+
 
 static long int get_long_int(str)
                          Q_CHAR   *str
 ;{                  long int    i;
                          Q_CHAR   *ch;
    ch = str;   i = 0;
    while( (*ch>= ’0’) && (*ch <=’9’) ){
      i = 10*i + *(ch++) - ’0’;
    }
    return i;
 }
 -_-_-

Dynamic Memory Alloc

<..defines..>+
 #define m_alloc(typ,n) (typ *) malloc_chk((int) ((n) * sizeof(typ)))
 -_-_-

<..header functions..>+
 static void* malloc_chk(ARG_I(int));
 -_-_-

<..functions..>+
 
 static void* malloc_chk( n ) int n
 ;{      void* p;
    if((p = (void *) malloc( (size_t) n)) == NULL ) bad_mem;
    return p;
 }
 -_-_-

<..header functions..>+
 static void* r_alloc(ARG_II(void *, size_t));
 -_-_-

<..functions..>+
 
 static void* r_alloc( q, n )
       void   *q;
       size_t  n
 ;{    void*   p;
    if((p = (void *) realloc( q, (size_t) n)) == NULL) bad_mem;
    return p;
 }
 -_-_-

myfseek

The ftell() and fseek() are not consistent in ms-windows. The ftell() accounts for <cr> and <lf> in the byte stream, where fseek() ignore the �cr� bytes. A READ_BIN_FLAGS instead of READ_TEXT_FLAGS seems to solve the problem.

<..CopyTo read flags..>
 READ_BIN_FLAGS
 -_-_-

A possible alternative is to define a private fseek.

Pattern Recognition Functions

When failure (false status) arises, the input line is consumed to its end. The _until functions place in ”match[i]’ the string found.

<..header functions..>+
 static BOOL scan_until_end_str( ARG_IV(const C_CHAR *, int, BOOL, FILE *) );
 -_-_-

<..functions..>+
 
 static BOOL  scan_until_end_str(str,n,flag,file)
                          const C_CHAR   *str;
                          int    n;
                          BOOL   flag;
                          FILE*  file
 ;{                       Q_CHAR   *p;
                          int i;
    if( !flag ) { return flag; }
    p = match[n];  i = 0;
    while( TRUE ){
      if( (i+1) >= max_match[n] ){
         max_match[n] += 10;
         p = match[n] = (Q_CHAR *)
                      r_alloc((void *) match[n], (size_t) max_match[n]);
      }
      p[i] = (char) (eoln_ch = getc(file));
      if( (eoln_ch == (int) ’\n’) || (eoln_ch == EOF) ){  break; }
      i++;
    }
    p[i] = ’\0’;
    i -= (int) strlen(str);
    if( i>= 0 ){  return eq_str(p+i,str);   }
    return FALSE;
 }
 -_-_-

<..vars..>+
 static Q_CHAR* match[10];
 static int   max_match[10];
 -_-_-

<..main’s init..>+
 {          int i;
   for( i=0;  i<=9; i++){
     match[i] = (Q_CHAR *) malloc(70);
     max_match[i] = 70;
   }
 }
 -_-_-

<..header functions..>+
 static BOOL scan_until_str( ARG_IV(const C_CHAR *, int, BOOL, FILE *) );
 -_-_-

<..functions..>+
 
 static BOOL  scan_until_str(str,n,flag,file)
                          const C_CHAR   *str;
                          int    n;
                          BOOL   flag;
                          FILE*  file
 ;{                       Q_CHAR   *p, ch;
                          int i, j;
    if( !flag ) { return flag; }
    p = match[n];  i = 0;
    while( TRUE ){
      ch =  (char) (eoln_ch = getc(file));
      if( (eoln_ch == (int) ’\n’) || (eoln_ch == EOF) ){  return FALSE; }
      if( (i+1) >= max_match[n] ){
         max_match[n] += 10;
         p = match[n] = (Q_CHAR *)
                      r_alloc((void *) match[n], (size_t) max_match[n]);
      }
      p[i++] = ch;
      j =  i - (int) strlen(str);
      if( j>= 0 ){
        p[i] = ’\0’;
        if( eq_str(p+j,str) ) { return TRUE;  }
      }
    }
 }
 -_-_-

<..header functions..>+
 static BOOL scan_str( ARG_III(const C_CHAR *, BOOL, FILE *) );
 -_-_-

<..functions..>+
 
 static BOOL  scan_str(str,flag,file)
                          const C_CHAR   *str;
                          BOOL   flag;
                          FILE*  file
 ;{                        const Q_CHAR *p;
                          int temp_eoln_ch;
    if( !flag ) { return flag; }
    p = str;
    while( *p != ’\0’ ){
      if( *(p++) != (temp_eoln_ch = getc(file)) ) {
         while( (temp_eoln_ch != (int) ’\n’)
             && (temp_eoln_ch != EOF) ){ temp_eoln_ch = getc(file); }
         eoln_ch = temp_eoln_ch;  return FALSE;
      }
    }
    return TRUE;
 }
 -_-_-

Shorthands and Mnemonics

<..defines..>+
 #ifndef TRUE
 #define TRUE 1
 #endif
 #ifndef FALSE
 #define FALSE 0
 #endif
 #ifndef BOOL
 #define BOOL int
 #endif
 -_-_-

<..defines..>+
 #define eq_str(x,y) (!strcmp(x,y))
 -_-_-