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 *
StrDup(const char * buf)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
DisposeLineListContents(LineListPtr list)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
InitLineList(LineListPtr list)54 InitLineList(LineListPtr list)
55 {
56 (void) memset(list, 0, sizeof(LineList));
57 } /* InitLineList */
58
59
60
61
62 LinePtr
RemoveLine(LineListPtr list,LinePtr killMe)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
AddLine(LineListPtr list,const char * buf1)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
CopyLineList(LineListPtr dst,LineListPtr src)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
DisposeFileInfoListContents(FileInfoListPtr list)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
InitFileInfoList(FileInfoListPtr list)193 InitFileInfoList(FileInfoListPtr list)
194 {
195 (void) memset(list, 0, sizeof(FileInfoList));
196 } /* InitFileInfoList */
197
198
199
200
201 static int
TimeCmp(const void * a,const void * b)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
ReverseTimeCmp(const void * a,const void * b)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
SizeCmp(const void * a,const void * b)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
ReverseSizeCmp(const void * a,const void * b)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
ReverseNameCmp(const void * a,const void * b)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
NameCmp(const void * a,const void * b)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
BreadthFirstCmp(const void * a,const void * b)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
SortFileInfoList(FileInfoListPtr list,int sortKey,int sortOrder)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
VectorizeFileInfoList(FileInfoListPtr list)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
UnvectorizeFileInfoList(FileInfoListPtr list)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
InitFileInfo(FileInfoPtr fip)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
RemoveFileInfo(FileInfoListPtr list,FileInfoPtr killMe)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
AddFileInfo(FileInfoListPtr list,FileInfoPtr src)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
ConcatFileInfoList(FileInfoListPtr dst,FileInfoListPtr src)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
ComputeRNames(FileInfoListPtr dst,const char * dstdir,int pflag,int nochop)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
ComputeLNames(FileInfoListPtr dst,const char * srcdir,const char * dstdir,int nochop)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
ConcatFileToFileInfoList(FileInfoListPtr dst,char * rfile)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
LineListToFileInfoList(LineListPtr src,FileInfoListPtr dst)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
LineToFileInfoList(LinePtr lp,FileInfoListPtr dst)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