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
52typedef 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}
99Options;
100
101
102typedef 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}
113Switch;
114
115#define DESC_NEWLINE "\n\t\t"
116
117static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."};
118static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."};
119static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."};
120static Switch gModuleSwitch = {"--modules", "-m", 0, NULL, "Output individual module numbers as well."};
121static Switch gTotalSwitch = {"--totalonly", "-t", 0, NULL, "Output only one number." DESC_NEWLINE "The total overall size." DESC_NEWLINE "Overrides other output options."};
122static Switch gMinSize = {"--min-size", "-min", 1, NULL, "Only consider symbols equal to or greater than this size." DESC_NEWLINE "The default is 0x00000000."};
123static Switch gMaxSize = {"--max-size", "-max", 1, NULL, "Only consider symbols equal to or smaller than this size." DESC_NEWLINE "The default is 0xFFFFFFFF."};
124static 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."};
125static 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."};
126static 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."};
127static 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."};
128static 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."};
129static 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
131static 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
148typedef 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}
159SizeStats;
160
161
162typedef 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}
173ModuleStats;
174
175typedef enum __enum_SegmentClass
176{
177        CODE,
178        DATA
179}
180SegmentClass;
181
182
183static 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
208void 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
231int 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
601int 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
966void 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
1024void 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
1057int 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