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