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