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

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

Multiple languages are supported by the utility:

C and C++, Assembly, Resource Files and COBOL source.

File size: 39.1 KB
Line 
1/* $Id: fastdep.c,v 1.3 2000-02-29 10:48:10 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 <stdlib.h>
24#include <string.h>
25
26
27/*******************************************************************************
28* Structures and Typedefs *
29*******************************************************************************/
30typedef struct _Options
31{
32 const char * pszInclude;
33 const char * pszExclude;
34 BOOL fExcludeAll;
35 const char * pszObjectExt;
36 const char * pszObjectDir;
37 const char * pszRsrcExt;
38 BOOL fObjRule;
39 BOOL fNoObjectPath;
40 BOOL fSrcWhenObj;
41 BOOL fAppend; /* append to the output file, not overwrite it. */
42} OPTIONS, *POPTIONS;
43
44
45/*
46 * Language specific analysis functions type.
47 */
48typedef int ( _FNLANG) (FILE *phDep, const char *pszFilename, FILE *phFile,
49 BOOL fHeader, POPTIONS pOptions);
50typedef _FNLANG *PFNLANG;
51
52
53/**
54 * This struct holds the static configuration of the util.
55 */
56typedef struct _ConfigEntry
57{
58 const char **papszExts; /* Pointer to an array of pointer to extentions for this handler. */
59 /* If NULL this is the last entry. */
60 int iFirstHdr; /* Index into the papszExts array of the first headerfile/copybook. */
61 /* Set it to the NULL element of the array if no headers for this extention. */
62 /* A non-header file may get a object rule. */
63 PFNLANG pfn; /* Pointer to handler function. */
64} CONFIGENTRY, *PCONFIGENTRY;
65
66
67/*******************************************************************************
68* Internal Functions *
69*******************************************************************************/
70static void syntax(void);
71static int makeDependent(FILE *phDep, const char *pszFilename, POPTIONS pOptions);
72
73int langC_CPP(FILE *phDep, const char *pszFilename, FILE *phFile, BOOL fHeader, POPTIONS pOptions);
74int langAsm(FILE *phDep, const char *pszFilename, FILE *phFile, BOOL fHeader, POPTIONS pOptions);
75int langRC(FILE *phDep, const char *pszFilename, FILE *phFile, BOOL fHeader, POPTIONS pOptions);
76int langCOBOL(FILE *phDep, const char *pszFilename, FILE *phFile, BOOL fHeader, POPTIONS pOptions);
77
78
79/* string operations */
80static int strnicmpwords(const char *pszS1, const char *pszS2, int cch);
81
82/* file operations */
83char *filePath(const char *pszFilename, char *pszBuffer);
84char *filePathSlash(const char *pszFilename, char *pszBuffer);
85char *fileName(const char *pszFilename, char *pszBuffer);
86char *fileNameNoExt(const char *pszFilename, char *pszBuffer);
87char *fileExt(const char *pszFilename, char *pszBuffer);
88
89/* pathlist operations */
90char *pathlistFindFile(const char *pszPathList, const char *pszFilename, char *pszBuffer);
91
92
93/*******************************************************************************
94* Global Variables *
95*******************************************************************************/
96static const char pszDefaultDepFile[] = ".depend";
97static const char *apszExtC_CPP[] = {"c", "sqc", "cpp", "h", "hpp", NULL};
98static const char *apszExtAsm[] = {"asm", "inc", NULL};
99static const char *apszExtRC[] = {"rc", "dlg", NULL};
100static const char *apszExtCOBOL[] = {"cbl", "cob", "sqb", NULL};
101
102static CONFIGENTRY aConfig[] =
103{
104 {
105 apszExtC_CPP,
106 3,
107 langC_CPP,
108 },
109
110 {
111 apszExtAsm,
112 1,
113 langAsm,
114 },
115
116 {
117 apszExtRC,
118 1,
119 langRC,
120 },
121
122 {
123 apszExtCOBOL,
124 3,
125 langCOBOL,
126 },
127
128 /* terminating entry */
129 {
130 NULL,
131 -1,
132 NULL
133 }
134};
135
136
137/**
138 * Main function.
139 * @returns 0 on success.
140 * -n count of failiures.
141 * @param
142 * @param
143 * @equiv
144 * @precond
145 * @methdesc
146 * @result
147 * @time
148 * @sketch
149 * @algo
150 * @remark
151 */
152int main(int argc, char **argv)
153{
154 FILE *phDep = NULL;
155 int rc = 0;
156 int argi = 1;
157 const char *pszDepFile = pszDefaultDepFile;
158
159 static char szObjectDir[CCHMAXPATH];
160 static char szObjectExt[64] = "obj";
161 static char szRsrcExt[64] = "res";
162 static char szInclude[32768] = ";";
163 static char szExclude[32768] = ";";
164
165 OPTIONS options =
166 {
167 szInclude, /* pszInclude */
168 szExclude, /* pszExclude */
169 FALSE, /* fExcludeAll */
170 szObjectExt, /* pszObjectExt */
171 szObjectDir, /* pszObjectDir */
172 szRsrcExt, /* pszRsrcExt */
173 TRUE, /* fObjRule */
174 FALSE, /* fNoObjectPath */
175 TRUE, /* fSrcWhenObj */
176 FALSE /* fAppend */
177 };
178
179 szObjectDir[0] = '\0';
180
181 if (argc == 1)
182 {
183 syntax();
184 return -87;
185 }
186
187 while (argi < argc)
188 {
189 if (argv[argi][0] == '-' || argv[argi][0] == '/')
190 {
191 /* parameters */
192 switch (argv[argi][1])
193 {
194 case 'A':
195 case 'a': /* Append to the output file */
196 options.fAppend = argv[argi][2] != '-';
197 break;
198
199 case 'D':
200 case 'd': /* "-d <filename>" */
201 if (argv[argi][2] != '\0')
202 pszDepFile = &argv[argi][2];
203 else
204 {
205 if (argi + 1 < argc)
206 pszDepFile = argv[++argi];
207 else
208 {
209 fprintf(stderr, "invalid parameter -d, filename missing!\n");
210 return -1;
211 }
212 }
213 if (phDep != NULL)
214 {
215 fclose(phDep);
216 phDep = NULL;
217 }
218 break;
219
220 case 'E': /* list of paths. If a file is found in one of these directories the */
221 case 'e': /* filename will be used without the directory path. */
222 /* Eall<[+]|-> ? */
223 if (strlen(&argv[argi][1]) <= 5 && strnicmp(&argv[argi][1], "Eall", 4) == 0)
224 {
225 options.fExcludeAll = argv[argi][5] != '-';
226 break;
227 }
228 /* path or path list */
229 if (strlen(argv[argi]) > 2)
230 strcat(szExclude, &argv[argi][2]);
231 else
232 {
233 strcat(szExclude, argv[argi+1]);
234 argi++;
235 }
236 if (szExclude[strlen(szExclude)-1] != ';')
237 strcat(szExclude, ";");
238 break;
239
240 case 'I': /* optional include path. This has precedence over the INCLUDE environment variable. */
241 case 'i':
242 if (strlen(argv[argi]) > 2)
243 strcat(szInclude, &argv[argi][2]);
244 else
245 {
246 strcat(szInclude, argv[argi+1]);
247 argi++;
248 }
249 if (szInclude[strlen(szInclude)-1] != ';')
250 strcat(szInclude, ";");
251 break;
252
253 case 'n': /* no object path , -N<[+]|-> */
254 case 'N':
255 if (strlen(argv[argi]) <= 1+1+1)
256 options.fNoObjectPath = argv[argi][2] != '-';
257 else
258 {
259 fprintf(stderr, "error: invalid parameter!, '%s'\n", argv[argi]);
260 return -1;
261 }
262 break;
263
264 case 'o': /* object base directory, Obj or Obr<[+]|-> */
265 case 'O':
266 if (strlen(&argv[argi][1]) <= 4 && strnicmp(&argv[argi][1], "Obr", 3) == 0)
267 {
268 options.fObjRule = argv[argi][4] != '-';
269 break;
270 }
271
272 if (strlen(&argv[argi][1]) >= 4 && strnicmp(&argv[argi][1], "Obj", 3) == 0)
273 {
274 if (strlen(argv[argi]) > 4)
275 strcpy(szObjectExt, argv[argi]+4);
276 else
277 {
278 strcpy(szObjectExt, argv[argi+1]);
279 argi++;
280 }
281 break;
282 }
283
284 /* path */
285 if (strlen(argv[argi]) > 2)
286 strcpy(szObjectDir, argv[argi]+2);
287 else
288 {
289 strcpy(szObjectDir, argv[argi+1]);
290 argi++;
291 }
292 if (szObjectDir[strlen(szObjectDir)-1] != '\\'
293 && szObjectDir[strlen(szObjectDir)-1] != '/'
294 )
295 strcat(szObjectDir, "\\");
296 break;
297
298 case 'r':
299 case 'R':
300 if (strlen(argv[argi]) > 2)
301 strcpy(szObjectExt, argv[argi]+2);
302 else
303 {
304 strcpy(szObjectExt, argv[argi+1]);
305 argi++;
306 }
307 break;
308
309 case 'h':
310 case 'H':
311 case '?':
312 syntax();
313 return 1;
314
315 default:
316 fprintf(stderr, "error: invalid parameter! '%s'\n", argv[argi]);
317 return -1;
318 }
319
320 }
321 else
322 { /* not a parameter! */
323 ULONG ulRc;
324 FILEFINDBUF3 filebuf;
325 HDIR hDir = HDIR_CREATE;
326 ULONG ulFound = 1;
327
328 memset(&filebuf, 0, sizeof(filebuf));
329
330 /*
331 * Open output file.
332 */
333 if (phDep == NULL)
334 {
335 phDep = fopen(pszDepFile, options.fAppend ? "a" : "w");
336 if (phDep == NULL)
337 {
338 fprintf(stderr, "error opening outputfile '%s'.\n", pszDepFile);
339 return 1;
340 }
341 }
342
343 /*
344 * Search for the files specified.
345 */
346 ulRc = DosFindFirst(argv[argi], &hDir,
347 FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_ARCHIVED,
348 &filebuf, sizeof(FILEFINDBUF3), &ulFound, FIL_STANDARD);
349 while (ulRc == NO_ERROR)
350 {
351 char *psz;
352 char szSource[CCHMAXPATH];
353
354 /*
355 * Make full path.
356 */
357 if ((psz = strrchr(argv[argi], '\\')) || (psz = strrchr(argv[argi], '/')))
358 {
359 strncpy(szSource, argv[argi], psz - argv[argi] + 1);
360 szSource[psz - argv[argi] + 1] = '\0';
361 }
362 else
363 szSource[0] = '\0';
364 strcat(szSource, filebuf.achName);
365
366 /*
367 * Analyse the file.
368 */
369 rc -= makeDependent(phDep, &szSource[0], &options);
370
371 /* next file */
372 ulRc = DosFindNext(hDir, &filebuf, sizeof(filebuf), &ulFound);
373 }
374 DosFindClose(hDir);
375 }
376 /* next */
377 argi++;
378 }
379
380 return rc;
381}
382
383
384/**
385 * Displays the syntax description for this util.
386 * @status completely implemented.
387 * @author knut st. osmundsen
388 */
389static void syntax(void)
390{
391 printf(
392 "FastDep v0.1\n"
393 "Quick and dirty dependant scanner. Creates a makefile readable depend file.\n"
394 "\n"
395 "Syntax: FastDep [-a<[+]|->] [-d <outputfn>] [-e <excludepath>] [-eall<[+]|->]\n"
396 " [-i <include>] [-n<[+]|->] [-o <objdir>] [-obr<[+]|->] <files>\n"
397 "\n"
398 " -a<[+]|-> Append to the output file. Default: Overwrite.\n"
399 " -d <outputfn> Output filename. Default: %s\n"
400 " -e excludepath Exclude paths. If a filename is found in any\n"
401 " of these paths only the filename is used, not\n"
402 " the path+filename (which is default).\n"
403 " -eall<[+]|-> -eall+: No path are added to the filename.\n"
404 " -eall-: The filename is appended the include path\n"
405 " was found in.\n"
406 " Default: eall-\n"
407 " -i <include> Additional include paths. INCLUDE is searched after this.\n"
408 " -n<[+]|-> No path for object files in the rules.\n"
409 " -o <objdir> Path were object files are placed. This path replaces the\n"
410 " entire filename path\n"
411 " -obr<[+]|-> -obr+: Object rule.\n"
412 " -obr-: No object rule, rule for source filename is generated.\n"
413 " -obj[ ]<objext> Object extention. Default: obj\n"
414 " -r[ ]<rsrcext> Resource binary extention. Default: res\n"
415 " <files> Files to scan. Wildchars are allowed.\n"
416 "\n",
417 pszDefaultDepFile
418 );
419}
420
421
422/**
423 * Generates depend info on this file, and fwrites it to phDep.
424 * @returns
425 * @param phDep Pointer to file struct for outfile.
426 * @param pszFilename Pointer to source filename.
427 * @param pOptions Pointer to options struct.
428 * @status completely implemented.
429 * @author knut st. osmundsen
430 */
431static int makeDependent(FILE *phDep, const char *pszFilename, POPTIONS pOptions)
432{
433 int rc = -1;
434 FILE *phFile;
435
436 phFile = fopen(pszFilename, "r");
437 if (phFile != NULL)
438 {
439 char szExt[CCHMAXPATH];
440 PCONFIGENTRY pCfg = &aConfig[0];
441 BOOL fHeader;
442
443 /*
444 * Find which filetype this is...
445 */
446 fileExt(pszFilename, szExt);
447 while (pCfg->papszExts != NULL)
448 {
449 const char **ppsz = pCfg->papszExts;
450 while (*ppsz != NULL && stricmp(*ppsz, szExt) != 0)
451 ppsz++;
452 if (*ppsz != NULL)
453 {
454 fHeader = &pCfg->papszExts[pCfg->iFirstHdr] <= ppsz;
455 break;
456 }
457 pCfg++;
458 }
459
460 /* Found? */
461 if (pCfg->papszExts != NULL)
462 rc = (*pCfg->pfn)(phDep, pszFilename, phFile, fHeader, pOptions);
463 else
464 {
465 if (*fileName(pszFilename, szExt) != '.') /* these are 'hidden' files, like .cvsignore, let's ignore them. */
466 fprintf(stderr, "warning: '%s' has an unknown file type.\n", pszFilename);
467 rc = 0;
468 }
469
470 fputs("\n", phDep);
471 fclose(phFile);
472 }
473 else
474 fprintf(stderr, "failed to open '%s'\n", pszFilename);
475
476 return rc;
477}
478
479
480/**
481 * Generates depend info on this C or C++ file, and writes it to phDep.
482 * @returns 0 on success.
483 * !0 on error.
484 * @param phDep Pointer to file struct for outfile.
485 * @param pszFilename Pointer to source filename.
486 * @param phFile Pointer to source file handle.
487 * @param pOptions Pointer to options struct.
488 * @status completely implemented.
489 * @author knut st. osmundsen
490 */
491int langC_CPP(FILE *phDep, const char *pszFilename, FILE *phFile, BOOL fHeader, POPTIONS pOptions)
492{
493 char szBuffer[4096]; /* max line length */
494 int iLine;
495
496
497 /**********************************/
498 /* print file name to depend file */
499 /**********************************/
500 if (pOptions->fObjRule && !fHeader)
501 {
502 if (pOptions->fNoObjectPath)
503 fprintf(phDep, "%s.%s:", fileNameNoExt(pszFilename, szBuffer), pOptions->pszObjectExt);
504 else
505 fprintf(phDep, "%s%s.%s:",
506 (*pOptions->pszObjectDir != '\0') ?
507 pOptions->pszObjectDir : filePathSlash(pszFilename, szBuffer),
508 fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH),
509 pOptions->pszObjectExt);
510
511 if (pOptions->fSrcWhenObj)
512 fprintf(phDep, " \\\n%4s %s", "", pszFilename);
513 }
514 else
515 fprintf(phDep, "%s:", pszFilename);
516
517
518 /*******************/
519 /* find dependants */
520 /*******************/
521 iLine = 0;
522 while (!feof(phFile)) /* line loop */
523 {
524 if (fgets(szBuffer, sizeof(szBuffer), phFile) != NULL)
525 {
526 /* search for #include */
527 int cbLen;
528 int i = 0;
529 iLine++;
530
531 /* skip blank chars */
532 cbLen = strlen(szBuffer);
533 while (i + 9 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t'))
534 i++;
535
536 /* is this an include? */
537 if (szBuffer[i] == '#' && strncmp(&szBuffer[i], "#include", 8) == 0)
538 {
539 char szFullname[CCHMAXPATH];
540 char *psz;
541 BOOL f = FALSE;
542 int j;
543
544 /* extract info between "" or <> */
545 while (i < cbLen && !(f = (szBuffer[i] == '"' || szBuffer[i] == '<')))
546 i++;
547 i++; /* skip '"' or '<' */
548
549 /* if invalid statement then continue with the next line! */
550 if (!f) continue;
551
552 /* find end */
553 j = f = 0;
554 while (i + j < cbLen && j < CCHMAXPATH &&
555 !(f = (szBuffer[i+j] == '"' || szBuffer[i+j] == '>')))
556 j++;
557
558 /* if invalid statement then continue with the next line! */
559 if (!f) continue;
560
561 /* copy filename */
562 strncpy(szFullname, &szBuffer[i], j);
563 szFullname[j] = '\0'; /* ensure terminatition. */
564
565 /* find include file! */
566 psz = pathlistFindFile(pOptions->pszInclude, szFullname, szBuffer);
567 if (psz == NULL)
568 psz = pathlistFindFile(getenv("INCLUDE"), szFullname, szBuffer);
569
570 /* did we find the include? */
571 if (psz != NULL)
572 {
573 char szBuffer2[CCHMAXPATH];
574 if (pOptions->fExcludeAll ||
575 pathlistFindFile(pOptions->pszExclude, szFullname, szBuffer2) != NULL
576 )
577 strcpy(szBuffer, szFullname);
578 fprintf(phDep, " \\\n%4.s %s", "", szBuffer);
579 }
580 else
581 fprintf(stderr, "%s(%d): warning include file '%s' not found!\n",
582 pszFilename, iLine, szFullname);
583 }
584 }
585 else
586 break;
587 } /*while*/
588 fputs("\n", phDep);
589
590 return 0;
591}
592
593
594/**
595 * Generates depend info on this file, and fwrites it to phDep.
596 * @returns 0 on success.
597 * !0 on error.
598 * @param phDep Pointer to file struct for outfile.
599 * @param pszFilename Pointer to source filename.
600 * @param phFile Pointer to source file handle.
601 * @param pOptions Pointer to options struct.
602 * @status completely implemented.
603 * @author knut st. osmundsen
604 */
605int langAsm(FILE *phDep, const char *pszFilename, FILE *phFile, BOOL fHeader, POPTIONS pOptions)
606{
607 char szBuffer[4096]; /* max line length */
608 int iLine;
609
610
611 /**********************************/
612 /* print file name to depend file */
613 /**********************************/
614 if (pOptions->fObjRule && !fHeader)
615 {
616 if (pOptions->fNoObjectPath)
617 fprintf(phDep, "%s.%s:", fileNameNoExt(pszFilename, szBuffer), pOptions->pszObjectExt);
618 else
619 fprintf(phDep, "%s%s.%s:",
620 (*pOptions->pszObjectDir != '\0') ?
621 pOptions->pszObjectDir : filePathSlash(pszFilename, szBuffer),
622 fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH),
623 pOptions->pszObjectExt);
624
625 if (pOptions->fSrcWhenObj)
626 fprintf(phDep, " \\\n%4s %s", "", pszFilename);
627 }
628 else
629 fprintf(phDep, "%s:", pszFilename);
630
631
632 /*******************/
633 /* find dependants */
634 /*******************/
635 iLine = 0;
636 while (!feof(phFile)) /* line loop */
637 {
638 if (fgets(szBuffer, sizeof(szBuffer), phFile) != NULL)
639 {
640 /* search for include */
641 int cbLen;
642 int i = 0;
643 iLine++;
644
645 /* skip blank chars */
646 cbLen = strlen(szBuffer);
647 while (i + 9 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t'))
648 i++;
649
650 /* is this an include? */
651 if (strnicmp(&szBuffer[i], "include", 7) == 0
652 && (szBuffer[i + 7] == '\t' || szBuffer[i + 7] == ' ')
653 )
654 {
655 char szFullname[CCHMAXPATH];
656 char *psz;
657 int j;
658
659 /* skip to first no blank char */
660 i += 7;
661 while (i < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t'))
662 i++;
663
664 /* comment check - if comment found, no filename was given. continue. */
665 if (szBuffer[i] == ';') continue;
666
667 /* find end */
668 j = 0;
669 while (i + j < cbLen
670 && j < CCHMAXPATH
671 && szBuffer[i+j] != ' ' && szBuffer[i+j] != '\t' && szBuffer[i+j] != '\n'
672 && szBuffer[i+j] != '\0' && szBuffer[i+j] != ';' && szBuffer[i+j] != '\r'
673 )
674 j++;
675
676 /* copy filename */
677 strncpy(szFullname, &szBuffer[i], j);
678 szFullname[j] = '\0'; /* ensure terminatition. */
679
680 /* find include file! */
681 psz = pathlistFindFile(pOptions->pszInclude, szFullname, szBuffer);
682 if (psz == NULL)
683 psz = pathlistFindFile(getenv("INCLUDE"), szFullname, szBuffer);
684
685 /* Did we find the include? */
686 if (psz != NULL)
687 {
688 char szBuffer2[CCHMAXPATH];
689 if (pOptions->fExcludeAll ||
690 pathlistFindFile(pOptions->pszExclude, szFullname, szBuffer2) != NULL
691 )
692 strcpy(szBuffer, szFullname);
693 fprintf(phDep, " \\\n%4.s %s", "", szBuffer);
694 }
695 else
696 fprintf(stderr, "%s(%d): warning include file '%s' not found!\n",
697 pszFilename, iLine, szFullname);
698 }
699 }
700 else
701 break;
702 } /*while*/
703 fputs("\n", phDep);
704
705 return 0;
706}
707
708
709/**
710 * Generates depend info on this Resource file, and writes it to phDep.
711 * @returns 0 on success.
712 * !0 on error.
713 * @param phDep Pointer to file struct for outfile.
714 * @param pszFilename Pointer to source filename.
715 * @param phFile Pointer to source file handle.
716 * @param pOptions Pointer to options struct.
717 * @status completely implemented.
718 * @author knut st. osmundsen
719 */
720int langRC(FILE *phDep, const char *pszFilename, FILE *phFile, BOOL fHeader, POPTIONS pOptions)
721{
722 char szBuffer[4096]; /* max line length */
723 int iLine;
724
725 /**********************************/
726 /* print file name to depend file */
727 /**********************************/
728 if (pOptions->fObjRule && !fHeader)
729 {
730 if (pOptions->fNoObjectPath)
731 fprintf(phDep, "%s.%s:", fileNameNoExt(pszFilename, szBuffer), pOptions->pszRsrcExt);
732 else
733 fprintf(phDep, "%s%s.res:",
734 (*pOptions->pszObjectDir != '\0') ?
735 pOptions->pszObjectDir : filePathSlash(pszFilename, szBuffer),
736 fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH),
737 pOptions->pszRsrcExt);
738
739 if (pOptions->fSrcWhenObj)
740 fprintf(phDep, " \\\n%4s %s", "", pszFilename);
741 }
742 else
743 fprintf(phDep, "%s:", pszFilename);
744
745
746 /*******************/
747 /* find dependants */
748 /*******************/
749 iLine = 0;
750 while (!feof(phFile)) /* line loop */
751 {
752 if (fgets(szBuffer, sizeof(szBuffer), phFile) != NULL)
753 {
754 /* search for #include */
755 int cbLen;
756 int i = 0;
757 iLine++;
758
759 /* skip blank chars */
760 cbLen = strlen(szBuffer);
761 while (i + 9 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t'))
762 i++;
763
764 /* is this an include? */
765 if ( strncmp(&szBuffer[i], "#include", 8) == 0
766 || strncmp(&szBuffer[i], "RCINCLUDE", 9) == 0
767 || strncmp(&szBuffer[i], "DLGINCLUDE", 10) == 0
768 )
769 {
770 char szFullname[CCHMAXPATH];
771 char *psz;
772 BOOL f = FALSE;
773 int j;
774
775 /* extract info between "" or <> */
776 while (i < cbLen && !(f = (szBuffer[i] == '"' || szBuffer[i] == '<')))
777 i++;
778 i++; /* skip '"' or '<' */
779
780 /* if invalid statement then continue with the next line! */
781 if (!f) continue;
782
783 /* find end */
784 j = f = 0;
785 while (i + j < cbLen && j < CCHMAXPATH &&
786 !(f = (szBuffer[i+j] == '"' || szBuffer[i+j] == '>')))
787 j++;
788
789 /* if invalid statement then continue with the next line! */
790 if (!f) continue;
791
792 /* copy filename */
793 strncpy(szFullname, &szBuffer[i], j);
794 szFullname[j] = '\0'; /* ensure terminatition. */
795
796 /* find include file! */
797 psz = pathlistFindFile(pOptions->pszInclude, szFullname, szBuffer);
798 if (psz == NULL)
799 psz = pathlistFindFile(getenv("INCLUDE"), szFullname, szBuffer);
800
801 /* did we find the include? */
802 if (psz != NULL)
803 {
804 char szBuffer2[CCHMAXPATH];
805 if (pOptions->fExcludeAll ||
806 pathlistFindFile(pOptions->pszExclude, szFullname, szBuffer2) != NULL
807 )
808 strcpy(szBuffer, szFullname);
809 fprintf(phDep, " \\\n%4.s %s", "", szBuffer);
810 }
811 else
812 fprintf(stderr, "%s(%d): warning include file '%s' not found!\n",
813 pszFilename, iLine, szFullname);
814 }
815 }
816 else
817 break;
818 } /*while*/
819 fputs("\n", phDep);
820
821 return 0;
822}
823
824
825/**
826 * Generates depend info on this COBOL file, and writes it to phDep.
827 * @returns 0 on success.
828 * !0 on error.
829 * @param phDep Pointer to file struct for outfile.
830 * @param pszFilename Pointer to source filename.
831 * @param phFile Pointer to source file handle.
832 * @param pOptions Pointer to options struct.
833 * @status completely implemented.
834 * @author knut st. osmundsen
835 */
836int langCOBOL(FILE *phDep, const char *pszFilename, FILE *phFile, BOOL fHeader, POPTIONS pOptions)
837{
838 char szBuffer[4096]; /* max line length */
839 int iLine;
840
841 /**********************************/
842 /* print file name to depend file */
843 /**********************************/
844 if (pOptions->fObjRule && !fHeader)
845 {
846 if (pOptions->fNoObjectPath)
847 fprintf(phDep, "%s.%s:", fileNameNoExt(pszFilename, szBuffer), pOptions->pszObjectExt);
848 else
849 fprintf(phDep, "%s%s.%s:",
850 (*pOptions->pszObjectDir != '\0') ?
851 pOptions->pszObjectDir : filePathSlash(pszFilename, szBuffer),
852 fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH),
853 pOptions->pszObjectExt);
854
855 if (pOptions->fSrcWhenObj)
856 fprintf(phDep, " \\\n%4s %s", "", pszFilename);
857 }
858 else
859 fprintf(phDep, "%s:", pszFilename);
860
861
862 /*******************/
863 /* find dependants */
864 /*******************/
865 iLine = 0;
866 while (!feof(phFile)) /* line loop */
867 {
868 if (fgets(szBuffer, sizeof(szBuffer), phFile) != NULL)
869 {
870 /* search for #include */
871 int cbLen;
872 int i = 0;
873 int i1, i2;
874 iLine++;
875
876 /* check for comment mark (column 7) */
877 if (szBuffer[6] == '*')
878 continue;
879
880 /* skip blank chars */
881 cbLen = strlen(szBuffer);
882 while (i + 9 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t'))
883 i++;
884
885 /* is this an include? */
886 if ( (i1 = strnicmp(&szBuffer[i], "COPY", 4)) == 0
887 || (i2 = strnicmpwords(&szBuffer[i], "EXEC SQL INCLUDE", 16)) == 0
888 )
889 {
890 char szFullname[CCHMAXPATH];
891 char *psz;
892 int j;
893
894 /* skip statement */
895 i += 4;
896 if (i1 != 0)
897 {
898 int y = 2; /* skip two words */
899 do
900 {
901 /* skip blanks */
902 while (szBuffer[i] == ' ' || szBuffer[i] == '\t')
903 i++;
904 /* skip word */
905 while (szBuffer[i] != ' ' && szBuffer[i] != '\t'
906 && szBuffer[i] != '\0' && szBuffer[i] != '\n')
907 i++;
908 y--;
909 } while (y > 0);
910 }
911
912 /* check for blank */
913 if (szBuffer[i] != ' ' && szBuffer[i] != '\t') /* no copybook specified... */
914 continue;
915
916 /* skip blanks */
917 while (szBuffer[i] == ' ' || szBuffer[i] == '\t')
918 i++;
919
920 /* if invalid statement then continue with the next line! */
921 if (szBuffer[i] == '\0' || szBuffer[i] == '\n')
922 continue;
923
924 /* find end */
925 j = 0;
926 while (i + j < cbLen && j < CCHMAXPATH
927 && szBuffer[i+j] != '.'
928 && szBuffer[i+j] != ' ' && szBuffer[i+j] != '\t'
929 && szBuffer[i+j] != '\0' && szBuffer[i+j] != '\n'
930 )
931 j++;
932
933 /* if invalid statement then continue with the next line! */
934 if (szBuffer[i+j] != '.' && szBuffer[i+j] != ' ' && szBuffer[i] != '\t')
935 continue;
936
937 /* copy filename */
938 strncpy(szFullname, &szBuffer[i], j);
939 szFullname[j] = '\0'; /* ensure terminatition. */
940
941 /* add extention .cpy - hardcoded for the moment. */
942 strcat(szFullname, ".cpy");
943
944 /* find include file! */
945 psz = pathlistFindFile(pOptions->pszInclude, szFullname, szBuffer);
946
947 /* did we find the include? */
948 if (psz != NULL)
949 {
950 char szBuffer2[CCHMAXPATH];
951 if (pOptions->fExcludeAll ||
952 pathlistFindFile(pOptions->pszExclude, szFullname, szBuffer2) != NULL
953 )
954 strcpy(szBuffer, szFullname);
955 fprintf(phDep, " \\\n%4.s %s", "", szBuffer);
956 }
957 else
958 fprintf(stderr, "%s(%d): warning include file '%s' not found!\n",
959 pszFilename, iLine, szFullname);
960 }
961 }
962 else
963 break;
964 } /*while*/
965 fputs("\n", phDep);
966
967 return 0;
968}
969
970#define upcase(ch) \
971 (ch >= 'a' && ch <= 'z' ? ch - ('a' - 'A') : ch)
972
973/**
974 * Compares words. Multiple spaces are treates as on single blank i both string when comparing them.
975 * @returns 0 equal. (same as strnicmp)
976 * @param pszS1 String 1
977 * @param pszS2 String 2
978 * @param cch Length to compare (relative to string 1)
979 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
980 */
981static int strnicmpwords(const char *pszS1, const char *pszS2, int cch)
982{
983 do
984 {
985 while (cch > 0 && upcase(*pszS1) == upcase(*pszS2) && *pszS1 != ' ')
986 pszS1++, pszS2++, cch--;
987
988 /* blank test and skipping */
989 if (cch > 0 && *pszS1 == ' ' && *pszS2 == ' ')
990 {
991 while (cch > 0 && *pszS1 == ' ')
992 pszS1++, cch--;
993
994 while (*pszS2 == ' ')
995 pszS2++;
996 }
997 else
998 break;
999 } while (cch > 0);
1000
1001 return cch == 0 ? 0 : *pszS1 - *pszS2;
1002}
1003
1004/**
1005 * Copies the path part (excluding the slash) into pszBuffer and returns
1006 * a pointer to the buffer.
1007 * If no path is found "" is returned.
1008 * @returns Pointer to pszBuffer with path.
1009 * @param pszFilename Pointer to readonly filename.
1010 * @param pszBuffer Pointer to output Buffer.
1011 * @status completely implemented.
1012 * @author knut st. osmundsen
1013 */
1014char *filePath(const char *pszFilename, char *pszBuffer)
1015{
1016 char *psz = strrchr(pszFilename, '\\');
1017 if (psz == NULL)
1018 psz = strrchr(pszFilename, '/');
1019
1020 if (psz == NULL)
1021 *pszBuffer = '\0';
1022 else
1023 {
1024 strncpy(pszBuffer, pszFilename, psz - pszFilename - 1);
1025 pszBuffer[psz - pszFilename - 1] = '\0';
1026 }
1027
1028 return pszBuffer;
1029}
1030
1031
1032/**
1033 * Copies the path part including the slash into pszBuffer and returns
1034 * a pointer to the buffer.
1035 * If no path is found "" is returned.
1036 * @returns Pointer to pszBuffer with path.
1037 * @param pszFilename Pointer to readonly filename.
1038 * @param pszBuffer Pointer to output Buffer.
1039 * @status completely implemented.
1040 * @author knut st. osmundsen
1041 */
1042char *filePathSlash(const char *pszFilename, char *pszBuffer)
1043{
1044 char *psz = strrchr(pszFilename, '\\');
1045 if (psz == NULL)
1046 psz = strrchr(pszFilename, '/');
1047
1048 if (psz == NULL)
1049 *pszBuffer = '\0';
1050 else
1051 {
1052 strncpy(pszBuffer, pszFilename, psz - pszFilename + 1);
1053 pszBuffer[psz - pszFilename + 1] = '\0';
1054 }
1055
1056 return pszBuffer;
1057}
1058
1059
1060/**
1061 * Copies the path name (with extention) into pszBuffer and returns
1062 * a pointer to the buffer.
1063 * If no path is found "" is returned.
1064 * @returns Pointer to pszBuffer with path.
1065 * @param pszFilename Pointer to readonly filename.
1066 * @param pszBuffer Pointer to output Buffer.
1067 * @status completely implemented.
1068 * @author knut st. osmundsen
1069 */
1070char *fileName(const char *pszFilename, char *pszBuffer)
1071{
1072 char *psz = strrchr(pszFilename, '\\');
1073 if (psz == NULL)
1074 psz = strrchr(pszFilename, '/');
1075
1076 strcpy(pszBuffer, psz == NULL ? pszFilename : psz + 1);
1077
1078 return pszBuffer;
1079}
1080
1081
1082/**
1083 * Copies the name part with out extention into pszBuffer and returns
1084 * a pointer to the buffer.
1085 * If no name is found "" is returned.
1086 * @returns Pointer to pszBuffer with path.
1087 * @param pszFilename Pointer to readonly filename.
1088 * @param pszBuffer Pointer to output Buffer.
1089 * @status completely implemented.
1090 * @author knut st. osmundsen
1091 */
1092char *fileNameNoExt(const char *pszFilename, char *pszBuffer)
1093{
1094 char *psz = strrchr(pszFilename, '\\');
1095 if (psz == NULL)
1096 psz = strrchr(pszFilename, '/');
1097
1098 strcpy(pszBuffer, psz == NULL ? pszFilename : psz + 1);
1099
1100 psz = strrchr(pszBuffer, '.');
1101 if (psz > pszBuffer) /* an extetion on it's own (.depend) is a filename not an extetion! */
1102 *psz = '\0';
1103
1104 return pszBuffer;
1105}
1106
1107
1108/**
1109 * Copies the extention part into pszBuffer and returns
1110 * a pointer to the buffer.
1111 * If no extention is found "" is returned.
1112 * The dot ('.') is not included!
1113 * @returns Pointer to pszBuffer with path.
1114 * @param pszFilename Pointer to readonly filename.
1115 * @param pszBuffer Pointer to output Buffer.
1116 * @status completely implemented.
1117 * @author knut st. osmundsen
1118 */
1119char *fileExt(const char *pszFilename, char *pszBuffer)
1120{
1121 char *psz = strrchr(pszFilename, '.');
1122 if (psz != NULL)
1123 {
1124 if (strchr(psz, '\\') != NULL || strchr(psz, '/') != NULL)
1125 *pszBuffer = '\0';
1126 else
1127 strcpy(pszBuffer, psz + 1);
1128 }
1129 else
1130 *pszBuffer = '\0';
1131
1132 return pszBuffer;
1133}
1134
1135
1136
1137
1138/**
1139 * Finds a filename in a specified pathlist.
1140 * @returns Pointer to a filename consiting of the path part + the given filename.
1141 * (pointer into pszBuffer)
1142 * NULL if file is not found. ("" in buffer)
1143 * @param pszPathList Path list to search for filename.
1144 * @parma pszFilename Filename to find.
1145 * @parma pszBuffer Ouput Buffer.
1146 * @status completely implemented.
1147 * @author knut st. osmundsen
1148 */
1149char *pathlistFindFile(const char *pszPathList, const char *pszFilename, char *pszBuffer)
1150{
1151 const char *psz = pszPathList;
1152 const char *pszNext = NULL;
1153
1154 *pszBuffer = '\0';
1155
1156 if (pszPathList == NULL)
1157 return NULL;
1158
1159 while (*psz != '\0')
1160 {
1161 /* find end of this path */
1162 pszNext = strchr(psz, ';');
1163 if (pszNext == NULL)
1164 pszNext = psz + strlen(psz);
1165
1166 if (pszNext - psz > 0)
1167 {
1168 HDIR hDir = HDIR_CREATE;
1169 ULONG cFiles = 1UL;
1170 FILEFINDBUF3 FileFindBuf;
1171 APIRET rc;
1172 char szFile[CCHMAXPATH];
1173
1174 /* make search statment */
1175 strncpy(szFile, psz, pszNext - psz);
1176 szFile[pszNext - psz] = '\0';
1177 if (szFile[pszNext - psz - 1] != '\\' && szFile[pszNext - psz - 1] != '/')
1178 strcpy(&szFile[pszNext - psz], "\\");
1179 strcat(szFile, pszFilename);
1180
1181 /* search for file */
1182 rc = DosFindFirst(szFile, &hDir, FILE_NORMAL, &FileFindBuf, sizeof(FileFindBuf),
1183 &cFiles, FIL_STANDARD);
1184 DosFindClose(hDir);
1185 if (rc == NO_ERROR)
1186 {
1187 strncpy(pszBuffer, psz, pszNext - psz);
1188 pszBuffer[pszNext - psz] = '\0';
1189 if (pszBuffer[pszNext - psz - 1] != '\\' && pszBuffer[pszNext - psz - 1] != '/')
1190 strcpy(&pszBuffer[pszNext - psz], "\\");
1191 strcat(pszBuffer, pszFilename);
1192 break;
1193 }
1194 }
1195
1196 /* next */
1197 if (*pszNext != ';')
1198 break;
1199 psz = pszNext + 1;
1200 }
1201
1202 return *pszBuffer == '\0' ? NULL : pszBuffer;
1203}
1204
Note: See TracBrowser for help on using the repository browser.