LETTERS

Standardizing the Standardizing Process

Dear DDJ,

Apparently columnist Al Stevens got a little carried away in his November 1989 column when he compared the ANSI standardization process to democracy.

Surely Mr. Stevens knows that a committee is, at best, only a representative democracy. As we in the U.S. are reminded every couple of years, one democratic problem lies in determining who gets to be on the committee. Since I do not remember voting for these people, I wonder whose interests they really represent.

Actually, I commend the C standardization committee for the extent to which they have discussed their issues in print; there has even been some serious discussion of comments from outsiders. In contrast, I was recently involved with comments to the ANSI X3J9 Extended Pascal standardization committee. Since I have read no articles whatsoever on Pascal standardization issues, I wonder how many Pascal programmers realize that such a standard is now virtually complete.

My introduction to Extended Pascal was a note in IEEE Computer (Sept. 1988, p. 70) which mentioned that a draft standard was available (for $35). After receiving the draft I became concerned about its content. In fact, I assumed that no group of responsible professionals would consider releasing such a document as an example of their work. But I did submit comments; that was in October 1988.

In June, 1989, I received a package which included copies of all the various comments received, with The Committee's formal response to each point. Apparently I got in on the tail end of the feedback process, since most of the comments were from various other nations' standards organizations, as well as some individuals who were commenting on previous responses. The Committee did decide to make some changes. But my earlier assumption was wrong: For the most part, the draft was allowed to stand.

After an eight-month delay for The Committee to get its responses together, the commentors were given "fifteen working days" to accept or reject their individual responses. Note that the Extended Pascal draft standard is a voluminous, excruciatingly detailed specification, and not everyone can simply drop what they are doing to analyze responses, generate objections, and construct a formal response to The Committee. I did just that, however, and perhaps I was the only one who did, for the response letter that I finally received this September addressed my objections only, and seemed appallingly condescending.

As an engineer myself, I would be the first to admit that some engineers seem to vie with one another to produce the most complex and oblique specification possible. I guess if nobody can understand the spec, then nobody can criticize it; of course, then nobody can help find the bugs in it, either. And I have seen some really awful specifications, with special mention going to IEEE Std 488-1975. But the extended Pascal draft standard, which purported to describe a structured programming language, was itself so unstructured as to be almost unreadable.

The creation of a specification need not differ from the creation of a program; each must eventually describe a derivative logical system that actually works. A complex system must have a detailed description, of course, but not necessarily a complex organization; that's the whole point of structured programming. In fact, if a system can only be understood in a complex way, how can anyone use it reliably? Simple systems can be reliable, but complex systems always contain errors, unless they can be exhaustively tested by an impartial mechanism, and even then, you never really know.

Some of my comments included the lack of exception handling, the lack of alphanumeric Goto labels, the complete lack of any comment nesting at all, and the lack of multiple integer and real data types corresponding to word sizes and IEEE reals. I wanted additional C-like looping enhancements such as Break and Continue to avoid the use of unstructured mid-loop Gotos, but The Committee preferred Goto instead. And I was especially concerned over the specification of a single Complex data type with a deliberately undefined implementation. There are two common representations for complex numbers, and each is best suited for different types of computation. The inability to force a particular representation seemed to be a serious programming limitation and a "numerical analysis nightmare." But the particular issues involved are not really the point.

The point in that we have a standardization process functioning largely behind closed doors, without a broad base of general input from the real users of the system under definition. The real users of a Pascal system are individual Pascal programmers. Where are all the comments from these users? When were they contacted? How are they being kept informed? Why were no standardization discussions printed in popular programming magazines? Although I am a member of IEEE, I cannot imagine that this organization is the appropriate sponsor of a programming language standard; a better-suited organization would seem to be the software-oriented ACM.

