1 /* Implementation for "cvs watch add", "cvs watchers", and related commands
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)
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. */
18 const char *const watch_usage
[] =
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",
31 static struct addremove_args the_args
;
34 watch_modify_watchers (const char *file
, struct addremove_args
*what
)
36 char *curattr
= fileattr_get0 (file
, "_watchers");
44 size_t mynewattr_size
;
47 int add_unedit_pending
;
48 int add_commit_pending
;
49 int remove_edit_pending
;
50 int remove_unedit_pending
;
51 int remove_commit_pending
;
52 int add_tedit_pending
;
53 int add_tunedit_pending
;
54 int add_tcommit_pending
;
56 TRACE( TRACE_FUNCTION
, "modify_watchers ( %s )", file
);
59 who_len
= strlen (who
);
61 /* Look for current watcher types for this user. */
67 if (strncmp (who
, p
, who_len
) == 0
70 /* Found this user. */
71 mycurattr
= p
+ who_len
+ 1;
79 if (mycurattr
!= NULL
)
81 mycurattr
= xstrdup (mycurattr
);
82 p
= strchr (mycurattr
, ',');
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). */
91 mynewattr_size
= sizeof "+edit+unedit+commit+tedit+tunedit+tcommit";
92 if (mycurattr
!= NULL
)
93 mynewattr_size
+= strlen (mycurattr
);
94 mynewattr
= xmalloc (mynewattr_size
);
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
;
107 /* Copy over existing watch types, except those to be removed. */
111 pend
= strchr (p
, '+');
114 pend
= p
+ strlen (p
);
120 /* Process this item. */
121 if (pend
- p
== 4 && strncmp ("edit", p
, 4) == 0)
123 if (!remove_edit_pending
)
124 strcat (mynewattr
, "+edit");
125 add_edit_pending
= 0;
127 else if (pend
- p
== 6 && strncmp ("unedit", p
, 6) == 0)
129 if (!remove_unedit_pending
)
130 strcat (mynewattr
, "+unedit");
131 add_unedit_pending
= 0;
133 else if (pend
- p
== 6 && strncmp ("commit", p
, 6) == 0)
135 if (!remove_commit_pending
)
136 strcat (mynewattr
, "+commit");
137 add_commit_pending
= 0;
139 else if (pend
- p
== 5 && strncmp ("tedit", p
, 5) == 0)
141 if (!what
->remove_temp
)
142 strcat (mynewattr
, "+tedit");
143 add_tedit_pending
= 0;
145 else if (pend
- p
== 7 && strncmp ("tunedit", p
, 7) == 0)
147 if (!what
->remove_temp
)
148 strcat (mynewattr
, "+tunedit");
149 add_tunedit_pending
= 0;
151 else if (pend
- p
== 7 && strncmp ("tcommit", p
, 7) == 0)
153 if (!what
->remove_temp
)
154 strcat (mynewattr
, "+tcommit");
155 add_tcommit_pending
= 0;
161 /* Copy over any unrecognized watch types, for future
163 mp
= mynewattr
+ strlen (mynewattr
);
165 strncpy (mp
, p
, pend
- p
);
166 *(mp
+ (pend
- p
)) = '\0';
169 /* Set up for next item. */
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");
191 fileattr_modify (curattr
,
193 mynewattr
[0] == '\0' ? NULL
: mynewattr
+ 1,
196 /* If the attribute is unchanged, don't rewrite the attribute file. */
197 if (!((curattr_new
== NULL
&& curattr
== NULL
)
198 || (curattr_new
!= NULL
200 && strcmp (curattr_new
, curattr
) == 0)))
204 if (curattr_new
!= NULL
)
210 if (mycurattr
!= NULL
)
212 if (mynewattr
!= NULL
)
216 static int addremove_fileproc (void *callerdat
,
217 struct file_info
*finfo
);
220 addremove_fileproc (void *callerdat
, struct file_info
*finfo
)
222 watch_modify_watchers (finfo
->file
, &the_args
);
226 static int addremove_filesdoneproc (void * callerdat
, int err
, const char * repository
,
227 const char *update_dir
, List
* entries
)
229 int set_default
= the_args
.setting_default
;
232 while ( !set_default
&& dir_check
< the_args
.num_dirs
)
234 /* If we are recursing, then just see if the first part of update_dir
235 matches any of the specified directories. Otherwise, it must be an exact
237 if ( the_args
.local
)
238 set_default
= strcmp( update_dir
, the_args
.dirs
[ dir_check
] )==0;
240 set_default
= strncmp( update_dir
, the_args
.dirs
[ dir_check
], strlen( the_args
.dirs
[ dir_check
] ) ) == 0;
245 watch_modify_watchers (NULL
, &the_args
);
251 watch_addremove (int argc
, char **argv
)
263 the_args
.num_dirs
= 0;
264 the_args
.dirs
= NULL
;
268 while ((c
= getopt (argc
, argv
, "+lRa:")) != -1)
280 if (strcmp (optarg
, "edit") == 0)
282 else if (strcmp (optarg
, "unedit") == 0)
284 else if (strcmp (optarg
, "commit") == 0)
286 else if (strcmp (optarg
, "all") == 0)
292 else if (strcmp (optarg
, "none") == 0)
310 the_args
.num_dirs
= 0;
311 max_dirs
= 4; /* Arbitrary choice. */
312 the_args
.dirs
= xmalloc( sizeof( const char * ) * max_dirs
);
314 TRACE (TRACE_FUNCTION
, "watch_addremove (%d)", argc
);
315 for ( arg_index
=0; arg_index
<argc
; ++arg_index
)
317 TRACE( TRACE_FUNCTION
, "\t%s", argv
[ arg_index
]);
318 if ( isdir( argv
[ arg_index
] ) )
320 if ( the_args
.num_dirs
>= max_dirs
)
323 the_args
.dirs
= (const char ** )xrealloc( (void *)the_args
.dirs
, max_dirs
);
325 the_args
.dirs
[ the_args
.num_dirs
++ ] = argv
[ arg_index
];
336 #ifdef CLIENT_SUPPORT
337 if (current_parsed_root
->isremote
)
344 /* FIXME: copes poorly with "all" if server is extended to have
345 new watch types and client is still running an old version. */
347 option_with_arg ("-a", "edit");
349 option_with_arg ("-a", "unedit");
351 option_with_arg ("-a", "commit");
352 if (!the_args
.edit
&& !the_args
.unedit
&& !the_args
.commit
)
353 option_with_arg ("-a", "none");
355 send_files (argc
, argv
, the_args
.local
, 0, SEND_NO_CONTENTS
);
356 send_file_names (argc
, argv
, SEND_EXPAND_WILD
);
357 send_to_server (the_args
.adding
?
358 "watch-add\012" : "watch-remove\012",
360 return get_responses_and_close ();
362 #endif /* CLIENT_SUPPORT */
364 the_args
.setting_default
= (argc
<= 0);
366 lock_tree_promotably (argc
, argv
, the_args
.local
, W_LOCAL
, 0);
368 err
= start_recursion
369 (addremove_fileproc
, addremove_filesdoneproc
, NULL
, NULL
, NULL
,
370 argc
, argv
, the_args
.local
, W_LOCAL
, 0, CVS_LOCK_WRITE
,
374 free( (void *)the_args
.dirs
);
375 the_args
.dirs
= NULL
;
383 watch_add (int argc
, char **argv
)
386 return watch_addremove (argc
, argv
);
390 watch_remove (int argc
, char **argv
)
393 return watch_addremove (argc
, argv
);
397 watch (int argc
, char **argv
)
401 if (strcmp (argv
[1], "on") == 0)
405 return watch_on (argc
, argv
);
407 else if (strcmp (argv
[1], "off") == 0)
411 return watch_off (argc
, argv
);
413 else if (strcmp (argv
[1], "add") == 0)
417 return watch_add (argc
, argv
);
419 else if (strcmp (argv
[1], "remove") == 0)
423 return watch_remove (argc
, argv
);
430 static const char *const watchers_usage
[] =
432 "Usage: %s %s [-lR] [<file>]...\n",
433 "-l\tProcess this directory only (not recursive).\n",
434 "-R\tProcess directories recursively (default).\n",
435 "(Specify the --help global option for a list of other help options.)\n",
439 static int watchers_fileproc (void *callerdat
,
440 struct file_info
*finfo
);
443 watchers_fileproc (void *callerdat
, struct file_info
*finfo
)
448 them
= fileattr_get0 (finfo
->file
, "_watchers");
452 cvs_output (finfo
->fullname
, 0);
457 cvs_output ("\t", 1);
458 while (*p
!= '>' && *p
!= '\0')
462 /* Only happens if attribute is misformed. */
463 cvs_output ("\n", 1);
467 cvs_output ("\t", 1);
470 while (*p
!= '+' && *p
!= ',' && *p
!= '\0')
474 cvs_output ("\n", 1);
483 cvs_output ("\t", 1);
485 cvs_output ("\n", 1);
493 watchers (int argc
, char **argv
)
499 usage (watchers_usage
);
502 while ((c
= getopt (argc
, argv
, "+lR")) != -1)
514 usage (watchers_usage
);
521 #ifdef CLIENT_SUPPORT
522 if (current_parsed_root
->isremote
)
530 send_files (argc
, argv
, local
, 0, SEND_NO_CONTENTS
);
531 send_file_names (argc
, argv
, SEND_EXPAND_WILD
);
532 send_to_server ("watchers\012", 0);
533 return get_responses_and_close ();
535 #endif /* CLIENT_SUPPORT */
537 return start_recursion (watchers_fileproc
, NULL
, NULL
,
538 NULL
, NULL
, argc
, argv
, local
, W_LOCAL
, 0,
539 CVS_LOCK_READ
, NULL
, 1, NULL
);