1 /* $Id: fileio.c,v 1.1.1.1.2.1 2000/12/01 10:01:06 amura Exp $ */
2 /*
3  *		bsd (4.2, others?), Sun (3.2, ?) and Ultrix-32 (?) file I/O.
4  */
5 
6 /*
7  * $Log: fileio.c,v $
8  * Revision 1.1.1.1.2.1  2000/12/01 10:01:06  amura
9  * fix problems open "/" and sybolic link directory
10  *
11  * Revision 1.1.1.1  2000/06/27 01:48:02  amura
12  * import to CVS
13  *
14  */
15 /* 90.01.29	Modified for Ng 1.0 by S.Yoshida */
16 
17 #include	"config.h"	/* 90.12.20  by S.Yoshida */
18 #include	"def.h"
19 
20 static	FILE	*ffp;
21 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__BSDI__)
22 #include <unistd.h>
23 #include <string.h>
24 #else
25  extern	char	*getenv(), *strncpy();
26 #endif
27 char	*adjustname();
28 
29 /*
30  * Open a file for reading.
31  */
ffropen(fn)32 ffropen(fn) char *fn; {
33 	if ((ffp=fopen(fn, "r")) == NULL)
34 		return (FIOFNF);
35 	return (FIOSUC);
36 }
37 
38 /*
39  * Open a file for writing.
40  * Return TRUE if all is well, and
41  * FALSE on error (cannot create).
42  */
ffwopen(fn)43 ffwopen(fn) char *fn; {
44 	if ((ffp=fopen(fn, "w")) == NULL) {
45 		ewprintf("Cannot open file for writing");
46 		return (FIOERR);
47 	}
48 	return (FIOSUC);
49 }
50 
51 /*
52  * Close a file.
53  * Should look at the status.
54  */
ffclose()55 ffclose() {
56 	(VOID) fclose(ffp);
57 	return (FIOSUC);
58 }
59 
60 /*
61  * Write a buffer to the already
62  * opened file. bp points to the
63  * buffer. Return the status.
64  * Check only at the newline and
65  * end of buffer.
66  */
ffputbuf(bp)67 ffputbuf(bp)
68 BUFFER *bp;
69 {
70     register char *cp;
71     register char *cpend;
72     register LINE *lp;
73     register LINE *lpend;
74 #ifdef	KANJI	/* 90.01.29  by S.Yoshida */
75     register int  kfio;
76 #endif	/* KANJI */
77 
78     lpend = bp->b_linep;
79 #ifdef	KANJI	/* 90.01.29  by S.Yoshida */
80     if (bp->b_kfio == NIL)
81 	ksetbufcode(bp);		/* Set buffer local KANJI code.	*/
82     kfio  = bp->b_kfio;
83 #endif	/* KANJI */
84     lp = lforw(lpend);
85     do {
86 	cp = &ltext(lp)[0];		/* begining of line	*/
87 	cpend = &cp[llength(lp)];	/* end of line		*/
88 	while(cp != cpend) {
89 #ifdef	KANJI	/* 90.01.29  by S.Yoshida */
90 	    kputc(*cp, ffp, kfio);
91 #else	/* NOT KANJI */
92 	    putc(*cp, ffp);
93 #endif	/* KANJI */
94 	    cp++;	/* putc may evalualte arguments more than once */
95 	}
96 #ifdef	KANJI	/* 90.01.29  by S.Yoshida */
97 	if (kfio == JIS) {
98 		kfselectcode(ffp, FALSE);
99 	}
100 #endif	/* KANJI */
101 	lp = lforw(lp);
102 	if(lp == lpend) break;		/* no implied newline on last line */
103 	putc('\n', ffp);
104     } while(!ferror(ffp));
105     if(ferror(ffp)) {
106 	ewprintf("Write I/O error");
107 	return FIOERR;
108     }
109     return FIOSUC;
110 }
111 
112 /*
113  * Read a line from a file, and store the bytes
114  * in the supplied buffer. Stop on end of file or end of
115  * line.  When FIOEOF is returned, there is a valid line
116  * of data without the normally implied \n.
117  */
ffgetline(buf,nbuf,nbytes)118 ffgetline(buf, nbuf, nbytes)
119 register char	*buf;
120 register int	nbuf;
121 register int	*nbytes;
122 {
123 	register int	c;
124 	register int	i;
125 
126 	i = 0;
127 	while((c = getc(ffp))!=EOF && c!='\n') {
128 		buf[i++] = c;
129 		if (i >= nbuf) return FIOLONG;
130 	}
131 	if (c == EOF  && ferror(ffp) != FALSE) {
132 		ewprintf("File read error");
133 		return FIOERR;
134 	}
135 	*nbytes = i;
136 	return c==EOF ? FIOEOF : FIOSUC;
137 }
138 
139 #ifndef NO_BACKUP
140 /*
141  * Rename the file "fname" into a backup
142  * copy. On Unix the backup has the same name as the
143  * original file, with a "~" on the end; this seems to
144  * be newest of the new-speak. The error handling is
145  * all in "file.c". The "unlink" is perhaps not the
146  * right thing here; I don't care that much as
147  * I don't enable backups myself.
148  */
fbackupfile(fn)149 fbackupfile(fn) char *fn; {
150 	register char	*nname;
151 
152 	if ((nname=malloc((unsigned)(strlen(fn)+1+1))) == NULL) {
153 		ewprintf("Can't get %d bytes", strlen(fn) + 1);
154 		return (ABORT);
155 	}
156 	(void) strcpy(nname, fn);
157 	(void) strcat(nname, "~");
158 	(void) unlink(nname);			/* Ignore errors.	*/
159 	if (rename(fn, nname) < 0) {
160 		free(nname);
161 		return (FALSE);
162 	}
163 	free(nname);
164 	return (TRUE);
165 }
166 
167 #ifdef	BUGFIX	/* 90.02.14  by S.Yoshida */
168 #ifndef	_SYS_STAT_H_
169 #include <sys/types.h>
170 #include <sys/stat.h>
171 #define	_SYS_STAT_H_
172 #endif	/* _SYS_STAT_H_ */
173 /*
174  * Get file mode of a file fn.
175  */
fgetfilemode(fn)176 fgetfilemode(fn)
177 char	*fn;
178 {
179 	struct	stat	filestat;
180 
181 	stat(fn, &filestat);
182 	return(filestat.st_mode & 0x0fff);
183 }
184 
185 /*
186  * Set file mode of a file fn to the specified mode.
187  */
fsetfilemode(fn,mode)188 fsetfilemode(fn, mode)
189 char	*fn;
190 int	mode;
191 {
192 	chmod(fn, mode);
193 }
194 #endif	/* BUGFIX */
195 #endif
196 
197 #ifdef	READONLY	/* 91.01.05  by S.Yoshida */
198 #ifndef	_SYS_STAT_H_
199 #include <sys/types.h>
200 #include <sys/stat.h>
201 #define	_SYS_STAT_H_
202 #endif	/* _SYS_STAT_H_ */
203 /*
204  * Check whether file is read-only of a file fn.
205  */
fchkreadonly(fn)206 fchkreadonly(fn)
207 char	*fn;
208 {
209 	struct	stat	filestat;
210 
211 	if (stat(fn, &filestat) == 0) {
212 		return(!(filestat.st_mode & S_IWRITE));
213 	} else {
214 		return FALSE;
215 	}
216 }
217 #endif	/* READONLY */
218 
219 /*
220  * The string "fn" is a file name.
221  * Perform any required appending of directory name or case adjustments.
222  * If NO_DIR is not defined, the same file should be refered to even if the
223  * working directory changes.
224  */
225 #ifdef SYMBLINK
226 #ifndef	_SYS_STAT_H_	/* 90.02.15  by S.Yoshida */
227 #include <sys/types.h>
228 #include <sys/stat.h>
229 #define	_SYS_STAT_H_
230 #endif	/* _SYS_STAT_H_ */
231 #ifndef MAXSYMLINKS
232 #define MAXSYMLINKS 8		/* maximum symbolic links to follow */
233 #endif
234 #endif
235 #include <pwd.h>
236 #ifndef NO_DIR
237 extern char *wdir;
238 #endif
239 
adjustname(fn)240 char *adjustname(fn)
241 register char *fn;
242 {
243     register char *cp;
244     static char fnb[NFILEN];
245     struct passwd *pwent;
246 #ifdef	SYMBLINK
247     struct stat statbuf;
248     int i, j;
249     char linkbuf[NFILEN];
250 #endif
251 
252     switch(*fn) {
253     	case '/':
254 	    cp = fnb;
255 	    *cp++ = *fn++;
256 	    break;
257 	case '~':
258 	    fn++;
259 	    if(*fn == '/' || *fn == '\0') {
260 		(VOID) strcpy(fnb, getenv("HOME"));
261 		cp = fnb + strlen(fnb);
262 	    	if(*fn) fn++;
263 		break;
264 	    } else {
265 		cp = fnb;
266 		while(*fn && *fn != '/') *cp++ = *fn++;
267 		*cp = '\0';
268 		if((pwent = getpwnam(fnb)) != NULL) {
269 		    (VOID) strcpy(fnb, pwent->pw_dir);
270 		    cp = fnb + strlen(fnb);
271 		    break;
272 		} else {
273 		    fn -= strlen(fnb) + 1;
274 		    /* can't find ~user, continue to default case */
275 		}
276 	    }
277 	default:
278 #ifndef	NODIR
279 	    strcpy(fnb, wdir);
280 	    cp = fnb + strlen(fnb);
281 	    break;
282 #else
283 	    return fn;				/* punt */
284 #endif
285     }
286     if(cp != fnb && cp[-1] != '/') *cp++ = '/';
287     while(*fn) {
288     	switch(*fn) {
289 	    case '.':
290 		switch(fn[1]) {
291 	            case '\0':
292 		    	*--cp = '\0';
293 		    	return fnb;
294 	    	    case '/':
295 	    	    	fn += 2;
296 		    	continue;
297 		    case '.':
298 		    	if(fn[2]=='/' || fn[2] == '\0') {
299 #ifdef SYMBLINK
300 			    cp[-1] = '\0';
301 			    for(j = MAXSYMLINKS; j-- &&
302 			    	    lstat(fnb, &statbuf) != -1 &&
303 			    	    (statbuf.st_mode&S_IFMT) == S_IFLNK &&
304 			    	    (i = readlink(fnb, linkbuf, sizeof linkbuf))
305 				    != -1 ;) {
306 				if(linkbuf[0] != '/') {
307 				    --cp;
308 				    while(cp > fnb && *--cp != '/') {}
309 				    ++cp;
310 				    (VOID) strncpy(cp, linkbuf, i);
311 				    cp += i;
312 				} else {
313 				    (VOID) strncpy(fnb, linkbuf, i);
314 				    cp = fnb + i;
315 				}
316 				if(cp[-1]!='/') *cp++ = '\0';
317 				else cp[-1] = '\0';
318 			    }
319 			    cp[-1] = '/';
320 #endif
321 			    --cp;
322 			    while(cp > fnb && *--cp != '/') {}
323 			    ++cp;
324 			    if(fn[2]=='\0') {
325 			        *--cp = '\0';
326 			        return fnb;
327 			    }
328 		            fn += 3;
329 		            continue;
330 		        }
331 		        break;
332 		    default:
333 		    	break;
334 	        }
335 		break;
336 	    case '/':
337 	    	fn++;
338 	    	continue;
339 	    default:
340 	    	break;
341 	}
342 	while(*fn && (*cp++ = *fn++) != '/') {}
343     }
344     if((cp-1)!=fnb && cp[-1]=='/') --cp;
345     *cp = '\0';
346     return fnb;
347 }
348 
349 #ifndef NO_STARTUP
350 #include <sys/file.h>
351 /*
352  * Find a startup file for the user and return its name. As a service
353  * to other pieces of code that may want to find a startup file (like
354  * the terminal driver in particular), accepts a suffix to be appended
355  * to the startup file name.
356  */
357 char *
358 #ifdef	ADDOPT
startupfile(ngrcfile,suffix)359 startupfile(ngrcfile, suffix)
360 char* ngrcfile;
361 #else
362  startupfile(suffix)
363 #endif
364 char *suffix;
365 {
366 	register char	*file;
367 	static char	home[NFILEN];
368 	char		*getenv();
369 
370 
371 #ifdef	ADDOPT
372 	if (ngrcfile == NULL)
373 		ngrcfile = getenv("NGRC");
374 	if (ngrcfile != NULL)
375 		if (access(ngrcfile, F_OK) == 0)  return ngrcfile;
376 #endif
377 	if ((file = getenv("HOME")) == NULL) goto notfound;
378 	if (strlen(file)+7 >= NFILEN - 1) goto notfound;
379 	(VOID) strcpy(home, file);
380 #ifdef	KANJI	/* 90.02.10  by S.Yoshida */
381 	(VOID) strcat(home, "/.ng");
382 #else	/* NOT KANJI */
383 	(VOID) strcat(home, "/.mg");
384 #endif	/* KANJI */
385 	if (suffix != NULL) {
386 		(VOID) strcat(home, "-");
387 		(VOID) strcat(home, suffix);
388 	}
389 	if (access(home, F_OK ) == 0) return home;
390 
391 notfound:
392 #ifdef	STARTUPFILE
393 	file = STARTUPFILE;
394 	if (suffix != NULL) {
395 		(VOID) strcpy(home, file);
396 		(VOID) strcat(home, "-");
397 		(VOID) strcat(home, suffix);
398 		file = home;
399 	}
400 	if (access(file, F_OK ) == 0) return file;
401 #endif
402 
403 	return NULL;
404 }
405 #endif
406 
407 #ifndef NO_DIRED
408 #include <sys/wait.h>
409 #include "kbd.h"
410 
copy(frname,toname)411 copy(frname, toname)
412 char *frname, *toname;
413 {
414     int pid;
415     char *eargv[3];
416     int status; 	/* change for Digital UNIX */
417 
418 #ifdef	BUGFIX	/* 91.01.11  by Y.Kaneko */
419     if((pid = vfork()) == 0) {
420 	execl("/bin/cp", "cp", frname, toname, (char *)NULL);
421 #else	/* ORIGINAL */
422     if(pid = vfork()) {
423 	if(pid == -1)	return	-1;
424 	eargv[0] = frname;
425 	eargv[1] = toname;
426 	eargv[2] = NULL;
427 	execve("cp", eargv, (char **)NULL);
428 #endif	/* BUGFIX */
429 	_exit(1);	/* shouldn't happen */
430     }
431 #ifdef	BUGFIX	/* 91.01.11  by Y.Kaneko */
432     if(pid == -1)	return	-1;
433 #endif	/* BUGFIX */
434     while(wait((int*)&status) != pid) {}
435 
436     return status == 0;
437 }
438 
dired_(dirname)439 BUFFER *dired_(dirname)
440 char *dirname;
441 {
442     register BUFFER *bp;
443     char line[256];
444     BUFFER *findbuffer();
445     FILE *dirpipe;
446     FILE *popen();
447 
448     if((dirname = adjustname(dirname)) == NULL) {
449 	ewprintf("Bad directory name");
450 	return NULL;
451     }
452     if(dirname[strlen(dirname)-1] != '/') (VOID) strcat(dirname, "/");
453     if((bp = findbuffer(dirname)) == NULL) {
454 	ewprintf("Could not create buffer");
455 	return NULL;
456     }
457     if(bclear(bp) != TRUE) return FALSE;
458 #ifdef	EXTD_DIR
459     strncpy(bp->b_cwd, dirname, NFILEN);
460     ensurecwd();
461 #endif
462 #ifdef	BUGFIX	/* 91.02.04  by M.Oki */
463     (VOID) strcpy(line, "/bin/ls -al ");
464     (VOID) strcpy(&line[12], dirname);
465 #else	/* ORIGINAL */
466     (VOID) strcpy(line, "ls -al ");
467     (VOID) strcpy(&line[7], dirname);
468 #endif	/* BUGFIX */
469     if((dirpipe = popen(line, "r")) == NULL) {
470 	ewprintf("Problem opening pipe to ls");
471 	return NULL;
472     }
473     line[0] = line[1] = ' ';
474     while(fgets(&line[2], 254, dirpipe) != NULL) {
475 	line[strlen(line) - 1] = '\0';		/* remove ^J	*/
476 	(VOID) addline(bp, line);
477     }
478     if(pclose(dirpipe) == -1) {
479 	ewprintf("Problem closing pipe to ls");
480 	return NULL;
481     }
482     bp->b_dotp = lforw(bp->b_linep);		/* go to first line */
483     (VOID) strncpy(bp->b_fname, dirname, NFILEN);
484     if((bp->b_modes[0] = name_mode("dired")) == NULL) {
485 	bp->b_modes[0] = &map_table[0];
486 	ewprintf("Could not find mode dired");
487 	return NULL;
488     }
489     bp->b_nmodes = 0;
490     return bp;
491 }
492 
d_makename(lp,fn)493 d_makename(lp, fn)
494 register LINE *lp;
495 register char **fn;
496 {
497   char* cp;
498   int l,l1,len;
499   char c;
500 
501   /* '47' is a magic number and is not correct always */
502 
503   if ( llength( lp ) <= 47 ) {
504     return ABORT ;
505   }
506   l = llength(lp);
507 
508   if (lgetc(lp, 2) == 'l') {
509     do {
510       while (l > 2 && lgetc(lp, l) != ' ')
511         l--;
512       if (bcmp(lp->l_text + l - 3, " -> ", 4) == 0)
513         break;
514       l--;
515     } while (l > 2);
516   }
517   else {
518     do {
519       while (l > 2 && lgetc(lp, l)!=' ')
520         l--;
521       l1 = l;
522       while (l > 2 && lgetc(lp, l)==' ')
523         l--;
524       while (l > 2 && (c=lgetc(lp, l))!=' ') {
525         if (c!=':' && (c<'0'&&c>'9')) {
526           break;
527         }
528         l--;
529       }
530     } while (l > 2 && c != ' ');
531   l = l1;
532   }
533   if (l <= 2)
534     return ABORT;
535   l++;
536 
537   len = llength(lp) - l + 1;
538   cp = malloc(len + strlen(curbp->b_fname) + 1);
539   if (cp) {
540     *fn = cp;
541     strcpy(cp, curbp->b_fname);
542     cp += strlen(cp);
543     bcopy(lp->l_text + l, cp, len);
544     cp[len-1] = '\0';
545 #ifdef SYMBLINK
546     if (lgetc(lp, 2) == 'l')
547       return ffisdir(curbp->b_fname);
548 #endif
549     return lgetc(lp, 2) == 'd';
550   }
551   else {
552     return ABORT;
553   }
554 }
555 #endif
556 
557 #ifndef NO_DIRED	/* 91.01.15  by K.Maeda */
558 #ifndef	_SYS_STAT_H_
559 #include <sys/types.h>
560 #include <sys/stat.h>
561 #define	_SYS_STAT_H_
562 #endif	/* _SYS_STAT_H_ */
563 /*
564  * Check whether file "dn" is directory.
565  */
ffisdir(dn)566 ffisdir(dn)
567 char *dn;
568 {
569 	struct	stat	filestat;
570 
571 	if (stat(dn, &filestat) == 0) {
572 		return ((filestat.st_mode & S_IFMT) == S_IFDIR);
573 	} else {
574 		return FALSE;
575 	}
576 }
577 #endif /* NO_DIRED */
578 
579 #ifndef NO_FILECOMP	/* 90.04.04  by K.Maeda */
580 #include <sys/dir.h>
581 
582 /* 89.11.20	Original code is for X68K (Human68K).
583  * 90.04.04	Modified for BSD UNIX by S.Yoshida
584  * Find file names starting with name.
585  * Result is stored in *buf, got from malloc();
586  * Return the number of files found, or
587  * -1 of error occured.
588  */
589 
590 #define	MALLOC_STEP	256
591 
fffiles(name,buf)592 fffiles(name, buf)
593 char *name, **buf;
594 {
595 	char pathbuf[128], tmpnam[128];
596 	char *cp, *dirpart, *nampart;
597 	DIR *dp;
598 #ifdef	BSD4_3
599 	register struct dirent *dirent;
600 #else
601 	register struct direct *dirent;
602 #endif
603 	int n, len, size, dirpartlen, nampartlen;
604 	char *buffer;
605 	struct stat st;
606 
607 	strcpy(pathbuf, name);
608 	dirpart = NULL;
609 	for (cp = pathbuf; *cp; cp++) {
610 		if (*cp == '/')
611 			dirpart = cp;
612 	}
613 	if (dirpart) {
614 		*++dirpart = '\0';
615 		dirpartlen = dirpart-pathbuf;
616 	} else {
617 		strcpy(pathbuf, "./");
618 		dirpartlen = 0;
619 	}
620 	nampart = name + dirpartlen;
621 	nampartlen = strlen(nampart);
622 
623 #ifndef	NEW_COMPLETE	/* 90.12.10    Sawayanagi Yosirou */
624 	if ((dp = opendir(pathbuf)) == NULL)
625 		return -1;
626 #endif	/* NOT NEW_COMPLETE */
627 
628 	buffer = malloc(MALLOC_STEP);
629 	if (buffer == NULL)
630 		return -1;
631 	size = MALLOC_STEP;
632 	len = 0; n = 0;
633 
634 #ifdef	NEW_COMPLETE	/* 90.12.10    Sawayanagi Yosirou */
635 	if ((dp = opendir(pathbuf)) == NULL) {
636 		*buf = buffer;
637 		buffer[0] = '\0';
638 		return 0;
639 	}
640 #endif	/* NEW_COMPLETE */
641 
642 	while ((dirent = readdir(dp)) != NULL) {
643 		register int l;
644 		if (strncmp(nampart, dirent->d_name, nampartlen) != 0)
645 			goto nomatch;		/* case-sensitive comparison */
646 		strncpy(tmpnam, pathbuf, dirpartlen);
647 		strcpy(tmpnam+dirpartlen, dirent->d_name);
648 		if (stat(tmpnam, &st) < -1) goto nomatch;
649 		if ((st.st_mode & S_IFMT)==S_IFDIR)
650 			strcat(tmpnam, "/");
651 		l = strlen(tmpnam)+1;
652 		if (l > 3 && tmpnam[l-3] == '.' && tmpnam[l-2] == 'o')
653 			goto nomatch;
654 		if (l+len >= size) {
655 				/* make room for double null */
656 			if ((buffer = realloc(buffer, size += MALLOC_STEP)) == NULL)
657 				return -1;
658 		}
659 		strcpy(buffer+len, tmpnam);
660 		len += l;
661 		n++;
662 	nomatch:;
663 	}
664 	closedir(dp);
665 
666 	*buf = buffer;
667 	buffer[len] = '\0';
668 	return n;
669 }
670 #endif
671 
672 #ifdef	NEW_COMPLETE	/* 90.12.10    Sawayanagi Yosirou */
673 char *
file_name_part(s)674 file_name_part (s)
675     char    *s;
676 {
677     int    i;
678 
679     for (i = strlen (s); i > 0; i--)
680       {
681         if (s[i - 1] == '/')
682 	  break;
683       }
684     return (s + i);
685 }
686 
687 char *
copy_dir_name(d,s)688 copy_dir_name (d, s)
689     char    *d;
690     char    *s;
691 {
692     int    i;
693 
694     i = file_name_part (s) - s;
695     strncpy (d, s, i);
696     d[i] = '\0';
697     return (d);
698 }
699 #endif	/* NEW_COMPLETE */
700