186d7f5d3SJohn Marino /* Implementation for "cvs watch add", "cvs watchers", and related commands
286d7f5d3SJohn Marino
386d7f5d3SJohn Marino This program is free software; you can redistribute it and/or modify
486d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
586d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
686d7f5d3SJohn Marino any later version.
786d7f5d3SJohn Marino
886d7f5d3SJohn Marino This program is distributed in the hope that it will be useful,
986d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
1086d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1186d7f5d3SJohn Marino GNU General Public License for more details. */
1286d7f5d3SJohn Marino
1386d7f5d3SJohn Marino #include "cvs.h"
1486d7f5d3SJohn Marino #include "edit.h"
1586d7f5d3SJohn Marino #include "fileattr.h"
1686d7f5d3SJohn Marino #include "watch.h"
1786d7f5d3SJohn Marino
1886d7f5d3SJohn Marino const char *const watch_usage[] =
1986d7f5d3SJohn Marino {
2086d7f5d3SJohn Marino "Usage: %s %s {on|off|add|remove} [-lR] [-a <action>]... [<path>]...\n",
2186d7f5d3SJohn Marino "on/off: Turn on/off read-only checkouts of files.\n",
2286d7f5d3SJohn Marino "add/remove: Add or remove notification on actions.\n",
2386d7f5d3SJohn Marino "-l (on/off/add/remove): Local directory only, not recursive.\n",
2486d7f5d3SJohn Marino "-R (on/off/add/remove): Process directories recursively (default).\n",
2586d7f5d3SJohn Marino "-a (add/remove): Specify what actions, one of: `edit', `unedit',\n",
2686d7f5d3SJohn Marino " `commit', `all', or `none' (defaults to `all').\n",
2786d7f5d3SJohn Marino "(Specify the --help global option for a list of other help options.)\n",
2886d7f5d3SJohn Marino NULL
2986d7f5d3SJohn Marino };
3086d7f5d3SJohn Marino
3186d7f5d3SJohn Marino static struct addremove_args the_args;
3286d7f5d3SJohn Marino
3386d7f5d3SJohn Marino void
watch_modify_watchers(const char * file,struct addremove_args * what)3486d7f5d3SJohn Marino watch_modify_watchers (const char *file, struct addremove_args *what)
3586d7f5d3SJohn Marino {
3686d7f5d3SJohn Marino char *curattr = fileattr_get0 (file, "_watchers");
3786d7f5d3SJohn Marino char *p;
3886d7f5d3SJohn Marino char *pend;
3986d7f5d3SJohn Marino char *nextp;
4086d7f5d3SJohn Marino char *who;
4186d7f5d3SJohn Marino int who_len;
4286d7f5d3SJohn Marino char *mycurattr;
4386d7f5d3SJohn Marino char *mynewattr;
4486d7f5d3SJohn Marino size_t mynewattr_size;
4586d7f5d3SJohn Marino
4686d7f5d3SJohn Marino int add_edit_pending;
4786d7f5d3SJohn Marino int add_unedit_pending;
4886d7f5d3SJohn Marino int add_commit_pending;
4986d7f5d3SJohn Marino int remove_edit_pending;
5086d7f5d3SJohn Marino int remove_unedit_pending;
5186d7f5d3SJohn Marino int remove_commit_pending;
5286d7f5d3SJohn Marino int add_tedit_pending;
5386d7f5d3SJohn Marino int add_tunedit_pending;
5486d7f5d3SJohn Marino int add_tcommit_pending;
5586d7f5d3SJohn Marino
5686d7f5d3SJohn Marino TRACE( TRACE_FUNCTION, "modify_watchers ( %s )", file );
5786d7f5d3SJohn Marino
5886d7f5d3SJohn Marino who = getcaller ();
5986d7f5d3SJohn Marino who_len = strlen (who);
6086d7f5d3SJohn Marino
6186d7f5d3SJohn Marino /* Look for current watcher types for this user. */
6286d7f5d3SJohn Marino mycurattr = NULL;
6386d7f5d3SJohn Marino if (curattr != NULL)
6486d7f5d3SJohn Marino {
6586d7f5d3SJohn Marino p = curattr;
6686d7f5d3SJohn Marino while (1) {
6786d7f5d3SJohn Marino if (strncmp (who, p, who_len) == 0
6886d7f5d3SJohn Marino && p[who_len] == '>')
6986d7f5d3SJohn Marino {
7086d7f5d3SJohn Marino /* Found this user. */
7186d7f5d3SJohn Marino mycurattr = p + who_len + 1;
7286d7f5d3SJohn Marino }
7386d7f5d3SJohn Marino p = strchr (p, ',');
7486d7f5d3SJohn Marino if (p == NULL)
7586d7f5d3SJohn Marino break;
7686d7f5d3SJohn Marino ++p;
7786d7f5d3SJohn Marino }
7886d7f5d3SJohn Marino }
7986d7f5d3SJohn Marino if (mycurattr != NULL)
8086d7f5d3SJohn Marino {
8186d7f5d3SJohn Marino mycurattr = xstrdup (mycurattr);
8286d7f5d3SJohn Marino p = strchr (mycurattr, ',');
8386d7f5d3SJohn Marino if (p != NULL)
8486d7f5d3SJohn Marino *p = '\0';
8586d7f5d3SJohn Marino }
8686d7f5d3SJohn Marino
8786d7f5d3SJohn Marino /* Now copy mycurattr to mynewattr, making the requisite modifications.
8886d7f5d3SJohn Marino Note that we add a dummy '+' to the start of mynewattr, to reduce
8986d7f5d3SJohn Marino special cases (but then we strip it off when we are done). */
9086d7f5d3SJohn Marino
9186d7f5d3SJohn Marino mynewattr_size = sizeof "+edit+unedit+commit+tedit+tunedit+tcommit";
9286d7f5d3SJohn Marino if (mycurattr != NULL)
9386d7f5d3SJohn Marino mynewattr_size += strlen (mycurattr);
9486d7f5d3SJohn Marino mynewattr = xmalloc (mynewattr_size);
9586d7f5d3SJohn Marino mynewattr[0] = '\0';
9686d7f5d3SJohn Marino
9786d7f5d3SJohn Marino add_edit_pending = what->adding && what->edit;
9886d7f5d3SJohn Marino add_unedit_pending = what->adding && what->unedit;
9986d7f5d3SJohn Marino add_commit_pending = what->adding && what->commit;
10086d7f5d3SJohn Marino remove_edit_pending = !what->adding && what->edit;
10186d7f5d3SJohn Marino remove_unedit_pending = !what->adding && what->unedit;
10286d7f5d3SJohn Marino remove_commit_pending = !what->adding && what->commit;
10386d7f5d3SJohn Marino add_tedit_pending = what->add_tedit;
10486d7f5d3SJohn Marino add_tunedit_pending = what->add_tunedit;
10586d7f5d3SJohn Marino add_tcommit_pending = what->add_tcommit;
10686d7f5d3SJohn Marino
10786d7f5d3SJohn Marino /* Copy over existing watch types, except those to be removed. */
10886d7f5d3SJohn Marino p = mycurattr;
10986d7f5d3SJohn Marino while (p != NULL)
11086d7f5d3SJohn Marino {
11186d7f5d3SJohn Marino pend = strchr (p, '+');
11286d7f5d3SJohn Marino if (pend == NULL)
11386d7f5d3SJohn Marino {
11486d7f5d3SJohn Marino pend = p + strlen (p);
11586d7f5d3SJohn Marino nextp = NULL;
11686d7f5d3SJohn Marino }
11786d7f5d3SJohn Marino else
11886d7f5d3SJohn Marino nextp = pend + 1;
11986d7f5d3SJohn Marino
12086d7f5d3SJohn Marino /* Process this item. */
12186d7f5d3SJohn Marino if (pend - p == 4 && strncmp ("edit", p, 4) == 0)
12286d7f5d3SJohn Marino {
12386d7f5d3SJohn Marino if (!remove_edit_pending)
12486d7f5d3SJohn Marino strcat (mynewattr, "+edit");
12586d7f5d3SJohn Marino add_edit_pending = 0;
12686d7f5d3SJohn Marino }
12786d7f5d3SJohn Marino else if (pend - p == 6 && strncmp ("unedit", p, 6) == 0)
12886d7f5d3SJohn Marino {
12986d7f5d3SJohn Marino if (!remove_unedit_pending)
13086d7f5d3SJohn Marino strcat (mynewattr, "+unedit");
13186d7f5d3SJohn Marino add_unedit_pending = 0;
13286d7f5d3SJohn Marino }
13386d7f5d3SJohn Marino else if (pend - p == 6 && strncmp ("commit", p, 6) == 0)
13486d7f5d3SJohn Marino {
13586d7f5d3SJohn Marino if (!remove_commit_pending)
13686d7f5d3SJohn Marino strcat (mynewattr, "+commit");
13786d7f5d3SJohn Marino add_commit_pending = 0;
13886d7f5d3SJohn Marino }
13986d7f5d3SJohn Marino else if (pend - p == 5 && strncmp ("tedit", p, 5) == 0)
14086d7f5d3SJohn Marino {
14186d7f5d3SJohn Marino if (!what->remove_temp)
14286d7f5d3SJohn Marino strcat (mynewattr, "+tedit");
14386d7f5d3SJohn Marino add_tedit_pending = 0;
14486d7f5d3SJohn Marino }
14586d7f5d3SJohn Marino else if (pend - p == 7 && strncmp ("tunedit", p, 7) == 0)
14686d7f5d3SJohn Marino {
14786d7f5d3SJohn Marino if (!what->remove_temp)
14886d7f5d3SJohn Marino strcat (mynewattr, "+tunedit");
14986d7f5d3SJohn Marino add_tunedit_pending = 0;
15086d7f5d3SJohn Marino }
15186d7f5d3SJohn Marino else if (pend - p == 7 && strncmp ("tcommit", p, 7) == 0)
15286d7f5d3SJohn Marino {
15386d7f5d3SJohn Marino if (!what->remove_temp)
15486d7f5d3SJohn Marino strcat (mynewattr, "+tcommit");
15586d7f5d3SJohn Marino add_tcommit_pending = 0;
15686d7f5d3SJohn Marino }
15786d7f5d3SJohn Marino else
15886d7f5d3SJohn Marino {
15986d7f5d3SJohn Marino char *mp;
16086d7f5d3SJohn Marino
16186d7f5d3SJohn Marino /* Copy over any unrecognized watch types, for future
16286d7f5d3SJohn Marino expansion. */
16386d7f5d3SJohn Marino mp = mynewattr + strlen (mynewattr);
16486d7f5d3SJohn Marino *mp++ = '+';
16586d7f5d3SJohn Marino strncpy (mp, p, pend - p);
16686d7f5d3SJohn Marino *(mp + (pend - p)) = '\0';
16786d7f5d3SJohn Marino }
16886d7f5d3SJohn Marino
16986d7f5d3SJohn Marino /* Set up for next item. */
17086d7f5d3SJohn Marino p = nextp;
17186d7f5d3SJohn Marino }
17286d7f5d3SJohn Marino
17386d7f5d3SJohn Marino /* Add in new watch types. */
17486d7f5d3SJohn Marino if (add_edit_pending)
17586d7f5d3SJohn Marino strcat (mynewattr, "+edit");
17686d7f5d3SJohn Marino if (add_unedit_pending)
17786d7f5d3SJohn Marino strcat (mynewattr, "+unedit");
17886d7f5d3SJohn Marino if (add_commit_pending)
17986d7f5d3SJohn Marino strcat (mynewattr, "+commit");
18086d7f5d3SJohn Marino if (add_tedit_pending)
18186d7f5d3SJohn Marino strcat (mynewattr, "+tedit");
18286d7f5d3SJohn Marino if (add_tunedit_pending)
18386d7f5d3SJohn Marino strcat (mynewattr, "+tunedit");
18486d7f5d3SJohn Marino if (add_tcommit_pending)
18586d7f5d3SJohn Marino strcat (mynewattr, "+tcommit");
18686d7f5d3SJohn Marino
18786d7f5d3SJohn Marino {
18886d7f5d3SJohn Marino char *curattr_new;
18986d7f5d3SJohn Marino
19086d7f5d3SJohn Marino curattr_new =
19186d7f5d3SJohn Marino fileattr_modify (curattr,
19286d7f5d3SJohn Marino who,
19386d7f5d3SJohn Marino mynewattr[0] == '\0' ? NULL : mynewattr + 1,
19486d7f5d3SJohn Marino '>',
19586d7f5d3SJohn Marino ',');
19686d7f5d3SJohn Marino /* If the attribute is unchanged, don't rewrite the attribute file. */
19786d7f5d3SJohn Marino if (!((curattr_new == NULL && curattr == NULL)
19886d7f5d3SJohn Marino || (curattr_new != NULL
19986d7f5d3SJohn Marino && curattr != NULL
20086d7f5d3SJohn Marino && strcmp (curattr_new, curattr) == 0)))
20186d7f5d3SJohn Marino fileattr_set (file,
20286d7f5d3SJohn Marino "_watchers",
20386d7f5d3SJohn Marino curattr_new);
20486d7f5d3SJohn Marino if (curattr_new != NULL)
20586d7f5d3SJohn Marino free (curattr_new);
20686d7f5d3SJohn Marino }
20786d7f5d3SJohn Marino
20886d7f5d3SJohn Marino if (curattr != NULL)
20986d7f5d3SJohn Marino free (curattr);
21086d7f5d3SJohn Marino if (mycurattr != NULL)
21186d7f5d3SJohn Marino free (mycurattr);
21286d7f5d3SJohn Marino if (mynewattr != NULL)
21386d7f5d3SJohn Marino free (mynewattr);
21486d7f5d3SJohn Marino }
21586d7f5d3SJohn Marino
21686d7f5d3SJohn Marino static int addremove_fileproc (void *callerdat,
21786d7f5d3SJohn Marino struct file_info *finfo);
21886d7f5d3SJohn Marino
21986d7f5d3SJohn Marino static int
addremove_fileproc(void * callerdat,struct file_info * finfo)22086d7f5d3SJohn Marino addremove_fileproc (void *callerdat, struct file_info *finfo)
22186d7f5d3SJohn Marino {
22286d7f5d3SJohn Marino watch_modify_watchers (finfo->file, &the_args);
22386d7f5d3SJohn Marino return 0;
22486d7f5d3SJohn Marino }
22586d7f5d3SJohn Marino
addremove_filesdoneproc(void * callerdat,int err,const char * repository,const char * update_dir,List * entries)22686d7f5d3SJohn Marino static int addremove_filesdoneproc (void * callerdat, int err, const char * repository,
22786d7f5d3SJohn Marino const char *update_dir, List * entries)
22886d7f5d3SJohn Marino {
22986d7f5d3SJohn Marino int set_default = the_args.setting_default;
23086d7f5d3SJohn Marino int dir_check = 0;
23186d7f5d3SJohn Marino
23286d7f5d3SJohn Marino while ( !set_default && dir_check < the_args.num_dirs )
23386d7f5d3SJohn Marino {
23486d7f5d3SJohn Marino /* If we are recursing, then just see if the first part of update_dir
23586d7f5d3SJohn Marino matches any of the specified directories. Otherwise, it must be an exact
23686d7f5d3SJohn Marino match. */
23786d7f5d3SJohn Marino if ( the_args.local )
23886d7f5d3SJohn Marino set_default = strcmp( update_dir, the_args.dirs[ dir_check ] )==0;
23986d7f5d3SJohn Marino else
24086d7f5d3SJohn Marino set_default = strncmp( update_dir, the_args.dirs[ dir_check ], strlen( the_args.dirs[ dir_check ] ) ) == 0;
24186d7f5d3SJohn Marino dir_check++;
24286d7f5d3SJohn Marino }
24386d7f5d3SJohn Marino
24486d7f5d3SJohn Marino if (set_default)
24586d7f5d3SJohn Marino watch_modify_watchers (NULL, &the_args);
24686d7f5d3SJohn Marino return err;
24786d7f5d3SJohn Marino }
24886d7f5d3SJohn Marino
24986d7f5d3SJohn Marino
25086d7f5d3SJohn Marino static int
watch_addremove(int argc,char ** argv)25186d7f5d3SJohn Marino watch_addremove (int argc, char **argv)
25286d7f5d3SJohn Marino {
25386d7f5d3SJohn Marino int c;
25486d7f5d3SJohn Marino int err;
25586d7f5d3SJohn Marino int a_omitted;
25686d7f5d3SJohn Marino int arg_index;
25786d7f5d3SJohn Marino int max_dirs;
25886d7f5d3SJohn Marino
25986d7f5d3SJohn Marino a_omitted = 1;
26086d7f5d3SJohn Marino the_args.commit = 0;
26186d7f5d3SJohn Marino the_args.edit = 0;
26286d7f5d3SJohn Marino the_args.unedit = 0;
26386d7f5d3SJohn Marino the_args.num_dirs = 0;
26486d7f5d3SJohn Marino the_args.dirs = NULL;
26586d7f5d3SJohn Marino the_args.local = 0;
26686d7f5d3SJohn Marino
26786d7f5d3SJohn Marino optind = 0;
26886d7f5d3SJohn Marino while ((c = getopt (argc, argv, "+lRa:")) != -1)
26986d7f5d3SJohn Marino {
27086d7f5d3SJohn Marino switch (c)
27186d7f5d3SJohn Marino {
27286d7f5d3SJohn Marino case 'l':
27386d7f5d3SJohn Marino the_args.local = 1;
27486d7f5d3SJohn Marino break;
27586d7f5d3SJohn Marino case 'R':
27686d7f5d3SJohn Marino the_args.local = 0;
27786d7f5d3SJohn Marino break;
27886d7f5d3SJohn Marino case 'a':
27986d7f5d3SJohn Marino a_omitted = 0;
28086d7f5d3SJohn Marino if (strcmp (optarg, "edit") == 0)
28186d7f5d3SJohn Marino the_args.edit = 1;
28286d7f5d3SJohn Marino else if (strcmp (optarg, "unedit") == 0)
28386d7f5d3SJohn Marino the_args.unedit = 1;
28486d7f5d3SJohn Marino else if (strcmp (optarg, "commit") == 0)
28586d7f5d3SJohn Marino the_args.commit = 1;
28686d7f5d3SJohn Marino else if (strcmp (optarg, "all") == 0)
28786d7f5d3SJohn Marino {
28886d7f5d3SJohn Marino the_args.edit = 1;
28986d7f5d3SJohn Marino the_args.unedit = 1;
29086d7f5d3SJohn Marino the_args.commit = 1;
29186d7f5d3SJohn Marino }
29286d7f5d3SJohn Marino else if (strcmp (optarg, "none") == 0)
29386d7f5d3SJohn Marino {
29486d7f5d3SJohn Marino the_args.edit = 0;
29586d7f5d3SJohn Marino the_args.unedit = 0;
29686d7f5d3SJohn Marino the_args.commit = 0;
29786d7f5d3SJohn Marino }
29886d7f5d3SJohn Marino else
29986d7f5d3SJohn Marino usage (watch_usage);
30086d7f5d3SJohn Marino break;
30186d7f5d3SJohn Marino case '?':
30286d7f5d3SJohn Marino default:
30386d7f5d3SJohn Marino usage (watch_usage);
30486d7f5d3SJohn Marino break;
30586d7f5d3SJohn Marino }
30686d7f5d3SJohn Marino }
30786d7f5d3SJohn Marino argc -= optind;
30886d7f5d3SJohn Marino argv += optind;
30986d7f5d3SJohn Marino
31086d7f5d3SJohn Marino the_args.num_dirs = 0;
31186d7f5d3SJohn Marino max_dirs = 4; /* Arbitrary choice. */
31286d7f5d3SJohn Marino the_args.dirs = xmalloc( sizeof( const char * ) * max_dirs );
31386d7f5d3SJohn Marino
31486d7f5d3SJohn Marino TRACE (TRACE_FUNCTION, "watch_addremove (%d)", argc);
31586d7f5d3SJohn Marino for ( arg_index=0; arg_index<argc; ++arg_index )
31686d7f5d3SJohn Marino {
31786d7f5d3SJohn Marino TRACE( TRACE_FUNCTION, "\t%s", argv[ arg_index ]);
31886d7f5d3SJohn Marino if ( isdir( argv[ arg_index ] ) )
31986d7f5d3SJohn Marino {
32086d7f5d3SJohn Marino if ( the_args.num_dirs >= max_dirs )
32186d7f5d3SJohn Marino {
32286d7f5d3SJohn Marino max_dirs *= 2;
32386d7f5d3SJohn Marino the_args.dirs = (const char ** )xrealloc( (void *)the_args.dirs, max_dirs );
32486d7f5d3SJohn Marino }
32586d7f5d3SJohn Marino the_args.dirs[ the_args.num_dirs++ ] = argv[ arg_index ];
32686d7f5d3SJohn Marino }
32786d7f5d3SJohn Marino }
32886d7f5d3SJohn Marino
32986d7f5d3SJohn Marino if (a_omitted)
33086d7f5d3SJohn Marino {
33186d7f5d3SJohn Marino the_args.edit = 1;
33286d7f5d3SJohn Marino the_args.unedit = 1;
33386d7f5d3SJohn Marino the_args.commit = 1;
33486d7f5d3SJohn Marino }
33586d7f5d3SJohn Marino
33686d7f5d3SJohn Marino #ifdef CLIENT_SUPPORT
33786d7f5d3SJohn Marino if (current_parsed_root->isremote)
33886d7f5d3SJohn Marino {
33986d7f5d3SJohn Marino start_server ();
34086d7f5d3SJohn Marino ign_setup ();
34186d7f5d3SJohn Marino
34286d7f5d3SJohn Marino if (the_args.local)
34386d7f5d3SJohn Marino send_arg ("-l");
34486d7f5d3SJohn Marino /* FIXME: copes poorly with "all" if server is extended to have
34586d7f5d3SJohn Marino new watch types and client is still running an old version. */
34686d7f5d3SJohn Marino if (the_args.edit)
34786d7f5d3SJohn Marino option_with_arg ("-a", "edit");
34886d7f5d3SJohn Marino if (the_args.unedit)
34986d7f5d3SJohn Marino option_with_arg ("-a", "unedit");
35086d7f5d3SJohn Marino if (the_args.commit)
35186d7f5d3SJohn Marino option_with_arg ("-a", "commit");
35286d7f5d3SJohn Marino if (!the_args.edit && !the_args.unedit && !the_args.commit)
35386d7f5d3SJohn Marino option_with_arg ("-a", "none");
35486d7f5d3SJohn Marino send_arg ("--");
35586d7f5d3SJohn Marino send_files (argc, argv, the_args.local, 0, SEND_NO_CONTENTS);
35686d7f5d3SJohn Marino send_file_names (argc, argv, SEND_EXPAND_WILD);
35786d7f5d3SJohn Marino send_to_server (the_args.adding ?
35886d7f5d3SJohn Marino "watch-add\012" : "watch-remove\012",
35986d7f5d3SJohn Marino 0);
36086d7f5d3SJohn Marino return get_responses_and_close ();
36186d7f5d3SJohn Marino }
36286d7f5d3SJohn Marino #endif /* CLIENT_SUPPORT */
36386d7f5d3SJohn Marino
36486d7f5d3SJohn Marino the_args.setting_default = (argc <= 0);
36586d7f5d3SJohn Marino
36686d7f5d3SJohn Marino lock_tree_promotably (argc, argv, the_args.local, W_LOCAL, 0);
36786d7f5d3SJohn Marino
36886d7f5d3SJohn Marino err = start_recursion
36986d7f5d3SJohn Marino (addremove_fileproc, addremove_filesdoneproc, NULL, NULL, NULL,
37086d7f5d3SJohn Marino argc, argv, the_args.local, W_LOCAL, 0, CVS_LOCK_WRITE,
37186d7f5d3SJohn Marino NULL, 1, NULL);
37286d7f5d3SJohn Marino
37386d7f5d3SJohn Marino Lock_Cleanup ();
37486d7f5d3SJohn Marino free( (void *)the_args.dirs );
37586d7f5d3SJohn Marino the_args.dirs = NULL;
37686d7f5d3SJohn Marino
37786d7f5d3SJohn Marino return err;
37886d7f5d3SJohn Marino }
37986d7f5d3SJohn Marino
38086d7f5d3SJohn Marino
38186d7f5d3SJohn Marino
38286d7f5d3SJohn Marino int
watch_add(int argc,char ** argv)38386d7f5d3SJohn Marino watch_add (int argc, char **argv)
38486d7f5d3SJohn Marino {
38586d7f5d3SJohn Marino the_args.adding = 1;
38686d7f5d3SJohn Marino return watch_addremove (argc, argv);
38786d7f5d3SJohn Marino }
38886d7f5d3SJohn Marino
38986d7f5d3SJohn Marino int
watch_remove(int argc,char ** argv)39086d7f5d3SJohn Marino watch_remove (int argc, char **argv)
39186d7f5d3SJohn Marino {
39286d7f5d3SJohn Marino the_args.adding = 0;
39386d7f5d3SJohn Marino return watch_addremove (argc, argv);
39486d7f5d3SJohn Marino }
39586d7f5d3SJohn Marino
39686d7f5d3SJohn Marino int
watch(int argc,char ** argv)39786d7f5d3SJohn Marino watch (int argc, char **argv)
39886d7f5d3SJohn Marino {
39986d7f5d3SJohn Marino if (argc <= 1)
40086d7f5d3SJohn Marino usage (watch_usage);
40186d7f5d3SJohn Marino if (strcmp (argv[1], "on") == 0)
40286d7f5d3SJohn Marino {
40386d7f5d3SJohn Marino --argc;
40486d7f5d3SJohn Marino ++argv;
40586d7f5d3SJohn Marino return watch_on (argc, argv);
40686d7f5d3SJohn Marino }
40786d7f5d3SJohn Marino else if (strcmp (argv[1], "off") == 0)
40886d7f5d3SJohn Marino {
40986d7f5d3SJohn Marino --argc;
41086d7f5d3SJohn Marino ++argv;
41186d7f5d3SJohn Marino return watch_off (argc, argv);
41286d7f5d3SJohn Marino }
41386d7f5d3SJohn Marino else if (strcmp (argv[1], "add") == 0)
41486d7f5d3SJohn Marino {
41586d7f5d3SJohn Marino --argc;
41686d7f5d3SJohn Marino ++argv;
41786d7f5d3SJohn Marino return watch_add (argc, argv);
41886d7f5d3SJohn Marino }
41986d7f5d3SJohn Marino else if (strcmp (argv[1], "remove") == 0)
42086d7f5d3SJohn Marino {
42186d7f5d3SJohn Marino --argc;
42286d7f5d3SJohn Marino ++argv;
42386d7f5d3SJohn Marino return watch_remove (argc, argv);
42486d7f5d3SJohn Marino }
42586d7f5d3SJohn Marino else
42686d7f5d3SJohn Marino usage (watch_usage);
42786d7f5d3SJohn Marino return 0;
42886d7f5d3SJohn Marino }
42986d7f5d3SJohn Marino
43086d7f5d3SJohn Marino static const char *const watchers_usage[] =
43186d7f5d3SJohn Marino {
43286d7f5d3SJohn Marino "Usage: %s %s [-lR] [<file>]...\n",
43386d7f5d3SJohn Marino "-l\tProcess this directory only (not recursive).\n",
43486d7f5d3SJohn Marino "-R\tProcess directories recursively (default).\n",
43586d7f5d3SJohn Marino "(Specify the --help global option for a list of other help options.)\n",
43686d7f5d3SJohn Marino NULL
43786d7f5d3SJohn Marino };
43886d7f5d3SJohn Marino
43986d7f5d3SJohn Marino static int watchers_fileproc (void *callerdat,
44086d7f5d3SJohn Marino struct file_info *finfo);
44186d7f5d3SJohn Marino
44286d7f5d3SJohn Marino static int
watchers_fileproc(void * callerdat,struct file_info * finfo)44386d7f5d3SJohn Marino watchers_fileproc (void *callerdat, struct file_info *finfo)
44486d7f5d3SJohn Marino {
44586d7f5d3SJohn Marino char *them;
44686d7f5d3SJohn Marino char *p;
44786d7f5d3SJohn Marino
44886d7f5d3SJohn Marino them = fileattr_get0 (finfo->file, "_watchers");
44986d7f5d3SJohn Marino if (them == NULL)
45086d7f5d3SJohn Marino return 0;
45186d7f5d3SJohn Marino
45286d7f5d3SJohn Marino cvs_output (finfo->fullname, 0);
45386d7f5d3SJohn Marino
45486d7f5d3SJohn Marino p = them;
45586d7f5d3SJohn Marino while (1)
45686d7f5d3SJohn Marino {
45786d7f5d3SJohn Marino cvs_output ("\t", 1);
45886d7f5d3SJohn Marino while (*p != '>' && *p != '\0')
45986d7f5d3SJohn Marino cvs_output (p++, 1);
46086d7f5d3SJohn Marino if (*p == '\0')
46186d7f5d3SJohn Marino {
46286d7f5d3SJohn Marino /* Only happens if attribute is misformed. */
46386d7f5d3SJohn Marino cvs_output ("\n", 1);
46486d7f5d3SJohn Marino break;
46586d7f5d3SJohn Marino }
46686d7f5d3SJohn Marino ++p;
46786d7f5d3SJohn Marino cvs_output ("\t", 1);
46886d7f5d3SJohn Marino while (1)
46986d7f5d3SJohn Marino {
47086d7f5d3SJohn Marino while (*p != '+' && *p != ',' && *p != '\0')
47186d7f5d3SJohn Marino cvs_output (p++, 1);
47286d7f5d3SJohn Marino if (*p == '\0')
47386d7f5d3SJohn Marino {
47486d7f5d3SJohn Marino cvs_output ("\n", 1);
47586d7f5d3SJohn Marino goto out;
47686d7f5d3SJohn Marino }
47786d7f5d3SJohn Marino if (*p == ',')
47886d7f5d3SJohn Marino {
47986d7f5d3SJohn Marino ++p;
48086d7f5d3SJohn Marino break;
48186d7f5d3SJohn Marino }
48286d7f5d3SJohn Marino ++p;
48386d7f5d3SJohn Marino cvs_output ("\t", 1);
48486d7f5d3SJohn Marino }
48586d7f5d3SJohn Marino cvs_output ("\n", 1);
48686d7f5d3SJohn Marino }
48786d7f5d3SJohn Marino out:;
48886d7f5d3SJohn Marino free (them);
48986d7f5d3SJohn Marino return 0;
49086d7f5d3SJohn Marino }
49186d7f5d3SJohn Marino
49286d7f5d3SJohn Marino int
watchers(int argc,char ** argv)49386d7f5d3SJohn Marino watchers (int argc, char **argv)
49486d7f5d3SJohn Marino {
49586d7f5d3SJohn Marino int local = 0;
49686d7f5d3SJohn Marino int c;
49786d7f5d3SJohn Marino
49886d7f5d3SJohn Marino if (argc == -1)
49986d7f5d3SJohn Marino usage (watchers_usage);
50086d7f5d3SJohn Marino
50186d7f5d3SJohn Marino optind = 0;
50286d7f5d3SJohn Marino while ((c = getopt (argc, argv, "+lR")) != -1)
50386d7f5d3SJohn Marino {
50486d7f5d3SJohn Marino switch (c)
50586d7f5d3SJohn Marino {
50686d7f5d3SJohn Marino case 'l':
50786d7f5d3SJohn Marino local = 1;
50886d7f5d3SJohn Marino break;
50986d7f5d3SJohn Marino case 'R':
51086d7f5d3SJohn Marino local = 0;
51186d7f5d3SJohn Marino break;
51286d7f5d3SJohn Marino case '?':
51386d7f5d3SJohn Marino default:
51486d7f5d3SJohn Marino usage (watchers_usage);
51586d7f5d3SJohn Marino break;
51686d7f5d3SJohn Marino }
51786d7f5d3SJohn Marino }
51886d7f5d3SJohn Marino argc -= optind;
51986d7f5d3SJohn Marino argv += optind;
52086d7f5d3SJohn Marino
52186d7f5d3SJohn Marino #ifdef CLIENT_SUPPORT
52286d7f5d3SJohn Marino if (current_parsed_root->isremote)
52386d7f5d3SJohn Marino {
52486d7f5d3SJohn Marino start_server ();
52586d7f5d3SJohn Marino ign_setup ();
52686d7f5d3SJohn Marino
52786d7f5d3SJohn Marino if (local)
52886d7f5d3SJohn Marino send_arg ("-l");
52986d7f5d3SJohn Marino send_arg ("--");
53086d7f5d3SJohn Marino send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
53186d7f5d3SJohn Marino send_file_names (argc, argv, SEND_EXPAND_WILD);
53286d7f5d3SJohn Marino send_to_server ("watchers\012", 0);
53386d7f5d3SJohn Marino return get_responses_and_close ();
53486d7f5d3SJohn Marino }
53586d7f5d3SJohn Marino #endif /* CLIENT_SUPPORT */
53686d7f5d3SJohn Marino
53786d7f5d3SJohn Marino return start_recursion (watchers_fileproc, NULL, NULL,
53886d7f5d3SJohn Marino NULL, NULL, argc, argv, local, W_LOCAL, 0,
53986d7f5d3SJohn Marino CVS_LOCK_READ, NULL, 1, NULL);
54086d7f5d3SJohn Marino }
541