From: SMTP%"RELAY-INFO-VAX@CRVAX.SRI.COM" 27-DEC-1993 10:39:08.10 To: EVERHART CC: Subj: RE: VMS system `read' Message-Id: <9312242352.AA10993@uu3.psi.com> Date: Fri, 24 Dec 93 18:52:07 EDT From: Jerry Leichter To: INFO-VAX@sri.com Subject: RE: VMS system `read' X-Vms-Mail-To: UUCP%"jla@gnu.ai.mit.edu" GNU indent uses a special form of `read' under VMS. Several people have sent me differing versions of this function (with different semantics), and have also said this function was not really required. Could some VMS guru(s) please settle this question for me? The version of this function currently used by GNU indent (donated by MEHRDAD@glum.dev.cf.ac.uk) is included. below. Thanks in advance, Joe int vms_read (int file_desc, char *buffer, int nbytes) { register char *bufp; register int nread, nleft; bufp = buffer; nread = 0; nleft = nbytes; nread = read (file_desc, bufp, nleft); while (nread > 0) { bufp += nread; nleft -= nread; if (nleft < 0) sys_error ("Internal buffering error"); nread = read (file_desc, bufp, nleft); } return nbytes - nleft; } This code is basically correct. My main criticism of it is that, in usual Unix fashion, it ignores the possibility of an error return. What if read() returns a negative value? At least this code won't go into an infinite loop, as the test (nread > 0) is correct. Note that higher-level code which uses vms_read() in place of read() will never see an error return, since the value returned by the function is always computed directly from nbytes and nleft. If the intent is that vms_read() should be "just like read() but ignore short returns", any error return should be propagated back. On a more general philosophical note: This routine is not, and should not be, VMS-specific. It's a common Unix hacker's assumption that read() will return as many bytes as you ask it for. Not true. Until fairly recently, no such guarantee existed anywhere at all. Moderns specs do provide such a guarantee, mainly for disk reads - but not, for example, for things like pipes or FIFO's. The careful programmer will use this routine on ALL systems. The additional overhead is trivial. BTW, does sys_error() abort the program? If it returns, you are heading for an infinite loop. (In any case, the only way nleft can become negative is for read() to operate incorrectly: Its specification doesn't permit it to return a value larger than its third argument. I think this test is a waste of time.) Stylistically: I can't understand why anyone today would bother with register declarations except in very special cases. Let the compiler do its job! Even VAX C, which isn't the world's smartest C compiler, would have no trouble deciding to put these variables in registers. You can also structure the loop better: Why have two identical calls to read()? C lets you put the test in the middle of the loop. How about: int big_read (int file_desc, char *buffer, int nbytes) { char *bufp; int nread, nleft; bufp = buffer; /* nread = 0; First access is a write, why initialize? */ nleft = nbytes; /* * Why call read() with nleft = 0? */ while (nleft > 0) { nread = read (file_desc, bufp, nleft); if (nread <= 0) break; bufp += nread; nleft -= nread; } /* * If you must test this, at least do it out of line! */ if (nleft < 0) sys_error ("Internal buffering error"); if (nread < 0) return nread; /* Pass back error return */ else return nbytes - nleft; } Of course, there can be problems if read() returns EINTR (interrupted opera- tion) - no great surprise. If you want to worry about that, it has to be handled within this routine, since necessary context is lost once it returns. (Actually, it's not easy to recover cleanly!) BTW, the System V spec says that read's third argument is an unsigned. Since the value returned by read() is an int, it's left to the spec reader's imagi- nation what read() does if it retrieves more bytes than the largest possible signed int. (It gets especially amusing when it reads the maximum possible unsigned int bytes, since if it tries to return THAT number on a 2's comple- ment machine, the result as a signed int looks like -1, the error signal. Aren't the Unix specs fun?) -- Jerry