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