home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / flistfrontend / src / fl.c < prev    next >
C/C++ Source or Header  |  1995-10-27  |  21KB  |  801 lines

  1. #ifndef NO_IDENT
  2. static char *Id = "$Id: fl.c,v 1.24 1995/10/27 21:30:44 tom Exp $";
  3. #endif
  4.  
  5. /*
  6.  * Title:    flist.c (FLIST main program)
  7.  * Author:    T.E.Dickey
  8.  * Created:    31 Apr 1984
  9.  * Last update:
  10.  *        26 Oct 1995, err in stdarg conversion
  11.  *        22 Oct 1995, DEC-C clean-compile.  Added seconds to "/dlong".
  12.  *        28 May 1995, use stdarg instead of VARARGS hack.
  13.  *        18 Mar 1995, prototypes
  14.  *        18 Feb 1995, port to AXP (DATENT mods, renamed 'alarm')
  15.  *        28 Feb 1989, log 132-wide messages instead of 80.
  16.  *        23 Feb 1989, use 'flist_chdir()'
  17.  *        04 Nov 1988, added expired-date
  18.  *        05 Oct 1985, added key-argument to 'flist_help'
  19.  *        17 Aug 1985, make 'flist_log' a write-thru from 'flist_lis'
  20.  *        14 Aug 1985, added code to make '?FIND' nested.
  21.  *        31 Jul 1985, added call on 'fledit_pack'.  Restrict subset-options
  22.  *                 to exclude anything modifying XAB's in 'dirent'.
  23.  *        28 Jul 1985, 'getenv' does not appear to return a value when
  24.  *                 running from DEC/shell.
  25.  *        25 Jul 1985, added 'flist_lis' to open/write/close to listing
  26.  *                 file used for '?READ'.
  27.  *        24 Jul 1985, show invocation on /LOG.  Make D_opt inherit properly
  28.  *                 when we do recursion.
  29.  *        23 Jul 1985, separated out options-code for use by EDIT command.
  30.  *        05 Jul 1985, modified calls on 'dirpath_init/free' to make a
  31.  *                 single structured character heap via 'nameheap'.
  32.  *        03 Jul 1985, cleanup 'filelist' definitions.
  33.  *        23 Jun 1985, if cannot enter level, set 'multi_quit'.
  34.  *        15 Jun 1985, use '&' in 'opts[]' declaration for CC2.0,
  35.  *                 typed 'dclarea', 'ropen2'.
  36.  *        14 Jun 1985, call it '/SINCE' instead of '/AFTER'.  Provide
  37.  *                 alternate names /BACKUP, /CREATED, /MODIFIED
  38.  *                 for /DB, /DC, /DR.
  39.  *        13 Jun 1985, added '/AFTER', '/BEFORE' options
  40.  *        24 May 1985, corrected 'flset_mark', 'flset_hold' 'NO' tests
  41.  *        12 May 1985, corrected 'flset_date' switch
  42.  *        05 May 1985, chopped out the no-argument commands to leave them
  43.  *                 solely under control of 'dircmd' module.  The
  44.  *                 'flset_' stuff here is merely a remnant.
  45.  *        13 Apr 1985, set default-for /COMMAND, added '/LOG'.
  46.  *        08 Apr 1985, added /COMMAND option via 'getraw'
  47.  *        30 Mar 1985, added '?MEMORY' display command.
  48.  *        28 Mar 1985, provided conventional error-return point
  49.  *        21 Mar 1985, moved help-code into 'crt_help'.  Also, added "-1"
  50.  *                 interpretation to 'D_mode' (/DS, /DL) to allow a
  51.  *                 very-short date format.
  52.  *        14 Mar 1985, modified help-file search to account for system
  53.  *                 installation.
  54.  *        03 Mar 1985, do flcols-init only once (hierarchical-inherit)
  55.  *        08 Feb 1985, check for limit to nesting-level
  56.  *        02 Feb 1985, use scrolling-margins
  57.  *        01 Feb 1985, broke 'dirread' from 'dirpath'.
  58.  *        14 Jan 1985, altered 'DCLOPT' init-data
  59.  *        10 Jan 1985, had wrong default for '/OWNER'
  60.  *        08 Jan 1985, renamed '/BACKUP' to '/DBACKUP', etc.
  61.  *        02 Jan 1985, use ^Z for quit-command.
  62.  *        30 Dec 1984, make clean call to 'flmore' for current-entry.
  63.  *        29 Dec 1984, added '/mark', '/nomark' to avoid keypad dependency.
  64.  *        24 Dec 1984, added 'D_mode' to drive day-of-week display.
  65.  *        22 Dec 1984, show allocation in "?SIZE"
  66.  *        21 Dec 1984, added 'flist_sysmsg'.
  67.  *        19 Dec 1984, moved 'cmdstk' init here, for hierarchy.
  68.  *        11 Dec 1984, added "?QUOTA".  No "HOURS" option (implicit).
  69.  *        03 Dec 1984, use 'whoami'.
  70.  *        22 Oct 1984, added figure-of-merit (sysfom)
  71.  *        17 Oct 1984, do refresh in 'dircmd'
  72.  *        10 Sep 1984, got rid of <stdio>
  73.  *        03 Sep 1984, use "import"
  74.  *        30 Aug 1984, need at least 6 args in VARARGS
  75.  *        28 Aug 1984, cleanup buffer sizes, added '?'-prefix commands
  76.  *        15 Aug 1984, added date-display toggles (/dcreated, etc.)
  77.  *        14 Aug 1984, added 'warn2' entry
  78.  *        06 Aug 1984, added options BACKUP, REVISED and HOURS
  79.  *        27 Jul 1984, use 'dirpath_free'
  80.  *        25 Jul 1984, added 'cmd_arg' to 'dclarg()', added 'verify'
  81.  *        17 Jul 1984, fixed default on VERSIONS option
  82.  *        14 Jul 1984, use DCLOPT for option parsing
  83.  *        09 Jul 1984, fix kludgey 'more' interface.
  84.  *        30 Jun 1984, removed EDIT/VIEW function entirely to 'fledit'
  85.  *        26 Jun 1984
  86.  *
  87.  * Function:    This program provides screen-oriented directory editing
  88.  *        functions (rename, delete, change protection), combined
  89.  *        with wildcard selection, and sorting on all visible
  90.  *        attributes.  The program design is influenced by the EDT
  91.  *        editor, the DIRED program on Unix, and the FLIST program
  92.  *        on IBM CMS.
  93.  */
  94.  
  95. #define DIRENT
  96.  
  97. #include    <stdlib.h>
  98. #include    <stdio.h>
  99. #include    <unixio.h>
  100. #include    <unixlib.h>    /* for 'getcwd()' */
  101. #include    <signal.h>    /* for 'sleep()' */
  102. #include    <stdarg.h>
  103. #include    <string.h>
  104. #include    <ctype.h>
  105. #include    <descrip.h>
  106. #include    <stsdef.h>
  107.  
  108. #include    "cmdstk.h"
  109. #include    "getpad.h"
  110. #include    "dclarg.h"        /* FIXME */
  111. #include    "flist.h"
  112. #include    "rmsio.h"
  113. #include    "whoami.h"
  114.  
  115. #include    "dds.h"
  116. #include    "dirent.h"
  117. #include    "dircmd.h"
  118. #include    "dirpath.h"
  119. #include    "dirread.h"
  120. #include    "dclopt.h"
  121.  
  122. #include    "getraw.h"
  123. #include    "freelist.h"
  124. #include    "nameheap.h"
  125. #include    "strutils.h"
  126. #include    "sysutils.h"
  127.  
  128. #undef  EXIT_SUCCESS
  129. #undef  EXIT_FAILURE
  130.  
  131. #define    EXIT_FAILURE    (STS$M_INHIB_MSG | STS$K_ERROR)
  132. #define    EXIT_SUCCESS    (STS$M_INHIB_MSG | STS$K_SUCCESS)
  133.  
  134. /*
  135.  * External data:
  136.  */
  137. import(filelist); import(numfiles);
  138. import(AnyXAB);
  139. import(A_opt);    import(D_opt);    import(M_opt);
  140. import(O_opt);    import(P_opt);    import(V_opt);
  141. import(D_mode);
  142. import(dateflag);    import(datechek);
  143.  
  144. import(filelink);
  145. import(pathlist);
  146. import(readlist);
  147. import(readllen);
  148.  
  149. static    void    FlistTellVA (char *format, va_list ap);
  150. static    void    FlistInfoVA (char *format, va_list ap);
  151.  
  152. /*
  153.  * Local (static) data:
  154.  */
  155. static
  156. int    beep_flag,    warn_flag,
  157.     hold_flag,    nesting_lvl,    did_crt_init = FALSE;
  158. static
  159. char    dftspec[] = "*.*;*";
  160.  
  161. /*
  162.  * Options:
  163.  *    AFTER        Append to display-list only files with dates *after*
  164.  *    BEFORE        Append to display-list only files with dates *before*
  165.  *    COMMAND        Read commands from a file until EOF, then terminal
  166.  *    DBACKUP        Show backup dates instead of creation dates
  167.  *    DREVISED    Show file revision dates instead of creation dates
  168.  *    DEXPIRED    Show file expriation dates instead of creation dates
  169.  *    FAST        Suppress all fields other than the filename (*3 faster)
  170.  *    LOG        Record commands and error messages
  171.  *    NOALL        Suppress filename if no privilege for other data
  172.  *    NODATE        Suppress creation-date+time
  173.  *    NOOWNER        Suppress display of owner code
  174.  *    NOPROTECTION    Suppress display of protection mask
  175.  *    NOSIZE        Suppress allocation (size) data
  176.  *    NOVERSIONS    Show only highest version of each file
  177.  */
  178. static
  179. int    _FALSE    = FALSE,
  180.     _TRUE    = TRUE,
  181.     Xfast,    D_opt1, D_opt2,    D_opt3, D_opt4;
  182.  
  183. #define    COMMAND_    "command"
  184. #define    LOG_        "log"
  185.  
  186. static    int    H_opt;
  187.  
  188. static    RFILE    *LisRAB;
  189. static    RFILE    *LogRAB;
  190.  
  191. static    char    *LogFile;
  192. static    char    *CmdFile;
  193. static    char    LogDft[] = "SYS$LOGIN:FLIST.LOG",
  194.         CmdDft[] = "SYS$LOGIN:FLIST.CMD",
  195.         LisFile[]= "SYS$LOGIN:FLIST.LIS";
  196.  
  197. #define    SZ(n)    &n,sizeof(n)
  198. static
  199. DCLOPT    opts[] = {
  200.     {"fast",    &_FALSE,0,    SZ(Xfast),    1,    00017},
  201.     {COMMAND_,    0,    CmdDft,    0,0,        1,    00200},
  202.     {LOG_,        0,    LogDft,    0,0,        1,    00400},
  203.     {"date",    &D_opt,    0,    SZ(D_opt1),    1,    00001},
  204.     {"owner",    &_TRUE,    0,    SZ(O_opt),    1,    00002},
  205.     {"protection",    &_TRUE,    0,    SZ(M_opt),    1,    00004},
  206.     {"size",    &_TRUE,    0,    SZ(A_opt),    3,    00010},
  207. #define    SUBOPT    7
  208.     /* * * * * * end-of-subset-options * * * * * */
  209.     {"after",    0,    0,    SZ(datechek),    2,    01000},
  210.     {"all",        &_TRUE,    0,    SZ(P_opt),    1,    00100},
  211.     {"backup",    &_FALSE,0,    SZ(D_opt2),    2,    00001},
  212.     {"before",    0,    0,    SZ(datechek),    2,    01000},
  213.     {"created",    &D_opt,    0,    SZ(D_opt1),    1,    00001},
  214.     {"dbackup",    &_FALSE,0,    SZ(D_opt2),    2,    00001},
  215.     {"drevised",    &_FALSE,0,    SZ(D_opt3),    2,    00001},
  216.     {"dexpired",    &_FALSE,0,    SZ(D_opt4),    2,    00001},
  217.     {"help",    &_FALSE,0,    SZ(H_opt),    1,    07777},
  218.     {"modified",    &_FALSE,0,    SZ(D_opt3),    1,    00001},
  219.     {"since",    0,    0,    SZ(datechek),    3,    01000},
  220.     {"versions",    &_TRUE,    0,    SZ(V_opt),    1,    00400}
  221.     };
  222.  
  223. int    main (int argc, char **argv)
  224. {
  225.     DCLARG    *arg_    = argvdcl (argc, argv, dftspec, 0);
  226.     char    *path_    = getenv("PATH");
  227.  
  228.     CmdFile    = dclarea (COMMAND_,    MAX_PATH, (DCLOPT *)&opts, sizeof(opts));
  229.     LogFile    = dclarea (LOG_,    MAX_PATH, (DCLOPT *)&opts, sizeof(opts));
  230.     D_opt    = TRUE;        /* set default so we can inherit it    */
  231.  
  232.     if (dclchk (arg_, 0))                return(EXIT_FAILURE);
  233.     if (flist_opts (argc, argv, arg_, FALSE))    return(EXIT_FAILURE);
  234.  
  235.     sysfom (nullC);        /* Initialize timer            */
  236.  
  237.     nesting_lvl = 0;
  238.     hold_flag = FALSE;
  239.     crt_init (0);
  240.     did_crt_init = TRUE;
  241.     crt_margin (1, crt_lpp()-1);
  242.     flcols_init();        /* initialize set of columns to display    */
  243.     dircmd_init();        /* Initialize command processor        */
  244.     flist (arg_);        /* Perform root-level call (wildcards)    */
  245.     freelist (arg_);    /* Release argument list        */
  246.     if (path_)
  247.         flist_chdir (path_);/* restore original working directory    */
  248.     flist_quit (EXIT_SUCCESS);
  249. }
  250.  
  251. /*
  252.  * Set default directory.
  253.  */
  254. void    flist_chdir(char *path)
  255. {
  256.     static    char    old_path[MAX_PATH];
  257.     auto    char    new_path[MAX_PATH];
  258.  
  259.     chdir(path);
  260.     getcwd(new_path, sizeof(new_path));
  261.     if (strcmp(old_path, new_path)) {
  262.         if (strcmp(new_path, path))
  263.             flist_log("! asked %s", path);
  264.         flist_log("! chdir %s", strcpy(old_path, new_path));
  265.     }
  266. }
  267.  
  268. /*
  269.  * Common error/normal exit point:
  270.  */
  271. void    flist_quit (int status)
  272. {
  273.     if (did_crt_init)
  274.         crt_quit (TRUE);    /* Make a clean exit        */
  275.     exit (status);
  276. }
  277.  
  278. void    flist (DCLARG *dcl_)
  279. {
  280.     int    curfile = 0;
  281.     int    Quit    = FALSE;
  282.     CMDSTK    *cmdstk_ = cmdstk_init();
  283.  
  284.     flfind_init (nesting_lvl);
  285.     clrwarn();
  286.     filelist = 0;
  287.     if (Quit = (++nesting_lvl > 8))
  288.         warn ("Too many display levels");
  289.     else
  290.     {
  291.         dirpath_init (nesting_lvl);
  292.         dirent (dcl_);        /* Read directory    */
  293.         if (Quit = (numfiles <= 0))
  294.             warn ("No files found");
  295.         else
  296.         {
  297.             fledit_pack ();    /* We got to a new level    */
  298.             dds_all(0, curfile);
  299.         }
  300.     }
  301.     if (Quit)    sleep (3);    /* Make sure we see fatal message */
  302.     else        dircmd();    /* Loop, executing all commands    */
  303.  
  304.     /*
  305.      * Release subdirectory storage and miscellaneous lists.  'filelist'
  306.      * is initialized only if we have successfully executed a directory
  307.      * read via 'dirent'.
  308.      *
  309.      * Note: 'dcl_' is free'd on return to 'dircmd' or main program.
  310.      */
  311.     if (filelist)
  312.     {
  313.         cfree (filelist);
  314.         dirread_free ();
  315.     }
  316.  
  317.     cmdstk_free(cmdstk_);    /* ...and command history    */
  318.     dirpath_free (nesting_lvl);
  319.     nameheap_set (--nesting_lvl);
  320. }
  321.  
  322. /*
  323.  * Move the cursor to a new line.  If no actual movement results, flag an
  324.  * error message so that the user will know what happened.
  325.  */
  326. void    flist_move (int *curfile_, int ref, int code)
  327. {
  328.     int    old = *curfile_;
  329.     *curfile_ = dds_move (ref, code);
  330.     if ((ref == old) && (old == *curfile_) && (code /* 2's comp */ & 1))
  331.         warn ((code < 0) ? "Already at top" : "No more files");
  332. }
  333.  
  334. /*
  335.  * Make the 'hold'-flag visible to external world (see: 'dds_hold()').
  336.  */
  337. int    flist_hold(void)
  338. {
  339.     return (hold_flag);
  340. }
  341.  
  342. tDIRCMD(flset_hold)
  343. {
  344.     hold_flag = (xcmd_[1] != 'n');
  345. }
  346.  
  347. /*
  348.  * Set/clear selection-mark:
  349.  */
  350. tDIRCMD(flset_mark)
  351. {
  352.     dircmd_select (xcmd_[1] == 'n' ? -1 : *curfile_);
  353. }
  354.  
  355. /*
  356.  * Set flags controlling data-display:
  357.  */
  358. tDIRCMD(flset_date)
  359. {
  360.     switch (xcmd_[2])
  361.     {
  362.     case 's':    D_mode--; flist_date2 (*curfile_);    break;
  363.     case 'l':    D_mode++; flist_date2 (*curfile_);    break;
  364.     case 'b':    flist_date (*curfile_, 2);    break;
  365.     case 'r':    flist_date (*curfile_, 3);    break;
  366.     case 'e':    flist_date (*curfile_, 4);    break;
  367.     default:    flist_date (*curfile_, 1);
  368.     }
  369. }
  370.  
  371. /*
  372.  * Set flag 'D_mode', which controls the width of the data-field in the display.
  373.  * Values:
  374.  *    -1, very short, minimal 12-character format
  375.  *     0, nominal (date to minutes)
  376.  *     1, long (day of week plus date to minutes)
  377.  *     2, very long (day of week plus date to seconds)
  378.  */
  379. void    flist_date2 (int curfile)
  380. {
  381.     if (D_opt)
  382.     {
  383.         D_mode = max(-1, min(2, D_mode));
  384.         dds_all (dds_fast(DDS_U_C), curfile);
  385.     }
  386.     else
  387.         flist_date (curfile, 0);
  388. }
  389.  
  390. /*
  391.  * Toggle the date-display mode.  To make FLIST faster, normally only one
  392.  * type of filedate (CREATED,BACKUP,REVISED) is shown on the screen at a time.
  393.  */
  394. void    flist_date (int curfile, int opt)
  395. {
  396.     if (D_opt)        /* Can I toggle it ?    */
  397.     {
  398.         if (opt != D_opt)
  399.         {
  400.             D_opt = opt;
  401.             dds_all (dds_fast(DDS_U_C), curfile);
  402.         }
  403.     }
  404.     else
  405.         warn ("Date-toggle is invalid since NODATE was used");
  406. }
  407.  
  408. /*
  409.  * FLIST sounds an audible alarm whenever a warning is sent to the status line.
  410.  * This, and other messages are normally cleared from the status line to show
  411.  * the current default directory, and the index into the file-list.  We use
  412.  * flags (beep_flag, warn_flag) to avoid having the status line alternate too
  413.  * often between its default (pathname) and informational states:
  414.  *
  415.  *    beep_flag - tested in 'dds_tell', prevents new data from being typed
  416.  *        on the status line.  This flag is normally reset on the first
  417.  *        character of a new command, except when the character is the
  418.  *        same as the last (single-character) command, which generated
  419.  *        a message.
  420.  *
  421.  *    warn_flag - (maintained here, tested in 'dircmd') is set by any
  422.  *        warning message.  If a single command generates multiple
  423.  *        warnings, we do not really care to see more than one (e.g.,
  424.  *        the case of a repeated, erroneous command).  It is reset in
  425.  *        'dircmd' when we receive the first character of a new command
  426.  *        (so that we can tell if we have the repeated single-character
  427.  *        command).
  428.  */
  429. void    set_beep(void)    {    beep_flag = TRUE;    }
  430. void    clrbeep(void)    {    beep_flag = FALSE;    }
  431. int    didbeep(void)    {    return (beep_flag);    }
  432.  
  433. void    clrwarn(void)    {    clrbeep(); warn_flag = FALSE;    }
  434. int    didwarn(void)    {    return (warn_flag);    }
  435.  
  436. /*
  437.  * Display a warning message at the bottom of the screen.
  438.  */
  439. static
  440. void    WarnVA (char *format, va_list ap)
  441. {
  442.     if (!didbeep())
  443.     {
  444.         warn_flag = TRUE;
  445.         sound_alarm();
  446.         FlistTellVA (format, ap);
  447.     }
  448.     else if (++beep_flag < 99)    /* Continue beeping, but limit it */
  449.         sound_alarm();
  450. }
  451.  
  452. void    warn (char *format, ...)
  453. {
  454.     va_list    ap;
  455.  
  456.     va_start(ap, format);
  457.     WarnVA(format, ap);
  458.     va_end(ap);
  459. }
  460.  
  461. /*
  462.  * This entry is used for the (rare) case in which a series of operations
  463.  * is requested, any of which may generate a warning message.  If a warning
  464.  * has been posted, wait before setting a new message.
  465.  */
  466. void    warn2 (char *format, ...)
  467. {
  468.     va_list    ap;
  469.  
  470.     if (didbeep())
  471.     {
  472.         clrbeep();
  473.         sleep(1);    /* patch: should use some type of hold */
  474.     }
  475.     va_start(ap, format);
  476.     WarnVA (format, ap);
  477.     va_end(ap);
  478. }
  479.  
  480. /* <flist_tell>:
  481.  * Unconditionally send a warning message, overwriting any pending text:
  482.  */
  483. static
  484. void    FlistTellVA (char *format, va_list ap)
  485. {
  486.     clrbeep();
  487.     FlistInfoVA (format, ap);
  488.     warn_flag = TRUE;
  489. }
  490.  
  491. void    flist_tell (char *format, ...)
  492. {
  493.     va_list ap;
  494.  
  495.     va_start(ap, format);
  496.     FlistTellVA (format, ap);
  497.     va_end(ap);
  498. }
  499.  
  500. /* <flist_info>:
  501.  * Display informational message at the bottom of the screen.  We expect no
  502.  * more than 2 filespecs, usually abbreviated.  If a message is already
  503.  * pending (cf: 'didbeep'), then 'dds_tell' will not update the summary line.
  504.  *
  505.  * Route all error- and informational-messages through this point so that we
  506.  * can send them to a log-file.
  507.  */
  508. static
  509. void    FlistInfoVA (char *format, va_list ap)
  510. {
  511.     char    bfr[(3*MAX_PATH) + CRT_COLS];
  512.  
  513.     vsprintf (bfr, format, ap);
  514.  
  515.     if (did_crt_init)
  516.         dds_tell (bfr,-1);
  517.     else
  518.     {
  519.         putraw (bfr);
  520.         putraw ("\r\n");
  521.     }
  522.     flist_log ("%.132s", bfr);
  523. }
  524.  
  525. void    flist_info (char *format, ...)
  526. {
  527.     va_list    ap;
  528.  
  529.     va_start(ap, format);
  530.     FlistInfoVA(format, ap);
  531.     va_end(ap);
  532. }
  533.  
  534. /*
  535.  * Call 'flist_tell', when the argument is a VMS descriptor-string:
  536.  */
  537. int    flist_tell_dsc (struct    dsc$descriptor_s *ds_)
  538. {
  539.     char    bfr[CRT_COLS];
  540.     int    len = ds_->dsc$w_length;
  541.  
  542.     if (len > sizeof(bfr))    len = sizeof(bfr);
  543.     strncpy (bfr, ds_->dsc$a_pointer, len);
  544.     bfr[len] = EOS;
  545.     flist_tell ("%s", bfr);
  546.     return (EXIT_SUCCESS);
  547. }
  548.  
  549. /*
  550.  * Display a system message at the bottom of the screen.  We ignore success-
  551.  * and info-messages.
  552.  *
  553.  * Return TRUE on success so that the caller can use this routine to test
  554.  * completion as well.  We assume that legal VMS status codes are nonzero
  555.  * unsigned integers.
  556.  */
  557. int    flist_sysmsg (unsigned status)
  558. {
  559.     char    buffer[CRT_COLS];
  560.  
  561.     if (!status || $VMS_STATUS_SUCCESS(status))
  562.         return (TRUE);
  563.     else
  564.     {
  565.         sysgetmsg (status, buffer, sizeof(buffer));
  566.         warn2 ("%s", buffer);
  567.         return (FALSE);
  568.     }
  569. }
  570.  
  571. /*
  572.  * Display fatal-error message, exit:
  573.  */
  574. void    error (int status, char *msg_)
  575. {
  576.     auto    char    who[MAX_PATH];
  577.  
  578.     if (did_crt_init)
  579.     {
  580.         crt_quit (TRUE);    /* Make a clean exit        */
  581.         did_crt_init = FALSE;
  582.     }
  583.  
  584.     whoami (who, 3);
  585.     strcat (who, "-f-");
  586.     if (msg_)    /* patch: We should send this to SYS$ERROR */
  587.         printf ("\n%s%s\n", who, msg_);
  588.     else
  589.         perror (who);
  590.     flist_quit (status ? status : EXIT_FAILURE);
  591. }
  592.  
  593. /* <flist_help>:
  594.  * Provide help for this program.  Route through this one point so we can
  595.  * use a common-name for the program.
  596.  */
  597. void    flist_help (int curfile, char *key)
  598. {
  599.     char    bfr[CRT_COLS];
  600.     int    len;
  601.  
  602.     strcpy (bfr, "FLIST ");
  603.     if (key)
  604.     {
  605.         len = strlen (bfr);
  606.         strncat (&bfr[len], key, sizeof(bfr)-len-1);
  607.         bfr[sizeof(bfr)-1] = EOS;
  608.     }
  609.     crt_help (0, bfr);
  610. }
  611.  
  612. /* <flist_log>:
  613.  * Write the specified information to the LOG-file, if it is open:
  614.  */
  615. static
  616. void    FlistLogVA (char *format, va_list ap)
  617. {
  618.     if (LogRAB != 0)
  619.     {
  620.         register int j,k,next;
  621.         char    bfr[CRT_COLS+(2*MAX_PATH)],
  622.             bfr2[CRT_COLS];
  623.  
  624.         sprintf (bfr2, "%*s", nesting_lvl, " ");
  625.         vsprintf (bfr, format, ap);
  626.  
  627.         /*
  628.          * Split the buffer if it contains embedded newlines.  Ignore
  629.          * completely-null buffers.
  630.          */
  631.         j = k = 0;
  632.         while (bfr[j])
  633.         {
  634.             next = nesting_lvl;
  635.             for (k = j; bfr[k] && bfr[k] != '\n'; k++)
  636.                 bfr2[next++] = bfr[k];
  637.             rputr (LogRAB, bfr2, next);
  638.             j = bfr[k] ? k + 1: k;
  639.         }
  640.     }
  641. }
  642.  
  643. void    flist_log (char *format, ...)
  644. {
  645.     va_list    ap;
  646.     va_start(ap, format);
  647.     FlistLogVA (format, ap);
  648.     va_end(ap);
  649. }
  650.  
  651. /*
  652.  * Make available the nesting-level:
  653.  */
  654. int    flist_nest (void)
  655. {
  656.     return (nesting_lvl);
  657. }
  658.  
  659. /* <flist_opts>:
  660.  * Process options for either the main entry, or for EDIT-directory (subset).
  661.  * In the latter case, some options are unavailable because of a conflict of
  662.  * resources which would result.  However, we generally inherit options from
  663.  * the main-level.
  664.  *
  665.  * Return TRUE if an error is found.
  666.  *
  667.  * patch: should resolve the ability to do COMMAND, LOG options within levels.
  668.  */
  669. int    flist_opts (int argc, char **argv, DCLARG *arg_, int subset)
  670. {
  671.     char    msg[CRT_COLS + 8 * MAX_PATH];
  672.  
  673.     if (subset)    subset = SUBOPT; /* Number of entries to ignore    */
  674.     if (dclopt (msg, arg_, &opts[subset],
  675.         sizeof(opts) - subset * sizeof(DCLOPT)))
  676.     {
  677.         if (subset)        warn ("%s", msg);
  678.         else            error (0, msg);
  679.         return (TRUE);
  680.     }
  681.  
  682.     if (H_opt) {
  683.         int    n;
  684.         printf("FLIST -- File List -- built %s\n", __DATE__);
  685.         printf("\nOptions:\n");
  686.         for (n = 0; n < sizeof(opts) / sizeof(opts[0]); n++)
  687.         {
  688.             printf("\t/%s\n", opts[n].opt_name);
  689.         }
  690.         exit(EXIT_SUCCESS);
  691.     }
  692.  
  693.     if (D_opt1)    D_opt = 1;
  694.     if (D_opt2)    D_opt = 2;
  695.     if (D_opt3)    D_opt = 3;
  696.     if (D_opt4)    D_opt = 4;
  697.     if (! subset)
  698.     {
  699.         if (Xfast)    A_opt = D_opt = M_opt = FALSE;
  700.         AnyXAB = (!Xfast || A_opt || D_opt || M_opt || O_opt);
  701.         D_mode = 0;    /* Normally don't show day-of-week    */
  702.     }
  703.  
  704.     /*
  705.      * If a date-selection (/AFTER or /BEFORE) option was made, find the
  706.      * side-effect flags 'dateflag[]'.
  707.      */
  708.     dateflag[0] = dateflag[1] = 0;
  709.     if (isOkDate(&datechek))
  710.     {
  711.         if (dateflag[1] = D_opt)
  712.         {
  713.         DCLARG    *d_ = arg_;
  714.             while (d_ && ! dateflag[0])
  715.             {
  716.                 strucpy (msg, d_->dcl_text);
  717.                 if (!strncmp (msg, "/AF", 3)
  718.                 ||  !strncmp (msg, "/SI", 3))
  719.                     dateflag[0] = 1;
  720.                 else if (!strncmp (msg, "/BE", 3))
  721.                     dateflag[0] = -1;
  722.                 d_ = d_->dcl_next;
  723.             }
  724.         }
  725.         else
  726.             error (0, "Date-selection requires date-lookup");
  727.     }
  728.  
  729.     if (! subset)
  730.     {
  731.         if (*LogFile)
  732.         {
  733.             if (!(LogRAB = ropen2 (LogFile, LogDft, "w")))
  734.             {
  735.                 rerror();
  736.                 return (TRUE);
  737.             }
  738.             else if (argc > 0)
  739.             {
  740.                 int    j;
  741.                 size_t    len = 0;
  742.  
  743.                 msg[0]    = EOS;
  744.                 for (j = 0; j < argc; j++)
  745.                 {
  746.                     char    *parm = argv[j];
  747.                     len += (strlen(parm) + 1);
  748.                     if (len >= sizeof(msg) - 1)
  749.                         break;
  750.                     strcat (msg, " ");
  751.                     strcat (msg, parm);
  752.                 }
  753.                 flist_log ("!%s", msg);
  754.             }
  755.         }
  756.         getraw_init(CmdFile,CmdDft);
  757.         /* Init this first, in case of error!!    */
  758.     }
  759.  
  760.     return (FALSE);            /* no errors found    */
  761. }
  762.  
  763. /* <flist_lis>:
  764.  * Open/write-to/close listing-file used for miscellaneous displays which do
  765.  * not fit into either the status-line, or into the normal file-display list.
  766.  *
  767.  * If the operation is successful, return the actual-name for use by the caller
  768.  * (i.e., to browse it).
  769.  */
  770. char    *flist_lis (char *format, ...)
  771. {
  772.     char    bfr[CRT_COLS+(2*MAX_PATH)];
  773.  
  774.     if (format)    /* If arguments given, open/write-to    */
  775.     {
  776.         va_list ap;
  777.  
  778.         if (! LisRAB)
  779.         {
  780.             if (!(LisRAB = ropen (LisFile, "w")))
  781.             {
  782.                 rerror();
  783.                 return (nullC);
  784.             }
  785.         }
  786.  
  787.         va_start(ap, format);
  788.         FlistLogVA (format, ap);
  789.         vsprintf (bfr, format, ap);
  790.         va_end(ap);
  791.  
  792.         rputr (LisRAB, bfr, strlen(bfr));
  793.     }
  794.     else if (LisRAB)
  795.     {
  796.         rclose (LisRAB);
  797.         LisRAB    = 0;
  798.     }
  799.     return (LisFile);
  800. }
  801.