LETTERS

Faster Animation

Dear DDJ,

I enjoyed Rahner James's article on "Real Time Animation" in the January 1990 issue of DDJ. Ever since the price of EGA devices dropped, magazines have been filled with how-to articles, but few have covered icons or sprites. In 1986 I ported a collection of graphics routines from my Zenith 100 system to the EGA. These routines are now part of an icon development environment called "ProGraphx Toolbox," available from Stanwood Associates.

Speed is definitely the key to success in graphics, and Mr. James's routines definitely are fast. In my routines I have come up with another approach, which, I believe, is slightly faster in displaying icons. Since the EGA is latched, you must determine which planes will be accessed during a write, a clock cycle consuming process. Mr. James's routines store one byte per pixel, enabling 128 colors and an intensity bit. If the format of the sprite were laid out plane by plane rather than pixel by pixel, the function could set the registers for a plane and then write all the data for that plane. The function would continue plane by plane, only setting up the register once per plane per icon. Additionally, the EGA does not allow bit access. So why not place a byte's worth of data on the screen during each write rather than only one new bit? I enjoy seeing quality articles every time I open a new issue of DDJ. Keep it up!

Peder Jungck,

Stanwood Assoc.

Chicago, Illinois

On Location

Dear DDJ,

The excellent article "Location is Everything," by Mark Nelson, (January, 1990) was most timely. Once again DDJ came up with just what I wanted just when I needed it. I think, however, there is a small problem with the code.

Mark uses the exe header field "Displacement of stack in Paras" (0e) to locate the start of the initialized data area. This works only when the amount of initialized data is less than one paragraph long since the stack displacement corresponds to the end of the initialized data area. In the general case, the program needs the starting paragraph. I was able to easily find this value by parsing it out of the .MAP file. Using this value in the relocation function causes the program to perform as advertised.

/* input_base_data_segment is a global unsigned int */ 
/* data_seg is declared as char data_seg[81] */ 
/* map_file is a FILE* to the .MAP file created by */ 
/* Scan the .map file for the word "BSS" */ 

while(strcmp(data_seg, "BSS") ! = 0) 
	fscanf(map_file, "%s", data_seg); 
/* The next field in the file is the location of the */ 
/* data. */ 
fscanf(map_file, "%s", data_seg); 
data_seg[strlen(data_seg)- 1 ] = ' \ 0'; 
/*kill the 'H'*/ 
input_base_data_segment = htoi(data_seg) >> 4;

In the function process_relocation_table( ), replace all references to the variable first_data_segment_in_exe_ file with input_base_data_segment.

Stephen J. Beaver

Winchester, Virginia

Mark responds: As Stephen Beaver notes, there is a field in the header portion of an EXE file that tells me where the start of the program stack segment is located. I use this field to determine where RAM data starts in the EXE file. Mr. Beaver must have taken note of the lines in my START.ASM file shown below. Because the stack segment follows the DATA, BSS, and CONST segments, Mr. Beaver concludes that the value I calculate for the start of RAM actually points past all these segments. However, there is an additional segment definition line a little farther down in the START.ASM file:

DGROUP GROUP_CONST, _BSS, _DATA, _STACK

This statement causes the compiler and linker to gather all four of these segments together into one segment. This means that all four segments are collected together, and the pointer to the start of the stack segment will actually point to the start of DGROUP, which will be at the start of the_CONST segment. So, if you use the START.ASM startup file as I required, the LOCATE.EXE program will work properly. By the way, Mr. Beaver "solved" this problem by modifying my LOCATE program to read in a MAP file that the linker has produced. Reading in MAP files to drive a Locate program is not a bad approach. In fact, Jensen & Partners International are providing a TSLOCATE utility with their new TopSpeed C compiler, which does just that. I chose to avoid this approach for a couple of reasons. First, there is no standard MAP file format. Every linker is free to create their own format, and a good LOCATE program would be forced to continually adapt to these. Second, a program using this approach is vulnerable to errors caused when the MAP file is not actually the one from the latest link. Because the information I wanted was in the EXE file, and the EXE format is standardized across all MS-DOS compilers, I elected to not read in the MAP file. I hope this clears up some of the confusion. Dealing with program segments at a low level is usually concealed from HLL programmers by the compiler, for which we can all give thanks.

_TEXT                          SEGMENT BYTE PUBLIC 'CODE'   
_TEXT                          ENDS
END_OF_ROM                     SEGMENT PARA PUBLIC 'STARTUP_CODE'
END_OF_ROM                     ENDS
_CONST                         SEGMENT PARA PUBLIC 'CONST'
_CONST                         ENDS
_BSS                           SEGMENT WORD PUBLIC 'BSS'
_BSS                           ENDS
_DATA                          SEGMENT WORD PUBLIC 'DATA'
_DATA                          ENDS
_STACK                         SEGMENT WORD STACK 'STACK
MYSTACK                        DB 512 DUP (?)
_STACK                         ENDS

Random Structures

Dear DDJ,

