chiark / gitweb /
Merge branch 'arkkra' into shiny
[mup] / mup / mup / macros.c
CommitLineData
69695f33
MW
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 */
43struct 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 */
50struct 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 */
71static struct MACRO *Mactable[MTSIZE];
72
73/* temporary file for saving text of macros. Need separate handles for reading
74 * and writing */
75static FILE *Mactmp_read = (FILE *) 0;
76static FILE *Mactmp_write = (FILE *) 0;
77#ifdef UNIX_LIKE_FILES
78static 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
88static 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
96static char *Read_mode = "rb";
97#ifndef UNIX_LIKE_FILES
98static char *Write_mode = "wb";
99static char *Append_mode = "ab";
100#endif
101#else
102static char *Read_mode = "r";
103#ifndef UNIX_LIKE_FILES
104static char *Write_mode = "w";
105static 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
124struct 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
134static struct FILESTACK Filestack[MAXFSTK];
135
136static int Fstkptr = -1; /* stack pointer for Filestack */
137static char quote_designator[] = "`";
138
139extern int unlink(); /* to remove temp file */
140extern char *tmpnam(); /* generate temp file name */
141
142/* static function declarations */
143static void pushfile P((FILE *file, char *filename, int lineno,
144 struct MACRO *mac_p));
145static char *path_combiner P((char *prefix));
146static int is_absolute_path P((char *filename));
147static struct MACRO *findMacro P((char *macname));
148static int hashmac P(( char *macname));
149static struct MACRO *setup_macro P((char *macname));
150static void free_parameters P((struct MAC_PARAM *param_p, char *macname,
151 int values_only));
152static char *dupstring P((char *string));
153static char *mkmacparm_name P((char *macname, char *param_name));
154static struct MACRO *resolve_mac_name P((char *macname));
155static 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
162void
163define_macro(macname)
164
165char *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
232static struct MACRO *
233setup_macro(macname)
234
235char *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
372void
373mac_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
387static struct MACRO *
388findMacro(macname)
389
390char *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
418void
419undef_macro(macname)
420
421char *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
454static int
455hashmac(macname)
456
457char *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
472void
473call_macro(macname)
474
475char *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
522static void
523pushfile(file, filename, lineno, mac_p)
524
525FILE *file; /* replace current file with this file */
526char *filename; /* name of new file to use */
527int lineno; /* current linenumber in new file */
528struct 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
575int
576popfile()
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
623int
624not_in_mac(inc_dec)
625
626int 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
641void
642mac_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
661void
662includefile(fname)
663
664char *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
702FILE *
703find_file(filename_p)
704
705char **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
781static int
782is_absolute_path(filename)
783
784char *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
814static char *
815path_combiner(prefix)
816
817char *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
844int
845is_defined(macname, paramtoo)
846
847char *macname;
848int 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
863void
864cmdline_macro(macdef)
865
866char *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
928static void
929free_parameters(param_p, macname, values_only)
930
931struct MAC_PARAM *param_p; /* what to free */
932char *macname; /* name of macro having this parameter */
933int 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
968void
969add_parameter(macname, param_name)
970
971char *macname;
972char *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
1027static char *
1028dupstring(string)
1029
1030char *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
1045void
1046set_parm_value(macname, argbuff, argnum)
1047
1048char *macname; /* name of macro */
1049char *argbuff; /* value of argument */
1050int 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
1170static char *
1171mkmacparm_name(macname, param_name)
1172
1173char *macname;
1174char *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
1190char *
1191add2argbuff(argbuff, c)
1192
1193char *argbuff; /* the argument buffer so far */
1194int 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
1227static struct MACRO *
1228resolve_mac_name(macname)
1229
1230char *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
1286static int
1287has_quote_designator(macname)
1288
1289char *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
1302void
1303preproc()
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}