home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d3xx / d352 / mg.lha / MG / src.LZH / mg / file.c < prev    next >
C/C++ Source or Header  |  1990-05-23  |  14KB  |  542 lines

  1. /*
  2.  * File commands. 
  3.  */
  4. #include    "no_backup.h"
  5. #include    "makebackup.h"
  6.  
  7. #include    "def.h"
  8. #include    "line.h"
  9. #include    "buffer.h"
  10. #include    "window.h"
  11.  
  12. #ifdef    ANSI
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #endif
  16.  
  17. struct buffer  *findbuffer();
  18. VOID 
  19. makename(), upmodes();
  20. static char    *itos();
  21. #ifndef        NO_PROTO
  22. static char    *itos 
  23. PROTO((char *bufp, unsigned int num));
  24. #endif
  25.  
  26. /*
  27.  * insert a file into the current buffer. Real easy - just call the
  28.  * insertfile routine with the file name. 
  29.  */
  30. /* ARGSUSED */
  31. fileinsert(f, n)
  32. {
  33.     register int    s;
  34.     char            fname[NFILEN];
  35.  
  36.     if ((s = ereply("Insert file: ", fname, NFILEN)) != TRUE)
  37.         return (s);
  38.     return insertfile(adjustname(fname), (char *) NULL);
  39.     /* don't set buffer name */
  40. }
  41.  
  42. /*
  43.  * Select a file for editing. Look around to see if you can find the fine in
  44.  * another buffer; if you can find it just switch to the buffer. If you
  45.  * cannot find the file, create a new buffer, read in the text, and switch to
  46.  * the new buffer. 
  47.  */
  48. /* ARGSUSED */
  49. filevisit(f, n)
  50. {
  51.     register struct buffer *bp;
  52.     int             s;
  53.     char            fname[NFILEN];
  54.     char           *adjf;
  55.  
  56.     if ((s = ereply("Find file: ", fname, NFILEN)) != TRUE)
  57.         return s;
  58.     adjf = adjustname(fname);
  59.     if ((bp = findbuffer(adjf)) == NULL)
  60.         return FALSE;
  61.     curbp = bp;
  62.     if (showbuffer(bp, curwp, WFHARD) != TRUE)
  63.         return FALSE;
  64.     if (bp->b_fname[0] == 0)
  65.         return readin(adjf);    /* Read it in.         */
  66.     return TRUE;
  67. }
  68. /*
  69.  * Pop to a file in the other window. Same as last function, just popbuf
  70.  * instead of showbuffer. 
  71.  */
  72. /* ARGSUSED */
  73. poptofile(f, n)
  74. {
  75.     register struct buffer *bp;
  76.     register struct window *wp;
  77.     int             s;
  78.     char            fname[NFILEN];
  79.     char           *adjf;
  80.  
  81.     if ((s = ereply("Find file in other window: ", fname, NFILEN)) != TRUE)
  82.         return s;
  83.     adjf = adjustname(fname);
  84.     if ((bp = findbuffer(adjf)) == NULL)
  85.         return FALSE;
  86.     if ((wp = popbuf(bp)) == NULL)
  87.         return FALSE;
  88.     curbp = bp;
  89.     curwp = wp;
  90.     if (bp->b_fname[0] == 0)
  91.         return readin(adjf);    /* Read it in.         */
  92.     return TRUE;
  93. }
  94.  
  95. /*
  96.  * reads the file being edited back into the buffer, throwing away changes. 
  97.  */
  98. revertbuffer(f, n)
  99. {
  100.     int             s;
  101.     char            prompt[NLINE];
  102.  
  103.     if (curbp->b_fname[0] == '\0') {
  104.         ewprintf("Buffer does not seem to be associated with any file");
  105.         return TRUE;
  106.     }
  107.     strcpy(prompt, "Revert buffer from file ");
  108.     strcat(prompt, curbp->b_fname);
  109.     if ((s = eyesno(prompt)) != TRUE)
  110.         return s;
  111.     curbp->b_flag &= ~BFCHG;/* Don't ask, just chung it */
  112.     readin(curbp->b_fname);
  113. }
  114.  
  115. /*
  116.  * given a file name, either find the buffer it uses, or create a new empty
  117.  * buffer to put it in. 
  118.  */
  119. struct buffer  *
  120. findbuffer(fname)
  121.     char           *fname;
  122. {
  123.     register struct buffer *bp;
  124.     char            bname[NBUFN], *cp;
  125.     unsigned        count = 0;
  126.  
  127.     for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
  128.         if (fncmp(bp->b_fname, fname) == 0)
  129.             return bp;
  130.     }
  131.     makename(bname, fname);    /* New buffer name.     */
  132.     cp = bname + strlen(bname);
  133.     while (bfind(bname, FALSE) != NULL) {
  134.         *cp = '<';    /* add "<count>" to then name     */
  135.         (VOID) strcpy(itos(cp, count += 1) + 1, ">");
  136.     }
  137.     return bfind(bname, TRUE);
  138. }
  139.  
  140. /*
  141.  * Put the decimal representation of num into a buffer.  Hacked to be faster,
  142.  * smaller, and less general. 
  143.  */
  144. static char    *
  145. itos(bufp, num)
  146.     char           *bufp;
  147.     unsigned        num;
  148. {
  149.     if (num >= 10) {
  150.         bufp = itos(bufp, num / 10);
  151.         num %= 10;
  152.     }
  153.     *++bufp = '0' + num;
  154.     return bufp;
  155. }
  156.  
  157. /*
  158.  * Read the file "fname" into the current buffer. Make all of the text in the
  159.  * buffer go away, after checking for unsaved changes. This is called by the
  160.  * "read" command, the "visit" command, and the mainline (for "uemacs file"). 
  161.  */
  162. readin(fname)
  163.     char           *fname;
  164. {
  165.     register int    status;
  166.     register struct window *wp;
  167.  
  168.     if (bclear(curbp) != TRUE)    /* Might be old.     */
  169.         return TRUE;
  170.     status = insertfile(fname, fname);
  171. #ifdef    FOOB
  172.     curbp->b_foob = getfoob(fname);
  173. #endif
  174.     curbp->b_flag &= ~BFCHG;/* No change.         */
  175.     for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
  176.         if (wp->w_bufp == curbp) {
  177.             wp->w_dotp = wp->w_linep = lforw(curbp->b_linep);
  178.             wp->w_doto = 0;
  179.             wp->w_markp = NULL;
  180.             wp->w_marko = 0;
  181.         }
  182.     }
  183.     return status;
  184. }
  185. /*
  186.  * insert a file in the current buffer, after dot. Set mark at the end of the
  187.  * text inserted, point at the beginning. Return a standard status. Print a
  188.  * summary (lines read, error message) out as well. If the BACKUP conditional
  189.  * is set, then this routine also does the read end of backup processing. The
  190.  * BFBAK flag, if set in a buffer, says that a backup should be taken. It is
  191.  * set when a file is read in, but not on a new file (you don't need to make
  192.  * a backup copy of nothing). 
  193.  */
  194. insertfile(fname, newname)
  195.     char            fname[], newname[];
  196. {
  197.     register struct line *lp1;
  198.     register struct line *lp2;
  199.     register struct window *wp;
  200.     int             nbytes;
  201.     struct line    *olp;    /* Line we started at */
  202.     int             opos;    /* and offset into it */
  203.     int             s, nline;
  204.     struct buffer  *bp;
  205.     char            line[NLINE];
  206.  
  207.     bp = curbp;        /* Cheap.         */
  208.     if (newname != (char *) NULL)
  209.         (VOID) strcpy(bp->b_fname, newname);
  210.     if ((s = ffropen(fname)) == FIOERR)    /* Hard file open.     */
  211.         goto out;
  212.     if (s == FIOFNF) {    /* File not found.     */
  213.         if (newname != NULL)
  214.             ewprintf("(New file)");
  215.         else
  216.             ewprintf("(File not found)");
  217.         goto out;
  218.     }
  219.     opos = curwp->w_doto;
  220.     /* Open a new line, at point, and start inserting after it */
  221.     (VOID) lnewline();
  222.     olp = lback(curwp->w_dotp);
  223.     if (olp == curbp->b_linep) {
  224.         /* if at end of buffer, create a line to insert before */
  225.         (VOID) lnewline();
  226.         curwp->w_dotp = lback(curwp->w_dotp);
  227.     }
  228.     nline = 0;        /* Don't count fake line at end */
  229.     while ((s = ffgetline(line, NLINE, &nbytes)) != FIOERR) {
  230.         switch (s) {
  231.         case FIOSUC:
  232.             ++nline;
  233.             /* and continue */
  234.         case FIOEOF:    /* the last line of the file         */
  235.             if ((lp1 = lalloc(nbytes)) == NULL) {
  236.                 s = FIOERR;    /* Keep message on the     */
  237.                 goto endoffile;    /* display.         */
  238.             }
  239.             bcopy(line, <ext(lp1)[0], nbytes);
  240.     lineread:    lp2 = lback(curwp->w_dotp);
  241.             lp2->l_fp = lp1;
  242.             lp1->l_fp = curwp->w_dotp;
  243.             lp1->l_bp = lp2;
  244.             curwp->w_dotp->l_bp = lp1;
  245.             if (s == FIOEOF)
  246.                 goto endoffile;
  247.             break;
  248.         case FIOLONG:{    /* a line to long to fit in our buffer     */
  249.                 char           *cp;
  250.                 char           *cp2 = 0;    /* For lint */
  251.                 int             i;
  252.  
  253.                 nbytes = 0;
  254.                 for (;;) {
  255.                     if ((cp = (char *) malloc((unsigned) (nbytes + NLINE))) == NULL) {
  256.                         ewprintf("Could not allocate %d bytes",
  257.                              nbytes + NLINE);
  258.                         s = FIOERR;
  259.                         if (nbytes)
  260.                             free(cp2);
  261.                         goto endoffile;
  262.                     }
  263.                     if (nbytes) {
  264.                         bcopy(cp2, cp, nbytes);
  265.                         free(cp2);
  266.                     }
  267.                     bcopy(line, cp + nbytes, NLINE);
  268.                     nbytes += NLINE;
  269.                     switch (s = ffgetline(line, NLINE, &i)) {
  270.                     case FIOERR:
  271.                         free(cp);
  272.                         goto endoffile;
  273.                     case FIOLONG:
  274.                         cp2 = cp;
  275.                         break;
  276.                     case FIOEOF:
  277.                     case FIOSUC:
  278.                         if ((lp1 = lalloc(nbytes + i)) == NULL) {
  279.                             s = FIOERR;
  280.                             free(cp);
  281.                             goto endoffile;
  282.                         }
  283.                         bcopy(cp, <ext(lp1)[0], nbytes);
  284.                         bcopy(line, <ext(lp1)[nbytes], i);
  285.                         goto lineread;
  286.                     }
  287.                 }
  288.             }
  289.         default:
  290.             ewprintf("Unknown code %d reading file", s);
  291.             s = FIOERR;
  292.             break;
  293.         }
  294.     }
  295. endoffile:
  296.     (VOID) ffclose();    /* Ignore errors.     */
  297.     if (s == FIOEOF) {    /* Don't zap an error.     */
  298.         if (nline == 1)
  299.             ewprintf("(Read 1 line)");
  300.         else
  301.             ewprintf("(Read %d lines)", nline);
  302.     }
  303.     /* Set mark at the end of the text */
  304.     curwp->w_dotp = curwp->w_markp = lback(curwp->w_dotp);
  305.     curwp->w_marko = llength(curwp->w_markp);
  306.     (VOID) ldelnewline();
  307.     curwp->w_dotp = olp;
  308.     curwp->w_doto = opos;
  309.     if (olp == curbp->b_linep)
  310.         curwp->w_dotp = lforw(olp);
  311. #ifndef NO_BACKUP
  312.     if (newname != NULL)
  313.         bp->b_flag |= BFCHG | BFBAK;    /* Need a backup.     */
  314.     else
  315.         bp->b_flag |= BFCHG;
  316. #else
  317.     bp->b_flag |= BFCHG;
  318. #endif
  319.     /*
  320.      * if the insert was at the end of buffer, set lp1 to the end of
  321.      * buffer line, and lp2 to the beginning of the newly inserted text.
  322.      * (Otherwise lp2 is set to NULL.)  This is used below to set
  323.      * pointers in other windows correctly if they are also at the end of
  324.      * buffer. 
  325.      */
  326.     lp1 = bp->b_linep;
  327.     if (curwp->w_markp == lp1) {
  328.         lp2 = curwp->w_dotp;
  329.     } else {
  330.         (VOID) ldelnewline();    /* delete extranious newline */
  331. out:        lp2 = NULL;
  332.     }
  333.     for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
  334.         if (wp->w_bufp == curbp) {
  335.             wp->w_flag |= WFMODE | WFEDIT;
  336.             if (wp != curwp && lp2 != NULL) {
  337.                 if (wp->w_dotp == lp1)
  338.                     wp->w_dotp = lp2;
  339.                 if (wp->w_markp == lp1)
  340.                     wp->w_markp = lp2;
  341.                 if (wp->w_linep == lp1)
  342.                     wp->w_linep = lp2;
  343.             }
  344.         }
  345.     }
  346.     return s != FIOERR;    /* False if error.     */
  347. }
  348.  
  349. /*
  350.  * Take a file name, and from it fabricate a buffer name. This routine knows
  351.  * about the syntax of file names on the target system. BDC1        left
  352.  * scan delimiter. BDC2        optional second left scan delimiter. BDC3
  353.  * ptional right scan delimiter. 
  354.  */
  355. VOID
  356. makename(bname, fname)
  357.     char            bname[];
  358. char            fname[];
  359. {
  360.     register char  *cp1;
  361.     register char  *cp2;
  362.  
  363.     cp1 = &fname[0];
  364.     while (*cp1 != 0)
  365.         ++cp1;
  366.     --cp1;            /* insure at least 1 character ! */
  367. #ifdef    BDC2
  368.     while (cp1 != &fname[0] && cp1[-1] != BDC1 && cp1[-1] != BDC2)
  369.         --cp1;
  370. #else
  371.     while (cp1 != &fname[0] && cp1[-1] != BDC1)
  372.         --cp1;
  373. #endif
  374.     cp2 = &bname[0];
  375. #ifdef    BDC3
  376.     while (cp2 != &bname[NBUFN - 1] && *cp1 != 0 && *cp1 != BDC3)
  377.         *cp2++ = *cp1++;
  378. #else
  379.     while (cp2 != &bname[NBUFN - 1] && *cp1 != 0)
  380.         *cp2++ = *cp1++;
  381. #endif
  382.     *cp2 = 0;
  383. }
  384.  
  385. /*
  386.  * Ask for a file name, and write the contents of the current buffer to that
  387.  * file. Update the remembered file name and clear the buffer changed flag.
  388.  * This handling of file names is different from the earlier versions, and is
  389.  * more compatable with Gosling EMACS than with ITS EMACS. 
  390.  */
  391. /* ARGSUSED */
  392. filewrite(f, n)
  393. {
  394.     register int    s, count = 0;
  395.     char            fname[NFILEN], bname[NBUFN];
  396.     register char  *adjfname, *cp;
  397.  
  398.     if ((s = ereply("Write file: ", fname, NFILEN)) != TRUE)
  399.         return (s);
  400.     adjfname = adjustname(fname);
  401.     if ((s = writeout(curbp, adjfname)) == TRUE) {
  402.         (VOID) strcpy(curbp->b_fname, adjfname);
  403.         makename(bname, fname);
  404.         cp = bname + strlen(bname);
  405.         while (bfind(bname, FALSE) != NULL) {
  406.             *cp = '<';
  407.             strcpy(itos(cp, count += 1) + 1, ">");
  408.         }
  409.         if ((cp = (char *) malloc(strlen(bname) + 1)) == NULL)
  410.             ewprintf("Couldn't get %d bytes", strlen(bname) + 1);
  411.         else {
  412.             free(curbp->b_bname);
  413.             strcpy(cp, bname);
  414.             curbp->b_bname = cp;
  415.         }
  416.  
  417. #ifndef NO_BACKUP
  418.         curbp->b_flag &= ~(BFBAK | BFCHG);
  419. #else
  420.         curbp->b_flag &= ~BFCHG;
  421. #endif
  422.         upmodes(curbp);
  423.     }
  424.     return s;
  425. }
  426.  
  427. /*
  428.  * Save the contents of the current buffer back into its associated file. 
  429.  */
  430. #ifndef NO_BACKUP
  431. static int      makebackup = MAKEBACKUP;
  432. #endif
  433.  
  434. /* ARGSUSED */
  435. filesave(f, n)
  436. {
  437.     return buffsave(curbp);
  438. }
  439.  
  440. /*
  441.  * Save the contents of the buffer argument into its associated file. Do
  442.  * nothing if there have been no changes (is this a bug, or a feature). Error
  443.  * if there is no remembered file name. If this is the first write since the
  444.  * read or visit, then a backup copy of the file is made. Allow user to
  445.  * select whether or not to make backup files by looking at the value of
  446.  * makebackup. 
  447.  */
  448. buffsave(bp)
  449.     struct buffer  *bp;
  450. {
  451.     register int    s;
  452.  
  453.     if ((bp->b_flag & BFCHG) == 0) {    /* Return, no changes.     */
  454.         ewprintf("(No changes need to be saved)");
  455.         return TRUE;
  456.     }
  457.     if (bp->b_fname[0] == '\0') {    /* Must have a name.     */
  458.         ewprintf("No file name");
  459.         return (FALSE);
  460.     }
  461. #ifndef NO_BACKUP
  462.     if (makebackup && (bp->b_flag & BFBAK)) {
  463.         s = fbackupfile(bp->b_fname);
  464.         if (s == ABORT)    /* Hard error.         */
  465.             return FALSE;
  466.         if (s == FALSE    /* Softer error.     */
  467.             && (s = eyesno("Backup error, save anyway")) != TRUE)
  468.             return s;
  469.     }
  470. #endif
  471.     if ((s = writeout(bp, bp->b_fname)) == TRUE) {
  472. #ifndef NO_BACKUP
  473.         bp->b_flag &= ~(BFCHG | BFBAK);
  474. #else
  475.         bp->b_flag &= ~BFCHG;
  476. #endif
  477.         upmodes(bp);
  478.     }
  479.     return s;
  480. }
  481.  
  482. #ifndef NO_BACKUP
  483. /*
  484.  * Since we don't have variables (we probably should) this is a command
  485.  * processor for changing the value of the make backup flag.  If no argument
  486.  * is given, sets makebackup to true, so backups are made.  If an argument is
  487.  * given, no backup files are made when saving a new version of a file. Only
  488.  * used when BACKUP is #defined. 
  489.  */
  490. /* ARGSUSED */
  491. makebkfile(f, n)
  492. {
  493.     if (f & FFARG)
  494.         makebackup = n > 0;
  495.     else
  496.         makebackup = !makebackup;
  497.     ewprintf("Backup files %sabled", makebackup ? "en" : "dis");
  498.     return TRUE;
  499. }
  500. #endif
  501.  
  502. /*
  503.  * This function performs the details of file writing; writing the file in
  504.  * buffer bp to file fn. Uses the file management routines in the "fileio.c"
  505.  * package. Most of the grief is checking of some sort. 
  506.  */
  507. writeout(bp, fn)
  508.     register struct buffer *bp;
  509.     char           *fn;
  510. {
  511.     register int    s;
  512.  
  513.     if ((s = ffwopen(fn)) != FIOSUC)    /* Open writes message. */
  514.         return (FALSE);
  515.     s = ffputbuf(bp);
  516.     if (s == FIOSUC) {    /* No write error.     */
  517.         s = ffclose();
  518.         if (s == FIOSUC)
  519.             ewprintf("Wrote %s", fn);
  520.     } else            /* Ignore close error     */
  521.         (VOID) ffclose();    /* if a write error.     */
  522. #ifdef    FOOB
  523.     putfoob(fn, bp->b_foob);
  524. #endif
  525.     return s == FIOSUC;
  526. }
  527.  
  528. /*
  529.  * Tag all windows for bp (all windows if bp NULL) as needing their mode line
  530.  * updated. 
  531.  */
  532. VOID
  533. upmodes(bp)
  534.     register struct buffer *bp;
  535. {
  536.     register struct window *wp;
  537.  
  538.     for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
  539.         if (bp == NULL || wp->w_bufp == bp)
  540.             wp->w_flag |= WFMODE;
  541. }
  542.