Compare commits

...

13 Commits

Author SHA1 Message Date
Stephen Heumann 5b04986f08 Add tool glue code for ReadMouse2.
This is documented in TBR3 and is already declared in <misctool.h>, but did not previously have glue code. TBR3 says "Applications should never make this call," but it may be useful in system utilities.
2024-04-17 19:57:23 -05:00
Stephen Heumann d9e26d4467 Small optimizations related to 8/16-bit register switching. 2024-03-22 21:10:33 -05:00
Stephen Heumann 0e519e1e58 Small optimizations in memset and memcpy. 2024-02-29 17:16:47 -06:00
Stephen Heumann 49ffb1065b Unroll the core loop of strlen one time.
This makes the core loop about 10% faster at the cost of 5 extra code bytes, which seems like a reasonable tradeoff.
2024-02-26 22:14:59 -06:00
Stephen Heumann 9181b0bd73 fclose: Free the file buffer earlier.
This moves the free() call for the file buffer before the malloc() that occurs when closing a temp file, which should at least slightly reduce the chances that the malloc() call fails.
2024-02-20 22:22:26 -06:00
Stephen Heumann 7384c82667 fclose: Check for malloc failure when closing temp files.
Previously, the code for closing a temporary file assumed that malloc would succeed. If it did not, the code would trash memory and (at least in my testing) crash the system. Now it checks for and handles malloc failures, although they will still lead to the temporary file not being deleted.

Here is a test program illustrating the problem:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
        FILE *f = tmpfile();
        if (!f)
                return 0;

        void *p;
        do {
                p = malloc(8*1024);
        } while (p);

        fclose(f);
}
2024-02-20 22:20:17 -06:00
Stephen Heumann 16c7952648 fclose: close stream even if there is an error flushing buffered data.
This can happen, e.g., if there is an IO error or if there is insufficient free disk space to flush the data. In this case, fclose should return -1 to report an error, but it should still effectively close the stream and deallocate the buffer for it. (This behavior is explicitly specified in the C99 and later standards.)

Previously, ORCA/C effectively left the stream open in these cases. As a result, the buffer was not deallocated. More importantly, this could cause the program to hang at exit, because the stream would never be removed from the list of open files.

Here is an example program that demonstrates the problem:

/*
 * Run this on a volume with less than 1MB of free space, e.g. a floppy.
 * The fclose return value should be -1 (EOF), indicating an error, but
 * the two RealFreeMem values should be close to each other (indicating
 * that the buffer was freed), and the program should not hang on exit.
 */

#include <stdio.h>
#include <stddef.h>
#include <memory.h>

#define BUFFER_SIZE 1000000

int main(void) {
        size_t i;
        int ret;

        printf("At start, RealFreeMem = %lu\n", RealFreeMem());

        FILE *f = fopen("testfile", "wb");
        if (!f)
                return 0;

        setvbuf(f, NULL, _IOFBF, BUFFER_SIZE);

        for (i = 0; i < BUFFER_SIZE; i++) {
                putc('x', f);
        }

        ret = fclose(f);
        printf("fclose return value = %d\n", ret);

        printf("At end, RealFreeMem = %lu (should be close to start value)\n",
                RealFreeMem());
}
2024-02-19 22:30:15 -06:00
Stephen Heumann 9d42552756 strncmp: Fix issues related to very large n values.
This fixes the following issues:
*If n was 0x80000000 or greater, strncmp would return 0 without performing a comparison.
*If n was 0x1000000 or greater, strncmp might compare fewer characters than it should because the high byte of n was effectively ignored, causing it to return 0 when it should not.

Here is an example demonstrating these issues:

#pragma memorymodel 1
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define LEN 100000
int main(void) {
        char *s1 = malloc(LEN+1);
        char *s2 = malloc(LEN+1);
        if (!s1 || !s2)
                return 0;
        for (unsigned long i = 0; i < LEN; i++) {
                s2[i] = s1[i] = '0' + (i & 0x07);
        }
        s1[LEN] = 'x';
        return strncmp(s1,s2,0xFFFFFFFF);
}
2024-02-19 22:12:26 -06:00
Stephen Heumann bbfad1e299 strncat: fix more issues related to large n values.
This addresses the following issues:
*If the low-order 16 bits of n were 0x0000, no concatenation would be performed.
*If n was 0x1000000 or greater, the output could be cut off prematurely because the high byte of n was effectively ignored.

The following test program demonstrates these issues:

