PageRenderTime 64ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/cvs-1.12/src/subr.c

http://github.com/davshao/dflygsocdrm
C | 2003 lines | 1392 code | 201 blank | 410 comment | 243 complexity | 9198ff74ab433f85b23248392872d4c6 MD5 | raw file
Possible License(s): AGPL-1.0, CC-BY-SA-3.0, LGPL-2.0, GPL-3.0, LGPL-2.1, LGPL-3.0, MPL-2.0-no-copyleft-exception, 0BSD, BSD-3-Clause, GPL-2.0

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file