In order for a programming language like W to be useful, it must be accompanied by a run-time system of some kind that interfaces programs to the underlying operating system. In some programming languages, the run-time system is, in fact, part of the language specification (e.g., I/O instructions are part of the language.) Not so in W; interfacing with the operating system is accomplished through a series of library functions that are ordinary (user-defined) functions themselves.

The library functions presented here are not part of the W language specification; they are, however, the same functions that were used for the W compiler itself for file I/O, formatted output, and string manipulation.

File I/O functions

write(file, data, length)

The write() function is used to write a set number of bytes to a file or device. This function is a wrapper for the MS-DOS Interrupt 21h function 40h. The first parameter is the MS-DOS file handle; the second parameter is a pointer to the data to be written; the third parameter is the number of bytes to be written.

Return value: the function returns the number of bytes actually written, or 0 if no data has been written.

write := 0x8B55, 0x8BEC, 0x085E, 0x4E8B, 0x8B04, 0x0656, 0x00B8,
	 0xCD40, 0x7321, 0x3102, 0x8BC0, 0x5DE5, 0x90C3
;
; 0100 55            PUSH    BP
; 0101 8BEC          MOV     BP,SP
; 0103 8B5E08        MOV     BX,[BP+08]
; 0106 8B4E04        MOV     CX,[BP+04]
; 0109 8B5606        MOV     DX,[BP+06]
; 010C B80040        MOV     AX,4000
; 010F CD21          INT     21
; 0111 7302          JNB     0115
; 0113 31C0          XOR     AX,AX
; 0115 8BE5          MOV     SP,BP
; 0117 5D            POP     BP
; 0118 C3            RET

 

read(file, data, length)

The read() function is used to read a set number of bytes from a file or device. This function is a wrapper for the MS-DOS Interrupt 21h function 3Fh. The first parameter is the MS-DOS file handle; the second parameter is a pointer to a buffer where data will be copied; the third parameters in the maximum number of bytes to be read.

Return value: the function returns the number of bytes actually read, or 0 if no data has been read.

read := 0x8B55, 0x8BEC, 0x085E, 0x4E8B, 0x8B04, 0x0656, 0x00B8,
	0xCD3F, 0x7321, 0x3102, 0x8BC0, 0x5DE5, 0x90C3
;
; 0100 55            PUSH    BP
; 0101 8BEC          MOV     BP,SP
; 0103 8B5E08        MOV     BX,[BP+08]
; 0106 8B4E04        MOV     CX,[BP+04]
; 0109 8B5606        MOV     DX,[BP+06]
; 010C B8003F        MOV     AX,3F00
; 010F CD21          INT     21
; 0111 7302          JNB     0115
; 0113 31C0          XOR     AX,AX
; 0115 8BE5          MOV     SP,BP
; 0117 5D            POP     BP
; 0118 C3            RET

 

open(filename, mode)

The open() function opens a file or device for reading or writing. If a file that's being opened for writing doesn't exist, it is created by this function. The filename parameter is any valid MS-DOS file name in the form of a null-terminated string. The mode parameter can be 0 (open the file for reading), 1 (open the file for writing), or 2 (open the file for reading or writing). This function is a wrapper for MS-DOS Interrupt 21h functions 3Ch and 3Dh.

Return value: upon success, the function returns the MS-DOS file handle. Upon failure, the return value is 0.

open := 0x8955, 0x8BE5, 0x0656, 0x468B, 0x3C04, 0x7501, 0x3107, 0xB8C9,
	0x3C00, 0x02EB, 0x3DB4, 0x21CD, 0x0273, 0xC031, 0xEC89, 0xC35D

; 0100 55            PUSH    BP
; 0101 89E5          MOV     BP,SP
; 0103 8B5606        MOV     DX,[BP+06]
; 0106 8B4604        MOV     AX,[BP+04]
; 0109 3C01          CMP     AL,01
; 010B 7507          JNZ     0114
; 010D 31C9          XOR     CX,CX
; 010F B8003C        MOV     AX,3C00
; 0112 EB02          JMP     0116
; 0114 B43D          MOV     AH,3D
; 0116 CD21          INT     21
; 0118 7302          JNB     011C
; 011A 31C0          XOR     AX,AX
; 011C 89EC          MOV     SP,BP
; 011E 5D            POP     BP
; 011F C3            RET

 

close(file)

The close() function closes a previously opened file handle. This function is a wrapper for MS-DOS Interrupt 21h function 3Eh.

close := 0x8955, 0x8BE5, 0x045E, 0x00B8, 0xCD3E,
	 0x7221, 0x3102, 0x89C0, 0x5DEC, 0x90C3

