home *** CD-ROM | disk | FTP | other *** search
- /* for utility
-
- FOR var IN list DO cmd_list DONE
-
- list may contain wildcards
- cmd_list is a semicolon separated list of commands with options
- (and $var). Several commands may be included in () to execute them
- in a subshell. The command CD is handled in a special way.
-
- The following two lines are equal
-
- FOR dir IN dir1 dir2 dir2 DO cd $dir ";" dir ";" cd / DONE
- FOR dir IN dir1 dir2 dir2 DO ( cd $dir ";" dir ) DONE
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <exec/memory.h>
- #include <dos/dos.h>
- #include <dos/dostags.h>
- #include <dos/dosasl.h>
- #include <proto/exec.h>
- #include <proto/dos.h>
-
- #include "util.h"
-
- #define FULLPATHSIZE 1024L
- #define ANCHORSIZE (sizeof (struct AnchorPath) + FULLPATHSIZE)
-
- static int show_debug;
-
- int for_command (int, char **);
- int cd_command (char *);
- int execute_commands (int, char **);
-
- /* Remember the current dir and start the first level of FOR */
- int main (int argc, char ** argv)
- {
- int status;
- BPTR cd, orig;
-
- if (!(cd = Lock ("", SHARED_LOCK)) )
- {
- PrintFault (IoErr(), "FOR: Cannot lock current directory");
- return 20;
- }
-
- orig = CurrentDir (cd);
-
- status = for_command (argc, argv);
-
- UnLock (CurrentDir (orig));
-
- return status;
- }
-
- /* Set a local variable according to a list of patterns and execute a
- list of commands with each pattern */
- int for_command (int argc, char ** argv)
- {
- char * var;
- char * pat;
- int first_pat, last_pat;
- int first_cmd, last_cmd;
- int t, level, len, has_wild;
- int status = 0;
-
- /* There have to be 5 args min: FOR var IN DO DONE */
- if (argc < 5 || argv[1][0] == '?')
- {
- show_usage:
- puts ("Usage: FOR var IN list DO cmd_list DONE");
- return 10;
- }
-
- t = 1;
-
- /* Enable debugging */
- if (argv[t][0] == '-' && argv[t][1] == 'd')
- {
- show_debug = 1;
- t ++;
- }
-
- /* Read name of variable */
- var = argv[t ++];
-
- /* Show it, if neccessary */
- if (show_debug)
- printf ("Var=\"%s\"\n", var);
-
- /* Now IN must follow */
- if (strcmpi (argv[t], "IN"))
- {
- fprintf (stderr, "FOR: Missing IN\n");
- goto show_usage;
- }
-
- t ++;
-
- /* This is the start of the patterns */
- first_pat = t;
-
- /* Search until the end of arguments or DO is found */
- while (t<argc && strcmpi (argv[t],"DO"))
- t ++;
-
- /* If we ran out of arguments, this is an error */
- if (t == argc)
- {
- fprintf (stderr, "FOR: Missing DO\n");
- goto show_usage;
- }
-
- /* Set the end of patterns to the pre-last visited arg */
- last_pat = t-1;
-
- /* If the last pattern is ";" (like in the bourne shell), ignore it */
- if (argv[last_pat][0] == ';' && !argv[last_pat][1])
- last_pat--;
-
- /* If there are no patterns, don't do anything (this is NO error !) */
- if (last_pat < first_pat)
- return 0;
-
- /* Skip DO */
- t ++;
-
- /* If the first command is ";" (like in the bourne shell), ignore it */
- if (argv[t][0] == ';' && !argv[t][1])
- t ++;
-
- /* Now check the rest of the line. The current position is the first
- command to execute */
- first_cmd = t;
-
- /* Search until the end of arguments or DONE is found and that DONE
- belongs to the current FOR */
- level = 0;
- while (t<argc)
- {
- if (!strcmpi (argv[t], "FOR"))
- level ++;
- else if (!strcmpi (argv[t], "DONE"))
- {
- if (!level)
- break;
-
- level --;
- }
-
- t ++;
- }
-
- /* If there are more arguments or the last thing is not DONE, show
- usage */
- if (t == argc || level)
- {
- fprintf (stderr, "FOR: Missing DONE (t=%d, argc=%d, level=%d)\n",
- t, argc, level);
- goto show_usage;
- }
-
- /* Set the pointer to the last cmd */
- last_cmd = t-1;
-
- /* If the last pattern is ";" (like in the bourne shell), ignore it */
- if (argv[last_cmd][0] == ';' && !argv[last_cmd][1])
- last_cmd --;
-
- /* If's ok to have no commands at all */
- if (last_cmd < first_cmd)
- return 0;
-
- /* Now execute the commands for each pattern */
- for (t=first_pat; t<=last_pat && !status; t++)
- {
- len = (strlen (argv[t])+1)*2;
- pat = AllocMem (len, MEMF_ANY);
-
- if (!pat)
- {
- fprintf (stderr, "FOR: Ran our of memory\n");
- return 20;
- }
-
- has_wild = ParsePatternNoCase (argv[t], pat, len);
-
- switch (has_wild)
- {
- case -1: /* Error in pattern */
- fprintf (stderr, "FOR: Error parsing \"%s\":", argv[t]);
- PrintFault (IoErr(), NULL);
- status = 10;
- break;
-
- case 0: /* No pattern, just a simple string */
- if (!SetVar (var, argv[t], -1, GVF_LOCAL_ONLY))
- {
- fprintf (stderr, "FOR: Error setting %s to \"%s\":", var,
- argv[t]);
- PrintFault (IoErr(), "FOR: Error parsing \"%s\":");
- status = 10;
- }
- else
- status = execute_commands (last_cmd-first_cmd+1,
- &argv[first_cmd]);
- break;
-
- case 1: { /* Wildcards */
- struct AnchorPath * ap;
- LONG error;
-
- if (!(ap = AllocMem (ANCHORSIZE, MEMF_CLEAR)) )
- {
- fprintf (stderr, "FOR: Ran out of memory\n");
- status = 10;
- }
- else
- {
- ap->ap_BreakBits = SIGBREAKF_CTRL_C;
- ap->ap_Strlen = FULLPATHSIZE;
-
- for (error=MatchFirst(argv[t],ap); !error && !status;
- error=MatchNext(ap))
- {
- if (!SetVar (var, ap->ap_Buf, -1, GVF_LOCAL_ONLY))
- {
- fprintf (stderr, "FOR: Error setting %s to \"%s\":",
- var, argv[t]);
- PrintFault (IoErr(), "FOR: Error parsing \"%s\":");
- status = 10;
- }
- else
- status = execute_commands (last_cmd-first_cmd+1,
- &argv[first_cmd]);
- }
-
- if (error != ERROR_NO_MORE_ENTRIES)
- {
- PrintFault (error, "FOR");
- status = 10;
- }
-
- FreeMem (ap, ANCHORSIZE);
- }
- break; }
- }
-
- FreeMem (pat, len);
- }
-
- return status;
- } /* for_command */
-
- /* Execute a list of commands. Each command is separated by ";".
- Commands may be grouped in () to form a sub-shell. Currently
- this sub-shell just restores the current directory */
- int execute_commands (int argc, char ** argv)
- {
- int t;
- int status = 0;
- int first_arg, last_arg;
- int level;
- BPTR cd, orig;
-
- /* Check all arguments. Note that this is not the only
- place where t might change */
- for (t=0; t<argc && !status; t++)
- {
- /* Find out where we are */
- if (argv[t][0] == '(' && !argv[t][1]) /* Subshell */
- {
- if ((cd = Lock ("", SHARED_LOCK)))
- {
- /* Find all commands which are in the subshell */
- first_arg = ++t;
- level = 0;
-
- while (t<argc)
- {
- if (argv[t][0] == '(' && !argv[t][1])
- level ++;
- else if (argv[t][0] == ')' && !argv[t][1])
- {
- if (!level)
- break;
-
- level --;
- }
-
- t ++;
- }
-
- if (t != argc)
- {
- last_arg = t-1;
-
- /* Remeber the current dir */
- orig = CurrentDir (cd);
-
- /* Execute the commands of the sub-shell */
- status = execute_commands (last_arg-first_arg+1,
- &argv[first_arg]);
-
- /* Come back to the original dir */
- UnLock (CurrentDir (orig));
- }
- else
- {
- fprintf (stderr, "FOR: Missing ) in sub shell\n");
- status = 10;
- }
- }
- else
- {
- PrintFault (IoErr(), "FOR: Cannot lock current dir");
- status = 10;
- }
- }
- else if (!strcmpi (argv[t], "CD")) /* cd command */
- {
- /* ignore the CD */
- t ++;
-
- /* Change the dir */
- status = cd_command (t!=argc ? argv[t] : NULL);
- }
- else /* Normal command */
- {
- first_arg = t;
-
- while (t<argc && !(argv[t][0] == ';' && !argv[t][1]))
- t ++;
-
- last_arg = t-1;
-
- status = execute_command (last_arg-first_arg+1, &argv[first_arg]);
- }
- }
-
- return status;
- } /* execute_commands */
-
- int cd_command (char * path)
- {
- BPTR lock;
- char * realpath;
-
- if (path)
- {
- realpath = replace_vars (path);
-
- if (show_debug)
- printf ("CD (%s)\n", realpath);
-
- if (!(lock = Lock (realpath, SHARED_LOCK)) )
- {
- fprintf (stderr, "FOR: Cannot Lock \"%s\"\n", realpath);
- free (realpath);
- PrintFault (IoErr(), NULL);
- return 10;
- }
-
- free (realpath);
- UnLock (CurrentDir (lock));
- }
- else
- {
- if (!(lock = Lock ("", SHARED_LOCK)) )
- {
- fprintf (stderr, "FOR: Cannot Lock current dir");
- PrintFault (IoErr(), NULL);
- return 10;
- }
-
- realpath = malloc (4096);
-
- NameFromLock (lock, realpath, 4096);
- puts (realpath);
- free (realpath);
- }
-
- return 0;
- } /* cd_command */
-