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