home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 3 / AACD03.BIN / CDTools / ClassAct / Examples / EnvEdit / EnvEdit.c < prev    next >
C/C++ Source or Header  |  1997-07-09  |  22KB  |  890 lines

  1.  
  2. /**
  3.  **  EnvEdit.c -- Environmental variable editor.
  4.  **
  5.  **  This is a cute little tool to edit your environmental variables with a
  6.  **  GUI.  Seen a dozen of these already have you eh?  Well, this one is
  7.  **  different.  It uses a hierarchical listbrowser, so you can not only
  8.  **  see simple environmental variables, but also ones buried deep in
  9.  **  directories (we'll call those directories "records", since these are
  10.  **  supposed to be variables).  Also, we do not have to call an external
  11.  **  text editor to edit the value of variables, not are we limited to
  12.  **  one-line variables because we use textfield for editing variables.
  13.  **
  14.  **  With all that said, there are somethings missing: the ability to delete,
  15.  **  rename and create variables.  Think of this as an exercise in learning
  16.  **  ClassAct, to add these features (and send us the source when you're
  17.  **  done :).
  18.  **
  19.  **/
  20.  
  21. #include <exec/types.h>
  22. #include <exec/memory.h>
  23. #include <dos/exall.h>
  24. #include <intuition/intuition.h>
  25. #include <intuition/gadgetclass.h>
  26. #include <intuition/imageclass.h>
  27. #include <intuition/icclass.h>
  28. #include <utility/tagitem.h>
  29. #include <proto/dos.h>
  30. #include <proto/exec.h>
  31. #include <proto/icon.h>
  32. #include <proto/intuition.h>
  33. #include <classact.h>
  34. #include <strings.h>
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37.  
  38. /* #define D(x) x to compile with debugging output.
  39.  */
  40. #define D(x)
  41.  
  42. #ifdef _DCC
  43. #define SAVEDS __geta4
  44. #define ASM
  45. #define REG_A0 __A0
  46. #define REG_A1 __A1
  47. #else
  48. #define SAVEDS __saveds
  49. #define ASM __asm
  50. #define REG_A0 register __a0
  51. #define REG_A1 register __a1
  52. #endif
  53.  
  54. enum { GAD_LIST, GAD_EDIT, GAD_SAVE, GAD_USE, GAD_CANCEL };
  55.  
  56. /* ARexx command IDs
  57.  */
  58. enum { REXX_NAME, REXX_VERSION, REXX_AUTHOR, REXX_ACTIVATE, REXX_DEACTIVATE,
  59.         REXX_QUIT, REXX_WINDOWTOBACK, REXX_WINDOWTOFRONT };
  60.  
  61.  
  62.  
  63. /* Some additional info we put in listbrowser node userdata field.
  64.  */
  65. struct LBUserData
  66. {
  67.     UBYTE lbud_FileName[255];
  68.     BOOL lbud_Changed;
  69.     STRPTR lbud_Buf;
  70.     ULONG lbud_BufSize;
  71. };
  72.  
  73.  
  74. /* Function prototypes.
  75.  */
  76. VOID load_text(struct Window *);
  77. LONG file_size(char *);
  78. VOID save_changed(struct List *, STRPTR, BOOL);
  79. BOOL read_files(struct List *, STRPTR, WORD);
  80. VOID bstrcpy(STRPTR, BSTR);
  81. VOID free_list(struct List *);
  82. LONG easy_req(struct Window *, char *, char *, char *, ...);
  83. VOID ASM rexx_name(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
  84. VOID ASM rexx_version(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
  85. VOID ASM rexx_author(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
  86. VOID ASM rexx_activate(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
  87. VOID ASM rexx_deactivate(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
  88. VOID ASM rexx_quit(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
  89. VOID ASM rexx_about(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
  90. VOID ASM rexx_windowtoback(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
  91. VOID ASM rexx_windowtofront(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
  92.  
  93. /* Global variables.
  94.  */
  95. struct List file_list;
  96. struct Gadget *layout, *list_gad, *edit_gad;
  97. struct DrawInfo *drinfo;
  98. Object *window_obj;
  99. struct Window *win;
  100. BOOL ok = TRUE;
  101.  
  102. struct ColumnInfo ci[] =
  103. {
  104.     { 75, "Variable", 0 },
  105.     { 25, "Size", 0 },
  106.     { 75, "Date", 0 },
  107.     { 25, "Time", 0 },
  108.     { -1, (STRPTR)~0, -1 }
  109. };
  110.  
  111. /* ARexx command table.  These commands may not seem terribly useful at first,
  112.  * but these are a basic set of commands that every app should support.
  113.  */
  114. struct ARexxCmd arexx_cmds[] =
  115. {
  116.     { "NAME",            REXX_NAME,            rexx_name,            NULL,        NULL, },
  117.     { "VERSION",        REXX_VERSION,        rexx_version,        NULL,        NULL, },
  118.     { "AUTHOR",            REXX_AUTHOR,        rexx_author,        NULL,        NULL, },
  119.     { "ACTIVATE",        REXX_ACTIVATE,        rexx_activate,        NULL,        NULL, },
  120.     { "DEACTIVATE",        REXX_DEACTIVATE,    rexx_deactivate,    NULL,        NULL, },
  121.     { "QUIT",            REXX_QUIT,            rexx_quit,            NULL,        NULL, },
  122.     { "WINDOWTOBACK",    REXX_WINDOWTOBACK,    rexx_windowtoback,    NULL,        NULL, },
  123.     { "WINDOWTOFRONT",    REXX_WINDOWTOFRONT,    rexx_windowtofront,    NULL,        NULL, },
  124.     { NULL,                NULL,                NULL,                NULL,        NULL, }
  125. };
  126.  
  127.  
  128. /* Custom leaf/show/hide images for the hierarchy control.
  129.  */
  130. __chip UWORD leaf_data[27] =
  131. {
  132.     /* Plane 0 */
  133.     0x0800, 0x1C00, 0x3600, 0x6B00,
  134.     0xD580, 0x6B00, 0x3600, 0x1C00,
  135.     0x0800,
  136.     /* Plane 1 */
  137.     0x0800, 0x1800, 0x3400, 0x6A00,
  138.     0xD500, 0x6A00, 0x3400, 0x1800,
  139.     0x0000,
  140. };
  141.  
  142. struct Image leaf_image =
  143. {
  144.     0, 0, 9, 9, 2, &leaf_data[0], 0x3, 0x0, NULL
  145. };
  146.  
  147. __chip UWORD show_data[27] =
  148. {
  149.     /* Plane 0 */
  150.     0x7C00, 0xD600, 0xABC0, 0x8020,
  151.     0xD560, 0xAAA0, 0xD560, 0xAAA0,
  152.     0x7FC0,
  153.     /* Plane 1 */
  154.     0x7C00, 0xD600, 0xABC0, 0x8000,
  155.     0xD540, 0xAA80, 0xD540, 0xAA80,
  156.     0x0000,
  157. };
  158.  
  159. struct Image show_image =
  160. {
  161.     0, 0, 11, 9, 2, &show_data[0], 0x3, 0x0, NULL
  162. };
  163.  
  164. __chip UWORD hide_data[27] =
  165. {
  166.     /* Plane 0 */
  167.     0x7C00, 0xD600, 0xABC0, 0xFFF0,
  168.     0xF558, 0xEAA8, 0xD550, 0xFFE0,
  169.     0x7FC0,
  170.     /* Plane 1 */
  171.     0x7C00, 0xD600, 0xABC0, 0xAFF0,
  172.     0xD550, 0xAAA0, 0xD540, 0xFFC0,
  173.     0x0000,
  174. };
  175.  
  176. struct Image hide_image =
  177. {
  178.     0, 0, 13, 9, 2, &hide_data[0], 0x3, 0x0, NULL
  179. };
  180.  
  181.  
  182. /* This is the start of our programme.
  183.  */
  184. #ifdef _DCC
  185. wbmain() { main(); }
  186. #endif
  187.  
  188. main()
  189. {
  190.     struct Screen *screen = NULL;
  191.  
  192.     if (!ButtonBase) return(20);
  193.  
  194.     /* We'll just open up on the default public screen, and use its screen font.
  195.      */
  196.     if (screen = LockPubScreen(NULL))
  197.     {
  198.         UWORD mapping[4];
  199.  
  200.         drinfo = GetScreenDrawInfo(screen);
  201.  
  202.         NewList(&file_list);
  203.         read_files(&file_list, "ENV:", 1);
  204.  
  205.         /* Setup a simple mapping.
  206.          */
  207.         mapping[0] = drinfo->dri_Pens[BACKGROUNDPEN];
  208.         mapping[1] = drinfo->dri_Pens[SHADOWPEN];
  209.         mapping[2] = drinfo->dri_Pens[SHINEPEN];
  210.         mapping[3] = drinfo->dri_Pens[FILLPEN];
  211.  
  212.         /* Do the layout.
  213.          */
  214.         if (layout = LayoutObject,
  215.                             GA_DrawInfo, drinfo,
  216.                             ICA_TARGET, ICTARGET_IDCMP,
  217.                             LAYOUT_DeferLayout, TRUE,
  218.  
  219.                             LAYOUT_SpaceOuter, TRUE,
  220.                             LAYOUT_Orientation, LAYOUT_ORIENT_VERT,
  221.                             LAYOUT_HorizAlignment, LAYOUT_ALIGN_CENTER,
  222.  
  223.                             LAYOUT_AddChild, list_gad = ListBrowserObject,
  224.                                 GA_ID, GAD_LIST,
  225.                                 GA_RelVerify, TRUE,
  226.                                 LISTBROWSER_Labels, (ULONG)&file_list,
  227.                                 LISTBROWSER_ColumnInfo, (ULONG)&ci,
  228.                                 LISTBROWSER_ColumnTitles, TRUE,
  229.                                 LISTBROWSER_ShowSelected, TRUE,
  230.                                 LISTBROWSER_Separators, FALSE,
  231.                                 LISTBROWSER_Hierarchical, TRUE,
  232.                                 LISTBROWSER_LeafImage, &leaf_image,
  233.                                 LISTBROWSER_ShowImage, &show_image,
  234.                                 LISTBROWSER_HideImage, &hide_image,
  235.                                 LISTBROWSER_AutoFit, TRUE,
  236.                                 ListBrowserEnd,
  237.                             CHILD_WeightedHeight, 100,
  238.  
  239.                             LAYOUT_AddChild, edit_gad = TextFieldObject,
  240.                                 GA_ID, GAD_EDIT,
  241.                                 GA_RelVerify, TRUE,
  242.                                 TEXTFIELD_Border, TEXTFIELD_BORDER_DOUBLEBEVEL,
  243.                                 TextFieldEnd,
  244.                             CHILD_MinHeight, screen->Font->ta_YSize + 6,
  245.                             CHILD_WeightedHeight, 50,
  246.  
  247.                             LAYOUT_AddChild, LayoutObject,
  248.                                 LAYOUT_Orientation, LAYOUT_ORIENT_HORIZ,
  249.                                 LAYOUT_EvenSize, TRUE,
  250.     
  251.                                 LAYOUT_AddChild, ButtonObject,
  252.                                     GA_ID, GAD_SAVE,
  253.                                     GA_Text, "_Save",
  254.                                     GA_RelVerify, TRUE,
  255.                                     ButtonEnd,
  256.                                 CHILD_NominalSize, TRUE,
  257.                                 CHILD_WeightedWidth, 0,
  258.  
  259.                                 LAYOUT_AddChild, ButtonObject,
  260.                                     GA_ID, GAD_USE,
  261.                                     GA_Text, "_Use",
  262.                                     GA_RelVerify, TRUE,
  263.                                     ButtonEnd,
  264.                                 CHILD_NominalSize, TRUE,
  265.                                 CHILD_WeightedWidth, 0,
  266.  
  267.                                 LAYOUT_AddChild, ButtonObject,
  268.                                     GA_ID, GAD_CANCEL,
  269.                                     GA_Text, " _Cancel ",
  270.                                     GA_RelVerify, TRUE,
  271.                                     ButtonEnd,
  272.                                 CHILD_NominalSize, TRUE,
  273.                                 CHILD_WeightedWidth, 0,
  274.  
  275.                                 LayoutEnd,
  276.                             CHILD_WeightedHeight, 0,
  277.                             LayoutEnd)
  278.         {
  279.             struct MsgPort *app_port;
  280.  
  281.             /* Create a message port for App* messages.  This is needed for
  282.              * iconification.  We're being a touch naughty by not checking
  283.              * the return code, but that just means that iconification won't
  284.              * work, nothing really bad will happen.
  285.              */
  286.             app_port = CreateMsgPort();
  287.  
  288.             /* Create the window object.
  289.              */
  290.             if (window_obj = WindowObject,
  291.                                 WA_Left, 0,
  292.                                 WA_Top, screen->Font->ta_YSize + 3,
  293.                                 WA_CustomScreen, screen,
  294.                                 WA_IDCMP, IDCMP_CLOSEWINDOW,
  295.                                 WA_Flags, WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET |
  296.                                             WFLG_SIZEGADGET | WFLG_ACTIVATE | WFLG_SMART_REFRESH,
  297.                                 WA_Title, "Environmental Variable Editor",
  298.                                 WA_NewLookMenus, TRUE,
  299.                                 WINDOW_ParentGroup, layout,
  300.                                 WINDOW_IconifyGadget, TRUE,
  301.                                 WINDOW_Icon, GetDiskObject("PROGDIR:EnvEdit"),
  302.                                 WINDOW_IconTitle, "EnvEdit",
  303.                                 WINDOW_AppPort, app_port,
  304.                                 TAG_DONE))
  305.             {
  306.                 /* Increase the initial hieght.
  307.                  */
  308.                 SetAttrs(window_obj,
  309.                     WA_InnerHeight, screen->Font->ta_YSize * 16,
  310.                     TAG_DONE);
  311.  
  312.                 /*  Open the window.
  313.                  */
  314.                 if (win = (struct Window *)CA_OpenWindow(window_obj))
  315.                 {
  316.                     Object *arexx_obj;
  317.  
  318.                     /* Create host object.
  319.                      */
  320.                     if (arexx_obj = ARexxObject,
  321.                                         AREXX_HostName, "ENVEDIT",
  322.                                         AREXX_Commands, arexx_cmds,
  323.                                         ARexxEnd)
  324.                     {
  325.                         /* Input Event Loop
  326.                          */
  327.                         while (ok)
  328.                         {
  329.                             ULONG signal, winsig, rxsig;
  330.                             ULONG result;
  331.     
  332.                             /* Obtain the window and ARexx wait signal masks.
  333.                              */
  334.                             GetAttr(WINDOW_SigMask, window_obj, &winsig);
  335.                             GetAttr(AREXX_SigMask, arexx_obj, &rxsig);        
  336.     
  337.                             signal = Wait(rxsig | winsig | (1L << app_port->mp_SigBit) | SIGBREAKF_CTRL_C);
  338.     
  339.                             /* ARexx event?
  340.                              */
  341.                             if (signal & rxsig)
  342.                                 CA_HandleRexx(arexx_obj);
  343.  
  344.                             /* Window event?
  345.                              */
  346.                             if (signal & winsig)
  347.                             {
  348.                                 /* CA_HandleInput() returns the gadget ID of a clicked
  349.                                  * gadget, or one of several pre-defined values.  For
  350.                                  * this demo, we're only actually interested in a
  351.                                  * close window and a couple of gadget clicks.
  352.                                  */
  353.                                 while ((result = CA_HandleInput(window_obj, NULL)) != WMHI_LASTMSG)
  354.                                 {
  355.                                     switch(result & WMHI_CLASSMASK)
  356.                                     {
  357.                                         case WMHI_CLOSEWINDOW:
  358.                                             ok = FALSE;
  359.                                             break;
  360.         
  361.                                         case WMHI_GADGETUP:
  362.                                             switch (result & WMHI_GADGETMASK)
  363.                                             {
  364.                                                 case GAD_LIST:
  365.                                                     D( PutStr("Load text\n"); )
  366.                                                     load_text(win);
  367.                                                     break;
  368.         
  369.                                                 case GAD_EDIT:
  370.                                                     D( PutStr("Text edited\n"); )
  371.                                                     {
  372.                                                         struct Node *node;
  373.         
  374.                                                         GetAttr(LISTBROWSER_SelectedNode, list_gad, (ULONG *)&node);
  375.                                                         if (node)
  376.                                                         {
  377.                                                             struct LBUserData *lbud;
  378.                                                             ULONG flags;
  379.         
  380.                                                             /* Gotta change a flag in
  381.                                                              * our special user data
  382.                                                              * structure.
  383.                                                              */
  384.                                                             GetListBrowserNodeAttrs(node,
  385.                                                                 LBNA_Flags, &flags,
  386.                                                                 LBNA_UserData, &lbud,
  387.                                                                 TAG_DONE);
  388.                                                             if (lbud && !(flags & LBFLG_HASCHILDREN))
  389.                                                                 lbud->lbud_Changed = TRUE;
  390.                                                         }
  391.                                                     }
  392.                                                     break;
  393.         
  394.                                                 case GAD_SAVE:
  395.                                                     save_changed(&file_list, "ENV:", TRUE);
  396.                                                     save_changed(&file_list, "ENVARC:", FALSE);
  397.                                                     ok = FALSE;
  398.                                                     break;
  399.         
  400.                                                 case GAD_USE:
  401.                                                     save_changed(&file_list, "ENV:", FALSE);
  402.                                                     ok = FALSE;
  403.                                                     break;
  404.         
  405.                                                 case GAD_CANCEL:
  406.                                                     ok = FALSE;
  407.                                                     break;
  408.         
  409.                                                 default:
  410.                                                     break;
  411.                                             }
  412.                                             break;
  413.         
  414.                                         case WMHI_ICONIFY:
  415.                                             if (CA_Iconify(window_obj))
  416.                                                 win = NULL;
  417.                                             break;
  418.                                      
  419.                                         case WMHI_UNICONIFY:
  420.                                             win = CA_OpenWindow(window_obj);
  421.                                             break;
  422.         
  423.                                         default:
  424.                                             break;
  425.                                     }
  426.                                 }
  427.                             }
  428.                             /* CTRL-C should quit.
  429.                              */
  430.                             if (signal & SIGBREAKF_CTRL_C)
  431.                             {
  432.                                 ok = FALSE;
  433.                             }
  434.                         }
  435.                         /* Free up ARexx.
  436.                          */
  437.                         DisposeObject(arexx_obj);
  438.                     }
  439.                     else
  440.                         easy_req(NULL, "EnvEdit failed to start\nCouldn't create ARexx host", "Quit", "");
  441.                  }
  442.                 else
  443.                     easy_req(NULL, "EnvEdit failed to start\nCouldn't open window", "Quit", "");
  444.  
  445.                 /* Disposing of the window object will also close the
  446.                  * window if it is already opened and it will dispose of
  447.                  * all objects attached to it.
  448.                  */
  449.                 DisposeObject(window_obj);
  450.             }
  451.             else
  452.                 easy_req(NULL, "EnvEdit failed to start\nCouldn't create window", "Quit", "");
  453.  
  454.             /* Lose the App* message port.
  455.              */
  456.             if (app_port)
  457.                 DeleteMsgPort(app_port);
  458.         }
  459.         else
  460.             easy_req(NULL, "EnvEdit failed to start\nCouldn't create layout", "Quit", "");
  461.  
  462.         free_list(&file_list);
  463.  
  464.         if (drinfo)
  465.             FreeScreenDrawInfo(screen, drinfo);
  466.  
  467.         UnlockPubScreen(0, screen);
  468.     }
  469.     else
  470.         easy_req(NULL, "EnvEdit failed to start\nCouldn't lock destination screen", "Quit", "");
  471.  
  472.     exit(0);
  473. }
  474.  
  475.  
  476. /* Load text for the currently selected item in the variable list into the
  477.  * textfield gadget.
  478.  */
  479. VOID load_text(struct Window *win)
  480. {
  481.     struct Node *node;
  482.  
  483.     SetGadgetAttrs(edit_gad, win, NULL,
  484.         TEXTFIELD_Text, "",
  485.         TAG_DONE);
  486.  
  487.     /* Get the selected node.
  488.      */
  489.     GetAttr(LISTBROWSER_SelectedNode, list_gad, (ULONG *)&node);
  490.     if (node)
  491.     {
  492.         struct LBUserData *lbud;
  493.         ULONG flags;
  494.  
  495.         /* We stashed some important info in the userdata, so get that.
  496.          */
  497.         GetListBrowserNodeAttrs(node,
  498.             LBNA_Flags, &flags,
  499.             LBNA_UserData, &lbud,
  500.             TAG_DONE);
  501.         if (lbud && !(flags & LBFLG_HASCHILDREN))
  502.         {
  503.             /* Open up the file for read.
  504.              */
  505.             if (lbud->lbud_FileName)
  506.             {
  507.                 LONG size;
  508.  
  509.                 /* Found out how big the file is.
  510.                  */
  511.                 if (size = file_size(lbud->lbud_FileName))
  512.                 {
  513.                     BPTR fh;
  514.  
  515.                     /* Open up the file for read.
  516.                      */
  517.                     if (fh = Open(lbud->lbud_FileName, MODE_OLDFILE))
  518.                     {
  519.                         /* Allocate a buffer large enough to load the whole
  520.                          * file into, if we don't already have one big enough.
  521.                          */
  522.                         if (size > lbud->lbud_BufSize)
  523.                         {
  524.                             if (lbud->lbud_Buf)
  525.                                 FreeVec(lbud->lbud_Buf);
  526.                             lbud->lbud_Buf = (STRPTR)AllocVec(size + 1, MEMF_ANY);
  527.                             lbud->lbud_BufSize = size + 1;
  528.                         }
  529.                         
  530.                         if (lbud->lbud_Buf)
  531.                         {
  532.                             /* Go ahead and load our text in.
  533.                              */
  534.                             lbud->lbud_BufSize = Read(fh, lbud->lbud_Buf, size);
  535.                             lbud->lbud_Buf[lbud->lbud_BufSize] = '\0';
  536.  
  537.                             /* Tell the edit gadget to display it.
  538.                              */
  539.                             SetGadgetAttrs(edit_gad, win, NULL,
  540.                                 TEXTFIELD_Text, lbud->lbud_Buf,
  541.                                 TAG_DONE);
  542.                         }
  543.                         else
  544.                         {
  545.                             D( PutStr("No buffer\n"); )
  546.                             lbud->lbud_BufSize = 0;
  547.                         }
  548.  
  549.                         Close(fh);
  550.                     }
  551.                     D( else PutStr("Can't open file\n"); )
  552.                 }
  553.                 D( else PutStr("No file size\n"); )
  554.             }
  555.             D( else PutStr("No filename\n"); )
  556.         }
  557.         else if (flags & LBFLG_HASCHILDREN)
  558.         {
  559.             ULONG relevent;
  560.  
  561.             GetAttr(LISTBROWSER_RelEvent, list_gad, &relevent);
  562.             if (relevent != LBRE_SHOWCHILDREN && relevent != LBRE_HIDECHILDREN)
  563.             {
  564.                 SetGadgetAttrs(list_gad, win, NULL,
  565.                     LISTBROWSER_Labels, ~0,
  566.                     TAG_DONE);
  567.  
  568.                 if (flags & LBFLG_SHOWCHILDREN)
  569.                     HideListBrowserNodeChildren(node);
  570.                 else
  571.                     ShowListBrowserNodeChildren(node, 1);
  572.  
  573.                 SetGadgetAttrs(list_gad, win, NULL,
  574.                     LISTBROWSER_Labels, &file_list,
  575.                     TAG_DONE);
  576.             }
  577.         }
  578.     }
  579.     D( else PutStr("No selected node\n"); )
  580. }
  581.  
  582. /* Get the file size (in bytes) of a file.
  583.  */
  584. LONG file_size(char *filename)
  585. {
  586.     BPTR lock;
  587.     LONG size = -1;
  588.  
  589.     if (lock = Lock(filename, ACCESS_READ))
  590.     {
  591.         struct FileInfoBlock *fib;
  592.  
  593.         if (fib = (struct FileInfoBlock *)AllocDosObject(DOS_FIB,TAG_END))
  594.         {
  595.             if (Examine(lock, fib))
  596.                 size = fib->fib_Size;
  597.             FreeDosObject(DOS_FIB, fib);
  598.         }
  599.         UnLock(lock);
  600.     }
  601.     return(size);
  602. }
  603.  
  604.  
  605. /* Save all changed variables to the specified directory.
  606.  */
  607. VOID save_changed(struct List *list, STRPTR dir, BOOL nochange)
  608. {
  609.     struct Node *node;
  610.  
  611.     /* Peruse all nodes.
  612.      */
  613.     for (node = list->lh_Head; node->ln_Succ; node = node->ln_Succ)
  614.     {
  615.         struct LBUserData *lbud;
  616.         ULONG flags;
  617.  
  618.         /* Get our user data structure.
  619.          */
  620.         GetListBrowserNodeAttrs(node,
  621.             LBNA_Flags, &flags,
  622.             LBNA_UserData, &lbud,
  623.             TAG_DONE);
  624.         if (lbud && !(flags & LBFLG_HASCHILDREN))
  625.         {
  626.             /* See if the node has changed and if we have a filename
  627.              * and if we have a buffer.
  628.              */
  629.             if (lbud->lbud_Changed && lbud->lbud_FileName)
  630.             {
  631.                 UBYTE open_file[255];
  632.                 BPTR fh;
  633.  
  634.                 /* Convert the filename.
  635.                  */
  636.                 sprintf(open_file, "%s%s", dir, lbud->lbud_FileName + 4);
  637.  
  638.                 /* Try and open the file for write.
  639.                  */
  640.                 if (fh = Open(open_file, MODE_NEWFILE))
  641.                 {
  642.                     if (lbud->lbud_BufSize == Write(fh, lbud->lbud_Buf, lbud->lbud_BufSize))
  643.                         lbud->lbud_Changed = nochange;
  644.                     Close(fh);
  645.                 }
  646.             }
  647.         }
  648.     }
  649. }
  650.  
  651.  
  652. /* Read files in a directory to a listbrowser list.
  653.  */
  654. BOOL read_files(struct List *list, STRPTR dir, WORD generation)
  655. {
  656.     BPTR lock;
  657.  
  658.     D( Printf("Read directory: %s\n", dir); )
  659.  
  660.     if (lock = Lock(dir, ACCESS_READ))
  661.     {
  662.         char *eadata;
  663.  
  664.         if (eadata = (char *)AllocVec(sizeof(struct ExAllData) * 200, MEMF_CLEAR))
  665.         {
  666.             struct ExAllControl *eac;
  667.  
  668.             if (eac = (struct ExAllControl *)AllocDosObject(DOS_EXALLCONTROL, NULL))
  669.             {
  670.                 BOOL more;
  671.  
  672.                 eac->eac_LastKey = 0;
  673.                 do
  674.                 {
  675.                     struct ExAllData *ead;
  676.  
  677.                     more = ExAll(lock, eadata, sizeof(struct ExAllData) * 200, ED_DATE, eac);
  678.                     if (!more && IoErr() != ERROR_NO_MORE_ENTRIES)
  679.                         return(FALSE);
  680.  
  681.                     if (eac->eac_Entries == 0)
  682.                         return(FALSE);
  683.  
  684.                     ead = (struct ExAllData *)eadata;
  685.                     do
  686.                     {
  687.                         struct Node *node;
  688.                         struct DateTime dat;
  689.                         char temp1[255], temp2[12], temp3[12], temp4[12];
  690.                         ULONG flags = LBFLG_CUSTOMPENS;
  691.  
  692.                         if (ead->ed_Type == ST_USERDIR)
  693.                         {
  694.                             flags |= LBFLG_HASCHILDREN;
  695.                             strcpy(temp2, "Record");
  696.                         }
  697.                         else
  698.                             sprintf(temp2, "%ld", ead->ed_Size);
  699.  
  700.                         if (generation > 1)
  701.                             flags |= LBFLG_HIDDEN;
  702.  
  703.                         /* Convert the date and time to strings.
  704.                          */
  705.                         dat.dat_Stamp.ds_Days = ead->ed_Days;
  706.                         dat.dat_Stamp.ds_Minute = ead->ed_Mins;
  707.                         dat.dat_Stamp.ds_Tick = ead->ed_Ticks;
  708.                         dat.dat_Flags = 0;
  709.                         dat.dat_StrDate = temp3;
  710.                         dat.dat_StrTime = temp4;
  711.                         dat.dat_StrDay = NULL;
  712.  
  713.                         if (!DateToStr(&dat))
  714.                             temp3[0] = temp4[0] = '\0';
  715.  
  716.                         if (node = AllocListBrowserNode(4,
  717.                                         LBNA_Column, 0,
  718.                                             LBNCA_CopyText, TRUE,
  719.                                             LBNCA_Text, ead->ed_Name,
  720.                                             LBNCA_FGPen, drinfo->dri_Pens[TEXTPEN],
  721.                                         LBNA_Column, 1,
  722.                                             LBNCA_CopyText, TRUE,
  723.                                             LBNCA_Text, temp2,
  724.                                             LBNCA_FGPen, (ead->ed_Type == ST_USERDIR? drinfo->dri_Pens[HIGHLIGHTTEXTPEN] : drinfo->dri_Pens[TEXTPEN]),
  725.                                             LBNCA_Justification, LCJ_RIGHT,
  726.                                         LBNA_Column, 2,
  727.                                             LBNCA_CopyText, TRUE,
  728.                                             LBNCA_Text, temp3,
  729.                                             LBNCA_FGPen, drinfo->dri_Pens[TEXTPEN],
  730.                                         LBNA_Column, 3,
  731.                                             LBNCA_CopyText, TRUE,
  732.                                             LBNCA_Text, temp4,
  733.                                             LBNCA_FGPen, drinfo->dri_Pens[TEXTPEN],
  734.                                         LBNA_Generation, generation,
  735.                                         LBNA_Flags, flags,
  736.                                         TAG_DONE))
  737.                         {
  738.                             struct LBUserData *lbud;
  739.  
  740.                             AddTail(list, (struct Node *)node);
  741.  
  742.                             strcpy(temp1, dir);
  743.                             AddPart(temp1, ead->ed_Name, 255);
  744.  
  745.                             if (lbud = (struct LBUserData *)AllocVec(sizeof(struct LBUserData), MEMF_CLEAR))
  746.                             {
  747.                                 strcpy(lbud->lbud_FileName, temp1);
  748.  
  749.                                 SetListBrowserNodeAttrs(node,
  750.                                     LBNA_UserData, lbud,
  751.                                     TAG_DONE);
  752.                             }
  753.  
  754.                             if (ead->ed_Type == ST_USERDIR)
  755.                             {
  756.                                 read_files(list, temp1, generation + 1);
  757.                             }
  758.                         }
  759.  
  760.                         ead = ead->ed_Next;
  761.                     } while (ead);
  762.                 } while (more);
  763.  
  764.                 FreeDosObject(DOS_EXALLCONTROL, eac);
  765.             }
  766.             else
  767.                 return(FALSE);
  768.             FreeVec(eadata);
  769.         }
  770.         else
  771.             return(FALSE);
  772.         UnLock(lock);
  773.     }
  774.     else
  775.         return(FALSE);
  776.  
  777.     return(TRUE);
  778. }
  779.  
  780.  
  781. /* Copy a B string to a C string.
  782.  */
  783. VOID bstrcpy(STRPTR cstr, BSTR bstr)
  784. {
  785.     strncpy(cstr, (char *)BADDR(bstr) + 1, ((char *)BADDR(bstr))[0]);
  786.     cstr[((char *)BADDR(bstr))[0]] = '\0';
  787. }
  788.  
  789.  
  790. /* Function to free an Exec List.
  791.  */
  792. VOID free_list(struct List *list)
  793. {
  794.     struct Node *node, *nextnode;
  795.  
  796.     node = list->lh_Head;
  797.     while (nextnode = node->ln_Succ)
  798.     {
  799.         struct LBUserData *lbud;
  800.  
  801.         GetListBrowserNodeAttrs(node,
  802.             LBNA_UserData, &lbud,
  803.             TAG_DONE);
  804.         if (lbud)
  805.             if (lbud->lbud_Buf);
  806.                 FreeVec(lbud->lbud_Buf);
  807.  
  808.         FreeListBrowserNode(node);
  809.         node = nextnode;
  810.     }
  811.     NewList(list);
  812. }
  813.  
  814.  
  815. /* Do an easy requester.
  816.  */
  817. LONG easy_req(struct Window *win, char *reqtext, char *reqgads, char *reqargs, ...)
  818. {
  819.     struct EasyStruct general_es =
  820.     {
  821.         sizeof(struct EasyStruct),
  822.         0,
  823.         "SBGen",
  824.         NULL,
  825.         NULL
  826.     };
  827.  
  828.     general_es.es_TextFormat = reqtext;
  829.     general_es.es_GadgetFormat = reqgads;
  830.  
  831.     return(EasyRequestArgs(win, &general_es, NULL, &reqargs));
  832. }
  833.  
  834. /* NAME
  835.  */
  836. VOID SAVEDS ASM rexx_name(REG_A0 struct ARexxCmd *ac, REG_A1 struct RexxMsg *rxm)
  837. {
  838.     ac->ac_Result = "EnvEdit";
  839. }
  840.  
  841. /* VERSION
  842.  */
  843. VOID SAVEDS ASM rexx_version(REG_A0 struct ARexxCmd *ac, REG_A1 struct RexxMsg *rxm)
  844. {
  845.     ac->ac_Result = "1.0";
  846. }
  847.  
  848. /* AUTHOR
  849.  */
  850. VOID SAVEDS ASM rexx_author(REG_A0 struct ARexxCmd *ac, REG_A1 struct RexxMsg *rxm)
  851. {
  852.     ac->ac_Result = "Timothy Aston";
  853. }
  854.  
  855. /* DEACTIVATE
  856.  */
  857. VOID SAVEDS ASM rexx_deactivate(REG_A0 struct ARexxCmd *ac, REG_A1 struct RexxMsg *rxm)
  858. {
  859.     if (CA_Iconify(window_obj))
  860.         win = NULL;
  861. }
  862.  
  863. /* ACTIVATE
  864.  */
  865. VOID SAVEDS ASM rexx_activate(REG_A0 struct ARexxCmd *ac, REG_A1 struct RexxMsg *rxm)
  866. {
  867.     win = CA_OpenWindow(window_obj);
  868. }
  869.  
  870. /* QUIT
  871.  */
  872. VOID SAVEDS ASM rexx_quit(REG_A0 struct ARexxCmd *ac, REG_A1 struct RexxMsg *rxm)
  873. {
  874.     ok = FALSE;
  875. }
  876.  
  877. /* 
  878.  */
  879. VOID SAVEDS ASM rexx_windowtoback(REG_A0 struct ARexxCmd *ac, REG_A1 struct RexxMsg *rxm)
  880. {
  881.     WindowToBack(win);
  882. }
  883.  
  884. /* WINDOWTOFRONT
  885.  */
  886. VOID SAVEDS ASM rexx_windowtofront(REG_A0 struct ARexxCmd *ac, REG_A1 struct RexxMsg *rxm)
  887. {
  888.     WindowToFront(win);
  889. }
  890.