home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / VILE327.ZIP / VILE327.TAR / vile3.27 / random.c < prev    next >
Text File  |  1992-12-14  |  26KB  |  1,192 lines

  1. /*
  2.  * This file contains the command processing functions for a number of random
  3.  * commands. There is no functional grouping here, for sure.
  4.  *
  5.  * $Log: random.c,v $
  6.  * Revision 1.79  1992/12/04  09:51:00  foxharp
  7.  * assume POSIX machines have getcwd.  they should.
  8.  *
  9.  * Revision 1.78  1992/12/04  09:14:36  foxharp
  10.  * deleted unused assigns
  11.  *
  12.  * Revision 1.77  1992/08/20  23:40:48  foxharp
  13.  * typo fixes -- thanks, eric
  14.  *
  15.  * Revision 1.76  1992/08/19  23:06:06  foxharp
  16.  * handle DOS's multiple current directories better (i.e. one per drive), and
  17.  * allow npopen to follow PATH to find "pwd", since it isn't always in /bin.
  18.  * sheesh.
  19.  *
  20.  * Revision 1.75  1992/08/06  23:55:07  foxharp
  21.  * changes to canonical pathnames and directory changing to support DOS and
  22.  * its drive designators
  23.  *
  24.  * Revision 1.74  1992/08/05  22:10:03  foxharp
  25.  * hopefully handle DOS pathnames better
  26.  *
  27.  * Revision 1.73  1992/08/04  20:13:29  foxharp
  28.  * fclose() --> npclose().  thanks eric.
  29.  *
  30.  * Revision 1.72  1992/07/20  22:49:51  foxharp
  31.  * took out ifdef'ed BEFORE code
  32.  *
  33.  * Revision 1.71  1992/07/18  13:13:56  foxharp
  34.  * put all path-shortening in one place (shorten_path()), and took out some old code now
  35.  * unnecessary
  36.  *
  37.  * Revision 1.70  1992/07/17  19:14:57  foxharp
  38.  * clean up gcc -Wall warnings
  39.  *
  40.  * Revision 1.69  1992/07/16  22:18:54  foxharp
  41.  * ins() takes an argument -- whether or not to playback, usually FALSE
  42.  *
  43.  * Revision 1.68  1992/07/15  08:58:46  foxharp
  44.  * added, and ifdef'ed out, code for dealing with DOS drive designators
  45.  * in ch_fname()
  46.  *
  47.  * Revision 1.67  1992/07/13  19:39:03  foxharp
  48.  * finished canonicalizing pathnames
  49.  *
  50.  * Revision 1.66  1992/07/13  09:28:37  foxharp
  51.  * preliminary changes for canonical path names
  52.  *
  53.  * Revision 1.65  1992/06/25  23:00:50  foxharp
  54.  * changes for dos/ibmpc
  55.  *
  56.  * Revision 1.64  1992/05/29  09:40:53  foxharp
  57.  * split out modes.c, fences.c, and insert.c from random.c
  58.  *
  59.  * Revision 1.63  1992/05/29  08:37:59  foxharp
  60.  * getfence() changes for #ifdef matching and C comment matching
  61.  *
  62.  * Revision 1.62  1992/05/25  21:07:48  foxharp
  63.  * extern func declarations moved to header
  64.  *
  65.  * Revision 1.61  1992/05/20  18:55:08  foxharp
  66.  * better confirmation output from cd command
  67.  *
  68.  * Revision 1.60  1992/05/19  08:55:44  foxharp
  69.  * more prototype and shadowed decl fixups
  70.  *
  71.  * Revision 1.59  1992/05/16  14:02:55  pgf
  72.  * header/typedef fixups
  73.  *
  74.  * Revision 1.58  1992/05/16  12:00:31  pgf
  75.  * prototypes/ansi/void-int stuff/microsoftC
  76.  *
  77.  * Revision 1.57  1992/05/13  09:14:50  pgf
  78.  * when scanning for a fence character, don't go past end of line.
  79.  * i hate do/while loops.
  80.  *
  81.  * Revision 1.56  1992/04/14  08:51:44  pgf
  82.  * missing local var in DOS ifdef
  83.  *
  84.  * Revision 1.55  1992/03/24  22:45:09  pgf
  85.  * allow ^D to back up past autoindented whitespace
  86.  *
  87.  * Revision 1.54  1992/03/24  07:45:08  pgf
  88.  * made separate internal and external entry points for go[to]col, so that
  89.  * users see columns starting at 1, and vile sees them starting from 0
  90.  *
  91.  * Revision 1.53  1992/03/19  23:23:31  pgf
  92.  * removed extra string lib externs and include
  93.  *
  94.  * Revision 1.52  1992/03/05  09:19:55  pgf
  95.  * changed some mlwrite() to mlforce(), due to new terse support
  96.  *
  97.  * Revision 1.51  1992/03/03  08:43:47  pgf
  98.  * fixed off-by-one error in gotocol()
  99.  *
  100.  * Revision 1.50  1992/03/01  18:38:40  pgf
  101.  * added fence matching on #if, #el, and #en, and
  102.  * fixed compilation error #if COLOR
  103.  *
  104.  * Revision 1.49  1992/02/26  21:58:17  pgf
  105.  * changes to entab/detabline, to better support shift operations
  106.  *
  107.  * Revision 1.48  1992/02/17  08:55:57  pgf
  108.  * added showmode support, and
  109.  * fixed backspace-after-wrapword bug, and
  110.  * fixed '=' parsing in set commands, and
  111.  * some small changes for saber cleanup
  112.  *
  113.  * Revision 1.47  1992/01/13  23:33:32  pgf
  114.  * finished shiftwidth implementation -- ^D works now
  115.  *
  116.  * Revision 1.46  1992/01/10  08:08:46  pgf
  117.  * added shiftwidth(), and some bug fixes to en/detabline()
  118.  *
  119.  * Revision 1.45  1992/01/05  00:06:13  pgf
  120.  * split mlwrite into mlwrite/mlprompt/mlforce to make errors visible more
  121.  * often.  also normalized message appearance somewhat.
  122.  *
  123.  * Revision 1.44  1992/01/03  23:31:49  pgf
  124.  * use new ch_fname() to manipulate filenames, since b_fname is now
  125.  * a malloc'ed sting, to avoid length limits
  126.  *
  127.  * Revision 1.43  1991/12/24  09:18:47  pgf
  128.  * added current/change directory support  (Dave Lemke's changes)
  129.  *
  130.  * Revision 1.42  1991/11/16  18:39:50  pgf
  131.  * pass new magic arg to regcomp, and
  132.  * fixed bug in openup/opendown pair
  133.  *
  134.  * Revision 1.41  1991/11/13  20:09:27  pgf
  135.  * X11 changes, from dave lemke
  136.  *
  137.  * Revision 1.40  1991/11/10  22:02:09  pgf
  138.  * fixed bug in openup(), and made counts work right
  139.  *
  140.  * Revision 1.39  1991/11/08  14:13:58  pgf
  141.  * fixed settab() and setfillcol()
  142.  *
  143.  * Revision 1.38  1991/11/08  13:10:26  pgf
  144.  * lint cleanup, and
  145.  * put in dave lemke's "autoinsert works going up" fix, and
  146.  * made autoinsert clean up pre-existing leading whitespace
  147.  *
  148.  * Revision 1.37  1991/11/06  23:28:08  pgf
  149.  * getfence() will scan for a fence if not on one to begin with.  it'll
  150.  * scan in either direction, depending on arg to matchfence or matchfenceback
  151.  *
  152.  * Revision 1.36  1991/11/03  17:46:30  pgf
  153.  * removed f,n args from all region functions -- they don't use them,
  154.  * since they're no longer directly called by the user
  155.  *
  156.  * Revision 1.35  1991/11/01  14:38:00  pgf
  157.  * saber cleanup
  158.  *
  159.  * Revision 1.34  1991/10/29  03:04:45  pgf
  160.  * fixed argument mismatches
  161.  *
  162.  * Revision 1.33  1991/10/28  14:21:52  pgf
  163.  * eliminated TABVAL and fillcol macros, converted gasave to per-buffer
  164.  *
  165.  * Revision 1.32  1991/10/27  01:51:48  pgf
  166.  * new regex values are now settable and displayable
  167.  *
  168.  * Revision 1.31  1991/10/24  13:01:03  pgf
  169.  * bug fix for append'ing in empty buffer
  170.  *
  171.  * Revision 1.30  1991/10/18  10:56:54  pgf
  172.  * added code to use modified VALUE structures and lists to display settings
  173.  * more easily (adjvalueset).  also removed some old ifdefs.
  174.  *
  175.  * Revision 1.29  1991/10/15  12:01:20  pgf
  176.  * added backspacelimit support, and fewer tty chars are hard-coded now
  177.  *
  178.  * Revision 1.28  1991/10/08  01:09:38    pgf
  179.  * added ^W and ^U processing to ins().  should make this depend on the tty
  180.  * settings, and add option to control whether it's okay to backspace or
  181.  * line or word kill back beyond the insert point
  182.  *
  183.  * Revision 1.27  1991/09/30  01:47:24    pgf
  184.  * reformat listing of values a bit
  185.  *
  186.  * Revision 1.26  1991/09/26  13:13:07    pgf
  187.  * created window values, and allow them to be displayed and set.  still needs
  188.  * cleaning up
  189.  *
  190.  * Revision 1.25  1991/09/24  02:07:29    pgf
  191.  * suppressed extra whitespace in listmodes
  192.  *
  193.  * Revision 1.24  1991/09/24  01:03:49    pgf
  194.  * pass FALSE to gotoeol to avoid unnecessary work
  195.  *
  196.  * Revision 1.23  1991/09/23  01:57:20    pgf
  197.  * n
  198.  * don't pass null pointers to strcmp()
  199.  *
  200.  * Revision 1.22  1991/09/20  13:11:53    pgf
  201.  * add local value settings to the listmodes output
  202.  *
  203.  * Revision 1.21  1991/09/19  13:39:53    pgf
  204.  * added shortname synonyms to mode and value names
  205.  *
  206.  * Revision 1.20  1991/09/10  01:21:34    pgf
  207.  * re-tabbed
  208.  *
  209.  * Revision 1.19  1991/09/10  00:43:31    pgf
  210.  * ifdef'ed out obsolete "showm", and change calls to it to "listmodes"
  211.  *
  212.  * Revision 1.18  1991/08/16  11:12:26    pgf
  213.  * added the third flavor of insertmode for replace-char, and
  214.  * added support for the insertmode indicator on the modeline, and
  215.  * created the catnap routine for use by fmatch, and the typahead
  216.  * check in the ANSI_SPEC code in kbd_key
  217.  *
  218.  * Revision 1.17  91/08/13    12:51:29  pgf
  219.  * make sure we pass a non-NULL arg to poll, even though the count is zero
  220.  * 
  221.  * Revision 1.16  1991/08/13  02:52:25    pgf
  222.  * the fmatch() code now works if you have poll or select, and
  223.  * is enabled by "set showmatch"
  224.  *
  225.  * Revision 1.15  1991/08/12  15:06:21    pgf
  226.  * added ANSI_SPEC capability -- can now use the arrow keys from
  227.  * command or insert mode
  228.  *
  229.  * Revision 1.14  1991/08/08  13:21:25    pgf
  230.  * removed ifdef BEFORE
  231.  *
  232.  * Revision 1.13  1991/08/07  12:35:07    pgf
  233.  * added RCS log messages
  234.  *
  235.  * revision 1.12
  236.  * date: 1991/08/06 15:25:02;
  237.  *    global/local values
  238.  * and list changes
  239.  * 
  240.  * revision 1.11
  241.  * date: 1991/06/26 09:35:48;
  242.  * made count work correctly on flipchar, and
  243.  * removed old ifdef BEFORE stuff
  244.  * 
  245.  * revision 1.10
  246.  * date: 1991/06/25 19:53:09;
  247.  * massive data structure restructure
  248.  * 
  249.  * revision 1.9
  250.  * date: 1991/06/20 17:23:24;
  251.  * fixed & --> && problem in indent_newline
  252.  * 
  253.  * revision 1.8
  254.  * date: 1991/06/16 17:38:02;
  255.  * switched to modulo tab calculations, and
  256.  * converted entab, detab, and trim to work on regions,
  257.  * and stripped some old ifdef NOCOUNT stuff for openup and opendown
  258.  * and added support for local and globla tabstop and fillcol values
  259.  * 
  260.  * revision 1.7
  261.  * date: 1991/06/15 09:09:27;
  262.  * changed some forwchar calls to forwchar_to_eol, and
  263.  * now prevent 'x', 's', 'r' from destroying the newline when used on
  264.  * empty lines
  265.  * 
  266.  * revision 1.6
  267.  * date: 1991/06/06 13:58:23;
  268.  * added autoindent mode and "set all"
  269.  * 
  270.  * revision 1.5
  271.  * date: 1991/05/31 11:19:06;
  272.  * added showlength function, for "=" ex command, and
  273.  * switched from stutterfunc to godotplus
  274.  * 
  275.  * revision 1.4
  276.  * date: 1991/04/04 09:40:25;
  277.  * fixed autoinsert bug
  278.  * 
  279.  * revision 1.3
  280.  * date: 1991/02/12 09:49:33;
  281.  * doindent had an unset return value, causing autoindents of 0 chars to fail
  282.  * 
  283.  * revision 1.2
  284.  * date: 1990/10/03 16:01:00;
  285.  * make backspace work for everyone
  286.  * 
  287.  * revision 1.1
  288.  * date: 1990/09/21 10:25:54;
  289.  * initial vile RCS revision
  290.  */
  291.  
  292. #include    <stdio.h>
  293. #include    "estruct.h"
  294. #include    "edef.h"
  295. #if HAVE_POLL
  296. # include <poll.h>
  297. #endif
  298.  
  299. extern CMDFUNC f_forwchar, f_backchar, f_forwchar_to_eol, f_backchar_to_bol;
  300.  
  301.  
  302. /* generic "lister", which takes care of popping a window/buffer pair under
  303.     the given name, and calling "func" with a couple of args to fill in
  304.     the buffer */
  305. int
  306. liststuff(name,func,iarg,carg)
  307. char *name;
  308. void (*func)();        /* ptr to function to execute */
  309. int iarg;
  310. char *carg;
  311. {
  312.     register BUFFER *bp;
  313.     register int    s;
  314.  
  315.     /* create the buffer list buffer   */
  316.     bp = bfind(name, OK_CREAT, BFSCRTCH);
  317.     if (bp == NULL)
  318.         return FALSE;
  319.         
  320.     if ((s=bclear(bp)) != TRUE) /* clear old text (?) */
  321.         return (s);
  322.     bp->b_flag |= BFSCRTCH;
  323.     s = TRUE;
  324.     if (!s || popupbuff(bp) == FALSE) {
  325.         mlforce("[Can't list. ]");
  326.         zotbuf(bp);
  327.         return (FALSE);
  328.     }
  329.     /* call the passed in function, giving it both the integer and 
  330.         character pointer arguments */
  331.     (*func)(iarg,carg);
  332.     gotobob(FALSE,1);
  333.     { char buf[80];
  334.       lsprintf(buf, "       %s   %s",prognam,version);
  335.       if (bp->b_fname)
  336.         free(bp->b_fname);
  337.       bp->b_fname = strmalloc(buf);
  338.       bp->b_fnlen = strlen(buf);
  339.       /* was ch_fname() */
  340.     }
  341.     bp->b_flag &= ~BFCHG;
  342.     bp->b_active = TRUE;
  343.     make_local_b_val(bp,MDVIEW);
  344.     set_b_val(bp,MDVIEW,TRUE);
  345.     make_local_b_val(bp,VAL_TAB);
  346.     set_b_val(bp,VAL_TAB,8);
  347.     make_local_b_val(bp,MDDOS);
  348.     set_b_val(bp,MDDOS,FALSE);
  349.  
  350.     return TRUE;
  351. }
  352.  
  353. /*
  354.  * Display the current position of the cursor, lines and columns, in the file,
  355.  * the character that is under the cursor (in hex), and the fraction of the
  356.  * text that is before the cursor. The displayed column is not the current
  357.  * column, but the column that would be used on an infinite width display.
  358.  */
  359. /* ARGSUSED */
  360. int
  361. showcpos(f, n)
  362. int f,n;
  363. {
  364.     register LINE    *lp;        /* current line */
  365.     register long    numchars = 0;    /* # of chars in file */
  366.     register int    numlines = 0;    /* # of lines in file */
  367.     register long    predchars = 0;    /* # chars preceding point */
  368.     register int    predlines = 0;    /* # lines preceding point */
  369.     register int    curchar = '\n';    /* character under cursor */
  370.     int ratio;
  371.     int col;
  372.     int savepos;            /* temp save for current offset */
  373.     int ecol;            /* column pos/end of current line */
  374.  
  375.     /* starting at the beginning of the buffer */
  376.     lp = lforw(curbp->b_line.l);
  377.  
  378.     /* start counting chars and lines */
  379.     while (lp != curbp->b_line.l) {
  380.         /* if we are on the current line, record it */
  381.         if (lp == DOT.l) {
  382.             predlines = numlines;
  383.             predchars = numchars + DOT.o;
  384.             if (DOT.o == llength(lp))
  385.                 curchar = '\n';
  386.             else
  387.                 curchar = char_at(DOT);
  388.         }
  389.         /* on to the next line */
  390.         ++numlines;
  391.         numchars += llength(lp) + 1;
  392.         lp = lforw(lp);
  393.     }
  394.  
  395.     /* if at end of file, record it */
  396.     if (is_header_line(DOT,curbp)) {
  397.         predlines = numlines;
  398.         predchars = numchars;
  399.     }
  400.  
  401.     /* Get real column and end-of-line column. */
  402.     col = getccol(FALSE);
  403.     savepos = DOT.o;
  404.     DOT.o = llength(DOT.l);
  405.     ecol = getccol(FALSE);
  406.     DOT.o = savepos;
  407.  
  408.     ratio = 0;        /* Ratio before dot. */
  409.     if (numchars != 0)
  410.         ratio = (100L*predchars) / numchars;
  411.  
  412.     /* summarize and report the info */
  413.     mlforce(
  414. "Line %d of %d, Col %d of %d, Char %D of %D (%d%%) char is 0x%x",
  415.         predlines+1, numlines, col+1, ecol,
  416.         predchars+1, numchars, ratio, curchar);
  417.     return TRUE;
  418. }
  419.  
  420. /* ARGSUSED */
  421. int
  422. showlength(f,n)
  423. int f,n;
  424. {
  425.     register LINE    *lp;        /* current line */
  426.     register int    numlines = 0;    /* # of lines in file */
  427.  
  428.     /* starting at the beginning of the buffer */
  429.     lp = lforw(curbp->b_line.l);
  430.     while (lp != curbp->b_line.l) {
  431.         ++numlines;
  432.         lp = lforw(lp);
  433.     }
  434.     mlforce("%d",numlines);
  435.     return TRUE;
  436. }
  437.  
  438. #if ! SMALLER
  439. int
  440. getcline()    /* get the current line number */
  441. {
  442.     register LINE    *lp;        /* current line */
  443.     register int    numlines;    /* # of lines before point */
  444.  
  445.     /* starting at the beginning of the buffer */
  446.     lp = lforw(curbp->b_line.l);
  447.  
  448.     /* start counting lines */
  449.     numlines = 0;
  450.     while (lp != curbp->b_line.l) {
  451.         /* if we are on the current line, record it */
  452.         if (lp == DOT.l)
  453.             break;
  454.         ++numlines;
  455.         lp = lforw(lp);
  456.     }
  457.  
  458.     /* and return the resulting count */
  459.     return(numlines + 1);
  460. }
  461. #endif
  462.  
  463. /*
  464.  * Return current screen column.  Stop at first non-blank given TRUE argument.
  465.  */
  466. int
  467. getccol(bflg)
  468. int bflg;
  469. {
  470.     register int c, i, col;
  471.     col = 0;
  472.     for (i=0; i < DOT.o; ++i) {
  473.         c = lgetc(DOT.l, i);
  474.         if (!isspace(c) && bflg)
  475.             break;
  476.         col = next_column(c,col);
  477.     }
  478.     return col;
  479. }
  480.  
  481.  
  482. /*
  483.  * Set current column, based on counting from 1
  484.  */
  485. int
  486. gotocol(f,n)
  487. int f,n;
  488. {
  489.     if (!f || n <= 0)
  490.         n = 1;
  491.     return gocol(n - 1);
  492. }
  493.  
  494. /* really set column, based on counting from 0, for internal use */
  495. int
  496. gocol(n)
  497. int n;
  498. {
  499.     register int c;     /* character being scanned */
  500.     register int i;     /* index into current line */
  501.     register int col;    /* current cursor column   */
  502.     register int llen;    /* length of line in bytes */
  503.  
  504.     col = 0;
  505.     llen = llength(DOT.l);
  506.  
  507.     /* scan the line until we are at or past the target column */
  508.     for (i = 0; i < llen; ++i) {
  509.         /* upon reaching the target, drop out */
  510.         if (col >= n)
  511.             break;
  512.  
  513.         /* advance one character */
  514.         c = lgetc(DOT.l, i);
  515.         col = next_column(c,col);
  516.     }
  517.  
  518.     /* set us at the new position */
  519.     DOT.o = i;
  520.  
  521.     /* and tell whether we made it */
  522.     return(col >= n);
  523. }
  524.  
  525. #if ! SMALLER
  526. /*
  527.  * Twiddle the two characters on either side of dot. If dot is at the end of
  528.  * the line twiddle the two characters before it. Return with an error if dot
  529.  * is at the beginning of line; it seems to be a bit pointless to make this
  530.  * work. This fixes up a very common typo with a single stroke.
  531.  * This always works within a line, so "WFEDIT" is good enough.
  532.  */
  533. /* ARGSUSED */
  534. int
  535. twiddle(f, n)
  536. int f,n;
  537. {
  538.     MARK        dot;
  539.     register int    cl;
  540.     register int    cr;
  541.  
  542.     dot = DOT;
  543.     if (is_empty_line(dot))
  544.         return (FALSE);
  545.     --dot.o;
  546.     cr = char_at(dot);
  547.     if (--dot.o < 0)
  548.         return (FALSE);
  549.     cl = char_at(dot);
  550.     copy_for_undo(dot.l);
  551.     put_char_at(dot, cr);
  552.     ++dot.o;
  553.     put_char_at(dot, cl);
  554.     lchange(WFEDIT);
  555.     return (TRUE);
  556. }
  557. #endif
  558.  
  559.  
  560. /*
  561.  * change all tabs in the line to the right number of spaces.
  562.  * leadingonly says only do leading whitespace
  563.  */
  564. int
  565. detabline(leadingonly)
  566. int leadingonly;
  567. {
  568.     register int    s;
  569.     register int    c;
  570.     int    ocol;
  571.  
  572.     ocol = getccol(FALSE);
  573.  
  574.     DOT.o = 0;
  575.  
  576.     /* detab the entire current line */
  577.     while (DOT.o < llength(DOT.l)) {
  578.         c = char_at(DOT);
  579.         if (leadingonly && !isspace(c))
  580.             break;
  581.         /* if we have a tab */
  582.         if (c == '\t') {
  583.             if ((s = ldelete(1L, FALSE)) != TRUE) {
  584.                 return s;
  585.             }
  586.             insspace( TRUE, curtabval - (DOT.o % curtabval) );
  587.         }
  588.         DOT.o++;
  589.     }
  590.     gocol(ocol);
  591.     return TRUE;
  592. }
  593.  
  594. /*
  595.  * change all tabs in the region to the right number of spaces
  596.  */
  597. int
  598. detab_region()
  599. {
  600.     return do_fl_region(detabline,FALSE);
  601. }
  602.  
  603. /*
  604.  * convert all appropriate spaces in the line to tab characters.
  605.  * leadingonly says only do leading whitespace
  606.  */
  607. int
  608. entabline(leadingonly)
  609. int leadingonly;
  610. {
  611.     register int fspace;    /* pointer to first space if in a run */
  612.     register int ccol;    /* current cursor column */
  613.     register char cchar;    /* current character */
  614.     int    ocol;
  615.  
  616.     ocol = getccol(FALSE);
  617.  
  618.     /* entab the current line */
  619.     /* would this have been easier if it had started at
  620.         the _end_ of the line, rather than the beginning?  -pgf */
  621.     fspace = -1;
  622.     ccol = 0;
  623.  
  624.     detabline(leadingonly);    /* get rid of possible existing tabs */
  625.     DOT.o = 0;
  626.     while (1) {
  627.         /* see if it is time to compress */
  628.         if ((fspace >= 0) && (nextab(fspace) <= ccol))
  629.             if (ccol - fspace < 2)
  630.                 fspace = -1;
  631.             else {
  632.                 backchar(TRUE, ccol - fspace);
  633.                 ldelete((long)(ccol - fspace), FALSE);
  634.                 linsert(1, '\t');        
  635.                 fspace = -1;
  636.             }
  637.  
  638.         if (DOT.o >= llength(DOT.l))
  639.             break;
  640.  
  641.         /* get the current character */
  642.         cchar = char_at(DOT);
  643.  
  644.         if (cchar == ' ') { /* a space...compress? */
  645.             if (fspace == -1)
  646.                 fspace = ccol;
  647.         } else {
  648.             if (leadingonly)
  649.                 break;
  650.             fspace = -1;
  651.         }
  652.         ccol++;
  653.         DOT.o++;
  654.     }
  655.     gocol(ocol);
  656.     return TRUE;
  657. }
  658.  
  659. /*
  660.  * convert all appropriate spaces in the region to tab characters
  661.  */
  662. int
  663. entab_region()
  664. {
  665.     return do_fl_region(entabline,FALSE);
  666. }
  667.  
  668. /* trim trailing whitespace from a line.  leave dot at end of line */
  669. int
  670. trimline()
  671. {
  672.     register int off, orig;
  673.     register LINE *lp;
  674.         
  675.     lp = DOT.l;
  676.             
  677.     off = llength(lp)-1;
  678.     orig = off;
  679.     while (off >= 0) {
  680.         if (!isspace(lgetc(lp,off)))
  681.             break;
  682.         off--;
  683.     }
  684.         
  685.     if (off == orig)
  686.         return TRUE;
  687.  
  688.     DOT.o = off+1;
  689.             
  690.     return ldelete((long)(orig - off),FALSE);
  691. }
  692.  
  693. /*
  694.  * trim trailing whitespace from a region
  695.  */
  696. int
  697. trim_region()
  698. {
  699.     return do_fl_region(trimline,0);
  700. }
  701.  
  702.  
  703. #if AEDIT
  704. /*
  705.  * Delete blank lines around dot. What this command does depends if dot is
  706.  * sitting on a blank line. If dot is sitting on a blank line, this command
  707.  * deletes all the blank lines above and below the current line. If it is
  708.  * sitting on a non blank line then it deletes all of the blank lines after
  709.  * the line. Any argument is ignored.
  710.  */
  711. /* ARGSUSED */
  712. int
  713. deblank(f, n)
  714. int f,n;
  715. {
  716.     register LINE    *lp1;
  717.     register LINE    *lp2;
  718.     long nld;
  719.  
  720.     lp1 = DOT.l;
  721.     while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_line.l)
  722.         lp1 = lp2;
  723.     lp2 = lp1;
  724.     nld = 0;
  725.     while ((lp2=lforw(lp2))!=curbp->b_line.l && llength(lp2)==0)
  726.         ++nld;
  727.     if (nld == 0)
  728.         return (TRUE);
  729.     DOT.l = lforw(lp1);
  730.     DOT.o = 0;
  731.     return (ldelete(nld, FALSE));
  732. }
  733.  
  734. #endif
  735.  
  736. /* '~' is synonymous with 'M-~<space>' */
  737. int
  738. flipchar(f, n)
  739. int f,n;
  740. {
  741.     int s;
  742.  
  743.     havemotion = &f_forwchar_to_eol;
  744.     s = operflip(f,n);
  745.     if (s != TRUE)
  746.         return s;
  747.     return forwchar_to_eol(f,n);
  748. }
  749.  
  750. /* 'x' is synonymous with 'd<space>' */
  751. int
  752. forwdelchar(f, n)
  753. int f,n;
  754. {
  755.  
  756.     havemotion = &f_forwchar_to_eol;
  757.     return operdel(f,n);
  758. }
  759.  
  760. /* 'X' is synonymous with 'd<backspace>' */
  761. int
  762. backdelchar(f, n)
  763. int f,n;
  764. {
  765.     havemotion = &f_backchar_to_bol;
  766.     return operdel(f,n);
  767. }
  768.  
  769. /* 'D' is synonymous with 'd$' */
  770. /* ARGSUSED */
  771. int
  772. deltoeol(f, n)
  773. int f,n;
  774. {
  775.     extern CMDFUNC f_gotoeol;
  776.  
  777.     if (llength(DOT.l) == 0)
  778.         return TRUE;
  779.  
  780.     havemotion = &f_gotoeol;
  781.     return operdel(FALSE,1);
  782. }
  783.  
  784. /* 'C' is synonymous with 'c$' */
  785. /* ARGSUSED */
  786. int
  787. chgtoeol(f, n)
  788. int f,n;
  789. {
  790.     extern CMDFUNC f_gotoeol;
  791.  
  792.     if (llength(DOT.l) == 0) {
  793.         return ins(FALSE);
  794.     } else {
  795.         havemotion = &f_gotoeol;
  796.         return operchg(FALSE,1);
  797.     }
  798. }
  799.  
  800. /* 'Y' is synonymous with 'yy' */
  801. int
  802. yankline(f, n)
  803. int f,n;
  804. {
  805.     extern CMDFUNC f_godotplus;
  806.     havemotion = &f_godotplus;
  807.     return(operyank(f,n));
  808. }
  809.  
  810. /* 'S' is synonymous with 'cc' */
  811. int
  812. chgline(f, n)
  813. int f,n;
  814. {
  815.     extern CMDFUNC f_godotplus;
  816.     havemotion = &f_godotplus;
  817.     return(operchg(f,n));
  818. }
  819.  
  820. /* 's' is synonymous with 'c<space>' */
  821. int
  822. chgchar(f, n)
  823. int f,n;
  824. {
  825.     havemotion = &f_forwchar_to_eol;
  826.     return(operchg(f,n));
  827. }
  828.  
  829.  
  830.  
  831. /*    This function simply clears the message line,
  832.         mainly for macro usage            */
  833.  
  834. /* ARGSUSED */
  835. int
  836. clrmes(f, n)
  837. int f, n;    /* arguments ignored */
  838. {
  839.     mlforce("");
  840.     return(TRUE);
  841. }
  842.  
  843. #if ! SMALLER
  844.  
  845. /*    This function writes a string on the message line
  846.         mainly for macro usage            */
  847.  
  848. /* ARGSUSED */
  849. int
  850. writemsg(f, n)
  851. int f, n;    /* arguments ignored */
  852. {
  853.     register int status;
  854.     char buf[NPAT];     /* buffer to receive message into */
  855.  
  856.     buf[0] = 0;
  857.     if ((status = mlreply("Message to write: ", buf, NPAT - 1)) != TRUE)
  858.         return(status);
  859.  
  860.     /* write the message out */
  861.     mlforce("%s",buf);
  862.     return(TRUE);
  863. }
  864. #endif
  865.  
  866.  
  867. void
  868. catnap(milli)
  869. int milli;
  870. {
  871. #if ! UNIX
  872.     long i;
  873.     for (i = 0; i < term.t_pause; i++)
  874.         ;
  875. #else
  876. # if HAVE_SELECT
  877.  
  878.     struct timeval tval;
  879.     tval.tv_sec = 0;
  880.     tval.tv_usec = milli * 1000;    /* microseconds */
  881.     select (0, NULL, NULL, NULL, &tval);
  882.  
  883. # else
  884. #  if HAVE_POLL
  885.  
  886.     struct pollfd pfd;
  887.     poll(&pfd, 0, milli); /* milliseconds */
  888.  
  889. #  else
  890.  
  891.     sleep(1); /* 1 second.    ugh. */
  892.  
  893. #  endif
  894. # endif
  895. #endif
  896. }
  897.  
  898. #if ! SMALLER
  899. int
  900. istring(f, n)    /* ask for and insert a string into the current
  901.            buffer at the current point */
  902. int f, n;
  903. {
  904.     register char *tp;    /* pointer into string to add */
  905.     register int status;    /* status return code */
  906.     static char tstring[NPAT+1];    /* string to add */
  907.  
  908.     /* ask for string to insert */
  909.     status = mlreply("String to insert: ", tstring, NPAT);
  910.     if (status != TRUE)
  911.         return(status);
  912.  
  913.     if (f == FALSE)
  914.         n = 1;
  915.  
  916.     if (n < 0)
  917.         n = - n;
  918.  
  919.     /* insert it */
  920.     while (n--) {
  921.         tp = &tstring[0];
  922.         while (*tp) {
  923.             if (*tp == '\n')
  924.                 status = lnewline();
  925.             else
  926.                 status = linsert(1, *tp);
  927.             ++tp;
  928.             if (status != TRUE)
  929.                 return(status);
  930.         }
  931.     }
  932.  
  933.     return(TRUE);
  934. }
  935. #endif
  936.  
  937. #if UNIX
  938. #include    <sys/param.h>
  939. #endif
  940.  
  941.  
  942.  
  943. /* return a string naming the current directory */
  944. char *
  945. current_directory(force)
  946. int force;
  947. {
  948.     char *s;
  949.     static char    dirname[NFILEN];
  950.     static char *cwd;
  951.  
  952.     if (!force && cwd)
  953.         return cwd;
  954. #if USG && ! POSIX
  955.     {
  956.     FILE *f, *npopen();
  957.     int n;
  958.     f = npopen("pwd", "r");
  959.     if (f == NULL) {
  960.         npclose(f);
  961.         return NULL;
  962.     }
  963.     n = fread(dirname, 1, NFILEN, f);
  964.  
  965.     dirname[n] = '\0';
  966.     npclose(f);
  967.     cwd = dirname;
  968.     }
  969. #else
  970. # if (MSDOS & MSC) || POSIX
  971.  
  972.     cwd = getcwd(dirname, NFILEN);
  973. # else
  974.     cwd = getwd(dirname);
  975. # endif
  976. #endif
  977.     s = strchr(cwd, '\n');
  978.     if (s)
  979.         *s = '\0';
  980. #if MSDOS & MSC
  981.     update_dos_drv_dir(cwd);
  982. #endif
  983.  
  984.     return cwd;
  985. }
  986.  
  987. #if MSDOS
  988.  
  989. /* returns drive _letter_ */
  990. int
  991. curdrive()
  992. {
  993.     return (bdos(0x19, 0, 0) & 0xff) + 'A';
  994. }
  995.  
  996. /* take drive _letter_ as arg. */
  997. int
  998. setdrive(d)
  999. int d;
  1000. {
  1001. /* FIXME must put some error range/checking in here */
  1002.     bdos(0x0e, d-'A', 0);
  1003.     return TRUE;
  1004. #if LATER
  1005.     mlforce("[Bad drive specifier]");
  1006. #endif
  1007. }
  1008.  
  1009.  
  1010. static int curd;
  1011. static char *cwds[26];
  1012.  
  1013. char *
  1014. curr_dir_on_drive(drive)
  1015. int drive;
  1016. {
  1017.     if (drive == 0)
  1018.         return current_directory(FALSE);
  1019.  
  1020.     if (curd == 0)
  1021.         curd = curdrive();
  1022.  
  1023.     if (cwds[drive-'A'])
  1024.         return cwds[drive-'A'];
  1025.     else
  1026.         cwds[drive-'A'] = (char *)malloc(NFILEN);
  1027.  
  1028.     if (!cwds[drive-'A'])
  1029.         return current_directory(FALSE);
  1030.  
  1031.     if (setdrive(drive) == TRUE) {
  1032.         strcpy(cwds[drive-'A'], current_directory(TRUE));
  1033.         setdrive(curd);
  1034.         (void)current_directory(TRUE);
  1035.         return cwds[drive-'A'];
  1036.     }
  1037.     return current_directory(FALSE);
  1038. }
  1039.  
  1040. void
  1041. update_dos_drv_dir(cwd)
  1042. char *cwd;
  1043. {
  1044.     char drive = 0;
  1045.     if (isupper(cwd[0]) && cwd[1] == ':') {
  1046.         drive = *cwd;
  1047.         cwd += 2;
  1048.     }
  1049.     if (!drive)
  1050.         return;
  1051.  
  1052.     if (!cwds[drive-'A'])
  1053.         cwds[drive-'A'] = (char *)malloc(NFILEN);
  1054.  
  1055.     if (!cwds[drive-'A'])
  1056.         return;
  1057.  
  1058.     strcpy(cwds[drive-'A'],cwd);
  1059.     
  1060. }
  1061. #endif
  1062.  
  1063.  
  1064. /* ARGSUSED */
  1065. int
  1066. cd(f,n)
  1067. int f, n;
  1068. {
  1069.     int status;
  1070.     static char cdirname[NFILEN];
  1071.     status = mlreply("Change to directory: ", cdirname, NFILEN);
  1072.     if (status != TRUE) {
  1073.         /* should go HOME here */
  1074.         return status;
  1075.     }
  1076.     return set_directory(cdirname);
  1077. }
  1078.  
  1079. /* ARGSUSED */
  1080. int
  1081. pwd(f,n)
  1082. int f, n;
  1083. {
  1084.     mlforce("%s",current_directory(f));
  1085.     return TRUE;
  1086. }
  1087.  
  1088. /* move to the named directory.  (Dave Lemke) */
  1089. int
  1090. set_directory(dir)
  1091. char    *dir;
  1092. {
  1093.     char       exdir[NFILEN];
  1094.     char *exdp;
  1095. #if MSDOS
  1096.     int curd = curdrive();
  1097. #endif
  1098.     WINDOW *wp;
  1099.  
  1100.     for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
  1101.     wp->w_flag |= WFMODE;
  1102.  
  1103.     strcpy(exdir, dir);
  1104.  
  1105.     exdp = exdir;
  1106.  
  1107.     if (glob(exdp)) {
  1108. #if MSDOS
  1109.     if (isupper(exdp[0]) && exdp[1] == ':') {
  1110.         if (setdrive(exdp[0]) == TRUE) {
  1111.             exdp += 2;
  1112.             if (!*exdp) {
  1113.                 pwd(TRUE,1);
  1114.                 return TRUE;
  1115.             }
  1116.         } else {
  1117.             return FALSE;
  1118.         }
  1119.     }
  1120. #endif
  1121.     if (chdir(exdp) == 0) {
  1122.         pwd(TRUE,1);
  1123.         return TRUE;
  1124.     }
  1125.     }
  1126. #if MSDOS
  1127.     setdrive(curd);
  1128.     current_directory(TRUE);
  1129. #endif
  1130.     mlforce("[Couldn't change to \"%s\"]", exdir);
  1131.     return FALSE;
  1132. }
  1133.  
  1134. void
  1135. ch_fname(bp,fname)
  1136. BUFFER *bp;
  1137. char *fname;
  1138. {
  1139.     int len;
  1140.     char nfilen[512];
  1141.     char *np;
  1142.     char *holdp = NULL;
  1143.     char *cwd;
  1144.     char *name;
  1145.  
  1146.     name = fname;
  1147.  
  1148.     /* produce a full pathname, unless already absolute or "internal" */
  1149.     np = name;
  1150.     if (name[0] != '\0' && name[0] != '[' && name[0] != '!') {
  1151. #if MSDOS
  1152.         char drive = 0;
  1153.         if (isupper(np[0]) && np[1] == ':') {
  1154.             drive = *np;
  1155.             np += 2;
  1156.         }
  1157.         cwd = curr_dir_on_drive(drive);
  1158. #else
  1159.         cwd = current_directory(FALSE);
  1160. #endif
  1161.         if (np[0] != slash && cwd != NULL) {
  1162.             lsprintf(nfilen, "%s%c%s", cwd, slash, np );
  1163.             np = canonpath(nfilen);
  1164.         } else {
  1165.             np = canonpath(name);
  1166.         }
  1167.     }
  1168.  
  1169.     len = strlen(np)+1;
  1170.  
  1171.     if (bp->b_fname && bp->b_fnlen < len ) {
  1172.         /* don't free it yet -- it _may_ have been passed in as name */
  1173.         holdp = bp->b_fname;
  1174.         bp->b_fname = NULL;
  1175.     }
  1176.  
  1177.     if (!bp->b_fname) {
  1178.         bp->b_fname = strmalloc(np);
  1179.         if (!bp->b_fname) {
  1180.             bp->b_fname = "NO MEMORY";
  1181.             bp->b_fnlen = 9;
  1182.             return;
  1183.         }
  1184.         bp->b_fnlen = len;
  1185.     }
  1186.  
  1187.     /* it'll fit, leave len untouched */
  1188.     strcpy(bp->b_fname, np);
  1189.     if (holdp)
  1190.         free(holdp);
  1191. }
  1192.