1 | /* SB - Copyright 1982 by Ken Harrenstien, SRI International
|
---|
2 | * This software is quasi-public; it may be used freely with
|
---|
3 | * like software, but may NOT be sold or made part of licensed
|
---|
4 | * products without permission of the author. In all cases
|
---|
5 | * the source code and any modifications thereto must remain
|
---|
6 | * available to any user.
|
---|
7 | *
|
---|
8 | * This is part of the SB library package.
|
---|
9 | * Any software using the SB library must likewise be made
|
---|
10 | * quasi-public, with freely available sources.
|
---|
11 | */
|
---|
12 |
|
---|
13 | #if 0
|
---|
14 | Todo stuff:
|
---|
15 | New definitions:
|
---|
16 | sbbuffer - old sbstr. Abbrev & struct "sbbuff". Macro SBBUFF
|
---|
17 | (or SBBUF?)
|
---|
18 | sbstring - list of sds. Abbrev sbstr. Macro SBSTR.
|
---|
19 | Should *sbstr == *sdblk? Yeah.
|
---|
20 | sbfile - as before. Macro SBFILE. (or SBFIL?)
|
---|
21 |
|
---|
22 | Try to get zero-length sdblks flushed on the fly,
|
---|
23 | rather than waiting for moby GC. Also, need to set
|
---|
24 | up compaction of SD freelist, as well as SM freelist.
|
---|
25 | Make SM freelist compact self-invoked by SBM_MGET?
|
---|
26 | Any need for phys disk ptrs other than for tempfile?
|
---|
27 | Can do sbm_forn through SDblks to find active sdfiles
|
---|
28 | so list isn''t needed for that.
|
---|
29 | Can sdback be flushed? (not needed for keeping list sorted,
|
---|
30 | or for searching it -- only used when linking
|
---|
31 | blocks in or out of list.) Perhaps use circular list?
|
---|
32 | If list only used for tmpfile, then to link in/out could
|
---|
33 | always start from sfptr1 of tmpfile? Sure, but slow?
|
---|
34 | Last SD on phys list could belong to no logical list,
|
---|
35 | and denote free space on tmpfile?
|
---|
36 |
|
---|
37 | --------------------------
|
---|
38 |
|
---|
39 | An "open" SBBUFFER will allow one to read, write, insert into,
|
---|
40 | and delete from a sbstring (a logical character string). "Dot" refers
|
---|
41 | to the current logical character position, which is where all
|
---|
42 | operations must happen; sb_fseek must be used to change this location.
|
---|
43 | There are several states that the I/O can be in:
|
---|
44 | !SBCUR ----CLOSED----
|
---|
45 | All other elements, including SBIOP, should also be 0.
|
---|
46 | Dot is 0.
|
---|
47 | SBCUR && !SBIOP ----OPEN/IDLE----
|
---|
48 | SBCUR points to a SD block (its SDMEM may or may not exist)
|
---|
49 | SBIOP==0 (otherwise it would be open/ready)
|
---|
50 | Dot is SBDOT + SBOFF.
|
---|
51 | R/Wleft must be 0.
|
---|
52 | SBCUR && SBIOP ----OPEN/READY----
|
---|
53 | SBCUR points to a SDBLK (SDMEM must exist!)
|
---|
54 | SBIOP exists.
|
---|
55 | Dot is SBDOT + offset into SMBLK. SBOFF is ignored!
|
---|
56 | SB_WRIT flag is set if "smuse" must be updated.
|
---|
57 | The R/Wleft counts are set up:
|
---|
58 | 1. Rleft 0, Wleft 0 -- Since SBIOP is set, must assume
|
---|
59 | counts are too.
|
---|
60 | So this means at end of text, no room left.
|
---|
61 | Otherwise would imply that setup needs doing.
|
---|
62 | 2. Rleft N, Wleft 0 -- At beg or middle of text
|
---|
63 | 3. Rleft 0, Wleft N -- At end of text
|
---|
64 | 4. Rleft N, Wleft N -- Shouldn''t ever happen
|
---|
65 |
|
---|
66 | Note that Rleft is always correct. Wleft is sometimes
|
---|
67 | set 0 in order to force a call to determine real state.
|
---|
68 |
|
---|
69 | Note that SBIOP alone is a sufficient test for being OPEN/READY.
|
---|
70 |
|
---|
71 | The important thing about updating the smblk is to ensure that the "smuse"
|
---|
72 | field is correct. This can only be changed by writing or deleting. We assume
|
---|
73 | that deletions always update immediately, thus to determine if an update
|
---|
74 | is necessary, see if SB_WRIT is set. If so, update smuse before doing
|
---|
75 | anything but more writing!!!!
|
---|
76 |
|
---|
77 | The SDBLK must be marked "modified" whenever a write operation is
|
---|
78 | done. We try to do this only the first time, by keeping Wleft zero
|
---|
79 | until after the first write. This is also when SB_WRIT gets set.
|
---|
80 | However, if in overwrite mode, Wleft must be kept zero in order to
|
---|
81 | force the proper actions; SB_WRIT is also not turned on since smuse
|
---|
82 | will not change. Note that at EOF, overwrite becomes the same thing
|
---|
83 | as insert and is treated identically...
|
---|
84 |
|
---|
85 | If a SBLK has an in-core copy but no disk copy, it can be
|
---|
86 | freely modified. Otherwise, modifications should preferably split
|
---|
87 | the block so as to retain "pure" blocks as long as possible. "Pure" blocks
|
---|
88 | can always have their in-core versions flushed immediately (unless for
|
---|
89 | compaction purposes they''ll need to be written out in the same GC pass).
|
---|
90 | Alternatively, mods can simply mark the disk copy "free" and go
|
---|
91 | ahead as if no such copy existed.
|
---|
92 | No additions or changes to a pure block are allowed, but
|
---|
93 | deletions from the end or beginning are always allowed. All other
|
---|
94 | changes must split or insert new blocks to accomplish the changes.
|
---|
95 |
|
---|
96 | Locking:
|
---|
97 | SDBLKs are subject to unpredictable relocation, compaction,
|
---|
98 | and garbage collecting. There are three ways in which a SDBLK can
|
---|
99 | remain fixed:
|
---|
100 |
|
---|
101 | 1. The SDBLK has the SD_LOCK flag set. This flag is used whenever
|
---|
102 | a SBBUF''s SBCUR is pointing to this SDBLK.
|
---|
103 | 2. The SDBLK has the SD_LCK2 flag set. This flag is used only
|
---|
104 | during execution of various internal routines and should
|
---|
105 | not be seen anywhere during execution of user code.
|
---|
106 | 3. The SDBLK has no back-pointer (is first block in a sbstring).
|
---|
107 | Such SDBLKs cannot be relocated (since it is not known
|
---|
108 | what may be pointing to them) but unlike the other 2 cases
|
---|
109 | they are still subject to compaction with succeeding SDBLKs.
|
---|
110 |
|
---|
111 | The SDBLK must be locked with SD_LOCK for as long as it is being
|
---|
112 | pointed to by SBCUR. The sole exception is when a SBBUF in the
|
---|
113 | OPEN/IDLE state is pointing to the first SDBLK of a sbstring; this
|
---|
114 | sdblk is guaranteed not to be moved, since sdblks without a
|
---|
115 | back-pointer are never moved. SD_LOCK is asserted as soon as the state
|
---|
116 | changes to OPEN/READY, of course. The internal routines take pains to
|
---|
117 | always move SD_LOCK as appropriate. Note that only one SD in a
|
---|
118 | sbstring can ever have SD_LOCK turned on. SD_LCK2 is an auxiliary flag
|
---|
119 | which may appear in more than one SDBLK, for use by low-level routines
|
---|
120 | for various temporary reasons; either will prevent the SDBLK from being
|
---|
121 | modified in any way by the storage compactor.
|
---|
122 |
|
---|
123 | SEEKs are a problem because it''s unclear at seek time what will happen
|
---|
124 | next, so the excision of the smblk can''t be optimized. If the seek
|
---|
125 | happens to land in a sdblk with an existing smblk, there''s no problem;
|
---|
126 | but if it''s a sdblk alone, how to decide which part of it to read in???
|
---|
127 | If next action is:
|
---|
128 | write - split up sdblk and create new one. Read nothing in.
|
---|
129 | read - read in 512 bytes starting at disk blk boundary if possible
|
---|
130 | else read in 128 bytes starting with selected char
|
---|
131 | (include beg of sdblk if less than 64 chars away)
|
---|
132 | overwrite - as for read.
|
---|
133 | backread - like read but position at end of sdblk.
|
---|
134 | delete - split up sdblk, read nothing in.
|
---|
135 |
|
---|
136 | We solve this through the OPEN/IDLE state, where SBIOP == 0 means SBOFF
|
---|
137 | points to logical offset from start of current sdblk, so that the seek
|
---|
138 | need not take any action. Only when a specific operation is requested
|
---|
139 | will the transition to OPEN/READY take place, at which time we''ll know
|
---|
140 | what the optimal excision strategy is. The routine SBX_READY performs
|
---|
141 | this function.
|
---|
142 |
|
---|
143 | The physical links (SDFORW and SDBACK) are only valid when SDFILE is
|
---|
144 | set (likewise for SDLEN and SDADDR). In other words, mungs to a sdblk
|
---|
145 | must check SDFILE to see whether or not the phys links should be
|
---|
146 | altered. Normally they aren''t except during sdblk creation, deletion,
|
---|
147 | or swapout, no matter how much the sdblk gets shuffled around
|
---|
148 | logically. The disk physical list is kept sorted in order of starting
|
---|
149 | addresses. The text blocks indicated can overlap. When a GC is
|
---|
150 | necessary, the code must figure out how much space is actually free.
|
---|
151 |
|
---|
152 | -------------- Old woolgathering, ignore rest of this page ---------------
|
---|
153 |
|
---|
154 | Question: should 512-byte buffers be maintained, one for each SBFILE?
|
---|
155 | Or should the in-core text be hacked up to serve for buffering?
|
---|
156 | Question is where to point the READ/WRITE system calls. Currently,
|
---|
157 | they are pointed directly at the in-core text, and there are no
|
---|
158 | auxiliary buffers.
|
---|
159 |
|
---|
160 | If use auxiliary buffers:
|
---|
161 | How to handle flushing, when changing location etc?
|
---|
162 | Could be clever about reading from large disk block, only
|
---|
163 | get part of it into buffer instead of splitting up in order to
|
---|
164 | read a "whole" block.
|
---|
165 | Problem: sbstrings can include pieces of several different files.
|
---|
166 | Hard to maintain just one buffer per FD without hacking
|
---|
167 | done on one sbstring screwing that on another.
|
---|
168 | If don''t use buffers:
|
---|
169 | Need to have a "chars-left" field in mem blocks, so know how
|
---|
170 | much more can be added. Will need heuristics for how much
|
---|
171 | extra space to allocate.
|
---|
172 | #endif /*COMMENT*/
|
---|
173 | |
---|
174 |
|
---|
175 | /* Includes, initial definitions */
|
---|
176 |
|
---|
177 | #include <stdio.h>
|
---|
178 | #include "sb.h"
|
---|
179 |
|
---|
180 | #ifndef V6
|
---|
181 | #define V6 0
|
---|
182 | #endif
|
---|
183 |
|
---|
184 | #if V6
|
---|
185 | #include <stat.h>
|
---|
186 | #else
|
---|
187 | #include <sys/types.h>
|
---|
188 | #include <sys/stat.h>
|
---|
189 | #if MINIX
|
---|
190 | #include <fcntl.h> /* For open() flags */
|
---|
191 | #else
|
---|
192 | #include <sys/file.h> /* For open() flags */
|
---|
193 | #endif /* MINIX */
|
---|
194 | #endif /*-V6*/
|
---|
195 |
|
---|
196 | extern int errno;
|
---|
197 | extern char *strerror(); /* From ANSI <string.h> */
|
---|
198 |
|
---|
199 | /* Allocation decls */
|
---|
200 | SBFILE sbv_tf; /* SBFILE for temp swapout file */
|
---|
201 | int (*sbv_debug)(); /* Error handler address */
|
---|
202 |
|
---|
203 |
|
---|
204 | /* SBX_READY argument flags (internal to SBSTR routines only)
|
---|
205 | * The following values should all be unique; the exact value
|
---|
206 | * doesn't matter as long as the right SKM flags are given.
|
---|
207 | */
|
---|
208 | #define SK_READF 0 /* 0-skip fwd, align BOB */
|
---|
209 | #define SK_READB (0|SKM_0BACK|SKM_EOB) /* 0-skip bkwd, align EOB */
|
---|
210 | #define SK_WRITEF (0|SKM_EOB) /* 0-skip fwd, align EOB */
|
---|
211 | #define SK_DELF (4|SKM_0BACK) /* 0-skip bkwd, align BOB */
|
---|
212 | #define SK_DELB (4|SKM_EOB) /* 0-skip fwd, align EOB */
|
---|
213 | #define SKM_0BACK 01 /* Zero-skip direction: 0 = fwd, set = backwd
|
---|
214 | * Don't ever change this value! See SBX_NORM. */
|
---|
215 | #define SKM_EOB 02 /* Alignment: 0 = Beg-Of-Buf, set = End-Of-Buf */
|
---|
216 |
|
---|
217 | /* Note on routine names:
|
---|
218 | * "SB_" User callable, deals with sbbufs (usually).
|
---|
219 | * "SBS_" User callable, deals with sbstrings only.
|
---|
220 | * "SBX_" Internal routine, not meant for external use.
|
---|
221 | * "SBM_" Routine handling mem alloc, usually user callable.
|
---|
222 | */
|
---|
223 | |
---|
224 |
|
---|
225 | /* SBBUF Opening, Closing, Mode setting */
|
---|
226 |
|
---|
227 | /* SB_OPEN(sb,sd) - Sets up SBBUF given pointer to first SD of a sbstring.
|
---|
228 | * If SD == 0 then creates null sbstring.
|
---|
229 | * Any previous contents of SBBUF are totally ignored!!! If you
|
---|
230 | * want to save the stuff, use SB_UNSET.
|
---|
231 | * Sets I/O ptr to start of sbstring.
|
---|
232 | * Returns 0 if error, else the given SB.
|
---|
233 | */
|
---|
234 | SBBUF *
|
---|
235 | sb_open(sbp,sdp)
|
---|
236 | SBBUF *sbp;
|
---|
237 | SBSTR *sdp;
|
---|
238 | { register struct sdblk *sd;
|
---|
239 | register int cnt;
|
---|
240 | register WORD *clrp;
|
---|
241 |
|
---|
242 | if(!sbp) return((SBBUF *)0);
|
---|
243 | if((sd = sdp) == 0)
|
---|
244 | { sd = sbx_ndget(); /* Get a fresh node */
|
---|
245 | clrp = (WORD *) sd; /* Clear it all */
|
---|
246 | cnt = rnddiv(sizeof(struct sdblk));
|
---|
247 | do { *clrp++ = 0; } while(--cnt);
|
---|
248 | sd->sdflags = SD_NID; /* Except flags of course */
|
---|
249 | }
|
---|
250 | else if(sd->slback) /* Must be first thing in sbstring */
|
---|
251 | return((SBBUF *)0); /* Perhaps could normalize tho */
|
---|
252 |
|
---|
253 | clrp = (WORD *) sbp; /* Clear sbbuffer stuff */
|
---|
254 | cnt = rnddiv(sizeof(SBBUF));
|
---|
255 | do { *clrp++ = 0; } while(--cnt);
|
---|
256 |
|
---|
257 | sbp->sbcur = sd;
|
---|
258 | /* Note that SD_LOCK need not be set, because first SDBLK has no
|
---|
259 | * backptr. This is desirable to allow storage compactor maximum
|
---|
260 | * freedom in merging sdblks.
|
---|
261 | */
|
---|
262 | /* sd->sdflags |= SD_LOCK; */ /* Lock this one */
|
---|
263 | return(sbp);
|
---|
264 | }
|
---|
265 |
|
---|
266 |
|
---|
267 | /* SB_CLOSE(sb) - Close a SBBUF.
|
---|
268 | * Returns pointer to start of sbstring (first SD).
|
---|
269 | * Returns 0 if error.
|
---|
270 | */
|
---|
271 | SBSTR *
|
---|
272 | sb_close(sbp)
|
---|
273 | SBBUF *sbp;
|
---|
274 | { register SBBUF *sb;
|
---|
275 | register struct sdblk *sd;
|
---|
276 |
|
---|
277 | if((sb = sbp) == 0) /* Verify pointer */
|
---|
278 | return((SBSTR *)0);
|
---|
279 | sb_rewind(sb); /* Do most of the work, including unlock */
|
---|
280 | sd = sb->sbcur; /* Save ptr to sbstring */
|
---|
281 | sb->sbcur = 0; /* Now reset the sbbuffer structure */
|
---|
282 | sb->sbflags = 0;
|
---|
283 | return(sd);
|
---|
284 | }
|
---|
285 |
|
---|
286 |
|
---|
287 | /* SB_SETOVW(sbp) - Set SBBUF Over-write mode for PUTC's.
|
---|
288 | * SB_CLROVW(sbp) - Clear ditto.
|
---|
289 | */
|
---|
290 | sb_setovw(sbp)
|
---|
291 | SBBUF *sbp;
|
---|
292 | { register SBBUF *sb;
|
---|
293 | if(sb=sbp)
|
---|
294 | { sb->sbflags |= SB_OVW;
|
---|
295 | sb->sbwleft = 0;
|
---|
296 | }
|
---|
297 | }
|
---|
298 |
|
---|
299 | sb_clrovw(sbp)
|
---|
300 | SBBUF *sbp;
|
---|
301 | { register SBBUF *sb;
|
---|
302 | if(sb=sbp) sb->sbflags &= ~SB_OVW;
|
---|
303 | }
|
---|
304 | |
---|
305 |
|
---|
306 | /* SBSTRING file system operations (see also sb_fsave) */
|
---|
307 |
|
---|
308 | /* SB_FDUSE(fd) - Make a sbstring for given file.
|
---|
309 | * FD is an open file descriptor.
|
---|
310 | * Returns pointer to a SBSTR containing the given file, or 0 if error.
|
---|
311 | * The FD must not be closed until a SB_FDCLS is done to
|
---|
312 | * purge memory of any blocks pointing at the file.
|
---|
313 | * ** Maybe allocate sbfile structs with sbx_ndget, i.e. overlay on
|
---|
314 | * ** top of sdblk node?? Wd this screw verify, GC, etc? Maybe not if
|
---|
315 | * ** SD_LCK2 set...
|
---|
316 | */
|
---|
317 |
|
---|
318 | struct sbfile *sbv_ftab[SB_NFILES];
|
---|
319 |
|
---|
320 | chroff
|
---|
321 | sbx_fdlen(fd)
|
---|
322 | int fd;
|
---|
323 | {
|
---|
324 | #if !V6
|
---|
325 | struct stat statb;
|
---|
326 | #else
|
---|
327 | struct statb statb;
|
---|
328 | chroff len;
|
---|
329 | struct {int hiwd ; int lowd;} foo;
|
---|
330 | #endif /*V6*/
|
---|
331 |
|
---|
332 | if(fstat(fd,&statb) < 0) return((chroff)-1);
|
---|
333 | #if V6
|
---|
334 | len = statb.i_size1;
|
---|
335 | len.hiwd = statb.i_size0 & 0377;
|
---|
336 | return(len);
|
---|
337 | #else
|
---|
338 | return((chroff)statb.st_size);
|
---|
339 | #endif /*-V6*/
|
---|
340 | }
|
---|
341 |
|
---|
342 | SBSTR *
|
---|
343 | sb_fduse(ifd)
|
---|
344 | int ifd;
|
---|
345 | { register struct sdblk *sd;
|
---|
346 | register struct sbfile *sf;
|
---|
347 | register int fd;
|
---|
348 | chroff len;
|
---|
349 |
|
---|
350 | if((fd = ifd) < 0 || SB_NFILES <= fd /* Check for absurd FD */
|
---|
351 | || sbv_ftab[fd]) /* and slot already in use */
|
---|
352 | return((SBSTR *)0);
|
---|
353 | if((len = sbx_fdlen(fd)) < 0) return((SBSTR *)0);
|
---|
354 | sbv_ftab[fd]= sf = (struct sbfile *)sbx_malloc(sizeof(struct sbfile));
|
---|
355 | sf->sffd = fd;
|
---|
356 | sf->sfptr1 = sd = sbx_ndget();
|
---|
357 | sf->sflen = len;
|
---|
358 | sd->slforw = 0;
|
---|
359 | sd->slback = 0;
|
---|
360 | sd->sdforw = 0;
|
---|
361 | sd->sdback = 0;
|
---|
362 | sd->sdmem = 0;
|
---|
363 | sd->sdfile = sf;
|
---|
364 | sd->sdlen = len;
|
---|
365 | sd->sdaddr = 0;
|
---|
366 | return(sd);
|
---|
367 | }
|
---|
368 |
|
---|
369 | /* SB_FDCLS(fd) - Close a file descriptor being used by sbstrings.
|
---|
370 | * If arg is -1, closes all FD's that are unused (a "sweep").
|
---|
371 | * For specific arg, returns 0 if couldn't close FD because still in use.
|
---|
372 | * Perhaps later version of routine could have option to copy
|
---|
373 | * still-used SD's to tempfile, and force the FD closed?
|
---|
374 | */
|
---|
375 | sb_fdcls(ifd)
|
---|
376 | int ifd;
|
---|
377 | { register int fd;
|
---|
378 |
|
---|
379 | if((fd = ifd) >= 0)
|
---|
380 | { if(fd >= SB_NFILES) return(0); /* Error of sorts */
|
---|
381 | return(sbx_fcls(sbv_ftab[fd]));
|
---|
382 | }
|
---|
383 | fd = SB_NFILES-1;
|
---|
384 | do {
|
---|
385 | sbx_fcls(sbv_ftab[fd]);
|
---|
386 | } while(--fd); /* Doesn't try FD 0 ! */
|
---|
387 | return(1);
|
---|
388 | }
|
---|
389 |
|
---|
390 | sbx_fcls(sfp)
|
---|
391 | struct sbfile *sfp;
|
---|
392 | { register struct sbfile *sf;
|
---|
393 | register int fd;
|
---|
394 |
|
---|
395 | if((sf = sfp)==0 /* Ignore null args */
|
---|
396 | || sf == &sbv_tf) /* and never close our tempfile! */
|
---|
397 | return(0);
|
---|
398 | fd = sf->sffd; /* Find sys file descriptor */
|
---|
399 | if(sbv_ftab[fd] != sf) /* Ensure consistency */
|
---|
400 | return(sbx_err(0,"SF table inconsistency"));
|
---|
401 | if(sf->sfptr1) /* Any phys list still exists? */
|
---|
402 | return(0); /* Yes, still in use, can't close */
|
---|
403 | close(fd); /* Maybe do this when list gone? */
|
---|
404 | sbv_ftab[fd] = 0; /* Remove from table */
|
---|
405 | free(sf); /* Remove sbfile struct from mem */
|
---|
406 | }
|
---|
407 |
|
---|
408 | /* SB_FDINP(sb,fd) - Returns TRUE if specified fd is still in use
|
---|
409 | * by specified sbbuffer.
|
---|
410 | */
|
---|
411 | sb_fdinp(sb, fd)
|
---|
412 | register SBBUF *sb;
|
---|
413 | int fd;
|
---|
414 | { register struct sdblk *sd;
|
---|
415 | register struct sbfile *sf;
|
---|
416 |
|
---|
417 | if((sf = sbv_ftab[fd]) == 0
|
---|
418 | || (sd = sb->sbcur) == 0)
|
---|
419 | return(0);
|
---|
420 | sd = sbx_beg(sd); /* Move to beginning of sbstring */
|
---|
421 | for(; sd; sd = sd->slforw) /* Scan thru all blocks in string */
|
---|
422 | if(sd->sdfile == sf) /* If any of them match, */
|
---|
423 | return(1); /* Return tally-ho */
|
---|
424 | return(0);
|
---|
425 | }
|
---|
426 |
|
---|
427 | /* SB_FSAVE(sb,fd) - Write entire SBBUF out to specified FD.
|
---|
428 | * Returns 0 if successful, else system call error number.
|
---|
429 | */
|
---|
430 | sb_fsave(sb,fd) /* Write all of given sbbuf to given fd */
|
---|
431 | register SBBUF *sb;
|
---|
432 | int fd;
|
---|
433 | {
|
---|
434 | sbx_smdisc(sb);
|
---|
435 | return(sbx_aout(sbx_beg(sb->sbcur), 2, fd));
|
---|
436 | }
|
---|
437 | |
---|
438 |
|
---|
439 | /* SBBUF Character Operations */
|
---|
440 |
|
---|
441 | /* SB_GETC(sb) - Get next char from sbstring.
|
---|
442 | * Returns char at current location and advances I/O ptr.
|
---|
443 | * Returns EOF on error or end-of-string.
|
---|
444 | */
|
---|
445 | int
|
---|
446 | sb_sgetc(sb)
|
---|
447 | register SBBUF *sb;
|
---|
448 | {
|
---|
449 | if(--(sb->sbrleft) >= 0)
|
---|
450 | return sb_uchartoint(*sb->sbiop++);
|
---|
451 |
|
---|
452 | /* Must do hard stuff -- check ptrs, get next blk */
|
---|
453 | sb->sbrleft = 0; /* Reset cnt to zero */
|
---|
454 | if(sb->sbcur == 0 /* Make sure sbbuffer there */
|
---|
455 | || (int)sbx_ready(sb,SK_READF,0,SB_BUFSIZ) <= 0) /* Normalize & gobble */
|
---|
456 | return(EOF);
|
---|
457 | return(sb_sgetc(sb)); /* Try again */
|
---|
458 | } /* Loop wd be faster, but PDL OV will catch infinite-loop bugs */
|
---|
459 |
|
---|
460 |
|
---|
461 | /* SB_PUTC(sb,ch) - Put char into sbstring.
|
---|
462 | * Inserts char at current location.
|
---|
463 | * Returns EOF on error, else the char value.
|
---|
464 | */
|
---|
465 | int
|
---|
466 | sb_sputc(sb,ch)
|
---|
467 | register SBBUF *sb;
|
---|
468 | int ch;
|
---|
469 | {
|
---|
470 | register struct sdblk *sd;
|
---|
471 |
|
---|
472 | if(--(sb->sbwleft) >= 0) return(*sb->sbiop++ = ch);
|
---|
473 |
|
---|
474 | sb->sbwleft = 0; /* Reset cnt to avoid overflow */
|
---|
475 | if((sd = sb->sbcur) == 0) /* Verify string is there */
|
---|
476 | return(EOF); /* Could perhaps create it?? */
|
---|
477 | if(sb->sbflags&SB_OVW) /* If overwriting, handle std case */
|
---|
478 | { if(sb->sbiop &&
|
---|
479 | --sb->sbrleft >= 0) /* Use this for real count */
|
---|
480 | { sd->sdflags |= SD_MOD; /* Win, munging... */
|
---|
481 | return(*sb->sbiop++ = ch);
|
---|
482 | }
|
---|
483 | /* Overwriting and hit end of this block. */
|
---|
484 | if((int)sbx_ready(sb,SK_READF,0,SB_BUFSIZ) > 0) /* Re-normalize */
|
---|
485 | return(sb_sputc(sb,ch));
|
---|
486 |
|
---|
487 | /* No blks left, fall through to insert stuff at end */
|
---|
488 | }
|
---|
489 |
|
---|
490 | /* Do canonical setup with heavy artillery */
|
---|
491 | if((int)sbx_ready(sb,SK_WRITEF,SB_SLOP,SB_BUFSIZ) <= 0) /* Get room */
|
---|
492 | return(EOF); /* Should never happen, but... */
|
---|
493 | sb->sbflags |= SB_WRIT;
|
---|
494 | sb->sbcur->sdflags |= SD_MOD;
|
---|
495 | return(sb_sputc(sb,ch)); /* Try again */
|
---|
496 | } /* Loop wd be faster, but PDL OV will catch infinite-loop bugs */
|
---|
497 |
|
---|
498 |
|
---|
499 | /* SB_PEEKC(sb) - Peek at next char from sbstring.
|
---|
500 | * Returns char that sb_getc would next return, but without
|
---|
501 | * changing I/O ptr.
|
---|
502 | * Returns EOF on error or end-of-string.
|
---|
503 | */
|
---|
504 | int
|
---|
505 | sb_speekc(sb)
|
---|
506 | register SBBUF *sb;
|
---|
507 | {
|
---|
508 | if (sb->sbrleft <= 0) /* See if OK to read */
|
---|
509 | { if (sb_sgetc(sb) == EOF) /* No, try hard to get next */
|
---|
510 | return EOF; /* Failed, return EOF */
|
---|
511 | sb_backc(sb); /* Won, back up */
|
---|
512 | }
|
---|
513 | return sb_uchartoint(*sb->sbiop);
|
---|
514 | }
|
---|
515 |
|
---|
516 | /* SB_RGETC(sb) - Get previous char from sbstring.
|
---|
517 | * Returns char prior to current location and backs up I/O ptr.
|
---|
518 | * Returns EOF on error or beginning-of-string.
|
---|
519 | */
|
---|
520 | int
|
---|
521 | sb_rgetc(sb)
|
---|
522 | register SBBUF *sb;
|
---|
523 | {
|
---|
524 | register struct smblk *sm;
|
---|
525 | register struct sdblk *sd;
|
---|
526 |
|
---|
527 | if((sd=sb->sbcur) && (sm = sd->sdmem)
|
---|
528 | && sb->sbiop > sm->smaddr)
|
---|
529 | { if(sb->sbflags&SB_WRIT)
|
---|
530 | { sm->smuse = sb->sbiop - sm->smaddr;
|
---|
531 | sb->sbwleft = 0;
|
---|
532 | sb->sbflags &= ~SB_WRIT;
|
---|
533 | }
|
---|
534 | sb->sbrleft++;
|
---|
535 | return sb_uchartoint(*--sb->sbiop); /* Return char */
|
---|
536 | }
|
---|
537 | if((int)sbx_ready(sb,SK_READB,SB_BUFSIZ,0) <= 0)
|
---|
538 | return(EOF);
|
---|
539 | return(sb_rgetc(sb));
|
---|
540 | }
|
---|
541 |
|
---|
542 | /* SB_RDELC(sb) - Delete backwards one char.
|
---|
543 | * Returns nothing.
|
---|
544 | */
|
---|
545 | sb_rdelc(sbp)
|
---|
546 | SBBUF *sbp;
|
---|
547 | { register SBBUF *sb;
|
---|
548 | register struct sdblk *sd;
|
---|
549 |
|
---|
550 | if(((sb=sbp)->sbflags&SB_WRIT) /* Handle simple case fast */
|
---|
551 | && sb->sbiop > (sd = sb->sbcur)->sdmem->smaddr)
|
---|
552 | { sb->sbwleft++;
|
---|
553 | sb->sbiop--;
|
---|
554 | sd->sdflags |= SD_MOD;
|
---|
555 | return;
|
---|
556 | }
|
---|
557 | else sb_deln(sb,(chroff) -1); /* Else punt... */
|
---|
558 | }
|
---|
559 |
|
---|
560 | /* SB_DELC(sb) - Delete one char forward? */
|
---|
561 | /* SB_INSC(sb,ch) - Insert char? (instead of or in addition to PUTC) */
|
---|
562 |
|
---|
563 | |
---|
564 |
|
---|
565 | /* SBBUF string or N-char operations */
|
---|
566 |
|
---|
567 | /* SB_DELN(sb,chroff) - delete N chars. Negative N means backwards.
|
---|
568 | * Differs from sb_killn in that it flushes the text forever,
|
---|
569 | * and doesn't return anything.
|
---|
570 | */
|
---|
571 |
|
---|
572 | sb_deln(sbp, num)
|
---|
573 | SBBUF *sbp;
|
---|
574 | chroff num;
|
---|
575 | {
|
---|
576 | register struct sdblk *sd;
|
---|
577 |
|
---|
578 | if(sd = sb_killn(sbp,num))
|
---|
579 | sbs_del(sd); /* Punt */
|
---|
580 | }
|
---|
581 |
|
---|
582 | /* SB_KILLN(sb,chroff) - delete N chars, saving. Negative N means backwards.
|
---|
583 | * Returns SD pointer to beginning of saved sbstring.
|
---|
584 | */
|
---|
585 | struct sdblk *
|
---|
586 | sb_killn(sbp, num)
|
---|
587 | SBBUF *sbp;
|
---|
588 | chroff num;
|
---|
589 | { register SBBUF *sb;
|
---|
590 | register struct sdblk *sd, *sd2;
|
---|
591 | struct sdblk *sdr, *sdx;
|
---|
592 | chroff savdot;
|
---|
593 |
|
---|
594 | if((sd = sbx_xcis((sb=sbp),num,&sdr,&savdot)) == 0)
|
---|
595 | return((struct sdblk *)0);
|
---|
596 |
|
---|
597 | sb->sbcur->sdflags &= ~SD_LOCK; /* Now can flush sbcur lock */
|
---|
598 |
|
---|
599 | /* SD and SD2 now delimit bounds of stuff to excise.
|
---|
600 | * First do direction dependent fixups
|
---|
601 | */
|
---|
602 | if(num >= 0) /* If deleting forward, */
|
---|
603 | sb->sbdot = savdot; /* must reset dot to initial loc */
|
---|
604 |
|
---|
605 | /* SD and SD2 now in first/last order. Complete SBCUR fixup. */
|
---|
606 | sd2 = sdr; /* sdr has ptr to end of stuff */
|
---|
607 | if(sd2 = sd2->slforw) /* More stuff after killed list? */
|
---|
608 | { sb->sbcur = sd2; /* Yes, point at it */
|
---|
609 | sb->sboff = 0; /* Dot already set right */
|
---|
610 | }
|
---|
611 | else if(sdx = sd->slback) /* See if any prior to killed list */
|
---|
612 | { sb->sbcur = sdx; /* Yes, point at it */
|
---|
613 | sb->sboff = (sdx->sdmem ? /* Get len of prev blk */
|
---|
614 | sdx->sdmem->smuse : sdx->sdlen);
|
---|
615 | sb->sbdot -= sb->sboff;
|
---|
616 | }
|
---|
617 | else sb_open(sb,(SBSTR *)0); /* No stuff left! Create null sbstring */
|
---|
618 |
|
---|
619 | /* Fix up logical links. Note SD2 points to succ of killed stuff */
|
---|
620 | if(sd->slback) /* If previous exists */
|
---|
621 | { if(sd->slback->slforw = sd2) /* Point it to succ, and */
|
---|
622 | sd2->slback = sd->slback; /* thence to self */
|
---|
623 | sd->slback = 0; /* Now init killed list */
|
---|
624 | }
|
---|
625 | else if(sd2) sd2->slback = 0; /* No prev, clean rest */
|
---|
626 | (sd2 = sdr)->slforw = 0; /* Finish killed list */
|
---|
627 |
|
---|
628 | sb->sbcur->sdflags |= SD_LOCK; /* Ensure current SD now locked */
|
---|
629 | sd->sdflags &= ~SD_LCK2; /* And unlock killed list */
|
---|
630 | sd2->sdflags &= ~SD_LCK2;
|
---|
631 | return(sd);
|
---|
632 | }
|
---|
633 |
|
---|
634 | /* SB_CPYN(sbp,num) - Copy num characters, returns SD to sbstring.
|
---|
635 | * Like SB_KILLN but doesn't take chars out of original sbstring.
|
---|
636 | */
|
---|
637 | SBSTR *
|
---|
638 | sb_cpyn(sbp,num)
|
---|
639 | SBBUF *sbp;
|
---|
640 | chroff num;
|
---|
641 | { register SBBUF *sb;
|
---|
642 | register struct sdblk *sd, *sd2;
|
---|
643 | struct sdblk *sdr;
|
---|
644 | chroff savloc;
|
---|
645 |
|
---|
646 | sb = sbp;
|
---|
647 | if((sd = sbx_xcis(sb,num,&sdr,&savloc)) == 0)
|
---|
648 | return((SBSTR *)0);
|
---|
649 | sd2 = sbx_scpy(sd,sdr);
|
---|
650 | sb_seek(sb,-num,1); /* Return to original loc */
|
---|
651 | return(sd2); /* Return val is ptr to head of copy.
|
---|
652 | * It needn't be locked, because GC will
|
---|
653 | * never move list heads!
|
---|
654 | */
|
---|
655 | }
|
---|
656 |
|
---|
657 | /* SB_SINS(sb,sd) - Insert sbstring at current location
|
---|
658 | *
|
---|
659 | */
|
---|
660 | sb_sins(sbp,sdp)
|
---|
661 | SBBUF *sbp;
|
---|
662 | struct sdblk *sdp;
|
---|
663 | { register SBBUF *sb;
|
---|
664 | register struct sdblk *sd, *sdx;
|
---|
665 | chroff inslen;
|
---|
666 |
|
---|
667 | if((sb = sbp)==0
|
---|
668 | || (sd = sdp) == 0)
|
---|
669 | return(0);
|
---|
670 | if(sd->slback) /* Perhaps normalize to beg? */
|
---|
671 | return(0);
|
---|
672 | if((sdx = (struct sdblk *)sbx_ready(sb,SK_DELB)) == 0) /* Get cur pos ready */
|
---|
673 | return(0);
|
---|
674 | inslen = sbs_len(sd); /* Save length of inserted stuff */
|
---|
675 |
|
---|
676 | sd->slback = sdx; /* Fix up links */
|
---|
677 | if(sdx->slforw)
|
---|
678 | { while(sd->slforw) /* Hunt for end of inserted sbstring */
|
---|
679 | sd = sd->slforw;
|
---|
680 | sd->slforw = sdx->slforw;
|
---|
681 | sd->slforw->slback = sd;
|
---|
682 | }
|
---|
683 | sdx->slforw = sdp;
|
---|
684 | sb->sboff += inslen; /* Set IO ptr to end of new stuff */
|
---|
685 | return(1);
|
---|
686 | }
|
---|
687 | |
---|
688 |
|
---|
689 | /* SBSTRING routines - operate on "bare" sbstrings. */
|
---|
690 |
|
---|
691 | /* SBS_CPY(sd) - Copies given sbstring, returns ptr to new sbstring.
|
---|
692 | */
|
---|
693 | SBSTR *
|
---|
694 | sbs_cpy(sdp)
|
---|
695 | SBSTR *sdp;
|
---|
696 | { return(sbx_scpy(sdp,(struct sdblk *)0));
|
---|
697 | }
|
---|
698 |
|
---|
699 | /* SBS_DEL(sd) - Flush a sbstring.
|
---|
700 | */
|
---|
701 | sbs_del(sdp)
|
---|
702 | SBSTR *sdp;
|
---|
703 | { register struct sdblk *sd;
|
---|
704 |
|
---|
705 | if(sd = sdp)
|
---|
706 | while(sd = sbx_ndel(sd));
|
---|
707 | }
|
---|
708 |
|
---|
709 |
|
---|
710 | /* SBS_APP(sd1,sd2) - Appends sbstring sd2 at end of sbstring sd1.
|
---|
711 | * Returns sd1 (pointer to new sbstring).
|
---|
712 | */
|
---|
713 |
|
---|
714 | SBSTR *
|
---|
715 | sbs_app(sdp,sdp2)
|
---|
716 | struct sdblk *sdp,*sdp2;
|
---|
717 | { register struct sdblk *sd, *sdx;
|
---|
718 |
|
---|
719 | if(sd = sdp)
|
---|
720 | { while(sdx = sd->slforw)
|
---|
721 | sd = sdx;
|
---|
722 | if(sd->slforw = sdx = sdp2)
|
---|
723 | sdx->slback = sd;
|
---|
724 | }
|
---|
725 | return(sdp);
|
---|
726 | }
|
---|
727 |
|
---|
728 | /* SBS_LEN(sd) - Find length of sbstring.
|
---|
729 | */
|
---|
730 | chroff
|
---|
731 | sbs_len(sdp)
|
---|
732 | SBSTR *sdp;
|
---|
733 | { register struct sdblk *sd;
|
---|
734 | register struct smblk *sm;
|
---|
735 | chroff len;
|
---|
736 |
|
---|
737 | if((sd = sdp)==0) return((chroff)0);
|
---|
738 | len = 0;
|
---|
739 | for(; sd ; sd = sd->slforw)
|
---|
740 | { if(sm = sd->sdmem)
|
---|
741 | len += (chroff)sm->smuse;
|
---|
742 | else len += sd->sdlen;
|
---|
743 | }
|
---|
744 | return(len);
|
---|
745 | }
|
---|
746 | |
---|
747 |
|
---|
748 | /* SBBUF I/O pointer ("dot") routines */
|
---|
749 |
|
---|
750 | /* SB_SEEK(sb,chroff,flag) - Like FSEEK. Changes I/O ptr value as
|
---|
751 | * indicated by "flag":
|
---|
752 | * 0 - offset from beg
|
---|
753 | * 1 - offset from current pos
|
---|
754 | * 2 - offset from EOF
|
---|
755 | * Returns -1 on errors.
|
---|
756 | * Seeking beyond beginning or end of sbbuf will leave pointer
|
---|
757 | * at the beginning or end respectively.
|
---|
758 | * Returns 0 unless error (then returns -1).
|
---|
759 | */
|
---|
760 | sb_seek(sbp, coff, flg)
|
---|
761 | SBBUF *sbp;
|
---|
762 | chroff coff;
|
---|
763 | int flg;
|
---|
764 | { register SBBUF *sb;
|
---|
765 | register struct smblk *sm;
|
---|
766 | register struct sdblk *sd;
|
---|
767 | SBMO moff;
|
---|
768 |
|
---|
769 | sb = sbp;
|
---|
770 | if((sd = sb->sbcur) == 0) return(-1);
|
---|
771 | if(sb->sbiop == 0)
|
---|
772 | { switch(flg)
|
---|
773 | { case 0: if(coff == 0) /* Optimize common case */
|
---|
774 | return(sb_rewind(sb));
|
---|
775 | sb->sboff = coff - sb->sbdot; /* Abs */
|
---|
776 | break;
|
---|
777 | case 1: sb->sboff += coff; /* Rel */
|
---|
778 | break;
|
---|
779 | case 2: sb->sboff += sb_ztell(sb) + coff;
|
---|
780 | break;
|
---|
781 | default: return(-1);
|
---|
782 | }
|
---|
783 | sbx_norm(sb,0);
|
---|
784 | return(0);
|
---|
785 | }
|
---|
786 | if((sm = sd->sdmem) == 0)
|
---|
787 | return(sbx_err(-1,"SDMEM 0"));
|
---|
788 | moff = sb->sbiop - sm->smaddr; /* Get cur smblk offset */
|
---|
789 | if(sb->sbflags&SB_WRIT) /* Update since moving out */
|
---|
790 | { sm->smuse = moff;
|
---|
791 | sb->sbflags &= ~SB_WRIT;
|
---|
792 | }
|
---|
793 | sb->sbwleft = 0; /* Always gets zapped */
|
---|
794 | switch(flg)
|
---|
795 | { case 0: /* Offset from beginning */
|
---|
796 | coff -= sb->sbdot + (chroff)moff; /* Make rel */
|
---|
797 |
|
---|
798 | case 1: /* Offset from current loc */
|
---|
799 | break;
|
---|
800 |
|
---|
801 | case 2: /* Offset from end */
|
---|
802 | coff += sb_ztell(sb);
|
---|
803 | break;
|
---|
804 | default: return(-1);
|
---|
805 | }
|
---|
806 |
|
---|
807 | /* COFF now has relative offset from current location */
|
---|
808 | if (-(chroff)moff <= coff && coff <= sb->sbrleft)
|
---|
809 | { /* Win! Handle repos-within-smblk */
|
---|
810 | sb->sbiop += coff;
|
---|
811 | sb->sbrleft -= coff; /* Set r; wleft already 0 */
|
---|
812 | return(0);
|
---|
813 | }
|
---|
814 |
|
---|
815 | /* Come here when moving to a different sdblk. */
|
---|
816 | sb->sbrleft = 0;
|
---|
817 | sb->sbiop = 0;
|
---|
818 | sb->sboff = coff + (chroff)moff;
|
---|
819 | sbx_norm(sb,0);
|
---|
820 | return(0);
|
---|
821 | }
|
---|
822 |
|
---|
823 | /* SB_REWIND(sb) - Go to beginning of sbbuffer.
|
---|
824 | * Much faster than using sb_seek. Note that this leaves the sbbuffer
|
---|
825 | * in an open/idle state which is maximally easy to compact.
|
---|
826 | */
|
---|
827 | sb_rewind(sbp)
|
---|
828 | SBBUF *sbp;
|
---|
829 | { register SBBUF *sb;
|
---|
830 | register struct sdblk *sd;
|
---|
831 |
|
---|
832 | if((sb = sbp)==0) return;
|
---|
833 | sbx_smdisc(sb); /* Ensure I/O disconnected */
|
---|
834 | (sd = sb->sbcur)->sdflags &= ~SD_LOCK; /* Unlock current blk */
|
---|
835 | sd = sbx_beg(sd); /* Move to beg of sbstring */
|
---|
836 | /* Need not lock - see sb_open comments, also sb_close */
|
---|
837 | /* sd->sdflags |= SD_LOCK; */ /* Lock onto this one */
|
---|
838 | sb->sbcur = sd;
|
---|
839 | sb->sbdot = 0;
|
---|
840 | sb->sboff = 0;
|
---|
841 | }
|
---|
842 |
|
---|
843 | /* SB_TELL(sb) - Get I/O ptr value for SBBUF.
|
---|
844 | * Returns -1 on errors.
|
---|
845 | */
|
---|
846 |
|
---|
847 | chroff
|
---|
848 | sb_tell(sbp)
|
---|
849 | SBBUF *sbp;
|
---|
850 | { register SBBUF *sb;
|
---|
851 | register struct smblk *sm;
|
---|
852 | register struct sdblk *sd;
|
---|
853 |
|
---|
854 | if((sd = (sb=sbp)->sbcur) == 0)
|
---|
855 | return((chroff)-1);
|
---|
856 | if(sb->sbiop == 0)
|
---|
857 | return(sb->sbdot + sb->sboff);
|
---|
858 | if((sm = sd->sdmem) == 0)
|
---|
859 | return(sbx_err(0,"SDMEM 0"));
|
---|
860 | return(sb->sbdot + (unsigned)(sb->sbiop - sm->smaddr));
|
---|
861 | }
|
---|
862 |
|
---|
863 | /* SB_ZTELL(sb) - Get I/O ptr relative to "Z" (EOF).
|
---|
864 | * Returns # chars from current location to EOF; 0 if any errors.
|
---|
865 | */
|
---|
866 | chroff
|
---|
867 | sb_ztell(sbp)
|
---|
868 | SBBUF *sbp;
|
---|
869 | { register SBBUF *sb;
|
---|
870 | register struct smblk *sm;
|
---|
871 | register struct sdblk *sd;
|
---|
872 |
|
---|
873 | if((sd = (sb=sbp)->sbcur) == 0)
|
---|
874 | return((chroff)0);
|
---|
875 | if(sb->sbiop && (sm = sd->sdmem))
|
---|
876 | { if(sb->sbflags&SB_WRIT) /* If actively writing, */
|
---|
877 | return(sbs_len(sd->slforw)); /* ignore this blk. */
|
---|
878 | /* Note that previous code makes it unnecessary
|
---|
879 | * to invoke sbx_smdisc. (otherwise wrong
|
---|
880 | * smuse would confuse sbs_len).
|
---|
881 | */
|
---|
882 | return(sbs_len(sd) - (sb->sbiop - sm->smaddr));
|
---|
883 | }
|
---|
884 | else
|
---|
885 | return(sbs_len(sd) - sb->sboff);
|
---|
886 | }
|
---|
887 | |
---|
888 |
|
---|
889 | /* Code past this point should insofar as possible be INTERNAL. */
|
---|
890 |
|
---|
891 | /* SBX_READY(sb,type,cmin,cmax) - Set up SBBUF for reading or writing.
|
---|
892 | *
|
---|
893 | * If no current smblk:
|
---|
894 | * reading - set up for reading
|
---|
895 | * writing - set up for splitting?
|
---|
896 | * If current smblk:
|
---|
897 | * reading - if can read, OK. Else position at beg of next sdblk
|
---|
898 | * writing - if can write, OK. Else position at end of prev sdblk,
|
---|
899 | * or set up for splitting?
|
---|
900 | * Types:
|
---|
901 | * 0 - Read forward (BOB)
|
---|
902 | * 1 - Read backward (EOB)
|
---|
903 | * 3 - Write (insert forward) (EOB)
|
---|
904 | * 4 - Delete forward (return SD, force BOB-aligned)
|
---|
905 | * 5 - Delete backward (return SD, force EOB-aligned)
|
---|
906 | * Connected SD is always locked.
|
---|
907 | * Returns 0 if error, -1 if EOF-type error, 1 for success.
|
---|
908 | *
|
---|
909 | * For types 0,1:
|
---|
910 | * CMIN,CMAX represent max # chars to read in to left and right of
|
---|
911 | * I/O ptr (prev and post). Actual amount read in may be
|
---|
912 | * much less, but will never be zero.
|
---|
913 | * Successful return guarantees that SBIOP etc. are ready.
|
---|
914 | * For type 3:
|
---|
915 | * If new block is allocated, CMIN and CMAX represent min, max sizes
|
---|
916 | * of the block.
|
---|
917 | * Successful return guarantees that SBIOP etc. are ready, but
|
---|
918 | * NOTE that SB_WRIT and SD_MOD are not set! If not going to use
|
---|
919 | * for writing, be sure to clear sbwleft on return!
|
---|
920 | * For types 4,5:
|
---|
921 | * CMIN, CMAX are ignored.
|
---|
922 | * SBIOP is always cleared. SBOFF is guaranteed to be 0 for
|
---|
923 | * type 4, SMUSE for type 5.
|
---|
924 | * Return value is a SD ptr; 0 indicates error. -1 isn't used.
|
---|
925 | */
|
---|
926 |
|
---|
927 | struct sdblk *
|
---|
928 | sbx_ready(sbp,type,cmin,cmax)
|
---|
929 | SBBUF *sbp;
|
---|
930 | int type;
|
---|
931 | SBMO cmin,cmax;
|
---|
932 | { register SBBUF *sb;
|
---|
933 | register struct sdblk *sd;
|
---|
934 | register struct smblk *sm;
|
---|
935 | int cnt, slop, rem;
|
---|
936 | SBMO moff;
|
---|
937 |
|
---|
938 | if((sd = (sb=sbp)->sbcur) == 0)
|
---|
939 | return(0);
|
---|
940 | if(sb->sbiop) /* Canonicalize for given operation */
|
---|
941 | { if((sm = sd->sdmem)==0)
|
---|
942 | return(0);
|
---|
943 | moff = sb->sbiop - sm->smaddr; /* Current block offset */
|
---|
944 | switch(type)
|
---|
945 | {
|
---|
946 | case SK_READF: /* Read Forward */
|
---|
947 | if(sb->sbrleft > 0) /* Already set up? */
|
---|
948 | return(1); /* Yup, fast return */
|
---|
949 | sbx_smdisc(sb); /* None left, disc to get next */
|
---|
950 | if((sd = sbx_next(sb)) == 0) /* Try to get next blk */
|
---|
951 | return(-1); /* At EOF */
|
---|
952 | break;
|
---|
953 |
|
---|
954 | case SK_READB: /* Read Backward */
|
---|
955 | if(moff) /* Stuff there to read? */
|
---|
956 | { if(sb->sbflags&SB_WRIT) /* Yup, turn writes off */
|
---|
957 | { sm->smuse = moff;
|
---|
958 | sb->sbflags &= ~SB_WRIT;
|
---|
959 | }
|
---|
960 | sb->sbwleft = 0;
|
---|
961 | return(1);
|
---|
962 | }
|
---|
963 | sbx_smdisc(sb);
|
---|
964 | break;
|
---|
965 |
|
---|
966 | case SK_WRITEF: /* Writing */
|
---|
967 | if(sb->sbrleft <= 0)
|
---|
968 | sb->sbwleft = sm->smlen - moff;
|
---|
969 | if(sb->sbwleft > 0)
|
---|
970 | return(1); /* OK to write now */
|
---|
971 | /* NOTE: flags not set!!! */
|
---|
972 | sbx_smdisc(sb);
|
---|
973 | break;
|
---|
974 |
|
---|
975 | case SK_DELF: /* Delete forward - force BOB */
|
---|
976 | if(sb->sbrleft <= 0) /* At end of blk? */
|
---|
977 | { sbx_smdisc(sb); /* Win, unhook */
|
---|
978 | return(sbx_next(sb)); /* Return next or 0 if EOF */
|
---|
979 | }
|
---|
980 | sbx_smdisc(sb); /* Not at end, but see if */
|
---|
981 | if(moff == 0) /* at beg of blk? */
|
---|
982 | return(sd); /* Fast win! */
|
---|
983 | break;
|
---|
984 |
|
---|
985 | case SK_DELB: /* Delete backward - force EOB */
|
---|
986 | if(sb->sbrleft <= 0) /* Win if already EOB */
|
---|
987 | { sbx_smdisc(sb);
|
---|
988 | return(sd);
|
---|
989 | }
|
---|
990 | sbx_smdisc(sb);
|
---|
991 | break;
|
---|
992 |
|
---|
993 | default:
|
---|
994 | return(0);
|
---|
995 | }
|
---|
996 | }
|
---|
997 |
|
---|
998 | /* Schnarf in the text, or whatever.
|
---|
999 | * SD points to current sdblk (must be SD_LOCKed)
|
---|
1000 | * SBDOT must have correct value for this SD
|
---|
1001 | * SBOFF has offset from there to put I/O ptr at.
|
---|
1002 | *
|
---|
1003 | * After normalization, SBOFF is guaranteed to point within
|
---|
1004 | * the SD. Other guarantees apply to boundary cases, depending
|
---|
1005 | * on the mode (type) bits.
|
---|
1006 | */
|
---|
1007 | sd = sbx_norm(sb,type); /* Normalize I/O pos appropriately */
|
---|
1008 | sm = sd->sdmem;
|
---|
1009 | switch(type)
|
---|
1010 | {
|
---|
1011 | case SK_READB: /* Read Backward */
|
---|
1012 | if(sb->sboff == 0) /* Due to normalize, if 0 seen */
|
---|
1013 | return(-1); /* then we know it's BOF */
|
---|
1014 | if(sm) goto sekr2;
|
---|
1015 | else goto sekr1;
|
---|
1016 |
|
---|
1017 | case SK_READF: /* Read Forward */
|
---|
1018 | if(sm) goto sekr2;
|
---|
1019 | if(sb->sboff == sd->sdlen) /* Normalize means if EOB */
|
---|
1020 | return(-1); /* then at EOF. */
|
---|
1021 | sekr1: slop = SB_SLOP;
|
---|
1022 | sekr3: if(sb->sboff > cmin+slop) /* Too much leading text? */
|
---|
1023 | { /* Split off leading txt */
|
---|
1024 | sbx_split(sd,(chroff)(sb->sboff - cmin));
|
---|
1025 | sd = sbx_next(sb); /* Point to next sdblk */
|
---|
1026 | sb->sboff = cmin; /* Set correct offset */
|
---|
1027 | /* (sbx_next assumes 0) */
|
---|
1028 | }
|
---|
1029 | if(sd->sdlen > sb->sboff+cmax+slop) /* Too much trailing txt? */
|
---|
1030 | sbx_split(sd,(chroff)(sb->sboff+cmax));
|
---|
1031 |
|
---|
1032 | /* ----- Try to get mem blk to read stuff into ----- */
|
---|
1033 | /* Note alignment hack for extra efficiency. This ensures
|
---|
1034 | * that all reads from disk to memory are made with the same
|
---|
1035 | * source and destination word alignment, so the system kernel
|
---|
1036 | * only needs byte-moves for the first or last bytes; all
|
---|
1037 | * others can be word-moves.
|
---|
1038 | * This works because sbx_mget always returns word-aligned
|
---|
1039 | * storage, and we use sbx_msplit to trim off the right number
|
---|
1040 | * of bytes from the start.
|
---|
1041 | */
|
---|
1042 | cnt = sd->sdlen; /* Get # bytes we'd like */
|
---|
1043 | if(rem = rndrem(sd->sdaddr)) /* If disk not word-aligned */
|
---|
1044 | cnt += rem; /* allow extra for aligning.*/
|
---|
1045 | if(sm == 0) /* Always true 1st time */
|
---|
1046 | { sm = sbx_mget(SB_SLOP,cnt); /* Get room (may GC!)*/
|
---|
1047 | if(sm->smlen < cnt) /* Got what we wanted? */
|
---|
1048 | { slop = 0; /* NO!! Impose stricter */
|
---|
1049 | cmin = 0; /* limits. Allow for new */
|
---|
1050 | cmax = sm->smlen - (WDSIZE-1); /* rem. */
|
---|
1051 | if(type == SK_READB)
|
---|
1052 | { cmin = cmax; cmax = 0; }
|
---|
1053 | goto sekr3; /* Go try again, sigh. */
|
---|
1054 | }
|
---|
1055 | }
|
---|
1056 | else if(sm->smlen < cnt) /* 2nd time shd always win */
|
---|
1057 | { sbx_err(0,"Readin blksiz err"); /* Internal error, */
|
---|
1058 | if((cmax /= 2) > 0) goto sekr3; /* w/crude recovery */
|
---|
1059 | return(0);
|
---|
1060 | }
|
---|
1061 | if(rem) /* If disk not word-aligned, hack stuff */
|
---|
1062 | { sm = sbx_msplit(sm, (SBMO)rem); /* Trim off from beg*/
|
---|
1063 | sbm_mfree(sm->smback); /* Free the excess */
|
---|
1064 | }
|
---|
1065 | sd->sdmem = sm;
|
---|
1066 | sm->smuse = sd->sdlen;
|
---|
1067 |
|
---|
1068 | if(sd->sdfile == 0)
|
---|
1069 | return(sbx_err(0,"No file")); /* Gasp? */
|
---|
1070 | if(!sbx_rdf(sd->sdfile->sffd, sm->smaddr, sm->smuse,
|
---|
1071 | 1, sd->sdaddr))
|
---|
1072 | return(sbx_err(0,"Readin SD: %o", sd));
|
---|
1073 | /* ------- */
|
---|
1074 |
|
---|
1075 | sekr2: sbx_sbrdy(sb); /* Make it current, pt to beg */
|
---|
1076 | sb->sbwleft = 0; /* Ensure not set (esp if READB) */
|
---|
1077 | break;
|
---|
1078 |
|
---|
1079 | case SK_WRITEF: /* Write-type seek */
|
---|
1080 | if(sm == 0)
|
---|
1081 | { /* Block is on disk, so always split (avoid readin) */
|
---|
1082 | if(sd->sdlen) /* May be empty */
|
---|
1083 | { sbx_split(sd, sb->sboff); /* Split at IO ptr */
|
---|
1084 | sd = sbx_next(sb); /* Move to 2nd part */
|
---|
1085 | if(sd->sdlen) /* If stuff there, */
|
---|
1086 | /* split it again. */
|
---|
1087 | sbx_split(sd, (chroff) 0);
|
---|
1088 | }
|
---|
1089 | goto sekwget;
|
---|
1090 | }
|
---|
1091 |
|
---|
1092 | /* Block in memory */
|
---|
1093 | moff = sm->smuse;
|
---|
1094 | if(sb->sboff == moff) /* At end of the block? */
|
---|
1095 | { if(sm->smlen > moff) /* Yes, have room? */
|
---|
1096 | goto sekw; /* Win, go setup and ret */
|
---|
1097 | if(sm->smforw /* If next mem blk */
|
---|
1098 | && (sm->smforw->smflags /* Can have bytes */
|
---|
1099 | & (SM_USE|SM_NXM))==0 /* stolen from it */
|
---|
1100 | && (sd->sdflags&SD_MOD) /* and we ain't pure*/
|
---|
1101 | && sm->smlen < cmax) /* and not too big */
|
---|
1102 | { /* Then steal some core!! Note that without
|
---|
1103 | * the size test, a stream of putc's could
|
---|
1104 | * create a monster block gobbling all mem.
|
---|
1105 | */
|
---|
1106 | cmin = cmax - sm->smlen;
|
---|
1107 | if(cmin&01) cmin++; /* Ensure wd-align */
|
---|
1108 | if(sm->smforw->smlen <= cmin)
|
---|
1109 | { sbm_mmrg(sm);
|
---|
1110 | goto sekw;
|
---|
1111 | }
|
---|
1112 | sm->smforw->smlen -= cmin;
|
---|
1113 | sm->smforw->smaddr += cmin;
|
---|
1114 | sm->smlen += cmin;
|
---|
1115 | goto sekw;
|
---|
1116 | }
|
---|
1117 | /* Last try... check next logical blk for room */
|
---|
1118 | if(sd->slforw && (sm = sd->slforw->sdmem)
|
---|
1119 | && sm->smuse == 0
|
---|
1120 | && sm->smlen)
|
---|
1121 | { sd = sbx_next(sb); /* Yup, go there */
|
---|
1122 | goto sekw;
|
---|
1123 | }
|
---|
1124 | }
|
---|
1125 |
|
---|
1126 | /* Middle of block, split up to insert */
|
---|
1127 | sbx_split(sd, sb->sboff); /* Split at IO ptr */
|
---|
1128 | if(sd->sdmem) /* Unless blk now empty, */
|
---|
1129 | { sd = sbx_next(sb); /* move to next. */
|
---|
1130 | if(sd->sdmem) /* If not empty either */
|
---|
1131 | sbx_split(sd, (chroff) 0); /* Split again */
|
---|
1132 | }
|
---|
1133 |
|
---|
1134 | /* Have empty SD block, get some mem for it */
|
---|
1135 | sekwget: sd->sdmem = sm = sbx_mget(cmin,cmax);
|
---|
1136 | sm->smuse = 0;
|
---|
1137 | sekw: sbx_sbrdy(sb); /* Sets up sbwleft... */
|
---|
1138 | return(1);
|
---|
1139 |
|
---|
1140 | case SK_DELF: /* Delete forward */
|
---|
1141 | if(sb->sboff == 0) /* At block beg already? */
|
---|
1142 | return(sd); /* Win, return it */
|
---|
1143 | sbx_split(sd, sb->sboff); /* No, split up and */
|
---|
1144 | return(sbx_next(sb)); /* return ptr to 2nd part */
|
---|
1145 |
|
---|
1146 | case SK_DELB: /* Delete backward (force EOB align) */
|
---|
1147 | if(sb->sboff != /* If not at EOB already, */
|
---|
1148 | (sm ? (chroff)(sm->smuse) : sd->sdlen))
|
---|
1149 | sbx_split(sd, sb->sboff); /* Then split */
|
---|
1150 | return(sd); /* And return ptr to 1st part */
|
---|
1151 | break;
|
---|
1152 |
|
---|
1153 | default:
|
---|
1154 | return(0);
|
---|
1155 | } /* End of switch */
|
---|
1156 | return(1);
|
---|
1157 | }
|
---|
1158 |
|
---|
1159 | struct sdblk *
|
---|
1160 | sbx_next (sbp)
|
---|
1161 | SBBUF *sbp;
|
---|
1162 | { register SBBUF *sb;
|
---|
1163 | register struct sdblk *sd, *sdf;
|
---|
1164 | if((sdf = (sd = (sb=sbp)->sbcur)->slforw) == 0)
|
---|
1165 | return((struct sdblk *)0);
|
---|
1166 | sb->sbdot += (sd->sdmem ? (chroff)sd->sdmem->smuse : sd->sdlen);
|
---|
1167 | sb->sboff = 0;
|
---|
1168 | sd->sdflags &= ~SD_LOCK; /* Unlock current */
|
---|
1169 | sdf->sdflags |= SD_LOCK; /* Lock next */
|
---|
1170 | sb->sbcur = sdf;
|
---|
1171 | return(sdf);
|
---|
1172 | }
|
---|
1173 | |
---|
1174 |
|
---|
1175 | /* SBX_NORM(sb,mode) - Normalizes I/O position as desired.
|
---|
1176 | * The SBBUF must have I/O disconnected (SBIOP==0).
|
---|
1177 | * Adjusts SBCUR, SBDOT, and SBOFF so that SBOFF is guaranteed
|
---|
1178 | * to point to a location in the current SD block.
|
---|
1179 | * The mode flags determine action when there is more than
|
---|
1180 | * one possible SD that could be pointed to, as is the case
|
---|
1181 | * when the I/O pos falls on a block boundary (possibly with
|
---|
1182 | * adjacent zero-length blocks as well).
|
---|
1183 | * SKM_0BACK - Zero-skip direction.
|
---|
1184 | * 0 = Skip forward over zero-length blocks.
|
---|
1185 | * set = Skip backward over zero-length blocks.
|
---|
1186 | * SKM_EOB - Block-end selection (applies after skipping done).
|
---|
1187 | * 0 = Point to BOB (Beginning Of Block).
|
---|
1188 | * set = Point to EOB (End Of Block).
|
---|
1189 | * Returns the new current SD as a convenience.
|
---|
1190 | * Notes:
|
---|
1191 | * The SKM_0BACK flag value is a special hack to search in
|
---|
1192 | * the right direction when SBOFF is initially 0.
|
---|
1193 | * None of the mode flags have any effect if the I/O pos falls
|
---|
1194 | * within a block.
|
---|
1195 | * Perhaps this routine should flush the zero-length blks it
|
---|
1196 | * finds, if they're not locked??
|
---|
1197 | */
|
---|
1198 | struct sdblk *
|
---|
1199 | sbx_norm(sbp,mode)
|
---|
1200 | SBBUF *sbp;
|
---|
1201 | int mode;
|
---|
1202 | { register struct sdblk *sd;
|
---|
1203 | register struct smblk *sm;
|
---|
1204 | register SBBUF *sb;
|
---|
1205 | chroff len;
|
---|
1206 |
|
---|
1207 | if((sd = (sb=sbp)->sbcur) == 0)
|
---|
1208 | { sb->sbdot = 0;
|
---|
1209 | sb->sboff = 0;
|
---|
1210 | return(sd);
|
---|
1211 | }
|
---|
1212 | sd->sdflags &= ~SD_LOCK; /* Unlock current blk */
|
---|
1213 |
|
---|
1214 | if(sb->sboff >= (mode&01)) /* Hack hack to get right skip */
|
---|
1215 | for(;;) /* Scan forwards */
|
---|
1216 | { if(sm = sd->sdmem) /* Get length of this blk */
|
---|
1217 | len = sm->smuse;
|
---|
1218 | else len = sd->sdlen;
|
---|
1219 | if(sb->sboff <= len)
|
---|
1220 | if(sb->sboff < len /* If == and fwd 0-skip, continue */
|
---|
1221 | || (mode&SKM_0BACK))
|
---|
1222 | { if((mode&SKM_EOB) /* Done, adjust to EOB? */
|
---|
1223 | && sb->sboff == 0 /* Yes, are we at BOB? */
|
---|
1224 | && sd->slback) /* and can do it? */
|
---|
1225 | { sd = sd->slback; /* Move to EOB */
|
---|
1226 | sb->sboff = (sm = sd->sdmem)
|
---|
1227 | ? (chroff)(sm->smuse) : sd->sdlen;
|
---|
1228 | sb->sbdot -= sb->sboff;
|
---|
1229 | }
|
---|
1230 | break;
|
---|
1231 | }
|
---|
1232 | if(sd->slforw == 0) /* At EOF? */
|
---|
1233 | { sb->sboff = len;
|
---|
1234 | break;
|
---|
1235 | }
|
---|
1236 | sd = sd->slforw;
|
---|
1237 | sb->sboff -= len;
|
---|
1238 | sb->sbdot += len;
|
---|
1239 | }
|
---|
1240 | else /* Scan backwards */
|
---|
1241 | for(;;)
|
---|
1242 | { if(sd->slback == 0) /* At BOF? */
|
---|
1243 | { sb->sboff = 0;
|
---|
1244 | sb->sbdot = 0; /* Should already be 0, but... */
|
---|
1245 | break;
|
---|
1246 | }
|
---|
1247 | sd = sd->slback;
|
---|
1248 | if(sm = sd->sdmem) /* Get length of this blk */
|
---|
1249 | len = sm->smuse;
|
---|
1250 | else len = sd->sdlen;
|
---|
1251 | sb->sbdot -= len;
|
---|
1252 | if((sb->sboff += len) >= 0)
|
---|
1253 | if(sb->sboff > 0 /* If == 0 and bkwd 0-skip, continue */
|
---|
1254 | || !(mode&SKM_0BACK))
|
---|
1255 | { if((mode&SKM_EOB) == 0 /* Done, adjust to BOB? */
|
---|
1256 | && sb->sboff == len /* Yes, are we at EOB? */
|
---|
1257 | && sd->slforw) /* and can do it? */
|
---|
1258 | { sd = sd->slforw; /* Move to BOB */
|
---|
1259 | sb->sboff = 0;
|
---|
1260 | sb->sbdot += len;
|
---|
1261 | }
|
---|
1262 | break;
|
---|
1263 | }
|
---|
1264 | }
|
---|
1265 | sb->sbcur = sd;
|
---|
1266 | sd->sdflags |= SD_LOCK;
|
---|
1267 | return(sd);
|
---|
1268 | }
|
---|
1269 | |
---|
1270 |
|
---|
1271 |
|
---|
1272 | struct sdblk *
|
---|
1273 | sbx_beg(sdp)
|
---|
1274 | struct sdblk *sdp;
|
---|
1275 | { register struct sdblk *sd, *sdx;
|
---|
1276 | if(sd = sdp)
|
---|
1277 | while(sdx = sd->slback)
|
---|
1278 | sd = sdx;
|
---|
1279 | return(sd);
|
---|
1280 | }
|
---|
1281 |
|
---|
1282 |
|
---|
1283 | sbx_smdisc(sbp)
|
---|
1284 | SBBUF *sbp;
|
---|
1285 | { register SBBUF *sb;
|
---|
1286 | register struct smblk *sm;
|
---|
1287 | register struct sdblk *sd;
|
---|
1288 |
|
---|
1289 | sb = sbp;
|
---|
1290 | if((sd = sb->sbcur) == 0
|
---|
1291 | || (sm = sd->sdmem) == 0)
|
---|
1292 | return;
|
---|
1293 | if(sb->sbflags&SB_WRIT)
|
---|
1294 | { sm->smuse = sb->sbiop - sm->smaddr;
|
---|
1295 | sb->sbflags &= ~SB_WRIT;
|
---|
1296 | }
|
---|
1297 | sb->sboff = sb->sbiop - sm->smaddr;
|
---|
1298 | sb->sbiop = 0;
|
---|
1299 | sb->sbrleft = sb->sbwleft = 0;
|
---|
1300 | }
|
---|
1301 |
|
---|
1302 | sbx_sbrdy(sbp) /* Sets up SBIOP, SBRLEFT, SBWLEFT */
|
---|
1303 | SBBUF *sbp;
|
---|
1304 | { register SBBUF *sb;
|
---|
1305 | register struct sdblk *sd;
|
---|
1306 | register struct smblk *sm;
|
---|
1307 |
|
---|
1308 | if((sd = (sb=sbp)->sbcur) == 0
|
---|
1309 | || (sm = sd->sdmem) == 0)
|
---|
1310 | return;
|
---|
1311 | sd->sdflags |= SD_LOCK;
|
---|
1312 | sb->sbiop = sm->smaddr + sb->sboff;
|
---|
1313 | if(sb->sbrleft = sm->smuse - sb->sboff)
|
---|
1314 | sb->sbwleft = 0;
|
---|
1315 | else sb->sbwleft = sm->smlen - sm->smuse;
|
---|
1316 | }
|
---|
1317 | |
---|
1318 |
|
---|
1319 |
|
---|
1320 | /* SBX_SCPY(sd,sdl) - Copies given sbstring, returns ptr to new sbstring.
|
---|
1321 | * Only goes as far as sdl (last copied blk); 0 for entire sbstring.
|
---|
1322 | */
|
---|
1323 | struct sdblk *
|
---|
1324 | sbx_scpy(sdp,sdlast)
|
---|
1325 | struct sdblk *sdp, *sdlast;
|
---|
1326 | { register struct sdblk *sd, *sd2, *sdn;
|
---|
1327 | struct sdblk *sdr;
|
---|
1328 |
|
---|
1329 | if((sd = sdp) == 0) return((struct sdblk *)0);
|
---|
1330 | sdn = 0;
|
---|
1331 | do {
|
---|
1332 | sd->sdflags |= SD_LCK2;
|
---|
1333 | sd2 = sbx_sdcpy(sd);
|
---|
1334 | if(sd2->slback = sdn)
|
---|
1335 | { sdn->slforw = sd2;
|
---|
1336 | sdn->sdflags &= ~SD_LOCKS;
|
---|
1337 | }
|
---|
1338 | else sdr = sd2; /* Save 1st */
|
---|
1339 | sdn = sd2;
|
---|
1340 | sd->sdflags &= ~SD_LCK2;
|
---|
1341 | } while(sd != sdlast && (sd = sd->slforw));
|
---|
1342 | sd2->slforw = 0;
|
---|
1343 | sd2->sdflags &= ~SD_LOCKS;
|
---|
1344 | return(sdr);
|
---|
1345 | }
|
---|
1346 |
|
---|
1347 |
|
---|
1348 | /* SBX_SDCPY(sd) - Copies given sdblk, returns ptr to new blk.
|
---|
1349 | * Does not set locks, assumes caller does this (which it MUST,
|
---|
1350 | * to avoid compaction lossage!)
|
---|
1351 | */
|
---|
1352 |
|
---|
1353 | struct sdblk *
|
---|
1354 | sbx_sdcpy(sdp)
|
---|
1355 | struct sdblk *sdp;
|
---|
1356 | { register struct sdblk *sd, *sd2;
|
---|
1357 | register struct smblk *sm, *sm2;
|
---|
1358 |
|
---|
1359 | if((sd = sdp) == 0) return((struct sdblk *)0);
|
---|
1360 | sd2 = sbx_ndget(); /* Get a free sdblk */
|
---|
1361 | bcopy((SBMA)sd, (SBMA)sd2, sizeof(struct sdblk)); /* Copy sdblk data */
|
---|
1362 | sd2->slforw = 0; /* Don't let it think it's on a list */
|
---|
1363 | sd2->slback = 0;
|
---|
1364 | if(sd2->sdfile) /* If has disk copy, */
|
---|
1365 | { sd->sdforw = sd2; /* Fix phys list ptrs */
|
---|
1366 | sd2->sdback = sd;
|
---|
1367 | if(sd2->sdforw)
|
---|
1368 | sd2->sdforw->sdback = sd2;
|
---|
1369 | }
|
---|
1370 | if(sm = sd2->sdmem) /* If has in-core copy, try to */
|
---|
1371 | { if(sm2 = sbm_mget(sm->smuse,sm->smuse)) /* get mem for it */
|
---|
1372 | { bcopy(sm->smaddr,sm2->smaddr,sm->smuse);
|
---|
1373 | sm2->smuse = sm->smuse;
|
---|
1374 | sd2->sdmem = sm2; /* Point new sd to copy */
|
---|
1375 | }
|
---|
1376 | else /* Can't get mem... */
|
---|
1377 | { if(sd2->sdflags&SD_MOD)
|
---|
1378 | sbx_aout(sd2,1); /* Swap out the blk */
|
---|
1379 | sd2->sdmem = 0; /* Don't have incore copy */
|
---|
1380 | }
|
---|
1381 | }
|
---|
1382 | return(sd2);
|
---|
1383 | }
|
---|
1384 | |
---|
1385 |
|
---|
1386 | /* SBX_XCIS(sbp,coff,&sdp2,adot) - Internal routine to excise a sbstring,
|
---|
1387 | * defined as everything between current location and given offset.
|
---|
1388 | * SD to first sdblk is returned (0 if error)
|
---|
1389 | * SD2 (address passed as 3rd arg) is set to last sdblk.
|
---|
1390 | * Both are locked with LCK2 to ensure that pointers are valid.
|
---|
1391 | * The current location at time of call is also returned via adot.
|
---|
1392 | */
|
---|
1393 | struct sdblk *
|
---|
1394 | sbx_xcis(sbp,num,asd2,adot)
|
---|
1395 | SBBUF *sbp;
|
---|
1396 | chroff num, *adot;
|
---|
1397 | struct sdblk **asd2;
|
---|
1398 | { register SBBUF *sb;
|
---|
1399 | register struct sdblk *sd, *sd2;
|
---|
1400 | int dirb;
|
---|
1401 |
|
---|
1402 | if((sb = sbp) == 0) return((struct sdblk *)0);
|
---|
1403 | dirb = 0; /* Delete forward */
|
---|
1404 | if(num == 0) return((struct sdblk *)0); /* Delete nothing */
|
---|
1405 | if(num < 0) dirb++; /* Delete backward */
|
---|
1406 |
|
---|
1407 | if((sd = (struct sdblk *)
|
---|
1408 | sbx_ready(sb, (dirb ? SK_DELB : SK_DELF))) == 0)
|
---|
1409 | return((struct sdblk *)0); /* Maybe nothing there */
|
---|
1410 | sd->sdflags |= SD_LCK2; /* Lock up returned SD */
|
---|
1411 | *adot = sb->sbdot; /* Save current location */
|
---|
1412 | sb->sboff += num; /* Move to other end of range */
|
---|
1413 |
|
---|
1414 | if((sd2 = (struct sdblk *)
|
---|
1415 | sbx_ready(sb,(dirb ? SK_DELF : SK_DELB))) == 0)
|
---|
1416 | { sd->sdflags &= ~SD_LCK2; /* This shd never happen if */
|
---|
1417 | return( /* we got this far, but... */
|
---|
1418 | (struct sdblk *)sbx_err(0,"KILLN SD2 failed"));
|
---|
1419 | }
|
---|
1420 | sd2->sdflags |= SD_LCK2; /* Lock up other end of stuff */
|
---|
1421 |
|
---|
1422 | /* SD and SD2 now delimit bounds of stuff to excise.
|
---|
1423 | * Now do direction dependent fixups
|
---|
1424 | */
|
---|
1425 | if(dirb)
|
---|
1426 | { /* Backward, current sbdot is ok but must get SD/SD2
|
---|
1427 | * into first/last order. Also, due to nature of block
|
---|
1428 | * splitups, a backward delete within single block will leave
|
---|
1429 | * SD actually pointing at predecessor block.
|
---|
1430 | */
|
---|
1431 | if(sd->slforw == sd2) /* If SD became pred, fix things. */
|
---|
1432 | { sd->sdflags &= ~SD_LCK2; /* Oops, unlock! */
|
---|
1433 | sd = sd2;
|
---|
1434 | }
|
---|
1435 | else /* Just need to swap SD, SD2 ptrs. */
|
---|
1436 | { /* Goddamit why doesn't C have an */
|
---|
1437 | /* exchange operator??? */
|
---|
1438 | *asd2 = sd;
|
---|
1439 | return(sd2);
|
---|
1440 | }
|
---|
1441 | }
|
---|
1442 | *asd2 = sd2;
|
---|
1443 | return(sd);
|
---|
1444 | }
|
---|
1445 | |
---|
1446 |
|
---|
1447 | /* SBX_SPLIT(sd,chroff) - Splits block SD at point CHROFF (offset from
|
---|
1448 | * start of block). SD remains valid; it is left locked.
|
---|
1449 | * The smblk is split too, if one exists, and SMUSE adjusted.
|
---|
1450 | * If offset 0, or equal to block length, the 1st or 2nd SD respectively
|
---|
1451 | * will not have a smblk and its sdlen will be 0.
|
---|
1452 | * (Note that if a smblk exists, a zero sdlen doesn't indicate much)
|
---|
1453 | */
|
---|
1454 | struct sdblk *
|
---|
1455 | sbx_split(sdp, coff)
|
---|
1456 | struct sdblk *sdp;
|
---|
1457 | chroff coff;
|
---|
1458 | { register struct sdblk *sd, *sdf, *sdx;
|
---|
1459 |
|
---|
1460 | if((sd=sdp) == 0)
|
---|
1461 | return((struct sdblk *)0);
|
---|
1462 | sd->sdflags |= SD_LOCK;
|
---|
1463 | if(sd->sdflags&SD_MOD) /* If block has been munged, */
|
---|
1464 | sbx_npdel(sd); /* Flush from phys list now. */
|
---|
1465 | sdf = sbx_ndget(); /* Get a sdblk node */
|
---|
1466 | bcopy((SBMA)sd, (SBMA)sdf, (sizeof (struct sdblk))); /* Copy node */
|
---|
1467 | /* Note that the flags are copied, so both sdblks are locked and
|
---|
1468 | * safe from possible GC compaction during call to sbx_msplit...
|
---|
1469 | */
|
---|
1470 | if(coff == 0) /* If offset was 0, */
|
---|
1471 | { /* then 1st SD becomes null */
|
---|
1472 | if(sdf->sdfile) /* Fix up phys links here */
|
---|
1473 | { if(sdx = sdf->sdback)
|
---|
1474 | sdx->sdforw = sdf;
|
---|
1475 | else sdf->sdfile->sfptr1 = sdf;
|
---|
1476 | if(sdx = sdf->sdforw)
|
---|
1477 | sdx->sdback = sdf;
|
---|
1478 | }
|
---|
1479 | sdx = sd;
|
---|
1480 | goto nulsdx;
|
---|
1481 | }
|
---|
1482 | else if(sd->sdmem)
|
---|
1483 | if(coff >= sd->sdmem->smuse)
|
---|
1484 | goto nulsdf;
|
---|
1485 | else sdf->sdmem = sbx_msplit(sd->sdmem, (SBMO)coff);
|
---|
1486 | else if(coff >= sd->sdlen)
|
---|
1487 | nulsdf: { sdx = sdf;
|
---|
1488 | nulsdx: sdx->sdforw = 0;
|
---|
1489 | sdx->sdback = 0;
|
---|
1490 | sdx->sdmem = 0;
|
---|
1491 | sdx->sdfile = 0;
|
---|
1492 | sdx->sdlen = 0;
|
---|
1493 | sdx->sdaddr = 0;
|
---|
1494 | goto nulskp;
|
---|
1495 | }
|
---|
1496 | if(sd->sdfile)
|
---|
1497 | { sdf->sdlen -= coff; /* Set size of remainder */
|
---|
1498 | sdf->sdaddr += coff; /* and address */
|
---|
1499 | sd->sdlen = coff; /* Set size of 1st part */
|
---|
1500 |
|
---|
1501 | /* Link 2nd block into proper place in physical sequence.
|
---|
1502 | * 1st block is already in right place. Search forward until
|
---|
1503 | * find a block with same or higher disk address, and insert
|
---|
1504 | * in front of it. If sdlen is zero, just flush the links,
|
---|
1505 | * which is OK since the 1st block is what's pointed to anyway.
|
---|
1506 | */
|
---|
1507 | if(sdf->sdlen > 0)
|
---|
1508 | { while((sdx = sd->sdforw) /* Find place to insert */
|
---|
1509 | && sdf->sdaddr > sdx->sdaddr)
|
---|
1510 | sd = sdx;
|
---|
1511 | sdf->sdback = sd; /* Link following sd. */
|
---|
1512 | if(sdf->sdforw = sd->sdforw)
|
---|
1513 | sdf->sdforw->sdback = sdf;
|
---|
1514 | sd->sdforw = sdf;
|
---|
1515 | sd = sdp; /* Restore pointer */
|
---|
1516 | }
|
---|
1517 | else
|
---|
1518 | { sdf->sdforw = 0;
|
---|
1519 | sdf->sdback = 0;
|
---|
1520 | sdf->sdfile = 0; /* Say no disk */
|
---|
1521 | }
|
---|
1522 | }
|
---|
1523 |
|
---|
1524 | nulskp: sdf->slback = sd; /* Link in logical sequence */
|
---|
1525 | if(sd->slforw)
|
---|
1526 | sd->slforw->slback = sdf;
|
---|
1527 | sd->slforw = sdf;
|
---|
1528 |
|
---|
1529 | sdf->sdflags &= ~SD_LOCKS; /* Unlock 2nd but not 1st */
|
---|
1530 | return(sd); /* Note sd, not sdf */
|
---|
1531 | }
|
---|
1532 |
|
---|
1533 | /* SBX_MSPLIT - Like sbm_split but never fails, and sets
|
---|
1534 | * SMUSE values appropriately
|
---|
1535 | */
|
---|
1536 | struct smblk *
|
---|
1537 | sbx_msplit(smp, size)
|
---|
1538 | struct smblk *smp;
|
---|
1539 | SBMO size;
|
---|
1540 | { register struct smblk *sm, *smx;
|
---|
1541 | register int lev;
|
---|
1542 |
|
---|
1543 | lev = 0;
|
---|
1544 | while((smx = sbm_split((sm = smp), size)) == 0)
|
---|
1545 | sbx_comp(SB_BUFSIZ,lev++); /* Need to get some smblk nodes */
|
---|
1546 | if(sm->smlen >= sm->smuse) /* Split across used portion? */
|
---|
1547 | smx->smuse = 0; /* Nope, new blk is all free */
|
---|
1548 | else
|
---|
1549 | { smx->smuse = sm->smuse - sm->smlen;
|
---|
1550 | sm->smuse = sm->smlen;
|
---|
1551 | }
|
---|
1552 | return(smx);
|
---|
1553 | }
|
---|
1554 | |
---|
1555 |
|
---|
1556 | /* SBX_NDEL - flush a SD and associated SM. Fixes up logical
|
---|
1557 | * and physical links properly. Returns ptr to next logical SD.
|
---|
1558 | * NOTE: if sd->slback does not exist, the returned SD is your
|
---|
1559 | * only hold on the list, since the SD gets flushed anyway!
|
---|
1560 | */
|
---|
1561 | struct sdblk *
|
---|
1562 | sbx_ndel(sdp)
|
---|
1563 | struct sdblk *sdp;
|
---|
1564 | { register struct sdblk *sd, *sdx;
|
---|
1565 | register struct smblk *sm;
|
---|
1566 |
|
---|
1567 | sd = sdp;
|
---|
1568 | if(sm = sd->sdmem) /* If smblk exists, */
|
---|
1569 | { sbm_mfree(sm); /* flush it. */
|
---|
1570 | sd->sdmem = 0;
|
---|
1571 | }
|
---|
1572 | if(sdx = sd->slback)
|
---|
1573 | sdx->slforw = sd->slforw;
|
---|
1574 | if(sd->slforw)
|
---|
1575 | sd->slforw->slback = sdx; /* May be zero */
|
---|
1576 |
|
---|
1577 | /* Logical links done, now hack phys links */
|
---|
1578 | if(sd->sdfile) /* Have phys links? */
|
---|
1579 | sbx_npdel(sd); /* Yes, flush from phys list */
|
---|
1580 |
|
---|
1581 | sdx = sd->slforw;
|
---|
1582 | sbx_ndfre(sd);
|
---|
1583 | return(sdx);
|
---|
1584 | }
|
---|
1585 |
|
---|
1586 | sbx_npdel(sdp)
|
---|
1587 | struct sdblk *sdp;
|
---|
1588 | { register struct sdblk *sd, *sdx;
|
---|
1589 | register struct sbfile *sf;
|
---|
1590 |
|
---|
1591 | if((sf = (sd=sdp)->sdfile) == 0)
|
---|
1592 | return;
|
---|
1593 | if(sdx = sd->sdback) /* Start of disk file? */
|
---|
1594 | sdx->sdforw = sd->sdforw;
|
---|
1595 | else
|
---|
1596 | sf->sfptr1 = sd->sdforw;
|
---|
1597 | if(sdx = sd->sdforw)
|
---|
1598 | sdx->sdback = sd->sdback;
|
---|
1599 | sd->sdfile = 0;
|
---|
1600 | sd->sdlen = 0;
|
---|
1601 | }
|
---|
1602 |
|
---|
1603 | |
---|
1604 |
|
---|
1605 | struct sdblk *sbx_nfl; /* Pointer to sdblk node freelist */
|
---|
1606 |
|
---|
1607 | struct sdblk *
|
---|
1608 | sbx_ndget() /* Like sbm_nget but never fails! */
|
---|
1609 | { register struct sdblk *sd;
|
---|
1610 | register int lev;
|
---|
1611 |
|
---|
1612 | lev = 0;
|
---|
1613 | while((sd = sbx_nfl) == 0 /* Get a node */
|
---|
1614 | /* If fail, make more */
|
---|
1615 | && (sd = sbm_nmak((sizeof (struct sdblk)),SM_DNODS)) == 0)
|
---|
1616 | /* If still fail, try GC */
|
---|
1617 | sbx_comp(sizeof(struct sdblk)*SM_DNODS,lev++);
|
---|
1618 |
|
---|
1619 | sbx_nfl = sd->slforw; /* Take it off freelist */
|
---|
1620 | sd->sdflags = SD_NID;
|
---|
1621 | return(sd); /* Return ptr to it */
|
---|
1622 | }
|
---|
1623 |
|
---|
1624 | sbx_ndfre(sdp)
|
---|
1625 | struct sdblk *sdp;
|
---|
1626 | { register struct sdblk *sd;
|
---|
1627 | (sd = sdp)->sdflags = 0;
|
---|
1628 | sd->slforw = sbx_nfl;
|
---|
1629 | sbx_nfl = sd;
|
---|
1630 | }
|
---|
1631 |
|
---|
1632 | SBMA
|
---|
1633 | sbx_malloc(size)
|
---|
1634 | unsigned size;
|
---|
1635 | {
|
---|
1636 | register int lev;
|
---|
1637 | register SBMA res;
|
---|
1638 |
|
---|
1639 | lev = 0;
|
---|
1640 | while((res = (SBMA)malloc(size)) == 0)
|
---|
1641 | sbx_comp(size,lev++);
|
---|
1642 | return(res);
|
---|
1643 | }
|
---|
1644 |
|
---|
1645 | struct smblk *
|
---|
1646 | sbx_mget(cmin,cmax) /* like sbm_mget but never fails! */
|
---|
1647 | SBMO cmin, cmax;
|
---|
1648 | { register struct smblk *sm;
|
---|
1649 | register int lev, csiz;
|
---|
1650 |
|
---|
1651 | lev = 0;
|
---|
1652 | csiz = cmax;
|
---|
1653 | for(;;)
|
---|
1654 | { if(sm = sbm_mget(csiz,cmax))
|
---|
1655 | return(sm); /* Won right off... */
|
---|
1656 | sbx_comp(csiz,lev++); /* Barf, invoke GC */
|
---|
1657 | if(sm = sbm_mget(csiz,cmax)) /* Then try again */
|
---|
1658 | return(sm);
|
---|
1659 | if((csiz >>= 1) < cmin) /* If still short, reduce */
|
---|
1660 | csiz = cmin; /* request down to min */
|
---|
1661 | }
|
---|
1662 | }
|
---|
1663 | |
---|
1664 |
|
---|
1665 | chroff sbv_taddr; /* Disk addr of place to write into (set by TSET) */
|
---|
1666 | struct sdblk *sbv_tsd; /* SD that disk addr comes after (set by TSET) */
|
---|
1667 |
|
---|
1668 | #define sbx_qlk(sd) (sd->sdflags&SD_LOCKS)
|
---|
1669 |
|
---|
1670 | #if 0
|
---|
1671 | This is the compaction routine, which is the key to the
|
---|
1672 | entire scheme. Paging text to and from disk is trivial, but the
|
---|
1673 | ability to merge blocks is the important thing since it allows
|
---|
1674 | flushing the pointer information as well as the actual text! This
|
---|
1675 | eliminates fragmentation as a fatal problem.
|
---|
1676 | There are a variety of ways that storage can be reclaimed:
|
---|
1677 |
|
---|
1678 | - "pure" in-core blocks can be flushed instantly.
|
---|
1679 | - "impure" incore blocks can be written to tempfile storage and flushed.
|
---|
1680 | - The SM node freelist can be compacted so as to flush memory which is
|
---|
1681 | used for nothing but holding free nodes.
|
---|
1682 | - The SD node freelist can be compacted, ditto.
|
---|
1683 | - SBBUFs can be compacted, by:
|
---|
1684 | - Merging logically & physically adjacent on-disk pieces
|
---|
1685 | - merging logically & physically adjacent in-core pieces
|
---|
1686 | - merging logically adjacent in-core pieces
|
---|
1687 | - merging logically adjacent disk pieces, by reading in
|
---|
1688 | and then writing out to tempfile storage.
|
---|
1689 | Worst case would reduce whole sbstr to single tempfile block.
|
---|
1690 |
|
---|
1691 | Problems:
|
---|
1692 | What is "optimal" algorithm for typical usage?
|
---|
1693 | Must go over all code to make sure right things get locked
|
---|
1694 | and unlocked to avoid having rug pulled out from under.
|
---|
1695 | Could have optional "registration table" for sbstruc; if exist
|
---|
1696 | in table, can check during GC. If find one, can first
|
---|
1697 | do sbx_smdisc and then repoint sbcur to 1st block,
|
---|
1698 | with sbdot of 0 and sboff of sb_tell(). This allows
|
---|
1699 | reducing whole thing to one block even tho "locked".
|
---|
1700 | Never touch stuff locked with SD_LCK2, though.
|
---|
1701 | Also may need way to protect the sbstr SD actually being
|
---|
1702 | pointed to by current sbx routine processing.
|
---|
1703 | Could have count of # nodes free for SM and SD; don''t GC
|
---|
1704 | unless # is some number greater than size of a node block!
|
---|
1705 | Have different levels of compaction; pass level # down thru calls
|
---|
1706 | so as to invoke progressively sterner compaction measures.
|
---|
1707 | Can invoke sbx_comp with any particular level!
|
---|
1708 | Must have list somewhere of SBBUFs? or maybe OK to scan core
|
---|
1709 | for SM_DNODS, then scan sdblks?
|
---|
1710 | Screw: could happen that stuff gets flushed (cuz pure) or even
|
---|
1711 | written out to tempfile, and then we have to read it back
|
---|
1712 | in so as to compact more stuff into tempfile... how to avoid?
|
---|
1713 | If pure stuff small and next to impure stuff, merge?
|
---|
1714 | Some calls just want to get another free node and don''t need
|
---|
1715 | new core. How to indicate this? How to decide between
|
---|
1716 | freeing up used nodes, and creating new node freelist?
|
---|
1717 | #endif /*COMMENT*/
|
---|
1718 | /* Compact stuff.
|
---|
1719 | * General algorithm for getting storage is:
|
---|
1720 | * 1) allocate from freelist if enough there
|
---|
1721 | * 2) find unlocked pure smblk to free up
|
---|
1722 | * 3) find unlocked impure smblks, write out.
|
---|
1723 | * 4) Compact stuff by reducing # of sdblks. This is key to scheme!
|
---|
1724 | * Otherwise fragmentation will kill program.
|
---|
1725 | * Maybe put age cnt in each sbstr? Bump global and set cntr each time
|
---|
1726 | * sbstr gets major hacking (not just getc/putc).
|
---|
1727 | */
|
---|
1728 | extern struct smblk *sbm_list;
|
---|
1729 | sbx_comp(cmin,lev)
|
---|
1730 | int cmin, lev;
|
---|
1731 | { int sbx_sdgc();
|
---|
1732 |
|
---|
1733 | if(lev > 100) /* If program has no way to handle this, */
|
---|
1734 | abort(); /* then simply blow up. */
|
---|
1735 | if(lev > 10) /* Too many iterations? Try to warn. */
|
---|
1736 | return(sbx_err(0,"GC loop, cannot free block of size %d",
|
---|
1737 | cmin));
|
---|
1738 |
|
---|
1739 | /* Step thru core hunting for SD node blocks */
|
---|
1740 | sbm_nfor(SM_DNODS,sizeof(struct sdblk),sbx_sdgc,lev);
|
---|
1741 | }
|
---|
1742 |
|
---|
1743 | /* Do GC stuff on a sdblk. Guaranteed to exist, but may be locked */
|
---|
1744 | sbx_sdgc(sdp,lev)
|
---|
1745 | struct sdblk *sdp;
|
---|
1746 | int lev;
|
---|
1747 | { register struct sdblk *sd, *sdf;
|
---|
1748 | register struct smblk *sm;
|
---|
1749 | struct smblk *smf, *sbm_exp ();
|
---|
1750 | SBMO more;
|
---|
1751 |
|
---|
1752 | sd = sdp;
|
---|
1753 | if(sbx_qlk(sd)) return(0);
|
---|
1754 | sm = sd->sdmem;
|
---|
1755 | sdf = sd->slforw;
|
---|
1756 | if (lev < 4) goto lev3;
|
---|
1757 |
|
---|
1758 | /* Level 4 - write out everything possible */
|
---|
1759 | /* Back up to start of sbstr */
|
---|
1760 | while((sdf = sd->slback) && !sbx_qlk(sdf))
|
---|
1761 | sd = sdf;
|
---|
1762 | if((sdf = sd->slforw) == 0 /* If only 1 blk, ensure on disk */
|
---|
1763 | || sbx_qlk(sdf))
|
---|
1764 | { if(sm = sd->sdmem)
|
---|
1765 | { if(sd->sdflags&SD_MOD) /* If impure, */
|
---|
1766 | sbx_aout(sd, 1); /* swap out the SD */
|
---|
1767 | sbm_mfree(sm);
|
---|
1768 | sd->sdmem = 0;
|
---|
1769 | }
|
---|
1770 | return(0);
|
---|
1771 | }
|
---|
1772 | /* At least two blocks in string. Set up for flushout. */
|
---|
1773 | sbx_aout(sd, 0); /* Swapout as much of sbstring as possible */
|
---|
1774 | return(0);
|
---|
1775 |
|
---|
1776 | lev3: /* Level 3 - write out more */
|
---|
1777 | lev2: /* Level 2 - write out all impure & small pure */
|
---|
1778 | lev1: if(lev >= 1) /* Level 1 - merge small impure & small pure */
|
---|
1779 | { if(!sm || !sdf) return(0);
|
---|
1780 | while(((smf = sdf->sdmem) && !(sdf->sdflags&SD_LOCKS)
|
---|
1781 | && (more = smf->smuse + sm->smuse) < SB_BUFSIZ) )
|
---|
1782 | { if(sm->smforw != smf
|
---|
1783 | && more > sm->smlen) /* If need more rm */
|
---|
1784 | { sm = sbm_exp(sm,more); /* Get it */
|
---|
1785 | if(!sm) return(0); /* If none, stop */
|
---|
1786 | sd->sdmem = sm;
|
---|
1787 | }
|
---|
1788 | bcopy(smf->smaddr,
|
---|
1789 | sm->smaddr + sm->smuse, smf->smuse);
|
---|
1790 | sm->smuse = more;
|
---|
1791 | if(sm->smforw == smf)
|
---|
1792 | { sdf->sdmem = 0;
|
---|
1793 | sbm_mmrg(sm); /* Merge */
|
---|
1794 | if(sm->smlen > more+SB_SLOP)
|
---|
1795 | sbm_mfree(sbm_split(sm, more));
|
---|
1796 | /* Guaranteed to win since mmrg
|
---|
1797 | * just freed a mem node */
|
---|
1798 | }
|
---|
1799 | sd->sdflags |= SD_MOD;
|
---|
1800 | if(sdf = sbx_ndel(sdf))
|
---|
1801 | continue;
|
---|
1802 | return(0);
|
---|
1803 | }
|
---|
1804 | }
|
---|
1805 |
|
---|
1806 | if(lev <= 0) /* Level 0 - free up large pure blocks */
|
---|
1807 | /* Also merge blocks which are adjacent on disk */
|
---|
1808 | { if(sm)
|
---|
1809 | { if(sm->smuse == 0)
|
---|
1810 | sd->sdlen = 0;
|
---|
1811 | else if((sd->sdflags&SD_MOD) == 0
|
---|
1812 | && sm->smuse > 64)
|
---|
1813 | { sbm_mfree(sm);
|
---|
1814 | sd->sdmem = 0;
|
---|
1815 | goto lev0adj;
|
---|
1816 | }
|
---|
1817 | else goto lev0adj;
|
---|
1818 | }
|
---|
1819 |
|
---|
1820 | if(sd->sdlen == 0 /* Free zero blocks */
|
---|
1821 | && sd->slback) /* Make sure don't lose list */
|
---|
1822 | { sbx_ndel(sd);
|
---|
1823 | if((sd = sdf) == 0)
|
---|
1824 | return(0);
|
---|
1825 | sdf = sd->slforw;
|
---|
1826 | }
|
---|
1827 | lev0adj: /* Merge blocks if adjacent on disk */
|
---|
1828 | /* This is common after reading thru large chunks
|
---|
1829 | * of a file but not modifying it much.
|
---|
1830 | */
|
---|
1831 | if((sd->sdflags&SD_MOD) == 0 /* Pure */
|
---|
1832 | && sdf && (sdf->sdflags&(SD_LOCKS|SD_MOD)) == 0
|
---|
1833 | && sd->sdfile && (sd->sdfile == sdf->sdfile)
|
---|
1834 | && (sd->sdaddr + sd->sdlen) == sdf->sdaddr )
|
---|
1835 | { sd->sdlen += sdf->sdlen;
|
---|
1836 | sbx_ndel(sdf); /* Flush 2nd */
|
---|
1837 | if(sm = sd->sdmem)
|
---|
1838 | { sbm_mfree(sm);
|
---|
1839 | sd->sdmem = 0;
|
---|
1840 | }
|
---|
1841 | }
|
---|
1842 | return(0);
|
---|
1843 | }
|
---|
1844 | return(0);
|
---|
1845 | }
|
---|
1846 | |
---|
1847 |
|
---|
1848 | /* SBX_AOUT - output ALL of a hackable sbstring starting at given sdblk.
|
---|
1849 | * Note that code is careful to do things so that an abort at any
|
---|
1850 | * time (e.g. write error) will still leave sbstring in valid state.
|
---|
1851 | * Flag value:
|
---|
1852 | * 0 - Writes out as many unlocked sdblks as possible, and merges
|
---|
1853 | * so that resulting sdblk (same one pointed to by arg)
|
---|
1854 | * incorporates all stuff written out.
|
---|
1855 | * 1 - Writes out single sdblk indicated, whether unlocked or not.
|
---|
1856 | * Doesn't free mem or merge anything; does update physlist
|
---|
1857 | * and flags.
|
---|
1858 | * 2 - Writes out all sdblks to specified FD/offset, no mods at all,
|
---|
1859 | * not even to physlist or flags. Good for saving files
|
---|
1860 | * when something seems wrong. (How to pass fd/off args?)
|
---|
1861 | * (offset arg not implemented, no need yet; 0 assumed)
|
---|
1862 | * Returns 0 if successful, else UNIX system call error number.
|
---|
1863 | */
|
---|
1864 |
|
---|
1865 | sbx_aout(sdp,flag,fd)
|
---|
1866 | struct sdblk *sdp;
|
---|
1867 | int flag, fd;
|
---|
1868 | { register struct sdblk *sd;
|
---|
1869 | register struct smblk *sm;
|
---|
1870 | register int cnt;
|
---|
1871 | int ifd, ofd, skflg, rem;
|
---|
1872 | chroff inlen;
|
---|
1873 | extern SBMA sbm_lowaddr; /* Need this from SBM for rndrem */
|
---|
1874 | char buf[SB_BUFSIZ+16]; /* Get buffer space from stack! */
|
---|
1875 | /* Allow extra for word-align reads. */
|
---|
1876 | /* This should be +WDSIZE, but some */
|
---|
1877 | /* C compilers (eg XENIX) can't handle */
|
---|
1878 | /* "sizeof" arith in allocation stmts! */
|
---|
1879 |
|
---|
1880 | /* This flag and the two ptrs below are needed because UNIX
|
---|
1881 | * maintains only one I/O ptr per open file, and we can sometimes
|
---|
1882 | * be reading from/writing to the swapout file at same time.
|
---|
1883 | * Using DUP() to get a new FD (to avoid seeking back and forth)
|
---|
1884 | * won't help since both FD's will use the same I/O ptr!!!
|
---|
1885 | * Lastly, can't depend on returned value of LSEEK to push/pop
|
---|
1886 | * ptr, since V6 systems don't implement tell() or lseek() directly.
|
---|
1887 | * So we have to do it by hand...
|
---|
1888 | */
|
---|
1889 | int botchflg;
|
---|
1890 | chroff outptr, inptr;
|
---|
1891 |
|
---|
1892 | if((sd = sdp)==0) return;
|
---|
1893 | ofd = sbv_tf.sffd; /* Default output FD */
|
---|
1894 | if(flag==0)
|
---|
1895 | { sbx_tset(sbx_qlen(sd),0);/* Find place for whole string */
|
---|
1896 | outptr = sbv_taddr; /* We'll have to update wrt ptr */
|
---|
1897 | }
|
---|
1898 | else if (flag==1) /* Single SD block, so it's reasonable to
|
---|
1899 | * try aligning the output with the input. */
|
---|
1900 | { if(sm = sd->sdmem)
|
---|
1901 | { cnt = rndrem(sm->smaddr - sbm_lowaddr);
|
---|
1902 | sbx_tset((chroff)(sm->smuse),cnt);
|
---|
1903 | }
|
---|
1904 | else
|
---|
1905 | { cnt = rndrem(sd->sdaddr);
|
---|
1906 | sbx_tset(sd->sdlen, cnt);
|
---|
1907 | }
|
---|
1908 | outptr = sbv_taddr; /* We'll have to update wrt ptr */
|
---|
1909 | }
|
---|
1910 | else /* Outputting a whole sbstring to a file */
|
---|
1911 | { ofd = fd;
|
---|
1912 | outptr = 0;
|
---|
1913 | }
|
---|
1914 |
|
---|
1915 | for(; sd;)
|
---|
1916 | { if(flag==0 && sbx_qlk(sd))
|
---|
1917 | break; /* Stop when hit locked sdblk */
|
---|
1918 | if(sm = sd->sdmem)
|
---|
1919 | { if(cnt = sm->smuse)
|
---|
1920 | if(write(ofd, sm->smaddr, cnt) != cnt)
|
---|
1921 | return(sbx_err(errno,"Swapout wrt err"));
|
---|
1922 | outptr += cnt;
|
---|
1923 | if(flag==0)
|
---|
1924 | { sd->sdmem = 0; /* Flush the mem used */
|
---|
1925 | sbm_mfree(sm);
|
---|
1926 | }
|
---|
1927 | inlen = cnt;
|
---|
1928 | }
|
---|
1929 | else if(inlen = sd->sdlen)
|
---|
1930 | { if(sd->sdfile == 0)
|
---|
1931 | return(sbx_err(errno,"Sdfile 0, SD %o",sd));
|
---|
1932 | /* Foo on UNIX */
|
---|
1933 | botchflg = ((ifd = sd->sdfile->sffd) == ofd) ? 1 : 0;
|
---|
1934 | skflg = 1; /* Always seek first time */
|
---|
1935 | inptr = sd->sdaddr;
|
---|
1936 | /* Efficiency hack - set up for first read so that
|
---|
1937 | * transfer is word-aligned and terminates at end
|
---|
1938 | * of a disk block.
|
---|
1939 | */
|
---|
1940 | rem = rndrem(inptr); /* Get alignment */
|
---|
1941 | cnt = SB_BUFSIZ - (int)(inptr%SB_BUFSIZ);
|
---|
1942 | while(inlen > 0)
|
---|
1943 | {
|
---|
1944 | if(inlen < cnt) cnt = inlen;
|
---|
1945 | if(!sbx_rdf(ifd, buf+rem, cnt, skflg, inptr))
|
---|
1946 | return(sbx_err(errno,"Swapout err, SD %o",sd));
|
---|
1947 | /* Further seeks depend on botch setting */
|
---|
1948 | if(skflg = botchflg)
|
---|
1949 | { if(lseek(ofd,outptr,0) < 0)
|
---|
1950 | return(sbx_err(errno,
|
---|
1951 | "Swapout sk err"));
|
---|
1952 | inptr += cnt;
|
---|
1953 | }
|
---|
1954 | if(write(ofd, buf+rem, cnt) != cnt)
|
---|
1955 | return(sbx_err(errno,
|
---|
1956 | "Swapout wrt err"));
|
---|
1957 | outptr += cnt;
|
---|
1958 | inlen -= cnt;
|
---|
1959 | cnt = SB_BUFSIZ; /* Now can use full blocks */
|
---|
1960 | rem = 0; /* Aligned nicely, too! */
|
---|
1961 | }
|
---|
1962 | inlen = sd->sdlen;
|
---|
1963 | }
|
---|
1964 |
|
---|
1965 | /* Text written out, now merge block in */
|
---|
1966 | if(flag == 2) /* No merge if saving file */
|
---|
1967 | goto donxt;
|
---|
1968 | if(sd != sdp) /* First block? */
|
---|
1969 | { sdp->sdlen += inlen; /* No, simple merge */
|
---|
1970 | sd = sbx_ndel(sd); /* Flush, get next */
|
---|
1971 | continue;
|
---|
1972 | }
|
---|
1973 |
|
---|
1974 | /* Handle 1st block specially */
|
---|
1975 | if(sd->sdfile /* Unlink from phys list */
|
---|
1976 | && sd != sbv_tsd) /* Don't unlink if self */
|
---|
1977 | sbx_npdel(sd);
|
---|
1978 | sd->sdlen = inlen;
|
---|
1979 | sd->sdfile = &sbv_tf;
|
---|
1980 | sd->sdaddr = sbv_taddr; /* Set from sbx_tset val */
|
---|
1981 | sd->sdflags &= ~SD_MOD; /* On disk, no longer modified */
|
---|
1982 |
|
---|
1983 | /* Now insert into phys list at specified place */
|
---|
1984 | if(sd == sbv_tsd) /* If already same place */
|
---|
1985 | goto next; /* Skip linkin. */
|
---|
1986 | if(sd->sdback = sbv_tsd)
|
---|
1987 | { sd->sdforw = sbv_tsd->sdforw;
|
---|
1988 | sd->sdback->sdforw = sd;
|
---|
1989 | }
|
---|
1990 | else
|
---|
1991 | { sd->sdforw = sbv_tf.sfptr1;
|
---|
1992 | sbv_tf.sfptr1 = sd;
|
---|
1993 | }
|
---|
1994 | if(sd->sdforw)
|
---|
1995 | sd->sdforw->sdback = sd;
|
---|
1996 |
|
---|
1997 | next: if(flag==1) /* If only doing 1 sdblk, */
|
---|
1998 | break; /* stop here. */
|
---|
1999 | donxt: sd = sd->slforw; /* Done with 1st, get next */
|
---|
2000 | }
|
---|
2001 | return(0); /* Win return, no errors */
|
---|
2002 | }
|
---|
2003 |
|
---|
2004 | /* Returns hackable length of a sbstring (ends at EOF or locked block) */
|
---|
2005 | chroff
|
---|
2006 | sbx_qlen(sdp)
|
---|
2007 | struct sdblk *sdp;
|
---|
2008 | { register struct sdblk *sd;
|
---|
2009 | register struct smblk *sm;
|
---|
2010 | chroff len;
|
---|
2011 |
|
---|
2012 | len = 0;
|
---|
2013 | for(sd = sdp; sd && !sbx_qlk(sd); sd = sd->slforw)
|
---|
2014 | if(sm = sd->sdmem)
|
---|
2015 | len += (chroff)sm->smuse;
|
---|
2016 | else len += sd->sdlen;
|
---|
2017 | return(len);
|
---|
2018 | }
|
---|
2019 |
|
---|
2020 | |
---|
2021 |
|
---|
2022 | /* SBX_TSET - finds a place on temp swapout file big enough to hold
|
---|
2023 | * given # of chars. Sets SBV_TADDR to that location, as well
|
---|
2024 | * as seeking to it so the next write call will output there.
|
---|
2025 | * This location is guaranteed to have the requested
|
---|
2026 | * byte alignment (0 = word-aligned).
|
---|
2027 | */
|
---|
2028 | sbx_tset(loff, align)
|
---|
2029 | chroff loff;
|
---|
2030 | int align;
|
---|
2031 | { register int fd;
|
---|
2032 |
|
---|
2033 | if(sbv_tf.sffd <= 0)
|
---|
2034 | { /* Must open the temp file! */
|
---|
2035 | /* Temporary file mechanism is system-dependent. Eventually this
|
---|
2036 | ** will probably require inclusion of a true c-env header file; for the
|
---|
2037 | ** time being, we can cheat a little by checking O_T20_WILD, which will
|
---|
2038 | ** be defined by <sys/file.h> on TOPS-20. Otherwise, we assume we are
|
---|
2039 | ** on a real Unix.
|
---|
2040 | */
|
---|
2041 | #ifdef O_T20_WILD
|
---|
2042 | extern char *tmpnam(); /* Use ANSI function */
|
---|
2043 | fd = open(tmpnam((char *)NULL),
|
---|
2044 | O_RDWR | O_CREAT | O_TRUNC | O_BINARY);
|
---|
2045 | if(fd < 0)
|
---|
2046 | return(sbx_err(0,"Swapout creat err"));
|
---|
2047 | #else /* Real Unix */
|
---|
2048 | static char fcp[] = "/tmp/sbd.XXXXXX";
|
---|
2049 | if((fd = creat(mktemp(fcp),0600)) < 0)
|
---|
2050 | return(sbx_err(0,"Swapout creat err"));
|
---|
2051 | /* Must re-open so that we can both read and write to it */
|
---|
2052 | close(fd);
|
---|
2053 | if((fd = open(fcp,2)) < 0)
|
---|
2054 | return(sbx_err(0,"Swapout open err"));
|
---|
2055 | unlink(fcp); /* Set so it vanishes when we do */
|
---|
2056 | #endif
|
---|
2057 |
|
---|
2058 | sbv_tf.sffd = fd; /* Initialize the sbfile struct */
|
---|
2059 | sbv_tf.sfptr1 = 0;
|
---|
2060 | sbv_ftab[fd] = &sbv_tf; /* Record in table of all sbfiles */
|
---|
2061 | sbv_taddr = 0; /* "Return" this value */
|
---|
2062 | return; /* Ignore alignment for now */
|
---|
2063 | }
|
---|
2064 | sbv_tsd = sbx_ffnd(&sbv_tf, loff+align, &sbv_taddr);
|
---|
2065 | sbv_taddr += align;
|
---|
2066 | if(lseek(sbv_tf.sffd, sbv_taddr, 0) < 0)
|
---|
2067 | return(sbx_err(0,"Swapout seek err: (%d,%ld,0) %d %s",
|
---|
2068 | sbv_tf.sffd, sbv_taddr, errno, strerror(errno)));
|
---|
2069 |
|
---|
2070 | }
|
---|
2071 |
|
---|
2072 | /* SBX_FFND - searches disk list of given file for free space of
|
---|
2073 | * at least size chars. Note that list must be sorted by ascending
|
---|
2074 | * disk addrs in order for this to work! If sdaddrs are only
|
---|
2075 | * changed in SBX_SPLIT this will be true.
|
---|
2076 | * Sets "aloc" to disk address for writing (this is guaranteed to
|
---|
2077 | * be word-aligned, for efficiency), and returns SD ptr to
|
---|
2078 | * block which this addr should follow in the physical list. If ptr
|
---|
2079 | * is 0, it means addr should be 1st thing in list.
|
---|
2080 | */
|
---|
2081 | struct sdblk *
|
---|
2082 | sbx_ffnd(sfp, size, aloc)
|
---|
2083 | SBFILE *sfp;
|
---|
2084 | chroff size, *aloc;
|
---|
2085 | { register struct sdblk *sd, *sds, *sdl;
|
---|
2086 | chroff cur;
|
---|
2087 |
|
---|
2088 | cur = 0;
|
---|
2089 | sds = 0;
|
---|
2090 | sd = sfp->sfptr1;
|
---|
2091 | redo: for(; sd ; sd = (sds=sd)->sdforw)
|
---|
2092 | { if(cur < sd->sdaddr) /* Gap seen? */
|
---|
2093 | { if(size <= (sd->sdaddr - cur)) /* Yes, big enuf? */
|
---|
2094 | break; /* Yup! */
|
---|
2095 | } /* No, bump. */
|
---|
2096 | else if(cur >=(sd->sdaddr + sd->sdlen)) /* No gap but chk */
|
---|
2097 | continue; /* No overlap, ok */
|
---|
2098 | /* Bump to next possible gap. */
|
---|
2099 | cur = sd->sdaddr + sd->sdlen;
|
---|
2100 | cur = (long)rndup(cur); /* Round up to word boundary! */
|
---|
2101 | }
|
---|
2102 | *aloc = cur; /* Return winning addr */
|
---|
2103 |
|
---|
2104 | /* Perform verification check -- make sure this really is OK
|
---|
2105 | * and complain if not. If this never blows up, eventually can
|
---|
2106 | * take the check out.
|
---|
2107 | */
|
---|
2108 | sdl = sd;
|
---|
2109 | for(sd = sfp->sfptr1; sd; sd = sd->sdforw)
|
---|
2110 | { if(cur < sd->sdaddr)
|
---|
2111 | { if(size <= (sd->sdaddr - cur))
|
---|
2112 | continue;
|
---|
2113 | }
|
---|
2114 | else if(cur >= (sd->sdaddr + sd->sdlen))
|
---|
2115 | continue;
|
---|
2116 |
|
---|
2117 | sbx_err(0,"FFND blew it, but recovered. SD %o siz %ld",
|
---|
2118 | sd, size);
|
---|
2119 | sd = (sds = sdl)->sdforw;
|
---|
2120 | goto redo;
|
---|
2121 | }
|
---|
2122 |
|
---|
2123 |
|
---|
2124 | return(sds); /* Return ptr to block this addr follows */
|
---|
2125 | }
|
---|
2126 |
|
---|
2127 | sbx_rdf(fd,addr,cnt,skflg,loc)
|
---|
2128 | register int fd;
|
---|
2129 | char *addr;
|
---|
2130 | int skflg;
|
---|
2131 | chroff loc;
|
---|
2132 | { register int rres, eres;
|
---|
2133 | long lres;
|
---|
2134 | char *errtyp, *ftyp;
|
---|
2135 | chroff curlen;
|
---|
2136 |
|
---|
2137 | errno = 0;
|
---|
2138 | if(skflg && (lres = lseek(fd, (long)loc, 0)) == -1)
|
---|
2139 | { errtyp = "Sk err";
|
---|
2140 | goto errhan;
|
---|
2141 | }
|
---|
2142 | if((rres = read(fd, addr, cnt)) != cnt)
|
---|
2143 | { lres = rres;
|
---|
2144 | errtyp = "Rd err";
|
---|
2145 | goto errhan;
|
---|
2146 | }
|
---|
2147 | return(rres);
|
---|
2148 | errhan: /* Handle read or seek error */
|
---|
2149 | eres = errno;
|
---|
2150 | if(fd == sbv_tf.sffd) /* See if dealing with swapout file */
|
---|
2151 | { ftyp = "(swap)";
|
---|
2152 | curlen = 0;
|
---|
2153 | }
|
---|
2154 | else { /* No, normal buffer file. */
|
---|
2155 | ftyp = "";
|
---|
2156 | curlen = sbx_fdlen(fd);
|
---|
2157 | if(sbv_ftab[fd] &&
|
---|
2158 | (curlen != sbv_ftab[fd]->sflen)) /* File changed? */
|
---|
2159 | if(sbx_rugpull(fd)) /* Yes, handle special case */
|
---|
2160 | return(cnt); /* Allow "win" return */
|
---|
2161 | }
|
---|
2162 | sbx_err(0,"%s %d:%s, %ld:(%d%s,%o,%d)=%ld (fl %ld)",
|
---|
2163 | errtyp, eres, strerror(eres),
|
---|
2164 | loc, fd, ftyp, addr, cnt, lres,
|
---|
2165 | curlen);
|
---|
2166 | return(0);
|
---|
2167 | }
|
---|
2168 |
|
---|
2169 | /* SBX_RUGPULL(fd) - Special routine called when package detects that
|
---|
2170 | * the file indicated by the fd has changed since its original
|
---|
2171 | * opening. This can happen when a file is over-written by some
|
---|
2172 | * other program (ED, for example).
|
---|
2173 | * This means that all sdblks which reference this fd
|
---|
2174 | * are probably bad. Pass special error back up to the calling
|
---|
2175 | * program to give it a chance at doing something.
|
---|
2176 | * Extra credit: scan all sdblks and unpurify all which point to this
|
---|
2177 | * file, so as to protect everything we still remember about it.
|
---|
2178 | * Otherwise a GC could flush pure in-core portions.
|
---|
2179 | */
|
---|
2180 | sbx_rugpull(fd) /* FD already known to have entry in sbv_ftab */
|
---|
2181 | register int fd;
|
---|
2182 | { int sbx_unpur();
|
---|
2183 |
|
---|
2184 | /* First scan all sdblks to save what we still have. */
|
---|
2185 | /* This does NOT remove the sdfile pointer, so we can still
|
---|
2186 | * find blocks that are affected. */
|
---|
2187 | sbm_nfor(SM_DNODS, sizeof(struct sdblk), sbx_unpur, sbv_ftab[fd]);
|
---|
2188 |
|
---|
2189 | if((int)sbv_debug == 1 || !sbv_debug)
|
---|
2190 | return(0); /* Nothing else we can do */
|
---|
2191 | return((*sbv_debug)(2,(int *)0,"",fd)); /* Let caller handle it */
|
---|
2192 | }
|
---|
2193 | sbx_unpur(sd, sf) /* Auxiliary routine for SBX_RUGPULL */
|
---|
2194 | register struct sdblk *sd;
|
---|
2195 | register struct sbfile *sf;
|
---|
2196 | { if(sd->sdfile == sf /* If sdblk belongs to affected file */
|
---|
2197 | && sd->sdmem) /* and has in-core version of text, */
|
---|
2198 | sd->sdflags |= SD_MOD; /* then ensure core version is used */
|
---|
2199 | }
|
---|
2200 |
|
---|
2201 | sbx_err(val,str,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)
|
---|
2202 | char *str;
|
---|
2203 | { int *sptr;
|
---|
2204 |
|
---|
2205 | sptr = (int *) &sptr; /* Point to self on stack */
|
---|
2206 | sptr += 5; /* Point to return addr */
|
---|
2207 | if((int)sbv_debug == 1)
|
---|
2208 | { abort();
|
---|
2209 | }
|
---|
2210 | if(sbv_debug)
|
---|
2211 | (*sbv_debug)(1,*sptr,str,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12);
|
---|
2212 | return(val);
|
---|
2213 | }
|
---|