home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / XAP / XFILEMAN / XFILEMAN.TAR / xfilemanager / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-22  |  15.2 KB  |  686 lines

  1. /*
  2.  * Copyright 1993 by Ove Kalkan, Cremlingen, Germany
  3.  *
  4.  * Permission to use, copy, modify, distribute and sell this software and it's
  5.  * documentation for any purpose is hereby granted without fee, rpovided that
  6.  * the above copyright notice and this permission appear in supporting
  7.  * documentation, and that the name of Ove Kalkan not to be used in
  8.  * advertising or publicity pertaining to distributiopn of the software without
  9.  * specific, written prior permission. Ove Kalkan makes no representations
  10.  * about the suitability of this software for any purpose. It is provided
  11.  * as is without express or implied warranty.
  12.  *
  13.  * OVE KALKAN DISPLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  14.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABLILITY AND FITNESS, IN NO
  15.  * EVENT SHALL OVE KALKAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  16.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  17.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  18.  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  19.  * PERFORMANCE OF THIS SOFTWARE.
  20.  *
  21.  * $Header: filename,v 1.0 yyyy/mm/dd hh:mm:ss loginname Exp $
  22.  */
  23.  
  24. #define    MAIN
  25. #include "global.h"
  26.  
  27. #include "resources.h"
  28.  
  29. /*
  30.  * Globale Variablen
  31.  */
  32.  
  33.  
  34. /*
  35. **    Function name : main
  36. **
  37. **    Description :    Hauptinitialisierung
  38. **    Input :     int argc, char **argv;
  39. **    Ouput :        none
  40. */
  41. void main (int argc, char **argv)
  42. {
  43.     Arg    args[2];
  44.     Widget    but;
  45.  
  46. #ifdef    DEBUG
  47.     {
  48.         FILE    *fp;
  49.         if ((fp = fopen("xfm.debug","w"))) {
  50.             fprintf(fp,"Xfilemanager Version %s - Debugging\n",VERSION);
  51.             fclose(fp);
  52.         }
  53.     }
  54. #endif
  55.  
  56.     /*
  57.      * Den App-Context initalisieren und das ToplevelWidget holen
  58.      */
  59.     XtSetArg(args[0],XtNminWidth, 200);
  60.     XtSetArg(args[1],XtNminHeight,100);
  61.     toplevel = XtAppInitialize(&app_context,"Xfilemanager",
  62.                    options,XtNumber(options),
  63.                    &argc,argv,NULL,args,2);
  64.  
  65.     XtAppAddActions (app_context, actions, XtNumber (actions));
  66.     XtVaGetApplicationResources (toplevel,(XtPointer) &defaults,resources,
  67.                      XtNumber(resources),NULL);
  68.  
  69.     /*
  70.      * Wenn Trashcan, dann schauen ob das directory existiert
  71.      */
  72.     if (defaults.trashcan) {
  73.         struct    stat    buf;
  74.  
  75.         if (defaults.trashcan[0] == '~' && defaults.trashcan[1] == '/') {
  76.             char    s[1024];
  77.  
  78.             sprintf(s,"%s%s",getenv("HOME"),&defaults.trashcan[1]);
  79.             defaults.trashcan = (char *) malloc(strlen(s) + 1);
  80.             if (!defaults.trashcan)
  81.                 FATAL_ERROR("main: tmalloc failed");
  82.             sprintf(defaults.trashcan,"%s",s);
  83.         }
  84.         if (!lstat(defaults.trashcan,&buf) || !S_ISDIR(buf.st_mode)) {
  85.             char    s[500];
  86.             sprintf(s,"%s %s",MKDIR_CMD,defaults.trashcan);
  87.             system(s);
  88.         }
  89.     }
  90.  
  91.     /*
  92.      * Den Main-WidgetTree auf diesem Fenster erzeugen
  93.      */
  94.     if (!defaults.multi_window) {
  95.         if (!(folder = (Folder_Glyph *) malloc (sizeof(Folder_Glyph))))
  96.             FATAL_ERROR ("main: Cannot create folder\n");
  97.  
  98.         /*
  99.          * Den Main-Folder setzen
  100.          */
  101.         folder->file_count = 0;
  102.         folder->dir = &root;
  103.         folder_count = 1;
  104.         folder->file = NULL;
  105.         folder->filter = NULL;
  106.         folders[0] = folder;
  107.         folder->fs_type = FS_NORMAL;
  108.     }
  109.     createWidgets(toplevel);
  110.  
  111.     /*
  112.      * Die Usersettings fuer Filetypen einlesen und die Pixmaps
  113.      * generieren
  114.      */
  115.     readCustomSettings();
  116.  
  117.     /*
  118.      * Den Root-Glyph initialisieren
  119.      */
  120.     root.x = 0;
  121.     root.y = 0;
  122.     root.open = TRUE;
  123. #ifndef RESTRICTED_DIRS
  124.     if (!defaults.root_dir) {
  125. #endif
  126.         root.name = (String) getenv("HOME");
  127.         if (!root.name)
  128.             root.name = "/";
  129. #ifdef    RESTRICTED_DIRS
  130.     if (!strncmp(root.name,defaults.root_dir,strlen(root.name)))
  131.         root.name = defaults.root_dir;
  132. #else
  133.     }
  134.     else
  135.         root.name = defaults.root_dir;
  136. #endif
  137.     root.parent = NULL;
  138.     root.dir = NULL;
  139.     root.dir_count = 0;
  140.  
  141.     /*
  142.      * Den Status des Root-Directories holen
  143.      */
  144.     {
  145.         struct stat buf;
  146.  
  147.         (void) stat (root.name,&buf);
  148.         root.flags = getFlags(&buf);
  149.     }
  150.  
  151.     fillDir(&root);
  152.     if (folders[0])
  153.         fillFolder(folders[0]);
  154.  
  155.     /*
  156.      * Jetzt die Widgets erst einmal darstellen
  157.      */
  158.     if (!defaults.multi_window) {
  159.         Arg    args[2];
  160.  
  161.         XtSetArg(args[0],XtNwidth,100);
  162.         XtSetArg(args[1],XtNheight,100);
  163.         XtSetValues(folder->window,args,2);
  164.     }
  165.     XtRealizeWidget(toplevel);
  166.  
  167.     /*
  168.      * Die Pixmaps laden
  169.      */
  170.     if (getuid() == 0)
  171.         LoadDeviceIcons(toplevel);
  172.     loadIcons();
  173.     loadTypeIcons();
  174.     readWorkspace(&workspace,".xfmwrc");
  175.  
  176.     /*
  177.      * Das Haupmenu erweitern - muss hier geschehen, da Icons verlangt werden
  178.      */
  179.     makeIconBar(NULL,icon_bar,icon_left,FALSE,TRUE);
  180.     XtVaCreateManagedWidget("clock",clockWidgetClass, icon_bar,
  181.                 XtNwidth, 34,
  182.                 XtNheight, 34,
  183.                 XtNleft, XawChainRight,
  184.                 XtNright, XawChainRight,
  185.                 XtNtop, XawChainTop,
  186.                 XtNbottom, XawChainBottom,
  187.                 XtNhorizDistance, (defaults.multi_window ? 360 : 860),
  188.                 XtNshapeWindow, FALSE,
  189.                 NULL);
  190.  
  191.     /*
  192.      * Auf der Form 2 Buttons fuer Edit und Delete einrichten
  193.      */
  194.     but = XtVaCreateManagedWidget("wse_but", iconBWidgetClass, ws_bar,
  195.                     XtNleft, XawChainLeft,
  196.                     XtNright, XawChainLeft,
  197.                     XtNbottom, XawChainTop,
  198.                     XtNtop, XawChainTop,
  199.                     XtNimageWidth, 32,
  200.                     XtNimageHeight, 32,
  201.                     XtNimage, Icon_WSE_PM,
  202.                     NULL);
  203.     XtAddCallback(but,XtNcallback,(XtCallbackProc) start_WSedit,NULL);
  204.  
  205.     but = XtVaCreateManagedWidget("wsd_but", iconBWidgetClass, ws_bar,
  206.                     XtNleft, XawChainLeft,
  207.                     XtNright, XawChainLeft,
  208.                     XtNbottom, XawChainTop,
  209.                     XtNtop, XawChainTop,
  210.                     XtNfromHoriz, but,
  211.                     XtNimageWidth, 32,
  212.                     XtNimageHeight, 32,
  213.                     XtNimage, Icon_WSD_PM,
  214.                     NULL);
  215.     XtAddCallback(but,XtNcallback,(XtCallbackProc) start_WSdelete,NULL);
  216.  
  217.     /*
  218.      * Die GC's zum Zeichnen des Dir-Trees initialisieren
  219.      */
  220.     {
  221.         XtGCMask    mask;
  222.         XGCValues    values;
  223.         Arg        args[1];
  224.  
  225.         mask = GCFont | GCForeground;
  226.         values.font = defaults.icon_font->fid;
  227.         values.foreground = XBlackPixel (XtDisplay(toplevel),
  228.                          XDefaultScreen(XtDisplay(toplevel)));
  229.         line_gc = XtGetGC (toplevel, mask, &values);
  230.  
  231.         XtSetArg(args[0],XtNbackground,&values.foreground);
  232.         XtGetValues(toplevel,args,1);
  233.         back_gc = XtGetGC (toplevel, mask, &values);
  234.  
  235.         values.foreground = XWhitePixel (XtDisplay(toplevel),
  236.                          XDefaultScreen(XtDisplay(toplevel)));
  237.         white_gc = XtGetGC (toplevel, mask, &values);
  238.  
  239.         values.foreground = defaults.select_color;
  240.         selc_gc = XtGetGC (toplevel, mask, &values);
  241.     }
  242.     XtManageChild(dir_area);
  243.     XtManageChild(workspace.window);
  244.  
  245.     if (!defaults.multi_window) {
  246.         Arg    args[2];
  247.         char    *s = getPath(folder->dir);
  248.  
  249.         XtSetArg(args[0],XtNwidth,100);
  250.         XtSetArg(args[1],XtNheight,100);
  251.         XtSetValues(folder->window,args,2);
  252.         XtManageChild(folder->window);
  253.         XtSetArg(args[0],XtNlabel,(*s == '\0' ? "/" : s));
  254.         XtSetValues(folder->label,args,1);
  255.  
  256.     }
  257.     else {
  258.         XtWidgetGeometry    a,b;
  259.  
  260.         a.width = workspace.fw;
  261.         a.height = workspace.fh;
  262.         a.x = workspace.fx;
  263.         a.y = workspace.fy;
  264.         a.request_mode = CWWidth | CWHeight | CWX | CWY;
  265.         XtMakeGeometryRequest(workspace.shell,&a,&b);
  266.  
  267.         XtManageChild(workspace.shell);
  268.     }
  269.     /*
  270.      * Den Default Cursor setzen
  271.      */
  272.     makeCursor();
  273.  
  274.     XDefineCursor(XtDisplay(dir_area),XtWindow(dir_area), def_cursor);
  275.     XDefineCursor (XtDisplay(workspace.window), 
  276.             XtWindow(workspace.window), def_cursor);
  277.     if (!defaults.multi_window)
  278.         XDefineCursor(XtDisplay(folder->window),
  279.                 XtWindow(folder->window), def_cursor);
  280.     folder = NULL;
  281.  
  282. #ifdef    HAS_QUOTA
  283.     showQuota(quota_label);
  284. #endif
  285.  
  286.     signal(SIGCHLD, signal_handler);
  287.     /*
  288.      * Der Main-Loop
  289.      */
  290.     XtAppMainLoop(app_context);
  291. }
  292.  
  293.  
  294. MYSIGTYPE    signal_handler(int sig)
  295. {
  296.     while (waitpid(-1,NULL,WNOHANG) > 0);
  297.     signal(SIGCHLD, signal_handler);
  298. }
  299.  
  300.  
  301. /*
  302. **    Function name : createWidgets
  303. **
  304. **    Description :    Diese Funktion erzeugt ein Directoryfenster
  305. **    Input :        Widget    parent;    Zeiger auf das Parentwidget
  306. **    Ouput :        none
  307. */
  308. void createWidgets (Widget parent)
  309. {
  310.     Arg    args[12];
  311.     Widget    field_pane,
  312.         dir_pane,
  313.         dummy,
  314.         viewport,
  315.         dev_box,
  316.         main_pane;
  317.     
  318.     
  319.     /*
  320.      * Zunaechst erst einmal den main-pane erzeugen
  321.      */
  322.     main_pane = XtCreateManagedWidget("main_pane", panedWidgetClass,
  323.                       parent, args,0);
  324.  
  325.     /*
  326.      * Das Haupmenu ergaenzen
  327.      */
  328.     makeMenu (main_pane);
  329.  
  330.     /*
  331.      * Die Seperator-pane fuer die Directoryfields setzen
  332.      */
  333.     if (!defaults.multi_window) {
  334.         XtSetArg(args[0],XtNorientation, XtorientHorizontal);
  335.         field_pane = XtCreateManagedWidget("field_pane", panedWidgetClass,
  336.                            main_pane, args,1);
  337.         XtSetArg(args[0],XtNwidth,300);    /* Bei Single Window hat die
  338.                            Iconbar Oben genug Platz */
  339.     }
  340.     else {
  341.         field_pane = main_pane;
  342.         XtSetArg(args[0],XtNwidth, 400);
  343.     }
  344.  
  345.     /*
  346.      * Unter der Dir-Area muss noch ein Feld fuer die Quotas stehen, darum
  347.      * pane erzeugen
  348.      */
  349.     dir_pane = XtVaCreateManagedWidget ("dir_pane",formWidgetClass,
  350.                         field_pane,
  351.                         XtNdefaultDistance, 0,
  352.                         NULL);
  353.  
  354.     /*
  355.      * Auf dieses field_pane jetzt den Viewport setzen, der das
  356.      * Simple-Widget fuer den Directory-Tree enthalten soll
  357.      */
  358.     
  359.     XtSetArg(args[1],XtNheight,480);
  360.     XtSetArg(args[2],XtNallowHoriz, TRUE);
  361.     XtSetArg(args[3],XtNallowVert, TRUE);
  362.     XtSetArg(args[4],XtNforceBars, TRUE);
  363.     XtSetArg(args[5],XtNuseBottom, TRUE);
  364.     XtSetArg(args[6],XtNuseRight, TRUE);
  365.     XtSetArg(args[7],XtNleft, XawChainLeft);
  366.     XtSetArg(args[8],XtNright, XawChainRight);
  367.     XtSetArg(args[9],XtNbottom, XawChainBottom);
  368.     XtSetArg(args[10],XtNtop,XawChainTop);
  369.     viewport = XtCreateManagedWidget("viewport", viewportWidgetClass,
  370.                      dir_pane, args,11);
  371.     dir_vp = viewport;
  372.  
  373.     /*
  374.      * Auf das Viewport kommt jetzt das Simple-Widget fuer den
  375.      * Directory Tree
  376.      */
  377.     dir_area = XtCreateWidget("dir_simple", simpleWidgetClass,
  378.                   viewport, args, 2);
  379.     XtOverrideTranslations(dir_area, 
  380.                    XtParseTranslationTable("<Leave>: leave-window()\n\
  381.                             <Enter>: enter-window()\n\
  382.                                 <Expose>: refresh-dirs()\n\
  383.                             <Btn3Down>: start-popup()\n\
  384.                             <Btn1Down>: clear-multi() start-single()\n\
  385.                                 <Btn1Motion>: follow-single()\n\
  386.                                 <Btn1Up>: end-single()"));
  387.     /*
  388.      * Den Quota_label erzeugen
  389.      */
  390.     if (getuid() == 0)
  391.         dev_box = CreateDeviceBox(dir_pane,viewport);
  392. #ifdef    HAS_QUOTA
  393.     else
  394.         quota_label = XtVaCreateManagedWidget("quota_label",labelWidgetClass,
  395.                         dir_pane,
  396.                         XtNfromVert,dir_vp,
  397.                         XtNborderWidth,0,
  398.                         XtNleft, XawChainLeft,
  399.                         XtNright, XawChainRight,
  400.                         XtNtop, XawChainBottom,
  401.                         XtNbottom, XawChainBottom,
  402.                         XtNjustify, XtJustifyLeft,
  403.                         XtNwidth, (defaults.multi_window ? 400 : 300),
  404.                         NULL);
  405. #endif
  406.     /*
  407.      * Den ersten Folder ersellen, je nach Status der Default-Variable
  408.      * im Pane in einem eigenen Fenster
  409.      */
  410.     if (!defaults.multi_window) {
  411.         dummy = field_pane;
  412.         /*
  413.          * Den Folder erzeugen
  414.          */
  415.         makeFolderWindow (dummy, folder,0);
  416.         makeWorkspaceWindow (dummy, &workspace);
  417.     }
  418.     else {
  419.         Widget    shell;
  420.  
  421.         shell = XtVaCreatePopupShell("ws_shell",topLevelShellWidgetClass,
  422.                        toplevel, XtNtitle,"Workspace",NULL);
  423.         makeWorkspaceWindow (shell, &workspace);
  424.     }
  425. }
  426.  
  427.  
  428.  
  429. /*
  430. **    Function name : FATAL_ERROR
  431. **
  432. **    Description : Bricht im Fehlerfall mit einer Fehlermeldung ab
  433. **    Input : 
  434. **    Ouput :
  435. */
  436. void FATAL_ERROR (char *message)
  437. {
  438.     fprintf(stderr,"%s",message);
  439.     exit(1);
  440. }
  441.  
  442.  
  443.  
  444. /*
  445. **    Function name : refresh_files
  446. **
  447. **    Description : Neuzeichnen des Directories nach einem Expose
  448. **    Input : none
  449. **    Ouput : none
  450. */
  451. XtActionProc refresh_files (Widget w, XExposeEvent *e, String *s, Cardinal *c)
  452. {
  453.     Dimension    lx = 0, ly;
  454.     Arg        args[4];
  455.     int        hs, he;
  456.     Folder_Glyph    *rfolder;
  457.  
  458.     while (lx < folder_count && lx < MAX_FOLDERS && folders[lx]->window != w)
  459.         lx++;
  460.  
  461.     if (lx < folder_count) {
  462.         rfolder = folders[lx];
  463.  
  464.         /*
  465.          * Directorypfad neu Zeichnen
  466.          */
  467.         if (FILE_CHANGED) {
  468.             XClearWindow(XtDisplay(rfolder->window),
  469.                      XtWindow(rfolder->window));
  470.             FILE_CHANGED = FALSE;
  471.             if (!defaults.multi_window)
  472.                 XtMoveWidget(rfolder->window,0,0);
  473.         }
  474.         /*
  475.          * Berechnen, welche Eintrage gerade sichtbar sind und eines Refreshs
  476.          * beduerfen. Die derzeitige Loesung koennte Probleme bei Terminals
  477.          * mit Backingstores geben.
  478.          */
  479.         if (!e){
  480.             hs = 0;
  481.             he = rfolder->file_count - 1;
  482.         }
  483.         else {
  484.             hs = (e->y - 4) / DIR_Y_STEP;
  485.             if (hs < 0)
  486.                 hs = 0;
  487.             he = hs + e->height/DIR_Y_STEP + 1;
  488.             if (he > rfolder->file_count - 1)
  489.                 he = rfolder->file_count - 1;
  490.         }
  491.         showFolder (rfolder->window, rfolder, 20, 6, &lx, &ly, hs, he);
  492.  
  493.         /*
  494.          * Die Hoehe anpassen
  495.          */
  496.         {
  497.             Arg        args[2];
  498.  
  499.             XtSetArg(args[0],XtNwidth,lx + 2*DIR_Y_STEP + typelength);
  500.             XtSetArg(args[1],XtNheight, ly + 2*DIR_Y_STEP);
  501.             XtSetValues(rfolder->window,args,2);
  502.         }
  503.     }
  504. }
  505.  
  506.  
  507.  
  508. /*
  509. **    Function name : refresh_dirs
  510. **
  511. **    Description : Neuzeichnen des Directories nach einem Expose
  512. **    Input : none
  513. **    Ouput : none
  514. */
  515. XtActionProc refresh_dirs (Widget w, XExposeEvent *e, String *s, Cardinal *c)
  516. {
  517.     Dimension    lx = 0, ly;
  518.     int        hs,he;
  519.  
  520.     /*
  521.      * Directorypfad neu Zeichnen
  522.      */
  523.     if (DIR_CHANGED) {
  524.         DIR_CHANGED = FALSE;
  525.         XClearWindow(XtDisplay(dir_area),XtWindow(dir_area));
  526.     }
  527.     /*
  528.      * Berechnen, welche Eintrage gerade sichtbar sind und eines Refreshs
  529.      * beduerfen. Die derzeitige Loesung koennte Probleme bei Terminals
  530.      * mit Backingstores geben.
  531.      */
  532.     if (!e) {
  533.         hs = 0;
  534.         he = 16000;
  535.     }
  536.     else {
  537.         hs = e->y - DIR_Y_STEP;
  538.         if (hs < 0)
  539.             hs = 0;
  540.  
  541.         he = hs + e->height + 2*DIR_Y_STEP;
  542.     }
  543.  
  544.     showDir (dir_area, &root, 20, 6, &lx, &ly,hs,he);
  545.  
  546.     /*
  547.      * Die Hoehe anpassen
  548.      */
  549.     {
  550.         Arg        args[2];
  551.  
  552.         XtSetArg(args[0],XtNwidth,lx + 2*DIR_Y_STEP);
  553.         XtSetArg(args[1],XtNheight, ly + 2*DIR_Y_STEP);
  554.         XtSetValues(dir_area,args,2);
  555.     }
  556. }
  557.  
  558.  
  559.  
  560.  
  561.  
  562.  
  563. /*
  564. **    Function name : getGlyph
  565. **
  566. **    Description : Prueft, ob an den Koordinaten x,y ein Glyph liegt
  567. **    Input : Dir_Glyph Root; Position x,y
  568. **    Ouput :
  569. */
  570. Dir_Glyph *getGlyph (Dir_Glyph *d, Dimension x, Dimension y)
  571. {
  572.     /*
  573.      * Pruefen ob Punkt ueberhaupt im Bereich liegen kann
  574.      */
  575.     if (y < d->y || x < d->x)
  576.         return(NULL);
  577.  
  578.     /*
  579.      * Pruefen ob das Icon das an dieser Position liegt
  580.      */
  581.     if ( y < d->y + 16 && x < d->x + 24 + 8*strlen(d->name))
  582.         return(d);
  583.  
  584.     /*
  585.      * Das Stammglyph war es nicht, also Verzeichnis durchsuchen
  586.      */
  587.     if (d->dir_count > 0 && d->open) {
  588.         int    i;
  589.  
  590.         /*
  591.          * alle Glyphs durchprobieren
  592.          */
  593.         for (i = 0; i < d->dir_count; i++) {
  594.             Dir_Glyph    *b;
  595.  
  596.             b = getGlyph(d->dir[i],x,y);
  597.             if (b != NULL)
  598.                 return(b);
  599.         }
  600.     }
  601.     return(NULL);
  602. }
  603.  
  604.  
  605.  
  606. #ifdef    HAS_QUOTA
  607. /*********************************************************
  608.  * name:    showQuota
  609.  * description:    Anzeigen der Userquotas
  610.  * input:    Widget w - Quota-Label
  611.  * output:    none
  612.  * author:    Ove Kalkan
  613.  * date:    20.7.1993
  614.  *********************************************************/
  615. void    showQuota(Widget w)
  616. {
  617.     uid_t    uid = getuid();
  618.     Arg    args[1];
  619. #if defined(hpux) || defined(ultrix)
  620.     struct dqblk    addr;
  621. #endif
  622.     if (uid == 0)
  623.         return;
  624. #if defined(hpux) || defined(ultrix)
  625.     if (quotactl(Q_GETQUOTA,QUOTA_DEV,
  626.             uid, (void *) &addr))
  627. #else
  628.     if (1)
  629. #endif
  630. #ifdef    DEUTSCH
  631.         XtSetArg(args[0],XtNlabel,"Keine Beschraenkungen");
  632. #else
  633.         XtSetArg(args[0],XtNlabel,"Cannot get Quotas");
  634. #endif
  635.     else {
  636.         char    s[200];
  637. #if defined(hpux) || defined(ultrix)
  638. #ifdef    DEUTSCH
  639.         sprintf(s,"Beschraenkung: %d von %d Bloecken",
  640. #else
  641.         sprintf(s,"Quotas: %d of %d Blocks",
  642. #endif
  643.             addr.dqb_curblocks,
  644.                 addr.dqb_bsoftlimit);
  645. #endif
  646.         XtSetArg(args[0],XtNlabel,s);
  647.     }
  648.     XtSetValues(w,args,1);
  649. }
  650.  
  651. #endif
  652.  
  653.  
  654. #ifdef HAS_NO_STRRSTR
  655. /*
  656.  * This function is missing in libc.so.4.4.1 on linux systems,
  657.  */
  658. char    *strrstr (char *vs, char *ve)
  659. {
  660.     register u_int    i = strlen(ve);
  661.     register u_int    j = strlen(vs);
  662.     register u_int    h;
  663.  
  664.     if (i > j)
  665.         return(NULL);
  666.     for (h = j - i; h; h--) {
  667.         if (!strncmp(vs+h,ve,i))
  668.             return(vs+h);
  669.     }
  670.     return(NULL);
  671. }
  672. #endif
  673.  
  674.  
  675. #ifdef DEBUG
  676. void    debug (const char *format, __va_list list)
  677. {
  678.     FILE    *fp;
  679.  
  680.     if (!(fp = fopen("xfm.debug","a")))
  681.         return;
  682.     fprintf(fp,format,list);
  683.     fclose(fp);
  684. }
  685. #endif
  686.