Annotation of mstools/samples/sdktools/windiff/compitem.c, revision 1.1.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.