home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume3 / browserw / part01 / Browser.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-17  |  30.4 KB  |  1,261 lines

  1. #if ( !defined(lint) && !defined(Pete_copyright))
  2. #define Pete_copyright 1
  3. static char pete_copyright[] = "\
  4.  Copyright 1986 by Peter Shipley All rights reserved\n\
  5. \n\
  6.  Copy permission is hereby granted provided that this notice is\n\
  7.  retained on all partial or complete copies.\n\
  8. \n\
  9.  please mail questions and fixes to shipley@widow,berkeley.edu\n";
  10. #endif
  11.  
  12.  
  13. #include <stdio.h>
  14. #include <errno.h>
  15. #include <ctype.h>
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #include <sys/file.h>
  19. #include <sys/param.h>
  20. #include <sys/dir.h>
  21. #include <signal.h>
  22.  
  23. #include <X11/Xlib.h>
  24. #include <X11/IntrinsicP.h>
  25. /*
  26. #include <X11/Shell.h>
  27. #include <X11/Form.h>
  28. */
  29. #include <X11/cursorfont.h>
  30. /* #include <X11/Xlibint.h> */
  31. #include <X11/AsciiText.h>
  32. #include <X11/StringDefs.h>
  33. #include <X11/Xos.h>
  34. #include <X11/Xutil.h>
  35. #include <X11/Command.h>
  36. #include <X11/List.h>
  37. #include <X11/Viewport.h>
  38. #include <X11/Xmu.h>
  39.  
  40.  
  41. #include "BrowserP.h"
  42.  
  43. /* Private Definitions */
  44.  
  45. static int def_spacing = 10;
  46.  
  47.  
  48.     /* {name, class, type, size, offset, default_type, default_addr}, */
  49. static XtResource resources[] = {
  50.     {XtNvalue, XtCValue, XtRString, sizeof(String),
  51.     XtOffset(BrowserWidget, browser.path), XtRString, NULL},
  52.     {XtNdefaultDistance, XtCThickness, XtRInt, sizeof(int),
  53.     XtOffset(BrowserWidget, browser.spacing), XtRInt,(caddr_t)&def_spacing},
  54.     {XtNcancelCallback, XtCCallback, XtRCallback, sizeof(caddr_t),
  55.     XtOffset(BrowserWidget, browser.sel_callback), XtRCallback, NULL},
  56.     {XtNopenCallback, XtCCallback, XtRCallback, sizeof(caddr_t),
  57.     XtOffset(BrowserWidget, browser.can_callback), XtRCallback, NULL},
  58.     {XtNfunction, XtCFunction, XtRFunction, sizeof (XtWorkProc),
  59.     XtOffset(BrowserWidget, browser.testProc), XtRFunction, NULL},
  60.     {XtNreverseVideo, XtCReverseVideo, XtRBoolean, sizeof (Boolean),
  61.     XtOffset(BrowserWidget, browser.reverse_video), XtRString, "FALSE"}
  62. };
  63.  
  64. static Boolean SetValues(), ConstraintSetValues();
  65. static XtGeometryResult GeometryManager();
  66. static list_type *createFileList();
  67.  
  68. extern int alphasort();
  69.  
  70.  
  71. static void CreateLabelWidget(),    /* random Widget creation func. */
  72.         CreateFileListWidget(),
  73.         CreateErrorWidget(),
  74.         CreateCommandButtons(),
  75.  
  76.         CreateCursors(),
  77.  
  78.         followdir(),
  79.         Bdestroy(),            /* callback to deallocate shit */
  80.                     /* toolkit failures */
  81.  
  82.         UpDateLabel(),        /* Update the path label */
  83.         LocalNotify(),        /* generic callback */
  84. #ifdef DEBUG
  85.         showList(),            /* DEBUG func. (prints current list) */
  86. #endif DEBUG
  87.  
  88.         prev_callback(),
  89.         next_callback(),
  90.         path_completion(),
  91.         kill_callback(),
  92.  
  93.         dummy(),            /* a do nothing func. */
  94.  
  95.         _openCall(),        /* callback for open button */
  96.         _cancelCall(),        /* callback for cancel button */
  97.  
  98.         ChangeManaged(),
  99.         Initialize(),
  100.         Resize(),
  101.         Realize(),
  102.         RefigureLocations(),
  103.         ConstraintInitialize(),
  104.  
  105.         showError(),
  106.         clearError(),
  107.  
  108.         SetWorkState(),
  109.  
  110.         deleteList();        /* de-allocate current list */
  111.  
  112. #ifdef DEBUG
  113. #define printList(X) (void) fprintf(stderr, \
  114.     "list->count = %d\tmin = '%s'\tmax = '%s'\n", \
  115.     X->count, X->namelist[0],  X->namelist[X->count -1]);
  116. #endif DEBUG
  117.  
  118.  
  119.  
  120.  
  121. BrowserClassRec browserClassRec = {
  122.   { /* core_class fields */
  123.     /* superclass         */    (WidgetClass) &compositeClassRec,
  124.     /* class_name         */    "Browser",
  125.     /* widget_size        */    sizeof(BrowserRec),
  126.     /* class_initialize   */    NULL,
  127.     /* class_part_init    */    NULL,
  128.     /* class_inited       */    FALSE,
  129.     /* initialize         */    Initialize,
  130.     /* initialize_hook    */    NULL,
  131.     /* realize            */    Realize,
  132.     /* actions            */    NULL,
  133.     /* num_actions        */    0,
  134.     /* resources          */    resources,
  135.     /* num_resources      */    XtNumber(resources),
  136.     /* xrm_class          */    NULLQUARK,
  137.     /* compress_motion    */    TRUE,
  138.     /* compress_exposure  */    TRUE,
  139.     /* compress_enterleave*/    TRUE,
  140.     /* visible_interest   */    FALSE,
  141.     /* destroy            */    Bdestroy,
  142.     /* resize             */    Resize,
  143.     /* expose             */    XtInheritExpose,
  144.     /* set_values         */    SetValues,
  145.     /* set_values_hook    */    NULL,
  146.     /* set_values_almost  */    XtInheritSetValuesAlmost,
  147.     /* get_values_hook    */    NULL,
  148.     /* accept_focus       */    NULL,
  149.     /* version            */    XtVersion,
  150.     /* callback_private   */    NULL,
  151.     /* tm_table           */    NULL,
  152.     /* query_geometry     */    XtInheritQueryGeometry,    /* %%% fix this! */
  153.     /* display_accelerator*/    XtInheritDisplayAccelerator,
  154.     /* extension          */    NULL
  155.   },
  156.   { /* composite_class fields */
  157.     /* geometry_manager   */   GeometryManager,
  158.     /* change_managed     */   NULL, /* ChangeManaged, */
  159.     /* insert_child       */   XtInheritInsertChild,
  160.     /* delete_child       */   XtInheritDeleteChild,
  161.     /* extension          */   NULL
  162.   },
  163.   { /* browser_class fields */
  164.     /* empty              */   0
  165.   }
  166. };
  167.  
  168. WidgetClass browserWidgetClass = (WidgetClass)&browserClassRec;
  169.  
  170. /****************************************************************
  171.  *
  172.  * Private Procedures
  173.  *
  174.  ****************************************************************/
  175.  
  176. static void CreateCursors(br)
  177. BrowserWidget br;
  178. {
  179.  
  180. static XColor b = { 0,    0,     0,     0  };  /* black */
  181. static XColor f = { 0, 65535, 65535, 65535 };  /* white */
  182.  
  183. #ifdef nodef
  184. XColor f, b;
  185.  
  186.     if (XtDisplay(br)->cursor_font == None) {
  187.     XtDisplay(br)->cursor_font = XLoadFont (XtDisplay(br), CURSORFONT);
  188.     if (XtDisplay(br)->cursor_font) {
  189.         XtWarning("failed to open cursor_font");
  190.         return;
  191.     }
  192.     }
  193.  
  194.     if(br->browser.reverse_video) {
  195.     f = foreground;
  196.     b = background;
  197.     } else {
  198.     b = foreground;
  199.     f = background;
  200.     }
  201.  
  202.     br->browser.ArrowCursor = XCreateGlyphCursor(XtDisplay(br),
  203.         XtDisplay(br)->cursor_font, XtDisplay(br)->cursor_font,
  204.         XC_left_ptr, XC_left_ptr +1, &f, &b);
  205.  
  206.     br->browser.CrossCursor = XCreateGlyphCursor(XtDisplay(br),
  207.         XtDisplay(br)->cursor_font, XtDisplay(br)->cursor_font,
  208.         XC_cross, XC_cross +1, &f, &b);
  209.  
  210.     br->browser.ClockCursor = XCreateGlyphCursor(XtDisplay(br),
  211.         XtDisplay(br)->cursor_font, XtDisplay(br)->cursor_font,
  212.         XC_watch, XC_watch +1, &f, &b);
  213. #endif nodef
  214.  
  215.     /* get the standard Cursors */
  216.     br->browser.ArrowCursor = XCreateFontCursor(XtDisplay(br), XC_left_ptr);
  217.     br->browser.CrossCursor = XCreateFontCursor(XtDisplay(br), XC_cross);
  218.     br->browser.ClockCursor = XCreateFontCursor(XtDisplay(br), XC_watch);
  219.  
  220.     /* recolor cursor is we are displayed in reverse video. */
  221.     if(br->browser.reverse_video) {
  222.     XRecolorCursor(XtDisplay(br), br->browser.CrossCursor, &f, &b);
  223.     XRecolorCursor(XtDisplay(br), br->browser.ClockCursor, &f, &b);
  224.     }
  225.  
  226.     return;
  227. }
  228.  
  229. /* ARGSUSED */
  230. static void Initialize(request, new)
  231.     Widget request, new;
  232. {
  233.     BrowserWidget br = (BrowserWidget)new;
  234.  
  235.  
  236.     if(br->core.width == 0) br->core.width = 400;
  237.     if(br->core.height == 0) br->core.height = 350;
  238.  
  239.     /* allocate room for path data */
  240.     br->browser.labelpath = XtMalloc(MAXPATHLEN);
  241.     br->browser.basepath = XtMalloc(MAXPATHLEN);
  242.  
  243.     /* labelpath NEEDS to be  NULL */
  244.     bzero(br->browser.labelpath, MAXPATHLEN);
  245.  
  246.     /* copy the base into an interal string */
  247.     (void) strcpy(br->browser.basepath, br->browser.path);
  248.  
  249.     CreateCursors(br);
  250.  
  251.     /* get the dirt on the basepath */
  252.     br->browser.list = (list_type *) createFileList(br, br->browser.path);
  253.  
  254. #ifdef DEBUG
  255.     showList(br->browser.list);
  256. #endif DEBUG
  257.  
  258.     /* Guess what these do ... */
  259.     CreateLabelWidget(br);
  260.  
  261.     CreateErrorWidget(br);
  262.  
  263.     CreateFileListWidget(br);
  264.  
  265.     CreateCommandButtons(br);
  266.  
  267.     /* set the Keyboard Focus */
  268.     XtSetKeyboardFocus(br, br->browser.b_label);
  269.  
  270.     /* display the current path */
  271.     UpDateLabel(br, TRUE);
  272.  
  273.     return;
  274. }
  275.  
  276.  
  277. static void CreateLabelWidget(br)
  278. BrowserWidget br;
  279. {
  280. XtTranslations  text_tran;
  281.  
  282.     static String newtextTranslations =
  283.        "Ctrl<Key>W:        prev_callback()\n\
  284.     Ctrl<Key>M:        next_callback()\n\
  285.     Ctrl<Key>J:        next_callback()\n\
  286.     <Key>0xFF0D:        next_callback()\n\
  287.     <Key>0xFF0A:        next_callback()\n\
  288.     Meta<Key>I:        dummy()\n\
  289.     Ctrl<Key>C:        kill_callback()\n\
  290.     <Key>0xFF1B:        path_completion()\n\
  291.     Ctrl<Key>[:        path_completion()\n";
  292.  
  293.     static XtActionsRec newtext_actions[] = {
  294.     {"prev_callback",    prev_callback},
  295.     {"next_callback",    next_callback},
  296.     {"path_completion",    path_completion},
  297.     {"kill_callback",    kill_callback},
  298.     {"dummy",        dummy}
  299.     };
  300.  
  301.     static Arg label_arg[] = {
  302.     {XtNstring,        (XtArgVal) NULL},
  303.     {XtNcursor,        (XtArgVal) NULL},
  304.     {XtNlength,        (XtArgVal) MAXPATHLEN},
  305.     {XtNtextOptions,    (XtArgVal) editable},
  306.     {XtNeditType,        (XtArgVal) XttextEdit},
  307.     {XtNjustify,        (XtArgVal) XtJustifyLeft},
  308.     {XtNborderWidth,    (XtArgVal) 0},
  309.     {XtNresize,        (XtArgVal) FALSE}
  310.     };
  311.  
  312.     label_arg[0].value = (XtArgVal) br->browser.labelpath;
  313.     label_arg[1].value = (XtArgVal) br->browser.CrossCursor;
  314.  
  315.     br->browser.b_label = XtCreateManagedWidget("Browser_label",
  316.         asciiStringWidgetClass, br, label_arg, XtNumber(label_arg));
  317.  
  318.     /* install the new actions record */
  319.     XtAddActions(newtext_actions, XtNumber(newtext_actions));
  320.  
  321.     /* creat a Translation Table */
  322.     text_tran = XtParseTranslationTable(newtextTranslations);
  323.  
  324.     /* install the new Translation Table */
  325.     XtOverrideTranslations(br->browser.b_label, text_tran);
  326.  
  327.     return;
  328. }
  329.  
  330.  
  331. static void CreateFileListWidget(br)
  332. BrowserWidget br;
  333. {
  334. XtTranslations list_trans;
  335.  
  336.     static Arg view_args[] = {
  337.     {XtNallowVert,          (XtArgVal) TRUE},
  338.     {XtNforceBars,          (XtArgVal) TRUE},
  339.     {XtNresize,             (XtArgVal) FALSE},
  340.     {XtNuseRight,           (XtArgVal) TRUE}
  341.     };
  342.  
  343.     static String newTranslations =
  344.     "<Btn1Down>:    Set()\n\
  345.     <Btn1Down>(2+): Notify()\n";
  346.  
  347.     static XtCallbackRec list_call[] = {
  348.     {(XtCallbackProc) _openCall,    (caddr_t) NULL},
  349.     {(XtCallbackProc) NULL,        (caddr_t) NULL}
  350.     };
  351.  
  352.     static Arg list_args[] = {
  353.     {XtNlist,        (XtArgVal) NULL},
  354.     {XtNnumberStrings,    (XtArgVal) NULL},
  355.     {XtNcallback,        (XtArgVal) list_call},
  356.     {XtNverticalList,    (XtArgVal) TRUE},
  357.     {XtNforceColumns,    (XtArgVal) 1},
  358.     {XtNdefaultColumns,    (XtArgVal) 1},
  359.     {XtNcolumnSpacing,    (XtArgVal) 1000}
  360.     };
  361.  
  362.  
  363.     list_call[0].closure = (caddr_t) br;
  364.  
  365.     list_args[0].value = (XtArgVal) br->browser.list->list;
  366.     list_args[1].value = (XtArgVal) br->browser.list->count;
  367.  
  368.     /* create a viewport widget so the list widget will have scrollbars */
  369.     br->browser.b_view = XtCreateManagedWidget( "view", viewportWidgetClass,
  370.             br, view_args, XtNumber(view_args));
  371.  
  372.     /* Create the list widget at a child of the viewport widget */
  373.     br->browser.b_list = XtCreateManagedWidget( "list", listWidgetClass,
  374.             br->browser.b_view, list_args, XtNumber(list_args));
  375.  
  376.     /* Parse the replacement TranslationTable and install it */
  377.     list_trans = XtParseTranslationTable(newTranslations);
  378.     XtOverrideTranslations(br->browser.b_list, list_trans);
  379.  
  380.     return;
  381. }
  382.  
  383. static void CreateErrorWidget(br)
  384. BrowserWidget br;
  385. {
  386.     static Arg error_list[] = {
  387.     {XtNjustify,        (XtArgVal) XtJustifyLeft},
  388.     {XtNborderWidth,    (XtArgVal) 0},
  389.     {XtNresize,             (XtArgVal) FALSE},
  390.     {XtNlabel,        (XtArgVal) ">"}
  391.     };
  392.  
  393.     br->browser.b_error = XtCreateManagedWidget("error", labelWidgetClass,
  394.             br, error_list, XtNumber(error_list));
  395.     return;
  396. }
  397.  
  398.  
  399. static void CreateCommandButtons(br)
  400. BrowserWidget br;
  401. {
  402.     static XtCallbackRec cancel_call[] = {
  403.     {(XtCallbackProc) _cancelCall,    (caddr_t) NULL},
  404.     {(XtCallbackProc) NULL,        (caddr_t) NULL}
  405.     };
  406.  
  407.     static XtCallbackRec open_call[] = {
  408.     {(XtCallbackProc) _openCall,    (caddr_t) NULL},
  409.     {(XtCallbackProc) NULL,        (caddr_t) NULL}
  410.     };
  411.  
  412.     static Arg comm_args[] = {
  413.     {XtNcursor,        (XtArgVal) NULL},
  414.     {XtNlabel,        (XtArgVal) "Open"},
  415.     {XtNcallback,        (XtArgVal) open_call},
  416.     {XtNresize,             (XtArgVal) FALSE},
  417.     {XtNresizable,        (XtArgVal) FALSE},
  418.     {XtNwidth,        (XtArgVal) 70}
  419.     };
  420.  
  421.     comm_args[0].value = (XtArgVal) br->browser.ArrowCursor;
  422.  
  423.     /* compleate the callback data arrays */
  424.     open_call[0].closure = cancel_call[0].closure = (caddr_t) br;
  425.  
  426.     /* create the open button */
  427.     br->browser.b_open = XtCreateManagedWidget( "open", commandWidgetClass,
  428.             br, comm_args, XtNumber(comm_args) );
  429.  
  430.     /* reuses the arg array for the Cancel button */
  431.     comm_args[1].value = (XtArgVal) "Cancel";
  432.     comm_args[2].value = (XtArgVal) cancel_call;
  433.  
  434.     /* and now the Cancel command button */
  435.     br->browser.b_cancel = XtCreateManagedWidget( "Cancel", commandWidgetClass,
  436.             br, comm_args, XtNumber(comm_args));
  437.  
  438.     return;
  439. }
  440.  
  441.  
  442. static void RefigureLocations(wi)
  443.     BrowserWidget wi;
  444. {
  445.     BrowserWidget br = (BrowserWidget)wi;
  446.  
  447.     Position x, y, y1;
  448.  
  449. #ifdef DEBUG
  450.     (void) fputs("RefigureLocations called\n", stderr);
  451. #endif DEBUG
  452.  
  453.     /* first we do the label bar */
  454.     XtConfigureWidget(br->browser.b_label,
  455.         br->browser.spacing, br->browser.spacing,    /* x & y*/
  456.         br->core.width -(br->browser.spacing *2)     /* width */
  457.         -(br->browser.b_label->core.border_width *2),
  458.         br->browser.b_label->core.height,        /* height */
  459.         br->browser.b_label->core.border_width);    /* border */
  460.  
  461.     /* here we calc the Y Position for the selection list & buttons  */
  462.     y1 = br->browser.b_label->core.height
  463.         +(br->browser.spacing *2)
  464.         +(br->browser.b_label->core.border_width *2);
  465.  
  466.  
  467.     /* calc the X Position for the buttons */
  468.     x = br->core.width -br->browser.spacing -br->browser.b_cancel->core.width;
  469.  
  470.     /* Position the first button */
  471.     XtMoveWidget(br->browser.b_open, x, y1);
  472.  
  473.     XtMoveWidget(br->browser.b_cancel, x, 
  474.         y1 +br->browser.spacing
  475.         +br->browser.b_open->core.height
  476.         +(br->browser.b_open->core.border_width *2));
  477.  
  478.  
  479.     /* here we calc the Y Position error area */
  480.     y = br->core.height -br->browser.spacing -br->browser.b_error->core.height
  481.         -(br->browser.b_error->core.border_width *2);
  482.  
  483.     XtConfigureWidget(br->browser.b_error,
  484.         br->browser.spacing, y,                /* x & y */
  485.         br->core.width -(br->browser.spacing *2)        /* width */
  486.         -(br->browser.b_error->core.border_width *2),
  487.         br->browser.b_error->core.height,            /* height */
  488.         br->browser.b_error->core.border_width);        /* border */
  489.  
  490.  
  491.  
  492.     XtConfigureWidget(br->browser.b_view,
  493.         br->browser.spacing, y1,                /* x & y */
  494.         x -(br->browser.b_view->core.border_width *2)    /* width */
  495.         -(br->browser.spacing *2),
  496.         y -(br->browser.b_view->core.border_width *2)    /* height */
  497.         -y1 -br->browser.spacing,
  498.         br->browser.b_view->core.border_width);        /* border */
  499.  
  500.     /* done */
  501.     return;
  502. }
  503.  
  504.  
  505. static void Realize(wi, value_mask, attributes)
  506. Widget               wi;
  507. Mask                 *value_mask;
  508. XSetWindowAttributes *attributes;
  509. {
  510.  
  511. #ifdef DEBUG
  512.     (void) fputs("Realize called\n", stderr);
  513. #endif DEBUG
  514.  
  515.     XtCreateWindow(wi, (unsigned int) InputOutput,
  516.     (Visual *) CopyFromParent, *value_mask, attributes);
  517.  
  518.     RefigureLocations((BrowserWidget) wi);
  519.  
  520.     XDefineCursor(XtDisplay(wi), XtWindow(wi),
  521.             ((BrowserWidget) wi)->browser.CrossCursor);
  522.  
  523.     return;
  524. }
  525.  
  526.  
  527. static void Resize(w)
  528.     Widget w;
  529. {
  530.  
  531. #ifdef DEBUG
  532.     (void) fputs("Resize called\n", stderr);
  533. #endif DEBUG
  534.  
  535.     RefigureLocations((BrowserWidget) w);
  536.  
  537.     return;
  538. }
  539.  
  540.  
  541. /* ARGSUSED */
  542. static XtGeometryResult GeometryManager(w, request, reply)
  543.     Widget w;
  544.     XtWidgetGeometry *request;
  545.     XtWidgetGeometry *reply;    /* RETURN */
  546. {
  547. #ifdef DEBUG
  548.     (void) fprintf(stderr, "GeometryManager called: %s\n", w->core.name);
  549. #endif DEBUG
  550.  
  551.     return XtGeometryNo;
  552. }
  553.  
  554.  
  555.  
  556. /* ARGSUSED */
  557. static Boolean SetValues(current, request, new)
  558.     Widget current, request, new;
  559. {
  560.     BrowserWidget br = (BrowserWidget)new;
  561.     BrowserWidget old = (BrowserWidget)current;
  562.  
  563. #ifdef DEBUG
  564.     (void) fputs("SetValues called\n", stderr);
  565. #endif DEBUG
  566.  
  567.     if(br->browser.path != old->browser.path
  568.     || br->browser.path != NULL
  569.         && (old->browser.path != NULL
  570.         && strcmp(br->browser.path, old->browser.path)))
  571.     {
  572.     /* delete the old list */
  573.     deleteList(old->browser.list);
  574.  
  575.     /* copy the new path into a safe area */
  576.     (void) strcpy(br->browser.basepath, br->browser.path);
  577.  
  578.     /* create list of file to select from */
  579.     br->browser.list = createFileList(br, br->browser.path);
  580.  
  581.     /* Update the displayed list */
  582.     XtListChange(br->browser.b_list, br->browser.list->list,
  583.             br->browser.list->count, 0, TRUE);
  584.  
  585.     /* update the displayed label */
  586.     UpDateLabel(br, TRUE);
  587.  
  588.     }
  589.  
  590.     return( FALSE );
  591. }
  592.  
  593. /* this is the util. for creating file listings */
  594. static list_type *createFileList(br, selection)
  595. BrowserWidget br;
  596. char *selection;
  597. {
  598. register Cardinal    i;
  599. struct stat stat_buf;
  600. list_type *ret_list;
  601. extern errno;
  602.  
  603.     errno = 0;
  604.  
  605.     /* open requested directory */
  606.     if (selection == (char *) NULL)
  607.     selection = ".";
  608.  
  609.     /* malloc the return list */
  610.     ret_list = (list_type *) XtMalloc(sizeof (list_type));
  611.  
  612.  
  613.     /* report fuckups */
  614.     if (ret_list == NULL) {
  615.     return (list_type *) NULL;
  616.     }
  617.  
  618.     ret_list->count =
  619.         scandir(selection, &ret_list->namelist, br->browser.testProc,
  620.         alphasort);
  621.  
  622.     /* test the scaning */
  623.     if(ret_list->count == -1) {
  624. #ifdef DEBUG
  625.     XtWarning("Fucked up in opening dir");
  626. #endif DEBUG
  627.     XtFree((char *) ret_list);
  628.     return (list_type *) NULL;
  629.     }
  630.  
  631.     ret_list->list = (char **)XtCalloc(ret_list->count +1, sizeof(char *));
  632.     ret_list->mode = (int *)  XtCalloc(ret_list->count, sizeof(int));
  633.  
  634.     for(i=0; i < ret_list->count; i++) {
  635.     int len;
  636.     char tbuf[MAXNAMLEN +2];
  637.  
  638.     /* get the length of the file name for later use [and reuse] */
  639.     len = strlen(ret_list->namelist[i]->d_name) + 2;
  640.  
  641.     /* copy file name into a new buffer */
  642.     ret_list->list[i] =
  643.         strcpy( XtMalloc(len), ret_list->namelist[i]->d_name);
  644.  
  645.     /* copy the current directory into a tempory space */
  646.     (void) strcpy(tbuf, selection);
  647.  
  648.     /* add a "/" to the current directory path if it's not there already */
  649.     if (tbuf[strlen(tbuf) -1] != '/')
  650.         (void) strcat(tbuf, "/");
  651.  
  652.     /* tack on the current file name */
  653.     (void) strcat(tbuf, ret_list->list[i]);
  654.  
  655.     /* get the status of our 'file', if we fail ignore the file */
  656.     if ( stat(tbuf, &stat_buf) != 0 ) {
  657. #ifdef DEBUG
  658.         (void) perror(ret_list->namelist[i]->d_name);
  659.         XtWarning("Fucked up in stating file");
  660. #endif DEBUG
  661.         showError(br, ret_list->list[i]);
  662.         continue;
  663.     }
  664.  
  665.     ret_list->mode[i] = stat_buf.st_mode;
  666.  
  667.     /* add the '/' to the end of the name to indicate directrices, etc..*/
  668.     switch (ret_list->mode[i] & S_IFMT) {
  669.         case S_IFDIR:
  670.         (void) strcat(ret_list->list[i], "/");
  671.         break;
  672.         case S_IFSOCK:
  673.         (void) strcat(ret_list->list[i], "=");
  674.         break;
  675.         default:
  676.         if ( (stat_buf.st_mode & ~S_IFMT) & 0111)
  677.             (void) strcat(ret_list->list[i], "*");
  678.         break;
  679.     }
  680.     }
  681.  
  682.     /* null out the next slot [it should be null from calloc but..] */
  683.     ret_list->list[i +1] = (char *) NULL;
  684.  
  685. #ifdef DEBUG
  686.     printList(ret_list);
  687. #endif DEBUG
  688.  
  689.     /* return with our work */
  690.     return ret_list;
  691. }
  692.  
  693.  
  694. /* A clean up utility */
  695. static void deleteList(dead_list)
  696. list_type *dead_list;
  697. {
  698. register int i;
  699.  
  700.     /* Test to see it we have a list */
  701.     if(dead_list == (list_type *) NULL)
  702.     return;
  703.  
  704.     /* free the strings */
  705.     for(i=0; i < dead_list->count; i++) {
  706.     XtFree( (char *) dead_list->list[i]);
  707.     }
  708.  
  709.     XtFree((char *) dead_list->namelist);
  710.     XtFree((char *) dead_list->list);
  711.     XtFree((char *) dead_list);
  712.  
  713.     return;
  714. }
  715.  
  716.  
  717.  
  718. /*ARGUSED*/
  719. static void _cancelCall(wi, client_data, call_data)
  720. Widget wi;
  721. caddr_t client_data;
  722. caddr_t call_data;
  723. {
  724. BrowserWidget br = (BrowserWidget)client_data;
  725.  
  726.     /* Change the Cursors to a clock so the they think we're fuckup */
  727.     SetWorkState(br, TRUE);
  728.  
  729.     /* Clear the error line*/
  730.     clearError(br);
  731.  
  732.     XtCallCallbacks((Widget) br, XtNcancelCallback, (char *) NULL);
  733.  
  734.     /* Tell the user we are done */
  735.     SetWorkState(br, FALSE);
  736.  
  737.     return;
  738. }
  739.  
  740.  
  741. /*ARGUSED*/
  742. static void _openCall(wi, client_data, call_data)
  743. Widget wi;
  744. caddr_t client_data;
  745. caddr_t call_data;
  746. {
  747. int i;
  748. XtListReturnStruct *ret_value;
  749. BrowserWidget br = (BrowserWidget)client_data;
  750.  
  751.     /* Clear the error line*/
  752.     clearError(br);
  753.  
  754.     /* get the current selected list */
  755.     ret_value = XtListShowCurrent(br->browser.b_list);
  756.     i = ret_value->index;
  757.  
  758.     /* free as soon as we don't need */
  759.     XtFree((char *)ret_value);
  760.  
  761.  
  762.     /* test to see it there is a current seletion */
  763.     if( i != XT_LIST_NONE ) {
  764.  
  765.     /* Change the Cursors to a clock so the they think we're fuckup */
  766.     SetWorkState(br, TRUE);
  767.  
  768.     /* test if we are looking at a directory or not */
  769.     if ( br->browser.list->mode[i] & (S_IFMT & S_IFDIR) )
  770.         followdir(br, br->browser.list->namelist[i]->d_name);
  771.     else
  772.         XtCallCallbacks((Widget) br, XtNopenCallback,
  773.                 br->browser.list->namelist[i]->d_name);
  774.  
  775.     /* Tell the user we are done */
  776.     SetWorkState(br, FALSE);
  777.  
  778.     }
  779.  
  780.     return;
  781. }
  782.  
  783.  
  784.  
  785.  
  786. static void followdir(br, new_path)
  787. BrowserWidget br;
  788. String new_path;
  789. {
  790. register u_int i;
  791. char    *c;
  792. char    t_path[MAXPATHLEN];
  793. list_type *t_list;
  794.  
  795.     /* reset the error index */
  796.     clearError(br);
  797.  
  798. #ifdef DEBUG
  799.     (void) fputs("followdir\n", stderr);
  800. #endif DEBUG
  801.  
  802.     /* just in case save the old path and lists */
  803.     (void) strcpy(t_path, br->browser.basepath);
  804.     t_list = br->browser.list;
  805.  
  806.     /* see it we are just backing up one dir, there has to be a better way.. */
  807.     if( strncmp(new_path, "..", 2) == 0 ) {
  808.  
  809.     /* get the last occurance of the char '/' in the string  */
  810.     c = rindex(br->browser.basepath, '/');
  811.  
  812.     /* report if it is not possible to back out */
  813.     if(c == (char *)NULL) {
  814.         showError(br, "Burp!: could not track '/'");
  815.         return;
  816.     }
  817.  
  818.     /* check if we index'ed  to root's "/" */
  819.     if ( c == br->browser.basepath ) {
  820.         (void) strcpy(br->browser.basepath, "/");
  821.     } else {
  822.         /* Null out the rest of the string */
  823.         while( *c != '\0') *c++ = '\0';
  824.     }
  825.  
  826.     } else {
  827.  
  828.     i = strlen(br->browser.basepath) -1;
  829.  
  830.     if (br->browser.basepath[i] != '/')
  831.         (void) strcat(br->browser.basepath, "/");
  832.  
  833.     (void) strcat(br->browser.basepath, new_path);
  834.  
  835.     i = strlen(br->browser.basepath) -1;
  836.  
  837.     if (br->browser.basepath[i] == '/')
  838.         br->browser.basepath[i] = (char) NULL;
  839.     }
  840.  
  841.     /* create a new list of files useing the new base path */
  842.     br->browser.list = createFileList(br, br->browser.basepath);
  843.  
  844.     /* Test the new list, if error report it and restore old values */
  845.     if (br->browser.list == (list_type *) NULL) {
  846.     showError(br, br->browser.basepath);
  847.     (void) strcpy(br->browser.basepath, t_path);
  848.     br->browser.list = t_list;
  849.     return;
  850.     }
  851.  
  852.     /* free the storage used by the current list */
  853.     deleteList(t_list);
  854.  
  855. #ifdef DEBUG
  856.     showList(br->browser.list);
  857.     (void) fprintf(stderr, "basepath = `%s`\n", br->browser.basepath);
  858. #endif DEBUG
  859.  
  860.     /* Update the path label with the new path */
  861.     UpDateLabel(br, TRUE);
  862.  
  863.     /* Update the listing with the new list */
  864.     XtListChange(br->browser.b_list, br->browser.list->list, br->browser.list->count, 0, TRUE);
  865.  
  866.     return;
  867. }
  868.  
  869. #ifdef DEBUG
  870. static void showList(ll)
  871. list_type *ll;
  872. {
  873. register int i;
  874.  
  875.     for (i=0; i < ll->count; i++)
  876.     (void) fprintf(stderr,
  877.     "%d:\tlist->list[i] = `%s`\tnamelist[i]->d_name= `%s`\tmode = %lo\n",
  878.         i, ll->list[i], ll->namelist[i]->d_name, ll->mode[i]);
  879.  
  880.     printList(ll);
  881.  
  882.     return;
  883. }
  884. #endif DEBUG
  885.  
  886. static void UpDateLabel(br, copy)
  887. BrowserWidget br;
  888. Boolean copy;
  889. {
  890. XtTextPosition len;
  891.  
  892.     /* Unset whatever maybe highlighted */
  893.     XtTextUnsetSelection(br->browser.b_label);
  894.  
  895.     /* copy the real path in the shown path */
  896.     if(copy)
  897.     (void) strcpy(br->browser.labelpath, br->browser.basepath);
  898.  
  899.     /* get the length of the current path */
  900.     len = (XtTextPosition) strlen(br->browser.labelpath);
  901.  
  902.     /* set the last position in the buffer */
  903.     XtTextSetLastPos(br->browser.b_label, len);
  904.  
  905.     /* move the Cursor to the last position in the buffer */
  906.     XtTextSetInsertionPoint(br->browser.b_label, len);
  907.  
  908.     return;
  909. }
  910.  
  911. /* this is the callback for our widget when it it is destroyed */
  912. static void Bdestroy(wi)
  913. Widget wi;
  914. {
  915.     BrowserWidget br = (BrowserWidget)wi;
  916.  
  917. #ifdef DEBUG
  918.     (void) fputs("Bdestroy called\n", stderr);
  919. #endif DEBUG
  920.  
  921.     deleteList(br->browser.list);
  922.  
  923.     XtFree(br->browser.basepath);
  924.     XtFree(br->browser.labelpath);
  925.  
  926.     XFreeCursor(br->browser.ArrowCursor);
  927.     XFreeCursor(br->browser.CrossCursor);
  928.     XFreeCursor(br->browser.ClockCursor);
  929.  
  930.     return;
  931. }
  932.  
  933. static void
  934. prev_callback(wi)
  935. Widget wi;
  936. {
  937. char *c;
  938. BrowserWidget br = (BrowserWidget)XtParent(wi);
  939.  
  940.     /* clear the error window */
  941.     clearError(br);
  942.  
  943.     /* get the last occurance of the char '/' in the string  */
  944.     c = rindex(br->browser.labelpath, '/');
  945.  
  946.     /* report if it is not possible to back out */
  947.     if(c == (char *)NULL) {
  948.     showError(br, "Burp!: could not track '/'");
  949.     XBell(XtDisplay(br), 0);
  950.     return;
  951.     }
  952.  
  953.     /* check if we index'ed  to root's "/" */
  954.     if ( c == br->browser.labelpath ) {
  955.     (void) strcpy(br->browser.labelpath, "/");
  956.     } else {
  957.     /* Null out the rest of the string */
  958.     while( *c != '\0') *c++ = '\0';
  959.     }
  960.  
  961.     /* have the label reflect the change */
  962.     UpDateLabel(br, FALSE);
  963.  
  964.     return;
  965. }
  966.  
  967. static void next_callback(wi)
  968. Widget wi;
  969. {
  970. struct stat stat_buf;
  971. BrowserWidget br = (BrowserWidget)XtParent(wi);
  972.  
  973. #ifdef DEBUG
  974.     (void) fputs("next_callback called\n", stderr);
  975. #endif DEBUG
  976.  
  977.     /* turn off input and set the cursors to a clock */
  978.     SetWorkState(br, TRUE);
  979.  
  980.     /* clear the error window */
  981.     clearError(br);
  982.  
  983.     /* get the status of our 'file', if we fail ignore the file */
  984.     if ( stat(br->browser.labelpath, &stat_buf) != 0 ) {
  985.         showError(br, br->browser.labelpath);
  986.     }
  987.  
  988.     if (stat_buf.st_mode & (S_IFMT & S_IFDIR) ) {
  989.         list_type *t_list = br->browser.list;
  990.  
  991.         br->browser.list = createFileList(br, br->browser.labelpath);
  992.  
  993.         /* Test the new list */
  994.         if (br->browser.list == (list_type *) NULL) {
  995.  
  996.         /* (void) strcpy(br->browser.basepath, t_path); */
  997.         br->browser.list = t_list;
  998.         showError(br, br->browser.labelpath);
  999.         SetWorkState(br, FALSE);
  1000.         return;
  1001.         }
  1002.  
  1003.         /* Update the listing with the new list */
  1004.         XtListChange(br->browser.b_list, br->browser.list->list,
  1005.                     br->browser.list->count, 0, TRUE);
  1006.  
  1007.         (void) strcpy(br->browser.basepath, br->browser.labelpath);
  1008.  
  1009.         /* this should not be needed */
  1010.         UpDateLabel(br, FALSE);
  1011.  
  1012.     } else
  1013.         XtCallCallbacks(br, XtNopenCallback, br->browser.labelpath);
  1014.  
  1015.     SetWorkState(br, FALSE);
  1016.  
  1017.     return;
  1018. }
  1019.  
  1020. static void path_completion(wi)
  1021. Widget wi;
  1022. {
  1023. char *c;
  1024. int     len;
  1025. int    dir_count;
  1026. u_int   i;
  1027. u_int   hit=0;
  1028. char    selection[MAXPATHLEN];
  1029. char    name[MAXNAMLEN];
  1030. struct direct **dir_list;
  1031. Boolean free;
  1032. BrowserWidget br = (BrowserWidget)XtParent(wi);
  1033.  
  1034.  
  1035. #ifdef DEBUG
  1036.     (void) fputs("path_completion called\n", stderr);
  1037. #endif DEBUG
  1038.  
  1039.     clearError(br);
  1040.  
  1041.     /* get the last occurance of the char '/' in the string  */
  1042.     c = rindex(br->browser.labelpath, '/');
  1043.  
  1044.     /* report if it is not possible to back out */
  1045.     if(c == (char *)NULL) {
  1046.     c = br->browser.labelpath;
  1047.     /*
  1048.     showError(br, "Burp!: could not track '/'");
  1049.     return;
  1050.     */
  1051.     }
  1052.  
  1053.     /* move forward to skip the '/' */
  1054.     *c++;
  1055.  
  1056.     len = strlen(c);
  1057.  
  1058.     /* we will have trouble it these strings are not nulled */
  1059.     bzero(name, MAXNAMLEN);
  1060.     bzero(selection, MAXPATHLEN);
  1061.  
  1062.     (void) strncpy(selection, br->browser.labelpath,
  1063.         ((int)c -(int)br->browser.labelpath));
  1064.  
  1065.     if (strcmp(selection, br->browser.basepath) == 0) {
  1066.     dir_count = br->browser.list->count;
  1067.     dir_list = br->browser.list->namelist;
  1068.     free = FALSE;
  1069.     } else {
  1070.     dir_count = scandir(selection, &dir_list, br->browser.testProc,
  1071.         alphasort);
  1072.  
  1073.     if ( dir_count == -1) {
  1074.         showError(br, selection);
  1075.         return;
  1076.     }
  1077.  
  1078.     free = TRUE;
  1079.     }
  1080.  
  1081.     /* Enter Loop only if there is something to do */
  1082.     if (len > 0) {
  1083.     for(i=0; i < dir_count; i++)
  1084.         if ( strncmp(c, dir_list[i]->d_name, len) == 0) {
  1085.         /* if this is the first match copy if in full */
  1086.         hit++;
  1087.         if(hit == 1)
  1088.             (void) strcpy(name, dir_list[i]->d_name);
  1089.         else {
  1090.             register int j=0;
  1091.  
  1092.             for(; dir_list[i]->d_name[j] == name[j]; j++);
  1093.  
  1094.             name[j] = '\0';
  1095.  
  1096.             if(j == len)
  1097.             break;
  1098.         }
  1099.         }
  1100.  
  1101.  
  1102.     /* Ugly Ugly Ugly */
  1103.     if(hit == 0) {
  1104.  
  1105.         XBell(XtDisplay(br), 0);
  1106.         showError(br, "No matches found");
  1107.  
  1108.     } else {
  1109.  
  1110.         /* if we matched more then once ring bell */
  1111.         if(hit > 1) {
  1112.         char tbuf[MAXPATHLEN];
  1113.  
  1114.         (void) strcpy(tbuf, "\"");
  1115.         (void) strcat(tbuf, c);
  1116.         (void) strcat(tbuf, "\": ambiguous");
  1117.  
  1118.         XBell(XtDisplay(br), 0);
  1119.         showError(br, tbuf);
  1120.         }
  1121.  
  1122.         /* if we matched ANYTHING add the result to the current path*/
  1123.         if(hit) {
  1124.         (void) strcpy(c, name);
  1125.         UpDateLabel(br, FALSE);
  1126.         }
  1127.     }
  1128.  
  1129.  
  1130.     }
  1131.  
  1132.     if(free)
  1133.     XtFree((char *) dir_list);
  1134.  
  1135.     return;
  1136. }
  1137.  
  1138. static void dummy()
  1139. {
  1140. #ifdef DEBUG
  1141.     (void) fputs("dummy called\n", stderr);
  1142. #endif DEBUG
  1143.     return;
  1144. }
  1145.  
  1146. /* this is call if the user types in a Cont-C */
  1147. static void kill_callback(wi)
  1148. Widget wi;
  1149. {
  1150. BrowserWidget br = (BrowserWidget)XtParent(wi);
  1151.  
  1152.     XtCallCallbacks(br, XtNcancelCallback, NULL);
  1153.  
  1154.     return;
  1155. }
  1156.  
  1157. static void clearError(br)
  1158. BrowserWidget br;
  1159. {
  1160.  
  1161.     static Arg update_arg[] = {
  1162.     {XtNlabel,        (XtArgVal) ">"}
  1163.     };
  1164.  
  1165.     errno = 0;
  1166.  
  1167. #ifdef DEBUG
  1168.     (void) fputs("clearError called\n", stderr);
  1169. #endif DEBUG
  1170.  
  1171.     XtSetValues(br->browser.b_error, update_arg, XtNumber(update_arg));
  1172.  
  1173.     return;
  1174. }
  1175.  
  1176.  
  1177. /*
  1178.  * This func displays the current error in
  1179.  * a error window on the browser window
  1180.  */
  1181. static void showError(br, string)
  1182. BrowserWidget br;
  1183. char *string;
  1184. {
  1185. char    tbuf[MAXPATHLEN +80];
  1186. extern  char *sys_errlist[];
  1187. extern  int sys_nerr;
  1188. extern  int errno;
  1189.  
  1190.     static Arg update_arg[] = {
  1191.     {XtNlabel,        (XtArgVal) NULL}
  1192.     };
  1193.  
  1194.     if (string != (char *) NULL)
  1195.     (void) strcpy(tbuf, string);
  1196.     else
  1197.     (void) strcpy(tbuf, "Error");
  1198.  
  1199. #ifdef DEBUG
  1200.     (void) perror(tbuf);
  1201. #endif DEBUG
  1202.  
  1203.     if (errno > 0 && errno < sys_nerr) {
  1204.     (void) strcat(tbuf, ": ");
  1205.     (void) strcat(tbuf, sys_errlist[errno]);
  1206.     }
  1207.  
  1208.     update_arg[0].value = (XtArgVal) tbuf;
  1209.  
  1210.     XBell(XtDisplay(br), 0);
  1211.  
  1212.     if(XtIsRealized(br))
  1213.     XtSetValues(br->browser.b_error, update_arg, XtNumber(update_arg));
  1214.  
  1215.     return;
  1216. }
  1217.  
  1218. static void SetWorkState(br, state)
  1219. BrowserWidget br;
  1220. Boolean state;
  1221. {
  1222.  
  1223.     if (state) {
  1224.     XDefineCursor(XtDisplay(br), XtWindow(br), br->browser.ClockCursor);
  1225.     XDefineCursor(XtDisplay(br), XtWindow(br->browser.b_list),
  1226.                 br->browser.ClockCursor);
  1227.     XDefineCursor(XtDisplay(br), XtWindow(br->browser.b_label),
  1228.                 br->browser.ClockCursor);
  1229.  
  1230.  
  1231.     XtSetSensitive(br->browser.b_open, FALSE);
  1232.     XtSetSensitive(br->browser.b_label, FALSE);
  1233.     XtSetSensitive(br->browser.b_cancel, FALSE);
  1234.  
  1235.     } else {
  1236.  
  1237.     XDefineCursor(XtDisplay(br), XtWindow(br), br->browser.CrossCursor);
  1238.     XDefineCursor(XtDisplay(br), XtWindow(br->browser.b_list),
  1239.                 br->browser.ArrowCursor);
  1240.     XDefineCursor(XtDisplay(br), XtWindow(br->browser.b_label),
  1241.                 br->browser.CrossCursor);
  1242.  
  1243.     XtSetSensitive(br->browser.b_open, TRUE);
  1244.     XtSetSensitive(br->browser.b_label, TRUE);
  1245.     XtSetSensitive(br->browser.b_cancel, TRUE);
  1246.     }
  1247.  
  1248.     return;
  1249. }
  1250.  
  1251. /**********************************************************************
  1252.  *
  1253.  * Public routines
  1254.  *
  1255.  **********************************************************************/
  1256.  
  1257. /* none */
  1258.  
  1259.  
  1260. /* END OF TEXT */
  1261.