123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458 |
- /* To be done:
- archive members as targets or dependencies.
- deletion of targets on interrupts. */
- #include <stdio.h>
- #include <sys/param.h>
- #include <stat.h>
- #include <sys/file.h>
- #define max(a, b) ((a) > (b) ? (a) : (b))
- /* A `struct linebuffer' is a structure which holds a line of text.
- `readline' reads a line from a stream into a linebuffer
- and works regardless of the length of the line. */
- struct linebuffer
- {
- long size;
- char *buffer;
- };
- struct linebuffer lb1;
- /* Structure that represents the info on one file
- that the makefile says how to make.
- All of these are chained together through `next'. */
- struct file
- {
- struct file *next;
- char *name;
- struct dep *deps;
- struct cmd *cmds;
- int double_colon; /* Nonzero for double-colon entry */
- int is_target; /* Nonzero if file is described as target */
- char *prefix; /* common prefix, if implicit rule has been used */
- };
- /* Chain of files the makefile knows how to make. */
- struct file *files;
- /* Structure representing one dependency of a file.
- Each struct file's `deps' points to a chain of these,
- chained through the `next'.
- Note that the first two words of this match a struct nameseq. */
- struct dep
- {
- struct dep *next;
- char *name;
- struct file *file;
- int changed;
- };
- /* Structure representing one command line for remaking a file.
- Each struct file's `cmds' points to a chain of these,
- chained through the `next'. */
- struct cmd
- {
- struct cmd *next;
- char *line;
- };
- /* Structure used in chains of names, for parsing and globbing */
- struct nameseq
- {
- struct nameseq *next;
- char *name;
- };
- /* Structure that represents one macro definition.
- All these are changed together through `next'. */
- struct macro
- {
- struct macro *next;
- char *name;
- char *value;
- int user; /* Nonzero if specified by command-line arg */
- };
- /* Chain of all macro definitions. */
- struct macro *macros;
- /* Pointers to struct macro's for the 4 built-in macros,
- $*, $@, $? and $<. */
- struct macro *star_macro;
- struct macro *at_macro;
- struct macro *qmark_macro;
- struct macro *less_macro;
- /* First file defined in the makefile whose name does not
- start with `.'. This is the default to remake if the
- command line does not specify. */
- struct file *default_goal_file;
- /* Pointer to structure for the file .SUFFIXES
- whose dependencies are the suffixes to be searched. */
- struct file *suffix_file;
- /* Pointer to structure for the file .DEFAULT
- whose commands are used for any file that has none of its own.
- This is zero if the makefiles do not define .DEFAULT. */
- struct file *default_file;
- /* Nonzero means do not print commands to be executed (-s). */
- int silent_flag;
- /* Nonzero means just touch the files
- that would appear to need remaking (-t) */
- int touch_flag;
- /* Nonzero means just print what commands would need to be executed,
- don't actually execute them (-n). */
- int just_print_flag;
- /* Print debugging trace info (-d). */
- int debug_flag;
- /* Nonzero means ignore status codes returned by commands
- executed to remake files. Just treat them all as successful (-i). */
- int ignore_errors_flag;
- /* Nonzero means don't remake anything, just print the data base
- that results from reading the makefile (-p). */
- int print_data_base_flag;
- /* Nonzero means don't remake anything; just return a nonzero status
- if the specified targets are not up to date (-q). */
- int question_flag;
- /* Nonzero means do not use any of the builtin rules (-r). */
- int no_builtin_rules_flag;
- /* Nonzero means keep going even if remaking some file fails (-k). */
- int keep_going_flag;
- /* The next two describe the macro output buffer.
- This buffer is used to hold the macro-expansion of a line of the makefile.
- It is made bigger with realloc whenever it is too small.
- macro_buffer_length is the size currently allocated.
- macro_buffer is the address of the buffer. */
- int macro_buffer_length;
- char *macro_buffer;
- /* Our working directory */
- char wdir[MAXPATHLEN];
- /* Forward declarations */
- struct macro *define_macro ();
- struct macro *lookup_macro ();
- char *macro_expand ();
- struct file *enter_file ();
- struct file *lookup_file ();
- struct cmd *store_command_line ();
- char *savestring ();
- void initbuffer ();
- void freebuffer ();
- long readline ();
- char *concat ();
- struct nameseq *parse_file_seq ();
- struct nameseq *multi_glob ();
- /* Data base of implicit rules */
- char *default_suffixes = ".o .c .e .r .f .p .y .yr .ye .l .s";
- char *implicit_rules[] =
- {
- ".c.o",
- "$(CC) -c $(CFLAGS) $<",
- ".p.o",
- "$(PC) -c $(PFLAGS) $<",
- ".e.o",
- "$(FC) -c $(RFLAGS) $(EFLAGS) $(FFLAGS) $<",
- ".r.o",
- "$(FC) -c $(RFLAGS) $(EFLAGS) $(FFLAGS) $<",
- ".f.o",
- "$(FC) -c $(RFLAGS) $(EFLAGS) $(FFLAGS) $<",
- ".s.o",
- "$(AS) -o $@ $<",
- ".yr.r",
- "$(YACCR) $(YFLAGS) $< ; mv y.tab.r $@",
- ".ye.e",
- "$(YACCE) $(YFLAGS) $< ; mv y.tab.e $@",
- ".y.c",
- "$(YACC) $(YFLAGS) $< ; mv y.tab.c $@",
- ".y.o",
- "$(YACC) $(YFLAGS) $< ; $(CC) $(CFLAGS) -c y.tab.c ;\
- rm y.tab.c ; mv y.tab.o $@",
- ".ye.o",
- "$(YACCE) $(YFLAGS) $< ; $(EC) $(EFLAGS) -c y.tab.e ;\
- rm y.tab.e ; mv y.tab.o $@",
- ".yr.o",
- "$(YACCR) $(YFLAGS) $< ; $(RC) $(RFLAGS) -c y.tab.r ;\
- rm y.tab.r ; mv y.tab.o $@",
- ".l.c",
- "$(LEX) $(LFLAGS) $< ; mv lex.yy.c $@",
- ".l.o",
- "$(LEX) $(LFLAGS) $< ; $(CC) $(CFLAGS) -c lex.yy.c; \
- rm lex.yy.c; mv lex.yy.o $@",
- 0,
- };
- char *default_macros[] =
- {
- "AS = as",
- "CC = cc",
- "FC = fc",
- "RC = fc",
- "EC = fc",
- "PC = pc",
- "LEX = lex",
- "YACC = yacc",
- "YACCR = yacc -r",
- "YACCE = yacc -e",
- 0,
- };
- main (argc, argv, envp)
- int argc;
- char **argv;
- char **envp;
- {
- register struct file *f;
- register int i;
- int num_remade = 0;
- int status = 0;
- int this_status;
- register char **p;
- char *ptr;
- files = 0;
- macros = 0;
- macro_buffer = 0;
- getwd (wdir);
- /* Search for command line arguments that define macros,
- and do the definitions. */
- for (i = 1; i < argc; i++)
- {
- /* Don't even try an arg that is a switch. */
- if (!strcmp (argv[i], "-f"))
- i++;
- else if (argv[i][0] != '-')
- {
- /* If the arg is a macro definition,
- replace it with "-"
- so that it will not be taken as a file to remake. */
- if (try_macro_definition (argv[i], 1))
- argv[i] = "-";
- }
- }
- /* Decode the switches now */
- decode_switches (argc, argv);
- /* Define the initial list of suffixes */
- suffix_file = enter_file (".SUFFIXES");
- if (!no_builtin_rules_flag)
- {
- ptr = default_suffixes;
- suffix_file->deps = (struct dep *) parse_file_seq (&ptr, 0,
- sizeof (struct dep));
- for (p = implicit_rules; *p;)
- {
- f = enter_file (*p++);
- f->cmds = (struct cmd *) xmalloc (sizeof (struct cmd));
- f->cmds->line = *p++;
- }
- for (p = default_macros; *p;)
- try_macro_definition (*p++);
- }
- /* Read all the specified or default makefiles */
- read_all_makefiles (argc, argv);
- if (lookup_file (".IGNORE"))
- ignore_errors_flag = 1;
- if (lookup_file (".SILENT"))
- silent_flag = 1;
- default_file = lookup_file (".DEFAULT");
- /* Make each struct dep point at the struct file for the file depended on. */
- snap_deps ();
- define_automatic_macros ();
- /* Search command line for files to remake. */
- for (i = 1; i < argc; i++)
- {
- /* Anything not a switch or an argument of a switch
- is a file to be remade.
- Note that macro definition args were replaced with
- dummies that look like switches. */
- if (!strcmp (argv[i], "-f"))
- i++;
- else if (argv[i][0] != '-')
- {
- f = enter_file (argv[i]);
- num_remade++;
- this_status = update_file (f, 1);
- if (this_status)
- {
- status = this_status;
- if (!keep_going_flag)
- break;
- }
- }
- }
- /* Command line did not specify any file to remake => use default. */
- if (!num_remade && default_goal_file)
- status = update_file (default_goal_file, 1);
- if (print_data_base_flag)
- print_data_base ();
- return status;
- }
- decode_switches (argc, argv)
- int argc;
- char **argv;
- {
- register int i;
- register char *sw;
- debug_flag = 0;
- ignore_errors_flag = 0;
- keep_going_flag = 0;
- just_print_flag = 0;
- print_data_base_flag = 0;
- question_flag = 0;
- no_builtin_rules_flag = 0;
- silent_flag = 0;
- touch_flag = 0;
- for (i = 1; i < argc; i++)
- {
- sw = argv[i];
- if (strcmp (sw, "-f") && *sw++ == '-')
- while (*sw)
- switch (*sw++)
- {
- case 'd':
- debug_flag = 1;
- break;
- case 'i':
- ignore_errors_flag = 1;
- break;
- case 'k':
- keep_going_flag = 1;
- break;
- case 'n':
- just_print_flag = 1;
- break;
- case 'p':
- print_data_base_flag = 1;
- break;
- case 'q':
- question_flag = 1;
- break;
- case 'r':
- no_builtin_rules_flag = 1;
- break;
- case 's':
- silent_flag = 1;
- break;
- case 't':
- touch_flag = 1;
- break;
- default:
- fatal ("unknown switch: %c", sw[-1]);
- }
- }
- }
- /* Implement macros. */
- /* Define macro named NAME with value VALUE.
- LENGTH is the length of NAME, which does not
- need to be null-terminated.
- USER nonzero means this is a definition specified by the
- user in the command line; it should not be overridden
- by a later definition in a makefile. */
- struct macro *
- define_macro (name, length, value, user)
- char *name, *value;
- int length;
- int user;
- {
- register struct macro *m;
- register char *s;
- m = lookup_macro (name, length);
- if (m)
- {
- if (user || !m->user)
- {
- m->value = concat (value, "", "");
- m->user = user;
- }
- return m;
- }
- s = (char *) xmalloc (length + 1);
- bcopy (name, s, length);
- s[length] = 0;
- m = (struct macro *) xmalloc (sizeof (struct macro));
- m->name = s;
- m->value = concat (value, "", "");
- m->user = user;
- m->next = macros;
- return macros = m;
- }
- struct macro *
- lookup_macro (name, length)
- char *name;
- int length;
- {
- register struct macro *m;
- for (m = macros; m; m = m->next)
- if (!strncmp (m->name, name, length) && m->name[length] == 0)
- return m;
- return 0;
- }
- /* Define the automatic macros, and record the addresses
- of their structures so we can redefine them quickly. */
- define_automatic_macros ()
- {
- register char *mflags;
- star_macro = define_macro ("*", 1, savestring (0, 0), 1);
- at_macro = define_macro ("@", 1, savestring (0, 0), 1);
- qmark_macro = define_macro ("?", 1, savestring (0, 0), 1);
- less_macro = define_macro ("<", 1, savestring (0, 0), 1);
- /* Define the built-in macro MFLAGS to contain the command line switches.
- We can ignore here those switches that cause commands from the
- makefile not to be run. */
- mflags = (char *) xmalloc (20);
- strcpy (mflags, "-");
- if (debug_flag) strcat (mflags, "d");
- if (ignore_errors_flag) strcat (mflags, "i");
- if (keep_going_flag) strcat (mflags, "k");
- if (no_builtin_rules_flag) strcat (mflags, "r");
- if (silent_flag) strcat (mflags, "s");
- if (mflags[1] == 0) mflags = "";
- define_macro ("MFLAGS", 6, mflags, 0);
- }
- /* Try to interpret LINE (a null-terminated string)
- as a macro definition. If it is one, define the macro and return 1.
- Otherwise return 0.
- USER nonzero means this is a definition specified by the
- user in the command line; it should not be overridden
- by a later definition in a makefile. */
- int
- try_macro_definition (line, user)
- char *line;
- int user;
- {
- register int c;
- register char *p = line;
- register char *beg;
- register char *end;
- while (1)
- {
- c = *p++;
- if (c == 0 || c == '\t' || c == ':' || c == '#')
- return 0;
- if (c == '=')
- break;
- }
- beg = line;
- while (*beg == ' ') beg++;
- end = p - 1;
- while (end[-1] == ' ') end--;
- while (*p == ' ' || *p == '\t') p++;
- macro_expand (p);
- define_macro (beg, end - beg, macro_buffer, user);
- return 1;
- }
- char *
- macro_buffer_output (ptr, string, length)
- char *ptr, *string;
- int length;
- {
- register int newlen = length + (ptr - macro_buffer);
- register char *new;
- if (newlen > macro_buffer_length)
- {
- macro_buffer_length = max (2 * macro_buffer_length, newlen + 100);
- new = (char *) xrealloc (macro_buffer, macro_buffer_length);
- ptr += new - macro_buffer;
- macro_buffer = new;
- }
- bcopy (string, ptr, length);
- return ptr + length;
- }
- /* Scan LINE for macro calls. Build in macro_buffer
- the result of replacing all macro calls in LINE with the macro values.
- Return the address of the resulting string, which is null-terminated
- and is only valid until the next time this function is called. */
- char *
- macro_expand (line)
- char *line;
- {
- register char *p, *o, *p1;
- char *p0;
- register struct macro *m;
- if (!macro_buffer)
- {
- macro_buffer_length = 500;
- macro_buffer = (char *) xmalloc (macro_buffer_length);
- }
- p = line;
- o = macro_buffer;
- while (1)
- {
- p1 = (char *) index (p, '$');
- o = macro_buffer_output (o, p, p1 ? p1 - p : strlen (p) + 1);
- if (p1 == 0)
- break;
- p = p1;
- p++;
- if (*p == '$')
- {
- o = macro_buffer_output (o, p, 1);
- p += 2;
- }
- else if (*p == '(' || *p == '{')
- {
- p++;
- p0 = p;
- for (p1 = p; *p1 && *p1 != ')' && *p1 != '}'; p1++)
- ;
- p = p1 + 1;
- }
- else
- {
- p0 = p;
- p1 = ++p;
- }
- /* p0 is start of macro name, p1 is first character after end of name.
- p is advanced past the macro reference. */
- m = lookup_macro (p0, p1 - p0);
- if (m)
- o = macro_buffer_output (o, m->value, strlen (m->value));
- }
- return macro_buffer;
- }
- /* Access the list of all file records.
- lookup_file given a name, return the struct file * for that name,
- or 0 if there is none.
- enter_file similar, but create one if there is none. */
- struct file *
- lookup_file (name)
- char *name;
- {
- register struct file *f = files;
- for (; f; f = f->next)
- {
- if (!strcmp (f->name, name))
- return f;
- }
- return 0;
- }
- struct file *
- enter_file (name)
- char *name;
- {
- register struct file *f = lookup_file (name);
- if (f) return f;
- f = (struct file *) xmalloc (sizeof (struct file));
- f->name = name;
- f->cmds = 0;
- f->deps = 0;
- f->double_colon = 0;
- f->prefix = 0;
- f->is_target = 0;
- f->next = files;
- files = f;
- return f;
- }
- /* Print the contents of the files and macros data bases */
- print_data_base ()
- {
- register struct macro *m;
- register struct file *f;
- register struct dep *d;
- register struct cmd *cmd;
- printf ("Macros\n\n");
- for (m = macros; m; m = m->next)
- {
- printf ("Macro %s, value is %s\n",
- m->name, m->value);
- }
- printf ("\nFiles\n\n");
- for (f = files; f; f = f->next)
- {
- printf ("File %s:", f->name);
- if (f->double_colon)
- printf (":");
- if (f->prefix)
- printf (" (implicit rule prefix %s)", f->prefix);
- printf ("\n");
- for (d = f->deps; d; d = d->next)
- printf (" depends on %s\n", d->name);
- if (f->cmds)
- printf (" commands to execute:\n");
- for (cmd = f->cmds; cmd; cmd = cmd->next)
- printf (" %s\n", cmd->line);
- }
- printf ("\nDone\n");
- }
- read_all_makefiles (argc, argv)
- int argc;
- char **argv;
- {
- register int i;
- int num_makefiles = 0;
- for (i = 1; i < argc; i++)
- {
- if (!strcmp (argv[i], "-f"))
- {
- read_makefile (argv[++i]);
- num_makefiles++;
- }
- }
- if (num_makefiles == 0)
- {
- if (file_mtime ("makefile") >= 0)
- read_makefile ("makefile");
- else if (file_mtime ("Makefile") >= 0)
- read_makefile ("Makefile");
- else
- fatal ("no arguments or description file");
- }
- }
- read_makefile (filename)
- char *filename;
- {
- register FILE *infile;
- struct linebuffer lb;
- register char *p;
- char *p2;
- struct cmd *commands = 0;
- /* Last struct cmd attached to current file,
- or 0 if none so far. Used for adding new ones to end of chain. */
- struct cmd *lastc;
- struct nameseq *filenames = 0;
- struct dep *deps = 0;
- int lineno = 0;
- int two_colon;
- /* First, get a stream to read */
- if (!strcmp (filename, "-"))
- infile = stdin;
- else
- infile = fopen (filename, "r");
- if (!infile)
- pfatal_with_name (filename);
- /* Loop over lines in the file */
- initbuffer (&lb);
- while (!feof (infile))
- {
- readline (&lb, infile);
- lineno++;
- /* Look for a #-comment and discard it if found */
- discard_line_comment (lb.buffer);
- p = lb.buffer;
- while (*p == ' ') p++;
- if (try_macro_definition (p, 0))
- continue;
- else if (*p == 0)
- continue;
- else if (*p == '\t')
- {
- /* This line is a shell command */
- while (*p && (*p == ' ' || *p == '\t')) p++;
- if (!filenames)
- fatal ("description file \"%s\" has command before any target file", filename);
- lastc = store_command_line (p, &commands, lastc);
- }
- else
- {
- /* This line describes some target files */
- record_files (filenames, deps, commands, two_colon);
- lastc = 0;
- p2 = macro_expand (p);
- filenames = multi_glob (parse_file_seq (&p2, ':',
- sizeof (struct nameseq)),
- wdir,
- sizeof (struct nameseq));
- if (!*p2++)
- fatal ("no separator in file \"%s\", line %d", filename, lineno);
- /* Is this a one-colon or two-colon entry? */
- two_colon = *p2 == ':';
- if (two_colon) p2++;
- /* Parse the dependencies. */
- deps = (struct dep *)
- multi_glob (parse_file_seq (&p2, ';', sizeof (struct dep)),
- wdir,
- sizeof (struct dep));
- commands = 0;
- /* Did we stop at end of line, or at a semicolon? */
- if (*p2 == ';')
- {
- /* Semicolon means rest of line is a command */
- lastc = store_command_line (p2 + 1, &commands, 0);
- }
- }
- }
- record_files (filenames, deps, commands, two_colon);
- freebuffer (&lb);
- if (infile != stdin)
- fclose (infile);
- }
- /* Record a description line for files FILENAMES,
- with dependencies DEPS, commands to execute COMMANDS.
- TWO_COLON is nonzero if a double colon was used.
- The links of FILENAMES are freed, and so are any names in it
- that are not incorporated into other data structures. */
- record_files (filenames, deps, commands, two_colon)
- struct nameseq *filenames;
- struct dep *deps;
- struct cmd *commands;
- int two_colon;
- {
- register struct file *f;
- register char *name;
- register struct dep *d;
- struct nameseq *nextf;
- for (; filenames; filenames = nextf)
- {
- nextf = filenames->next;
- name = filenames->name;
- free (filenames);
- if (!two_colon)
- {
- /* Single-colon. Combine these dependencies
- with any others in file's existing record, if any. */
- f = enter_file (name);
- if (f->double_colon)
- fatal ("target file \"%s\" has both : and :: entries", f->name);
- if (commands && f->cmds)
- fatal ("target file \"%s\" has commands specified twice", f->name);
- f->cmds = commands;
- /* Defining .SUFFIXES with no dependencies
- clears out the list of suffixes. */
- if (f == suffix_file && deps == 0)
- f->deps = 0;
- else if (f->deps)
- {
- for (d = f->deps; d->next; d = d->next);
- d->next = deps;
- }
- else
- f->deps = deps;
- }
- else
- {
- /* Double-colon. Make a new record even if file has one. */
- f = lookup_file (name);
- if (f && !f->double_colon)
- fatal ("target file \"%s\" has both : and :: entries", f->name);
- f = (struct file *) xmalloc (sizeof (struct file));
- f->deps = deps;
- f->cmds = commands;
- f->name = name;
- f->next = files;
- f->double_colon = 1;
- f->prefix = 0;
- f->is_target = 0;
- files = f;
- }
- /* Free name if not needed further */
- if (name != f->name)
- free (name);
- /* See if this is first file seen whose name
- does not start with a `.'. */
- if (!default_goal_file && *name != '.')
- default_goal_file = f;
- }
- }
- /* Scan the null-terminated string LINE for a # not quoted.
- If one is found, replace it with a null character. */
- discard_line_comment (line)
- char *line;
- {
- register char *p = line;
- register int c;
- register int instring = 0;
- while (c = *p++)
- {
- if (c == '\\')
- {
- if (!*p++)
- break;
- }
- else if (c == '"')
- instring = ~instring;
- else if (instring)
- continue;
- else if (c == '#')
- {
- p[-1] = 0;
- break;
- }
- }
- }
- struct cmd *
- store_command_line (string, cmds, lastc)
- char *string;
- struct cmd **cmds;
- struct cmd *lastc;
- {
- register struct cmd *c;
- c = (struct cmd *) xmalloc (sizeof (struct cmd));
- c->line = savestring (string, strlen (string));
- c->next = 0;
- if (lastc)
- lastc->next = c;
- else
- *cmds = c;
- return c;
- }
- /* Parse a string into a sequence of filenames
- represented as a chain of struct nameseq's in reverse order.
- Return that chain.
- The string is passed as STRINGP, the address of a string pointer.
- The string pointer is updated to point at the first character
- not parsed, which either is a null char or equals STOPCHAR.
- SIZE is how big to construct chain elements.
- This is useful if we want them actually to be other structures
- that have room for additional info. */
- struct nameseq *
- parse_file_seq (stringp, stopchar, size)
- char **stringp;
- int stopchar;
- int size;
- {
- register struct nameseq *new = 0;
- register struct nameseq *new1;
- register char *p = *stringp;
- char *q;
- char *name;
- register int c;
- struct nameseq *nexto;
-
- while (1)
- {
- /* Skip whitespace; see if any more names are left. */
- while (*p == ' ' || *p == '\t') p++;
- if (*p == 0 || *p == stopchar)
- break;
- /* Yes, find end of next name. */
- q = p;
- while (1)
- {
- c = *p++;
- if (c == 0 || c == ' ' || c == '\t' || c == stopchar)
- break;
- }
- p--;
- /* Extract the filename just found, and skip it. */
- name = savestring (q, p - q);
- /* Add it to the front of the chain. */
- new1 = (struct nameseq *) xmalloc (size);
- new1->name = name;
- new1->next = new;
- new = new1;
- }
- *stringp = p;
- return new;
- }
- alpha_compare (s1, s2)
- char **s1, **s2;
- {
- return strcmp (*s1, *s2);
- }
- /* Given a chain of struct nameseq's describing a sequence of filenames,
- in reverse of the intended order,
- return a new chain describing the result of globbing the filenames.
- The new chain is in forward order.
- The links of the old chain are freed or used in the new chain.
- Likewise for the names in the old chain.
- Globbing is done in directory DIR.
- SIZE is how big to construct chain elements.
- This is useful if we want them actually to be other structures
- that have room for additional info. */
- struct nameseq *
- multi_glob (chain, dir, size)
- struct nameseq *chain;
- char *dir;
- int size;
- {
- register struct nameseq *new = 0;
- register struct nameseq *tem;
- register struct nameseq *old;
- register char **vector;
- register int i;
- int length;
- extern char **glob_vector ();
- struct nameseq *nexto;
- for (old = chain; old; old = nexto)
- {
- nexto = old->next;
- if (glob_pattern_p (old->name))
- {
- vector = glob_vector (old->name, dir);
- free (old->name);
- for (i = 0; vector[i]; i++);
- length = i;
- qsort (vector, length, sizeof (char *), alpha_compare);
- for (i = length - 1; i >= 0; i--)
- {
- tem = (struct nameseq *) xmalloc (size);
- tem->name = vector[i];
- tem->next = new;
- new = tem;
- }
- free (vector);
- free (old);
- }
- else
- {
- old->next = new;
- new = old;
- }
- }
- return new;
- }
- /* For each dependency of each file, make it point at the
- file that it depends on. */
- snap_deps ()
- {
- register struct file *f;
- register struct dep *d;
- for (f = files; f; f = f->next)
- for (d = f->deps; d; d = d->next)
- d->file = enter_file (d->name);
- }
- /* If FILE is not up to date, execute the commands for it.
- Return 0 if successful, 1 if unsuccessful;
- but with some flag settings, just call `exit' if unsuccessful.
- TOPLEVEL is nonzero if this file is a top level goal;
- in that case, if nothing needs to be done, say so. */
- int
- update_file (file, toplevel)
- struct file *file;
- int toplevel;
- {
- register struct dep *d;
- register int thisdate;
- register int must_redo;
- int dep_status = 0;
- int status;
- int noerror;
- int noprint;
- register char *line;
- int dep_size = 0;
- register struct cmd *cmd;
-
- if (debug_flag)
- printf ("Considering target file \"%s\".\n", file->name);
- if (file->cmds == 0 && file->is_target)
- if (!try_implicit_rule (file))
- {
- if (default_file)
- file->cmds = default_file->cmds;
- else
- fatal ("no specification for making file \"%s\"", file->name);
- }
- /* Update all the files we depend on, if necessary. */
- for (d = file->deps; d; d = d->next)
- {
- dep_status |= update_file (d->file, 0);
- if (dep_status && !keep_going_flag)
- {
- if (debug_flag)
- printf ("Giving up on target file \"%s\".\n", file->name);
- return dep_status;
- }
- }
- if (dep_status || print_data_base_flag)
- {
- if (debug_flag)
- printf ("Giving up on target file \"%s\".\n", file->name);
- return dep_status;
- }
-
- if (debug_flag)
- printf ("Finished dependencies of target file \"%s\".\n", file->name);
- thisdate = file_mtime (file->name);
- /* Update if any file depended on is more recent than this file,
- or if this file does not exist.
- Must in any case check all of the dependencies
- so we can create $@. */
- must_redo = thisdate < 0;
- for (d = file->deps; d; d = d->next)
- {
- d->changed = thisdate < 0 || thisdate < file_mtime (d->name);
-
- if (debug_flag)
- printf ("File \"%s\" is %s than file \"%s\".\n",
- file->name, d->changed ? "older" : "newer", d->name);
- if (d->changed)
- {
- must_redo = 1;
- dep_size += strlen (d->name) + 1;
- }
- }
-
- if (debug_flag && must_redo)
- printf ("Must remake target file \"%s\".\n", file->name);
- /* If we find the file needs to be remade,
- execute its commands one by one. */
- if (question_flag)
- return must_redo;
- if (must_redo && touch_flag)
- {
- /* Should set file's modification date and do nothing else. */
- printf ("touch(%s)\n", file->name);
- close (open (file->name, O_APPEND + O_CREAT, 0666));
- }
- else if (must_redo)
- {
- /* First set the automatic macros according to this file */
- at_macro->value = file->name;
- star_macro->value = file->prefix ? file->prefix : "";
- less_macro->value = file->prefix ? file->deps->name : "";
- line = (char *) xmalloc (dep_size + 1);
- line[0] = 0;
- for (d = file->deps; d; d = d->next)
- {
- if (d->changed)
- {
- strcat (line, d->name);
- strcat (line, " ");
- }
- }
- line[strlen (line) - 1] = 0;
- qmark_macro->value = line;
- /* Now execute the command lines */
- for (cmd = file->cmds; cmd; cmd = cmd->next)
- {
- macro_expand (cmd->line);
- line = macro_buffer;
- noprint = 0;
- noerror = 0;
- /* Print each line that does not start with `@',
- unless -s was specified. */
- while (*line)
- {
- if (*line == '@')
- noprint = 1;
- else if (*line == '-')
- noerror = 1;
- else if (*line == ' ' || *line == '\t')
- ;
- else
- break;
- line++;
- }
- if (!silent_flag && (!noprint || just_print_flag))
- printf ("%s\n", line);
- /* If -n was specified, don't really execute. */
- if (just_print_flag)
- continue;
- status = system (line);
- if (status && !ignore_errors_flag && !noerror)
- return status;
- }
- /* Now free the macro values made above */
- free (qmark_macro->value);
- qmark_macro->value = "";
- }
- else if (toplevel && !silent_flag)
- printf ("File '%s' is up to date.\n", file->name);
- return 0;
- }
- /* For a FILE which has no commands specified, try to figure out some
- from the implicit rules and suffix list.
- Returns 1 if a suitable implicit rule was found,
- after modifying FILE to contain the appropriate commands and deps,
- or returns 0 if no implicit rule was found. */
- int
- try_implicit_rule (file)
- struct file *file;
- {
- register struct dep *d;
- register int flen = strlen (file->name);
- register int len;
- char *rulename;
- struct file *rulefile;
- char *prefix;
- char *depname;
- /* Try each defined suffix, looking for one this file has. */
- for (d = suffix_file->deps; d; d = d->next)
- {
- len = strlen (d->name);
- if (!strcmp (file->name + flen - len, d->name))
- break;
- }
- if (!d) return 0;
- /* Found one; now extract the name sans suffix. */
- prefix = savestring (file->name, flen - len);
- /* Now try the remaining suffixes, looking for one for which
- there is an existing file and a rule for making this one from it. */
- for (d = d->next; d; d = d->next)
- {
- depname = concat (star_macro->value, d->name, "");
- if (file_mtime (less_macro->value) >= 0)
- {
- rulename = concat (d->name, file->name + flen - len, "");
- rulefile = lookup_file (rulename);
- free (rulename);
- if (rulefile)
- break;
- }
- free (depname);
- }
- if (!rulefile)
- {
- free (prefix);
- return 0;
- }
- /* We found the implicit rule. Stick it into FILE. */
- file->cmds = rulefile->cmds;
- d = (struct dep *) xmalloc (sizeof (struct dep));
- d->name = depname;
- d->file = enter_file (depname);
- d->next = file->deps;
- file->deps = d;
- file->prefix = prefix;
- return 1;
- }
- /* Initialize a linebuffer for use */
- void
- initbuffer (linebuffer)
- struct linebuffer *linebuffer;
- {
- linebuffer->size = 200;
- linebuffer->buffer = (char *) xmalloc (200);
- }
- void
- freebuffer (linebuffer)
- struct linebuffer *linebuffer;
- {
- free (linebuffer->buffer);
- }
- /* Read a line of text from `stream' into `linebuffer'.
- Return the length of the line.
- Combine continuation lines into one line. */
- long
- readline (linebuffer, stream)
- struct linebuffer *linebuffer;
- FILE *stream;
- {
- char *buffer = linebuffer->buffer;
- register char *p = linebuffer->buffer;
- register char *end = p + linebuffer->size;
- register char *p1;
- register int c;
- while (1)
- {
- c = getc (stream);
- if (p == end)
- {
- buffer = (char *) xrealloc (buffer, linebuffer->size *= 2);
- p += buffer - linebuffer->buffer;
- end += buffer - linebuffer->buffer;
- linebuffer->buffer = buffer;
- }
- if (c < 0)
- break;
- if (c == '\n')
- {
- p1 = p;
- while (p1 != buffer && p1[-1] == '\\') p1--;
- if ((p1 - p) & 1)
- {
- /* Line ends with odd number of backslashes -- continuation! */
- /* Discard the backslash that means continuation. */
- p--;
- /* Discard whitespace at start of next line. */
- while ((c = getc (stream)) == ' ' || c == '\t');
- ungetc (c, stream);
- /* Replace it all with one space. */
- c = ' ';
- }
- else
- /* Line not continued. Return what we have so far. */
- break;
- }
- *p++ = c;
- }
- *p = 0;
- return p - buffer;
- }
- int
- file_mtime (name)
- char *name;
- {
- struct stat st;
- if (stat (name, &st) < 0)
- return -1;
- return st.st_mtime;
- }
- /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
- char *
- concat (s1, s2, s3)
- char *s1, *s2, *s3;
- {
- int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
- char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
- strcpy (result, s1);
- strcpy (result + len1, s2);
- strcpy (result + len1 + len2, s3);
- *(result + len1 + len2 + len3) = 0;
- return result;
- }
- /* Print error message and exit. */
- fatal (s1, s2, s3)
- char *s1, *s2, *s3;
- {
- printf ("make: ");
- printf (s1, s2, s3);
- printf (". Stop.\n");
- exit (1);
- }
- /* Print error message. `s1' is printf control string, `s2' is arg for it. */
- error (s1, s2)
- char *s1, *s2;
- {
- printf ("make: ");
- printf (s1, s2);
- printf ("\n");
- }
- pfatal_with_name (name)
- char *name;
- {
- extern int errno, sys_nerr;
- extern char *sys_errlist[];
- char *s;
- if (errno < sys_nerr)
- s = concat ("", sys_errlist[errno], " for %s");
- else
- s = "cannot open %s";
- fatal (s, name);
- }
- /* Like malloc but get fatal error if memory is exhausted. */
- int
- xmalloc (size)
- int size;
- {
- int result = malloc (size);
- if (!result)
- fatal ("virtual memory exhausted", 0);
- return result;
- }
- int
- xrealloc (ptr, size)
- char *ptr;
- int size;
- {
- int result = realloc (ptr, size);
- if (!result)
- fatal ("virtual memory exhausted");
- return result;
- }
- char *
- savestring (string, length)
- char *string;
- int length;
- {
- register char *out = (char *) xmalloc (length + 1);
- bcopy (string, out, length);
- out[length] = 0;
- return out;
- }
|