"Fossies" - the Fresh Open Source Software Archive

Member "xcircuit-3.10.30/filelist.c" (27 Dec 2020, 27186 Bytes) of package /linux/misc/xcircuit-3.10.30.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "filelist.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.10.29_vs_3.10.30.

    1 /*-------------------------------------------------------------------------*/
    2 /* filelist.c --- Xcircuit routines for the filelist widget        */ 
    3 /* Copyright (c) 2002  Tim Edwards, Johns Hopkins University               */
    4 /*-------------------------------------------------------------------------*/
    5 
    6 #include <stdio.h>
    7 #include <stdlib.h>
    8 #include <string.h>
    9 #include <signal.h>
   10 #include <sys/types.h>
   11 #include <ctype.h>  /* For isspace() */
   12 
   13 #ifdef HAVE_DIRENT_H
   14 #include <dirent.h>
   15 #include <unistd.h>
   16 #define direct dirent
   17 #elif !defined(_MSC_VER)
   18 #include <sys/dir.h>
   19 #endif
   20 
   21 #include <sys/stat.h>
   22 #include <errno.h>
   23 #include <limits.h>
   24 
   25 #ifndef XC_WIN32
   26 #include <X11/Intrinsic.h>
   27 #include <X11/StringDefs.h>
   28 #include <X11/Shell.h>
   29 #include <X11/Xutil.h>
   30 #include <X11/cursorfont.h>
   31 #endif
   32 #ifdef TCL_WRAPPER 
   33 #include <tk.h>
   34 #else
   35 #ifndef XC_WIN32
   36 #include "Xw/Xw.h"
   37 #include "Xw/WorkSpace.h"
   38 #include "Xw/TextEdit.h"
   39 #include "Xw/Toggle.h"
   40 #endif
   41 #endif
   42 
   43 #if defined(XC_WIN32) && defined(TCL_WRAPPER)
   44 #include <X11/Xlib.h>
   45 #include <X11/Xutil.h>
   46 #include <X11/cursorfont.h>
   47 #endif
   48 
   49 
   50 /*-------------------------------------------------------------------------*/
   51 /* Local includes                              */
   52 /*-------------------------------------------------------------------------*/
   53 
   54 #include "colordefs.h"
   55 #include "xcircuit.h"
   56 
   57 /*----------------------------------------------------------------------*/
   58 /* Function prototype declarations                                      */
   59 /*----------------------------------------------------------------------*/
   60 #include "prototypes.h"
   61 
   62 /*-------------------------------------------------------------------------*/
   63 /* Local definitions                               */
   64 /*-------------------------------------------------------------------------*/
   65 
   66 #define INITDIRS 10
   67 
   68 /*-------------------------------------------------------------------------*/
   69 /* Global Variable definitions                         */
   70 /*-------------------------------------------------------------------------*/
   71 
   72 #ifdef TCL_WRAPPER
   73 extern Tcl_Interp *xcinterp;
   74 #endif
   75 
   76 extern Display    *dpy;
   77 extern XCWindowData *areawin;
   78 extern ApplicationData appdata;
   79 extern colorindex *colorlist;
   80 extern short      popups;     /* total number of popup windows */
   81 extern char   _STR2[250];
   82 extern char   _STR[150];
   83 extern Globaldata xobjs;
   84 
   85 Pixmap   flistpix = (Pixmap)NULL;    /* For file-selection widget */
   86 short    flstart, flfiles, flcurrent;
   87 int  flcurwidth;
   88 
   89 GC   hgc = NULL, sgc = NULL;
   90 char     *cwdname = NULL;
   91 fileliststruct *files;
   92 
   93 #if !defined(XC_WIN32) || defined(TCL_WRAPPER)
   94 
   95 /*-------------------------------------------------------------------------*/
   96 /* Compare two filenames (for use by qsort())                  */
   97 /*-------------------------------------------------------------------------*/
   98 
   99 int fcompare(const void *a, const void *b)
  100 {
  101    return (strcmp((char *)(((fileliststruct *)a)->filename),
  102     (char *)(((fileliststruct *)b)->filename)));
  103 }
  104 
  105 /*-------------------------------------------------------------------------*/
  106 /* Routines for drawing a box around the currently selected file       */
  107 /*-------------------------------------------------------------------------*/
  108 
  109 void dragfilebox(xcWidget w, caddr_t clientdata, XMotionEvent *event)
  110 {
  111    short filenum;
  112    int twidth;
  113    Window lwin = xcWindow(w);
  114 
  115    filenum = (event->y - 10 + FILECHARHEIGHT) / FILECHARHEIGHT + flstart - 1;
  116    if (filenum < 0) filenum = 0;
  117    else if (filenum >= flfiles) filenum = flfiles - 1;
  118   
  119    if (filenum == flcurrent) return;
  120 
  121    if (flcurrent >= 0)      /* erase previous box */
  122       XDrawRectangle(dpy, lwin, areawin->gc, 5,
  123        10 + FILECHARHEIGHT * (flcurrent
  124        - flstart), flcurwidth + 10, FILECHARHEIGHT);
  125 
  126    if (files == NULL) return;
  127 
  128    twidth = XTextWidth(appdata.filefont, files[filenum].filename,
  129         strlen(files[filenum].filename));
  130    XDrawRectangle(dpy, lwin, areawin->gc, 5,
  131        10 + FILECHARHEIGHT * (filenum
  132        - flstart), twidth + 10, FILECHARHEIGHT);
  133 
  134    flcurrent = filenum;
  135    flcurwidth = twidth;
  136 }
  137 
  138 /*-------------------------------------------------------------------------*/
  139 /* Begin tracking the cursor position relative to the files in the list    */
  140 /*-------------------------------------------------------------------------*/
  141 
  142 void startfiletrack(xcWidget w, caddr_t clientdata, XCrossingEvent *event)
  143 {
  144 #ifdef TCL_WRAPPER
  145    Tk_CreateEventHandler(w, PointerMotionMask,
  146         (Tk_EventProc *)xctk_dragfilebox, (ClientData)w);
  147 #else
  148    xcAddEventHandler(w, PointerMotionMask, False, (xcEventHandler)dragfilebox, NULL);
  149 #endif
  150 
  151    XSetFunction(dpy, areawin->gc, GXcopy);
  152    XSetForeground(dpy, areawin->gc, colorlist[AUXCOLOR].color.pixel);
  153    XSetLineAttributes(dpy, areawin->gc, 1, LineSolid, CapRound, JoinMiter);
  154 
  155    /* draw initial box */
  156 
  157    flcurrent = -1;
  158    dragfilebox(w, NULL, (XMotionEvent *)event);
  159 
  160    XSetFunction(dpy, areawin->gc, GXxor);
  161    XSetForeground(dpy, areawin->gc, colorlist[AUXCOLOR].color.pixel ^
  162         colorlist[BACKGROUND].color.pixel);
  163 }
  164 
  165 /*-------------------------------------------------------------------------*/
  166 /* Stop tracking the cursor and return to default state            */
  167 /*-------------------------------------------------------------------------*/
  168 
  169 void endfiletrack(xcWidget w, caddr_t clientdata, XCrossingEvent *event)
  170 {
  171    Window lwin = xcWindow(w);
  172 
  173    XDrawRectangle(dpy, lwin, areawin->gc, 5,
  174        10 + FILECHARHEIGHT * (flcurrent
  175        - flstart), flcurwidth + 10, FILECHARHEIGHT);
  176 
  177 #ifdef TCL_WRAPPER
  178    Tk_DeleteEventHandler(w, PointerMotionMask,
  179         (Tk_EventProc *)xctk_dragfilebox, (ClientData)w);
  180 #else
  181    xcRemoveEventHandler(w, PointerMotionMask, False,
  182         (xcEventHandler)dragfilebox, NULL);
  183 #endif
  184 
  185    /* Restore graphics state values */
  186    XSetForeground(dpy, areawin->gc, colorlist[areawin->gccolor].color.pixel);
  187    XSetFunction(dpy, areawin->gc, GXcopy);
  188 }
  189 
  190 #endif
  191 
  192 /*----------------------------------------------------------------------*/
  193 /* Read a crash file to find the name of the original file.     */
  194 /*----------------------------------------------------------------------*/
  195 
  196 char *getcrashfilename()
  197 {
  198    FILE *fi;
  199    char temp[256];
  200    char *retstr = NULL, *tpos, *spos;
  201    int slen;
  202 
  203    if ((fi = fopen(_STR2, "r")) != NULL) {
  204       while (fgets(temp, 255, fi) != NULL) {
  205      if ((tpos = strstr(temp, "Title:")) != NULL) {
  206         ridnewline(temp);
  207         tpos += 7;
  208         if ((spos = strrchr(temp, '/')) != NULL)
  209            tpos = spos + 1;
  210         retstr = (char *)malloc(1 + strlen(tpos));
  211         strcpy(retstr, tpos);
  212      }
  213      else if ((tpos = strstr(temp, "CreationDate:")) != NULL) {
  214         ridnewline(temp);
  215         tpos += 14;
  216         slen = strlen(retstr);
  217         retstr = (char *)realloc(retstr, 4 + slen + strlen(tpos));
  218         sprintf(retstr + slen, " (%s)", tpos);
  219         break;
  220      }
  221       }
  222       fclose(fi);
  223    }
  224    return retstr;
  225 }
  226 
  227 /*----------------------------------------------------------------------*/
  228 /* Crash recovery:  load the file, and link the tempfile name to it.    */
  229 /*----------------------------------------------------------------------*/
  230 
  231 void crashrecover()
  232 {
  233    if (xobjs.tempfile != NULL) {
  234       unlink(xobjs.tempfile);
  235       free(xobjs.tempfile);
  236       xobjs.tempfile = NULL;
  237    }
  238    if (strlen(_STR2) == 0) {
  239       Wprintf("Error: No temp file name for crash recovery!");
  240    }
  241    else {
  242       xobjs.tempfile = strdup(_STR2);
  243       startloadfile(-1);
  244    }
  245 }
  246 
  247 /*----------------------------------------------------------------------*/
  248 /* Look for any files left over from a crash.                           */
  249 /*----------------------------------------------------------------------*/
  250 
  251 void findcrashfiles()
  252 {
  253    DIR *cwd;
  254    struct direct *dp;
  255    struct stat sbuf;
  256 #ifndef _MSC_VER
  257    uid_t userid = getuid();
  258 #endif
  259    time_t recent = 0;
  260    char *snptr;
  261    int pid;
  262 
  263    cwd = opendir(xobjs.tempdir);
  264    if (cwd == NULL) return; /* No tmp directory, no tmp files! */
  265 
  266    while ((dp = readdir(cwd)) != NULL) {
  267       sprintf(_STR, "%s/%s", xobjs.tempdir, dp->d_name);
  268       snptr = _STR + strlen(xobjs.tempdir) + 1;
  269       if (!strncmp(snptr, "XC", 2)) {
  270      char *dotptr = strchr(snptr, '.');
  271      pid = -1;
  272      if (dotptr && dotptr > snptr + 2) {
  273         *dotptr = '\0';
  274         if (sscanf(snptr + 2, "%d", &pid) != 1) 
  275            pid = -1;
  276         *dotptr = '.';
  277          }
  278          if ((!stat(_STR, &sbuf))
  279 #ifndef _MSC_VER
  280          && (sbuf.st_uid == userid)
  281 #endif
  282          ) {
  283         if ((recent == 0) || (sbuf.st_ctime > recent)) {
  284 
  285            /* Check if the PID belongs to an active process */
  286            /* by sending a CONT signal and checking if  */
  287            /* there was no error result.            */
  288 
  289 #ifndef _MSC_VER
  290            if (pid != -1)
  291           if (kill((pid_t)pid, SIGCONT) == 0)
  292              continue;
  293 #endif
  294 
  295            recent = sbuf.st_ctime;
  296            strcpy(_STR2, _STR);
  297         }
  298      }
  299       }
  300    }
  301    closedir(cwd);
  302    
  303    if (recent > 0) {    /* There exists at least one temporary file */
  304             /* belonging to this user.  Ask to recover  */
  305             /* the most recent one.             */
  306 
  307       /* Warn user of existing tempfile, and ask user if file   */
  308       /* should be recovered immediately.           */
  309 
  310 #ifdef TCL_WRAPPER
  311       char *cfile = getcrashfilename();
  312 
  313       sprintf(_STR, ".query.title.field configure -text "
  314         "\"Recover file \'%s\'?\"", 
  315         (cfile == NULL) ? "(unknown)" : cfile);
  316       Tcl_Eval(xcinterp, _STR);
  317       Tcl_Eval(xcinterp, ".query.bbar.okay configure -command "
  318         "{filerecover; wm withdraw .query}; wm deiconify .query");
  319       if (cfile != NULL) free(cfile);
  320 #else
  321       getfile(NULL, (pointertype)RECOVER, NULL);   /* Crash recovery mode */
  322 #endif
  323    }
  324 }  
  325 
  326 /*----------------------------------------------------------------------*/
  327 /* Match a filename extension against the file filter list.     */
  328 /*----------------------------------------------------------------------*/
  329 
  330 #if !defined(XC_WIN32) || defined(TCL_WRAPPER)
  331 
  332 Boolean match_filter(char *fname, char *filter)
  333 {
  334    char *dotptr = strrchr(fname, '.');
  335    char *filtptr, *endptr;
  336    int filtlen, extlen;
  337 
  338    if (filter == NULL) return False;
  339    if (dotptr == NULL) return False;
  340 
  341    /* New 11/08:  Empty string for filter is a wildcard match, the same */
  342    /* as turning off the filter.                    */
  343 
  344    if (filter[0] == '\0') return True;
  345 
  346    dotptr++;
  347    extlen = strlen(dotptr);
  348    filtptr = filter;
  349 
  350    while (*filtptr != '\0') {
  351       endptr = filtptr;
  352       while (*endptr != '\0' && !isspace(*endptr)) endptr++;
  353       filtlen = (int)(endptr - filtptr);
  354       if (filtlen == extlen)
  355          if (!strncmp(dotptr, filtptr, extlen))
  356         return True;
  357 
  358       filtptr = endptr;
  359       while (*filtptr != '\0' && isspace(*filtptr)) filtptr++;
  360    }
  361    return False;
  362 }
  363 
  364 /*----------------------------------------------------------------------*/
  365 /* Make a list of the files in the list widget window           */
  366 /*----------------------------------------------------------------------*/
  367 
  368 void listfiles(xcWidget w, popupstruct *okaystruct, caddr_t calldata)
  369 {
  370    XGCValues    values;
  371 #ifndef TCL_WRAPPER
  372    Arg wargs[2];
  373 #endif
  374    DIR *cwd;
  375    char *filter;
  376    Window lwin = xcWindow(w);
  377    short allocd = INITDIRS;
  378    short n = 0;
  379    struct direct *dp;
  380    struct stat statbuf;
  381    int pixheight;
  382    Dimension textwidth, textheight;
  383 
  384    filter = okaystruct->filter;
  385 
  386    if (sgc == NULL) {
  387       values.foreground = colorlist[FOREGROUND].color.pixel;
  388       values.font = appdata.filefont->fid;
  389       values.function = GXcopy;
  390       values.graphics_exposures = False;
  391       sgc = XCreateGC(dpy, lwin, GCForeground | GCFont | GCFunction
  392         | GCGraphicsExposures, &values);
  393    }
  394 
  395 #ifdef TCL_WRAPPER
  396    textwidth = Tk_Width(w);
  397    textheight = Tk_Height(w);
  398 #else
  399    XtnSetArg(XtNwidth, &textwidth);
  400    XtnSetArg(XtNheight, &textheight);
  401    XtGetValues(w, wargs, n);
  402 #endif
  403 
  404    /* Generate a new flistpix pixmap if currently nonexistent */
  405 
  406    if (!flistpix) {
  407 
  408       /* get list of files in the current directory (cwd) */
  409 
  410       flfiles = 0;
  411       if (cwdname == NULL) {
  412      cwdname = (char *) malloc (sizeof(char));
  413      cwdname[0] = '\0';
  414       }
  415       if (cwdname[0] == '\0')
  416          cwd = opendir(".");
  417       else
  418          cwd = opendir(cwdname);
  419 
  420       /* If current directory cannot be accessed for some reason, */
  421       /* print "Invalid Directory" to the file list window.   */
  422 
  423       if (cwd == NULL) {
  424          XSetForeground(dpy, sgc, colorlist[BACKGROUND].color.pixel);
  425          XFillRectangle(dpy, lwin, sgc, 0, 0, textwidth, textheight);
  426          XSetForeground(dpy, sgc, colorlist[AUXCOLOR].color.pixel);
  427          XDrawString(dpy, lwin, sgc, 10, textheight / 2,
  428         "(Invalid Directory)", 19);
  429      return;
  430       }
  431       else {
  432      if (files == NULL) 
  433         files = (fileliststruct *) malloc (INITDIRS * sizeof(fileliststruct));
  434 
  435      /* write the contents of the current directory into the   */
  436      /* array "filenames[]" (except for current directory ".") */
  437 
  438          while ((dp = readdir(cwd)) != NULL) {
  439         /* don't put current directory in list */
  440         if (!strcmp(dp->d_name, ".")) continue;
  441 
  442         /* record the type of file */
  443     
  444         sprintf(_STR2, "%s%s", cwdname, dp->d_name); 
  445         if (stat(_STR2, &statbuf)) continue;
  446         if ((statbuf.st_mode & S_IFDIR) != 0) /* is a directory */
  447            files[flfiles].filetype = DIRECTORY;
  448         else if (match_filter(dp->d_name, filter))
  449            files[flfiles].filetype = MATCH;
  450         else {
  451            if (xobjs.filefilter)
  452           continue;
  453            else
  454               files[flfiles].filetype = NONMATCH;
  455         }
  456 
  457         /* save the filename */
  458 
  459         files[flfiles].filename = (char *) malloc ((strlen(dp->d_name) + 
  460          ((files[flfiles].filetype == DIRECTORY) ? 2 : 1)) * sizeof(char));
  461         strcpy(files[flfiles].filename, dp->d_name);
  462         if (files[flfiles].filetype == DIRECTORY)
  463            strcat(files[flfiles].filename, "/");
  464         if (++flfiles == allocd) {
  465            allocd += INITDIRS;
  466            files = (fileliststruct *) realloc(files,
  467             allocd * sizeof(fileliststruct));
  468         }
  469          }
  470       }
  471       closedir(cwd);
  472 
  473       /* sort the files[] array into alphabetical order (like "ls") */
  474 
  475       qsort((void *)files, (size_t)flfiles, sizeof(fileliststruct), fcompare);
  476 
  477       pixheight = flfiles * FILECHARHEIGHT + 25;
  478       if (pixheight < textheight) pixheight = textheight;
  479 
  480       flistpix = XCreatePixmap(dpy, areawin->window, textwidth, pixheight,
  481        DefaultDepthOfScreen(xcScreen(w)));
  482 
  483       /* Write the filenames onto the pixmap */
  484 
  485       XSetForeground(dpy, sgc, colorlist[BACKGROUND].color.pixel);
  486       XFillRectangle(dpy, flistpix, sgc, 0, 0, textwidth, pixheight);
  487       XSetForeground(dpy, sgc, colorlist[FOREGROUND].color.pixel);
  488       for (n = 0; n < flfiles; n++) {
  489      switch (files[n].filetype) {
  490         case DIRECTORY:
  491            XSetForeground(dpy, sgc, colorlist[SELECTCOLOR].color.pixel);
  492            break;
  493         case MATCH:
  494            XSetForeground(dpy, sgc, colorlist[FILTERCOLOR].color.pixel);
  495            break;
  496         case NONMATCH:
  497            XSetForeground(dpy, sgc, colorlist[FOREGROUND].color.pixel);
  498            break;
  499      }
  500          XDrawString(dpy, flistpix, sgc, 10, 10 + FILECHARASCENT + n * FILECHARHEIGHT,
  501         files[n].filename, strlen(files[n].filename));
  502       }
  503    }
  504 
  505    /* Copy the pixmap of filenames into the file list window */
  506 
  507    XSetForeground(dpy, sgc, colorlist[BACKGROUND].color.pixel);
  508    XFillRectangle(dpy, lwin, sgc, 0, 0, textwidth, textheight);
  509    XCopyArea(dpy, flistpix, lwin, sgc, 0, flstart * FILECHARHEIGHT,
  510     textwidth, textheight, 0, 0);
  511 }
  512 
  513 /*-------------------------------------------------------------------------*/
  514 /* Generate a new pixmap for writing the filelist and set the scrollbar    */
  515 /* size accordingly.                               */
  516 /*-------------------------------------------------------------------------*/
  517 
  518 void newfilelist(xcWidget w, popupstruct *okaystruct)
  519 {
  520    short n;
  521 
  522 #ifdef TCL_WRAPPER
  523    int bval;
  524    int result;
  525    char *cstr = (char *)Tcl_GetVar2(xcinterp, "XCOps", "filter", 0);
  526    if (cstr == NULL) {
  527       Wprintf("Error: No variable $XCOps(filter) in Tcl!");
  528       return;
  529    }
  530    result = Tcl_GetBoolean(xcinterp, cstr, &bval);
  531    if (result != TCL_OK) {
  532       Wprintf("Error: Bad variable $XCOps(filter) in Tcl!");
  533       return;  
  534    }
  535    xobjs.filefilter = bval;
  536 #else
  537    xcWidget textw = okaystruct->textw;
  538 #endif
  539 
  540    for (n = 0; n < flfiles; n++)
  541       free(files[n].filename);
  542    free(files);
  543    if (flistpix != (Pixmap)NULL) XFreePixmap(dpy, flistpix);
  544    files = NULL;
  545    flistpix = (Pixmap)NULL;
  546    flstart = 0;
  547    listfiles(w, okaystruct, NULL);
  548 #ifdef TCL_WRAPPER
  549    showlscroll(Tk_NameToWindow(xcinterp, ".filelist.listwin.sb", w), NULL, NULL);
  550    Tcl_Eval(xcinterp, ".filelist.textent.txt delete 0 end");
  551    sprintf(_STR2, ".filelist.textent.txt insert 0 %s", cwdname);
  552    Tcl_Eval(xcinterp, _STR2);
  553 #else
  554    showlscroll(XtNameToWidget(xcParent(w), "LScroll"), NULL, NULL);
  555    XwTextClearBuffer(textw);
  556    XwTextInsert(textw, cwdname);
  557    XwTextResize(textw);
  558 #endif
  559 }
  560 
  561 /*-------------------------------------------------------------------------*/
  562 /* Button press handler for file list window                   */
  563 /*-------------------------------------------------------------------------*/
  564 
  565 void fileselect(xcWidget w, popupstruct *okaystruct, XButtonEvent *event)
  566 {
  567    Window lwin = xcWindow(w);
  568    Dimension textwidth, textheight;
  569    short filenum;
  570    char *tbuf, *ebuf;
  571 
  572 #ifdef TCL_WRAPPER
  573    textwidth = Tk_Width(w);
  574    textheight = Tk_Height(w);
  575 #else
  576    Arg wargs[2];
  577    short n = 0;
  578    xcWidget textw = okaystruct->textw;
  579 
  580    XtnSetArg(XtNwidth, &textwidth);
  581    XtnSetArg(XtNheight, &textheight);
  582    XtGetValues(w, wargs, n);
  583 #endif
  584 
  585    flcurrent = -1;
  586 
  587    if (files == NULL) return;   /* shouldn't happen */
  588 
  589    /* third mouse button cancels selection and reverts buffer to cwd name */
  590 
  591    if (event->button == Button3) {
  592       newfilelist(w, okaystruct);
  593       return;
  594    }
  595 
  596    filenum = (event->y - 10 + FILECHARHEIGHT) / FILECHARHEIGHT + flstart - 1;
  597    if (filenum < 0) filenum = 0;
  598    else if (filenum >= flfiles) filenum = flfiles - 1;
  599 
  600    /* Attempt to enter invalid directory. . . treat like button 3 */
  601 
  602    if (filenum < 0) {
  603       newfilelist(w, okaystruct);
  604       return;
  605    }
  606    
  607    /* check if this file is a directory or not */
  608 
  609    if (strchr(files[filenum].filename, '/') == NULL)    {
  610 
  611       /* highlight the entry. . . */
  612 
  613       XSetForeground(dpy, sgc, colorlist[AUXCOLOR].color.pixel);
  614       XDrawString(dpy, flistpix, sgc, 10, 10 + FILECHARASCENT + filenum * FILECHARHEIGHT,
  615        files[filenum].filename, strlen(files[filenum].filename));
  616       XCopyArea(dpy, flistpix, lwin, sgc, 0, flstart * FILECHARHEIGHT,
  617        textwidth, textheight, 0, 0);
  618 
  619       /* . . .and append it to the text field */
  620 
  621 #ifdef TCL_WRAPPER
  622       Tcl_Eval(xcinterp, ".filelist.textent.txt get");
  623       ebuf = (char *)Tcl_GetStringResult(xcinterp);
  624       tbuf = (char *)malloc((strlen(ebuf) +
  625         strlen(files[filenum].filename) + 6) * sizeof(char));
  626 #else
  627       ebuf = (char *)XwTextCopyBuffer(textw);
  628       tbuf = (char *)malloc((XwTextGetLastPos(textw)
  629          + strlen(files[filenum].filename) + 5) * sizeof(char));
  630 #endif
  631       strcpy(tbuf, ebuf);
  632 
  633       /* add a comma if there is already text in the destination buffer */
  634 
  635       if (tbuf[0] != '\0') {
  636          if (tbuf[strlen(tbuf) - 1] != '/') strcat(tbuf, ",");
  637       }
  638       else {
  639      if (cwdname != NULL) {
  640         if (cwdname[0] != '\0') {
  641            tbuf = (char *)realloc(tbuf, (strlen(cwdname) +
  642             strlen(files[filenum].filename) + 5) * sizeof(char));
  643            strcpy(tbuf, cwdname);
  644         }
  645      }
  646       }
  647       strcat(tbuf, files[filenum].filename);
  648 #ifdef TCL_WRAPPER
  649       Tcl_Eval(xcinterp, ".filelist.textent.txt delete 0 end");
  650       sprintf(_STR2, ".filelist.textent.txt insert 0 %s", tbuf);
  651       Tcl_Eval(xcinterp, _STR2);
  652 #else
  653       XwTextClearBuffer(textw);
  654       XwTextInsert(textw, tbuf);
  655       XwTextResize(textw);
  656 #endif
  657       free(tbuf);
  658    }
  659    else {  /* move to new directory */
  660 
  661       if (!strcmp(files[filenum].filename, "../")) {
  662          char *cptr, *sptr = cwdname;
  663      if (!strcmp(cwdname, "/")) return; /* no way up from root dir. */
  664      while(strstr(sptr, "../") != NULL) sptr += 3;
  665      if ((cptr = strrchr(sptr, '/')) != NULL) {
  666         *cptr = '\0';
  667         if ((cptr = strrchr(sptr, '/')) != NULL) *(cptr + 1) = '\0';
  668         else *sptr = '\0';
  669          }
  670      else {
  671             cwdname = (char *)realloc(cwdname, (strlen(cwdname) +
  672             4) * sizeof(char));
  673             strcat(cwdname, "../");
  674      }
  675       }
  676       else {
  677      cwdname = (char *)realloc(cwdname, (strlen(cwdname) +
  678             strlen(files[filenum].filename) + 1) * sizeof(char));
  679          strcat(cwdname, files[filenum].filename);
  680       }
  681       newfilelist(w, okaystruct);
  682    }
  683 }
  684 
  685 /*-------------------------------------------------------------------------*/
  686 /* Scrollbar handler for file list widget                  */
  687 /*-------------------------------------------------------------------------*/
  688 
  689 void showlscroll(xcWidget w, caddr_t clientdata, caddr_t calldata)
  690 {
  691    Window swin = xcWindow(w);
  692    Dimension swidth, sheight;
  693    int pstart, pheight, finscr;
  694 
  695 #ifdef TCL_WRAPPER
  696    swidth = Tk_Width(w);
  697    sheight = Tk_Height(w);
  698 #else
  699 
  700    Arg wargs[2];
  701    short n = 0;
  702 
  703    XtnSetArg(XtNwidth, &swidth);
  704    XtnSetArg(XtNheight, &sheight);
  705    XtGetValues(w, wargs, n);
  706 #endif
  707 
  708    XClearWindow(dpy, swin);
  709 
  710    if (flfiles > 0) {   /* no files, no bar */
  711 
  712       finscr = sheight / FILECHARHEIGHT;
  713       if (finscr > flfiles) finscr = flfiles;
  714 
  715       pstart = (flstart * sheight) / flfiles;
  716       pheight = (finscr * sheight) / flfiles;
  717 
  718       XSetForeground(dpy, sgc, colorlist[BARCOLOR].color.pixel);
  719       XFillRectangle(dpy, swin, sgc, 0, pstart, swidth, pheight);
  720    }
  721    flcurrent = -1;
  722 }
  723 
  724 /*-------------------------------------------------------------------------*/
  725 /* Button Motion handler for moving the scrollbar up and down          */
  726 /*-------------------------------------------------------------------------*/
  727 
  728 void draglscroll(xcWidget w, popupstruct *okaystruct, XButtonEvent *event)
  729 {
  730    Dimension sheight;
  731    int phheight, finscr, flsave = flstart;
  732    xcWidget filew = okaystruct->filew;
  733 
  734 #ifdef TCL_WRAPPER
  735    sheight = Tk_Height(w);
  736 #else
  737    Arg wargs[1];
  738    short n = 0;
  739 
  740    XtnSetArg(XtNheight, &sheight);
  741    XtGetValues(w, wargs, n);
  742 #endif
  743 
  744    finscr = sheight / FILECHARHEIGHT;
  745    if (finscr > flfiles) finscr = flfiles;
  746 
  747    /* center scrollbar on pointer vertical position */   
  748 
  749    phheight = (finscr * sheight) / (flfiles * 2);
  750    flstart = (event->y > phheight) ? ((event->y - phheight) * flfiles) / sheight : 0;
  751    if (flstart > (flfiles - finscr + 2)) flstart = (flfiles - finscr + 2);
  752 
  753    if (flstart != flsave) {
  754       showlscroll(w, NULL, NULL);
  755       listfiles(filew, okaystruct, NULL); 
  756    }
  757 }
  758 
  759 /*----------------------------------------------------------------------*/
  760 /* Set/unset the file filtering function                */
  761 /*----------------------------------------------------------------------*/
  762 
  763 #ifndef TCL_WRAPPER
  764 
  765 void setfilefilter(xcWidget w, popupstruct *okaystruct, caddr_t calldata)
  766 {
  767    xobjs.filefilter = (xobjs.filefilter) ? False : True;
  768 
  769    /* Force regeneration of the file list */
  770 
  771    newfilelist(okaystruct->filew, okaystruct);
  772 }
  773 
  774 #endif
  775 
  776 /*----------------------------------------------------------------------*/
  777 /* Generate the file list window                    */
  778 /*----------------------------------------------------------------------*/
  779 
  780 #ifdef TCL_WRAPPER
  781 
  782 void genfilelist(xcWidget parent, popupstruct *okaystruct, Dimension width)
  783 {
  784    xcWidget     listarea, lscroll, entertext;
  785 
  786    entertext = okaystruct->textw;
  787    listarea = Tk_NameToWindow(xcinterp, ".filelist.listwin.win", parent);
  788 
  789    xcAddEventHandler(listarea, ButtonPressMask, False,
  790       (xcEventHandler)fileselect, okaystruct);
  791    xcAddEventHandler(listarea, EnterWindowMask, False,
  792       (xcEventHandler)startfiletrack, NULL);
  793    xcAddEventHandler(listarea, LeaveWindowMask, False,
  794       (xcEventHandler)endfiletrack, NULL);
  795    flstart = 0;
  796    okaystruct->filew = listarea;
  797 
  798    lscroll = Tk_NameToWindow(xcinterp, ".filelist.listwin.sb", parent);
  799 
  800    Tk_CreateEventHandler(lscroll, Button1MotionMask | Button2MotionMask,
  801         (Tk_EventProc *)xctk_draglscroll, (ClientData)okaystruct);
  802 
  803    /* force new file list, in case the highlight filter changed */
  804 
  805    if (flistpix != (Pixmap)NULL) XFreePixmap(dpy, flistpix);
  806    flistpix = (Pixmap)NULL;
  807 }
  808 
  809 #else
  810 
  811 void genfilelist(xcWidget parent, popupstruct *okaystruct, Dimension width)
  812 {
  813    Arg      wargs[8];
  814    xcWidget     listarea, lscroll, entertext, dofilter;
  815    short    n = 0;
  816    int      wwidth;
  817 
  818    XtnSetArg(XtNx, 20);
  819    XtnSetArg(XtNy, FILECHARHEIGHT - 10);
  820    XtnSetArg(XtNwidth, width - SBARSIZE - 40);
  821    XtnSetArg(XtNheight, LISTHEIGHT - FILECHARHEIGHT);
  822    XtnSetArg(XtNfont, appdata.filefont);
  823 
  824    entertext = okaystruct->textw;
  825 
  826    listarea = XtCreateManagedWidget("Filelist", XwworkSpaceWidgetClass,
  827       parent, wargs, n); n = 0;
  828    XtAddCallback(listarea, XtNexpose, (XtCallbackProc)listfiles, okaystruct);
  829 
  830    xcAddEventHandler(listarea, ButtonPressMask, False,
  831       (xcEventHandler)fileselect, okaystruct);
  832    xcAddEventHandler(listarea, EnterWindowMask, False,
  833       (xcEventHandler)startfiletrack, NULL);
  834    xcAddEventHandler(listarea, LeaveWindowMask, False,
  835       (xcEventHandler)endfiletrack, NULL);
  836    flstart = 0;
  837    okaystruct->filew = listarea;
  838 
  839    XtnSetArg(XtNx, width - SBARSIZE - 20);
  840    XtnSetArg(XtNy, FILECHARHEIGHT - 10);
  841    XtnSetArg(XtNwidth, SBARSIZE);
  842    XtnSetArg(XtNheight, LISTHEIGHT - FILECHARHEIGHT);
  843    XtnSetArg(XtNfont, appdata.xcfont);
  844 
  845    lscroll = XtCreateManagedWidget("LScroll", XwworkSpaceWidgetClass,
  846          parent, wargs, n); n = 0;
  847 
  848    XtAddCallback(lscroll, XtNexpose, (XtCallbackProc)showlscroll, NULL);
  849    xcAddEventHandler(lscroll, Button1MotionMask | Button2MotionMask,
  850          False, (xcEventHandler)draglscroll, okaystruct);
  851 
  852    /* Add a toggle widget to turn file filtering on/off */
  853 
  854    wwidth = XTextWidth(appdata.xcfont, "filter", strlen("filter"));
  855    XtnSetArg(XtNx, width - wwidth - 50);
  856    XtnSetArg(XtNy, LISTHEIGHT + 10);
  857    XtnSetArg(XtNset, xobjs.filefilter);
  858    XtnSetArg(XtNsquare, True);
  859    XtnSetArg(XtNborderWidth, 0);
  860    XtnSetArg(XtNfont, appdata.xcfont);
  861    XtnSetArg(XtNlabelLocation, XwLEFT);
  862    dofilter = XtCreateManagedWidget("Filter", XwtoggleWidgetClass,
  863         parent, wargs, n); n = 0;
  864    XtAddCallback(dofilter, XtNselect, (XtCallbackProc)setfilefilter, okaystruct);
  865    XtAddCallback(dofilter, XtNrelease, (XtCallbackProc)setfilefilter, okaystruct);
  866 
  867    /* force new file list, in case the highlight filter changed */
  868 
  869    if (flistpix != (Pixmap)NULL) XFreePixmap(dpy, flistpix);
  870    flistpix = (Pixmap)NULL;
  871 }
  872 
  873 #endif  /* TCL_WRAPPER */
  874 
  875 #endif
  876 
  877 /*-------------------------------------------------------------------------*/
  878 /* Look for a directory name in a string and update cwdname accordingly    */
  879 /*-------------------------------------------------------------------------*/
  880 
  881 int lookdirectory(char *lstring, int nchars)
  882 {
  883    int slen;
  884    DIR *cwd = NULL;
  885 
  886    xc_tilde_expand(lstring, nchars);
  887    slen = strlen(lstring);
  888 
  889    if (lstring[slen - 1] == '/' || ((cwd=opendir(lstring)) != NULL)) {
  890       if (cwd) closedir(cwd);
  891       if (lstring[slen - 1] != '/') strcat(lstring, "/");
  892       cwdname = (char *)realloc(cwdname, (slen + 2) * sizeof(char));
  893       strcpy(cwdname, lstring);
  894       return(1);
  895    }
  896    return(0);
  897 }
  898 
  899 /*-------------------------------------------------------------------------*/