|
|
1.1 root 1:
2: Elvis 1.4 INTERNAL Page 8-1
3:
4:
5: E8. INTERNALF
6:
7: You don't need to know the material in this section to use
8: elvis. You only need it if you intend to modify elvis.
9:
10:
11: E8.1 The temporary fileF
12:
13: The temporary file is divided into blocks of 1024 bytes each.
14:
15: When elvis starts up, the file is copied into the temporary
16: file. Small amounts of extra space are inserted into the temporary
17: file to insure that no text lines cross block boundaries; this
18: speeds up processing and simplifies storage management. The "extra
19: space" is filled with NUL characters; the input file must not
20: contain any NULs, to avoid confusion.
21:
22: The first block of the temporary file is an array of shorts
23: which describe the order of the blocks; i.e. header[1] is the
24: block number of the first block, and so on. This limits the
25: temporary file to 512 active blocks, so the largest file you can
26: edit is about 400K bytes long. I hope that's enough!
27:
28: When blocks are altered, they are rewritten to a -1different-0 block
29: in the file, and the in-core version of the header block is updated
30: accordingly. The in-core header block will be copied to the temp
31: file immediately before the next change... or, to undo this
32: change, swap the old header (from the temp file) with the new
33: (in-core) header.
34:
35: Elvis maintains another in-core array which contains the
36: line-number of the last line in every block. This allows you to go
37: directly to a line, given its line number.
38:
39:
40: E8.2 Implementation of EditingF
41:
42: There are three basic operations which affect text:
43:
44: * delete text - delete(from, to)
45: * add text - add(at, text)
46: * yank text - cut(from, to)
47:
48: To yank text, all text between two text positions is copied into
49: a cut buffer. The original text is not changed. To copy the text
50: into a cut buffer, you need only remember which physical blocks
51: that contain the cut text, the offset into the first block of the
52: start of the cut, the offset into the last block of the end of the
53: cut, and what kind of cut it was. (Cuts may be either character
54: cuts or line cuts; the kind of a cut affects the way it is later
55: "put".) This is implemented in the function cut().
56:
57: To delete text, you must modify the first and last blocks, and
58: remove any reference to the intervening blocks in the header's
59: list. The text to be deleted is specified by two marks. This is
60: implemented in the function delete().
61:
62:
63:
64:
65:
66:
67:
68: Elvis 1.4 INTERNAL Page 8-2
69:
70:
71: To add text, you must specify the text to insert (as a
72: NUL-terminated string) and the place to insert it (as a mark). The
73: block into which the text is to be inserted may need to be split
74: into as many as four blocks, with new intervening blocks needed as
75: well... or it could be as simple as modifying a single block.
76: This is implemented in the function add().
77:
78: Other interesting functions are paste() (to copy text from a cut
79: buffer into the file), modify() (for an efficient way to implement
80: a combined delete/add sequence), and input() (to get text from the
81: user & insert it into the file).
82:
83: When text is modified, an internal file-revision counter, called
84: "changes", is incremented. This counter is used to detect when
85: certain caches are out of date. (The "changes" counter is also
86: incremented when we switch to a different file, and also in one or
87: two similar situations -- all related to invalidating caches.)
88:
89:
90: E8.3 Marks and the CursorF
91:
92: Marks are places within the text. They are represented
93: internally as a long variable which is split into two bitfields: a
94: line number and a character index. Line numbers start with 1, and
95: character indexes start with 0.
96:
97: Since line numbers start with 1, it is impossible for a set mark
98: to have a value of 0L. 0L is therefore used to represent unset
99: marks.
100:
101: When you do the "delete text" change, any marks that were part
102: of the deleted text are unset, and any marks that were set to
103: points after it are adjusted. Similarly, marks are adjusted after
104: new text is inserted.
105:
106: The cursor is represented as a mark.
107:
108:
109: E8.4 Colon Command InterpretationF
110:
111: Colon commands are parsed, and the command name is looked up in
112: an array of structures which also contain a pointer to the function
113: that implements the command, and a description of the arguments
114: that the command can take. If the command is recognized and its
115: arguments are legal, then the function is called.
116:
117: Each function performs its task; this may cause the cursor to be
118: moved to a different line, or whatever.
119:
120:
121: E8.5 Screen ControlF
122:
123: The screen is updated via a package which looks like the
124: "curses" library, but isn't. It is actually much simpler. Most
125: curses operations are implemented as macros which copy characters
126: into a large I/O buffer, which is then written with a single large
127: write() call as part of the refresh() operation.
128:
129:
130:
131:
132:
133:
134: Elvis 1.4 INTERNAL Page 8-3
135:
136:
137: The functions which modify text (namely add() and delete())
138: remember where text has been modified. They do this by calling the
139: function redrawrange(). The screen redrawing function, redraw(),
140: uses these clues to help it reduce the amount of text that is
141: redrawn each time.
142:
143:
144: E8.6 PortabilityF
145:
146: To improve portability, Elvis collects as much of the
147: system-dependent definitions as possible into the config.h file.
148: This file begins with some preprocessor instructions which attempt
149: to determine which compiler and operating system you have. After
150: that, it conditionally defines some macros and constants for your
151: system.
152:
153: One of the more significant macros is ttyread(buf,n). This
154: macro is used to read raw characters from the keyboard. An attempt
155: to read may be cut short by a SIGALRM signal. For UNIX systems,
156: this simply reads bytes from stdin. For MSDOS, TOS, and OS9,
157: ttyread() is a function defined in curses.c. There is also a
158: ttywrite() macro.
159:
160: The tread() and twrite() macros are versions of read() and
161: write() that are used for text files. On UNIX systems, these are
162: equivelent to read() and write(). On MS-DOS, these are also
163: equivelent to read() and write(), since DOS libraries are generally
164: clever enough to convert newline characters automatically. For
165: Atari TOS, though, the MWC library is too stupid to do this, so we
166: had to do the conversion explicitly.
167:
168: Other macros may substitute index() for strchr(), or bcopy() for
169: memcpy(), or map the "void" data type to "int", or whatever.
170:
171: The file "tinytcap.c" contains a set of functions that emulate
172: the termcap library for a small set of terminal types. The
173: terminal-specific info is hard-coded into this file. It is only
174: used for systems that don't support real termcap. Another
175: alternative for screen control can be seen in the "curses.h" and
176: "pc.c" files. Here, macros named VOIDBIOS and CHECKBIOS are used
177: to indirectly call functions which perform low-level screen
178: manipulation via BIOS calls.
179:
180: The stat() function must be able to come up with UNIX-style
181: major/minor/inode numbers that uniquely identify a file or
182: directory.
183:
184: Please try to keep you changes localized, and wrap them in
185: #if/#endif pairs, so that elvis can still be compiled on other
186: systems. And PLEASE let me know about it, so I can incorporate
187: your changes into my latest-and-greatest version of elvis.
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.