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

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

Implemented simple C/C++ preprocessor.

File size: 48.1 KB
Line 
1/* $Id: fastdep.c,v 1.4 2000-03-04 23:51:57 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 const char * pszRsrcExt;
77 BOOL fObjRule;
78 BOOL fNoObjectPath;
79 BOOL fSrcWhenObj;
80 BOOL fAppend; /* append to the output file, not overwrite it. */
81} OPTIONS, *POPTIONS;
82
83
84/*
85 * Language specific analysis functions type.
86 */
87typedef int ( _FNLANG) (FILE *phDep, const char *pszFilename, FILE *phFile,
88 BOOL fHeader, POPTIONS pOptions);
89typedef _FNLANG *PFNLANG;
90
91
92/**
93 * This struct holds the static configuration of the util.
94 */
95typedef struct _ConfigEntry
96{
97 const char **papszExts; /* Pointer to an array of pointer to extentions for this handler. */
98 /* If NULL this is the last entry. */
99 int iFirstHdr; /* Index into the papszExts array of the first headerfile/copybook. */
100 /* Set it to the NULL element of the array if no headers for this extention. */
101 /* A non-header file may get a object rule. */
102 PFNLANG pfn; /* Pointer to handler function. */
103} CONFIGENTRY, *PCONFIGENTRY;
104
105
106/*******************************************************************************
107* Internal Functions *
108*******************************************************************************/
109static void syntax(void);
110static int makeDependent(FILE *phDep, const char *pszFilename, POPTIONS pOptions);
111
112int langC_CPP(FILE *phDep, const char *pszFilename, FILE *phFile, BOOL fHeader, POPTIONS pOptions);
113int langAsm(FILE *phDep, const char *pszFilename, FILE *phFile, BOOL fHeader, POPTIONS pOptions);
114int langRC(FILE *phDep, const char *pszFilename, FILE *phFile, BOOL fHeader, POPTIONS pOptions);
115int langCOBOL(FILE *phDep, const char *pszFilename, FILE *phFile, BOOL fHeader, POPTIONS pOptions);
116
117
118/* string operations */
119static int strnicmpwords(const char *pszS1, const char *pszS2, int cch);
120
121/* file operations */
122char *filePath(const char *pszFilename, char *pszBuffer);
123char *filePathSlash(const char *pszFilename, char *pszBuffer);
124char *fileName(const char *pszFilename, char *pszBuffer);
125char *fileNameNoExt(const char *pszFilename, char *pszBuffer);
126char *fileExt(const char *pszFilename, char *pszBuffer);
127
128/* pathlist operations */
129char *pathlistFindFile(const char *pszPathList, const char *pszFilename, char *pszBuffer);
130
131/* word operations */
132static char *findEndOfWord(char *psz);
133#if 0 /* not used */
134static char *findStartOfWord(char *psz, const char *pszStart);
135#endif
136
137/*******************************************************************************
138* Global Variables *
139*******************************************************************************/
140static const char pszDefaultDepFile[] = ".depend";
141static const char *apszExtC_CPP[] = {"c", "sqc", "cpp", "h", "hpp", NULL};
142static const char *apszExtAsm[] = {"asm", "inc", NULL};
143static const char *apszExtRC[] = {"rc", "dlg", NULL};
144static const char *apszExtCOBOL[] = {"cbl", "cob", "sqb", NULL};
145
146static CONFIGENTRY aConfig[] =
147{
148 {
149 apszExtC_CPP,
150 3,
151 langC_CPP,
152 },
153
154 {
155 apszExtAsm,
156 1,
157 langAsm,
158 },
159
160 {
161 apszExtRC,
162 1,
163 langRC,
164 },
165
166 {
167 apszExtCOBOL,
168 3,
169 langCOBOL,
170 },
171
172 /* terminating entry */
173 {
174 NULL,
175 -1,
176 NULL
177 }
178};
179
180
181/**
182 * Main function.
183 * @returns 0 on success.
184 * -n count of failiures.
185 * @param
186 * @param
187 * @equiv
188 * @precond
189 * @methdesc
190 * @result
191 * @time
192 * @sketch
193 * @algo
194 * @remark
195 */
196int main(int argc, char **argv)
197{
198 FILE *phDep = NULL;
199 int rc = 0;
200 int argi = 1;
201 const char *pszDepFile = pszDefaultDepFile;
202
203 static char szObjectDir[CCHMAXPATH];
204 static char szObjectExt[64] = "obj";
205 static char szRsrcExt[64] = "res";
206 static char szInclude[32768] = ";";
207 static char szExclude[32768] = ";";
208
209 OPTIONS options =
210 {
211 szInclude, /* pszInclude */
212 szExclude, /* pszExclude */
213 FALSE, /* fExcludeAll */
214 szObjectExt, /* pszObjectExt */
215 szObjectDir, /* pszObjectDir */
216 szRsrcExt, /* pszRsrcExt */
217 TRUE, /* fObjRule */
218 FALSE, /* fNoObjectPath */
219 TRUE, /* fSrcWhenObj */
220 FALSE /* fAppend */
221 };
222
223 szObjectDir[0] = '\0';
224
225 if (argc == 1)
226 {
227 syntax();
228 return -87;
229 }
230
231 while (argi < argc)
232 {
233 if (argv[argi][0] == '-' || argv[argi][0] == '/')
234 {
235 /* parameters */
236 switch (argv[argi][1])
237 {
238 case 'A':
239 case 'a': /* Append to the output file */
240 options.fAppend = argv[argi][2] != '-';
241 break;
242
243 case 'D':
244 case 'd': /* "-d <filename>" */
245 if (argv[argi][2] != '\0')
246 pszDepFile = &argv[argi][2];
247 else
248 {
249 if (argi + 1 < argc)
250 pszDepFile = argv[++argi];
251 else
252 {
253 fprintf(stderr, "invalid parameter -d, filename missing!\n");
254 return -1;
255 }
256 }
257 if (phDep != NULL)
258 {
259 fclose(phDep);
260 phDep = NULL;
261 }
262 break;
263
264 case 'E': /* list of paths. If a file is found in one of these directories the */
265 case 'e': /* filename will be used without the directory path. */
266 /* Eall<[+]|-> ? */
267 if (strlen(&argv[argi][1]) <= 5 && strnicmp(&argv[argi][1], "Eall", 4) == 0)
268 {
269 options.fExcludeAll = argv[argi][5] != '-';
270 break;
271 }
272 /* path or path list */
273 if (strlen(argv[argi]) > 2)
274 strcat(szExclude, &argv[argi][2]);
275 else
276 {
277 strcat(szExclude, argv[argi+1]);
278 argi++;
279 }
280 if (szExclude[strlen(szExclude)-1] != ';')
281 strcat(szExclude, ";");
282 break;
283
284 case 'I': /* optional include path. This has precedence over the INCLUDE environment variable. */
285 case 'i':
286 if (strlen(argv[argi]) > 2)
287 strcat(szInclude, &argv[argi][2]);
288 else
289 {
290 strcat(szInclude, argv[argi+1]);
291 argi++;
292 }
293 if (szInclude[strlen(szInclude)-1] != ';')
294 strcat(szInclude, ";");
295 break;
296
297 case 'n': /* no object path , -N<[+]|-> */
298 case 'N':
299 if (strlen(argv[argi]) <= 1+1+1)
300 options.fNoObjectPath = argv[argi][2] != '-';
301 else
302 {
303 fprintf(stderr, "error: invalid parameter!, '%s'\n", argv[argi]);
304 return -1;
305 }
306 break;
307
308 case 'o': /* object base directory, Obj or Obr<[+]|-> */
309 case 'O':
310 if (strlen(&argv[argi][1]) <= 4 && strnicmp(&argv[argi][1], "Obr", 3) == 0)
311 {
312 options.fObjRule = argv[argi][4] != '-';
313 break;
314 }
315
316 if (strlen(&argv[argi][1]) >= 4 && strnicmp(&argv[argi][1], "Obj", 3) == 0)
317 {
318 if (strlen(argv[argi]) > 4)
319 strcpy(szObjectExt, argv[argi]+4);
320 else
321 {
322 strcpy(szObjectExt, argv[argi+1]);
323 argi++;
324 }
325 break;
326 }
327
328 /* path */
329 if (strlen(argv[argi]) > 2)
330 strcpy(szObjectDir, argv[argi]+2);
331 else
332 {
333 strcpy(szObjectDir, argv[argi+1]);
334 argi++;
335 }
336 if (szObjectDir[strlen(szObjectDir)-1] != '\\'
337 && szObjectDir[strlen(szObjectDir)-1] != '/'
338 )
339 strcat(szObjectDir, "\\");
340 break;
341
342 case 'r':
343 case 'R':
344 if (strlen(argv[argi]) > 2)
345 strcpy(szObjectExt, argv[argi]+2);
346 else
347 {
348 strcpy(szObjectExt, argv[argi+1]);
349 argi++;
350 }
351 break;
352
353 case 'h':
354 case 'H':
355 case '?':
356 syntax();
357 return 1;
358
359 default:
360 fprintf(stderr, "error: invalid parameter! '%s'\n", argv[argi]);
361 return -1;
362 }
363
364 }
365 else
366 { /* not a parameter! */
367 ULONG ulRc;
368 FILEFINDBUF3 filebuf;
369 HDIR hDir = HDIR_CREATE;
370 ULONG ulFound = 1;
371
372 memset(&filebuf, 0, sizeof(filebuf));
373
374 /*
375 * Open output file.
376 */
377 if (phDep == NULL)
378 {
379 phDep = fopen(pszDepFile, options.fAppend ? "a" : "w");
380 if (phDep == NULL)
381 {
382 fprintf(stderr, "error opening outputfile '%s'.\n", pszDepFile);
383 return 1;
384 }
385 }
386
387 /*
388 * Search for the files specified.
389 */
390 ulRc = DosFindFirst(argv[argi], &hDir,
391 FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_ARCHIVED,
392 &filebuf, sizeof(FILEFINDBUF3), &ulFound, FIL_STANDARD);
393 while (ulRc == NO_ERROR)
394 {
395 char *psz;
396 char szSource[CCHMAXPATH];
397
398 /*
399 * Make full path.
400 */
401 if ((psz = strrchr(argv[argi], '\\')) || (psz = strrchr(argv[argi], '/')))
402 {
403 strncpy(szSource, argv[argi], psz - argv[argi] + 1);
404 szSource[psz - argv[argi] + 1] = '\0';
405 }
406 else
407 szSource[0] = '\0';
408 strcat(szSource, filebuf.achName);
409
410 /*
411 * Analyse the file.
412 */
413 rc -= makeDependent(phDep, &szSource[0], &options);
414
415 /* next file */
416 ulRc = DosFindNext(hDir, &filebuf, sizeof(filebuf), &ulFound);
417 }
418 DosFindClose(hDir);
419 }
420 /* next */
421 argi++;
422 }
423
424 return rc;
425}
426
427
428/**
429 * Displays the syntax description for this util.
430 * @status completely implemented.
431 * @author knut st. osmundsen
432 */
433static void syntax(void)
434{
435 printf(
436 "FastDep v0.1\n"
437 "Quick and dirty dependant scanner. Creates a makefile readable depend file.\n"
438 "\n"
439 "Syntax: FastDep [-a<[+]|->] [-d <outputfn>] [-e <excludepath>] [-eall<[+]|->]\n"
440 " [-i <include>] [-n<[+]|->] [-o <objdir>] [-obr<[+]|->] <files>\n"
441 "\n"
442 " -a<[+]|-> Append to the output file. Default: Overwrite.\n"
443 " -d <outputfn> Output filename. Default: %s\n"
444 " -e excludepath Exclude paths. If a filename is found in any\n"
445 " of these paths only the filename is used, not\n"
446 " the path+filename (which is default).\n"
447 " -eall<[+]|-> -eall+: No path are added to the filename.\n"
448 " -eall-: The filename is appended the include path\n"
449 " was found in.\n"
450 " Default: eall-\n"
451 " -i <include> Additional include paths. INCLUDE is searched after this.\n"
452 " -n<[+]|-> No path for object files in the rules.\n"
453 " -o <objdir> Path were object files are placed. This path replaces the\n"
454 " entire filename path\n"
455 " -obr<[+]|-> -obr+: Object rule.\n"
456 " -obr-: No object rule, rule for source filename is generated.\n"
457 " -obj[ ]<objext> Object extention. Default: obj\n"
458 " -r[ ]<rsrcext> Resource binary extention. Default: res\n"
459 " <files> Files to scan. Wildchars are allowed.\n"
460 "\n",
461 pszDefaultDepFile
462 );
463}
464
465
466/**
467 * Generates depend info on this file, and fwrites it to phDep.
468 * @returns
469 * @param phDep Pointer to file struct for outfile.
470 * @param pszFilename Pointer to source filename.
471 * @param pOptions Pointer to options struct.
472 * @status completely implemented.
473 * @author knut st. osmundsen
474 */
475static int makeDependent(FILE *phDep, const char *pszFilename, POPTIONS pOptions)
476{
477 int rc = -1;
478 FILE *phFile;
479
480 phFile = fopen(pszFilename, "r");
481 if (phFile != NULL)
482 {
483 char szExt[CCHMAXPATH];
484 PCONFIGENTRY pCfg = &aConfig[0];
485 BOOL fHeader;
486
487 /*
488 * Find which filetype this is...
489 */
490 fileExt(pszFilename, szExt);
491 while (pCfg->papszExts != NULL)
492 {
493 const char **ppsz = pCfg->papszExts;
494 while (*ppsz != NULL && stricmp(*ppsz, szExt) != 0)
495 ppsz++;
496 if (*ppsz != NULL)
497 {
498 fHeader = &pCfg->papszExts[pCfg->iFirstHdr] <= ppsz;
499 break;
500 }
501 pCfg++;
502 }
503
504 /* Found? */
505 if (pCfg->papszExts != NULL)
506 rc = (*pCfg->pfn)(phDep, pszFilename, phFile, fHeader, pOptions);
507 else
508 {
509 if (*fileName(pszFilename, szExt) != '.') /* these are 'hidden' files, like .cvsignore, let's ignore them. */
510 fprintf(stderr, "warning: '%s' has an unknown file type.\n", pszFilename);
511 rc = 0;
512 }
513
514 fputs("\n", phDep);
515 fclose(phFile);
516 }
517 else
518 fprintf(stderr, "failed to open '%s'\n", pszFilename);
519
520 return rc;
521}
522
523
524/**
525 * Generates depend info on this C or C++ file, and writes it to phDep.
526 * @returns 0 on success.
527 * !0 on error.
528 * @param phDep Pointer to file struct for outfile.
529 * @param pszFilename Pointer to source filename.
530 * @param phFile Pointer to source file handle.
531 * @param pOptions Pointer to options struct.
532 * @status completely implemented.
533 * @author knut st. osmundsen
534 */
535int langC_CPP(FILE *phDep, const char *pszFilename, FILE *phFile, BOOL fHeader, POPTIONS pOptions)
536{
537 int iLine; /* Linenumber. */
538 char szBuffer[4096]; /* Max line length is 4096... should not be a problem. */
539 BOOL fComment; /* TRUE when within a multiline comment. */
540 /* FALSE when not within a multiline comment. */
541 int iIfStack; /* StackPointer. */
542 struct IfStackEntry
543 {
544 int fIncluded : 1; /* TRUE: include this code;
545 * FALSE: excluded */
546 int fIf : 1; /* TRUE: #if part of the expression.
547 * FALSE: #else part of the expression. */
548 int fSupported : 1; /* TRUE: supported if/else statement
549 * FALSE: unsupported all else[<something>] are ignored
550 * All code is included.
551 */
552 } achIfStack[256];
553
554
555 /**********************************/
556 /* print file name to depend file */
557 /**********************************/
558 if (pOptions->fObjRule && !fHeader)
559 {
560 if (pOptions->fNoObjectPath)
561 fprintf(phDep, "%s.%s:", fileNameNoExt(pszFilename, szBuffer), pOptions->pszObjectExt);
562 else
563 fprintf(phDep, "%s%s.%s:",
564 (*pOptions->pszObjectDir != '\0') ?
565 pOptions->pszObjectDir : filePathSlash(pszFilename, szBuffer),
566 fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH),
567 pOptions->pszObjectExt);
568
569 if (pOptions->fSrcWhenObj)
570 fprintf(phDep, " \\\n%4s %s", "", pszFilename);
571 }
572 else
573 fprintf(phDep, "%s:", pszFilename);
574
575
576 /*******************/
577 /* find dependants */
578 /*******************/
579 /* Initiate the IF-stack, comment state and line number. */
580 iIfStack = 0;
581 achIfStack[iIfStack].fIf = TRUE;
582 achIfStack[iIfStack].fIncluded = TRUE;
583 achIfStack[iIfStack].fSupported = TRUE;
584 fComment = FALSE;
585 iLine = 0;
586 while (!feof(phFile)) /* line loop */
587 {
588 if (fgets(szBuffer, sizeof(szBuffer), phFile) != NULL)
589 {
590 /* search for #include */
591 register char *pszC;
592 int cbLen;
593 int i = 0;
594 iLine++;
595
596 /* skip blank chars */
597 cbLen = strlen(szBuffer);
598 while (i + 2 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t'))
599 i++;
600
601 /* preprocessor statement? */
602 if (!fComment && szBuffer[i] == '#')
603 {
604 /*
605 * Preprocessor checks
606 * We known that we have a preprocessor statment (starting with an '#' * at szBuffer[i]).
607 * Depending on the word afterwards we'll take some different actions.
608 * So we'll start of by extracting that word and make a string swich on it.
609 * Note that there might be some blanks between the hash and the word.
610 */
611 int cchWord;
612 char * pszEndWord;
613 char * pszArgument;
614 i++; /* skip hash ('#') */
615 while (szBuffer[i] == '\t' || szBuffer[i] == ' ') /* skip blanks */
616 i++;
617 pszArgument = pszEndWord = findEndOfWord(&szBuffer[i]);
618 cchWord = pszEndWord - &szBuffer[i];
619
620 /*
621 * Find the argument by skipping the blanks.
622 */
623 while (*pszArgument == '\t' || *pszArgument == ' ') /* skip blanks */
624 pszArgument++;
625
626 /*
627 * string switch.
628 */
629 if (strncmp(&szBuffer[i], "include", cchWord) == 0)
630 {
631 /*
632 * #include
633 *
634 * Are we in a state where this file is to be included?
635 */
636 if (achIfStack[iIfStack].fIncluded)
637 {
638 char szFullname[CCHMAXPATH];
639 char *psz;
640 BOOL f = FALSE;
641 int j;
642
643 /* extract info between "" or <> */
644 while (i < cbLen && !(f = (szBuffer[i] == '"' || szBuffer[i] == '<')))
645 i++;
646 i++; /* skip '"' or '<' */
647
648 /* if invalid statement then continue with the next line! */
649 if (!f) continue;
650
651 /* find end */
652 j = f = 0;
653 while (i + j < cbLen && j < CCHMAXPATH &&
654 !(f = (szBuffer[i+j] == '"' || szBuffer[i+j] == '>')))
655 j++;
656
657 /* if invalid statement then continue with the next line! */
658 if (!f) continue;
659
660 /* copy filename */
661 strncpy(szFullname, &szBuffer[i], j);
662 szFullname[j] = '\0'; /* ensure terminatition. */
663
664 /* find include file! */
665 psz = pathlistFindFile(pOptions->pszInclude, szFullname, szBuffer);
666 if (psz == NULL)
667 psz = pathlistFindFile(getenv("INCLUDE"), szFullname, szBuffer);
668
669 /* did we find the include? */
670 if (psz != NULL)
671 {
672 char szBuffer2[CCHMAXPATH];
673 if (pOptions->fExcludeAll ||
674 pathlistFindFile(pOptions->pszExclude, szFullname, szBuffer2) != NULL
675 )
676 strcpy(szBuffer, szFullname);
677 fprintf(phDep, " \\\n%4.s %s", "", szBuffer);
678 }
679 else
680 fprintf(stderr, "%s(%d): warning include file '%s' not found!\n",
681 pszFilename, iLine, szFullname);
682 }
683 }
684 else
685 /*
686 * #if
687 */
688 if (strncmp(&szBuffer[i], "if", cchWord) == 0)
689 { /* #if 0 and #if <1-9> are supported */
690 pszEndWord = findEndOfWord(pszArgument);
691 iIfStack++;
692 if ((pszEndWord - pszArgument) == 1
693 && *pszArgument >= '0' && *pszArgument <= '9')
694 {
695 if (*pszArgument != '0')
696 achIfStack[iIfStack].fIncluded = TRUE;
697 else
698 achIfStack[iIfStack].fIncluded = FALSE;
699 }
700 else
701 achIfStack[iIfStack].fSupported = FALSE;
702 achIfStack[iIfStack].fIncluded = TRUE;
703 achIfStack[iIfStack].fIf = TRUE;
704 }
705 else
706 /*
707 * #else
708 */
709 if (strncmp(&szBuffer[i], "else", cchWord) == 0)
710 {
711 if (achIfStack[iIfStack].fSupported)
712 {
713 if (achIfStack[iIfStack].fIncluded) /* ARG!! this'll prevent warning */
714 achIfStack[iIfStack].fIncluded = FALSE;
715 else
716 achIfStack[iIfStack].fIncluded = TRUE;
717 }
718 achIfStack[iIfStack].fIf = FALSE;
719 }
720 else
721 /*
722 * #endif
723 */
724 if (strncmp(&szBuffer[i], "endif", cchWord) == 0)
725 { /* Pop the if-stack. */
726 if (iIfStack > 0)
727 iIfStack--;
728 else
729 fprintf(stderr, "%s(%d): If-Stack underflow!\n", pszFilename, iLine);
730 }
731 /*
732 * general if<something> and elseif<something> implementations
733 */
734 else
735 if (strncmp(&szBuffer[i], "elseif", 6) == 0)
736 {
737 achIfStack[iIfStack].fSupported = FALSE;
738 achIfStack[iIfStack].fIncluded = TRUE;
739 }
740 else
741 if (strncmp(&szBuffer[i], "if", 2) == 0)
742 {
743 iIfStack++;
744 achIfStack[iIfStack].fIf = TRUE;
745 achIfStack[iIfStack].fSupported = FALSE;
746 achIfStack[iIfStack].fIncluded = TRUE;
747 }
748 /* The rest of them aren't implemented yet.
749 else if (strncmp(&szBuffer[i], "if") == 0)
750 {
751 }
752 */
753 }
754
755 /*
756 * Comment checks.
757 * -Start at first non-blank.
758 * -Loop thru the line since we might have more than one
759 * comment statement on a single line.
760 */
761 pszC = &szBuffer[i];
762 while (pszC != NULL && *pszC != '\0')
763 {
764 if (fComment)
765 pszC = strstr(pszC, "*/"); /* look for end comment mark. */
766 else
767 {
768 char *pszLC;
769 pszLC= strstr(pszC, "//"); /* look for single line comment mark. */
770 pszC = strstr(pszC, "/*"); /* look for start comment mark */
771 if (pszLC && pszLC < pszC) /* if there is an single line comment mark before the */
772 break; /* muliline comment mark we'll ignore the multiline mark. */
773 }
774
775 /* Comment mark found? */
776 if (pszC != NULL)
777 {
778 fComment = !fComment;
779 pszC += 2; /* skip comment mark */
780
781 /* debug */
782 /*
783 if (fComment)
784 fprintf(stderr, "starts at line %d\n", iLine);
785 else
786 fprintf(stderr, "ends at line %d\n", iLine);
787 */
788 }
789 }
790 }
791 else
792 break;
793 } /*while*/
794 fputs("\n", phDep);
795
796 return 0;
797}
798
799
800/**
801 * Generates depend info on this file, and fwrites it to phDep.
802 * @returns 0 on success.
803 * !0 on error.
804 * @param phDep Pointer to file struct for outfile.
805 * @param pszFilename Pointer to source filename.
806 * @param phFile Pointer to source file handle.
807 * @param pOptions Pointer to options struct.
808 * @status completely implemented.
809 * @author knut st. osmundsen
810 */
811int langAsm(FILE *phDep, const char *pszFilename, FILE *phFile, BOOL fHeader, POPTIONS pOptions)
812{
813 char szBuffer[4096]; /* max line length */
814 int iLine;
815
816
817 /**********************************/
818 /* print file name to depend file */
819 /**********************************/
820 if (pOptions->fObjRule && !fHeader)
821 {
822 if (pOptions->fNoObjectPath)
823 fprintf(phDep, "%s.%s:", fileNameNoExt(pszFilename, szBuffer), pOptions->pszObjectExt);
824 else
825 fprintf(phDep, "%s%s.%s:",
826 (*pOptions->pszObjectDir != '\0') ?
827 pOptions->pszObjectDir : filePathSlash(pszFilename, szBuffer),
828 fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH),
829 pOptions->pszObjectExt);
830
831 if (pOptions->fSrcWhenObj)
832 fprintf(phDep, " \\\n%4s %s", "", pszFilename);
833 }
834 else
835 fprintf(phDep, "%s:", pszFilename);
836
837
838 /*******************/
839 /* find dependants */
840 /*******************/
841 iLine = 0;
842 while (!feof(phFile)) /* line loop */
843 {
844 if (fgets(szBuffer, sizeof(szBuffer), phFile) != NULL)
845 {
846 /* search for include */
847 int cbLen;
848 int i = 0;
849 iLine++;
850
851 /* skip blank chars */
852 cbLen = strlen(szBuffer);
853 while (i + 9 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t'))
854 i++;
855
856 /* is this an include? */
857 if (strnicmp(&szBuffer[i], "include", 7) == 0
858 && (szBuffer[i + 7] == '\t' || szBuffer[i + 7] == ' ')
859 )
860 {
861 char szFullname[CCHMAXPATH];
862 char *psz;
863 int j;
864
865 /* skip to first no blank char */
866 i += 7;
867 while (i < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t'))
868 i++;
869
870 /* comment check - if comment found, no filename was given. continue. */
871 if (szBuffer[i] == ';') continue;
872
873 /* find end */
874 j = 0;
875 while (i + j < cbLen
876 && j < CCHMAXPATH
877 && szBuffer[i+j] != ' ' && szBuffer[i+j] != '\t' && szBuffer[i+j] != '\n'
878 && szBuffer[i+j] != '\0' && szBuffer[i+j] != ';' && szBuffer[i+j] != '\r'
879 )
880 j++;
881
882 /* copy filename */
883 strncpy(szFullname, &szBuffer[i], j);
884 szFullname[j] = '\0'; /* ensure terminatition. */
885
886 /* find include file! */
887 psz = pathlistFindFile(pOptions->pszInclude, szFullname, szBuffer);
888 if (psz == NULL)
889 psz = pathlistFindFile(getenv("INCLUDE"), szFullname, szBuffer);
890
891 /* Did we find the include? */
892 if (psz != NULL)
893 {
894 char szBuffer2[CCHMAXPATH];
895 if (pOptions->fExcludeAll ||
896 pathlistFindFile(pOptions->pszExclude, szFullname, szBuffer2) != NULL
897 )
898 strcpy(szBuffer, szFullname);
899 fprintf(phDep, " \\\n%4.s %s", "", szBuffer);
900 }
901 else
902 fprintf(stderr, "%s(%d): warning include file '%s' not found!\n",
903 pszFilename, iLine, szFullname);
904 }
905 }
906 else
907 break;
908 } /*while*/
909 fputs("\n", phDep);
910
911 return 0;
912}
913
914
915/**
916 * Generates depend info on this Resource file, and writes it to phDep.
917 * @returns 0 on success.
918 * !0 on error.
919 * @param phDep Pointer to file struct for outfile.
920 * @param pszFilename Pointer to source filename.
921 * @param phFile Pointer to source file handle.
922 * @param pOptions Pointer to options struct.
923 * @status completely implemented.
924 * @author knut st. osmundsen
925 */
926int langRC(FILE *phDep, const char *pszFilename, FILE *phFile, BOOL fHeader, POPTIONS pOptions)
927{
928 char szBuffer[4096]; /* max line length */
929 int iLine;
930
931 /**********************************/
932 /* print file name to depend file */
933 /**********************************/
934 if (pOptions->fObjRule && !fHeader)
935 {
936 if (pOptions->fNoObjectPath)
937 fprintf(phDep, "%s.%s:", fileNameNoExt(pszFilename, szBuffer), pOptions->pszRsrcExt);
938 else
939 fprintf(phDep, "%s%s.res:",
940 (*pOptions->pszObjectDir != '\0') ?
941 pOptions->pszObjectDir : filePathSlash(pszFilename, szBuffer),
942 fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH),
943 pOptions->pszRsrcExt);
944
945 if (pOptions->fSrcWhenObj)
946 fprintf(phDep, " \\\n%4s %s", "", pszFilename);
947 }
948 else
949 fprintf(phDep, "%s:", pszFilename);
950
951
952 /*******************/
953 /* find dependants */
954 /*******************/
955 iLine = 0;
956 while (!feof(phFile)) /* line loop */
957 {
958 if (fgets(szBuffer, sizeof(szBuffer), phFile) != NULL)
959 {
960 /* search for #include */
961 int cbLen;
962 int i = 0;
963 iLine++;
964
965 /* skip blank chars */
966 cbLen = strlen(szBuffer);
967 while (i + 9 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t'))
968 i++;
969
970 /* is this an include? */
971 if ( strncmp(&szBuffer[i], "#include", 8) == 0
972 || strncmp(&szBuffer[i], "RCINCLUDE", 9) == 0
973 || strncmp(&szBuffer[i], "DLGINCLUDE", 10) == 0
974 )
975 {
976 char szFullname[CCHMAXPATH];
977 char *psz;
978 BOOL f = FALSE;
979 int j;
980
981 /* extract info between "" or <> */
982 while (i < cbLen && !(f = (szBuffer[i] == '"' || szBuffer[i] == '<')))
983 i++;
984 i++; /* skip '"' or '<' */
985
986 /* if invalid statement then continue with the next line! */
987 if (!f) continue;
988
989 /* find end */
990 j = f = 0;
991 while (i + j < cbLen && j < CCHMAXPATH &&
992 !(f = (szBuffer[i+j] == '"' || szBuffer[i+j] == '>')))
993 j++;
994
995 /* if invalid statement then continue with the next line! */
996 if (!f) continue;
997
998 /* copy filename */
999 strncpy(szFullname, &szBuffer[i], j);
1000 szFullname[j] = '\0'; /* ensure terminatition. */
1001
1002 /* find include file! */
1003 psz = pathlistFindFile(pOptions->pszInclude, szFullname, szBuffer);
1004 if (psz == NULL)
1005 psz = pathlistFindFile(getenv("INCLUDE"), szFullname, szBuffer);
1006
1007 /* did we find the include? */
1008 if (psz != NULL)
1009 {
1010 char szBuffer2[CCHMAXPATH];
1011 if (pOptions->fExcludeAll ||
1012 pathlistFindFile(pOptions->pszExclude, szFullname, szBuffer2) != NULL
1013 )
1014 strcpy(szBuffer, szFullname);
1015 fprintf(phDep, " \\\n%4.s %s", "", szBuffer);
1016 }
1017 else
1018 fprintf(stderr, "%s(%d): warning include file '%s' not found!\n",
1019 pszFilename, iLine, szFullname);
1020 }
1021 }
1022 else
1023 break;
1024 } /*while*/
1025 fputs("\n", phDep);
1026
1027 return 0;
1028}
1029
1030
1031/**
1032 * Generates depend info on this COBOL file, and writes it to phDep.
1033 * @returns 0 on success.
1034 * !0 on error.
1035 * @param phDep Pointer to file struct for outfile.
1036 * @param pszFilename Pointer to source filename.
1037 * @param phFile Pointer to source file handle.
1038 * @param pOptions Pointer to options struct.
1039 * @status completely implemented.
1040 * @author knut st. osmundsen
1041 */
1042int langCOBOL(FILE *phDep, const char *pszFilename, FILE *phFile, BOOL fHeader, POPTIONS pOptions)
1043{
1044 char szBuffer[4096]; /* max line length */
1045 int iLine;
1046
1047 /**********************************/
1048 /* print file name to depend file */
1049 /**********************************/
1050 if (pOptions->fObjRule && !fHeader)
1051 {
1052 if (pOptions->fNoObjectPath)
1053 fprintf(phDep, "%s.%s:", fileNameNoExt(pszFilename, szBuffer), pOptions->pszObjectExt);
1054 else
1055 fprintf(phDep, "%s%s.%s:",
1056 (*pOptions->pszObjectDir != '\0') ?
1057 pOptions->pszObjectDir : filePathSlash(pszFilename, szBuffer),
1058 fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH),
1059 pOptions->pszObjectExt);
1060
1061 if (pOptions->fSrcWhenObj)
1062 fprintf(phDep, " \\\n%4s %s", "", pszFilename);
1063 }
1064 else
1065 fprintf(phDep, "%s:", pszFilename);
1066
1067
1068 /*******************/
1069 /* find dependants */
1070 /*******************/
1071 iLine = 0;
1072 while (!feof(phFile)) /* line loop */
1073 {
1074 if (fgets(szBuffer, sizeof(szBuffer), phFile) != NULL)
1075 {
1076 /* search for #include */
1077 int cbLen;
1078 int i = 0;
1079 int i1, i2;
1080 iLine++;
1081
1082 /* check for comment mark (column 7) */
1083 if (szBuffer[6] == '*')
1084 continue;
1085
1086 /* skip blank chars */
1087 cbLen = strlen(szBuffer);
1088 while (i + 9 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t'))
1089 i++;
1090
1091 /* is this an include? */
1092 if ( (i1 = strnicmp(&szBuffer[i], "COPY", 4)) == 0
1093 || (i2 = strnicmpwords(&szBuffer[i], "EXEC SQL INCLUDE", 16)) == 0
1094 )
1095 {
1096 char szFullname[CCHMAXPATH];
1097 char *psz;
1098 int j;
1099
1100 /* skip statement */
1101 i += 4;
1102 if (i1 != 0)
1103 {
1104 int y = 2; /* skip two words */
1105 do
1106 {
1107 /* skip blanks */
1108 while (szBuffer[i] == ' ' || szBuffer[i] == '\t')
1109 i++;
1110 /* skip word */
1111 while (szBuffer[i] != ' ' && szBuffer[i] != '\t'
1112 && szBuffer[i] != '\0' && szBuffer[i] != '\n')
1113 i++;
1114 y--;
1115 } while (y > 0);
1116 }
1117
1118 /* check for blank */
1119 if (szBuffer[i] != ' ' && szBuffer[i] != '\t') /* no copybook specified... */
1120 continue;
1121
1122 /* skip blanks */
1123 while (szBuffer[i] == ' ' || szBuffer[i] == '\t')
1124 i++;
1125
1126 /* if invalid statement then continue with the next line! */
1127 if (szBuffer[i] == '\0' || szBuffer[i] == '\n')
1128 continue;
1129
1130 /* find end */
1131 j = 0;
1132 while (i + j < cbLen && j < CCHMAXPATH
1133 && szBuffer[i+j] != '.'
1134 && szBuffer[i+j] != ' ' && szBuffer[i+j] != '\t'
1135 && szBuffer[i+j] != '\0' && szBuffer[i+j] != '\n'
1136 )
1137 j++;
1138
1139 /* if invalid statement then continue with the next line! */
1140 if (szBuffer[i+j] != '.' && szBuffer[i+j] != ' ' && szBuffer[i] != '\t')
1141 continue;
1142
1143 /* copy filename */
1144 strncpy(szFullname, &szBuffer[i], j);
1145 szFullname[j] = '\0'; /* ensure terminatition. */
1146
1147 /* add extention .cpy - hardcoded for the moment. */
1148 strcat(szFullname, ".cpy");
1149
1150 /* find include file! */
1151 psz = pathlistFindFile(pOptions->pszInclude, szFullname, szBuffer);
1152
1153 /* did we find the include? */
1154 if (psz != NULL)
1155 {
1156 char szBuffer2[CCHMAXPATH];
1157 if (pOptions->fExcludeAll ||
1158 pathlistFindFile(pOptions->pszExclude, szFullname, szBuffer2) != NULL
1159 )
1160 strcpy(szBuffer, szFullname);
1161 fprintf(phDep, " \\\n%4.s %s", "", szBuffer);
1162 }
1163 else
1164 fprintf(stderr, "%s(%d): warning include file '%s' not found!\n",
1165 pszFilename, iLine, szFullname);
1166 }
1167 }
1168 else
1169 break;
1170 } /*while*/
1171 fputs("\n", phDep);
1172
1173 return 0;
1174}
1175
1176#define upcase(ch) \
1177 (ch >= 'a' && ch <= 'z' ? ch - ('a' - 'A') : ch)
1178
1179/**
1180 * Compares words. Multiple spaces are treates as on single blank i both string when comparing them.
1181 * @returns 0 equal. (same as strnicmp)
1182 * @param pszS1 String 1
1183 * @param pszS2 String 2
1184 * @param cch Length to compare (relative to string 1)
1185 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
1186 */
1187static int strnicmpwords(const char *pszS1, const char *pszS2, int cch)
1188{
1189 do
1190 {
1191 while (cch > 0 && upcase(*pszS1) == upcase(*pszS2) && *pszS1 != ' ')
1192 pszS1++, pszS2++, cch--;
1193
1194 /* blank test and skipping */
1195 if (cch > 0 && *pszS1 == ' ' && *pszS2 == ' ')
1196 {
1197 while (cch > 0 && *pszS1 == ' ')
1198 pszS1++, cch--;
1199
1200 while (*pszS2 == ' ')
1201 pszS2++;
1202 }
1203 else
1204 break;
1205 } while (cch > 0);
1206
1207 return cch == 0 ? 0 : *pszS1 - *pszS2;
1208}
1209
1210/**
1211 * Copies the path part (excluding the slash) into pszBuffer and returns
1212 * a pointer to the buffer.
1213 * If no path is found "" is returned.
1214 * @returns Pointer to pszBuffer with path.
1215 * @param pszFilename Pointer to readonly filename.
1216 * @param pszBuffer Pointer to output Buffer.
1217 * @status completely implemented.
1218 * @author knut st. osmundsen
1219 */
1220char *filePath(const char *pszFilename, char *pszBuffer)
1221{
1222 char *psz = strrchr(pszFilename, '\\');
1223 if (psz == NULL)
1224 psz = strrchr(pszFilename, '/');
1225
1226 if (psz == NULL)
1227 *pszBuffer = '\0';
1228 else
1229 {
1230 strncpy(pszBuffer, pszFilename, psz - pszFilename - 1);
1231 pszBuffer[psz - pszFilename - 1] = '\0';
1232 }
1233
1234 return pszBuffer;
1235}
1236
1237
1238/**
1239 * Copies the path part including the slash into pszBuffer and returns
1240 * a pointer to the buffer.
1241 * If no path is found "" is returned.
1242 * @returns Pointer to pszBuffer with path.
1243 * @param pszFilename Pointer to readonly filename.
1244 * @param pszBuffer Pointer to output Buffer.
1245 * @status completely implemented.
1246 * @author knut st. osmundsen
1247 */
1248char *filePathSlash(const char *pszFilename, char *pszBuffer)
1249{
1250 char *psz = strrchr(pszFilename, '\\');
1251 if (psz == NULL)
1252 psz = strrchr(pszFilename, '/');
1253
1254 if (psz == NULL)
1255 *pszBuffer = '\0';
1256 else
1257 {
1258 strncpy(pszBuffer, pszFilename, psz - pszFilename + 1);
1259 pszBuffer[psz - pszFilename + 1] = '\0';
1260 }
1261
1262 return pszBuffer;
1263}
1264
1265
1266/**
1267 * Copies the path name (with extention) into pszBuffer and returns
1268 * a pointer to the buffer.
1269 * If no path is found "" is returned.
1270 * @returns Pointer to pszBuffer with path.
1271 * @param pszFilename Pointer to readonly filename.
1272 * @param pszBuffer Pointer to output Buffer.
1273 * @status completely implemented.
1274 * @author knut st. osmundsen
1275 */
1276char *fileName(const char *pszFilename, char *pszBuffer)
1277{
1278 char *psz = strrchr(pszFilename, '\\');
1279 if (psz == NULL)
1280 psz = strrchr(pszFilename, '/');
1281
1282 strcpy(pszBuffer, psz == NULL ? pszFilename : psz + 1);
1283
1284 return pszBuffer;
1285}
1286
1287
1288/**
1289 * Copies the name part with out extention into pszBuffer and returns
1290 * a pointer to the buffer.
1291 * If no name is found "" is returned.
1292 * @returns Pointer to pszBuffer with path.
1293 * @param pszFilename Pointer to readonly filename.
1294 * @param pszBuffer Pointer to output Buffer.
1295 * @status completely implemented.
1296 * @author knut st. osmundsen
1297 */
1298char *fileNameNoExt(const char *pszFilename, char *pszBuffer)
1299{
1300 char *psz = strrchr(pszFilename, '\\');
1301 if (psz == NULL)
1302 psz = strrchr(pszFilename, '/');
1303
1304 strcpy(pszBuffer, psz == NULL ? pszFilename : psz + 1);
1305
1306 psz = strrchr(pszBuffer, '.');
1307 if (psz > pszBuffer) /* an extetion on it's own (.depend) is a filename not an extetion! */
1308 *psz = '\0';
1309
1310 return pszBuffer;
1311}
1312
1313
1314/**
1315 * Copies the extention part into pszBuffer and returns
1316 * a pointer to the buffer.
1317 * If no extention is found "" is returned.
1318 * The dot ('.') is not included!
1319 * @returns Pointer to pszBuffer with path.
1320 * @param pszFilename Pointer to readonly filename.
1321 * @param pszBuffer Pointer to output Buffer.
1322 * @status completely implemented.
1323 * @author knut st. osmundsen
1324 */
1325char *fileExt(const char *pszFilename, char *pszBuffer)
1326{
1327 char *psz = strrchr(pszFilename, '.');
1328 if (psz != NULL)
1329 {
1330 if (strchr(psz, '\\') != NULL || strchr(psz, '/') != NULL)
1331 *pszBuffer = '\0';
1332 else
1333 strcpy(pszBuffer, psz + 1);
1334 }
1335 else
1336 *pszBuffer = '\0';
1337
1338 return pszBuffer;
1339}
1340
1341
1342
1343
1344/**
1345 * Finds a filename in a specified pathlist.
1346 * @returns Pointer to a filename consiting of the path part + the given filename.
1347 * (pointer into pszBuffer)
1348 * NULL if file is not found. ("" in buffer)
1349 * @param pszPathList Path list to search for filename.
1350 * @parma pszFilename Filename to find.
1351 * @parma pszBuffer Ouput Buffer.
1352 * @status completely implemented.
1353 * @author knut st. osmundsen
1354 */
1355char *pathlistFindFile(const char *pszPathList, const char *pszFilename, char *pszBuffer)
1356{
1357 const char *psz = pszPathList;
1358 const char *pszNext = NULL;
1359
1360 *pszBuffer = '\0';
1361
1362 if (pszPathList == NULL)
1363 return NULL;
1364
1365 while (*psz != '\0')
1366 {
1367 /* find end of this path */
1368 pszNext = strchr(psz, ';');
1369 if (pszNext == NULL)
1370 pszNext = psz + strlen(psz);
1371
1372 if (pszNext - psz > 0)
1373 {
1374 HDIR hDir = HDIR_CREATE;
1375 ULONG cFiles = 1UL;
1376 FILEFINDBUF3 FileFindBuf;
1377 APIRET rc;
1378 char szFile[CCHMAXPATH];
1379
1380 /* make search statment */
1381 strncpy(szFile, psz, pszNext - psz);
1382 szFile[pszNext - psz] = '\0';
1383 if (szFile[pszNext - psz - 1] != '\\' && szFile[pszNext - psz - 1] != '/')
1384 strcpy(&szFile[pszNext - psz], "\\");
1385 strcat(szFile, pszFilename);
1386
1387 /* search for file */
1388 rc = DosFindFirst(szFile, &hDir, FILE_NORMAL, &FileFindBuf, sizeof(FileFindBuf),
1389 &cFiles, FIL_STANDARD);
1390 DosFindClose(hDir);
1391 if (rc == NO_ERROR)
1392 {
1393 strncpy(pszBuffer, psz, pszNext - psz);
1394 pszBuffer[pszNext - psz] = '\0';
1395 if (pszBuffer[pszNext - psz - 1] != '\\' && pszBuffer[pszNext - psz - 1] != '/')
1396 strcpy(&pszBuffer[pszNext - psz], "\\");
1397 strcat(pszBuffer, pszFilename);
1398 break;
1399 }
1400 }
1401
1402 /* next */
1403 if (*pszNext != ';')
1404 break;
1405 psz = pszNext + 1;
1406 }
1407
1408 return *pszBuffer == '\0' ? NULL : pszBuffer;
1409}
1410
1411
1412/**
1413 * Finds the first char after word.
1414 * @returns Pointer to the first char after word.
1415 * @param psz Where to start.
1416 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
1417 */
1418static char *findEndOfWord(char *psz)
1419{
1420
1421 while (*psz != '\0' &&
1422 (
1423 (*psz >= 'A' && *psz <= 'Z') || (*psz >= 'a' && *psz <= 'z')
1424 ||
1425 (*psz >= '0' && *psz <= '9')
1426 ||
1427 *psz == '_'
1428 )
1429 )
1430 ++psz;
1431 return (char *)psz;
1432}
1433
1434#if 0 /* not used */
1435/**
1436 * Find the starting char of a word
1437 * @returns Pointer to first char in word.
1438 * @param psz Where to start.
1439 * @param pszStart Where to stop.
1440 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
1441 */
1442static char *findStartOfWord(const char *psz, const char *pszStart)
1443{
1444 const char *pszR = psz;
1445 while (psz >= pszStart &&
1446 (
1447 (*psz >= 'A' && *psz <= 'Z')
1448 || (*psz >= 'a' && *psz <= 'z')
1449 || (*psz >= '0' && *psz <= '9')
1450 || *psz == '_'
1451 )
1452 )
1453 pszR = psz--;
1454 return (char*)pszR;
1455}
1456#endif
1457
1458/*
1459 * Testin purpose.
1460 */
1461#include <os2.h>
1462
Note: See TracBrowser for help on using the repository browser.