summaryrefslogtreecommitdiff
path: root/v2.0/source/SYSCALL.txt
diff options
context:
space:
mode:
authorGravatar Rich Turner1983-08-12 17:53:34 -0700
committerGravatar Rich Turner2018-09-21 17:53:34 -0700
commit80ab2fddfdf30f09f0a0a637654cbb3cd5c7baa6 (patch)
treeee4357f7f3dd0f2ded59b9c6e7384432d85e7ec9 /v2.0/source/SYSCALL.txt
parentMS-DOS v1.25 Release (diff)
downloadms-dos-80ab2fddfdf30f09f0a0a637654cbb3cd5c7baa6.tar.gz
ms-dos-80ab2fddfdf30f09f0a0a637654cbb3cd5c7baa6.tar.xz
ms-dos-80ab2fddfdf30f09f0a0a637654cbb3cd5c7baa6.zip
MS-DOS v2.0 Release
Diffstat (limited to 'v2.0/source/SYSCALL.txt')
-rw-r--r--v2.0/source/SYSCALL.txt1657
1 files changed, 1657 insertions, 0 deletions
diff --git a/v2.0/source/SYSCALL.txt b/v2.0/source/SYSCALL.txt
new file mode 100644
index 0000000..26d4729
--- /dev/null
+++ b/v2.0/source/SYSCALL.txt
@@ -0,0 +1,1657 @@
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 MS-DOS 2.0
20
21 System Calls Reference
22
23
24
25
26
27
28
29
30
31
32
33
34+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
35| |
36| C A V E A T P R O G R A M M E R |
37| |
38| Certain structures, constants and system calls below |
39| are private to the DOS and are extremely |
40| version-dependent. They may change at any time at the |
41| implementors' whim. As a result, they must not be |
42| documented to the general public. If an extreme case |
43| arises, they must be documented with this warning. |
44| |
45| Those structures and constants that are subject to the |
46| above will be marked and bracketed with the flag: |
47| |
48| C A V E A T P R O G R A M M E R |
49| |
50+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 Section 1
70
71 Extensions to existing call structure
72
73
74 Name: * Alloc - allocate memory
75
76 Assembler usage:
77 MOV BX,size
78 MOV AH,Alloc
79 INT 21h
80 ; AX:0 is pointer to allocated memory
81 ; if alloc fails, BX is the largest block available
82
83 Description:
84 Alloc returns a pointer to a free block of memory
85 that has the requested size in paragraphs.
86
87 Error return:
88 AX = error_not_enough_memory
89 The largest available free block is smaller
90 than that requested or there is no free block.
91 = error_arena_trashed
92 The internal consistency of the memory arena
93 has been destroyed. This is due to a user
94 program changing memory that does not belong
95 to it.
96
97
98 Name: * CharOper - change incompatible configuration
99 parameters
100
101 Assembler usage:
102 MOV AH, CharOper
103 MOV AL, func
104 MOV DL, data
105 INT 21h
106 ; on read functions, data is returned in DL
107
108 Description:
109 CharOper allows a program to change system
110 parameters to allow for switch indicators and whether
111 devices are available at every level of the directory
112 tree.
113
114 A function code is passed in AL:
115
116 AL Function
117 -- --------
118 0 DL, on return, will contain the DOS switch
119 character. On most systems this will default to
120 '-'.
121 1 Set the switch character to the character in DL.
122 2 Read the device availability byte into DL. If
123 this byte is 0, then devices must be accessed in
124 file I/O calls by /dev/device. If this byte is
125 non-zero, then the devices are available at every
126 node of the directory tree (i.e. CON is the
127 console device not the file CON). This byte is
128 generally 0.
129 3 Set the device availability byte to the value in
130 DL.
131
132 Error returns:
133 AL = FF
134 The function code specified in AL is not in
135 the range 0:3
136
137
138 Name: * CurrentDir - return text of current directory
139
140 Assembler usage:
141 MOV AH,CurrentDir
142 LDS SI,area
143 MOV DL,drive
144 INT 21h
145 ; DS:SI is a pointer to 64 byte area that contains
146 ; drive current directory.
147
148 Description:
149 CurrentDir returns the current directory for a
150 particular drive. The directory is root-relative and
151 does not contain the drive specifier. The drive code
152 passed in DL is 0=default, 1=A, 2=B, etc.
153
154 Error returns:
155 AX = error_invalid_drive
156 The drive specified in DL was invalid.
157
158
159 Name: * Dealloc - free allocated memory
160
161 Assembler usage:
162 MOV ES,block
163 MOV AH,dealloc
164 INT 21h
165
166 Description:
167 Dealloc returns a piece of memory to the system
168 pool that was allocated by alloc.
169
170 Error return:
171 AX = error_invalid_block
172 The block passed in ES is not one allocated
173 via Alloc.
174 = error_arena_trashed
175 The internal consistency of the memory arena
176 has been destroyed. This is due to a user
177 program changing memory that does not belong
178 to it.
179
180
181 Name: * FileTimes - get/set the write times of a
182 handle
183
184 Assembler usage:
185 MOV AH, FileTimes
186 MOV AL, func
187 MOV BX, handle
188 ; if AL = 1 then then next two are mandatory
189 MOV CX, time
190 MOV DX, date
191 INT 21h
192 ; if AL = 0 then CX/DX has the last write time/date
193 ; for the handle.
194
195 Description:
196 FileTimes returns or sets the last-write time for
197 a handle. These times are not recorded until the file
198 is closed.
199
200 A function code is passed in AL:
201
202 AL Function
203 -- --------
204 0 Return the time/date of the handle in CX/DX
205 1 Set the time/date of the handle to CX/DX
206
207 Error returns:
208 AX = error_invalid_function
209 The function passed in AL was not in the range
210 0:1.
211 = error_invalid_handle
212 The handle passed in BX was not currently
213 open.
214
215
216 Name: * FindFirst - find matching file
217
218 Assembler usage:
219 MOV AH, FindFirst
220 LDS DX, pathname
221 MOV CX, attr
222 INT 21h
223 ; DMA address has datablock
224
225 Description:
226 FindFirst takes a pathname with wildcards in the
227 last component (passed in DS:DX), a set of attributes
228 (passed in CX) and attempts to find all files that
229 match the pathname and have a subset of the required
230 attributes. A datablock at the current DMA is written
231 that contains information in the following form:
232
233 find_buf STRUC
234+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
235| C A V E A T P R O G R A M M E R |
236| |
237 find_buf_sattr DB ? ; attribute of search
238 find_buf_drive DB ? ; drive of search
239 find_buf_name DB 11 DUP (?); search name
240 find_buf_LastEnt DW ? ; LastEnt
241 find_buf_ThisDPB DD ? ; This DPB
242 find_buf_DirStart DW ? ; DirStart
243| |
244| C A V E A T P R O G R A M M E R |
245+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
246
247 find_buf_attr DB ? ; attribute found
248 find_buf_time DW ? ; time
249 find_buf_date DW ? ; date
250 find_buf_size_l DW ? ; low(size)
251 find_buf_size_h DW ? ; high(size)
252 find_buf_pname DB 13 DUP (?) ; packed name
253 find_buf ENDS
254
255 To obtain the subsequent matches of the pathname,
256 see the description of FindNext
257
258 Error Returns:
259 AX = error_file_not_found
260 The path specified in DS:DX was an invalid
261 path.
262 = error_no_more_files
263 There were no files matching this
264 specification.
265
266
267 Name: * FindNext - step through a directory matching
268 files
269
270 Assembler usage:
271 ; DMA points at area returned by find_first
272 MOV AH, findnext
273 INT 21h
274 ; next entry is at dma
275
276 Description:
277 FindNext finds the next matching entry in a
278 directory. The current DMA address must point at a
279 block returned by FindFirst (see FindFirst).
280
281 Error Returns:
282 AX = error_no_more_files
283 There are no more files matching this pattern.
284
285
286 Name: * GetDMA - get current DMA transfer address
287
288 Assembler usage:
289 MOV AH,GetDMA
290 INT 21h
291 ; ES:BX has current DMA transfer address
292
293 Description:
294 Return DMA transfer address.
295
296 Error returns:
297 None.
298
299+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
300| C A V E A T P R O G R A M M E R |
301| |
302
303 Name: * GetDSKPT(DL) - get pointer to drive parameter
304 block
305
306 Assembler usage:
307 MOV AH,GetDSKPT
308 INT 21h
309 ; DS:BX has address of drive parameter block
310
311 Description:
312 Return pointer to default drive parameter block.
313
314 Error returns:
315 None.
316
317 Assembler usage:
318 MOV DL,DrvNUM
319 MOV AH,GetDSKPTDL
320 INT 21h
321 ; DS:BX has address of drive parameter block
322
323 Description:
324 Return pointer to drive parameter block for drive
325 designated in DL (0=Default, A=1, B=2 ...)
326
327 Error returns:
328 AL = FF
329 The drive given in DL is invalid.
330| |
331| C A V E A T P R O G R A M M E R |
332+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
333
334
335 Name: * GetFreespace - get Disk free space
336
337 Assembler usage:
338 MOV AH,GetFreespace
339 MOV DL,Drive ;0 = default, A = 1
340 INT 21h
341 ; BX = Number of free allocation units on drive
342 ; DX = Total number of allocation units on drive
343 ; CX = Bytes per sector
344 ; AX = Sectors per allocation unit
345
346 Description:
347 Return Free space on disk along with additional
348 information about the disk.
349
350 Error returns:
351 AX = FFFF
352 The drive number given in DL was invalid.
353
354 NOTE: This call returns the same information in the same
355 registers (except for the FAT pointer) as the get FAT
356 pointer calls did in previous versions of the DOS.
357
358
359 Name: * GetInDOSF - get DOS critical-section flag
360
361 Assembler usage:
362 MOV AH,GetInDOSF
363 INT 21h
364 ; ES:BX has location of the flag
365 MOV CritSEG, ES
366 MOV CritOFF, BX
367 ...
368 IntVec:
369 MOV AX, DWORD PTR Crit
370 CMP AX,0
371 JZ DoFunc
372 IRET
373 DoFunc: ...
374
375 Description:
376 Return location of indos flag. On return ES:BX is
377 the address of a byte memory cell inside the DOS. If
378 used in an interrupt service routine, it indicates
379 whether or not the DOS was interrupted in a critical
380 section. If the cell was zero, then the DOS was not
381 in a critical section and thus can be called by the
382 interrupt routine. If the cell was non-zero, the DOS
383 should be considered to be in an uninterruptable state
384 and for reliability, no DOS calls should be given.
385
386 Error returns:
387 None.
388
389
390 Name: * GetVector - get interrupt vector
391
392 Assembler usage:
393 MOV AH,GetVector
394 MOV AL,interrupt
395 INT 21h
396 ; ES:BX now has long pointer to interrupt routine
397
398 Description:
399 Return interrupt vector associated with an
400 interrupt.
401
402 Error returns:
403 None.
404
405
406 Name: * GetVerifyFlag - return current setting of the
407 verify after write flag.
408
409 Assembler usage:
410 MOV AH,GetVerifyFlag
411 INT 21h
412 ; AL is the current verify flag value
413
414 Description:
415 The current value of the verify flag is returned
416 in AL.
417
418 Error returns:
419 None.
420
421
422 Name: * GetVersion - get DOS version number
423
424 Assembler usage:
425 MOV AH,GetVersion
426 INT 21h
427 ; AL is the major version number
428 ; AH is the minor version number
429 ; BH is the OEM number
430 ; BL:CX is the (24 bit) user number
431
432 Description:
433 Return MS-DOS version number. On return AL.AH
434 will be the two part version designation, ie. for
435 MS-DOS 1.28 AL would be 1 and AH would be 28. For pre
436 1.28 DOS AL = 0. Note that version 1.1 is the same as
437 1.10, not the same as 1.01.
438
439 Error returns:
440 None.
441
442
443 Name: * International - return country dependent
444 information
445
446 Assembler usage:
447 LDS DX, blk
448 MOV AH, International
449 MOV AL, func
450 INT 21h
451
452 Description:
453 This call returns in the block of memory pointed
454 to by DS:DX, the following information pertinent to
455 international applications:
456
457 +---------------------------+
458 | WORD Date/time format |
459 +---------------------------+
460 | BYTE ASCIZ string |
461 | currency symbol |
462 +---------------------------+
463 | BYTE ASCIZ string |
464 | thousands separator |
465 +---------------------------+
466 | BYTE ASCIZ string decimal |
467 | separator |
468 +---------------------------+
469
470 The date/time format has the following values and
471 meanings:
472
473 0 - USA standard h:m:s m/d/y
474 1 - Europe standard h:m:s d/m/y
475 2 - Japan standard y/m/d h:m:s
476
477 The value passed in AL is either 0 (for current
478 country) or a country code (to be defined later.
479 Currently the country code must be zero).
480
481 Error returns:
482 AX = error_invalid_function
483 The function passed in AL was not 0
484 (currently).
485
486
487 Name: * KeepProcess - terminate process and remain
488 resident
489
490 Assembler usage:
491 MOV AL, exitcode
492 MOV DX, parasize
493 MOV AH, KeepProcess
494 INT 21h
495
496 Description:
497 This call terminates the current process and
498 attempts to set the initial allocation block to a
499 specific size in paragraphs. It will not free up any
500 other allocation blocks belonging to that process.
501 The exit code passed in AX is retrievable by the
502 parent via Wait.
503
504 Error Returns:
505 None.
506
507
508 Name: * Rename - move a directory entry
509
510 Assembler usage:
511 LDS DX, source
512 LES DI, dest
513 MOV AH, Rename
514 INT 21h
515
516 Description:
517 Rename will attempt to rename a file into another
518 path. The paths must be on the same device.
519
520 Error returns:
521 AX = error_file_not_found
522 The file name specifed by DS:DX was not found.
523 = error_not_same_device
524 The source and destination are on different
525 drives.
526 = error_access_denied
527 The path specified in DS:DX was a directory or
528 the file specified by ES:DI exists or the
529 destination directory entry could not be
530 created.
531
532
533 Name: * SetBlock - modify allocated blocks
534
535 Assembler usage:
536 MOV ES,block
537 MOV BX,newsize
538 MOV AH,setblock
539 INT 21h
540 ; if setblock fails for growing, BX will have the
541 ; maximum size possible
542
543 Description:
544 Setblock will attempt to grow/shrink an allocated
545 block of memory.
546
547 Error return:
548 AX = error_invalid_block
549 The block passed in ES is not one allocated
550 via Alloc.
551 = error_arena_trashed
552 The internal consistency of the memory arena
553 has been destroyed. This is due to a user
554 program changing memory that does not belong
555 to it.
556 = error_not_enough_memory
557 There was not enough free memory after the
558 specified block to satisfy the grow request.
559
560
561 Name: * SetCtrlCTrapping - turn on/off broad ^C
562 checking
563
564 Assembler usage:
565 MOV DL,val
566 MOV AH,SetCtrlCTrapping
567 MOV AL,func
568 INT 21h
569 ; If AL was 0, then DL has the current value of the
570 ; ^C check
571
572 Description:
573 MSDOS ordinarily checks for a ^C on the
574 controlling device only when doing a function 1-12
575 operation to that device. SetCtrlCTrapping allows the
576 user to expand this checking to include any system
577 call. For example, with the ^C trapping off, all disk
578 I/O will proceed without interruption while with ^C
579 trapping on, the ^C interrupt is given at the system
580 call that initiates the disk operation.
581
582 Error return:
583 AL = FF
584 The function passed in AL was not in the range
585 0:1.
586
587+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
588| C A V E A T P R O G R A M M E R |
589| |
590
591 Name: * Set_OEM_Handler - set handler for OEM
592 specific INT 21H calls.
593
594 Assembler usage:
595 LDS DX,handler_address
596 MOV AH,Set_OEM_Handler
597 INT 21H
598
599 Description:
600 Set handler address for 0F9H-0FFH INT 21H system
601 calls to DS:DX. To return the 0F9H-0FFH calls to
602 the uninitialized state, give DS=DX=-1.
603
604 Error returns:
605 None.
606
607 Handler entry:
608 All registers as user set them when INT 21H
609 issued (including SS:SP). INT 21 return is on
610 stack, so the correct method for the OEM handler
611 to return to the user is to give an IRET. The
612 OEM handler is free to make any INT 21H system
613 call (including the 0F9H- 0FFH group if the OEM
614 handler is re-entrant).
615
616
617 The AH INT 21H function codes 0F8H through 0FFH are
618 reserved for OEM extensions to the INT 21H calling
619 convention. These calls have two states, initialized
620 and uninitialized. There will be one handler for all 7
621 (0F9-0FFH) functions. When the DOS is first
622 initialized, these calls are uninitialized. The AH=0F8H
623 call is the call which will set the handler address for
624 the 0F9-0FFH calls. If the 0F9-0FFH calls are
625 uninitialized, an attempt to call them results in the
626 normal invalid system call number return.
627 OEMs should NOT document the 0F8 call.
628| |
629| C A V E A T P R O G R A M M E R |
630+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649 Section 2
650
651 XENIX-compatible system calls
652
653
654
655 Previous to version 2.0, MSDOS had a simple single
656 directory structure that sufficed for small (160k to 320K)
657 diskettes. As the need for hard disk support grows, and
658 as MSDOS 2.0 will support a wide variety of hard disks,
659 the need for better disk organization also grows. Merely
660 expanding the directory is not an effective solution;
661 doing a 'DIR' on a directory with 1000 files is not a
662 user-friendly characteristic.
663
664 People, by nature, think in hierarchical terms:
665 organization charts and family trees, for example. It
666 would be nice to allow users to organize their files on
667 disk in a similar manner. Consider the following:
668
669 In a particular business, both sales and accounting
670 share a computer with a large disk and the individual
671 employees use it for preparation of reports and
672 maintaining accounting information. One would naturally
673 view the organization of files on the disk in this
674 fashion:
675
676 +-disk-+
677 / \
678 / \
679 / \
680 sales accounting
681 / | | \
682 / | | \
683 / | | \
684 John Mary Steve Sue
685 / | (A) | | | \
686 / | | | | \
687 / | | | | \
688 report accts. report accts. report report
689 receiv. receiv
690
691 In MSDOS 2.0 the user can arrange his files in such a
692 manner that files that are not part of his current task do
693 not interfere with that task. Pre-2.0 versions of MSDOS
694 has a single directory that contains files. MSDOS extends
695 this concept to allow a directory to contain both files
696 and directories and to introduce the notion of the
697 'current' directory.
698
699 To specify a filename, the user could use one of two
700 methods, either specify a path from the root node to the
701 file, or specify a path from the current node to the file.
702 A path is a series of directory names separated by '/' and
703 ending with a filename. A path that starts at the root
704 begins with a '/'.
705
706 There is a special directory entry in each directory,
707 denoted by '..' that is the parent of the directory. The
708 root directory's parent is itself (who created God?).
709
710 Using a directory structure like the hierarchy above,
711 and assuming that the current directory is at point (D),
712 to reference the report under John, the following are all
713 equivalent:
714
715 report
716 /sales/John/report
717 ../John/report
718
719 To refer to the report under Mary, the following are
720 all equivalent:
721
722 ../Mary/report
723 /sales/Mary/report
724
725 To refer to the report under Sue, the following are
726 all equivalent.
727
728 ../../accounting/Sue/report
729 /accounting/Sue/report
730
731 There is no restriction in MSDOS 2.0 on the depth of a
732 tree (the length of the longest path from root to leaf)
733 except in the number of allocation units available. The
734 root directory will have a fixed number of entries, 64 for
735 the single sided diskettes to XXX for a large hard disk.
736 For non-root directories, there is no limit to the number
737 of files per directory excepting in the number of
738 allocation units available.
739
740 Old (pre-2.0) disks will appear to MSDOS 2.0 as having
741 only a root directory with files in it and no
742 subdirectories whatever.
743
744 Implementation of the tree-structure is simple. The
745 root directory is the pre-2.0 directory. Subdirectories
746 of the root have a special attribute set indicating that
747 they are directories. The subdirectories themselves are
748 files, linked through the FAT as usual. Their contents
749 are identical in character to the contents of the root
750 directory.
751
752 Pre-2.0 programs that use system calls not described
753 below will not be able to make use of files in other
754 directories. They will only be able to access files in
755 the current directory. This is no great loss of
756 functionality as users will aggregate their files into
757 sub-directories on basis of functionality; the files that
758 are being used will be found in the current directory.
759 Those that are not necessary for the current task will be
760 placed in other directories. Out of sight, out of mind.
761
762 There are also new attributes in 2.0. These and the
763 old attributes apply to the tree structured directories in
764 the following manner:
765
766 Attribute Meaning/Function Meaning/Function
767 for files for directories
768
769 volume_id Present at the root. Meaningless.
770 Only one file may have
771 this set.
772
773 directory Meaningless. Indicates that the
774 directory entry is a
775 directory. Cannot be
776 changed with ChMod.
777
778 read_only Old fcb-create, new Meaningless.
779 Creat, new open (for
780 write or read/write)
781 will fail.
782
783 archive Set when file is Meaningless.
784 written. Set/reset via
785 ChMod.
786
787 hidden/ Prevents file from Prevents directory
788 system being found in search entry from being
789 first/search next. found. ChDir to
790 New open will fail. directory will still
791 work.
792
793
794 Name: * ChDir - Change the current directory
795
796 Assembler usage:
797 LDS DX, name
798 MOV AH, ChDir
799 INT 21h
800
801 Description:
802 ChDir is given the ASCIZ name of the directory
803 which is to become the current directory. If any
804 member of the specified pathname does not exist, then
805 the current directory is unchanged. Otherwise, the
806 current directory is set to the string.
807
808 Error returns:
809 AX = error_path_not_found
810 The path specified in DS:DX either indicated a
811 file or the path was invalid.
812
813
814 Name: * ChMod - change write protection
815
816 Assembler usage:
817 LDS DX, name
818 MOV CX, attribute
819 MOV AL, func
820 MOV AH, ChMod
821 INT 21h
822
823 Description:
824 Given an ASCIZ name, ChMod will set/get the
825 attributes of the file to those given in CX.
826
827 A function code is passed in AL:
828
829 AL Function
830 -- --------
831 0 Return the attributes of the file in CX
832 1 Set the attributes of the file to those in CX
833
834 Error returns:
835 AX = error_path_not_found
836 The path specified was invalid.
837 = error_access_denied
838 The attributes specified in CX contained one
839 that could not be changed (directory, volume
840 ID).
841 = error_invalid_function
842 The function passed in AL was not in the range
843 0:1.
844
845
846 Name: * Close - close a file handle
847
848 Assembler usage:
849 MOV BX, handle
850 MOV AH, Close
851 INT 21h
852
853 Description:
854 In BX is passed a file handle (like that returned
855 by Open, Creat or Dup); the Close call will close the
856 associated file. Internal buffers are flushed.
857
858 Error return:
859 AX = error_invalid_handle
860 The handle passed in BX was not currently
861 open.
862
863
864 Name: * Creat - create a file
865
866 Assembler usage:
867 LDS DX, name
868 MOV AH, Creat
869 MOV CX, attribute
870 INT 21h
871 ; AX now has the handle
872
873 Description:
874 Creat creates a new file or truncates an old file
875 to zero length in preparation for writing. If the
876 file did not exist, then the file is created in the
877 appropriate directory and the file is given the
878 read/write protection code of access.
879
880 CX contains the default attributes to be set for
881 the file. Currently, the read-only bit must be off.
882
883 Error returns:
884 AX = error_access_denied
885 The attributes specified in CX contained one
886 that could not be created (directory, volume
887 ID), a file already existed with a more
888 inclusive set of attributes, or a directory
889 existed with the same name.
890 = error_path_not_found
891 The path specified was invalid.
892 = error_too_many_open_files
893 The file was created with the specified
894 attributes, but there were no free handles
895 available for the process or that the internal
896 system tables were full.
897
898
899 Name: * Dup - duplicate a file handle
900
901 Assembler usage:
902 MOV BX, fh
903 MOV AH, Dup
904 INT 21h
905 ; AX has the returned handle
906
907 Description:
908 Dup takes an already opened file handle and
909 returns a new handle that refers to the same file at
910 the same position.
911
912 Error returns:
913 AX = error_invalid_handle
914 The handle passed in BX was not currently
915 open.
916 = error_too_many_open_files
917 There were no free handles available in the
918 current process or the internal system tables
919 were full.
920
921
922 Name: * Dup2 - force a duplicate of a handle
923
924 Assembler usage:
925 MOV BX, fh
926 MOV CX, newfh
927 MOV AH, Dup2
928 INT 21h
929
930 Description:
931 Dup2 will cause newfh to refer to the same stream
932 as fh. If there was an open file on newfh, then it is
933 closed first.
934
935 Error returns:
936 AX = error_invalid_handle
937 The handle passed in BX was not currently
938 open.
939
940
941 Name: * Exec - load / execute a program
942
943 Assembler usage:
944 LDS DX, name
945 LES BX, blk
946 MOV AH, Exec
947 MOV AL, func
948 INT 21h
949
950 Description:
951 This call allows a program to load another program
952 into memory and (default) begin execution of it.
953 DS:DX points to the ASCIZ name of the file to be
954 loaded. ES:BX points to a parameter block for the
955 load.
956
957 A function code is passed in AL:
958
959 AL Function
960 -- --------
961 0 Load and execute the program. A program header is
962 established for the program and the terminate and
963 ^C addresses are set to the instruction after the
964 EXEC system call.
965
966 NOTE: When control is returned, via a ^C or
967 terminate, from the program being EXECed ALL
968 registers are altered including the stack.
969 This is because control is returned from the
970 EXECed program, not the system. To regain
971 your stack, store an SS:SP value in a data
972 location reachable from your CS.
973
974+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
975| C A V E A T P R O G R A M M E R |
976| |
977 1 Load, create the program header but do not begin
978 execution. The CS:IP/SS:SP of the program are
979 returned in the area provided by the user.
980| |
981| C A V E A T P R O G R A M M E R |
982+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
983
984 3 Load, do not create the program header, and do not
985 begin execution. This is useful in loading
986 program overlays.
987
988 For each value of AL, the block has the following
989 format:
990
991 AL = 0 -> load/execute program
992
993 +---------------------------+
994 | WORD segment address of |
995 | environment. |
996 +---------------------------+
997 | DWORD pointer to command |
998 | line at 80h |
999 +---------------------------+
1000 | DWORD pointer to default |
1001 | FCB to be passed at 5Ch |
1002 +---------------------------+
1003 | DWORD pointer to default |
1004 | FCB to be passed at 6Ch |
1005 +---------------------------+
1006
1007+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1008| C A V E A T P R O G R A M M E R |
1009| |
1010 AL = 1 -> load program
1011
1012 +---------------------------+
1013 | WORD segment address of |
1014 | environment. |
1015 +---------------------------+
1016 | DWORD pointer to command |
1017 | line at 80h |
1018 +---------------------------+
1019 | DWORD pointer to default |
1020 | FCB to be passed at 5Ch |
1021 +---------------------------+
1022 | DWORD pointer to default |
1023 | FCB to be passed at 6Ch |
1024 +---------------------------+
1025 | DWORD returned value of |
1026 | SS:SP |
1027 +---------------------------+
1028 | DWORD returned value of |
1029 | CS:IP |
1030 +---------------------------+
1031| |
1032| C A V E A T P R O G R A M M E R |
1033+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1034
1035 AL = 3 -> load overlay
1036
1037 +---------------------------+
1038 | WORD segment address where|
1039 | file will be loaded. |
1040 +---------------------------+
1041 | WORD relocation factor to |
1042 | be applied to the image. |
1043 +---------------------------+
1044
1045 Note that all open files of a process are
1046 duplicated in the child process after an Exec. This
1047 is extremely powerful; the parent process has control
1048 over the meanings of stdin, stdout, stderr, stdaux and
1049 stdprn. The parent could, for example, write a series
1050 of records to a file, open the file as standard input,
1051 open a listing file as standard output and then Exec a
1052 sort program that takes its input from stdin and
1053 writes to stdout.
1054
1055 Also inherited (or passed from the parent) is an
1056 'environment'. This is a block of text strings (less
1057 than 32K bytes total) that convey various
1058 configurations parameters. The format of the
1059 environment is as follows:
1060
1061 (paragraph boundary)
1062 +---------------------------+
1063 | BYTE asciz string 1 |
1064 +---------------------------+
1065 | BYTE asciz string 2 |
1066 +---------------------------+
1067 | ... |
1068 +---------------------------+
1069 | BYTE asciz string n |
1070 +---------------------------+
1071 | BYTE of zero |
1072 +---------------------------+
1073
1074 Typically the environment strings have the form:
1075
1076 parameter=value
1077
1078 for example, COMMAND.COM always passes its execution
1079 search path as:
1080
1081 PATH=A:/BIN;B:/BASIC/LIB
1082
1083 A zero value of the environment address will cause the
1084 child process to inherit the parent's environment
1085 unchanged.
1086
1087 Note that on a successful return from EXEC, all
1088 registers, except for CS:IP, are changed.
1089
1090 Error return:
1091 AX = error_invalid_function
1092 The function passed in AL was not 0, 1 or 3.
1093 = error_bad_environment
1094 The environment was larger than 32Kb.
1095 = error_bad_format
1096 The file pointed to by DS:DX was an EXE format
1097 file and contained information that was
1098 internally inconsistent.
1099 = error_not_enough_memory
1100 There was not enough memory for the process to
1101 be created.
1102 = error_file_not_found
1103 The path specified was invalid or not found.
1104
1105
1106 Name: * Exit - terminate a process
1107
1108 Assembler usage:
1109 MOV AL, code
1110 MOV AH, Exit
1111 INT 21h
1112
1113 Description:
1114 Exit will terminate the current process,
1115 transferring control to the invoking process. In
1116 addition, a return code may be sent. All files open
1117 at the time are closed.
1118
1119 Error returns:
1120 None.
1121
1122
1123 Name: * Ioctl - I/O control for devices
1124
1125 Assembler usage:
1126 MOV BX, Handle
1127
1128 (or MOV BL, drive for calls AL=4,5
1129 0=default,A=1...)
1130
1131 MOV DX, Data
1132
1133 (or LDS DX, buf and
1134 MOV CX, count for calls AL=2,3,4,5)
1135
1136 MOV AH, Ioctl
1137 MOV AL, func
1138 INT 21h
1139 ; For calls AL=2,3,4,5 AX is the number of bytes
1140 ; transferred (same as READ and WRITE).
1141 ; For calls AL=6,7 AL is status returned, AL=0 if
1142 ; status is not ready, AL=0FFH otherwise.
1143
1144 Description:
1145 Set or Get device information associated with open
1146 Handle, or send/receive control string to device
1147 Handle or device.
1148
1149 The following values are allowed for func:
1150
1151 Request Function
1152 ------ --------
1153 0 Get device information (returned in DX)
1154 1 Set device information (as determined by DX)
1155 2 Read CX number of bytes into DS:DX from device
1156 control channel.
1157 3 Write CX number of bytes from DS:DX to device
1158 control channel.
1159 4 Same as 2 only drive number in BL
1160 0=default,A=1,B=2,...
1161 5 Same as 3 only drive number in BL
1162 0=default,A=1,B=2,...
1163 6 Get input status
1164 7 Get output status
1165
1166 Ioctl can be used to get information about device
1167 channels. It is ok to make Ioctl calls on regular
1168 files but only calls 0,6 and 7 are defined in that
1169 case (AL=0,6,7), all other calls return an
1170 error_invalid_function error.
1171
1172 CALLS AL=0 and AL=1
1173
1174 The bits of DX are defined as follows for calls
1175 AL=0 and AL=1. Note that the upper byte MUST be zero
1176 on a set call.
1177
1178 |
1179 15 14 13 12 11 10 9 8|7 6 5 4 3 2 1 0
1180 +--+--+--+--+--+--+-+-+-+-+-+-+-+-+-+-+
1181 | R| C| |I|E|R|S|I|I|I|I|
1182 | e| T| |S|O|A|P|S|S|S|S|
1183 | s| R| Reserved |D|F|W|E|C|N|C|C|
1184 | | L| |E| | |C|L|U|O|I|
1185 | | | |V| | |L|K|L|T|N|
1186 +--+--+--+--+--+--+-+-+-+-+-+-+-+-+-+-+
1187 |
1188
1189 ISDEV = 1 if this channel is a device
1190 = 0 if this channel is a disk file (Bits 8-15 =
1191 0 in this case)
1192
1193 If ISDEV = 1
1194
1195 EOF = 0 if End Of File on input
1196 RAW = 1 if this device is in Raw mode
1197 = 0 if this device is cooked
1198 ISCLK = 1 if this device is the clock device
1199 ISNUL = 1 if this device is the null device
1200 ISCOT = 1 if this device is the console output
1201 ISCIN = 1 if this device is the console input
1202 SPECL = 1 if this device is special
1203
1204 CTRL = 0 if this device can NOT do control strings
1205 via calls AL=2 and AL=3.
1206 CTRL = 1 if this device can process control
1207 strings via calls AL=2 and AL=3.
1208 NOTE that this bit cannot be set.
1209
1210 If ISDEV = 0
1211 EOF = 0 if channel has been written
1212 Bits 0-5 are the block device number for the
1213 channel (0 = A, 1 = B, ...)
1214
1215 Bits 15,8-13,4 are reserved and should not be altered.
1216
1217 Calls 2..5:
1218 These four calls allow arbitrary control strings to be
1219 sent or received from a device. The Call syntax is
1220 the same as the READ and WRITE calls, except for 4 and
1221 5 which take a drive number in BL instead of a handle
1222 in BX.
1223
1224 An error_invalid_function error is returned if the
1225 CTRL bit (see above) is 0.
1226
1227 An error_access_denied is returned by calls AL=4,5 if
1228 the drive number is invalid.
1229
1230 Calls 6,7:
1231 These two calls allow the user to check if a file
1232 handle is ready for input or output. Status of
1233 handles open to a device is the intended use of these
1234 calls, but status of a handle open to a disk file is
1235 OK and is defined as follows:
1236
1237 Input:
1238 Always ready (AL=FF) until EOF reached, then
1239 always not ready (AL=0) unless current
1240 position changed via LSEEK.
1241 Output:
1242 Always ready (even if disk full).
1243
1244 IMPORTANT NOTE:
1245 The status is defined at the time the system is
1246 CALLED. On future versions, by the time control is
1247 returned to the user from the system, the status
1248 returned may NOT correctly reflect the true current
1249 state of the device or file.
1250
1251 Error returns:
1252 AX = error_invalid_handle
1253 The handle passed in BX was not currently
1254 open.
1255 = error_invalid_function
1256 The function passed in AL was not in the range
1257 0:7.
1258 = error_invalid_data
1259 = error_access_denied (calls AL=4..7)
1260
1261
1262 Name: * LSeek - move file read/write pointer
1263
1264 Assembler usage:
1265 MOV DX, offsetlow
1266 MOV CX, offsethigh
1267 MOV AL, method
1268 MOV BX, handle
1269 MOV AH, LSeek
1270 INT 21h
1271 ; DX:AX has the new location of the pointer
1272
1273 Description:
1274 LSeek moves the read/write pointer according to
1275 method:
1276
1277 Method Function
1278 ------ --------
1279 0 The pointer is moved to offset bytes from the
1280 beginning of the file.
1281 1 The pointer is moved to the current location
1282 plus offset.
1283 2 The pointer is moved to the end of file plus
1284 offset.
1285
1286 Offset should be regarded as a 32-bit integer with
1287 CX occupying the most significant 16 bits.
1288
1289 Error returns:
1290 AX = error_invalid_handle
1291 The handle passed in BX was not currently
1292 open.
1293 = error_invalid_function
1294 The function passed in AL was not in the range
1295 0:2.
1296
1297
1298 Name: * MkDir - Create a directory entry
1299
1300 Assembler usage:
1301 LDS DX, name
1302 MOV AH, MkDir
1303 INT 21h
1304
1305 Description:
1306 Given a pointer to an ASCIZ name, create a new
1307 directory entry at the end.
1308
1309 Error returns:
1310 AX = error_path_not_found
1311 The path specified was invalid or not found.
1312 = error_access_denied
1313 The directory could not be created (no room in
1314 parent directory), the directory/file already
1315 existed or a device name was specified.
1316
1317
1318 Name: * Open - access a file
1319
1320 Assembler usage:
1321 LDS DX, name
1322 MOV AH, Open
1323 MOV AL, access
1324 INT 21h
1325 ; AX has error or file handle
1326 ; If successful open
1327
1328 Description:
1329 Open associates a 16-bit file handle with a file.
1330
1331 The following values are allowed for access:
1332
1333 ACCESS Function
1334 ------ --------
1335 0 file is opened for reading
1336 1 file is opened for writing
1337 2 file is opened for both reading and writing.
1338
1339 DS:DX point to an ASCIZ name of the file to be
1340 opened.
1341
1342 The read/write pointer is set at the first byte of
1343 the file and the record size of the file is 1 byte.
1344 The returned file handle must be used for subsequent
1345 I/O to the file.
1346
1347 The DOS, on initialization, will have a maximum
1348 number of files. See the configuration file document
1349 for information on changing this default.
1350
1351 Error returns:
1352 AX = error_invalid_access
1353 The access specified in AL was not in the
1354 range 0:2.
1355 = error_file_not_found
1356 The path specified was invalid or not found.
1357 = error_access_denied
1358 The user attempted to open a directory or
1359 volume-id, or open a read-only file for
1360 writing.
1361 = error_too_many_open_files
1362 There were no free handles available in the
1363 current process or the internal system tables
1364 were full.
1365
1366
1367 Name: * Read - Do file/device I/O
1368
1369 Assembler usage:
1370 LDS DX, buf
1371 MOV CX, count
1372 MOV BX, handle
1373 MOV AH, Read
1374 INT 21h
1375 ; AX has number of bytes read
1376
1377 Description:
1378 Read transfers count bytes from a file into a
1379 buffer location. It is not guaranteed that all count
1380 bytes will be read; for example, reading from the
1381 keyboard will read at most one line of text. If the
1382 returned value is zero, then the program has tried to
1383 read from the end of file.
1384
1385 All I/O is done using normalized pointers; no
1386 segment wraparound will occur.
1387
1388 Error returns:
1389 AX = error_invalid_handle
1390 The handle passed in BX was not currently
1391 open.
1392 = error_access_denied
1393 The handle passed in BX was opened in a mode
1394 that did not allow reading.
1395
1396
1397 Name: * RmDir - Remove a directory entry
1398
1399 Assembler usage:
1400 LDS DX, name
1401 MOV AH, RmDir
1402 INT 21h
1403
1404 Description:
1405 RmDir is given an asciz name of a directory. That
1406 directory is removed from its parent
1407
1408 Error returns:
1409 AX = error_path_not_found
1410 The path specified was invalid or not found.
1411 = error_access_denied
1412 The path specified was not empty, not a
1413 directory, the root directory or contained
1414 invalid information.
1415 = error_current_directory
1416 The path specified was the current directory
1417 on a drive.
1418
1419
1420 Name: * Unlink - delete a directory entry
1421
1422 Assembler usage:
1423 LDS DX, name
1424 MOV AH, Unlink
1425 INT 21h
1426
1427 Description:
1428 Unlink removes a directory entry associated with a
1429 filename. If the file is currently open on another
1430 handle, then no removal will take place.
1431
1432 Error returns:
1433 AX = error_file_not_found
1434 The path specified was invalid or not found.
1435 = error_access_denied
1436 The path specified was a directory or
1437 read-only.
1438
1439
1440 Name: * Wait - retrieve the return code of a child
1441
1442 Assembler usage:
1443 MOV AH, Wait
1444 INT 21h
1445 ; AX has the exit code
1446
1447 Description:
1448 Wait will return the Exit code specified by a
1449 child process. It will return this Exit code only
1450 once. The low byte of this code is that sent by the
1451 Exit routine. The high byte is one of the following:
1452
1453 0 - terminate/abort
1454 1 - ^C
1455 2 - Hard error
1456 3 - Terminate and stay resident
1457
1458 Error returns:
1459 None.
1460
1461
1462 Name: * Write - write to a file
1463
1464 Assembler usage:
1465 LDS DX, buf
1466 MOV CX, count
1467 MOV BX, handle
1468 MOV AH, Write
1469 INT 21h
1470 ; AX has number of bytes written
1471
1472 Description:
1473 Write transfers count bytes from a buffer into
1474 a file. It should be regarded as an error if the
1475 number of bytes written is not the same as the number
1476 requested.
1477
1478 It is important to note that the write system
1479 call with a count of zero (CX = 0) will truncate
1480 the file at the current position.
1481
1482 All I/O is done using normalized pointers; no
1483 segment wraparound will occur.
1484
1485 Error Returns:
1486 AX = error_invalid_handle
1487 The handle passed in BX was not currently
1488 open.
1489 = error_access_denied
1490 The handle was not opened in a mode that
1491 allowed writing.
1492
1493
1494The following XENIX convention is followed for the new 2.0
1495system calls:
1496
1497 o If no error occurred, then the carry flag will be
1498 reset and register AX will contain the appropriate
1499 information.
1500
1501 o If an error occurred, then the carry flag will be
1502 set and register AX will contain the error code.
1503
1504The following code sample illustrates the recommended method
1505of detecting these errors:
1506
1507 ...
1508 MOV errno,0
1509 INT 21h
1510 JNC continue
1511 MOV errno,AX
1512continue:
1513 ...
1514
1515The word variable errno will now have the correct error code
1516for that system call.
1517
1518The current equates for the error codes are:
1519
1520no_error_occurred EQU 0
1521
1522error_invalid_function EQU 1
1523error_file_not_found EQU 2
1524error_path_not_found EQU 3
1525error_too_many_open_files EQU 4
1526error_access_denied EQU 5
1527error_invalid_handle EQU 6
1528error_arena_trashed EQU 7
1529error_not_enough_memory EQU 8
1530error_invalid_block EQU 9
1531error_bad_environment EQU 10
1532error_bad_format EQU 11
1533error_invalid_access EQU 12
1534error_invalid_data EQU 13
1535error_invalid_drive EQU 15
1536error_current_directory EQU 16
1537error_not_same_device EQU 17
1538error_no_more_files EQU 18
1539
1540
1541System call assignments:
1542
1543ABORT EQU 0 ; 0 0
1544STD_CON_INPUT EQU 1 ; 1 1
1545STD_CON_OUTPUT EQU 2 ; 2 2
1546STD_AUX_INPUT EQU 3 ; 3 3
1547STD_AUX_OUTPUT EQU 4 ; 4 4
1548STD_PRINTER_OUTPUT EQU 5 ; 5 5
1549RAW_CON_IO EQU 6 ; 6 6
1550RAW_CON_INPUT EQU 7 ; 7 7
1551STD_CON_INPUT_NO_ECHO EQU 8 ; 8 8
1552STD_CON_STRING_OUTPUT EQU 9 ; 9 9
1553STD_CON_STRING_INPUT EQU 10 ; 10 A
1554STD_CON_INPUT_STATUS EQU 11 ; 11 B
1555STD_CON_INPUT_FLUSH EQU 12 ; 12 C
1556DISK_RESET EQU 13 ; 13 D
1557SET_DEFAULT_DRIVE EQU 14 ; 14 E
1558FCB_OPEN EQU 15 ; 15 F
1559FCB_CLOSE EQU 16 ; 16 10
1560DIR_SEARCH_FIRST EQU 17 ; 17 11
1561DIR_SEARCH_NEXT EQU 18 ; 18 12
1562FCB_DELETE EQU 19 ; 19 13
1563FCB_SEQ_READ EQU 20 ; 20 14
1564FCB_SEQ_WRITE EQU 21 ; 21 15
1565FCB_CREATE EQU 22 ; 22 16
1566FCB_RENAME EQU 23 ; 23 17
1567GET_DEFAULT_DRIVE EQU 25 ; 25 19
1568SET_DMA EQU 26 ; 26 1A
1569+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1570| C A V E A T P R O G R A M M E R |
1571| |
1572GET_DEFAULT_DPB EQU 31 ; 31 1F
1573| |
1574| C A V E A T P R O G R A M M E R |
1575+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1576FCB_RANDOM_READ EQU 33 ; 33 21
1577FCB_RANDOM_WRITE EQU 34 ; 34 22
1578GET_FCB_FILE_LENGTH EQU 35 ; 35 23
1579GET_FCB_POSITION EQU 36 ; 36 24
1580SET_INTERRUPT_VECTOR EQU 37 ; 37 25
1581CREATE_PROCESS_DATA_BLOCK EQU 38 ; 38 26
1582FCB_RANDOM_READ_BLOCK EQU 39 ; 39 27
1583FCB_RANDOM_WRITE_BLOCK EQU 40 ; 40 28
1584PARSE_FILE_DESCRIPTOR EQU 41 ; 41 29
1585GET_DATE EQU 42 ; 42 2A
1586SET_DATE EQU 43 ; 43 2B
1587GET_TIME EQU 44 ; 44 2C
1588SET_TIME EQU 45 ; 45 2D
1589SET_VERIFY_ON_WRITE EQU 46 ; 46 2E
1590; Extended functionality group
1591GET_DMA EQU 47 ; 47 2F
1592GET_VERSION EQU 48 ; 48 30
1593KEEP_PROCESS EQU 49 ; 49 31
1594+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1595| C A V E A T P R O G R A M M E R |
1596| |
1597GET_DPB EQU 50 ; 50 32
1598| |
1599| C A V E A T P R O G R A M M E R |
1600+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1601SET_CTRL_C_TRAPPING EQU 51 ; 51 33
1602GET_INDOS_FLAG EQU 52 ; 52 34
1603GET_INTERRUPT_VECTOR EQU 53 ; 53 35
1604GET_DRIVE_FREESPACE EQU 54 ; 54 36
1605CHAR_OPER EQU 55 ; 55 37
1606INTERNATIONAL EQU 56 ; 56 38
1607; XENIX CALLS
1608; Directory Group
1609MKDIR EQU 57 ; 57 39
1610RMDIR EQU 58 ; 58 3A
1611CHDIR EQU 59 ; 59 3B
1612; File Group
1613CREAT EQU 60 ; 60 3C
1614OPEN EQU 61 ; 61 3D
1615CLOSE EQU 62 ; 62 3E
1616READ EQU 63 ; 63 3F
1617WRITE EQU 64 ; 64 40
1618UNLINK EQU 65 ; 65 41
1619LSEEK EQU 66 ; 66 42
1620CHMOD EQU 67 ; 67 43
1621IOCTL EQU 68 ; 68 44
1622XDUP EQU 69 ; 69 45
1623XDUP2 EQU 70 ; 70 46
1624CURRENT_DIR EQU 71 ; 71 47
1625; Memory Group
1626ALLOC EQU 72 ; 72 48
1627DEALLOC EQU 73 ; 73 49
1628SETBLOCK EQU 74 ; 74 4A
1629; Process Group
1630EXEC EQU 75 ; 75 4B
1631EXIT EQU 76 ; 76 4C
1632WAIT EQU 77 ; 77 4D
1633FIND_FIRST EQU 78 ; 78 4E
1634; Special Group
1635FIND_NEXT EQU 79 ; 79 4F
1636; SPECIAL SYSTEM GROUP
1637+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1638| C A V E A T P R O G R A M M E R |
1639| |
1640SET_CURRENT_PDB EQU 80 ; 80 50
1641GET_CURRENT_PDB EQU 81 ; 81 51
1642GET_IN_VARS EQU 82 ; 82 52
1643SETDPB EQU 83 ; 83 53
1644| |
1645| C A V E A T P R O G R A M M E R |
1646+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1647GET_VERIFY_ON_WRITE EQU 84 ; 84 54
1648+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1649| C A V E A T P R O G R A M M E R |
1650| |
1651DUP_PDB EQU 85 ; 85 55
1652| |
1653| C A V E A T P R O G R A M M E R |
1654+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1655RENAME EQU 86 ; 86 56
1656FILE_TIMES EQU 87 ; 87 57
1657