diff options
| author | 2024-04-25 21:24:10 +0100 | |
|---|---|---|
| committer | 2024-04-25 22:32:27 +0000 | |
| commit | 2d04cacc5322951f187bb17e017c12920ac8ebe2 (patch) | |
| tree | 80ee017efa878dfd5344b44249e6a241f2a7f6e2 /v4.0/src/CMD/FC/FC.C | |
| parent | Merge pull request #430 from jpbaltazar/typoptbr (diff) | |
| download | ms-dos-main.tar.gz ms-dos-main.tar.xz ms-dos-main.zip | |
Diffstat (limited to 'v4.0/src/CMD/FC/FC.C')
| -rw-r--r-- | v4.0/src/CMD/FC/FC.C | 864 |
1 files changed, 864 insertions, 0 deletions
diff --git a/v4.0/src/CMD/FC/FC.C b/v4.0/src/CMD/FC/FC.C new file mode 100644 index 0000000..d1dc0f6 --- /dev/null +++ b/v4.0/src/CMD/FC/FC.C | |||
| @@ -0,0 +1,864 @@ | |||
| 1 | /* file compare | ||
| 2 | |||
| 3 | Fcom compares two files in either a line-by-line mode or in a strict | ||
| 4 | byte-by-byte mode. | ||
| 5 | |||
| 6 | The byte-by-byte mode is simple; merely read both files and print the | ||
| 7 | offsets where they differ and the contents. | ||
| 8 | |||
| 9 | The line compare mode attempts to isolate differences in ranges of lines. | ||
| 10 | Two buffers of lines are read and compared. No hashing of lines needs | ||
| 11 | to be done; hashing only speedily tells you when things are different, | ||
| 12 | not the same. Most files run through this are expected to be largely | ||
| 13 | the same. Thus, hashing buys nothing. | ||
| 14 | |||
| 15 | |||
| 16 | *********************************************************************** | ||
| 17 | The algorithm that immediately follows does not work. There is an error | ||
| 18 | somewhere in the range of lines 11 on. An alternative explanation follows. | ||
| 19 | KGS | ||
| 20 | ************************************************************************ | ||
| 21 | |||
| 22 | [0] Fill buffers | ||
| 23 | [1] If both buffers are empty then | ||
| 24 | [1.1] Done | ||
| 25 | [2] Adjust buffers so 1st differing lines are at top. | ||
| 26 | [3] If buffers are empty then | ||
| 27 | [3.1] Goto [0] | ||
| 28 | |||
| 29 | This is the difficult part. We assume that there is a sequence of inserts, | ||
| 30 | deletes and replacements that will bring the buffers back into alignment. | ||
| 31 | |||
| 32 | [4] xd = yd = FALSE | ||
| 33 | [5] xc = yc = 1 | ||
| 34 | [6] xp = yp = 1 | ||
| 35 | [7] If buffer1[xc] and buffer2[yp] begin a "sync" range then | ||
| 36 | [7.1] Output lines 1 through xc-1 in buffer 1 | ||
| 37 | [7.2] Output lines 1 through yp-1 in buffer 2 | ||
| 38 | [7.3] Adjust buffer 1 so line xc is at beginning | ||
| 39 | [7.4] Adjust buffer 2 so line yp is at beginning | ||
| 40 | [7.5] Goto [0] | ||
| 41 | [8] If buffer1[xp] and buffer2[yc] begin a "sync" range then | ||
| 42 | [8.1] Output lines 1 through xp-1 in buffer 1 | ||
| 43 | [8.2] Output lines 1 through yc-1 in buffer 2 | ||
| 44 | [8.3] Adjust buffer 1 so line xp is at beginning | ||
| 45 | [8.4] Adjust buffer 2 so line yc is at beginning | ||
| 46 | [8.5] Goto [0] | ||
| 47 | [9] xp = xp + 1 | ||
| 48 | [10] if xp > xc then | ||
| 49 | [10.1] xp = 1 | ||
| 50 | [10.2] xc = xc + 1 | ||
| 51 | [10.3] if xc > number of lines in buffer 1 then | ||
| 52 | [10.4] xc = number of lines | ||
| 53 | [10.5] xd = TRUE | ||
| 54 | [11] if yp > yc then | ||
| 55 | [11.1] yp = 1 | ||
| 56 | [11.2] yc = yc + 1 | ||
| 57 | [11.3] if yc > number of lines in buffer 2 then | ||
| 58 | [11.4] yc = number of lines | ||
| 59 | [11.5] yd = TRUE | ||
| 60 | [12] if not xd or not yd then | ||
| 61 | [12.1] goto [6] | ||
| 62 | |||
| 63 | At this point there is no possible match between the buffers. For | ||
| 64 | simplicity, we punt. | ||
| 65 | |||
| 66 | [13] Display error message. | ||
| 67 | |||
| 68 | EXPLANATION 2 | ||
| 69 | |||
| 70 | This is a variation of the Largest Common Subsequence problem. A | ||
| 71 | detailed explanation of this can be found on p 189 of Data Structures | ||
| 72 | and Algorithms by Aho Hopcroft and Ulman. | ||
| 73 | |||
| 74 | |||
| 75 | |||
| 76 | FC maintains two buffers within which it tries to find the Largest Common | ||
| 77 | Subsequence (The largest common subsequence is simply the pattern in | ||
| 78 | buffer1 that yields the most matches with the pattern in buffer2, or the | ||
| 79 | pattern in buffer2 that yields the most matches with the pattern in buffer1) | ||
| 80 | |||
| 81 | FC makes a simplifying assumption that the contents of one buffer can be | ||
| 82 | converted to the contents of the other buffer by deleting the lines that are | ||
| 83 | different between the two buffers. | ||
| 84 | |||
| 85 | Two indices into each buffer are maintained: | ||
| 86 | |||
| 87 | xc, yc == point to the last line that has been scanned up to now | ||
| 88 | |||
| 89 | xp, yp == point to the first line that has not been exhaustively | ||
| 90 | compared to lines 0 - #c in the other buffer. | ||
| 91 | |||
| 92 | FC now makes a second simplifying assumption: | ||
| 93 | It is unnecessary to do any calculations on lines that are equal. | ||
| 94 | |||
| 95 | Hence FC scans File1 and File two line by line until a difference is | ||
| 96 | encountered. | ||
| 97 | |||
| 98 | |||
| 99 | When a difference is encountered the two buffers are filled such that | ||
| 100 | the line containing the first difference heads the buffer. The following | ||
| 101 | exhaustive search algorithm is applied to find the first "sync" occurance. | ||
| 102 | (The below is simplified to use == for comparison. In practice more than | ||
| 103 | one line needs to match for a "sync" to be established). | ||
| 104 | |||
| 105 | |||
| 106 | FOR xc,yc = 1; xc,yx <= sizeof( BUFFERS ); xc++, yc++ | ||
| 107 | |||
| 108 | FOR xp,yp = 1; xp,yp <= xc,yc; xp++, yp++ | ||
| 109 | |||
| 110 | IF ( BUFFER1[xp] == BUFFER2[yc] ) | ||
| 111 | |||
| 112 | Then the range of lines BUFFER1[ 1 ... xp ] and | ||
| 113 | BUFFER2[ 1 ... yc ] need to be deleted for the | ||
| 114 | two files to be equal. Therefore DISPLAY these | ||
| 115 | ranges, and begin scanning both files starting at | ||
| 116 | the matching lines. | ||
| 117 | FI | ||
| 118 | |||
| 119 | IF ( BUFFER1[yp] == BUFFER2[xc] ) | ||
| 120 | |||
| 121 | Then the range of lines BUFFER2[ 1 ... yp ] and | ||
| 122 | BUFFER1[ 1 ... xc ] need to be deleted for the | ||
| 123 | two files to be equal. Therefore DISPLAY these | ||
| 124 | ranges, and begin scanning both files starting at | ||
| 125 | the matching lines. | ||
| 126 | FI | ||
| 127 | FOREND | ||
| 128 | FOREND | ||
| 129 | |||
| 130 | If a match is not found within the buffers, the message "RESYNC FAILED" | ||
| 131 | is issued and further comparison is aborted since there is no valid way | ||
| 132 | to find further matching lines. | ||
| 133 | |||
| 134 | |||
| 135 | |||
| 136 | |||
| 137 | END EXPLANATION 2 | ||
| 138 | |||
| 139 | |||
| 140 | |||
| 141 | |||
| 142 | |||
| 143 | Certain flags may be set to modify the behavior of the comparison: | ||
| 144 | |||
| 145 | -a abbreviated output. Rather than displaying all of the modified | ||
| 146 | ranges, just display the beginning, ... and the ending difference | ||
| 147 | -b compare the files in binary (or byte-by-byte) mode. This mode is | ||
| 148 | default on .EXE, .OBJ, .LIB, .COM, .BIN, and .SYS files | ||
| 149 | -c ignore case on compare (cmp = strcmpi instead of strcmp) | ||
| 150 | -l compare files in line-by-line mode | ||
| 151 | -lb n set the size of the internal line buffer to n lines from default | ||
| 152 | of 100 | ||
| 153 | -w ignore blank lines and white space (ignore len 0, use strcmps) | ||
| 154 | -t do not untabify (use fgets instead of fgetl) | ||
| 155 | -n output the line number also | ||
| 156 | -NNNN set the number of lines to resynchronize to n which defaults | ||
| 157 | to 2. Failure to have this value set correctly can result in | ||
| 158 | odd output: | ||
| 159 | file1: file2: | ||
| 160 | abcdefg abcdefg | ||
| 161 | aaaaaaa aaaaaab | ||
| 162 | aaaaaaa aaaaaaa | ||
| 163 | aaaaaaa aaaaaaa | ||
| 164 | abcdefg abcdefg | ||
| 165 | |||
| 166 | with default sync of 2 yields: with sync => 3 yields: | ||
| 167 | |||
| 168 | *****f1 *****f1 | ||
| 169 | abcdefg abcdefg | ||
| 170 | aaaaaaa aaaaaaa | ||
| 171 | *****f2 aaaaaaa | ||
| 172 | abcdefg *****f2 | ||
| 173 | aaaaaab abcdefg | ||
| 174 | aaaaaaa aaaaaab | ||
| 175 | aaaaaaa | ||
| 176 | *****f1 | ||
| 177 | aaaaaaa | ||
| 178 | aaaaaaa | ||
| 179 | abcdefg | ||
| 180 | *****f2 | ||
| 181 | aaaaaaa | ||
| 182 | abcdefg | ||
| 183 | |||
| 184 | |||
| 185 | |||
| 186 | |||
| 187 | |||
| 188 | |||
| 189 | WARNING: | ||
| 190 | This program makes use of GOTO's and hence is not as straightforward | ||
| 191 | as it could be! CAVEAT PROGRAMMER. | ||
| 192 | |||
| 193 | |||
| 194 | |||
| 195 | |||
| 196 | |||
| 197 | |||
| 198 | |||
| 199 | |||
| 200 | |||
| 201 | |||
| 202 | |||
| 203 | |||
| 204 | |||
| 205 | |||
| 206 | |||
| 207 | */ | ||
| 208 | |||
| 209 | |||
| 210 | #include "tools.h" | ||
| 211 | #include "fc.h" | ||
| 212 | |||
| 213 | /* #define DEBUG FALSE */ | ||
| 214 | |||
| 215 | extern int fgetl(), | ||
| 216 | strcmp (); | ||
| 217 | |||
| 218 | extern byte toupper (); | ||
| 219 | |||
| 220 | int (*funcRead) (), /* function to use to read lines */ | ||
| 221 | (*fCmp) (); /* function to use to compare lines */ | ||
| 222 | |||
| 223 | extern byte BadSw[], | ||
| 224 | Bad_ver[], | ||
| 225 | BadOpn[], | ||
| 226 | LngFil[], | ||
| 227 | NoDif[], | ||
| 228 | NoMem[], | ||
| 229 | UseMes[], | ||
| 230 | ReSyncMes[]; | ||
| 231 | |||
| 232 | int ctSync = -1, /* number of lines required to sync */ | ||
| 233 | cLine = -1; /* number of lines in internal buffs */ | ||
| 234 | |||
| 235 | flagType fAbbrev = FALSE, /* abbreviated output */ | ||
| 236 | fBinary = FALSE, /* binary comparison */ | ||
| 237 | fLine = FALSE, /* line comparison */ | ||
| 238 | fNumb = FALSE, /* display line numbers */ | ||
| 239 | fCase = TRUE, /* case is significant */ | ||
| 240 | fIgnore = FALSE; /* ignore spaces and blank lines */ | ||
| 241 | |||
| 242 | #ifdef DEBUG | ||
| 243 | |||
| 244 | flagType fDebug = FALSE; | ||
| 245 | #endif | ||
| 246 | |||
| 247 | struct lineType *buffer1, | ||
| 248 | *buffer2; | ||
| 249 | |||
| 250 | byte line[MAXARG]; /* single line buffer */ | ||
| 251 | |||
| 252 | byte *extBin[] = { ".EXE", ".OBJ", ".LIB", | ||
| 253 | ".COM", ".BIN", ".SYS", NULL }; | ||
| 254 | |||
| 255 | |||
| 256 | main (c, v) | ||
| 257 | int c; | ||
| 258 | byte *v[]; | ||
| 259 | { | ||
| 260 | |||
| 261 | int i; | ||
| 262 | int j; | ||
| 263 | int fileargs; | ||
| 264 | char *strpbrk(), | ||
| 265 | *slash; | ||
| 266 | char n[2][80]; | ||
| 267 | char temp; | ||
| 268 | |||
| 269 | |||
| 270 | |||
| 271 | extern byte _osmajor, _osminor; | ||
| 272 | word version; /* _osmajor._osminor, used for */ | ||
| 273 | /* version binding checks. */ | ||
| 274 | |||
| 275 | |||
| 276 | |||
| 277 | /* Issue error message if DOS version is not within valid range. */ | ||
| 278 | version = ((word)_osmajor << 8) + (word)_osminor; | ||
| 279 | if (( LOWVERSION > version) || (version > HIGHVERSION)) | ||
| 280 | { | ||
| 281 | usage (Bad_ver, 1); | ||
| 282 | } | ||
| 283 | |||
| 284 | funcRead = (int (*) ())FNADDR(fgetl); | ||
| 285 | |||
| 286 | fileargs=0; | ||
| 287 | |||
| 288 | for (i=1; i < c ; i++) | ||
| 289 | { | ||
| 290 | /** | ||
| 291 | * If argument doesn't begin with a /, parse a filename off of it | ||
| 292 | * then examine the argument for following switches. | ||
| 293 | * | ||
| 294 | **/ | ||
| 295 | if (*v[i] != '/') | ||
| 296 | { | ||
| 297 | slash= strpbrk( v[i],"/" ); | ||
| 298 | |||
| 299 | if ( slash ) | ||
| 300 | { | ||
| 301 | temp = *slash; | ||
| 302 | *slash='\0' ; | ||
| 303 | strcpy(n[fileargs++],v[i]); | ||
| 304 | *slash =temp ; | ||
| 305 | } | ||
| 306 | else | ||
| 307 | strcpy(n[fileargs++],v[i]); | ||
| 308 | } | ||
| 309 | |||
| 310 | for ( j=0 ; j < strlen( v[i] ) ; j++) | ||
| 311 | { | ||
| 312 | if(*(v[i]+j)=='/') | ||
| 313 | { | ||
| 314 | switch(toupper( *(v[i]+j+1))) | ||
| 315 | { | ||
| 316 | case 'A' : | ||
| 317 | fAbbrev = TRUE; | ||
| 318 | break; | ||
| 319 | case 'B' : | ||
| 320 | fBinary = TRUE; | ||
| 321 | break; | ||
| 322 | case 'C' : | ||
| 323 | fCase = FALSE; | ||
| 324 | break; | ||
| 325 | #ifdef DEBUG | ||
| 326 | case 'D' : | ||
| 327 | fDebug = TRUE; | ||
| 328 | break; | ||
| 329 | #endif | ||
| 330 | case 'W' : | ||
| 331 | fIgnore = TRUE; | ||
| 332 | break; | ||
| 333 | case 'L' : | ||
| 334 | if (toupper(*(v[i]+j+2))=='B') | ||
| 335 | { | ||
| 336 | cLine = ntoi ((v[i]+j+3),10); | ||
| 337 | break; | ||
| 338 | } | ||
| 339 | else | ||
| 340 | fLine = TRUE; | ||
| 341 | break; | ||
| 342 | case 'N' : | ||
| 343 | fNumb = TRUE; | ||
| 344 | break; | ||
| 345 | case 'T' : | ||
| 346 | funcRead =(int (*) ())FNADDR(fgets); | ||
| 347 | break; | ||
| 348 | default: | ||
| 349 | if (*strbskip((v[i]+j+1),"0123456789") == 0) | ||
| 350 | { | ||
| 351 | ctSync = ntoi ((v[i]+j+1), 10); | ||
| 352 | } | ||
| 353 | else | ||
| 354 | { | ||
| 355 | usage (NULL, 1); | ||
| 356 | } | ||
| 357 | } /* end switch */ | ||
| 358 | } /* end if */ | ||
| 359 | } /* end parse of argument for '/' */ | ||
| 360 | } /* End ARGUMENT Search */ | ||
| 361 | |||
| 362 | |||
| 363 | |||
| 364 | if (fileargs != 2) | ||
| 365 | usage (NULL, 1); | ||
| 366 | |||
| 367 | if (ctSync != -1) | ||
| 368 | fLine = TRUE; | ||
| 369 | else | ||
| 370 | ctSync = 2; | ||
| 371 | |||
| 372 | if (cLine == -1) | ||
| 373 | cLine = 100; | ||
| 374 | |||
| 375 | if (!fBinary && !fLine) | ||
| 376 | { | ||
| 377 | extention (n[0], line); | ||
| 378 | |||
| 379 | for (i = 0; extBin[i]; i++) | ||
| 380 | if (!strcmpi (extBin[i], line)) | ||
| 381 | fBinary = TRUE; | ||
| 382 | |||
| 383 | if (!fBinary) | ||
| 384 | fLine = TRUE; | ||
| 385 | } | ||
| 386 | |||
| 387 | if (fBinary && (fLine || fNumb)) | ||
| 388 | usage (BadSw, 1); | ||
| 389 | |||
| 390 | if (fIgnore) | ||
| 391 | { | ||
| 392 | if (fCase) | ||
| 393 | fCmp = FNADDR(strcmps); | ||
| 394 | else | ||
| 395 | fCmp = FNADDR(strcmpis); | ||
| 396 | } | ||
| 397 | else | ||
| 398 | { | ||
| 399 | if (fCase) | ||
| 400 | fCmp = FNADDR(strcmp); | ||
| 401 | else | ||
| 402 | fCmp = FNADDR(strcmpi); | ||
| 403 | } | ||
| 404 | |||
| 405 | if (fBinary) | ||
| 406 | BinaryCompare (n[0], n[1]); | ||
| 407 | else | ||
| 408 | LineCompare (n[0], n[1]); | ||
| 409 | |||
| 410 | } | ||
| 411 | |||
| 412 | usage (p, erc) | ||
| 413 | unsigned char *p; | ||
| 414 | { | ||
| 415 | if (p) | ||
| 416 | printf ("fc: %s\n", p); | ||
| 417 | else | ||
| 418 | printf (UseMes); | ||
| 419 | |||
| 420 | exit (erc); | ||
| 421 | } | ||
| 422 | |||
| 423 | BinaryCompare (f1, f2) | ||
| 424 | unsigned char *f1, *f2; | ||
| 425 | { | ||
| 426 | register int c1, c2; | ||
| 427 | long pos; | ||
| 428 | FILE *fh1, *fh2; | ||
| 429 | flagType fSame; | ||
| 430 | |||
| 431 | fSame = TRUE; | ||
| 432 | |||
| 433 | if ((fh1 = fopen (f1, "rb")) == NULL) | ||
| 434 | { | ||
| 435 | sprintf (line, BadOpn, f1, error ()); | ||
| 436 | usage (line, 1); | ||
| 437 | } | ||
| 438 | |||
| 439 | if ((fh2 = fopen (f2, "rb")) == NULL) | ||
| 440 | { | ||
| 441 | sprintf (line, BadOpn, f2, error ()); | ||
| 442 | usage (line, 1); | ||
| 443 | } | ||
| 444 | pos = 0L; | ||
| 445 | |||
| 446 | while (TRUE) | ||
| 447 | { | ||
| 448 | if ((c1 = getc (fh1)) != EOF) | ||
| 449 | { | ||
| 450 | if ((c2 = getc (fh2)) != EOF) | ||
| 451 | { | ||
| 452 | if (c1 == c2) | ||
| 453 | ; | ||
| 454 | else | ||
| 455 | { | ||
| 456 | fSame = FALSE; | ||
| 457 | printf ("%08lX: %02X %02X\n", pos, c1, c2); | ||
| 458 | } | ||
| 459 | } | ||
| 460 | else | ||
| 461 | { | ||
| 462 | sprintf (line, LngFil, f1, f2); | ||
| 463 | usage (line, 1); | ||
| 464 | } | ||
| 465 | } | ||
| 466 | else | ||
| 467 | { | ||
| 468 | if ((c2 = getc (fh2)) == EOF) | ||
| 469 | { | ||
| 470 | if (fSame) | ||
| 471 | usage (NoDif, 0); | ||
| 472 | else | ||
| 473 | exit (1); | ||
| 474 | } | ||
| 475 | else | ||
| 476 | { | ||
| 477 | sprintf (line, LngFil, f2, f1); | ||
| 478 | usage (line, 1); | ||
| 479 | } | ||
| 480 | } | ||
| 481 | pos++; | ||
| 482 | } | ||
| 483 | } | ||
| 484 | |||
| 485 | /* compare a range of lines */ | ||
| 486 | flagType compare (l1, s1, l2, s2, ct) | ||
| 487 | int l1, l2, ct; | ||
| 488 | register int s1, s2; | ||
| 489 | { | ||
| 490 | |||
| 491 | #ifdef DEBUG | ||
| 492 | if (fDebug) | ||
| 493 | printf ("compare (%d, %d, %d, %d, %d)\n", l1, s1, l2, s2, ct); | ||
| 494 | #endif | ||
| 495 | |||
| 496 | if (ct == 0 || s1+ct > l1 || s2+ct > l2) | ||
| 497 | return FALSE; | ||
| 498 | |||
| 499 | while (ct--) | ||
| 500 | { | ||
| 501 | |||
| 502 | #ifdef DEBUG | ||
| 503 | if (fDebug) | ||
| 504 | printf ("'%s' == '%s'? ", buffer1[s1].text, buffer2[s2].text); | ||
| 505 | #endif | ||
| 506 | |||
| 507 | if ((*fCmp)(buffer1[s1++].text, buffer2[s2++].text)) | ||
| 508 | { | ||
| 509 | |||
| 510 | #ifdef DEBUG | ||
| 511 | if (fDebug) | ||
| 512 | printf ("No\n"); | ||
| 513 | #endif | ||
| 514 | return FALSE; | ||
| 515 | } | ||
| 516 | } | ||
| 517 | |||
| 518 | #ifdef DEBUG | ||
| 519 | if (fDebug) | ||
| 520 | printf ("Yes\n"); | ||
| 521 | #endif | ||
| 522 | |||
| 523 | return TRUE; | ||
| 524 | } | ||
| 525 | |||
| 526 | LineCompare (f1, f2) | ||
| 527 | unsigned char *f1, *f2; | ||
| 528 | { | ||
| 529 | FILE *fh1, *fh2; | ||
| 530 | int l1, l2, i, xp, yp, xc, yc; | ||
| 531 | flagType xd, yd, fSame; | ||
| 532 | int line1, line2; | ||
| 533 | |||
| 534 | fSame = TRUE; | ||
| 535 | |||
| 536 | if ((fh1 = fopen (f1, "rb")) == NULL) | ||
| 537 | { | ||
| 538 | sprintf (line, BadOpn, f1, error ()); | ||
| 539 | usage (line, 1); | ||
| 540 | } | ||
| 541 | |||
| 542 | if ((fh2 = fopen (f2, "rb")) == NULL) | ||
| 543 | { | ||
| 544 | sprintf (line, BadOpn, f2, error ()); | ||
| 545 | usage (line, 1); | ||
| 546 | } | ||
| 547 | |||
| 548 | if ((buffer1 = (struct lineType *)malloc (cLine * (sizeof *buffer1))) == NULL || | ||
| 549 | (buffer2 = (struct lineType *)malloc (cLine * (sizeof *buffer1))) == NULL) | ||
| 550 | usage (NoMem); | ||
| 551 | |||
| 552 | l1 = l2 = 0; | ||
| 553 | line1 = line2 = 0; | ||
| 554 | l0: | ||
| 555 | |||
| 556 | #ifdef DEBUG | ||
| 557 | if (fDebug) | ||
| 558 | printf ("At scan beginning\n"); | ||
| 559 | #endif | ||
| 560 | |||
| 561 | l1 += xfill (buffer1+l1, fh1, cLine-l1, &line1); | ||
| 562 | l2 += xfill (buffer2+l2, fh2, cLine-l2, &line2); | ||
| 563 | |||
| 564 | if (l1 == 0 && l2 == 0) | ||
| 565 | { | ||
| 566 | if (fSame) | ||
| 567 | usage (NoDif, 0); | ||
| 568 | return; | ||
| 569 | } | ||
| 570 | xc = min (l1, l2); | ||
| 571 | |||
| 572 | for (i=0; i < xc; i++) | ||
| 573 | { | ||
| 574 | if (!compare (l1, i, l2, i, 1)) | ||
| 575 | break; | ||
| 576 | } | ||
| 577 | |||
| 578 | if (i != xc) | ||
| 579 | i = max (i-1, 0); | ||
| 580 | |||
| 581 | l1 = adjust (buffer1, l1, i); | ||
| 582 | l2 = adjust (buffer2, l2, i); | ||
| 583 | |||
| 584 | /* KLUDGE ALERT!! GOTO USED */ | ||
| 585 | if (l1 == 0 && l2 == 0) | ||
| 586 | goto l0; | ||
| 587 | |||
| 588 | l1 += xfill (buffer1+l1, fh1, cLine-l1, &line1); | ||
| 589 | l2 += xfill (buffer2+l2, fh2, cLine-l2, &line2); | ||
| 590 | |||
| 591 | #ifdef DEBUG | ||
| 592 | if (fDebug) | ||
| 593 | printf ("buffers are adjusted, %d, %d remain\n", l1, l2); | ||
| 594 | #endif | ||
| 595 | |||
| 596 | xd = yd = FALSE; | ||
| 597 | xc = yc = 1; | ||
| 598 | xp = yp = 1; | ||
| 599 | |||
| 600 | l6: | ||
| 601 | |||
| 602 | #ifdef DEBUG | ||
| 603 | if (fDebug) | ||
| 604 | printf ("Trying resync %d,%d %d,%d\n", xc, xp, yc, yp); | ||
| 605 | #endif | ||
| 606 | |||
| 607 | i = min (l1-xc,l2-yp); | ||
| 608 | i = min (i, ctSync); | ||
| 609 | |||
| 610 | if (compare (l1, xc, l2, yp, i)) | ||
| 611 | { | ||
| 612 | fSame = FALSE; | ||
| 613 | printf ("***** %s\n", f1); | ||
| 614 | dump (buffer1, 0, xc); | ||
| 615 | printf ("***** %s\n", f2); | ||
| 616 | dump (buffer2, 0, yp); | ||
| 617 | printf ("*****\n\n"); | ||
| 618 | |||
| 619 | l1 = adjust (buffer1, l1, xc); | ||
| 620 | l2 = adjust (buffer2, l2, yp); | ||
| 621 | |||
| 622 | /* KLUDGE ALERT!! GOTO USED */ | ||
| 623 | goto l0; | ||
| 624 | } | ||
| 625 | i = min (l1-xp, l2-yc); | ||
| 626 | i = min (i, ctSync); | ||
| 627 | |||
| 628 | if (compare (l1, xp, l2, yc, i)) | ||
| 629 | { | ||
| 630 | fSame = FALSE; | ||
| 631 | printf ("***** %s\n", f1); | ||
| 632 | dump (buffer1, 0, xp); | ||
| 633 | printf ("***** %s\n", f2); | ||
| 634 | dump (buffer2, 0, yc); | ||
| 635 | printf ("*****\n\n"); | ||
| 636 | |||
| 637 | l1 = adjust (buffer1, l1, xp); | ||
| 638 | l2 = adjust (buffer2, l2, yc); | ||
| 639 | |||
| 640 | /* KLUDGE ALERT!! GOTO USED */ | ||
| 641 | goto l0; | ||
| 642 | } | ||
| 643 | |||
| 644 | if (++xp > xc) | ||
| 645 | { | ||
| 646 | xp = 1; | ||
| 647 | if (++xc >= l1) | ||
| 648 | { | ||
| 649 | xc = l1; | ||
| 650 | xd = TRUE; | ||
| 651 | } | ||
| 652 | } | ||
| 653 | |||
| 654 | if (++yp > yc) | ||
| 655 | { | ||
| 656 | yp = 1; | ||
| 657 | if (++yc >= l2) | ||
| 658 | { | ||
| 659 | yc = l1; | ||
| 660 | yd = TRUE; | ||
| 661 | } | ||
| 662 | } | ||
| 663 | |||
| 664 | if (!xd || !yd) | ||
| 665 | goto l6; | ||
| 666 | fSame = FALSE; | ||
| 667 | |||
| 668 | if (l1 >= cLine || l2 >= cLine) | ||
| 669 | printf ("%s", ReSyncMes); | ||
| 670 | |||
| 671 | printf ("***** %s\n", f1); | ||
| 672 | dump (buffer1, 0, l1-1); | ||
| 673 | printf ("***** %s\n", f2); | ||
| 674 | dump (buffer2, 0, l2-1); | ||
| 675 | printf ("*****\n\n"); | ||
| 676 | exit (1); | ||
| 677 | } | ||
| 678 | |||
| 679 | |||
| 680 | |||
| 681 | /* return number of lines read in */ | ||
| 682 | xfill (pl, fh, ct, plnum) | ||
| 683 | struct lineType *pl; | ||
| 684 | FILE *fh; | ||
| 685 | int ct; | ||
| 686 | int *plnum; | ||
| 687 | { | ||
| 688 | int i; | ||
| 689 | |||
| 690 | #ifdef DEBUG | ||
| 691 | if (fDebug) | ||
| 692 | printf ("xfill (%04x, %04x)\n", pl, fh); | ||
| 693 | #endif | ||
| 694 | |||
| 695 | i = 0; | ||
| 696 | while (ct-- && (*funcRead) (pl->text, MAXARG, fh) != NULL) | ||
| 697 | { | ||
| 698 | if (funcRead == (int (*) ())FNADDR(fgets)) | ||
| 699 | pl->text[strlen(pl->text)-1] = 0; | ||
| 700 | if (fIgnore && !strcmps (pl->text, "")) | ||
| 701 | pl->text[0] = 0; | ||
| 702 | if (strlen (pl->text) != 0 || !fIgnore) | ||
| 703 | { | ||
| 704 | pl->line = ++*plnum; | ||
| 705 | pl++; | ||
| 706 | i++; | ||
| 707 | } | ||
| 708 | } | ||
| 709 | |||
| 710 | #ifdef DEBUG | ||
| 711 | if (fDebug) | ||
| 712 | printf ("xfill returns %d\n", i); | ||
| 713 | #endif | ||
| 714 | |||
| 715 | return i; | ||
| 716 | } | ||
| 717 | |||
| 718 | |||
| 719 | /* adjust returns number of lines in buffer */ | ||
| 720 | adjust (pl, ml, lt) | ||
| 721 | struct lineType *pl; | ||
| 722 | int ml; | ||
| 723 | int lt; | ||
| 724 | { | ||
| 725 | |||
| 726 | #ifdef DEBUG | ||
| 727 | if (fDebug) | ||
| 728 | printf ("adjust (%04x, %d, %d) = ", pl, ml, lt); | ||
| 729 | if (fDebug) | ||
| 730 | printf ("%d\n", ml-lt); | ||
| 731 | #endif | ||
| 732 | |||
| 733 | if (ml <= lt) | ||
| 734 | return 0; | ||
| 735 | |||
| 736 | #ifdef DEBUG | ||
| 737 | if (fDebug) | ||
| 738 | printf ("move (%04x, %04x, %04x)\n", &pl[lt], &pl[0], sizeof (*pl)*(ml-lt)); | ||
| 739 | #endif | ||
| 740 | |||
| 741 | Move ((unsigned char far *)&pl[lt], (char far *)&pl[0], sizeof (*pl)*(ml-lt)); | ||
| 742 | return ml-lt; | ||
| 743 | } | ||
| 744 | |||
| 745 | |||
| 746 | /* dump | ||
| 747 | * dump outputs a range of lines. | ||
| 748 | * | ||
| 749 | * INPUTS | ||
| 750 | * pl pointer to current lineType structure | ||
| 751 | * start starting line number | ||
| 752 | * end ending line number | ||
| 753 | * | ||
| 754 | * CALLS | ||
| 755 | * pline, printf | ||
| 756 | * | ||
| 757 | */ | ||
| 758 | dump (pl, start, end) | ||
| 759 | struct lineType *pl; | ||
| 760 | int start, end; | ||
| 761 | { | ||
| 762 | if (fAbbrev && end-start > 2) | ||
| 763 | { | ||
| 764 | pline (pl+start); | ||
| 765 | printf ("...\n"); | ||
| 766 | pline (pl+end); | ||
| 767 | } | ||
| 768 | else | ||
| 769 | while (start <= end) | ||
| 770 | pline (pl+start++); | ||
| 771 | } | ||
| 772 | |||
| 773 | |||
| 774 | |||
| 775 | |||
| 776 | /* PrintLINE | ||
| 777 | * pline prints a single line of output. If the /n flag | ||
| 778 | * has been specified, the line number of the printed text is added. | ||
| 779 | * | ||
| 780 | * Inputs | ||
| 781 | * pl pointer to current lineType structure | ||
| 782 | * fNumb TRUE if /n specified | ||
| 783 | * | ||
| 784 | */ | ||
| 785 | pline (pl) | ||
| 786 | struct lineType *pl; | ||
| 787 | { | ||
| 788 | if (fNumb) | ||
| 789 | printf ("%5d: ", pl->line); | ||
| 790 | |||
| 791 | printf ("%s\n", pl->text); | ||
| 792 | } | ||
| 793 | |||
| 794 | /* | ||
| 795 | * strcmpi will compare two string lexically and return one of | ||
| 796 | * the following: | ||
| 797 | * - 0 if the strings are equal | ||
| 798 | * - 1 if first > the second | ||
| 799 | * - (-1) if first < the second | ||
| 800 | * | ||
| 801 | * This was written to replace the run time library version of | ||
| 802 | * strcmpi which does not correctly compare the european character set. | ||
| 803 | * This version relies on a version of toupper which uses IToupper. | ||
| 804 | */ | ||
| 805 | |||
| 806 | int strcmpi(str1, str2) | ||
| 807 | unsigned char *str1, *str2; | ||
| 808 | { | ||
| 809 | unsigned char c1, c2; | ||
| 810 | |||
| 811 | while ((c1 = toupper(*str1++)) == (c2 = toupper(*str2++))) { | ||
| 812 | if (c1 == '\0') | ||
| 813 | return(0); | ||
| 814 | } | ||
| 815 | |||
| 816 | if (c1 > c2) | ||
| 817 | return(1); | ||
| 818 | else | ||
| 819 | return(-1); | ||
| 820 | } | ||
| 821 | |||
| 822 | |||
| 823 | /* compare two strings, ignoring white space, case is significant, return | ||
| 824 | * 0 if identical, <>0 otherwise | ||
| 825 | */ | ||
| 826 | strcmps (p1, p2) | ||
| 827 | unsigned char *p1, *p2; | ||
| 828 | { | ||
| 829 | while (TRUE) { | ||
| 830 | while (ISSPACE(*p1)) | ||
| 831 | p1++; | ||
| 832 | while (ISSPACE(*p2)) | ||
| 833 | p2++; | ||
| 834 | if (*p1 == *p2) | ||
| 835 | if (*p1++ == 0) | ||
| 836 | return 0; | ||
| 837 | else | ||
| 838 | p2++; | ||
| 839 | else | ||
| 840 | return *p1-*p2; | ||
| 841 | } | ||
| 842 | } | ||
| 843 | |||
| 844 | |||
| 845 | /* compare two strings, ignoring white space, case is not significant, return | ||
| 846 | * 0 if identical, <>0 otherwise | ||
| 847 | */ | ||
| 848 | int strcmpis (p1, p2) | ||
| 849 | unsigned char *p1, *p2; | ||
| 850 | { | ||
| 851 | while (TRUE) { | ||
| 852 | while (ISSPACE(*p1)) | ||
| 853 | p1++; | ||
| 854 | while (ISSPACE(*p2)) | ||
| 855 | p2++; | ||
| 856 | if (toupper (*p1) == toupper (*p2)) | ||
| 857 | if (*p1++ == 0) | ||
| 858 | return 0; | ||
| 859 | else | ||
| 860 | p2++; | ||
| 861 | else | ||
| 862 | return *p1-*p2; | ||
| 863 | } | ||
| 864 | } | ||