=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/cvs/cvs.c,v retrieving revision 1.16 retrieving revision 1.17 diff -u -r1.16 -r1.17 --- src/usr.bin/cvs/cvs.c 2004/12/06 21:58:31 1.16 +++ src/usr.bin/cvs/cvs.c 2004/12/07 06:33:10 1.17 @@ -1,4 +1,4 @@ -/* $OpenBSD: cvs.c,v 1.16 2004/12/06 21:58:31 jfb Exp $ */ +/* $OpenBSD: cvs.c,v 1.17 2004/12/07 06:33:10 jfb Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau * All rights reserved. @@ -52,13 +52,14 @@ /* compression level used with zlib, 0 meaning no compression taking place */ int cvs_compress = 0; +int cvs_readrc = 1; /* read .cvsrc on startup */ int cvs_trace = 0; int cvs_nolog = 0; int cvs_readonly = 0; -int cvs_nocase = 0; /* set to 1 to disable case sensitivity on filenames */ +int cvs_nocase = 0; /* set to 1 to disable filename case sensitivity */ -/* name of the command we are running */ -char *cvs_command; +char *cvs_defargs; /* default global arguments from .cvsrc */ +char *cvs_command; /* name of the command we are running */ int cvs_cmdop; char *cvs_rootstr; char *cvs_rsh = CVS_RSH_DEFAULT; @@ -93,66 +94,77 @@ char *cmd_synopsis; char *cmd_opts; char cmd_descr[CVS_CMD_MAXDESCRLEN]; + char *cmd_defargs; } cvs_cdt[] = { { CVS_OP_ADD, "add", { "ad", "new" }, cvs_add, "[-m msg] file ...", "", "Add a new file/directory to the repository", + NULL, }, { -1, "admin", { "adm", "rcs" }, NULL, "", "", "Administration front end for rcs", + NULL, }, { CVS_OP_ANNOTATE, "annotate", { "ann" }, NULL, "", "", "Show last revision where each line was modified", + NULL, }, { CVS_OP_CHECKOUT, "checkout", { "co", "get" }, cvs_checkout, "", "", "Checkout sources for editing", + NULL, }, { CVS_OP_COMMIT, "commit", { "ci", "com" }, cvs_commit, "[-flR] [-F logfile | -m msg] [-r rev] ...", "F:flm:Rr:", "Check files into the repository", + NULL, }, { CVS_OP_DIFF, "diff", { "di", "dif" }, cvs_diff, "[-cilu] [-D date] [-r rev] ...", "cD:ilur:", "Show differences between revisions", + NULL, }, { -1, "edit", { }, NULL, "", "", "Get ready to edit a watched file", + NULL, }, { -1, "editors", { }, NULL, "", "", "See who is editing a watched file", + NULL, }, { -1, "export", { "ex", "exp" }, NULL, "", "", "Export sources from CVS, similar to checkout", + NULL, }, { CVS_OP_HISTORY, "history", { "hi", "his" }, cvs_history, "", "", "Show repository access history", + NULL, }, { CVS_OP_IMPORT, "import", { "im", "imp" }, NULL, @@ -160,12 +172,14 @@ "repository vendor-tag release-tags ...", "b:dI:k:m:", "Import sources into CVS, using vendor branches", + NULL, }, { CVS_OP_INIT, "init", { }, cvs_init, "", "", "Create a CVS repository if it doesn't exist", + NULL, }, #if defined(HAVE_KERBEROS) { @@ -173,6 +187,7 @@ "", "", "Start a Kerberos authentication CVS server", + NULL, }, #endif { @@ -180,95 +195,111 @@ "", "", "Print out history information for files", + NULL, }, { -1, "login", {}, NULL, "", "", "Prompt for password for authenticating server", + NULL, }, { -1, "logout", {}, NULL, "", "", "Removes entry in .cvspass for remote repository", + NULL, }, { -1, "rdiff", {}, NULL, "", "", "Create 'patch' format diffs between releases", + NULL, }, { -1, "release", {}, NULL, "", "", "Indicate that a Module is no longer in use", + NULL, }, { CVS_OP_REMOVE, "remove", {}, NULL, "", "", "Remove an entry from the repository", + NULL, }, { -1, "rlog", {}, NULL, "", "", "Print out history information for a module", + NULL, }, { -1, "rtag", {}, NULL, "", "", "Add a symbolic tag to a module", + NULL, }, { CVS_OP_SERVER, "server", {}, cvs_server, "", "", "Server mode", + NULL, }, { CVS_OP_STATUS, "status", { "st", "stat" }, cvs_status, "", "", "Display status information on checked out files", + NULL, }, { CVS_OP_TAG, "tag", { "ta", "freeze" }, NULL, "", "", "Add a symbolic tag to checked out version of files", + NULL, }, { -1, "unedit", {}, NULL, "", "", "Undo an edit command", + NULL, }, { CVS_OP_UPDATE, "update", { "up", "upd" }, cvs_update, "", "", "Bring work tree in sync with repository", + NULL, }, { CVS_OP_VERSION, "version", { "ve", "ver" }, cvs_version, "", "", "Show current CVS version(s)", + NULL, }, { -1, "watch", {}, NULL, "", "", "Set watches", + NULL, }, { -1, "watchers", {}, NULL, "", "", "See who is watching a file", + NULL, }, }; @@ -278,8 +309,9 @@ void usage (void); void sigchld_hdlr (int); -void cvs_readrc (void); +void cvs_read_rcfile (void); struct cvs_cmd* cvs_findcmd (const char *); +int cvs_getopt (int, char **); /* @@ -301,13 +333,10 @@ int main(int argc, char **argv) { - char *envstr, *ep; - int ret; - u_int i, readrc; + char *envstr, *cmd_argv[CVS_CMD_MAXARG], **targv; + int i, ret, cmd_argc; struct cvs_cmd *cmdp; - readrc = 1; - if (cvs_log_init(LD_STD, 0) < 0) err(1, "failed to initialize logging"); @@ -327,6 +356,95 @@ ((envstr = getenv("EDITOR")) != NULL)) cvs_editor = envstr; + ret = cvs_getopt(argc, argv); + + argc -= ret; + argv += ret; + if (argc == 0) { + usage(); + exit(EX_USAGE); + } + cvs_command = argv[0]; + + if (cvs_readrc) { + cvs_read_rcfile(); + + if (cvs_defargs != NULL) { + targv = cvs_makeargv(cvs_defargs, &i); + if (targv == NULL) { + cvs_log(LP_ERR, + "failed to load default arguments to %s", + __progname); + exit(EX_OSERR); + } + + cvs_getopt(i, targv); + cvs_freeargv(targv, i); + free(targv); + } + } + + /* setup signal handlers */ + signal(SIGPIPE, SIG_IGN); + + cvs_file_init(); + + ret = -1; + + cmdp = cvs_findcmd(cvs_command); + if (cmdp == NULL) { + fprintf(stderr, "Unknown command: `%s'\n\n", cvs_command); + fprintf(stderr, "CVS commands are:\n"); + for (i = 0; i < (int)CVS_NBCMD; i++) + fprintf(stderr, "\t%-16s%s\n", + cvs_cdt[i].cmd_name, cvs_cdt[i].cmd_descr); + exit(EX_USAGE); + } + + if (cmdp->cmd_hdlr == NULL) { + cvs_log(LP_ERR, "command `%s' not implemented", cvs_command); + exit(1); + } + + cvs_cmdop = cmdp->cmd_op; + + cmd_argc = 0; + memset(cmd_argv, 0, sizeof(cmd_argv)); + + cmd_argv[cmd_argc++] = argv[0]; + if (cmdp->cmd_defargs != NULL) { + /* transform into a new argument vector */ + ret = cvs_getargv(cmdp->cmd_defargs, cmd_argv + 1, + CVS_CMD_MAXARG - 1); + if (ret < 0) { + cvs_log(LP_ERRNO, "failed to generate argument vector " + "from default arguments"); + exit(EX_DATAERR); + } + cmd_argc += ret; + } + for (ret = 1; ret < argc; ret++) + cmd_argv[cmd_argc++] = argv[ret]; + + ret = (*cmdp->cmd_hdlr)(cmd_argc, cmd_argv); + if (ret == EX_USAGE) { + fprintf(stderr, "Usage: %s %s %s\n", __progname, cvs_command, + cmdp->cmd_synopsis); + } + + if (cvs_files != NULL) + cvs_file_free(cvs_files); + + return (ret); +} + + +int +cvs_getopt(int argc, char **argv) +{ + int ret; + char *ep; + while ((ret = getopt(argc, argv, "b:d:e:fHlnQqrtvz:")) != -1) { switch (ret) { case 'b': @@ -344,7 +462,7 @@ cvs_editor = optarg; break; case 'f': - readrc = 0; + cvs_readrc = 0; break; case 'l': cvs_nolog = 1; @@ -389,55 +507,10 @@ } } - argc -= optind; - argv += optind; - - /* reset getopt() for use by commands */ + ret = optind; optind = 1; - optreset = 1; + optreset = 1; /* for next call */ - if (argc == 0) { - usage(); - exit(EX_USAGE); - } - - /* setup signal handlers */ - signal(SIGPIPE, SIG_IGN); - - cvs_file_init(); - - if (readrc) - cvs_readrc(); - - cvs_command = argv[0]; - ret = -1; - - cmdp = cvs_findcmd(cvs_command); - if (cmdp == NULL) { - fprintf(stderr, "Unknown command: `%s'\n\n", cvs_command); - fprintf(stderr, "CVS commands are:\n"); - for (i = 0; i < CVS_NBCMD; i++) - fprintf(stderr, "\t%-16s%s\n", - cvs_cdt[i].cmd_name, cvs_cdt[i].cmd_descr); - exit(EX_USAGE); - } - - if (cmdp->cmd_hdlr == NULL) { - cvs_log(LP_ERR, "command `%s' not implemented", cvs_command); - exit(1); - } - - cvs_cmdop = cmdp->cmd_op; - - ret = (*cmdp->cmd_hdlr)(argc, argv); - if (ret == EX_USAGE) { - fprintf(stderr, "Usage: %s %s %s\n", __progname, cvs_command, - cmdp->cmd_synopsis); - } - - if (cvs_files != NULL) - cvs_file_free(cvs_files); - return (ret); } @@ -476,7 +549,7 @@ /* - * cvs_readrc() + * cvs_read_rcfile() * * Read the CVS `.cvsrc' file in the user's home directory. If the file * exists, it should contain a list of arguments that should always be given @@ -484,9 +557,10 @@ */ void -cvs_readrc(void) +cvs_read_rcfile(void) { char rcpath[MAXPATHLEN], linebuf[128], *lp; + size_t len; struct cvs_cmd *cmdp; struct passwd *pw; FILE *fp; @@ -508,16 +582,32 @@ } while (fgets(linebuf, sizeof(linebuf), fp) != NULL) { - lp = strchr(linebuf, ' '); - - /* ignore lines with no arguments */ - if (lp == NULL) + if ((len = strlen(linebuf)) == 0) continue; + if (linebuf[len - 1] != '\n') { + cvs_log(LP_WARN, ".cvsrc line too long"); + break; + } + linebuf[--len] = '\0'; - *(lp++) = '\0'; + lp = strchr(linebuf, ' '); + if (lp == NULL) + continue; /* ignore lines with no arguments */ + *lp = '\0'; if (strcmp(linebuf, "cvs") == 0) { - /* global options */ + /* + * Global default options. In the case of cvs only, + * we keep the 'cvs' string as first argument because + * getopt() does not like starting at index 0 for + * argument processing. + */ + *lp = ' '; + cvs_defargs = strdup(linebuf); + if (cvs_defargs == NULL) + cvs_log(LP_ERRNO, + "failed to copy global arguments"); } else { + lp++; cmdp = cvs_findcmd(linebuf); if (cmdp == NULL) { cvs_log(LP_NOTICE, @@ -525,6 +615,12 @@ linebuf); continue; } + + cmdp->cmd_defargs = strdup(lp); + if (cmdp->cmd_defargs == NULL) + cvs_log(LP_ERRNO, + "failed to copy default arguments for %s", + cmdp->cmd_name); } } if (ferror(fp)) {