This is in response to the December 1989 letter by Dan W. Crockett. He is treating the term "structured" and the term "modular" as being equivalent. A structured module, program, or system need not be modular, and a module may or may not be structured. Also, a module, program, or system that has "spaghetti code" has a structure. It is called a random structure.

One of the purposes of using modules is that the code is reusable. We use this all the time. The modules are in libraries. Examples are the Fortran library routine SIN(x), the Cobol COPYLIB file, and the C library routine sin(x). The proper term for module tree relationship is a "caller" module and a "called" module. This describes the relationship much better than the "father" - "son" model. Further, a module should not know anything about the "caller" module, other than what is in its argument list. Can you imagine the chaos that would result if we had to rewrite SIN(x) or sin(x) every time they had more than one caller?

Ned Logan

Seattle, Washington

Pascal Participation, Pleeez

Dear DDJ,

After reading Terry Ritter's letter entitled "Standardizing the Standardizing Process" in your February 1990 "Letters" column, I have the feeling that many readers may not understand the standardization process and will be given a false impression.

Membership on X3J9, the other X3 committees, and the IEEE committees is not restricted to some elitist group. Membership is open to all interested parties who are willing to participate. Users are especially encouraged to participate.

Decisions are not made in a back room behind closed doors. Committee meetings are open to the public with visitors and observers not only welcome but encouraged. Likewise, committee documents are open to the public and people who cannot attend meetings can become official observers and receive all committee mailings.

Consensus is the method by which most decisions are made both at the international level and at the domestic level for Pascal. However, it is the consensus of those who participate.

It was not only the consensus, but the unanimous vote of both the International Working Group on Pascal and the American National Standards Committee on Pascal that no action be taken on some of Mr. Ritter's comments for the Extended Pascal standard. The main reason for this was that major changes and development would have been required and it was felt that this should be handled separately rather than unduly delay the standard, which was in its final stages of review.

This does not mean that his comments have been shoved under the table. Many of the areas brought up by his comments, including exception handling, alphanumeric labels, and multiple arithmetic data types, are being worked on by the committee. The intent is to issue information bulletins, technical reports, and addenda to standards when work on them is completed. User participation is encouraged in this work, especially now when it is still in a nearly stage of development.

