1 /* linelist.c 2 * 3 * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft. 4 * All rights reserved. 5 * 6 */ 7 8 #include "syshdrs.h" 9 10 /* Dynamically make a copy of a string. */ 11 char * 12 StrDup(const char *buf) 13 { 14 char *cp; 15 size_t len; 16 17 if (buf == NULL) 18 return (NULL); 19 20 len = strlen(buf) + 1; 21 cp = (char *) malloc(len); 22 if (cp != NULL) 23 (void) memcpy(cp, buf, len); 24 return (cp); 25 } /* StrDup */ 26 27 28 29 /* Disposes each node of a LineList. Does a few extra things 30 * so the disposed memory won't be very useful after it is freed. 31 */ 32 void 33 DisposeLineListContents(LineListPtr list) 34 { 35 LinePtr lp, lp2; 36 37 for (lp = list->first; lp != NULL; ) { 38 lp2 = lp; 39 lp = lp->next; 40 if (lp2->line != NULL) { 41 lp2->line[0] = '\0'; 42 free(lp2->line); 43 } 44 free(lp2); 45 } 46 /* Same as InitLineList. */ 47 (void) memset(list, 0, sizeof(LineList)); 48 } /* DisposeLineListContents */ 49 50 51 52 53 void 54 InitLineList(LineListPtr list) 55 { 56 (void) memset(list, 0, sizeof(LineList)); 57 } /* InitLineList */ 58 59 60 61 62 LinePtr 63 RemoveLine(LineListPtr list, LinePtr killMe) 64 { 65 LinePtr nextLine, prevLine; 66 67 nextLine = killMe->next; 68 prevLine = killMe->prev; 69 if (killMe->line != NULL) { 70 killMe->line[0] = '\0'; /* Make it useless just in case. */ 71 free(killMe->line); 72 } 73 74 if (list->first == killMe) 75 list->first = nextLine; 76 if (list->last == killMe) 77 list->last = prevLine; 78 79 if (nextLine != NULL) 80 nextLine->prev = prevLine; 81 if (prevLine != NULL) 82 prevLine->next = nextLine; 83 84 free(killMe); 85 list->nLines--; 86 return (nextLine); 87 } /* RemoveLine */ 88 89 90 91 92 /* Adds a string to the LineList specified. */ 93 LinePtr 94 AddLine(LineListPtr list, const char *buf1) 95 { 96 LinePtr lp; 97 char *buf; 98 99 lp = (LinePtr) malloc(sizeof(Line)); 100 if (lp != NULL) { 101 buf = StrDup(buf1); 102 if (buf == NULL) { 103 free(lp); 104 lp = NULL; 105 } else { 106 lp->line = buf; 107 lp->next = NULL; 108 if (list->first == NULL) { 109 list->first = list->last = lp; 110 lp->prev = NULL; 111 list->nLines = 1; 112 } else { 113 lp->prev = list->last; 114 list->last->next = lp; 115 list->last = lp; 116 list->nLines++; 117 } 118 } 119 } 120 return lp; 121 } /* AddLine */ 122 123 124 125 126 int 127 CopyLineList(LineListPtr dst, LineListPtr src) 128 { 129 LinePtr lp, lp2; 130 131 InitLineList(dst); 132 for (lp = src->first; lp != NULL; ) { 133 lp2 = lp; 134 lp = lp->next; 135 if (lp2->line != NULL) { 136 if (AddLine(dst, lp2->line) == NULL) { 137 DisposeLineListContents(dst); 138 return (-1); 139 } 140 } 141 } 142 return (0); 143 } /* CopyLineList */ 144 145 146 147 148 /* Disposes each node of a FileInfoList. Does a few extra things 149 * so the disposed memory won't be very useful after it is freed. 150 */ 151 void 152 DisposeFileInfoListContents(FileInfoListPtr list) 153 { 154 FileInfoPtr lp, lp2; 155 156 for (lp = list->first; lp != NULL; ) { 157 lp2 = lp; 158 lp = lp->next; 159 if (lp2->relname != NULL) { 160 lp2->relname[0] = '\0'; 161 free(lp2->relname); 162 } 163 if (lp2->lname != NULL) { 164 lp2->lname[0] = '\0'; 165 free(lp2->lname); 166 } 167 if (lp2->rname != NULL) { 168 lp2->rname[0] = '\0'; 169 free(lp2->rname); 170 } 171 if (lp2->rlinkto != NULL) { 172 lp2->rlinkto[0] = '\0'; 173 free(lp2->rlinkto); 174 } 175 if (lp2->plug != NULL) { 176 lp2->plug[0] = '\0'; 177 free(lp2->plug); 178 } 179 free(lp2); 180 } 181 182 if (list->vec != NULL) 183 free(list->vec); 184 185 /* Same as InitFileInfoList. */ 186 (void) memset(list, 0, sizeof(FileInfoList)); 187 } /* DisposeFileInfoListContents */ 188 189 190 191 192 void 193 InitFileInfoList(FileInfoListPtr list) 194 { 195 (void) memset(list, 0, sizeof(FileInfoList)); 196 } /* InitFileInfoList */ 197 198 199 200 201 static int 202 TimeCmp(const void *a, const void *b) 203 { 204 FileInfoPtr *fipa, *fipb; 205 206 fipa = (FileInfoPtr *) a; 207 fipb = (FileInfoPtr *) b; 208 if ((**fipb).mdtm == (**fipa).mdtm) 209 return (0); 210 else if ((**fipb).mdtm < (**fipa).mdtm) 211 return (-1); 212 return (1); 213 } /* TimeCmp */ 214 215 216 217 218 static int 219 ReverseTimeCmp(const void *a, const void *b) 220 { 221 FileInfoPtr *fipa, *fipb; 222 223 fipa = (FileInfoPtr *) a; 224 fipb = (FileInfoPtr *) b; 225 if ((**fipa).mdtm == (**fipb).mdtm) 226 return (0); 227 else if ((**fipa).mdtm < (**fipb).mdtm) 228 return (-1); 229 return (1); 230 } /* ReverseTimeCmp */ 231 232 233 234 235 static int 236 SizeCmp(const void *a, const void *b) 237 { 238 FileInfoPtr *fipa, *fipb; 239 240 fipa = (FileInfoPtr *) a; 241 fipb = (FileInfoPtr *) b; 242 if ((**fipb).size == (**fipa).size) 243 return (0); 244 else if ((**fipb).size < (**fipa).size) 245 return (-1); 246 return (1); 247 } /* SizeCmp */ 248 249 250 251 252 static int 253 ReverseSizeCmp(const void *a, const void *b) 254 { 255 FileInfoPtr *fipa, *fipb; 256 257 fipa = (FileInfoPtr *) a; 258 fipb = (FileInfoPtr *) b; 259 if ((**fipa).size == (**fipb).size) 260 return (0); 261 else if ((**fipa).size < (**fipb).size) 262 return (-1); 263 return (1); 264 } /* ReverseSizeCmp */ 265 266 267 268 269 static int 270 ReverseNameCmp(const void *a, const void *b) 271 { 272 FileInfoPtr *fipa, *fipb; 273 274 fipa = (FileInfoPtr *) a; 275 fipb = (FileInfoPtr *) b; 276 #ifdef HAVE_SETLOCALE 277 return (strcoll((**fipb).relname, (**fipa).relname)); 278 #else 279 return (strcmp((**fipb).relname, (**fipa).relname)); 280 #endif 281 } /* ReverseNameCmp */ 282 283 284 285 286 static int 287 NameCmp(const void *a, const void *b) 288 { 289 FileInfoPtr *fipa, *fipb; 290 291 fipa = (FileInfoPtr *) a; 292 fipb = (FileInfoPtr *) b; 293 #ifdef HAVE_SETLOCALE 294 return (strcoll((**fipa).relname, (**fipb).relname)); 295 #else 296 return (strcmp((**fipa).relname, (**fipb).relname)); 297 #endif 298 } /* NameCmp */ 299 300 301 302 303 static int 304 BreadthFirstCmp(const void *a, const void *b) 305 { 306 FileInfoPtr *fipa, *fipb; 307 char *cp, *cpa, *cpb; 308 int depth, deptha, depthb; 309 int c; 310 311 fipa = (FileInfoPtr *) a; 312 fipb = (FileInfoPtr *) b; 313 314 cpa = (**fipa).relname; 315 cpb = (**fipb).relname; 316 317 for (cp = cpa, depth = 0;;) { 318 c = *cp++; 319 if (c == '\0') 320 break; 321 if ((c == '/') || (c == '\\')) { 322 depth++; 323 } 324 } 325 deptha = depth; 326 327 for (cp = cpb, depth = 0;;) { 328 c = *cp++; 329 if (c == '\0') 330 break; 331 if ((c == '/') || (c == '\\')) { 332 depth++; 333 } 334 } 335 depthb = depth; 336 337 if (deptha < depthb) 338 return (-1); 339 else if (deptha > depthb) 340 return (1); 341 342 #ifdef HAVE_SETLOCALE 343 return (strcoll(cpa, cpb)); 344 #else 345 return (strcmp(cpa, cpb)); 346 #endif 347 } /* BreadthFirstCmp */ 348 349 350 351 352 void 353 SortFileInfoList(FileInfoListPtr list, int sortKey, int sortOrder) 354 { 355 FileInfoVec fiv; 356 FileInfoPtr fip; 357 int i, j, n, n2; 358 359 fiv = list->vec; 360 if (fiv == NULL) 361 return; 362 363 if (list->sortKey == sortKey) { 364 if (list->sortOrder == sortOrder) 365 return; /* Already sorted they you want. */ 366 367 /* Reverse the sort. */ 368 n = list->nFileInfos; 369 if (n > 1) { 370 n2 = n / 2; 371 for (i=0; i<n2; i++) { 372 j = n - i - 1; 373 fip = fiv[i]; 374 fiv[i] = fiv[j]; 375 fiv[j] = fip; 376 } 377 } 378 379 list->sortOrder = sortOrder; 380 } else if ((sortKey == 'n') && (sortOrder == 'a')) { 381 qsort(fiv, (size_t) list->nFileInfos, sizeof(FileInfoPtr), 382 NameCmp); 383 list->sortKey = sortKey; 384 list->sortOrder = sortOrder; 385 } else if ((sortKey == 'n') && (sortOrder == 'd')) { 386 qsort(fiv, (size_t) list->nFileInfos, sizeof(FileInfoPtr), 387 ReverseNameCmp); 388 list->sortKey = sortKey; 389 list->sortOrder = sortOrder; 390 } else if ((sortKey == 't') && (sortOrder == 'a')) { 391 qsort(fiv, (size_t) list->nFileInfos, sizeof(FileInfoPtr), 392 TimeCmp); 393 list->sortKey = sortKey; 394 list->sortOrder = sortOrder; 395 } else if ((sortKey == 't') && (sortOrder == 'd')) { 396 qsort(fiv, (size_t) list->nFileInfos, sizeof(FileInfoPtr), 397 ReverseTimeCmp); 398 list->sortKey = sortKey; 399 list->sortOrder = sortOrder; 400 } else if ((sortKey == 's') && (sortOrder == 'a')) { 401 qsort(fiv, (size_t) list->nFileInfos, sizeof(FileInfoPtr), 402 SizeCmp); 403 list->sortKey = sortKey; 404 list->sortOrder = sortOrder; 405 } else if ((sortKey == 's') && (sortOrder == 'd')) { 406 qsort(fiv, (size_t) list->nFileInfos, sizeof(FileInfoPtr), 407 ReverseSizeCmp); 408 list->sortKey = sortKey; 409 list->sortOrder = sortOrder; 410 } else if (sortKey == 'b') { 411 /* This is different from the rest. */ 412 list->sortKey = sortKey; 413 list->sortOrder = sortOrder; 414 qsort(fiv, (size_t) list->nFileInfos, sizeof(FileInfoPtr), 415 BreadthFirstCmp); 416 } 417 } /* SortFileInfoList */ 418 419 420 421 422 void 423 VectorizeFileInfoList(FileInfoListPtr list) 424 { 425 FileInfoVec fiv; 426 FileInfoPtr fip; 427 int i; 428 429 fiv = (FileInfoVec) calloc((size_t) (list->nFileInfos + 1), sizeof(FileInfoPtr)); 430 if (fiv != (FileInfoVec) 0) { 431 for (i = 0, fip = list->first; fip != NULL; fip = fip->next, i++) 432 fiv[i] = fip; 433 list->vec = fiv; 434 } 435 } /* VectorizeFileInfoList */ 436 437 438 439 440 void 441 UnvectorizeFileInfoList(FileInfoListPtr list) 442 { 443 FileInfoVec fiv; 444 FileInfoPtr fip; 445 int i, n; 446 447 fiv = list->vec; 448 if (fiv != (FileInfoVec) 0) { 449 list->first = fiv[0]; 450 n = list->nFileInfos; 451 if (n > 0) { 452 list->last = fiv[n - 1]; 453 fip = fiv[0]; 454 fip->prev = NULL; 455 fip->next = fiv[1]; 456 for (i = 1; i < n; i++) { 457 fip = fiv[i]; 458 fip->prev = fiv[i - 1]; 459 fip->next = fiv[i + 1]; 460 } 461 } 462 free(fiv); 463 list->vec = (FileInfoVec) 0; 464 } 465 } /* UnvectorizeFileInfoList */ 466 467 468 469 470 void 471 InitFileInfo(FileInfoPtr fip) 472 { 473 (void) memset(fip, 0, sizeof(FileInfo)); 474 fip->type = '-'; 475 fip->size = kSizeUnknown; 476 fip->mdtm = kModTimeUnknown; 477 } /* InitFileInfoList */ 478 479 480 481 482 FileInfoPtr 483 RemoveFileInfo(FileInfoListPtr list, FileInfoPtr killMe) 484 { 485 FileInfoPtr nextFileInfo, prevFileInfo; 486 487 nextFileInfo = killMe->next; 488 prevFileInfo = killMe->prev; 489 if (killMe->lname != NULL) { 490 killMe->lname[0] = '\0'; /* Make it useless just in case. */ 491 free(killMe->lname); 492 } 493 if (killMe->relname != NULL) { 494 killMe->relname[0] = '\0'; 495 free(killMe->relname); 496 } 497 if (killMe->rname != NULL) { 498 killMe->rname[0] = '\0'; 499 free(killMe->rname); 500 } 501 if (killMe->rlinkto != NULL) { 502 killMe->rlinkto[0] = '\0'; 503 free(killMe->rlinkto); 504 } 505 if (killMe->plug != NULL) { 506 killMe->plug[0] = '\0'; 507 free(killMe->plug); 508 } 509 510 if (list->first == killMe) 511 list->first = nextFileInfo; 512 if (list->last == killMe) 513 list->last = prevFileInfo; 514 515 if (nextFileInfo != NULL) 516 nextFileInfo->prev = prevFileInfo; 517 if (prevFileInfo != NULL) 518 prevFileInfo->next = nextFileInfo; 519 520 free(killMe); 521 list->nFileInfos--; 522 return (nextFileInfo); 523 } /* RemoveFileInfo */ 524 525 526 527 528 /* Adds a string to the FileInfoList specified. */ 529 FileInfoPtr 530 AddFileInfo(FileInfoListPtr list, FileInfoPtr src) 531 { 532 FileInfoPtr lp; 533 534 lp = (FileInfoPtr) malloc(sizeof(FileInfo)); 535 if (lp != NULL) { 536 (void) memcpy(lp, src, sizeof(FileInfo)); 537 lp->next = NULL; 538 if (list->first == NULL) { 539 list->first = list->last = lp; 540 lp->prev = NULL; 541 list->nFileInfos = 1; 542 } else { 543 lp->prev = list->last; 544 list->last->next = lp; 545 list->last = lp; 546 list->nFileInfos++; 547 } 548 } 549 return lp; 550 } /* AddFileInfo */ 551 552 553 554 555 int 556 ConcatFileInfoList(FileInfoListPtr dst, FileInfoListPtr src) 557 { 558 FileInfoPtr lp, lp2; 559 FileInfo newfi; 560 561 for (lp = src->first; lp != NULL; lp = lp2) { 562 lp2 = lp->next; 563 newfi = *lp; 564 newfi.relname = StrDup(lp->relname); 565 newfi.lname = StrDup(lp->lname); 566 newfi.rname = StrDup(lp->rname); 567 newfi.rlinkto = StrDup(lp->rlinkto); 568 newfi.plug = StrDup(lp->plug); 569 if (AddFileInfo(dst, &newfi) == NULL) 570 return (-1); 571 } 572 return (0); 573 } /* ConcatFileInfoList */ 574 575 576 577 578 int 579 ComputeRNames(FileInfoListPtr dst, const char *dstdir, int pflag, int nochop) 580 { 581 FileInfoPtr lp, lp2; 582 char *buf; 583 char *cp; 584 585 if (dstdir == NULL) 586 dstdir = "."; 587 588 for (lp = dst->first; lp != NULL; lp = lp2) { 589 lp2 = lp->next; 590 591 buf = NULL; 592 if (nochop != 0) { 593 if ((dstdir[0] != '\0') && (strcmp(dstdir, "."))) { 594 if (Dynscat(&buf, dstdir, "/", lp->relname, 0) == NULL) 595 goto memerr; 596 597 if (pflag != 0) { 598 /* Init lname to parent dir name of remote dir */ 599 cp = strrchr(dstdir, '/'); 600 if (cp == NULL) 601 cp = strrchr(dstdir, '\\'); 602 if (cp != NULL) { 603 if (Dynscat(&lp->lname, cp + 1, 0) == NULL) 604 goto memerr; 605 TVFSPathToLocalPath(lp->lname); 606 } 607 } 608 } else { 609 if (Dynscat(&buf, lp->relname, 0) == NULL) 610 goto memerr; 611 } 612 } else { 613 if ((dstdir[0] != '\0') && (strcmp(dstdir, "."))) { 614 cp = strrchr(lp->relname, '/'); 615 if (cp == NULL) 616 cp = strrchr(lp->relname, '\\'); 617 if (cp != NULL) { 618 cp++; 619 } else { 620 cp = lp->relname; 621 } 622 if (Dynscat(&buf, dstdir, "/", cp, 0) == NULL) 623 goto memerr; 624 625 if (pflag != 0) { 626 /* Init lname to parent dir name of remote dir */ 627 cp = strrchr(dstdir, '/'); 628 if (cp == NULL) 629 cp = strrchr(dstdir, '\\'); 630 if (cp != NULL) { 631 if (Dynscat(&lp->lname, cp + 1, 0) == NULL) 632 goto memerr; 633 TVFSPathToLocalPath(lp->lname); 634 } 635 } 636 } else { 637 cp = strrchr(lp->relname, '/'); 638 if (cp == NULL) 639 cp = strrchr(lp->relname, '\\'); 640 if (cp != NULL) { 641 cp++; 642 } else { 643 cp = lp->relname; 644 } 645 if (Dynscat(&buf, cp, 0) == NULL) 646 goto memerr; 647 } 648 } 649 lp->rname = buf; 650 if (lp->rname == NULL) { 651 memerr: 652 return (-1); 653 } 654 LocalPathToTVFSPath(lp->rname); 655 } 656 return (0); 657 } /* ComputeRNames */ 658 659 660 661 662 int 663 ComputeLNames(FileInfoListPtr dst, const char *srcdir, const char *dstdir, int nochop) 664 { 665 FileInfoPtr lp, lp2; 666 char *buf; 667 char *cp; 668 669 if (srcdir != NULL) { 670 cp = strrchr(srcdir, '/'); 671 if (cp == NULL) 672 cp = strrchr(srcdir, '\\'); 673 if (cp != NULL) 674 srcdir = cp + 1; 675 } 676 if (dstdir == NULL) 677 dstdir = "."; 678 679 for (lp = dst->first; lp != NULL; lp = lp2) { 680 lp2 = lp->next; 681 682 buf = NULL; 683 if (nochop != 0) { 684 if ((dstdir[0] != '\0') && (strcmp(dstdir, "."))) { 685 if (Dynscat(&buf, dstdir, "/", 0) == NULL) 686 goto memerr; 687 } 688 if (lp->lname != NULL) { 689 if (Dynscat(&buf, lp->lname, "/", 0) == NULL) 690 goto memerr; 691 } else if (srcdir != NULL) { 692 if (Dynscat(&buf, srcdir, "/", 0) == NULL) 693 goto memerr; 694 } 695 if (Dynscat(&buf, lp->relname, 0) == NULL) 696 goto memerr; 697 } else { 698 if ((dstdir[0] != '\0') && (strcmp(dstdir, "."))) { 699 cp = strrchr(lp->relname, '/'); 700 if (cp == NULL) 701 cp = strrchr(lp->relname, '\\'); 702 if (cp == NULL) { 703 cp = lp->relname; 704 } else { 705 cp++; 706 } 707 if (Dynscat(&buf, dstdir, "/", cp, 0) == NULL) 708 goto memerr; 709 } else { 710 cp = strrchr(lp->relname, '/'); 711 if (cp == NULL) 712 cp = strrchr(lp->relname, '\\'); 713 if (cp == NULL) { 714 cp = lp->relname; 715 } else { 716 cp++; 717 } 718 if (Dynscat(&buf, cp, 0) == NULL) 719 goto memerr; 720 } 721 } 722 if (buf == NULL) { 723 memerr: 724 return (-1); 725 } 726 if (lp->lname != NULL) { 727 free(lp->lname); 728 lp->lname = NULL; 729 } 730 lp->lname = buf; 731 TVFSPathToLocalPath(lp->lname); 732 } 733 return (0); 734 } /* ComputeLNames */ 735 736 737 738 739 int 740 ConcatFileToFileInfoList(FileInfoListPtr dst, char *rfile) 741 { 742 FileInfo newfi; 743 744 InitFileInfo(&newfi); /* Use defaults. */ 745 newfi.relname = StrDup(rfile); 746 newfi.rname = NULL; 747 newfi.lname = NULL; 748 749 if (AddFileInfo(dst, &newfi) == NULL) 750 return (-1); 751 return (0); 752 } /* ConcatFileToFileInfoList */ 753 754 755 756 757 int 758 LineListToFileInfoList(LineListPtr src, FileInfoListPtr dst) 759 { 760 LinePtr lp, lp2; 761 762 InitFileInfoList(dst); 763 for (lp = src->first; lp != NULL; lp = lp2) { 764 lp2 = lp->next; 765 if (ConcatFileToFileInfoList(dst, lp->line) < 0) 766 return (-1); 767 } 768 return (0); 769 } /* LineListToFileList */ 770 771 772 773 774 int 775 LineToFileInfoList(LinePtr lp, FileInfoListPtr dst) 776 { 777 InitFileInfoList(dst); 778 if (ConcatFileToFileInfoList(dst, lp->line) < 0) 779 return (-1); 780 return (0); 781 } /* LineToFileInfoList */ 782 783 /* eof */ 784