Added Inkwell lightpen drivers for the C64 and the C128.
GETFL = $27 ;get file length
CHDIR_MYDOS = $29 ;change directory (MyDOS)
MKDIR = $2A ;make directory (MyDOS/SpartaDOS)
+RMDIR = $2B ;remove directory (SpartaDOS)
CHDIR_SPDOS = $2C ;change directory (SpartaDOS)
FORMAT = $FE ;format
CODE: load = RAM, type = ro, define = yes;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss, define = yes;
BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp;
EXTZP: load = ZP, type = zp, optional = yes;
CODE: load = RAM, type = ro, define = yes;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss, define = yes;
BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp;
EXTZP: load = ZP, type = zp, optional = yes;
.import initlib, donelib
.import callmain, zerobss
- .import __STARTUP_LOAD__, __ZPSAVE_LOAD__
+ .import __STARTUP_LOAD__, __BSS_LOAD__
.import __RESERVED_MEMORY__
.include "zeropage.inc"
.word $FFFF
.word __STARTUP_LOAD__
- .word __ZPSAVE_LOAD__ - 1
+ .word __BSS_LOAD__ - 1
; ------------------------------------------------------------------------
; Actual code
; Real entry point:
-; Save the zero page locations we need
-
- ldx #zpspace-1
-L1: lda sp,x
- sta zpsave,x
- dex
- bpl L1
-
; Clear the BSS data
jsr zerobss
lda appmsav+1
sta APPMHI+1
-; Copy back the zero page stuff
-
- ldx #zpspace-1
-L2: lda zpsave,x
- sta sp,x
- dex
- bpl L2
-
; Turn on cursor
- inx
+ ldx #0
stx CRSINH
; Back to DOS
; ------------------------------------------------------------------------
-.segment "ZPSAVE"
-
-zpsave: .res zpspace
-
-; ------------------------------------------------------------------------
-
.bss
spsave: .res 1
old_shflok: .res 1
old_lmargin: .res 1
- .segment "AUTOSTRT"
- .word RUNAD ; defined in atari.h
+
+.segment "AUTOSTRT"
+ .word RUNAD ; defined in atari.inc
.word RUNAD+1
.word __STARTUP_LOAD__ + 1
.export __graphics
.import findfreeiocb
- .import __do_oserror,__oserror
+ .import __oserror
.import fddecusage
.import clriocb
.import fdtoiocb
stx __oserror
rts
-cioerr: jsr fddecusage ; decrement usage counter of fd as open failed
- jmp __do_oserror
+cioerr: sty tmp3 ; remember error code
+ lda #CLOSE
+ sta ICCOM,x
+ jsr CIOV ; close IOCB again since open failed
+ jsr fddecusage ; and decrement usage counter of fd
+ lda tmp3 ; put error code into A
+ jmp __mappederrno
.endproc ; __graphics
jsr ldaxysp
.ifdef UCASE_FILENAME
-
+.ifdef DEFAULT_DEVICE
+ ldy #$80
+ sty tmp2 ; set flag for ucase_fn
+.endif
jsr ucase_fn
bcc ucok1
invret: lda #<EINVAL ; file name is too long
plp
bpl ok
- jsr fddecusage ; decrement usage counter of fd as open failed
- tya ; put error code into A
+ sty tmp3 ; remember error code
+ lda #CLOSE
+ sta ICCOM,x
+ jsr CIOV ; close IOCB again since open failed
+ jsr fddecusage ; and decrement usage counter of fd
+ lda tmp3 ; put error code into A
jmp __mappederrno
ok: lda tmp2 ; get fd
.endproc
cioerr: sty __oserror
+ lda #CLOSE
+ sta ICCOM,x
+ jsr CIOV ; close IOCB again since open failed
jmp return0
.proc _readdir
.importzp tmp3
.import addysp
.import ucase_fn
+.ifdef DEFAULT_DEVICE
+ .importzp tmp2
+.endif
.endif
.export __syschdir
.ifdef UCASE_FILENAME
+.ifdef DEFAULT_DEVICE
+ ldy #$80
+ sty tmp2 ; set flag for ucase_fn
+.endif
jsr ucase_fn
bcc ucok1
.ifdef UCASE_FILENAME
.importzp tmp3
.import ucase_fn
+.ifdef DEFAULT_DEVICE
+ .importzp tmp2
+.endif
.endif
.export __sysmkdir
.ifdef UCASE_FILENAME
+.ifdef DEFAULT_DEVICE
+ ldy #$80
+ sty tmp2 ; set flag for ucase_fn
+.endif
jsr ucase_fn
bcc ucok1
.importzp tmp3
.import addysp
.import ucase_fn
+.ifdef DEFAULT_DEVICE
+ .importzp tmp2
+.endif
.endif
.export __sysremove
.ifdef UCASE_FILENAME
+.ifdef DEFAULT_DEVICE
+ ldy #$80
+ sty tmp2 ; set flag for ucase_fn
+.endif
jsr ucase_fn
bcc ucok1
--- /dev/null
+;
+; Christian Groessler, 2013-07-24
+;
+; unsigned char __fastcall__ _sysrename (const char* oldname, const char* newname);
+;
+
+ .include "atari.inc"
+ .import findfreeiocb
+ .importzp tmp4, sp, ptr2, ptr3
+ .import incsp2, subysp, addysp, popax
+.ifdef UCASE_FILENAME
+ .importzp tmp3
+ .import ucase_fn
+.ifdef DEFAULT_DEVICE
+ .importzp tmp2
+.endif
+.endif
+ .export __sysrename
+
+.proc __sysrename
+
+ pha ; save input parameter
+ txa
+ pha
+
+ jsr findfreeiocb
+ beq iocbok ; we found one
+
+ pla
+ pla ; fix up stack
+ jsr incsp2
+
+ lda #TMOF ; too many open files
+ rts
+
+iocbok: stx tmp4 ; remember IOCB index
+
+ pla
+ sta ptr2+1 ; remember newname
+ pla
+ sta ptr2 ; ditto.
+
+ jsr popax ; get oldname
+
+ ldy #0
+ sty sspc+1 ; initialize stack space
+
+.ifndef UCASE_FILENAME
+
+ sta ptr3
+ stx ptr3+1
+ sty sspc
+
+.else
+
+; uppercase first (old) name and prepend device if needed
+
+.ifdef DEFAULT_DEVICE
+ ldy #$80
+ sty tmp2 ; set flag for ucase_fn
+.endif
+ jsr ucase_fn
+ bcc ucok1
+
+ lda #183 ; see oserror.s
+ rts
+
+ucok1: sta ptr3
+ stx ptr3+1 ; remember pointer to uppercased old name
+ lda tmp3 ; # of bytes reserved on the stack
+ sta sspc ; remember...
+
+; uppercase second (new) name and don't prepend device
+
+.ifdef DEFAULT_DEVICE
+ ldy #0
+ sty tmp2 ; set flag for ucase_fn
+.endif
+ lda ptr2
+ ldx ptr2+1
+
+ jsr ucase_fn
+ bcc ucok2
+
+ ldy tmp3 ; get size
+ jsr addysp ; free used space on the stack
+ lda #183 ; see oserror.s
+ rts
+
+ucok2: sta ptr2 ; remember pointer to uppercased new name
+ stx ptr2+1
+
+; update sspc -- # of bytes used on the stack
+
+ lda sspc
+ clc
+ adc tmp3
+ sta sspc
+ bcc ukok4
+ inc sspc+1
+ukok4:
+
+.endif
+
+; create a string on the stack with the old filename and the new filename separated by an invalid character (space in our case)
+; ptr2 - pointer to new name
+; ptr3 - pointer to old name
+
+ lda #128
+ tay
+ clc
+ adc sspc
+ sta sspc
+ bcc L1
+ inc sspc+1
+L1: jsr subysp ; make room on the stack
+
+; copy old name
+ ldy #0
+con: lda (ptr3),y
+ sta (sp),y
+ beq copyend
+ iny
+ bne con
+
+copyend:lda #$20 ; space
+ sta (sp),y
+ iny
+ tya ; get current offset (beyond old name)
+ clc
+ adc sp
+ sta ptr3
+ lda sp+1
+ adc #0
+ sta ptr3+1 ; ptr3 now contains pointer to space for new filename
+
+; copy new name
+ ldy #0
+cnn: lda (ptr2),y
+ sta (ptr3),y
+ beq copend2
+ iny
+ bne cnn
+
+copend2:ldx tmp4
+ lda sp
+ sta ICBAL,x
+ lda sp+1
+ sta ICBAH,x
+ lda #RENAME
+ sta ICCOM,x
+ lda #0
+ sta ICAX1,x
+ sta ICAX2,x
+ sta ICBLL,x
+ sta ICBLH,x
+ jsr CIOV
+ tya
+ pha
+
+; clean up stack
+
+ lda sp
+ clc
+ adc sspc
+ sta sp
+ lda sp+1
+ adc sspc+1
+ sta sp+1
+
+; handle status
+
+ pla
+ tay
+ bmi cioerr
+ lda #0
+ rts
+cioerr: tya
+ rts
+
+.endproc ; __sysrename
+
+ .bss
+
+sspc: .res 2 ; stack space used
;
; Stefan Haubenthal, 2005-12-24
+; Christian Groessler, 2013-07-16
;
; unsigned char __fastcall__ _sysrmdir (const char* name);
+;
+; for SpartaDOS and MyDOS
;
+ .include "atari.inc"
+ .include "errno.inc"
.export __sysrmdir
.import __sysremove
+ .import __dos_type
+ .import findfreeiocb
+ .importzp tmp4
+.ifdef UCASE_FILENAME
+ .import ucase_fn
+ .import addysp
+ .importzp sreg
+ .importzp tmp3
+.ifdef DEFAULT_DEVICE
+ .importzp tmp2
+.endif
+.endif
+
+.proc __sysrmdir
+
+ pha
+ lda __dos_type
+ beq not_impl ; AtariDOS
+ cmp #OSADOS+1
+ bcc do_sparta ; OS/A and SpartaDOS
+ pla
+ jmp __sysremove ; MyDOS and others (TODO: check XDOS)
+
+not_impl:
+ pla
+ lda #NVALID
+ rts
+
+iocberr:
+ pla ; cleanup stack
+ pla
+ lda #TMOF
+ rts
+
+do_sparta:
+ txa
+ pha
+ jsr findfreeiocb
+ bne iocberr ; no IOCB available
+
+ stx tmp4 ; remember IOCB
+ pla
+ tax
+ pla
+
+.ifdef UCASE_FILENAME
+
+.ifdef DEFAULT_DEVICE
+ ldy #$80
+ sty tmp2 ; set flag for ucase_fn
+.endif
+ jsr ucase_fn
+ bcc ucok1
+
+ lda #183 ; see oserror.s
+ rts
+ucok1:
+
+.endif ; defined UCASE_FILENAME
+
+ ldy tmp4 ; IOCB index
+ sta ICBAL,y ; store pointer to filename
+ txa
+ sta ICBAH,y
+ tya
+ tax
+ lda #RMDIR
+ sta ICCOM,x
+ lda #0
+ sta ICAX1,x
+ lda #0
+ sta ICAX2,x
+ sta ICBLL,x
+ sta ICBLH,x
+ jsr CIOV
+
+.ifdef UCASE_FILENAME
+ tya
+ pha
+ ldy tmp3 ; get size
+ jsr addysp ; free used space on the stack
+ pla
+ tay
+.endif ; defined UCASE_FILENAME
+
+ bmi cioerr
+ lda #0
+ rts
+
+cioerr: tya
+ rts
-__sysrmdir := __sysremove
+.endproc ; __sysrmdir
;
; Calling parameters:
; AX - points to filename
+; tmp2 - 0/$80 for don't/do prepend default device if no device
+; is present in the passed string (only .ifdef DEFAULT_DEVICE)
; Return parameters:
; C - 0/1 for OK/Error (filename too long)
; AX - points to uppercased version of the filename on the stack
stx ptr4+1
.ifdef DEFAULT_DEVICE
+ ; bit #0 of tmp2 is used as a flag whether device name is present in passed string (1 = present, 0 = not present)
ldy #1
- sty tmp2 ; initialize flag: device present in passed string
+ inc tmp2 ; initialize flag: device present
lda #':'
cmp (ptr4),y
beq hasdev
iny
cmp (ptr4),y
beq hasdev
- sta tmp2 ; set flag: no device in passed string
+ dec tmp2 ; set flag: no device in passed string
hasdev:
.endif
sty tmp3 ; save size
jsr subysp ; make room on the stack
- ; copy filename to the temp. place on the stack, also uppercasing it
+ ; copy filename to the temp. place on the stack, while uppercasing it
ldy #0
loop2: lda (ptr4),y
copy_end:
.ifdef DEFAULT_DEVICE
- lda tmp2
- cmp #1 ; was device present in passed string?
- beq hasdev2 ; yes, don't prepend something
+ lda #1
+ bit tmp2
+ bne hasdev2 ; yes, don't prepend something
+ bpl hasdev2
ldy #128+3 ; no, prepend "D:" (or other device)
sty tmp3 ; adjust stack size used
}
/* Symbol only valid if storage class not auto */
- if (((InfoBits & ibSymId) != 0) != (SC != CC65_CSYM_AUTO)) {
+ if (((InfoBits & ibSymId) != 0) && (SC == CC65_CSYM_AUTO)) {
ParseError (D, CC65_ERROR, "Only non auto symbols can have a symbol attached");
goto ErrorExit;
}
/* */
/* */
/* */
-/* (C) 1998-2012, Ullrich von Bassewitz */
+/* (c) 1998-2013, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* Calculate the new address */
Addr += S->Seg->Size;
- /* If this segment goes out to the file, increase the file size */
- if ((S->Flags & SF_BSS) == 0 && S->Load == M) {
+ /* If this segment will go out to the file, or its place
+ * in the file will be filled, then increase the file size.
+ */
+ if (S->Load == M &&
+ ((S->Flags & SF_BSS) == 0 || (M->Flags & MF_FILL) != 0)) {
M->F->Size += Addr - StartAddr;
}
--- /dev/null
+/*
+ * Simple ("tiny") shell to test filename and directory functions.
+ * Copyright (c) 2013, Christian Groessler, chris@groessler.org
+ */
+
+#define VERSION_ASC "0.90"
+
+#define KEYB_BUFSZ 80
+#define PROMPT ">>> "
+#ifdef __ATARI__
+#define UPPERCASE /* define (e.g. for Atari) to convert filenames etc. to upper case */
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#ifndef __CC65__
+#include <sys/stat.h>
+#include <sys/param.h>
+#else
+#define MAXPATHLEN 64
+#endif
+#include <sys/types.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#define CMD_NOTHING 0
+#define CMD_INVALID 1
+#define CMD_HELP 2
+#define CMD_QUIT 3
+#define CMD_LS 4
+#define CMD_MKDIR 5
+#define CMD_RMDIR 6
+#define CMD_CHDIR 7
+#define CMD_RM 8
+#define CMD_RENAME 9
+#define CMD_COPY 10
+#define CMD_PWD 11
+
+static unsigned char terminate;
+static unsigned char cmd;
+static unsigned char *cmd_asc, *arg1, *arg2, *arg3;
+static unsigned char keyb_buf[KEYB_BUFSZ];
+static size_t cpbuf_sz = 4096;
+
+struct cmd_table {
+ unsigned char *name;
+ unsigned char code;
+} cmd_table[] = {
+ { "help", CMD_HELP },
+ { "quit", CMD_QUIT },
+ { "q", CMD_QUIT },
+ { "exit", CMD_QUIT },
+ { "ls", CMD_LS },
+ { "dir", CMD_LS },
+ { "md", CMD_MKDIR },
+ { "mkdir", CMD_MKDIR },
+ { "rd", CMD_RMDIR },
+ { "rmdir", CMD_RMDIR },
+ { "cd", CMD_CHDIR },
+ { "chdir", CMD_CHDIR },
+ { "rm", CMD_RM },
+ { "del", CMD_RM },
+ { "cp", CMD_COPY },
+ { "copy", CMD_COPY },
+ { "mv", CMD_RENAME },
+ { "ren", CMD_RENAME },
+ { "pwd", CMD_PWD },
+ { NULL, 0 }
+};
+
+static void banner(void)
+{
+ puts("\"tiny\" command line shell, v" VERSION_ASC);
+ puts("written by chris@groessler.org");
+ puts("type 'help' for help\n");
+}
+
+static void get_command(void)
+{
+ unsigned char i = 0;
+
+ arg1 = arg2 = arg3 = NULL;
+
+ /* issue prompt */
+ printf(PROMPT);
+
+ /* get input from the user */
+ if (! fgets(keyb_buf, KEYB_BUFSZ, stdin)) {
+ puts("");
+ cmd = CMD_QUIT;
+ return;
+ }
+
+ /* split input into cmd, arg1, arg2, arg3 */
+
+ /* get and parse command */
+ cmd_asc = strtok(keyb_buf, " \t\n");
+ if (! cmd_asc) {
+ cmd = CMD_NOTHING;
+ return;
+ }
+ cmd = CMD_INVALID;
+ while (cmd_table[i].name) {
+ if (! strcmp(cmd_table[i].name, cmd_asc)) {
+ cmd = cmd_table[i].code;
+ break;
+ }
+ i++;
+ }
+
+ /* get arguments */
+ arg1 = strtok(NULL, " \t\n");
+ if (! arg1)
+ return;
+ arg2 = strtok(NULL, " \t\n");
+ if (! arg2)
+ return;
+ arg3 = strtok(NULL, " \t\n");
+}
+
+static void cmd_help(void)
+{
+ puts("quit, exit - exit shell");
+ puts("ls, dir - display current directory");
+ puts(" and drive contents");
+ puts("rm, del - delete file");
+ puts("cp, copy - copy file");
+ puts("mv, ren - rename file");
+ puts("cd, chdir - change directory or drive");
+ puts("md, mkdir - make directory or drive");
+ puts("rd, rmdir - remove directory or drive");
+ puts("sorry, you cannot start programs here");
+}
+
+static void cmd_ls(void)
+{
+ DIR *dir;
+ unsigned char *arg;
+ struct dirent *dirent;
+#ifdef __ATARI__
+ char need_free = 0;
+#endif
+
+ if (arg2) {
+ puts("usage: ls [dir]");
+ return;
+ }
+
+ /* print directory listing */
+ if (arg1) {
+#ifdef UPPERCASE
+ strupr(arg1);
+#endif
+#ifdef __ATARI__
+ /* not sure if this shouldn't be done by the runtime lib */
+ if (*(arg1 + strlen(arg1) - 1) == ':' || *(arg1 + strlen(arg1) - 1) == '>') {
+ arg = malloc(strlen(arg1) + 4);
+ if (! arg) {
+ printf("malloc failed: %s", strerror(errno));
+ return;
+ }
+ need_free = 1;
+ memcpy(arg, arg1, strlen(arg1) + 1);
+ strcat(arg, "*.*");
+ }
+ else
+#endif
+ arg = arg1;
+ }
+ else
+ arg = ".";
+
+ dir = opendir(arg);
+#ifdef __ATARI__
+ if (need_free) free(arg);
+#endif
+ if (! dir) {
+ puts("opendir failed");
+ return;
+ }
+
+ while (dirent = readdir(dir))
+ puts(dirent->d_name);
+
+ closedir(dir);
+}
+
+static void cmd_rm(void)
+{
+ if (!arg1 || arg2) {
+ puts("usage: rm <file>");
+ return;
+ }
+
+#ifdef UPPERCASE
+ strupr(arg1);
+#endif
+
+ if (unlink(arg1))
+ printf("remove failed: %s\n", strerror(errno));
+}
+
+static void cmd_mkdir(void)
+{
+ if (!arg1 || arg2) {
+ puts("usage: mkdir <dir>");
+ return;
+ }
+
+#ifdef UPPERCASE
+ strupr(arg1);
+#endif
+
+ if (mkdir(arg1, 0777))
+ printf("mkdir failed: %s\n", strerror(errno));
+}
+
+static void cmd_rmdir(void)
+{
+ if (!arg1 || arg2) {
+ puts("usage: rmdir <dir>");
+ return;
+ }
+
+#ifdef UPPERCASE
+ strupr(arg1);
+#endif
+
+ if (rmdir(arg1))
+ printf("rmdir failed: %s\n", strerror(errno));
+}
+
+static void cmd_chdir(void)
+{
+ if (!arg1 || arg2) {
+ puts("usage: cddir <dir>");
+ return;
+ }
+
+#ifdef UPPERCASE
+ strupr(arg1);
+#endif
+
+ if (chdir(arg1))
+ printf("chdir failed: %s\n", strerror(errno));
+}
+
+static void cmd_pwd(void)
+{
+ char *buf;
+
+ if (arg1) {
+ puts("usage: pwd");
+ return;
+ }
+
+ buf = malloc(MAXPATHLEN);
+ if (! buf) {
+ printf("malloc %u bytes failed: %s\n", MAXPATHLEN, strerror(errno));
+ return;
+ }
+ if (!getcwd(buf, MAXPATHLEN)) {
+ printf("getcwd failed: %s\n", strerror(errno));
+ free(buf);
+ return;
+ }
+
+ puts(buf);
+ free(buf);
+}
+
+static void cmd_rename(void)
+{
+ if (!arg2 || arg3) {
+ puts("usage: mv <oldname> <newname>");
+ return;
+ }
+
+#ifdef UPPERCASE
+ strupr(arg1);
+ strupr(arg2);
+#endif
+
+ if (rename(arg1, arg2))
+ printf("rename failed: %s\n", strerror(errno));
+}
+
+static void cmd_copy(void)
+{
+ int srcfd = -1, dstfd = -1;
+ unsigned char *buf;
+ int readsz, writesz;
+
+ if (!arg2 || arg3) {
+ puts("usage: cp <src> <dest>");
+ return;
+ }
+
+#ifdef UPPERCASE
+ strupr(arg1);
+ strupr(arg2);
+#endif
+
+ buf = malloc(cpbuf_sz);
+ if (! buf) {
+ printf("malloc %u bytes failed: %s\n", cpbuf_sz, strerror(errno));
+ return;
+ }
+
+ while (1) {
+ if (srcfd == -1) {
+ srcfd = open(arg1, O_RDONLY);
+ if (srcfd < 0) {
+ printf("open(%s) failed: %s\n", arg1, strerror(errno));
+ break;
+ }
+ }
+
+ readsz = read(srcfd, buf, cpbuf_sz);
+ if (readsz < 0) {
+ printf("read error: %s\n", strerror(errno));
+ break;
+ }
+ if (! readsz)
+ break;
+
+ if (dstfd == -1) {
+ dstfd = open(arg2, O_WRONLY | O_CREAT | O_TRUNC, 0777);
+ if (dstfd < 0) {
+ printf("open(%s) failed: %s\n", arg2, strerror(errno));
+ break;
+ }
+ }
+
+ writesz = write(dstfd, buf, readsz);
+ if (writesz < 0 || writesz != readsz) {
+ printf("write error: %s\n", strerror(errno));
+ break;
+ }
+ if (readsz != cpbuf_sz)
+ break;
+ }
+
+ free(buf);
+ if (srcfd >= 0) close(srcfd);
+ if (dstfd >= 0) close(dstfd);
+}
+
+static void run_command(void)
+{
+ switch (cmd) {
+ default: puts("internal error"); return;
+ case CMD_NOTHING: return;
+ case CMD_INVALID: puts("invalid command"); return;
+ case CMD_HELP: cmd_help(); return;
+ case CMD_QUIT: terminate = 1; return;
+ case CMD_LS: cmd_ls(); return;
+ case CMD_RM: cmd_rm(); return;
+ case CMD_CHDIR: cmd_chdir(); return;
+ case CMD_MKDIR: cmd_mkdir(); return;
+ case CMD_RMDIR: cmd_rmdir(); return;
+ case CMD_PWD: cmd_pwd(); return;
+ case CMD_RENAME: cmd_rename(); return;
+ case CMD_COPY: cmd_copy(); return;
+ }
+}
+
+int main(void)
+{
+ banner();
+
+ while (! terminate) {
+ get_command();
+ run_command();
+ }
+ return 0;
+}
+
+/* Local Variables: */
+/* c-file-style: "cpg" */
+/* c-basic-offset: 4 */
+/* End: */