|
|
/*-----------------------------------------------------------------------------
Name: mkdep.c
Description: Determine file dependencies
To Build: cl /Ox /W3 mkdep.c
Revision History: brendand (8/3/94) - Taken from GaryBu, merged files into a single unit brendand (8/4/94) - Added .PCH and wild-card support -----------------------------------------------------------------------------*/
// Includes -------------------------------------------------------------------
#define LINT_ARGS
#include <assert.h>
#include <ctype.h>
#include <io.h>
#include <malloc.h>
#include <process.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// Types and Constants --------------------------------------------------------
#ifndef CDECL
#define CDECL
#endif
#ifndef CONST
#define CONST
#endif
#ifndef STATIC
#define STATIC static
#endif
#ifndef Assert
#define Assert(f) assert(f)
#endif
#define TRUE 1
#define FALSE 0
#define FOREVER while(1)
#define BLOCK
#define VOID void
#ifdef D86
#define szROText "rt"
#define szRWText "r+t"
#define szWOText "wt"
#define szROBin "rb"
#define szRWBin "r+b"
#define szWOBin "wb"
#endif
typedef int BOOL; typedef char* SZ; typedef unsigned char BYTE; typedef BYTE* PB; typedef unsigned short WORD; typedef WORD* PW; typedef unsigned long LONG;
#define lpbNull ((PB) NULL)
#define LOWORD(l) ((WORD)l)
#define HIWORD(l) ((WORD)(((LONG)l >> 16) & 0xffff))
#define LOBYTE(w) ((BYTE)w)
#define HIBYTE(w) (((WORD)w >> 8) & 0xff)
#define MAKEWORD(l,h) ((WORD)(l)|((WORD)(h)<<8))
#define MAKELONG(l,h) ((long)(((unsigned)l)|((unsigned long)((unsigned)h))<<16))
/* Args Record - MarkArgs, UnmarkArgs */ typedef struct { int cargArr; SZ *pszArr; } ARR;
/* drive usage types - getdt */ #define dtNil 0
#define dtLocal 1
#define dtUserNet 2
/* File attributes - getatr, setatr */ #define atrError 0xffff
#define atrReadOnly FILE_READONLY
#define atrHidden FILE_HIDDEN
#define atrSystem FILE_SYSTEM
#define atrVolume 0x08
#define atrDirectory FILE_DIRECTORY
#define atrArchive FILE_ARCHIVED
/* Macro for defining Linked list inertion */ #define AddToList(new,head,tail,link,null) { if(head==null) head=new; else tail->link = new; tail=new; new->link=null; }
/* & deletion */ #define DeleteFromList(item,head,tail,link,null,prev) { if(prev==null) head=item->link; else prev->link = item->link; \
if (tail==item) tail = prev; }
/* for MtimeOfFile() */ typedef long MTIME; #define mtimeError ((MTIME) -1L)
typedef enum { langUnknown, langC, langAsm, langRC } LANG;
typedef struct _di { struct _di *pdiNext; /* next in list */ char *szPath; /* path name */ char *szName; /* full name */ BOOL fPathIsStd; /* name from standard includes (-I) */ } DI; /* dir info */
typedef struct _lk { struct _lk *plkNext; /* next in list */ struct _fi *pfi; /* file info for link */ } LK; /* File link */
typedef struct _fi { struct _fi *pfiNext; /* single link */ char *szPath; /* path name */ char *szName; /* full name */ LANG lang; /* language */ struct _lk *plkHead; /* included list */ struct _lk *plkTail; /* included list */ unsigned fIgnore:1; /* ignore: either -X and std include or -x <file> */ unsigned cout:15; /* output count */ } FI; /* file info */
typedef VOID (*PFN_ENUM)(char *, char *);
#define iszIncMax 40
char* szPrefix = ""; char* szSuffix = ".$O";
#define rmj 1
#define rmm 1
#define rup 0
#define szVerName "Forms3 Version"
// Globals --------------------------------------------------------------------
DI* pdiHead = NULL; /* stack of directories of files included */ FI* pfiHead = NULL; FI* pfiTail = NULL; WORD coutCur = 0; int cchLine;
int iszIncMac = 0; char* rgszIncPath[iszIncMax]; // actual path
char* rgszIncName[iszIncMax]; // name to output
BOOL fVerbose = FALSE; BOOL fReplacePrefix = FALSE; BOOL fNoGenHeaders = FALSE; // True if all header files must be present
BOOL fIgnoreStd = FALSE; // True if std include files should be ignored
BOOL fUseCurDir = FALSE; // When True: if a file doesn't exist and
// we are going to print a dependency for
// it, use the current directory rather
// than the directory of the source file.
char* szPrintDir = NULL; // If set, only print files in this dir.
char* szPCHFile = NULL; // .H which marks end of .PCH
// Prototypes -----------------------------------------------------------------
int main(int, char**); VOID Usage(void);
char* SzIncludesC(char *, BOOL *), *SzIncludesAsm(char *), *SzIncludesRC(char *, BOOL *); FI* PfiDependFn(char *, char *, BOOL, LANG, BOOL); FI* PfiLookup(char *, char *, LANG); FI* PfiAlloc(char *, char *, BOOL, LANG); VOID FreeFi(FI *); VOID AllocLk(FI *, FI *); VOID FreeAllLk(FI *); VOID StartReport(void); VOID ContinueReport(void); VOID EndReport(void); VOID EndLine(void); VOID Indent(void); VOID Report(char *, char *); VOID PrReverse(char *, char *); BOOL FPrintFi(FI *); VOID EnumChildren(FI *, PFN_ENUM, char *); VOID Process(char *, BOOL); VOID Fatal(char *); SZ SzTransEnv(SZ); VOID NormalizePath(SZ); VOID MakeName(SZ, SZ, SZ); VOID CopyPath(SZ, SZ); VOID PushDir(char *, char *, BOOL); VOID PopDir(void); DI* PdiFromIdi(int); int AddIncludeDir(char *);
VOID Fatal(sz) char *sz; { fprintf(stderr, "mkdep: error: %s\n", sz); exit(1); }
VOID Usage() { if (rup == 0) fprintf(stderr, "Mkdep V%d.%02d\n", rmj, rmm); else fprintf(stderr, "Mkdep V%d.%02d.%02d\n", rmj, rmm, rup);
fprintf(stderr, "usage: mkdep [-v] [-r] [-n] [-X] [-C] [-I includeDir]*\n" "\t[-p prefix] [-P replace_prefix] [-s suffix] \n" "\t[-d file]* [-D printDir] files\n\n" "\t-v Verbose\n" "\t-r Reverse the dependencies that are output\n" "\t-n Don't emit dependencies on files that don't now exist\n" "\t-X Search, but don't print standard includes\n" "\t-C If file doesn't exist, use .\\ not the directory of including file\n" "\t-I Include directory to search for <> includes\n" // "\t-J Search include directories from the INCLUDE environment variable\n"
"\t-p Prefix for all target-file names\n" "\t-P Ditto, but first remove existing prefix from name\n" "\t-s Suffix for all target-file names (default %s)\n" "\t-d Search, but don't print named file\n" "\t-D Only print files which are in named dir\n" "\t-h Header which marks the end of the .PCH\n\n" "A response file can be used by specifying '@filename' as an option.\n" , szSuffix); exit(1); }
char **CmdArgs; int cArgs; int CurArg = 1; FILE *pfileResponse = NULL; char achBuf[256]; char * pBuf = NULL;
char * GetNextArg() { char *pszTokens = " \t\n";
if (pfileResponse) { char * psz;
if (pBuf) { pBuf = strtok(NULL, pszTokens);
if (pBuf) return pBuf; }
do { psz = fgets(achBuf, 256, pfileResponse); if (psz == NULL) { fclose(pfileResponse); pfileResponse = NULL; } else if (achBuf[strlen(achBuf)-1] != '\n') { fclose(pfileResponse); Fatal("Line too long in response file. Must be less " "than 256 characters."); } else { pBuf = strtok(achBuf, pszTokens);
if (pBuf) return pBuf; } } while (psz && !pBuf); }
if (CurArg >= cArgs) return NULL;
return CmdArgs[CurArg++]; }
#define FSwitchCh(ch) ((ch)=='-' || (ch) == '/' || (ch) == '@')
int main(iszMax, rgsz) int iszMax; char *rgsz[]; { BOOL fReverse = FALSE; char *pszArg; int i = 0;
if (iszMax == 1) Usage();
CmdArgs = rgsz; cArgs = iszMax;
/* Parse command line switches.
*/ while (((pszArg = GetNextArg()) != NULL) && FSwitchCh(pszArg[0])) { char chSwitch = pszArg[1];
if (pszArg[0] == '@') { if (pszArg[1] == '\0') Usage();
pfileResponse = fopen(&pszArg[1], "rt"); if (!pfileResponse) { fprintf(stderr, "mkdep: error: Could not open response file " "'%s'.\n", &pszArg[1]); return(1); }
continue; }
// fprintf(stderr, "Arg %d: '%s' ", i++, pszArg);
switch (chSwitch) { case 'v': fVerbose = TRUE; break; case 'r': fReverse = TRUE; break; case 'n': fNoGenHeaders = TRUE; break; case 'x': case 'X': fIgnoreStd = TRUE; break; case 'C': fUseCurDir = TRUE; break;
#if 0
case 'J': { SZ szInc = getenv("INCLUDE"); if (szInc) { char rgszDir[iszIncMax][_MAX_FNAME]; int nDirs,i; char* psz;
// Convert embedded semicolons to blanks
for (psz=szInc; *psz; psz++) if (*psz == ';') *psz = ' ';
/* This is very bogus! a dynamic way of reading the dirs
should be done so up to iszIncMax dirs can be read. Also, AddIncludeDir does not copy the strings and rgszDir is an automatic variable! */ fprintf(stderr, "-J option: only first 16 include dirs parsed.\n"); nDirs = sscanf(szInc, "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s", rgszDir[0],rgszDir[1],rgszDir[2],rgszDir[3],rgszDir[4], rgszDir[5],rgszDir[6],rgszDir[7],rgszDir[8],rgszDir[9], rgszDir[10],rgszDir[11],rgszDir[12],rgszDir[13], rgszDir[14],rgszDir[15]); for (i = 0; i < nDirs; i++) AddIncludeDir(rgszDir[i]); } else fprintf(stderr,"-J option: INCLUDE variable not set.\n"); } break; #endif
case 's': case 'P': case 'p': case 'I': case 'd': case 'D': case 'h': { char *sz = &pszArg[2];
if (sz[0] == '\0') { /* Allow "-I includefile"
* and "-IincludeFile" */ pszArg = GetNextArg(); if (!pszArg) Usage();
sz = pszArg; }
// fprintf(stderr, "File: '%s'.", sz);
sz = strdup(sz);
switch (chSwitch) { case 's': szSuffix = sz; break; case 'P': fReplacePrefix = TRUE; // Drop through
case 'p': szPrefix = sz; break; case 'I': AddIncludeDir(sz); break; case 'd': { FI *pfi;
// exlude file given
// NOTE: the -C option if given, must appear before now
NormalizePath(sz);
if ((pfi = PfiDependFn(SzTransEnv(sz), sz, FALSE, langUnknown, FALSE)) != NULL) // file existed; ignore it
pfi->fIgnore = TRUE; else // file doesn't exist, create FI
(void)PfiAlloc(SzTransEnv(sz), sz, TRUE, langUnknown); break; } case 'D': /* only print files from given directory */ NormalizePath(sz); szPrintDir = sz; break; case 'h': szPCHFile = sz; break; } } break;
default: Usage(); break; }
// fprintf(stderr, "\n");
}
while (pszArg) { long hf; char szPath[_MAX_DIR]; char szName[_MAX_PATH]; struct _finddata_t fd;
// fprintf(stderr, "Reading path '%s' - ", pszArg);
NormalizePath(pszArg); CopyPath(szPath, pszArg);
// fprintf(stderr, "'%s\\%s'\n", szPath, pszArg);
hf = _findfirst(pszArg, &fd);
if (hf > -1) { do { MakeName(szName, szPath, fd.name); // fprintf(stderr, " -- '%s'\n", szName);
Process(szName, fReverse); } while (!_findnext(hf, &fd)); _findclose(hf); } // else
// fprintf(stderr, "Unable to find source file: %s\n", pszArg);
pszArg = GetNextArg(); } return( 0 ); }
/*****************************************************************************/ /* standard dependency report */
VOID StartReport() /*
-- prepare for a new line */ { cchLine = 77; }
VOID EndLine() /*
-- Make it so that the next Report starts on a new line. */ { cchLine = 0; }
VOID ContinueReport() /*
-- Output continuation character, new line, then indent. */ { printf(" \\\n"); StartReport(); Indent(); }
VOID EndReport() /*
-- Finish off this line. */ { printf("\n\n"); }
VOID Indent() /*
-- Indent a tab at the beginning of a line. */ { printf("\t"); cchLine -= 8; /* for tab */ }
VOID Report(sz, szParm) /*
-- report string -- if too many characters extend line */ register char * sz; char * szParm; /* ignored */ { int cch = strlen(sz);
if (cch > cchLine) { ContinueReport(); while (isspace(sz[0])) { sz++; cch--; } }
while (*sz != '\0') { if (*sz == '#') { putchar('\\'); /* escape any # in path */ cch++; } putchar(*sz); sz++; } cchLine -= cch; }
/*****************************************************************************/ /* Reverse dependency printing */
VOID PrReverse(szHdr, szSource) /*
-- report reverse dependency */ char * szHdr; char * szSource; { printf("%s: %s\n", szHdr, szSource); }
/*****************************************************************************/
BOOL FPrintFi(pfi) /*
-- returns true if we should print this file; false if ignore; false if szPrintDir is != 0 and it is a prefix of szName. The current directory is a zero length string and is handled specially */ FI *pfi; { if (pfi->fIgnore) return FALSE;
if (szPrintDir == NULL) return TRUE;
if (*szPrintDir == '\0') // only print current directory (check for / in name)
return strchr(pfi->szName, '/') == 0; else // print if szPrintDir is prefix of name
return strncmp(szPrintDir, pfi->szName, strlen(szPrintDir)) == 0; }
VOID EnumChildren(pfi, pfnDo, szParm) /*
-- enumerate children, call *pfnDo for each element */ FI * pfi; PFN_ENUM pfnDo; char * szParm; { LK *plk;
for (plk = pfi->plkHead; plk != NULL; plk = plk->plkNext) { FI *pfi = plk->pfi;
if (pfi->cout < coutCur) { /* Mark that we've visited this node, to prevent
* infinite recursion should we have a self referential * dependency graph. */ pfi->cout = coutCur;
if (FPrintFi(pfi)) { if (szParm == NULL) (*pfnDo)(" ", szParm); (*pfnDo)(pfi->szName, szParm); }
// recurse on nested includes; may include a non-standard includes
EnumChildren(pfi, pfnDo, szParm); } } }
VOID Process(szPath, fReverse) /*
-- process a file -- reverse => show headers as depending on files */ char * szPath; // path name to file
BOOL fReverse; { FI * pfi;
strlwr(szPath);
/* Build a list of all dependencies. */ pfi = PfiDependFn(szPath, szPath, FALSE, langUnknown, FALSE);
if (pfi == NULL) { if (fVerbose) fprintf(stderr, "mkdep: warning: file %s ignored\n", szPath); } else if (pfi->plkHead != NULL) { /* file depends on something */
if (!fReverse) { /* normal dependencies */ char * pch;
/* truncate any suffix */ pch = strrchr(szPath, '.'); if (pch) { if (strchr(pch, '/') || strchr(pch, '\\')) pch = NULL; } if (pch != NULL) *pch = '\0';
StartReport();
Report(szPrefix, NULL); if (fReplacePrefix) { /* prefix replaces any name prefix */ char * szName = szPath;
while (*szPath != '\0') { if (*szPath == '\\' || *szPath == '/') szName = szPath+1; szPath++; } Report(szName, NULL); } else { Report(szPath, NULL); } Report(szSuffix, NULL); Report(" :", NULL);
EndLine();
coutCur++; EnumChildren(pfi, Report, NULL);
EndReport(); } else { /* reverse dependencies */ coutCur++; EnumChildren(pfi, PrReverse, szPath); } }
if (pfi != NULL) // free top level FI (presumably for .c/.asm file which won't be needed)
FreeFi(pfi); }
FI * PfiDependFn(szPath, szName, fPathIsStd, lang, fIsPCHFile) /*
-- given a file name & language, return a filled in FI -- return NULL if error */ char * szPath; // path name to file
char * szName; // official name of file
BOOL fPathIsStd; // path portion of szPath is from standard includes (-I)
LANG lang; // propagate parent language
BOOL fIsPCHFile; // Is .PCH marker file
{ FILE * pfile; char rgch[256]; char * sz; char * szSuffix; FI * pfi;
/* first check to see if already in list */ if ((pfi = PfiLookup(szPath, szName, lang)) != NULL) return pfi;
if (lang != langUnknown) { /* do nothing -- keep old language */ } else if ((szSuffix = strrchr(szPath, '.')) == NULL) return NULL; else if (strcmp(szSuffix, ".asm") == 0 || strcmp(szSuffix, ".inc") == 0) lang = langAsm; else if (strcmp(szSuffix, ".rc") == 0) lang = langRC; else lang = langC;
if ((pfile = fopen(szPath, "rt")) == NULL) { // fprintf(stderr, "Could not open file '%s'.\n", szPath);
return NULL; }
pfi = PfiAlloc(szPath, szName, fPathIsStd && fIgnoreStd, lang);
if (lang == langRC) { //
// Make sure we don't try to parse binary files - major waste of time!
//
static char *aszBinary[] = { ".ico", ".sqz", ".bmp", ".tlb", ".cur", ".odg", ".ppg", ".otb" }; static int cBinary = sizeof(aszBinary)/sizeof(aszBinary[0]); int i;
if (!szSuffix) { if ((szSuffix = strrchr(szPath, '.')) == NULL) goto Cleanup; }
for (i = cBinary; i && stricmp(szSuffix, aszBinary[i-1]); i--) ;
if (i != 0) goto Cleanup; }
// Don't search inside of the .PCH marker file
if (!fIsPCHFile) {
BLOCK { /* Push the directory of this file on the list of directories for
* include searches. Save an indication as to whether this include is * from a standard place. */ char szPathT[256]; char szNameT[256];
CopyPath(szPathT, szPath); CopyPath(szNameT, szName);
PushDir(szPathT, szNameT, fPathIsStd); }
while ((sz = fgets(rgch, 256, pfile)) != NULL) { char * szInc; BOOL fThisDirNew = FALSE; /* must be in this directory */ int cch = strlen(sz);
if (cch < 2) continue; if (sz[cch-1] == '\n') sz[cch-1] = '\0'; /* note : will truncate long lines */
if ((lang == langC && (szInc = SzIncludesC(sz, &fThisDirNew)) != NULL) || (lang == langAsm && (szInc = SzIncludesAsm(sz)) != NULL) || (lang == langRC && (szInc = SzIncludesRC(sz, &fThisDirNew)) != NULL)) { FI * pfiNew = NULL; char szPathNew[256]; char szNameNew[256]; BOOL fIsPCH;
fIsPCH = (szPCHFile && !_stricmp(szInc, szPCHFile));
/* if file can be found in current directory, cycle
* through all current directories possible. */ if (fThisDirNew) { int idi; DI * pdi;
for (idi = 0; (pdi = PdiFromIdi(idi)) != NULL; idi++) { MakeName(szPathNew, pdi->szPath, szInc); MakeName(szNameNew, pdi->szName, szInc);
/* Do recursive call to include file */ pfiNew = PfiDependFn(szPathNew, szNameNew, pdi->fPathIsStd, lang, fIsPCH);
/* If we found it, get out of loop */ if (pfiNew != NULL) break; } }
/* If the file hasn't been found yet, look for it
* in the standard include directories. */ if (pfiNew == NULL) { int isz;
for (isz = 0; isz < iszIncMac; isz++) { MakeName(szPathNew, rgszIncPath[isz], szInc); MakeName(szNameNew, rgszIncName[isz], szInc);
/* Do recursive call to include file */ pfiNew = PfiDependFn(szPathNew, szNameNew, TRUE, lang, fIsPCH);
/* If we found it, mark it and get out of loop */ if (pfiNew != NULL) break; } }
/* The file doesn't exist anywhere. If it was included
* with quote marks and the user didn't specify -n, we * will pretend the file is in the same directory as * the file that's including it. */ if (pfiNew == NULL && fThisDirNew && !fNoGenHeaders) { BOOL fPathIsStd;
if (fUseCurDir) { MakeName(szPathNew, ".\\", szInc); MakeName(szNameNew, ".\\", szInc); fPathIsStd = FALSE;
/* Look for -d names */ if ((pfiNew = PfiLookup(szPathNew, szNameNew,lang)) == NULL) pfiNew = PfiAlloc(szPathNew, szNameNew, FALSE, lang); } else { DI * pdi;
pdi = PdiFromIdi(0); if (pdi == NULL) Fatal("mkdep: internal error"); MakeName(szPathNew, pdi->szPath, szInc); MakeName(szNameNew, pdi->szName, szInc);
// in this case we already look through existing FI list
pfiNew = PfiAlloc(szPathNew, szNameNew, pdi->fPathIsStd && fIgnoreStd, lang); } }
// If the .PCH marker file has been found, truncate all preceeding .H files
if (pfiNew && fIsPCH) { FreeAllLk(pfi); FreeFi(pfi->pfiNext); pfi->pfiNext = NULL; }
/* If we found the file, add it to the list of files */ if (pfiNew != NULL) { /* add if not already in list */ LK * plk; BOOL fRedundant = FALSE;
for (plk = pfi->plkHead; plk != NULL; plk = plk->plkNext) { if (plk->pfi == pfiNew) { fRedundant = TRUE; break; } } if (!fRedundant) AllocLk(pfi, pfiNew); } } }
PopDir(); }
Cleanup: fclose(pfile); return pfi; }
char * SzIncludesC(sz, pfThisDir) /*
-- return file name of include file or NULL -- if returning non-NULL, set *pfThisDir if file should exist in this directory (i.e. #include "..."). */ char *sz; BOOL *pfThisDir; { char *szLine = sz;
while (isspace(*sz)) sz++;
if (sz[0] == '#') { /* Allow space after '#' but before directive.
*/ sz++; while (isspace(sz[0])) sz++;
if (strncmp(sz, "include", 7) == 0) { /* found it */ char * pchEnd;
sz += 7; while (isspace(*sz)) sz++; if ((*sz == '<' && (pchEnd =strchr(sz+1,'>')) !=NULL) || (*sz == '"' && (pchEnd =strchr(sz+1, '"')) !=NULL)) { *pfThisDir = *sz == '"'; *pchEnd = '\0'; return sz+1; } else { fprintf(stderr, "mkdep: warning: ignoring line : %s\n", szLine); return NULL; } } } return NULL; }
char * SzIncludesAsm(sz) /*
-- return file name of include file or NULL */ char *sz; { char *szLine = sz;
strlwr(szLine);
while (isspace(*sz)) sz++;
if (strncmp(sz, "include", 7) == 0) { /* found it */ char *pchEnd;
sz += 7; while (isspace(*sz)) sz++; pchEnd = sz; while (*pchEnd && !isspace(*pchEnd) && *pchEnd != ';') pchEnd++; if (pchEnd == sz) { fprintf(stderr, "mkdep: warning: ignoring line : %s\n", szLine); return NULL; } *pchEnd = '\0'; return sz; } return NULL; }
char * SzIncludesRC(sz, pfThisDir) /*
-- return name of include file or resource file for an RC file -- if returning non-NULL, set *pfThisDir if file should exist in this directory (i.e. #include "..."). */ char *sz; BOOL *pfThisDir; {
static char *aszValidTypes[] = { "CURSOR", "ICON", "RT_DOCFILE", "TYPELIB", "BITMAP" }; static int cValidTypes = sizeof(aszValidTypes)/sizeof(aszValidTypes[0]);
char achIdent[255] = { 0 }; char achType[255] = { 0 }; char achFile[255] = { 0 }; char * pch; int cch; char * szC; int n, i;
szC = SzIncludesC(sz, pfThisDir); if (szC) return szC;
*pfThisDir = TRUE;
n = sscanf(sz, "%[a-zA-Z0-9_] %[a-zA-Z0-9_] %n%[a-zA-Z0-9.\"]", achIdent, achType, &cch, achFile);
if (n < 3) return NULL;
for (i = cValidTypes; i && stricmp(achType, aszValidTypes[i-1]); i--) ;
if (i == 0) return NULL;
sz += cch;
while (isspace(*sz)) sz++;
sz[strlen(achFile)] = '\0';
if (*sz == '\"') sz++;
if ((pch = strrchr(sz, '\"')) != NULL) *pch = '\0';
return sz;
}
FI * PfiLookup(szPath, szName, lang) /*
-- lookup name in current list of FI; if file is of an unknown language and lang is not, set the language of this file. */ char * szPath; // path name to file
char * szName; // official name of file
LANG lang; // lang desired; langUnknown means any acceptible
{ FI *pfi;
for (pfi = pfiHead; pfi != NULL; pfi = pfi->pfiNext) { if (strcmp(szPath, pfi->szPath) == 0) { /* got one */ if (lang != langUnknown && lang != pfi->lang) { // want a specific language and that is not what the file is
if (pfi->lang != langUnknown) fprintf(stderr, "mkdep: warning: language conflict for file %s\n", pfi->szPath); else pfi->lang = lang; // was unknown, set to known
}
return pfi; } }
return NULL; }
FI * PfiAlloc(szPath, szName, fIgnore, lang) /*
-- allocate an FI */ char * szPath; // path name to file
char * szName; // official name of file
BOOL fIgnore; // true -> don't print this file
LANG lang; // lang for file; can be langUnknown
{ FI *pfi;
if ((pfi = (FI *) malloc(sizeof(FI))) == NULL || (pfi->szName = strdup(szName)) == NULL || (pfi->szPath = strdup(szPath)) == NULL) Fatal("out of memory"); pfi->lang = lang; pfi->fIgnore = fIgnore; pfi->plkHead = pfi->plkTail = NULL; AddToList(pfi, pfiHead, pfiTail, pfiNext, NULL); pfi->cout = coutCur; return pfi; }
VOID FreeFi(pfiFree) /*
-- free an FI and all associated LK and remove from FI list */ FI *pfiFree; { FI *pfiT, *pfiPrev;
FreeAllLk(pfiFree);
for (pfiT = pfiHead, pfiPrev = 0; pfiT != pfiFree; pfiPrev = pfiT, pfiT = pfiT->pfiNext) { // should find it on list
// Assert(pfiT != NULL);
}
DeleteFromList(pfiFree, pfiHead, pfiTail, pfiNext, NULL, pfiPrev);
free(pfiFree); }
VOID AllocLk(pfiOwner, pfiNew) /*
-- allocate a LK - add to owner list - point to pfiNew */ FI *pfiOwner; FI *pfiNew; { LK *plk;
if ((plk = (LK *) malloc(sizeof(LK))) == NULL) Fatal("out of memory"); plk->plkNext = NULL; AddToList(plk, pfiOwner->plkHead, pfiOwner->plkTail, plkNext, NULL); plk->pfi = pfiNew; }
VOID FreeAllLk(pfi) /*
-- free all lk attached to FI */ FI *pfi; { LK * plk; LK * plkNext;
for (plk = pfi->plkHead; plk != NULL; plk = plkNext) { plkNext = plk->plkNext; free(plk); }
pfi->plkHead = NULL; pfi->plkTail = NULL; }
SZ SzTransEnv(sz) /*
-- return a path string with optional $(...) in it */ SZ sz; { SZ szEnv; char * pch; char szT[256];
if (sz[0] != '$' || sz[1] != '(') return sz; sz += 2;
if ((pch = strchr(sz, ')')) == NULL) return sz; // something wrong
*pch = '\0'; if ((szEnv = getenv(sz)) == NULL) { fprintf(stderr, "mkdep: warning: environment variable %s not defined\n"); Fatal("incomplete path"); } *pch = ')'; // restore string
/* copy the environment variable into buffer */ strcpy(szT, szEnv); strcat(szT, pch+1); // and rest of string
NormalizePath(szT); // normalize again with new prefix
return strdup(szT); }
VOID NormalizePath(sz) /*
-- convert path to a normal form in place: forward slashes, no ../, etc. */ char *sz; { char *pch, *pch2;
/* change all backslashes to forward slashes */ for (pch=sz; *pch; ++pch) if (*pch == '\\') *pch = '/';
/* Remove ".." entries. (The algorithm below doesn't find all
* possible cases, but it's good enuff.) */ while ((pch=strstr(sz, "/../")) != NULL) { *pch = '\0'; pch2 = strrchr(sz, '/'); if (pch2 != NULL && pch2[1] != '$' && pch2[1] != '.') memmove(pch2+1, pch+4, strlen(pch+1)+1); else { *pch = '/'; break; } }
// remove single . and leading ./
if (sz[0] == '.') { if (sz[1] == '\0') sz[0] = '\0';
else if (sz[1] == '/') memmove(sz, sz+2, strlen(sz)-2+1); } }
VOID MakeName(szDest, szSrcPath, szSrcFile) /*
-- copy a path plus filename into a complete filename -- normalizes when done */ char * szDest; // where to store complete filename
char * szSrcPath; // path
char * szSrcFile; // filename
{ if (szSrcFile[0] && szSrcFile[1]==':') { if (!(szSrcPath[0] && szSrcPath[1]==':') || tolower(szSrcPath[0]) != tolower(szSrcFile[0])) { strcpy(szDest, szSrcFile); NormalizePath(szDest); return; } *szDest++ = *szSrcFile++; *szDest++ = *szSrcFile++; } if (szSrcFile[0] == '/' || szSrcFile[0] == '\\') { strcpy(szDest, szSrcFile); NormalizePath(szDest); return; }
strcpy(szDest, szSrcPath); if (szDest[0] != '\0') { char ch = szDest[strlen(szDest)-1];
if (ch != ':' && ch != '/' && ch != '\\') strcat(szDest, "/"); } strcat(szDest, szSrcFile);
NormalizePath(szDest); }
VOID CopyPath(szDestPath, szSrcFullName) /*
-- copy the path part of szSrcFullName into szDestPath */ char * szDestPath; char * szSrcFullName; { int ich; int ichPathEnd; // index to end of path part of szSrcFullName
char ch;
/* Figure out where the path part of szSrcFullName ends and the
* name part begins. */ for (ich = ichPathEnd = 0; (ch=szSrcFullName[ich]) != 0; ++ich) if (ch == ':' || ch == '/' || ch == '\\') ichPathEnd = ich+1;
/* Copy the path */ for (ich = 0; ich < ichPathEnd; ++ich) szDestPath[ich] = szSrcFullName[ich]; szDestPath[ich] = 0; }
VOID PushDir(szPath, szName, fPathIsStd) /*
-- push a directory name on the stack of directories for all nested includes */ char * szPath; // path name of file (e.g. "c:\foo\bar")
char * szName; // official name of file (e.g. "$(INCL)")
BOOL fPathIsStd; // path portion of szPath is from standard includes (-I)
{ DI * pdi;
if ((pdi = malloc(sizeof(DI))) == NULL) Fatal("out of memory"); pdi->szPath = strdup(szPath); pdi->szName = strdup(szName); pdi->fPathIsStd = fPathIsStd; /* Insert at head of list */ pdi->pdiNext = pdiHead; pdiHead = pdi; }
VOID PopDir(void) /*
-- pop a directory name from the stack of directories for all nested includes */ { DI *pdiFree;
if (pdiHead == NULL) Fatal("mkdep: internal error");
pdiFree = pdiHead; pdiHead = pdiHead->pdiNext;
free(pdiFree->szPath); free(pdiFree->szName); free(pdiFree); }
DI * PdiFromIdi(idi) /*
-- return a pointer to one element from the stack, or NULL */ int idi; // index of element to get (0 = top of stack)
{ DI * pdi;
for (pdi = pdiHead; pdi && idi; idi--) pdi = pdi->pdiNext; return pdi; }
int AddIncludeDir(szFile) char * szFile; { if (iszIncMac+1 >= iszIncMax) { fprintf(stderr, "mkdep: warning" ": too many include directories" "; ignoring %s\n", szFile); return 0; } else { /* normal include */ NormalizePath(szFile); rgszIncPath[iszIncMac] = SzTransEnv(szFile); rgszIncName[iszIncMac] = szFile; // fprintf(stderr,"Added include: %s\n",szFile);
iszIncMac++; return 1; } }
|