home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume22 / cvs-berliner / part02 < prev    next >
Encoding:
Internet Message Format  |  1990-06-07  |  54.2 KB

  1. Subject:  v22i016:  Brian Berliner's concurrent RCS system, Part02/07
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 7089c83b 62cfe0ab 4e8ae20e 5169468a
  5.  
  6. Submitted-by: Brian Berliner <berliner@prisma.com>
  7. Posting-number: Volume 22, Issue 16
  8. Archive-name: cvs-berliner/part02
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 2 (of 7)."
  17. # Contents:  src/add.c src/checkin.c src/checkout.c src/cvs.h
  18. #   src/diff.c src/maketime.c src/mkmodules.c src/set_lock.c src/tag.c
  19. # Wrapped by rsalz@litchi.bbn.com on Thu May  3 16:59:01 1990
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'src/add.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'src/add.c'\"
  23. else
  24. echo shar: Extracting \"'src/add.c'\" \(6263 characters\)
  25. sed "s/^X//" >'src/add.c' <<'END_OF_FILE'
  26. X#ifndef lint
  27. Xstatic char rcsid[] = "$Id: add.c,v 1.10 89/11/19 23:40:28 berliner Exp $";
  28. X#endif !lint
  29. X
  30. X/*
  31. X *    Copyright (c) 1989, Brian Berliner
  32. X *
  33. X *    You may distribute under the terms of the GNU General Public License
  34. X *    as specified in the README file that comes with the CVS 1.0 kit.
  35. X *
  36. X * Add
  37. X *
  38. X *    Adds a file or directory to the RCS source repository.  For a file,
  39. X *    the entry is marked as "needing to be added" in the user's own
  40. X *    CVS.adm directory, and really added to the repository when it is
  41. X *    committed.  For a directory, it is added at the appropriate place
  42. X *    in the source repository and a CVS.adm directory is generated
  43. X *    within the directory.
  44. X *
  45. X *    The -m option is currently the only supported option.  Some may wish
  46. X *    to supply standard "rcs" options here, but I've found that this
  47. X *    causes more trouble than anything else.
  48. X *
  49. X *    The user files or directories must already exist.  For a directory,
  50. X *    it must not already have a CVS.adm file in it.
  51. X *
  52. X *    An "add" on a file that has been "remove"d but not committed will
  53. X *    cause the file to be resurrected.
  54. X */
  55. X
  56. X#include <sys/param.h>
  57. X#include "cvs.h"
  58. X
  59. Xadd(argc, argv)
  60. X    int argc;
  61. X    char *argv[];
  62. X{
  63. X    char tmp[MAXPATHLEN], message[MAXMESGLEN];
  64. X    register int i;
  65. X    int c, err = 0;
  66. X
  67. X    if (argc == 1 || argc == -1)
  68. X    add_usage();
  69. X    message[0] = '\0';
  70. X    optind = 1;
  71. X    while ((c = getopt(argc, argv, "m:")) != -1) {
  72. X    switch (c) {
  73. X    case 'm':
  74. X        if (strlen(optarg) >= sizeof(message)) {
  75. X        warn(0, "warning: message too long; truncated!");
  76. X        (void) strncpy(message, optarg, sizeof(message));
  77. X        message[sizeof(message) - 1] = '\0';
  78. X        } else
  79. X        (void) strcpy(message, optarg);
  80. X        break;
  81. X    case '?':
  82. X    default:
  83. X        add_usage();
  84. X        break;
  85. X    }
  86. X    }
  87. X    argc -= optind;
  88. X    argv += optind;
  89. X    Name_Repository();
  90. X    for (i = 0; i < argc; i++) {
  91. X    (void) strcpy(User, argv[i]);
  92. X    if (isdir(User)) {
  93. X        err += add_directory(User);
  94. X        continue;
  95. X    }
  96. X    (void) sprintf(Rcs, "%s/%s%s", Repository, User, RCSEXT);
  97. X    Version_TS(Rcs, Tag, User);
  98. X    if (VN_User[0] == '\0') {
  99. X        /*
  100. X         * No entry available, TS_Rcs is invalid
  101. X         */
  102. X        if (VN_Rcs[0] == '\0') {
  103. X        /*
  104. X         * There is no RCS file either
  105. X         */
  106. X        if (TS_User[0] == '\0') {
  107. X            /*
  108. X             * There is no user file either
  109. X             */
  110. X            warn(0, "nothing known about %s", User);
  111. X            err++;
  112. X        } else {
  113. X            /*
  114. X             * There is a user file, so build the entry for it
  115. X             */
  116. X            if (Build_Entry(message) != 0)
  117. X            err++;
  118. X        }
  119. X        } else {
  120. X        /*
  121. X         * There is an RCS file already, so somebody else
  122. X         * must've added it
  123. X         */
  124. X        warn(0, "%s added independently by second party", User);
  125. X        err++;
  126. X        }
  127. X    } else if (VN_User[0] == '0' && VN_User[1] == '\0') {
  128. X        /*
  129. X         * An entry for a new-born file, TS_Rcs is dummy,
  130. X         * but that is inappropriate here
  131. X         */
  132. X        warn(0, "%s has already been entered", User);
  133. X        err++;
  134. X    } else if (VN_User[0] == '-') {
  135. X        /*
  136. X         * An entry for a removed file, TS_Rcs is invalid
  137. X         */
  138. X        if (TS_User[0] == '\0') {
  139. X        /*
  140. X         * There is no user file (as it should be)
  141. X         */
  142. X        if (VN_Rcs[0] == '\0') {
  143. X            /*
  144. X             * There is no RCS file, so somebody else must've
  145. X             * removed it from under us
  146. X             */
  147. X            warn(0, "cannot resurrect %s; RCS file removed by second party",
  148. X             User);
  149. X            err++;
  150. X        } else {
  151. X            /*
  152. X             * There is an RCS file, so remove the "-" from the
  153. X             * version number and restore the file
  154. X             */
  155. X            (void) strcpy(tmp, VN_User+1);
  156. X            (void) strcpy(VN_User, tmp);
  157. X            (void) sprintf(tmp, "Resurrected %s", User);
  158. X            Register(User, VN_User, tmp);
  159. X            if (update(2, argv+i-1) == 0) {
  160. X            warn(0, "%s, version %s, resurrected", User, VN_User);
  161. X            } else {
  162. X            warn(0, "could not resurrect %s", User);
  163. X            err++;
  164. X            }
  165. X        }
  166. X        } else {
  167. X        /*
  168. X         * The user file shouldn't be there
  169. X         */
  170. X        warn(0, "%s should be removed and is still there", User);
  171. X        err++;
  172. X        }
  173. X    } else {
  174. X        /*
  175. X         * A normal entry, TS_Rcs is valid, so it must already be there
  176. X         */
  177. X        warn(0, "%s already exists, with version number %s", User, VN_User);
  178. X        err++;
  179. X    }
  180. X    }
  181. X    Entries2Files();            /* update CVS.adm/Files file */
  182. X    exit(err);
  183. X}
  184. X
  185. X/*
  186. X * The specified user file is really a directory.  So, let's make sure that
  187. X * it is created in the RCS source repository, and that the user's
  188. X * directory is updated to include a CVS.adm directory.
  189. X *
  190. X * Returns 1 on failure, 0 on success.
  191. X */
  192. Xstatic
  193. Xadd_directory(dir)
  194. X    char *dir;
  195. X{
  196. X    char cwd[MAXPATHLEN], rcsdir[MAXPATHLEN];
  197. X    char message[MAXPATHLEN+100];
  198. X
  199. X    if (index(dir, '/') != NULL) {
  200. X    warn(0, "directory %s not added; must be a direct sub-directory", dir);
  201. X    return (1);
  202. X    }
  203. X    if (strcmp(dir, CVSADM) == 0) {
  204. X    warn(0, "cannot add a '%s' directory", CVSADM);
  205. X    return (1);
  206. X    }
  207. X    if (getwd(cwd) == NULL) {
  208. X    warn(0, "cannot get working directory: %s", cwd);
  209. X    return (1);
  210. X    }
  211. X    if (chdir(dir) < 0) {
  212. X    warn(1, "cannot chdir to %s", dir);
  213. X    return (1);
  214. X    }
  215. X    if (isfile(CVSADM)) {
  216. X    warn(0, "%s/%s already exists", dir, CVSADM);
  217. X    goto out;
  218. X    }
  219. X    (void) sprintf(rcsdir, "%s/%s", Repository, dir);
  220. X    if (isfile(rcsdir) && !isdir(rcsdir)) {
  221. X    warn(0, "%s is not a directory; %s not added", rcsdir, dir);
  222. X    goto out;
  223. X    }
  224. X    (void) sprintf(message, "Directory %s added to the repository\n", rcsdir);
  225. X    if (!isdir(rcsdir)) {
  226. X    int omask;
  227. X    FILE *fptty;
  228. X    char line[MAXLINELEN];
  229. X
  230. X    fptty = open_file("/dev/tty", "r");
  231. X    printf("Add directory %s to the repository (y/n) [n] ? ", rcsdir);
  232. X    (void) fflush(stdout);
  233. X    if (fgets(line, sizeof(line), fptty) == NULL ||
  234. X        (line[0] != 'y' && line[0] != 'Y')) {
  235. X        warn(0, "directory %s not added", rcsdir);
  236. X        (void) fclose(fptty);
  237. X        goto out;
  238. X    }
  239. X    (void) fclose(fptty);
  240. X    omask = umask(2);
  241. X    if (mkdir(rcsdir, 0777) < 0) {
  242. X        warn(1, "cannot mkdir %s", rcsdir);
  243. X        (void) umask(omask);
  244. X        goto out;
  245. X    }
  246. X    (void) umask(omask);
  247. X    (void) strcpy(Llist, " - New directory"); /* for title in message */
  248. X    Update_Logfile(rcsdir, message);
  249. X    }
  250. X    Create_Admin(rcsdir, DFLT_RECORD);
  251. X    printf("%s", message);
  252. Xout:
  253. X    if (chdir(cwd) < 0)
  254. X    error(1, "cannot chdir to %s", cwd);
  255. X    return (0);
  256. X}
  257. X
  258. Xstatic
  259. Xadd_usage()
  260. X{
  261. X    (void) fprintf(stderr,
  262. X           "%s %s [-m 'message'] files...\n", progname, command);
  263. X    exit(1);
  264. X}
  265. END_OF_FILE
  266. if test 6263 -ne `wc -c <'src/add.c'`; then
  267.     echo shar: \"'src/add.c'\" unpacked with wrong size!
  268. fi
  269. # end of 'src/add.c'
  270. fi
  271. if test -f 'src/checkin.c' -a "${1}" != "-c" ; then 
  272.   echo shar: Will not clobber existing file \"'src/checkin.c'\"
  273. else
  274. echo shar: Extracting \"'src/checkin.c'\" \(4205 characters\)
  275. sed "s/^X//" >'src/checkin.c' <<'END_OF_FILE'
  276. X#ifndef lint
  277. Xstatic char rcsid[] = "$Id: checkin.c,v 1.10 89/11/19 23:19:46 berliner Exp $";
  278. X#endif !lint
  279. X
  280. X/*
  281. X *    Copyright (c) 1989, Brian Berliner
  282. X *
  283. X *    You may distribute under the terms of the GNU General Public License
  284. X *    as specified in the README file that comes with the CVS 1.0 kit.
  285. X *
  286. X * Check In
  287. X *
  288. X *    Does a very careful checkin of the file "User", and tries not
  289. X *    to spoil its modification time (to avoid needless recompilations).
  290. X *    When RCS ID keywords get expanded on checkout, however, the
  291. X *    modification time is updated and there is no good way to get
  292. X *    around this.
  293. X *
  294. X *    Returns non-zero on error.
  295. X */
  296. X
  297. X#include <sys/param.h>
  298. X#include <ctype.h>
  299. X#include "cvs.h"
  300. X
  301. XCheckin(revision, message)
  302. X    char *revision;
  303. X    char *message;
  304. X{
  305. X    FILE *fp;
  306. X    char fname[MAXPATHLEN];
  307. X    char *tag;
  308. X    int err = 0;
  309. X
  310. X    /*
  311. X     * The revision that is passed in includes the "-r" option
  312. X     * as well as a numeric revision, otherwise it is a pointer
  313. X     * to a null string.
  314. X     */
  315. X    if (revision[0] == '-')
  316. X    tag = &revision[2];
  317. X    else
  318. X    tag = revision;
  319. X    printf("Checking in %s;\n", User);
  320. X    if (!use_editor)
  321. X    printf("Log: %s\n", message);
  322. X    (void) sprintf(Rcs, "%s/%s%s", Repository, User, RCSEXT);
  323. X    (void) sprintf(fname, "%s/%s%s", CVSADM, CVSPREFIX, User);
  324. X    /*
  325. X     * Move the user file to a backup file, so as to preserve its
  326. X     * modification times, then place a copy back in the original
  327. X     * file name for the checkin and checkout.
  328. X     */
  329. X    rename_file(User, fname);
  330. X    copy_file(fname, User);
  331. X    (void) sprintf(prog, "%s/%s -f %s %s", Rcsbin, RCS_CI, revision, Rcs);
  332. X    if ((fp = popen(prog, "w")) == NULL) {
  333. X    err++;
  334. X    } else {
  335. X    (void) fprintf(fp, "%s", message);
  336. X    err = pclose(fp);
  337. X    }
  338. X    if (err == 0) {
  339. X    /*
  340. X     * The checkin succeeded, so now check the new file back out
  341. X     * and see if it matches exactly with the one we checked in.
  342. X     * If it does, just move the original user file back, thus
  343. X     * preserving the modes; otherwise, we have no recourse but
  344. X     * to leave the newly checkout file as the user file and remove
  345. X     * the old original user file.
  346. X     */
  347. X    (void) sprintf(prog, "%s/%s -q %s %s", Rcsbin, RCS_CO, revision, Rcs);
  348. X    (void) system(prog);
  349. X    xchmod(User, 1);        /* make it writable */
  350. X    if (xcmp(User, fname) == 0)
  351. X        rename_file(fname, User);
  352. X    else
  353. X        (void) unlink(fname);
  354. X    /*
  355. X     * If we want read-only files, muck the permissions here,
  356. X     * before getting the user time-stamp.
  357. X     */
  358. X    if (cvswrite == FALSE) {
  359. X        xchmod(User, 0);
  360. X    }
  361. X    Version_TS(Rcs, tag, User);
  362. X    Register(User, VN_Rcs, TS_User);
  363. X    } else {
  364. X    /*
  365. X     * The checkin failed, for some unknown reason, so we restore
  366. X     * the original user file, print an error, try to unlock the
  367. X     * (supposedly locked) RCS file, and try to restore
  368. X     * any default branches, if they applied for this file.
  369. X     */
  370. X    rename_file(fname, User);
  371. X    warn(0, "could not check in %s", User);
  372. X    (void) sprintf(prog, "%s/%s -u %s", Rcsbin, RCS, Rcs);
  373. X    if (system(prog) != 0)
  374. X        warn(0, "could not UNlock %s", Rcs);
  375. X    restore_branch();
  376. X    return (1);
  377. X    }
  378. X    if (revision[0] != '\0') {
  379. X    /*
  380. X     * When checking in a specific revision, we may have locked the
  381. X     * wrong branch, so to be sure, we do an extra unlock here
  382. X     * before returning.
  383. X     */
  384. X    (void) sprintf(prog, "%s/%s -q -u %s 2>%s", Rcsbin, RCS, Rcs, DEVNULL);
  385. X    (void) system(prog);
  386. X    }
  387. X    return (0);
  388. X}
  389. X
  390. X/*
  391. X * Called when the above checkin fails, because we may have to
  392. X * restore the default branch that existed before we attempted
  393. X * the checkin.
  394. X *
  395. X * Scan Blist for a match of the User file, and if it has a branch
  396. X * number tagged with it, do the "rcs -b" to set it back.
  397. X */
  398. Xstatic
  399. Xrestore_branch()
  400. X{
  401. X    char blist[MAXLISTLEN];
  402. X    char *cp, *user;
  403. X
  404. X    (void) strcpy(blist, Blist);
  405. X    while ((cp = index(blist, ':')) != NULL) {
  406. X    user = cp;
  407. X    /*
  408. X     * The next line is safe because we "know" that
  409. X     * Blist always starts with a space if it has entries.
  410. X     */
  411. X    while (!isspace(user[-1]))
  412. X        user--;
  413. X    *cp++ = '\0';
  414. X    if (strcmp(User, user) == 0) {
  415. X        (void) sprintf(prog, "%s/%s -q -b%s %s", Rcsbin, RCS,
  416. X               cp, Rcs);
  417. X        if (system(prog) != 0)
  418. X        warn(0, "cannot restore default branch %s for %s",
  419. X             cp, Rcs);
  420. X        return;
  421. X    }
  422. X    }
  423. X}
  424. END_OF_FILE
  425. if test 4205 -ne `wc -c <'src/checkin.c'`; then
  426.     echo shar: \"'src/checkin.c'\" unpacked with wrong size!
  427. fi
  428. # end of 'src/checkin.c'
  429. fi
  430. if test -f 'src/checkout.c' -a "${1}" != "-c" ; then 
  431.   echo shar: Will not clobber existing file \"'src/checkout.c'\"
  432. else
  433. echo shar: Extracting \"'src/checkout.c'\" \(4525 characters\)
  434. sed "s/^X//" >'src/checkout.c' <<'END_OF_FILE'
  435. X#ifndef lint
  436. Xstatic char rcsid[] = "$Id: checkout.c,v 1.19 89/11/19 23:40:30 berliner Exp $";
  437. X#endif !lint
  438. X
  439. X/*
  440. X *    Copyright (c) 1989, Brian Berliner
  441. X *
  442. X *    You may distribute under the terms of the GNU General Public License
  443. X *    as specified in the README file that comes with the CVS 1.0 kit.
  444. X *
  445. X * Create Version
  446. X *
  447. X *    "checkout" creates a "version" of an RCS repository.  This version
  448. X *    is owned totally by the user and is actually an independent
  449. X *    copy, to be dealt with as seen fit.  Once "checkout" has been called
  450. X *    in a given directory, it never needs to be called again.  The
  451. X *    user can keep up-to-date by calling "update" when he feels like it;
  452. X *    this will supply him with a merge of his own modifications
  453. X *    and the changes made in the RCS original.  See "update" for details.
  454. X *
  455. X *    "checkout" can be given a list of directories or files to be updated
  456. X *    and in the case of a directory, will recursivley create any
  457. X *    sub-directories that exist in the repository.
  458. X *
  459. X *    When the user is satisfied with his own modifications, the
  460. X *    present version can be committed by "commit"; this keeps the present
  461. X *    version in tact, usually.
  462. X *
  463. X *    The call is
  464. X *        cvs checkout [options] <module-name>...
  465. X *
  466. X *    And the options supported are:
  467. X *        -f        Forces the symbolic tag specified with
  468. X *                the -r option to match in the RCS file, else
  469. X *                the RCS file is not extracted.
  470. X *        -Q        Causes "update" to be really quiet.
  471. X *        -q        Causes "update" and tag mis-matches to
  472. X *                be quiet; "update" just doesn't print a
  473. X *                message as it chdirs down a level.
  474. X *        -c        Cat's the modules file, sorted, to stdout.
  475. X *        -n        Causes "update" to *not* run any checkout prog.
  476. X *        -l        Only updates the local directory, not recursive.
  477. X *        -p        Prunes empty directories after checking them out
  478. X *        -r tag        Checkout revision 'tag', subject to the
  479. X *                setting of the -f option.
  480. X *        -D date-string    Checkout the most recent file equal to or
  481. X *                before the specifed date.
  482. X *
  483. X *    "checkout" creates a directory ./CVS.adm, in which it keeps its
  484. X *    administration, in two files, Repository and Entries.
  485. X *    The first contains the name of the repository.  The second
  486. X *    contains one line for each registered file,
  487. X *    consisting of the version number it derives from,
  488. X *    its time stamp at derivation time and its name.  Both files
  489. X *    are normal files and can be edited by the user, if necessary (when
  490. X *    the repository is moved, e.g.)
  491. X */
  492. X
  493. X#include <sys/param.h>
  494. X#include <ndbm.h>
  495. X#include "cvs.h"
  496. X
  497. Xextern int update_prune_dirs;
  498. Xextern int update_recursive;
  499. Xextern int run_module_prog;
  500. Xextern DBM *open_module();
  501. X
  502. Xcheckout(argc, argv)
  503. X    int argc;
  504. X    char *argv[];
  505. X{
  506. X    register int i;
  507. X    int c;
  508. X    DBM *db;
  509. X    int cat = 0, err = 0;
  510. X
  511. X    if (argc == -1)
  512. X    checkout_usage();
  513. X    optind = 1;
  514. X    while ((c = getopt(argc, argv, "nflpQqcr:D:")) != -1) {
  515. X    switch (c) {
  516. X    case 'n':
  517. X        run_module_prog = 0;
  518. X        break;
  519. X    case 'Q':
  520. X        really_quiet = 1;
  521. X        /* FALL THROUGH */
  522. X    case 'q':
  523. X        quiet = 1;
  524. X        break;
  525. X    case 'l':
  526. X        update_recursive = 0;
  527. X        break;
  528. X    case 'p':
  529. X        update_prune_dirs = 1;
  530. X        break;
  531. X    case 'c':
  532. X        cat = 1;
  533. X        break;
  534. X    case 'f':
  535. X        force_tag_match = 1;
  536. X        break;
  537. X    case 'r':
  538. X        (void) strcpy(Tag, optarg);
  539. X        break;
  540. X    case 'D':
  541. X        Make_Date(optarg, Date);
  542. X        break;
  543. X    case '?':
  544. X    default:
  545. X        checkout_usage();
  546. X        break;
  547. X    }
  548. X    }
  549. X    argc -= optind;
  550. X    argv += optind;
  551. X    if ((!cat && argc == 0) || (cat && argc != 0) || (Tag[0] && Date[0]))
  552. X    checkout_usage();
  553. X    if (cat) {
  554. X    cat_module();
  555. X    exit(0);
  556. X    }
  557. X    db = open_module();
  558. X    for (i = 0; i < argc; i++)
  559. X    err += do_module(db, argv[i], CHECKOUT, "Updating");
  560. X    close_module(db);
  561. X    exit(err);
  562. X}
  563. X
  564. XBuild_Dirs_and_chdir(dir)
  565. X    char *dir;
  566. X{
  567. X    FILE *fp;
  568. X    char path[MAXPATHLEN];
  569. X    char *slash;
  570. X    char *cp;
  571. X
  572. X    (void) strcpy(path, dir);
  573. X    for (cp = path; (slash = index(cp, '/')) != NULL; cp = slash+1) {
  574. X    *slash = '\0';
  575. X    (void) mkdir(cp, 0777);
  576. X    if (chdir(cp) < 0) {
  577. X        warn(1, "cannot chdir to %s", cp);
  578. X        return (1);
  579. X    }
  580. X    if (!isfile(CVSADM)) {
  581. X        (void) sprintf(Repository, "%s/%s", CVSroot, path);
  582. X        Create_Admin(Repository, DFLT_RECORD);
  583. X        fp = open_file(CVSADM_ENTSTAT, "w+");
  584. X        (void) fclose(fp);
  585. X    }
  586. X    *slash = '/';
  587. X    }
  588. X    (void) mkdir(cp, 0777);
  589. X    if (chdir(cp) < 0) {
  590. X    warn(1, "cannot chdir to %s", cp);
  591. X    return (1);
  592. X    }
  593. X    return (0);
  594. X}
  595. X
  596. Xstatic
  597. Xcheckout_usage()
  598. X{
  599. X    (void) fprintf(stderr,
  600. X    "Usage: %s %s [-Qqlfnp] [-c] [-r tag|-D date] modules...\n",
  601. X           progname, command);
  602. X    exit(1);
  603. X}
  604. END_OF_FILE
  605. if test 4525 -ne `wc -c <'src/checkout.c'`; then
  606.     echo shar: \"'src/checkout.c'\" unpacked with wrong size!
  607. fi
  608. # end of 'src/checkout.c'
  609. fi
  610. if test -f 'src/cvs.h' -a "${1}" != "-c" ; then 
  611.   echo shar: Will not clobber existing file \"'src/cvs.h'\"
  612. else
  613. echo shar: Extracting \"'src/cvs.h'\" \(5174 characters\)
  614. sed "s/^X//" >'src/cvs.h' <<'END_OF_FILE'
  615. X/*    $Id: cvs.h,v 1.24 89/11/19 23:19:57 berliner Exp $    */
  616. X
  617. X#include <strings.h>
  618. X#include <string.h>
  619. X#include <stdio.h>
  620. X
  621. X/*
  622. X *    Copyright (c) 1989, Brian Berliner
  623. X *
  624. X *    You may distribute under the terms of the GNU General Public License
  625. X *    as specified in the README file that comes with the CVS 1.0 kit.
  626. X *
  627. X * Definitions for the CVS Administrative directory and
  628. X * the files it contains.  Here as #define's to make changing
  629. X * the names a simple task.
  630. X */
  631. X#define    CVSADM        "CVS.adm"
  632. X#define    CVSADM_ENT    "CVS.adm/Entries"
  633. X#define    CVSADM_ENTBAK    "CVS.adm/Entries.Backup"
  634. X#define    CVSADM_ENTSTAT    "CVS.adm/Entries.Static"
  635. X#define    CVSADM_FILE    "CVS.adm/Files"
  636. X#define    CVSADM_MOD    "CVS.adm/Mod"
  637. X#define    CVSADM_REP    "CVS.adm/Repository"
  638. X#define    CVSADM_CIPROG    "CVS.adm/Checkin.prog"
  639. X
  640. X/*
  641. X * Definitions for the CVSROOT Administrative directory and
  642. X * the files it contains.  This directory is created as a
  643. X * sub-directory of the $CVSROOT environment variable, and holds
  644. X * global administration information for the entire source
  645. X * repository beginning at $CVSROOT.
  646. X */
  647. X#define    CVSROOTADM        "CVSROOT.adm"
  648. X#define    CVSROOTADM_MODULES    "CVSROOT.adm/modules"
  649. X#define    CVSROOTADM_LOGINFO    "CVSROOT.adm/loginfo"
  650. X
  651. X/* support for the CVSROOTADM files */
  652. X#define    CVSMODULE_FILE    "modules" /* last component of CVSROOTADM_MODULES */
  653. X#define    CVSMODULE_TMP    ".#modules.XXXXXX"
  654. X#define    CVSMODULE_OPTS    "ai:o:t:"
  655. X#define    CVSLOGINFO_FILE    "loginfo" /* last component of CVSROOTADM_LOGINFO */
  656. X#define    CVSLOGINFO_TMP    ".#loginfo.XXXXXX"
  657. X
  658. X/* Other CVS file names */
  659. X#define    CVSATTIC    "Attic"
  660. X#define    CVSLCK        "#cvs.lock"
  661. X#define    CVSTFL        "#cvs.tfl"
  662. X#define    CVSRFL        "#cvs.rfl"
  663. X#define    CVSWFL        "#cvs.wfl"
  664. X#define    CVSEXT_OPT    ",p"
  665. X#define    CVSEXT_LOG    ",t"
  666. X#define    CVSPREFIX    ",,"
  667. X#define    CVSTEMP        "/tmp/cvslog.XXXXXX"
  668. X
  669. X/* miscellaneous CVS defines */
  670. X#define    CVSEDITPREFIX    "CVS: "
  671. X#define    CVSLCKAGE    600        /* 10-min old lock files cleaned up */
  672. X#define    CVSLCKSLEEP    15        /* wait 15 seconds before retrying */
  673. X#define    DFLT_RECORD    "/dev/null"
  674. X#define    BAKPREFIX    ".#"        /* when rcsmerge'ing */
  675. X#define    DEVNULL        "/dev/null"
  676. X
  677. X#define    FALSE        0
  678. X#define    TRUE        1
  679. X
  680. X/*
  681. X * Definitions for the RCS file names.
  682. X */
  683. X#define    RCS        "rcs"
  684. X#define    RCS_CI        "ci"
  685. X#define    RCS_CO        "co"
  686. X#define    RCS_RLOG    "rlog"
  687. X#define    RCS_DIFF    "rcsdiff"
  688. X#define    RCS_MERGE    "rcsmerge"
  689. X#define    RCS_MERGE_PAT    "^>>>>>>> "    /* runs "grep" with this pattern */
  690. X#define    RCSID_PAT    "'\\$Id.*\\$'"    /* when committing files */
  691. X#define    RCSEXT        ",v"
  692. X#define    RCSHEAD        "head "
  693. X#define    RCSBRANCH    "branch "
  694. X#define    RCSSYMBOL    "symbols "
  695. X#define    RCSDATE        "date "
  696. X#define    RCSDESC        "desc"        /* ends the search for branches */
  697. X#define    DATEFORM    "%02d.%02d.%02d.%02d.%02d.%02d"
  698. X
  699. X/* Programs that cvs runs */
  700. X#define    DIFF        "/bin/diff"
  701. X#define    GREP        "/bin/grep"
  702. X#define    RM        "/bin/rm"
  703. X#define    SORT        "/usr/bin/sort"
  704. X
  705. X/*
  706. X * Environment variable used by CVS
  707. X */
  708. X#define    CVSREAD_ENV    "CVSREAD"    /* make files read-only */
  709. X#define    CVSREAD_DFLT    FALSE        /* writable files by default */
  710. X
  711. X#define    RCSBIN_ENV    "RCSBIN"    /* RCS binary directory */
  712. X#define    RCSBIN_DFLT    "/usr/local/bin" /* directory to find RCS progs */
  713. X
  714. X#define    EDITOR_ENV    "EDITOR"    /* which editor to use */
  715. X#define    EDITOR_DFLT    "/usr/ucb/vi"    /* somewhat standard */
  716. X
  717. X#define    CVSROOT_ENV    "CVSROOT"    /* source directory root */
  718. X#define    CVSROOT_DFLT    NULL        /* No dflt; must set for checkout */
  719. X
  720. X/*
  721. X * If the beginning of the Repository matches the following string,
  722. X * strip it so that the output to the logfile does not contain a full pathname.
  723. X *
  724. X * If the CVSROOT environment variable is set, it overrides this define.
  725. X */
  726. X#define    REPOS_STRIP    "/src/master/"
  727. X
  728. X/*
  729. X * The maximum number of files per each CVS directory.
  730. X * This is mainly for sizing arrays statically rather than
  731. X * dynamically.  3000 seems plenty for now.
  732. X */
  733. X#define    MAXFILEPERDIR    3000
  734. X#define    MAXLINELEN    1000        /* max input line from a file */
  735. X#define    MAXPROGLEN    30000        /* max program length to system() */
  736. X#define    MAXLISTLEN    20000        /* For [A-Z]list holders */
  737. X#define    MAXMESGLEN    1000        /* max RCS log message size */
  738. X
  739. X/*
  740. X * The type of request that is being done in do_module() &&
  741. X * the type of request that is being done in Find_Names().
  742. X */
  743. Xenum mtype { CHECKOUT, TAG, PATCH };
  744. Xenum ftype { ALL, ALLPLUSATTIC, MOD };
  745. X
  746. Xextern char *progname, *command;
  747. Xextern char Clist[], Glist[], Mlist[], Olist[], Dlist[];
  748. Xextern char Alist[], Rlist[], Wlist[], Llist[], Blist[];
  749. Xextern char User[], Repository[], SRepository[], Rcs[];
  750. Xextern char VN_User[], VN_Rcs[], TS_User[], TS_Rcs[];
  751. Xextern char Options[], Tag[], Date[], prog[];
  752. Xextern char *Rcsbin, *Editor, *CVSroot;
  753. Xextern int really_quiet, quiet;
  754. Xextern int use_editor;
  755. Xextern int cvswrite;
  756. Xextern int force_tag_match;
  757. X
  758. Xextern int fileargc;            /* for Find_Names() */
  759. Xextern char *fileargv[];
  760. X
  761. X/*
  762. X * Externs that are included directly in the CVS sources
  763. X */
  764. Xextern FILE *open_file();
  765. Xextern char *xmalloc();
  766. Xextern int ppstrcmp();
  767. Xextern int ppstrcmp_files();
  768. Xextern void Lock_Cleanup();
  769. X
  770. X/*
  771. X * Externs that are included in libc, but are used frequently
  772. X * enough to warrant defining here.
  773. X */
  774. Xextern char *sprintf();
  775. Xextern char *optarg;            /* for getopt() support */
  776. Xextern char *getwd();
  777. Xextern char *re_comp();
  778. Xextern int optind;
  779. END_OF_FILE
  780. if test 5174 -ne `wc -c <'src/cvs.h'`; then
  781.     echo shar: \"'src/cvs.h'\" unpacked with wrong size!
  782. fi
  783. # end of 'src/cvs.h'
  784. fi
  785. if test -f 'src/diff.c' -a "${1}" != "-c" ; then 
  786.   echo shar: Will not clobber existing file \"'src/diff.c'\"
  787. else
  788. echo shar: Extracting \"'src/diff.c'\" \(4082 characters\)
  789. sed "s/^X//" >'src/diff.c' <<'END_OF_FILE'
  790. X#ifndef lint
  791. Xstatic char rcsid[] = "$Id: diff.c,v 1.12 89/11/19 23:40:34 berliner Exp $";
  792. X#endif !lint
  793. X
  794. X/*
  795. X *    Copyright (c) 1989, Brian Berliner
  796. X *
  797. X *    You may distribute under the terms of the GNU General Public License
  798. X *    as specified in the README file that comes with the CVS 1.0 kit.
  799. X *
  800. X * Difference
  801. X *
  802. X *    Run diff against versions in the repository.  Options that
  803. X *    are specified are passed on directly to "rcsdiff".
  804. X *
  805. X *    Without any file arguments, runs diff against all the
  806. X *    currently modified files, as listed in the CVS.adm/Mod file.
  807. X */
  808. X
  809. X#include <sys/param.h>
  810. X#include "cvs.h"
  811. X
  812. Xdiff(argc, argv)
  813. X    int argc;
  814. X    char *argv[];
  815. X{
  816. X    register int i;
  817. X    char rev1[50], rev2[50], tmp[MAXPATHLEN];
  818. X    char *revision;
  819. X    int c, numopt, err = 0;
  820. X
  821. X    if (argc == -1)
  822. X    diff_usage();
  823. X    Name_Repository();
  824. X    /*
  825. X     * Note that we catch all the valid arguments here, so that we
  826. X     * can intercept the -r arguments for doing revision diffs
  827. X     */
  828. X    rev1[0] = rev2[0] = '\0';
  829. X    optind = 1;
  830. X    while ((c = getopt(argc, argv, "biwtcefhnqr:")) != -1) {
  831. X    switch (c) {
  832. X    case 'b':    case 'i':    case 'w':
  833. X    case 't':    case 'c':    case 'e':
  834. X    case 'f':    case 'h':    case 'n':
  835. X    case 'q':
  836. X        /* Get_Options will take care of these */
  837. X        break;
  838. X    case 'r':
  839. X        if (rev2[0] != '\0')
  840. X        error(0, "no more than two revisions can be specified");
  841. X        if (rev1[0] != '\0') {
  842. X        (void) strcpy(rev2, optarg);
  843. X        } else {
  844. X        (void) strcpy(rev1, optarg);
  845. X        }
  846. X        *optarg = '\0';        /* strip the -r */
  847. X        break;
  848. X    case '?':
  849. X    default:
  850. X        diff_usage();
  851. X        break;
  852. X    }
  853. X    }
  854. X    numopt = Get_Options(--argc, ++argv);
  855. X    argc -= numopt;
  856. X    argv += numopt;
  857. X    if (argc == 0) {
  858. X    if (rev2[0] != '\0')
  859. X        Find_Names(&fileargc, fileargv, MOD);
  860. X    else
  861. X        Find_Names(&fileargc, fileargv, ALL);
  862. X    argc = fileargc;
  863. X    argv = fileargv;
  864. X    if (rev2[0] == '\0') {
  865. X        for (i = 0; i < fileargc; i++) {
  866. X        (void) strcpy(User, fileargv[i]);
  867. X        Locate_RCS();
  868. X        if (rev1[0] != '\0') {
  869. X            revision = rev1;
  870. X        } else {
  871. X            Version_TS(Rcs, Tag, User);
  872. X            if (VN_User[0] == '\0' || VN_User[0] == '-' ||
  873. X            (VN_User[0] == '0' && VN_User[1] == '\0')) {
  874. X            fileargv[i][0] = '\0';
  875. X            } else if (VN_Rcs[0] == '\0' || TS_User[0] == '\0' ||
  876. X                   strcmp(TS_Rcs, TS_User) == 0) {
  877. X            fileargv[i][0] = '\0';
  878. X            } else {
  879. X            revision = VN_User;
  880. X            }
  881. X        }
  882. X        if (fileargv[i][0] != '\0') {
  883. X            (void) sprintf(tmp, "%s/%s%s", CVSADM, CVSPREFIX, User);
  884. X            (void) sprintf(prog, "%s/%s -p -q -r%s %s > %s", Rcsbin,
  885. X                   RCS_CO, revision, Rcs, tmp);
  886. X            if (system(prog) == 0 && xcmp(User, tmp) == 0)
  887. X            fileargv[i][0] = '\0';
  888. X            (void) unlink(tmp);
  889. X        }
  890. X        }
  891. X    }
  892. X    }
  893. X    for (i = 0; i < argc; i++) {
  894. X    if (argv[i][0] == '\0')
  895. X        continue;
  896. X    (void) strcpy(User, argv[i]);
  897. X    Locate_RCS();
  898. X    Version_TS(Rcs, Tag, User);
  899. X    if (VN_User[0] == '\0') {
  900. X        warn(0, "I know nothing about %s", User);
  901. X        continue;
  902. X    } else if (VN_User[0] == '0' && VN_User[1] == '\0') {
  903. X        warn(0, "%s is a new entry, no comparison available",
  904. X         User);
  905. X        continue;
  906. X    } else if (VN_User[0] == '-') {
  907. X        warn(0, "%s was removed, no comparison available",
  908. X         User);
  909. X        continue;
  910. X    } else {
  911. X        if (VN_Rcs[0] == '\0') {
  912. X        warn(0, "cannot find %s", Rcs);
  913. X        continue;
  914. X        } else {
  915. X        if (TS_User[0] == '\0') {
  916. X            warn(0, "cannot find %s", User);
  917. X            continue;
  918. X        }
  919. X        }
  920. X    }
  921. X    (void) fflush(stdout);
  922. X    if (i != 0) {
  923. X        printf("===================================================================\n");
  924. X        (void) fflush(stdout);
  925. X    }
  926. X    if (rev2[0] != '\0') {
  927. X        (void) sprintf(prog, "%s/%s %s -r%s -r%s %s", Rcsbin, RCS_DIFF,
  928. X               Options, rev1, rev2, Rcs);
  929. X    } else if (rev1[0] != '\0') {
  930. X        (void) sprintf(prog, "%s/%s %s -r%s %s", Rcsbin, RCS_DIFF,
  931. X               Options, rev1, Rcs);
  932. X    } else {
  933. X        (void) sprintf(prog, "%s/%s %s -r%s %s", Rcsbin, RCS_DIFF,
  934. X               Options, VN_User, Rcs);
  935. X    }
  936. X    (void) strcat(prog, " 2>&1");
  937. X    err += system(prog);
  938. X    (void) fflush(stdout);
  939. X    }
  940. X    exit(err);
  941. X}
  942. X
  943. Xdiff_usage()
  944. X{
  945. X    (void) fprintf(stderr, "%s %s [rcsdiff-options] [files...]\n", progname,
  946. X           command);
  947. X    exit(1);
  948. X}
  949. END_OF_FILE
  950. if test 4082 -ne `wc -c <'src/diff.c'`; then
  951.     echo shar: \"'src/diff.c'\" unpacked with wrong size!
  952. fi
  953. # end of 'src/diff.c'
  954. fi
  955. if test -f 'src/maketime.c' -a "${1}" != "-c" ; then 
  956.   echo shar: Will not clobber existing file \"'src/maketime.c'\"
  957. else
  958. echo shar: Extracting \"'src/maketime.c'\" \(6735 characters\)
  959. sed "s/^X//" >'src/maketime.c' <<'END_OF_FILE'
  960. X#ifndef lint
  961. Xstatic char rcsid[] = "$Id: maketime.c,v 1.2 89/05/11 12:03:02 berliner Exp $";
  962. X#endif !lint
  963. X
  964. X/*
  965. X * MAKETIME        derive 32-bit time value from TM structure.
  966. X *
  967. X * Usage:
  968. X *    long t,maketime();
  969. X *    struct tm *tp;    Pointer to TM structure from <time.h>
  970. X *            NOTE: this must be extended version!!!
  971. X *    t = maketime(tp);
  972. X *
  973. X * Returns:
  974. X *    0 if failure; parameter out of range or nonsensical.
  975. X *    else long time-value.
  976. X * Notes:
  977. X *    This code is quasi-public; it may be used freely in like software.
  978. X *    It is not to be sold, nor used in licensed software without
  979. X *    permission of the author.
  980. X *    For everyone's benefit, please report bugs and improvements!
  981. X *     Copyright 1981 by Ken Harrenstien, SRI International.
  982. X *    (ARPANET: KLH @ SRI)
  983. X */
  984. X
  985. X#include "cvs.h"
  986. X#include "rcstime.h"
  987. X
  988. Xint daytb[] = {   /* # days in year thus far, indexed by month (0-12!!) */
  989. X    0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
  990. X};
  991. X
  992. Xstruct tm *localtime();
  993. Xlong    time();
  994. X
  995. Xlong maketime(atm)
  996. Xstruct tm *atm;
  997. X{    register struct tm *tp;
  998. X    register int i;
  999. X    int year, yday, mon, day, hour, min, sec, zone, dst, leap;
  1000. X    long tres, curtim;
  1001. X
  1002. X    (void) time(&curtim);
  1003. X    tp = localtime(&curtim);        /* Get breakdowns of current time */
  1004. X    year = tp->tm_year;        /* Use to set up defaults */
  1005. X    mon = tp->tm_mon;
  1006. X    day = tp->tm_mday;
  1007. X
  1008. X
  1009. X#ifdef DEBUG
  1010. Xprintf("first YMD: %d %d %d, T=%ld\n",year,mon,day,tres);
  1011. X#endif DEBUG
  1012. X    tp = atm;
  1013. X
  1014. X    /* First must find date, using specified year, month, day.
  1015. X     * If one of these is unspecified, it defaults either to the
  1016. X     * current date (if no more global spec was given) or to the
  1017. X     * zero-value for that spec (i.e. a more global spec was seen).
  1018. X     * Start with year... note 32 bits can only handle 135 years.
  1019. X     */
  1020. X    if(tp->tm_year != TMNULL)
  1021. X      {    if((year = tp->tm_year) >= 1900)    /* Allow full yr # */
  1022. X              year -= 1900;            /* by making kosher */
  1023. X        mon = 0;        /* Since year was given, default */
  1024. X        day = 1;        /* for remaining specs is zero */
  1025. X      }
  1026. X    if(year < 70 || 70+134 < year )    /* Check range */
  1027. X        return(0);        /* ERR: year out of range */
  1028. X    leap = year&03 ? 0 : 1;        /* See if leap year */
  1029. X    year -= 70;            /* UNIX time starts at 1970 */
  1030. X
  1031. X    /*
  1032. X     * Find day of year.
  1033. X     * YDAY is used only if it exists and either the month or day-of-month
  1034. X     * is missing.
  1035. X     */
  1036. X    if (tp->tm_yday != TMNULL
  1037. X     && (tp->tm_mon == TMNULL || tp->tm_mday == TMNULL))
  1038. X        yday = tp->tm_yday;
  1039. X    else
  1040. X      {    if(tp->tm_mon  != TMNULL)
  1041. X          {    mon = tp->tm_mon;    /* Month was specified */
  1042. X            day = 1;        /* so set remaining default */
  1043. X          }
  1044. X        if(mon < 0 || 11 < mon) return(0);    /* ERR: bad month */
  1045. X        if(tp->tm_mday != TMNULL) day = tp->tm_mday;
  1046. X        if(day < 1
  1047. X         || (((daytb[mon+1]-daytb[mon]) < day)
  1048. X            && (day!=29 || mon!=1 || !leap) ))
  1049. X                return(0);        /* ERR: bad day */
  1050. X        yday = daytb[mon]    /* Add # of days in months so far */
  1051. X          + ((leap        /* Leap year, and past Feb?  If */
  1052. X              && mon>1)? 1:0)    /* so, add leap day for this year */
  1053. X          + day-1;        /* And finally add # days this mon */
  1054. X
  1055. X                if (tp->tm_yday != TMNULL       /* Confirm that YDAY correct */
  1056. X                 && tp->tm_yday != yday) return(0);     /* ERR: conflict */
  1057. X      }
  1058. X    if(yday < 0 || (leap?366:365) <= yday)
  1059. X        return(0);        /* ERR: bad YDAY or maketime bug */
  1060. X
  1061. X    tres = year*365            /* Get # days of years so far */
  1062. X        + ((year+1)>>2)        /* plus # of leap days since 1970 */
  1063. X        + yday;            /* and finally add # days this year */
  1064. X
  1065. X        if((i = tp->tm_wday) != TMNULL) /* Check WDAY if present */
  1066. X                if(i < 0 || 6 < i       /* Ensure within range */
  1067. X                  || i != (tres+4)%7)   /* Matches? Jan 1,1970 was Thu = 4 */
  1068. X                        return(0);      /* ERR: bad WDAY */
  1069. X
  1070. X#ifdef DEBUG
  1071. Xprintf("YMD: %d %d %d, T=%ld\n",year,mon,day,tres);
  1072. X#endif DEBUG
  1073. X    /*
  1074. X     * Now determine time.  If not given, default to zeros
  1075. X     * (since time is always the least global spec)
  1076. X     */
  1077. X    tres *= 86400L;            /* Get # seconds (24*60*60) */
  1078. X    hour = min = sec = 0;
  1079. X    if(tp->tm_hour != TMNULL) hour = tp->tm_hour;
  1080. X    if(tp->tm_min  != TMNULL) min  = tp->tm_min;
  1081. X    if(tp->tm_sec  != TMNULL) sec  = tp->tm_sec;
  1082. X    if( min < 0 || 60 <= min
  1083. X     || sec < 0 || 60 <= sec) return(0);    /* ERR: MS out of range */
  1084. X    if(hour < 0 || 24 <= hour)
  1085. X        if(hour != 24 || (min+sec) !=0)    /* Allow 24:00 */
  1086. X            return(0);        /* ERR: H out of range */
  1087. X
  1088. X    /* confirm AM/PM if there */
  1089. X    switch(tp->tm_ampm)
  1090. X      {    case 0: case TMNULL:    /* Ignore these values */
  1091. X            break;
  1092. X        case 1:            /* AM */
  1093. X        case 2:            /* PM */
  1094. X            if(hour > 12) return(0);  /* ERR: hrs 13-23 bad */
  1095. X            if(hour ==12) hour = 0;    /* Modulo 12 */
  1096. X            if(tp->tm_ampm == 2)    /* If PM, then */
  1097. X                hour += 12;    /*   get 24-hour time */
  1098. X            break;
  1099. X        default: return(0);    /* ERR: illegal TM_AMPM value */
  1100. X      }
  1101. X
  1102. X    tres += sec + 60L*(min + 60L*hour);    /* Add in # secs of time */
  1103. X
  1104. X#ifdef DEBUG
  1105. Xprintf("HMS: %d %d %d T=%ld\n",hour,min,sec,tres);
  1106. X#endif DEBUG
  1107. X    /*
  1108. X     * We now have the GMT date/time and must make final
  1109. X     * adjustment for the specified time zone.  If none is specified,
  1110. X     * the local time-zone is assumed.
  1111. X     */
  1112. X    if((zone = tp->tm_zon) == TMNULL    /* If unspecified */
  1113. X     || (zone == 1))            /* or local-zone requested */
  1114. X        zone = localzone();        /* then set to local zone */
  1115. X    if(zone < 0 || 24*60 <= zone)
  1116. X        return(0);            /* ERR: zone out of range */
  1117. X
  1118. X    /* See if must apply Daylight Saving Time shift.
  1119. X     * Note that if DST is specified, validity is not checked.
  1120. X     */
  1121. X    if((dst = tp->tm_isdst) == TMNULL)    /* Must we figure it out? */
  1122. X      {    curtim = tres +localzone()*60L;    /* Yuck.  Get equiv local */
  1123. X        dst = localtime(&curtim)->tm_isdst;     /* time, and ask. */
  1124. X      }
  1125. X    tres += zone*60L -(dst?3600:0);    /* Add in # seconds of zone adj */
  1126. X
  1127. X    return(tres);
  1128. X}
  1129. X
  1130. X
  1131. X/* LOCALZONE        return local timezone in # mins west of GMT
  1132. X *
  1133. X */
  1134. X
  1135. X#ifdef V6
  1136. Xextern long timezone;
  1137. X#else
  1138. X#ifdef USG
  1139. Xextern long timezone;
  1140. X#else /* V7 */
  1141. X#include <sys/types.h>
  1142. X#include <sys/timeb.h>
  1143. X#endif USG
  1144. X#endif V6
  1145. X
  1146. Xint _lclzon = -1;
  1147. Xlocalzone()
  1148. X{
  1149. X#ifdef V6
  1150. X    return(_lclzon >= 0 ? _lclzon : (_lclzon = timezone/60L));
  1151. X#else
  1152. X#ifdef USG
  1153. X    tzset();
  1154. X    return(_lclzon >= 0 ? _lclzon : (_lclzon = timezone/60L));
  1155. X#else /* V7 */
  1156. X    struct timeb tb;
  1157. X
  1158. X    if(_lclzon < 0)
  1159. X      {    ftime(&tb);
  1160. X        _lclzon = tb.timezone;
  1161. X      }
  1162. X    return(_lclzon);
  1163. X
  1164. X#endif USG
  1165. X#endif V6
  1166. X}
  1167. X
  1168. XMake_Date(rawdate, date)
  1169. X    char *rawdate;
  1170. X    char *date;
  1171. X{
  1172. X    extern int force_tag_match;
  1173. X    struct tm parseddate, *ftm;
  1174. X    long unixtime;
  1175. X
  1176. X    /*
  1177. X     * Dates must "match", else the file is ignored
  1178. X     */
  1179. X    force_tag_match = 1;
  1180. X    if (partime(rawdate, &parseddate) == 0)
  1181. X    error(0, "Can't parse date/time: %s", rawdate);
  1182. X    if ((unixtime = maketime(&parseddate)) == 0L)
  1183. X    error(0, "Inconsistent date/time: %s", rawdate);
  1184. X    ftm = localtime(&unixtime);
  1185. X    (void) sprintf(date, DATEFORM, ftm->tm_year, ftm->tm_mon+1,
  1186. X         ftm->tm_mday, ftm->tm_hour, ftm->tm_min, ftm->tm_sec);
  1187. X}
  1188. END_OF_FILE
  1189. if test 6735 -ne `wc -c <'src/maketime.c'`; then
  1190.     echo shar: \"'src/maketime.c'\" unpacked with wrong size!
  1191. fi
  1192. # end of 'src/maketime.c'
  1193. fi
  1194. if test -f 'src/mkmodules.c' -a "${1}" != "-c" ; then 
  1195.   echo shar: Will not clobber existing file \"'src/mkmodules.c'\"
  1196. else
  1197. echo shar: Extracting \"'src/mkmodules.c'\" \(5871 characters\)
  1198. sed "s/^X//" >'src/mkmodules.c' <<'END_OF_FILE'
  1199. X#ifndef lint
  1200. Xstatic char rcsid[] = "$Id: mkmodules.c,v 1.9 89/11/19 23:20:10 berliner Exp $";
  1201. X#endif !lint
  1202. X
  1203. X/*
  1204. X *    Copyright (c) 1989, Brian Berliner
  1205. X *
  1206. X *    You may distribute under the terms of the GNU General Public License
  1207. X *    as specified in the README file that comes with the CVS 1.0 kit.
  1208. X *
  1209. X * mkmodules
  1210. X *
  1211. X *    Re-build the modules database for the CVS system.  Accepts one
  1212. X *    argument, which is the directory that the modules,v file lives in.
  1213. X */
  1214. X
  1215. X#include <sys/param.h>
  1216. X#include <fcntl.h>
  1217. X#include <signal.h>
  1218. X#include <ndbm.h>
  1219. X#include <ctype.h>
  1220. X#include "cvs.h"
  1221. X
  1222. Xchar *progname;
  1223. X
  1224. Xchar prog[MAXPROGLEN];
  1225. Xchar *Rcsbin = RCSBIN_DFLT;
  1226. X
  1227. Xmain(argc, argv)
  1228. X    int argc;
  1229. X    char *argv[];
  1230. X{
  1231. X    extern char *getenv();
  1232. X    char temp[50];
  1233. X    char *cp;
  1234. X
  1235. X    /*
  1236. X     * Just save the last component of the path for error messages
  1237. X     */
  1238. X    if ((progname = rindex(argv[0], '/')) == NULL)
  1239. X    progname = argv[0];
  1240. X    else
  1241. X    progname++;
  1242. X
  1243. X    if (argc != 2)
  1244. X    mkmodules_usage();
  1245. X    
  1246. X    if ((cp = getenv(RCSBIN_ENV)) != NULL)
  1247. X    Rcsbin = cp;
  1248. X
  1249. X    if (chdir(argv[1]) < 0)
  1250. X    error(1, "cannot chdir to %s", argv[1]);
  1251. X    /*
  1252. X     * First, do the work necessary to update the "modules" database.
  1253. X     */
  1254. X    make_tempfile(CVSMODULE_TMP, temp);
  1255. X    if (checkout_file(CVSMODULE_FILE, temp) == 0) {
  1256. X    write_dbmfile(temp);
  1257. X    rename_dbmfile(temp);
  1258. X    }
  1259. X    (void) unlink(temp);
  1260. X    /*
  1261. X     * Now, check out the "loginfo" file, so that it is always up-to-date
  1262. X     * in the CVSROOT.adm directory.
  1263. X     */
  1264. X    make_tempfile(CVSLOGINFO_TMP, temp);
  1265. X    if (checkout_file(CVSLOGINFO_FILE, temp) == 0)
  1266. X    rename_loginfo(temp);
  1267. X    (void) unlink(temp);
  1268. X    exit(0);
  1269. X}
  1270. X
  1271. Xstatic
  1272. Xmake_tempfile(file, temp)
  1273. X    char *file;
  1274. X    char *temp;
  1275. X{
  1276. X    int fd;
  1277. X
  1278. X    (void) strcpy(temp, file);
  1279. X    if ((fd = mkstemp(temp)) < 0)
  1280. X    error(1, "cannot create temporary file %s", temp);
  1281. X    (void) close(fd);
  1282. X}
  1283. X
  1284. Xstatic
  1285. Xcheckout_file(file, temp)
  1286. X    char *file;
  1287. X    char *temp;
  1288. X{
  1289. X    (void) sprintf(prog, "%s/%s -q -p %s > %s", Rcsbin, RCS_CO, file, temp);
  1290. X    if (system(prog) != 0) {
  1291. X    warn(0, "failed to check out %s file", file);
  1292. X    return (1);
  1293. X    }
  1294. X    return (0);
  1295. X}
  1296. X
  1297. Xstatic
  1298. Xwrite_dbmfile(temp)
  1299. X    char *temp;
  1300. X{
  1301. X    char line[DBLKSIZ], value[DBLKSIZ];
  1302. X    FILE *fp;
  1303. X    DBM *db;
  1304. X    char *cp, *vp;
  1305. X    datum key, val;
  1306. X    int len, cont, err = 0;
  1307. X
  1308. X    fp = open_file(temp, "r");
  1309. X    if ((db = dbm_open(temp, O_RDWR|O_CREAT|O_TRUNC, 0666)) == NULL)
  1310. X    error(1, "cannot open dbm file %s for creation", temp);
  1311. X    for (cont = 0; fgets(line, sizeof(line), fp) != NULL; ) {
  1312. X    if ((cp = rindex(line, '\n')) != NULL)
  1313. X        *cp = '\0';            /* strip the newline */
  1314. X    /*
  1315. X     * Add the line to the value, at the end if this is a continuation
  1316. X     * line; otherwise at the beginning, but only after any trailing
  1317. X     * backslash is removed.
  1318. X     */
  1319. X    vp = value;
  1320. X    if (cont)
  1321. X        vp += strlen(value);
  1322. X    /*
  1323. X     * See if the line we read is a continuation line, and strip the
  1324. X     * backslash if so.
  1325. X     */
  1326. X    len = strlen(line);
  1327. X    if (len > 0)
  1328. X        cp = &line[len-1];
  1329. X    else
  1330. X        cp = line;
  1331. X    if (*cp == '\\') {
  1332. X        cont = 1;
  1333. X        *cp = '\0';
  1334. X    } else {
  1335. X        cont = 0;
  1336. X    }
  1337. X    (void) strcpy(vp, line);
  1338. X    if (value[0] == '#')
  1339. X        continue;            /* comment line */
  1340. X    vp = value;
  1341. X    while (*vp && isspace(*vp))
  1342. X        vp++;
  1343. X    if (*vp == '\0')
  1344. X        continue;            /* empty line */
  1345. X    /*
  1346. X     * If this was not a continuation line, add the entry to the database
  1347. X     */
  1348. X    if (!cont) {
  1349. X        key.dptr = vp;
  1350. X        while (*vp && !isspace(*vp))
  1351. X        vp++;
  1352. X        key.dsize = vp - key.dptr;
  1353. X        *vp++ = '\0';        /* NULL terminate the key */
  1354. X        while (*vp && isspace(*vp))
  1355. X        vp++;            /* skip whitespace to value */
  1356. X        if (*vp == '\0') {
  1357. X        warn(0, "warning: NULL value for key '%s'", key.dptr);
  1358. X        continue;
  1359. X        }
  1360. X        val.dptr = vp;
  1361. X        val.dsize = strlen(vp);
  1362. X        if (dbm_store(db, key, val, DBM_INSERT) == 1) {
  1363. X        warn(0, "duplicate key found for '%s'", key.dptr);
  1364. X        err++;
  1365. X        }
  1366. X    }
  1367. X    }
  1368. X    dbm_close(db);
  1369. X    (void) fclose(fp);
  1370. X    (void) unlink(temp);
  1371. X    if (err) {
  1372. X    char dotdir[50], dotpag[50];
  1373. X
  1374. X    (void) sprintf(dotdir, "%s.dir", temp);
  1375. X    (void) sprintf(dotpag, "%s.pag", temp);
  1376. X    (void) unlink(dotdir);
  1377. X    (void) unlink(dotpag);
  1378. X    error(0, "DBM creation failed; correct above errors");
  1379. X    }
  1380. X}
  1381. X
  1382. Xstatic
  1383. Xrename_dbmfile(temp)
  1384. X    char *temp;
  1385. X{
  1386. X    char newdir[50], newpag[50];
  1387. X    char dotdir[50], dotpag[50];
  1388. X    char bakdir[50], bakpag[50];
  1389. X
  1390. X    (void) signal(SIGHUP, SIG_IGN);    /* don't mess with me... */
  1391. X    (void) signal(SIGINT, SIG_IGN);
  1392. X    (void) signal(SIGQUIT, SIG_IGN);
  1393. X    (void) signal(SIGTERM, SIG_IGN);
  1394. X
  1395. X    (void) sprintf(dotdir, "%s.dir", CVSMODULE_FILE);
  1396. X    (void) sprintf(dotpag, "%s.pag", CVSMODULE_FILE);
  1397. X    (void) sprintf(bakdir, "%s%s.dir", BAKPREFIX, CVSMODULE_FILE);
  1398. X    (void) sprintf(bakpag, "%s%s.pag", BAKPREFIX, CVSMODULE_FILE);
  1399. X    (void) sprintf(newdir, "%s.dir", temp);
  1400. X    (void) sprintf(newpag, "%s.pag", temp);
  1401. X
  1402. X    (void) chmod(newdir, 0666);
  1403. X    (void) chmod(newpag, 0666);
  1404. X
  1405. X    (void) unlink(bakdir);        /* rm .#modules.dir .#modules.pag */
  1406. X    (void) unlink(bakpag);
  1407. X    (void) rename(dotdir, bakdir);    /* mv modules.dir .#modules.dir */
  1408. X    (void) rename(dotpag, bakpag);    /* mv modules.pag .#modules.pag */
  1409. X    (void) rename(newdir, dotdir);    /* mv "temp".dir modules.dir */
  1410. X    (void) rename(newpag, dotpag);    /* mv "temp".pag modules.pag */
  1411. X}
  1412. X
  1413. Xstatic
  1414. Xrename_loginfo(temp)
  1415. X    char *temp;
  1416. X{
  1417. X    char bak[50];
  1418. X
  1419. X    if (chmod(temp, 0666) < 0)            /* chmod 666 "temp" */
  1420. X    warn(1, "warning: cannot chmod %s", temp);
  1421. X    (void) sprintf(bak, "%s%s", BAKPREFIX, CVSLOGINFO_FILE);
  1422. X    (void) unlink(bak);                /* rm .#loginfo */
  1423. X    (void) rename(CVSLOGINFO_FILE, bak);    /* mv loginfo .#loginfo */
  1424. X    (void) rename(temp, CVSLOGINFO_FILE);    /* mv "temp" loginfo */
  1425. X}
  1426. X
  1427. X/*
  1428. X * For error() only
  1429. X */
  1430. Xvoid
  1431. XLock_Cleanup(sig)
  1432. X{
  1433. X#ifdef lint
  1434. X    sig = sig;
  1435. X#endif lint
  1436. X}
  1437. X
  1438. Xstatic
  1439. Xmkmodules_usage()
  1440. X{
  1441. X    (void) fprintf(stderr, "Usage: %s modules-directory\n", progname);
  1442. X    exit(1);
  1443. X}
  1444. END_OF_FILE
  1445. if test 5871 -ne `wc -c <'src/mkmodules.c'`; then
  1446.     echo shar: \"'src/mkmodules.c'\" unpacked with wrong size!
  1447. fi
  1448. # end of 'src/mkmodules.c'
  1449. fi
  1450. if test -f 'src/set_lock.c' -a "${1}" != "-c" ; then 
  1451.   echo shar: Will not clobber existing file \"'src/set_lock.c'\"
  1452. else
  1453. echo shar: Extracting \"'src/set_lock.c'\" \(6263 characters\)
  1454. sed "s/^X//" >'src/set_lock.c' <<'END_OF_FILE'
  1455. X#ifndef lint
  1456. Xstatic char rcsid[] = "$Id: set_lock.c,v 1.8 89/11/19 23:20:26 berliner Exp $";
  1457. X#endif !lint
  1458. X
  1459. X/*
  1460. X *    Copyright (c) 1989, Brian Berliner
  1461. X *
  1462. X *    You may distribute under the terms of the GNU General Public License
  1463. X *    as specified in the README file that comes with the CVS 1.0 kit.
  1464. X *
  1465. X * Set Lock
  1466. X *
  1467. X * Lock file support for CVS.  Currently, only "update" and "commit"
  1468. X * (and by extension, "checkout") adhere to this locking protocol.
  1469. X * Maybe some day, others will too.
  1470. X */
  1471. X
  1472. X#include <sys/param.h>
  1473. X#include <sys/types.h>
  1474. X#include <sys/stat.h>
  1475. X#include <signal.h>
  1476. X#include <dirent.h>
  1477. X#include "cvs.h"
  1478. X
  1479. Xstatic char lckdir[MAXPATHLEN], lckrfl[MAXPATHLEN], lckwfl[MAXPATHLEN];
  1480. X
  1481. X/*
  1482. X * Remove the lock files (without complaining if they are not there),
  1483. X * and do a quick check to see if the Entries file is missing, but
  1484. X * the Entries.Backup file is there.
  1485. X */
  1486. Xvoid
  1487. XLock_Cleanup(sig)
  1488. X    int sig;
  1489. X{
  1490. X    struct stat sb;
  1491. X
  1492. X    if (lckrfl[0] != '\0')
  1493. X    (void) unlink(lckrfl);
  1494. X    if (lckwfl[0] != '\0')
  1495. X    (void) unlink(lckwfl);
  1496. X    if (lckdir[0] != '\0') {
  1497. X    /*
  1498. X     * Only remove the lock directory if it is ours, note that this does
  1499. X     * lead to the limitation that one user ID should not be committing
  1500. X     * files into the same Repository directory at the same time.
  1501. X     * Oh well.
  1502. X     */
  1503. X    if (stat(lckdir, &sb) != -1 && sb.st_uid == geteuid())
  1504. X        (void) rmdir(lckdir);
  1505. X    }
  1506. X    if (!isfile(CVSADM_ENT) && isfile(CVSADM_ENTBAK)) {
  1507. X    warn(0, "warning: restoring %s to %s", CVSADM_ENTBAK, CVSADM_ENT);
  1508. X    rename_file(CVSADM_ENTBAK, CVSADM_ENT);
  1509. X    }
  1510. X    if (sig != 0)
  1511. X    exit(1);
  1512. X}
  1513. X
  1514. X/*
  1515. X * Create a lock file for readers (like "update" is)
  1516. X */
  1517. XReader_Lock()
  1518. X{
  1519. X    extern char *ctime();
  1520. X    extern time_t time();
  1521. X    char *cp;
  1522. X    time_t now;
  1523. X    FILE *fp;
  1524. X
  1525. X    (void) sprintf(lckdir, "%s/%s", Repository, CVSLCK);
  1526. X    (void) sprintf(lckrfl, "%s/%s.%d", Repository, CVSTFL, getpid());
  1527. X    (void) signal(SIGHUP, Lock_Cleanup);
  1528. X    (void) signal(SIGINT, Lock_Cleanup);
  1529. X    (void) signal(SIGQUIT, Lock_Cleanup);
  1530. X    (void) signal(SIGTERM, Lock_Cleanup);
  1531. X    if ((fp = fopen(lckrfl, "w+")) != NULL) {
  1532. X    (void) fclose(fp);
  1533. X    (void) unlink(lckrfl);
  1534. X    set_lock(lckdir);
  1535. X    (void) sprintf(lckrfl, "%s/%s.%d", Repository, CVSRFL, getpid());
  1536. X    if ((fp = fopen(lckrfl, "w+")) == NULL)
  1537. X        warn(1, "cannot create read lock file %s", lckrfl);
  1538. X    else
  1539. X        (void) fclose(fp);
  1540. X    if (rmdir(lckdir) < 0)
  1541. X        warn(1, "failed to remove lock dir %s", lckdir);
  1542. X    } else {
  1543. X    while (isfile(lckdir)) {
  1544. X        struct stat sb;
  1545. X
  1546. X        (void) time(&now);
  1547. X        /*
  1548. X         * If the create time of the directory is more than CVSLCKAGE
  1549. X         * seconds ago, try to clean-up the lock directory, and if
  1550. X         * successful, we are (somewhat) free and clear.
  1551. X         */
  1552. X        if (stat(lckdir, &sb) != -1 && now >= (sb.st_ctime + CVSLCKAGE)) {
  1553. X        if (rmdir(lckdir) != -1)
  1554. X            break;
  1555. X        }
  1556. X        cp = ctime(&now);
  1557. X        warn(0, "%s: waiting for the lock directory to go away", cp);
  1558. X        sleep(CVSLCKSLEEP);
  1559. X    }
  1560. X    }
  1561. X}
  1562. X
  1563. X/*
  1564. X * Create a lock file for writers (like "commit" is)
  1565. X */
  1566. XWriter_Lock()
  1567. X{
  1568. X    FILE *fp;
  1569. X
  1570. X    (void) sprintf(lckdir, "%s/%s", Repository, CVSLCK);
  1571. X    (void) sprintf(lckrfl, "%s/%s.%d", Repository, CVSTFL, getpid());
  1572. X    (void) sprintf(lckwfl, "%s/%s.%d", Repository, CVSWFL, getpid());
  1573. X    (void) signal(SIGHUP, Lock_Cleanup);
  1574. X    (void) signal(SIGINT, Lock_Cleanup);
  1575. X    (void) signal(SIGQUIT, Lock_Cleanup);
  1576. X    (void) signal(SIGTERM, Lock_Cleanup);
  1577. X    if ((fp = fopen(lckrfl, "w+")) == NULL)
  1578. X    error(1, "you have no write permission in %s", Repository);
  1579. X    (void) fclose(fp);
  1580. X    (void) unlink(lckrfl);
  1581. X    (void) sprintf(lckrfl, "%s/%s.%d", Repository, CVSRFL, getpid());
  1582. X    set_lock(lckdir);
  1583. X    if ((fp = fopen(lckwfl, "w+")) == NULL)
  1584. X    warn(1, "cannot create write lock file %s", lckwfl);
  1585. X    else
  1586. X    (void) fclose(fp);
  1587. X    while (readers_exist()) {
  1588. X    extern char *ctime();
  1589. X    extern time_t time();
  1590. X    char *cp;
  1591. X    time_t now;
  1592. X
  1593. X    (void) time(&now);
  1594. X    cp = ctime(&now);
  1595. X    cp[24] = ' ';
  1596. X    warn(0, "%s: waiting for readers to go away", cp);
  1597. X    sleep(CVSLCKSLEEP);
  1598. X    }
  1599. X}
  1600. X
  1601. X/*
  1602. X * readers_exist() returns 0 if there are no reader lock files
  1603. X * remaining in the repository; else 1 is returned, to indicate that the
  1604. X * caller should sleep a while and try again.
  1605. X */
  1606. Xstatic
  1607. Xreaders_exist()
  1608. X{
  1609. X    char line[MAXLINELEN];
  1610. X    DIR *dirp;
  1611. X    struct dirent *dp;
  1612. X    char *cp;
  1613. X    int ret = 0;
  1614. X
  1615. Xagain:
  1616. X    if ((dirp = opendir(Repository)) == NULL)
  1617. X    error(0, "cannot open directory %s", Repository);
  1618. X    (void) sprintf(line, "^%s.*", CVSRFL);
  1619. X    if ((cp = re_comp(line)) != NULL)
  1620. X    error(0, "%s", cp);
  1621. X    while ((dp = readdir(dirp)) != NULL) {
  1622. X    if (re_exec(dp->d_name)) {
  1623. X        struct stat sb;
  1624. X        long now;
  1625. X
  1626. X        (void) time(&now);
  1627. X        /*
  1628. X         * If the create time of the file is more than CVSLCKAGE
  1629. X         * seconds ago, try to clean-up the lock file, and if
  1630. X         * successful, re-open the directory and try again.
  1631. X         */
  1632. X        (void) sprintf(line, "%s/%s", Repository, dp->d_name);
  1633. X        if (stat(line, &sb) != -1 && now >= (sb.st_ctime + CVSLCKAGE)) {
  1634. X        if (unlink(line) != -1) {
  1635. X            (void) closedir(dirp);
  1636. X            goto again;
  1637. X        }
  1638. X        }
  1639. X        ret = 1;
  1640. X        break;
  1641. X    }
  1642. X    }
  1643. X    (void) closedir(dirp);
  1644. X    return (ret);
  1645. X}
  1646. X
  1647. X/*
  1648. X * Persistently tries to make the directory "lckdir",, which serves as a lock.
  1649. X * If the create time on the directory is greater than CVSLCKAGE seconds
  1650. X * old, just try to remove the directory.
  1651. X */
  1652. Xstatic
  1653. Xset_lock(lckdir)
  1654. X    char *lckdir;
  1655. X{
  1656. X    extern char *ctime();
  1657. X    extern time_t time();
  1658. X    struct stat sb;
  1659. X    char *cp;
  1660. X    time_t now;
  1661. X
  1662. X    /*
  1663. X     * Note that it is up to the callers of Set_Lock() to
  1664. X     * arrange for signal handlers that do the appropriate things,
  1665. X     * like remove the lock directory before they exit.
  1666. X     */
  1667. X    for (;;) {
  1668. X    if (mkdir(lckdir, 0777) < 0) {
  1669. X        (void) time(&now);
  1670. X        /*
  1671. X         * If the create time of the directory is more than CVSLCKAGE
  1672. X         * seconds ago, try to clean-up the lock directory, and if
  1673. X         * successful, just quietly retry to make it.
  1674. X         */
  1675. X        if (stat(lckdir, &sb) != -1 && now >= (sb.st_ctime + CVSLCKAGE)) {
  1676. X        if (rmdir(lckdir) != -1)
  1677. X            continue;
  1678. X        }
  1679. X        cp = ctime(&now);
  1680. X        cp[24] = ' ';
  1681. X        warn(0, "%s: waiting for the lock to go away", cp);
  1682. X        sleep(CVSLCKSLEEP);
  1683. X    } else {
  1684. X        break;
  1685. X    }
  1686. X    }
  1687. X}
  1688. X
  1689. END_OF_FILE
  1690. if test 6263 -ne `wc -c <'src/set_lock.c'`; then
  1691.     echo shar: \"'src/set_lock.c'\" unpacked with wrong size!
  1692. fi
  1693. # end of 'src/set_lock.c'
  1694. fi
  1695. if test -f 'src/tag.c' -a "${1}" != "-c" ; then 
  1696.   echo shar: Will not clobber existing file \"'src/tag.c'\"
  1697. else
  1698. echo shar: Extracting \"'src/tag.c'\" \(5848 characters\)
  1699. sed "s/^X//" >'src/tag.c' <<'END_OF_FILE'
  1700. X#ifndef lint
  1701. Xstatic char rcsid[] = "$Id: tag.c,v 1.19 89/11/19 23:40:46 berliner Exp $";
  1702. X#endif !lint
  1703. X
  1704. X/*
  1705. X *    Copyright (c) 1989, Brian Berliner
  1706. X *
  1707. X *    You may distribute under the terms of the GNU General Public License
  1708. X *    as specified in the README file that comes with the CVS 1.0 kit.
  1709. X *
  1710. X * Tag
  1711. X *
  1712. X *    Add or delete a symbolic name to an RCS file, or a collection
  1713. X *    of RCS files.  Uses the modules database, if necessary.
  1714. X */
  1715. X
  1716. X#include <sys/param.h>
  1717. X#include <ndbm.h>
  1718. X#include <dirent.h>
  1719. X#include <ctype.h>
  1720. X#include "cvs.h"
  1721. X
  1722. Xextern char update_dir[];
  1723. Xextern int run_module_prog;
  1724. Xextern DBM *open_module();
  1725. X
  1726. Xstatic char *symtag;
  1727. Xstatic char *numtag = "";        /* must be null string, not pointer */
  1728. Xstatic int delete = 0;            /* adding a tag by default */
  1729. Xstatic int tag_recursive = 1;        /* recursive by default */
  1730. X
  1731. Xtag(argc, argv)
  1732. X    int argc;
  1733. X    char *argv[];
  1734. X{
  1735. X    register int i;
  1736. X    int c;
  1737. X    DBM *db;
  1738. X    int err = 0;
  1739. X
  1740. X    if (argc == -1)
  1741. X    tag_usage();
  1742. X    optind = 1;
  1743. X    while ((c = getopt(argc, argv, "nfQqldr:D:")) != -1) {
  1744. X    switch (c) {
  1745. X    case 'n':
  1746. X        run_module_prog = 0;
  1747. X        break;
  1748. X    case 'Q':
  1749. X        really_quiet = 1;
  1750. X        /* FALL THROUGH */
  1751. X    case 'q':
  1752. X        quiet = 1;
  1753. X        break;
  1754. X    case 'l':
  1755. X        tag_recursive = 0;
  1756. X        break;
  1757. X    case 'd':
  1758. X        delete = 1;
  1759. X        /* FALL THROUGH */
  1760. X    case 'f':
  1761. X        /*
  1762. X         * Only makes sense when the -r option is specified, or deleting
  1763. X         */
  1764. X        force_tag_match = 1;
  1765. X        break;
  1766. X    case 'r':
  1767. X        numtag = optarg;
  1768. X        break;
  1769. X    case 'D':
  1770. X        Make_Date(optarg, Date);
  1771. X        break;
  1772. X    case '?':
  1773. X    default:
  1774. X        tag_usage();
  1775. X        break;
  1776. X    }
  1777. X    }
  1778. X    argc -= optind;
  1779. X    argv += optind;
  1780. X    if (argc < 2)
  1781. X    tag_usage();
  1782. X    symtag = argv[0];
  1783. X    argc--;
  1784. X    argv++;
  1785. X    /*
  1786. X     * Do some consistency checks on the symbolic tag... I'm not sure
  1787. X     * how these relate to the checks that RCS does.
  1788. X     */
  1789. X    if (isdigit(symtag[0]) || index(symtag, '.') ||
  1790. X    index(symtag, ':') || index(symtag, ';'))
  1791. X    error(0, "symbolic tag %s must not contain any of '.:;' or start with 0-9",
  1792. X          symtag);
  1793. X    db = open_module();
  1794. X    for (i = 0; i < argc; i++)
  1795. X    err += do_module(db, argv[i], TAG, "Tagging");
  1796. X    close_module(db);
  1797. X    exit(err);
  1798. X}
  1799. X
  1800. X/*
  1801. X * This is the recursive function that adds/deletes tags from
  1802. X * RCS files.  If the "rcs" argument is NULL, descend the current
  1803. X * directory, tagging all the files as appropriate; otherwise, just
  1804. X * tag the argument rcs file
  1805. X */
  1806. Xtagit(rcs)
  1807. X    char *rcs;
  1808. X{
  1809. X    DIR *dirp;
  1810. X    struct dirent *dp;
  1811. X    char line[10];
  1812. X    char *cp;
  1813. X    int err = 0;
  1814. X
  1815. X    if (rcs == NULL) {
  1816. X    if ((dirp = opendir(".")) == NULL) {
  1817. X        err++;
  1818. X    } else {
  1819. X        (void) sprintf(line, ".*%s$", RCSEXT);
  1820. X        if ((cp = re_comp(line)) != NULL) {
  1821. X        warn(0, "%s", cp);
  1822. X        err++;
  1823. X        } while ((dp = readdir(dirp)) != NULL) {
  1824. X        if (strcmp(dp->d_name, ".") == 0 ||
  1825. X            strcmp(dp->d_name, "..") == 0 ||
  1826. X            strcmp(dp->d_name, CVSLCK) == 0)
  1827. X            continue;
  1828. X        if (strcmp(dp->d_name, CVSATTIC) == 0 &&
  1829. X            !delete && numtag[0] == '\0')
  1830. X            continue;
  1831. X        if (isdir(dp->d_name) && tag_recursive) {
  1832. X            char cwd[MAXPATHLEN];
  1833. X
  1834. X            if (getwd(cwd) == NULL) {
  1835. X            warn(0, "cannot get working directory: %s", cwd);
  1836. X            continue;
  1837. X            }
  1838. X            if (update_dir[0] == '\0') {
  1839. X            (void) strcpy(update_dir, dp->d_name);
  1840. X            } else {
  1841. X            (void) strcat(update_dir, "/");
  1842. X            (void) strcat(update_dir, dp->d_name);
  1843. X            }
  1844. X            if (!quiet) {
  1845. X            printf("%s %s: Tagging %s\n",
  1846. X                   progname, command, update_dir);
  1847. X            }
  1848. X            if (chdir(dp->d_name) < 0) {
  1849. X            warn(0, "chdir failed, %s ignored", update_dir);
  1850. X            continue;
  1851. X            }
  1852. X            err += tagit((char *)0);
  1853. X            if ((cp = rindex(update_dir, '/')) != NULL)
  1854. X            *cp = '\0';
  1855. X            else
  1856. X            update_dir[0] = '\0';
  1857. X            if (chdir(cwd) < 0)
  1858. X            error(1, "cannot chdir back to %s", cwd);
  1859. X            continue;
  1860. X        }
  1861. X        if (re_exec(dp->d_name))
  1862. X            err += tag_file(dp->d_name);
  1863. X        }
  1864. X    }
  1865. X    if (dirp)
  1866. X        (void) closedir(dirp);
  1867. X    } else {
  1868. X    return (tag_file(rcs));
  1869. X    }
  1870. X    return (err);
  1871. X}
  1872. X
  1873. X/*
  1874. X * Called to tag a particular file, as appropriate with the options
  1875. X * that were set above.
  1876. X */
  1877. Xtag_file(rcs)
  1878. X    char *rcs;
  1879. X{
  1880. X    char version[50];
  1881. X
  1882. X    if (delete) {
  1883. X    /*
  1884. X     * If -d is specified, "force_tag_match" is set, so that this call
  1885. X     * to Version_Number() will return a NULL version string if
  1886. X     * the symbolic tag does not exist in the RCS file.
  1887. X     *
  1888. X     * If the -r flag was used, numtag is set, and we only delete
  1889. X     * the symtag from files that have contain numtag.
  1890. X     *
  1891. X     * This is done here because it's MUCH faster than just blindly
  1892. X     * calling "rcs" to remove the tag... trust me.
  1893. X     */
  1894. X    if (numtag[0] != '\0') {
  1895. X        Version_Number(rcs, numtag, "", version);
  1896. X        if (version[0] == '\0')
  1897. X        return (0);
  1898. X    }
  1899. X    Version_Number(rcs, symtag, "", version);
  1900. X    if (version[0] == '\0')
  1901. X        return (0);
  1902. X    (void) sprintf(prog, "%s/%s -q -N%s %s 2>%s", Rcsbin, RCS,
  1903. X               symtag, rcs, DEVNULL);
  1904. X    if (system(prog) != 0) {
  1905. X        warn(0, "failed to remove tag %s for %s", symtag, rcs);
  1906. X        return (1);
  1907. X    }
  1908. X    return (0);
  1909. X    }
  1910. X    Version_Number(rcs, numtag, Date, version);
  1911. X    if (version[0] == '\0') {
  1912. X    if (!really_quiet) {
  1913. X        warn(0, "cannot find tag '%s' for %s", numtag[0] ? numtag : "head",
  1914. X         rcs);
  1915. X    }
  1916. X    return (1);
  1917. X    }
  1918. X    if (isdigit(numtag[0]) && strcmp(numtag, version) != 0) {
  1919. X    /*
  1920. X     * We didn't find a match for the numeric tag that was specified,
  1921. X     * but that's OK.  just pass the numeric tag on to rcs, to be
  1922. X     * tagged as specified
  1923. X     */
  1924. X    (void) strcpy(version, numtag);
  1925. X    }
  1926. X    (void) sprintf(prog, "%s/%s -q -N%s:%s %s", Rcsbin, RCS, symtag,
  1927. X           version, rcs);
  1928. X    if (system(prog) != 0) {
  1929. X    warn(0, "failed to set tag %s to revision %s for %s",
  1930. X         symtag, version, rcs);
  1931. X    return (1);
  1932. X    }
  1933. X    return (0);
  1934. X}
  1935. X
  1936. Xstatic
  1937. Xtag_usage()
  1938. X{
  1939. X    (void) fprintf(stderr,
  1940. X    "Usage: %s %s [-Qqlfn] [-d] [-r tag|-D date] tag modules...\n",
  1941. X           progname, command);
  1942. X    exit(1);
  1943. X}
  1944. END_OF_FILE
  1945. if test 5848 -ne `wc -c <'src/tag.c'`; then
  1946.     echo shar: \"'src/tag.c'\" unpacked with wrong size!
  1947. fi
  1948. # end of 'src/tag.c'
  1949. fi
  1950. echo shar: End of archive 2 \(of 7\).
  1951. cp /dev/null ark2isdone
  1952. MISSING=""
  1953. for I in 1 2 3 4 5 6 7 ; do
  1954.     if test ! -f ark${I}isdone ; then
  1955.     MISSING="${MISSING} ${I}"
  1956.     fi
  1957. done
  1958. if test "${MISSING}" = "" ; then
  1959.     echo You have unpacked all 7 archives.
  1960.     rm -f ark[1-9]isdone
  1961. else
  1962.     echo You still need to unpack the following archives:
  1963.     echo "        " ${MISSING}
  1964. fi
  1965. ##  End of shell archive.
  1966. exit 0
  1967. exit 0 # Just in case...
  1968.