The C64 OS Programmer's Guide is being written
This guide is being written and released and few chapters at a time. If a chapter seems to be empty, or if you click a chapter in the table of contents but it loads up Chapter 1, that's mostly likely because the chapter you've clicked doesn't exist yet.
Discussion of development topics are on-going about what to put in this guide. The discusssions are happening in the C64 OS Community Support Discord server, available to licensed C64 OS users.
C64 OS PROGRAMMER'S GUIDE
Chapter 4: Using the KERNAL → File (module)
Thin abstraction of the KERNAL ROM and CBM DOS
The KERNAL ROM's routines only operate on channels to devices, and reading or writing single bytes to and from those channels. The File KERNAL module does not do away with the KERNAL ROM, and it does not reimplement any part of the DOS found on each storage device. It is instead a thin wrapper on the KERNAL ROM's concept of logical file numbers, device numbers, secondary addresses, the C64's input and output channel, and the CHKIN/CHKOUT, CHRIN/CHROUT pairs of routines.
The File KERNAL routines operate on C64 OS file reference structures. There are two representations of a C64 OS file reference: A memory structure, and a serialized string. The routine frefcvt can be used to convert the in-memory structure to the serialized string format, or vice versa.
The in-memory structure must be page aligned and each component is found at a standard offset within the page. The string format is designed to be human readable, reminiscent of the standard path format pioneered by CMD and used by IDE64 and SD2IEC. The string format is useful for being written to config files, for being displayed on screen, or for being taken as input from the user.
File Reference (in-memory structure)Constant | Offset | Size | Notes |
---|---|---|---|
frefdev | 0 | 1 | Device # (1 to 30) |
frefpart | 1 | 1 | Partition # (1 to 255) |
freflfn | 2 | 1 | Logical File Number. 0 = File not open. |
frefblks | 3 | 2 | 16-bit (little endian) block size of the file on disk. |
frefname | 5 | 17 | 16 character filename, null terminated. |
frefpath | 22 | 234 | Absolute path from root of partition, null terminated. |
The path is the only component that is of arbitrary length, which is why it comes at the end of the structure. This allows it to be appended into the free space at the end of the page, up to a maximum of 234 characters.
Saving memory
In order to save memory, if it is known that the path of a given file reference will not exceed some maximum length (e.g., 40 characters,) then the remaining space in the page may be used for other purposes.
Having other data stored after the file reference structure in the page will not interfere with the ability of the File routines to use the file reference. They stop at the null terminator of the path component. Just beware, if you append to the path, it may overwrite whatever else is stored later in the page.
A valid path must begin with two slashes, which means root directory. Each additional subdirectory, including the final subdirectory, must end with a slash.
INVALID: os/c64tools/ /os/c64tools/ //os/c64tools VALID: //os/c64tools/
File Reference (serialized string format)
Each of the components is separated by a full colon. The components are, device number, partition number, filename, path.
8:10:PRGAlias Creator://os/c64tools/
The above example is a file reference to the file called "PRGAlias Creator", which is found on device 8, partition 10, at the absolute path "//os/c64tools/".
The path must be valid, and is the same path format used for the in-memory file reference. The serialized file reference cannot be used to open a file, therefore it does not have any representation of the logical file number or the block size of the file. A serialized file reference has to first be converted to an in-memory structure before it can be used to open a file. When a KERNAL or library routine says that they take a pointer to a file reference, it is always to a file reference in-memory structure, unless otherwise explicitly noted.
File-based ClipboardThe C64 OS universal clipboard is based on the file system. While it is technically possible to read from and write to the clipboard using just file routines, a series of clipboard-related routines are provided as a convenience. These are a thin wrapper on fopen, fread, fwrite, and fclose.
finit
Purpose | Initialize the drive to work with a file reference. |
---|---|
Module offset | 0 |
Communication registers | A, X, Y |
Stack requirements | 11 bytes + |
Zero page usage | $1c, $1d, $61, $62, $63, $64, $65, $66, $67, $68, $ba |
Registers affected | A, X, Y |
Input parameters | RegPtr → Pointer to file reference. |
Output parameters |
C ← Set on error. A ← Error code. X ← Current device's Command Channel's LFN. currentdv ← Set to FileRef's device number. |
NOTE: The KERNAL ROM must be patched in to call finit.
Description: Prepares the drive to access the file specified by the file reference by initializing the drive's defaults. Sets the C64's current device, represented by currentdv. Changes the device's default partition. Changes the device's current path. Checks for errors in the process of changing partition and path, and updates the status bar. Returns the error state in the carry.
The routine returns in the X register the logical file number to the command channel to the new current device. The KERNAL ROM routines CHKIN and CHKOUT both take the logical file number in the X register. This allows you to call finit on a file reference and then immediately issue a command to that device, relative to the partition and path where the file is found, without needing to explicitly know any of the numbers involved.
The following example shows how to rename a file represented by a fileref, by lowercasing its name.
ferror
Purpose | Read the current device's error channel. |
---|---|
Module offset | 3 |
Communication registers | A |
Stack requirements | 11 bytes + |
Zero page usage | $61, $62, $63, $64, $65, $66, $67, $68, $ba |
Registers affected | A, X, Y |
Input parameters | currentdv → The current device number. |
Output parameters | A ← The current device's drive status code. |
NOTE: The KERNAL ROM must be patched in to call ferror.
Description: This routine is used to read the current device's drive status code. It doesn't take any input parameters, but uses the workspace variable currentdv, which is set by finit and fopen.
Ferror clears the current device's error channel, and thus stops a drive's error LED from blinking after an error occurred. The drive's status is saved in workspace memory and the status bar is told to update by calling updstat in the Service KERNAL module.
The drive's status code is returned in the accumulator. By CBM DOS convention, codes 0 to 19 are not errors. All codes 20 and above are errors. Ferror should be called anytime after you send some command to the drive that could fail.
The following example is a slight modification on the example shown above for finit. It shows how to rename a file represented by a fileref, by lowercasing its name. However, the drive's media could be write protected, or the directory could already contain another file with the new name, etc. Because the rename command could fail, ferror should be called. If an error occurred, the original name is restored. The user can review the error message in the status bar.
Opening and Closing, Reading and Writing Files
The following four routines form a group that are almost always used together. The typical pattern is to fopen a file by file reference, fread some data out of the file to a memory buffer, then fclose the file. Or, fopen a file by file reference, fwrite a memory buffer of data to the file, then fclose the file.
Due to the importance and usefulness of this group of four routines, they can be called directly from a Utility, with the KERNAL patched out. These routines automatically patch the KERNAL in and back out for you. This is not the case for finit or ferror. Before calling finit or ferror, the KERNAL must be patched in.
The mouse pointer is automatically killed and automatically restored to its previous state at the beginning and end of fread and fwrite. If your code will make a series of separate calls to fread or fwrite, it is recommended to manually kill the mouse first, and restore it manually at the end, to prevent it from being enabled and disabled between calls to fread or fwrite.
fopen
Purpose | Open a file by file reference for read or write. |
---|---|
Module offset | 6 |
Communication registers | A, X, Y |
Stack requirements | 14 bytes + |
Zero page usage | $1c, $1d, $61, $62, $63, $64, $65, $66, $67, $68, $ba |
Registers affected | A |
Input parameters |
RegPtr → File reference to file to open. A → File Open Flags |
Output parameters |
RegPtr ← File reference to the same input file. C → Set on error A → Error code |
Description: This routine is used to open a file by file reference. The file can be opened for read, write, overwrite or append, depending on the file open flags. Load a RegPtr to a file reference and put the file open flags in the accumulator, then call fopen. The RegPtr is maintained so that it can be passed directly into the next call, either fread, fwrite or fclose. If an error occurred, the carry is returned set and the error code is in the accumulator.
Auto-allocation of Logical File Numbers
The KERNAL ROM maintains a table of 10 open files. It connects a logical file number (LFN) to a corresponding device number and secondary address. Traditionally, the KERNAL ROM requires you to choose which logical file number to use when opening a file.
C64 OS features auto-allocation of logical file numbers. A file reference holds the LFN assigned to this file. If the LFN is 0, that means the file is not open and no LFN has been assigned. Upon opening a file with fopen, the first (i.e., lowest) available logical file number is selected automatically. The LFN is written into the file reference structure, at offset freflfn. This byte serves to identify the open connection at the KERNAL ROM level, but it also serves as a flag to indicate that the file is open.
When an open file reference is closed with fclose, the process is reveresed. The low-level connection to the device is closed, freeing up one channel on that device. The logical file number is released back into the pool for auto-allocation. The freflfn property of the file reference is set back to zero, indicating that the file is closed.
When fopen is called, it automatically calls finit internally. fopen explicitly patches the KERNAL ROM in, and restores the KERNAL ROM state upon return, allowing this routine to be called directly from a Utility.
Following are the set of file open flags to specify the mode and options. These are bit flags which are OR'd together. Not every combination is valid, see the notes in the table for their usage.
Constant | Value | Direction | Notes |
---|---|---|---|
ff_r | %00000001 | input | Open an existing file for read. |
ff_s | %00000010 | input | May only be combined with ff_r, retrieve the file's block size. |
ff_w | %00000100 | output | Create and open a new file for write. Default file type: SEQ |
ff_a | %00001000 | output | Open an existing file for append. File must already exist. |
ff_o | %00010000 | output | Optional flag to combine with ff_w. If the file already exists it will be overwritten. |
— | %00100000 | — | reserved |
ff_p | %01000000 | output | Optional flag to combine with ff_w. Creates the file as PRG instead of SEQ. |
— | %10000000 | — | reserved |
fread
Purpose | Read data from an open file reference to a memory buffer. |
---|---|
Module offset | 9 |
Communication registers | A, X, Y |
Stack requirements | 8 bytes + |
Zero page usage | $1c, $1d, $1e, $1f, $20, $21, $90, $ba |
Registers affected | A |
Input parameters |
RegPtr → File reference to file fopen'd for read. a1 → .Word, pointer to memory buffer. a2 → .Word, length of data to read. |
Output parameters |
RegPtr ← File reference to file fopen'd for read. This routine raises exceptions. |
Description: This routine is used to read data of a fixed length from a file, that has previously been opened for read by fopen, into a memory buffer. Load the opened file reference into a RegPtr and call fread. This routine takes two inline arguments. The first is a word, a pointer to the memory buffer into which to read the data from the file. The second is another word, a 16-bit length of data to read.
There are no checks to confirm that the buffer is valid or has enough allocated space to hold the length of data that is read. It is therefore necessary to explicitely allocated a buffer of the necessary size, and to not read a data length greater than the allocation size.
The length to read is a maximum. If the end of the file is reached before reading in the specifed length, fread returns without modifying the remainder of the buffer.
Fread does not return anything, except that it maintains the RegPtr to the file reference. This can be used to make multiple calls to fread in a row without needing to reload the RegPtr to the file reference between calls. This routine may raises exceptions.
Mix-and-match fread with chrin
As discussed earlier, fopen and fread are a thin layer on top of the KERNAL ROM's underlying system of logical file numbers, device numbers, secondary addresses, and the CHKIN and CHRIN routines.
It is, therefore, not only possible but intentional by design to combine the use of CHKIN/CHRIN with fread. Each call to fread uses the logical file number found in the file reference to perform a CHKIN. It then performs a 16-bit loop over the length specified, and repeatedly calls CHRIN, writing each byte to the next address in the memory buffer.
It is safe, and often desirable, to read the LFN from the file reference and manually call CHKIN. You can then call CHRIN to read individual characters from the open file. Calls to fread and manual reads with calls to CHKIN/CHRIN/CLRCHN can be interleaved. However, closing the file should be performed with fclose in order to update the file reference and perform other low-level steps.
Below is an example of reading 16 bytes into a static buffer using fread. Followed by a manual read of 2 bytes into two other static variables.
fwrite
Purpose | Write data to an open file reference from a memory buffer. |
---|---|
Module offset | 12 |
Communication registers | A, X, Y |
Stack requirements | 8 bytes + |
Zero page usage | $1c, $1d, $1e, $1f, $20, $21, $90, $ba |
Registers affected | A |
Input parameters |
RegPtr → File reference to file fopen'd for write or append. a1 → .Word, pointer to memory buffer. a2 → .Word, length of data to write. |
Output parameters |
RegPtr ← File reference to file fopen'd for write or append. This routine raises exceptions. |
Description: This routine is used to write data of a fixed length to a file, that has previously been opened for write or append by fopen, from a memory buffer. Load the opened file reference into a RegPtr and call fwrite. This routine takes two inline arguments. The first is a word, a pointer to the memory buffer from which to write the data to the file. The second is another word, a 16-bit length of data to write.
There are no checks to confirm that the buffer, from which the data is being written to the file, is valid.
Fwrite does not return anything, except that it maintains the RegPtr to the file reference. This can be used to make multiple calls to fwrite in a row without needing to reload the RegPtr to the file reference between calls. This routine may raises exceptions.
Mix-and-match fwrite with chrout
As discussed earlier, fopen and fwrite are a thin layer on top of the KERNAL ROM's underlying system of logical file numbers, device numbers, secondary addresses, and the CHKOUT and CHROUT routines.
It is, therefore, not only possible but intentional by design to combine the use of CHKOUT/CHROUT with fwrite. Each call to fwrite uses the logical file number found in the file reference to perform a CHKOUT. It then performs a 16-bit loop over the length specified, and repeatedly calls CHROUT, writing each byte from the buffer out to the file.
It is safe, and often desirable, to read the LFN from the file reference and manually call CHKOUT. You can then call CHROUT to write individual characters to the open file. Calls to fwrite and manual writes with calls to CHKOUT/CHROUT/CLRCHN can be interleaved. However, closing the file should be performed with fclose in order to update the file reference and perform other low-level steps.
Below is an example of write 16 bytes from a static buffer using fwrite. Followed by a manual write of 2 bytes from two other static variables. Fopen has been opened with ff_w for write, as well as ff_o for overwrite. If the file does not yet exist, it will be created. If it already exists, it will be overwritten.
fclose
Purpose | Close a previously opened file by file reference. |
---|---|
Module offset | 15 |
Communication registers | X, Y |
Stack requirements | 8 bytes + |
Zero page usage | $1c, $1d |
Registers affected | A, X, Y |
Input parameters |
RegPtr → File reference to file previously opened with fopen. |
Output parameters | None |
Description: This routine is used to close a file that was previously opened using fopen. Call fclose by passing a RegPtr to the file reference that was passed to fopen. The file on the device is closed. The channel used on the device is freed to be used again. The logical file number is freed so it can be used again. The logical file number in the file reference is zeroed to indicate that this file is closed. The KERNAL ROM routine clrchn is called to restore the C64's default channels.
frefcvt
Purpose | Convert a file reference from string to struct or vice versa. |
---|---|
Module offset | 18 |
Communication registers | X, Y |
Stack requirements | 8 bytes |
Zero page usage | $61, $62, $63, $64, $fb, $fc, $fd, $fe |
Registers affected | A, X, Y |
Input parameters |
C → Set to serialize. RegPtr → Pointer to file reference in-memory structure C → Clear to unserialize. RegPtr → Pointer to serialized file reference string |
Output parameters |
If C was passed in Set: RegPtr ← Pointer to serialized file reference string If C was passed in Clear: RegPtr ← Pointer to file reference in-memory structure This routine raises exceptions. |
Description: This routine is used to convert a file reference between the in-memory structure format and the serialized string format. A pointer to the source format is passed as a RegPtr, and a RegPtr is returned to the target format. The carry is used to indicate whether you are performing a serialization or an unserialization.
A serialized file reference string must be null terminated.
One page of memory is allocated by the system. When this routine returns a pointer to that new memory allocation, it becomes owned by the process that called frefcvt. It is the responsibility of the process that called frefcvt to ensure that this memory is later deallocated, or memory will be leaked. If the one page of memory cannot be allocated, an exception is raised.
Below is an example of how convert a file reference string to the in-memory format, use it, and then deallocate its memory page. This is only an example, the file reference string is hardcoded to device 8, partition 10, with a path of "//text files/". This kind of hardcoding should be avoided in practice.
File-Based Universal Clipboard
C64 OS provides KERNAL-level support for a universal clipboard. Any process may write data to the clipboard, assigning a type and subtype when the data is written. Data already stored on the clipboard is automatically overwritten. Clipboard writes usually happen when the user performs a cut or copy operation. If data is cut, it is the responsibility of the process to remove from its own context the data that was written to the clipboard. This functionality is built-in to some Toolkit classes, such as the TKInput text field.
Any process may read from the clipboard. This usually happens when the user performs a paste operation. Generally speaking, any process that can read from the clipboard will check the current type, subtype and length of data on the clipboard, and determine if the data is of a type that it can read in. If the data type is not compatible, the process should reject the paste, or preferably pre-emptively prevent the user's ability to paste, such as by disabling a menu option or a button.
Workspace memory variables hold the current type, subtype and size of the clipboard. The data content of the clipboard is held in the file "//os/clipboard/:0.d". The .d extension is used for generic data of any type. The "0" filename is to allow a multi-clipboard manager to maintain multiple numbered clipboards. When the clipboard is written to, the data is written to the 0.d file and the type, subtype and size are written to "//os/clipboard/:0.t". During bootup C64 OS reads the type, subtype and clipboard size from 0.t into workspace memory. Thus, the contents of the clipboard are preserved between changing Applications and between rebooting C64 OS and power cycles of the machine.
The following clipboard workspace variables are defined by //os/s/:file.s. C64 OS data types and subtypes are defined by //os/s/:type.s.
Constant | Value | Notes |
---|---|---|
c_dtype | $246 | C64 OS Data Type |
c_dstype | $247 | C64 OS Data Subtype |
c_dsize | $248-$249 | Clipboard data size. 16-bit little endian. |
See: Appendices → Data Types for a list of
C64 OS data types and subtypes.
See also: C64 OS User's Guide Appendices → III. Data Types.
Both the Application and the Utility are sent an asynchronous clipboard changed message (mc_cpbd) whenever the clipboard contents change. This is used, for example, by the Places Utility. When Places is open, it is listening for clipboard changed messages. In response to the message, it checks if the new clipboard type/subtype is text/fref. If it is, and the cursor is in one of the text fields, it clears the text field and replaces its contents with the new file reference string from the clipboard. This is just an example of how Applications and Utilties can respond automatically when something is cut or copied to the clipboard.
clipin
Purpose | Read the clipboard into a buffer. |
---|---|
Module offset | 21 |
Communication registers | A, X, Y |
Stack requirements | 12 bytes + |
Zero page usage | $1c, $1d, $1e, $1f, $20, $21, $90, $ba |
Registers affected | A, X, Y |
Input parameters |
RegPtr → Pointer to buffer to read into. A → Maximum length to read. 0 = No limit. |
Output parameters | None. |
Description: This routine is used to read the contents of the clipboard into a buffer in the most convenient way possible. A pointer to a memory buffer into which the data will be read is passed in a RegPtr. The accumulator passes the amount of data to be read, or 0 to read the entire contents of the clipboard. Because the accumulator is 8-bit, this method can only be used to read 1 to 255 bytes, or the entire clipboard.
It is strongly recommended that you check and confirm the data type and subtype before reading the data in with clipin. It is also strongly recommended that you confirm the data size before using clipin with the no limit option. There are no checks that the data size will not overflow the buffer, or even the entire memory contents of the C64.
Clipin is a convenient wrapper; Its functionality is basic and limited, but easy to use. If you need more control, use copen, cread and cclose.
clipout
Purpose | Write a string to the clipboard. |
---|---|
Module offset | 24 |
Communication registers | A, X, Y |
Stack requirements | 12 bytes + |
Zero page usage | $1c, $1d, $1e, $1f, $20, $21, $90, $ba |
Registers affected | A, X, Y |
Input parameters |
RegPtr → Pointer to string to write to clipboard. A → Maximum length to write. 0 = Up to strlen bytes. |
Output parameters | None. |
Description: This routine is used to write a string to the clipboard in the most convenient way possible. A pointer to a string to write is passed in a RegPtr. The accumulator passes the length of data to write, or 0 can be used to perform a strlen on the string first, and write out the number of bytes equal to the string's length. Note, that strlen counts characters up to but not including the null terminator. Because the accumulator is 8-bit, this method can only be used to write 1 to 255 bytes, or the entire length of the string.
If the strlen option is used, the string must be null terminated, or the routine will write out everything up until it finds the first 0-byte. The data type and subtype produced by clipout is always text/pettxt.
Clipout is a convenient wrapper; Its functionality is basic and limited, but easy to use. If you need more control or if you need to write a data type other than text/pettxt, use copen, cwrite and cclose.
copen
Purpose | Begin a clipboard read/write operation. |
---|---|
Module offset | 27 |
Communication registers | A, X, Y |
Stack requirements | 14 bytes + |
Zero page usage | $1c, $1d, $61, $62, $63, $64, $65, $66, $67, $68, $ba |
Registers affected | A, X, Y |
Input parameters | A → Clipboard "file" flags. |
Output parameters |
RegWrd ← Size of current clipboard data. A ← Logical file number of the clipboard file reference. |
Description: This routine is used to open the clipboard in preparation for a read or write (i.e., paste or cut/copy) operation. The clipboard's file flags are a subset of those for fopen.
Constant | Value | Direction | Notes |
---|---|---|---|
ff_r | %00000001 | input | Open clipboard for read. |
ff_w | %00000100 | output | Open clipboard for write. |
When the clipboard is opened for write, it is automatically opened for overwrite. It is not possible to open for append. Writing in multiple stages to the clipboard can be done by calling copen once, then calling cwrite as many times as necessary, and then calling cclose once, which defines the data type and subtype for the clipboard and finalizes its data size. Once the clipboard has been closed, the next set of copen/cwrite/cclose calls overwrites the existing content. The clipboard data file is always a SEQ type file.
When the clipboard is opened for read, its current data size is returned in a RegWrd. When the clipboard is opened for write, its current data size is zeroed, and zero is returned in the RegWrd. The logical file number of the file reference, used internally for the clipboard data file, is returned in the accumulator. This can be used with CHKIN/CHRIN, or CHKOUT/CHROUT to perform low-level custom reads and writes, to and form the clipboard data file.
cread
Purpose | Read data from the clipboard, currently open for read. |
---|---|
Module offset | 30 |
Communication registers | A, X, Y |
Stack requirements | 10 bytes + |
Zero page usage | $1c, $1d, $1e, $1f, $20, $21, $90, $ba |
Registers affected | A, X, Y |
Input parameters |
RegPtr → Pointer to buffer to read into. A → Maximum length to read. 0 = No limit. |
Output parameters |
None. This routine raises exceptions. |
Description: This routine is used to read data from the clipboard into a memory buffer. The clipboard must have previously been opened with copen using the ff_r file flag. A pointer to a memory buffer is passed in a RegPtr, and the amount of data to read is passed in the accumulator. If 0 is passed in the accumulator, the entire contents of the clipboard are read into the buffer.
No data checks are performed. It is highly recommended that you check and confirm the data type, subtype and size before reading data from the clipboard, especially using the no limit option. The accumulator is only 8-bit, which limits the amount of data that can be read to 1 to 255 bytes, or the entire clipboard. To read a controlled amount of data in excess of 255 bytes, it is necessary to call cread multiple times.
cwrite
Purpose | Write data to the clipboard, currently open for write. |
---|---|
Module offset | 33 |
Communication registers | A, X, Y |
Stack requirements | 10 bytes + |
Zero page usage | $1c, $1d, $1e, $1f, $20, $21, $90, $ba |
Registers affected | A, X, Y |
Input parameters |
RegPtr → Pointer to buffer to write from. A → Length to write. 0 = Up to strlen bytes. |
Output parameters |
None. This routine raises exceptions. |
Description: This routine is used to write data to the clipboard from a memory buffer. The clipboard must have previously been opened with copen using the ff_w file flag. A pointer to a memory buffer is passed in a RegPtr, and the amount of data to write is passed in the accumulator.
The accumulator is only 8-bit, which limits the amount of data that can be written to 1 to 255 bytes. If the accumulator is passed as 0, the data pointer is first passed to strlen. The number of bytes written out is equal to the 16-bit length returned from strlen. This option should only be used on appropriate data, such as a null terminated string. To write a controlled amount of data in excess of 255 bytes, it is necessary to call cwrite multiple times. The in-memory data size of the clipboard is updated after each call to cwrite.
If the clipboard is manually written to using CHKOUT/CHROUT, it is necessary to add to c_dsize (16-bit little endian) the number of bytes written. The value of c_dsize should only be added to, not overwritten, because manual writes can be combined with calls to cwrite. Each method of writing should augment the c_dsize, so that when the clipboard is closed the correct size of its full data contents are recorded to //os/clipboard/:0.t.
cclose
Purpose | Close a clipboard read/write operation. |
---|---|
Module offset | 36 |
Communication registers | X, Y |
Stack requirements | 10 bytes + |
Zero page usage | $1c, $1d, $1e, $1f, $20, $21, $90, $ba |
Registers affected | A, X, Y |
Input parameters |
If clipboard was opened for read: None. If clipboard was opened for write: X → C64 OS data type of clipboard contents. Y → C64 OS data subtype of clipboard contents. |
Output parameters |
None. If clipboard was opened for write: Sends asynchronous mc_cpbd message to both Application and Utility, on a 20 jiffy delay. |
Description: This routine is used to close the clipboard after it has been opened using copen. It is absolutely necessary to close the clipboard after it has been opened, regardless of how it was read from or written to.
If the clipboard was opened for read, cclose takes no parameters; The clipboard is closed, and the contents of the clipboard remain unmodified.
If the clipboard was opened for write, cclose takes the C64 OS data type and subtype in the X and Y registers respectively. The clipboard is closed, the in-memory data size is written, along with the data type and subtype, to //os/clipboard/:0.t.
Tracking the clipboard data size
When the clipboard is opened for write, the in-memory data size (c_dsize) is zeroed automatically. With each call to cwrite the number of bytes written is added to c_dsize automatically. If any bytes are written out manually, using CHROUT, it is necessary to add that number of bytes to c_dsize manually. When the clipboard is closed, c_dsize is written out along with the type and subtype.
If c_dsize is not tracked correctly, the process that tries to paste will not have an accurate account of how much data is on the clipboard, and may not be able to read in the data correctly.
The following is a code example that uses copen for write, calls cwrite twice, writes out some data manually with CHROUT and manually adds to c_dsize, then closes the clipboard with cclose, outputting the data type and subtype for the entire session.
KERNAL Modules in Alphabetical Order
KERNAL Modules in Module Lookup Table Order
Return to Using the KERNAL → KERNAL Modules
Table of Contents
This document is subject to revision updates.
Last modified: May 08, 2023