keep obj/fcntl mcopy fcntl.macros case on **************************************************************** * * fcntl - UNIX primitive input/output facilities * * This code implements the tables and subroutines needed to * support a subset of the UNIX library FCNTL. * * October 1989 * Mike Westerfield * * Copyright 1989 * Byte Works, Inc. * **************************************************************** * FCNTL start dummy segment copy equates.asm strSize gequ 255 max size of a GS/OS path name end **************************************************************** * * ctoosstr - convert a C string to a GS/OS input string * * Inputs: * cstr - pointer to the c string * * Outputs: * returns a pointer to the OS string * * Notes: * If the C string is longer than strSize bytes, the * string is truncated without warning. * **************************************************************** * ctoosstr private osptr equ 1 os string pointer csubroutine (4:cstr),4 phb use a local B reg phk plb short M copy over the characters ldy #0 lb1 lda [cstr],Y beq lb2 sta osstr+2,Y iny cpy #strSize bne lb1 lb2 sty osstr set the string length long M lla osptr,osstr set the address of the string plb restore caller's B creturn 4:osptr return osptr osstr ds 2+strSize GS/OS string buffer end **************************************************************** * * int chmod(char *path, int mode); * * Changes the access bits. * * Inputs: * path - name of the file * mode - zero or more flags to set: * 0x0100 - read * 0x0080 - write * 0x1000 - delete * 0x2000 - rename * 0x4000 - backup * 0x8000 - invisible * * Outputs: * returns 0 if successful; else -1 * errno - set if an error occurred * **************************************************************** * chmod start err equ 1 error return code csubroutine (4:path,2:mode),2 phb use local B phk plb stz err err = 0 {no error} lda mode convert mode to ProDOS format jsr unixtoprodos sta siAccess ph4 errno dec err lb2 plb creturn 2:err cbRec dc i'1' ClearBackup record cbPathname ds 4 siRec dc i'2' SetFileInfo record siPathname ds 4 siAccess ds 2 end **************************************************************** * * int close(int filds); * * Close a file. * * Inputs: * filds - file ID of the file to close * * Outputs: * returns 0 if successful; else -1 * errno - set if an error occurred * **************************************************************** * close start err equ 1 error return code csubroutine (2:filds),2 stz err err = 0 {no error} lda filds error if there are too many open files cmp #OPEN_MAX bge lb2 asl A get the file reference number asl A tax lda >files,X beq lb2 sta >clRefnum lda #0 free the file record sta >files,X ldx #OPEN_MAX*4-4 for each file record do lda >clRefnum if the file is a duplicate then lb1 cmp >files,X beq lb3 skip the close dex dex dex dex bpl lb1 OSClose clRec close the file bcc lb3 lb2 lda #EBADF an error occurred - set errno sta >errno dec err err = -1 lb3 creturn 2:err clRec dc i'1' close record clRefnum ds 2 end **************************************************************** * * int creat(char *path, int mode); * * Create a file. * * Inputs: * path - name of the file * mode - zero or more flags to set: * 0x0100 - read * 0x0080 - write * 0x1000 - delete * 0x2000 - rename * 0x4000 - backup * 0x8000 - invisible * * Outputs: * returns 0 if successful; else -1 * errno - set if an error occurred * **************************************************************** * creat start err equ 1 error return code csubroutine (4:path,2:mode),2 ph2 #O_WRONLY+O_TRUNC+O_CREAT ph2 errno bra lb7 lb1 lda filds error if there are too many open files cmp #OPEN_MAX bge lb2 asl A get the file reference number asl A tax lda >files,X bne lb3 lb2 dec err flag an invalid filds error lda #EBADF sta >errno bra lb7 lb3 sta refnum lda >files+2,X get the file flags sta flags lda arg find a new filds cmp #OPEN_MAX bge lb5 asl A asl A lb4 lda >files,X beq lb6 inx inx inx inx cpx #OPEN_MAX*4 bne lb4 lb5 dec err none are available -- flag the error lda #EMFILE sta >errno bra lb7 lb6 lda refnum set the new refnum sta >files,X lda flags set the new flags sta >files+2,X txa return the filds lsr A lsr A sta err lb7 creturn 2:err end **************************************************************** * * files - array of file records * * There are OPEN_MAX elements, each with the following format: * * bytes use * ----- --- * 2 file reference number; 0 if element is free * 2 flags; set by open command * * Notes: Array calculations throughout the module depend on * a record size within the array of exactly 4 bytes. * **************************************************************** * files private ds 4*OPEN_MAX end **************************************************************** * * long lseek(int filds, long offset, int whence); * * Set the file mark * * Inputs: * filds - file ID of file * offset - new file mark * whence - set the mark in relation to: * 0 - file start * 1 - current mark * 2 - file end * * Outputs: * returns file pointer if successful; -1 for an error * errno - set if an error occurred * **************************************************************** * lseek start mark equ 1 new file mark csubroutine (2:filds,4:offset,2:whence),4 lda #$FFFF assume we will get an error sta mark sta mark+2 lda filds get the file refnum cmp #OPEN_MAX bge lb1 asl A asl A tax lda >files,X bne lb2 lb1 bra lb4a bad refnum error lb2 sta >smRefnum set the file refnum sta >gmRefnum lda whence convert from UNIX whence to GS/OS base cmp #SEEK_SET if whence == 0 (SEEK_SET) bne lb2a lda offset+2 if offset is negative bmi lb4 fail with EINVAL lda #0 set mark to offset bra lb3 lb2a cmp #SEEK_END else if whence == 2 (SEEK_END) bne lb2c lda offset+2 if offset > 0 bmi lb2b ora offset bne lb4 fail with EINVAL lb2b sub4 #0,offset,offset negate offset lda #1 set mark to EOF - offset bra lb3 lb2c cmp #SEEK_CUR else if whence == 1 (SEEK_CUR) bne lb4 lda offset if offset is positive or 0 bmi lb2d lda #2 set mark to old mark + offset bra lb3 else lb2d sub4 #0,offset,offset negate offset lda #3 set mark to old mark - offset lb3 sta >smBase save the base parameter lb3a lda offset set the displacement sta >smDisplacement lda offset+2 sta >smDisplacement+2 OSSet_Mark smRec set the file mark bcc lb5 cmp #$4D out of range error => fail with EINVAL bne lb4a lb4 lda #EINVAL bra lb4b lb4a lda #EBADF bad refnum error lb4b sta >errno bra lb6 lb5 OSGet_Mark gmRec get the new mark bcs lb4a lda >gmDisplacement sta mark lda >gmDisplacement+2 sta mark+2 lb6 creturn 4:mark smRec dc i'3' SetMark record smRefnum ds 2 smBase ds 2 smDisplacement ds 4 gmRec dc i'2' GetMark record gmRefnum ds 2 gmDisplacement ds 4 end **************************************************************** * * int open(char *path, int oflag); * * Open a file * * Inputs: * path - name of the file * oflag - output flags * * Outputs: * returns 0 if successful; else -1 * errno - set if an error occurred * **************************************************************** * open start err equ 1 error return code csubroutine (4:path,2:oflag),2 ph2 errno brl lb11 lb2 stx index save the index to the file ph4 errno bra lb11 lb4a ph2 errno bra lb11 lb7 OSCreate crRec create the file bcs lb9 lb8 anop OSOpen opRec open the file bcs lb9 lda oflag if the O_TRUNC flag is set then and #O_TRUNC beq lb10 lda opRefnum set the EOF to 0 sta efRefnum OSSet_EOF efRec bcc lb10 lb9 dec err flag an I/O error lda #EACCES sta >errno bra lb11 lb10 lda opRefnum save the reference number ldx index sta files,X txa set the return file index lsr A lsr A sta err lb11 plb restore the caller's B creturn 2:err crRec dc i'3' Create record crPathname ds 4 crAccess ds 2 crFileType ds 2 giRec dc i'2' GetFileInfo record giPathname ds 4 ds 2 opRec dc i'2' Open record opRefnum ds 2 opPathname ds 4 efRec dc i'3' SetEOF record efRefnum ds 2 dc i'0' dc i4'0' end **************************************************************** * * int read(int filds, char *buf, int n); * * Read from a file * * Inputs: * filds - file ID of file * buf - file buffer * n - # of bytes to read * * Outputs: * returns 0 if successful; else -1 * errno - set if an error occurred * **************************************************************** * read start err equ 1 error return code csubroutine (2:filds,4:buf,2:n),2 stz err err = 0 {no error} phb use our B phk plb lda filds error if the file has not been opened cmp #OPEN_MAX bge lb0 asl A get the file reference number asl A tax lda files,X beq lb0 sta rdRefnum stx filds lda files+2,X make sure the file is open for reading and #O_RDONLY+O_RDWR bne lb0a lb0 lda #EBADF errno = EBANF sta >errno dec err return = -1 bra lb5 lb0a move4 buf,rdDataBuffer set the location to read to lda n set the number of bytes to read sta rdRequestCount OSRead rdRec read the bytes bcc lb1 if an error occurred cmp #$4C and it was not EOF then beq lb1 lda #EIO errno = EIO sta >errno dec err return -1 bra lb5 lb1 ldy rdTransferCount return the bytes read sty err beq lb5 lb2 ldx filds if the file is not binary then lda files+2,X and #O_BINARY bne lb5 dey for each byte do beq lb4a short M lb3 lda [buf],Y if the byte is \r then cmp #13 bne lb4 lda #10 change it to \n sta [buf],Y lb4 dey next byte bne lb3 lb4a lda [buf] if the first byte is \r then cmp #13 bne lb4b lda #10 change it to \n sta [buf] lb4b long M lb5 plb restore B creturn 2:err rdRec dc i'4' Read record rdRefnum ds 2 rdDataBuffer ds 4 rdRequestCount ds 4 rdTransferCount ds 4 end **************************************************************** * * unixtoprodos - Convert UNIX access flags to ProDOS access flags * * Inputs: * A - UNIX access flags * * Outputs: * A - ProDOS access flags * **************************************************************** * unixtoprodos private bits equ 3 ProDOS bits pea 0 set ProDOS bits to 0 phd set up a stack frame tax tsc tcd txa bit #$1000 if unix delete bit is set then beq lb1 sec set the ProDOS delete bit rol bits lb1 bit #$2000 if unix rename bit is set then beq lb2 sec set the ProDOS rename bit bra lb3 else lb2 clc clear the ProDOS rename bit lb3 rol bits bit #$4000 if unix backup bit is set then beq lb4 sec set the ProDOS backup bit bra lb5 else lb4 clc clear the ProDOS backup bit lb5 rol bits rol bits roll in the two unused bit fields rol bits bit #$8000 if unix invisible bit is set then beq lb6 sec set the ProDOS invisible bit bra lb7 else lb6 clc clear the ProDOS invisible bit lb7 rol bits bit #$0080 if unix write bit is set then beq lb8 sec set the ProDOS write bit bra lb9 else lb8 clc clear the ProDOS write bit lb9 rol bits bit #$0100 if unix read bit is set then beq lb10 sec set the ProDOS read bit bra lb11 else lb10 clc clear the ProDOS read bit lb11 rol bits pld return the new flags pla rts end **************************************************************** * * int write(filds, char *buf, unsigned n); * * Write to a file * * Inputs: * filds - file ID of file * buf - file buffer * n - # of bytes to write * * Outputs: * returns 0 if successful; else -1 * errno - set if an error occurred * **************************************************************** * write start err equ 1 error return code nbuff equ 3 new buffer pointer csubroutine (2:filds,4:buf,2:n),6 stz err err = 0 {no error} phb use our B phk plb lda filds error if the file has not been opened cmp #OPEN_MAX bge lb0 asl A get the file reference number asl A tax lda files,X beq lb0 sta wrRefnum sta smRefnum stx filds lda files+2,X make sure the file is open for writing and #O_WRONLY+O_RDWR bne lb0a lb0 lda #EBADF errno = EBADF sta >errno dec err return = -1 brl lb5 lb0a move4 buf,wrDataBuffer set the location to write from lda n set the number of bytes to read sta wrRequestCount stz nbuff nbuff == nil stz nbuff+2 ldx filds if the file is not binary then lda files+2,X and #O_BINARY bne lb0g pea 0 reserve a file buffer ph2 errno bra lb5 lb0b ldy n move the bytes to the new buffer, beq lb0f converting \n chars to \r chars dey in the process beq lb0da short M lb0c lda [buf],Y cmp #10 bne lb0d lda #13 lb0d sta [nbuff],Y dey bne lb0c lb0da lda [buf] cmp #10 bne lb0e lda #13 lb0e sta [nbuff] long M lb0f move4 nbuff,wrDataBuffer set the data buffer start lb0g ldx filds if the file is in O_APPEND mode then lda files+2,X and #O_APPEND beq lb0h OSSet_Mark smRec set mark to EOF lb0h OSWrite wrRec write the bytes bcc lb1 if an error occurred then lda #EIO errno = EIO sta >errno dec err return -1 bra lb5 lb1 ldy wrTransferCount return the bytes read sty err lda nbuff if nbuff <> NULL then ora nbuff+2 beq lb2 ph4