]> git.proxmox.com Git - mirror_edk2.git/blame - Tools/CodeTools/TianoTools/MakeDeps/MakeDeps.c
Restructuring for better separation of Tool packages.
[mirror_edk2.git] / Tools / CodeTools / 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
93f5dd0a 289 fprintf(mGlobals.OutFptr, "\t\n"); // file ending flag\r
b09da165 290 fclose (mGlobals.OutFptr);\r
291 }\r
292\r
293 if (mGlobals.NeverFail) {\r
294 return STATUS_SUCCESS;\r
295 }\r
296 //\r
297 // If any errors, then delete our output so that it will get created\r
298 // again on a rebuild.\r
299 //\r
300 if ((GetUtilityStatus () == STATUS_ERROR) && (mGlobals.OutFileName != NULL)) {\r
301 remove (mGlobals.OutFileName);\r
302 }\r
303\r
304 return GetUtilityStatus ();\r
305}\r
306\r
307static\r
308STATUS\r
309ProcessFile (\r
310 INT8 *TargetFileName,\r
311 INT8 *FileName,\r
312 UINT32 NestDepth,\r
313 STRING_LIST *ProcessedFiles\r
314 )\r
315/*++\r
316\r
317Routine Description:\r
318\r
319 Given a source file name, open the file and parse all #include lines.\r
320 \r
321Arguments:\r
322\r
323 TargetFileName - name of the usually .obj target\r
324 FileName - name of the file to process\r
325 NestDepth - how deep we're nested in includes\r
326 ProcessedFiles - list of processed files.\r
327\r
328Returns:\r
329\r
330 standard status.\r
331 \r
332--*/\r
333{\r
334 FILE *Fptr;\r
335 INT8 Line[MAX_LINE_LEN];\r
336 INT8 *Cptr;\r
337 INT8 *EndPtr;\r
338 INT8 *SaveCptr;\r
339 INT8 EndChar;\r
340 INT8 FileNameCopy[MAX_PATH];\r
341 INT8 MacroIncludeFileName[MAX_LINE_LEN];\r
342 INT8 SumDepsFile[MAX_PATH];\r
343 STATUS Status;\r
344 UINT32 Index;\r
345 UINT32 LineNum;\r
346 STRING_LIST *ListPtr;\r
347\r
348 Status = STATUS_SUCCESS;\r
349 Fptr = NULL;\r
350 //\r
351 // Print the file being processed. Indent so you can tell the include nesting\r
352 // depth.\r
353 //\r
354 if (mGlobals.Verbose) {\r
355 fprintf (stdout, "%*cProcessing file '%s'\n", NestDepth * 2, ' ', FileName);\r
356 }\r
357 //\r
358 // If we're using summary dependency files, and a matching .dep file is\r
359 // found for this file, then just emit the summary dependency file as\r
360 // a dependency and return.\r
361 //\r
362 if (mGlobals.UseSumDeps) {\r
363 strcpy (SumDepsFile, mGlobals.SumDepsPath);\r
364 strcat (SumDepsFile, FileName);\r
365 for (Cptr = SumDepsFile + strlen (SumDepsFile) - 1;\r
52cbbdbc 366 (*Cptr != '\\' && *Cptr != '/') && (Cptr > SumDepsFile) && (*Cptr != '.');\r
b09da165 367 Cptr--\r
368 )\r
369 ;\r
370 if (*Cptr == '.') {\r
371 strcpy (Cptr, ".dep");\r
372 } else {\r
373 strcat (SumDepsFile, ".dep");\r
374 }\r
375 //\r
376 // See if the summary dep file exists. Could use _stat() function, but\r
377 // it's less portable.\r
378 //\r
379 if ((Fptr = fopen (SumDepsFile, "r")) != NULL) {\r
380 PrintDependency (TargetFileName, SumDepsFile);\r
381 return STATUS_SUCCESS;\r
382 }\r
383 }\r
384 //\r
385 // If we're not doing duplicates, and we've already seen this filename,\r
386 // then return\r
387 //\r
388 if (mGlobals.NoDupes) {\r
389 for (ListPtr = ProcessedFiles->Next; ListPtr != NULL; ListPtr = ListPtr->Next) {\r
390 if (stricmp (FileName, ListPtr->Str) == 0) {\r
391 break;\r
392 }\r
393 }\r
394 //\r
395 // If we found a match, we're done. If we didn't, create a new element\r
396 // and add it to the list.\r
397 //\r
398 if (ListPtr != NULL) {\r
399 //\r
400 // Print a message if verbose mode\r
401 //\r
402 if (mGlobals.Verbose) {\r
403 DebugMsg (NULL, 0, 0, FileName, "duplicate include -- not processed again");\r
404 }\r
405\r
406 return STATUS_SUCCESS;\r
407 }\r
408\r
409 ListPtr = malloc (sizeof (STRING_LIST));\r
410 ListPtr->Str = malloc (strlen (FileName) + 1);\r
411 strcpy (ListPtr->Str, FileName);\r
412 ListPtr->Next = ProcessedFiles->Next;\r
413 ProcessedFiles->Next = ListPtr;\r
414 }\r
415\r
416 //\r
417 // Make sure we didn't exceed our maximum nesting depth\r
418 //\r
419 if (NestDepth > MAX_NEST_DEPTH) {\r
420 Error (NULL, 0, 0, FileName, "max nesting depth exceeded on file");\r
421 goto Finish;\r
422 }\r
423 //\r
424 // Make a local copy of the filename. Then we can manipulate it\r
425 // if we have to.\r
426 //\r
427 strcpy (FileNameCopy, FileName);\r
428 //\r
429 // Try to open the file locally\r
430 //\r
431 if ((Fptr = fopen (FileNameCopy, "r")) == NULL) {\r
432 //\r
433 // Try to find it among the paths.\r
434 //\r
435 Fptr = FindFile (FileNameCopy, sizeof (FileNameCopy));\r
436 if (Fptr == NULL) {\r
437 //\r
438 // If this is not the top-level file, and the command-line argument\r
439 // said to ignore missing files, then return ok\r
440 //\r
441 if (NestDepth != START_NEST_DEPTH) {\r
442 if (mGlobals.IgnoreNotFound) {\r
443 if (!mGlobals.QuietMode) {\r
444 DebugMsg (NULL, 0, 0, FileNameCopy, "could not find file");\r
445 }\r
446\r
447 return STATUS_SUCCESS;\r
448 } else {\r
449 Error (NULL, 0, 0, FileNameCopy, "could not find file");\r
450 return STATUS_ERROR;\r
451 }\r
452 } else {\r
453 //\r
454 // Top-level (first) file. Emit an error.\r
455 //\r
456 Error (NULL, 0, 0, FileNameCopy, "could not find file");\r
457 return STATUS_ERROR;\r
458 }\r
459 }\r
460 }\r
461 //\r
462 // Print the dependency, with string substitution\r
463 //\r
464 PrintDependency (TargetFileName, FileNameCopy);\r
465\r
466 //\r
467 // Now read in lines and find all #include lines. Allow them to indent, and\r
468 // to put spaces between the # and include.\r
469 //\r
470 LineNum = 0;\r
471 while ((fgets (Line, sizeof (Line), Fptr) != NULL) && (Status == STATUS_SUCCESS)) {\r
472 LineNum++;\r
473 Cptr = Line;\r
474 //\r
475 // Skip preceeding spaces on the line\r
476 //\r
477 while (*Cptr && (isspace (*Cptr))) {\r
478 Cptr++;\r
479 }\r
480 //\r
481 // Check for # character\r
482 //\r
483 if (*Cptr == '#') {\r
484 Cptr++;\r
485 //\r
486 // Check for "include"\r
487 //\r
488 while (*Cptr && (isspace (*Cptr))) {\r
489 Cptr++;\r
490 }\r
491\r
492 if (strncmp (Cptr, "include", 7) == 0) {\r
493 //\r
494 // Skip over "include" and move on to filename as "file" or <file>\r
495 //\r
496 Cptr += 7;\r
497 while (*Cptr && (isspace (*Cptr))) {\r
498 Cptr++;\r
499 }\r
500\r
501 if (*Cptr == '<') {\r
502 EndChar = '>';\r
503 } else if (*Cptr == '"') {\r
504 EndChar = '"';\r
505 } else {\r
506 //\r
507 // Handle special #include MACRO_NAME(file)\r
508 // Set EndChar to null so we fall through on processing below.\r
509 //\r
510 EndChar = 0;\r
511 //\r
512 // Look for all the special include macros and convert accordingly.\r
513 //\r
514 for (Index = 0; mMacroConversion[Index].IncludeMacroName != NULL; Index++) {\r
515 //\r
516 // Save the start of the string in case some macros are substrings\r
517 // of others.\r
518 //\r
519 SaveCptr = Cptr;\r
520 if (strncmp (\r
521 Cptr,\r
522 mMacroConversion[Index].IncludeMacroName,\r
523 strlen (mMacroConversion[Index].IncludeMacroName)\r
524 ) == 0) {\r
525 //\r
526 // Skip over the macro name\r
527 //\r
528 Cptr += strlen (mMacroConversion[Index].IncludeMacroName);\r
529 //\r
530 // Skip over open parenthesis, blank spaces, then find closing\r
531 // parenthesis or blank space\r
532 //\r
533 while (*Cptr && (isspace (*Cptr))) {\r
534 Cptr++;\r
535 }\r
536\r
537 if (*Cptr == '(') {\r
538 Cptr++;\r
539 while (*Cptr && (isspace (*Cptr))) {\r
540 Cptr++;\r
541 }\r
542\r
543 EndPtr = Cptr;\r
544 while (*EndPtr && !isspace (*EndPtr) && (*EndPtr != ')')) {\r
545 EndPtr++;\r
546 }\r
547\r
548 *EndPtr = 0;\r
549 //\r
550 // Create the path\r
551 //\r
552 strcpy (MacroIncludeFileName, mMacroConversion[Index].PathName);\r
553 strcat (MacroIncludeFileName, Cptr);\r
52cbbdbc 554 strcat (MacroIncludeFileName, "/");\r
b09da165 555 strcat (MacroIncludeFileName, Cptr);\r
556 strcat (MacroIncludeFileName, ".h");\r
557 //\r
558 // Process immediately, then break out of the outside FOR loop.\r
559 //\r
560 Status = ProcessFile (TargetFileName, MacroIncludeFileName, NestDepth + 1, ProcessedFiles);\r
561 break;\r
562 }\r
563 }\r
564 //\r
565 // Restore the start\r
566 //\r
567 Cptr = SaveCptr;\r
568 }\r
569 //\r
570 // Don't recognize the include line? Ignore it. We assume that the\r
571 // file compiles anyway.\r
572 //\r
573 if (mMacroConversion[Index].IncludeMacroName == NULL) {\r
574 //\r
575 // Warning (FileNameCopy, LineNum, 0, "could not parse line", NULL);\r
576 // Status = STATUS_WARNING;\r
577 //\r
578 }\r
579 }\r
580 //\r
581 // Process "normal" includes. If the endchar is 0, then the\r
582 // file has already been processed. Otherwise look for the\r
583 // endchar > or ", and process the include file.\r
584 //\r
585 if (EndChar != 0) {\r
586 Cptr++;\r
587 EndPtr = Cptr;\r
588 while (*EndPtr && (*EndPtr != EndChar)) {\r
589 EndPtr++;\r
590 }\r
591\r
592 if (*EndPtr == EndChar) {\r
593 //\r
594 // If we're processing it, do it\r
595 //\r
596 if ((EndChar != '>') || (!mGlobals.NoSystem)) {\r
597 //\r
598 // Null terminate the filename and try to process it.\r
599 //\r
600 *EndPtr = 0;\r
601 Status = ProcessFile (TargetFileName, Cptr, NestDepth + 1, ProcessedFiles);\r
602 }\r
603 } else {\r
604 Warning (FileNameCopy, LineNum, 0, "malformed include", "missing closing %c", EndChar);\r
605 Status = STATUS_WARNING;\r
606 goto Finish;\r
607 }\r
608 }\r
609 }\r
610 }\r
611 }\r
612\r
613Finish:\r
614 //\r
615 // Close open files and return status\r
616 //\r
617 if (Fptr != NULL) {\r
618 fclose (Fptr);\r
619 }\r
620\r
621 return Status;\r
622}\r
623\r
624static\r
625void\r
626PrintDependency (\r
627 INT8 *TargetFileName,\r
628 INT8 *DependentFile\r
629 )\r
630/*++\r
631\r
632Routine Description:\r
633\r
634 Given a target (.obj) file name, and a dependent file name, do any string\r
635 substitutions (per the command line options) on the file names, then\r
636 print the dependency line of form:\r
637 \r
638 TargetFileName : DependentFile\r
639 \r
640Arguments:\r
641\r
642 TargetFileName - build target file name\r
643 DependentFile - file on which TargetFileName depends\r
644\r
645Returns:\r
646\r
647 None\r
648 \r
649--*/\r
650{\r
651 INT8 Str[MAX_PATH];\r
652\r
653 //\r
654 // Go through the symbols and do replacements\r
655 //\r
b09da165 656 strcpy (Str, DependentFile);\r
657 ReplaceSymbols (Str, sizeof (Str));\r
658 fprintf (mGlobals.OutFptr, "%s\n", Str);\r
659}\r
660\r
661static\r
662void\r
663ReplaceSymbols (\r
664 INT8 *Str,\r
665 UINT32 StrSize\r
666 )\r
667{\r
668 SYMBOL *Sym;\r
669 INT8 StrCopy[MAX_LINE_LEN];\r
670 INT8 *From;\r
671 INT8 *To;\r
672 BOOLEAN Replaced;\r
673\r
674 //\r
675 // Go through the entire string to look for replacement strings at\r
676 // every position.\r
677 //\r
678 From = Str;\r
679 To = StrCopy;\r
680 while (*From) {\r
681 //\r
682 // Copy the character\r
683 //\r
684 *To = *From;\r
685 Replaced = FALSE;\r
686 //\r
687 // Go through each symbol and try to find a string substitution\r
688 //\r
689 Sym = mGlobals.SymbolTable;\r
690 while (Sym != NULL) {\r
691 if (strnicmp (From, Sym->Value, strlen (Sym->Value)) == 0) {\r
692 //\r
693 // Replace the string, then advance the pointers past the\r
694 // replaced strings\r
695 //\r
696 strcpy (To, Sym->Name);\r
697 To += strlen (Sym->Name);\r
698 From += strlen (Sym->Value);\r
699 Replaced = TRUE;\r
700 //\r
701 // Break from the while()\r
702 //\r
703 break;\r
704 } else {\r
705 Sym = Sym->Next;\r
706 }\r
707 }\r
708\r
709 if (!Replaced) {\r
710 From++;\r
711 To++;\r
712 }\r
713 }\r
714 //\r
715 // Null terminate, and return it\r
716 //\r
717 *To = 0;\r
718 if (strlen (StrCopy) < StrSize) {\r
719 strcpy (Str, StrCopy);\r
720 }\r
721}\r
722//\r
723// Given a filename, try to find it along the include paths.\r
724//\r
725static\r
726FILE *\r
727FindFile (\r
728 INT8 *FileName,\r
729 UINT32 FileNameLen\r
730 )\r
731{\r
732 FILE *Fptr;\r
733 STRING_LIST *List;\r
734 STRING_LIST *SubDir;\r
735 INT8 FullFileName[MAX_PATH * 2];\r
736\r
737 //\r
738 // Traverse the list of paths and try to find the file\r
739 //\r
740 List = mGlobals.IncludePaths;\r
741 while (List != NULL) {\r
742 //\r
743 // Put the path and filename together\r
744 //\r
745 if (strlen (List->Str) + strlen (FileName) + 1 > sizeof (FullFileName)) {\r
746 Error (\r
747 __FILE__,\r
748 __LINE__,\r
749 0,\r
750 "application error",\r
751 "cannot concatenate '%s' + '%s'",\r
752 List->Str,\r
753 FileName\r
754 );\r
755 return NULL;\r
756 }\r
757 //\r
758 // Append the filename to this include path and try to open the file.\r
759 //\r
760 strcpy (FullFileName, List->Str);\r
761 strcat (FullFileName, FileName);\r
762 if ((Fptr = fopen (FullFileName, "r")) != NULL) {\r
763 //\r
764 // Return the file name\r
765 //\r
766 if (FileNameLen <= strlen (FullFileName)) {\r
767 Error (__FILE__, __LINE__, 0, "application error", "internal path name of insufficient length");\r
768 //\r
769 // fprintf (stdout, "File length > %d: %s\n", FileNameLen, FullFileName);\r
770 //\r
771 return NULL;\r
772 }\r
773\r
774 strcpy (FileName, FullFileName);\r
775 return Fptr;\r
776 }\r
777 //\r
778 // Didn't find it there. Now try this directory with every subdirectory\r
779 // the user specified on the command line\r
780 //\r
781 for (SubDir = mGlobals.SubDirs; SubDir != NULL; SubDir = SubDir->Next) {\r
782 strcpy (FullFileName, List->Str);\r
783 strcat (FullFileName, SubDir->Str);\r
784 strcat (FullFileName, FileName);\r
785 if ((Fptr = fopen (FullFileName, "r")) != NULL) {\r
786 //\r
787 // Return the file name\r
788 //\r
789 if (FileNameLen <= strlen (FullFileName)) {\r
790 Error (__FILE__, __LINE__, 0, "application error", "internal path name of insufficient length");\r
791 return NULL;\r
792 }\r
793\r
794 strcpy (FileName, FullFileName);\r
795 return Fptr;\r
796 }\r
797 }\r
798\r
799 List = List->Next;\r
800 }\r
801 //\r
802 // Not found\r
803 //\r
804 return NULL;\r
805}\r
806//\r
807// Process the command-line arguments\r
808//\r
809static\r
810STATUS\r
811ProcessArgs (\r
812 int Argc,\r
813 char *Argv[]\r
814 )\r
815{\r
816 STRING_LIST *NewList;\r
817 STRING_LIST *LastIncludePath;\r
818 STRING_LIST *LastSourceFile;\r
819 SYMBOL *Symbol;\r
820 int Index;\r
821 //\r
822 // Clear our globals\r
823 //\r
824 memset ((char *) &mGlobals, 0, sizeof (mGlobals));\r
825 mGlobals.NoDupes = TRUE;\r
826 //\r
827 // Skip program name\r
828 //\r
829 Argc--;\r
830 Argv++;\r
831 //\r
832 // Initialize locals\r
833 //\r
834 LastIncludePath = NULL;\r
835 LastSourceFile = NULL;\r
836 //\r
837 // Process until no more args\r
838 //\r
839 while (Argc) {\r
840 //\r
841 // -i path add include search path\r
842 //\r
843 if (stricmp (Argv[0], "-i") == 0) {\r
844 //\r
845 // check for one more arg\r
846 //\r
847 if (Argc > 1) {\r
848 //\r
849 // Allocate memory for a new list element, fill it in, and\r
850 // add it to our list of include paths. Always make sure it\r
851 // has a "\" on the end of it.\r
852 //\r
853 NewList = malloc (sizeof (STRING_LIST));\r
854 if (NewList == NULL) {\r
855 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
856 return STATUS_ERROR;\r
857 }\r
858\r
859 NewList->Next = NULL;\r
860 NewList->Str = malloc (strlen (Argv[1]) + 2);\r
861 if (NewList->Str == NULL) {\r
862 free (NewList);\r
863 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
864 return STATUS_ERROR;\r
865 }\r
866\r
867 strcpy (NewList->Str, Argv[1]);\r
52cbbdbc 868 if (NewList->Str[strlen (NewList->Str) - 1] != '\\' && NewList->Str[strlen (NewList->Str) - 1] != '/') {\r
869 strcat (NewList->Str, "/");\r
b09da165 870 }\r
871 //\r
872 // Add it to the end of the our list of include paths\r
873 //\r
874 if (mGlobals.IncludePaths == NULL) {\r
875 mGlobals.IncludePaths = NewList;\r
876 } else {\r
877 LastIncludePath->Next = NewList;\r
878 }\r
879\r
880 LastIncludePath = NewList;\r
881 //\r
882 // fprintf (stdout, "Added path: %s\n", NewList->Str);\r
883 //\r
884 } else {\r
885 Error (NULL, 0, 0, Argv[0], "option requires an include path");\r
886 Usage ();\r
887 return STATUS_ERROR;\r
888 }\r
889\r
890 Argc--;\r
891 Argv++;\r
892 } else if (stricmp (Argv[0], "-f") == 0) {\r
893 //\r
894 // Check for one more arg\r
895 //\r
896 if (Argc > 1) {\r
897 //\r
898 // Allocate memory for a new list element, fill it in, and\r
899 // add it to our list of source files.\r
900 //\r
901 NewList = malloc (sizeof (STRING_LIST));\r
902 if (NewList == NULL) {\r
903 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
904 return STATUS_ERROR;\r
905 }\r
906\r
907 NewList->Next = NULL;\r
908 //\r
909 // Allocate space to replace ".c" with ".obj", plus null termination\r
910 //\r
911 NewList->Str = malloc (strlen (Argv[1]) + 5);\r
912 if (NewList->Str == NULL) {\r
913 free (NewList);\r
914 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
915 return STATUS_ERROR;\r
916 }\r
917\r
918 strcpy (NewList->Str, Argv[1]);\r
919 if (mGlobals.SourceFiles == NULL) {\r
920 mGlobals.SourceFiles = NewList;\r
921 } else {\r
922 LastSourceFile->Next = NewList;\r
923 }\r
924\r
925 LastSourceFile = NewList;\r
926 } else {\r
927 Error (NULL, 0, 0, Argv[0], "option requires a file name");\r
928 Usage ();\r
929 return STATUS_ERROR;\r
930 }\r
931 //\r
932 // The C compiler first looks for #include files in the directory where\r
933 // the source file came from. Add the file's source directory to the\r
934 // list of include paths.\r
935 //\r
936 NewList = malloc (sizeof (STRING_LIST));\r
937 if (NewList == NULL) {\r
938 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
939 return STATUS_ERROR;\r
940 }\r
941\r
942 NewList->Next = NULL;\r
943 NewList->Str = malloc (strlen (Argv[1]) + 3);\r
944 if (NewList->Str == NULL) {\r
945 free (NewList);\r
946 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
947 return STATUS_ERROR;\r
948 }\r
949\r
950 strcpy (NewList->Str, Argv[1]);\r
951 //\r
952 // Back up in the source file name to the last backslash and terminate after it.\r
953 //\r
52cbbdbc 954 for (Index = strlen (NewList->Str) - 1; (Index > 0) && (NewList->Str[Index] != '\\' && NewList->Str[Index] != '/'); Index--)\r
b09da165 955 ;\r
956 if (Index < 0) {\r
52cbbdbc 957 strcpy (NewList->Str, "./");\r
b09da165 958 } else {\r
959 NewList->Str[Index + 1] = 0;\r
960 }\r
961 //\r
962 // Add it to the end of the our list of include paths\r
963 //\r
964 if (mGlobals.IncludePaths == NULL) {\r
965 mGlobals.IncludePaths = NewList;\r
966 } else {\r
967 LastIncludePath->Next = NewList;\r
968 }\r
969\r
970 if (mGlobals.Verbose) {\r
971 fprintf (stdout, "Adding include path: %s\n", NewList->Str);\r
972 }\r
973\r
974 LastIncludePath = NewList;\r
975 Argc--;\r
976 Argv++;\r
977 } else if (stricmp (Argv[0], "-s") == 0) {\r
978 //\r
979 // -s subdir add subdirectory subdir to list of subdirecties to scan.\r
980 // Check for one more arg first.\r
981 //\r
982 if (Argc > 1) {\r
983 //\r
984 // Allocate memory for a new list element, fill it in, and\r
985 // add it to our list of subdirectory include paths. Always\r
986 // make sure it has a "\" on the end of it.\r
987 //\r
988 NewList = malloc (sizeof (STRING_LIST));\r
989 if (NewList == NULL) {\r
990 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
991 return STATUS_ERROR;\r
992 }\r
993\r
994 NewList->Str = malloc (strlen (Argv[1]) + 2);\r
995 if (NewList->Str == NULL) {\r
996 free (NewList);\r
997 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
998 return STATUS_ERROR;\r
999 }\r
1000\r
1001 strcpy (NewList->Str, Argv[1]);\r
52cbbdbc 1002 if (NewList->Str[strlen (NewList->Str) - 1] != '\\' && NewList->Str[strlen (NewList->Str) - 1] != '/') {\r
1003 strcat (NewList->Str, "/");\r
b09da165 1004 }\r
1005\r
1006 NewList->Next = mGlobals.SubDirs;\r
1007 mGlobals.SubDirs = NewList;\r
1008 } else {\r
1009 Error (NULL, 0, 0, Argv[0], "option requires a subdirectory name");\r
1010 Usage ();\r
1011 return STATUS_ERROR;\r
1012 }\r
1013\r
1014 Argc--;\r
1015 Argv++;\r
1016 } else if (stricmp (Argv[0], "-sub") == 0) {\r
1017 //\r
1018 // -sub symname symvalue to do string substitution in the output\r
1019 //\r
1020 if (Argc > 2) {\r
1021 //\r
1022 // Allocate memory for the symbol object\r
1023 //\r
1024 Symbol = malloc (sizeof (SYMBOL));\r
1025 if (Symbol == NULL) {\r
1026 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
1027 return STATUS_ERROR;\r
1028 }\r
1029 //\r
1030 // Allocate memory for the symbol name and value, then save copies\r
1031 //\r
1032 Symbol->Name = malloc (strlen (Argv[1]) + 1);\r
1033 if (Symbol->Name == NULL) {\r
1034 free (Symbol);\r
1035 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
1036 return STATUS_ERROR;\r
1037 }\r
1038\r
1039 strcpy (Symbol->Name, Argv[1]);\r
1040 Symbol->Value = malloc (strlen (Argv[2]) + 1);\r
1041 if (Symbol->Value == NULL) {\r
1042 free (Symbol->Name);\r
1043 free (Symbol);\r
1044 Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
1045 return STATUS_ERROR;\r
1046 }\r
1047\r
1048 strcpy (Symbol->Value, Argv[2]);\r
1049 //\r
1050 // Add it to the list\r
1051 //\r
1052 Symbol->Next = mGlobals.SymbolTable;\r
1053 mGlobals.SymbolTable = Symbol;\r
1054 } else {\r
1055 Error (NULL, 0, 0, Argv[0], "option requires a symbol name and value");\r
1056 Usage ();\r
1057 return STATUS_ERROR;\r
1058 }\r
1059 //\r
1060 // Skip over args\r
1061 //\r
1062 Argc -= 2;\r
1063 Argv += 2;\r
1064 } else if (stricmp (Argv[0], "-nosystem") == 0) {\r
1065 mGlobals.NoSystem = TRUE;\r
1066 } else if (stricmp (Argv[0], "-nodupes") == 0) {\r
1067 mGlobals.NoDupes = TRUE;\r
1068 } else if (stricmp (Argv[0], "-nodups") == 0) {\r
1069 mGlobals.NoDupes = TRUE;\r
1070 } else if (stricmp (Argv[0], "-target") == 0) {\r
1071 //\r
1072 // -target TargetFileName - Target object file (only one allowed right\r
1073 // now) is TargetFileName rather than SourceFile.obj\r
1074 //\r
1075 if (Argc > 1) {\r
1076 strcpy (mGlobals.TargetFileName, Argv[1]);\r
1077 } else {\r
1078 Error (NULL, 0, 0, Argv[0], "option requires a target file name");\r
1079 Usage ();\r
1080 return STATUS_ERROR;\r
1081 }\r
1082\r
1083 Argc--;\r
1084 Argv++;\r
1085 } else if (stricmp (Argv[0], "-usesumdeps") == 0) {\r
1086 //\r
1087 // -usesumdeps Path - if we find an included file xxx.h, and file\r
1088 // Path/xxx.dep exists, list Path/xxx.dep as a dependency rather than\r
1089 // xxx.h and don't parse xxx.h. This allows you to create a dependency\r
1090 // file for a commonly included file, and have its dependency file updated\r
1091 // only if its included files are updated. Then anyone else including this\r
1092 // common include file can simply have a dependency on that file's .dep file\r
1093 // rather than on all the files included by it. Confusing enough?\r
1094 //\r
1095 mGlobals.UseSumDeps = 1;\r
1096 if (Argc > 1) {\r
1097 strcpy (mGlobals.SumDepsPath, Argv[1]);\r
1098 //\r
1099 // Add slash on end if not there\r
1100 //\r
52cbbdbc 1101 if (mGlobals.SumDepsPath[strlen (mGlobals.SumDepsPath) - 1] != '\\' && mGlobals.SumDepsPath[strlen (mGlobals.SumDepsPath) - 1] != '/') {\r
1102 strcat (mGlobals.SumDepsPath, "/");\r
b09da165 1103 }\r
1104 } else {\r
1105 Error (NULL, 0, 0, Argv[0], "option requires path to summary dependency files");\r
1106 Usage ();\r
1107 return STATUS_ERROR;\r
1108 }\r
1109\r
1110 Argc--;\r
1111 Argv++;\r
1112\r
1113 } else if (stricmp (Argv[0], "-o") == 0) {\r
1114 //\r
1115 // -o OutputFileName - specify an output filename for dependency list\r
1116 // check for one more arg\r
1117 //\r
1118 if (Argc > 1) {\r
1119 //\r
1120 // Try to open the file\r
1121 //\r
1122 if ((mGlobals.OutFptr = fopen (Argv[1], "w")) == NULL) {\r
1123 Error (NULL, 0, 0, Argv[1], "could not open file for writing");\r
1124 return STATUS_ERROR;\r
1125 }\r
1126\r
1127 mGlobals.OutFileName = Argv[1];\r
1128 } else {\r
1129 Error (NULL, 0, 0, Argv[0], "option requires output file name");\r
1130 Usage ();\r
1131 return STATUS_ERROR;\r
1132 }\r
1133\r
1134 Argc--;\r
1135 Argv++;\r
1136 } else if (stricmp (Argv[0], "-v") == 0) {\r
1137 mGlobals.Verbose = TRUE;\r
1138 } else if (stricmp (Argv[0], "-neverfail") == 0) {\r
1139 mGlobals.NeverFail = TRUE;\r
1140 } else if (stricmp (Argv[0], "-q") == 0) {\r
1141 mGlobals.QuietMode = TRUE;\r
1142 } else if (stricmp (Argv[0], "-ignorenotfound") == 0) {\r
1143 mGlobals.IgnoreNotFound = TRUE;\r
1144 } else if ((stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) {\r
1145 Usage ();\r
1146 return STATUS_ERROR;\r
1147 } else {\r
1148 Error (NULL, 0, 0, Argv[0], "unrecognized option");\r
1149 Usage ();\r
1150 return STATUS_ERROR;\r
1151 }\r
1152\r
1153 Argc--;\r
1154 Argv++;\r
1155 }\r
1156 //\r
1157 // Had to specify at least one source file\r
1158 //\r
1159 if (mGlobals.SourceFiles == NULL) {\r
1160 Error (NULL, 0, 0, "must specify one source file name", NULL);\r
1161 Usage ();\r
1162 return STATUS_ERROR;\r
1163 }\r
1164 //\r
1165 // Assume output to stdout if not specified\r
1166 //\r
1167 if (mGlobals.OutFptr == NULL) {\r
1168 mGlobals.OutFptr = stdout;\r
1169 }\r
1170\r
1171 return STATUS_SUCCESS;\r
1172}\r
1173//\r
1174// Free the global string lists we allocated memory for\r
1175//\r
1176static\r
1177void\r
1178FreeLists (\r
1179 VOID\r
1180 )\r
1181{\r
1182 STRING_LIST *Temp;\r
1183 SYMBOL *NextSym;\r
1184\r
1185 //\r
1186 // printf ("Free lists.....");\r
1187 //\r
1188 // Traverse the include paths, freeing each\r
1189 // printf ("freeing include paths\n");\r
1190 //\r
1191 while (mGlobals.IncludePaths != NULL) {\r
1192 Temp = mGlobals.IncludePaths->Next;\r
1193 //\r
1194 // printf ("Freeing include path string '%s' at 0x%X\n",\r
1195 // mGlobals.IncludePaths->Str, (int)(mGlobals.IncludePaths->Str));\r
1196 //\r
1197 free (mGlobals.IncludePaths->Str);\r
1198 //\r
1199 // printf ("Freeing include path object at 0x%X\n", (int)(mGlobals.IncludePaths));\r
1200 //\r
1201 free (mGlobals.IncludePaths);\r
1202 mGlobals.IncludePaths = Temp;\r
1203 }\r
1204 //\r
1205 // Traverse the source files, freeing each\r
1206 //\r
1207 while (mGlobals.SourceFiles != NULL) {\r
1208 Temp = mGlobals.SourceFiles->Next;\r
1209 free (mGlobals.SourceFiles->Str);\r
1210 free (mGlobals.SourceFiles);\r
1211 mGlobals.SourceFiles = Temp;\r
1212 }\r
1213 //\r
1214 // Traverse the subdirectory list, freeing each\r
1215 //\r
1216 while (mGlobals.SubDirs != NULL) {\r
1217 Temp = mGlobals.SubDirs->Next;\r
1218 free (mGlobals.SubDirs->Str);\r
1219 free (mGlobals.SubDirs);\r
1220 mGlobals.SubDirs = Temp;\r
1221 }\r
1222 //\r
1223 // Free the symbol table\r
1224 //\r
1225 while (mGlobals.SymbolTable != NULL) {\r
1226 NextSym = mGlobals.SymbolTable->Next;\r
1227 free (mGlobals.SymbolTable->Name);\r
1228 free (mGlobals.SymbolTable->Value);\r
1229 mGlobals.SymbolTable = NextSym;\r
1230 }\r
1231 //\r
1232 // printf ("done\n");\r
1233 //\r
1234}\r
1235\r
1236static\r
1237void\r
1238Usage (\r
1239 VOID\r
1240 )\r
1241/*++\r
1242\r
1243Routine Description:\r
1244\r
1245 Print usage information for this utility.\r
1246 \r
1247Arguments:\r
1248\r
1249 None.\r
1250\r
1251Returns:\r
1252\r
1253 Nothing.\r
1254 \r
1255--*/\r
1256{\r
1257 int Index;\r
1258 static const char *Str[] = {\r
1259 UTILITY_NAME " -- make dependencies",\r
1260 " Usage: MakeDeps [options]",\r
1261 " Options include:",\r
1262 " -h or -? for this help information",\r
1263 " -f SourceFile add SourceFile to list of files to scan",\r
1264 " -i IncludePath add IncludePath to list of search paths",\r
1265 " -o OutputFile write output dependencies to OutputFile",\r
1266 " -s SubDir for each IncludePath, also search IncludePath\\SubDir",\r
1267 " -v for verbose output",\r
1268 " -ignorenotfound don't warn for files not found",\r
1269 " -target Target for single SourceFile, target is Target, not SourceFile.obj",\r
1270 " -q quiet mode to not report files not found if ignored",\r
1271 " -sub sym str replace all occurrances of 'str' with 'sym' in the output",\r
1272 " -nosystem not process system <include> files",\r
1273 " -neverfail always return a success return code",\r
1274 //\r
1275 // " -nodupes keep track of include files, don't rescan duplicates",\r
1276 //\r
1277 " -usesumdeps path use summary dependency files in 'path' directory.",\r
1278 "",\r
1279 NULL\r
1280 };\r
1281 for (Index = 0; Str[Index] != NULL; Index++) {\r
1282 fprintf (stdout, "%s\n", Str[Index]);\r
1283 }\r
1284}\r