Index: third_party/codesighs/nm2tsv.c |
=================================================================== |
--- third_party/codesighs/nm2tsv.c (revision 0) |
+++ third_party/codesighs/nm2tsv.c (revision 0) |
@@ -0,0 +1,505 @@ |
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
+ * |
+ * ***** BEGIN LICENSE BLOCK ***** |
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
+ * |
+ * The contents of this file are subject to the Mozilla Public License Version |
+ * 1.1 (the "License"); you may not use this file except in compliance with |
+ * the License. You may obtain a copy of the License at |
+ * http://www.mozilla.org/MPL/ |
+ * |
+ * Software distributed under the License is distributed on an "AS IS" basis, |
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
+ * for the specific language governing rights and limitations under the |
+ * License. |
+ * |
+ * The Original Code is nm2tsv.c code, released |
+ * Oct 10, 2002. |
+ * |
+ * The Initial Developer of the Original Code is |
+ * Netscape Communications Corporation. |
+ * Portions created by the Initial Developer are Copyright (C) 2002 |
+ * the Initial Developer. All Rights Reserved. |
+ * |
+ * Contributor(s): |
+ * Garrett Arch Blythe, 10-October-2002 |
+ * |
+ * Alternatively, the contents of this file may be used under the terms of |
+ * either the GNU General Public License Version 2 or later (the "GPL"), or |
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
+ * in which case the provisions of the GPL or the LGPL are applicable instead |
+ * of those above. If you wish to allow use of your version of this file only |
+ * under the terms of either the GPL or the LGPL, and not to allow others to |
+ * use your version of this file under the terms of the MPL, indicate your |
+ * decision by deleting the provisions above and replace them with the notice |
+ * and other provisions required by the GPL or the LGPL. If you do not delete |
+ * the provisions above, a recipient may use your version of this file under |
+ * the terms of any one of the MPL, the GPL or the LGPL. |
+ * |
+ * ***** END LICENSE BLOCK ***** */ |
+ |
+#include <stdio.h> |
+#include <stdlib.h> |
+#include <string.h> |
+#include <time.h> |
+#include <ctype.h> |
+ |
+ |
+#define ERROR_REPORT(num, val, msg) fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg)); |
+#define CLEANUP(ptr) do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0) |
+ |
+ |
+typedef struct __struct_Options |
+/* |
+** Options to control how we perform. |
+** |
+** mProgramName Used in help text. |
+** mInput File to read for input. |
+** Default is stdin. |
+** mInputName Name of the file. |
+** mOutput Output file, append. |
+** Default is stdout. |
+** mOutputName Name of the file. |
+** mHelp Whether or not help should be shown. |
+*/ |
+{ |
+ const char* mProgramName; |
+ FILE* mInput; |
+ char* mInputName; |
+ FILE* mOutput; |
+ char* mOutputName; |
+ int mHelp; |
+} |
+Options; |
+ |
+ |
+typedef struct __struct_Switch |
+/* |
+** Command line options. |
+*/ |
+{ |
+ const char* mLongName; |
+ const char* mShortName; |
+ int mHasValue; |
+ const char* mValue; |
+ const char* mDescription; |
+} |
+Switch; |
+ |
+#define DESC_NEWLINE "\n\t\t" |
+ |
+static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."}; |
+static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."}; |
+static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."}; |
+ |
+static Switch* gSwitches[] = { |
+ &gInputSwitch, |
+ &gOutputSwitch, |
+ &gHelpSwitch |
+}; |
+ |
+ |
+char* scanWhite(char* inScan) |
+/* |
+** Scan for whitespace. |
+*/ |
+{ |
+ char* retval = inScan; |
+ |
+ while('\0' != *retval && 0 == isspace(*retval)) |
+ { |
+ retval++; |
+ } |
+ |
+ return retval; |
+} |
+ |
+ |
+void trimWhite(char* inString) |
+/* |
+** Remove any whitespace from the end of the string. |
+*/ |
+{ |
+ int len = strlen(inString); |
+ |
+ while(len) |
+ { |
+ len--; |
+ |
+ if(isspace(*(inString + len))) |
+ { |
+ *(inString + len) = '\0'; |
+ } |
+ else |
+ { |
+ break; |
+ } |
+ } |
+} |
+ |
+ |
+int nm2tsv(Options* inOptions) |
+/* |
+** Read all input. |
+** Output tab separated value data. |
+** |
+** We expect our data to be in a particular format. |
+** nm --format=bsd --size-sort --print-file-name --demangle |
+*/ |
+{ |
+ int retval = 0; |
+ char lineBuffer[4096]; /* yes, the are some very large symbols */ |
+ char* module = NULL; |
+ char* size = NULL; |
+ char* type = NULL; |
+ char* symbol = NULL; |
+ |
+ /* |
+ ** Read in the nm file. |
+ */ |
+ while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput)) |
+ { |
+ trimWhite(lineBuffer); |
+ |
+ /* |
+ ** Find the various pieces of information we'll be looking for. |
+ */ |
+ size = strchr(lineBuffer, ':'); |
+ if(NULL != size) |
+ { |
+ *size = '\0'; |
+ size++; |
+ |
+ module = strrchr(lineBuffer, '/'); |
+ if(NULL == module) |
+ { |
+ module = lineBuffer; |
+ } |
+ else |
+ { |
+ *module = '\0'; |
+ module++; |
+ } |
+ |
+ type = scanWhite(size); |
+ *type = '\0'; |
+ type++; |
+ |
+ symbol = type + 1; |
+ *symbol = '\0'; |
+ symbol++; |
+ |
+ /* |
+ ** Skip certain types. |
+ */ |
+ switch(*type) |
+ { |
+ case '-': |
+ continue; |
+ break; |
+ default: |
+ break; |
+ } |
+ |
+ /* |
+ ** Simply output the data with a little more interpretation. |
+ ** First is size. |
+ */ |
+ fprintf(inOptions->mOutput, "%s\t", size); |
+ |
+ /* |
+ ** Type, CODE or DATA |
+ */ |
+ switch(toupper(*type)) |
+ { |
+ case 'T': /* text (code) */ |
+ case 'W': /* weak symbol ??? */ |
+ fprintf(inOptions->mOutput, "CODE\t"); |
+ break; |
+ default: |
+ fprintf(inOptions->mOutput, "DATA\t"); |
+ break; |
+ } |
+ |
+ /* |
+ ** Scope, PUBLIC, STATIC, or UNDEF |
+ */ |
+ if(islower(*type)) |
+ { |
+ fprintf(inOptions->mOutput, "STATIC\t"); |
+ } |
+ else |
+ { |
+ switch(*type) |
+ { |
+ case '?': |
+ fprintf(inOptions->mOutput, "UNDEF\t"); |
+ break; |
+ default: |
+ fprintf(inOptions->mOutput, "PUBLIC\t"); |
+ break; |
+ } |
+ } |
+ |
+ /* |
+ ** Module name, segment. |
+ */ |
+ fprintf(inOptions->mOutput, "%s\t", module); |
+ fprintf(inOptions->mOutput, "%c\t", toupper(*type)); |
+ |
+ /* |
+ ** Origin |
+ */ |
+ fprintf(inOptions->mOutput, "UNDEF:%s:%c\t", module, toupper(*type)); |
+ |
+ /* |
+ ** Symbol is last. |
+ */ |
+ fprintf(inOptions->mOutput, "%s\n", symbol); |
+ } |
+ else |
+ { |
+ retval = __LINE__; |
+ ERROR_REPORT(retval, lineBuffer, "Malformed input line."); |
+ } |
+ } |
+ |
+ if(0 == retval && 0 != ferror(inOptions->mInput)) |
+ { |
+ retval = __LINE__; |
+ ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file."); |
+ } |
+ |
+ return retval; |
+} |
+ |
+ |
+int initOptions(Options* outOptions, int inArgc, char** inArgv) |
+/* |
+** returns int 0 if successful. |
+*/ |
+{ |
+ int retval = 0; |
+ int loop = 0; |
+ int switchLoop = 0; |
+ int match = 0; |
+ const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]); |
+ Switch* current = NULL; |
+ |
+ /* |
+ ** Set any defaults. |
+ */ |
+ memset(outOptions, 0, sizeof(Options)); |
+ outOptions->mProgramName = inArgv[0]; |
+ outOptions->mInput = stdin; |
+ outOptions->mInputName = strdup("stdin"); |
+ outOptions->mOutput = stdout; |
+ outOptions->mOutputName = strdup("stdout"); |
+ |
+ if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName) |
+ { |
+ retval = __LINE__; |
+ ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup."); |
+ } |
+ |
+ /* |
+ ** Go through and attempt to do the right thing. |
+ */ |
+ for(loop = 1; loop < inArgc && 0 == retval; loop++) |
+ { |
+ match = 0; |
+ current = NULL; |
+ |
+ for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++) |
+ { |
+ if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop])) |
+ { |
+ match = __LINE__; |
+ } |
+ else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop])) |
+ { |
+ match = __LINE__; |
+ } |
+ |
+ if(match) |
+ { |
+ if(gSwitches[switchLoop]->mHasValue) |
+ { |
+ /* |
+ ** Attempt to absorb next option to fullfill value. |
+ */ |
+ if(loop + 1 < inArgc) |
+ { |
+ loop++; |
+ |
+ current = gSwitches[switchLoop]; |
+ current->mValue = inArgv[loop]; |
+ } |
+ } |
+ else |
+ { |
+ current = gSwitches[switchLoop]; |
+ } |
+ |
+ break; |
+ } |
+ } |
+ |
+ if(0 == match) |
+ { |
+ outOptions->mHelp = __LINE__; |
+ retval = __LINE__; |
+ ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch."); |
+ } |
+ else if(NULL == current) |
+ { |
+ outOptions->mHelp = __LINE__; |
+ retval = __LINE__; |
+ ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value."); |
+ } |
+ else |
+ { |
+ /* |
+ ** Do something based on address/swtich. |
+ */ |
+ if(current == &gInputSwitch) |
+ { |
+ CLEANUP(outOptions->mInputName); |
+ if(NULL != outOptions->mInput && stdin != outOptions->mInput) |
+ { |
+ fclose(outOptions->mInput); |
+ outOptions->mInput = NULL; |
+ } |
+ |
+ outOptions->mInput = fopen(current->mValue, "r"); |
+ if(NULL == outOptions->mInput) |
+ { |
+ retval = __LINE__; |
+ ERROR_REPORT(retval, current->mValue, "Unable to open input file."); |
+ } |
+ else |
+ { |
+ outOptions->mInputName = strdup(current->mValue); |
+ if(NULL == outOptions->mInputName) |
+ { |
+ retval = __LINE__; |
+ ERROR_REPORT(retval, current->mValue, "Unable to strdup."); |
+ } |
+ } |
+ } |
+ else if(current == &gOutputSwitch) |
+ { |
+ CLEANUP(outOptions->mOutputName); |
+ if(NULL != outOptions->mOutput && stdout != outOptions->mOutput) |
+ { |
+ fclose(outOptions->mOutput); |
+ outOptions->mOutput = NULL; |
+ } |
+ |
+ outOptions->mOutput = fopen(current->mValue, "a"); |
+ if(NULL == outOptions->mOutput) |
+ { |
+ retval = __LINE__; |
+ ERROR_REPORT(retval, current->mValue, "Unable to open output file."); |
+ } |
+ else |
+ { |
+ outOptions->mOutputName = strdup(current->mValue); |
+ if(NULL == outOptions->mOutputName) |
+ { |
+ retval = __LINE__; |
+ ERROR_REPORT(retval, current->mValue, "Unable to strdup."); |
+ } |
+ } |
+ } |
+ else if(current == &gHelpSwitch) |
+ { |
+ outOptions->mHelp = __LINE__; |
+ } |
+ else |
+ { |
+ retval = __LINE__; |
+ ERROR_REPORT(retval, current->mLongName, "No handler for command line switch."); |
+ } |
+ } |
+ } |
+ |
+ return retval; |
+} |
+ |
+ |
+void cleanOptions(Options* inOptions) |
+/* |
+** Clean up any open handles. |
+*/ |
+{ |
+ CLEANUP(inOptions->mInputName); |
+ if(NULL != inOptions->mInput && stdin != inOptions->mInput) |
+ { |
+ fclose(inOptions->mInput); |
+ } |
+ CLEANUP(inOptions->mOutputName); |
+ if(NULL != inOptions->mOutput && stdout != inOptions->mOutput) |
+ { |
+ fclose(inOptions->mOutput); |
+ } |
+ |
+ memset(inOptions, 0, sizeof(Options)); |
+} |
+ |
+ |
+void showHelp(Options* inOptions) |
+/* |
+** Show some simple help text on usage. |
+*/ |
+{ |
+ int loop = 0; |
+ const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]); |
+ const char* valueText = NULL; |
+ |
+ printf("usage:\t%s [arguments]\n", inOptions->mProgramName); |
+ printf("\n"); |
+ printf("arguments:\n"); |
+ |
+ for(loop = 0; loop < switchCount; loop++) |
+ { |
+ if(gSwitches[loop]->mHasValue) |
+ { |
+ valueText = " <value>"; |
+ } |
+ else |
+ { |
+ valueText = ""; |
+ } |
+ |
+ printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText); |
+ printf("\t %s%s", gSwitches[loop]->mShortName, valueText); |
+ printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription); |
+ } |
+ |
+ printf("This tool normalizes nm output for use by other tools.\n"); |
+ printf("GNU nm is assumed for symbol type determination.\n"); |
+ printf("i.e. Use this tool to parse the output of:\n"); |
+ printf("\t/usr/bin/nm --format=bsd --size-sort --print-file-name --demangle <exefile>\n"); |
+} |
+ |
+ |
+int main(int inArgc, char** inArgv) |
+{ |
+ int retval = 0; |
+ Options options; |
+ |
+ retval = initOptions(&options, inArgc, inArgv); |
+ if(options.mHelp) |
+ { |
+ showHelp(&options); |
+ } |
+ else if(0 == retval) |
+ { |
+ retval = nm2tsv(&options); |
+ } |
+ |
+ cleanOptions(&options); |
+ return retval; |
+} |
+ |
Property changes on: third_party/codesighs/nm2tsv.c |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |