home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume4 / uemacs3.6 / part6 < prev    next >
Text File  |  1986-11-30  |  42KB  |  1,217 lines

  1. Subject: MicroEMACS 3.6 (Part 6 of 8)
  2. Newsgroups: mod.sources
  3. Approved: jpn@panda.UUCP
  4.  
  5. Mod.sources:  Volume 4, Issue 103
  6. Submitted by: ihnp4!itivax!duncan!lawrence
  7.  
  8. echo x - line.c
  9. sed 's/^X//' >line.c <<'*-*-END-of-line.c-*-*'
  10. X/*
  11. X * The functions in this file are a general set of line management utilities.
  12. X * They are the only routines that touch the text. They also touch the buffer
  13. X * and window structures, to make sure that the necessary updating gets done.
  14. X * There are routines in this file that handle the kill buffer too. It isn't
  15. X * here for any good reason.
  16. X *
  17. X * Note that this code only updates the dot and mark values in the window list.
  18. X * Since all the code acts on the current window, the buffer that we are
  19. X * editing must be being displayed, which means that "b_nwnd" is non zero,
  20. X * which means that the dot and mark values in the buffer headers are nonsense.
  21. X */
  22. X
  23. X#include        <stdio.h>
  24. X#include    "estruct.h"
  25. X#include        "edef.h"
  26. X
  27. X#define NBLOCK  16                      /* Line block chunk size        */
  28. X#define KBLOCK  1024                    /* Kill buffer block size       */
  29. X
  30. Xchar    *kbufp  = NULL;                 /* Kill buffer data             */
  31. Xunsigned kused   = 0;                   /* # of bytes used in KB        */
  32. Xunsigned ksize   = 0;                   /* # of bytes allocated in KB   */
  33. X
  34. X/*
  35. X * This routine allocates a block of memory large enough to hold a LINE
  36. X * containing "used" characters. The block is always rounded up a bit. Return
  37. X * a pointer to the new block, or NULL if there isn't any memory left. Print a
  38. X * message in the message line if no space.
  39. X */
  40. XLINE    *
  41. Xlalloc(used)
  42. Xregister int    used;
  43. X{
  44. X        register LINE   *lp;
  45. X        register int    size;
  46. X    char *malloc();
  47. X
  48. X        size = (used+NBLOCK-1) & ~(NBLOCK-1);
  49. X        if (size == 0)                          /* Assume that an empty */
  50. X                size = NBLOCK;                  /* line is for type-in. */
  51. X        if ((lp = (LINE *) malloc(sizeof(LINE)+size)) == NULL) {
  52. X                mlwrite("Cannot allocate %d bytes", size);
  53. X                return (NULL);
  54. X        }
  55. X        lp->l_size = size;
  56. X        lp->l_used = used;
  57. X        return (lp);
  58. X}
  59. X
  60. X/*
  61. X * Delete line "lp". Fix all of the links that might point at it (they are
  62. X * moved to offset 0 of the next line. Unlink the line from whatever buffer it
  63. X * might be in. Release the memory. The buffers are updated too; the magic
  64. X * conditions described in the above comments don't hold here.
  65. X */
  66. Xlfree(lp)
  67. Xregister LINE   *lp;
  68. X{
  69. X        register BUFFER *bp;
  70. X        register WINDOW *wp;
  71. X
  72. X        wp = wheadp;
  73. X        while (wp != NULL) {
  74. X                if (wp->w_linep == lp)
  75. X                        wp->w_linep = lp->l_fp;
  76. X                if (wp->w_dotp  == lp) {
  77. X                        wp->w_dotp  = lp->l_fp;
  78. X                        wp->w_doto  = 0;
  79. X                }
  80. X                if (wp->w_markp == lp) {
  81. X                        wp->w_markp = lp->l_fp;
  82. X                        wp->w_marko = 0;
  83. X                }
  84. X                wp = wp->w_wndp;
  85. X        }
  86. X        bp = bheadp;
  87. X        while (bp != NULL) {
  88. X                if (bp->b_nwnd == 0) {
  89. X                        if (bp->b_dotp  == lp) {
  90. X                                bp->b_dotp = lp->l_fp;
  91. X                                bp->b_doto = 0;
  92. X                        }
  93. X                        if (bp->b_markp == lp) {
  94. X                                bp->b_markp = lp->l_fp;
  95. X                                bp->b_marko = 0;
  96. X                        }
  97. X                }
  98. X                bp = bp->b_bufp;
  99. X        }
  100. X        lp->l_bp->l_fp = lp->l_fp;
  101. X        lp->l_fp->l_bp = lp->l_bp;
  102. X        free((char *) lp);
  103. X}
  104. X
  105. X/*
  106. X * This routine gets called when a character is changed in place in the current
  107. X * buffer. It updates all of the required flags in the buffer and window
  108. X * system. The flag used is passed as an argument; if the buffer is being
  109. X * displayed in more than 1 window we change EDIT t HARD. Set MODE if the
  110. X * mode line needs to be updated (the "*" has to be set).
  111. X */
  112. Xlchange(flag)
  113. Xregister int    flag;
  114. X{
  115. X        register WINDOW *wp;
  116. X
  117. X        if (curbp->b_nwnd != 1)                 /* Ensure hard.         */
  118. X                flag = WFHARD;
  119. X        if ((curbp->b_flag&BFCHG) == 0) {       /* First change, so     */
  120. X                flag |= WFMODE;                 /* update mode lines.   */
  121. X                curbp->b_flag |= BFCHG;
  122. X        }
  123. X        wp = wheadp;
  124. X        while (wp != NULL) {
  125. X                if (wp->w_bufp == curbp)
  126. X                        wp->w_flag |= flag;
  127. X                wp = wp->w_wndp;
  128. X        }
  129. X}
  130. X
  131. Xinsspace(f, n)    /* insert spaces forward into text */
  132. X
  133. Xint f, n;    /* default flag and numeric argument */
  134. X
  135. X{
  136. X    linsert(n, ' ');
  137. X    backchar(f, n);
  138. X}
  139. X
  140. X/*
  141. X * Insert "n" copies of the character "c" at the current location of dot. In
  142. X * the easy case all that happens is the text is stored in the line. In the
  143. X * hard case, the line has to be reallocated. When the window list is updated,
  144. X * take special care; I screwed it up once. You always update dot in the
  145. X * current window. You update mark, and a dot in another window, if it is
  146. X * greater than the place where you did the insert. Return TRUE if all is
  147. X * well, and FALSE on errors.
  148. X */
  149. Xlinsert(n, c)
  150. X{
  151. X        register char   *cp1;
  152. X        register char   *cp2;
  153. X        register LINE   *lp1;
  154. X        register LINE   *lp2;
  155. X        register LINE   *lp3;
  156. X        register int    doto;
  157. X        register int    i;
  158. X        register WINDOW *wp;
  159. X
  160. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  161. X        return(rdonly());    /* we are in read only mode    */
  162. X        lchange(WFEDIT);
  163. X        lp1 = curwp->w_dotp;                    /* Current line         */
  164. X        if (lp1 == curbp->b_linep) {            /* At the end: special  */
  165. X                if (curwp->w_doto != 0) {
  166. X                        mlwrite("bug: linsert");
  167. X                        return (FALSE);
  168. X                }
  169. X                if ((lp2=lalloc(n)) == NULL)    /* Allocate new line    */
  170. X                        return (FALSE);
  171. X                lp3 = lp1->l_bp;                /* Previous line        */
  172. X                lp3->l_fp = lp2;                /* Link in              */
  173. X                lp2->l_fp = lp1;
  174. X                lp1->l_bp = lp2;
  175. X                lp2->l_bp = lp3;
  176. X                for (i=0; i<n; ++i)
  177. X                        lp2->l_text[i] = c;
  178. X                curwp->w_dotp = lp2;
  179. X                curwp->w_doto = n;
  180. X                return (TRUE);
  181. X        }
  182. X        doto = curwp->w_doto;                   /* Save for later.      */
  183. X        if (lp1->l_used+n > lp1->l_size) {      /* Hard: reallocate     */
  184. X                if ((lp2=lalloc(lp1->l_used+n)) == NULL)
  185. X                        return (FALSE);
  186. X                cp1 = &lp1->l_text[0];
  187. X                cp2 = &lp2->l_text[0];
  188. X                while (cp1 != &lp1->l_text[doto])
  189. X                        *cp2++ = *cp1++;
  190. X                cp2 += n;
  191. X                while (cp1 != &lp1->l_text[lp1->l_used])
  192. X                        *cp2++ = *cp1++;
  193. X                lp1->l_bp->l_fp = lp2;
  194. X                lp2->l_fp = lp1->l_fp;
  195. X                lp1->l_fp->l_bp = lp2;
  196. X                lp2->l_bp = lp1->l_bp;
  197. X                free((char *) lp1);
  198. X        } else {                                /* Easy: in place       */
  199. X                lp2 = lp1;                      /* Pretend new line     */
  200. X                lp2->l_used += n;
  201. X                cp2 = &lp1->l_text[lp1->l_used];
  202. X                cp1 = cp2-n;
  203. X                while (cp1 != &lp1->l_text[doto])
  204. X                        *--cp2 = *--cp1;
  205. X        }
  206. X        for (i=0; i<n; ++i)                     /* Add the characters   */
  207. X                lp2->l_text[doto+i] = c;
  208. X        wp = wheadp;                            /* Update windows       */
  209. X        while (wp != NULL) {
  210. X                if (wp->w_linep == lp1)
  211. X                        wp->w_linep = lp2;
  212. X                if (wp->w_dotp == lp1) {
  213. X                        wp->w_dotp = lp2;
  214. X                        if (wp==curwp || wp->w_doto>doto)
  215. X                                wp->w_doto += n;
  216. X                }
  217. X                if (wp->w_markp == lp1) {
  218. X                        wp->w_markp = lp2;
  219. X                        if (wp->w_marko > doto)
  220. X                                wp->w_marko += n;
  221. X                }
  222. X                wp = wp->w_wndp;
  223. X        }
  224. X        return (TRUE);
  225. X}
  226. X
  227. X/*
  228. X * Insert a newline into the buffer at the current location of dot in the
  229. X * current window. The funny ass-backwards way it does things is not a botch;
  230. X * it just makes the last line in the file not a special case. Return TRUE if
  231. X * everything works out and FALSE on error (memory allocation failure). The
  232. X * update of dot and mark is a bit easier then in the above case, because the
  233. X * split forces more updating.
  234. X */
  235. Xlnewline()
  236. X{
  237. X        register char   *cp1;
  238. X        register char   *cp2;
  239. X        register LINE   *lp1;
  240. X        register LINE   *lp2;
  241. X        register int    doto;
  242. X        register WINDOW *wp;
  243. X
  244. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  245. X        return(rdonly());    /* we are in read only mode    */
  246. X        lchange(WFHARD);
  247. X        lp1  = curwp->w_dotp;                   /* Get the address and  */
  248. X        doto = curwp->w_doto;                   /* offset of "."        */
  249. X        if ((lp2=lalloc(doto)) == NULL)         /* New first half line  */
  250. X                return (FALSE);
  251. X        cp1 = &lp1->l_text[0];                  /* Shuffle text around  */
  252. X        cp2 = &lp2->l_text[0];
  253. X        while (cp1 != &lp1->l_text[doto])
  254. X                *cp2++ = *cp1++;
  255. X        cp2 = &lp1->l_text[0];
  256. X        while (cp1 != &lp1->l_text[lp1->l_used])
  257. X                *cp2++ = *cp1++;
  258. X        lp1->l_used -= doto;
  259. X        lp2->l_bp = lp1->l_bp;
  260. X        lp1->l_bp = lp2;
  261. X        lp2->l_bp->l_fp = lp2;
  262. X        lp2->l_fp = lp1;
  263. X        wp = wheadp;                            /* Windows              */
  264. X        while (wp != NULL) {
  265. X                if (wp->w_linep == lp1)
  266. X                        wp->w_linep = lp2;
  267. X                if (wp->w_dotp == lp1) {
  268. X                        if (wp->w_doto < doto)
  269. X                                wp->w_dotp = lp2;
  270. X                        else
  271. X                                wp->w_doto -= doto;
  272. X                }
  273. X                if (wp->w_markp == lp1) {
  274. X                        if (wp->w_marko < doto)
  275. X                                wp->w_markp = lp2;
  276. X                        else
  277. X                                wp->w_marko -= doto;
  278. X                }
  279. X                wp = wp->w_wndp;
  280. X        }
  281. X        return (TRUE);
  282. X}
  283. X
  284. X/*
  285. X * This function deletes "n" bytes, starting at dot. It understands how do deal
  286. X * with end of lines, etc. It returns TRUE if all of the characters were
  287. X * deleted, and FALSE if they were not (because dot ran into the end of the
  288. X * buffer. The "kflag" is TRUE if the text should be put in the kill buffer.
  289. X */
  290. Xldelete(n, kflag)
  291. X{
  292. X        register char   *cp1;
  293. X        register char   *cp2;
  294. X        register LINE   *dotp;
  295. X        register int    doto;
  296. X        register int    chunk;
  297. X        register WINDOW *wp;
  298. X
  299. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  300. X        return(rdonly());    /* we are in read only mode    */
  301. X        while (n != 0) {
  302. X                dotp = curwp->w_dotp;
  303. X                doto = curwp->w_doto;
  304. X                if (dotp == curbp->b_linep)     /* Hit end of buffer.   */
  305. X                        return (FALSE);
  306. X                chunk = dotp->l_used-doto;      /* Size of chunk.       */
  307. X                if (chunk > n)
  308. X                        chunk = n;
  309. X                if (chunk == 0) {               /* End of line, merge.  */
  310. X                        lchange(WFHARD);
  311. X                        if (ldelnewline() == FALSE
  312. X                        || (kflag!=FALSE && kinsert('\n')==FALSE))
  313. X                                return (FALSE);
  314. X                        --n;
  315. X                        continue;
  316. X                }
  317. X                lchange(WFEDIT);
  318. X                cp1 = &dotp->l_text[doto];      /* Scrunch text.        */
  319. X                cp2 = cp1 + chunk;
  320. X                if (kflag != FALSE) {           /* Kill?                */
  321. X                        while (cp1 != cp2) {
  322. X                                if (kinsert(*cp1) == FALSE)
  323. X                                        return (FALSE);
  324. X                                ++cp1;
  325. X                        }
  326. X                        cp1 = &dotp->l_text[doto];
  327. X                }
  328. X                while (cp2 != &dotp->l_text[dotp->l_used])
  329. X                        *cp1++ = *cp2++;
  330. X                dotp->l_used -= chunk;
  331. X                wp = wheadp;                    /* Fix windows          */
  332. X                while (wp != NULL) {
  333. X                        if (wp->w_dotp==dotp && wp->w_doto>=doto) {
  334. X                                wp->w_doto -= chunk;
  335. X                                if (wp->w_doto < doto)
  336. X                                        wp->w_doto = doto;
  337. X                        }
  338. X                        if (wp->w_markp==dotp && wp->w_marko>=doto) {
  339. X                                wp->w_marko -= chunk;
  340. X                                if (wp->w_marko < doto)
  341. X                                        wp->w_marko = doto;
  342. X                        }
  343. X                        wp = wp->w_wndp;
  344. X                }
  345. X                n -= chunk;
  346. X        }
  347. X        return (TRUE);
  348. X}
  349. X
  350. X/*
  351. X * Delete a newline. Join the current line with the next line. If the next line
  352. X * is the magic header line always return TRUE; merging the last line with the
  353. X * header line can be thought of as always being a successful operation, even
  354. X * if nothing is done, and this makes the kill buffer work "right". Easy cases
  355. X * can be done by shuffling data around. Hard cases require that lines be moved
  356. X * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
  357. X * "ldelete" only.
  358. X */
  359. Xldelnewline()
  360. X{
  361. X        register char   *cp1;
  362. X        register char   *cp2;
  363. X        register LINE   *lp1;
  364. X        register LINE   *lp2;
  365. X        register LINE   *lp3;
  366. X        register WINDOW *wp;
  367. X
  368. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  369. X        return(rdonly());    /* we are in read only mode    */
  370. X        lp1 = curwp->w_dotp;
  371. X        lp2 = lp1->l_fp;
  372. X        if (lp2 == curbp->b_linep) {            /* At the buffer end.   */
  373. X                if (lp1->l_used == 0)           /* Blank line.          */
  374. X                        lfree(lp1);
  375. X                return (TRUE);
  376. X        }
  377. X        if (lp2->l_used <= lp1->l_size-lp1->l_used) {
  378. X                cp1 = &lp1->l_text[lp1->l_used];
  379. X                cp2 = &lp2->l_text[0];
  380. X                while (cp2 != &lp2->l_text[lp2->l_used])
  381. X                        *cp1++ = *cp2++;
  382. X                wp = wheadp;
  383. X                while (wp != NULL) {
  384. X                        if (wp->w_linep == lp2)
  385. X                                wp->w_linep = lp1;
  386. X                        if (wp->w_dotp == lp2) {
  387. X                                wp->w_dotp  = lp1;
  388. X                                wp->w_doto += lp1->l_used;
  389. X                        }
  390. X                        if (wp->w_markp == lp2) {
  391. X                                wp->w_markp  = lp1;
  392. X                                wp->w_marko += lp1->l_used;
  393. X                        }
  394. X                        wp = wp->w_wndp;
  395. X                }
  396. X                lp1->l_used += lp2->l_used;
  397. X                lp1->l_fp = lp2->l_fp;
  398. X                lp2->l_fp->l_bp = lp1;
  399. X                free((char *) lp2);
  400. X                return (TRUE);
  401. X        }
  402. X        if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
  403. X                return (FALSE);
  404. X        cp1 = &lp1->l_text[0];
  405. X        cp2 = &lp3->l_text[0];
  406. X        while (cp1 != &lp1->l_text[lp1->l_used])
  407. X                *cp2++ = *cp1++;
  408. X        cp1 = &lp2->l_text[0];
  409. X        while (cp1 != &lp2->l_text[lp2->l_used])
  410. X                *cp2++ = *cp1++;
  411. X        lp1->l_bp->l_fp = lp3;
  412. X        lp3->l_fp = lp2->l_fp;
  413. X        lp2->l_fp->l_bp = lp3;
  414. X        lp3->l_bp = lp1->l_bp;
  415. X        wp = wheadp;
  416. X        while (wp != NULL) {
  417. X                if (wp->w_linep==lp1 || wp->w_linep==lp2)
  418. X                        wp->w_linep = lp3;
  419. X                if (wp->w_dotp == lp1)
  420. X                        wp->w_dotp  = lp3;
  421. X                else if (wp->w_dotp == lp2) {
  422. X                        wp->w_dotp  = lp3;
  423. X                        wp->w_doto += lp1->l_used;
  424. X                }
  425. X                if (wp->w_markp == lp1)
  426. X                        wp->w_markp  = lp3;
  427. X                else if (wp->w_markp == lp2) {
  428. X                        wp->w_markp  = lp3;
  429. X                        wp->w_marko += lp1->l_used;
  430. X                }
  431. X                wp = wp->w_wndp;
  432. X        }
  433. X        free((char *) lp1);
  434. X        free((char *) lp2);
  435. X        return (TRUE);
  436. X}
  437. X
  438. X/*
  439. X * Delete all of the text saved in the kill buffer. Called by commands when a
  440. X * new kill context is being created. The kill buffer array is released, just
  441. X * in case the buffer has grown to immense size. No errors.
  442. X */
  443. Xkdelete()
  444. X{
  445. X        if (kbufp != NULL) {
  446. X                free((char *) kbufp);
  447. X                kbufp = NULL;
  448. X                kused = 0;
  449. X                ksize = 0;
  450. X        }
  451. X}
  452. X
  453. X/*
  454. X * Insert a character to the kill buffer, enlarging the buffer if there isn't
  455. X * any room. Always grow the buffer in chunks, on the assumption that if you
  456. X * put something in the kill buffer you are going to put more stuff there too
  457. X * later. Return TRUE if all is well, and FALSE on errors.
  458. X */
  459. X
  460. Xkinsert(c)
  461. X{
  462. X        register char   *nbufp;
  463. X    char *realloc();
  464. X    char *malloc();
  465. X
  466. X        if (kused == ksize) {
  467. X        if (ksize == 0)    /* first time through? */
  468. X            nbufp = malloc(KBLOCK);    /* alloc the first block */
  469. X        else    /* or re allocate a bigger block */
  470. X            nbufp = realloc(kbufp, ksize+KBLOCK);
  471. X        if (nbufp == NULL)        /* abort if it fails */
  472. X            return(FALSE);
  473. X                kbufp  = nbufp;        /* point our global at it */
  474. X                ksize += KBLOCK;    /* and adjust the size */
  475. X        }
  476. X        kbufp[kused++] = c;
  477. X        return (TRUE);
  478. X}
  479. X
  480. X/*
  481. X * This function gets characters from the kill buffer. If the character index
  482. X * "n" is off the end, it returns "-1". This lets the caller just scan along
  483. X * until it gets a "-1" back.
  484. X */
  485. Xkremove(n)
  486. X{
  487. X        if (n >= kused)
  488. X                return (-1);
  489. X        else
  490. X                return (kbufp[n] & 0xFF);
  491. X}
  492. X
  493. X#if    LATTICE
  494. X/*    we need to have the following functions to manage memory that
  495. X    don't exist under Lattice                    */
  496. X
  497. X
  498. Xchar *realloc(ptr, size)    /* re-allocate a memory chunk to a
  499. X                   different size, copying what can
  500. X                   by copied                */
  501. X
  502. Xchar *ptr;    /* pointer to the original block */
  503. Xunsigned size;    /* # of bytes needed in new block */
  504. X
  505. X{
  506. X    char *newptr;    /* pointer to new block */
  507. X    unsigned csize;    /* size of area to copy from old buffer to new */
  508. X    char *malloc();
  509. X
  510. X    newptr = malloc(size);        /* get the new block */
  511. X    if (newptr == NULL)        /* if malloc fails....*/
  512. X        return(NULL);
  513. X
  514. X    csize = ksize;    /******THIS IS A CHEAT SINCE WE CAN NOT GET
  515. X                   AT THE SIZE OF THE MALLOCED BLOCK!!
  516. X                   DO NOT USE THIS FUNCTION GENERICALLY!!!*/
  517. X    if (csize > size)    /* we need to copy some stuff from */
  518. X        csize = size;    /* the old buffer to the new    */
  519. X
  520. X    movmem(ptr, newptr, csize);    /* copy the availible bytes */
  521. X    free(ptr);            /* dump the old buffer */
  522. X    return(newptr);            /* and return the new */
  523. X}
  524. X#endif
  525. X
  526. *-*-END-of-line.c-*-*
  527. echo x - main.c
  528. sed 's/^X//' >main.c <<'*-*-END-of-main.c-*-*'
  529. X/*
  530. X * This program is in public domain; written by Dave G. Conroy.
  531. X * This file contains the main driving routine, and some keyboard processing
  532. X * code, for the MicroEMACS screen editor.
  533. X *
  534. X * REVISION HISTORY:
  535. X *
  536. X * 1.0  Steve Wilhite, 30-Nov-85
  537. X *      - Removed the old LK201 and VT100 logic. Added code to support the
  538. X *        DEC Rainbow keyboard (which is a LK201 layout) using the the Level
  539. X *        1 Console In ROM INT. See "rainbow.h" for the function key defs
  540. X *      Steve Wilhite, 1-Dec-85
  541. X *      - massive cleanup on code in display.c and search.c
  542. X *
  543. X * 2.0  George Jones, 12-Dec-85
  544. X *      - Ported to Amiga.
  545. X *
  546. X * 3.0  Daniel Lawrence, 29-Dec-85
  547. X *      - rebound keys/added new fast buffered I/O for AMIGA
  548. X *    - added META- repeat commands
  549. X *    - added reposition default to center screen (yeah!)
  550. X *    - changed exit with modified buffers message
  551. X *    - made filesave tell us what it is doing
  552. X *    - changed search string entry to terminate with <ESC>
  553. X *      so we can use <NL> in search/replace strings
  554. X *    - updated version number in mode line to 3.0
  555. X *    12-Jan-86
  556. X *    - Added code to reconize the Search/replace functions
  557. X *    - Added code to perform search/replace & query functions
  558. X *    14-Jan-86
  559. X *    - moved search logic to separate function in search.c
  560. X *    - added replace and query replace functions
  561. X *    - separated out control key expansions to be used by others in search.c
  562. X *    15-Jan-86
  563. X *    - changed "visiting" to finding
  564. X *    - changed yes/no responces to not need return
  565. X *    - cleaned up various messages
  566. X *    16-jan-86
  567. X *    - fixed spurious spawn message in MSDOS
  568. X *    - added ^X-S synonime to save command
  569. X *    - moved escape to shell to ^X-C
  570. X *    21-jan-86
  571. X *    - added code to suspend shell under BSD
  572. X *    22-jan-86
  573. X *    - added function key support (SPEC) under MSDOS
  574. X *    - Abort now prints [Aborted] on message line
  575. X *    23-jan-86
  576. X *    - Added modes and commends to set/unset them
  577. X *    24-jan-86
  578. X *    - Added Goto Line command
  579. X *    - added Rename Buffer command
  580. X *    28-jan-86
  581. X *    - added goto begining and end of paragraph commands (META-P/META-N)
  582. X *    - re-wrote kdelete to use realloc. gained MUCH speed here when
  583. X *      doing large wipes both on UNIX and MSDOS. Changed kill buffer
  584. X *      allocation block size from 256 bytes to 1 k
  585. X *    29-jan-86
  586. X *    - moved extern function declarations to efunc.h
  587. X *    - made name[] name binding table
  588. X *    30-jan-86
  589. X *    - fixed Previous/Next paragraph command not to wrap around EOF
  590. X *    - added Fill Paragraph command (META-Q)
  591. X *    4-feb-86
  592. X *    - added code to properly display long lines, scrolling them right
  593. X *      to left
  594. X *    5-feb-85
  595. X *    - rewrote code to right/left scroll...much better
  596. X *    - added shifted arror keys on IBMPC
  597. X *    6-feb-85
  598. X *    - add option to allow forword-word to jump to begining of
  599. X *      next word instead of end of current one. This is different from
  600. X *      other emacs' but can be configured off in estruct.h
  601. X *    - added VIEW mode to allow a buffer to be read only
  602. X *       (-v switch on command line will activate this)
  603. X *    - changed quick exit to write out ALL changed buffers!!!
  604. X *      MAKE SURE YOU KNOW THIS WHEN META-Zing
  605. X *    10-feb-86
  606. X *    - added handling of lines longer than allowed on file read in
  607. X *      (they wrap on additional lines)
  608. X *    - made having space clear the message line and NOT insert itself
  609. X *      a configuration option in ed.h
  610. X *    11-feb-86
  611. X *    - added Describe-command and Help commands.
  612. X *    13-feb-86
  613. X *    - added View file command (^X ^V) and finished HELP command
  614. X *    14-feb-86
  615. X *    - added option to let main loop skip update if type ahead commands
  616. X *       are queued up
  617. X *    16-feb-86
  618. X *    - added Insert File command
  619. X *    17-feb-86
  620. X *    - added scroll next window up/down commands
  621. X *    18-feb-86
  622. X *    - added CMODE indentation
  623. X *    - re-arranged header files to standerdize extern and global
  624. X *      definitions
  625. X *    - changed version number to 3.2
  626. X *    - added numeric arguments to search, reverse search and
  627. X *      search and replace
  628. X *    24-feb-86
  629. X *    - added Bind To Key function (^C for now) to allow the user
  630. X *      to change his command keys
  631. X *    - added Unbind key function (M-^C for now)
  632. X *    - added execute named command to execute unbound commands (M-X)
  633. X *    - added describe bindings command (not bound)
  634. X *    - changed version number to 3.3
  635. X *    25-feb-86
  636. X *    - scrapped CERROR mode (too many compilers)
  637. X *    - added EXACT mode for case sensitive searchers
  638. X *    26-feb-86
  639. X *    - added command completion on execute named command and
  640. X *      all routined grabbing a command name
  641. X *    - adding execute-command-line command and its support functions
  642. X *      (in preporation for sourcing files)
  643. X *    - added Execute Buffer command
  644. X *    27-feb-86
  645. X *    - added execute(source) file command and added code to automatically
  646. X *      execute emacs.rc (or .emacsrc on UNIX) before initial read in
  647. X *    - changed version number to 3.4
  648. X *    4-mar-86
  649. X *    - changed word delete to be consistant with word move (it gets
  650. X *      rid of the inter word space now) This is configurable with the
  651. X *      NFWORD symbol in estruct.h
  652. X *    - added B_ACTIVE entry to the buffer table. Let emacs read multiple
  653. X *      file names from the command line and only read them in as needed
  654. X *    5-mar-85
  655. X *    - rewrote command line parser to get rid of my patchy code
  656. X *    - changed version number to 3.5
  657. X *    1-apr-86
  658. X *    - added support for Aztec C 3.20e under MSDOS
  659. X *    - fixed bug in mlwrite on ADM3's and thier ilk under V7
  660. X *    - added insertion of pounds in column one under CMODE
  661. X *    - changed version number to 3.6
  662. X *    3-apr-86
  663. X *    - added next-buffer command (^X-X)
  664. X *    5-apr-86
  665. X *    - added kill paragraph command (M-^W)
  666. X *    - changed fill-paragraph to leave 2 spaces after a period at the
  667. X *      end of a word.
  668. X *    - added OVERWRITE mode
  669. X *    7-apr-86
  670. X *    - fixed overwrite mode to handle tabs
  671. X *    8-apr-86
  672. X *    - added add/delete global mode (<ESC>M & <ESC> ^M) commands
  673. X *    9-apr-86
  674. X *    - added insert space command
  675. X *    - moved bindings around        ^C    insert space
  676. X *                    M-K    bind-to-key
  677. X *                    INSERT    insert space
  678. X *                    DELETE    forwdel
  679. X *    - added hunt forward and hunt reverse commands
  680. X *    10-apr-86
  681. X *    - fixed bug in DOBUF with non-terminated command string
  682. X *    15-apr-86
  683. X *    - fixed tab expansion bug in DISPLAY which hung the AMIGA
  684. X *      (send in by Dawn Banks)
  685. X *    - fixed curcol problen if forwline/backline during keyboard
  686. X *      macro execution (sent in by Ernst Christen)
  687. X *    - added AMIGA function/cursor key support
  688. X *    - fixed nonterminating <NL> replacement bug
  689. X *    - fixed word wrapping problems
  690. X *    16-apr-86
  691. X *    - updated documentation and froze development for 3.6 net release
  692. X */
  693. X
  694. X#include        <stdio.h>
  695. X
  696. X/* make global definitions not external */
  697. X#define    maindef
  698. X
  699. X#include        "estruct.h"    /* global structures and defines */
  700. X#include    "efunc.h"    /* function declarations and name table    */
  701. X#include    "edef.h"    /* global definitions */
  702. X#include    "ebind.h"    /* default key bindings */
  703. X
  704. X#if     VMS
  705. X#include        <ssdef.h>
  706. X#define GOOD    (SS$_NORMAL)
  707. X#endif
  708. X
  709. X#ifndef GOOD
  710. X#define GOOD    0
  711. X#endif
  712. X
  713. Xmain(argc, argv)
  714. Xchar    *argv[];
  715. X{
  716. X        register int    c;
  717. X        register int    f;
  718. X        register int    n;
  719. X        register int    mflag;
  720. X    register BUFFER *bp;
  721. X    register int    ffile;        /* first file flag */
  722. X    register int    carg;        /* current arg to scan */
  723. X    int basec;            /* c stripped of meta character */
  724. X    int viewflag;            /* are we starting in view mode? */
  725. X        char bname[NBUFN];        /* buffer name of file to read */
  726. X
  727. X    /* initialize the editor and process the startup file */
  728. X        strcpy(bname, "main");    /* default buffer name */
  729. X        edinit(bname);        /* Buffers, windows.    */
  730. X        vtinit();        /* Displays.            */
  731. X    startup();        /* execute .emacsrc if there */
  732. X    viewflag = FALSE;
  733. X    ffile = TRUE;        /* no file to edit yet */
  734. X    update();        /* let the user know we are here */
  735. X    
  736. X    /* scan through the command line and get the files to edit */
  737. X    for (carg = 1; carg < argc; ++carg) {
  738. X        /* if its a switch, process it */
  739. X        if (argv[carg][0] == '-') {
  740. X            switch (argv[carg][1]) {
  741. X                case 'v':    /* -v for View File */
  742. X                case 'V':
  743. X                    viewflag = TRUE;
  744. X                    break;
  745. X                case 'e':    /* -e for Edit file */
  746. X                case 'E':
  747. X                    viewflag = FALSE;
  748. X                    break;
  749. X                default:    /* unknown switch */
  750. X                    /* ignore this for now */
  751. X                    break;
  752. X            }
  753. X        } else {    /* process a file name */
  754. X            /* set up a buffer for this file */
  755. X                    makename(bname, argv[carg]);
  756. X
  757. X            /* if this is the first file, read it in */
  758. X            if (ffile) {
  759. X                bp = curbp;
  760. X                makename(bname, argv[carg]);
  761. X                strcpy(bp->b_bname, bname);
  762. X                strcpy(bp->b_fname, argv[carg]);
  763. X                if (readin(argv[carg], (viewflag==FALSE))
  764. X                                == ABORT) {
  765. X                    strcpy(bp->b_bname, "main");
  766. X                    strcpy(bp->b_fname, "");
  767. X                }
  768. X                bp->b_dotp = bp->b_linep;
  769. X                bp->b_doto = 0;
  770. X                ffile = FALSE;
  771. X            } else {
  772. X                /* set this to inactive */
  773. X                bp = bfind(bname, TRUE, 0);
  774. X                strcpy(bp->b_fname, argv[carg]);
  775. X                bp->b_active = FALSE;
  776. X            }
  777. X
  778. X            /* set the view mode appropriatly */
  779. X            if (viewflag)
  780. X                bp->b_mode |= MDVIEW;
  781. X        }
  782. X    }
  783. X
  784. X    /* setup to process commands */
  785. X        lastflag = 0;                           /* Fake last flags.     */
  786. X    curbp->b_mode = curbp->b_mode | gmode;    /* and set default modes*/
  787. X    curwp->w_flag |= WFMODE;        /* and force an update    */
  788. X
  789. Xloop:
  790. X        update();                               /* Fix up the screen    */
  791. X        c = getkey();
  792. X        if (mpresf != FALSE) {
  793. X                mlerase();
  794. X                update();
  795. X#if    CLRMSG
  796. X                if (c == ' ')                   /* ITS EMACS does this  */
  797. X                        goto loop;
  798. X#endif
  799. X        }
  800. X        f = FALSE;
  801. X        n = 1;
  802. X
  803. X    /* do META-# processing if needed */
  804. X
  805. X    basec = c & ~META;        /* strip meta char off if there */
  806. X    if ((c & META) && ((basec >= '0' && basec <= '9') || basec == '-')) {
  807. X        f = TRUE;        /* there is a # arg */
  808. X        n = 0;            /* start with a zero default */
  809. X        mflag = 1;        /* current minus flag */
  810. X        c = basec;        /* strip the META */
  811. X        while ((c >= '0' && c <= '9') || (c == '-')) {
  812. X            if (c == '-') {
  813. X                /* already hit a minus or digit? */
  814. X                if ((mflag == -1) || (n != 0))
  815. X                    break;
  816. X                mflag = -1;
  817. X            } else {
  818. X                n = n * 10 + (c - '0');
  819. X            }
  820. X            if ((n == 0) && (mflag == -1))    /* lonely - */
  821. X                mlwrite("Arg:");
  822. X            else
  823. X                mlwrite("Arg: %d",n * mflag);
  824. X
  825. X            c = getkey();    /* get the next key */
  826. X        }
  827. X        n = n * mflag;    /* figure in the sign */
  828. X    }
  829. X
  830. X    /* do ^U repeat argument processing */
  831. X
  832. X        if (c == (CTRL|'U')) {                  /* ^U, start argument   */
  833. X                f = TRUE;
  834. X                n = 4;                          /* with argument of 4 */
  835. X                mflag = 0;                      /* that can be discarded. */
  836. X                mlwrite("Arg: 4");
  837. X                while ((c=getkey()) >='0' && c<='9' || c==(CTRL|'U') || c=='-'){
  838. X                        if (c == (CTRL|'U'))
  839. X                                n = n*4;
  840. X                        /*
  841. X                         * If dash, and start of argument string, set arg.
  842. X                         * to -1.  Otherwise, insert it.
  843. X                         */
  844. X                        else if (c == '-') {
  845. X                                if (mflag)
  846. X                                        break;
  847. X                                n = 0;
  848. X                                mflag = -1;
  849. X                        }
  850. X                        /*
  851. X                         * If first digit entered, replace previous argument
  852. X                         * with digit and set sign.  Otherwise, append to arg.
  853. X                         */
  854. X                        else {
  855. X                                if (!mflag) {
  856. X                                        n = 0;
  857. X                                        mflag = 1;
  858. X                                }
  859. X                                n = 10*n + c - '0';
  860. X                        }
  861. X                        mlwrite("Arg: %d", (mflag >=0) ? n : (n ? -n : -1));
  862. X                }
  863. X                /*
  864. X                 * Make arguments preceded by a minus sign negative and change
  865. X                 * the special argument "^U -" to an effective "^U -1".
  866. X                 */
  867. X                if (mflag == -1) {
  868. X                        if (n == 0)
  869. X                                n++;
  870. X                        n = -n;
  871. X                }
  872. X        }
  873. X        if (c == (CTRL|'X'))                    /* ^X is a prefix       */
  874. X                c = CTLX | getctl();
  875. X        if (kbdmip != NULL) {                   /* Save macro strokes.  */
  876. X                if (c!=(CTLX|')') && kbdmip>&kbdm[NKBDM-6]) {
  877. X                        ctrlg(FALSE, 0);
  878. X                        goto loop;
  879. X                }
  880. X                if (f != FALSE) {
  881. X                        *kbdmip++ = (CTRL|'U');
  882. X                        *kbdmip++ = n;
  883. X                }
  884. X                *kbdmip++ = c;
  885. X        }
  886. X        execute(c, f, n);                       /* Do it.               */
  887. X        goto loop;
  888. X}
  889. X
  890. X/*
  891. X * Initialize all of the buffers and windows. The buffer name is passed down
  892. X * as an argument, because the main routine may have been told to read in a
  893. X * file by default, and we want the buffer name to be right.
  894. X */
  895. Xedinit(bname)
  896. Xchar    bname[];
  897. X{
  898. X        register BUFFER *bp;
  899. X        register WINDOW *wp;
  900. X    char *malloc();
  901. X
  902. X        bp = bfind(bname, TRUE, 0);             /* First buffer         */
  903. X        blistp = bfind("[List]", TRUE, BFTEMP); /* Buffer list buffer   */
  904. X        wp = (WINDOW *) malloc(sizeof(WINDOW)); /* First window         */
  905. X        if (bp==NULL || wp==NULL || blistp==NULL)
  906. X                exit(1);
  907. X        curbp  = bp;                            /* Make this current    */
  908. X        wheadp = wp;
  909. X        curwp  = wp;
  910. X        wp->w_wndp  = NULL;                     /* Initialize window    */
  911. X        wp->w_bufp  = bp;
  912. X        bp->b_nwnd  = 1;                        /* Displayed.           */
  913. X        wp->w_linep = bp->b_linep;
  914. X        wp->w_dotp  = bp->b_linep;
  915. X        wp->w_doto  = 0;
  916. X        wp->w_markp = NULL;
  917. X        wp->w_marko = 0;
  918. X        wp->w_toprow = 0;
  919. X        wp->w_ntrows = term.t_nrow-1;           /* "-1" for mode line.  */
  920. X        wp->w_force = 0;
  921. X        wp->w_flag  = WFMODE|WFHARD;            /* Full.                */
  922. X}
  923. X
  924. X/*
  925. X * This is the general command execution routine. It handles the fake binding
  926. X * of all the keys to "self-insert". It also clears out the "thisflag" word,
  927. X * and arranges to move it to the "lastflag", so that the next command can
  928. X * look at it. Return the status of command.
  929. X */
  930. Xexecute(c, f, n)
  931. X{
  932. X        register KEYTAB *ktp;
  933. X        register int    status;
  934. X
  935. X        ktp = &keytab[0];                       /* Look in key table.   */
  936. X        while (ktp->k_fp != NULL) {
  937. X                if (ktp->k_code == c) {
  938. X                        thisflag = 0;
  939. X                        status   = (*ktp->k_fp)(f, n);
  940. X                        lastflag = thisflag;
  941. X                        return (status);
  942. X                }
  943. X                ++ktp;
  944. X        }
  945. X
  946. X        /*
  947. X         * If a space was typed, fill column is defined, the argument is non-
  948. X         * negative, wrap mode is enabled, and we are now past fill column,
  949. X     * and we are not read-only, perform word wrap.
  950. X         */
  951. X        if (c == ' ' && (curwp->w_bufp->b_mode & MDWRAP) && fillcol > 0 &&
  952. X        n >= 0 && getccol(FALSE) > fillcol &&
  953. X        (curwp->w_bufp->b_mode & MDVIEW) == FALSE)
  954. X                wrapword();
  955. X
  956. X        if ((c>=0x20 && c<=0x7E)                /* Self inserting.      */
  957. X        ||  (c>=0xA0 && c<=0xFE)) {
  958. X                if (n <= 0) {                   /* Fenceposts.          */
  959. X                        lastflag = 0;
  960. X                        return (n<0 ? FALSE : TRUE);
  961. X                }
  962. X                thisflag = 0;                   /* For the future.      */
  963. X
  964. X        /* if we are in overwrite mode, not at eol,
  965. X           and next char is not a tab or we are at a tab stop,
  966. X           delete a char forword            */
  967. X        if (curwp->w_bufp->b_mode & MDOVER &&
  968. X            curwp->w_doto < curwp->w_dotp->l_used &&
  969. X            (lgetc(curwp->w_dotp, curwp->w_doto) != '\t' ||
  970. X             (curwp->w_doto) % 8 == 7))
  971. X                ldelete(1, FALSE);
  972. X
  973. X        /* do the appropriate insertion */
  974. X        if (c == '}' && (curbp->b_mode & MDCMOD) != 0)
  975. X                status = insbrace(n, c);
  976. X            else if (c == '#' && (curbp->b_mode & MDCMOD) != 0)
  977. X                status = inspound();
  978. X            else
  979. X                    status = linsert(n, c);
  980. X
  981. X                lastflag = thisflag;
  982. X                return (status);
  983. X        }
  984. X    mlwrite("\007[Key not bound]");        /* complain        */
  985. X        lastflag = 0;                           /* Fake last flags.     */
  986. X        return (FALSE);
  987. X}
  988. X
  989. X/*
  990. X * Read in a key.
  991. X * Do the standard keyboard preprocessing. Convert the keys to the internal
  992. X * character set.
  993. X */
  994. Xgetkey()
  995. X{
  996. X    int    c;
  997. X#if    AMIGA
  998. X    int    d;
  999. X#endif
  1000. X
  1001. X        c = (*term.t_getchar)();
  1002. X
  1003. X#if RAINBOW
  1004. X
  1005. X        if (c & Function_Key)
  1006. X                {
  1007. X                int i;
  1008. X
  1009. X                for (i = 0; i < lk_map_size; i++)
  1010. X                        if (c == lk_map[i][0])
  1011. X                                return lk_map[i][1];
  1012. X                }
  1013. X        else if (c == Shift + 015) return CTRL | 'J';
  1014. X        else if (c == Shift + 0x7F) return META | 0x7F;
  1015. X#endif
  1016. X
  1017. X#if    MSDOS
  1018. X    if (c == 0) {                /* Apply SPEC prefix    */
  1019. X        c = getkey();
  1020. X        return(SPEC | c);
  1021. X    }
  1022. X#endif
  1023. X
  1024. X#if    AMIGA
  1025. X    /* apply SPEC prefix */
  1026. X    if ((unsigned)c == 155) {
  1027. X        c = (*term.t_getchar)();
  1028. X
  1029. X        /* first try to see if it is a cursor key */
  1030. X        if ((c >= 'A' && c <= 'D') || c == 'S' || c == 'T')
  1031. X            return(SPEC | c);
  1032. X
  1033. X        /* next, a 2 char sequence */
  1034. X        d = (*term.t_getchar)();
  1035. X        if (d == '~')
  1036. X            return(SPEC | c);
  1037. X
  1038. X        /* decode a 3 char sequence */
  1039. X        c = d + 32;
  1040. X        /* if a shifted function key, eat the tilde */
  1041. X        if (d >= '0' && d <= '9')
  1042. X            d = (*term.t_getchar)();
  1043. X        return(SPEC | c);
  1044. X    }
  1045. X#endif
  1046. X
  1047. X        if (c == METACH) {                      /* Apply M- prefix      */
  1048. X                c = getctl();
  1049. X                return (META | c);
  1050. X        }
  1051. X
  1052. X        if (c>=0x00 && c<=0x1F)                 /* C0 control -> C-     */
  1053. X                c = CTRL | (c+'@');
  1054. X        return (c);
  1055. X}
  1056. X
  1057. X/*
  1058. X * Get a key.
  1059. X * Apply control modifications to the read key.
  1060. X */
  1061. Xgetctl()
  1062. X{
  1063. X        register int    c;
  1064. X
  1065. X        c = (*term.t_getchar)();
  1066. X        if (c>='a' && c<='z')                   /* Force to upper       */
  1067. X                c -= 0x20;
  1068. X        if (c>=0x00 && c<=0x1F)                 /* C0 control -> C-     */
  1069. X                c = CTRL | (c+'@');
  1070. X        return (c);
  1071. X}
  1072. X
  1073. X/*
  1074. X * Fancy quit command, as implemented by Norm. If the any buffer has
  1075. X * changed do a write on that buffer and exit emacs, otherwise simply exit.
  1076. X */
  1077. Xquickexit(f, n)
  1078. X{
  1079. X    register BUFFER *bp;    /* scanning pointer to buffers */
  1080. X
  1081. X    bp = bheadp;
  1082. X    while (bp != NULL) {
  1083. X            if ((bp->b_flag&BFCHG) != 0    /* Changed.             */
  1084. X            && (bp->b_flag&BFTEMP) == 0) {    /* Real.                */
  1085. X            curbp = bp;        /* make that buffer cur    */
  1086. X            mlwrite("[Saving %s]",bp->b_fname);
  1087. X                    filesave(f, n);
  1088. X        }
  1089. X    bp = bp->b_bufp;            /* on to the next buffer */
  1090. X    }
  1091. X        quit(f, n);                             /* conditionally quit   */
  1092. X}
  1093. X
  1094. X/*
  1095. X * Quit command. If an argument, always quit. Otherwise confirm if a buffer
  1096. X * has been changed and not written out. Normally bound to "C-X C-C".
  1097. X */
  1098. Xquit(f, n)
  1099. X{
  1100. X        register int    s;
  1101. X
  1102. X        if (f != FALSE                          /* Argument forces it.  */
  1103. X        || anycb() == FALSE                     /* All buffers clean.   */
  1104. X                        /* User says it's OK.   */
  1105. X        || (s=mlyesno("Modified buffers exist. Leave anyway")) == TRUE) {
  1106. X#if    FILOCK
  1107. X        if (lockrel() != TRUE) {
  1108. X            (*term.t_putchar)('\n');
  1109. X            (*term.t_putchar)('\r');
  1110. X            (*term.t_close)();
  1111. X            exit(1);
  1112. X        }
  1113. X#endif
  1114. X                vttidy();
  1115. X                exit(GOOD);
  1116. X        }
  1117. X    mlwrite("");
  1118. X        return (s);
  1119. X}
  1120. X
  1121. X/*
  1122. X * Begin a keyboard macro.
  1123. X * Error if not at the top level in keyboard processing. Set up variables and
  1124. X * return.
  1125. X */
  1126. Xctlxlp(f, n)
  1127. X{
  1128. X        if (kbdmip!=NULL || kbdmop!=NULL) {
  1129. X                mlwrite("Not now");
  1130. X                return (FALSE);
  1131. X        }
  1132. X        mlwrite("[Start macro]");
  1133. X        kbdmip = &kbdm[0];
  1134. X        return (TRUE);
  1135. X}
  1136. X
  1137. X/*
  1138. X * End keyboard macro. Check for the same limit conditions as the above
  1139. X * routine. Set up the variables and return to the caller.
  1140. X */
  1141. Xctlxrp(f, n)
  1142. X{
  1143. X        if (kbdmip == NULL) {
  1144. X                mlwrite("Not now");
  1145. X                return (FALSE);
  1146. X        }
  1147. X        mlwrite("[End macro]");
  1148. X        kbdmip = NULL;
  1149. X        return (TRUE);
  1150. X}
  1151. X
  1152. X/*
  1153. X * Execute a macro.
  1154. X * The command argument is the number of times to loop. Quit as soon as a
  1155. X * command gets an error. Return TRUE if all ok, else FALSE.
  1156. X */
  1157. Xctlxe(f, n)
  1158. X{
  1159. X        register int    c;
  1160. X        register int    af;
  1161. X        register int    an;
  1162. X        register int    s;
  1163. X
  1164. X        if (kbdmip!=NULL || kbdmop!=NULL) {
  1165. X                mlwrite("Not now");
  1166. X                return (FALSE);
  1167. X        }
  1168. X        if (n <= 0)
  1169. X                return (TRUE);
  1170. X        do {
  1171. X                kbdmop = &kbdm[0];
  1172. X                do {
  1173. X                        af = FALSE;
  1174. X                        an = 1;
  1175. X                        if ((c = *kbdmop++) == (CTRL|'U')) {
  1176. X                                af = TRUE;
  1177. X                                an = *kbdmop++;
  1178. X                                c  = *kbdmop++;
  1179. X                        }
  1180. X                        s = TRUE;
  1181. X                } while (c!=(CTLX|')') && (s=execute(c, af, an))==TRUE);
  1182. X                kbdmop = NULL;
  1183. X        } while (s==TRUE && --n);
  1184. X        return (s);
  1185. X}
  1186. X
  1187. X/*
  1188. X * Abort.
  1189. X * Beep the beeper. Kill off any keyboard macro, etc., that is in progress.
  1190. X * Sometimes called as a routine, to do general aborting of stuff.
  1191. X */
  1192. Xctrlg(f, n)
  1193. X{
  1194. X        (*term.t_beep)();
  1195. X        if (kbdmip != NULL) {
  1196. X                kbdm[0] = (CTLX|')');
  1197. X                kbdmip  = NULL;
  1198. X        }
  1199. X    mlwrite("[Aborted]");
  1200. X        return (ABORT);
  1201. X}
  1202. X
  1203. X/* tell the user that this command is illegal while we are in
  1204. X   VIEW (read-only) mode                */
  1205. X
  1206. Xrdonly()
  1207. X
  1208. X{
  1209. X    (*term.t_beep)();
  1210. X    mlwrite("[Key illegal in VIEW mode]");
  1211. X    return(FALSE);
  1212. X}
  1213. *-*-END-of-main.c-*-*
  1214. exit
  1215.  
  1216.  
  1217.