summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/watch.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/watch.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/watch.c')
-rw-r--r--contrib/cvs/src/watch.c521
1 files changed, 521 insertions, 0 deletions
diff --git a/contrib/cvs/src/watch.c b/contrib/cvs/src/watch.c
new file mode 100644
index 0000000..0873489
--- /dev/null
+++ b/contrib/cvs/src/watch.c
@@ -0,0 +1,521 @@
+/* Implementation for "cvs watch add", "cvs watchers", and related commands
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "cvs.h"
+#include "edit.h"
+#include "fileattr.h"
+#include "watch.h"
+
+const char *const watch_usage[] =
+{
+ "Usage: %s %s [on|off|add|remove] [-l] [-a action] [files...]\n",
+ "on/off: turn on/off read-only checkouts of files\n",
+ "add/remove: add or remove notification on actions\n",
+ "-l (on/off/add/remove): Local directory only, not recursive\n",
+ "-a (add/remove): Specify what actions, one of\n",
+ " edit,unedit,commit,all,none\n",
+ NULL
+};
+
+static struct addremove_args the_args;
+
+void
+watch_modify_watchers (file, what)
+ char *file;
+ struct addremove_args *what;
+{
+ char *curattr = fileattr_get0 (file, "_watchers");
+ char *p;
+ char *pend;
+ char *nextp;
+ char *who;
+ int who_len;
+ char *mycurattr;
+ char *mynewattr;
+ size_t mynewattr_size;
+
+ int add_edit_pending;
+ int add_unedit_pending;
+ int add_commit_pending;
+ int remove_edit_pending;
+ int remove_unedit_pending;
+ int remove_commit_pending;
+ int add_tedit_pending;
+ int add_tunedit_pending;
+ int add_tcommit_pending;
+
+ who = getcaller ();
+ who_len = strlen (who);
+
+ /* Look for current watcher types for this user. */
+ mycurattr = NULL;
+ if (curattr != NULL)
+ {
+ p = curattr;
+ while (1) {
+ if (strncmp (who, p, who_len) == 0
+ && p[who_len] == '>')
+ {
+ /* Found this user. */
+ mycurattr = p + who_len + 1;
+ }
+ p = strchr (p, ',');
+ if (p == NULL)
+ break;
+ ++p;
+ }
+ }
+ if (mycurattr != NULL)
+ {
+ mycurattr = xstrdup (mycurattr);
+ p = strchr (mycurattr, ',');
+ if (p != NULL)
+ *p = '\0';
+ }
+
+ /* Now copy mycurattr to mynewattr, making the requisite modifications.
+ Note that we add a dummy '+' to the start of mynewattr, to reduce
+ special cases (but then we strip it off when we are done). */
+
+ mynewattr_size = sizeof "+edit+unedit+commit+tedit+tunedit+tcommit";
+ if (mycurattr != NULL)
+ mynewattr_size += strlen (mycurattr);
+ mynewattr = xmalloc (mynewattr_size);
+ mynewattr[0] = '\0';
+
+ add_edit_pending = what->adding && what->edit;
+ add_unedit_pending = what->adding && what->unedit;
+ add_commit_pending = what->adding && what->commit;
+ remove_edit_pending = !what->adding && what->edit;
+ remove_unedit_pending = !what->adding && what->unedit;
+ remove_commit_pending = !what->adding && what->commit;
+ add_tedit_pending = what->add_tedit;
+ add_tunedit_pending = what->add_tunedit;
+ add_tcommit_pending = what->add_tcommit;
+
+ /* Copy over existing watch types, except those to be removed. */
+ p = mycurattr;
+ while (p != NULL)
+ {
+ pend = strchr (p, '+');
+ if (pend == NULL)
+ {
+ pend = p + strlen (p);
+ nextp = NULL;
+ }
+ else
+ nextp = pend + 1;
+
+ /* Process this item. */
+ if (pend - p == 4 && strncmp ("edit", p, 4) == 0)
+ {
+ if (!remove_edit_pending)
+ strcat (mynewattr, "+edit");
+ add_edit_pending = 0;
+ }
+ else if (pend - p == 6 && strncmp ("unedit", p, 6) == 0)
+ {
+ if (!remove_unedit_pending)
+ strcat (mynewattr, "+unedit");
+ add_unedit_pending = 0;
+ }
+ else if (pend - p == 6 && strncmp ("commit", p, 6) == 0)
+ {
+ if (!remove_commit_pending)
+ strcat (mynewattr, "+commit");
+ add_commit_pending = 0;
+ }
+ else if (pend - p == 5 && strncmp ("tedit", p, 5) == 0)
+ {
+ if (!what->remove_temp)
+ strcat (mynewattr, "+tedit");
+ add_tedit_pending = 0;
+ }
+ else if (pend - p == 7 && strncmp ("tunedit", p, 7) == 0)
+ {
+ if (!what->remove_temp)
+ strcat (mynewattr, "+tunedit");
+ add_tunedit_pending = 0;
+ }
+ else if (pend - p == 7 && strncmp ("tcommit", p, 7) == 0)
+ {
+ if (!what->remove_temp)
+ strcat (mynewattr, "+tcommit");
+ add_tcommit_pending = 0;
+ }
+ else
+ {
+ char *mp;
+
+ /* Copy over any unrecognized watch types, for future
+ expansion. */
+ mp = mynewattr + strlen (mynewattr);
+ *mp++ = '+';
+ strncpy (mp, p, pend - p);
+ *(mp + (pend - p)) = '\0';
+ }
+
+ /* Set up for next item. */
+ p = nextp;
+ }
+
+ /* Add in new watch types. */
+ if (add_edit_pending)
+ strcat (mynewattr, "+edit");
+ if (add_unedit_pending)
+ strcat (mynewattr, "+unedit");
+ if (add_commit_pending)
+ strcat (mynewattr, "+commit");
+ if (add_tedit_pending)
+ strcat (mynewattr, "+tedit");
+ if (add_tunedit_pending)
+ strcat (mynewattr, "+tunedit");
+ if (add_tcommit_pending)
+ strcat (mynewattr, "+tcommit");
+
+ {
+ char *curattr_new;
+
+ curattr_new =
+ fileattr_modify (curattr,
+ who,
+ mynewattr[0] == '\0' ? NULL : mynewattr + 1,
+ '>',
+ ',');
+ /* If the attribute is unchanged, don't rewrite the attribute file. */
+ if (!((curattr_new == NULL && curattr == NULL)
+ || (curattr_new != NULL
+ && curattr != NULL
+ && strcmp (curattr_new, curattr) == 0)))
+ fileattr_set (file,
+ "_watchers",
+ curattr_new);
+ if (curattr_new != NULL)
+ free (curattr_new);
+ }
+
+ if (curattr != NULL)
+ free (curattr);
+ if (mycurattr != NULL)
+ free (mycurattr);
+ if (mynewattr != NULL)
+ free (mynewattr);
+}
+
+static int addremove_fileproc PROTO ((struct file_info *finfo));
+
+static int
+addremove_fileproc (finfo)
+ struct file_info *finfo;
+{
+ watch_modify_watchers (finfo->file, &the_args);
+ return 0;
+}
+
+static int addremove_filesdoneproc PROTO ((int, char *, char *));
+
+static int
+addremove_filesdoneproc (err, repository, update_dir)
+ int err;
+ char *repository;
+ char *update_dir;
+{
+ if (the_args.setting_default)
+ watch_modify_watchers (NULL, &the_args);
+ return err;
+}
+
+static int watch_addremove PROTO ((int argc, char **argv));
+
+static int
+watch_addremove (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int local = 0;
+ int err;
+ int a_omitted;
+
+ a_omitted = 1;
+ the_args.commit = 0;
+ the_args.edit = 0;
+ the_args.unedit = 0;
+ optind = 1;
+ while ((c = getopt (argc, argv, "la:")) != -1)
+ {
+ switch (c)
+ {
+ case 'l':
+ local = 1;
+ break;
+ case 'a':
+ a_omitted = 0;
+ if (strcmp (optarg, "edit") == 0)
+ the_args.edit = 1;
+ else if (strcmp (optarg, "unedit") == 0)
+ the_args.unedit = 1;
+ else if (strcmp (optarg, "commit") == 0)
+ the_args.commit = 1;
+ else if (strcmp (optarg, "all") == 0)
+ {
+ the_args.edit = 1;
+ the_args.unedit = 1;
+ the_args.commit = 1;
+ }
+ else if (strcmp (optarg, "none") == 0)
+ {
+ the_args.edit = 0;
+ the_args.unedit = 0;
+ the_args.commit = 0;
+ }
+ else
+ usage (watch_usage);
+ break;
+ case '?':
+ default:
+ usage (watch_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (a_omitted)
+ {
+ the_args.edit = 1;
+ the_args.unedit = 1;
+ the_args.commit = 1;
+ }
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ start_server ();
+ ign_setup ();
+
+ if (local)
+ send_arg ("-l");
+ /* FIXME: copes poorly with "all" if server is extended to have
+ new watch types and client is still running an old version. */
+ if (the_args.edit)
+ {
+ send_arg ("-a");
+ send_arg ("edit");
+ }
+ if (the_args.unedit)
+ {
+ send_arg ("-a");
+ send_arg ("unedit");
+ }
+ if (the_args.commit)
+ {
+ send_arg ("-a");
+ send_arg ("commit");
+ }
+ if (!the_args.edit && !the_args.unedit && !the_args.commit)
+ {
+ send_arg ("-a");
+ send_arg ("none");
+ }
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+ /* FIXME: We shouldn't have to send current files, but I'm not sure
+ whether it works. So send the files --
+ it's slower but it works. */
+ send_files (argc, argv, local, 0);
+ send_to_server (the_args.adding ?
+ "watch-add\012" : "watch-remove\012",
+ 0);
+ return get_responses_and_close ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ the_args.setting_default = (argc <= 0);
+
+ lock_tree_for_write (argc, argv, local, 0);
+
+ err = start_recursion (addremove_fileproc, addremove_filesdoneproc,
+ (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL,
+ argc, argv, local, W_LOCAL, 0, 0, (char *)NULL,
+ 1, 0);
+
+ lock_tree_cleanup ();
+ return err;
+}
+
+int
+watch_add (argc, argv)
+ int argc;
+ char **argv;
+{
+ the_args.adding = 1;
+ return watch_addremove (argc, argv);
+}
+
+int
+watch_remove (argc, argv)
+ int argc;
+ char **argv;
+{
+ the_args.adding = 0;
+ return watch_addremove (argc, argv);
+}
+
+int
+watch (argc, argv)
+ int argc;
+ char **argv;
+{
+ if (argc <= 1)
+ usage (watch_usage);
+ if (strcmp (argv[1], "on") == 0)
+ {
+ --argc;
+ ++argv;
+ return watch_on (argc, argv);
+ }
+ else if (strcmp (argv[1], "off") == 0)
+ {
+ --argc;
+ ++argv;
+ return watch_off (argc, argv);
+ }
+ else if (strcmp (argv[1], "add") == 0)
+ {
+ --argc;
+ ++argv;
+ return watch_add (argc, argv);
+ }
+ else if (strcmp (argv[1], "remove") == 0)
+ {
+ --argc;
+ ++argv;
+ return watch_remove (argc, argv);
+ }
+ else
+ usage (watch_usage);
+ return 0;
+}
+
+static const char *const watchers_usage[] =
+{
+ "Usage: %s %s [files...]\n",
+ NULL
+};
+
+static int watchers_fileproc PROTO ((struct file_info *finfo));
+
+static int
+watchers_fileproc (finfo)
+ struct file_info *finfo;
+{
+ char *them;
+ char *p;
+
+ them = fileattr_get0 (finfo->file, "_watchers");
+ if (them == NULL)
+ return 0;
+
+ fputs (finfo->fullname, stdout);
+
+ p = them;
+ while (1)
+ {
+ putc ('\t', stdout);
+ while (*p != '>' && *p != '\0')
+ putc (*p++, stdout);
+ if (*p == '\0')
+ {
+ /* Only happens if attribute is misformed. */
+ putc ('\n', stdout);
+ break;
+ }
+ ++p;
+ putc ('\t', stdout);
+ while (1)
+ {
+ while (*p != '+' && *p != ',' && *p != '\0')
+ putc (*p++, stdout);
+ if (*p == '\0')
+ {
+ putc ('\n', stdout);
+ goto out;
+ }
+ if (*p == ',')
+ {
+ ++p;
+ break;
+ }
+ ++p;
+ putc ('\t', stdout);
+ }
+ putc ('\n', stdout);
+ }
+ out:;
+ return 0;
+}
+
+int
+watchers (argc, argv)
+ int argc;
+ char **argv;
+{
+ int local = 0;
+ int c;
+
+ if (argc == -1)
+ usage (watchers_usage);
+
+ optind = 1;
+ while ((c = getopt (argc, argv, "l")) != -1)
+ {
+ switch (c)
+ {
+ case 'l':
+ local = 1;
+ break;
+ case '?':
+ default:
+ usage (watchers_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ start_server ();
+ ign_setup ();
+
+ if (local)
+ send_arg ("-l");
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+ /* FIXME: We shouldn't have to send current files, but I'm not sure
+ whether it works. So send the files --
+ it's slower but it works. */
+ send_files (argc, argv, local, 0);
+ send_to_server ("watchers\012", 0);
+ return get_responses_and_close ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ return start_recursion (watchers_fileproc, (FILESDONEPROC) NULL,
+ (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL,
+ argc, argv, local, W_LOCAL, 0, 1, (char *)NULL,
+ 1, 0);
+}
OpenPOWER on IntegriCloud