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