The committee is also now beginning to look at object-oriented extensions to Pascal, and has submitted a project proposal to its parent bodies for approval of this work. It is expected that approval will be received early this year. When this approval is received, announcements will be submitted to all publications (including Dr. Dobb's and similar user-oriented publications) that might have an interested audience.

People from Apple, Borland, Microsoft, and other vendors are planning to participating in the object work. User's views, and user participation, at this early stage would be especially welcome.

I encourage Mr. Ritter and other users to participate in Pascal and other standardization efforts. No one needs to elect you. All you need to do is participate.

For users that do not have financial support, there are organizations (such as SIGPLAN) that have funds allocated for this purpose.

To find out more about participating in the Pascal standards activity please contact me by letter, phone, FAX, or e-mail.

Thomas N. Turba

Chairman X3J9, Pascal

Unisys Corp.,

MS: WE3C

P.O. Box 64942

St. Paul, MN 55164

612-635-2349;

612-635-2003 (Fax)

NET: turba@rsvl.unisys.

comuunet!s5000!turba

There's More than One Way to Get From Pascal to C, or Return of the Living Fugu-Eater

Dear DDJ,

I too enjoy Jeff Duntemann's writings, though not for the same reason as does Dale Lucas ("Letters," Jan. 1990). I love a good argument. So I get a kick out of reading Jeff's ravings against C, all the while thinking up incontrovertible (I'm sure they must be) refutations.

I do agree with him that C is ugly. It looks like Dagwood's dialogue after he hammers his thumb, %*!&()*#$@! But I put up with that for the sake of the language's abilities. Jeff, on the other hand, sees no redeeming value in C, whatsoever, as we were so forcefully reminded in the January issue.

Recall that Dale Lucas asked him whether there's a way to call a third-party (sans source) C library's routines from a Turbo Pascal program. This little spark lit the fuse to one of Jeff's best tirades to date, in which he accused C programmers of acting macho, of neglecting to neck with their spouses and play with their dogs, and (this was the killer blow) of EATING FUGU!

Oh boy, did he give it to us. Unfortunately, he got so carried away with his ranting twaddle that he neglected to help his Pascal co-linguist. He told Dale to rewrite the whole library in Pascal!

If you don't mind taking advice from a fugu-eater, Dale, I think there's a way to hook those C routines. But first a question: Doesn't Turbo Pascal have something akin to Microsoft's "[C]" attribute, which you append to a procedure declaration to tell the compiler to use C's calling and naming conventions? Guess not, or the problem would be trivial and you wouldn't have written.

So you'll need to turn to a more powerful language -- ummmh, let's say C -- to write the hooks. Your third-party library will have given you a header file, for instance "WINDOW.H," declaring its functions. For example:

int WinCreate(int height, int width, int color);

void WinOpen(int winnumber, int xcord, int ycord);

And so forth. Add to this file a new Pascal-callable hook function for each declaration, thusly:

int pascal HOOK_WinCreate(int height, int width, int color) {

return( WinCreate(height, width, color)); }

void pascal HOOK_WinOpen(int win-number, int xcord, int ycord.)
{WinOpen(winnumber, xcord, ycord); return;}

Rename the file, say to "HOOK.C," and compile it. Finally, translate the hook function prototypes into declarations for your Pascal modules:

function HOOK_WinCreate (height,width,color : integer) : integer; extern;

procedure HOOK_WinOpen (winnumber,xcord,ycord : integer) :extern;

(Do I have that right? I read Pascal but speak it poorly.) The C code above works on my Watcom compiler, and ought to work on QuickC as well. Of course, I've begged the more difficult questions like memory models and translating C strings and structures into Pascal. But this might be enough to get you started.

A couple of closing questions. Dale . . . wouldn't it be easier just to code your app in a real-man's language like C? And Jeff . . . what the hell IS fugu, anyhow?

Bob Twilling

Bozeman, Montana

Dear DDJ,

In your January issue, you printed a letter from Dale Lucas asking for help interfacing Turbo Pascal to C. Jeff Duntemann's response spent more effort bashing C than helping Mr. Lucas. I'm not particularly fond of C either, but I think I have a very simple solution.

I know nothing about Turbo Pascal, but if it uses (or can be made to use) the same calling convention as Microsoft Pascal, we're in luck. Simply use Microsoft QuickC to create one-line helper functions that translate the calling conventions. These helper functions would be declared as "pascal" functions, and thus be callable directly by Pascal. The only statement in the function would be a call to the library function using the C calling convention. For example:

int cdecl foobarC(int,int);
/* This is in the library
*/ int pascal foobarPascal(int arg1, int arg2)
{
return ( foobarC(arg1, arg2));
}

This assumes the C-based library has a function called foobarC( ), which has two integer arguments and an integer return value. The function foobarPascal( ) passes the arguments in the return value out.

  Tim Paterson
  Renton, Washington

Dear DDJ,

This letter is in response to Jeff Duntemann's answer to Dale Lucas's letter in the January 1990 issue of Dr. Dobb's Journal.

I disagree with Jeff's answer. A Pascal routine can call a C routine by using an impedance matching routine written in assembly. The routine takes the Pascal arguments, pushes them on the stack, calls the C routine, cleans up the arguments pushed, and then cleans up the stack for the Pascal caller. A macro can be built, which has the Pascal entry point, the matching C entry point, and the size of the arguments in bytes. The macro CHook in Listing One (below) implements this.

The Pascal programmer simply calls the Pascal entry point. The impedance matcher handles the language differences and returns. Simple, easy, and direct. Much better than recoding a debugged, commercial library.

By placing the code in a macro, the user can just build a table of macro calls which reflect all entries to the C library. Each macro expands and builds the impedance matching code for each library entry point.

Some notes involving the use of the macro:

This code has not been tested with Turbo Pascal. It has only been tested using a Microsoft C program (Listing One) that calls the Pascal entry using the pascal keyword. If the macro doesn't work with Turbo Pascal, it should only take a small amount of tweaking to make it work. The key is to draw a picture of your stack frame and test it in Debug, following the argument flow.

Jim Shimandle,

Primary Syncretics

Santa Clara, Calif.

_LETTERS TO THE EDITOR_ DDJ, April 1990 [LISTING ONE]



;
; c2pas.asm
; C/PASCAL impedence matching module
;
        .model large
code   segment para public 'code'

;----------------------------------------------------

CHook   MACRO   PascalEntry, CEntry, ArgSize
   EXTRN   CEntry:FAR
   PUBLIC   PascalEntry
PascalEntry   PROC

   PUSH   BP      ;Make stack frame
   MOV   BP,SP

   PUSH   CX
   PUSH   SI
   PUSH   DI
   PUSH   DS

   MOV   CX,SS      ; Set DS to point to stack
   MOV   DS,CX

   SUB   SP, ArgSize   ; Save space for arguments
   MOV   CX, ArgSize   ; Set count for arg transfer
   MOV   SI, BP      ; Get frame pointer
   ADD   SI, 6      ; Point to start of PASCAL arguments
   MOV   DI, SP      ; Point to start of C arguments
   CLD         ; Move is up
   REP MOVSB      ; Move the arguments

   CALL    CEntry      ; Call the C routine
   ADD   SP, ArgSize   ; Remove arguments from stack

   POP   DS
   POP   DI
   POP   SI
   POP   CX

   POP   BP      ; Restore frame
   RET   ArgSize      ; Exit

PascalEntry   ENDP
   ENDM

;--------------------------------------------------------

; Invoke macro for test routine

CHook    p_sum3, _c_sum3, 6   ; Invoke macro for
            ;   p_sum3 is PASCAL call
            ;   c_sum3 is C library routine
            ;   6 is the number of argument bytes

;--------------------------------------------------------

code   ends
   end

;
; end of c2pas.asm
;