source: trunk/tools/fastdep/fastdep.c@ 3132

Last change on this file since 3132 was 3132, checked in by bird, 25 years ago

More performance improovements:

  • Cache entire directories. When the number of scanned files are > 25 in one file specification.
  • Lowercases all names added to the trees and uses case sentivie key searches.
  • Added a tree of cached directories so that these are not searched with the slow DosQueryPathInfo too.
File size: 69.7 KB
Line 
1/* $Id: fastdep.c,v 1.10 2000-03-16 23:51:26 bird Exp $
2 *
3 * Fast dependents. (Fast = Quick and Dirty!)
4 *
5 * Copyright (c) 1999-2000 knut st. osmundsen
6 *
7 * Project Odin Software License can be found in LICENSE.TXT
8 *
9 */
10
11/*******************************************************************************
12* Defined Constants And Macros *
13*******************************************************************************/
14#define INCL_DOSERRORS
15#define INCL_FILEMGR
16
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#include <os2.h>
22#include <stdio.h>
23#include <string.h>
24#include <stdlib.h>
25
26#include "avl.h"
27
28#ifndef INLINE
29# if defined(__IBMC__)
30# define INLINE _Inline
31# elif defined(__IBMCPP__)
32# define INLINE inline
33# else
34# error "unknown compiler - inline keyword unknown!"
35# endif
36#endif
37
38/*
39 * This following section is used while testing fastdep.
40 * stdio.h should be included; string.h never included.
41 */
42/*
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46*/
47
48#if 1
49#include <stdio.h>
50#else
51#include <string.h>
52#include <string.h>
53#endif
54
55/*
56 */ /* */ /*
57#include <string.h>
58 */
59#if 1
60# if 1
61 #if 0
62# include <string.h>
63 #else
64# if 1
65 #if 1
66 #if 0
67# include <string.h>
68 #else /* */ /*
69*/
70 # include <stdio.h>
71 #endif
72 #endif
73 #endif
74 #endif
75 #endif
76#endif
77
78/*******************************************************************************
79* Structures and Typedefs *
80*******************************************************************************/
81typedef struct _Options
82{
83 const char * pszInclude;
84 const char * pszExclude;
85 BOOL fExcludeAll;
86 const char * pszObjectExt;
87 const char * pszObjectDir;
88 BOOL fObjectDir; /* replace object directory? */
89 const char * pszRsrcExt;
90 BOOL fObjRule;
91 BOOL fNoObjectPath;
92 BOOL fSrcWhenObj;
93 BOOL fAppend; /* append to the output file, not overwrite it. */
94} OPTIONS, *POPTIONS;
95
96
97/*
98 * Language specific analysis functions type.
99 */
100typedef int ( _FNLANG) (const char *pszFilename, void *pvFile,
101 BOOL fHeader, POPTIONS pOptions);
102typedef _FNLANG *PFNLANG;
103
104
105/**
106 * This struct holds the static configuration of the util.
107 */
108typedef struct _ConfigEntry
109{
110 const char **papszExts; /* Pointer to an array of pointer to extentions for this handler. */
111 /* If NULL this is the last entry. */
112 int iFirstHdr; /* Index into the papszExts array of the first headerfile/copybook. */
113 /* Set it to the NULL element of the array if no headers for this extention. */
114 /* A non-header file may get a object rule. */
115 PFNLANG pfn; /* Pointer to handler function. */
116} CONFIGENTRY, *PCONFIGENTRY;
117
118
119/**
120 * Dependant Rule
121 */
122typedef struct _DepRule
123{
124 char * pszRule; /* Pointer to rule name */
125 int cDeps; /* Entries in the dependant array. */
126 char ** papszDep; /* Pointer to an array of pointers to dependants. */
127 struct _DepRule *pNext; /* Pointer to the next rule */
128} DEPRULE, *PDEPRULE;
129
130
131/**
132 * Filename cache entry.
133 */
134#define FCACHEENTRY AVLNODECORE
135#define PFCACHEENTRY PAVLNODECORE
136
137
138/*******************************************************************************
139* Internal Functions *
140*******************************************************************************/
141static void syntax(void);
142static int makeDependent(const char *pszFilename, POPTIONS pOptions);
143
144int langC_CPP(const char *pszFilename, void *pvFile, BOOL fHeader, POPTIONS pOptions);
145int langAsm(const char *pszFilename, void *pvFile, BOOL fHeader, POPTIONS pOptions);
146int langRC(const char *pszFilename, void *pvFile, BOOL fHeader, POPTIONS pOptions);
147int langCOBOL(const char *pszFilename, void *pvFile, BOOL fHeader, POPTIONS pOptions);
148
149
150/* string operations */
151static int strnicmpwords(const char *pszS1, const char *pszS2, int cch);
152
153/* file operations */
154static char *fileNormalize(char *pszFilename);
155 char *filePath(const char *pszFilename, char *pszBuffer);
156static char *filePathSlash(const char *pszFilename, char *pszBuffer);
157static char *filePathSlash2(const char *pszFilename, char *pszBuffer);
158static char *fileName(const char *pszFilename, char *pszBuffer);
159static char *fileNameNoExt(const char *pszFilename, char *pszBuffer);
160static char *fileExt(const char *pszFilename, char *pszBuffer);
161
162/* filecache operations */
163static BOOL filecacheAddFile(const char *pszFilename);
164static BOOL filecacheAddDir(const char *pszDir);
165static BOOL filecacheFind(const char *pszFilename);
166static BOOL filecacheIsDirCached(const char *pszDir);
167
168/* pathlist operations */
169static char *pathlistFindFile(const char *pszPathList, const char *pszFilename, char *pszBuffer);
170
171/* word operations */
172static char *findEndOfWord(char *psz);
173#if 0 /* not used */
174static char *findStartOfWord(char *psz, const char *pszStart);
175#endif
176
177/* file helpers */
178static signed long fsize(FILE *phFile);
179
180/* text helpers */
181INLINE char *trim(char *psz);
182INLINE char *trimR(char *psz);
183
184/* textbuffer */
185static void *textbufferCreate(const char *pszFilename);
186static void textbufferDestroy(void *pvBuffer);
187static char *textbufferNextLine(void *pvBuffer, char *psz);
188static char *textbufferGetNextLine(void *pvBuffer, void **ppv, char *pszLineBuffer, int cchLineBuffer);
189
190/* depend workers */
191static BOOL depReadFile(const char *pszFilename);
192static BOOL depWriteFile(const char *pszFilename);
193static void depRemoveAll(void);
194static void *depAddRule(const char *pszRulePath, const char *pszName, const char *pszExt);
195static BOOL depAddDepend(void *pvRule, const char *pszDep);
196#if 0 /* not used */
197static BOOL depCleanFile(const char *pszFilename);
198#endif
199
200
201/*******************************************************************************
202* Global Variables *
203*******************************************************************************/
204/*
205 * Pointer to the list of dependencies.
206 */
207static PDEPRULE pdepList = NULL;
208static BOOL fCacheSearchDirs = FALSE;
209
210
211/*
212 * Filecache - tree starts here.
213 */
214static PFCACHEENTRY pfcTree = NULL;
215static unsigned cfcNodes = 0;
216static PFCACHEENTRY pfcDirTree = NULL;
217
218
219/*
220 * Configuration stuff.
221 */
222static const char pszDefaultDepFile[] = ".depend";
223static const char *apszExtC_CPP[] = {"c", "sqc", "cpp", "h", "hpp", NULL};
224static const char *apszExtAsm[] = {"asm", "inc", NULL};
225static const char *apszExtRC[] = {"rc", "dlg", NULL};
226static const char *apszExtCOBOL[] = {"cbl", "cob", "sqb", NULL};
227static CONFIGENTRY aConfig[] =
228{
229 {
230 apszExtC_CPP,
231 3,
232 langC_CPP,
233 },
234
235 {
236 apszExtAsm,
237 1,
238 langAsm,
239 },
240
241 {
242 apszExtRC,
243 1,
244 langRC,
245 },
246
247 {
248 apszExtCOBOL,
249 3,
250 langCOBOL,
251 },
252
253 /* terminating entry */
254 {
255 NULL,
256 -1,
257 NULL
258 }
259};
260
261
262/**
263 * Main function.
264 * @returns 0 on success.
265 * -n count of failiures.
266 * @param
267 * @param
268 * @equiv
269 * @precond
270 * @methdesc
271 * @result
272 * @time
273 * @sketch
274 * @algo
275 * @remark
276 */
277int main(int argc, char **argv)
278{
279 int rc = 0;
280 int argi = 1;
281 const char *pszDepFile = pszDefaultDepFile;
282
283 static char szObjectDir[CCHMAXPATH];
284 static char szObjectExt[64] = "obj";
285 static char szRsrcExt[64] = "res";
286 static char szInclude[32768] = ";";
287 static char szExclude[32768] = ";";
288
289 OPTIONS options =
290 {
291 szInclude, /* pszInclude */
292 szExclude, /* pszExclude */
293 FALSE, /* fExcludeAll */
294 szObjectExt, /* pszObjectExt */
295 szObjectDir, /* pszObjectDir */
296 FALSE, /* fObjectDir */
297 szRsrcExt, /* pszRsrcExt */
298 TRUE, /* fObjRule */
299 FALSE, /* fNoObjectPath */
300 TRUE, /* fSrcWhenObj */
301 FALSE /* fAppend */
302 };
303
304 szObjectDir[0] = '\0';
305
306 if (argc == 1)
307 {
308 syntax();
309 return -87;
310 }
311
312 while (argi < argc)
313 {
314 if (argv[argi][0] == '-' || argv[argi][0] == '/')
315 {
316 /* parameters */
317 switch (argv[argi][1])
318 {
319 case 'A':
320 case 'a': /* Append to the output file */
321 options.fAppend = argv[argi][2] != '-';
322 break;
323
324 case 'D':
325 case 'd': /* "-d <filename>" */
326 {
327 const char *pszOld = pszDepFile;
328 if (argv[argi][2] != '\0')
329 pszDepFile = &argv[argi][2];
330 else
331 {
332 if (argi + 1 < argc)
333 pszDepFile = argv[++argi];
334 else
335 {
336 fprintf(stderr, "invalid parameter -d, filename missing!\n");
337 return -1;
338 }
339 }
340
341 /* if dependencies are generated we'll flush them to the old filename */
342 if (pdepList != NULL && pszOld != pszDepFile)
343 {
344 if (!depWriteFile(pszOld))
345 fprintf(stderr, "error: failed to write (flush) dependencies.\n");
346 depRemoveAll();
347 }
348 break;
349 }
350
351 case 'E': /* list of paths. If a file is found in one of these directories the */
352 case 'e': /* filename will be used without the directory path. */
353 /* Eall<[+]|-> ? */
354 if (strlen(&argv[argi][1]) <= 5 && strnicmp(&argv[argi][1], "Eall", 4) == 0)
355 {
356 options.fExcludeAll = argv[argi][5] != '-';
357 break;
358 }
359 /* path or path list */
360 if (strlen(argv[argi]) > 2)
361 strcat(szExclude, &argv[argi][2]);
362 else
363 {
364 strcat(szExclude, argv[argi+1]);
365 argi++;
366 }
367 if (szExclude[strlen(szExclude)-1] != ';')
368 strcat(szExclude, ";");
369 break;
370
371 case 'I': /* optional include path. This has precedence over the INCLUDE environment variable. */
372 case 'i':
373 if (strlen(argv[argi]) > 2)
374 strcat(szInclude, &argv[argi][2]);
375 else
376 {
377 strcat(szInclude, argv[argi+1]);
378 argi++;
379 }
380 if (szInclude[strlen(szInclude)-1] != ';')
381 strcat(szInclude, ";");
382 break;
383
384 case 'n': /* no object path , -N<[+]|-> */
385 case 'N':
386 if (strlen(argv[argi]) <= 1+1+1)
387 options.fNoObjectPath = argv[argi][2] != '-';
388 else
389 {
390 fprintf(stderr, "error: invalid parameter!, '%s'\n", argv[argi]);
391 return -1;
392 }
393 break;
394
395 case 'o': /* object base directory, Obj or Obr<[+]|-> */
396 case 'O':
397 if (strlen(&argv[argi][1]) <= 4 && strnicmp(&argv[argi][1], "Obr", 3) == 0)
398 {
399 options.fObjRule = argv[argi][4] != '-';
400 break;
401 }
402
403 if (strlen(&argv[argi][1]) >= 4 && strnicmp(&argv[argi][1], "Obj", 3) == 0)
404 {
405 if (strlen(argv[argi]) > 4)
406 strcpy(szObjectExt, argv[argi]+4);
407 else
408 {
409 strcpy(szObjectExt, argv[argi+1]);
410 argi++;
411 }
412 break;
413 }
414
415 /* path: -o or -o- */
416 options.fObjectDir = TRUE;
417 if (strlen(argv[argi]) > 2)
418 {
419 if (argv[argi][2] == '-') /* no object path */
420 szObjectDir[0] = '\0';
421 else
422 strcpy(szObjectDir, argv[argi]+2);
423 }
424 else
425 {
426 strcpy(szObjectDir, argv[argi+1]);
427 argi++;
428 }
429 if (szObjectDir[0] != '\0'
430 && szObjectDir[strlen(szObjectDir)-1] != '\\'
431 && szObjectDir[strlen(szObjectDir)-1] != '/'
432 )
433 strcat(szObjectDir, "\\");
434 break;
435
436 case 'r':
437 case 'R':
438 if (strlen(argv[argi]) > 2)
439 strcpy(szObjectExt, argv[argi]+2);
440 else
441 {
442 strcpy(szObjectExt, argv[argi+1]);
443 argi++;
444 }
445 break;
446
447 case 'h':
448 case 'H':
449 case '?':
450 syntax();
451 return 1;
452
453 default:
454 fprintf(stderr, "error: invalid parameter! '%s'\n", argv[argi]);
455 return -1;
456 }
457
458 }
459 else
460 { /* not a parameter! */
461 ULONG ulRc;
462 char achBuffer[4096];
463 PFILEFINDBUF3 pfindbuf3 = (PFILEFINDBUF3)(void*)&achBuffer[0];
464 HDIR hDir = HDIR_CREATE;
465 ULONG cFiles = ~0UL;
466 int i;
467
468 /*
469 * If append option is specified we'll have to read the existing dep file
470 * before starting adding new dependencies.
471 */
472 if (pdepList == NULL && options.fAppend)
473 depReadFile(pszDepFile);
474
475 /*
476 * Search for the files specified.
477 */
478 ulRc = DosFindFirst(argv[argi], &hDir,
479 FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_ARCHIVED,
480 pfindbuf3, sizeof(achBuffer), &cFiles, FIL_STANDARD);
481 if (!fCacheSearchDirs)
482 fCacheSearchDirs = cFiles > 25;
483 while (ulRc == NO_ERROR)
484 {
485 for (i = 0;
486 i < cFiles;
487 i++, pfindbuf3 = (PFILEFINDBUF3)((int)pfindbuf3 + pfindbuf3->oNextEntryOffset)
488 )
489 {
490 char *psz;
491 char szSource[CCHMAXPATH];
492
493 /*
494 * Make full path.
495 */
496 if ((psz = strrchr(argv[argi], '\\')) || (psz = strrchr(argv[argi], '/')))
497 {
498 strncpy(szSource, argv[argi], psz - argv[argi] + 1);
499 szSource[psz - argv[argi] + 1] = '\0';
500 }
501 else
502 szSource[0] = '\0';
503 strcat(szSource, pfindbuf3->achName);
504
505 /*
506 * Analyse the file.
507 */
508 rc -= makeDependent(&szSource[0], &options);
509 }
510
511 /* next file */
512 cFiles = ~0UL;
513 pfindbuf3 = (PFILEFINDBUF3)(void*)&achBuffer[0];
514 ulRc = DosFindNext(hDir, pfindbuf3, sizeof(achBuffer), &cFiles);
515 }
516 DosFindClose(hDir);
517 }
518 /* next */
519 argi++;
520 }
521
522 /* Write the depend file! */
523 if (!depWriteFile(pszDepFile))
524 fprintf(stderr, "error: failed to write dependencies file!\n");
525 #if 0
526 printf("cfcNodes=%d\n", cfcNodes);
527 #endif
528
529 return rc;
530}
531
532
533/**
534 * Displays the syntax description for this util.
535 * @status completely implemented.
536 * @author knut st. osmundsen
537 */
538static void syntax(void)
539{
540 printf(
541 "FastDep v0.1\n"
542 "Quick and dirty dependant scanner. Creates a makefile readable depend file.\n"
543 "\n"
544 "Syntax: FastDep [-a<[+]|->] [-d <outputfn>] [-e <excludepath>] [-eall<[+]|->]\n"
545 " [-i <include>] [-n<[+]|->] [-o <objdir>] [-obr<[+]|->] <files>\n"
546 "\n"
547 " -a<[+]|-> Append to the output file. Default: Overwrite.\n"
548 " -d <outputfn> Output filename. Default: %s\n"
549 " -e excludepath Exclude paths. If a filename is found in any\n"
550 " of these paths only the filename is used, not\n"
551 " the path+filename (which is default) (don't work?).\n"
552 " -eall<[+]|-> Include and source filenames, paths or no paths.\n"
553 " -eall+: No path are added to the filename.\n"
554 " -eall-: The filename is appended the include path\n"
555 " was found in.\n"
556 " Default: eall-\n"
557 " -i <include> Additional include paths. INCLUDE is searched after this.\n"
558 " -n<[+]|-> No path for object files in the rules.\n"
559 " -o <objdir> Path were object files are placed. This path replaces the\n"
560 " entire filename path\n"
561 " -o- No object path\n"
562 " -obr<[+]|-> -obr+: Object rule.\n"
563 " -obr-: No object rule, rule for source filename is generated.\n"
564 " -obj[ ]<objext> Object extention. Default: obj\n"
565 " -r[ ]<rsrcext> Resource binary extention. Default: res\n"
566 " <files> Files to scan. Wildchars are allowed.\n"
567 "\n",
568 pszDefaultDepFile
569 );
570}
571
572
573/**
574 * Generates depend info on this file, these are stored internally
575 * and written to file later.
576 * @returns
577 * @param pszFilename Pointer to source filename.
578 * @param pOptions Pointer to options struct.
579 * @status completely implemented.
580 * @author knut st. osmundsen
581 */
582static int makeDependent(const char *pszFilename, POPTIONS pOptions)
583{
584 int rc = -1;
585 void * pvFile;
586
587 pvFile = textbufferCreate(pszFilename);
588 if (pvFile != NULL)
589 {
590 char szExt[CCHMAXPATH];
591 PCONFIGENTRY pCfg = &aConfig[0];
592 BOOL fHeader;
593
594 /*
595 * Find which filetype this is...
596 */
597 fileExt(pszFilename, szExt);
598 while (pCfg->papszExts != NULL)
599 {
600 const char **ppsz = pCfg->papszExts;
601 while (*ppsz != NULL && stricmp(*ppsz, szExt) != 0)
602 ppsz++;
603 if (*ppsz != NULL)
604 {
605 fHeader = &pCfg->papszExts[pCfg->iFirstHdr] <= ppsz;
606 break;
607 }
608 pCfg++;
609 }
610
611 /* Found? */
612 if (pCfg->papszExts != NULL)
613 rc = (*pCfg->pfn)(pszFilename, pvFile, fHeader, pOptions);
614 else
615 {
616 if (*fileName(pszFilename, szExt) != '.') /* these are 'hidden' files, like .cvsignore, let's ignore them. */
617 fprintf(stderr, "warning: '%s' has an unknown file type.\n", pszFilename);
618 rc = 0;
619 }
620
621 textbufferDestroy(pvFile);
622 }
623 else
624 fprintf(stderr, "failed to open '%s'\n", pszFilename);
625
626 return rc;
627}
628
629
630/**
631 * Generates depend info on this C or C++ file, these are stored internally
632 * and written to file later.
633 * @returns 0 on success.
634 * !0 on error.
635 * @param pszFilename Pointer to source filename.
636 * @param pvFile Pointer to file textbuffer.
637 * @param pOptions Pointer to options struct.
638 * @status completely implemented.
639 * @author knut st. osmundsen
640 */
641int langC_CPP(const char *pszFilename, void *pvFile, BOOL fHeader, POPTIONS pOptions)
642{
643 void * pvRule; /* Handle to the current rule. */
644 char szBuffer[4096]; /* Max line length is 4096... should not be a problem. */
645 int iLine; /* Linenumber. */
646 void * pv = NULL; /* An index used by textbufferGetNextLine. */
647 BOOL fComment; /* TRUE when within a multiline comment. */
648 /* FALSE when not within a multiline comment. */
649 int iIfStack; /* StackPointer. */
650 struct IfStackEntry
651 {
652 int fIncluded : 1; /* TRUE: include this code;
653 * FALSE: excluded */
654 int fIf : 1; /* TRUE: #if part of the expression.
655 * FALSE: #else part of the expression. */
656 int fSupported : 1; /* TRUE: supported if/else statement
657 * FALSE: unsupported all else[<something>] are ignored
658 * All code is included.
659 */
660 } achIfStack[256];
661
662
663 /**********************************/
664 /* Add the depend rule */
665 /**********************************/
666 if (pOptions->fObjRule && !fHeader)
667 {
668 if (pOptions->fNoObjectPath)
669 pvRule = depAddRule(fileNameNoExt(pszFilename, szBuffer), NULL, pOptions->pszObjectExt);
670 else
671 pvRule = depAddRule(pOptions->fObjectDir ?
672 pOptions->pszObjectDir :
673 filePathSlash(pszFilename, szBuffer),
674 fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH),
675 pOptions->pszObjectExt);
676
677 if (pOptions->fSrcWhenObj && pvRule)
678 depAddDepend(pvRule, pOptions->fExcludeAll ? fileName(pszFilename, szBuffer) : pszFilename);
679 }
680 else
681 pvRule = depAddRule(pszFilename, NULL, NULL);
682
683 /* duplicate rule? */
684 if (pvRule == NULL)
685 return 0;
686
687
688 /*******************/
689 /* find dependants */
690 /*******************/
691 /* Initiate the IF-stack, comment state and line number. */
692 iIfStack = 0;
693 achIfStack[iIfStack].fIf = TRUE;
694 achIfStack[iIfStack].fIncluded = TRUE;
695 achIfStack[iIfStack].fSupported = TRUE;
696 fComment = FALSE;
697 iLine = 0;
698 while (textbufferGetNextLine(pvFile, &pv, szBuffer, sizeof(szBuffer)) != NULL) /* line loop */
699 {
700 /* search for #include */
701 register char *pszC;
702 int cbLen;
703 int i = 0;
704 iLine++;
705
706 /* skip blank chars */
707 cbLen = strlen(szBuffer);
708 while (i + 2 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t'))
709 i++;
710
711 /* preprocessor statement? */
712 if (!fComment && szBuffer[i] == '#')
713 {
714 /*
715 * Preprocessor checks
716 * We known that we have a preprocessor statment (starting with an '#' * at szBuffer[i]).
717 * Depending on the word afterwards we'll take some different actions.
718 * So we'll start of by extracting that word and make a string swich on it.
719 * Note that there might be some blanks between the hash and the word.
720 */
721 int cchWord;
722 char * pszEndWord;
723 char * pszArgument;
724 i++; /* skip hash ('#') */
725 while (szBuffer[i] == '\t' || szBuffer[i] == ' ') /* skip blanks */
726 i++;
727 pszArgument = pszEndWord = findEndOfWord(&szBuffer[i]);
728 cchWord = pszEndWord - &szBuffer[i];
729
730 /*
731 * Find the argument by skipping the blanks.
732 */
733 while (*pszArgument == '\t' || *pszArgument == ' ') /* skip blanks */
734 pszArgument++;
735
736 /*
737 * string switch.
738 */
739 if (strncmp(&szBuffer[i], "include", cchWord) == 0)
740 {
741 /*
742 * #include
743 *
744 * Are we in a state where this file is to be included?
745 */
746 if (achIfStack[iIfStack].fIncluded)
747 {
748 char szFullname[CCHMAXPATH];
749 char *psz;
750 BOOL f = FALSE;
751 int j;
752
753 /* extract info between "" or <> */
754 while (i < cbLen && !(f = (szBuffer[i] == '"' || szBuffer[i] == '<')))
755 i++;
756 i++; /* skip '"' or '<' */
757
758 /* if invalid statement then continue with the next line! */
759 if (!f) continue;
760
761 /* find end */
762 j = f = 0;
763 while (i + j < cbLen && j < CCHMAXPATH &&
764 !(f = (szBuffer[i+j] == '"' || szBuffer[i+j] == '>')))
765 j++;
766
767 /* if invalid statement then continue with the next line! */
768 if (!f) continue;
769
770 /* copy filename */
771 strncpy(szFullname, &szBuffer[i], j);
772 szFullname[j] = '\0'; /* ensure terminatition. */
773
774 /* find include file! */
775 psz = pathlistFindFile(pOptions->pszInclude, szFullname, szBuffer);
776 if (psz == NULL)
777 psz = pathlistFindFile(getenv("INCLUDE"), szFullname, szBuffer);
778
779 /* did we find the include? */
780 if (psz != NULL)
781 {
782 char szBuffer2[CCHMAXPATH];
783 if (pOptions->fExcludeAll ||
784 pathlistFindFile(pOptions->pszExclude, szFullname, szBuffer2) != NULL
785 )
786 depAddDepend(pvRule, szFullname);
787 else
788 depAddDepend(pvRule, szBuffer);
789 }
790 else
791 fprintf(stderr, "%s(%d): warning include file '%s' not found!\n",
792 pszFilename, iLine, szFullname);
793 }
794 }
795 else
796 /*
797 * #if
798 */
799 if (strncmp(&szBuffer[i], "if", cchWord) == 0)
800 { /* #if 0 and #if <1-9> are supported */
801 pszEndWord = findEndOfWord(pszArgument);
802 iIfStack++;
803 if ((pszEndWord - pszArgument) == 1
804 && *pszArgument >= '0' && *pszArgument <= '9')
805 {
806 if (*pszArgument != '0')
807 achIfStack[iIfStack].fIncluded = TRUE;
808 else
809 achIfStack[iIfStack].fIncluded = FALSE;
810 }
811 else
812 achIfStack[iIfStack].fSupported = FALSE;
813 achIfStack[iIfStack].fIncluded = TRUE;
814 achIfStack[iIfStack].fIf = TRUE;
815 }
816 else
817 /*
818 * #else
819 */
820 if (strncmp(&szBuffer[i], "else", cchWord) == 0)
821 {
822 if (achIfStack[iIfStack].fSupported)
823 {
824 if (achIfStack[iIfStack].fIncluded) /* ARG!! this'll prevent warning */
825 achIfStack[iIfStack].fIncluded = FALSE;
826 else
827 achIfStack[iIfStack].fIncluded = TRUE;
828 }
829 achIfStack[iIfStack].fIf = FALSE;
830 }
831 else
832 /*
833 * #endif
834 */
835 if (strncmp(&szBuffer[i], "endif", cchWord) == 0)
836 { /* Pop the if-stack. */
837 if (iIfStack > 0)
838 iIfStack--;
839 else
840 fprintf(stderr, "%s(%d): If-Stack underflow!\n", pszFilename, iLine);
841 }
842 /*
843 * general if<something> and elseif<something> implementations
844 */
845 else
846 if (strncmp(&szBuffer[i], "elseif", 6) == 0)
847 {
848 achIfStack[iIfStack].fSupported = FALSE;
849 achIfStack[iIfStack].fIncluded = TRUE;
850 }
851 else
852 if (strncmp(&szBuffer[i], "if", 2) == 0)
853 {
854 iIfStack++;
855 achIfStack[iIfStack].fIf = TRUE;
856 achIfStack[iIfStack].fSupported = FALSE;
857 achIfStack[iIfStack].fIncluded = TRUE;
858 }
859 /* The rest of them aren't implemented yet.
860 else if (strncmp(&szBuffer[i], "if") == 0)
861 {
862 }
863 */
864 }
865
866 /*
867 * Comment checks.
868 * -Start at first non-blank.
869 * -Loop thru the line since we might have more than one
870 * comment statement on a single line.
871 */
872 pszC = &szBuffer[i];
873 while (pszC != NULL && *pszC != '\0')
874 {
875 if (fComment)
876 pszC = strstr(pszC, "*/"); /* look for end comment mark. */
877 else
878 {
879 char *pszLC;
880 pszLC= strstr(pszC, "//"); /* look for single line comment mark. */
881 pszC = strstr(pszC, "/*"); /* look for start comment mark */
882 if (pszLC && pszLC < pszC) /* if there is an single line comment mark before the */
883 break; /* muliline comment mark we'll ignore the multiline mark. */
884 }
885
886 /* Comment mark found? */
887 if (pszC != NULL)
888 {
889 fComment = !fComment;
890 pszC += 2; /* skip comment mark */
891
892 /* debug */
893 /*
894 if (fComment)
895 fprintf(stderr, "starts at line %d\n", iLine);
896 else
897 fprintf(stderr, "ends at line %d\n", iLine);
898 */
899 }
900 }
901 } /*while*/
902
903 return 0;
904}
905
906
907/**
908 * Generates depend info on this file, these are stored internally
909 * and written to file later.
910 * @returns 0 on success.
911 * !0 on error.
912 * @param pszFilename Pointer to source filename.
913 * @param pvFile Pointer to file textbuffer.
914 * @param pOptions Pointer to options struct.
915 * @status completely implemented.
916 * @author knut st. osmundsen
917 */
918int langAsm(const char *pszFilename, void *pvFile, BOOL fHeader, POPTIONS pOptions)
919{
920 void * pvRule; /* Handle to the current rule. */
921 char szBuffer[4096]; /* Temporary buffer (max line lenght size...) */
922 int iLine; /* current line number */
923 void * pv = NULL; /* An index used by textbufferGetNextLine. */
924
925
926 /**********************************/
927 /* Add the depend rule */
928 /**********************************/
929 if (pOptions->fObjRule && !fHeader)
930 {
931 if (pOptions->fNoObjectPath)
932 pvRule = depAddRule(fileNameNoExt(pszFilename, szBuffer), NULL, pOptions->pszObjectExt);
933 else
934 pvRule = depAddRule(pOptions->fObjectDir ?
935 pOptions->pszObjectDir :
936 filePathSlash(pszFilename, szBuffer),
937 fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH),
938 pOptions->pszObjectExt);
939
940 if (pOptions->fSrcWhenObj && pvRule)
941 depAddDepend(pvRule, pOptions->fExcludeAll ? fileName(pszFilename, szBuffer) : pszFilename);
942 }
943 else
944 pvRule = depAddRule(pszFilename, NULL, NULL);
945
946 /* duplicate rule? */
947 if (pvRule == NULL)
948 return 0;
949
950
951 /*******************/
952 /* find dependants */
953 /*******************/
954 iLine = 0;
955 while (textbufferGetNextLine(pvFile, &pv, szBuffer, sizeof(szBuffer)) != NULL) /* line loop */
956 {
957 /* search for include */
958 int cbLen;
959 int i = 0;
960 iLine++;
961
962 /* skip blank chars */
963 cbLen = strlen(szBuffer);
964 while (i + 9 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t'))
965 i++;
966
967 /* is this an include? */
968 if (strnicmp(&szBuffer[i], "include", 7) == 0
969 && (szBuffer[i + 7] == '\t' || szBuffer[i + 7] == ' ')
970 )
971 {
972 char szFullname[CCHMAXPATH];
973 char *psz;
974 int j;
975
976 /* skip to first no blank char */
977 i += 7;
978 while (i < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t'))
979 i++;
980
981 /* comment check - if comment found, no filename was given. continue. */
982 if (szBuffer[i] == ';') continue;
983
984 /* find end */
985 j = 0;
986 while (i + j < cbLen
987 && j < CCHMAXPATH
988 && szBuffer[i+j] != ' ' && szBuffer[i+j] != '\t' && szBuffer[i+j] != '\n'
989 && szBuffer[i+j] != '\0' && szBuffer[i+j] != ';' && szBuffer[i+j] != '\r'
990 )
991 j++;
992
993 /* copy filename */
994 strncpy(szFullname, &szBuffer[i], j);
995 szFullname[j] = '\0'; /* ensure terminatition. */
996
997 /* find include file! */
998 psz = pathlistFindFile(pOptions->pszInclude, szFullname, szBuffer);
999 if (psz == NULL)
1000 psz = pathlistFindFile(getenv("INCLUDE"), szFullname, szBuffer);
1001
1002 /* Did we find the include? */
1003 if (psz != NULL)
1004 {
1005 char szBuffer2[CCHMAXPATH];
1006 if (pOptions->fExcludeAll ||
1007 pathlistFindFile(pOptions->pszExclude, szFullname, szBuffer2) != NULL
1008 )
1009 depAddDepend(pvRule, szFullname);
1010 else
1011 depAddDepend(pvRule, szBuffer);
1012 }
1013 else
1014 fprintf(stderr, "%s(%d): warning include file '%s' not found!\n",
1015 pszFilename, iLine, szFullname);
1016 }
1017 } /*while*/
1018
1019 return 0;
1020}
1021
1022
1023/**
1024 * Generates depend info on this Resource file, these are stored internally
1025 * and written to file later.
1026 * @returns 0 on success.
1027 * !0 on error.
1028 * @param pszFilename Pointer to source filename.
1029 * @param pvFile Pointer to file textbuffer.
1030 * @param pOptions Pointer to options struct.
1031 * @status completely implemented.
1032 * @author knut st. osmundsen
1033 */
1034int langRC(const char *pszFilename, void *pvFile, BOOL fHeader, POPTIONS pOptions)
1035{
1036 void * pvRule; /* Handle to the current rule. */
1037 char szBuffer[4096]; /* Temporary buffer (max line lenght size...) */
1038 int iLine; /* current line number */
1039 void * pv = NULL; /* An index used by textbufferGetNextLine. */
1040
1041
1042 /**********************************/
1043 /* Add the depend rule */
1044 /**********************************/
1045 if (pOptions->fObjRule && !fHeader)
1046 {
1047 if (pOptions->fNoObjectPath)
1048 pvRule = depAddRule(fileNameNoExt(pszFilename, szBuffer), NULL, pOptions->pszRsrcExt);
1049 else
1050 pvRule = depAddRule(pOptions->fObjectDir ?
1051 pOptions->pszObjectDir :
1052 filePathSlash(pszFilename, szBuffer),
1053 fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH),
1054 pOptions->pszRsrcExt);
1055
1056 if (pOptions->fSrcWhenObj && pvRule)
1057 depAddDepend(pvRule, pOptions->fExcludeAll ? fileName(pszFilename, szBuffer) : pszFilename);
1058 }
1059 else
1060 pvRule = depAddRule(pszFilename, NULL, NULL);
1061
1062 /* duplicate rule? */
1063 if (pvRule == NULL)
1064 return 0;
1065
1066
1067 /*******************/
1068 /* find dependants */
1069 /*******************/
1070 iLine = 0;
1071 while (textbufferGetNextLine(pvFile, &pv, szBuffer, sizeof(szBuffer)) != NULL) /* line loop */
1072 {
1073 /* search for #include */
1074 int cbLen;
1075 int i = 0;
1076 iLine++;
1077
1078 /* skip blank chars */
1079 cbLen = strlen(szBuffer);
1080 while (i + 9 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t'))
1081 i++;
1082
1083 /* is this an include? */
1084 if ( strncmp(&szBuffer[i], "#include", 8) == 0
1085 || strncmp(&szBuffer[i], "RCINCLUDE", 9) == 0
1086 || strncmp(&szBuffer[i], "DLGINCLUDE", 10) == 0
1087 )
1088 {
1089 char szFullname[CCHMAXPATH];
1090 char *psz;
1091 BOOL f = FALSE;
1092 int j;
1093
1094 /* extract info between "" or <> */
1095 while (i < cbLen && !(f = (szBuffer[i] == '"' || szBuffer[i] == '<')))
1096 i++;
1097 i++; /* skip '"' or '<' */
1098
1099 /* if invalid statement then continue with the next line! */
1100 if (!f) continue;
1101
1102 /* find end */
1103 j = f = 0;
1104 while (i + j < cbLen && j < CCHMAXPATH &&
1105 !(f = (szBuffer[i+j] == '"' || szBuffer[i+j] == '>')))
1106 j++;
1107
1108 /* if invalid statement then continue with the next line! */
1109 if (!f) continue;
1110
1111 /* copy filename */
1112 strncpy(szFullname, &szBuffer[i], j);
1113 szFullname[j] = '\0'; /* ensure terminatition. */
1114
1115 /* find include file! */
1116 psz = pathlistFindFile(pOptions->pszInclude, szFullname, szBuffer);
1117 if (psz == NULL)
1118 psz = pathlistFindFile(getenv("INCLUDE"), szFullname, szBuffer);
1119
1120 /* did we find the include? */
1121 if (psz != NULL)
1122 {
1123 char szBuffer2[CCHMAXPATH];
1124 if (pOptions->fExcludeAll ||
1125 pathlistFindFile(pOptions->pszExclude, szFullname, szBuffer2) != NULL
1126 )
1127 depAddDepend(pvRule, szFullname);
1128 else
1129 depAddDepend(pvRule, szBuffer);
1130 }
1131 else
1132 fprintf(stderr, "%s(%d): warning include file '%s' not found!\n",
1133 pszFilename, iLine, szFullname);
1134 }
1135 } /*while*/
1136
1137 return 0;
1138}
1139
1140
1141/**
1142 * Generates depend info on this COBOL file, these are stored internally
1143 * and written to file later.
1144 * @returns 0 on success.
1145 * !0 on error.
1146 * @param pszFilename Pointer to source filename.
1147 * @param pvFile Pointer to file textbuffer.
1148 * @param pOptions Pointer to options struct.
1149 * @status completely implemented.
1150 * @author knut st. osmundsen
1151 */
1152int langCOBOL(const char *pszFilename, void *pvFile, BOOL fHeader, POPTIONS pOptions)
1153{
1154 void * pvRule; /* Handle to the current rule. */
1155 char szBuffer[4096]; /* Temporary buffer (max line lenght size...) */
1156 int iLine; /* current line number */
1157 void * pv = NULL; /* An index used by textbufferGetNextLine. */
1158
1159
1160 /**********************************/
1161 /* Add the depend rule */
1162 /**********************************/
1163 if (pOptions->fObjRule && !fHeader)
1164 {
1165 if (pOptions->fNoObjectPath)
1166 pvRule = depAddRule(fileNameNoExt(pszFilename, szBuffer), NULL, pOptions->pszObjectExt);
1167 else
1168 pvRule = depAddRule(pOptions->fObjectDir ?
1169 pOptions->pszObjectDir :
1170 filePathSlash(pszFilename, szBuffer),
1171 fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH),
1172 pOptions->pszObjectExt);
1173
1174 if (pOptions->fSrcWhenObj && pvRule)
1175 depAddDepend(pvRule, pOptions->fExcludeAll ? fileName(pszFilename, szBuffer) : pszFilename);
1176 }
1177 else
1178 pvRule = depAddRule(pszFilename, NULL, NULL);
1179
1180 /* duplicate rule? */
1181 if (pvRule == NULL)
1182 return 0;
1183
1184
1185 /*******************/
1186 /* find dependants */
1187 /*******************/
1188 iLine = 0;
1189 while (textbufferGetNextLine(pvFile, &pv, szBuffer, sizeof(szBuffer)) != NULL) /* line loop */
1190 {
1191 /* search for #include */
1192 int cbLen;
1193 int i = 0;
1194 int i1, i2;
1195 iLine++;
1196
1197 /* check for comment mark (column 7) */
1198 if (szBuffer[6] == '*')
1199 continue;
1200
1201 /* skip blank chars */
1202 cbLen = strlen(szBuffer);
1203 while (i + 9 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t'))
1204 i++;
1205
1206 /* is this an include? */
1207 if ( (i1 = strnicmp(&szBuffer[i], "COPY", 4)) == 0
1208 || (i2 = strnicmpwords(&szBuffer[i], "EXEC SQL INCLUDE", 16)) == 0
1209 )
1210 {
1211 char szFullname[CCHMAXPATH];
1212 char *psz;
1213 int j;
1214
1215 /* skip statement */
1216 i += 4;
1217 if (i1 != 0)
1218 {
1219 int y = 2; /* skip two words */
1220 do
1221 {
1222 /* skip blanks */
1223 while (szBuffer[i] == ' ' || szBuffer[i] == '\t')
1224 i++;
1225 /* skip word */
1226 while (szBuffer[i] != ' ' && szBuffer[i] != '\t'
1227 && szBuffer[i] != '\0' && szBuffer[i] != '\n')
1228 i++;
1229 y--;
1230 } while (y > 0);
1231 }
1232
1233 /* check for blank */
1234 if (szBuffer[i] != ' ' && szBuffer[i] != '\t') /* no copybook specified... */
1235 continue;
1236
1237 /* skip blanks */
1238 while (szBuffer[i] == ' ' || szBuffer[i] == '\t')
1239 i++;
1240
1241 /* if invalid statement then continue with the next line! */
1242 if (szBuffer[i] == '\0' || szBuffer[i] == '\n')
1243 continue;
1244
1245 /* find end */
1246 j = 0;
1247 while (i + j < cbLen && j < CCHMAXPATH
1248 && szBuffer[i+j] != '.'
1249 && szBuffer[i+j] != ' ' && szBuffer[i+j] != '\t'
1250 && szBuffer[i+j] != '\0' && szBuffer[i+j] != '\n'
1251 )
1252 j++;
1253
1254 /* if invalid statement then continue with the next line! */
1255 if (szBuffer[i+j] != '.' && szBuffer[i+j] != ' ' && szBuffer[i] != '\t')
1256 continue;
1257
1258 /* copy filename */
1259 strncpy(szFullname, &szBuffer[i], j);
1260 szFullname[j] = '\0'; /* ensure terminatition. */
1261
1262 /* add extention .cpy - hardcoded for the moment. */
1263 strcat(szFullname, ".cpy");
1264
1265 /* find include file! */
1266 psz = pathlistFindFile(pOptions->pszInclude, szFullname, szBuffer);
1267
1268 /* did we find the include? */
1269 if (psz != NULL)
1270 {
1271 char szBuffer2[CCHMAXPATH];
1272 if (pOptions->fExcludeAll ||
1273 pathlistFindFile(pOptions->pszExclude, szFullname, szBuffer2) != NULL
1274 )
1275 depAddDepend(pvRule, szFullname);
1276 else
1277 depAddDepend(pvRule, szBuffer);
1278 }
1279 else
1280 fprintf(stderr, "%s(%d): warning include file '%s' not found!\n",
1281 pszFilename, iLine, szFullname);
1282 }
1283 } /*while*/
1284
1285 return 0;
1286}
1287
1288#define upcase(ch) \
1289 (ch >= 'a' && ch <= 'z' ? ch - ('a' - 'A') : ch)
1290
1291/**
1292 * Compares words. Multiple spaces are treates as on single blank i both string when comparing them.
1293 * @returns 0 equal. (same as strnicmp)
1294 * @param pszS1 String 1
1295 * @param pszS2 String 2
1296 * @param cch Length to compare (relative to string 1)
1297 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
1298 */
1299static int strnicmpwords(const char *pszS1, const char *pszS2, int cch)
1300{
1301 do
1302 {
1303 while (cch > 0 && upcase(*pszS1) == upcase(*pszS2) && *pszS1 != ' ')
1304 pszS1++, pszS2++, cch--;
1305
1306 /* blank test and skipping */
1307 if (cch > 0 && *pszS1 == ' ' && *pszS2 == ' ')
1308 {
1309 while (cch > 0 && *pszS1 == ' ')
1310 pszS1++, cch--;
1311
1312 while (*pszS2 == ' ')
1313 pszS2++;
1314 }
1315 else
1316 break;
1317 } while (cch > 0);
1318
1319 return cch == 0 ? 0 : *pszS1 - *pszS2;
1320}
1321
1322
1323/**
1324 * Normalizes the path slashes for the filename.
1325 * @returns pszFilename
1326 * @param pszFilename Pointer to filename string.
1327 */
1328char *fileNormalize(char *pszFilename)
1329{
1330 char *psz = pszFilename;
1331
1332 while ((pszFilename = strchr(pszFilename, '//')) != NULL)
1333 *pszFilename++ = '\\';
1334
1335 return psz;
1336}
1337
1338/**
1339 * Copies the path part (excluding the slash) into pszBuffer and returns
1340 * a pointer to the buffer.
1341 * If no path is found "" is returned.
1342 * @returns Pointer to pszBuffer with path.
1343 * @param pszFilename Pointer to readonly filename.
1344 * @param pszBuffer Pointer to output Buffer.
1345 * @status completely implemented.
1346 * @author knut st. osmundsen
1347 */
1348char *filePath(const char *pszFilename, char *pszBuffer)
1349{
1350 char *psz = strrchr(pszFilename, '\\');
1351 if (psz == NULL)
1352 psz = strrchr(pszFilename, '/');
1353
1354 if (psz == NULL)
1355 *pszBuffer = '\0';
1356 else
1357 {
1358 strncpy(pszBuffer, pszFilename, psz - pszFilename - 1);
1359 pszBuffer[psz - pszFilename - 1] = '\0';
1360 }
1361
1362 return pszBuffer;
1363}
1364
1365
1366/**
1367 * Copies the path part including the slash into pszBuffer and returns
1368 * a pointer to the buffer.
1369 * If no path is found "" is returned.
1370 * @returns Pointer to pszBuffer with path.
1371 * @param pszFilename Pointer to readonly filename.
1372 * @param pszBuffer Pointer to output Buffer.
1373 * @status completely implemented.
1374 * @author knut st. osmundsen
1375 */
1376static char *filePathSlash(const char *pszFilename, char *pszBuffer)
1377{
1378 char *psz = strrchr(pszFilename, '\\');
1379 if (psz == NULL)
1380 psz = strrchr(pszFilename, '/');
1381
1382 if (psz == NULL)
1383 *pszBuffer = '\0';
1384 else
1385 {
1386 strncpy(pszBuffer, pszFilename, psz - pszFilename + 1);
1387 pszBuffer[psz - pszFilename + 1] = '\0';
1388 }
1389
1390 return pszBuffer;
1391}
1392
1393
1394/**
1395 * Copies the path part including the slash into pszBuffer and returns
1396 * a pointer to the buffer. If no path is found "" is returned.
1397 * The path is normalized to only use '\\'.
1398 * @returns Pointer to pszBuffer with path.
1399 * @param pszFilename Pointer to readonly filename.
1400 * @param pszBuffer Pointer to output Buffer.
1401 * @status completely implemented.
1402 * @author knut st. osmundsen
1403 */
1404static char *filePathSlash2(const char *pszFilename, char *pszBuffer)
1405{
1406 char *psz = strrchr(pszFilename, '\\');
1407 if (psz == NULL)
1408 psz = strrchr(pszFilename, '/');
1409
1410 if (psz == NULL)
1411 *pszBuffer = '\0';
1412 else
1413 {
1414 strncpy(pszBuffer, pszFilename, psz - pszFilename + 1);
1415 pszBuffer[psz - pszFilename + 1] = '\0';
1416
1417 /* normalize all '/' to '\\' */
1418 psz = pszBuffer;
1419 while ((psz = strchr(psz, '/')) != NULL)
1420 *psz++ = '\\';
1421 }
1422
1423 return pszBuffer;
1424}
1425
1426
1427/**
1428 * Copies the filename (with extention) into pszBuffer and returns
1429 * a pointer to the buffer.
1430 * @returns Pointer to pszBuffer with path.
1431 * @param pszFilename Pointer to readonly filename.
1432 * @param pszBuffer Pointer to output Buffer.
1433 * @status completely implemented.
1434 * @author knut st. osmundsen
1435 */
1436char *fileName(const char *pszFilename, char *pszBuffer)
1437{
1438 char *psz = strrchr(pszFilename, '\\');
1439 if (psz == NULL)
1440 psz = strrchr(pszFilename, '/');
1441
1442 strcpy(pszBuffer, psz == NULL ? pszFilename : psz + 1);
1443
1444 return pszBuffer;
1445}
1446
1447
1448/**
1449 * Copies the name part with out extention into pszBuffer and returns
1450 * a pointer to the buffer.
1451 * If no name is found "" is returned.
1452 * @returns Pointer to pszBuffer with path.
1453 * @param pszFilename Pointer to readonly filename.
1454 * @param pszBuffer Pointer to output Buffer.
1455 * @status completely implemented.
1456 * @author knut st. osmundsen
1457 */
1458char *fileNameNoExt(const char *pszFilename, char *pszBuffer)
1459{
1460 char *psz = strrchr(pszFilename, '\\');
1461 if (psz == NULL)
1462 psz = strrchr(pszFilename, '/');
1463
1464 strcpy(pszBuffer, psz == NULL ? pszFilename : psz + 1);
1465
1466 psz = strrchr(pszBuffer, '.');
1467 if (psz > pszBuffer) /* an extetion on it's own (.depend) is a filename not an extetion! */
1468 *psz = '\0';
1469
1470 return pszBuffer;
1471}
1472
1473
1474/**
1475 * Copies the extention part into pszBuffer and returns
1476 * a pointer to the buffer.
1477 * If no extention is found "" is returned.
1478 * The dot ('.') is not included!
1479 * @returns Pointer to pszBuffer with path.
1480 * @param pszFilename Pointer to readonly filename.
1481 * @param pszBuffer Pointer to output Buffer.
1482 * @status completely implemented.
1483 * @author knut st. osmundsen
1484 */
1485char *fileExt(const char *pszFilename, char *pszBuffer)
1486{
1487 char *psz = strrchr(pszFilename, '.');
1488 if (psz != NULL)
1489 {
1490 if (strchr(psz, '\\') != NULL || strchr(psz, '/') != NULL)
1491 *pszBuffer = '\0';
1492 else
1493 strcpy(pszBuffer, psz + 1);
1494 }
1495 else
1496 *pszBuffer = '\0';
1497
1498 return pszBuffer;
1499}
1500
1501
1502/**
1503 * Adds a file to the cache.
1504 * @returns Success indicator.
1505 * @param pszFilename Name of the file which is to be added. (with path!)
1506 */
1507static BOOL filecacheAddFile(const char *pszFilename)
1508{
1509 PFCACHEENTRY pfcNew;
1510
1511 /* allocate new block and fill in data */
1512 pfcNew = malloc(sizeof(FCACHEENTRY) + strlen(pszFilename) + 1);
1513 if (pfcNew == NULL)
1514 {
1515 fprintf(stderr, "error: out of memory! (line=%d)\n", __LINE__);
1516 return FALSE;
1517 }
1518 pfcNew->Key = (char*)(void*)pfcNew + sizeof(FCACHEENTRY);
1519 strcpy((char*)(unsigned)pfcNew->Key, pszFilename);
1520 if (!AVLInsert(&pfcTree, pfcNew))
1521 {
1522 free(pfcNew);
1523 return TRUE;
1524 }
1525 cfcNodes++;
1526
1527 return TRUE;
1528}
1529
1530
1531
1532/**
1533 * Adds a file to the cache.
1534 * @returns Success indicator.
1535 * @param pszDir Name of the path which is to be added. (with slash!)
1536 */
1537static BOOL filecacheAddDir(const char *pszDir)
1538{
1539 PFCACHEENTRY pfcNew;
1540 APIRET rc;
1541 char szDir[CCHMAXPATH];
1542 int cchDir;
1543 char achBuffer[16384];
1544 PFILEFINDBUF3 pfindbuf3 = (PFILEFINDBUF3)(void*)&achBuffer[0];
1545 HDIR hDir = HDIR_CREATE;
1546 ULONG cFiles = 0xFFFFFFF;
1547 int i;
1548
1549 /* Make path */
1550 filePathSlash2(pszDir, szDir);
1551 strlwr(szDir); /* Convert name to lower case to allow faster searchs! */
1552 cchDir = strlen(szDir);
1553
1554
1555 /* Add directory to pfcDirTree. */
1556 pfcNew = malloc(sizeof(FCACHEENTRY) + cchDir + 1);
1557 if (pfcNew == NULL)
1558 {
1559 fprintf(stderr, "error: out of memory! (line=%d)\n", __LINE__);
1560 DosFindClose(hDir);
1561 return FALSE;
1562 }
1563 pfcNew->Key = (char*)(void*)pfcNew + sizeof(FCACHEENTRY);
1564 strcpy((char*)(unsigned)pfcNew->Key, szDir);
1565 AVLInsert(&pfcDirTree, pfcNew);
1566
1567
1568 /* Start to search directory - all files */
1569 strcat(szDir + cchDir, "*");
1570 rc = DosFindFirst(szDir, &hDir, FILE_NORMAL,
1571 pfindbuf3, sizeof(achBuffer),
1572 &cFiles, FIL_STANDARD);
1573 while (rc == NO_ERROR)
1574 {
1575 for (i = 0;
1576 i < cFiles;
1577 i++, pfindbuf3 = (PFILEFINDBUF3)((int)pfindbuf3 + pfindbuf3->oNextEntryOffset)
1578 )
1579 {
1580 pfcNew = malloc(sizeof(FCACHEENTRY) + cchDir + pfindbuf3->cchName + 1);
1581 if (pfcNew == NULL)
1582 {
1583 fprintf(stderr, "error: out of memory! (line=%d)\n", __LINE__);
1584 DosFindClose(hDir);
1585 return FALSE;
1586 }
1587 pfcNew->Key = (char*)(void*)pfcNew + sizeof(FCACHEENTRY);
1588 strcpy((char*)(unsigned)pfcNew->Key, szDir);
1589 strcpy((char*)(unsigned)pfcNew->Key + cchDir, pfindbuf3->achName);
1590 strlwr((char*)(unsigned)pfcNew->Key + cchDir); /* Convert name to lower case to allow faster searchs! */
1591 if (!AVLInsert(&pfcTree, pfcNew))
1592 free(pfcNew);
1593 else
1594 cfcNodes++;
1595 _heap_check();
1596 }
1597
1598 /* next */
1599 cFiles = 0xFFFFFFF;
1600 pfindbuf3 = (PFILEFINDBUF3)(void*)&achBuffer[0];
1601 rc = DosFindNext(hDir, pfindbuf3, sizeof(achBuffer), &cFiles);
1602 }
1603
1604 DosFindClose(hDir);
1605
1606 return TRUE;
1607}
1608
1609
1610/**
1611 * Checks if pszFilename is exists in the cache.
1612 * @return TRUE if found. FALSE if not found.
1613 * @param pszFilename Name of the file to be found. (with path!)
1614 * This is in lower case!
1615 */
1616static BOOL filecacheFind(const char *pszFilename)
1617{
1618 return AVLGet(&pfcTree, (AVLKEY)pszFilename) != NULL;
1619}
1620
1621
1622/**
1623 * Checks if pszFilename is exists in the cache.
1624 * @return TRUE if found. FALSE if not found.
1625 * @param pszFilename Name of the file to be found. (with path!)
1626 * This is in lower case!
1627 */
1628static BOOL filecacheIsDirCached(const char *pszDir)
1629{
1630 return AVLGet(&pfcDirTree, (AVLKEY)pszDir) != NULL;
1631}
1632
1633
1634
1635/**
1636 * Finds a filename in a specified pathlist.
1637 * @returns Pointer to a filename consiting of the path part + the given filename.
1638 * (pointer into pszBuffer)
1639 * NULL if file is not found. ("" in buffer)
1640 * @param pszPathList Path list to search for filename.
1641 * @parma pszFilename Filename to find.
1642 * @parma pszBuffer Ouput Buffer.
1643 * @status completely implemented.
1644 * @author knut st. osmundsen
1645 * @remark need substantial optimizations. 95% of execution is spend here.
1646 */
1647static char *pathlistFindFile(const char *pszPathList, const char *pszFilename, char *pszBuffer)
1648{
1649 const char *psz = pszPathList;
1650 const char *pszNext = NULL;
1651
1652 *pszBuffer = '\0';
1653
1654 if (pszPathList == NULL)
1655 return NULL;
1656
1657 while (*psz != '\0')
1658 {
1659 /* find end of this path */
1660 pszNext = strchr(psz, ';');
1661 if (pszNext == NULL)
1662 pszNext = psz + strlen(psz);
1663
1664 if (pszNext - psz > 0)
1665 {
1666 APIRET rc;
1667 char szFile[CCHMAXPATH];
1668
1669 /* make search statment */
1670 strncpy(szFile, psz, pszNext - psz);
1671 szFile[pszNext - psz] = '\0';
1672 if (szFile[pszNext - psz - 1] != '\\' && szFile[pszNext - psz - 1] != '/')
1673 strcpy(&szFile[pszNext - psz], "\\");
1674 strcat(szFile, pszFilename);
1675 strlwr(szFile); /* to speed up AVL tree search we'll lowercase all names. */
1676 fileNormalize(szFile);
1677
1678 /*
1679 * Search for the file in this directory.
1680 * Search cache first
1681 */
1682 if (!filecacheFind(szFile))
1683 {
1684 char szDir[CCHMAXPATH];
1685
1686 filePathSlash(szFile, szDir);
1687 if (filecacheIsDirCached(szDir))
1688 rc = ERROR_FILE_NOT_FOUND;
1689 else
1690 {
1691 /*
1692 * If caching of entire dirs are enabled, we'll
1693 * add the directory to the cache and search it.
1694 */
1695 if (fCacheSearchDirs && filecacheAddDir(szDir))
1696 rc = filecacheFind(szFile) ? NO_ERROR : ERROR_FILE_NOT_FOUND;
1697 else
1698 {
1699 FILESTATUS3 fsts3;
1700
1701 /* ask the OS */
1702 rc = DosQueryPathInfo(szFile, FIL_STANDARD, &fsts3, sizeof(fsts3));
1703 if (rc == NO_ERROR)
1704 { /* add file to cache. */
1705 filecacheAddFile(szFile);
1706 }
1707 }
1708 }
1709 }
1710 else
1711 rc = NO_ERROR;
1712
1713 /* did we find it? */
1714 if (rc == NO_ERROR)
1715 {
1716 strncpy(pszBuffer, psz, pszNext - psz);
1717 pszBuffer[pszNext - psz] = '\0';
1718 if (pszBuffer[pszNext - psz - 1] != '\\' && pszBuffer[pszNext - psz - 1] != '/')
1719 strcpy(&pszBuffer[pszNext - psz], "\\");
1720 strcat(pszBuffer, pszFilename);
1721 break;
1722 }
1723 }
1724
1725 /* next */
1726 if (*pszNext != ';')
1727 break;
1728 psz = pszNext + 1;
1729 }
1730
1731 return *pszBuffer == '\0' ? NULL : pszBuffer;
1732}
1733
1734
1735/**
1736 * Finds the first char after word.
1737 * @returns Pointer to the first char after word.
1738 * @param psz Where to start.
1739 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
1740 */
1741static char *findEndOfWord(char *psz)
1742{
1743
1744 while (*psz != '\0' &&
1745 (
1746 (*psz >= 'A' && *psz <= 'Z') || (*psz >= 'a' && *psz <= 'z')
1747 ||
1748 (*psz >= '0' && *psz <= '9')
1749 ||
1750 *psz == '_'
1751 )
1752 )
1753 ++psz;
1754 return (char *)psz;
1755}
1756
1757#if 0 /* not used */
1758/**
1759 * Find the starting char of a word
1760 * @returns Pointer to first char in word.
1761 * @param psz Where to start.
1762 * @param pszStart Where to stop.
1763 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
1764 */
1765static char *findStartOfWord(const char *psz, const char *pszStart)
1766{
1767 const char *pszR = psz;
1768 while (psz >= pszStart &&
1769 (
1770 (*psz >= 'A' && *psz <= 'Z')
1771 || (*psz >= 'a' && *psz <= 'z')
1772 || (*psz >= '0' && *psz <= '9')
1773 || *psz == '_'
1774 )
1775 )
1776 pszR = psz--;
1777 return (char*)pszR;
1778}
1779#endif
1780
1781/**
1782 * Find the size of a file.
1783 * @returns Size of file. -1 on error.
1784 * @param phFile File handle.
1785 */
1786static signed long fsize(FILE *phFile)
1787{
1788 int ipos;
1789 signed long cb;
1790
1791 if ((ipos = ftell(phFile)) < 0
1792 ||
1793 fseek(phFile, 0, SEEK_END) != 0
1794 ||
1795 (cb = ftell(phFile)) < 0
1796 ||
1797 fseek(phFile, ipos, SEEK_SET) != 0
1798 )
1799 cb = -1;
1800 return cb;
1801}
1802
1803
1804
1805/**
1806 * Trims a string, ie. removing spaces (and tabs) from both ends of the string.
1807 * @returns Pointer to first not space or tab char in the string.
1808 * @param psz Pointer to the string which is to be trimmed.
1809 * @status completely implmented.
1810 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
1811 */
1812INLINE char *trim(char *psz)
1813{
1814 int i;
1815 if (psz == NULL)
1816 return NULL;
1817 while (*psz == ' ' || *psz == '\t')
1818 psz++;
1819 i = strlen(psz) - 1;
1820 while (i >= 0 && (psz[i] == ' ' || *psz == '\t'))
1821 i--;
1822 psz[i+1] = '\0';
1823 return psz;
1824}
1825
1826
1827/**
1828 * Right trims a string, ie. removing spaces (and tabs) from the end of the stri
1829 * @returns Pointer to the string passed in.
1830 * @param psz Pointer to the string which is to be right trimmed.
1831 * @status completely implmented.
1832 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
1833 */
1834INLINE char *trimR(char *psz)
1835{
1836 int i;
1837 if (psz == NULL)
1838 return NULL;
1839 i = strlen(psz) - 1;
1840 while (i >= 0 && (psz[i] == ' ' || *psz == '\t'))
1841 i--;
1842 psz[i+1] = '\0';
1843 return psz;
1844}
1845
1846
1847/**
1848 * Creates a memory buffer for a text file.
1849 * @returns Pointer to file memoryblock. NULL on error.
1850 * @param pszFilename Pointer to filename string.
1851 */
1852static void *textbufferCreate(const char *pszFilename)
1853{
1854 void *pvFile = NULL;
1855 FILE *phFile;
1856
1857 phFile = fopen(pszFilename, "r");
1858 if (phFile != NULL)
1859 {
1860 signed long cbFile = fsize(phFile);
1861 if (cbFile > 0)
1862 {
1863 pvFile = malloc(cbFile + 1);
1864 if (pvFile != NULL)
1865 {
1866 memset(pvFile, 0, cbFile + 1);
1867 if (fread(pvFile, 1, cbFile, phFile) == 0)
1868 { /* failed! */
1869 free(pvFile);
1870 pvFile = NULL;
1871 }
1872 }
1873 else
1874 fprintf(stderr, "warning/error: failed to open file %s\n", pszFilename);
1875 }
1876 fclose(phFile);
1877 }
1878 return pvFile;
1879}
1880
1881
1882/**
1883 * Destroys a text textbuffer.
1884 * @param pvBuffer Buffer handle.
1885 */
1886static void textbufferDestroy(void *pvBuffer)
1887{
1888 free(pvBuffer);
1889}
1890
1891
1892/**
1893 * Gets the next line from an textbuffer.
1894 * @returns Pointer to the next line.
1895 * @param pvBuffer Buffer handle.
1896 * @param psz Pointer to current line.
1897 * NULL is passed in to get the first line.
1898 */
1899static char *textbufferNextLine(void *pvBuffer, register char *psz)
1900{
1901 register char ch;
1902
1903 /* if first line psz is NULL. */
1904 if (psz == NULL)
1905 return (char*)pvBuffer;
1906
1907 /* skip till end of file or end of line. */
1908 ch = *psz;
1909 while (ch != '\0' && ch != '\n' && ch != '\r')
1910 ch = *++psz;
1911
1912 /* skip line end */
1913 if (ch == '\n')
1914 psz++;
1915 if (*psz == '\r')
1916 psz++;
1917
1918 return psz;
1919}
1920
1921
1922/**
1923 * Gets the next line from an textbuffer.
1924 * (fgets for textbuffer)
1925 * @returns Pointer to pszOutBuffer. NULL when end of file.
1926 * @param pvBuffer Buffer handle.
1927 * @param ppv Pointer to a buffer index pointer. (holds the current buffer index)
1928 * Pointer to a null pointer is passed in to get the first line.
1929 * @param pszLineBuffer Output line buffer. (!= NULL)
1930 * @param cchLineBuffer Size of the output line buffer. (> 0)
1931 * @remark '\n' and '\r' are removed!
1932 */
1933static char *textbufferGetNextLine(void *pvBuffer, void **ppv, char *pszLineBuffer, int cchLineBuffer)
1934{
1935 char * pszLine = pszLineBuffer;
1936 char * psz = *(char**)(void*)ppv;
1937 register char ch;
1938
1939 /* first line? */
1940 if (psz == NULL)
1941 psz = pvBuffer;
1942
1943 /* Copy to end of the line or end of the linebuffer. */
1944 ch = *psz;
1945 cchLineBuffer--; /* reserve space for '\0' */
1946 while (cchLineBuffer > 0 && ch != '\0' && ch != '\n' && ch != '\r')
1947 {
1948 *pszLine++ = ch;
1949 ch = *++psz;
1950 }
1951 *pszLine = '\0';
1952
1953 /* skip line end */
1954 if (ch == '\n')
1955 ch = *++psz;
1956 if (ch == '\r')
1957 psz++;
1958
1959 /* check if position has changed - if unchanged it's the end of file! */
1960 if (*ppv == (void*)psz)
1961 pszLineBuffer = NULL;
1962
1963 /* store current position */
1964 *ppv = (void*)psz;
1965
1966 return pszLineBuffer;
1967}
1968
1969
1970/**
1971 * Appends a depend file to the internal file.
1972 */
1973static BOOL depReadFile(const char *pszFilename)
1974{
1975 void *pvFile;
1976 char *pszNext;
1977 BOOL fMoreDeps = FALSE;
1978 void *pvRule = NULL;
1979
1980 /* read depend file */
1981 pvFile = textbufferCreate(pszFilename);
1982 if (pvFile == NULL)
1983 return FALSE;
1984
1985 /* parse the original depend file */
1986 pszNext = pvFile;
1987 while (*pszNext != '\0')
1988 {
1989 int i;
1990 int cch;
1991 char *psz;
1992
1993 /* get the next line. */
1994 psz = pszNext;
1995 pszNext = textbufferNextLine(pvFile, pszNext);
1996
1997 /*
1998 * Process the current line:
1999 * Start off by terminating the line.
2000 * Trim the line,
2001 * Skip empty lines.
2002 * If not looking for more deps Then
2003 * Check if new rule starts here.
2004 * Endif
2005 *
2006 * If more deps to last rule Then
2007 * Get dependant name.
2008 * Endif
2009 */
2010 i = -1;
2011 while (psz <= &pszNext[i] && pszNext[i] == '\n' || pszNext[i] == '\r')
2012 pszNext[i--] = '\0';
2013 trimR(psz);
2014 cch = strlen(psz);
2015 if (cch == 0)
2016 continue;
2017
2018 /* new rule? */
2019 if (!fMoreDeps && *psz != ' ' && *psz != '\t' && *psz != '\0')
2020 {
2021 i = 0;
2022 while (psz[i] != '\0')
2023 {
2024 if (psz[i] == ':'
2025 && (psz[i+1] == ' '
2026 || psz[i+1] == '\t'
2027 || psz[i+1] == '\0'
2028 || psz[i+1] == '\\'
2029 )
2030 )
2031 break;
2032 i++;
2033 }
2034
2035 if (psz[i] == ':')
2036 { /* new rule! */
2037 psz[i] = '\0';
2038 pvRule = depAddRule(trimR(psz), NULL, NULL);
2039 psz += i + 1;
2040 cch -= i + 1;
2041 fMoreDeps = TRUE;
2042 }
2043 }
2044
2045 /* more dependants */
2046 if (fMoreDeps)
2047 {
2048 if (cch > 0 && psz[cch-1] == '\\')
2049 {
2050 fMoreDeps = TRUE;
2051 psz[cch-1] = '\0';
2052 }
2053 else
2054 fMoreDeps = FALSE;
2055
2056 /* if not duplicate rule */
2057 if (pvRule != NULL)
2058 {
2059 psz = trim(psz);
2060 if (*psz != '\0')
2061 depAddDepend(pvRule, psz);
2062 }
2063 }
2064 } /* while */
2065
2066
2067 /* return succesfully */
2068 textbufferDestroy(pvFile);
2069 return TRUE;
2070}
2071
2072/**
2073 *
2074 * @returns Success indicator.
2075 * @params pszFilename Pointer to name of the output file.
2076 */
2077static BOOL depWriteFile(const char *pszFilename)
2078{
2079 FILE *phFile;
2080 phFile = fopen(pszFilename, "w");
2081 if (phFile != NULL)
2082 {
2083 char szBuffer[4096];
2084 int iBuffer = 0;
2085 int cch;
2086 PDEPRULE pdep = pdepList;
2087
2088 while (pdep != NULL)
2089 {
2090 /* Write rule. Flush the buffer first if necessary. */
2091 cch = strlen(pdep->pszRule);
2092 if (iBuffer + cch + 2 >= sizeof(szBuffer))
2093 {
2094 fwrite(szBuffer, iBuffer, 1, phFile);
2095 iBuffer = 0;
2096 }
2097 strcpy(szBuffer + iBuffer, pdep->pszRule);
2098 iBuffer += cch;
2099 strcpy(szBuffer + iBuffer++, ":");
2100
2101 /* write rule dependants. */
2102 if (pdep->papszDep != NULL)
2103 {
2104 char **ppsz = pdep->papszDep;
2105 while (*ppsz != NULL)
2106 {
2107 /* flush buffer? */
2108 if (iBuffer + strlen(*ppsz) + 20 >= sizeof(szBuffer))
2109 {
2110 fwrite(szBuffer, iBuffer, 1, phFile);
2111 iBuffer = 0;
2112 }
2113 iBuffer += sprintf(szBuffer + iBuffer, " \\\n %s", *ppsz);
2114
2115 /* next dependant */
2116 ppsz++;
2117 }
2118 }
2119
2120 /* Add two new lines. Flush buffer first if necessary. */
2121 if (iBuffer + 2 >= sizeof(szBuffer))
2122 {
2123 fwrite(szBuffer, iBuffer, 1, phFile);
2124 iBuffer = 0;
2125 }
2126 strcpy(szBuffer + iBuffer, "\n\n");
2127 iBuffer += 2;
2128
2129 /* next rule */
2130 pdep = pdep->pNext;
2131 }
2132
2133 /* flush buffer. */
2134 fwrite(szBuffer, iBuffer, 1, phFile);
2135
2136 fclose(phFile);
2137 return TRUE;
2138 }
2139
2140 return FALSE;
2141}
2142
2143
2144/**
2145 * Removes all entries in the list of dependencies. (pdepList)
2146 */
2147static void depRemoveAll(void)
2148{
2149 while (pdepList != NULL)
2150 {
2151 register PDEPRULE pdepToBeFree = pdepList;
2152 /* next */
2153 pdepList = pdepToBeFree->pNext;
2154
2155 /* free this */
2156 if (pdepToBeFree->papszDep != NULL)
2157 {
2158 char ** ppsz = pdepToBeFree->papszDep;
2159 while (*ppsz != NULL)
2160 free(*ppsz++);
2161 free(pdepToBeFree->papszDep);
2162 }
2163 free(pdepToBeFree);
2164 }
2165}
2166
2167
2168/**
2169 * Adds a rule to the list of dependant rules.
2170 * @returns Rule handle. NULL if rule exists/error.
2171 * @param pszRulePath Pointer to rule text. Empty strings are banned!
2172 * This string might only contain the path of the rule. (with '\\')
2173 * @param pszName Name of the rule.
2174 * NULL if pszRulePath contains the entire rule.
2175 * @param pszExt Extention (without '.')
2176 * NULL if pszRulePath or pszRulePath and pszName contains the entire rule.
2177 */
2178static void *depAddRule(const char *pszRulePath, const char *pszName, const char *pszExt)
2179{
2180 char szRule[CCHMAXPATH*2];
2181 PDEPRULE pdepPrev = NULL;
2182 PDEPRULE pdep = pdepList;
2183 PDEPRULE pNew;
2184 int cch;
2185
2186 /* make rulename */
2187 strcpy(szRule, pszRulePath);
2188 cch = strlen(szRule);
2189 if (pszName != NULL)
2190 {
2191 strcpy(szRule + cch, pszName);
2192 cch += strlen(szRule + cch);
2193 }
2194 if (pszExt != NULL)
2195 {
2196 strcat(szRule + cch++, ".");
2197 strcat(szRule + cch, pszExt);
2198 cch += strlen(szRule + cch);
2199 }
2200
2201 /* find location */
2202 while (pdep != NULL && stricmp(pdep->pszRule, szRule) < 0)
2203 {
2204 pdepPrev = pdep;
2205 pdep = pdep->pNext;
2206 }
2207
2208 /* check if matching rule name */
2209 if (pdep != NULL && stricmp(pdep->pszRule, szRule) == 0)
2210 return NULL;
2211
2212 /*
2213 * Allocate a new rule structure and fill in data
2214 * Note. One block for both the DEPRULE and the pszRule string.
2215 */
2216 pNew = malloc(sizeof(DEPRULE) + cch + 1);
2217 if (pNew == NULL)
2218 return NULL;
2219 pNew->pszRule = (char*)(void*)(pNew + 1);
2220 strcpy(pNew->pszRule, szRule);
2221 pNew->cDeps = 0;
2222 pNew->papszDep = NULL;
2223
2224 /* link in module (before pdep) */
2225 pNew->pNext = pdep;
2226 if (pdepPrev == NULL)
2227 pdepList = pNew;
2228 else
2229 pdepPrev->pNext = pNew;
2230
2231 _heap_check();
2232 return pNew;
2233}
2234
2235
2236
2237/**
2238 * Adds a dependant to a rule.
2239 * @returns Successindicator.
2240 * @param pvRule Rule handle.
2241 * @param pszDep Pointer to dependant name
2242 */
2243static BOOL depAddDepend(void *pvRule, const char *pszDep)
2244{
2245 PDEPRULE pdep = (PDEPRULE)pvRule;
2246
2247 /* allocate more array space */
2248 if (((pdep->cDeps) % 48) == 0)
2249 {
2250 pdep->papszDep = realloc(pdep->papszDep, sizeof(char*) * (pdep->cDeps + 50));
2251 if (pdep->papszDep == NULL)
2252 {
2253 pdep->cDeps = 0;
2254 return FALSE;
2255 }
2256 }
2257
2258 /* allocate string space and copy pszDep */
2259 if ((pdep->papszDep[pdep->cDeps] = malloc(strlen(pszDep) + 1)) == NULL)
2260 return FALSE;
2261 strcpy(pdep->papszDep[pdep->cDeps], pszDep);
2262
2263 /* terminate array and increment dep count */
2264 pdep->papszDep[++pdep->cDeps] = NULL;
2265
2266 /* successful! */
2267 _heap_check();
2268 return TRUE;
2269}
2270
2271
2272
2273/*
2274 * Testing purpose.
2275 */
2276#include <os2.h>
2277
2278
2279
Note: See TracBrowser for help on using the repository browser.