--- gawk-3.1.5.dfsg/io.c 2009-01-10 11:50:52.000000000 +0100 +++ gawk-3.1.5.dfsg/io.c 2009-01-10 11:53:46.454403619 +0100 @@ -148,6 +148,7 @@ size_t rt_len; /* length of terminator */ }; +static DIR *iop_dirp = NULL; static IOBUF *nextfile P((int skipping)); static int inrec P((IOBUF *iop)); static int iop_close P((IOBUF *iop)); @@ -368,6 +369,7 @@ iop->flag &= ~IOP_AT_EOF; iop->flag |= IOP_CLOSED; /* there may be dangling pointers */ iop->dataend = NULL; + iop->name = NULL; #ifdef _CRAY /* Work around bug in UNICOS popen */ if (iop->fd < 3) @@ -375,7 +377,7 @@ else #endif /* save these for re-use; don't free the storage */ - if ((iop->flag & IOP_IS_INTERNAL) != 0) { + if ((iop->flag & (IOP_NO_FREE |IOP_IS_INTERNAL)) != 0) { iop->off = iop->buf; iop->end = iop->buf + strlen(iop->buf); iop->count = 0; @@ -388,9 +390,13 @@ || iop->fd == fileno(stdout) || iop->fd == fileno(stderr)) ret = 0; - else - ret = close(iop->fd); - + else { + if ((iop->flag & IOP_IS_DIR) != 0) { + rewinddir(iop->dirp); + ret = closedir(iop->dirp); + } else + ret = close(iop->fd); + } if (iop->close_func != NULL) (*iop->close_func)(iop); @@ -1253,6 +1259,20 @@ } #endif /* HAVE_SOCKETS */ +int +dir_open(const char *name) +{ + int openfd; + char *cp; + cp = (char *) name + 5; + iop_dirp = opendir(cp); + if (iop_dirp == NULL) + openfd = INVALID_HANDLE; + else + openfd = dirfd(iop_dirp); + return openfd; +} + /* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */ /* @@ -1309,6 +1329,8 @@ /* do not set close-on-exec for inherited fd's */ if (openfd != INVALID_HANDLE) return openfd; + } else if (STREQN(name, "/dir/", 5)) { + return dir_open(name); } else if (STREQN(name, "/inet/", 6)) { #ifdef HAVE_SOCKETS /* /inet/protocol/localport/hostname/remoteport */ @@ -1410,8 +1432,11 @@ if (openfd == INVALID_HANDLE) openfd = open(name, flag, 0666); if (openfd != INVALID_HANDLE) { - if (os_isdir(openfd)) - fatal(_("file `%s' is a directory"), name); + if (os_isdir(openfd)) { + openfd = INVALID_HANDLE; + errno = EISDIR; + // fatal(_("file `%s' is a directory"), name); + } os_close_on_exec(openfd, name, "file", ""); } @@ -1441,6 +1466,10 @@ iop->dataend = iop->end; iop->fd = -1; iop->flag = IOP_IS_INTERNAL | IOP_AT_START; + if (iop->flag & IOP_IS_DIR) { + iop->fd = dir_open(iop->name); + iop->flag |= IOP_IS_DIR; + } } /* specfdopen --- open an fd special file */ @@ -1461,7 +1490,7 @@ return INVALID_HANDLE; } *iop = *tp; - iop->flag |= IOP_NO_FREE; + iop->flag |= IOP_NOFREE_OBJ; free(tp); return 0; } @@ -1556,6 +1585,7 @@ { "/dev/ppid", 9, pidopen }, { "/dev/pgrpid", 11, pidopen }, { "/dev/user", 9, useropen }, + { "/dir/", 5, specfdopen }, }; int devcount = sizeof(table) / sizeof(table[0]); @@ -1565,7 +1595,8 @@ openfd = fileno(stdin); else if (do_traditional) goto strictopen; - else if (STREQN(name, "/dev/", 5) || STREQN(name, "/inet/", 6)) { + else if (STREQN(name, "/dev/", 5) || STREQN(name, "/inet/", 6) || + STREQN(name, "/dir/", 5)) { int i; for (i = 0; i < devcount; i++) { @@ -1573,11 +1604,12 @@ iop = & table[i].iob; if (iop->buf != NULL) { + iop->name = name; spec_setup(iop, 0, FALSE); return iop; - } else if ((*table[i].fp)(iop, name, mode) == 0) + } else if ((*table[i].fp)(iop, name, mode) == 0) { return iop; - else { + } else { warning(_("could not open `%s', mode `%s'"), name, mode); return NULL; @@ -1591,8 +1623,11 @@ if (openfd == INVALID_HANDLE) openfd = open(name, flag, 0666); if (openfd != INVALID_HANDLE) { - if (os_isdir(openfd)) - fatal(_("file `%s' is a directory"), name); + if (os_isdir(openfd)) { + openfd = INVALID_HANDLE; + errno = EISDIR; + // fatal(_("file `%s' is a directory"), name); + } } /* * At this point, fd could still be INVALID_HANDLE. @@ -2499,10 +2534,16 @@ } if (isatty(iop->fd)) iop->flag |= IOP_IS_TTY; - iop->readsize = iop->size = optimal_bufsize(iop->fd, & sbuf); + if (os_isdir(iop->fd)) { + iop->flag |= IOP_IS_DIR; + iop->dirp = iop_dirp; + iop->readsize = iop->size = NAME_MAX + 1; + } else { + iop->readsize = iop->size = optimal_bufsize(iop->fd, & sbuf); + } iop->sbuf = sbuf; if (do_lint && S_ISREG(sbuf.st_mode) && sbuf.st_size == 0) - lintwarn(_("data file `%s' is empty"), name); + lintwarn(_("data file `%s' is empty"), name); errno = 0; iop->count = iop->scanoff = 0; emalloc(iop->buf, char *, iop->size += 2, "iop_alloc"); @@ -2883,7 +2924,7 @@ } /* = */ -/* get_a_record --- read a record from IOP into out, return length of EOF, set RT */ +/* get_a_record --- read a record from IOP into out, return length or EOF, set RT */ int get_a_record(char **out, /* pointer to pointer to data */ @@ -2897,12 +2938,22 @@ NODE *rtval = NULL; static RECVALUE (*lastmatchrec)P((IOBUF *iop, struct recmatch *recm, SCANSTATE *state)) = NULL; - if (at_eof(iop) && no_data_left(iop)) + if (at_eof(iop) && no_data_left(iop)) { return EOF; - - if (iop->get_record != NULL) + } + if (iop->get_record != NULL) { return (*iop->get_record)(out, iop, errcode); - + } + if (iop->flag & IOP_IS_DIR) { + struct dirent *dent; + dent = readdir(iop->dirp); + if (dent != NULL) { + memcpy(iop->buf, dent->d_name, NAME_MAX); + *out = iop->buf; + return strlen(iop->buf); + } else + return EOF; + } /* = */ if (has_no_data(iop) || no_data_left(iop)) { iop->count = read(iop->fd, iop->buf, iop->readsize); @@ -3171,6 +3222,7 @@ { IOP_AT_EOF, "IOP_AT_EOF" }, { IOP_CLOSED, "IOP_CLOSED" }, { IOP_AT_START, "IOP_AT_START" }, + { IOP_IS_DIR, "IOP_IS_DIR" }, { 0, NULL } };