#pragma memorymodel 1
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define LEN2 100000
int main(void) {
        char *s1 = malloc(LEN2+2);
        char *s2 = malloc(LEN2+1);
        if (!s1 || !s2)
                return 0;
        for (unsigned long i = 0; i < LEN2; i++)
                s2[i] = '0' + (i & 0x07);
        strcpy(s1,"a");
        strncat(s1, s2, 0x1000000);
        puts(s1);
        printf("len = %zu\n", strlen(s1));
}
2024-02-19 22:01:53 -06:00
Stephen Heumann f1582be5a2 Fix handling of large strings in strncat.
There were two issues:
*If bit 15 of the n value was set, the second string would not be copied.
*If the length of the second string was 64K or more, it would not be copied properly because the pointers were not updated.

This test program demonstrates both issues:

#pragma memorymodel 1
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define LEN2 100000
int main(void) {
        char *s1 = malloc(LEN2+2);
        char *s2 = malloc(LEN2+1);
        if (!s1 || !s2)
                return 0;
        for (unsigned long i = 0; i < LEN2; i++)
                s2[i] = '0' + (i & 0x07);
        strcpy(s1,"a");
        strncat(s1, s2, LEN2);
        puts(s1);
        printf("len = %zu\n", strlen(s1));
}
2024-02-18 21:53:03 -06:00
Stephen Heumann b60c307ee6 Make strcat and strncat work properly when first string crosses a bank boundary.
Previously, the pointer was not properly updated to account for the bank crossing, so the characters from the second string would be written to the wrong bank.

Here is an example that illustrates this:

#include <memory.h>
#include <string.h>
#include <orca.h>
#include <stdio.h>
int main(void) {
        Handle hndl = NewHandle(0x1000f, userid(), 0xC000, 0);
        if (toolerror())
                return 0;
        char *s = *hndl;
        s = (void*)((unsigned long)s | 0xffff);
        strcpy(s, "foo");
        strcat(s, "bar");
        strncat(s, "baz", 5);
        puts(s);
}
2024-02-18 21:01:01 -06:00
Stephen Heumann bf3a4d7ceb Small optimizations in library code.
There should be no functional differences.
2024-02-18 17:35:21 -06:00
Stephen Heumann ce87c0e008 Add script to set filetypes. 2023-08-06 17:48:41 -05:00
7 changed files with 178 additions and 112 deletions

10
settypes Normal file
View File

@ -0,0 +1,10 @@
filetype -p =.asm src; change -p =.asm asm65816
filetype -p =.macros src; change -p =.macros asm65816
filetype m16.int64 src; change m16.int64 exec
filetype smac src; change smac asm65816
filetype backup src; change backup exec
filetype make src; change make exec
filetype settypes src; change settypes exec
filetype LICENSE txt
filetype README.md txt
filetype obj:README.txt txt

View File

@ -107,9 +107,8 @@ lb2 asl A get the signal handler address
tay
lda >subABRT-2,X
bmi lb3 skip if it is SIG_DFL or SIG_IGN
short M set up the call address
sta >jsl+3
long M
xba set up the call address
sta >jsl+2
tya
sta >jsl+1
ph2 <sig call the user signal handler

100
stdio.asm
View File

