home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume19 / xfig / part15 / w_dir.c
Encoding:
C/C++ Source or Header  |  1993-05-27  |  21.1 KB  |  769 lines

  1. /* This file is part of xdir, an X-based directory browser.
  2.  *
  3.  *    Created: 13 Aug 88
  4.  *
  5.  *    Win Treese
  6.  *    Cambridge Research Lab
  7.  *    Digital Equipment Corporation
  8.  *    treese@crl.dec.com
  9.  *
  10.  *    $Source: /trx/u2/treese/Src/Xdir.rel/RCS/xdir.c,v $
  11.  *
  12.  *        COPYRIGHT 1990
  13.  *      DIGITAL EQUIPMENT CORPORATION
  14.  *       MAYNARD, MASSACHUSETTS
  15.  *      ALL RIGHTS RESERVED.
  16.  *
  17.  * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
  18.  * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
  19.  * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE
  20.  * FOR ANY PURPOSE.  IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED
  21.  * WARRANTY.
  22.  *
  23.  * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT
  24.  * RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN
  25.  * ADDITION TO THAT SET FORTH ABOVE.
  26.  *
  27.  * Permission to use, copy, modify, and distribute this software and its
  28.  * documentation for any purpose and without fee is hereby granted, provided
  29.  * that the above copyright notice appear in all copies and that both that
  30.  * copyright notice and this permission notice appear in supporting
  31.  * documentation, and that the name of Digital Equipment Corporation not be
  32.  * used in advertising or publicity pertaining to distribution of the
  33.  * software without specific, written prior permission.
  34.  *
  35.  *    Modified: 4 Dec 91 - Paul King (king@cs.uq.oz.au)
  36.  */
  37.  
  38. #include "w_util.h"
  39. #include "fig.h"
  40. #include "figx.h"
  41. #include "resources.h"
  42. #include "mode.h"
  43. #include "w_dir.h"
  44. #include "w_setup.h"
  45. #include "w_drawprim.h"        /* for char_height */
  46. #ifdef USE_DIRENT
  47. #include <dirent.h>
  48. #else
  49. #include <sys/dir.h>
  50. #endif
  51.  
  52. /* Static variables */
  53.  
  54. DeclareStaticArgs(10);
  55. static Boolean    errorInProgress;
  56. static String    dir_translations =
  57.     "<Key>Return: SetDir()\n\
  58.     Ctrl<Key>X: EmptyTextKey()\n\
  59.     <Key>F18: PastePanelKey()\n";
  60. static String    list_panel_translations =
  61.     "<Btn3Up>: ParentDir()\n";
  62. static char    CurrentSelectionName[PATH_MAX];
  63. static int    file_entry_cnt, dir_entry_cnt;
  64. static char   **file_list, **dir_list;
  65. static char   **filelist, **dirlist;
  66. static char    *dirmask;
  67.  
  68. /* External variables */
  69.  
  70. extern Widget    file_panel, export_panel;
  71. extern Widget    exp_selfile, file_selfile, exp_dir, file_dir, exp_flist,
  72.         file_flist, exp_dlist, file_dlist, exp_mask, file_mask;
  73. extern Boolean    file_up, export_up;
  74. extern char    export_dir[];
  75.  
  76. /* Functions */
  77.  
  78. void        DoChangeDir(),
  79.         SetDir(),
  80.         Rescan(),
  81.         CallbackRescan();
  82.  
  83. static void    ParentDir();
  84.  
  85. /* Function:    FileSelected() is called when the user selects a file.
  86.  *        Set the global variable "CurrentSelectionName"
  87.  *        and set either the export or file panel file name, whichever is popped up
  88.  * Arguments:    Standard Xt callback arguments.
  89.  * Returns:    Nothing.
  90.  * Notes:
  91.  */
  92.  
  93. void
  94. FileSelected(w, client_data, ret_val)
  95.     Widget        w;
  96.     XtPointer        client_data;
  97.     XtPointer        ret_val;
  98. {
  99.     XawListReturnStruct *ret_struct = (XawListReturnStruct *) ret_val;
  100.  
  101.     strcpy(CurrentSelectionName, ret_struct->string);
  102.     FirstArg(XtNstring, CurrentSelectionName);
  103.     /* I don't know why this doesn't work? */
  104.     /* NextArg(XtNinsertPosition, strlen(CurrentSelectionName));*/
  105.     if (export_up) {
  106.     SetValues(exp_selfile);
  107.         XawTextSetInsertionPoint(exp_selfile, strlen(CurrentSelectionName));
  108.     } else {
  109.     SetValues(file_selfile);
  110.         XawTextSetInsertionPoint(file_selfile, strlen(CurrentSelectionName));
  111.     }
  112. }
  113.  
  114. /* Function:    DirSelected() is called when the user selects a directory.
  115.  *
  116.  * Arguments:    Standard Xt callback arguments.
  117.  * Returns:    Nothing.
  118.  * Notes:
  119.  */
  120.  
  121. void
  122. DirSelected(w, client_data, ret_val)
  123.     Widget        w;
  124.     XtPointer        client_data;
  125.     XtPointer        ret_val;
  126. {
  127.     XawListReturnStruct *ret_struct = (XawListReturnStruct *) ret_val;
  128.  
  129.     strcpy(CurrentSelectionName, ret_struct->string);
  130.     DoChangeDir(CurrentSelectionName);
  131. }
  132.  
  133. void
  134. GoHome(w, client_data, ret_val)
  135.     Widget        w;
  136.     XtPointer        client_data;
  137.     XtPointer        ret_val;
  138. {
  139.      parseuserpath("~",cur_dir);
  140.      DoChangeDir(cur_dir);
  141. }
  142.  
  143. /*
  144.    come here when the user presses return in the directory path widget
  145.    Get the current string from the widget and set the current directory to that
  146.    Also, copy the dir to the current directory widget in the file popup
  147. */
  148.  
  149. /* Function:  SetDir() changes to the parent directory.
  150.  * Arguments: Standard Xt action arguments.
  151.  * Returns:   Nothing.
  152.  * Notes:
  153.  */
  154.  
  155. void
  156. SetDir(widget, event, params, num_params)
  157.     Widget        widget;
  158.     XEvent       *event;
  159.     String       *params;
  160.     Cardinal       *num_params;
  161. {
  162.     char       *ndir;
  163.  
  164.     /* get the string from the widget */
  165.     FirstArg(XtNstring, &ndir);
  166.     if (file_up)
  167.     GetValues(file_dir);
  168.     else {
  169.     GetValues(exp_dir);
  170.     strcpy(export_dir,ndir);    /* save in global var */
  171.     }
  172.     /* if there is a ~ in the directory, parse the username */
  173.     if (ndir[0]=='~')
  174.     {
  175.     char longdir[PATH_MAX];
  176.     parseuserpath(ndir,longdir);
  177.     ndir=longdir;
  178.     }
  179.     strcpy(cur_dir, ndir);
  180.     DoChangeDir(cur_dir);
  181. }
  182.  
  183. /* make the full path from ~/partialpath */
  184. parseuserpath(path,longpath)
  185. char *path,*longpath;
  186. {
  187.     char      *home,*p;
  188.     struct passwd *who;
  189.  
  190.     /* this user's home */
  191.     if (strlen(path)==1 || path[1]=='/')
  192.     {
  193.     strcpy(longpath,getenv("HOME"));
  194.     if (strlen(path)==1)        /* nothing after the ~, we have the full path */
  195.         return;
  196.     strcat(longpath,&path[1]);    /* append the rest of the path */
  197.     return;
  198.     }
  199.     /* another user name after ~ */
  200.     strcpy(longpath,&path[1]);
  201.     p=index(longpath,'/');
  202.     if (p)
  203.         *p='\0';
  204.     who = getpwnam(longpath);
  205.     if (!who)
  206.     {
  207.     file_msg("No such user: %s",longpath);
  208.     strcpy(longpath,path);
  209.     }
  210.     else
  211.     {
  212.     strcpy(longpath,who->pw_dir);
  213.     p=index(path,'/');
  214.     if (p)
  215.         strcat(longpath,p);    /* attach stuff after the / */
  216.     }
  217. }
  218.  
  219. static String    mask_text_translations =
  220.         "<Key>Return: rescan()\n\
  221.         Ctrl<Key>J: rescan()\n\
  222.         Ctrl<Key>M: rescan()\n";
  223.  
  224. static XtActionsRec actionTable[] = {
  225.     {"ParentDir", ParentDir},
  226.     {"SetDir", SetDir},
  227.     {"rescan", Rescan},
  228. };
  229.  
  230. static int      actions_added=0;
  231.  
  232. void
  233. create_dirinfo(parent, below, ret_beside, ret_below,
  234.            mask_w, dir_w, flist_w, dlist_w)
  235.     Widget        parent, below, *ret_beside, *ret_below, *mask_w, *dir_w,
  236.            *flist_w, *dlist_w;
  237.  
  238. {
  239.     Widget        w,dir_alt,home;
  240.     Widget        file_viewport;
  241.     Widget        dir_viewport;
  242.     PIX_FONT        temp_font;
  243.     int            char_ht;
  244.  
  245.     dir_entry_cnt = NENTRIES;
  246.     file_entry_cnt = NENTRIES;
  247.     filelist = (char **) calloc(file_entry_cnt, sizeof(char *));
  248.     dirlist = (char **) calloc(dir_entry_cnt, sizeof(char *));
  249.  
  250.     get_directory(cur_dir);
  251.  
  252.     FirstArg(XtNlabel, "     Alternatives:");
  253.     NextArg(XtNfromVert, below);
  254.     NextArg(XtNborderWidth, 0);
  255.     w = XtCreateManagedWidget("file_alt_label", labelWidgetClass,
  256.                   parent, Args, ArgCount);
  257.     FirstArg(XtNfont, &temp_font);
  258.     GetValues(w);
  259.     char_ht = char_height(temp_font) + 2;
  260.  
  261.     FirstArg(XtNallowVert, True);
  262.     NextArg(XtNfromHoriz, w);
  263.     NextArg(XtNfromVert, below);
  264.     NextArg(XtNborderWidth, INTERNAL_BW);
  265.     NextArg(XtNwidth, 350);
  266.     NextArg(XtNheight, char_ht * 10);
  267.     file_viewport = XtCreateManagedWidget("vport", viewportWidgetClass,
  268.                       parent, Args, ArgCount);
  269.  
  270.     FirstArg(XtNlabel, "    Filename Mask:");
  271.     NextArg(XtNborderWidth, 0);
  272.     NextArg(XtNfromVert, file_viewport);
  273.     w = XtCreateManagedWidget("mask_label", labelWidgetClass, 
  274.                 parent, Args, ArgCount);
  275.  
  276.     FirstArg(XtNeditType, XawtextEdit);
  277.     NextArg(XtNscrollHorizontal, XawtextScrollNever);
  278.     NextArg(XtNborderWidth, INTERNAL_BW);
  279.     NextArg(XtNscrollVertical, XawtextScrollNever);
  280.     NextArg(XtNresize, XawtextResizeWidth);
  281.     NextArg(XtNwidth, 100);
  282.     NextArg(XtNfromHoriz, w);
  283.     NextArg(XtNfromVert, file_viewport);
  284.     *mask_w = XtCreateManagedWidget("mask", asciiTextWidgetClass, 
  285.                     parent, Args, ArgCount);
  286.     XtOverrideTranslations(*mask_w,
  287.                XtParseTranslationTable(mask_text_translations));
  288.  
  289.     /* get the first directory listing */
  290.     FirstArg(XtNstring, &dirmask);
  291.     GetValues(*mask_w);
  292.     if (MakeFileList(cur_dir, dirmask, &dir_list, &file_list) == False)
  293.     file_msg("No files in directory?");
  294.  
  295.     FirstArg(XtNlabel, "Current Directory:");
  296.     NextArg(XtNborderWidth, 0);
  297.     NextArg(XtNfromVert, *mask_w);
  298.     NextArg(XtNvertDistance, 15);
  299.     w = XtCreateManagedWidget("dir_label", labelWidgetClass,
  300.                   parent, Args, ArgCount);
  301.     FirstArg(XtNstring, cur_dir);
  302.     NextArg(XtNinsertPosition, strlen(cur_dir));
  303.     NextArg(XtNheight, char_ht * 2);
  304.     NextArg(XtNborderWidth, INTERNAL_BW);
  305.     NextArg(XtNscrollHorizontal, XawtextScrollWhenNeeded);
  306.     NextArg(XtNeditType, XawtextEdit);
  307.     NextArg(XtNfromVert, *mask_w);
  308.     NextArg(XtNvertDistance, 15);
  309.     NextArg(XtNfromHoriz, w);
  310.     NextArg(XtNwidth, 350);
  311.     *dir_w = XtCreateManagedWidget("dir_name", asciiTextWidgetClass,
  312.                    parent, Args, ArgCount);
  313.  
  314.     XtOverrideTranslations(*dir_w,
  315.                XtParseTranslationTable(dir_translations));
  316.  
  317.     FirstArg(XtNlabel, "     Alternatives:");
  318.     NextArg(XtNborderWidth, 0);
  319.     NextArg(XtNfromVert, *dir_w);
  320.     dir_alt = XtCreateManagedWidget("dir_alt_label", labelWidgetClass,
  321.                   parent, Args, ArgCount);
  322.  
  323.     /* put a Home button to the left of the list of directories */
  324.     FirstArg(XtNlabel, "Home");
  325.     NextArg(XtNfromVert, dir_alt);
  326.     NextArg(XtNfromHoriz, dir_alt);
  327.     NextArg(XtNhorizDistance, -70);
  328.     NextArg(XtNborderWidth, INTERNAL_BW);
  329.     home = XtCreateManagedWidget("home", commandWidgetClass, 
  330.                 parent, Args, ArgCount);
  331.     XtAddCallback(home, XtNcallback, GoHome, (XtPointer) NULL);
  332.  
  333.     FirstArg(XtNallowVert, True);
  334.     NextArg(XtNfromHoriz, dir_alt);
  335.     NextArg(XtNfromVert, *dir_w);
  336.     NextArg(XtNborderWidth, INTERNAL_BW);
  337.     NextArg(XtNwidth, 350);
  338.     NextArg(XtNheight, char_ht * 4);
  339.     dir_viewport = XtCreateManagedWidget("dirvport", viewportWidgetClass,
  340.                      parent, Args, ArgCount);
  341.  
  342.     FirstArg(XtNlist, file_list);
  343.     *flist_w = XtCreateManagedWidget("file_list_panel", listWidgetClass,
  344.                      file_viewport, Args, ArgCount);
  345.     XtOverrideTranslations(*flist_w,
  346.                XtParseTranslationTable(list_panel_translations));
  347.     XtAddCallback(*flist_w, XtNcallback, FileSelected,
  348.           (XtPointer) NULL);
  349.  
  350.     FirstArg(XtNlist, dir_list);
  351.     *dlist_w = XtCreateManagedWidget("dir_list_panel", listWidgetClass,
  352.                      dir_viewport, Args, ArgCount);
  353.  
  354.     XtOverrideTranslations(*dlist_w,
  355.                XtParseTranslationTable(list_panel_translations));
  356.     XtAddCallback(*dlist_w, XtNcallback, DirSelected,
  357.           (XtPointer) NULL);
  358.  
  359.     if (!actions_added) {
  360.     XtAppAddActions(tool_app, actionTable, XtNumber(actionTable));
  361.     actions_added = 1;
  362.     }
  363.  
  364.     FirstArg(XtNlabel, "Rescan");
  365.     NextArg(XtNfromVert, dir_viewport);
  366.     NextArg(XtNborderWidth, INTERNAL_BW);
  367.     NextArg(XtNvertDistance, 15);
  368.     NextArg(XtNhorizDistance, 45);
  369.     NextArg(XtNheight, 25);
  370.     w = XtCreateManagedWidget("rescan", commandWidgetClass, parent,
  371.                   Args, ArgCount);
  372.     XtAddCallback(w, XtNcallback, CallbackRescan, NULL);
  373.  
  374.     /* install accelerators so they can be used from each window */
  375.     XtInstallAccelerators(*flist_w, parent);
  376.     XtInstallAccelerators(*dlist_w, parent);
  377.  
  378.     *ret_beside = w;
  379.     *ret_below = dir_viewport;
  380.     return;
  381. }
  382.  
  383. /* Function:    SPComp() compares two string pointers for qsort().
  384.  * Arguments:    s1, s2: strings to be compared.
  385.  * Returns:    Value of strcmp().
  386.  * Notes:
  387.  */
  388.  
  389. static int
  390. SPComp(s1, s2)
  391.     char      **s1, **s2;
  392. {
  393.     return (strcmp(*s1, *s2));
  394. }
  395.  
  396. Boolean
  397. MakeFileList(dir_name, mask, dir_list, file_list)
  398.     char       *dir_name;
  399.     char       *mask, ***dir_list, ***file_list;
  400. {
  401.     DIR           *dirp;
  402.     DIRSTRUCT      *dp;
  403.     char      **cur_file, **cur_directory;
  404.     char      **last_file, **last_dir;
  405.  
  406.     set_temp_cursor(wait_cursor);
  407.     cur_file = filelist;
  408.     cur_directory = dirlist;
  409.     last_file = filelist + file_entry_cnt - 1;
  410.     last_dir = dirlist + dir_entry_cnt - 1;
  411.  
  412.     dirp = opendir(dir_name);
  413.     if (dirp == NULL) {
  414.     reset_cursor();
  415.     *file_list = filelist;
  416.     *file_list[0]="";
  417.     *dir_list = dirlist;
  418.     *dir_list[0]="..";
  419.     return False;
  420.     }
  421.     /* process any events to ensure cursor is set to wait_cursor */
  422.     /*
  423.      * don't do this inside the following loop because this procedure could
  424.      * be re-entered if the user presses (e.g.) rescan
  425.      */
  426.     app_flush();
  427.  
  428.     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  429.     /* skip over '.' (current dir) */
  430.     if (!strcmp(dp->d_name, "."))
  431.         continue;
  432.  
  433.     if (IsDirectory(dir_name, dp->d_name)) {
  434.         *cur_directory++ = SaveString(dp->d_name);
  435.         if (cur_directory == last_dir) {    /* out of space, make more */
  436.         dirlist = (char **) realloc(dirlist,
  437.                     2 * dir_entry_cnt * sizeof(char *));
  438.         cur_directory = dirlist + dir_entry_cnt - 1;
  439.         dir_entry_cnt = 2 * dir_entry_cnt;
  440.         last_dir = dirlist + dir_entry_cnt - 1;
  441.         }
  442.     } else {
  443.         /* check if matches regular expression */
  444.         if ((mask == NULL) || (*mask == '\0'))
  445.         mask = "*";
  446.         if (wild_match(dp->d_name, mask) == 0)
  447.         continue;    /* no, do next */
  448.         if (mask[0] == '*' && dp->d_name[0] == '.')
  449.         continue;    /* skip files with leading . */
  450.         *cur_file++ = SaveString(dp->d_name);
  451.         if (cur_file == last_file) {    /* out of space, make more */
  452.         filelist = (char **) realloc(filelist,
  453.                        2 * file_entry_cnt * sizeof(char *));
  454.         cur_file = filelist + file_entry_cnt - 1;
  455.         file_entry_cnt = 2 * file_entry_cnt;
  456.         last_file = filelist + file_entry_cnt - 1;
  457.         }
  458.     }
  459.     }
  460.     *cur_file = NULL;
  461.     *cur_directory = NULL;
  462.     if (cur_file != filelist)
  463.     qsort(filelist, cur_file - filelist, sizeof(char *), (int(*)())SPComp);
  464.     if (cur_directory != dirlist)
  465.     qsort(dirlist, cur_directory - dirlist, sizeof(char *), (int(*)())SPComp);
  466.     *file_list = filelist;
  467.     *dir_list = dirlist;
  468.     reset_cursor();
  469.     closedir(dirp);
  470.     return True;
  471. }
  472.  
  473. /* Function:    ParentDir() changes to the parent directory.
  474.  * Arguments:    Standard Xt action arguments.
  475.  * Returns:    Nothing.
  476.  * Notes:
  477.  */
  478.  
  479. static void
  480. ParentDir(w, event, params, num_params)
  481.     Widget        w;
  482.     XEvent*        event;
  483.     String*        params;
  484.     Cardinal*        num_params;
  485. {
  486.     DoChangeDir("..");
  487. }
  488.  
  489. /* Function:    DoChangeDir() actually changes the directory and changes
  490.  *        the list widget values to the new listing.
  491.  * Arguments:    dir:    Pathname of new directory.
  492.  * Returns:    Nothing.
  493.  * Notes:
  494.  *    NULL for dir means to rebuild the file list for the current directory
  495.  *    (as in an update to the directory or change in filename filter).
  496.  */
  497.  
  498. void
  499. DoChangeDir(dir)
  500.     char       *dir;
  501. {
  502.     char      **file_list;
  503.     char      **dir_list;
  504.     char       *p;
  505.     Arg            args[10];
  506.     Cardinal        arg_cnt;
  507.     char        ndir[PATH_MAX], tmpdir[PATH_MAX];
  508.  
  509.     
  510.     strcpy(ndir, cur_dir);
  511.     if (dir != NULL && dir[0] != '/') { /* relative path, prepend current dir */
  512.     if (dir[strlen(dir) - 1] == '/')
  513.         dir[strlen(dir) - 1] = '\0';
  514.     if (!strcmp(dir, "..")) {    /* Parent directory. */
  515.         if (*ndir == '\0')
  516.         return;            /* no current directory, */
  517.                     /* can't do anything unless absolute path */
  518.         p = rindex(ndir, '/');
  519.         *p = EOS;
  520.         if (ndir[0] == EOS)
  521.         strcpy(ndir, "/");
  522.     } else {
  523.         if (strcmp(ndir, "/"))    /* At the root already */
  524.         strcat(ndir, "/");
  525.         strcat(ndir, dir);
  526.     }
  527.     }
  528.     strcpy(tmpdir, cur_dir);
  529.     strcpy(cur_dir, ndir);
  530.     if (change_directory(cur_dir) != 0 ) {
  531.     file_msg("Can't change to directory %s", cur_dir);
  532.     strcpy(cur_dir, tmpdir);
  533.     } else if (MakeFileList(ndir, dirmask, &dirlist, &filelist) == False) {
  534.     file_msg("Unable to list directory %s", ndir);
  535.     strcpy(cur_dir, tmpdir);
  536.     }
  537.  
  538.     FirstArg(XtNstring, cur_dir);
  539.     /* I don't know why this doesn't work? */
  540.     /* NextArg(XtNinsertPosition, strlen(cur_dir));*/
  541.     /* update the current directory and file/dir list widgets */
  542.     if (file_up) 
  543.     {
  544.     SetValues(file_dir);
  545.     XawTextSetInsertionPoint(file_dir, strlen(cur_dir));
  546.     NewList(file_flist,filelist);
  547.     NewList(file_dlist,dirlist);
  548.     } else {
  549.     SetValues(exp_dir);
  550.     strcpy(export_dir,cur_dir);    /* save in global var */
  551.     XawTextSetInsertionPoint(exp_dir, strlen(cur_dir));
  552.     NewList(exp_flist, filelist);
  553.     NewList(exp_dlist, dirlist);
  554.     }
  555.     CurrentSelectionName[0] = '\0';
  556. }
  557.  
  558. void 
  559. CallbackRescan(widget, closure, call_data)
  560.     Widget    widget;
  561.     XtPointer closure;
  562.     XtPointer call_data;
  563. {
  564.      Rescan(0, 0, 0, 0);
  565. }
  566.  
  567. void
  568. Rescan(widget, event, params, num_params)
  569.     Widget    widget;
  570.     XEvent*    event;
  571.     String*    params;
  572.     Cardinal*    num_params;
  573. {
  574.     char    *dir;
  575.  
  576.     /*
  577.      * get the mask string from the File or Export mask widget and put in
  578.      * dirmask
  579.      */
  580.     if (file_up) {
  581.     FirstArg(XtNstring, &dirmask);
  582.     GetValues(file_mask);
  583.     FirstArg(XtNstring, &dir);
  584.     GetValues(file_dir);
  585.     (void) MakeFileList(dir, dirmask, &dir_list, &file_list);
  586.     NewList(file_flist,file_list);
  587.     NewList(file_dlist,dir_list);
  588.     } else {
  589.     FirstArg(XtNstring, &dirmask);
  590.     GetValues(exp_mask);
  591.     FirstArg(XtNstring, &dir);
  592.     GetValues(exp_dir);
  593.     strcpy(export_dir,dir);        /* save in global var */
  594.     (void) MakeFileList(dir, dirmask, &dir_list, &file_list);
  595.     NewList(exp_flist, file_list);
  596.     NewList(exp_dlist, dir_list);
  597.     }
  598. }
  599.  
  600. static String null_entry = " ";
  601. static String *null_list = { &null_entry };
  602.  
  603. NewList(listwidget, list)
  604.     Widget    listwidget;
  605.     String   *list;
  606. {
  607.     XawListChange(listwidget, null_list, 1, 0, True);
  608.     XawListChange(listwidget, list, 0, 0, True);
  609. }
  610.  
  611.  
  612. /* Function:    SaveString() creates a copy of a string.
  613.  * Arguments:    string: String to save.
  614.  * Returns:    A pointer to the new copy (char *).
  615.  * Notes:
  616.  */
  617.  
  618. char           *
  619. SaveString(string)
  620.     char       *string;
  621. {
  622.     char       *new;
  623.  
  624.     new = (char *) malloc(strlen(string) + 1);
  625.     strcpy(new, string);
  626.     return (new);
  627. }
  628.  
  629. /* Function:    IsDirectory() tests to see if a pathname is a directory.
  630.  * Arguments:    path:    Pathname of file to test.
  631.  * Returns:    True or False.
  632.  * Notes:    False is returned if the directory is not accessible.
  633.  */
  634.  
  635. Boolean
  636. IsDirectory(root, path)
  637.     char       *root;
  638.     char       *path;
  639. {
  640.     char        fullpath[PATH_MAX];
  641.     struct stat        statbuf;
  642.  
  643.     if (path == NULL)
  644.     return (False);
  645.     MakeFullPath(root, path, fullpath);
  646.     if (stat(fullpath, &statbuf))    /* some error, report that it is not
  647.                      * a directory */
  648.     return (False);
  649.     if (statbuf.st_mode & S_IFDIR)
  650.     return (True);
  651.     else
  652.     return (False);
  653. }
  654.  
  655. /* Function:    MakeFullPath() creates the full pathname for the given file.
  656.  * Arguments:    filename:    Name of the file in question.
  657.  *        pathname:    Buffer for full name.
  658.  * Returns:    Nothing.
  659.  * Notes:
  660.  */
  661.  
  662. void
  663. MakeFullPath(root, filename, pathname)
  664.     char       *root;
  665.     char       *filename;
  666.     char       *pathname;
  667. {
  668.     strcpy(pathname, root);
  669.     strcat(pathname, "/");
  670.     strcat(pathname, filename);
  671. }
  672.  
  673. /* wildmatch.c - Unix-style command line wildcards
  674.  
  675.    This procedure is in the public domain.
  676.  
  677.    After that, it is just as if the operating system had expanded the
  678.    arguments, except that they are not sorted.    The program name and all
  679.    arguments that are expanded from wildcards are lowercased.
  680.  
  681.    Syntax for wildcards:
  682.    *        Matches zero or more of any character (except a '.' at
  683.         the beginning of a name).
  684.    ?        Matches any single character.
  685.    [r3z]    Matches 'r', '3', or 'z'.
  686.    [a-d]    Matches a single character in the range 'a' through 'd'.
  687.    [!a-d]    Matches any single character except a character in the
  688.         range 'a' through 'd'.
  689.  
  690.    The period between the filename root and its extension need not be
  691.    given explicitly.  Thus, the pattern `a*e' will match 'abacus.exe'
  692.    and 'axyz.e' as well as 'apple'.  Comparisons are not case sensitive.
  693.  
  694.    The wild_match code was written by Rich Salz, rsalz@bbn.com,
  695.    posted to net.sources in November, 1986.
  696.  
  697.    The code connecting the two is by Mike Slomin, bellcore!lcuxa!mike2,
  698.    posted to comp.sys.ibm.pc in November, 1988.
  699.  
  700.    Major performance enhancements and bug fixes, and source cleanup,
  701.    by David MacKenzie, djm@ai.mit.edu. */
  702.  
  703. /* Shell-style pattern matching for ?, \, [], and * characters.
  704.    I'm putting this replacement in the public domain.
  705.  
  706.    Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. */
  707.  
  708. /* The character that inverts a character class; '!' or '^'. */
  709. #define INVERT '!'
  710.  
  711. static int    star();
  712.  
  713. /* Return nonzero if `string' matches Unix-style wildcard pattern
  714.    `pattern'; zero if not. */
  715.  
  716. int
  717. wild_match(string, pattern)
  718.     char       *string, *pattern;
  719. {
  720.     int            prev;    /* Previous character in character class. */
  721.     int            matched;    /* If 1, character class has been matched. */
  722.     int            reverse;    /* If 1, character class is inverted. */
  723.  
  724.     for (; *pattern; string++, pattern++)
  725.     switch (*pattern) {
  726.     case '\\':
  727.         /* Literal match with following character; fall through. */
  728.         pattern++;
  729.     default:
  730.         if (*string != *pattern)
  731.         return 0;
  732.         continue;
  733.     case '?':
  734.         /* Match anything. */
  735.         if (*string == '\0')
  736.         return 0;
  737.         continue;
  738.     case '*':
  739.         /* Trailing star matches everything. */
  740.         return *++pattern ? star(string, pattern) : 1;
  741.     case '[':
  742.         /* Check for inverse character class. */
  743.         reverse = pattern[1] == INVERT;
  744.         if (reverse)
  745.         pattern++;
  746.         for (prev = 256, matched = 0; *++pattern && *pattern != ']';
  747.          prev = *pattern)
  748.         if (*pattern == '-'
  749.             ? *string <= *++pattern && *string >= prev
  750.             : *string == *pattern)
  751.             matched = 1;
  752.         if (matched == reverse)
  753.         return 0;
  754.         continue;
  755.     }
  756.  
  757.     return *string == '\0';
  758. }
  759.  
  760. static int
  761. star(string, pattern)
  762.     char       *string, *pattern;
  763. {
  764.     while (wild_match(string, pattern) == 0)
  765.     if (*++string == '\0')
  766.         return 0;
  767.     return 1;
  768. }
  769.