home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / ver_cont / cvs-1.8 / cvs-1 / cvs-1.8.1 / src / watch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-06  |  11.3 KB  |  522 lines

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