1 
2 #include <stdio.h>
3 #if __STDC__
4 #include <stdlib.h>
5 #include <locale.h>
6 #else
7 #include <malloc.h>
8 #endif
9 #include <ctype.h>
10 #include <string.h>
11 #include <time.h>
12 
13 #include "cc.h"
14 
15 #define MAXINCPATH	5
16 
17 int main P((int argc, char ** argv));
18 void undefine_macro P((char * name));
19 void define_macro P((char * name));
20 void print_toks_cpp P((void));
21 void print_toks_raw P((void));
22 void define_macro P((char *));
23 void undefine_macro P((char *));
24 void cmsg P((char * mtype, char * str));
25 char * token_txn P((int));
26 void pr_indent P((int));
27 void hash_line P((void));
28 
29 char * include_paths[MAXINCPATH];
30 
31 char last_name[512] = "";
32 int last_line = -1;
33 int debug_mode = 0;
34 int p_flag = 0;
35 int exit_code = 0;
36 
37 char * outfile = 0;
38 FILE * ofd = 0;
39 
40 int
main(argc,argv)41 main(argc, argv)
42 int argc;
43 char ** argv;
44 {
45    int ar, i;
46    char * p;
47 static char Usage[] = "Usage: cpp -E -0 -Dxxx -Uxxx -Ixxx infile -o outfile";
48 
49 #ifdef LC_CTYPE
50    setlocale(LC_CTYPE, "");
51 #endif
52 
53    alltok = 1;	/* Get all tokens from the cpp. */
54 
55    for(ar=1; ar<argc; ar++) if( argv[ar][0] == '-') switch(argv[ar][1])
56    {
57    case 'd': debug_mode++; break;
58    case 'T': alltok = 0; break;
59    case 'A': dialect = DI_ANSI; break;
60    case 'K': dialect = DI_KNR; break;
61 
62 	     /* Some options for describing the code generator. */
63    case '0': define_macro("__BCC__");
64 	     define_macro("__AS386_16__");
65 	     define_macro("__8086__");
66 	     break;
67    case '3': define_macro("__BCC__");
68 	     define_macro("__AS386_32__");
69 	     define_macro("__i386__");
70 	     break;
71    case 'c': define_macro("__CALLER_SAVES__");
72 	     break;
73    case 'f': define_macro("__FIRST_ARG_IN_AX__");
74 	     break;
75    case 'O': define_macro("__OPTIMISED__");
76 	     break;
77 
78    case 'C': /* Keep comments. */
79 	     cwarn("-C not implemented");
80 	     break;
81    case 'P': p_flag++;
82 	     break;
83 
84    case 'I':
85 	     if (argv[ar][2]) p=argv[ar]+2;
86 	     else {
87 		ar++;
88 		if (ar>=argc) cfatal(Usage);
89 		p = argv[ar];
90 	     }
91 	     for(i=0; i<MAXINCPATH; i++)
92 		if (!include_paths[i]) {
93 		   include_paths[i] = p;
94 		   break;
95 		}
96 	     if (i>=MAXINCPATH)
97 		cfatal("Too many items in include path for CPP");
98 	     break;
99    case 'D':
100 	     if (argv[ar][2]) p=argv[ar]+2;
101 	     else {
102 		ar++;
103 		if (ar>=argc) cfatal(Usage);
104 		p = argv[ar];
105 	     }
106 	     define_macro(p);
107 	     break;
108    case 'U':
109 	     if (argv[ar][2]) p=argv[ar]+2;
110 	     else {
111 		ar++;
112 		if (ar>=argc) cfatal(Usage);
113 		p = argv[ar];
114 	     }
115 	     undefine_macro(p);
116 	     break;
117    case 'o':
118 	     if (argv[ar][2]) p=argv[ar]+2;
119 	     else {
120 		ar++;
121 		if (ar>=argc) cfatal(Usage);
122 		p = argv[ar];
123 	     }
124 	     if (outfile) cfatal(Usage);
125 	     outfile = p;
126 	     break;
127    default:
128 	     fprintf(stderr, "CPP Unknown option %s\n", argv[ar]);
129 	     cfatal(Usage);
130    } else if (!curfile) {
131       /* Input file */
132       curfile = fopen(argv[ar], "r");
133       c_fname = argv[ar]; c_lineno = 1;
134       if (!curfile)
135 	 cfatal("Cannot open input file");
136    } else
137       cfatal(Usage);
138 
139    if (!curfile)
140       cfatal(Usage);
141 
142    /* Define date and time macros. */
143    if (dialect != DI_KNR) {
144       time_t now;
145       char * timep;
146       char buf[128];
147       time(&now);
148       timep = ctime(&now);
149 
150       /* Yes, well */
151       sprintf(buf, "__TIME__=\"%.8s\"", timep + 11);
152       define_macro(buf);
153       /* US order; Seems to be mandated by standard. */
154       sprintf(buf, "__DATE__=\"%.3s %.2s %.4s\"", timep + 4, timep + 8, timep + 20);
155       define_macro(buf);
156    }
157 
158    if (outfile) ofd = fopen(outfile, "w");
159    else         ofd = stdout;
160    if (!ofd)
161       cfatal("Cannot open output file");
162 
163    if (debug_mode)
164       print_toks_raw();
165    else
166       print_toks_cpp();
167 
168    if (outfile) fclose(ofd);
169    exit(exit_code);
170 }
171 
172 void
undefine_macro(name)173 undefine_macro(name)
174 char * name;
175 {
176    struct define_item * ptr;
177 
178    ptr = read_entry(0, name);
179    if (ptr) {
180       set_entry(0, name, (void*)0);
181       if (!ptr->in_use) free(ptr);
182    }
183 }
184 
185 void
define_macro(name)186 define_macro(name)
187 char * name;
188 {
189    char * p;
190    char * value;
191    struct define_item * ptr;
192 
193    if ((p=strchr(name, '=')) != 0) {
194       *p = 0;
195       value = p+1;
196    } else
197       value = "1";
198 
199    undefine_macro(name);
200 
201    ptr = malloc(sizeof(struct define_item) + strlen(value));
202    ptr->name = set_entry(0, name, ptr);
203    strcpy(ptr->value, value);
204    ptr->arg_count = -1;
205    ptr->in_use = 0;
206    ptr->next = 0;
207 }
208 
209 FILE *
open_include(fname,mode,checkrel)210 open_include(fname, mode, checkrel)
211 char * fname;
212 char * mode;
213 int checkrel;
214 {
215    FILE * fd = 0;
216    int i;
217    char buf[256], *p;
218 
219    if( checkrel )
220    {
221       strcpy(buf, c_fname);
222       p = strrchr(buf, '/');
223       if (p) *++p = 0; else *(p=buf) = 0;
224       strcpy(p, fname);
225 
226       fd=fopen(buf, mode);
227    }
228    if (!fd) {
229       for(i=0; i<MAXINCPATH; i++)
230 	 if (include_paths[i]) {
231 	   strcpy(buf, include_paths[i]);
232 	   if (buf[strlen(buf)-1] != '/') strcat(buf, "/");
233 	   strcat(buf, fname);
234 	   fd=fopen(buf,  mode);
235 	   if( fd ) break;
236 	 }
237    }
238    if (!fd) return fd;
239    c_fname = strdup(buf);
240    c_lineno = 1;
241 
242    return fd;
243 }
244 
245 /*----------------------------------------------------------------------*/
246 
247 static int outpos = 0;
248 
249 void
cmsg(mtype,str)250 cmsg(mtype, str)
251 char * mtype;
252 char * str;
253 {
254    if (c_fname && (*c_fname || c_lineno))
255       fprintf(stderr, "%s:%d: ", c_fname, c_lineno);
256 
257    if (mtype && *mtype)
258       fprintf(stderr, "%s: %s\n", mtype, str);
259    else
260       fprintf(stderr, "%s\n", str);
261 }
262 
263 void
cfatal(str)264 cfatal(str)
265 char * str;
266 {
267    cmsg("CPP-FATAL error", str);
268    exit(255);
269 }
270 
271 void
cerror(str)272 cerror(str)
273 char * str;
274 {
275    exit_code = 1;
276    cmsg("error", str);
277 }
278 
279 void
cwarn(str)280 cwarn(str)
281 char * str;
282 {
283    cmsg("warning", str);
284 }
285 
286 void
pr_indent(count)287 pr_indent(count)
288 int count;
289 {
290    if(count>10) count=10;
291    while(count>0) {fprintf(ofd, "\t"); count--; }
292 }
293 
294 void
hash_line()295 hash_line()
296 {
297    if( strcmp(last_name, c_fname) != 0 ) last_line = -1;
298    if( c_lineno != last_line || last_line <= 0 )
299    {
300       if( outpos != 0 ) {
301 	 fputc('\n', ofd); outpos=0;
302 	 if (last_line > 0) last_line++;
303       }
304       while( c_lineno > last_line &&
305              (p_flag || c_lineno < last_line+4) &&
306 	     last_line > 0 &&
307 	    !debug_mode )
308       {
309 	 fputc('\n', ofd); last_line++;
310       }
311 
312       if( !p_flag && (c_lineno != last_line || last_line <= 0 ))
313       {
314 	 fprintf(ofd, "# %d", c_lineno);
315 	 if( last_line <= 0 ) fprintf(ofd, " \"%s\"", c_fname);
316 	 fprintf(ofd, "\n");
317       }
318 
319       strcpy(last_name, c_fname);
320       last_line = c_lineno;
321    }
322 }
323 
324 void
print_toks_cpp()325 print_toks_cpp()
326 {
327    int i;
328    int indent=0;
329    int paren=0;
330 
331    hash_line();
332    while( (i=gettok()) != EOF )
333    {
334       hash_line();
335       switch(i)
336       {
337       case '\n':
338 	 cwarn("newline received from tokeniser!");
339 	 break;
340 
341       case TK_STR:
342 	 outpos += fprintf(ofd, "%s", curword);
343 	 break;
344 
345       case TK_COPY:
346 	 if( outpos ) { fputc('\n', ofd); last_line++; }
347 	 outpos = 0; last_line++;
348 	 fprintf(ofd, "#%s\n", curword);
349 	 break;
350 
351       case TK_FILE: sprintf(curword, "\"%s\"", c_fname); if(0) {
352       case TK_LINE: sprintf(curword, "%d", c_lineno);
353 		    }
354 		    /*FALLTHROUGH*/
355       default:
356 	 if (!alltok) {
357 	    if(i == '}' || i == TK_CASE || i == TK_DEFAULT ) indent--;
358 	    if(i ==')') paren--;
359 
360 	    if(outpos) { fputc(' ', ofd); outpos++; }
361 	    else pr_indent(indent+(paren!=0));
362 
363 	    if(i == '{' || i == TK_CASE || i == TK_DEFAULT ) indent++;
364 	    if(i ==';') paren=0;
365 	    if(i =='(') paren++;
366 	 }
367 
368 	 outpos += fprintf(ofd, "%s", curword);
369 
370 	 if ( i == '"' || i == '\'' )
371 	 {
372 	    while((i=gettok()) == TK_STR) {
373 	       outpos += fprintf(ofd, "%s", curword);
374 	    }
375 	    if (i != '\n')
376 	       outpos += fprintf(ofd, "%s", curword);
377 	 }
378 	 break;
379       }
380    }
381    if( outpos ) fputc('\n', ofd);
382    outpos = 0;
383 }
384 
385 void
print_toks_raw()386 print_toks_raw()
387 {
388    int i;
389    long val;
390 
391    hash_line();
392    while( (i=gettok()) != EOF )
393    {
394       hash_line();
395       switch(i)
396       {
397       case '"': case '\'':
398 		     if (debug_mode < 2) {
399 			fprintf(ofd, "%-16s: %s", "Quoted string", curword);
400 			while((i=gettok()) == TK_STR)
401 			   outpos+= fprintf(ofd, "%s", curword);
402 			if ( i == '\n' ) fprintf(ofd, " --> EOL!!\n");
403 			else    outpos+= fprintf(ofd, "%s\n", curword);
404 			break;
405 		     }
406 		     /*FALLTHROUGH*/
407       default:       fprintf(ofd, "%-16s: '", token_txn(i));
408 		     {
409 			char *p;
410 			for(p=curword; *p; p++)
411 			   if(isprint(*p) && *p != '\'' && *p != '\\')
412 			      fputc(*p, ofd);
413 			   else if (*p == '\n') fprintf(ofd, "\\n");
414 			   else if (*p == '\t') fprintf(ofd, "\\t");
415 			   else if (*p == '\v') fprintf(ofd, "\\v");
416 			   else if (*p == '\b') fprintf(ofd, "\\b");
417 			   else if (*p == '\r') fprintf(ofd, "\\r");
418 			   else if (*p == '\f') fprintf(ofd, "\\f");
419 			   else if (*p == '\a') fprintf(ofd, "\\a");
420 			   else
421 			      fprintf(ofd, "\\x%02x", (unsigned char)*p);
422 		     }
423 		     fprintf(ofd, "'\n");
424 		     break;
425       case TK_NUM:
426 		     val = strtoul(curword, (void*)0, 0);
427 		     fprintf(ofd, "%-16s: ", token_txn(i));
428 		     fprintf(ofd, "%s => %ld\n", curword, val);
429 		     break;
430       case TK_COPY:
431 		     fprintf(ofd, "%-16s: ", token_txn(i));
432 		     fprintf(ofd, "#%s\n", curword);
433 		     break;
434       case '\n':
435 		     fprintf(ofd, "%-16s:\n", "Newline char");
436 		     break;
437       }
438    }
439 }
440 
441 char *
token_txn(token)442 token_txn(token)
443 int token;
444 {
445    char * s = "UNKNOWN";
446    static char buf[17];
447 
448    if (token> ' ' && token <= '~')
449    {
450       sprintf(buf, "TK_CHAR('%c')", token);
451       return buf;
452    }
453    if (token >= 0 && token < 0x100)
454    {
455       sprintf(buf, "TK_CHAR(%d)", token);
456       return buf;
457    }
458 
459    switch(token)
460    {
461    case TK_WSPACE       : s="TK_WSPACE"; break;
462    case TK_WORD         : s="TK_WORD"; break;
463    case TK_NUM          : s="TK_NUM"; break;
464    case TK_FLT          : s="TK_FLT"; break;
465    case TK_QUOT         : s="TK_QUOT"; break;
466    case TK_STR          : s="TK_STR"; break;
467    case TK_FILE         : s="TK_FILE"; break;
468    case TK_LINE         : s="TK_LINE"; break;
469    case TK_COPY         : s="TK_COPY"; break;
470    case TK_NE_OP        : s="TK_NE_OP"; break;
471    case TK_MOD_ASSIGN   : s="TK_MOD_ASSIGN"; break;
472    case TK_AND_OP       : s="TK_AND_OP"; break;
473    case TK_AND_ASSIGN   : s="TK_AND_ASSIGN"; break;
474    case TK_MUL_ASSIGN   : s="TK_MUL_ASSIGN"; break;
475    case TK_INC_OP       : s="TK_INC_OP"; break;
476    case TK_ADD_ASSIGN   : s="TK_ADD_ASSIGN"; break;
477    case TK_DEC_OP       : s="TK_DEC_OP"; break;
478    case TK_SUB_ASSIGN   : s="TK_SUB_ASSIGN"; break;
479    case TK_PTR_OP       : s="TK_PTR_OP"; break;
480    case TK_ELLIPSIS     : s="TK_ELLIPSIS"; break;
481    case TK_DIV_ASSIGN   : s="TK_DIV_ASSIGN"; break;
482    case TK_LEFT_OP      : s="TK_LEFT_OP"; break;
483    case TK_LEFT_ASSIGN  : s="TK_LEFT_ASSIGN"; break;
484    case TK_LE_OP        : s="TK_LE_OP"; break;
485    case TK_EQ_OP        : s="TK_EQ_OP"; break;
486    case TK_GE_OP        : s="TK_GE_OP"; break;
487    case TK_RIGHT_OP     : s="TK_RIGHT_OP"; break;
488    case TK_RIGHT_ASSIGN : s="TK_RIGHT_ASSIGN"; break;
489    case TK_XOR_ASSIGN   : s="TK_XOR_ASSIGN"; break;
490    case TK_OR_ASSIGN    : s="TK_OR_ASSIGN"; break;
491    case TK_OR_OP        : s="TK_OR_OP"; break;
492    case TK_AUTO         : s="TK_AUTO"; break;
493    case TK_BREAK        : s="TK_BREAK"; break;
494    case TK_CASE         : s="TK_CASE"; break;
495    case TK_CHAR         : s="TK_CHAR"; break;
496    case TK_CONST        : s="TK_CONST"; break;
497    case TK_CONTINUE     : s="TK_CONTINUE"; break;
498    case TK_DEFAULT      : s="TK_DEFAULT"; break;
499    case TK_DO           : s="TK_DO"; break;
500    case TK_DOUBLE       : s="TK_DOUBLE"; break;
501    case TK_ELSE         : s="TK_ELSE"; break;
502    case TK_ENUM         : s="TK_ENUM"; break;
503    case TK_EXTERN       : s="TK_EXTERN"; break;
504    case TK_FLOAT        : s="TK_FLOAT"; break;
505    case TK_FOR          : s="TK_FOR"; break;
506    case TK_GOTO         : s="TK_GOTO"; break;
507    case TK_IF           : s="TK_IF"; break;
508    case TK_INT          : s="TK_INT"; break;
509    case TK_LONG         : s="TK_LONG"; break;
510    case TK_REGISTER     : s="TK_REGISTER"; break;
511    case TK_RETURN       : s="TK_RETURN"; break;
512    case TK_SHORT        : s="TK_SHORT"; break;
513    case TK_SIGNED       : s="TK_SIGNED"; break;
514    case TK_SIZEOF       : s="TK_SIZEOF"; break;
515    case TK_STATIC       : s="TK_STATIC"; break;
516    case TK_STRUCT       : s="TK_STRUCT"; break;
517    case TK_SWITCH       : s="TK_SWITCH"; break;
518    case TK_TYPEDEF      : s="TK_TYPEDEF"; break;
519    case TK_UNION        : s="TK_UNION"; break;
520    case TK_UNSIGNED     : s="TK_UNSIGNED"; break;
521    case TK_VOID         : s="TK_VOID"; break;
522    case TK_VOLATILE     : s="TK_VOLATILE"; break;
523    case TK_WHILE        : s="TK_WHILE"; break;
524    }
525    return s;
526 }
527