home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 308.lha / treewalk / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1980-12-05  |  13.4 KB  |  562 lines

  1. /*
  2.  * treewalk - a command to get the power of treewalk out to the CLI.
  3.  *
  4.  *    Copyright (C) 1989  Mike Meyer
  5.  *
  6.  *    This program is free software; you can redistribute it and/or modify
  7.  *    it under the terms of the GNU General Public License as published by
  8.  *    the Free Software Foundation; either version 1, or any later version.
  9.  *
  10.  *    This program is distributed in the hope that it will be useful,
  11.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *    GNU General Public License for more details.
  14.  *
  15.  *    You should have received a copy of the GNU General Public License
  16.  *    along with this program; if not, write to the Free Software
  17.  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20. #include <exec/types.h>
  21. #include <libraries/dos.h>
  22. #include <proto/dos.h>
  23. #include <proto/exec.h>
  24. #include <proto/intuition.h>
  25. #include <dos.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <ctype.h>
  30. #include "treewalk.h"
  31. #include "errors.h"
  32.  
  33. /*
  34.  * Filter parsing functions, prototypes thereof. The "void *"'s are a lie,
  35.  * but they serve their purpose.
  36.  */
  37. void *parse(char *) ;
  38. long execute(struct FileInfoBlock *, void *) ;
  39.  
  40. /* Flags needed by the visit function, to help it decide what to do */
  41. static int    singlearg = FALSE, verbose = FALSE, ignore = FALSE ;
  42. static void    *code = NULL ;
  43.  
  44. /* Things visible to other files */
  45. char    *my_name ;
  46. int    errorflag = ERROR_NONE ;
  47.  
  48. /*
  49.  * And the functions I need from below.
  50.  */
  51. static int    dofiles(long, struct FileInfoBlock *) ;
  52.  
  53. /*
  54.  * We need storage for the duration of a filter execution. We use
  55.  * the RememberKey and free it after the execution.
  56.  */
  57. static struct Remember *filterstrings = NULL ;
  58.  
  59. /*
  60.  * Things for dealing with a issuance of commands
  61.  */
  62. #define COMMAX    240    /* WShell is 240, stock would be 256 */
  63. static char    command[COMMAX] = "", *commnext = command, *commend ;
  64.  
  65. static void
  66. growcommand(char *stuff, int pad) {
  67.  
  68.     strcpy(commnext, stuff) ;
  69.     commnext += strlen(stuff) ;
  70.     if (!pad) return ;
  71.     *commnext++ = ' ' ;
  72.     *commnext = '\0' ;
  73.     }
  74.  
  75. static void
  76. endcommand(void) {
  77.  
  78.     commend = commnext ;
  79.     }
  80.  
  81. static void
  82. docommand(void) {
  83.  
  84.     if (verbose) fprintf(stderr, "Executing: %s\n", command) ;
  85.     Execute(command, NULL, NULL) ;
  86.     if (!ignore && IoErr()) {
  87.         errorflag = ERROR_WARN ;
  88.         if (verbose) fprintf(stderr, "Error from command\n") ;
  89.         else fprintf(stderr, "Error from command '%s'\n", command) ;
  90.         }
  91.     *commend = '\0' ;
  92.     commnext = commend ;
  93.     }
  94.  
  95. void
  96. main(int argc, char **argv) {
  97.     int    treeflags = TREE_PRE, stat ;
  98.     char    *rootdir = "", *filter = NULL ;
  99.     long    root ;
  100.  
  101.     my_name = argv[0] ;
  102.  
  103.     if ((IntuitionBase = (struct IntuitionBase *)
  104.         OpenLibrary("intuition.library", 33)) == NULL) {
  105.             fprintf(stderr, "%s: Can't open intuition.library\n", my_name) ;
  106.         exit(20) ;
  107.         }
  108.  
  109.     /* Argument parsing time again... */
  110.     while (*++argv)
  111.         if (!strcmp(*argv, "?")) {
  112.             fprintf(stderr, "usage: %s [options] [command]\n", my_name) ;
  113.             fprintf(stderr, "options: [post|both] [single] [verbose] [ignore] [dir <dir>] [filter <filter>] [command]\n") ;
  114.             exit(RETURN_OK) ;
  115.             }
  116.         else if (!strnicmp(*argv, "single", 3)) singlearg = TRUE ;
  117.         else if (!strnicmp(*argv, "verbose", 3)) verbose = TRUE ;
  118.         else if (!strnicmp(*argv, "ignore", 3)) ignore = TRUE ;
  119.         else if (!strnicmp(*argv, "post", 3)) treeflags = TREE_POST ;
  120.         else if (!strnicmp(*argv, "both", 3)) treeflags = TREE_BOTH ;
  121.         else if (!strnicmp(*argv, "dir", 3)) rootdir = *++argv ;
  122.         else if (!strnicmp(*argv, "filter", 3)) filter = *++argv ;
  123.         else if (!strnicmp(*argv, "command", 3)) {
  124.             argv += 1 ;
  125.             break ;
  126.             }
  127.         else break ;    /* Start of command */
  128.  
  129.     /* Check for filter */
  130.     if (filter) {
  131.         if ((code = parse(filter)) == NULL) {
  132.             fprintf(stderr, "%s: exiting\n", my_name) ;
  133.             exit(RETURN_ERROR) ;
  134.             }
  135.         if (filterstrings) {
  136.             FreeRemember(&filterstrings, FALSE) ;
  137.             filterstrings = NULL ;
  138.             }
  139.         }
  140.  
  141.     /*
  142.      * Now, stack up commands. Command is large enough to hold any valid
  143.      * command, so it must be large enough to hold the tail of this one.
  144.      */
  145.     while (*argv)
  146.         growcommand(*argv++, TRUE) ;
  147.     endcommand() ;
  148.  
  149.     if ((root = Lock(rootdir, ACCESS_READ)) == NULL) {
  150.         fprintf(stderr, "%s: Can't lock %s\n", my_name, rootdir) ;
  151.         exit(RETURN_ERROR) ;
  152.         }
  153.  
  154.     treewalk(root, dofiles, treeflags) ;
  155.     UnLock(root) ;
  156.  
  157.     /* Clean up any leftover commands */
  158.     if (*commend) docommand() ;
  159.  
  160.     /* Tell the user how we exited, if need be */
  161.     switch (errorflag) {
  162.         case ERROR_BREAK: printf("*** Break: %s\n", my_name) ;
  163.         /* Fall through to next case */
  164.  
  165.         case ERROR_NONE: stat = 0;
  166.         break ;
  167.  
  168.         case ERROR_WARN: stat = RETURN_WARN ;
  169.         break ;
  170.  
  171.         case ERROR_HALT: stat = RETURN_ERROR ;
  172.         fprintf(stderr, "%s: Execution halting\n", my_name) ;
  173.         break ;
  174.         }
  175.     exit(stat) ;
  176.     }
  177.  
  178. /*
  179.  * And now, where all the work is really done. Various things for dealing
  180.  * filtering out files, getting their true name, and building & executing
  181.  * commands.
  182.  */
  183.  
  184. /*
  185.  * pathname code: is either a valid pathname, or a "". Getpathname makes it
  186.  * hold the right thing, or return TRUE ;
  187.  */
  188. static char    pathname[FMSIZE] = "" ;
  189.  
  190. static int
  191. getpathname(long lock) {
  192.  
  193.     if (getpath(lock, pathname)) {
  194.         fprintf(stderr, "%s: Failure in getting full path name!\n",
  195.             my_name) ;
  196.         *pathname = '\0' ;
  197.         errorflag = ERROR_HALT ;
  198.         return TRUE ;
  199.         }
  200.     strcat(pathname, strchr(pathname, ':') == NULL ? ":" : "/") ;
  201.     return FALSE ;
  202.     }
  203.  
  204. /*
  205.  * Some globals for use by the primitives below. The values don't change
  206.  * during one filter execution, so it don't matter much.
  207.  */
  208. static long            lock_global ;
  209.  
  210. /*
  211.  * The visit function - where all the work is actually done...
  212.  */
  213. static int
  214. dofiles(long lock, struct FileInfoBlock *fib) {
  215.     int    status ;
  216.  
  217.     /* First, check to see if we need to stop */
  218.     if (errorflag == ERROR_HALT) return TREE_STOP ;
  219.  
  220.     if (SetSignal(0, 0) & SIGBREAKF_CTRL_C) {
  221.         errorflag = ERROR_BREAK ;
  222.         return TREE_STOP ;
  223.         }
  224.  
  225.     /* Start a new directory */
  226.     if (fib == NULL) {
  227.         /* flush path */
  228.         pathname[0] = '\0' ;
  229.         return TREE_CONT ;
  230.         }
  231.  
  232.     /* See if we want to deal with this file */
  233.     if (code) {
  234.         lock_global = lock ;
  235.         status = !execute(fib, code) ;
  236.         if (filterstrings) {
  237.             FreeRemember(&filterstrings, TRUE) ;
  238.             filterstrings = NULL ;
  239.             }
  240.         if (status) return TREE_CONT ;
  241.         }
  242.  
  243.     /* We do, so if we don't have it yet, get it's full name */
  244.     if (!*pathname && getpathname(lock)) return TREE_STOP ;
  245.  
  246.     /* print it if nothing better to do */
  247.     if (!*command) {
  248.         printf("%s%s\n", pathname, fib->fib_FileName) ;
  249.         return TREE_CONT ;
  250.         }
  251.  
  252.     /* Deal with easy commands - just one argument! */
  253.     if (singlearg) {
  254.         growcommand("\"", FALSE) ;
  255.         growcommand(pathname, FALSE) ;
  256.         growcommand(fib->fib_FileName, FALSE) ;
  257.         growcommand("\"", FALSE) ;
  258.         docommand() ;
  259.         return TREE_CONT ;
  260.         }
  261.  
  262.     /* Otherwise, build up the command if we need to */
  263.     if (commnext - command + strlen(pathname) + strlen(fib->fib_FileName) + 3 > COMMAX)
  264.         docommand() ;
  265.     growcommand("\"", FALSE) ;
  266.     growcommand(pathname, FALSE) ;
  267.     growcommand(fib->fib_FileName, FALSE) ;
  268.     growcommand("\"", TRUE) ;
  269.     return TREE_CONT ;
  270.     }
  271.  
  272. /*
  273.  * And here we have things that check the global FIB, and extract values
  274.  * from it.
  275.  */
  276. long
  277. fibkey(struct FileInfoBlock *fib) {
  278.     return fib->fib_DiskKey ;
  279.     }
  280.  
  281. long
  282. fibdirtype(struct FileInfoBlock *fib) {
  283.     return fib->fib_DirEntryType ;
  284.     }
  285.  
  286. char *
  287. fibname(struct FileInfoBlock *fib) {
  288.     char *tmpname ;
  289.  
  290.     if ((tmpname = AllocRemember(&filterstrings, 100, 0L)) == NULL) {
  291.         fprintf(stderr, "%s: Out of memory\n", my_name) ;
  292.         errorflag = ERROR_HALT ;
  293.         return NULL ;
  294.         }
  295.     strcpy(tmpname, fib->fib_FileName) ;
  296.     strlwr(tmpname) ;
  297.     return tmpname ;
  298.     }
  299.  
  300. long
  301. fibprot(struct FileInfoBlock *fib) {
  302.     return fib->fib_Protection ^ 017 ;
  303.     }
  304.  
  305. long
  306. fibtype(struct FileInfoBlock *fib) {
  307.     return fib->fib_EntryType ;
  308.     }
  309.  
  310. long
  311. fibsize(struct FileInfoBlock *fib) {
  312.     return fib->fib_Size ;
  313.     }
  314.  
  315. long
  316. fibblock(struct FileInfoBlock *fib) {
  317.     return fib->fib_NumBlocks ;
  318.     }
  319.  
  320. long
  321. fibdate(struct FileInfoBlock *fib) {
  322.     return fib->fib_Date.ds_Days * 24 * 60 + fib->fib_Date.ds_Minute ;
  323.     }
  324.  
  325. long
  326. fibday(struct FileInfoBlock *fib) {
  327.     return fib->fib_Date.ds_Days * 24 * 60 ;
  328.     }
  329.  
  330. char *
  331. fibcomment(struct FileInfoBlock *fib) {
  332.     char *tmpname ;
  333.  
  334.     if ((tmpname = AllocRemember(&filterstrings, 80, 0L)) == NULL) {
  335.         fprintf(stderr, "%s: Out of memory\n", my_name) ;
  336.         errorflag = ERROR_HALT ;
  337.         return NULL ;
  338.         }
  339.     strcpy(tmpname, fib->fib_Comment) ;
  340.     strlwr(tmpname) ;
  341.     return tmpname ;
  342.     }
  343.  
  344. long
  345. askuser(struct FileInfoBlock *fib) {
  346.     char c ;
  347.  
  348.     if (!*pathname && getpathname(lock_global)) return 1 ;
  349.     fprintf(stderr, "%s%s? ", pathname, fib->fib_FileName) ;
  350.     fflush(stderr) ;
  351.     while ((c = getchar()) == ' ' || c == '\t')
  352.         ;
  353.     while (getchar() != '\n')
  354.         ;
  355.     return (long) (toupper(c) == 'Y') ;
  356.     }
  357.  
  358. char *
  359. fullname(struct FileInfoBlock *fib) {
  360.     char *tmpname ;
  361.  
  362.     if ((tmpname = AllocRemember(&filterstrings, FMSIZE, 0L)) == NULL) {
  363.         fprintf(stderr, "%s: Out of memory\n", my_name) ;
  364.         errorflag = ERROR_HALT ;
  365.         return NULL ;
  366.         }
  367.     if (!*pathname) getpathname(lock_global) ;
  368.     strcpy(tmpname, pathname) ;
  369.     strcat(tmpname, fib->fib_FileName) ;
  370.     strlwr(tmpname) ;
  371.     return tmpname ;
  372.     }
  373.  
  374. long
  375. isfile(struct FileInfoBlock *fib) {
  376.     return (long) (fib->fib_DirEntryType < 0) ;
  377.     }
  378.  
  379. long
  380. isdir(struct FileInfoBlock *fib) {
  381.     return (long) (fib->fib_DirEntryType >= 0) ;
  382.     }
  383.  
  384. /*
  385.  * dofib - apply one of the fibfuncs to a named file.
  386.  */
  387. long
  388. dofib(char *file, long (*func)(struct FileInfoBlock *)) {
  389.     long            lock, out ;
  390.     struct FileInfoBlock    *fib ;
  391.  
  392.     if ((fib = AllocMem(sizeof(struct FileInfoBlock), 0)) == NULL) {
  393.         fprintf(stderr, "%s: Out of memory\n", my_name) ;
  394.         errorflag = ERROR_HALT ;
  395.         return 0 ;
  396.         }
  397.  
  398.     if (!(lock = Lock(file, ACCESS_READ))) {
  399.         fprintf(stderr, "%s: Can't lock %s\n", my_name, file) ;
  400.         errorflag = ERROR_HALT ;
  401.         FreeMem(fib, sizeof(*fib)) ;
  402.         return 0 ;
  403.         }
  404.  
  405.     lock_global = lock ;
  406.     *pathname = '\0' ;
  407.     if (!Examine(lock, fib)) {
  408.         fprintf(stderr, "%s: Can't examine %s\n", my_name, file) ;
  409.         errorflag = ERROR_HALT ;
  410.         UnLock(lock) ;
  411.         FreeMem(fib, sizeof(*fib)) ;
  412.         return 0 ;
  413.         }
  414.  
  415.     out = func(fib) ;
  416.     UnLock(lock) ;
  417.     FreeMem(fib, sizeof(*fib)) ;
  418.     return out ;
  419.     }
  420.  
  421. #ifndef    NO_REXX
  422. /*
  423.  * Rexx interface - for now, just feed the routine to Rexx, and return
  424.  * whatever integer it gives us back.
  425.  */
  426. #include <rexx/rxslib.h>
  427. #include <rexx/storage.h>
  428. #include <exec/ports.h>
  429.  
  430.  
  431. struct Library        *RexxSysBase = NULL ;
  432. #define    REXXNAME    "ftw"
  433.  
  434. long
  435. dorexx(char *macro, struct FileInfoBlock *fib) {
  436.     struct RexxMsg    *msg ;
  437.     struct MsgPort    *rexxport, *port ;
  438.     long        out ;
  439.     void        *code ;
  440.     char        result[12] ;
  441.  
  442.     /* Get the library if we need it */
  443.     if ((RexxSysBase = OpenLibrary("rexxsyslib.library", 0)) == NULL) {
  444.         fprintf(stderr, "%s: Can't open rexx library\n", my_name) ;
  445.         errorflag = ERROR_HALT ;
  446.         return 0 ;
  447.         }
  448.  
  449.     /* Create the port I use to talk to Rexx */
  450.     Forbid() ;
  451.     if (FindPort(REXXNAME) == NULL)
  452.         port = CreatePort(REXXNAME, 0) ;
  453.     Permit() ;
  454.     if (port == NULL) {
  455.         fprintf(stderr, "%s: Can't create port for rexx\n", my_name) ;
  456.         goto badnews ;
  457.         }
  458.  
  459.     /* Build the message to send */
  460.     if ((msg = CreateRexxMsg(port, REXXNAME, port->mp_Node.ln_Name)) == NULL) {
  461.         fprintf(stderr, "%s: Can't create rexx msg\n", my_name) ;
  462.         goto badnews ;
  463.         }
  464.     msg->rm_Action = RXFUNC | RXFF_RESULT | 2 ;
  465.  
  466.     /* The command & two arguments */
  467.     if (!*pathname) getpathname(lock_global) ;
  468.     msg->rm_Args[0] = macro ;
  469.     msg->rm_Args[1] = pathname ;
  470.     msg->rm_Args[2] = fib->fib_FileName ;
  471.     if (!FillRexxMsg(msg, 3, 0)) {
  472.         fprintf(stderr, "%s: Can't create rexx arguments\n", my_name) ;
  473.         DeleteRexxMsg(msg) ;
  474.         goto badnews ;
  475.         }
  476.  
  477.     /* send the message */
  478.     Forbid() ;
  479.     if (rexxport = FindPort(RXSDIR))
  480.         PutMsg(rexxport, (struct Message *) msg) ;
  481.     Permit() ;
  482.     if (!rexxport) {
  483.         fprintf(stderr, "%s: Can't find rexx port\n", my_name) ;
  484.         goto badnews ;
  485.         }
  486.  
  487.     /* Now, wait for it to come back to me */
  488.     for (;;) {
  489.         /* Get a message, and break if it's what I want */
  490.         WaitPort(port) ;
  491.         msg = (struct RexxMsg *) GetMsg(port) ;
  492.         if (msg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG) break ;
  493.  
  494.         /*
  495.          * Got a command - so we interpret the "command" as a filter,
  496.          * and run it over the current fib.
  497.          */
  498.         if ((code = parse(msg->rm_Args[0])) == NULL) {
  499.             /* Didn't parse - so return "broken command string" */
  500.             msg->rm_Result1 = 10 ;
  501.             msg->rm_Result2 = 11 ;
  502.             }
  503.         else {
  504.             out = execute(fib, code) ;
  505.             if (!(msg->rm_Action & RXFF_RESULT)) {
  506.                 /* Don't want results, so return TRUE/FALSE */
  507.                 msg->rm_Result1 = (out ? 0 : 1) ;
  508.                 msg->rm_Result2 = 0 ;
  509.                 }
  510.             else {    /* Want a result, so try and give it to them */
  511.                 sprintf(result, "%08lx", out) ;
  512.                 if ((msg->rm_Result2 =
  513.                     (LONG) CreateArgstring(result, (long) strlen(result)))
  514.                     != NULL)
  515.                     /* All ok, set result so */
  516.                     msg->rm_Result1 = 0 ;
  517.                 else {
  518.                     /* No memory, say so */
  519.                     msg->rm_Result1 = 20 ;
  520.                     msg->rm_Result2 = 3 ;
  521.                     }
  522.                 }
  523.             }
  524.         ReplyMsg((struct Message *) msg) ;
  525.         }
  526.         
  527.     /* Check the result and do what must be done */
  528.     if (msg->rm_Result1 == 0) {
  529.         out = atoi((char *) msg->rm_Result2) ;
  530.         DeleteArgstring((struct RexxArg *) msg->rm_Result2) ;
  531.         }
  532.     else {
  533.         fprintf(stderr, "%s: Rexx error: %s\n", my_name,
  534.             ErrorMsg(msg->rm_Result2)->ns_Buff) ;
  535.         goto badnews ;
  536.         }
  537.  
  538.     if (0) {    /* Make sure we execute this iff we had a problem */
  539. badnews:
  540.         errorflag = ERROR_HALT ;
  541.         out = 0 ;
  542.         }
  543.  
  544.     /* Clean up the port */
  545.     if (port != NULL) {
  546.         FreeSignal((long) (port->mp_SigBit)) ;
  547.         RemPort(port) ;
  548.         DeletePort(port) ;
  549.         }
  550.  
  551.     /* Clean up the rexx msg */
  552.     if (msg != NULL) {
  553.         ClearRexxMsg(msg, 3) ;
  554.         DeleteRexxMsg(msg) ;
  555.         }
  556.  
  557.     /* Close the library, and return */
  558.     if (RexxSysBase != NULL) CloseLibrary(RexxSysBase) ;
  559.     return out ;
  560.     }
  561. #endif
  562.