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