@ -83,16 +83,13 @@ stdfile equ 7 is this a standard file?
phk
plb
lda #EOF assume we will get an error
sta err
ph4 <stream verify that stream exists
jsl ~VerifyStream
jcs rts
jcs rts_err
ph4 <stream do any pending I/O
jsl fflush
tax
jne rts
sta err initialize err to fflush result
stz stdfile not a standard file
lda stream+2 bypass file disposal if the file is
@ -110,11 +107,10 @@ lb1 inc stdfile
cl0 lla p,stderr+4 find the file record that points to this
ldy #2 one
cl1 lda [p]
ora [p],Y
jeq rts
lda [p],Y
cl1 lda [p],Y
tax
ora [p]
jeq rts_err
lda [p]
cmp stream
bne cl2
@ -128,46 +124,10 @@ cl3 lda [stream] remove stream from the file list
sta [p]
lda [stream],Y
sta [p],Y
cl3a ldy #FILE_flag if the file was opened by tmpfile then
lda [stream],Y
and #_IOTEMPFILE
beq cl3d
ph4 #nameBuffSize p = malloc(nameBuffSize)
jsl malloc grPathname = p
sta p dsPathname = p+2
stx p+2
sta grPathname
stx grPathname+2
clc
adc #2
bcc cl3b
inx
cl3b sta dsPathname
stx dsPathname+2
lda #nameBuffSize p->size = nameBuffSize
sta [p]
ldy #FILE_file clRefnum = grRefnum = stream->_file
lda [stream],Y
beq cl3e
sta grRefnum
GetRefInfoGS gr GetRefInfoGS(gr)
bcs cl3c
lda grRefnum OSClose(cl)
sta clRefNum
OSClose cl
DestroyGS ds DestroyGS(ds)
cl3c ph4 <p free(p)
jsl free
bra cl3e else
cl3d ldy #FILE_file close the file
lda [stream],Y
beq cl3e
sta clRefNum
OSClose cl
cl3e ldy #FILE_flag if the buffer was allocated by fopen then
cl3a ldy #FILE_flag if the buffer was allocated by fopen then
lda [stream],Y
and #_IOMYBUF
beq cl4
beq cl3b
ldy #FILE_base+2 dispose of the file buffer
lda [stream],Y
pha
@ -176,6 +136,47 @@ cl3e ldy #FILE_flag if the buffer was allocated by fopen the
lda [stream],Y
pha
jsl free
cl3b ldy #FILE_flag if the file was opened by tmpfile then
lda [stream],Y
and #_IOTEMPFILE
beq cl3f
ph4 #nameBuffSize p = malloc(nameBuffSize)
jsl malloc
sta p
stx p+2
ora p+2 if p == NULL then
bne cl3c
lda #EOF flag error
sta err
bra cl3f just close the file
cl3c lda p
sta grPathname grPathname = p
stx grPathname+2
clc dsPathname = p+2
adc #2
bcc cl3d
inx
cl3d sta dsPathname
stx dsPathname+2
lda #nameBuffSize p->size = nameBuffSize
sta [p]
ldy #FILE_file clRefnum = grRefnum = stream->_file
lda [stream],Y
beq cl4
sta grRefnum
sta clRefNum
GetRefInfoGS gr GetRefInfoGS(gr)
bcs cl3e
OSClose cl OSClose(cl)
DestroyGS ds DestroyGS(ds)
cl3e ph4 <p free(p)
jsl free
bra cl4 else
cl3f ldy #FILE_file close the file
lda [stream],Y
beq cl4
sta clRefNum
OSClose cl
cl4 lda stdfile if this is not a standard file then
bne cl5
ph4 <stream dispose of the file buffer
@ -189,7 +190,10 @@ cl6 lda [p],Y
dey
cpy #2
bne cl6
cl7 stz err no error found
cl7 bra rts no error found
rts_err lda #EOF
sta err
rts plb
creturn 2:err

View File

@ -1584,16 +1584,13 @@ cn3 cmp base branch if the digit is too big
cn3a clc add in the new digit
adc val
sta val
lda val+2
adc #0
sta val+2
lda val+4
adc #0
sta val+4
lda val+6
adc #0
sta val+6
bcc cn4
inc val+2
bne cn4
inc val+4
bne cn4
inc val+6
bne cn4
stz rangeOK
cn4 inc4 str next char
bra cn1

View File

