OLD | NEW |
(Empty) | |
| 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 maptsvdifftool.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 |
| 47 #define ERROR_REPORT(num, val, msg) fprintf(stderr, "error(%d):\t\"%s\"\t%s\n"
, (num), (val), (msg)); |
| 48 #define CLEANUP(ptr) do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(
0) |
| 49 |
| 50 |
| 51 typedef struct __struct_Options |
| 52 /* |
| 53 ** Options to control how we perform. |
| 54 ** |
| 55 ** mProgramName Used in help text. |
| 56 ** mInput File to read for input. |
| 57 ** Default is stdin. |
| 58 ** mInputName Name of the file. |
| 59 ** mOutput Output file, append. |
| 60 ** Default is stdout. |
| 61 ** mOutputName Name of the file. |
| 62 ** mHelp Whether or not help should be shown. |
| 63 ** mSummaryOnly Only output a signle line. |
| 64 ** mZeroDrift Output zero drift data. |
| 65 ** mNegation Perform negation heuristics on the symbol drifts. |
| 66 */ |
| 67 { |
| 68 const char* mProgramName; |
| 69 FILE* mInput; |
| 70 char* mInputName; |
| 71 FILE* mOutput; |
| 72 char* mOutputName; |
| 73 int mHelp; |
| 74 int mSummaryOnly; |
| 75 int mZeroDrift; |
| 76 int mNegation; |
| 77 } |
| 78 Options; |
| 79 |
| 80 |
| 81 typedef struct __struct_Switch |
| 82 /* |
| 83 ** Command line options. |
| 84 */ |
| 85 { |
| 86 const char* mLongName; |
| 87 const char* mShortName; |
| 88 int mHasValue; |
| 89 const char* mValue; |
| 90 const char* mDescription; |
| 91 } |
| 92 Switch; |
| 93 |
| 94 #define DESC_NEWLINE "\n\t\t" |
| 95 |
| 96 static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DE
SC_NEWLINE "stdin is default."}; |
| 97 static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file."
DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."}; |
| 98 static Switch gSummarySwitch = {"--summary", "-s", 0, NULL, "Only output a singl
e line." DESC_NEWLINE "The cumulative size changes." DESC_NEWLINE "Overrides all
other output options."}; |
| 99 static Switch gZeroDriftSwitch = {"--zerodrift", "-z", 0, NULL, "Output zero dri
ft data." DESC_NEWLINE "Reports symbol changes even when there is no net drift."
}; |
| 100 static Switch gNegationSwitch = {"--negation", "-n", 0, NULL, "Use negation heur
istics." DESC_NEWLINE "When symbol sizes are inferred by offset, order changes c
ause noise." DESC_NEWLINE "This helps see through the noise by eliminating equal
and opposite drifts."}; |
| 101 static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."}; |
| 102 |
| 103 static Switch* gSwitches[] = { |
| 104 &gInputSwitch, |
| 105 &gOutputSwitch, |
| 106 &gSummarySwitch, |
| 107 &gZeroDriftSwitch, |
| 108 &gNegationSwitch, |
| 109 &gHelpSwitch |
| 110 }; |
| 111 |
| 112 |
| 113 typedef struct __struct_SizeComposition |
| 114 /* |
| 115 ** Used to keep which parts positive and negative resulted in the total. |
| 116 */ |
| 117 { |
| 118 int mPositive; |
| 119 int mNegative; |
| 120 } |
| 121 SizeComposition; |
| 122 |
| 123 |
| 124 typedef struct __struct_SizeStats |
| 125 /* |
| 126 ** Keep track of sizes. |
| 127 ** Use signed integers so that negatives are valid, in which case we shrunk. |
| 128 */ |
| 129 { |
| 130 int mCode; |
| 131 SizeComposition mCodeComposition; |
| 132 |
| 133 int mData; |
| 134 SizeComposition mDataComposition; |
| 135 } |
| 136 SizeStats; |
| 137 |
| 138 |
| 139 typedef enum __enum_SegmentClass |
| 140 /* |
| 141 ** What type of data a segment holds. |
| 142 */ |
| 143 { |
| 144 CODE, |
| 145 DATA |
| 146 } |
| 147 SegmentClass; |
| 148 |
| 149 |
| 150 typedef struct __struct_SymbolStats |
| 151 /* |
| 152 ** Symbol level stats. |
| 153 */ |
| 154 { |
| 155 char* mSymbol; |
| 156 int mSize; |
| 157 } |
| 158 SymbolStats; |
| 159 |
| 160 |
| 161 typedef struct __struct_ObjectStats |
| 162 /* |
| 163 ** Object level stats. |
| 164 */ |
| 165 { |
| 166 char* mObject; |
| 167 int mSize; |
| 168 SizeComposition mComposition; |
| 169 SymbolStats* mSymbols; |
| 170 unsigned mSymbolCount; |
| 171 } |
| 172 ObjectStats; |
| 173 |
| 174 |
| 175 typedef struct __struct_SegmentStats |
| 176 /* |
| 177 ** Segment level stats. |
| 178 */ |
| 179 { |
| 180 char* mSegment; |
| 181 SegmentClass mClass; |
| 182 int mSize; |
| 183 SizeComposition mComposition; |
| 184 ObjectStats* mObjects; |
| 185 unsigned mObjectCount; |
| 186 } |
| 187 SegmentStats; |
| 188 |
| 189 |
| 190 typedef struct __struct_ModuleStats |
| 191 /* |
| 192 ** Module level stats. |
| 193 */ |
| 194 { |
| 195 char* mModule; |
| 196 SizeStats mSize; |
| 197 SegmentStats* mSegments; |
| 198 unsigned mSegmentCount; |
| 199 } |
| 200 ModuleStats; |
| 201 |
| 202 |
| 203 static int moduleCompare(const void* in1, const void* in2) |
| 204 /* |
| 205 ** qsort helper. |
| 206 */ |
| 207 { |
| 208 int retval = 0; |
| 209 |
| 210 ModuleStats* one = (ModuleStats*)in1; |
| 211 ModuleStats* two = (ModuleStats*)in2; |
| 212 |
| 213 int oneSize = (one->mSize.mCode + one->mSize.mData); |
| 214 int twoSize = (two->mSize.mCode + two->mSize.mData); |
| 215 |
| 216 if(oneSize < twoSize) |
| 217 { |
| 218 retval = 1; |
| 219 } |
| 220 else if(oneSize > twoSize) |
| 221 { |
| 222 retval = -1; |
| 223 } |
| 224 else |
| 225 { |
| 226 retval = strcmp(one->mModule, two->mModule); |
| 227 if(0 > oneSize && 0 > twoSize) |
| 228 { |
| 229 retval *= -1; |
| 230 } |
| 231 } |
| 232 |
| 233 return retval; |
| 234 } |
| 235 |
| 236 |
| 237 static int segmentCompare(const void* in1, const void* in2) |
| 238 /* |
| 239 ** qsort helper. |
| 240 */ |
| 241 { |
| 242 int retval = 0; |
| 243 |
| 244 SegmentStats* one = (SegmentStats*)in1; |
| 245 SegmentStats* two = (SegmentStats*)in2; |
| 246 |
| 247 if(one->mSize < two->mSize) |
| 248 { |
| 249 retval = 1; |
| 250 } |
| 251 else if(one->mSize > two->mSize) |
| 252 { |
| 253 retval = -1; |
| 254 } |
| 255 else |
| 256 { |
| 257 retval = strcmp(one->mSegment, two->mSegment); |
| 258 if(0 > one->mSize && 0 > two->mSize) |
| 259 { |
| 260 retval *= -1; |
| 261 } |
| 262 } |
| 263 |
| 264 return retval; |
| 265 } |
| 266 |
| 267 |
| 268 static int objectCompare(const void* in1, const void* in2) |
| 269 /* |
| 270 ** qsort helper. |
| 271 */ |
| 272 { |
| 273 int retval = 0; |
| 274 |
| 275 ObjectStats* one = (ObjectStats*)in1; |
| 276 ObjectStats* two = (ObjectStats*)in2; |
| 277 |
| 278 if(one->mSize < two->mSize) |
| 279 { |
| 280 retval = 1; |
| 281 } |
| 282 else if(one->mSize > two->mSize) |
| 283 { |
| 284 retval = -1; |
| 285 } |
| 286 else |
| 287 { |
| 288 retval = strcmp(one->mObject, two->mObject); |
| 289 if(0 > one->mSize && 0 > two->mSize) |
| 290 { |
| 291 retval *= -1; |
| 292 } |
| 293 } |
| 294 |
| 295 return retval; |
| 296 } |
| 297 |
| 298 |
| 299 static int symbolCompare(const void* in1, const void* in2) |
| 300 /* |
| 301 ** qsort helper. |
| 302 */ |
| 303 { |
| 304 int retval = 0; |
| 305 |
| 306 SymbolStats* one = (SymbolStats*)in1; |
| 307 SymbolStats* two = (SymbolStats*)in2; |
| 308 |
| 309 if(one->mSize < two->mSize) |
| 310 { |
| 311 retval = 1; |
| 312 } |
| 313 else if(one->mSize > two->mSize) |
| 314 { |
| 315 retval = -1; |
| 316 } |
| 317 else |
| 318 { |
| 319 retval = strcmp(one->mSymbol, two->mSymbol); |
| 320 if(0 > one->mSize && 0 > two->mSize) |
| 321 { |
| 322 retval *= -1; |
| 323 } |
| 324 } |
| 325 |
| 326 return retval; |
| 327 } |
| 328 |
| 329 |
| 330 void trimWhite(char* inString) |
| 331 /* |
| 332 ** Remove any whitespace from the end of the string. |
| 333 */ |
| 334 { |
| 335 int len = strlen(inString); |
| 336 |
| 337 while(len) |
| 338 { |
| 339 len--; |
| 340 |
| 341 if(isspace(*(inString + len))) |
| 342 { |
| 343 *(inString + len) = '\0'; |
| 344 } |
| 345 else |
| 346 { |
| 347 break; |
| 348 } |
| 349 } |
| 350 } |
| 351 |
| 352 |
| 353 int difftool(Options* inOptions) |
| 354 /* |
| 355 ** Read a diff file and spit out relevant information. |
| 356 */ |
| 357 { |
| 358 int retval = 0; |
| 359 char lineBuffer[0x500]; |
| 360 SizeStats overall; |
| 361 ModuleStats* modules = NULL; |
| 362 unsigned moduleCount = 0; |
| 363 unsigned moduleLoop = 0; |
| 364 ModuleStats* theModule = NULL; |
| 365 unsigned segmentLoop = 0; |
| 366 SegmentStats* theSegment = NULL; |
| 367 unsigned objectLoop = 0; |
| 368 ObjectStats* theObject = NULL; |
| 369 unsigned symbolLoop = 0; |
| 370 SymbolStats* theSymbol = NULL; |
| 371 unsigned allSymbolCount = 0; |
| 372 |
| 373 memset(&overall, 0, sizeof(overall)); |
| 374 |
| 375 /* |
| 376 ** Read the entire diff file. |
| 377 ** We're only interested in lines beginning with < or > |
| 378 */ |
| 379 while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions
->mInput)) |
| 380 { |
| 381 trimWhite(lineBuffer); |
| 382 |
| 383 if(('<' == lineBuffer[0] || '>' == lineBuffer[0]) && ' ' == lineBuffer[1
]) |
| 384 { |
| 385 int additive = 0; |
| 386 char* theLine = &lineBuffer[2]; |
| 387 int scanRes = 0; |
| 388 int size; |
| 389 char segClass[0x10]; |
| 390 char scope[0x10]; |
| 391 char module[0x100]; |
| 392 char segment[0x40]; |
| 393 char object[0x100]; |
| 394 char* symbol = NULL; |
| 395 |
| 396 /* |
| 397 ** Figure out if the line adds or subtracts from something. |
| 398 */ |
| 399 if('>' == lineBuffer[0]) |
| 400 { |
| 401 additive = __LINE__; |
| 402 } |
| 403 |
| 404 |
| 405 /* |
| 406 ** Scan the line for information. |
| 407 */ |
| 408 scanRes = sscanf(theLine, |
| 409 "%x\t%s\t%s\t%s\t%s\t%s\t", |
| 410 (unsigned*)&size, |
| 411 segClass, |
| 412 scope, |
| 413 module, |
| 414 segment, |
| 415 object); |
| 416 |
| 417 if(6 == scanRes) |
| 418 { |
| 419 SegmentClass segmentClass = DATA; |
| 420 |
| 421 symbol = strrchr(theLine, '\t') + 1; |
| 422 |
| 423 if(0 == strcmp(segClass, "CODE")) |
| 424 { |
| 425 segmentClass = CODE; |
| 426 } |
| 427 else if(0 == strcmp(segClass, "DATA")) |
| 428 { |
| 429 segmentClass = DATA; |
| 430 } |
| 431 else |
| 432 { |
| 433 retval = __LINE__; |
| 434 ERROR_REPORT(retval, segClass, "Unable to determine segment
class."); |
| 435 } |
| 436 |
| 437 if(0 == retval) |
| 438 { |
| 439 unsigned moduleIndex = 0; |
| 440 |
| 441 /* |
| 442 ** Find, in succession, the following things: |
| 443 ** the module |
| 444 ** the segment |
| 445 ** the object |
| 446 ** the symbol |
| 447 ** Failure to find any one of these means to create it. |
| 448 */ |
| 449 |
| 450 for(moduleIndex = 0; moduleIndex < moduleCount; moduleIndex+
+) |
| 451 { |
| 452 if(0 == strcmp(modules[moduleIndex].mModule, module)) |
| 453 { |
| 454 break; |
| 455 } |
| 456 } |
| 457 |
| 458 if(moduleIndex == moduleCount) |
| 459 { |
| 460 void* moved = NULL; |
| 461 |
| 462 moved = realloc(modules, sizeof(ModuleStats) * (1 + modu
leCount)); |
| 463 if(NULL != moved) |
| 464 { |
| 465 modules = (ModuleStats*)moved; |
| 466 moduleCount++; |
| 467 memset(modules + moduleIndex, 0, sizeof(ModuleStats)
); |
| 468 |
| 469 modules[moduleIndex].mModule = strdup(module); |
| 470 if(NULL == modules[moduleIndex].mModule) |
| 471 { |
| 472 retval = __LINE__; |
| 473 ERROR_REPORT(retval, module, "Unable to duplicat
e string."); |
| 474 } |
| 475 } |
| 476 else |
| 477 { |
| 478 retval = __LINE__; |
| 479 ERROR_REPORT(retval, inOptions->mProgramName, "Unabl
e to increase module array."); |
| 480 } |
| 481 } |
| 482 |
| 483 if(0 == retval) |
| 484 { |
| 485 unsigned segmentIndex = 0; |
| 486 theModule = (modules + moduleIndex); |
| 487 |
| 488 for(segmentIndex = 0; segmentIndex < theModule->mSegment
Count; segmentIndex++) |
| 489 { |
| 490 if(0 == strcmp(segment, theModule->mSegments[segment
Index].mSegment)) |
| 491 { |
| 492 break; |
| 493 } |
| 494 } |
| 495 |
| 496 if(segmentIndex == theModule->mSegmentCount) |
| 497 { |
| 498 void* moved = NULL; |
| 499 |
| 500 moved = realloc(theModule->mSegments, sizeof(Segment
Stats) * (theModule->mSegmentCount + 1)); |
| 501 if(NULL != moved) |
| 502 { |
| 503 theModule->mSegments = (SegmentStats*)moved; |
| 504 theModule->mSegmentCount++; |
| 505 memset(theModule->mSegments + segmentIndex, 0, s
izeof(SegmentStats)); |
| 506 |
| 507 theModule->mSegments[segmentIndex].mClass = segm
entClass; |
| 508 theModule->mSegments[segmentIndex].mSegment = st
rdup(segment); |
| 509 if(NULL == theModule->mSegments[segmentIndex].mS
egment) |
| 510 { |
| 511 retval = __LINE__; |
| 512 ERROR_REPORT(retval, segment, "Unable to dup
licate string."); |
| 513 } |
| 514 } |
| 515 else |
| 516 { |
| 517 retval = __LINE__; |
| 518 ERROR_REPORT(retval, inOptions->mProgramName, "U
nable to increase segment array."); |
| 519 } |
| 520 } |
| 521 |
| 522 if(0 == retval) |
| 523 { |
| 524 unsigned objectIndex = 0; |
| 525 theSegment = (theModule->mSegments + segmentIndex); |
| 526 |
| 527 for(objectIndex = 0; objectIndex < theSegment->mObje
ctCount; objectIndex++) |
| 528 { |
| 529 if(0 == strcmp(object, theSegment->mObjects[obje
ctIndex].mObject)) |
| 530 { |
| 531 break; |
| 532 } |
| 533 } |
| 534 |
| 535 if(objectIndex == theSegment->mObjectCount) |
| 536 { |
| 537 void* moved = NULL; |
| 538 |
| 539 moved = realloc(theSegment->mObjects, sizeof(Obj
ectStats) * (1 + theSegment->mObjectCount)); |
| 540 if(NULL != moved) |
| 541 { |
| 542 theSegment->mObjects = (ObjectStats*)moved; |
| 543 theSegment->mObjectCount++; |
| 544 memset(theSegment->mObjects + objectIndex, 0
, sizeof(ObjectStats)); |
| 545 |
| 546 theSegment->mObjects[objectIndex].mObject =
strdup(object); |
| 547 if(NULL == theSegment->mObjects[objectIndex]
.mObject) |
| 548 { |
| 549 retval = __LINE__; |
| 550 ERROR_REPORT(retval, object, "Unable to
duplicate string."); |
| 551 } |
| 552 } |
| 553 else |
| 554 { |
| 555 retval = __LINE__; |
| 556 ERROR_REPORT(retval, inOptions->mProgramName
, "Unable to increase object array."); |
| 557 } |
| 558 } |
| 559 |
| 560 if(0 == retval) |
| 561 { |
| 562 unsigned symbolIndex = 0; |
| 563 theObject = (theSegment->mObjects + objectIndex)
; |
| 564 |
| 565 for(symbolIndex = 0; symbolIndex < theObject->mS
ymbolCount; symbolIndex++) |
| 566 { |
| 567 if(0 == strcmp(symbol, theObject->mSymbols[s
ymbolIndex].mSymbol)) |
| 568 { |
| 569 break; |
| 570 } |
| 571 } |
| 572 |
| 573 if(symbolIndex == theObject->mSymbolCount) |
| 574 { |
| 575 void* moved = NULL; |
| 576 |
| 577 moved = realloc(theObject->mSymbols, sizeof(
SymbolStats) * (1 + theObject->mSymbolCount)); |
| 578 if(NULL != moved) |
| 579 { |
| 580 theObject->mSymbols = (SymbolStats*)move
d; |
| 581 theObject->mSymbolCount++; |
| 582 allSymbolCount++; |
| 583 memset(theObject->mSymbols + symbolIndex
, 0, sizeof(SymbolStats)); |
| 584 |
| 585 theObject->mSymbols[symbolIndex].mSymbol
= strdup(symbol); |
| 586 if(NULL == theObject->mSymbols[symbolInd
ex].mSymbol) |
| 587 { |
| 588 retval = __LINE__; |
| 589 ERROR_REPORT(retval, symbol, "Unable
to duplicate string."); |
| 590 } |
| 591 } |
| 592 else |
| 593 { |
| 594 retval = __LINE__; |
| 595 ERROR_REPORT(retval, inOptions->mProgram
Name, "Unable to increase symbol array."); |
| 596 } |
| 597 } |
| 598 |
| 599 if(0 == retval) |
| 600 { |
| 601 theSymbol = (theObject->mSymbols + symbolInd
ex); |
| 602 |
| 603 /* |
| 604 ** Update our various totals. |
| 605 */ |
| 606 if(additive) |
| 607 { |
| 608 if(CODE == segmentClass) |
| 609 { |
| 610 overall.mCode += size; |
| 611 theModule->mSize.mCode += size; |
| 612 } |
| 613 else if(DATA == segmentClass) |
| 614 { |
| 615 overall.mData += size; |
| 616 theModule->mSize.mData += size; |
| 617 } |
| 618 |
| 619 theSegment->mSize += size; |
| 620 theObject->mSize += size; |
| 621 theSymbol->mSize += size; |
| 622 } |
| 623 else |
| 624 { |
| 625 if(CODE == segmentClass) |
| 626 { |
| 627 overall.mCode -= size; |
| 628 theModule->mSize.mCode -= size; |
| 629 } |
| 630 else if(DATA == segmentClass) |
| 631 { |
| 632 overall.mData -= size; |
| 633 theModule->mSize.mData -= size; |
| 634 } |
| 635 |
| 636 theSegment->mSize -= size; |
| 637 theObject->mSize -= size; |
| 638 theSymbol->mSize -= size; |
| 639 } |
| 640 } |
| 641 } |
| 642 } |
| 643 } |
| 644 } |
| 645 } |
| 646 else |
| 647 { |
| 648 retval = __LINE__; |
| 649 ERROR_REPORT(retval, inOptions->mInputName, "Unable to scan line
data."); |
| 650 } |
| 651 } |
| 652 } |
| 653 |
| 654 if(0 == retval && 0 != ferror(inOptions->mInput)) |
| 655 { |
| 656 retval = __LINE__; |
| 657 ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file."); |
| 658 } |
| 659 |
| 660 /* |
| 661 ** Next, it is time to perform revisionist history of sorts. |
| 662 ** If the negation switch is in play, we perfrom the following |
| 663 ** aggressive steps: |
| 664 ** |
| 665 ** For each section, find size changes which have an equal and |
| 666 ** opposite change, and set them both to zero. |
| 667 ** However, you can only do this if the number of negating changes |
| 668 ** is even, as if it is odd, then any one of the many could be |
| 669 ** at fault for the actual change. |
| 670 ** |
| 671 ** This orginally exists to make the win32 codesighs reports more |
| 672 ** readable/meaningful. |
| 673 */ |
| 674 if(0 == retval && 0 != inOptions->mNegation) |
| 675 { |
| 676 ObjectStats** objArray = NULL; |
| 677 SymbolStats** symArray = NULL; |
| 678 |
| 679 /* |
| 680 ** Create arrays big enough to hold all symbols. |
| 681 ** As well as an array to keep the owning object at the same index. |
| 682 ** We will keep the object around as we may need to modify the size. |
| 683 */ |
| 684 objArray = (ObjectStats**)malloc(allSymbolCount * sizeof(ObjectStats*)); |
| 685 symArray = (SymbolStats**)malloc(allSymbolCount * sizeof(SymbolStats*)); |
| 686 if(NULL == objArray || NULL == symArray) |
| 687 { |
| 688 retval = __LINE__; |
| 689 ERROR_REPORT(retval, inOptions->mProgramName, "Unable to allocate ne
gation array memory."); |
| 690 } |
| 691 else |
| 692 { |
| 693 unsigned arrayCount = 0; |
| 694 unsigned arrayLoop = 0; |
| 695 |
| 696 /* |
| 697 ** Go through and perform the steps on each section/segment. |
| 698 */ |
| 699 for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++) |
| 700 { |
| 701 theModule = modules + moduleLoop; |
| 702 |
| 703 for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; seg
mentLoop++) |
| 704 { |
| 705 theSegment = theModule->mSegments + segmentLoop; |
| 706 |
| 707 /* |
| 708 ** Collect all symbols under this section. |
| 709 ** The symbols are spread out between all the objects, |
| 710 ** so keep track of both independently at the |
| 711 ** same index. |
| 712 */ |
| 713 arrayCount = 0; |
| 714 |
| 715 for(objectLoop = 0; objectLoop < theSegment->mObjectCount; o
bjectLoop++) |
| 716 { |
| 717 theObject = theSegment->mObjects + objectLoop; |
| 718 |
| 719 for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount
; symbolLoop++) |
| 720 { |
| 721 theSymbol = theObject->mSymbols + symbolLoop; |
| 722 |
| 723 objArray[arrayCount] = theObject; |
| 724 symArray[arrayCount] = theSymbol; |
| 725 arrayCount++; |
| 726 } |
| 727 } |
| 728 |
| 729 /* |
| 730 ** Now that we have a list of symbols, go through each |
| 731 ** and see if there is a chance of negation. |
| 732 */ |
| 733 for(arrayLoop = 0; arrayLoop < arrayCount; arrayLoop++) |
| 734 { |
| 735 /* |
| 736 ** If the item is NULL, it was already negated. |
| 737 ** Don't do this for items with a zero size. |
| 738 */ |
| 739 if(NULL != symArray[arrayLoop] && 0 != symArray[arrayLoo
p]->mSize) |
| 740 { |
| 741 unsigned identicalValues = 0; |
| 742 unsigned oppositeValues = 0; |
| 743 unsigned lookLoop = 0; |
| 744 const int lookingFor = symArray[arrayLoop]->mSize; |
| 745 |
| 746 /* |
| 747 ** Count the number of items with this value. |
| 748 ** Count the number of items with the opposite equa
l value. |
| 749 ** If they are equal, go through and negate all siz
es. |
| 750 */ |
| 751 for(lookLoop = arrayLoop; lookLoop < arrayCount; loo
kLoop++) |
| 752 { |
| 753 /* |
| 754 ** Skip negated items. |
| 755 ** Skip zero length items. |
| 756 */ |
| 757 if(NULL == symArray[lookLoop] || 0 == symArray[l
ookLoop]->mSize) |
| 758 { |
| 759 continue; |
| 760 } |
| 761 |
| 762 if(lookingFor == symArray[lookLoop]->mSize) |
| 763 { |
| 764 identicalValues++; |
| 765 } |
| 766 else if((-1 * lookingFor) == symArray[lookLoop]-
>mSize) |
| 767 { |
| 768 oppositeValues++; |
| 769 } |
| 770 } |
| 771 |
| 772 if(0 != identicalValues && identicalValues == opposi
teValues) |
| 773 { |
| 774 unsigned negationLoop = 0; |
| 775 |
| 776 for(negationLoop = arrayLoop; 0 != identicalValu
es || 0 != oppositeValues; negationLoop++) |
| 777 { |
| 778 /* |
| 779 ** Skip negated items. |
| 780 ** Skip zero length items. |
| 781 */ |
| 782 if(NULL == symArray[negationLoop] || 0 == sy
mArray[negationLoop]->mSize) |
| 783 { |
| 784 continue; |
| 785 } |
| 786 |
| 787 /* |
| 788 ** Negate any size matches. |
| 789 ** Reflect the change in the object as well
. |
| 790 ** Clear the symbol. |
| 791 */ |
| 792 if(lookingFor == symArray[negationLoop]->mSi
ze) |
| 793 { |
| 794 objArray[negationLoop]->mSize -= looking
For; |
| 795 symArray[negationLoop]->mSize = 0; |
| 796 symArray[negationLoop] = NULL; |
| 797 |
| 798 identicalValues--; |
| 799 } |
| 800 else if((-1 * lookingFor) == symArray[negati
onLoop]->mSize) |
| 801 { |
| 802 objArray[negationLoop]->mSize += looking
For; |
| 803 symArray[negationLoop]->mSize = 0; |
| 804 symArray[negationLoop] = NULL; |
| 805 |
| 806 oppositeValues--; |
| 807 } |
| 808 } |
| 809 } |
| 810 } |
| 811 } |
| 812 } |
| 813 } |
| 814 } |
| 815 |
| 816 CLEANUP(objArray); |
| 817 CLEANUP(symArray); |
| 818 } |
| 819 |
| 820 |
| 821 /* |
| 822 ** If all went well, time to report. |
| 823 */ |
| 824 if(0 == retval) |
| 825 { |
| 826 /* |
| 827 ** Loop through our data once more, so that the symbols can |
| 828 ** propigate their changes upwards in a positive/negative |
| 829 ** fashion. |
| 830 ** This will help give the composite change more meaning. |
| 831 */ |
| 832 for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++) |
| 833 { |
| 834 theModule = modules + moduleLoop; |
| 835 |
| 836 /* |
| 837 ** Skip if there is zero drift, or no net change. |
| 838 */ |
| 839 if(0 == inOptions->mZeroDrift && 0 == (theModule->mSize.mCode + theM
odule->mSize.mData)) |
| 840 { |
| 841 continue; |
| 842 } |
| 843 |
| 844 for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segment
Loop++) |
| 845 { |
| 846 theSegment = theModule->mSegments + segmentLoop; |
| 847 |
| 848 /* |
| 849 ** Skip if there is zero drift, or no net change. |
| 850 */ |
| 851 if(0 == inOptions->mZeroDrift && 0 == theSegment->mSize) |
| 852 { |
| 853 continue; |
| 854 } |
| 855 |
| 856 for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objec
tLoop++) |
| 857 { |
| 858 theObject = theSegment->mObjects + objectLoop; |
| 859 |
| 860 /* |
| 861 ** Skip if there is zero drift, or no net change. |
| 862 */ |
| 863 if(0 == inOptions->mZeroDrift && 0 == theObject->mSize) |
| 864 { |
| 865 continue; |
| 866 } |
| 867 |
| 868 for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount; sy
mbolLoop++) |
| 869 { |
| 870 theSymbol = theObject->mSymbols + symbolLoop; |
| 871 |
| 872 /* |
| 873 ** Propagate the composition all the way to the top. |
| 874 ** Sizes of zero change are skipped. |
| 875 */ |
| 876 if(0 < theSymbol->mSize) |
| 877 { |
| 878 theObject->mComposition.mPositive += theSymbol->mSiz
e; |
| 879 theSegment->mComposition.mPositive += theSymbol->mSi
ze; |
| 880 if(CODE == theSegment->mClass) |
| 881 { |
| 882 overall.mCodeComposition.mPositive += theSymbol-
>mSize; |
| 883 theModule->mSize.mCodeComposition.mPositive += t
heSymbol->mSize; |
| 884 } |
| 885 else if(DATA == theSegment->mClass) |
| 886 { |
| 887 overall.mDataComposition.mPositive += theSymbol-
>mSize; |
| 888 theModule->mSize.mDataComposition.mPositive += t
heSymbol->mSize; |
| 889 } |
| 890 } |
| 891 else if(0 > theSymbol->mSize) |
| 892 { |
| 893 theObject->mComposition.mNegative += theSymbol->mSiz
e; |
| 894 theSegment->mComposition.mNegative += theSymbol->mSi
ze; |
| 895 if(CODE == theSegment->mClass) |
| 896 { |
| 897 overall.mCodeComposition.mNegative += theSymbol-
>mSize; |
| 898 theModule->mSize.mCodeComposition.mNegative += t
heSymbol->mSize; |
| 899 } |
| 900 else if(DATA == theSegment->mClass) |
| 901 { |
| 902 overall.mDataComposition.mNegative += theSymbol-
>mSize; |
| 903 theModule->mSize.mDataComposition.mNegative += t
heSymbol->mSize; |
| 904 } |
| 905 } |
| 906 } |
| 907 } |
| 908 } |
| 909 } |
| 910 |
| 911 |
| 912 if(inOptions->mSummaryOnly) |
| 913 { |
| 914 fprintf(inOptions->mOutput, "%+d (%+d/%+d)\n", overall.mCode + overa
ll.mData, overall.mCodeComposition.mPositive + overall.mDataComposition.mPositiv
e, overall.mCodeComposition.mNegative + overall.mDataComposition.mNegative); |
| 915 } |
| 916 else |
| 917 { |
| 918 fprintf(inOptions->mOutput, "Overall Change in Size\n"); |
| 919 fprintf(inOptions->mOutput, "\tTotal:\t%+11d (%+d/%+d)\n", overall.m
Code + overall.mData, overall.mCodeComposition.mPositive + overall.mDataComposit
ion.mPositive, overall.mCodeComposition.mNegative + overall.mDataComposition.mNe
gative); |
| 920 fprintf(inOptions->mOutput, "\tCode:\t%+11d (%+d/%+d)\n", overall.mC
ode, overall.mCodeComposition.mPositive, overall.mCodeComposition.mNegative); |
| 921 fprintf(inOptions->mOutput, "\tData:\t%+11d (%+d/%+d)\n", overall.mD
ata, overall.mDataComposition.mPositive, overall.mDataComposition.mNegative); |
| 922 } |
| 923 |
| 924 /* |
| 925 ** Check what else we should output. |
| 926 */ |
| 927 if(0 == inOptions->mSummaryOnly && NULL != modules && moduleCount) |
| 928 { |
| 929 const char* segmentType = NULL; |
| 930 |
| 931 /* |
| 932 ** We're going to sort everything. |
| 933 */ |
| 934 qsort(modules, moduleCount, sizeof(ModuleStats), moduleCompare); |
| 935 for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++) |
| 936 { |
| 937 theModule = modules + moduleLoop; |
| 938 |
| 939 qsort(theModule->mSegments, theModule->mSegmentCount, sizeof(Seg
mentStats), segmentCompare); |
| 940 |
| 941 for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; seg
mentLoop++) |
| 942 { |
| 943 theSegment = theModule->mSegments + segmentLoop; |
| 944 |
| 945 qsort(theSegment->mObjects, theSegment->mObjectCount, sizeof
(ObjectStats), objectCompare); |
| 946 |
| 947 for(objectLoop = 0; objectLoop < theSegment->mObjectCount; o
bjectLoop++) |
| 948 { |
| 949 theObject = theSegment->mObjects + objectLoop; |
| 950 |
| 951 qsort(theObject->mSymbols, theObject->mSymbolCount, size
of(SymbolStats), symbolCompare); |
| 952 } |
| 953 } |
| 954 } |
| 955 |
| 956 /* |
| 957 ** Loop through for output. |
| 958 */ |
| 959 for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++) |
| 960 { |
| 961 theModule = modules + moduleLoop; |
| 962 |
| 963 /* |
| 964 ** Skip if there is zero drift, or no net change. |
| 965 */ |
| 966 if(0 == inOptions->mZeroDrift && 0 == (theModule->mSize.mCode +
theModule->mSize.mData)) |
| 967 { |
| 968 continue; |
| 969 } |
| 970 |
| 971 fprintf(inOptions->mOutput, "\n"); |
| 972 fprintf(inOptions->mOutput, "%s\n", theModule->mModule); |
| 973 fprintf(inOptions->mOutput, "\tTotal:\t%+11d (%+d/%+d)\n", theMo
dule->mSize.mCode + theModule->mSize.mData, theModule->mSize.mCodeComposition.mP
ositive + theModule->mSize.mDataComposition.mPositive, theModule->mSize.mCodeCom
position.mNegative + theModule->mSize.mDataComposition.mNegative); |
| 974 fprintf(inOptions->mOutput, "\tCode:\t%+11d (%+d/%+d)\n", theMod
ule->mSize.mCode, theModule->mSize.mCodeComposition.mPositive, theModule->mSize.
mCodeComposition.mNegative); |
| 975 fprintf(inOptions->mOutput, "\tData:\t%+11d (%+d/%+d)\n", theMod
ule->mSize.mData, theModule->mSize.mDataComposition.mPositive, theModule->mSize.
mDataComposition.mNegative); |
| 976 |
| 977 for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; seg
mentLoop++) |
| 978 { |
| 979 theSegment = theModule->mSegments + segmentLoop; |
| 980 |
| 981 /* |
| 982 ** Skip if there is zero drift, or no net change. |
| 983 */ |
| 984 if(0 == inOptions->mZeroDrift && 0 == theSegment->mSize) |
| 985 { |
| 986 continue; |
| 987 } |
| 988 |
| 989 if(CODE == theSegment->mClass) |
| 990 { |
| 991 segmentType = "CODE"; |
| 992 } |
| 993 else if(DATA == theSegment->mClass) |
| 994 { |
| 995 segmentType = "DATA"; |
| 996 } |
| 997 |
| 998 fprintf(inOptions->mOutput, "\t%+11d (%+d/%+d)\t%s (%s)\n",
theSegment->mSize, theSegment->mComposition.mPositive, theSegment->mComposition.
mNegative, theSegment->mSegment, segmentType); |
| 999 |
| 1000 for(objectLoop = 0; objectLoop < theSegment->mObjectCount; o
bjectLoop++) |
| 1001 { |
| 1002 theObject = theSegment->mObjects + objectLoop; |
| 1003 |
| 1004 /* |
| 1005 ** Skip if there is zero drift, or no net change. |
| 1006 */ |
| 1007 if(0 == inOptions->mZeroDrift && 0 == theObject->mSize) |
| 1008 { |
| 1009 continue; |
| 1010 } |
| 1011 |
| 1012 fprintf(inOptions->mOutput, "\t\t%+11d (%+d/%+d)\t%s\n",
theObject->mSize, theObject->mComposition.mPositive, theObject->mComposition.mN
egative, theObject->mObject); |
| 1013 |
| 1014 for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount
; symbolLoop++) |
| 1015 { |
| 1016 theSymbol = theObject->mSymbols + symbolLoop; |
| 1017 |
| 1018 /* |
| 1019 ** Skip if there is zero drift, or no net change. |
| 1020 */ |
| 1021 if(0 == inOptions->mZeroDrift && 0 == theSymbol->mSi
ze) |
| 1022 { |
| 1023 continue; |
| 1024 } |
| 1025 |
| 1026 fprintf(inOptions->mOutput, "\t\t\t%+11d\t%s\n", the
Symbol->mSize, theSymbol->mSymbol); |
| 1027 } |
| 1028 } |
| 1029 } |
| 1030 } |
| 1031 } |
| 1032 } |
| 1033 |
| 1034 /* |
| 1035 ** Cleanup time. |
| 1036 */ |
| 1037 for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++) |
| 1038 { |
| 1039 theModule = modules + moduleLoop; |
| 1040 |
| 1041 for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop
++) |
| 1042 { |
| 1043 theSegment = theModule->mSegments + segmentLoop; |
| 1044 |
| 1045 for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoo
p++) |
| 1046 { |
| 1047 theObject = theSegment->mObjects + objectLoop; |
| 1048 |
| 1049 for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount; symbol
Loop++) |
| 1050 { |
| 1051 theSymbol = theObject->mSymbols + symbolLoop; |
| 1052 |
| 1053 CLEANUP(theSymbol->mSymbol); |
| 1054 } |
| 1055 |
| 1056 CLEANUP(theObject->mSymbols); |
| 1057 CLEANUP(theObject->mObject); |
| 1058 } |
| 1059 |
| 1060 CLEANUP(theSegment->mObjects); |
| 1061 CLEANUP(theSegment->mSegment); |
| 1062 } |
| 1063 |
| 1064 CLEANUP(theModule->mSegments); |
| 1065 CLEANUP(theModule->mModule); |
| 1066 } |
| 1067 CLEANUP(modules); |
| 1068 |
| 1069 return retval; |
| 1070 } |
| 1071 |
| 1072 |
| 1073 int initOptions(Options* outOptions, int inArgc, char** inArgv) |
| 1074 /* |
| 1075 ** returns int 0 if successful. |
| 1076 */ |
| 1077 { |
| 1078 int retval = 0; |
| 1079 int loop = 0; |
| 1080 int switchLoop = 0; |
| 1081 int match = 0; |
| 1082 const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]); |
| 1083 Switch* current = NULL; |
| 1084 |
| 1085 /* |
| 1086 ** Set any defaults. |
| 1087 */ |
| 1088 memset(outOptions, 0, sizeof(Options)); |
| 1089 outOptions->mProgramName = inArgv[0]; |
| 1090 outOptions->mInput = stdin; |
| 1091 outOptions->mInputName = strdup("stdin"); |
| 1092 outOptions->mOutput = stdout; |
| 1093 outOptions->mOutputName = strdup("stdout"); |
| 1094 |
| 1095 if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName) |
| 1096 { |
| 1097 retval = __LINE__; |
| 1098 ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup."); |
| 1099 } |
| 1100 |
| 1101 /* |
| 1102 ** Go through and attempt to do the right thing. |
| 1103 */ |
| 1104 for(loop = 1; loop < inArgc && 0 == retval; loop++) |
| 1105 { |
| 1106 match = 0; |
| 1107 current = NULL; |
| 1108 |
| 1109 for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop+
+) |
| 1110 { |
| 1111 if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop])) |
| 1112 { |
| 1113 match = __LINE__; |
| 1114 } |
| 1115 else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop])
) |
| 1116 { |
| 1117 match = __LINE__; |
| 1118 } |
| 1119 |
| 1120 if(match) |
| 1121 { |
| 1122 if(gSwitches[switchLoop]->mHasValue) |
| 1123 { |
| 1124 /* |
| 1125 ** Attempt to absorb next option to fullfill value. |
| 1126 */ |
| 1127 if(loop + 1 < inArgc) |
| 1128 { |
| 1129 loop++; |
| 1130 |
| 1131 current = gSwitches[switchLoop]; |
| 1132 current->mValue = inArgv[loop]; |
| 1133 } |
| 1134 } |
| 1135 else |
| 1136 { |
| 1137 current = gSwitches[switchLoop]; |
| 1138 } |
| 1139 |
| 1140 break; |
| 1141 } |
| 1142 } |
| 1143 |
| 1144 if(0 == match) |
| 1145 { |
| 1146 outOptions->mHelp = __LINE__; |
| 1147 retval = __LINE__; |
| 1148 ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch."); |
| 1149 } |
| 1150 else if(NULL == current) |
| 1151 { |
| 1152 outOptions->mHelp = __LINE__; |
| 1153 retval = __LINE__; |
| 1154 ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a v
alue."); |
| 1155 } |
| 1156 else |
| 1157 { |
| 1158 /* |
| 1159 ** Do something based on address/swtich. |
| 1160 */ |
| 1161 if(current == &gInputSwitch) |
| 1162 { |
| 1163 CLEANUP(outOptions->mInputName); |
| 1164 if(NULL != outOptions->mInput && stdin != outOptions->mInput) |
| 1165 { |
| 1166 fclose(outOptions->mInput); |
| 1167 outOptions->mInput = NULL; |
| 1168 } |
| 1169 |
| 1170 outOptions->mInput = fopen(current->mValue, "r"); |
| 1171 if(NULL == outOptions->mInput) |
| 1172 { |
| 1173 retval = __LINE__; |
| 1174 ERROR_REPORT(retval, current->mValue, "Unable to open input
file."); |
| 1175 } |
| 1176 else |
| 1177 { |
| 1178 outOptions->mInputName = strdup(current->mValue); |
| 1179 if(NULL == outOptions->mInputName) |
| 1180 { |
| 1181 retval = __LINE__; |
| 1182 ERROR_REPORT(retval, current->mValue, "Unable to strdup.
"); |
| 1183 } |
| 1184 } |
| 1185 } |
| 1186 else if(current == &gOutputSwitch) |
| 1187 { |
| 1188 CLEANUP(outOptions->mOutputName); |
| 1189 if(NULL != outOptions->mOutput && stdout != outOptions->mOutput) |
| 1190 { |
| 1191 fclose(outOptions->mOutput); |
| 1192 outOptions->mOutput = NULL; |
| 1193 } |
| 1194 |
| 1195 outOptions->mOutput = fopen(current->mValue, "a"); |
| 1196 if(NULL == outOptions->mOutput) |
| 1197 { |
| 1198 retval = __LINE__; |
| 1199 ERROR_REPORT(retval, current->mValue, "Unable to open output
file."); |
| 1200 } |
| 1201 else |
| 1202 { |
| 1203 outOptions->mOutputName = strdup(current->mValue); |
| 1204 if(NULL == outOptions->mOutputName) |
| 1205 { |
| 1206 retval = __LINE__; |
| 1207 ERROR_REPORT(retval, current->mValue, "Unable to strdup.
"); |
| 1208 } |
| 1209 } |
| 1210 } |
| 1211 else if(current == &gHelpSwitch) |
| 1212 { |
| 1213 outOptions->mHelp = __LINE__; |
| 1214 } |
| 1215 else if(current == &gSummarySwitch) |
| 1216 { |
| 1217 outOptions->mSummaryOnly = __LINE__; |
| 1218 } |
| 1219 else if(current == &gZeroDriftSwitch) |
| 1220 { |
| 1221 outOptions->mZeroDrift = __LINE__; |
| 1222 } |
| 1223 else if(current == &gNegationSwitch) |
| 1224 { |
| 1225 outOptions->mNegation = __LINE__; |
| 1226 } |
| 1227 else |
| 1228 { |
| 1229 retval = __LINE__; |
| 1230 ERROR_REPORT(retval, current->mLongName, "No handler for command
line switch."); |
| 1231 } |
| 1232 } |
| 1233 } |
| 1234 |
| 1235 return retval; |
| 1236 } |
| 1237 |
| 1238 |
| 1239 void cleanOptions(Options* inOptions) |
| 1240 /* |
| 1241 ** Clean up any open handles. |
| 1242 */ |
| 1243 { |
| 1244 CLEANUP(inOptions->mInputName); |
| 1245 if(NULL != inOptions->mInput && stdin != inOptions->mInput) |
| 1246 { |
| 1247 fclose(inOptions->mInput); |
| 1248 } |
| 1249 CLEANUP(inOptions->mOutputName); |
| 1250 if(NULL != inOptions->mOutput && stdout != inOptions->mOutput) |
| 1251 { |
| 1252 fclose(inOptions->mOutput); |
| 1253 } |
| 1254 |
| 1255 memset(inOptions, 0, sizeof(Options)); |
| 1256 } |
| 1257 |
| 1258 |
| 1259 void showHelp(Options* inOptions) |
| 1260 /* |
| 1261 ** Show some simple help text on usage. |
| 1262 */ |
| 1263 { |
| 1264 int loop = 0; |
| 1265 const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]); |
| 1266 const char* valueText = NULL; |
| 1267 |
| 1268 printf("usage:\t%s [arguments]\n", inOptions->mProgramName); |
| 1269 printf("\n"); |
| 1270 printf("arguments:\n"); |
| 1271 |
| 1272 for(loop = 0; loop < switchCount; loop++) |
| 1273 { |
| 1274 if(gSwitches[loop]->mHasValue) |
| 1275 { |
| 1276 valueText = " <value>"; |
| 1277 } |
| 1278 else |
| 1279 { |
| 1280 valueText = ""; |
| 1281 } |
| 1282 |
| 1283 printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText); |
| 1284 printf("\t %s%s", gSwitches[loop]->mShortName, valueText); |
| 1285 printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription); |
| 1286 } |
| 1287 |
| 1288 printf("This tool takes the diff of two sorted tsv files to form a summary r
eport\n"); |
| 1289 printf("of code and data size changes which is hoped to be human readable.\n
"); |
| 1290 } |
| 1291 |
| 1292 |
| 1293 int main(int inArgc, char** inArgv) |
| 1294 { |
| 1295 int retval = 0; |
| 1296 Options options; |
| 1297 |
| 1298 retval = initOptions(&options, inArgc, inArgv); |
| 1299 if(options.mHelp) |
| 1300 { |
| 1301 showHelp(&options); |
| 1302 } |
| 1303 else if(0 == retval) |
| 1304 { |
| 1305 retval = difftool(&options); |
| 1306 } |
| 1307 |
| 1308 cleanOptions(&options); |
| 1309 return retval; |
| 1310 } |
| 1311 |
OLD | NEW |