Bug 810458 - Make mozRTCSessionDescriptor respect the spec. r=jesup
[gecko.git] / tools / codesighs / maptsvdifftool.c
blobebba434d0453465a757b8205d75d919318c7fc1e
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <time.h>
11 #include <ctype.h>
13 #define ERROR_REPORT(num, val, msg) fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
14 #define CLEANUP(ptr) do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
17 typedef struct __struct_Options
19 ** Options to control how we perform.
21 ** mProgramName Used in help text.
22 ** mInput File to read for input.
23 ** Default is stdin.
24 ** mInputName Name of the file.
25 ** mOutput Output file, append.
26 ** Default is stdout.
27 ** mOutputName Name of the file.
28 ** mHelp Whether or not help should be shown.
29 ** mSummaryOnly Only output a signle line.
30 ** mZeroDrift Output zero drift data.
31 ** mNegation Perform negation heuristics on the symbol drifts.
34 const char* mProgramName;
35 FILE* mInput;
36 char* mInputName;
37 FILE* mOutput;
38 char* mOutputName;
39 int mHelp;
40 int mSummaryOnly;
41 int mZeroDrift;
42 int mNegation;
44 Options;
47 typedef struct __struct_Switch
49 ** Command line options.
52 const char* mLongName;
53 const char* mShortName;
54 int mHasValue;
55 const char* mValue;
56 const char* mDescription;
58 Switch;
60 #define DESC_NEWLINE "\n\t\t"
62 static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."};
63 static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."};
64 static Switch gSummarySwitch = {"--summary", "-s", 0, NULL, "Only output a single line." DESC_NEWLINE "The cumulative size changes." DESC_NEWLINE "Overrides all other output options."};
65 static Switch gZeroDriftSwitch = {"--zerodrift", "-z", 0, NULL, "Output zero drift data." DESC_NEWLINE "Reports symbol changes even when there is no net drift."};
66 static Switch gNegationSwitch = {"--negation", "-n", 0, NULL, "Use negation heuristics." DESC_NEWLINE "When symbol sizes are inferred by offset, order changes cause noise." DESC_NEWLINE "This helps see through the noise by eliminating equal and opposite drifts."};
67 static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."};
69 static Switch* gSwitches[] = {
70 &gInputSwitch,
71 &gOutputSwitch,
72 &gSummarySwitch,
73 &gZeroDriftSwitch,
74 &gNegationSwitch,
75 &gHelpSwitch
79 typedef struct __struct_SizeComposition
81 ** Used to keep which parts positive and negative resulted in the total.
84 int mPositive;
85 int mNegative;
87 SizeComposition;
90 typedef struct __struct_SizeStats
92 ** Keep track of sizes.
93 ** Use signed integers so that negatives are valid, in which case we shrunk.
96 int mCode;
97 SizeComposition mCodeComposition;
99 int mData;
100 SizeComposition mDataComposition;
102 SizeStats;
105 typedef enum __enum_SegmentClass
107 ** What type of data a segment holds.
110 CODE,
111 DATA
113 SegmentClass;
116 typedef struct __struct_SymbolStats
118 ** Symbol level stats.
121 char* mSymbol;
122 int mSize;
124 SymbolStats;
127 typedef struct __struct_ObjectStats
129 ** Object level stats.
132 char* mObject;
133 int mSize;
134 SizeComposition mComposition;
135 SymbolStats* mSymbols;
136 unsigned mSymbolCount;
138 ObjectStats;
141 typedef struct __struct_SegmentStats
143 ** Segment level stats.
146 char* mSegment;
147 SegmentClass mClass;
148 int mSize;
149 SizeComposition mComposition;
150 ObjectStats* mObjects;
151 unsigned mObjectCount;
153 SegmentStats;
156 typedef struct __struct_ModuleStats
158 ** Module level stats.
161 char* mModule;
162 SizeStats mSize;
163 SegmentStats* mSegments;
164 unsigned mSegmentCount;
166 ModuleStats;
169 static int moduleCompare(const void* in1, const void* in2)
171 ** qsort helper.
174 int retval = 0;
176 ModuleStats* one = (ModuleStats*)in1;
177 ModuleStats* two = (ModuleStats*)in2;
179 int oneSize = (one->mSize.mCode + one->mSize.mData);
180 int twoSize = (two->mSize.mCode + two->mSize.mData);
182 if(oneSize < twoSize)
184 retval = 1;
186 else if(oneSize > twoSize)
188 retval = -1;
190 else
192 retval = strcmp(one->mModule, two->mModule);
193 if(0 > oneSize && 0 > twoSize)
195 retval *= -1;
199 return retval;
203 static int segmentCompare(const void* in1, const void* in2)
205 ** qsort helper.
208 int retval = 0;
210 SegmentStats* one = (SegmentStats*)in1;
211 SegmentStats* two = (SegmentStats*)in2;
213 if(one->mSize < two->mSize)
215 retval = 1;
217 else if(one->mSize > two->mSize)
219 retval = -1;
221 else
223 retval = strcmp(one->mSegment, two->mSegment);
224 if(0 > one->mSize && 0 > two->mSize)
226 retval *= -1;
230 return retval;
234 static int objectCompare(const void* in1, const void* in2)
236 ** qsort helper.
239 int retval = 0;
241 ObjectStats* one = (ObjectStats*)in1;
242 ObjectStats* two = (ObjectStats*)in2;
244 if(one->mSize < two->mSize)
246 retval = 1;
248 else if(one->mSize > two->mSize)
250 retval = -1;
252 else
254 retval = strcmp(one->mObject, two->mObject);
255 if(0 > one->mSize && 0 > two->mSize)
257 retval *= -1;
261 return retval;
265 static int symbolCompare(const void* in1, const void* in2)
267 ** qsort helper.
270 int retval = 0;
272 SymbolStats* one = (SymbolStats*)in1;
273 SymbolStats* two = (SymbolStats*)in2;
275 if(one->mSize < two->mSize)
277 retval = 1;
279 else if(one->mSize > two->mSize)
281 retval = -1;
283 else
285 retval = strcmp(one->mSymbol, two->mSymbol);
286 if(0 > one->mSize && 0 > two->mSize)
288 retval *= -1;
292 return retval;
296 void trimWhite(char* inString)
298 ** Remove any whitespace from the end of the string.
301 int len = strlen(inString);
303 while(len)
305 len--;
307 if(isspace(*(inString + len)))
309 *(inString + len) = '\0';
311 else
313 break;
319 int difftool(Options* inOptions)
321 ** Read a diff file and spit out relevant information.
324 int retval = 0;
325 char lineBuffer[0x500];
326 SizeStats overall;
327 ModuleStats* modules = NULL;
328 unsigned moduleCount = 0;
329 unsigned moduleLoop = 0;
330 ModuleStats* theModule = NULL;
331 unsigned segmentLoop = 0;
332 SegmentStats* theSegment = NULL;
333 unsigned objectLoop = 0;
334 ObjectStats* theObject = NULL;
335 unsigned symbolLoop = 0;
336 SymbolStats* theSymbol = NULL;
337 unsigned allSymbolCount = 0;
339 memset(&overall, 0, sizeof(overall));
342 ** Read the entire diff file.
343 ** We're only interested in lines beginning with < or >
345 while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
347 trimWhite(lineBuffer);
349 if(('<' == lineBuffer[0] || '>' == lineBuffer[0]) && ' ' == lineBuffer[1])
351 int additive = 0;
352 char* theLine = &lineBuffer[2];
353 int scanRes = 0;
354 int size;
355 #define SEGCLASS_CHARS 15
356 char segClass[SEGCLASS_CHARS + 1];
357 #define SCOPE_CHARS 15
358 char scope[SCOPE_CHARS + 1];
359 #define MODULE_CHARS 255
360 char module[MODULE_CHARS + 1];
361 #define SEGMENT_CHARS 63
362 char segment[SEGMENT_CHARS + 1];
363 #define OBJECT_CHARS 255
364 char object[OBJECT_CHARS + 1];
365 char* symbol = NULL;
368 ** Figure out if the line adds or subtracts from something.
370 if('>' == lineBuffer[0])
372 additive = __LINE__;
377 ** Scan the line for information.
380 #define STRINGIFY(s_) STRINGIFY2(s_)
381 #define STRINGIFY2(s_) #s_
383 scanRes = sscanf(theLine,
384 "%x\t%" STRINGIFY(SEGCLASS_CHARS) "s\t%"
385 STRINGIFY(SCOPE_CHARS) "s\t%" STRINGIFY(MODULE_CHARS)
386 "s\t%" STRINGIFY(SEGMENT_CHARS) "s\t%"
387 STRINGIFY(OBJECT_CHARS) "s\t",
388 (unsigned*)&size,
389 segClass,
390 scope,
391 module,
392 segment,
393 object);
395 if(6 == scanRes)
397 SegmentClass segmentClass = DATA;
399 symbol = strrchr(theLine, '\t') + 1;
401 if(0 == strcmp(segClass, "CODE"))
403 segmentClass = CODE;
405 else if(0 == strcmp(segClass, "DATA"))
407 segmentClass = DATA;
409 else
411 retval = __LINE__;
412 ERROR_REPORT(retval, segClass, "Unable to determine segment class.");
415 if(0 == retval)
417 unsigned moduleIndex = 0;
420 ** Find, in succession, the following things:
421 ** the module
422 ** the segment
423 ** the object
424 ** the symbol
425 ** Failure to find any one of these means to create it.
428 for(moduleIndex = 0; moduleIndex < moduleCount; moduleIndex++)
430 if(0 == strcmp(modules[moduleIndex].mModule, module))
432 break;
436 if(moduleIndex == moduleCount)
438 void* moved = NULL;
440 moved = realloc(modules, sizeof(ModuleStats) * (1 + moduleCount));
441 if(NULL != moved)
443 modules = (ModuleStats*)moved;
444 moduleCount++;
445 memset(modules + moduleIndex, 0, sizeof(ModuleStats));
447 modules[moduleIndex].mModule = strdup(module);
448 if(NULL == modules[moduleIndex].mModule)
450 retval = __LINE__;
451 ERROR_REPORT(retval, module, "Unable to duplicate string.");
454 else
456 retval = __LINE__;
457 ERROR_REPORT(retval, inOptions->mProgramName, "Unable to increase module array.");
461 if(0 == retval)
463 unsigned segmentIndex = 0;
464 theModule = (modules + moduleIndex);
466 for(segmentIndex = 0; segmentIndex < theModule->mSegmentCount; segmentIndex++)
468 if(0 == strcmp(segment, theModule->mSegments[segmentIndex].mSegment))
470 break;
474 if(segmentIndex == theModule->mSegmentCount)
476 void* moved = NULL;
478 moved = realloc(theModule->mSegments, sizeof(SegmentStats) * (theModule->mSegmentCount + 1));
479 if(NULL != moved)
481 theModule->mSegments = (SegmentStats*)moved;
482 theModule->mSegmentCount++;
483 memset(theModule->mSegments + segmentIndex, 0, sizeof(SegmentStats));
485 theModule->mSegments[segmentIndex].mClass = segmentClass;
486 theModule->mSegments[segmentIndex].mSegment = strdup(segment);
487 if(NULL == theModule->mSegments[segmentIndex].mSegment)
489 retval = __LINE__;
490 ERROR_REPORT(retval, segment, "Unable to duplicate string.");
493 else
495 retval = __LINE__;
496 ERROR_REPORT(retval, inOptions->mProgramName, "Unable to increase segment array.");
500 if(0 == retval)
502 unsigned objectIndex = 0;
503 theSegment = (theModule->mSegments + segmentIndex);
505 for(objectIndex = 0; objectIndex < theSegment->mObjectCount; objectIndex++)
507 if(0 == strcmp(object, theSegment->mObjects[objectIndex].mObject))
509 break;
513 if(objectIndex == theSegment->mObjectCount)
515 void* moved = NULL;
517 moved = realloc(theSegment->mObjects, sizeof(ObjectStats) * (1 + theSegment->mObjectCount));
518 if(NULL != moved)
520 theSegment->mObjects = (ObjectStats*)moved;
521 theSegment->mObjectCount++;
522 memset(theSegment->mObjects + objectIndex, 0, sizeof(ObjectStats));
524 theSegment->mObjects[objectIndex].mObject = strdup(object);
525 if(NULL == theSegment->mObjects[objectIndex].mObject)
527 retval = __LINE__;
528 ERROR_REPORT(retval, object, "Unable to duplicate string.");
531 else
533 retval = __LINE__;
534 ERROR_REPORT(retval, inOptions->mProgramName, "Unable to increase object array.");
538 if(0 == retval)
540 unsigned symbolIndex = 0;
541 theObject = (theSegment->mObjects + objectIndex);
543 for(symbolIndex = 0; symbolIndex < theObject->mSymbolCount; symbolIndex++)
545 if(0 == strcmp(symbol, theObject->mSymbols[symbolIndex].mSymbol))
547 break;
551 if(symbolIndex == theObject->mSymbolCount)
553 void* moved = NULL;
555 moved = realloc(theObject->mSymbols, sizeof(SymbolStats) * (1 + theObject->mSymbolCount));
556 if(NULL != moved)
558 theObject->mSymbols = (SymbolStats*)moved;
559 theObject->mSymbolCount++;
560 allSymbolCount++;
561 memset(theObject->mSymbols + symbolIndex, 0, sizeof(SymbolStats));
563 theObject->mSymbols[symbolIndex].mSymbol = strdup(symbol);
564 if(NULL == theObject->mSymbols[symbolIndex].mSymbol)
566 retval = __LINE__;
567 ERROR_REPORT(retval, symbol, "Unable to duplicate string.");
570 else
572 retval = __LINE__;
573 ERROR_REPORT(retval, inOptions->mProgramName, "Unable to increase symbol array.");
577 if(0 == retval)
579 theSymbol = (theObject->mSymbols + symbolIndex);
582 ** Update our various totals.
584 if(additive)
586 if(CODE == segmentClass)
588 overall.mCode += size;
589 theModule->mSize.mCode += size;
591 else if(DATA == segmentClass)
593 overall.mData += size;
594 theModule->mSize.mData += size;
597 theSegment->mSize += size;
598 theObject->mSize += size;
599 theSymbol->mSize += size;
601 else
603 if(CODE == segmentClass)
605 overall.mCode -= size;
606 theModule->mSize.mCode -= size;
608 else if(DATA == segmentClass)
610 overall.mData -= size;
611 theModule->mSize.mData -= size;
614 theSegment->mSize -= size;
615 theObject->mSize -= size;
616 theSymbol->mSize -= size;
624 else
626 retval = __LINE__;
627 ERROR_REPORT(retval, inOptions->mInputName, "Unable to scan line data.");
632 if(0 == retval && 0 != ferror(inOptions->mInput))
634 retval = __LINE__;
635 ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file.");
639 ** Next, it is time to perform revisionist history of sorts.
640 ** If the negation switch is in play, we perfrom the following
641 ** aggressive steps:
643 ** For each section, find size changes which have an equal and
644 ** opposite change, and set them both to zero.
645 ** However, you can only do this if the number of negating changes
646 ** is even, as if it is odd, then any one of the many could be
647 ** at fault for the actual change.
649 ** This orginally exists to make the win32 codesighs reports more
650 ** readable/meaningful.
652 if(0 == retval && 0 != inOptions->mNegation)
654 ObjectStats** objArray = NULL;
655 SymbolStats** symArray = NULL;
658 ** Create arrays big enough to hold all symbols.
659 ** As well as an array to keep the owning object at the same index.
660 ** We will keep the object around as we may need to modify the size.
662 objArray = (ObjectStats**)malloc(allSymbolCount * sizeof(ObjectStats*));
663 symArray = (SymbolStats**)malloc(allSymbolCount * sizeof(SymbolStats*));
664 if(NULL == objArray || NULL == symArray)
666 retval = __LINE__;
667 ERROR_REPORT(retval, inOptions->mProgramName, "Unable to allocate negation array memory.");
669 else
671 unsigned arrayCount = 0;
672 unsigned arrayLoop = 0;
675 ** Go through and perform the steps on each section/segment.
677 for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
679 theModule = modules + moduleLoop;
681 for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
683 theSegment = theModule->mSegments + segmentLoop;
686 ** Collect all symbols under this section.
687 ** The symbols are spread out between all the objects,
688 ** so keep track of both independently at the
689 ** same index.
691 arrayCount = 0;
693 for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
695 theObject = theSegment->mObjects + objectLoop;
697 for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount; symbolLoop++)
699 theSymbol = theObject->mSymbols + symbolLoop;
701 objArray[arrayCount] = theObject;
702 symArray[arrayCount] = theSymbol;
703 arrayCount++;
708 ** Now that we have a list of symbols, go through each
709 ** and see if there is a chance of negation.
711 for(arrayLoop = 0; arrayLoop < arrayCount; arrayLoop++)
714 ** If the item is NULL, it was already negated.
715 ** Don't do this for items with a zero size.
717 if(NULL != symArray[arrayLoop] && 0 != symArray[arrayLoop]->mSize)
719 unsigned identicalValues = 0;
720 unsigned oppositeValues = 0;
721 unsigned lookLoop = 0;
722 const int lookingFor = symArray[arrayLoop]->mSize;
725 ** Count the number of items with this value.
726 ** Count the number of items with the opposite equal value.
727 ** If they are equal, go through and negate all sizes.
729 for(lookLoop = arrayLoop; lookLoop < arrayCount; lookLoop++)
732 ** Skip negated items.
733 ** Skip zero length items.
735 if(NULL == symArray[lookLoop] || 0 == symArray[lookLoop]->mSize)
737 continue;
740 if(lookingFor == symArray[lookLoop]->mSize)
742 identicalValues++;
744 else if((-1 * lookingFor) == symArray[lookLoop]->mSize)
746 oppositeValues++;
750 if(0 != identicalValues && identicalValues == oppositeValues)
752 unsigned negationLoop = 0;
754 for(negationLoop = arrayLoop; 0 != identicalValues || 0 != oppositeValues; negationLoop++)
757 ** Skip negated items.
758 ** Skip zero length items.
760 if(NULL == symArray[negationLoop] || 0 == symArray[negationLoop]->mSize)
762 continue;
766 ** Negate any size matches.
767 ** Reflect the change in the object as well.
768 ** Clear the symbol.
770 if(lookingFor == symArray[negationLoop]->mSize)
772 objArray[negationLoop]->mSize -= lookingFor;
773 symArray[negationLoop]->mSize = 0;
774 symArray[negationLoop] = NULL;
776 identicalValues--;
778 else if((-1 * lookingFor) == symArray[negationLoop]->mSize)
780 objArray[negationLoop]->mSize += lookingFor;
781 symArray[negationLoop]->mSize = 0;
782 symArray[negationLoop] = NULL;
784 oppositeValues--;
794 CLEANUP(objArray);
795 CLEANUP(symArray);
800 ** If all went well, time to report.
802 if(0 == retval)
805 ** Loop through our data once more, so that the symbols can
806 ** propigate their changes upwards in a positive/negative
807 ** fashion.
808 ** This will help give the composite change more meaning.
810 for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
812 theModule = modules + moduleLoop;
815 ** Skip if there is zero drift, or no net change.
817 if(0 == inOptions->mZeroDrift && 0 == (theModule->mSize.mCode + theModule->mSize.mData))
819 continue;
822 for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
824 theSegment = theModule->mSegments + segmentLoop;
827 ** Skip if there is zero drift, or no net change.
829 if(0 == inOptions->mZeroDrift && 0 == theSegment->mSize)
831 continue;
834 for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
836 theObject = theSegment->mObjects + objectLoop;
839 ** Skip if there is zero drift, or no net change.
841 if(0 == inOptions->mZeroDrift && 0 == theObject->mSize)
843 continue;
846 for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount; symbolLoop++)
848 theSymbol = theObject->mSymbols + symbolLoop;
851 ** Propagate the composition all the way to the top.
852 ** Sizes of zero change are skipped.
854 if(0 < theSymbol->mSize)
856 theObject->mComposition.mPositive += theSymbol->mSize;
857 theSegment->mComposition.mPositive += theSymbol->mSize;
858 if(CODE == theSegment->mClass)
860 overall.mCodeComposition.mPositive += theSymbol->mSize;
861 theModule->mSize.mCodeComposition.mPositive += theSymbol->mSize;
863 else if(DATA == theSegment->mClass)
865 overall.mDataComposition.mPositive += theSymbol->mSize;
866 theModule->mSize.mDataComposition.mPositive += theSymbol->mSize;
869 else if(0 > theSymbol->mSize)
871 theObject->mComposition.mNegative += theSymbol->mSize;
872 theSegment->mComposition.mNegative += theSymbol->mSize;
873 if(CODE == theSegment->mClass)
875 overall.mCodeComposition.mNegative += theSymbol->mSize;
876 theModule->mSize.mCodeComposition.mNegative += theSymbol->mSize;
878 else if(DATA == theSegment->mClass)
880 overall.mDataComposition.mNegative += theSymbol->mSize;
881 theModule->mSize.mDataComposition.mNegative += theSymbol->mSize;
890 if(inOptions->mSummaryOnly)
892 fprintf(inOptions->mOutput, "%+d (%+d/%+d)\n", overall.mCode + overall.mData, overall.mCodeComposition.mPositive + overall.mDataComposition.mPositive, overall.mCodeComposition.mNegative + overall.mDataComposition.mNegative);
894 else
896 fprintf(inOptions->mOutput, "Overall Change in Size\n");
897 fprintf(inOptions->mOutput, "\tTotal:\t%+11d (%+d/%+d)\n", overall.mCode + overall.mData, overall.mCodeComposition.mPositive + overall.mDataComposition.mPositive, overall.mCodeComposition.mNegative + overall.mDataComposition.mNegative);
898 fprintf(inOptions->mOutput, "\tCode:\t%+11d (%+d/%+d)\n", overall.mCode, overall.mCodeComposition.mPositive, overall.mCodeComposition.mNegative);
899 fprintf(inOptions->mOutput, "\tData:\t%+11d (%+d/%+d)\n", overall.mData, overall.mDataComposition.mPositive, overall.mDataComposition.mNegative);
903 ** Check what else we should output.
905 if(0 == inOptions->mSummaryOnly && NULL != modules && moduleCount)
907 const char* segmentType = NULL;
910 ** We're going to sort everything.
912 qsort(modules, moduleCount, sizeof(ModuleStats), moduleCompare);
913 for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
915 theModule = modules + moduleLoop;
917 qsort(theModule->mSegments, theModule->mSegmentCount, sizeof(SegmentStats), segmentCompare);
919 for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
921 theSegment = theModule->mSegments + segmentLoop;
923 qsort(theSegment->mObjects, theSegment->mObjectCount, sizeof(ObjectStats), objectCompare);
925 for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
927 theObject = theSegment->mObjects + objectLoop;
929 qsort(theObject->mSymbols, theObject->mSymbolCount, sizeof(SymbolStats), symbolCompare);
935 ** Loop through for output.
937 for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
939 theModule = modules + moduleLoop;
942 ** Skip if there is zero drift, or no net change.
944 if(0 == inOptions->mZeroDrift && 0 == (theModule->mSize.mCode + theModule->mSize.mData))
946 continue;
949 fprintf(inOptions->mOutput, "\n");
950 fprintf(inOptions->mOutput, "%s\n", theModule->mModule);
951 fprintf(inOptions->mOutput, "\tTotal:\t%+11d (%+d/%+d)\n", theModule->mSize.mCode + theModule->mSize.mData, theModule->mSize.mCodeComposition.mPositive + theModule->mSize.mDataComposition.mPositive, theModule->mSize.mCodeComposition.mNegative + theModule->mSize.mDataComposition.mNegative);
952 fprintf(inOptions->mOutput, "\tCode:\t%+11d (%+d/%+d)\n", theModule->mSize.mCode, theModule->mSize.mCodeComposition.mPositive, theModule->mSize.mCodeComposition.mNegative);
953 fprintf(inOptions->mOutput, "\tData:\t%+11d (%+d/%+d)\n", theModule->mSize.mData, theModule->mSize.mDataComposition.mPositive, theModule->mSize.mDataComposition.mNegative);
955 for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
957 theSegment = theModule->mSegments + segmentLoop;
960 ** Skip if there is zero drift, or no net change.
962 if(0 == inOptions->mZeroDrift && 0 == theSegment->mSize)
964 continue;
967 if(CODE == theSegment->mClass)
969 segmentType = "CODE";
971 else if(DATA == theSegment->mClass)
973 segmentType = "DATA";
976 fprintf(inOptions->mOutput, "\t%+11d (%+d/%+d)\t%s (%s)\n", theSegment->mSize, theSegment->mComposition.mPositive, theSegment->mComposition.mNegative, theSegment->mSegment, segmentType);
978 for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
980 theObject = theSegment->mObjects + objectLoop;
983 ** Skip if there is zero drift, or no net change.
985 if(0 == inOptions->mZeroDrift && 0 == theObject->mSize)
987 continue;
990 fprintf(inOptions->mOutput, "\t\t%+11d (%+d/%+d)\t%s\n", theObject->mSize, theObject->mComposition.mPositive, theObject->mComposition.mNegative, theObject->mObject);
992 for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount; symbolLoop++)
994 theSymbol = theObject->mSymbols + symbolLoop;
997 ** Skip if there is zero drift, or no net change.
999 if(0 == inOptions->mZeroDrift && 0 == theSymbol->mSize)
1001 continue;
1004 fprintf(inOptions->mOutput, "\t\t\t%+11d\t%s\n", theSymbol->mSize, theSymbol->mSymbol);
1013 ** Cleanup time.
1015 for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
1017 theModule = modules + moduleLoop;
1019 for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
1021 theSegment = theModule->mSegments + segmentLoop;
1023 for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
1025 theObject = theSegment->mObjects + objectLoop;
1027 for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount; symbolLoop++)
1029 theSymbol = theObject->mSymbols + symbolLoop;
1031 CLEANUP(theSymbol->mSymbol);
1034 CLEANUP(theObject->mSymbols);
1035 CLEANUP(theObject->mObject);
1038 CLEANUP(theSegment->mObjects);
1039 CLEANUP(theSegment->mSegment);
1042 CLEANUP(theModule->mSegments);
1043 CLEANUP(theModule->mModule);
1045 CLEANUP(modules);
1047 return retval;
1051 int initOptions(Options* outOptions, int inArgc, char** inArgv)
1053 ** returns int 0 if successful.
1056 int retval = 0;
1057 int loop = 0;
1058 int switchLoop = 0;
1059 int match = 0;
1060 const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
1061 Switch* current = NULL;
1064 ** Set any defaults.
1066 memset(outOptions, 0, sizeof(Options));
1067 outOptions->mProgramName = inArgv[0];
1068 outOptions->mInput = stdin;
1069 outOptions->mInputName = strdup("stdin");
1070 outOptions->mOutput = stdout;
1071 outOptions->mOutputName = strdup("stdout");
1073 if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName)
1075 retval = __LINE__;
1076 ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup.");
1080 ** Go through and attempt to do the right thing.
1082 for(loop = 1; loop < inArgc && 0 == retval; loop++)
1084 match = 0;
1085 current = NULL;
1087 for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
1089 if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
1091 match = __LINE__;
1093 else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
1095 match = __LINE__;
1098 if(match)
1100 if(gSwitches[switchLoop]->mHasValue)
1103 ** Attempt to absorb next option to fullfill value.
1105 if(loop + 1 < inArgc)
1107 loop++;
1109 current = gSwitches[switchLoop];
1110 current->mValue = inArgv[loop];
1113 else
1115 current = gSwitches[switchLoop];
1118 break;
1122 if(0 == match)
1124 outOptions->mHelp = __LINE__;
1125 retval = __LINE__;
1126 ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
1128 else if(NULL == current)
1130 outOptions->mHelp = __LINE__;
1131 retval = __LINE__;
1132 ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
1134 else
1137 ** Do something based on address/swtich.
1139 if(current == &gInputSwitch)
1141 CLEANUP(outOptions->mInputName);
1142 if(NULL != outOptions->mInput && stdin != outOptions->mInput)
1144 fclose(outOptions->mInput);
1145 outOptions->mInput = NULL;
1148 outOptions->mInput = fopen(current->mValue, "r");
1149 if(NULL == outOptions->mInput)
1151 retval = __LINE__;
1152 ERROR_REPORT(retval, current->mValue, "Unable to open input file.");
1154 else
1156 outOptions->mInputName = strdup(current->mValue);
1157 if(NULL == outOptions->mInputName)
1159 retval = __LINE__;
1160 ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
1164 else if(current == &gOutputSwitch)
1166 CLEANUP(outOptions->mOutputName);
1167 if(NULL != outOptions->mOutput && stdout != outOptions->mOutput)
1169 fclose(outOptions->mOutput);
1170 outOptions->mOutput = NULL;
1173 outOptions->mOutput = fopen(current->mValue, "a");
1174 if(NULL == outOptions->mOutput)
1176 retval = __LINE__;
1177 ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
1179 else
1181 outOptions->mOutputName = strdup(current->mValue);
1182 if(NULL == outOptions->mOutputName)
1184 retval = __LINE__;
1185 ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
1189 else if(current == &gHelpSwitch)
1191 outOptions->mHelp = __LINE__;
1193 else if(current == &gSummarySwitch)
1195 outOptions->mSummaryOnly = __LINE__;
1197 else if(current == &gZeroDriftSwitch)
1199 outOptions->mZeroDrift = __LINE__;
1201 else if(current == &gNegationSwitch)
1203 outOptions->mNegation = __LINE__;
1205 else
1207 retval = __LINE__;
1208 ERROR_REPORT(retval, current->mLongName, "No handler for command line switch.");
1213 return retval;
1217 void cleanOptions(Options* inOptions)
1219 ** Clean up any open handles.
1222 CLEANUP(inOptions->mInputName);
1223 if(NULL != inOptions->mInput && stdin != inOptions->mInput)
1225 fclose(inOptions->mInput);
1227 CLEANUP(inOptions->mOutputName);
1228 if(NULL != inOptions->mOutput && stdout != inOptions->mOutput)
1230 fclose(inOptions->mOutput);
1233 memset(inOptions, 0, sizeof(Options));
1237 void showHelp(Options* inOptions)
1239 ** Show some simple help text on usage.
1242 int loop = 0;
1243 const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
1244 const char* valueText = NULL;
1246 printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
1247 printf("\n");
1248 printf("arguments:\n");
1250 for(loop = 0; loop < switchCount; loop++)
1252 if(gSwitches[loop]->mHasValue)
1254 valueText = " <value>";
1256 else
1258 valueText = "";
1261 printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText);
1262 printf("\t %s%s", gSwitches[loop]->mShortName, valueText);
1263 printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription);
1266 printf("This tool takes the diff of two sorted tsv files to form a summary report\n");
1267 printf("of code and data size changes which is hoped to be human readable.\n");
1271 int main(int inArgc, char** inArgv)
1273 int retval = 0;
1274 Options options;
1276 retval = initOptions(&options, inArgc, inArgv);
1277 if(options.mHelp)
1279 showHelp(&options);
1281 else if(0 == retval)
1283 retval = difftool(&options);
1286 cleanOptions(&options);
1287 return retval;