[BACK]Return to rcs.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / cvs

Diff for /src/usr.bin/cvs/rcs.c between version 1.171 and 1.172

version 1.171, 2006/05/01 18:17:39 version 1.172, 2006/05/27 03:30:31
Line 26 
Line 26 
   
 #include "includes.h"  #include "includes.h"
   
   #include "buf.h"
 #include "cvs.h"  #include "cvs.h"
   #include "diff.h"
 #include "log.h"  #include "log.h"
 #include "rcs.h"  #include "rcs.h"
 #include "diff.h"  #include "util.h"
   #include "xmalloc.h"
   
 #define RCS_BUFSIZE     16384  #define RCS_BUFSIZE     16384
 #define RCS_BUFEXTSIZE  8192  #define RCS_BUFEXTSIZE  8192
 #define RCS_KWEXP_SIZE  1024  #define RCS_KWEXP_SIZE  1024
   
   
 /* RCS token types */  /* RCS token types */
 #define RCS_TOK_ERR     -1  #define RCS_TOK_ERR     -1
 #define RCS_TOK_EOF     0  #define RCS_TOK_EOF     0
Line 45 
Line 47 
 #define RCS_TOK_SCOLON  4  #define RCS_TOK_SCOLON  4
 #define RCS_TOK_COLON   5  #define RCS_TOK_COLON   5
   
   
 #define RCS_TOK_HEAD            8  #define RCS_TOK_HEAD            8
 #define RCS_TOK_BRANCH          9  #define RCS_TOK_BRANCH          9
 #define RCS_TOK_ACCESS          10  #define RCS_TOK_ACCESS          10
