]> git.proxmox.com Git - mirror_edk2.git/blame - Tools/Source/TianoTools/MakeDeps/MakeDeps.c
- Fixed EDKT146; The override warning message has been reduced to almost none.
[mirror_edk2.git] / Tools / Source / TianoTools / MakeDeps / MakeDeps.c
CommitLineData
b09da165 1/*++\r
2\r
3Copyright (c) 2004, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 MakeDeps.c \r
15\r
16Abstract:\r
17\r
18 Recursively scan source files to find include files and emit them to \r
19 create dependency lists.\r
20\r
21--*/\r
22\r
23#include <stdio.h>\r
24#include <string.h>\r
25#include <stdlib.h>\r
26#include <ctype.h>\r
27\r
ce53a8c3 28#include <Common/UefiBaseTypes.h>\r
29\r
b09da165 30#include "EfiUtilityMsgs.h"\r
ce53a8c3 31#include "CommonLib.h"\r
b09da165 32\r
33//\r
34// Structure to maintain a linked list of strings\r
35//\r
36typedef struct _STRING_LIST {\r
37 struct _STRING_LIST *Next;\r
38 char *Str;\r
39} STRING_LIST;\r
40\r
41#define UTILITY_NAME "MakeDeps"\r
42\r
43#define MAX_LINE_LEN 2048\r
44#define MAX_PATH 2048\r
45#define START_NEST_DEPTH 1\r
46#define MAX_NEST_DEPTH 1000 // just in case we get in an endless loop.\r
47//\r
48// Define the relative paths used by the special #include macros\r
49//\r
52cbbdbc 50#define PROTOCOL_DIR_PATH "Protocol/"\r
51#define GUID_DIR_PATH "Guid/"\r
52#define ARCH_PROTOCOL_DIR_PATH "ArchProtocol/"\r
53#define PPI_PROTOCOL_DIR_PATH "Ppi/"\r
b09da165 54\r
55//\r
56// Use this structure to keep track of all the special #include forms\r
57//\r
58typedef struct {\r
59 INT8 *IncludeMacroName;\r
60 INT8 *PathName;\r
61} INCLUDE_MACRO_CONVERSION;\r
62\r
63//\r
64// This data is used to convert #include macros like:\r
65// #include EFI_PROTOCOL_DEFINITION(xxx)\r
66// into\r
67// #include Protocol/xxx/xxx.h\r
68//\r
69static const INCLUDE_MACRO_CONVERSION mMacroConversion[] = {\r
70 "EFI_PROTOCOL_DEFINITION",\r
71 PROTOCOL_DIR_PATH,\r
72 "EFI_GUID_DEFINITION",\r
73 GUID_DIR_PATH,\r
74 "EFI_ARCH_PROTOCOL_DEFINITION",\r
75 ARCH_PROTOCOL_DIR_PATH,\r
76 "EFI_PROTOCOL_PRODUCER",\r
77 PROTOCOL_DIR_PATH,\r
78 "EFI_PROTOCOL_CONSUMER",\r
79 PROTOCOL_DIR_PATH,\r
80 "EFI_PROTOCOL_DEPENDENCY",\r
81 PROTOCOL_DIR_PATH,\r
82 "EFI_ARCH_PROTOCOL_PRODUCER",\r
83 ARCH_PROTOCOL_DIR_PATH,\r
84 "EFI_ARCH_PROTOCOL_CONSUMER",\r
85 ARCH_PROTOCOL_DIR_PATH,\r
86 "EFI_ARCH_PROTOCOL_DEPENDENCY",\r
87 ARCH_PROTOCOL_DIR_PATH,\r
88 "EFI_PPI_DEFINITION",\r
89 PPI_PROTOCOL_DIR_PATH,\r
90 "EFI_PPI_PRODUCER",\r
91 PPI_PROTOCOL_DIR_PATH,\r
92 "EFI_PPI_CONSUMER",\r
93 PPI_PROTOCOL_DIR_PATH,\r
94 "EFI_PPI_DEPENDENCY",\r
95 PPI_PROTOCOL_DIR_PATH,\r
96 NULL,\r
97 NULL\r
98};\r
99\r
100typedef struct _SYMBOL {\r
101 struct _SYMBOL *Next;\r
102 INT8 *Name;\r
103 INT8 *Value;\r
104} SYMBOL;\r
105\r
106//\r
107// Here's all our globals. We need a linked list of include paths, a linked\r
108// list of source files, a linked list of subdirectories (appended to each\r
109// include path when searching), and flags to keep track of command-line options.\r
110//\r
111static struct {\r
112 STRING_LIST *IncludePaths; // all include paths to search\r
113 STRING_LIST *SourceFiles; // all source files to parse\r
114 STRING_LIST *SubDirs; // appended to each include path when searching\r
115 SYMBOL *SymbolTable; // for replacement strings\r
116 FILE *OutFptr; // output dependencies to this file\r
117 BOOLEAN Verbose; // for more detailed output\r
118 BOOLEAN IgnoreNotFound; // no warnings if files not found\r
119 BOOLEAN QuietMode; // -q - don't print missing file warnings\r
120 BOOLEAN NoSystem; // don't process #include <system> files\r
121 BOOLEAN NeverFail; // always return success\r
122 BOOLEAN NoDupes; // to not list duplicate dependency files (for timing purposes)\r
123 BOOLEAN UseSumDeps; // use summary dependency files if found\r
124 INT8 TargetFileName[MAX_PATH]; // target object filename\r
125 INT8 SumDepsPath[MAX_PATH]; // path to summary files\r
126 INT8 *OutFileName; // -o option\r
127} mGlobals;\r
128\r
129static\r
130STATUS\r
131ProcessFile (\r
132 INT8 *TargetFileName,\r
133 INT8 *FileName,\r
134 UINT32 NestDepth,\r
135 STRING_LIST *ProcessedFiles\r
136 );\r
137\r
138static\r
139FILE *\r
140FindFile (\r
141 INT8 *FileName,\r
142 UINT32 FileNameLen\r
143 );\r
144\r
145static\r
146void\r
147PrintDependency (\r
148 INT8 *Target,\r
149 INT8 *DependentFile\r
150 );\r
151\r
152static\r
153void\r
154ReplaceSymbols (\r
155 INT8 *Str,\r
156 UINT32 StrSize\r
157 );\r
158\r
159static\r
160STATUS\r
161ProcessArgs (\r
162 int Argc,\r
163 char *Argv[]\r
164 );\r
165\r
166static\r
167void\r
168Usage (\r
169 VOID\r
170 );\r
171\r
172static\r
173void\r
174FreeLists (\r
175 VOID\r
176 );\r
177\r
178int\r
179main (\r
180 int Argc,\r
181 char *Argv[]\r
182 )\r
183/*++\r
184\r
185Routine Description:\r
186\r
187 Call the routine to parse the command-line options, then process each file\r
188 to build dependencies.\r
189 \r
190Arguments:\r
191\r
192 Argc - Standard C main() argc.\r
193 Argv - Standard C main() argv.\r
194\r
195Returns:\r
196\r
197 0 if successful\r
198 nonzero otherwise\r
199 \r
200--*/\r
201{\r
202 STRING_LIST *File;\r
203 STRING_LIST ProcessedFiles;\r
204 STRING_LIST *TempList;\r
205 STATUS Status;\r
206 INT8 *Cptr;\r
207 INT8 TargetFileName[MAX_PATH];\r
208\r
209 SetUtilityName (UTILITY_NAME);\r
210 //\r
211 // Process the command-line arguments\r
212 //\r
213 Status = ProcessArgs (Argc, Argv);\r
214 if (Status != STATUS_SUCCESS) {\r
215 return STATUS_ERROR;\r
216 }\r
217 //\r
218 // Go through the list of source files and process each.\r
219 //\r
220 memset (&ProcessedFiles, 0, sizeof (STRING_LIST));\r
221 File = mGlobals.SourceFiles;\r
222 while (File != NULL) {\r
223 //\r
224 // Clear out our list of processed files\r
225 //\r
226 TempList = ProcessedFiles.Next;\r
227 while (ProcessedFiles.Next != NULL) {\r
228 TempList = ProcessedFiles.Next->Next;\r
229 free (ProcessedFiles.Next->Str);\r
230 free (ProcessedFiles.Next);\r
231 ProcessedFiles.Next = TempList;\r
232 }\r
233 //\r
234 // Replace filename extension with ".obj" if they did not\r
235 // specifically specify the target file\r
236 //\r
237 if (mGlobals.TargetFileName[0] == 0) {\r
238 strcpy (TargetFileName, File->Str);\r
239 //\r
240 // Find the .extension\r
241 //\r
242 for (Cptr = TargetFileName + strlen (TargetFileName) - 1;\r
52cbbdbc 243 (*Cptr != '\\' && *Cptr != '/') && (Cptr > TargetFileName) && (*Cptr != '.');\r
b09da165 244 Cptr--\r
245 )\r
246 ;\r
247 if (Cptr == TargetFileName) {\r
248 Error (NULL, 0, 0, File->Str, "could not locate extension in filename");\r
249 goto Finish;\r
250 }\r
251 //\r
252 // Tack on the ".obj"\r
253 //\r
254 strcpy (Cptr, ".obj");\r
255 } else {\r
256 //\r
257 // Copy the target filename they specified\r
258 //\r
259 strcpy (TargetFileName, mGlobals.TargetFileName);\r
260 }\r
261\r
262 Status = ProcessFile (TargetFileName, File->Str, START_NEST_DEPTH, &ProcessedFiles);\r
263 if (Status != STATUS_SUCCESS) {\r
264 goto Finish;\r
265 }\r
266\r
267 File = File->Next;\r
268 }\r
269\r
270Finish:\r
271 //\r
272 // Free up memory\r
273 //\r
274 FreeLists ();\r
275 //\r
276 // Free up our processed files list\r
277 //\r
278 TempList = ProcessedFiles.Next;\r
279 while (ProcessedFiles.Next != NULL) {\r
280 TempList = ProcessedFiles.Next->Next;\r
281 free (ProcessedFiles.Next->Str);\r
282 free (ProcessedFiles.Next);\r
283 ProcessedFiles.Next = TempList;\r
284 }\r
285 //\r
286 // Close our output file\r
287 //\r
288 if ((mGlobals.OutFptr != stdout) && (mGlobals.OutFptr != NULL)) {\r
289 fclose (mGlobals.OutFptr);\r
290 }\r
291\r
292 if (mGlobals.NeverFail) {\r
293 return STATUS_SUCCESS;\r
294 }\r
295 //\r
296 // If any errors, then delete our output so that it will get created\r
297 // again on a rebuild.\r
298 //\r
299 if ((GetUtilityStatus () == STATUS_ERROR) && (mGlobals.OutFileName != NULL)) {\r
300 remove (mGlobals.OutFileName);\r
301 }\r
302\r
303 return GetUtilityStatus ();\r
304}\r
305\r
306static\r
307STATUS\r
308ProcessFile (\r
309 INT8 *TargetFileName,\r
310 INT8 *FileName,\r
311 UINT32 NestDepth,\r
312 STRING_LIST *ProcessedFiles\r
313 )\r
314/*++\r
315\r
316Routine Description:\r
317\r
318 Given a source file name, open the file and parse all #include lines.\r
319 \r
320Arguments:\r
321\r
322 TargetFileName - name of the usually .obj target\r
323 FileName - name of the file to process\r
324 NestDepth - how deep we're nested in includes\r
325 ProcessedFiles - list of processed files.\r
326\r
327Returns:\r
328\r
329 standard status.\r
330 \r
331--*/\r
332{\r
333 FILE *Fptr;\r
334 INT8 Line[MAX_LINE_LEN];\r
335 INT8 *Cptr;\r
336 INT8 *EndPtr;\r
337 INT8 *SaveCptr;\r
338 INT8 EndChar;\r
339 INT8 FileNameCopy[MAX_PATH];\r
340 INT8 MacroIncludeFileName[MAX_LINE_LEN];\r
341 INT8 SumDepsFile[MAX_PATH];\r
342 STATUS Status;\r
343 UINT32 Index;\r
344 UINT32 LineNum;\r
345 STRING_LIST *ListPtr;\r
346\r
347 Status = STATUS_SUCCESS;\r
348 Fptr = NULL;\r
349 //\r
350 // Print the file being processed. Indent so you can tell the include nesting\r
351 // depth.\r
352 //\r
353 if (mGlobals.Verbose) {\r
354 fprintf (stdout, "%*cProcessing file '%s'\n", NestDepth * 2, ' ', FileName);\r
355 }\r
356 //\r
357 // If we're using summary dependency files, and a matching .dep file is\r
358 // found for this file, then just emit the summary dependency file as\r
359 // a dependency and return.\r
360 //\r
361 if (mGlobals.UseSumDeps) {\r
362 strcpy (SumDepsFile, mGlobals.SumDepsPath);\r
363 strcat (SumDepsFile, FileName);\r
364 for (Cptr = SumDepsFile + strlen (SumDepsFile) - 1;\r
52cbbdbc 365 (*Cptr != '\\' && *Cptr != '/') && (Cptr > SumDepsFile) && (*Cptr != '.');\r
b09da165 366 Cptr--\r
367 )\r
368 ;\r
369 if (*Cptr == '.') {\r
370 strcpy (Cptr, ".dep");\r
371 } else {\r
372 strcat (SumDepsFile, ".dep");\r
373 }\r
374 //\r
375 // See if the summary dep file exists. Could use _stat() function, but\r
376 // it's less portable.\r
377 //\r
378 if ((Fptr = fopen (SumDepsFile, "r")) != NULL) {\r
379 PrintDependency (TargetFileName, SumDepsFile);\r
380 return STATUS_SUCCESS;\r
381 }\r
382 }\r
383 //\r
384 // If we're not doing duplicates, and we've already seen this filename,\r
385 // then return\r
386 //\r
387 if (mGlobals.NoDupes) {\r
388 for (ListPtr = ProcessedFiles->Next; ListPtr != NULL; ListPtr = ListPtr->Next) {\r
389 if (stricmp (FileName, ListPtr->Str) == 0) {\r
390 break;\r
391 }\r
392 }\r
393 //\r
394 // If we found a match, we're done. If we didn't, create a new element\r
395 // and add it to the list.\r
396 //\r
397 if (ListPtr != NULL) {\r
398 //\r
399 // Print a message if verbose mode\r
400 //\r
401 if (mGlobals.Verbose) {\r
402 DebugMsg (NULL, 0, 0, FileName, "duplicate include -- not processed again");\r
403 }\r
404\r
405 return STATUS_SUCCESS;\r
406 }\r
407\r
408 ListPtr = malloc (sizeof (STRING_LIST));\r
409 ListPtr->Str = malloc (strlen (FileName) + 1);\r
410 strcpy (ListPtr->Str, FileName);\r
411 ListPtr->Next = ProcessedFiles->Next;\r
412 ProcessedFiles->Next = ListPtr;\r
413 }\r
414\r
415 //\r
416 // Make sure we didn't exceed our maximum nesting depth\r
417 //\r
418 if (NestDepth > MAX_NEST_DEPTH) {\r
419 Error (NULL, 0, 0, FileName, "max nesting depth exceeded on file");\r
420 goto Finish;\r
421 }\r
422 //\r
423 // Make a local copy of the filename. Then we can manipulate it\r
424 // if we have to.\r
425 //\r
426 strcpy (FileNameCopy, FileName);\r
427 //\r
428 // Try to open the file locally\r
429 //\r
430 if ((Fptr = fopen (FileNameCopy, "r")) == NULL) {\r
431 //\r
432 // Try to find it among the paths.\r
433 //\r
434 Fptr = FindFile (FileNameCopy, sizeof (FileNameCopy));\r
435 if (Fptr == NULL) {\r
436 //\r
437 // If this is not the top-level file, and the command-line argument\r
438 // said to ignore missing files, then return ok\r
439 //\r
440 if (NestDepth != START_NEST_DEPTH) {\r
441 if (mGlobals.IgnoreNotFound) {\r
442 if (!mGlobals.QuietMode) {\r
443 DebugMsg (NULL, 0, 0, FileNameCopy, "could not find file");\r
444 }\r
445\r
446 return STATUS_SUCCESS;\r
447 } else {\r
448 Error (NULL, 0, 0, FileNameCopy, "could not find file");\r
449 return STATUS_ERROR;\r
450 }\r
451 } else {\r
452 //\r
453 // Top-level (first) file. Emit an error.\r
454 //\r
455 Error (NULL, 0, 0, FileNameCopy, "could not find file");\r
456 return STATUS_ERROR;\r
457 }\r
458 }\r
459 }\r
460 //\r
461 // Print the dependency, with string substitution\r
462 //\r
463 PrintDependency (TargetFileName, FileNameCopy);\r
464\r
465 //\r
466 // Now read in lines and find all #include lines. Allow them to indent, and\r
467 // to put spaces between the # and include.\r
468 //\r
469 LineNum = 0;\r
470 while ((fgets (Line, sizeof (Line), Fptr) != NULL) && (Status == STATUS_SUCCESS)) {\r
471 LineNum++;\r
472 Cptr = Line;\r
473 //\r
474 // Skip preceeding spaces on the line\r
475 //\r
476 while (*Cptr && (isspace (*Cptr))) {\r
477 Cptr++;\r
478 }\r
479 //\r
480 // Check for # character\r
481 //\r
482 if (*Cptr == '#') {\r
483 Cptr++;\r
484 //\r
485 // Check for "include"\r
486 //\r
487 while (*Cptr && (isspace (*Cptr))) {\r
488 Cptr++;\r
489 }\r
490\r
491 if (strncmp (Cptr, "include", 7) == 0) {\r
492 //\r
493 // Skip over "include" and move on to filename as "file" or <file>\r
494 //\r
495 Cptr += 7;\r
496 while (*Cptr && (isspace (*Cptr))) {\r
497 Cptr++;\r
498 }\r
499\r
500 if (*Cptr == '<') {\r
501 EndChar = '>';\r
502 } else if (*Cptr == '"') {\r
503 EndChar = '"';\r
504 } else {\r
505 //\r
506 // Handle special #include MACRO_NAME(file)\r
507 // Set EndChar to null so we fall through on processing below.\r
508 //\r
509 EndChar = 0;\r
510 //\r
511 // Look for all the special include macros and convert accordingly.\r
512 //\r
513 for (Index = 0; mMacroConversion[Index].IncludeMacroName != NULL; Index++) {\r
514 //\r
515 // Save the start of the string in case some macros are substrings\r
516 // of others.\r
517 //\r
518 SaveCptr = Cptr;\r
519 if (strncmp (\r
520 Cptr,\r
521 mMacroConversion[Index].IncludeMacroName,\r
522 strlen (mMacroConversion[Index].IncludeMacroName)\r
523 ) == 0) {\r
524 //\r
525 // Skip over the macro name\r
526 //\r
527 Cptr += strlen (mMacroConversion[Index].IncludeMacroName);\r
528 //\r
529 // Skip over open parenthesis, blank spaces, then find closing\r
530 // parenthesis or blank space\r
531 //\r
532 while (*Cptr && (isspace (*Cptr))) {\r
533 Cptr++;\r
534 }\r
535\r
536 if (*Cptr == '(') {\r
537 Cptr++;\r
538 while (*Cptr && (isspace (*Cptr))) {\r
539 Cptr++;\r
540 }\r
541\r
542 EndPtr = Cptr;\r
543 while (*EndPtr && !isspace (*EndPtr) && (*EndPtr != ')')) {\r
544 EndPtr++;\r
545 }\r
546\r
547 *EndPtr = 0;\r
548 //\r
549 // Create the path\r
550 //\r
551 strcpy (MacroIncludeFileName, mMacroConversion[Index].PathName);\r
552 strcat (MacroIncludeFileName, Cptr);\r
52cbbdbc 553 strcat (MacroIncludeFileName, "/");\r
b09da165 554 strcat (MacroIncludeFileName, Cptr);\r
555 strcat (MacroIncludeFileName, ".h");\r
556 //\r
557 // Process immediately, then break out of the outside FOR loop.\r
558 //\r
559 Status = ProcessFile (TargetFileName, MacroIncludeFileName, NestDepth + 1, ProcessedFiles);\r
560 break;\r
561 }\r
562 }\r
563 //\r
564 // Restore the start\r
565 //\r
566 Cptr = SaveCptr;\r
567 }\r
568 //\r
569 // Don't recognize the include line? Ignore it. We assume that the\r
570 // file compiles anyway.\r
571 //\r
572 if (mMacroConversion[Index].IncludeMacroName == NULL) {\r
573 //\r
574 // Warning (FileNameCopy, LineNum, 0, "could not parse line", NULL);\r
575 // Status = STATUS_WARNING;\r
576 //\r
577 }\r
578 }\r
579 //\r
580 // Process "normal" includes. If the endchar is 0, then the\r
581 // file has already been processed. Otherwise look for the\r
582 // endchar > or ", and process the include file.\r
583 //\r
584 if (EndChar != 0) {\r
585 Cptr++;\r
586 EndPtr = Cptr;\r
587 while (*EndPtr && (*EndPtr != EndChar)) {\r
588 EndPtr++;\r
589 }\r
590\r
591 if (*EndPtr == EndChar) {\r
592 //\r
593 // If we're processing it, do it\r
594 //\r
595 if ((EndChar != '>') || (!mGlobals.NoSystem)) {\r
596 //\r
597 // Null terminate the filename and try to process it.\r
598 //\r
599 *EndPtr = 0;\r
600 Status = ProcessFile (TargetFileName, Cptr, NestDepth + 1, ProcessedFiles);\r
601 }\r
602 } else {\r
603 Warning (FileNameCopy, LineNum, 0, "malformed include", "missing closing %c", EndChar);\r
604 Status = STATUS_WARNING;\r
605 goto Finish;\r
606 }\r
607 }\r
608 }\r
609 }\r
610 }\r
611\r
612Finish:\r
613 //\r
614 // Close open files and return status\r
615 //\r
616 if (Fptr != NULL) {\r
617 fclose (Fptr);\r
618 }\r
619\r
620 return Status;\r
621}\r
622\r
623static\r
624void\r
625PrintDependency (\r
626 INT8 *TargetFileName,\r
627 INT8 *DependentFile\r
628 )\r
629/*++\r
630\r
631Routine Description:\r
632\r
633 Given a target (.obj) file name, and a dependent file name, do any string\r
634 substitutions (per the command line options) on the file names, then\r
635 print the dependency line of form:\r
636 \r
637 TargetFileName : DependentFile\r
638 \r
639Arguments:\r
640\r
641 TargetFileName - build target file name\r
642 DependentFile - file on which TargetFileName depends\r
643\r
644Returns:\r
645\r
646 None\r
647 \r
648--*/\r
649{\r
650 INT8 Str[MAX_PATH];\r
651\r
652 //\r
653 // Go through the symbols and do replacements\r
654 //\r
b09da165 655 strcpy (Str, DependentFile);\r
656 ReplaceSymbols (Str, sizeof (Str));\r
657 fprintf (mGlobals.OutFptr, "%s\n", Str);\r
658}\r
659\r
660static\r
661void\r
662ReplaceSymbols (\r
663 INT8 *Str,\r
664 UINT32 StrSize\r
665 )\r
666{\r
667 SYMBOL *Sym;\r
668 INT8 StrCopy[MAX_LINE_LEN];\r
669 INT8 *From;\r
670 INT8 *To;\r
671 BOOLEAN Replaced;\r
672\r
673 //\r
674 // Go through the entire string to look for replacement strings at\r
675 // every position.\r
676 //\r
677 From = Str;\r
678 To = StrCopy;\r
679 while (*From) {\r
680 //\r
681 // Copy the character\r
682 //\r
683 *To = *From;\r
684 Replaced = FALSE;\r
685 //\r
686 // Go through each symbol and try to find a string substitution\r
687 //\r
688 Sym = mGlobals.SymbolTable;\r
689 while (Sym != NULL) {\r
690 if (strnicmp (From, Sym->Value, strlen (Sym->Value)) == 0) {\r
691 //\r
692 // Replace the string, then advance the pointers past the\r
693 // replaced strings\r
694 //\r
695 strcpy (To, Sym->Name);\r
696 To += strlen (Sym->Name);\r
697 From += strlen (Sym->Value);\r
698 Replaced = TRUE;\r
699 //\r
700 // Break from the while()\r
701 //\r
702 break;\r
703 } else {\r
704 Sym = Sym->Next;\r
705 }\r
706 }\r
707\r
708 if (!Replaced) {\r
709 From++;\r
710 To++;\r
711 }\r
712 }\r
713 //\r
714 // Null terminate, and return it\r
715 //\r
716 *To = 0;\r
717 if (strlen (StrCopy) < StrSize) {\r
718 strcpy (Str, StrCopy);\r
719 }\r
720}\r
721//\r
722// Given a filename, try to find it along the include paths.\r
723//\r
724static\r
725FILE *\r
726FindFile (\r
727 INT8 *FileName,\r
728 UINT32 FileNameLen\r
729 )\r
730{\r
731 FILE *Fptr;\r
732 STRING_LIST *List;\r
733 STRING_LIST *SubDir;\r
734 INT8 FullFileName[MAX_PATH * 2];\r
735\r
736 //\r
737 // Traverse the list of paths and try to find the file\r
738 //\r
739 List = mGlobals.IncludePaths;\r
740 while (List != NULL) {\r
741 //\r
742 // Put the path and filename together\r
743 //\r
744 if (strlen (List->Str) + strlen (FileName) + 1 > sizeof (FullFileName)) {\r
745 Error (\r
746 __FILE__,\r
747 __LINE__,\r
748 0,\r
749 "application error",\r
750 "cannot concatenate '%s' + '%s'",\r
751 List->Str,\r
752 FileName\r
753 );\r
754 return NULL;\r
755 }\r
756 //\r
757 // Append the filename to this include path and try to open the file.\r
758 //\r
759 strcpy (FullFileName, List->Str);\r
760 strcat (FullFileName, FileName);\r
761 if ((Fptr = fopen (FullFileName, "r")) != NULL) {\r
762 //\r
763 // Return the file name\r
764 //\r
765 if (FileNameLen <= strlen (FullFileName)) {\r
766 Error (__FILE__, __LINE__, 0, "application error", "internal path name of insufficient length");\r
767 //\r
768 // fprintf (stdout, "File length > %d: %s\n", FileNameLen, FullFileName);\r
769 //\r
770 return NULL;\r
771 }\r
772\r
773 strcpy (FileName, FullFileName);\r
774 return Fptr;\r
775 }\r
776 //\r
777 // Didn't find it there. Now try this directory with every subdirectory\r
778 // the user specified on the command line\r
779 //\r
780 for (SubDir = mGlobals.SubDirs; SubDir != NULL; SubDir = SubDir->Next) {\r
781 strcpy (FullFileName, List->Str);\r
782 strcat (FullFileName, SubDir->Str);\r
783 strcat (FullFileName, FileName);\r
784 if ((Fptr = fopen (FullFileName, "r")) != NULL) {\r
785 //\r
786 // Return the file name\r
787 //\r
788 if (FileNameLen <= strlen (FullFileName)) {\r
789 Error (__FILE__, __LINE__, 0, "application error", "internal path name of insufficient length");\r
790 return NULL;\r
791 }\r
792\r
793 strcpy (FileName, FullFileName);\r
794 return Fptr;\r
795 }\r
796 }\r
797\r
798 List = List->Next;\r
799 }\r
800 //\r
801 // Not found\r
802 //\r
803 return NULL;\r
804}\r
805//\r
806// Process the command-line arguments\r
807//\r
808static\r
809STATUS\r
810ProcessArgs (\r
811 int Argc,\r
812 char *Argv[]\r
813 )\r
814{\r
815 STRING_LIST *NewList;\r
816 STRING_LIST *LastIncludePath;\r
817 STRING_LIST *LastSourceFile;\r
818 SYMBOL *Symbol;\r
819 int Index;\r
820 //\r
821 // Clear our globals\r
822 //\r
823 memset ((char *) &mGlobals, 0, sizeof (mGlobals));\r
824 mGlobals.NoDupes = TRUE;\r
825 //\r
826 // Skip program name\r
827 //\r
828 Argc--;\r
829 Argv++;\r
830 //\r
831 // Initialize locals\r
832 //\r
833 LastIncludePath = NULL;\r
834 LastSourceFile = NULL;\r
835 //\r
836 // Process until no more args\r
837 //\r
838 while (Argc) {\r
839 //\r
840 // -i path add include search path\r
841 //\r
842 if (stricmp (Argv[0], "-i") == 0) {\r
843 //\r
844 // check for one more arg\r
845 //\r
846 if (Argc > 1) {\r
847 //\r
848 // Allocate memory for a new list element, fill it in, and\r
849 // add it to our list of include paths. Always make sure it\r
850 // has a "\" on the end of it.\r
851 //\r
852 NewList = malloc (sizeof (STRING_LIST));\r
853 if (NewList == NULL) {\r
854 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
855 return STATUS_ERROR;\r
856 }\r
857\r
858 NewList->Next = NULL;\r
859 NewList->Str = malloc (strlen (Argv[1]) + 2);\r
860 if (NewList->Str == NULL) {\r
861 free (NewList);\r
862 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
863 return STATUS_ERROR;\r
864 }\r
865\r
866 strcpy (NewList->Str, Argv[1]);\r
52cbbdbc 867 if (NewList->Str[strlen (NewList->Str) - 1] != '\\' && NewList->Str[strlen (NewList->Str) - 1] != '/') {\r
868 strcat (NewList->Str, "/");\r
b09da165 869 }\r
870 //\r
871 // Add it to the end of the our list of include paths\r
872 //\r
873 if (mGlobals.IncludePaths == NULL) {\r
874 mGlobals.IncludePaths = NewList;\r
875 } else {\r
876 LastIncludePath->Next = NewList;\r
877 }\r
878\r
879 LastIncludePath = NewList;\r
880 //\r
881 // fprintf (stdout, "Added path: %s\n", NewList->Str);\r
882 //\r
883 } else {\r
884 Error (NULL, 0, 0, Argv[0], "option requires an include path");\r
885 Usage ();\r
886 return STATUS_ERROR;\r
887 }\r
888\r
889 Argc--;\r
890 Argv++;\r
891 } else if (stricmp (Argv[0], "-f") == 0) {\r
892 //\r
893 // Check for one more arg\r
894 //\r
895 if (Argc > 1) {\r
896 //\r
897 // Allocate memory for a new list element, fill it in, and\r
898 // add it to our list of source files.\r
899 //\r
900 NewList = malloc (sizeof (STRING_LIST));\r
901 if (NewList == NULL) {\r
902 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
903 return STATUS_ERROR;\r
904 }\r
905\r
906 NewList->Next = NULL;\r
907 //\r
908 // Allocate space to replace ".c" with ".obj", plus null termination\r
909 //\r
910 NewList->Str = malloc (strlen (Argv[1]) + 5);\r
911 if (NewList->Str == NULL) {\r
912 free (NewList);\r
913 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
914 return STATUS_ERROR;\r
915 }\r
916\r
917 strcpy (NewList->Str, Argv[1]);\r
918 if (mGlobals.SourceFiles == NULL) {\r
919 mGlobals.SourceFiles = NewList;\r
920 } else {\r
921 LastSourceFile->Next = NewList;\r
922 }\r
923\r
924 LastSourceFile = NewList;\r
925 } else {\r
926 Error (NULL, 0, 0, Argv[0], "option requires a file name");\r
927 Usage ();\r
928 return STATUS_ERROR;\r
929 }\r
930 //\r
931 // The C compiler first looks for #include files in the directory where\r
932 // the source file came from. Add the file's source directory to the\r
933 // list of include paths.\r
934 //\r
935 NewList = malloc (sizeof (STRING_LIST));\r
936 if (NewList == NULL) {\r
937 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
938 return STATUS_ERROR;\r
939 }\r
940\r
941 NewList->Next = NULL;\r
942 NewList->Str = malloc (strlen (Argv[1]) + 3);\r
943 if (NewList->Str == NULL) {\r
944 free (NewList);\r
945 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
946 return STATUS_ERROR;\r
947 }\r
948\r
949 strcpy (NewList->Str, Argv[1]);\r
950 //\r
951 // Back up in the source file name to the last backslash and terminate after it.\r
952 //\r
52cbbdbc 953 for (Index = strlen (NewList->Str) - 1; (Index > 0) && (NewList->Str[Index] != '\\' && NewList->Str[Index] != '/'); Index--)\r
b09da165 954 ;\r
955 if (Index < 0) {\r
52cbbdbc 956 strcpy (NewList->Str, "./");\r
b09da165 957 } else {\r
958 NewList->Str[Index + 1] = 0;\r
959 }\r
960 //\r
961 // Add it to the end of the our list of include paths\r
962 //\r
963 if (mGlobals.IncludePaths == NULL) {\r
964 mGlobals.IncludePaths = NewList;\r
965 } else {\r
966 LastIncludePath->Next = NewList;\r
967 }\r
968\r
969 if (mGlobals.Verbose) {\r
970 fprintf (stdout, "Adding include path: %s\n", NewList->Str);\r
971 }\r
972\r
973 LastIncludePath = NewList;\r
974 Argc--;\r
975 Argv++;\r
976 } else if (stricmp (Argv[0], "-s") == 0) {\r
977 //\r
978 // -s subdir add subdirectory subdir to list of subdirecties to scan.\r
979 // Check for one more arg first.\r
980 //\r
981 if (Argc > 1) {\r
982 //\r
983 // Allocate memory for a new list element, fill it in, and\r
984 // add it to our list of subdirectory include paths. Always\r
985 // make sure it has a "\" on the end of it.\r
986 //\r
987 NewList = malloc (sizeof (STRING_LIST));\r
988 if (NewList == NULL) {\r
989 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
990 return STATUS_ERROR;\r
991 }\r
992\r
993 NewList->Str = malloc (strlen (Argv[1]) + 2);\r
994 if (NewList->Str == NULL) {\r
995 free (NewList);\r
996 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
997 return STATUS_ERROR;\r
998 }\r
999\r
1000 strcpy (NewList->Str, Argv[1]);\r
52cbbdbc 1001 if (NewList->Str[strlen (NewList->Str) - 1] != '\\' && NewList->Str[strlen (NewList->Str) - 1] != '/') {\r
1002 strcat (NewList->Str, "/");\r
b09da165 1003 }\r
1004\r
1005 NewList->Next = mGlobals.SubDirs;\r
1006 mGlobals.SubDirs = NewList;\r
1007 } else {\r
1008 Error (NULL, 0, 0, Argv[0], "option requires a subdirectory name");\r
1009 Usage ();\r
1010 return STATUS_ERROR;\r
1011 }\r
1012\r
1013 Argc--;\r
1014 Argv++;\r
1015 } else if (stricmp (Argv[0], "-sub") == 0) {\r
1016 //\r
1017 // -sub symname symvalue to do string substitution in the output\r
1018 //\r
1019 if (Argc > 2) {\r
1020 //\r
1021 // Allocate memory for the symbol object\r
1022 //\r
1023 Symbol = malloc (sizeof (SYMBOL));\r
1024 if (Symbol == NULL) {\r
1025 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
1026 return STATUS_ERROR;\r
1027 }\r
1028 //\r
1029 // Allocate memory for the symbol name and value, then save copies\r
1030 //\r
1031 Symbol->Name = malloc (strlen (Argv[1]) + 1);\r
1032 if (Symbol->Name == NULL) {\r
1033 free (Symbol);\r
1034 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
1035 return STATUS_ERROR;\r
1036 }\r
1037\r
1038 strcpy (Symbol->Name, Argv[1]);\r
1039 Symbol->Value = malloc (strlen (Argv[2]) + 1);\r
1040 if (Symbol->Value == NULL) {\r
1041 free (Symbol->Name);\r
1042 free (Symbol);\r
1043 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
1044 return STATUS_ERROR;\r
1045 }\r
1046\r
1047 strcpy (Symbol->Value, Argv[2]);\r
1048 //\r
1049 // Add it to the list\r
1050 //\r
1051 Symbol->Next = mGlobals.SymbolTable;\r
1052 mGlobals.SymbolTable = Symbol;\r
1053 } else {\r
1054 Error (NULL, 0, 0, Argv[0], "option requires a symbol name and value");\r
1055 Usage ();\r
1056 return STATUS_ERROR;\r
1057 }\r
1058 //\r
1059 // Skip over args\r
1060 //\r
1061 Argc -= 2;\r
1062 Argv += 2;\r
1063 } else if (stricmp (Argv[0], "-nosystem") == 0) {\r
1064 mGlobals.NoSystem = TRUE;\r
1065 } else if (stricmp (Argv[0], "-nodupes") == 0) {\r
1066 mGlobals.NoDupes = TRUE;\r
1067 } else if (stricmp (Argv[0], "-nodups") == 0) {\r
1068 mGlobals.NoDupes = TRUE;\r
1069 } else if (stricmp (Argv[0], "-target") == 0) {\r
1070 //\r
1071 // -target TargetFileName - Target object file (only one allowed right\r
1072 // now) is TargetFileName rather than SourceFile.obj\r
1073 //\r
1074 if (Argc > 1) {\r
1075 strcpy (mGlobals.TargetFileName, Argv[1]);\r
1076 } else {\r
1077 Error (NULL, 0, 0, Argv[0], "option requires a target file name");\r
1078 Usage ();\r
1079 return STATUS_ERROR;\r
1080 }\r
1081\r
1082 Argc--;\r
1083 Argv++;\r
1084 } else if (stricmp (Argv[0], "-usesumdeps") == 0) {\r
1085 //\r
1086 // -usesumdeps Path - if we find an included file xxx.h, and file\r
1087 // Path/xxx.dep exists, list Path/xxx.dep as a dependency rather than\r
1088 // xxx.h and don't parse xxx.h. This allows you to create a dependency\r
1089 // file for a commonly included file, and have its dependency file updated\r
1090 // only if its included files are updated. Then anyone else including this\r
1091 // common include file can simply have a dependency on that file's .dep file\r
1092 // rather than on all the files included by it. Confusing enough?\r
1093 //\r
1094 mGlobals.UseSumDeps = 1;\r
1095 if (Argc > 1) {\r
1096 strcpy (mGlobals.SumDepsPath, Argv[1]);\r
1097 //\r
1098 // Add slash on end if not there\r
1099 //\r
52cbbdbc 1100 if (mGlobals.SumDepsPath[strlen (mGlobals.SumDepsPath) - 1] != '\\' && mGlobals.SumDepsPath[strlen (mGlobals.SumDepsPath) - 1] != '/') {\r
1101 strcat (mGlobals.SumDepsPath, "/");\r
b09da165 1102 }\r
1103 } else {\r
1104 Error (NULL, 0, 0, Argv[0], "option requires path to summary dependency files");\r
1105 Usage ();\r
1106 return STATUS_ERROR;\r
1107 }\r
1108\r
1109 Argc--;\r
1110 Argv++;\r
1111\r
1112 } else if (stricmp (Argv[0], "-o") == 0) {\r
1113 //\r
1114 // -o OutputFileName - specify an output filename for dependency list\r
1115 // check for one more arg\r
1116 //\r
1117 if (Argc > 1) {\r
1118 //\r
1119 // Try to open the file\r
1120 //\r
1121 if ((mGlobals.OutFptr = fopen (Argv[1], "w")) == NULL) {\r
1122 Error (NULL, 0, 0, Argv[1], "could not open file for writing");\r
1123 return STATUS_ERROR;\r
1124 }\r
1125\r
1126 mGlobals.OutFileName = Argv[1];\r
1127 } else {\r
1128 Error (NULL, 0, 0, Argv[0], "option requires output file name");\r
1129 Usage ();\r
1130 return STATUS_ERROR;\r
1131 }\r
1132\r
1133 Argc--;\r
1134 Argv++;\r
1135 } else if (stricmp (Argv[0], "-v") == 0) {\r
1136 mGlobals.Verbose = TRUE;\r
1137 } else if (stricmp (Argv[0], "-neverfail") == 0) {\r
1138 mGlobals.NeverFail = TRUE;\r
1139 } else if (stricmp (Argv[0], "-q") == 0) {\r
1140 mGlobals.QuietMode = TRUE;\r
1141 } else if (stricmp (Argv[0], "-ignorenotfound") == 0) {\r
1142 mGlobals.IgnoreNotFound = TRUE;\r
1143 } else if ((stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) {\r
1144 Usage ();\r
1145 return STATUS_ERROR;\r
1146 } else {\r
1147 Error (NULL, 0, 0, Argv[0], "unrecognized option");\r
1148 Usage ();\r
1149 return STATUS_ERROR;\r
1150 }\r
1151\r
1152 Argc--;\r
1153 Argv++;\r
1154 }\r
1155 //\r
1156 // Had to specify at least one source file\r
1157 //\r
1158 if (mGlobals.SourceFiles == NULL) {\r
1159 Error (NULL, 0, 0, "must specify one source file name", NULL);\r
1160 Usage ();\r
1161 return STATUS_ERROR;\r
1162 }\r
1163 //\r
1164 // Assume output to stdout if not specified\r
1165 //\r
1166 if (mGlobals.OutFptr == NULL) {\r
1167 mGlobals.OutFptr = stdout;\r
1168 }\r
1169\r
1170 return STATUS_SUCCESS;\r
1171}\r
1172//\r
1173// Free the global string lists we allocated memory for\r
1174//\r
1175static\r
1176void\r
1177FreeLists (\r
1178 VOID\r
1179 )\r
1180{\r
1181 STRING_LIST *Temp;\r
1182 SYMBOL *NextSym;\r
1183\r
1184 //\r
1185 // printf ("Free lists.....");\r
1186 //\r
1187 // Traverse the include paths, freeing each\r
1188 // printf ("freeing include paths\n");\r
1189 //\r
1190 while (mGlobals.IncludePaths != NULL) {\r
1191 Temp = mGlobals.IncludePaths->Next;\r
1192 //\r
1193 // printf ("Freeing include path string '%s' at 0x%X\n",\r
1194 // mGlobals.IncludePaths->Str, (int)(mGlobals.IncludePaths->Str));\r
1195 //\r
1196 free (mGlobals.IncludePaths->Str);\r
1197 //\r
1198 // printf ("Freeing include path object at 0x%X\n", (int)(mGlobals.IncludePaths));\r
1199 //\r
1200 free (mGlobals.IncludePaths);\r
1201 mGlobals.IncludePaths = Temp;\r
1202 }\r
1203 //\r
1204 // Traverse the source files, freeing each\r
1205 //\r
1206 while (mGlobals.SourceFiles != NULL) {\r
1207 Temp = mGlobals.SourceFiles->Next;\r
1208 free (mGlobals.SourceFiles->Str);\r
1209 free (mGlobals.SourceFiles);\r
1210 mGlobals.SourceFiles = Temp;\r
1211 }\r
1212 //\r
1213 // Traverse the subdirectory list, freeing each\r
1214 //\r
1215 while (mGlobals.SubDirs != NULL) {\r
1216 Temp = mGlobals.SubDirs->Next;\r
1217 free (mGlobals.SubDirs->Str);\r
1218 free (mGlobals.SubDirs);\r
1219 mGlobals.SubDirs = Temp;\r
1220 }\r
1221 //\r
1222 // Free the symbol table\r
1223 //\r
1224 while (mGlobals.SymbolTable != NULL) {\r
1225 NextSym = mGlobals.SymbolTable->Next;\r
1226 free (mGlobals.SymbolTable->Name);\r
1227 free (mGlobals.SymbolTable->Value);\r
1228 mGlobals.SymbolTable = NextSym;\r
1229 }\r
1230 //\r
1231 // printf ("done\n");\r
1232 //\r
1233}\r
1234\r
1235static\r
1236void\r
1237Usage (\r
1238 VOID\r
1239 )\r
1240/*++\r
1241\r
1242Routine Description:\r
1243\r
1244 Print usage information for this utility.\r
1245 \r
1246Arguments:\r
1247\r
1248 None.\r
1249\r
1250Returns:\r
1251\r
1252 Nothing.\r
1253 \r
1254--*/\r
1255{\r
1256 int Index;\r
1257 static const char *Str[] = {\r
1258 UTILITY_NAME " -- make dependencies",\r
1259 " Usage: MakeDeps [options]",\r
1260 " Options include:",\r
1261 " -h or -? for this help information",\r
1262 " -f SourceFile add SourceFile to list of files to scan",\r
1263 " -i IncludePath add IncludePath to list of search paths",\r
1264 " -o OutputFile write output dependencies to OutputFile",\r
1265 " -s SubDir for each IncludePath, also search IncludePath\\SubDir",\r
1266 " -v for verbose output",\r
1267 " -ignorenotfound don't warn for files not found",\r
1268 " -target Target for single SourceFile, target is Target, not SourceFile.obj",\r
1269 " -q quiet mode to not report files not found if ignored",\r
1270 " -sub sym str replace all occurrances of 'str' with 'sym' in the output",\r
1271 " -nosystem not process system <include> files",\r
1272 " -neverfail always return a success return code",\r
1273 //\r
1274 // " -nodupes keep track of include files, don't rescan duplicates",\r
1275 //\r
1276 " -usesumdeps path use summary dependency files in 'path' directory.",\r
1277 "",\r
1278 NULL\r
1279 };\r
1280 for (Index = 0; Str[Index] != NULL; Index++) {\r
1281 fprintf (stdout, "%s\n", Str[Index]);\r
1282 }\r
1283}\r