Changeset 1309 for trunk/src/kmk/kmkbuiltin/cmp_util.c
- Timestamp:
- Dec 2, 2007, 5:53:40 AM (18 years ago)
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/kmkbuiltin/cmp_util.c
r1301 r1309 1 1 /* $NetBSD: cmp.c,v 1.15 2006/01/19 20:44:57 garbled Exp $ */ 2 /* $NetBSD: misc.c,v 1.11 2007/08/22 16:59:19 christos Exp $ */ 3 /* $NetBSD: regular.c,v 1.20 2006/06/03 21:47:55 christos Exp $ */ 4 /* $NetBSD: special.c,v 1.12 2007/08/21 14:09:54 christos Exp $ */ 2 5 3 6 /* … … 30 33 */ 31 34 32 /*#include <sys/cdefs.h>*/33 #ifndef lint34 35 /*__COPYRIGHT("@(#) Copyright (c) 1987, 1990, 1993, 1994\n\ 35 36 The Regents of the University of California. All rights reserved.\n");*/ 36 #endif /* not lint */37 38 #ifndef lint39 /*#if 040 static char sccsid[] = "@(#)cmp.c 8.3 (Berkeley) 4/2/94";41 #else42 __RCSID("$NetBSD: cmp.c,v 1.15 2006/01/19 20:44:57 garbled Exp $");43 #endif*/44 #endif /* not lint */45 37 46 38 #include <sys/types.h> 47 39 #include <sys/stat.h> 48 49 #include "err.h" 40 #if defined(__FreeBSD__) || defined(__NetBSD__) /** @todo more mmap capable OSes. */ 41 # define CMP_USE_MMAP 42 # include <sys/param.h> 43 # include <sys/mman.h> 44 #endif 50 45 #include <errno.h> 51 46 #include <fcntl.h> … … 55 50 #ifndef _MSC_VER 56 51 # include <unistd.h> 57 #else 52 # ifndef O_BINARY 53 # define O_BINARY 0 54 # endif 55 #else 56 # define MSC_DO_64_BIT_IO 58 57 # include "mscfakes.h" 59 # if _MSC_VER >= 1400 /* We want 64-bit file lengths here when possible. */ 60 # define off_t __int64 61 # define stat _stat64 62 # define fstat _fstat64 63 # define lseek _lseeki64 64 # endif 65 #endif 66 #include <locale.h> 67 #include "getopt.h" 68 69 #ifndef O_BINARY 70 # define O_BINARY 0 71 #endif 72 73 /*#include "extern.h"*/ 74 75 #include "kmkbuiltin.h" 76 77 78 static int lflag, sflag; 79 80 static struct option long_options[] = 81 { 82 { "help", no_argument, 0, 261 }, 83 { "version", no_argument, 0, 262 }, 84 { 0, 0, 0, 0 }, 85 }; 86 87 88 /* this is kind of ugly but its the simplest way to avoid namespace mess. */ 89 #include "cmp_misc.c" 90 #include "cmp_special.c" 91 #if defined(__FreeBSD__) || defined(__NetBSD__) /** @todo more mmap capable OSes. */ 92 #include "cmp_regular.c" 93 #else 94 #include "cmp_regular_std.c" 95 #endif 96 97 static int usage(FILE *); 98 58 #endif 59 #include "err.h" 60 61 #include "cmp_extern.h" 62 63 64 static int 65 errmsg(const char *file, off_t byte, off_t line, int lflag) 66 { 67 if (lflag) 68 #ifdef _MSC_VER 69 return err(ERR_EXIT, "%s: char %I64d, line %lld", file, (__int64)byte, (long long)line); 70 #else 71 return err(ERR_EXIT, "%s: char %lld, line %lld", file, (long long)byte, (long long)line); 72 #endif 73 return err(ERR_EXIT, "%s", file); 74 } 75 76 77 static int 78 eofmsg(const char *file, off_t byte, off_t line, int sflag, int lflag) 79 { 80 if (!sflag) 81 { 82 if (!lflag) 83 warnx("EOF on %s", file); 84 else 85 { 86 #ifdef _MSC_VER 87 if (line > 0) 88 warnx("EOF on %s: char %I64d, line %I64d", file, (__int64)byte, (__int64)line); 89 else 90 warnx("EOF on %s: char %I64d", file, (__int64)byte); 91 #else 92 if (line > 0) 93 warnx("EOF on %s: char %lld, line %lld", file, (long long)byte, (long long)line); 94 else 95 warnx("EOF on %s: char %lld", file, (long long)byte); 96 #endif 97 } 98 } 99 return DIFF_EXIT; 100 } 101 102 103 static int 104 diffmsg(const char *file1, const char *file2, off_t byte, off_t line, int sflag) 105 { 106 if (!sflag) 107 #ifdef _MSC_VER 108 printf("%s %s differ: char %I64d, line %I64d\n", 109 file1, file2, (__int64)byte, (__int64)line); 110 #else 111 printf("%s %s differ: char %lld, line %lld\n", 112 file1, file2, (long long)byte, (long long)line); 113 #endif 114 return DIFF_EXIT; 115 } 116 117 118 /** 119 * Compares two files, where one or both are non-regular ones. 120 */ 121 static int 122 c_special(int fd1, const char *file1, off_t skip1, 123 int fd2, const char *file2, off_t skip2, 124 int lflag, int sflag) 125 { 126 int fd1dup, fd2dup; 127 FILE *fp1; 128 int rc; 129 130 /* duplicate because fdopen+fclose will otherwise close the handle. */ 131 fd1dup = dup(fd1); 132 if (fd1 < 0) 133 return err(ERR_EXIT, "%s", file1); 134 fp1 = fdopen(fd1dup, "rb"); 135 if (!fp1) 136 fp1 = fdopen(fd1dup, "r"); 137 if (!fp1) 138 { 139 err(ERR_EXIT, "%s", file1); 140 close(fd1dup); 141 return ERR_EXIT; 142 } 143 144 fd2dup = dup(fd2); 145 if (fd2dup >= 0) 146 { 147 FILE *fp2 = fdopen(fd2dup, "rb"); 148 if (!fp2) 149 fp2 = fdopen(fd2dup, "r"); 150 if (fp2) 151 { 152 off_t byte; 153 off_t line; 154 int ch1 = 0; 155 int ch2 = 0; 156 157 /* skipping ahead */ 158 rc = OK_EXIT; 159 for (byte = line = 1; skip1--; byte++) 160 { 161 ch1 = getc(fp1); 162 if (ch1 == EOF) 163 break; 164 if (ch1 == '\n') 165 line++; 166 } 167 for (byte = line = 1; skip2--; byte++) 168 { 169 ch2 = getc(fp2); 170 if (ch2 == EOF) 171 break; 172 if (ch2 == '\n') 173 line++; 174 } 175 if (ch2 != EOF && ch1 != EOF) 176 { 177 /* compare byte by byte */ 178 for (byte = line = 1;; ++byte) 179 { 180 ch1 = getc(fp1); 181 ch2 = getc(fp2); 182 if (ch1 == EOF || ch2 == EOF) 183 break; 184 if (ch1 != ch2) 185 { 186 if (!lflag) 187 { 188 rc = diffmsg(file1, file2, byte, line, sflag); 189 break; 190 } 191 rc = DIFF_EXIT; 192 #ifdef _MSC_VER 193 printf("%6i64d %3o %3o\n", (__int64)byte, ch1, ch2); 194 #else 195 printf("%6lld %3o %3o\n", (long long)byte, ch1, ch2); 196 #endif 197 } 198 if (ch1 == '\n') 199 ++line; 200 } 201 } 202 203 /* Check for errors and length differences (EOF). */ 204 if (ferror(fp1) && rc != ERR_EXIT) 205 rc = errmsg(file1, byte, line, lflag); 206 if (ferror(fp2) && rc != ERR_EXIT) 207 rc = errmsg(file2, byte, line, lflag); 208 if (rc == OK_EXIT) 209 { 210 if (feof(fp1)) 211 { 212 if (!feof(fp2)) 213 rc = eofmsg(file1, byte, line, sflag, lflag); 214 } 215 else if (feof(fp2)) 216 rc = eofmsg(file2, byte, line, sflag, lflag); 217 } 218 219 fclose(fp2); 220 } 221 else 222 { 223 rc = err(ERR_EXIT, "%s", file2); 224 close(fd2dup); 225 } 226 } 227 else 228 rc = err(ERR_EXIT, "%s", file2); 229 230 fclose(fp1); 231 return rc; 232 } 233 234 235 #ifdef CMP_USE_MMAP 236 /** 237 * Compare two files using mmap. 238 */ 239 static int 240 c_regular(int fd1, const char *file1, off_t skip1, off_t len1, 241 int fd2, const char *file2, off_t skip2, off_t len2, int sflag, int lflag) 242 { 243 unsigned char ch, *p1, *p2, *b1, *b2; 244 off_t byte, length, line; 245 int dfound; 246 size_t blk_sz, blk_cnt; 247 248 if (sflag && len1 != len2) 249 return DIFF_EXIT; 250 251 if (skip1 > len1) 252 return eofmsg(file1, len1 + 1, 0, sflag, lflag); 253 len1 -= skip1; 254 if (skip2 > len2) 255 return eofmsg(file2, len2 + 1, 0, sflag, lflag); 256 len2 -= skip2; 257 258 byte = line = 1; 259 dfound = 0; 260 length = len1 <= len2 ? len1 : len2; 261 for (blk_sz = 1024 * 1024; length != 0; length -= blk_sz) 262 { 263 if (blk_sz > length) 264 blk_sz = length; 265 b1 = p1 = mmap(NULL, blk_sz, PROT_READ, MAP_FILE | MAP_SHARED, fd1, skip1); 266 if (p1 == MAP_FAILED) 267 goto l_mmap_failed; 268 269 b2 = p2 = mmap(NULL, blk_sz, PROT_READ, MAP_FILE | MAP_SHARED, fd2, skip2); 270 if (p2 == MAP_FAILED) 271 { 272 munmap(p1, blk_sz); 273 goto l_mmap_failed; 274 } 275 276 blk_cnt = blk_sz; 277 for (; blk_cnt--; ++p1, ++p2, ++byte) 278 { 279 if ((ch = *p1) != *p2) 280 { 281 if (!lflag) 282 { 283 munmap(b1, blk_sz); 284 munmap(b2, blk_sz); 285 return diffmsg(file1, file2, byte, line, sflag); 286 } 287 dfound = 1; 288 #ifdef _MSC_VER 289 printf("%6I64d %3o %3o\n", (__int64)byte, ch, *p2); 290 #else 291 printf("%6lld %3o %3o\n", (long long)byte, ch, *p2); 292 #endif 293 } 294 if (ch == '\n') 295 ++line; 296 } 297 munmap(p1 - blk_sz, blk_sz); 298 munmap(p2 - blk_sz, blk_sz); 299 skip1 += blk_sz; 300 skip2 += blk_sz; 301 } 302 303 if (len1 != len2) 304 return eofmsg(len1 > len2 ? file2 : file1, byte, line, sflag, lflag); 305 if (dfound) 306 return DIFF_EXIT; 307 return OK_EXIT; 308 309 l_mmap_failed: 310 return c_special(fd1, file1, skip1, fd2, file2, skip2, lflag, sflag); 311 } 312 313 #else /* non-mmap c_regular: */ 314 315 /** 316 * Compare two files without mmaping them. 317 */ 318 static int 319 c_regular(int fd1, const char *file1, off_t skip1, off_t len1, 320 int fd2, const char *file2, off_t skip2, off_t len2, int sflag, int lflag) 321 { 322 unsigned char ch, *p1, *p2, *b1 = 0, *b2 = 0; 323 off_t byte, length, line, bytes_read; 324 int dfound; 325 size_t blk_sz, blk_cnt; 326 327 if (sflag && len1 != len2) 328 return DIFF_EXIT; 329 330 if (skip1 > len1) 331 return eofmsg(file1, len1 + 1, 0, sflag, lflag); 332 len1 -= skip1; 333 if (skip2 > len2) 334 return eofmsg(file2, len2 + 1, 0, sflag, lflag); 335 len2 -= skip2; 336 337 if (skip1 && lseek(fd1, skip1, SEEK_SET) < 0) 338 goto l_special; 339 if (skip2 && lseek(fd2, skip2, SEEK_SET) < 0) 340 { 341 if (skip1 && lseek(fd1, 0, SEEK_SET) < 0) 342 return err(1, "seek failed"); 343 goto l_special; 344 } 345 346 #define CMP_BUF_SIZE (128*1024) 347 348 b1 = malloc(CMP_BUF_SIZE); 349 b2 = malloc(CMP_BUF_SIZE); 350 if (!b1 || !b2) 351 goto l_malloc_failed; 352 353 byte = line = 1; 354 dfound = 0; 355 length = len1; 356 if (length > len2) 357 length = len2; 358 for (blk_sz = CMP_BUF_SIZE; length != 0; length -= blk_sz) 359 { 360 if ((off_t)blk_sz > length) 361 blk_sz = length; 362 363 bytes_read = read(fd1, b1, blk_sz); 364 if (bytes_read != blk_sz) 365 goto l_read_error; 366 367 bytes_read = read(fd2, b2, blk_sz); 368 if (bytes_read != blk_sz) 369 goto l_read_error; 370 371 blk_cnt = blk_sz; 372 p1 = b1; 373 p2 = b2; 374 for (; blk_cnt--; ++p1, ++p2, ++byte) 375 { 376 if ((ch = *p1) != *p2) 377 { 378 if (!lflag) 379 { 380 free(b1); 381 free(b2); 382 return diffmsg(file1, file2, byte, line, sflag); 383 } 384 dfound = 1; 385 #ifdef _MSC_VER 386 printf("%6I64d %3o %3o\n", (__int64)byte, ch, *p2); 387 #else 388 printf("%6lld %3o %3o\n", (long long)byte, ch, *p2); 389 #endif 390 } 391 if (ch == '\n') 392 ++line; 393 } 394 skip1 += blk_sz; 395 skip2 += blk_sz; 396 } 397 398 if (len1 != len2) 399 return eofmsg(len1 > len2 ? file2 : file1, byte, line, sflag, lflag); 400 if (dfound) 401 return DIFF_EXIT; 402 return OK_EXIT; 403 404 l_read_error: 405 if ( lseek(fd1, 0, SEEK_SET) < 0 406 || lseek(fd2, 0, SEEK_SET) < 0) 407 { 408 err(1, "seek failed"); 409 free(b1); 410 free(b2); 411 return 1; 412 } 413 l_malloc_failed: 414 free(b1); 415 free(b2); 416 l_special: 417 return c_special(fd1, file1, skip1, fd2, file2, skip2, lflag, sflag); 418 } 419 #endif /* non-mmap c_regular */ 420 421 422 /** 423 * Compares two open files. 424 */ 99 425 int 100 kmk_builtin_cmp(int argc, char *argv[], char **envp) 101 { 102 struct stat sb1, sb2; 103 off_t skip1 = 0, skip2 = 0; 104 int ch, fd1, fd2, special; 105 char *file1, *file2; 106 int rc; 107 108 #ifdef kmk_builtin_cmp 109 setlocale(LC_ALL, ""); 110 #endif 111 /* init globals */ 112 lflag = sflag = 0; 113 114 /* reset getopt and set progname. */ 115 g_progname = argv[0]; 116 opterr = 1; 117 optarg = NULL; 118 optopt = 0; 119 optind = 0; /* init */ 120 121 while ((ch = getopt_long(argc, argv, "ls", long_options, NULL)) != -1) 122 switch (ch) { 123 case 'l': /* print all differences */ 124 lflag = 1; 125 break; 126 case 's': /* silent run */ 127 sflag = 1; 128 break; 129 case 261: 130 usage(stdout); 131 return 0; 132 case 262: 133 return kbuild_version(argv[0]); 134 case '?': 135 default: 136 return usage(stderr); 137 } 138 argv += optind; 139 argc -= optind; 140 141 if (lflag && sflag) 142 return errx(ERR_EXIT, "only one of -l and -s may be specified"); 143 144 if (argc < 2 || argc > 4) 145 return usage(stderr); 146 147 /* Backward compatibility -- handle "-" meaning stdin. */ 148 special = 0; 149 if (strcmp(file1 = argv[0], "-") == 0) { 150 special = 1; 151 fd1 = 0; 152 file1 = "stdin"; 153 } 154 else if ((fd1 = open(file1, O_RDONLY | O_BINARY, 0)) < 0) { 155 if (!sflag) 156 warn("%s", file1); 157 return(ERR_EXIT); 158 } 159 if (strcmp(file2 = argv[1], "-") == 0) { 160 if (special) 161 return errx(ERR_EXIT, 162 "standard input may only be specified once"); 163 special = 1; 164 fd2 = 0; 165 file2 = "stdin"; 166 } 167 else if ((fd2 = open(file2, O_RDONLY | O_BINARY, 0)) < 0) { 168 if (!sflag) 169 warn("%s", file2); 170 if (fd1 != 0) close(fd1); 171 return(ERR_EXIT); 172 } 173 174 if (argc > 2) { 175 char *ep; 176 177 errno = 0; 178 skip1 = strtoll(argv[2], &ep, 0); 179 if (errno || ep == argv[2]) { 180 rc = usage(stderr); 181 goto l_exit; 182 } 183 184 if (argc == 4) { 185 skip2 = strtoll(argv[3], &ep, 0); 186 if (errno || ep == argv[3]) { 187 rc = usage(stderr); 188 goto l_exit; 189 } 190 } 191 } 192 193 if (!special) { 194 if (fstat(fd1, &sb1)) { 195 rc = err(ERR_EXIT, "%s", file1); 196 goto l_exit; 197 } 198 if (!S_ISREG(sb1.st_mode)) 199 special = 1; 200 else { 201 if (fstat(fd2, &sb2)) { 202 rc = err(ERR_EXIT, "%s", file2); 203 goto l_exit; 204 } 205 if (!S_ISREG(sb2.st_mode)) 206 special = 1; 207 } 208 } 209 210 if (special) 211 rc = c_special(fd1, file1, skip1, fd2, file2, skip2); 212 else 213 rc = c_regular(fd1, file1, skip1, sb1.st_size, 214 fd2, file2, skip2, sb2.st_size); 215 l_exit: 216 if (fd1 != 0) close(fd1); 217 if (fd2 != 0) close(fd2); 218 return rc; 219 } 220 221 static int 222 usage(FILE *fp) 223 { 224 fprintf(fp, "usage: %s [-l | -s] file1 file2 [skip1 [skip2]]\n" 225 " or: %s --help\n" 226 " or: %s --version\n", 227 g_progname, g_progname, g_progname); 228 return(ERR_EXIT); 229 } 426 cmp_fd_and_fd_ex(int fd1, const char *file1, off_t skip1, 427 int fd2, const char *file2, off_t skip2, 428 int sflag, int lflag, int special) 429 { 430 struct stat st1, st2; 431 int rc; 432 433 if (fstat(fd1, &st1)) 434 return err(ERR_EXIT, "%s", file1); 435 if (fstat(fd2, &st2)) 436 return err(ERR_EXIT, "%s", file2); 437 438 if ( !S_ISREG(st1.st_mode) 439 || !S_ISREG(st2.st_mode) 440 || special) 441 rc = c_special(fd1, file1, skip1, 442 fd2, file2, skip2, sflag, lflag); 443 else 444 rc = c_regular(fd1, file1, skip1, st1.st_size, 445 fd2, file2, skip2, st2.st_size, sflag, lflag); 446 return rc; 447 } 448 449 450 /** 451 * Compares two open files. 452 */ 453 int 454 cmp_fd_and_fd(int fd1, const char *file1, 455 int fd2, const char *file2, 456 int sflag, int lflag, int special) 457 { 458 return cmp_fd_and_fd_ex(fd1, file1, 0, fd2, file2, 0, sflag, lflag, special); 459 } 460 461 462 /** 463 * Compares an open file with another that isn't open yet. 464 */ 465 int 466 cmp_fd_and_file_ex(int fd1, const char *file1, off_t skip1, 467 const char *file2, off_t skip2, 468 int sflag, int lflag, int special) 469 { 470 int rc; 471 int fd2; 472 473 if (!strcmp(file2, "-")) 474 { 475 fd2 = 0 /* stdin */; 476 special = 1; 477 file2 = "stdin"; 478 } 479 else 480 fd2 = open(file2, O_RDONLY | O_BINARY, 0); 481 if (fd2 >= 0) 482 { 483 rc = cmp_fd_and_fd_ex(fd1, file1, skip1, 484 fd2, file2, skip2, sflag, lflag, special); 485 close(fd2); 486 } 487 else 488 { 489 if (!sflag) 490 warn("%s", file2); 491 rc = ERR_EXIT; 492 } 493 return rc; 494 } 495 496 497 /** 498 * Compares an open file with another that isn't open yet. 499 */ 500 int 501 cmp_fd_and_file(int fd1, const char *file1, 502 const char *file2, 503 int sflag, int lflag, int special) 504 { 505 return cmp_fd_and_file_ex(fd1, file1, 0, 506 file2, 0, sflag, lflag, special); 507 } 508 509 510 /** 511 * Opens and compare two files. 512 */ 513 int 514 cmp_file_and_file_ex(const char *file1, off_t skip1, 515 const char *file2, off_t skip2, 516 int sflag, int lflag, int special) 517 { 518 int fd1; 519 int rc; 520 521 if (lflag && sflag) 522 return errx(ERR_EXIT, "only one of -l and -s may be specified"); 523 524 if (!strcmp(file1, "-")) 525 { 526 if (!strcmp(file2, "-")) 527 return errx(ERR_EXIT, "standard input may only be specified once"); 528 file1 = "stdin"; 529 fd1 = 1; 530 special = 1; 531 } 532 else 533 fd1 = open(file1, O_RDONLY | O_BINARY, 0); 534 if (fd1 >= 0) 535 { 536 rc = cmp_fd_and_file_ex(fd1, file1, skip1, 537 file2, skip2, sflag, lflag, special); 538 close(fd1); 539 } 540 else 541 { 542 if (!sflag) 543 warn("%s", file1); 544 rc = ERR_EXIT; 545 } 546 547 return rc; 548 } 549 550 551 /** 552 * Opens and compare two files. 553 */ 554 int 555 cmp_file_and_file(const char *file1, const char *file2, int sflag, int lflag, int special) 556 { 557 return cmp_file_and_file_ex(file1, 0, file2, 0, sflag, lflag, special); 558 } 559
Note:
See TracChangeset
for help on using the changeset viewer.