Line 65 
Line 66 
   
 #define RCS_ISKEY(t)    (((t) >= RCS_TOK_HEAD) && ((t) <= RCS_TOK_BRANCHES))  #define RCS_ISKEY(t)    (((t) >= RCS_TOK_HEAD) && ((t) <= RCS_TOK_BRANCHES))
   
   
 #define RCS_NOSCOL      0x01    /* no terminating semi-colon */  #define RCS_NOSCOL      0x01    /* no terminating semi-colon */
 #define RCS_VOPT        0x02    /* value is optional */  #define RCS_VOPT        0x02    /* value is optional */
   
   
 /* opaque parse data */  /* opaque parse data */
 struct rcs_pdata {  struct rcs_pdata {
         u_int   rp_lines;          u_int   rp_lines;
Line 86 
Line 85 
         FILE    *rp_file;          FILE    *rp_file;
 };  };
   
   
 #define RCS_TOKSTR(rfp) ((struct rcs_pdata *)rfp->rf_pdata)->rp_buf  #define RCS_TOKSTR(rfp) ((struct rcs_pdata *)rfp->rf_pdata)->rp_buf
 #define RCS_TOKLEN(rfp) ((struct rcs_pdata *)rfp->rf_pdata)->rp_tlen  #define RCS_TOKLEN(rfp) ((struct rcs_pdata *)rfp->rf_pdata)->rp_tlen
   
   
 /* invalid characters in RCS symbol names */  /* invalid characters in RCS symbol names */
 static const char rcs_sym_invch[] = RCS_SYM_INVALCHAR;  static const char rcs_sym_invch[] = RCS_SYM_INVALCHAR;
   
   
 /* comment leaders, depending on the file's suffix */  /* comment leaders, depending on the file's suffix */
 static const struct rcs_comment {  static const struct rcs_comment {
         const char      *rc_suffix;          const char      *rc_suffix;
Line 179 
Line 175 
   
 #define NB_COMTYPES     (sizeof(rcs_comments)/sizeof(rcs_comments[0]))  #define NB_COMTYPES     (sizeof(rcs_comments)/sizeof(rcs_comments[0]))
   
 #ifdef notyet  
 static struct rcs_kfl {  
         char    rk_char;  
         int     rk_val;  
 } rcs_kflags[] = {  
         { 'k',   RCS_KWEXP_NAME },  
         { 'v',   RCS_KWEXP_VAL  },  
         { 'l',   RCS_KWEXP_LKR  },  
         { 'o',   RCS_KWEXP_OLD  },  
         { 'b',   RCS_KWEXP_NONE },  
 };  
 #endif  
   
 static struct rcs_key {  static struct rcs_key {
         char    rk_str[16];          char    rk_str[16];
         int     rk_id;          int     rk_id;
Line 218 
Line 201 
   
 #define RCS_NKEYS       (sizeof(rcs_keys)/sizeof(rcs_keys[0]))  #define RCS_NKEYS       (sizeof(rcs_keys)/sizeof(rcs_keys[0]))
   
   
 static const char *rcs_errstrs[] = {  static const char *rcs_errstrs[] = {
         "No error",          "No error",
         "No such entry",          "No such entry",
Line 230 
Line 212 
   
 #define RCS_NERR   (sizeof(rcs_errstrs)/sizeof(rcs_errstrs[0]))  #define RCS_NERR   (sizeof(rcs_errstrs)/sizeof(rcs_errstrs[0]))
   
   
 int rcs_errno = RCS_ERR_NOERR;  int rcs_errno = RCS_ERR_NOERR;
 char *timezone_flag = NULL;  
   
   int             rcs_patch_lines(struct cvs_lines *, struct cvs_lines *);
   static int      rcs_movefile(char *, char *, mode_t, u_int);
 static void     rcs_parse_init(RCSFILE *);  static void     rcs_parse_init(RCSFILE *);
 static int      rcs_parse_admin(RCSFILE *);  static int      rcs_parse_admin(RCSFILE *);
 static int      rcs_parse_delta(RCSFILE *);  static int      rcs_parse_delta(RCSFILE *);
Line 256 
Line 238 
 static char*   rcs_expand_keywords(char *, struct rcs_delta *, char *,  static char*   rcs_expand_keywords(char *, struct rcs_delta *, char *,
                     size_t, int);                      size_t, int);
   
 /*  
  * rcs_open()  
  *  
  * Open a file containing RCS-formatted information.  The file's path is  
  * given in <path>, and the opening flags are given in <flags>, which is either  
  * RCS_READ, RCS_WRITE, or RCS_RDWR.  If the open requests write access and  
  * the file does not exist, the RCS_CREATE flag must also be given, in which  
  * case it will be created with the mode specified in a third argument of  
  * type mode_t.  If the file exists and RCS_CREATE is passed, the open will  
  * fail.  
  * Returns a handle to the opened file on success, or NULL on failure.  
  */  
 RCSFILE *  RCSFILE *
 rcs_open(const char *path, int flags, ...)  rcs_open(const char *path, int fd, int flags, ...)
 {  {
         int ret, mode;          int mode;
         mode_t fmode;          mode_t fmode;
         RCSFILE *rfp;          RCSFILE *rfp;
         struct stat st;  
         va_list vap;          va_list vap;
         struct rcs_delta *rdp;          struct rcs_delta *rdp;
         struct rcs_lock *lkr;          struct rcs_lock *lkr;
Line 282 
Line 251 
         fmode = S_IRUSR|S_IRGRP|S_IROTH;          fmode = S_IRUSR|S_IRGRP|S_IROTH;
         flags &= 0xffff;        /* ditch any internal flags */          flags &= 0xffff;        /* ditch any internal flags */
   
         if (((ret = stat(path, &st)) == -1) && errno == ENOENT) {          if (flags & RCS_CREATE) {
                 if (flags & RCS_CREATE) {                  va_start(vap, flags);
                         va_start(vap, flags);                  mode = va_arg(vap, int);
                         mode = va_arg(vap, int);                  va_end(vap);
                         va_end(vap);                  fmode = (mode_t)mode;
                         fmode = (mode_t)mode;  
                 } else {  
                         /* XXX, make this command dependant? */  
 #if 0  
                         cvs_log(LP_ERR, "RCS file `%s' does not exist", path);  
 #endif  
                         rcs_errno = RCS_ERR_NOENT;  
                         return (NULL);  
                 }  
         } else if (ret == 0 && (flags & RCS_CREATE)) {  
                 cvs_log(LP_ERR, "RCS file `%s' exists", path);  
                 return (NULL);  
         }          }
   
         rfp = xcalloc(1, sizeof(*rfp));          rfp = xcalloc(1, sizeof(*rfp));
Line 306 
Line 263 
         rfp->rf_path = xstrdup(path);          rfp->rf_path = xstrdup(path);
         rfp->rf_flags = flags | RCS_SLOCK | RCS_SYNCED;          rfp->rf_flags = flags | RCS_SLOCK | RCS_SYNCED;
         rfp->rf_mode = fmode;          rfp->rf_mode = fmode;
           rfp->fd = fd;
   
         TAILQ_INIT(&(rfp->rf_delta));          TAILQ_INIT(&(rfp->rf_delta));
         TAILQ_INIT(&(rfp->rf_access));          TAILQ_INIT(&(rfp->rf_access));
Line 396 
Line 354 
  *   *
  * Write the contents of the RCS file handle <rfp> to disk in the file whose   * Write the contents of the RCS file handle <rfp> to disk in the file whose
  * path is in <rf_path>.   * path is in <rf_path>.
  * Returns 0 on success, or -1 on failure.  
  */   */
 int  void
 rcs_write(RCSFILE *rfp)  rcs_write(RCSFILE *rfp)
 {  {
         FILE *fp;          FILE *fp;
         char buf[1024], numbuf[64], fn[19] = "";          char buf[1024], numbuf[64], *fn;
         void *bp;  
         struct rcs_access *ap;          struct rcs_access *ap;
         struct rcs_sym *symp;          struct rcs_sym *symp;
         struct rcs_branch *brp;          struct rcs_branch *brp;
         struct rcs_delta *rdp;          struct rcs_delta *rdp;
         struct rcs_lock *lkp;          struct rcs_lock *lkp;
         ssize_t nread, nwritten;  
         size_t len;          size_t len;
         int fd, from_fd, to_fd;          int fd, from_fd, to_fd;
   
         from_fd = to_fd = fd = -1;          from_fd = to_fd = fd = -1;
   
         if (rfp->rf_flags & RCS_SYNCED)          if (rfp->rf_flags & RCS_SYNCED)
                 return (0);                  return;
   
         /* Write operations need the whole file parsed */          /* Write operations need the whole file parsed */
         rcs_parse_deltatexts(rfp, NULL);          rcs_parse_deltatexts(rfp, NULL);
   
         strlcpy(fn, "/tmp/rcs.XXXXXXXXXX", sizeof(fn));          (void)xasprintf(&fn, "%s/rcs.XXXXXXXXXX", cvs_tmpdir);
   
         if ((fd = mkstemp(fn)) == -1)          if ((fd = mkstemp(fn)) == -1)
                 fatal("mkstemp: `%s': %s", fn, strerror(errno));                  fatal("%s", fn);
   
         if ((fp = fdopen(fd, "w+")) == NULL) {          if ((fp = fdopen(fd, "w+")) == NULL) {
                 fd = errno;                  int saved_errno;
                 unlink(fn);  
                 fatal("fdopen: %s", strerror(fd));                  saved_errno = errno;
                   (void)unlink(fn);
                   errno = saved_errno;
                   fatal("%s", fn);
         }          }
   
         if (rfp->rf_head != NULL)          if (rfp->rf_head != NULL)
Line 452 
Line 411 
         fprintf(fp, "symbols");          fprintf(fp, "symbols");
         TAILQ_FOREACH(symp, &(rfp->rf_symbols), rs_list) {          TAILQ_FOREACH(symp, &(rfp->rf_symbols), rs_list) {
                 rcsnum_tostr(symp->rs_num, numbuf, sizeof(numbuf));                  rcsnum_tostr(symp->rs_num, numbuf, sizeof(numbuf));
                 strlcpy(buf, symp->rs_name, sizeof(buf));                  if (strlcpy(buf, symp->rs_name, sizeof(buf)) >= sizeof(buf) ||
                 strlcat(buf, ":", sizeof(buf));                      strlcat(buf, ":", sizeof(buf)) >= sizeof(buf) ||
                 strlcat(buf, numbuf, sizeof(buf));                      strlcat(buf, numbuf, sizeof(buf)) >= sizeof(buf))
                           fatal("rcs_write: string overflow");
                 fprintf(fp, "\n\t%s", buf);                  fprintf(fp, "\n\t%s", buf);
         }          }
         fprintf(fp, ";\n");          fprintf(fp, ";\n");
Line 537 
Line 497 
                 }                  }
                 fputs("@\n", fp);                  fputs("@\n", fp);
         }          }
         fclose(fp);          (void)fclose(fp);
   
         /*          if (rcs_movefile(fn, rfp->rf_path, rfp->rf_mode, rfp->rf_flags) == -1) {
          * We try to use rename() to atomically put the new file in place.                  (void)unlink(fn);
          * If that fails, we try a copy.                  fatal("rcs_movefile failed");
          */          }
         if (rename(fn, rfp->rf_path) == -1) {  
                 if (errno == EXDEV) {  
                         /* rename() not supported so we have to copy. */  
                         if (chmod(rfp->rf_path, S_IWUSR) == -1 &&  
                             !(rfp->rf_flags & RCS_CREATE)) {  
                                 fatal("chmod(%s, 0%o) failed",  
                                     rfp->rf_path, S_IWUSR);  
                         }  
   
                         if ((from_fd = open(fn, O_RDONLY)) == -1) {          rfp->rf_flags |= RCS_SYNCED;
                                 cvs_log(LP_ERRNO, "failed to open `%s'",  
                                     rfp->rf_path);  
                                 return (-1);  
                         }  
   
                         if ((to_fd = open(rfp->rf_path,          if (fn != NULL)
                             O_WRONLY|O_TRUNC|O_CREAT)) == -1) {                  xfree(fn);
                                 cvs_log(LP_ERRNO, "failed to open `%s'", fn);  }
                                 close(from_fd);  
                                 return (-1);  
                         }  
   
                         bp = xmalloc(MAXBSIZE);  /*
                         for (;;) {   * rcs_movefile()
                                 if ((nread = read(from_fd, bp, MAXBSIZE)) == 0)   *
                                         break;   * Move a file using rename(2) if possible and copying if not.
                                 if (nread == -1)   * Returns 0 on success, -1 on failure.
                                         goto err;   */
                                 nwritten = write(to_fd, bp, (size_t)nread);  static int
                                 if (nwritten == -1 || nwritten != nread)  rcs_movefile(char *from, char *to, mode_t perm, u_int to_flags)
                                         goto err;  {
                         }          FILE *src, *dst;
           size_t nread, nwritten;
           char *buf;
           int ret;
   
                         if (nread < 0) {          ret = -1;
 err:                            if (unlink(rfp->rf_path) == -1)  
                                         cvs_log(LP_ERRNO,  
                                             "failed to unlink `%s'",  
                                             rfp->rf_path);  
                                 close(from_fd);  
                                 close(to_fd);  
                                 xfree(bp);  
                                 return (-1);  
                         }  
   
                         close(from_fd);          if (rename(from, to) == 0) {
                         close(to_fd);                  if (chmod(to, perm) == -1) {
                         xfree(bp);                          cvs_log(LP_ERRNO, "%s", to);
   
                         if (unlink(fn) == -1) {  
                                 cvs_log(LP_ERRNO,  
                                     "failed to unlink `%s'", fn);  
                                 return (-1);  
                         }  
                 } else {  
                         cvs_log(LP_ERRNO,  
                             "failed to access temp RCS output file");  
                         return (-1);                          return (-1);
                 }                  }
                   return (0);
           } else if (errno != EXDEV) {
                   cvs_log(LP_NOTICE, "failed to access temp RCS output file");
                   return (-1);
         }          }
   
         if (chmod(rfp->rf_path, rfp->rf_mode) == -1) {          if ((chmod(to, S_IWUSR) == -1) && !(to_flags & RCS_CREATE)) {
                 cvs_log(LP_ERRNO, "failed to chmod `%s'",                  cvs_log(LP_ERR, "chmod(%s, 0%o) failed", to, S_IWUSR);
                     rfp->rf_path);  
                 return (-1);                  return (-1);
         }          }
   
         rfp->rf_flags |= RCS_SYNCED;          /* different filesystem, have to copy the file */
           if ((src = fopen(from, "r")) == NULL) {
                   cvs_log(LP_ERRNO, "%s", from);
                   return (-1);
           }
           if ((dst = fopen(to, "w")) == NULL) {
                   cvs_log(LP_ERRNO, "%s", to);
                   return (-1);
           }
           if (fchmod(fileno(dst), perm)) {
                   cvs_log(LP_ERR, "%s", to);
                   (void)unlink(to);
                   return (-1);
           }
   
         return (0);          buf = xmalloc(MAXBSIZE);
           while ((nread = fread(buf, sizeof(char), MAXBSIZE, src)) != 0) {
                   if (ferror(src)) {
                           cvs_log(LP_ERRNO, "failed to read `%s'", from);
                           (void)unlink(to);
                           goto out;
                   }
                   nwritten = fwrite(buf, sizeof(char), nread, dst);
                   if (nwritten != nread) {
                           cvs_log(LP_ERRNO, "failed to write `%s'", to);
                           (void)unlink(to);
                           goto out;
                   }
           }
   
           ret = 0;
   
           (void)fclose(src);
           (void)fclose(dst);
           (void)unlink(from);
   
   out:
           xfree(buf);
   
           return (ret);
 }  }
   
 /*  /*
Line 1383 
Line 1353 
 int  int
 rcs_rev_remove(RCSFILE *rf, RCSNUM *rev)  rcs_rev_remove(RCSFILE *rf, RCSNUM *rev)
 {  {
         size_t len;          char *newdeltatext, *path_tmp1, *path_tmp2;
         char *tmpdir;  
         char *newdeltatext, path_tmp1[MAXPATHLEN], path_tmp2[MAXPATHLEN];  
         struct rcs_delta *rdp, *prevrdp, *nextrdp;          struct rcs_delta *rdp, *prevrdp, *nextrdp;
         BUF *nextbuf, *prevbuf, *newdiff;          BUF *nextbuf, *prevbuf, *newdiff;
   
 #if defined(RCSPROG)  
         tmpdir = rcs_tmpdir;  
 #else  
         tmpdir = cvs_tmpdir;  
 #endif  
   
         if (rev == RCS_HEAD_REV)          if (rev == RCS_HEAD_REV)
                 rev = rf->rf_head;                  rev = rf->rf_head;
   
Line 1429 
Line 1391 
                 newdiff = cvs_buf_alloc(64, BUF_AUTOEXT);                  newdiff = cvs_buf_alloc(64, BUF_AUTOEXT);
   
                 /* calculate new diff */                  /* calculate new diff */
                 len = strlcpy(path_tmp1, tmpdir, sizeof(path_tmp1));                  (void)xasprintf(&path_tmp1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir);
                 if (len >= sizeof(path_tmp1))                  cvs_buf_write_stmp(nextbuf, path_tmp1, 0600, NULL);
                         fatal("path truncation in rcs_rev_remove");  
   
                 len = strlcat(path_tmp1, "/diff1.XXXXXXXXXX",  
                     sizeof(path_tmp1));  
                 if (len >= sizeof(path_tmp1))  
                         fatal("path truncation in rcs_rev_remove");  
   
                 cvs_buf_write_stmp(nextbuf, path_tmp1, 0600);  
                 cvs_buf_free(nextbuf);                  cvs_buf_free(nextbuf);
   
                 len = strlcpy(path_tmp2, tmpdir, sizeof(path_tmp2));                  (void)xasprintf(&path_tmp2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir);
                 if (len >= sizeof(path_tmp2))                  cvs_buf_write_stmp(prevbuf, path_tmp2, 0600, NULL);
                         fatal("path truncation in rcs_rev_remove");  
   
                 len = strlcat(path_tmp2, "/diff2.XXXXXXXXXX",  
                     sizeof(path_tmp2));  
                 if (len >= sizeof(path_tmp2))  
                         fatal("path truncation in rcs_rev_remove");  
   
                 cvs_buf_write_stmp(prevbuf, path_tmp2, 0600);  
                 cvs_buf_free(prevbuf);                  cvs_buf_free(prevbuf);
   
                 diff_format = D_RCSDIFF;                  diff_format = D_RCSDIFF;
                 cvs_diffreg(path_tmp1, path_tmp2, newdiff);                  if (cvs_diffreg(path_tmp1, path_tmp2, newdiff) == D_ERROR)
                           fatal("rcs_diffreg failed");
   
                 newdeltatext = cvs_buf_release(newdiff);                  newdeltatext = cvs_buf_release(newdiff);
         } else if (nextrdp == NULL && prevrdp != NULL) {          } else if (nextrdp == NULL && prevrdp != NULL) {
Line 1490 
Line 1437 
         if (newdeltatext != NULL)          if (newdeltatext != NULL)
                 xfree(newdeltatext);                  xfree(newdeltatext);
   
           if (path_tmp1 != NULL)
                   xfree(path_tmp1);
           if (path_tmp2 != NULL)
                   xfree(path_tmp2);
   
         return (0);          return (0);
 }  }
   