; 0100 55            PUSH    BP
; 0101 89E5          MOV     BP,SP
; 0103 8B5E04        MOV     BX,[BP+04]
; 0106 B8003E        MOV     AX,3E00
; 0109 CD21          INT     21
; 010B 7202          JB      010F
; 010D 31C0          XOR     AX,AX
; 010F 89EC          MOV     SP,BP
; 0111 5D            POP     BP
; 0112 C3            RET
; 0113 90            NOP

 

seek(file, position, direction)

The seek() function positions the read/write pointer within an open file. The position parameter is a pointer to a two-word array that determines the location where the file pointer is to be moved. The direction parameter can be 0, meaning the move is relative to the beginning of the file; 1, meaning the move is relative to the current location; or 2, meaning the move is relative to the end of the file. If the direction parameter is 1 or 2, the position parameter is interpreted as a signed quantity, meaning that it is possible to move the file pointer both forward and backward.

The seek() function is a wrapper for MS-DOS Interrupt 21h function 42h.

Return value: upon failure, the function returns 0xFFFF and sets the position value pointed to by the position parameter to 0xFFFF, 0xFFFF. Upon success, the function sets the position value to the current (new) file location. It is, therefore, possible to use the seek() function to determine the current location in the file by setting the position pointed to by the position parameter to 0, 0, and the direction parameter to 1.

The behavior of seek() is undefined if file is a handle to an I/O device.

seek := 0x8955, 0x8BE5, 0x065E, 0x178B, 0x4F8B, 0x8B02, 0x085E, 0x468B,
	0xB404, 0xCD42, 0x7321, 0xB806, 0xFFFF, 0xFFBA, 0x8BFF, 0x065E,
	0x0789, 0x5789, 0x8902, 0x5DEC, 0x90C3

; 0100 55            PUSH    BP
; 0101 89E5          MOV     BP,SP
; 0103 8B5E06        MOV     BX,[BP+06]
; 0106 8B17          MOV     DX,[BX]
; 0108 8B4F02        MOV     CX,[BX+02]
; 010B 8B5E08        MOV     BX,[BP+08]
; 010E 8B4604        MOV     AX,[BP+04]
; 0111 B442          MOV     AH,42
; 0113 CD21          INT     21
; 0115 7306          JNB     011D
; 0117 B8FFFF        MOV     AX,FFFF
; 011A BAFFFF        MOV     DX,FFFF
; 011D 8B5E06        MOV     BX,[BP+06]
; 0120 8907          MOV     [BX],AX
; 0122 895702        MOV     [BX+02],DX
; 0125 89EC          MOV     SP,BP
; 0127 5D            POP     BP
; 0128 C3            RET
; 0129 90            NOP

 

unlink(filename)

The unlink() function deletes the file specified by the filename parameter. This parameter can point to a string containing any valid, null-terminated MS-DOS filename. This function is a wrapper for MS-DOS Interrupt 21h function 41h.

Return value: the function returns 0 on success, or a non-0 error value.

unlink := 0x8955, 0x8BE5, 0x0456, 0x00B8, 0xCD41, 0x7221, 0x3102, 0x89C0,
	  0x5DEC, 0x90C3

; 0100 55            PUSH    BP
; 0101 89E5          MOV     BP,SP
; 0103 8B5604        MOV     DX,[BP+04]
; 0106 B80041        MOV     AX,4100
; 0109 CD21          INT     21
; 010B 7202          JB      010F
; 010D 31C0          XOR     AX,AX
; 010F 89EC          MOV     SP,BP
; 0111 5D            POP     BP
; 0112 C3            RET
; 0113 90            NOP

 

Standard file handles

In addition to the file manipulation functions described above, the following standard file handles are defined:

stdin  := 0	; MS-DOS standard input
stdout := 1	; MS-DOS standard output
stderr := 2	; and standard error

These file handles are open and valid when a W program begins execution.

getc(file)

The getc() function retrieves a single character from a file or device.

Return value: the return value is the character read, or 0xFFFF is the end of the file has been reached or an error occurred.