This experience has taught me a lot about what a standard really means. First of all, there is no reason to think that voting should produce a good standard. Design should be an exercise in consistency and correctness, something not conferred by a winning vote. Indeed, voting for Clarity seems unpopular, possible (cynically) because if a normally intelligent person could simply read the standard, they might not need an expert consultant to help interpret it.

And, when you think about it, democratic voting is itself an adversarial process (indeed, a form of ritualized combat). There may be a substantial minority which is firmly opposed to the outcome, and in scientific or engineering disputes, the minority view may well be correct. Moreover, as in the case of our national political parties, those in the minority have an honorable duty to continue their opposition, if they feel it to be right, against the day when their arguments may prevail. Thus, it is important that not everyone change the way they do things simply because a particular design is voted "standard." And there is certainly no reason to force programming classes to use a particular language selected by some elitist committee.

At one time there was some discussion in DDJ of Borland's Turbo Pascal with respect to the Pascal "standard." I used to wonder why Turbo Pascal did not provide a Standard Pascal mode, but, after studying the Extended Pascal draft standard, now I know: Standard Pascal is a turkey. Although I do have some differences with the Turbo Pascal design, it is a fine language for program expression; it is also clearly described in a structured manner. Perhaps Turbo Pascal represents the product for the loyal opposition.

Our standards process could be based on the more democratic and obviously more successful Japanese approach of building a widely held consensus, in which case the standards would carry some real weight. But in this Pascal standardization effort, we instead see Ugly American political domination in action. We see back room maneuvering for ANSI institutional support of a particular design, essentially without regard for, or input from, most of the real potential users. This is not democracy, and it may be time for a change.

Terry Ritter, P.E.

Blue Jean Computer Engineering

Austin, Texas

Container Object Fix

Dear DDJ,

I really am glad to see the number of OOPS articles that have been in DDJ recently. I especially appreciated Anders Hejlsberg's article on container objects ("Container Object Types in Turbo Pascal," Nov. 1989), but have found several errors in the code listings:

In Listing one, function ListNode.Prev, change the two references to Self to reference the address of Self (@Self) as follows:

P:=@Self;
while P^.Next<>@Self do P:=P^.Next;

The code will not compile without the above changes, as self is a listnode object type while P is a ListNodePtr type.

In Listing two, change the with statement in procedure GetIdent by adding an address operator to Name as follows:

with IdentRefPtr(Idents.Search(@Name,NewIdent))^ do

The first parameter to search (the key) should be a pointer.

One useful addition to the list methods is a procedure to concatenate two lists. The circular list type in the contain unit can be efficiently concatenated by swapping the two lists last.next pointer.

