[9] | 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 | }
|
---|