޶-READMES1STPOSTLISTTXT 1 POSTING 0 QcZ80EMACSDOC0CCLASS H MCFGNAMESH XED H ,TGMAPPING H **MEDISP H TMEMAIN C \oMETAB H mBASIC C PIBSEARCH C uBUFFER C CCLASS C #%QCOPYREG C EFILENAMEC FILEREADC FILERITEC jFILESAVEC GFILEVISIC GETREG C SGROWWIN C $ KBUF C / KILLBUF C : KILLREG C ELDELETE C J[LDELNEWLC XLFREE C m nLINE C w0CLINSERT C @LISTBUF C /[LNEWLINEC  qLOWREG C fMEDISP C sMEMISC C  MEML C ":METAB C !xMEUPDATEC %#zMEVT C H +MEXEQ C T ` MVUPWIN C aONLYWIN C qOVBGN ASMLOVEXIT30C OVKBDM29C  OVMDLN28C  _OVMISC1 C +OVOPEN32C OVOPWR33C fOVREAD27C  OVREADINC OVUDFB31C A}xOVWORD1 C ;*OVWRIT34C Z ߻READIN C dySHRNKWINC k SPLITWINC u9[TELANSI C  OUPREG C  USEBUF C  VWINDOW C WRITEOUTC  EDOMAPKEYSUB MAPKEYS C bCMAPPING TXT &{MECONFIGC "?tMKCONFIGSUBayZMECMDS LSTcMYLIB SUBr8ALL SUByALL2 SUB LINKROOTSUB/ROOT DATLINKALL SUBSSUBS DATCThis is the "read me first" file for the Z80EMACS source distribution. It is in ZMAX-S01.LZR; The binary distribution is in ZMAX-B01.LZR so you can see this is release 0.1! Documentation: POSTLIST.TXT some file descriptors from the internet posting. Z80EMACS.DOC General intro, and commercial POSTING.0 slightly old general info from the internet posting. Other files are as described in postlist.txt. This is mostly a pro-forma source posting, because 1) You need AZTEC C to compile, and who has that? 2) Some aztec files are part of the package ( they were modified for Z80EMACS ), but they're not included here. Even if the source is not too useful, here it is -- Z80EMACS is open to the world! This package was done with AZTEC C, version 1.05c; of course it should be ported over to BDS!  Here are file descriptions from the internet source posting: ( AZTEC C files are NOT INCLUDED in this library. ) cclass.h -- character class, better for an editor than ctype.h cfgnames.h -- belongs to mapkeys.c ed.h -- microemacs main include file mapping.h -- default bindings medisp.h -- microemacs display routines, include file memain.c -- main() metab.h -- include file for programs that need to know about keystroke bindings and how they are handled. stdio.h -- modified version of aztec C 1.05c stdio.h file. It bears a copyright notice, but is of no use to anyone who doesn't have aztec C, so I think it's okay for everyone to see it. basic.c right arrow and left arrow; bound to keystrokes and also called by many overlays. bsearch.c search backwards. buffer.c this is what's left in the root segment from the original buffer.c cclass.c "ctype" type of stuff. copyreg.c "copy region" overlay command. croot.c modified AZTEC source filename.c rename file; rename buffer fileread.c read a new file into current buffer filerite.c write current buffer with new file name filesave.c save filevisi.c edit a new file in its own buffer, or, go to the buffer that already contains it. getreg.c subroutine included in the overlays of all "region" commands. growwin.c make window larger kbuf.c store and recover deleted text killbuf.c remove a buffer from the list of buffers and free its resources. killreg.c kill region ldelete.c delete "n" bytes ldelnewl.c delete a newline lfree.c free a line line.c lalloc() and lchange() linsert.c insert a character listbuf.c list active buffers lnewline.c insert newline lowreg.c lowercase region medisp.c display a line memisc.c get input meml.c message line routines metab.c binding tables. meupdate.c mevt.c mexeq.c mvupwin.c onlywin.c ovbgn.asm ovexit30.c ovkbdm29.c ovmdln28.c ovmisc1.c ovopen32.c ovopwr33.c ovread27.c ovreadin.c ovudfb31.c The most important overlay of all. ovword1.c ovwrit34.c readin.c Included by fileread... shrnkwin.c splitwin.c telansi.c televid.c ** obsolete, not included ** upreg.c usebuf.c window.c word.c ** obsolete, not included ** writeout.c Included by filesave, filerite... domapkey.sub How to compile mapkeys.c mapkeys.c Prepares a mapping of commands to keystrokes. Reads zmecmds.lst, writes maptable.zme. If you want standard emacs mappings, you have to use this program. mapping.txt My terminal has two pages of 24x80 display memory. I like to type this file to the screen and keep it available on the page that isn't used, as a quick reference guide. It's very abbreviated; TVI means TeleVideo, M-Y killbuf, TVI "PAGE ERA" means that the key labeled PAGE ERA sends escape-Y and therefore kills a buffer. meconfig.c Reads maptable.zme, patches ME.COM mkconfig.sub How to compile meconfig.c zmecmds.lst Input to mapkeys.c, this gives the UECS name and number for every command available in Z80EMACS. (cfgnames.h) It's in archive 1; cfgnames.h describes the mappings for overlays in ME.COM. It gives the UECS name, the key to which the name is bound by default, the overlay number, the function within the overlay, and the UECS command number. The default binding isn't necessarily the same as that in mapping.h. This file is included by both mapkeys.c and meconfig.c. meconfig knows the names of the built-in functions, and it finds their addresses by reading ME.SYM. Both of the programs are pretty nifty... fgets.c fopen.c fputs.c fwrite.c getbuff.c getc.c lseek.c malloc.c These files are copyright aztec C, and you have no use for them unless you have aztec C. Distributing them should do no harm. Some of them are modified to save space in the root segment. This is why you SHOULD have these files if you DO have aztec C To avoid copyright controversy, the files are slightly mangled; partial lines are obliterated, and must be reconstructed from files in your aztec C delivery. How dull, these are the .SUB files. They give an idea of what files are involved, and how the overlays are structured. MYLIB.SUB was used to make a Z80 version of the AZTEC library, with some of the subroutines customized. ALL.SUB and ALL2.SUB were used to compile "everything". LINKROOT.SUB invokes the linker to make the root segment. ROOT.DAT is used by linkroot.sub LINKALL.SUB invokes the linker to make the overlays. SUBS.DAT is used by linkall.sub all.sub was too long and had to be broken up into all.sub and all2.sub; danger, I added a few comments and either might now be too long. all.sub is not quite up-to-date. In linkall.sub, you will see that not all the ".o" files are mentioned in all*.sub; some ".c" files mentioned in all*.sub are also obsolete, and not supplied. The last thing I did while I was working on this was to add a few more overlays. By force, they had to be in linkall.sub; but until I recompiled everything, they didn't have to be in all*.sub. That's why the sub files didn't get updated.  This is the first posting of the Z80 microemacs source. 1. HISTORY I started with microemacs 3.6, which said " * This program is in public domain; written by Dave G. Conroy." All the files being edited in the buffers are kept in memory; it was fairly easy to compile the version of microemacs I used, and produce a runnable program, but the first version had no space at all for files! (March 1989). Porting to cp/m was easy because I used AZTEC C ( version 1.05c, from 1982 ). I really would have preferred BDS/C because compilation is so fast, but: no static initializers, no typedefs, no "long"... I'm not sure if BDS has overlays. If BDS has overlays, it would be worth while porting my version to BDS. If it doesn't, an overlay system could be added. I started making overlays and optimizing, and soon ( June 1989 ) could edit about 24KB of one file ( 58KB TPA ). As soon as I could edit 3K, I started using the editor to maintain itself; editors are always well-tested if you use them to maintain themselves. This is why the original files were split up into very small pieces, and some comments removed. The comments removed include the microemacs authors' names, but microemacs is freely available with attribution. No attempt to hide the origin is intended. I think the version of microemacs I used was 3.6, but I can't be sure. Then I stopped and created a program for customization of the binaries, figuring to distribute the z80me program in that fashion. There is one customization program that patches terminal-control sequences into the binary, and another that patches keystroke-to-command bindings. I could find no CP/M BBS to post it to, and gave up. ( July 1989 ). Documentation was never written, especially for the customization, and now I have to work from memory. In fact, I find no program to patch terminal-control; the term-control module was written to make this possible, though. In August or September, 1991, I saw a message in comp.os.cpm asking about editors. I posted a notice about microemacs for cp/m and got many helpful and encouraging replies. ---------------------------- 2. PHILOSOPHY AND FEATURES This program also embodies some of my thoughts about the nature of editors. Programmers use the editor more than any tool, and think about it less than any other. Even with a simple editor like vi, most programmers don't bother to learn every command... The version of microemacs that I started with was an awful editor, and I hated it. Some things had to change if I was to use it, so I changed them. If an editor's bindings are perfect from the standpoint of having neat little mnemonics ( ^N for "next line" ), they may are unlikely to be perfect from the standpoint of making frequently-used commands easy to type. A prime example is the emacs binding of Meta-f for "word forwards"; this is a frequently-used command, and should be ONE KEYSTROKE! The default Z80EMACS word forward is ^F, word back is ^B, del word forward is ^W. If an editor's bindings are perfect from both of the above standpoints, they still will run into trouble with the keyboard: yes, the dreaded ARROW KEYS. If you're alert, and leaning forward over the keyboard, you may not want to use the arrow keys; such is the argument in favor of vi's "hjkl". If you're thinking instead of typing, browsing instead of hacking, you want the arrow keys to work. Z80EMACS has predefined arrow keys that fit most ASCII terminals, ^H^J^K^L, and ^V the same as ^J. If a command is hard to type, so what? If you use it twice in a row, simply use the "REPEAT LAST COMMAND" key! It appears that I never put this feature into Z80EMACS. vi has two different kinds of word commands, "W" and "w" ( it also provides forward, backward, and forward-to-end directions for them ). Z80EMACS has word-forward and word-backward commands, just two commands, but there is another command that changes the way these two work -- you can use vi-style or emacs-style words, and stop at end-of-word or at beginning-of-word. Z80EMACS doesn't implement the vi ^^ ( control-carat ) command, that you use to toggle between buffers, but it does have the vi :n command, that you use to sequentially walk the linked list of buffers. It is inexcusable for any editor to be without at least one of these two commands. Both commands SHOULD exist. Z80EMACS can display more than one buffer on the screen at the same time; this capability was part of the original microemacs. With more than one buffer on the screen, however, you must remember to type very slowly! Z80EMACS stores its keyboard macro in a file; it uses the same mechanism as the "execute-file" command, which microemacs didn't have. Keyboard macro execution is slow, but it's better than retyping commands. Storing the keyboard macro in a file means that you can use it again after you exit and restart the editor. It looks like Z80EMACS still doesn't have "execute file"; however, internally, "execfile" would use the same mechanisms that you use to execute the keyboard macro from a file, and so "exec file" can be added with relative ease. Z80EMACS makes ".BAK" files when it saves or writes. Z80EMACS has the "vikill" command; kills whole lines, no matter where the cursor is in the line. I despise the emacs ^K command, except when used as "kill-to-end" ( the emacs-style kill is still there ). Z80EMACS has funny vertical arrows. Up-arrow moves two lines. Both up-arrow and down-arrow can wrap from the last line of the buffer to the first line. These are both bugs that would have been easy to fix; both are interesting features. I put the funny up-arrow in my unix version of emacs, and used it for at least a year before deciding I didn't like it after all ( it was that close to being a wash! ). The idea is, if you don't specify a parameter, up-arrow moves by two lines; if you do specify, it moves the correct number. If you want to move up 1, 2, 3, 4, 5, or 6 lines, it takes 2, 1, 3, 2, 4, or 3 keystrokes instead of 1, 2, 3, 4, 5, or 6 keystrokes; an average savings of one keystroke per line. However, moving up 1 line is the most common case, and the extra mental effort involved in overshooting and moving down one is distracting. ( As I type this, I have funny-up-arrow in effect on UNIX; you really do get used to it. ) Z80EMACS has two different command introducers; one for positive values ( ^U, "universal parameter" ), one for negative ( ^\ ). Many commands have special meanings with negative parameters. According to my editor theories, it's easier to learn and remember some of the odd commands if they're shoehorned onto normal commands with special parameters. For example, take the "go-to-start-of-line" command, with the normal emacs binding of ^A; if you just enter ^A with no parameters, you go to column 0; with the "shoehorn" theory in effect, if you specify a positive parameter, you go to column N, and if you specify a negative parameter, you go to the first non-white-space character in the line. I feel this is better than having three separate commands ( vi "0", "|", and "_", respectively. Metadigits start arguments. They start arguments between those who like their emacs to accept escape-9 as a command, and those who like it to supply an argument of 9 to the next command. I am in the latter camp, so in Z80EMACS, Metadigits start arguments. Z80EMACS has the vi "find-character-in-line" command. Z80EMACS has the "goto line by line number" command. (but doesn't display line numbers, so it's not as useful a command as it should be). Z80EMACS allows you to change the buffer name as well as the file name. Z80EMACS has the vi "go to column number" command: "go to start of line" with a positive parameter goes to a specific column in the line. ( with a negative parameter, it goes to end-of-line. ) ----------------------------------------------- Alas, no regular expressions, no search-replace. ----------------------------------------------- 3. OPTIMIZATION TO SAVE SPACE In order to have more room for editing files, the program had to be made smaller. A large part of this was done by moving things to overlays, but some of it was pure byte-squeezing. Most of the optimization was done in the root segment, but several overlays were optimized to make the overlay area smaller. The key to good performance with overlays is to have all the most-often-used commands in one overlay: this is ovudfb31.c ( overlay up down forward back, overlay 31 ) Almost every file was touched. Simple things like "putting the most-often-used structure member first in the structure" can save a lot of bytes. Using exactly the right number of register variables helps. Making exactly the right variables into registers helps. You have to experiment with your compiler... #define temp_int (*(int *)0xc0) saves bytes, compared to a stack variable; if ZCPR uses this area, too bad. I used a simple CP/M 2.2, with CCPPLUS, and the original ( Digital Research ) BDOS. I used zsid on the program to find out where in main() the main processing loop starts, and used up those addresses as variable addresses; I also discovered that nobody was using 0xc0 to 0xcf, and used those locations as well. Using temporary variables instead of repeated curwp->w_bufp->b_dotp->something->something_else saves a lot of bytes. Rewriting the whole thing with a better algorithm also saves a lot sometimes! When microemacs lengthens a line, or when it creates a new line, it allocates 16 bytes. Z80EMACS allocates 4 bytes. The savings is tremendous, especially when there are blank lines in the file. This is in line.c; for a while, I had COHERENT 3.0, which came with microemacs 3.8 as its only editor. I made the same change there, because they only had small-model compiler, and it dumped core! The AZTEC C library was available in source form. I chopped it down by quite a few bytes. Goodbye, stderr! Replacing shared, duplicated code with a "goto" is an optimization that a real C compiler will perform. The one that comes free with UNIX doesn't do it, and neither does CP/M AZTEC C. ( "gcc" does, though. ) Making the messages more terse saves bytes! 4. STRUCTURE OF THE PROGRAM AND OF THE POSTINGS comp.os.cpm isn't a "source-files" newsgroup. The whole source adds up to just under 600KB, uncompressed. One is not supposed to post so much to comp.os.cpm... I don't have direct internet access, so I can't just pop it into an archive site. I've decided to handle the source by mailing it to a volunteer >> acknowledged in the Internet version ofthis file << who can simply stick it into an internet archive site. This will be part00, and it will run to about 8 parts. The Z80EMACS editing system now consists of 3 ".COM" files, a slew of overlay files, a text data file, a ".SYM" file, source of one module, and minimal documentation. It supports ASCII and ANSI terminals, but the user has to patch it by hand; this uses the source file and the ".SYM" file. Binding of keystrokes to editor commands is a two-step procedure, using two of the ".COM" files, the text file, and the ".SYM" file. mapkeys.com makes a mapping, writing it to an intermediate file; meconfig.com uses the intermediate file to patch ME.COM. Z80EMACS can find its overlays if they are on the current drive, on drive a:, or on drive b:, or on drive c:, but only ( I think ) in the current user area -- checking other user areas is a job for a more advanced BDOS than the one I used, not a job for an application program. There are only two known bugs: 1. Random crashes, about once every three or four hours. No clues, and it doesn't happen often enough to make it easy to track down. 2. The file you name on the command line doesn't get read in. The buffer gets named okay, but the file is never read. Note: both the bugs were fixed since the above was written. Several other things were also corrected. This is a CP/M, Z80 version of emacs, derived from microemacs version 3.6; the CP/M version was created by Ralph Betza in 1989. Z80EMACS is an editor, not a word processor. It's also not really finished, although as it stands it works quite well and is more feature-rich than any other CP/M editor. ( No, it doesn't have wordprocessing features; it's an editor, not... ). This is a good place for a commercial: Z80EMACS isn't quite finished; it lacks several features that I think any decent editor really ought to have ( but few do ). If enough people send checks to Ralph Betza 646 11th Avenue New Hyde Park, NY, 11040 there will be another release of Z80EMACS, with new features, and with fixes ( if any are needed ;-) I won't do it if nobody cares, but I'll work for a buck an hour on it if enough people do care. This isn't shareware, so don't feel guilty... End of commercial. Z80EMACS is a so-called "modeless" editor, like WordStar and VDE; control characters are commands, and printable characters get put into the file. Here are some of the features of Z80EMACS that make it so much more powerful than what you're used to seeing on CP/M: 1. As in any version of emacs, you can use Z80EMACS to edit more than one file at a time; not all of the files being edited need to be on the screen at the same time, but more than one of them can be -- Given that there are 24 screen lines available, and each file shown must get at least 2 lines of the screen, you could get up to 12 files shown at once. ( You wouldn't want to, but you could ). Two files at once on the screen is usually enough -- an include file and a program. Two files at once being edited is often not enough; the number of files in Z80EMACS is limited only by available memory. In EMACS, we like to call each file a "buffer". You can be editing text that doesn't have a filename. ( You'll find there are uses for this ). It's easy to copy or move text from one file to another. 2. You can reconfigure Z80EMACS; if you want ^N to be the down-arrow key, you can have what you want. See MAPKEYS.DOC for details. 3. When you delete text, you can get it back; this is great if you made a mistake, and it's also part of the method used to move or copy text. 4. Up-arrow and down-arrow move straight up and down the screen -- like WordStar, not like VDE ( unless VDE fixed this since 1989 ). 5. Variable tabs ( sorry, only by inserting N spaces, not by displaying tabs as different numbers of spaces on the screen while having tabs in the file -- next release, maybe ). 6. "Word" commands can work in any of 4 ways, at your pleasure. There are 7 different "word" commands. 7. Z80EMACS can remember one position in each window, and one position in each file that's not shown on the screen. In EMACS, we like to call this remembered position a "mark". 8. Lots of "region" commands: the area between the cursor and the "mark" is called the "current region". There are currently only 5 things you can do to the current region, but wait for next release... The emacs "region" concept is similar to the WordStar "block" concept. Each way of doing things has its own advantages and disadvantages. 9. The emacs "keyboard macro": you tell Z80EMACS to start remembering what you type, do your normal editing commands, tell it to stop remembering, and you can execute the same sequence again. Much better than VDE macros. Z80EMACS saves its keyboard macro in a file, so you can use it again tomorrow. 10. When you try to exit, Z80EMACS asks for confirmation if any of your files are modified -- and it's smart enough to keep its mouth shut if you already saved everything. 11. Z80EMACS has 9 "Display Control" commands, to let you control windows, a bunch of "session control" commands ( some are mistakenly labeled as editing comands in ZMECMDS.LST, I'd say there are about 10 session control commands in all ), to let you control the buffers and the files in them, and more editing commands than you're likely to use. 12. Z80EMACS lets you give parameters to the commands. The parameters are numeric. For example, if you type ^U60+ at the start of a line, you get ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ( notice that even the printable characters are ordinary commands ). 13. Source code for Z80EMACS is available. You should be able to find it in the same place you found the binaries. ============================================================ There are other advantages, but these are the most important. The rest of what I'm going to say is good news/bad news: Z80EMACS is a big program, and it uses overlays; that's bad if you use floppies, good if you have a ramdisk. It's good in either case because it makes it easier to expand Z80EMACS; you could even add an overlay without recompiling, using MAPKEYS.COM to get the new overlay invoked. Despite the overlays, performance is good; all the most-frequently-used commands are in the same overlay, and the overlays are small, so they don't take a lot of time to read in. Z80EMACS keeps all file data in memory, in linked lists of lines. "In memory" is faster than a temporary file, but limits the size; with my 60KB TPA, I can edit 22542 bytes in 824 lines of one file ( the same file I always use to test this after I've tried to improve these figures ), or fewer bytes spread over more files. Of course, the size limit encourages modular programming... "Linked lists" are okay because most operations on the file use sequential access. A pointer array would have plusses and minuses. If there is more than one window on the screen showing the same file that you're typing in, and if you type at all quickly, you will lose characters. This only happens if more than one window is showing the current buffer, which is an uncommon situation. Documentation could be better, but then, it could be worse. Ralph Betza, October 4, 1991 #define c_SIMPLE 0x01 /* 1 screen char */ #define c_CWORD 0x02 /* alphanumeric or _ */ #define c_WHITE 0x04 #define c_TAB 0x08 #define c_LOWC 0x10 #define c_ALPHA 0x20 #define c_DIGIT 0x40 #define c_FENCE 0x80  { "EC-Goto-Beginning-Of-Line", 0, 31, 12, 142 }, { "EC-Word-Back", 2, 31, 3, 282 }, { "EC-Goto-Next-Page", 3, 31, 10, 161 }, { "EC-Kill-Char-Forw", 4, 31, 6, 212 }, { "EC-Goto-End-Of-Line", 5, 31, 13, 144 }, { "EC-Word-Forw", 6, 31, 2, 283 }, { "EC-TAB", 9, 31, 40, 263 }, { "EC-Arrow-Down", 10, 31, 0, 79 }, { "EC-Arrow-Up", 11, 31, 1, 82 }, { "EC-CR-With-Indent", 13, 31, 42, 93 }, { "EC-Forward-Search-Simple", 14, 2, 0, 129 }, { "EC-Open-Lines", 15, 31, 41, 224 }, { "EC-Backward-Search-Simple", 16, 1, 0, 91 }, { "EC-Page-Backward", 'r'&0x1f, 31, 11, 180 }, { "EC-Grab-From-Stack", 'y'&0x1f, 31, 44, 192 }, { "EC-Exchange-Local-Mark", CTLX|('x'&0x1f), 31, 46, 103 }, { "SC-SwitchTo-Next-Sequential-Buffer", -1, 16, 1, 495 }, { "EC-Kill-Char-Back", 0x7f, 31, 7, 211 }, { "EC-Set-LocalMark", META|' ', 31, 45, 255 }, { "DC-Reposit-Top", -1, 14, 1, 63 }, { "EC-Goto-First-Buffer-Line", META|'g', 31, 8, 145 }, { "EC-Goto-Last-Buffer-Line", META|'G', 31, 9, 150 }, { "EC-Kill-Word-Back", META|'b', 31, 5, 213 }, { "EC-Capitalize-Word", META|'C', 21, 2, 96 }, { "EC-Kill-Word-Forw", META|'f', 31, 4, 216 }, { "CI-Keyboard-Macro-Execute", -1, 29, 2, 36 }, { "EC-Uppercase-Region", -1, 10, 0, 276 }, { "EC-Kill-Region", -1, 3, 0, 208 }, { "EC-PickUp-Region", -1, 19, 0, 229 }, { "CI-Quote-One", META|'q', 5, 1, 235 }, { "EC-Kill-Lines-Count", -1, 31, 47, 204 }, { "EC-Kill-EOL-Emacs", -1, 31, 43, 209 }, { "EC-Set-Word-Mode", META|'W', 30, 4, 258 }, { "EC-Unset-Word-Mode", META|'w', 30, 2, 268 }, { "SC-Discard-Buffer", -1, 17, 0, 487 }, { "DC-Redraw", -1, 14, 2, 238 }, { "EC-Lower-Case-Word", -1, 21, 1, 220 }, { "EC-Uppercase-Word", -1, 21, 0, 277 }, { "EC-Transpose-Characters", -1, 7, 1, 265 }, { "UI-Buffer-Selection-Menu",CTLX|(0x1f&'b'), 4, 0, 528 }, { "EC-Exit", -1, 30, 0, 107 }, { "EC-Find-File", CTLX|(0x1f& 'f' ), 11, 0, 111 }, { "DC-Scroll-Down", CTLX|(0x1f& 'j' ), 8, 0, 64 }, { "DC-Scroll-Up", CTLX|(0x1f& 'k' ), 8, 1, 67 }, { "EC-Lower-Case-Region", -1, 6, 0, 219 }, { "SC-ReName-Buffer", CTLX|(0x1f& 'n' ), 5, 0, 240 }, { "EC-Deblank", -1, 7, 2, 98 }, { "EC-Read-File", CTLX|(0x1f& 'r' ), 20, 0, 236}, { "EC-Save-File", CTLX|'S', 9, 0, 244 }, { "EC-Write-File", CTLX|(0x1f& 'w' ), 12, 0, 286 }, { "DC-Shrink-Window", -1, 13, 0, 72 }, { "UI-Give-Statistics", CTLX|'=', 7, 0, 543 }, { "DC-Discard-Other-Window", CTLX|'1', 14, 0, 58 }, { "DC-Split-Window", CTLX|'2', 15, 0, 73 }, { "CI-Keyboard-Macro-Start", CTLX|'(', 29, 0, 34 }, { "CI-Keyboard-Macro-End", CTLX|')', 29, 1, 35 }, { "SC-Goto-Next-Window", CTLX|'j', 8, 2, 166 }, { "SC-Goto-Previous-Window", CTLX|'k', 8, 3, 186 }, { "DC-Enlarge-Window", -1, 18, 0, 59 },  #define CPM80 1 /* CP/M */ #define TELEVIDEO 1 #define CVMVAS 1 /* C-V, M-V arg. in screens. */ #define NFILEN 15 #define NBUFN 15 #define NLINE 128 #define NPAT 20 #define HUGE 1000 /* Huge number */ #define METACH 0x1B /* M- prefix, Control-[, ESC */ #define CMINUSCH 0x1c #define META 0x0200 /* Meta flag, or'ed in */ #define CTLX 0x0400 /* ^X flag, or'ed in */ #define MAGIC 0x0100 /* MAIGIC flag */ #define FALSE 0 /* False, no, bad, etc. */ #define TRUE 1 /* True, yes, good, etc. */ #define ABORT 2 /* Death, ^G, abort, etc. */ #define FIOSUC 0 /* File I/O, success. */ #define FIOFNF 1 /* File I/O, file not found. */ #define FIOEOF 2 /* File I/O, end of file. */ #define FIOERR 3 /* File I/O, error. */ #define CFCPCN 0x0001 /* Last command was C-P, C-N */ #define CFKILL 0x0002 /* Last command was a kill */ /* * There is a window structure allocated for * every active display window. The windows are kept in a * big list, in top to bottom screen order, with the listhead at * "wheadp". Each window contains its own values of dot and mark. * The flag field contains some bits that are set by commands * to guide redisplay; although this is a bit of a compromise in * terms of decoupling, the full blown redisplay is just too * expensive to run for every input character. */ typedef struct WINDOW { struct LINE *w_dotp; /* Line containing "." */ short w_doto; /* Byte offset for "." */ struct LINE *w_markp; /* Line containing "mark" */ short w_marko; /* Byte offset for "mark" */ struct WINDOW *w_wndp; /* Next window */ struct BUFFER *w_bufp; /* Buffer displayed in window */ struct LINE *w_linep; /* Top line in the window */ char w_toprow; /* Origin 0 top row of window */ char w_ntrows; /* # of rows of text in window */ char w_force; /* If NZ, forcing row. */ char w_flag; /* Flags. */ } WINDOW; #define WFFORCE 0x01 /* Window needs forced reframe */ #define WFMOVE 0x02 /* Movement from line to line */ #define WFEDIT 0x04 /* Editing within a line */ #define WFHARD 0x08 /* Better to a full display */ #define WFMODE 0x10 /* Update mode line. */ /* * Text is kept in buffers. A buffer header, described * below, exists for every buffer in the system. The buffers are * kept in a big list, so that commands that search for a buffer by * name can find the buffer header. There is a safe store for the * dot and mark in the header, but this is only valid if the buffer * is not being displayed (that is, if "b_nwnd" is 0). The text for * the buffer is kept in a circularly linked list of lines, with * a pointer to the header line in "b_linep". */ typedef struct BUFFER { struct LINE *b_dotp; /* Link to "." LINE structure */ short b_doto; /* Offset of "." in above LINE */ struct LINE *b_markp; /* The same as the above two, */ short b_marko; /* but for the "mark" */ struct BUFFER *b_bufp; /* Link to next BUFFER */ struct LINE *b_linep; /* Link to the header LINE */ char b_nwnd; /* Count of windows on buffer */ char b_flag; /* Flags */ char b_fname[NFILEN]; /* File name */ char b_bname[NBUFN]; /* Buffer name */ } BUFFER; #define BFTEMP 0x01 /* Internal temporary buffer */ #define BFCHG 0x02 /* Changed since last write */ /* * The starting position of a * region, and the size of the region in * characters, is kept in a region structure. * Used by the region commands. */ typedef struct { struct LINE *r_linep; /* Origin LINE address. */ short r_offset; /* Origin LINE offset. */ short r_size; /* Length in characters. */ } REGION; /* * All text is kept in circularly linked * lists of "LINE" structures. These begin at the * header line (which is the blank line beyond the * end of the buffer). This line is pointed to by * the "BUFFER". Each line contains a the number of * bytes in the line (the "used" size), the size * of the text array, and the text. The end of line * is not stored as a byte; it's implied. Future * additions will include update hints, and a * list of marks into the line. */ typedef struct LINE { struct LINE *l_fp; /* Link to the next line */ struct LINE *l_bp; /* Link to the previous line */ char l_size; /* Allocated size */ char l_used; /* Used size */ char l_text[1]; /* A bunch of characters. */ } LINE; #define lforw(lp) ((lp)->l_fp) #define lback(lp) ((lp)->l_bp) #define lgetc(lp, n) ((lp)->l_text[(n)]) #define lputc(lp, n, c) ((lp)->l_text[(n)]=(c)) #define llength(lp) ((lp)->l_used) extern int fillcol; /* Fill column */ extern int currow; /* Cursor row */ extern int curcol; /* Cursor column */ extern int thisflag; /* Flags, this command */ extern int lastflag; /* Flags, last command */ extern int curgoal; /* Goal for C-P, C-N */ extern int mpresf; /* Stuff in message line */ extern int sgarbf; /* State of screen unknown */ extern WINDOW *curwp; /* Current window */ extern BUFFER *curbp; /* Current buffer */ extern WINDOW *wheadp; /* Head of list of windows */ extern BUFFER *bheadp; /* Head of list of buffers */ extern BUFFER *blistp; /* Buffer for C-X C-B */ extern char pat[NPAT]; /* Search pattern */ extern BUFFER *bfind(); /* Lookup a buffer by name */ extern WINDOW *wpopup(); /* Pop up window creation */ extern LINE *lalloc(); /* Allocate a line */ extern char cclass[128]; /* the OV macro is for overlays; the BI macro is for built-ins */ #ifdef OLDMAP BI( 0x1f&'@', &gotobol ) /* ZMAP */ /* ^A == TVI magic prefix */ BI( 0x1f&'B', &backword ) /* ZMAP */ OV( 0x1f&'C', 23, 2 ) /* forwpage ZMAP */ BI( 0x1f&'D', &forwdel ) /* ZMAp */ BI( 0x1f&'E', &gotoeol ) #else OV( 0x1f&'@', 31, 12 ) /* gotobol ZMAP */ /* ^A == TVI magic prefix */ OV( 0x1f&'B', 31, 3 ) /* wordback ZMAP */ OV( 0x1f&'C', 31, 10 ) /* forwpage ZMAP */ OV( 0x1f&'D', 31, 6 ) /* forwdel ZMAP */ OV( 0x1f&'E', 31, 13 ) /* gotoeol ZMAP */ #endif #ifdef OLDMAP BI( 0x1f&'F', &forwword ) /* ZMAP */ #else OV( 0x1f&'F', 31, 2 ) /* forwword ZMAP */ #endif BI( 0x1f&'G', &ctrlg ) /* ZMAP */ BI( 0x1f&'H', &backchar ) /* ZMAP */ #ifdef OLDMAP BI( 0x1f&'I', &tab ) /* ZMAP */ OV( 0x1f&'J', 22, 0 ) /* forwline ZMAP */ OV( 0x1f&'K', 22, 1 ) /* backline, ZMAP */ #else OV( 0x1f&'I', 31, 40 ) /* tab, ZMAP */ OV( 0x1f&'J', 31, 0 ) /* forwline ZMAP */ OV( 0x1f&'K', 31, 1 ) /* backline, ZMAP */ #endif BI( 0x1f&'L', &forwchar ) /* ZMAP */ #ifdef OLDMAP OV( 0x1f&'M', 26, 0 ) /* indent ZMAP */ #else OV( 0x1f&'M', 31, 42 ) /* indent ZMAP */ #endif OV( 0x1f&'N', 2, 0 ) /* fsearch ZMAP */ #ifdef OLDMAP OV( 0x1f&'O', 26, 1 ) /* openline */ #else OV( 0x1f&'O', 31, 41 ) /* openline */ #endif OV( 0x1f&'P', 1, 0 ) /* bsearch, ZMAP */ /* ^Q available */ #ifdef OLDMAP OV( 0x1f&'R', 23, 3 ) /* backpage ZMAP */ #else OV( 0x1f&'R', 31, 11 ) /* backpage ZMAP */ #endif /* ^S available */ /* ^T findchar ZMAP */ /* ^U parameter introducer ZMAP */ #ifdef OLDMAP OV( 0x1f&'V', 22, 0 ) /* forwline TVI arrow */ #else OV( 0x1f&'V', 31, 0 ) /* forwline TVI arrow */ #endif /* ^W */ /* ^X ZMAP prefix */ #ifdef OLDMAP OV( 0x1f&'Y', 25, 1 ) /* ????yank */ #else OV( 0x1f&'Y', 31, 44 ) /* ????yank */ #endif #ifdef OLDMAP OV( 0x1f&'Z', 24, 1 ) /* swapmark, TVI CLEAR key */ #else OV( 0x1f&'Z', 31, 46 ) /* swapmark, TVI CLEAR key */ #endif /* ^[ META prefix ZMAP */ /* ^\ negative parameter introducer ZMAP */ /* ^] */ OV( 0x1f&'^', 16, 1 ) /* next buffer, TVI HOME key */ /* ^_ */ /* space to twiddle (0x20 to 0x7e) self-insert */ #ifdef OLDMAP BI( 0x7F, &backdel ) /* ZMAP */ #else OV( 0x7F, 31, 7 ) /* backdel ZMAP */ #endif /* META-control: mostly not used for now */ OV( META|(0x1f&'Z'), 30, 1 ) /* quick save and exit */ /* M-punctuation: mostly not used for now */ #ifdef OLDMAP OV( META|'*', 24, 0 ) /* setmark TVI SHIFT-CLEAR key */ #else OV( META|'*', 31, 45 ) /* setmark TVI SHIFT-CLEAR key */ #endif /* M-6 is SHIFT SEND (programmable) */ /* M-7 is SEND (programmable) */ OV( META|'!', 14, 1 ) /* ???reposition */ #ifdef OLDMAP OV( META|'<', 23, 0 ) /* gotobob */ OV( META|'>', 23, 1 ) /* gotoeob */ BI( META|'b', &delbword ) /* ??? */ #else OV( META|'g', 31, 8 ) /* gotobob gotoline ZMAP */ OV( META|'G', 31, 9 ) /* gotoeob */ OV( META|'b', 31, 5 ) /* delbword ??? */ #endif OV( META|'c', 21, 2 ) /* capword */ /* M-E TVI "LINE INS" */ #ifdef OLDMAP BI( META|'f', &delfword ) /* ??? */ #else OV( META|'f', 31, 4 ) /* delfword ??? */ #endif OV( META|'I', 29, 2 ) /* exec kbmac, TVI BACKTAB key */ OV( META|'j', 10, 0 ) /* uppercase region, TVI "SHIFT uparrow" */ OV( META|'L', 3, 0 ) /* killregion, TVI "SHIFT PRINT" key */ /* M-N TVI "SHIFT LINE INS" */ /* M-O TVI "SHIFT LINE DEL " key */ OV( META|'P', 19, 0 ) /* copyregion, TVI "PRINT" key */ OV( META|'Q', 5, 1 ) /* quote, ZMAP and TVI "CHAR INS" */ #ifdef OLDMAP OV( META|'T', 25, 0 ) /* kill, TVI "LINE ERA" key */ #else OV( META|'R', 31, 47 ) /* kill lines vi-style, TVI "LINE DEL" */ OV( META|'T', 31, 43 ) /* kill, TVI "LINE ERA" key */ #endif OV( META|'W', 30, 4 ) /* WORD/word mode */ OV( META|'w', 30, 2 ) /* WORD/word mode */ OV( META|'Y', 17, 0 ) /* killbuffer, TVI "PAGE ERA" key */ OV( META|'\\', 14, 2 ) /* refresh */ OV( META|'_', 21, 1 ) /* lowerword */ OV( META|'^', 21, 0 ) /* upperword */ OV( META|'~', 7, 1 ) /* twiddle */ OV( CTLX|(0x1f&'B'), 4, 0 ) /* listbuf */ OV( CTLX|(0x1f&'C'), 30, 0 ) /* Hard quit. */ OV( CTLX|(0x1f&'F'), 11, 0 ) /* visit file */ OV( CTLX|(0x1f&'J'), 8, 0 ) /* scroll down window */ OV( CTLX|(0x1f&'K'), 8, 1 ) /* scroll up window */ OV( CTLX|(0x1f&'L'), 6, 0 ) /* ??? lowercase region */ OV( CTLX|(0x1f&'N'), 5, 0 ) /* filename */ OV( CTLX|(0x1f&'O'), 7, 2 ) /* ???deblank */ OV( CTLX|(0x1f&'R'), 20, 0 ) /* fileread */ OV( CTLX|(0x1f&'S'), 9, 0 ) /* filesave */ OV( CTLX|(0x1f&'V'), 8, 0 ) /* scroll down window */ OV( CTLX|(0x1f&'W'), 12, 0 ) /* ???write file */ OV( CTLX|(0x1f&'Z'), 13, 0 ) /* ???shrink current window. */ #ifdef NEVER OV( CTLX|'F', 21, 3 ) /* setfillcol??? */ #endif /*CTLX|'!', &spawn, /* Run 1 command. */ OV( CTLX|'=', 7, 0 ) /* show cursor stats */ OV( CTLX|'1', 14, 0 ) /* one window */ OV( CTLX|'2', 15, 0 ) /* split window */ OV( CTLX|'b', 16, 0 ) /* ??? use buffer. */ OV( CTLX|'(', 29, 0 ) /* startmacro */ OV( CTLX|')', 29, 1 ) /* endmacro */ OV( CTLX|'n', 8, 2 ) /* ???nextwind */ OV( CTLX|'p', 8, 3 ) /* ???prevwind */ OV( CTLX|'z', 18, 0 ) /* ???enlarge window */  #ifndef OWNER #define Extern extern #else #define Extern #endif #include "stdio.h" #include "ed.h" /*efine WFDEBUG 0 /* Window flag debug. */ typedef struct VIDEO { short v_flag; /* Flags */ char v_text[1]; /* Screen data. */ } VIDEO; #define VFCHG 0x0001 /* Changed. */ Extern int sgarbf #ifdef OWNER = TRUE #endif ; /* TRUE if screen is garbage */ Extern int mpresf #ifdef OWNER = FALSE #endif ; /* TRUE if message in last line */ Extern int vtrow #ifdef OWNER = 0 #endif ; /* Row location of SW cursor */ Extern int vtcol #ifdef OWNER = 0 #endif ; /* Column location of SW cursor */ Extern int ttrow #ifdef OWNER = HUGE #endif ; /* Row location of HW cursor */ Extern int ttcol #ifdef OWNER = HUGE #endif ; /* Column location of HW cursor */ Extern VIDEO **vscreen; /* Virtual screen. */ Extern VIDEO **pscreen; /* Physical screen. */ #include "metab.h" int ovreq; int ovsub; int ovreq2; int ovsub2; FILE * ffp; main() { /* static int c;*/ #define cmdchar (*(int *)0x100) #define cmdflag (*(int *)0x102) #define cmdparm (*(int *)0x104) /* static int f; */ /* static int n; */ /* static int mflag; */ #define mflag (*(int *)0x106) settop( 0x700 ); myovinit( "meov" ); /*ovreq = 0;*/ ovloader( 0 ); /* , argc, argv[1] ); * initialize. */ while ( ovreq ) { cmdchar = ovreq; ovreq = 0; if ( ovloader( cmdchar, ovsub ) != TRUE ) break; } loop: update(); /* Fix up the screen */ cmdchar = getkey(); if (mpresf != FALSE) { mlerase(); update(); /*if (c == ' ') goto loop; ** ITS EMACS does this */ } cmdflag = FALSE; cmdparm = 1; if ( cmdchar == CMINUSCH ) { cmdflag = TRUE; goto negparm; #ifdef NEVER cmdparm = 0; mflag = -1; goto argloop; #endif } if (cmdchar == (0x1f&'U')) { /* ^U, start argument */ cmdflag = TRUE; cmdparm = 4; /* with argument of 4 */ mflag = 0; /* that can be discarded. */ argloop: for ( ;; ) { mlwrite( "Arg: %d", ( mflag >= 0 ) ? cmdparm : ( cmdparm ? -cmdparm : -1)); if ( ( cmdchar = getkey()) == (0x1f&'U')) cmdparm <<= 2; else if ( cmdchar == '-' ) { if ( mflag ) break; /* insert n dashes */ negparm: cmdparm = 0; mflag = -1; } else if ( cmdchar >= '0' && cmdchar <= '9' ) { if ( ! mflag ) /* 1st digit */ { cmdparm = 0; mflag = 1; } cmdparm = 10 * cmdparm + cmdchar - '0'; } else break; } /* * Make arguments preceded by a minus sign negative and change * the special argument "^U -" to an effective "^U -1". */ if (mflag == -1) { if ( ! cmdparm ) cmdparm++; cmdparm = -cmdparm; } } if (cmdchar == (0x1f&'X')) /* ^X is a prefix */ cmdchar = CTLX | getstroke(); ovreq = ovreq2 = 0; execute( ); /* Do it. */ while ( ovreq ) { cmdchar = ovreq; ovreq = 0; if ( ovloader( cmdchar, ovsub ) != TRUE ) break; } goto loop; } #include "stdio.h" #include "ed.h" #ifndef GOOD #define GOOD 0 #endif #ifdef OWNER #define Extern #else #define Extern extern #endif Extern int currow; /* Working cursor row */ Extern int curcol; /* Working cursor column */ Extern int fillcol; /* Current fill column */ Extern int thisflag; /* Flags, this command */ Extern int lastflag; /* Flags, last command */ Extern int curgoal; /* Goal column */ Extern BUFFER *curbp; /* Current buffer */ Extern WINDOW *curwp; /* Current window */ Extern BUFFER *bheadp; /* BUFFER listhead */ Extern WINDOW *wheadp; /* WINDOW listhead */ Extern BUFFER *blistp; /* Buffer list BUFFER */ /* Extern short kbdm[NKBDM] /* #ifdef OWNER /* = { CTLX|')', 0 } /* #endif /* ; /* Macro */ /* Extern short *kbdmip; /* Input for above */ /* Extern short *kbdmop; /* Output for above */ Extern char pat[NPAT]; /* Pattern */ typedef struct { short k_code; /* Key code */ int (*k_fp)(); /* Routine to handle it */ } KEYTAB; typedef struct { short k_code; /* same as KEYTAB */ char ovcode; /* which overlay. */ char ovparm; /* which routine in overlay. */ } OVERTAB; extern int ctrlg(); /* Abort out of things */ extern int quit(); /* Quit */ extern int getccol(); /* Get current column */ extern int gotobol(); /* Move to start of line */ extern int forwchar(); /* Move forward by characters */ extern int gotoeol(); /* Move to end of line */ extern int backchar(); /* Move backward by characters */ extern int setfillcol(); /* Set fill column. */ extern int tab(); /* Insert tab */ extern int newline(); /* Insert CR-LF */ extern int backword(); /* Backup by words */ extern int forwword(); /* Advance by words */ extern int forwdel(); /* Forward delete */ extern int backdel(); /* Backward delete */ extern int delfword(); /* Delete forward word. */ extern int delbword(); /* Delete backward word. */ extern int quickexit(); /* low keystroke style exit. */ extern char *strcpy(); /* copy string */ extern KEYTAB keytab[]; extern int NKEYTAB; extern OVERTAB overtab[]; extern int NOVERTAB; /* * The routines in this file * move the cursor around on the screen. * They compute a new value for the cursor, then * adjust ".". The display code always updates the * cursor location, so only moves between lines, * or functions that adjust the top line in the window * and invalidate the framing, are hard. */ #include "stdio.h" #include "ed.h" int tabsize; #ifdef OLDMAP /* * Move the cursor to the * beginning of the current line. * Trivial. */ gotobol(f, n) { curwp->w_doto = 0; return (TRUE); } #endif /* * Move the cursor backwards by * "n" characters. If "n" is less than * zero call "forwchar" to actually do the * move. Otherwise compute the new cursor * location. Error if you try and move * out of the buffer. Set the flag if the * line pointer for dot changes. */ backchar(f, n) register int n; { register LINE *lp; if (n < 0) return (forwchar(f, -n)); while (n--) { if (curwp->w_doto == 0) { if ((lp=lback(curwp->w_dotp)) == curbp->b_linep) return (FALSE); curwp->w_dotp = lp; curwp->w_doto = llength(lp); curwp->w_flag |= WFMOVE; } else curwp->w_doto--; } return (TRUE); } #ifdef OLDMAP /* * Move the cursor to the end * of the current line. Trivial. * No errors. */ gotoeol(f, n) { curwp->w_doto = llength(curwp->w_dotp); return (TRUE); } #endif /* * Move the cursor forwwards by * "n" characters. If "n" is less than * zero call "backchar" to actually do the * move. Otherwise compute the new cursor * location, and move ".". Error if you * try and move off the end of the * buffer. Set the flag if the line pointer * for dot changes. */ forwchar(f, n) register int n; { if (n < 0) return (backchar(f, -n)); while (n--) { if (curwp->w_doto == llength(curwp->w_dotp)) { if (curwp->w_dotp == curbp->b_linep) return (FALSE); curwp->w_dotp = lforw(curwp->w_dotp); curwp->w_doto = 0; curwp->w_flag |= WFMOVE; } else curwp->w_doto++; } return (TRUE); } #include "stdio.h" #include "ed.h" /* * Reverse search. * Get a search string from the * user, and search, starting at "." * and proceeding toward the front of * the buffer. If found "." is left * pointing at the first character of * the pattern [the last character that * was matched]. Bound to "M-R". */ ovmain(x, f, n) { register LINE *clp; register int cbo; register LINE *tlp; register int tbo; register int c; register char *epp; register char *pp; register int s; if ((s=readpattern("Reverse search")) != TRUE) return (s); for (epp = &pat[0]; epp[1] != 0; ++epp) ; clp = curwp->w_dotp; cbo = curwp->w_doto; for (;;) { if (cbo == 0) { clp = lback(clp); if (clp == curbp->b_linep) { mlwrite("Not found"); return (FALSE); } cbo = llength(clp)+1; } if (--cbo == llength(clp)) c = '\n'; else c = lgetc(clp, cbo); if (eq(c, *epp) != FALSE) { tlp = clp; tbo = cbo; pp = epp; while (pp != &pat[0]) { if (tbo == 0) { tlp = lback(tlp); if (tlp == curbp->b_linep) goto fail; tbo = llength(tlp)+1; } if (--tbo == llength(tlp)) c = '\n'; else c = lgetc(tlp, tbo); if (eq(c, *--pp) == FALSE) goto fail; } curwp->w_dotp = tlp; curwp->w_doto = tbo; curwp->w_flag |= WFMOVE; return (TRUE); } fail: ; } } /* * Compare two characters. * The "bc" comes from the buffer. * It has it's case folded out. The * "pc" is from the pattern. */ eq(bc, pc) register int bc; register int pc; { if (bc>='a' && bc<='z') bc -= 0x20; if (pc>='a' && pc<='z') pc -= 0x20; if (bc == pc) return (TRUE); return (FALSE); } /* * Read a pattern. * Stash it in the external * variable "pat". The "pat" is * not updated if the user types in * an empty line. If the user typed * an empty line, and there is no * old pattern, it is an error. * Display the old pattern, in the * style of Jeff Lomicka. There is * some do-it-yourself control * expansion. */ readpattern(prompt) char *prompt; { register char *cp1; register char *cp2; register int c; register int s; char tpat[NPAT+20]; cp1 = &tpat[0]; /* Copy prompt */ cp2 = prompt; while ((c = *cp2++) != '\0') *cp1++ = c; if (pat[0] != '\0') { /* Old pattern */ *cp1++ = ' '; *cp1++ = '['; cp2 = &pat[0]; while ((c = *cp2++) != 0) { if (cp1 < &tpat[NPAT+20-6]) { /* "??]: \0" */ if (c<0x20 || c==0x7F) { *cp1++ = '^'; c ^= 0x40; } else if (c == '%') /* Map "%" to */ *cp1++ = c; /* "%%". */ *cp1++ = c; } } *cp1++ = ']'; } *cp1++ = ':'; /* Finish prompt */ *cp1++ = ' '; *cp1++ = '\0'; s = mlreply(tpat, tpat, NPAT); /* Read pattern */ if (s == TRUE) /* Specified */ strcpy(pat, tpat); else if (s==FALSE && pat[0]!=0) /* CR, but old one */ s = TRUE; return (s); }  /* * Buffer management. * Some of the functions are internal, * and some are actually attached to user * keys. Like everyone else, they set hints * for the display system. */ #include "stdio.h" #include "ed.h" /* * Find a buffer, by name. Return a pointer * to the BUFFER structure associated with it. If * the named buffer is found, but is a TEMP buffer (like * the buffer list) conplain. If the buffer is not found * and the "cflag" is TRUE, create it. The "bflag" is * the settings for the flags in in buffer. */ BUFFER * bfind(bname, cflag, bflag) char *bname; { register BUFFER *bp; register LINE *lp; bp = bheadp; while (bp != NULL) { if ( ! strcmp( bname, bp->b_bname )) { /* if ((bp->b_flag&BFTEMP) != 0) */ /* { mlwrite("Cannot select builtin buffer"); */ /* return (NULL); */ /* } */ return (bp); } bp = bp->b_bufp; } if (cflag != FALSE) { if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL) return (NULL); if ((lp=lalloc(0)) == NULL) { free((char *) bp); return (NULL); } bp->b_bufp = bheadp; bheadp = bp; lp->l_fp = lp->l_bp = bp->b_dotp = bp->b_linep = lp; /**** bp->b_doto = ** malloc() already did this. */ /**** bp->b_markp = */ /**** bp->b_marko = */ /**** bp->b_nwnd = 0; */ bp->b_flag = bflag; /**** strcpy(bp->b_fname, ""); ** malloc() did it. */ strcpy(bp->b_bname, bname); } return (bp); } /* * This routine blows away all of the text * in a buffer. If the buffer is marked as changed * then we ask if it is ok to blow it away; this is * to save the user the grief of losing text. The * window chain is nearly always wrong if this gets * called; the caller must arrange for the updates * that are required. Return TRUE if everything * looks good. */ bclear(bp) BUFFER *bp; { register LINE *lp; if (( bp->b_flag & ( BFTEMP | BFCHG )) == BFCHG && mlyesno("Junk changes") != TRUE) return (0); bp->b_flag &= ~BFCHG; /* Not changed */ while ((lp=lforw(bp->b_linep)) != bp->b_linep) lfree(lp); bp->b_dotp = bp->b_linep; /* Fix "." */ bp->b_doto = bp->b_markp = bp->b_marko = 0; return (TRUE); } #include "ed.h" #include "cclass.h" char cclass[128] = { /* character classes. */ 0, /* ^@ */ 0, /* ^A */ 0, /* ^B */ 0, /* ^C */ 0, /* ^D */ 0, /* ^E */ 0, /* ^F */ 0, /* ^G */ 0, /* ^H */ (c_TAB|c_WHITE), /* ^I */ 0, /* ^J */ 0, /* ^K */ 0, /* ^L */ 0, /* ^M */ 0, /* ^N */ 0, /* ^O */ 0, /* ^P */ 0, /* ^Q */ 0, /* ^R */ 0, /* ^S */ 0, /* ^T */ 0, /* ^U */ 0, /* ^V */ 0, /* ^W */ 0, /* ^X */ 0, /* ^Y */ 0, /* ^Z */ 0, /* ^[ */ 0, /* ^\ */ 0, /* ^] */ 0, /* ^^ */ 0, /* ^_ */ (c_SIMPLE|c_WHITE), /* blank */ c_SIMPLE, /* ! */ c_SIMPLE, /* " */ c_SIMPLE, /* # */ c_SIMPLE, /* $ */ c_SIMPLE, /* % */ c_SIMPLE, /* & */ c_SIMPLE, /* ' */ (c_FENCE|c_SIMPLE), /* ( */ (c_FENCE|c_SIMPLE), /* ) */ c_SIMPLE, /* * */ c_SIMPLE, /* + */ c_SIMPLE, /* , */ c_SIMPLE, /* - */ c_SIMPLE, /* . */ c_SIMPLE, /* / */ (c_CWORD|c_DIGIT|c_SIMPLE), /* 0 */ (c_CWORD|c_DIGIT|c_SIMPLE), /* 1 */ (c_CWORD|c_DIGIT|c_SIMPLE), /* 2 */ (c_CWORD|c_DIGIT|c_SIMPLE), /* 3 */ (c_CWORD|c_DIGIT|c_SIMPLE), /* 4 */ (c_CWORD|c_DIGIT|c_SIMPLE), /* 5 */ (c_CWORD|c_DIGIT|c_SIMPLE), /* 6 */ (c_CWORD|c_DIGIT|c_SIMPLE), /* 7 */ (c_CWORD|c_DIGIT|c_SIMPLE), /* 8 */ (c_CWORD|c_DIGIT|c_SIMPLE), /* 9 */ c_SIMPLE, /* : */ c_SIMPLE, /* ; */ c_SIMPLE, /* < */ c_SIMPLE, /* = */ c_SIMPLE, /* > */ c_SIMPLE, /* ? */ c_SIMPLE, /* @ */ (c_CWORD|c_ALPHA|c_SIMPLE), /* A */ (c_CWORD|c_ALPHA|c_SIMPLE), /* B */ (c_CWORD|c_ALPHA|c_SIMPLE), /* C */ (c_CWORD|c_ALPHA|c_SIMPLE), /* D */ (c_CWORD|c_ALPHA|c_SIMPLE), /* E */ (c_CWORD|c_ALPHA|c_SIMPLE), /* F */ (c_CWORD|c_ALPHA|c_SIMPLE), /* G */ (c_CWORD|c_ALPHA|c_SIMPLE), /* H */ (c_CWORD|c_ALPHA|c_SIMPLE), /* I */ (c_CWORD|c_ALPHA|c_SIMPLE), /* J */ (c_CWORD|c_ALPHA|c_SIMPLE), /* K */ (c_CWORD|c_ALPHA|c_SIMPLE), /* L */ (c_CWORD|c_ALPHA|c_SIMPLE), /* M */ (c_CWORD|c_ALPHA|c_SIMPLE), /* N */ (c_CWORD|c_ALPHA|c_SIMPLE), /* O */ (c_CWORD|c_ALPHA|c_SIMPLE), /* P */ (c_CWORD|c_ALPHA|c_SIMPLE), /* Q */ (c_CWORD|c_ALPHA|c_SIMPLE), /* R */ (c_CWORD|c_ALPHA|c_SIMPLE), /* S */ (c_CWORD|c_ALPHA|c_SIMPLE), /* T */ (c_CWORD|c_ALPHA|c_SIMPLE), /* U */ (c_CWORD|c_ALPHA|c_SIMPLE), /* V */ (c_CWORD|c_ALPHA|c_SIMPLE), /* W */ (c_CWORD|c_ALPHA|c_SIMPLE), /* X */ (c_CWORD|c_ALPHA|c_SIMPLE), /* Y */ (c_CWORD|c_ALPHA|c_SIMPLE), /* Z */ (c_FENCE|c_SIMPLE), /* [ */ c_SIMPLE, /* \ */ (c_FENCE|c_SIMPLE), /* ] */ c_SIMPLE, /* ^ */ (c_CWORD|c_SIMPLE), /* _ */ c_SIMPLE, /* ` */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* a */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* b */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* c */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* d */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* e */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* f */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* g */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* h */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* i */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* j */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* k */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* l */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* m */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* n */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* o */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* p */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* q */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* r */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* s */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* t */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* u */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* v */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* w */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* x */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* y */ (c_CWORD|c_ALPHA|c_LOWC|c_SIMPLE), /* z */ (c_FENCE|c_SIMPLE), /* { */ c_SIMPLE, /* | */ (c_FENCE|c_SIMPLE), /* } */ c_SIMPLE, /* ~ */ 0 /* ^? */ }; isinsert( CcharC ) { if ( CcharC > 0x80 ) return( 0 ); return( cclass[ CcharC ] & c_SIMPLE ); } #ifdef NEVER isupper( c ) int c; { /* if ( c > 0x80 ) return( 0 ); */ return ( ( cclass[c] & ( c_ALPHA | c_LOWC )) == c_ALPHA ); } #endif islower( c ) int c; { if ( c > 0x80 ) return ( 0 ); return ( ( cclass[c] &c_LOWC )); } int wstyle; inword() { register int c; if (curwp->w_doto == llength(curwp->w_dotp)) return (FALSE); c = cclass[ lgetc( curwp->w_dotp, curwp->w_doto )]; if ( wstyle &1 ) return ( ( c & ( c_SIMPLE | c_WHITE )) == c_SIMPLE ); return ( c & c_CWORD ); } #include "stdio.h" #include "ed.h" /* * Copy all of the characters in the * region to the kill buffer. Don't move dot * at all. This is a bit like a kill region followed * by a yank. Bound to "M-W". */ ovmain(x, f, n) { register LINE *linep; register int loffs; register int s; REGION region; if ((s=getregion(®ion)) != TRUE) return (s); if ((lastflag&CFKILL) == 0) /* Kill type command. */ kdelete(); thisflag |= CFKILL; linep = region.r_linep; /* Current line. */ loffs = region.r_offset; /* Current offset. */ while (region.r_size--) { if (loffs == llength(linep)) { /* End of line. */ if ((s=kinsert('\n')) != TRUE) return (s); linep = lforw(linep); loffs = 0; } else { /* Middle of line. */ if ((s=kinsert(lgetc(linep, loffs))) != TRUE) return (s); ++loffs; } } return (TRUE); } #include "getreg.c" #include "stdio.h" #include "ed.h" /* * The command allows the user * to modify the file name associated with * the current buffer. It is like the "f" command * in UNIX "ed". The operation is simple; just zap * the name in the BUFFER structure, and mark the windows * as needing an update. You can type a blank line at the * prompt if you wish. */ ovmain(x, f, n) { register WINDOW *wp; register int s; char fname[NFILEN]; char bname[NBUFN]; if ( x == 1 ) return ( quote( f, n )); if ( n > 0 ) goto dobufname; if ((s=mlreply("File Name: ", fname, NFILEN)) == ABORT) return (s); if (s == FALSE) strcpy(curbp->b_fname, ""); else strcpy(curbp->b_fname, fname); wp = wheadp; /* Update mode lines. */ while (wp != NULL) { if (wp->w_bufp == curbp) wp->w_flag |= WFMODE; wp = wp->w_wndp; } return (TRUE); dobufname: if ((s=mlreply("Buffer Name: ", bname, NBUFN)) == ABORT) return (s); if (s == FALSE) return (s); else strcpy(curbp->b_bname, bname); wp = wheadp; /* Update mode lines. */ while (wp != NULL) { if (wp->w_bufp == curbp) wp->w_flag |= WFMODE; wp = wp->w_wndp; } return (TRUE); } /* * Quote the next character, and * insert it into the buffer. All the characters * are taken literally, with the exception of the newline, * which always has its line splitting meaning. The character * is always read, even if it is inserted 0 times, for * regularity. Bound to "M-Q" (for me) and "C-Q" (for Rich, * and only on terminals that don't need XON-XOFF). */ quote(f, n) { register int s; register int c; c = getstroke(); if (n < 0) return (FALSE); if (n == 0) return (TRUE); if (c == '\n') { do { s = lnewline(); } while (s==TRUE && --n); return (s); } return (linsert(n, c)); } /* * The routines in this file * handle the reading and writing of * disk files. All of details about the * reading and writing of the disk are * in "fileio.c". */ #include "stdio.h" #include "ed.h" /* * Read a file into the current * buffer. This is really easy; all you do it * find the name of the file, and call the standard * "read a file into the current buffer" code. * Bound to "C-X C-R". */ ovmain( x, f, n ) { register int s; char fname[NFILEN]; if ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE) return (s); return (readin(fname, ( n > 0))); } #include "readin.c" #include "stdio.h" #include "ed.h" /* * Ask for a file name, and write the * contents of the current buffer to that file. * Update the remembered file name and clear the * buffer changed flag. This handling of file names * is different from the earlier versions, and * is more compatable with Gosling EMACS than * with ITS EMACS. Bound to "C-X C-W". */ ovmain(x, f, n) { register int s; char fname[NFILEN]; if (( s = mlreply( "Write file: ", fname, NFILEN )) != TRUE ) return (s); return ( writeout( fname )); } #include "writeout.c" #include "stdio.h" #include "ed.h" extern int ovreq, ovreq2, ovsub, ovsub2; /* * Save the contents of the current * buffer in its associated file. No nothing * if nothing has changed (this may be a bug, not a * feature). Error if there is no remembered file * name for the buffer. Bound to "C-X C-S". May * get called by "C-Z". */ ovmain( x, f, n ) { register int s; if ((curbp->b_flag&BFCHG) == 0) /* Return, no changes. */ return (TRUE); if (curbp->b_fname[0] == 0) { /* Must have a name. */ mlwrite("No file name"); return (FALSE); } return ( writeout( curbp->b_fname )); } #include "writeout.c" #include "stdio.h" #include "ed.h" /* * Select a file for editing. * Look around to see if you can find the * fine in another buffer; if you can find it * just switch to the buffer. If you cannot find * the file, create a new buffer, read in the * text, and switch to the new buffer. * Bound to C-X C-V. */ ovmain( x, f, n ) { register BUFFER *bp; register WINDOW *wp; register LINE *lp; register int i; register int s; char bname[NBUFN]; char fname[NFILEN]; if ((s=mlreply("Find file: ", fname, NFILEN)) != TRUE) return (s); for ( bp = bheadp; bp != NULL; bp = bp->b_bufp ) { if ((bp->b_flag&BFTEMP)==0 && strcmp(bp->b_fname, fname)==0) { if (--curbp->b_nwnd == 0) { blockmv( curbp, curwp, 8 ); } curbp = curwp->w_bufp = bp; if (bp->b_nwnd++ == 0) { blockmv( curwp, bp, 8 ); } else { wp = wheadp; while ( wp != NULL ) { if ( wp != curwp && wp->w_bufp==bp) { blockmv( curwp, wp, 8 ); break; } wp = wp->w_wndp; } } lp = curwp->w_dotp; /* i = curwp->w_ntrows >> 1; */ /* while ( i-- && lback(lp) != curbp->b_linep ) */ /* lp = lback(lp); */ curwp->w_linep = lp; curwp->w_flag |= WFMODE|WFHARD; mlwrite("[Old buffer]"); return (TRUE); } } makename(bname, fname); /* New buffer name. */ while (( bp = bfind( bname, FALSE, 0 )) != NULL ) { if ( ( s = mlreply( "Buffer name: ", bname, NBUFN )) == ABORT) return (s); /* ^G to just quit */ if (s == FALSE) /* CR to clobber it */ { makename( bname, fname ); break; } } if ( bp == NULL && ( bp = bfind( bname, TRUE, 0 )) == NULL ) { mlwrite("No buffer"); return (FALSE); } if (--curbp->b_nwnd == 0) /* Undisplay. */ { blockmv( curbp, curwp, 8 ); } ( curbp = /* Switch to it. */ curwp->w_bufp = bp)-> b_nwnd++; return ( readin( fname, 1 )); /* Read it in. */ } makename(bname, fname) char *bname; char *fname; { register char * cp1; cp1 = fname; while ( *cp1 != ':' ) { if ( ! *cp1 ) { cp1 = fname; break; } cp1++; } if ( *cp1 == ':' ) cp1++; strcpy( bname, cp1 ); } #include "readin.c" /* getreg.c is included by overlaid region commands. * This routine figures out the * bounds of the region in the current window, and * fills in the fields of the "REGION" structure pointed * to by "rp". Because the dot and mark are usually very * close together, we scan outward from dot looking for * mark. This should save time. Return a standard code. * Callers of this routine should be prepared to get * an "ABORT" status; we might make this have the * conform thing later. */ getregion(rp) register REGION *rp; { register LINE *flp; register LINE *blp; register int fsize; register int bsize; if (curwp->w_markp == NULL) { mlwrite("No mark set in this window"); return (FALSE); } if (curwp->w_dotp == curwp->w_markp) { rp->r_linep = curwp->w_dotp; if (curwp->w_doto < curwp->w_marko) { rp->r_offset = curwp->w_doto; rp->r_size = curwp->w_marko-curwp->w_doto; } else { rp->r_offset = curwp->w_marko; rp->r_size = curwp->w_doto-curwp->w_marko; } return (TRUE); } blp = curwp->w_dotp; bsize = curwp->w_doto; flp = curwp->w_dotp; fsize = llength(flp)-curwp->w_doto+1; while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep) { if (flp != curbp->b_linep) { flp = lforw(flp); if (flp == curwp->w_markp) { rp->r_linep = curwp->w_dotp; rp->r_offset = curwp->w_doto; rp->r_size = fsize+curwp->w_marko; return (TRUE); } fsize += llength(flp)+1; } if (lback(blp) != curbp->b_linep) { blp = lback(blp); bsize += llength(blp)+1; if (blp == curwp->w_markp) { rp->r_linep = blp; rp->r_offset = curwp->w_marko; rp->r_size = bsize - curwp->w_marko; return (TRUE); } } } mlwrite("Bug: lost mark"); return (FALSE); } #include "stdio.h" #include "ed.h" /* * Enlarge the current window. * Find the window that loses space. Make * sure it is big enough. If so, hack the window * descriptions, and ask redisplay to do all the * hard work. You don't just set "force reframe" * because dot would move. Bound to "C-X Z". */ ovmain(x, f, n) { register WINDOW *adjwp; register LINE *lp; register int i; if (n < 0) { ctrlg(); return (FALSE); } /* return (shrinkwind(f, -n)); */ if (wheadp->w_wndp == NULL) { mlwrite("Only one window"); return (FALSE); } if ((adjwp=curwp->w_wndp) == NULL) { adjwp = wheadp; while (adjwp->w_wndp != curwp) adjwp = adjwp->w_wndp; } if (adjwp->w_ntrows <= n) { mlwrite("Impossible change"); return (FALSE); } if (curwp->w_wndp == adjwp) { /* Shrink below. */ lp = adjwp->w_linep; for (i=0; iw_bufp->b_linep; ++i) lp = lforw(lp); adjwp->w_linep = lp; adjwp->w_toprow += n; } else { /* Shrink above. */ lp = curwp->w_linep; for (i=0; ib_linep; ++i) lp = lback(lp); curwp->w_linep = lp; curwp->w_toprow -= n; } curwp->w_ntrows += n; adjwp->w_ntrows -= n; curwp->w_flag |= WFMODE|WFHARD; adjwp->w_flag |= WFMODE|WFHARD; return (TRUE); } #include "stdio.h" #include "ed.h" #define NBLOCK 16 /* Line block chunk size */ #define KBLOCK 256 /* Kill buffer block size */ char *kbufp = NULL; /* Kill buffer data */ int kused = 0; /* # of bytes used in KB */ int ksize = 0; /* # of bytes allocated in KB */ /* * Delete all of the text * saved in the kill buffer. Called by commands * when a new kill context is being created. The kill * buffer array is released, just in case the buffer has * grown to immense size. No errors. */ kdelete() { if (kbufp != NULL) { free((char *) kbufp); kbufp = kused = ksize = 0; } } /* * Insert a character to the kill buffer, * enlarging the buffer if there isn't any room. Always * grow the buffer in chunks, on the assumption that if you * put something in the kill buffer you are going to put * more stuff there too later. Return TRUE if all is * well, and FALSE on errors. */ kinsert(c) { register char *nbufp; register int i; if (kused == ksize) { if ((nbufp=malloc(ksize+KBLOCK)) == NULL) return (FALSE); blockmv( nbufp, kbufp, ksize ); /* for (i=0; ib_nwnd != 0) { /* Error if on screen. */ mlwrite("Buffer is being displayed"); return (FALSE); } if ((s=bclear(bp)) != TRUE) /* Blow text away. */ return (s); free((char *) bp->b_linep); /* Release header line. */ bp1 = NULL; /* Find the header. */ bp2 = bheadp; while (bp2 != bp) { bp1 = bp2; bp2 = bp2->b_bufp; } bp2 = bp2->b_bufp; /* Next one in chain. */ if (bp1 == NULL) /* Unlink it. */ bheadp = bp2; else bp1->b_bufp = bp2; free((char *) bp); /* Release buffer block */ return (TRUE); } #include "stdio.h" #include "ed.h" /* * Kill the region. Ask "getregion" * to figure out the bounds of the region. * Move "." to the start, and kill the characters. * Bound to "C-W". */ ovmain(x, f, n) { register int s; REGION region; if ((s=getregion(®ion)) != TRUE) return (s); if ((lastflag&CFKILL) == 0) /* This is a kill type */ kdelete(); /* command, so do magic */ thisflag |= CFKILL; /* kill buffer stuff. */ curwp->w_dotp = region.r_linep; curwp->w_doto = region.r_offset; return (ldelete(region.r_size, TRUE)); } #include "getreg.c" #include "stdio.h" #include "ed.h" /* * This function deletes "n" bytes, * starting at dot. It understands how do deal * with end of lines, etc. It returns TRUE if all * of the characters were deleted, and FALSE if * they were not (because dot ran into the end of * the buffer. The "kflag" is TRUE if the text * should be put in the kill buffer. */ ldelete(n, kflag) { register WINDOW *wp; #define dotp (*(LINE **)0x90) register char *cp1; #define cp3 (*(char **)0x9a) #define cp2 (*(char**)0x92) #define doto (*(int *)0x94) #define chunk (*(int *)0x96) #define left (*(int *)0x98) #define localn (*(int *)0xa2) localn = n; while ( localn > 0 ) { if ( curbp->b_linep == ( dotp = curwp->w_dotp ) ) return ( 0 ); /* Hit end of buffer. */ doto = curwp->w_doto; if ( localn < ( chunk = left = dotp->l_used - doto ) ) chunk = localn; if ( chunk == 0 ) /* End of line, merge. */ { lchange(WFHARD); if ( ldelnewline() == FALSE || ( kflag != FALSE && kinsert('\n') == FALSE )) return (FALSE); --localn; continue; } lchange(WFEDIT); cp2 = ( cp3 = cp1 = &dotp->l_text[doto] ) + chunk; if (kflag != FALSE) /* Kill? */ { while ( cp1 != cp2 ) { if (kinsert( *cp1++ ) == FALSE) return (FALSE); } } blockmv( cp3, cp2, left - chunk ); dotp->l_used -= chunk; wp = wheadp; /* Fix windows */ while (wp != NULL) { if ( wp->w_dotp == dotp && wp->w_doto >= doto ) { wp->w_doto -= chunk; if (wp->w_doto < doto) wp->w_doto = doto; } if ( wp->w_markp == dotp && wp->w_marko >= doto ) { wp->w_marko -= chunk; if (wp->w_marko < doto) wp->w_marko = doto; } wp = wp->w_wndp; } localn -= chunk; } return (TRUE); } #include "stdio.h" #include "ed.h" /* * Delete a newline. Join the current line * with the next line. If the next line is the magic * header line always return TRUE; merging the last line * with the header line can be thought of as always being a * successful operation, even if nothing is done, and this makes * the kill buffer work "right". Easy cases can be done by * shuffling data around. Hard cases require that lines be moved * about in memory. Return FALSE on error and TRUE if all * looks ok. Called by "ldelete" only. */ ldelnewline() { register WINDOW *wp; /* appears 29 times. */ register LINE *myline; /* appears 25 times. */ /* register LINE *nextline; */ /* register LINE *lp3; */ #define nextline (*(LINE **)0x9c) #define lp3 (*(LINE **)0x9e) #define mysize (*(int *)0xa0) mysize = ( myline = curwp->w_dotp )->l_used; if ( ( nextline = myline->l_fp ) == curbp->b_linep ) { /* At the buffer end. */ if ( ! mysize ) /* Blank line. */ lfree( myline ); rettrue: return ( 1 ); } #ifdef NEVER To save space, we will ALWAYS allocate a new line which will contain both myline and nextline. . if ( nextline->l_used <= myline->l_size - mysize ) . { /* nextline fits in myline. */ . blockmv( &myline->l_text[mysize], . &nextline->l_text[0], nextline->l_used ); . wp = wheadp; . while (wp != NULL) . { if (wp->w_linep == nextline) . wp->w_linep = myline; . if (wp->w_dotp == nextline) . { wp->w_doto += . ( wp->w_dotp = myline )-> . l_used; . } . if (wp->w_markp == nextline) . { wp->w_marko += ( wp->w_markp = myline )-> . l_used; . } . wp = wp->w_wndp; . } . mysize += nextline->l_used; . (myline->l_fp = nextline->l_fp)->l_bp = myline; . free((char *) nextline); . return (TRUE); . } #endif if ( ( lp3 = lalloc( mysize + nextline->l_used )) == NULL ) return (FALSE); blockmv( &lp3->l_text[0], &myline->l_text[0], mysize ); blockmv( &lp3->l_text[mysize], &nextline->l_text[0], nextline->l_used ); myline->l_bp->l_fp = nextline->l_fp->l_bp = lp3; lp3->l_fp = nextline->l_fp; lp3->l_bp = myline->l_bp; wp = wheadp; while (wp != NULL) { if ( wp->w_linep == myline || wp->w_linep == nextline ) wp->w_linep = lp3; if (wp->w_dotp == myline) goto xyz2; if ( wp->w_dotp == nextline ) { wp->w_doto += mysize; xyz2: wp->w_dotp = lp3; } if (wp->w_markp == myline) goto xyz3; if (wp->w_markp == nextline) { wp->w_marko += mysize; xyz3: wp->w_markp = lp3; } wp = wp->w_wndp; } free((char *) myline); free((char *) nextline); return (TRUE); } #include "stdio.h" #include "ed.h" /* * Delete line "lp". Fix all of the * links that might point at it (they are * moved to offset 0 of the next line. * Unlink the line from whatever buffer it * might be in. Release the memory. The * buffers are updated too; the magic conditions * described in the above comments don't hold * here. */ lfree(lp) LINE *lp; { register BUFFER *bp; register WINDOW *wp; #define wp ((WINDOW *)bp) #define llfp (*(LINE **)0xac) register LINE * lp1; bp = wheadp; llfp = ( lp1 = lp )->l_fp; while (wp != NULL) { if ( wp->w_linep == lp1 ) wp->w_linep = llfp; if ( wp->w_dotp == lp1 ) { wp->w_dotp = llfp; wp->w_doto = 0; } if ( wp->w_markp == lp1 ) { wp->w_markp = llfp; wp->w_marko = 0; } wp = wp->w_wndp; } bp = bheadp; while (bp != NULL) { /* if ( bp->b_nwnd == 0 ) */ /* { */ if ( bp->b_dotp == lp1 ) { bp->b_dotp = llfp; bp->b_doto = 0; } if ( bp->b_markp == lp1 ) { bp->b_markp = llfp; bp->b_marko = 0; } /* } */ bp = bp->b_bufp; } lp1->l_bp->l_fp = llfp; llfp->l_bp = lp->l_bp; free((char *) lp1); } /* * The functions in this file * are a general set of line management * utilities. They are the only routines that * touch the text. They also touch the buffer * and window structures, to make sure that the * necessary updating gets done. There are routines * in this file that handle the kill buffer too. * It isn't here for any good reason. * * Note that this code only updates the dot and * mark values in the window list. Since all the code * acts on the current window, the buffer that we * are editing must be being displayed, which means * that "b_nwnd" is non zero, which means that the * dot and mark values in the buffer headers are * nonsense. */ #include "stdio.h" #include "ed.h" #define NBLOCK 4 /* Line block chunk size */ /* changed from 16 to 8 in an attempt to save space. */ /* * This routine allocates a block * of memory large enough to hold a LINE * containing "used" characters. The block is * always rounded up a bit. Return a pointer * to the new block, or NULL if there isn't * any memory left. Print a message in the * message line if no space. */ LINE * lalloc(used) int used; { register LINE *lp; register int size; size = (used+NBLOCK-1) & ~(NBLOCK-1); if (size == 0) /* Assume that an empty */ size = NBLOCK; /* line is for type-in. */ if ((lp = (LINE *) malloc(sizeof(LINE)+size)) == NULL) { mlwrite("No Memory"); return (NULL); } lp->l_size = size; lp->l_used = used; return (lp); } /* * This routine gets called when * a character is changed in place in the * current buffer. It updates all of the required * flags in the buffer and window system. The flag * used is passed as an argument; if the buffer is being * displayed in more than 1 window we change EDIT to * HARD. Set MODE if the mode line needs to be * updated (the "*" has to be set). */ lchange(flag) { register WINDOW *wp; if (curbp->b_nwnd != 1) /* Ensure hard. */ flag = WFHARD; if ((curbp->b_flag&BFCHG) == 0) { /* First change, so */ flag |= WFMODE; /* update mode lines. */ curbp->b_flag |= BFCHG; } wp = wheadp; while (wp != NULL) { if (wp->w_bufp == curbp) wp->w_flag |= flag; wp = wp->w_wndp; } } #include "stdio.h" #include "ed.h" /* * Insert "n" copies of the character "c" * at the current location of dot. In the easy case * all that happens is the text is stored in the line. * In the hard case, the line has to be reallocated. * When the window list is updated, take special * care; I screwed it up once. You always update dot * in the current window. You update mark, and a * dot in another window, if it is greater than * the place where you did the insert. Return TRUE * if all is well, and FALSE on errors. */ linsert(n, c) { #define cp1 (*(char **)0xa0) #define cp2 (*(char **)0xa2) register LINE *lp1; /* 23 times. */ #define lp2 (*(LINE **)0xa8) #define lp3 (*(LINE **)0xa4) #define doto (*(int *)0xa6) register WINDOW *wp; /* 15 times, but the best! */ #define localn (*(int *)0xaa) lchange( WFEDIT ); wp = curwp; localn = n; if (( lp1 = wp->w_dotp ) == curbp->b_linep ) { /* At the end: special. Assert that w_doto == 0 */ /* There is no line at all here, so we must ** allocate a new line ( lp2 ) and link it in. */ if ( ( lp2 = lalloc( localn )) == NULL ) { /* must be out of memory. */ retfalse: return ( 0 ); } ( lp3 = lp1->l_bp )->l_fp = lp2; lp2->l_fp = lp1; ( wp->w_dotp = lp1->l_bp = lp2)->l_bp = lp3; #ifdef SANITY if ( wp->w_doto = localn ) { /* not zero count. */ clear( &lp2->l_text[0], localn, c ); } #else clear( &lp2->l_text[0], ( wp->w_doto = localn ), c ); #endif rettrue: return ( 1 ); } doto = wp->w_doto; if ( ( lp1->l_used + localn ) > lp1->l_size ) { /* The lp1 line grows and must be reallocated. */ if ( ( lp2 = lalloc( lp1->l_used + localn )) == NULL ) goto retfalse; blockmv( lp2, lp1, 4 ); /* lp2->l_fp = lp1->l_fp; */ /* lp2->l_bp = lp1->l_bp; */ blockmv( lp2->l_text, lp1->l_text, doto ); blockmv( &lp2->l_text[ localn + doto ], &lp1->l_text[ doto ], lp1->l_used - doto ); lp1->l_fp->l_bp = lp1->l_bp->l_fp = lp2; free((char *) lp1); } else { /* Easy: in place */ (lp2 = lp1)-> /* Pretend new line */ l_used += localn; cp2 = &lp1->l_text[lp1->l_used]; cp1 = cp2-localn; while (cp1 != &lp1->l_text[doto]) *--cp2 = *--cp1; } if ( localn ) clear( &lp2->l_text[doto], localn, c ); wp = wheadp; /* Update windows */ while (wp != NULL) { if (wp->w_linep == lp1) wp->w_linep = lp2; if (wp->w_dotp == lp1) { wp->w_dotp = lp2; if ( wp == curwp || wp->w_doto > doto ) { wp->w_doto += localn; } } if ( wp->w_markp == lp1 ) { wp->w_markp = lp2; if ( wp->w_marko > doto ) wp->w_marko += localn; } wp = wp->w_wndp; } return (TRUE); } #include "stdio.h" #include "ed.h" /* * List all of the active * buffers. First update the special * buffer that holds the list. Next make * sure at least 1 window is displaying the * buffer list, splitting the screen if this * is what it takes. Lastly, repaint all of * the windows that are displaying the * list. Bound to "C-X C-B". */ ovmain(x, f, n) { /* register WINDOW *wp; */ register BUFFER *bp; register int s; if ( x ) return ( usebuf( x, f, n )); if ( ! usebuf( 2, 0, 0 )) return ( 0 ); if ((s=makelist()) != TRUE) return (s); #ifdef NEVER if (blistp->b_nwnd == 0) { /* Not on screen yet. */ if ((wp=wpopup()) == NULL) return (FALSE); bp = wp->w_bufp; if (--bp->b_nwnd == 0) { bp->b_dotp = wp->w_dotp; bp->b_doto = wp->w_doto; bp->b_markp = wp->w_markp; bp->b_marko = wp->w_marko; } wp->w_bufp = blistp; ++blistp->b_nwnd; } #endif #ifdef NEVER while (wp != NULL) { if (wp->w_bufp == blistp) { wp->w_linep = wp->w_dotp = lforw(blistp->b_linep); wp->w_markp = wp->w_doto = wp->w_marko = 0; wp->w_flag |= WFMODE|WFHARD; } wp = wp->w_wndp; } #endif return (TRUE); } /* * This routine rebuilds the * text in the special secret buffer * that holds the buffer list. It is called * by the list buffers command. Return TRUE * if everything works. Return FALSE if there * is an error (if there is no memory). */ makelist() { register char *cp1; register char *cp2; register int c; register BUFFER *bp; register LINE *lp; register int nbytes; register int s; register int type; char b[6+1]; char line[128]; int nbuff; nbuff = 0; blistp->b_flag &= ~BFCHG; /* Don't complain! */ if ((s=bclear(blistp)) != TRUE) /* Blow old text away */ return (s); blistp->b_fname[0] = 0; if (addline(" C Size Buffer File") == FALSE || addline(" - ---- ------ ----") == FALSE) return (FALSE); bp = bheadp; /* For all buffers */ while (bp != NULL) { if ( bp->b_flag & BFTEMP ) { bp = bp->b_bufp; /* Skip magic ones. */ continue; } cp1 = &line[-1]; /* Start at left edge */ cp2 = &b[0]; itoa( cp2, 3, ++nbuff ); /* 6 digit buffer size. */ while (*++cp1 = *cp2++); *cp1 = ' '; /* Gap. */ *++cp1 = ( bp->b_flag & BFCHG ) ? '*' : ' '; /* "*" if changed */ *++cp1 = ' '; /* Gap. */ nbytes = 0; /* Count bytes in buf. */ lp = lforw(bp->b_linep); while (lp != bp->b_linep) { nbytes += llength(lp)+1; lp = lforw(lp); } cp2 = &b[0]; itoa( cp2, 6, nbytes ); /* 6 digit buffer size. */ while (*++cp1 = *cp2++); *cp1 = ' '; /* Gap. */ cp2 = &bp->b_bname[0]; /* Buffer name */ while (*++cp1 = *cp2++); cp2 = &bp->b_fname[0]; /* File name */ if (*cp2 != 0) { while (cp1 < &line[4+1+1+6+1+NBUFN+1]) *cp1++ = ' '; while ( *cp1++ = *cp2++ ); } *cp1 = 0; if (addline(line) == FALSE) return (FALSE); bp = bp->b_bufp; } return (TRUE); /* All done */ } /* * The argument "text" points to * a string. Append this line to the * buffer list buffer. Handcraft the EOL * on the end. Return TRUE if it worked and * FALSE if you ran out of room. */ addline(text) char *text; { register LINE *lp; register int ntext; ntext = strlen(text); if ((lp=lalloc(ntext)) == NULL) return (FALSE); blockmv( &lp->l_text[0], text, ntext ); /**** for (i=0; il_bp = blistp->b_linep->l_bp )->l_fp = lp; ( lp->l_fp = blistp->b_linep )->l_bp = lp; if (blistp->b_dotp == blistp->b_linep) /* If "." is at the end */ blistp->b_dotp = lp; /* move it to new line */ return (TRUE); } itoa(buf, width, num) register char buf[]; register int width; register int num; { buf[width] = 0; /* End of string. */ clear( buf, width, ' ' ); while (num >= 10) { /* Conditional digits. */ buf[--width] = (num%10) + '0'; num /= 10; } buf[--width] = num + '0'; /* Always 1 digit. */ #ifdef NEVER while (width != 0) /* Pad with blanks. */ buf[--width] = ' '; #endif } /* * Attach a buffer to a window. The * values of dot and mark come from the buffer * if the use count is 0. Otherwise, they come * from some other window. */ usebuf( x, f, n) { register BUFFER *bp; register WINDOW *wp; register int s; char bufn[NBUFN]; if ( x == 1 ) { /* "next buffer" */ bp = curbp->b_bufp; if ( bp == NULL ) bp = bheadp; } else if ( x == 2 ) { if ( ( bp = bfind( "[List]", TRUE, BFTEMP )) == NULL ) return ( 0 ); } else { /* normal usebuffer() routine. */ if ((s=mlreply("Use buffer: ", bufn, NBUFN)) != TRUE) return (s); if ((bp=bfind(bufn, TRUE, 0)) == NULL) return (FALSE); } if (--curbp->b_nwnd == 0) { /* Last use. */ /**** curbp->b_dotp = curwp->w_dotp; ****/ /**** curbp->b_doto = curwp->w_doto; ****/ /**** curbp->b_markp = curwp->w_markp; ****/ /**** curbp->b_marko = curwp->w_marko; ****/ blockmv( curbp, curwp, 8 ); } curbp = bp; /* Switch. */ curwp->w_bufp = bp; curwp->w_linep = bp->b_linep; /* For macros, ignored. */ curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty. */ if (bp->b_nwnd++ == 0) { /* First use. */ blockmv( curwp, curbp, 8 ); #ifdef NEVER curwp->w_dotp = bp->b_dotp; curwp->w_doto = bp->b_doto; curwp->w_markp = bp->b_markp; curwp->w_marko = bp->b_marko; #endif return (TRUE); } wp = wheadp; /* Look for old. */ while (wp != NULL) { if (wp!=curwp && wp->w_bufp==bp) { blockmv( curwp, curbp, 8 ); #ifdef NEVER curwp->w_dotp = wp->w_dotp; curwp->w_doto = wp->w_doto; curwp->w_markp = wp->w_markp; curwp->w_marko = wp->w_marko; #endif break; } wp = wp->w_wndp; } return (TRUE); } #include "stdio.h" #include "ed.h" /* * Insert a newline into the buffer * at the current location of dot in the current * window. The funny ass-backwards way it does things * is not a botch; it just makes the last line in * the file not a special case. Return TRUE if everything * works out and FALSE on error (memory allocation * failure). The update of dot and mark is a bit * easier then in the above case, because the split * forces more updating. */ lnewline() { register WINDOW *wp; register LINE *lp1; #define lp2 (*(LINE **)0x90) #define doto (*(int *)0x92) /* register LINE *lp2; */ /* register int doto; */ lchange( WFHARD ); wp = curwp; lp1 = wp->w_dotp; /* Get the address and */ doto = wp->w_doto; /* offset of "." */ if ( ( lp2 = lalloc( doto )) == NULL ) /* New first half line */ return (FALSE); blockmv( &lp2->l_text[0], &lp1->l_text[0], doto ); blockmv( &lp1->l_text[ 0 ], &lp1->l_text[ doto ], lp1->l_used - doto ); lp1->l_used -= doto; lp2->l_bp = lp1->l_bp; lp1->l_bp = lp2->l_bp->l_fp = lp2; lp2->l_fp = lp1; wp = wheadp; /* Windows */ while (wp != NULL) { if (wp->w_linep == lp1) wp->w_linep = lp2; if (wp->w_dotp == lp1) { if (wp->w_doto < doto) wp->w_dotp = lp2; else wp->w_doto -= doto; } if (wp->w_markp == lp1) { if (wp->w_marko < doto) wp->w_markp = lp2; else wp->w_marko -= doto; } wp = wp->w_wndp; } return (TRUE); } #include "stdio.h" #include "ed.h" /* lowreg.c * Lower case region. Zap all of the upper * case characters in the region to lower case. Use * the region code to set the limits. Scan the buffer, * doing the changes. Call "lchange" to ensure that * redisplay is done in all buffers. Bound to * "C-X C-L". */ ovmain(x, f, n) { register LINE *linep; register int loffs; register int c; register int s; REGION region; if ((s=getregion(®ion)) != TRUE) return (s); lchange(WFHARD); linep = region.r_linep; loffs = region.r_offset; while (region.r_size--) { if (loffs == llength(linep)) { linep = lforw(linep); loffs = 0; } else { c = lgetc(linep, loffs); if (c>='A' && c<='Z') lputc(linep, loffs, c+'a'-'A'); ++loffs; } } return (TRUE); } #include "getreg.c" #include "medisp.h" /* * Update a single line. This * does not know how to use insert * or delete character sequences; we are * using VT52 functionality. Update the physical * row and column variables. It does try an * exploit erase to end of line. The RAINBOW version * of this routine uses fast video. */ updateline(row, vline, pline) char *vline; char *pline; { register char *cp1; register char *cp2; #define cp3 (*(char **)0x110) #define cp4 (*(char **)0x112) #define cp5 (*(char **)0x114) #define nbflag (*(int *)0x116) cp1 = vline; /* Compute left match. */ cp2 = pline; cp5 = &vline[80]; while ( *cp1 == *cp2 ) { if (cp1 == cp5) return;/* All equal. */ ++cp1; ++cp2; } /* This can still happen, even though we only call this routine */ /* on changed lines. A hard update is always done when a line */ /* splits, a massive change is done, or a buffer is displayed */ /* twice. This optimizes out most of the excess updating. A lot */ /* of computes are used, but these tend to be hard operations */ /* that do a lot of update, so I don't really care. */ nbflag = FALSE; cp3 = cp5; /* Compute right match. */ cp4 = &pline[80]; while ( *(--cp3) == *(--cp4) ) { if ( *cp3 != ' ') /* Note if any nonblank */ nbflag = TRUE; /* in right match. */ } cp5 = ++cp3; ++cp4; if (nbflag == FALSE) /* Erase to EOL ? */ { while ( cp5 != cp1 && cp5[ -1 ] == ' ' ) --cp5; #ifdef NEVER if ( cp3 - cp5 <= 3 ) /* Use only if erase is */ cp5 = cp3; /* fewer characters. */ #endif } movecursor(row, cp1 - &vline[0]); /* Go to start of line. */ while (cp1 != cp5) /* Ordinary. */ { conout( *cp2++ = *cp1++ ); ++ttcol; /* *cp2++ = *cp1++; */ } if (cp5 != cp3) /* Erase. */ { ansieeol(); while (cp1 != cp3) *cp2++ = *cp1++; } } /* * Send a command to the terminal * to move the hardware cursor to row "row" * and column "col". The row and column arguments * are origin 0. Optimize out random calls. * Update "ttrow" and "ttcol". */ movecursor(row, col) int row, col; { if ( row != ttrow || col != ttcol ) { ttrow = row; ttcol = col; ansimove( row, col ); } } #define OWNER 1 #include "metab.h" FILE * kbdmf; int kbdmstate; getstroke() { /* get physical key from current source. */ register int c; if ( kbdmstate == 2 ) { /* execute "keyboard mac" or "exec file" */ if (( c = getc( kbdmf )) == EOF || c == 26 ) { kbdmclose(); } } if ( kbdmstate != 2 ) { c = conin(); if ( kbdmstate == 1 ) { /* save keyboard mac */ if ( putc( c, kbdmf ) == EOF ) { ctrlg(); } } } return ( c ); } /* kbdmget() { return( getc( kbdmf )); } */ kbdmclose() { if ( kbdmf ) fclose( kbdmf ); kbdmf = kbdmstate = 0; } conin() { return( bios( 3 )); } getkey() { register int c; if ( ( c = getstroke()) == METACH ) /* Apply M- prefix */ { return (META | getstroke()); } #ifdef NEVER if ( c == CMINUSCH ) return ( c ); /* negative parameter introducer. */ if ( c <= 0x1F ) /* C0 control -> C- */ c |= ( CTRL | '@' ); #endif return (c); } #ifdef NEVER /* * Get a key. * Apply control modifications * to the read key. */ getctl() { register int c; if ( ( c = getstroke()) <= 0x1f ) c |= ( CTRL | '@' ); if ( islower( c )) c -= 0x20; return (c); } #endif /* * Abort. * Beep the beeper. * Kill off any keyboard macro, * etc., that is in progress. * Sometimes called as a routine, * to do general aborting of * stuff. */ ctrlg() { conout( 7 ); kbdmclose(); return (ABORT); } #include "medisp.h" /* * Erase the message line. * This is a special routine because * the message line is not considered to be * part of the virtual screen. It always works * immediately; the terminal buffer is flushed * via a call to the flusher. */ mlerase() { movecursor(23, 0); ansieeol(); mpresf = FALSE; } /* * Ask a yes or no question in * the message line. Return either TRUE, * FALSE, or ABORT. The ABORT status is returned * if the user bumps out of the question with * a ^G. Used any time a confirmation is * required. */ mlyesno(prompt) char *prompt; { register int s; char buf[64]; strcpy(buf, prompt); strcat(buf, " [y/n]? "); s = mlreply(buf, buf, sizeof(buf)); if ( s == ABORT ) return (ABORT); if ( s != FALSE && ( buf[0] == 'y' || buf[0] == 'Y' )) return ( 1 ); return ( 0 ); } /* * Write a prompt into the message * line, then read back a response. Keep * track of the physical position of the cursor. * If we are in a keyboard macro throw the prompt * away, and return the remembered response. This * lets macros run at full speed. The reply is * always terminated by a carriage return. Handle * erase, kill, and abort keys. */ mlreply(prompt, buf, nbuf) char *prompt; char *buf; { register int cpos; register int c; cpos = 0; mlwrite(prompt); for (;;) { switch ( c = getstroke()) { case 0x0D: /* Return, end of line */ buf[cpos++] = 0; conout( '\r' ); ttcol = 0; if (buf[0] == 0) return (FALSE); return (TRUE); case 0x07: /* Bell, abort */ conout( '^' ); conout( 'G' ); ttcol += 2; ctrlg(); return (ABORT); case 0x7F: /* Rubout, erase */ case 0x08: /* Backspace, erase */ if (cpos != 0) { crtbs(); if (buf[--cpos] < 0x20) { crtbs(); } } break; #ifdef NEVER case 0x15: /* C-U, kill */ while (cpos != 0) { crtbs(); if (buf[--cpos] < 0x20) { crtbs(); } } break; #endif default: if (cpos < nbuf-1) { buf[cpos++] = c; if (c < ' ') { conout( '^' ); ++ttcol; c ^= 0x40; } conout( c ); ++ttcol; } } } } crtbs() { conout( '\b' ); conout( ' ' ); conout( '\b' ); --ttcol; } conout( c ) { bios( 4, c ); } /* * Write a message into the message * line. Keep track of the physical cursor * position. A small class of printf like format * items is handled. Assumes the stack grows * down; this assumption is made by the "++" * in the argument scan loop. Set the "message * line" flag TRUE. */ mlwrite(fmt, arg) char *fmt; { register int c; register char *ap; movecursor(23, 0); ap = (char *) &arg; while ((c = *fmt++) != 0) { if (c != '%') goto out_it; c = *fmt++; switch (c) { case 'd': mlputi(*(int *)ap, 10); ap += sizeof(int); break; #ifdef NEVER case 'o': mlputi(*(int *)ap, 8); ap += sizeof(int); break; case 'x': mlputi(*(int *)ap, 16); ap += sizeof(int); break; case 'D': mlputli(*(long *)ap, 10); ap += sizeof(long); break; #endif case 's': mlputs(*(char **)ap); ap += sizeof(char *); break; default: out_it: conout( c ); ++ttcol; } } ansieeol(); mpresf = TRUE; } /* * Write out a string. * Update the physical cursor position. * This assumes that the characters in the * string all have width "1"; if this is * not the case things will get screwed up * a little. */ mlputs(s) char *s; { register int c; while ((c = *s++) != 0) { conout( c ); ++ttcol; } } /* * Write out an integer, in * the specified radix. Update the physical * cursor position. This will not handle any * negative numbers; maybe it should. */ mlputi(i, r) { register int q; static char hexdigits[] = "0123456789ABCDEF"; if (i < 0) { i = -i; conout( '-'); } q = i/r; if (q != 0) mlputi(q, r); conout( hexdigits[i%r]); ++ttcol; } #ifdef NEVER /* * do the same except as a long integer. */ mlputli(l, r) long l; { register long q; if (l < 0) { l = -l; conout( '-'); } q = l/r; if (q != 0) mlputli(q, r); conout( (int)(l%r)+'0'); ++ttcol; } #endif  /* #define OWNER */ #include "metab.h" #undef BI #undef OV #define OV( a, b, c ) /* */ #define BI( a, b ) a, b, KEYTAB keytab[] = { #include "mapping.h" -1, 0 } ; int NKEYTAB = (sizeof(keytab)/sizeof(keytab[0])); #undef BI #undef OV #define OV( a, b, c ) a, b, c, #define BI( a, b ) /* */ struct OVERTAB overtab[] = { #include "mapping.h" -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0 }; int NOVERTAB = (sizeof(overtab) / sizeof(overtab[0])); /* * The functions in this file * handle redisplay. There are two halves, * the ones that update the virtual display * screen, and the ones that make the physical * display screen the same as the virtual * display screen. These functions use hints * that are left in the windows by the * commands. */ #define OWNER #include "medisp.h" /* * Make sure that the display is * right. This is a three part process. First, * scan through all of the windows looking for dirty * ones. Check the framing, and refresh the screen. * Second, make sure that "currow" and "curcol" are * correct for the current window. Third, make the * virtual and physical screens the same. */ extern char * Argv[]; update() { register LINE *lp; register WINDOW *wp; #define vp1 (*(VIDEO **)0x108) #define i (*(int *)0x10c) #define c (*(int *)0x10e) #define lp2 (*(LINE **)0x110) #define wrows (*(int *)0x112) /* lp2 and wrows will be wiped out when meupdate is called. */ wp = wheadp; while (wp != NULL) { /* Look at any window with update flags set on. */ wrows = wp->w_ntrows; lp2 = wp->w_bufp->b_linep; if (wp->w_flag != 0) { /* If not force reframe, check the framing. */ if ( ( wp->w_flag & WFFORCE ) == 0 ) { lp = wp->w_linep; for ( i = 0 ; ++i <= wrows; ) { if ( lp == wp->w_dotp ) goto out; if ( lp == lp2 ) break; lp = lforw(lp); } } /* Not acceptable, better compute a new value */ /* for the line at the top of the window. Then */ /* set the "WFHARD" flag to force full redraw. */ if ( ( i = wp->w_force ) > 0) { if ( --i >= wrows ) i = wrows - 1; } else if ( i < 0 ) { i += wrows; if ( i < 0 ) i = 0; } else i = wrows >> 1; lp = wp->w_dotp; while ( --i >= 0 && lback(lp) != lp2 ) { lp = lback(lp); } wp->w_linep = lp; wp->w_flag |= WFHARD; /* Force full. */ out: /* Try to use reduced update. Mode line update */ /* has its own special flag. The fast update is */ /* used if the only thing to do is within the */ /* line editing. */ lp = wp->w_linep; i = wp->w_toprow; if ( wp->w_flag & WFMODE ) { Argv[3] = (char *)wp; ovloader( 28, 0 ); } /* modeline(wp); */ if ( wp->w_flag & WFHARD ) { while ( i < wp->w_toprow + wrows ) { if ( ! cramline( lp, wp )) lp = lforw(lp); ++i;/* cramline uses i... */ } } else if (wp->w_flag & WFEDIT) { while (lp != wp->w_dotp) { ++i; lp = lforw(lp); } cramline( lp, wp ); } wp->w_flag = 0; wp->w_force = 0; } /*#if WFDEBUG /* modeline(wp); /* wp->w_flag = 0; /* wp->w_force = 0; /*#endif*/ wp = wp->w_wndp; } /* Always recompute the row and column number of the hardware */ /* cursor. This is the only update for simple moves. */ lp = curwp->w_linep; currow = curwp->w_toprow; while (lp != curwp->w_dotp) { ++currow; lp = lforw(lp); } curcol = 0; i = 0; while (i < curwp->w_doto) { c = lgetc(lp, i++); if (c == '\t') curcol |= 0x07; else if ( ! isinsert( c )) ++curcol; ++curcol; } if (curcol >= 80) /* Long line. */ curcol = 79; /* Special hacking if the screen is garbage. Clear the hardware */ /* screen, and update your copy to agree with it. Set all the */ /* virtual screen change bits, to force a full update. */ if (sgarbf != FALSE) { for ( i=0; i < 23; ++i ) { vscreen[i]->v_flag |= VFCHG; clear( &( pscreen[ i ]->v_text[ 0 ]), 80, ' ' ); } ansiclear(); /*clear */ ttrow = ttcol = sgarbf = /* Erase-page clears */ mpresf = 0; /* the message area. */ } /* Make sure that the physical and virtual displays agree. */ /* Unlike before, the "updateline" code is only called with a */ /* line that has been updated for sure. */ for (i=0; i<23; ++i) { vp1 = vscreen[i]; if (( vp1->v_flag & VFCHG ) != 0 ) { vp1->v_flag &= ~VFCHG; updateline( i, &vp1->v_text[0], &pscreen[i]->v_text[0]); } } /* Finally, update the hardware cursor and flush out buffers. */ movecursor( currow, curcol ); } cramline( lp, wp ) LINE * lp; WINDOW * wp; { register int j, k, retval; retval = 1; vscreen[i]->v_flag |= VFCHG; vtmove( i, 0 ); if (lp != wp->w_bufp->b_linep) { k = llength(lp); for ( retval = j = 0; j < k; ++j ) vtputc(lgetc(lp, j)); } vteeol(); return ( retval ); } /* * The functions in this file * handle redisplay. There are two halves, * the ones that update the virtual display * screen, and the ones that make the physical * display screen the same as the virtual * display screen. These functions use hints * that are left in the windows by the * commands. */ #include "medisp.h" /* * Set the virtual cursor to * the specified row and column on the * virtual screen. There is no checking for * nonsense values; this might be a good * idea during the early stages. */ vtmove(row, col) int row, col; { vtrow = row; vtcol = col; } /* * Write a character to the * virtual screen. The virtual row and * column are updated. If the line is too * long put a "$" in the last column. * This routine only puts printing characters * into the virtual terminal buffers. * Only column overflow is checked. */ vtputc(c) int c; { register char *vp; if (vtcol >= 80) { vscreen[vtrow]->v_text[79] = '$'; return 0; } if ( isinsert( c )) { vscreen[vtrow]->v_text[vtcol++] = c; return 1; } vp = &vscreen[vtrow]->v_text[vtcol]; if (c == '\t') { do { *(vp++) = ' '; } while (( ++vtcol & 7 ) && vtcol < 80); } else { *(vp++) = '^'; *vp = (c ^ 0x40); vtcol += 2; } return 1; } /* * Erase from the end of the * software cursor to the end of the * line on which the software cursor is * located. */ vteeol() { clear( &vscreen[vtrow]->v_text[vtcol], 80 - vtcol, ' ' ); } #include "metab.h" /* This is the general command execution * routine. It handles the fake binding of all the * keys to "self-insert". It also clears out the "thisflag" * word, and arranges to move it to the "lastflag", so that * the next command can look at it. Return the status of * command. */ execute() #define cmdchar (*(int *)0x100) #define cmdflag (*(int *)0x102) #define cmdparm (*(int *)0x104) { register char * gp; #define ktp ((KEYTAB *)gp) #define otp ((OVERTAB *)gp) register int status; extern int currow; thisflag = 0; if ( isinsert( cmdchar )) { /* Self inserting. */ #ifdef NEVER /* If space typed, fill column defined, argument non- * negative, and past fill column, word wrap. */ if (cmdchar == ' ' && fillcol > 0 && cmdparm >= 0 && currow >= fillcol ) ovloader( 21, 4 ); /* wrapword(); */ This doesn't work anyway, so... out with it! #endif if (cmdparm <= 0) /* Fenceposts. */ { lastflag = 0; return ( cmdparm < 0 ? FALSE : TRUE); } status = linsert( cmdparm, cmdchar ); byebye: lastflag = thisflag; return (status); } ktp = &keytab[0]; /* Look in key table. */ while (ktp < &keytab[NKEYTAB]) { if (ktp->k_code == cmdchar) { status = (*ktp->k_fp)( cmdflag, cmdparm); goto byebye; } ++ktp; } otp = &overtab[0]; while ( otp < &overtab[NOVERTAB]) { if (otp->k_code == cmdchar) { status = ovloader( otp->ovcode, otp->ovparm, cmdflag, cmdparm ); goto byebye; } ++otp; } lastflag = 0; /* Fake last flags. */ return (ctrlg()); } #include "stdio.h" #include "ed.h" /* * Move the current window up by "arg" * lines. Recompute the new top line of the window. * Look to see if "." is still on the screen. If it is, * you win. If it isn't, then move "." to center it * in the new framing of the window (this command does * not really move "."; it moves the frame). Bound * to "C-X C-P". */ ovmain(x, f, n) register int n; { register LINE *lp; register int i; if (x == 1) { n = -n; x = 0; } if (x == 3) return ( prevwind( f, n )); if (x == 2) return ( nextwind( f, n )); lp = curwp->w_linep; if (n < 0) { while (n++ && lp!=curbp->b_linep) lp = lforw(lp); } else { while (n-- && lback(lp)!=curbp->b_linep) lp = lback(lp); } curwp->w_linep = lp; curwp->w_flag |= WFHARD; /* Mode line is OK. */ for (i=0; iw_ntrows; ++i) { if (lp == curwp->w_dotp) return (TRUE); if (lp == curbp->b_linep) break; lp = lforw(lp); } lp = curwp->w_linep; i = curwp->w_ntrows/2; while (i-- && lp!=curbp->b_linep) lp = lforw(lp); curwp->w_dotp = lp; curwp->w_doto = 0; return (TRUE); } /* * The command make the next * window (next => down the screen) * the current window. There are no real * errors, although the command does * nothing if there is only 1 window on * the screen. Bound to "C-X C-N". */ nextwind(f, n) { register WINDOW *wp; if ((wp=curwp->w_wndp) == NULL) wp = wheadp; curwp = wp; curbp = wp->w_bufp; return (TRUE); } /* * This command makes the previous * window (previous => up the screen) the * current window. There arn't any errors, * although the command does not do a lot * if there is 1 window. */ prevwind(f, n) { register WINDOW *wp1; register WINDOW *wp2; wp1 = wheadp; wp2 = curwp; if (wp1 == wp2) wp2 = NULL; while (wp1->w_wndp != wp2) wp1 = wp1->w_wndp; curwp = wp1; curbp = wp1->w_bufp; return (TRUE); } #include "stdio.h" #include "ed.h" /* * This command makes the current * window the only window on the screen. * Bound to "C-X 1". Try to set the framing * so that "." does not have to move on * the display. Some care has to be taken * to keep the values of dot and mark * in the buffer structures right if the * distruction of a window makes a buffer * become undisplayed. */ ovmain(x, f, n) { register WINDOW *wp; register LINE *lp; register int i; if ( x == 1 ) return ( reposition( f, n )); if ( x == 2 ) return ( refresh( f, n )); while (wheadp != curwp) { wp = wheadp; wheadp = wp->w_wndp; if (--wp->w_bufp->b_nwnd == 0) { wp->w_bufp->b_dotp = wp->w_dotp; wp->w_bufp->b_doto = wp->w_doto; wp->w_bufp->b_markp = wp->w_markp; wp->w_bufp->b_marko = wp->w_marko; } free((char *) wp); } while (curwp->w_wndp != NULL) { wp = curwp->w_wndp; curwp->w_wndp = wp->w_wndp; if (--wp->w_bufp->b_nwnd == 0) { wp->w_bufp->b_dotp = wp->w_dotp; wp->w_bufp->b_doto = wp->w_doto; wp->w_bufp->b_markp = wp->w_markp; wp->w_bufp->b_marko = wp->w_marko; } free((char *) wp); } lp = curwp->w_linep; i = curwp->w_toprow; while (i!=0 && lback(lp)!=curbp->b_linep) { --i; lp = lback(lp); } curwp->w_toprow = 0; curwp->w_ntrows = 22 /* term.t_nrow-1 */; curwp->w_linep = lp; curwp->w_flag |= WFMODE|WFHARD; return (TRUE); } /* * Reposition dot in the current * window to line "n". If the argument is * positive, it is that line. If it is negative it * is that line from the bottom. If it is 0 the window * is centered (this is what the standard redisplay code * does). With no argument it defaults to 1. Bound to * M-!. Because of the default, it works like in * Gosling. */ reposition(f, n) { curwp->w_force = n; curwp->w_flag |= WFFORCE; return (TRUE); } /* * Refresh the screen. With no * argument, it just does the refresh. With an * argument it recenters "." in the current * window. Bound to "C-L". */ refresh(f, n) { if (f == FALSE) { curwp->w_flag |= WFHARD | WFFORCE; sgarbf = TRUE; } else { curwp->w_force = 0; /* Center dot. */ curwp->w_flag |= WFFORCE; } return (TRUE); }  public .ovbgn, ovexit_ ext ovmain_,prctyp dseg ovstkpt: ds 2 saveret: ds 2 cseg .ovbgn: pop h pop h pop h pop h sphl pop b ; call prctyp ;8080 or z80 processor? ; jnc ovbgn10 ;jump if 8080 db 253,225,221,225 ;pop ix, pop iy for z80 processor ovbgn10: pop h shld saveret pop d lxi h,ovret push h lxi h,0 dad sp shld ovstkpt ;save stack pointer for ovexit jmp ovmain_ ovret: xchg ;save return value lhld saveret ;get return addr push h ;place dummy overlay name ptr on stack push h ;place return addr on stack xchg ;restore return value to hl ret ;return to caller ; ovexit_: lxi h,2 ;get return value dad sp mov e,m inx h mov d,m lhld ovstkpt ;get original stack pointer sphl ;and restore it xchg ret ;return back to root end #include "medisp.h" extern int wstyle; extern int ovreq, ovsub, ovreq2, ovsub2; ovmain( x, f, n ) { switch ( x ) { case 0: return ( quit( f, n )); case 1: return ( ctrlg()); case 4: case 2: wstyle = ( x > 3 ) + (( n < 0 ) ? 2 : 0 ); if ( wstyle & 1 ) { if ( wstyle & 2 ) mlwrite( "[vi WORD mode]" ); else mlwrite( "[emacs WORD mode]" ); } else { if ( wstyle & 2 ) mlwrite( "[vi word mode]" ); else mlwrite( "[emacs word mode]" ); } return( TRUE ); case 3: return ( quit( FALSE, n )); } } #ifdef NEVER /* * Fancy quit command, as implemented * by Norm. If the current buffer has changed * do a write current buffer and exit emacs, * otherwise simply exit. */ quickexit(f, n) register int f, n; { if ( ( curbp->b_flag & ( BFCHG | BFTEMP )) == BFTEMP ) { /* changed buffer, not [List] */ ovreq = 9; /* save */ ovsub = 0; ovreq2 = 30; /* conditionally quit */ ovsub2 = 3; } return( TRUE ); } #endif /* * Quit command. If an argument, always * quit. Otherwise confirm if a buffer has been * changed and not written out. Normally bound * to "C-X C-C". */ quit(f, n) { register int s; if (f != FALSE /* Argument forces it. */ || anycb() == FALSE /* All buffers clean. */ || (s=mlyesno("Quit")) == TRUE) { /* User says it's OK. */ vttidy(); exit(0); } return (s); } /* * Look through the list of * buffers. Return TRUE if there * are any changed buffers. Buffers * that hold magic internal stuff are * not considered; who cares if the * list of buffer names is hacked. * Return FALSE if no buffers * have been changed. */ anycb() { register BUFFER *bp; bp = bheadp; while (bp != NULL) { if ( ( bp->b_flag & ( BFTEMP | BFCHG )) == BFCHG ) return (TRUE); bp = bp->b_bufp; } return (FALSE); } /* * Clean up the virtual terminal * system, in anticipation for a return to the * operating system. Move down to the last line and * clear it out (the next system prompt will be * written in the line). Shut down the channel * to the terminal. */ vttidy() { movecursor( 23, 0 ); ansieeol(); }  #include "metab.h" extern FILE * kbdmf; extern FILE * ffp; extern int kbdmstate; extern int ovreq, ovreq2, ovsub, ovsub2; extern char Argbuf[128]; ovmain( x, f, n ) { switch ( x ) { case 0: { /* start keyboard macro */ if ( kbdmf != NULL || ffptest() || kbdmstate != 0 ) { notnow: mlwrite("Not Now"); return (FALSE); } strcpy( Argbuf, "KY+BD+MC.KBM" ); /***********************kbdmf = fopen( "KY+BD+MC.KBM", "w" ); */ ovreq = 33; ovsub2 = 3; ret29: ovreq2 = 29; rettrue: return ( 1 ); } /* end case 1 */ case 3: { /* continue from case 1 */ kbdmf = ffp; ffp = NULL; if ( kbdmf == NULL ) { retbeep: return ( ctrlg()); } mlwrite("[StartMac]"); kbdmstate = 1; goto rettrue; } /* end case 3 */ case 1: { /* end macro */ if ( kbdmf == NULL || ffptest() || ( kbdmstate != 1 && kbdmstate != 2 )) { goto notnow; } fclose( kbdmf ); kbdmstate = 0; mlwrite( ( kbdmstate == 1 ) ? "[EndMac]" : "[MacDone]" ); kbdmf = NULL; goto rettrue; } /* end case 1 */ case 2: { /* execute macro */ if ( kbdmf != NULL || ffptest() || kbdmstate != 0 ) { goto notnow; } strcpy( Argbuf, "KY+BD+MC.KBM" ); ovreq = 32; ovsub2 = 4; goto ret29; } case 4: { /* continue case 2 */ kbdmf = ffp; ffp = NULL; if ( kbdmf == NULL ) { goto retbeep; } kbdmstate = 2; goto rettrue; } } } ffptest() { if ( ffp == NULL ) return ( 0 ); return ( ffp->_flags ); } #include "medisp.h" /* * Redisplay the mode line for * the window pointed to by the "wp". * This is the only routine that has any idea * of how the modeline is formatted. You can * change the modeline format by hacking at * this routine. Called by "update" any time * there is a dirty window. */ extern char * Argv[]; ovmain() { register WINDOW *wp; register char *cp; register int c; register int n; register BUFFER *bp; wp = (WINDOW *) Argv[3]; n = wp->w_toprow+wp->w_ntrows; /* Location. */ vscreen[n]->v_flag |= VFCHG; /* Redraw next time. */ vtmove(n, 0); /* Seek to right line. */ vtputc('='); bp = wp->w_bufp; if ((bp->b_flag&BFCHG) != 0) /* "*" if changed. */ vtputc('*'); else vtputc('='); n = 2; cp = " BetzaEMACS == "; /* Buffer name. */ while ((c = *cp++) != 0) { vtputc(c); ++n; } cp = &bp->b_bname[0]; while ((c = *cp++) != 0) { vtputc(c); ++n; } vtputc(' '); ++n; if (bp->b_fname[0] != 0) { /* File name. */ cp = "== File: "; while ((c = *cp++) != 0) { vtputc(c); ++n; } cp = &bp->b_fname[0]; while ((c = *cp++) != 0) { vtputc(c); ++n; } vtputc(' '); ++n; } #ifdef WFDEBUG vtputc('='); vtputc((wp->w_flag&WFMODE)!=0 ? 'M' : '-'); vtputc((wp->w_flag&WFHARD)!=0 ? 'H' : '-'); vtputc((wp->w_flag&WFEDIT)!=0 ? 'E' : '-'); vtputc((wp->w_flag&WFMOVE)!=0 ? 'V' : '-'); vtputc((wp->w_flag&WFFORCE)!=0 ? 'F' : '-'); n += 6; #endif while (n < 80) { /* Pad to full width. */ vtputc('='); ++n; } } #include "stdio.h" #include "ed.h" ovmain( x, f, n ) { switch (x) { case 0: return (showcpos( f, n )); case 1: return ( twiddle( f, n )); case 2: return ( deblank( f, n )); } } /* * Display the current position of the cursor, * in origin 1 X-Y coordinates, the character that is * under the cursor (in octal), and the fraction of the * text that is before the cursor. The displayed column * is not the current column, but the column that would * be used on an infinite width display. Normally this * is bound to "C-X =". */ showcpos(f, n) { register LINE *clp; register int nch; register int cbo; register int nbc; register int cac; register int ratio; register int col; register int i; register int c; int curln, lines; extern int currow; clp = lforw(curbp->b_linep); /* Grovel the data. */ cbo = nch = lines = 0; for (;;) { lines++; if ( clp == curwp->w_dotp ) { nbc = nch + ( cbo = curwp->w_doto ); curln = lines; if (cbo == llength(clp)) cac = '\n'; else cac = lgetc(clp, cbo); } nch += llength( clp ) + 1; /* 1 allows for newline. */ if (clp == curbp->b_linep) break; clp = lforw(clp); } col = currow + 1; /* Get real column. */ ratio = 0; /* Ratio before dot. */ if (nch != 0) ratio = nbc / ( nch / 100 ); mlwrite("X=%d Y=%d CH=0x%d .=%d (%d%% of %d) line %d of %d", col+1, currow+1, cac, nbc, ratio, nch, curln, lines); return (TRUE); } /* * Twiddle the two characters on either side of * dot. If dot is at the end of the line twiddle the * two characters before it. Return with an error if dot * is at the beginning of line; it seems to be a bit * pointless to make this work. This fixes up a very * common typo with a single stroke. Normally bound * to "C-T". This always works within a line, so * "WFEDIT" is good enough. */ twiddle(f, n) { register LINE *dotp; register int doto; register int cl; register int cr; dotp = curwp->w_dotp; doto = curwp->w_doto; if (doto==llength(dotp) && --doto<0) return (FALSE); cr = lgetc(dotp, doto); if (--doto < 0) return (FALSE); cl = lgetc(dotp, doto); lputc(dotp, doto+0, cr); lputc(dotp, doto+1, cl); lchange(WFEDIT); return (TRUE); } /* * Delete blank lines around dot. * What this command does depends if dot is * sitting on a blank line. If dot is sitting on a * blank line, this command deletes all the blank lines * above and below the current line. If it is sitting * on a non blank line then it deletes all of the * blank lines after the line. Normally this command * is bound to "C-X C-O". Any argument is ignored. */ deblank(f, n) { register LINE *lp1; register LINE *lp2; register int nld; lp1 = curwp->w_dotp; while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep) lp1 = lp2; lp2 = lp1; nld = 0; while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0) ++nld; if (nld == 0) return (TRUE); curwp->w_dotp = lforw(lp1); curwp->w_doto = 0; return (ldelete(nld)); } #include "stdio.h" #include "ed.h" extern FILE * ffp; extern char Argbuf[128]; extern int ovreq; extern int ovsub; extern int ovreq2; extern int ovsub2; ovmain() { ffp = fopen( Argbuf, "r" ); ovreq = ovreq2; ovsub = ovsub2; return ( 1 ); } #include "stdio.h" #include "ed.h" extern FILE * ffp; extern char Argbuf[128]; int ovreq; int ovsub; int ovreq2; int ovsub2; ovmain() { ffp = fopen( Argbuf, "w" ); ovreq = ovreq2; ovsub = ovsub2; return ( 1 ); } #include "stdio.h" #include "ed.h" /* readin.c, continued in another overlay. */ extern FILE * ffp; extern char Argbuf[128]; ovmain( flag ) { register LINE *lp1; register LINE *lp2; register int i; register WINDOW *wp; register int s; register int nbytes; register int nline = 0; char line[NLINE+1]; #ifdef NEVER if (flag < 0) { flag += 2; goto out; } #else if ( ffp == NULL ) { mlwrite( "[New file]" ); goto out; } mlwrite("[Reading]"); #endif if ( ! flag ) { if ( curwp->w_doto ) { lnewline(); curwp->w_doto = 0; } curwp->w_dotp = curwp->w_dotp->l_bp; curbp->b_flag |= BFCHG; } while ( fgets( line, NLINE, ffp) != NULL ) { nbytes = strlen(line); if ( line[ --nbytes ] != '\n' ) { mlwrite( "Long Line" ); nbytes++; } if ((lp1=xlalloc(nbytes)) == NULL) { goto closer; } lp2 = (flag) ? lback(curbp->b_linep) : curwp->w_dotp; (lp1->l_fp = lp2->l_fp)->l_bp = lp1; curwp->w_dotp = (lp1->l_bp = lp2)->l_fp = lp1; blockmv( &lp1->l_text[0], &line[0], nbytes ); ++nline; } mlwrite("[Read %d lines]", nline); if ( ! flag ) curwp->w_dotp = curwp->w_dotp->l_fp; closer: fclose(ffp); /* Ignore errors. */ out: for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) { if (wp->w_bufp == curbp) { wp->w_linep = lforw(curbp->b_linep); wp->w_dotp = ( flag ) ? lforw(curbp->b_linep) : curwp->w_dotp; wp->w_doto = wp->w_markp = wp->w_marko = 0; wp->w_flag |= WFMODE|WFHARD; } } return (TRUE); } /* * This routine allocates a block * of memory large enough to hold a LINE * containing "used" characters. The block is * always rounded up a bit. Return a pointer * to the new block, or NULL if there isn't * any memory left. Print a message in the * message line if no space. */ LINE * xlalloc(size) int size; { register LINE *lp; if ((lp = (LINE *) malloc(( sizeof(LINE)-1 ) +size)) == NULL) { mlwrite("No memory"); return (NULL); } lp->l_size = lp->l_used = size; return (lp); } #include "stdio.h" #include "ed.h" /* * Read file "fname" into the current * buffer, blowing away any text found there. Called * by both the read and visit commands. Return the final * status of the read. Also called by the mainline, * to read in a file specified on the command line as * an argument. */ extern FILE * ffp; #define fname ((char *)0x80) ovmain( flag ) { register LINE *lp1; register LINE *lp2; register int i; register WINDOW *wp; register BUFFER *bp; register int s; register int nbytes; register int nline; char line[NLINE+1]; if (flag && ((s=bclear(bp=curbp)) != TRUE))/* Might be old. */ return (s); bp->b_flag &= ~(BFTEMP|BFCHG); if (flag) strcpy(bp->b_fname, fname); if (( ffp = fopen(fname, "r" )) == NULL) { mlwrite( "[New file]" ); goto out; } mlwrite("[Reading]"); nline = 0; while ( fgets( line, NLINE, ffp) != NULL ) { nbytes = strlen(line); while ( ( s = line[ nbytes - 1 ] ) == '\n' || s == '\r' ) if ( --nbytes <= 0 ) break; if ( nbytes == strlen( line )) mlwrite( "Long Line" ); if ((lp1=xlalloc(nbytes)) == NULL) { s = FIOERR; /* Keep message on the */ break; /* display. */ } lp2 = (flag) ? lback(curbp->b_linep) : (( curwp->w_doto == 0 ) ? curwp->w_dotp->l_fp : curwp->w_dotp ); lp1->l_fp = lp2->l_fp; lp2->l_fp = lp1; lp1->l_bp = lp2; lp1->l_fp->l_bp = lp1; curwp->w_dotp = lp1; curwp->w_doto = 0; /* for (i=0; il_text[0], &line[0], nbytes ); ++nline; } fclose(ffp); /* Ignore errors. */ if (s == FIOEOF) /* Don't zap message! */ { mlwrite("[Read %d lines]", nline); } out: for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) { if (wp->w_bufp == curbp) { wp->w_linep = lforw(curbp->b_linep); wp->w_dotp = ( flag ) ? lforw(curbp->b_linep) : curwp->w_dotp; wp->w_doto = wp->w_markp = wp->w_marko = 0; wp->w_flag |= WFMODE|WFHARD; } } if (s == FIOERR) /* False if error. */ return (FALSE); return (TRUE); } /* * This routine allocates a block * of memory large enough to hold a LINE * containing "used" characters. The block is * always rounded up a bit. Return a pointer * to the new block, or NULL if there isn't * any memory left. Print a message in the * message line if no space. */ LINE * xlalloc(size) int size; { register LINE *lp; if ((lp = (LINE *) malloc(( sizeof(LINE)-1 ) +size)) == NULL) { mlwrite("No memory"); return (NULL); } lp->l_size = lp->l_used = size; return (lp); } #include "stdio.h" #include "ed.h" /* ovudfb31.c: (read "up down forward back" for "udfb") ** overlay 31 source code. ** this large overlay is a portmanteau of frequently-used ** commands. One can hardly justify having some of them in ** overlays UNLESS the overlay in question is one which is ** likely to be in memory at all times -- so, this overlay ** includes gobs of the most useful commands. */ extern int wstyle; /* Which kind of Word operations? */ extern int currow; /* set by update() */ extern int tabsize; /* if tabs are expanded to spaces. */ extern char *kbufp; /* Kill buffer data */ extern int kused; /* # of bytes used in KB */ extern int ksize; /* # of bytes allocated in KB */ #define TABCASE 40 /* case TABCASE and above are special. */ /* cases < TABCASE are numbered so that we can handle a negative ** parameter with "casenumber ^= 1" */ ovmain( x ) #define cmdflag (*(int *)0x102) #define cmdparm (*(int *)0x104) { register LINE * mylp; register WINDOW * mywp; #define temp_int (*(int *)0xc0) #define mydoto (*(int *)0xc2) #define xbufchar (*(int *)0xc4) #define limitp (*(LINE **)0xc6) #define localx (*(int *)0xc8) #define xinsct (*(int *)0xca) #define mylen (*(int *)0xcc) #define Wdoto (*(int *)0xce) /* the above #defines are temporary variables, in effect: ** the compiler generates much smaller code for specific addresses ** than it does for stack variables. */ xinsct = 1; mywp = curwp; mylp = mywp->w_dotp; limitp = curbp->b_linep; temp_int = mydoto = 0; mylen = llength( mylp ); Wdoto = mywp->w_doto; if ( ( localx = x ) < TABCASE ) { /* most commands here have negative-parameter counterparts. */ if ( cmdparm < 0 ) { localx ^= 1; cmdparm = -cmdparm; } } switch ( localx ) { case 13: /* goto end of line. */ mydoto = mylen; goto dotpset; case 12: /* goto start of line. */ if ( cmdflag && ( mydoto = cmdparm -1 ) > mylen ) mydoto = mylen; goto dotpset; case 10: /* page forwards */ case 11: /* page back. */ cmdparm *= ( mywp->w_ntrows - 1 ); goto linemotion; case 1: /* up arrow. */ ++cmdparm; goto linemo2; /* backward goes n+1 lines! */ case 9: /* gotoeob */ if ( cmdparm ) --cmdparm; case 8: /* gotobob */ mylp = curbp->b_linep; linemotion: /* if ( localx & 1 ) */ /* { mylp = lforw( mylp ); */ /* } */ curgoal = curcol = 0; /* mywp->w_flag |= WFHARD; */ linemo2: /* fall through. */ case 0: /* down arrow */ { /* up or down */ if ( ! ( lastflag & CFCPCN )) { /* Reset goal if last not up/down */ curgoal = curcol; } thisflag |= CFCPCN; if ( localx & 1 ) /* backward */ { while ( decparm() && ( mylp = lback( mylp )) != limitp ); } else { while ( decparm() && ( mylp = lforw( mylp )) != limitp ); } /* "--n >= 0" for n+1 lines. */ while ( mydoto != llength( mylp ))/* NOT mylen! */ { if ( ( xbufchar = lgetc( mylp, mydoto )) == '\t' ) temp_int |= 0x07; else if ( ! isinsert( xbufchar )) plustemp(); if ( ++temp_int > curgoal ) break; ++mydoto; } dotpmove: wfmove(); dotpset: mywp->w_dotp = mylp; mywp->w_doto = mydoto; goto rettrue; /* return ( 1 ); */ } /* end case 0 or 1 */ case 2: /* word forward */ case 4: /* del word forward */ { /* mylp = curwp->w_dotp; at top (mylp) */ mydoto = Wdoto; while ( decparm()) { if ( ! ( wstyle & 2 ) && ! fwx()) { goto retfalse; } while ( inword( )) { fc1(); /* assert the above cannot fail. */ plustemp(); } if ( wstyle & 2 && ! fwx()) { goto retfalse; } } if ( localx == 2 ) goto rettrue; mywp->w_dotp = mylp; mywp->w_doto = mydoto; goto retldel; /* return ( ldelete( temp_int, 1 )); */ } /* end case 2 or 4 */ case 3: /* word backward */ case 5: /* del word backward */ { if ( ! bc1( )) goto retfalse; /* TOF */ /* temp_int++; */ while ( decparm()) { while ( ! inword( )) { if ( ! bc1()) goto retfalse; plustemp(); } while ( inword( )) { if ( ! bc1()) { /* top of file. */ retfalse: return ( 0 ); } plustemp(); } } /* temp_int--; */ fc1(); /* can't fail. */ if ( localx == 5 ) { /* delword. */ retldel: cmdflag = 1; ret2ldel: return ( ldelete( temp_int, cmdflag )); } rettrue: return ( 1 ); } /* end case 3 or 5. */ case 6: /* forwdel() */ case 7: /* backdel() */ { if ( cmdflag ) { /* Really a kill. */ kdcheck(); } if ( ( localx & 1 ) && ! backchar( cmdflag, cmdparm )) goto retfalse; temp_int = cmdparm; goto ret2ldel; /*return(ldelete(cmdparm,cmdflag));*/ } /* end cases 6 and 7 */ case TABCASE: { /* with no parameter, perform tab function; ** with one, set tabsize. */ if ( cmdparm < 0 ) return ( 0 ); if ( cmdparm != 1 ) { tabsize = cmdparm; return( 1 ); } xbufchar = '\t'; if ( tabsize ) { xinsct = tabsize - ( ( curcol + 1 ) % tabsize ); xbufchar = ' '; } return( xlinsc( )); } /* end case TABCASE */ case TABCASE+1: /* openline() */ case TABCASE+2: /* indent() */ { /* openline() keeps cursor in same place, ** inserts arg newlines. ** indent() moves forward with its newlines, ** adds whitespace to match the current line. */ mylp = lback( mylp ); mydoto = Wdoto; while ( decparm()) if ( ! lnewline()) goto retfalse; mylp = lforw( mylp ); /* lnewline() may delete the original ** target of mylp. */ if ( localx == ( TABCASE + 1 )) { /* openline(), done. */ goto dotpset; } while ( ( xbufchar = lgetc( mylp, ++cmdparm )) == ' ' || xbufchar == '\t' ) { xlinsc( ); } if ( xbufchar == '{' ) { /* C indent */ xbufchar = '\t'; xlinsc(); } goto rettrue; } /* end case indent() and openline() */ case TABCASE+7: /* vi-style kill. */ cmdflag = 1; mywp->w_doto = Wdoto = 0; /* fall through. */ case TABCASE+3: /* kill() */ { kdcheck(); mydoto = Wdoto; if ( ! cmdflag ) { temp_int = mylen - mydoto; if ( temp_int == 0 ) temp_int = 1; } else if ( ! cmdparm ) { temp_int = mydoto; mywp->w_doto = 0; } else if ( decparm()) /* "if n > 0" */ { temp_int = mylen - mydoto + 1; mylp = lforw( mylp ); while (decparm()) /* while --n */ { if ( mylp == limitp ) goto retfalse; temp_int += llength( mylp ) + 1; mylp = lforw( mylp ); } } else { /* mlwrite("neg kill"); */ ctrlg(); goto retfalse; } goto retldel; /*return(ldelete(temp_int,TRUE));*/ } /* end case "kill()" */ case TABCASE+4: /* yank() */ { if ( ! decparm()) goto retfalse; do /* make cmdparm copies. */ { temp_int = 0; while ( temp_int < kused ) { if ( ( xbufchar = kbufp[ temp_int ]) == '\n' ) { lnewline( ); } else { if ( ! xlinsc()) goto retfalse; } plustemp(); } } while ( decparm( )); goto rettrue; } /* end case yank() */ case TABCASE+5: /* set mark */ { mlwrite("[Mark]"); markset: mywp->w_markp = mylp; mywp->w_marko = Wdoto; goto rettrue; } /* end case set mark */ case TABCASE+6: /* exchange mark and cursor. */ { if ( mywp->w_markp == NULL ) { mlwrite("No mark"); return ( 0 ); } mywp->w_dotp = mywp->w_markp; mywp->w_doto = mywp->w_marko; wfmove(); goto markset; } /* end case ^X^X */ } } fc1() /* saves 10 bytes per call to it. */ { return( forwchar( 0, 1 )); } bc1() /* saves 10 bytes per call to it. */ { return( backchar( 0, 1 )); } fwx() /* loop used twice in forwword. */ { while ( ! inword( )) { if ( ! fc1( )) return ( 0 ); plustemp(); } return ( 1 ); } plustemp() /* temp_int++ : saves 2 bytes per call. */ { ++temp_int; } decparm() /* --cmdparm >= 0 */ { return ( --cmdparm >= 0 ); } xlinsc() { return( linsert( xinsct, xbufchar )); } kdcheck() { if ( ! ( lastflag & CFKILL )) kdelete(); thisflag |= CFKILL; } wfmove() { curwp->w_flag |= WFMOVE; } /* * The routines in this file * implement commands that work word at * a time. There are all sorts of word mode * commands. If I do any sentence and/or paragraph * mode commands, they are likely to be put in * this file. */ #include "stdio.h" #include "ed.h" ovmain( x, f, n ) { switch ( x ) { case 0: return ( upperword( f, n )); case 1: return ( lowerword( f, n )); case 2: return ( capword( f, n )); /* case 3: return ( setfillcol( f, n )); */ /* case 4: return ( wrapword( )); */ } } #ifdef NEVER /* Word wrap on n-spaces. * Back-over whatever precedes the point on the current line and * stop on the first word-break or the beginning of the line. * If we reach the beginning of the line, jump back to the end of the * word and start a new line. Otherwise, break the line at the * word-break, eat it, and jump back to the end of the word. * NOTE: This function may leaving trailing blanks. * Returns TRUE on success, FALSE on errors. */ wrapword() { register int cnt; register LINE *oldp; oldp = curwp->w_dotp; cnt = -1; do { cnt++; if (! backchar(NULL, 1)) return(FALSE); } while (! inword()); if (! backword(NULL, 1)) return(FALSE); if (oldp == curwp->w_dotp && curwp->w_doto ) { if (! backdel(NULL, 1)) return(FALSE); if (! newline(NULL, 1)) return(FALSE); } return(forwword(NULL, 1) && forwchar(NULL, cnt)); } /* * Set fill column to n. */ setfillcol(f, n) { fillcol = n; return(TRUE); } #endif /* * Move the cursor forward by * the specified number of words. As you move, * convert any characters to upper case. Error * if you try and move beyond the end of the * buffer. Bound to "M-U". */ upperword(f, n) { register int c; if (n < 0) return (FALSE); while (n--) { while (inword() == FALSE) { if (forwchar(FALSE, 1) == FALSE) return (FALSE); } while (inword() != FALSE) { c = lgetc(curwp->w_dotp, curwp->w_doto); if (c>='a' && c<='z') { c -= 'a'-'A'; lputc(curwp->w_dotp, curwp->w_doto, c); lchange(WFHARD); } if (forwchar(FALSE, 1) == FALSE) return (FALSE); } } return (TRUE); } /* * Move the cursor forward by * the specified number of words. As you move * convert characters to lower case. Error if you * try and move over the end of the buffer. * Bound to "M-L". */ lowerword(f, n) { register int c; if (n < 0) return (FALSE); while (n--) { while (inword() == FALSE) { if (forwchar(FALSE, 1) == FALSE) return (FALSE); } while (inword() != FALSE) { c = lgetc(curwp->w_dotp, curwp->w_doto); if (c>='A' && c<='Z') { c += 'a'-'A'; lputc(curwp->w_dotp, curwp->w_doto, c); lchange(WFHARD); } if (forwchar(FALSE, 1) == FALSE) return (FALSE); } } return (TRUE); } /* * Move the cursor forward by * the specified number of words. As you move * convert the first character of the word to upper * case, and subsequent characters to lower case. Error * if you try and move past the end of the buffer. * Bound to "M-C". */ capword(f, n) { register int c; if (n < 0) return (FALSE); while (n--) { while (inword() == FALSE) { if (forwchar(FALSE, 1) == FALSE) return (FALSE); } if (inword() != FALSE) { c = lgetc(curwp->w_dotp, curwp->w_doto); if (c>='a' && c<='z') { c -= 'a'-'A'; lputc(curwp->w_dotp, curwp->w_doto, c); lchange(WFHARD); } if (forwchar(FALSE, 1) == FALSE) return (FALSE); while (inword() != FALSE) { c = lgetc(curwp->w_dotp, curwp->w_doto); if (c>='A' && c<='Z') { c += 'a'-'A'; lputc(curwp->w_dotp, curwp->w_doto, c); lchange(WFHARD); } if (forwchar(FALSE, 1) == FALSE) return (FALSE); } } } return (TRUE); } #include "stdio.h" #include "ed.h" extern FILE * ffp; extern int ovreq, ovreq2, ovsub, ovsub2; extern char Argbuf[128]; /* * This function performs the details of file * writing. Sadly, it looks inside a LINE; Most of the grief is error * checking of some sort. * fopen() is in overlay 33! Too big! */ ovmain() { register WINDOW * wp; register int s; register LINE *lp; register int nline; char backname[NFILEN]; s = TRUE; if ( ffp == NULL) return (ctrlg()); lp = lforw(curbp->b_linep); /* First line. */ nline = 0; /* Number of lines. */ while (lp != curbp->b_linep) { if ( fwrite( &lp->l_text[0], 1, llength(lp), ffp) != llength(lp) || putc( '\r', ffp ) == EOF || putc( '\n', ffp ) == EOF ) { s = FALSE; mlwrite("Write I/O error"); break; } ++nline; lp = lforw(lp); } putc( ('z'&0x1f), ffp ); fclose( ffp ); if (s == TRUE) { /* No write error. */ mlwrite("[Wrote %d lines]", nline); curbp->b_flag &= ~BFCHG; wp = wheadp; /* Update mode lines. */ while (wp != NULL) { if (wp->w_bufp == curbp) wp->w_flag |= WFMODE; wp = wp->w_wndp; } } return ( s ); } /* included... */ extern FILE * ffp; extern int ovsub, ovreq, ovsub2, ovreq2; /* * Read file "fname" into the current * buffer, blowing away any text found there. Called * by both the read and visit commands. Return the final * status of the read. Also called by the mainline, * to read in a file specified on the command line as * an argument. */ extern char Argbuf[128]; readin( fname, flag ) char *fname; { register BUFFER *bp; register int s; bp = curbp; if ( flag ) { if (( s = bclear( bp )) != TRUE ) /* Might be old. */ return (s); strcpy( bp->b_fname, fname ); } bp->b_flag &= ~( BFTEMP | BFCHG ); /* set up overlay thread: */ strcpy( Argbuf, fname ); /* parameter to fopen() */ ovreq = 32; /* first call fopen() overlay. */ ovreq2 = 27; /* then call ovread27 */ ovsub2 = flag; /* parameter for ovread27 */ return ( TRUE ); } #include "stdio.h" #include "ed.h" /* * Shrink the current window. * Find the window that gains space. Hack at * the window descriptions. Ask the redisplay to * do all the hard work. Bound to "C-X C-Z". */ ovmain(x, f, n) { register WINDOW *adjwp; register LINE *lp; register int i; if (n < 0) { ctrlg(); return (FALSE); } /* return (enlargewind(f, -n));*/ if (wheadp->w_wndp == NULL) { mlwrite("Only one window"); return (FALSE); } if ((adjwp=curwp->w_wndp) == NULL) { adjwp = wheadp; while (adjwp->w_wndp != curwp) adjwp = adjwp->w_wndp; } if (curwp->w_ntrows <= n) { mlwrite("Impossible change"); return (FALSE); } if (curwp->w_wndp == adjwp) { /* Grow below. */ lp = adjwp->w_linep; for (i=0; iw_bufp->b_linep; ++i) lp = lback(lp); adjwp->w_linep = lp; adjwp->w_toprow -= n; } else { /* Grow above. */ lp = curwp->w_linep; for (i=0; ib_linep; ++i) lp = lforw(lp); curwp->w_linep = lp; curwp->w_toprow += n; } curwp->w_ntrows -= n; adjwp->w_ntrows += n; curwp->w_flag |= WFMODE|WFHARD; adjwp->w_flag |= WFMODE|WFHARD; return (TRUE); } #include "stdio.h" #include "ed.h" /* * Split the current window. A window * smaller than 3 lines cannot be split. * The only other error that is possible is * a "malloc" failure allocating the structure * for the new window. Bound to "C-X 2". */ ovmain( x, f, n ) { register WINDOW *wp; register LINE *lp; register int ntru; register int ntrl; register int ntrd; register WINDOW *wp1; register WINDOW *wp2; if (curwp->w_ntrows < 3) { mlwrite("Cannot split a %d line window", curwp->w_ntrows); return (FALSE); } if ((wp = (WINDOW *) malloc(sizeof(WINDOW))) == NULL) { mlwrite("Cannot allocate WINDOW block"); return (FALSE); } ++curbp->b_nwnd; /* Displayed twice. */ wp->w_bufp = curbp; wp->w_dotp = curwp->w_dotp; wp->w_doto = curwp->w_doto; wp->w_markp = curwp->w_markp; wp->w_marko = curwp->w_marko; wp->w_flag = 0; wp->w_force = 0; ntru = (curwp->w_ntrows-1) / 2; /* Upper size */ ntrl = (curwp->w_ntrows-1) - ntru; /* Lower size */ lp = curwp->w_linep; ntrd = 0; while (lp != curwp->w_dotp) { ++ntrd; lp = lforw(lp); } lp = curwp->w_linep; if (ntrd <= ntru) { /* Old is upper window. */ if (ntrd == ntru) /* Hit mode line. */ lp = lforw(lp); curwp->w_ntrows = ntru; wp->w_wndp = curwp->w_wndp; curwp->w_wndp = wp; wp->w_toprow = curwp->w_toprow+ntru+1; wp->w_ntrows = ntrl; } else { /* Old is lower window */ wp1 = NULL; wp2 = wheadp; while (wp2 != curwp) { wp1 = wp2; wp2 = wp2->w_wndp; } if (wp1 == NULL) wheadp = wp; else wp1->w_wndp = wp; wp->w_wndp = curwp; wp->w_toprow = curwp->w_toprow; wp->w_ntrows = ntru; ++ntru; /* Mode line. */ curwp->w_toprow += ntru; curwp->w_ntrows = ntrl; while (ntru--) lp = lforw(lp); } curwp->w_linep = lp; /* Adjust the top lines */ wp->w_linep = lp; /* if necessary. */ curwp->w_flag |= WFMODE|WFHARD; wp->w_flag |= WFMODE|WFHARD; return (TRUE); } #include "stdio.h" #include "ed.h" #define NROW 24 /* Screen size. */ #define NCOL 80 /* Edit if you want to. */ #define BEL 0x07 /* BEL character. */ #define ESC 0x1B /* ESC character. */ int ansiterm; char termctrl[3][10] = { 4, ESC, '=', ' ', ' ', 0,0,0,0,0, 2, ESC, 'T', 0,0, 0,0,0,0,0, 1, 26, 0,0,0, 0,0,0,0,0 }; ansimove(row, col) { register char * cp; register int i; cp = &termctrl[0][0]; i = *cp++; conout( *cp++ ); --i; conout( *cp++ ); --i; if ( ! ansiterm ) { conout( row + *cp++ ); ++i; conout( col + *cp++ ); ++i; } else { conout( ( row / 10 ) + *cp++ ); ++i; conout( ( row % 10 ) + *cp++ ); ++i; conout( *cp++ ); --i; conout( ( row / 10 ) + *cp++ ); ++i; conout( ( row % 10 ) + *cp++ ); ++i; } while ( --i >= 0 ) conout( *cp++ ); } ansiclear() { ctlout( 2 ); } ansieeol() { ctlout( 1 ); } ctlout( x ) { register char * cp; register int i; cp = &termctrl[x][0]; i = *cp++; while ( --i >= 0 ) conout( *cp++ ); } ansibeep() { conout( BEL ); } #include "stdio.h" #include "ed.h" /* * Upper case region. Zap all of the lower * case characters in the region to upper case. Use * the region code to set the limits. Scan the buffer, * doing the changes. Call "lchange" to ensure that * redisplay is done in all buffers. Bound to * "C-X C-L". */ ovmain(x, f, n) { register LINE *linep; register int loffs; register int c; register int s; REGION region; if ((s=getregion(®ion)) != TRUE) return (s); lchange(WFHARD); linep = region.r_linep; loffs = region.r_offset; while (region.r_size--) { if (loffs == llength(linep)) { linep = lforw(linep); loffs = 0; } else { c = lgetc(linep, loffs); if (c>='a' && c<='z') lputc(linep, loffs, c-'a'+'A'); ++loffs; } } return (TRUE); } #include "getreg.c" #include "stdio.h" #include "ed.h" /* * Attach a buffer to a window. The * values of dot and mark come from the buffer * if the use count is 0. Otherwise, they come * from some other window. */ ovmain( x, f, n) { register BUFFER *bp; register WINDOW *wp; register int s; char bufn[NBUFN]; if ( x ) { /* "next buffer" */ bp = curbp->b_bufp; if ( bp == NULL ) bp = bheadp; } else { /* normal usebuffer() routine. */ if ((s=mlreply("Use buffer: ", bufn, NBUFN)) != TRUE) return (s); if ((bp=bfind(bufn, TRUE, 0)) == NULL) return (FALSE); } if (--curbp->b_nwnd == 0) { /* Last use. */ curbp->b_dotp = curwp->w_dotp; curbp->b_doto = curwp->w_doto; curbp->b_markp = curwp->w_markp; curbp->b_marko = curwp->w_marko; } curbp = bp; /* Switch. */ curwp->w_bufp = bp; curwp->w_linep = bp->b_linep; /* For macros, ignored. */ curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty. */ if (bp->b_nwnd++ == 0) { /* First use. */ curwp->w_dotp = bp->b_dotp; curwp->w_doto = bp->b_doto; curwp->w_markp = bp->b_markp; curwp->w_marko = bp->b_marko; return (TRUE); } wp = wheadp; /* Look for old. */ while (wp != NULL) { if (wp!=curwp && wp->w_bufp==bp) { curwp->w_dotp = wp->w_dotp; curwp->w_doto = wp->w_doto; curwp->w_markp = wp->w_markp; curwp->w_marko = wp->w_marko; break; } wp = wp->w_wndp; } return (TRUE); } /* * Window management. * Some of the functions are internal, * and some are attached to keys that the * user actually types. */ #include "stdio.h" #include "ed.h" /* * Pick a window for a pop-up. * Split the screen if there is only * one window. Pick the uppermost window that * isn't the current window. An LRU algorithm * might be better. Return a pointer, or * NULL on error. */ WINDOW * wpopup() { register WINDOW *wp; if (wheadp->w_wndp == NULL) /* Only 1 window */ /* && splitwind(FALSE, 0) == FALSE) /* and it won't split */ return (NULL); wp = wheadp; /* Find window to use */ while (wp!=NULL && wp==curwp) wp = wp->w_wndp; return (wp); } extern FILE * ffp; extern int ovreq, ovreq2, ovsub, ovsub2; extern char Argbuf[128]; /* writeout.c: #included by filesave.c and filewrite.c * This function starts to write a file. It makes a * CP/M-style backup file, then sets up an overlay thread, * ovopwr33 and ovwrit34. */ writeout(fn) char *fn; { register int s; /* register LINE *lp; */ /* register int nline; */ char backname[NFILEN]; strcpy( backname, fn ); s = 0; while ( backname[s] && backname[s] != '.' ) s++; if ( backname[s] == '.') backname[++s] = 0; else { backname[++s] = '.'; backname[++s] = 0; } strcat( backname, "bak" ); rename( fn, backname ); /* CP/M style backup file has been created. */ strcpy( Argbuf, fn ); ovreq = 33; ovreq2 = 34; return ( 1 ); #ifdef NEVER s = TRUE; if ((ffp=fopen(fn, "w")) == NULL) /* Open writes message. */ return (ctrlg()); lp = lforw(curbp->b_linep); /* First line. */ nline = 0; /* Number of lines. */ while (lp != curbp->b_linep) { if ( fwrite( &lp->l_text[0], 1, llength(lp), ffp) != llength(lp) || putc( '\r', ffp ) == EOF || putc( '\n', ffp ) == EOF ) { s = FALSE; mlwrite("Write I/O error"); break; } ++nline; lp = lforw(lp); } putc( ('z'&0x1f), ffp ); fclose( ffp ); if (s == TRUE) { /* No write error. */ mlwrite("[Wrote %d lines]", nline); } return ( s ); #endif } czii mapkeys.c as mapkeys.asm era mapkeys.asm ln mapkeys.o c:z80libc.lib c:mylib.lib mapkeys  /**********************************************************/ /* */ /* Implements CI-Vague-Input: */ /* */ /* The task is to match up a command name from the */ /* UECS with a user input. In the comparison, dashes */ /* and case are ignored. Furthermore, the user can */ /* input a partial string: "visi" returns */ /* */ /* SC-Visit-Cursor-Buffer */ /* SC-Visit-Cursor-File */ /* SC-Visit-File */ /* UI-File-Selection-Visit-File */ /* */ /* The above example also demonstrates the */ /* significance of the dashes in the names in the */ /* UECS list -- the portion of the name that follows */ /* a dash is selectable! */ /* */ /* This means that this implementation of */ /* CI-Vague-Input also effectively includes */ /* CI-Help-Apropos! */ /* */ /* The user's ability to enter a partial string */ /* effectively implements a form of */ /* CI-Command-Completion! */ /* */ /**********************************************************/ #include "ostdio.h" #include "fcntl.h" #define NSNLEN 50 #define MAXnnoffs 8 struct ns { int noff[MAXnnoffs]; /* noff[0] is offset of start of main portion. */ int nnoffs; int nlen; int nsnumber; char nsname[NSNLEN]; char nsoname[NSNLEN]; } nstab[200]; int nsentries; struct ns * ns_matched; char linebuf[256]; char workbuf[256]; int worklen; char * UECSfile = "zmecmds.lst"; char * outname = "maptable.zme"; int outfile; main( argc, argv ) char ** argv; { if ( argc > 1 ) { UECSfile = argv[1]; } if ( argc > 2 ) { outname = argv[2]; } outfile = open( outname, O_CREAT|O_WRONLY|O_TRUNC ); if ( outfile < 0 ) { fprintf( stderr, "could not open %d for output\n", outname ); myexit ( 1 ); } nsload(); while ( 1 ) { inget(); if ( nscomp() == 1 ) dokey(); } } nsload() { FILE * inf; int lnumber = 0; int i, j; char * cp, *qp; int c; struct ns * nsp; if ( ( inf = fopen( UECSfile, "r" )) == NULL ) { fprintf( stderr, "open fails: %s\n", UECSfile ); myexit ( 1 ); } nsp = & nstab[0]; while ( fgets( linebuf, 254, inf ) != NULL ) { ++lnumber; if ( linebuf[0] < '0' || linebuf[0] > '9' ) continue; cp = linebuf; while ( c = *cp++ ) { if ( c == '\t' ) { goto foundtab; } } continue; foundtab: i = strlen( cp ); while ( i > 0 && ( ( c = cp[ --i ]) == '\n' || c == '\r' || c == ' ' || c == '\t' ) ) cp[ i ] = 0; if ( i < 0 || i > ( NSNLEN - 1 ) ) continue; for ( i = 0, qp = linebuf; *qp <= '9' && *qp >= '0'; ++qp ) { i *= 10; i += *qp - '0'; } nsp->nsnumber = i; strcpy( nsp->nsoname, cp ); nsp->nnoffs = 0; for ( i = j = 0; nsp->nnoffs < MAXnnoffs && cp[ i ]; ++i ) { if ( cp[i] == '-' ) { nsp->noff[ nsp->nnoffs++ ] = j; } else ++j; } for ( qp = nsp->nsname; *cp; ++cp ) { if ( *cp == '-' ) continue; c = *cp; if ( c >= 'A' && c <= 'Z' ) { c ^= ( 'a' ^ 'A' ); /* tolower */ } *qp++ = c; *qp = 0; } nsp->nlen = strlen( nsp->nsname ); ++nsp; ++nsentries; } printf( "Read %d lines\n\n", nsentries ); } inget() { printf( "Enter a name: " ); linebuf[0] = 0; if ( fgets( linebuf, 254, stdin ) == NULL || linebuf[0] == 26 || linebuf[0] == 0 || linebuf[0] == 4 ) { printf( "\nreached EOF\n" ); myexit ( 0 ); } } myexit( n ) { if ( outfile >= 0 ) close( outfile ); exit ( n ); } nscomp() { int i, c, j; char * cp, *qp; int wlen; int nmatch; struct ns * nsp; cp = linebuf; nsp = &nstab[ nmatch = i = j = 0 ]; if ( *cp == ( 'z' & 0x1f )) myexit ( 0 ); while ( ( c = *cp++ ) >= '0' && c <= '9' ) { /* Numeric. */ j *= 10; j += c - '0'; } if ( j ) { /* Numeric. */ for ( ; i < nsentries; ++nsp, ++i ) { if ( nsp->nsnumber != j ) continue; ++nmatch; ns_matched = nsp; printf( "%3d %s\n", nsp->nsnumber, nsp->nsoname ); } goto outa_here; } --cp; i = strlen( cp ); while ( i > 0 && ( ( c = cp[ --i ]) == '\n' || c == '\r' || c == ' ' || c == '\t' ) ) cp[ i ] = 0; if ( i < 0 || i > ( NSNLEN - 1 ) ) { printf( "bad input line\n" ); myexit ( 0 ); } /* i == 0 prints them all. */ for ( qp = workbuf; *cp; ++cp ) { if ( *cp == '-' ) continue; c = *cp; if ( c >= 'A' && c <= 'Z' ) { c ^= ( 'a' ^ 'A' ); /* tolower */ } *qp++ = c; *qp = 0; } worklen = strlen( workbuf ); for ( i = 0; i < nsentries; ++nsp, ++i ) { wlen = nsp->nlen; if ( worklen > wlen ) { /* if the string that the user entered is longer ** than the string in the table, this is a ** mismatch! */ continue; } if ( worklen < wlen ) wlen = worklen; if ( ! strncmp( workbuf, nsp->nsname, wlen )) { printf( "%3d %s\n", nsp->nsnumber, nsp->nsoname ); ns_matched = nsp; retcon( ++nmatch ); continue; } for ( j = 0; j < nsp->nnoffs; ++j ) { /* try pieces of the input name. */ wlen = nsp->nlen - nsp->noff[j]; if ( worklen > wlen ) break; if ( worklen < wlen ) wlen = worklen; if ( ! strncmp( workbuf, &nsp->nsname[ nsp->noff[j] ], wlen )) { printf( "%3d %s\n", nsp->nsnumber, nsp->nsoname ); ns_matched = nsp; retcon( ++nmatch ); break; } } } outa_here: printf( "===== %d matches\n", nmatch ); return nmatch; } retcon( n ) { if ( n % 23 ) return; printf( "[MORE]" ); while ( ( n = getchar()) != '\n' && n != EOF ); } struct { int UECSout; int KEYout; } out; dokey() { /* ns_matched is set to the nstab entry we need. */ int result, i, c, flags, state; #define META 0x200 #define CTLX 0x400 #define MAGIC 0x100 again: i = -1; flags = state = 0; printf( "Enter a keystroke sequence: " ); while ( ( c = getchar()) != EOF && c != '\n' ) { if ( state & 4 ) continue; switch ( c ) { case '\r': case ' ': continue; case '^': if ( ! ( state & 1 )) { state |= 1; continue; } ctlchar: i = c & 0x1f; ctldel: state &= ~1; if ( ! ( state & 2 )) { /* first character */ if ( i == ( 'x' & 0x1f )) { state |= 2; flags |= CTLX; continue; } if ( i == 0x1b ) { state |= 2; flags |= META; continue; } if ( i == 1 ) { state |= 2; flags |= MAGIC; continue; } state |= 4; continue; } /* else second character: */ state |= 4; continue; case '?': if ( state & 1 ) { i = 0x7f; goto ctldel; } default: i = c; if ( c < 0x20 || c > 0x7f ) continue; if ( state & 1 ) goto ctlchar; if ( ! ( state & 2 )) flags = -1; state |= 4; continue; } } switch ( flags ) { case META: case CTLX: break; case 0: if ( ! ( i >= 0x20 && i <= 0x7f )) break; goto badseq; case MAGIC: if ( i >= 0x20 && i <= 0x7f ) break; default: badseq: printf( "Please try again\n" ); goto again; } if ( i == -1 ) { printf( "Okay, we'll skip this one.\n" ); return; } out.UECSout = ns_matched->nsnumber; out.KEYout = i | flags; if ( write( outfile, &out, sizeof( out )) != sizeof( out )) { fprintf( stderr, "write error\n" ); myexit( 1 ); } printf( "The internal code 0x%x has been mapped to %d %s\n", i | flags, ns_matched->nsnumber, ns_matched->nsoname ); } ^@ gotobol M-Y killbuf, TVI "PAGE ERA" M-_ lowerword ^B wordback M-* setmark "SHIFT-CLEAR" M-~ twiddle ^C forwpage M-! reposition ^X^B listbuf ^D forwdel M-b del word back ^X^C Hard quit. ^E gotoeol M-c capword ^X^F visit file ^F forwword M-f delfword ^X^J scroll down window ^G ctrlg M-g gotobob gotoline ^X^K scroll up window ^H backchar M-G gotoeob ^X^L lowercase region ^I tab M-I exec kbmac BACKTAB ^X^N change name ^J forw M-j upperc reg "SHIFT up" ^X^O deblank ^K backline M-L killreg "SHIFT PRINT" ^X^R fileread ^L forwchar M-P copyregion "PRINT" ^X^S filesave ^M inde M-Q quote "CHAR INS" ^X^V scroll down window ^N fsearch M-R vi kill "LINE DEL" ^X^W write file ^O openline M-T kill "LINE ERA" ^X^Z shrink current window ^P bsearch M-w word mode ^X= show cursor stats ^R backpage M-W Word mode ^X1 one window ^X2 split win ^U parameter M-Y killbuf "PAGE ERA" ^\ negative param ^V TVI DOWN ARR M-\ refresh ^Xb use buffer ^X prefix M-_ lowerword ^X( startmacro ^X) endmacro ^Y yank M-^ upperword ^Xz grow window ^Z swapmark"CLEAR" ^^ next buf "HOME" ^Xn nextwind ^Xp prevwind ^[ META prefix ^? backdel M-\ refresh #include "stdio.h" #include "fcntl.h" #define NEEDNAME 8 int gotname; /* we have to fine NEEDNAME names in ME.SYM */ #define METACH 0x1B /* M- prefix, Control-[, ESC */ #define CMINUSCH 0x1c #define META 0x0200 /* Meta flag, or'ed in */ #define CTLX 0x0400 /* ^X flag, or'ed in */ typedef struct { short k_code; /* Key code */ int (*k_fp)(); /* Routine to handle it */ } KEYTAB; typedef struct { short k_code; /* same as KEYTAB */ char ovcode; /* which overlay. */ char ovparm; /* which routine in overlay. */ } OVERTAB; KEYTAB * pMyKeytab; /* where I will malloc() my version. */ int myNKEYTAB; /* contents of NKEYTAB from me.com */ int pkeytab; /* address of keytab[] in me.com */ int pNKEYTAB; /* address of NKEYTAB in me.com */ char * NKname = "NKEYTAB_"; /* name of NKEYTAB in me.sym */ char * KTname = "keytab_"; /* name of keytab[] in me.sym */ OVERTAB * pMyOvertab; int myNOVERTAB; int povertab; int pNOVERTAB; char * NOname = "NOVERTAB"; char * OTname = "overtab_"; struct bitab { /* built-in commands. */ char * bifname; /* name in ME.SYM */ int (*biffunc)(); /* Address from ME.SYM */ char * biUECSname; /* UECS name. */ int biUM; /* UM/UECS mapping. */ int biUECS; /* UECS number. */ } bi [] = { /* static initializers. */ { "ctrlg_" , 0, "CI-Abort-Cancel", 7, 11 }, { "backchar", 0, "EC-Arrow-Left", 8, 80 }, { "forwchar", 0, "EC-Arrow-Right", 12, 81 }, { "linsert_", 0, "EC-Self_Insert", -1, 245 }, { "", 0, "", -1, -1 } }; struct ovlytab { /* overlays to be mapped. */ char * ovUECSname; int ovUM; char xovnum; char xovparm; int ovUECS; } ovly[] = { /* and here they are! */ #include "cfgnames.h" { "", -1, 0, 0, -1 } }; char symbuf[80]; FILE * symf; int i; char * cp; int comfd; char * symname = "ME.SYM"; char * comname = "ME.COM"; long lspos; char * maptname = "maptable.zme"; int maptfd; main() { symf = fopen( symname, "r" ); if ( symf == NULL ) { printf( "%s not found\n", symname ); badex: exit ( 1 ); } maptfd = open( maptname, O_RDONLY ); if ( maptfd < 0 ) { printf( "%s not found\n", maptname ); goto badex; } gotname = 0; while ( gotname < NEEDNAME && fgets( symbuf, 79, symf ) != NULL ) { i = strlen( symbuf ) -1; while ( symbuf[i] == '\r' || symbuf[i] == '\n' ) symbuf[ i-- ] = 0; cp = &symbuf[ 5 ]; for ( i = 0; bi[i].bifname[0]; i++) { if ( ! strcmp( cp, &bi[i].bifname[0] )) { cvout( &bi[i].biffunc ); continue; } } if ( ! strcmp( cp, KTname )) { cvout( &pkeytab ); continue; } if ( ! strcmp( cp, OTname )) { cvout( &povertab ); continue; } if ( ! strcmp( cp, NKname )) { cvout( &pNKEYTAB ); continue; } if ( ! strcmp( cp, NOname )) { cvout( &pNOVERTAB ); continue; } } fclose( symf ); if ( gotname < NEEDNAME ) { printf( "only %d out of %d names found in %s\n", gotname, NEEDNAME, symname ); goto badex; } comfd = open( comname, O_RDWR ); if ( comfd < 0 ) { printf( "%s not found\n", comname ); goto badex; } /* We have opened the .COM file; now we need to ** do some lpos() and read() operations: the purpose is ** to get the number of entries for the KEYTAB and ** OVERTAB arrays, then to read in the arrays from ** the .COM file. */ dolseek( pNOVERTAB ); /* address in .COM of NOVERTAB */ if ( read( comfd, &myNOVERTAB, 2 ) != 2 ) { printf( "read myNOVERTAB fails\n" ); goto badex; } /* now we havew retrieved a value from .COM file. */ if ( ( pMyOvertab = (OVERTAB *)malloc( sizeof(OVERTAB) * myNOVERTAB )) == NULL ) { printf( "failed: pMyOvertab = malloc( %d * %d )\n", sizeof( OVERTAB ), myNOVERTAB ); goto badex; } dolseek( povertab ); if ( read( comfd, pMyOvertab, sizeof(OVERTAB) * myNOVERTAB ) != ( sizeof(OVERTAB) * myNOVERTAB )) { printf( " failed: read overlay dispatch table\n" ); goto badex; } dolseek( pNKEYTAB ); if ( read( comfd, &myNKEYTAB, 2 ) != 2 ) { printf( "read myNKEYTAB fails\n" ); goto badex; } if ( ( pMyKeytab = (KEYTAB *)malloc( sizeof(KEYTAB) * myNKEYTAB )) == NULL ) { printf( "failed: pMyKeytab = malloc( %d * %d )\n", sizeof( KEYTAB ), myNKEYTAB ); goto badex; } dolseek( pkeytab ); if ( read( comfd, pMyKeytab, sizeof(KEYTAB) * myNKEYTAB ) != ( sizeof(KEYTAB) * myNKEYTAB )) { printf( " failed: read builtin dispatch table\n" ); goto badex; } verify(); readmap(); dolseek( povertab ); if ( write( comfd, pMyOvertab, sizeof(OVERTAB) * myNOVERTAB ) != ( sizeof(OVERTAB) * myNOVERTAB )) { printf( "failed: write overlay dispatch table\n" ); goto badex; } dolseek( pkeytab ); if ( write( comfd, pMyKeytab, sizeof(KEYTAB) * myNKEYTAB ) != ( sizeof(KEYTAB) * myNKEYTAB )) { printf( " failed: write builtin dispatch table\n" ); goto badex; } close( comfd ); exit ( 0 ); } dolseek( x ) { lspos = x - 0x100; if ( lseek( comfd, lspos, 0 ) < 0L ) { printf( "lseek failure %x\n", x ); exit ( 5 ); } } char * hexd = "0123456789ABCDEF"; cvout( ip ) int * ip; { int ii, jj; *ip = 0; for ( ii = 0; ii < 4; ++ii ) { *ip <<= 4; for ( jj = 0; jj < 16; ++jj ) { if ( symbuf[ii] == hexd[jj] ) { *ip += jj ; break; } } } ++gotname; } verify() { /* verify keytab. */ int bix, ktx; for ( bix = 0; bix < 3; ++bix ) { for ( ktx = 0; ktx < myNKEYTAB; ++ktx ) { if ( pMyKeytab[ktx].k_fp == bi[bix].biffunc ) goto foundit; } printf( "No match for UECS number %d\n", bi[bix].biUECS ); printf( "UECS Name: %s\n", bi[bix].biUECSname ); printf( "Function Name: %s\n", bi[bix].bifname ); printf( "Core Address: %x\n", pMyKeytab[ktx].k_fp ); printf( "Address From %s: %x\n", symname, bi[bix].biffunc ); exit ( 1 ); foundit: continue; } printf( "Version Information Verified\n" ); } struct { int UECS; int key; } x; int mapdone; readmap() { int x_entries; mapdone = x_entries = 0; while ( read( maptfd, &x, 4 ) == 4 ) { if ( x.UECS == 0x1a1a ) break; ++x_entries; if ( x.UECS == 999 ) delkey(); else stashkey(); } printf( "Read %d Mapping Entries\n", x_entries ); printf( "Succeeded in Mapping %d of them\n", mapdone ); printf( "\nShall we update the .COM file? " ); x_entries = getchar(); if ( x_entries != 'y' && x_entries != 'Y' ) { printf( "\nSo long, then!\n" ); exit ( 0 ); } } stashkey() { int bix, ktx; for ( bix = 0; bi[bix].biUECS != -1; ++bix ) { if ( x.UECS != bi[bix].biUECS ) continue; for ( ktx = 0; ktx < myNKEYTAB; ++ktx ) { if ( pMyKeytab[ktx].k_code != -1 ) continue; pMyKeytab[ktx].k_code = x.key; pMyKeytab[ktx].k_fp = bi[bix].biffunc; ++mapdone; return; } printf( "Built-in table full, cannot map %s\n", bi[bix].biUECSname ); return; } for ( bix = 0; ovly[bix].ovUECS != -1; ++bix ) { if ( x.UECS != ovly[bix].ovUECS ) continue; for ( ktx = 0; ktx < myNOVERTAB; ++ktx ) { if ( pMyOvertab[ktx].k_code != -1 ) continue; pMyOvertab[ktx].k_code = x.key; pMyOvertab[ktx].ovcode = ovly[bix].xovnum; pMyOvertab[ktx].ovparm = ovly[bix].xovparm; ++mapdone; return; } printf( "Overlay table full, cannot map %s\n", ovly[bix].ovUECSname ); return; } printf( "UECS function number %d is unknown to me.\n", x.UECS ); } delkey() { int bix, ktx; for ( bix = 0; bi[bix].biUECS != -1; ++bix ) { for ( ktx = 0; ktx < myNKEYTAB; ++ktx ) { if ( pMyKeytab[ktx].k_code != x.key ) continue; pMyKeytab[ktx].k_code = -1; ++mapdone; return; } } for ( bix = 0; ovly[bix].ovUECS != -1; ++bix ) { for ( ktx = 0; ktx < myNOVERTAB; ++ktx ) { if ( pMyOvertab[ktx].k_code != x.key ) continue; pMyOvertab[ktx].k_code = -1; ++mapdone; return; } } printf( "Key %04x was not mapped!\n", x.key ); } czii -z4000 meconfig.c as meconfig.asm era meconfig.asm ln meconfig.o c:malloc.o c:sbrk.o c:callcpm.o c:z80libc.lib meconfig # EMACS_MODES: tabstop=8 lnumb=0 lnowid=20 # EC edit command DC display control SC session control # UI extended user interface SI system interface CI command input # EE electric edit MAC macro PAD scratchpad # MODE changeable modes INFO read-only modes Block block 11 CI-Abort-Cancel 34 CI-Keyboard-Macro-Begin 35 CI-Keyboard-Macro-End 36 CI-Keyboard-Macro-Execute 58 DC-Discard-Other-Window 59 DC-Enlarge-Window 63 DC-Reposit-Top 64 DC-Scroll-Down 67 DC-Scroll-Up 72 DC-Shrink-Window 73 DC-Split-Window 79 EC-Arrow-Down 80 EC-Arrow-Left 81 EC-Arrow-Right 82 EC-Arrow-Up 91 EC-Back-Search-Simple 93 EC-CR-With-Indent 95 EC-Capitalize-Region 96 EC-Capitalize-Word 98 EC-Deblank 103 EC-Exchange-Local-Mark 106 EC-Execute-File 107 EC-Exit 111 EC-Find-File 129 EC-Forward-Search-Simple 142 EC-Goto-Beginning-Of-Line 144 EC-Goto-End-of-Line 145 EC-Goto-First-Buffer-Line 150 EC-Goto-Last-Buffer-Line 161 EC-Goto-Next-Page 166 EC-Goto-Next-Window 180 EC-Goto-Previous-Page 186 EC-Goto-Previous-Window 192 EC-GrabFrom-Stack 204 EC-Kill-Lines-Count 208 EC-Kill-Region 209 EC-Kill-to-EOL-emacs 211 EC-Kill-Char-Back 212 EC-Kill-Char-Forw 213 EC-Kill-Word-Back 214 EC-Kill-Word-Forw 219 EC-Lower-Case-Region 220 EC-Lower-Case-Word 221 EC-Match-Fence 224 EC-Open-Lines 229 EC-PickUp-Region 235 EC-Quote-One 236 EC-Read-File 238 EC-Redraw 240 EC-Rename-Buffer 244 EC-Save-File 245 EC-Self-Insert 255 EC-Set-Local-Mark 258 EC-Set-Word-Mode 263 EC-TAB 265 EC-Transpose-Chars 268 EC-Unset-Word-Mode 276 EC-Upper-Case-Region 277 EC-Upper-Case-Word 282 EC-Word-Back 283 EC-Word-Forw 286 EC-Write-File 487 SC-Discard-Buffer 494 SC-SwitchTo-Buffer 495 SC-SwitchTo-Next-Sequential-Buffer 528 UI-Buffer-Selection-Menu 543 UI-Give-Statistics 999 Undefined-Function ;czii o:fgets.c ;as o:fgets.asm ;era o:fgets.asm ;czii o:open.c ;as o:open.asm ;era o:open.asm ;czii o:fopen.c ;as o:fopen.asm ;era o:fopen.asm ;czii o:putc.c ;as o:putc.asm ;era o:putc.asm ;czii o:getbuff.c ;as o:getbuff.asm ;era o:getbuff.asm ;czii o:read.c ;as o:read.asm ;era o:read.asm ;czii o:getc.c ;as o:getc.asm ;era o:getc.asm ;czii o:write.c ;as o:write.asm ;era o:write.asm ;czii o:lseek.c ;as o:lseek.asm ;era o:lseek.asm ;czii o:fputs.c ;as o:fputs.asm ;era o:fputs.asm ;czii o:fwrite.c ;as o:fwrite.asm ;era o:fwrite.asm ERA C:MYLIB.LIB XSUB LIBUTIL -O C:MYLIB.LIB . O:FOPEN.O O:OPEN.O O:FGETS.O O:FPUTS.O O:FWRITE.O O:GETC.O O:PUTC.O O:GETBUFF.O O:READ.O O:WRITE.O O:LSEEK.O . ; formerly main.c: czii c:memain.c as c:memain.asm era c:memain.asm czii c:metab.c as c:metab.asm era c:metab.asm czii c:memisc.c as c:memisc.asm era c:memisc.asm czii c:mexeq.c as c:mexeq.asm era c:mexeq.asm czii c:meinit.c as c:meinit.asm era c:meinit.asm czii c:ovkbdm29.c as c:ovkbdm29.asm era c:ovkbdm29.asm ; formerly window.c: czii c:window.c as c:window.asm era c:window.asm czii c:mvupwin.c as c:mvupwin.asm era c:mvupwin.asm czii c:splitwin.c as c:splitwin.asm era c:splitwin.asm czii c:onlywin.c as c:onlywin.asm era c:onlywin.asm czii c:growwin.c as c:growwin.asm era c:growwin.asm czii c:shrnkwin.c as c:shrnkwin.asm era c:shrnkwin.asm ; formerly line.c: czii c:line.c as c:line.asm era c:line.asm czii c:lfree.c as c:lfree.asm era c:lfree.asm czii c:linsert.c as c:linsert.asm era c:linsert.asm czii c:kbuf.c as c:kbuf.asm era c:kbuf.asm czii c:ldelete.c as c:ldelete.asm era c:ldelete.asm czii c:ldelnewl.c as c:ldelnewl.asm era c:ldelnewl.asm czii c:lnewline.c as c:lnewline.asm era c:lnewline.asm ; formerly basic.c: czii c:basic.c as c:basic.asm era c:basic.asm czii c:updown.c as c:updown.asm era c:updown.asm czii c:paginate.c as c:paginate.asm era c:paginate.asm czii c:mark.c as c:mark.asm era c:mark.asm ; random.c: czii c:random.c as c:random.asm era c:random.asm czii c:ovmisc1.c as c:ovmisc1.asm era c:ovmisc1.asm czii c:indent.c as c:indent.asm era c:indent.asm ; formerly region.c: czii c:killreg.c as c:killreg.asm era c:killreg.asm czii c:copyreg.c as c:copyreg.asm era c:copyreg.asm czii c:lowreg.c as c:lowreg.asm era c:lowreg.asm czii c:upreg.c as c:upreg.asm era c:upreg.asm ; word.c: czii c:word.c as c:word.asm era c:word.asm czii c:ovword1.c as c:ovword1.asm era c:ovword1.asm ; formerly search.c: czii c:fsearch.c as c:fsearch.asm era c:fsearch.asm czii c:bsearch.c as c:bsearch.asm era c:bsearch.asm submit all2 ; formerly display.c: czii c:medisp.c as c:medisp.asm era c:medisp.asm czii c:ovmdln28.c as c:ovmdln28.asm era c:ovmdln28.asm czii c:meml.c as c:meml.asm era c:meml.asm czii c:meupdate.c as c:meupdate.asm era c:meupdate.asm czii c:mevt.c as c:mevt.asm era c:mevt.asm ; buffer.c: czii c:buffer.c as c:buffer.asm era c:buffer.asm czii c:usebuf.c as c:usebuf.asm era c:usebuf.asm czii c:killbuf.c as c:killbuf.asm era c:killbuf.asm czii c:listbuf.c as c:listbuf.asm era c:listbuf.asm ; file.c: (file.c is GONE) czii c:filevisi.c as c:filevisi.asm era c:filevisi.asm czii c:filesave.c as c:filesave.asm era c:filesave.asm czii c:filerite.c as c:filerite.asm era c:filerite.asm czii c:filename.c as c:filename.asm era c:filename.asm czii c:fileread.c as c:fileread.asm era c:fileread.asm czii c:ovread27.c as c:ovread27.asm era c:ovread27.asm ; fileio.c: permanently gone. ; termio.c: permanently gone. czii c:telansi.c as c:telansi.asm era c:telansi.asm ; czii c:abort.c ; as c:abort.asm ; era c:abort.asm ; as c:callcpm.ual ; as c:sbrk.ual ; czii c:malloc.c ; as c:malloc.asm ; era c:malloc.asm czii c:abort.c as c:abort.asm era c:abort.asm ;czii c:myovload.c ;as c:myovload.asm ;era c:myovload.asm ;pip c:ovloader.o=c:myovload.o ; as c:ovbgn.asm czii c:killyank.c as c:killyank.asm era c:killyank.asm czii c:cclass.c as c:cclass.asm era c:cclass.asm submit linkall ln -o c:me.com -t -r c:memain.o -f root.dat c:ovloader.o o:croot.o o:getbuff.o o:open.o c:cclass.o c:memisc.o c:metab.o c:mexeq.o c:line.o c:linsert.o c:lfree.o c:kbuf.o c:lnewline.o c:ldelete.o c:ldelnewl.o c:basic.o c:meml.o c:mevt.o c:medisp.o c:meupdate.o c:buffer.o c:telansi.o c:malloc.o c:sbrk.o c:callcpm.o c:mylib.lib c:mylib.lib c:z80libc.lib c:z80libc.lib ; czii c:.c ; as c:.asm ; era c:.asm era c:*.rsm era c:*.ovr era c:me.com ln -o c:me.com -r c:memain.o -f root.dat ln -o c:meov000.ovr c:meinit.o -f subs.dat ln -o c:meov001.ovr c:bsearch.o -f subs.dat ln -o c:meov002.ovr c:fsearch.o -f subs.dat ln -o c:meov003.ovr c:killreg.o -f subs.dat ln -o c:meov004.ovr c:listbuf.o c:window.o -f subs.dat ln -o c:meov005.ovr c:filename.o -f subs.dat ln -o c:meov006.ovr c:lowreg.o -f subs.dat ln -o c:meov007.ovr c:ovmisc1.o -f subs.dat ln -o c:meov008.ovr c:mvupwin.o -f subs.dat ln -o c:meov009.ovr c:filesave.o -f subs.dat ln -o c:meov010.ovr c:upreg.o -f subs.dat ln -o c:meov011.ovr c:filevisi.o -f subs.dat ln -o c:meov012.ovr c:filerite.o -f subs.dat ln -o c:meov013.ovr c:shrnkwin.o -f subs.dat ln -o c:meov014.ovr c:onlywin.o -f subs.dat ln -o c:meov015.ovr c:splitwin.o -f subs.dat ln -o c:meov016.ovr c:usebuf.o -f subs.dat ln -o c:meov017.ovr c:killbuf.o -f subs.dat ln -o c:meov018.ovr c:growwin.o -f subs.dat ln -o c:meov019.ovr c:copyreg.o -f subs.dat ln -o c:meov020.ovr c:fileread.o -f subs.dat ln -o c:meov021.ovr c:ovword1.o -f subs.dat ;ln -o c:meov022.ovr c:updown.o -f subs.dat ;ln -o c:meov023.ovr c:paginate.o -f subs.dat ;ln -o c:meov024.ovr c:mark.o -f subs.dat ;ln -o c:meov025.ovr c:killyank.o -f subs.dat ;ln -o c:meov026.ovr c:indent.o -f subs.dat ln -o c:meov027.ovr c:ovread27.o -f subs.dat ln -o c:meov028.ovr c:ovmdln28.o -f subs.dat ln -o c:meov029.ovr c:ovkbdm29.o -f subs.dat ln -o c:meov030.ovr c:ovexit30.o -f subs.dat ln -o c:meov031.ovr c:ovudfb31.o -f subs.dat ln -o c:meov032.ovr c:ovopen32.o -f subs.dat ln -o c:meov033.ovr c:ovopwr33.o -f subs.dat ln -o c:meov034.ovr c:ovwrit34.o -f subs.dat ;ln -o c:meov0.ovr c:%.o -f subs.dat c:me.rsm c:ovbgn.o c:mylib.lib c:mylib.lib c:z80libc.lib c:z80libc.lib