getc(f) :=
{
	c := 0

	read(f, #c, 1) ? c, 0xFFFF
}

 

ungetc(file)

The ungetc() function positions the read/write pointer in a file backward by one byte. The effect of this function is undefined for handles that don't represent a disk file.

ungetc(f) :=
{
	p[2] := 0xFFFF, 0xFFFF
	seek(f, #p, 1)
}

Data conversion functions

atoi(string)

The atoi() function interprets a null-terminated string value as a decimal integer and converts it to a binary value.

Return value: the return value is a binary word corresponding to the number represented by the string. There is no error return.

atoi(s) :=
{
	n := 0
	p := $
	@s&0xFF >= '0' ?
	{
		@s&0xFF <= '9' ?
		{
			n = n*10 + (@s&0xFF - '0')
			s = s+1
			$ = p
		}
	}
	n	; Return value
}

 

itoa(number, string)

The itoa() function converts a binary number into a decimal number using its ASCII string representation. The converted string is stored at the location pointed to by the string parameter; this parameter must point to a location containing at least 3 words of allocated memory.

Return value: the return value is the number of digits in the result.

itoa(n, s) :=
{
	@s = @s & 0xFF00
	c := 0
	p := $
	m := n / 10
	d := n % 10

	m || d ?
	{
		i := c
		q := $
		i > 0 ?
		{
			@(s+i) = (@(s+i) & 0xFF00) + (@(s+i-1) & 0xFF)
			i = i - 1
			$ = q
		}
	
		c = c + 1
		@s = (@s & 0xFF00) + d + '0'
		n = m
		$ = p
	}
	c == 0 ?
	{
		@s = '0'
		c = c + 1
	}
	c
}

 

itox(number, string)

The itox() function converts a binary number into a hexadecimal number using its 4-digit ASCII string representation. Leading zeroes are not suppressed. The converted string is stored at the location pointed to by the string parameter; this parameter must point to a location containing at least 3 words of allocated memory.

Return value: the return value is the number of digits in the result (i.e., it's always 4.)

itox(n, s) :=
{
	i := 0
	x := ?
	p := $
	i < 4 ?
	{
		x = (n & 0xF000) >> 12
		@(s+i) = @(s+i) & 0xFF00 + (x > 9 ? x + 'A' - 10, x + '0')
		n = n << 4
		i = i + 1
		$ = p
	}
	@s[2] = 0
	i
}

String manipulation functions

strlen(string)

The strlen() function computes the length of a null-terminated character string pointed to by the string parameter. The terminating null character is not included in the count.

Return value: the function returns the length of its string parameter.

strlen := 0x8955, 0x57E5, 0x7E8B, 0xB904, 0xFFFF, 0x30FC, 0xF2C0, 0xB8AE,
	  0xFFFE, 0xC829, 0x5D5F, 0x90C3

; 55            PUSH    BP
; 89E5          MOV     BP,SP
; 57            PUSH    DI
; 8B7E04        MOV     DI,[BP+04]
; B9FFFF        MOV     CX,FFFF
; FC            CLD
; 30C0          XOR     AL,AL
; F2            REPNZ
; AE            SCASB
; B8FEFF        MOV     AX,FFFE
; 29C8          SUB     AX,CX
; 5F            POP     DI
; 5D            POP     BP
; C3            RET
; 90            NOP

 

strncpy(dst, src, len)

The strncpy() function copies up to len characters from the location pointed to by src to the location pointed to by dst. If a null character is encountered, the copy operation is stopped.

strncpy := 0x8955, 0x57E5, 0x8B56, 0x067E, 0x4E8B, 0xFC04, 0xC030, 0xAEF2,
	   0x4E2B, 0xF704, 0x8BD9, 0x087E, 0x768B, 0xF306, 0x5EA4, 0x5D5F, 0x90C3

; 0100 55            PUSH    BP
; 0101 89E5          MOV     BP,SP
; 0103 57            PUSH    DI
; 0104 56            PUSH    SI
; 0105 8B7E06        MOV     DI,[BP+06]
; 0108 8B4E04        MOV     CX,[BP+04]
; 010B FC            CLD
; 010C 30C0          XOR     AL,AL
; 010E F2            REPNZ
; 010F AE            SCASB
; 0110 2B4E04        SUB     CX,[BP+04]
; 0113 F7D9          NEG     CX
; 0115 8B7E08        MOV     DI,[BP+08]
; 0118 8B7606        MOV     SI,[BP+06]
; 011B F3            REPZ
; 011C A4            MOVSB
; 011D 5E            POP     SI
; 011E 5F            POP     DI
; 011F 5D            POP     BP
; 0120 C3            RET
; 0121 90            NOP

 

strcpy(dst, src)

The strcpy() functions copies strings from src to dst up to and including the terminating null character.

strcpy(d, s) := strncpy(d, s, 0xFFFF)

 

memcmp(dst, src, len)

The memcmp() function compares up to len bytes of data located at the addresses pointed to by the src and dst parameters.

Return value: the return value is 0 if the two areas of memory contain the same data; if there is a difference, the return value is non-0 (but otherwise undefined.)

memcmp := 0x8955, 0x57E5, 0x8B56, 0x044E, 0x7E8B, 0x8B08, 0x0676, 0xA6F3,
	  0x01B8, 0x7500, 0x3102, 0x5EC0, 0x5D5F, 0x90C3

; 0100 55            PUSH    BP
; 0101 89E5          MOV     BP,SP
; 0103 57            PUSH    DI
; 0104 56            PUSH    SI
; 0105 8B4E04        MOV     CX,[BP+04]
; 0108 8B7E08        MOV     DI,[BP+08]
; 010B 8B7606        MOV     SI,[BP+06]
; 010E F3            REPZ
; 010F A6            CMPSB
; 0110 B80100        MOV     AX,0001
; 0113 7502          JNZ     0117
; 0115 31C0          XOR     AX,AX
; 0117 5E            POP     SI
; 0118 5F            POP     DI
; 0119 5D            POP     BP
; 011A C3            RET
; 011B 90            NOP

 

strncmp(dst, src, len)

The strncmp() function compares up to len bytes of string data located at the addresses pointed to by the src and dst parameters. The compare operation stops if a null character is encountered in either strings.

Return value: the return value is 0 if the two strings contain the same data; if there is a difference, the return value is non-0 (but otherwise undefined.)

strncmp(d, s, n) :=
{
	k := strlen(d)
	l := strlen(s)

	0 != ((k > n && l > n) || (k == l)) ?
	{
		k < n ? n = k
		memcmp(d, s, n)
	}, 0xFFFF
}

 

strcmp(dst, src)

The strcmp() function compares two strings data located at the addresses pointed to by the src and dst parameters. The compare operation stops if a null character is encountered in either strings.

Return value: the return value is 0 if the two strings contain the same data; if there is a difference, the return value is non-0 (but otherwise undefined.)

strcmp(d, s) := strncmp(d, s, 0xFFFF)

 

at(string, number)

The at() function retrieves a specific character (determined by the number parameter) from the string pointed to by the string parameter.

Return value: the return value is the byte at the specified location. There is no error return.

at(s, n) := (@s[n >> 1] & ((n&1) ? 0xFF00, 0x00FF)) >> ((n&1) ? 8, 0)

Character classification functions

isalphabetic(character)

The isalphabetic() function returns a non-zero result if its argument represents the ASCII code of an upper-, or lowercase letter.

isalphabetic(c) :=
{
	c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'
}

 

isdigit(character)

The isdigit() function returns a non-zero result if its argument represent the ASCII code of a digit.

isdigit(c) :=
{
	c >= '0' ? c <= '9'
}

 

isalphanumeric(character)

The isalphanumeric() function returns a non-zero result if its argument is either a letter, or a digit.

isalphanumeric(c) :=
{
	isalphabetic(c) || isdigit(c)
}

 

isspace(character)

The isspace() function returns a non-zero value if its argument is the ASCII code of a whitespace character: i.e., a space, tab, carriage-return or newline character.

isspace(c) :=
{
	c == ' ' || c == '\t' || c == '\r' || c == '\n'
}

Formatted output functions

puts(file, string)

The puts() function writes a null-terminated string to the file or device represented by the file parameter.

Return value: the return value is the number of bytes written, or 0 if no data is written.

puts(o, s) := write(o, s, strlen(s))

 

putn(file, number)

The putn() function formats a binary value as a decimal number and writes it to the file or device represented by the file parameter.

Return value: the return value is the number of bytes written, or 0 if no data is written.

putn(o, n) :=
{
	s[3] := ?
	n = itoa(n, #s)
	write(o, #s, n)
}

 

putx(file, number)

The putx() function formats a binary value as a hexadecimal number and writes it to the file or device represented by the file parameter.

Return value: the return value is the number of bytes written, or 0 if no data is written.

putx(o, n) :=
{
	s[3] := ?
	n = itox(n, #s)
	write(o, #s, n)
}

 

putss(string)

The putss() function writes a null-terminated string to standard output. Its operation is identical to that of puts().

putss(s) := puts(stdout, #s)

 

putsn(number)

The putsn() function writes a null-terminated string to standard output. Its operation is identical to that of putn().

putsn(n) := putn(stdout, n)

 

printf([parameters,...] format-string, file)

The printf() function emits formatted output to the specified device. The format-string parameter points to a string that controls the appearance of the output. The format string may contain the special character sequences, which will be replaced with additional parameters supplied to this function. The sequence %s means a string substitution; the sequence %d means a decimal parameter; and the sequence %x means a hexadecimal parameter. Any other character following a % character (including a second % character) is printed unchanged.

The printf() function is a function with a variable number of arguments. These arguments must appear in reverse order relative to the appearance of the corresponding placeholders in format-string.

printf(s, o) :=
{
	n := 0
	m := 0
	c := ?
	p := #s + 2

	r := $
	c = at(s, n)
	c != 0 ?
	{
		c == '%' ?
		{
			write(o, s + m, n - m)
			m = n + 2
			n = n + 1
			c = at(s, n)
			c == 's' ?
			{
				puts(o, @p)
			},
			c == 'd' ?
			{
				putn(o, @p)
			},
			c == 'x' ?
			{
				putx(o, @p)
			},
			{
				write(o, #c, 1)
			}
			p = p + 2
		}
		n = n + 1
		c = at(s, n)
		$ = r
	}
	m < n ? write(o, s + m, n - m)
}