home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware 1 2 the Maxx
/
sw_1.zip
/
sw_1
/
EDITORS
/
TDE20.ZIP
/
TDEASM.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-06-05
|
78KB
|
1,943 lines
/*
* In the DTE 5.1 editor, the end of file was marked with '\0'. I have
* decided to use ^Z to mark the begin and end of files instead of '\0'.
* That way, null characters are allowed as normal text characters. ^Z is used
* to mark the end of strings in buffers instead of '\0'. The standard C
* string library functions should not be used when dealing with text buffers.
*
* The often used string routines have been rewritten in assembly. When using
* 16 bit processors, accessing memory by WORDs on WORD boundaries is twice
* as fast as accessing memory by BYTEs. If a memory pointer is even then it
* is WORD aligned. If a memory pointer is odd, do the first BYTE and then
* the rest of the string is WORD aligned on an even boundary.
*
* Two routines were written to adjust the string pointers whenever they
* approach the end of a segment, cpf() and cpb() (check pointer foward and
* check pointer backward). With these two routines, the code may be
* compiled without the huge memory model. Another assembly routine was
* written to compare physical memory locations, ptoul(). For example,
* all of these pointers point to same physical memory address:
*
* 59a1:9122 == 58a1:a122 == 62a1:0122 = physical address 404,274
*
* An efficient way to compare far pointers is to convert them to either
* unsigned long or long integers. Either one will do - their is no such
* thing a negative physical memory address. A long int goes from
* -2 billion to 2 billion, which leaves plenty of room to describe a physical
* address, using a long, where the max is 1 MEG. I used unsigned long. When
* adding or subtracting from the physical address of a pointer, we should
* never, ever get a negative physical address. This is the concept behind the
* function ptoul(), which is short for pointer to unsigned long.
*
* With these functions written in assembly, this editor is fairly fast.
* I feel the need for speed.
*
* New editor name: tde, the Thomson-Davis Editor.
* Author: Frank Davis
* Date: June 5, 1991, version 1.0
* Date: July 29, 1991, version 1.1
* Date: October 5, 1991, version 1.2
* Date: January 20, 1992, version 1.3
* Date: February 17, 1992, version 1.4
* Date: April 1, 1992, version 1.5
* Date: June 5, 1992, version 2.0
*
* This modification of Douglas Thomson's code is released into the
* public domain, Frank Davis. You may distribute it freely.
*/
#include "tdestr.h"
#include "common.h"
#include "tdefunc.h"
/*
* Name: cpf - check_pointer_forward
* Purpose: To adjust a pointer if it is nearing end of a segment (within 16k)
* Date: June 5, 1991
* Passed: s: string pointer
* Notes: To avoid a bunch of code generated for pointer arithmetic when using
* the huge memory model, this routine adjusts a pointer when it
* approaches the end of a segment.
*/
text_ptr cpf( text_ptr s )
{
_asm {
mov ax, WORD PTR s ; get OFFSET of s
mov dx, WORD PTR s+2 ; get SEGMENT of s
cmp ax, 0xc000 ; are we within 16k of top of segment?
jb get_out ; no, get out
sub ax, 0x8000 ; yes, subtract 32k from offset
add dx, 0x0800 ; add 0x0800 paragraphs to segment == 32k
ALIGN 2
get_out:
}
}
/*
* Name: cpb - check_pointer_backward
* Purpose: To adjust a pointer if it is nearing beginning of a segment (16k)
* Date: June 5, 1991
* Passed: s: string pointer
* Notes: To avoid a bunch of code generated for pointer arithmetic when using
* the huge memory model, this routine adjusts a pointer when it
* approaches the beginning of a segment. Don't check NULL pointer.
*/
text_ptr cpb( text_ptr s )
{
_asm {
mov ax, WORD PTR s ; get OFFSET of s
mov dx, WORD PTR s+2 ; get SEGMENT of s
cmp ax, 0 ; is offset of s == NULL?
jne not_null ; no, check pointer
cmp dx, 0 ; is segment of s == NULL?
je get_out ; yes, don't check NULL pointer
ALIGN 2
not_null:
cmp ax, 0x4000 ; are we within 16k of beginning of segment?
jae get_out ; no, get out
add ax, 0x8000 ; yes, add 32k to offset
sub dx, 0x0800 ; sub 0x0800 paragraphs from segment == 32k
ALIGN 2
get_out:
}
}
/*
* Name: ptoul - pointer to unsigned long
* Purpose: convert a far pointer to unsigned long integer
* Date: June 5, 1991
* Passed: s: a far pointer
* Notes: combine the offset and segment like so:
* offset 0000
* segment + 0000
* =======
* 00000
* result is returned in dx:ax
*/
unsigned long ptoul( void far *s )
{
_asm {
mov ax, WORD PTR s ; ax = OFFSET of s
mov dx, WORD PTR s+2 ; dx = SEGMENT of s
mov bx, dx ; put copy of segment in bx
mov cl, 12 ; cl = decimal 12 - shift hi word 3 hex digits
shr dx, cl ; convert to 'real segment'
mov cl, 4 ; cl = 4 - shift hi word 1 hex digit left
shl bx, cl ; shift bx - to add 3 digits of seg to 4 of off
add ax, bx ; add low part of segment to offset
adc dx, 0 ; if carry, bump to next 'real' segment
}
}
/*
* Name: nptos - normalize pointer to segment
* Purpose: make the offset of a pointer no larger than a paragraph (16 bytes)
* Date: June 5, 1991
* Passed: s: string pointer
* Notes: move all but the paragraph from the offset of the pointer to the
* segment. The offset will be no larger than 16 bytes. Why? because
* we can add up to 0xFFF0 reliably to a pointer in small, compact or
* large model and not worry about segment wrap.
*
* offset abcx
* segment 0000
* =======
* offset 000x
* segment 0abc
* result is returned in dx:ax
*/
text_ptr nptos( text_ptr s )
{
_asm {
mov ax, WORD PTR s ; ax = OFFSET of s
mov dx, WORD PTR s+2 ; dx = SEGMENT of s
mov bx, ax ; put copy of offset in bx
mov cl, 4 ; cl = 4 - shift lo word 1 hex digit
shr bx, cl ; shift bx - line up on paragraph
add dx, bx ; add hi part of offset to segment
and ax, 0x000f ; mask out three hex digits in offset
}
}
/*
* Name: addltop - add long to pointer
* Purpose: add long integer to a pointer
* Date: June 5, 1991
* Passed: l: long
* p: text pointer
* Returns: pointer + long integer
* Notes: A long integer takes two WORDs. A far pointer takes two WORDs.
* A long integer cannot be added directly to a far pointer.
* This diagram may help explain better than I can write.
*
* far pointer 0000 offset
* 0xxx segment
* +
* long integer 00000000 throw away those three
* ====== hex digits on long integer,
* 0000 offset they have no effect
* new far pointer 0xxx segment
*
* msw = Most Significant WORD
* lsw = Least Significant WORD
*
* When working with the long integer, we don't need to worry about
* the three x's on segment of the pointer. Add or subtract the lsw
* of the long integer to/from the offset. If there is a carry,
* it only affects the left most digit of the msw of the pointer.
*/
text_ptr addltop( long l, text_ptr p )
{
if (l >= 0) {
_asm {
mov ax, WORD PTR p ; ax = OFFSET of p
mov dx, WORD PTR p+2 ; dx = SEGMENT of p
mov bx, WORD PTR l+2 ; msw of l in bx
add ax, WORD PTR l ; add offset of p and lsw of l
adc bx, 0 ; if carry, pointer in another segment
mov cl, 12 ; cl = 12 - shift off 3 hex digits
shl bx, cl ; consider the 1st hex digit of msw of l
add dx, bx ; add segment of p and 1st digit of msw of l
}
} else {
l = -l; /* convert l to positive and subtract from pointer p */
_asm {
mov ax, WORD PTR p ; ax = OFFSET of p
mov dx, WORD PTR p+2 ; dx = SEGMENT of p
mov bx, WORD PTR l+2 ; msw of l in bx
mov cl, 12 ; cl = 12 - shift off 3 hex digits
sub ax, WORD PTR l ; subtract low part of pointer
adc bx, 0 ; if we borrowed then add it back to bx
shl bx, cl ; only handle 1st hex digit of msw of l
sub dx, bx ; subtract msw from segment of p
}
}
}
/*
* Name: find_CONTROL_Z - assembler version, see commented C at end
* Purpose: To determine the length of a line up to ^Z
* Date: June 5, 1991
* Passed: s: the line to be measured
* Notes: DOS carried over ^Z to mark the end of files from CP/M. Since
* it is the only character not allowed in regular text files. ^Z
* can be used, instead of '\0', to mark the end of strings. All
* ASCII characters, except ^Z, may be included in a text file.
* However, none of the C string library functions should be used
* when working with text. The string library functions can be used
* on responses solicited from the user.
* Returns: the length of the line
*/
unsigned int find_CONTROL_Z( text_ptr s )
{
s = cpf( s );
_asm {
mov dx, ds ; keep ds in dx, MUST save data segment
push si ; put copy of si on stack
xor cx, cx ; cx = 0
mov si, WORD PTR s ; put OFFSET of s in si
mov ax, WORD PTR s+2 ; get SEGMENT of s
mov ds, ax ; else, segment in ds
cmp si, 0 ; is offset of s == NULL?
jne not_null ; no, find length
cmp ax, 0 ; is segment of s == NULL?
je get_out ; yes, line length = 0
ALIGN 2
not_null:
mov bl, CONTROL_Z ; keep Control Z in bl - eos marker
mov ax, si ; pointer is ok, check for word align
shr ax, 1 ; if [si] is odd, lsb is 1 - rotate to carry
jnc top ; see if string is WORD aligned
lodsb ; no, get a BYTE - now WORD aligned
cmp al, bl ; is ds:[si] == ^Z?
je get_out ; yes, have length, cx = 0
inc cx ; increment length variable
ALIGN 2
top:
lodsw ; string is WORD aligned
cmp al, bl ; is lo BYTE == ^Z?
je get_out ; yes, we have length
inc cx ; no, increment counter
cmp ah, bl ; now test higher BYTE, is it ^Z?
je get_out ; yes, we have length
inc cx ; no, increment length
jmp SHORT top ; look at next two characters
ALIGN 2
get_out:
mov ax, cx ; put length in ax - as defined by Microsoft
mov ds, dx ; get back data segment from dx
pop si ; get back si from stack
}
/*
int len = 0;
while (*s != ^Z) {
++len;
++s;
}
return len;
*/
}
/*
* Name: linelen - assembler version, see commented C at end of routine
* Purpose: To determine the length of a line, up to either a \n or a
* ^Z, whichever comes first.
* Date: June 5, 1991
* Passed: s: the line to be measured
* Notes: Demonstrates 'lodsb' and 'lodsw'. Memory operations are most
* efficient when working with WORDs. See if first BYTE in
* string is WORD aligned. If it is then work with WORDs else
* get the first BYTE and rest of string will be WORD aligned.
* The 'mov' instruction could have been used, but 'lobsb' and
* 'lodsw' automatically increment the memory pointer.
* Returns: the length of the line
*/
unsigned int linelen( text_ptr s )
{
s = cpf( s );
_asm {
mov dx, ds ; keep ds in dx, MUST save data segment
push si ; save si on stack
xor cx, cx ; cx = 0
mov si, WORD PTR s ; put OFFSET of s in si
mov ax, WORD PTR s+2 ; get SEGMENT of s
mov ds, ax ; else, segment in ds
cmp si, 0 ; is offset of s == NULL?
jne not_null ; no, find length
cmp ax, 0 ; is segment of s == NULL?
je get_out ; yes, line length = 0
ALIGN 2
not_null:
mov bl, '\n' ; keep new line character in bl
mov bh, CONTROL_Z ; keep Control Z in bh - DOS eof marker
mov ax, si ; pointer is ok, check for word align
shr ax, 1 ; if [si] is odd, lsb is 1 - rotate to carry
jnc top ; see if string is WORD aligned
lodsb ; no, get a BYTE - now WORD aligned
cmp al, bl ; is BYTE == '\n'?
je get_out ; yes, have length, cx = 0
cmp al, bh ; is ds:[si] == ^Z?
je get_out ; yes, have length, cx = 0
inc cx ; increment length variable
ALIGN 2
top:
lodsw ; string is WORD aligned
cmp al, bl ; test lower BYTE, is it '\n'
je get_out ; yes, we have length
cmp al, bh ; no, test for ^Z
je get_out ; yes, we have length
inc cx ; no, not '\n' or ^Z so increment counter
cmp ah, bl ; now test higher BYTE, is it '\n'
je get_out ; yes, we have length
cmp ah, bh ; is it ^Z
je get_out ; yes, we have length
inc cx ; no, not '\n' or ^Z so increment length
jmp SHORT top ; look at next two characters
ALIGN 2
get_out:
mov ax, cx ; put length in ax - as defined by Microsoft
mov ds, dx ; get back data segment from dx
pop si ; get back si from stack
}
/*
int len = 0;
while (*s && *s != '\n') {
++len;
++s;
}
return len;
*/
}
/************* prelinelen is not used, but left in for reference **********/
/*
* Name: prelinelen
* Purpose: To determine the length of a line, from the current position
* backwards to either a \n or a ^Z, whichever comes first.
* Date: June 5, 1991
* Passed: s: the line to be measured
* Returns: the length of the line up to the current position
* Notes: It is assumed there will be a "terminating" ^Z before the
* start of the first line.
*/
/*
unsigned int prelinelen( text_ptr s )
{
s = cpb( s );
_asm {
push di ; put copy of di on stack
xor ax, ax ; ax = 0, keep string length in ax
mov di, WORD PTR s ; get offset of string
mov dx, WORD PTR s+2 ; get segment of string
mov es, dx ; put segment in es
cmp di, 0 ; is offset of string == NULL?
jne not_null ; no, do string stuff
cmp dx, 0 ; is, segment of string == NULL?
je get_out ; yes, don't do NULL string
not_null:
dec di ; look at previous character
ALWORD: dec di ; get ready to check for WORD align
mov bl, '\n' ; keep '\n' in bl
mov bh, CONTROL_Z ; keep ^Z in bh
mov dx, di ; pointer is ok, check for WORD align
shr dx, 1 ; if [di] is odd, lsb is 1 - rotate to carry
jnc top ; string is WORD aligned
inc di ; fix the second decrement - see ALWORD
mov dl, BYTE PTR es:[di] ; get a BYTE - put in DL
cmp dl, bl ; is it '\n'
je get_out ; yes, get out - count = 0
cmp dl, bh ; is it ^Z
je get_out ; yes, get out - count = 0
inc ax ; increment length counter
dec di ; pointer was BYTE aligned, dec pointer
dec di ; pointer is now WORD aligned
ALIGN 2
top:
mov dx, WORD PTR es:[di] ; load WORD - hi BYTE is next
cmp dh, bl ; is hi BYTE (next char) '\n'?
je get_out ; yes, get out - count already in ax
cmp dh, bh ; is hi BYTE (next char) ^Z?
je get_out ; yes, get out - count already in ax
inc ax ; increment character counter
cmp dl, bl ; now check lo BYTE, is it '\n'?
je get_out ; yes, get out - count is in ax
cmp dl, bh ; is lo BYTE ^Z?
je get_out ; yes, get out - count is in ax
inc ax ; increment character counter
dec di ; decrement pointer
dec di ; align pointer on WORD
jmp SHORT top ; test next 2 characters
get_out:
pop di ; get back di from stack
}
int len = 0;
while (*--s != CONTROL_Z && *s != '\n')
++len;
return len;
}
*/
/************************** prelinelen is not used ************************/
/*
* Name: find_next
* Purpose: To find the first character in the next line
* Date: June 5, 1991
* Passed: s: the starting point
* Returns: the first character in the next line
* Notes: This function goes faster if machine works with WORDs. See if
* first BYTE in string is WORD aligned. If it is not, get first
* BYTE in string then the rest of string is WORD aligned.
* Code added at end to adjust segment:offset if needed.
*/
text_ptr find_next( text_ptr s )
{
_asm {
push ds ; save ds on stack
push si ; save si on stack
mov si, WORD PTR s ; load OFFSET of s
mov ax, WORD PTR s+2 ; load SEGMENT of s
mov ds, ax
cmp si, 0 ; is offset of string == NULL?
jne not_null ; no, do string stuff
cmp ax, 0 ; is segment of string == NULL?
je return_null ; yes, return NULL if string is NULL
ALIGN 2
not_null:
mov bl, '\n' ; keep '\n' in bl
mov bh, CONTROL_Z ; keep ^Z in bh
mov ax, si ; move offset of si to ax
shr ax, 1 ; shift right into carry flag
jnc top ; is string WORD aligned?
lodsb ; no, get a BYTE
cmp al, bl ; is it '\n'?
je next_even ; yes, si already incremented by lodsb
cmp al, bh ; is it ^Z?
je return_null ; yes, return NULL
ALIGN 2
top:
lodsw ; string is WORD aligned, get two BYTEs
cmp al, bl ; is next BYTE == '\n'?
je next_odd ; yes, since si inc for WORD (lodsw) - dec di
cmp al, bh ; is next BYTE == ^Z?
je return_null ; yes, return NULL
cmp ah, bl ; is next BYTE in AH == '\n'?
je next_even ; yes, si is OK - return pointer to next BYTE
cmp ah, bh ; is next BYTE in AH == ^Z?
je return_null ; yes, return NULL
jmp SHORT top ; look at next WORD
ALIGN 2
return_null:
xor ax, ax ; clear ax - offset = NULL
xor dx, dx ; clear dx - segment = NULL
jmp SHORT get_out ; return text_ptr in dx:ax - see Microsoft
ALIGN 2
next_odd:
dec si ; 'lodsw' went one BYTE too far - so dec si
next_even:
mov ax, si ; ds:si now points to next line, load ax
mov dx, ds ; load dx with segment of next BYTE
cmp ax, 0xc000 ; are we within 16k of segment?
jb get_out ; no, get out
sub ax, 0x8000 ; yes, subtract 32k from offset
add dx, 0x0800 ; add 0x0800 paragraphs to segment
ALIGN 2
get_out:
pop si ; get back si from stack
pop ds ; get back ds from stack
}
/*
while (*s && *s != '\n' && *s != CONTROL_Z)
++s;
if (*s)
return ++s;
else
return NULL;
*/
}
/*
* Name: find_prev
* Purpose: To find the start of the previous line
* Date: June 5, 1991
* Passed: current: the current line
* Returns: the start if the previous line
* Notes: current should be at the start of the current line.
* There must be a ^Z preceding the first line.
* This function goes faster if machine works with WORDs. See if
* first BYTE in string is WORD aligned. If it is not, get first
* BYTE in string then the rest of string is WORD aligned.
* The test for '\n' will pass a lot more than the test for
* ^Z. Set up the WORD align stuff first.
* Since we are searching, by WORDs, backwards, the hi BYTE is the
* prev BYTE and the al BYTE is two prev BYTEs (make sense?).
* Code added at end to adjust segment:offset if needed.
*/
text_ptr find_prev( text_ptr current )
{
_asm {
push di ; save di on stack
mov di, WORD PTR current ; load OFFSET of current
DECR1: dec di ; decrement it
mov ax, WORD PTR current+2 ; load SEGMENT of current
mov es, ax
cmp di, 0 ; is offset of string == NULL?
jne not_null ; no, do string stuff
cmp ax, 0 ; is segment of string == NULL?
je return_null ; yes, return NULL if string NULL
ALIGN 2
not_null:
mov bl, '\n' ; keep '\n' in bl
mov bh, CONTROL_Z ; keep ^Z in bh
mov ax, di ; put copy of offset in ax
shr ax, 1 ; shift right thru carry flag
jnc on_boundary ; if no carry, string is WORD aligned
;
; if we were to dec the pointer twice, it would be WORD aligned with the
; '--current' BYTE in the AH register. if ^Z test fails, might as well
; test the BYTE in the AL register.
;
DECR2: dec di ; dec offset one more so it is WORD aligned
mov ax, WORD PTR es:[di] ; might as well load WORD
cmp ah, bh ; is prev BYTE ^Z?
je return_null ; yes, return NULL
;
; now we are in the for loop - see commented C code at bottom.
; 'on_boundary' is not part of the for loop so jump past it if needed.
;
cmp al, bl ; is prev BYTE '\n'?
je inc_pointer ; yes, increment the pointer and return
cmp al, bh ; is it ^Z?
je inc_pointer ; yes, increment the pointer and return
jmp SHORT for_loop ;no, pointer is now WORD aligned - do for loop
ALIGN 2
;
; the string ended on an odd boundary and the DECR1 has now aligned the
; string on a WORD. if we load a WORD, the '--current' BYTE would be in the
; AL register.
;
on_boundary:
mov ax, WORD PTR es:[di] ; load --current, aligned on WORD
cmp al, bh ; is --current ^Z?
je return_null ; yes, return NULL
;
; now we are in the for loop and string is guaranteed WORD aligned.
; IMPORTANT: there are 2 cases if the test for '\n' or ^Z pass.
; 1) AH passed, so di must be increment twice for '++current'
; 2) AL passed, inc di once for '++current'
;
ALIGN 2
for_loop:
dec di ; decrement di twice so it will be
dec di ; WORD aligned
mov ax, WORD PTR es:[di] ; string is WORD aligned
cmp ah, bl ; is --current '\n'?
je next_even ; yes, increment di twice to return ++current
cmp ah, bh ; is --current ^Z?
je next_even ; yes, increment di twice to return ++current
cmp al, bl ; look at low part of WORD, is it '\n'?
je inc_pointer ; yes, increment di once to return ++current
cmp al, bh ; is low part of WORD ^Z?
je inc_pointer ; yes, increment di once to return ++current
jmp SHORT for_loop ; get next WORD
ALIGN 2
return_null:
xor ax, ax ; clear ax - offset = NULL
xor dx, dx ; clear dx - segment = NULL
jmp SHORT get_out ; return text_ptr in dx:ax - see Microsoft
ALIGN 2
next_even:
inc di ; di is a WORD too far - inc di
inc_pointer:
inc di ; ++current
mov ax, di ; put offset in ax
mov dx, es ; put segment in dx, return dx:ax - Microsoft
cmp ax, 0x4000 ; are we within 16k of segment?
jae get_out ; no, get out
add ax, 0x8000 ; yes, add 32k to offset
sub dx, 0x0800 ; sub 0x0800 paragraphs to segment
ALIGN 2
get_out:
pop di ; get back di from stack
}
/*
if (*--current == ^Z)
return NULL;
for (;;) {
if (*--current == '\n' || *current == ^Z)
return ++current;
}
*/
}
/*
* Name: update_line
* Purpose: Display the current line in window
* Date: June 5, 1991
* Passed: window: pointer to current window
* Notes: Show string starting at column zero and if needed blank rest
* of line. Put max_col in cx and count down. When we run into
* '\n', cx contains number of columns to blank out. Use the
* fast 'rep stosw' to clear the end of line.
* The C routine was probably fast enough, but let's do some
* assembly because it's so fun.
* To handle line lengths longer than 255 characters,
* block begin and end columns were changed from real
* to virtual columns in this display routine.
*/
void update_line( WINDOW *window )
{
text_ptr text; /* current character of orig begin considered */
char far *screen_ptr;
int off;
int attr;
int line;
int col;
int bcol;
int bc, ec;
int normal, block;
int max_col;
int block_line;
int show_eol;
int len;
int c;
long rline;
file_infos *file;
if (window->rline > window->file_info->length)
return;
file = window->file_info;
max_col = window->end_col + 1 - window->start_col;
line = window->cline;
normal = g_display.text_color;
block = g_display.block_color;
show_eol = mode.show_eol;
/*
* set the screen pointer to physical screen memory.
*/
screen_ptr = g_display.display_address;
/* 160 = 80 chars + 80 attr for each line */
off = line * 160 + window->start_col * 2;
/*
* figure which line to display. assume we are displaying window->cursor.
* if the current line is in the line buffer, then text will be the
* same as buff_line, which means we need to display the line_buff.
*/
text = cpf( window->cursor );
if (g_status.copied && ptoul( text ) == ptoul( g_status.buff_line ))
text = g_status.line_buff;
/*
* lets look at the base column. if the line to display is shorter
* than the base column, then set text to eol and we can't see the
* eol either.
*/
bc = window->bcol;
if (bc > 0) {
if ((col = linelen( text )) < bc) {
bc = col;
show_eol = FALSE;
}
text += bc;
}
bcol = window->bcol;
rline = window->rline;
if (file->block_type && rline >= file->block_br && rline <= file->block_er)
block_line = TRUE;
else
block_line = FALSE;
/*
* do this if 1) a box block is marked, or 2) a stream block begins
* and ends on the same line.
*/
if (block_line == TRUE && (file->block_type == BOX ||
(file->block_type == STREAM &&
rline == file->block_br && rline == file->block_er))) {
len = linelen( text );
/*
* start with the bc and ec equal to physical block marker.
*/
bc = file->block_bc;
ec = file->block_ec;
if (ec < bcol || bc >= bcol + max_col)
/*
* we can't see block if ending column is less than the base col or
* the beginning column is greater than max_col.
*/
ec = bc = max_col + 1;
else if (ec < bcol + max_col) {
/*
* if the ec is less than the max column, make ec relative to
* base column then figure the bc.
*/
ec = ec - bcol;
if (bc < bcol)
bc = 0;
else
bc = bc - bcol;
} else if (bc < bcol + max_col) {
/*
* if the bc is less than the max column, make bc relative to
* base column then figure the ec.
*/
bc = bc - bcol;
if (ec > bcol + max_col)
ec = max_col;
else
ec = ec - bcol;
} else if (bc < bcol && ec >= bcol + max_col) {
/*
* if the block is wider than the screen, make bc start at the
* logical begin and make ec end at the logical end of the
* window.
*/
bc = 0;
ec = max_col;
}
_asm {
push ds ; MUST save ds - push it on stack
push si ; save si on stack
push di ; save di on stack
; on the stack so we can pop it when we're thru displaying line.
mov ax, WORD PTR show_eol ; get the show_eol flag
push ax ; push the flag
;
; set up local register variables
;
mov ax, WORD PTR bc ; get beginning column
mov bl, al ; keep it in bl
mov ax, WORD PTR ec ; get ending column
mov bh, al ; keep it in bh
mov ax, WORD PTR normal ; get normal attribute
mov dl, al ; keep it in dl
mov ax, WORD PTR block ; get block attribute
mov dh, al ; keep it in dh
mov ax, WORD PTR max_col ; get max number columns on screen
mov ch, al ; keep it in ch
xor cl, cl ; col = 0, keep col in cl
;
; load screen and text pointer
;
mov di, WORD PTR screen_ptr ; load OFFSET of screen ptr
add di, WORD PTR off ; add offset of line
mov ax, WORD PTR screen_ptr+2 ; load SEGMENT of screen ptr
mov es, ax
mov si, WORD PTR text ; load OFFSET of text ptr
mov ax, WORD PTR text+2 ; load SEGMENT of text ptr
mov ds, ax ; move segment of text in ds
cmp si, 0 ; is offset of text ptr == NULL?
jne not_null ; no, output string
cmp ax, 0 ; is segment of text ptr == NULL?
je block_eol ; yes, clear end of line
not_null:
ALIGN 2
top:
cmp cl, ch ; is col == max_col 0?
je getout ; yes, thru with line
lodsb ; get next char in string
cmp al, CONTROL_Z ; is it ^Z?
je block_eol ; yes, must check block past ^Z
cmp al, '\n' ; is it '\n'?
je dspl_eol ; yes, must check block past '\n'
mov ah, dl ; assume normal attribute
cmp cl, bl ; is col < bc? (less than beginning col)
jl ch_out1 ; yes, show char and normal attribute
cmp cl, bh ; is col > ec? (greater than ending col)
jg ch_out1 ; yes, show char and normal attribute
mov ah, dh ; must be in a block - show block attribute
ch_out1:
stosw ; else show char on screen
inc cl ; ++col
jmp SHORT top ; get another character
ALIGN 2
dspl_eol:
pop ax ; look at the show_eol flag
push ax ; push it back on stack
or ax, ax ; or the flag - test for 0
je block_eol ; show_eol flag is FALSE, blank line
mov al, EOL_CHAR ; load some eol indicator
mov ah, dl ; assume normal attribute
cmp cl, bl ; is col < bc? (less than beginning col)
jl ch_out2 ; yes, show char and normal attribute
cmp cl, bh ; is col > ec? (greater than ending col)
jg ch_out2 ; yes, show char and normal attribute
mov ah, dh ; must be in a block - show block attribute
ALIGN 2
ch_out2:
stosw ; write eol and attribute to screen
inc cl ; ++col
cmp cl, ch ; is col == max_col?
je getout ; yes, we're done
ALIGN 2
block_eol:
mov al, ' ' ; clear rest of line w/ spaces
b1:
mov ah, dl ; assume normal attribute
cmp cl, bl ; is col < bc? (less than beginning col)
jl ch_out3 ; yes, show char and normal attribute
cmp cl, bh ; is col > ec? (greater than ending col)
jg ch_out3 ; yes, show char and normal attribute
mov ah, dh ; must be in a block - show block attribute
ALIGN 2
ch_out3:
stosw ; write blank and attribute to screen
inc cl ; ++col
cmp cl, ch ; is col == max_col?
jl b1 ; while less output block
ALIGN 2
getout:
add sp, 2 ; "pop" the show_eol flag
pop di
pop si
pop ds
}
/*
for (col=0; col < max_col; col++) {
attr = normal;
if (col >= bc && col <= ec)
attr = block;
if (col < len)
c = text[col];
else
c = ' ';
update_char( c, col, line, attr );
}
*/
} else if (block_line == TRUE && file->block_type == STREAM &&
(rline == file->block_br || rline == file->block_er)) {
len = linelen( text );
if (rline == file->block_br)
bc = file->block_bc;
else {
bc = file->block_ec + 1;
ec = normal;
normal = block;
block = ec;
}
if (bc < bcol)
bc = 0;
else if (bc < bcol + max_col)
bc = bc - bcol;
else
bc = max_col + 1;
_asm {
push ds ; MUST save ds - push it on stack
push si ; save si on stack
push di ; save di on stack
; on the stack so we can pop it when we're thru displaying line.
mov ax, WORD PTR show_eol ; get the show_eol flag
push ax ; push the flag
;
; set up local register variables
;
mov ax, WORD PTR bc ; get beginning column
mov bl, al ; keep it in bl
mov ax, WORD PTR normal ; get normal attribute
mov dl, al ; keep it in dl
mov ax, WORD PTR block ; get block attribute
mov dh, al ; keep it in dh
mov ax, WORD PTR max_col ; get max number columns on screen
mov ch, al ; keep it in ch
xor cl, cl ; col = 0, keep col in cl
;
; load screen and text pointer
;
mov di, WORD PTR screen_ptr ; load OFFSET of screen ptr
add di, WORD PTR off ; add offset of line
mov ax, WORD PTR screen_ptr+2 ; load SEGMENT of screen ptr
mov es, ax
mov si, WORD PTR text ; load OFFSET of text ptr
mov ax, WORD PTR text+2 ; load SEGMENT of text ptr
mov ds, ax ; move segment of text in ds
cmp si, 0 ; is offset of text ptr == NULL?
jne nott_null ; no, output string
cmp ax, 0 ; is segment of text ptr == NULL?
je stream_eol ; yes, clear end of line
nott_null:
ALIGN 2
ttop:
cmp cl, ch ; is col == max_col?
je ggetout ; yes, thru with line
lodsb ; get next char in string
cmp al, CONTROL_Z ; is it ^Z?
je stream_eol ; yes, must check block past ^Z
cmp al, '\n' ; is it '\n'?
je ddspl_eol ; yes, must check block past '\n'
mov ah, dl ; assume normal attribute
cmp cl, bl ; is col < bc? (less than beginning col)
jl str_out1 ; yes, show char and normal attribute
mov ah, dh ; must be in a block - show block attribute
ALIGN 2
str_out1:
stosw ; else show char on screen
inc cl ; ++col
jmp SHORT ttop ; get another character
ALIGN 2
ddspl_eol:
pop ax ; look at the show_eol flag
push ax ; push it back on stack
or ax, ax ; or the flag - test for 0
je stream_eol ; show_eol flag is FALSE, blank line
mov al, EOL_CHAR ; load some eol indicator
mov ah, dl ; assume normal attribute
cmp cl, bl ; is col < bc? (less than beginning col)
jl str_out2 ; yes, show char and normal attribute
mov ah, dh ; must be in a block - show block attribute
ALIGN 2
str_out2:
stosw ; write blank and attribute to screen
inc cl ; ++col
cmp cl, ch ; is col == max_col?
je ggetout ; yes, we're done
ALIGN 2
stream_eol:
mov al, ' ' ; clear rest of line w/ spaces
ALIGN 2
c1:
mov ah, dl ; assume normal attribute
cmp cl, bl ; is col < bc? (less than beginning col)
jl str_out3 ; yes, show char and normal attribute
mov ah, dh ; must be in a block - show block attribute
ALIGN 2
str_out3:
stosw ; write blank and attribute to screen
inc cl ; ++col
cmp cl, ch ; is col == max_col?
jl c1 ; while less output block
ALIGN 2
ggetout:
add sp, 2 ; "pop" show_eol
pop di
pop si
pop ds
}
/*
for (col=0; col < max_col; col++) {
attr = normal;
if (col >= bc && col <= ec)
attr = block;
if (col < len)
c = text[col];
else
c = ' ';
update_char( c, col, line, attr );
}
*/
} else {
if (block_line)
attr = block;
else
attr = normal;
_asm {
mov dx, ds ; MUST save ds - keep it in dx
push di ; save di on stack
push si ; save si on stack
; on the stack so we can pop it when we're thru displaying line.
mov ax, WORD PTR show_eol ; get the show_eol flag
push ax ; push the flag
mov bx, WORD PTR attr ; keep attribute in bl
mov bh, '\n' ; keep '\n' in bh
mov cx, WORD PTR max_col ; keep max_col in cx
mov di, WORD PTR screen_ptr ; load OFFST of screen ptr
add di, WORD PTR off ; add offset of line
mov ax, WORD PTR screen_ptr+2 ; load SEGMENT of screen ptr
mov es, ax
mov si, WORD PTR text ; load OFFSET of text ptr
mov ax, WORD PTR text+2 ; load SEGMENT of text ptr
mov ds, ax ; move segment of text in ds
cmp si, 0 ; is offset of pointer == NULL?
jne nnot_null ; no, output string
cmp ax, 0 ; is segment of pointer == NULL?
je clreol ; yes, then clear rest of line
nnot_null:
mov ah, bl ; get attribute
ALIGN 2
topp:
or cx, cx ; col == 0 ?
je getoutt ; yes, thru with line
lodsb ; get next char in string
cmp al, CONTROL_Z ; is it ^Z
je clreol ; yes, clear end of line
cmp al, bh ; is it '\n'
je normeol ; yes, clear end of line
stosw ; else show char on screen
dec cx ; --col, count down from max_column
jmp SHORT topp ; get another character
ALIGN 2
normeol:
pop ax ; look at the show_eol flag
push ax ; push it back on stack
or ax, ax ; or the flag - test for 0
je clreol ; show_eol flag is FALSE, blank line
mov al, EOL_CHAR ; load some eol indicator
mov ah, bl ; assume normal attribute
stosw ; write blank and attribute to screen
dec cl ; ++col
or cl, cl ; is col == 0?
je getoutt ; yes, we're done
ALIGN 2
clreol:
mov ah, bl ; get attribute
mov al, ' ' ; clear eol with ' '
rep stosw ; count is in cx - set rest of line to ' '
ALIGN 2
getoutt:
add sp, 2 ; "pop" show_eol
pop si
pop di
mov ds, dx
}
}
/*
if (orig != NULL) {
text = orig;
screen_ptr = g_display.display_address + line * 160 + col * 2;
for (; *text != '\n' && *text != ^Z && col < max_col; text++, col++) {
*screen_ptr++ = *text;
*screen_ptr++ = attr;
}
}
if (col < max_col)
eol_clear( col, line, attr );
*/
}
/*
* Name: c_output
* Purpose: Output one character on prompt lines
* Date: June 5, 1991
* Passed: c: character to output to screen
* col: col to display character
* line: line number to display character
* attr: attribute of character
* Returns: none
*/
void c_output( int c, int col, int line, int attr )
{
void far *screen_ptr;
int off;
screen_ptr = (void far *)g_display.display_address;
off = line * 160 + col * 2;
_asm {
mov bx, WORD PTR screen_ptr ; load OFFSET of screen ptr
add bx, WORD PTR off ; add offset of line:col
mov ax, WORD PTR screen_ptr+2 ; load SEGMENT of screen ptr
mov es, ax
mov cx, WORD PTR attr ; get attribute
mov ah, cl ; put in ah
mov cx, WORD PTR c ; get character
mov al, cl ; put in al
mov WORD PTR es:[bx], ax ; show char on screen
}
/*
screen_ptr = g_display.display_address + line * 160 + col * 2;
*screen_ptr++ = c;
*screen_ptr = attr;
*/
}
/*
* Name: s_output
* Purpose: To output a string
* Date: June 5, 1991
* Passed: s: string to output
* line: line to display
* col: column to begin display
* attr: color to display string
* Notes: This function is used to output most strings not part of file text.
*
* All strings in the SMALL memory model are in the default NEAR data
* segment (used in production version of tde). Prototype the output
* string as far because when compiling for debugging, you must
* compile with the LARGE library since the /Zi code will not
* fit in the SMALL model.
*/
void s_output( char far *s, int line, int col, int attr )
{
void far *screen_ptr;
int off;
int max_col;
max_col = g_display.ncols;
screen_ptr = (void far *)g_display.display_address;
off = line * 160 + col * 2;
_asm {
push ds ; save ds on stack
push di ; save di on stack
push si ; save si on stack
mov bx, WORD PTR attr ; keep attribute in bx
mov cx, WORD PTR col ; put cols in cx
mov dx, WORD PTR max_col ; keep max_col in dx
mov di, WORD PTR screen_ptr ; load OFFSET of screen ptr
add di, WORD PTR off ; add offset of line:col
mov ax, WORD PTR screen_ptr+2 ; load SEGMENT of screen ptr
mov es, ax
mov si, WORD PTR s ; load offset of string ptr
or si, si ; is it == NULL?
je getout ; yes, no output needed
mov ax, WORD PTR s+2 ; load segment of string ptr
or ax, ax ; is pointer == NULL?
je getout ; yes, no output needed
mov ds, ax ; load segment of text in ds
mov ah, bl ; put attribute in AH
ALIGN 2
top:
cmp cx, dx ; col < max_cols?
jge getout ; no, thru with line
lodsb ; get next char in string - put in al
or al, al ; is it '\0'
je getout ; yes, end of string
cmp al, '\n' ; is it '\n'?
je getout ; yes, end of string
stosw ; else show attr + char on screen (ah + al)
inc cx ; col++
jmp SHORT top ; get another character
ALIGN 2
getout:
pop si ; get back si
pop di ; get back di
pop ds ; get back ds
}
/*
screen_ptr = g_display.display_address + line * 160 + col * 2;
max_col = g_display.ncols;
while (*s && col < max) {
*screen_ptr++ = *s++;
*screen_ptr++ = attr;
}
*/
}
/*
* Name: eol_clear
* Purpose: To clear the line from col to max columns
* Date: June 5, 1991
* Passed: col: column to begin clear
* line: line to clear
* attr: color to clear
* Notes: Basic assembly
*/
void eol_clear( int col, int line, int attr )
{
int max_col;
void far *screen_ptr;
int off;
max_col = g_display.ncols;
screen_ptr = (void far *)g_display.display_address;
off = line * 160 + col * 2;
_asm {
push di ; save di on stack
mov bx, WORD PTR attr ; keep attribute in bx
mov dx, WORD PTR col ; put cols in dx
mov cx, WORD PTR max_col ; put max_col in cx
cmp dx, cx ; max_cols < cols?
jge getout ; no, thru with line
sub cx, dx ; number of column to clear
mov di, WORD PTR screen_ptr ; load OFFSET of screen ptr
add di, WORD PTR off ; add offset of line:col
mov ax, WORD PTR screen_ptr+2 ; load SEGMENT of screen ptr
mov es, ax
mov ah, bl ; get attribute in ah
mov al, ' ' ; store ' ' in al
rep stosw ; clear to end of line
getout:
pop di ; get back di from stack
}
/*
for (; col < g_display.ncols; col++) {
*p++ = ' ';
*p++ = attr;
}
*/
}
/*
* Name: window_eol_clear
* Purpose: To clear the line from start_col to end_col
* Date: June 5, 1991
* Passed: col: column to begin clear
* line: line to clear
* attr: color to clear
* Notes: Basic assembly
*/
void window_eol_clear( WINDOW *window, int attr )
{
int max_col;
void far *screen_ptr;
int off;
screen_ptr = (void far *)g_display.display_address;
off = window->cline * 160 + window->start_col * 2;
max_col = window->end_col + 1 - window->start_col;
_asm {
push di ; save di on stack
mov bx, WORD PTR attr ; keep attribute in bx
mov cx, WORD PTR max_col ; put max_col in cx
mov di, WORD PTR screen_ptr ; load OFFSET of screen ptr
add di, WORD PTR off ; add offset of line:col
mov ax, WORD PTR screen_ptr+2 ; load SEGMENT of screen ptr
mov es, ax
mov ah, bl ; get attribute in ah
mov al, ' ' ; store ' ' in al
rep stosw ; clear to end of line
getout:
pop di ; get back di from stack
}
/*
for (; col < g_display.ncols; col++) {
*p++ = ' ';
*p++ = attr;
}
*/
}
/*
* Name: upper_asm
* Purpose: To convert all lower case characters to upper characters
* Date: June 5, 1991
* Passed: s: the starting point
* count: number of characters to convert (unsigned)
* Returns: none
* Notes: This function goes faster if machine works with WORDs. See if
* first BYTE in string is WORD aligned. If it is not, get first
* BYTE in string then the rest of string is WORD aligned.
*
* The pointer should have been normalized, using the nptos, as
* this function does not handle segment wrap.
*
* ax, ah, al = characters from string
* bl = 'a'
* bh = 'z'
* cx = number of characters to look at
* dl = 0x20, xor 0x20 with lower case to get upper case
* ds:si = far pointer to character string
* use ds:si so there is no segment override
*/
void upper_asm( text_ptr s, unsigned count )
{
_asm {
push ds ; save ds on stack
push si ; save si on stack
mov cx, WORD PTR count ; load count in cx
jcxz get_out ; 1st, if count == 0 then do nothing
mov si, WORD PTR s ; load OFFSET of s
mov ax, WORD PTR s+2 ; load SEGMENT of s
mov ds, ax
or si, si ; is offset of string == NULL or 0?
jne not_null ; no, do string stuff
or ax, ax ; is segment of string == NULL or 0?
je get_out ; yes, don't upper case a NULL string
ALIGN 2
not_null:
mov bh, 'z' ; keep 'z' in bh
mov bl, 'a' ; keep 'a' in bl
mov dl, 0x20 ; keep 0x20 in dl
mov ax, si ; move offset of si to ax
shr ax, 1 ; shift right into carry flag
jnc top ; is string WORD aligned?
mov al, BYTE PTR [si] ; no, get a BYTE
cmp al, bl ; is al < 'a' (use unsigned test)
jb word_align ; yes, dec count and align on WORD
cmp al, bh ; is al > 'z' (use unsigned test)
ja word_align ; yes, dec count and align on WORD
xor al, dl ; convert lower case to upper
mov BYTE PTR [si], al ; store the character or BYTE
ALIGN 2
word_align:
inc si ; inc the string pointer - now WORD aligned
dec cx ; decrement the character count
jcxz get_out ; if count or cx == 0 then we're done, get_out
ALIGN 2
top:
mov ax, WORD PTR [si] ; string is WORD aligned, get two BYTEs
cmp al, bl ; is al < 'a'?
jb upper_hi ; yes, dec count and check the hi byte
cmp al, bh ; is al > 'z'?
ja upper_hi ; yes, dec count and check the hi byte
xor al, dl ; convert lower case to upper
ALIGN 2
upper_hi:
dec cx ; decrement the count
jcxz clean_up ; if count or cx == 0 then we're done, clean_up
cmp ah, bl ; is al < 'a'?
jb save_word ; yes, dec count and do next word
cmp ah, bh ; is al > 'z'?
ja save_word ; yes, dec count and do next word
xor ah, dl ; convert lower case to upper
ALIGN 2
save_word:
mov WORD PTR [si], ax ; else, save changes
dec cx ; decrement the count
jcxz get_out ; if count or cx == 0 then we're done, get_out
inc si ; increment the pointer to next word
inc si
jmp SHORT top ; look at next WORD
ALIGN 2
clean_up:
mov WORD PTR [si], ax ; else, save changes then we're done
ALIGN 2
get_out:
pop si ; get back si from stack
pop ds ; get back ds from stack
}
/*
while (count-- > 0) {
if (*s >= 'a' && *s <= 'z')
*s++ &= 0xdf;
}
*/
}
/*
* Name: lower_asm
* Purpose: To convert all upper case characters to lower characters
* Date: June 5, 1991
* Passed: s: the starting point
* count: number of characters to convert (unsigned)
* Returns: none
* Notes: This function goes faster if machine works with WORDs. See if
* first BYTE in string is WORD aligned. If it is not, get first
* BYTE in string then the rest of string is WORD aligned.
*
* The pointer should have been normalized, using the nptos, as
* this function does not handle segment wrap. One could safely
* pass a count of 0xFFF0 if the pointer has been normalized to
* a segment
*
* ax, ah, al = characters from string
* bl = 'A'
* bh = 'Z'
* cx = number of characters to look at, unsigned
* dl = 0x20, or upper case with 0x20 to get lower case
* ds:si = far pointer to character string
* use ds:si so there is no segment override
*/
void lower_asm( text_ptr s, unsigned count )
{
_asm {
push ds ; save ds on stack
push si ; save si on stack
mov cx, WORD PTR count ; load count in cx
jcxz get_out ; 1st, if count == 0 then do nothing
mov si, WORD PTR s ; load OFFSET of s
mov ax, WORD PTR s+2 ; load SEGMENT of s
mov ds, ax
or si, si ; is offset of string == NULL or 0?
jne not_null ; no, do string stuff
or ax, ax ; is segment of string == NULL or 0?
je get_out ; yes, don't upper case a NULL string
ALIGN 2
not_null:
mov bh, 'Z' ; keep 'z' in bh
mov bl, 'A' ; keep 'a' in bl
mov dl, 0x20 ; keep 0x20 in dl
mov ax, si ; move offset of si to ax
shr ax, 1 ; shift right into carry flag
jnc top ; is string WORD aligned?
mov al, BYTE PTR [si] ; no, get a BYTE
cmp al, bl ; is al < 'A' (use unsigned test)
jb word_align ; yes, dec count and align on WORD
cmp al, bh ; is al > 'Z' (use unsigned test)
ja word_align ; yes, dec count and align on WORD
or al, dl ; convert upper case to lower
mov BYTE PTR [si], al ; store the character or BYTE
ALIGN 2
word_align:
inc si ; inc the string pointer - now WORD aligned
dec cx ; decrement the character count
jcxz get_out ; if count or cx == 0 then we're done
ALIGN 2
top:
mov ax, WORD PTR [si] ; string is WORD aligned, get two BYTEs
cmp al, bl ; is al < 'A'?
jb lower_hi ; yes, dec count and check the hi byte
cmp al, bh ; is al > 'Z'?
ja lower_hi ; yes, dec count and check the hi byte
or al, dl ; convert upper case to lower
ALIGN 2
lower_hi:
dec cx ; decrement the character count
jcxz clean_up ; if count or cx == 0 then we're done, clean_up
cmp ah, bl ; is al < 'A'?
jb save_word ; yes, dec count and do next word
cmp ah, bh ; is al > 'Z'?
ja save_word ; yes, dec count and do next word
or ah, dl ; convert upper case to lower
ALIGN 2
save_word:
mov WORD PTR [si], ax ; else, save changes
dec cx ; decrement the count
jcxz get_out ; if count or cx == 0 then we're done, get out
inc si ; increment the pointer to next word
inc si
jmp SHORT top ; look at next WORD
ALIGN 2
clean_up:
mov WORD PTR [si], ax ; else, save changes then we're done
ALIGN 2
get_out:
pop si ; get back si from stack
pop ds ; get back ds from stack
}
/*
while (count-- > 0) {
if (*s >= 'a' && *s <= 'z')
*s++ &= 0xdf;
}
*/
}
/*
* Name: strip_asm
* Purpose: To strip bit 7 from characters
* Date: June 5, 1991
* Passed: s: the starting point, which should be normalized to a segment
* count: number of characters to strip (unsigned)
* count should not be greater than 0xfff0
* Returns: none
* Notes: This function goes faster if machine works with WORDs. See if
* first BYTE in string is WORD aligned. If it is not, get first
* BYTE in string then the rest of string is WORD aligned.
*
* The pointer should have been normalized, using the nptos, as
* this function does not handle segment wrap.
*
* ax, ah, al = characters from string
* bl = 01111111 or 0x7f to strip the hi bit from characters
* cx = number of characters to look at
* ds:si = far pointer to character string
* use ds:si so there is no segment override
*/
void strip_asm( text_ptr s, unsigned count )
{
_asm {
push ds ; save ds on stack
push si ; save si on stack
mov cx, WORD PTR count ; load count in cx
jcxz get_out ; 1st, if count == 0 then do nothing
mov si, WORD PTR s ; load OFFSET of s
mov ax, WORD PTR s+2 ; load SEGMENT of s
mov ds, ax
or si, si ; is offset of string == NULL or 0?
jne not_null ; no, do string stuff
or ax, ax ; is segment of string == NULL or 0?
je get_out ; yes, don't upper case a NULL string
ALIGN 2
not_null:
mov bl, 0x7f ; turn all bits except high bit in bl
mov ax, si ; move offset of si to ax
shr ax, 1 ; shift right into carry flag
jnc top ; is string WORD aligned?
mov al, BYTE PTR [si] ; no, get a BYTE
and al, bl ; strip the high bit
mov BYTE PTR [si], al ; store the character or BYTE
word_align:
inc si ; inc the string pointer - now WORD aligned
dec cx ; dec the character count
jcxz get_out ; if count or cx == 0 then we're done
ALIGN 2
top:
mov ax, WORD PTR [si] ; string is WORD aligned, get two BYTEs
and al, bl ; strip the hi bit from the lo byte
dec cx ; decrement the count
jcxz clean_up ; if count or cx == 0 then let's clean up
and ah, bl ; strip the hi bit from the hi byte
mov WORD PTR [si], ax ; save changes
dec cx ; decrement the count
jcxz get_out ; if count or cx == 0 then we're done
inc si ; increment the pointer to next word
inc si
jmp SHORT top ; look at next WORD
ALIGN 2
clean_up:
mov WORD PTR [si], ax ; else, save changes then we're done
ALIGN 2
get_out:
pop si ; get back si from stack
pop ds ; get back ds from stack
}
/*
while (count-- > 0) {
if (*s >= 'a' && *s <= 'z')
*s++ &= 0xdf;
}
*/
}
/*
* Name: get_fattr
* Purpose: To get dos file attributes
* Date: December 26, 1991
* Passed: fname: ASCIIZ file name. Null terminated file name
* fattr: pointer to file attributes
* Returns: 0 if successfull, non zero if not
* Notes: Uses the DOS function to get file attributes. I really didn't
* like the file attribute functions in the C library: fstat() and
* stat() or access() and chmod().
* FYI, File Attributes:
* 0x00 = Normal. Can be read or written w/o restriction
* 0x01 = Read-only. Cannot be opened for write; a file with
* the same name cannot be created.
* 0x02 = Hidden. Not found by directory search.
* 0x04 = System. Not found by directory search.
* 0x08 = Volumn Label.
* 0x10 = Directory.
* 0x20 = Archive. Set whenever the file is changed, or
* cleared by the Backup command.
* Return codes:
* 0 = No error
* 1 = AL not 0 or 1
* 2 = file is invalid or does not exist
* 3 = path is invalid or does not exist
* 5 = Access denied
*/
int get_fattr( char far *fname, int *fattr )
{
int rc; /* return code */
int attr;
_asm {
push ds
mov dx, WORD PTR fname ; get OFFSET of filename string
mov ax, WORD PTR fname+2 ; get SEGMENT of filename string
mov ds, ax ; put SEGMENT in ds
mov ax, 0x4300 ; function: get file attributes
int 0x21 ; DOS interrupt
pop ds
jc an_error ; save the error code from get attr
xor ax, ax ; if no carry, no error
jmp SHORT get_out ; lets get out
an_error:
xor cx, cx ; if error, then zero out cx - attrs
get_out:
mov WORD PTR rc, ax ; ax contains error number on error
mov WORD PTR attr, cx ; cx contains file attributes
}
*fattr = attr;
if (ceh.flag == ERROR)
rc = ERROR;
return( rc );
}
/*
* Name: set_fattr
* Purpose: To set dos file attributes
* Date: December 26, 1991
* Passed: fname: ASCIIZ file name. Null terminated file name
* fattr: file attributes
* Returns: 0 if successfull, non zero if not
* Notes: Uses the DOS function to get file attributes.
* Return codes:
* 0 = No error
* 1 = AL not 0 or 1
* 2 = file is invalid or does not exist
* 3 = path is invalid or does not exist
* 5 = Access denied
*/
int set_fattr( char far *fname, int fattr )
{
int rc; /* return code */
_asm {
push ds
mov dx, WORD PTR fname ; get OFFSET of filename string
mov ax, WORD PTR fname+2 ; get SEGMENT of filename string
mov ds, ax ; put SEGMENT in ds
mov cx, WORD PTR fattr ; cx contains file attributes
mov ax, 0x4301 ; function: get file attributes
int 0x21 ; DOS interrupt
pop ds
jc get_out ; save the error code from get attr
xor ax, ax ; if no carry, no error
get_out:
mov WORD PTR rc, ax ; ax contains error number on error
}
if (ceh.flag == ERROR)
rc = ERROR;
return( rc );
}
/*
* Name: get_current_directory
* Purpose: get current directory
* Date: February 13, 1992
* Passed: path: pointer to buffer to store path
* drive: drive to get current directory
* Notes: use simple DOS interrupt
*/
int get_current_directory( char far *path, int drive )
{
int rc;
_asm {
push si ; save register vars if any
push ds ; save ds
mov dx, WORD PTR drive ; dl = drive, 0 = default, 1 = a, etc..
mov si, WORD PTR path ; get OFFSET of path
mov ax, WORD PTR path+2 ; get SEGMENT of path
mov ds, ax ; put it in ds
mov ah, 0x47 ; function 0x47 == get current dir
int 0x21 ; standard DOS interrupt
xor ax, ax ; zero out ax, return OK if no error
jnc no_error ; if carry set, then an error
mov ax, -1 ; return -1 if error
no_error:
pop ds ; get back ds
pop si ; get back si
mov WORD PTR rc, ax ; save return code
}
if (ceh.flag == ERROR)
rc = ERROR;
return( rc );
}
/*
* Name: set_current_directory
* Purpose: set current directory
* Date: February 13, 1992
* Passed: new_path: directory path which may include drive letter
* Notes: use simple DOS interrupt
*/
int set_current_directory( char far *new_path )
{
int rc;
_asm {
push ds ; save ds
mov dx, WORD PTR new_path ; get OFFSET of new_path
mov ax, WORD PTR new_path+2 ; get SEGMENT of new_path
mov ds, ax ; put it in ds
mov ah, 0x3b ; function 0x3b == set current dir
int 0x21 ; standard DOS interrupt
xor ax, ax ; zero out ax, return OK if no error
jnc no_error ; if carry set, then an error
mov ax, -1 ; return -1 if error
no_error:
pop ds ; get back ds
mov WORD PTR rc, ax ; save return code
}
if (ceh.flag == ERROR)
rc = ERROR;
return( rc );
}
/*
* Name: hlight_line
* Date: July 21, 1991
* Passed: x: column to begin hi lite
* y: line to begin hi lite
* lgth: number of characters to hi lite
* attr: attribute color
* Notes: The attribute byte is the hi byte.
*/
void hlight_line( int x, int y, int lgth, int attr )
{
int off;
void far *screen_ptr;
screen_ptr = (void far *)g_display.display_address;
off = y * 160 + 2 * x + 1; /* add one - so it points to attribute byte */
_asm {
push di ; save di
mov cx, lgth ; number of characters to change color
mov di, WORD PTR screen_ptr ; get destination - video memory
add di, off ; add offset
mov ax, WORD PTR screen_ptr+2
mov es, ax
mov ax, attr ; attribute
lite_len:
stosb ; store a BYTE
inc di ; skip over character to next attribute
loop lite_len ; change next attribute
pop di ; restore di
}
}
/*
* Name: cls
* Purpose: clear screen
* Date: June 5, 1991
* Notes: Call the video BIOS routine to clear the screen.
*/
void cls( void )
{
int line;
line = g_display.nlines+1;
_asm {
xor ch, ch ; starting row in ch = 0
xor cl, cl ; starting column in cl = 0
mov ax, WORD PTR line ; get ending row
mov dh, al ; put it in dh
mov dl, 79 ; ending column in dl = 79
mov bh, 7 ; attribute in bh = 7 (normal)
mov al, 0 ; get number of lines
mov ah, 6 ; get function number
push bp ; some BIOS versions wipe out bp
int 0x10
pop bp
}
}
/*
* Name: set_cursor_size
* Purpose: To set cursor size according to insert mode.
* Date: June 5, 1991
* Passed: csize: desired cursor size
* Notes: use the global display structures to set the cursor size
*/
void set_cursor_size( int csize )
{
_asm {
mov ah, 1 ; function 1 - set cursor size
mov cx, WORD PTR csize ; get cursor size ch:cl == top:bot
int VIDEO_INT ; video interrupt = 10h
}
}
/*
* Name: findfirst
* Purpose: find the first file matching a pattern using DOS interrupt
* Date: January 6, 1992
* Passed: dta: disk transfer address
* path: path to search for files
* f_attr: attributes of files to search for
* Notes: return codes for findfirst:
* 0 no error
* 2 file is invalid or does not exist
* 3 path is invalid or does not exist
* 18 no matching directory entry was found
* -1 check the critical error flag for critical errors
*/
int findfirst( DTA far *dta, char far *path, int f_attr )
{
void far *old_dta;
void far *new_dta;
int rc;
new_dta = (void far *)dta;
_asm {
; save the old dta
mov ah, 0x2f ; DOS get dta
int 0x21 ; DOS interrupt
mov WORD PTR old_dta, bx ; save OFFSET of old DTA
mov ax, es
mov WORD PTR old_dta+2, ax ; save SEGMENT of old DTA
; set the new dta
push ds ; save ds
mov dx, WORD PTR new_dta ; get OFFSET of new dta
mov ax, WORD PTR new_dta+2 ; get SEGMENT of new dta
mov ds, ax ; put it in ds
mov ah, 0x1a ; DOS set dta
int 0x21 ; DOS interrupt
pop ds ; get back ds
; find first matching file
push ds ; save ds
mov cx, WORD PTR f_attr ; file attributes to search for
mov dx, WORD PTR path ; get OFFSET of path
mov ax, WORD PTR path+2 ; get SEGMENT of path
mov ds, ax ; put it in ds
mov ah, 0x4e ; DOS find first file
int 0x21 ; DOS interrupt
pop ds ; get back ds
; save the return code
jc an_error ; carry is set if an error occured
xor ax, ax ; zero out ax, return OK if no error
an_error:
mov WORD PTR rc, ax ; save the return code
; get back old dta
push ds ; save ds
mov dx, WORD PTR old_dta ; get OFFSET of old dta
mov ax, WORD PTR old_dta+2 ; get SEGMENT of old dta
mov ds, ax ; put it in ds
mov ah, 0x1a ; DOS set dta
int 0x21 ; DOS interrupt
pop ds ; get back ds
}
if (ceh.flag == ERROR)
rc = ERROR;
return( rc );
}
/*
* Name: findnext
* Purpose: find the next file matching a pattern using DOS interrupt
* Date: January 6, 1992
* Passed: dta: disk transfer address
* Notes: findfirst() MUST be called before calling this function.
* return codes for findnext:
* 0 no error
* 2 path is invalid or does not exist
* 18 no matching directory entry was found
* -1 check the critical error flag for critical errors
*/
int findnext( DTA far *dta )
{
void far *old_dta;
void far *new_dta;
int rc;
new_dta = (void far *)dta;
_asm {
; save the old dta
mov ah, 0x2f ; DOS get dta
int 0x21 ; DOS interrupt
mov WORD PTR old_dta, bx ; save OFFSET of old DTA
mov ax, es
mov WORD PTR old_dta+2, ax ; save SEGMENT of old DTA
; set the new dta
push ds ; save ds
mov dx, WORD PTR new_dta ; get OFFSET of new dta
mov ax, WORD PTR new_dta+2 ; get SEGMENT of new dta
mov ds, ax ; put it in ds
mov ah, 0x1a ; DOS set dta
int 0x21 ; DOS interrupt
pop ds ; get back ds
; find next matching file
mov ah, 0x4f ; DOS find first file
int 0x21 ; DOS interrupt
; save the return code
jc an_error ; carry is set if an error occured
xor ax, ax ; zero out ax, return OK if no error
an_error:
mov WORD PTR rc, ax ; save the return code
; get back old dta
push ds ; save ds
mov dx, WORD PTR old_dta ; get OFFSET of old dta
mov ax, WORD PTR old_dta+2 ; get SEGMENT of old dta
mov ds, ax ; put it in ds
mov ah, 0x1a ; DOS set dta
int 0x21 ; DOS interrupt
pop ds ; get back ds
}
if (ceh.flag == ERROR)
rc = ERROR;
return( rc );
}