Assignment 6, Solved
Part of
the homework for 22C:50, Summer 2003
|
The first problem we face is to figure out what the baud-rate divisor means. We know that 115,200 baud translates to a divisor of 1, while 57,600 baud translates to a divisor of 2 -- half the baud rate translates to twice the divisor! We know that the divisor is 3 for 38,400 baud, and again, we discover that 1/3 the baud rate translates to 3 times the divisor.
So, the problem asks about the archaic baud rates 45.5 baud and 75 baud. All we need to do is divide 115,200 by this to get the divisor! So:
115200/45.5 = 253210 = 9E416 115200/75 = 153610 = 60016
The divisor for 45.5 baud is approximate, while the divisor for 75 baud is exact.
void comreadline( struct filevariable * f, char buf[], int len ); { int p = 0; /*a*/ int col = 1; /* count columns in the output */ do { char ch = f->read(f); if (ch >= ' ') { /* character is printable */ if (p < len) { /* space is available in buffer */ buf[p] = ch; /* put it in the buffer */ p = p + 1; /*a*/ col = col + 1; /* record current column */ f->write(f, ch); /* echo it */ } } else if (ch == '\b') { /* character is backspace */ if (p > 0) then begin p = p - 1; /*a*/ col = col - 1; /* record current column */ f->write(f, '\b'); /* erase a character */ f->write(f, ' '); f->write(f, '\b'); } } else if (ch == '\t') { /* character is tab */ /*a*/ while (((col % 8) != 0) && (p < len)) { /*a*/ buf[p] = ' '; /* put blank in the buffer */ /*a*/ p = p + 1; /*a*/ col = col + 1; /* record current column */ /*a*/ f->write(f, ' '); /* echo the blank */ /*a*/ } } } while ((ch != '\n') && (ch != '\r')); if (p < len) { /* space is available in buffer */ buf[p] = '\0'; /* put terminator in buffer */ } f->write(f, '\r'); f->write(f, '\n'); }
Changes to the code from the figure are marked with a marginal comment. Note that this code cheats, a bit, by putting the right number of blanks in the buffer when the user hits a tab, and as a result, the problem of erasing tabs is greatly simplified because erasure always moves the cursor back one column. If I had recorded the tab in the buffer, I'd have had to do quite a bit more work to erase them properly!
The broad general answer: Methods of the object need access to the variables of that object. In the text (*f->put)(f,c), the first use of f is only concerned with transfer of control to the function that implements the desired method, while the second use of f gives that function access to the variables local to the object f.
The specific answer: In the text (*f->put)(f,c), the first use of f is only concerned with transfer of control to the put function in the appropriate I/O driver, while the second use of f gives that function access to the state information in f that is specific to that particular file or device.
Suppose you are writing to a block-sequential DMA device such as a high-speed tape backup on a UNIX system. The block size on the device is 512 bytes, but your software uses a buffer of 1000 bytes. Explain why the operating system cannot do output directly from the user's bufer, but must copy from the user's buffer to a system buffer before doing output to the device. Make careful use of the relevant terminology from Chapter 9.
Whenever a block is written to tape where that block lies entirely within the user's buffer, it could be written without the need for an intermediate buffer. So, from the first 1000 word buffer written by the user, we may write the first block to tape from bytes 0 to 511 of the user's buffer. However, the second block to tape will be composed of bytes 512 to 999 from the user's first buffer followed by bytes 0 to 23 of the user's second buffer, and these must be assembled into a single buffer, provided by the operating system before being written to tape.
The third block to tape can again be written directly from the user's second buffer, bytes 24 to 535, but the fourth block will need to be assembled in a system buffer again.
This is called blocking (or reblocking) the user's data stream into blocks that match the device's requirements.