FNAM_BANK := $C7 ; Bank for filename
KEY_COUNT := $D0 ; Number of keys in input buffer
FKEY_COUNT := $D1 ; Characters for function key
-MODE := $D7 ; 40/80 column mode flag
+MODE := $D7 ; 40-/80-column mode (bit 7: 80 columns)
CURS_X := $EC ; Cursor column
CURS_Y := $EB ; Cursor row
SCREEN_PTR := $E0 ; Pointer to current char in text screen
; ---------------------------------------------------------------------------
; I/O: VDC (128 only)
-VDC_INDEX := $D600
-VDC_DATA := $D601
+VDC_INDEX := $D600 ; register address port
+VDC_DATA := $D601 ; data port
+
+; Registers
+VDC_DATA_HI = 18 ; video RAM address (big endian)
+VDC_DATA_LO = 19
+VDC_CSET = 28
+VDC_RAM_RW = 31 ; RAM port
; ---------------------------------------------------------------------------
; I/O: Complex Interface Adapters
<title>cc65 function reference
<author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">,<newline>
<url url="mailto:greg.king5@verizon.net" name="Greg King">
-<date>2017-11-21
+<date>2017-12-09
<abstract>
cc65 is a C compiler for 6502 based systems. This function reference describes
<item><ref id="chline" name="chline">
<item><ref id="chlinexy" name="chlinexy">
<item><ref id="clrscr" name="clrscr">
+<item><ref id="cpeekc" name="cpeekc">
+<item><ref id="cpeekcolor" name="cpeekcolor">
+<item><ref id="cpeekrevers" name="cpeekrevers">
+<item><ref id="cpeeks" name="cpeeks">
<item><ref id="cprintf" name="cprintf">
<item><ref id="cputc" name="cputc">
<item><ref id="cputcxy" name="cputcxy">
</quote>
+<sect1>cpeekc<label id="cpeekc"><p>
+
+<quote>
+<descrip>
+<tag/Function/Get a character from the display memory.
+<tag/Header/<tt/<ref id="conio.h" name="conio.h">/
+<tag/Declaration/<tt/char cpeekc (void);/
+<tag/Description/The function gets the character that's at the current location
+of the cursor in the display screen RAM. That character is converted, if
+needed, into the encoding that can be passed to <tt/cputc()/.
+<tag/Notes/<itemize>
+<item>Conio peek functions don't have <tt/cpeek...xy()/ versions. That was
+done to make it obvious that peeking doesn't move the cursor in any way. Your
+program must place the cursor where it wants to peek before it calls any of
+those functions.
+</itemize>
+<tag/Availability/cc65
+<tag/See also/
+<ref id="cpeekcolor" name="cpeekcolor">,
+<ref id="cpeekrevers" name="cpeekrevers">,
+<ref id="cpeeks" name="cpeeks">,
+<ref id="cputc" name="cputc">
+<tag/Example/None.
+</descrip>
+</quote>
+
+
+<sect1>cpeekcolor<label id="cpeekcolor"><p>
+
+<quote>
+<descrip>
+<tag/Function/Get a color from the display memory.
+<tag/Header/<tt/<ref id="conio.h" name="conio.h">/
+<tag/Declaration/<tt/unsigned char cpeekcolor (void);/
+<tag/Description/The function gets the color number that's at the current
+location of the cursor in the display screen RAM. That number can be passed to
+<tt/textcolor()/.
+<tag/Notes/<itemize>
+<item>Conio peek functions don't have <tt/cpeek...xy()/ versions. That was
+done to make it obvious that peeking doesn't move the cursor in any way. Your
+program must place the cursor where it wants to peek before it calls any of
+those functions.
+</itemize>
+<tag/Availability/cc65
+<tag/See also/
+<ref id="cpeekc" name="cpeekc">,
+<ref id="cpeekrevers" name="cpeekrevers">,
+<ref id="cpeeks" name="cpeeks">,
+<ref id="cputc" name="cputc">,
+<ref id="textcolor" name="textcolor">
+<tag/Example/None.
+</descrip>
+</quote>
+
+
+<sect1>cpeekrevers<label id="cpeekrevers"><p>
+
+<quote>
+<descrip>
+<tag/Function/Get a reverse-character attribute from the display memory.
+<tag/Header/<tt/<ref id="conio.h" name="conio.h">/
+<tag/Declaration/<tt/unsigned char cpeekrevers (void);/
+<tag/Description/The function gets the "reverse-mode" attribute of the
+character that's at the current location of the cursor in the display screen
+RAM. It returns a boolean value (0/1) that can be passed to <tt/revers()/.
+<tag/Notes/<itemize>
+<item>Conio peek functions don't have <tt/cpeek...xy()/ versions. That was
+done to make it obvious that peeking doesn't move the cursor in any way. Your
+program must place the cursor where it wants to peek before it calls any of
+those functions.
+</itemize>
+<tag/Availability/cc65
+<tag/See also/
+<ref id="cpeekc" name="cpeekc">,
+<ref id="cpeekcolor" name="cpeekcolor">,
+<ref id="cpeeks" name="cpeeks">,
+<ref id="cputc" name="cputc">,
+<ref id="revers" name="revers">
+<tag/Example/None.
+</descrip>
+</quote>
+
+
+<sect1>cpeeks<label id="cpeeks"><p>
+
+<quote>
+<descrip>
+<tag/Function/Get a string from the display memory.
+<tag/Header/<tt/<ref id="conio.h" name="conio.h">/
+<tag/Declaration/<tt/void __fastcall__ cpeeks (char* s, unsigned length);/
+<tag/Description/The function gets a fixed-length string ('\0'-terminated) of
+characters that start at the current location of the cursor in the display
+screen RAM. Those characters are converted, if needed, into the encoding that
+can be passed to <tt/cputs()/. The first argument must point to a RAM area
+that's large enough to hold "length + 1" bytes.
+<tag/Notes/<itemize>
+<item>Conio peek functions don't have <tt/cpeek...xy()/ versions. That was
+done to make it obvious that peeking doesn't move the cursor in any way. Your
+program must place the cursor where it wants to peek before it calls any of
+those functions.
+<item>The function is available as only a fastcall function;
+so, it may be used only in the presence of a prototype.
+</itemize>
+<tag/Availability/cc65
+<tag/See also/
+<ref id="cpeekc" name="cpeekc">,
+<ref id="cpeekcolor" name="cpeekcolor">,
+<ref id="cpeekrevers" name="cpeekrevers">,
+<ref id="cputc" name="cputc">,
+<ref id="cputs" name="cputs">
+<tag/Example/None.
+</descrip>
+</quote>
+
+
<sect1>creat<label id="creat"><p>
<quote>
#define _textcolor(color) COLOR_WHITE
#define _bgcolor(color) COLOR_BLACK
#define _bordercolor(color) COLOR_BLACK
+#define _cpeekcolor(color) COLOR_WHITE
/* End of cbm610.h */
#endif
-
-
-
int __fastcall__ vcscanf (const char* format, va_list ap);
/* Like vscanf(), but uses direct keyboard input */
+char cpeekc (void);
+/* Return the character from the current cursor position */
+
+unsigned char cpeekcolor (void);
+/* Return the color from the current cursor position */
+
+unsigned char cpeekrevers (void);
+/* Return the reverse attribute from the current cursor position.
+** If the character is reversed, then return 1; return 0 otherwise.
+*/
+
+void __fastcall__ cpeeks (char* s, unsigned int length);
+/* Return a string of the characters that start at the current cursor position.
+** Put the string into the buffer to which "s" points. The string will have
+** "length" characters, then will be '\0'-terminated.
+*/
+
unsigned char __fastcall__ cursor (unsigned char onoff);
/* If onoff is 1, a cursor is displayed when waiting for keyboard input. If
** onoff is 0, the cursor is hidden when waiting for keyboard input. The
#if defined(_bordercolor)
# define bordercolor(x) _bordercolor(x)
#endif
+#if defined(_cpeekcolor)
+# define cpeekcolor(x) _cpeekcolor(x)
+#endif
#define _textcolor(color) COLOR_WHITE
#define _bgcolor(color) COLOR_BLACK
#define _bordercolor(color) COLOR_BLACK
+#define _cpeekcolor(color) COLOR_WHITE
--- /dev/null
+;
+; 2016-02-28, Groepaz
+; 2017-06-26, Greg King
+;
+; char cpeekc (void);
+;
+
+ .export _cpeekc
+
+ .import plot, popa
+
+ .include "zeropage.inc"
+ .include "c128.inc"
+
+
+_cpeekc:
+ lda MODE
+ bmi @c80
+
+ ldy CURS_X
+ lda (SCREEN_PTR),y ; get char
+
+@return:
+ and #<~$80 ; remove reverse flag
+
+; Convert the screen code into a PetSCII code.
+; $00 - $1F: +$40
+; $20 - $3F
+; $40 - $7F: +$80
+
+ cmp #$20
+ bcs @sk1 ;(bge)
+ ora #$40
+ rts
+
+@sk1: cmp #$40
+ bcc @end ;(blt)
+ ora #$80
+@end: ldx #0
+ rts
+
+@c80:
+ lda SCREEN_PTR
+ ldy SCREEN_PTR+1
+ clc
+ adc CURS_X
+ bcc @s
+ iny
+
+ ; get byte from VDC mem
+@s: ldx #VDC_DATA_LO
+ stx VDC_INDEX
+@L0: bit VDC_INDEX
+ bpl @L0
+ sta VDC_DATA
+ dex
+ stx VDC_INDEX
+ sty VDC_DATA
+
+ ldx #VDC_RAM_RW
+ stx VDC_INDEX
+@L1: bit VDC_INDEX
+ bpl @L1 ; wait for blanking
+ lda VDC_DATA
+ jmp @return
--- /dev/null
+;
+; 2016-02-28, Groepaz
+; 2017-06-26, Greg King
+;
+; unsigned char cpeekcolor (void);
+;
+
+ .export _cpeekcolor
+
+ .include "c128.inc"
+
+
+_cpeekcolor:
+ bit MODE
+ bmi @c80
+
+ ldy CURS_X
+ lda (CRAM_PTR),y ; get color
+ and #$0F
+ ldx #>$0000
+ rts
+
+@c80: lda CRAM_PTR
+ ldy CRAM_PTR+1
+ clc
+ adc CURS_X
+ bcc @s
+ iny
+
+ ; get byte from VDC mem
+@s: ldx #VDC_DATA_LO
+ stx VDC_INDEX
+@L0: bit VDC_INDEX
+ bpl @L0
+ sta VDC_DATA
+ dex
+ stx VDC_INDEX
+ sty VDC_DATA
+
+ ldx #VDC_RAM_RW
+ stx VDC_INDEX
+@L1: bit VDC_INDEX
+ bpl @L1 ; wait for blanking
+ lda VDC_DATA
+ and #$0F
+
+; translate VDC->VIC colour
+
+vdctovic:
+ ldy #$0F + 1
+@L2: dey
+ cmp $CE5C,y
+ bne @L2
+ tya
+ ldx #>$0000
+ rts
--- /dev/null
+;
+; 2016-02-28, Groepaz
+; 2017-06-26, Greg King
+;
+; unsigned char cpeekrevers (void);
+;
+
+ .export _cpeekrevers
+
+ .include "zeropage.inc"
+ .include "c128.inc"
+
+
+_cpeekrevers:
+ lda MODE
+ bmi @c80
+
+ ldy CURS_X
+ lda (SCREEN_PTR),y ; get char
+
+@return:
+ and #$80 ; get reverse flag
+ asl a
+ tax ; ldx #>$0000
+ rol a ; return boolean value
+ rts
+
+@c80:
+ lda SCREEN_PTR
+ ldy SCREEN_PTR+1
+ clc
+ adc CURS_X
+ bcc @s
+ iny
+
+ ; get byte from VDC mem
+@s: ldx #VDC_DATA_LO
+ stx VDC_INDEX
+@L0: bit VDC_INDEX
+ bpl @L0
+ sta VDC_DATA
+ dex
+ stx VDC_INDEX
+ sty VDC_DATA
+
+ ldx #VDC_RAM_RW
+ stx VDC_INDEX
+@L1: bit VDC_INDEX
+ bpl @L1 ; wait for blanking
+ lda VDC_DATA
+ jmp @return
--- /dev/null
+;
+; 2017-11-23, Greg King
+;
+; void cpeeks (char* s, unsigned length);
+;
+; C128 can't use "cbm/cpeeks.s" because both 40 and 80 columns must be handled.
+; Stub file, for now, so that its library can be built.
+
+ .export _cpeeks
+
+ .import popax
+
+
+_cpeeks:
+ jmp popax ; pop s
--- /dev/null
+;
+; 2016-02-28, Groepaz
+; 2017-06-22, Greg King
+;
+; char cpeekc (void);
+;
+
+ .export _cpeekc
+
+; Get a system-specific file.
+; Note: The cbm610, and c128 targets need special
+; versions that handle RAM banking and the 80-column VDC.
+
+.if .def(__C16__)
+ .include "plus4.inc" ; both C16 and Plus4
+.elseif .def(__C64__)
+ .include "c64.inc"
+.elseif .def(__CBM510__)
+ .import CURS_X: zp, SCREEN_PTR: zp
+ .include "cbm510.inc"
+.elseif .def(__PET__)
+ .include "pet.inc"
+.elseif .def(__VIC20__)
+ .include "vic20.inc"
+.endif
+
+
+_cpeekc:
+ ldy CURS_X
+ lda (SCREEN_PTR),y ; get screen code
+ ldx #>$0000
+ and #<~$80 ; remove reverse bit
+
+; Convert the screen code into a PetSCII code.
+; $00 - $1F: +$40
+; $20 - $3F
+; $40 - $5f: +$20
+; $60 - $7F: +$40
+
+ cmp #$20
+ bcs @sk1 ;(bge)
+ ora #$40
+ rts
+
+@sk1: cmp #$40
+ bcc @end ;(blt)
+ cmp #$60
+ bcc @sk2 ;(blt)
+ ;sec
+ adc #$20 - $01
+@sk2: ;clc ; both above cmp and adc clear carry flag
+ adc #$20
+@end: rts
--- /dev/null
+;
+; 2016-02-28, Groepaz
+; 2017-06-22, Greg King
+;
+; unsigned char cpeekcolor (void);
+;
+
+ .export _cpeekcolor
+
+; Get a system-specific file.
+; Note: The cbm510, cbm610, c128, and Pet targets need special
+; versions that handle RAM banking, the 80-column VDC, and monochrome.
+
+.if .def(__C16__)
+ .include "plus4.inc" ; both C16 and Plus4
+.elseif .def(__C64__)
+ .include "c64.inc"
+.elseif .def(__VIC20__)
+ .include "vic20.inc"
+.endif
+
+
+_cpeekcolor:
+ ldy CURS_X
+ lda (CRAM_PTR),y ; get color
+ and #$0F
+ ldx #>$0000
+ rts
--- /dev/null
+;
+; 2016-02-28, Groepaz
+; 2017-06-15, Greg King
+;
+; unsigned char cpeekrevers (void);
+;
+
+ .export _cpeekrevers
+
+; Get a system-specific file.
+; Note: The cbm610, and c128 targets need special
+; versions that handle RAM banking and the 80-column VDC.
+
+.if .def(__C16__)
+ .include "plus4.inc" ; both C16 and Plus4
+.elseif .def(__C64__)
+ .include "c64.inc"
+.elseif .def(__CBM510__)
+ .import CURS_X: zp, SCREEN_PTR: zp
+ .include "cbm510.inc"
+.elseif .def(__PET__)
+ .include "pet.inc"
+.elseif .def(__VIC20__)
+ .include "vic20.inc"
+.endif
+
+
+_cpeekrevers:
+ ldy CURS_X
+ lda (SCREEN_PTR),y ; get screen code
+ and #$80 ; get reverse bit
+ asl a
+ tax ; ldx #>$0000
+ rol a ; return boolean value
+ rts
--- /dev/null
+;
+; 2017-07-05, Greg King
+;
+; void cpeeks (char* s, unsigned length);
+;
+
+ .export _cpeeks
+
+ .import popax
+ .importzp ptr1, ptr2, ptr3, tmp1, tmp2
+
+ .macpack generic
+
+; Get a system-specific file.
+; Note: The cbm610, and c128 targets need special
+; versions that handle RAM banking and the 80-column VDC.
+
+.if .def(__C16__)
+ .include "plus4.inc" ; both C16 and Plus4
+.elseif .def(__C64__)
+ .include "c64.inc"
+.elseif .def(__CBM510__)
+ .import CURS_X: zp, SCREEN_PTR: zp
+ .include "cbm510.inc"
+.elseif .def(__PET__)
+ .include "pet.inc"
+.elseif .def(__VIC20__)
+ .include "vic20.inc"
+.endif
+
+
+_cpeeks:
+ eor #<$FFFF ; counting a word upward is faster
+ sta ptr3 ; so, we use -(length + 1)
+ txa
+ eor #>$FFFF
+ sta ptr3+1
+
+ lda SCREEN_PTR
+ ldx SCREEN_PTR+1
+ sta ptr2
+ stx ptr2+1
+ ldy CURS_X
+ sty tmp2
+
+ jsr popax
+ sta tmp1 ; (will be a .Y index)
+ stx ptr1+1
+ ldx #<$0000
+ stx ptr1
+ bze L3 ; branch always
+
+L4: ldy tmp2
+ lda (ptr2),y ; get char
+ iny
+ bnz L2
+ inc ptr2+1
+L2: sty tmp2
+ and #<~$80 ; remove reverse bit
+
+; Convert the screen code into a PetSCII code.
+; $00 - $1F: +$40
+; $20 - $3F
+; $40 - $5f: +$20
+; $60 - $7F: +$40
+
+ cmp #$20
+ blt @sk1 ;(bcc)
+ cmp #$40
+ blt L5
+ cmp #$60
+ blt @sk2 ;(bcc)
+ clc
+@sk1: adc #$20
+@sk2: ;clc ; both above cmp and adc clear carry flag
+ adc #$20
+
+L5: ldy tmp1
+ sta (ptr1),y
+ iny
+ bnz L1
+ inc ptr1+1
+L1: sty tmp1
+
+L3: inc ptr3 ; count length
+ bnz L4
+ inc ptr3+1
+ bnz L4
+
+ txa ; terminate the string
+ ldy tmp1
+ sta (ptr1),y
+ rts
--- /dev/null
+;
+; 2016-02-28, Groepaz
+; 2017-06-19, Greg King
+;
+; unsigned char cpeekcolor (void);
+;
+
+ .export _cpeekcolor
+
+ .import CURS_X: zp, CRAM_PTR: zp
+
+ .include "cbm510.inc"
+
+
+_cpeekcolor:
+ ldx IndReg
+ lda #$0F
+ sta IndReg
+ ldy CURS_X
+ lda (CRAM_PTR),y ; get color
+ stx IndReg
+ and #$0F
+ ldx #>$0000
+ rts
--- /dev/null
+;
+; 2016-06, Christian Groessler
+; 2017-07-05, Greg King
+;
+; unsigned char doesclrscrafterexit (void);
+;
+; Returns 0/1 if, after program termination, the screen isn't/is cleared.
+;
+
+ .import return1
+
+; cc65's CBM510 programs switch to a display screen in the program RAM bank;
+; then, they switch back to the system bank when they exit.
+; The screen is cleared.
+
+ .export _doesclrscrafterexit := return1
--- /dev/null
+;
+; 2016-02-28, Groepaz
+; 2017-06-19, Greg King
+;
+; char cpeekc (void);
+;
+
+ .export _cpeekc
+
+ .import CURS_X: zp, CharPtr: zp
+
+ .include "cbm610.inc"
+
+
+_cpeekc:
+ ldx IndReg
+ ldy #$0F
+ sty IndReg
+
+ ldy CURS_X
+ lda (CharPtr),y ; get char from system bank
+ stx IndReg
+ ldx #>$0000
+ and #<~$80 ; remove reverse bit
+
+; Convert the screen code into a PetSCII code.
+; $00 - $1F: +$40
+; $20 - $3F
+; $40 - $5f: +$20
+; $60 - $7F: +$40
+
+ cmp #$20
+ bcs @sk1 ;(bge)
+ ora #$40
+ rts
+
+@sk1: cmp #$40
+ bcc @end ;(blt)
+ cmp #$60
+ bcc @sk2 ;(blt)
+ ;sec
+ adc #$20 - $01
+@sk2: ;clc ; both above cmp and adc clear carry flag
+ adc #$20
+@end: rts
--- /dev/null
+;
+; 2017-06-03, Greg King
+;
+; unsigned char cpeekcolor (void);
+;
+
+ .import return1
+ .export _cpeekcolor := return1 ; always COLOR_WHITE
--- /dev/null
+;
+; 2016-02-28, Groepaz
+; 2017-06-19, Greg King
+;
+; unsigned char cpeekrevers (void);
+;
+
+ .export _cpeekrevers
+
+ .import plot
+ .import CURS_X: zp, CharPtr: zp
+
+ .include "cbm610.inc"
+
+
+_cpeekrevers:
+ ldx IndReg
+ ldy #$0F
+ sty IndReg
+
+ ldy CURS_X
+ lda (CharPtr),y ; get char from system bank
+ stx IndReg
+ ldx #>$0000
+ and #$80 ; get reverse bit
+ asl a
+ tax ; ldx #>$0000
+ rol a ; return boolean value
+ rts
--- /dev/null
+;
+; 2017-07-05, Greg King
+;
+; void cpeeks (char* s, unsigned length);
+;
+
+ .export _cpeeks
+
+ .import popax
+ .importzp ptr1, ptr2, ptr3, tmp1, tmp2
+ .importzp CURS_X, SCREEN_PTR
+
+ .include "cbm610.inc"
+ .macpack generic
+
+
+_cpeeks:
+ eor #<$FFFF ; counting a word upward is faster
+ sta ptr3 ; so, we use -(length + 1)
+ txa
+ eor #>$FFFF
+ sta ptr3+1
+
+ lda SCREEN_PTR
+ ldx SCREEN_PTR+1
+ sta ptr2
+ stx ptr2+1
+ ldy CURS_X
+ sty tmp2
+
+ jsr popax
+ sta tmp1 ; (will be a .Y index)
+ stx ptr1+1
+ ldx IndReg
+ ldy #<$0000
+ sty ptr1
+ bze L3 ; branch always
+
+L4: ldy #$0F
+ sty IndReg
+ ldy tmp2
+ lda (ptr2),y ; get char from system bank
+ stx IndReg
+ iny
+ bnz L2
+ inc ptr2+1
+L2: sty tmp2
+ and #<~$80 ; remove reverse bit
+
+; Convert the screen code into a PetSCII code.
+; $00 - $1F: +$40
+; $20 - $3F
+; $40 - $5f: +$20
+; $60 - $7F: +$40
+
+ cmp #$20
+ blt @sk1 ;(bcc)
+ cmp #$40
+ blt L5
+ cmp #$60
+ blt @sk2 ;(bcc)
+ clc
+@sk1: adc #$20
+@sk2: ;clc ; both above cmp and adc clear carry flag
+ adc #$20
+
+L5: ldy tmp1
+ sta (ptr1),y
+ iny
+ bnz L1
+ inc ptr1+1
+L1: sty tmp1
+
+L3: inc ptr3 ; count length
+ bnz L4
+ inc ptr3+1
+ bnz L4
+
+ lda #$00 ; terminate the string
+ ldy tmp1
+ sta (ptr1),y
+ rts
--- /dev/null
+;
+; 2017-06-03, Greg King
+;
+; unsigned char cpeekcolor (void);
+;
+
+ .import return1
+ .export _cpeekcolor := return1 ; always COLOR_WHITE
--- /dev/null
+/* Test that the cpeek...() functions are the inverses of cputc(),
+** revers(), and textcolor() for the full range of character codes.
+**
+** 2017-07-15, Greg King
+*/
+
+#include <conio.h>
+#include <cc65.h>
+
+/* Standard location of the screen */
+
+#if defined(__C128__) || defined(__C64__)
+/* only 40-column screen */
+# define SCREEN_RAM ((unsigned char*)0x0400)
+#elif defined(__C16__) /* Plus4 also */
+# define SCREEN_RAM ((unsigned char*)0x0C00)
+#elif defined(__CBM510__)
+# define SCREEN_RAM ((unsigned char*)0xF000)
+#elif defined(__CBM610__)
+# define SCREEN_RAM ((unsigned char*)0xD000)
+#elif defined(__PET__)
+# define SCREEN_RAM ((unsigned char*)0x0800)
+#elif defined(__VIC20__)
+# define SCREEN_RAM ((unsigned char*)0x1000)
+#else
+# error This program cannot test that target.
+# define SCREEN_RAM ((unsigned char*)0)
+#endif
+
+static unsigned char width;
+
+
+/* Move the cursor backward one char with
+** the recognition of a row change.
+*/
+static void chBack (void)
+{
+ unsigned char y = wherey ();
+ unsigned char x = wherex ();
+
+ if (x == 0) {
+ x = width;
+ --y;
+ }
+ --x;
+
+ gotoxy (x, y);
+}
+
+
+/* Move the cursor forward one char with
+** the recognition of a row change.
+*/
+static void chForth (void)
+{
+ unsigned char y = wherey ();
+ unsigned char x = wherex ();
+
+ if (++x >= width) {
+ x = 0;
+ ++y;
+ }
+
+ gotoxy (x, y);
+}
+
+
+/* A hack to get an unmodified byte from the
+** screen memory at the current cursor position.
+*/
+static unsigned char peekChWithoutTranslation (void)
+{
+#if defined(__CBM610__)
+ return peekbsys ((unsigned)&SCREEN_RAM[wherey () * width + wherex ()]);
+#else
+ return SCREEN_RAM[wherey () * width + wherex ()];
+#endif
+}
+
+
+/* A test which outputs the given char, reads it back from
+** screen memory, outputs the returned char at the next position,
+** then compares the two screen memory bytes for identity.
+**
+** Note: cpeekc() must be tested indirectly because some platforms "fold" their
+** character code-set into a smaller screen code-set. Therefore, cpeekc() might
+** return an equivalent, but not equal, character to the one that was cputc().
+*/
+static unsigned char testCPeekC (char ch)
+{
+ unsigned char ch2_a, ch2_b, ch2_c;
+
+ /* Test the given char-code, but not the
+ ** special characters NEWLINE and RETURN
+ ** (they don't put anything on the screen).
+ */
+ if (('\n' == ch) || ('\r' == ch)
+ ) {
+ return 1;
+ }
+
+ /* Output the char to the screen. */
+ cputc (ch);
+
+ /* Move the cursor pos. to the previous output. */
+ chBack ();
+
+ /* Get back the written char without any translation. */
+ ch2_b = peekChWithoutTranslation ();
+
+ /* Get back the written char,
+ ** including the translation, screen-code -> text.
+ */
+ ch2_a = cpeekc ();
+
+ /* Move the cursor to the following writing position. */
+ chForth ();
+
+ /* Output again the char which was read back by cpeekc(). */
+ cputc (ch2_a);
+
+ /* Move the cursor pos. to the second output. */
+ chBack ();
+
+ /* Get back the second written char without any translation;
+ ** and, compare it to the first untranslated char.
+ */
+ ch2_c = peekChWithoutTranslation ();
+ if (ch2_c != ch2_b) {
+ /* The test was NOT succesful.
+ ** Output a diagnostic; and, return FAILURE.
+ */
+ revers(0);
+ cprintf ("\r\nError on char: %#x was %#x instead.", ch, ch2_a);
+ cprintf ("\r\nRaw screen codes: %#x, %#x.", ch2_b, ch2_c);
+ return 0;
+ }
+
+ /* The test was succesful.
+ ** Move the cursor to the following writing position.
+ */
+ chForth ();
+ return 1;
+}
+
+
+/* The main code initiates the screen for the tests, and sets the reverse flag.
+** Then, it calls testCPeekC() for every char within 0..255.
+** Returns zero for success, one for failure.
+*/
+int main (void)
+{
+ unsigned char i;
+ int ret = 0;
+
+ clrscr ();
+ revers (1);
+ screensize (&width, &i);
+
+#if defined(__VIC20__)
+ /* The VIC-20's screen is too small to hold the full test. */
+ i = 2;
+#else
+ i = 0;
+#endif
+ do {
+ if (!testCPeekC (i)) {
+ ret = 1;
+ break;
+ }
+ } while (++i != 0); /* will wrap around when finished */
+
+ if (doesclrscrafterexit()) {
+ cgetc();
+ }
+ return ret;
+}