├── .gitattributes ├── README.md ├── be ├── be.c ├── be.com ├── be.m2a ├── be.md ├── makefile.dat └── mkbe.sub ├── clib ├── LICENSE ├── makefile.dat ├── memcpy.c ├── mkclib.sub ├── strchr.c ├── strstr.c └── tstclib.c ├── images ├── be1.png ├── cpm_inside.png ├── digital_research.png └── ue1.png ├── kbm ├── LICENSE ├── kbm.c ├── kbm.com └── mkkbm.sub ├── m2a ├── m2a.c ├── m2a.com ├── m2a.m2a ├── m2a.md └── mkm2a.sub ├── screen ├── mkscreen.sub ├── screen.c └── screen.com ├── shl ├── makefile.dat ├── mkshl.sub ├── shl.c ├── shl.h ├── shl.m2a ├── shl.md ├── tstshl.c ├── tstshl.com ├── tstshl.sub └── tstshlc.com └── ue ├── makefile.dat ├── mkue.sub ├── ue.c ├── ue.com ├── ue.m2a ├── ue.md ├── ueshl.com └── ueshlc.com /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # CP/M files with these file extensions uses CR/LF 5 | *.sub text eol=crlf 6 | 7 | # CP/M files with these file extensions are binary 8 | *.com binary 9 | 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CP/M 2 | 3 | ![CP/M Inside](https://github.com/lindehaven/CP-M/blob/master/images/cpm_inside.png) 4 | 5 | From Wikipedia: 6 | 7 | > CP/M, originally standing for Control Program/Monitor and later Control 8 | > Program for Microcomputers, is a mass-market operating system created for 9 | > Intel 8080/85-based microcomputers by Gary Kildall of Digital Research, Inc. 10 | > Initially confined to single-tasking on 8-bit processors and no more than 64 11 | > kilobytes of memory, later versions of CP/M added multi-user variations and 12 | > were migrated to 16-bit processors. 13 | 14 | 15 | ![Digital Research](https://github.com/lindehaven/CP-M/blob/master/images/digital_research.png) 16 | 17 | 18 | ## Background 19 | 20 | I wrote lots of code for CP/M in the early 80's. Basic, TurboPascal, C and 21 | assembly. My source code is unfortunately gone with the disks that I stored 22 | it on and with the computers I ran it on; a Spectravideo SV-328, a Jet 80 and 23 | a Bondwell BW-2. By 1995 I thought that I would not use CP/M again. UNIX and 24 | M$ Windows had taken over. 25 | 26 | But when I found and tried out some CP/M emulators I got the urge to write 27 | some of that good old code again. 28 | 29 | I started with the Binary Editor because I had real good use of that kind of 30 | editor and it should be a given tool in any programmers toolbox. Could not 31 | find any CP/M source code or binary in the web archives. Managed to design, 32 | code, test and debug a decent binary editor in a couple of days. Have already 33 | used it a few times when inspecting files saved by other programs. 34 | 35 | Continued with an attempt to port the Kilo editor [1] to CP/M because I wanted 36 | a source code editor with syntax highlighting. But I soon discovered that the 37 | Kilo editor was using too much of the 62 KB TPA so I decided to write an editor 38 | that uses less memory. 39 | 40 | Also wrote the Syntax Highlighter that is a variant of the syntax highlighting 41 | from Kilo editor [1]. I focused on reducing the memory requirements because I 42 | want to have as much free memory in TPA as possible if the Syntax Highlighter 43 | is to be linked with a text editor. 44 | 45 | While developing the Syntax Highlighter I found the micro editor [2] written 46 | for Linux. It is small and lean so I ported it to CP/M. Added undo, added 47 | replace, added auto-indentation and syntax highlighting. Working fine. 48 | 49 | Although the micro editor works fine in a CP/M emulator, it is way too slow for 50 | use on an actual Intel 8080 or Zilog Z80 running on a few MHz. So, my pursuit 51 | for a faster code editor with syntax highlighting continues. 52 | 53 | At the time of writing, I'm working on extending a fork of the TED editor [3] 54 | with Zilog Z80 assembly syntax highlighting - in Zilog Z80 assembly of course. 55 | 56 | 57 | ## References 58 | 59 | [1] Kilo editor (kilo) by Salvatore Sanfilippo 60 | ([antirez](https://github.com/antirez/kilo)) 61 | 62 | [2] Micro Editor by Anthony Howe and Terry Loveall 63 | ([ue](http://web.archive.org/web/20081019042406/http://www.modest-proposals.com/binary/ue.1.25.tgz)) 64 | 65 | [3] TED editor by Hector Peraza 66 | ([hperaza](https://github.com/hperaza/TED)) 67 | 68 | ## Binary Editor (BE) 69 | 70 | ![BE](https://github.com/lindehaven/CP-M/blob/master/images/be1.png) 71 | 72 | ### Summary 73 | 74 | Binary Editor (BE) enables hexadecimal and ASCII editing of binary files up to 75 | 32 KB in size. 76 | 77 | CP/M programs starts at address `0x0100` by default so this is also the address 78 | offset used by BE as default. This can be changed by the user when starting BE. 79 | 80 | BE continuously keeps track of the current position and displays that on the 81 | top of the terminal screen together with the total file size. 82 | 83 | Any unsaved edits are marked with inverse video on the terminal screen. The 84 | user must also confirm if unsaved edits shall be saved or discarded when 85 | exiting BE. 86 | 87 | Keyboard mapping can be easily changed without compiling the BE source code, 88 | assembling and linking. There are 13 editor keys that are located at even 89 | adresses `0x0010 - 0x0028` in `BE.COM`. By editing `BE.COM` using itself(!) 90 | you can change these key mappings and save the `BE.COM` that you want. The 91 | help text for key mappings are located at `0x0030 - 0x00ff` and you should 92 | edit those too while you are at it. Save a backup of the original `BE.COM` 93 | before you start editing. 94 | 95 | See `be/be.md` or `be/be.m2a` for details. 96 | 97 | ### Internals 98 | 99 | Copyright (c) 2017-2022 Lars Lindehaven. 100 | 101 | * Digital Research CP/M systems 102 | * ANSI terminal 103 | * Aztec C Compiler Vers. 1.06D by Manx Software Systems 104 | * YAZE-AG 2.51.1 by Frank D. Cringle, Michael Haardt and Andreas Gerlich 105 | 106 | 107 | ## Aztec C Library (CLIB) 108 | 109 | A few modules that were missing in the Aztec C distribution. 110 | 111 | * `memcpy.c` 112 | * `strchr.c` 113 | * `strstr.c` 114 | 115 | 116 | ## Markdown to ANSI (M2A) 117 | 118 | ### Summary 119 | 120 | M2A converts and prints markdown code to ANSI screen codes. I wrote it to get 121 | better readability of markdown files on an ANSI terminal. I use it to convert 122 | my markdown files and supply the ANSI-coded files for my CP/M programs. 123 | I give the ANSI-coded files the extension `.M2A`. 124 | Example: `M2A.COM < M2A.MD > M2A.M2A` 125 | 126 | The ANSI-code files then looks ok when dumping them on an ANSI screen. 127 | Example: `TYPE M2A.M2A` 128 | 129 | M2A supports the following markdown: 130 | 131 | * Headings 132 | * Block quotes 133 | * Code blocks 134 | * Unordered lists 135 | * Inline code 136 | * Emphasized text 137 | 138 | 139 | ### Internals 140 | 141 | Public domain (C) 2022 Lars Lindehaven 142 | 143 | * Digital Research CP/M systems 144 | * ANSI terminal 145 | * Aztec C Compiler Vers. 1.06D by Manx Software Systems 146 | * YAZE-AG 2.51.1 by Frank D. Cringle, Michael Haardt and Andreas Gerlich 147 | 148 | ### Summary 149 | 150 | See `m2a/m2a.md` or `m2a/m2a.m2a` for details. 151 | 152 | 153 | ## Screen 154 | 155 | Small utility to set background and foreground colors on an ANSI terminal. 156 | Written in C. 157 | 158 | 159 | ## Syntax Highlighter (SHL) 160 | 161 | ### Summary 162 | 163 | Parses and prints a byte buffer with highlighting of syntax for the selected 164 | language. The language is selected by calling `shl_select_language()` with the 165 | name of a file as argument, see `shl/shl.h` for details. 166 | Example: `shl_select_language("EXAMPLE.C")` selects the C language. 167 | 168 | The parsing and printing highlighted strings are performed by calling 169 | `shl_highlight()` with appropriate arguments, see `shl/shl.h` for details. 170 | 171 | * Keywords for the language, ex: `if`, `then`, `else`, `return` 172 | * Single-line comments, ex: `// single-line comment` 173 | * Multi-line comments, ex: `/* multi-line comment */` 174 | * Strings, ex: `"this is a string"` 175 | * Numeric constants, ex: `3.14159`, `0xFACE`, `.01` 176 | 177 | Languages need to be defined in `shl/shl.c`, there is no reading of language 178 | definition files (yet). 179 | 180 | Possible to parse and print none, parts or all of the byte buffer so that the 181 | CPU load can be kept to a minimum. 182 | 183 | Keeps state of multi-line comments to enable faster parsing in editors, for 184 | example Lean Editor. 185 | 186 | ### Internals 187 | 188 | Copyright (C) 2017-2022 Lars Lindehaven 189 | 190 | Work based on the Program Kilo editor, v0.1.1. 191 | Copyright (c) 2016, Salvatore Sanfilippo 192 | 193 | ## Micro Editor (UE) 194 | 195 | ![UE](https://github.com/lindehaven/CP-M/blob/master/images/ue1.png) 196 | 197 | ### Summary 198 | 199 | See `ue/ue.md` or `ue/ue.m2a` for details. 200 | 201 | ### Internals 202 | 203 | Public Domain 2017-2022 (C) by Lars Lindehaven. 204 | 205 | * Digital Research CP/M systems 206 | * ANSI terminal 207 | * Aztec C Compiler Vers. 1.06D by Manx Software Systems 208 | * YAZE-AG 2.51.1 by Frank D. Cringle, Michael Haardt and Andreas Gerlich 209 | 210 | Work based on the Micro editor, v1.25 by Terry Loveall. 211 | Public Domain 2002 (C) by Terry Loveall. 212 | Public Domain 1991 by Anthony Howe. All rights released. 213 | 214 | See `ue/ue.md` or `ue/ue.m2a` for details. 215 | -------------------------------------------------------------------------------- /be/be.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Binary Editor -- a small binary editor for programmers 3 | * 4 | * Copyright (C) 2017-2022 Lars Lindehaven 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are 9 | * met: 10 | * 11 | * * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 14 | * * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include "ctype.h" 33 | #include "stdio.h" 34 | 35 | /* DEFINITIONS ------------------------------------------------------------ */ 36 | 37 | #define PROG_NAME "Binary Editor" 38 | #define PROG_AUTH "Lars Lindehaven" 39 | #define PROG_VERS "v0.1.6 2022-09-13" 40 | #define PROG_SYST "CP/M" 41 | 42 | #define WORDBITS 16 /* # of bits in a word */ 43 | #define MAX_FNAME 16 /* Max filename length */ 44 | #define MAX_WHERE 2047 /* Max change info size */ 45 | #define MAX_BYTES (MAX_WHERE * WORDBITS) /* Max byte buffer size */ 46 | 47 | #define ED_ROWS 16 /* # of rows */ 48 | #define ED_COLS 16 /* # of columns */ 49 | #define ED_PAGE (ED_ROWS * ED_COLS) /* Page size */ 50 | 51 | #define ED_TITLE 1 /* Title row */ 52 | #define ED_INFO (ED_TITLE + 1) /* Information row */ 53 | #define ED_MSG (ED_INFO + 1) /* Message row */ 54 | #define ED_HEAD (ED_MSG + 2) /* Heading row */ 55 | #define ED_ROWT (ED_HEAD + 1) /* Top of page */ 56 | #define ED_ROWB (ED_ROWT + ED_ROWS - 1) /* Bottom of page */ 57 | #define ED_TAIL (ED_ROWB + 1) /* Trailing row */ 58 | 59 | #define ED_CLM 2 /* Column Left Margin */ 60 | #define ED_CHW 3 /* Column Hex Width */ 61 | #define ED_CHL (ED_CLM + 8) /* Column Hex Left */ 62 | #define ED_CHR (ED_CHL + ED_COLS * ED_CHW) /* Column Hex Right */ 63 | #define ED_CAW 1 /* Column ASCII Width */ 64 | #define ED_CAL (ED_CHR + 4) /* Column ASCII Left */ 65 | #define ED_CAR (ED_CAL + ED_COLS * ED_CAW) /* Column ASCII Right */ 66 | 67 | /* ANSI Screen */ 68 | #define TERM_ROWS 25 /* # of rows on terminal screen. */ 69 | #define TERM_COLS 80 /* # of columns on terminal screen. */ 70 | 71 | /* GLOBALS ---------------------------------------------------------------- */ 72 | 73 | /* CP/M Keyboard */ 74 | char *key[] = { 75 | "L.Lindehaven", 76 | "\x0a", /* ^J Help */ 77 | "\x05", /* ^E Cursor one row up */ 78 | "\x18", /* ^X Cursor one row down */ 79 | "\x13", /* ^S Cursor one column left */ 80 | "\x04", /* ^D Cursor one column right */ 81 | "\x12", /* ^R Cursor one page up */ 82 | "\x03", /* ^C Cursor one page down */ 83 | "\x14", /* ^T Cursor to beginning of byte buffer (top) */ 84 | "\x16", /* ^V Cursor to end of byte buffer (bottom) */ 85 | "\x01", /* ^A Set edit mode HEX */ 86 | "\x06", /* ^F Set edit mode ASCII */ 87 | "\x1a", /* ^Z Toggle edit mode (ASCII/HEX) */ 88 | "\x17", /* ^W Write byte buffer to file (save) */ 89 | "\x1b", /* ESC Quit */ 90 | "\x00", /* Reserved for future use */ 91 | "\x00", /* Reserved for future use */ 92 | }; 93 | 94 | char *help[] = { 95 | "^J Help (this)", 96 | "^E Row up ", 97 | "^X Row down ", 98 | "^S Col left ", 99 | "^D Col right ", 100 | "^R Page up ", 101 | "^C Page down ", 102 | "^T Top ", 103 | "^V Bottom ", 104 | "^A HEX mode ", 105 | "^F ASCII mode ", 106 | "^Z Toggle mode", 107 | "^W Write file ", 108 | "ESC Quit ", 109 | " ", 110 | " " 111 | }; 112 | 113 | char fname[MAX_FNAME]; /* Filename */ 114 | int eatop = 0; /* Address on top row in editor */ 115 | int aoffs = 0x0100; /* Offset when displaying address */ 116 | int erow = 0; /* Row in editor */ 117 | int ecol = 0; /* Column in editor */ 118 | int eascii = 0; /* Edit mode: 0 (HEX) or 1 (ASCII) */ 119 | int bcurr = 0; /* Current position in byte buffer */ 120 | int bsize = 0; /* Size of byte buffer */ 121 | int bchanges = 0; /* # of changes made in byte buffer */ 122 | int bwhere[MAX_WHERE]; /* Where changes have been made */ 123 | char bbuff[MAX_BYTES]; /* Byte buffer (maximum 32767 bytes) */ 124 | 125 | 126 | /* PROGRAM ---------------------------------------------------------------- */ 127 | 128 | int main(argc, argv) int argc, argv[]; { 129 | int rc = 0; 130 | 131 | if (argc > 1) { 132 | if (strlen(argv[1]) > MAX_FNAME - 1) { 133 | fprintf(stderr, "Filename is too long."); 134 | return -1; 135 | } else { 136 | strcpy(fname, argv[1]); 137 | if (fileRead()) 138 | return -1; 139 | } 140 | if (argc == 3) { 141 | aoffs = atoi(argv[2]); 142 | } 143 | } else { 144 | fprintf(stderr, "Usage: be filename.ext [address offset]"); 145 | return -1; 146 | } 147 | scrClr(); 148 | rc = edLoop(); 149 | scrClr(); 150 | return rc; 151 | } 152 | 153 | /* EDITING ---------------------------------------------------------------- */ 154 | 155 | /* Main editor loop */ 156 | int edLoop() { 157 | int ch; 158 | 159 | sysTitle(); 160 | sysHead(); 161 | edResetChanges(); 162 | edUpdAll(); 163 | while (1) { 164 | sysInfo(); 165 | edPosCur(); 166 | ch = keyPressed(); 167 | if (ch == *key[1]) 168 | edHelp(); 169 | else if (ch == *key[2]) 170 | rowUp(); 171 | else if (ch == *key[3]) 172 | rowDown(); 173 | else if (ch == *key[4] || ch == 127) 174 | colLeft(); 175 | else if (ch == *key[5] || ch == 9) 176 | colRight(); 177 | else if (ch == *key[6]) 178 | pageUp(); 179 | else if (ch == *key[7]) 180 | pageDown(); 181 | else if (ch == *key[8]) 182 | buffTop(); 183 | else if (ch == *key[9]) 184 | buffBottom(); 185 | else if (ch == *key[10]) 186 | eascii = 0; 187 | else if (ch == *key[11]) 188 | eascii = 1; 189 | else if (ch == *key[12]) 190 | eascii ^= 1; 191 | else if (ch == *key[13]) 192 | fileWrite(); 193 | else if (ch == *key[14]) { 194 | fileQuit(); 195 | return 0; 196 | /* *key[15] and *key[16] are free to use */ 197 | } 198 | else 199 | edInput(ch); 200 | } 201 | } 202 | 203 | /* Position cursor depending on edit mode (HEX or ASCII) */ 204 | edPosCur() { 205 | if (eascii) 206 | scrPosCur(ED_ROWT + erow, ED_CAL + ED_CAW * ecol); 207 | else 208 | scrPosCur(ED_ROWT + erow, ED_CHL + ED_CHW * ecol); 209 | } 210 | 211 | /* Edit current line */ 212 | edInput(ch) char ch; { 213 | int hi, lo, new; 214 | 215 | if (eascii) { 216 | if (ch != bbuff[bcurr] && ch > 0x1f && ch < 0x7f) { 217 | bbuff[bcurr] = ch; 218 | edSetChange(bcurr); 219 | edUpd(erow, 1); 220 | colRight(); 221 | } 222 | } else { 223 | if ((hi = edHex2Nibble(ch)) > -1) { 224 | putchar(tolower(ch)); 225 | ch = keyPressed(); 226 | if ((lo = edHex2Nibble(ch)) > -1) { 227 | putchar(tolower(ch)); 228 | new = 16 * hi + lo; 229 | if (new != bbuff[bcurr]) { 230 | bbuff[bcurr] = new; 231 | edSetChange(bcurr); 232 | } 233 | } 234 | edUpd(erow, 1); 235 | colRight(); 236 | } 237 | } 238 | } 239 | 240 | /* Convert hexadecimal to nibble (0-15) */ 241 | int edHex2Nibble(ch) char ch; { 242 | if (ch >= '0' && ch <= '9') 243 | return (ch - '0'); 244 | else if (ch >= 'A' && ch <= 'F') 245 | return (ch - 'A' + 10); 246 | else if (ch >= 'a' && ch <= 'f') 247 | return (ch - 'a' + 10); 248 | else 249 | return -1; 250 | } 251 | 252 | /* Store number of changes and where they have been made */ 253 | edSetChange(bindex) int bindex; { 254 | if (!edIsChanged(bindex)) { 255 | bwhere[bindex / WORDBITS] |= 1 << bindex % WORDBITS; 256 | bchanges += 1; 257 | } 258 | } 259 | 260 | /* Check if byte is changed */ 261 | int edIsChanged(bindex) int bindex; { 262 | return ((bwhere[bindex / WORDBITS] >> bindex % WORDBITS) & 1); 263 | } 264 | 265 | /* Reset number of changes and where they have been made */ 266 | edResetChanges() { 267 | int i; 268 | 269 | for (i = 0; i < MAX_WHERE; i++) 270 | bwhere[i] = 0; 271 | bchanges = 0; 272 | } 273 | 274 | /* Update all columns on row(s) on editor screen */ 275 | edUpd(fromrow, nrows) int fromrow, nrows; { 276 | int r, c, i; 277 | 278 | for (r = fromrow; r < fromrow + nrows && r < ED_ROWS; r++) { 279 | scrClrRow(ED_ROWT + r); 280 | scrPosCur(ED_ROWT + r, ED_CLM); 281 | printf("%04x", aoffs + eatop + r * ED_COLS); 282 | for (c = 0; c < ED_COLS; c++) { 283 | i = eatop + r * ED_COLS + c; 284 | scrPosCur(ED_ROWT + r, ED_CHL + ED_CHW * c); 285 | if (edIsChanged(i)) 286 | scrInvVideo(); 287 | printf("%02x", bbuff[i]); 288 | scrPosCur(ED_ROWT + r, ED_CAL + ED_CAW * c); 289 | if (bbuff[i] > 0x1f && bbuff[i] < 0x7f) 290 | putchar(bbuff[i]); 291 | else 292 | putchar('.'); 293 | if (edIsChanged(i)) 294 | scrNorVideo(); 295 | } 296 | } 297 | } 298 | 299 | /* Update editor screen from first row to last row */ 300 | edUpdAll() { 301 | scrHideCursor(); 302 | edUpd(0, ED_ROWS); 303 | scrShowCursor(); 304 | } 305 | 306 | /* Display command help */ 307 | edHelp() { 308 | int r, helprows; 309 | 310 | helprows = sizeof(help) / sizeof(help[0]); 311 | for (r = 0; r < ED_ROWS; r++) 312 | scrClrRow(ED_ROWT + r); 313 | for (r = 0; r < ED_ROWS && r < helprows; r++) { 314 | scrPosCur(ED_ROWT + r, TERM_COLS/2 - strlen(help[0])); 315 | printf("%s", help[r]); 316 | } 317 | sysMsgKey("Press any key to continue editing: "); 318 | edUpdAll(); 319 | } 320 | 321 | /* CURSOR MOVEMENT -------------------------------------------------------- */ 322 | 323 | /* Move cursor one row up */ 324 | rowUp() { 325 | if (bcurr >= ED_COLS) { 326 | bcurr -= ED_COLS; 327 | if (eatop >= ED_COLS && erow == 0) { 328 | eatop -= ED_COLS; 329 | edUpdAll(); 330 | } else if (erow > 0) { 331 | erow--; 332 | } 333 | edPosCur(); 334 | } 335 | } 336 | 337 | /* Move cursor one row down */ 338 | rowDown() { 339 | if (bcurr < bsize-ED_COLS) { 340 | bcurr += ED_COLS; 341 | if (eatop <= bsize-ED_COLS && erow == ED_ROWS-1) { 342 | eatop += ED_COLS; 343 | edUpdAll(); 344 | } else if (erow < ED_ROWS-1) { 345 | erow++; 346 | } 347 | edPosCur(); 348 | } 349 | } 350 | 351 | /* Move cursor one column left */ 352 | colLeft() { 353 | if (bcurr > 0) { 354 | bcurr--; 355 | if (ecol > 0) { 356 | ecol--; 357 | } else { 358 | ecol = ED_COLS-1; 359 | if (eatop >= ED_COLS && erow == 0) { 360 | eatop -= ED_COLS; 361 | edUpdAll(); 362 | } else if (erow > 0) { 363 | erow--; 364 | } 365 | } 366 | edPosCur(); 367 | } 368 | } 369 | 370 | /* Move cursor one column right */ 371 | colRight() { 372 | if (bcurr < bsize-1) { 373 | bcurr++; 374 | if (ecol < ED_COLS-1) { 375 | ecol++; 376 | } else { 377 | ecol = 0; 378 | if (eatop <= bsize-ED_COLS && erow == ED_ROWS-1) { 379 | eatop += ED_COLS; 380 | edUpdAll(); 381 | } else if (erow < ED_ROWS-1) { 382 | erow++; 383 | } 384 | } 385 | edPosCur(); 386 | } 387 | } 388 | 389 | /* Move cursor one page up */ 390 | pageUp() { 391 | if (bcurr >= ED_PAGE) { 392 | bcurr -= ED_PAGE; 393 | if (bcurr < ED_PAGE) { 394 | bcurr = ecol; 395 | eatop = 0; 396 | erow = 0; 397 | } else { 398 | eatop -= ED_PAGE; 399 | } 400 | edUpdAll(); 401 | edPosCur(); 402 | } 403 | } 404 | 405 | /* Move cursor one page down */ 406 | pageDown() { 407 | if (bcurr < bsize - ED_PAGE) { 408 | bcurr += ED_PAGE; 409 | eatop += ED_PAGE; 410 | edUpdAll(); 411 | edPosCur(); 412 | } 413 | } 414 | 415 | /* Move cursor to beginning of buffer */ 416 | buffTop() { 417 | if (bcurr != 0) { 418 | bcurr = 0; 419 | eatop = 0; 420 | erow = 0; 421 | ecol = 0; 422 | edUpdAll(); 423 | edPosCur(); 424 | } 425 | } 426 | 427 | /* Move cursor to end of buffer */ 428 | buffBottom() { 429 | if (bcurr != bsize - 1) { 430 | bcurr = bsize - 1; 431 | eatop = bsize - ED_COLS; 432 | erow = 0; 433 | ecol = bcurr % ED_COLS; 434 | edUpdAll(); 435 | edPosCur(); 436 | } 437 | } 438 | 439 | /* FILE I/O --------------------------------------------------------------- */ 440 | 441 | /* Read file to byte buffer */ 442 | fileRead() { 443 | FILE *fp; 444 | int i; 445 | 446 | if (!(fp = fopen(fname, "r"))) { 447 | fprintf(stderr, "Cannot open %s", fname); 448 | return -1; 449 | } 450 | for (i = 0; i < MAX_BYTES; ++i) { 451 | bbuff[i] = fgetc(fp); 452 | if (feof(fp)) 453 | break; 454 | } 455 | fclose(fp); 456 | if (i >= MAX_BYTES) { 457 | fprintf(stderr, "Not enough memory to read %s", fname); 458 | return -1; 459 | } 460 | bsize = i; 461 | return 0; 462 | } 463 | 464 | /* Write byte buffer to file */ 465 | fileWrite() { 466 | FILE *fp; 467 | int bytes; 468 | 469 | if (!(fp = fopen(fname, "w"))) { 470 | sysMsgKey("Could not open file for writing! Press any key: "); 471 | return -1; 472 | } 473 | for (bytes = 0; bytes < bsize; bytes++) { 474 | fputc(bbuff[bytes], fp); 475 | } 476 | if (fclose(fp) == EOF) { 477 | sysMsgKey("Could not close file after writing! Press any key: "); 478 | return -1; 479 | } 480 | if (bytes < bsize) { 481 | sysMsgKey("Could not write to file! Press any key: "); 482 | return -1; 483 | } 484 | edResetChanges(); 485 | edUpdAll(); 486 | return 0; 487 | } 488 | 489 | /* Let user choose to save or disregard any changes made */ 490 | fileQuit() { 491 | char ch = ' '; 492 | 493 | if (bchanges) { 494 | while (ch != 'S' && ch != 'Q') { 495 | ch = sysMsgKey("There are unsaved changes. S(ave) or Q(uit)? "); 496 | ch = toupper(ch); 497 | if (ch == 'S') 498 | fileWrite(); 499 | } 500 | } 501 | } 502 | 503 | /* SYSTEM INFORMATION ----------------------------------------------------- */ 504 | 505 | /* Print system title. */ 506 | sysTitle() { 507 | scrPosCur(ED_TITLE, ED_CLM); 508 | printf("%s %s for %s by %s", PROG_NAME, PROG_VERS, PROG_SYST, PROG_AUTH); 509 | } 510 | 511 | /* Display the file information */ 512 | sysInfo() { 513 | scrPosCur(ED_INFO, ED_CLM); 514 | printf("%s ", fname); 515 | if (bchanges) { 516 | scrInvVideo(); 517 | putchar('*'); 518 | } else { 519 | scrNorVideo(); 520 | putchar(' '); 521 | } 522 | printf(" %5d ", bchanges); 523 | scrNorVideo(); 524 | printf(" %04x/%04x ", bcurr, bsize-1); 525 | if (eascii) printf("ASCII"); else printf("HEX "); 526 | printf(" Press ^J for help"); 527 | } 528 | 529 | /* Print header on system line */ 530 | sysHead() { 531 | int i; 532 | 533 | scrPosCur(ED_HEAD, 0); 534 | for (i = 0; i < TERM_COLS; i++) 535 | putchar('='); 536 | scrPosCur(ED_HEAD, ED_CLM-1); 537 | printf(" ADDR "); 538 | scrPosCur(ED_HEAD, ED_CHL-1); 539 | printf(" HEX "); 540 | scrPosCur(ED_HEAD, ED_CAL-1); 541 | printf(" ASCII "); 542 | scrPosCur(ED_TAIL, 0); 543 | for (i = 0; i < TERM_COLS; i++) 544 | putchar('='); 545 | } 546 | 547 | /* Print message on system line */ 548 | sysMsg(s) char *s; { 549 | scrClrRow(ED_MSG); 550 | scrPosCur(ED_MSG, ED_CLM); 551 | printf("%s", s); 552 | } 553 | 554 | /* Print message on system line and wait for a key press */ 555 | int sysMsgKey(s) char *s; { 556 | int ch; 557 | 558 | scrInvVideo(); 559 | sysMsg(s); 560 | ch = keyPressed(); 561 | scrNorVideo(); 562 | scrClrRow(ED_MSG); 563 | return ch; 564 | } 565 | 566 | /* ANSI SCREEN ------------------------------------------------------------ */ 567 | 568 | /* Clear screen and send cursor to upper left corner. */ 569 | scrClr() { 570 | printf("\x1b[2J"); 571 | printf("\x1b[H"); 572 | } 573 | 574 | /* Move cursor to row, col */ 575 | scrPosCur(row, col) int row, col; { 576 | printf("\x1b[%d;%dH", row+1, col+1); 577 | } 578 | 579 | /* Erase from the cursor to the end of the line */ 580 | scrClrEol() { 581 | printf("\x1b[K"); 582 | } 583 | 584 | /* Move cursor to row and clear line */ 585 | scrClrRow(row) int row; { 586 | scrPosCur(row, 0); 587 | scrClrEol(); 588 | } 589 | 590 | /* Set inverse video */ 591 | scrInvVideo() { 592 | printf("\x1b[7m"); 593 | } 594 | 595 | /* Set normal video */ 596 | scrNorVideo() { 597 | printf("\x1b[27m"); 598 | } 599 | 600 | /* Hide cursor */ 601 | scrHideCursor() { 602 | printf("\x1b[?25l"); 603 | } 604 | 605 | /* Show cursor */ 606 | scrShowCursor() { 607 | printf("\x1b[?25h"); 608 | } 609 | 610 | /* CP/M KEYBOARD ---------------------------------------------------------- */ 611 | 612 | #asm 613 | ; int keyPressed(void); 614 | public keyPressed 615 | keyPressed: 616 | lxi d,253 617 | mvi c,6 618 | call 5 619 | mvi h,0 620 | mov l,a 621 | ret 622 | #endasm 623 | 624 | -------------------------------------------------------------------------------- /be/be.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lindehaven/CP-M/3b81ed2c72c6acdb537abf102a59281b884281d3/be/be.com -------------------------------------------------------------------------------- /be/be.m2a: -------------------------------------------------------------------------------- 1 |  Binary Editor 2 |  3 | A small binary editor for programmers 4 | 5 | 6 |  Summary 7 |  8 | Binary Editor (BE) enables hexadecimal and ASCII editing of binary 9 | files up to 32 KB in size. 10 | 11 | CP/M programs starts at address 0x0100 by default so this is also 12 | the address offset used by BE as default. This can be changed by 13 | the user when starting BE. 14 | 15 | BE continuously keeps track of the current position and displays 16 | that on the top of the terminal screen together with the total file 17 | size. 18 | 19 | Any unsaved edits are marked with inverse video on the terminal 20 | screen. The user must also confirm if unsaved edits shall be saved 21 | or discarded when exiting BE. 22 | 23 | NOTE! 24 | If ^S is pressed repeatedly then screen output may pause. 25 | Press ^Q once to unpause. 26 | 27 | 28 |  Help Key 29 |  30 | ^J Show help about key controls. 31 | 32 | 33 |  Navigation Keys 34 |  35 | ^E Cursor one row up. 36 | ^X Cursor one row down. 37 | ^S Cursor one column left. 38 | ^D Cursor one column right. 39 | ^R Cursor one page up. 40 | ^C Cursor one page down. 41 | ^T Cursor to beginning of byte buffer (top). 42 | ^V Cursor to end of byte buffer (bottom). 43 | 44 | 45 |  Editing Keys 46 |  47 | ^A Set edit mode HEX. 48 | ^F Set edit mode ASCII. 49 | ^Z Toggle edit mode (ASCII/HEX). 50 | 51 | 52 |  File Command Keys 53 |  54 | ^W Write buffer to file (save). 55 | ESC Quit program. 56 | 57 | 58 |  Internals 59 |  60 | - Digital Research CP/M systems 61 | - ANSI terminal 62 | - Aztec C Compiler Vers. 1.06D by Manx Software Systems 63 | - YAZE-AG 2.51.1 by Frank D. Cringle, Michael Haardt and Andreas Gerlich 64 | 65 | Keyboard mapping can be easily changed without compiling the BE 66 | source code, assembling and linking. There are 13 editor keys that 67 | are located at 0x0010 - 0x0028 in BE.COM. By editing BE.COM using 68 | itself(!) you can change these key mappings and save the BE.COM 69 | that you want. The help text for key mappings are located at 70 | 0x0030 - 0x00ff and you should edit those too while you are at it. 71 | Save a backup of the original BE.COM before you start editing. 72 | 73 | 74 |  License 75 |  76 | Copyright (C) 2017-2022 Lars Lindehaven. All rights reserved. 77 | 78 | Redistribution and use in source and binary forms, with or without 79 | modification, are permitted provided that the following conditions are 80 | met: 81 | 82 | Redistributions of source code must retain the above copyright 83 | notice, this list of conditions and the following disclaimer. 84 | 85 | Redistributions in binary form must reproduce the above copyright 86 | notice, this list of conditions and the following disclaimer in the 87 | documentation and/or other materials provided with the distribution. 88 | 89 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 90 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 91 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 92 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 93 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 94 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 95 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 96 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 97 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 98 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 99 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 100 |  101 |  -------------------------------------------------------------------------------- /be/be.md: -------------------------------------------------------------------------------- 1 | # Binary Editor 2 | 3 | _A small binary editor for programmers_ 4 | 5 | 6 | ## Summary 7 | 8 | Binary Editor (BE) enables hexadecimal and ASCII editing of binary 9 | files up to 32 KB in size. 10 | 11 | CP/M programs starts at address 0x0100 by default so this is also 12 | the address offset used by BE as default. This can be changed by 13 | the user when starting BE. 14 | 15 | BE continuously keeps track of the current position and displays 16 | that on the top of the terminal screen together with the total file 17 | size. 18 | 19 | Any unsaved edits are marked with inverse video on the terminal 20 | screen. The user must also confirm if unsaved edits shall be saved 21 | or discarded when exiting BE. 22 | 23 | ___NOTE!___ 24 | If ^S is pressed repeatedly then screen output may pause. 25 | Press ^Q once to unpause. 26 | 27 | 28 | ## Help Key 29 | 30 | ^J Show help about key controls. 31 | 32 | 33 | ## Navigation Keys 34 | 35 | ^E Cursor one row up. 36 | ^X Cursor one row down. 37 | ^S Cursor one column left. 38 | ^D Cursor one column right. 39 | ^R Cursor one page up. 40 | ^C Cursor one page down. 41 | ^T Cursor to beginning of byte buffer (top). 42 | ^V Cursor to end of byte buffer (bottom). 43 | 44 | 45 | ## Editing Keys 46 | 47 | ^A Set edit mode HEX. 48 | ^F Set edit mode ASCII. 49 | ^Z Toggle edit mode (ASCII/HEX). 50 | 51 | 52 | ## File Command Keys 53 | 54 | ^W Write buffer to file (save). 55 | ESC Quit program. 56 | 57 | 58 | ## Internals 59 | 60 | * Digital Research CP/M systems 61 | * ANSI terminal 62 | * Aztec C Compiler Vers. 1.06D by Manx Software Systems 63 | * YAZE-AG 2.51.1 by Frank D. Cringle, Michael Haardt and Andreas Gerlich 64 | 65 | Keyboard mapping can be easily changed without compiling the BE 66 | source code, assembling and linking. There are 13 editor keys that 67 | are located at 0x0010 - 0x0028 in BE.COM. By editing BE.COM using 68 | itself(!) you can change these key mappings and save the BE.COM 69 | that you want. The help text for key mappings are located at 70 | 0x0030 - 0x00ff and you should edit those too while you are at it. 71 | Save a backup of the original BE.COM before you start editing. 72 | 73 | 74 | ## License 75 | _ 76 | Copyright (C) 2017-2022 Lars Lindehaven. All rights reserved. 77 | 78 | Redistribution and use in source and binary forms, with or without 79 | modification, are permitted provided that the following conditions are 80 | met: 81 | 82 | Redistributions of source code must retain the above copyright 83 | notice, this list of conditions and the following disclaimer. 84 | 85 | Redistributions in binary form must reproduce the above copyright 86 | notice, this list of conditions and the following disclaimer in the 87 | documentation and/or other materials provided with the distribution. 88 | 89 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 90 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 91 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 92 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 93 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 94 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 95 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 96 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 97 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 98 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 99 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 100 | _ 101 | -------------------------------------------------------------------------------- /be/makefile.dat: -------------------------------------------------------------------------------- 1 | # MAKEFILE FOR AZTEC C 2 | 3 | CCC = cc.com 4 | ASM = as.com 5 | LNK = ln.com 6 | 7 | all: be 8 | 9 | be: 10 | $(CCC) be.c 11 | $(ASM) be.asm 12 | $(LNK) -o be.com be.o c.lib 13 | -------------------------------------------------------------------------------- /be/mkbe.sub: -------------------------------------------------------------------------------- 1 | ; Build Binary Editor using AZTEC 2 | cc be 3 | as -ZAP be.asm 4 | ln -o be.com be.o c.lib 5 | -------------------------------------------------------------------------------- /clib/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (C) 2017-2022 Lars Lindehaven. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /clib/makefile.dat: -------------------------------------------------------------------------------- 1 | # MAKEFILE FOR AZTEC C 2 | 3 | CCC = cc.com 4 | ASM = as.com 5 | LNK = ln.com 6 | 7 | all: clib clibtest 8 | 9 | clib: 10 | $(CCC) memcpy.c 11 | $(CCC) strchr.c 12 | $(CCC) strstr.c 13 | $(ASM) memcpy.asm 14 | $(ASM) strchr.asm 15 | $(ASM) strstr.asm 16 | 17 | clibtest: 18 | $(CCC) clibtest.c 19 | $(ASM) clibtest.asm 20 | $(LNK) -o clibtest.com clibtest.o memcpy.o strchr.o strstr.o c.lib 21 | -------------------------------------------------------------------------------- /clib/memcpy.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017-2022 by Lars Lindehaven 2 | * Copies n characters from memory area str2 to memory area str1. 3 | * Returns pointer to destination, which is str1. 4 | */ 5 | void *memcpy(str1,str2,n) 6 | void *str1; void *str2; unsigned int n; 7 | { 8 | unsigned int i; 9 | char *csrc = (char *)str2; 10 | char *cdest = (char *)str1; 11 | 12 | for (i = 0; i < n; i++) 13 | cdest[i] = csrc[i]; 14 | 15 | return str1; 16 | } 17 | -------------------------------------------------------------------------------- /clib/mkclib.sub: -------------------------------------------------------------------------------- 1 | ; Build Lars Lindehaven's modules for Aztec C 2 | ;------ memcpy -------- 3 | cc memcpy 4 | as -ZAP memcpy.asm 5 | ;------ strchr -------- 6 | cc strchr.c 7 | as -ZAP strchr.asm 8 | ;------ strstr -------- 9 | cc strstr.c 10 | as -ZAP strstr.asm 11 | ;------ tstclib -------- 12 | cc tstclib.c 13 | as -ZAP tstclib.asm 14 | ln -o tstclib.com tstclib.o memcpy.o strchr.o strstr.o c.lib 15 | tstclib.com 16 | -------------------------------------------------------------------------------- /clib/strchr.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017-2022 by Lars Lindehaven 2 | * Searches for the first occurrence of the character c (an unsigned char) in 3 | * the string pointed to by the argument str. 4 | * Returns a pointer to the first occurence of the character n in the string 5 | * str, or NULL if the character is not found. 6 | */ 7 | #ifndef NULL 8 | #define NULL 0 9 | #endif 10 | char *strchr(str,c) 11 | char *str; int c; 12 | { 13 | while (*str) 14 | { 15 | if(*str == c) 16 | return str; 17 | str++; 18 | } 19 | return NULL; 20 | } 21 | -------------------------------------------------------------------------------- /clib/strstr.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017-2022 by Lars Lindehaven 2 | * Finds the first occurrence of the substring needle in the string haystack. 3 | * The terminating '\0' characters are not compared. 4 | * Returns a pointer to the first occurrence in haystack of any of the entire 5 | * sequence of characters specified in needle, or a null pointer if the 6 | * sequence is not present in haystack. 7 | */ 8 | #ifndef NULL 9 | #define NULL 0 10 | #endif 11 | int compare(cx, cy) 12 | char *cx; char *cy; 13 | { 14 | while (*cx && *cy) 15 | { 16 | if (*cx != *cy) 17 | return 0; 18 | cx++; 19 | cy++; 20 | } 21 | return (*cy == '\0'); 22 | } 23 | 24 | char *strstr(haystack,needle) 25 | char *haystack; char *needle; 26 | { 27 | while (*haystack != '\0') 28 | { 29 | if ((*haystack == *needle) && compare(haystack, needle)) 30 | return haystack; 31 | haystack++; 32 | } 33 | return NULL; 34 | } 35 | -------------------------------------------------------------------------------- /clib/tstclib.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017-2022 by Lars Lindehaven 2 | * Test of modules for Aztec C. 3 | */ 4 | #include "stdio.h" 5 | 6 | int main(argc, argv) int argc; char* argv[]; 7 | { 8 | int tcno = 0; 9 | int passed = 0; 10 | int failed = 0; 11 | char *str1 = "failed of course"; 12 | char *str2 = "passed"; 13 | char *haystack = "This is a huge haystack where needle is found!"; 14 | char pin = 'n'; 15 | char screw = 'Y'; 16 | char *needle = "needle"; 17 | char *nail = "nail"; 18 | char *res = NULL; 19 | 20 | printf("Copyright (C) 2017-2018 by Lars Lindehaven."); 21 | printf("\n Test of modules for Aztec C."); 22 | 23 | printf("\n Testcase %2d: ", ++tcno); 24 | if ((res = memcpy(str1, str2, 4)) != NULL) {++passed; printf("Passed");} else {++failed; printf("Failed");} 25 | 26 | printf("\n Testcase %2d: ", ++tcno); 27 | if ((res = strchr(haystack, pin)) != NULL) {++passed; printf("Passed");} else {++failed; printf("Failed");} 28 | 29 | printf("\n Testcase %2d: ", ++tcno); 30 | if ((res = strchr(haystack, screw)) == NULL) {++passed; printf("Passed");} else {++failed; printf("Failed");} 31 | 32 | printf("\n Testcase %2d: ", ++tcno); 33 | if ((res = strchr(",.()+-/*=~%<>[]:;", '+')) != NULL) {++passed; printf("Passed");} else {++failed; printf("Failed");} 34 | 35 | printf("\n Testcase %2d: ", ++tcno); 36 | if ((res = strchr(",.()+-/*=~%<>[]:;", '?')) == NULL) {++passed; printf("Passed");} else {++failed; printf("Failed");} 37 | 38 | printf("\n Testcase %2d: ", ++tcno); 39 | if ((res = strstr(haystack, needle)) != NULL) {++passed; printf("Passed");} else {++failed; printf("Failed");} 40 | 41 | printf("\n Testcase %2d: ", ++tcno); 42 | if ((res = strstr(haystack, nail)) == NULL) {++passed; printf("Passed");} else {++failed; printf("Failed");} 43 | 44 | printf("\n Testcase %2d: ", ++tcno); 45 | if ((res = strstr("Lars Lindehaven", "s L")) != NULL) {++passed; printf("Passed");} else {++failed; printf("Failed");} 46 | 47 | if (!failed) 48 | printf("\n Success! All %d tests passed.\n", passed+failed); 49 | else 50 | printf("\n Failure! %d of %d tests failed.\n", failed, passed+failed); 51 | } 52 | -------------------------------------------------------------------------------- /images/be1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lindehaven/CP-M/3b81ed2c72c6acdb537abf102a59281b884281d3/images/be1.png -------------------------------------------------------------------------------- /images/cpm_inside.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lindehaven/CP-M/3b81ed2c72c6acdb537abf102a59281b884281d3/images/cpm_inside.png -------------------------------------------------------------------------------- /images/digital_research.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lindehaven/CP-M/3b81ed2c72c6acdb537abf102a59281b884281d3/images/digital_research.png -------------------------------------------------------------------------------- /images/ue1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lindehaven/CP-M/3b81ed2c72c6acdb537abf102a59281b884281d3/images/ue1.png -------------------------------------------------------------------------------- /kbm/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (C) 2017-2022 Lars Lindehaven. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /kbm/kbm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Keyboard Mapping 3 | * 4 | * Copyright (C) 2017-2022 Lars Lindehaven. All rights reserved. 5 | */ 6 | 7 | main(argc, argv) int argc, argv[]; 8 | { 9 | int c; 10 | printf("Press key to show keyboard mapping. Press Ctrl+C (^C) to quit.\n"); 11 | while ((c = keyInAsm()) != 3) { 12 | if (c < 0x20) { 13 | putchar('^'); 14 | putchar(c + 'A' - 1); 15 | } 16 | else if (c > 0x7f) { 17 | printf("%x", c); 18 | } 19 | else { 20 | putchar(c); 21 | } 22 | if ((c == 0x0a) || (c == 0x0d)){ 23 | putchar(0x0a); 24 | putchar(0x0d); 25 | } 26 | else { 27 | putchar(' '); 28 | } 29 | } 30 | } 31 | 32 | #asm 33 | ; int keyInAsm(void); 34 | ; Get character from the keyboard. 35 | public keyInAsm 36 | keyInAsm: 37 | lhld 1 ;ld hl,(1) 38 | lxi d,6 ;ld de,6 39 | dad d ;add hl,de 40 | lxi d,keyin2 ;ld de,keyin2 41 | push d ;push de 42 | pchl ;jp (hl) 43 | keyin2: 44 | mvi h,0 ;ld h,0 45 | mov l,a ;ld l,a 46 | ret ;ret 47 | 48 | ; void charOutAsm(int ch); 49 | ; Output character to the terminal screen. 50 | public charOutAsm 51 | charOutAsm: 52 | mov a,l ;ld a,l 53 | cpi 10 ;cp 10 54 | jnz charout2 ;jr nz,charout2 55 | call charout2 ;call charout2 56 | mvi l,13 ;ld l,13 57 | charout2: 58 | mov c,l ;ld c,l 59 | lhld 1 ;ld hl,(1) 60 | lxi d,9 ;ld de,9 61 | dad d ;add hl,de 62 | pchl ;jp (hl) 63 | #endasm 64 | -------------------------------------------------------------------------------- /kbm/kbm.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lindehaven/CP-M/3b81ed2c72c6acdb537abf102a59281b884281d3/kbm/kbm.com -------------------------------------------------------------------------------- /kbm/mkkbm.sub: -------------------------------------------------------------------------------- 1 | ; Build Keyboard Mapping using AZTEC 2 | cz kbm 3 | as kbm.asm 4 | era kbm.asm 5 | ln -o kbm.com kbm.o c.lib 6 | -------------------------------------------------------------------------------- /m2a/m2a.c: -------------------------------------------------------------------------------- 1 | /* m2a -- convert markdown to ANSI screen codes */ 2 | 3 | #include "ctype.h" 4 | #include "stdio.h" 5 | 6 | /* Send ANSI screen codes */ 7 | int reset() { printf("\x1b[0m"); } 8 | int bold() { printf("\x1b[1m"); } 9 | int faint() { printf("\x1b[2m"); } 10 | int normal() { printf("\x1b[22m"); } 11 | int italics() { printf("\x1b[3m"); } 12 | int no_italics() { printf("\x1b[23m"); } 13 | int single_under() { printf("\x1b[4m"); } 14 | int double_under() { printf("\x1b[21m"); } 15 | int no_under() { printf("x1b[24m"); } 16 | int inverse() { printf("\x1b[7m"); } 17 | int no_inverse() { printf("\x1b[27m"); } 18 | 19 | /* 0 = no emphasis, 1 = italics, 2 = bold, 3 = italics and bold */ 20 | int is_emphasis = 0; 21 | 22 | /* 0 = not inline code, 1 = inline code */ 23 | int is_inline = 0; 24 | 25 | /* 0 = not block, 1 = block */ 26 | int is_block = 0; 27 | 28 | /* Returns 1 if heading was converted */ 29 | int heading(string) char *string; { 30 | int level = 0; 31 | if (strstr(string, "#") == string) { 32 | while (*string++ == '#') 33 | ++level; 34 | inverse(); 35 | switch (level) { 36 | case 1 : single_under(); 37 | bold(); 38 | break; 39 | case 2 : double_under(); 40 | bold(); 41 | break; 42 | case 3 : single_under(); 43 | normal(); 44 | break; 45 | case 4 : double_under(); 46 | normal(); 47 | break; 48 | case 5 : single_under(); 49 | faint(); 50 | break; 51 | default: double_under(); 52 | faint(); 53 | } 54 | printf("%s\n", string-1); 55 | reset(); 56 | return (1); 57 | } else { 58 | return (0); 59 | } 60 | } 61 | 62 | /* Returns 1 if quote was converted */ 63 | int quote(string) char *string; { 64 | int level = 0; 65 | int m; 66 | if (strstr(string, ">") == string) { 67 | while (*string++ == '>') 68 | ++level; 69 | reset(); 70 | bold(); 71 | for (m = 0; m < level; m++) 72 | printf("|"); 73 | normal(); 74 | italics(); 75 | printf("%s\n", string-1); 76 | no_italics(); 77 | return (1); 78 | } else { 79 | return (0); 80 | } 81 | } 82 | 83 | /* Returns 1 if code block was converted */ 84 | int block(string) char *string; { 85 | if (strstr(string, "```") == string || 86 | strstr(string, "~~~") == string) { 87 | if (is_block == 1) { 88 | is_block = 0; 89 | normal(); 90 | } else { 91 | is_block = 1; 92 | bold(); 93 | } 94 | return (1); 95 | } else { 96 | return (0); 97 | } 98 | } 99 | 100 | /* Returns 1 if unordered list was converted */ 101 | int unordered(string) char *string; { 102 | if (strstr(string, "*") == string || 103 | strstr(string, "+") == string || 104 | strstr(string, "-") == string) { 105 | reset(); 106 | bold(); 107 | printf("-"); 108 | normal(); 109 | emphasis(string+1); 110 | return (1); 111 | } else { 112 | return (0); 113 | } 114 | } 115 | 116 | /* Returns 1 if plain text or inline code/emphasis was converted */ 117 | int emphasis(string) char *string; { 118 | int i; 119 | if (!is_block) { 120 | for (i = 0; i < strlen(string); i++) { 121 | if (strstr(&string[i], "`") == &string[i]) { 122 | if (is_inline) { 123 | is_inline = 0; 124 | normal(); 125 | } else { 126 | is_emphasis = 0; 127 | is_inline = 1; 128 | bold(); 129 | } 130 | i += 1; 131 | } else if (!is_inline) { 132 | if (strstr(&string[i], "***") == &string[i] || 133 | strstr(&string[i], "___") == &string[i]) { 134 | if (is_emphasis == 3) { 135 | is_emphasis = 0; 136 | no_italics(); 137 | normal(); 138 | } else { 139 | is_emphasis = 3; 140 | italics(); 141 | bold(); 142 | } 143 | i += 3; 144 | } else if (strstr(&string[i], "**") == &string[i] || 145 | strstr(&string[i], "__") == &string[i]) { 146 | if (is_emphasis == 2) { 147 | is_emphasis = 0; 148 | normal(); 149 | } else { 150 | is_emphasis = 2; 151 | bold(); 152 | } 153 | i += 2; 154 | } else if (strstr(&string[i], "*") == &string[i] || 155 | strstr(&string[i], "_") == &string[i]) { 156 | if (is_emphasis == 1) { 157 | is_emphasis = 0; 158 | no_italics(); 159 | } else { 160 | is_emphasis = 1; 161 | italics(); 162 | } 163 | i += 1; 164 | } 165 | } 166 | printf("%c", string[i]); 167 | } 168 | printf("\n"); 169 | return (1); 170 | } else { 171 | printf(" %s\n", string); 172 | return (0); 173 | } 174 | } 175 | 176 | /* Convert all supported markdown codes */ 177 | int convert(string) char *string; { 178 | if (!is_block && !is_inline && heading(string)) 179 | ; 180 | else if (!is_block && !is_inline && quote(string)) 181 | ; 182 | else if (!is_block && !is_inline && unordered(string)) 183 | ; 184 | else if (block(string)) 185 | ; 186 | else 187 | emphasis(string); 188 | return (1); 189 | } 190 | 191 | /* Read lines and convert until end of file */ 192 | int main() { 193 | char line[1024]; 194 | while (1) { 195 | if (gets(line) != NULL) 196 | convert(line); 197 | else 198 | break; 199 | } 200 | reset(); 201 | } 202 | -------------------------------------------------------------------------------- /m2a/m2a.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lindehaven/CP-M/3b81ed2c72c6acdb537abf102a59281b884281d3/m2a/m2a.com -------------------------------------------------------------------------------- /m2a/m2a.m2a: -------------------------------------------------------------------------------- 1 |  Markdown to ANSI (M2A) 2 |  3 |  Summary 4 |  5 | M2A converts and prints markdown code to ANSI screen codes. I wrote it to get 6 | better readability of markdown files on an ANSI terminal. I use it to convert 7 | my markdown files and supply the ANSI-coded files for my CP/M programs. 8 | I give the ANSI-coded files the extension .M2A. 9 | 10 | Example 11 | M2A.COM < M2A.MD > M2A.M2A 12 | 13 | The ANSI-code files then looks ok when dumping them on an ANSI screen. 14 | Example 15 | TYPE M2A.M2A 16 | 17 | M2A supports the following markdown: 18 | 19 | - Headings 20 | - Block quotes 21 | - Code blocks 22 | - Unordered lists 23 | - Inline code 24 | - Emphasized text 25 | 26 | 27 |  Internals 28 |  29 | - Digital Research CP/M systems 30 | - ANSI terminal 31 | - Aztec C Compiler Vers. 1.06D by Manx Software Systems 32 | - YAZE-AG 2.51.1 by Frank D. Cringle, Michael Haardt and Andreas Gerlich 33 | 34 |  License 35 |  36 | Copyright (C) 2022 Lars Lindehaven. All rights reserved. 37 | 38 | Redistribution and use in source and binary forms, with or without 39 | modification, are permitted provided that the following conditions are 40 | met: 41 | 42 | Redistributions of source code must retain the above copyright 43 | notice, this list of conditions and the following disclaimer. 44 | 45 | Redistributions in binary form must reproduce the above copyright 46 | notice, this list of conditions and the following disclaimer in the 47 | documentation and/or other materials provided with the distribution. 48 | 49 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 50 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 51 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 52 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 53 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 54 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 55 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 56 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 57 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 58 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 59 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 60 |  61 |  -------------------------------------------------------------------------------- /m2a/m2a.md: -------------------------------------------------------------------------------- 1 | # Markdown to ANSI (M2A) 2 | 3 | ## Summary 4 | 5 | M2A converts and prints markdown code to ANSI screen codes. I wrote it to get 6 | better readability of markdown files on an ANSI terminal. I use it to convert 7 | my markdown files and supply the ANSI-coded files for my CP/M programs. 8 | I give the ANSI-coded files the extension `.M2A`. 9 | 10 | _Example_ 11 | `M2A.COM < M2A.MD > M2A.M2A` 12 | 13 | The ANSI-code files then looks ok when dumping them on an ANSI screen. 14 | _Example_ 15 | `TYPE M2A.M2A` 16 | 17 | M2A supports the following markdown: 18 | 19 | * Headings 20 | * Block quotes 21 | * Code blocks 22 | * Unordered lists 23 | * Inline code 24 | * Emphasized text 25 | 26 | 27 | ## Internals 28 | 29 | * Digital Research CP/M systems 30 | * ANSI terminal 31 | * Aztec C Compiler Vers. 1.06D by Manx Software Systems 32 | * YAZE-AG 2.51.1 by Frank D. Cringle, Michael Haardt and Andreas Gerlich 33 | 34 | ## License 35 | _ 36 | Copyright (C) 2022 Lars Lindehaven. All rights reserved. 37 | 38 | Redistribution and use in source and binary forms, with or without 39 | modification, are permitted provided that the following conditions are 40 | met: 41 | 42 | Redistributions of source code must retain the above copyright 43 | notice, this list of conditions and the following disclaimer. 44 | 45 | Redistributions in binary form must reproduce the above copyright 46 | notice, this list of conditions and the following disclaimer in the 47 | documentation and/or other materials provided with the distribution. 48 | 49 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 50 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 51 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 52 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 53 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 54 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 55 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 56 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 57 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 58 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 59 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 60 | _ 61 | -------------------------------------------------------------------------------- /m2a/mkm2a.sub: -------------------------------------------------------------------------------- 1 | ; Build Markdown to ANSI using AZTEC 2 | cc m2a 3 | as -ZAP m2a.asm 4 | ln -o m2a.com m2a.o strstr.o c.lib 5 | -------------------------------------------------------------------------------- /screen/mkscreen.sub: -------------------------------------------------------------------------------- 1 | ; Build GREEN.COM with AZTEC 2 | cc screen.c 3 | as -ZAP screen.asm 4 | ln -o screen.com screen.o c.lib 5 | era screen.o 6 | -------------------------------------------------------------------------------- /screen/screen.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #define SENTINEL "\0x03" 4 | 5 | char *all[] = { 6 | "BLACK", 7 | "RED", 8 | "GREEN", 9 | "YELLOW", 10 | "BLUE", 11 | "MAGENTA", 12 | "CYAN", 13 | "WHITE", 14 | SENTINEL 15 | }; 16 | 17 | int main(argc, argv) int argc; char **argv; { 18 | int i; 19 | if (argc<2) { 20 | printf("Usage : SCREEN foreground-color [background-color]\n"); 21 | printf("Colors: "); 22 | i=0; 23 | do { 24 | printf("%s ", all[i]); 25 | ++i; 26 | } while (strcmp(SENTINEL, all[i]) != 0); 27 | } 28 | if (argc>1) { /* foreground-color */ 29 | i=0; 30 | do { 31 | if (strcmp(argv[1], all[i]) == 0) 32 | printf("\x1b[3%dm", i); 33 | ++i; 34 | } while (strcmp(SENTINEL, all[i]) != 0); 35 | } 36 | if (argc>2) { /* background-color */ 37 | i=0; 38 | do { 39 | if (strcmp(argv[2], all[i]) == 0) 40 | printf("\x1b[4%dm", i); 41 | ++i; 42 | } while (strcmp(SENTINEL, all[i]) != 0); 43 | } 44 | } 45 |  -------------------------------------------------------------------------------- /screen/screen.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lindehaven/CP-M/3b81ed2c72c6acdb537abf102a59281b884281d3/screen/screen.com -------------------------------------------------------------------------------- /shl/makefile.dat: -------------------------------------------------------------------------------- 1 | # MAKEFILE FOR AZTEC C 2 | 3 | CCC = cc.com 4 | ASM = as.com 5 | LNK = ln.com 6 | 7 | all: shl shlcolor 8 | 9 | shl: 10 | $(CCC) shl.c 11 | $(CCC) shl_test.c 12 | $(ASM) shl.asm 13 | $(ASM) shl_test.asm 14 | $(LNK) -o shl_test.com shl_test.o shl.o strchr.o strstr.o c.lib 15 | 16 | shlcolor: 17 | $(CCC) -dCOLOR shl.c 18 | $(CCC) shl_test.c 19 | $(ASM) shl.asm 20 | $(ASM) shl_test.asm 21 | $(LNK) -o shl_test.com shl_test.o shl.o strchr.o strstr.o c.lib 22 | -------------------------------------------------------------------------------- /shl/mkshl.sub: -------------------------------------------------------------------------------- 1 | ; Build Syntax Highlighter using AZTEC 2 | 3 | cc shl.h 4 | 5 | ; shlc.o (color) 6 | cc shl.c -DCOLOR 7 | as -ZAP shl.asm 8 | era shlc.o 9 | ren shlc.o=shl.o 10 | 11 | ; shl.o 12 | cc shl.c 13 | as -ZAP shl.asm 14 | -------------------------------------------------------------------------------- /shl/shl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Syntax Highlighter -- prints highlighted source code 3 | * Copyright (C) 2017-2022 Lars Lindehaven 4 | * 5 | * Work based on the Program Kilo editor, v0.1.1. 6 | * Copyright (c) 2016, Salvatore Sanfilippo 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are 10 | * met: 11 | * 12 | * * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 15 | * * Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | * 31 | */ 32 | 33 | #include "ctype.h" 34 | #include "stdio.h" 35 | #include "shl.h" 36 | 37 | /* DEFINITIONS ------------------------------------------------------------ */ 38 | 39 | #define SH_PLAIN 0 /* Plain text that is not any of the following: */ 40 | #define SH_MLC 1 /* Multi-line comment as defined in shl_data. */ 41 | #define SH_MLC_END 2 42 | #define SH_SLC 3 /* Single line comment as defined in shl_data. */ 43 | #define SH_SLC_END 4 44 | #define SH_SQS 5 /* Single quote string, ex: 'She said: "No way!"' */ 45 | #define SH_SQS_END 6 46 | #define SH_DQS 7 /* Double quote string, ex: "It's time to go." */ 47 | #define SH_DQS_END 8 48 | #define SH_NUM 9 /* Numeric, ex: 123, 4.5, 0xef */ 49 | #define SH_KEYW 10 /* Keyword as defined in shlk_* structures. */ 50 | 51 | #ifdef COLOR /* Syntax highlighting with colors. */ 52 | #define TE_MLC "\x1b[0;32m" /* Green */ 53 | #define TE_SLC "\x1b[0;32m" /* Green */ 54 | #define TE_SQS "\x1b[0;36m" /* Normal Cyan */ 55 | #define TE_DQS "\x1b[0;36m" /* Normal Cyan */ 56 | #define TE_NUM "\x1b[0;31m" /* Normal Red */ 57 | #define TE_KEYW "\x1b[1;34m" /* Bold Blue */ 58 | #define TE_PLAIN "\x1b[0;35m" /* Normal Magenta */ 59 | #define TE_RESET "\x1b[39;49m" /* Reset colors */ 60 | #else /* Syntax highlighting with attributes. */ 61 | #define TE_MLC "\x1b[2m" /* Faint */ 62 | #define TE_SLC "\x1b[2m" /* Faint */ 63 | #define TE_SQS "\x1b[3m" /* Italics */ 64 | #define TE_DQS "\x1b[3m" /* Italics */ 65 | #define TE_NUM "\x1b[4m" /* Underline */ 66 | #define TE_KEYW "\x1b[1m" /* Bold */ 67 | #define TE_PLAIN "\x1b[0m" /* Plain */ 68 | #define TE_RESET "\x1b[0m" /* Reset attributes */ 69 | #endif 70 | 71 | typedef char bool; 72 | #define FALSE 0 73 | #define TRUE 1 74 | 75 | struct shl_type { 76 | char** file_ext; 77 | char** keywords; 78 | char* slc_start; 79 | char* mlc_start; 80 | char* mlc_end; 81 | }; 82 | 83 | /* C keywords */ 84 | char* shle_cpp[] = {".C", ".H", NULL}; 85 | char* shlk_cpp[] = { 86 | "auto", "break", "case", "char", "const", "continue", "default", "do", 87 | "double", "else", "enum", "extern", "float", "for", "goto", "if", "int", 88 | "long", "register", "return", "short", "signed", "sizeof", "static", 89 | "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", 90 | "while", 91 | "#asm", "#define", "#elif", "#else", "#endasm", "#endif", "#error", 92 | "#ifdef", "#ifndef", "#if", "#include", "#line", "#pragma", "#undef", 93 | "__DATE__", "__FILE__", "__LINE__", "__STDC__", "__STDC_VERSION__", 94 | "__TIME__", 95 | NULL 96 | }; 97 | 98 | /* CP/M Plus commands */ 99 | char* shle_sub[] = {".SUB", NULL}; 100 | char* shlk_sub[] = { 101 | "COPYSYS", "DATE", "DEVICE", "DIR", "DIRS", "DUMP", "ED", "ERA", "ERASE", 102 | "GENCOM", "GET", "HELP", "HEXCOM", "INITDIR", "LIB", "LINK", "MAC", 103 | "PATCH", "PIP", "PUT", "REN", "RENAME", "RMAC", "SAVE", "SET", "SETDEF", 104 | "SHOW", "SID", "SUBMIT", "TYPE", "USER", "XREF", 105 | "copysys", "date", "device", "dir", "dirs", "dump", "ed", "era", "erase", 106 | "gencom", "get", "help", "hexcom", "initdir", "lib", "link", "mac", 107 | "patch", "pip", "put", "ren", "rename", "rmac", "save", "set", "setdef", 108 | "show", "sid", "submit", "type", "user", "xref", 109 | NULL 110 | }; 111 | 112 | struct shl_type shl_data[] = { 113 | /* extensions, keywords, single cmt, multi-cmt, multi-cmt end */ 114 | { shle_cpp, shlk_cpp, "//" , "/*" , "*/" }, 115 | { shle_sub, shlk_sub, ";" , "" , "" } 116 | }; 117 | 118 | #define SHL_LANGUAGES (sizeof(shl_data) / sizeof(shl_data[0])) 119 | 120 | static int g_language = SHL_FAIL; 121 | static int g_state = SH_PLAIN; 122 | static int g_tab_stop = 8; 123 | static int g_column = 0; 124 | static int g_width = 32767; 125 | 126 | void emit_str(); 127 | void set_mlc(); 128 | void clr_mlc(); 129 | 130 | 131 | /* int shl_language(char *lang_file); 132 | * Sets the desired language for parsing and highlighting. 133 | * @lang_file File name with file extension for the desired language. 134 | * Returns SHL_DONE if language is supported or SHL_FAIL if language is 135 | * not supported. 136 | */ 137 | int shl_language(lang_file) 138 | char *lang_file; 139 | { 140 | struct shl_type *shl_p; 141 | int lang_ix, ext_ix, ext_len; 142 | char* str_p = NULL; 143 | 144 | g_state = SH_PLAIN; 145 | for (lang_ix = 0; lang_ix < SHL_LANGUAGES; lang_ix++) { 146 | shl_p = &shl_data[lang_ix]; 147 | ext_ix = 0; 148 | while (shl_p->file_ext[ext_ix]) { 149 | str_p = strstr(lang_file, shl_p->file_ext[ext_ix]); 150 | if (str_p != NULL) { 151 | ext_len = strlen(shl_p->file_ext[ext_ix]); 152 | if (shl_p->file_ext[ext_ix][0] == '.' && 153 | str_p[ext_len] == '\0') { 154 | g_language = lang_ix; 155 | return SHL_DONE; 156 | } 157 | } 158 | ext_ix++; 159 | } 160 | } 161 | g_language = SHL_FAIL; 162 | return g_language; 163 | } 164 | 165 | /* int shl_tab_stop(int tab_stop); 166 | * Sets the desired tab stop for emitting highlighted strings. 167 | * @tab_stop Desired tab stop (tab width) in the range {1..8}. Default 8. 168 | * Returns the set tab stop. 169 | */ 170 | int shl_tab_stop(tab_stop) 171 | int tab_stop; 172 | { 173 | if (tab_stop >= 1 && tab_stop <= 8) 174 | g_tab_stop = tab_stop; 175 | return g_tab_stop; 176 | } 177 | 178 | /* int shl_width(int width); 179 | * Sets the desired screen width for emitting highlighted strings. 180 | * @width Desired width in the range {1..32767}. Default 32767. 181 | * Returns the set width. 182 | */ 183 | int shl_width(width) 184 | int width; 185 | { 186 | if (width >= 1 && width <= 32767) 187 | g_width = width; 188 | return g_width; 189 | } 190 | 191 | /* int shl_column(int column); 192 | * Sets the desired column for emitting highlighted strings. 193 | * @column Desired column in the range {0..32767}. Default 32767. 194 | * Returns the set column. 195 | */ 196 | int shl_column(column) 197 | int column; 198 | { 199 | if (column >= 0 && column <= 32767) 200 | g_column = column; 201 | return g_column; 202 | } 203 | 204 | /* int shl_clear(char *buf_b, char *buf_e); 205 | * Clears buffer from highlighting markers (msb). 206 | * @buf_b Points to beginning of buffer. 207 | * @buf_e Points to end of buffer. 208 | * Returns number of cleared characters. 209 | */ 210 | int shl_clear(buf_b, buf_e) 211 | char *buf_b, *buf_e; 212 | { 213 | int cleared = 0; 214 | 215 | while (buf_b < buf_e) { 216 | clr_mlc(buf_b++); 217 | cleared++; 218 | } 219 | return cleared; 220 | } 221 | 222 | /* int shl_highlight(char *buf_b, char *buf_e, char *buf_p, int rows); 223 | * Parses buffer and prints highlighted string on screen. 224 | * @buf_b Points to beginning of buffer. 225 | * @buf_e Points to end of buffer. 226 | * @buf_p Points to part of buffer where the printing shall start. 227 | * @rows Maximum number of rows to print. 228 | * Returns number of parsed characters or SHL_FAIL if failed. 229 | */ 230 | int shl_highlight(buf_b, buf_e, buf_p, rows) 231 | char *buf_b, *buf_e, *buf_p; int rows; 232 | { 233 | int parsed = 0, len = 0, cur_row = 0; 234 | char *buf_s, *tmp_w, *tmp_b = buf_b; 235 | 236 | if (g_language == SHL_FAIL) 237 | return SHL_FAIL; 238 | else { 239 | buf_s = buf_b; 240 | while (buf_b < buf_e) { 241 | if ((is_set_mlc(buf_b) || is_beg_mlc(buf_b)) 242 | && g_state != SH_SQS && g_state != SH_DQS) { 243 | g_state = SH_MLC; 244 | while (buf_b < buf_e && !is_end_mlc(buf_b)) 245 | set_mlc(buf_b++); 246 | len = is_end_mlc(buf_b); 247 | if (len) 248 | g_state = SH_MLC_END; 249 | while (buf_b < buf_e && len--) 250 | set_mlc(buf_b++); 251 | } 252 | else if (len = is_end_mlc(buf_b) 253 | && g_state != SH_SQS && g_state != SH_DQS) { 254 | if (g_state == SH_MLC) 255 | g_state = SH_MLC_END; 256 | while (buf_b < buf_e && len--) 257 | buf_b++; 258 | tmp_w = buf_b; 259 | while (tmp_w < buf_e && !is_set_mlc(tmp_w)) 260 | clr_mlc(tmp_w++); 261 | } 262 | else if (is_slc(buf_b) 263 | && g_state != SH_SQS && g_state != SH_DQS) { 264 | g_state = SH_SLC; 265 | while (buf_b < buf_e && !is_eol(buf_b)) 266 | buf_b++; 267 | g_state = SH_SLC_END; 268 | } 269 | else if (is_sqs(buf_b) && g_state != SH_DQS 270 | && g_state != SH_SLC && g_state != SH_MLC) { 271 | g_state = SH_SQS; 272 | while (++buf_b <= buf_e && !is_eol(buf_b) && !is_sqs(buf_b)) 273 | ; 274 | while (buf_b < buf_e && is_sqs(buf_b)) 275 | buf_b++; 276 | g_state = SH_SQS_END; 277 | } 278 | else if (is_dqs(buf_b) && g_state != SH_SQS 279 | && g_state != SH_SLC && g_state != SH_MLC) { 280 | g_state = SH_DQS; 281 | while (++buf_b <= buf_e && !is_eol(buf_b) && !is_dqs(buf_b)) 282 | ; 283 | while (buf_b < buf_e && is_dqs(buf_b)) 284 | buf_b++; 285 | g_state = SH_DQS_END; 286 | } 287 | else if (is_nums(buf_b) 288 | && g_state != SH_SLC && g_state != SH_MLC 289 | && g_state != SH_SQS && g_state != SH_DQS) { 290 | g_state = SH_NUM; 291 | while (buf_b < buf_e && is_numc(buf_b)) 292 | buf_b++; 293 | } 294 | else if ((len = is_keyw(buf_b)) 295 | && g_state != SH_SLC && g_state != SH_MLC 296 | && g_state != SH_SQS && g_state != SH_DQS) { 297 | g_state = SH_KEYW; 298 | buf_b += len; 299 | } 300 | else if (is_eol(buf_b)) { 301 | cur_row++; 302 | buf_b++; 303 | if (g_state == SH_SLC 304 | || g_state == SH_SQS_END || g_state == SH_DQS_END) 305 | g_state = SH_PLAIN; 306 | else if (g_state == SH_MLC) { 307 | while (buf_b < buf_e && !is_end_mlc(buf_b)) 308 | set_mlc(buf_b++); 309 | len = is_end_mlc(buf_b); 310 | if (len) 311 | g_state = SH_MLC; 312 | while (buf_b < buf_e && len--) 313 | set_mlc(buf_b++); 314 | } 315 | } 316 | else if (g_state == SH_MLC_END) { 317 | g_state = SH_PLAIN; 318 | } 319 | else { 320 | g_state = SH_PLAIN; 321 | if (buf_b < buf_e) 322 | buf_b++; 323 | } 324 | if (buf_b > buf_p && cur_row < rows) { 325 | switch (g_state) { 326 | case SH_MLC : 327 | case SH_MLC_END : 328 | emit_str(TE_MLC, buf_s, buf_b, buf_e); 329 | break; 330 | case SH_SLC : 331 | case SH_SLC_END : 332 | emit_str(TE_SLC, buf_s, buf_b, buf_e); 333 | break; 334 | case SH_SQS : 335 | case SH_SQS_END : 336 | emit_str(TE_SQS, buf_s, buf_b, buf_e); 337 | break; 338 | case SH_DQS : 339 | case SH_DQS_END : 340 | emit_str(TE_DQS, buf_s, buf_b, buf_e); 341 | break; 342 | case SH_NUM : 343 | emit_str(TE_NUM, buf_s, buf_b, buf_e); 344 | break; 345 | case SH_KEYW : 346 | emit_str(TE_KEYW, buf_s, buf_b, buf_e); 347 | break; 348 | case SH_PLAIN : 349 | emit_str(TE_PLAIN, buf_s, buf_b, buf_e); 350 | break; 351 | default: 352 | printf("%s", TE_RESET); 353 | fprintf(stderr, "\nInternal error!\n"); 354 | return SHL_FAIL; 355 | break; 356 | } 357 | } 358 | parsed += buf_b - buf_s; 359 | buf_s = buf_b; 360 | } 361 | printf("%s", TE_RESET); 362 | return parsed; 363 | } 364 | } 365 | 366 | /* Prints the highlighting marker and then a string. 367 | * @marker Points to the highlighting marker for the terminal. 368 | * @buf_s Points to the beginning of the string to print. 369 | * @buf_b Points to the end of the string to print. 370 | * @buf_e Points to end of buffer. 371 | */ 372 | void emit_str(marker, buf_s, buf_b, buf_e) 373 | char *marker, *buf_s, *buf_b, *buf_e; 374 | { 375 | char *buf_c, ch; 376 | 377 | printf("%s", marker); 378 | buf_c = buf_s; 379 | while (buf_c < buf_b && buf_c < buf_e && g_column < g_width) { 380 | ch = *buf_c & 0x7f; 381 | if (ch == '\r' || ch == '\n') { 382 | putchar(ch); 383 | g_column = 0; 384 | } else if (ch == '\t') { 385 | do 386 | putchar(' '); 387 | while (++g_column % g_tab_stop && g_column < g_width); 388 | } else if (ch > 0 && ch < 0x7f) { 389 | putchar(ch); 390 | ++g_column; 391 | } 392 | buf_c++; 393 | } 394 | } 395 | 396 | /* Set as multi-line comment */ 397 | void set_mlc(str) char *str; { 398 | *str |= 0x80; 399 | } 400 | 401 | /* Clear multi-line comment */ 402 | void clr_mlc(str) char *str; { 403 | *str &= 0x7f; 404 | } 405 | 406 | /* Returns 1 if strings are equal or 0 if unequal. */ 407 | int is_equ_str(str1, str2, len) char *str1, *str2; int len; { 408 | char ch1, ch2; 409 | int i; 410 | 411 | for (i = 0; i < len; i++) { 412 | ch1 = str1[i] & 0x7f; 413 | ch2 = str2[i] & 0x7f; 414 | if (ch1 != ch2) break; 415 | } 416 | return (i == len); 417 | } 418 | 419 | /* Returns length of multi-line comment beginning or 0 if no match. */ 420 | int is_beg_mlc(str) char *str; { 421 | char *look_p; 422 | int len = 0; 423 | 424 | look_p = shl_data[g_language].mlc_start; 425 | len = strlen(look_p); 426 | if (is_equ_str(str, look_p, len)) 427 | return len; 428 | else 429 | return 0; 430 | } 431 | 432 | /* Returns 1 if multi-line comment or 0 if no match. */ 433 | int is_set_mlc(str) char *str; { 434 | return str[0] & 0x80 ? 1 : 0; 435 | } 436 | 437 | /* Returns length of multi-line comment end or 0 if no match. */ 438 | int is_end_mlc(str) char *str; { 439 | char *look_p; 440 | int len = 0; 441 | 442 | look_p = shl_data[g_language].mlc_end; 443 | len = strlen(look_p); 444 | if (is_equ_str(str, look_p, len)) 445 | return len; 446 | else 447 | return 0; 448 | } 449 | 450 | /* Returns length of single line comment start or 0 if no match */ 451 | int is_slc(str) char *str; { 452 | char *look_p; 453 | int len = 0; 454 | 455 | look_p = shl_data[g_language].slc_start; 456 | len = strlen(look_p); 457 | if (is_equ_str(str, look_p, len)) 458 | return len; 459 | else 460 | return 0; 461 | } 462 | 463 | /* Returns length of keyword or 0 if no match */ 464 | int is_keyw(str) char *str; { 465 | char **look_p; 466 | int i, len = 0; 467 | 468 | look_p = shl_data[g_language].keywords; 469 | for (i = 0; look_p[i]; i++) { 470 | len = strlen(look_p[i]); 471 | if (is_equ_str(str, look_p[i], len) 472 | && is_sep(str[-1]) && is_sep(str[len])) 473 | return len; 474 | } 475 | return 0; 476 | } 477 | 478 | /* Returns 1 if single-quote string */ 479 | int is_sqs(str) char *str; { 480 | char chp = str[-1] & 0x7f; 481 | char ch = str[0] & 0x7f; 482 | return (chp != 0x5c && ch == 0x27); 483 | } 484 | 485 | /* Returns 1 if double-quoted string */ 486 | int is_dqs(str) char *str; { 487 | char chp = str[-1] & 0x7f; 488 | char ch = str[0] & 0x7f; 489 | return (chp != 0x5c && ch == 0x22); 490 | } 491 | 492 | /* Returns 1 if numeric start */ 493 | int is_nums(str) char *str; { 494 | char ch = str[0] & 0x7f; 495 | char chp = str[-1] & 0x7f; 496 | char chn = str[1] & 0x7f; 497 | return (isdigit(ch) && is_sep(chp) || ch == '.' && isdigit(chn)); 498 | } 499 | 500 | /* Returns 1 if numeric continues */ 501 | int is_numc(str) char *str; { 502 | char ch = str[0] & 0x7f; 503 | return (isdigit(ch) || ch == '.' 504 | || ch == 'X' || (ch >= 'A' && ch <= 'F') 505 | || ch == 'x' || (ch >= 'a' && ch <= 'f')); 506 | } 507 | 508 | /* Returns 1 if separator character */ 509 | int is_sep(ch) char ch; { 510 | ch &= 0x7f; 511 | return (isspace(ch) || ch == '\0' 512 | || strchr(",.()+-/*=~%<>[]:;", ch) != NULL); 513 | } 514 | 515 | /* Returns 1 if end of line */ 516 | int is_eol(str) char *str; { 517 | char ch = str[0] & 0x7f; 518 | return (ch == '\r' || ch == '\n' || ch == '\0'); 519 | } 520 | 521 | -------------------------------------------------------------------------------- /shl/shl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Syntax Highlighter -- prints highlighted source code 3 | * Copyright (C) 2017 Lars Lindehaven 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are 7 | * met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | */ 29 | 30 | #define SHL_FAIL -1 31 | #define SHL_DONE 0 32 | 33 | /* int shl_language(char *lang_file); 34 | * Sets the desired language for parsing and highlighting. 35 | * @lang_file File name with file extension for the desired language. 36 | * Returns SHL_DONE if language is supported or SHL_FAIL if language is 37 | * not supported. 38 | */ 39 | extern int shl_language(); 40 | 41 | /* int shl_tab_stop(int tab_stop); 42 | * Sets the desired tab stop for emitting highlighted strings. 43 | * @tab_stop Desired tab stop (tab width) in the range {1..8}. Default 8. 44 | * Returns the set tab stop. 45 | */ 46 | extern int shl_tab_stop(); 47 | 48 | /* int shl_width(int width); 49 | * Sets the desired screen width for emitting highlighted strings. 50 | * @width Desired width in the range {1..32767}. Default 32767. 51 | * Returns the set width. 52 | */ 53 | extern int shl_width(); 54 | 55 | /* int shl_column(int column); 56 | * Sets the desired column for emitting highlighted strings. 57 | * @column Desired column in the range {0..32767}. Default 32767. 58 | * Returns the set column. 59 | */ 60 | extern int shl_column(); 61 | 62 | /* int shl_highlight(char *buf_b, char *buf_e, char *buf_p, int rows); 63 | * Parses buffer and prints highlighted string on screen. 64 | * @buf_b Points to beginning of buffer. 65 | * @buf_e Points to end of buffer. 66 | * @buf_p Points to part of buffer where the printing shall start. 67 | * @rows Maximum number of rows to print. 68 | * Returns number of parsed characters or SHL_FAIL if failed. 69 | */ 70 | extern int shl_highlight(); 71 | -------------------------------------------------------------------------------- /shl/shl.m2a: -------------------------------------------------------------------------------- 1 |  Syntax Highlighter 2 |  3 | Prints highlighted source code 4 | 5 | 6 |  Summary 7 |  8 | Parses and prints a byte buffer with highlighting of syntax for the 9 | selected language. 10 | 11 | The language is selected by calling shl_select_language() with the 12 | name of a file as argument. 13 | 14 | Example: Select the C language 15 | shl_select_language("EXAMPLE.C") 16 | 17 | The parsing and printing highlighted strings are performed by calling 18 | shl_highlight() with appropriate arguments. 19 | 20 | - Keywords for the language, ex: if, then, else, return 21 | - Single-line comments, ex: // single-line comment 22 | - Multi-line comments, ex: /* multi-line comment */ 23 | - Strings, ex: "this is a string" 24 | - Numeric constants, ex: 3.14159, 0xFACE, .01 25 | 26 | Languages need to be defined in shl.c, there is no reading of 27 | language definition files (yet). 28 | 29 | Possible to parse and print none, parts or all of the byte buffer so that 30 | the CPU load can be kept to a minimum. 31 | 32 | Keeps state of multi-line comments to enable faster parsing in editors, 33 | for example Lean Editor. 34 | 35 | 36 |  Internals 37 |  38 | - Digital Research CP/M systems 39 | - ANSI terminal 40 | - Aztec C Compiler Vers. 1.06D by Manx Software Systems 41 | - YAZE-AG 2.51.1 by Frank D. Cringle, Michael Haardt and Andreas Gerlich 42 | 43 | 44 |  License 45 |  46 | Copyright (C) 2017-2022 Lars Lindehaven. 47 | 48 | Work based on the Program Kilo editor, v0.1.1. 49 | Copyright (c) 2016, Salvatore Sanfilippo 50 | 51 | Redistribution and use in source and binary forms, with or without 52 | modification, are permitted provided that the following conditions are 53 | met: 54 | 55 | Redistributions of source code must retain the above copyright 56 | notice, this list of conditions and the following disclaimer. 57 | 58 | Redistributions in binary form must reproduce the above copyright 59 | notice, this list of conditions and the following disclaimer in the 60 | documentation and/or other materials provided with the distribution. 61 | 62 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 63 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 64 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 65 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 66 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 67 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 68 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 69 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 70 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 72 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 |  74 |  -------------------------------------------------------------------------------- /shl/shl.md: -------------------------------------------------------------------------------- 1 | # Syntax Highlighter 2 | 3 | _Prints highlighted source code_ 4 | 5 | 6 | ## Summary 7 | 8 | Parses and prints a byte buffer with highlighting of syntax for the 9 | selected language. 10 | 11 | The language is selected by calling `shl_select_language()` with the 12 | name of a file as argument. 13 | 14 | _Example: Select the C language_ 15 | `shl_select_language("EXAMPLE.C")` 16 | 17 | The parsing and printing highlighted strings are performed by calling 18 | `shl_highlight()` with appropriate arguments. 19 | 20 | * Keywords for the language, ex: `if`, `then`, `else`, `return` 21 | * Single-line comments, ex: `// single-line comment` 22 | * Multi-line comments, ex: `/* multi-line comment */` 23 | * Strings, ex: `"this is a string"` 24 | * Numeric constants, ex: `3.14159`, `0xFACE`, `.01` 25 | 26 | Languages need to be defined in shl.c, there is no reading of 27 | language definition files (yet). 28 | 29 | Possible to parse and print none, parts or all of the byte buffer so that 30 | the CPU load can be kept to a minimum. 31 | 32 | Keeps state of multi-line comments to enable faster parsing in editors, 33 | for example Lean Editor. 34 | 35 | 36 | ## Internals 37 | 38 | * Digital Research CP/M systems 39 | * ANSI terminal 40 | * Aztec C Compiler Vers. 1.06D by Manx Software Systems 41 | * YAZE-AG 2.51.1 by Frank D. Cringle, Michael Haardt and Andreas Gerlich 42 | 43 | 44 | ## License 45 | _ 46 | Copyright (C) 2017-2022 Lars Lindehaven. 47 | 48 | Work based on the Program Kilo editor, v0.1.1. 49 | Copyright (c) 2016, Salvatore Sanfilippo 50 | 51 | Redistribution and use in source and binary forms, with or without 52 | modification, are permitted provided that the following conditions are 53 | met: 54 | 55 | Redistributions of source code must retain the above copyright 56 | notice, this list of conditions and the following disclaimer. 57 | 58 | Redistributions in binary form must reproduce the above copyright 59 | notice, this list of conditions and the following disclaimer in the 60 | documentation and/or other materials provided with the distribution. 61 | 62 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 63 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 64 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 65 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 66 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 67 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 68 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 69 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 70 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 72 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 | _ -------------------------------------------------------------------------------- /shl/tstshl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Syntax Highlighter -- tests highlighted source code 3 | * Copyright (C) 2017-2018 Lars Lindehaven 4 | * 5 | */ 6 | 7 | #include "shl.h" 8 | #include "stdio.h" 9 | 10 | int tcno = 0; 11 | int passed = 0; 12 | int failed = 0; 13 | 14 | void suite1() { 15 | char *lang, *mlcs, *mlce, *slc, *str, *code, *code2; 16 | char *buf_b, *buf_e, *buf_p; 17 | int res = 0; 18 | 19 | lang = "FILEIS.???"; 20 | printf("\nTestcase %2d: shl_language()", ++tcno); 21 | if ((res = shl_language(lang)) == SHL_FAIL) 22 | {++passed; printf("\nPassed");} else {++failed; printf("\nFailed");} 23 | 24 | printf("\nTestcase %2d: shl_tab_stop()", ++tcno); 25 | if ((res = shl_tab_stop(4)) == 4) 26 | {++passed; printf("\nPassed");} else {++failed; printf("\nFailed");} 27 | 28 | printf("\nTestcase %2d: shl_highlight()", ++tcno); 29 | if ((res = shl_highlight(buf_b,buf_e,buf_p,10)) != buf_e-buf_b) 30 | {++passed; printf("\nPassed");} else { 31 | ++failed; printf("\nFailed : %d != %d\n",res,buf_e-buf_b);} 32 | 33 | lang = "FILEIS.C"; 34 | printf("\nTestcase %2d: shl_language()", ++tcno); 35 | if ((res = shl_language(lang)) == SHL_DONE) 36 | {++passed; printf("\nPassed");} else {++failed; printf("\nFailed");} 37 | 38 | mlcs = "/*"; 39 | printf("\nTestcase %2d: is_beg_mlc()", ++\tcno); 40 | if ((res = is_beg_mlc(mlcs)) == 2) 41 | {++passed; printf("\nPassed");} else {++failed; printf("\nFailed");} 42 | 43 | mlce = "*/"; 44 | printf("\nTestcase %2d: is_end_mlc()", ++\tcno); 45 | if ((res = is_end_mlc(mlce)) == 2) 46 | {++passed; printf("\nPassed");} else {++failed; printf("\nFailed");} 47 | 48 | printf("\nTestcase %2d: is_end_mlc()", ++\tcno); 49 | if ((res = is_end_mlc(&mlce[1])) == 0) 50 | {++passed; printf("\nPassed");} else {++failed; printf("\nFailed");} 51 | 52 | slc = "//"; 53 | printf("\nTestcase %2d: is_slc()", ++\tcno); 54 | if ((res = is_slc(slc)) == 2) 55 | {++passed; printf("\nPassed");} else {++failed; printf("\nFailed");} 56 | 57 | str = "\""; 58 | printf("\nTestcase %2d: is_str()", ++\tcno); 59 | if ((res = is_str(str))) 60 | {++passed; printf("\nPassed");} else {++failed; printf("\nFailed");} 61 | 62 | printf("\nTestcase %2d: is_keyw()", ++\tcno); 63 | if ((res = is_keyw("int four = 4;")) == 3) 64 | {++passed; printf("\nPassed");} else {++failed; printf("\nFailed");} 65 | 66 | code = "\n main(argc,argv) { // switch else case\n int intchar=0xaf; //int\n /*float*/ float pi_float=3.14;\n printf(\"Hello \\\"world\\\"!\");\n\t/*\tHere starts a multi-line comment"; 67 | buf_b = buf_p = code; 68 | buf_e = buf_b + strlen(code); 69 | printf("\nTestcase %2d: shl_highlight()", ++tcno); 70 | if ((res = shl_highlight(buf_b,buf_e,buf_p,6)) == buf_e-buf_b) 71 | {++passed; printf("\nPassed");} else { 72 | ++failed; printf("\nFailed : %d != %d\n",res,buf_e-buf_b);} 73 | 74 | code2 = "\n\t\tand the multi-line comment ends here!\n\t*/"; 75 | buf_b = buf_p = code2; 76 | buf_e = buf_b + strlen(code2); 77 | printf("\nTestcase %2d: shl_highlight()", ++tcno); 78 | if ((res = shl_highlight(buf_b,buf_e,buf_p,3)) == buf_e-buf_b) 79 | {++passed; printf("\nPassed");} else { 80 | ++failed; printf("\nFailed : %d != %d\n",res,buf_e-buf_b);} 81 | 82 | } 83 | 84 | void suite2() { 85 | char *lang, *slc, *code; 86 | char *buf_b, *buf_e, *buf_p; 87 | int res = 0; 88 | int tab; 89 | 90 | lang = "FILEIS.SUB"; 91 | printf("\nTestcase %2d: shl_language()", ++tcno); 92 | if ((res = shl_language(lang)) == SHL_DONE) 93 | {++passed; printf("\nPassed");} else {++failed; printf("\nFailed");} 94 | 95 | code = "\n \"This string does not continue\n here but \"here\"."; 96 | buf_b = buf_p = code; 97 | buf_e = buf_b + strlen(code); 98 | printf("\nTestcase %2d: shl_highlight()", ++tcno); 99 | if ((res = shl_highlight(buf_b,buf_e,buf_p,3)) == buf_e-buf_b) 100 | {++passed; printf("\nPassed");} else { 101 | ++failed; printf("\nFailed : %d != %d\n",res,buf_e-buf_b);} 102 | 103 | code = "\n ; TYPE FILE.TXT\n TYPE FILE.TXT\n dir *.123"; 104 | buf_b = buf_p = code; 105 | buf_e = buf_b + strlen(code); 106 | printf("\nTestcase %2d: shl_highlight()", ++tcno); 107 | if ((res = shl_highlight(buf_b,buf_e,buf_p,4)) == buf_e-buf_b) 108 | {++passed; printf("\nPassed");} else { 109 | ++failed; printf("\nFailed : %d != %d\n",res,buf_e-buf_b);} 110 | 111 | code = "\n\t|"; 112 | buf_b = buf_p = code; 113 | buf_e = buf_b + strlen(code); 114 | printf("\nTestcase %2d: shl_tab_stop()", ++tcno); 115 | for (tab = 2; tab <= 8; tab++) { 116 | if ((res = shl_tab_stop(tab)) == tab) 117 | {++passed;} else {++failed;} 118 | if ((res = shl_highlight(buf_b,buf_e,buf_p,2)) == buf_e-buf_b) 119 | {++passed;} else {++failed; printf("\nFailed");} 120 | } 121 | if (!failed) printf("\nPassed"); else printf("\nFailed"); 122 | } 123 | 124 | int main(argc, argv) int argc; char* argv[]; { 125 | 126 | printf("Copyright (C) 2017-2018 by Lars Lindehaven.\n"); 127 | printf("Test of modules for Syntax Highlighter.\n"); 128 | 129 | suite1(); 130 | suite2(); 131 | 132 | if (!failed) 133 | printf("\nSuccess! %d of %d tests passed.\n", passed, passed+failed); 134 | else 135 | printf("\nFailure! %d of %d tests failed.\n", failed, passed+failed); 136 | } 137 |  -------------------------------------------------------------------------------- /shl/tstshl.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lindehaven/CP-M/3b81ed2c72c6acdb537abf102a59281b884281d3/shl/tstshl.com -------------------------------------------------------------------------------- /shl/tstshl.sub: -------------------------------------------------------------------------------- 1 | ; Build and run Syntax Highlighter test 2 | cc tstshl.c 3 | as -ZAP tstshl.asm 4 | ln -o tstshl.com tstshl.o shl.o strchr.o strstr.o c.lib 5 | tstshl.com 6 | ln -o tstshlc.com tstshl.o shlc.o strchr.o strstr.o c.lib 7 | tstshlc.com 8 |  -------------------------------------------------------------------------------- /shl/tstshlc.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lindehaven/CP-M/3b81ed2c72c6acdb537abf102a59281b884281d3/shl/tstshlc.com -------------------------------------------------------------------------------- /ue/makefile.dat: -------------------------------------------------------------------------------- 1 | # MAKEFILE FOR AZTEC C 2 | 3 | CCC = cc.com 4 | ASM = as.com 5 | LNK = ln.com 6 | 7 | all: ue ueshl 8 | 9 | ue: 10 | $(CCC) ue.c 11 | $(ASM) ue.asm 12 | $(LNK) -o ue.com ue.o c.lib 13 | 14 | ueshl: 15 | $(CCC) -dSHL ue.c 16 | $(ASM) ue.asm 17 | $(LNK) -o ue.com ue.o shl.o strchr.o strstr.o c.lib 18 | -------------------------------------------------------------------------------- /ue/mkue.sub: -------------------------------------------------------------------------------- 1 | ; Build U Editor using Aztec C Compiler 2 | 3 | ; Plain 4 | cc ue.c 5 | as -ZAP ue.asm 6 | ln -o ue.com ue.o c.lib 7 | 8 | ; With highlighting 9 | mkshl.sub 10 | cc ue.c -DSHL 11 | as -zap ue.asm 12 | ln -o ueshl.com ue.o shl.o strstr.o strchr.o c.lib 13 | ln -o ueshlc.com ue.o shlc.o strstr.o strchr.o c.lib 14 | -------------------------------------------------------------------------------- /ue/ue.c: -------------------------------------------------------------------------------- 1 | /* 2 | Micro Editor (ue) 3 | 4 | Public Domain 2017-2022 (C) by Lars Lindehaven. 5 | Public Domain 2002 (C) by Terry Loveall. 6 | Public Domain 1991 by Anthony Howe. All rights released. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are 10 | met: 11 | 12 | * Redistributions of source code must retain the above copyright 13 | notice, this list of conditions and the following disclaimer. 14 | 15 | * Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | */ 32 | 33 | #include "ctype.h" 34 | #include "stdio.h" 35 | #ifdef SHL 36 | #include "shl.h" 37 | #endif 38 | 39 | #define KEY_FQUIT (0x1b) /* Escape (save and quit) */ 40 | #define KEY_WLT ('A' & 0x1f) /* Cursor one word left */ 41 | #define KEY_LMVDN ('B' & 0x1f) /* Move line down */ 42 | #define KEY_PDN ('C' & 0x1f) /* Cursor one page down */ 43 | #define KEY_CRT ('D' & 0x1f) /* Cursor one column right */ 44 | #define KEY_RUP ('E' & 0x1f) /* Cursor one row up */ 45 | #define KEY_WRT ('F' & 0x1f) /* Cursor one word right */ 46 | #define KEY_DEL ('G' & 0x1f) /* Delete character to the right */ 47 | #define KEY_RUB ('H' & 0x1f) /* Delete character to the left */ 48 | #define KEY_TAB ('I' & 0x1f) /* Insert tab */ 49 | #define KEY_LBEG ('J' & 0x1f) /* Cursor to beginning of line */ 50 | #define KEY_LEND ('K' & 0x1f) /* Cursor to end of line */ 51 | #define KEY_SRCH ('L' & 0x1f) /* Search string incrementally */ 52 | #define KEY_LINS ('M' & 0x1f) /* Insert new line */ 53 | #define KEY_REPL ('N' & 0x1f) /* Replace string incrementally */ 54 | #define KEY_CUT ('O' & 0x1f) /* Cut to end of line */ 55 | #define KEY_PASTE ('P' & 0x1f) /* Paste */ 56 | #define KEY_SCREEN ('Q' & 0x1f) /* Unpause output and refresh screen */ 57 | #define KEY_PUP ('R' & 0x1f) /* Cursor one page up */ 58 | #define KEY_CLT ('S' & 0x1f) /* Cursor one column left */ 59 | #define KEY_FBEG ('T' & 0x1f) /* Cursor to beginning of file */ 60 | #define KEY_TABW ('U' & 0x1f) /* Change tab width */ 61 | #define KEY_FEND ('V' & 0x1f) /* Cursor to end of file */ 62 | #define KEY_FSAVE ('W' & 0x1f) /* Write to file */ 63 | #define KEY_RDN ('X' & 0x1f) /* Cursor one row down */ 64 | #define KEY_LMVUP ('Y' & 0x1f) /* Move line up */ 65 | #define KEY_UNDO ('Z' & 0x1f) /* Undo last character insert/delete */ 66 | #define KEY_BS (0x7f) /* Delete character to the left */ 67 | 68 | #ifdef SHL 69 | #define MAX_UNDO 2100 70 | #define EDIT_SIZE 21000 71 | #define PASTE_SIZE 1000 72 | #else 73 | #define MAX_UNDO 2800 74 | #define EDIT_SIZE 28000 75 | #define PASTE_SIZE 1000 76 | #endif 77 | #define UNDO_SIZE MAX_UNDO*sizeof(U_REC) 78 | #define SRCH_SIZE 32 79 | #define FNAM_SIZE 32 80 | 81 | #define STAT_FILE "Filename: " 82 | #define STAT_SRCH "Search for: " 83 | #define STAT_REPL "Replace with: " 84 | #define STAT_ERR "!!! " 85 | 86 | #define DEF_FNAME "$$$$$$$$.$$$" 87 | #define MIN_TW 2 88 | #define DEF_TW 8 89 | #define MAX_TW 8 90 | #define MIN_AI 0 91 | #define DEF_AI 1 92 | #define MAX_AI 1 93 | #define MIN_ROWS 10 94 | #define DEF_ROWS 25 95 | #define MAX_ROWS 50 96 | #define MIN_COLS 40 97 | #define DEF_COLS 80 98 | #define MAX_COLS 132 99 | 100 | typedef struct { 101 | int X; 102 | int Y; 103 | } COORD; 104 | 105 | typedef struct { 106 | char ch; 107 | char *pos; 108 | } U_REC; 109 | 110 | char undobuf[UNDO_SIZE], editbuf[EDIT_SIZE], pastebuf[PASTE_SIZE]; 111 | char *editp = editbuf, *endp = editbuf, *pastep = pastebuf; 112 | char *page, *epage, fname[FNAM_SIZE]; 113 | U_REC* undop = (U_REC*)&undobuf; 114 | COORD outxy; 115 | int done = 0, lines = 1, cuts = 0, row = 0, col = 0; 116 | long int eds = 0; 117 | int tw, ai, rows, cols; 118 | #ifdef SHL 119 | int shl; 120 | #endif 121 | 122 | void rup(); 123 | void rdn(); 124 | void clt(); 125 | void crt(); 126 | void wlt(); 127 | void wrt(); 128 | void lbeg(); 129 | void lend(); 130 | void pup(); 131 | void pdn(); 132 | void fbeg(); 133 | void fend(); 134 | void sarstr(); 135 | void inctw(); 136 | void ins(); 137 | void del(); 138 | void rub(); 139 | void cut(); 140 | void paste(); 141 | void lmvup(); 142 | void lmvdn(); 143 | void undo(); 144 | int fread(); 145 | void fsave(); 146 | void fquit(); 147 | void nop(); 148 | void display(); 149 | void status(); 150 | void screen(); 151 | 152 | char key[] = { 153 | KEY_RUP, KEY_RDN, KEY_CLT, KEY_CRT, 154 | KEY_WLT, KEY_WRT, KEY_LBEG, KEY_LEND, 155 | KEY_PUP, KEY_PDN, KEY_FBEG, KEY_FEND, 156 | KEY_SRCH, KEY_REPL, KEY_TABW, KEY_DEL, 157 | KEY_RUB, KEY_BS, KEY_CUT, KEY_PASTE, 158 | KEY_LMVUP, KEY_LMVDN, KEY_UNDO, KEY_FSAVE, 159 | KEY_FQUIT, KEY_SCREEN, 160 | '\0' 161 | }; 162 | 163 | void (*func[])() = { 164 | rup, rdn, clt, crt, 165 | wlt, wrt, lbeg, lend, 166 | pup, pdn, fbeg, fend, 167 | sarstr, sarstr, inctw, del, 168 | rub, rub, cut, paste, 169 | lmvup, lmvdn, undo, fsave, 170 | fquit, screen, 171 | nop 172 | }; 173 | 174 | void clrscreen() { 175 | printf("\x1b[2J"); 176 | } 177 | 178 | void gotoxy(x, y) int x; int y; { 179 | printf("\x1b[%d;%dH", y, x); 180 | outxy.X = x; outxy.Y = y; 181 | } 182 | 183 | void clrtoeol() { 184 | printf("\x1b[0K"); 185 | gotoxy(outxy.X, outxy.Y); 186 | } 187 | 188 | void invvideo() { 189 | printf("\x1b[7m"); 190 | } 191 | 192 | void normvideo() { 193 | printf("\x1b[27m"); 194 | } 195 | 196 | void hidecur() { 197 | printf("\x1b[?25l"); 198 | } 199 | 200 | void showcur() { 201 | printf("\x1b[?25h"); 202 | } 203 | 204 | 205 | #asm 206 | ; int keyPressed(void); 207 | public keyPressed 208 | keyPressed: 209 | lxi d,253 210 | mvi c,6 211 | call 5 212 | mvi h,0 213 | mov l,a 214 | ret 215 | #endasm 216 | 217 | void settw(t) int t; { 218 | tw = t >= MIN_TW && t <= MAX_TW ? t : DEF_TW; 219 | #ifdef SHL 220 | shl_tab_stop(tw); 221 | #endif 222 | } 223 | 224 | void setai(a) int a; { 225 | ai = a >= MIN_AI && a <= MAX_AI ? a : DEF_AI; 226 | } 227 | 228 | void setrows(r) int r; { 229 | rows = r >= MIN_ROWS && r <= MAX_ROWS ? r : DEF_ROWS; 230 | } 231 | 232 | void setcols(c) int c; { 233 | cols = c >= MIN_COLS && c <= MAX_COLS ? c : DEF_COLS; 234 | } 235 | 236 | int emitchar(emitp, currp, emit) char *emitp, *currp; int emit; { 237 | char ch = *emitp & 0x7f; 238 | int len = 0; 239 | if (emitp == currp) { 240 | col = outxy.X; 241 | row = outxy.Y-1; 242 | } 243 | if (ch == '\n') { 244 | if (emit) clrtoeol(); 245 | outxy.X = 0; outxy.Y++; 246 | #ifdef SHL 247 | shl_column(0); 248 | #endif 249 | if (emit) putchar('\n'); 250 | } else if (ch == '\t') { 251 | do { 252 | len++; 253 | if (outxy.X < cols-1 && emit) putchar(' '); 254 | } while (++outxy.X % tw); 255 | } else if (ch > 0x00 && ch < 0x80) { 256 | len++; 257 | if (++outxy.X < cols && emit) putchar(ch); 258 | } 259 | if (outxy.X >= cols) { 260 | putchar('\b'); invvideo(); putchar('+'); normvideo(); 261 | } 262 | return len; 263 | } 264 | 265 | int emitline(emitp, currp) char *emitp, *currp; { 266 | char ch = emitp[0] & 0x7f; 267 | int i, j, len; 268 | if (ch == '\n') { 269 | len = emitchar(emitp, currp, 1); 270 | } else { 271 | len = linelen(emitp); 272 | #ifdef SHL 273 | for (i = 0, j = 0; j < len && i < cols-1; j++) { 274 | ch = emitp[j] & 0x7f; 275 | if (ch == '\t') do ; while (++i % tw && i < cols-1); 276 | else ++i; 277 | } 278 | if (shl != SHL_FAIL) { 279 | shl_highlight(emitp, emitp+j, emitp, 1); 280 | for (i = 0; i < len; i++) emitchar(&emitp[i], currp, 0); 281 | shl_highlight(emitp+j, emitp+len, emitp+j, 0); 282 | } else 283 | #endif 284 | for (i = 0; i < len; i++) emitchar(&emitp[i], currp, 1); 285 | } 286 | return len; 287 | } 288 | 289 | char *prevline(p) char *p; { 290 | while (--p > editbuf && (*p & 0x7f) != '\n') ; 291 | return editbuf < p ? ++p : editbuf; 292 | } 293 | 294 | char *nextline(p) char *p; { 295 | while (p < endp && (*p++ & 0x7f) != '\n') ; 296 | return p < endp ? p : endp; 297 | } 298 | 299 | char *adjust(p, column) char *p; int column; { 300 | int j = 0; 301 | while (p < endp && (*p & 0x7f) != '\n' && j < column) 302 | j += (*p++ & 0x7f) == '\t' ? tw - j % tw : 1; 303 | return p; 304 | } 305 | 306 | int currline() { 307 | char *p = editbuf; 308 | int line = 1; 309 | while (++p <= editp && p <= endp) if ((*(p-1) & 0x7f) == '\n') line++; 310 | return line; 311 | } 312 | 313 | int linelen(p) char *p; { 314 | char *pp = prevline(p); 315 | char *np = nextline(p); 316 | return np - pp - 1; 317 | } 318 | 319 | void charmove(src, dest, cnt) char *src; char *dest; int cnt; { 320 | if (src > dest) 321 | while (cnt--) *dest++ = *src++; 322 | if (src < dest) { 323 | src += cnt; dest += cnt; 324 | while (cnt--) *--dest = *--src; 325 | } 326 | } 327 | 328 | void editmove(src, dest, cnt) char *src; char *dest; int cnt; { 329 | charmove(src, dest, cnt); 330 | endp += dest-src; 331 | } 332 | 333 | void undopfull() { 334 | status(STAT_ERR, "Undo buffer is full. "); keyPressed(); 335 | } 336 | 337 | void editbfull() { 338 | status(STAT_ERR, "Edit buffer is full. "); keyPressed(); 339 | } 340 | 341 | void pastebfull() { 342 | status(STAT_ERR, "Paste buffer is full. "); keyPressed(); 343 | } 344 | 345 | void fwriterr() { 346 | status(STAT_ERR, "%s could not be written. ", fname); keyPressed(); 347 | } 348 | 349 | void rup() { 350 | editp = adjust(prevline(prevline(editp)-1), col); 351 | } 352 | 353 | void rdn() { 354 | editp = adjust(nextline(editp), col); 355 | } 356 | 357 | void clt() { 358 | if (editbuf < editp) --editp; 359 | } 360 | 361 | void crt() { 362 | if (editp < endp) ++editp; 363 | } 364 | 365 | void wlt() { 366 | while (isspace(*(editp-1) & 0x7f) && editbuf < editp) --editp; 367 | while (!isspace(*(editp-1) & 0x7f) && editbuf < editp) --editp; 368 | } 369 | 370 | void wrt() { 371 | while (!isspace(*editp & 0x7f) && editp < endp) ++editp; 372 | while (isspace(*editp & 0x7f) && editp < endp) ++editp; 373 | } 374 | 375 | void lbeg() { 376 | editp = prevline(editp); 377 | } 378 | 379 | void lend() { 380 | editp = nextline(editp); 381 | clt(); 382 | } 383 | 384 | void pup() { 385 | int i = rows-1; 386 | while (--i > 0) { page = prevline(page-1); rup(); } 387 | } 388 | 389 | void pdn() { 390 | page = editp = prevline(epage-1); 391 | while (row-- > 0) rdn(); 392 | epage = endp; 393 | } 394 | 395 | void fbeg() { 396 | editp = editbuf; 397 | } 398 | 399 | void fend() { 400 | epage = editp = endp; 401 | } 402 | 403 | int sarins(str, len, ch) char *str; int len; char ch; { 404 | if (len < SRCH_SIZE-1) { 405 | str[len] = ch == '\r' ? '\n' : ch; 406 | str[++len] = 0; 407 | } 408 | return len; 409 | } 410 | 411 | int sardel(str, len) char *str; int len; { 412 | if (len > 0) str[--len] = 0; 413 | return len; 414 | } 415 | 416 | void sarshow(len) int len; { 417 | char *p; 418 | for (col = 0, p = prevline(editp); p < editp; p++) 419 | col += *p == '\t' ? tw - col % tw : 1; 420 | gotoxy(col+1, row+1); 421 | invvideo(); 422 | while (len--) emitchar(p++, NULL, 1); 423 | normvideo(); 424 | } 425 | 426 | void sarstr() { 427 | static char s7string[SRCH_SIZE] = ""; 428 | static char s8string[SRCH_SIZE] = ""; 429 | static char rstring[SRCH_SIZE] = ""; 430 | static int slen = 0, rlen = 0; 431 | int i, found = 0, replace = 0; 432 | char ch, *foundp = editp; 433 | do { 434 | if (replace) status(STAT_REPL, rstring); 435 | else status(STAT_SRCH, s7string); 436 | ch = (char)keyPressed() & 0x7f; 437 | if (ch == KEY_RUB || ch == KEY_BS) { 438 | if (replace) rlen = sardel(rstring, rlen); 439 | else { 440 | sardel(s8string, slen); 441 | slen = sardel(s7string, slen); 442 | } 443 | } else if (ch > 0x1f || ch == '\r' || ch == '\t') { 444 | if (replace) rlen = sarins(rstring, rlen, ch); 445 | else { 446 | sarins(s8string, slen, ch | 0x80); 447 | slen = sarins(s7string, slen, ch); 448 | } 449 | } 450 | if (slen > 0) { 451 | if (found && replace && ch == KEY_REPL) { 452 | for (i = 0; i < slen; i++) del(); 453 | for (i = 0; i < rlen; i++) ins(rstring[i]); 454 | crt(); 455 | } else if (!replace && ch == KEY_REPL) { 456 | replace = 1; 457 | } else if (ch == KEY_SRCH) { 458 | replace = 0; 459 | crt(); 460 | } 461 | while (editp < endp-1 && strncmp(editp, s8string, slen) 462 | && strncmp(editp, s7string, slen)) 463 | crt(); 464 | if (editp < endp-1) { 465 | foundp = page = editp; 466 | epage = editp+1; 467 | found = 1; lbeg(); display(); 468 | editp = foundp; 469 | sarshow(slen); 470 | } else { 471 | found = 0; fbeg(); display(); 472 | } 473 | } 474 | } while (ch != 0x1b && ch != KEY_CLT && ch != KEY_CRT && 475 | ch != KEY_RUP && ch != KEY_RDN); 476 | } 477 | 478 | void inctw() { 479 | if (++tw > 8) tw = 2; 480 | #ifdef SHL 481 | shl_tab_stop(tw); 482 | #endif 483 | } 484 | 485 | void ins(ch) char ch; { 486 | char *p; 487 | if (endp < editbuf+EDIT_SIZE-1) { 488 | if ((void*)undop < (void*)editbuf) { 489 | if (ch == '\r') { 490 | ins('\n'); 491 | if (ai) { 492 | p = editp-1; 493 | while (--p > editbuf && (*p & 0x7f) != '\n') ; 494 | while ((*++p & 0x7f) == '\t' || (*p & 0x7f) == ' ') 495 | ins(*p); 496 | } 497 | } else { 498 | if (ch == '\n') lines++; 499 | editmove(editp, editp+1, endp-editp); 500 | undop->ch = *editp = ch & 0x7f; 501 | undop->pos = editp; 502 | undop++; eds++; 503 | editp++; 504 | } 505 | } else 506 | undopfull(); 507 | } else 508 | editbfull(); 509 | } 510 | 511 | void del() { 512 | if (editp < endp) { 513 | if ((void*)undop < (void*)editbuf) { 514 | if (*editp == '\n') lines--; 515 | undop->ch = *editp | 0x80; 516 | undop->pos = editp; 517 | undop++; eds++; 518 | editmove(editp+1, editp, endp-editp); 519 | } else 520 | undopfull(); 521 | } 522 | } 523 | 524 | void rub() { 525 | if (editp > editbuf) { clt(); del(); } 526 | } 527 | 528 | void cut() { 529 | while (editp < endp && (void*)undop < (void*)editbuf 530 | && cuts < PASTE_SIZE) { 531 | pastep[cuts] = *editp; 532 | del(); 533 | if (pastep[cuts++] == '\n') break; 534 | } 535 | if ((void*)undop >= (void*)editbuf) undopfull(); 536 | if (cuts >= PASTE_SIZE) pastebfull(); 537 | } 538 | 539 | void paste() { 540 | int i = 0; 541 | while (i < cuts && endp < editbuf+EDIT_SIZE-1-cuts 542 | && (void*)undop < (void*)editbuf) 543 | ins(pastep[i++]); 544 | if ((void*)undop >= (void*)editbuf) undopfull(); 545 | if (endp >= editbuf+EDIT_SIZE-1-cuts) editbfull(); 546 | cuts = 0; 547 | } 548 | 549 | void lmvup() { 550 | if (currline() > 1) { lbeg(); cut(); rup(); paste(); rup(); } 551 | } 552 | 553 | void lmvdn() { 554 | if (currline() < lines) { lbeg(); cut(); rdn(); paste(); rup(); } 555 | } 556 | 557 | void undo() { 558 | if ((void*)undop > (void*)undobuf) { 559 | undop--; eds--; 560 | editp = undop->pos; 561 | if (undop->ch & 0x80) { 562 | editmove(editp, editp+1, endp-editp); 563 | *editp = undop->ch & 0x7f; 564 | if (*editp == '\n') lines++; 565 | } else { 566 | if (*editp == '\n') lines--; 567 | editmove(editp+1, editp, endp-editp); 568 | } 569 | } 570 | } 571 | 572 | int fread() { 573 | FILE *fp; 574 | char ch; 575 | if (fp = fopen(fname, "r")) { 576 | ch = fgetc(fp) & 0x7f; 577 | while (!feof(fp) && endp < editbuf+EDIT_SIZE) { 578 | if (ch > 0x1f || ch == '\t' || ch == '\n') { 579 | *endp++ = ch; 580 | if (ch == '\n') lines++; 581 | } 582 | ch = fgetc(fp) & 0x7f; 583 | } 584 | fclose(fp); 585 | } 586 | if (!fp || endp >= editbuf+EDIT_SIZE) 587 | return -1; 588 | else 589 | return 0; 590 | } 591 | 592 | void fsave() { 593 | FILE *fp; 594 | char ch; 595 | char *p = &editbuf; 596 | if (fp = fopen(fname, "w")) { 597 | while (p < endp) { 598 | ch = *p & 0x7f; 599 | if (ch != '\n') fputc(ch, fp); 600 | else { fputc('\r', fp); fputc('\n', fp); } 601 | p++; 602 | } 603 | fclose(fp); 604 | } else 605 | fwriterr(); 606 | undop = &undobuf; pastep = &pastebuf; cuts = 0; eds = 0; 607 | } 608 | 609 | void fquit() { 610 | if (eds) { 611 | status(STAT_ERR, "Quit without saving changes? "); 612 | if (toupper(keyPressed()) == 'Y') done = 1; 613 | } else 614 | done = 1; 615 | } 616 | 617 | void nop() { 618 | } 619 | 620 | void screen() { 621 | #ifdef SHL 622 | shl_clear(editbuf, endp); 623 | shl_highlight(editbuf, endp, endp, 0); 624 | #endif 625 | display(); 626 | } 627 | 628 | void display() { 629 | int r = 0, len = 0; 630 | char ch; 631 | hidecur(); 632 | if (editp < page) 633 | page = prevline(editp); 634 | if (epage <= editp) { 635 | page = editp; 636 | r = rows-1; 637 | while (r-- > 1) page = prevline(page-1); 638 | } 639 | epage = page; 640 | gotoxy(0, 1); 641 | while (1) { 642 | if (editp == epage) { row = r; col = outxy.X; } 643 | if (r >= rows-1 || r >= lines || epage >= endp) break; 644 | len = emitline(epage, editp); 645 | if (len) epage += len; 646 | else { ++r; ++epage; } 647 | } 648 | r = outxy.Y; 649 | while (r++ <= rows-1) { clrtoeol(); gotoxy(1, r); } 650 | status(STAT_FILE, fname); 651 | gotoxy(col+1, row+1); 652 | showcur(); 653 | } 654 | 655 | void statstr(s) char *s; { 656 | int i = 0; 657 | while (*s && i < SRCH_SIZE) { 658 | if (*s > 0x1f) { 659 | putchar(*s); i += 1; 660 | } else if (*s == '\t') { 661 | putchar('\\'); putchar('t'); i += 2; 662 | } else if (*s == '\n') { 663 | putchar('\\'); putchar('n'); i += 2; 664 | } 665 | s++; 666 | } 667 | } 668 | 669 | void status(stat, str) char *stat, *str; { 670 | long int u = 100*eds/(MAX_UNDO+MAX_UNDO/99)+1; 671 | int i; 672 | if (!eds) u = 0; 673 | invvideo(); 674 | gotoxy(1, rows); clrtoeol(); 675 | for (i = 0; i < cols; i++) putchar(' '); 676 | gotoxy(cols-30, rows); 677 | printf("U:%03d%% T:%1d C:%03d R:%05d/%05d", 678 | (int)u, tw, col+1, currline(), lines); 679 | gotoxy(2, rows); 680 | statstr(stat); statstr(str); 681 | normvideo(); 682 | } 683 | 684 | int main(argc, argv) int argc, argv[]; { 685 | int i; 686 | char ch, *p; 687 | if (argc > 1) strcpy(fname, argv[1]); else strcpy(fname, DEF_FNAME); 688 | if (argc > 2) settw(atoi(argv[2])); else settw(DEF_TW); 689 | if (argc > 3) setai(atoi(argv[3])); else setai(DEF_AI); 690 | if (argc > 4) setrows(atoi(argv[4])); else setrows(DEF_ROWS); 691 | if (argc > 5) setcols(atoi(argv[5])); else setcols(DEF_COLS); 692 | if (fread()) { 693 | fprintf(stderr, "Could not read %s", fname); 694 | return -1; 695 | } else { 696 | clrscreen(); 697 | #ifdef SHL 698 | shl = shl_language(fname); 699 | if (shl != SHL_FAIL) { 700 | shl_width(cols-1); 701 | shl_highlight(editp, endp, editp, 0); 702 | } 703 | #endif 704 | while (!done) { 705 | display(); 706 | ch = (char)keyPressed() & 0x7f; 707 | for (i = 0; key[i] != ch && key[i] != '\0'; i++) ; 708 | (*func[i])(); 709 | if (key[i] == '\0' && (ch > 0x1f || ch == '\r' || ch == '\t')) 710 | ins(ch); 711 | } 712 | clrscreen(); 713 | return 0; 714 | } 715 | } 716 |  -------------------------------------------------------------------------------- /ue/ue.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lindehaven/CP-M/3b81ed2c72c6acdb537abf102a59281b884281d3/ue/ue.com -------------------------------------------------------------------------------- /ue/ue.m2a: -------------------------------------------------------------------------------- 1 |  Micro Editor (ue) 2 |  3 | 4 |  Summary 5 |  6 | Micro Editor (UE) enables easy editing of small source code files. Source 7 | code files are limited in size to fit into the transient program area 8 | (TPA) of CP/M. 9 | 10 | NOTE! 11 | If ^S is pressed repeatedly then screen output may pause. 12 | Press ^Q once to unpause screen output. 13 | Press ^Q again to refresh the screen. 14 | 15 | 16 |  Command Line Options 17 |  18 | UE can be started with a number of optional attribute values. 19 | 20 | UE.COM [filename [tabwidth [autoindent [rows [columns]]]]] 21 | 22 | Default values for optional attributes are: 23 | 24 | - filename = $$$$$$$$.$$$ 25 | - tabwidth = 8 26 | - autoindent = 1 (on) 27 | - rows = 25 28 | - columns = 80 29 | 30 | Examples 31 | UE.COM UE.C 4 0 32 | UE.COM NARROW.ASM 2 1 25 40 33 | 34 | 35 |  Files 36 |  37 | When UE reads a file it discards all control characters except TAB (0x09) 38 | and LF (0x0a). When UE saves a file it adds a CR (0x0d) to each LF so that 39 | end of line is according to CP/M standard. Lines can be of arbitrary length 40 | but should, for the sake of reading and editing source code, be shortened 41 | to fit inside terminal screen borders. 42 | 43 | 44 |  Undo 45 |  46 | All changes are placed in the undo buffer and can be reverted by pressing 47 | ^Z (Undo last insert/delete). In case the undo buffer becomes full it needs 48 | to be emptied by pressing ^Z (Undo last insert) or ^W (Write to file). 49 | 50 | 51 |  Search & Replace 52 |  53 | A string can be searched incrementally by pressing ^L (Search string 54 | incrementally) and then typing the string to search for. If the search 55 | string is found then the cursor will move to the string in the edit buffer 56 | and display it in inverse video. If the search string is not found then the 57 | cursor will move to the beginning of the file. Pressing ^L again will 58 | search for the next occurrence of the search string. 59 | 60 | A string can be replaced by pressing ^N (Replace string) and then typing 61 | the new string. If the search string has been found then it will be 62 | possible to replace it with the new string. Pressing ^N again will replace 63 | the search string with the new string and search for the next occurrence of 64 | the search string. Pressing ^L again will search for the next occurrence of 65 | the search string without replacing it. 66 | 67 | Pressing ^[ (Escape), ^E (Cursor one row up), ^X (Cursor one row down), 68 | ^S (Cursor one column left) or ^D (Cursor one column right) exits the 69 | search/replace mode and returns to edit mode. 70 | 71 | 72 |  Syntax Highlighting 73 |  74 | To give more help for programmers, UE can be linked with the Syntax 75 | Highlighter (SHL) module to highlight source code while editing. 76 | 77 | This feature has been tested in the YAZE-AG simulator running on different 78 | hardware platforms and operating systems. Using UE with SHL on a hardware 79 | platform with a 4MHz CPU is not recommended (and not usable). 80 | 81 | In order to reduce the CPU load, the highlighting of multi-line comments is 82 | not continuously updated while typing. However, by pressing ^Q the edit 83 | buffer is parsed completely and the source code is highlighted on the screen. 84 | 85 | 86 |  Screen layout 87 |  88 | In case lines are too long to be displayed in full then the rightmost 89 | column is marked with a '+' to indicate that there are more characters 90 | beyond the right screen border. 91 | 92 | The last row of the screen is called the status row and displays: 93 | 94 | - Filename: filename 95 | - U: undo buffer usage 96 | - T: tabwidth 97 | - C: current column 98 | - R: current row / last row 99 | 100 | Example 101 | Filename: $$$$$$$$.$$$ U:000% T:8 C:009 R:00094/00463 102 | 103 | If an incremental string search is active then it is shown instead of the 104 | filename: 105 | 106 | - Search for: 107 | 108 | Example 109 | Search for: while (*p++ U:009% T:4 C:021 R:00382/00463 110 | 111 | If an incremental string replacements is active then it is shown instead 112 | of the file name: 113 | 114 | - Replace with: 115 | 116 | Example 117 | Replace with: while (*ptr++ U:009% T:4 C:021 R:00382/00463 118 | 119 | 120 |  Navigation Keys 121 |  122 | ^E Cursor one row up. 123 | ^X Cursor one row down. 124 | ^S Cursor one column left. 125 | ^D Cursor one column right. 126 | ^A Cursor one word left. 127 | ^F Cursor one word right. 128 | ^J Cursor to beginning of line. 129 | ^K Cursor to end of line. 130 | ^R Cursor one page up. 131 | ^C Cursor one page down. 132 | ^T Cursor to beginning of file. 133 | ^V Cursor to end of file. 134 | ^Q Unpause screen output and update screen. 135 | ^L Search string incrementally. Looks for search string in the 136 | edit buffer and marks it with inverse video. Wraps when 137 | reached the end of the edit buffer. 138 | 139 | 140 |  Editing Keys 141 |  142 | ^N Replace string. Replaces a search string with a new string. 143 | ^U Change tabwidth. Can be 2-8 spaces. 144 | ^I Insert tab (Tab). 145 | ^M Insert new line (Enter). 146 | ^G Delete character to the right (Delete). 147 | ^H Delete character to the left (Backspace). 148 | ^Z Undo last insert/delete. 149 | ^O Cut to end of line. Moves text to paste buffer. 150 | ^P Paste. Inserts all text from paste buffer. 151 | ^Y Move line up. 152 | ^B Move line down. 153 | 154 | 155 |  File Command Keys 156 |  157 | ^W Write to file. Saves the edit buffer to file with a carriage 158 | return '\r' and a new line '\n' as end of line. Empties the 159 | undo and paste buffers. 160 | ESC Escape. Exits the program if no changes have been made or the 161 | user does not want to save changes. 162 | 163 | 164 |  Internals 165 |  166 | - Digital Research CP/M systems 167 | - ANSI terminal 168 | - Aztec C Compiler Vers. 1.06D by Manx Software Systems 169 | - YAZE-AG 2.51.1 by Frank D. Cringle, Michael Haardt and Andreas Gerlich 170 | 171 | UE is small - less than 1000 lines of code and around 15 KB binary. 172 | 173 | UE is easy to adapt to your needs as a programmer - just edit and rebuild. 174 | 175 | - Keyboard mapping is very much a personal preference and is therefore 176 | made easy to change. 177 | - If you for some reason does not have an ANSI terminal then it should 178 | not be too difficult to adapt the source code to handle your terminal. 179 | - The sizes of the edit, undo and paste buffers are limited to fit inside 180 | a Transient Program Area (TPA) of size 62 KB. Adjust with care as the 181 | program will not run if too much memory is statically allocated. 182 | 183 | 184 |  License 185 |  186 | Public Domain 2022 (C) by Lars Lindehaven. 187 | Public Domain 2002 (C) by Terry Loveall. 188 | Public Domain 1991 by Anthony Howe. All rights released. 189 | 190 | Redistribution and use in source and binary forms, with or without 191 | modification, are permitted provided that the following conditions are 192 | met: 193 | 194 | Redistributions of source code must retain the above copyright 195 | notice, this list of conditions and the following disclaimer. 196 | 197 | Redistributions in binary form must reproduce the above copyright 198 | notice, this list of conditions and the following disclaimer in the 199 | documentation and/or other materials provided with the distribution. 200 | 201 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 202 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 203 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 204 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 205 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 206 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 207 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 208 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 209 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 210 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 211 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 212 |  213 |  -------------------------------------------------------------------------------- /ue/ue.md: -------------------------------------------------------------------------------- 1 | # Micro Editor (ue) 2 | 3 | 4 | ## Summary 5 | 6 | Micro Editor (UE) enables easy editing of small source code files. Source 7 | code files are limited in size to fit into the transient program area 8 | (TPA) of CP/M. 9 | 10 | ___NOTE!___ 11 | If ^S is pressed repeatedly then screen output may pause. 12 | Press ^Q once to unpause screen output. 13 | Press ^Q again to refresh the screen. 14 | 15 | 16 | ## Command Line Options 17 | 18 | UE can be started with a number of optional attribute values. 19 | 20 | `UE.COM [filename [tabwidth [autoindent [rows [columns]]]]]` 21 | 22 | Default values for optional attributes are: 23 | 24 | * filename = $$$$$$$$.$$$ 25 | * tabwidth = 8 26 | * autoindent = 1 (on) 27 | * rows = 25 28 | * columns = 80 29 | 30 | _Examples_ 31 | `UE.COM UE.C 4 0` 32 | `UE.COM NARROW.ASM 2 1 25 40` 33 | 34 | 35 | ## Files 36 | 37 | When UE reads a file it discards all control characters except TAB (0x09) 38 | and LF (0x0a). When UE saves a file it adds a CR (0x0d) to each LF so that 39 | end of line is according to CP/M standard. Lines can be of arbitrary length 40 | but should, for the sake of reading and editing source code, be shortened 41 | to fit inside terminal screen borders. 42 | 43 | 44 | ## Undo 45 | 46 | All changes are placed in the undo buffer and can be reverted by pressing 47 | ^Z (Undo last insert/delete). In case the undo buffer becomes full it needs 48 | to be emptied by pressing ^Z (Undo last insert) or ^W (Write to file). 49 | 50 | 51 | ## Search & Replace 52 | 53 | A string can be searched incrementally by pressing ^L (Search string 54 | incrementally) and then typing the string to search for. If the search 55 | string is found then the cursor will move to the string in the edit buffer 56 | and display it in inverse video. If the search string is not found then the 57 | cursor will move to the beginning of the file. Pressing ^L again will 58 | search for the next occurrence of the search string. 59 | 60 | A string can be replaced by pressing ^N (Replace string) and then typing 61 | the new string. If the search string has been found then it will be 62 | possible to replace it with the new string. Pressing ^N again will replace 63 | the search string with the new string and search for the next occurrence of 64 | the search string. Pressing ^L again will search for the next occurrence of 65 | the search string without replacing it. 66 | 67 | Pressing ^[ (Escape), ^E (Cursor one row up), ^X (Cursor one row down), 68 | ^S (Cursor one column left) or ^D (Cursor one column right) exits the 69 | search/replace mode and returns to edit mode. 70 | 71 | 72 | ## Syntax Highlighting 73 | 74 | To give more help for programmers, UE can be linked with the Syntax 75 | Highlighter (SHL) module to highlight source code while editing. 76 | 77 | This feature has been tested in the YAZE-AG simulator running on different 78 | hardware platforms and operating systems. Using UE with SHL on a hardware 79 | platform with a 4MHz CPU is not recommended (and not usable). 80 | 81 | In order to reduce the CPU load, the highlighting of multi-line comments is 82 | not continuously updated while typing. However, by pressing ^Q the edit 83 | buffer is parsed completely and the source code is highlighted on the screen. 84 | 85 | 86 | ## Screen layout 87 | 88 | In case lines are too long to be displayed in full then the rightmost 89 | column is marked with a '+' to indicate that there are more characters 90 | beyond the right screen border. 91 | 92 | The last row of the screen is called the status row and displays: 93 | 94 | * Filename: filename 95 | * U: undo buffer usage 96 | * T: tabwidth 97 | * C: current column 98 | * R: current row / last row 99 | 100 | _Example_ 101 | `Filename: $$$$$$$$.$$$ U:000% T:8 C:009 R:00094/00463` 102 | 103 | If an incremental string search is active then it is shown instead of the 104 | filename: 105 | 106 | * Search for: 107 | 108 | _Example_ 109 | `Search for: while (*p++ U:009% T:4 C:021 R:00382/00463` 110 | 111 | If an incremental string replacements is active then it is shown instead 112 | of the file name: 113 | 114 | * Replace with: 115 | 116 | _Example_ 117 | `Replace with: while (*ptr++ U:009% T:4 C:021 R:00382/00463` 118 | 119 | 120 | ## Navigation Keys 121 | 122 | ^E Cursor one row up. 123 | ^X Cursor one row down. 124 | ^S Cursor one column left. 125 | ^D Cursor one column right. 126 | ^A Cursor one word left. 127 | ^F Cursor one word right. 128 | ^J Cursor to beginning of line. 129 | ^K Cursor to end of line. 130 | ^R Cursor one page up. 131 | ^C Cursor one page down. 132 | ^T Cursor to beginning of file. 133 | ^V Cursor to end of file. 134 | ^Q Unpause screen output and update screen. 135 | ^L Search string incrementally. Looks for search string in the 136 | edit buffer and marks it with inverse video. Wraps when 137 | reached the end of the edit buffer. 138 | 139 | 140 | ## Editing Keys 141 | 142 | ^N Replace string. Replaces a search string with a new string. 143 | ^U Change tabwidth. Can be 2-8 spaces. 144 | ^I Insert tab (Tab). 145 | ^M Insert new line (Enter). 146 | ^G Delete character to the right (Delete). 147 | ^H Delete character to the left (Backspace). 148 | ^Z Undo last insert/delete. 149 | ^O Cut to end of line. Moves text to paste buffer. 150 | ^P Paste. Inserts all text from paste buffer. 151 | ^Y Move line up. 152 | ^B Move line down. 153 | 154 | 155 | ## File Command Keys 156 | 157 | ^W Write to file. Saves the edit buffer to file with a carriage 158 | return '\r' and a new line '\n' as end of line. Empties the 159 | undo and paste buffers. 160 | ESC Escape. Exits the program if no changes have been made or the 161 | user does not want to save changes. 162 | 163 | 164 | ## Internals 165 | 166 | * Digital Research CP/M systems 167 | * ANSI terminal 168 | * Aztec C Compiler Vers. 1.06D by Manx Software Systems 169 | * YAZE-AG 2.51.1 by Frank D. Cringle, Michael Haardt and Andreas Gerlich 170 | 171 | UE is small - less than 1000 lines of code and around 15 KB binary. 172 | 173 | UE is easy to adapt to your needs as a programmer - just edit and rebuild. 174 | 175 | * Keyboard mapping is very much a personal preference and is therefore 176 | made easy to change. 177 | * If you for some reason does not have an ANSI terminal then it should 178 | not be too difficult to adapt the source code to handle your terminal. 179 | * The sizes of the edit, undo and paste buffers are limited to fit inside 180 | a Transient Program Area (TPA) of size 62 KB. Adjust with care as the 181 | program will not run if too much memory is statically allocated. 182 | 183 | 184 | ## License 185 | _ 186 | Public Domain 2022 (C) by Lars Lindehaven. 187 | Public Domain 2002 (C) by Terry Loveall. 188 | Public Domain 1991 by Anthony Howe. All rights released. 189 | 190 | Redistribution and use in source and binary forms, with or without 191 | modification, are permitted provided that the following conditions are 192 | met: 193 | 194 | Redistributions of source code must retain the above copyright 195 | notice, this list of conditions and the following disclaimer. 196 | 197 | Redistributions in binary form must reproduce the above copyright 198 | notice, this list of conditions and the following disclaimer in the 199 | documentation and/or other materials provided with the distribution. 200 | 201 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 202 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 203 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 204 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 205 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 206 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 207 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 208 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 209 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 210 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 211 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 212 | _ 213 |  -------------------------------------------------------------------------------- /ue/ueshl.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lindehaven/CP-M/3b81ed2c72c6acdb537abf102a59281b884281d3/ue/ueshl.com -------------------------------------------------------------------------------- /ue/ueshlc.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lindehaven/CP-M/3b81ed2c72c6acdb537abf102a59281b884281d3/ue/ueshlc.com --------------------------------------------------------------------------------