Index: src/checkout.c =================================================================== RCS file: /cvs/src/gnu/usr.bin/cvs/src/checkout.c,v retrieving revision 1.14 diff -u -u -r1.14 checkout.c --- src/checkout.c 8 Jan 2002 08:01:45 -0000 1.14 +++ src/checkout.c 5 May 2005 02:02:02 -0000 @@ -44,7 +44,7 @@ static const char *const checkout_usage[] = { - "Usage:\n %s %s [-ANPRcflnps] [-t id] [-r rev] [-D date] [-d dir]\n", + "Usage:\n %s %s [-ANPRcflnps] [-r rev] [-D date] [-d dir]\n", " [-j rev1] [-j rev2] [-k kopt] modules...\n", "\t-A\tReset any sticky tags/date/kopts.\n", "\t-N\tDon't shorten module paths if -d specified.\n", @@ -61,14 +61,13 @@ "\t-d dir\tCheck out into dir instead of module name.\n", "\t-k kopt\tUse RCS kopt -k option on checkout. (is sticky)\n", "\t-j rev\tMerge in changes made between current revision and rev.\n", - "\t-t id\tRCS identifier to expand on checkout.\n", "(Specify the --help global option for a list of other help options)\n", NULL }; static const char *const export_usage[] = { - "Usage: %s %s [-NRfln] [-r rev] [-t id] [-D date] [-d dir] [-k kopt] module...\n", + "Usage: %s %s [-NRfln] [-r rev] [-D date] [-d dir] [-k kopt] module...\n", "\t-N\tDon't shorten module paths if -d specified.\n", "\t-f\tForce a head revision match if tag/date not found.\n", "\t-l\tLocal directory only, not recursive\n", @@ -78,7 +77,6 @@ "\t-D date\tExport revisions as of date.\n", "\t-d dir\tExport into dir instead of module name.\n", "\t-k kopt\tUse RCS kopt -k option on checkout.\n", - "\t-t id\tRCS identifier to expand on export.\n", "(Specify the --help global option for a list of other help options)\n", NULL }; @@ -123,13 +121,13 @@ if (strcmp (command_name, "export") == 0) { m_type = EXPORT; - valid_options = "+Nnk:d:flRQqr:t:D:"; + valid_options = "+Nnk:d:flRQqr:D:"; valid_usage = export_usage; } else { m_type = CHECKOUT; - valid_options = "+ANnk:d:flRpQqcsr:t:D:j:P"; + valid_options = "+ANnk:d:flRpQqcsr:D:j:P"; valid_usage = checkout_usage; } @@ -200,11 +198,6 @@ case 'r': tag = optarg; checkout_prune_dirs = 1; - break; - case 't': - if (RCS_citag) - free(RCS_citag); - RCS_citag = strdup(optarg); break; case 'D': date = Make_Date (optarg); Index: src/cvs.h =================================================================== RCS file: /cvs/src/gnu/usr.bin/cvs/src/cvs.h,v retrieving revision 1.25 diff -u -u -r1.25 cvs.h --- src/cvs.h 9 Jun 2004 18:16:05 -0000 1.25 +++ src/cvs.h 5 May 2005 02:02:03 -0000 @@ -191,6 +191,7 @@ #define CVSROOTADM_WRITERS "writers" #define CVSROOTADM_PASSWD "passwd" #define CVSROOTADM_CONFIG "config" +#define CVSROOTADM_OPTIONS "options" #define CVSNULLREPOS "Emptydir" /* an empty directory */ @@ -369,7 +370,6 @@ extern int use_editor; extern int cvswrite; extern mode_t cvsumask; -extern char *RCS_citag; /* Access method specified in CVSroot. */ typedef enum { @@ -507,6 +507,7 @@ char *get_homedir PROTO ((void)); char *cvs_temp_name PROTO ((void)); FILE *cvs_temp_file PROTO ((char **filename)); +void parseopts PROTO ((const char *root)); int numdots PROTO((const char *s)); char *increment_revnum PROTO ((const char *)); Index: src/main.c =================================================================== RCS file: /cvs/src/gnu/usr.bin/cvs/src/main.c,v retrieving revision 1.37 diff -u -u -r1.37 main.c --- src/main.c 28 Sep 2001 23:26:33 -0000 1.37 +++ src/main.c 5 May 2005 02:02:05 -0000 @@ -50,7 +50,6 @@ int top_level_admin = 0; mode_t cvsumask = UMASK_DFLT; -char *RCS_citag = NULL; char *CurDir; @@ -978,6 +977,9 @@ if we didn't, then there would be no way to check in a new CVSROOT/config file to fix the broken one! */ parse_config (current_parsed_root->directory); + + /* Now is a convenient time to read CVSROOT/options */ + parseopts(current_parsed_root->directory); } #ifdef CLIENT_SUPPORT @@ -1162,4 +1164,57 @@ for (; *cpp; cpp++) (void) fprintf (stderr, *cpp); error_exit(); +} + +void +parseopts(root) + const char *root; +{ + char path[PATH_MAX]; + int save_errno; + char buf[1024]; + const char *p; + char *q; + FILE *fp; + + if (root == NULL) { + printf("no CVSROOT in parseopts\n"); + return; + } + p = strchr (root, ':'); + if (p) + p++; + else + p = root; + if (p == NULL) { + printf("mangled CVSROOT in parseopts\n"); + return; + } + (void) sprintf (path, "%s/%s/%s", p, CVSROOTADM, CVSROOTADM_OPTIONS); + if ((fp = fopen(path, "r")) != NULL) { + while (fgets(buf, sizeof buf, fp) != NULL) { + if (buf[0] == '#') + continue; + q = strrchr(buf, '\n'); + if (q) + *q = '\0'; + + if (!strncmp(buf, "tag=", 4)) { + char *what; + char *rcs_localid; + + rcs_localid = buf + 4; + RCS_setlocalid(rcs_localid); + } + if (!strncmp(buf, "tagexpand=", 10)) { + char *what; + char *rcs_incexc; + + rcs_incexc = buf + 10; + RCS_setincexc(rcs_incexc); + } + /* Silently ignore other commands. */ + } + fclose(fp); + } } Index: src/parseinfo.c =================================================================== RCS file: /cvs/src/gnu/usr.bin/cvs/src/parseinfo.c,v retrieving revision 1.8 diff -u -u -r1.8 parseinfo.c --- src/parseinfo.c 23 Jan 2003 20:00:20 -0000 1.8 +++ src/parseinfo.c 5 May 2005 02:02:05 -0000 @@ -336,12 +336,7 @@ } } else if (strcmp (line, "tag") == 0) { - RCS_citag = strdup(p); - if (RCS_citag == NULL) { - error (0, 0, "%s: no memory for local tag '%s'", - infopath, p); - goto error_return; - } + RCS_setlocalid(p); } else if (strcmp (line, "umask") == 0) { cvsumask = (mode_t)(strtol(p, NULL, 8) & 0777); Index: src/rcs.c =================================================================== RCS file: /cvs/src/gnu/usr.bin/cvs/src/rcs.c,v retrieving revision 1.18.4.1 diff -u -u -r1.18.4.1 rcs.c --- src/rcs.c 23 Apr 2005 02:42:18 -0000 1.18.4.1 +++ src/rcs.c 5 May 2005 02:02:10 -0000 @@ -120,6 +120,8 @@ evaluates its arguments multiple times. */ #define STREQ(a, b) ((a)[0] == (b)[0] && strcmp ((a), (b)) == 0) +static char * getfullCVSname PROTO ((char *, char **)); + /* * We don't want to use isspace() from the C library because: * @@ -3340,28 +3342,31 @@ { const char *string; size_t len; + int expandit; }; #define KEYWORD_INIT(s) (s), sizeof (s) - 1 static struct rcs_keyword keywords[] = { - { KEYWORD_INIT ("Author") }, - { KEYWORD_INIT ("Date") }, - { KEYWORD_INIT ("Header") }, - { KEYWORD_INIT ("Id") }, - { KEYWORD_INIT ("Locker") }, - { KEYWORD_INIT ("Log") }, - { KEYWORD_INIT ("Name") }, - { KEYWORD_INIT ("RCSfile") }, - { KEYWORD_INIT ("Revision") }, - { KEYWORD_INIT ("Source") }, - { KEYWORD_INIT ("State") }, - { NULL, 0 }, - { NULL, 0 } + { KEYWORD_INIT ("Author"), 1 }, + { KEYWORD_INIT ("Date"), 1 }, + { KEYWORD_INIT ("CVSHeader"), 1 }, + { KEYWORD_INIT ("Header"), 1 }, + { KEYWORD_INIT ("Id"), 1 }, + { KEYWORD_INIT ("Locker"), 1 }, + { KEYWORD_INIT ("Log"), 1 }, + { KEYWORD_INIT ("Name"), 1 }, + { KEYWORD_INIT ("RCSfile"), 1 }, + { KEYWORD_INIT ("Revision"), 1 }, + { KEYWORD_INIT ("Source"), 1 }, + { KEYWORD_INIT ("State"), 1 }, + { NULL, 0, 0 }, + { NULL, 0, 0 } }; enum keyword { KEYWORD_AUTHOR = 0, KEYWORD_DATE, + KEYWORD_CVSHEADER, KEYWORD_HEADER, KEYWORD_ID, KEYWORD_LOCKER, @@ -3373,6 +3378,7 @@ KEYWORD_STATE, KEYWORD_LOCALID }; +enum keyword keyword_local = KEYWORD_ID; /* Convert an RCS date string into a readable string. This is like the RCS date2str function. */ @@ -3508,12 +3514,6 @@ return; } - if (RCS_citag != NULL && *RCS_citag && *RCS_citag != '-' - && keywords[KEYWORD_LOCALID].string == NULL) { - keywords[KEYWORD_LOCALID].string = RCS_citag; - keywords[KEYWORD_LOCALID].len = strlen(RCS_citag); - } - /* If we are using -kkvl, dig out the locker information if any. */ locker = NULL; if (expand == KFLAG_KVL) @@ -3558,7 +3558,8 @@ slen = s - srch; for (keyword = keywords; keyword->string != NULL; keyword++) { - if (keyword->len == slen + if (keyword->expandit + && keyword->len == slen && strncmp (keyword->string, srch, slen) == 0) { break; @@ -3605,6 +3606,7 @@ free_value = 1; break; + case KEYWORD_CVSHEADER: case KEYWORD_HEADER: case KEYWORD_ID: case KEYWORD_LOCALID: @@ -3612,9 +3614,17 @@ char *path; int free_path; char *date; + char *old_path; - if (kw == KEYWORD_HEADER) + old_path = NULL; + if (kw == KEYWORD_HEADER || + (kw == KEYWORD_LOCALID && + keyword_local == KEYWORD_HEADER)) path = rcs->path; + else if (kw == KEYWORD_CVSHEADER || + (kw == KEYWORD_LOCALID && + keyword_local == KEYWORD_CVSHEADER)) + path = getfullCVSname(rcs->path, &old_path); else path = last_component (rcs->path); path = escape_keyword_value (path, &free_path); @@ -3634,6 +3644,8 @@ locker != NULL ? locker : ""); if (free_path) free (path); + if (old_path) + free (old_path); free (date); free_value = 1; } @@ -8428,4 +8440,106 @@ (void) sprintf (label, "-L%s\t%s", path, datebuf); } return label; +} + +void +RCS_setlocalid (arg) + const char *arg; +{ + char *copy, *next, *key; + + copy = xstrdup(arg); + next = copy; + key = strtok(next, "="); + + keywords[KEYWORD_LOCALID].string = xstrdup(key); + keywords[KEYWORD_LOCALID].len = strlen(key); + keywords[KEYWORD_LOCALID].expandit = 1; + + /* options? */ + while (key = strtok(NULL, ",")) { + if (!strcmp(key, keywords[KEYWORD_ID].string)) + keyword_local = KEYWORD_ID; + else if (!strcmp(key, keywords[KEYWORD_HEADER].string)) + keyword_local = KEYWORD_HEADER; + else if (!strcmp(key, keywords[KEYWORD_CVSHEADER].string)) + keyword_local = KEYWORD_CVSHEADER; + else + error(1, 0, "Unknown LocalId mode: %s", key); + } + free(copy); +} + +void +RCS_setincexc (arg) + const char *arg; +{ + char *key; + char *copy, *next; + int include = 0; + struct rcs_keyword *keyword; + + copy = xstrdup(arg); + next = copy; + switch (*next++) { + case 'e': + include = 0; + break; + case 'i': + include = 1; + break; + default: + free(copy); + return; + } + + if (include) + for (keyword = keywords; keyword->string != NULL; keyword++) + { + keyword->expandit = 0; + } + + key = strtok(next, ","); + while (key) { + for (keyword = keywords; keyword->string != NULL; keyword++) { + if (strcmp (keyword->string, key) == 0) + keyword->expandit = include; + } + key = strtok(NULL, ","); + } + free(copy); + return; +} + +#define ATTIC "/" CVSATTIC +static char * +getfullCVSname(CVSname, pathstore) + char *CVSname, **pathstore; +{ + if (current_parsed_root->directory) { + int rootlen; + char *c = NULL; + int alen = sizeof(ATTIC) - 1; + + *pathstore = xstrdup(CVSname); + if ((c = strrchr(*pathstore, '/')) != NULL) { + if (c - *pathstore >= alen) { + if (!strncmp(c - alen, ATTIC, alen)) { + while (*c != '\0') { + *(c - alen) = *c; + c++; + } + *(c - alen) = '\0'; + } + } + } + + rootlen = strlen(current_parsed_root->directory); + if (!strncmp(*pathstore, current_parsed_root->directory, rootlen) && + (*pathstore)[rootlen] == '/') + CVSname = (*pathstore + rootlen + 1); + else + CVSname = (*pathstore); + } + return CVSname; } Index: src/rcs.h =================================================================== RCS file: /cvs/src/gnu/usr.bin/cvs/src/rcs.h,v retrieving revision 1.1.1.15 diff -u -u -r1.1.1.15 rcs.h --- src/rcs.h 28 Sep 2001 22:45:39 -0000 1.1.1.15 +++ src/rcs.h 5 May 2005 02:02:11 -0000 @@ -240,6 +240,8 @@ void RCS_deltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *, char *, enum rcs_delta_op, char **, size_t *, char **, size_t *)); +void RCS_setincexc PROTO ((const char *arg)); +void RCS_setlocalid PROTO ((const char *arg)); char *make_file_label PROTO ((char *, char *, RCSNode *)); extern int preserve_perms; Index: src/server.c =================================================================== RCS file: /cvs/src/gnu/usr.bin/cvs/src/server.c,v retrieving revision 1.31 diff -u -u -r1.31 server.c --- src/server.c 9 Jun 2004 18:16:05 -0000 1.31 +++ src/server.c 5 May 2005 02:02:15 -0000 @@ -785,6 +785,9 @@ nothing. But for rsh, we need to do it now. */ parse_config (current_parsed_root->directory); + /* Now is a good time to read CVSROOT/options too. */ + parseopts(current_parsed_root->directory); + path = malloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM) + 2); Index: src/update.c =================================================================== RCS file: /cvs/src/gnu/usr.bin/cvs/src/update.c,v retrieving revision 1.20 diff -u -u -r1.20 update.c --- src/update.c 6 May 2003 18:41:15 -0000 1.20 +++ src/update.c 5 May 2005 02:02:18 -0000 @@ -109,7 +109,7 @@ static const char *const update_usage[] = { "Usage: %s %s [-APCdflRp] [-k kopt] [-r rev] [-D date] [-j rev]\n", - " [-I ign] [-W spec] [-t id] [files...]\n", + " [-I ign] [-W spec] [files...]\n", "\t-A\tReset any sticky tags/date/kopts.\n", "\t-P\tPrune empty directories.\n", "\t-C\tOverwrite locally modified files with clean repository copies.\n", @@ -124,7 +124,6 @@ "\t-j rev\tMerge in changes made between current revision and rev.\n", "\t-I ign\tMore files to ignore (! to reset).\n", "\t-W spec\tWrappers specification line.\n", - "\t-t id\tRCS identifier to expand on update.\n", "(Specify the --help global option for a list of other help options)\n", NULL }; @@ -149,7 +148,7 @@ /* parse the args */ optind = 0; - while ((c = getopt (argc, argv, "+ApCPflRQqduk:r:t:D:j:I:W:")) != -1) + while ((c = getopt (argc, argv, "+ApCPflRQqduk:r:D:j:I:W:")) != -1) { switch (c) { @@ -195,11 +194,6 @@ break; case 'r': tag = optarg; - break; - case 't': - if (RCS_citag) - free(RCS_citag); - RCS_citag = strdup(optarg); break; case 'D': date = Make_Date (optarg);