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

Last change on this file since 3128 was 3123, checked in by bird, 26 years ago

Changed to use internal list of dependencies which is flushed to disk
on when all files are searched.
This list is sorted, and don't allow two rules with the same name. The existing
rule has precedence. (This feature might come in handy when using OpusMake!)

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