#include <assert.h>
#include "cvs.h"
#include "savecwd.h"
#define CVSMODULE_OPTS "+ad:lo:e:s:t:"
#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));
DBM *
open_module ()
{
char *mfile;
DBM *retval;
if (current_parsed_root == NULL)
{
error (0, 0, "must set the CVSROOT environment variable");
error (1, 0, "or specify the '-d' global option");
}
mfile = xmalloc (strlen (current_parsed_root->directory)
+ sizeof (CVSROOTADM)
+ sizeof (CVSROOTADM_MODULES) + 3);
(void) sprintf (mfile, "%s/%s/%s", current_parsed_root->directory,
CVSROOTADM, CVSROOTADM_MODULES);
retval = dbm_open (mfile, O_RDONLY, 0666);
free (mfile);
return retval;
}
void
close_module (db)
DBM *db;
{
if (db != NULL)
dbm_close (db);
}
static int
my_module (db, mname, m_type, msg, callback_proc, where, shorten,
local_specified, run_module_prog, build_dirs, extra_arg,
stack)
DBM *db;
char *mname;
enum mtype m_type;
char *msg;
CALLBACKPROC callback_proc;
char *where;
int shorten;
int local_specified;
int run_module_prog;
int build_dirs;
char *extra_arg;
List *stack;
{
char *checkout_prog = NULL;
char *export_prog = NULL;
char *tag_prog = NULL;
struct saved_cwd cwd;
int cwd_saved = 0;
char *line;
int modargc;
int xmodargc;
char **modargv;
char **xmodargv = NULL;
char *value = NULL;
char *mwhere = NULL;
char *mfile = NULL;
char *spec_opt = NULL;
char *xvalue = NULL;
int alias = 0;
datum key, val;
char *cp;
int c, err = 0;
int nonalias_opt = 0;
#ifdef SERVER_SUPPORT
int restore_server_dir = 0;
char *server_dir_to_restore = NULL;
if (trace)
{
char *buf;
buf = xmalloc (100
+ strlen (mname)
+ strlen (msg)
+ (where ? strlen (where) : 0)
+ (extra_arg ? strlen (extra_arg) : 0));
sprintf (buf, "%s-> my_module (%s, %s, %s, %s)\n",
CLIENT_SERVER_STR,
mname, msg, where ? where : "",
extra_arg ? extra_arg : "");
cvs_outerr (buf, 0);
free (buf);
}
#endif
if (isabsolute (mname))
error (1, 0, "Absolute module reference invalid: `%s'", mname);
if (pathname_levels (mname) > 0)
error (1, 0, "up-level in module reference (`..') invalid: `%s'.",
mname);
if (mname[0] == '!' && mname[1] != '\0')
{
ign_dir_add (mname+1);
goto do_module_return;
}
strip_trailing_slashes (mname);
key.dptr = mname;
key.dsize = strlen (key.dptr);
if (db != NULL)
val = dbm_fetch (db, key);
else
val.dptr = NULL;
if (val.dptr != NULL)
{
value = xmalloc (val.dsize + 1);
memcpy (value, val.dptr, val.dsize);
value[val.dsize] = '\0';
if ((cp = strchr (value, '#')) != NULL)
*cp = '\0';
else
cp = value + val.dsize;
while (cp > value && isspace ((unsigned char) *--cp))
*cp = '\0';
mwhere = xstrdup (mname);
goto found;
}
else
{
char *file;
char *attic_file;
char *acp;
int is_found = 0;
file = xmalloc (strlen (current_parsed_root->directory)
+ strlen (mname) + sizeof(RCSEXT) + 2);
(void) sprintf (file, "%s/%s", current_parsed_root->directory, mname);
attic_file = xmalloc (strlen (current_parsed_root->directory)
+ strlen (mname)
+ sizeof (CVSATTIC) + sizeof (RCSEXT) + 3);
if ((acp = strrchr (mname, '/')) != NULL)
{
*acp = '\0';
(void) sprintf (attic_file, "%s/%s/%s/%s%s", current_parsed_root->directory,
mname, CVSATTIC, acp + 1, RCSEXT);
*acp = '/';
}
else
(void) sprintf (attic_file, "%s/%s/%s%s",
current_parsed_root->directory,
CVSATTIC, mname, RCSEXT);
if (isdir (file))
{
modargv = xmalloc (sizeof (*modargv));
modargv[0] = xstrdup (mname);
modargc = 1;
is_found = 1;
}
else
{
(void) strcat (file, RCSEXT);
if (isfile (file) || isfile (attic_file))
{
if ((cp = strrchr (mname, '/')) != NULL && cp != mname)
{
modargv = xmalloc (2 * sizeof (*modargv));
modargv[0] = xmalloc (strlen (mname) + 2);
strncpy (modargv[0], mname, cp - mname);
modargv[0][cp - mname] = '\0';
modargv[1] = xstrdup (cp + 1);
modargc = 2;
}
else
{
if (cp == mname)
{
modargv = xmalloc (2 * sizeof (*modargv));
modargv[0] = xstrdup (".");
modargv[1] = xstrdup (mname + 1);
modargc = 2;
}
else
{
modargv = xmalloc (2 * sizeof (*modargv));
modargv[0] = xstrdup (".");
modargv[1] = xstrdup (mname);
modargc = 2;
}
}
is_found = 1;
}
}
free (attic_file);
free (file);
if (is_found)
{
assert (value == NULL);
if (save_cwd (&cwd))
error_exit ();
cwd_saved = 1;
err += callback_proc (modargc, modargv, where, mwhere, mfile,
shorten,
local_specified, mname, msg);
free_names (&modargc, modargv);
if (restore_cwd (&cwd, NULL))
error_exit ();
free_cwd (&cwd);
cwd_saved = 0;
goto do_module_return;
}
}
if (mname[0] != '/' && (cp = strchr (mname, '/')) != NULL)
{
*cp = '\0';
key.dptr = mname;
key.dsize = strlen (key.dptr);
if (db != NULL)
val = dbm_fetch (db, key);
else
val.dptr = NULL;
if (val.dptr != NULL)
{
char *cp2;
value = xmalloc (val.dsize + 1);
memcpy (value, val.dptr, val.dsize);
value[val.dsize] = '\0';
if ((cp2 = strchr (value, '#')) != NULL)
*cp2 = '\0';
else
cp2 = value + val.dsize;
while (cp2 > value && isspace ((unsigned char) *--cp2))
*cp2 = '\0';
mwhere = xstrdup (mname);
mfile = cp + 1;
assert (strlen (mfile));
*cp = '/';
goto found;
}
*cp = '/';
}
error (0, 0, "cannot find module `%s' - ignored", mname);
err++;
goto do_module_return;
found:
if (save_cwd (&cwd))
error_exit ();
cwd_saved = 1;
assert (value != NULL);
if ((cp = strchr (value, CVSMODULE_SPEC)) != NULL)
{
*cp = '\0';
spec_opt = cp + 1;
while (cp > value && isspace ((unsigned char) *--cp))
*cp = '\0';
}
if (mfile != NULL)
spec_opt = NULL;
line = xmalloc (strlen (value) + 5);
strcpy(line, "XXX ");
strcpy(line + 4, value);
line2argv (&xmodargc, &xmodargv, line, " \t");
free (line);
modargc = xmodargc;
modargv = xmodargv;
optind = 0;
while ((c = getopt (modargc, modargv, CVSMODULE_OPTS)) != -1)
{
switch (c)
{
case 'a':
alias = 1;
break;
case 'd':
if (mwhere)
free (mwhere);
mwhere = xstrdup (optarg);
nonalias_opt = 1;
break;
case 'l':
local_specified = 1;
nonalias_opt = 1;
break;
case 'o':
if (checkout_prog)
free (checkout_prog);
checkout_prog = xstrdup (optarg);
nonalias_opt = 1;
break;
case 'e':
if (export_prog)
free (export_prog);
export_prog = xstrdup (optarg);
nonalias_opt = 1;
break;
case 't':
if (tag_prog)
free (tag_prog);
tag_prog = xstrdup (optarg);
nonalias_opt = 1;
break;
case '?':
error (0, 0,
"modules file has invalid option for key %s value %s",
key.dptr, value);
err++;
goto do_module_return;
}
}
modargc -= optind;
modargv += optind;
if (modargc == 0 && spec_opt == NULL)
{
error (0, 0, "modules file missing directory for module %s", mname);
++err;
goto do_module_return;
}
if (alias && nonalias_opt)
{
error (0, 0, "\
-a cannot be specified in the modules file along with other options");
++err;
goto do_module_return;
}
if (alias)
{
int i;
for (i = 0; i < modargc; i++)
{
if (stack && findnode (stack, mname))
error (0, 0,
"module `%s' in modules file contains infinite loop",
mname);
else
{
if (!stack) stack = getlist();
push_string (stack, mname);
err += my_module (db, modargv[i], m_type, msg, callback_proc,
where, shorten, local_specified,
run_module_prog, build_dirs, extra_arg,
stack);
pop_string (stack);
if (isempty (stack)) dellist (&stack);
}
}
goto do_module_return;
}
if (mfile != NULL && modargc > 1)
{
error (0, 0, "\
module `%s' is a request for a file in a module which is not a directory",
mname);
++err;
goto do_module_return;
}
if (modargc > 0)
{
err += callback_proc (modargc, modargv, where, mwhere, mfile, shorten,
local_specified, mname, msg);
}
else
{
char *dir;
if (!build_dirs)
goto do_special;
dir = where ? where : (mwhere ? mwhere : mname);
make_directories (dir);
if (CVS_CHDIR (dir) < 0)
{
error (0, errno, "cannot chdir to %s", dir);
spec_opt = NULL;
err++;
goto do_special;
}
if (!isfile (CVSADM))
{
char *nullrepos;
nullrepos = emptydir_name ();
Create_Admin (".", dir,
nullrepos, (char *) NULL, (char *) NULL, 0, 0, 1);
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
}
free (nullrepos);
}
}
do_special:
free_names (&xmodargc, xmodargv);
xmodargv = NULL;
if (local_specified)
spec_opt = NULL;
#ifdef SERVER_SUPPORT
if (server_active && spec_opt != NULL)
{
char *change_to;
change_to = where ? where : (mwhere ? mwhere : mname);
server_dir_to_restore = server_dir;
restore_server_dir = 1;
server_dir =
xmalloc ((server_dir_to_restore != NULL
? strlen (server_dir_to_restore)
: 0)
+ strlen (change_to)
+ 5);
server_dir[0] = '\0';
if (server_dir_to_restore != NULL)
{
strcat (server_dir, server_dir_to_restore);
strcat (server_dir, "/");
}
strcat (server_dir, change_to);
}
#endif
while (spec_opt != NULL)
{
char *next_opt;
cp = strchr (spec_opt, CVSMODULE_SPEC);
if (cp != NULL)
{
next_opt = cp + 1;
do
*cp = '\0';
while (cp > spec_opt && isspace ((unsigned char) *--cp));
}
else
next_opt = NULL;
while (isspace ((unsigned char) *spec_opt))
spec_opt++;
if (*spec_opt == '\0')
error (0, 0, "Mal-formed %c option for module %s - ignored",
CVSMODULE_SPEC, mname);
else
err += my_module (db, spec_opt, m_type, msg, callback_proc,
(char *) NULL, 0, local_specified,
run_module_prog, build_dirs, extra_arg,
stack);
spec_opt = next_opt;
}
#ifdef SERVER_SUPPORT
if (server_active && restore_server_dir)
{
free (server_dir);
server_dir = server_dir_to_restore;
}
#endif
if (restore_cwd (&cwd, NULL))
error_exit ();
free_cwd (&cwd);
cwd_saved = 0;
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))
{
char *real_prog = NULL;
char *prog = (m_type == TAG ? tag_prog :
(m_type == CHECKOUT ? checkout_prog : export_prog));
char *real_where = (where != NULL ? where : mwhere);
char *expanded_path;
if ((*prog != '/') && (*prog != '.'))
{
real_prog = xmalloc (strlen (real_where) + strlen (prog)
+ 10);
(void) sprintf (real_prog, "%s/%s", real_where, prog);
if (isfile (real_prog))
prog = real_prog;
}
expanded_path = expand_path (prog, "modules", 0);
if (expanded_path != NULL)
{
run_setup (expanded_path);
run_arg (real_where);
if (extra_arg)
run_arg (extra_arg);
if (!quiet)
{
cvs_output (program_name, 0);
cvs_output (" ", 1);
cvs_output (cvs_cmd_name, 0);
cvs_output (": Executing '", 0);
run_print (stdout);
cvs_output ("'\n", 0);
cvs_flushout ();
}
err += run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
free (expanded_path);
}
if (real_prog) free (real_prog);
}
}
do_module_return:
if (xmodargv != NULL)
free_names (&xmodargc, xmodargv);
if (mwhere)
free (mwhere);
if (checkout_prog)
free (checkout_prog);
if (export_prog)
free (export_prog);
if (tag_prog)
free (tag_prog);
if (cwd_saved)
free_cwd (&cwd);
if (value != NULL)
free (value);
if (xvalue != NULL)
free (xvalue);
return (err);
}
int
do_module (db, mname, m_type, msg, callback_proc, where, shorten,
local_specified, run_module_prog, build_dirs, 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;
int build_dirs;
char *extra_arg;
{
return my_module (db, mname, m_type, msg, callback_proc, where, shorten,
local_specified, run_module_prog, build_dirs, extra_arg,
NULL);
}
static struct sortrec *s_head;
static int s_max = 0;
static int s_count = 0;
static int Status;
static char def_status[] = "NONE";
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 ((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;
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';
while (isspace ((unsigned char) *cp))
cp++;
while (*cp)
{
if (isspace ((unsigned char) *cp))
{
*cp2++ = ' ';
while (isspace ((unsigned char) *cp))
cp++;
}
else
*cp2++ = *cp++;
}
*cp2 = '\0';
if (Status)
{
s_rec->status = def_status;
for (cp = s_rec->rest; (cp2 = strchr (cp, '-')) != NULL; cp = ++cp2)
{
if (*(cp2 + 1) == 's' && *(cp2 + 2) == ' ')
{
char *status_start;
cp2 += 3;
status_start = cp2;
while (*cp2 != ' ' && *cp2 != '\0')
cp2++;
s_rec->status = xmalloc (cp2 - status_start + 1);
strncpy (s_rec->status, status_start, cp2 - status_start);
s_rec->status[cp2 - status_start] = '\0';
cp = cp2;
break;
}
}
}
else
cp = s_rec->rest;
if ((cp2 = cp = strchr (cp, '#')) != NULL)
{
if (*--cp2 == ' ')
*cp2 = '\0';
if (*++cp == ' ')
cp++;
s_rec->comment = cp;
}
else
s_rec->comment = "";
s_count++;
}
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 **moduleargv;
Status = status;
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);
}
close_module (db);
qsort ((PTR) s_head, s_count, sizeof (struct sortrec), sort_order);
indent = 12 + (status * 12);
fill = cols - (indent + 2);
for (s_h = s_head, i = 0; i < s_count; i++, s_h++)
{
char *line;
line = xmalloc (strlen (s_h->modname) + 15);
sprintf (line, "%-12s", s_h->modname);
cvs_output (line, 0);
free (line);
if (status)
{
line = xmalloc (strlen (s_h->status) + 15);
sprintf (line, " %-11s", s_h->status);
cvs_output (line, 0);
free (line);
}
line = xmalloc (strlen (s_h->modname) + strlen (s_h->rest) + 15);
(void) sprintf (line, "%s %s", s_h->modname, s_h->rest);
line2argv (&moduleargc, &moduleargv, line, " \t");
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')
{
char buf[5];
sprintf (buf, " -%c", c);
cvs_output (buf, 0);
wid += 3;
}
else
{
char buf[10];
if (strlen (optarg) + 4 + wid > (unsigned) fill)
{
int j;
cvs_output ("\n", 1);
for (j = 0; j < indent; ++j)
cvs_output (" ", 1);
wid = 0;
}
sprintf (buf, " -%c ", c);
cvs_output (buf, 0);
cvs_output (optarg, 0);
wid += strlen (optarg) + 4;
}
}
}
argc -= optind;
argv += optind;
for (; argc--; argv++)
{
if (strlen (*argv) + wid > (unsigned) fill)
{
int j;
cvs_output ("\n", 1);
for (j = 0; j < indent; ++j)
cvs_output (" ", 1);
wid = 0;
}
cvs_output (" ", 1);
cvs_output (*argv, 0);
wid += strlen (*argv) + 1;
}
cvs_output ("\n", 1);
for (cp2 = cp = s_h->comment; *cp; cp2 = cp)
{
int j;
for (j = 0; j < indent; ++j)
cvs_output (" ", 1);
cvs_output (" # ", 0);
if (strlen (cp2) < (unsigned) (fill - 2))
{
cvs_output (cp2, 0);
cvs_output ("\n", 1);
break;
}
cp += fill - 2;
while (*cp != ' ' && cp > cp2)
cp--;
if (cp == cp2)
{
cvs_output (cp2, 0);
cvs_output ("\n", 1);
break;
}
*cp++ = '\0';
cvs_output (cp2, 0);
cvs_output ("\n", 1);
}
free_names(&moduleargc, moduleargv);
}
}