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 = <ext(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