source: trunk/minix/commands/elle/eefile.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 19.9 KB
Line 
1/* ELLE - Copyright 1982, 1984, 1987 by Ken Harrenstien, SRI International
2 * This software is quasi-public; it may be used freely with
3 * like software, but may NOT be sold or made part of licensed
4 * products without permission of the author.
5 */
6/*
7 * EEFILE File reading/writing functions
8 */
9
10#include "elle.h"
11#include <stdio.h> /* Use "standard" I/O package for writing */
12#ifndef BUFSIZ
13#define BUFSIZ BUFSIZE /* Some places use wrong name in stdio.h */
14#endif /*-BUFSIZ*/
15#if V6
16 struct stat {
17 int st_dev;
18 int st_ino;
19 char *st_mode;
20 char st_nlink;
21 char st_uid;
22 char st_gid;
23 char st_size0;
24 char st_size;
25 int st_addr[8];
26 long st_atime;
27 long st_mtime;
28 };
29#define ENOENT (2) /* Syscall error - no such file or dir */
30#else
31#include <errno.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#endif /*-V6*/
35
36#if TOPS20
37#include <sys/file.h> /* Get open mode bits */
38#endif
39
40extern char *strerror(); /* Return error string for errno */
41extern struct buffer *make_buf(), *find_buf();
42
43char *fncons(), *last_fname();
44
45int hoardfd = -1; /* Retain a FD here to ensure we can always write */
46
47/* Flags for iwritfile() */
48#define WF_SMASK 07 /* Source Mask */
49#define WF_SBUFF 0 /* source: Buffer */
50#define WF_SREG 1 /* source: Region */
51#define WF_SKILL 2 /* source: Last Kill */
52#define WF_ASK 010 /* Ask for filename to write to */
53static int iwritfile();
54
55
56/* EFUN: "Find File" */
57/* Ask user for a filename and do a find_file for it.
58 * If buffer exists for that filename, select that buffer.
59 * Else create a buffer for it, and read in the file if it exists.
60 */
61f_ffile()
62{ int find_file();
63#if IMAGEN
64 hack_file("Visit file: ", find_file);
65#else
66 hack_file("Find file: ", find_file);
67#endif /*-IMAGEN*/
68}
69
70/* EFUN: "Read File" */
71/* User read_file function, asks user for a filename and reads it
72 */
73f_rfile() { u_r_file("Read file: "); }
74
75/* EFUN: "Visit File" */
76/* Same as Read File, with different prompt.
77 */
78f_vfile() { u_r_file("Visit file: "); }
79
80
81u_r_file(prompt)
82char *prompt;
83{ register char *f_name;
84 register struct buffer *b;
85
86 if((f_name = ask (prompt))==0) /* prompt user for filename */
87 return; /* user punted... */
88 b = cur_buf;
89 if(*f_name == '\0')
90 { if (b -> b_fn == 0)
91 ding("No default file name.");
92 else read_file(b -> b_fn);
93 }
94 else read_file(f_name);
95 chkfree(f_name);
96}
97
98/* EFUN: "Insert File" */
99/* Asks for a filename and inserts the file at current location.
100 * Point is left at beginning, and the mark at the end.
101 */
102f_ifile()
103{ int ins_file();
104 hack_file("Insert file: ", ins_file);
105}
106
107
108/* EFUN: "Save File" */
109/* Save current buffer to its default file name
110 */
111f_sfile()
112{ if(cur_buf->b_flags&B_MODIFIED)
113 return(iwritfile(WF_SBUFF)); /* Write buffer, don't ask */
114 else
115 { saynow("(No changes need to be written)");
116 return(1);
117 }
118}
119
120#if FX_SAVEFILES || FX_WFEXIT
121/* EFUN: "Save All Files" */
122/* F_SAVEFILES - Offer to save all modified files.
123 * With argument, doesn't ask.
124 * Returns 0 if user aborts or if an error happened.
125 */
126f_savefiles()
127{ register struct buffer *b, *savb;
128 register int res = 1;
129 char *ans;
130
131 savb = cur_buf;
132 for (b = buf_head; res && b; b = b->b_next)
133 if ((b->b_flags & B_MODIFIED) && b->b_fn)
134 { if(exp_p) /* If arg, */
135 { chg_buf(b); /* just save, don't ask */
136 res = f_sfile();
137 continue; /* Check next buffer */
138 }
139 /* Ask user whether to save */
140 ans = ask("Buffer %s contains changes - write out? ",
141 b->b_name);
142 if(ans == 0)
143 { res = 0; /* User aborted */
144 break;
145 }
146 if (upcase(*ans) == 'Y')
147 { chg_buf(b);
148 res = f_sfile(); /* Save File */
149 }
150 chkfree(ans);
151 }
152 chg_buf(savb);
153 return(res);
154}
155#endif /*FX_SAVEFILES||FX_WFEXIT*/
156
157
158/* EFUN: "Write File" */
159/* Write out the buffer to an output file.
160 */
161f_wfile()
162{ return iwritfile(WF_ASK|WF_SBUFF);
163}
164
165/* EFUN: "Write Region" */
166/* Write region out to a file
167 */
168f_wreg()
169{ return iwritfile(WF_ASK|WF_SREG); /* Ask, write region */
170}
171
172#if FX_WLASTKILL
173/* EFUN: "Write Last Kill" (not EMACS) */
174/* Write current kill buffer out to a file.
175** This is mainly for MINIX.
176*/
177extern int kill_ptr; /* From EEF3 */
178extern SBSTR *kill_ring[];
179
180f_wlastkill()
181{ return iwritfile(WF_ASK|WF_SKILL);
182}
183#endif
184
185
186
187/* HACK_FILE - intermediate subroutine
188 */
189hack_file(prompt, rtn)
190char *prompt;
191int (*rtn)();
192{ register char *f_name;
193
194 if((f_name = ask(prompt)) == 0)
195 return;
196 if (*f_name != '\0') /* Check for null answer */
197 (*rtn)(f_name);
198 chkfree(f_name);
199}
200
201/* FIND_FILE(f_name)
202 * If there is a buffer whose fn == f_name, select that buffer.
203 * Else create one with name of the last section of f_name and
204 * read the file into that buffer.
205 */
206find_file(f_name)
207register char *f_name;
208{ register struct buffer *b;
209 register char *ans;
210 char *lastn;
211 int fd;
212
213#if IMAGEN
214 char real_name[128]; /* File name w/ expanded ~ and $ */
215 expand_file(real_name, f_name);
216 f_name = real_name;
217#endif /*IMAGEN*/
218
219 for (b = buf_head; b; b = b -> b_next)
220 if(b->b_fn && (strcmp (b -> b_fn, f_name) == 0))
221 break;
222 if (b) /* if we found one */
223 { sel_buf(b); /* go there */
224 return; /* and we are done */
225 }
226 if((fd = open(f_name,0)) < 0) /* See if file exists */
227 { if(errno != ENOENT) /* No, check reason */
228 { ferr_ropn(); /* Strange error, complain */
229 return; /* and do nothing else. */
230 }
231 }
232 else close(fd); /* Found! Close FD, since the */
233 /* read_file rtn will re-open. */
234
235 lastn = last_fname(f_name); /* Find buffer name */
236 b = find_buf(lastn); /* Is there a buffer of that name? */
237 if (b && (ex_blen(b) || b->b_fn))
238 { ans = ask("Buffer %s contains %s, which buffer shall I use? ",
239 b -> b_name, b->b_fn ? b->b_fn : "something");
240 if(ans == 0) return; /* Aborted */
241 if (*ans != '\0') /* if null answer, use b */
242 b = make_buf(ans); /* else use ans */
243 chkfree(ans);
244 }
245 else
246 b = make_buf(lastn);
247 sel_buf(b);
248 if(fd < 0) /* If file doesn't exist, */
249 { set_fn(f_name); /* just say "new" and set filename */
250 return; /* and return right away. */
251 }
252 if (read_file(f_name)==0) /* File exists, read it in! */
253 { if(b->b_fn) /* Failed... if filename, */
254 { chkfree(b->b_fn); /* flush the filename. */
255 b->b_fn = 0;
256 }
257 }
258}
259
260/* READ_FILE(f_name)
261 * Reads file into current buffer, flushing any
262 * previous contents (if buffer modified, will ask about saving)
263 * Returns 0 if failed.
264 */
265read_file(f_name)
266char *f_name;
267{
268#if IMAGEN
269 struct stat s;
270 char real_name[128]; /* File name w/ expanded ~ and $ */
271#endif /*IMAGEN*/
272
273 if(!zap_buffer()) /* Flush the whole buffer */
274 return; /* Unless user aborts */
275#if IMAGEN
276 expand_file(real_name, f_name);
277 f_name = real_name; /* Hack, hack! */
278#endif /*IMAGEN*/
279 set_fn(f_name);
280 if (ins_file(f_name)==0)
281 return 0;
282 f_bufnotmod(); /* Say not modified now */
283#if IMAGEN
284 stat(f_name, &s); /* Get file stat */
285 cur_buf->b_mtime = s.st_mtime; /* and pick out last-modified time */
286#endif /*IMAGEN*/
287 return 1;
288}
289
290/* INS_FILE(f_name)
291 * Inserts file named f_name into current buffer at current point
292 * Point is not moved; mark is set to end of inserted stuff.
293 * Returns 0 if failed, 1 if won.
294 */
295ins_file (f_name)
296char *f_name;
297{ register int ifd;
298 register SBSTR *sd;
299 chroff insdot; /* To check for range of mods */
300
301#if IMAGEN
302 char real_name[128]; /* File name w/ expanded ~ and $ */
303 expand_file(real_name, f_name);
304 f_name = real_name;
305#endif /*IMAGEN*/
306#if !(TOPS20)
307 if((ifd = open(f_name,0)) < 0)
308#else
309 if((ifd = open(f_name,O_RDONLY|O_UNCONVERTED)) < 0)
310#endif /*TOPS20*/
311 { ferr_ropn(); /* Can't open, complain */
312 return 0; /* no redisplay */
313 }
314 errno = 0;
315 if((sd = sb_fduse(ifd)) == 0)
316 { if (ifd >= SB_NFILES)
317 dingtoo(" Cannot read - too many internal files");
318 else if (errno)
319 ferr_ropn();
320 else errbarf("SB rtn cannot read file?");
321 close(ifd);
322 return 0;
323 }
324 sb_sins(cur_buf,sd);
325 insdot = e_dot();
326 f_setmark(); /* Set mark at current ptr */
327 if(cur_dot != insdot) /* If pointer was advanced, */
328 buf_tmat(insdot); /* then stuff was inserted */
329 e_gocur();
330 return 1;
331}
332
333ferr_ropn() { ferr(" Cannot read"); }
334ferr_wopn() { ferr(" Cannot write"); }
335ferr(str)
336char *str;
337{ saytoo(str);
338 saytoo(" - ");
339 dingtoo(strerror(errno));
340}
341
342
343
344/* IWRITFILE - auxiliary for writing files.
345** Returns 1 if write successful, 0 if not.
346*/
347static int
348iwritfile(flags)
349int flags;
350{ register struct buffer *b;
351 register char *o_name; /* output file name */
352 int styp = flags & WF_SMASK; /* Source type, one of WF_Sxxx */
353 char *prompt;
354#ifdef STDWRITE
355 register FILE *o_file; /* output file pointer */
356 char obuf[BUFSIZ];
357 chroff dotcnt;
358#endif /*STDWRITE*/
359 int ofd; /* output file FD */
360 SBSTR *sd;
361 char fname[FNAMSIZ]; /* To avoid chkfree hassle */
362 char newname[FNAMSIZ]; /* for robustness */
363 char oldname[FNAMSIZ]; /* ditto */
364 int res;
365 struct stat statb;
366 int statres;
367#if IMAGEN
368 struct stat s;
369 char real_name[128]; /* File name w/ expanded ~ and $ */
370#endif /*IMAGEN*/
371 res = 1; /* Let's keep track of success */
372
373 /* Check for existence of source, and set prompt string */
374 switch(styp)
375 {
376 case WF_SBUFF:
377 prompt = "Write File: ";
378 break;
379 case WF_SREG:
380 if(!mark_p)
381 { dingtoo(" No Mark!");
382 return(0);
383 }
384 prompt = "Write Region: ";
385 break;
386#if FX_WLASTKILL
387 case WF_SKILL:
388 if(!kill_ring[kill_ptr])
389 { dingtoo("No killed stuff");
390 return(0);
391 }
392 prompt = "Write Last Kill: ";
393 break;
394#endif
395 default: /* Internal error */
396 errbarf("bad iwritfile arg");
397 return 0;
398 }
399
400 if (flags&WF_ASK)
401 { if((o_name = ask(prompt))==0)
402 return(0); /* User punted. */
403 strcpy(&fname[0], o_name); /* Copy filename onto stack */
404 chkfree(o_name);
405 }
406 o_name = &fname[0];
407 b = cur_buf;
408 if (!(flags&WF_ASK) || (*o_name == '\0'))
409 { if (b->b_fn == 0)
410 { ding("No default file name.");
411 return(0);
412 }
413 strcpy(o_name, b->b_fn);
414 }
415
416#if IMAGEN
417 expand_file(real_name, o_name);
418 o_name = real_name; /* Hack, hack */
419#endif /*IMAGEN*/
420
421 statres = stat(o_name,&statb); /* Get old file's info (if any) */
422
423#if IMAGEN
424 /* Now, make sure someone hasn't written the file behind our backs */
425 if ((styp==WF_SBUFF) && !(flags&WF_ASK)
426 && b->b_fn && stat(b->b_fn, &s) >= 0)
427 if (s.st_mtime != b->b_mtime)
428 { char *ans;
429 ans = ask("Since you last read \"%s\", someone has changed it.\nDo you want to write it anyway (NOT RECOMMENDED!)? ",
430 b->b_fn);
431 if (ans == 0 || upcase(*ans) != 'Y')
432 {
433 ding("I suggest you either read it again, or\nwrite it to a temporary file, and merge the two versions manually.");
434 if (ans) chkfree(ans);
435 return(0);
436 }
437 if (ans) chkfree(ans);
438 }
439#endif /*IMAGEN*/
440
441 /* Try to get around major UNIX screw of smashing files.
442 * This still isn't perfect (screws up with long filenames) but...
443 * 1. Write out to <newname>
444 * 2. Rename <name> to <oldname> (may have to delete existing <oldname>)
445 * 3. Rename <newname> to <name>.
446 */
447 fncons(oldname,ev_fno1,o_name,ev_fno2); /* Set up "old" filename */
448 fncons(newname,ev_fnn1,o_name,ev_fnn2); /* Set up "new" filename */
449 unlink(newname); /* Ensure we don't clobber */
450 unhoard(); /* Now give up saved FD */
451#if !(V6) /* Standard V6 doesn't have access call */
452 if(statres >= 0) /* If file exists, */
453 { if(access(o_name, 2) != 0) /* check for write access */
454 { ferr_wopn();
455 res = 0; /* Failure */
456 goto wdone;
457 }
458 }
459#endif /*-V6*/
460#ifdef STDWRITE
461 if(flags&WF_ASK)
462 { if((o_file = fopen(newname, "w")) ==0) /* Create new output file */
463 { ferr_wopn();
464 res = 0; /* Failure */
465 goto wdone;
466 }
467 setbuf(o_file,obuf); /* Ensure always have buffer */
468 }
469 else /* New stuff */
470#endif /*STDWRITE*/
471 {
472#if !(TOPS20)
473 if((ofd = creat(newname,ev_filmod)) < 0)
474#else
475 if((ofd = open(newname,O_WRONLY|O_UNCONVERTED)) < 0)
476#endif /*TOPS20*/
477 { ferr_wopn();
478 res = 0; /* Failure */
479 goto wdone;
480 }
481 }
482 if (styp==WF_SBUFF)
483 set_fn(o_name); /* Won, so set default fn for buff */
484#if IMAGEN
485 saynow("Writing ");
486 switch(styp)
487 { case WF_SBUFF: saytoo(b->b_fn); break;
488 case WF_SREG: saytoo("region"); break;
489#if FX_WLASTKILL
490 case WF_SKILL: saytoo("last kill"); break;
491#endif
492 }
493 sayntoo("...");
494#else
495 saynow("Writing...");
496#endif /*-IMAGEN*/
497
498#if !(TOPS20) /* T20 does all this already */
499 if(statres >= 0) /* Get old file's modes */
500 { /* Try to duplicate them */
501 /* Do chmod first since after changing owner we may not
502 ** have permission to change mode, at least on V6.
503 */
504 chmod(newname,statb.st_mode & 07777);
505#if V6
506 chown(newname, (statb.st_gid<<8)|(statb.st_uid&0377));
507#else
508 chown(newname,statb.st_uid,statb.st_gid);
509#endif /*-V6*/
510 }
511#if V6
512 /* If no old file existed, and we are a V6 system, try to set
513 * the modes explicitly. On V7 we're OK because the user can
514 * diddle "umask" to get whatever is desired.
515 * On TOPS-20 of course everything is all peachy.
516 */
517 else chmod(newname, ev_filmod);
518#endif /*V6*/
519#endif /*TOPS20*/
520
521
522#ifdef STDWRITE
523 if(flags&WF_ASK)
524 { switch(styp)
525 {
526 case WF_SBUFF:
527 dotcnt = e_blen();
528 e_gobob();
529 break;
530 case WF_SREG:
531 if((dotcnt = mark_dot - cur_dot) < 0)
532 { e_goff(dotcnt);
533 dotcnt = -dotcnt;
534 }
535 else e_gocur();
536 break;
537 /* WF_SKILL not implemented here */
538 }
539 while(--dotcnt >= 0)
540 putc(sb_getc(((SBBUF *)b)), o_file);
541 e_gocur();
542 fflush(o_file); /* Force everything out */
543 res = ferror(o_file); /* Save result of stuff */
544 fclose(o_file); /* Now flush FD */
545 }
546 else /* New stuff */
547#endif /*STDWRITE*/
548 {
549 switch(styp)
550 {
551 case WF_SBUFF:
552 res = sb_fsave((SBBUF *)b, ofd);
553 break;
554 case WF_SREG:
555 e_gocur();
556 sd = e_copyn((chroff)(mark_dot - cur_dot));
557 res = sbx_aout(sd, 2, ofd);
558 sbs_del(sd);
559 break;
560#if FX_WLASTKILL
561 case WF_SKILL:
562 res = sbx_aout(kill_ring[kill_ptr], 2, ofd);
563 break;
564#endif
565 }
566 close(ofd);
567 }
568 if(errno = res)
569 { ferr(" Output error");
570 res = 0; /* Failure */
571 goto wdone;
572 }
573 else
574 res = 1; /* Success so far */
575 if(styp == WF_SBUFF)
576 f_bufnotmod(); /* Reset "buffer modified" flag */
577
578 /* Here we effect the screw-prevention steps explained earlier. */
579 /* TOPS-20, with generation numbers, need not worry about this. */
580#if TOPS20
581 saynow("Written");
582
583#else /*-TOPS20*/
584#if IMAGEN /* KLH -- This conditional bracketting is prone to lossage */
585 /* Only create the .BAK file once per editing session!! */
586 if ((styp==WF_SBUFF) || !(b->b_flags & B_BACKEDUP))
587 { if (styp==WF_SBUFF)
588 b->b_flags |= B_BACKEDUP;
589#endif /*IMAGEN*/
590 unlink(oldname); /* remove any existing "old" file */
591 if(link(o_name,oldname) == 0) /* Rename current to "old" */
592 unlink(o_name);
593 /* Here is the critical point... if we stop here, there is no
594 * longer any file with the appropriate filename!!!
595 */
596#if IMAGEN
597 }
598 else
599 unlink(o_name);
600#endif /*IMAGEN*/
601 if(link(newname,o_name) == 0) /* Rename "new" to current */
602 { unlink(newname);
603#if IMAGEN
604 sayntoo("OK");
605#else
606 saynow("Written");
607#endif /*-IMAGEN*/
608 }
609 else
610 { dingtoo("rename error!");
611 res = 0;
612 }
613#endif /*-TOPS20*/
614
615#if IMAGEN
616 /* Update the last-modified time for the file in this buffer */
617 if ((styp == WF_SBUFF) && b->b_fn)
618 { stat(b->b_fn, &s);
619 b->b_mtime = s.st_mtime;
620 }
621#endif /*IMAGEN*/
622
623wdone:
624 hoard(); /* Get back a retained FD */
625 return(res);
626}
627
628
629/* FNCONS(dest,pre,f_name,post)
630 * Specialized routine to cons up a filename string into "dest",
631 * given prefix and postfix strings to be added onto last component of
632 * filename.
633 */
634char *
635fncons(dest, pre, f_name, post)
636char *dest,*pre,*f_name,*post;
637{ register char *cp, *cp2;
638 char *last_fname();
639
640 cp = dest;
641 *cp = 0; /* Make dest string null initially */
642 cp2 = last_fname(f_name); /* Get pointer to beg of last name */
643 strncat(cp,f_name,cp2-f_name); /* Copy first part of filename */
644 if(pre) strcat(cp, pre); /* If prefix exists, add it on */
645 cp = last_fname(cp); /* Recheck in case levels added */
646 strcat(cp, cp2); /* Now add last name */
647 if(cp2 = post) /* If there's a postfix, must check */
648 { cp[FNAMELEN-strlen(cp2)] = 0; /* and cut dest so postfix */
649 strcat(cp, cp2); /* will fit on end. */
650 }
651 return(dest);
652}
653
654/* LAST_FNAME(string)
655 * Get the last component of a file name. Returns pointer to
656 * start of component; does NOT copy string!
657 */
658char *
659last_fname(f_name)
660char *f_name;
661{ register char *cp, *p;
662 register int c;
663
664 p = f_name; /* pointer to last slash */
665 cp = p;
666 while(c = *cp++)
667 if(c == '/')
668 p = cp; /* point to after the slash */
669 return(p);
670}
671
672/* SET_FN(string)
673 * Set the default filename for current buffer to "string".
674 */
675set_fn (string)
676char *string;
677{ register struct buffer *b;
678 register char *str;
679#if IMAGEN
680 register char *cp;
681 register int len;
682#endif /*IMAGEN*/
683 char *strdup();
684
685 b = cur_buf;
686 str = strdup(string); /* Copy now in case copying self */
687 if(b->b_fn)
688 chkfree(b->b_fn);
689 b -> b_fn = str;
690#if IMAGEN
691 /* Do mode determination based on file name (HACK HACK) */
692 len = strlen(str);
693 b->b_flags &= ~(B_CMODE|B_TEXTMODE);
694 if (len > 4)
695 { if (strcmp(&str[len - 5], "draft") == 0)
696 b->b_flags |= B_TEXTMODE;
697 else
698 { cp = &str[len - 4];
699 if (strcmp(cp, ".txt") == 0 ||
700 strcmp(cp, ".mss") == 0)
701 b->b_flags |= B_TEXTMODE;
702 }
703 }
704 if (len > 2)
705 { cp = &str[len - 2];
706 if (strcmp(cp, ".h") == 0 || strcmp(cp, ".c") == 0)
707 b->b_flags |= B_CMODE;
708 }
709#endif /*IMAGEN*/
710 redp(RD_MODE);
711}
712
713
714/* SAVEWORLD - Attempt to save all changes user has made.
715 * Currently this amounts to writing out all modified buffers
716 * to the files $HOME/+buffername. If a buffer is given as argument,
717 * only that buffer is saved.
718 * This is only called from the error handling routines with
719 * the TTY either gone or in normal (non-edit) mode. The "grunt"
720 * flag says whether to output feedback during the saving process.
721 */
722saveworld(bp, grunt)
723struct buffer *bp;
724int grunt;
725{ register struct buffer *b;
726 register int wfd;
727 char sfname[FNAMSIZ];
728 struct buffer *sel_mbuf();
729
730 unhoard(); /* Ensure a FD is free for writing */
731 if(b = bp) goto once;
732 while(!bp && (b = sel_mbuf(b)))
733 {
734 once: strcat(strcat(strcpy(sfname,homedir),"/+"),b->b_name);
735 if(grunt) printf("Saving %s...",sfname);
736#if !(TOPS20)
737 if((wfd = creat(sfname, ev_filmod)) < 0)
738#else
739 if((wfd = open(sfname,O_WRONLY|O_UNCONVERTED)) < 0)
740#endif /*TOPS20*/
741 { if(grunt)
742 printf(" error - %s\n", strerror(errno));
743 }
744 else
745 { sb_fsave((SBBUF *)b, wfd);
746 close(wfd);
747 if(grunt) printf("\n");
748 }
749 b->b_flags &= ~B_MODIFIED;
750 }
751 hoard();
752}
753
754/* HOARD, UNHOARD - Routines to save a FD for writing, to make sure
755 * that we can always write out a buffer no matter how many
756 * file descriptors we are currently using.
757 */
758hoard() /* Stash away a FD */
759{ if(hoardfd <= 0)
760#if !(TOPS20)
761 hoardfd = open("nul:", 1);
762#else
763 hoardfd = open("/dev/null", 1);
764#endif
765}
766unhoard() /* Give up our stashed FD so it can be re-used */
767{ close(hoardfd);
768 hoardfd = -1;
769}
770
771
772#if IMAGEN
773#include <pwd.h>
774#include <ctype.h>
775
776/*
777 * expand_file: expand any ~user-name/ or $env-var/ prefixes in sfn,
778 * producing the full name in dfn
779 */
780expand_file(dfn, sfn)
781register char *dfn, *sfn;
782{
783 register char *sp, *tp;
784 register int c;
785 register struct passwd *pw;
786 char ts[128];
787
788 /* HORRIBLE, GROSS, DISGUSTING HACK: if the destination and
789 * source strings are identical (same pointer), then do not
790 * do any expansion--this happens to work with the current
791 * structure very well, since multiple expansions may happen.
792 */
793 if (dfn == sfn)
794 return;
795
796 ts[0] = 0;
797
798 /* If have a leading $, then expand environment variable */
799 if (*sfn == '$')
800 { ++sfn;
801 tp = ts;
802 while (*tp++ = *sfn)
803 if (!isalnum(*sfn))
804 break;
805 else
806 ++sfn;
807 *--tp = 0; /* Just in case */
808 strcpy(ts, getenv(ts)); /* MARGINAL!! */
809 }
810 /* If have leading ~, then expand login name (null means $HOME) */
811 else if (*sfn == '~')
812 { ++sfn;
813 if (*sfn == '/' || *sfn == 0)
814 strcpy(ts, getenv("HOME"));
815 else
816 { tp = ts;
817 while (*sfn && *sfn != '/')
818 *tp++ = *sfn++;
819 *tp = 0;
820 pw = (struct passwd *)getpwnam(ts);
821 if (! pw)
822 strcpy(ts, "???");
823 else
824 strcpy(ts, pw->pw_dir);
825 }
826 }
827
828 /* Now, ts is either empty or contains the expansion;
829 * sfn has been updated correctly.
830 */
831 strcpy(dfn, ts);
832 strcat(dfn, sfn);
833}
834#endif /*IMAGEN*/
Note: See TracBrowser for help on using the repository browser.