home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume33 / xvi / part14 < prev    next >
Encoding:
Text File  |  1992-11-01  |  55.3 KB  |  2,604 lines

  1. Newsgroups: comp.sources.misc
  2. From: jmd@cyclone.bt.co.uk (John Downey)
  3. Subject:  v33i023:  xvi - portable multi-window vi-like editor, Part14/18
  4. Message-ID: <1992Oct24.172505.2306@sparky.imd.sterling.com>
  5. X-Md4-Signature: a5250c1c495f2b1e0480fec378fce6b3
  6. Date: Sat, 24 Oct 1992 17:25:05 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: jmd@cyclone.bt.co.uk (John Downey)
  10. Posting-number: Volume 33, Issue 23
  11. Archive-name: xvi/part14
  12. Environment: Unix, MS-DOS, OS/2, QNX
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then feed it
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # Contents:  xvi/src/map.c xvi/src/misccmds.c xvi/src/msdos_c.c
  19. #   xvi/src/sunback.c xvi/src/tos.c
  20. # Wrapped by kent@sparky on Thu Oct 22 09:03:44 1992
  21. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  22. echo If this archive is complete, you will see the following message:
  23. echo '          "shar: End of archive 14 (of 18)."'
  24. if test -f 'xvi/src/map.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'xvi/src/map.c'\"
  26. else
  27.   echo shar: Extracting \"'xvi/src/map.c'\" \(10435 characters\)
  28.   sed "s/^X//" >'xvi/src/map.c' <<'END_OF_FILE'
  29. X/* Copyright (c) 1990,1991,1992 Chris and John Downey */
  30. X#ifndef lint
  31. Xstatic char *sccsid = "@(#)map.c    2.1 (Chris & John Downey) 7/29/92";
  32. X#endif
  33. X
  34. X/***
  35. X
  36. X* program name:
  37. X    xvi
  38. X* function:
  39. X    PD version of UNIX "vi" editor, with extensions.
  40. X* module name:
  41. X    map.c
  42. X* module function:
  43. X    Keyboard input/pushback routines, "map" command.
  44. X
  45. X    Note that we provide key mapping through a different interface,
  46. X    so that cursor key mappings etc do not show up to the user.
  47. X    This works by having a two-stage process; first keymapping is
  48. X    done, and then the result is fed through the normal mapping
  49. X    process. The intent of the keymapping stage is to convert
  50. X    machine-local keys into a standard form.
  51. X
  52. X* bug:
  53. X    If a map fails, we just pass all characters which had already
  54. X    been accepted, plus the character which caused the mismatch,
  55. X    straight through. This is not quite correct because we might
  56. X    have got a good match starting at the very next character, i.e.
  57. X    if we have mapped
  58. X
  59. X        foo    to    bar
  60. X
  61. X    and get input "ffoo", then the seconf 'f' will cause the map to
  62. X    fail and both characters will go through, and so the whole thing
  63. X    will pass through unmapped.
  64. X
  65. X    The only way around this problem is to introduce another flexbuf
  66. X    on the input side of the keymap stage, to give us somewhere to
  67. X    put all characters after the first, when a map fails. I.e. in the
  68. X    case above, we would pass the first 'f' through to the "mp_dest"
  69. X    flexbuf, and stuff any characters after that into "mp_src".
  70. X
  71. X* history:
  72. X    STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  73. X    Originally by Tim Thompson (twitch!tjt)
  74. X    Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  75. X    Heavily modified by Chris & John Downey
  76. X
  77. X***/
  78. X
  79. X#include "xvi.h"
  80. X
  81. X/*
  82. X * This is the fundamental structure type which is used
  83. X * to hold mappings from one string to another.
  84. X */
  85. Xtypedef struct map {
  86. X    struct map        *m_next;
  87. X    char        *m_lhs;        /* lhs of map */
  88. X    char        *m_rhs;        /* rhs of map */
  89. X    unsigned int    m_same;        /* no characters same as next map */
  90. X} Map;
  91. X
  92. X/*
  93. X * This structure holds a current position while scanning a map list.
  94. X * It is also effectively used to form a chain of mapping structures,
  95. X * interconnected with flexbufs.
  96. X */
  97. Xtypedef struct mpos {
  98. X    Map        *mp_map;
  99. X    int        mp_index;
  100. X    Flexbuf    *mp_src;
  101. X    Flexbuf    *mp_dest;
  102. X} Mpos;
  103. X
  104. X/*
  105. X * Two mapping structures exist; one for "map", and one for "map!".
  106. X */
  107. Xstatic    Map    *cmd_map = NULL;
  108. Xstatic    Map    *ins_map = NULL;
  109. Xstatic    Map    *key_map = NULL;
  110. X
  111. X/*
  112. X * This is the position in cmd_map/ins_map when we are waiting for
  113. X * the next character. When not waiting, mp_map is NULL (as at start).
  114. X * Also stores flexbuf pointers for input and output at each stage.
  115. X */
  116. Xstatic    Flexbuf    getcbuff;
  117. Xstatic    Flexbuf inputbuff;
  118. Xstatic    Mpos    npos = { NULL, 0, &inputbuff,    &getcbuff };
  119. Xstatic    Mpos    kpos = { NULL, 0, NULL,        &inputbuff };
  120. X
  121. X/*
  122. X * This is used for "display" mode; it records the current map which
  123. X * is being displayed. It is used by show_map().
  124. X */
  125. Xstatic    Map    *curmap;
  126. Xstatic    char    *show_map P((void));
  127. X
  128. Xstatic    void    mapthrough P((void));
  129. Xstatic    bool_t    process_map P((int, Mpos *));
  130. Xstatic    void    calc_same P((Map *));
  131. Xstatic    void    map_failed P((Mpos *));
  132. Xstatic    void    insert_map P((Map **, char *, char *, bool_t));
  133. Xstatic    void    delete_map P((Map **, char *));
  134. X
  135. X/*VARARGS1*/
  136. X/*PRINTFLIKE*/
  137. Xvoid
  138. Xstuff
  139. X#ifdef    __STDC__
  140. X    (char *format, ...)
  141. X#else /* not __STDC__ */
  142. X    (format, va_alist)
  143. X    char    *format;
  144. X    va_dcl
  145. X#endif
  146. X{
  147. X    va_list    argp;
  148. X
  149. X    VA_START(argp, format);
  150. X    (void) vformat(npos.mp_dest, format, argp);
  151. X    va_end(argp);
  152. X}
  153. X
  154. Xint
  155. Xmap_getc()
  156. X{
  157. X    return(flexempty(npos.mp_dest) ? EOF : flexpopch(npos.mp_dest));
  158. X}
  159. X
  160. Xvoid
  161. Xmap_char(c)
  162. Xregister int    c;
  163. X{
  164. X    /*
  165. X     * Send the input character through the keymap list.
  166. X     */
  167. X    if (kpos.mp_map == NULL) {
  168. X        kpos.mp_map = key_map;
  169. X    kpos.mp_index = 0;
  170. X    }
  171. X    if (process_map(c, &kpos) == FALSE) {
  172. X    /*
  173. X     * Send resulting output through the normal map list.
  174. X     */
  175. X    kpos.mp_map = NULL;
  176. X    mapthrough();
  177. X    }
  178. X}
  179. X
  180. X/*
  181. X * Process any characters in the input buffer through the
  182. X * cmd_map/ins_map lists into the output buffer, whence
  183. X * characters go into the editor itself.
  184. X */
  185. Xstatic void
  186. Xmapthrough()
  187. X{
  188. X    while (!flexempty(npos.mp_src)) {
  189. X    if (npos.mp_map == NULL) {
  190. X        if (State == NORMAL) {
  191. X        npos.mp_map = cmd_map;
  192. X        } else if (State == INSERT || State == REPLACE) {
  193. X        npos.mp_map = ins_map;
  194. X        }
  195. X        npos.mp_index = 0;
  196. X    }
  197. X
  198. X    if (process_map(flexpopch(npos.mp_src), &npos) == FALSE) {
  199. X        npos.mp_map = NULL;
  200. X    }
  201. X    }
  202. X}
  203. X
  204. X/*
  205. X * Process the given character through the maplist pointed to
  206. X * by the given position. Returns TRUE if we should continue,
  207. X * or FALSE if this attempt at mapping has terminated (either
  208. X * due to success or definite failure).
  209. X */
  210. Xstatic bool_t
  211. Xprocess_map(c, pos)
  212. Xregister int    c;
  213. Xregister Mpos    *pos;
  214. X{
  215. X    register Map    *tmp;
  216. X    register int    ind;
  217. X
  218. X    ind = pos->mp_index;
  219. X    for (tmp = pos->mp_map; tmp != NULL; tmp = tmp->m_next) {
  220. X    if (tmp->m_lhs[ind] == c) {
  221. X        if (tmp->m_lhs[ind + 1] == '\0') {
  222. X        /*
  223. X         * Found complete match. Insert the result into
  224. X         * the appropriate output buffer, according to
  225. X         * whether "remap" is set or not.
  226. X         */
  227. X        (void) lformat((Pb(P_remap) && pos->mp_src != NULL) ?
  228. X                pos->mp_src : pos->mp_dest, "%s", tmp->m_rhs);
  229. X        return(FALSE);
  230. X        } else {
  231. X        /*
  232. X         * Found incomplete match,
  233. X         * keep going.
  234. X         */
  235. X        pos->mp_map = tmp;
  236. X        pos->mp_index++;
  237. X        }
  238. X        return(TRUE);
  239. X    }
  240. X
  241. X    /*
  242. X     * Can't move on to next map entry unless the m_same
  243. X     * field is sufficient that the match so far would
  244. X     * have worked.
  245. X     */
  246. X    if (tmp->m_same < ind) {
  247. X        break;
  248. X    }
  249. X    }
  250. X
  251. X    map_failed(pos);
  252. X
  253. X    /*
  254. X     * Don't forget to re-stuff the character we have just received.
  255. X     */
  256. X    (void) flexaddch(pos->mp_dest, c);
  257. X    return(FALSE);
  258. X}
  259. X
  260. Xvoid
  261. Xmap_timeout()
  262. X{
  263. X    if (kpos.mp_map != NULL) {
  264. X    map_failed(&kpos);
  265. X    mapthrough();
  266. X    } else {
  267. X        map_failed(&npos);
  268. X    }
  269. X}
  270. X
  271. Xbool_t
  272. Xmap_waiting()
  273. X{
  274. X    return(kpos.mp_map != NULL || npos.mp_map != NULL);
  275. X}
  276. X
  277. X/*
  278. X * This routine is called when a timeout has occurred.
  279. X */
  280. Xstatic void
  281. Xmap_failed(pos)
  282. XMpos    *pos;
  283. X{
  284. X    register char    *cp;
  285. X    register Flexbuf    *fbp;
  286. X    register int    i;
  287. X
  288. X    if (pos->mp_map != NULL) {
  289. X    fbp = pos->mp_dest;
  290. X    for (i = 0, cp = pos->mp_map->m_lhs; i < pos->mp_index; i++) {
  291. X        (void) flexaddch(fbp, cp[i]);
  292. X    }
  293. X    pos->mp_map = NULL;
  294. X    }
  295. X}
  296. X
  297. X/*
  298. X * Insert the key map lhs as mapping into rhs.
  299. X */
  300. Xvoid
  301. Xxvi_keymap(lhs, rhs)
  302. Xchar    *lhs;
  303. Xchar    *rhs;
  304. X{
  305. X    insert_map(&key_map, lhs, rhs, FALSE);
  306. X}
  307. X
  308. X/*
  309. X * Insert the entry "lhs" as mapping into "rhs".
  310. X */
  311. Xvoid
  312. Xxvi_map(argc, argv, exclam, inter)
  313. Xint    argc;
  314. Xchar    *argv[];
  315. Xbool_t    exclam;
  316. Xbool_t    inter;
  317. X{
  318. X    switch (argc) {
  319. X    case 2:                /* valid input */
  320. X    if (argv[0][0] == '\0') {
  321. X        if (inter) {
  322. X        show_message(curwin, "Usage: map lhs rhs");
  323. X        }
  324. X        return;
  325. X    }
  326. X    insert_map(exclam ? &ins_map : &cmd_map, argv[0], argv[1], inter);
  327. X    break;
  328. X
  329. X    case 0:
  330. X    curmap = exclam ? ins_map : cmd_map;
  331. X    disp_init(curwin, show_map, (int) curwin->w_ncols, FALSE);
  332. X    break;
  333. X
  334. X    default:
  335. X    if (inter) {
  336. X        show_message(curwin, "Wrong number of arguments to map");
  337. X    }
  338. X    }
  339. X}
  340. X
  341. Xstatic void
  342. Xinsert_map(maplist, left, right, interactive)
  343. XMap        **maplist;
  344. Xchar        *left;
  345. Xchar        *right;
  346. Xbool_t        interactive;
  347. X{
  348. X    char    *lhs;            /* saved lhs of map */
  349. X    char    *rhs;            /* saved rhs of map */
  350. X    Map        *mptr;            /* new map element */
  351. X    Map        **p;            /* used for loop to find position */
  352. X    int        rel;
  353. X
  354. X    lhs = strsave(left);
  355. X    if (lhs == NULL || (rhs = strsave(right)) == NULL) {
  356. X    if (interactive) {
  357. X        show_message(curwin, "no memory for that map");
  358. X    }
  359. X    return;
  360. X    }
  361. X
  362. X    mptr = (Map *) alloc(sizeof(Map));
  363. X    if (mptr == NULL) {
  364. X    free(lhs);
  365. X    free(rhs);
  366. X    return;
  367. X    }
  368. X
  369. X    mptr->m_lhs = lhs;
  370. X    mptr->m_rhs = rhs;
  371. X
  372. X    p = maplist;
  373. X    if ((*p) == NULL || strcmp((*p)->m_lhs, lhs) > 0) {
  374. X    /*
  375. X     * Either there are no maps yet, or the one
  376. X     * we want to enter should go at the start.
  377. X     */
  378. X    mptr->m_next = *p;
  379. X    *p = mptr;
  380. X    calc_same(mptr);
  381. X    } else if (strcmp((*p)->m_lhs, lhs) == 0) {
  382. X    /*
  383. X     * We need to replace the rhs of the first map.
  384. X     */
  385. X    free(lhs);
  386. X    free((char *) mptr);
  387. X    free((*p)->m_rhs);
  388. X    (*p)->m_rhs = rhs;
  389. X    calc_same(*p);
  390. X    } else {
  391. X    for ( ; (*p) != NULL; p = &((*p)->m_next)) {
  392. X        /*
  393. X         * Set "rel" to +ve if the next element is greater
  394. X         * than the current one, -ve if it is less, or 0
  395. X         * if they are the same (if the lhs is the same).
  396. X         */
  397. X        rel = ((*p)->m_next == NULL) ? 1 :
  398. X        strcmp((*p)->m_next->m_lhs, lhs);
  399. X
  400. X        if (rel >= 0) {
  401. X        if (rel > 0) {
  402. X            /*
  403. X             * The right place to insert
  404. X             * the new map.
  405. X             */
  406. X            mptr->m_next = (*p)->m_next;
  407. X            (*p)->m_next = mptr;
  408. X            calc_same(*p);
  409. X            calc_same(mptr);
  410. X        } else /* rel == 0 */ {
  411. X            /*
  412. X             * The lhs of the new map is identical
  413. X             * to that of an existing map.
  414. X             * Replace the old rhs with the new.
  415. X             */
  416. X            free(lhs);
  417. X            free((char *) mptr);
  418. X            mptr = (*p)->m_next;
  419. X            free(mptr->m_rhs);
  420. X            mptr->m_rhs = rhs;
  421. X            calc_same(mptr);
  422. X        }
  423. X        return;
  424. X        }
  425. X    }
  426. X    }
  427. X}
  428. X
  429. Xvoid
  430. Xxvi_unmap(argc, argv, exclam, inter)
  431. Xint    argc;
  432. Xchar    *argv[];
  433. Xbool_t    exclam;
  434. Xbool_t    inter;
  435. X{
  436. X    int    count;
  437. X
  438. X    if (argc < 1) {
  439. X    if (inter) {
  440. X        show_message(curwin, "But what do you want me to unmap?");
  441. X    }
  442. X    return;
  443. X    }
  444. X
  445. X    for (count = 0; count < argc; count++) {
  446. X    delete_map(exclam ? &ins_map : &cmd_map, argv[count]);
  447. X    }
  448. X}
  449. X
  450. Xstatic void
  451. Xdelete_map(maplist, lhs)
  452. XMap    **maplist;
  453. Xchar    *lhs;
  454. X{
  455. X    Map    *p;
  456. X
  457. X    p = *maplist;
  458. X    if (p != NULL && strcmp(p->m_lhs, lhs) == 0) {
  459. X    *maplist = p->m_next;
  460. X    } else {
  461. X    for (; p != NULL; p = p->m_next) {
  462. X        if (p->m_next != NULL && strcmp(lhs, p->m_next->m_lhs) == 0) {
  463. X        Map    *tmp;
  464. X
  465. X        tmp = p->m_next;
  466. X        p->m_next = p->m_next->m_next;
  467. X        free(tmp->m_lhs);
  468. X        free(tmp->m_rhs);
  469. X        free((char *) tmp);
  470. X        calc_same(p);
  471. X        }
  472. X    }
  473. X    }
  474. X}
  475. X
  476. Xstatic void
  477. Xcalc_same(mptr)
  478. XMap    *mptr;
  479. X{
  480. X    register char    *a, *b;
  481. X
  482. X    mptr->m_same = 0;
  483. X    if (mptr->m_next != NULL) {
  484. X    for (a = mptr->m_lhs, b = mptr->m_next->m_lhs; *a == *b; a++, b++) {
  485. X        mptr->m_same++;
  486. X    }
  487. X    }
  488. X}
  489. X
  490. Xstatic char *
  491. Xshow_map()
  492. X{
  493. X    static Flexbuf    buf;
  494. X
  495. X    /*
  496. X     * Have we reached the end?
  497. X     */
  498. X    if (curmap == NULL) {
  499. X    return(NULL);
  500. X    }
  501. X
  502. X    flexclear(&buf);
  503. X    (void) lformat(&buf, "%-18.18s %-s", curmap->m_lhs, curmap->m_rhs);
  504. X    curmap = curmap->m_next;
  505. X    return flexgetstr(&buf);
  506. X}
  507. END_OF_FILE
  508.   if test 10435 -ne `wc -c <'xvi/src/map.c'`; then
  509.     echo shar: \"'xvi/src/map.c'\" unpacked with wrong size!
  510.   fi
  511.   # end of 'xvi/src/map.c'
  512. fi
  513. if test -f 'xvi/src/misccmds.c' -a "${1}" != "-c" ; then 
  514.   echo shar: Will not clobber existing file \"'xvi/src/misccmds.c'\"
  515. else
  516.   echo shar: Extracting \"'xvi/src/misccmds.c'\" \(11158 characters\)
  517.   sed "s/^X//" >'xvi/src/misccmds.c' <<'END_OF_FILE'
  518. X/* Copyright (c) 1990,1991,1992 Chris and John Downey */
  519. X#ifndef lint
  520. Xstatic char *sccsid = "@(#)misccmds.c    2.2 (Chris & John Downey) 8/28/92";
  521. X#endif
  522. X
  523. X/***
  524. X
  525. X* program name:
  526. X    xvi
  527. X* function:
  528. X    PD version of UNIX "vi" editor, with extensions.
  529. X* module name:
  530. X    misccmds.c
  531. X* module function:
  532. X    Miscellaneous functions.
  533. X
  534. X    This module will probably get hacked later and split
  535. X    up more sensibly.
  536. X* history:
  537. X    STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  538. X    Originally by Tim Thompson (twitch!tjt)
  539. X    Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  540. X    Heavily modified by Chris & John Downey
  541. X
  542. X***/
  543. X
  544. X#include "xvi.h"
  545. X
  546. X/*
  547. X * Add a blank line above or below the current line.
  548. X * Returns TRUE for success, FALSE for failure to get memory.
  549. X *
  550. X * The single boolean parameter tells us whether to split the
  551. X * current line at the cursor position, or just to open a new
  552. X * line leaving the current one intact.
  553. X */
  554. Xbool_t
  555. Xopenfwd(split_line)
  556. Xbool_t    split_line;
  557. X{
  558. X    Line        *l;        /* pointer to newly allocated line */
  559. X    register Posn    *oldposn;
  560. X    register Line    *oldline;
  561. X    register char    *otext;
  562. X
  563. X    oldposn = curwin->w_cursor;
  564. X    oldline = oldposn->p_line;
  565. X    otext = oldline->l_text;
  566. X
  567. X    /*
  568. X     * First find space for new line.
  569. X     *
  570. X     * By asking for as much space as the prior line had we make sure
  571. X     * that we'll have enough space for any auto-indenting.
  572. X     */
  573. X    l = newline(strlen(otext) + SLOP);
  574. X    if (l == NULL)
  575. X    return(FALSE);
  576. X
  577. X    /*
  578. X     * Link the new line into the list.
  579. X     */
  580. X    repllines(curwin, oldline->l_next, 0L, l);
  581. X
  582. X    /*
  583. X     * Do auto-indent.
  584. X     */
  585. X    if (Pb(P_autoindent)) {
  586. X    *l->l_text = '\0';
  587. X    indentchars = set_indent(l, get_indent(oldline));
  588. X    } else {
  589. X    indentchars = 0;
  590. X    }
  591. X
  592. X    /*
  593. X     * If we're in insert mode, we need to move the remainder of the
  594. X     * current line onto the new line. Otherwise the new line is left
  595. X     * blank.
  596. X     */
  597. X    if (split_line) {
  598. X    char    *s;
  599. X
  600. X    s = otext + oldposn->p_index;
  601. X
  602. X    replchars(curwin, l, indentchars, 0, s);
  603. X    replchars(curwin, oldline, oldposn->p_index, strlen(s), "");
  604. X    }
  605. X
  606. X    /*
  607. X     * Move cursor to the new line.
  608. X     */
  609. X    move_cursor(curwin, l, indentchars);
  610. X    move_window_to_cursor(curwin);
  611. X    cursupdate(curwin);
  612. X    update_buffer(curbuf);
  613. X
  614. X    return(TRUE);
  615. X}
  616. X
  617. X/*
  618. X * Add a blank line above the current line.
  619. X * Returns TRUE for success, FALSE for failure to get memory.
  620. X */
  621. Xbool_t
  622. Xopenbwd()
  623. X{
  624. X    Line        *l;
  625. X    register Line    *oldline;
  626. X    register char    *otext;
  627. X
  628. X    oldline = curwin->w_cursor->p_line;
  629. X    otext = oldline->l_text;
  630. X
  631. X    /*
  632. X     * First find space for new line.
  633. X     */
  634. X    l = newline(strlen(otext) + SLOP);
  635. X    if (l == NULL)
  636. X    return(FALSE);
  637. X
  638. X    /*
  639. X     * Link the new line into the list.
  640. X     */
  641. X    repllines(curwin, oldline, 0L, l);
  642. X
  643. X    /*
  644. X     * Do auto-indent.
  645. X     */
  646. X    if (Pb(P_autoindent)) {
  647. X    *l->l_text = '\0';
  648. X    indentchars = set_indent(l, get_indent(oldline));
  649. X    } else {
  650. X    indentchars = 0;
  651. X    }
  652. X
  653. X    /*
  654. X     * Ensure the cursor is pointing at the right line.
  655. X     */
  656. X    move_cursor(curwin, l, indentchars);
  657. X    move_window_to_cursor(curwin);
  658. X    cursupdate(curwin);
  659. X    update_buffer(curbuf);
  660. X
  661. X    return(TRUE);
  662. X}
  663. X
  664. X/*
  665. X * Count the number of lines between the two given lines.
  666. X * If the two given lines are the same, the return value
  667. X * is 1, not 0; i.e. the count is inclusive.
  668. X *
  669. X * Note that this function has been changed to give the
  670. X * correct number of lines, even if they are ordered wrongly.
  671. X * This change is backwards-compatible with the old version.
  672. X */
  673. Xlong
  674. Xcntllines(pbegin, pend)
  675. XLine        *pbegin;
  676. Xregister Line    *pend;
  677. X{
  678. X    register Line    *lp;
  679. X    register long    lnum;
  680. X    bool_t        swapped = FALSE;
  681. X
  682. X    /*
  683. X     * Ensure correct ordering.
  684. X     */
  685. X    if (later(pbegin, pend)) {
  686. X    lp = pbegin;
  687. X    pbegin = pend;
  688. X    pend = lp;
  689. X    swapped = TRUE;
  690. X    }
  691. X
  692. X    for (lnum = 1, lp = pbegin; lp != pend; lp = lp->l_next) {
  693. X    lnum++;
  694. X    }
  695. X
  696. X    if (swapped)
  697. X    lnum = - lnum;
  698. X
  699. X    return(lnum);
  700. X}
  701. X
  702. X/*
  703. X * plines(lp) - return the number of physical screen lines taken by line 'lp'.
  704. X */
  705. Xlong
  706. Xplines(win, lp)
  707. XXviwin    *win;
  708. XLine    *lp;
  709. X{
  710. X    register long    col;
  711. X    register char    *s;
  712. X
  713. X    s = lp->l_text;
  714. X
  715. X    if (*s == '\0')        /* empty line */
  716. X    return(1);
  717. X
  718. X    /*
  719. X     * If list mode is on, then the '$' at the end of
  720. X     * the line takes up one extra column.
  721. X     */
  722. X    col = Pb(P_list) ? 1 : 0;
  723. X
  724. X    if (Pb(P_number)) {
  725. X    col += NUM_SIZE;
  726. X    }
  727. X
  728. X    for ( ; *s != '\0'; s++) {
  729. X    col += vischar(*s, (char **) NULL, (int) col);
  730. X    }
  731. X
  732. X    {
  733. X    register int    row;
  734. X    register int    columns;
  735. X
  736. X    columns = win->w_ncols;
  737. X    for (row = 1; col > columns; ) {
  738. X        row++;
  739. X        col -= columns;
  740. X    }
  741. X    return row;
  742. X    }
  743. X}
  744. X
  745. X/*
  746. X * Count the number of physical lines between the two given lines.
  747. X *
  748. X * This routine is like cntllines(), except that:
  749. X *    it counts physical rather than logical lines
  750. X *    it always returns the absolute number of physical lines
  751. X *    it is non-inclusive
  752. X *    if the physical line count for a group of lines is greater
  753. X *    than or equal to rows * 2, we just return rows * 2; we assume
  754. X *    the caller isn't interested in the exact number.
  755. X */
  756. Xlong
  757. Xcntplines(win, pbegin, pend)
  758. XXviwin        *win;
  759. XLine        *pbegin;
  760. Xregister Line    *pend;
  761. X{
  762. X    register Line    *lp;
  763. X    register long    physlines;
  764. X    unsigned        toomuch;
  765. X
  766. X    /*
  767. X     * Ensure correct ordering.
  768. X     */
  769. X    if (later(pbegin, pend)) {
  770. X    lp = pbegin;
  771. X    pbegin = pend;
  772. X    pend = lp;
  773. X    }
  774. X
  775. X    toomuch = win->w_nrows * 2;
  776. X    for (physlines = 0, lp = pbegin; lp != pend; lp = lp->l_next) {
  777. X    physlines += plines(win, lp);
  778. X    if (physlines >= toomuch)
  779. X        break;
  780. X    }
  781. X
  782. X    return(physlines);
  783. X}
  784. X
  785. X/*
  786. X * gotoline(buffer, n) - return a pointer to line 'n' in the given buffer
  787. X *
  788. X * Returns the first line of the file if n is 0.
  789. X * Returns the last line of the file if n is beyond the end of the file.
  790. X */
  791. XLine *
  792. Xgotoline(b, n)
  793. XBuffer            *b;
  794. Xregister unsigned long    n;
  795. X{
  796. X    if (n == 0) {
  797. X    return(b->b_file);
  798. X    } else {
  799. X    register Line    *lp;
  800. X
  801. X    for (lp = b->b_file; --n > 0 && lp->l_next != b->b_lastline;
  802. X                            lp = lp->l_next) {
  803. X        ;
  804. X    }
  805. X    return(lp);
  806. X    }
  807. X}
  808. X
  809. Xint
  810. Xget_indent(lp)
  811. Xregister Line    *lp;
  812. X{
  813. X    register char   *text;
  814. X    register int    indent;
  815. X    register int    ts = Pn(P_tabstop);    /* synonym for efficiency */
  816. X
  817. X    if (lp == NULL || (text = lp->l_text) == NULL) {
  818. X    show_error(curwin, "Internal error: get_indent(NULL)");
  819. X    return 0;
  820. X    }
  821. X
  822. X    for (indent = 0; *text != '\0' && (*text == ' ' || *text == '\t');
  823. X                                    text++) {
  824. X    indent += *text == ' ' ? 1 : ts - indent % ts;
  825. X    }
  826. X    return indent;
  827. X}
  828. X
  829. X/*
  830. X * Set number of columns of leading whitespace on line, regardless of
  831. X * what was there before, & return number of characters (not columns)
  832. X * used.
  833. X */
  834. Xint
  835. Xset_indent(lp, indent)
  836. XLine        *lp;
  837. Xregister int    indent;
  838. X{
  839. X    register char    *cp;        /* temp char pointer for loops */
  840. X    register int    ntabs;        /* number of tabs to use */
  841. X    unsigned        nnew;        /* no of chars used in old line */
  842. X    unsigned        nold;        /* no of chars used in new version */
  843. X    char        *newstr;    /* allocated string for new indent */
  844. X
  845. X    if (lp == NULL || lp->l_text == NULL) {
  846. X    show_error(curwin, "Internal error: set_indent(0)");
  847. X    return(0);
  848. X    }
  849. X
  850. X    /*
  851. X     * Find out how many tabs we need, & how many spaces.
  852. X     */
  853. X    for (ntabs = 0; indent >= Pn(P_tabstop); ntabs++)
  854. X    indent -= Pn(P_tabstop);
  855. X
  856. X    /*
  857. X     * Find out how many characters were used for initial
  858. X     * whitespace in the current (old) line.
  859. X     */
  860. X    for (cp = lp->l_text; *cp == ' ' || *cp == '\t'; cp++) {
  861. X    ;
  862. X    }
  863. X    nold = cp - lp->l_text;
  864. X
  865. X    /*
  866. X     * "nnew" is the number of characters we will use
  867. X     * for indentation in the new version of the line.
  868. X     */
  869. X    nnew = ntabs + indent;
  870. X
  871. X    /*
  872. X     * Get some space, and place into it the string of tabs
  873. X     * and spaces which will form the new indentation.
  874. X     * If no space available, return nold as we have not
  875. X     * changed the line; this is the correct action.
  876. X     */
  877. X    newstr = alloc((unsigned) nnew + 1);
  878. X    if (newstr == NULL)
  879. X    return(nold);
  880. X
  881. X    cp = newstr;
  882. X    while (ntabs-- > 0)
  883. X    *cp++ = '\t';
  884. X    while (indent-- > 0)
  885. X    *cp++ = ' ';
  886. X    *cp = '\0';
  887. X
  888. X    /*
  889. X     * Finally, replace the old with the new.
  890. X     */
  891. X    replchars(curwin, lp, 0, (int) nold, newstr);
  892. X
  893. X    free(newstr);
  894. X
  895. X    return(nnew);
  896. X}
  897. X
  898. X/*
  899. X * tabinout(inout, start, finish)
  900. X *
  901. X * "inout" is either '<' or '>' to indicate left or right shift.
  902. X */
  903. Xvoid
  904. Xtabinout(inout, start, finish)
  905. Xint    inout;
  906. XLine    *start;
  907. XLine    *finish;
  908. X{
  909. X    Line    *lp;
  910. X    long    nlines = 0;
  911. X
  912. X    if (!start_command(curwin)) {
  913. X    return;
  914. X    }
  915. X
  916. X    finish = finish->l_next;
  917. X
  918. X    for (lp = start; lp != finish; lp = lp->l_next) {
  919. X    register char *p;
  920. X
  921. X    /*
  922. X     * Find out whether it's a blank line (either
  923. X     * empty or containing only spaces & tabs).
  924. X     * If so, just remove all whitespace from it.
  925. X     */
  926. X    for (p = lp->l_text; *p && (*p == '\t' || *p == ' '); p++)
  927. X        ;
  928. X    if (*p == '\0') {
  929. X        if (p > lp->l_text) {
  930. X        replchars(curwin, lp, 0, p - lp->l_text, "");
  931. X        }
  932. X    } else if (inout == '<') {
  933. X        int oldindent = get_indent(lp);
  934. X
  935. X        (void) set_indent(lp, (oldindent <= Pn(P_shiftwidth) ?
  936. X                    0 : oldindent - Pn(P_shiftwidth)));
  937. X    } else {
  938. X        (void) set_indent(lp, get_indent(lp) + Pn(P_shiftwidth));
  939. X    }
  940. X
  941. X    nlines++;
  942. X    }
  943. X
  944. X    end_command(curwin);
  945. X
  946. X    if (nlines > Pn(P_report)) {
  947. X    show_message(curwin, "%ld lines %ced", nlines, inout);
  948. X    }
  949. X}
  950. X
  951. X/*
  952. X * Construct a vector of pointers into each word in
  953. X * the given string. Intervening whitespace will be
  954. X * converted to null bytes.
  955. X *
  956. X * Returned vector is constructed in allocated space,
  957. X * and so must be freed after use.
  958. X *
  959. X * An extra NULL pointer is always allocated for safety.
  960. X *
  961. X * If memory cannot be allocated, or if there are no
  962. X * words in the given string, or if it is a NULL ptr,
  963. X * then the returned values will be 0 and NULL.
  964. X *
  965. X * The "whites" argument is a pointer to an array of
  966. X * characters which are to be considered as whitespace.
  967. X */
  968. Xvoid
  969. Xmakeargv(str, argcp, argvp, whites)
  970. Xchar    *str;
  971. Xint    *argcp;
  972. Xchar    ***argvp;
  973. Xchar    *whites;
  974. X{
  975. X    int        argc;
  976. X    char    **argv;
  977. X    int        argv_size;
  978. X
  979. X    *argcp = 0;
  980. X    *argvp = NULL;
  981. X
  982. X    if (str == NULL)
  983. X    return;
  984. X
  985. X    /*
  986. X     * Scan past initial whitespace.
  987. X     */
  988. X    while (*str != '\0' && strchr(whites, *str) != NULL) {
  989. X    if (*str == '\\' && strchr(whites, str[1]) != NULL) {
  990. X        str++;
  991. X    }
  992. X    str++;
  993. X    }
  994. X    if (*str == '\0')
  995. X    return;
  996. X
  997. X    argv = (char **) alloc(sizeof(char *) * 8);
  998. X    if (argv == NULL)
  999. X    return;
  1000. X    argv_size = 8;
  1001. X    argc = 0;
  1002. X
  1003. X    do {
  1004. X    if (argc >= (argv_size - 1)) {
  1005. X        argv_size += 8;
  1006. X        argv = (char **) realloc((char *) argv,
  1007. X                (unsigned) argv_size * sizeof(char *));
  1008. X        if (argv == NULL)
  1009. X        return;
  1010. X    }
  1011. X
  1012. X    argv[argc++] = str;
  1013. X
  1014. X    while (*str != '\0' && strchr(whites, *str) == NULL) {
  1015. X        if (*str == '\\' && strchr(whites, str[1]) != NULL) {
  1016. X        char    *p;
  1017. X
  1018. X        /*
  1019. X         * What a hack. Copy the rest of the string
  1020. X         * down by one byte to remove the backslash.
  1021. X         * Don't forget to copy the null byte.
  1022. X         */
  1023. X        for (p = str + 1; (*(p-1) = *p) != '\0'; p++)
  1024. X            ;
  1025. X        }
  1026. X        str++;
  1027. X    }
  1028. X    while (*str != '\0' && strchr(whites, *str) != NULL)
  1029. X        *str++ = '\0';
  1030. X
  1031. X    } while (*str != '\0');
  1032. X
  1033. X    argv[argc] = NULL;
  1034. X
  1035. X    *argvp = argv;
  1036. X    *argcp = argc;
  1037. X}
  1038. END_OF_FILE
  1039.   if test 11158 -ne `wc -c <'xvi/src/misccmds.c'`; then
  1040.     echo shar: \"'xvi/src/misccmds.c'\" unpacked with wrong size!
  1041.   fi
  1042.   # end of 'xvi/src/misccmds.c'
  1043. fi
  1044. if test -f 'xvi/src/msdos_c.c' -a "${1}" != "-c" ; then 
  1045.   echo shar: Will not clobber existing file \"'xvi/src/msdos_c.c'\"
  1046. else
  1047.   echo shar: Extracting \"'xvi/src/msdos_c.c'\" \(10422 characters\)
  1048.   sed "s/^X//" >'xvi/src/msdos_c.c' <<'END_OF_FILE'
  1049. X/* Copyright (c) 1990,1991,1992 Chris and John Downey */
  1050. X#ifndef lint
  1051. Xstatic char *sccsid = "@(#)msdos_c.c    2.1 (Chris & John Downey) 7/29/92";
  1052. X#endif
  1053. X
  1054. X/***
  1055. X
  1056. X* program name:
  1057. X    xvi
  1058. X* function:
  1059. X    PD version of UNIX "vi" editor, with extensions.
  1060. X* module name:
  1061. X    msdos_c.c
  1062. X* module function:
  1063. X    System interface routines for MS-DOS.
  1064. X
  1065. X    The system interface consists of this module & msdos_a.asm;
  1066. X    the terminal interface for IBM PC compatibles consists of
  1067. X    ibmpc_a.asm & ibmpc_c.c. Some comments on the demarcation
  1068. X    between system interface and terminal interface modules are in
  1069. X    the source.ms document.
  1070. X* history:
  1071. X    STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  1072. X    Originally by Tim Thompson (twitch!tjt)
  1073. X    Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  1074. X    Heavily modified by Chris & John Downey
  1075. X
  1076. X***/
  1077. X
  1078. X#include "xvi.h"
  1079. X
  1080. X#ifdef __ZTC__
  1081. X    /*
  1082. X     * Zortech 3.0 has a really stupid method of specifying
  1083. X     * filename expansion on the command line.
  1084. X     */
  1085. X#   ifdef WILDCARDS
  1086. X    WILDCARDS
  1087. X#   endif /* WILDCARDS */
  1088. X
  1089. X    /*
  1090. X     * Set default stack size. This seems a reasonable compromise.
  1091. X     */
  1092. X    unsigned _stack = 20480;
  1093. X#endif        /* __ZTC__ */
  1094. X
  1095. Xvoid
  1096. Xignore_signals(void)
  1097. X{
  1098. X    msdsignal(&kbdintr);
  1099. X}
  1100. X
  1101. Xvoid
  1102. Xsys_init(void)
  1103. X{
  1104. X    char    *sh;
  1105. X
  1106. X    /*
  1107. X     * Set up a default value for Ps(P_shell). This can be overridden
  1108. X     * by xvi_startup() (in startup.c) if %SHELL% is defined, or if a
  1109. X     * value is given explicitly in the startup
  1110. X     * script.
  1111. X     *
  1112. X     * %COMSPEC% should always be defined on MS-DOS. The system can't
  1113. X     * really run without it.
  1114. X     */
  1115. X    if ((sh = getenv("COMSPEC")) != NULL) {
  1116. X    set_param(P_shell, sh);
  1117. X    }
  1118. X    tty_open(&Rows, &Columns);
  1119. X    sys_startv();
  1120. X}
  1121. X
  1122. Xstatic    enum {
  1123. X    m_SYS = 0,
  1124. X    m_VI
  1125. X}    curmode;
  1126. X
  1127. X/*
  1128. X * Set up video state for editor.
  1129. X */
  1130. Xvoid
  1131. Xsys_startv(void)
  1132. X{
  1133. X    if (curmode == m_SYS) {
  1134. X    tty_startv();
  1135. X    set_colour(Pn(P_colour));
  1136. X    curmode = m_VI;
  1137. X    }
  1138. X}
  1139. X
  1140. X/*
  1141. X * Restore video state to what it was when we started.
  1142. X */
  1143. Xvoid
  1144. Xsys_endv(void)
  1145. X{
  1146. X    if (curmode == m_VI) {
  1147. X    tty_goto(Rows - 1, 0);
  1148. X    set_colour(Pn(P_systemcolour));
  1149. X    erase_line();
  1150. X    tty_endv();
  1151. X    /*
  1152. X     * tty_endv() is responsible for calling
  1153. X     * flush_output().
  1154. X     */
  1155. X    curmode = m_SYS;
  1156. X    }
  1157. X}
  1158. X
  1159. Xvoid
  1160. Xsys_exit(int r)
  1161. X{
  1162. X    sys_endv();
  1163. X    tty_close();
  1164. X    exit(r);
  1165. X}
  1166. X
  1167. X#ifndef W_OK
  1168. X#    define    F_OK    0
  1169. X#    define    W_OK    2
  1170. X#endif
  1171. X
  1172. X/*
  1173. X * Returns TRUE if file does not exist or exists and is writeable.
  1174. X */
  1175. Xbool_t
  1176. Xcan_write(char* file)
  1177. X{
  1178. X#ifdef __ZTC__
  1179. X    struct FIND    *p;
  1180. X
  1181. X    p = findfirst(file, FA_HIDDEN | FA_SYSTEM | FA_DIREC);
  1182. X
  1183. X    return(p == NULL ||
  1184. X       (p->attribute & (FA_RDONLY | FA_HIDDEN | FA_SYSTEM | FA_DIREC)) == 0);
  1185. X#else    /* __ZTC__ */
  1186. X    return access(file, F_OK) != 0 || access(file, W_OK) == 0;
  1187. X#endif    /* __ZTC__ */
  1188. X}
  1189. X
  1190. X#ifndef __ZTC__
  1191. X
  1192. X/*
  1193. X * The Zortech library has this anyway.
  1194. X */
  1195. Xvoid
  1196. Xsleep(n)
  1197. Xunsigned    n;
  1198. X{
  1199. X    /*
  1200. X     * This works with Microsoft C.
  1201. X     */
  1202. X    time_t    start = time((time_t*) 0);
  1203. X
  1204. X    flush_output();
  1205. X    while (time((time_t*) 0) < start + n)
  1206. X    ;
  1207. X}
  1208. X
  1209. X#endif /* not __ZTC__ */
  1210. X
  1211. Xvoid
  1212. Xdelay()
  1213. X{
  1214. X    clock_t start = clock();
  1215. X
  1216. X    flush_output();
  1217. X    while (clock() < start + CLK_TCK / 5)
  1218. X    ;
  1219. X}
  1220. X
  1221. X/*
  1222. X * This function is only used by tempfname(). It constructs a filename
  1223. X * suffix based on an index number.
  1224. X *
  1225. X * The suffix ".$$$" is commonly used for temporary file names on
  1226. X * MS-DOS & OS/2 systems. We also use the sequence ".$$1", ".$$2" ...
  1227. X * ".fff" (all digits are hexadecimal).
  1228. X */
  1229. Xstatic char * near
  1230. Xhexsuffix(i)
  1231. Xunsigned    i;
  1232. X{
  1233. X    static char    suffix [] = ".$$$";
  1234. X    static char    hextab [] = "0123456789abcdef";
  1235. X    char*        sp = &suffix[3];
  1236. X
  1237. X    while (sp > suffix) {
  1238. X    if (i > 0) {
  1239. X        *sp-- = hextab [i & 0xf];
  1240. X        i >>= 4;
  1241. X    } else {
  1242. X        *sp-- = '$';
  1243. X    }
  1244. X    }
  1245. X    return suffix;
  1246. X}
  1247. X
  1248. X/*
  1249. X * Construct unique name for temporary file, to be used as a backup
  1250. X * file for the named file.
  1251. X */
  1252. Xchar*
  1253. Xtempfname(srcname)
  1254. Xchar        *srcname;
  1255. X{
  1256. X    char    *srctail,
  1257. X        *srcdot,
  1258. X        *endp,
  1259. X        *retp;
  1260. X    unsigned    indexnum = 0;
  1261. X    unsigned    baselen;
  1262. X
  1263. X    srctail = srcdot = NULL;
  1264. X    endp = srcname;
  1265. X
  1266. X    while (*endp) {
  1267. X    switch (*endp++) {
  1268. X    case '\\':
  1269. X    case '/':
  1270. X        srctail = endp;
  1271. X        srcdot = (char*) 0;
  1272. X        continue;
  1273. X    case '.':
  1274. X        srcdot = endp - 1;
  1275. X    }
  1276. X    }
  1277. X
  1278. X    if (srctail == NULL) {
  1279. X    /*
  1280. X     * We haven't found any directory separators ('/' or '\\').
  1281. X     */
  1282. X    srctail = srcname;
  1283. X    /*
  1284. X     * Check to see if there's a disk drive name. If there
  1285. X     * is, skip over it.
  1286. X     */
  1287. X    if (*srcname && is_alpha(*srcname) && srcname[1] == ':') {
  1288. X        srctail = &srcname[2];
  1289. X    }
  1290. X    }
  1291. X
  1292. X    /*
  1293. X     * There isn't a dot in the trailing part of the filename:
  1294. X     * just add it at the end.
  1295. X     */
  1296. X    if (srcdot == NULL) {
  1297. X    srcdot = endp;
  1298. X    }
  1299. X
  1300. X    /*
  1301. X     * Don't make name too long.
  1302. X     */
  1303. X    if (srcdot - srctail > MAXNAMLEN - 4)
  1304. X    srcdot = srctail + MAXNAMLEN - 4;
  1305. X    if (srcdot - srcname > MAXPATHLEN - 4)
  1306. X    srcdot = srcname + MAXPATHLEN - 4;
  1307. X    baselen = srcdot - srcname;
  1308. X    /*
  1309. X     * Allocate space for new temporary file name ...
  1310. X     */
  1311. X    if ((retp = alloc(baselen + 5)) == NULL)
  1312. X    return NULL;
  1313. X    if (baselen > 0)
  1314. X    (void) memcpy(retp, srcname, baselen);
  1315. X    do {
  1316. X    /*
  1317. X     * Keep trying this until we get a unique file name.
  1318. X     */
  1319. X    strcpy(&retp[baselen], hexsuffix(indexnum++));
  1320. X    } while (exists(retp));
  1321. X    return retp;
  1322. X}
  1323. X
  1324. X/*
  1325. X * Fake out a pipe by writing output to temp file, running a process with
  1326. X * i/o redirected from this file to another temp file, and then reading
  1327. X * the second temp file back in.
  1328. X */
  1329. Xbool_t
  1330. Xsys_pipe(cmd, writefunc, readfunc)
  1331. Xchar    *cmd;
  1332. Xint    (*writefunc) P((FILE *));
  1333. Xlong    (*readfunc) P((FILE *));
  1334. X{
  1335. X    char    *temp1;
  1336. X    FILE    *fp;
  1337. X    bool_t    retval;
  1338. X
  1339. X    /*
  1340. X     * Create first temporary file ...
  1341. X     */
  1342. X    if ((temp1 = tempfname("xvi_out")) == NULL ||
  1343. X                    (fp = fopen(temp1, "w")) == NULL) {
  1344. X    retval = FALSE;
  1345. X    } else {
  1346. X    char    *temp2 = NULL;
  1347. X    int    savcon;
  1348. X    int    fd1 = -1,
  1349. X        fd2 = -1;
  1350. X
  1351. X    /*
  1352. X     * ... then write to it & close it ...
  1353. X     */
  1354. X    (void) (*writefunc)(fp);
  1355. X    (void) fclose(fp);
  1356. X
  1357. X    /*
  1358. X     * ... then re-open it for reading, open second one
  1359. X     * for writing & re-arrange file descriptors.
  1360. X     *
  1361. X     * Note that we assume that the editor's standard
  1362. X     * input, output & error files are the same device,
  1363. X     * since I can't imagine how any of them could
  1364. X     * usefully be redirected to anything else.
  1365. X     */
  1366. X
  1367. X#ifndef O_BINARY
  1368. X#    define O_BINARY 0
  1369. X#endif
  1370. X#ifndef O_EXCL
  1371. X#    define O_EXCL 0
  1372. X#endif
  1373. X    if (
  1374. X        (savcon = dup(0)) < 3
  1375. X        ||
  1376. X        (fd1 = open(temp1, O_RDONLY | O_BINARY)) < 3
  1377. X        ||
  1378. X        (temp2 = tempfname("xvi_in")) == NULL 
  1379. X        ||
  1380. X        (fd2 = open(temp2, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0600)) < 3
  1381. X    ) {
  1382. X        retval = FALSE;
  1383. X    } else {
  1384. X        (void) dup2(fd1, 0);
  1385. X        (void) dup2(fd2, 1);
  1386. X        (void) dup2(fd2, 2);
  1387. X
  1388. X        (void) close(fd1);
  1389. X        (void) close(fd2);
  1390. X        fd1 = fd2 = -1;
  1391. X
  1392. X        /*
  1393. X         * Run the command.
  1394. X         */
  1395. X        (void) system(cmd);
  1396. X
  1397. X        /*
  1398. X         * Restore our standard input, output & error
  1399. X         * files.
  1400. X         */
  1401. X        (void) dup2(savcon, 0);
  1402. X        (void) dup2(savcon, 1);
  1403. X        (void) dup2(savcon, 2);
  1404. X
  1405. X        /*
  1406. X         * Now read from the second temporary file,
  1407. X         * close it, & we're done.
  1408. X         */
  1409. X        if ((fp = fopen(temp2, "r")) == NULL) {
  1410. X        retval = FALSE;
  1411. X        } else {
  1412. X        (void) (*readfunc)(fp);
  1413. X        (void) fclose(fp);
  1414. X        retval = TRUE;
  1415. X        }
  1416. X    }
  1417. X    /*
  1418. X     * Clean up.
  1419. X     */
  1420. X    if (temp2) {
  1421. X        (void) remove(temp2);
  1422. X        free(temp2);
  1423. X    }
  1424. X    if (savcon > 2)
  1425. X        (void) close(savcon);
  1426. X    if (fd1 > 2)
  1427. X        (void) close(fd1);
  1428. X    if (fd2 > 2)
  1429. X        (void) close(fd2);
  1430. X    }
  1431. X
  1432. X    if (temp1) {
  1433. X    (void) remove(temp1);
  1434. X    free(temp1);
  1435. X    }
  1436. X
  1437. X    return(retval);
  1438. X}
  1439. X
  1440. X#if 0
  1441. X
  1442. X/*
  1443. X * The following functions are untested because neither of us has
  1444. X * access to an MS-DOS compiler at the moment.
  1445. X */
  1446. X
  1447. X/*
  1448. X * Expand environment variables in filename.
  1449. X */
  1450. X
  1451. X#define VMETACHAR    '$'
  1452. X
  1453. Xstatic char * near
  1454. Xvexpand(name)
  1455. X    char        *name;
  1456. X{
  1457. X    static Flexbuf    b;
  1458. X    register char    *p1, *p2;
  1459. X
  1460. X    if ((p2 = strchr(name, VMETACHAR)) == (char *) NULL) {
  1461. X    return name;
  1462. X    }
  1463. X    flexclear(&b);
  1464. X    p1 = name;
  1465. X    while (*p1) {
  1466. X    register int    c;
  1467. X    register char    *val;
  1468. X    Flexbuf        vname;
  1469. X
  1470. X    while (p1 < p2) {
  1471. X        (void) flexaddch(&b, *p1++);
  1472. X    }
  1473. X    flexnew(&vname);
  1474. X    for (p2++; (c = *p2) != '\0' && (is_alnum(c) || c == '_'); p2++) {
  1475. X        (void) flexaddch(&vname, c);
  1476. X    }
  1477. X    if (!flexempty(&vname)
  1478. X        &&
  1479. X        (val = getenv(flexgetstr(&vname))) != (char *) NULL) {
  1480. X        while ((c = *val++) != '\0') {
  1481. X        (void) flexaddch(&b, c);
  1482. X        }
  1483. X        p1 = p2;
  1484. X    }
  1485. X    flexdelete(&vname);
  1486. X    if ((p2 = strchr(p1, VMETACHAR) == (char *) NULL) {
  1487. X        while ((c = *p1) != '\0') {
  1488. X        (void) flexaddch(&b, c);
  1489. X        p1++;
  1490. X        }
  1491. X    }
  1492. X    }
  1493. X    return flexgetstr(&b);
  1494. X}
  1495. X
  1496. Xstatic struct dstat    info;
  1497. X
  1498. Xchar *
  1499. Xfexpand(name)
  1500. X    char        *name;
  1501. X{
  1502. X    static Flexbuf    newname;
  1503. X    char        *lastdelim;
  1504. X    bool_t        has_meta;
  1505. X    register char    *p;
  1506. X
  1507. X    has_meta = FALSE;
  1508. X    lastdelim = (char *) NULL;
  1509. X    for (name = p = vexpand(name); *p; p++) {
  1510. X    switch (*p) {
  1511. X        case ':':
  1512. X        case '\\':
  1513. X        case '/':
  1514. X        lastdelim = p;
  1515. X        /*
  1516. X         * DOS only understands metacharacters in the file's
  1517. X         * base name, not in any directory names.
  1518. X         */
  1519. X        has_meta = FALSE;
  1520. X        continue;
  1521. X        case '*':
  1522. X        case '?':
  1523. X        has_meta = TRUE;
  1524. X        continue;
  1525. X    }
  1526. X    }
  1527. X    if (!has_meta) {
  1528. X    return name;
  1529. X    }
  1530. X    if (statfirst(name, &info, dst_HIDDEN | dst_SYSTEM | dst_DIR) != 0) {
  1531. X    return name;
  1532. X    }
  1533. X    flexclear(&newname);
  1534. X    for (;;) {
  1535. X    register int    c;
  1536. X
  1537. X    if (lastdelim) {
  1538. X        for (p = name; p <= lastdelim;) {
  1539. X        if (!flexaddch(&newname, *p++)) {
  1540. X            break;
  1541. X        }
  1542. X        }
  1543. X    }
  1544. X    for (p = dst_BASENAME(info);
  1545. X         p < &dst_LAST(info) && (c = *p++) != '\0';) {
  1546. X        /*
  1547. X         * DOS gives us the file's base name in nasty CAPITAL
  1548. X         * LETTERS, so we convert them to lower-case here.
  1549. X         */
  1550. X        if (!flexaddch(&newname, is_upper(c) ? to_lower(c) : (c))) {
  1551. X        break;
  1552. X        }
  1553. X    }
  1554. X    /*
  1555. X     * Note the order of events here; we only append a ' ' to
  1556. X     * newname if there's still at least one more file name to
  1557. X     * append after it.
  1558. X     */
  1559. X    if (statnext(&info) != 0) {
  1560. X        break;
  1561. X    }
  1562. X    if (!flexaddch(&newname, ' ')) {
  1563. X        break;
  1564. X    }
  1565. X    }
  1566. X    if (flexempty(&newname)) {
  1567. X    return name;
  1568. X    }
  1569. X    return flexgetstr(&newname);
  1570. X}
  1571. X
  1572. Xbool_t
  1573. Xexists(name)
  1574. X    char * name;
  1575. X{
  1576. X    return statfirst(name, &info, dst_HIDDEN | dst_SYSTEM | dst_DIR) == 0;
  1577. X}
  1578. X
  1579. Xbool_t
  1580. Xcan_write(name)
  1581. X    char * name;
  1582. X{
  1583. X    return statfirst(name, &info, dst_HIDDEN | dst_SYSTEM | dst_DIR) != 0 ||
  1584. X       (info.dst_mode &
  1585. X        (dst_READONLY | dst_HIDDEN | dst_SYSTEM | dst_DIR)) == 0;
  1586. X}
  1587. X
  1588. X#endif    /* 0 */
  1589. END_OF_FILE
  1590.   if test 10422 -ne `wc -c <'xvi/src/msdos_c.c'`; then
  1591.     echo shar: \"'xvi/src/msdos_c.c'\" unpacked with wrong size!
  1592.   fi
  1593.   # end of 'xvi/src/msdos_c.c'
  1594. fi
  1595. if test -f 'xvi/src/sunback.c' -a "${1}" != "-c" ; then 
  1596.   echo shar: Will not clobber existing file \"'xvi/src/sunback.c'\"
  1597. else
  1598.   echo shar: Extracting \"'xvi/src/sunback.c'\" \(10695 characters\)
  1599.   sed "s/^X//" >'xvi/src/sunback.c' <<'END_OF_FILE'
  1600. X#ifndef lint
  1601. Xstatic char *sccsid = "@(#)sunback.c    2.1 (Chris & John Downey) 7/29/92";
  1602. X#endif
  1603. X
  1604. X/***
  1605. X
  1606. X* program name:
  1607. X    xvi
  1608. X* function:
  1609. X    PD version of UNIX "vi" editor, with extensions.
  1610. X* module name:
  1611. X    sunback.c
  1612. X* module function:
  1613. X    Terminal interface module for SunView: module for linking to
  1614. X    main program.
  1615. X* history:
  1616. X    STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  1617. X    Originally by Tim Thompson (twitch!tjt)
  1618. X    Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  1619. X    Heavily modified by Chris & John Downey
  1620. X***/
  1621. X
  1622. X#include "xvi.h"
  1623. X
  1624. X/*
  1625. X * Exported.
  1626. X */
  1627. Xunsigned int    Rows = 0;             /* screen dimensions */
  1628. Xunsigned int    Columns = 0;
  1629. X
  1630. X/*
  1631. X * These are used to optimize output.
  1632. X */
  1633. Xstatic    int    real_row, real_col;
  1634. Xstatic    int    virt_row, virt_col;
  1635. Xstatic    bool_t    optimize;
  1636. X
  1637. X#define NO_COLOUR    -1
  1638. X
  1639. Xstatic int    old_colour = NO_COLOUR;
  1640. X
  1641. X/*
  1642. X * Update real cursor position.
  1643. X *
  1644. X * SunView can be painfully slow, at least on Sun 3's and 386i's, but
  1645. X * it's difficult to know the best way of optimizing it. The number of
  1646. X * characters sent to the display probably isn't really significant,
  1647. X * because it isn't a terminal. The things that take the most time are
  1648. X * more likely to be calculations (especially divisions &
  1649. X * multiplications) & manipulating bit maps. The bitmap for a single
  1650. X * character has to be xor'ed twice for each cursor movement, since
  1651. X * terminal subwindows use a reverse video block cursor.
  1652. X */
  1653. X#define MAXCMOVES    3    /*
  1654. X                 * This is a guess at the probable
  1655. X                 * maximum number of individual cursor
  1656. X                 * movements that's worthwhile to
  1657. X                 * avoid the calculations involved in
  1658. X                 * an absolute goto.
  1659. X                 */
  1660. X#ifndef ABS
  1661. X#    define ABS(n) ((n) < 0 ? -(n) : (n))
  1662. X#endif
  1663. X
  1664. Xstatic void
  1665. Xxyupdate()
  1666. X{
  1667. X    int hdisp,    /* horizontal (rightward) displacement wanted */
  1668. X    vdisp,    /* vertical (downward) displacement wanted */
  1669. X    ahdisp,    /* absolute horizontal displacement wanted */
  1670. X    avdisp,    /* absolute vertical displacement wanted */
  1671. X    homedisp;    /* total displacement from home position */
  1672. X
  1673. X    if (optimize) {
  1674. X    if (virt_col == real_col && virt_row == real_row)
  1675. X        /*
  1676. X         * Nothing to do.
  1677. X         */
  1678. X        return;
  1679. X    } else {
  1680. X        hdisp = virt_col - real_col;
  1681. X        vdisp = virt_row - real_row;
  1682. X        ahdisp = ABS(hdisp);
  1683. X        avdisp = ABS(vdisp);
  1684. X    }
  1685. X    }
  1686. X    homedisp = virt_row + virt_col;
  1687. X    /*
  1688. X     * Is it worth sending a cursor home sequence?
  1689. X     */
  1690. X    if (homedisp < MAXCMOVES && (!optimize || homedisp < avdisp + ahdisp)) {
  1691. X    fputs("\033[H", stdout);
  1692. X    real_row = real_col = 0;
  1693. X    ahdisp = hdisp = virt_col;
  1694. X    avdisp = vdisp = virt_row;
  1695. X    optimize = TRUE;
  1696. X    }
  1697. X    if (optimize) {
  1698. X    /*
  1699. X     * Is it worth sending a carriage return?
  1700. X     */
  1701. X    if (hdisp < 0 && virt_col < ahdisp && virt_col < MAXCMOVES) {
  1702. X        putc('\r', stdout);
  1703. X        real_col = 0;
  1704. X        ahdisp = hdisp = virt_col;
  1705. X    }
  1706. X    if (hdisp == 0 && vdisp == 0) {
  1707. X        /*
  1708. X         * We're already there, so there's nothing to do.
  1709. X         */
  1710. X        return;
  1711. X    }
  1712. X    /*
  1713. X     * Calculate total absolute displacement to see
  1714. X     * whether it's worthwhile doing any of this.
  1715. X     */
  1716. X    if (ahdisp + avdisp <= MAXCMOVES) {
  1717. X        for (; real_col < virt_col; real_col++)
  1718. X        /*
  1719. X         * Do non-destructive spaces.
  1720. X         */
  1721. X        fputs("\033[C", stdout);
  1722. X        for (; real_col > virt_col; real_col--)
  1723. X        /*
  1724. X         * Do backspaces.
  1725. X         */
  1726. X        putc('\b', stdout);
  1727. X        for (; real_row < virt_row; real_row++)
  1728. X        /*
  1729. X         * Go down.
  1730. X         */
  1731. X        putc('\n', stdout);
  1732. X        for (; real_row > virt_row; real_row--)
  1733. X        /*
  1734. X         * Go up.
  1735. X         */
  1736. X        fputs("\033[A", stdout);
  1737. X        return;
  1738. X    }
  1739. X    /*
  1740. X     * It isn't worthwhile. Give up & send an absolute
  1741. X     * goto.
  1742. X     */
  1743. X    }
  1744. X    fprintf(stdout, "\033[%d;%dH", virt_row + 1, virt_col + 1);
  1745. X    real_row = virt_row;
  1746. X    real_col = virt_col;
  1747. X    optimize = TRUE;
  1748. X}
  1749. X
  1750. X/*
  1751. X * Flush any pending output, including cursor position.
  1752. X */
  1753. Xvoid
  1754. Xflush_output()
  1755. X{
  1756. X    xyupdate();
  1757. X    (void) fflush(stdout);
  1758. X}
  1759. X
  1760. X/*
  1761. X * Put out a "normal" character, updating the cursor position.
  1762. X */
  1763. Xvoid
  1764. Xoutchar(c)
  1765. Xregister int    c;
  1766. X{
  1767. X    xyupdate();
  1768. X    putc(c, stdout);
  1769. X    if (++virt_col >= Columns) {
  1770. X    virt_col = 0;
  1771. X    if (++virt_row >= Rows)
  1772. X        --virt_row;
  1773. X    real_row = virt_row;
  1774. X    }
  1775. X    real_col = virt_col;
  1776. X}
  1777. X
  1778. X/*
  1779. X * Put out a "normal" string, updating the cursor position.
  1780. X */
  1781. Xvoid
  1782. Xoutstr(s)
  1783. Xregister char    *s;
  1784. X{
  1785. X    xyupdate();
  1786. X    for (; *s; s++)
  1787. X    {
  1788. X    putc(*s, stdout);
  1789. X    if (++virt_col >= Columns)
  1790. X    {
  1791. X        virt_col = 0;
  1792. X        if (++virt_row >= Rows)
  1793. X        --virt_row;
  1794. X    }
  1795. X    }
  1796. X    real_row = virt_row;
  1797. X    real_col = virt_col;
  1798. X}
  1799. X
  1800. X/*
  1801. X * Beep at the user.
  1802. X */
  1803. Xvoid
  1804. Xalert()
  1805. X{
  1806. X    putc('\007', stdout);
  1807. X    (void) fflush(stdout);
  1808. X}
  1809. X
  1810. X/*
  1811. X * Get a hexadecimal number from the front end process.
  1812. X */
  1813. Xstatic
  1814. Xhexnumber()
  1815. X{
  1816. X    register int x;
  1817. X
  1818. X    x = 0;
  1819. X    for (;;) {
  1820. X    register int c;
  1821. X
  1822. X    c = inch(0);
  1823. X    if (c == ';')
  1824. X        return x;
  1825. X    if (!is_xdigit(c))
  1826. X        return -1;
  1827. X    x = (x << 4) | hex_to_bin(c);
  1828. X    }
  1829. X}
  1830. X
  1831. X/*
  1832. X * Get single character or control sequence from front-end process.
  1833. X * The following control sequences are understood:
  1834. X *
  1835. X * Sequence            Meaning
  1836. X *
  1837. X * PREFIXCHAR 'k'        up arrow key pressed
  1838. X * PREFIXCHAR 'j'        down arrow key pressed
  1839. X * PREFIXCHAR '\b'        left arrow key pressed
  1840. X * PREFIXCHAR ' '        right arrow key pressed
  1841. X * PREFIXCHAR CTRL('F')        page down key pressed
  1842. X * PREFIXCHAR CTRL('B')        page up key pressed
  1843. X * PREFIXCHAR 'H'        home key pressed
  1844. X * PREFIXCHAR 'L'        end key pressed
  1845. X * PREFIXCHAR PREFIXCHAR    PREFIXCHAR pressed
  1846. X * PREFIXCHAR 'p' hexnum ';' hexnum ';'
  1847. X *                mouse button pressed at row & column
  1848. X *                specified by the digits.
  1849. X * PREFIXCHAR 'm' hexnum ';' hexnum ';' hexnum ';' hexnum ';'
  1850. X *                mouse dragged with middle button held
  1851. X *                down. Numbers give starting row &
  1852. X *                column, then ending row & column, in
  1853. X *                that order.
  1854. X *
  1855. X * PREFIXCHAR is currently control-R. A `hexnum' is 0 or more
  1856. X * hexadecimal digits.
  1857. X *
  1858. X * Any other process run in the same tty subwindow (with the ":!" or
  1859. X * "sh" commands) will also receive the same sequences for the events
  1860. X * shown, but using control-R as a prefix should be reasonably safe.
  1861. X *
  1862. X * The sequence for mouse clicks is dealt with by mouseposn().
  1863. X */
  1864. Xint
  1865. Xinchar(timeout)
  1866. Xlong    timeout;
  1867. X{
  1868. X    for (;;) {
  1869. X    register int    c;
  1870. X
  1871. X    if ((c = inch(timeout)) == PREFIXCHAR) {
  1872. X    /*
  1873. X     * This looks like the beginning of a control sequence.
  1874. X     */
  1875. X        switch (c = inch(0)) {
  1876. X        case PREFIXCHAR:
  1877. X            return PREFIXCHAR;
  1878. X        case CTRL('B'): case CTRL('F'):
  1879. X        case 'H': case 'L':
  1880. X        case '\b': case ' ':
  1881. X        case 'j': case 'k':
  1882. X            /*
  1883. X             * This looks like a function
  1884. X             * key.
  1885. X             */
  1886. X            if (State == NORMAL) {
  1887. X            return c;
  1888. X            } else {
  1889. X            alert();
  1890. X            continue;
  1891. X            }
  1892. X        case 'm':
  1893. X        {
  1894. X            unsigned row1, row2, col1, col2;
  1895. X
  1896. X            /*
  1897. X             * Even if we aren't in normal
  1898. X             * mode here, we have to call
  1899. X             * hexnumber() to eat all the
  1900. X             * hex. digits we should be
  1901. X             * getting.
  1902. X             */
  1903. X            if (
  1904. X            (row1 = hexnumber()) >= 0
  1905. X            &&
  1906. X            (row2 = hexnumber()) >= 0
  1907. X            &&
  1908. X            (col1 = hexnumber()) >= 0
  1909. X            &&
  1910. X            (col2 = hexnumber()) >= 0
  1911. X            &&
  1912. X            State == NORMAL
  1913. X            ) {
  1914. X            mousedrag(row1, row2, col1, col2);
  1915. X            }
  1916. X            continue;
  1917. X        }
  1918. X        case 'p':
  1919. X        {
  1920. X            unsigned row, col;
  1921. X
  1922. X            /*
  1923. X             * Even if we aren't in normal
  1924. X             * mode here, we have to call
  1925. X             * hexnumber() to eat all the
  1926. X             * hex. digits we should be
  1927. X             * getting.
  1928. X             */
  1929. X            if (
  1930. X            (row = hexnumber()) >= 0
  1931. X            &&
  1932. X            (col = hexnumber()) >= 0
  1933. X            &&
  1934. X            State == NORMAL
  1935. X            ) {
  1936. X            mouseclick(row, col);
  1937. X            }
  1938. X            continue;
  1939. X        }
  1940. X        default:
  1941. X            continue;
  1942. X        }
  1943. X    } else if (c == CTRL('Z') && State == NORMAL) {
  1944. X        /*
  1945. X         * This isn't reasonable. Job control isn't
  1946. X         * available here because this process wasn't
  1947. X         * started from a shell (it was started by the
  1948. X         * SunView Notifier). They can always use
  1949. X         * another window to run commands.
  1950. X         */
  1951. X        alert();
  1952. X        continue;
  1953. X    } else {    /* It's just a normal character. */
  1954. X        return c;
  1955. X    }
  1956. X    }
  1957. X}
  1958. X
  1959. Xstatic time_t    starttime;
  1960. X
  1961. X/*
  1962. X * Initialise the terminal interface.
  1963. X *
  1964. X * This must be done before any screen-based i/o is performed.
  1965. X */
  1966. Xvoid
  1967. Xtty_open(prows, pcolumns)
  1968. Xunsigned int *prows,
  1969. X         *pcolumns;
  1970. X{
  1971. X    /*
  1972. X     * If sys_startv() hasn't already got valid values for the
  1973. X     * window size from its TIOCGWINSZ ioctl, something is
  1974. X     * seriously wrong with SunOS.
  1975. X     */
  1976. X    Rows = *prows;
  1977. X    Columns = *pcolumns;
  1978. X
  1979. X    (void) time(&starttime);
  1980. X
  1981. X#ifdef sparc
  1982. X    /*
  1983. X     * Unfortunately, this implementation still doesn't give us
  1984. X     * scrolling windows, but SparcStations are fast enough that
  1985. X     * it doesn't really matter.
  1986. X     */
  1987. X    set_param(P_jumpscroll, js_OFF, (char **) NULL);
  1988. X#endif
  1989. X
  1990. X    {
  1991. X    /*
  1992. X     * These escape sequences may be generated by the
  1993. X     * arrow keys, depending on how the defaults database
  1994. X     * has been set up. All other function keys (page up,
  1995. X     * page down, etc.) should be received as function
  1996. X     * keys & handled appropriately by the front end
  1997. X     * process.
  1998. X     */
  1999. X    static char *mapargs[] = {
  2000. X        "\033[A",    "k",
  2001. X        "\033[B",    "j",
  2002. X        "\033[C",    "l",
  2003. X        "\033[D",    "h",
  2004. X        NULL
  2005. X    };
  2006. X    char **argp;
  2007. X
  2008. X    for (argp = mapargs; *argp != NULL; argp += 2) {
  2009. X        xvi_keymap(argp[0], argp[1]);
  2010. X    }
  2011. X    }
  2012. X}
  2013. X
  2014. Xvoid
  2015. Xtty_startv()
  2016. X{
  2017. X    old_colour = NO_COLOUR;
  2018. X    optimize = FALSE;
  2019. X}
  2020. X
  2021. X/*
  2022. X * Set terminal into the mode it was in when we started.
  2023. X */
  2024. Xvoid
  2025. Xtty_endv()
  2026. X{
  2027. X    flush_output();
  2028. X}
  2029. X
  2030. X/*
  2031. X * Tell front end process to quit.
  2032. X */
  2033. Xvoid
  2034. Xtty_close()
  2035. X{
  2036. X    time_t    stayuptime, now;
  2037. X
  2038. X    /*
  2039. X     * If we're immediately crashing with an error message, give
  2040. X     * them a chance (5 seconds) to read it.
  2041. X     */
  2042. X    stayuptime = starttime + 5;
  2043. X    if ((now = time((time_t *) 0)) < stayuptime)
  2044. X    sleep(stayuptime - now);
  2045. X    write(3, "q", 1);
  2046. X}
  2047. X
  2048. Xvoid
  2049. Xtty_goto(row, col)
  2050. Xint    row, col;
  2051. X{
  2052. X    virt_row = row;
  2053. X    virt_col = col;
  2054. X}
  2055. X
  2056. X/*
  2057. X * Erase the entire current line.
  2058. X */
  2059. Xvoid
  2060. Xerase_line()
  2061. X{
  2062. X    xyupdate();
  2063. X    fputs("\033[K", stdout);
  2064. X}
  2065. X
  2066. X/*
  2067. X * Insert one line.
  2068. X */
  2069. Xvoid
  2070. Xinsert_line()
  2071. X{
  2072. X    xyupdate();
  2073. X    fputs("\033[L", stdout);
  2074. X}
  2075. X
  2076. X/*
  2077. X * Delete one line.
  2078. X */
  2079. Xvoid
  2080. Xdelete_line()
  2081. X{
  2082. X    xyupdate();
  2083. X    fputs("\033[M", stdout);
  2084. X}
  2085. X
  2086. X/*
  2087. X * Erase display (may optionally home cursor).
  2088. X */
  2089. Xvoid
  2090. Xerase_display()
  2091. X{
  2092. X    putc('\f', stdout);
  2093. X    optimize = FALSE;
  2094. X    old_colour = NO_COLOUR;
  2095. X}
  2096. X
  2097. X/*
  2098. X * Set the specified colour. Just does standout/standend mode for now.
  2099. X *
  2100. X * Colour mapping is as follows:
  2101. X *
  2102. X *    0    (default systemcolour)    normal
  2103. X *    1    (default colour)    normal
  2104. X *    2    (default statuscolour)    reverse video
  2105. X */
  2106. Xvoid
  2107. Xset_colour(c)
  2108. Xint    c;
  2109. X{
  2110. X    if (c == 1) {
  2111. X    c = 0;
  2112. X    } else if (c > 2) {
  2113. X    c = 2;
  2114. X    }
  2115. X    if (c != old_colour) {
  2116. X    xyupdate();
  2117. X    fputs((c ? "\033[7m" : "\033[m"), stdout);
  2118. X    old_colour = c;
  2119. X    }
  2120. X}
  2121. X
  2122. X/*
  2123. X * Insert the given character at the cursor position.
  2124. X */
  2125. Xvoid
  2126. Xinschar(c)
  2127. Xchar    c;
  2128. X{
  2129. X    xyupdate();
  2130. X    fputs("\033[@", stdout);
  2131. X    outchar(c);
  2132. X}
  2133. END_OF_FILE
  2134.   if test 10695 -ne `wc -c <'xvi/src/sunback.c'`; then
  2135.     echo shar: \"'xvi/src/sunback.c'\" unpacked with wrong size!
  2136.   fi
  2137.   # end of 'xvi/src/sunback.c'
  2138. fi
  2139. if test -f 'xvi/src/tos.c' -a "${1}" != "-c" ; then 
  2140.   echo shar: Will not clobber existing file \"'xvi/src/tos.c'\"
  2141. else
  2142.   echo shar: Extracting \"'xvi/src/tos.c'\" \(7890 characters\)
  2143.   sed "s/^X//" >'xvi/src/tos.c' <<'END_OF_FILE'
  2144. X/* Copyright (c) 1990,1991,1992 Chris and John Downey */
  2145. X#ifndef lint
  2146. Xstatic char *sccsid = "@(#)tos.c    2.1 (Chris & John Downey) 7/29/92";
  2147. X#endif
  2148. X
  2149. X/***
  2150. X
  2151. X* program name:
  2152. X    xvi
  2153. X* function:
  2154. X    Portable version of UNIX "vi" editor, with extensions.
  2155. X* module name:
  2156. X    tos.c
  2157. X* module function:
  2158. X    System interface module for the Atari ST.
  2159. X* history:
  2160. X    STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  2161. X    Originally by Tim Thompson (twitch!tjt)
  2162. X    Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  2163. X    Heavily modified by Chris & John Downey
  2164. X
  2165. X    Atari port modified by Steve Found for LATTICE C V5.0
  2166. X
  2167. X***/
  2168. X
  2169. X#include "xvi.h"
  2170. X
  2171. X#include <osbind.h>
  2172. X
  2173. X/*
  2174. X * The following buffer is used to work around a bug in TOS. It appears that
  2175. X * unread console input can cause a crash, but only if console output is
  2176. X * going on. The solution is to always grab any unread input before putting
  2177. X * out a character. The following buffer holds any characters read in this
  2178. X * fashion. The problem can be easily produced because we can't yet keep
  2179. X * up with the normal auto-repeat rate in insert mode.
  2180. X */
  2181. X#define IBUFSZ    128
  2182. X
  2183. Xstatic    long    inbuf[IBUFSZ];        /* buffer for unread input */
  2184. Xstatic    long    *inptr = inbuf;        /* where to put next character */
  2185. X
  2186. X/*
  2187. X * These are globals which are set by the OS-specific module,
  2188. X * and used for various purposes throughout the rest of xvi.
  2189. X */
  2190. Xint    Rows;                /* Number of Rows and Columns */
  2191. Xint    Columns;            /* in the current window. */
  2192. X
  2193. Xstatic    char    tmpbuff[L_tmpnam];
  2194. Xstatic    char    *logscreen;
  2195. X
  2196. X/*
  2197. X * inchar() - get a character from the keyboard
  2198. X *
  2199. X * Certain special keys are mapped to values above 0x80. These
  2200. X * mappings are defined in keymap.h. If the key has a non-zero
  2201. X * ascii value, it is simply returned. Otherwise it may be a
  2202. X * special key we want to map.
  2203. X *
  2204. X * The ST has a bug involving keyboard input that seems to occur
  2205. X * when typing quickly, especially typing capital letters. Sometimes
  2206. X * a value of 0x02540000 is read. This doesn't correspond to anything
  2207. X * on the keyboard, according to my documentation. My solution is to
  2208. X * loop when any unknown key is seen. Normally, the bell is rung to
  2209. X * indicate the error. If the "bug" value is seen, we ignore it completely.
  2210. X *
  2211. X * "timeout" parameter not handled at the moment.
  2212. X */
  2213. Xint
  2214. Xinchar(timeout)
  2215. Xlong    timeout;
  2216. X{
  2217. X    int        k, s;
  2218. X
  2219. X    for (;;) {
  2220. X    long c;
  2221. X
  2222. X    /*
  2223. X     * Get the next input character, either from the input
  2224. X     * buffer or directly from TOS.
  2225. X     */
  2226. X    if (inptr != inbuf) {    /* input in the buffer, use it */
  2227. X        long    *p;
  2228. X
  2229. X        c = inbuf[0];
  2230. X        /*
  2231. X         * Shift everything else in the buffer down. This
  2232. X         * would be cleaner if we used a circular buffer,
  2233. X         * but it really isn't worth it.
  2234. X         */
  2235. X        inptr--;
  2236. X        for (p = inbuf; p < inptr ;p++)
  2237. X        *p = *(p+1);
  2238. X    } else {
  2239. X        c = Crawcin();
  2240. X    }
  2241. X
  2242. X    k = (c & 0xFF);
  2243. X    s = (c >> 16) & 0xFF;
  2244. X    if (k != 0)
  2245. X        break;
  2246. X
  2247. X    switch (s) {
  2248. X
  2249. X    case 0x62: k = K_HELP; break;
  2250. X    case 0x61: k = K_UNDO; break;
  2251. X    case 0x52: k = K_INSERT; break;
  2252. X    case 0x47: k = K_HOME; break;
  2253. X    case 0x48: k = K_UARROW; break;
  2254. X    case 0x50: k = K_DARROW; break;
  2255. X    case 0x4b: k = K_LARROW; break;
  2256. X    case 0x4d: k = K_RARROW; break;
  2257. X    case 0x29: k = K_CGRAVE; break; /* control grave accent */
  2258. X
  2259. X    /*
  2260. X     * Occurs due to a bug in TOS.
  2261. X     */
  2262. X    case 0x54:
  2263. X        break;
  2264. X
  2265. X    /*
  2266. X     * Add the function keys here later if we put in support
  2267. X     * for macros.
  2268. X     */
  2269. X
  2270. X    default:
  2271. X        k = 0;
  2272. X        alert();
  2273. X        break;
  2274. X    }
  2275. X
  2276. X    if (k != 0) {
  2277. X        break;
  2278. X    }
  2279. X    }
  2280. X    return(k);
  2281. X}
  2282. X
  2283. X/*
  2284. X * get_inchars - snarf away any pending console input
  2285. X *
  2286. X * If the buffer overflows, we discard what's left and ring the bell.
  2287. X */
  2288. Xstatic void
  2289. Xget_inchars()
  2290. X{
  2291. X    while (Cconis()) {
  2292. X    if (inptr >= &inbuf[IBUFSZ]) {    /* no room in buffer? */
  2293. X        Crawcin();        /* discard the input */
  2294. X        alert();            /* and sound the alarm */
  2295. X    } else {
  2296. X        *inptr++ = Crawcin();
  2297. X    }
  2298. X    }
  2299. X}
  2300. X
  2301. Xvoid
  2302. Xoutchar(c)
  2303. Xchar    c;
  2304. X{
  2305. X    get_inchars();
  2306. X    Cconout((short)c);
  2307. X}
  2308. X
  2309. Xvoid
  2310. Xoutstr(s)
  2311. Xregister char    *s;
  2312. X{
  2313. X    get_inchars();
  2314. X    Cconws(s);
  2315. X}
  2316. X
  2317. X#define BGND    0
  2318. X#define TEXT    1
  2319. X
  2320. X/*
  2321. X * vbeep() - visual bell
  2322. X */
  2323. Xstatic void
  2324. Xvbeep()
  2325. X{
  2326. X    int        text, bgnd;        /* text and background colors */
  2327. X    long    l;
  2328. X
  2329. X    text = Setcolor(TEXT, -1);
  2330. X    bgnd = Setcolor(BGND, -1);
  2331. X
  2332. X    Setcolor(TEXT, (short) bgnd);        /* swap colors */
  2333. X    Setcolor(BGND, (short) text);
  2334. X
  2335. X    for (l=0; l < 5000 ;l++)    /* short pause */
  2336. X    ;
  2337. X
  2338. X    Setcolor(TEXT, (short) text);        /* restore colors */
  2339. X    Setcolor(BGND, (short) bgnd);
  2340. X}
  2341. X
  2342. Xvoid
  2343. Xalert()
  2344. X{
  2345. X    if (Pb(P_vbell))
  2346. X    vbeep();
  2347. X    else
  2348. X    outchar('\007');
  2349. X}
  2350. X
  2351. Xbool_t
  2352. Xcan_write(file)
  2353. Xchar    *file;
  2354. X{
  2355. X    if (access(file, 0) == -1 || access(file, 2) == 0) {
  2356. X    return(TRUE);
  2357. X    } else {
  2358. X    return(FALSE);
  2359. X    }
  2360. X}
  2361. X
  2362. X/*
  2363. X * remove(file) - remove a file
  2364. X * I don't know whether success is detectable here - cmd.
  2365. X */
  2366. X#ifndef LATTICE
  2367. Xbool_t
  2368. Xremove(file)
  2369. Xchar    *file;
  2370. X{
  2371. X    Fdelete(file);
  2372. X    return(TRUE);
  2373. X}
  2374. X#endif
  2375. X
  2376. Xvoid
  2377. Xsys_init()
  2378. X{
  2379. X    logscreen = (char *) Logbase();
  2380. X    if (Getrez() == 0)
  2381. X    Columns = 40;        /* low resolution */
  2382. X    else
  2383. X    Columns = 80;        /* medium or high */
  2384. X
  2385. X    Rows = 25;
  2386. X
  2387. X    Cursconf(1, NULL);
  2388. X}
  2389. X
  2390. Xvoid
  2391. Xsys_startv()
  2392. X{
  2393. X}
  2394. X
  2395. Xvoid
  2396. Xsys_endv()
  2397. X{
  2398. X}
  2399. X
  2400. Xvoid
  2401. Xsys_exit(r)
  2402. Xint    r;
  2403. X{
  2404. X    tty_goto(25, 0);
  2405. X    outchar('\n');
  2406. X    exit(r);
  2407. X}
  2408. X
  2409. Xvoid
  2410. Xtty_goto(r, c)
  2411. Xint    r, c;
  2412. X{
  2413. X    outstr("\033Y");
  2414. X    outchar(r + ' ');
  2415. X    outchar(c + ' ');
  2416. X}
  2417. X
  2418. X/*
  2419. X * System calls or library routines missing in TOS.
  2420. X */
  2421. X
  2422. Xvoid
  2423. Xsleep(n)
  2424. Xunsigned    n;
  2425. X{
  2426. X    int        k;
  2427. X
  2428. X    k = Tgettime();
  2429. X    while (Tgettime() <= k + n)
  2430. X    ;
  2431. X}
  2432. X
  2433. Xvoid
  2434. Xdelay()
  2435. X{
  2436. X    long    n;
  2437. X
  2438. X    for (n = 0; n < 8000; n++)
  2439. X    ;
  2440. X}
  2441. X
  2442. X#ifndef LATTICE
  2443. Xint
  2444. Xsystem(cmd)
  2445. Xchar    *cmd;
  2446. X{
  2447. X    char    arg[1];
  2448. X
  2449. X    arg[0] = '\0';        /* no arguments passed to the shell */
  2450. X
  2451. X    if (Pexec(0, cmd, arg, 0L) < 0) {
  2452. X    return(-1);
  2453. X    } else {
  2454. X    return(0);
  2455. X    }
  2456. X}
  2457. X#endif
  2458. X
  2459. X#ifdef    MEGAMAX
  2460. Xchar *
  2461. Xstrchr(s, c)
  2462. Xchar    *s;
  2463. Xint    c;
  2464. X{
  2465. X    do {
  2466. X    if (*s == c)
  2467. X        return(s);
  2468. X    } while (*s++);
  2469. X
  2470. X    return(NULL);
  2471. X}
  2472. X#endif /* MEGAMAX */
  2473. X
  2474. X/*
  2475. X * getenv() - get a string from the environment
  2476. X *
  2477. X * Both Alcyon and Megamax are missing getenv(). This routine works for
  2478. X * both compilers and with the Beckemeyer and Gulam shells. With gulam,
  2479. X * the env_style variable should be set to either "mw" or "gu".
  2480. X */
  2481. X#ifndef LATTICE
  2482. Xchar *
  2483. Xgetenv(name)
  2484. Xchar    *name;
  2485. X{
  2486. X    extern long    _base;
  2487. X    char    *envp, *p;
  2488. X
  2489. X    envp = *((char **) (_base + 0x2c));
  2490. X
  2491. X    for ( ; *envp; envp += strlen(envp) + 1) {
  2492. X    if (strncmp(envp, name, strlen(name)) == 0) {
  2493. X        p = envp + strlen(name);
  2494. X        if (*p++ == '=')
  2495. X        return(p);
  2496. X    }
  2497. X    }
  2498. X    return(NULL);
  2499. X}
  2500. X#endif
  2501. X
  2502. X/*
  2503. X * Set the specified colour. Just does standout/standend mode for now.
  2504. X * Optimisation here to avoid setting standend when we aren't in
  2505. X * standout; assumes calling routines are well-behaved (i.e. only do
  2506. X * screen movement in P_colour) or some terminals will write garbage
  2507. X * all over the screen.
  2508. X */
  2509. Xvoid
  2510. Xset_colour(c)
  2511. Xint    c;
  2512. X{
  2513. X    static int    oldc = -1;
  2514. X
  2515. X    if (c == oldc)
  2516. X    return;
  2517. X
  2518. X    if (c != 0)
  2519. X    outstr("\033p");
  2520. X    else
  2521. X    outstr("\033q");
  2522. X
  2523. X    oldc = c;
  2524. X}
  2525. X
  2526. X/*
  2527. X * tempfname - Create a temporary file name.
  2528. X */
  2529. Xchar *
  2530. Xtempfname(srcname)
  2531. Xchar *srcname;
  2532. X{
  2533. X    return(tmpnam(tmpbuff));
  2534. X}
  2535. X
  2536. X#ifndef ABS
  2537. X#    define ABS(n) ((n) < 0 ? -(n) : (n))
  2538. X#endif
  2539. X
  2540. X/*
  2541. X * Scroll the ST Monochrome screen.
  2542. X */
  2543. Xvoid
  2544. Xst_scroll(start, end, nlines)
  2545. Xunsigned start, end;
  2546. Xint nlines;
  2547. X{
  2548. X    char *s, *e, *d;
  2549. X    char *s2;
  2550. X    size_t bytes, clr_bytes;
  2551. X
  2552. X    if (ABS(nlines) > (end + 1 - start) || nlines == 0)
  2553. X    return;
  2554. X
  2555. X    invis_cursor();
  2556. X
  2557. X    if (nlines > 0) {
  2558. X    d = logscreen + (start * 1280);
  2559. X    s = d + (nlines * 1280);
  2560. X    s2 = d + bytes;
  2561. X    } else /* (nlines < 0) */ {
  2562. X    nlines = -nlines;
  2563. X    s2 = s = logscreen + (start * 1280);
  2564. X    d = s + (nlines * 1280);
  2565. X    }
  2566. X
  2567. X    /*
  2568. X     * Move the appropriate lines up or down.
  2569. X     */
  2570. X    bytes = (end + 1 - start - nlines) * 1280;
  2571. X    memmove(d, s, bytes);
  2572. X
  2573. X    /*
  2574. X     * Clear the ones left behind.
  2575. X     */
  2576. X    clr_bytes = ((end + 1 - start) * 1280) - bytes;
  2577. X    (void) memset(s2, 0, clr_bytes);
  2578. X
  2579. X    vis_cursor();
  2580. X}
  2581. END_OF_FILE
  2582.   if test 7890 -ne `wc -c <'xvi/src/tos.c'`; then
  2583.     echo shar: \"'xvi/src/tos.c'\" unpacked with wrong size!
  2584.   fi
  2585.   # end of 'xvi/src/tos.c'
  2586. fi
  2587. echo shar: End of archive 14 \(of 18\).
  2588. cp /dev/null ark14isdone
  2589. MISSING=""
  2590. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ; do
  2591.     if test ! -f ark${I}isdone ; then
  2592.     MISSING="${MISSING} ${I}"
  2593.     fi
  2594. done
  2595. if test "${MISSING}" = "" ; then
  2596.     echo You have unpacked all 18 archives.
  2597.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2598. else
  2599.     echo You still must unpack the following archives:
  2600.     echo "        " ${MISSING}
  2601. fi
  2602. exit 0
  2603. exit 0 # Just in case...
  2604.