home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 9 / FreshFishVol9-CD2.bin / bbs / gfx / megaview-2.0.lha / MegaView / source / megaview / MegaView.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-21  |  41.8 KB  |  1,013 lines

  1. /**** REVISION HEADER **************************************************\
  2. *                                                                       *
  3. *       Filename            :   MegaView.c                              *
  4. *       Source Rev          :   $VER: MegaView.c 2.001 (24 Nov 1993) :   See documentation                       *
  5. *                                                                       *
  6. *   Revision History:                                                   *
  7. *   Date        Revision    Comment                                     *
  8. *   ---------------------------------------------------------------     *
  9. *   12-Jul-93   1.0         First public release                        *
  10. *   22-Jul-93   1.01        Added REQ commandline switch to allow       *
  11. *                           File Requester from the Shell               *
  12. *   22-Jul-93   1.02        Added 'loop' mode for SELECT button in      *
  13. *                           Popup requester to select more than one     *
  14. *                           file for viewing until cancel is pressed    *
  15. *   30-Jul-93   1.03        File requester is now "multi-select", i.e.  *
  16. *                           you can select more than one file to view   *
  17. *   06-Oct-93   1.1         Back from Holliday. Just adding a new       *
  18. *                           options which allows the user to recursively*
  19. *                           collect files from a directory or volume    *
  20. *                           Suggested by Richard Ludwig.                *
  21. *   10-Oct-93   1.2         Started work on the XPK Interface.          *
  22. *                           Suggested by Arne Hinrichsen.               *
  23. *   11-Oct-93   1.2         Added some new command line switches. The   *
  24. *                           XPK Interface took me some two hours. Great *
  25. *                           stuff! And easy to use.                     *
  26. *   26-Oct-93   2.0         New Version. Major bug fixes, lots of new   *
  27. *                           features planned.                           *
  28. *   13-Nov-93   2.0         Implemented the MAN switch                  *
  29. *   23-Nov-93   2.0         Added Localization!                         *
  30. *                                                                       *
  31. \***********************************************************************/
  32.  
  33. #include "global.h"
  34. #include "locale.h"
  35.  
  36. struct Library *WhatIsBase;
  37. struct Library *IntuitionBase;
  38. struct Library *WorkbenchBase;
  39. struct Library *IconBase;
  40. struct Library *AslBase;
  41. struct Library *XpkBase;
  42. struct Library *LocaleBase;
  43.  
  44. #define REVISION "2.0"
  45. static char *version = "$VER: MegaView " REVISION ;
  46.  
  47. /* The FileActions Template */
  48. #define CONFIG_TEMPLATE (APTR)"TYPE/K/A,ACTION/K/A,QUOTES/S"
  49. #define CT_TYPE         0
  50. #define CT_ACTION       1
  51. #define CT_QUOTES       2
  52. #define CT_LENGTH       3
  53. LONG ConfigLine[CT_LENGTH];
  54.  
  55.  
  56. /* The Command Line Template */
  57. #define COMMAND_TEMPLATE (APTR)"FILE,ICON/S,MENU/S,ICONNAME/K,MENUNAME/K,REQUESTER=REQ/S,"\
  58.                                "ALL/S,PACK/K,AFILE/K,TMPDIR/K,KEEPFILES=KF/S,SC=SHORTCUT/S,"\
  59.                                "MAN/K"
  60. #define CO_FILE         0
  61. #define CO_ICON         1
  62. #define CO_MENU         2
  63. #define CO_ICONNAME     3
  64. #define CO_MENUNAME     4
  65. #define CO_REQ          5
  66. #define CO_ALL          6
  67. #define CO_PACK         7
  68. #define CO_AFILE        8
  69. #define CO_TMPDIR       9
  70. #define CO_KEEPFILES    10
  71. #define CO_SHORTCUT     11
  72. #define CO_MAN          12
  73. #define CO_LENGTH       13
  74. LONG CommandLine[CO_LENGTH];
  75.  
  76. #define BUFSIZE 512
  77. #define PNAME "MegaView"
  78. #define ABOUT PNAME " V" REVISION "\n© 1993 DIgital DImensions\nVersion " REVISION
  79.  
  80. char win[256];
  81.  
  82. char pbuf[512];
  83. BOOL wbrun=FALSE;
  84. BOOL IconMode=FALSE, MenuMode=FALSE;
  85. char IconName[50];
  86. char MenuName[50];
  87. BOOL Recurse=FALSE;
  88. char XPKName[50];
  89. char ftstring[50];
  90. char ACTIONFILE[50];
  91. char TEMPDIR[50];
  92. char EDITOR[50];
  93. BOOL KeepFiles=FALSE;
  94. BOOL ShortCut=FALSE;
  95.  
  96. LONG ix=0,iy=0;
  97.  
  98. #define ICONID 4711L
  99.  
  100. char FileName[256]="";
  101. int NumArgs=0;
  102. struct FileRequester *request=NULL;
  103.  
  104. struct TagItem witags[] = {
  105.     WI_Deep, DEEPTYPE,
  106.     WI_FIB, 0,
  107.     TAG_DONE, 0L
  108. };
  109.  
  110. struct TagItem atags[] = {
  111.     ASL_Hail,       0L,
  112.     ASL_Dir,        0L,
  113.     TAG_DONE,       0L
  114. };
  115.  
  116. struct TagItem atags2[] = {
  117.     ASL_FuncFlags,  FILF_MULTISELECT,
  118.     TAG_DONE,   0L
  119. };
  120.  
  121. /* This is the icon data. You can remove the stuff and replace it
  122.  * with an image done with the IconEdit program (Save as C...)  
  123.  */
  124. UWORD MegaViewI1Data[] =
  125. {
  126. /* Plane 0 */
  127.     0x0000,0x0000,0x0000,0x3F80,0x0000,0x0000,0x0000,0x60E0,
  128.     0x0000,0x0000,0x0001,0xF830,0x0000,0x0000,0x001F,0xFF98,
  129.     0x0000,0x0000,0x0020,0x0058,0x0000,0x0000,0x0027,0x9E58,
  130.     0x0AAA,0xAAFE,0xAAA7,0x9E58,0x2822,0xAAEE,0xAAA7,0x9E70,
  131.     0x22A8,0x0000,0x02A0,0x0060,0x2AA8,0x0000,0x03A0,0x0040,
  132.     0x2AA8,0x00E0,0x03A0,0x0040,0x2AA8,0x07F8,0x03A0,0x0040,
  133.     0x2AA8,0x3FF0,0x03A0,0x0040,0x2AA8,0x7FEF,0x03A0,0x0040,
  134.     0x2AA8,0xFFFF,0x03A2,0xAA40,0x2AA8,0x73FE,0x03AA,0xAAC0,
  135.     0x2AA8,0x01DF,0xC3AA,0xAAC0,0x2AA8,0x000F,0xE3AA,0xAC00,
  136.     0x2AA8,0x0000,0x63AA,0xAC00,0x2AA8,0x0000,0x03AA,0xAC00,
  137.     0x2AA8,0x0000,0x03AA,0xAC00,0x2AA7,0xFFFF,0xFFCA,0xAC00,
  138.     0x0AAA,0xBEAA,0xBEAA,0x8C00,0x0000,0x0000,0x0000,0x0C00,
  139.     0x0000,0x0000,0x0000,0x0C00,0x7FFF,0xFFFF,0xFFFF,0xFC00,
  140.     0x0000,0x0000,0x0000,0x0000,
  141. /* Plane 1 */
  142.     0x0000,0x0000,0x0000,0x4000,0x0000,0x0000,0x0000,0x8100,
  143.     0x0000,0x0000,0x0002,0x0040,0x0000,0x0000,0x0000,0x0020,
  144.     0xFFFF,0xFFFF,0xFFDF,0xFFA0,0xD555,0x5555,0x5558,0x61A0,
  145.     0xD000,0x0100,0x0018,0x61A0,0xC7D8,0x0110,0x0018,0x6180,
  146.     0xCC03,0xFFFF,0xFC1F,0xFF80,0xC003,0xFFFF,0xFC1F,0xFF80,
  147.     0xC003,0xFFDF,0xFC1F,0xFF80,0xC003,0xFFE7,0xFC1F,0xFF80,
  148.     0xC003,0xFCCF,0xFC1F,0xFF80,0xC003,0xF19E,0xFC1F,0xFF80,
  149.     0xC003,0xE76C,0xFC1D,0x5580,0xC003,0x8F99,0xFC15,0x5500,
  150.     0xC003,0xFE3F,0xBC15,0x5500,0xC003,0xFFF0,0xDC00,0x1000,
  151.     0xC003,0xFFFF,0x9C00,0x1000,0xC003,0xFFFF,0xFC00,0x1000,
  152.     0xC003,0xFFFF,0xFC00,0x1000,0xC008,0x0000,0x0000,0x1000,
  153.     0xD000,0x4000,0x4000,0x5000,0xD555,0x5555,0x5555,0x5000,
  154.     0xD555,0x5555,0x5555,0x5000,0x8000,0x0000,0x0000,0x0000,
  155.     0x0000,0x0000,0x0000,0x0000,
  156. };
  157.  
  158. struct Image MegaViewI1 =
  159. {
  160.     0, 0,                       /* Upper left corner */
  161.     61, 27, 2,                  /* Width, Height, Depth */
  162.     MegaViewI1Data,             /* Image data */
  163.     0x0003, 0x0000,             /* PlanePick, PlaneOnOff */
  164.     NULL                        /* Next image */
  165. };
  166.  
  167. struct DiskObject MegaView =
  168. {
  169.     WB_DISKMAGIC,               /* Magic Number */
  170.     WB_DISKVERSION,             /* Version */
  171.     {                           /* Embedded Gadget Structure */
  172.         NULL,                   /* Next Gadget Pointer */
  173.         0, 0, 61, 27,           /* Left,Top,Width,Height */
  174.         GADGIMAGE | GADGHCOMP,  /* Flags */
  175.         RELVERIFY,              /* Activation Flags */
  176.         BOOLGADGET,             /* Gadget Type */
  177.         (APTR)&MegaViewI1,      /* Render Image */
  178.         NULL,                   /* Select Image */
  179.         NULL,                   /* Gadget Text */
  180.         NULL,                   /* Mutual Exclude */
  181.         NULL,                   /* Special Info */
  182.         100,                    /* Gadget ID */
  183.         (APTR) 0x0001,          /* User Data (Revision) */
  184.     },
  185.     WBTOOL,                     /* Icon Type */
  186.     NULL,                       /* Default Tool */
  187.     NULL,                       /* Tool Type Array */
  188.     NO_ICON_POSITION,           /* Current X */
  189.     NO_ICON_POSITION,           /* Current Y */
  190.     NULL,                       /* Drawer Structure */
  191.     NULL,                       /* Tool Window */
  192.     4096                                /* Stack Size */
  193. };
  194.  
  195.  
  196. BOOL FileRequest(void) {
  197. /*
  198.  * Call an ASL File Requester. This one is multi-selectable. The return
  199.  * value indicates if cancel (=FALSE) was pressed, or it was terminated
  200.  * OK (=TRUE)
  201.  */
  202.     static char dir[256] = "\0";
  203.     BOOL result;
  204.  
  205.     NumArgs = 0;
  206.  
  207.     if (!request) request=(struct FileRequester *)
  208.         AllocAslRequestTags(ASL_FileRequest,
  209.             ASL_Hail, "MegaView V" REVISION,
  210.             ASL_Dir,  dir,
  211.             TAG_DONE);
  212.     if (request==NULL) return FALSE ;
  213.     result = AslRequest(request,atags2);
  214.     if (result==FALSE) return FALSE;
  215.     strcpy(dir,(char *)(request->rf_Dir));
  216.     NumArgs=request->rf_NumArgs;
  217.     /* if only one file was selected, copy this to the global variable
  218.      * FileName.
  219.      */
  220.     if (NumArgs == 0) {
  221.         strncpy(FileName,(char *)(request->rf_Dir),256);
  222.         AddPart((STRPTR)FileName,(STRPTR)request->rf_File,256);
  223.     } else {
  224.         /* Otherwise just copy the directory name and let the caller
  225.          * tag on the rest
  226.          */
  227.         strncpy(FileName,(char *)(request->rf_Dir),256);
  228.     }
  229.     return TRUE;
  230. }
  231.  
  232. long ShowRequest(STRPTR text, STRPTR gads) {
  233. /* Show a standard intuition EasyRequest. The first argument is
  234.  * the text of the request, while the second is used to label
  235.  * the gadgets. Note that you may have any number of gadgets
  236.  * by just putting in a bar ("|") character between the labels,
  237.  * e.g. "OK|Break|Cancel". The return value will be the number of
  238.  * the gadget that was pressed. Note however, that the first gadget
  239.  * is number 1, the second is 2, etc. upto the last, which will
  240.  * be number 0! OK in the above example would be 1, Break would be
  241.  * 2 and Cancel WOULD BE 0!
  242.  */
  243.     struct EasyStruct es;
  244.     es.es_StructSize=sizeof(struct EasyStruct);
  245.     es.es_Flags=0;
  246.     es.es_Title=(UBYTE *)PNAME "V" REVISION;
  247.     es.es_TextFormat=(UBYTE *)text;
  248.     es.es_GadgetFormat=(UBYTE *)gads;
  249.     return EasyRequestArgs(NULL,&es,NULL,NULL);
  250. }
  251.  
  252. void print(STRPTR s) {
  253.     if (wbrun==TRUE && IntuitionBase) ShowRequest(s,GetString(msgOK));
  254.     else printf("%s\n",(char *)s);
  255. }
  256.  
  257. void CloseAll(STRPTR s) {
  258. /* This routine is used to panic out of the program, cleaning up
  259.  * as much of the mess as possible. If called with a text as
  260.  * parameter, this text is printed on the console, if MegaView
  261.  * was run from shell, or pop up a requester if it was launched
  262.  * from WB.
  263.  */
  264.     if (s) print(s);
  265.     CloseMegaViewCatalog();
  266.     if (request)        FreeAslRequest(request);
  267.     if (XpkBase)        CloseLibrary(XpkBase);
  268.     if (WhatIsBase)     CloseLibrary(WhatIsBase);
  269.     if (IntuitionBase)  CloseLibrary(IntuitionBase);
  270.     if (WorkbenchBase)  CloseLibrary(WorkbenchBase);
  271.     if (IconBase)       CloseLibrary(IconBase);
  272.     if (AslBase)        CloseLibrary(AslBase);
  273.     if (LocaleBase)     CloseLibrary(LocaleBase);
  274.     exit(0L);
  275. }
  276.  
  277. void OpenAll(void) {
  278. /* This is the reverse of the above, opening all resources we need
  279.  * globally for MegaView, and doing some global initialization.
  280.  */
  281.     strcpy(FileName,"\0");
  282.     XpkBase         =   OpenLibrary((APTR)"xpkmaster.library",2L);
  283.     LocaleBase      =   OpenLibrary((APTR)"locale.library",38L);
  284.     WhatIsBase      =   OpenLibrary((APTR)"whatis.library",0L);
  285.     if (!WhatIsBase)    CloseAll(GetString(msgNeedWhatIs));
  286.     IntuitionBase   =   OpenLibrary((APTR)"intuition.library",37L);
  287.     if (!IntuitionBase) CloseAll(GetString(msgNeedIntuition));
  288.     WorkbenchBase   =   OpenLibrary((APTR)"workbench.library",37L);
  289.     if (!WorkbenchBase) CloseAll(GetString(msgNeedWorkbench));
  290.     IconBase        =   OpenLibrary((APTR)"icon.library",37L);
  291.     if (!IconBase)      CloseAll(GetString(msgNeedIcon));
  292.     AslBase         =   OpenLibrary((APTR)"asl.library",37L);
  293.     if (!AslBase)       CloseAll(GetString(msgNeedASL));
  294.     OpenMegaViewCatalog(NULL,NULL);
  295. }
  296.  
  297. BOOL Scan(char *type, APTR buf, ULONG bufsize, BOOL *quotes) {
  298. /* This routine scans the FileActions file, trying to find an action
  299.  * for the file type given in <file>. If it is successfull, it returns
  300.  * TRUE and fills the buffer pointed at by <buf> with the action template
  301.  * from the file. <quotes> is set if the actions wished to have its filename
  302.  * enclosed with quotes. If unsuccessful, it returns FALSE.
  303.  */
  304.     BPTR fh=NULL;
  305.     APTR cs;
  306.     int line=0;
  307.     int c=0;
  308.     UBYTE *cur;
  309.     BOOL res=TRUE;
  310.     struct RDArgs *myargs=NULL,*ap;
  311.     fh=Open((APTR) ACTIONFILE,MODE_OLDFILE);
  312.     if (!fh) CloseAll(GetString(msgNeedActionfile));
  313.     /* try to set up a ReadArgs structure. We want the input to come
  314.      * from a filehanle, not from the command line.
  315.      */
  316.     cs= AllocVec(BUFSIZE,MEMF_CLEAR);
  317.     if (!cs) {
  318.         if (fh) Close(fh);
  319.         fh=NULL;
  320.         return FALSE;
  321.     }
  322.     myargs=(struct RDArgs *)AllocDosObject(DOS_RDARGS,TAG_DONE);
  323.     if (!myargs) {
  324.         if (fh) Close(fh);
  325.         fh = NULL;
  326.         FreeVec(cs);
  327.         return FALSE;
  328.     }
  329.     /* Main loop starts here */
  330.     do {
  331.         line++;
  332.         /* Read a line from the file */
  333.         cur=(UBYTE *)FGets(fh,(STRPTR)cs,BUFSIZE);
  334.         if (!cur) {
  335.             res=FALSE;
  336.             break;
  337.         }
  338.         c=0;
  339.         c=strlen(cur);
  340.         /* skip empty and comment lines */
  341.         if (*cur==';') continue;
  342.         if (*cur=='\n') continue;
  343.         if (cur[c-1]!='\n') {
  344.             print(GetString(msgMissingNewline));
  345.             res=FALSE;
  346.             break;
  347.         }
  348.         /* Parse the line, using the ReadArgs call and the Template */
  349.         myargs->RDA_Flags |= RDAF_NOPROMPT;
  350.         myargs->RDA_Source.CS_Buffer = cs;
  351.         myargs->RDA_Source.CS_Length = c;
  352.         myargs->RDA_Source.CS_CurChr = 0L;
  353.         ap=ReadArgs(CONFIG_TEMPLATE,ConfigLine,myargs);
  354.         if (!ap) {
  355.             /* We had an error while parsing, so bail out here and
  356.              * tell the user
  357.              */
  358.             res=FALSE;
  359.             Fault(IoErr(),NULL, cs, BUFSIZE);
  360.             sprintf(pbuf,GetString(msgParseError), line, (char *)cs);
  361.             print((STRPTR)pbuf);
  362.             break;
  363.         }
  364.         /* The Parse was successful if we reach here. Look what filetype
  365.          * is this entry for. If it is the one we seek, prepare to leave
  366.          */
  367.         if (stricmp(type,(char *)ConfigLine[CT_TYPE])==0) {
  368.             strncpy((char *)buf,(char *)ConfigLine[CT_ACTION],bufsize);
  369.             res=TRUE;
  370.             if (bufsize<strlen((char *)ConfigLine[CT_ACTION])) res=FALSE;
  371.             if (ConfigLine[CT_QUOTES]) *quotes=TRUE; else *quotes=FALSE;
  372.             break;
  373.         }
  374.         FreeArgs(ap);
  375.     } while (1);
  376.     /* Clean up behind us */
  377.     if (fh) Close(fh);
  378.     fh = NULL;
  379.     if (cs) FreeVec(cs);
  380.     if (myargs) FreeDosObject(DOS_RDARGS,myargs);
  381.     return res;
  382. }
  383.  
  384. void HandleFile(char *fname) {
  385. /* The heart of the matter. This routine takes a filename as its argument
  386.  * and tries to find a matching action for it. If successful, this action
  387.  * is performed on the file.
  388.  */
  389.     BOOL bl,ok,quote;
  390.     char cln[512];
  391.     char clx[512];
  392.     BPTR lock;
  393.     APTR Buffer;
  394.     BPTR window;
  395.     LONG err;
  396.     BPTR CLock, NLock;
  397.     FileType DirType,VolType,ft;
  398.     struct FileInfoBlock *fib,*bif;
  399.     int i;
  400.     Buffer=AllocVec(BUFSIZE,MEMF_CLEAR);
  401.     if (Buffer) {
  402.         /* We have 'nuff memory to do it, so lock the file, and we will
  403.          * try to get more info on it.
  404.          */
  405.         lock=Lock((APTR)fname, SHARED_LOCK);
  406.         if (lock) {
  407.             /* The lock was ok, get the file's FileInfoBlock. First, we
  408.              * must allocate this (via AllocDosObject).
  409.              */
  410.             fib=(struct FileInfoBlock *)AllocDosObject(DOS_FIB,NULL);
  411.             if (fib) {
  412.                 /* Examine the file. We need this info for the filetype
  413.                  * examination. */
  414.                 Examine(lock,fib);
  415.                 witags[1].ti_Data=(ULONG)fib;
  416.                 /* Now, what type is this file? WhatIs will check this for us*/
  417.                 ft=WhatIs(fname,witags);
  418.                 /* Do we know this file? */
  419.                 if (CmpFileType(ft,TYPE_UNKNOWNFILETYPE)==0) {
  420.                     print(GetString(msgUnknownFiletype));
  421.                 } else {
  422.                     DirType = GetIDType("Dir");
  423.                     VolType = GetIDType("Volume");
  424.                     /* Check if the "file" was a directory or volume, and
  425.                      * the Recurse flag was set. If yes, go down into the
  426.                      * directory and scan ALL files there, recursively.
  427.                      */
  428.                     if (Recurse==TRUE && (CmpFileType(DirType,ft)==0 || CmpFileType(VolType,ft)==0)) {
  429.                         NLock=Lock((APTR)fname,SHARED_LOCK);
  430.                         if (NLock) {
  431.                             CLock=CurrentDir(NLock);
  432.                             if (CLock) {
  433.                                 /* We tried to enter the directory, and we
  434.                                  * were successful. Examine the directory
  435.                                  * recursively, and HandleFile() every entry
  436.                                  * we find, thus descending into subdirs
  437.                                  * using the same mechanism. This could
  438.                                  * eat up a lot of stack!
  439.                                  */
  440.                                 bif=(struct FileInfoBlock *)AllocDosObject(DOS_FIB,NULL);
  441.                                 if (bif) {
  442.                                     ok=Examine(NLock,bif);
  443.                                     while (ok!=FALSE) {
  444.                                         ok=ExNext(NLock,bif);
  445.                                         if (ok) HandleFile(bif->fib_FileName);
  446.                                         /* Recursion Alert! Watch yer stack! */
  447.                                     }
  448.                                     if (IoErr()!=ERROR_NO_MORE_ENTRIES) {
  449.                                         print(GetString(msgErrorReadingDir));
  450.                                     }
  451.                                     FreeDosObject(DOS_FIB,bif);
  452.                                 } else print(GetString(msgErrorFileInfoBlock));
  453.                             } else print(GetString(msgErrorCurrentDir));
  454.                             CurrentDir(CLock);
  455.                             UnLock(NLock);
  456.                         } else print(GetString(msgErrorLockDirectory));
  457.                     } else {
  458.                         /* We reach here if we are to examine the file(s)
  459.                          * normally. First, we do look if the file is one
  460.                          * of the "crunched" types.
  461.                          */
  462.                         strcpy(ftstring,GetIDString(ft));
  463.                         if (XPKName[0]!='\0' && MatchToolValue((STRPTR)XPKName,(STRPTR)ftstring)) {
  464.                             /* The file is packed. We use the TEMPDIR value 
  465.                              * from the environment and decrunch it there.
  466.                              * We HandleFile() the result again. Note that
  467.                              * if the crunched file was crunched more than
  468.                              * once (quite silly, but not impossible), we
  469.                              * will decrunch it until we have it complete.
  470.                              */
  471.                             strcpy(cln,TEMPDIR);
  472.                             AddPart((STRPTR)cln,FilePart((STRPTR)fname),512);
  473.                             err=XpkUnpackTags(XPK_InName,fname,
  474.                                               XPK_OutName,cln,
  475.                                               TAG_DONE);
  476.                             if (err!=XPKERR_OK) {
  477.                                 sprintf(cln,"XPK Error %d\n",err);
  478.                                 print((STRPTR)cln);
  479.                             } else {
  480.                                 HandleFile(cln);
  481.                                 /* Recursion Alert! Watch yer stack! */
  482.                                 if (KeepFiles==FALSE) DeleteFile((STRPTR)cln);
  483.                             }
  484.                         } else { 
  485.                             /* The final stage, this is where files get
  486.                              * finally handled if they are neither crunched
  487.                              * nor directory/volumes. We get the ACTION via 
  488.                              * the Scan() routine, and perform it, possibly
  489.                              * enclosing the filename with quotes if desired.
  490.                              */
  491.                             bl=Scan(ftstring,Buffer,BUFSIZE,"e);
  492.                             if (bl==FALSE) {
  493.                                 sprintf(cln,GetString(msgNoAction),ftstring);
  494.                                 print((STRPTR)cln);
  495.                             } else {
  496.                                 if (quote==TRUE) sprintf(clx,"\042%s\042",fname);
  497.                                 else             strcpy(clx,fname);
  498.                                 sprintf(cln,(char *)Buffer,clx);
  499.                                 window=Open((STRPTR)win,MODE_READWRITE);
  500.                                 /* Call the program */
  501.                                 SystemTags((STRPTR)cln,
  502.                                     SYS_Output, window,
  503.                                     TAG_DONE);
  504.                                 Close(window);
  505.                             }
  506.                         }
  507.                     }
  508.                 }
  509.                 /* Clean up after us */
  510.                 FreeDosObject(DOS_FIB,fib);
  511.             } else print(GetString(msgErrorFileInfoBlock));
  512.             UnLock(lock);
  513.         } else print(GetString(msgErrorLockFile));
  514.         FreeVec(Buffer);
  515.     } else print(GetString(msgErrorAllocateBuffer));
  516. }
  517.  
  518. void SetUpAndHandleIcon(char *IconName) {
  519. /* This routine, as the name implies, sets up the icon and does the
  520.  * handling thereof. It is the routine that gets executed the most
  521.  * if you are running MegaView in Icon mode.
  522.  */
  523.     struct DiskObject *dobj;
  524.     struct AppIcon *ai;
  525.     struct MsgPort *port;
  526.     struct AppMessage *msg;
  527.     char fname[512];
  528.     int i;
  529.     BOOL loaded=FALSE;
  530.     BPTR oldlock;
  531.     BOOL running=TRUE;
  532.     BOOL flg=FALSE;
  533.     /* GetDiskObject() tries to find an Icon with the name specified
  534.      * in the command line/ToolTypes. If no name was given, this is
  535.      * the name of the Icon MegaView was started with. If none is
  536.      * found, the default icon (struct DiskObject MegaView above) is
  537.      * used to represent us on the workbench.
  538.      */
  539.     dobj=GetDiskObject((STRPTR)IconName);
  540.     if (dobj==NULL) dobj=&MegaView;
  541.     else loaded=TRUE;
  542.     /* ix and iy contain the x/y coordinate pair we want out icon to
  543.      * appear. If none was specified, we let workbench decide were
  544.      * to put the icon, by setting the x/y coordinates to the constant
  545.      * NO_ICON_POSITION. Note that the same thing is done with icons
  546.      * on disk: When they are created, the get their coordinates set
  547.      * to the above constant. Doing a SNAPSHOT on those will overwrite
  548.      * the coordinates with real values.
  549.      */
  550.     if (ix==0) dobj->do_CurrentX=NO_ICON_POSITION; else dobj->do_CurrentX=ix;
  551.     if (iy==0) dobj->do_CurrentY=NO_ICON_POSITION; else dobj->do_CurrentY=iy;
  552.     /* We need a message port for the Icon. It is created using the routine
  553.      * from the C/Amiga.lib
  554.      */
  555.     port=CreatePort(NULL,0L);
  556.     if (port) {
  557.         /* If we got our port, we can add our Icon to the workbench's
  558.          * AppIcon list.
  559.          */
  560.         ai=AddAppIconA(ICONID,0L,(STRPTR)IconName,port,
  561.                 NULL,dobj,NULL);
  562.         if (ai) {
  563.             while (running) {
  564.                 /* Wait for anything to happen. 'Anything' can either mean
  565.                  * that someone dropped (an) Icon(s) on us, or that someone
  566.                  * double-stabbed us with the mouse.
  567.                  * In either case, this should be a message of type 
  568.                  * MTYPE_APPICON, every other message will simply
  569.                  * bounce off.
  570.                  */
  571.                 Wait(1<<port->mp_SigBit);
  572.                 while (msg=(struct AppMessage *)GetMsg(port)) {
  573.                     if (msg->am_Type!=MTYPE_APPICON) {
  574.                         ReplyMsg((struct Message *)msg);
  575.                         continue;
  576.                     }
  577.                     if (msg->am_NumArgs==0) {
  578.                         /* A NumArgs of zero means that our icon was
  579.                          * double clicked. Every value greater than
  580.                          * that means there was this number of icons
  581.                          * for us to handle.
  582.                          */
  583.                         if (ShortCut==TRUE) i=2;
  584.                         else i=ShowRequest((STRPTR)ABOUT,GetString(msgReqText));
  585.                         switch(i) {
  586.                         case 0:
  587.                             break;
  588.                         case 1:
  589.                             running=FALSE;
  590.                             break;
  591.                         case 2:
  592.                             flg=TRUE;
  593.                             while (flg==TRUE) {
  594.                                 flg=FileRequest();
  595.                                 if (flg==FALSE) break;
  596.                                 if (NumArgs==0) HandleFile(FileName);
  597.                                 else {
  598.                                     int i;
  599.                                     char buffer[256];
  600.                                     for (i=0; i<NumArgs; i++) {
  601.                                         strncpy(buffer,FileName,256);
  602.                                         AddPart((STRPTR)buffer,(STRPTR)(request->rf_ArgList[i].wa_Name),256);
  603.                                         HandleFile(buffer);
  604.                                     }
  605.                                 }
  606.                                 if (flg==TRUE) Delay(1L);
  607.                             }
  608.                             break;
  609.                         case 3:
  610.                             SystemTagList((STRPTR)EDITOR,NULL);
  611.                             break;
  612.                         }
  613.                     } else {
  614.                         /* We got one or more icons. The WBArg structure array
  615.                          * contains the file name, and the lock to the
  616.                          * files directory. We CurrentDir() (=CD) into this
  617.                          * dir and HandleFile() the file.
  618.                          */
  619.                         for (i=0; i<msg->am_NumArgs; i++) {
  620.                             strcpy(fname,(char *)(msg->am_ArgList[i].wa_Name));
  621.                             oldlock=CurrentDir(msg->am_ArgList[i].wa_Lock);
  622.                             HandleFile(fname);
  623.                             CurrentDir(oldlock);
  624.                         }
  625.                     }
  626.                     /* Messages MUST ALWAYS be sent back, or the system
  627.                      * will lock.
  628.                      */
  629.                     ReplyMsg((struct Message *)msg);
  630.                 }
  631.             }
  632.             /* Make sure there is no pending message at our port,
  633.              * by replying everything that is still queued up.
  634.              */
  635.             while (msg=(struct AppMessage *)GetMsg(port)) {
  636.                 ReplyMsg((struct Message *)msg);
  637.             }
  638.             /* Remove the icon from the Workbench */
  639.             RemoveAppIcon(ai);
  640.         } else print(GetString(msgErrorAppIcon));
  641.         DeletePort(port);
  642.     } else print(GetString(msgErrorCreatePort));
  643.     /* If out Icon was loaded from disk, free the memory space */
  644.     if (loaded==TRUE) {
  645.         FreeDiskObject(dobj);
  646.     }
  647. }
  648.  
  649.  
  650. void SetUpAndHandleMenu(char *MenuName) {
  651. /* This routine does the same as the above icon handler, except that there
  652.  * is no need to load an icon image. Everything is handled exactly the
  653.  * same way as above.
  654.  */
  655.     struct AppMenuItem *ai;
  656.     struct MsgPort *port;
  657.     struct AppMessage *msg;
  658.     char fname[512];
  659.     int i;
  660.     BPTR oldlock;
  661.     BOOL running=TRUE;
  662.     BOOL flg=FALSE;
  663.     port=CreatePort(NULL,0L);
  664.     if (port) {
  665.         ai=AddAppMenuItemA(ICONID,0L,(STRPTR)MenuName,port,NULL);
  666.         if (ai) {
  667.             while (running) {
  668.                 Wait(1<<port->mp_SigBit);
  669.                 while (msg=(struct AppMessage *)GetMsg(port)) {
  670.                     if (msg->am_Type!=MTYPE_APPMENUITEM) {
  671.                         ReplyMsg((struct Message *)msg);
  672.                         continue;
  673.                     }
  674.                     if (msg->am_NumArgs==0) {
  675.                         if (ShortCut==TRUE) i=2;
  676.                         else i=ShowRequest((STRPTR)ABOUT,GetString(msgReqText));
  677.                         switch(i) {
  678.                         case 0:
  679.                             break;
  680.                         case 1:
  681.                             running=FALSE;
  682.                             break;
  683.                         case 2:
  684.                             flg=TRUE;
  685.                             while (flg==TRUE) {
  686.                                 flg=FileRequest();
  687.                                 if (flg==FALSE) break;
  688.                                 if (NumArgs==0) HandleFile(FileName);
  689.                                 else {
  690.                                     int i;
  691.                                     char buffer[256];
  692.                                     for (i=0; i<NumArgs; i++) {
  693.                                         strncpy(buffer,FileName,256);
  694.                                         AddPart((STRPTR)buffer,(STRPTR)(request->rf_ArgList[i].wa_Name),256);
  695.                                         HandleFile(buffer);
  696.                                     }
  697.                                 }
  698.                                 if (flg==TRUE) Delay(1L); /* this is here to fix an optimzer bug in Aztec 5.0 */
  699.                             }
  700.                             break;
  701.                         case 3:
  702.                             SystemTagList((STRPTR)EDITOR,NULL);
  703.                             break;
  704.                         }
  705.                     } else {
  706.                         for (i=0; i<msg->am_NumArgs; i++) {
  707.                             strcpy(fname,(char *)(msg->am_ArgList[i].wa_Name));
  708.                             oldlock=CurrentDir(msg->am_ArgList[i].wa_Lock);
  709.                             HandleFile(fname);
  710.                             CurrentDir(oldlock);
  711.                         }
  712.                     }
  713.                     ReplyMsg((struct Message *)msg);
  714.                 }
  715.             }
  716.             while (msg=(struct AppMessage *)GetMsg(port)) {
  717.                 ReplyMsg((struct Message *)msg);
  718.             }
  719.             RemoveAppMenuItem(ai);
  720.         } else print(GetString(msgErrorAppMenu));
  721.         DeletePort(port);
  722.     } else print(GetString(msgErrorCreatePort));
  723. }
  724.  
  725. void HandleWBStartup(char **argv) {
  726. /* What we do here is to handle startup via the workbench. This routine does
  727.  * also handle the tooltypes, and processes files that were selected when
  728.  * our program icon was double clicked, or which had us as there default
  729.  * tool. Please note that being multi-select-started (i.e. being started
  730.  * with some projects selected simultaneously) or being started as a
  731.  * default tool makes not much difference for a program.
  732.  */
  733.     int i;
  734.     BPTR oldlock;
  735.     struct WBStartup *wbs;
  736.     char fname[256];
  737.     UBYTE **ta, *s;
  738.     struct DiskObject *dob;
  739.     struct WBArg *wba;
  740.     /* C startup code stores the WBStartup message in argv if argc is zero */
  741.     wbs=(struct WBStartup *)argv;
  742.     wbrun=TRUE;
  743.     wba=wbs->sm_ArgList;
  744.     strcpy(IconName,PNAME);
  745.     strcpy(MenuName,PNAME);
  746.     /* If there is more than one icon selected when we were launched, we
  747.      * want them to be displayed. This works much the same way as with the
  748.      * AppIcon messages. The AppIcon message supplied us with an array
  749.      * of WBArg structures. The WBStartup message does the same.
  750.      */
  751.     if (wbs->sm_NumArgs>1) { /* Display Files */
  752.         if (wba->wa_Name) {
  753.             /* We load the project's icon to examine its tooltypes */
  754.             dob=GetDiskObject((STRPTR)(wba->wa_Name));
  755.             if (dob) {
  756.                 ta = (UBYTE **)dob->do_ToolTypes;
  757.                 /* There are two ToolType handling functions, FindToolType()
  758.                  * and MatchToolValue(). The first searches for a line
  759.                  * <VARIABLE>=<value> in the tooltype array and returns
  760.                  * the <value> part. MatchToolValue() checks if there is
  761.                  * a string in the <value> which matches the string we
  762.                  * search, e.g. you can look for a "YES" in a value of
  763.                  * "YES|JA|OUI|SI", or you can check if you need to 
  764.                  * set styles like "BOLD|ITALIC". See RKM's for details
  765.                  */
  766.                 if (s=FindToolType(ta,(UBYTE *)"WINDOW"))   strcpy(win,s);
  767.                 if (s=FindToolType(ta,(UBYTE *)"RECURSE"))  Recurse=TRUE;
  768.                                                     else    Recurse=FALSE;             
  769.                 if (s=FindToolType(ta,(UBYTE *)"PACK"))     strcpy(XPKName,s);
  770.                 if (s=FindToolType(ta,(UBYTE *)"AFILE"))    strcpy(ACTIONFILE,s);
  771.                 if (s=FindToolType(ta,(UBYTE *)"TMPDIR"))   strcpy(TEMPDIR,s);
  772.                 if (s=FindToolType(ta,(UBYTE *)"KEEPFILES"))KeepFiles=TRUE;
  773.                 if (s=FindToolType(ta,(UBYTE *)"EDITOR"))   strcpy(EDITOR,s);
  774.                 FreeDiskObject(dob);
  775.             }
  776.         } 
  777.         /* Do the showing. This is, as I said, exactly as in the icon handler */
  778.         for (i=1; i<wbs->sm_NumArgs; i++) {
  779.             strcpy(fname,(char *)(wbs->sm_ArgList[i].wa_Name));
  780.             oldlock=CurrentDir(wbs->sm_ArgList[i].wa_Lock);
  781.             HandleFile(fname);
  782.             CurrentDir(oldlock);
  783.         }
  784.     } else {
  785.         /* We were started as a tool, without arguments. Look into the
  786.          * tooltype array what exactly we are supposed to do, or tell
  787.          * the user that we need more info on something
  788.          */
  789.         if (wba->wa_Name) {
  790.             dob=GetDiskObject((STRPTR)(wba->wa_Name));
  791.             if (dob) {
  792.                 ta = (UBYTE  **)dob->do_ToolTypes;
  793.                 if (s=FindToolType(ta,(UBYTE *)"SHORTCUT")) ShortCut=TRUE;
  794.                 if (s=FindToolType(ta,(UBYTE *)"WINDOW"))   strcpy(win,s);
  795.                 if (s=FindToolType(ta,(UBYTE *)"ICONNAME")) strcpy(IconName,s);
  796.                 if (s=FindToolType(ta,(UBYTE *)"MENUNAME")) strcpy(MenuName,s);
  797.                 if (s=FindToolType(ta,(UBYTE *)"MODE")) {
  798.                     /* Decide if we should stay resident. Either
  799.                      * MODE=Icon or MODE=Menu must be specified, or
  800.                      * we will exit with a short requester. Icon and Menu
  801.                      * are mutually exclusive, you can only specify one
  802.                      */
  803.                     if (MatchToolValue(s,(UBYTE *)"Icon"))  IconMode=TRUE;
  804.                     if (MatchToolValue(s,(UBYTE *)"Menu"))  MenuMode=TRUE;
  805.                     /* Note that the above would make it possible to 
  806.                      * specify MODE=Icon|Menu, resulting in both modes
  807.                      * to be set. We check below if this happened, and
  808.                      * if yes, refuse to run.
  809.                      */
  810.                 }
  811.                 if (s=FindToolType(ta,(UBYTE *)"RECURSE"))  Recurse=TRUE;
  812.                 else Recurse=FALSE;
  813.                 if (s=FindToolType(ta,(UBYTE *)"ICON_X"))   ix=atoi(s);
  814.                 if (s=FindToolType(ta,(UBYTE *)"ICON_Y"))   iy=atoi(s);
  815.                 if (s=FindToolType(ta,(UBYTE *)"PACK"))     strcpy(XPKName,s);
  816.                 if (s=FindToolType(ta,(UBYTE *)"AFILE"))    strcpy(ACTIONFILE,s);
  817.                 if (s=FindToolType(ta,(UBYTE *)"TMPDIR"))   strcpy(TEMPDIR,s);
  818.                 if (s=FindToolType(ta,(UBYTE *)"KEEPFILES"))KeepFiles=TRUE;
  819.                 if (s=FindToolType(ta,(UBYTE *)"EDITOR"))   strcpy(EDITOR,s);
  820.                 FreeDiskObject(dob);
  821.                 if (IconMode && MenuMode) {
  822.                     print(GetString(msgErrorMenuIcon));
  823.                 } else {
  824.                     if (IconMode==TRUE) SetUpAndHandleIcon(IconName);
  825.                     if (MenuMode==TRUE) SetUpAndHandleMenu(MenuName);
  826.                     if (MenuMode==FALSE && IconMode==FALSE) {
  827.                         print(GetString(msgWorkbenchUsage));
  828.                     }
  829.                 }
  830.             } else print(GetString(msgErrorIcon));
  831.         } else print(GetString(msgNoIcon));
  832.         /* this funny error message means that the user has shift-clicked
  833.          * an icon which does not exists, and this should not happen at all.
  834.          */
  835.     }
  836. }
  837.  
  838. void SearchMan(char *name) {
  839. /* Simulate the UN*X 'MAN' command. We get a list of paths, seperated
  840.  * with commas, and search a file which starts with the name specified
  841.  * but does not end with '.info'.
  842.  */
  843.     char NewName[512];
  844.     char dir[512];
  845.     char paths[512];
  846.     struct AnchorPath *ap;
  847.     int i,j,k;
  848.     LONG err;
  849.     BPTR lock,oldlock;
  850.     BOOL ok=FALSE;
  851.     i=GetVar((STRPTR)"MegaViewPATHS",(STRPTR)paths,512,0L);
  852.     if (i==-1) strcpy(paths,".");
  853.     i=0; k=strlen(paths);
  854.     ap=(struct AnchorPath *)AllocMem(sizeof(struct AnchorPath), MEMF_ANY|MEMF_CLEAR);
  855.     if (ap) {
  856.         while (i<k) {
  857.             j=0; 
  858.             /* Extract a path. Treat '.' as the current dir. */
  859.             while (paths[i]!=',' && paths[i]!=0) 
  860.                 dir[j++]=paths[i++];
  861.             ++i;
  862.             dir[j]=0;
  863.             if (strcmp(dir,".")==0) lock=Lock((STRPTR)"",ACCESS_READ);
  864.                                else lock=Lock((STRPTR)dir,ACCESS_READ);
  865.             if (lock) {
  866.                 /* Change into the directory and try to find a file
  867.                  * we can use. MatchFirst will give us the name of
  868.                  * this file, if it exists. In fact, the file is 
  869.                  * matched as (name~(#?.info)|name). This would
  870.                  * match things like name, name.doc, name.dok,
  871.                  * name.documentation.txt, but not things like
  872.                  * name.info or name.documentation.txt.info
  873.                  */
  874.                 oldlock=CurrentDir(lock);
  875.                 sprintf(NewName, "(%s~(#?.info)|%s)", name, name);
  876.                 err=MatchFirst((STRPTR)NewName,ap);
  877.                 if (err==0) {
  878.                     strcpy(name, (char *)ap->ap_Info.fib_FileName);
  879.                     HandleFile(name);
  880.                     ok=TRUE;
  881.                 }
  882.                 MatchEnd(ap);
  883.                 UnLock(lock);
  884.                 lock=NULL;
  885.                 CurrentDir(oldlock);
  886.                 oldlock=NULL;
  887.                 if (ok==TRUE) break;
  888.             } else print(GetString(msgErrorManDir));
  889.         }
  890.         FreeMem((APTR)ap,sizeof(struct AnchorPath));
  891.     } else print(GetString(msgErrorAnchor));
  892. }
  893.  
  894. void main(int argc, char **argv) {
  895. /* The main routine. */
  896.     struct RDArgs *rda;
  897.     char fname[256];
  898.     int i;
  899.     /* Get us the resources we need. If this routine returns at all,
  900.      * the we have everything up and running. If not, it has
  901.      * wimped out of the program, leaving an error message to
  902.      * the user.
  903.      */
  904.     OpenAll();
  905.     /* Get some variables. These could be environment variables
  906.      * (from the ENV: dir) or shell variables. If they don't exist
  907.      * fill the fields with default values.
  908.      */
  909.     i=GetVar((STRPTR)"MegaViewPACK",(STRPTR)XPKName,49,0L);
  910.     if (i==-1) XPKName[0]=0;
  911.     i=GetVar((STRPTR)"MegaViewACTION",(STRPTR)ACTIONFILE,49,0L);
  912.     if (i==-1) strcpy(ACTIONFILE,"s:FileActions");
  913.     i=GetVar((STRPTR)"MegaViewTEMP",(STRPTR)TEMPDIR,49,0L);
  914.     if (i==-1) strcpy(TEMPDIR,"T:");
  915.     i=GetVar((STRPTR)"MegaViewEDIT",(STRPTR)EDITOR,49,0L);
  916.     if (i==-1) strcpy(EDITOR,"FAEdit");
  917.     /* Check if we are run from Workbench (argc is zero) */
  918.     if (argc==0) {
  919.         HandleWBStartup(argv);
  920.         CloseAll(NULL);
  921.     }
  922.     /* Parse the command line. We use the Command template from the
  923.      * beginning of this file. These templates are also used for
  924.      * the system commands, which essentially use the same function
  925.      * for their command line parsing. Calling this function will
  926.      * also display the template if we enter 'MegaView ?', and
  927.      * will prompt for input after that, without our program
  928.      * knowing that.
  929.      */
  930.     rda=ReadArgs(COMMAND_TEMPLATE,CommandLine,NULL);
  931.     /* The result if NULL if the command line was invalid. We print an
  932.      * error message about what was wrong with it, and panic out of the
  933.      * program.
  934.      */
  935.     if (rda==NULL) {
  936.         PrintFault(IoErr(),NULL);
  937.         CloseAll(NULL);
  938.     }
  939.     /* We were given a valid command line. Take out the info we need
  940.      * and store it for later use.
  941.      */
  942.     if (CommandLine[CO_SHORTCUT]) ShortCut=TRUE;
  943.                             else  ShortCut=FALSE;
  944.     if (CommandLine[CO_FILE]) strcpy(fname,(char *)CommandLine[CO_FILE]);
  945.                          else strcpy(fname,"");
  946.     if (CommandLine[CO_PACK]) strcpy(XPKName,(char *)CommandLine[CO_PACK]);
  947.     if (CommandLine[CO_AFILE]) strcpy(ACTIONFILE,(char *)CommandLine[CO_AFILE]);
  948.     if (CommandLine[CO_TMPDIR]) strcpy(TEMPDIR,(char *)CommandLine[CO_TMPDIR]);
  949.     if (CommandLine[CO_KEEPFILES]) KeepFiles=TRUE;
  950.                             else   KeepFiles=FALSE;
  951.     if (CommandLine[CO_REQ]) {
  952.         /* This loop asks for files via the file requester until the user
  953.          * pressed cancel
  954.          */
  955.         BOOL flg;
  956.         for (i=0; i<7; i++) {
  957.             Delay(1L);
  958.             if (!request) request=(struct FileRequester *)AllocAslRequest(ASL_FileRequest,atags);
  959.             if (request) break;
  960.         }
  961.         flg=TRUE;
  962.         while (flg==TRUE) {
  963.             flg=FileRequest();
  964.             if (flg==FALSE) break;
  965.             if (NumArgs==0) HandleFile(FileName);
  966.             else {
  967.                 int i;
  968.                 char buffer[256];
  969.                 for (i=0; i<NumArgs; i++) {
  970.                     strncpy(buffer,FileName,256);
  971.                     AddPart((STRPTR)buffer,(STRPTR)(request->rf_ArgList[i].wa_Name),256);
  972.                     HandleFile(buffer);
  973.                 }
  974.             }
  975.             if (flg==TRUE) Delay(1L); /* this is here to fix an optimzer bug in Aztec 5.0 */
  976.         }
  977.         FreeArgs(rda);
  978.         CloseAll(NULL);
  979.     }
  980.     if (CommandLine[CO_ICON]) {
  981.         if (CommandLine[CO_ICONNAME]) strncpy(IconName,(char *)CommandLine[CO_ICONNAME],50);
  982.         else strcpy(IconName,"MegaView");
  983.         SetUpAndHandleIcon(IconName);
  984.         FreeArgs(rda);
  985.         CloseAll(NULL);
  986.     }
  987.     if (CommandLine[CO_MENU]) {
  988.         if (CommandLine[CO_MENUNAME]) strncpy(MenuName,(char *)CommandLine[CO_MENUNAME],50);
  989.         else strcpy(MenuName,"MegaView");
  990.         SetUpAndHandleMenu(MenuName);
  991.         FreeArgs(rda);
  992.         CloseAll(NULL);
  993.     }
  994.     if (CommandLine[CO_ALL]) {
  995.         Recurse=TRUE;
  996.     } else {
  997.         Recurse=FALSE;
  998.     }
  999.     if (CommandLine[CO_MAN]) {
  1000.         strcpy(fname, (char *)CommandLine[CO_MAN]);
  1001.         SearchMan(fname);
  1002.     } else {
  1003.         if (fname[0]=='\0') {
  1004.             if (CommandLine[CO_ICON]==0 || CommandLine[CO_MENU]==0) {
  1005.                 print(GetString(msgNeedFilename));
  1006.             }
  1007.         } else HandleFile(fname);
  1008.     }
  1009.     FreeArgs(rda);
  1010.     CloseAll(NULL);
  1011. }
  1012.  
  1013.