Line 1768 
Line 1720 
         pdp->rp_lines = 0;          pdp->rp_lines = 0;
         pdp->rp_pttype = RCS_TOK_ERR;          pdp->rp_pttype = RCS_TOK_ERR;
   
         if ((pdp->rp_file = fopen(rfp->rf_path, "r")) == NULL)          if ((pdp->rp_file = fdopen(rfp->fd, "r")) == NULL)
                 fatal("fopen: `%s': %s", rfp->rf_path, strerror(errno));                  fatal("fopen: `%s'", rfp->rf_path);
   
         pdp->rp_buf = xmalloc((size_t)RCS_BUFSIZE);          pdp->rp_buf = xmalloc((size_t)RCS_BUFSIZE);
         pdp->rp_blen = RCS_BUFSIZE;          pdp->rp_blen = RCS_BUFSIZE;
Line 2057 
Line 2009 
                         break;                          break;
                 default:                  default:
                         rcs_errno = RCS_ERR_PARSE;                          rcs_errno = RCS_ERR_PARSE;
                         cvs_log(LP_ERR,                          cvs_log(LP_ERR, "unexpected token `%s' in RCS delta",
                             "unexpected token `%s' in RCS delta",  
                             RCS_TOKSTR(rfp));                              RCS_TOKSTR(rfp));
                         rcs_freedelta(rdp);                          rcs_freedelta(rdp);
                         return (-1);                          return (-1);
