Home | History | Annotate | Download | only in codesighs
      1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
      2  *
      3  * ***** BEGIN LICENSE BLOCK *****
      4  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
      5  *
      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/
     10  *
     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.
     15  *
     16  * The Original Code is codesighs.c code, released
     17  * Oct 3, 2002.
     18  *
     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.
     23  *
     24  * Contributor(s):
     25  *   Garrett Arch Blythe, 03-October-2002
     26  *
     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.
     38  *
     39  * ***** END LICENSE BLOCK ***** */
     40 
     41 #include <stdio.h>
     42 #include <stdlib.h>
     43 #include <string.h>
     44 #include <time.h>
     45 #include <ctype.h>
     46 #include <errno.h>
     47 
     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)
     50 
     51 
     52 typedef struct __struct_Options
     53 /*
     54 **  Options to control how we perform.
     55 **
     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.
     64 **  mModules        Output module by module information.
     65 **  mTotalOnly      Only output one number, the total.
     66 **  mMinSize        Ignore lines below this size.
     67 **  mMaxSize        Ignore lines above this size.
     68 **  mMatchScopes    For a line to be processed, it should match.
     69 **  mMachClasses    For a line to be processed, it should match.
     70 **  mMatchModules   For a line to be processed, it should match.
     71 **  mMatchSections  For a line to be processed, it should match.
     72 **  mMatchObjects   For a line to be processed, it should match.
     73 **  mMatchSymbols   For a line to be processed, it should match.
     74 */
     75 {
     76     const char* mProgramName;
     77     FILE* mInput;
     78     char* mInputName;
     79     FILE* mOutput;
     80     char* mOutputName;
     81     int mHelp;
     82     int mModules;
     83     int mTotalOnly;
     84     unsigned long mMinSize;
     85     unsigned long mMaxSize;
     86     char** mMatchScopes;
     87     unsigned mMatchScopeCount;
     88     char** mMatchClasses;
     89     unsigned mMatchClassCount;
     90     char** mMatchModules;
     91     unsigned mMatchModuleCount;
     92     char** mMatchSections;
     93     unsigned mMatchSectionCount;
     94     char** mMatchObjects;
     95     unsigned mMatchObjectCount;
     96     char** mMatchSymbols;
     97     unsigned mMatchSymbolCount;
     98 }
     99 Options;
    100 
    101 
    102 typedef struct __struct_Switch
    103 /*
    104 **  Command line options.
    105 */
    106 {
    107     const char* mLongName;
    108     const char* mShortName;
    109     int mHasValue;
    110     const char* mValue;
    111     const char* mDescription;
    112 }
    113 Switch;
    114 
    115 #define DESC_NEWLINE "\n\t\t"
    116 
    117 static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."};
    118 static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."};
    119 static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."};
    120 static Switch gModuleSwitch = {"--modules", "-m", 0, NULL, "Output individual module numbers as well."};
    121 static Switch gTotalSwitch = {"--totalonly", "-t", 0, NULL, "Output only one number." DESC_NEWLINE "The total overall size." DESC_NEWLINE "Overrides other output options."};
    122 static Switch gMinSize = {"--min-size", "-min", 1, NULL, "Only consider symbols equal to or greater than this size." DESC_NEWLINE "The default is 0x00000000."};
    123 static Switch gMaxSize = {"--max-size", "-max", 1, NULL, "Only consider symbols equal to or smaller than this size." DESC_NEWLINE "The default is 0xFFFFFFFF."};
    124 static Switch gMatchScope = {"--match-scope", "-msco", 1, NULL, "Only consider scopes that have a substring match." DESC_NEWLINE "Multiple uses allowed to specify a range of scopes," DESC_NEWLINE "though PUBLIC, STATIC, and UNDEF are your only choices."};
    125 static Switch gMatchClass = {"--match-class", "-mcla", 1, NULL, "Only consider classes that have a substring match." DESC_NEWLINE "Multiple uses allowed to specify a range of classes," DESC_NEWLINE "though CODE and DATA are your only choices."};
    126 static Switch gMatchModule = {"--match-module", "-mmod", 1, NULL, "Only consider modules that have a substring match." DESC_NEWLINE "Multiple uses allowed to specify an array of modules."};
    127 static Switch gMatchSection = {"--match-section", "-msec", 1, NULL, "Only consider sections that have a substring match." DESC_NEWLINE "Multiple uses allowed to specify an array of sections."  DESC_NEWLINE "Section is considered symbol type."};
    128 static Switch gMatchObject = {"--match-object", "-mobj", 1, NULL, "Only consider objects that have a substring match." DESC_NEWLINE "Multiple uses allowed to specify an array of objects."};
    129 static Switch gMatchSymbol = {"--match-symbol", "-msym", 1, NULL, "Only consider symbols that have a substring match." DESC_NEWLINE "Multiple uses allowed to specify an array of symbols."};
    130 
    131 static Switch* gSwitches[] = {
    132         &gInputSwitch,
    133         &gOutputSwitch,
    134         &gModuleSwitch,
    135         &gTotalSwitch,
    136         &gMinSize,
    137         &gMaxSize,
    138         &gMatchClass,
    139         &gMatchScope,
    140         &gMatchModule,
    141         &gMatchSection,
    142         &gMatchObject,
    143         &gMatchSymbol,
    144         &gHelpSwitch
    145 };
    146 
    147 
    148 typedef struct __struct_SizeStats
    149 /*
    150 **  Track totals.
    151 **
    152 **  mData       Size of data.
    153 **  mCode       Size of code.
    154 */
    155 {
    156     unsigned long mData;
    157     unsigned long mCode;
    158 }
    159 SizeStats;
    160 
    161 
    162 typedef struct __struct_ModuleStats
    163 /*
    164 **  Track module level information.
    165 **
    166 **  mModule     Module name.
    167 **  mSize       Size of module.
    168 */
    169 {
    170     char* mModule;
    171     SizeStats mSize;
    172 }
    173 ModuleStats;
    174 
    175 typedef enum __enum_SegmentClass
    176 {
    177         CODE,
    178         DATA
    179 }
    180 SegmentClass;
    181 
    182 
    183 static int moduleCompare(const void* in1, const void* in2)
    184 /*
    185 **  qsort helper function.
    186 */
    187 {
    188     int retval = 0;
    189 
    190     const ModuleStats* one = (const ModuleStats*)in1;
    191     const ModuleStats* two = (const ModuleStats*)in2;
    192     unsigned long oneSize = one->mSize.mCode + one->mSize.mData;
    193     unsigned long twoSize = two->mSize.mCode + two->mSize.mData;
    194 
    195     if(oneSize < twoSize)
    196     {
    197         retval = 1;
    198     }
    199     else if(oneSize > twoSize)
    200     {
    201         retval = -1;
    202     }
    203 
    204     return retval;
    205 }
    206 
    207 
    208 void trimWhite(char* inString)
    209 /*
    210 **  Remove any whitespace from the end of the string.
    211 */
    212 {
    213     int len = strlen(inString);
    214 
    215     while(len)
    216     {
    217         len--;
    218 
    219         if(isspace(*(inString + len)))
    220         {
    221             *(inString + len) = '\0';
    222         }
    223         else
    224         {
    225             break;
    226         }
    227     }
    228 }
    229 
    230 
    231 int codesighs(Options* inOptions)
    232 /*
    233 **  Output a simplistic report based on our options.
    234 */
    235 {
    236     int retval = 0;
    237     char lineBuffer[0x1000];
    238     int scanRes = 0;
    239     unsigned long size;
    240     char segClass[0x10];
    241     char scope[0x10];
    242     char module[0x100];
    243     char segment[0x40];
    244     char object[0x100];
    245     char* symbol;
    246     SizeStats overall;
    247     ModuleStats* modules = NULL;
    248     unsigned moduleCount = 0;
    249 
    250     memset(&overall, 0, sizeof(overall));
    251 
    252     /*
    253     **  Read the file line by line, regardless of number of fields.
    254     **  We assume tab separated value formatting, at least 7 lead values:
    255     **      size class scope module segment object symbol ....
    256     */
    257     while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
    258     {
    259         trimWhite(lineBuffer);
    260 
    261         scanRes = sscanf(lineBuffer,
    262             "%x\t%s\t%s\t%s\t%s\t%s\t",
    263             (unsigned*)&size,
    264             segClass,
    265             scope,
    266             module,
    267             segment,
    268             object);
    269 
    270         if(6 == scanRes)
    271         {
    272             SegmentClass segmentClass = CODE;
    273 
    274             symbol = strchr(lineBuffer, '\t') + 1;
    275 
    276             /*
    277             **  Qualify the segment class.
    278             */
    279             if(0 == strcmp(segClass, "DATA"))
    280             {
    281                 segmentClass = DATA;
    282             }
    283             else if(0 == strcmp(segClass, "CODE"))
    284             {
    285                 segmentClass = CODE;
    286             }
    287             else
    288             {
    289                 retval = __LINE__;
    290                 ERROR_REPORT(retval, segClass, "Unable to determine segment class.");
    291             }
    292 
    293             if(0 == retval)
    294             {
    295                 /*
    296                 **  Match any options required before continuing.
    297                 **  This is where you would want to add more restrictive totalling.
    298                 */
    299 
    300                 /*
    301                 **  Match size.
    302                 */
    303                 if(size < inOptions->mMinSize)
    304                 {
    305                     continue;
    306                 }
    307                 if(size > inOptions->mMaxSize)
    308                 {
    309                     continue;
    310                 }
    311 
    312                 /*
    313                 **  Match class.
    314                 */
    315                 if(0 != inOptions->mMatchClassCount)
    316                 {
    317                     unsigned loop = 0;
    318 
    319                     for(loop = 0; loop < inOptions->mMatchClassCount; loop++)
    320                     {
    321                         if(NULL != strstr(segClass, inOptions->mMatchClasses[loop]))
    322                         {
    323                             break;
    324                         }
    325                     }
    326 
    327                     /*
    328                     **  If there was no match, we skip the line.
    329                     */
    330                     if(loop == inOptions->mMatchClassCount)
    331                     {
    332                         continue;
    333                     }
    334                 }
    335 
    336                 /*
    337                 **  Match scope.
    338                 */
    339                 if(0 != inOptions->mMatchScopeCount)
    340                 {
    341                     unsigned loop = 0;
    342 
    343                     for(loop = 0; loop < inOptions->mMatchScopeCount; loop++)
    344                     {
    345                         if(NULL != strstr(scope, inOptions->mMatchScopes[loop]))
    346                         {
    347                             break;
    348                         }
    349                     }
    350 
    351                     /*
    352                     **  If there was no match, we skip the line.
    353                     */
    354                     if(loop == inOptions->mMatchScopeCount)
    355                     {
    356                         continue;
    357                     }
    358                 }
    359 
    360                 /*
    361                 **  Match modules.
    362                 */
    363                 if(0 != inOptions->mMatchModuleCount)
    364                 {
    365                     unsigned loop = 0;
    366 
    367                     for(loop = 0; loop < inOptions->mMatchModuleCount; loop++)
    368                     {
    369                         if(NULL != strstr(module, inOptions->mMatchModules[loop]))
    370                         {
    371                             break;
    372                         }
    373                     }
    374 
    375                     /*
    376                     **  If there was no match, we skip the line.
    377                     */
    378                     if(loop == inOptions->mMatchModuleCount)
    379                     {
    380                         continue;
    381                     }
    382                 }
    383 
    384                 /*
    385                 **  Match sections.
    386                 */
    387                 if(0 != inOptions->mMatchSectionCount)
    388                 {
    389                     unsigned loop = 0;
    390 
    391                     for(loop = 0; loop < inOptions->mMatchSectionCount; loop++)
    392                     {
    393                         if(NULL != strstr(segment, inOptions->mMatchSections[loop]))
    394                         {
    395                             break;
    396                         }
    397                     }
    398 
    399                     /*
    400                     **  If there was no match, we skip the line.
    401                     */
    402                     if(loop == inOptions->mMatchSectionCount)
    403                     {
    404                         continue;
    405                     }
    406                 }
    407 
    408                 /*
    409                 **  Match object.
    410                 */
    411                 if(0 != inOptions->mMatchObjectCount)
    412                 {
    413                     unsigned loop = 0;
    414 
    415                     for(loop = 0; loop < inOptions->mMatchObjectCount; loop++)
    416                     {
    417                         if(NULL != strstr(object, inOptions->mMatchObjects[loop]))
    418                         {
    419                             break;
    420                         }
    421                     }
    422 
    423                     /*
    424                     **  If there was no match, we skip the line.
    425                     */
    426                     if(loop == inOptions->mMatchObjectCount)
    427                     {
    428                         continue;
    429                     }
    430                 }
    431 
    432                 /*
    433                 **  Match symbols.
    434                 */
    435                 if(0 != inOptions->mMatchSymbolCount)
    436                 {
    437                     unsigned loop = 0;
    438 
    439                     for(loop = 0; loop < inOptions->mMatchSymbolCount; loop++)
    440                     {
    441                         if(NULL != strstr(symbol, inOptions->mMatchSymbols[loop]))
    442                         {
    443                             break;
    444                         }
    445                     }
    446 
    447                     /*
    448                     **  If there was no match, we skip the line.
    449                     */
    450                     if(loop == inOptions->mMatchSymbolCount)
    451                     {
    452                         continue;
    453                     }
    454                 }
    455 
    456                 /*
    457                 **  Update overall totals.
    458                 */
    459                 if(CODE == segmentClass)
    460                 {
    461                     overall.mCode += size;
    462                 }
    463                 else if(DATA == segmentClass)
    464                 {
    465                     overall.mData += size;
    466                 }
    467 
    468                 /*
    469                 **  See what else we should be tracking.
    470                 */
    471                 if(0 == inOptions->mTotalOnly)
    472                 {
    473                     if(inOptions->mModules)
    474                     {
    475                         unsigned index = 0;
    476 
    477                         /*
    478                         **  Find the module to modify.
    479                         */
    480                         for(index = 0; index < moduleCount; index++)
    481                         {
    482                             if(0 == strcmp(modules[index].mModule, module))
    483                             {
    484                                 break;
    485                             }
    486                         }
    487 
    488                         /*
    489                         **  If the index is the same as the count, we need to
    490                         **      add a new module.
    491                         */
    492                         if(index == moduleCount)
    493                         {
    494                             void* moved = NULL;
    495 
    496                             moved = realloc(modules, sizeof(ModuleStats) * (moduleCount + 1));
    497                             if(NULL != moved)
    498                             {
    499                                 modules = (ModuleStats*)moved;
    500                                 moduleCount++;
    501 
    502                                 memset(modules + index, 0, sizeof(ModuleStats));
    503                                 modules[index].mModule = strdup(module);
    504                                 if(NULL == modules[index].mModule)
    505                                 {
    506                                     retval = __LINE__;
    507                                     ERROR_REPORT(retval, module, "Unable to duplicate string.");
    508                                 }
    509                             }
    510                             else
    511                             {
    512                                 retval = __LINE__;
    513                                 ERROR_REPORT(retval, inOptions->mProgramName, "Unable to allocate module memory.");
    514                             }
    515                         }
    516 
    517                         if(0 == retval)
    518                         {
    519                             if(CODE == segmentClass)
    520                             {
    521                                 modules[index].mSize.mCode += size;
    522                             }
    523                             else if(DATA == segmentClass)
    524                             {
    525                                 modules[index].mSize.mData += size;
    526                             }
    527                         }
    528                     }
    529                 }
    530             }
    531         }
    532         else
    533         {
    534             retval = __LINE__;
    535             ERROR_REPORT(retval, inOptions->mInputName, "Problem extracting values from file.");
    536         }
    537     }
    538 
    539     if(0 == retval && 0 != ferror(inOptions->mInput))
    540     {
    541         retval = __LINE__;
    542         ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file.");
    543     }
    544 
    545     /*
    546     **  If all went well, time to report.
    547     */
    548     if(0 == retval)
    549     {
    550         if(inOptions->mTotalOnly)
    551         {
    552             fprintf(inOptions->mOutput, "%u\n", (unsigned)(overall.mCode + overall.mData));
    553         }
    554         else
    555         {
    556             fprintf(inOptions->mOutput, "Overall Size\n");
    557             fprintf(inOptions->mOutput, "\tTotal:\t%10u\n", (unsigned)(overall.mCode + overall.mData));
    558             fprintf(inOptions->mOutput, "\tCode:\t%10u\n", (unsigned)overall.mCode);
    559             fprintf(inOptions->mOutput, "\tData:\t%10u\n", (unsigned)overall.mData);
    560         }
    561 
    562         /*
    563         **  Check options to see what else we should output.
    564         */
    565         if(inOptions->mModules && moduleCount)
    566         {
    567             unsigned loop = 0;
    568 
    569             /*
    570             **  Sort the modules by their size.
    571             */
    572             qsort(modules, (size_t)moduleCount, sizeof(ModuleStats), moduleCompare);
    573 
    574             /*
    575             **  Output each one.
    576             **  Might as well clean up while we go too.
    577             */
    578             for(loop = 0; loop < moduleCount; loop++)
    579             {
    580                 fprintf(inOptions->mOutput, "\n");
    581                 fprintf(inOptions->mOutput, "%s\n", modules[loop].mModule);
    582                 fprintf(inOptions->mOutput, "\tTotal:\t%10u\n", (unsigned)(modules[loop].mSize.mCode + modules[loop].mSize.mData));
    583                 fprintf(inOptions->mOutput, "\tCode:\t%10u\n", (unsigned)modules[loop].mSize.mCode);
    584                 fprintf(inOptions->mOutput, "\tData:\t%10u\n", (unsigned)modules[loop].mSize.mData);
    585 
    586                 CLEANUP(modules[loop].mModule);
    587             }
    588 
    589             /*
    590             **  Done with modules.
    591             */
    592             CLEANUP(modules);
    593             moduleCount = 0;
    594         }
    595     }
    596 
    597     return retval;
    598 }
    599 
    600 
    601 int initOptions(Options* outOptions, int inArgc, char** inArgv)
    602 /*
    603 **  returns int     0 if successful.
    604 */
    605 {
    606     int retval = 0;
    607     int loop = 0;
    608     int switchLoop = 0;
    609     int match = 0;
    610     const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
    611     Switch* current = NULL;
    612 
    613     /*
    614     **  Set any defaults.
    615     */
    616     memset(outOptions, 0, sizeof(Options));
    617     outOptions->mProgramName = inArgv[0];
    618     outOptions->mInput = stdin;
    619     outOptions->mInputName = strdup("stdin");
    620     outOptions->mOutput = stdout;
    621     outOptions->mOutputName = strdup("stdout");
    622     outOptions->mMaxSize = 0xFFFFFFFFU;
    623 
    624     if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName)
    625     {
    626         retval = __LINE__;
    627         ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup.");
    628     }
    629 
    630     /*
    631     **  Go through and attempt to do the right thing.
    632     */
    633     for(loop = 1; loop < inArgc && 0 == retval; loop++)
    634     {
    635         match = 0;
    636         current = NULL;
    637 
    638         for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
    639         {
    640             if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
    641             {
    642                 match = __LINE__;
    643             }
    644             else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
    645             {
    646                 match = __LINE__;
    647             }
    648 
    649             if(match)
    650             {
    651                 if(gSwitches[switchLoop]->mHasValue)
    652                 {
    653                     /*
    654                     **  Attempt to absorb next option to fullfill value.
    655                     */
    656                     if(loop + 1 < inArgc)
    657                     {
    658                         loop++;
    659 
    660                         current = gSwitches[switchLoop];
    661                         current->mValue = inArgv[loop];
    662                     }
    663                 }
    664                 else
    665                 {
    666                     current = gSwitches[switchLoop];
    667                 }
    668 
    669                 break;
    670             }
    671         }
    672 
    673         if(0 == match)
    674         {
    675             outOptions->mHelp = __LINE__;
    676             retval = __LINE__;
    677             ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
    678         }
    679         else if(NULL == current)
    680         {
    681             outOptions->mHelp = __LINE__;
    682             retval = __LINE__;
    683             ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
    684         }
    685         else
    686         {
    687             /*
    688             ** Do something based on address/swtich.
    689             */
    690             if(current == &gInputSwitch)
    691             {
    692                 CLEANUP(outOptions->mInputName);
    693                 if(NULL != outOptions->mInput && stdin != outOptions->mInput)
    694                 {
    695                     fclose(outOptions->mInput);
    696                     outOptions->mInput = NULL;
    697                 }
    698 
    699                 outOptions->mInput = fopen(current->mValue, "r");
    700                 if(NULL == outOptions->mInput)
    701                 {
    702                     retval = __LINE__;
    703                     ERROR_REPORT(retval, current->mValue, "Unable to open input file.");
    704                 }
    705                 else
    706                 {
    707                     outOptions->mInputName = strdup(current->mValue);
    708                     if(NULL == outOptions->mInputName)
    709                     {
    710                         retval = __LINE__;
    711                         ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
    712                     }
    713                 }
    714             }
    715             else if(current == &gOutputSwitch)
    716             {
    717                 CLEANUP(outOptions->mOutputName);
    718                 if(NULL != outOptions->mOutput && stdout != outOptions->mOutput)
    719                 {
    720                     fclose(outOptions->mOutput);
    721                     outOptions->mOutput = NULL;
    722                 }
    723 
    724                 outOptions->mOutput = fopen(current->mValue, "a");
    725                 if(NULL == outOptions->mOutput)
    726                 {
    727                     retval = __LINE__;
    728                     ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
    729                 }
    730                 else
    731                 {
    732                     outOptions->mOutputName = strdup(current->mValue);
    733                     if(NULL == outOptions->mOutputName)
    734                     {
    735                         retval = __LINE__;
    736                         ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
    737                     }
    738                 }
    739             }
    740             else if(current == &gHelpSwitch)
    741             {
    742                 outOptions->mHelp = __LINE__;
    743             }
    744             else if(current == &gModuleSwitch)
    745             {
    746                 outOptions->mModules = __LINE__;
    747             }
    748             else if(current == &gTotalSwitch)
    749             {
    750                 outOptions->mTotalOnly = __LINE__;
    751             }
    752             else if(current == &gMinSize)
    753             {
    754                 unsigned long arg = 0;
    755                 char* endScan = NULL;
    756 
    757                 errno = 0;
    758                 arg = strtoul(current->mValue, &endScan, 0);
    759                 if(0 == errno && endScan != current->mValue)
    760                 {
    761                     outOptions->mMinSize = arg;
    762                 }
    763                 else
    764                 {
    765                     retval = __LINE__;
    766                     ERROR_REPORT(retval, current->mValue, "Unable to convert to a number.");
    767                 }
    768             }
    769             else if(current == &gMaxSize)
    770             {
    771                 unsigned long arg = 0;
    772                 char* endScan = NULL;
    773 
    774                 errno = 0;
    775                 arg = strtoul(current->mValue, &endScan, 0);
    776                 if(0 == errno && endScan != current->mValue)
    777                 {
    778                     outOptions->mMaxSize = arg;
    779                 }
    780                 else
    781                 {
    782                     retval = __LINE__;
    783                     ERROR_REPORT(retval, current->mValue, "Unable to convert to a number.");
    784                 }
    785             }
    786             else if(current == &gMatchClass)
    787             {
    788                 char* dupMatch = NULL;
    789 
    790                 dupMatch = strdup(current->mValue);
    791                 if(NULL != dupMatch)
    792                 {
    793                     void* moved = NULL;
    794 
    795                     moved = realloc(outOptions->mMatchClasses, sizeof(char*) * (outOptions->mMatchClassCount + 1));
    796                     if(NULL != moved)
    797                     {
    798                         outOptions->mMatchClasses = (char**)moved;
    799                         outOptions->mMatchClasses[outOptions->mMatchClassCount] = dupMatch;
    800                         outOptions->mMatchClassCount++;
    801                     }
    802                     else
    803                     {
    804                         retval = __LINE__;
    805                         ERROR_REPORT(retval, current->mLongName, "Unable to expand array.");
    806                     }
    807                 }
    808                 else
    809                 {
    810                     retval = __LINE__;
    811                     ERROR_REPORT(retval, current->mValue, "Unable to duplicate string.");
    812                 }
    813             }
    814             else if(current == &gMatchScope)
    815             {
    816                 char* dupMatch = NULL;
    817 
    818                 dupMatch = strdup(current->mValue);
    819                 if(NULL != dupMatch)
    820                 {
    821                     void* moved = NULL;
    822 
    823                     moved = realloc(outOptions->mMatchScopes, sizeof(char*) * (outOptions->mMatchScopeCount + 1));
    824                     if(NULL != moved)
    825                     {
    826                         outOptions->mMatchScopes = (char**)moved;
    827                         outOptions->mMatchScopes[outOptions->mMatchScopeCount] = dupMatch;
    828                         outOptions->mMatchScopeCount++;
    829                     }
    830                     else
    831                     {
    832                         retval = __LINE__;
    833                         ERROR_REPORT(retval, current->mLongName, "Unable to expand array.");
    834                     }
    835                 }
    836                 else
    837                 {
    838                     retval = __LINE__;
    839                     ERROR_REPORT(retval, current->mValue, "Unable to duplicate string.");
    840                 }
    841             }
    842             else if(current == &gMatchModule)
    843             {
    844                 char* dupMatch = NULL;
    845 
    846                 dupMatch = strdup(current->mValue);
    847                 if(NULL != dupMatch)
    848                 {
    849                     void* moved = NULL;
    850 
    851                     moved = realloc(outOptions->mMatchModules, sizeof(char*) * (outOptions->mMatchModuleCount + 1));
    852                     if(NULL != moved)
    853                     {
    854                         outOptions->mMatchModules = (char**)moved;
    855                         outOptions->mMatchModules[outOptions->mMatchModuleCount] = dupMatch;
    856                         outOptions->mMatchModuleCount++;
    857                     }
    858                     else
    859                     {
    860                         retval = __LINE__;
    861                         ERROR_REPORT(retval, current->mLongName, "Unable to expand array.");
    862                     }
    863                 }
    864                 else
    865                 {
    866                     retval = __LINE__;
    867                     ERROR_REPORT(retval, current->mValue, "Unable to duplicate string.");
    868                 }
    869             }
    870             else if(current == &gMatchSection)
    871             {
    872                 char* dupMatch = NULL;
    873 
    874                 dupMatch = strdup(current->mValue);
    875                 if(NULL != dupMatch)
    876                 {
    877                     void* moved = NULL;
    878 
    879                     moved = realloc(outOptions->mMatchSections, sizeof(char*) * (outOptions->mMatchSectionCount + 1));
    880                     if(NULL != moved)
    881                     {
    882                         outOptions->mMatchSections = (char**)moved;
    883                         outOptions->mMatchSections[outOptions->mMatchSectionCount] = dupMatch;
    884                         outOptions->mMatchSectionCount++;
    885                     }
    886                     else
    887                     {
    888                         retval = __LINE__;
    889                         ERROR_REPORT(retval, current->mLongName, "Unable to expand array.");
    890                     }
    891                 }
    892                 else
    893                 {
    894                     retval = __LINE__;
    895                     ERROR_REPORT(retval, current->mValue, "Unable to duplicate string.");
    896                 }
    897             }
    898             else if(current == &gMatchObject)
    899             {
    900                 char* dupMatch = NULL;
    901 
    902                 dupMatch = strdup(current->mValue);
    903                 if(NULL != dupMatch)
    904                 {
    905                     void* moved = NULL;
    906 
    907                     moved = realloc(outOptions->mMatchObjects, sizeof(char*) * (outOptions->mMatchObjectCount + 1));
    908                     if(NULL != moved)
    909                     {
    910                         outOptions->mMatchObjects = (char**)moved;
    911                         outOptions->mMatchObjects[outOptions->mMatchObjectCount] = dupMatch;
    912                         outOptions->mMatchObjectCount++;
    913                     }
    914                     else
    915                     {
    916                         retval = __LINE__;
    917                         ERROR_REPORT(retval, current->mLongName, "Unable to expand array.");
    918                     }
    919                 }
    920                 else
    921                 {
    922                     retval = __LINE__;
    923                     ERROR_REPORT(retval, current->mValue, "Unable to duplicate string.");
    924                 }
    925             }
    926             else if(current == &gMatchSymbol)
    927             {
    928                 char* dupMatch = NULL;
    929 
    930                 dupMatch = strdup(current->mValue);
    931                 if(NULL != dupMatch)
    932                 {
    933                     void* moved = NULL;
    934 
    935                     moved = realloc(outOptions->mMatchSymbols, sizeof(char*) * (outOptions->mMatchSymbolCount + 1));
    936                     if(NULL != moved)
    937                     {
    938                         outOptions->mMatchSymbols = (char**)moved;
    939                         outOptions->mMatchSymbols[outOptions->mMatchSymbolCount] = dupMatch;
    940                         outOptions->mMatchSymbolCount++;
    941                     }
    942                     else
    943                     {
    944                         retval = __LINE__;
    945                         ERROR_REPORT(retval, current->mLongName, "Unable to expand array.");
    946                     }
    947                 }
    948                 else
    949                 {
    950                     retval = __LINE__;
    951                     ERROR_REPORT(retval, current->mValue, "Unable to duplicate string.");
    952                 }
    953             }
    954             else
    955             {
    956                 retval = __LINE__;
    957                 ERROR_REPORT(retval, current->mLongName, "No handler for command line switch.");
    958             }
    959         }
    960     }
    961 
    962     return retval;
    963 }
    964 
    965 
    966 void cleanOptions(Options* inOptions)
    967 /*
    968 **  Clean up any open handles.
    969 */
    970 {
    971     unsigned loop = 0;
    972 
    973     CLEANUP(inOptions->mInputName);
    974     if(NULL != inOptions->mInput && stdin != inOptions->mInput)
    975     {
    976         fclose(inOptions->mInput);
    977     }
    978     CLEANUP(inOptions->mOutputName);
    979     if(NULL != inOptions->mOutput && stdout != inOptions->mOutput)
    980     {
    981         fclose(inOptions->mOutput);
    982     }
    983 
    984     for(loop = 0; loop < inOptions->mMatchClassCount; loop++)
    985     {
    986         CLEANUP(inOptions->mMatchClasses[loop]);
    987     }
    988     CLEANUP(inOptions->mMatchClasses);
    989 
    990     for(loop = 0; loop < inOptions->mMatchScopeCount; loop++)
    991     {
    992         CLEANUP(inOptions->mMatchScopes[loop]);
    993     }
    994     CLEANUP(inOptions->mMatchScopes);
    995 
    996     for(loop = 0; loop < inOptions->mMatchModuleCount; loop++)
    997     {
    998         CLEANUP(inOptions->mMatchModules[loop]);
    999     }
   1000     CLEANUP(inOptions->mMatchModules);
   1001 
   1002     for(loop = 0; loop < inOptions->mMatchSectionCount; loop++)
   1003     {
   1004         CLEANUP(inOptions->mMatchSections[loop]);
   1005     }
   1006     CLEANUP(inOptions->mMatchSections);
   1007 
   1008     for(loop = 0; loop < inOptions->mMatchObjectCount; loop++)
   1009     {
   1010         CLEANUP(inOptions->mMatchObjects[loop]);
   1011     }
   1012     CLEANUP(inOptions->mMatchObjects);
   1013 
   1014     for(loop = 0; loop < inOptions->mMatchSymbolCount; loop++)
   1015     {
   1016         CLEANUP(inOptions->mMatchSymbols[loop]);
   1017     }
   1018     CLEANUP(inOptions->mMatchSymbols);
   1019 
   1020     memset(inOptions, 0, sizeof(Options));
   1021 }
   1022 
   1023 
   1024 void showHelp(Options* inOptions)
   1025 /*
   1026 **  Show some simple help text on usage.
   1027 */
   1028 {
   1029     int loop = 0;
   1030     const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
   1031     const char* valueText = NULL;
   1032 
   1033     printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
   1034     printf("\n");
   1035     printf("arguments:\n");
   1036 
   1037     for(loop = 0; loop < switchCount; loop++)
   1038     {
   1039         if(gSwitches[loop]->mHasValue)
   1040         {
   1041             valueText = " <value>";
   1042         }
   1043         else
   1044         {
   1045             valueText = "";
   1046         }
   1047 
   1048         printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText);
   1049         printf("\t %s%s", gSwitches[loop]->mShortName, valueText);
   1050         printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription);
   1051     }
   1052 
   1053     printf("This tool takes a tsv file and reports composite code and data sizes.\n");
   1054 }
   1055 
   1056 
   1057 int main(int inArgc, char** inArgv)
   1058 {
   1059     int retval = 0;
   1060     Options options;
   1061 
   1062     retval = initOptions(&options, inArgc, inArgv);
   1063     if(options.mHelp)
   1064     {
   1065         showHelp(&options);
   1066     }
   1067     else if(0 == retval)
   1068     {
   1069         retval = codesighs(&options);
   1070     }
   1071 
   1072     cleanOptions(&options);
   1073     return retval;
   1074 }
   1075 
   1076