In a circular list representation, last.next points to the first list element. Given the list {a,b,c}, a.next->b, b.next->c, and c.next->a. Last is a pointer to c. To concatenate list {d, e, f}, all we need to do is make f.next point to a and c.next point to d. In other words, the last^.next pointers of the two lists need to be swapped. Then the last variables of the lists need to be adjusted.

  
  	unit Concat;
  	interface

  	Uses Contain; {from DDJNov. '89 type
  	CatListPtr = ^CatList; CatList = object(List)
        procedure cat(L: CatListPtr); end;
  	implementation
  	Procedure CatList.Cat(L: CatListPtr);
  	{Concatenate list L to the list invoking the method 
  	- L is appended to the END of the list being acted on.}

Var P: ListNodePtr; {temporary} Begin
    {swap the two pointers}
    P:= Last^.Next;
    Last^.Next:= L^.Last^.Next;
    L^.Last^.Next:= P;

   {adjust pointers}   
   Last := L^.Last;
   L^.Last := NIL; End; END.

Eric Friedman

Glenview, Illinois

Delving into Drive Paths

Dear DDJ,

I have been able to make a great deal of use of the information in Mr. James' article, "Undocumented DOS," June, 1989. In the process, I have determined a more precise definition of the Drive Path Table that he presented. Perhaps some of your readers will find this information as useful as I have.

The Drive Path Table is as follows. (Note that some of the following information is in direct conflict with the information presented by Mr. James.)

The number of entries in the Drive Path Table is set by the LASTDRIVE=xx command in your CONFIG.SYS file. To access the Drive Path Table for a particular drive, start with the drive number (0 = A, 1 = B,...) and make sure it is less than the LASTDRIVE=xx value; if it is not less, the drive number is invalid. (See Mr. James' article, Table 2, byte 21H.) If the drive number is valid, multiply it by 51H and add that value to the Drive Path Table pointer (same article, same table, offset 16H). The resulting 32-bit value points at the Drive Path Table entry for that drive.

For normal drives, the pathname field contains the current default pathname (e.g. C:\MY_PATH), the flags field has the value 4000H, and the root-length field has the value 2.

For unused drives, the flags field has the value 0. All remaining fields are set to all 0s or all 1s, except the pathname field, which contains the drive letter, a colon, and a '\'.

For drives created with the SUBST command, the pathname field contains the target path, the flags field has the value 5000H, and the root-length field is set to the length of the target path. For example, after executing the command SUBST E: C:\BIN the pathname field for drive E would be "C:\BIN", and the root-length field would have the value 6.

Now, if you change directories on drive E (e.g. CD E:NEXT) the pathname field is updated (C:\BIN\NEXT) but the root-length field remains unchanged at 6.

If you use the JOIN command on a drive, the pathname field contains the path to which the drive is joined, the flags field contains the value 6000H, and the root-length field is set to 2. For example, after the command JOIN A: C:\DRIVEA the pathname field for drive A would be "C:\DRIVEA". Because drive A is no longer a valid drive, you cannot change the current default directory of this drive. If you CD to C:\DRIVEA\ANYPATH, that pathname is stored in the Drive Path Table entry for drive C, not A.

For network drives, the pathname field contains the network name, followed by the network path; the network name is preceded by two back-slashes. The flags field contains the value 0C000H, and the root-length field is set to the length of the combined network name and path strings. For example, after the command NET USE F: \\MYNET\MYPATH the pathname field for drive F would contain "\\MYNET\MYPATH", and the root-length field would contain the value 14.

More Details.


  Offset    Size     Description
  --------------------------------------------------------
  0         byte     pathname: an ASCIIZ string.
            [67]
  43H       word     flags:
                     8000H a network drive.
                     4000H this entry is valid.
                     2000H a JOIN drive.
                     1000H a SUBST drive.
  45H       dword    pointer to the drive parameter block.
  49H       word     block/track/sector information.
  4BH       dword    unused (set to 0FFFFFFFFH)
  4FH       word     root length.

Now, if you change directories on drive F (e.g. CD F:NEXT) the pathname field is updated (\\MYNET\MYPATH\NEXT) but the root-length field remains unchanged at 14.

For network drives, the last few fields of the Drive Path Table are redefined slightly. Beginning at offset 45H, the Drive Path Table becomes:

  45H   dword   unused (set to 0)
  49H   dword   pointer to a
                network drive table
  4DH   word    saved parameter
  4FH   word    root length

The pointer at offset 49II points into a linked list of network devices (drives and printers).

The saved-parameter field stores a user-defined value. This value is selected when the drive is created. (See INT 21H function 5F03H.) I suppose it would be used by someone writing a network driver, who needed to keep track of additional information about the drive.

When accessing the Drive Path Table, you should be aware of the ASSIGN command. If the ASSIGN command has been invoked, it will automatically translate drive letters that are passed through the conventional INT 21H function calls. But, it will NOT translate these drive letters as you access the Drive Path Table directly.

In DOS 3.xx, you can determine whether ASSIGN is installed (ASSIGN is a TSR) like this:

MOV    	AX,0600H
INT   	2FH   
OR     	AL,AL   
JZ		NOTINSTALLED   
88

If ASSIGN is installed, you can get a pointer to its translation table like this:

MOV  	AH,19H    
INT  	21H  
PUSH   	AX; save the current default drive
MOV  	AX,0601H  
INT  	2FH   
POP    	DX; restore the drive
MOV  	AH,0EH    
INT  	21H   
MOV 	AL,ES:[0103H+drivenumber1] ;drivenumber: 1=A, 2=B, . . .

The translation table is always 26 bytes. By default, each drive is assigned to itself (e.g. entry 1=1, entry 2=2, . . .). After an assignment such as ASSIGN A=C, entry 1 gets the value 3, and then all attempts to access drive A are routed to drive C.

Thus, whenever you access the Drive Path Table, you should index the drive number into the ASSIGN translation table, if it exists. And if you use the pathname field, you should reverse-assign the drive letter therein.

Reverse-assigning a drive letter means scanning the ASSIGN translate table to find a drive number that, when translated, will result in the drive letter that appears in the Drive Path Table pathname field. And be prepared that you may not be able to find such a drive number.

For DOS 2.xx, I do not know of a reliable way of determining whether the ASSIGN command is installed. The ASSIGN command tries to detect itself, but the method it uses is not the elegant INT 2FH interface, and it fails under certain circumstances.

To detect itself, DOS 2.xx ASSIGN looks at the first few bytes pointed at by the INT 21H interrupt vector. If those bytes match the first few bytes of ASSIGN's INT 21H handler (80, FC, 0C, 76, 2D, 80, FC, 50), ASSIGN decides that it is already installed. Rather than installing a second copy of itself, ASSIGN updates the installed translation table, and exits quietly. (To access the installed translation table, ASSIGN uses the segment value from interrupt vector 21H and an offset value of 0103H.)

The problem is that, after installing ASSIGN, if you install any TSR that also has an INT 21H handler, this detection scheme falls. In fact, if you run the ASSIGN command again under these circumstances, it will install itself a second time. This will likely cause strange results, because the drives may be translated multiple times.

If, when working with drives, your program uses exclusively one method or the other (that is, either conventional interfaces or undocumented interfaces, but not both) then you probably need not worry about the ASSIGN command.

If you must use both interfaces, and you want your program to work correctly in DOS v2.xx, you should warn the program's users about the restrictions regarding the DOS 2.xx ASSIGN command.

In summary, the Drive Path Table allows access to information that would not otherwise be available to normal programs (i.e. the JOIN and SUBST information.)

Michael Cook

Mitel Semiconductor

Kanata, Ontario

Graphics For the Rest of Us

Dear DDJ,

I found the interview with David Parker in Michael Swaine's column entitled "Parker's Perceptions" in the October 1989 DDJ especially interesting since I'm a very satisfied user of his "AcroSpin" graphics software. I'd known nothing about the person behind it!

Swaine says "it seems to have a good product," and I can testify that it does indeed. My colleagues and I need to do 3-D graphics in a variety of languages, on a number of different IBM PC compatible machines. We also cannot afford fancy hardware; my own machine doesn't even have a hard drive.

AcroSpin is the only product I've seen that does the things I need on the hardware I've got. On all our PC's at this institution, I've yet to encounter one that has some kind of graphics and cannot run AcroSpin. It's clean, simple, and does exactly what the manual says it'll do.

Matthew D. Healy

Zoology graduate student

Duke University, North Carolina

FPCA '89 Proceedings

Dear DDJ,

I very much enjoyed Ronald Fischer's report on functional programming and FPCA '89. I must take issue with Mr. Fischer on one point. He states that "Scheme is a deviation of Lisp that doesn't offer lazy evaluation." Scheme certainly does offer delayed (lazy) evaluation, via the DELAY and FORCE primitives. See, for instance, Chapter 3 of Abelson, Sussman, and Sussman's Structure and Interpretation of Computer Programs for a superb introduction to streams and delayed evaluation in Scheme.

I was disappointed that the article did not mention how to obtain the conference proceedings. Could you provide this information?

David Cabana

Tampa, Florida