home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / memacs400_src.lzh / MEMACS400 / SRC / file.c < prev    next >
Text File  |  1996-04-25  |  22KB  |  908 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    "eproto.h"
  12. #include    "edef.h"
  13. #include    "elang.h"
  14. #if    BSD | FREEBSD | SUN | USG | AIX
  15. #include    <sys/types.h>
  16. #include    <sys/stat.h>
  17. #endif
  18.  
  19. /*
  20.  * Read a file into the current
  21.  * buffer. This is really easy; all you do is
  22.  * find the name of the file, and call the standard
  23.  * "read a file into the current buffer" code.
  24.  * Bound to "C-X C-R".
  25.  */
  26. PASCAL NEAR fileread(f, n)
  27.  
  28. int f, n;    /* defualt and numeric arguments (unused) */
  29.  
  30. {
  31.     char *fname;    /* file name to read */
  32.  
  33.     if (restflag)        /* don't allow this command if restricted */
  34.         return(resterr());
  35.  
  36.     if ((fname = gtfilename(TEXT131)) == NULL)
  37. /*                              "Read file" */
  38.         return(FALSE);
  39.     return(readin(fname, TRUE));
  40. }
  41.  
  42. /*
  43.  * Insert a file into the current
  44.  * buffer. This is really easy; all you do it
  45.  * find the name of the file, and call the standard
  46.  * "insert a file into the current buffer" code.
  47.  * Bound to "C-X C-I".
  48.  */
  49. PASCAL NEAR insfile(f, n)
  50.  
  51. int f,n;    /* prefix flag and argument */
  52.  
  53. {
  54.     register int    s;
  55.     char *fname;    /* file name */
  56.     LINE *curline;
  57.  
  58.     if (restflag)        /* don't allow this command if restricted */
  59.         return(resterr());
  60.     if (curbp->b_mode&MDVIEW)      /* don't allow this command if  */
  61.         return(rdonly());    /* we are in read only mode    */
  62.  
  63.     if ((fname = gtfilename(TEXT132)) == NULL) 
  64. /*                              "Insert file" */
  65.         return(FALSE);
  66.     /*
  67.      * Save the local pointers to hold global ".", in case
  68.      * $yankflag is set to 1.  Insert-file always places the
  69.      * starting offset point at 0.  Hold *previous* line
  70.      * position, since the current line may be re-allocated.
  71.      */
  72.     if (yankflag)
  73.         curline = lback(curwp->w_dotp);
  74.  
  75.     s = ifile(fname);
  76.  
  77.     if (yankflag)
  78.         curwp->w_dotp = lforw(curline);
  79.  
  80.     return (s);
  81. }
  82.  
  83. /*
  84.  * Select a file for editing.
  85.  * Look around to see if you can find the
  86.  * fine in another buffer; if you can find it
  87.  * just switch to the buffer. If you cannot find
  88.  * the file, create a new buffer, read in the
  89.  * text, and switch to the new buffer.
  90.  * Bound to C-X C-F.
  91.  */
  92. PASCAL NEAR filefind(f, n)
  93.  
  94. int f,n;    /* prefix flag and argument */
  95.  
  96. {
  97.     char *fname;    /* file user wishes to find */    /* file name */
  98.  
  99.     if (restflag)        /* don't allow this command if restricted */
  100.         return(resterr());
  101.  
  102.     if ((fname = gtfilename(TEXT133)) == NULL) 
  103. /*                              "Find file" */
  104.         return(FALSE);
  105.     return(getfile(fname, TRUE));
  106. }
  107.  
  108. PASCAL NEAR viewfile(f, n)    /* visit a file in VIEW mode */
  109.  
  110. int f,n;    /* prefix flag and argument */
  111.  
  112. {
  113.     char *fname;    /* file user wishes to find */    /* file name */
  114.     register int s;    /* status return */
  115.  
  116.     if (restflag)        /* don't allow this command if restricted */
  117.         return(resterr());
  118.  
  119.     if ((fname = gtfilename(TEXT134)) == NULL) 
  120. /*                              "View file" */
  121.         return(FALSE);
  122.     s = getfile(fname, FALSE);
  123.     if (s) {    /* if we succeed, put it in view mode */
  124.         curwp->w_bufp->b_mode |= MDVIEW;
  125.         upmode();
  126.     }
  127.     return(s);
  128. }
  129.  
  130. #if    CRYPT
  131. PASCAL NEAR resetkey()    /* reset the encryption key if needed */
  132.  
  133. {
  134.     register int s; /* return status */
  135.  
  136.     /* turn off the encryption flag */
  137.     cryptflag = FALSE;
  138.  
  139.     /* if we are in crypt mode */
  140.     if (curbp->b_mode & MDCRYPT) {
  141.         if (curbp->b_key[0] == 0) {
  142.             s = setekey(FALSE, 0);
  143.             if (s != TRUE)
  144.                 return(s);
  145.         }
  146.  
  147.         /* let others know... */
  148.         cryptflag = TRUE;
  149.  
  150.         /* and set up the key to be used! */
  151.         /* de-encrypt it */
  152.         ecrypt((char *)NULL, 0);
  153.         ecrypt(curbp->b_key, strlen(curbp->b_key));
  154.  
  155.         /* re-encrypt it...seeding it to start */
  156.         ecrypt((char *)NULL, 0);
  157.         ecrypt(curbp->b_key, strlen(curbp->b_key));
  158.     }
  159.  
  160.     return(TRUE);
  161. }
  162. #endif
  163.  
  164. PASCAL NEAR getfile(fname, lockfl)
  165.  
  166. char fname[];        /* file name to find */
  167. int lockfl;        /* check the file for locks? */
  168.  
  169. {
  170.     register BUFFER *bp;
  171.     register LINE    *lp;
  172.     register int    i;
  173.     register int    s;
  174.     SCREEN        *sp;    /* screen pointer, if we need it */
  175.     char bname[NBUFN];    /* buffer name to put file */
  176.     char prompt[NSTRING];    /* string for collisions prompt */
  177.  
  178. #if    MSDOS | WINNT | AOSVS | VMS | TOS | defined(OSK)
  179.     mklower(fname);            /* msdos isn't case sensitive */
  180. #endif
  181.     for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
  182.         if ((bp->b_flag&BFINVS)==0 && strcmp(bp->b_fname, fname)==0) {
  183.             swbuffer(bp);
  184.             lp = curwp->w_dotp;
  185.             i = curwp->w_ntrows/2;
  186.             while (i-- && lback(lp)!=curbp->b_linep)
  187.                 lp = lback(lp);
  188.             curwp->w_linep = lp;
  189.             curwp->w_flag |= WFMODE|WFHARD;
  190.             mlwrite(TEXT135);
  191. /*                              "[Old buffer]" */
  192.             return(TRUE);
  193.         }
  194.     }
  195.     makename(bname, fname);         /* New buffer name.    */
  196.  
  197.     /* prevent buffer name conflicts */
  198.     while ((bp=bfind(bname, FALSE, 0)) != NULL) {
  199.  
  200.         /* first, come up with our own name */
  201.         unqname(bname);
  202.  
  203.         /* if interactive, let em change it if they dislike our names */
  204.         if (clexec == FALSE) {
  205.  
  206.             strcpy(prompt, TEXT136);
  207. /*                       "Buffer name: " */
  208.             strcpy(&prompt[strlen(prompt) - 2], "[");
  209.             strcat(prompt, bname);
  210.             strcat(prompt, "]: ");
  211.             s = mlreply(prompt, bname, NBUFN);
  212.  
  213.             if (s == ABORT)     /* ^G to just quit    */
  214.                 return(s);
  215.             if (s == FALSE) {    /* CR to let the computer pick */
  216.                 makename(bname, fname);    /* New buffer name. */
  217.                 unqname(bname);        /* which is unique */
  218.             }
  219.         }
  220.     }
  221.  
  222.     /* create the new buffer */
  223.     if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) {
  224.         mlwrite(TEXT137);
  225. /*                      "Cannot create buffer" */
  226.         return(FALSE);
  227.     }
  228.  
  229.     /*
  230.      * Check $newscreen, see if we make a
  231.      * new screen for the new file.
  232.      */
  233.     if (newscreenflag) {
  234.         sp = lookup_screen(bname);
  235.         if (sp == (SCREEN *)NULL) {
  236.             /* screen does not exist, create it */
  237.             sp = init_screen(bname, bp);
  238.         }
  239.         select_screen(sp, FALSE);
  240.     }
  241.  
  242.     swbuffer(bp);            /* switch to the new buffer */
  243.     return(readin(fname, lockfl));    /* Read it in.        */
  244. }
  245.  
  246. /*
  247.     Read file "fname" into the current buffer, blowing away any text
  248.     found there.  Called by both the read and find commands.  Return
  249.     the final status of the read.  Also called by the mainline, to
  250.     read in a file specified on the command line as an argument. 
  251.     The command in $readhook is called after the buffer is set up
  252.     and before it is read. 
  253. */
  254.  
  255. PASCAL NEAR readin(fname, lockfl)
  256.  
  257. char    fname[];    /* name of file to read */
  258. int    lockfl;        /* check for file locks? */
  259.  
  260. {
  261.     register LINE *lp1;
  262.     register LINE *lp2;
  263.     register int i;
  264.     register EWINDOW *wp;
  265.     register BUFFER *bp;
  266.     register int s;
  267.     register long nline;
  268.     register int cmark;    /* current mark */
  269.     int nbytes;
  270.     char mesg[NSTRING];
  271.  
  272. #if    FILOCK
  273.     force_read = FALSE;
  274.     if (lockfl && lockchk(fname) == ABORT)
  275.         force_read = TRUE;
  276. #endif
  277.  
  278.     bp = curbp;                /* Cheap.        */
  279.     if ((s=bclear(bp)) != TRUE)        /* Might be old.    */
  280.         return(s);
  281.     bp->b_flag &= ~(BFINVS|BFCHG);
  282.     strcpy(bp->b_fname, fname);
  283.  
  284.     /* let a user macro get hold of things...if he wants */
  285.     execkey(&readhook, FALSE, 1);
  286.  
  287. #if    CRYPT
  288.     /* set up for decryption */
  289.     s = resetkey();
  290.     if (s != TRUE)
  291.         return(s);
  292. #endif
  293.  
  294.     /* turn off ALL keyboard translation in case we get a dos error */
  295.     TTkclose();
  296.  
  297.     if ((s=ffropen(fname)) == FIOERR)    /* Hard file open.    */
  298.         goto out;
  299.  
  300.     if (s == FIOFNF) {            /* File not found.    */
  301.         mlwrite(TEXT138);
  302. /*                      "[New file]" */
  303.         goto out;
  304.     }
  305.  
  306.     /* read the file in */
  307.     mlwrite(TEXT139);
  308. /*              "[Reading file]" */
  309.     nline = 0L;
  310.     while ((s=ffgetline(&nbytes)) == FIOSUC) {
  311.         if ((lp1=lalloc(nbytes)) == NULL) {
  312.             s = FIOMEM;        /* Keep message on the    */
  313.             break;            /* display.        */
  314.         }
  315.         lp2 = lback(curbp->b_linep);
  316.         lp2->l_fp = lp1;
  317.         lp1->l_fp = curbp->b_linep;
  318.         lp1->l_bp = lp2;
  319.         curbp->b_linep->l_bp = lp1;
  320.         for (i=0; i<nbytes; ++i)
  321.             lputc(lp1, i, fline[i]);
  322.         ++nline;
  323.     }
  324.     ffclose();                /* Ignore errors.    */
  325.  
  326. #if    BSD || FREEBSD || USG || AUX || SMOS || HPUX8 || HPUX9 || SUN || XENIX || AVION
  327.     /* if we don't have write priviledges, make this in VIEW mode */
  328.     if (s !=FIOERR && s != FIOFNF) {
  329.         if (access(fname, 2 /* W_OK*/) != 0)
  330.             curbp->b_mode |= MDVIEW;
  331.     }
  332. #endif
  333.  
  334.     strcpy(mesg, "[");
  335.     if (s==FIOERR) {
  336.         strcat(mesg, TEXT141);
  337. /*                           "I/O ERROR, " */
  338.         curbp->b_flag |= BFTRUNC;
  339.     }
  340.     if (s == FIOMEM) {
  341.         strcat(mesg, TEXT142);
  342. /*                           "OUT OF MEMORY, " */
  343.         curbp->b_flag |= BFTRUNC;
  344.     }
  345.     strcat(mesg, TEXT140);
  346. /*                   "Read " */
  347.     strcat(mesg, long_asc(nline));
  348.     strcat(mesg, TEXT143);
  349. /*                   " line" */
  350.     if (nline > 1L)
  351.         strcat(mesg, "s");
  352.     strcat(mesg, "]");
  353.     mlwrite(mesg);
  354.  
  355. out:
  356.     TTkopen();    /* open the keyboard again */
  357.     for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
  358.         if (wp->w_bufp == curbp) {
  359.             wp->w_linep = lforw(curbp->b_linep);
  360.             wp->w_dotp  = lforw(curbp->b_linep);
  361.             wp->w_doto  = 0;
  362.             for (cmark = 0; cmark < NMARKS; cmark++) {
  363.                 wp->w_markp[cmark] = NULL;
  364.                 wp->w_marko[cmark] = 0;
  365.             }
  366.             wp->w_flag |= WFMODE|WFHARD;
  367.         }
  368.     }
  369. #if    FILOCK
  370.     if (force_read == TRUE) {
  371.         curbp->b_mode |= MDVIEW;
  372.         upmode();
  373.     }
  374. #endif
  375.     if (s == FIOERR || s == FIOFNF)     /* False if error.    */
  376.         return(FALSE);
  377.     return(TRUE);
  378. }
  379.  
  380. /*
  381.  * Take a file name, and from it
  382.  * fabricate a buffer name. This routine knows
  383.  * about the syntax of file names on the target system.
  384.  * I suppose that this information could be put in
  385.  * a better place than a line of code.
  386.  * Returns a pointer into fname indicating the end of the file path; i.e.,
  387.  * 1 character BEYOND the path name.
  388.  */
  389. char *PASCAL NEAR makename(bname, fname)
  390.  
  391. char *bname;
  392. char *fname;
  393.  
  394. {
  395.     register char *cp1;
  396.     register char *cp2;
  397.     register char *pathp;
  398.  
  399. #if     AOSVS | MV_UX
  400.         resolve_full_pathname(fname, fname);
  401.         mklower(fname);   /* aos/vs not case sensitive */
  402. #endif
  403.     cp1 = &fname[0];
  404.     while (*cp1 != 0)
  405.         ++cp1;
  406.  
  407. #if    AMIGA
  408.     while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='/')
  409.         --cp1;
  410. #endif
  411. #if     AOSVS | MV_UX
  412.         while (cp1!=&fname[0] && cp1[-1]!=':')
  413.                 --cp1;
  414. #endif
  415. #if    VMS
  416.     while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']')
  417.         --cp1;
  418. #endif
  419. #if    MSDOS | OS2 | WINNT
  420.     while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
  421.         --cp1;
  422. #endif
  423. #if    TOS
  424.     while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\')
  425.         --cp1;
  426. #endif
  427. #if    FINDER
  428.     while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
  429.         --cp1;
  430. #endif
  431. #if    USG | AIX | AUX | SMOS | HPUX8 | HPUX9 | BSD | FREEBSD | SUN | XENIX | AVIION
  432.     while (cp1!=&fname[0] && cp1[-1]!='/')
  433.         --cp1;
  434. #endif
  435. #if WMCS
  436.     while (cp1!=&fname[0] && cp1[-1]!='_' && cp1[-1]!='/')
  437.         --cp1;
  438. #endif
  439.     /* cp1 is pointing to the first real filename char */
  440.     pathp = cp1;
  441.  
  442.     cp2 = &bname[0];
  443.     while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
  444.         *cp2++ = *cp1++;
  445.     *cp2 = 0;
  446.  
  447.     return(pathp);
  448. }
  449.  
  450. VOID PASCAL NEAR unqname(name)    /* make sure a buffer name is unique */
  451.  
  452. char *name;    /* name to check on */
  453.  
  454. {
  455.     register char *sp;
  456.  
  457.     /* check to see if it is in the buffer list */
  458.     while (bfind(name, 0, FALSE) != NULL) {
  459.  
  460.         /* go to the end of the name */
  461.         sp = name;
  462.         while (*sp)
  463.             ++sp;
  464.         if (sp == name || (*(sp-1) <'0' || *(sp-1) > '8')) {
  465.             *sp++ = '0';
  466.             *sp = 0;
  467.         } else
  468.               *(--sp) += 1;
  469.     }
  470. }
  471.  
  472. /*
  473.  * Ask for a file name, and write the
  474.  * contents of the current buffer to that file.
  475.  * Update the remembered file name and clear the
  476.  * buffer changed flag. This handling of file names
  477.  * is different from the earlier versions, and
  478.  * is more compatable with Gosling EMACS than
  479.  * with ITS EMACS. Bound to "C-X C-W" for writing
  480.  * and ^X^A for appending.
  481.  */
  482.  
  483. PASCAL NEAR filewrite(f, n)
  484.  
  485. int f, n;    /* emacs arguments */
  486.  
  487. {
  488.     register int s;
  489.     char *fname;
  490.  
  491.     if (restflag)        /* don't allow this command if restricted */
  492.         return(resterr());
  493.  
  494.     if ((fname = gtfilename(TEXT144)) == NULL)
  495. /*                     "Write file: " */
  496.         return(FALSE);
  497.     if ((s=writeout(fname, "w")) == TRUE) {
  498.         strcpy(curbp->b_fname, fname);
  499.         curbp->b_flag &= ~BFCHG;
  500.         /* Update mode lines.    */
  501.         upmode();
  502.     }
  503.     return(s);
  504. }
  505.  
  506. PASCAL NEAR fileapp(f, n)    /* append file */
  507.  
  508. int f, n;    /* emacs arguments */
  509.  
  510. {
  511.     register int s;
  512.     char *fname;
  513.  
  514.     if (restflag)        /* don't allow this command if restricted */
  515.         return(resterr());
  516.     if ((fname = gtfilename(TEXT218)) == NULL)
  517. /*                     "Append file: " */
  518.         return(FALSE);
  519.     if ((s=writeout(fname, "a")) == TRUE) {
  520.         curbp->b_flag &= ~BFCHG;
  521.         /* Update mode lines.    */
  522.         upmode();
  523.     }
  524.     return(s);
  525. }
  526.  
  527. /*
  528.  * Save the contents of the current
  529.  * buffer in its associatd file. Do nothing
  530.  * if nothing has changed (this may be a bug, not a
  531.  * feature). Error if there is no remembered file
  532.  * name for the buffer. Bound to "C-X C-S". May
  533.  * get called by "C-Z".
  534.  */
  535. PASCAL NEAR filesave(f, n)
  536.  
  537. int f,n;    /* prefix flag and argument */
  538.  
  539. {
  540.     register int s;
  541.  
  542.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  543.         return(rdonly());    /* we are in read only mode    */
  544.     if ((curbp->b_flag&BFCHG) == 0)     /* Return, no changes.    */
  545.         return(TRUE);
  546.     if (curbp->b_fname[0] == 0) {        /* Must have a name.    */
  547.         mlwrite(TEXT145);
  548. /*                      "No file name" */
  549.         return(FALSE);
  550.     }
  551.  
  552.     /* complain about truncated files */
  553.     if ((curbp->b_flag&BFTRUNC) != 0) {
  554.         if (mlyesno(TEXT146) == FALSE) {
  555. /*                          "Truncated file..write it out" */
  556.             mlwrite(TEXT8);
  557. /*                              "[Aborted]" */
  558.             return(FALSE);
  559.         }
  560.     }
  561.  
  562.     /* complain about narrowed buffers */
  563.     if ((curbp->b_flag&BFNAROW) != 0) {
  564.         if (mlyesno(TEXT147) == FALSE) {
  565. /*                          "Narrowed Buffer..write it out" */
  566.             mlwrite(TEXT8);
  567. /*                              "[Aborted]" */
  568.             return(FALSE);
  569.         }
  570.     }
  571.  
  572.     if ((s=writeout(curbp->b_fname, "w")) == TRUE) {
  573.         curbp->b_flag &= ~BFCHG;
  574.         /* Update mode lines.    */
  575.         upmode();
  576.     }
  577.     return(s);
  578. }
  579.  
  580. /*
  581.  * This function performs the details of file writing. It uses
  582.  * the file management routines in the "fileio.c" package. The
  583.  * number of lines written is displayed. Several errors are
  584.  * posible, and cause writeout to return a FALSE result. When
  585.  * $ssave is TRUE,  the buffer is written out to a temporary
  586.  * file, and then the old file is unlinked and the temporary
  587.  * renamed to the original name.  Before the file is written,
  588.  * a user specifyable routine (in $writehook) can be run.
  589.  */
  590.  
  591. PASCAL NEAR writeout(fn, mode)
  592.  
  593. char *fn;    /* name of file to write current buffer to */
  594. char *mode;    /* mode to open file (w = write a = append) */
  595. {
  596.     register LINE *lp;    /* line to scan while writing */
  597.     register char *sp;    /* temporary string pointer */
  598.     register long nline;    /* number of lines written */
  599.     int status;        /* return status */
  600.     int sflag;        /* are we safe saving? */
  601.     char tname[NSTRING];    /* temporary file name */
  602.     char buf[NSTRING];    /* message buffer */
  603. #if    BSD | FREEBSD | SUN | XENIX | USG | AIX
  604.     struct stat st;        /* we need info about the file permisions */
  605. #endif
  606.  
  607.     /* let a user macro get hold of things...if he wants */
  608.     execkey(&writehook, FALSE, 1);
  609.  
  610.     /* determine if we will use the save method */
  611.     sflag = FALSE;
  612.     if (ssave && fexist(fn) && *mode == 'w')
  613.         sflag = TRUE;
  614.  
  615. #if    CRYPT
  616.     /* set up for file encryption */
  617.     status = resetkey();
  618.     if (status != TRUE)
  619.         return(status);
  620. #endif
  621.  
  622.     /* turn off ALL keyboard translation in case we get a dos error */
  623.     TTkclose();
  624.  
  625.     /* Perform Safe Save..... */
  626.     if (sflag) {
  627.         /* duplicate original file name, and find where to trunc it */
  628.         sp = tname + (makename(tname, fn) - fn) + 1;
  629.         strcpy(tname, fn);
  630.  
  631.         /* create a unique name, using random numbers */
  632.         do {
  633.             *sp = 0;
  634.             strcat(tname, int_asc(ernd() & 0xffff));
  635.         } while(fexist(tname));
  636.  
  637.         /* open the temporary file */
  638. #if     AOSVS
  639.                 status = ffwopen(fn, "w", tname);
  640. #else
  641.         status = ffwopen(tname, "w");
  642. #endif
  643.     } else
  644. #if     AOSVS
  645.                 status = ffwopen(fn, mode, NULL);
  646. #else
  647.         status = ffwopen(fn, mode);
  648. #endif
  649.  
  650.     /* if the open failed.. clean up and abort */
  651.     if (status != FIOSUC) {
  652.         TTkopen();
  653.         return(FALSE);
  654.     }
  655.  
  656.     /* write the current buffer's lines to the open disk file */
  657.     mlwrite(TEXT148);    /* tell us that we're writing */
  658. /*              "[Writing...]" */
  659.     lp = lforw(curbp->b_linep);    /* start at the first line.    */
  660.     nline = 0L;            /* track the Number of lines    */
  661.     while (lp != curbp->b_linep) {
  662.         if ((status = ffputline(&lp->l_text[0], lused(lp))) != FIOSUC)
  663.             break;
  664.         ++nline;
  665.         lp = lforw(lp);
  666.     }
  667.  
  668.  
  669.     /* report on status of file write */
  670.     *buf = 0;
  671.     status |= ffclose();
  672.     if (status == FIOSUC) {
  673.         /* report on success (or lack therof) */
  674.         strcpy(buf, TEXT149);
  675. /*                          "[Wrote " */
  676.         strcat(buf, long_asc(nline));
  677.         strcat(buf, TEXT143);
  678. /*                          " line" */
  679.         if (nline > 1L)
  680.             strcat(buf, "s");
  681.  
  682.         if (sflag) {
  683. #if    BSD | FREEBSD | SUN | XENIX | USG | AIX
  684.             /* get the permisions on the original file */
  685.             stat(fn, &st);
  686. #endif
  687.             /* erase original file */
  688.             /* rename temporary file to original name */
  689.             if (unlink(fn) == 0 && rename(tname, fn) == 0) {
  690. #if    BSD | FREEBSD | SUN | XENIX | USG | AIX
  691.                 chown(fn, (int)st.st_uid, (int)st.st_gid);
  692.                 chmod(fn, (int)st.st_mode);
  693. #else
  694.                 ;
  695. #endif
  696.             } else {
  697.                 strcat(buf, TEXT150);
  698. /*                                          ", saved as " */
  699.                 strcat(buf, tname);
  700.                 status = FIODEL;        /* failed */
  701.             }
  702.         }
  703.         strcat(buf, "]");
  704.         mlwrite(buf);
  705.     }
  706.  
  707.     /* reopen the keyboard, and return our status */
  708.     TTkopen();
  709.     return(status == FIOSUC);
  710. }
  711.  
  712. /*
  713.  * The command allows the user
  714.  * to modify the file name associated with
  715.  * the current buffer. It is like the "f" command
  716.  * in UNIX "ed". The operation is simple; just zap
  717.  * the name in the BUFFER structure, and mark the windows
  718.  * as needing an update. You can type a blank line at the
  719.  * prompt if you wish.
  720.  */
  721.  
  722. PASCAL NEAR filename(f, n)
  723.  
  724. int f,n;    /* prefix flag and argument */
  725.  
  726. {
  727.     register int    s;
  728.     char        fname[NFILEN];
  729.  
  730.     if (restflag)        /* don't allow this command if restricted */
  731.         return(resterr());
  732.     if ((s=FILENAMEREPLY(TEXT151, fname, NFILEN)) == ABORT)
  733. /*                     "Name: " */
  734.         return(s);
  735.     if (s == FALSE)
  736.         strcpy(curbp->b_fname, "");
  737.     else
  738.         strcpy(curbp->b_fname, fname);
  739.     /* Update mode lines.    */
  740.     upmode();
  741.     curbp->b_mode &= ~MDVIEW;      /* no longer read only mode */
  742.     return(TRUE);
  743. }
  744.  
  745. /*
  746.  * Insert file "fname" into the current
  747.  * buffer, Called by insert file command. Return the final
  748.  * status of the read.
  749.  */
  750. PASCAL NEAR ifile(fname)
  751. char    fname[];
  752. {
  753.     register LINE *lp0;
  754.     register LINE *lp1;
  755.     register LINE *lp2;
  756.     register int i;
  757.     register BUFFER *bp;
  758.     register int s;
  759.     register long nline;
  760.     int nbytes;
  761.     int cmark;    /* current mark */
  762.     char mesg[NSTRING];
  763.  
  764.     bp = curbp;                /* Cheap.        */
  765.     bp->b_flag |= BFCHG;            /* we have changed    */
  766.     bp->b_flag &= ~BFINVS;            /* and are not temporary*/
  767.     if ((s=ffropen(fname)) == FIOERR)    /* Hard file open.    */
  768.         goto out;
  769.     if (s == FIOFNF) {            /* File not found.    */
  770.         mlwrite(TEXT152);
  771. /*                      "[No such file]" */
  772.         return(FALSE);
  773.     }
  774.     mlwrite(TEXT153);
  775. /*              "[Inserting file]" */
  776.  
  777. #if    CRYPT
  778.     s = resetkey();
  779.     if (s != TRUE)
  780.         return(s);
  781. #endif
  782.     /* back up a line and save the mark here */
  783.     curwp->w_dotp = lback(curwp->w_dotp);
  784.     curwp->w_doto = 0;
  785.     for (cmark = 0; cmark < NMARKS; cmark++) {
  786.         if (curwp->w_markp[cmark] == lforw(curwp->w_dotp)) {
  787.             curwp->w_markp[cmark] = curwp->w_dotp;
  788.             curwp->w_marko[cmark] = 0;
  789.         }
  790.     }
  791.  
  792.     nline = 0L;
  793.     while ((s=ffgetline(&nbytes)) == FIOSUC) {
  794.         if ((lp1=lalloc(nbytes)) == NULL) {
  795.             s = FIOMEM;        /* Keep message on the    */
  796.             break;            /* display.        */
  797.         }
  798.         lp0 = curwp->w_dotp;  /* line previous to insert */
  799.         lp2 = lp0->l_fp;    /* line after insert */
  800.  
  801.         /* re-link new line between lp0 and lp2 */
  802.         lp2->l_bp = lp1;
  803.         lp0->l_fp = lp1;
  804.         lp1->l_bp = lp0;
  805.         lp1->l_fp = lp2;
  806.  
  807.         /* and advance and write out the current line */
  808.         curwp->w_dotp = lp1;
  809.         for (i=0; i<nbytes; ++i)
  810.             lputc(lp1, i, fline[i]);
  811.         ++nline;
  812.     }
  813.     ffclose();                /* Ignore errors.    */
  814.     for (cmark = 0; cmark < NMARKS; cmark++)
  815.         if (curwp->w_markp[cmark] == lback(curwp->w_dotp))
  816.             curwp->w_markp[cmark] = lforw(curwp->w_markp[cmark]);
  817.  
  818.     strcpy(mesg, "[");
  819.     if (s==FIOERR) {
  820.         strcat(mesg, TEXT141);
  821. /*                           "I/O ERROR, " */
  822.         curbp->b_flag |= BFTRUNC;
  823.     }
  824.     if (s == FIOMEM) {
  825.         strcat(mesg, TEXT142);
  826. /*                           "OUT OF MEMORY, " */
  827.         curbp->b_flag |= BFTRUNC;
  828.     }
  829.     strcat(mesg, TEXT154);
  830. /*                   "Inserted " */
  831.     strcat(mesg, long_asc(nline));
  832.     strcat(mesg, TEXT143);
  833. /*                   " line" */
  834.     if (nline > 1L)
  835.         strcat(mesg, "s");
  836.     strcat(mesg, "]");
  837.     mlwrite(mesg);
  838.  
  839. out:
  840.     /* advance to the next line and mark the window for changes */
  841.     curwp->w_dotp = lforw(curwp->w_dotp);
  842.     curwp->w_flag |= WFHARD | WFMODE;
  843.  
  844.     /* copy window parameters back to the buffer structure */
  845.     curbp->b_dotp = curwp->w_dotp;
  846.     curbp->b_doto = curwp->w_doto;
  847.     for (cmark = 0; cmark < NMARKS; cmark++) {
  848.         curbp->b_markp[cmark] = curwp->w_markp[cmark];
  849.         curbp->b_marko[cmark] = curwp->w_marko[cmark];
  850.     }
  851.     curbp->b_fcol = curwp->w_fcol;
  852.  
  853.     if (s == FIOERR)            /* False if error.    */
  854.         return(FALSE);
  855.     return(TRUE);
  856. }
  857.  
  858. /*    show-files    Bring up a fake buffer and list the
  859.             names of all the files in a given directory
  860. */
  861.  
  862. PASCAL NEAR showfiles(f, n)
  863.  
  864. int f,n;    /* prefix flag and argument */
  865.  
  866. {
  867.     register BUFFER *dirbuf;/* buffer to put file list into */
  868.     char outseq[NSTRING];    /* output buffer for file names */
  869.     char *sp;        /* output ptr for file names */
  870.     char mstring[NSTRING];    /* string to match cmd names to */
  871.     int status;        /* status return */
  872.  
  873.     /* ask what directory mask to search */
  874.     status = mlreply("Directory to show: ", mstring, NSTRING - 1);
  875.     if (status == ABORT)
  876.         return(status);
  877.  
  878.     /* get a buffer for the file list */
  879.     dirbuf = bfind("File List", TRUE, BFINVS);
  880.     if (dirbuf == NULL || bclear(dirbuf) == FALSE) {
  881.         mlwrite("Can not display file list");
  882. /*            "Can not display function list" */
  883.         return(FALSE);
  884.     }
  885.  
  886.     /* let us know this is in progress */
  887.     mlwrite("[Building File List]");
  888.  
  889.     /* get the first file name */
  890.     sp = getffile(mstring);
  891.  
  892.     while (sp) {
  893.  
  894.         /* add a name to the buffer */
  895.         strcpy(outseq, sp);
  896.         if (addline(dirbuf, outseq) != TRUE)
  897.             return(FALSE);
  898.  
  899.         /* and get the next name */
  900.         sp = getnfile();
  901.     }
  902.  
  903.     /* display the list */
  904.     wpopup(dirbuf);
  905.     mlerase();    /* clear the mode line */
  906.     return(TRUE);
  907. }
  908.