home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume6 / uemacs3.7 / part07 < prev    next >
Text File  |  1986-11-30  |  55KB  |  1,579 lines

  1. Subject: v06i077:  MicroEmacs, Version 3.7 (uEmacs3.7), Part07/12
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.UUCP
  4.  
  5. Submitted by: ihnp4!pur-ee!pur-phy!duncan!lawrence
  6. Mod.sources: Volume 6, Issue 77
  7. Archive-name: uEmacs3.7/Part07
  8.  
  9. [  This is the latest revision of one of two programs named "MicroEmacs";
  10.    when discussing these on the net, or in contacting the authors, make
  11.    sure to mention the version number -- in this case 3.7 -- as that is
  12.    the easiest way to distinguish between them.  Daniel will be posting
  13.    uuencoded executables in net.micro.pc and net.micro.amiga; the file
  14.    'readme' contains information on how to also get these from him
  15.    directly.   --r$ ]
  16.  
  17. echo extracting - line.c
  18. sed 's/^X//' > line.c << 'FRIDAY_NIGHT'
  19. X/*
  20. X * The functions in this file are a general set of line management utilities.
  21. X * They are the only routines that touch the text. They also touch the buffer
  22. X * and window structures, to make sure that the necessary updating gets done.
  23. X * There are routines in this file that handle the kill buffer too. It isn't
  24. X * here for any good reason.
  25. X *
  26. X * Note that this code only updates the dot and mark values in the window list.
  27. X * Since all the code acts on the current window, the buffer that we are
  28. X * editing must be being displayed, which means that "b_nwnd" is non zero,
  29. X * which means that the dot and mark values in the buffer headers are nonsense.
  30. X */
  31. X
  32. X#include        <stdio.h>
  33. X#include    "estruct.h"
  34. X#include        "edef.h"
  35. X
  36. XKILL *ykbuf;    /* ptr to current kill buffer chunk being yanked */
  37. Xint ykboff;    /* offset into that chunk */
  38. X
  39. X/*
  40. X * This routine allocates a block of memory large enough to hold a LINE
  41. X * containing "used" characters. The block is always rounded up a bit. Return
  42. X * a pointer to the new block, or NULL if there isn't any memory left. Print a
  43. X * message in the message line if no space.
  44. X */
  45. XLINE    *
  46. Xlalloc(used)
  47. Xregister int    used;
  48. X{
  49. X        register LINE   *lp;
  50. X        register int    size;
  51. X    char *malloc();
  52. X
  53. X        size = (used+NBLOCK-1) & ~(NBLOCK-1);
  54. X        if (size == 0)                          /* Assume that an empty */
  55. X                size = NBLOCK;                  /* line is for type-in. */
  56. X        if ((lp = (LINE *) malloc(sizeof(LINE)+size)) == NULL) {
  57. X                mlwrite("Cannot allocate %d bytes", size);
  58. X                return (NULL);
  59. X        }
  60. X        lp->l_size = size;
  61. X        lp->l_used = used;
  62. X        return (lp);
  63. X}
  64. X
  65. X/*
  66. X * Delete line "lp". Fix all of the links that might point at it (they are
  67. X * moved to offset 0 of the next line. Unlink the line from whatever buffer it
  68. X * might be in. Release the memory. The buffers are updated too; the magic
  69. X * conditions described in the above comments don't hold here.
  70. X */
  71. Xlfree(lp)
  72. Xregister LINE   *lp;
  73. X{
  74. X        register BUFFER *bp;
  75. X        register WINDOW *wp;
  76. X
  77. X        wp = wheadp;
  78. X        while (wp != NULL) {
  79. X                if (wp->w_linep == lp)
  80. X                        wp->w_linep = lp->l_fp;
  81. X                if (wp->w_dotp  == lp) {
  82. X                        wp->w_dotp  = lp->l_fp;
  83. X                        wp->w_doto  = 0;
  84. X                }
  85. X                if (wp->w_markp == lp) {
  86. X                        wp->w_markp = lp->l_fp;
  87. X                        wp->w_marko = 0;
  88. X                }
  89. X                wp = wp->w_wndp;
  90. X        }
  91. X        bp = bheadp;
  92. X        while (bp != NULL) {
  93. X                if (bp->b_nwnd == 0) {
  94. X                        if (bp->b_dotp  == lp) {
  95. X                                bp->b_dotp = lp->l_fp;
  96. X                                bp->b_doto = 0;
  97. X                        }
  98. X                        if (bp->b_markp == lp) {
  99. X                                bp->b_markp = lp->l_fp;
  100. X                                bp->b_marko = 0;
  101. X                        }
  102. X                }
  103. X                bp = bp->b_bufp;
  104. X        }
  105. X        lp->l_bp->l_fp = lp->l_fp;
  106. X        lp->l_fp->l_bp = lp->l_bp;
  107. X        free((char *) lp);
  108. X}
  109. X
  110. X/*
  111. X * This routine gets called when a character is changed in place in the current
  112. X * buffer. It updates all of the required flags in the buffer and window
  113. X * system. The flag used is passed as an argument; if the buffer is being
  114. X * displayed in more than 1 window we change EDIT t HARD. Set MODE if the
  115. X * mode line needs to be updated (the "*" has to be set).
  116. X */
  117. Xlchange(flag)
  118. Xregister int    flag;
  119. X{
  120. X        register WINDOW *wp;
  121. X
  122. X        if (curbp->b_nwnd != 1)                 /* Ensure hard.         */
  123. X                flag = WFHARD;
  124. X        if ((curbp->b_flag&BFCHG) == 0) {       /* First change, so     */
  125. X                flag |= WFMODE;                 /* update mode lines.   */
  126. X                curbp->b_flag |= BFCHG;
  127. X        }
  128. X        wp = wheadp;
  129. X        while (wp != NULL) {
  130. X                if (wp->w_bufp == curbp)
  131. X                        wp->w_flag |= flag;
  132. X                wp = wp->w_wndp;
  133. X        }
  134. X}
  135. X
  136. Xinsspace(f, n)    /* insert spaces forward into text */
  137. X
  138. Xint f, n;    /* default flag and numeric argument */
  139. X
  140. X{
  141. X    linsert(n, ' ');
  142. X    backchar(f, n);
  143. X}
  144. X
  145. X/*
  146. X * Insert "n" copies of the character "c" at the current location of dot. In
  147. X * the easy case all that happens is the text is stored in the line. In the
  148. X * hard case, the line has to be reallocated. When the window list is updated,
  149. X * take special care; I screwed it up once. You always update dot in the
  150. X * current window. You update mark, and a dot in another window, if it is
  151. X * greater than the place where you did the insert. Return TRUE if all is
  152. X * well, and FALSE on errors.
  153. X */
  154. Xlinsert(n, c)
  155. X{
  156. X        register char   *cp1;
  157. X        register char   *cp2;
  158. X        register LINE   *lp1;
  159. X        register LINE   *lp2;
  160. X        register LINE   *lp3;
  161. X        register int    doto;
  162. X        register int    i;
  163. X        register WINDOW *wp;
  164. X
  165. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  166. X        return(rdonly());    /* we are in read only mode    */
  167. X        lchange(WFEDIT);
  168. X        lp1 = curwp->w_dotp;                    /* Current line         */
  169. X        if (lp1 == curbp->b_linep) {            /* At the end: special  */
  170. X                if (curwp->w_doto != 0) {
  171. X                        mlwrite("bug: linsert");
  172. X                        return (FALSE);
  173. X                }
  174. X                if ((lp2=lalloc(n)) == NULL)    /* Allocate new line    */
  175. X                        return (FALSE);
  176. X                lp3 = lp1->l_bp;                /* Previous line        */
  177. X                lp3->l_fp = lp2;                /* Link in              */
  178. X                lp2->l_fp = lp1;
  179. X                lp1->l_bp = lp2;
  180. X                lp2->l_bp = lp3;
  181. X                for (i=0; i<n; ++i)
  182. X                        lp2->l_text[i] = c;
  183. X                curwp->w_dotp = lp2;
  184. X                curwp->w_doto = n;
  185. X                return (TRUE);
  186. X        }
  187. X        doto = curwp->w_doto;                   /* Save for later.      */
  188. X        if (lp1->l_used+n > lp1->l_size) {      /* Hard: reallocate     */
  189. X                if ((lp2=lalloc(lp1->l_used+n)) == NULL)
  190. X                        return (FALSE);
  191. X                cp1 = &lp1->l_text[0];
  192. X                cp2 = &lp2->l_text[0];
  193. X                while (cp1 != &lp1->l_text[doto])
  194. X                        *cp2++ = *cp1++;
  195. X                cp2 += n;
  196. X                while (cp1 != &lp1->l_text[lp1->l_used])
  197. X                        *cp2++ = *cp1++;
  198. X                lp1->l_bp->l_fp = lp2;
  199. X                lp2->l_fp = lp1->l_fp;
  200. X                lp1->l_fp->l_bp = lp2;
  201. X                lp2->l_bp = lp1->l_bp;
  202. X                free((char *) lp1);
  203. X        } else {                                /* Easy: in place       */
  204. X                lp2 = lp1;                      /* Pretend new line     */
  205. X                lp2->l_used += n;
  206. X                cp2 = &lp1->l_text[lp1->l_used];
  207. X                cp1 = cp2-n;
  208. X                while (cp1 != &lp1->l_text[doto])
  209. X                        *--cp2 = *--cp1;
  210. X        }
  211. X        for (i=0; i<n; ++i)                     /* Add the characters   */
  212. X                lp2->l_text[doto+i] = c;
  213. X        wp = wheadp;                            /* Update windows       */
  214. X        while (wp != NULL) {
  215. X                if (wp->w_linep == lp1)
  216. X                        wp->w_linep = lp2;
  217. X                if (wp->w_dotp == lp1) {
  218. X                        wp->w_dotp = lp2;
  219. X                        if (wp==curwp || wp->w_doto>doto)
  220. X                                wp->w_doto += n;
  221. X                }
  222. X                if (wp->w_markp == lp1) {
  223. X                        wp->w_markp = lp2;
  224. X                        if (wp->w_marko > doto)
  225. X                                wp->w_marko += n;
  226. X                }
  227. X                wp = wp->w_wndp;
  228. X        }
  229. X        return (TRUE);
  230. X}
  231. X
  232. X/*
  233. X * Insert a newline into the buffer at the current location of dot in the
  234. X * current window. The funny ass-backwards way it does things is not a botch;
  235. X * it just makes the last line in the file not a special case. Return TRUE if
  236. X * everything works out and FALSE on error (memory allocation failure). The
  237. X * update of dot and mark is a bit easier then in the above case, because the
  238. X * split forces more updating.
  239. X */
  240. Xlnewline()
  241. X{
  242. X        register char   *cp1;
  243. X        register char   *cp2;
  244. X        register LINE   *lp1;
  245. X        register LINE   *lp2;
  246. X        register int    doto;
  247. X        register WINDOW *wp;
  248. X
  249. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  250. X        return(rdonly());    /* we are in read only mode    */
  251. X        lchange(WFHARD);
  252. X        lp1  = curwp->w_dotp;                   /* Get the address and  */
  253. X        doto = curwp->w_doto;                   /* offset of "."        */
  254. X        if ((lp2=lalloc(doto)) == NULL)         /* New first half line  */
  255. X                return (FALSE);
  256. X        cp1 = &lp1->l_text[0];                  /* Shuffle text around  */
  257. X        cp2 = &lp2->l_text[0];
  258. X        while (cp1 != &lp1->l_text[doto])
  259. X                *cp2++ = *cp1++;
  260. X        cp2 = &lp1->l_text[0];
  261. X        while (cp1 != &lp1->l_text[lp1->l_used])
  262. X                *cp2++ = *cp1++;
  263. X        lp1->l_used -= doto;
  264. X        lp2->l_bp = lp1->l_bp;
  265. X        lp1->l_bp = lp2;
  266. X        lp2->l_bp->l_fp = lp2;
  267. X        lp2->l_fp = lp1;
  268. X        wp = wheadp;                            /* Windows              */
  269. X        while (wp != NULL) {
  270. X                if (wp->w_linep == lp1)
  271. X                        wp->w_linep = lp2;
  272. X                if (wp->w_dotp == lp1) {
  273. X                        if (wp->w_doto < doto)
  274. X                                wp->w_dotp = lp2;
  275. X                        else
  276. X                                wp->w_doto -= doto;
  277. X                }
  278. X                if (wp->w_markp == lp1) {
  279. X                        if (wp->w_marko < doto)
  280. X                                wp->w_markp = lp2;
  281. X                        else
  282. X                                wp->w_marko -= doto;
  283. X                }
  284. X                wp = wp->w_wndp;
  285. X        }
  286. X        return (TRUE);
  287. X}
  288. X
  289. X/*
  290. X * This function deletes "n" bytes, starting at dot. It understands how do deal
  291. X * with end of lines, etc. It returns TRUE if all of the characters were
  292. X * deleted, and FALSE if they were not (because dot ran into the end of the
  293. X * buffer. The "kflag" is TRUE if the text should be put in the kill buffer.
  294. X */
  295. Xldelete(n, kflag)
  296. X
  297. Xlong n;        /* # of chars to delete */
  298. Xint kflag;    /* put killed text in kill buffer flag */
  299. X
  300. X{
  301. X        register char   *cp1;
  302. X        register char   *cp2;
  303. X        register LINE   *dotp;
  304. X        register int    doto;
  305. X        register int    chunk;
  306. X        register WINDOW *wp;
  307. X
  308. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  309. X        return(rdonly());    /* we are in read only mode    */
  310. X        while (n != 0) {
  311. X                dotp = curwp->w_dotp;
  312. X                doto = curwp->w_doto;
  313. X                if (dotp == curbp->b_linep)     /* Hit end of buffer.   */
  314. X                        return (FALSE);
  315. X                chunk = dotp->l_used-doto;      /* Size of chunk.       */
  316. X                if (chunk > n)
  317. X                        chunk = n;
  318. X                if (chunk == 0) {               /* End of line, merge.  */
  319. X                        lchange(WFHARD);
  320. X                        if (ldelnewline() == FALSE
  321. X                        || (kflag!=FALSE && kinsert('\n')==FALSE))
  322. X                                return (FALSE);
  323. X                        --n;
  324. X                        continue;
  325. X                }
  326. X                lchange(WFEDIT);
  327. X                cp1 = &dotp->l_text[doto];      /* Scrunch text.        */
  328. X                cp2 = cp1 + chunk;
  329. X                if (kflag != FALSE) {           /* Kill?                */
  330. X                        while (cp1 != cp2) {
  331. X                                if (kinsert(*cp1) == FALSE)
  332. X                                        return (FALSE);
  333. X                                ++cp1;
  334. X                        }
  335. X                        cp1 = &dotp->l_text[doto];
  336. X                }
  337. X                while (cp2 != &dotp->l_text[dotp->l_used])
  338. X                        *cp1++ = *cp2++;
  339. X                dotp->l_used -= chunk;
  340. X                wp = wheadp;                    /* Fix windows          */
  341. X                while (wp != NULL) {
  342. X                        if (wp->w_dotp==dotp && wp->w_doto>=doto) {
  343. X                                wp->w_doto -= chunk;
  344. X                                if (wp->w_doto < doto)
  345. X                                        wp->w_doto = doto;
  346. X                        }
  347. X                        if (wp->w_markp==dotp && wp->w_marko>=doto) {
  348. X                                wp->w_marko -= chunk;
  349. X                                if (wp->w_marko < doto)
  350. X                                        wp->w_marko = doto;
  351. X                        }
  352. X                        wp = wp->w_wndp;
  353. X                }
  354. X                n -= chunk;
  355. X        }
  356. X        return (TRUE);
  357. X}
  358. X
  359. X/*
  360. X * Delete a newline. Join the current line with the next line. If the next line
  361. X * is the magic header line always return TRUE; merging the last line with the
  362. X * header line can be thought of as always being a successful operation, even
  363. X * if nothing is done, and this makes the kill buffer work "right". Easy cases
  364. X * can be done by shuffling data around. Hard cases require that lines be moved
  365. X * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
  366. X * "ldelete" only.
  367. X */
  368. Xldelnewline()
  369. X{
  370. X        register char   *cp1;
  371. X        register char   *cp2;
  372. X        register LINE   *lp1;
  373. X        register LINE   *lp2;
  374. X        register LINE   *lp3;
  375. X        register WINDOW *wp;
  376. X
  377. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  378. X        return(rdonly());    /* we are in read only mode    */
  379. X        lp1 = curwp->w_dotp;
  380. X        lp2 = lp1->l_fp;
  381. X        if (lp2 == curbp->b_linep) {            /* At the buffer end.   */
  382. X                if (lp1->l_used == 0)           /* Blank line.          */
  383. X                        lfree(lp1);
  384. X                return (TRUE);
  385. X        }
  386. X        if (lp2->l_used <= lp1->l_size-lp1->l_used) {
  387. X                cp1 = &lp1->l_text[lp1->l_used];
  388. X                cp2 = &lp2->l_text[0];
  389. X                while (cp2 != &lp2->l_text[lp2->l_used])
  390. X                        *cp1++ = *cp2++;
  391. X                wp = wheadp;
  392. X                while (wp != NULL) {
  393. X                        if (wp->w_linep == lp2)
  394. X                                wp->w_linep = lp1;
  395. X                        if (wp->w_dotp == lp2) {
  396. X                                wp->w_dotp  = lp1;
  397. X                                wp->w_doto += lp1->l_used;
  398. X                        }
  399. X                        if (wp->w_markp == lp2) {
  400. X                                wp->w_markp  = lp1;
  401. X                                wp->w_marko += lp1->l_used;
  402. X                        }
  403. X                        wp = wp->w_wndp;
  404. X                }
  405. X                lp1->l_used += lp2->l_used;
  406. X                lp1->l_fp = lp2->l_fp;
  407. X                lp2->l_fp->l_bp = lp1;
  408. X                free((char *) lp2);
  409. X                return (TRUE);
  410. X        }
  411. X        if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
  412. X                return (FALSE);
  413. X        cp1 = &lp1->l_text[0];
  414. X        cp2 = &lp3->l_text[0];
  415. X        while (cp1 != &lp1->l_text[lp1->l_used])
  416. X                *cp2++ = *cp1++;
  417. X        cp1 = &lp2->l_text[0];
  418. X        while (cp1 != &lp2->l_text[lp2->l_used])
  419. X                *cp2++ = *cp1++;
  420. X        lp1->l_bp->l_fp = lp3;
  421. X        lp3->l_fp = lp2->l_fp;
  422. X        lp2->l_fp->l_bp = lp3;
  423. X        lp3->l_bp = lp1->l_bp;
  424. X        wp = wheadp;
  425. X        while (wp != NULL) {
  426. X                if (wp->w_linep==lp1 || wp->w_linep==lp2)
  427. X                        wp->w_linep = lp3;
  428. X                if (wp->w_dotp == lp1)
  429. X                        wp->w_dotp  = lp3;
  430. X                else if (wp->w_dotp == lp2) {
  431. X                        wp->w_dotp  = lp3;
  432. X                        wp->w_doto += lp1->l_used;
  433. X                }
  434. X                if (wp->w_markp == lp1)
  435. X                        wp->w_markp  = lp3;
  436. X                else if (wp->w_markp == lp2) {
  437. X                        wp->w_markp  = lp3;
  438. X                        wp->w_marko += lp1->l_used;
  439. X                }
  440. X                wp = wp->w_wndp;
  441. X        }
  442. X        free((char *) lp1);
  443. X        free((char *) lp2);
  444. X        return (TRUE);
  445. X}
  446. X
  447. X/*
  448. X * Delete all of the text saved in the kill buffer. Called by commands when a
  449. X * new kill context is being created. The kill buffer array is released, just
  450. X * in case the buffer has grown to immense size. No errors.
  451. X */
  452. Xkdelete()
  453. X{
  454. X    KILL *kp;    /* ptr to scan kill buffer chunk list */
  455. X
  456. X        if (kbufh != NULL) {
  457. X
  458. X        /* first, delete all the chunks */
  459. X            kbufp = kbufh;
  460. X            while (kbufp != NULL) {
  461. X                kp = kbufp->d_next;
  462. X                free(kbufp);
  463. X                kbufp = kp;
  464. X            }
  465. X
  466. X        /* and reset all the kill buffer pointers */
  467. X        kbufh = kbufp = NULL;
  468. X        kused = KBLOCK;                
  469. X        }
  470. X}
  471. X
  472. X/*
  473. X * Insert a character to the kill buffer, allocating new chunks as needed.
  474. X * Return TRUE if all is well, and FALSE on errors.
  475. X */
  476. X
  477. Xkinsert(c)
  478. X
  479. Xint c;        /* character to insert in the kill buffer */
  480. X
  481. X{
  482. X    KILL *nchunk;    /* ptr to newly malloced chunk */
  483. X
  484. X    /* check to see if we need a new chunk */
  485. X    if (kused >= KBLOCK) {
  486. X        if ((nchunk = (KILL *)malloc(sizeof(KILL))) == NULL)
  487. X            return(FALSE);
  488. X        if (kbufh == NULL)    /* set head ptr if first time */
  489. X            kbufh = nchunk;
  490. X        if (kbufp != NULL)    /* point the current to this new one */
  491. X            kbufp->d_next = nchunk;
  492. X        kbufp = nchunk;
  493. X        kbufp->d_next = NULL;
  494. X        kused = 0;
  495. X    }
  496. X
  497. X    /* and now insert the character */
  498. X    kbufp->d_chunk[kused++] = c;
  499. X    return(TRUE);
  500. X}
  501. X
  502. X/*
  503. X * Yank text back from the kill buffer. This is really easy. All of the work
  504. X * is done by the standard insert routines. All you do is run the loop, and
  505. X * check for errors. Bound to "C-Y".
  506. X */
  507. Xyank(f, n)
  508. X{
  509. X        register int    c;
  510. X        register int    i;
  511. X    register char    *sp;    /* pointer into string to insert */
  512. X    KILL *kp;        /* pointer into kill buffer */
  513. X
  514. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  515. X        return(rdonly());    /* we are in read only mode    */
  516. X        if (n < 0)
  517. X                return (FALSE);
  518. X    /* make sure there is something to yank */
  519. X    if (kbufh == NULL)
  520. X        return(TRUE);        /* not an error, just nothing */
  521. X
  522. X    /* for each time.... */
  523. X        while (n--) {
  524. X        kp = kbufh;
  525. X        while (kp != NULL) {
  526. X            if (kp->d_next == NULL)
  527. X                i = kused;
  528. X            else
  529. X                i = KBLOCK;
  530. X            sp = kp->d_chunk;
  531. X            while (i--) {
  532. X                            if ((c = *sp++) == '\n') {
  533. X                                    if (lnewline(FALSE, 1) == FALSE)
  534. X                                            return (FALSE);
  535. X                            } else {
  536. X                                    if (linsert(1, c) == FALSE)
  537. X                                            return (FALSE);
  538. X                            }
  539. X                    }
  540. X                    kp = kp->d_next;
  541. X                }
  542. X        }
  543. X        return (TRUE);
  544. X}
  545. X
  546. X
  547. FRIDAY_NIGHT
  548. echo extracting - lock.c
  549. sed 's/^X//' > lock.c << 'FRIDAY_NIGHT'
  550. X/*    LOCK:    File locking command routines for MicroEMACS
  551. X        written by Daniel Lawrence
  552. X                                */
  553. X
  554. X#include <stdio.h>
  555. X#include "estruct.h"
  556. X#include "edef.h"
  557. X
  558. X#if    FILOCK
  559. X#if    BSD
  560. X#include <sys/errno.h>
  561. X
  562. Xextern int sys_nerr;        /* number of system error messages defined */
  563. Xextern char *sys_errlist[];    /* list of message texts */
  564. Xextern int errno;        /* current error */
  565. X
  566. Xchar *lname[NLOCKS];    /* names of all locked files */
  567. Xint numlocks;        /* # of current locks active */
  568. X
  569. X/* lockchk:    check a file for locking and add it to the list */
  570. X
  571. Xlockchk(fname)
  572. X
  573. Xchar *fname;    /* file to check for a lock */
  574. X
  575. X{
  576. X    register int i;        /* loop indexes */
  577. X    register int status;    /* return status */
  578. X    char *undolock();
  579. X
  580. X    /* check to see if that file is already locked here */
  581. X    if (numlocks > 0)
  582. X        for (i=0; i < numlocks; ++i)
  583. X            if (strcmp(fname, lname[i]) == 0)
  584. X                return(TRUE);
  585. X
  586. X    /* if we have a full locking table, bitch and leave */
  587. X    if (numlocks == NLOCKS) {
  588. X        mlwrite("LOCK ERROR: Lock table full");
  589. X        return(ABORT);
  590. X    }
  591. X
  592. X    /* next, try to lock it */
  593. X    status = lock(fname);
  594. X    if (status == ABORT)    /* file is locked, no override */
  595. X        return(ABORT);
  596. X    if (status == FALSE)    /* locked, overriden, dont add to table */
  597. X        return(TRUE);
  598. X
  599. X    /* we have now locked it, add it to our table */
  600. X    lname[++numlocks - 1] = (char *)malloc(strlen(fname) + 1);
  601. X    if (lname[numlocks - 1] == NULL) {    /* malloc failure */
  602. X        undolock(fname);        /* free the lock */
  603. X        mlwrite("Cannot lock, out of memory");
  604. X        --numlocks;
  605. X        return(ABORT);
  606. X    }
  607. X
  608. X    /* everthing is cool, add it to the table */
  609. X    strcpy(lname[numlocks-1], fname);
  610. X    return(TRUE);
  611. X}
  612. X
  613. X/*    lockrel:    release all the file locks so others may edit */
  614. X
  615. Xlockrel()
  616. X
  617. X{
  618. X    register int i;        /* loop index */
  619. X    register int status;    /* status of locks */
  620. X    register int s;        /* status of one unlock */
  621. X
  622. X    status = TRUE;
  623. X    if (numlocks > 0)
  624. X        for (i=0; i < numlocks; ++i) {
  625. X            if ((s = unlock(lname[i])) != TRUE)
  626. X                status = s;
  627. X            free(lname[i]);
  628. X        }
  629. X    numlocks = 0;
  630. X    return(status);
  631. X}
  632. X
  633. X/* lock:    Check and lock a file from access by others
  634. X        returns    TRUE = files was not locked and now is
  635. X            FALSE = file was locked and overridden
  636. X            ABORT = file was locked, abort command
  637. X*/
  638. X
  639. Xlock(fname)
  640. X
  641. Xchar *fname;    /* file name to lock */
  642. X
  643. X{
  644. X    register char *locker;    /* lock error message */
  645. X    register int status;    /* return status */
  646. X    char msg[NSTRING];    /* message string */
  647. X    char *dolock();
  648. X
  649. X    /* attempt to lock the file */
  650. X    locker = dolock(fname);
  651. X    if (locker == NULL)    /* we win */
  652. X        return(TRUE);
  653. X
  654. X    /* file failed...abort */
  655. X    if (strncmp(locker, "LOCK", 4) == 0) {
  656. X        lckerror(locker);
  657. X        return(ABORT);
  658. X    }
  659. X
  660. X    /* someone else has it....override? */
  661. X    strcpy(msg, "File in use by ");
  662. X    strcat(msg, locker);
  663. X    strcat(msg, ", overide?");
  664. X    status = mlyesno(msg);        /* ask them */
  665. X    if (status == TRUE)
  666. X        return(FALSE);
  667. X    else
  668. X        return(ABORT);
  669. X}
  670. X
  671. X/*    unlock:    Unlock a file
  672. X        this only warns the user if it fails
  673. X                            */
  674. X
  675. Xunlock(fname)
  676. X
  677. Xchar *fname;    /* file to unlock */
  678. X
  679. X{
  680. X    register char *locker;    /* undolock return string */
  681. X    char *undolock();
  682. X
  683. X    /* unclock and return */
  684. X    locker = undolock(fname);
  685. X    if (locker == NULL)
  686. X        return(TRUE);
  687. X
  688. X    /* report the error and come back */
  689. X    lckerror(locker);
  690. X    return(FALSE);
  691. X}
  692. X
  693. Xlckerror(errstr)    /* report a lock error */
  694. X
  695. Xchar *errstr;        /* lock error string to print out */
  696. X
  697. X{
  698. X    char obuf[NSTRING];    /* output buffer for error message */
  699. X
  700. X    strcpy(obuf, errstr);
  701. X    strcat(obuf, " - ");
  702. X    if (errno < sys_nerr)
  703. X        strcat(obuf, sys_errlist[errno]);
  704. X    else
  705. X        strcat(obuf, "[can not get system error message]");
  706. X    mlwrite(obuf);
  707. X}
  708. X#endif
  709. X#else
  710. Xlckhello()    /* dummy function */
  711. X{
  712. X}
  713. X#endif
  714. FRIDAY_NIGHT
  715. echo extracting - main.c
  716. sed 's/^X//' > main.c << 'FRIDAY_NIGHT'
  717. X/*
  718. X * This program is in public domain; written by Dave G. Conroy.
  719. X * This file contains the main driving routine, and some keyboard processing
  720. X * code, for the MicroEMACS screen editor.
  721. X *
  722. X * REVISION HISTORY:
  723. X *
  724. X * 1.0  Steve Wilhite, 30-Nov-85
  725. X *      - Removed the old LK201 and VT100 logic. Added code to support the
  726. X *        DEC Rainbow keyboard (which is a LK201 layout) using the the Level
  727. X *        1 Console In ROM INT. See "rainbow.h" for the function key defs
  728. X *      Steve Wilhite, 1-Dec-85
  729. X *      - massive cleanup on code in display.c and search.c
  730. X *
  731. X * 2.0  George Jones, 12-Dec-85
  732. X *      - Ported to Amiga.
  733. X *
  734. X * 3.0  Daniel Lawrence, 29-Dec-85
  735. X *      - rebound keys/added new fast buffered I/O for AMIGA
  736. X *    - added META- repeat commands
  737. X *    - added reposition default to center screen (yeah!)
  738. X *    - changed exit with modified buffers message
  739. X *    - made filesave tell us what it is doing
  740. X *    - changed search string entry to terminate with <ESC>
  741. X *      so we can use <NL> in search/replace strings
  742. X *    - updated version number in mode line to 3.0
  743. X *    12-Jan-86
  744. X *    - Added code to reconize the Search/replace functions
  745. X *    - Added code to perform search/replace & query functions
  746. X *    14-Jan-86
  747. X *    - moved search logic to separate function in search.c
  748. X *    - added replace and query replace functions
  749. X *    - separated out control key expansions to be used by others in search.c
  750. X *    15-Jan-86
  751. X *    - changed "visiting" to finding
  752. X *    - changed yes/no responces to not need return
  753. X *    - cleaned up various messages
  754. X *    16-jan-86
  755. X *    - fixed spurious spawn message in MSDOS
  756. X *    - added ^X-S synonime to save command
  757. X *    - moved escape to shell to ^X-C
  758. X *    21-jan-86
  759. X *    - added code to suspend shell under BSD
  760. X *    22-jan-86
  761. X *    - added function key support (SPEC) under MSDOS
  762. X *    - Abort now prints [Aborted] on message line
  763. X *    23-jan-86
  764. X *    - Added modes and commends to set/unset them
  765. X *    24-jan-86
  766. X *    - Added Goto Line command
  767. X *    - added Rename Buffer command
  768. X *    28-jan-86
  769. X *    - added goto begining and end of paragraph commands (META-P/META-N)
  770. X *    - re-wrote kdelete to use realloc. gained MUCH speed here when
  771. X *      doing large wipes both on UNIX and MSDOS. Changed kill buffer
  772. X *      allocation block size from 256 bytes to 1 k
  773. X *    29-jan-86
  774. X *    - moved extern function declarations to efunc.h
  775. X *    - made name[] name binding table
  776. X *    30-jan-86
  777. X *    - fixed Previous/Next paragraph command not to wrap around EOF
  778. X *    - added Fill Paragraph command (META-Q)
  779. X *    4-feb-86
  780. X *    - added code to properly display long lines, scrolling them right
  781. X *      to left
  782. X *    5-feb-85
  783. X *    - rewrote code to right/left scroll...much better
  784. X *    - added shifted arror keys on IBMPC
  785. X *    6-feb-85
  786. X *    - add option to allow forword-word to jump to begining of
  787. X *      next word instead of end of current one. This is different from
  788. X *      other emacs' but can be configured off in estruct.h
  789. X *    - added VIEW mode to allow a buffer to be read only
  790. X *       (-v switch on command line will activate this)
  791. X *    - changed quick exit to write out ALL changed buffers!!!
  792. X *      MAKE SURE YOU KNOW THIS WHEN META-Zing
  793. X *    10-feb-86
  794. X *    - added handling of lines longer than allowed on file read in
  795. X *      (they wrap on additional lines)
  796. X *    - made having space clear the message line and NOT insert itself
  797. X *      a configuration option in ed.h
  798. X *    11-feb-86
  799. X *    - added Describe-command and Help commands.
  800. X *    13-feb-86
  801. X *    - added View file command (^X ^V) and finished HELP command
  802. X *    14-feb-86
  803. X *    - added option to let main loop skip update if type ahead commands
  804. X *       are queued up
  805. X *    16-feb-86
  806. X *    - added Insert File command
  807. X *    17-feb-86
  808. X *    - added scroll next window up/down commands
  809. X *    18-feb-86
  810. X *    - added CMODE indentation
  811. X *    - re-arranged header files to standerdize extern and global
  812. X *      definitions
  813. X *    - changed version number to 3.2
  814. X *    - added numeric arguments to search, reverse search and
  815. X *      search and replace
  816. X *    24-feb-86
  817. X *    - added Bind To Key function (^C for now) to allow the user
  818. X *      to change his command keys
  819. X *    - added Unbind key function (M-^C for now)
  820. X *    - added execute named command to execute unbound commands (M-X)
  821. X *    - added describe bindings command (not bound)
  822. X *    - changed version number to 3.3
  823. X *    25-feb-86
  824. X *    - scrapped CERROR mode (too many compilers)
  825. X *    - added EXACT mode for case sensitive searchers
  826. X *    26-feb-86
  827. X *    - added command completion on execute named command and
  828. X *      all routined grabbing a command name
  829. X *    - adding execute-command-line command and its support functions
  830. X *      (in preporation for sourcing files)
  831. X *    - added Execute Buffer command
  832. X *    27-feb-86
  833. X *    - added execute(source) file command and added code to automatically
  834. X *      execute emacs.rc (or .emacsrc on UNIX) before initial read in
  835. X *    - changed version number to 3.4
  836. X *    4-mar-86
  837. X *    - changed word delete to be consistant with word move (it gets
  838. X *      rid of the inter word space now) This is configurable with the
  839. X *      NFWORD symbol in estruct.h
  840. X *    - added B_ACTIVE entry to the buffer table. Let emacs read multiple
  841. X *      file names from the command line and only read them in as needed
  842. X *    5-mar-85
  843. X *    - rewrote command line parser to get rid of my patchy code
  844. X *    - changed version number to 3.5
  845. X *    1-apr-86
  846. X *    - added support for Aztec C 3.20e under MSDOS
  847. X *    - fixed bug in mlwrite on ADM3's and thier ilk under V7
  848. X *    - added insertion of pounds in column one under CMODE
  849. X *    - changed version number to 3.6
  850. X *    3-apr-86
  851. X *    - added next-buffer command (^X-X)
  852. X *    5-apr-86
  853. X *    - added kill paragraph command (M-^W)
  854. X *    - changed fill-paragraph to leave 2 spaces after a period at the
  855. X *      end of a word.
  856. X *    - added OVERWRITE mode
  857. X *    7-apr-86
  858. X *    - fixed overwrite mode to handle tabs
  859. X *    8-apr-86
  860. X *    - added add/delete global mode (<ESC>M & <ESC> ^M) commands
  861. X *    9-apr-86
  862. X *    - added insert space command
  863. X *    - moved bindings around        ^C    insert space
  864. X *                    M-K    bind-to-key
  865. X *                    INSERT    insert space
  866. X *                    DELETE    forwdel
  867. X *    - added hunt forward and hunt reverse commands
  868. X *    10-apr-86
  869. X *    - fixed bug in DOBUF with non-terminated command string
  870. X *    15-apr-86
  871. X *    - fixed tab expansion bug in DISPLAY which hung the AMIGA
  872. X *      (send in by Dawn Banks)
  873. X *    - fixed curcol problen if forwline/backline during keyboard
  874. X *      macro execution (sent in by Ernst Christen)
  875. X *    - added AMIGA function/cursor key support
  876. X *    - fixed nonterminating <NL> replacement bug
  877. X *    - fixed word wrapping problems
  878. X *    16-apr-86
  879. X *    - updated documentation and froze development for 3.6 net release
  880. X *    23-apr-86    version 3.6a
  881. X *    - added forground and background colors. Setable with the
  882. X *      add mode commands for the moment
  883. X *    24-apr-86
  884. X *    - added command to pipe CLI output to a buffer
  885. X *    25-apr-86
  886. X *    - added Dana Hoggat's code to replace lattice's sick system()
  887. X *      function, now we no longer care what the switchar is.
  888. X *    - cleaned up the positioning on several of the spawing commands
  889. X *    26-apr-86
  890. X *    - added a output flush in vttidy(). Unix really appreciates this.
  891. X *    - added filter-buffer (^X#) command to send a buffer through
  892. X *      a dos filter
  893. X *    - made automatic CMODE on .c and .h file compilation dependant
  894. X *      in estruct.h
  895. X *    1-may-86
  896. X *    - optimized some code in update(). It certainly need a lot more.
  897. X *    - added AZTEC profiling capabilities. These are conditional on
  898. X *      the APROF symbol in estruct.h
  899. X *    2-may-86
  900. X *    - added (u)ndo command in query-replace. undoes last repalce.
  901. X *    6-may-86
  902. X *    - re-orginized and wrote the update() function in display.c
  903. X *      now my color hacks are in the right places and the code can be
  904. X *      understood.
  905. X *    [Released version 3.6f for BETA test sites]
  906. X *    8-may-86
  907. X *    - fixed bug in new display routine to wrap cursor on extended
  908. X *      lines at the right time
  909. X *    - modified the buffer-position command to give reasonable info
  910. X *    9-may-86
  911. X *    - improved the word wrap algorithm as not to discard non-space
  912. X *      delimiters. The backscan now looks for white space rather than
  913. X *      !inword().
  914. X *    [Released version 3.6g to Krannert]
  915. X *    10-may-86
  916. X *    - Added IBMPC.C an IBM-PC specific display driver. This makes paging
  917. X *      4-6 times faster. Also made some conditional changes to DISPLAY.C
  918. X *      to eliminate the pscreen[] if using the PC driver.
  919. X *    [changed version number to 3.6i]
  920. X *    12-may-86
  921. X *    - added delete-window (^X 0) command to dispose of a single window
  922. X *    - fixed problem with multiple prefixes from a command line which
  923. X *      was reported by John Gamble
  924. X *    14-may-86
  925. X *    - Added AZTEC support for the IBMPC display driver. Had to
  926. X *      readjust some includes and defines for this.
  927. X *    - fixed bug in delete-window.
  928. X *    - fixed some bizarre behavior with the cursor after coming back
  929. X *      from spawn calls.
  930. X *    [changed version number to 3.7 Freezing development for net release]
  931. X *    15-may-86
  932. X *    - (that didn't last long...) Added execute-macro-(1 thru 20) commands
  933. X *      to execute macro buffers (named "[Macro nn]")
  934. X *    - changed BFTEMP to BFINVS and cleaned up treatment of invisable
  935. X *      buffers.
  936. X *    16-may-86
  937. X *    - added store-macro (unbound) to store any executed command lines to
  938. X *      macro buffer.
  939. X *    - added clear-message-line (unbound) command to do just that
  940. X *    - added resize-window command to change a window's size to the
  941. X *      specified argument
  942. X *    - improved help's logic not to re-read the file if it was already
  943. X *      in a buffer
  944. X *    - added MAGIC mode to all structures and command tables, but the
  945. X *      regular expression code that John Gamble is writting is not ready.
  946. X *    18-may-86
  947. X *    - added interactive prompt requests in command line execution. IE
  948. X *      while executing a macro, a parameter starting with an at sign (@)
  949. X *      causes emacs to prompt with the rest of the parameter and return
  950. X *      the resulting input as the value of the parameter.
  951. X *    - added arguments to split-current-window to force the cursor into
  952. X *      the upper or lower window.
  953. X *    20-may-86
  954. X *    - added support for the Microsoft C compiler as per the changes
  955. X *      send in by Oliver Sharp
  956. X *    - made some upgrades and fixes for VMS sent in by Guy Streeter
  957. X *    21-may-86
  958. X *    - fixed an AZTEC bug in ttgetc by clearing the upper byte
  959. X *    - fixed buf in CMODE with #preprocesser input (bug fix submitted by
  960. X *      Willis of unknown path)
  961. X *    - added support of alternative startup file ( @<filename> ) in
  962. X *      the command line
  963. X *    - added ^Q quoting in interactive input (mlreplyt()).
  964. X *    - added re-binding of meta-prefix and ctlx-prefix
  965. X *    22-may-86
  966. X *    - reorginize getkey routines to make more sense and let prefix
  967. X *      binding work properly.
  968. X *    23-may-86
  969. X *    - checked new code on BSD4.2 made a few fixes
  970. X *    - added optional fence matching while in CMODE
  971. X *    - added goto and search command line arguments by Mike Spitzer
  972. X *    26-may-86
  973. X *    - added parameter fetching from buffers
  974. X *    27-may-86
  975. X *    - fixed some HP150 bugs......
  976. X *    31-may-86
  977. X *    - Added Wang PC keyboard support from modifications by
  978. X *      Sid Shapiro @ Wang Institute
  979. X *    - Fixed some reverse video bugs with code submitted by Peter Chubb
  980. X *    - Fixed bug in nextbuffer reported by Dave Forslund
  981. X *    - added system V support (USG) from Linwood Varney
  982. X *    2-jun-86
  983. X *    - changed defines to just define one unix define (for example,
  984. X *      just define BSD for Unix BSD 4.2)
  985. X *    - Added Incremental search functions written by D. R. Banks
  986. X *      in file ISEARCH.C
  987. X *    - added insert-string (unbound) command to help the macro
  988. X *      language out.
  989. X *    - added unmark-buffer (M-~) command to turn off the current buffers
  990. X *      change flag
  991. X *    - fixed nxtarg to truncate strings longer than asked for max length
  992. X *    4-jun-86
  993. X *    - added special characters in command line tokens. Tidle (~) is
  994. X *      the special leadin character for "nrtb".
  995. X *    - Fixed bad ifdef in aztec code so it could look at HOME dir
  996. X *      for startup, help, and emacs.rc files
  997. X *    6-jun-86
  998. X *    - make delete word commands clear the kill buffer if not after another
  999. X *      kill command
  1000. X *    11-jun-86
  1001. X *    - made ~@ in string arguments pass as char(192) to nxtarg() so one can
  1002. X *      quote @ at the begining of string arguments
  1003. X *    - changed buffer size vars in listbuffers() to long (for big files)
  1004. X *    - re-wrote buffer-position command to be much faster
  1005. X *    12-jun-86
  1006. X *    - added count-words (M-^C) command to count the words/chars and
  1007. X *      lines in a region
  1008. X *    - changed regions so they could be larger than 65535 (short ->
  1009. X *      long in the REGION structure)
  1010. X *    - changed ldelete() and all callers to use a long size. The kill
  1011. X *      buffer will still have a problem >65535 that can not be solved
  1012. X *      until I restructure it.
  1013. X *    - grouped paragraph commands and word count together under symbol
  1014. X *      WORDPRO to allow them to be conditionally made (or not)
  1015. X *    13-jun-86
  1016. X *    - re-wrote kill buffer routines again. Now they support an unlimited
  1017. X *      size kill buffer, and are (in theory) faster.
  1018. X *    - changed delete-next-word (M-D) to not eat the newline after a word,
  1019. X *      instead it checks and eats a newline at the cursor.
  1020. X *    17-jun-85
  1021. X *    - added numeric argument to next/previous-window to access the nth
  1022. X *      window from the top/bottom
  1023. X *    - added support for the data General 10 MSDOS machine
  1024. X *    - added save-window (unbound) and restore-window (unbound) commands
  1025. X *      for the use of the menu script. Save-window remembers which window
  1026. X *      is current, and restore-window returns the cursor to that window.
  1027. X *    20-jun-86
  1028. X *    - fixed a bug with the fence matching locking up near the begining
  1029. X *    of a buffer
  1030. X *    - added argument to update to selectivaly force a complete update
  1031. X *    - added update-screen (unbound) command so macros can force a
  1032. X *      screen update
  1033. X *    21-jun-86
  1034. X *    - rearranged token() and nxtarg() calls so that command names and
  1035. X *      repeat counts could also be prompted and fetched from buffers
  1036. X *    - added write-message (unbound) command to write out a message
  1037. X *      on the message line (for macros)
  1038. X *    - changed ifdef's so that color modes are reconized as legal in
  1039. X *      b/w version, and simply do nothing (allowing us to use the same
  1040. X *      script files)
  1041. X */
  1042. X
  1043. X#include        <stdio.h>
  1044. X
  1045. X/* make global definitions not external */
  1046. X#define    maindef
  1047. X
  1048. X#include        "estruct.h"    /* global structures and defines */
  1049. X#include    "efunc.h"    /* function declarations and name table    */
  1050. X#include    "edef.h"    /* global definitions */
  1051. X#include    "ebind.h"    /* default key bindings */
  1052. X
  1053. X#if     VMS
  1054. X#include        <ssdef.h>
  1055. X#define GOOD    (SS$_NORMAL)
  1056. X#endif
  1057. X
  1058. X#ifndef GOOD
  1059. X#define GOOD    0
  1060. X#endif
  1061. X
  1062. X#if    APROF    /* Declarations needed for AZTEC C profiling */
  1063. Xint _Corg();    /* first address of program */
  1064. Xint _Cend();    /* last address of program */
  1065. X
  1066. Xshort monbuf[NBUCK];    /* buffer for gather info */
  1067. X#endif
  1068. X
  1069. Xmain(argc, argv)
  1070. Xchar    *argv[];
  1071. X{
  1072. X        register int    c;
  1073. X        register int    f;
  1074. X        register int    n;
  1075. X        register int    mflag;
  1076. X    register BUFFER *bp;
  1077. X    register int    ffile;        /* first file flag */
  1078. X    register int    carg;        /* current arg to scan */
  1079. X    register int    startf;        /* startup executed flag */
  1080. X    int basec;            /* c stripped of meta character */
  1081. X    int viewflag;            /* are we starting in view mode? */
  1082. X        int gotoflag;                   /* do we need to goto a line at start? */
  1083. X        int gline;                      /* if so, what line? */
  1084. X        int searchflag;                 /* Do we need to search at start? */
  1085. X        char bname[NBUFN];        /* buffer name of file to read */
  1086. X
  1087. X#if    APROF
  1088. X    /* if we are doing AZTEC C profiling, start it up */
  1089. X    /*_intr_sp(18);     set clock interupt for 60/second */
  1090. X    monitor(_Corg, _Cend, monbuf, NBUCK, 0);
  1091. X#endif
  1092. X
  1093. X    /* initialize the editor and process the command line arguments */
  1094. X        strcpy(bname, "main");    /* default buffer name */
  1095. X        vtinit();        /* Displays.            */
  1096. X        edinit(bname);        /* Buffers, windows.    */
  1097. X    viewflag = FALSE;    /* view mode defaults off in command line */
  1098. X    gotoflag = FALSE;    /* set to off to begin with */
  1099. X    searchflag = FALSE;    /* set to off to begin with */
  1100. X    ffile = TRUE;        /* no file to edit yet */
  1101. X    startf = FALSE;        /* startup file not executed yet */
  1102. X#if    COLOR
  1103. X    curwp->w_fcolor = gfcolor;        /* and set colors    */
  1104. X    curwp->w_bcolor = gbcolor;
  1105. X#endif
  1106. X    
  1107. X    /* scan through the command line and get the files to edit */
  1108. X    for (carg = 1; carg < argc; ++carg) {
  1109. X        /* if its a switch, process it */
  1110. X        if (argv[carg][0] == '-') {
  1111. X            switch (argv[carg][1]) {
  1112. X                case 'v':    /* -v for View File */
  1113. X                case 'V':
  1114. X                    viewflag = TRUE;
  1115. X                    break;
  1116. X                case 'e':    /* -e for Edit file */
  1117. X                case 'E':
  1118. X                    viewflag = FALSE;
  1119. X                    break;
  1120. X                case 's':    /* -s for initial search string */
  1121. X                case 'S':
  1122. X                    searchflag = TRUE;
  1123. X                    strcpy(pat,&argv[carg][2]);
  1124. X                    break;
  1125. X                case 'g':    /* -g for initial goto */
  1126. X                case 'G':    
  1127. X                    gotoflag = TRUE;
  1128. X                    gline = atoi(&argv[carg][2]);
  1129. X                    break;
  1130. X                default:    /* unknown switch */
  1131. X                    /* ignore this for now */
  1132. X                    break;
  1133. X            }
  1134. X        } else     /* check for a macro file */
  1135. X            if (argv[carg][0]== '@') {
  1136. X
  1137. X            if (startup(&argv[carg][1]) == TRUE)
  1138. X                startf = TRUE;    /* don't execute emacs.rc */
  1139. X
  1140. X        } else {    /* process a file name */
  1141. X            /* if we haven't run emacs.rc, do it now */
  1142. X            if (startf == FALSE) {
  1143. X                startup("");
  1144. X                startf = TRUE;
  1145. X            }
  1146. X
  1147. X            /* set up a buffer for this file */
  1148. X                    makename(bname, argv[carg]);
  1149. X
  1150. X            /* if this is the first file, read it in */
  1151. X            if (ffile) {
  1152. X                bp = curbp;
  1153. X                makename(bname, argv[carg]);
  1154. X                strcpy(bp->b_bname, bname);
  1155. X                strcpy(bp->b_fname, argv[carg]);
  1156. X                if (readin(argv[carg], (viewflag==FALSE))
  1157. X                                == ABORT) {
  1158. X                    strcpy(bp->b_bname, "main");
  1159. X                    strcpy(bp->b_fname, "");
  1160. X                }
  1161. X                bp->b_dotp = bp->b_linep;
  1162. X                bp->b_doto = 0;
  1163. X                ffile = FALSE;
  1164. X            } else {
  1165. X                /* set this to inactive */
  1166. X                bp = bfind(bname, TRUE, 0);
  1167. X                strcpy(bp->b_fname, argv[carg]);
  1168. X                bp->b_active = FALSE;
  1169. X            }
  1170. X
  1171. X            /* set the view mode appropriatly */
  1172. X            if (viewflag)
  1173. X                bp->b_mode |= MDVIEW;
  1174. X        }
  1175. X    }
  1176. X
  1177. X    /* if invoked with nothing, run the startup file here */
  1178. X    if (startf == FALSE) {
  1179. X        startup("");
  1180. X        startf = TRUE;
  1181. X    }
  1182. X        /* Deal with startup gotos and searches */
  1183. X        if (gotoflag && searchflag) {
  1184. X            update(FALSE);
  1185. X        mlwrite("[Can not search and goto at the same time!]");
  1186. X    }
  1187. X        else if (gotoflag) {
  1188. X                if (gotoline(NULL,gline) == FALSE) {
  1189. X                    update(FALSE);
  1190. X            mlwrite("[Bogus goto argument]");
  1191. X        }
  1192. X        } else if (searchflag) {
  1193. X                if (forscan(&pat[0], 2) == FALSE) {
  1194. X                    update(FALSE);
  1195. X            mlwrite("Not found.");
  1196. X        }
  1197. X        }
  1198. X
  1199. X    /* setup to process commands */
  1200. X        lastflag = 0;                           /* Fake last flags.     */
  1201. X    curbp->b_mode = curbp->b_mode | gmode;    /* and set default modes*/
  1202. X    curwp->w_flag |= WFMODE;        /* and force an update    */
  1203. X#if    COLOR
  1204. X    curwp->w_fcolor = gfcolor;        /* and set colors    */
  1205. X    curwp->w_bcolor = gbcolor;
  1206. X#endif
  1207. X
  1208. Xloop:
  1209. X        update(FALSE);                          /* Fix up the screen    */
  1210. X        c = getcmd();
  1211. X        if (mpresf != FALSE) {
  1212. X                mlerase();
  1213. X                update(FALSE);
  1214. X#if    CLRMSG
  1215. X                if (c == ' ')                   /* ITS EMACS does this  */
  1216. X                        goto loop;
  1217. X#endif
  1218. X        }
  1219. X        f = FALSE;
  1220. X        n = 1;
  1221. X
  1222. X    /* do META-# processing if needed */
  1223. X
  1224. X    basec = c & ~META;        /* strip meta char off if there */
  1225. X    if ((c & META) && ((basec >= '0' && basec <= '9') || basec == '-')) {
  1226. X        f = TRUE;        /* there is a # arg */
  1227. X        n = 0;            /* start with a zero default */
  1228. X        mflag = 1;        /* current minus flag */
  1229. X        c = basec;        /* strip the META */
  1230. X        while ((c >= '0' && c <= '9') || (c == '-')) {
  1231. X            if (c == '-') {
  1232. X                /* already hit a minus or digit? */
  1233. X                if ((mflag == -1) || (n != 0))
  1234. X                    break;
  1235. X                mflag = -1;
  1236. X            } else {
  1237. X                n = n * 10 + (c - '0');
  1238. X            }
  1239. X            if ((n == 0) && (mflag == -1))    /* lonely - */
  1240. X                mlwrite("Arg:");
  1241. X            else
  1242. X                mlwrite("Arg: %d",n * mflag);
  1243. X
  1244. X            c = getcmd();    /* get the next key */
  1245. X        }
  1246. X        n = n * mflag;    /* figure in the sign */
  1247. X    }
  1248. X
  1249. X    /* do ^U repeat argument processing */
  1250. X
  1251. X        if (c == (CTRL|'U')) {                  /* ^U, start argument   */
  1252. X                f = TRUE;
  1253. X                n = 4;                          /* with argument of 4 */
  1254. X                mflag = 0;                      /* that can be discarded. */
  1255. X                mlwrite("Arg: 4");
  1256. X                while ((c=getcmd()) >='0' && c<='9' || c==(CTRL|'U') || c=='-'){
  1257. X                        if (c == (CTRL|'U'))
  1258. X                                n = n*4;
  1259. X                        /*
  1260. X                         * If dash, and start of argument string, set arg.
  1261. X                         * to -1.  Otherwise, insert it.
  1262. X                         */
  1263. X                        else if (c == '-') {
  1264. X                                if (mflag)
  1265. X                                        break;
  1266. X                                n = 0;
  1267. X                                mflag = -1;
  1268. X                        }
  1269. X                        /*
  1270. X                         * If first digit entered, replace previous argument
  1271. X                         * with digit and set sign.  Otherwise, append to arg.
  1272. X                         */
  1273. X                        else {
  1274. X                                if (!mflag) {
  1275. X                                        n = 0;
  1276. X                                        mflag = 1;
  1277. X                                }
  1278. X                                n = 10*n + c - '0';
  1279. X                        }
  1280. X                        mlwrite("Arg: %d", (mflag >=0) ? n : (n ? -n : -1));
  1281. X                }
  1282. X                /*
  1283. X                 * Make arguments preceded by a minus sign negative and change
  1284. X                 * the special argument "^U -" to an effective "^U -1".
  1285. X                 */
  1286. X                if (mflag == -1) {
  1287. X                        if (n == 0)
  1288. X                                n++;
  1289. X                        n = -n;
  1290. X                }
  1291. X        }
  1292. X
  1293. X        if (kbdmip != NULL) {                   /* Save macro strokes.  */
  1294. X                if (c!=(CTLX|')') && kbdmip>&kbdm[NKBDM-6]) {
  1295. X                        ctrlg(FALSE, 0);
  1296. X                        goto loop;
  1297. X                }
  1298. X                if (f != FALSE) {
  1299. X                        *kbdmip++ = (CTRL|'U');
  1300. X                        *kbdmip++ = n;
  1301. X                }
  1302. X                *kbdmip++ = c;
  1303. X        }
  1304. X        execute(c, f, n);                       /* Do it.               */
  1305. X        goto loop;
  1306. X}
  1307. X
  1308. X/*
  1309. X * Initialize all of the buffers and windows. The buffer name is passed down
  1310. X * as an argument, because the main routine may have been told to read in a
  1311. X * file by default, and we want the buffer name to be right.
  1312. X */
  1313. Xedinit(bname)
  1314. Xchar    bname[];
  1315. X{
  1316. X        register BUFFER *bp;
  1317. X        register WINDOW *wp;
  1318. X    char *malloc();
  1319. X
  1320. X        bp = bfind(bname, TRUE, 0);             /* First buffer         */
  1321. X        blistp = bfind("[List]", TRUE, BFINVS); /* Buffer list buffer   */
  1322. X        wp = (WINDOW *) malloc(sizeof(WINDOW)); /* First window         */
  1323. X        if (bp==NULL || wp==NULL || blistp==NULL)
  1324. X                exit(1);
  1325. X        curbp  = bp;                            /* Make this current    */
  1326. X        wheadp = wp;
  1327. X        curwp  = wp;
  1328. X        wp->w_wndp  = NULL;                     /* Initialize window    */
  1329. X        wp->w_bufp  = bp;
  1330. X        bp->b_nwnd  = 1;                        /* Displayed.           */
  1331. X        wp->w_linep = bp->b_linep;
  1332. X        wp->w_dotp  = bp->b_linep;
  1333. X        wp->w_doto  = 0;
  1334. X        wp->w_markp = NULL;
  1335. X        wp->w_marko = 0;
  1336. X        wp->w_toprow = 0;
  1337. X#if    COLOR
  1338. X    /* initalize colors to global defaults */
  1339. X    wp->w_fcolor = gfcolor;
  1340. X    wp->w_bcolor = gbcolor;
  1341. X#endif
  1342. X        wp->w_ntrows = term.t_nrow-1;           /* "-1" for mode line.  */
  1343. X        wp->w_force = 0;
  1344. X        wp->w_flag  = WFMODE|WFHARD;            /* Full.                */
  1345. X}
  1346. X
  1347. X/*
  1348. X * This is the general command execution routine. It handles the fake binding
  1349. X * of all the keys to "self-insert". It also clears out the "thisflag" word,
  1350. X * and arranges to move it to the "lastflag", so that the next command can
  1351. X * look at it. Return the status of command.
  1352. X */
  1353. Xexecute(c, f, n)
  1354. X{
  1355. X        register KEYTAB *ktp;
  1356. X        register int    status;
  1357. X
  1358. X        ktp = &keytab[0];                       /* Look in key table.   */
  1359. X        while (ktp->k_fp != NULL) {
  1360. X                if (ktp->k_code == c) {
  1361. X                        thisflag = 0;
  1362. X                        status   = (*ktp->k_fp)(f, n);
  1363. X                        lastflag = thisflag;
  1364. X                        return (status);
  1365. X                }
  1366. X                ++ktp;
  1367. X        }
  1368. X
  1369. X        /*
  1370. X         * If a space was typed, fill column is defined, the argument is non-
  1371. X         * negative, wrap mode is enabled, and we are now past fill column,
  1372. X     * and we are not read-only, perform word wrap.
  1373. X         */
  1374. X        if (c == ' ' && (curwp->w_bufp->b_mode & MDWRAP) && fillcol > 0 &&
  1375. X        n >= 0 && getccol(FALSE) > fillcol &&
  1376. X        (curwp->w_bufp->b_mode & MDVIEW) == FALSE)
  1377. X                wrapword();
  1378. X
  1379. X        if ((c>=0x20 && c<=0x7E)                /* Self inserting.      */
  1380. X        ||  (c>=0xA0 && c<=0xFE)) {
  1381. X                if (n <= 0) {                   /* Fenceposts.          */
  1382. X                        lastflag = 0;
  1383. X                        return (n<0 ? FALSE : TRUE);
  1384. X                }
  1385. X                thisflag = 0;                   /* For the future.      */
  1386. X
  1387. X        /* if we are in overwrite mode, not at eol,
  1388. X           and next char is not a tab or we are at a tab stop,
  1389. X           delete a char forword            */
  1390. X        if (curwp->w_bufp->b_mode & MDOVER &&
  1391. X            curwp->w_doto < curwp->w_dotp->l_used &&
  1392. X            (lgetc(curwp->w_dotp, curwp->w_doto) != '\t' ||
  1393. X             (curwp->w_doto) % 8 == 7))
  1394. X                ldelete(1L, FALSE);
  1395. X
  1396. X        /* do the appropriate insertion */
  1397. X        if (c == '}' && (curbp->b_mode & MDCMOD) != 0)
  1398. X                status = insbrace(n, c);
  1399. X            else if (c == '#' && (curbp->b_mode & MDCMOD) != 0)
  1400. X                status = inspound();
  1401. X            else
  1402. X                    status = linsert(n, c);
  1403. X
  1404. X#if    CFENCE
  1405. X        /* check for CMODE fence matching */
  1406. X        if ((c == '}' || c == ')') && (curbp->b_mode & MDCMOD) != 0)
  1407. X            fmatch(c);
  1408. X#endif
  1409. X
  1410. X                lastflag = thisflag;
  1411. X                return (status);
  1412. X        }
  1413. X    (*term.t_beep)();
  1414. X    mlwrite("[Key not bound]");        /* complain        */
  1415. X        lastflag = 0;                           /* Fake last flags.     */
  1416. X        return (FALSE);
  1417. X}
  1418. X
  1419. X/*
  1420. X * Fancy quit command, as implemented by Norm. If the any buffer has
  1421. X * changed do a write on that buffer and exit emacs, otherwise simply exit.
  1422. X */
  1423. Xquickexit(f, n)
  1424. X{
  1425. X    register BUFFER *bp;    /* scanning pointer to buffers */
  1426. X
  1427. X    bp = bheadp;
  1428. X    while (bp != NULL) {
  1429. X            if ((bp->b_flag&BFCHG) != 0    /* Changed.             */
  1430. X            && (bp->b_flag&BFINVS) == 0) {    /* Real.                */
  1431. X            curbp = bp;        /* make that buffer cur    */
  1432. X            mlwrite("[Saving %s]",bp->b_fname);
  1433. X                    filesave(f, n);
  1434. X        }
  1435. X    bp = bp->b_bufp;            /* on to the next buffer */
  1436. X    }
  1437. X        quit(f, n);                             /* conditionally quit   */
  1438. X}
  1439. X
  1440. X/*
  1441. X * Quit command. If an argument, always quit. Otherwise confirm if a buffer
  1442. X * has been changed and not written out. Normally bound to "C-X C-C".
  1443. X */
  1444. Xquit(f, n)
  1445. X{
  1446. X        register int    s;
  1447. X
  1448. X        if (f != FALSE                          /* Argument forces it.  */
  1449. X        || anycb() == FALSE                     /* All buffers clean.   */
  1450. X                        /* User says it's OK.   */
  1451. X        || (s=mlyesno("Modified buffers exist. Leave anyway")) == TRUE) {
  1452. X#if    FILOCK
  1453. X        if (lockrel() != TRUE) {
  1454. X            (*term.t_putchar)('\n');
  1455. X            (*term.t_putchar)('\r');
  1456. X            (*term.t_close)();
  1457. X            exit(1);
  1458. X        }
  1459. X#endif
  1460. X                vttidy();
  1461. X#if    APROF
  1462. X        /* if doing AZTEC C profiling, close up and write it out */
  1463. X        monitor(0,0,0,0,0);
  1464. X#endif
  1465. X                exit(GOOD);
  1466. X        }
  1467. X    mlwrite("");
  1468. X        return (s);
  1469. X}
  1470. X
  1471. X/*
  1472. X * Begin a keyboard macro.
  1473. X * Error if not at the top level in keyboard processing. Set up variables and
  1474. X * return.
  1475. X */
  1476. Xctlxlp(f, n)
  1477. X{
  1478. X        if (kbdmip!=NULL || kbdmop!=NULL) {
  1479. X                mlwrite("Not now");
  1480. X                return (FALSE);
  1481. X        }
  1482. X        mlwrite("[Start macro]");
  1483. X        kbdmip = &kbdm[0];
  1484. X        return (TRUE);
  1485. X}
  1486. X
  1487. X/*
  1488. X * End keyboard macro. Check for the same limit conditions as the above
  1489. X * routine. Set up the variables and return to the caller.
  1490. X */
  1491. Xctlxrp(f, n)
  1492. X{
  1493. X        if (kbdmip == NULL) {
  1494. X                mlwrite("Not now");
  1495. X                return (FALSE);
  1496. X        }
  1497. X        mlwrite("[End macro]");
  1498. X        kbdmip = NULL;
  1499. X        return (TRUE);
  1500. X}
  1501. X
  1502. X/*
  1503. X * Execute a macro.
  1504. X * The command argument is the number of times to loop. Quit as soon as a
  1505. X * command gets an error. Return TRUE if all ok, else FALSE.
  1506. X */
  1507. Xctlxe(f, n)
  1508. X{
  1509. X        register int    c;
  1510. X        register int    af;
  1511. X        register int    an;
  1512. X        register int    s;
  1513. X
  1514. X        if (kbdmip!=NULL || kbdmop!=NULL) {
  1515. X                mlwrite("Not now");
  1516. X                return (FALSE);
  1517. X        }
  1518. X        if (n <= 0)
  1519. X                return (TRUE);
  1520. X        do {
  1521. X                kbdmop = &kbdm[0];
  1522. X                do {
  1523. X                        af = FALSE;
  1524. X                        an = 1;
  1525. X                        if ((c = *kbdmop++) == (CTRL|'U')) {
  1526. X                                af = TRUE;
  1527. X                                an = *kbdmop++;
  1528. X                                c  = *kbdmop++;
  1529. X                        }
  1530. X                        s = TRUE;
  1531. X                } while (c!=(CTLX|')') && (s=execute(c, af, an))==TRUE);
  1532. X                kbdmop = NULL;
  1533. X        } while (s==TRUE && --n);
  1534. X        return (s);
  1535. X}
  1536. X
  1537. X/*
  1538. X * Abort.
  1539. X * Beep the beeper. Kill off any keyboard macro, etc., that is in progress.
  1540. X * Sometimes called as a routine, to do general aborting of stuff.
  1541. X */
  1542. Xctrlg(f, n)
  1543. X{
  1544. X        (*term.t_beep)();
  1545. X        if (kbdmip != NULL) {
  1546. X                kbdm[0] = (CTLX|')');
  1547. X                kbdmip  = NULL;
  1548. X        }
  1549. X    mlwrite("[Aborted]");
  1550. X        return (ABORT);
  1551. X}
  1552. X
  1553. X/* tell the user that this command is illegal while we are in
  1554. X   VIEW (read-only) mode                */
  1555. X
  1556. Xrdonly()
  1557. X
  1558. X{
  1559. X    (*term.t_beep)();
  1560. X    mlwrite("[Key illegal in VIEW mode]");
  1561. X    return(FALSE);
  1562. X}
  1563. X
  1564. Xmeta()    /* dummy function for binding to meta prefix */
  1565. X{
  1566. X}
  1567. X
  1568. Xcex()    /* dummy function for binding to control-x prefix */
  1569. X{
  1570. X}
  1571. X
  1572. X
  1573. FRIDAY_NIGHT
  1574. echo es.7 completed!
  1575. : That's all folks!
  1576.  
  1577.