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