@ -244,8 +244,8 @@ lb3 lda [p1],Y scan until the end of memory is reached
dex
bne lb3
ldx #0 memory matches
bra lb5
; ldx #0
bra lb5 memory matches
lb4 blt less memory differs - set the result
ldx #1
@ -253,9 +253,9 @@ lb4 blt less memory differs - set the result
less ldx #-1
lb5 long M
lda rtl remove the parameters from the stack
lb5 lda rtl remove the parameters from the stack
sta len+1
long M
lda rtl+1
sta len+2
pld
@ -303,8 +303,8 @@ rtl equ 1 return address
short M move 1 byte now
lda [p2]
sta [p1]
long M
dec len
long M
inc4 p1
inc4 p2
lb1 anop endif
@ -436,11 +436,11 @@ lb10 lda [p2],Y
dex
bne lb9
lb11 long M
ply get the original source pointer
lb11 ply get the original source pointer
plx
lda rtl remove the parameters from the stack
sta len+1
long M
lda rtl+1
sta len+2
pld
@ -482,19 +482,19 @@ rtl equ 1 return address
ph4 <p save the pointer
short M
lda val form a 2 byte value
sta val+1
short I,M
ldx val form a 2 byte value
stx val+1
lda len if there are an odd # of bytes then
lsr A
bcc lb1
lda val set 1 byte now
txa set 1 byte now
sta [p]
long M
dec len
long I,M
inc4 p
lb1 long M endif
lb1 long I,M endif
lda val set len bytes
ldx len+2 set full banks
@ -616,7 +616,9 @@ lb2 long M
clc
adc s1
sta s1
short M copy characters 'til the null is found
bcc lb2a
inc s1+2
lb2a short M copy characters 'til the null is found
ldy #0
lb3 lda [s2],Y
sta [s1],Y
@ -627,9 +629,9 @@ lb3 lda [s2],Y
inc s2+2
bra lb3
lb4 long M return to the caller
lda rtl
lb4 lda rtl return to the caller
sta s2+1
long M
lda rtl+1
sta s2+2
ldx rval+2
@ -749,9 +751,9 @@ less ldx #-1 It wasn't, so *s1 < *s2
lb3 blt less the strings differ - set the result
ldx #1
lb4 long M
lda rtl remove the parameters from the stack
lb4 lda rtl remove the parameters from the stack
sta s2+1
long M
lda rtl+1
sta s2+2
pld
@ -828,9 +830,9 @@ lb1 lda [s2],Y
inc s2+2
bra lb1
lb2 long M return to the caller
lda rtl
lb2 lda rtl return to the caller
sta s2+1
long M
lda rtl+1
sta s2+2
ldx rval+2
@ -956,9 +958,12 @@ str equ 4 pointer to the string
tcd
ldy #0 advance s1 to point to the terminating
ldx #0 null
tyx null
short M
lb1 lda [str],Y
beq lb2
iny
lda [str],Y
beq lb2
iny
bne lb1
@ -966,10 +971,10 @@ lb1 lda [str],Y
inc str+2
bra lb1
lb2 long M
pld remove str from the stack
lda 2,S
sta 6,S
lb2 pld remove str from the stack
lda 3,S
sta 7,S
long M
pla
sta 3,S
pla
@ -1013,27 +1018,35 @@ lb2 long M
clc
adc s1
sta s1
short M copy characters 'til the null is found
bcc lb2a
inc s1+2
lb2a ldx n copy characters 'til the null is found
bne lb2b
lda n+2
beq lb6
lb2b short M
ldy #0
ldx n
beq lb4
bmi lb4
lb3 lda [s2],Y
sta [s1],Y
beq lb4
beq lb5
iny
dex
bne lb3a
inc s1+2
inc s2+2
lb3a dex
bne lb3
lda n+2
ldx n+2
beq lb4
dec n+2
dex
stx n+2
ldx #0
bra lb3
lb4 lda #0 write the terminating null
sta [s1],Y
long M return to the caller
lb5 long M return to the caller
creturn 4:rval
lb6 creturn 4:rval
end
****************************************************************
@ -1060,7 +1073,6 @@ flag equ 1 return flag
ldy #0 scan until the end of string is reached
ldx n+2 or a difference is found
bmi equal
bne lb0
ldx n
beq equal
@ -1072,9 +1084,11 @@ lb1 lda [s1],Y
bne lb3
dex
bne lb1a
lda n+2
ldx n+2
beq equal
dec n+2
dex
stx n+2
ldx #0
lb1a iny
bne lb1
inc s1+2
@ -1189,20 +1203,19 @@ lb1 lda [s],Y
short M
bra lb1
lb2 long I,M no match found -> return NULL
ldx #0
lb2 ldx #0 no match found -> return NULL
txy
long I,M
bra lb4
lb3 long I,M increment s by Y and load the value
tya
and #$00FF
clc
adc s
tay
lda s+2
adc #0
tax
ldx s+2
bcc lb4
inx
lb4 lda rtl+1 remove the parameters
sta set+2
@ -1252,10 +1265,10 @@ lb1 lda [str],Y
lb2 ldy #-1 no match found -> return -1
lb3 long M
pld remove parameters from the stack
lda 2,S
sta 8,S
lb3 pld remove parameters from the stack
lda 3,S
sta 9,S
long M
pla
sta 5,S
pla
@ -1363,10 +1376,10 @@ lb2 cmp #0
iny
bpl lb1
lb3 long M
pld remove parameters from the stack
lda 2,S
sta 8,S
lb3 pld remove parameters from the stack
lda 3,S
sta 9,S
long M
pla
sta 5,S
pla

View File

@ -206,6 +206,44 @@ yPos ds 2
xPos ds 2
end
****************************************************************
*
* ReadMouse2 - return mouse statistics
*
* Outputs:
* Returns a pointer to a record with the following
* structure:
*
* typedef struct MouseRec {
* char mouseMode;
* char mouseStatus;
* int yPos;
* int xPos;
* }
*
****************************************************************
*
ReadMouse2 start
pha
pha
pha
_ReadMouse2
sta >~TOOLERROR
pl2 >mouseMode
pl2 >yPos
pl2 >xPos
lda #mouseMode
ldx #^mouseMode
rtl
mouseMode ds 1
mouseStatus ds 1
yPos ds 2
xPos ds 2
end
****************************************************************
*
* ReadTimeHex - returns the time in hex format

View File

@ -384,3 +384,8 @@
&lab ldx #$1F23
jsl $E10000
MEND
MACRO
&lab _ReadMouse2
&lab ldx #$3303
jsl $E10000
MEND