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
16 * The Original Code is nm2tsv.c code, released
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.
25 * Garrett Arch Blythe, 10-October-2002
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 ***** */
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.
59 ** mInputName Name of the file.
60 ** mOutput Output file, append.
62 ** mOutputName Name of the file.
63 ** mHelp Whether or not help should be shown.
66 const char* mProgramName
;
76 typedef struct __struct_Switch
78 ** Command line options.
81 const char* mLongName
;
82 const char* mShortName
;
85 const char* mDescription
;
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
[] = {
102 char* scanWhite(char* inScan
)
104 ** Scan for whitespace.
107 char* retval
= inScan
;
109 while('\0' != *retval
&& 0 == isspace(*retval
))
118 void trimWhite(char* inString
)
120 ** Remove any whitespace from the end of the string.
123 int len
= strlen(inString
);
129 if(isspace(*(inString
+ len
)))
131 *(inString
+ len
) = '\0';
141 int nm2tsv(Options
* inOptions
)
144 ** Output tab separated value data.
146 ** We expect our data to be in a particular format.
147 ** nm --format=bsd --size-sort --print-file-name --demangle
151 char lineBuffer
[4096]; /* yes, the are some very large symbols */
158 ** Read in the nm file.
160 while(0 == retval
&& NULL
!= fgets(lineBuffer
, sizeof(lineBuffer
), inOptions
->mInput
))
162 trimWhite(lineBuffer
);
165 ** Find the various pieces of information we'll be looking for.
167 size
= strchr(lineBuffer
, ':');
173 module
= strrchr(lineBuffer
, '/');
184 type
= scanWhite(size
);
193 ** Skip certain types.
205 ** Simply output the data with a little more interpretation.
208 fprintf(inOptions
->mOutput
, "%s\t", size
);
211 ** Type, CODE or DATA
213 switch(toupper(*type
))
215 case 'T': /* text (code) */
216 case 'W': /* weak symbol ??? */
217 fprintf(inOptions
->mOutput
, "CODE\t");
220 fprintf(inOptions
->mOutput
, "DATA\t");
225 ** Scope, PUBLIC, STATIC, or UNDEF
229 fprintf(inOptions
->mOutput
, "STATIC\t");
236 fprintf(inOptions
->mOutput
, "UNDEF\t");
239 fprintf(inOptions
->mOutput
, "PUBLIC\t");
245 ** Module name, segment.
247 fprintf(inOptions
->mOutput
, "%s\t", module
);
248 fprintf(inOptions
->mOutput
, "%c\t", toupper(*type
));
253 fprintf(inOptions
->mOutput
, "UNDEF:%s:%c\t", module
, toupper(*type
));
258 fprintf(inOptions
->mOutput
, "%s\n", symbol
);
263 ERROR_REPORT(retval
, lineBuffer
, "Malformed input line.");
267 if(0 == retval
&& 0 != ferror(inOptions
->mInput
))
270 ERROR_REPORT(retval
, inOptions
->mInputName
, "Unable to read file.");
277 int initOptions(Options
* outOptions
, int inArgc
, char** inArgv
)
279 ** returns int 0 if successful.
286 const int switchCount
= sizeof(gSwitches
) / sizeof(gSwitches
[0]);
287 Switch
* current
= NULL
;
292 memset(outOptions
, 0, sizeof(Options
));
293 outOptions
->mProgramName
= inArgv
[0];
294 outOptions
->mInput
= stdin
;
295 outOptions
->mInputName
= strdup("stdin");
296 outOptions
->mOutput
= stdout
;
297 outOptions
->mOutputName
= strdup("stdout");
299 if(NULL
== outOptions
->mOutputName
|| NULL
== outOptions
->mInputName
)
302 ERROR_REPORT(retval
, "stdin/stdout", "Unable to strdup.");
306 ** Go through and attempt to do the right thing.
308 for(loop
= 1; loop
< inArgc
&& 0 == retval
; loop
++)
313 for(switchLoop
= 0; switchLoop
< switchCount
&& 0 == retval
; switchLoop
++)
315 if(0 == strcmp(gSwitches
[switchLoop
]->mLongName
, inArgv
[loop
]))
319 else if(0 == strcmp(gSwitches
[switchLoop
]->mShortName
, inArgv
[loop
]))
326 if(gSwitches
[switchLoop
]->mHasValue
)
329 ** Attempt to absorb next option to fullfill value.
331 if(loop
+ 1 < inArgc
)
335 current
= gSwitches
[switchLoop
];
336 current
->mValue
= inArgv
[loop
];
341 current
= gSwitches
[switchLoop
];
350 outOptions
->mHelp
= __LINE__
;
352 ERROR_REPORT(retval
, inArgv
[loop
], "Unknown command line switch.");
354 else if(NULL
== current
)
356 outOptions
->mHelp
= __LINE__
;
358 ERROR_REPORT(retval
, inArgv
[loop
], "Command line switch requires a value.");
363 ** Do something based on address/swtich.
365 if(current
== &gInputSwitch
)
367 CLEANUP(outOptions
->mInputName
);
368 if(NULL
!= outOptions
->mInput
&& stdin
!= outOptions
->mInput
)
370 fclose(outOptions
->mInput
);
371 outOptions
->mInput
= NULL
;
374 outOptions
->mInput
= fopen(current
->mValue
, "r");
375 if(NULL
== outOptions
->mInput
)
378 ERROR_REPORT(retval
, current
->mValue
, "Unable to open input file.");
382 outOptions
->mInputName
= strdup(current
->mValue
);
383 if(NULL
== outOptions
->mInputName
)
386 ERROR_REPORT(retval
, current
->mValue
, "Unable to strdup.");
390 else if(current
== &gOutputSwitch
)
392 CLEANUP(outOptions
->mOutputName
);
393 if(NULL
!= outOptions
->mOutput
&& stdout
!= outOptions
->mOutput
)
395 fclose(outOptions
->mOutput
);
396 outOptions
->mOutput
= NULL
;
399 outOptions
->mOutput
= fopen(current
->mValue
, "a");
400 if(NULL
== outOptions
->mOutput
)
403 ERROR_REPORT(retval
, current
->mValue
, "Unable to open output file.");
407 outOptions
->mOutputName
= strdup(current
->mValue
);
408 if(NULL
== outOptions
->mOutputName
)
411 ERROR_REPORT(retval
, current
->mValue
, "Unable to strdup.");
415 else if(current
== &gHelpSwitch
)
417 outOptions
->mHelp
= __LINE__
;
422 ERROR_REPORT(retval
, current
->mLongName
, "No handler for command line switch.");
431 void cleanOptions(Options
* inOptions
)
433 ** Clean up any open handles.
436 CLEANUP(inOptions
->mInputName
);
437 if(NULL
!= inOptions
->mInput
&& stdin
!= inOptions
->mInput
)
439 fclose(inOptions
->mInput
);
441 CLEANUP(inOptions
->mOutputName
);
442 if(NULL
!= inOptions
->mOutput
&& stdout
!= inOptions
->mOutput
)
444 fclose(inOptions
->mOutput
);
447 memset(inOptions
, 0, sizeof(Options
));
451 void showHelp(Options
* inOptions
)
453 ** Show some simple help text on usage.
457 const int switchCount
= sizeof(gSwitches
) / sizeof(gSwitches
[0]);
458 const char* valueText
= NULL
;
460 printf("usage:\t%s [arguments]\n", inOptions
->mProgramName
);
462 printf("arguments:\n");
464 for(loop
= 0; loop
< switchCount
; loop
++)
466 if(gSwitches
[loop
]->mHasValue
)
468 valueText
= " <value>";
475 printf("\t%s%s\n", gSwitches
[loop
]->mLongName
, valueText
);
476 printf("\t %s%s", gSwitches
[loop
]->mShortName
, valueText
);
477 printf(DESC_NEWLINE
"%s\n\n", gSwitches
[loop
]->mDescription
);
480 printf("This tool normalizes nm output for use by other tools.\n");
481 printf("GNU nm is assumed for symbol type determination.\n");
482 printf("i.e. Use this tool to parse the output of:\n");
483 printf("\t/usr/bin/nm --format=bsd --size-sort --print-file-name --demangle <exefile>\n");
487 int main(int inArgc
, char** inArgv
)
492 retval
= initOptions(&options
, inArgc
, inArgv
);
499 retval
= nm2tsv(&options
);
502 cleanOptions(&options
);