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