chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / macros.c
1
2 /* Copyright (c) 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2004, 2005, 2006 by Arkkra Enterprises */
3 /* All rights reserved */
4
5 /* functions to support Mup macros */
6
7 /* When a macro is defined, its text is copied to a file. When a macro is
8  * invoked, information about the current input file is pushed on a stack,
9  * and the macro text is read from the macro file. This file also has the
10  * code to handle include files. They are handled similarly. Info about the
11  * current file is pushed on a stack, and text is read from the included
12  * file. */
13
14 #include <string.h>
15 #include <fcntl.h>
16 #include "globals.h"
17
18 #ifdef VMS
19 #define unlink delete
20 #endif
21
22 /* size of macro name hash table. should be prime, big enough to not have too
23  * many collisions, small enough to not use too much memory. */
24 #define MTSIZE  (79)
25
26 /* how many bytes to allocate at a time when collecting macro arguments */
27 #define MAC_ARG_SZ      (512)
28
29 /* We may need just a plain copy of the text passed as a macro parameter,
30  * or a quoted copy, or both. These flags say which we need.
31  * This is currently only actually implemented in a limited form:
32  * we always generate an unquoted copy, and if there is any chance any
33  * parameter in a macro will be needed in quoted form, we make quoted
34  * copies of all parameters for that macro. This is because to really
35  * figure out unequivicably which we need would be complicated enough
36  * that we'd probably wind up spending more than we'd save,
37  * so just doing this half-hearted optimization seems like the best tradeoff.
38  */
39 #define QS_UNQUOTED     (0x1)
40 #define QS_QUOTED       (0x2)
41
42 /* information about a macro parameter */
43 struct MAC_PARAM {
44         char    *param_name;    /* name of the parameter */
45         int     quote_style;    /* bitmap of QS_* values */
46         struct MAC_PARAM *next; /* for linked list */
47 };
48
49 /* info about a macro */
50 struct MACRO {
51         char    *macname;       /* name of macro */
52         char    *filename;      /* file in which macro was defined */   
53         int     lineno;         /* line in file where macro definition began */
54         int     lineoffset;     /* how many lines we are into macro */
55         long    offset;         /* offset in macro temporary file where the
56                                  * text of the macro is stored for later use */
57         long    quoted_offset;  /* offset into macro temp file where the
58                                  * quoted version is stored, if any.
59                                  * Only used on macro parameters. */
60         struct MACRO    *next;  /* for hash collision list */
61         int     recursion;      /* incremented each time the macro is called,
62                                  * and decremented on completion. If this gets
63                                  * above 1 we are in trouble and ufatal */
64         int     num_params;     /* how many parameters */
65         struct  MAC_PARAM *parameters_p;        /* list of macro parameter
66                                  * names. Null if this macro doesn't
67                                  * have parameters */
68 };
69
70 /* macro information hash table */
71 static struct MACRO *Mactable[MTSIZE];
72
73 /* temporary file for saving text of macros. Need separate handles for reading
74  * and writing */
75 static FILE *Mactmp_read = (FILE *) 0;
76 static FILE *Mactmp_write = (FILE *) 0;
77 #ifdef UNIX_LIKE_FILES
78 static char Macfile[] = "mupmacXXXXXX";         /* name of temp file */
79 #else
80 /* As last resort, we use a temp file name of 11 character length,
81  * so make sure we have enough room for that. Usually L_tmpnam is
82  * already longer than that, but better safe than core dump.
83  */
84 #if L_tmpnam < 12
85 #undef L_tmpnam
86 #define L_tmpnam 12
87 #endif
88 static char Macfile[L_tmpnam];          /* name of temp file */
89 #endif
90
91 /* Some OSs require us to open files in binary mode. Most implementations
92  * of fopen these days accept the 'b' suffix, even when they don't care
93  * about it, but to be safe, we only add on systems that appear to have
94  * binary mode defined. */
95 #ifdef O_BINARY
96 static char *Read_mode = "rb";
97 #ifndef UNIX_LIKE_FILES
98 static char *Write_mode = "wb";
99 static char *Append_mode = "ab";
100 #endif
101 #else
102 static char *Read_mode = "r";
103 #ifndef UNIX_LIKE_FILES
104 static char *Write_mode = "w";
105 static char *Append_mode = "a";
106 #endif
107 #endif
108
109 /* maximum number of files on file stack */
110 #ifndef FOPEN_MAX
111 #ifdef _NFILE
112 #define FOPEN_MAX       _NFILE
113 #else
114 #define FOPEN_MAX       (20)
115 #endif
116 #endif
117 /* The -5 is to account for stdin, stdout, stderr, and the 2 tmp file handles.
118  * The +20 is to allow for nested macros. They can take 2 stack slots per call
119  * since argument expansion also uses a slot, but they don't take extra
120  * file descriptors, since all the macros are kept in one file. */
121 #define MAXFSTK (FOPEN_MAX - 5 + 20)
122
123
124 struct FILESTACK {
125         FILE    *file;
126         char    *filename;
127         long    fileoffset;             /* fseek position in file */
128         int     lineno;                 /* where we are in the file */
129         struct MACRO    *mac_p;         /* if pushing because of a macro call,
130                                          * this will point to info about the
131                                          * macro, otherwise 0. */
132 };
133
134 static struct FILESTACK Filestack[MAXFSTK];
135
136 static int Fstkptr = -1;                /* stack pointer for Filestack */
137 static char quote_designator[] = "`";
138
139 extern int unlink();                    /* to remove temp file */
140 extern char *tmpnam();          /* generate temp file name */
141
142 /* static function declarations */
143 static void pushfile P((FILE *file, char *filename, int lineno,
144                 struct MACRO *mac_p));
145 static char *path_combiner P((char *prefix));
146 static int is_absolute_path P((char *filename));
147 static struct MACRO *findMacro P((char *macname));
148 static int hashmac P(( char *macname));
149 static struct MACRO *setup_macro P((char *macname));
150 static void free_parameters P((struct MAC_PARAM *param_p, char *macname,
151                 int values_only));
152 static char *dupstring P((char *string));
153 static char *mkmacparm_name P((char *macname, char *param_name));
154 static struct MACRO *resolve_mac_name P((char *macname));
155 static int has_quote_designator P((char *macname));
156
157
158 \f
159
160 /* add macro name to hash table and arrange to save its text in temp file */
161
162 void
163 define_macro(macname)
164
165 char *macname;          /* name of macro to be defined */
166
167 {
168         int has_params = NO;
169         char *mac_name;         /* copy of macro name, because what gets
170                                  * passed in can get overwritten by parameter
171                                  * names */
172         struct MACRO *mac_p;
173         struct MAC_PARAM *parm_p;
174
175         debug (4, "define_macro macname=%s\n", macname);
176
177         /* there might be some leading white space in front of macro name,
178          * if so, ignore that */
179         while (*macname == ' ' || *macname == '\t') {
180                 macname++;
181         }
182
183         /* if ends with a ( this macro has parameters */
184         if (macname[strlen(macname) - 1] == '(') {
185                 /* this is a macro with parameters */
186                 macname[strlen(macname) - 1] = '\0';
187                 has_params = YES;
188         }
189
190         mac_p = setup_macro(macname);
191         mac_name = mac_p->macname;
192
193         if (has_params == YES) {
194                 get_parameters(mac_name);
195         }
196
197         /* copy the macro text to the macro temp file */
198         if (save_macro(Mactmp_write) == YES) {
199                 /* There may have been a reference to a parameter to be
200                  * quoted. So remind ourseleves to create quoted copies
201                  * of parameters when this macro is called later.
202                  * This is a half-hearted optimization:
203                  * we will sometimes create extra copies unnecessarily,
204                  * but much of the time we will get the benefit of a
205                  * full optimization with only a fraction of the work. */
206                 for (parm_p = mac_p->parameters_p;
207                                         parm_p != (struct MAC_PARAM *) 0;
208                                         parm_p = parm_p->next) {
209                         parm_p->quote_style |= QS_QUOTED;
210                 }
211         }
212                 
213
214         /* terminate the macro with a NULL, so that when lex hits it when
215          * the macro is called, it will think it hit EOF */
216         putc('\0', Mactmp_write);
217
218         /* make sure macro has really been written and not still buffered */
219         (void) fflush(Mactmp_write);
220
221 #ifndef UNIX_LIKE_FILES
222         /* on non-unix system, multiple opens on the same file may not work,
223          * so open and close each time */
224         fclose(Mactmp_write);
225 #endif
226 }
227 \f
228
229 /* save macro info in hash table and make sure macro temporary file is
230  * set up and ready to use */
231
232 static struct MACRO *
233 setup_macro(macname)
234
235 char *macname;          /* name of macro being defined */
236
237 {
238         struct MACRO *mac_p;    /* info about current macro */
239         int h;                  /* hash number */
240         static int have_mac_file = NO;
241 #ifdef UNIX_LIKE_FILES
242         int filedesc;           /* of tmp file for storing macros */
243 #endif
244
245
246         /* if macro has not been defined before, add to hash table */
247         if ((mac_p = findMacro(macname)) == (struct MACRO *) 0) {
248
249                 MALLOC(MACRO, mac_p, 1);
250                 h = hashmac(macname);
251                 mac_p->next = Mactable[h];
252                 Mactable[h] = mac_p;
253
254                 mac_p->macname = dupstring(macname);
255                 mac_p->num_params = 0;
256                 mac_p->parameters_p = (struct MAC_PARAM *) 0;
257                 mac_p->recursion = 0;
258         }
259         else {
260                 l_warning(Curr_filename, yylineno,
261                                         "macro '%s' redefined", macname);
262                 free_parameters(mac_p->parameters_p, macname, NO);
263                 mac_p->parameters_p = (struct MAC_PARAM *) 0;
264                 mac_p->num_params = 0;
265         }
266
267         /* save current filename and line number so they can be used to give
268          * useful error messages when the macro is called */
269         if (Fstkptr >= 0 && Filestack[Fstkptr].mac_p != (struct MACRO *) 0) {
270                 /* if current expanding a macro, get file/line info relative
271                  * to the macro */
272                 mac_p->filename = Filestack[Fstkptr].mac_p->filename;
273                 mac_p->lineno = Filestack[Fstkptr].mac_p->lineno +
274                                 Filestack[Fstkptr].mac_p->lineoffset;
275         }
276         else {
277                 mac_p->filename = Curr_filename;
278                 mac_p->lineno = yylineno;
279         }
280
281         /* if we don't yet have a temp file to store macro info, open one */
282         if (have_mac_file == NO) {
283                 /* We need separate read/write file pointers in case of defining
284                  * one macro inside another, so can't easily use tmpfile().
285                  * The most straightforward way to do this is to use tmpnam.
286                  * But recent versions of gcc complain loudly that tmpnam
287                  * is dangerous--you should use mkstemp instead. While it's
288                  * true tmpnam could have problems under certain conditions,
289                  * Mup's use of it hardly qualifies as "dangerous." Yes,
290                  * perhaps if you tried really hard by running lots and
291                  * lots of instances of Mup simultaneously, and they all
292                  * used macros, maybe you could get one of them to fail once
293                  * in a while. But some systems may not support mkstemp,
294                  * since it's more from BSD than System V, and it's unclear
295                  * how it ought to function on a system that has DOS-style
296                  * (8.3 character) filenames if you gave it a longer string
297                  * than would be a legal file name.
298                  * And, interestingly, the Solaris manual pages say
299                  * that you should NOT use mkstemp, in direct conflict with
300                  * gcc's opinion. They say to use tmpfile, which we can't do
301                  * because that just gives a single file pointer for writing,
302                  * but we want one for writing and one for reading.
303                  * So it's very unclear what to do. For unix-ish systems
304                  * we'll go with mkstemp, and for others use tmpnam.
305                  * We get a temp file name, open it twice, once for writing,
306                  * once for reading, then remove the file. This will make it a
307                  * hidden file that will disappear when the 2 file pointers
308                  * are closed.
309                  */
310 #ifdef UNIX_LIKE_FILES
311                 if ((filedesc = mkstemp(Macfile)) < 0) {
312                         ufatal("can't create temporary file for macro storage (possibly you don't have write permissions on directory/file?)");
313                 }
314                 if ((Mactmp_write = fdopen(filedesc, "w")) == (FILE *) 0) {
315                         pfatal("can't fdopen temporary file for macro storage");
316                 }
317                 if ((Mactmp_read = fopen(Macfile, "r")) == (FILE *) 0) {
318                         pfatal("can't open temporary file for reading macro");
319                 }
320
321                 /* arrange for file to vanish */
322                 (void) unlink(Macfile);
323 #else
324                 /* On non-UNIX systems, unlinking an open file may not have
325                  * the desired effect, and some systems don't properly
326                  * handle both a read and write FILE * on the same file.
327                  * So for those we just create it here and have to open
328                  * and close the file each time. */
329                 (void) tmpnam(Macfile);
330                 if ((Mactmp_write = fopen(Macfile, Write_mode)) == (FILE *) 0) {
331                         /* If tmpnam isn't implemented or fails,
332                          * try a hard-coded temp name and hope
333                          * for the best... */
334                         (void) strcpy(Macfile, "MupMacF.tmp");
335                         if ((Mactmp_write = fopen(Macfile, Write_mode))
336                                                         == (FILE *) 0) {
337                                 ufatal("can't open temporary file for macro storage (possibly you don't have write permissions on directory/file?)");
338                         }
339                 }
340 #endif
341                 have_mac_file = YES;
342         }
343 #ifndef UNIX_LIKE_FILES
344         else {
345                 if ((Mactmp_write = fopen(Macfile, Append_mode)) == (FILE *) 0) {
346                         pfatal("can't open temporary file for macro storage (maybe out of memory?)");
347                 }
348         }
349 #endif
350         /* make sure we're at the end. Now that we have separate read/write
351          * file pointers, this should be unnecessary. However, on one non-UNIX
352          * system is seemed the opening for append didn't really work,
353          * requiring this fseek to actually go to the end. And in a previous
354          * variation of this code, this fseek was needed for the UNIX way too.
355          * In any case, it doesn't hurt to be sure we are where we want to be. */
356         if (fseek(Mactmp_write, 0L, SEEK_END) != 0) {
357                 pfatal("fseek failed in setup_macro");
358         }
359
360         /* keep track of where this macro will begin in the temp file */
361         mac_p->offset = ftell(Mactmp_write);
362
363         return(mac_p);
364 }
365 \f
366
367 #ifndef UNIX_LIKE_FILES
368 /* on non-unix systems, unlinking an open file may produce undesired results,
369  * so clean up the macro temp file after parsing is done. Unfortunately,
370  * this leave a higher possibility of leaving an orphan temp file. */
371
372 void
373 mac_cleanup()
374
375 {
376         if (Macfile[0] != '\0') {
377                 unlink(Macfile);
378         }
379         Macfile[0] =  '\0';
380 }
381 #endif
382 \f
383
384 /* look up macro name in hash table and return info about it, or null if
385  * not defined */
386
387 static struct MACRO *
388 findMacro(macname)
389
390 char *macname;          /* which macro to look up */
391
392 {
393         struct MACRO *mac_p;    /* pointer to info about macro */
394
395
396         /* search hash table and collision chain off the table for match
397          * of macro name */
398         for (mac_p = Mactable[ hashmac(macname) ]; mac_p != (struct MACRO *) 0;
399                                                 mac_p = mac_p->next) {
400
401                 if (strcmp(mac_p->macname, macname) == 0) {
402                         /* found it! */
403                         return(mac_p);
404                 }
405         }
406
407         /* macro not defined */
408         return( (struct MACRO *) 0);
409 }
410 \f
411
412 /* remove a macro definition. We just remove its entry from the hash table.
413  * Its text will still remain in the macro temp file, because it seems like
414  * too much trouble to do storage management on a temp file. */
415 /* Note that if asked to undef a macro that isn't defined, it silently
416  * does nothing. */
417
418 void
419 undef_macro(macname)
420
421 char *macname;          /* which macro to undefine */
422
423 {
424         struct MACRO *mac_p;    /* to walk though list of info about macros */
425         struct MACRO **mac_p_p; /* to keep track of delete place */
426
427
428         /* there might be some leading white space in front of macro name,
429          * if so, ignore that */
430         while (*macname == ' ' || *macname == '\t') {
431                 macname++;
432         }
433
434         /* keep track of where to delete from linked list */
435         for (mac_p_p = &(Mactable[ hashmac(macname) ]);
436                                         *mac_p_p != (struct MACRO *) 0;
437                                         mac_p_p = &((*mac_p_p)->next)) {
438                 mac_p = *mac_p_p;
439                 if (strcmp(mac_p->macname, macname) == 0) {
440                         
441                         /* found it--delete this entry from list */
442                         *mac_p_p = mac_p->next;
443                         FREE(mac_p->macname);
444                         free_parameters(mac_p->parameters_p, macname, NO);
445                         FREE(mac_p);
446                         return;
447                 }
448         }
449 }
450 \f
451
452 /* generate hash number from macro name */
453
454 static int
455 hashmac(macname)
456
457 char *macname;
458
459 {
460         int h;
461
462         /* add up characters of name and take sum modulo hash table size */
463         for (h = 0; *macname != '\0'; macname++) {
464                 h += *macname;
465         }
466         return(h % MTSIZE);
467 }
468 \f
469
470 /* when macro is called, arrange to read its text from macro file */
471
472 void
473 call_macro(macname)
474
475 char *macname;          /* which macro to call */
476
477 {
478         struct MACRO *mac_p;    /* info about the macro */
479
480
481         debug(4, "call_macro macname=%s\n", macname);
482
483         if ((mac_p = resolve_mac_name(macname)) == (struct MACRO *) 0) {
484                 l_yyerror(Curr_filename, yylineno,
485                                 "macro '%s' not defined", macname);
486                 return;
487         }
488
489         
490         /* if macro has parameter,  remove any previous arguments
491          * and gather the arguments for this call */
492         if (mac_p->parameters_p != (struct MAC_PARAM *) 0) {
493                 free_parameters(mac_p->parameters_p, macname, YES);
494                 if (get_mac_arguments(macname, mac_p->num_params) == NO) {
495                         /* something was wrong with argument. Don't bother
496                          * trying to expand, because we'll probably just
497                          * just lots more error messages */
498                         return;
499                 }
500         }
501
502 #ifndef UNIX_LIKE_FILES
503         if ((Mactmp_read = fopen(Macfile, Read_mode)) == (FILE *) 0) {
504                 pfatal("can't open macro file for reading (maybe out of memory?)");
505         }
506 #endif
507
508         /* save old yyin value and make macro definition the input */
509         pushfile(Mactmp_read, mac_p->filename, mac_p->lineno, mac_p);
510         
511         /* go to where macro definition begins */
512         if (fseek(Mactmp_read, (has_quote_designator(macname)
513                         ? mac_p->quoted_offset : mac_p->offset),
514                         SEEK_SET) != 0) {
515                 pfatal("fseek failed in call_macro");
516         }
517 }
518 \f
519
520 /* save info about current yyin and set yyin to specified file */
521
522 static void
523 pushfile(file, filename, lineno, mac_p)
524
525 FILE *file;             /* replace current file with this file */
526 char *filename;         /* name of new file to use */
527 int lineno;             /* current linenumber in new file */
528 struct MACRO *mac_p;    /* if switching to macro temp file because of a
529                          * macro call, this is information about macro.
530                          * Otherwise, it will be null. */
531
532 {
533         debug(4, "pushfile file=%s", filename);
534
535         /* do error checks */
536         if (++Fstkptr >= MAXFSTK) {
537                 l_ufatal(filename, lineno,
538                         "too many nested files or macros (%d levels maximum)\n",
539                         MAXFSTK);
540         }
541         
542         if (mac_p != (struct MACRO *) 0) {
543                 if ( ++(mac_p->recursion) != 1) {
544                         l_ufatal(Curr_filename, yylineno,
545                                 "macro '%s' called recursively",
546                                 mac_p->macname);
547                 }
548         }
549
550         /* save current info */
551         Filestack[Fstkptr].file = yyin;
552         Filestack[Fstkptr].fileoffset = ftell(yyin);
553         Filestack[Fstkptr].filename = Curr_filename;
554         Filestack[Fstkptr].lineno = yylineno;
555         Filestack[Fstkptr].mac_p = mac_p;
556
557         /* arrange to use the new file */
558         new_lexbuff(file);
559
560         /* if we are now expanding a macro, we don't change the input line
561          * number.  If doing an include, then we do. */
562         if (Filestack[Fstkptr].mac_p == (struct MACRO *) 0) {
563                 yylineno = lineno;
564                 Curr_filename = filename;
565         }
566         else {
567                 Filestack[Fstkptr].mac_p->lineoffset = 0;
568         }
569 }
570 \f
571
572 /* if there are any files on the Filestack, go back to the previous one
573  * on the stack. Return 1 if something was popped, 0 if stack was empty */
574
575 int
576 popfile()
577
578 {
579         debug(4, "popfile");
580
581         /* if nothing on file stack, nothing to do  except return 0 */
582         if (Fstkptr < 0) {
583                 return(0);
584         }
585
586         if (Filestack[Fstkptr].mac_p != (struct MACRO *) 0) {
587                 /* returning from macro call */
588                 Filestack[Fstkptr].mac_p->recursion = 0;
589 #ifndef UNIX_LIKE_FILES
590                 (void) fclose(yyin);
591 #endif
592         }
593         else {
594                 /* this is an include rather than a macro file, so close it */
595                 (void) fclose(yyin);
596         }
597
598         /* set things back to the previous file */
599         yyin = Filestack[Fstkptr].file;
600         Curr_filename = Filestack[Fstkptr].filename;
601         if (Filestack[Fstkptr].fileoffset >= 0) {
602                 if (fseek(yyin, Filestack[Fstkptr].fileoffset, SEEK_SET) != 0) {
603                         pfatal("fseek failed in popfile");
604                 }
605         }
606         yylineno = Filestack[Fstkptr].lineno;
607
608         /* go back to previous file */
609         del_lexbuff();
610
611         /* decrement stackpointer */
612         Fstkptr--;
613
614         return(1);
615 }
616 \f
617
618 /* return 1 if we are NOT currently expanding a macro, 0 if we are.
619  * This backwards logic is used because when we ARE doing a macro, we
620  * should NOT muck with yylineno, and vice versa. If in a macro, adjust
621  * the line offset within the macro by the specified amount. */
622
623 int
624 not_in_mac(inc_dec)
625
626 int inc_dec;    /* how much to increment/decrement the in-macro line offset */
627 {
628         if (Fstkptr >= 0 && Filestack[Fstkptr].mac_p != (struct MACRO *) 0) {
629                 /* we are in a macro */
630                 Filestack[Fstkptr].mac_p->lineoffset += inc_dec;
631                 return(0);
632         }
633         else {
634                 return(1);
635         }
636 }
637 \f
638
639 /* if an error occurs while expanding a macro, give additional help */
640
641 void
642 mac_error()
643
644 {
645         struct MACRO *mac_p;
646
647         if (Fstkptr >= 0 && (mac_p = Filestack[Fstkptr].mac_p)
648                                                 != (struct MACRO *) 0) {
649                 (void) fprintf(stderr, "note: previous error found while expanding macro %s'%s' from %s: line %d:\n",
650                                 (strchr(mac_p->macname, '(') ? "parameter " : ""),
651                                 mac_p->macname,
652                                 mac_p->filename,
653                                 mac_p->lineno + mac_p->lineoffset);
654                 print_offending_line(mac_p->filename, mac_p->lineno + mac_p->lineoffset);
655         }
656 }
657 \f
658
659 /* process an included file */
660
661 void
662 includefile(fname)
663
664 char *fname;    /* name of file to include */
665
666 {
667         FILE *file;             /* the included file */
668         char *fnamecopy;
669
670
671         /* attempt to open file. Give message if fail */
672         /* Note that if we find the file somewhere up the MUPPATH
673          * rather than directly, fname will be updated to contain the
674          * actual path of the file we are using, so we can tell that
675          * to the user. That way if they have several files by the same
676          * name but in different directories, and we're picking up a different
677          * one than they had intended, we can give them a clue of what's
678          * going on... */
679         if ((file = find_file(&fname)) == (FILE *) 0) {
680
681                 l_ufatal(Curr_filename, yylineno,
682                                 "can't open include file '%s'", fname);
683         }
684
685         /* need to make copy of file name */
686         fnamecopy = dupstring(fname);
687
688         /* arrange to connect yyin to the included file, save info, etc */
689         pushfile(file, fnamecopy, 1, (struct MACRO *) 0);
690 }
691 \f
692
693 /* Find a file to be included. First look using file name as is.
694  * If not found, check if is absolute path name, and if so, give up.
695  * Otherwise, try prepending each component of $MUPPATH in turn,
696  * and trying that as a path. If a file is found, return that.
697  * If we reach the end of the list, give up. 
698  * Giving up means returning 0. If we find it somewhere up the MUPPATH
699  * rather than directly, update filename to point to the actual path used.
700  */
701
702 FILE *
703 find_file(filename_p)
704
705 char **filename_p;
706
707 {
708         char *filename;
709         FILE *file;
710         char *fullpath;
711         char *combiner;                 /* what goes between path components */
712         char *muppath;                  /* value of $MUPPATH */
713         char *prefix;                   /* component of $MUPPATH,
714                                          * to prepend to filename */
715         char *path_separator = "\0";    /* between components in $MUPPATH */
716
717
718         /* first try name just as it is. */
719         filename = *filename_p;
720         if ((file = fopen(filename, Read_mode)) != (FILE *) 0) {
721                 return(file);
722         }
723
724         /* If it's an absolute path, we have to give up */
725         if (is_absolute_path(filename)) {
726                 return ((FILE *) 0);
727         }
728
729         /* See if user set a $MUPPATH for where to look for includes */
730         if ((muppath = getenv("MUPPATH")) != (char *) 0) {
731
732 #ifdef UNIX_LIKE_PATH_RULES
733                 path_separator = ":";
734 #endif
735 #ifdef DOS_LIKE_PATH_RULES
736                 path_separator = ";";
737 #endif
738                 if (*path_separator == '\0') {
739                         /* If user went to the trouble of setting $MUPPATH,
740                          * they probably think it will work, so we better
741                          * let them know it doesn't. Hopefully they will
742                          * tell us what path rules their operating system
743                          * uses, so we support it in the next release. */
744                         warning("MUPPATH facility not implemented for this operating system");
745                         return (FILE *) 0;
746                 }
747
748                 /* walk through $MUPPATH */
749                 for (prefix = strtok(muppath, path_separator);
750                                 prefix != (char *) 0;
751                                 prefix = strtok(0, path_separator)) {
752         
753                         combiner = path_combiner(prefix);
754
755                         /* get enough space for the full name */
756                         MALLOCA(char, fullpath, strlen(filename) +
757                                 strlen(prefix) + 1 + strlen(combiner));
758
759                         /* create full path */
760                         sprintf(fullpath, "%s%s%s", prefix, combiner, filename);
761
762                         /* See if this file exists */
763                         debug(4, "checking '%s' for include, using MUPPATH",
764                                         fullpath);
765                         if ((file = fopen(fullpath, Read_mode)) != (FILE *) 0) {
766                                 *filename_p = fullpath;
767                                 return(file);
768                         }
769
770                         /* no file here, no need to save this path */
771                         FREE(fullpath);
772                 }
773         }
774
775         return (FILE *) 0;
776 }
777 \f
778
779 /* return true if given filename is an absolute path name */
780
781 static int
782 is_absolute_path(filename)
783
784 char *filename;
785
786 {
787
788 #ifdef UNIX_LIKE_PATH_RULES
789         /* For Unix, a pathname is absolute if it starts with a slash */
790         return (*filename == '/');
791 #endif
792
793 #ifdef DOS_LIKE_PATH_RULES
794         /* If second character is a colon, then absolute */
795         if (*filename != '\0' && *(filename + 1) == ':') {
796                 return(1);
797         }
798         else {
799                 return(0);
800         }
801 #endif
802
803 #if ! defined(UNIX_LIKE_PATH_RULES) && ! defined(DOS_LIKE_PATH_RULES)
804         /* Not implemented for this operating system. We'll pretend
805          * it's not, which will make it fall through and fail later. */
806         return(0);
807 #endif
808 }
809 \f
810
811 /* What to use to glue together a prefix and relative path to get a
812  * full path. */
813
814 static char *
815 path_combiner(prefix)
816
817 char *prefix;
818
819 {
820
821 #ifdef UNIX_LIKE_PATH_RULES
822         /* Unix separator is slash. If there was already a slash at the
823          * end of the prefix, no problem: multiples slashes are like one */
824         return ("/");
825 #endif
826
827 #ifdef DOS_LIKE_PATH_RULES
828         /* Use backslash, unless prefix ended with slash or backslash,
829          * in which case we don't need anything. */
830         char last_ch;
831         last_ch = prefix[strlen(prefix) - 1];
832         return ((last_ch == '\\' || last_ch == '/') ? "" : "\\");
833 #endif
834
835 #if ! defined(UNIX_LIKE_PATH_RULES) && ! defined(DOS_LIKE_PATH_RULES)
836         /* Shouldn't be here. Unimplemented for this operating system */
837         return ("");
838 #endif
839 }
840 \f
841
842 /* return YES if macro is currently defined, NO if it isn't */
843
844 int
845 is_defined(macname, paramtoo)
846
847 char *macname;
848 int paramtoo;   /* if YES, also look for macro parameter by this name,
849                  * otherwise just macro */
850
851 {
852         if (paramtoo) {
853                 return(resolve_mac_name(macname) == 0 ? NO : YES);
854         }
855         else {
856                 return(findMacro(macname) == 0 ? NO : YES);
857         }
858 }
859 \f
860
861 /* when the -D option is used on the command line, save the macro definition. */
862
863 void
864 cmdline_macro(macdef)
865
866 char *macdef;   /* MACRO=definition */
867
868 {
869         char *def;
870
871
872         /* separate out the macro name */
873         if (*macdef == '_') {
874                 if (Mupmate == YES) {
875                         l_yyerror(0, -1, "Run > Set Options > Define Macros: macro name cannot start with underscore.");
876                 }
877                 else {
878                         l_yyerror(0, -1, "argument for %cD is invalid: macro name cannot start with underscore", Optch);
879                 }
880                 return;
881         }
882         for (def = macdef; *def != '\0'; def++) {
883                 if ( ! isupper(*def) && ! isdigit(*def) && *def != '_') {
884                         break;
885                 }
886         }
887
888         /* make sure has form XXX=definition */
889         if (def == macdef) {
890                 if (Mupmate == YES) {
891                         l_yyerror(0, -1, "Run > Set Options > Define Macros: macro name only allowed to contain upper case letters, numbers and underscores.");
892                 }
893                 else {
894                         l_yyerror(0, -1, "argument for %cD is missing or wrong format", Optch);
895                 }
896                 return;
897         }
898
899         if (*def == '=') {
900                 *def++ = '\0';
901         }
902         else if (*def != '\0') {
903                 if (Mupmate == YES) {
904                         l_yyerror(0, -1, "Run > Set Options > Define Macros: macro name is invalid or missing '=' on macro definition.");
905                 }
906                 else {
907                         l_yyerror(0, -1, "argument for %cD had invalid name or missing '=' on macro definition", Optch);
908                 }
909                 return;
910         }
911
912         Curr_filename = "Command line argument";
913         (void) setup_macro(macdef);
914
915         /* copy the macro to the macro temp file */
916         do {
917                 putc(*def, Mactmp_write);
918         } while ( *def++ != '\0');
919         (void) fflush(Mactmp_write);
920 #ifndef UNIX_LIKE_FILES
921         fclose(Mactmp_write);
922 #endif
923 }
924 \f
925
926 /* recursively free a list of macro parameters */
927
928 static void
929 free_parameters(param_p, macname, values_only)
930
931 struct MAC_PARAM *param_p;      /* what to free */
932 char *macname;                  /* name of macro having this parameter */
933 int values_only;                /* if YES, just get rid of current
934                                  * argument values, otherwise dispose of
935                                  * the entire parameters list */
936
937 {
938         char *mp_name;          /* internal name of macro parameter */
939
940
941         if (param_p == (struct MAC_PARAM *) 0) {
942                 /* end of list */
943                 return;
944         }
945
946         /* recurse */
947         free_parameters(param_p->next, macname, values_only);
948
949         /* need to undef the internal name */
950         mp_name = mkmacparm_name(macname, param_p->param_name);
951         undef_macro(mp_name);
952         FREE(mp_name);
953
954         if (values_only == NO) {
955
956                 /* release space */
957                 if (param_p->param_name != (char *) 0) {
958                         FREE(param_p->param_name);
959                 }
960                 FREE(param_p);
961         }
962 }
963 \f
964
965 /* given a macro name and a parameter name, add the parameter name to the
966  * list of parameters for the macro */
967
968 void
969 add_parameter(macname, param_name)
970
971 char *macname;
972 char *param_name;               /* name of parameter to add */
973
974 {
975         struct MACRO *macinfo_p;        /* which macro to add to */
976         struct MAC_PARAM *new_p;        /* new parameter */
977         struct MAC_PARAM *param_p;      /* to walk through parameter list */
978
979
980         /* get space to store info about the parameter */
981         MALLOC(MAC_PARAM, new_p, 1);
982
983         /* get the macro information to know where to attach */
984         if ((macinfo_p = findMacro(macname)) == (struct MACRO *) 0) {
985                 pfatal("add_parameter unable to find macro %s", macname);
986         }
987
988         /* if this is first parameter, link directly to macro, otherwise
989          * to the end of the parameter linked list */
990         if (macinfo_p->parameters_p == (struct MAC_PARAM *) 0) {
991                 macinfo_p->parameters_p = new_p;
992         }
993         else {
994                 /* walk down current parameter list */
995                 for (param_p = macinfo_p->parameters_p;
996                                 param_p != (struct MAC_PARAM *) 0;
997                                 param_p = param_p->next) {
998
999                         /* check for duplicate name */
1000                         if (strcmp(param_name, param_p->param_name) == 0) {
1001                                 l_yyerror(Curr_filename, yylineno,
1002                                         "duplicate parameter name %s for macro %s",
1003                                         param_name, macname);
1004                         }
1005
1006                         /* link onto end of list */
1007                         if (param_p->next == (struct MAC_PARAM *) 0) {
1008                                 param_p->next = new_p;
1009                                 break;
1010                         }
1011                 }
1012         }
1013
1014         /* fill in the info */
1015         new_p->param_name = dupstring(param_name);
1016         /* assume non-quoted for now */
1017         new_p->quote_style = QS_UNQUOTED;
1018         new_p->next = (struct MAC_PARAM *) 0;
1019
1020         (macinfo_p->num_params)++;
1021 }
1022 \f
1023
1024 /* given a string to duplicate, allocate space for a copy and return pointer
1025  * to the copy. Caller is responsible for freeing if it needs to be freed */
1026
1027 static char *
1028 dupstring(string)
1029
1030 char *string;   /* what to duplicate */
1031
1032 {
1033         char *newstr;   /* the duplicate */
1034
1035         /* get space and copy the old to new */
1036         MALLOCA(char, newstr, strlen(string) + 1);
1037         (void) strcpy(newstr, string);
1038
1039         return(newstr);
1040 }
1041 \f
1042
1043 /* save the value of a macro argument by making a macro out of it */
1044
1045 void
1046 set_parm_value(macname, argbuff, argnum)
1047
1048 char *macname;  /* name of macro */
1049 char *argbuff;  /* value of argument */
1050 int argnum;     /* which argument. 1 for the first, 2 for second, etc */
1051
1052 {
1053         static struct MAC_PARAM *param_p;       /* keep track of current
1054                          * parameter. The first time we are called for a
1055                          * given macro, we look up the macro and get its
1056                          * first parameter. After that, we just follow
1057                          * the linked list of parameters */
1058         struct MACRO *mac_p;    /* info about macro */
1059         struct MACRO *argmac_p; /* info about the parameter */
1060         char *mp_name;  /* pointer to malloc-ed space containing internal
1061                          * name of MACRO(PARAMETER) */
1062         char *p;        /* to copy value to macro temp file */
1063
1064         if (argnum == 1) {
1065                 /* this is the first argument, so we have to look up the
1066                  * macro */
1067                 if ((mac_p = findMacro(macname)) == (struct MACRO *) 0) {
1068                         pfatal("set_parm_value can't find macro");
1069                 }
1070
1071                 /* point to head of parameters list */
1072                 param_p = mac_p->parameters_p;
1073         }
1074         else {
1075                 /* just advance to the next parameter */
1076                 if (param_p != (struct MAC_PARAM *) 0) {
1077                         param_p = param_p->next;
1078                 }
1079                 if (param_p == (struct MAC_PARAM *) 0) {
1080                         /* no next parameter. Error msg is printed elsewhere,
1081                          * so just clean up and return */
1082                         FREE(argbuff);
1083                         return;
1084                 }
1085         }
1086
1087         /* if argbuff is null, there is no argument, which really means the
1088          * argument is the null string. */
1089         if (argbuff == (char *) 0) {
1090                 argbuff = dupstring("");
1091         }
1092
1093         /* now associate the value with the parameter */
1094         mp_name = mkmacparm_name(macname, param_p->param_name);
1095         argmac_p = setup_macro(mp_name);
1096
1097         /* copy the macro to the macro temp file */
1098         if (param_p->quote_style & QS_UNQUOTED) {
1099                 fprintf(Mactmp_write, "%s", argbuff);
1100                 putc('\0', Mactmp_write);
1101         }
1102
1103         if (param_p->quote_style & QS_QUOTED) {
1104                 short in_string;        /* are we within double quotes? */
1105                 short escaped;          /* did we just see a backslash? */
1106
1107                 /* Remember where we are stashing this quoted copy */
1108                 argmac_p->quoted_offset = ftell(Mactmp_write);
1109
1110                 /* Add the initial quote */
1111                 putc('"', Mactmp_write);
1112
1113                 /* Have to copy a character at a time, because we
1114                  * need to backslash any embedded quotes. This follows
1115                  * rules like the ANSI C preprocessor, except we only have
1116                  * to worry about strings, not character constants, because
1117                  * Mup doesn't have character constants. Also, we don't
1118                  * squeeze not-in-string white space runs to a single space,
1119                  * because this keeps the code simpler and there's no
1120                  * particular benefit in squeezing, other than perhaps
1121                  * saving a few bytes in the macro temp file. This code
1122                  * is similar to the gcc implementation of cpp. */
1123                 in_string = escaped = NO;
1124                 for (p = argbuff; *p != '\0'; p++) {
1125                         if (escaped == YES) {
1126                                 escaped = NO;
1127                         }
1128                         else {
1129                                 if (*p == '\\') {
1130                                         escaped = YES;
1131                                 }
1132                                 if (in_string == YES) {
1133                                         if (*p == '"') {
1134                                                 /* reached end of string */
1135                                                 in_string = NO;
1136                                         }
1137                                 }
1138                                 else if (*p == '"') {
1139                                         /* starting a string */
1140                                         in_string = YES;
1141                                 }
1142                         }
1143
1144                         /* Escape quotes always; escape backslashes
1145                          * when they are inside strings. */
1146                         if (*p == '"' || (in_string == YES && *p == '\\')) {
1147                                 putc('\\', Mactmp_write);
1148                         }
1149                         putc(*p, Mactmp_write);
1150                 }
1151
1152                 /* Add the final quote */
1153                 putc('"', Mactmp_write);
1154                 putc('\0', Mactmp_write);
1155         }
1156         (void) fflush(Mactmp_write);
1157 #ifndef UNIX_LIKE_FILES
1158         fclose(Mactmp_write);
1159 #endif
1160
1161         /* temp space no longer needed */
1162         FREE(mp_name);
1163         FREE(argbuff);
1164 }
1165 \f
1166
1167 /* make an internal macro name for a macro parameter name. The internal
1168  * name is MACRO(PARAMETER). Space for name is malloc-ed, caller must free */
1169
1170 static char *
1171 mkmacparm_name(macname, param_name)
1172
1173 char *macname;
1174 char *param_name;
1175
1176 {
1177         char *internal_name;
1178
1179         /* add 3 for the 2 parentheses and the null */
1180         MALLOCA(char, internal_name,
1181                         strlen(macname) + strlen(param_name) + 3);
1182
1183         (void) sprintf(internal_name, "%s(%s)", macname, param_name);
1184         return(internal_name);
1185 }
1186 \f
1187
1188 /* add a character to the current macro argument buffer. */
1189
1190 char *
1191 add2argbuff(argbuff, c)
1192
1193 char *argbuff;          /* the argument buffer so far */
1194 int c;                  /* a character to add to the buffer */
1195
1196 {
1197         static int offset;      /* where in argbuff to put character */
1198         static int length;      /* how many characters we have allocated */
1199
1200
1201         if (argbuff == (char *) 0) {
1202                 /* first time we were called, so malloc some space */
1203                 MALLOCA(char, argbuff, MAC_ARG_SZ);
1204                 offset = 0;
1205                 length = MAC_ARG_SZ;
1206         }
1207         else if (offset == length - 1) {
1208                 /* need more space */
1209                 length += MAC_ARG_SZ;
1210                 REALLOCA(char, argbuff, length);
1211         }
1212
1213         /* put character in the buffer and null terminate it */
1214         argbuff[offset++] = (char) c;
1215         argbuff[offset] = '\0';
1216
1217         return(argbuff);
1218 }
1219 \f
1220
1221 /* given a macro name that might be either a macro parameter or a regular
1222  * macro, return pointer to the proper MACRO struct. We do this by
1223  * searching up the stack of macros being expanded. If the name matches
1224  * that of a macro parameter, use that, otherwise treat as a normal macro.
1225  * Return null if can't resolve */
1226
1227 static struct MACRO *
1228 resolve_mac_name(macname)
1229
1230 char *macname;
1231
1232 {
1233         struct MACRO *mac_p;    /* macro that matches the macname */
1234         int i;                  /* index through file stack */
1235         char *mp_name;          /* macro parameter internal name */
1236         int quoted;             /* if has quote designator */
1237         char *basename;         /* macname not counting quote designator */
1238
1239
1240         if ((quoted = has_quote_designator(macname)) == YES) {
1241                 basename = macname + strlen(quote_designator);
1242         }
1243         else {
1244                 basename = macname;
1245         } 
1246                 
1247         /* first go up the stack of macro calls, seeing if the macro
1248          * name matches the parameter name of any macro. If so, that's
1249          * the correct macro to use. Failing that, we look for the macro
1250          * name just as is. If that fails too, we have to admit defeat
1251          * and return null. */
1252         for (i = 0; i <= Fstkptr; i++) {
1253                 if (Filestack[i].mac_p != (struct MACRO *) 0) {
1254                         /* we are expanding a macro. See if that macro
1255                          * has a parameter by the name we are trying to
1256                          * resolve. If so, that's what we want */
1257                         mp_name = mkmacparm_name(Filestack[i].mac_p->macname,
1258                                         basename);
1259                         mac_p = findMacro(mp_name);
1260                         FREE(mp_name);
1261                         if (mac_p != 0) {
1262                                 /* Eureka! We found it */
1263                                 return(mac_p);
1264                         }
1265                 }
1266         }
1267
1268         /* well, guess it wasn't a macro parameter. Try treating as
1269          * just an ordinary macro name */
1270         /* Not allowed to be a special quoted macro; you can only do that
1271          * to a macro parameter */
1272         if (quoted == YES) {
1273                 l_yyerror(Curr_filename, yylineno,
1274                         "cannot use '%s' on a macro, only on a macro parameter",
1275                         quote_designator);
1276                 return ((struct MACRO *) 0);
1277         }
1278
1279         return(findMacro(macname));
1280 }
1281 \f
1282
1283 /* Return YES if macro name reference includes designator denoting
1284  * it is to be quoted (like usage of # in ANSI C preprocessor) */
1285
1286 static int
1287 has_quote_designator(macname)
1288
1289 char *macname;
1290
1291 {
1292         return (strncmp(macname, quote_designator, strlen(quote_designator))
1293                                                         == 0 ? YES : NO );
1294 }
1295 \f
1296
1297 /* For "preprocessor" option, similar to the C compiler option to
1298  * just run the macro preprocessor, instead of the usual yacc-generated
1299  * yyparse(), we have this function that simply writes tokens out.
1300  */
1301
1302 void
1303 preproc()
1304 {
1305         while (yylex() != 0) {
1306                 /* In strings, the backslashes before any embedded quotes
1307                  * will have been swallowed, so we have to recreate them. */
1308                 if (yytext[0] == '"') {
1309                         char *t;
1310                         putchar('"');
1311                         for (t = yytext + 1; *t != '\0'; t++) {
1312                                 if (*t == '"' && *(t+1) != '\0') {
1313                                         putchar('\\');
1314                                 }
1315                                 putchar(*t);
1316                         }
1317                 }
1318                 else {
1319                         printf("%s", yytext);
1320                 }
1321         }
1322 }