jon@boulder.UUCP (Jonathan Corbet) (05/17/85)
[fnord! $ ! $ ! This is VMS make part three. $ ! $ babble :== write sys$output $ babble "Creating FILETYPE.C" $ create filetype.c # include <stdio.h> char * file_type (file) char *file; /* * Return a pointer to the type of the file, or NULL if there is * none. * * Jonathan Corbet * National Center for Atmospheric Research, Field Observing Facility. */ { char *dp, *strchr (); /* * Find the offset to the end of the directory name. */ if ((dp = strchr (file, ']')) == NULL) dp = strchr (file, '>'); return (strchr (dp ? dp : file, '.')); } $ $ babble "Creating FINDCONS.C" $ create findcons.c # include <stdio.h> # include "make.h" # include "debug.h" char ** find_cons (target, source, lib) char *target, *source; int lib; /* * Find a construction for the given (indirect) target. A NULL return * implies it can't be done. If lib is TRUE, then source is used * instead of a modification of target for the source type. * * Jonathan Corbet * National Center for Atmospheric Research, Field Observing Facility. */ { char *fp, *tp, *wcp, *mknstr (), *st_getsym (), *strchr (); char *file_type (), *temp, file[200], st_symcat (), **ct_find_cons (); char **cons; int len, status, has_type; /* * Get the target file name. */ if ((fp = st_getsym (target)) == NULL) c_panic ("No file name for %s", target); if (debug (D_FINDCONS)) printf ("\nLib is %d. Target is %s", lib, fp); /* * Get the type of the target. Force it to be .obj if necessary. */ if ((tp = file_type (fp)) == NULL) { st_symcat (target, ".OBJ"); fp = st_getsym (target); tp = file_type (fp); } st_defsym ("MAKE$TARGET_TYPE", tp); if (debug (D_FINDCONS)) printf (" is now %s", fp); /* * For libraries, make the target type "(typ)" so as not to * confuse things in the construction table. */ if (lib) { st_defsym ("MAKE$IN_LIB", "("); st_symcat ("MAKE$IN_LIB", tp); st_symcat ("MAKE$IN_LIB", ")"); tp = st_getsym ("MAKE$IN_LIB"); } /* * Now we need to create a file name with type ".*". If we have a * library here, take the name from "source". */ if (lib) { char *ltp = st_getsym (source); if ((temp = file_type (ltp)) == NULL) st_defsym ("MAKE$FILE_TEMP", ltp); else { temp = mknstr (ltp, temp - ltp); st_defsym ("MAKE$FILE_TEMP", temp); free (temp); } } /* * Else derive it from the target name. */ else { temp = mknstr (fp, tp - fp); st_defsym ("MAKE$FILE_TEMP", temp); st_defsym (source, temp); free (temp); } st_symcat ("MAKE$FILE_TEMP", ".*;"); wcp = st_getsym ("MAKE$FILE_TEMP"); if (debug (D_FINDCONS)) printf ("\nSearching on %s", wcp); /* * Do a search on the file. */ sea_init (wcp); cons = 0; while (sea_search (file)) { *strchr (file, ';') = NULL; if (debug (D_FINDCONS)) printf ("\nSearching for %s to %s", file_type(file),tp); if ((cons = ct_find_cons (file_type (file), tp))) { st_defsym ("MAKE$SOURCE_TYPE", file_type (file)); break; } } if (debug (D_FINDCONS)) printf ("\nStatus is %d, file is %s", status, file); /* * If no luck, try for a create from thin air. */ if (! cons) if ((cons = ct_find_cons ("X", tp)) != NULL) st_defsym ("MAKE$SOURCE_TYPE", "X"); return (cons); } $ $ babble "Creating GETTARGET.C" $ create gettarget.c # include <stdio.h> char * get_target (line, sym) char *line, *sym; /* * Isolate the target file name from the conditional line. This * file name is stored as "sym". The return value is the portion * of the line beyond the target name, or NULL for a trashy line. * * Jonathan Corbet * National Center for Atmospheric Research, Field Observing Facility. */ { char *cp = NULL, *colon, *sp, *mknstr (), *l_blank (); char *strchr (), *strrchr (); /* * Check for new format conditional with < */ if (colon = strchr (line, '<')) cp = colon; /* * Otherwise, look for an occurence of ": ". */ else { colon = line; while (colon = strchr (colon + 1, ':')) if (*(colon + 1) == ' ') { cp = colon; break; } if (! cp) if ((cp = strrchr (line, ':')) == NULL) { printf ("\nWeird conditional: %s", line); return (NULL); } } /* * Now, hopefully, we have cp pointing to the end of the target. */ sp = mknstr (line, cp - line); st_defsym (sym, sp); return (l_blank (cp)); } $ $ babble "Creating LINETYPE.C" $ create linetype.c # include "ltype.h" char line_type (line) char *line; /* * Classify the given line. * * Jonathan Corbet * National Center for Atmospheric Research, Field Observing Facility. */ { if (*line == C_SHARP) return (LT_SHARP); else if (*line == C_COMMAND) return (LT_COMMAND); else if (strchr (line, C_COND) || strchr (line, '<')) return (LT_COND); else return (LT_TRASH); } $ $ babble "Creating LOG.C" $ create log.c log () {} /* Someday */ $ $ babble "Creating LTYPE.H" $ create ltype.h /* * Ltype.h. * * Definitions of makefile line types. */ # define LT_COMMAND 1 /* DCL command */ # define LT_COND 2 /* Conditional line */ # define LT_SHARP 3 /* # line */ # define LT_TRASH 4 /* Unrecognized line */ /* * Command characters. */ # define C_SHARP '#' /* Indicates # line */ # define C_COMMAND '$' /* Indicates DCL line */ # define C_COND ':' /* Indicates conditional */ $ $ babble "Creating MAKE.C" $ create make.c /* * Make program, version 3. * * Jonathan Corbet * National Center for Atmospheric Research, Field Observing Facility. */ # include <stdio.h> # include "make.h" extern int handler (); main (argc, argv) int argc; char **argv; { int i, cons; char string[80]; /* * Set up exit and ^C handlers. */ set_ctl_c (handler); set_exh (handler); /* set_ctl_d (); */ /* * Initialize the file date module. */ fd_init (); /* * Initialize global variables. */ if_level = 0; /* * Define the default symbols. Note this has to be done before interpreting * the command line. */ st_defsym ("for_opts", "/nolist"); st_defsym ("mac_opts", "/nolist"); st_defsym ("pas_opts", "/nolist /nostandard"); st_defsym ("c_opts", "/nolist"); st_defsym ("msg_opts", "/nolist"); st_defsym ("lib_opts", ""); # ifdef VMS_V4 /* * Uncomment this if you are running version four, and no longer wish to have * the module name to file name translation (remove _'s and truncate to nine * characters) applied. */ st_defsym ("MAKE$VMS_V4", ""); # endif /* * Define the default constructions. */ cons = ct_add_cons ("x", ".tlb"); ct_add_line (cons, "library /create /text ^MAKE$TARGET"); ct_add_line (cons, "# wait"); cons = ct_add_cons ("x", ".olb"); ct_add_line (cons, "library /create ^MAKE$TARGET"); ct_add_line (cons, "# wait"); cons = ct_add_cons (".for", ".obj"); ct_add_line (cons, "fortran ^for_opts ^$"); cons = ct_add_cons (".mar", ".obj"); ct_add_line (cons, "macro ^mac_opts ^$"); cons = ct_add_cons (".msg", ".obj"); ct_add_line (cons, "message ^msg_opts ^$"); cons = ct_add_cons (".pas", ".obj"); ct_add_line (cons, "pascal ^pas_opts ^$"); cons = ct_add_cons (".c", ".obj"); ct_add_line (cons, "cc ^c_opts ^$"); cons = ct_add_cons (".mar", "(.olb)"); ct_add_line (cons, "macro ^mac_opts ^MAKE$SOURCE"); ct_add_line (cons,"library ^lib_opts ^MAKE$TARGET ^MAKE$SOURCE"); ct_add_line (cons, "delete ^MAKE$SOURCE.obj;"); cons = ct_add_cons (".pas", "(.olb)"); ct_add_line (cons, "pascal ^pas_opts ^MAKE$SOURCE"); ct_add_line (cons,"library ^lib_opts ^MAKE$TARGET ^MAKE$SOURCE"); ct_add_line (cons, "delete ^MAKE$SOURCE.obj;"); cons = ct_add_cons (".msg", "(.olb)"); ct_add_line (cons, "message ^msg_opts ^MAKE$SOURCE"); ct_add_line (cons,"library ^lib_opts ^MAKE$TARGET ^MAKE$SOURCE"); ct_add_line (cons, "delete ^MAKE$SOURCE.obj;"); cons = ct_add_cons (".obj", ".exe"); ct_add_line (cons, "link ^linkopts ^$,^LIB/lib"); cons = ct_add_cons (".h", "(.tlb)"); ct_add_line (cons, "library ^lib_opts /text /replace ^MAKE$TARGET ^MAKE$SOURCE"); cons = ct_add_cons (".c", "(.olb)"); ct_add_line (cons, "cc ^c_opts ^MAKE$SOURCE"); ct_add_line (cons,"library ^lib_opts ^MAKE$TARGET ^MAKE$SOURCE"); ct_add_line (cons, "delete ^MAKE$SOURCE.obj;"); cons = ct_add_cons (".for", "(.olb)"); ct_add_line (cons, "fortran ^for_opts ^MAKE$SOURCE"); ct_add_line (cons,"library ^lib_opts ^MAKE$TARGET ^MAKE$SOURCE"); ct_add_line (cons, "delete ^MAKE$SOURCE.obj;"); /* * Deal with the command line. */ com_line (argc, argv); /* * Find out who we are. */ who_are_we (); /* * Fire off the subprocess. We don't want AST's here since a ^C during * the spawn will leave the process around, but we won't have it's PID. */ sys$setast (0); /* p_open (); */ sys$setast (1); /* * Process the file. */ while (file_getline ("MAKE$INPUT", TRUE)) process_line ("MAKE$INPUT"); /* * Clean up and exit. */ if (if_level) printf ("\nMissing #endif."); m_exit (); } int handler () /* * Drastic cleanup and exit. */ { if (timing) tim_show (); p_zap (); exit (1); } $ $ babble "Creating MAKE.H" $ create make.h /* * Global definitions of interest. */ # define C_QUOTE 0x80 /* Set high bit of characters. */ # define ebit(c) (c & 0xff) # define error(st) (! (st & 0x1)) /* check for system service error */ # define ___ 0 /* * Global variables, hopefully not too many. */ extern int if_level; /* How deeply nested in #if's we are. */ extern int timing; /* Are we timing or not? */ extern int in_sh_make; /* Are we in a #make? */ $ $ babble "Creating MEXIT.C" $ create mexit.c m_exit () /* * Exit the program gracefully. * * Jonathan Corbet * National Center for Atmospheric Research, Field Observing Facility. */ { p_close (); exit (1); } $ $ babble "Creating processl.c" $ create processl.c # include <stdio.h> # include "ltype.h" process_line (sym) char *sym; /* * Process an input line. "Sym" is the name of the line. * * Jonathan Corbet * National Center for Atmospheric Research, Field Observing Facility. */ { char l_type, line_type (), *lp, *st_getsym (), *l_blank (); int silent; /* * Classify the line. */ lp = st_getsym (sym); /** printf ("P|%s.\n", lp); **/ l_type = line_type (lp); switch (l_type) { /* * Simply complain about trashy lines. */ case LT_TRASH: printf ("Garbage line: %s\n", lp); break; /* * DCL command. */ case LT_COMMAND: lp = l_blank (lp); dcl (lp); break; /* * Make command. */ case LT_SHARP: lp = l_blank (lp); sharp (lp); break; /* * Conditional line. */ case LT_COND: do_cond (lp); break; /* * Something very strange. */ otherwise: c_panic ("Unknown line type %d\n", l_type); } } $ $ babble "Creating REFSYM.C" $ create refsym.c # include <stdio.h> # include <ctype.h> refsym (sym) char *sym; /* * Replace the line named by "sym" with a copy in which * all symbol references have been replaced with their * values. * * Jonathan Corbet * National Center for Atmospheric Research, Field Observing Facility. */ { char *st_getsym (), *strchr (), *mknstr (), *non_alpha (); char *cp, *sp, *ap; /* * Make sure we have a line. */ if (! st_getsym (sym)) c_panic ("No line for symbol %s", sym); /* * Copy the line over to a temporary, and reset it. */ st_defsym ("MAKE$REFSYM", st_getsym (sym)); st_defsym (sym, ""); if ((cp = st_getsym ("MAKE$REFSYM")) == NULL) c_panic ("MAKE$REFSYM disappeared"); /* * Now substitute symbols. */ while (ap = strchr (cp, '^')) { /* * Copy everything up to the symbol. */ *ap++ = NULL; /* Trashes line in symbol table! */ st_symcat (sym, cp); /* * Find the end of the symbol. */ if (*ap == '{') { ap++; if ((cp = strchr (ap, '}')) == NULL) { printf ("\nMissing '}'"); cp = ap; break; } sp = mknstr (ap, cp - ap); cp++; } /* * The symbol is not delimited by {} -- Go * forward to the first non-alpha character. */ else { cp = non_alpha (ap); sp = mknstr (ap, cp - ap); } /* * In any case, we now have: * * cp -> The first character beyond the symbol * sp -> the symbol. * * It is now time to substitute in the symbol. */ if ((ap = st_getsym (sp)) == NULL) { /* * Undefined symbol. Be silent if it is a positional * parameter, otherwise complain. */ if (strlen (sp) != 1 || ! isdigit (*sp)) printf ("\nUndefined symbol: %s", sp); } else st_symcat (sym, ap); free (sp); /* * Go around again. */ } /* * Finally, copy anything left over at the end. */ st_symcat (sym, cp); /** st_undef ("MAKE$REFSYM"); **/ } $ $ babble "Creating SEARCH.C" $ create search.c /* * File searching routines. * * Jonathan Corbet * National Center for Atmospheric Research, Field Observing Facility. */ # include <stdio.h> # include <rmsdef.h> # include <fab.h> # include <nam.h> # include "make.h" static struct FAB s_fab; static struct NAM s_nam; static char rs_name[200]; static int rs_len; static char esn[200]; static int esl; sea_init (file) char *file; /* * Initialize for a search on the given file. */ { int status; /* * Set up the RMS blocks. */ s_fab = cc$rms_fab; s_fab.fab$l_fna = file; s_fab.fab$b_fns = strlen (file); s_fab.fab$l_nam = &s_nam; s_fab.fab$l_fop = FAB$M_NAM; s_fab.fab$l_dna = ".*;"; s_fab.fab$b_dns = 3; s_nam = cc$rms_nam; s_nam.nam$l_rsa = rs_name; s_nam.nam$b_rss = 200; s_nam.nam$l_esa = esn; s_nam.nam$b_ess = 200; /* * Do the parse. */ status = sys$parse (&s_fab); if (error (status)) { errmes (&status); printf ("\nUnable to do parse on %s", file); m_exit (); } } int sea_search (file) char *file; /* * Do a search on the file given to sea_init. If there is another file * that matches the specification, return it in "file" and return TRUE. * Else FALSE is returned. */ { int status; status = sys$search (&s_fab); if (status == RMS$_NMF || status == RMS$_FNF) return (FALSE); else if (error (status)) { errmes (&status); printf ("\nUnable to do search"); m_exit (); } strncpy (file, rs_name, s_nam.nam$b_rsl); file[s_nam.nam$b_rsl] = NULL; return (TRUE); } $ $ babble "Creating SETDEBUG.C" $ create setdebug.c /* * Debug stuff. * * Jonathan Corbet * National Center for Atmospheric Research, Field Observing Facility. */ # include "debug.h" static struct db_st { char *db_name; /* Debug flag name */ int db_fl; /* Debug flag value */ } debs[] = { { "findcons", D_FINDCONS }, { "fdate", D_FDATE }, { "p_write", D_P_WRITE }, { 0 } }; set_debug (flag) char *flag; /* * Toggle a debug flag. */ { int i; /* * Search for the flag. */ for (i = 0; debs[i].db_name; i++) if (! strcmp (debs[i].db_name, flag)) { db_flags ^= debs[i].db_fl; return; } printf ("\nUnknown debug flag: %s", flag); } $ $ babble "Creating SHARP.C" $ create sharp.c # include <stdio.h> # include "make.h" sharp (line) char *line; /* * Handle a # line. * * Jonathan Corbet * National Center for Atmospheric Research, Field Observing Facility. */ { int nch; char *strchr (), *cp, *nlp, *token (); char tok[100]; /* * Pull the first token from the line. */ cp = token (line, tok); line = l_blank (cp); /* * Attempt to recognize it. */ /* * Chdir Change to a new directory. */ if (! strcmp (tok, "chdir")) ch_dir (line); /* * Cons Define a construction. */ else if (! strcmp (tok, "cons")) cons (line); /* * Debug. Set debug flags. */ else if (! strcmp (tok, "debug")) set_debug (line); /* * Dirty Clear a file/library cache entry. */ else if (! strcmp (tok, "dirty")) dirty (line); /* * Dump Dump a table of interest. */ else if (! strcmp (tok, "dump")) if ((cp = token (line, tok)) == NULL) printf ("\nNull dump command"); else if (! strcmp (tok, "symbols")) st_dump (); else if (! strcmp (tok, "constructions")) ct_dump_ctbl (); else if (! strcmp (tok, "file_cache")) fd_dump_cache (); else if (! strcmp (tok, "lib_cache")) fd_dump_lib (); else if (! strcmp (tok, "file_stats")) fd_put_stats (); else if (! strcmp (tok, "vm_stats")) lib$show_vm (); else printf ("\nI can't dump %s!", tok); /* * Defclp. Define the command line parameters as * symbols in their own right. */ else if (! strcmp (tok, "defclp")) defclp (); /* * Define Define a symbol. */ else if (! strcmp (tok, "define")) if (*cp == NULL) printf ("\nNull symbol definition."); else { cp = l_blank (token (line, tok)); st_defsym (tok, cp); check_def (tok); } /* * Else Just skip to the # endif. */ else if (! strcmp (tok, "else")) skip_to_else (FALSE); /* * Endif Decrement the #if level. */ else if (! strcmp (tok, "endif")) if (if_level <= 0) printf ("\nExtra #endif."); else if_level--; /* * Endm. End of a #make range. */ else if (! strcmp (tok, "endm")) if (! in_sh_make) printf ("Error -> #endm while not in a #make.\n"); else in_sh_make = 0; /* * Exit. Stop reading the current file. */ else if (! strcmp (tok, "exit")) { if (file_close ()) { printf ("\nExit."); m_exit (); } } /* * Ifdef Execute the following lines iff the given * symbol is defined. */ else if (! strcmp (tok, "ifdef")) if (*cp == NULL) printf ("\nBad #ifdef"); else { if_level++; cp = token (line, tok); if (*cp) printf ("\nJunk beyond #ifdef: %s", cp); if (! st_getsym (tok)) skip_to_else (TRUE); } /* * Include Include the contents of another file. */ else if (! strcmp (tok, "include")) file_open (line); /* * Log Write an entry to the log file. */ else if (! strcmp (tok, "log")) log (line); /* * Make. Type II conditional line. */ else if (! strcmp (tok, "make")) sh_make (line); /* * Message Put out a message to the terminal. */ else if (! strcmp (tok, "message")) printf ("\n%s\r", line); /* * Quit. Terminate execution. */ else if (! strcmp (tok, "quit")) { printf ("\nQuit."); m_exit (); } /* * Undef. Undefine a symbol. */ else if (! strcmp (tok, "undef")) if (*cp == NULL) printf ("\nNull # undef."); else { st_undef (line); check_undef (line); } /* * Wait. Wait for the subprocess to finish * whatever it is doing. */ else if (! strcmp (tok, "wait")) p_write ("$ "); else printf ("\nBad # line: #%s %s", tok, line); } char * token (line, tok) char *line, *tok; /* * Return the next token from "line" into "token". The returned * pointer is to the first space beyond the token, unless "line" is * a null string, in which case "line" is returned. */ { char *cp, *strchr (); if ((cp = strchr (line, ' ')) != NULL) { int len = cp - line; strncpy (tok, line, len); tok[len] = NULL; return (cp); } else { strcpy (tok, line); while (*line) /* Return EOS */ line++; return (line); } } $ $ babble "Creating SHEXEC.C" $ create shexec.c # include "make.h" int in_sh_make = 0; sh_exec () /* * Execute all lines up to a #endm * * Jonathan Corbet * National Center for Atmospheric Research, Field Observing Facility. */ { in_sh_make = 1; } $ $ babble "Creating SHMAKE.C" $ create shmake.c # include "make.h" # include "fdate.h" sh_make (line) char *line; /* * Implement the #make line. * * # make target [from a b c ....] * * Jonathan Corbet * National Center for Atmospheric Research, Field Observing Facility. */ { char target[40], incl[40], *token (); int exist; f_date_t t_date, i_date; /* * Separate out the target name. */ if (*line == 0) { printf ("Error -> Null # make.\n"); return; } line = token (line, target); /* * Get the date. */ exist = fd_date (target, &t_date, 0); /* * Check for the existence of source files. If there are none, do the * make if the target does not exist. */ if (*line == 0) { if (! exist) { st_defsym ("MAKE$OUT_OF_DATE", target); sh_exec (); } else sh_skip (); return; } /* * Otherwise we enter a loop to check each dependancy file. */ while (*line) { /* * Pull off the next file. */ line = token (line + 1, incl); /* * Get the date. */ if (! fd_date (incl, &i_date, 0)) { printf ("%s does not exist -- can't make %s\n", incl, target); exit (1); } /* * Compare dates. */ if (fd_cmp_date (t_date, i_date) < 0) { st_defsym ("MAKE$OUT_OF_DATE", incl); sh_exec (); return; } } /* * No make here, do the skip to the #endm. */ sh_skip (); } $ $ babble "Creating SHSKIP.C" $ create shskip.c sh_skip () /* * Skip through input to a #endm * * Jonathan Corbet * National Center for Atmospheric Research, Field Observing Facility. */ { char *cp, *st_getsym (), tok[20], *token (), *l_blank (); while (file_getline ("MAKE$SKIP_ENDM", 0)) { /* * See if this is a # line. */ if ((cp = st_getsym ("MAKE$SKIP_ENDM")) == 0) c_panic ("MAKE$SKIP_ENDM disappeared!"); if (*cp == '#') { cp = token (l_blank (cp), tok); if (! strcmp (tok, "endm")) return; } } printf ("Error -> Missing #endm\n"); m_exit (); } $ $ babble "Creating SKIPTOELS.C" $ create skiptoels.c # include <stdio.h> # include "make.h" skip_to_else (else_ok) int else_ok; /* * Skip through this branch of a # if. If "else_ok", we can stop at * a # else, otherwise a # else is an error. * * Jonathan Corbet * National Center for Atmospheric Research, Field Observing Facility. */ { char *cp, *l_blank (), *st_getsym (), *token (), tok[100]; int if_count = 1; while (if_count) { /* * Get the next line. */ if (! file_getline ("MAKE$SKIP_ELSE", FALSE)) { printf ("\nMissing # endif"); m_exit (); } /* * See if this is a # line. */ if ((cp = st_getsym ("MAKE$SKIP_ELSE")) == NULL) c_panic ("MAKE$SKIP_ELSE disappeared"); if (*cp == '#') { cp = token (l_blank (cp), tok); /* * If this is a #if, we need to increment * increment the if count. */ if (! strncmp (tok, "if", 2)) if_count++; /* * Else if it is a # else, we pay attention only if * we are not nested inside skipped #if's. */ else if ((! strcmp (tok, "else")) && if_count == 1) { if (else_ok) if_count = 0; else printf ("\nBad #if structure - extra # else."); } /* * If it is a # endif, decrement the if count, and perhaps * the if level. */ else if (! strcmp (tok, "endif")) { if_count--; if (if_count <= 0) if_level--; } } } } $ $ babble "---- End of MAKE part 3 ----" $ exit -- Jonathan Corbet National Center for Atmospheric Research, Field Observing Facility {seismo|hplabs}!hao!boulder!jon (Thanks to CU CS department)