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