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

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

Append option added.

File size: 24.5 KB
Line 
1/* $Id: fastdep.c,v 1.2 2000-02-23 09:26:58 bird Exp $
2 *
3 * Fast dependents. (Fast = Quick and Dirty!)
4 *
5 * Copyright (c) 1999 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 BOOL fObjRule;
38 BOOL fNoObjectPath;
39 BOOL fSrcWhenObj;
40 BOOL fAppend; /* append to the output file, not overwrite it. */
41} OPTIONS, *POPTIONS;
42
43
44/*******************************************************************************
45* Global Variables *
46*******************************************************************************/
47static const char pszDefaultDepFile[] = ".depend";
48
49/*******************************************************************************
50* Internal Functions *
51*******************************************************************************/
52static void syntax(void);
53static int makeDependent(FILE *phDep, const char *pszFilename, POPTIONS pOptions);
54static int getFullIncludename(char *pszFilename, const char *pszInclude);
55
56/* file operations */
57char *filePath(const char *pszFilename, char *pszBuffer);
58char *filePathSlash(const char *pszFilename, char *pszBuffer);
59char *fileName(const char *pszFilename, char *pszBuffer);
60char *fileNameNoExt(const char *pszFilename, char *pszBuffer);
61char *fileExt(const char *pszFilename, char *pszBuffer);
62
63char *pathlistFindFile(const char *pszPathList, const char *pszFilename, char *pszBuffer);
64
65
66/**
67 * Main function.
68 * @returns 0 on success.
69 * -n count of failiures.
70 * @param
71 * @param
72 * @equiv
73 * @precond
74 * @methdesc
75 * @result
76 * @time
77 * @sketch
78 * @algo
79 * @remark
80 */
81int main(int argc, char **argv)
82{
83 FILE *phDep = NULL;
84 int rc = 0;
85 int argi = 1;
86 const char *pszDepFile = pszDefaultDepFile;
87
88 static char szObjectDir[CCHMAXPATH] = {0};
89 static char szObjectExt[64] = {"obj"};
90 static char szInclude[32768] = ";";
91 static char szExclude[32768] = ";";
92
93 OPTIONS options =
94 {
95 szInclude, /* pszInclude */
96 szExclude, /* pszExclude */
97 FALSE, /* fExcludeAll */
98 szObjectExt, /* pszObjectExt */
99 szObjectDir, /* pszObjectDir */
100 TRUE, /* fObjRule */
101 FALSE, /* fNoObjectPath */
102 TRUE, /* fSrcWhenObj */
103 FALSE /* fAppend */
104 };
105
106 if (argc == 1)
107 {
108 syntax();
109 return -87;
110 }
111
112 while (argi < argc)
113 {
114 if (argv[argi][0] == '-' || argv[argi][0] == '/')
115 {
116 /* parameters */
117 switch (argv[argi][1])
118 {
119 case 'A':
120 case 'a': /* Append to the output file */
121 options.fAppend = argv[argi][2] != '-';
122 break;
123
124 case 'D':
125 case 'd': /* "-d <filename>" */
126 if (argv[argi][2] != '\0')
127 pszDepFile = &argv[argi][2];
128 else
129 {
130 if (argi + 1 < argc)
131 pszDepFile = argv[++argi];
132 else
133 {
134 fprintf(stderr, "invalid parameter -d, filename missing!\n");
135 return -1;
136 }
137 }
138 if (phDep != NULL)
139 {
140 fclose(phDep);
141 phDep = NULL;
142 }
143 break;
144
145 case 'E': /* list of paths. If a file is found in one of these directories the */
146 case 'e': /* filename will be used without the directory path. */
147 /* Eall<[+]|-> ? */
148 if (strlen(&argv[argi][1]) <= 5 && strnicmp(&argv[argi][1], "Eall", 4) == 0)
149 {
150 options.fExcludeAll = argv[argi][5] != '-';
151 break;
152 }
153 /* path or path list */
154 if (strlen(argv[argi]) > 2)
155 strcat(szExclude, &argv[argi][2]);
156 else
157 {
158 strcat(szExclude, argv[argi+1]);
159 argi++;
160 }
161 if (szExclude[strlen(szExclude)-1] != ';')
162 strcat(szExclude, ";");
163 break;
164
165 case 'I': /* optional include path. This has precedence over the INCLUDE environment variable. */
166 case 'i':
167 if (strlen(argv[argi]) > 2)
168 strcat(szInclude, &argv[argi][2]);
169 else
170 {
171 strcat(szInclude, argv[argi+1]);
172 argi++;
173 }
174 if (szInclude[strlen(szInclude)-1] != ';')
175 strcat(szInclude, ";");
176 break;
177
178 case 'n': /* no object path , -N<[+]|-> */
179 case 'N':
180 if (strlen(argv[argi]) <= 1+1+1)
181 options.fNoObjectPath = argv[argi][2] != '-';
182 else
183 {
184 fprintf(stderr, "error: invalid parameter!, '%s'\n", argv[argi]);
185 return -1;
186 }
187 break;
188
189 case 'o': /* object base directory, Obj or Obr<[+]|-> */
190 case 'O':
191 if (strlen(&argv[argi][1]) <= 4 && strnicmp(&argv[argi][1], "Obr", 3) == 0)
192 {
193 options.fObjRule = argv[argi][4] != '-';
194 break;
195 }
196
197 if (strlen(&argv[argi][1]) >= 4 && strnicmp(&argv[argi][1], "Obj", 3) == 0)
198 {
199 if (strlen(argv[argi]) > 4)
200 strcpy(szObjectExt, argv[argi]+4);
201 else
202 {
203 strcpy(szObjectExt, argv[argi+1]);
204 argi++;
205 }
206 break;
207 }
208
209 /* path */
210 if (strlen(argv[argi]) > 2)
211 strcpy(szObjectDir, argv[argi]+2);
212 else
213 {
214 strcpy(szObjectDir, argv[argi+1]);
215 argi++;
216 }
217 if (szObjectDir[strlen(szObjectDir)-1] != '\\'
218 && szObjectDir[strlen(szObjectDir)-1] != '/'
219 )
220 strcat(szObjectDir, "\\");
221 break;
222
223 case 'h':
224 case 'H':
225 case '?':
226 syntax();
227 return 1;
228
229 default:
230 fprintf(stderr, "error: invalid parameter! '%s'\n", argv[argi]);
231 return -1;
232 }
233
234 }
235 else
236 { /* not a parameter! */
237 ULONG ulRc;
238 FILEFINDBUF3 filebuf = {0};
239 HDIR hDir = HDIR_CREATE;
240 ULONG ulFound = 1;
241
242 /*
243 * Open output file.
244 */
245 if (phDep == NULL)
246 {
247 phDep = fopen(pszDepFile, options.fAppend ? "a" : "w");
248 if (phDep == NULL)
249 {
250 fprintf(stderr, "error opening outputfile '%s'.\n", pszDepFile);
251 return 1;
252 }
253 }
254
255 /*
256 * Search for the files specified.
257 */
258 ulRc = DosFindFirst(argv[argi], &hDir,
259 FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_ARCHIVED,
260 &filebuf, sizeof(FILEFINDBUF3), &ulFound, FIL_STANDARD);
261 while (ulRc == NO_ERROR)
262 {
263 char *psz;
264 char szSource[CCHMAXPATH];
265
266 /*
267 * Make full path.
268 */
269 if ((psz = strrchr(argv[argi], '\\')) || (psz = strrchr(argv[argi], '/')))
270 {
271 strncpy(szSource, argv[argi], psz - argv[argi] + 1);
272 szSource[psz - argv[argi] + 1] = '\0';
273 }
274 else
275 szSource[0] = '\0';
276 strcat(szSource, filebuf.achName);
277
278 /*
279 * Analyse the file.
280 */
281 rc -= makeDependent(phDep, &szSource[0], &options);
282
283 /* next file */
284 ulRc = DosFindNext(hDir, &filebuf, sizeof(filebuf), &ulFound);
285 }
286 DosFindClose(hDir);
287 }
288 /* next */
289 argi++;
290 }
291
292 return rc;
293}
294
295
296/**
297 * Displays the syntax description for this util.
298 * @status completely implemented.
299 * @author knut st. osmundsen
300 */
301static void syntax(void)
302{
303 printf(
304 "FastDep v0.1\n"
305 "Quick and dirty dependant scanner. Creates a makefile readable depend file.\n"
306 "\n"
307 "Syntax: FastDep [-a<[+]|->] [-d <outputfn>] [-e <excludepath>] [-eall<[+]|->]\n"
308 " [-i <include>] [-n<[+]|->] [-o <objdir>] [-obr<[+]|->] <files>\n"
309 "\n"
310 " -a<[+]|-> Append to the output file. Default: Overwrite.\n"
311 " -d <outputfn> Output filename. Default: %s\n"
312 " -e excludepath Exclude paths. If a filename is found in any\n"
313 " of these paths only the filename is used, not\n"
314 " the path+filename (which is default).\n"
315 " -eall<[+]|-> -eall+: No path are added to the filename.\n"
316 " -eall-: The filename is appended the include path\n"
317 " was found in.\n"
318 " Default: eall-\n"
319 " -i <include> Additional include paths. INCLUDE is searched after this.\n"
320 " -n<[+]|-> No path for object files in the rules.\n"
321 " -o <objdir> Path were object files are placed. This path replaces the\n"
322 " entire filename path\n"
323 " -obr<[+]|-> -obr+: Object rule.\n"
324 " -obr-: No object rule, rule for source filename is generated.\n"
325 " <files> Files to scan. Wildchars are allowed.\n"
326 "\n",
327 pszDefaultDepFile
328 );
329}
330
331
332/**
333 * Generates depend info on this file, and fwrites it to phDep.
334 * @returns
335 * @param phDep Pointer to file struct for outfile.
336 * @param pszFilename Pointer to source filename.
337 * @param pOptions Pointer to options struct.
338 * @status completely implemented.
339 * @author knut st. osmundsen
340 */
341static int makeDependent(FILE *phDep, const char *pszFilename, POPTIONS pOptions)
342{
343 FILE *phFile;
344
345 phFile = fopen(pszFilename, "r");
346 if (phFile != NULL)
347 {
348 char szBuffer[4096]; /* max line lenght */
349 int k = strlen(pszFilename) - 1;
350 int l;
351 int iLine;
352
353 /**********************************/
354 /* print file name to depend file */
355 /**********************************/
356 if (pOptions->fObjRule)
357 {
358 char szExt[CCHMAXPATH];
359 char szObj[CCHMAXPATH];
360
361 if (pOptions->fNoObjectPath)
362 fileNameNoExt(pszFilename, szObj);
363 else if (*pOptions->pszObjectDir != '\0')
364 {
365 fileNameNoExt(pszFilename, szExt);
366 strcpy(szObj, pOptions->pszObjectDir);
367 strcat(szObj, szExt);
368 }
369 else
370 {
371 filePathSlash(pszFilename, szObj);
372 fileNameNoExt(pszFilename, szObj + strlen(szObj));
373 }
374
375 fileExt(pszFilename, szExt);
376 if (!stricmp(szExt, "c") || !stricmp(szExt, "sqc")
377 || !stricmp(szExt, "cpp") || !stricmp(szExt, "asm")
378 || !stricmp(szExt, "rc"))
379 {
380 if (!stricmp(szExt, "rc"))
381 strcat(szObj, ".res");
382 else
383 {
384 strcat(szObj, ".");
385 strcat(szObj, pOptions->pszObjectExt);
386 }
387 fprintf(phDep, "%s:", szObj);
388
389 if (pOptions->fSrcWhenObj)
390 fprintf(phDep, " \\\n%6s %s", "", pszFilename);
391 }
392 else
393 fprintf(phDep, "%s:", pszFilename);
394 }
395 else
396 fprintf(phDep, "%s:", pszFilename);
397
398 /*******************/
399 /* find dependants */
400 /*******************/
401 iLine = 0;
402 while (!feof(phFile)) /* line loop */
403 {
404 if (fgets(szBuffer, sizeof(szBuffer), phFile) != NULL)
405 {
406 /* search for #include or RCINCLUDE */
407 int cbLen;
408 int i = 0;
409 iLine++;
410
411 cbLen = strlen(szBuffer);
412 while (i + 9 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t'))
413 i++;
414
415 /* Found include! */
416 if (strncmp(&szBuffer[i], "#include", 8) == 0 || strncmp(&szBuffer[i], "RCINCLUDE", 9) == 0)
417 {
418 int f = 0;
419
420 /* extract info between "" or <> */
421 while (i < cbLen && !(f = (szBuffer[i] == '"' || szBuffer[i] == '<')))
422 i++;
423 i++; /* skip '"' or '<' */
424 if (f)
425 {
426 int j;
427 /* find end */
428 j = f = 0;
429 while (i + j < cbLen && j < CCHMAXPATH &&
430 !(f = (szBuffer[i+j] == '"' || szBuffer[i+j] == '>')))
431 j++;
432
433 if (f)
434 {
435 char szFullname[CCHMAXPATH];
436 char *psz;
437
438 /* copy filename */
439 strncpy(szFullname, &szBuffer[i], j);
440 szFullname[j] = '\0'; /* ensure terminatition. */
441
442 /* find include file! */
443 psz = pathlistFindFile(pOptions->pszInclude, szFullname, szBuffer);
444 if (psz == NULL)
445 psz = pathlistFindFile(getenv("INCLUDE"), szFullname, szBuffer);
446
447 if (psz != NULL)
448 {
449 char szBuffer2[CCHMAXPATH];
450 if (pOptions->fExcludeAll ||
451 pathlistFindFile(pOptions->pszExclude, szFullname, szBuffer2) != NULL
452 )
453 strcpy(szBuffer, szFullname);
454 fprintf(phDep, " \\\n%6.s %s", "", szBuffer);
455 }
456 else
457 fprintf(stderr, "%s(%d): warning include file '%s' not found!\n",
458 pszFilename, iLine, szFullname);
459 }
460 }
461 }
462 }
463 /*
464 else
465 break;
466 */
467 } /*while*/
468 fputs("\n", phDep);
469 fclose(phFile);
470 }
471 else
472 {
473 fprintf(stderr, "failed to open '%s'\n", pszFilename);
474 return -1;
475 }
476
477 return 0;
478}
479
480
481
482
483/**
484 * Gets the fullpath include-filename.
485 * @returns 0 on success, -1 on error.
486 * @param pszFilename Input: Pointer to filename to be found, and buffer for output.
487 * Ouput: Buffer now contains fullpath include-filename.
488 * @param pszInclude Additional includepath.
489 */
490static int getFullIncludename(char *pszFilename, const char *pszInclude)
491{
492 const char *pszEnvInclude;
493 const char *psz;
494
495 pszEnvInclude = getenv("INCLUDE");
496 if ((pszEnvInclude == NULL && (pszInclude == NULL || strlen(pszInclude) == 0)) || strlen(pszFilename) == 0)
497 return -1;
498
499 psz = "";
500 while (psz != NULL && psz != '\0')
501 {
502 const char *pszNext;
503 int cbLen;
504 char szFileTmpIn[260];
505 FILEFINDBUF3 filebuf;
506 ULONG ulRc;
507 HDIR hDir = HDIR_CREATE;
508 ULONG ulFound = 1;
509
510 /* get addr of next ';' or '\0' */
511 pszNext = strchr(psz, ';');
512 if (pszNext == NULL)
513 pszNext = psz + strlen(psz);
514
515 /* add a '\\' and the pszFilename string to the include path part. */
516 cbLen = (int)pszNext - (int)psz;
517 if (cbLen > 0)
518 {
519 strncpy(szFileTmpIn, psz, (int)pszNext - (int)psz);
520 if (szFileTmpIn[cbLen - 1] != '\\' && szFileTmpIn[cbLen - 1] != '/')
521 szFileTmpIn[cbLen++] = '\\';
522 }
523 strcpy(&szFileTmpIn[cbLen], pszFilename);
524
525
526 /**************************/
527 /* check if file is found */
528 /**************************/
529 ulRc = DosFindFirst(&szFileTmpIn[0], &hDir,
530 FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_ARCHIVED,
531 &filebuf, sizeof(FILEFINDBUF3), &ulFound, FIL_STANDARD);
532 if (ulRc == NO_ERROR)
533 {
534 strcpy(pszFilename, szFileTmpIn);
535 DosFindClose(hDir);
536 return 0;
537 }
538
539 /* next */
540 if (*pszNext == ';' && pszNext[1] != '\0')
541 psz = pszNext + 1;
542 else
543 {
544 psz = pszInclude;
545 pszInclude = NULL;
546
547 if (psz == NULL)
548 {
549 psz = pszEnvInclude;
550 pszEnvInclude = NULL;
551 }
552 }
553 }
554
555 return -1;
556}
557
558
559
560/**
561 * Copies the path part (excluding the slash) into pszBuffer and returns
562 * a pointer to the buffer.
563 * If no path is found "" is returned.
564 * @returns Pointer to pszBuffer with path.
565 * @param pszFilename Pointer to readonly filename.
566 * @param pszBuffer Pointer to output Buffer.
567 * @status completely implemented.
568 * @author knut st. osmundsen
569 */
570char *filePath(const char *pszFilename, char *pszBuffer)
571{
572 char *psz = strrchr(pszFilename, '\\');
573 if (psz == NULL)
574 psz = strrchr(pszFilename, '/');
575
576 if (psz == NULL)
577 *pszBuffer = '\0';
578 else
579 {
580 strncpy(pszBuffer, pszFilename, psz - pszFilename - 1);
581 pszBuffer[psz - pszFilename - 1] = '\0';
582 }
583
584 return pszBuffer;
585}
586
587
588/**
589 * Copies the path part including the slash into pszBuffer and returns
590 * a pointer to the buffer.
591 * If no path is found "" is returned.
592 * @returns Pointer to pszBuffer with path.
593 * @param pszFilename Pointer to readonly filename.
594 * @param pszBuffer Pointer to output Buffer.
595 * @status completely implemented.
596 * @author knut st. osmundsen
597 */
598char *filePathSlash(const char *pszFilename, char *pszBuffer)
599{
600 char *psz = strrchr(pszFilename, '\\');
601 if (psz == NULL)
602 psz = strrchr(pszFilename, '/');
603
604 if (psz == NULL)
605 *pszBuffer = '\0';
606 else
607 {
608 strncpy(pszBuffer, pszFilename, psz - pszFilename + 1);
609 pszBuffer[psz - pszFilename + 1] = '\0';
610 }
611
612 return pszBuffer;
613}
614
615
616/**
617 * Copies the path name (with extention) into pszBuffer and returns
618 * a pointer to the buffer.
619 * If no path is found "" is returned.
620 * @returns Pointer to pszBuffer with path.
621 * @param pszFilename Pointer to readonly filename.
622 * @param pszBuffer Pointer to output Buffer.
623 * @status completely implemented.
624 * @author knut st. osmundsen
625 */
626char *fileName(const char *pszFilename, char *pszBuffer)
627{
628 char *psz = strrchr(pszFilename, '\\');
629 if (psz == NULL)
630 psz = strrchr(pszFilename, '/');
631
632 strcpy(pszBuffer, psz == NULL ? pszFilename : psz + 1);
633
634 return pszBuffer;
635}
636
637
638/**
639 * Copies the name part with out extention into pszBuffer and returns
640 * a pointer to the buffer.
641 * If no name is found "" is returned.
642 * @returns Pointer to pszBuffer with path.
643 * @param pszFilename Pointer to readonly filename.
644 * @param pszBuffer Pointer to output Buffer.
645 * @status completely implemented.
646 * @author knut st. osmundsen
647 */
648char *fileNameNoExt(const char *pszFilename, char *pszBuffer)
649{
650 char *psz = strrchr(pszFilename, '\\');
651 if (psz == NULL)
652 psz = strrchr(pszFilename, '/');
653
654 strcpy(pszBuffer, psz == NULL ? pszFilename : psz + 1);
655
656 psz = strrchr(pszBuffer, '.');
657 if (psz > pszBuffer) /* an extetion on it's own (.depend) is a filename not an extetion! */
658 *psz = '\0';
659
660 return pszBuffer;
661}
662
663
664/**
665 * Copies the extention part into pszBuffer and returns
666 * a pointer to the buffer.
667 * If no extention is found "" is returned.
668 * The dot ('.') is not included!
669 * @returns Pointer to pszBuffer with path.
670 * @param pszFilename Pointer to readonly filename.
671 * @param pszBuffer Pointer to output Buffer.
672 * @status completely implemented.
673 * @author knut st. osmundsen
674 */
675char *fileExt(const char *pszFilename, char *pszBuffer)
676{
677 char *psz = strrchr(pszFilename, '.');
678 if (psz != NULL)
679 {
680 if (strchr(psz, '\\') != NULL || strchr(psz, '/') != NULL)
681 *pszBuffer = '\0';
682 else
683 strcpy(pszBuffer, psz + 1);
684 }
685 else
686 *pszBuffer = '\0';
687
688 return pszBuffer;
689}
690
691
692
693
694/**
695 * Finds a filename in a specified pathlist.
696 * @returns Pointer to a filename consiting of the path part + the given filename.
697 * (pointer into pszBuffer)
698 * NULL if file is not found. ("" in buffer)
699 * @param pszPathList Path list to search for filename.
700 * @parma pszFilename Filename to find.
701 * @parma pszBuffer Ouput Buffer.
702 * @status completely implemented.
703 * @author knut st. osmundsen
704 */
705char *pathlistFindFile(const char *pszPathList, const char *pszFilename, char *pszBuffer)
706{
707 const char *psz = pszPathList;
708 const char *pszNext = NULL;
709
710 *pszBuffer = '\0';
711
712 if (pszPathList == NULL)
713 return NULL;
714
715 while (*psz != '\0')
716 {
717 /* find end of this path */
718 pszNext = strchr(psz, ';');
719 if (pszNext == NULL)
720 pszNext = psz + strlen(psz);
721
722 if (pszNext - psz > 0)
723 {
724 HDIR hDir = HDIR_CREATE;
725 ULONG cFiles = 1UL;
726 FILEFINDBUF3 FileFindBuf;
727 APIRET rc;
728 char szFile[CCHMAXPATH];
729
730 /* make search statment */
731 strncpy(szFile, psz, pszNext - psz);
732 szFile[pszNext - psz] = '\0';
733 if (szFile[pszNext - psz - 1] != '\\' && szFile[pszNext - psz - 1] != '/')
734 strcpy(&szFile[pszNext - psz], "\\");
735 strcat(szFile, pszFilename);
736
737 /* search for file */
738 rc = DosFindFirst(szFile, &hDir, FILE_NORMAL, &FileFindBuf, sizeof(FileFindBuf),
739 &cFiles, FIL_STANDARD);
740 DosFindClose(hDir);
741 if (rc == NO_ERROR)
742 {
743 strncpy(pszBuffer, psz, pszNext - psz);
744 pszBuffer[pszNext - psz] = '\0';
745 if (pszBuffer[pszNext - psz - 1] != '\\' && pszBuffer[pszNext - psz - 1] != '/')
746 strcpy(&pszBuffer[pszNext - psz], "\\");
747 strcat(pszBuffer, pszFilename);
748 break;
749 }
750 }
751
752 /* next */
753 if (*pszNext != ';')
754 break;
755 psz = pszNext + 1;
756 }
757
758 return *pszBuffer == '\0' ? NULL : pszBuffer;
759}
760
Note: See TracBrowser for help on using the repository browser.