├── CHANGELOG ├── MANUAL.ws ├── README.edx ├── README.md ├── configure ├── edx.c ├── edxrc.example ├── eeng.c ├── snprintf.c ├── strlcat.c ├── strlcpy.c └── ws.c /CHANGELOG: -------------------------------------------------------------------------------- 1 | 08/12/23 1.08 (OpenBSD) 2 | Add configure script to ease building on non-OpenBSD platforms. 3 | Add portable versions of snprintf, strlcat, and strlcpy. 4 | 5 | 08/11/23 1.07 (OpenBSD) 6 | Fix -d flag handling. 7 | Fix some warnings emitted by gcc-14. 8 | Remove last vestige of -DWORDSTAR. 9 | Remove last vestige of -DDOGTK. 10 | Change default tabsize to 8. 11 | 12 | 04/15/20 1.06 (OpenBSD) 13 | Add -d flag for runtime dark mode toggle. 14 | Silence some warnings emitted by clang. 15 | Add missing include to edx.c 16 | 17 | 10/25/19 1.05 (OpenBSD) 18 | Change all uses of sprintf to snprintf. 19 | Change all uses of strcat to strlcat. 20 | Change all uses of strcpy to strlcpy. 21 | Use mkstemp instead of mktemp. 22 | Remove everything else not related to the Wordstar clone. 23 | 24 | 10/23/19 1.04 25 | Update Makefile for modern GTK/glibc; fix empty default case. 26 | 27 | 12/03/04 1.03 28 | Fixed SegFault on attempt to write to read-only filesystem. 29 | Added exit query "Save, eXit or Cont?" if file modified but unsaved. 30 | 31 | 11/29/04 1.03 32 | Changed termcap console version name from mye to e. 33 | Added '\r' handling to function show_rest() in eeng.c. 34 | 35 | 10/10/04 1.03 36 | Added mouse wheel navigation. 37 | 38 | 03/11/04 1.02 39 | Fixed runaway keypress during mark block operations. 40 | 41 | 02/27/04 1.01 42 | Made 'stdin' more robust so that non-existent files don't cause 'stdin' file 43 | reading, and no 'stdin' pipe input exits gracefully. 44 | Updated mye VERSION number from 0.75 (finally!). 45 | 46 | 02/27/04 1.01 47 | added file input from 'stdin' in eeng.c for edx only if no file name given. 48 | added command line option '-b' to disable detaching from the console. 49 | 50 | 02/26/04 1.01 51 | added GTK_quit to func sys_exit in eeng.c to eliminate bogus exit msgs. 52 | 53 | 01/13/04 1.00 54 | commented out GLIBS and GINCS in Makefile to not compile with GTK 55 | 56 | 09/05/03 0.99 57 | Made xid/Gtk a compile time option by uncommenting the GLIBS and GINCS defines 58 | in Makefile. 59 | Added bash script 'fsx' which recursively searches subdirectories and then 60 | displays the results in a new instance of edx for use as a file picker. 61 | Set F5 invoked 'Command' buffer to default to "fsx ". 62 | 63 | 09/04/03 0.99 64 | Added word_marknopen which marks word under cursor and open in new window if a 65 | valid filename 66 | 67 | 08/22/03 Gtk 0.98 68 | Added tests for non-zero xid for 'fork' and display setups so that edx can 69 | run standalone or as Gtk client app. 70 | 71 | 07/11/03 Gtk 0.97 72 | Modified Xwindows structure to use Gtk toplevel window and added a Gtk socket 73 | plug option for the toplevel window in order to run inside a tabbed version 74 | of dillo for IDE purposes. 75 | 76 | 07/11/03 0.96 77 | fixed incomplete 0.95 fix with changes to new_edit (changed fn test) and 78 | dialog (added '0' parameter to call to dialogCB). 79 | 80 | 07/11/03 0.95 81 | Added file name char string to newedit() to fix failure to open named files. 82 | 83 | 07/10/03 0.94 84 | Added signal handler to kill off child zombie processes. 85 | 86 | 03/19/03 0.93 87 | Turn off mark before 'return to prev pos' 88 | 89 | 01/04/03 0.92 90 | Added ^O^W flag to enable/disable 'Word' mode searches. 91 | 92 | 12/15/02 0.91 93 | Modified 'init(' to accept grep style 'filename:linenumber' format. 94 | 95 | 07/15/02 0.88 96 | Reworked clreol and show_vbar to eliminate excessive flashing of scrollbar 97 | during use. 98 | 99 | 07/08/02 0.88 100 | Updated ws.c and emacs.c for TERMINAL mode. 101 | Smoothed show_vbar for consistent scrollbar colors. 102 | 103 | 07/07/02 0.87 104 | Enhanced 3D effect by outlining status bar and tweaking clreol to support it. 105 | 106 | 07/06/02 0.86 107 | Completed full 3D scrollbar with tweaks in clreol and show_note. Scrollbar 108 | size now 1296 bytes total. 109 | 110 | 07/04/02 0.83 111 | Added outlines and triangles to 3D scrollbar. Optimized for size. Non-3D now 112 | 676 bytes. 113 | 114 | 07/03/02 0.82 115 | Reworked and optimized scrollbar code for function, speed and size. Now behaves 116 | like a proper scrollbar, i.e. scroll 1 line up/down, 1 page up/down and track 117 | scrollbar thumb. Non 3d size is 708 bytes. 118 | Updated README to include scrollbar. 119 | Removed NOEDIT option. 120 | My thanks again to Jean-Pierre Demailly for his elegant code. 121 | 122 | 06/29/02 0.80 123 | Changed 3d effect code from DrawLine to Drawlines. 124 | 125 | 06/28/02 0.79 126 | Added THREED option for scrollbar 'thumb'. Scrollbar size now up to 872 bytes. 127 | 128 | 06/28/02 0.78 129 | Optimized scrollbar code for size and speed. Changed 'thumb' to outline. Now 130 | 644 bytes. 131 | Fixed occasional initial status bar offset by changing drawcursor to clrscr in 132 | function main in edx.c. 133 | 134 | 06/27/02 0.77 135 | Added Jean-Pierre's NODEDIT option that filters all keys except navigation 136 | keys. 137 | Added Jean-Pierre's superbly elegant vertical scrollbar code. Only 872 bytes! 138 | 139 | 06/12/02 0.76 140 | Replaced magic number sizes of 256 with 'NLEN' define in edx.c and eeng.c 141 | 142 | 06/12/02 0.75 143 | BUGFIX: changed max edit buffer input length for chgdir. 144 | 145 | 05/26/02 0.74 146 | BUGFIX: Added buffer length limits to file eeng.c, function dialog. 147 | Added "Undo buffer 90% full!" warning to file eeng.c, function new_undo. 148 | 149 | 05/21/02 0.72 150 | Following changes from Jean-Pierre. Thank you. 151 | Modified goto_x to force screen update only when left margin changes. 152 | Modified chg_case to also update text changed flag. 153 | Added show_top to end of function key_control in both ws.c and emacs.c thereby 154 | elimenating some status line visual artifacts. 155 | 156 | 05/18/02 0.71 157 | Modified eeng.c, transpose to save undo data and indicate file changed. 158 | 159 | 05/17/02 0.70 160 | BUGFIX: Changed eeng.c, file_fout. Would not save files from '/' being edited 161 | in another directory. Left temp file in '/'. 162 | Modified ws.c to unmark blocks for unshifted control keys. 163 | 164 | 05/16/02 0.69 165 | Modified eeng.c to compile either static or dynamic edbuf, bb and unbuf 166 | allocation code with #define STATICBUF. Mye.c defaults to static for 167 | compatability with Win32 compilers. 168 | 169 | 05/14/02 0.68 170 | Modified mye.c and eeng.c to use the same editor engine across the board for X 171 | and linux console. Win32 console does not compile static buffer code due to 172 | header file incompatability with 'void' pointers. Static buffer code OK. 173 | Fixed Backspace key binding. 174 | 175 | 05/10/02 0.67 176 | Modified cursor_left, cursor_right, word_left and move_to to support moving 177 | past begin/end of line, which also enabled cursor selection to track to empty 178 | lines. 179 | Modified block_fill to properly wrap at word boundaries when Fill mode enabled. 180 | 181 | 05/08/02 0.66 182 | Folded in Jean-Pierre's dynamic buffer allocation code for the block buffer, 183 | undo and main edit buffer. Smaller initial memory footprint and more stable on 184 | large undo/redo runs. 185 | 186 | 04/30/02 0.65 187 | Added new_edit, which takes both a pointer to a directory and a pointer to a 188 | file name as parameters for opening a new instance of edx. 189 | Added #define EXTHELP to specifiy opening an external text file in a new 190 | instance of edx as a response to invoking help. 191 | 192 | 04/27/02 0.64 193 | Coded ws.c function key_func F3 to open named file in a new instance of edx. 194 | Coded ws.c function key_func ^F3 to open named/empty file in current instance 195 | of edx. 196 | Coded explicit save-as into ws.c function ctrlk_key ^KF rather than implicit 197 | for a modified file. 198 | Added function newfile to invoke file open dialog for new edx instance. 199 | Modified newedit to use newbuf for file name to open. 200 | Modified functions block_format and block_fill to use autoindent code to 201 | provide left margin formatting. 202 | 203 | 04/25/02 0.64 204 | Added setting lastmk to goto_find for proper marked block operation. 205 | Tweaked function ws.c key_control for proper marked block operation. 206 | Added function find_match to search for and display matching '(,{,[,],},)'. 207 | Added code to ws.c function key_control to turn off marked blocks unless shift 208 | held down. 209 | 210 | 04/19/02 0.62 211 | BUGFIX: function dorepl(), advanced search pointer past replaced string to 212 | prevent forever loop. 213 | Added #define VERSION for single point rev. control. 214 | Added GENERIC/PERSONAL compiler #defines. 215 | Grouped #defines to aid customization. 216 | Reworked ws/emacs compiler switches and structure. 217 | Added compiler #define to select either vertical or horizontal cursor. 218 | Added compiler #define to select mouse operational characteristics. 219 | Added compiler #define to enable/disable bak file creation. 220 | Added compiler #define to enable/disable edxrc file. 221 | Merged Jean-Pierre Demailly's fixes/improvements into ver. 0.58. 222 | 223 | 04/16/02 0.60 224 | Recieved Jean-Pierre Demailly's code changes/improvements as ver. 0.60: 225 | ws/emacs key bindings. 226 | Selectable cursor color. 227 | Simplified font metrics. 228 | Added edxrc for user programmable Alt-key bindings. 229 | Additional command line options. 230 | Improved mouse selection code. 231 | Improved start up sequencing. 232 | Updated help text. 233 | Added Greek letter capability. 234 | Added goto last mark function. 235 | Improved title bar title setting code. 236 | Added transpose char code. 237 | Modified show_help to display edxrc settings. 238 | Added bak file creation. 239 | Added reset_mark function. 240 | 241 | 04/05/02 0.58 242 | BUGFIX: Initialized cur_pos in eeng.c, function file_new to prevent GPF when 243 | paste is first action performed. 244 | 245 | 04/02/02 0.56 246 | BUGFIX: Limited mouse moveto x range to positive numbers, preventing program 247 | lockup. 248 | Updated edx help screen to reflect recent changes. 249 | Added Makefile.lcc to compile 20k mye.exe binary. 250 | Use 'cl -DMSVC -Ox mye.c' on MSVC to compile a 55k mye.exe binary. 251 | 252 | 04/01/02 0.54 253 | Retrofit all edx improvements into mye. Update users manual at the beginning 254 | of mye.c. Update HELP_STR to new mye.c configuration. 255 | 256 | 03/31/02 0.52 257 | Added suspend autoindent to paste_primary from X selection. 258 | 259 | 03/29/02 0.50 260 | Added TODO file. 261 | Added autoiNdent flag and support code to key_return. 262 | Added convert marked block to UPPER/lower case. 263 | 264 | 03/28/02 0.49 265 | Updated MANUAL and README. 266 | Moved SYSTEM and cd functions from edx.c to eeng.c. 267 | Cleaned up display for lines longer than screen_width. 268 | Reworked macro recording and playback. 269 | Removed unused function show_status. 270 | Restructured status line. 271 | Improved goto last position logic. 272 | Reworked block_fill to match improved display. 273 | 274 | 03/24/02 0.48 275 | BUGFIX: removed memset write-out-of-bounds GPF in function 'drstr'. 276 | 277 | 03/24/02 0.46 278 | Improved dialog character editing. 279 | Added change directory dialog, 280 | Added xcalc and xcalendar hot keys. 281 | Added block format undo/redo. 282 | -------------------------------------------------------------------------------- /MANUAL.ws: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | edx Users Manual: 3 | 4 | Copyright (C) 2002,2003,2004, Terry Loveall, 5 | 6 | Based upon the original work ee.c of Yijun Ding, copyright 1991. His logic 7 | simplicity was elegant. Any problems are mine. 8 | 9 | The original work is source in the public domain and so is edx. I would 10 | appreciate hearing about any bug fixes or improvements. 11 | 12 | ----------------------------------------------------------------------------- 13 | Command line options 14 | 15 | Usage: edx [-fn font] [-j line#] [-t tab#] [-w width] [-h height] [-b] 16 | [-bg color] [-fg color] [-hibg color] [-hifg color] [-cur color] 17 | [-rc rcfile] [-xid XID] [file] 18 | 19 | ------------------------------------------------------------------------------ 20 | Edx doesn't have menus, but if it did, they would look something like this: 21 | 22 | File Edit Search Navigation Options Run Help 23 | -------------------------------------------------- 24 | 25 | File: 26 | ----- 27 | ^K^F save as:, open new file 28 | F2 save file and resume 29 | ^K^S save file and resume 30 | ^K^W write block to disk 31 | ^K^R insert file at cursor pos 32 | ^K^D toggle file Modified 33 | ^K^Q exit only if file saved/unmodified 34 | ^K^X exit only if file saved/unmodified 35 | 36 | Edit: 37 | ----- 38 | ^U undo 39 | Alt-U redo 40 | ^I insert tab char 41 | Tab insert tab char 42 | ^M newline 43 | ^N newline 44 | Enter newline 45 | ^P insert next char as inline literal 46 | ^B reformat from cursor to end of paragraph 47 | ^Q^L convert marked block to lower case 48 | ^Q^U convert marked block to UPPER case 49 | ^Q^T exchange two consecutive chars 50 | 51 | ^G delete cursor char 52 | Del delete cursor char 53 | BS delete prev char 54 | ^H delete prev char 55 | ^T delete word 56 | ^Y delete line 57 | ^Q^Y delete to end of line 58 | 59 | F7 toggle mark block 60 | F8 toggle mark block 61 | ^K^B toggle mark block 62 | ^K^K toggle mark block 63 | ^F1 mark cursor word 64 | 65 | ^K^Y Cut block to block buffer 66 | ^K^C Copy block to X _and_ to block buffer 67 | ^K^V Paste block buffer to cursor 68 | 69 | Shift-Del Cut block to X 70 | ^Ins Copy block to X 71 | Shift-Ins Paste from X 72 | 73 | ^K^M record macro 74 | ^K^P play macro 75 | 76 | Search: 77 | ------- 78 | ^Q^F find 79 | ^Q^A find and replace 80 | ^L find again 81 | ^J goto line 82 | ^Q^I goto line 83 | 84 | Navigation: 85 | ----------- 86 | ^A word left 87 | ^F word right 88 | ^S left 89 | ^D right 90 | ^E up 91 | ^X down 92 | ^R pgup 93 | ^C pgdn 94 | ^Z scroll up 95 | ^W scroll down 96 | up 97 | down 98 | right 99 | left 100 | PgUp 101 | PgDn 102 | ^Left word left 103 | ^Right word right 104 | Home beginning of line 105 | End end of line 106 | ^Q^S beginning of line 107 | ^Q^D end of line 108 | ^Home beginning of file 109 | ^End end of file 110 | ^Q^R beginning of file 111 | ^Q^C end of file 112 | ^Q^P goto last pos 113 | ^Q^X goto other end of marked block 114 | 115 | Options: 116 | -------- 117 | Ins toggle insert mode 118 | F12 toggle insert mode (I have a flaky Ins/F12 key, use for your own purpose) 119 | ^V toggle Insert mode 120 | ^Q^M get right margin 121 | ^K^T get tab size 122 | ^O change modes [MFOCTBNRA] 123 | ^OM toggle file Modified 124 | ^OF toggle Fill (autowrap) 125 | ^OO toggle insert/Overwrite 126 | ^OC toggle search Case 127 | ^OT toggle Tab convert 128 | ^OB toggle marked Block (DONT use, indicator only, use ^K^B) 129 | ^ON toggle autoiNdent mode 130 | ^OR toggle record Macro (DONT use, indicator only, use ^K^M) 131 | ^OA toggle replace All 132 | 133 | Run: 134 | ---- 135 | F5 get and run cmd 136 | F6 get & change to dir 137 | F10 open rxvt term 138 | ^K^Z open rxvt term 139 | ^F3 open new edx 140 | Alt-C xcalc 141 | Alt-D phone Dir 142 | Alt-L xcalendar 143 | 144 | Help: 145 | ----- 146 | F1 show help 147 | ^K^H show help 148 | ------------------------------------------------------------------------------ 149 | 150 | For input, edx uses a version of the old WordStar style control key sequences; 151 | i.e. ^k^h or ^kh, always lower case control chars. ^kc copies marked block to 152 | clipboard, right mouse pastes from clipboard. ^ky deletes marked block to 153 | block buffer, ^kv copies from from block buffer to cursor position. 154 | 155 | Basic navigation is on the left of the keyboard: 156 | 157 | Q W E R ^E ^W ^R 158 | A S D F ^S ^D ^A ^F 159 | Z X C ^X ^Z ^C 160 | 161 | ^E - up 162 | ^X - down 163 | ^D - right 164 | ^S - left 165 | 166 | ^W - scroll down 1 line 167 | ^Z - scroll up 1 line 168 | 169 | ^R - page up 170 | ^C - page down 171 | 172 | ^F - word right 173 | ^A - word left 174 | 175 | ^Q^D - goto end of line 176 | ^Q^S - goto start of line 177 | 178 | ^Q^R - goto start of file 179 | ^Q^C - goto end of file 180 | 181 | ^Q^F - find 182 | ^Q^A - find and replace 183 | 184 | Once you learn the 'magic diamond' of EXDS with ^Q extensions, function keys 185 | and mouse become irrelevant. Following are the rest of the key commands: 186 | 187 | ^B - word wrap text until the next double newline 188 | ^G - delete character under cursor 189 | ^H - delete character left of cursor 190 | ^I - insert tab char 191 | ^J - goto line 192 | ^K - prefix for file/block operations 193 | ^L - repeat last find 194 | ^M - insert newline 195 | ^N - insert newline 196 | ^O - prefix for display and change mode flags 197 | ^P - inline literal 198 | ^T - delete from cursor to start of next string 199 | ^U - undo 200 | ^V - toggle insert/overwrite mode 201 | ^Y - delete cursor line 202 | 203 | ^QI - goto line 204 | ^QL - refresh screen 205 | ^QM - get new right margin 206 | ^QY - delete from cursor to end of line 207 | 208 | ^KB - toggle mark block 209 | ^KC - copy marked block to selection 210 | ^KD - exit if file not modified 211 | ^KF - open new file 212 | ^KH - help 213 | ^KK - toggle mark block 214 | ^KM - record macro 215 | ^KP - play macro 216 | ^KQ - exit if file not modified 217 | ^KR - read a file and paste into cursor position 218 | ^KS - save and continue 219 | ^KT - get new tab size 220 | ^KV - paste block buffer into cursor position 221 | ^KW - write marked block to file 222 | ^KX - exit if file not modified 223 | ^KY - cut marked block to block buffer 224 | 225 | Under X the following function keys are operational: 226 | ---------------------------------------------------- 227 | 228 | (key) (description) (same as) 229 | ---------------------------------------------------------------------- 230 | F1 help ^KH 231 | F2 file save (if modified) ^KS 232 | F3 open new file (prompts to save if file modified) ^KF 233 | F5 prompt for and execute user command line 234 | F6 get and change directory 235 | F7 toggle mark block ^KB 236 | F8 toggle mark block ^KK 237 | F10 open an rxvt terminal in the current directory ^KZ 238 | Ins toggle insert/overwrite ^V 239 | shf-Del cut marked block to X clipboard 240 | ctl-Ins copy marked block to X clipboard 241 | shf-Ins paste from X clipboard 242 | Del delete character under cursor or marked block ^G 243 | Home move cursor to beginning of line ^QS 244 | End move cursor to end of line ^QD 245 | PgUp move up one screen ^R 246 | PgDn move down one screen ^C 247 | 248 | Navigation keys (arrows, Home, End, PgUp and PgDn) are operational. 249 | 250 | Shift navigation marks text. 251 | 252 | ^Home and ^End go to BOF and EOF, respectively. 253 | 254 | Control left arrow and right arrow move by word. 255 | 256 | Left (or right) mouse button click: set text cursor. 257 | 258 | Left (or right) mouse button double click: select word under cursor. 259 | 260 | Left (or right) mouse button click and drag: 261 | marks and copies a text block to X clipboard. 262 | 263 | Middle mouse button click: paste from X clipboard. 264 | 265 | Middle mouse button drag: marks a text block. 266 | 267 | Modes and flags: 268 | ---------------- 269 | 270 | Changing modes of operation is performed by ^o followed by one of the 271 | displayed upper/lower case characters MFOCTBA. This will toggle the specific 272 | flag. Modes are indicated as being on by displaying their upper case 273 | character. The file modified M flag can be toggled off explicitly. The block 274 | mark B active flag indicates a complex state. Toggle it off with the block 275 | mark key sequences, NOT with ^oB. 276 | 277 | M : file modified set by anything that modifies file. 278 | F : word wrap at text entry toggle with ^oF 279 | O : overwrite toggle with ^oO, ^V or function key Insert 280 | C : search is case sensitive toggle with ^oC 281 | T : expand/compress tabs toggle with ^oT 282 | B : block mark active toggle ^KB, ^KK, F7 or F8 (don't with ^oB) 283 | N : autoiNdent mode toggle with ^oN 284 | A : replace all occurences flag toggle with ^oA 285 | 286 | The editor does display tab chars as multiple spaces. Tab (0x09) chars are 287 | displayed as tabsize spaces. Default tab size is 4. To change tab-width to 8 288 | the command line is 'edx -t 8'. To change from within the editor use ^KT. 289 | 290 | To go to a specified line on initial file opening, the command line is 291 | 'edx -j 507 somefile'. Input a ^J to go to a line from within e. 292 | 293 | Turning on (F)ill mode enables wordwrap during text entry. Block reformat 294 | wraps the text at the right screen edge until a double newline is encounterd. 295 | To reformat a paragraph, place the cursor at the desired point of reformat and 296 | enter a ^b. To change the right margin use ^Q^M. 297 | 298 | As noted, undo and redo are available. ^U for undo, Alt-U for redo. A complete 299 | record of the edit session is maintained. Undoing all actions in the undo 300 | buffer will reset the Marked flag. 301 | 302 | X clipboard is integrated. 303 | 304 | ^K^C copies the marked block to the X clipboard and the right mouse button 305 | pastes from it. 306 | 307 | ^K^Y yanks the marked block from the text buffer to the block buffer. 308 | 309 | ^K^V copies the deleted block from the block buffer to the point of the text 310 | cursor. 311 | 312 | Cut, copy and paste wrt the X clipboard by Shift-Del, Control-Insert and 313 | Shift-Insert, respectively. 314 | 315 | Find and 'Search and Replace' will pick up any marked blocks, text under 316 | the cursor or user input in that order. Found text is highlighted. Set replace 317 | ALL flag wth ^oA option before running SAR to replace all occurences. 318 | 319 | For general dialog entry, if the first character entered is not ^H, ^C, End, 320 | Esc or Enter, the dialog string is discarded. End moves the cursor to the end 321 | of the dialog string (thereby recovering Bacspace'd over chars). There is 322 | no insert char mode for dialogs. 323 | 324 | For a complete understanding of the operation of edx, study the code. It is the 325 | final authority on operation. 326 | 327 | Remember, when all else fails READ THE SCREEN. 328 | ------------------------------------------------------------------------------ 329 | -------------------------------------------------------------------------------- /README.edx: -------------------------------------------------------------------------------- 1 | Edx - a small Wordstar/mini Emacs clone for the X Window system 2 | Copyright (C) 2002, Terry Loveall, email: 3 | This program is released into the public domain. 4 | 5 | THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY OR BINARIES. COMPILE AND USE 6 | AT YOUR OWN RISK. 7 | 8 | To select either wordstar or emacs key bindings, uncomment the appropriate 9 | TYPE define in Makefile. Specific key bindings for each are listed in 10 | MANUAL.ws and MANUAL.emacs. Default setting is wordstar. 11 | 12 | To build all: run 'make'. For specifics see Makefile. 13 | To generate patches use 'diff -pru ref-directory target-directory > patchfile' 14 | To patch use 'patch -p1 < patchfile' in the directory to be patched. 15 | 16 | Please send any questions, bug fixes or improvements to the above email. 17 | 18 | Edx includes code from Jean-Pierre Demailly . 19 | Thank you, Jean-Pierre, for the excellent code! See CHANGELOG for specifics. 20 | For Jean-Pierre's full-featured emacs oriented version, see: 21 | ftp://ftp.ac-grenoble.fr/ge/Office/editkit-1.00.tgz 22 | 23 | ------------------------------------------------------------------------ 24 | ASCII Text Editor to X Conversion 25 | and theory of operation 26 | 27 | The purpose of the edx.c/eeng.c package is a proof of concept for converting a 28 | 'standard' ASCII terminal based text editor to the GUI X windows. 29 | 30 | Using a text editor as a native window application enables the user to have 31 | multiple applications open simultaneously on screen. Yet the available X text 32 | editors have always left something to be desired. Usually an incomplete or 33 | hostile UI coupled with one or more of the following: written in C++ 34 | preventing easy modification, over-sized binaries which are slow to load and 35 | respond or just plain buggy code. 36 | 37 | In the interest of attempting to alleviate some, if not all, of the above 38 | complaints, the edx text editor is presented. It is composed of three files: 39 | edx.c which provides the direct interface to X windows, eeng.c, which provides 40 | a relatively simple basic text editor engine and either ws.c or emacs.c which 41 | provide the selected key bindings. 42 | 43 | Mye.c is still wordstar only. 44 | 45 | Edx is a _programming_ text editor. Real programs are written in ASCII text. 46 | If you want/need a locale sensitive editor get a word processor. 47 | 48 | GENERIC/PERSONAL Customization: 49 | 50 | There is a compile option at the beginning of edx.c for either a generic full 51 | blown version or personal configuration. 52 | 53 | The generic includes white horizontal cursor under the character with yellow 54 | chars on black background, the user programmable edxrc file for Alt-[a..z] 55 | keys, bak file creation, standard three button mouse operation and dynamic 56 | memory allocation for the edit, undo and block buffers. 57 | 58 | The personal settings are a red vertical cursor on the left of the char with 59 | black chars on a linen background, no edxrc file (explicitly coded key 60 | functions obviate the need for secondary files), no bak file littering (save 61 | frequently, save often destroys bak file effectiveness), a two button 62 | mouse strategy (left button hilites, right button pastes from clipboard on 63 | click, copies selection to clipboard on drag) and static pre-allocated edit, 64 | undo and block buffers. 65 | 66 | Different fixed fonts are commented out. Choose others as you desire. 67 | Proportional fonts are _not_ recommended. 68 | 69 | Edx.c description: 70 | 71 | The functions provided by edx.c are a generic set designed to provide all 72 | necessary functions that are not inherent to the text editor engine. 73 | 74 | Edx.c provides the basic X windows initialization code, character/mouse input, 75 | character/string output, cursor positioning, X clipboard selection and the 76 | main event driven executive loop. 77 | 78 | These are: 79 | 80 | Cursor: 81 | 82 | void gotoxy(int horz,int vert); 83 | void cursor_draw(unsigned long color); 84 | void draw_cursor(); 85 | void undraw_cursor(); 86 | 87 | Character: 88 | 89 | void drawstring(char *str, int len); 90 | void cputs(char *prntstr); 91 | int putch(char chr); 92 | void clreol(); 93 | void highvideo(); 94 | void lowvideo(); 95 | void clrscr(); 96 | 97 | Window support: 98 | 99 | void bell(); 100 | void update(); 101 | void sig_handler(int); 102 | void font_height(void); 103 | 104 | X clipboard selection 105 | 106 | int paste_primary(int win, int property, int Delete); 107 | int request_selection(int time); 108 | char *mrealloc(char *s, int len); 109 | void set_selection(); 110 | void send_selection(XSelectionRequestEvent * rq); 111 | void moveto(); 112 | void do_paste(); 113 | void do_select(int delete); 114 | 115 | App Initialization and execution: 116 | 117 | void init(int argc,char *argv[]); 118 | void handle_key(char *astr, int skey, int state); 119 | int main(int argc,char *argv[]); 120 | 121 | -------------------------- 122 | Terminal X app conversion: 123 | 124 | Converting an ASCII text editor, that runs in a terminal environment, to an 125 | event driven windowed GUI app is fairly straight forward in concept. 126 | 127 | The analysis results in a seperation of functions into window dependent and 128 | window independent. 129 | 130 | For window dependent functions, analysis produces the following 6 categories: 131 | 132 | 1. Window creation and application initialization. 133 | 2. Executive loop and function dispatch. 134 | 3. Window support. 135 | 4. Character display 136 | 5. Cursor management 137 | 6. X clipboard/selection 138 | 139 | A potential 7th category, dialogs, is not included in X for the sake of 140 | program simplicity. Dialogs are presented and controlled in the context of the 141 | ASCII status bar by the editor engine in eeng.c. 142 | 143 | 1. Window creation and application initialization: 144 | 145 | The function 'main(argc, argv)' is where window creation and initialization is 146 | controlled. The sequence is as follows: 147 | 148 | disconnect from the console 149 | 150 | call init: 151 | open the display 152 | setup to gracefully respond to exit requests from X 153 | establish window manager hints data structure 154 | setup font(s) 155 | setup window dimensions 156 | initialize clreol string to all blanks 157 | create the only window 158 | setup window hints 159 | setup window class resource names 160 | notify X on how to force the app to exit 161 | specify accepted XEvent loop events 162 | make the window real by mapping it 163 | create the Graphic Context for drawing purposes 164 | allocate required colors 165 | apply colors to window 166 | set the font 167 | 168 | App init in main() 169 | get command line options 170 | open a (possibly) named file for editing 171 | request/create WM_PROTOCOLS atom 172 | set up the signal handler response 173 | display the initial cursor 174 | 175 | 2. Executive loop and function dispatch: 176 | 177 | At the successful completion of window creation and app initialization, 178 | execution enters the main() event loop, where requested events are decoded and 179 | dispatched to the appropriate functions. 180 | 181 | The event categories decoded are as follows: 182 | 183 | Expose 184 | MotionNotify 185 | ButtonPress 186 | Button1 187 | Button2 188 | Button3 189 | ButtonRelease 190 | Button1 191 | Button2 192 | Button3 193 | KeyPress 194 | ConfigureNotify 195 | ClientMessage 196 | DestroyNotify 197 | 198 | The four event categories of concern are ButtonPress, ButtonRelease, 199 | MotionNotify and KeyPress. 200 | 201 | The button and motion events call the editor functions which: 202 | 203 | set the cursor position, 204 | select text with highlights and 205 | insert text from a buffer. 206 | 207 | KeyPress calls one of several key decoding functions that are mode specific in 208 | the text editor engine. These modes correspond to: 209 | 210 | normal editor cursor and text input, 211 | file and search string dialogs and 212 | option settings. 213 | 214 | 3. Window support: 215 | 216 | Window support amounts to only 5 functions that are broken out to improve 217 | readability. They are: 218 | 219 | bell: make noise for incorrect input. 220 | update: redraw the screen. 221 | sig_handler: handle signal events from the OS. 222 | font_height: calculate font height. 223 | 224 | 4. Character display: 225 | 226 | drawstring is the basic text output. 227 | cputs outputs an ASCIIZ string. 228 | putch just outputs one char. 229 | lowvideo sets output to normal mode. 230 | highvideo sets output to highligted mode. 231 | clreol erases from the current output position to the right edge. 232 | clrscr erases the entire window. 233 | 234 | 5. Cursor management: 235 | 236 | gotoxy positions the cursor relative to the upper left window corner. 237 | cursor_draw draws a cursor at current location in the specified color. 238 | draw_cursor draws a cursor in the foreground color. 239 | undraw_cursor draws a cursor in the background color. 240 | show_vbar draws a vertical scrollbar. 241 | scroll_text positions the text and updates the scrollbar position. 242 | 243 | 6. X clipboard/selection: 244 | 245 | mrealloc manages the buffer size for X selection 246 | paste_primary sequentially feeds chars to handle_char for pasting 247 | request_selection requests the current selection from XA_CUT_BUFFER0 if any 248 | set_selection processes and sends the marked block to XA_CUT_BUFFER0 249 | send_selection posts an event saying selection is available 250 | moveto mouse support convenience function for multiple calls 251 | do_paste paste function for both keyboard and mouse 252 | do_select also for both keyboard and mouse 253 | 254 | ------------------- 255 | Eeng.c description: 256 | 257 | Eeng.c provides window independent functions and is derived from a functional 258 | ASCII text editor in a non-windowed environment. Changes made to eeng.c amount 259 | to converting the following functions from loop form to single pass character 260 | decoding: 261 | 262 | main executive: 263 | main_exec: dispatch ASCII characters and function keys for processing. 264 | 265 | all ASCII text dialogs: 266 | file_save: file open/save/new. 267 | goto_line: request specified line number to goto. 268 | goto_col: request goto column in current line 269 | goto_search: request string to search for. 270 | goto_replace: request search string for search&replace operation. 271 | doSAR: request replace string for search&replace operation. 272 | tab_size: request new tab size. 273 | window_size: request new right margin for block reformat. 274 | block_read: request file name to insert at current position. 275 | block_write: request file name to write marked block to. 276 | 277 | select and set options: 278 | show_mode: 279 | 280 | An additional change to the text dialogs was to use a generic string input 281 | with prompt format and a callback. The callback provides specific processing 282 | of the input string. 283 | 284 | The change to a windowed environment also required replacing all terminal I/O 285 | with equivalent X functions. This code did not change, but rather was replaced 286 | by the same named X functions. These functions are comprised of the X cursor 287 | and character groups. The major source difference was specifying function and 288 | control keys from . 289 | 290 | ----------------------------- 291 | Basic eeng.c code structures: 292 | 293 | The center of the editor engine is the char* pointer 'line_start'. All 294 | operations center around it. cur_pos is calculated by 'line_start+x_offset'. 295 | Conversion from screen x co-ordinate is accomplished with 'get_tru'. Moving 296 | around within the text file always requires moving line_start and counting 297 | EOLs. 298 | 299 | Text display counts back 'y' number of lines to generate a complete screen in 300 | the function 'show_scr'. There, the left margin display offset 'lxo' is used 301 | to determine the start of each display line. lxo is primarily maintained by 302 | cursor_left and cursor_right functions. 303 | 304 | Text insertion and deletion is provided by the function 'file_resize', which, 305 | when destination address is greater than source, opens a gap for insert 306 | operations, or deletes when destination address is less than source. Undo 307 | recording basically monitors 'file_resize' plus a few special cases such as 308 | block_fill and others. 309 | 310 | Main program execution is controlled by the function 'main_exec' which is 311 | basically just a conditional state test to select the proper 'switch(key)' 312 | function from one of key_normal, key_control, ctrlk_key, ctrlq_key, func_key 313 | and key_alt. Each one of these decodes for a specific set of keys and the 314 | key state from the global key event data structure 'keve'. From there, the 315 | individual key functions are invoked. 316 | 317 | X windows just passes basic key values and keyboard state. The difference 318 | between an ASCII 'A' and a control 'A' is only in the bit indicating the 319 | control key is pressed. The bad part is the program has to decode this in 320 | order to respond reasonably. The good part is the program gets to decode this 321 | in order to respond reasonably and controls _all_ decoding. If you do not like 322 | the way edx operates you _can_ change it. 323 | 324 | Marked block operation is comprised of flag[BLK], the char pointer 'mk' and 325 | cur_pos. If flag[BLK] is set, only then can you have a marked block. 326 | 327 | File operations are basically treated as block operations, and do very 328 | conventional file I/O. 329 | 330 | External program execution: 331 | 332 | SYSTEM forks a new process to run '/bin/sh $@' 333 | gorun invokes a dialog to get a command line from the user to execute 334 | newedx invokes a new instance of edx 335 | mterm opens an rxvt terminal in the current directory 336 | 337 | For more detailed operation of the edx editor see the files 'MANUAL' and 338 | 'eeng.c'. 339 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | edx 2 | === 3 | Edx is a small Wordstar-like text editor for X11. 4 | 5 | Building 6 | -------- 7 | ```sh 8 | $ ./configure 9 | $ make 10 | $ sudo make install 11 | ``` 12 | 13 | X11 flags will be detected using 14 | [`pkg-config`](https://www.freedesktop.org/wiki/Software/pkg-config/). 15 | 16 | If you don't have `pkg-config`, X11 flags can be manually set using 17 | the `--cflags` and `--ldflags` options to `configure`. 18 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This configure script written by Brian Callahan 4 | # and released into the Public Domain. 5 | 6 | Makefile() { 7 | if [ -z "$cc" ] ; then 8 | cc=$CC 9 | fi 10 | cat << EOF > Makefile 11 | # This Makefile automatically generated by configure. 12 | 13 | CC = $cc 14 | CFLAGS = $cflags 15 | EOF 16 | 17 | if [ ! -z "$ldflags" ] ; then 18 | cat << EOF >> Makefile 19 | LDFLAGS = $ldflags 20 | EOF 21 | fi 22 | 23 | if [ ! -z "$vpath" ] ; then 24 | cat << EOF >> Makefile 25 | 26 | VPATH = $vpath 27 | EOF 28 | fi 29 | 30 | cat << EOF >> Makefile 31 | 32 | PREFIX = $prefix 33 | 34 | PROG = edx 35 | OBJS = $objs 36 | LIBS = $libs 37 | 38 | all: \${OBJS} 39 | \${CC} \${LDFLAGS} -o \${PROG} \${OBJS} \${LIBS} 40 | 41 | install: 42 | install -d \${DESTDIR}\${PREFIX}/bin 43 | install -c -m 755 \${PROG} \${DESTDIR}\${PREFIX}/bin 44 | 45 | uninstall: 46 | rm -f \${DESTDIR}\${PREFIX}/bin/\${PROG} 47 | 48 | test: 49 | echo "No tests" 50 | 51 | clean: 52 | rm -f \${PROG} \${OBJS} 53 | 54 | distclean: clean 55 | rm -f Makefile config.h \${PROG}.core 56 | EOF 57 | } 58 | 59 | c99check() { 60 | cat << EOF > conftest.c 61 | #include 62 | int main(void){for (long long i=0;i<1;i++)printf("%s",__DATE__);return 0;} 63 | EOF 64 | $cc $cflags -std=c99 -o conftest.o -c conftest.c > /dev/null 2>&1 65 | if [ $? -eq 0 ] ; then 66 | rm -f conftest conftest.o conftest.c 67 | return 0 68 | else 69 | rm -f conftest conftest.o conftest.c 70 | return 1 71 | fi 72 | } 73 | 74 | cccheck() { 75 | cat << EOF > conftest.c 76 | int main(void){return 0;} 77 | EOF 78 | $CC -o conftest.o -c conftest.c > /dev/null 2>&1 79 | $CC $ldflags -o conftest conftest.o > /dev/null 2>&1 80 | if [ $? -eq 0 ] ; then 81 | ./conftest 82 | if [ $? -eq 0 ] ; then 83 | rm -f conftest conftest.o conftest.c 84 | cc="$CC" 85 | return 0 86 | else 87 | echo "could not build working executables" 88 | echo "Please ensure your C compiler is a native compiler" 89 | exit 1 90 | fi 91 | else 92 | rm -f conftest conftest.o conftest.c 93 | fi 94 | 95 | for compiler in cc clang pcc tcc xlc lacc cparser ccomp kefir gcc ; do 96 | cat << EOF > conftest.c 97 | int main(void){return 0;} 98 | EOF 99 | 100 | $compiler -o conftest.o -c conftest.c > /dev/null 2>&1 101 | $compiler $ldflags -o conftest conftest.o > /dev/null 2>&1 102 | 103 | if [ $? -eq 0 ] ; then 104 | ./conftest 105 | if [ $? -eq 0 ] ; then 106 | rm -f conftest conftest.o conftest.c 107 | cc="$compiler" 108 | return 0 109 | else 110 | echo "could not build working executables" 111 | echo "Please ensure your C compiler is a native compiler" 112 | exit 1 113 | fi 114 | else 115 | rm -f conftest conftest.o conftest.c 116 | fi 117 | done 118 | return 1 119 | } 120 | 121 | defaultcflagscheck() { 122 | cat << EOF > conftest.c 123 | int main(void){return 0;} 124 | EOF 125 | $cc $defaultcflags -o conftest.o -c conftest.c > /dev/null 2>&1 126 | if [ $? -eq 0 ] ; then 127 | rm -f conftest conftest.o conftest.c 128 | return 1 129 | else 130 | rm -f conftest conftest.o conftest.c 131 | return 0 132 | fi 133 | } 134 | 135 | defaultgflagcheck() { 136 | cat << EOF > conftest.c 137 | int main(void){return 0;} 138 | EOF 139 | $cc $cflags -g -o conftest.o -c conftest.c > /dev/null 2>&1 140 | if [ $? -eq 0 ] ; then 141 | rm -f conftest conftest.o conftest.c 142 | return 1 143 | else 144 | rm -f conftest conftest.o conftest.c 145 | return 0 146 | fi 147 | } 148 | 149 | defaultpipeflagcheck() { 150 | cat << EOF > conftest.c 151 | int main(void){return 0;} 152 | EOF 153 | $cc $cflags -pipe -o conftest.o -c conftest.c > /dev/null 2>&1 154 | if [ $? -eq 0 ] ; then 155 | rm -f conftest conftest.o conftest.c 156 | return 1 157 | else 158 | rm -f conftest conftest.o conftest.c 159 | return 0 160 | fi 161 | } 162 | 163 | gnu99check() { 164 | cat << EOF > conftest.c 165 | #include 166 | int main(void){for (long long i=0;i<1;i++)printf("%s",__DATE__);return 0;} 167 | EOF 168 | $cc $cflags -std=gnu99 -o conftest.o -c conftest.c > /dev/null 2>&1 169 | if [ $? -eq 0 ] ; then 170 | rm -f conftest conftest.o conftest.c 171 | return 0 172 | else 173 | rm -f conftest conftest.o conftest.c 174 | return 1 175 | fi 176 | } 177 | 178 | noc99check() { 179 | cat << EOF > conftest.c 180 | #include 181 | int main(void){for (long long i=0;i<1;i++)printf("%s",__DATE__);return 0;} 182 | EOF 183 | $cc $cflags -o conftest.o -c conftest.c > /dev/null 2>&1 184 | if [ $? -eq 0 ] ; then 185 | rm -f conftest conftest.o conftest.c 186 | return 0 187 | else 188 | rm -f conftest conftest.o conftest.c 189 | return 1 190 | fi 191 | } 192 | 193 | pledgecheck() { 194 | cat << EOF > conftest.c 195 | #include 196 | int main(void){pledge(NULL,NULL);return 0;} 197 | EOF 198 | $cc $cflags -o conftest.o -c conftest.c > /dev/null 2>&1 199 | $cc $ldflags -o conftest conftest.o > /dev/null 2>&1 200 | if [ $? -eq 0 ] ; then 201 | rm -f conftest conftest.o conftest.c 202 | return 0 203 | else 204 | rm -f conftest conftest.o conftest.c 205 | return 1 206 | fi 207 | } 208 | 209 | snprintfcheck() { 210 | cat << EOF > conftest.c 211 | #include 212 | int main(void){snprintf(NULL,0,NULL);return 0;} 213 | EOF 214 | $cc $cflags -o conftest.o -c conftest.c > /dev/null 2>&1 215 | $cc $ldflags -o conftest conftest.o > /dev/null 2>&1 216 | if [ $? -eq 0 ] ; then 217 | rm -f conftest conftest.o conftest.c 218 | return 0 219 | else 220 | rm -f conftest conftest.o conftest.c 221 | return 1 222 | fi 223 | } 224 | 225 | strlcatcheck() { 226 | cat << EOF > conftest.c 227 | #include 228 | int main(void){strlcat(NULL,NULL,0);return 0;} 229 | EOF 230 | $cc $cflags -o conftest.o -c conftest.c > /dev/null 2>&1 231 | $cc $ldflags -o conftest conftest.o > /dev/null 2>&1 232 | if [ $? -eq 0 ] ; then 233 | rm -f conftest conftest.o conftest.c 234 | return 0 235 | else 236 | rm -f conftest conftest.o conftest.c 237 | return 1 238 | fi 239 | } 240 | 241 | strlcpycheck() { 242 | cat << EOF > conftest.c 243 | #include 244 | int main(void){strlcpy(NULL,NULL,0);return 0;} 245 | EOF 246 | $cc $cflags -o conftest.o -c conftest.c > /dev/null 2>&1 247 | $cc $ldflags -o conftest conftest.o > /dev/null 2>&1 248 | if [ $? -eq 0 ] ; then 249 | rm -f conftest conftest.o conftest.c 250 | return 0 251 | else 252 | rm -f conftest conftest.o conftest.c 253 | return 1 254 | fi 255 | } 256 | 257 | x11check() { 258 | command -v pkg-config > /dev/null 2>&1 259 | if [ $? -eq 0 ] ; then 260 | pkg-config --exists x11 261 | if [ $? -eq 0 ] ; then 262 | cflags="$cflags $(pkg-config --cflags x11)" 263 | libs="$libs $(pkg-config --libs x11)" 264 | return 0 265 | else 266 | return 1 267 | fi 268 | else 269 | return 1 270 | fi 271 | } 272 | 273 | # Option variables 274 | if [ ! -z "$PREFIX" ] ; then 275 | prefix="$PREFIX" 276 | else 277 | prefix="/usr/local" 278 | fi 279 | 280 | defaultcflags="-O2" 281 | objs="edx.o" 282 | static=0 283 | cross=0 284 | 285 | os=$(uname -s) 286 | if [ "x$os" = "xSunOS" ] ; then 287 | cpu=$(isainfo -k) 288 | else 289 | cpu=$(uname -m) 290 | fi 291 | 292 | # Options 293 | for opt 294 | do 295 | case "$opt" in 296 | --prefix=*) 297 | prefix=${opt#*=} 298 | ;; 299 | --cc=*) 300 | CC=${opt#*=} 301 | ;; 302 | --cflags=*) 303 | CFLAGS=${opt#*=} 304 | ;; 305 | --ldflags=*) 306 | LDFLAGS=${opt#*=} 307 | ;; 308 | --disable-static|--enable-static) 309 | if [ "x$opt" = "x--enable-static" ] ; then 310 | static=1 311 | else 312 | static=0 313 | fi 314 | ;; 315 | --optimize-size) 316 | defaultcflags="-Oz" 317 | ;; 318 | --optimize-speed) 319 | defaultcflags="-Ofast" 320 | ;; 321 | --help|-h) 322 | echo "Usage: configure [options]" 323 | echo "" 324 | echo "Options:" 325 | printf " --help or -h " 326 | echo "Display this help message" 327 | printf " --prefix=PREFIX " 328 | echo "Top level install directory is PREFIX [$prefix]" 329 | printf " --cc=CC " 330 | echo "Use specified C compiler [default=cc]" 331 | printf " --cflags=CFLAGS " 332 | echo "Use specified CFLAGS [default=$defaultcflags]" 333 | printf " --ldflags=LDFLAGS " 334 | echo "Use specified LDFLAGS [default=\"\"]" 335 | printf " --enable-static " 336 | echo "Statically link executables [default=no]" 337 | printf " --optimize-size " 338 | echo "Aggressively optimize for size [default=no]" 339 | printf " --optimize-speed " 340 | echo "Aggressively optimize for speed [default=no]" 341 | exit 1 342 | ;; 343 | *) 344 | ;; 345 | esac 346 | done 347 | 348 | if [ ! -z "$CFLAGS" ] ; then 349 | cflags="$CFLAGS" 350 | else 351 | cflags="" 352 | fi 353 | 354 | if [ ! -z "$LDFLAGS" ] ; then 355 | ldflags="$LDFLAGS " 356 | else 357 | ldflags="" 358 | fi 359 | 360 | if [ $static -ne 0 ] ; then 361 | ldflags="$ldflags -static" 362 | fi 363 | 364 | if [ $cross -eq 1 ] ; then 365 | if [ -z "$CC" ] ; then 366 | echo "error: must specify a C compiler when cross compiling" 367 | exit 1 368 | fi 369 | fi 370 | 371 | printf "checking for C compiler... " 372 | if [ $cross -eq 1 ] ; then 373 | echo "cross compilation detected" 374 | echo "warning: disabling toolchain checks because of cross compilation" 375 | else 376 | cccheck 377 | if [ $? -ne 0 ] ; then 378 | echo "not found" 379 | echo "Please install a C compiler and re-run configure." 380 | exit 1 381 | else 382 | echo "$cc" 383 | fi 384 | fi 385 | 386 | if [ "x$cc" = "xvc" ] ; then 387 | if [ $cross -eq 0 ] ; then 388 | echo "using vbcc, setting CFLAGS to -g -O=990" 389 | cflags="-g -O=990" 390 | fi 391 | fi 392 | 393 | if [ "x$cflags" = "x" ] ; then 394 | printf "checking whether the compiler accepts %s... " $defaultcflags 395 | defaultcflagscheck 396 | if [ $? -eq 0 ] ; then 397 | echo "no" 398 | if [ "x$defaultcflags" = "x-Oz" ] ; then 399 | defaultcflags="-Os" 400 | printf "checking whether the compiler accepts %s... " $defaultcflags 401 | defaultcflagscheck 402 | if [ $? -eq 0 ] ; then 403 | echo "no" 404 | else 405 | cflags="$cflags $defaultcflags" 406 | echo "yes" 407 | fi 408 | fi 409 | if [ "x$defaultcflags" = "x-Ofast" ] ; then 410 | defaultcflags="-O3" 411 | printf "checking whether the compiler accepts %s... " $defaultcflags 412 | defaultcflagscheck 413 | if [ $? -eq 0 ] ; then 414 | echo "no" 415 | else 416 | cflags="$cflags $defaultcflags" 417 | echo "yes" 418 | fi 419 | fi 420 | else 421 | cflags="$cflag $defaultcflags" 422 | echo "yes" 423 | fi 424 | fi 425 | 426 | printf "checking whether the compiler accepts -pipe... " 427 | defaultpipeflagcheck 428 | if [ $? -eq 0 ] ; then 429 | echo "no" 430 | else 431 | cflags="$cflags -pipe" 432 | echo "yes" 433 | fi 434 | 435 | printf "checking whether the compiler accepts -g... " 436 | defaultgflagcheck 437 | if [ $? -eq 0 ] ; then 438 | echo "no" 439 | else 440 | cflags="$cflags -g" 441 | echo "yes" 442 | fi 443 | 444 | printf "checking for %s option to enable C99 features... " $cc 445 | noc99check 446 | if [ $? -ne 0 ] ; then 447 | gnu99check 448 | if [ $? -ne 0 ] ; then 449 | c99check 450 | if [ $? -ne 0 ] ; then 451 | echo "cannot compile C99" 452 | echo "You must have a C99 compiler to build pc!" 453 | exit 1 454 | else 455 | cflags="$cflags -std=c99" 456 | echo "-std=c99" 457 | fi 458 | else 459 | cflags="$cflags -std=gnu99" 460 | echo "-std=gnu99" 461 | fi 462 | else 463 | echo "none needed" 464 | fi 465 | 466 | printf "checking for X11... " 467 | x11check 468 | if [ $? -eq 0 ] ; then 469 | echo "yes" 470 | else 471 | echo "no" 472 | echo "warning: could not find X11" 473 | echo "You will need to manually set this with --cflags and --ldflags" 474 | fi 475 | 476 | if [ $cross -eq 0 ] ; then 477 | printf "checking for pledge... " 478 | pledgecheck 479 | if [ $? -eq 0 ] ; then 480 | cflags="$cflags -DHAVE_PLEDGE" 481 | echo "yes" 482 | else 483 | echo "no" 484 | fi 485 | fi 486 | 487 | if [ $cross -eq 0 ] ; then 488 | printf "checking for snprintf... " 489 | snprintfcheck 490 | if [ $? -eq 0 ] ; then 491 | echo "yes" 492 | else 493 | objs="$objs snprintf.o" 494 | echo "no" 495 | fi 496 | fi 497 | 498 | if [ $cross -eq 0 ] ; then 499 | printf "checking for strlcat... " 500 | strlcatcheck 501 | if [ $? -eq 0 ] ; then 502 | echo "yes" 503 | else 504 | objs="$objs strlcat.o" 505 | echo "no" 506 | fi 507 | fi 508 | 509 | if [ $cross -eq 0 ] ; then 510 | printf "checking for strlcpy... " 511 | strlcpycheck 512 | if [ $? -eq 0 ] ; then 513 | echo "yes" 514 | else 515 | objs="$objs strlcpy.o" 516 | echo "no" 517 | fi 518 | fi 519 | 520 | printf "checking for out-of-tree build... " 521 | if [ "x$(dirname $0)" = "x." ] ; then 522 | echo "no" 523 | elif [ "x$(dirname $0)" = "x$(pwd)" ] ; then 524 | echo "no" 525 | else 526 | vpath="$(dirname $0)" 527 | cflags="$cflags -I$(pwd)" 528 | echo "yes" 529 | fi 530 | 531 | if [ ! -z "$cflags" ] ; then 532 | cflags=$(echo "$cflags" | xargs) 533 | fi 534 | 535 | if [ ! -z "$ldflags" ] ; then 536 | ldflags=$(echo "$ldflags" | xargs) 537 | fi 538 | 539 | if [ ! -z "$libs" ] ; then 540 | libs=$(echo "$libs" | xargs) 541 | fi 542 | 543 | printf "creating Makefile... " 544 | Makefile 545 | echo "done" 546 | -------------------------------------------------------------------------------- /edx.c: -------------------------------------------------------------------------------- 1 | #define VERSION "1.07 (OpenBSD)" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #define XK_MISCELLANY 19 | #include 20 | #include 21 | 22 | #define DEFAULT_WIDTH 80 23 | #define DEFAULT_HEIGHT 25 24 | 25 | //#define GENERIC 26 | #ifndef GENERIC 27 | 28 | //the following defines are for personal settings 29 | // EXTHELP for external help file ~/MANUAL.ws 30 | //#define EXTHELP 31 | // VERTCURS for a vertical cursor 32 | #define VERTCURS 33 | // TWOBUTN paste with button3 click, set selection with button3 drag 34 | #define TWOBUTN 35 | // MINIMAL remove /usr/share/edx and edxrc 36 | #define MINIMAL 37 | // NOBAK remove bak files. 38 | #define NOBAK 39 | // STATICBUF forces edbuf, bb and unbuf to static fixed location/sizes. 40 | //#define STATICBUF 41 | // THREED gives the scrollbar 'thumb' depth 42 | #define THREED 43 | 44 | // DARK is for the hacker in you 45 | //#define DARK 46 | #ifdef DARK 47 | 48 | // yellow char on black, white cursor, black on grey high-lights 49 | char *FgColor="Yellow", *BgColor="Black", *CrColor="White", *HiFgColor="Black", *HiBgColor="Grey75"; 50 | 51 | // bold font for yellon on black with no cursor artifacts 52 | #define FONTNAME "-b&h-lucidatypewriter-medium-r-normal-sans-12-*-*-*-m-70-iso8859-1" 53 | 54 | #else 55 | 56 | // black char on linen, red cursor, black on grey high-lights 57 | char *FgColor="Black", *BgColor="Linen", *CrColor="Red", *HiFgColor="Black", *HiBgColor="Grey75"; 58 | int dark; 59 | 60 | // medium font for black on linen best presentation 61 | #define FONTNAME "-b&h-lucidatypewriter-medium-r-normal-sans-12-*-*-*-m-70-iso8859-1" 62 | #endif /* DARK */ 63 | 64 | /* turns on display of keypressed event values in upper right corner */ 65 | //#define DEBUG 66 | 67 | #else 68 | 69 | /* screen color defines */ 70 | //char *FgColor="Black", *BgColor="Linen", *CrColor="Red", *HiFgColor="Black", *HiBgColor="Grey75"; 71 | char *FgColor="Yellow", *BgColor="Black", *CrColor="White", *HiFgColor="Black", *HiBgColor="Grey75"; 72 | 73 | //#define FONTNAME "-b&h-lucidatypewriter-medium-r-normal-sans-12-*-*-*-m-70-iso8859-1" 74 | #define FONTNAME "-b&h-lucidatypewriter-bold-r-normal-sans-12-*-*-*-m-70-iso8859-1" 75 | //#define FONTNAME "8x13" 76 | //#define FONTNAME "9x15bold" 77 | 78 | #endif /* GENERIC */ 79 | 80 | #define AMAX 0xD0000 /* main buffer size */ 81 | #define BMAX 0x10000 /* block size */ 82 | #define YTOP 0 /* first line */ 83 | 84 | #define EOL '\0' /* end of line marker */ 85 | #define BLNK ' ' /* blank */ 86 | #define LF '\n' /* new line */ 87 | #define NLEN 256 /* input buffer length */ 88 | #define XINC 20 /* increment for x offset */ 89 | 90 | #define CHG 0 /* file Modified: =0 file not changed, !=0 file changed */ 91 | #define FIL 1 /* Fill */ 92 | #define OVR 2 /* character insert=0, Overwrite=1 */ 93 | #define CAS 3 /* Case sensitive: =0 no, !=0 yes */ 94 | #define TAB 4 /* Tab expand */ 95 | #define BLK 5 /* block mark active */ 96 | 97 | #define IND 6 /* auto indent flag */ 98 | #define REC 7 /* recording macro flag */ 99 | #define ALL 8 /* replace all flag */ 100 | #define WRD 9 /* find wdelims delimited word */ 101 | #define SHW 10 /* update & show entire screen */ 102 | #define NEW 11 /* editing a new file */ 103 | #define WIN 12 /* window: <0 same win, =0 load new */ 104 | 105 | /************************************************************/ 106 | 107 | /* use MS style COORD to track cursor pos */ 108 | typedef struct { 109 | int X; /* x coordinate */ 110 | int Y; /* y coordinate */ 111 | } COORD; /* x-y structure */ 112 | 113 | COORD outxy; /* cursor coordinates for screen positioning */ 114 | 115 | /************************************************************/ 116 | 117 | /* character handler types */ 118 | static enum { 119 | MAIN, 120 | DIALOG, 121 | OPTIONS 122 | } executive = MAIN; /* default character handler */ 123 | 124 | /* X related globals */ 125 | Display *dpy; 126 | Window win; 127 | GC gc; 128 | XFontStruct *font; 129 | XEvent event; 130 | XKeyEvent *keve; 131 | Time eve_time; 132 | char *selection_text; /* selected text for X clipboard */ 133 | int selection_length; 134 | int do_background = -1; 135 | 136 | int Width, Height; 137 | int fwidth, fheight; /* font character width, height */ 138 | 139 | /* Foreground, Background normal and highlight colores */ 140 | XColor FgXColor, BgXColor, CrXColor, HiFgXColor, HiBgXColor; 141 | 142 | int HiLo; /* hightlight status, 0=off */ 143 | Atom DeleteWindow; /* Atom of delete window message */ 144 | 145 | char *FontName=NULL; 146 | char *DisplayName=NULL; 147 | char *AppName; 148 | char *RcFile = NULL; 149 | 150 | char Command[NLEN] = "fsx "; 151 | char *cfdpath; 152 | 153 | char *Geometry=NULL; 154 | /* maximum viewable 6x8 chars on a 2000x1600 screen */ 155 | #define MAXVLINE 2048 156 | char eolbuf[MAXVLINE]; /* holds spaces for clreol(), 450 is 2000x1600 */ 157 | 158 | /* func prototypes */ 159 | 160 | void gotoxy(int horz,int vert); 161 | void cursor_draw(unsigned long color); 162 | void draw_cursor(); 163 | void undraw_cursor(); 164 | void drawstring(char *str, int len); 165 | void cputs(char *prntstr); 166 | int putch(char chr); 167 | void clreol(); 168 | void highvideo(); 169 | void lowvideo(); 170 | void clrscr(); 171 | void bell(); 172 | void update(); 173 | void show_vbar(); 174 | void scroll_text(); 175 | void child_sig_handler(int signal); 176 | void sig_handler(int); 177 | void font_height(void); 178 | int paste_primary(int win, int property, int Delete); 179 | int request_selection(int time); 180 | char *mrealloc(char *s, int len); 181 | void set_selection(); 182 | void send_selection(XSelectionRequestEvent * rq); 183 | void init(int argc,char *argv[]); 184 | void handle_key(char *astr, int skey, int state); 185 | void moveto(); 186 | void do_paste(); 187 | void do_select(int delete); 188 | int main(int argc,char *argv[]); 189 | 190 | /* for monolithic whole include edit engine here */ 191 | 192 | #define EDIT "edx" 193 | #ifndef MINIMAL 194 | #define SHARE_DIR "/etc" 195 | #define DEFAULT_RC "edxrc" 196 | #endif /* MINIMAL */ 197 | 198 | #include "ws.c" 199 | 200 | /******************** Start of cursor I/O ********************/ 201 | 202 | /* Goto the specified location. */ 203 | 204 | void gotoxy(int horz,int vert) 205 | { 206 | outxy.X = horz; 207 | outxy.Y = vert; 208 | } 209 | 210 | void cursor_draw(unsigned long color) 211 | { 212 | XSetForeground(dpy, gc, color); 213 | #ifndef VERTCURS 214 | XFillRectangle(dpy, win, gc, 215 | (outxy.X * fwidth) + 2, ((outxy.Y+1)* fheight) + 2, fwidth-1, 2); 216 | #else 217 | XDrawRectangle(dpy, win, gc, 218 | (outxy.X * fwidth) + 2, (outxy.Y * fheight) + 2, 0, fheight); 219 | #endif /* VERTCURS */ 220 | XSetForeground(dpy, gc, HiLo ? HiFgXColor.pixel : FgXColor.pixel); 221 | } 222 | 223 | void draw_cursor() 224 | { 225 | cursor_draw( CrXColor.pixel); 226 | } 227 | 228 | void undraw_cursor() 229 | { 230 | cursor_draw( HiLo ? HiBgXColor.pixel : BgXColor.pixel); 231 | } 232 | 233 | void drawstring(char *str, int len) 234 | { 235 | if (outxy.X+len>screen_width+1) len = screen_width+1-outxy.X; 236 | XDrawImageString(dpy, win, gc, (outxy.X * fwidth) + 2, (outxy.Y+1) * fheight, str, len > 0 ? len : 0); 237 | } 238 | 239 | int putch(char chr) 240 | { 241 | static char str[]="\0\0"; 242 | 243 | if(!(chr) || ((chr & 0xff) == LF)){ 244 | clreol(); 245 | outxy.X = 0; 246 | outxy.Y += 1; 247 | } else { 248 | str[0] = chr; 249 | drawstring(str, 1); 250 | outxy.X += 1; 251 | } 252 | 253 | return 0; 254 | } 255 | 256 | void cputs(char *prntstr) 257 | { 258 | int strl = strlen(prntstr); 259 | 260 | drawstring(prntstr, strl); 261 | outxy.X += strl; 262 | } 263 | 264 | /* Erase from cursor to end of line. */ 265 | 266 | void clreol() 267 | { 268 | int tmpx = outxy.X; 269 | int eollen = abs(screen_width+1 - tmpx); 270 | outxy.X = outxy.X <= screen_width ? outxy.X : screen_width; 271 | #ifdef THREED 272 | drawstring(eolbuf, eollen+1); 273 | #else 274 | drawstring(eolbuf, eollen); 275 | #endif /* THREED */ 276 | outxy.X = tmpx; 277 | } 278 | 279 | /* display string if visible, bump X */ 280 | 281 | void highvideo() 282 | { 283 | XSetBackground(dpy,gc,HiBgXColor.pixel); 284 | XSetForeground(dpy,gc,HiFgXColor.pixel); 285 | HiLo = -1; 286 | } 287 | 288 | void lowvideo() 289 | { 290 | XSetBackground(dpy,gc,BgXColor.pixel); 291 | XSetForeground(dpy,gc,FgXColor.pixel); 292 | HiLo = 0; 293 | } 294 | 295 | void clrscr() 296 | { 297 | XClearWindow(dpy,win); 298 | } 299 | 300 | void bell() 301 | { 302 | XBell(dpy,100); 303 | } 304 | 305 | void update() 306 | { 307 | flag[SHW] = 1; 308 | show_top(); 309 | scr_update(); 310 | } 311 | 312 | int vtot, vcur, pos, ftheight; 313 | 314 | void show_vbar() 315 | { 316 | int j; 317 | 318 | // display buffer screen height in pixels 319 | vtot = (screen_height-2)*fheight; 320 | 321 | // font true height as a constant 322 | ftheight = fheight+font->descent+1; 323 | 324 | // thumb height is display buffer percentage of total lines 325 | vcur = (vtot*(screen_height-1))/((ytot)?ytot:1); 326 | 327 | // min thumb size is 1 char 328 | if (vcurj) vcur = j; 333 | 334 | // current line number to vertical thumb pos 335 | pos = (ytru*(vtot-(vcur-fheight)))/((ytot)?ytot:1); 336 | 337 | // draw scrollbar trough 338 | XSetForeground(dpy,gc,HiBgXColor.pixel); 339 | #ifdef THREED // provide background for line scroll triangles 340 | XFillRectangle(dpy, win, gc, Width-11, 0, 11, Height); 341 | #else // indicate line scroll rectangles 342 | XFillRectangle(dpy, win, gc, Width-11, ftheight, 11, Height+2-2*(ftheight)); 343 | #endif /* THREED */ 344 | 345 | // draw thumb 346 | if (dark) 347 | XSetForeground(dpy,gc,~HiFgXColor.pixel); 348 | else 349 | XSetForeground(dpy,gc,FgXColor.pixel); 350 | XDrawRectangle(dpy, win, gc, Width-10, ftheight+pos, 9, vcur); 351 | 352 | #ifdef THREED 353 | { 354 | XPoint opoints[] ={{Width-11,Height},{0,-Height}, 355 | {-(Width-11),0},{0,ftheight-1}, 356 | {Width,0}, // draw boxes 357 | {-5,-10},{-5,10},{0,Height+2-(2*(ftheight))}, 358 | {5,10},{5,-10},{-11,0} // draw triangles 359 | }; 360 | XSegment lpoints[] ={{Width-1, ftheight+pos, Width-10, ftheight+pos}, 361 | {Width-10, ftheight+pos, Width-10, ftheight+pos+vcur-1}, 362 | {Width-10, ftheight-2, Width-5, ftheight-11}, 363 | {Width-9, Height+2-ftheight, Width-6, Height+3-ftheight+6} 364 | }; 365 | 366 | // outline trough and end triangles 367 | XDrawLines(dpy, win, gc, opoints, 11,CoordModePrevious); 368 | 369 | // draw in light color for 3D shading 370 | if (dark) 371 | XSetForeground(dpy,gc,BgXColor.pixel); 372 | else 373 | XSetForeground(dpy,gc,BgXColor.pixel); 374 | XDrawSegments(dpy, win, gc, lpoints, 4); 375 | } 376 | #endif /* THREED */ 377 | lowvideo(); 378 | } 379 | 380 | void scroll_text(int ycur) 381 | { 382 | int m, newy; 383 | 384 | m = ycur - ftheight; 385 | newy = (m*ytot)/vtot; 386 | 387 | if(m<0) scroll_down(); // if cursor at top of screen 388 | else if(m>vtot+ftheight) scroll_up(); // if cursor at bottom of screen 389 | else if(mpos+vcur) cursor_pagedown(); // if cursor below thumb 391 | else goto_y(newy); // else cursor on thumb so track it 392 | 393 | scr_update(); // does show_vbar 394 | } 395 | 396 | void child_sig_handler(int signal) 397 | { 398 | if (signal == SIGCHLD) wait(NULL); 399 | } 400 | 401 | void sig_handler(int nothing) 402 | { 403 | update(); 404 | XFlush(dpy); 405 | } 406 | 407 | int paste_primary(int win, int property, int Delete) 408 | { 409 | Atom actual_type; 410 | int actual_format, i; 411 | long nitem, bytes_after, nread; 412 | unsigned char *data; 413 | char indent = flag[IND]; /* stash autoindent state */ 414 | 415 | if (property == None) /* don't paste nothing */ 416 | return(0); 417 | 418 | flag[IND] = 0; /* off autoindent */ 419 | nread = 0; 420 | /* X-selection paste loop */ 421 | do { 422 | if (XGetWindowProperty /* get remaining selection max 1024 chars */ 423 | (dpy, win, property, nread / 4, 1024, Delete, 424 | AnyPropertyType, &actual_type, &actual_format, &nitem, 425 | &bytes_after, (unsigned char **) &data) 426 | != Success) 427 | return(0); 428 | update_scr = 0; /* dont update scr...yet */ 429 | /* paste last batch one char at a time */ 430 | for(i = 0; i < nitem; handle_key(NULL, data[i++],0)); 431 | nread += nitem; 432 | XFree(data); 433 | } while (bytes_after > 0); 434 | update_scr = 1; /* _now_ update display */ 435 | flag[SHW] = 1; 436 | scr_update(); 437 | flag[IND] = indent; /* restore autoindent state */ 438 | return(nread); 439 | } 440 | 441 | int request_selection(int time) 442 | { 443 | Window w; 444 | Atom property; 445 | 446 | if ((w = XGetSelectionOwner(dpy, XA_PRIMARY)) == None) { 447 | int tmp = paste_primary(DefaultRootWindow(dpy), XA_CUT_BUFFER0, False); 448 | return(tmp); 449 | } 450 | property = XInternAtom(dpy, "VT_SELECTION", False); 451 | XConvertSelection(dpy, XA_PRIMARY, XA_STRING, property, win, time); 452 | return(0); 453 | } 454 | 455 | char *mrealloc(char *s, int len) 456 | { 457 | char *ttt; 458 | if(!s) ttt = (char *) malloc(len); 459 | else ttt = (char *) realloc(s, len); 460 | return ttt; 461 | } 462 | 463 | void set_selection() 464 | { 465 | int i; 466 | 467 | if(!flag[BLK] || mk == cur_pos) return; 468 | 469 | if(cur_pos < mk) 470 | { bstart = cur_pos; bend = mk; } 471 | else 472 | { bstart = mk; bend = cur_pos; } 473 | 474 | selection_length = bend - bstart; 475 | if ((selection_text = (char *) mrealloc(selection_text, selection_length)) == NULL) { 476 | printf("realloc.\n"); 477 | se_exit: 478 | bell(); 479 | return; 480 | } 481 | for (i = 0; i < selection_length; i++) { 482 | selection_text[i] = bstart[i] == EOL ? '\n' : bstart[i]; 483 | } 484 | XSetSelectionOwner(dpy, XA_PRIMARY, win, (Time) eve_time); 485 | if (XGetSelectionOwner(dpy, XA_PRIMARY) != win) { 486 | printf("Cant select.\n"); 487 | goto se_exit; 488 | } 489 | XChangeProperty(dpy, DefaultRootWindow(dpy), XA_CUT_BUFFER0, 490 | XA_STRING, 8, PropModeReplace, selection_text, 491 | selection_length); 492 | } 493 | 494 | void send_selection(XSelectionRequestEvent * rq) 495 | { 496 | XSelectionEvent notify; 497 | 498 | notify.type = SelectionNotify; 499 | notify.display = rq->display; 500 | notify.requestor = rq->requestor; 501 | notify.selection = rq->selection; 502 | notify.target = rq->target; 503 | notify.time = rq->time; 504 | XChangeProperty(dpy, rq->requestor, rq->property, XA_STRING, 8, 505 | PropModeReplace, selection_text, selection_length); 506 | notify.property = rq->property; 507 | XSendEvent(dpy, rq->requestor, False, 0, (XEvent *) & notify); 508 | } 509 | 510 | #ifndef MINIMAL 511 | void parse_rc(FILE *f) 512 | { 513 | char buf[512], *ptr; 514 | int i, l; 515 | while ((ptr=fgets(buf, 510, f))) { 516 | if (*ptr == '#' || isspace(*ptr)) continue; 517 | i = (int)*(ptr++) - (int)'a'; 518 | if (*ptr==':' && i>=0 && i<26) { 519 | ++ptr; 520 | while(isspace(*ptr)) ++ptr; 521 | l = strlen(ptr)-1; 522 | if (l>=0 && ptr[l]=='\n') ptr[l] = '\0'; 523 | if (binding[i]) free(binding[i]); 524 | binding[i] = strdup(ptr); 525 | } 526 | } 527 | } 528 | 529 | void read_rc() 530 | { 531 | FILE *fr = NULL; 532 | char name[NLEN], *ptr; 533 | 534 | if ((ptr=getenv("HOME")) || RcFile) { 535 | if (RcFile) { 536 | if (ptr && *RcFile == '~' && RcFile[1] == '/') 537 | snprintf(name, sizeof name, "%s/%s", ptr, RcFile+2); 538 | else 539 | strlcpy(name, RcFile, sizeof name); 540 | } 541 | else 542 | snprintf(name, sizeof name, "%s/.%s", ptr, DEFAULT_RC); 543 | } else { 544 | snprintf(name, sizeof name, "%s/%s", SHARE_DIR, DEFAULT_RC); 545 | } 546 | fr = fopen(name, "r"); 547 | if (fr) { 548 | parse_rc(fr); 549 | fclose(fr); 550 | } 551 | } 552 | #endif /* MINIMAL */ 553 | 554 | void init(int argc,char *argv[]) 555 | { 556 | int screen; 557 | XWMHints *wmh; 558 | XSizeHints *xsh; 559 | XClassHint *classh; 560 | XColor tmp; 561 | int i, x = 1, y = 0; 562 | 563 | /* Default settings */ 564 | memset((void *)binding, 0, 26*sizeof(char *)); 565 | *ewin.name = '\0'; 566 | #ifndef STATICBUF 567 | amax = AMAX; 568 | bmax = BMAX; 569 | umax = UMAX; 570 | #endif /* STATICBUF */ 571 | 572 | /* engine screen width, height, font */ 573 | screen_height = DEFAULT_HEIGHT - 1; 574 | screen_width = DEFAULT_WIDTH; 575 | 576 | /* get command line options */ 577 | for (i=1; iascent + font->descent; 663 | Height = fheight * screen_height + font->descent+3; 664 | 665 | /* font width */ 666 | fwidth = XTextWidth(font,"8",1); 667 | 668 | Width = (fwidth * screen_width)+13; 669 | xsh->flags = PSize; 670 | xsh->width = Width; 671 | xsh->height = Height; 672 | 673 | /* initialize clreol string to all blanks */ 674 | memset(eolbuf, ' ', sizeof(eolbuf)); 675 | 676 | /* create the only window */ 677 | win=XCreateSimpleWindow(dpy,RootWindow(dpy,screen),x,y,Width,Height,0, 678 | BlackPixel(dpy,screen),WhitePixel(dpy,screen)); 679 | 680 | /* setup window hints */ 681 | wmh->initial_state=NormalState; 682 | wmh->input=True; 683 | wmh->window_group = win; 684 | wmh->flags = StateHint | InputHint | WindowGroupHint; 685 | 686 | /* setup window class resource names */ 687 | classh->res_name = (AppName==NULL)?"edx":AppName; 688 | classh->res_class = "Xedit"; 689 | 690 | /* name that window */ 691 | XmbSetWMProperties(dpy, win, "edx", "edx", argv, argc, 692 | xsh, wmh, classh); 693 | 694 | /* setup to gracefully respond to exit requests from X */ 695 | DeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False); 696 | XSetWMProtocols(dpy, win, &DeleteWindow, 1); 697 | 698 | /* specify accepted XEvent loop events */ 699 | XSelectInput(dpy, win, 700 | KeyPressMask|\ 701 | FocusChangeMask|\ 702 | StructureNotifyMask|\ 703 | ButtonPressMask|\ 704 | ButtonReleaseMask|\ 705 | ExposureMask|\ 706 | PropertyChangeMask|\ 707 | Button1MotionMask|\ 708 | Button2MotionMask|\ 709 | Button3MotionMask|\ 710 | VisibilityChangeMask 711 | ); 712 | keve = (XKeyEvent *)&event; 713 | 714 | /* create the Graphic Context for drawing purposes */ 715 | gc=XCreateGC(dpy,win,0,NULL); 716 | 717 | /* allocate required colors */ 718 | XAllocNamedColor(dpy,DefaultColormap(dpy,screen),FgColor,&FgXColor,&tmp); 719 | XAllocNamedColor(dpy,DefaultColormap(dpy,screen),BgColor,&BgXColor,&tmp); 720 | XAllocNamedColor(dpy,DefaultColormap(dpy,screen),CrColor,&CrXColor,&tmp); 721 | XAllocNamedColor(dpy,DefaultColormap(dpy,screen),HiFgColor,&HiFgXColor,&tmp); 722 | XAllocNamedColor(dpy,DefaultColormap(dpy,screen),HiBgColor,&HiBgXColor,&tmp); 723 | 724 | /* apply colors to window */ 725 | XSetForeground(dpy,gc,FgXColor.pixel); 726 | XSetWindowBackground(dpy,win,BgXColor.pixel); 727 | 728 | /* set the font */ 729 | XSetFont(dpy,gc,font->fid); 730 | 731 | /* map the window real */ 732 | XMapWindow(dpy, win); 733 | } 734 | 735 | void handle_key(char *astr, int skey, int state) 736 | { 737 | char chstr[NLEN]; 738 | int x=outxy.X, y=outxy.Y, n=0; 739 | 740 | /* display keyboard shift/control/alt status */ 741 | highvideo(); 742 | gotoxy(0,y01); 743 | for(n=5;n;chstr[n--]=' '); 744 | if(state & ShiftMask) chstr[n++] = 'S'; 745 | if(state & Mod1Mask) chstr[n++] = 'A'; 746 | if(skey & 0xff00) chstr[n++] = 'F'; 747 | if(state & ControlMask) chstr[n++] = '^'; 748 | chstr[n] = skey & 0xff; 749 | chstr[5] = '\0'; 750 | cputs(chstr); 751 | chstr[0] = '\0'; 752 | 753 | #ifdef DEBUG 754 | /* display raw key event data */ 755 | snprintf(chstr, sizeof chstr, "k=%4x,s=%2x.",skey,state); 756 | #endif /* DEBUG */ 757 | gotoxy(screen_width - 12,0); 758 | clreol(); 759 | cputs(chstr); 760 | gotoxy(x,y); 761 | show_vbar(); 762 | 763 | if((skey >= 0xffe1) && (skey <= 0xffee)) return; 764 | if(skey == NoSymbol) return; 765 | 766 | switch(executive) { 767 | case MAIN: 768 | main_exec(skey); 769 | break; 770 | case DIALOG: 771 | dialog(skey); 772 | break; 773 | case OPTIONS: 774 | options(skey); 775 | break; 776 | } 777 | } 778 | 779 | void moveto() 780 | { 781 | move_to(((event.xbutton.x < 0 ? 0 : event.xbutton.x)/fwidth) + 1 + xlo, 782 | ((event.xbutton.y-3)/fheight) - 1); 783 | } 784 | 785 | void do_select(int delete) 786 | { 787 | if(flag[BLK] && mk != cur_pos) { 788 | set_selection(); 789 | block_copy(delete); 790 | } 791 | mark_off(); 792 | } 793 | 794 | void do_paste() 795 | { 796 | if(flag[BLK] && executive == MAIN) block_remove_update(); 797 | request_selection(event.xbutton.time); 798 | } 799 | 800 | int main(int argc,char *argv[]) 801 | { 802 | Atom WM_PROTOCOLS = 0; 803 | struct sigaction sig; 804 | struct sigaction act; 805 | int y0 = 0, y01 = 0, yf, yt; 806 | 807 | init(argc,argv); 808 | #ifndef MINIMAL 809 | read_rc(); 810 | #endif /* MINIMAL */ 811 | 812 | /* disconnect from the console */ 813 | if(do_background) 814 | {switch (fork()) { case 0: case -1: break; default: exit(0); }} 815 | 816 | /* set path */ 817 | if (cfdpath == NULL) { 818 | cfdpath = (char *) malloc(BUFSIZ); 819 | getcwd(cfdpath, BUFSIZ); 820 | if (strcmp(cfdpath, "/") != 0) 821 | strlcat(cfdpath, "/", BUFSIZ); 822 | } 823 | 824 | usleep(10000); 825 | XFlush(dpy); 826 | do_open(); 827 | 828 | /* end of edit engine init */ 829 | 830 | /* request/create WM_PROTOCOLS atom */ 831 | WM_PROTOCOLS = XInternAtom(dpy, "WM_PROTOCOLS", False); 832 | 833 | // kill off zombie child processes 834 | act.sa_handler = child_sig_handler; 835 | act.sa_flags = 0; 836 | sigaction(SIGCHLD, &act, NULL); 837 | 838 | /* set up the signal handler response */ 839 | sig.sa_handler=sig_handler; 840 | sigemptyset(&sig.sa_mask); 841 | sig.sa_flags=SA_RESTART; 842 | sigaction(SIGALRM,&sig,NULL); 843 | 844 | clrscr(); 845 | 846 | #define DBLCLICK 500 847 | 848 | /* main event loop, dispatch function calls in response to events */ 849 | for(;;) { 850 | static Time button_release_time; 851 | static int buttonpressed = 0; 852 | 853 | XNextEvent(dpy,&event); 854 | 855 | switch(event.type) { 856 | case Expose: 857 | while(XCheckTypedEvent(dpy,Expose,&event)); 858 | update(); 859 | break; 860 | case MotionNotify: 861 | if (buttonpressed==-1) { 862 | if (executive == MAIN) 863 | scroll_text(event.xbutton.y); 864 | break; 865 | } 866 | if(buttonpressed) { 867 | if(!flag[BLK]) block_mark(); 868 | undraw_cursor(); 869 | if (event.xbutton.y < fheight+2) { 870 | moveto(); 871 | cur_pos = get_cur(); 872 | scroll_down(); 873 | scr_update(); 874 | } else if (event.xbutton.y >= Height-6-font->descent) { 875 | moveto(); 876 | cur_pos = get_cur(); 877 | scroll_up(); 878 | scr_update(); 879 | } else { 880 | moveto(); 881 | yf = y0; 882 | if (yyt) yt = y; 886 | if (y01>yt) yt = y01; 887 | show_scr(yf, yt); 888 | moveto(); 889 | cur_pos = get_cur(); 890 | gotoxy(x-1,y+1); 891 | draw_cursor(); 892 | y01 = y; 893 | } 894 | } 895 | break; 896 | case ButtonPress: 897 | if((event.xbutton.button == Button5) || 898 | (event.xbutton.button == Button4)) 899 | break; /* ignore mouse wheel */ 900 | if (event.xbutton.x>=Width-10) { 901 | buttonpressed = -1; 902 | if (executive == MAIN) 903 | scroll_text(event.xbutton.y); 904 | break; 905 | } 906 | buttonpressed = event.xbutton.button; 907 | if (event.xbutton.time - eve_time < DBLCLICK) break; 908 | eve_time = event.xbutton.time; 909 | if(event.xbutton.button == Button1) mark_off(); /* unmark */ 910 | if(!mk){ 911 | moveto(); 912 | y0 = y; 913 | cur_pos = get_cur(); 914 | block_mark(); /* start new mark */ 915 | flag[SHW] = 1; 916 | scr_update(); 917 | } 918 | break; 919 | case ButtonRelease: 920 | if (buttonpressed==-1) { 921 | buttonpressed = 0; 922 | break; 923 | } 924 | buttonpressed = 0; 925 | switch (event.xbutton.button) { 926 | #ifdef TWOBUTN 927 | case Button5: 928 | if (executive == MAIN) scroll_up(); 929 | goto scrupdt; 930 | case Button4: 931 | if (executive == MAIN) scroll_down(); 932 | goto scrupdt; 933 | case Button1: 934 | if (event.xbutton.time - button_release_time < DBLCLICK) { 935 | mark_off(); word_marknopen(); scr_update(); 936 | break; 937 | } 938 | else 939 | { 940 | button_release_time = event.xbutton.time; 941 | if(mk == cur_pos) mark_off(); 942 | goto setcursor; 943 | } 944 | break; 945 | case Button3: 946 | if ((event.xbutton.time - eve_time < DBLCLICK) && 947 | (event.xbutton.time - eve_time)) { 948 | do_paste(); 949 | break; 950 | } 951 | else 952 | { 953 | button_release_time = event.xbutton.time; 954 | set_selection(); 955 | mark_off(); /* unmark */ 956 | } 957 | goto setcursor; 958 | #else 959 | case Button1: 960 | case Button3: 961 | if (event.xbutton.time - button_release_time < DBLCLICK) { 962 | mark_off(); cursor_right(); word_left(); block_mark(); /* set mark to left end of word */ 963 | word_right(); scr_update(); /* set mark to right end of word */ 964 | break; 965 | } 966 | else 967 | { 968 | button_release_time = event.xbutton.time; 969 | set_selection(); 970 | goto setcursor; 971 | } 972 | break; 973 | #endif /* TWOBUTN */ 974 | case Button2: 975 | if ((event.xbutton.time - eve_time < DBLCLICK) && 976 | (event.xbutton.time - eve_time)) { 977 | do_paste(); 978 | } 979 | goto setcursor; 980 | } 981 | break; 982 | setcursor: 983 | moveto(); 984 | scrupdt: 985 | flag[SHW] = 1; 986 | cur_pos = get_cur(); 987 | scr_update(); 988 | break; 989 | case KeyPress:{ 990 | int count; 991 | char astr[10]; 992 | KeySym skey; 993 | { int i = 128; while(XCheckTypedEvent(dpy,KeyPress,&event) && i--);} 994 | eve_time = keve->time; 995 | astr[0] = 0; 996 | count = XLookupString(keve, astr, 997 | sizeof (astr), &skey, NULL); 998 | astr[count] = 0; 999 | handle_key(astr, skey, keve->state); 1000 | } 1001 | break; 1002 | case SelectionClear: 1003 | break; 1004 | case SelectionRequest: 1005 | send_selection((XSelectionRequestEvent *) & 1006 | event); 1007 | break; 1008 | case SelectionNotify: 1009 | paste_primary(event.xselection.requestor, 1010 | event.xselection.property, True); 1011 | break; 1012 | case ConfigureNotify: 1013 | Width = event.xconfigure.width; 1014 | screen_width = (Width-16)/fwidth; 1015 | Height = event.xconfigure.height; 1016 | screen_height = (Height/fheight) -1 ; 1017 | update(); 1018 | break; 1019 | case ClientMessage: 1020 | if(event.xclient.message_type == WM_PROTOCOLS) { 1021 | if(event.xclient.data.l[0] == DeleteWindow) { 1022 | sys_exit(0); 1023 | }; 1024 | }; 1025 | break; 1026 | case DestroyNotify: 1027 | XCloseDisplay(dpy); 1028 | exit(0); 1029 | default: 1030 | break; 1031 | }; 1032 | }; 1033 | } 1034 | -------------------------------------------------------------------------------- /edxrc.example: -------------------------------------------------------------------------------- 1 | # Key bindings for edx 2 | # All keys 'a' to 'z' (lower case) can be bound. 3 | # There are two string arguments %s %s, respectively 4 | # - the current working directory 5 | # - the name of the file being edited 6 | # 7 | d: xdiary & 8 | e: DIR=%s; ROOTNAME=`echo %s | cut -d"." -f 1`; edx $DIR/$ROOTNAME.log & 9 | l: latex %s/%s & 10 | p: xenscript %s/%s & 11 | t: tex %s/%s & 12 | v: DIR=%s; ROOTNAME=`echo %s | cut -d"." -f 1`; xdvi -s 6 $DIR/$ROOTNAME.dvi & 13 | z: cd %s; rxvt -font 8x13 -pr green -cr red -sl 500 -sr +st -geometry 80x30 & 14 | -------------------------------------------------------------------------------- /eeng.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | edx (EDitor for X), (C) 2003, Terry Loveall 4 | released into the public domain. 5 | Based upon the original work ee.c of Yijun Ding, copyright 1991 which is 6 | in the public domain. 7 | This program comes with no warranties or binaries. Use at your own risk. 8 | */ 9 | 10 | #define VOID_LINK (unsigned int)-1 11 | 12 | #ifdef GREEK 13 | /* Greek letters */ 14 | static char *greek_letter[26] = { 15 | "alpha", "!beta", "Chi", "Delta", "!epsilon", "!Phi", 16 | "Gamma", "eta", "iota", "Psi", "kappa", "Lambda", "mu", "nu", 17 | "omega", "Pi", "!Theta", "!rho", "!Sigma", "tau", "Upsilon", NULL, 18 | "Omega", "Xi", "Psi", "zeta" 19 | }; 20 | int var_greek = 0; /* variant of Greek letters */ 21 | #endif 22 | 23 | int x=0, screen_width; /* screen position 1 <= x <= screen_width */ 24 | int y=1, screen_height; /* screen size 0 <= y <= screen_height */ 25 | int eolx; /* coord of eol */ 26 | int update_scr = 1; /* do screen updates flag */ 27 | int first_time = 1; /* first time flag for stdin use */ 28 | 29 | char *bstart, *bend; /* marked block start, end and char pointer */ 30 | char *binding[26]; 31 | 32 | #define YTOP 0 /* first line */ 33 | 34 | char bbuf[NLEN]; /* temp file name */ 35 | char sbuf[NLEN], rbuf[NLEN]; /* search buffer, replace buffer */ 36 | char *s; /* pointer to search string */ 37 | int rlen, slen; /* replace and search lengths */ 38 | 39 | unsigned blen; /* length of text in block buffer */ 40 | char *cur_pos; 41 | char *line_start; /* current pos, start of current line */ 42 | char *screen_start; /* global screen start */ 43 | unsigned int xlo; /* x offset for left display edge */ 44 | char *last_pos; /* last last position visited */ 45 | char *old_pos; /* last position visited */ 46 | 47 | int x_offset; /* offset of xtru from line_start */ 48 | int xtru = 0, ytru = 0; /* file position */ 49 | int ytot = 0; /* 0 <= ytru <= ytot */ 50 | 51 | int y01, y2; /* 1st, 2nd line of window */ 52 | int tabsize=8; /* tab size */ 53 | int doCtrlC = 0; /* decode next char from ^C function */ 54 | int doCtrlK = 0; /* decode next char from ^K function */ 55 | int doCtrlQ = 0; /* decode next char from ^Q function */ 56 | int doCtrlX = 0; /* decode next char from ^X function */ 57 | int doEscap = 0; /* decode next char from Esc function */ 58 | int help_done = 0; 59 | int literal = 0; 60 | 61 | int col; /* width of dialog preset (if any) */ 62 | int diastart; /* start of dialog input field */ 63 | int first; /* first dialog char flag, 0=true */ 64 | int dblen; /* current dialog buffer size */ 65 | char *diabuf; /* dialog buffer pointer */ 66 | void (*dialogCB) (); /* callback pointer */ 67 | 68 | static char lbuf[16]; /* goto line number buffer */ 69 | static char cbuf[16]; /* goto column number buffer */ 70 | static char wbuf[8]="78"; /* reformat block right margin */ 71 | static char twbuf[8]="4"; /* tab width buffer */ 72 | 73 | static char mbuf[NLEN]; /* macro record buffer */ 74 | static char *pmbuf=mbuf; /* record pointer for macro buffer */ 75 | struct stat ofstat; /* edit file stat structure */ 76 | 77 | FILE *fi, *fb; /* file handles for input, block */ 78 | static int fo; /* file handle for output */ 79 | static char fbuf[NLEN]; /* current file name buffer */ 80 | #ifndef TERMINAL 81 | static char newbuf[NLEN]; /* new file name buffer */ 82 | #endif /* TERMINAL */ 83 | 84 | char flag[WIN+1]="\0\0\0C\0\0N\0\0"; /* options flag presets */ 85 | char fsym[]="MFOCTBNRAW"; /* Modified,Fill,Overwrite,Case,Tab,Block marked,autoiNdent,Rec,All,Word */ 86 | 87 | /* word delimiter chars */ 88 | char wdelims[] = "\t ,;+*=^&|?:`()[]{}<>\"\'"; 89 | char mdelims[] = "\t ,;+-*=^&|?`()[]{}<>\"\'"; 90 | char sdelims[] = "\t >]})"; 91 | char s1delims[] = "\t "; 92 | 93 | /* current window struct */ 94 | typedef struct { 95 | char name[NLEN]; 96 | int jump; 97 | } MWIN; /* my window structure */ 98 | 99 | MWIN ewin; /* current window */ 100 | 101 | char *file_end; /* end of file */ 102 | char *mk; /* mark */ 103 | char *last_mk = NULL; /* prev mk position */ 104 | 105 | #ifdef STATICBUF 106 | /* static buffer allocation scheme */ 107 | char bb[BMAX]; /* block buffer */ 108 | char edbuf[AMAX]; /* edit buffer */ 109 | char unbuf[AMAX]; /* undo stack */ 110 | 111 | /* undo record struct */ 112 | typedef struct { 113 | void *link; 114 | char *pos; 115 | int length; 116 | char str[1]; 117 | } U_REC; 118 | 119 | #else 120 | 121 | /* dynamic buffer allocation scheme */ 122 | #define UMAX 0x2000 /* undo level */ 123 | unsigned int amax, bmax, umax; /* main buffer, block size, undo level */ 124 | char *bb; /* block buffer */ 125 | char *edbuf; /* edit buffer */ 126 | void *unbuf; /* undo stack */ 127 | 128 | /* undo record struct */ 129 | typedef struct { 130 | unsigned int link; 131 | int pos; 132 | int length; 133 | char str[0]; 134 | } U_REC; 135 | #endif /* STATICBUF */ 136 | 137 | int undo_wrap = 0; /* undo buffer wrap flag */ 138 | U_REC* undop; /* active undo/redo pointer */ 139 | U_REC* undosp; /* top of undo stack pointer */ 140 | int in_undo; /* dont reset undop to undosp if true */ 141 | int undone=1; /* have undone all */ 142 | 143 | /* function prototypes */ 144 | 145 | int get_tru(char* pos); 146 | char* get_cur(); 147 | void init_undo(); 148 | U_REC* new_undo(char *pos, int len); 149 | void u_del(char *pos, int len); 150 | void u_ins(char *pos, int len); 151 | void ytot_ins(); 152 | void undo(); 153 | void redo(); 154 | void sys_exit(int code); 155 | void bell(); 156 | void move_to(int newx, int newy); 157 | void getx(); 158 | void cursor_up(), cursor_down(), cursor_left(), cursor_right(); 159 | void cursor_pageup(); 160 | void cursor_pagedown(); 161 | void word_left(); 162 | void word_right(); 163 | void word_mark(); 164 | void word_marknopen(); 165 | void drstr(char* disp, int i); 166 | void show_rest(int len, char *s); 167 | void show_scr(int fr, int to); 168 | void scroll_up(); 169 | void scroll_down(); 170 | void show_sdn(int line); 171 | void show_flag(int x, int g); 172 | void dialog(int key); 173 | void show_note(char *prp); 174 | int show_gets(char *prp, char *buf, int blen, void *cb); 175 | void options(int key); 176 | void show_pos(); 177 | void show_top(), show_help(), show_mode(); 178 | void top(); 179 | char *file_new(); 180 | void file_read(); 181 | char *file_ltab(char *s); 182 | int file_write(int fd, char *s, char *e); 183 | int file_fout(); 184 | void do_save(); 185 | #ifndef TERMINAL 186 | void set_title(); 187 | int SYSTEM (char *cmd); 188 | void gorun(); 189 | void new_edit(char *path, char *fn); 190 | void newedit(char *fn); 191 | void mterm(); 192 | #endif /* TERMINAL */ 193 | void do_cd(); 194 | void chgdir(); 195 | void do_open(); 196 | void file_save(int f_all, int f_win); 197 | void newfile(); 198 | void file_resize(char *s, char *d); 199 | void goto_x(int xx), goto_y(int yy); 200 | void goto_ptr(char *s); 201 | void goline(); 202 | void goto_last(); 203 | void goto_line(), goto_col(); 204 | void gocol(); 205 | void goto_col(); 206 | void twist_pos(); 207 | int str_cmp(char *s); 208 | void gofind(); 209 | char *goto_find(char *s, int back); 210 | void get_mk(char* dbuf); 211 | char *goto_search(int back); 212 | void dorepl(); 213 | void doSAR(); 214 | void goto_replace(int all); 215 | void gettab(); 216 | void tab_size(); 217 | void getmarg(); 218 | void window_size(); 219 | void mark_off(); 220 | void block_put(), block_get(), block_mark(); 221 | void remove_block(); 222 | void block_remove_update(); 223 | void chg_case(int upper); 224 | void transpose(); 225 | void block_copy(int delete); 226 | void block_paste(), block_write(), block_line(); 227 | void doblockr(); 228 | void doblockw(); 229 | void block_read(); 230 | int block_fill(); 231 | void find_match(); 232 | void block_format(); 233 | void key_return(), key_deleol(char *s), key_delete(); 234 | void key_backspace(), key_delword(int eol); 235 | void key_tab(int tabi); 236 | void key_normal(int key); 237 | void key_macros(int record); 238 | #ifdef GREEK 239 | void l(int key); 240 | #endif 241 | void ctrlc_key(int key); 242 | void ctrlk_key(int key); 243 | void ctrlq_key(int key); 244 | void key_control(int key); 245 | #ifdef TERMINAL 246 | void main_meta(int key); 247 | #else 248 | void key_alt(int key); 249 | void key_escape(int key); 250 | void key_func(int key); 251 | #endif /* TERMINAL */ 252 | void scr_update(); 253 | void main_exec(int key); 254 | 255 | /* code */ 256 | 257 | /* 258 | void prrec(U_REC* undp, char indicator) 259 | { 260 | char str[NLEN]; 261 | 262 | if(undp == NULL) return; 263 | 264 | memset(str,0,NLEN); 265 | memcpy(str, undp->str, undp->length >= 0 ? undp->length: 0 - undp->length); 266 | printf("%c:p=%x, l=%x, pos=%x, ln=%x, str=%s.\n", 267 | indicator, 268 | (unsigned int)undp, 269 | (unsigned int)undp->link + unbuf, 270 | (unsigned int)(undp->pos + edbuf), 271 | undp->length, 272 | str); 273 | } 274 | */ 275 | 276 | /* get true x co-ord for char at 'pos' */ 277 | int get_tru(char* pos) 278 | { 279 | char* tmpp; 280 | int i = 1; 281 | 282 | tmpp = line_start + strlen(line_start+1)+1; 283 | if(line_start > pos || tmpp < pos) { 284 | #ifdef DEBUG 285 | printf("Pos=%x, ls=%x, le=%x.\n", 286 | (unsigned int)pos, 287 | (unsigned int)line_start, 288 | (unsigned int)tmpp); 289 | #else 290 | printf("get_tru\n"); 291 | bell(); 292 | #endif /* DEBUG */ 293 | return 0; 294 | } 295 | for(tmpp = line_start+1; tmpp < pos; tmpp++){ 296 | if(*tmpp != '\t') {i++;} 297 | else { 298 | i = i + ((tabsize) - ((i-1)%tabsize)); 299 | } 300 | } 301 | return(i); 302 | } 303 | 304 | char* get_cur() 305 | { 306 | return(line_start+x_offset); 307 | } 308 | 309 | #ifdef STATICBUF 310 | 311 | void init_undo() 312 | { 313 | undosp = undop = (void*)&unbuf; 314 | undop->link = NULL; 315 | undop->pos = cur_pos - 1; 316 | undop->length = 0; 317 | } 318 | 319 | static char ub[2] = ""; 320 | 321 | U_REC* new_undo(char *pos, int len) 322 | { 323 | U_REC *tmp; 324 | int tlen = abs(undosp->length); 325 | 326 | /* wrap undo pointer if no space for requested len in undo buffer */ 327 | tmp = (char*) &undosp->str[tlen] + sizeof(U_REC) + len < (char*) &unbuf + AMAX 328 | ? (char*)&undosp->str[tlen] 329 | : (void*)&unbuf; 330 | tmp->link = undosp; 331 | tmp->pos = pos; 332 | tmp->length = 0; 333 | if(flag[CHG] && ((char*)tmp->link > 334 | (char*)&unbuf + (AMAX - (AMAX / 10)))){ 335 | bell(); 336 | show_gets("Undo buffer 90\% full! ", (char*)ub, 1, show_pos); 337 | } 338 | return tmp; 339 | } 340 | 341 | void u_del(char *pos, int len) 342 | { 343 | if(!undosp) init_undo(); 344 | 345 | if(!undosp->length) undosp->pos = pos; 346 | /* get new_undo if top rec is u_ins, or different pos or no space */ 347 | else if((undosp->length > 0) || 348 | ( (void*)&undosp->pos[0 - undosp->length] != pos ) || /* stack only del not bs */ 349 | ( (char*)&undosp->str[0 - undosp->length] + len >= (char*)unbuf + AMAX )) { 350 | undosp = new_undo(pos, abs(len)); 351 | if(undosp == (void*)&unbuf) undo_wrap--; /* say undo wrapped */ 352 | } 353 | 354 | if(len) memcpy(&undosp->str[abs(undosp->length)], pos, len); 355 | undosp->length = undosp->length - len; 356 | 357 | if(!in_undo) { undop = undosp; undone = 0;} 358 | } 359 | 360 | void u_ins(char *pos, int len) 361 | { 362 | int tlen; 363 | if(!undosp) init_undo(); 364 | 365 | if(!undosp->length) undosp->pos = pos; 366 | /* get new_undo if top rec is u_del, or different pos or no space */ 367 | else if((undosp->length < 0) || 368 | /* stack only left to right insertions */ 369 | ( (void*)&undosp->pos[undosp->length] != pos ) || 370 | ( (char*)&undosp->str[undosp->length] + len >= (char*)unbuf + AMAX )) { 371 | undosp = new_undo(pos, abs(len)); 372 | if(undosp == (void*)&unbuf) undo_wrap--; /* say undo wrapped */ 373 | } 374 | tlen = abs(undosp->length); 375 | 376 | if(len) memcpy(&undosp->str[tlen], pos, len); 377 | undosp->length = tlen + len; 378 | if(!in_undo) { undop = undosp; undone = 0;} 379 | } 380 | 381 | void ytot_ins() 382 | { 383 | char* e; 384 | for(e=undop->pos; epos + abs(undop->length); e++) 385 | if(*e == EOL) ytot++; 386 | } 387 | 388 | void undo() 389 | { 390 | /* dont undo nothing, but say nothing is unchanged */ 391 | if(undone) { bell(); return; } 392 | if(undop != undosp) undop = undop->link; 393 | in_undo++; 394 | goto_ptr(undop->pos); 395 | if(undop->length < 0) { /* is delete so insert */ 396 | /* delete flag is negative length */ 397 | file_resize(undop->pos, undop->pos - undop->length); 398 | memcpy(undop->pos, &undop->str[0], 0 - undop->length); 399 | u_ins(undop->pos, 0 - undop->length); 400 | ytot_ins(); /* adjust ytot when inserting */ 401 | } 402 | else { /* is insert so delete */ 403 | file_resize(undop->pos + undop->length, undop->pos); 404 | } 405 | goto_ptr(undop->pos); 406 | if(!undop->link) { 407 | undone = -1; 408 | flag[CHG] = 0; 409 | show_top(); 410 | } 411 | in_undo--; 412 | flag[SHW] = 1; 413 | } 414 | 415 | void redo() 416 | { 417 | /* dont redo nothing */ 418 | if(undop == undosp) { bell(); return; } 419 | in_undo++; 420 | goto_ptr(undop->pos); 421 | 422 | if(undop->length > 0) { /* is insert so insert */ 423 | file_resize(undop->pos, undop->pos + undop->length); 424 | memcpy(undop->pos, &undop->str[0], undop->length); 425 | u_ins(undop->pos, undop->length); 426 | ytot_ins(); /* adjust ytot when inserting */ 427 | } 428 | else { /* is delete so delete */ 429 | file_resize(undop->pos - undop->length, undop->pos); 430 | } 431 | goto_ptr(undop->pos); 432 | 433 | undop = (void*)&undop->str[abs(undosp->length)]; 434 | undone = 0; 435 | in_undo--; 436 | flag[SHW] = 1; 437 | } 438 | 439 | #else /* STATICBUF */ 440 | 441 | char * realloc_buffer(int mode) 442 | { 443 | char *ptr; 444 | int i; 445 | switch(mode) { 446 | 447 | case 0: { 448 | i = amax+AMAX+tabsize+1; 449 | if (i<0) return NULL; 450 | ptr = realloc(edbuf, (size_t)i); 451 | if (ptr) { 452 | amax += AMAX; 453 | i = ptr - edbuf; 454 | edbuf += i; 455 | file_end += i; 456 | cur_pos += i; 457 | line_start += i; 458 | last_pos += i; 459 | old_pos += i; 460 | screen_start += i; 461 | mk += i; 462 | bstart += i; 463 | bend += i; 464 | if (last_mk) last_mk += i; 465 | } 466 | return ptr; 467 | } 468 | 469 | case 1: { 470 | i = bmax+BMAX+tabsize+1; 471 | if (i<0) return NULL; 472 | ptr = realloc(bb, (size_t)i); 473 | if (ptr) { 474 | bmax += BMAX; 475 | bb = ptr; 476 | } 477 | return ptr; 478 | } 479 | 480 | case 2: { 481 | i = umax+UMAX+1; 482 | if (i<0) return NULL; 483 | ptr = realloc(unbuf, (size_t)i); 484 | if (ptr) { 485 | umax += UMAX; 486 | i = (intptr_t)ptr - (intptr_t)unbuf; 487 | unbuf = ptr; 488 | undop = (void*)undop+i; 489 | undosp = (void*)undosp+i; 490 | } 491 | return ptr; 492 | } 493 | } 494 | return NULL; 495 | } 496 | 497 | void init_undo() 498 | { 499 | undosp = undop = unbuf; 500 | undop->link = VOID_LINK; 501 | undop->pos = cur_pos - edbuf -1; 502 | undop->length = 0; 503 | } 504 | 505 | U_REC* new_undo(char *pos, int len) 506 | { 507 | U_REC *tmp; 508 | int tlen = abs(undosp->length); 509 | 510 | retry: 511 | /* wrap undo pointer if no space for requested len in undo buffer */ 512 | if ((void *)undosp->str + tlen + sizeof(U_REC) + len < unbuf + umax) { 513 | tmp = (void *)undosp->str + tlen; 514 | } else { 515 | if (realloc_buffer(2)) goto retry; 516 | tmp = (void *)unbuf; 517 | } 518 | 519 | tmp->link = (uintptr_t)undosp - (uintptr_t)unbuf; 520 | tmp->pos = pos - edbuf; 521 | tmp->length = 0; 522 | return tmp; 523 | } 524 | 525 | void u_del(char *pos, int len) 526 | { 527 | if(!undosp) init_undo(); 528 | 529 | if(!undosp->length) undosp->pos = pos - edbuf; 530 | /* get new_undo if top rec is u_ins, or different pos or no space */ 531 | if((undosp->length > 0) || 532 | ( undosp->pos + edbuf - undosp->length != pos) || /* stack only del not bs */ 533 | ( (void*)undosp->str - undosp->length + abs(len) >= unbuf + umax )) { 534 | undosp = new_undo(pos, abs(len)); 535 | if(undosp == unbuf) undo_wrap--; /* say undo wrapped */ 536 | } 537 | 538 | if(len) memcpy(undosp->str + abs(undosp->length), pos, len); 539 | undosp->length = undosp->length - len; 540 | 541 | if(!in_undo) { undop = undosp; undone = 0;} 542 | } 543 | 544 | void u_ins(char *pos, int len) 545 | { 546 | int tlen; 547 | if(!undosp) init_undo(); 548 | 549 | if(!undosp->length) undosp->pos = pos - edbuf; 550 | /* get new_undo if top rec is u_del, or different pos or no space */ 551 | if((undosp->length < 0) || 552 | /* stack only left to right insertions */ 553 | ( undosp->pos + edbuf + undosp->length != pos ) || 554 | ( (void *)undosp->str + undosp->length + abs(len) >= unbuf + umax )) { 555 | undosp = new_undo(pos, abs(len)); 556 | if(undosp == unbuf) undo_wrap--; /* say undo wrapped */ 557 | } 558 | tlen = abs(undosp->length); 559 | if(len) memcpy(undosp->str + tlen, pos, len); 560 | undosp->length = tlen + len; 561 | if(!in_undo) { undop = undosp; undone = 0;} 562 | } 563 | 564 | void ytot_ins() 565 | { 566 | char* e; 567 | for(e=undop->pos+edbuf; epos+edbuf + abs(undop->length); e++) 568 | if(*e == EOL) ytot++; 569 | } 570 | 571 | void undo() 572 | { 573 | /* dont undo nothing, but say nothing is unchanged */ 574 | if(undone) { bell(); return; } 575 | if(undop != undosp) { 576 | if (undop->link == VOID_LINK) 577 | undop = unbuf; 578 | else 579 | undop = undop->link + unbuf; 580 | } 581 | in_undo++; 582 | goto_ptr(undop->pos + edbuf); 583 | if(undop->length < 0) { /* is delete so insert */ 584 | /* delete flag is negative length */ 585 | file_resize(undop->pos + edbuf, undop->pos + edbuf - undop->length); 586 | memcpy(undop->pos + edbuf, undop->str, - undop->length); 587 | u_ins(undop->pos + edbuf, - undop->length); 588 | ytot_ins(); /* adjust ytot when inserting */ 589 | } 590 | else { /* is insert so delete */ 591 | file_resize(undop->pos + edbuf + undop->length, undop->pos + edbuf); 592 | } 593 | goto_ptr(undop->pos + edbuf); 594 | if(undop->link==VOID_LINK) { 595 | undone = -1; 596 | flag[CHG] = 0; 597 | show_top(); 598 | } 599 | in_undo--; 600 | flag[SHW] = 1; 601 | } 602 | 603 | void redo() 604 | { 605 | /* dont redo nothing */ 606 | if(undop == undosp) { bell(); return; } 607 | in_undo++; 608 | goto_ptr(undop->pos + edbuf); 609 | 610 | if(undop->length > 0) { /* is insert so insert */ 611 | file_resize(undop->pos + edbuf, undop->pos + edbuf + undop->length); 612 | memcpy(undop->pos + edbuf, undop->str, undop->length); 613 | u_ins(undop->pos + edbuf, undop->length); 614 | ytot_ins(); /* adjust ytot when inserting */ 615 | } 616 | else { /* is delete< so delete */ 617 | file_resize(undop->pos + edbuf - undop->length, undop->pos + edbuf); 618 | } 619 | goto_ptr(undop->pos + edbuf); 620 | 621 | undop = (void*)undop->str + abs(undosp->length); 622 | undone = 0; 623 | in_undo--; 624 | flag[SHW] = 1; 625 | } 626 | 627 | #endif /* STATICBUF */ 628 | 629 | #ifdef TERMINAL 630 | void sys_exit(int code) 631 | { 632 | if(!(flag[CHG])) { 633 | /* watch where you're goin', clean up where you been */ 634 | if(cfdpath) free(cfdpath); 635 | gotoxy(0,phys_height+2); 636 | ttclose(); 637 | exitf = 0; 638 | } else putch(7); 639 | } 640 | 641 | void bell() 642 | { 643 | putch(7); 644 | } 645 | #else 646 | char a[2] = ""; 647 | void do_exit(int code) 648 | { 649 | if((a[0] & ~0x20) == 'S') {do_save(); sys_exit(0);} 650 | if((a[0] & ~0x20) == 'X') {flag[CHG] = 0; sys_exit(0);} 651 | } 652 | 653 | void sys_exit(int code) 654 | { 655 | // if file modified then do 'Save-as:', optionally save-and-exit. 656 | if(flag[CHG]) { 657 | bell(); 658 | show_gets("Changed: Save, eXit or Cont.?", a, sizeof(a), &do_exit); 659 | return; 660 | } 661 | if(!(flag[CHG])) { 662 | /* watch where you're goin', clean up where you been */ 663 | if(selection_text) free(selection_text); 664 | if(cfdpath) free(cfdpath); 665 | exit(code); 666 | } 667 | bell(); 668 | } 669 | #endif /* TERMINAL */ 670 | 671 | void goto_xpos() 672 | { 673 | goto_x(x_offset < strlen(line_start+1)+1 ? 674 | x_offset : 675 | strlen(line_start+1)+1); 676 | } 677 | 678 | /* cursor movement */ 679 | void cursor_up() 680 | { 681 | if(flag[BLK]) flag[SHW] = 1; 682 | if(ytru == 0) return; 683 | ytru--; 684 | while(*--line_start != EOL) ; 685 | y--; 686 | goto_xpos(); 687 | } 688 | 689 | void cursor_down() 690 | { 691 | if(flag[BLK]) flag[SHW] = 1; 692 | if(ytru == ytot) return; 693 | ytru++; 694 | while(*++line_start != EOL) ; 695 | y++; 696 | goto_xpos(); 697 | } 698 | 699 | void move_to(int newx, int newy) 700 | { 701 | int old; 702 | if ((newy < 0) || (file_end==edbuf+1)) return; 703 | if((y == newy && x == newx) || (executive != MAIN)) return; 704 | 705 | while((y < newy) && (ytru < ytot)) cursor_down(); 706 | while((y > newy) && (ytru > 0)) cursor_up(); 707 | 708 | if((line_start[x_offset] == EOL) && (x_offset != 1)) cursor_left(); 709 | 710 | /* detect impossible to achieve x pos within tabs */ 711 | old = xtru - newx; 712 | while((old > 0 ? xtru > newx : xtru < newx) && (*cur_pos != EOL)){ 713 | xtru < newx ? cursor_right() : cursor_left(); 714 | } 715 | } 716 | 717 | void getx() 718 | { 719 | xtru = get_tru(cur_pos); 720 | x_offset = cur_pos - line_start; 721 | x = xtru - xlo; 722 | } 723 | 724 | /* cursor left & right */ 725 | void cursor_left() 726 | { 727 | if(xtru == 1){ cursor_up(); goto_x(strlen(line_start+1)+1); return;}; 728 | if(flag[BLK]) flag[SHW] = 1; 729 | if( x == 1 && xlo != 0){ 730 | xlo -= XINC; 731 | flag[SHW] = 1; 732 | } 733 | --cur_pos; 734 | getx(); 735 | } 736 | 737 | void cursor_right() 738 | { 739 | if(*cur_pos == EOL) {goto_x(1); cursor_down(); return;}; 740 | if(flag[BLK]) flag[SHW] = 1; 741 | if(x == screen_width-1) { 742 | xlo += XINC; 743 | flag[SHW] = 1; 744 | } 745 | ++cur_pos; 746 | getx(); 747 | } 748 | 749 | void cursor_pageup() 750 | { 751 | int i,ytmp=y; 752 | 753 | for(i=1; i= ytot) return; /* don't go past end */ 791 | cursor_down(); 792 | goto_x(1); /* goto start of line */ 793 | return; 794 | } 795 | /* skip real chars */ 796 | while(!strchr(wdelims,*d)) { d++; cursor_right(); } 797 | /* skip white space seperators */ 798 | while(strchr(wdelims,*d)) { d++; cursor_right(); } 799 | } 800 | 801 | void word_mark() 802 | { 803 | if(cur_pos[0] <= BLNK) return; /* don't mark nothing */ 804 | mark_off(); 805 | if(!strchr(wdelims,cur_pos[-1])) word_left(); 806 | block_mark(); 807 | while(!strchr(wdelims,*cur_pos)) cursor_right(); 808 | #ifndef TERMINAL 809 | keve->state |= ShiftMask; 810 | #endif /* TERMINAL */ 811 | } 812 | 813 | // mark word under cursor and open in new window if a valid filename 814 | void word_marknopen() 815 | { 816 | char sbuf[NLEN]; 817 | char *s = sbuf; 818 | struct stat o_stat; 819 | 820 | get_mk(sbuf); // get just the filename 821 | #ifndef TERMINAL 822 | s += strlen(sbuf); 823 | if(!stat(sbuf,&o_stat) && S_ISREG(o_stat.st_mode)){ 824 | // pick up possible grep ':nnn:' string for implicit edx goto line 825 | while(!strchr(mdelims,*cur_pos)){ *s++ = *cur_pos; cursor_right();} 826 | *s = 0; 827 | new_edit(cfdpath, sbuf); 828 | } 829 | #endif /* TERMINAL */ 830 | } 831 | 832 | /* display --------------------------------------------------------*/ 833 | /* assuming cursor in correct position: show_rest(screen_width-x,line_start+x_offset) */ 834 | 835 | void drstr(char* disp, int i) 836 | { 837 | #ifdef TERMINAL 838 | disp[i] = 0; 839 | cputs(disp); 840 | #else 841 | drawstring(disp,i); 842 | #endif /* TERMINAL */ 843 | outxy.X += i; 844 | } 845 | 846 | void show_rest(int len, char *s) 847 | { 848 | char *ss; 849 | char disp[MAXVLINE]; 850 | int i,j,k=0,xlt=xlo; 851 | 852 | ss = s; 853 | i = 0; 854 | if(flag[BLK]) { 855 | if(cur_pos < mk) 856 | { bstart = cur_pos; bend = mk; } 857 | else 858 | { bstart = mk; bend = cur_pos; } 859 | if ((ss >= bstart) && (ss < bend)) highvideo(); 860 | } 861 | while(*ss != EOL && i < MAXVLINE) { 862 | if(flag[BLK]) { 863 | if (ss == bstart) { drstr(disp+xlo,i-xlo); k += i; xlo=i=0; highvideo(); } 864 | if (ss == bend) { drstr(disp+xlo,i-xlo); k += i; xlo=i=0; lowvideo(); } 865 | } 866 | if(*ss == '\t') { 867 | for(j = i +(tabsize - (k+i)%tabsize); i edbuf && *--screen_start != EOL) ; 891 | for(; i>y; i--) while(*++screen_start != EOL) ; 892 | 893 | /* first line */ 894 | screen_start++; 895 | do { 896 | gotoxy(0,fr+y2); 897 | if(screen_start xlo) 898 | show_rest(len, screen_start); 899 | else { 900 | if(((flag[BLK]) && 901 | (screen_start == bend)) || 902 | (screen_start == bend+1)) lowvideo(); 903 | clreol(); 904 | } 905 | /* skip EOL */ 906 | while(*screen_start++) ; 907 | } while(++fr <= to); 908 | } 909 | 910 | void scroll_up() 911 | { 912 | if(!y) cursor_down(); 913 | y--; 914 | flag[SHW] = 1; 915 | } 916 | 917 | void scroll_down() 918 | { 919 | if(line_start <= edbuf) return; 920 | if(ytru <= y) return; 921 | if(y >= screen_height-1) cursor_up(); 922 | y++; 923 | flag[SHW] = 1; 924 | } 925 | 926 | void show_sdn(int line) 927 | { 928 | gotoxy(0,y2+line); 929 | show_scr(0, screen_height-1); 930 | } 931 | 932 | void show_flag(int x, int g) 933 | { 934 | gotoxy(20+x-1,y01); 935 | putch(g? fsym[x]: '.'); 936 | flag[x] = g; 937 | } 938 | 939 | /* 940 | simple minded line input executive for status line dialogs. 941 | Successful completion, indicated by a Return key, executes the 942 | callback in dialogCB. Responds to 'Esc' and ^C by terminating 943 | without executing the callback. Printing first char resets Col. 944 | Use ^H to overwrite preset string, 'End' displays cursor to EOS. 945 | All other characters input to diabuf. Set by 'show_gets'. 946 | */ 947 | 948 | void dialog(int key) 949 | { 950 | int skey; 951 | skey = key & 0xff; 952 | 953 | gotoxy(diastart+col,y01); 954 | #ifdef TERMINAL 955 | if(key == 0x0c) { /* ^L */ 956 | #else 957 | undraw_cursor(); 958 | if(keve->state & ControlMask) skey &= 0x1f; 959 | if(key == XK_End) { 960 | #endif /* TERMINAL */ 961 | while((diabuf[col] != 0) && (col < dblen)) putch(diabuf[col++]); 962 | } else { 963 | switch(skey){ 964 | case 8: { 965 | if(col < 0) col = strlen(diabuf); 966 | #ifdef TERMINAL 967 | if(col) { col--; gotoxy(--outxy.X,outxy.Y); putch(' '); gotoxy(outxy.X,outxy.Y);} 968 | #else 969 | if(col) { col--; outxy.X--; putch(' '); outxy.X--;} 970 | #endif /* TERMINAL */ 971 | break; 972 | } 973 | case 3: 974 | case 13: 975 | case 27: { 976 | executive = MAIN; 977 | diabuf[col] = 0; 978 | if(skey == 13) dialogCB(0); 979 | flag[SHW] = 1; 980 | scr_update(); 981 | show_top(); 982 | break; 983 | } 984 | default: { 985 | if(col < 0 || !first) { 986 | col = 0; 987 | gotoxy(diastart+col,y01); 988 | clreol(); 989 | } 990 | if(col < dblen){ 991 | diabuf[col++] = key; 992 | putch(key); 993 | } else bell(); 994 | } 995 | } 996 | } 997 | first = key; 998 | #ifndef TERMINAL 999 | draw_cursor(); 1000 | show_vbar(); 1001 | #endif /* TERMINAL */ 1002 | } 1003 | 1004 | /* display a dialog property string at fixed location in the status bar */ 1005 | 1006 | void show_note(char *prp) 1007 | { 1008 | gotoxy(29,y01); 1009 | clreol(); 1010 | #ifdef TERMINAL 1011 | gotoxy(29,y01); 1012 | #endif /* TERMINAL */ 1013 | cputs(prp); 1014 | #ifdef TERMINAL 1015 | diastart = outxy.X+strlen(prp)+2; 1016 | #else 1017 | diastart = outxy.X+2; 1018 | show_vbar(); 1019 | #endif /* TERMINAL */ 1020 | } 1021 | 1022 | /* setup status line interactive dialog and input data processing callback */ 1023 | 1024 | int show_gets(char *prp, char *buf, int blen, void *cb) 1025 | { 1026 | diabuf = buf; // point at the input buffer 1027 | dialogCB = cb; // setup the dialog callback 1028 | first = 0; // first = 0 = True; 1029 | dblen = blen; // set max dialog buffer input char count 1030 | 1031 | lowvideo(); // make dialog stand out in status line 1032 | show_note(prp); // show function 1033 | cputs(": "); 1034 | cputs(diabuf); // show preset, if any 1035 | col=strlen(diabuf); // point cursor at _end_ of preset string. 1036 | executive = DIALOG; // tell handle_key() to pass keys to dialog 1037 | #ifndef TERMINAL 1038 | draw_cursor(); 1039 | #endif /* TERMINAL */ 1040 | return 0; 1041 | } 1042 | 1043 | /* update line and col */ 1044 | void show_pos() 1045 | { 1046 | char tbuf[NLEN]; 1047 | 1048 | if(executive != MAIN) return; 1049 | highvideo(); 1050 | gotoxy(5,y01); 1051 | snprintf(tbuf, sizeof tbuf, "%d %d ", ytru+1, xtru); 1052 | cputs(tbuf); 1053 | } 1054 | 1055 | /* redraw the status line only in executive == MAIN mode */ 1056 | 1057 | void show_top() 1058 | { 1059 | int i; 1060 | char tbuf[NLEN]; 1061 | 1062 | #ifdef TERMINAL 1063 | if(executive != MAIN || !exitf) return; 1064 | #else 1065 | if(executive != MAIN) return; 1066 | #endif /* TERMINAL */ 1067 | gotoxy(0,y01); 1068 | highvideo(); 1069 | clreol(); 1070 | show_pos(); 1071 | for(i=0; i<= SHW-1; i++) 1072 | show_flag(i, flag[i]); 1073 | #ifdef TERMINAL 1074 | snprintf(tbuf, sizeof tbuf, " Help=^KH %s", cfdpath); 1075 | #else 1076 | snprintf(tbuf, sizeof tbuf, " %s", cfdpath); 1077 | #endif /* TERMINAL */ 1078 | cputs(tbuf); 1079 | lowvideo(); 1080 | gotoxy(x-1,y+y2); 1081 | } 1082 | 1083 | /* display help/about page */ 1084 | 1085 | #ifdef TERMINAL 1086 | void show_help() 1087 | { 1088 | int myy=1; 1089 | char* prntstr = HELP_STR; 1090 | if(!mk) mk = (void*) -1; 1091 | clrscr(); 1092 | show_top(); 1093 | gotoxy(0,y2); 1094 | { 1095 | /* line at a time to process EOL char */ 1096 | while(prntstr < HELP_STR + sizeof(HELP_STR)){ 1097 | puts(prntstr); 1098 | prntstr += strlen(prntstr)+1; 1099 | gotoxy(0,++myy); 1100 | }; 1101 | } 1102 | help_done = -1; 1103 | if(mk == (void*) -1) mk = 0; 1104 | } 1105 | #else 1106 | void show_help(int mode) 1107 | { 1108 | #ifdef EXTHELP 1109 | char name[NLEN], *ptr; 1110 | ptr=getenv("HOME"); 1111 | snprintf(name, sizeof name, "%s/%s", ptr, "MANUAL.ws"); 1112 | new_edit(cfdpath, name); 1113 | #else 1114 | if(!mk) mk = (void*) -1; 1115 | clrscr(); 1116 | show_top(); 1117 | gotoxy(0,y2); 1118 | if (mode == 0) { 1119 | int i; char* prntstr = HELP_STR; 1120 | /* char at a time to process EOL char */ 1121 | for(i=0; i < sizeof(HELP_STR); putch(prntstr[i++])); 1122 | } 1123 | if (mode == 1) { 1124 | int i, j; 1125 | char *ptr = "Alt-key bindings"; 1126 | for (j=0; j= edbuf+amax) { 1218 | d = file_end - col; 1219 | realloc_buffer(0); 1220 | col = file_end - d; 1221 | } 1222 | } while(file_end < edbuf+amax); 1223 | #endif /* STATICBUF */ 1224 | for(; ewin.jump>1; ewin.jump--) cursor_down(); 1225 | badex: 1226 | first_time = 0; 1227 | } 1228 | 1229 | /* compress one line from end */ 1230 | 1231 | char *file_ltab(char *s) 1232 | { 1233 | char *d, *e; 1234 | 1235 | e = d = strchr(s--, EOL); 1236 | while(*--e == BLNK) ; /* trailing blank */ 1237 | while(e > s) { 1238 | if(e[0] == BLNK && (e-s)%tabsize == 0 && e[-1] == BLNK) { 1239 | *--d = 9; 1240 | while(*--e == BLNK && (e-s)%tabsize != 0) ; 1241 | } 1242 | else *--d = *e--; 1243 | } 1244 | return d; 1245 | } 1246 | 1247 | /* routine used for write block file also, this makes it more complicated */ 1248 | 1249 | int file_write(int fd, char *s, char *e) 1250 | { 1251 | if(fd == 0) return 1; /* no write */ 1252 | do { 1253 | if(flag[TAB] && *s != EOL) 1254 | s = file_ltab(s); 1255 | if (*s && write(fd, s, strlen(s)) < 0) 1256 | return 1; 1257 | if (write(fd, "\n", 1) < 0) 1258 | return 1; 1259 | while(*s++ != EOL) ; 1260 | } while(s < e); 1261 | return 0; 1262 | } 1263 | 1264 | int file_fout(void) 1265 | { 1266 | if(fo == 0) { 1267 | strlcpy(bbuf, ewin.name, sizeof bbuf); 1268 | strlcat(bbuf, "XXXXXX", sizeof bbuf); 1269 | if(!(fo=mkstemp(bbuf))) return -1; 1270 | } 1271 | 1272 | #ifndef MSVC 1273 | if (!flag[NEW]) { 1274 | fchmod(fo, ofstat.st_mode & 07777); 1275 | } 1276 | #endif /* MSVC */ 1277 | return file_write(fo, edbuf+1, file_end); 1278 | } 1279 | 1280 | void do_save() 1281 | { 1282 | char bakfile[NLEN+1]; 1283 | 1284 | /* prompt on empty filename */ 1285 | if(ewin.name[0] == 0) { file_save(-1,0); return;} 1286 | 1287 | executive=MAIN; 1288 | if(file_fout() ) { 1289 | bell(); 1290 | return; /* exit if can't write output */ 1291 | } 1292 | 1293 | fchmod(fo, 0644); 1294 | close(fo); 1295 | fo = 0; /* set fo to known condition */ 1296 | 1297 | /* if editing old file then delete old file */ 1298 | if (flag[NEW] == 0) { 1299 | strlcpy(bakfile, ewin.name, sizeof bakfile); 1300 | strlcat(bakfile, "~", sizeof bakfile); 1301 | unlink(bakfile); 1302 | rename(ewin.name, bakfile); 1303 | #ifdef NOBAK 1304 | unlink(bakfile); 1305 | #endif 1306 | } 1307 | 1308 | rename(bbuf, ewin.name); /* ren new temp to old name */ 1309 | flag[CHG] = 0; 1310 | show_top(); 1311 | } 1312 | 1313 | /* go to top of file and reset to known condition */ 1314 | void top() 1315 | { 1316 | y01 = YTOP; 1317 | y2 = y01+1; 1318 | line_start = edbuf; 1319 | x_offset = 1; 1320 | xtru = x = 1; 1321 | ytru = y = 0; 1322 | flag[SHW] = 1; 1323 | } 1324 | 1325 | #ifndef TERMINAL 1326 | void set_title(char *str) 1327 | { 1328 | char b[NLEN]; 1329 | 1330 | snprintf(b, sizeof b, "%s -"EDIT, str); 1331 | XStoreName(dpy, win, b); 1332 | } 1333 | #endif /* TERMINAL */ 1334 | 1335 | /* new file init */ 1336 | char *file_new() 1337 | { 1338 | top(); 1339 | edbuf[0] = EOL; 1340 | last_pos = cur_pos = file_end = edbuf+1; 1341 | ytot = 0; 1342 | flag[NEW] = 0; 1343 | mark_off(); 1344 | last_mk = NULL; 1345 | if((fi = fopen(ewin.name, "r")) == 0) flag[NEW]++; 1346 | else fstat(fileno(fi), &ofstat); 1347 | return(file_end); 1348 | } 1349 | 1350 | #ifndef TERMINAL 1351 | /* exec the forking cmd */ 1352 | int SYSTEM (char *cmd) 1353 | { 1354 | #define SHELL "/bin/sh" 1355 | pid_t pid; 1356 | switch(pid=fork()) { 1357 | case 0: 1358 | execl(SHELL,"sh","-c",cmd,(char *) 0); 1359 | printf("Execl failed!\n"); 1360 | _exit(127); 1361 | case -1: printf("fork error\n"); 1362 | default: return(0); 1363 | } 1364 | } 1365 | 1366 | void gorun() 1367 | { 1368 | SYSTEM(Command); 1369 | } 1370 | 1371 | /* chdir to specified directory and fire up another copy of edx */ 1372 | void new_edit(char *path, char *fn) 1373 | { 1374 | char b[1024]; 1375 | snprintf(b, sizeof b, "cd %s; "EDIT" %s", path ? path : "./", fn ? fn : newbuf ); 1376 | SYSTEM(b); 1377 | } 1378 | 1379 | void newedit(char *fn) 1380 | { 1381 | new_edit(cfdpath, fn); 1382 | } 1383 | 1384 | #ifdef MINIMAL 1385 | /* chdir to working directory and fire up rxvt */ 1386 | 1387 | void mterm() 1388 | { 1389 | char b[1024]; 1390 | snprintf(b, sizeof b, "cd %s;rxvt -font 8x16 -ls -sl 500 -sr +st -geometry 96x28 &", 1391 | cfdpath ? cfdpath : "./"); 1392 | SYSTEM(b); 1393 | } 1394 | #endif /* MINIMAL */ 1395 | #endif /* TERMINAL */ 1396 | 1397 | void do_cd() 1398 | { 1399 | chdir(cfdpath); 1400 | } 1401 | 1402 | void chgdir() 1403 | { 1404 | show_gets("cd", cfdpath, BUFSIZ, do_cd); 1405 | } 1406 | 1407 | void do_open() 1408 | { 1409 | file_read(); 1410 | #ifndef TERMINAL 1411 | set_title(ewin.name); 1412 | #endif /* TERMINAL */ 1413 | executive=MAIN; 1414 | } 1415 | 1416 | void file_save(int f_all, int f_win) 1417 | { 1418 | if(((flag[CHG]) | f_all)) { 1419 | show_gets("Save as", ewin.name, sizeof(ewin.name), &do_save); 1420 | return; 1421 | } 1422 | /* optionally make new empty file */ 1423 | if(f_win) { 1424 | show_gets("Open", ewin.name, sizeof(ewin.name), &do_open); 1425 | } 1426 | } 1427 | 1428 | #ifndef TERMINAL 1429 | void newfile() 1430 | { 1431 | /* get new file name */ 1432 | show_gets("Open", newbuf, sizeof(newbuf), newedit); 1433 | } 1434 | #endif /* TERMINAL */ 1435 | 1436 | /* main editor workhorse. Inserts/deletes specified source/destination */ 1437 | void file_resize(char *s, char *d) 1438 | { 1439 | #ifdef STATICBUF 1440 | char *e = file_end; 1441 | unsigned i = e-s; 1442 | #else 1443 | char *e; 1444 | unsigned int i; 1445 | int s_rel = s - edbuf; 1446 | int d_rel = d - edbuf; 1447 | #endif /* STATICBUF */ 1448 | 1449 | /* immediate problem only when block buffer on disk too big */ 1450 | #ifdef STATICBUF 1451 | if((file_end += (d-s)) >= edbuf+AMAX) { 1452 | #else 1453 | 1454 | i = file_end - s; 1455 | file_end += d-s; 1456 | retry: 1457 | if(file_end>= edbuf+amax) { 1458 | if (realloc_buffer(0)) { 1459 | s = edbuf + s_rel; 1460 | d = edbuf + d_rel; 1461 | goto retry; 1462 | } 1463 | #endif /* STATICBUF */ 1464 | show_note("Main buffer full!"); 1465 | bell(); 1466 | return; 1467 | } 1468 | #ifndef STATICBUF 1469 | e = s+i; 1470 | #endif /* STATICBUF */ 1471 | if(s < d) { /* expand */ 1472 | d += e - s; 1473 | s = e; 1474 | while(i-- > 0) *--d = *--s; 1475 | } 1476 | else { 1477 | u_del(d, s - d); /* save undo delete string */ 1478 | /* adjust ytot when shrink */ 1479 | for(e=d; e 0) *d++ = *s++; 1481 | } 1482 | *file_end = EOL; /* last line may not complete */ 1483 | if(!flag[CHG] ) { 1484 | show_flag(CHG, 1); 1485 | gotoxy(x-1,y+y2); 1486 | clreol(); 1487 | } 1488 | } 1489 | 1490 | /* search and goto */ 1491 | 1492 | /* xx >= 1, yy >= 0 */ 1493 | 1494 | void goto_x(int xx) 1495 | { 1496 | cur_pos = line_start + xx; 1497 | if (cur_pos>file_end) cur_pos=file_end; 1498 | xtru = get_tru(cur_pos); 1499 | if(!xtru) cur_pos--; 1500 | x_offset = cur_pos - line_start; 1501 | 1502 | xx = xlo; 1503 | if(xtru == 1) xlo = 0; 1504 | if(xtru-xlo >= screen_width) 1505 | xlo = ((xtru + XINC - screen_width)/XINC) * XINC; 1506 | x = xtru - xlo; 1507 | if (xlo!= xx) flag[SHW]=1; 1508 | } 1509 | 1510 | void goto_y(int yy) 1511 | { 1512 | int i, n; 1513 | 1514 | n = ytru; 1515 | 1516 | for(i=n; i screen_height || y < 0) { 1519 | flag[SHW] = 1; 1520 | y = screen_height/4; 1521 | } 1522 | } 1523 | 1524 | void goto_ptr(char *s) 1525 | { 1526 | /* find line_start <= s */ 1527 | char *s1 = s; 1528 | int yo = y; 1529 | 1530 | #ifdef STATICBUF 1531 | if(s < edbuf || s >= edbuf + AMAX) { 1532 | #else 1533 | if(s < edbuf || s >= edbuf + amax) { 1534 | #endif /* STATICBUF */ 1535 | bell(); 1536 | return; 1537 | } 1538 | top(); 1539 | while(*--s1 != EOL && s1 > edbuf) ; /* find start of target line */ 1540 | while(line_start+1 <= s1 && y < ytot) cursor_down();/* move to target line */ 1541 | while(line_start+1 > s && y > 0) cursor_up(); /* move back before target */ 1542 | goto_x(s-line_start); /* get x from line start */ 1543 | if(y > screen_height || xlo != 0) { 1544 | flag[SHW] = 1; 1545 | y = yo; 1546 | } 1547 | } 1548 | 1549 | void goline() 1550 | { 1551 | goto_y(atoi(lbuf)-1); 1552 | } 1553 | 1554 | void goto_last() 1555 | { 1556 | mark_off(); 1557 | goto_ptr(last_pos); cursor_down(); 1558 | } 1559 | 1560 | void goto_line() 1561 | { 1562 | show_gets("Goto line", lbuf, sizeof(lbuf), goline); 1563 | } 1564 | 1565 | #ifndef TERMINAL 1566 | void run() 1567 | { 1568 | show_gets("Command", Command, sizeof(Command), gorun); 1569 | } 1570 | #endif /* TERMINAL */ 1571 | 1572 | void gocol() 1573 | { 1574 | goto_x(atoi(cbuf) ); 1575 | } 1576 | 1577 | void goto_col() 1578 | { 1579 | show_gets("Goto Column", cbuf, sizeof(cbuf), gocol); 1580 | } 1581 | 1582 | void twist_pos() 1583 | { 1584 | char *c; 1585 | if (!last_mk || last_mk>=file_end) return; 1586 | c = cur_pos; 1587 | goto_ptr(last_mk); 1588 | last_mk = c; 1589 | if (mk) mk = last_mk; 1590 | } 1591 | 1592 | /* compare to sbuf. used by search */ 1593 | int str_cmp(char *s) 1594 | { 1595 | char *d = sbuf; 1596 | 1597 | if(flag[CAS] ) 1598 | { 1599 | while(*d ) if(*s++ != *d++ ) return 1; 1600 | } 1601 | else 1602 | { 1603 | while(*d ) if(tolower(*s++) != tolower(*d++)) return 1; 1604 | } 1605 | return 0; 1606 | } 1607 | 1608 | /* back/forward search */ 1609 | char *goto_find(char *s, int back) 1610 | { 1611 | int slen = strlen(sbuf); 1612 | mark_off(); 1613 | l1: 1614 | do 1615 | { 1616 | if(back) { 1617 | if(--s <= edbuf) { 1618 | bell(); 1619 | return 0; 1620 | } 1621 | } 1622 | else { 1623 | if(++s >= file_end) { 1624 | bell(); 1625 | return 0; 1626 | } 1627 | } 1628 | } while(str_cmp(s) ); 1629 | 1630 | if( flag[WRD] && ((!strchr(wdelims,s[-1])) || (!strchr(wdelims,s[slen]))) ) 1631 | goto l1; 1632 | 1633 | #ifdef TERMINAL 1634 | goto_ptr(s+slen); 1635 | block_mark(); 1636 | last_mk = mk -= slen; 1637 | #else 1638 | goto_ptr(s); 1639 | block_mark(); 1640 | last_mk = mk += slen; 1641 | #endif /* TERMINAL */ 1642 | return s; 1643 | } 1644 | 1645 | void gofind() 1646 | { 1647 | goto_find(cur_pos, 0); 1648 | } 1649 | 1650 | void get_mk(char* dbuf) 1651 | { 1652 | if(strchr(sdelims,*cur_pos) && !flag[BLK]) return; 1653 | memset(dbuf,0,NLEN * sizeof(char)); 1654 | if(!flag[BLK]) word_mark(); 1655 | if(flag[BLK] && (mk != cur_pos) && (labs(cur_pos - mk) < NLEN)){ 1656 | memcpy(dbuf, mk < cur_pos ? mk : cur_pos, labs(cur_pos - mk)); 1657 | } 1658 | } 1659 | 1660 | char *goto_search(int back) 1661 | { 1662 | get_mk(sbuf); 1663 | show_gets("Search for", sbuf, sizeof(sbuf), gofind); 1664 | return NULL; 1665 | } 1666 | 1667 | void dorepl() 1668 | { 1669 | rlen = strlen(rbuf); 1670 | do { 1671 | file_resize(s+slen, s); /* delete srch string&save undo data */ 1672 | file_resize(s, s+rlen); /* insert space for replace string */ 1673 | memcpy(s, rbuf, rlen); 1674 | u_ins(s, rlen); /* add replace string to undo buf */ 1675 | s = s+rlen; /* skip over new string */ 1676 | } 1677 | while(flag[ALL] && (s=goto_find(s, 0)) != 0) ; 1678 | flag[SHW] = 1; 1679 | } 1680 | 1681 | void doSAR() 1682 | { 1683 | if((s =(char*) goto_find(cur_pos,0))) { 1684 | slen = strlen(sbuf); 1685 | show_scr(0, screen_height-1); 1686 | gotoxy(x-1,y+y2); 1687 | highvideo(); 1688 | { 1689 | int i = slen; 1690 | char *sb=s; 1691 | while(i-- && !putch(*sb++)); 1692 | } 1693 | lowvideo(); 1694 | show_gets("Replace with", rbuf, sizeof(rbuf), dorepl); 1695 | } 1696 | } 1697 | 1698 | void goto_replace(int all) 1699 | { 1700 | get_mk(sbuf); 1701 | show_gets("SAR for", sbuf, sizeof(sbuf), doSAR); 1702 | } 1703 | 1704 | void gettab() 1705 | { 1706 | tabsize = atoi(twbuf); 1707 | } 1708 | 1709 | void tab_size() 1710 | { 1711 | show_gets("Tab size",twbuf, sizeof(twbuf), gettab); 1712 | } 1713 | 1714 | void getmarg() 1715 | { 1716 | screen_width = atoi(wbuf); 1717 | flag[SHW]++; 1718 | } 1719 | 1720 | void window_size() 1721 | { 1722 | show_gets("Wrap col",wbuf, sizeof(wbuf), getmarg); 1723 | } 1724 | 1725 | /* block and format ---*/ 1726 | /* use blen, mk, bb */ 1727 | 1728 | void mark_off() 1729 | { 1730 | mk = NULL; 1731 | flag[BLK] = 0; 1732 | flag[SHW] = 1; 1733 | show_top(); 1734 | } 1735 | 1736 | void reset_mark() 1737 | { 1738 | if (!last_mk) return; 1739 | flag[BLK] = 1; mk = last_mk; 1740 | } 1741 | 1742 | void block_mark() 1743 | { 1744 | if( mk == NULL ) { 1745 | mk = cur_pos; 1746 | last_mk = mk; 1747 | flag[BLK] = 1; 1748 | show_top(); 1749 | } 1750 | else 1751 | mark_off(); 1752 | } 1753 | 1754 | void block_put() 1755 | { 1756 | #ifdef STATICBUF 1757 | if(blen < BMAX) memcpy(bb, mk, blen); 1758 | #else 1759 | while (blen >= bmax && realloc_buffer(1)); 1760 | 1761 | if (blen < bmax) 1762 | memcpy(bb, mk, blen); 1763 | #endif /* STATICBUF */ 1764 | else { 1765 | if(fb == 0 && (fb = tmpfile()) == 0) return; 1766 | fseek(fb, 0L, 0); 1767 | fwrite(mk, 1, blen, fb); 1768 | } 1769 | } 1770 | 1771 | void block_get() 1772 | { 1773 | int i; 1774 | 1775 | #ifdef STATICBUF 1776 | if(blen < BMAX) memcpy(mk, bb, blen); 1777 | #else 1778 | while (mk+blen >= edbuf+amax && realloc_buffer(0)); 1779 | if (mk+blen < edbuf+amax) 1780 | memcpy(mk, bb, blen); 1781 | #endif /* STATICBUF */ 1782 | else { 1783 | if(fb == 0) return; 1784 | fseek(fb, 0L, 0); /* 0L offset, 0=beginning of file */ 1785 | fread(mk, 1, blen, fb); 1786 | } 1787 | /* calculate ytot */ 1788 | for(i=0; i= mk */ 1816 | s = cur_pos ; /* swap cur_pos & mk */ 1817 | cur_pos = mk ; 1818 | mk = s ; 1819 | } 1820 | s = cur_pos; 1821 | goto_ptr(mk); 1822 | 1823 | /* delete block and save to undo buf */ 1824 | file_resize(s, mk); 1825 | cur_pos = mk; 1826 | } 1827 | 1828 | void block_remove_update() 1829 | { 1830 | remove_block(); 1831 | mark_off(); 1832 | } 1833 | 1834 | void chg_case(int upper) 1835 | { 1836 | char *s; 1837 | int i; 1838 | 1839 | if(!flag[BLK]) return; /* exit if no mark */ 1840 | if(cur_pos < mk) { /* ensure cur_pos >= mk */ 1841 | s = cur_pos ; /* swap cur_pos & mk */ 1842 | cur_pos = mk ; 1843 | mk = s ; 1844 | goto_ptr(cur_pos); 1845 | } 1846 | i = cur_pos+1 - mk; /* get length */ 1847 | u_del(mk, i-1); /* save undo data enmasse */ 1848 | while(i--) mk[i] = !upper ? tolower(mk[i]) : toupper(mk[i]); 1849 | u_ins(mk, cur_pos - mk); 1850 | flag[SHW] = flag[CHG] = 1; 1851 | } 1852 | 1853 | void transpose() 1854 | { 1855 | char c; 1856 | if (cur_pos && cur_pos>edbuf+1 && cur_pos= mk */ 1872 | s = cur_pos ; /* swap cur_pos & mk */ 1873 | cur_pos = mk ; 1874 | mk = s ; 1875 | } 1876 | blen = cur_pos - mk; /* get length */ 1877 | block_put(); /* copy block to buffer */ 1878 | if(delete) { 1879 | block_remove_update(); 1880 | return; 1881 | } 1882 | mark_off(); 1883 | } 1884 | 1885 | void block_paste() 1886 | { 1887 | if(!blen) return; /* dont paste nothing */ 1888 | if(flag[BLK]) block_remove_update(); /* delete marked block */ 1889 | 1890 | file_resize(cur_pos, cur_pos+blen); 1891 | mk = cur_pos; 1892 | block_get(); 1893 | 1894 | /* save to undo buf */ 1895 | u_ins(mk - 1, blen); 1896 | goto_ptr(mk + blen); 1897 | mark_off(); 1898 | } 1899 | 1900 | /* read file into cursor position */ 1901 | void doblockr() 1902 | { 1903 | char *bb_end; 1904 | #ifdef STATICBUF 1905 | int c; 1906 | #else 1907 | int c, d; 1908 | #endif /* STATICBUF */ 1909 | char *col; 1910 | 1911 | if(!(fb = fopen(fbuf, "r"))) { bell(); return; }; 1912 | 1913 | fseek(fb, 0L, 2); /* seek to 0L offset, 2=end of file */ 1914 | blen=ftell(fb); /* get file length */ 1915 | fseek(fb, 0L, 0); /* seek back to file start */ 1916 | bb_end = col = bb; 1917 | 1918 | /* read complete file */ 1919 | do { 1920 | c = fgetc(fb); 1921 | if(c == EOF) { 1922 | fclose(fb); 1923 | fb = 0; /* no more read */ 1924 | break; 1925 | } 1926 | if(c == '\t' && flag[TAB]) { 1927 | do (*bb_end++ = BLNK); 1928 | while( ((bb_end-col) % tabsize) != 0); 1929 | } 1930 | else 1931 | if(c == LF) { 1932 | *bb_end++ = EOL; 1933 | col = bb_end; 1934 | } 1935 | else 1936 | *bb_end++ = c; 1937 | #ifdef STATICBUF 1938 | } while(bb_end < bb+BMAX || c != EOF); 1939 | #else 1940 | if (bb_end >= bb+bmax) { 1941 | d = (intptr_t)bb; 1942 | realloc_buffer(1); 1943 | d = (intptr_t)bb - d; 1944 | col += d; 1945 | bb_end += d; 1946 | } 1947 | } while(bb_end < bb+bmax); 1948 | #endif /* STATICBUF */ 1949 | 1950 | blen = bb_end - bb; 1951 | block_paste(); 1952 | } 1953 | 1954 | void block_read() 1955 | { 1956 | show_gets("Read file", fbuf, sizeof(fbuf), doblockr); 1957 | } 1958 | 1959 | /* copy block to file, not to block buffer */ 1960 | void doblockw() 1961 | { 1962 | int fd; 1963 | 1964 | show_flag(TAB, 0); 1965 | fd = open(fbuf, O_RDWR|O_CREAT, 0644); 1966 | file_write(fd, bstart, bend); 1967 | close(fd); 1968 | show_top(); 1969 | } 1970 | 1971 | void block_write() 1972 | { 1973 | if(!flag[BLK]) return; 1974 | if(cur_pos < mk) 1975 | { bstart = cur_pos; bend = mk; } 1976 | else 1977 | { bstart = mk; bend = cur_pos; } 1978 | 1979 | show_gets("Write file", fbuf, sizeof(fbuf),(void*) doblockw); 1980 | } 1981 | 1982 | /* fill current line */ 1983 | int block_fill() 1984 | { 1985 | goto_x(screen_width); 1986 | while((cur_pos > line_start+1) && ((*cur_pos == EOL)||(*cur_pos > BLNK))) cursor_left(); 1987 | if(cur_pos == line_start+1) 1988 | goto_x(screen_width-1); 1989 | else 1990 | key_delete(); 1991 | key_return(); 1992 | goto_x(strlen(line_start+1)+1); 1993 | flag[CHG] = 1; 1994 | return cur_pos - line_start; 1995 | } 1996 | 1997 | /* format paragraph */ 1998 | void block_format() 1999 | { 2000 | char *s=line_start; 2001 | 2002 | goto_x(1); 2003 | /* remove newlines to end of para */ 2004 | while(s = strchr(++s, EOL), ytru < ytot && s[1] != EOL) { 2005 | u_del(s,1); 2006 | *s = BLNK; 2007 | u_ins(s,1); 2008 | ytot--; 2009 | flag[CHG] = 1; 2010 | } 2011 | /* truncate line <= screen_width */ 2012 | while(goto_x(strlen(line_start+1)+1), x_offset >= screen_width) block_fill(); 2013 | /* goto end of line */ 2014 | while(line_start[x_offset] ) cursor_right(); 2015 | show_top(); 2016 | flag[SHW] = 1; 2017 | } 2018 | 2019 | /* find and set cursor to matching bracket '(,{,[,],},)' */ 2020 | 2021 | void find_match() 2022 | { 2023 | char *s = cur_pos; 2024 | int dire, cnt; 2025 | char ch, mch; 2026 | 2027 | if (!s) return; 2028 | 2029 | ch = *s; 2030 | switch (ch) { 2031 | case '(': mch = ')'; dire = 0; break; 2032 | case ')': mch = '('; dire = 1; break; 2033 | case '[': mch = ']'; dire = 0; break; 2034 | case ']': mch = '['; dire = 1; break; 2035 | case '{': mch = '}'; dire = 0; break; 2036 | case '}': mch = '{'; dire = 1; break; 2037 | default: return; 2038 | } 2039 | cnt = 0; 2040 | if (dire) { 2041 | while (--s >= edbuf) { 2042 | if (*s == ch) cnt++; 2043 | else if (*s == mch) { 2044 | if (!cnt) goto match; 2045 | cnt--; 2046 | } 2047 | } 2048 | } else { 2049 | while (++s < file_end) { 2050 | if (*s == ch) cnt++; 2051 | else if (*s == mch) { 2052 | if (!cnt) goto match; 2053 | cnt--; 2054 | } 2055 | } 2056 | } 2057 | return; 2058 | match: 2059 | goto_ptr(s); 2060 | flag[SHW]=1; 2061 | } 2062 | 2063 | /* key actions ---*/ 2064 | 2065 | void key_deleol(char *s) 2066 | { 2067 | if(ytru == ytot) return; 2068 | if(flag[BLK]) { 2069 | block_remove_update(); /* delete marked block */ 2070 | return; 2071 | } 2072 | goto_ptr(s); 2073 | 2074 | /* delete eol and save to undo buf */ 2075 | file_resize(s+1, s); 2076 | flag[SHW]=1; 2077 | } 2078 | 2079 | /* delete char under cursor */ 2080 | void key_delete() 2081 | { 2082 | char *s=cur_pos; 2083 | 2084 | if(flag[BLK]) { 2085 | block_remove_update(); 2086 | return; 2087 | } 2088 | else if( *s == EOL) { 2089 | key_deleol(s); 2090 | return; 2091 | } 2092 | /* delete cursor char and save to undo buf */ 2093 | file_resize(s+1, s); 2094 | show_rest(screen_width-x, s); 2095 | } 2096 | 2097 | /* delete char before cursor */ 2098 | void key_backspace() 2099 | { 2100 | char *s=cur_pos; 2101 | 2102 | if(flag[BLK]) { 2103 | block_remove_update(); 2104 | return; 2105 | } 2106 | if(*--s == EOL) { /* delete EOL */ 2107 | if(ytru == 0) return; 2108 | cursor_up(); 2109 | goto_x(strlen(line_start+1)+1); 2110 | key_deleol(s); 2111 | return; 2112 | } 2113 | cursor_left(); 2114 | key_delete(); 2115 | flag[SHW]=1; 2116 | } 2117 | 2118 | /* delete non-white string + white-space string */ 2119 | void key_delword(int eol) 2120 | { 2121 | char *d=cur_pos; 2122 | 2123 | if(flag[BLK]) { 2124 | block_remove_update(); 2125 | return; 2126 | } 2127 | if(*d == EOL) { 2128 | key_deleol(d); 2129 | return; 2130 | } 2131 | if(eol) while(*d != EOL) d++; 2132 | else { 2133 | while(!strchr(sdelims,*d) && *d != EOL) d++; 2134 | while(strchr(s1delims,*d) && *d != EOL) d++; 2135 | } 2136 | /* delete word and save to undo buf */ 2137 | file_resize(d, cur_pos); 2138 | flag[SHW]=1; 2139 | } 2140 | 2141 | /* insert tab char */ 2142 | void key_tab(int tabi) 2143 | { 2144 | if(flag[BLK]) { 2145 | key_delete(); 2146 | } 2147 | 2148 | if(flag[TAB]){ 2149 | do key_normal(' '); 2150 | while((xtru%tabsize) != 1 && *cur_pos != EOL); 2151 | } else { 2152 | key_normal('\t'); 2153 | } 2154 | } 2155 | 2156 | /* insert newline, increase line count */ 2157 | void key_return() 2158 | { 2159 | char *s = cur_pos; 2160 | 2161 | /* reset marked block on char entry */ 2162 | if(flag[BLK]) { 2163 | key_delete(); 2164 | s = cur_pos; 2165 | } 2166 | else if(flag[OVR] ) { 2167 | cursor_down(); 2168 | goto_x(1); 2169 | return; 2170 | } 2171 | file_resize(s, s+1); 2172 | goto_x(1); 2173 | *s = EOL; 2174 | /* save newly inserted EOL to undo buf */ 2175 | u_ins(s, 1); 2176 | ytot++; 2177 | /* get prev line_start */ 2178 | s = line_start+1; 2179 | cursor_down(); 2180 | goto_x(1); /* ensure visible cursor */ 2181 | if(flag[IND]) { 2182 | int i=0; 2183 | /* count spaces and tabs */ 2184 | while(s[i] == BLNK || s[i] == '\t') i++; 2185 | if(i){ /* and only if */ 2186 | file_resize(line_start+1, line_start+1+i); 2187 | memcpy(line_start+1,s, sizeof(char) * i); 2188 | /* save undo info */ 2189 | u_ins(line_start+1, i); 2190 | x_offset += i; 2191 | goto_x(i+1); 2192 | } 2193 | } 2194 | flag[SHW]=1; 2195 | } 2196 | 2197 | /* everything ASCII else */ 2198 | void key_normal(int key) 2199 | { 2200 | char *s=line_start+x_offset; 2201 | 2202 | /* reset marked block on char entry */ 2203 | if(flag[BLK]) { key_delete(); s = cur_pos; } 2204 | 2205 | if(flag[OVR] && *s != EOL) { 2206 | /* save old overwrite char to undo buf */ 2207 | u_del(s, 1); 2208 | putch(*s = key); 2209 | flag[CHG] = 1; 2210 | } 2211 | else { 2212 | file_resize(s, s+1); 2213 | *s = key; 2214 | flag[SHW] =1 ; 2215 | } 2216 | cursor_right(); 2217 | /* save new overwrite/insert char to undo buf */ 2218 | u_ins(s, 1); 2219 | 2220 | if(!flag[FIL] || xtru < screen_width) return; 2221 | 2222 | (void) block_fill(); /* cursor_down */ 2223 | } 2224 | 2225 | /* simple, aint it? */ 2226 | void rec_macro(int k) 2227 | { 2228 | 2229 | if(k & 0xff00) bell(); /* beep&discard non ASCII, ie func keys */ 2230 | else /* else record key */ 2231 | #ifdef TERMINAL 2232 | *pmbuf++ = k; 2233 | #else 2234 | *pmbuf++ = keve->state & ControlMask ? k & 0x1f: k; 2235 | #endif /* TERMINAL */ 2236 | } 2237 | 2238 | /* turn on macro recording or play back macro */ 2239 | void key_macros(int record) 2240 | { 2241 | char *s=mbuf; 2242 | int k; 2243 | 2244 | if(!record) { /* play macro back */ 2245 | if(*s == 0) { bell(); return; }; /* ding user on empty mbuf */ 2246 | doCtrlX = 0; /* turn off control key state from ^K */ 2247 | #ifndef TERMINAL 2248 | keve->state = 0; /* turn off control key state from ^P */ 2249 | #endif /* TERMINAL */ 2250 | while(*s != 0) { 2251 | k = 255 & *s++; 2252 | switch(executive) { 2253 | case MAIN: 2254 | main_exec(k); 2255 | break; 2256 | case DIALOG: 2257 | dialog(k); 2258 | break; 2259 | case OPTIONS: 2260 | options(k); 2261 | break; 2262 | } 2263 | } 2264 | flag[SHW] = 1; 2265 | return; 2266 | } 2267 | /* else toggle recording on/off */ 2268 | flag[REC] ^= 1; 2269 | show_top(); 2270 | if(!flag[REC]) { /* terminal condition */ 2271 | pmbuf[-2] = 0; /* backup over ^K^M & terminate macro with a 0x0 */ 2272 | pmbuf = mbuf; /* reset record pointer to start of mbuf */ 2273 | } 2274 | } 2275 | 2276 | #ifdef GREEK 2277 | void key_greek(int key) 2278 | { 2279 | unsigned char c; 2280 | char *seq = NULL; 2281 | int i, l; 2282 | c = key | 0x40; 2283 | if (c>='a' && c<='z') 2284 | seq = greek_letter[c-'a']; 2285 | if (c>='A' && c<='Z') 2286 | seq = greek_letter[c-'A']; 2287 | if (seq) { 2288 | key_normal('\\'); 2289 | if (*seq=='!') { 2290 | ++seq; 2291 | if (var_greek && c>='a') { 2292 | key_normal('v'); 2293 | key_normal('a'); 2294 | key_normal('r'); 2295 | } 2296 | } 2297 | l = strlen(seq); 2298 | if (c>='a') 2299 | for (i=0; i 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | int vsnprintf(char* str, size_t size, const char* format, va_list arg); 44 | 45 | /** 46 | * Very portable snprintf implementation, limited in functionality, 47 | * esp. for %[capital] %[nonportable] and so on. Reduced float functionality, 48 | * mostly in formatting and range (e+-16), for %f and %g. 49 | * 50 | * %s, %d, %u, %i, %x, %c, %n and %% are fully supported. 51 | * This includes width, precision, flags 0- +, and *(arg for wid,prec). 52 | * %f, %g, %m, %p have reduced support, support for wid,prec,flags,*, but 53 | * less floating point range, no %e formatting for %g. 54 | */ 55 | int snprintf(char* str, size_t size, const char* format, ...) 56 | { 57 | int r; 58 | va_list args; 59 | va_start(args, format); 60 | r = vsnprintf(str, size, format, args); 61 | va_end(args); 62 | return r; 63 | } 64 | 65 | /** add padding to string */ 66 | static void 67 | print_pad(char** at, size_t* left, int* ret, char p, int num) 68 | { 69 | while(num--) { 70 | if(*left > 1) { 71 | *(*at)++ = p; 72 | (*left)--; 73 | } 74 | (*ret)++; 75 | } 76 | } 77 | 78 | /** get negative symbol, 0 if none */ 79 | static char 80 | get_negsign(int negative, int plus, int space) 81 | { 82 | if(negative) 83 | return '-'; 84 | if(plus) 85 | return '+'; 86 | if(space) 87 | return ' '; 88 | return 0; 89 | } 90 | 91 | #define PRINT_DEC_BUFSZ 32 /* 20 is enough for 64 bit decimals */ 92 | /** print decimal into buffer, returns length */ 93 | static int 94 | print_dec(char* buf, int max, unsigned int value) 95 | { 96 | int i = 0; 97 | if(value == 0) { 98 | if(max > 0) { 99 | buf[0] = '0'; 100 | i = 1; 101 | } 102 | } else while(value && i < max) { 103 | buf[i++] = '0' + value % 10; 104 | value /= 10; 105 | } 106 | return i; 107 | } 108 | 109 | /** print long decimal into buffer, returns length */ 110 | static int 111 | print_dec_l(char* buf, int max, unsigned long value) 112 | { 113 | int i = 0; 114 | if(value == 0) { 115 | if(max > 0) { 116 | buf[0] = '0'; 117 | i = 1; 118 | } 119 | } else while(value && i < max) { 120 | buf[i++] = '0' + value % 10; 121 | value /= 10; 122 | } 123 | return i; 124 | } 125 | 126 | /** print long decimal into buffer, returns length */ 127 | static int 128 | print_dec_ll(char* buf, int max, unsigned long long value) 129 | { 130 | int i = 0; 131 | if(value == 0) { 132 | if(max > 0) { 133 | buf[0] = '0'; 134 | i = 1; 135 | } 136 | } else while(value && i < max) { 137 | buf[i++] = '0' + value % 10; 138 | value /= 10; 139 | } 140 | return i; 141 | } 142 | 143 | /** print hex into buffer, returns length */ 144 | static int 145 | print_hex(char* buf, int max, unsigned int value) 146 | { 147 | const char* h = "0123456789abcdef"; 148 | int i = 0; 149 | if(value == 0) { 150 | if(max > 0) { 151 | buf[0] = '0'; 152 | i = 1; 153 | } 154 | } else while(value && i < max) { 155 | buf[i++] = h[value & 0x0f]; 156 | value >>= 4; 157 | } 158 | return i; 159 | } 160 | 161 | /** print long hex into buffer, returns length */ 162 | static int 163 | print_hex_l(char* buf, int max, unsigned long value) 164 | { 165 | const char* h = "0123456789abcdef"; 166 | int i = 0; 167 | if(value == 0) { 168 | if(max > 0) { 169 | buf[0] = '0'; 170 | i = 1; 171 | } 172 | } else while(value && i < max) { 173 | buf[i++] = h[value & 0x0f]; 174 | value >>= 4; 175 | } 176 | return i; 177 | } 178 | 179 | /** print long long hex into buffer, returns length */ 180 | static int 181 | print_hex_ll(char* buf, int max, unsigned long long value) 182 | { 183 | const char* h = "0123456789abcdef"; 184 | int i = 0; 185 | if(value == 0) { 186 | if(max > 0) { 187 | buf[0] = '0'; 188 | i = 1; 189 | } 190 | } else while(value && i < max) { 191 | buf[i++] = h[value & 0x0f]; 192 | value >>= 4; 193 | } 194 | return i; 195 | } 196 | 197 | /** copy string into result, reversed */ 198 | static void 199 | spool_str_rev(char** at, size_t* left, int* ret, const char* buf, int len) 200 | { 201 | int i = len; 202 | while(i) { 203 | if(*left > 1) { 204 | *(*at)++ = buf[--i]; 205 | (*left)--; 206 | } else --i; 207 | (*ret)++; 208 | } 209 | } 210 | 211 | /** copy string into result */ 212 | static void 213 | spool_str(char** at, size_t* left, int* ret, const char* buf, int len) 214 | { 215 | int i; 216 | for(i=0; i 1) { 218 | *(*at)++ = buf[i]; 219 | (*left)--; 220 | } 221 | (*ret)++; 222 | } 223 | } 224 | 225 | /** print number formatted */ 226 | static void 227 | print_num(char** at, size_t* left, int* ret, int minw, int precision, 228 | int prgiven, int zeropad, int minus, int plus, int space, 229 | int zero, int negative, char* buf, int len) 230 | { 231 | int w = len; /* excludes minus sign */ 232 | char s = get_negsign(negative, plus, space); 233 | if(minus) { 234 | /* left adjust the number into the field, space padding */ 235 | /* calc numw = [sign][zeroes][number] */ 236 | int numw = w; 237 | if(precision == 0 && zero) numw = 0; 238 | if(numw < precision) numw = precision; 239 | if(s) numw++; 240 | 241 | /* sign */ 242 | if(s) print_pad(at, left, ret, s, 1); 243 | 244 | /* number */ 245 | if(precision == 0 && zero) { 246 | /* "" for the number */ 247 | } else { 248 | if(w < precision) 249 | print_pad(at, left, ret, '0', precision - w); 250 | spool_str_rev(at, left, ret, buf, len); 251 | } 252 | /* spaces */ 253 | if(numw < minw) 254 | print_pad(at, left, ret, ' ', minw - numw); 255 | } else { 256 | /* pad on the left of the number */ 257 | /* calculate numw has width of [sign][zeroes][number] */ 258 | int numw = w; 259 | if(precision == 0 && zero) numw = 0; 260 | if(numw < precision) numw = precision; 261 | if(!prgiven && zeropad && numw < minw) numw = minw; 262 | else if(s) numw++; 263 | 264 | /* pad with spaces */ 265 | if(numw < minw) 266 | print_pad(at, left, ret, ' ', minw - numw); 267 | /* print sign (and one less zeropad if so) */ 268 | if(s) { 269 | print_pad(at, left, ret, s, 1); 270 | numw--; 271 | } 272 | /* pad with zeroes */ 273 | if(w < numw) 274 | print_pad(at, left, ret, '0', numw - w); 275 | if(precision == 0 && zero) 276 | return; 277 | /* print the characters for the value */ 278 | spool_str_rev(at, left, ret, buf, len); 279 | } 280 | } 281 | 282 | /** print %d and %i */ 283 | static void 284 | print_num_d(char** at, size_t* left, int* ret, int value, 285 | int minw, int precision, int prgiven, int zeropad, int minus, 286 | int plus, int space) 287 | { 288 | char buf[PRINT_DEC_BUFSZ]; 289 | int negative = (value < 0); 290 | int zero = (value == 0); 291 | int len = print_dec(buf, (int)sizeof(buf), 292 | (unsigned int)(negative?-value:value)); 293 | print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, 294 | plus, space, zero, negative, buf, len); 295 | } 296 | 297 | /** print %ld and %li */ 298 | static void 299 | print_num_ld(char** at, size_t* left, int* ret, long value, 300 | int minw, int precision, int prgiven, int zeropad, int minus, 301 | int plus, int space) 302 | { 303 | char buf[PRINT_DEC_BUFSZ]; 304 | int negative = (value < 0); 305 | int zero = (value == 0); 306 | int len = print_dec_l(buf, (int)sizeof(buf), 307 | (unsigned long)(negative?-value:value)); 308 | print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, 309 | plus, space, zero, negative, buf, len); 310 | } 311 | 312 | /** print %lld and %lli */ 313 | static void 314 | print_num_lld(char** at, size_t* left, int* ret, long long value, 315 | int minw, int precision, int prgiven, int zeropad, int minus, 316 | int plus, int space) 317 | { 318 | char buf[PRINT_DEC_BUFSZ]; 319 | int negative = (value < 0); 320 | int zero = (value == 0); 321 | int len = print_dec_ll(buf, (int)sizeof(buf), 322 | (unsigned long long)(negative?-value:value)); 323 | print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, 324 | plus, space, zero, negative, buf, len); 325 | } 326 | 327 | /** print %u */ 328 | static void 329 | print_num_u(char** at, size_t* left, int* ret, unsigned int value, 330 | int minw, int precision, int prgiven, int zeropad, int minus, 331 | int plus, int space) 332 | { 333 | char buf[PRINT_DEC_BUFSZ]; 334 | int negative = 0; 335 | int zero = (value == 0); 336 | int len = print_dec(buf, (int)sizeof(buf), value); 337 | print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, 338 | plus, space, zero, negative, buf, len); 339 | } 340 | 341 | /** print %lu */ 342 | static void 343 | print_num_lu(char** at, size_t* left, int* ret, unsigned long value, 344 | int minw, int precision, int prgiven, int zeropad, int minus, 345 | int plus, int space) 346 | { 347 | char buf[PRINT_DEC_BUFSZ]; 348 | int negative = 0; 349 | int zero = (value == 0); 350 | int len = print_dec_l(buf, (int)sizeof(buf), value); 351 | print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, 352 | plus, space, zero, negative, buf, len); 353 | } 354 | 355 | /** print %llu */ 356 | static void 357 | print_num_llu(char** at, size_t* left, int* ret, unsigned long long value, 358 | int minw, int precision, int prgiven, int zeropad, int minus, 359 | int plus, int space) 360 | { 361 | char buf[PRINT_DEC_BUFSZ]; 362 | int negative = 0; 363 | int zero = (value == 0); 364 | int len = print_dec_ll(buf, (int)sizeof(buf), value); 365 | print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, 366 | plus, space, zero, negative, buf, len); 367 | } 368 | 369 | /** print %x */ 370 | static void 371 | print_num_x(char** at, size_t* left, int* ret, unsigned int value, 372 | int minw, int precision, int prgiven, int zeropad, int minus, 373 | int plus, int space) 374 | { 375 | char buf[PRINT_DEC_BUFSZ]; 376 | int negative = 0; 377 | int zero = (value == 0); 378 | int len = print_hex(buf, (int)sizeof(buf), value); 379 | print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, 380 | plus, space, zero, negative, buf, len); 381 | } 382 | 383 | /** print %lx */ 384 | static void 385 | print_num_lx(char** at, size_t* left, int* ret, unsigned long value, 386 | int minw, int precision, int prgiven, int zeropad, int minus, 387 | int plus, int space) 388 | { 389 | char buf[PRINT_DEC_BUFSZ]; 390 | int negative = 0; 391 | int zero = (value == 0); 392 | int len = print_hex_l(buf, (int)sizeof(buf), value); 393 | print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, 394 | plus, space, zero, negative, buf, len); 395 | } 396 | 397 | /** print %llx */ 398 | static void 399 | print_num_llx(char** at, size_t* left, int* ret, unsigned long long value, 400 | int minw, int precision, int prgiven, int zeropad, int minus, 401 | int plus, int space) 402 | { 403 | char buf[PRINT_DEC_BUFSZ]; 404 | int negative = 0; 405 | int zero = (value == 0); 406 | int len = print_hex_ll(buf, (int)sizeof(buf), value); 407 | print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, 408 | plus, space, zero, negative, buf, len); 409 | } 410 | 411 | /** print %llp */ 412 | static void 413 | print_num_llp(char** at, size_t* left, int* ret, void* value, 414 | int minw, int precision, int prgiven, int zeropad, int minus, 415 | int plus, int space) 416 | { 417 | char buf[PRINT_DEC_BUFSZ]; 418 | int negative = 0; 419 | int zero = (value == 0); 420 | #if defined(SIZE_MAX) && defined(UINT32_MAX) && (UINT32_MAX == SIZE_MAX || INT32_MAX == SIZE_MAX) 421 | /* avoid warning about upcast on 32bit systems */ 422 | unsigned long long llvalue = (unsigned long)value; 423 | #else 424 | unsigned long long llvalue = (unsigned long long)value; 425 | #endif 426 | int len = print_hex_ll(buf, (int)sizeof(buf), llvalue); 427 | if(zero) { 428 | buf[0]=')'; 429 | buf[1]='l'; 430 | buf[2]='i'; 431 | buf[3]='n'; 432 | buf[4]='('; 433 | len = 5; 434 | } else { 435 | /* put '0x' in front of the (reversed) buffer result */ 436 | if(len < PRINT_DEC_BUFSZ) 437 | buf[len++] = 'x'; 438 | if(len < PRINT_DEC_BUFSZ) 439 | buf[len++] = '0'; 440 | } 441 | print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, 442 | plus, space, zero, negative, buf, len); 443 | } 444 | 445 | #define PRINT_FLOAT_BUFSZ 64 /* xx.yy with 20.20 about the max */ 446 | /** spool remainder after the decimal point to buffer, in reverse */ 447 | static int 448 | print_remainder(char* buf, int max, double r, int prec) 449 | { 450 | unsigned long long cap = 1; 451 | unsigned long long value; 452 | int len, i; 453 | if(prec > 19) prec = 19; /* max we can do */ 454 | if(max < prec) return 0; 455 | for(i=0; i= 5) { 462 | value++; 463 | /* that might carry to numbers before the comma, if so, 464 | * just ignore that rounding. failure because 64bitprintout */ 465 | if(value >= cap) 466 | value = cap-1; 467 | } 468 | len = print_dec_ll(buf, max, value); 469 | while(len < prec) { /* pad with zeroes, e.g. if 0.0012 */ 470 | buf[len++] = '0'; 471 | } 472 | if(len < max) 473 | buf[len++] = '.'; 474 | return len; 475 | } 476 | 477 | /** spool floating point to buffer */ 478 | static int 479 | print_float(char* buf, int max, double value, int prec) 480 | { 481 | /* as xxx.xxx if prec==0, no '.', with prec decimals after . */ 482 | /* no conversion for NAN and INF, because we do not want to require 483 | linking with -lm. */ 484 | /* Thus, the conversions use 64bit integers to convert the numbers, 485 | * which makes 19 digits before and after the decimal point the max */ 486 | unsigned long long whole = (unsigned long long)value; 487 | double remain = value - (double)whole; 488 | int len = 0; 489 | if(prec != 0) 490 | len = print_remainder(buf, max, remain, prec); 491 | len += print_dec_ll(buf+len, max-len, whole); 492 | return len; 493 | } 494 | 495 | /** print %f */ 496 | static void 497 | print_num_f(char** at, size_t* left, int* ret, double value, 498 | int minw, int precision, int prgiven, int zeropad, int minus, 499 | int plus, int space) 500 | { 501 | char buf[PRINT_FLOAT_BUFSZ]; 502 | int negative = (value < 0); 503 | int zero = 0; 504 | int len; 505 | if(!prgiven) precision = 6; 506 | len = print_float(buf, (int)sizeof(buf), negative?-value:value, 507 | precision); 508 | print_num(at, left, ret, minw, 1, 0, zeropad, minus, 509 | plus, space, zero, negative, buf, len); 510 | } 511 | 512 | /* rudimentary %g support */ 513 | static int 514 | print_float_g(char* buf, int max, double value, int prec) 515 | { 516 | unsigned long long whole = (unsigned long long)value; 517 | double remain = value - (double)whole; 518 | int before = 0; 519 | int len = 0; 520 | 521 | /* number of digits before the decimal point */ 522 | while(whole > 0) { 523 | before++; 524 | whole /= 10; 525 | } 526 | whole = (unsigned long long)value; 527 | 528 | if(prec > before && remain != 0.0) { 529 | /* see if the last decimals are zero, if so, skip them */ 530 | len = print_remainder(buf, max, remain, prec-before); 531 | while(len > 0 && buf[0]=='0') { 532 | memmove(buf, buf+1, --len); 533 | } 534 | } 535 | len += print_dec_ll(buf+len, max-len, whole); 536 | return len; 537 | } 538 | 539 | 540 | /** print %g */ 541 | static void 542 | print_num_g(char** at, size_t* left, int* ret, double value, 543 | int minw, int precision, int prgiven, int zeropad, int minus, 544 | int plus, int space) 545 | { 546 | char buf[PRINT_FLOAT_BUFSZ]; 547 | int negative = (value < 0); 548 | int zero = 0; 549 | int len; 550 | if(!prgiven) precision = 6; 551 | if(precision == 0) precision = 1; 552 | len = print_float_g(buf, (int)sizeof(buf), negative?-value:value, 553 | precision); 554 | print_num(at, left, ret, minw, 1, 0, zeropad, minus, 555 | plus, space, zero, negative, buf, len); 556 | } 557 | 558 | 559 | /** strnlen (compat implementation) */ 560 | static int 561 | my_strnlen(const char* s, int max) 562 | { 563 | int i; 564 | for(i=0; i 1) { 629 | *at++ = *fmt++; 630 | left--; 631 | } else fmt++; 632 | ret++; 633 | } 634 | 635 | /* see if we are at end */ 636 | if(!*fmt) break; 637 | 638 | /* fetch next argument % designation from format string */ 639 | fmt++; /* skip the '%' */ 640 | 641 | /********************************/ 642 | /* get the argument designation */ 643 | /********************************/ 644 | /* we must do this vararg stuff inside this function for 645 | * portability. Hence, get_designation, and print_designation 646 | * are not their own functions. */ 647 | 648 | /* printout designation: 649 | * conversion specifier: x, d, u, s, c, m, p 650 | * flags: # not supported 651 | * 0 zeropad (on the left) 652 | * - left adjust (right by default) 653 | * ' ' printspace for positive number (in - position). 654 | * + alwayssign 655 | * fieldwidth: [1-9][0-9]* minimum field width. 656 | * if this is * then type int next argument specifies the minwidth. 657 | * if this is negative, the - flag is set (with positive width). 658 | * precision: period[digits]*, %.2x. 659 | * if this is * then type int next argument specifies the precision. 660 | * just '.' or negative value means precision=0. 661 | * this is mindigits to print for d, i, u, x 662 | * this is aftercomma digits for f 663 | * this is max number significant digits for g 664 | * maxnumber characters to be printed for s 665 | * length: 0-none (int), 1-l (long), 2-ll (long long) 666 | * notsupported: hh (char), h (short), L (long double), q, j, z, t 667 | * Does not support %m$ and *m$ argument designation as array indices. 668 | * Does not support %#x 669 | * 670 | */ 671 | minw = 0; 672 | precision = 1; 673 | prgiven = 0; 674 | zeropad = 0; 675 | minus = 0; 676 | plus = 0; 677 | space = 0; 678 | length = 0; 679 | 680 | /* get flags in any order */ 681 | for(;;) { 682 | if(*fmt == '0') 683 | zeropad = 1; 684 | else if(*fmt == '-') 685 | minus = 1; 686 | else if(*fmt == '+') 687 | plus = 1; 688 | else if(*fmt == ' ') 689 | space = 1; 690 | else break; 691 | fmt++; 692 | } 693 | 694 | /* field width */ 695 | if(*fmt == '*') { 696 | fmt++; /* skip char */ 697 | minw = va_arg(arg, int); 698 | if(minw < 0) { 699 | minus = 1; 700 | minw = -minw; 701 | } 702 | } else while(*fmt >= '0' && *fmt <= '9') { 703 | minw = minw*10 + (*fmt++)-'0'; 704 | } 705 | 706 | /* precision */ 707 | if(*fmt == '.') { 708 | fmt++; /* skip period */ 709 | prgiven = 1; 710 | precision = 0; 711 | if(*fmt == '*') { 712 | fmt++; /* skip char */ 713 | precision = va_arg(arg, int); 714 | if(precision < 0) 715 | precision = 0; 716 | } else while(*fmt >= '0' && *fmt <= '9') { 717 | precision = precision*10 + (*fmt++)-'0'; 718 | } 719 | } 720 | 721 | /* length */ 722 | if(*fmt == 'l') { 723 | fmt++; /* skip char */ 724 | length = 1; 725 | if(*fmt == 'l') { 726 | fmt++; /* skip char */ 727 | length = 2; 728 | } 729 | } 730 | 731 | /* get the conversion */ 732 | if(!*fmt) conv = 0; 733 | else conv = *fmt++; 734 | 735 | /***********************************/ 736 | /* print that argument designation */ 737 | /***********************************/ 738 | switch(conv) { 739 | case 'i': 740 | case 'd': 741 | if(length == 0) 742 | print_num_d(&at, &left, &ret, va_arg(arg, int), 743 | minw, precision, prgiven, zeropad, minus, plus, space); 744 | else if(length == 1) 745 | print_num_ld(&at, &left, &ret, va_arg(arg, long), 746 | minw, precision, prgiven, zeropad, minus, plus, space); 747 | else if(length == 2) 748 | print_num_lld(&at, &left, &ret, 749 | va_arg(arg, long long), 750 | minw, precision, prgiven, zeropad, minus, plus, space); 751 | break; 752 | case 'u': 753 | if(length == 0) 754 | print_num_u(&at, &left, &ret, 755 | va_arg(arg, unsigned int), 756 | minw, precision, prgiven, zeropad, minus, plus, space); 757 | else if(length == 1) 758 | print_num_lu(&at, &left, &ret, 759 | va_arg(arg, unsigned long), 760 | minw, precision, prgiven, zeropad, minus, plus, space); 761 | else if(length == 2) 762 | print_num_llu(&at, &left, &ret, 763 | va_arg(arg, unsigned long long), 764 | minw, precision, prgiven, zeropad, minus, plus, space); 765 | break; 766 | case 'x': 767 | if(length == 0) 768 | print_num_x(&at, &left, &ret, 769 | va_arg(arg, unsigned int), 770 | minw, precision, prgiven, zeropad, minus, plus, space); 771 | else if(length == 1) 772 | print_num_lx(&at, &left, &ret, 773 | va_arg(arg, unsigned long), 774 | minw, precision, prgiven, zeropad, minus, plus, space); 775 | else if(length == 2) 776 | print_num_llx(&at, &left, &ret, 777 | va_arg(arg, unsigned long long), 778 | minw, precision, prgiven, zeropad, minus, plus, space); 779 | break; 780 | case 's': 781 | print_str(&at, &left, &ret, va_arg(arg, char*), 782 | minw, precision, prgiven, minus); 783 | break; 784 | case 'c': 785 | print_char(&at, &left, &ret, va_arg(arg, int), 786 | minw, minus); 787 | break; 788 | case 'n': 789 | /* unsupported to harden against format string 790 | * exploitation, 791 | * handled like an unknown format specifier. */ 792 | /* *va_arg(arg, int*) = ret; */ 793 | break; 794 | case 'm': 795 | print_str(&at, &left, &ret, strerror(errno), 796 | minw, precision, prgiven, minus); 797 | break; 798 | case 'p': 799 | print_num_llp(&at, &left, &ret, va_arg(arg, void*), 800 | minw, precision, prgiven, zeropad, minus, plus, space); 801 | break; 802 | case '%': 803 | print_pad(&at, &left, &ret, '%', 1); 804 | break; 805 | case 'f': 806 | print_num_f(&at, &left, &ret, va_arg(arg, double), 807 | minw, precision, prgiven, zeropad, minus, plus, space); 808 | break; 809 | case 'g': 810 | print_num_g(&at, &left, &ret, va_arg(arg, double), 811 | minw, precision, prgiven, zeropad, minus, plus, space); 812 | break; 813 | /* unknown */ 814 | default: 815 | case 0: break; 816 | } 817 | } 818 | 819 | /* zero terminate */ 820 | if(left > 0) 821 | *at = 0; 822 | return ret; 823 | } 824 | -------------------------------------------------------------------------------- /strlcat.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strlcat.c,v 1.19 2019/01/25 00:19:25 millert Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1998, 2015 Todd C. Miller 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | /* 23 | * Appends src to string dst of size dsize (unlike strncat, dsize is the 24 | * full size of dst, not space left). At most dsize-1 characters 25 | * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). 26 | * Returns strlen(src) + MIN(dsize, strlen(initial dst)). 27 | * If retval >= dsize, truncation occurred. 28 | */ 29 | size_t 30 | strlcat(char *dst, const char *src, size_t dsize) 31 | { 32 | const char *odst = dst; 33 | const char *osrc = src; 34 | size_t n = dsize; 35 | size_t dlen; 36 | 37 | /* Find the end of dst and adjust bytes left but don't go past end. */ 38 | while (n-- != 0 && *dst != '\0') 39 | dst++; 40 | dlen = dst - odst; 41 | n = dsize - dlen; 42 | 43 | if (n-- == 0) 44 | return(dlen + strlen(src)); 45 | while (*src != '\0') { 46 | if (n != 0) { 47 | *dst++ = *src; 48 | n--; 49 | } 50 | src++; 51 | } 52 | *dst = '\0'; 53 | 54 | return(dlen + (src - osrc)); /* count does not include NUL */ 55 | } 56 | -------------------------------------------------------------------------------- /strlcpy.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strlcpy.c,v 1.16 2019/01/25 00:19:25 millert Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1998, 2015 Todd C. Miller 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | /* 23 | * Copy string src to buffer dst of size dsize. At most dsize-1 24 | * chars will be copied. Always NUL terminates (unless dsize == 0). 25 | * Returns strlen(src); if retval >= dsize, truncation occurred. 26 | */ 27 | size_t 28 | strlcpy(char *dst, const char *src, size_t dsize) 29 | { 30 | const char *osrc = src; 31 | size_t nleft = dsize; 32 | 33 | /* Copy as many bytes as will fit. */ 34 | if (nleft != 0) { 35 | while (--nleft != 0) { 36 | if ((*dst++ = *src++) == '\0') 37 | break; 38 | } 39 | } 40 | 41 | /* Not enough room in dst, add NUL and traverse rest of src. */ 42 | if (nleft == 0) { 43 | if (dsize != 0) 44 | *dst = '\0'; /* NUL-terminate dst */ 45 | while (*src++) 46 | ; 47 | } 48 | 49 | return(src - osrc - 1); /* count does not include NUL */ 50 | } 51 | -------------------------------------------------------------------------------- /ws.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | edx ( small ws clone EDitor for X), (C) 2003, Terry Loveall 4 | released into the public domain. This program comes with no warranties or 5 | binaries. Compile and use at your own risk. 6 | */ 7 | 8 | #ifndef EXTHELP 9 | /* Help screen -- rewrite to suit your own tastes */ 10 | 11 | static char HELP_STR[] = "ws clone EDX (EDitor for X) Ver. "VERSION"\0\ 12 | Usage: edx [-fn font] [-j line#] [-t tab#] [-w width] [-h height] [-bg color]\0\ 13 | [-fg color] [-hibg color] [-hifg color] [-cur color] [-rc rcfile] [file]\0\ 14 | ^O[mfoctbnaw] (Mod, Fill, Ovrwrit, Case, Tab, Blk mk, Ndent, repl All, Word)\0\ 15 | *NOTE: M flag must be reset to exit or load new file.\0\ 16 | F6 Chgdir Alt-? show Alt key bindings ^QX switch block marks\0\ 17 | ^QS goto bol ^KQ or ^KX exit ^KH F1 show help ^F1 Mrk&Opn Str\0\ 18 | ^QD goto eol ^KB mark block on ^KR read file\0\ 19 | ^QR start of file ^KK mark block off ^KF save as\0\ 20 | ^QC end of file ^KY cut block ^KS F2 save & resume\0\ 21 | ^QF find ^KC copy block ^KZ F10 rxvt\0\ 22 | ^QA find & repl ^KV paste block F4 find matching\0\ 23 | ^QY del to eol ^KW write block F5 exec command\0\ 24 | ^QM get margin ^KT get tab size ^QP goto prev pos\0\ 25 | ^QU uppercase blk ^QL lowercase blk ^QT transpose characters\0\ 26 | Shift-Del cut ^Ins copy Shift-Ins paste F3 open new file\0\ 27 | ^A word left ^R page up ^Z scroll up ^I insert tab\0\ 28 | ^F word right ^C page down ^W scroll dn ^J goto line\0\ 29 | ^T del word ^D right ^V toggle insert ^L repeat find\0\ 30 | ^G del char ^S left ^M ^N put newline ^B reformat para\0\ 31 | ^H del prev char ^E up ^KP play macro ^U undo\0\ 32 | ^Y delete line ^X down ^KM togl rec mac Alt-U redo\0\ 33 | Press any key to continue ..."; 34 | #endif /* EXTHELP */ 35 | 36 | /* include the editor engine */ 37 | #include "eeng.c" 38 | 39 | /* Wordstar bindings */ 40 | 41 | #ifdef GREEK 42 | /* similar to Ctrl-C under emacs... */ 43 | void ctrlc_key(int key) 44 | { 45 | key_greek(key); 46 | doCtrlC = var_greek; 47 | } 48 | #endif /* GREEK */ 49 | 50 | /* ctrl K keys */ 51 | void ctrlk_key(int key) 52 | { 53 | switch(key | 0x60) { 54 | case 'b': block_mark(); break; /* ^K^B set mark block on */ 55 | case 'c': set_selection(); /* ^K^C block copy to X clipboard */ 56 | block_copy(0); break; /* and to bbuffer */ 57 | case 'd': flag[CHG]=0; break; /* ^K^D say file not changed */ 58 | case 'f': file_save(-1,0); break; /* ^K^F save as */ 59 | #ifdef GREEK 60 | case 'g': doCtrlC = 1; break; /* ^K^G Greek char */ 61 | #endif /* GREEK */ 62 | case 'h': show_help(0); break; /* ^K^H show help menu */ 63 | case 'k': block_mark(); break; /* ^K^K set mark block on */ 64 | case 'm': key_macros(1); break; /* ^K^M record macro */ 65 | case 'p': key_macros(0); break; /* ^K^P play macro */ 66 | case 'q': sys_exit(0); break; /* ^K^Q exit only if file saved */ 67 | case 'r': block_read(); break; /* ^K^R read file into cursor pos */ 68 | case 's': do_save(); break; /* ^K^S save file and resume */ 69 | case 't': tab_size(); break; /* ^K^T get tab size */ 70 | case 'v': block_paste(); break; /* ^K^V copy buffer to cursor */ 71 | case 'w': block_write(); break; /* ^K^W write block to disk */ 72 | case 'x': sys_exit(0); break; /* ^K^X exit only if file saved */ 73 | case 'y': block_copy(1); break; /* ^K^Y cut block to buffer */ 74 | #ifdef MINIMAL 75 | case 'z': mterm(); break; /* ^K^Z open an rxvt term */ 76 | #endif 77 | } 78 | doCtrlK = 0; 79 | show_top(); 80 | } 81 | 82 | /* ctrl Q keys */ 83 | void ctrlq_key(int key) 84 | { 85 | switch(key | 0x60) { 86 | case 'a': goto_replace(0); break; /* ^Q^A replace */ 87 | case 'c': goto_y(ytot); /* ^Q^C eof */ 88 | case 'd': goto_x(strlen(line_start+1)+1); break; /* ^Q^D eol */ 89 | case 'f': goto_search(0); break; /* ^Q^F find */ 90 | case 'i': goto_line(); break; /* ^Q^I goto line */ 91 | case 'l': chg_case(0); break; /* ^Q^L lower case block */ 92 | case 'm': window_size(); break; /* ^Q^M get right margin */ 93 | case 'p': goto_last(); break; /* ^Q^P goto last pos */ 94 | case 'r': top(); /* ^Q^R bof */ 95 | case 's': goto_x(1); break; /* ^Q^S bol */ 96 | case 't': transpose(); break; /* ^Q^T transpose chars */ 97 | case 'u': chg_case(1); break; /* ^Q^L upper case block */ 98 | case 'x': twist_pos(); break; /* ^Q^X switch between block marks */ 99 | case 'y': key_delword(1); break; /* ^Q^Y delete to end of line */ 100 | } 101 | doCtrlQ = 0; 102 | show_top(); 103 | } 104 | 105 | /* Alt key bindings */ 106 | void key_alt(int key) 107 | { 108 | #ifdef MINIMAL 109 | switch(key) { 110 | case 'c': SYSTEM("xcalc"); break; /* Alt-C xcalc*/ 111 | case 'd': newedit("/c/text/phone.dir"); break; /* Alt-D phone Dir */ 112 | case 'l': SYSTEM("xcalendar"); break; /* Alt-L xcalendar */ 113 | case 'u': redo(); break; /* Alt-U redo */ 114 | } 115 | #else 116 | char b[1024]; 117 | if (key=='?') { show_help(1); return; } 118 | if (key=='u') { redo(); return; } 119 | if (key>=0x20) key = (key|0x60)-'a'; 120 | if (key>=0 && key<26) if (binding[key]) { 121 | snprintf(b, sizeof b, binding[key], (cfdpath? cfdpath : "./"), ewin.name); 122 | SYSTEM(b); 123 | } 124 | #endif /* MINIMAL */ 125 | } 126 | 127 | void oblk() 128 | { 129 | // if shift not pressed turn off marked block 130 | if(!(keve->state & ShiftMask) && flag[BLK]) mark_off(); 131 | } 132 | 133 | /* Shift, control and bare Function keys */ 134 | void key_func(int key) 135 | { 136 | if(keve->state & ShiftMask) 137 | switch(key) { 138 | case XK_Insert : do_paste(); return; /* Shift Ins paste */ 139 | case XK_Delete : do_select(1); return; /* Shift Del cut */ 140 | } 141 | if((keve->state & ShiftMask) && !flag[BLK] && 142 | key >= XK_Home && key <= XK_End) block_mark(); /* enable marked block with Shift */ 143 | if(keve->state & ControlMask) { 144 | switch(key) { 145 | case XK_F1 : word_marknopen(); break; /* ^F1 mark cursor word & open */ 146 | case XK_F3 : file_save(0,1); break; /* ^F3 open new file */ 147 | case XK_Home : top(); break; /* ^Home bof */ 148 | case XK_End : goto_y(ytot); break; /* ^End eof */ 149 | case XK_Left : word_left(); break; /* ^Left word left */ 150 | case XK_Right : word_right(); break; /* ^Right word right */ 151 | case XK_Insert : do_select(0); break; /* ^Ins copy */ 152 | } 153 | } else 154 | switch(key) { 155 | case XK_F1 : show_help(0); break; /* F1 show help */ 156 | case XK_F2 : do_save(); break; /* F2 save file and resume */ 157 | case XK_F3 : newfile(); break; /* F3 open new edx */ 158 | case XK_F4 : find_match(); break; /* F4 find matching bracket */ 159 | case XK_F5 : run(); break; /* F5 get and run cmd */ 160 | case XK_F6 : chgdir(); break; /* F6 get & change to dir */ 161 | case XK_F7 : block_mark(); break; /* F7 set mark block on */ 162 | case XK_F8 : block_mark(); break; /* F8 set mark block on */ 163 | #ifdef MINIMAL 164 | case XK_F10 : mterm(); break; /* F10 open rxvt in cur.dir */ 165 | #else 166 | case XK_F10 : key_alt('z'); break; /* F10 open rxvt in cur.dir */ 167 | #endif 168 | case XK_F12 : show_flag(OVR, !flag[OVR]); break;/* Ins toggle insert mode */ 169 | case XK_Return : key_return(); break; /* Enter newline at cursor */ 170 | case XK_Tab : key_tab(0); break; /* Tab insert tab char at cursor */ 171 | case XK_BackSpace: key_backspace(); break; /* BS delete prev char */ 172 | case XK_Insert : show_flag(OVR, !flag[OVR]); break;/* Ins toggle insert mode */ 173 | case XK_Delete : key_delete(); break; /* Del delete cursor char */ 174 | case XK_Page_Up : cursor_pageup(); break; /* PgUp */ 175 | case XK_Page_Down: cursor_pagedown(); break; /* PgDn */ 176 | case XK_End : goto_x(strlen(line_start+1)+1); break;/* End eol */ 177 | case XK_Home : goto_x(1); break; /* Home bol */ 178 | case XK_Up : cursor_up(); break; /* up */ 179 | case XK_Down : cursor_down(); break; /* down */ 180 | case XK_Right : cursor_right(); break; /* right */ 181 | case XK_Left : cursor_left(); break; /* left */ 182 | } 183 | oblk(); // conditionally off block mark 184 | } 185 | 186 | /* Control keys */ 187 | void key_control(int key) 188 | { 189 | int xkey=1; 190 | switch(key|0x60) { 191 | case 'b': block_format(); break; /* reformat block */ 192 | case 'g': key_delete(); break; /* delete cursor char */ 193 | case 'h': key_backspace(); break; /* destructive backspace */ 194 | case 'i': key_tab(0); break; /* insert tab char */ 195 | case 'j': keve->state & ControlMask ? 196 | goto_line() : /* goto line# */ 197 | key_return(); break; /* newline */ 198 | case 'k': doCtrlK = key; break; /* ^K key */ 199 | case 'l': goto_find(cur_pos, 0); break; /* find again */ 200 | case 'm': 201 | case 'n': key_return(); break; /* newline at cursor */ 202 | case 'o': show_mode(); break; /* change modes */ 203 | case 'p': literal = 1; break; /* get inline literal */ 204 | case 'q': doCtrlQ = key; break; /* ^Q key */ 205 | case 't': key_delword(0); break; /* delete word/to word */ 206 | case 'u': undo(); break; /* undo */ 207 | case 'v': show_flag(OVR,!flag[OVR]); 208 | case 'w': scroll_down(); break; /* scroll down */ 209 | case 'y': block_line(); break; /* delete line */ 210 | case 'z': scroll_up(); break; /* scroll up */ 211 | break; /* toggle Insert mode */ 212 | default: xkey--; // say nothing done 213 | } 214 | if(!xkey){ 215 | oblk(); // off marked block unless shift key pressed 216 | switch(key|0x60) { 217 | case 'a': word_left(); break; /* word left */ 218 | case 'c': cursor_pagedown(); break; /* pgdn */ 219 | case 'd': cursor_right(); break; /* right */ 220 | case 'e': cursor_up(); break; /* up */ 221 | case 'f': word_right(); break; /* word right */ 222 | case 'r': cursor_pageup(); break; /* pgup */ 223 | case 's': cursor_left(); break; /* left */ 224 | case 'x': cursor_down(); break; /* down */ 225 | } 226 | } 227 | show_top(); 228 | } 229 | 230 | /* undraw, redraw status and display */ 231 | void scr_update() 232 | { 233 | if(executive == MAIN){ 234 | 235 | #ifndef TERMINAL 236 | undraw_cursor(); 237 | #endif /* TERMINAL */ 238 | /* update text buffer display */ 239 | if( flag[BLK] ) flag[SHW] = 1; 240 | if(y <= -1 || y >= screen_height) { 241 | if(y == -1) { 242 | y++; show_sdn(0); 243 | } 244 | else if(y == screen_height) { 245 | y--; show_sdn(0); 246 | } 247 | else { 248 | y = y < 0 ? 0 : screen_height-1; 249 | show_scr(0, screen_height-1); 250 | } 251 | } 252 | else if(flag[SHW] ) { 253 | show_scr(0, screen_height-1); 254 | } 255 | flag[SHW] = 0; 256 | 257 | show_pos(); 258 | gotoxy(x-1,y+y2); 259 | #ifndef TERMINAL 260 | draw_cursor(); 261 | show_vbar(); 262 | #else 263 | lowvideo(); 264 | #endif /* TERMINAL */ 265 | } 266 | } 267 | 268 | /* single char interpreter */ 269 | void main_exec(int key) 270 | { 271 | cur_pos = get_cur(); 272 | if(update_scr) { 273 | #ifndef TERMINAL 274 | undraw_cursor(); 275 | #endif /* TERMINAL */ 276 | if(flag[REC]) rec_macro(key); 277 | } 278 | if(help_done){ 279 | help_done = 0; 280 | flag[SHW] = 1; 281 | } else if(literal) { 282 | key_normal(keve->state & ControlMask ? key & 0x1f : key); 283 | literal = 0; 284 | } else { 285 | if(key & 0xFF00) key_func(key); else 286 | if(keve->state & Mod1Mask) key_alt(key); 287 | else { 288 | #ifdef GREEK 289 | /* Ctrl-C is enabled here by ^K^G */ 290 | if(doCtrlC) ctrlc_key(key); else 291 | #endif /* GREEK */ 292 | if(doCtrlK) ctrlk_key(key); else 293 | if(doCtrlQ) ctrlq_key(key); else { 294 | if(keve->state & ControlMask) key &= 0x1f; 295 | if(key >= BLNK) key_normal(key); 296 | else key_control(key); 297 | } 298 | } 299 | } 300 | if(!doCtrlK && !doCtrlQ && old_pos != line_start) { 301 | last_pos = old_pos; 302 | old_pos = line_start; 303 | } 304 | cur_pos = get_cur(); 305 | 306 | if(update_scr) scr_update(); 307 | } 308 | --------------------------------------------------------------------------------