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