home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / jove-4.16-src.tgz / tar.out / bsd / jove / buf.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  19KB  |  880 lines

  1. /************************************************************************
  2.  * This program is Copyright (C) 1986-1996 by Jonathan Payne.  JOVE is  *
  3.  * provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is *
  5.  * included in all the files.                                           *
  6.  ************************************************************************/
  7.  
  8. /* Contains commands that deal with creating, selecting, killing and
  9.    listing buffers, and buffer modes, and find-file, etc. */
  10.  
  11. #include "jove.h"
  12. #include "jctype.h"
  13. #include "disp.h"
  14. #include "ask.h"
  15. #include "extend.h"
  16. #include "fmt.h"
  17. #include "insert.h"
  18. #include "macros.h"    /* only for mac_getc(), used by do_find fudge */
  19. #include "marks.h"
  20. #include "move.h"
  21. #include "sysprocs.h"
  22. #include "proc.h"
  23. #include "wind.h"
  24.  
  25. #ifdef IPROCS
  26. # include "fp.h"
  27. # include "iproc.h"
  28. #endif
  29.  
  30. #ifdef MAC
  31. # include "mac.h"
  32. #else
  33. # include <sys/stat.h>
  34. #endif
  35.  
  36. #ifdef AUTO_BUFS
  37. char
  38.     *iobuff,
  39.     *genbuf,
  40.     *linebuf;
  41. #else
  42. char
  43.     iobuff[LBSIZE],
  44.     genbuf[LBSIZE],
  45.     linebuf[LBSIZE];
  46. #endif
  47.  
  48. private void
  49.     setbname proto((Buffer *, char *));
  50.  
  51. private char    *Mainbuf = "Main",
  52.     *NoName = "Sans un nom!";
  53.  
  54. Buffer
  55.     *world = NULL,        /* First in the list */
  56.     *curbuf = NULL,        /* pointer into world for current buffer */
  57.     *lastbuf = NULL,    /* Last buffer we were in so we have a default
  58.                    buffer during a select buffer. */
  59.     *perr_buf = NULL;    /* Buffer with error messages */
  60.  
  61. /* Toggle BIT in the current buffer's minor mode flags.  If argument is
  62.    supplied, a positive one always turns on the mode and zero argument
  63.    always turns it off. */
  64.  
  65. void
  66. TogMinor(bit)
  67. int    bit;
  68. {
  69.     if (is_an_arg()) {
  70.         if (arg_value() == 0)
  71.             curbuf->b_minor &= ~bit;
  72.         else
  73.             curbuf->b_minor |= bit;
  74.     } else
  75.         curbuf->b_minor ^= bit;
  76.     UpdModLine = YES;
  77. }
  78.  
  79. /* Creates a new buffer, links it at the end of the buffer chain, and
  80.    returns it. */
  81.  
  82. private Buffer    *free_bufs = NULL;
  83.  
  84. private Buffer *
  85. buf_alloc()
  86. {
  87.     register Buffer    *b,
  88.             *lastbp;
  89.  
  90.     lastbp = NULL;
  91.     for (b = world; b != NULL; b = b->b_next)
  92.         lastbp = b;
  93.  
  94.     if (free_bufs != NULL) {
  95.         b = free_bufs;
  96.         free_bufs = b->b_next;
  97.     } else {
  98.         b = (Buffer *) emalloc(sizeof (Buffer));
  99.     }
  100.     if (lastbp)
  101.         lastbp->b_next = b;
  102.     else
  103.         world = b;
  104.     b->b_first = NULL;
  105.     b->b_next = NULL;
  106. #ifdef MAC
  107.     b->Type = BUFFER;    /* kludge, but simplifies menu handlers */
  108.     b->Name = NULL;
  109. #endif
  110.     return b;
  111. }
  112.  
  113. /* Make a buffer and initialize it. */
  114.  
  115. private Buffer *
  116. mak_buf()
  117. {
  118.     register Buffer    *newb;
  119.     register int    i;
  120.  
  121.     newb = buf_alloc();
  122.     newb->b_fname = NULL;
  123.     newb->b_name = NoName;
  124.     newb->b_marks = NULL;
  125.     newb->b_themark = 0;        /* Index into markring */
  126.     /* No marks yet */
  127.     for (i = 0; i < NMARKS; i++)
  128.         newb->b_markring[i] = NULL;
  129.     newb->b_modified = newb->b_diverged = NO;
  130.     newb->b_type = B_FILE;  /* File until proven SCRATCH */
  131.     newb->b_minor = 0;
  132.     newb->b_major = TEXTMODE;
  133.     newb->b_first = NULL;
  134.     newb->b_map = NULL;
  135. #ifdef IPROCS
  136.     newb->b_process = NULL;
  137. #endif
  138.     buf_clear(newb);
  139. #ifdef MAC
  140.     Bufchange = YES;
  141. #endif
  142.     return newb;
  143. }
  144.  
  145. void
  146. ReNamBuf()
  147. {
  148.     setbname(curbuf, ask_buf((Buffer *)NULL, ALLOW_NEW));
  149. }
  150.  
  151. void
  152. FindFile()
  153. {
  154.     char    fnamebuf[FILESIZE];
  155.  
  156.     (void) ask_file((char *)NULL, curbuf->b_fname, fnamebuf);
  157.     SetABuf(curbuf);
  158.     SetBuf(do_find(curwind, fnamebuf, YES, NO));
  159.     if (curbuf->b_diverged)
  160.         rbell();    /* slight hint of divergence */
  161. }
  162.  
  163. private void
  164. mkbuflist(bnamp, ebnamp)
  165. register char    **bnamp;
  166. char        **ebnamp;
  167. {
  168.     register Buffer    *b;
  169.  
  170.     for (b = world; b != NULL; b = b->b_next) {
  171.         if (b->b_name != NULL) {
  172.             *bnamp++ = b->b_name;
  173.             if (bnamp >= ebnamp)
  174.                 complain("too many buffers to list");
  175.         }
  176.     }
  177.     *bnamp = NULL;
  178. }
  179.  
  180. char *
  181. ask_buf(def, flags)
  182. Buffer    *def;
  183. int    flags;
  184. {
  185.     char    *defname = def != NULL? def->b_name : (char *)NULL;
  186.     char    *bnames[200];
  187.     register char    *bname;
  188.     register int    offset;
  189.     char    prompt[100];
  190.  
  191.     /* The test for % in the next definition is a kludge to prevent
  192.      * the default buffer name in the prompt string from provoking
  193.      * unintended formatting.  Ugh!  The name will still be the default.
  194.      */
  195.     if (defname != NULL && strchr(defname, '%') == NULL)
  196.         swritef(prompt, sizeof(prompt), ": %%f (default %s) ", defname);
  197.     else
  198.         strcpy(prompt, ProcFmt);
  199.     mkbuflist(bnames, &bnames[elemsof(bnames)]);
  200.     /* Secret bonus: if there is no default, ^R will insert curbuf's name. */
  201.     offset = complete(bnames, defname==NULL? curbuf->b_name : defname, prompt,
  202.         flags | (defname == NULL? 0 : ALLOW_EMPTY));
  203.     if (offset < 0)
  204.         bname = *Minibuf == '\0' && defname != NULL? defname : Minibuf;
  205.     else
  206.         bname = bnames[offset];
  207.     return bname;
  208. }
  209.  
  210. void
  211. BufSelect()
  212. {
  213.     register char    *bname;
  214.  
  215.     bname = ask_buf(lastbuf, ALLOW_OLD | ALLOW_INDEX | ALLOW_NEW);
  216.     SetABuf(curbuf);
  217.     SetBuf(do_select(curwind, bname));
  218. }
  219.  
  220. private void
  221. BufNSelect(n)
  222. int    n;
  223. {
  224.     register Buffer    *b;
  225.  
  226.     for (b = world; b != NULL; b = b->b_next) {
  227.         if (b->b_name != NULL) {
  228.             n -= 1;
  229.             if (n == 0) {
  230.                 SetABuf(curbuf);
  231.                 SetBuf(do_select(curwind, b->b_name));
  232.                 return;
  233.             }
  234.         }
  235.     }
  236.     complain("[No such buffer]");
  237. }
  238.  
  239. void Buf1Select() { BufNSelect(1); }
  240. void Buf2Select() { BufNSelect(2); }
  241. void Buf3Select() { BufNSelect(3); }
  242. void Buf4Select() { BufNSelect(4); }
  243. void Buf5Select() { BufNSelect(5); }
  244. void Buf6Select() { BufNSelect(6); }
  245. void Buf7Select() { BufNSelect(7); }
  246. void Buf8Select() { BufNSelect(8); }
  247. void Buf9Select() { BufNSelect(9); }
  248. void Buf10Select() { BufNSelect(10); }
  249.  
  250. private void
  251. delb_wind(b)
  252. register Buffer *b;
  253. {
  254.     register Window    *w = fwind;
  255.     char    *alt = lastbuf != NULL && lastbuf != b? lastbuf->b_name
  256.         : b->b_next != NULL? b->b_next->b_name
  257.         : Mainbuf;
  258.  
  259.     do {
  260.         Window    *next = w->w_next;
  261.  
  262.         if (w->w_bufp == b) {
  263.             if (one_windp() || alt != Mainbuf)
  264.                 (void) do_select(w, alt);
  265.             else
  266.                 del_wind(w);
  267.         }
  268.         w = next;
  269.     } while (w != fwind || w->w_bufp == b);
  270. }
  271.  
  272. private Buffer *
  273. getNMbuf()
  274. {
  275.     register Buffer    *delbuf = buf_exists(ask_buf(curbuf,
  276.         ALLOW_OLD | ALLOW_INDEX));
  277.  
  278.     if (delbuf->b_modified)
  279.         confirm("%s modified, are you sure? ", delbuf->b_name);
  280.     return delbuf;
  281. }
  282.  
  283. void
  284. BufErase()
  285. {
  286.     register Buffer    *delbuf = getNMbuf();
  287.  
  288.     buf_clear(delbuf);
  289. }
  290.  
  291. /* Free a buffer structure.
  292.  * The actual struct is preserved to reduce the damage
  293.  * from dangling references to it.  They seem to be pervasive.
  294.  * We try to reset enough that a dangling reference will be useless.
  295.  */
  296.  
  297. private void
  298. kill_buf(delbuf)
  299. register Buffer    *delbuf;
  300. {
  301. #ifdef IPROCS
  302.     untieDeadProcess(delbuf);    /* check for lingering processes */
  303. #endif
  304.  
  305.     /* Clean up windows associated with this buffer
  306.      * before it becomes invalid.
  307.      */
  308.     delb_wind(delbuf);
  309.  
  310.     /* Resetting curbuf must be done after delb_wind since it can
  311.      * have a side-effect of setting curbuf to delbuf.  For the same
  312.      * reason, delbuf must not be unlinked until after delb_wind.
  313.      */
  314.     if (curbuf == delbuf)
  315.         curbuf = NULL;
  316.     if (lastbuf == delbuf)
  317.         lastbuf = curbuf;    /* even if NULL */
  318.     if (curbuf == NULL)
  319.         SetBuf(curwind->w_bufp);
  320.  
  321.     /* unlink the buffer */
  322.     if (world == delbuf) {
  323.         world = delbuf->b_next;
  324.     } else {
  325.         register Buffer    *b;
  326.  
  327.         for (b = world; b->b_next != delbuf; b = b->b_next)
  328.             ;
  329.         b->b_next = delbuf->b_next;
  330.     }
  331.  
  332.     if (perr_buf == delbuf) {
  333.         ErrFree();
  334.         perr_buf = NULL;
  335.     }
  336.  
  337.     lfreelist(delbuf->b_first);
  338.     delbuf->b_first = delbuf->b_dot = delbuf->b_last = NULL;
  339.     if (delbuf->b_name != NULL) {
  340.         free((UnivPtr) delbuf->b_name);
  341.         delbuf->b_name = NULL;
  342.     }
  343.     if (delbuf->b_fname != NULL) {
  344.         free((UnivPtr) delbuf->b_fname);
  345.         delbuf->b_fname = NULL;
  346.     }
  347.     flush_marks(delbuf);
  348.     delbuf->b_marks = NULL;
  349.     DelObjRef((data_obj *)delbuf->b_map);
  350.     delbuf->b_map = NULL;
  351.  
  352.     delbuf->b_next = free_bufs;
  353.     free_bufs = delbuf;
  354. #ifdef MAC
  355.     Bufchange = YES;
  356.     delbuf->Name = NULL;    /* ??? this cannot legitimately matter */
  357. #endif
  358. }
  359.  
  360. /* offer to kill some buffers */
  361.  
  362. void
  363. KillSome()
  364. {
  365.     register Buffer    *b,
  366.             *next;
  367.  
  368.     for (b = world; b != NULL; b = next) {
  369.         next = b->b_next;
  370.         if (!yes_or_no_p(IsModified(b)? "Kill %s [modified]? " : "Kill %s? ", b->b_name))
  371.             continue;
  372.         if (IsModified(b)
  373.         && yes_or_no_p("%s modified; should I save it? ", b->b_name))
  374.         {
  375.             Buffer    *oldb = curbuf;
  376.  
  377.             SetBuf(b);
  378.             SaveFile();
  379.             SetBuf(oldb);
  380.         }
  381.         kill_buf(b);
  382.     }
  383. }
  384.  
  385. void
  386. BufKill()
  387. {
  388.     kill_buf(getNMbuf());
  389. }
  390.  
  391. private const char    *const TypeNames[] = {
  392.     NULL,
  393.     "Scratch",
  394.     "File",
  395.     "Process",
  396. };
  397.  
  398. void
  399. BufList()
  400. {
  401.     register char    *fmt = "%2s %5s %-8s %-1s%-1s %-*s  %-s";
  402.     register Buffer    *b;
  403.     int    bcount = 1,        /* To give each buffer a number */
  404.         buf_width = 11;
  405.     bool
  406.         any_modified = NO,
  407.         any_ntbf = NO,
  408.         any_diverged = NO;
  409.  
  410.     for (b = world; b != NULL; b = b->b_next) {
  411.         buf_width = max(buf_width, (int)strlen(b->b_name));
  412.         any_modified |= IsModified(b);
  413.         any_ntbf |= b->b_ntbf;
  414.         any_diverged |= b->b_diverged;
  415.     }
  416.  
  417.     TOstart("Buffer list");
  418.  
  419.     if (any_modified)
  420.         Typeout("(* means buffer needs saving)");
  421.     if (any_ntbf)
  422.         Typeout("(+ means file hasn't been read yet)");
  423.     if (any_diverged)
  424.         Typeout("(# means file has been changed since buffer was read or written)");
  425.     if (any_modified | any_ntbf | any_diverged)
  426.         Typeout(NullStr);
  427.     Typeout(fmt, "NO", "Lines", "Type", NullStr, NullStr, buf_width, "Name", "File");
  428.     Typeout(fmt, "--", "-----", "----", NullStr, NullStr, buf_width, "----", "----");
  429.     for (b = world; b != NULL; b = b->b_next) {
  430.         char
  431.             bnostr[10],
  432.             linestr[10];
  433.  
  434.         swritef(bnostr, sizeof(bnostr), "%d", bcount++);
  435.         if (b->b_ntbf)
  436.             strcpy(linestr, "?");
  437.         else
  438.             swritef(linestr, sizeof(linestr), "%d",
  439.                 LinesTo(b->b_first, (LinePtr)NULL));
  440.         Typeout(fmt, bnostr, linestr, TypeNames[b->b_type],
  441.                 b->b_diverged ? "#" : NullStr,
  442.                 IsModified(b) ? "*" :
  443.                      b->b_ntbf ? "+" : NullStr,
  444.                 buf_width,    /* For the * (variable length field) */
  445.                 b->b_name,
  446.                 filename(b));
  447.  
  448.         if (TOabort)
  449.             break;
  450.     }
  451.     TOstop();
  452. }
  453.  
  454. private void
  455. bufname(b)
  456. register Buffer    *b;
  457. {
  458.     char    tmp[100],
  459.         *cp;
  460.     int    try = 1;
  461.  
  462.     if (b->b_fname == NULL)
  463.         complain("[No file name]");
  464.     cp = basename(b->b_fname);
  465.     strcpy(tmp, cp);
  466.     while (buf_exists(tmp)) {
  467.         swritef(tmp, sizeof(tmp), "%s.%d", cp, try);
  468.         try += 1;
  469.     }
  470.     setbname(b, tmp);
  471. }
  472.  
  473. void
  474. buf_clear(b)
  475. register Buffer    *b;
  476. {
  477.     lfreelist(b->b_first);
  478.     b->b_first = b->b_dot = b->b_last = NULL;
  479.     (void) listput(b, b->b_first);
  480.  
  481.     SavLine(b->b_dot, NullStr);
  482.     b->b_char = 0;
  483.     AllMarkReset(b, b->b_dot);
  484.     if (b == curbuf)
  485.         getDOT();
  486.  
  487.     diverge(b, NO);
  488.     if (b->b_modified)
  489.         UpdModLine = YES;
  490.     b->b_ntbf = b->b_modified = NO;
  491.  
  492. #ifdef USE_INO
  493.     b->b_dev = 0;
  494.     b->b_ino = 0;
  495. #endif
  496.     b->b_mtime = 0;
  497. }
  498.  
  499. /* Returns pointer to buffer with name NAME, or if NAME is a string of digits
  500.    returns the buffer whose number equals those digits.  Otherwise, returns
  501.    NULL. */
  502.  
  503. Buffer *
  504. buf_exists(name)
  505. register char    *name;
  506. {
  507.     register Buffer    *bp;
  508.  
  509.     if (name == NULL)
  510.         return NULL;
  511.  
  512.     for (bp = world; bp != NULL; bp = bp->b_next)
  513.         if (strcmp(bp->b_name, name) == 0)
  514.             return bp;
  515.  
  516.     return NULL;
  517. }
  518.  
  519. /* Returns buffer pointer with a file name NAME, if one is found.
  520.  * If target is NULL, all buffers are searched; otherwise, only
  521.  * target is examined.  Match is by inode (to catch links) or
  522.  * canonical name.
  523.  *
  524.  * Divergence is diligently searched for.  In particular, all
  525.  * buffers are examined to see if they match the specified file,
  526.  * in name or inode.  If they do, divergence is checked (i.e. loss
  527.  * of underlying file, change in inode number, or modification
  528.  * time different from last visit).
  529.  *
  530.  * DS_REUSE can be used to avoid redundant stat calls.  Use it
  531.  * with care!
  532.  */
  533.  
  534. bool
  535.     was_dir,    /* do_stat found a directory */
  536.     was_file;    /* do_stat found a (plain) file */
  537.  
  538. Buffer *
  539. do_stat(name, target, flags)
  540. register char    *name;
  541. Buffer    *target;
  542. int    flags;
  543. {
  544.     register Buffer    *b = NULL;
  545.     Buffer    *result = NULL;
  546.     char    fnamebuf[FILESIZE];
  547.     static struct stat    stbuf;
  548.  
  549.     PathParse(name, fnamebuf);
  550.  
  551.     if ((flags & DS_REUSE) == 0) {
  552.         stbuf.st_mode = S_IFREG;    /* default if stat fails */
  553. #ifdef USE_INO
  554.         stbuf.st_ino = 0;    /* impossible number */
  555.         stbuf.st_dev = 0;
  556. #endif
  557.         stbuf.st_mtime = 0;
  558.         (void) stat(fnamebuf, &stbuf);
  559.         was_dir = (stbuf.st_mode & S_IFMT) == S_IFDIR;
  560.         was_file = stbuf.st_ino != 0 && (stbuf.st_mode & S_IFMT) == S_IFREG;
  561.     }
  562.     if ((flags & DS_DIR) == 0 && was_dir)
  563.         complain("[%s is a directory]", fnamebuf);
  564.     if (flags & DS_SET) {
  565.         if ((stbuf.st_mode & S_IFMT) == S_IFREG) {
  566. #ifdef USE_INO
  567.             target->b_dev = stbuf.st_dev;
  568.             target->b_ino = stbuf.st_ino;
  569. #endif
  570.             target->b_mtime = stbuf.st_mtime;
  571.         } else {
  572. #ifdef USE_INO
  573.             target->b_dev = 0;
  574.             target->b_ino = 0;
  575. #endif
  576.             target->b_mtime = 0;
  577.         }
  578.         diverge(target, NO);
  579.     }
  580.  
  581.     for (b = world; b != NULL; b = b->b_next) {
  582. #ifdef USE_INO
  583.         if(b->b_ino != 0 && b->b_ino == stbuf.st_ino
  584.         && b->b_dev != 0 && b->b_dev == stbuf.st_dev)
  585.         {
  586.             /* A buffer's inode got a match; check divergence:
  587.              * - name is different & can't stat buffer's fname
  588.              * - name is different & stat yields a different inode
  589.              * - inode now refers to a non-file
  590.              */
  591.             struct stat    stbchk;
  592.  
  593.             if ((strcmp(b->b_fname, fnamebuf) != 0
  594.                && (stat(b->b_fname, &stbchk) == -1
  595.                   || b->b_ino != stbchk.st_ino || b->b_dev != stbchk.st_dev))
  596.             || (stbuf.st_mode & S_IFMT) != S_IFREG)
  597.             {
  598.                 /* false match: buffer's file has lost its inode */
  599.                 b->b_ino = 0;
  600.                 b->b_dev = 0;
  601.                 diverge(b, YES);
  602.                 continue;    /* try again */
  603.             }
  604.             /* true match -- check times */
  605.             if (b->b_mtime != stbuf.st_mtime)
  606.                 diverge(b, YES);
  607.             if (target == NULL || target == b)
  608.                 result = b;
  609.         } else if (b->b_fname != NULL && strcmp(b->b_fname, fnamebuf) == 0) {
  610.             /* a name (but not inode) match */
  611.             if (b->b_ino != stbuf.st_ino
  612.             || (stbuf.st_mode & S_IFMT) != S_IFREG)
  613.             {
  614.                 /* one or the other has an inode */
  615.                 b->b_ino = 0;
  616.                 b->b_dev = 0;
  617.                 diverge(b, YES);
  618.             }
  619.             if (target == NULL || target == b)
  620.                 result = b;
  621.         }
  622. #else
  623.         if (b->b_fname != NULL && strcmp(b->b_fname, fnamebuf) == 0) {
  624.             /* a name match -- check times */
  625.             if (stbuf.st_mtime != b->b_mtime)
  626.                 diverge(b, YES);
  627.             if (target == NULL || target == b)
  628.                 result = b;
  629.         }
  630. #endif
  631.     }
  632.     return result;
  633. }
  634.  
  635. private void
  636. setbname(b, name)
  637. register Buffer    *b;
  638. register char    *name;
  639. {
  640.     UpdModLine = YES;    /* Kludge ... but speeds things up considerably */
  641.     if (name != NULL) {
  642.         if (b->b_name == NoName)
  643.             b->b_name = NULL;
  644.         b->b_name = freealloc((UnivPtr) b->b_name, strlen(name) + 1);
  645.         strcpy(b->b_name, name);
  646.     } else {
  647.         b->b_name = NULL;
  648.     }
  649. #ifdef MAC
  650.     Bufchange = YES;
  651. #endif
  652. }
  653.  
  654. void
  655. setfname(b, name)
  656. register Buffer    *b;
  657. register char    *name;
  658. {
  659.     char    wholename[FILESIZE],
  660.         oldname[FILESIZE],
  661.         *oldptr = NULL;
  662.     Buffer    *save = curbuf;
  663.  
  664.     SetBuf(b);
  665.     UpdModLine = YES;    /* Kludge ... but speeds things up considerably */
  666.     if (b->b_fname != NULL) {
  667.         oldptr = strcpy(oldname, b->b_fname);
  668.         free((UnivPtr) b->b_fname);
  669.         b->b_fname = NULL;
  670.     }
  671.     if (name != NULL) {
  672.         PathParse(name, wholename);
  673.         curbuf->b_fname = strcpy(
  674.             (char *)emalloc(strlen(wholename) + 1), wholename);
  675.     }
  676.     DoAutoExec(curbuf->b_fname, oldptr);
  677.  
  678.     /* until they're known, zero these */
  679. #ifdef USE_INO
  680.     curbuf->b_dev = 0;
  681.     curbuf->b_ino = 0;
  682. #endif
  683.     curbuf->b_mtime = 0;
  684.     diverge(curbuf, NO);
  685.  
  686.     SetBuf(save);
  687. #ifdef MAC
  688.     Bufchange = YES;
  689. #endif
  690. }
  691.  
  692. /* Find the file `fname' into buf and put in in window `w' */
  693.  
  694. Buffer *
  695. do_find(w, fname, force, do_macros)
  696. register Window    *w;
  697. register char    *fname;
  698. bool    force;
  699. bool    do_macros;
  700. {
  701.     register Buffer *b;
  702.     Buffer    *oldb = curbuf;
  703.  
  704.     b = do_stat(fname, (Buffer *)NULL, DS_NONE);
  705.     if (b == NULL) {
  706.         b = mak_buf();
  707.         setfname(b, fname);
  708.         bufname(b);
  709.         (void) do_stat(b->b_fname, b, DS_SET | DS_REUSE);
  710.  
  711.         b->b_ntbf = force;
  712.         SetBuf(b);    /* force => load the file */
  713.         if (w)
  714.             tiewind(w, b);
  715.  
  716.         /* We now execute all pending macro text, on the
  717.          * unwarranted presumption that it must have come
  718.          * from an auto-execute-macro.  If we didn't do this
  719.          * here, it would get delayed until the current
  720.          * command was finished, which may be too late in the
  721.          * case of UNIX_cmdline, watch_input, find_tag, or
  722.          * ErrParse.
  723.          *
  724.          * There are some SetBuf(b) calls within the dispatch,
  725.          * but they do not cause reading of the file
  726.          * because b->b_ntbf will be false at this point.
  727.          * One consequence will be that the macro will be executed
  728.          * on the unfilled buffer -- somewhat surprising!
  729.          *
  730.          * ??? This code is a fudge, and should be replaced
  731.          * by a more elegant solution.
  732.          */
  733.         if (do_macros) {
  734.             ZXchar    c;
  735.             int    saved_tcmd = this_cmd;
  736.             int    saved_lcmd = last_cmd;
  737.             int    saved_as, saved_ac;
  738.  
  739.             save_arg(saved_as, saved_ac);
  740.             last_cmd = this_cmd = OTHER_CMD;
  741.             for (;;) {
  742.                 cmd_sync();
  743.                 if ((c = peekchar) != EOF) {
  744.                     /* double ugh! */
  745.                     peekchar = EOF;
  746.                 } else if ((c = mac_getc()) != EOF) {
  747.                     add_stroke(c);
  748.                 } else {
  749.                     break;
  750.                 }
  751.                 dispatch(LastKeyStruck=c);
  752.             }
  753.             last_cmd = saved_lcmd;
  754.             this_cmd = saved_tcmd;
  755.             restore_arg(saved_as, saved_ac);
  756.         }
  757.         /* ??? At this point, we make the rash assumption
  758.          * that buffer oldb still exists, even though
  759.          * the macro text could have deleted it.
  760.          */
  761.         b->b_ntbf = !force;
  762.         /*
  763.          * the file will be read when the user next mentions Buffer b
  764.          */
  765.         SetBuf(oldb);
  766.     } else {
  767.         if (force) {
  768.             SetBuf(b);    /* b->b_ntbf => load the file  */
  769.             SetBuf(oldb);
  770.         }
  771.         if (w)
  772.             tiewind(w, b);
  773.     }
  774.     return b;
  775. }
  776.  
  777. /* set alternate buffer */
  778.  
  779. void
  780. SetABuf(b)
  781. Buffer    *b;
  782. {
  783.     if (b != NULL)
  784.         lastbuf = b;
  785. }
  786.  
  787.  
  788. /* check to see if BP is a valid buffer pointer */
  789. bool
  790. valid_bp(bp)
  791. register Buffer    *bp;
  792. {
  793.     register Buffer    *b;
  794.  
  795.     for (b = world; b != NULL; b = b->b_next)
  796.         if (b == bp)
  797.             return YES;
  798.     return NO;
  799. }
  800.  
  801. void
  802. SetBuf(newbuf)
  803. register Buffer    *newbuf;
  804. {
  805.     if (newbuf == curbuf || newbuf == NULL)
  806.         return;
  807.  
  808.     if (!valid_bp(newbuf))
  809.         complain("Internal error: (0x%x) is not a valid buffer pointer!", newbuf);
  810.     lsave();
  811.     curbuf = newbuf;
  812.     getDOT();
  813.     /* do the read now ... */
  814.     if (curbuf->b_ntbf)
  815.         read_file(curbuf->b_fname, NO);
  816. #ifdef MAC
  817.     Modechange = YES;
  818. #endif
  819. }
  820.  
  821. Buffer *
  822. do_select(w, name)
  823. register Window    *w;
  824. register char    *name;
  825. {
  826.     register Buffer    *new;
  827.  
  828.     if ((new = buf_exists(name)) == NULL) {
  829.         new = mak_buf();
  830.         setfname(new, (char *)NULL);
  831.         setbname(new, name);
  832.     }
  833.     if (w != NULL)
  834.         tiewind(w, new);
  835.     return new;
  836. }
  837.  
  838. void
  839. buf_init()
  840. {
  841.     SetBuf(do_select(curwind, Mainbuf));
  842. }
  843.  
  844. LinePtr
  845. lastline(lp)
  846. register LinePtr    lp;
  847. {
  848.     register LinePtr    next;
  849.  
  850.     while ((next = lp->l_next) != NULL)
  851.         lp = next;
  852.     return lp;
  853. }
  854.  
  855. LinePtr
  856. next_line(line, num)
  857. register LinePtr    line;
  858. register int    num;
  859. {
  860.     if (num < 0)
  861.         return prev_line(line, -num);
  862.     if (line != NULL)
  863.         while (--num >= 0 && line->l_next != NULL)
  864.             line = line->l_next;
  865.     return line;
  866. }
  867.  
  868. LinePtr
  869. prev_line(line, num)
  870. register LinePtr    line;
  871. register int    num;
  872. {
  873.     if (num < 0)
  874.         return next_line(line, -num);
  875.     if (line != NULL)
  876.         while (--num >= 0 && line->l_prev != NULL)
  877.             line = line->l_prev;
  878.     return line;
  879. }
  880.