]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/cvs/src/watch.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / cvs / src / watch.c
1 /* Implementation for "cvs watch add", "cvs watchers", and related commands
2
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.  */
12
13 #include "cvs.h"
14 #include "edit.h"
15 #include "fileattr.h"
16 #include "watch.h"
17
18 const char *const watch_usage[] =
19 {
20     "Usage: %s %s {on|off|add|remove} [-lR] [-a <action>]... [<path>]...\n",
21     "on/off: Turn on/off read-only checkouts of files.\n",
22     "add/remove: Add or remove notification on actions.\n",
23     "-l (on/off/add/remove): Local directory only, not recursive.\n",
24     "-R (on/off/add/remove): Process directories recursively (default).\n",
25     "-a (add/remove): Specify what actions, one of: `edit', `unedit',\n",
26     "                 `commit', `all', or `none' (defaults to `all').\n",
27     "(Specify the --help global option for a list of other help options.)\n",
28     NULL
29 };
30
31 static struct addremove_args the_args;
32
33 void
34 watch_modify_watchers (file, what)
35     const char *file;
36     struct addremove_args *what;
37 {
38     char *curattr = fileattr_get0 (file, "_watchers");
39     char *p;
40     char *pend;
41     char *nextp;
42     char *who;
43     int who_len;
44     char *mycurattr;
45     char *mynewattr;
46     size_t mynewattr_size;
47
48     int add_edit_pending;
49     int add_unedit_pending;
50     int add_commit_pending;
51     int remove_edit_pending;
52     int remove_unedit_pending;
53     int remove_commit_pending;
54     int add_tedit_pending;
55     int add_tunedit_pending;
56     int add_tcommit_pending;
57
58     who = getcaller ();
59     who_len = strlen (who);
60
61     /* Look for current watcher types for this user.  */
62     mycurattr = NULL;
63     if (curattr != NULL)
64     {
65         p = curattr;
66         while (1) {
67             if (strncmp (who, p, who_len) == 0
68                 && p[who_len] == '>')
69             {
70                 /* Found this user.  */
71                 mycurattr = p + who_len + 1;
72             }
73             p = strchr (p, ',');
74             if (p == NULL)
75                 break;
76             ++p;
77         }
78     }
79     if (mycurattr != NULL)
80     {
81         mycurattr = xstrdup (mycurattr);
82         p = strchr (mycurattr, ',');
83         if (p != NULL)
84             *p = '\0';
85     }
86
87     /* Now copy mycurattr to mynewattr, making the requisite modifications.
88        Note that we add a dummy '+' to the start of mynewattr, to reduce
89        special cases (but then we strip it off when we are done).  */
90
91     mynewattr_size = sizeof "+edit+unedit+commit+tedit+tunedit+tcommit";
92     if (mycurattr != NULL)
93         mynewattr_size += strlen (mycurattr);
94     mynewattr = xmalloc (mynewattr_size);
95     mynewattr[0] = '\0';
96
97     add_edit_pending = what->adding && what->edit;
98     add_unedit_pending = what->adding && what->unedit;
99     add_commit_pending = what->adding && what->commit;
100     remove_edit_pending = !what->adding && what->edit;
101     remove_unedit_pending = !what->adding && what->unedit;
102     remove_commit_pending = !what->adding && what->commit;
103     add_tedit_pending = what->add_tedit;
104     add_tunedit_pending = what->add_tunedit;
105     add_tcommit_pending = what->add_tcommit;
106
107     /* Copy over existing watch types, except those to be removed.  */
108     p = mycurattr;
109     while (p != NULL)
110     {
111         pend = strchr (p, '+');
112         if (pend == NULL)
113         {
114             pend = p + strlen (p);
115             nextp = NULL;
116         }
117         else
118             nextp = pend + 1;
119
120         /* Process this item.  */
121         if (pend - p == 4 && strncmp ("edit", p, 4) == 0)
122         {
123             if (!remove_edit_pending)
124                 strcat (mynewattr, "+edit");
125             add_edit_pending = 0;
126         }
127         else if (pend - p == 6 && strncmp ("unedit", p, 6) == 0)
128         {
129             if (!remove_unedit_pending)
130                 strcat (mynewattr, "+unedit");
131             add_unedit_pending = 0;
132         }
133         else if (pend - p == 6 && strncmp ("commit", p, 6) == 0)
134         {
135             if (!remove_commit_pending)
136                 strcat (mynewattr, "+commit");
137             add_commit_pending = 0;
138         }
139         else if (pend - p == 5 && strncmp ("tedit", p, 5) == 0)
140         {
141             if (!what->remove_temp)
142                 strcat (mynewattr, "+tedit");
143             add_tedit_pending = 0;
144         }
145         else if (pend - p == 7 && strncmp ("tunedit", p, 7) == 0)
146         {
147             if (!what->remove_temp)
148                 strcat (mynewattr, "+tunedit");
149             add_tunedit_pending = 0;
150         }
151         else if (pend - p == 7 && strncmp ("tcommit", p, 7) == 0)
152         {
153             if (!what->remove_temp)
154                 strcat (mynewattr, "+tcommit");
155             add_tcommit_pending = 0;
156         }
157         else
158         {
159             char *mp;
160
161             /* Copy over any unrecognized watch types, for future
162                expansion.  */
163             mp = mynewattr + strlen (mynewattr);
164             *mp++ = '+';
165             strncpy (mp, p, pend - p);
166             *(mp + (pend - p)) = '\0';
167         }
168
169         /* Set up for next item.  */
170         p = nextp;
171     }
172
173     /* Add in new watch types.  */
174     if (add_edit_pending)
175         strcat (mynewattr, "+edit");
176     if (add_unedit_pending)
177         strcat (mynewattr, "+unedit");
178     if (add_commit_pending)
179         strcat (mynewattr, "+commit");
180     if (add_tedit_pending)
181         strcat (mynewattr, "+tedit");
182     if (add_tunedit_pending)
183         strcat (mynewattr, "+tunedit");
184     if (add_tcommit_pending)
185         strcat (mynewattr, "+tcommit");
186
187     {
188         char *curattr_new;
189
190         curattr_new =
191           fileattr_modify (curattr,
192                            who,
193                            mynewattr[0] == '\0' ? NULL : mynewattr + 1,
194                            '>',
195                            ',');
196         /* If the attribute is unchanged, don't rewrite the attribute file.  */
197         if (!((curattr_new == NULL && curattr == NULL)
198               || (curattr_new != NULL
199                   && curattr != NULL
200                   && strcmp (curattr_new, curattr) == 0)))
201             fileattr_set (file,
202                           "_watchers",
203                           curattr_new);
204         if (curattr_new != NULL)
205             free (curattr_new);
206     }
207
208     if (curattr != NULL)
209         free (curattr);
210     if (mycurattr != NULL)
211         free (mycurattr);
212     if (mynewattr != NULL)
213         free (mynewattr);
214 }
215
216 static int addremove_fileproc PROTO ((void *callerdat,
217                                       struct file_info *finfo));
218
219 static int
220 addremove_fileproc (callerdat, finfo)
221     void *callerdat;
222     struct file_info *finfo;
223 {
224     watch_modify_watchers (finfo->file, &the_args);
225     return 0;
226 }
227
228
229
230 static int addremove_filesdoneproc PROTO ((void *, int, const char *,
231                                            const char *, List *));
232
233 static int
234 addremove_filesdoneproc (callerdat, err, repository, update_dir, entries)
235     void *callerdat;
236     int err;
237     const char *repository;
238     const char *update_dir;
239     List *entries;
240 {
241     if (the_args.setting_default)
242         watch_modify_watchers (NULL, &the_args);
243     return err;
244 }
245
246 static int watch_addremove PROTO ((int argc, char **argv));
247
248 static int
249 watch_addremove (argc, argv)
250     int argc;
251     char **argv;
252 {
253     int c;
254     int local = 0;
255     int err;
256     int a_omitted;
257
258     a_omitted = 1;
259     the_args.commit = 0;
260     the_args.edit = 0;
261     the_args.unedit = 0;
262     optind = 0;
263     while ((c = getopt (argc, argv, "+lRa:")) != -1)
264     {
265         switch (c)
266         {
267             case 'l':
268                 local = 1;
269                 break;
270             case 'R':
271                 local = 0;
272                 break;
273             case 'a':
274                 a_omitted = 0;
275                 if (strcmp (optarg, "edit") == 0)
276                     the_args.edit = 1;
277                 else if (strcmp (optarg, "unedit") == 0)
278                     the_args.unedit = 1;
279                 else if (strcmp (optarg, "commit") == 0)
280                     the_args.commit = 1;
281                 else if (strcmp (optarg, "all") == 0)
282                 {
283                     the_args.edit = 1;
284                     the_args.unedit = 1;
285                     the_args.commit = 1;
286                 }
287                 else if (strcmp (optarg, "none") == 0)
288                 {
289                     the_args.edit = 0;
290                     the_args.unedit = 0;
291                     the_args.commit = 0;
292                 }
293                 else
294                     usage (watch_usage);
295                 break;
296             case '?':
297             default:
298                 usage (watch_usage);
299                 break;
300         }
301     }
302     argc -= optind;
303     argv += optind;
304
305     if (a_omitted)
306     {
307         the_args.edit = 1;
308         the_args.unedit = 1;
309         the_args.commit = 1;
310     }
311
312 #ifdef CLIENT_SUPPORT
313     if (current_parsed_root->isremote)
314     {
315         start_server ();
316         ign_setup ();
317
318         if (local)
319             send_arg ("-l");
320         /* FIXME: copes poorly with "all" if server is extended to have
321            new watch types and client is still running an old version.  */
322         if (the_args.edit)
323             option_with_arg ("-a", "edit");
324         if (the_args.unedit)
325             option_with_arg ("-a", "unedit");
326         if (the_args.commit)
327             option_with_arg ("-a", "commit");
328         if (!the_args.edit && !the_args.unedit && !the_args.commit)
329             option_with_arg ("-a", "none");
330         send_arg ("--");
331         send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
332         send_file_names (argc, argv, SEND_EXPAND_WILD);
333         send_to_server (the_args.adding ?
334                         "watch-add\012" : "watch-remove\012",
335                         0);
336         return get_responses_and_close ();
337     }
338 #endif /* CLIENT_SUPPORT */
339
340     the_args.setting_default = (argc <= 0);
341
342     lock_tree_for_write (argc, argv, local, W_LOCAL, 0);
343
344     err = start_recursion (addremove_fileproc, addremove_filesdoneproc,
345                            (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
346                            argc, argv, local, W_LOCAL, 0, CVS_LOCK_NONE,
347                            (char *) NULL, 1, (char *) NULL);
348
349     Lock_Cleanup ();
350     return err;
351 }
352
353 int
354 watch_add (argc, argv)
355     int argc;
356     char **argv;
357 {
358     the_args.adding = 1;
359     return watch_addremove (argc, argv);
360 }
361
362 int
363 watch_remove (argc, argv)
364     int argc;
365     char **argv;
366 {
367     the_args.adding = 0;
368     return watch_addremove (argc, argv);
369 }
370
371 int
372 watch (argc, argv)
373     int argc;
374     char **argv;
375 {
376     if (argc <= 1)
377         usage (watch_usage);
378     if (strcmp (argv[1], "on") == 0)
379     {
380         --argc;
381         ++argv;
382         return watch_on (argc, argv);
383     }
384     else if (strcmp (argv[1], "off") == 0)
385     {
386         --argc;
387         ++argv;
388         return watch_off (argc, argv);
389     }
390     else if (strcmp (argv[1], "add") == 0)
391     {
392         --argc;
393         ++argv;
394         return watch_add (argc, argv);
395     }
396     else if (strcmp (argv[1], "remove") == 0)
397     {
398         --argc;
399         ++argv;
400         return watch_remove (argc, argv);
401     }
402     else
403         usage (watch_usage);
404     return 0;
405 }
406
407 static const char *const watchers_usage[] =
408 {
409     "Usage: %s %s [-lR] [<file>]...\n",
410     "-l\tProcess this directory only (not recursive).\n",
411     "-R\tProcess directories recursively (default).\n",
412     "(Specify the --help global option for a list of other help options.)\n",
413     NULL
414 };
415
416 static int watchers_fileproc PROTO ((void *callerdat,
417                                      struct file_info *finfo));
418
419 static int
420 watchers_fileproc (callerdat, finfo)
421     void *callerdat;
422     struct file_info *finfo;
423 {
424     char *them;
425     char *p;
426
427     them = fileattr_get0 (finfo->file, "_watchers");
428     if (them == NULL)
429         return 0;
430
431     cvs_output (finfo->fullname, 0);
432
433     p = them;
434     while (1)
435     {
436         cvs_output ("\t", 1);
437         while (*p != '>' && *p != '\0')
438             cvs_output (p++, 1);
439         if (*p == '\0')
440         {
441             /* Only happens if attribute is misformed.  */
442             cvs_output ("\n", 1);
443             break;
444         }
445         ++p;
446         cvs_output ("\t", 1);
447         while (1)
448         {
449             while (*p != '+' && *p != ',' && *p != '\0')
450                 cvs_output (p++, 1);
451             if (*p == '\0')
452             {
453                 cvs_output ("\n", 1);
454                 goto out;
455             }
456             if (*p == ',')
457             {
458                 ++p;
459                 break;
460             }
461             ++p;
462             cvs_output ("\t", 1);
463         }
464         cvs_output ("\n", 1);
465     }
466   out:;
467     free (them);
468     return 0;
469 }
470
471 int
472 watchers (argc, argv)
473     int argc;
474     char **argv;
475 {
476     int local = 0;
477     int c;
478
479     if (argc == -1)
480         usage (watchers_usage);
481
482     optind = 0;
483     while ((c = getopt (argc, argv, "+lR")) != -1)
484     {
485         switch (c)
486         {
487             case 'l':
488                 local = 1;
489                 break;
490             case 'R':
491                 local = 0;
492                 break;
493             case '?':
494             default:
495                 usage (watchers_usage);
496                 break;
497         }
498     }
499     argc -= optind;
500     argv += optind;
501
502 #ifdef CLIENT_SUPPORT
503     if (current_parsed_root->isremote)
504     {
505         start_server ();
506         ign_setup ();
507
508         if (local)
509             send_arg ("-l");
510         send_arg ("--");
511         send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
512         send_file_names (argc, argv, SEND_EXPAND_WILD);
513         send_to_server ("watchers\012", 0);
514         return get_responses_and_close ();
515     }
516 #endif /* CLIENT_SUPPORT */
517
518     return start_recursion (watchers_fileproc, (FILESDONEPROC) NULL,
519                             (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
520                             argc, argv, local, W_LOCAL, 0, CVS_LOCK_READ,
521                             (char *) NULL, 1, (char *) NULL);
522 }