Don't preload rarely seen large images
[chromium-blink-merge.git] / third_party / codesighs / msdump2symdb.c
blob705c3c41739729f27feee30cced9264a81892519
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is msdump2symdb.c code, released
17 * Jan 16, 2003.
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 2002
22 * the Initial Developer. All Rights Reserved.
24 * Contributor(s):
25 * Garrett Arch Blythe, 16-January-2003
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <time.h>
45 #include <ctype.h>
46 #include <errno.h>
48 #define ERROR_REPORT(num, val, msg) fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
49 #define CLEANUP(ptr) do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
52 typedef struct __struct_Options
54 ** Options to control how we perform.
56 ** mProgramName Used in help text.
57 ** mInput File to read for input.
58 ** Default is stdin.
59 ** mInputName Name of the file.
60 ** mOutput Output file, append.
61 ** Default is stdout.
62 ** mOutputName Name of the file.
63 ** mHelp Whether or not help should be shown.
66 const char* mProgramName;
67 FILE* mInput;
68 char* mInputName;
69 FILE* mOutput;
70 char* mOutputName;
71 int mHelp;
73 Options;
76 typedef struct __struct_Switch
78 ** Command line options.
81 const char* mLongName;
82 const char* mShortName;
83 int mHasValue;
84 const char* mValue;
85 const char* mDescription;
87 Switch;
89 #define DESC_NEWLINE "\n\t\t"
91 static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."};
92 static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."};
93 static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."};
95 static Switch* gSwitches[] = {
96 &gInputSwitch,
97 &gOutputSwitch,
98 &gHelpSwitch
102 typedef struct __struct_MSDump_Symbol
104 ** Struct to hold infomration on a symbol.
106 ** mSize Size of the symbol once all work is complete.
107 ** mOffset Offset of the symbol in the section.
108 ** mName Symbolic name.
111 unsigned mSize;
112 unsigned mOffset;
113 char* mName;
115 MSDump_Symbol;
118 typedef struct __struct_MSDump_Section
120 ** Struct for holding information on a section.
122 ** mLength Length of the section in bytes.
123 ** mUsed Number of bytes used in the section thus far.
124 ** Should eventually match mLength after work is done.
125 ** mType Type of section, as string (.data, .text, et. al.)
126 ** mSymbols Symbols found inside the section.
127 ** mSymbolCount Number of symbols in array.
130 unsigned mLength;
131 unsigned mUsed;
132 char* mType;
134 MSDump_Symbol* mSymbols;
135 unsigned mSymbolCount;
137 MSDump_Section;
140 typedef struct __struct_MSDump_Object
142 ** Struct for holding object's data.
145 char* mObject;
147 MSDump_Section* mSections;
148 unsigned mSectionCount;
150 MSDump_Object;
153 typedef struct __struct_MSDump_ReadState
155 ** State flags while reading the input gives us hints on what to do.
157 ** mSkipLines Number of lines to skip without parsing.
158 ** mSectionDetails Section information next, like line length.
159 ** mCurrentObject Object file we are dealing with.
162 unsigned mSkipLines;
163 unsigned mSectionDetails;
164 MSDump_Object* mCurrentObject;
166 MSDump_ReadState;
169 typedef struct __struct_MSDump_Container
171 ** Umbrella container for all data encountered.
174 MSDump_ReadState mReadState;
176 MSDump_Object* mObjects;
177 unsigned mObjectCount;
179 MSDump_Container;
182 void trimWhite(char* inString)
184 ** Remove any whitespace from the end of the string.
187 int len = strlen(inString);
189 while(len)
191 len--;
193 if(isspace(*(inString + len)))
195 *(inString + len) = '\0';
197 else
199 break;
205 const char* skipWhite(const char* inString)
207 ** Return pointer to first non white space character.
210 const char* retval = inString;
212 while('\0' != *retval && isspace(*retval))
214 retval++;
217 return retval;
221 const char* skipNonWhite(const char* inString)
223 ** Return pointer to first white space character.
226 const char* retval = inString;
228 while('\0' != *retval && !isspace(*retval))
230 retval++;
233 return retval;
237 void slash2bs(char* inString)
239 ** Change any forward slash to a backslash.
242 char* slash = inString;
244 while(NULL != (slash = strchr(slash, '/')))
246 *slash = '\\';
247 slash++;
252 const char* skipToArg(const char* inString, unsigned inArgIndex)
254 ** Return pointer either to the arg or NULL.
255 ** 1 indexed.
258 const char* retval = NULL;
260 while(0 != inArgIndex && '\0' != *inString)
262 inArgIndex--;
264 inString = skipWhite(inString);
265 if(0 != inArgIndex)
267 inString = skipNonWhite(inString);
271 if('\0' != *inString)
273 retval = inString;
276 return retval;
280 const char* getLastArg(const char* inString)
282 ** Return pointer to last arg in string.
285 const char* retval = NULL;
286 int length = 0;
287 int sawString = 0;
289 length = strlen(inString);
290 while(0 != length)
292 length--;
294 if(0 == sawString)
296 if(0 == isspace(inString[length]))
298 sawString = __LINE__;
301 else
303 if(0 != isspace(inString[length]))
305 retval = inString + length + 1;
310 return retval;
314 int processLine(Options* inOptions, MSDump_Container* inContainer, const char* inLine)
316 ** Handle one line at a time.
317 ** Looking for several different types of lines.
318 ** Ignore all other lines.
319 ** The container is the state machine.
320 ** returns 0 on no error.
323 int retval = 0;
326 ** Check to see if we were expecting section details.
328 if(0 != inContainer->mReadState.mSectionDetails)
330 const char* length = NULL;
331 unsigned sectionIndex = 0;
334 ** Detail is a 1 based index....
335 ** Reset.
337 sectionIndex = inContainer->mReadState.mSectionDetails - 1;
338 inContainer->mReadState.mSectionDetails = 0;
340 if(0 == strncmp(" Section length", inLine, 18))
342 const char* sectionLength = NULL;
343 unsigned numericLength = 0;
344 char* endScan = NULL;
346 sectionLength = skipWhite(inLine + 18);
348 errno = 0;
349 numericLength = strtoul(sectionLength, &endScan, 16);
350 if(0 == errno && endScan != sectionLength)
352 inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mLength = numericLength;
354 else
356 retval = __LINE__;
357 ERROR_REPORT(retval, inLine, "Cannot scan for section length.");
360 else
362 retval = __LINE__;
363 ERROR_REPORT(retval, inLine, "Cannot parse section line.");
367 ** Check for switching object file symbols.
369 else if(0 == strncmp("Dump of file ", inLine, 13))
371 const char* dupMe = inLine + 13;
372 char* dup = NULL;
374 dup = strdup(dupMe);
375 if(NULL != dup)
377 void* growth = NULL;
379 trimWhite(dup);
380 slash2bs(dup);
383 growth = realloc(inContainer->mObjects, (inContainer->mObjectCount + 1) * sizeof(MSDump_Object));
384 if(NULL != growth)
386 unsigned int index = inContainer->mObjectCount;
388 inContainer->mObjectCount++;
389 inContainer->mObjects = growth;
390 memset(inContainer->mObjects + index, 0, sizeof(MSDump_Object));
392 inContainer->mObjects[index].mObject = dup;
395 ** Reset the read state for this new object.
397 memset(&inContainer->mReadState, 0, sizeof(MSDump_ReadState));
400 ** Record our current object file.
402 inContainer->mReadState.mCurrentObject = inContainer->mObjects + index;
405 ** We can skip a few lines.
407 inContainer->mReadState.mSkipLines = 4;
409 else
411 retval = __LINE__;
412 ERROR_REPORT(retval, dup, "Unable to grow object array.");
413 free(dup);
416 else
418 retval = __LINE__;
419 ERROR_REPORT(retval, dupMe, "Unable to copy string.");
424 ** Check for a symbol dump or a section header.
426 else if(isxdigit(*inLine) && isxdigit(*(inLine + 1)) && isxdigit(*(inLine + 2)))
428 const char* sectionString = NULL;
431 ** Determine the section for this line.
432 ** Ignore DEBUG sections.
434 sectionString = skipToArg(inLine, 3);
435 if(NULL != sectionString)
437 if(0 != strncmp(sectionString, "DEBUG", 5) && 0 != strncmp(sectionString, "ABS", 3) && 0 != strncmp(sectionString, "UNDEF", 5))
440 ** MUST start with "SECT"
442 if(0 == strncmp(sectionString, "SECT", 4))
444 unsigned sectionIndex1 = 0;
446 char *endScan = NULL;
448 sectionString += 4;
451 ** Convert the remaining string to an index.
452 ** It will be 1 based.
454 errno = 0;
455 sectionIndex1 = strtoul(sectionString, &endScan, 16);
456 if(0 == errno && endScan != sectionString && 0 != sectionIndex1)
458 unsigned sectionIndex = sectionIndex1 - 1;
461 ** Is this a new section? Assumed to be ascending.
462 ** Or is this a symbol in the section?
464 if(sectionIndex1 > inContainer->mReadState.mCurrentObject->mSectionCount)
466 const char* typeArg = NULL;
469 ** New Section, figure out the type.
471 typeArg = skipToArg(sectionString, 5);
472 if(NULL != typeArg)
474 char* typeDup = NULL;
477 ** Skip the leading period before duping.
479 if('.' == *typeArg)
481 typeArg++;
483 typeDup = strdup(typeArg);
485 if(NULL != typeDup)
487 void* moved = NULL;
488 char* nonWhite = NULL;
491 ** Terminate the duplicate after the section type.
493 nonWhite = (char*)skipNonWhite(typeDup);
494 if(NULL != nonWhite)
496 *nonWhite = '\0';
500 ** Create more space for the section in the object...
502 moved = realloc(inContainer->mReadState.mCurrentObject->mSections, sizeof(MSDump_Section) * sectionIndex1);
503 if(NULL != moved)
505 unsigned oldCount = inContainer->mReadState.mCurrentObject->mSectionCount;
507 inContainer->mReadState.mCurrentObject->mSections = (MSDump_Section*)moved;
508 inContainer->mReadState.mCurrentObject->mSectionCount = sectionIndex1;
509 memset(&inContainer->mReadState.mCurrentObject->mSections[oldCount], 0, sizeof(MSDump_Section) * (sectionIndex1 - oldCount));
512 ** Other section details.
514 inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mType = typeDup;
518 ** Mark it so that we look for the length on the next line.
519 ** This happens on next entry into the read state.
521 inContainer->mReadState.mSectionDetails = sectionIndex1;
523 else
525 retval = __LINE__;
526 ERROR_REPORT(retval, inLine, "Unable to grow for new section.");
527 free(typeDup);
530 else
532 retval = __LINE__;
533 ERROR_REPORT(retval, typeArg, "Unable to duplicate type.");
536 else
538 retval = __LINE__;
539 ERROR_REPORT(retval, inLine, "Unable to determine section type.");
543 else
545 const char* offsetArg = NULL;
546 const char* classArg = NULL;
547 unsigned classWords = 1;
548 const char* symbolArg = NULL;
551 ** This is an section we've seen before, and must list a symbol.
552 ** Figure out the things we want to know about the symbol, e.g. size.
553 ** We will ignore particular classes of symbols.
556 offsetArg = skipToArg(inLine, 2);
558 classArg = skipToArg(offsetArg, 4);
559 if(0 == strncmp(classArg, "()", 2))
561 classArg = skipToArg(classArg, 2);
563 if(0 == strncmp(classArg, ".bf or.ef", 9))
565 classWords = 2;
568 symbolArg = skipToArg(classArg, 3 + (classWords - 1));
571 ** Skip particular lines/items.
574 0 != strncmp(classArg, "Label", 5) &&
575 0 != strncmp(symbolArg, ".bf", 3) &&
576 0 != strncmp(symbolArg, ".lf", 3) &&
577 0 != strncmp(symbolArg, ".ef", 3)
580 char* endOffsetArg = NULL;
581 unsigned offset = 0;
584 ** Convert the offset to something meaninful (size).
586 errno = 0;
587 offset = strtoul(offsetArg, &endOffsetArg, 16);
588 if(0 == errno && endOffsetArg != offsetArg)
590 void* moved = NULL;
593 ** Increase the size of the symbol array in the section.
594 ** Assumed symbols are unique within each section.
596 moved = realloc(inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols, sizeof(MSDump_Symbol) * (inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbolCount + 1));
597 if(NULL != moved)
599 unsigned symIndex = 0;
602 ** Record symbol details.
603 ** Assumed symbols are encountered in order for their section (size calc depends on it).
605 symIndex = inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbolCount;
606 inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbolCount++;
607 inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols = (MSDump_Symbol*)moved;
608 memset(&inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex], 0, sizeof(MSDump_Symbol));
610 inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mOffset = offset;
613 ** We could allocate smarter here if it ever mattered.
615 inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mName = strdup(symbolArg);
616 if(NULL != inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mName)
618 char* trim = NULL;
620 trim = (char*)skipNonWhite(inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mName);
621 if(NULL != trim)
623 *trim = '\0';
626 else
628 retval = __LINE__;
629 ERROR_REPORT(retval, inLine, "Unable to duplicate symbol name.");
632 else
634 retval = __LINE__;
635 ERROR_REPORT(retval, inLine, "Unable to grow symbol array for section.");
638 else
640 retval = __LINE__;
641 ERROR_REPORT(retval, inLine, "Unable to convert offset to a number.");
646 else
648 retval = __LINE__;
649 ERROR_REPORT(retval, inLine, "Unable to determine section index.");
652 else
654 retval = __LINE__;
655 ERROR_REPORT(retval, inLine, "No match for section prefix.");
659 else
661 retval = __LINE__;
662 ERROR_REPORT(retval, inLine, "Unable to scan for section.");
666 return retval;
670 void dumpCleanup(MSDump_Container* inContainer)
672 ** Attempt to be nice and free up what we have allocated.
675 unsigned objectLoop = 0;
676 unsigned sectionLoop = 0;
677 unsigned symbolLoop = 0;
679 for(objectLoop = 0; objectLoop < inContainer->mObjectCount; objectLoop++)
681 for(sectionLoop = 0; sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++)
683 for(symbolLoop = 0; symbolLoop < inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount; symbolLoop++)
685 CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mName);
687 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount = 0;
688 CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols);
689 CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mType);
691 inContainer->mObjects[objectLoop].mSectionCount = 0;
692 CLEANUP(inContainer->mObjects[objectLoop].mSections);
694 CLEANUP(inContainer->mObjects);
695 inContainer->mObjectCount = 0;
699 int qsortSymOffset(const void* in1, const void* in2)
701 ** qsort callback to sort the symbols by their offset.
704 MSDump_Symbol* sym1 = (MSDump_Symbol*)in1;
705 MSDump_Symbol* sym2 = (MSDump_Symbol*)in2;
706 int retval = 0;
708 if(sym1->mOffset < sym2->mOffset)
710 retval = 1;
712 else if(sym1->mOffset > sym2->mOffset)
714 retval = -1;
717 return retval;
721 int calcContainer(Options* inOptions, MSDump_Container* inContainer)
723 ** Resposible for doing any size calculations based on the offsets known.
724 ** After this calculation, each sections mUsed will match mSize.
725 ** After this calculation, all symbols should know how big they are.
728 int retval = 0;
729 unsigned objectLoop = 0;
730 unsigned sectionLoop = 0;
731 unsigned symbolLoop = 0;
735 ** Need to sort all symbols by their offsets.
737 for(objectLoop = 0; 0 == retval && objectLoop < inContainer->mObjectCount; objectLoop++)
739 for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++)
741 qsort(
742 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols,
743 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount,
744 sizeof(MSDump_Symbol),
745 qsortSymOffset
752 ** Need to go through all symbols and calculate their size.
754 for(objectLoop = 0; 0 == retval && objectLoop < inContainer->mObjectCount; objectLoop++)
756 for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++)
758 for(symbolLoop = 0; 0 == retval && symbolLoop < inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount; symbolLoop++)
760 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mSize =
761 inContainer->mObjects[objectLoop].mSections[sectionLoop].mLength -
762 inContainer->mObjects[objectLoop].mSections[sectionLoop].mUsed -
763 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mOffset;
765 inContainer->mObjects[objectLoop].mSections[sectionLoop].mUsed +=
766 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mSize;
772 return retval;
776 int reportContainer(Options* inOptions, MSDump_Container* inContainer)
778 ** Display all symbols and their data.
779 ** We'll use a tsv format.
782 int retval = 0;
783 unsigned objectLoop = 0;
784 unsigned sectionLoop = 0;
785 unsigned symbolLoop = 0;
786 int printRes = 0;
788 for(objectLoop = 0; 0 == retval && objectLoop < inContainer->mObjectCount; objectLoop++)
790 for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++)
792 for(symbolLoop = 0; 0 == retval && symbolLoop < inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount; symbolLoop++)
794 printRes = fprintf(inOptions->mOutput, "%s\t%s\t%.8X\t%s\n",
795 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mName,
796 inContainer->mObjects[objectLoop].mSections[sectionLoop].mType,
797 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mSize,
798 inContainer->mObjects[objectLoop].mObject
801 if(0 > printRes)
803 retval = __LINE__;
804 ERROR_REPORT(retval, inOptions->mOutputName, "Unable to write to file.");
810 return retval;
814 int dump2symdb(Options* inOptions)
816 ** Convert the input into the output, respecting the options.
817 ** Returns 0 on success.
820 int retval = 0;
821 char lineBuffer[0x800];
822 MSDump_Container container;
824 memset(&container, 0, sizeof(container));
827 ** Read the file line by line.
829 while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
831 if(0 != container.mReadState.mSkipLines)
833 container.mReadState.mSkipLines--;
834 continue;
836 retval = processLine(inOptions, &container, lineBuffer);
840 ** Perform whatever calculations desired.
842 if(0 == retval)
844 retval = calcContainer(inOptions, &container);
848 ** Output what we know.
850 if(0 == retval)
852 retval = reportContainer(inOptions, &container);
856 ** Cleanup what we've done.
858 dumpCleanup(&container);
860 return retval;
864 int initOptions(Options* outOptions, int inArgc, char** inArgv)
866 ** returns int 0 if successful.
869 int retval = 0;
870 int loop = 0;
871 int switchLoop = 0;
872 int match = 0;
873 const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
874 Switch* current = NULL;
877 ** Set any defaults.
879 memset(outOptions, 0, sizeof(Options));
880 outOptions->mProgramName = inArgv[0];
881 outOptions->mInput = stdin;
882 outOptions->mInputName = strdup("stdin");
883 outOptions->mOutput = stdout;
884 outOptions->mOutputName = strdup("stdout");
886 if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName)
888 retval = __LINE__;
889 ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup.");
893 ** Go through and attempt to do the right thing.
895 for(loop = 1; loop < inArgc && 0 == retval; loop++)
897 match = 0;
898 current = NULL;
900 for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
902 if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
904 match = __LINE__;
906 else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
908 match = __LINE__;
911 if(match)
913 if(gSwitches[switchLoop]->mHasValue)
916 ** Attempt to absorb next option to fullfill value.
918 if(loop + 1 < inArgc)
920 loop++;
922 current = gSwitches[switchLoop];
923 current->mValue = inArgv[loop];
926 else
928 current = gSwitches[switchLoop];
931 break;
935 if(0 == match)
937 outOptions->mHelp = __LINE__;
938 retval = __LINE__;
939 ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
941 else if(NULL == current)
943 outOptions->mHelp = __LINE__;
944 retval = __LINE__;
945 ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
947 else
950 ** Do something based on address/swtich.
952 if(current == &gInputSwitch)
954 CLEANUP(outOptions->mInputName);
955 if(NULL != outOptions->mInput && stdin != outOptions->mInput)
957 fclose(outOptions->mInput);
958 outOptions->mInput = NULL;
961 outOptions->mInput = fopen(current->mValue, "r");
962 if(NULL == outOptions->mInput)
964 retval = __LINE__;
965 ERROR_REPORT(retval, current->mValue, "Unable to open input file.");
967 else
969 outOptions->mInputName = strdup(current->mValue);
970 if(NULL == outOptions->mInputName)
972 retval = __LINE__;
973 ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
977 else if(current == &gOutputSwitch)
979 CLEANUP(outOptions->mOutputName);
980 if(NULL != outOptions->mOutput && stdout != outOptions->mOutput)
982 fclose(outOptions->mOutput);
983 outOptions->mOutput = NULL;
986 outOptions->mOutput = fopen(current->mValue, "a");
987 if(NULL == outOptions->mOutput)
989 retval = __LINE__;
990 ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
992 else
994 outOptions->mOutputName = strdup(current->mValue);
995 if(NULL == outOptions->mOutputName)
997 retval = __LINE__;
998 ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
1002 else if(current == &gHelpSwitch)
1004 outOptions->mHelp = __LINE__;
1006 else
1008 retval = __LINE__;
1009 ERROR_REPORT(retval, current->mLongName, "No handler for command line switch.");
1014 return retval;
1018 void cleanOptions(Options* inOptions)
1020 ** Clean up any open handles.
1023 CLEANUP(inOptions->mInputName);
1024 if(NULL != inOptions->mInput && stdin != inOptions->mInput)
1026 fclose(inOptions->mInput);
1028 CLEANUP(inOptions->mOutputName);
1029 if(NULL != inOptions->mOutput && stdout != inOptions->mOutput)
1031 fclose(inOptions->mOutput);
1034 memset(inOptions, 0, sizeof(Options));
1038 void showHelp(Options* inOptions)
1040 ** Show some simple help text on usage.
1043 int loop = 0;
1044 const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
1045 const char* valueText = NULL;
1047 printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
1048 printf("\n");
1049 printf("arguments:\n");
1051 for(loop = 0; loop < switchCount; loop++)
1053 if(gSwitches[loop]->mHasValue)
1055 valueText = " <value>";
1057 else
1059 valueText = "";
1062 printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText);
1063 printf("\t %s%s", gSwitches[loop]->mShortName, valueText);
1064 printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription);
1067 printf("This tool takes the output of \"dumpbin /symbols\" to produce a simple\n");
1068 printf("tsv db file of symbols and their respective attributes, like size.\n");
1072 int main(int inArgc, char** inArgv)
1074 int retval = 0;
1075 Options options;
1077 retval = initOptions(&options, inArgc, inArgv);
1078 if(options.mHelp)
1080 showHelp(&options);
1082 else if(0 == retval)
1084 retval = dump2symdb(&options);
1087 cleanOptions(&options);
1088 return retval;