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