Annotation of mstools/samples/sdktools/windiff/compitem.c, revision 1.1

1.1     ! root        1: 
        !             2: /******************************************************************************\
        !             3: *       This is a part of the Microsoft Source Code Samples. 
        !             4: *       Copyright (C) 1993 Microsoft Corporation.
        !             5: *       All rights reserved. 
        !             6: *       This source code is only intended as a supplement to 
        !             7: *       Microsoft Development Tools and/or WinHelp documentation.
        !             8: *       See these sources for detailed information regarding the 
        !             9: *       Microsoft samples programs.
        !            10: \******************************************************************************/
        !            11: 
        !            12: /****************************** Module Header *******************************
        !            13: * Module Name: COMPITEM.C
        !            14: *
        !            15: * Module which does the comparison between two files. 
        !            16: *
        !            17: * Functions:
        !            18: *
        !            19: * ci_copytext()
        !            20: * ci_makecomposite()
        !            21: * ci_compare()
        !            22: * ci_onesection()
        !            23: * compitem_new()
        !            24: * compitem_delete()
        !            25: * compitem_discardsections()
        !            26: * compitem_getcomposite()
        !            27: * compitem_getleftsections()
        !            28: * compitem_getrightsections()
        !            29: * compitem_getleftfile()
        !            30: * compitem_getrightfile()
        !            31: * compitem_getstate()
        !            32: * compitem_gettext_tag()
        !            33: * compitem_gettext_result()
        !            34: * compitem_getfilename()
        !            35: * compitem_frefilename()
        !            36: *
        !            37: * Comments:
        !            38: *
        !            39: * This module uses the structure compitem which is a data type that knows
        !            40: * about two files, and can compare them. The result of the comparison
        !            41: * is a list of sections for each file, and a composite list of sections
        !            42: * representing the comparison of the two files.
        !            43: *
        !            44: * A compitem has a state (one of the integer values defined in state.h)
        !            45: * representing the result of the comparison. It can also be
        !            46: * queried for the text result (text equivalent of the state) as well
        !            47: * as the tag - or title for this compitem (usually a text string containing
        !            48: * the name(s) of the files being compared).
        !            49: *
        !            50: * A compitem will supply a composite section list even if the files are
        !            51: * the same, or if there is only one file. The composite section list will
        !            52: * only be built (and the files read in) when the compitem_getcomposite()
        !            53: * call is made (and not at compitem_new time).
        !            54: * 
        !            55: *  
        !            56: ****************************************************************************/
        !            57: 
        !            58: #include <windows.h>
        !            59: #include <stdlib.h>
        !            60: #include <string.h>
        !            61: 
        !            62: #include "gutils.h"
        !            63: #include "state.h"
        !            64: #include "windiff.h"
        !            65: #include "wdiffrc.h"
        !            66: #include "list.h"
        !            67: #include "line.h"
        !            68: #include "scandir.h"
        !            69: #include "file.h"
        !            70: #include "section.h"
        !            71: #include "compitem.h"
        !            72: 
        !            73: 
        !            74: struct compitem {
        !            75: 
        !            76:         FILEDATA left;          /* handle for left-hand file */
        !            77:         FILEDATA right;         /* handle for right-hand file */
        !            78: 
        !            79:         LIST secs_composite;    /* list of sections (composite file)*/
        !            80:         LIST secs_left;         /* list of sections (left file) */
        !            81:         LIST secs_right;        /* list of sections (right file) */
        !            82: 
        !            83:         int state;              /* compitem state - result of compare */
        !            84:         BOOL bDiscard;          /* true if not alloc-ed on list */
        !            85:         LPSTR tag;              /* text for tag (title of compitem) */
        !            86:         LPSTR result;           /* text equivalent of state */
        !            87: 
        !            88: };
        !            89: 
        !            90: 
        !            91: LPSTR ci_copytext(LPSTR in);
        !            92: void ci_makecomposite(COMPITEM ci);
        !            93: void ci_compare(COMPITEM ci);
        !            94: 
        !            95: 
        !            96: /***************************************************************************
        !            97:  * Function: compitem_new
        !            98:  *
        !            99:  * Purpose:
        !           100:  *
        !           101:  * Returns a handle to a new compitem - given the filenames for the
        !           102:  * left and right files to be compared. Either left or right or neither
        !           103:  * (but not both) may be null. In this case we set the state accordingly.
        !           104:  *
        !           105:  * The parameters are handles to DIRITEM objects: these allow us to get the
        !           106:  * the name of the file relative to the compare roots (needed for the tag)
        !           107:  * and the absolute name of the file (needed for opening the file).
        !           108:  *
        !           109:  * Comments:
        !           110:  *
        !           111:  * If the list parameter is not null, the List_New* functions are used to
        !           112:  * allocate memory for the compitem. We remember this (in the bDiscard flag)
        !           113:  * so we do not delete the compitem if it was allocated on the list.
        !           114:  *
        !           115:  * If the list parameter is null, the memory
        !           116:  * for the compitem is allocated from the gmem_* heap initialised by the app.
        !           117:  *
        !           118:  ****************************************************************************/
        !           119: COMPITEM
        !           120: compitem_new(DIRITEM leftname, DIRITEM rightname, LIST list, BOOL fExact)
        !           121: {
        !           122:         COMPITEM ci;
        !           123:         LPSTR str1, str2;
        !           124:         char buf[2*MAX_PATH+20];
        !           125: 
        !           126: 
        !           127:         /*
        !           128:          * Allocate the memory for the compitem, either at the end of the
        !           129:          * list or in the gmem_* heap.
        !           130:          */
        !           131:         if (list == NULL) {
        !           132:                 /* no list passed */
        !           133:                 ci = (COMPITEM) gmem_get(hHeap, sizeof(struct compitem));
        !           134:                 memset(ci, 0, sizeof(struct compitem));
        !           135:                 ci->bDiscard = TRUE;
        !           136:         } else {
        !           137:                 /* add to end of list */
        !           138:                 ci = (COMPITEM) List_NewLast(list, sizeof(struct compitem));
        !           139:                 ci->bDiscard = FALSE;
        !           140:         }
        !           141: 
        !           142:         ci->secs_composite = NULL;
        !           143:         ci->secs_left = NULL;
        !           144:         ci->secs_right = NULL;
        !           145: 
        !           146:         /*
        !           147:          * Make a filedata for each of the files that are non-null.
        !           148:          * Filedata objects are responsible for reading the file and
        !           149:          * accessing the lines in it. Don't read in the files until we need to.
        !           150:          */
        !           151:         if (leftname != NULL) {
        !           152:                 ci->left = file_new(leftname, FALSE);
        !           153:                 if (ci->left == NULL) {
        !           154:                         return(NULL);
        !           155:                 }
        !           156:         } else {
        !           157:                 ci->left = NULL;
        !           158:         }
        !           159:         if ( rightname != NULL) {
        !           160:                 ci->right = file_new(rightname, FALSE);
        !           161:                 if (ci->right == NULL) {
        !           162:                         return(NULL);
        !           163:                 }
        !           164:         } else {
        !           165:                 ci->right = NULL;
        !           166:         }
        !           167: 
        !           168: 
        !           169:         /*
        !           170:          * See if we have one or two files, and set the state accordingly
        !           171:          */
        !           172:         if ( ! ci->left && !ci->right) {
        !           173:                 /* two NULL files - this is wrong */
        !           174:                 return(NULL);
        !           175:         }
        !           176: 
        !           177: 
        !           178:         /* Set the tag (title field) for this item. If the
        !           179:          * two files have names that match, we use just that name -
        !           180:          * otherwise we use both names separated by a colon 'left : right'.
        !           181:          *
        !           182:          * In both cases, use the names relative to compare root (the
        !           183:          * names will certainly be different if we compare the abs paths)
        !           184:          */
        !           185:         str1 = dir_getrelname(leftname);
        !           186:         str2 = dir_getrelname(rightname);
        !           187: 
        !           188:         /* If only one file - set name to that */
        !           189:         if (ci->left == NULL) {
        !           190:                 ci->tag = ci_copytext(str2);
        !           191:         } else if (ci->right == NULL) {
        !           192:                 ci->tag = ci_copytext(str1);
        !           193:         } else {
        !           194:                 if (lstrcmpi(str1, str2) == 0) {
        !           195:                         ci->tag = ci_copytext(str2);
        !           196:                 } else {
        !           197:                         wsprintf(buf, "%s : %s", str1, str2);
        !           198:                         ci->tag = ci_copytext(buf);
        !           199:                 }
        !           200:         }
        !           201: 
        !           202:         dir_freerelname(leftname, str1);
        !           203:         dir_freerelname(leftname, str2);
        !           204: 
        !           205: 
        !           206:         if (ci->left == NULL) {
        !           207:                 str1 = dir_getroot_item(rightname);
        !           208:                 wsprintf(buf, "only in %s", str1);
        !           209:                 dir_freeroot_item(rightname, str1);
        !           210: 
        !           211:                 ci->result = ci_copytext(buf);
        !           212:                 ci->state = STATE_FILERIGHTONLY;
        !           213:         } else if (ci->right == NULL) {
        !           214:                 str1 = dir_getroot_item(leftname);
        !           215:                 wsprintf(buf, "only in %s", str1);
        !           216:                 dir_freeroot_item(leftname, str1);
        !           217: 
        !           218:                 ci->result = ci_copytext(buf);
        !           219:                 ci->state = STATE_FILELEFTONLY;
        !           220:         } else {
        !           221:                 /* two files - are they the same ? compare
        !           222:                  * the file sizes
        !           223:                  */
        !           224: 
        !           225: 
        !           226:                 if (dir_getfilesize(leftname) != dir_getfilesize(rightname)) 
        !           227:                 {
        !           228:                     ci->state = STATE_DIFFER;
        !           229:                     ci->result = ci_copytext("different sizes");
        !           230:                 } else if (!fExact){
        !           231:                     ci->result = ci_copytext("same size");
        !           232:                     ci->state = STATE_SAME;
        !           233:                 } else {
        !           234:                     ci->result =  ci_copytext("identical");
        !           235:                     ci->state = STATE_SAME;
        !           236:                 }
        !           237:         }
        !           238: 
        !           239: 
        !           240: #if FALSE
        !           241:                 if (dir_getfilesize(leftname) == dir_getfilesize(rightname)) {
        !           242:                     if (  !fExact )
        !           243:                        {
        !           244:                         ci->result = ci_copytext("same size etc.");
        !           245:                         ci->state = STATE_SAME;
        !           246:                     } else {
        !           247:                         ci->result = ci_copytext("files differ");
        !           248:                         ci->state = STATE_DIFFER;
        !           249:                         ci->result = ci_copytext("files differ");
        !           250:                      }
        !           251:                 } else {
        !           252:                         ci->result = ci_copytext("files differ");
        !           253:                         ci->state = STATE_DIFFER;
        !           254:                 }
        !           255:         }
        !           256: #endif
        !           257: 
        !           258:         /*
        !           259:          * Building the section lists and composite lists can wait
        !           260:          * until needed.
        !           261:          */
        !           262:         return(ci);
        !           263: } /* compitem_new */
        !           264: 
        !           265: /***************************************************************************
        !           266:  * Function: compitem_delete
        !           267:  *
        !           268:  * Purpose:
        !           269:  *
        !           270:  * Deletes a compitem and free all associated data.
        !           271:  *
        !           272:  * Comments:
        !           273:  *
        !           274:  * If the ci->bDiscard flag is set, the compitem was alloc-ed on a list,
        !           275:  * and should not be discarded (the list itself will be deleted).
        !           276:  *
        !           277:  * The DIRDATA we were passed are not deleted. the filedata, lines
        !           278:  * and sections are.
        !           279:  ***************************************************************************/
        !           280: void
        !           281: compitem_delete(COMPITEM ci)
        !           282: {
        !           283:         if (ci == NULL) {
        !           284:                 return;
        !           285:         }
        !           286: 
        !           287:         compitem_discardsections(ci);
        !           288: 
        !           289:         /* Delete the two filedatas (and associated line lists) */
        !           290:         file_delete(ci->left);
        !           291:         file_delete(ci->right);
        !           292: 
        !           293:         /* text we allocated */
        !           294:         gmem_free(hHeap, ci->tag, lstrlen(ci->tag) + 1);
        !           295:         gmem_free(hHeap, ci->result, lstrlen(ci->result) + 1);
        !           296: 
        !           297:         /* Free the compitem struct itself if not alloced on a list */
        !           298:         if (ci->bDiscard) {
        !           299:                 gmem_free(hHeap, (LPSTR) ci, sizeof(struct compitem));
        !           300:         }
        !           301: }
        !           302: 
        !           303: 
        !           304: /*
        !           305: /***************************************************************************
        !           306:  * Function: compitem_discardsections
        !           307:  *
        !           308:  * Purpose:
        !           309:  *
        !           310:  * To discard sections - throw away cached information relating to the
        !           311:  * comparison (but not the files if they are read into memory). This
        !           312:  * is used to force a re-compare if changes in the comparison options
        !           313:  * are made
        !           314:  *
        !           315:  ***************************************************************************/
        !           316: void
        !           317: compitem_discardsections(COMPITEM ci)
        !           318: {
        !           319:         /* delete the lists of sections we built */
        !           320:         if (ci == NULL) {
        !           321:                 return;
        !           322:         }
        !           323:         if (ci->secs_composite) {
        !           324:                 section_deletelist(ci->secs_composite);
        !           325:                 ci->secs_composite = NULL;
        !           326:         }
        !           327:         if (ci->secs_left) {
        !           328:                 section_deletelist(ci->secs_left);
        !           329:                 ci->secs_left = NULL;
        !           330:         }
        !           331:         if (ci->secs_right) {
        !           332:                 section_deletelist(ci->secs_right);
        !           333:                 ci->secs_right = NULL;
        !           334:         }
        !           335: 
        !           336:         /* reset the line lists to throw away cached hash codes and links */
        !           337:         if (ci->left != NULL) {
        !           338:                 file_reset(ci->left);
        !           339:         }
        !           340:         if (ci->right != NULL) {
        !           341:                 file_reset(ci->right);
        !           342:         }
        !           343: 
        !           344: }
        !           345: 
        !           346: /***************************************************************************
        !           347:  * Function: compitem_getcomposite
        !           348:  *
        !           349:  * Purpose:
        !           350:  *
        !           351:  * To get the handle for the composite section list 
        !           352:  *
        !           353:  ***************************************************************************/
        !           354: LIST
        !           355: compitem_getcomposite(COMPITEM ci)
        !           356: {
        !           357:         if (ci == NULL) {
        !           358:                 return NULL;
        !           359:         }
        !           360:         /*
        !           361:          * do the comparison if we haven't already done it
        !           362:          */
        !           363:         if (ci->secs_composite == NULL) {
        !           364:                 ci_makecomposite(ci);
        !           365:         }
        !           366: 
        !           367:         return(ci->secs_composite);
        !           368: }
        !           369: 
        !           370: /***************************************************************************
        !           371:  * Function: compitem_getleftsections
        !           372:  *
        !           373:  * Purpose:
        !           374:  *
        !           375:  * To get the handle for the list of sections in the left file 
        !           376:  *
        !           377:  ***************************************************************************/
        !           378: LIST
        !           379: compitem_getleftsections(COMPITEM ci)
        !           380: {
        !           381:         if (ci == NULL) {
        !           382:                 return NULL;
        !           383:         }
        !           384:         /*
        !           385:          * do the comparison if we haven't already done it
        !           386:          */
        !           387:         if (ci->secs_composite == NULL) {
        !           388:                 ci_makecomposite(ci);
        !           389:         }
        !           390: 
        !           391:         return(ci->secs_left);
        !           392: }
        !           393: 
        !           394: /***************************************************************************
        !           395:  * Function: compitem_getrightsections
        !           396:  *
        !           397:  * Purpose:
        !           398:  *
        !           399:  * To get the handle for the list of sections in the right file 
        !           400:  *
        !           401:  ***************************************************************************/
        !           402: LIST
        !           403: compitem_getrightsections(COMPITEM ci)
        !           404: {
        !           405:         if (ci == NULL) {
        !           406:                 return NULL;
        !           407:         }
        !           408:         /*
        !           409:          * do the comparison if we haven't already done it
        !           410:          */
        !           411:         if (ci->secs_composite == NULL) {
        !           412:                 ci_makecomposite(ci);
        !           413:         }
        !           414: 
        !           415:         return(ci->secs_right);
        !           416: }
        !           417: 
        !           418: /***************************************************************************
        !           419:  * Function: compitem_getleftfile
        !           420:  *
        !           421:  * Purpose:
        !           422:  *
        !           423:  * To get the handle to the left file itself
        !           424:  *
        !           425:  ***************************************************************************/
        !           426: FILEDATA
        !           427: compitem_getleftfile(COMPITEM ci)
        !           428: {
        !           429:         if (ci == NULL) {
        !           430:                 return(NULL);
        !           431:         }
        !           432:         return(ci->left);
        !           433: }
        !           434: 
        !           435: /***************************************************************************
        !           436:  * Function: compitem_getrightfile
        !           437:  *
        !           438:  * Purpose:
        !           439:  *
        !           440:  * To get the handle to the right file itself 
        !           441:  *
        !           442:  ***************************************************************************/
        !           443: FILEDATA
        !           444: compitem_getrightfile(COMPITEM ci)
        !           445: {
        !           446:         if (ci == NULL) {
        !           447:                 return(NULL);
        !           448:         }
        !           449:         return(ci->right);
        !           450: }
        !           451: 
        !           452: /***************************************************************************
        !           453:  * Function: compitem_getstate
        !           454:  *
        !           455:  * Purpose:
        !           456:  *
        !           457:  * To get the state (compare result) of this compitem 
        !           458:  *
        !           459:  ***************************************************************************/
        !           460: int
        !           461: compitem_getstate(COMPITEM ci)
        !           462: {
        !           463:         if (ci == NULL) {
        !           464:                 return(0);
        !           465:         }
        !           466:         return(ci->state);
        !           467: }
        !           468: 
        !           469: /***************************************************************************
        !           470:  * Function: compitem_gettext_tag
        !           471:  *
        !           472:  * Purpose:
        !           473:  *
        !           474:  * To get the tag (text for the compitem title) 
        !           475:  *
        !           476:  ***************************************************************************/
        !           477: LPSTR
        !           478: compitem_gettext_tag(COMPITEM ci)
        !           479: {
        !           480:         if (ci == NULL) {
        !           481:                 return(NULL);
        !           482:         }
        !           483:         return(ci->tag);
        !           484: }
        !           485: 
        !           486: /***************************************************************************
        !           487:  * Function: compitem_gettext_result
        !           488:  *
        !           489:  * Purpose:
        !           490:  *
        !           491:  * To get the result text (text equiv of state) 
        !           492:  *
        !           493:  ***************************************************************************/
        !           494: LPSTR
        !           495: compitem_gettext_result(COMPITEM ci)
        !           496: {
        !           497:         if (ci == NULL) {
        !           498:                 return(NULL);
        !           499:         }
        !           500:         return(ci->result);
        !           501: }
        !           502: 
        !           503: /***************************************************************************
        !           504:  * Function: compitem_getfilename
        !           505:  *
        !           506:  * Purpose:
        !           507:  *
        !           508:  * To return the name of the file associated with this compitem. The option
        !           509:  * argument (one of CI_LEFT, CI_RIGHT, CI_COMP) indicates which file
        !           510:  * is required.
        !           511:  *
        !           512:  * Comments:
        !           513:  *
        !           514:  * CI_LEFT and CI_RIGHT just result in calls to dir_getopenname to get
        !           515:  * an open-able filename.
        !           516:  *
        !           517:  * For CI_COMP, we create a temporary file, write out all the text in the
        !           518:  * composite section list to this file, and then pass the name of the
        !           519:  * temporary file to the caller. This file will be deleted on
        !           520:  * the call to compitem_freefilename().
        !           521:  * 
        !           522:  ***************************************************************************/
        !           523: LPSTR
        !           524: compitem_getfilename(COMPITEM item, int option)
        !           525: {
        !           526:         LPSTR fname;
        !           527:         LINE line;
        !           528:         LPSTR tag, text;
        !           529:         SECTION sec;
        !           530:         OFSTRUCT os;
        !           531:         int fh;
        !           532: 
        !           533:         if (item == NULL) {
        !           534:                 return(NULL);
        !           535:         }
        !           536: 
        !           537:         switch(option) {
        !           538:         case CI_LEFT:
        !           539:                 if (item->left != NULL) {
        !           540:                         return(dir_getopenname(file_getdiritem(item->left)));
        !           541:                 } else {
        !           542:                         return(NULL);
        !           543:                 }
        !           544: 
        !           545:         case CI_RIGHT:
        !           546:                 if (item->right != NULL) {
        !           547:                         return(dir_getopenname(file_getdiritem(item->right)));
        !           548:                 } else {
        !           549:                         return(NULL);
        !           550:                 }
        !           551: 
        !           552:         case CI_COMP:
        !           553: 
        !           554:                 /* caller has asked for the filename of the composite file.
        !           555:                  * we need to create a temporary file and write the
        !           556:                  * lines in the composite section list out to it.
        !           557:                  */
        !           558:                 fname = gmem_get(hHeap, MAX_PATH);
        !           559:                 GetTempPath(MAX_PATH, fname);
        !           560:                 GetTempFileName(fname, "wdf", 0, fname);
        !           561: 
        !           562:                 fh = OpenFile(fname, &os, OF_READWRITE|OF_SHARE_DENY_NONE);
        !           563:                 if (fh < 0) {
        !           564:                         MessageBox(NULL, "Cannot open temp file", "Error", MB_OK | MB_ICONSTOP);
        !           565:                         return(NULL);
        !           566:                 }
        !           567: 
        !           568:                 /* make sure the composite list has been built */
        !           569: 
        !           570:                 if (item->secs_composite == NULL) {
        !           571:                         ci_makecomposite(item);
        !           572:                 }
        !           573: 
        !           574:                 /* write out every line in every section on the composite
        !           575:                  * list to the temp file.
        !           576:                  */
        !           577:                 List_TRAVERSE(item->secs_composite, sec) {
        !           578: 
        !           579:                         /* get the tag field based on the section state*/
        !           580:                         switch(section_getstate(sec)) {
        !           581:                         case STATE_SAME:
        !           582:                                 tag = "    ";
        !           583:                                 break;
        !           584: 
        !           585:                         case STATE_LEFTONLY:
        !           586:                                 tag = " <! ";
        !           587:                                 break;
        !           588:                         case STATE_RIGHTONLY:
        !           589:                                 tag = " !> ";
        !           590:                                 break;
        !           591: 
        !           592:                         case STATE_MOVEDLEFT:
        !           593:                                 tag = " <- ";
        !           594:                                 break;
        !           595: 
        !           596:                         case STATE_MOVEDRIGHT:
        !           597:                                 tag = " -> ";
        !           598:                                 break;
        !           599:                         }
        !           600: 
        !           601:                         /* write out each line in this section.
        !           602:                          * non-standard traverse of list as we only
        !           603:                          * want to go from section first to section last
        !           604:                          * inclusive.
        !           605:                          */
        !           606:                         for (line = section_getfirstline(sec);
        !           607:                              line != NULL;
        !           608:                              line = List_Next(line) ) {
        !           609: 
        !           610:                                 text = line_gettext(line);
        !           611: 
        !           612:                                 /* write out to file */
        !           613:                                 _lwrite(fh, tag, lstrlen(tag));
        !           614:                                 _lwrite(fh, text, lstrlen(text));
        !           615: 
        !           616:                                 if (line == section_getlastline(sec)) {
        !           617:                                         break;
        !           618:                                 }
        !           619:                         }
        !           620:                 }
        !           621: 
        !           622:                 /* now close the file and return its name */
        !           623:                 _lclose(fh);
        !           624:                 return(fname);
        !           625: 
        !           626: 
        !           627:         default:
        !           628:                 MessageBox(NULL, "Bad argument", "Error", MB_OK | MB_ICONSTOP);
        !           629:                 return(NULL);
        !           630:         }
        !           631: }
        !           632: 
        !           633: /***************************************************************************
        !           634:  * Function: compitem_freefilename
        !           635:  *
        !           636:  * Purpose:
        !           637:  *
        !           638:  * Free memory created by a call to compitem_getfilename. If a temporary
        !           639:  * file was created, this may cause it to be deleted. The option argument must
        !           640:  * be the same as passed to the original compitem_getfilename call.
        !           641:  *
        !           642:  * If we created a temporary file for CI_COMP, then delete it; otherwise,
        !           643:  * just pass the name to dir_freeopenname.
        !           644:  *
        !           645:  ***************************************************************************/
        !           646: void
        !           647: compitem_freefilename(COMPITEM item, int option, LPSTR filename)
        !           648: {
        !           649:         OFSTRUCT os;
        !           650: 
        !           651: 
        !           652:         if ((item == NULL) || (filename == NULL)) {
        !           653:                 return;
        !           654:         }
        !           655: 
        !           656:         switch(option) {
        !           657: 
        !           658:         case CI_LEFT:
        !           659:                 dir_freeopenname(file_getdiritem(item->left), filename);
        !           660:                 break;
        !           661: 
        !           662:         case CI_RIGHT:
        !           663:                 dir_freeopenname(file_getdiritem(item->right), filename);
        !           664:                 break;
        !           665: 
        !           666:         case CI_COMP:
        !           667: 
        !           668:                 /* this is a temporary file we created. Delete it. */
        !           669:                 OpenFile(filename, &os, OF_DELETE);
        !           670: 
        !           671:                 gmem_free(hHeap, filename, MAX_PATH);
        !           672:                 break;
        !           673:         }
        !           674: }
        !           675: 
        !           676: 
        !           677: /***************************************************************************
        !           678:  * Function: ci_copytext
        !           679:  *
        !           680:  * Purpose:
        !           681:  *
        !           682:  * To alloc a buffer large enough for the text string and copy the text into
        !           683:  * it and return a pointer to the string.
        !           684:  *
        !           685:  ***************************************************************************/
        !           686: LPSTR
        !           687: ci_copytext(LPSTR in)
        !           688: {
        !           689:         LPSTR out;
        !           690: 
        !           691:         if (in == NULL) {
        !           692:                 out = gmem_get(hHeap, 1);
        !           693:                 out[0] = '\0';
        !           694:         } else {
        !           695:                 out = gmem_get(hHeap, lstrlen(in) + 1);
        !           696:                 lstrcpy(out, in);
        !           697:         }
        !           698:         return(out);
        !           699: }
        !           700: 
        !           701: /***************************************************************************
        !           702:  * Function: ci_onesection
        !           703:  *
        !           704:  * Purpose:
        !           705:  *
        !           706:  * To make a list containing a single section from the whole list of lines 
        !           707:  *
        !           708:  ***************************************************************************/
        !           709: LIST
        !           710: ci_onesection(FILEDATA file)
        !           711: {
        !           712:         LIST lines;
        !           713:         LIST sections;
        !           714:         SECTION section;
        !           715: 
        !           716:         lines = file_getlinelist(file);
        !           717: 
        !           718:         /* create a null list */
        !           719:         sections = List_Create();
        !           720: 
        !           721:         /* tell the section to create itself on the end of this list. */
        !           722:         section = section_new(List_First(lines), List_Last(lines), sections);
        !           723:         section_setstate(section, STATE_SAME);
        !           724: 
        !           725: 
        !           726:         return(sections);
        !           727: }
        !           728: 
        !           729: 
        !           730: 
        !           731: /***************************************************************************
        !           732:  * Function: ci_makecomposite
        !           733:  *
        !           734:  * Purpose:
        !           735:  *
        !           736:  * Compare the two files and build the composite list. This function is
        !           737:  * called whenever we need one of the section lists and only does the 
        !           738:  * comparison if the composite list does not already exist.
        !           739:  *
        !           740:  ***************************************************************************/
        !           741: void
        !           742: ci_makecomposite(COMPITEM ci)
        !           743: {
        !           744:         if (ci->secs_composite != NULL) {
        !           745:                 return;
        !           746:         }
        !           747: 
        !           748:         /* if there is only one file, make a single item list
        !           749:          * of sections
        !           750:          */
        !           751:         if (ci->left == NULL) {
        !           752:                 ci->secs_left = NULL;
        !           753:                 ci->secs_right = ci_onesection(ci->right);
        !           754: 
        !           755:                 /* make a second list, not a pointer to the first
        !           756:                  * or we will get confused when deleting
        !           757:                  */
        !           758:                 ci->secs_composite = ci_onesection(ci->right);
        !           759:                 return;
        !           760:         } else if (ci->right == NULL) {
        !           761:                 ci->secs_right = NULL;
        !           762:                 ci->secs_left = ci_onesection(ci->left);
        !           763: 
        !           764:                 /* make a second list, not a pointer to the first
        !           765:                  * or we will get confused when deleting
        !           766:                  */
        !           767:                 ci->secs_composite = ci_onesection(ci->left);
        !           768:                 return;
        !           769:         }
        !           770: 
        !           771:         /* we have two files - we need to compare them fully */
        !           772:         ci_compare(ci);
        !           773: }
        !           774: 
        !           775: /***************************************************************************
        !           776:  * Function: ci_compare
        !           777:  *
        !           778:  * Purpose:
        !           779:  *
        !           780:  * Compare files and build a composite list.
        !           781:  *
        !           782:  * Comments:
        !           783:  *
        !           784:  * Comparison method:
        !           785:  *
        !           786:  *    0   Break each file into lines and hash each line.  Lines which 
        !           787:  *        don't match can be rapidly eliminated by comparing the hash code.
        !           788:  *
        !           789:  *        Store the hash codes in a binary search tree that
        !           790:  *        will give for each hash code the number of times that it
        !           791:  *        occurred in each file and one of the lines where it occurred
        !           792:  *        in each file.  The tree is used to rapidly find the partner
        !           793:  *        of a line which occurs exactly once in each file.
        !           794:  *
        !           795:  *    1   Make a section covering the whole file (for both)
        !           796:  *        and link unique lines between these sections (i.e. link lines
        !           797:  *        which occur exactly once in each file as they must match each other).
        !           798:  *        These are referred to as anchor points.
        !           799:  *
        !           800:  *    2   Build section lists for both files by traversing line lists and
        !           801:  *        making a section for each set of adjacent lines that are unmatched
        !           802:  *        and for each set of adjacent lines that match a set of adjacent
        !           803:  *        lines in the other file.  In making a section we start from a
        !           804:  *        known matching line and work both forwards and backwards through
        !           805:  *        the file including lines which match, whether they are unique or not.
        !           806:  *
        !           807:  *    3   Establish links between sections that match
        !           808:  *        and also between sections that don't match but do
        !           809:  *        correspond (by position in file between matching sections)
        !           810:  *
        !           811:  *    4   For each section pair that don't match but do correspond,
        !           812:  *        link up matching lines unique within that section.  (i.e. do
        !           813:  *        the whole algorithm again on just this section).
        !           814:  *
        !           815:  *    There may be some lines which occur many times over in each file.
        !           816:  *    As these occurrences are matched up, so the number left to match
        !           817:  *    reduces, and may reach one in each file.  At this point these two
        !           818:  *    can be matched.  Therefore we...
        !           819:  *
        !           820:  *    Repeat steps 0-4 until no more new links are added, but (especially
        !           821:  *    in step 0) we only bother with lines which have not yet been matched.
        !           822:  *    This means that a line which has only one unmatched instance in each
        !           823:  *    file gets a count of one and so is a new anchor point.
        !           824:  *
        !           825:  *    Finally build a composite list from the two lists of sections.
        !           826:  *
        !           827:  ***************************************************************************/
        !           828: void
        !           829: ci_compare(COMPITEM ci)
        !           830: {
        !           831:         LIST lines_left, lines_right;
        !           832:         SECTION whole_left, whole_right;
        !           833:         BOOL bChanges;
        !           834: 
        !           835:         /* get the list of lines for each file */
        !           836:         lines_left = file_getlinelist(ci->left);
        !           837:         lines_right = file_getlinelist(ci->right);
        !           838: 
        !           839:         if ((lines_left == NULL) || (lines_right == NULL)) {
        !           840:                 ci->secs_left = NULL;
        !           841:                 ci->secs_right = NULL;
        !           842:                 ci->secs_composite = NULL;
        !           843:                 return;
        !           844:         }
        !           845: 
        !           846:         do {
        !           847: 
        !           848:                 /* we have made no changes so far this time round the
        !           849:                  * loop
        !           850:                  */
        !           851:                 bChanges = FALSE;
        !           852: 
        !           853:                 /* make a section covering the whole file */
        !           854:                 whole_left = section_new(List_First(lines_left),
        !           855:                                          List_Last(lines_left), NULL);
        !           856: 
        !           857:                 whole_right = section_new(List_First(lines_right),
        !           858:                                          List_Last(lines_right), NULL);
        !           859: 
        !           860:                 /* link up matching unique lines between these sections */
        !           861:                 if (section_match(whole_left, whole_right)) {
        !           862:                         bChanges = TRUE;
        !           863:                 }
        !           864: 
        !           865:                 /* delete the two temp sections */
        !           866:                 section_delete(whole_left);
        !           867:                 section_delete(whole_right);
        !           868: 
        !           869:                 /* discard previous section lists if made */
        !           870:                 if (ci->secs_left) {
        !           871:                         section_deletelist(ci->secs_left);
        !           872:                         ci->secs_left = NULL;
        !           873:                 }
        !           874:                 if (ci->secs_right) {
        !           875:                         section_deletelist(ci->secs_right);
        !           876:                         ci->secs_right = NULL;
        !           877:                 }
        !           878:                 /* build new section lists for both files */
        !           879:                 ci->secs_left = section_makelist(lines_left, TRUE);
        !           880:                 ci->secs_right = section_makelist(lines_right, FALSE);
        !           881: 
        !           882:                 /* match up sections - make links and corresponds between
        !           883:                  * sections. Attempts to section_match corresponding
        !           884:                  * sections that are not matched. returns true if any
        !           885:                  * further links were made
        !           886:                  */
        !           887:                 if (section_matchlists(ci->secs_left, ci->secs_right)) {
        !           888:                         bChanges = TRUE;
        !           889:                 }
        !           890: 
        !           891:         /* repeat as long as we keep adding new links */
        !           892: 
        !           893:         } while (bChanges);
        !           894: 
        !           895:         /* all possible lines linked, and section lists made .
        !           896:          * combine the two section lists to get a view of the
        !           897:          * whole comparison - the composite section list. This also
        !           898:          * sets the state of each section in the composite list.
        !           899:          */
        !           900:         ci->secs_composite = section_makecomposite(ci->secs_left, ci->secs_right);
        !           901: 
        !           902: }
        !           903: 
        !           904: 
        !           905: 
        !           906: 
        !           907: 
        !           908: 
        !           909: 
        !           910: 
        !           911: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.