├── .gitignore ├── LICENSE ├── Makefile ├── README ├── example.scr └── scr.c /.gitignore: -------------------------------------------------------------------------------- 1 | /scr 2 | /*.blk 3 | /*~ 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Mark Smith 2 | 3 | Permission to use, copy, modify, and distribute this software for any purpose 4 | with or without fee is hereby granted, provided that the above copyright notice 5 | and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 8 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 9 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 10 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 11 | OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 12 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 13 | THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BIN=scr 2 | 3 | PREFIX?=/usr/local 4 | BINDIR=${PREFIX}/bin 5 | 6 | CFLAGS+=-g -O2 -std=c11 -D_POSIX_C_SOURCE=200112L -pedantic -Wall -Wno-strict-overflow 7 | 8 | .PHONY: build clean install uninstall 9 | 10 | build: ${BIN} 11 | 12 | clean: 13 | -rm -vf ${BIN} 14 | 15 | install: ${BIN} 16 | @mkdir -p ${BINDIR} 17 | cp ${BIN} ${BINDIR}/${BIN} 18 | 19 | uninstall: 20 | -rm -vf ${BINDIR}/${BIN} 21 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | scr 2 | 3 | A tool for working with Forth code blocks. 4 | 5 | scr converts 1024-byte Forth code blocks to (and from) a plain-text source code 6 | format modeled on the 16x64 screen format and designed for reading and writing 7 | using common software. 8 | 9 | A screen contains 16 lines of code and each line of code can contain at most 64 10 | characters followed by a newline character. 11 | 12 | Screens may optionally include line numbers and screen numbers. 13 | 14 | Spaces should be used for indenting code. 15 | 16 | GETTING STARTED 17 | 18 | Building and installing 19 | 20 | $ make install 21 | ... 22 | $ 23 | 24 | Examples 25 | 26 | To convert a block file to a screen file: 27 | 28 | The -n, -l and -s options specify whether newline characters, line numbers or 29 | screen numbers (respectively) are included. 30 | 31 | $ scr -ls example.blk example.scr 32 | $ 33 | 34 | The -d option specifies whether the screen divider (dashed line) is included. 35 | 36 | To convert a screen file to a block file: 37 | 38 | The -r option specifies that the input is in screen format and the output should 39 | be in block format. 40 | 41 | $ scr -rls example.scr example.blk 42 | $ 43 | 44 | To display a block file in screen format with OPTIONS: 45 | 46 | If no output file is specified scr will write to stdout. 47 | 48 | $ scr OPTIONS example.blk 49 | ... 50 | $ 51 | 52 | To reformat and display a screen file with OPTIONS: 53 | 54 | If no input file is specified scr will read from stdin. 55 | 56 | $ scr -rls example.scr | scr OPTIONS 57 | ... 58 | $ 59 | 60 | LICENSE 61 | 62 | ISC-style license 63 | -------------------------------------------------------------------------------- /example.scr: -------------------------------------------------------------------------------- 1 | SCREEN 0 2 | 0 3 | 1 4 | 2 5 | 3 6 | 4 7 | 5 8 | 6 9 | 7 10 | 8 11 | 9 12 | 10 13 | 11 14 | 12 15 | 13 16 | 14 17 | 15 18 | SCREEN 1 19 | 0 2 load 20 | 1 ok 21 | 2 22 | 3 23 | 4 24 | 5 25 | 6 26 | 7 27 | 8 28 | 9 29 | 10 30 | 11 31 | 12 32 | 13 33 | 14 34 | 15 35 | SCREEN 2 36 | 0 : ok ." Hello, World!" cr ; 37 | 1 38 | 2 39 | 3 40 | 4 41 | 5 42 | 6 43 | 7 44 | 8 45 | 9 46 | 10 47 | 11 48 | 12 49 | 13 50 | 14 51 | 15 52 | SCREEN 3 53 | 0 54 | 1 55 | 2 56 | 3 57 | 4 58 | 5 59 | 6 60 | 7 61 | 8 62 | 9 63 | 10 64 | 11 65 | 12 66 | 13 67 | 14 68 | 15 69 | -------------------------------------------------------------------------------- /scr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | extern char *__progname; 8 | 9 | void 10 | usage() { 11 | fprintf(stderr, "usage: %s [-hrnlsd] [-b base] [infile [outfile]]\n", __progname); 12 | exit(1); 13 | } 14 | 15 | int 16 | main(int argc, char *argv[]) { 17 | int ropt; 18 | ropt = 0; 19 | int nopt; 20 | nopt = 0; 21 | int lopt; 22 | lopt = 0; 23 | int sopt; 24 | sopt = 0; 25 | int dopt; 26 | dopt = 0; 27 | int bopt; 28 | bopt = 0; 29 | int boptarg; 30 | boptarg = 0; 31 | char *ifn; 32 | ifn = NULL; 33 | FILE *ifp; 34 | ifp = stdin; 35 | char *ofn; 36 | ofn = NULL; 37 | FILE *ofp; 38 | ofp = stdout; 39 | 40 | char ch; 41 | while ((ch = getopt(argc, argv, "hrnlsdb:")) != -1) { 42 | switch (ch) { 43 | case 'r': 44 | if (ropt != 0) 45 | usage(); 46 | ropt = 1; 47 | break; 48 | case 'n': 49 | if (nopt != 0) 50 | usage(); 51 | nopt = 1; 52 | break; 53 | case 'l': 54 | if (lopt != 0) 55 | usage(); 56 | lopt = 3; 57 | break; 58 | case 's': 59 | if (sopt != 0) 60 | usage(); 61 | sopt = 1; 62 | break; 63 | case 'd': 64 | if (dopt != 0) 65 | usage(); 66 | dopt = 1; 67 | break; 68 | case 'b': 69 | if (bopt != 0) 70 | usage(); 71 | bopt = 1; 72 | boptarg = atoi(optarg); 73 | break; 74 | case 'h': 75 | default: 76 | usage(); 77 | } 78 | } 79 | 80 | argc -= optind; 81 | argv += optind; 82 | 83 | if (argc > 2) { 84 | usage(); 85 | } 86 | 87 | if (argc >= 1) { 88 | if (strcmp(argv[0], "-") != 0) { 89 | ifn = argv[0]; 90 | ifp = fopen(ifn, "r"); 91 | if (ifp == NULL) 92 | err(1, "%s", ifn); 93 | } 94 | } 95 | if (argc >= 2) { 96 | if (strcmp(argv[1], "-") != 0) { 97 | ofn = argv[1]; 98 | ofp = fopen(ofn, "w"); 99 | if (ofp == NULL) 100 | err(1, "%s", ofn); 101 | } 102 | } 103 | 104 | const char ln[16][3] = { 105 | " 0 ", 106 | " 1 ", 107 | " 2 ", 108 | " 3 ", 109 | " 4 ", 110 | " 5 ", 111 | " 6 ", 112 | " 7 ", 113 | " 8 ", 114 | " 9 ", 115 | "10 ", 116 | "11 ", 117 | "12 ", 118 | "13 ", 119 | "14 ", 120 | "15 ", 121 | }; 122 | 123 | int ls; 124 | ls = 0 + lopt; 125 | int le; 126 | le = 64 + lopt; 127 | 128 | int sn; 129 | sn = boptarg; 130 | 131 | if (!ropt) { 132 | int cc; 133 | cc = 0; 134 | int q; 135 | q = 0; 136 | while (!q) { 137 | int i, j; 138 | char s[16][68]; 139 | int d; 140 | d = 0; 141 | for (i = 0; i < 16; i++) { 142 | for (j = 0; j < ls; j++) 143 | s[i][j] = ln[i][j]; 144 | int k; 145 | k = ls; 146 | for (j = ls; j < le; j++) { 147 | int c; 148 | c = fgetc(ifp); 149 | if (c == EOF && feof(ifp)) { 150 | q = 1; 151 | break; 152 | } 153 | cc++; 154 | if (nopt && (char)c == '\n') 155 | c = ' '; 156 | if ((char)c != ' ') 157 | k = j + 1; 158 | s[i][j] = (char)c; 159 | d = 1; 160 | if ((char)c < 32 || (char)c > 126) { 161 | if (ifn != NULL) 162 | fprintf(stderr, "%s:", ifn); 163 | fprintf(stderr, "#%d: invalid character\n", cc); 164 | exit(2); 165 | } 166 | } 167 | s[i][k] = '\0'; 168 | } 169 | if (q && d) { 170 | if (ifn != NULL) 171 | fprintf(stderr, "%s:", ifn); 172 | fprintf(stderr, "#%d: screen truncated\n", cc); 173 | exit(2); 174 | } 175 | if (!q || d) { 176 | if (sopt || dopt) { 177 | if (lopt || (sopt && !dopt)) 178 | for (i = 0; i < 3; i++) 179 | fputc(' ', ofp); 180 | int n; 181 | n = 0; 182 | if (dopt) { 183 | for (i = 0; i < 3; i++) 184 | fputc('-', ofp); 185 | n += 3; 186 | } 187 | if (sopt) { 188 | if (dopt) { 189 | fputc(' ', ofp); 190 | n++; 191 | } 192 | n += fprintf(ofp, "SCREEN %d", sn++); 193 | if (dopt) { 194 | fputc(' ', ofp); 195 | n++; 196 | } 197 | } 198 | if (dopt) 199 | for (i = n; i < 64; i++) 200 | fputc('-', ofp); 201 | fputc('\n', ofp); 202 | } 203 | for (i = 0; i < 16; i++) { 204 | fputs(s[i], ofp); 205 | fputc('\n', ofp); 206 | } 207 | } 208 | } 209 | } else { 210 | int lc; 211 | lc = 1; 212 | int q; 213 | q = 0; 214 | while (!q) { 215 | int i, j; 216 | char s[17][67]; 217 | int d; 218 | d = 0; 219 | for (i = 0; i < 16 + sopt; i++) { 220 | for (j = 0; j < le; j++) 221 | s[i][j] = ' '; 222 | for (j = 0; j <= le; j++) { 223 | int c; 224 | c = fgetc(ifp); 225 | if (c == EOF && feof(ifp)) { 226 | q = 1; 227 | break; 228 | } 229 | if (!nopt && (char)c == '\n') 230 | break; 231 | if (j == le) { 232 | if (ifn != NULL) 233 | fprintf(stderr, "%s:", ifn); 234 | fprintf(stderr, "%d: line is too long\n", lc); 235 | exit(2); 236 | } 237 | s[i][j] = (char)c; 238 | d = 1; 239 | if ((char)c == '\n') 240 | break; 241 | if ((char)c < 32 || (char)c > 126) { 242 | if (ifn != NULL) 243 | fprintf(stderr, "%s:", ifn); 244 | fprintf(stderr, "%d: invalid character\n", lc); 245 | exit(2); 246 | } 247 | } 248 | lc++; 249 | } 250 | if (!q || d) 251 | for (i = sopt; i < 16 + sopt; i++) 252 | for (j = ls; j < le; j++) 253 | fputc(s[i][j], ofp); 254 | } 255 | } 256 | } 257 | --------------------------------------------------------------------------------