awp8101@ritcv.UUCP (Andrew W. Potter) (02/09/88)
$Part5: $ File_is="MKFILE.C" $ Check_Sum_is=694782456 $ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY X/* XMAKE version 1.1, April 1987 XCopyright (C) 1987 by Jesse Perry. XMAKE is in the public domain and may be freely distributed, Xused, and modified, provided this notice is not removed. X Xmkfile.c XThis file contains the routines which parse makefiles and create the Xnamed macro, default rule, and target statements. X*/ X X#include "make.h" X X/* Read the named makefile, placing definitions of Xtargets, macros, and rules in the lists provided. */ X Xget_make_file(fname, mlptr, rlptr, tlptr) Xchar *fname; XMAKE_TARGET **mlptr, **rlptr, **tlptr; X{ X`009MAKE_TOKEN *toklist; X`009FILE *mkfptr; X X`009/* Open named makefile. */ X X`009if (fname == NULL || *fname == '\0') { X`009`009mkfptr = NULL; X`009} else if ((mkfptr = fopen(fname, "r")) == NULL) { X X`009`009/* Try to add default makefile type. */ X X X X`009`009if ((mkfptr = fopen(fname, "r")) == NULL) { X`009`009`009if (Verbose) { X`009`009`009`009print_prefix(); X`009`009`009`009printf("Can't open file '%s'\n", fname); X`009`009`009} X`009`009`009return (0); X`009`009} X`009} X X`009/* Read makefile in for processing. */ X X`009toklist = make_token_list(mkfptr); X`009if (mkfptr != NULL) { X`009`009fclose(mkfptr); X`009} X X`009/* Parse token list, appending results to X`009rule list, macro list, and target list. */ X X`009return (parse_file(toklist, mlptr, rlptr, tlptr)); X} X X/* Check the syntax of a list of tokens representing a makefile. */ X Xparse_file(tokptr, mlptr, rlptr, tlptr) Xregister MAKE_TOKEN *tokptr; XMAKE_TARGET **mlptr, **rlptr, **tlptr; X{ X`009register MAKE_TARGET *tgptr; X`009register MAKE_COMMAND *cmdptr; X`009int c, parse_state, parse_error, experr; X`009char *errptr; X`009MAKE_TOKEN *prevtok, *alttok; X`009MAKE_COMMAND *prevcmd; X X#ifdef FILE_DEBUG Xprintf("\n[parse_file] Starting, lists are:\n"); Xshow_target(*mlptr, STMT_MACRO); Xshow_target(*rlptr, STMT_RULE); Xshow_target(*tlptr, STMT_TARGET); Xprintf(".................................\n"); X#endif X X`009/* Initialize to parse makefile. */ X X`009tgptr = NULL; X`009parse_error = FALSE; X`009parse_state = P_START_LINE; X X`009/* Scan through entire token list. */ X X`009while (tokptr != NULL || tgptr != NULL) { X#ifdef PARSE_DEBUG Xif (tokptr != NULL && tokptr->mt_text != NULL) { Xprintf("[parse] State = %s, token '%s', line %d\n", P_state_name[parse_state], X(*tokptr->mt_text == '\n' ? "\\n" : tokptr->mt_text), tokptr->mt_line); X} X#endif X`009`009switch (parse_state) { X X`009`009/* This state is entered whenever a newline token is X`009`009followed by anything but a space token. On entry, X`009`009tokptr points at the token after the newline. */ X X`009`009case P_START_LINE: X X`009`009`009if (tgptr != NULL) { X#ifdef PARSE_DEBUG Xprintf(" ** Warning, tgptr not NULL on entering P_START_LINE.\n"); X#endif X`009`009`009`009free_target(tgptr); X`009`009`009} X`009`009`009tgptr = NULL; X X`009`009`009/* Skip consecutive newlines. */ X X`009`009`009while (tokptr != NULL && *tokptr->mt_text == '\n') { X`009`009`009`009tokptr = free_first_token(tokptr); X`009`009`009} X X`009`009`009/* Check for tokens which are invalid X`009`009`009at the start of a line. */ X X`009`009`009while (tokptr != NULL && tokptr->mt_text[1] == '\0' && X`009`009`009 ((c = *tokptr->mt_text) == ' ' || X`009`009`009 c == DEPENDENCY || c == DEFINE_MACRO)) { X#ifdef VMS_ERROR X`009`009`009`009lib$signal(&Mak_badinitch, 3, X`009`009`009`009 1, &c, tokptr->mt_line); X#else V`009`009`009`009printf(" ** Bad initial character '%c' on line %d, deleted.\n" X, X`009`009`009`009 c, tokptr->mt_line); X#endif X`009`009`009`009parse_error = TRUE; X`009`009`009`009tokptr = free_first_token(tokptr); X`009`009`009} X X`009`009`009/* Change state to read list of targets. Note that X`009`009`009the current token is left in the input list to be X`009`009`009processed with any following target tokens. */ X X`009`009`009if (tokptr != NULL && *tokptr->mt_text != '\n') { X`009`009`009`009parse_state = P_GET_TARGET_LIST; X`009`009`009} X`009`009`009break; X X`009`009/* This state reads any number of target tokens from the X`009`009input list. The target token list ends when a newline, X`009`009DEPENDENCY, or DEFINE_MACRO token is found. */ X X`009`009case P_GET_TARGET_LIST: X X`009`009`009/* Create a MAKE_TARGET to hold the target list. */ X X`009`009`009tgptr = E_ALLOC(MAKE_TARGET); X`009`009`009tgptr->tg_next = NULL; X`009`009`009tgptr->tg_name = NULL; X`009`009`009tgptr->tg_dep = NULL; X`009`009`009tgptr->tg_cmd = NULL; X`009`009`009tgptr->tg_ndep = 0; X X`009`009`009/* Read target tokens until reaching a newline, X`009`009`009DEPENDENCY, or DEFINE_MACRO token. */ X X`009`009`009prevtok = NULL; X`009`009`009while (tokptr->mt_text[1] != '\0' || X`009`009`009 ((c = *tokptr->mt_text) != '\n' && X`009`009`009 c != DEPENDENCY && c != DEFINE_MACRO)) { X`009`009`009`009if (tgptr->tg_name == NULL) { X`009`009`009`009`009tgptr->tg_name = tokptr; X`009`009`009`009} X`009`009`009`009prevtok = tokptr; X`009`009`009`009tokptr = tokptr->mt_next; X`009`009`009`009if (tokptr == NULL) { X#ifdef VMS_ERROR X`009`009`009`009`009lib$signal(&Mak_nodepch, 5, X`009`009`009`009`009 1, &DEPENDENCY, X`009`009`009`009`009 FAO_AD(prevtok->mt_text), X`009`009`009`009`009 prevtok->mt_line); X`009`009`009`009`009lib$signal(&Mak_unexpeof); X#else X`009`009`009`009`009printf(" ** Expected '%c' after '%s', line %d.\n", X`009`009`009`009`009 DEPENDENCY, prevtok->mt_text, prevtok->mt_line); X`009`009`009`009`009printf(" ** End of file not preceded by newline.\n"); X#endif X`009`009`009`009`009parse_error = TRUE; X`009`009`009`009`009break; X`009`009`009`009} X`009`009`009} X`009`009`009if (tokptr == NULL) { X`009`009`009`009break; X`009`009`009} X`009`009`009if (prevtok != NULL) { X`009`009`009`009prevtok->mt_next = NULL; X`009`009`009} X X`009`009`009/* Decide what to do next based on what X`009`009`009token ended target name list. */ X X`009`009`009alttok = tokptr; X`009`009`009tokptr = tokptr->mt_next; X`009`009`009alttok->mt_next = NULL; X`009`009`009switch (c = *alttok->mt_text) { X`009`009`009case '\n': X#ifdef VMS_ERROR X`009`009`009`009lib$signal(&Mak_depneeded, 3, X`009`009`009`009 1, &DEPENDENCY, prevtok->mt_line); X#else V`009`009`009`009printf(" ** Missing '%c' on line %d; inserted at end of line.\ Xn", X`009`009`009`009 DEPENDENCY, prevtok->mt_line); X#endif X`009`009`009`009parse_error = TRUE; X`009`009`009`009tokptr = free_first_token(tokptr); X`009`009`009`009parse_state = P_GET_CMD; X`009`009`009`009break; X`009`009`009case ' ': X`009`009`009case DEPENDENCY: X`009`009`009case DEFINE_MACRO: X`009`009`009`009if (tokptr == NULL) { X`009`009`009`009`009if (c == ' ') { X#ifdef VMS_ERROR X`009`009`009`009`009`009lib$signal(&Mak_invblank, 1, X`009`009`009`009`009`009 alttok->mt_line); X#else V`009`009`009`009`009`009printf(" ** Blank invalid in target specification, lin Xe %d.\n", X`009`009`009`009`009`009 alttok->mt_line); X#endif X`009`009`009`009`009} else if (c == DEPENDENCY) { X#ifdef VMS_ERROR X`009`009`009`009`009`009lib$signal(&Mak_depeof, 3, X`009`009`009`009`009`009 1, &DEPENDENCY, X`009`009`009`009`009`009 alttok->mt_line); X#else V`009`009`009`009`009`009printf(" ** No dependencies or commands after '%c' on Xline %d.\n", X`009`009`009`009`009`009 DEPENDENCY, alttok->mt_line); X#endif X`009`009`009`009`009} else { X#ifdef VMS_ERROR X`009`009`009`009`009`009lib$signal(&Mak_notextmac, 3, X`009`009`009`009`009`009 FAO_AD(prevtok->mt_text), X`009`009`009`009`009`009 prevtok->mt_line); X#else X`009`009`009`009`009`009printf(" ** No text for macro '%s', line %d\n", X`009`009`009`009`009`009 prevtok->mt_text, prevtok->mt_line); X#endif X`009`009`009`009`009} X`009`009`009`009`009parse_error = TRUE; X`009`009`009`009`009break; X`009`009`009`009} X`009`009`009`009if (c == DEPENDENCY) { X`009`009`009`009`009parse_state = P_GET_DEPENDENCY_LIST; X`009`009`009`009} else { X`009`009`009`009`009parse_state = P_GET_MACRO_TEXT; X`009`009`009`009} X`009`009`009`009break; X`009`009`009default: V`009`009`009`009printf("FATAL ERROR, line %d: target name list terminated at '% Xs'\n", X`009`009`009`009 alttok->mt_line, alttok->mt_text); X`009`009`009`009make_exit(NORMAL_EXIT); X`009`009`009} X`009`009`009free_token(alttok); X`009`009`009break; X X`009`009/* This state is reached after reading the DEPENDENCY token X`009`009in a target definition. It reads all following names, up X`009`009to a newline, into the dependency list for the target being X`009`009created. DEPENDENCY and DEFINE_MACRO tokens are not allowed X`009`009in the dependency list. On entry, tokptr is set to the X`009`009first token after the DEPENDENCY in the input list, and X`009`009tgptr points to a MAKE_TARGET which has been given the X`009`009list of targets the dependencies apply to. */ X X`009`009case P_GET_MACRO_TEXT: X`009`009case P_GET_DEPENDENCY_LIST: X`009`009`009if (tgptr == NULL) { X`009`009`009`009printf("FATAL ERROR, tgptr is NULL in P_GET_%s\n", X`009`009`009`009 parse_state == P_GET_DEPENDENCY_LIST ? X`009`009`009`009 "DEPENDENCY_LIST" : "MACRO_TEXT"); X`009`009`009`009make_exit(NORMAL_EXIT); X`009`009`009} X`009`009`009prevtok = NULL; X`009`009`009while (tokptr != NULL && (c = *tokptr->mt_text) != '\n') { X`009`009`009`009if (tokptr->mt_text[1] == '\0' && X`009`009`009`009 (c == DEPENDENCY || c == DEFINE_MACRO)) { X`009`009`009`009`009errptr = "dependency list"; X`009`009`009`009`009if (parse_state == P_GET_MACRO_TEXT) { X`009`009`009`009`009`009errptr = "macro text"; X`009`009`009`009`009} X#ifdef VMS_ERROR X`009`009`009`009`009lib$signal(&Mak_invch, 5, 1, &c, X`009`009`009`009`009 FAO_AD(errptr), tokptr->mt_line); X#else X`009`009`009`009`009printf(" ** '%c' invalid in %s, on line %d; deleted.\n", X`009`009`009`009`009 c, errptr, tokptr->mt_line); X#endif X`009`009`009`009`009parse_error = TRUE; X`009`009`009`009`009tokptr = free_first_token(tokptr); X`009`009`009`009`009if (prevtok != NULL) { X`009`009`009`009`009`009prevtok->mt_next = tokptr; X`009`009`009`009`009} X`009`009`009`009} else { X`009`009`009`009`009if (tgptr->tg_dep == NULL) { X`009`009`009`009`009`009tgptr->tg_dep = tokptr; X`009`009`009`009`009} X`009`009`009`009`009prevtok = tokptr; X`009`009`009`009`009tokptr = tokptr->mt_next; X`009`009`009`009} X`009`009`009} X X`009`009`009if (tokptr == NULL) { X#ifdef VMS_ERROR X`009`009`009`009lib$signal(&Mak_unexpeof); X#else X`009`009`009`009printf(" ** End of file not preceded by newline.\n"); X#endif X`009`009`009`009parse_error = TRUE; X`009`009`009`009break; X`009`009`009} X`009`009`009if (prevtok != NULL) { X`009`009`009`009prevtok->mt_next = NULL; X`009`009`009} X`009`009`009tokptr = free_first_token(tokptr); X`009`009`009if (parse_state == P_GET_MACRO_TEXT) { X`009`009`009`009parse_state = P_CHECK_MACRO; X`009`009`009} else { X`009`009`009`009parse_state = P_GET_CMD; X`009`009`009} X`009`009`009break; X X`009`009case P_CHECK_MACRO: X`009`009`009experr = macro_expand(tgptr->tg_name, *mlptr); X`009`009`009if (tgptr->tg_name->mt_next != NULL) { X#ifdef VMS_ERROR X`009`009`009`009lib$signal(&Mak_multmacdef, 1, X`009`009`009`009 tgptr->tg_name->mt_line); X#else V`009`009`009`009printf(" ** More than one name in macro definition, line %d.\n X", X`009`009`009`009 tgptr->tg_name->mt_line); X#endif X`009`009`009`009parse_error = TRUE; X`009`009`009`009free_target(tgptr); X`009`009`009} else if (experr != EXP_SIMPLE) { X`009`009`009`009if (experr == EXP_SPECIAL) { X#ifdef VMS_ERROR X`009`009`009`009`009lib$signal(&Mak_specdef, 1, X`009`009`009`009`009 tgptr->tg_name->mt_line); X#else X`009`009`009`009`009printf(" ** Redefinition of special macro, line %d.\n", X`009`009`009`009`009 tgptr->tg_name->mt_line); X#endif X`009`009`009`009} X`009`009`009`009parse_error = TRUE; X`009`009`009`009free_target(tgptr); X`009`009`009} else if (macro_expand(tgptr->tg_dep, *mlptr) == X`009`009`009 EXP_ERROR || !macro_add(tgptr, mlptr)) { X`009`009`009`009parse_error = TRUE; X`009`009`009`009free_target(tgptr); X`009`009`009} X`009`009`009tgptr = NULL; X`009`009`009parse_state = P_START_LINE; X`009`009`009break; X X`009`009/* This state is reached after reading a dependency line and X`009`009any associated command lines. It expands any named macros in X`009`009the dependency or command lines and error checks the result. */ X X`009`009case P_EXPAND_TARGET: X`009`009`009if (tgptr == NULL) { X#ifdef PARSE_DEBUG X`009`009`009`009printf("FATAL ERROR: tgptr is NULL on entering %s.\n", X`009`009`009`009 P_state_name[parse_state]); X#endif X`009`009`009`009make_exit(NORMAL_EXIT); X`009`009`009} X`009`009`009experr = macro_expand(tgptr->tg_name, *mlptr); X`009`009`009if (experr == EXP_SPECIAL) { X#ifdef VMS_ERROR X`009`009`009`009lib$signal(&Mak_spectarg, 3, FAO_AD("name"), X`009`009`009`009 tgptr->tg_name->mt_line); X#else X`009`009`009`009printf(" ** Special macro used in target name, line %d.\n", X`009`009`009`009 tgptr->tg_name->mt_line); X#endif X`009`009`009`009parse_error = TRUE; X`009`009`009`009free_target(tgptr); X`009`009`009} else if (tgptr->tg_name == NULL) { X#ifdef VMS_ERROR X`009`009`009`009lib$signal(&Mak_notarg, 1, X`009`009`009`009 tgptr->tg_name->mt_line); X#else X`009`009`009`009printf(" ** No target name given, line %d.\n", X`009`009`009`009 tgptr->tg_name->mt_line); X#endif X`009`009`009`009parse_error = TRUE; X`009`009`009`009free_target(tgptr); X`009`009`009} else if (experr == EXP_ERROR || X`009`009`009 macro_expand(tgptr->tg_dep, *mlptr) == EXP_ERROR || X`009`009`009 cmd_expand(tgptr->tg_cmd, *mlptr) == EXP_ERROR) { X`009`009`009`009parse_error = TRUE; X`009`009`009`009free_target(tgptr); X`009`009`009} else if (save_target(tgptr, rlptr, tlptr) < 0) { X`009`009`009`009parse_error = TRUE; X`009`009`009} X`009`009`009tgptr = NULL; X`009`009`009parse_state = P_START_LINE; X`009`009`009break; X X`009`009/* This state is reached after reading a dependency line. X`009`009It checks to see if the next line is a command line which X`009`009tells how to update the target. If the next line is a X`009`009command line, it changes state to read the line, otherwise X`009`009the current target is completely read, so it changes state X`009`009to expand and save it. */ X X`009`009case P_GET_CMD: X`009`009`009if (tokptr != NULL && tokptr->mt_text[1] == '\0' && X`009`009`009 *tokptr->mt_text == BEGIN_CMD_LINE) { X`009`009`009`009tokptr = free_first_token(tokptr); X`009`009`009`009if (tgptr->tg_cmd == NULL) { X`009`009`009`009`009prevcmd = NULL; X`009`009`009`009} X`009`009`009`009parse_state = P_GET_CMD_FLAG; X`009`009`009} else { X`009`009`009`009parse_state = P_EXPAND_TARGET; X`009`009`009} X`009`009`009break; X X`009`009/* This state is reached after finding a BEGIN_CMD_LINE after X`009`009a newline. It reads the rest of the command line. */ X X`009`009case P_GET_CMD_FLAG: X`009`009`009cmdptr = E_ALLOC(MAKE_COMMAND); X`009`009`009cmdptr->cmd_next = cmdptr->cmd_word = NULL; X`009`009`009cmdptr->cmd_flag = 0; X`009`009`009while (tokptr->mt_text[1] == '\0') { X`009`009`009`009c = *tokptr->mt_text; X`009`009`009`009if (c == MC_IGN_ERROR) { X`009`009`009`009`009cmdptr->cmd_flag |= CMD_IGN_ERROR; X`009`009`009`009} else if (c == MC_NO_ECHO) { X`009`009`009`009`009cmdptr->cmd_flag |= CMD_NO_ECHO; X`009`009`009`009} else if (c == '\n') { X#ifdef VMS_ERROR X`009`009`009`009`009lib$signal(&Mak_nocmd, 1, X`009`009`009`009`009 tokptr->mt_line); X#else X`009`009`009`009`009printf(" ** No command text on line %d.\n", X`009`009`009`009`009 tokptr->mt_line); X#endif X/* this could be made a warning only */`009parse_error = TRUE; X`009`009`009`009`009tokptr = free_first_token(tokptr); X`009`009`009`009`009parse_state = P_GET_CMD; X`009`009`009`009`009free(cmdptr); X`009`009`009`009`009cmdptr = NULL; X`009`009`009`009`009break; X`009`009`009`009} else { X`009`009`009`009`009break; X`009`009`009`009} X`009`009`009`009tokptr = free_first_token(tokptr); X`009`009`009} X X`009`009`009/* Check for error during flag processing. */ X X`009`009`009if (cmdptr == NULL) { X`009`009`009`009break; X`009`009`009} X X`009`009`009/* Get words in command. First token is not newline. */ X X`009`009`009prevtok = NULL; X`009`009`009cmdptr->cmd_word = tokptr; X`009`009`009while (tokptr != NULL && *tokptr->mt_text != '\n') { X`009`009`009`009prevtok = tokptr; X`009`009`009`009tokptr = tokptr->mt_next; X`009`009`009} X`009`009`009prevtok->mt_next = NULL; X`009`009`009if (tokptr != NULL) { X`009`009`009`009tokptr = free_first_token(tokptr); X`009`009`009} X X`009`009`009/* Append latest command to current MAKE_TARGET. */ X X`009`009`009if (prevcmd == NULL) { X`009`009`009`009tgptr->tg_cmd = cmdptr; X`009`009`009} else { X`009`009`009`009prevcmd->cmd_next = cmdptr; X`009`009`009} X`009`009`009prevcmd = cmdptr; X`009`009`009cmdptr = NULL; X X`009`009`009/* Change state to check for another command line. */ X X`009`009`009parse_state = P_GET_CMD; X`009`009`009break; X X`009`009default: X`009`009`009printf("FATAL ERROR, line %d: bad parser state %d.\n", X`009`009`009 tokptr->mt_line, parse_state); X`009`009`009make_exit(NORMAL_EXIT); X`009`009} X`009} X X`009/* See if any errors were found in the token list. */ X X`009if (parse_error) { X`009`009return (-1); X`009} X`009return (0); X} X X/* The target pointed to by tgptr contains no named macros (they have all Xbeen previously expanded. It may contain special macros. The target name Xlist may contain more than one file name, and/or more than one rule Xdefinition. This routine splits these multiple target definitions into Xsingle target/rule definitions and merges them with any previously created Xtarget/rule definitions. */ X Xstatic Xsave_target(tgptr, rlptr, tlptr) XMAKE_TARGET *tgptr; XMAKE_TARGET **rlptr, **tlptr; X{ X`009register MAKE_TOKEN *nmptr, *nextptr; X`009int target_type; X`009MAKE_COMMAND *cmd; X`009MAKE_TARGET *newtg; X X`009/* Create a new target for each valid name in the target name list. */ X X`009for (nmptr = tgptr->tg_name; nmptr != NULL; nmptr = nextptr) { X X`009`009/* Detach first target name token from list of names. */ X X`009`009nextptr = nmptr->mt_next; X`009`009nmptr->mt_next = NULL; X X`009`009/* Check for errors in target name. */ X X`009`009target_type = check_tname(nmptr->mt_text, nmptr->mt_line); X X`009`009/* If error found in name, don't save. */ X X`009`009if (target_type < STMT_ERROR) { X`009`009`009return (-1); X`009`009} X X`009`009/* Since name is valid, perform final clean-up on it. */ X X`009`009char_process(nmptr, FALSE); X X`009`009/* Create new MAKE_TARGET. */ X X`009`009newtg = E_ALLOC(MAKE_TARGET); X`009`009newtg->tg_name = nmptr; X`009`009newtg->tg_cmd = NULL; X`009`009newtg->tg_next = NULL; X X`009`009/* Copy dependency list and expand special macros X`009`009in it using the current target name. */ X X`009`009new_copy_token(tgptr->tg_dep, &newtg->tg_dep, &newtg->tg_ndep); X`009`009if (expand_special(newtg->tg_dep, X`009`009 newtg->tg_name, NULL) == EXP_ERROR) { X`009`009`009return (-1); X`009`009} X`009`009char_process(newtg->tg_dep, FALSE); X X`009`009/* Copy update commands and expand special macros in them X`009`009using the current target name and dependency list. */ X X`009`009new_copy_cmd(tgptr->tg_cmd, &newtg->tg_cmd); X X`009`009/* Save target or rule in appropriate list. */ X X`009`009if (target_type == STMT_TARGET) { X`009`009`009if (cmd_exp_special(newtg->tg_cmd, X`009`009`009 newtg->tg_name, newtg->tg_dep) != EXP_ERROR) { X`009`009`009`009add_target(newtg, tlptr, TRUE); X`009`009`009} else { X#ifdef VMS_ERROR X`009`009`009`009lib$signal(&Mak_cmdspecexp, 3, X`009`009`009`009 FAO_AD(newtg->tg_name->mt_text), X`009`009`009`009 newtg->tg_name->mt_line); X#else V`009`009`009`009printf(" ** Error expanding special macros in command line of Xtarget %s, line %d\n", X`009`009`009`009 newtg->tg_name->mt_text, newtg->tg_name->mt_line); X#endif X`009`009`009`009return (-1); X`009`009`009} X`009`009} else { X`009`009`009add_target(newtg, rlptr, FALSE); X`009`009} X`009} X`009return (0);`009/* success */ X} X X/* Scan the name of a target. Return STMT_ERROR if it is invalid (contains Xa macro), STMT_TARGET if it is an ordinary target name, or STMT_RULE if it Xis a default rule target (.xxx.yyy). */ X Xstatic Xcheck_tname(tname, line) Xchar *tname; Xint line; X{ X`009register char *namestr; X`009int prev_literal, first_ch_rule, is_rule; X X`009/* Make sure target name has at least one character. */ X X`009if (tname == NULL || *tname == '\0') { X#ifdef VMS_ERROR X`009`009lib$signal(&Mak_notgname, 1, line); X#else X`009`009printf(" ** No name in target, line %d.\n", line); X#endif X`009`009return (STMT_ERROR); X`009} X X`009/* Scan the name. */ X X`009prev_literal = FALSE; X`009namestr = tname; X`009is_rule = FALSE; X`009first_ch_rule = (*namestr == FILE_TYPE_CHAR); X`009if (first_ch_rule) { X`009`009namestr++; X`009} X`009while (*namestr) { X`009`009switch (*namestr) { X`009`009case INVOKE_MACRO: X`009`009`009if (prev_literal) { X`009`009`009`009break; X`009`009`009} X#ifdef VMS_ERROR X`009`009`009lib$signal(&Mak_spectarg, 3, FAO_AD(tname), line); X#else X`009`009`009printf(" ** Special macro in target '%s', line %d.\n", X`009`009`009 tname, line); X#endif X`009`009`009return (STMT_ERROR); X`009`009`009break; X`009`009case FILE_TYPE_CHAR: X`009`009`009if (prev_literal) { X`009`009`009`009break; X`009`009`009} X`009`009`009if (first_ch_rule) { X`009`009`009`009is_rule = TRUE; X`009`009`009} X`009`009`009break; X`009`009} X`009`009prev_literal = !prev_literal && (*namestr++ == NEXT_LITERAL); X`009} X`009return (is_rule ? STMT_RULE : STMT_TARGET); X} X X/* Copy the list of commands pointed to by srctrg. Allocate space for the Xcopy and set the command pointer pointed to by dsttrgptr to point at the Xnew list. */ X Xnew_copy_target(srctrg, dsttrgptr) XMAKE_TARGET *srctrg; XMAKE_TARGET **dsttrgptr; X{ X`009register MAKE_TARGET *dsttrg; X X`009*dsttrgptr = NULL; X`009while (srctrg != NULL) { X`009`009dsttrg = *dsttrgptr = E_ALLOC(MAKE_TARGET); X`009`009dsttrg->tg_next = NULL; X`009`009new_copy_token(srctrg->tg_name, &dsttrg->tg_name, NULL); X`009`009new_copy_token(srctrg->tg_dep, &dsttrg->tg_dep, X`009`009 &dsttrg->tg_ndep); X`009`009new_copy_cmd(srctrg->tg_cmd, &dsttrg->tg_cmd); X`009`009dsttrgptr = &dsttrg->tg_next; X`009`009srctrg = srctrg->tg_next; X`009} X} X X/* Copy the list of commands pointed to by srccmd. Allocate space for the Xcopy and set the command pointer pointed to by dstcmdptr to point at the Xnew list. */ X Xnew_copy_cmd(srccmd, dstcmdptr) XMAKE_COMMAND *srccmd; XMAKE_COMMAND **dstcmdptr; X{ X`009register MAKE_COMMAND *dstcmd; X X`009*dstcmdptr = NULL; X`009while (srccmd != NULL) { X`009`009dstcmd = *dstcmdptr = E_ALLOC(MAKE_COMMAND); X`009`009dstcmd->cmd_next = NULL; X`009`009dstcmd->cmd_flag = srccmd->cmd_flag; X`009`009new_copy_token(srccmd->cmd_word, &dstcmd->cmd_word, X`009`009 &dstcmd->cmd_length); X`009`009dstcmdptr = &dstcmd->cmd_next; X`009`009srccmd = srccmd->cmd_next; X`009} X} X X/* Copy the list of tokens pointed to by srctk. Allocate space for the Xcopy and set the token pointer pointed to by dsttkptr to point at the Xnew list. */ X Xnew_copy_token(srctk, dsttkptr, lenptr) XMAKE_TOKEN *srctk; XMAKE_TOKEN **dsttkptr; XLISTLEN *lenptr; X{ X`009register MAKE_TOKEN *dsttk; X X`009*dsttkptr = NULL; X`009if (lenptr != NULL) { X`009`009*lenptr = 0; X`009} X`009while (srctk != NULL) { X`009`009dsttk = *dsttkptr = E_ALLOC(MAKE_TOKEN); X`009`009dsttk->mt_next = NULL; X`009`009dsttk->mt_text = newstr(srctk->mt_text, -1); X`009`009dsttk->mt_simple = srctk->mt_simple; X`009`009dsttk->mt_line = srctk->mt_line; X`009`009if (lenptr != NULL) { X`009`009`009*(lenptr)++; X`009`009} X`009`009dsttkptr = &dsttk->mt_next; X`009`009srctk = srctk->mt_next; X`009} X} X X/* Append a new target to the target list. If the target is already in Xthe list, don't add the new one, but merge the dependency lists if the Xmerge argument is non-zero. */ X Xstatic Xadd_target(ntptr, listptr, merge) XMAKE_TARGET *ntptr; XMAKE_TARGET **listptr; Xint merge; X{ X`009register MAKE_COMMAND *cmd; X`009register MAKE_TARGET *otptr, *prevtptr; X X`009/* Perform final processing on command line text. */ X X`009for (cmd = ntptr->tg_cmd; cmd != NULL; cmd = cmd->cmd_next) { X`009`009cmd->cmd_flag |= char_process(cmd->cmd_word, TRUE); X`009} X X`009/* Scan list to see if new target was defined previously. */ X X`009prevtptr = NULL; X`009for (otptr = *listptr; otptr != NULL; otptr = otptr->tg_next) { X`009`009if (COMPARE(ntptr->tg_name->mt_text, X`009`009 otptr->tg_name->mt_text) == 0) { X`009`009`009if (otptr->tg_cmd == NULL) { X`009`009`009`009otptr->tg_cmd = ntptr->tg_cmd; X`009`009`009} X`009`009`009if (merge) { X`009`009`009`009merge_dep(ntptr->tg_dep, &otptr->tg_dep, X`009`009`009`009 &otptr->tg_ndep); X`009`009`009} X`009`009`009return; X`009`009} X`009`009prevtptr = otptr; X`009} X X`009/* Add new target to list. */ X X`009if (prevtptr == NULL) { X`009`009ntptr->tg_next = *listptr; X`009`009*listptr = ntptr; X`009} else { X`009`009ntptr->tg_next = NULL; X`009`009prevtptr->tg_next = ntptr; X`009} X} X X/* Merge the list of tokens pointed to by new into the list whose address is Xpointed to by old. Set the length of the resulting list in the value pointed Xto by lenptr. */ X Xmerge_dep(new, old, lenptr) XMAKE_TOKEN *new; XMAKE_TOKEN **old; XLISTLEN *lenptr; X{ X`009MAKE_TOKEN *ocurr, *oprev; X X`009while (new != NULL) { X`009`009oprev = NULL; X`009`009ocurr = *old; X`009`009while (ocurr != NULL && COMPARE(ocurr->mt_text, new->mt_text)) { X`009`009`009oprev = ocurr; X`009`009`009ocurr = ocurr->mt_next; X`009`009} X`009`009if (ocurr == NULL) { X`009`009`009ocurr = new->mt_next; X`009`009`009if (oprev == NULL) { X`009`009`009`009new->mt_next = *old; X`009`009`009`009*old = new; X`009`009`009} else { X`009`009`009`009new->mt_next = oprev->mt_next; X`009`009`009`009oprev->mt_next = new; X`009`009`009} X`009`009`009if (lenptr != NULL) { X`009`009`009`009(*lenptr)++; X`009`009`009} X`009`009`009new = ocurr; X`009`009} else { X`009`009`009new = new->mt_next; X`009`009} X`009} X} X X/* Delete all instances of single NEXT_LITERALs. Convert pairs Xof NEXT_LITERALs into single NEXT_LITERALs. If a command line Xis passed, scan for leading command control characters, and for Xa trailing '-' (the DCL line continuation character). Return Xthe flags for this command line. */ X Xchar_process(tokptr, is_cmd) Xregister MAKE_TOKEN *tokptr; Xint is_cmd; X{ X`009register int cmdflag, startline; X`009register char *str, *copy; X X`009cmdflag = 0; X`009startline = TRUE; X`009for (; tokptr != NULL; tokptr = tokptr->mt_next) { X`009`009copy = str = tokptr->mt_text; X`009`009while (*str) { X`009`009`009if (startline) { X`009`009`009`009if (*str == MC_IGN_ERROR) { X`009`009`009`009`009cmdflag |= CMD_IGN_ERROR; X`009`009`009`009`009str++; X`009`009`009`009`009continue; X`009`009`009`009} else if (*str == MC_NO_ECHO) { X`009`009`009`009`009cmdflag |= CMD_NO_ECHO; X`009`009`009`009`009str++; X`009`009`009`009`009continue; X`009`009`009`009} else { X`009`009`009`009`009startline = FALSE; X`009`009`009`009} X`009`009`009} X`009`009`009if (*str == NEXT_LITERAL) { X`009`009`009`009if (*++str == '\0') { X`009`009`009`009`009break; X`009`009`009`009} X`009`009`009} X`009`009`009*copy++ = *str++; X`009`009} X`009`009*copy = '\0'; X`009} X`009if (is_cmd && *--copy == MC_CONTINUE) { X`009`009cmdflag |= CMD_CONTINUE; X`009} X`009return (cmdflag); X} $ GoSub Convert_File $ Goto Part6