summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/modules.c
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1996-08-20 23:46:10 +0000
committerpeter <peter@FreeBSD.org>1996-08-20 23:46:10 +0000
commit8982e501c77217c860f79bba431f46a62b607a21 (patch)
tree70187fdf5be4cbefd0baf46bddac7e5e32c13c24 /contrib/cvs/src/modules.c
parent01ee40fd6a76f6ff7ef247fc1b2cf6e337f216c5 (diff)
downloadFreeBSD-src-8982e501c77217c860f79bba431f46a62b607a21.zip
FreeBSD-src-8982e501c77217c860f79bba431f46a62b607a21.tar.gz
Import of slightly trimmed cvs-1.8 distribution. Generated files
and non-unix code has been left out.
Diffstat (limited to 'contrib/cvs/src/modules.c')
-rw-r--r--contrib/cvs/src/modules.c900
1 files changed, 900 insertions, 0 deletions
diff --git a/contrib/cvs/src/modules.c b/contrib/cvs/src/modules.c
new file mode 100644
index 0000000..0e07c0b
--- /dev/null
+++ b/contrib/cvs/src/modules.c
@@ -0,0 +1,900 @@
+/*
+ * Copyright (c) 1992, Brian Berliner and Jeff Polk
+ * Copyright (c) 1989-1992, Brian Berliner
+ *
+ * You may distribute under the terms of the GNU General Public License
+ * as specified in the README file that comes with the CVS 1.4 kit.
+ *
+ * Modules
+ *
+ * Functions for accessing the modules file.
+ *
+ * The modules file supports basically three formats of lines:
+ * key [options] directory files... [ -x directory [files] ] ...
+ * key [options] directory [ -x directory [files] ] ...
+ * key -a aliases...
+ *
+ * The -a option allows an aliasing step in the parsing of the modules
+ * file. The "aliases" listed on a line following the -a are
+ * processed one-by-one, as if they were specified as arguments on the
+ * command line.
+ */
+
+#include "cvs.h"
+#include "savecwd.h"
+
+
+/* Defines related to the syntax of the modules file. */
+
+/* Options in modules file. Note that it is OK to use GNU getopt features;
+ we already are arranging to make sure we are using the getopt distributed
+ with CVS. */
+#define CVSMODULE_OPTS "+ad:i:lo:e:s:t:u:"
+
+/* Special delimiter. */
+#define CVSMODULE_SPEC '&'
+
+struct sortrec
+{
+ char *modname;
+ char *status;
+ char *rest;
+ char *comment;
+};
+
+static int sort_order PROTO((const PTR l, const PTR r));
+static void save_d PROTO((char *k, int ks, char *d, int ds));
+
+
+/*
+ * Open the modules file, and die if the CVSROOT environment variable
+ * was not set. If the modules file does not exist, that's fine, and
+ * a warning message is displayed and a NULL is returned.
+ */
+DBM *
+open_module ()
+{
+ char mfile[PATH_MAX];
+
+ if (CVSroot == NULL)
+ {
+ (void) fprintf (stderr,
+ "%s: must set the CVSROOT environment variable\n",
+ program_name);
+ error (1, 0, "or specify the '-d' option to %s", program_name);
+ }
+ (void) sprintf (mfile, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_MODULES);
+ return (dbm_open (mfile, O_RDONLY, 0666));
+}
+
+/*
+ * Close the modules file, if the open succeeded, that is
+ */
+void
+close_module (db)
+ DBM *db;
+{
+ if (db != NULL)
+ dbm_close (db);
+}
+
+/*
+ * This is the recursive function that processes a module name.
+ * It calls back the passed routine for each directory of a module
+ * It runs the post checkout or post tag proc from the modules file
+ */
+int
+do_module (db, mname, m_type, msg, callback_proc, where,
+ shorten, local_specified, run_module_prog, extra_arg)
+ DBM *db;
+ char *mname;
+ enum mtype m_type;
+ char *msg;
+ CALLBACKPROC callback_proc;
+ char *where;
+ int shorten;
+ int local_specified;
+ int run_module_prog;
+ char *extra_arg;
+{
+ char *checkin_prog = NULL;
+ char *checkout_prog = NULL;
+ char *export_prog = NULL;
+ char *tag_prog = NULL;
+ char *update_prog = NULL;
+ struct saved_cwd cwd;
+ char *line;
+ int modargc;
+ int xmodargc;
+ char **modargv;
+ char *xmodargv[MAXFILEPERDIR];
+ char *value;
+ char *zvalue;
+ char *mwhere = NULL;
+ char *mfile = NULL;
+ char *spec_opt = NULL;
+ char xvalue[PATH_MAX];
+ int alias = 0;
+ datum key, val;
+ char *cp;
+ int c, err = 0;
+
+#ifdef SERVER_SUPPORT
+ if (trace)
+ {
+ fprintf (stderr, "%s%c-> do_module (%s, %s, %s, %s)\n",
+ error_use_protocol ? "E " : "",
+ (server_active) ? 'S' : ' ',
+ mname, msg, where ? where : "",
+ extra_arg ? extra_arg : "");
+ }
+#endif
+
+ /* if this is a directory to ignore, add it to that list */
+ if (mname[0] == '!' && mname[1] != '\0')
+ {
+ ign_dir_add (mname+1);
+ return(err);
+ }
+
+ /* strip extra stuff from the module name */
+ strip_path (mname);
+
+ /*
+ * Look up the module using the following scheme:
+ * 1) look for mname as a module name
+ * 2) look for mname as a directory
+ * 3) look for mname as a file
+ * 4) take mname up to the first slash and look it up as a module name
+ * (this is for checking out only part of a module)
+ */
+
+ /* look it up as a module name */
+ key.dptr = mname;
+ key.dsize = strlen (key.dptr);
+ if (db != NULL)
+ val = dbm_fetch (db, key);
+ else
+ val.dptr = NULL;
+ if (val.dptr != NULL)
+ {
+ /* null terminate the value XXX - is this space ours? */
+ val.dptr[val.dsize] = '\0';
+
+ /* If the line ends in a comment, strip it off */
+ if ((cp = strchr (val.dptr, '#')) != NULL)
+ {
+ do
+ *cp-- = '\0';
+ while (isspace (*cp));
+ }
+ else
+ {
+ /* Always strip trailing spaces */
+ cp = strchr (val.dptr, '\0');
+ while (cp > val.dptr && isspace(*--cp))
+ *cp = '\0';
+ }
+
+ value = val.dptr;
+ mwhere = xstrdup (mname);
+ goto found;
+ }
+ else
+ {
+ char file[PATH_MAX];
+ char attic_file[PATH_MAX];
+ char *acp;
+
+ /* check to see if mname is a directory or file */
+
+ (void) sprintf (file, "%s/%s", CVSroot, mname);
+ if ((acp = strrchr (mname, '/')) != NULL)
+ {
+ *acp = '\0';
+ (void) sprintf (attic_file, "%s/%s/%s/%s%s", CVSroot, mname,
+ CVSATTIC, acp + 1, RCSEXT);
+ *acp = '/';
+ }
+ else
+ (void) sprintf (attic_file, "%s/%s/%s%s", CVSroot, CVSATTIC,
+ mname, RCSEXT);
+
+ if (isdir (file))
+ {
+ value = mname;
+ goto found;
+ }
+ else
+ {
+ (void) strcat (file, RCSEXT);
+ if (isfile (file) || isfile (attic_file))
+ {
+ /* if mname was a file, we have to split it into "dir file" */
+ if ((cp = strrchr (mname, '/')) != NULL && cp != mname)
+ {
+ char *slashp;
+
+ /* put the ' ' in a copy so we don't mess up the original */
+ value = strcpy (xvalue, mname);
+ slashp = strrchr (value, '/');
+ *slashp = ' ';
+ }
+ else
+ {
+ /*
+ * the only '/' at the beginning or no '/' at all
+ * means the file we are interested in is in CVSROOT
+ * itself so the directory should be '.'
+ */
+ if (cp == mname)
+ {
+ /* drop the leading / if specified */
+ value = strcpy (xvalue, ". ");
+ (void) strcat (xvalue, mname + 1);
+ }
+ else
+ {
+ /* otherwise just copy it */
+ value = strcpy (xvalue, ". ");
+ (void) strcat (xvalue, mname);
+ }
+ }
+ goto found;
+ }
+ }
+ }
+
+ /* look up everything to the first / as a module */
+ if (mname[0] != '/' && (cp = strchr (mname, '/')) != NULL)
+ {
+ /* Make the slash the new end of the string temporarily */
+ *cp = '\0';
+ key.dptr = mname;
+ key.dsize = strlen (key.dptr);
+
+ /* do the lookup */
+ if (db != NULL)
+ val = dbm_fetch (db, key);
+ else
+ val.dptr = NULL;
+
+ /* if we found it, clean up the value and life is good */
+ if (val.dptr != NULL)
+ {
+ char *cp2;
+
+ /* null terminate the value XXX - is this space ours? */
+ val.dptr[val.dsize] = '\0';
+
+ /* If the line ends in a comment, strip it off */
+ if ((cp2 = strchr (val.dptr, '#')) != NULL)
+ {
+ do
+ *cp2-- = '\0';
+ while (isspace (*cp2));
+ }
+ value = val.dptr;
+
+ /* mwhere gets just the module name */
+ mwhere = xstrdup (mname);
+ mfile = cp + 1;
+
+ /* put the / back in mname */
+ *cp = '/';
+
+ goto found;
+ }
+
+ /* put the / back in mname */
+ *cp = '/';
+ }
+
+ /* if we got here, we couldn't find it using our search, so give up */
+ error (0, 0, "cannot find module `%s' - ignored", mname);
+ err++;
+ if (mwhere)
+ free (mwhere);
+ return (err);
+
+
+ /*
+ * At this point, we found what we were looking for in one
+ * of the many different forms.
+ */
+ found:
+
+ /* remember where we start */
+ if (save_cwd (&cwd))
+ exit (EXIT_FAILURE);
+
+ /* copy value to our own string since if we go recursive we'll be
+ really screwed if we do another dbm lookup */
+ zvalue = xstrdup (value);
+ value = zvalue;
+
+ /* search the value for the special delimiter and save for later */
+ if ((cp = strchr (value, CVSMODULE_SPEC)) != NULL)
+ {
+ *cp = '\0'; /* null out the special char */
+ spec_opt = cp + 1; /* save the options for later */
+
+ if (cp != value) /* strip whitespace if necessary */
+ while (isspace (*--cp))
+ *cp = '\0';
+
+ if (cp == value)
+ {
+ /*
+ * we had nothing but special options, so skip arg
+ * parsing and regular stuff entirely
+ *
+ * If there were only special ones though, we must
+ * make the appropriate directory and cd to it
+ */
+ char *dir;
+
+ /* XXX - XXX - MAJOR HACK - DO NOT SHIP - this needs to
+ be !pipeout, but we don't know that here yet */
+ if (!run_module_prog)
+ goto out;
+
+ dir = where ? where : mname;
+ /* XXX - think about making null repositories at each dir here
+ instead of just at the bottom */
+ make_directories (dir);
+ if (chdir (dir) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", dir);
+ spec_opt = NULL;
+ err++;
+ goto out;
+ }
+ if (!isfile (CVSADM))
+ {
+ char nullrepos[PATH_MAX];
+
+ (void) sprintf (nullrepos, "%s/%s/%s", CVSroot,
+ CVSROOTADM, CVSNULLREPOS);
+ if (!isfile (nullrepos))
+ {
+ mode_t omask;
+ omask = umask (cvsumask);
+ (void) CVS_MKDIR (nullrepos, 0777);
+ (void) umask (omask);
+ }
+ if (!isdir (nullrepos))
+ error (1, 0, "there is no repository %s", nullrepos);
+
+ Create_Admin (".", dir,
+ nullrepos, (char *) NULL, (char *) NULL);
+ if (!noexec)
+ {
+ FILE *fp;
+
+ fp = open_file (CVSADM_ENTSTAT, "w+");
+ if (fclose (fp) == EOF)
+ error (1, errno, "cannot close %s", CVSADM_ENTSTAT);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_set_entstat (dir, nullrepos);
+#endif
+ }
+ }
+ out:
+ goto do_special;
+ }
+ }
+
+ /* don't do special options only part of a module was specified */
+ if (mfile != NULL)
+ spec_opt = NULL;
+
+ /*
+ * value now contains one of the following:
+ * 1) dir
+ * 2) dir file
+ * 3) the value from modules without any special args
+ * [ args ] dir [file] [file] ...
+ * or -a module [ module ] ...
+ */
+
+ /* Put the value on a line with XXX prepended for getopt to eat */
+ line = xmalloc (strlen (value) + 10);
+ (void) sprintf (line, "%s %s", "XXX", value);
+
+ /* turn the line into an argv[] array */
+ line2argv (&xmodargc, xmodargv, line);
+ free (line);
+ modargc = xmodargc;
+ modargv = xmodargv;
+
+ /* parse the args */
+ optind = 1;
+ while ((c = getopt (modargc, modargv, CVSMODULE_OPTS)) != -1)
+ {
+ switch (c)
+ {
+ case 'a':
+ alias = 1;
+ break;
+ case 'd':
+ if (mwhere)
+ free (mwhere);
+ mwhere = xstrdup (optarg);
+ break;
+ case 'i':
+ checkin_prog = optarg;
+ break;
+ case 'l':
+ local_specified = 1;
+ break;
+ case 'o':
+ checkout_prog = optarg;
+ break;
+ case 'e':
+ export_prog = optarg;
+ break;
+ case 't':
+ tag_prog = optarg;
+ break;
+ case 'u':
+ update_prog = optarg;
+ break;
+ case '?':
+ error (0, 0,
+ "modules file has invalid option for key %s value %s",
+ key.dptr, val.dptr);
+ err++;
+ if (mwhere)
+ free (mwhere);
+ free (zvalue);
+ free_cwd (&cwd);
+ return (err);
+ }
+ }
+ modargc -= optind;
+ modargv += optind;
+ if (modargc == 0)
+ {
+ error (0, 0, "modules file missing directory for module %s", mname);
+ if (mwhere)
+ free (mwhere);
+ free (zvalue);
+ free_cwd (&cwd);
+ return (++err);
+ }
+
+ /* if this was an alias, call ourselves recursively for each module */
+ if (alias)
+ {
+ int i;
+
+ for (i = 0; i < modargc; i++)
+ {
+ if (strcmp (mname, modargv[i]) == 0)
+ error (0, 0,
+ "module `%s' in modules file contains infinite loop",
+ mname);
+ else
+ err += do_module (db, modargv[i], m_type, msg, callback_proc,
+ where, shorten, local_specified,
+ run_module_prog, extra_arg);
+ }
+ if (mwhere)
+ free (mwhere);
+ free (zvalue);
+ free_cwd (&cwd);
+ return (err);
+ }
+
+ /* otherwise, process this module */
+ err += callback_proc (&modargc, modargv, where, mwhere, mfile, shorten,
+ local_specified, mname, msg);
+
+#if 0
+ /* FIXME: I've fixed this so that the correct arguments are called,
+ but now this fails because there is code below this point that
+ uses optarg values extracted from the arg vector. */
+ free_names (&xmodargc, xmodargv);
+#endif
+
+ /* if there were special include args, process them now */
+
+ do_special:
+
+ /* blow off special options if -l was specified */
+ if (local_specified)
+ spec_opt = NULL;
+
+ while (spec_opt != NULL)
+ {
+ char *next_opt;
+
+ cp = strchr (spec_opt, CVSMODULE_SPEC);
+ if (cp != NULL)
+ {
+ /* save the beginning of the next arg */
+ next_opt = cp + 1;
+
+ /* strip whitespace off the end */
+ do
+ *cp = '\0';
+ while (isspace (*--cp));
+ }
+ else
+ next_opt = NULL;
+
+ /* strip whitespace from front */
+ while (isspace (*spec_opt))
+ spec_opt++;
+
+ if (*spec_opt == '\0')
+ error (0, 0, "Mal-formed %c option for module %s - ignored",
+ CVSMODULE_SPEC, mname);
+ else
+ err += do_module (db, spec_opt, m_type, msg, callback_proc,
+ (char *) NULL, 0, local_specified,
+ run_module_prog, extra_arg);
+ spec_opt = next_opt;
+ }
+
+ /* write out the checkin/update prog files if necessary */
+#ifdef SERVER_SUPPORT
+ if (err == 0 && !noexec && m_type == CHECKOUT && server_expanding)
+ {
+ if (checkin_prog != NULL)
+ server_prog (where ? where : mname, checkin_prog, PROG_CHECKIN);
+ if (update_prog != NULL)
+ server_prog (where ? where : mname, update_prog, PROG_UPDATE);
+ }
+ else
+#endif
+ if (err == 0 && !noexec && m_type == CHECKOUT && run_module_prog)
+ {
+ FILE *fp;
+
+ if (checkin_prog != NULL)
+ {
+ fp = open_file (CVSADM_CIPROG, "w+");
+ (void) fprintf (fp, "%s\n", checkin_prog);
+ if (fclose (fp) == EOF)
+ error (1, errno, "cannot close %s", CVSADM_CIPROG);
+ }
+ if (update_prog != NULL)
+ {
+ fp = open_file (CVSADM_UPROG, "w+");
+ (void) fprintf (fp, "%s\n", update_prog);
+ if (fclose (fp) == EOF)
+ error (1, errno, "cannot close %s", CVSADM_UPROG);
+ }
+ }
+
+ /* cd back to where we started */
+ if (restore_cwd (&cwd, NULL))
+ exit (EXIT_FAILURE);
+ free_cwd (&cwd);
+
+ /* run checkout or tag prog if appropriate */
+ if (err == 0 && run_module_prog)
+ {
+ if ((m_type == TAG && tag_prog != NULL) ||
+ (m_type == CHECKOUT && checkout_prog != NULL) ||
+ (m_type == EXPORT && export_prog != NULL))
+ {
+ /*
+ * If a relative pathname is specified as the checkout, tag
+ * or export proc, try to tack on the current "where" value.
+ * if we can't find a matching program, just punt and use
+ * whatever is specified in the modules file.
+ */
+ char real_prog[PATH_MAX];
+ char *prog = (m_type == TAG ? tag_prog :
+ (m_type == CHECKOUT ? checkout_prog : export_prog));
+ char *real_where = (where != NULL ? where : mwhere);
+
+ if ((*prog != '/') && (*prog != '.'))
+ {
+ (void) sprintf (real_prog, "%s/%s", real_where, prog);
+ if (isfile (real_prog))
+ prog = real_prog;
+ }
+
+ run_setup ("%s %s", prog, real_where);
+ if (extra_arg)
+ run_arg (extra_arg);
+
+ if (!quiet)
+ {
+ (void) printf ("%s %s: Executing '", program_name,
+ command_name);
+ run_print (stdout);
+ (void) printf ("'\n");
+ }
+ err += run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ }
+ }
+
+ /* clean up */
+ if (mwhere)
+ free (mwhere);
+ free (zvalue);
+
+ return (err);
+}
+
+/* - Read all the records from the modules database into an array.
+ - Sort the array depending on what format is desired.
+ - Print the array in the format desired.
+
+ Currently, there are only two "desires":
+
+ 1. Sort by module name and format the whole entry including switches,
+ files and the comment field: (Including aliases)
+
+ modulename -s switches, one per line, even if
+ -i it has many switches.
+ Directories and files involved, formatted
+ to cover multiple lines if necessary.
+ # Comment, also formatted to cover multiple
+ # lines if necessary.
+
+ 2. Sort by status field string and print: (*not* including aliases)
+
+ modulename STATUS Directories and files involved, formatted
+ to cover multiple lines if necessary.
+ # Comment, also formatted to cover multiple
+ # lines if necessary.
+*/
+
+static struct sortrec *s_head;
+
+static int s_max = 0; /* Number of elements allocated */
+static int s_count = 0; /* Number of elements used */
+
+static int Status; /* Nonzero if the user is
+ interested in status
+ information as well as
+ module name */
+static char def_status[] = "NONE";
+
+/* Sort routine for qsort:
+ - If we want the "Status" field to be sorted, check it first.
+ - Then compare the "module name" fields. Since they are unique, we don't
+ have to look further.
+*/
+static int
+sort_order (l, r)
+ const PTR l;
+ const PTR r;
+{
+ int i;
+ const struct sortrec *left = (const struct sortrec *) l;
+ const struct sortrec *right = (const struct sortrec *) r;
+
+ if (Status)
+ {
+ /* If Sort by status field, compare them. */
+ if ((i = strcmp (left->status, right->status)) != 0)
+ return (i);
+ }
+ return (strcmp (left->modname, right->modname));
+}
+
+static void
+save_d (k, ks, d, ds)
+ char *k;
+ int ks;
+ char *d;
+ int ds;
+{
+ char *cp, *cp2;
+ struct sortrec *s_rec;
+
+ if (Status && *d == '-' && *(d + 1) == 'a')
+ return; /* We want "cvs co -s" and it is an alias! */
+
+ if (s_count == s_max)
+ {
+ s_max += 64;
+ s_head = (struct sortrec *) xrealloc ((char *) s_head, s_max * sizeof (*s_head));
+ }
+ s_rec = &s_head[s_count];
+ s_rec->modname = cp = xmalloc (ks + 1);
+ (void) strncpy (cp, k, ks);
+ *(cp + ks) = '\0';
+
+ s_rec->rest = cp2 = xmalloc (ds + 1);
+ cp = d;
+ *(cp + ds) = '\0'; /* Assumes an extra byte at end of static dbm buffer */
+
+ while (isspace (*cp))
+ cp++;
+ /* Turn <spaces> into one ' ' -- makes the rest of this routine simpler */
+ while (*cp)
+ {
+ if (isspace (*cp))
+ {
+ *cp2++ = ' ';
+ while (isspace (*cp))
+ cp++;
+ }
+ else
+ *cp2++ = *cp++;
+ }
+ *cp2 = '\0';
+
+ /* Look for the "-s statusvalue" text */
+ if (Status)
+ {
+ s_rec->status = def_status;
+
+ /* Minor kluge, but general enough to maintain */
+ for (cp = s_rec->rest; (cp2 = strchr (cp, '-')) != NULL; cp = ++cp2)
+ {
+ if (*(cp2 + 1) == 's' && *(cp2 + 2) == ' ')
+ {
+ s_rec->status = (cp2 += 3);
+ while (*cp2 != ' ')
+ cp2++;
+ *cp2++ = '\0';
+ cp = cp2;
+ break;
+ }
+ }
+ }
+ else
+ cp = s_rec->rest;
+
+ /* Find comment field, clean up on all three sides & compress blanks */
+ if ((cp2 = cp = strchr (cp, '#')) != NULL)
+ {
+ if (*--cp2 == ' ')
+ *cp2 = '\0';
+ if (*++cp == ' ')
+ cp++;
+ s_rec->comment = cp;
+ }
+ else
+ s_rec->comment = "";
+
+ s_count++;
+}
+
+/* Print out the module database as we know it. If STATUS is
+ non-zero, print out status information for each module. */
+
+void
+cat_module (status)
+ int status;
+{
+ DBM *db;
+ datum key, val;
+ int i, c, wid, argc, cols = 80, indent, fill;
+ int moduleargc;
+ struct sortrec *s_h;
+ char *cp, *cp2, **argv;
+ char *line;
+ char *moduleargv[MAXFILEPERDIR];
+
+#ifdef sun
+#ifdef TIOCGSIZE
+ struct ttysize ts;
+
+ (void) ioctl (0, TIOCGSIZE, &ts);
+ cols = ts.ts_cols;
+#endif
+#else
+#ifdef TIOCGWINSZ
+ struct winsize ws;
+
+ (void) ioctl (0, TIOCGWINSZ, &ws);
+ cols = ws.ws_col;
+#endif
+#endif
+
+ Status = status;
+
+ /* Read the whole modules file into allocated records */
+ if (!(db = open_module ()))
+ error (1, 0, "failed to open the modules file");
+
+ for (key = dbm_firstkey (db); key.dptr != NULL; key = dbm_nextkey (db))
+ {
+ val = dbm_fetch (db, key);
+ if (val.dptr != NULL)
+ save_d (key.dptr, key.dsize, val.dptr, val.dsize);
+ }
+
+ /* Sort the list as requested */
+ qsort ((PTR) s_head, s_count, sizeof (struct sortrec), sort_order);
+
+ /*
+ * Run through the sorted array and format the entries
+ * indent = space for modulename + space for status field
+ */
+ indent = 12 + (status * 12);
+ fill = cols - (indent + 2);
+ for (s_h = s_head, i = 0; i < s_count; i++, s_h++)
+ {
+ /* Print module name (and status, if wanted) */
+ (void) printf ("%-12s", s_h->modname);
+ if (status)
+ {
+ (void) printf (" %-11s", s_h->status);
+ if (s_h->status != def_status)
+ *(s_h->status + strlen (s_h->status)) = ' ';
+ }
+
+ /* Parse module file entry as command line and print options */
+ line = xmalloc (strlen (s_h->modname) + strlen (s_h->rest) + 10);
+ (void) sprintf (line, "%s %s", s_h->modname, s_h->rest);
+ line2argv (&moduleargc, moduleargv, line);
+ free (line);
+ argc = moduleargc;
+ argv = moduleargv;
+
+ optind = 0;
+ wid = 0;
+ while ((c = getopt (argc, argv, CVSMODULE_OPTS)) != -1)
+ {
+ if (!status)
+ {
+ if (c == 'a' || c == 'l')
+ {
+ (void) printf (" -%c", c);
+ wid += 3; /* Could just set it to 3 */
+ }
+ else
+ {
+ if (strlen (optarg) + 4 + wid > (unsigned) fill)
+ {
+ (void) printf ("\n%*s", indent, "");
+ wid = 0;
+ }
+ (void) printf (" -%c %s", c, optarg);
+ wid += strlen (optarg) + 4;
+ }
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Format and Print all the files and directories */
+ for (; argc--; argv++)
+ {
+ if (strlen (*argv) + wid > (unsigned) fill)
+ {
+ (void) printf ("\n%*s", indent, "");
+ wid = 0;
+ }
+ (void) printf (" %s", *argv);
+ wid += strlen (*argv) + 1;
+ }
+ (void) printf ("\n");
+
+ /* Format the comment field -- save_d (), compressed spaces */
+ for (cp2 = cp = s_h->comment; *cp; cp2 = cp)
+ {
+ (void) printf ("%*s # ", indent, "");
+ if (strlen (cp2) < (unsigned) (fill - 2))
+ {
+ (void) printf ("%s\n", cp2);
+ break;
+ }
+ cp += fill - 2;
+ while (*cp != ' ' && cp > cp2)
+ cp--;
+ if (cp == cp2)
+ {
+ (void) printf ("%s\n", cp2);
+ break;
+ }
+
+ *cp++ = '\0';
+ (void) printf ("%s\n", cp2);
+ }
+
+ free_names(&moduleargc, moduleargv);
+ }
+}
OpenPOWER on IntegriCloud