Line 2149 
Line 2100 
         }          }
   
         rdp->rd_text = xmalloc(RCS_TOKLEN(rfp) + 1);          rdp->rd_text = xmalloc(RCS_TOKLEN(rfp) + 1);
         strlcpy(rdp->rd_text, RCS_TOKSTR(rfp), (RCS_TOKLEN(rfp) + 1));          if (strlcpy(rdp->rd_text, RCS_TOKSTR(rfp), (RCS_TOKLEN(rfp) + 1)) >=
               RCS_TOKLEN(rfp) + 1)
                   fatal("rcs_parse_deltatext: strlcpy");
         rdp->rd_tlen = RCS_TOKLEN(rfp);          rdp->rd_tlen = RCS_TOKLEN(rfp);
   
         return (1);          return (1);
Line 2436 
Line 2389 
   
         if (pdp->rp_pttype != RCS_TOK_ERR) {          if (pdp->rp_pttype != RCS_TOK_ERR) {
                 type = pdp->rp_pttype;                  type = pdp->rp_pttype;
                 strlcpy(pdp->rp_buf, pdp->rp_ptok, pdp->rp_blen);                  if (strlcpy(pdp->rp_buf, pdp->rp_ptok, pdp->rp_blen) >=
                       pdp->rp_blen)
                           fatal("rcs_gettok: strlcpy");
                 pdp->rp_pttype = RCS_TOK_ERR;                  pdp->rp_pttype = RCS_TOK_ERR;
                 return (type);                  return (type);
         }          }
