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