home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / EMACSOS2.ZIP / FILE.C < prev    next >
C/C++ Source or Header  |  1988-10-01  |  17KB  |  695 lines

  1. /*    FILE.C:   for MicroEMACS
  2.  
  3.     The routines in this file handle the reading, writing
  4.     and lookup of disk files.  All of details about the
  5.     reading and writing of the disk are in "fileio.c".
  6.  
  7. */
  8.  
  9. #include    <stdio.h>
  10. #include    "estruct.h"
  11. #include    "etype.h"
  12. #include    "edef.h"
  13.  
  14. /*
  15.  * Read a file into the current
  16.  * buffer. This is really easy; all you do is
  17.  * find the name of the file, and call the standard
  18.  * "read a file into the current buffer" code.
  19.  * Bound to "C-X C-R".
  20.  */
  21. PASCAL NEAR fileread(f, n)
  22. {
  23.     register int    s;
  24.     char fname[NFILEN];
  25.  
  26.     if (restflag)        /* don't allow this command if restricted */
  27.         return(resterr());
  28.     if ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE)
  29.         return(s);
  30.     return(readin(fname, TRUE));
  31. }
  32.  
  33. /*
  34.  * Insert a file into the current
  35.  * buffer. This is really easy; all you do it
  36.  * find the name of the file, and call the standard
  37.  * "insert a file into the current buffer" code.
  38.  * Bound to "C-X C-I".
  39.  */
  40. PASCAL NEAR insfile(f, n)
  41. {
  42.     register int    s;
  43.     char fname[NFILEN];
  44.  
  45.     if (restflag)        /* don't allow this command if restricted */
  46.         return(resterr());
  47.     if (curbp->b_mode&MDVIEW)      /* don't allow this command if  */
  48.         return(rdonly());    /* we are in read only mode    */
  49.     if ((s=mlreply("Insert file: ", fname, NFILEN)) != TRUE)
  50.         return(s);
  51.     return(ifile(fname));
  52. }
  53.  
  54. /*
  55.  * Select a file for editing.
  56.  * Look around to see if you can find the
  57.  * fine in another buffer; if you can find it
  58.  * just switch to the buffer. If you cannot find
  59.  * the file, create a new buffer, read in the
  60.  * text, and switch to the new buffer.
  61.  * Bound to C-X C-F.
  62.  */
  63. PASCAL NEAR filefind(f, n)
  64. {
  65.     char fname[NFILEN];    /* file user wishes to find */
  66.     register int s;        /* status return */
  67.  
  68.     if (restflag)        /* don't allow this command if restricted */
  69.         return(resterr());
  70.     if ((s=mlreply("Find file: ", fname, NFILEN)) != TRUE)
  71.         return(s);
  72.     return(getfile(fname, TRUE));
  73. }
  74.  
  75. PASCAL NEAR viewfile(f, n)    /* visit a file in VIEW mode */
  76. {
  77.     char fname[NFILEN];    /* file user wishes to find */
  78.     register int s;        /* status return */
  79.     register WINDOW *wp;    /* scan for windows that need updating */
  80.  
  81.     if (restflag)        /* don't allow this command if restricted */
  82.         return(resterr());
  83.     if ((s=mlreply("View file: ", fname, NFILEN)) != TRUE)
  84.         return (s);
  85.     s = getfile(fname, FALSE);
  86.     if (s) {    /* if we succeed, put it in view mode */
  87.         curwp->w_bufp->b_mode |= MDVIEW;
  88.  
  89.         /* scan through and update mode lines of all windows */
  90.         wp = wheadp;
  91.         while (wp != NULL) {
  92.             wp->w_flag |= WFMODE;
  93.             wp = wp->w_wndp;
  94.         }
  95.     }
  96.     return(s);
  97. }
  98.  
  99. #if    CRYPT
  100. PASCAL NEAR resetkey()    /* reset the encryption key if needed */
  101.  
  102. {
  103.     register int s; /* return status */
  104.  
  105.     /* turn off the encryption flag */
  106.     cryptflag = FALSE;
  107.  
  108.     /* if we are in crypt mode */
  109.     if (curbp->b_mode & MDCRYPT) {
  110.         if (curbp->b_key[0] == 0) {
  111.             s = setkey(FALSE, 0);
  112.             if (s != TRUE)
  113.                 return(s);
  114.         }
  115.  
  116.         /* let others know... */
  117.         cryptflag = TRUE;
  118.  
  119.         /* and set up the key to be used! */
  120.         /* de-encrypt it */
  121.         crypt((char *)NULL, 0);
  122.         crypt(curbp->b_key, strlen(curbp->b_key));
  123.  
  124.         /* re-encrypt it...seeding it to start */
  125.         crypt((char *)NULL, 0);
  126.         crypt(curbp->b_key, strlen(curbp->b_key));
  127.     }
  128.  
  129.     return(TRUE);
  130. }
  131. #endif
  132.  
  133. PASCAL NEAR getfile(fname, lockfl)
  134.  
  135. char fname[];        /* file name to find */
  136. int lockfl;        /* check the file for locks? */
  137.  
  138. {
  139.     register BUFFER *bp;
  140.     register LINE    *lp;
  141.     register int    i;
  142.     register int    s;
  143.     char bname[NBUFN];    /* buffer name to put file */
  144.  
  145. #if    MSDOS | OS2
  146.     mklower(fname);            /* msdos isn't case sensitive */
  147. #endif
  148.     for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
  149.         if ((bp->b_flag&BFINVS)==0 && strcmp(bp->b_fname, fname)==0) {
  150.             swbuffer(bp);
  151.             lp = curwp->w_dotp;
  152.             i = curwp->w_ntrows/2;
  153.             while (i-- && lback(lp)!=curbp->b_linep)
  154.                 lp = lback(lp);
  155.             curwp->w_linep = lp;
  156.             curwp->w_flag |= WFMODE|WFHARD;
  157.             mlwrite("[Old buffer]");
  158.             return (TRUE);
  159.         }
  160.     }
  161.     makename(bname, fname);         /* New buffer name.    */
  162.     while ((bp=bfind(bname, FALSE, 0)) != NULL) {
  163.         /* old buffer name conflict code */
  164.         s = mlreply("Buffer name: ", bname, NBUFN);
  165.         if (s == ABORT)         /* ^G to just quit    */
  166.             return (s);
  167.         if (s == FALSE) {        /* CR to clobber it    */
  168.             makename(bname, fname);
  169.             break;
  170.         }
  171.     }
  172.     if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) {
  173.         mlwrite("Cannot create buffer");
  174.         return (FALSE);
  175.     }
  176.     if (--curbp->b_nwnd == 0) {        /* Undisplay.        */
  177.         curbp->b_dotp = curwp->w_dotp;
  178.         curbp->b_doto = curwp->w_doto;
  179.         curbp->b_markp = curwp->w_markp;
  180.         curbp->b_marko = curwp->w_marko;
  181.         curbp->b_fcol = curwp->w_fcol;
  182.     }
  183.     curbp = bp;                /* Switch to it.    */
  184.     curwp->w_bufp = bp;
  185.     curbp->b_nwnd++;
  186.     return(readin(fname, lockfl));        /* Read it in.        */
  187. }
  188.  
  189. /*
  190.     Read file "fname" into the current buffer, blowing away any text
  191.     found there.  Called by both the read and find commands.  Return
  192.     the final status of the read.  Also called by the mainline, to
  193.     read in a file specified on the command line as an argument. 
  194.     The command in $readhook is called after the buffer is set up
  195.     and before it is read. 
  196. */
  197.  
  198. PASCAL NEAR readin(fname, lockfl)
  199.  
  200. char    fname[];    /* name of file to read */
  201. int    lockfl;        /* check for file locks? */
  202.  
  203. {
  204.     register LINE    *lp1;
  205.     register LINE    *lp2;
  206.     register int    i;
  207.     register WINDOW *wp;
  208.     register BUFFER *bp;
  209.     register int    s;
  210.     register int    nbytes;
  211.     register int    nline;
  212.     char mesg[NSTRING];
  213.  
  214. #if    FILOCK
  215.     if (lockfl && lockchk(fname) == ABORT)
  216.         return(ABORT);
  217. #endif
  218. #if    CRYPT
  219.     s = resetkey();
  220.     if (s != TRUE)
  221.         return(s);
  222. #endif
  223.     bp = curbp;                /* Cheap.        */
  224.     if ((s=bclear(bp)) != TRUE)        /* Might be old.    */
  225.         return (s);
  226.     bp->b_flag &= ~(BFINVS|BFCHG);
  227.     strcpy(bp->b_fname, fname);
  228.  
  229.     /* let a user macro get hold of things...if he wants */
  230.     (*readhook)(FALSE, 1);
  231.  
  232.     /* turn off ALL keyboard translation in case we get a dos error */
  233.     TTkclose();
  234.  
  235.     if ((s=ffropen(fname)) == FIOERR)    /* Hard file open.    */
  236.         goto out;
  237.  
  238.     if (s == FIOFNF) {            /* File not found.    */
  239.         mlwrite("[New file]");
  240.         goto out;
  241.     }
  242.  
  243.     /* read the file in */
  244.     mlwrite("[Reading file]");
  245.     nline = 0;
  246.     while ((s=ffgetline()) == FIOSUC) {
  247.         nbytes = strlen(fline);
  248.         if ((lp1=lalloc(nbytes)) == NULL) {
  249.             s = FIOMEM;        /* Keep message on the    */
  250.             break;            /* display.        */
  251.         }
  252.         lp2 = lback(curbp->b_linep);
  253.         lp2->l_fp = lp1;
  254.         lp1->l_fp = curbp->b_linep;
  255.         lp1->l_bp = lp2;
  256.         curbp->b_linep->l_bp = lp1;
  257.         for (i=0; i<nbytes; ++i)
  258.             lputc(lp1, i, fline[i]);
  259.         ++nline;
  260.     }
  261.     ffclose();                /* Ignore errors.    */
  262.     strcpy(mesg, "[");
  263.     if (s==FIOERR) {
  264.         strcat(mesg, "I/O ERROR, ");
  265.         curbp->b_flag |= BFTRUNC;
  266.     }
  267.     if (s == FIOMEM) {
  268.         strcat(mesg, "OUT OF MEMORY, ");
  269.         curbp->b_flag |= BFTRUNC;
  270.     }
  271.     strcat(mesg, "Read ");
  272.     strcat(mesg, int_asc(nline));
  273.     strcat(mesg, " line");
  274.     if (nline > 1)
  275.         strcat(mesg, "s");
  276.     strcat(mesg, "]");
  277.     mlwrite(mesg);
  278.  
  279. out:
  280.     TTkopen();    /* open the keyboard again */
  281.     for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
  282.         if (wp->w_bufp == curbp) {
  283.             wp->w_linep = lforw(curbp->b_linep);
  284.             wp->w_dotp  = lforw(curbp->b_linep);
  285.             wp->w_doto  = 0;
  286.             wp->w_markp = NULL;
  287.             wp->w_marko = 0;
  288.             wp->w_flag |= WFMODE|WFHARD;
  289.         }
  290.     }
  291.     if (s == FIOERR || s == FIOFNF)     /* False if error.    */
  292.         return(FALSE);
  293.     return (TRUE);
  294. }
  295.  
  296. /*
  297.  * Take a file name, and from it
  298.  * fabricate a buffer name. This routine knows
  299.  * about the syntax of file names on the target system.
  300.  * I suppose that this information could be put in
  301.  * a better place than a line of code.
  302.  * Returns a pointer into fname indicating the end of the file path; i.e.,
  303.  * 1 character BEYOND the path name.
  304.  */
  305. char *PASCAL NEAR makename(bname, fname)
  306. char    bname[];
  307. char    fname[];
  308. {
  309.     register char *cp1;
  310.     register char *cp2;
  311.     register char *pathp;
  312.  
  313.     cp1 = &fname[0];
  314.     while (*cp1 != 0)
  315.         ++cp1;
  316.  
  317. #if    AMIGA
  318.     while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='/')
  319.         --cp1;
  320. #endif
  321. #if    VMS
  322.     while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']')
  323.         --cp1;
  324. #endif
  325. #if    MSDOS | OS2
  326.     while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
  327.         --cp1;
  328. #endif
  329. #if    ST520
  330.     while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\')
  331.         --cp1;
  332. #endif
  333. #if    FINDER
  334.     while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
  335.         --cp1;
  336. #endif
  337. #if    V7 | USG | BSD
  338.     while (cp1!=&fname[0] && cp1[-1]!='/')
  339.         --cp1;
  340. #endif
  341. #if WMCS
  342.     while (cp1!=&fname[0] && cp1[-1]!='_' && cp1[-1]!='/')
  343.         --cp1;
  344. #endif
  345.     /* cp1 is pointing to the first real filename char */
  346.     pathp = cp1;
  347.  
  348.     cp2 = &bname[0];
  349.     while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
  350.         *cp2++ = *cp1++;
  351.     *cp2 = 0;
  352.  
  353.     return(pathp);
  354. }
  355.  
  356. PASCAL NEAR unqname(name)    /* make sure a buffer name is unique */
  357.  
  358. char *name;    /* name to check on */
  359.  
  360. {
  361.     register char *sp;
  362.  
  363.     /* check to see if it is in the buffer list */
  364.     while (bfind(name, 0, FALSE) != NULL) {
  365.  
  366.         /* go to the end of the name */
  367.         sp = name;
  368.         while (*sp)
  369.             ++sp;
  370.         if (sp == name || (*(sp-1) <'0' || *(sp-1) > '8')) {
  371.             *sp++ = '0';
  372.             *sp = 0;
  373.         } else
  374.               *(--sp) += 1;
  375.     }
  376. }
  377.  
  378. /*
  379.  * Ask for a file name, and write the
  380.  * contents of the current buffer to that file.
  381.  * Update the remembered file name and clear the
  382.  * buffer changed flag. This handling of file names
  383.  * is different from the earlier versions, and
  384.  * is more compatable with Gosling EMACS than
  385.  * with ITS EMACS. Bound to "C-X C-W".
  386.  */
  387. PASCAL NEAR filewrite(f, n)
  388. {
  389.     register WINDOW *wp;
  390.     register int    s;
  391.     char        fname[NFILEN];
  392.  
  393.     if (restflag)        /* don't allow this command if restricted */
  394.         return(resterr());
  395.     if ((s=mlreply("Write file: ", fname, NFILEN)) != TRUE)
  396.         return (s);
  397.     if ((s=writeout(fname)) == TRUE) {
  398.         strcpy(curbp->b_fname, fname);
  399.         curbp->b_flag &= ~BFCHG;
  400.         wp = wheadp;            /* Update mode lines.    */
  401.         while (wp != NULL) {
  402.             if (wp->w_bufp == curbp)
  403.                 wp->w_flag |= WFMODE;
  404.             wp = wp->w_wndp;
  405.         }
  406.     }
  407.     return (s);
  408. }
  409.  
  410. /*
  411.  * Save the contents of the current
  412.  * buffer in its associatd file. Do nothing
  413.  * if nothing has changed (this may be a bug, not a
  414.  * feature). Error if there is no remembered file
  415.  * name for the buffer. Bound to "C-X C-S". May
  416.  * get called by "C-Z".
  417.  */
  418. PASCAL NEAR filesave(f, n)
  419. {
  420.     register WINDOW *wp;
  421.     register int    s;
  422.  
  423.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  424.         return(rdonly());    /* we are in read only mode    */
  425.     if ((curbp->b_flag&BFCHG) == 0)     /* Return, no changes.    */
  426.         return (TRUE);
  427.     if (curbp->b_fname[0] == 0) {        /* Must have a name.    */
  428.         mlwrite("No file name");
  429.         return (FALSE);
  430.     }
  431.  
  432.     /* complain about truncated files */
  433.     if ((curbp->b_flag&BFTRUNC) != 0) {
  434.         if (mlyesno("Truncated file..write it out") == FALSE) {
  435.             mlwrite("[Aborted]");
  436.             return(FALSE);
  437.         }
  438.     }
  439.  
  440.     /* complain about narrowed buffers */
  441.     if ((curbp->b_flag&BFNAROW) != 0) {
  442.         if (mlyesno("Narrowed Buffer..write it out") == FALSE) {
  443.             mlwrite("[Aborted]");
  444.             return(FALSE);
  445.         }
  446.     }
  447.  
  448.     if ((s=writeout(curbp->b_fname)) == TRUE) {
  449.         curbp->b_flag &= ~BFCHG;
  450.         wp = wheadp;            /* Update mode lines.    */
  451.         while (wp != NULL) {
  452.             if (wp->w_bufp == curbp)
  453.                 wp->w_flag |= WFMODE;
  454.             wp = wp->w_wndp;
  455.         }
  456.     }
  457.     return (s);
  458. }
  459.  
  460. /*
  461.  * This function performs the details of file writing. It uses
  462.  * the file management routines in the "fileio.c" package. The
  463.  * number of lines written is displayed. Several errors are
  464.  * posible, and cause writeout to return a FALSE result. When
  465.  * $ssave is TRUE,  the buffer is written out to a temporary
  466.  * file, and then the old file is unlinked and the temporary
  467.  * renamed to the original name.
  468.  */
  469.  
  470. PASCAL NEAR writeout(fn)
  471.  
  472. char *fn;    /* name of file to write current buffer to */
  473.  
  474. {
  475.     register LINE *lp;    /* line to scan while writing */
  476.     register char *sp;    /* temporary string pointer */
  477.     register int nline;    /* number of lines written */
  478.     int status;        /* return status */
  479.     int sflag;        /* are we safe saving? */
  480.     char tname[NSTRING];    /* temporary file name */
  481.     char buf[NSTRING];    /* message buffer */
  482.  
  483. #if    CRYPT
  484.     status = resetkey();
  485.     if (status != TRUE)
  486.         return(status);
  487. #endif
  488.  
  489.     /* determine if we will use the save method */
  490.     sflag = FALSE;
  491.     if (ssave && fexist(fn))
  492.         sflag = TRUE;
  493.  
  494.     /* turn off ALL keyboard translation in case we get a dos error */
  495.     TTkclose();
  496.  
  497.     /* Perform Safe Save..... */
  498.     if (sflag) {
  499.         /* duplicate original file name, and find where to trunc it */
  500.         sp = tname + (makename(tname, fn) - fn) + 1;
  501.         strcpy(tname, fn);
  502.  
  503.         /* create a unique name, using random numbers */
  504.         do {
  505.             *sp = 0;
  506.             strcat(tname, int_asc(ernd()));
  507.         } while(fexist(tname));
  508.  
  509.         /* open the temporary file */
  510.         status = ffwopen(tname);
  511.     } else
  512.         status = ffwopen(fn);
  513.  
  514.     /* if the open failed.. clean up and abort */
  515.     if (status != FIOSUC) {
  516.         TTkopen();
  517.         return(FALSE);
  518.     }
  519.  
  520.     /* write the current buffer's lines to the open disk file */
  521.     mlwrite("[Writing...]");    /* tell us that we're writing */
  522.     lp = lforw(curbp->b_linep);    /* start at the first line.    */
  523.     nline = 0;            /* track the Number of lines    */
  524.     while (lp != curbp->b_linep) {
  525.         if ((status = ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
  526.             break;
  527.         ++nline;
  528.         lp = lforw(lp);
  529.     }
  530.  
  531.  
  532.     /* report on status of file write */
  533.     *buf = 0;
  534.     status |= ffclose();
  535.     if (status == FIOSUC) {
  536.         /* report on success (or lack therof) */
  537.         strcpy(buf, "[Wrote ");
  538.         strcat(buf, int_asc(nline));
  539.         strcat(buf, " line");
  540.         if (nline > 1)
  541.             strcat(buf, "s");
  542.  
  543.         if (sflag) {
  544.             /* erase original file */
  545.             /* rename temporary file to original name */
  546.             if (unlink(fn) == 0 && rename(tname, fn) == 0)
  547.                 ;
  548.             else {
  549.                 strcat(buf, ", saved as ");
  550.                 strcat(buf, tname);
  551.                 status = FIODEL;        /* failed */
  552.             }
  553.         }
  554.         strcat(buf, "]");
  555.         mlwrite(buf);
  556.     }
  557.  
  558.     /* reopen the keyboard, and return our status */
  559.     TTkopen();
  560.     return(status == FIOSUC);
  561. }
  562.  
  563. /*
  564.  * The command allows the user
  565.  * to modify the file name associated with
  566.  * the current buffer. It is like the "f" command
  567.  * in UNIX "ed". The operation is simple; just zap
  568.  * the name in the BUFFER structure, and mark the windows
  569.  * as needing an update. You can type a blank line at the
  570.  * prompt if you wish.
  571.  */
  572.  
  573. PASCAL NEAR filename(f, n)
  574.  
  575. {
  576.     register WINDOW *wp;
  577.     register int    s;
  578.     char        fname[NFILEN];
  579.  
  580.     if (restflag)        /* don't allow this command if restricted */
  581.         return(resterr());
  582.     if ((s=mlreply("Name: ", fname, NFILEN)) == ABORT)
  583.         return (s);
  584.     if (s == FALSE)
  585.         strcpy(curbp->b_fname, "");
  586.     else
  587.         strcpy(curbp->b_fname, fname);
  588.     wp = wheadp;                /* Update mode lines.    */
  589.     while (wp != NULL) {
  590.         if (wp->w_bufp == curbp)
  591.             wp->w_flag |= WFMODE;
  592.         wp = wp->w_wndp;
  593.     }
  594.     curbp->b_mode &= ~MDVIEW;      /* no longer read only mode */
  595.     return (TRUE);
  596. }
  597.  
  598. /*
  599.  * Insert file "fname" into the current
  600.  * buffer, Called by insert file command. Return the final
  601.  * status of the read.
  602.  */
  603. PASCAL NEAR ifile(fname)
  604. char    fname[];
  605. {
  606.     register LINE    *lp0;
  607.     register LINE    *lp1;
  608.     register LINE    *lp2;
  609.     register int    i;
  610.     register BUFFER *bp;
  611.     register int    s;
  612.     register int    nbytes;
  613.     register int    nline;
  614.     char mesg[NSTRING];
  615.  
  616.     bp = curbp;                /* Cheap.        */
  617.     bp->b_flag |= BFCHG;            /* we have changed    */
  618.     bp->b_flag &= ~BFINVS;            /* and are not temporary*/
  619.     if ((s=ffropen(fname)) == FIOERR)    /* Hard file open.    */
  620.         goto out;
  621.     if (s == FIOFNF) {            /* File not found.    */
  622.         mlwrite("[No such file]");
  623.         return(FALSE);
  624.     }
  625.     mlwrite("[Inserting file]");
  626.  
  627. #if    CRYPT
  628.     s = resetkey();
  629.     if (s != TRUE)
  630.         return(s);
  631. #endif
  632.     /* back up a line and save the mark here */
  633.     curwp->w_dotp = lback(curwp->w_dotp);
  634.     curwp->w_doto = 0;
  635.     curwp->w_markp = curwp->w_dotp;
  636.     curwp->w_marko = 0;
  637.  
  638.     nline = 0;
  639.     while ((s=ffgetline()) == FIOSUC) {
  640.         nbytes = strlen(fline);
  641.         if ((lp1=lalloc(nbytes)) == NULL) {
  642.             s = FIOMEM;        /* Keep message on the    */
  643.             break;            /* display.        */
  644.         }
  645.         lp0 = curwp->w_dotp;  /* line previous to insert */
  646.         lp2 = lp0->l_fp;    /* line after insert */
  647.  
  648.         /* re-link new line between lp0 and lp2 */
  649.         lp2->l_bp = lp1;
  650.         lp0->l_fp = lp1;
  651.         lp1->l_bp = lp0;
  652.         lp1->l_fp = lp2;
  653.  
  654.         /* and advance and write out the current line */
  655.         curwp->w_dotp = lp1;
  656.         for (i=0; i<nbytes; ++i)
  657.             lputc(lp1, i, fline[i]);
  658.         ++nline;
  659.     }
  660.     ffclose();                /* Ignore errors.    */
  661.     curwp->w_markp = lforw(curwp->w_markp);
  662.     strcpy(mesg, "[");
  663.     if (s==FIOERR) {
  664.         strcat(mesg, "I/O ERROR, ");
  665.         curbp->b_flag |= BFTRUNC;
  666.     }
  667.     if (s == FIOMEM) {
  668.         strcat(mesg, "OUT OF MEMORY, ");
  669.         curbp->b_flag |= BFTRUNC;
  670.     }
  671.     strcat(mesg, "Inserted ");
  672.     strcat(mesg, int_asc(nline));
  673.     strcat(mesg, " line");
  674.     if (nline > 1)
  675.         strcat(mesg, "s");
  676.     strcat(mesg, "]");
  677.     mlwrite(mesg);
  678.  
  679. out:
  680.     /* advance to the next line and mark the window for changes */
  681.     curwp->w_dotp = lforw(curwp->w_dotp);
  682.     curwp->w_flag |= WFHARD | WFMODE;
  683.  
  684.     /* copy window parameters back to the buffer structure */
  685.     curbp->b_dotp = curwp->w_dotp;
  686.     curbp->b_doto = curwp->w_doto;
  687.     curbp->b_markp = curwp->w_markp;
  688.     curbp->b_marko = curwp->w_marko;
  689.     curbp->b_fcol = curwp->w_fcol;
  690.  
  691.     if (s == FIOERR)            /* False if error.    */
  692.         return (FALSE);
  693.     return (TRUE);
  694. }
  695.