Line 2550 
Line 2505 
                 return (-1);                  return (-1);
   
         pdp->rp_pttype = type;          pdp->rp_pttype = type;
         strlcpy(pdp->rp_ptok, tok, sizeof(pdp->rp_ptok));          if (strlcpy(pdp->rp_ptok, tok, sizeof(pdp->rp_ptok)) >=
               sizeof(pdp->rp_ptok))
                   fatal("rcs_pushtok: strlcpy");
         return (0);          return (0);
 }  }
   
Line 2628 
Line 2585 
         i = 0;          i = 0;
   
         /*          /*
          * -z support for RCS  
          */  
         tb = rdp->rd_date;  
         if (timezone_flag != NULL)  
                 rcs_set_tz(timezone_flag, rdp, &tb);  
   
         /*  
          * Keyword formats:           * Keyword formats:
          * $Keyword$           * $Keyword$
          * $Keyword: value$           * $Keyword: value$
Line 2700 
Line 2650 
                         expbuf[0] = '\0';                          expbuf[0] = '\0';
   
                         if (mode & RCS_KWEXP_NAME) {                          if (mode & RCS_KWEXP_NAME) {
                                 strlcat(expbuf, "$", sizeof(expbuf));                                  if (strlcat(expbuf, "$", sizeof(expbuf))
                                 strlcat(expbuf, kwstr, sizeof(expbuf));                                      >= sizeof(expbuf) ||
                                 if (mode & RCS_KWEXP_VAL)                                      strlcat(expbuf, kwstr, sizeof(expbuf))
                                         strlcat(expbuf, ": ", sizeof(expbuf));                                      >= sizeof(expbuf))
                                           fatal("rcs_expand_keywords: truncated");
                                   if ((mode & RCS_KWEXP_VAL) &&
                                       strlcat(expbuf, ": ", sizeof(expbuf))
                                       >= sizeof(expbuf))
                                           fatal("rcs_expand_keywords: truncated");
                         }                          }
   
                         /*                          /*
Line 2713 
Line 2668 
                         if (mode & RCS_KWEXP_VAL) {                          if (mode & RCS_KWEXP_VAL) {
                                 if (kwtype & RCS_KW_RCSFILE) {                                  if (kwtype & RCS_KW_RCSFILE) {
                                         if (!(kwtype & RCS_KW_FULLPATH))                                          if (!(kwtype & RCS_KW_FULLPATH))
                                                 strlcat(expbuf,                                                  (void)strlcat(expbuf,
                                                     basename(rcsfile),                                                      basename(rcsfile),
                                                     sizeof(expbuf));                                                      sizeof(expbuf));
                                         else                                          else
                                                 strlcat(expbuf, rcsfile,                                                  (void)strlcat(expbuf,
                                                     sizeof(expbuf));                                                      rcsfile, sizeof(expbuf));
                                         strlcat(expbuf, " ", sizeof(expbuf));                                          if (strlcat(expbuf, " ",
                                               sizeof(expbuf)) >= sizeof(expbuf))
                                                   fatal("rcs_expand_keywords: "
                                                       "truncated");
                                 }                                  }
   
                                 if (kwtype & RCS_KW_REVISION) {                                  if (kwtype & RCS_KW_REVISION) {
                                         rcsnum_tostr(rdp->rd_num, buf,                                          rcsnum_tostr(rdp->rd_num, buf,
                                             sizeof(buf));                                              sizeof(buf));
                                         strlcat(buf, " ", sizeof(buf));                                          if (strlcat(buf, " ", sizeof(buf))
                                         strlcat(expbuf, buf, sizeof(expbuf));                                              >= sizeof(buf) ||
                                               strlcat(expbuf, buf,
                                               sizeof(expbuf)) >= sizeof(buf))
                                                   fatal("rcs_expand_keywords: "
                                                       "truncated");
                                 }                                  }
   
                                 if (kwtype & RCS_KW_DATE) {                                  if (kwtype & RCS_KW_DATE) {
                                         if (timezone_flag != NULL)                                          fmt = "%Y/%m/%d %H:%M:%S ";
                                                 fmt = "%Y/%m/%d %H:%M:%S%z ";  
                                         else  
                                                 fmt = "%Y/%m/%d %H:%M:%S ";  
   
                                         strftime(buf, sizeof(buf), fmt, &tb);                                          strftime(buf, sizeof(buf), fmt, &tb);
                                         strlcat(expbuf, buf, sizeof(expbuf));                                          if (strlcat(expbuf, buf,
                                               sizeof(expbuf)) >= sizeof(expbuf))
                                                   fatal("rcs_expand_keywords: "
                                                       "string truncated");
                                 }                                  }
   
                                 if (kwtype & RCS_KW_AUTHOR) {                                  if (kwtype & RCS_KW_AUTHOR) {
                                         strlcat(expbuf, rdp->rd_author,                                          if (strlcat(expbuf, rdp->rd_author,
                                             sizeof(expbuf));                                              sizeof(expbuf)) >= sizeof(expbuf) ||
                                         strlcat(expbuf, " ", sizeof(expbuf));                                              strlcat(expbuf, " ",
                                               sizeof(expbuf)) >= sizeof(expbuf))
                                                   fatal("rcs_expand_keywords: "
                                                       "string truncated");
                                 }                                  }
   
                                 if (kwtype & RCS_KW_STATE) {                                  if (kwtype & RCS_KW_STATE) {
                                         strlcat(expbuf, rdp->rd_state,                                          if (strlcat(expbuf, rdp->rd_state,
                                             sizeof(expbuf));                                              sizeof(expbuf)) >= sizeof(expbuf) ||
                                         strlcat(expbuf, " ", sizeof(expbuf));                                              strlcat(expbuf, " ",
                                               sizeof(expbuf)) >= sizeof(expbuf))
                                                   fatal("rcs_expand_keywords: "
                                                       "string truncated");
                                 }                                  }
   
                                 /* order does not matter anymore below */                                  /* order does not matter anymore below */
                                 if (kwtype & RCS_KW_LOG)                                  if (kwtype & RCS_KW_LOG)
                                         strlcat(expbuf, " ", sizeof(expbuf));                                          if (strlcat(expbuf, " ",
                                               sizeof(expbuf)) >= sizeof(expbuf))
                                                   fatal("rcs_expand_keywords: "
                                                       "string truncated");
   
                                 if (kwtype & RCS_KW_SOURCE) {                                  if (kwtype & RCS_KW_SOURCE) {
                                         strlcat(expbuf, rcsfile,                                          if (strlcat(expbuf, rcsfile,
                                             sizeof(expbuf));                                              sizeof(expbuf)) >= sizeof(expbuf) ||
                                         strlcat(expbuf, " ", sizeof(expbuf));                                              strlcat(expbuf, " ",
                                               sizeof(expbuf)) >= sizeof(expbuf))
                                                   fatal("rcs_expand_keywords: "
                                                       "string truncated");
                                 }                                  }
   
                                 if (kwtype & RCS_KW_NAME)                                  if (kwtype & RCS_KW_NAME)
                                         strlcat(expbuf, " ", sizeof(expbuf));                                          if (strlcat(expbuf, " ",
                                               sizeof(expbuf)) >= sizeof(expbuf))
                                                   fatal("rcs_expand_keywords: "
                                                       "string truncated");
                         }                          }
   
                         /* end the expansion */                          /* end the expansion */
                         if (mode & RCS_KWEXP_NAME)                          if (mode & RCS_KWEXP_NAME)
                                 strlcat(expbuf, "$", sizeof(expbuf));                                  if (strlcat(expbuf, "$",
                                       sizeof(expbuf)) >= sizeof(expbuf))
                                           fatal("rcs_expand_keywords: truncated");
   
                         sizdiff = strlen(expbuf) - (end - start);                          sizdiff = strlen(expbuf) - (end - start);
                         tbuf = xstrdup(end);                          tbuf = xstrdup(end);
   
                         /* only realloc if we have to */                          /* only realloc if we have to */
                         if (sizdiff > 0) {                          if (sizdiff > 0) {
                                 char *newdata;                                  char *newdata;
Line 2778 
Line 2758 
                                 len += sizdiff;                                  len += sizdiff;
                                 newdata = xrealloc(data, 1, len);                                  newdata = xrealloc(data, 1, len);
                                 data = newdata;                                  data = newdata;
   
                                 /*                                  /*
                                  * ensure string pointers are not invalidated                                   * ensure string pointers are not invalidated
                                  * after realloc()                                   * after realloc()
Line 2785 
Line 2766 
                                 start = data + start_offset;                                  start = data + start_offset;
                                 c = data + c_offset;                                  c = data + c_offset;
                         }                          }
                         strlcpy(start, expbuf, len);                          if (strlcpy(start, expbuf, len) >= len ||
                         strlcat(data, tbuf, len);                              strlcat(data, tbuf, len) >= len)
                                   fatal("rcs_expand_keywords: string truncated");
                         xfree(tbuf);                          xfree(tbuf);
                         i += strlen(expbuf);                          i += strlen(expbuf);
                 }                  }
Line 2954 
Line 2936 
   
         if (!(expmode & RCS_KWEXP_NONE)) {          if (!(expmode & RCS_KWEXP_NONE)) {
                 if ((rdp = rcs_findrev(rf, rev)) == NULL)                  if ((rdp = rcs_findrev(rf, rev)) == NULL)
                     fatal("could not fetch revision");                          fatal("could not fetch revision");
                 cvs_buf_putc(bp, '\0');                  cvs_buf_putc(bp, '\0');
                 len = cvs_buf_len(bp);                  len = cvs_buf_len(bp);
                 tbuf = cvs_buf_release(bp);                  tbuf = cvs_buf_release(bp);
Line 2966 
Line 2948 
         }          }
         return (bp);          return (bp);
 }  }
   
 #if !defined(RCSPROG)  
   
 static char *month_tab[] = {  
         "Jan",  
         "Feb",  
         "Mar",  
         "Apr",  
         "May",  
         "Jun",  
         "Jul",  
         "Aug",  
         "Sep",  
         "Oct",  
         "Nov",  
         "Dec"  
 };  
   
 void  
 rcs_kflag_usage(void)  
 {  
         (void)fprintf(stderr, "Valid expansion modes include:\n"  
             "\t-kkv\tGenerate keywords using the default form.\n"  
             "\t-kkvl\tLike -kkv, except locker's name inserted.\n"  
             "\t-kk\tGenerate only keyword names in keyword strings.\n"  
             "\t-kv\tGenerate only keyword values in keyword strings.\n"  
             "\t-ko\tGenerate old keyword string "  
             "(no changes from checked in file).\n"  
             "\t-kb\tGenerate binary file unmodified (merges not allowed).\n");  
 }  
   
 /*  
  * Checkout a certain revision <rev> of RCS file <rf> to either standard  
  * output when running in server mode, or to <fpath> when running in local mode.  
  *  
  * If type is CHECKOUT_REV_MERGED we have an extra argument, which  
  * is the buffer containing the merged file.  
  *  
  * If type is CHECKOUT_REV_REMOVED, the file has been removed and we  
  * need to do the same thing.  
  */  
 int  
 cvs_checkout_rev(RCSFILE *rf, RCSNUM *rev, CVSFILE *cf, char *fpath,  
     int local, int type, ...)  
 {  
         BUF *bp;  
         int l, ret, fsize;  
         char timebuf[32], entry[MAXPATHLEN], copyfile[MAXPATHLEN];  
         char *content, *repo, buf[MAXPATHLEN], modestr[16];  
         struct cvsroot *root;  
         struct cvs_ent *ent;  
         va_list ap;  
         time_t rcstime;  
         struct timeval tv[2];  
         struct tm *tp;  
         RCSNUM *oldrev;  
   
         bp = NULL;  
         ret = -1;  
         content = NULL;  
         oldrev = NULL;  
   
         if (type != CHECKOUT_REV_MERGED && type != CHECKOUT_REV_REMOVED) {  
                 /* fetch the contents of the revision */  
                 if ((bp = rcs_getrev(rf, rev)) == NULL) {  
                         cvs_log(LP_ERR, "revision '%s' not found in file '%s'",  
                             rcsnum_tostr(rev, buf, sizeof(buf)), fpath);  
                         goto out;  
                 }  
                 bp = rcs_kwexp_buf(bp, rf, rev);  
         } else if (type != CHECKOUT_REV_REMOVED) {  
                 va_start(ap, type);  
                 bp = va_arg(ap, BUF *);  
                 va_end(ap);  
         }  
   
         if (type == CHECKOUT_REV_CREATED)  
                 rcstime = rcs_rev_getdate(rf, rev);  
         else if (type == CHECKOUT_REV_MERGED ||  
             type == CHECKOUT_REV_UPDATED) {  
                 time(&rcstime);  
                 if ((rcstime = cvs_hack_time(rcstime, 1)) < 0)  
                         goto out;  
         }  
   
         if (type == CHECKOUT_REV_CREATED ||  
             type == CHECKOUT_REV_MERGED ||  
             type == CHECKOUT_REV_UPDATED) {  
                 ctime_r(&rcstime, timebuf);  
                 l = strlen(timebuf);  
                 if (l > 0 && timebuf[l - 1] == '\n')  
                         timebuf[--l] = '\0';  
   
                 l = snprintf(entry, sizeof(entry), "/%s/%s/%s/%s/", cf->cf_name,  
                     rcsnum_tostr(rev, buf, sizeof(buf)),  
                     (local == 1) ? timebuf : "",  
                     (type == CHECKOUT_REV_MERGED) ? "+=" : "");  
                 if (l == -1 || l >= (int)sizeof(buf))  
                         goto out;  
         }  
   
         if (type == CHECKOUT_REV_MERGED) {  
                 oldrev = rcsnum_alloc();  
                 rcsnum_cpy(rev, oldrev, 0);  
   
                 if (oldrev->rn_id[oldrev->rn_len - 1] <= 0)  
                         goto out;  
                 oldrev = rcsnum_dec(oldrev);  
   
                 l = snprintf(copyfile, sizeof(copyfile), ".#%s.%s",  
                     cf->cf_name, rcsnum_tostr(oldrev, buf, sizeof(buf)));  
                 if (l == -1 || l >= (int)sizeof(copyfile))  
                         goto out;  
         }  
   
         root = CVS_DIR_ROOT(cf);  
         repo = CVS_DIR_REPO(cf);  
   
         /*  
          * In local mode, just copy the entire contents to fpath.  
          * In server mode, we need to send it to the client together with  
          * some responses.  
          */  
         if (local) {  
                 l = 0;  
                 if (cf->cf_entry == NULL) {  
                         l = 1;  
                         cf->cf_entry = cvs_ent_open(cf->cf_dir, O_RDWR);  
                         if (cf->cf_entry == NULL) {  
                                 cvs_log(LP_ERR, "failed to open Entry "  
                                     "file '%s'", cf->cf_dir);  
                                 goto out;  
                         }  
                 }  
   
                 cvs_ent_remove(cf->cf_entry, cf->cf_name, 1);  
                 if (type != CHECKOUT_REV_REMOVED) {  
                         cvs_ent_addln(cf->cf_entry, entry);  
                         ent = cvs_ent_get(cf->cf_entry, cf->cf_name);  
                         ent->processed = 1;  
                 }  
   
                 if (l == 1)  
                         cvs_ent_close(cf->cf_entry);  
   
                 switch (type) {  
                 case CHECKOUT_REV_REMOVED:  
                         if (cvs_unlink(fpath) < 0)  
                                 goto out;  
                         break;  
                 case CHECKOUT_REV_MERGED:  
                         /* XXX move the old file when merging */  
                 case CHECKOUT_REV_UPDATED:  
                 case CHECKOUT_REV_CREATED:  
                         cvs_buf_write(bp, fpath, cf->cf_mode);  
                         /*  
                          * correct the time first  
                          */  
                         if ((rcstime = cvs_hack_time(rcstime, 0)) == 0)  
                                 goto out;  
   
                         tv[0].tv_sec = rcstime;  
                         tv[0].tv_usec = 0;  
                         tv[1] = tv[0];  
                         if (utimes(fpath, tv) == -1)  
                                 cvs_log(LP_ERRNO, "failed to set timestamps");  
                         break;  
                 }  
         } else {  
                 /* sanity */  
                 if (cf->cf_type != DT_REG) {  
                         cvs_log(LP_ERR, "cvs_checkout_rev: none DT_REG file");  
                         goto out;  
                 }  
   
                 /*  
                  * if we are removing a file, we don't need this stuff.  
                  */  
                 if (type != CHECKOUT_REV_REMOVED) {  
                         if ((rcstime = cvs_hack_time(rcstime, 0)) == 0)  
                                 goto out;  
   
                         tp = gmtime(&rcstime);  
                         l = snprintf(timebuf, sizeof(timebuf),  
                             "%02d %s %d %02d:%02d:%02d -0000",  
                             tp->tm_mday, month_tab[tp->tm_mon],  
                             tp->tm_year + 1900, tp->tm_hour,  
                             tp->tm_min, tp->tm_sec);  
                         if (l == -1 || l >= (int)sizeof(timebuf))  
                                 goto out;  
   
                         fsize = cvs_buf_len(bp);  
                         cvs_modetostr(cf->cf_mode, modestr, sizeof(modestr));  
                         cvs_buf_putc(bp, '\0');  
                         content = cvs_buf_release(bp);  
                         bp = NULL;  
                 }  
   
                 if (type == CHECKOUT_REV_MERGED) {  
                         printf("Copy-file %s/\n", (cf->cf_dir != NULL) ?  
                             cf->cf_dir : ".");  
                         printf("%s/%s/%s\n", root->cr_dir, repo, cf->cf_name);  
                         printf("%s\n", copyfile);  
                 }  
   
                 switch (type) {  
                 case CHECKOUT_REV_MERGED:  
                         printf("Merged");  
                         break;  
                 case CHECKOUT_REV_REMOVED:  
                         printf("Removed");  
                         break;  
                 case CHECKOUT_REV_CREATED:  
                         printf("Mod-time %s\n", timebuf);  
                         printf("Created");  
                         break;  
                 default:  
                         cvs_log(LP_ERR, "cvs_checkout_rev: bad type %d",  
                             type);  
                         goto out;  
                 }  
   
                 printf(" %s/\n", (cf->cf_dir != NULL) ? cf->cf_dir : ".");  
                 printf("%s/%s\n", repo, cf->cf_name);  
   
                 if (type != CHECKOUT_REV_REMOVED) {  
                         printf("%s\n", entry);  
                         printf("%s\n%d\n%s", modestr, fsize, content);  
                 }  
         }  
   
         ret = 0;  
   
 out:  
         if (oldrev != NULL)  
                 rcsnum_free(oldrev);  
         if (bp != NULL)  
                 cvs_buf_free(bp);  
         if (content != NULL)  
                 xfree(content);  
   
         return (ret);  
 }  
   
 #endif  /* !RCSPROG */  

Legend:
Removed from v.1.171  
changed lines
  Added in v.1.172