Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1490 lines
37 KiB

  1. /*-----------------------------------------------------------------------------
  2. Name: mkdep.c
  3. Description:
  4. Determine file dependencies
  5. To Build:
  6. cl /Ox /W3 mkdep.c
  7. Revision History:
  8. brendand (8/3/94) - Taken from GaryBu, merged files into a single unit
  9. brendand (8/4/94) - Added .PCH and wild-card support
  10. -----------------------------------------------------------------------------*/
  11. // Includes -------------------------------------------------------------------
  12. #define LINT_ARGS
  13. #include <assert.h>
  14. #include <ctype.h>
  15. #include <io.h>
  16. #include <malloc.h>
  17. #include <process.h>
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. // Types and Constants --------------------------------------------------------
  22. #ifndef CDECL
  23. #define CDECL
  24. #endif
  25. #ifndef CONST
  26. #define CONST
  27. #endif
  28. #ifndef STATIC
  29. #define STATIC static
  30. #endif
  31. #ifndef Assert
  32. #define Assert(f) assert(f)
  33. #endif
  34. #define TRUE 1
  35. #define FALSE 0
  36. #define FOREVER while(1)
  37. #define BLOCK
  38. #define VOID void
  39. #ifdef D86
  40. #define szROText "rt"
  41. #define szRWText "r+t"
  42. #define szWOText "wt"
  43. #define szROBin "rb"
  44. #define szRWBin "r+b"
  45. #define szWOBin "wb"
  46. #endif
  47. typedef int BOOL;
  48. typedef char* SZ;
  49. typedef unsigned char BYTE;
  50. typedef BYTE* PB;
  51. typedef unsigned short WORD;
  52. typedef WORD* PW;
  53. typedef unsigned long LONG;
  54. #define lpbNull ((PB) NULL)
  55. #define LOWORD(l) ((WORD)l)
  56. #define HIWORD(l) ((WORD)(((LONG)l >> 16) & 0xffff))
  57. #define LOBYTE(w) ((BYTE)w)
  58. #define HIBYTE(w) (((WORD)w >> 8) & 0xff)
  59. #define MAKEWORD(l,h) ((WORD)(l)|((WORD)(h)<<8))
  60. #define MAKELONG(l,h) ((long)(((unsigned)l)|((unsigned long)((unsigned)h))<<16))
  61. /* Args Record - MarkArgs, UnmarkArgs */
  62. typedef struct
  63. {
  64. int cargArr;
  65. SZ *pszArr;
  66. } ARR;
  67. /* drive usage types - getdt */
  68. #define dtNil 0
  69. #define dtLocal 1
  70. #define dtUserNet 2
  71. /* File attributes - getatr, setatr */
  72. #define atrError 0xffff
  73. #define atrReadOnly FILE_READONLY
  74. #define atrHidden FILE_HIDDEN
  75. #define atrSystem FILE_SYSTEM
  76. #define atrVolume 0x08
  77. #define atrDirectory FILE_DIRECTORY
  78. #define atrArchive FILE_ARCHIVED
  79. /* Macro for defining Linked list inertion */
  80. #define AddToList(new,head,tail,link,null) { if(head==null) head=new; else tail->link = new; tail=new; new->link=null; }
  81. /* & deletion */
  82. #define DeleteFromList(item,head,tail,link,null,prev) { if(prev==null) head=item->link; else prev->link = item->link; \
  83. if (tail==item) tail = prev; }
  84. /* for MtimeOfFile() */
  85. typedef long MTIME;
  86. #define mtimeError ((MTIME) -1L)
  87. typedef enum
  88. {
  89. langUnknown,
  90. langC,
  91. langAsm,
  92. langRC
  93. } LANG;
  94. typedef struct _di
  95. {
  96. struct _di *pdiNext; /* next in list */
  97. char *szPath; /* path name */
  98. char *szName; /* full name */
  99. BOOL fPathIsStd; /* name from standard includes (-I) */
  100. } DI; /* dir info */
  101. typedef struct _lk
  102. {
  103. struct _lk *plkNext; /* next in list */
  104. struct _fi *pfi; /* file info for link */
  105. } LK; /* File link */
  106. typedef struct _fi
  107. {
  108. struct _fi *pfiNext; /* single link */
  109. char *szPath; /* path name */
  110. char *szName; /* full name */
  111. LANG lang; /* language */
  112. struct _lk *plkHead; /* included list */
  113. struct _lk *plkTail; /* included list */
  114. unsigned fIgnore:1; /* ignore: either -X and std include or -x <file> */
  115. unsigned cout:15; /* output count */
  116. } FI; /* file info */
  117. typedef VOID (*PFN_ENUM)(char *, char *);
  118. #define iszIncMax 40
  119. char* szPrefix = "";
  120. char* szSuffix = ".$O";
  121. #define rmj 1
  122. #define rmm 1
  123. #define rup 0
  124. #define szVerName "Forms3 Version"
  125. // Globals --------------------------------------------------------------------
  126. DI* pdiHead = NULL; /* stack of directories of files included */
  127. FI* pfiHead = NULL;
  128. FI* pfiTail = NULL;
  129. WORD coutCur = 0;
  130. int cchLine;
  131. int iszIncMac = 0;
  132. char* rgszIncPath[iszIncMax]; // actual path
  133. char* rgszIncName[iszIncMax]; // name to output
  134. BOOL fVerbose = FALSE;
  135. BOOL fReplacePrefix = FALSE;
  136. BOOL fNoGenHeaders = FALSE; // True if all header files must be present
  137. BOOL fIgnoreStd = FALSE; // True if std include files should be ignored
  138. BOOL fUseCurDir = FALSE; // When True: if a file doesn't exist and
  139. // we are going to print a dependency for
  140. // it, use the current directory rather
  141. // than the directory of the source file.
  142. char* szPrintDir = NULL; // If set, only print files in this dir.
  143. char* szPCHFile = NULL; // .H which marks end of .PCH
  144. // Prototypes -----------------------------------------------------------------
  145. int main(int, char**);
  146. VOID Usage(void);
  147. char* SzIncludesC(char *, BOOL *), *SzIncludesAsm(char *), *SzIncludesRC(char *, BOOL *);
  148. FI* PfiDependFn(char *, char *, BOOL, LANG, BOOL);
  149. FI* PfiLookup(char *, char *, LANG);
  150. FI* PfiAlloc(char *, char *, BOOL, LANG);
  151. VOID FreeFi(FI *);
  152. VOID AllocLk(FI *, FI *);
  153. VOID FreeAllLk(FI *);
  154. VOID StartReport(void);
  155. VOID ContinueReport(void);
  156. VOID EndReport(void);
  157. VOID EndLine(void);
  158. VOID Indent(void);
  159. VOID Report(char *, char *);
  160. VOID PrReverse(char *, char *);
  161. BOOL FPrintFi(FI *);
  162. VOID EnumChildren(FI *, PFN_ENUM, char *);
  163. VOID Process(char *, BOOL);
  164. VOID Fatal(char *);
  165. SZ SzTransEnv(SZ);
  166. VOID NormalizePath(SZ);
  167. VOID MakeName(SZ, SZ, SZ);
  168. VOID CopyPath(SZ, SZ);
  169. VOID PushDir(char *, char *, BOOL);
  170. VOID PopDir(void);
  171. DI* PdiFromIdi(int);
  172. int AddIncludeDir(char *);
  173. VOID
  174. Fatal(sz)
  175. char *sz;
  176. {
  177. fprintf(stderr, "mkdep: error: %s\n", sz);
  178. exit(1);
  179. }
  180. VOID
  181. Usage()
  182. {
  183. if (rup == 0)
  184. fprintf(stderr, "Mkdep V%d.%02d\n", rmj, rmm);
  185. else
  186. fprintf(stderr, "Mkdep V%d.%02d.%02d\n", rmj, rmm, rup);
  187. fprintf(stderr,
  188. "usage: mkdep [-v] [-r] [-n] [-X] [-C] [-I includeDir]*\n"
  189. "\t[-p prefix] [-P replace_prefix] [-s suffix] \n"
  190. "\t[-d file]* [-D printDir] files\n\n"
  191. "\t-v Verbose\n"
  192. "\t-r Reverse the dependencies that are output\n"
  193. "\t-n Don't emit dependencies on files that don't now exist\n"
  194. "\t-X Search, but don't print standard includes\n"
  195. "\t-C If file doesn't exist, use .\\ not the directory of including file\n"
  196. "\t-I Include directory to search for <> includes\n"
  197. // "\t-J Search include directories from the INCLUDE environment variable\n"
  198. "\t-p Prefix for all target-file names\n"
  199. "\t-P Ditto, but first remove existing prefix from name\n"
  200. "\t-s Suffix for all target-file names (default %s)\n"
  201. "\t-d Search, but don't print named file\n"
  202. "\t-D Only print files which are in named dir\n"
  203. "\t-h Header which marks the end of the .PCH\n\n"
  204. "A response file can be used by specifying '@filename' as an option.\n"
  205. , szSuffix);
  206. exit(1);
  207. }
  208. char **CmdArgs;
  209. int cArgs;
  210. int CurArg = 1;
  211. FILE *pfileResponse = NULL;
  212. char achBuf[256];
  213. char * pBuf = NULL;
  214. char *
  215. GetNextArg()
  216. {
  217. char *pszTokens = " \t\n";
  218. if (pfileResponse)
  219. {
  220. char * psz;
  221. if (pBuf)
  222. {
  223. pBuf = strtok(NULL, pszTokens);
  224. if (pBuf)
  225. return pBuf;
  226. }
  227. do
  228. {
  229. psz = fgets(achBuf, 256, pfileResponse);
  230. if (psz == NULL)
  231. {
  232. fclose(pfileResponse);
  233. pfileResponse = NULL;
  234. }
  235. else if (achBuf[strlen(achBuf)-1] != '\n')
  236. {
  237. fclose(pfileResponse);
  238. Fatal("Line too long in response file. Must be less "
  239. "than 256 characters.");
  240. }
  241. else
  242. {
  243. pBuf = strtok(achBuf, pszTokens);
  244. if (pBuf)
  245. return pBuf;
  246. }
  247. } while (psz && !pBuf);
  248. }
  249. if (CurArg >= cArgs)
  250. return NULL;
  251. return CmdArgs[CurArg++];
  252. }
  253. #define FSwitchCh(ch) ((ch)=='-' || (ch) == '/' || (ch) == '@')
  254. int
  255. main(iszMax, rgsz)
  256. int iszMax;
  257. char *rgsz[];
  258. {
  259. BOOL fReverse = FALSE;
  260. char *pszArg;
  261. int i = 0;
  262. if (iszMax == 1)
  263. Usage();
  264. CmdArgs = rgsz;
  265. cArgs = iszMax;
  266. /* Parse command line switches.
  267. */
  268. while (((pszArg = GetNextArg()) != NULL) && FSwitchCh(pszArg[0]))
  269. {
  270. char chSwitch = pszArg[1];
  271. if (pszArg[0] == '@')
  272. {
  273. if (pszArg[1] == '\0')
  274. Usage();
  275. pfileResponse = fopen(&pszArg[1], "rt");
  276. if (!pfileResponse)
  277. {
  278. fprintf(stderr, "mkdep: error: Could not open response file "
  279. "'%s'.\n", &pszArg[1]);
  280. return(1);
  281. }
  282. continue;
  283. }
  284. // fprintf(stderr, "Arg %d: '%s' ", i++, pszArg);
  285. switch (chSwitch)
  286. {
  287. case 'v':
  288. fVerbose = TRUE;
  289. break;
  290. case 'r':
  291. fReverse = TRUE;
  292. break;
  293. case 'n':
  294. fNoGenHeaders = TRUE;
  295. break;
  296. case 'x':
  297. case 'X':
  298. fIgnoreStd = TRUE;
  299. break;
  300. case 'C':
  301. fUseCurDir = TRUE;
  302. break;
  303. #if 0
  304. case 'J':
  305. {
  306. SZ szInc = getenv("INCLUDE");
  307. if (szInc)
  308. {
  309. char rgszDir[iszIncMax][_MAX_FNAME];
  310. int nDirs,i;
  311. char* psz;
  312. // Convert embedded semicolons to blanks
  313. for (psz=szInc; *psz; psz++)
  314. if (*psz == ';')
  315. *psz = ' ';
  316. /* This is very bogus! a dynamic way of reading the dirs
  317. should be done so up to iszIncMax dirs can be read. Also,
  318. AddIncludeDir does not copy the strings and rgszDir is
  319. an automatic variable!
  320. */
  321. fprintf(stderr, "-J option: only first 16 include dirs parsed.\n");
  322. nDirs =
  323. sscanf(szInc,
  324. "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
  325. rgszDir[0],rgszDir[1],rgszDir[2],rgszDir[3],rgszDir[4],
  326. rgszDir[5],rgszDir[6],rgszDir[7],rgszDir[8],rgszDir[9],
  327. rgszDir[10],rgszDir[11],rgszDir[12],rgszDir[13],
  328. rgszDir[14],rgszDir[15]);
  329. for (i = 0; i < nDirs; i++)
  330. AddIncludeDir(rgszDir[i]);
  331. }
  332. else
  333. fprintf(stderr,"-J option: INCLUDE variable not set.\n");
  334. }
  335. break;
  336. #endif
  337. case 's':
  338. case 'P':
  339. case 'p':
  340. case 'I':
  341. case 'd':
  342. case 'D':
  343. case 'h':
  344. {
  345. char *sz = &pszArg[2];
  346. if (sz[0] == '\0')
  347. {
  348. /* Allow "-I includefile"
  349. * and "-IincludeFile"
  350. */
  351. pszArg = GetNextArg();
  352. if (!pszArg)
  353. Usage();
  354. sz = pszArg;
  355. }
  356. // fprintf(stderr, "File: '%s'.", sz);
  357. sz = strdup(sz);
  358. switch (chSwitch)
  359. {
  360. case 's':
  361. szSuffix = sz;
  362. break;
  363. case 'P':
  364. fReplacePrefix = TRUE;
  365. // Drop through
  366. case 'p':
  367. szPrefix = sz;
  368. break;
  369. case 'I':
  370. AddIncludeDir(sz);
  371. break;
  372. case 'd':
  373. {
  374. FI *pfi;
  375. // exlude file given
  376. // NOTE: the -C option if given, must appear before now
  377. NormalizePath(sz);
  378. if ((pfi = PfiDependFn(SzTransEnv(sz), sz, FALSE, langUnknown, FALSE)) != NULL)
  379. // file existed; ignore it
  380. pfi->fIgnore = TRUE;
  381. else
  382. // file doesn't exist, create FI
  383. (void)PfiAlloc(SzTransEnv(sz), sz, TRUE, langUnknown);
  384. break;
  385. }
  386. case 'D':
  387. /* only print files from given directory */
  388. NormalizePath(sz);
  389. szPrintDir = sz;
  390. break;
  391. case 'h':
  392. szPCHFile = sz;
  393. break;
  394. }
  395. }
  396. break;
  397. default:
  398. Usage();
  399. break;
  400. }
  401. // fprintf(stderr, "\n");
  402. }
  403. while (pszArg)
  404. {
  405. long hf;
  406. char szPath[_MAX_DIR];
  407. char szName[_MAX_PATH];
  408. struct _finddata_t fd;
  409. // fprintf(stderr, "Reading path '%s' - ", pszArg);
  410. NormalizePath(pszArg);
  411. CopyPath(szPath, pszArg);
  412. // fprintf(stderr, "'%s\\%s'\n", szPath, pszArg);
  413. hf = _findfirst(pszArg, &fd);
  414. if (hf > -1)
  415. {
  416. do
  417. {
  418. MakeName(szName, szPath, fd.name);
  419. // fprintf(stderr, " -- '%s'\n", szName);
  420. Process(szName, fReverse);
  421. }
  422. while (!_findnext(hf, &fd));
  423. _findclose(hf);
  424. }
  425. // else
  426. // fprintf(stderr, "Unable to find source file: %s\n", pszArg);
  427. pszArg = GetNextArg();
  428. }
  429. return( 0 );
  430. }
  431. /*****************************************************************************/
  432. /* standard dependency report */
  433. VOID
  434. StartReport()
  435. /*
  436. -- prepare for a new line
  437. */
  438. {
  439. cchLine = 77;
  440. }
  441. VOID
  442. EndLine()
  443. /*
  444. -- Make it so that the next Report starts on a new line.
  445. */
  446. {
  447. cchLine = 0;
  448. }
  449. VOID
  450. ContinueReport()
  451. /*
  452. -- Output continuation character, new line, then indent.
  453. */
  454. {
  455. printf(" \\\n");
  456. StartReport();
  457. Indent();
  458. }
  459. VOID
  460. EndReport()
  461. /*
  462. -- Finish off this line.
  463. */
  464. {
  465. printf("\n\n");
  466. }
  467. VOID
  468. Indent()
  469. /*
  470. -- Indent a tab at the beginning of a line.
  471. */
  472. {
  473. printf("\t");
  474. cchLine -= 8; /* for tab */
  475. }
  476. VOID
  477. Report(sz, szParm)
  478. /*
  479. -- report string
  480. -- if too many characters extend line
  481. */
  482. register char * sz;
  483. char * szParm; /* ignored */
  484. {
  485. int cch = strlen(sz);
  486. if (cch > cchLine)
  487. {
  488. ContinueReport();
  489. while (isspace(sz[0]))
  490. {
  491. sz++;
  492. cch--;
  493. }
  494. }
  495. while (*sz != '\0')
  496. {
  497. if (*sz == '#')
  498. {
  499. putchar('\\'); /* escape any # in path */
  500. cch++;
  501. }
  502. putchar(*sz);
  503. sz++;
  504. }
  505. cchLine -= cch;
  506. }
  507. /*****************************************************************************/
  508. /* Reverse dependency printing */
  509. VOID
  510. PrReverse(szHdr, szSource)
  511. /*
  512. -- report reverse dependency
  513. */
  514. char * szHdr;
  515. char * szSource;
  516. {
  517. printf("%s: %s\n", szHdr, szSource);
  518. }
  519. /*****************************************************************************/
  520. BOOL FPrintFi(pfi)
  521. /*
  522. -- returns true if we should print this file; false if ignore; false if
  523. szPrintDir is != 0 and it is a prefix of szName. The current directory
  524. is a zero length string and is handled specially
  525. */
  526. FI *pfi;
  527. {
  528. if (pfi->fIgnore)
  529. return FALSE;
  530. if (szPrintDir == NULL)
  531. return TRUE;
  532. if (*szPrintDir == '\0')
  533. // only print current directory (check for / in name)
  534. return strchr(pfi->szName, '/') == 0;
  535. else
  536. // print if szPrintDir is prefix of name
  537. return strncmp(szPrintDir, pfi->szName, strlen(szPrintDir)) == 0;
  538. }
  539. VOID
  540. EnumChildren(pfi, pfnDo, szParm)
  541. /*
  542. -- enumerate children, call *pfnDo for each element
  543. */
  544. FI * pfi;
  545. PFN_ENUM pfnDo;
  546. char * szParm;
  547. {
  548. LK *plk;
  549. for (plk = pfi->plkHead; plk != NULL; plk = plk->plkNext)
  550. {
  551. FI *pfi = plk->pfi;
  552. if (pfi->cout < coutCur)
  553. {
  554. /* Mark that we've visited this node, to prevent
  555. * infinite recursion should we have a self referential
  556. * dependency graph.
  557. */
  558. pfi->cout = coutCur;
  559. if (FPrintFi(pfi))
  560. {
  561. if (szParm == NULL)
  562. (*pfnDo)(" ", szParm);
  563. (*pfnDo)(pfi->szName, szParm);
  564. }
  565. // recurse on nested includes; may include a non-standard includes
  566. EnumChildren(pfi, pfnDo, szParm);
  567. }
  568. }
  569. }
  570. VOID
  571. Process(szPath, fReverse)
  572. /*
  573. -- process a file
  574. -- reverse => show headers as depending on files
  575. */
  576. char * szPath; // path name to file
  577. BOOL fReverse;
  578. {
  579. FI * pfi;
  580. strlwr(szPath);
  581. /* Build a list of all dependencies. */
  582. pfi = PfiDependFn(szPath, szPath, FALSE, langUnknown, FALSE);
  583. if (pfi == NULL)
  584. {
  585. if (fVerbose)
  586. fprintf(stderr, "mkdep: warning: file %s ignored\n", szPath);
  587. }
  588. else if (pfi->plkHead != NULL)
  589. {
  590. /* file depends on something */
  591. if (!fReverse)
  592. {
  593. /* normal dependencies */
  594. char * pch;
  595. /* truncate any suffix */
  596. pch = strrchr(szPath, '.');
  597. if (pch)
  598. {
  599. if (strchr(pch, '/') || strchr(pch, '\\'))
  600. pch = NULL;
  601. }
  602. if (pch != NULL)
  603. *pch = '\0';
  604. StartReport();
  605. Report(szPrefix, NULL);
  606. if (fReplacePrefix)
  607. {
  608. /* prefix replaces any name prefix */
  609. char * szName = szPath;
  610. while (*szPath != '\0')
  611. {
  612. if (*szPath == '\\' || *szPath == '/')
  613. szName = szPath+1;
  614. szPath++;
  615. }
  616. Report(szName, NULL);
  617. }
  618. else
  619. {
  620. Report(szPath, NULL);
  621. }
  622. Report(szSuffix, NULL);
  623. Report(" :", NULL);
  624. EndLine();
  625. coutCur++;
  626. EnumChildren(pfi, Report, NULL);
  627. EndReport();
  628. }
  629. else
  630. {
  631. /* reverse dependencies */
  632. coutCur++;
  633. EnumChildren(pfi, PrReverse, szPath);
  634. }
  635. }
  636. if (pfi != NULL)
  637. // free top level FI (presumably for .c/.asm file which won't be needed)
  638. FreeFi(pfi);
  639. }
  640. FI *
  641. PfiDependFn(szPath, szName, fPathIsStd, lang, fIsPCHFile)
  642. /*
  643. -- given a file name & language, return a filled in FI
  644. -- return NULL if error
  645. */
  646. char * szPath; // path name to file
  647. char * szName; // official name of file
  648. BOOL fPathIsStd; // path portion of szPath is from standard includes (-I)
  649. LANG lang; // propagate parent language
  650. BOOL fIsPCHFile; // Is .PCH marker file
  651. {
  652. FILE * pfile;
  653. char rgch[256];
  654. char * sz;
  655. char * szSuffix;
  656. FI * pfi;
  657. /* first check to see if already in list */
  658. if ((pfi = PfiLookup(szPath, szName, lang)) != NULL)
  659. return pfi;
  660. if (lang != langUnknown)
  661. {
  662. /* do nothing -- keep old language */
  663. }
  664. else if ((szSuffix = strrchr(szPath, '.')) == NULL)
  665. return NULL;
  666. else if (strcmp(szSuffix, ".asm") == 0 || strcmp(szSuffix, ".inc") == 0)
  667. lang = langAsm;
  668. else if (strcmp(szSuffix, ".rc") == 0)
  669. lang = langRC;
  670. else
  671. lang = langC;
  672. if ((pfile = fopen(szPath, "rt")) == NULL)
  673. {
  674. // fprintf(stderr, "Could not open file '%s'.\n", szPath);
  675. return NULL;
  676. }
  677. pfi = PfiAlloc(szPath, szName, fPathIsStd && fIgnoreStd, lang);
  678. if (lang == langRC)
  679. {
  680. //
  681. // Make sure we don't try to parse binary files - major waste of time!
  682. //
  683. static char *aszBinary[] = { ".ico", ".sqz", ".bmp", ".tlb", ".cur",
  684. ".odg", ".ppg", ".otb" };
  685. static int cBinary = sizeof(aszBinary)/sizeof(aszBinary[0]);
  686. int i;
  687. if (!szSuffix)
  688. {
  689. if ((szSuffix = strrchr(szPath, '.')) == NULL)
  690. goto Cleanup;
  691. }
  692. for (i = cBinary; i && stricmp(szSuffix, aszBinary[i-1]); i--)
  693. ;
  694. if (i != 0)
  695. goto Cleanup;
  696. }
  697. // Don't search inside of the .PCH marker file
  698. if (!fIsPCHFile)
  699. {
  700. BLOCK
  701. {
  702. /* Push the directory of this file on the list of directories for
  703. * include searches. Save an indication as to whether this include is
  704. * from a standard place.
  705. */
  706. char szPathT[256];
  707. char szNameT[256];
  708. CopyPath(szPathT, szPath);
  709. CopyPath(szNameT, szName);
  710. PushDir(szPathT, szNameT, fPathIsStd);
  711. }
  712. while ((sz = fgets(rgch, 256, pfile)) != NULL)
  713. {
  714. char * szInc;
  715. BOOL fThisDirNew = FALSE; /* must be in this directory */
  716. int cch = strlen(sz);
  717. if (cch < 2)
  718. continue;
  719. if (sz[cch-1] == '\n')
  720. sz[cch-1] = '\0'; /* note : will truncate long lines */
  721. if ((lang == langC && (szInc = SzIncludesC(sz, &fThisDirNew)) != NULL) ||
  722. (lang == langAsm && (szInc = SzIncludesAsm(sz)) != NULL) ||
  723. (lang == langRC && (szInc = SzIncludesRC(sz, &fThisDirNew)) != NULL))
  724. {
  725. FI * pfiNew = NULL;
  726. char szPathNew[256];
  727. char szNameNew[256];
  728. BOOL fIsPCH;
  729. fIsPCH = (szPCHFile && !_stricmp(szInc, szPCHFile));
  730. /* if file can be found in current directory, cycle
  731. * through all current directories possible.
  732. */
  733. if (fThisDirNew)
  734. {
  735. int idi;
  736. DI * pdi;
  737. for (idi = 0; (pdi = PdiFromIdi(idi)) != NULL; idi++)
  738. {
  739. MakeName(szPathNew, pdi->szPath, szInc);
  740. MakeName(szNameNew, pdi->szName, szInc);
  741. /* Do recursive call to include file */
  742. pfiNew = PfiDependFn(szPathNew, szNameNew, pdi->fPathIsStd, lang, fIsPCH);
  743. /* If we found it, get out of loop */
  744. if (pfiNew != NULL)
  745. break;
  746. }
  747. }
  748. /* If the file hasn't been found yet, look for it
  749. * in the standard include directories.
  750. */
  751. if (pfiNew == NULL)
  752. {
  753. int isz;
  754. for (isz = 0; isz < iszIncMac; isz++)
  755. {
  756. MakeName(szPathNew, rgszIncPath[isz], szInc);
  757. MakeName(szNameNew, rgszIncName[isz], szInc);
  758. /* Do recursive call to include file */
  759. pfiNew = PfiDependFn(szPathNew, szNameNew, TRUE, lang, fIsPCH);
  760. /* If we found it, mark it and get out of loop */
  761. if (pfiNew != NULL)
  762. break;
  763. }
  764. }
  765. /* The file doesn't exist anywhere. If it was included
  766. * with quote marks and the user didn't specify -n, we
  767. * will pretend the file is in the same directory as
  768. * the file that's including it.
  769. */
  770. if (pfiNew == NULL && fThisDirNew && !fNoGenHeaders)
  771. {
  772. BOOL fPathIsStd;
  773. if (fUseCurDir)
  774. {
  775. MakeName(szPathNew, ".\\", szInc);
  776. MakeName(szNameNew, ".\\", szInc);
  777. fPathIsStd = FALSE;
  778. /* Look for -d names */
  779. if ((pfiNew = PfiLookup(szPathNew, szNameNew,lang)) == NULL)
  780. pfiNew = PfiAlloc(szPathNew, szNameNew, FALSE, lang);
  781. }
  782. else
  783. {
  784. DI * pdi;
  785. pdi = PdiFromIdi(0);
  786. if (pdi == NULL)
  787. Fatal("mkdep: internal error");
  788. MakeName(szPathNew, pdi->szPath, szInc);
  789. MakeName(szNameNew, pdi->szName, szInc);
  790. // in this case we already look through existing FI list
  791. pfiNew = PfiAlloc(szPathNew, szNameNew,
  792. pdi->fPathIsStd && fIgnoreStd, lang);
  793. }
  794. }
  795. // If the .PCH marker file has been found, truncate all preceeding .H files
  796. if (pfiNew && fIsPCH)
  797. {
  798. FreeAllLk(pfi);
  799. FreeFi(pfi->pfiNext);
  800. pfi->pfiNext = NULL;
  801. }
  802. /* If we found the file, add it to the list of files */
  803. if (pfiNew != NULL)
  804. {
  805. /* add if not already in list */
  806. LK * plk;
  807. BOOL fRedundant = FALSE;
  808. for (plk = pfi->plkHead; plk != NULL;
  809. plk = plk->plkNext)
  810. {
  811. if (plk->pfi == pfiNew)
  812. {
  813. fRedundant = TRUE;
  814. break;
  815. }
  816. }
  817. if (!fRedundant)
  818. AllocLk(pfi, pfiNew);
  819. }
  820. }
  821. }
  822. PopDir();
  823. }
  824. Cleanup:
  825. fclose(pfile);
  826. return pfi;
  827. }
  828. char *
  829. SzIncludesC(sz, pfThisDir)
  830. /*
  831. -- return file name of include file or NULL
  832. -- if returning non-NULL, set *pfThisDir if file should exist in this
  833. directory (i.e. #include "...").
  834. */
  835. char *sz;
  836. BOOL *pfThisDir;
  837. {
  838. char *szLine = sz;
  839. while (isspace(*sz))
  840. sz++;
  841. if (sz[0] == '#')
  842. {
  843. /* Allow space after '#' but before directive.
  844. */
  845. sz++;
  846. while (isspace(sz[0]))
  847. sz++;
  848. if (strncmp(sz, "include", 7) == 0)
  849. {
  850. /* found it */
  851. char * pchEnd;
  852. sz += 7;
  853. while (isspace(*sz))
  854. sz++;
  855. if ((*sz == '<' && (pchEnd =strchr(sz+1,'>')) !=NULL) ||
  856. (*sz == '"' && (pchEnd =strchr(sz+1, '"')) !=NULL))
  857. {
  858. *pfThisDir = *sz == '"';
  859. *pchEnd = '\0';
  860. return sz+1;
  861. }
  862. else
  863. {
  864. fprintf(stderr, "mkdep: warning: ignoring line : %s\n", szLine);
  865. return NULL;
  866. }
  867. }
  868. }
  869. return NULL;
  870. }
  871. char *
  872. SzIncludesAsm(sz)
  873. /*
  874. -- return file name of include file or NULL
  875. */
  876. char *sz;
  877. {
  878. char *szLine = sz;
  879. strlwr(szLine);
  880. while (isspace(*sz))
  881. sz++;
  882. if (strncmp(sz, "include", 7) == 0)
  883. {
  884. /* found it */
  885. char *pchEnd;
  886. sz += 7;
  887. while (isspace(*sz))
  888. sz++;
  889. pchEnd = sz;
  890. while (*pchEnd && !isspace(*pchEnd) && *pchEnd != ';')
  891. pchEnd++;
  892. if (pchEnd == sz)
  893. {
  894. fprintf(stderr, "mkdep: warning: ignoring line : %s\n", szLine);
  895. return NULL;
  896. }
  897. *pchEnd = '\0';
  898. return sz;
  899. }
  900. return NULL;
  901. }
  902. char *
  903. SzIncludesRC(sz, pfThisDir)
  904. /*
  905. -- return name of include file or resource file for an RC file
  906. -- if returning non-NULL, set *pfThisDir if file should exist in this
  907. directory (i.e. #include "...").
  908. */
  909. char *sz;
  910. BOOL *pfThisDir;
  911. {
  912. static char *aszValidTypes[] =
  913. {
  914. "CURSOR", "ICON", "RT_DOCFILE", "TYPELIB", "BITMAP"
  915. };
  916. static int cValidTypes = sizeof(aszValidTypes)/sizeof(aszValidTypes[0]);
  917. char achIdent[255] = { 0 };
  918. char achType[255] = { 0 };
  919. char achFile[255] = { 0 };
  920. char * pch;
  921. int cch;
  922. char * szC;
  923. int n, i;
  924. szC = SzIncludesC(sz, pfThisDir);
  925. if (szC)
  926. return szC;
  927. *pfThisDir = TRUE;
  928. n = sscanf(sz, "%[a-zA-Z0-9_] %[a-zA-Z0-9_] %n%[a-zA-Z0-9.\"]",
  929. achIdent, achType, &cch, achFile);
  930. if (n < 3)
  931. return NULL;
  932. for (i = cValidTypes; i && stricmp(achType, aszValidTypes[i-1]); i--)
  933. ;
  934. if (i == 0)
  935. return NULL;
  936. sz += cch;
  937. while (isspace(*sz))
  938. sz++;
  939. sz[strlen(achFile)] = '\0';
  940. if (*sz == '\"')
  941. sz++;
  942. if ((pch = strrchr(sz, '\"')) != NULL)
  943. *pch = '\0';
  944. return sz;
  945. }
  946. FI *
  947. PfiLookup(szPath, szName, lang)
  948. /*
  949. -- lookup name in current list of FI; if file is of an unknown language and
  950. lang is not, set the language of this file.
  951. */
  952. char * szPath; // path name to file
  953. char * szName; // official name of file
  954. LANG lang; // lang desired; langUnknown means any acceptible
  955. {
  956. FI *pfi;
  957. for (pfi = pfiHead; pfi != NULL; pfi = pfi->pfiNext)
  958. {
  959. if (strcmp(szPath, pfi->szPath) == 0)
  960. {
  961. /* got one */
  962. if (lang != langUnknown && lang != pfi->lang)
  963. {
  964. // want a specific language and that is not what the file is
  965. if (pfi->lang != langUnknown)
  966. fprintf(stderr,
  967. "mkdep: warning: language conflict for file %s\n",
  968. pfi->szPath);
  969. else
  970. pfi->lang = lang; // was unknown, set to known
  971. }
  972. return pfi;
  973. }
  974. }
  975. return NULL;
  976. }
  977. FI *
  978. PfiAlloc(szPath, szName, fIgnore, lang)
  979. /*
  980. -- allocate an FI
  981. */
  982. char * szPath; // path name to file
  983. char * szName; // official name of file
  984. BOOL fIgnore; // true -> don't print this file
  985. LANG lang; // lang for file; can be langUnknown
  986. {
  987. FI *pfi;
  988. if ((pfi = (FI *) malloc(sizeof(FI))) == NULL ||
  989. (pfi->szName = strdup(szName)) == NULL ||
  990. (pfi->szPath = strdup(szPath)) == NULL)
  991. Fatal("out of memory");
  992. pfi->lang = lang;
  993. pfi->fIgnore = fIgnore;
  994. pfi->plkHead = pfi->plkTail = NULL;
  995. AddToList(pfi, pfiHead, pfiTail, pfiNext, NULL);
  996. pfi->cout = coutCur;
  997. return pfi;
  998. }
  999. VOID
  1000. FreeFi(pfiFree)
  1001. /*
  1002. -- free an FI and all associated LK and remove from FI list
  1003. */
  1004. FI *pfiFree;
  1005. {
  1006. FI *pfiT, *pfiPrev;
  1007. FreeAllLk(pfiFree);
  1008. for (pfiT = pfiHead, pfiPrev = 0; pfiT != pfiFree; pfiPrev = pfiT, pfiT = pfiT->pfiNext)
  1009. {
  1010. // should find it on list
  1011. // Assert(pfiT != NULL);
  1012. }
  1013. DeleteFromList(pfiFree, pfiHead, pfiTail, pfiNext, NULL, pfiPrev);
  1014. free(pfiFree);
  1015. }
  1016. VOID
  1017. AllocLk(pfiOwner, pfiNew)
  1018. /*
  1019. -- allocate a LK - add to owner list - point to pfiNew
  1020. */
  1021. FI *pfiOwner;
  1022. FI *pfiNew;
  1023. {
  1024. LK *plk;
  1025. if ((plk = (LK *) malloc(sizeof(LK))) == NULL)
  1026. Fatal("out of memory");
  1027. plk->plkNext = NULL;
  1028. AddToList(plk, pfiOwner->plkHead, pfiOwner->plkTail, plkNext, NULL);
  1029. plk->pfi = pfiNew;
  1030. }
  1031. VOID
  1032. FreeAllLk(pfi)
  1033. /*
  1034. -- free all lk attached to FI
  1035. */
  1036. FI *pfi;
  1037. {
  1038. LK * plk;
  1039. LK * plkNext;
  1040. for (plk = pfi->plkHead; plk != NULL; plk = plkNext)
  1041. {
  1042. plkNext = plk->plkNext;
  1043. free(plk);
  1044. }
  1045. pfi->plkHead = NULL;
  1046. pfi->plkTail = NULL;
  1047. }
  1048. SZ
  1049. SzTransEnv(sz)
  1050. /*
  1051. -- return a path string with optional $(...) in it
  1052. */
  1053. SZ sz;
  1054. {
  1055. SZ szEnv;
  1056. char * pch;
  1057. char szT[256];
  1058. if (sz[0] != '$' || sz[1] != '(')
  1059. return sz;
  1060. sz += 2;
  1061. if ((pch = strchr(sz, ')')) == NULL)
  1062. return sz; // something wrong
  1063. *pch = '\0';
  1064. if ((szEnv = getenv(sz)) == NULL)
  1065. {
  1066. fprintf(stderr,
  1067. "mkdep: warning: environment variable %s not defined\n");
  1068. Fatal("incomplete path");
  1069. }
  1070. *pch = ')'; // restore string
  1071. /* copy the environment variable into buffer */
  1072. strcpy(szT, szEnv);
  1073. strcat(szT, pch+1); // and rest of string
  1074. NormalizePath(szT); // normalize again with new prefix
  1075. return strdup(szT);
  1076. }
  1077. VOID NormalizePath(sz)
  1078. /*
  1079. -- convert path to a normal form in place: forward slashes, no ../, etc.
  1080. */
  1081. char *sz;
  1082. {
  1083. char *pch, *pch2;
  1084. /* change all backslashes to forward slashes */
  1085. for (pch=sz; *pch; ++pch)
  1086. if (*pch == '\\')
  1087. *pch = '/';
  1088. /* Remove ".." entries. (The algorithm below doesn't find all
  1089. * possible cases, but it's good enuff.)
  1090. */
  1091. while ((pch=strstr(sz, "/../")) != NULL)
  1092. {
  1093. *pch = '\0';
  1094. pch2 = strrchr(sz, '/');
  1095. if (pch2 != NULL && pch2[1] != '$' && pch2[1] != '.')
  1096. memmove(pch2+1, pch+4, strlen(pch+1)+1);
  1097. else
  1098. {
  1099. *pch = '/';
  1100. break;
  1101. }
  1102. }
  1103. // remove single . and leading ./
  1104. if (sz[0] == '.')
  1105. {
  1106. if (sz[1] == '\0')
  1107. sz[0] = '\0';
  1108. else if (sz[1] == '/')
  1109. memmove(sz, sz+2, strlen(sz)-2+1);
  1110. }
  1111. }
  1112. VOID
  1113. MakeName(szDest, szSrcPath, szSrcFile)
  1114. /*
  1115. -- copy a path plus filename into a complete filename
  1116. -- normalizes when done
  1117. */
  1118. char * szDest; // where to store complete filename
  1119. char * szSrcPath; // path
  1120. char * szSrcFile; // filename
  1121. {
  1122. if (szSrcFile[0] && szSrcFile[1]==':')
  1123. {
  1124. if (!(szSrcPath[0] && szSrcPath[1]==':') ||
  1125. tolower(szSrcPath[0]) != tolower(szSrcFile[0]))
  1126. {
  1127. strcpy(szDest, szSrcFile);
  1128. NormalizePath(szDest);
  1129. return;
  1130. }
  1131. *szDest++ = *szSrcFile++; *szDest++ = *szSrcFile++;
  1132. }
  1133. if (szSrcFile[0] == '/' || szSrcFile[0] == '\\')
  1134. {
  1135. strcpy(szDest, szSrcFile);
  1136. NormalizePath(szDest);
  1137. return;
  1138. }
  1139. strcpy(szDest, szSrcPath);
  1140. if (szDest[0] != '\0')
  1141. {
  1142. char ch = szDest[strlen(szDest)-1];
  1143. if (ch != ':' && ch != '/' && ch != '\\')
  1144. strcat(szDest, "/");
  1145. }
  1146. strcat(szDest, szSrcFile);
  1147. NormalizePath(szDest);
  1148. }
  1149. VOID
  1150. CopyPath(szDestPath, szSrcFullName)
  1151. /*
  1152. -- copy the path part of szSrcFullName into szDestPath
  1153. */
  1154. char * szDestPath;
  1155. char * szSrcFullName;
  1156. {
  1157. int ich;
  1158. int ichPathEnd; // index to end of path part of szSrcFullName
  1159. char ch;
  1160. /* Figure out where the path part of szSrcFullName ends and the
  1161. * name part begins.
  1162. */
  1163. for (ich = ichPathEnd = 0; (ch=szSrcFullName[ich]) != 0; ++ich)
  1164. if (ch == ':' || ch == '/' || ch == '\\')
  1165. ichPathEnd = ich+1;
  1166. /* Copy the path */
  1167. for (ich = 0; ich < ichPathEnd; ++ich)
  1168. szDestPath[ich] = szSrcFullName[ich];
  1169. szDestPath[ich] = 0;
  1170. }
  1171. VOID
  1172. PushDir(szPath, szName, fPathIsStd)
  1173. /*
  1174. -- push a directory name on the stack of directories for all nested
  1175. includes
  1176. */
  1177. char * szPath; // path name of file (e.g. "c:\foo\bar")
  1178. char * szName; // official name of file (e.g. "$(INCL)")
  1179. BOOL fPathIsStd; // path portion of szPath is from standard includes (-I)
  1180. {
  1181. DI * pdi;
  1182. if ((pdi = malloc(sizeof(DI))) == NULL)
  1183. Fatal("out of memory");
  1184. pdi->szPath = strdup(szPath);
  1185. pdi->szName = strdup(szName);
  1186. pdi->fPathIsStd = fPathIsStd;
  1187. /* Insert at head of list */
  1188. pdi->pdiNext = pdiHead;
  1189. pdiHead = pdi;
  1190. }
  1191. VOID
  1192. PopDir(void)
  1193. /*
  1194. -- pop a directory name from the stack of directories for all nested
  1195. includes
  1196. */
  1197. {
  1198. DI *pdiFree;
  1199. if (pdiHead == NULL)
  1200. Fatal("mkdep: internal error");
  1201. pdiFree = pdiHead;
  1202. pdiHead = pdiHead->pdiNext;
  1203. free(pdiFree->szPath);
  1204. free(pdiFree->szName);
  1205. free(pdiFree);
  1206. }
  1207. DI *
  1208. PdiFromIdi(idi)
  1209. /*
  1210. -- return a pointer to one element from the stack, or NULL
  1211. */
  1212. int idi; // index of element to get (0 = top of stack)
  1213. {
  1214. DI * pdi;
  1215. for (pdi = pdiHead; pdi && idi; idi--)
  1216. pdi = pdi->pdiNext;
  1217. return pdi;
  1218. }
  1219. int
  1220. AddIncludeDir(szFile)
  1221. char * szFile;
  1222. {
  1223. if (iszIncMac+1 >= iszIncMax)
  1224. {
  1225. fprintf(stderr,
  1226. "mkdep: warning"
  1227. ": too many include directories"
  1228. "; ignoring %s\n", szFile);
  1229. return 0;
  1230. }
  1231. else
  1232. {
  1233. /* normal include */
  1234. NormalizePath(szFile);
  1235. rgszIncPath[iszIncMac] = SzTransEnv(szFile);
  1236. rgszIncName[iszIncMac] = szFile;
  1237. // fprintf(stderr,"Added include: %s\n",szFile);
  1238. iszIncMac++;
  1239. return 1;
  1240. }
  1241. }