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