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