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

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

Simple cleanup is implemented but disabled.

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