1 /*
2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
3 *
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
5 * and others.
6 *
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner
9 *
10 * You may distribute under the terms of the GNU General Public License as
11 * specified in the README file that comes with the CVS source distribution.
12 *
13 * Various useful functions for the CVS support code.
14 */
15
16 #include "cvs.h"
17
18 #include "canonicalize.h"
19 #include "canon-host.h"
20 #include "getline.h"
21 #include "vasprintf.h"
22 #include "vasnprintf.h"
23
24 /* Get wint_t. */
25 #ifdef HAVE_WINT_T
26 # include <wchar.h>
27 #endif
28
29 __RCSID("$MirOS: src/gnu/usr.bin/cvs/src/subr.c,v 1.6 2011/07/28 15:54:35 tg Exp $");
30
31
32 extern char *getlogin (void);
33
34
35
36 /* *STRPTR is a pointer returned from malloc (or NULL), pointing to *N
37 characters of space. Reallocate it so that points to at least
38 NEWSIZE bytes of space. Gives a fatal error if out of memory;
39 if it returns it was successful. */
40 void
expand_string(char ** strptr,size_t * n,size_t newsize)41 expand_string (char **strptr, size_t *n, size_t newsize)
42 {
43 while (*n < newsize)
44 *strptr = x2realloc (*strptr, n);
45 }
46
47
48
49 /* char *
50 * Xreadlink (const char *link, size_t size)
51 *
52 * INPUTS
53 * link The original path.
54 * size A guess as to the size needed for the path. It need
55 * not be right.
56 * RETURNS
57 * The resolution of the final symbolic link in the path.
58 *
59 * ERRORS
60 * This function exits with a fatal error if it fails to read the
61 * link for any reason.
62 */
63 char *
Xreadlink(const char * link,size_t size)64 Xreadlink (const char *link, size_t size)
65 {
66 char *file = xreadlink (link, size);
67
68 if (file == NULL)
69 error (1, errno, "cannot readlink %s", link);
70
71 return file;
72 }
73
74
75
76 /* *STR is a pointer to a malloc'd string or NULL. *LENP is its allocated
77 * length. If *STR is NULL then *LENP must be 0 and visa-versa.
78 * Add SRC to the end of *STR, reallocating *STR if necessary. */
79 void
xrealloc_and_strcat(char ** str,size_t * lenp,const char * src)80 xrealloc_and_strcat (char **str, size_t *lenp, const char *src)
81 {
82 bool newstr = !*lenp;
83 expand_string (str, lenp, (newstr ? 0 : strlen (*str)) + strlen (src) + 1);
84 if (newstr)
85 strcpy (*str, src);
86 else
87 strcat (*str, src);
88 }
89
90
91
92 /* Remove trailing newlines from STRING, destructively.
93 *
94 * RETURNS
95 *
96 * True if any newlines were removed, false otherwise.
97 */
98 int
strip_trailing_newlines(char * str)99 strip_trailing_newlines (char *str)
100 {
101 size_t index, origlen;
102 index = origlen = strlen (str);
103
104 while (index > 0 && str[index-1] == '\n')
105 str[--index] = '\0';
106
107 return index != origlen;
108 }
109
110
111
112 /* Return the number of levels that PATH ascends above where it starts.
113 * For example:
114 *
115 * "../../foo" -> 2
116 * "foo/../../bar" -> 1
117 */
118 int
pathname_levels(const char * p)119 pathname_levels (const char *p)
120 {
121 int level;
122 int max_level;
123
124 if (p == NULL) return 0;
125
126 max_level = 0;
127 level = 0;
128 do
129 {
130 /* Now look for pathname level-ups. */
131 if (p[0] == '.' && p[1] == '.' && (p[2] == '\0' || ISSLASH (p[2])))
132 {
133 --level;
134 if (-level > max_level)
135 max_level = -level;
136 }
137 else if (p[0] == '\0' || ISSLASH (p[0]) ||
138 (p[0] == '.' && (p[1] == '\0' || ISSLASH (p[1]))))
139 ;
140 else
141 ++level;
142
143 /* q = strchr (p, '/'); but sub ISSLASH() for '/': */
144 while (*p != '\0' && !ISSLASH (*p)) p++;
145 if (*p != '\0') p++;
146 } while (*p != '\0');
147 return max_level;
148 }
149
150
151
152 /* Free a vector, where (*ARGV)[0], (*ARGV)[1], ... (*ARGV)[*PARGC - 1]
153 are malloc'd and so is *ARGV itself. Such a vector is allocated by
154 line2argv or expand_wild, for example. */
155 void
free_names(int * pargc,char ** argv)156 free_names (int *pargc, char **argv)
157 {
158 register int i;
159
160 for (i = 0; i < *pargc; i++)
161 { /* only do through *pargc */
162 free (argv[i]);
163 }
164 free (argv);
165 *pargc = 0; /* and set it to zero when done */
166 }
167
168
169
170 /* Convert LINE into arguments separated by SEPCHARS. Set *ARGC
171 to the number of arguments found, and (*ARGV)[0] to the first argument,
172 (*ARGV)[1] to the second, etc. *ARGV is malloc'd and so are each of
173 (*ARGV)[0], (*ARGV)[1], ... Use free_names() to return the memory
174 allocated here back to the free pool. */
175 void
line2argv(int * pargc,char *** argv,char * line,char * sepchars)176 line2argv (int *pargc, char ***argv, char *line, char *sepchars)
177 {
178 char *cp;
179 /* Could make a case for size_t or some other unsigned type, but
180 we'll stick with int to avoid signed/unsigned warnings when
181 comparing with *pargc. */
182 int argv_allocated;
183
184 /* Small for testing. */
185 argv_allocated = 1;
186 *argv = xnmalloc (argv_allocated, sizeof (**argv));
187
188 *pargc = 0;
189 for (cp = strtok (line, sepchars); cp; cp = strtok (NULL, sepchars))
190 {
191 if (*pargc == argv_allocated)
192 {
193 argv_allocated *= 2;
194 *argv = xnrealloc (*argv, argv_allocated, sizeof (**argv));
195 }
196 (*argv)[*pargc] = xstrdup (cp);
197 (*pargc)++;
198 }
199 }
200
201
202
203 /*
204 * Returns the number of dots ('.') found in an RCS revision number
205 */
206 int
numdots(const char * s)207 numdots (const char *s)
208 {
209 int dots = 0;
210
211 for (; *s; s++)
212 {
213 if (*s == '.')
214 dots++;
215 }
216 return (dots);
217 }
218
219
220
221 /* Compare revision numbers REV1 and REV2 by consecutive fields.
222 Return negative, zero, or positive in the manner of strcmp. The
223 two revision numbers must have the same number of fields, or else
224 compare_revnums will return an inaccurate result. */
225 int
compare_revnums(const char * rev1,const char * rev2)226 compare_revnums (const char *rev1, const char *rev2)
227 {
228 const char *sp, *tp;
229 char *snext, *tnext;
230 int result = 0;
231
232 sp = rev1;
233 tp = rev2;
234 while (result == 0)
235 {
236 result = strtoul (sp, &snext, 10) - strtoul (tp, &tnext, 10);
237 if (*snext == '\0' || *tnext == '\0')
238 break;
239 sp = snext + 1;
240 tp = tnext + 1;
241 }
242
243 return result;
244 }
245
246
247
248 /* Increment a revision number. Working on the string is a bit awkward,
249 but it avoid problems with integer overflow should the revision numbers
250 get really big. */
251 char *
increment_revnum(const char * rev)252 increment_revnum (const char *rev)
253 {
254 char *newrev, *p;
255 size_t len = strlen (rev);
256
257 newrev = xmalloc (len + 2);
258 memcpy (newrev, rev, len + 1);
259 for (p = newrev + len; p != newrev; )
260 {
261 --p;
262 if (!isdigit(*p))
263 {
264 ++p;
265 break;
266 }
267 if (*p != '9')
268 {
269 ++*p;
270 return newrev;
271 }
272 *p = '0';
273 }
274 /* The number was all 9s, so change the first character to 1 and add
275 a 0 to the end. */
276 *p = '1';
277 p = newrev + len;
278 *p++ = '0';
279 *p = '\0';
280 return newrev;
281 }
282
283
284
285 /* Return the username by which the caller should be identified in
286 CVS, in contexts such as the author field of RCS files, various
287 logs, etc. */
288 char *
getcaller(void)289 getcaller (void)
290 {
291 #ifndef SYSTEM_GETCALLER
292 static char *cache;
293 struct passwd *pw;
294 uid_t uid;
295 #endif
296
297 /* If there is a CVS username, return it. */
298 #ifdef AUTH_SERVER_SUPPORT
299 if (CVS_Username != NULL)
300 return CVS_Username;
301 #endif
302
303 #ifdef SYSTEM_GETCALLER
304 return SYSTEM_GETCALLER ();
305 #else
306 /* Get the caller's login from his uid. If the real uid is "root"
307 try LOGNAME USER or getlogin(). If getlogin() and getpwuid()
308 both fail, return the uid as a string. */
309
310 if (cache != NULL)
311 return cache;
312
313 uid = getuid ();
314 if (uid == (uid_t) 0)
315 {
316 char *name;
317
318 /* super-user; try getlogin() to distinguish */
319 if (((name = getlogin ()) || (name = getenv("LOGNAME")) ||
320 (name = getenv("USER"))) && *name)
321 {
322 cache = xstrdup (name);
323 return cache;
324 }
325 }
326 if ((pw = (struct passwd *) getpwuid (uid)) == NULL)
327 {
328 cache = Xasprintf ("uid%lu", (unsigned long) uid);
329 return cache;
330 }
331 cache = xstrdup (pw->pw_name);
332 return cache;
333 #endif
334 }
335
336
337
338 #ifdef lint
339 # ifndef __GNUC__
340 /* ARGSUSED */
341 bool
get_date(struct timespec * result,char const * p,struct timespec const * now)342 get_date (struct timespec *result, char const *p, struct timespec const *now)
343 {
344 result->tv_sec = 0;
345 result->tv_nsec = 0;
346
347 return false;
348 }
349 # endif
350 #endif
351
352
353
354 /* Given some revision, REV, return the first prior revision that exists in the
355 * RCS file, RCS.
356 *
357 * ASSUMPTIONS
358 * REV exists.
359 *
360 * INPUTS
361 * RCS The RCS node pointer.
362 * REV An existing revision in the RCS file referred to by RCS.
363 *
364 * RETURNS
365 * The first prior revision that exists in the RCS file, or NULL if no prior
366 * revision exists. The caller is responsible for disposing of this string.
367 *
368 * NOTES
369 * This function currently neglects the case where we are on the trunk with
370 * rev = X.1, where X != 1. If rev = X.Y, where X != 1 and Y > 1, then this
371 * function should work fine, as revision X.1 must exist, due to RCS rules.
372 */
373 char *
previous_rev(RCSNode * rcs,const char * rev)374 previous_rev (RCSNode *rcs, const char *rev)
375 {
376 char *p;
377 char *tmp = xstrdup (rev);
378 long r1;
379 char *retval;
380
381 /* Our retval can have no more digits and dots than our input revision. */
382 retval = xmalloc (strlen (rev) + 1);
383 p = strrchr (tmp, '.');
384 *p = '\0';
385 r1 = strtol (p+1, NULL, 10);
386 do {
387 if (--r1 == 0)
388 {
389 /* If r1 == 0, then we must be on a branch and our parent must
390 * exist, or we must be on the trunk with a REV like X.1.
391 * We are neglecting the X.1 with X != 1 case by assuming that
392 * there is no previous revision when we discover we were on
393 * the trunk.
394 */
395 p = strrchr (tmp, '.');
396 if (p == NULL)
397 /* We are on the trunk. */
398 retval = NULL;
399 else
400 {
401 *p = '\0';
402 sprintf (retval, "%s", tmp);
403 }
404 break;
405 }
406 sprintf (retval, "%s.%ld", tmp, r1);
407 } while (!RCS_exist_rev (rcs, retval));
408
409 free (tmp);
410 return retval;
411 }
412
413
414
415 /* Given two revisions, find their greatest common ancestor. If the
416 two input revisions exist, then rcs guarantees that the gca will
417 exist. */
418 char *
gca(const char * rev1,const char * rev2)419 gca (const char *rev1, const char *rev2)
420 {
421 int dots;
422 char *gca, *g;
423 const char *p1, *p2;
424 int r1, r2;
425 char *retval;
426
427 if (rev1 == NULL || rev2 == NULL)
428 {
429 error (0, 0, "sanity failure in gca");
430 abort();
431 }
432
433 /* The greatest common ancestor will have no more dots, and numbers
434 of digits for each component no greater than the arguments. Therefore
435 this string will be big enough. */
436 g = gca = xmalloc (strlen (rev1) + strlen (rev2) + 100);
437
438 /* walk the strings, reading the common parts. */
439 p1 = rev1;
440 p2 = rev2;
441 do
442 {
443 r1 = strtol (p1, (char **) &p1, 10);
444 r2 = strtol (p2, (char **) &p2, 10);
445
446 /* use the lowest. */
447 (void) sprintf (g, "%d.", r1 < r2 ? r1 : r2);
448 g += strlen (g);
449 if (*p1 == '.') ++p1;
450 else break;
451 if (*p2 == '.') ++p2;
452 else break;
453 } while (r1 == r2);
454
455 /* erase that last dot. */
456 *--g = '\0';
457
458 /* numbers differ, or we ran out of strings. we're done with the
459 common parts. */
460
461 dots = numdots (gca);
462 if (dots == 0)
463 {
464 /* revisions differ in trunk major number. */
465
466 if (r2 < r1) p1 = p2;
467 if (*p1 == '\0')
468 {
469 /* we only got one number. this is strange. */
470 error (0, 0, "bad revisions %s or %s", rev1, rev2);
471 abort();
472 }
473 else
474 {
475 /* we have a minor number. use it. */
476 *g++ = '.';
477 while (*p1 != '.' && *p1 != '\0')
478 *g++ = *p1++;
479 *g = '\0';
480 }
481 }
482 else if ((dots & 1) == 0)
483 {
484 /* if we have an even number of dots, then we have a branch.
485 remove the last number in order to make it a revision. */
486
487 g = strrchr (gca, '.');
488 *g = '\0';
489 }
490
491 retval = xstrdup (gca);
492 free (gca);
493 return retval;
494 }
495
496
497
498 /* Give fatal error if REV is numeric and ARGC,ARGV imply we are
499 planning to operate on more than one file. The current directory
500 should be the working directory. Note that callers assume that we
501 will only be checking the first character of REV; it need not have
502 '\0' at the end of the tag name and other niceties. Right now this
503 is only called from admin.c, but if people like the concept it probably
504 should also be called from diff -r, update -r, get -r, and log -r. */
505 void
check_numeric(const char * rev,int argc,char ** argv)506 check_numeric (const char *rev, int argc, char **argv)
507 {
508 if (rev == NULL || !isdigit ((unsigned char) *rev))
509 return;
510
511 /* Note that the check for whether we are processing more than one
512 file is (basically) syntactic; that is, we don't behave differently
513 depending on whether a directory happens to contain only a single
514 file or whether it contains more than one. I strongly suspect this
515 is the least confusing behavior. */
516 if (argc != 1
517 || (!wrap_name_has (argv[0], WRAP_TOCVS) && isdir (argv[0])))
518 {
519 error (0, 0, "while processing more than one file:");
520 error (1, 0, "attempt to specify a numeric revision");
521 }
522 }
523
524
525
526 /*
527 * Sanity checks and any required fix-up on message passed to RCS via '-m'.
528 * RCS 5.7 requires that a non-total-whitespace, non-null message be provided
529 * with '-m'. Returns a newly allocated, non-empty buffer with whitespace
530 * stripped from end of lines and end of buffer.
531 *
532 * TODO: We no longer use RCS to manage repository files, so maybe this
533 * nonsense about non-empty log fields can be dropped.
534 */
535 char *
make_message_rcsvalid(const char * message)536 make_message_rcsvalid (const char *message)
537 {
538 char *dst, *dp;
539 const char *mp;
540
541 if (message == NULL) message = "";
542
543 /* Strip whitespace from end of lines and end of string. */
544 dp = dst = (char *) xmalloc (strlen (message) + 1);
545 for (mp = message; *mp != '\0'; ++mp)
546 {
547 if (*mp == '\n')
548 {
549 /* At end-of-line; backtrack to last non-space. */
550 while (dp > dst && (dp[-1] == ' ' || dp[-1] == '\t'))
551 --dp;
552 }
553 *dp++ = *mp;
554 }
555
556 /* Backtrack to last non-space at end of string, and truncate. */
557 while (dp > dst && isspace ((unsigned char) dp[-1]))
558 --dp;
559 *dp = '\0';
560
561 /* After all that, if there was no non-space in the string,
562 substitute a non-empty message. */
563 if (*dst == '\0')
564 {
565 free (dst);
566 dst = xstrdup ("*** empty log message ***");
567 }
568
569 return dst;
570 }
571
572
573
574 /* Does the file FINFO contain conflict markers? The whole concept
575 of looking at the contents of the file to figure out whether there are
576 unresolved conflicts is kind of bogus (people do want to manage files
577 which contain those patterns not as conflict markers), but for now it
578 is what we do. */
579 int
file_has_markers(const struct file_info * finfo)580 file_has_markers (const struct file_info *finfo)
581 {
582 FILE *fp;
583 char *line = NULL;
584 size_t line_allocated = 0;
585 int result;
586
587 result = 0;
588 fp = CVS_FOPEN (finfo->file, "r");
589 if (fp == NULL)
590 error (1, errno, "cannot open %s", finfo->fullname);
591 while (getline (&line, &line_allocated, fp) > 0)
592 {
593 if (strncmp (line, RCS_MERGE_PAT_1, sizeof RCS_MERGE_PAT_1 - 1) == 0 ||
594 strncmp (line, RCS_MERGE_PAT_2, sizeof RCS_MERGE_PAT_2 - 1) == 0 ||
595 strncmp (line, RCS_MERGE_PAT_3, sizeof RCS_MERGE_PAT_3 - 1) == 0)
596 {
597 result = 1;
598 goto out;
599 }
600 }
601 if (ferror (fp))
602 error (0, errno, "cannot read %s", finfo->fullname);
603 out:
604 if (fclose (fp) < 0)
605 error (0, errno, "cannot close %s", finfo->fullname);
606 if (line != NULL)
607 free (line);
608 return result;
609 }
610
611
612
613 /* Read the entire contents of the file NAME into *BUF.
614 If NAME is NULL, read from stdin. *BUF
615 is a pointer returned from malloc (or NULL), pointing to *BUFSIZE
616 bytes of space. The actual size is returned in *LEN. On error,
617 give a fatal error. The name of the file to use in error messages
618 (typically will include a directory if we have changed directory)
619 is FULLNAME. MODE is "r" for text or "rb" for binary. */
620 void
get_file(const char * name,const char * fullname,const char * mode,char ** buf,size_t * bufsize,size_t * len)621 get_file (const char *name, const char *fullname, const char *mode, char **buf,
622 size_t *bufsize, size_t *len)
623 {
624 struct stat s;
625 size_t nread;
626 char *tobuf;
627 FILE *e;
628 size_t filesize;
629
630 if (name == NULL)
631 {
632 e = stdin;
633 filesize = 100; /* force allocation of minimum buffer */
634 }
635 else
636 {
637 /* Although it would be cleaner in some ways to just read
638 until end of file, reallocating the buffer, this function
639 does get called on files in the working directory which can
640 be of arbitrary size, so I think we better do all that
641 extra allocation. */
642
643 if (stat (name, &s) < 0)
644 error (1, errno, "can't stat %s", fullname);
645
646 /* Convert from signed to unsigned. */
647 filesize = s.st_size;
648
649 e = xfopen (name, mode);
650 }
651
652 if (*buf == NULL || *bufsize <= filesize)
653 {
654 *bufsize = filesize + 1;
655 *buf = xrealloc (*buf, *bufsize);
656 }
657
658 tobuf = *buf;
659 nread = 0;
660 while (1)
661 {
662 size_t got;
663
664 got = fread (tobuf, 1, *bufsize - (tobuf - *buf), e);
665 if (ferror (e))
666 error (1, errno, "can't read %s", fullname);
667 nread += got;
668 tobuf += got;
669
670 if (feof (e))
671 break;
672
673 /* Allocate more space if needed. */
674 if (tobuf == *buf + *bufsize)
675 {
676 int c;
677 long off;
678
679 c = getc (e);
680 if (c == EOF)
681 break;
682 off = tobuf - *buf;
683 expand_string (buf, bufsize, *bufsize + 100);
684 tobuf = *buf + off;
685 *tobuf++ = c;
686 ++nread;
687 }
688 }
689
690 if (e != stdin && fclose (e) < 0)
691 error (0, errno, "cannot close %s", fullname);
692
693 *len = nread;
694
695 /* Force *BUF to be large enough to hold a null terminator. */
696 if (nread == *bufsize)
697 expand_string (buf, bufsize, *bufsize + 1);
698 (*buf)[nread] = '\0';
699 }
700
701
702
703 /* Follow a chain of symbolic links to its destination. FILENAME
704 should be a handle to a malloc'd block of memory which contains the
705 beginning of the chain. This routine will replace the contents of
706 FILENAME with the destination (a real file). */
707 void
resolve_symlink(char ** filename)708 resolve_symlink (char **filename)
709 {
710 ssize_t rsize;
711
712 if (filename == NULL || *filename == NULL)
713 return;
714
715 while ((rsize = islink (*filename)) > 0)
716 {
717 #ifdef HAVE_READLINK
718 /* The clean thing to do is probably to have each filesubr.c
719 implement this (with an error if not supported by the
720 platform, in which case islink would presumably return 0).
721 But that would require editing each filesubr.c and so the
722 expedient hack seems to be looking at HAVE_READLINK. */
723 char *newname = Xreadlink (*filename, rsize);
724
725 if (ISABSOLUTE (newname))
726 {
727 free (*filename);
728 *filename = newname;
729 }
730 else
731 {
732 const char *oldname = last_component (*filename);
733 int dirlen = oldname - *filename;
734 char *fullnewname = xmalloc (dirlen + strlen (newname) + 1);
735 strncpy (fullnewname, *filename, dirlen);
736 strcpy (fullnewname + dirlen, newname);
737 free (newname);
738 free (*filename);
739 *filename = fullnewname;
740 }
741 #else
742 error (1, 0, "internal error: islink doesn't like readlink");
743 #endif
744 }
745 }
746
747
748
749 /*
750 * Rename a file to an appropriate backup name based on BAKPREFIX.
751 * If suffix non-null, then ".<suffix>" is appended to the new name.
752 *
753 * Returns the new name, which caller may free() if desired.
754 */
755 char *
backup_file(const char * filename,const char * suffix)756 backup_file (const char *filename, const char *suffix)
757 {
758 char *backup_name = Xasprintf ("%s%s%s%s", BAKPREFIX, filename,
759 suffix ? "." : "", suffix ? suffix : "");
760
761 if (isfile (filename))
762 copy_file (filename, backup_name);
763
764 return backup_name;
765 }
766
767
768
769 /*
770 * Copy a string into a buffer escaping any shell metacharacters. The
771 * buffer should be at least twice as long as the string.
772 *
773 * Returns a pointer to the terminating NUL byte in buffer.
774 */
775 char *
shell_escape(char * buf,const char * str)776 shell_escape(char *buf, const char *str)
777 {
778 static const char meta[] = "$`\\\"";
779 const char *p;
780
781 for (;;)
782 {
783 p = strpbrk(str, meta);
784 if (!p) p = str + strlen(str);
785 if (p > str)
786 {
787 memcpy(buf, str, p - str);
788 buf += p - str;
789 }
790 if (!*p) break;
791 *buf++ = '\\';
792 *buf++ = *p++;
793 str = p;
794 }
795 *buf = '\0';
796 return buf;
797 }
798
799
800
801 /*
802 * We can only travel forwards in time, not backwards. :)
803 */
804 void
sleep_past(time_t desttime)805 sleep_past (time_t desttime)
806 {
807 time_t t;
808 long s;
809 long us;
810
811 if (time (&t) > desttime) return;
812
813 while (time (&t) <= desttime)
814 {
815 #ifdef HAVE_GETTIMEOFDAY
816 struct timeval tv;
817 gettimeofday (&tv, NULL);
818 if (tv.tv_sec > desttime)
819 break;
820 s = desttime - tv.tv_sec;
821 if (tv.tv_usec > 0)
822 us = 1000000 - tv.tv_usec;
823 else
824 {
825 s++;
826 us = 0;
827 }
828 #else
829 /* default to 20 ms increments */
830 s = desttime - t;
831 us = 20000;
832 #endif
833
834 {
835 struct timespec ts;
836 ts.tv_sec = s;
837 ts.tv_nsec = us * 1000;
838 (void)nanosleep (&ts, NULL);
839 }
840 }
841
842 /* sleep another 20 ms (2 HZ) to avoid races */
843 {
844 struct timespec ts;
845 ts.tv_sec = 0;
846 ts.tv_nsec = 20 * 1000 * 1000;
847 (void)nanosleep (&ts, NULL);
848 }
849 }
850
851
852
853 /* used to store callback data in a list indexed by the user format string
854 */
855 typedef int (*CONVPROC_t) (Node *, void *);
856 struct cmdline_bindings
857 {
858 char conversion;
859 void *data;
860 CONVPROC_t convproc;
861 void *closure;
862 };
863 /* since we store the above in a list, we need to dispose of the data field.
864 * we don't have to worry about convproc or closure since pointers are stuck
865 * in there directly and format_cmdline's caller is responsible for disposing
866 * of those if necessary.
867 */
868 static void
cmdline_bindings_hash_node_delete(Node * p)869 cmdline_bindings_hash_node_delete (Node *p)
870 {
871 struct cmdline_bindings *b = p->data;
872
873 if (b->conversion != ',')
874 {
875 free (b->data);
876 }
877 free (b);
878 }
879
880
881
882 /*
883 * assume s is a literal argument and put it between quotes,
884 * escaping as appropriate for a shell command line
885 *
886 * the caller is responsible for disposing of the new string
887 */
888 char *
cmdlinequote(char quotes,char * s)889 cmdlinequote (char quotes, char *s)
890 {
891 char *quoted = cmdlineescape (quotes, s);
892 char *buf = Xasprintf ("%c%s%c", quotes, quoted, quotes);
893
894 free (quoted);
895 return buf;
896 }
897
898
899
900 /* read quotes as the type of quotes we are between (if any) and then make our
901 * argument so it could make it past a cmdline parser (using sh as a model)
902 * inside the quotes (if any).
903 *
904 * if you were planning on expanding any paths, it should be done before
905 * calling this function, as it escapes shell metacharacters.
906 *
907 * the caller is responsible for disposing of the new string
908 *
909 * FIXME: See about removing/combining this functionality with shell_escape()
910 * in subr.c.
911 */
912 char *
cmdlineescape(char quotes,char * s)913 cmdlineescape (char quotes, char *s)
914 {
915 char *buf = NULL;
916 size_t length = 0;
917 char *d = NULL;
918 size_t doff;
919 char *lastspace;
920
921 lastspace = s - 1;
922 do
923 {
924 /* FIXME: Single quotes only require other single quotes to be escaped
925 * for Bourne Shell.
926 */
927 if ( isspace( *s ) ) lastspace = s;
928 if( quotes
929 ? ( *s == quotes
930 || ( quotes == '"'
931 && ( *s == '$' || *s == '`' || *s == '\\' ) ) )
932 : ( strchr( "\\$`'\"*?", *s )
933 || isspace( *s )
934 || ( lastspace == ( s - 1 )
935 && *s == '~' ) ) )
936 {
937 doff = d - buf;
938 expand_string (&buf, &length, doff + 1);
939 d = buf + doff;
940 *d++ = '\\';
941 }
942 doff = d - buf;
943 expand_string (&buf, &length, doff + 1);
944 d = buf + doff;
945 } while ((*d++ = *s++) != '\0');
946 return (buf);
947 }
948
949
950
951 /* expand format strings in a command line. modeled roughly after printf
952 *
953 * this function's arg list must be NULL terminated
954 *
955 * assume a space delimited list of args is the desired final output,
956 * but args can be quoted (" or ').
957 *
958 * the best usage examples are in tag.c & logmsg.c, but here goes:
959 *
960 * INPUTS
961 * int oldway to support old format strings
962 * char *srepos you guessed it
963 * char *format the format string to parse
964 * ... NULL terminated data list in the following format:
965 * char *userformat, char *printfformat, <type> data
966 * where
967 * char *userformat a list of possible
968 * format characters the
969 * end user might pass us
970 * in the format string
971 * (e.g. those found in
972 * taginfo or loginfo)
973 * multiple characters in
974 * this strings will be
975 * aliases for each other
976 * char *printfformat the same list of args
977 * printf uses to
978 * determine what kind of
979 * data the next arg will
980 * be
981 * <type> data a piece of data to be
982 * formatted into the user
983 * string, <type>
984 * determined by the
985 * printfformat string.
986 * or
987 * char *userformat, char *printfformat, List *data,
988 * int (*convproc) (Node *, void *), void *closure
989 * where
990 * char *userformat same as above, except
991 * multiple characters in
992 * this string represent
993 * different node
994 * attributes which can be
995 * retrieved from data by
996 * convproc
997 * char *printfformat = ","
998 * List *data the list to be walked
999 * with walklist &
1000 * convproc to retrieve
1001 * data for each of the
1002 * possible format
1003 * characters in
1004 * userformat
1005 * int (*convproc)() see data
1006 * void *closure arg to be passed into
1007 * walklist as closure
1008 * data for convproc
1009 *
1010 * EXAMPLE
1011 * (ignoring oldway variable and srepos since those are only around while we
1012 * SUPPORT_OLD_INFO_FMT_STRINGS)
1013 * format_cmdline ("/cvsroot/CVSROOT/mytaginfoproc %t %o %{sVv}",
1014 * "t", "s", "newtag",
1015 * "o", "s", "mov",
1016 * "xG", "ld", longintwhichwontbeusedthispass,
1017 * "sVv", ",", tlist, pretag_list_to_args_proc,
1018 * (void *) mydata,
1019 * (char *) NULL);
1020 *
1021 * would generate the following command line, assuming two files in tlist,
1022 * file1 & file2, each with old versions 1.1 and new version 1.1.2.3:
1023 *
1024 * /cvsroot/CVSROOT/mytaginfoproc "newtag" "mov" "file1" "1.1" "1.1.2.3" "file2" "1.1" "1.1.2.3"
1025 *
1026 * RETURNS
1027 * pointer to newly allocated string. the caller is responsible for
1028 * disposing of this string.
1029 */
1030 char *
1031 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
format_cmdline(bool oldway,const char * srepos,const char * format,...)1032 format_cmdline (bool oldway, const char *srepos, const char *format, ...)
1033 #else /* SUPPORT_OLD_INFO_FMT_STRINGS */
1034 format_cmdline (const char *format, ...)
1035 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1036 {
1037 va_list args; /* our input function args */
1038 char *buf; /* where we store our output string */
1039 size_t length; /* the allocated length of our output string in bytes.
1040 * used as a temporary storage for the length of the
1041 * next function argument during function
1042 * initialization
1043 */
1044 char *pfmt; /* initially the list of fmt keys passed in,
1045 * but used as a temporary key buffer later
1046 */
1047 char *fmt; /* buffer for format string which we are processing */
1048 size_t flen; /* length of fmt buffer */
1049 char *d, *q, *r; /* for walking strings */
1050 const char *s;
1051 size_t doff, qoff;
1052 char inquotes;
1053
1054 List *pflist = getlist(); /* our list of input data indexed by format
1055 * "strings"
1056 */
1057 Node *p;
1058 struct cmdline_bindings *b;
1059 static int warned_of_deprecation = 0;
1060 char key[] = "?"; /* Used as temporary storage for a single
1061 * character search string used to locate a
1062 * hash key.
1063 */
1064 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1065 /* state varialbes in the while loop which parses the actual
1066 * format string in the final parsing pass*/
1067 int onearg;
1068 int subbedsomething;
1069 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1070
1071 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1072 if (oldway && !warned_of_deprecation)
1073 {
1074 /* warn the user that we don't like his kind 'round these parts */
1075 warned_of_deprecation = 1;
1076 error (0, 0,
1077 "warning: Set to use deprecated info format strings. Establish\n"
1078 "compatibility with the new info file format strings (add a temporary '1' in\n"
1079 "all info files after each '%%' which doesn't represent a literal percent)\n"
1080 "and set UseNewInfoFmtStrings=yes in CVSROOT/config. After that, convert\n"
1081 "individual command lines and scripts to handle the new format at your\n"
1082 "leisure.");
1083 }
1084 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1085
1086 va_start (args, format);
1087
1088 /* read our possible format strings
1089 * expect a certain number of arguments by type and a NULL format
1090 * string to terminate the list.
1091 */
1092 while ((pfmt = va_arg (args, char *)) != NULL)
1093 {
1094 char *conversion = va_arg (args, char *);
1095
1096 char conversion_error = 0;
1097 char char_conversion = 0;
1098 char decimal_conversion = 0;
1099 char integer_conversion = 0;
1100 char string_conversion = 0;
1101
1102 /* allocate space to save our data */
1103 b = xmalloc(sizeof(struct cmdline_bindings));
1104
1105 /* where did you think we were going to store all this data??? */
1106 b->convproc = NULL;
1107 b->closure = NULL;
1108
1109 /* read a length from the conversion string */
1110 s = conversion;
1111 length = 0;
1112 while (!length && *s)
1113 {
1114 switch (*s)
1115 {
1116 case 'h':
1117 integer_conversion = 1;
1118 if (s[1] == 'h')
1119 {
1120 length = sizeof (char);
1121 s += 2;
1122 }
1123 else
1124 {
1125 char_conversion = 1;
1126 length = sizeof (short);
1127 s++;
1128 }
1129 break;
1130 #ifdef HAVE_INTMAX_T
1131 case 'j':
1132 integer_conversion = 1;
1133 length = sizeof (intmax_t);
1134 s++;
1135 break;
1136 #endif /* HAVE_INTMAX_T */
1137 case 'l':
1138 integer_conversion = 1;
1139 if (s[1] == 'l')
1140 {
1141 #ifdef HAVE_LONG_LONG
1142 length = sizeof (long long);
1143 #endif
1144 s += 2;
1145 }
1146 else
1147 {
1148 char_conversion = 2;
1149 string_conversion = 2;
1150 length = sizeof (long);
1151 s++;
1152 }
1153 break;
1154 case 't':
1155 integer_conversion = 1;
1156 length = sizeof (ptrdiff_t);
1157 s++;
1158 break;
1159 case 'z':
1160 integer_conversion = 1;
1161 length = sizeof (size_t);
1162 s++;
1163 break;
1164 #ifdef HAVE_LONG_DOUBLE
1165 case 'L':
1166 decimal_conversion = 1;
1167 length = sizeof (long double);
1168 s++;
1169 break;
1170 #endif
1171 default:
1172 char_conversion = 1;
1173 decimal_conversion = 1;
1174 integer_conversion = 1;
1175 string_conversion = 1;
1176 /* take care of it when we find out what we're looking for */
1177 length = -1;
1178 break;
1179 }
1180 }
1181 /* if we don't have a valid conversion left, that is an error */
1182 /* read an argument conversion */
1183 buf = xmalloc (strlen(conversion) + 2);
1184 *buf = '%';
1185 strcpy (buf+1, conversion);
1186 switch (*s)
1187 {
1188 case 'c':
1189 /* chars (an integer conversion) */
1190 if (!char_conversion)
1191 {
1192 conversion_error = 1;
1193 break;
1194 }
1195 if (char_conversion == 2)
1196 {
1197 #ifdef HAVE_WINT_T
1198 length = sizeof (wint_t);
1199 #else
1200 conversion_error = 1;
1201 break;
1202 #endif
1203 }
1204 else
1205 length = sizeof (char);
1206 /* fall through... */
1207 case 'd':
1208 case 'i':
1209 case 'o':
1210 case 'u':
1211 case 'x':
1212 case 'X':
1213 /* integer conversions */
1214 if (!integer_conversion)
1215 {
1216 conversion_error = 1;
1217 break;
1218 }
1219 if (length == -1)
1220 {
1221 length = sizeof (int);
1222 }
1223 switch (length)
1224 {
1225 case sizeof(char):
1226 {
1227 char arg_char = (char) va_arg (args, int);
1228 b->data = Xasprintf (buf, arg_char);
1229 break;
1230 }
1231 #ifdef UNIQUE_INT_TYPE_WINT_T /* implies HAVE_WINT_T */
1232 case sizeof(wint_t):
1233 {
1234 wint_t arg_wint_t = va_arg (args, wint_t);
1235 b->data = Xasprintf (buf, arg_wint_t);
1236 break;
1237 }
1238 #endif /* UNIQUE_INT_TYPE_WINT_T */
1239 #ifdef UNIQUE_INT_TYPE_SHORT
1240 case sizeof(short):
1241 {
1242 short arg_short = (short) va_arg (args, int);
1243 b->data = Xasprintf (buf, arg_short);
1244 break;
1245 }
1246 #endif /* UNIQUE_INT_TYPE_SHORT */
1247 #ifdef UNIQUE_INT_TYPE_INT
1248 case sizeof(int):
1249 {
1250 int arg_int = va_arg (args, int);
1251 b->data = Xasprintf(buf, arg_int);
1252 break;
1253 }
1254 #endif /* UNIQUE_INT_TYPE_INT */
1255 #ifdef UNIQUE_INT_TYPE_LONG
1256 case sizeof(long):
1257 {
1258 long arg_long = va_arg (args, long);
1259 b->data = Xasprintf (buf, arg_long);
1260 break;
1261 }
1262 #endif /* UNIQUE_INT_TYPE_LONG */
1263 #ifdef UNIQUE_INT_TYPE_LONG_LONG /* implies HAVE_LONG_LONG */
1264 case sizeof(long long):
1265 {
1266 long long arg_long_long = va_arg (args, long long);
1267 b->data = Xasprintf (buf, arg_long_long);
1268 break;
1269 }
1270 #endif /* UNIQUE_INT_TYPE_LONG_LONG */
1271 #ifdef UNIQUE_INT_TYPE_INTMAX_T /* implies HAVE_INTMAX_T */
1272 case sizeof(intmax_t):
1273 {
1274 intmax_t arg_intmax_t = va_arg (args, intmax_t);
1275 b->data = Xasprintf (buf, arg_intmax_t);
1276 break;
1277 }
1278 #endif /* UNIQUE_INT_TYPE_INTMAX_T */
1279 #ifdef UNIQUE_INT_TYPE_SIZE_T
1280 case sizeof(size_t):
1281 {
1282 size_t arg_size_t = va_arg (args, size_t);
1283 b->data = Xasprintf (buf, arg_size_t);
1284 break;
1285 }
1286 #endif /* UNIQUE_INT_TYPE_SIZE_T */
1287 #ifdef UNIQUE_INT_TYPE_PTRDIFF_T
1288 case sizeof(ptrdiff_t):
1289 {
1290 ptrdiff_t arg_ptrdiff_t = va_arg (args, ptrdiff_t);
1291 b->data = Xasprintf (buf, arg_ptrdiff_t);
1292 break;
1293 }
1294 #endif /* UNIQUE_INT_TYPE_PTRDIFF_T */
1295 default:
1296 dellist(&pflist);
1297 free(b);
1298 error (1, 0,
1299 "internal error: unknown integer arg size (%zd)",
1300 length);
1301 break;
1302 }
1303 break;
1304 case 'a':
1305 case 'A':
1306 case 'e':
1307 case 'E':
1308 case 'f':
1309 case 'F':
1310 case 'g':
1311 case 'G':
1312 /* decimal conversions */
1313 if (!decimal_conversion)
1314 {
1315 conversion_error = 1;
1316 break;
1317 }
1318 if (length == -1)
1319 {
1320 length = sizeof (double);
1321 }
1322 switch (length)
1323 {
1324 case sizeof(double):
1325 {
1326 double arg_double = va_arg (args, double);
1327 b->data = Xasprintf (buf, arg_double);
1328 break;
1329 }
1330 #ifdef UNIQUE_FLOAT_TYPE_LONG_DOUBLE /* implies HAVE_LONG_DOUBLE */
1331 case sizeof(long double):
1332 {
1333 long double arg_long_double = va_arg (args, long double);
1334 b->data = Xasprintf (buf, arg_long_double);
1335 break;
1336 }
1337 #endif /* UNIQUE_FLOAT_TYPE_LONG_DOUBLE */
1338 default:
1339 dellist(&pflist);
1340 free(b);
1341 error (1, 0,
1342 "internal error: unknown floating point arg size (%zd)",
1343 length);
1344 break;
1345 }
1346 break;
1347 case 's':
1348 switch (string_conversion)
1349 {
1350 case 1:
1351 b->data = xstrdup (va_arg (args, char *));
1352 break;
1353 #ifdef HAVE_WCHAR_T
1354 case 2:
1355 {
1356 wchar_t *arg_wchar_t_string = va_arg (args, wchar_t *);
1357 b->data = Xasprintf (buf, arg_wchar_t_string);
1358 break;
1359 }
1360 #endif /* HAVE_WCHAR_T */
1361 default:
1362 conversion_error = 1;
1363 break;
1364 }
1365 break;
1366 case ',':
1367 if (length != -1)
1368 {
1369 conversion_error = 1;
1370 break;
1371 }
1372 b->data = va_arg (args, List *);
1373 b->convproc = va_arg (args, CONVPROC_t);
1374 b->closure = va_arg (args, void *);
1375 break;
1376 default:
1377 conversion_error = 1;
1378 break;
1379 }
1380 free (buf);
1381 /* fail if we found an error or haven't found the end of the string */
1382 if (conversion_error || s[1])
1383 {
1384 error (1, 0,
1385 "internal error (format_cmdline): '%s' is not a valid conversion!!!",
1386 conversion);
1387 }
1388
1389
1390 /* save our type - we really only care wheter it's a list type (',')
1391 * or not from now on, but what the hell...
1392 */
1393 b->conversion = *s;
1394
1395 /* separate the user format string into parts and stuff our data into
1396 * the pflist (once for each possible string - diverse keys can have
1397 * duplicate data).
1398 */
1399 q = pfmt;
1400 while (*q)
1401 {
1402 struct cmdline_bindings *tb;
1403 if (*q == '{')
1404 {
1405 s = q + 1;
1406 while (*++q && *q != '}');
1407 r = q + 1;
1408 }
1409 else
1410 {
1411 s = q++;
1412 r = q;
1413 }
1414 if (*r)
1415 {
1416 /* copy the data since we'll need it again */
1417 tb = xmalloc(sizeof(struct cmdline_bindings));
1418 if (b->conversion == ',')
1419 {
1420 tb->data = b->data;
1421 }
1422 else
1423 {
1424 tb->data = xstrdup(b->data);
1425 }
1426 tb->conversion = b->conversion;
1427 tb->convproc = b->convproc;
1428 tb->closure = b->closure;
1429 }
1430 else
1431 {
1432 /* we're done after this, so we don't need to copy the data */
1433 tb = b;
1434 }
1435 p = getnode();
1436 p->key = xmalloc((q - s) + 1);
1437 strncpy (p->key, s, q - s);
1438 p->key[q-s] = '\0';
1439 p->data = tb;
1440 p->delproc = cmdline_bindings_hash_node_delete;
1441 addnode(pflist,p);
1442 }
1443 }
1444
1445 /* we're done with va_list */
1446 va_end(args);
1447
1448 /* All formatted strings include a format character that resolves to the
1449 * empty string by default, so put it in pflist.
1450 */
1451 /* allocate space to save our data */
1452 b = xmalloc(sizeof(struct cmdline_bindings));
1453 b->conversion = 's';
1454 b->convproc = NULL;
1455 b->closure = NULL;
1456 b->data = xstrdup( "" );
1457 p = getnode();
1458 p->key = xstrdup( "n" );
1459 p->data = b;
1460 p->delproc = cmdline_bindings_hash_node_delete;
1461 addnode( pflist,p );
1462
1463 /* finally, read the user string and copy it into rargv as appropriate */
1464 /* user format strings look as follows:
1465 *
1466 * %% is a literal %
1467 * \X, where X is any character = \X, (this is the escape you'd expect, but
1468 * we are leaving the \ for an expected final pass which splits our
1469 * output string into separate arguments
1470 *
1471 * %X means sub var "X" into location
1472 * %{VWXYZ} means sub V,W,X,Y,Z into location as a single arg. The shell
1473 * || would be to quote the comma separated arguments. Each list
1474 * that V, W, X, Y, and Z represent attributes of will cause a new
1475 * tuple to be inserted for each list item with a space between
1476 * items.
1477 * e.g."V W1,X1,Z1 W2,X2,Z2 W3,X3,Z3 Y1 Y2" where V is not a list
1478 * variable, W,X,&Z are attributes of a list with 3 items and Y is an
1479 * attribute of a second list with 2 items.
1480 * %,{VWXYZ} means to separate the args. The previous example would produce
1481 * V W1 X1 Z1 W2 X2 Z2 W3 X3 Z3 Y1 Y2, where each variable is now a
1482 * separate, space delimited, arguments within a single argument.
1483 * a%{XY}, where 'a' is a literal, still produces a single arg (a"X Y", in
1484 * shell)
1485 * a%1{XY}, where 'a' is a literal, splits the literal as it produces
1486 * multiple args (a X Y). The rule is that each sub will produce a
1487 * separate arg. Without a comma, attributes will still be grouped
1488 * together & comma separated in what could be a single argument,
1489 * but internal quotes, commas, and spaces are not excaped.
1490 *
1491 * clearing the variable oldway, passed into this function, causes the
1492 * behavior of '1' and "," in the format string to reverse.
1493 */
1494
1495 /* for convenience, use fmt as a temporary key buffer.
1496 * for speed, attempt to realloc it as little as possible
1497 */
1498 fmt = NULL;
1499 flen = 0;
1500
1501 /* buf = current argv entry being built
1502 * length = current length of buf
1503 * s = next char in source buffer to read
1504 * d = next char location to write (in buf)
1505 * inquotes = current quote char or NUL
1506 */
1507 s = format;
1508 d = buf = NULL;
1509 length = 0;
1510 doff = d - buf;
1511 expand_string (&buf, &length, doff + 1);
1512 d = buf + doff;
1513
1514 inquotes = '\0';
1515 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1516 subbedsomething = 0;
1517 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1518 while ((*d++ = *s) != '\0')
1519 {
1520 int list = 0;
1521 switch (*s++)
1522 {
1523 case '\\':
1524 /* the character after a \ goes unprocessed but leave the \ in
1525 * the string so the function that splits this string into a
1526 * command line later can deal with quotes properly
1527 *
1528 * ignore a NUL
1529 */
1530 if (*s)
1531 {
1532 doff = d - buf;
1533 expand_string (&buf, &length, doff + 1);
1534 d = buf + doff;
1535 *d++ = *s++;
1536 }
1537 break;
1538 case '\'':
1539 case '"':
1540 /* keep track of quotes so we can escape quote chars we sub in
1541 * - the API is that a quoted format string will guarantee that
1542 * it gets passed into the command as a single arg
1543 */
1544 if (!inquotes) inquotes = s[-1];
1545 else if (s[-1] == inquotes) inquotes = '\0';
1546 break;
1547 case '%':
1548 if (*s == '%')
1549 {
1550 /* "%%" is a literal "%" */
1551 s++;
1552 break;
1553 }
1554 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1555 if (oldway && subbedsomething)
1556 {
1557 /* the old method was to sub only the first format string */
1558 break;
1559 }
1560 /* initialize onearg each time we get a new format string */
1561 onearg = oldway ? 1 : 0;
1562 subbedsomething = 1;
1563 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1564 d--; /* we're going to overwrite the '%' regardless
1565 * of other factors... */
1566 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1567 /* detect '1' && ',' in the fmt string. */
1568 if (*s == '1')
1569 {
1570 onearg = 1;
1571 s++;
1572 if (!oldway)
1573 {
1574 /* FIXME - add FILE && LINE */
1575 error (0, 0,
1576 "Using deprecated info format strings. Convert your scripts to use\n"
1577 "the new argument format and remove '1's from your info file format strings.");
1578 }
1579 }
1580 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1581
1582 /* parse the format string and sub in... */
1583 if (*s == '{')
1584 {
1585 list = 1;
1586 s++;
1587 }
1588 /* q = fmt start
1589 * r = fmt end + 1
1590 */
1591 q = fmt;
1592 do
1593 {
1594 qoff = q - fmt;
1595 expand_string (&fmt, &flen, qoff + 1);
1596 q = fmt + qoff;
1597 } while ((*q = *s++) && list && *q++ != '}');
1598 /* we will always copy one character, so, whether in list mode
1599 * or not, if we just copied a '\0', then we hit the end of the
1600 * string before we should have
1601 */
1602 if (!s[-1])
1603 {
1604 /* if we copied a NUL while processing a list, fail
1605 * - we had an empty fmt string or didn't find a list
1606 * terminator ('}')
1607 */
1608 /* FIXME - this wants a file name and line number in a bad
1609 * way.
1610 */
1611 error(1, 0,
1612 "unterminated format string encountered in command spec.\n"
1613 "This error is likely to have been caused by an invalid line in a hook script\n"
1614 "spec (see taginfo, loginfo, verifymsginfo, etc. in the Cederqvist). Most\n"
1615 "likely the offending line would end with a '%%' character or contain a string\n"
1616 "beginning \"%%{\" and no closing '}' before the end of the line.");
1617 }
1618 if (list)
1619 {
1620 q[-1] = '\0';
1621 }
1622 else
1623 {
1624 /* We're not in a list, so we must have just copied a
1625 * single character. Terminate the string.
1626 */
1627 q++;
1628 qoff = q - fmt;
1629 expand_string (&fmt, &flen, qoff + 1);
1630 q = fmt + qoff;
1631 *q = '\0';
1632 }
1633 /* fmt is now a pointer to a list of fmt chars, though the list
1634 * could be a single element one
1635 */
1636 q = fmt;
1637 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1638 /* always add quotes in the deprecated onearg case - for
1639 * backwards compatibility
1640 */
1641 if (onearg)
1642 {
1643 doff = d - buf;
1644 expand_string (&buf, &length, doff + 1);
1645 d = buf + doff;
1646 *d++ = '"';
1647 }
1648 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1649 /*
1650 * for each character in the fmt string,
1651 *
1652 * all output will be separate quoted arguments (with
1653 * internal quotes escaped) if the argument is in quotes
1654 * unless the oldway variable is set, in which case the fmt
1655 * statment will correspond to a single argument with
1656 * internal space or comma delimited arguments
1657 *
1658 * see the "user format strings" section above for more info
1659 */
1660 key[0] = *q;
1661 if ((p = findnode (pflist, key)) != NULL)
1662 {
1663 b = p->data;
1664 if (b->conversion == ',')
1665 {
1666 /* process the rest of the format string as a list */
1667 struct format_cmdline_walklist_closure c;
1668 c.format = q;
1669 c.buf = &buf;
1670 c.length = &length;
1671 c.d = &d;
1672 c.quotes = inquotes;
1673 c.closure = b->closure;
1674 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1675 c.onearg = onearg;
1676 c.firstpass = 1;
1677 c.srepos = srepos;
1678 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1679 walklist(b->data, b->convproc, &c);
1680 d--; /* back up one space. we know that ^
1681 always adds 1 extra */
1682 q += strlen(q);
1683 }
1684 else
1685 {
1686 /* got a flat item */
1687 char *outstr;
1688 if (strlen(q) > 1)
1689 {
1690 error (1, 0,
1691 "Multiple non-list variables are not allowed in a single format string.");
1692 }
1693 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1694 if (onearg)
1695 {
1696 outstr = b->data;
1697 }
1698 else /* !onearg */
1699 {
1700 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1701 /* the *only* case possible without
1702 * SUPPORT_OLD_INFO_FORMAT_STRINGS
1703 * - !onearg */
1704 if (!inquotes)
1705 {
1706 doff = d - buf;
1707 expand_string (&buf, &length, doff + 1);
1708 d = buf + doff;
1709 *d++ = '"';
1710 }
1711 outstr = cmdlineescape (inquotes ? inquotes : '"', b->data);
1712 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1713 } /* onearg */
1714 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1715 doff = d - buf;
1716 expand_string (&buf, &length, doff + strlen(outstr));
1717 d = buf + doff;
1718 strncpy(d, outstr, strlen(outstr));
1719 d += strlen(outstr);
1720 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1721 if (!onearg)
1722 {
1723 free(outstr);
1724 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1725 if (!inquotes)
1726 {
1727 doff = d - buf;
1728 expand_string (&buf, &length, doff + 1);
1729 d = buf + doff;
1730 *d++ = '"';
1731 }
1732 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1733 }
1734 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1735 q++;
1736 }
1737 }
1738 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1739 else if (onearg)
1740 {
1741 /* the old standard was to ignore unknown format
1742 * characters (print the empty string), but also that
1743 * any format character meant print srepos first
1744 */
1745 q++;
1746 doff = d - buf;
1747 expand_string (&buf, &length, doff + strlen(srepos));
1748 d = buf + doff;
1749 strncpy(d, srepos, strlen(srepos));
1750 d += strlen(srepos);
1751 }
1752 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1753 else /* no key */
1754 {
1755 /* print an error message to the user
1756 * FIXME - this should have a file and line number!!! */
1757 error (1, 0,
1758 "Unknown format character in info file ('%s').\n"
1759 "Info files are the hook files, verifymsg, taginfo, commitinfo, etc.",
1760 q);
1761 }
1762 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1763 /* always add quotes in the deprecated onearg case - for
1764 * backwards compatibility
1765 */
1766 if (onearg)
1767 {
1768 doff = d - buf;
1769 expand_string (&buf, &length, doff + 1);
1770 d = buf + doff;
1771 *d++ = '"';
1772 }
1773 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1774 break;
1775 }
1776 doff = d - buf;
1777 expand_string (&buf, &length, doff + 1);
1778 d = buf + doff;
1779 } /* while (*d++ = *s) */
1780 if (fmt) free (fmt);
1781 if (inquotes)
1782 {
1783 /* FIXME - we shouldn't need this - Parse_Info should be handling
1784 * multiple lines...
1785 */
1786 error (1, 0, "unterminated quote in format string: %s", format);
1787 }
1788
1789 dellist (&pflist);
1790 return buf;
1791 }
1792
1793
1794
1795 /* Like xstrdup (), but can handle a NULL argument.
1796 */
1797 char *
Xstrdup(const char * string)1798 Xstrdup (const char *string)
1799 {
1800 if (string == NULL) return NULL;
1801 return xmemdup (string, strlen (string) + 1);
1802 }
1803
1804
1805
1806 /* Like xasprintf(), but consider all errors fatal (may never return NULL).
1807 */
1808 char *
Xasprintf(const char * format,...)1809 Xasprintf (const char *format, ...)
1810 {
1811 va_list args;
1812 char *result;
1813
1814 va_start (args, format);
1815 if (vasprintf (&result, format, args) < 0)
1816 error (1, errno, "Failed to write to string.");
1817 va_end (args);
1818
1819 return result;
1820 }
1821
1822
1823
1824 /* Like xasnprintf(), but consider all errors fatal (may never return NULL).
1825 */
1826 char *
Xasnprintf(char * resultbuf,size_t * lengthp,const char * format,...)1827 Xasnprintf (char *resultbuf, size_t *lengthp, const char *format, ...)
1828 {
1829 va_list args;
1830 char *result;
1831
1832 va_start (args, format);
1833 result = vasnprintf (resultbuf, lengthp, format, args);
1834 if (result == NULL)
1835 error (1, errno, "Failed to write to string.");
1836 va_end (args);
1837
1838 return result;
1839 }
1840
1841
1842
1843 /* Print a warning and return false if P doesn't look like a string specifying
1844 * a boolean value.
1845 *
1846 * Sets *VAL to the parsed value when it is found to be valid. *VAL will not
1847 * be altered when false is returned.
1848 *
1849 * INPUTS
1850 * infopath Where the error is reported to be from on error. This could
1851 * be, for example, the name of the file the boolean is being read
1852 * from.
1853 * option An option name being parsed, reported in traces and any error
1854 * message.
1855 * p The string to actually read the option from.
1856 * val Pointer to where to store the boolean read from P.
1857 *
1858 * OUTPUTS
1859 * val TRUE/FALSE stored, as read, when there are no errors.
1860 *
1861 * RETURNS
1862 * true If VAL was read.
1863 * false On error.
1864 */
1865 bool
readBool(const char * infopath,const char * option,const char * p,bool * val)1866 readBool (const char *infopath, const char *option, const char *p, bool *val)
1867 {
1868 TRACE (TRACE_FLOW, "readBool (%s, %s, %s)", infopath, option, p);
1869 if (!strcasecmp (p, "no") || !strcasecmp (p, "false")
1870 || !strcasecmp (p, "off") || !strcmp (p, "0"))
1871 {
1872 TRACE (TRACE_DATA, "Read %d for %s", *val, option);
1873 *val = false;
1874 return true;
1875 }
1876 else if (!strcasecmp (p, "yes") || !strcasecmp (p, "true")
1877 || !strcasecmp (p, "on") || !strcmp (p, "1"))
1878 {
1879 TRACE (TRACE_DATA, "Read %d for %s", *val, option);
1880 *val = true;
1881 return true;
1882 }
1883
1884 error (0, 0, "%s: unrecognized value `%s' for `%s'",
1885 infopath, p, option);
1886 return false;
1887 }
1888
1889
1890
1891 /*
1892 * Open a file, exiting with a message on error.
1893 *
1894 * INPUTS
1895 * name The name of the file to open.
1896 * mode Mode to open file in, as POSIX fopen().
1897 *
1898 * NOTES
1899 * If you want to handle errors, just call fopen (NAME, MODE).
1900 *
1901 * RETURNS
1902 * The new FILE pointer.
1903 */
1904 FILE *
xfopen(const char * name,const char * mode)1905 xfopen (const char *name, const char *mode)
1906 {
1907 FILE *fp;
1908
1909 if (!(fp = fopen (name, mode)))
1910 error (1, errno, "cannot open %s", name);
1911 return fp;
1912 }
1913
1914
1915
1916 /* char *
1917 * xcanonicalize_file_name (const char *path)
1918 *
1919 * Like canonicalize_file_name(), but exit on error.
1920 *
1921 * INPUTS
1922 * path The original path.
1923 *
1924 * RETURNS
1925 * The path with any symbolic links, `.'s, or `..'s, expanded.
1926 *
1927 * ERRORS
1928 * This function exits with a fatal error if it fails to read the link for
1929 * any reason.
1930 */
1931 char *
xcanonicalize_file_name(const char * path)1932 xcanonicalize_file_name (const char *path)
1933 {
1934 char *hardpath = canonicalize_file_name (path);
1935 if (!hardpath)
1936 error (1, errno, "Failed to resolve path: `%s'", path);
1937 return hardpath;
1938 }
1939
1940
1941
1942 /* Declared in main.c. */
1943 extern char *server_hostname;
1944
1945 /* Return true if OTHERHOST resolves to this host in the DNS.
1946 *
1947 * GLOBALS
1948 * server_hostname The name of this host, as determined by the call to
1949 * xgethostname() in main().
1950 *
1951 * RETURNS
1952 * true If OTHERHOST equals or resolves to HOSTNAME.
1953 * false Otherwise.
1954 */
1955 bool
isThisHost(const char * otherhost)1956 isThisHost (const char *otherhost)
1957 {
1958 char *fqdno;
1959 char *fqdns;
1960 bool retval;
1961
1962 /* As an optimization, check the literal strings before looking up
1963 * OTHERHOST in the DNS.
1964 */
1965 if (!strcasecmp (server_hostname, otherhost))
1966 return true;
1967
1968 fqdno = canon_host (otherhost);
1969 if (!fqdno)
1970 error (1, 0, "Name lookup failed for `%s': %s",
1971 otherhost, ch_strerror ());
1972 fqdns = canon_host (server_hostname);
1973 if (!fqdns)
1974 error (1, 0, "Name lookup failed for `%s': %s",
1975 server_hostname, ch_strerror ());
1976
1977 retval = !strcasecmp (fqdns, fqdno);
1978
1979 free (fqdno);
1980 free (fqdns);
1981 return retval;
1982 }
1983
1984
1985
1986 /* Return true if two paths match, resolving symlinks.
1987 */
1988 bool
isSamePath(const char * path1_in,const char * path2_in)1989 isSamePath (const char *path1_in, const char *path2_in)
1990 {
1991 char *p1, *p2;
1992 bool same;
1993
1994 if (!strcmp (path1_in, path2_in))
1995 return true;
1996
1997 /* Path didn't match, but try to resolve any links that may be
1998 * present.
1999 */
2000 if (!isdir (path1_in) || !isdir (path2_in))
2001 /* To be resolvable, paths must exist on this server. */
2002 return false;
2003
2004 p1 = xcanonicalize_file_name (path1_in);
2005 p2 = xcanonicalize_file_name (path2_in);
2006 if (strcmp (p1, p2))
2007 same = false;
2008 else
2009 same = true;
2010
2011 free (p1);
2012 free (p2);
2013 return same;
2014 }
2015