1#include <ctype.h>		/* ANSI C */
2#include <errno.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <stdarg.h>
7#include <time.h>
8
9#include "efaxmsg.h"
10
11#define MAXTSTAMP 80		/* maximum length of a time stamp */
12#define MAXMSGBUF 4096		/* maximum status/error message bytes held */
13
14#define NLOG 2
15
16char *verb[NLOG] = { "ewin", "" } ;
17char *argv0 = "" ;
18
19int nxtoptind = 1 ;		/* for communication with nextopt() */
20char *nxtoptarg ;
21
22
23/* For systems without strerror(3) */
24
25#ifdef NO_STRERROR
26extern int sys_nerr;
27extern char *sys_errlist[];
28
29extern char *strerror( int i )
30{
31  return ( i >= 0 && i < sys_nerr ) ? sys_errlist[i] : "Unknown Error" ;
32}
33#endif
34
35
36/* Print time stamp. */
37
38time_t tstamp ( time_t last, FILE *f )
39{
40  time_t now ;
41  char tbuf [ MAXTSTAMP ] ;
42
43  now = time ( 0 ) ;
44
45  if (strftime ( tbuf, MAXTSTAMP,  ( now - last > 600 ) ? "%c" : "%M:%S",
46	    localtime( &now ) ))
47    fputs ( tbuf, f ) ;
48
49  return now ;
50}
51
52
53/* Return string corresponding to character c. */
54
55char *cname ( uchar c )
56{
57#define CNAMEFMT "<0x%02x>"
58#define CNAMELEN 6+1
59  static char *cnametab [ 256 ] = { /* character names */
60  "<NUL>","<SOH>","<STX>","<ETX>", "<EOT>","<ENQ>","<ACK>","<BEL>",
61  "<BS>", "<HT>", "<LF>", "<VT>",  "<FF>", "<CR>", "<SO>", "<SI>",
62  "<DLE>","<XON>","<DC2>","<XOFF>","<DC4>","<NAK>","<SYN>","<ETB>",
63  "<CAN>","<EM>", "<SUB>","<ESC>", "<FS>", "<GS>", "<RS>", "<US>" } ;
64  static char names[ (127-32)*2 + 129*(CNAMELEN) ] ;
65  char *p=names ;
66  static int i=0 ;
67
68  if ( ! i ) {
69    for ( i=32 ; i<256 ; i++ ) {
70      cnametab [ i ] = p ;
71      sprintf ( p, i<127 ? "%c" : CNAMEFMT, i ) ;
72      p += strlen ( p ) + 1 ;
73    }
74  }
75
76  return cnametab [ c ] ;
77}
78
79/* If a non-NULL parameter is passed in then that string
80 * is saved as the copyright string to be printed with the
81 * first call to msg(). If a NULL parameter is passed in then
82 * the copyright string is not changed. The function always
83 * returns the current copyright string.
84 */
85const char *setCopyright(const char *copyright)
86{
87    static const char *sCopyright = NULL;
88
89    if (copyright != NULL) {
90        if (sCopyright != NULL) free((char*)sCopyright);
91        sCopyright = strdup(copyright);
92    }
93
94    return sCopyright;
95}
96
97/* Print a message with a variable number of printf()-type
98   arguments if the first character appears in the global
99   verb[ose] string.  Other leading characters and digits do
100   additional actions: + allows the message to be continued on
101   the same line, '-' buffers the message instead of printing it,
102   E, and W expand into strings, S prints the error message for
103   the most recent system error, a digit sets the return value, a
104   space ends prefix but isn't printed.  Returns 0 if no prefix
105   digit. */
106
107enum  msgflags { E=0x01, W=0x02, S=0x04, NOFLSH=0x08, NOLF=0x10 } ;
108
109
110int msg ( char *fmt, ... )
111{
112  static int init=0 ;
113  static FILE *logfile [ NLOG ] ;
114  static char msgbuf [ NLOG ] [ MAXMSGBUF ] ;
115  static time_t logtime [ NLOG ] = { 0, 0 } ;
116  static int atcol1 [ NLOG ] = { 1, 1 } ;
117  static int copyrightSent [ NLOG ] = { 0, 0 } ;
118
119  int err=0, i, flags=0 ;
120  char *p ;
121
122  va_list ap ;
123  va_start ( ap, fmt ) ;
124
125  if ( ! init ) {
126    logfile[0] = stderr ;
127    logfile[1] = stdout ;
128    for ( i=0 ; i<NLOG ; i++ )
129      setvbuf ( logfile[i], msgbuf[i], _IOLBF, MAXMSGBUF ) ;
130    cname ( 0 ) ;
131    init = 1 ;
132  }
133
134  for ( i=0 ; i<NLOG ; i++ ) {
135
136    for ( p=fmt ; *p ; p++ ) {
137      switch ( *p ) {
138      case ' ': p++ ; goto print ;
139      case 'E': flags |= E ; break ;
140      case 'W': flags |= W ; break ;
141      case 'S': flags |= S ; break ;
142      case '+': flags |= NOLF ; break ;
143      case '-': flags |= NOFLSH ; break ;
144      default:
145	if ( isdigit ( *p ) ) {
146	  err = *p - '0' ;
147	} else if ( ! isupper ( *p ) ) {
148	  goto print ;
149	}
150      }
151    }
152
153    print:
154
155    if ( strchr ( verb[i], tolower ( *fmt ) ) ) {
156
157      if ( !copyrightSent[i] ) {
158        if ( setCopyright(NULL) ) fputs ( setCopyright(NULL), logfile[i] );
159        copyrightSent[i] = 1;
160      }
161
162      if ( atcol1[i] ) {
163	fprintf ( logfile[i], "%s: ", argv0 ) ;
164	logtime[i] = tstamp ( logtime[i], logfile[i] ) ;
165	fputs ( ( flags & E ) ? " Error: " :
166		( flags & W ) ? " Warning: " :
167		" ",
168		logfile[i] ) ;
169      }
170      vfprintf( logfile[i], p, ap ) ;
171      if ( flags & S ) fprintf ( logfile[i], " %s", strerror ( errno ) ) ;
172      if ( ! ( flags & NOLF ) ) fputs ( "\n", logfile[i] ) ;
173      atcol1[i] = flags & NOLF ? 0 : 1 ;
174      if ( ! ( flags & NOFLSH ) ) fflush ( logfile[i] ) ;
175
176    }
177
178  }
179
180  va_end ( ap ) ;
181
182  return err ;
183}
184
185
186/* Simple (one option per argument) version of getopt(3). */
187
188int nextopt( int argc, char **argv, char *args )
189{
190  char *a, *p ;
191
192  if ( nxtoptind >= argc || *(a = argv[nxtoptind]) != '-' ) return -1 ;
193  nxtoptind++ ;
194
195  if ( ! *(a+1) || ( ( p = strchr ( args, *(a+1) ) ) == 0 ) )
196    return msg ( "Eunknown option (%s)", a ), '?' ;
197
198  if ( *(p+1) != ':' ) nxtoptarg = 0 ;
199  else
200    if ( *(a+2) ) nxtoptarg = a+2 ;
201    else
202      if ( nxtoptind >= argc ) return msg ( "Eno argument for (%s)", a ), '?' ;
203      else nxtoptarg = argv [ nxtoptind++ ] ;
204  return *(a+1) ;
205}
206
207