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

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

Dependencies.

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