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