1 /*
2 "Disk-Video" (and RAM-Video and Expanded-Memory Video) routines
3
4 Reworked with fast caching July '90 by Pieter Branderhorst.
5 (I'm proud of this cache handler, had to get my name on it!)
6 Caution when modifying any code in here: bugs are possible which
7 slow the cache substantially but don't cause incorrect results.
8 Do timing tests for a variety of situations after any change.
9
10 */
11
12 #include <string.h>
13
14 /* see Fractint.c for a description of the "include" hierarchy */
15 #include "port.h"
16 #include "prototyp.h"
17
18 #define BOXROW 6
19 #define BOXCOL 11
20 #define BOXWIDTH 57
21 #define BOXDEPTH 12
22
23 int disk16bit = 0; /* storing 16 bit values for continuous potential */
24
25 static int timetodisplay;
26 static FILE *fp = NULL;
27 int disktarga;
28
29 #define BLOCKLEN 2048 /* must be a power of 2, must match next */
30 #define BLOCKSHIFT 11 /* must match above */
31 #define CACHEMIN 4 /* minimum cache size in Kbytes */
32 #define CACHEMAX 64 /* maximum cache size in Kbytes */
33 #define FREEMEM 33 /* try to leave this much far memory unallocated */
34 #define HASHSIZE 1024 /* power of 2, near CACHEMAX/(BLOCKLEN+8) */
35
36 static struct cache { /* structure of each cache entry */
37 long offset; /* pixel offset in image */
38 BYTE pixel[BLOCKLEN]; /* one pixel per byte (this *is* faster) */
39 unsigned int hashlink; /* ptr to next cache entry with same hash */
40 unsigned int dirty : 1; /* changed since read? */
41 unsigned int lru : 1; /* recently used? */
42 } far *cache_end, far *cache_lru, far *cur_cache;
43
44 struct cache far *cache_start = NULL;
45 long high_offset; /* highwater mark of writes */
46 long seek_offset; /* what we'll get next if we don't seek */
47 long cur_offset; /* offset of last block referenced */
48 int cur_row;
49 long cur_row_base;
50 unsigned int far *hash_ptr = NULL;
51 int pixelshift;
52 int headerlength;
53 unsigned int rowsize = 0; /* doubles as a disk video not ok flag */
54 unsigned int colsize; /* sydots, *2 when pot16bit */
55
56 BYTE far *membuf;
57 U16 dv_handle = 0;
58 long memoffset = 0;
59 long oldmemoffset = 0;
60 BYTE far *membufptr;
61
62 static void _fastcall near findload_cache(long);
63 static struct cache far * _fastcall near find_cache(long);
64 static void near write_cache_lru(void);
65 static void _fastcall near mem_putc(BYTE);
66 static BYTE near mem_getc(void);
67 static void _fastcall near mem_seek(long);
68
startdisk()69 int startdisk()
70 {
71 if (!diskisactive)
72 return(0);
73 headerlength = disktarga = 0;
74 return (common_startdisk(sxdots,sydots,colors));
75 }
76
pot_startdisk()77 int pot_startdisk()
78 {
79 int i;
80 if (dotmode == 11) /* ditch the original disk file */
81 enddisk();
82 else
83 {
84 static FCODE msg[] = {"clearing 16bit pot work area"};
85 showtempmsg(msg);
86 }
87 headerlength = disktarga = 0;
88 i = common_startdisk(sxdots,sydots<<1,colors);
89 cleartempmsg();
90 if (i == 0)
91 disk16bit = 1;
92 return (i);
93 }
94
targa_startdisk(FILE * targafp,int overhead)95 int targa_startdisk(FILE *targafp,int overhead)
96 {
97 int i;
98 if (dotmode == 11) { /* ditch the original disk file, make just the targa */
99 enddisk(); /* close the 'screen' */
100 setnullvideo(); /* set readdot and writedot routines to do nothing */
101 }
102 headerlength = overhead;
103 fp = targafp;
104 disktarga = 1;
105 /*
106 i = common_startdisk(sxdots*3,sydots,colors);
107 */
108 i = common_startdisk(xdots*3,ydots,colors);
109 high_offset = 100000000L; /* targa not necessarily init'd to zeros */
110 return (i);
111 }
112
common_startdisk(long newrowsize,long newcolsize,int colors)113 int _fastcall common_startdisk(long newrowsize, long newcolsize, int colors)
114 {
115 int i,freemem;
116 long memorysize, offset;
117 unsigned int far *fwd_link = NULL;
118 struct cache far *ptr1 = NULL;
119 long longtmp;
120 unsigned int cache_size;
121 BYTE far *tempfar = NULL;
122 char *savenameptr;
123
124 if (diskflag)
125 enddisk();
126 if (dotmode == 11) { /* otherwise, real screen also in use, don't hit it */
127 char buf[50];
128 static FCODE fmsg1[] = {"'Disk-Video' mode"};
129 static FCODE fmsg2[] = {"Screen resolution: "};
130 static FCODE fsname[] = {"Save name: "};
131 static FCODE stat[] = {"Status:"};
132 helptitle();
133 setattr(1,0,C_DVID_BKGRD,24*80); /* init rest to background */
134 for (i = 0; i < BOXDEPTH; ++i)
135 setattr(BOXROW+i,BOXCOL,C_DVID_LO,BOXWIDTH); /* init box */
136 putstring(BOXROW+2,BOXCOL+4,C_DVID_HI,fmsg1);
137 putstring(BOXROW+4,BOXCOL+4,C_DVID_LO,fmsg2);
138 sprintf(buf,"%d x %d",sxdots,sydots);
139 putstring(-1,-1,C_DVID_LO,buf);
140 if (disktarga) {
141 static FCODE tarmsg[] = {" 24 bit Targa"};
142 putstring(-1,-1,C_DVID_LO,tarmsg);
143 }
144 else {
145 static FCODE clrmsg[] = {" Colors: "};
146 putstring(-1,-1,C_DVID_LO,clrmsg);
147 sprintf(buf,"%d",colors);
148 putstring(-1,-1,C_DVID_LO,buf);
149 }
150 putstring(BOXROW+6,BOXCOL+4,C_DVID_LO,fsname);
151 savenameptr = strrchr(savename, SLASHC); /* check for full path */
152 if(savenameptr == NULL)
153 savenameptr = savename;
154 else
155 savenameptr++; /* point past slash */
156 sprintf(buf,"%s",savenameptr);
157 putstring(-1,-1,C_DVID_LO,buf);
158 putstring(BOXROW+10,BOXCOL+4,C_DVID_LO,stat);
159 {
160 static FCODE o_msg[] = {"clearing the 'screen'"};
161 char msg[sizeof(o_msg)];
162 far_strcpy(msg,o_msg);
163 dvid_status(0,msg);
164 }
165 }
166 cur_offset = seek_offset = high_offset = -1;
167 cur_row = -1;
168 if (disktarga)
169 pixelshift = 0;
170 else {
171 pixelshift = 3;
172 i = 2;
173 while (i < colors) {
174 i *= i;
175 --pixelshift;
176 }
177 }
178 if(bf_math)
179 timetodisplay = 10; /* time-to-display-status counter */
180 else
181 timetodisplay = 1000; /* time-to-display-status counter */
182
183 /* allocate cache: try for the max; leave FREEMEMk free if we can get
184 that much or more; if we can't get that much leave 1/2 of whatever
185 there is free; demand a certain minimum or nogo at all */
186 freemem = FREEMEM;
187
188 for (cache_size = CACHEMAX; cache_size >= CACHEMIN; --cache_size) {
189 longtmp = ((int)cache_size < freemem) ? (long)cache_size << 11
190 : (long)(cache_size+freemem) << 10;
191 if ((tempfar = farmemalloc(longtmp)) != NULL) {
192 farmemfree(tempfar);
193 break;
194 }
195 }
196 if(debugflag==4200) cache_size = CACHEMIN;
197 longtmp = (long)cache_size << 10;
198 cache_start = (struct cache far *)farmemalloc(longtmp);
199 if (cache_size == 64)
200 --longtmp; /* safety for next line */
201 cache_end = (cache_lru = cache_start) + longtmp / sizeof(*cache_start);
202 hash_ptr = (unsigned int far *)farmemalloc((long)(HASHSIZE<<1));
203 membuf = (BYTE far *)farmemalloc((long)BLOCKLEN);
204 if (cache_start == NULL || hash_ptr == NULL || membuf == NULL) {
205 static FCODE msg[]={"*** insufficient free memory for cache buffers ***"};
206 stopmsg(0,msg);
207 return(-1);
208 }
209 if (dotmode == 11) {
210 char buf[50];
211 sprintf(buf,"Cache size: %dK\n\n",cache_size);
212 putstring(BOXROW+8,BOXCOL+4,C_DVID_LO,buf);
213 }
214
215 /* preset cache to all invalid entries so we don't need free list logic */
216 for (i = 0; i < HASHSIZE; ++i)
217 hash_ptr[i] = 0xffff; /* 0xffff marks the end of a hash chain */
218 longtmp = 100000000L;
219 for (ptr1 = cache_start; ptr1 < cache_end; ++ptr1) {
220 ptr1->dirty = ptr1->lru = 0;
221 fwd_link = hash_ptr
222 + (((unsigned short)(longtmp+=BLOCKLEN) >> BLOCKSHIFT) & (HASHSIZE-1));
223 ptr1->offset = longtmp;
224 ptr1->hashlink = *fwd_link;
225 *fwd_link = (char far *)ptr1 - (char far *)cache_start;
226 }
227
228 memorysize = (long)(newcolsize) * newrowsize + headerlength;
229 if ((i = (short)memorysize & (BLOCKLEN-1)) != 0)
230 memorysize += BLOCKLEN - i;
231 memorysize >>= pixelshift;
232 memorysize >>= BLOCKSHIFT;
233 diskflag = 1;
234 rowsize = (unsigned int) newrowsize;
235 colsize = (unsigned int) newcolsize;
236
237 if (disktarga) {
238 /* Retrieve the header information first */
239 BYTE far *tmpptr;
240 tmpptr = membuf;
241 fseek(fp, 0L,SEEK_SET);
242 for (i = 0; i < headerlength; i++)
243 *tmpptr++ = (BYTE)fgetc(fp);
244 fclose(fp);
245 dv_handle = MemoryAlloc((U16)BLOCKLEN, memorysize, DISK);
246 }
247 else
248 dv_handle = MemoryAlloc((U16)BLOCKLEN, memorysize, EXPANDED);
249 if (dv_handle == 0) {
250 static FCODE msg[]={"*** insufficient free memory/disk space ***"};
251 stopmsg(0,msg);
252 goodmode = 0;
253 rowsize = 0;
254 return(-1);
255 }
256
257 if (dotmode == 11)
258 switch (MemoryType(dv_handle)) {
259 static FCODE fmsg1[] = {"Using no Memory, it's broke"};
260 static FCODE fmsg2[] = {"Using your Expanded Memory"};
261 static FCODE fmsg3[] = {"Using your Extended Memory"};
262 static FCODE fmsg4[] = {"Using your Disk Drive"};
263 case NOWHERE:
264 default:
265 putstring(BOXROW+2,BOXCOL+23,C_DVID_LO,fmsg1);
266 break;
267 case EXPANDED:
268 putstring(BOXROW+2,BOXCOL+23,C_DVID_LO,fmsg2);
269 break;
270 case EXTENDED:
271 putstring(BOXROW+2,BOXCOL+23,C_DVID_LO,fmsg3);
272 break;
273 case DISK:
274 putstring(BOXROW+2,BOXCOL+23,C_DVID_LO,fmsg4);
275 break;
276 }
277
278 membufptr = membuf;
279
280 if (!disktarga)
281 for (offset = 0; offset < memorysize; offset++) {
282 static FCODE cancel[] = {"Disk Video initialization interrupted:\n"};
283 SetMemory(0, (U16)BLOCKLEN, 1L, offset, dv_handle);
284 if (keypressed()) /* user interrupt */
285 if (stopmsg(2, cancel)) /* esc to cancel, else continue */
286 {
287 enddisk();
288 goodmode = 0;
289 return -2; /* -1 == failed, -2 == cancel */
290 }
291 }
292
293 if (disktarga) { /* Put header information in the file */
294 MoveToMemory(membuf, (U16)headerlength, 1L, 0, dv_handle);
295 }
296
297 if (dotmode == 11)
298 dvid_status(0,"");
299 return(0);
300 }
301
enddisk()302 void enddisk()
303 {
304 if (fp != NULL) {
305 if (disktarga) /* flush the cache */
306 for (cache_lru = cache_start; cache_lru < cache_end; ++cache_lru)
307 if (cache_lru->dirty)
308 write_cache_lru();
309 fclose(fp);
310 }
311
312 if (dv_handle != 0) {
313 MemoryRelease(dv_handle);
314 dv_handle = 0;
315 }
316 if (hash_ptr != NULL)
317 farmemfree((void far *)hash_ptr);
318 if (cache_start != NULL)
319 farmemfree((void far *)cache_start);
320 if (membuf != NULL)
321 farmemfree((void far *)membuf);
322 diskflag = rowsize = disk16bit = 0;
323 hash_ptr = NULL;
324 cache_start = NULL;
325 fp = NULL;
326 }
327
readdisk(unsigned int col,unsigned int row)328 int readdisk(unsigned int col, unsigned int row)
329 {
330 int col_subscr;
331 long offset;
332 char buf[41];
333 if (--timetodisplay < 0) { /* time to display status? */
334 if (dotmode == 11) {
335 sprintf(buf," reading line %4d",
336 (row >= (unsigned int)sydots) ? row-sydots : row); /* adjust when potfile */
337 dvid_status(0,buf);
338 }
339 if(bf_math)
340 timetodisplay = 10; /* time-to-display-status counter */
341 else
342 timetodisplay = 1000; /* time-to-display-status counter */
343 }
344 if (row != (unsigned int)cur_row) { /* try to avoid ghastly code generated for multiply */
345 if (row >= colsize) /* while we're at it avoid this test if not needed */
346 return(0);
347 cur_row_base = (long)(cur_row = row) * rowsize;
348 }
349 if (col >= rowsize)
350 return(0);
351 offset = cur_row_base + col;
352 col_subscr = (short)offset & (BLOCKLEN-1); /* offset within cache entry */
353 if (cur_offset != (offset & (0L-BLOCKLEN))) /* same entry as last ref? */
354 findload_cache(offset & (0L-BLOCKLEN));
355 return (cur_cache->pixel[col_subscr]);
356 }
357
FromMemDisk(long offset,int size,void far * dest)358 int FromMemDisk(long offset, int size, void far *dest)
359 {
360 int col_subscr = (int)(offset & (BLOCKLEN - 1));
361
362 if (col_subscr + size > BLOCKLEN) /* access violates a */
363 return 0; /* cache boundary */
364
365 if (cur_offset != (offset & (0L-BLOCKLEN))) /* same entry as last ref? */
366 findload_cache (offset & (0L-BLOCKLEN));
367
368 far_memcpy(dest, (void far *) &cur_cache->pixel[col_subscr], size);
369 cur_cache->dirty = 0;
370 return 1;
371 }
372
373
targa_readdisk(unsigned int col,unsigned int row,BYTE * red,BYTE * green,BYTE * blue)374 void targa_readdisk(unsigned int col, unsigned int row,
375 BYTE *red, BYTE *green, BYTE *blue)
376 {
377 col *= 3;
378 *blue = (BYTE)readdisk(col,row);
379 *green = (BYTE)readdisk(++col,row);
380 *red = (BYTE)readdisk(col+1,row);
381 }
382
writedisk(unsigned int col,unsigned int row,unsigned int color)383 void writedisk(unsigned int col, unsigned int row, unsigned int color)
384 {
385 int col_subscr;
386 long offset;
387 char buf[41];
388 if (--timetodisplay < 0) { /* time to display status? */
389 if (dotmode == 11) {
390 sprintf(buf," writing line %4d",
391 (row >= (unsigned int)sydots) ? row-sydots : row); /* adjust when potfile */
392 dvid_status(0,buf);
393 }
394 timetodisplay = 1000;
395 }
396 if (row != (unsigned int)cur_row) { /* try to avoid ghastly code generated for multiply */
397 if (row >= colsize) /* while we're at it avoid this test if not needed */
398 return;
399 cur_row_base = (long)(cur_row = row) * rowsize;
400 }
401 if (col >= rowsize)
402 return;
403 offset = cur_row_base + col;
404 col_subscr = (short)offset & (BLOCKLEN-1);
405 if (cur_offset != (offset & (0L-BLOCKLEN))) /* same entry as last ref? */
406 findload_cache(offset & (0L-BLOCKLEN));
407 if (cur_cache->pixel[col_subscr] != (color & 0xff)) {
408 cur_cache->pixel[col_subscr] = (BYTE)color;
409 cur_cache->dirty = 1;
410 }
411 }
412
ToMemDisk(long offset,int size,void far * src)413 int ToMemDisk(long offset, int size, void far *src)
414 {
415 int col_subscr = (int)(offset & (BLOCKLEN - 1));
416
417 if (col_subscr + size > BLOCKLEN) /* access violates a */
418 return 0; /* cache boundary */
419
420 if (cur_offset != (offset & (0L-BLOCKLEN))) /* same entry as last ref? */
421 findload_cache (offset & (0L-BLOCKLEN));
422
423 far_memcpy((void far *) &cur_cache->pixel[col_subscr], src, size);
424 cur_cache->dirty = 1;
425 return 1;
426 }
427
targa_writedisk(unsigned int col,unsigned int row,BYTE red,BYTE green,BYTE blue)428 void targa_writedisk(unsigned int col, unsigned int row,
429 BYTE red, BYTE green, BYTE blue)
430 {
431 writedisk(col*=3,row,blue);
432 writedisk(++col, row,green);
433 writedisk(col+1, row,red);
434 }
435
findload_cache(long offset)436 static void _fastcall near findload_cache(long offset) /* used by read/write */
437 {
438 #ifndef XFRACT
439 unsigned int tbloffset;
440 int i,j;
441 unsigned int far *fwd_link;
442 BYTE far *pixelptr;
443 BYTE tmpchar;
444 cur_offset = offset; /* note this for next reference */
445 /* check if required entry is in cache - lookup by hash */
446 tbloffset = hash_ptr[ ((unsigned short)offset >> BLOCKSHIFT) & (HASHSIZE-1) ];
447 while (tbloffset != 0xffff) { /* follow the hash chain */
448 cur_cache = (struct cache far *)((char far *)cache_start + tbloffset);
449 if (cur_cache->offset == offset) { /* great, it is in the cache */
450 cur_cache->lru = 1;
451 return;
452 }
453 tbloffset = cur_cache->hashlink;
454 }
455 /* must load the cache entry from backing store */
456 for(;;) { /* look around for something not recently used */
457 if (++cache_lru >= cache_end)
458 cache_lru = cache_start;
459 if (cache_lru->lru == 0)
460 break;
461 cache_lru->lru = 0;
462 }
463 if (cache_lru->dirty) /* must write this block before reusing it */
464 write_cache_lru();
465 /* remove block at cache_lru from its hash chain */
466 fwd_link = hash_ptr
467 + (((unsigned short)cache_lru->offset >> BLOCKSHIFT) & (HASHSIZE-1));
468 tbloffset = (char far *)cache_lru - (char far *)cache_start;
469 while (*fwd_link != tbloffset)
470 fwd_link = &((struct cache far *)((char far *)cache_start+*fwd_link))->hashlink;
471 *fwd_link = cache_lru->hashlink;
472 /* load block */
473 cache_lru->dirty = 0;
474 cache_lru->lru = 1;
475 cache_lru->offset = offset;
476 pixelptr = &cache_lru->pixel[0];
477 if (offset > high_offset) { /* never been this high before, just clear it */
478 high_offset = offset;
479 for (i = 0; i < BLOCKLEN; ++i)
480 *(pixelptr++) = 0;
481 }
482 else {
483 if (offset != seek_offset)
484 mem_seek(offset >> pixelshift);
485 seek_offset = offset + BLOCKLEN;
486 switch (pixelshift) {
487 case 0:
488 for (i = 0; i < BLOCKLEN; ++i)
489 *(pixelptr++) = mem_getc();
490 break;
491 case 1:
492 for (i = 0; i < BLOCKLEN/2; ++i) {
493 tmpchar = mem_getc();
494 *(pixelptr++) = (BYTE)(tmpchar >> 4);
495 *(pixelptr++) = (BYTE)(tmpchar & 15);
496 }
497 break;
498 case 2:
499 for (i = 0; i < BLOCKLEN/4; ++i) {
500 tmpchar = mem_getc();
501 for (j = 6; j >= 0; j -= 2)
502 *(pixelptr++) = (BYTE)((tmpchar >> j) & 3);
503 }
504 break;
505 case 3:
506 for (i = 0; i < BLOCKLEN/8; ++i) {
507 tmpchar = mem_getc();
508 for (j = 7; j >= 0; --j)
509 *(pixelptr++) = (BYTE)((tmpchar >> j) & 1);
510 }
511 break;
512 }
513 }
514 /* add new block to its hash chain */
515 fwd_link = hash_ptr + (((unsigned short)offset >> BLOCKSHIFT) & (HASHSIZE-1));
516 cache_lru->hashlink = *fwd_link;
517 *fwd_link = (char far *)cache_lru - (char far *)cache_start;
518 cur_cache = cache_lru;
519 #endif
520 }
521
find_cache(long offset)522 static struct cache far * _fastcall near find_cache(long offset)
523 /* lookup for write_cache_lru */
524 {
525 #ifndef XFRACT
526 unsigned int tbloffset;
527 struct cache far *ptr1;
528 tbloffset = hash_ptr[ ((unsigned short)offset >> BLOCKSHIFT) & (HASHSIZE-1) ];
529 while (tbloffset != 0xffff) {
530 ptr1 = (struct cache far *)((char far *)cache_start + tbloffset);
531 if (ptr1->offset == offset)
532 return (ptr1);
533 tbloffset = ptr1->hashlink;
534 }
535 return (NULL);
536 #endif
537 }
538
write_cache_lru()539 static void near write_cache_lru()
540 {
541 int i,j;
542 BYTE far *pixelptr;
543 long offset;
544 BYTE tmpchar = 0;
545 struct cache far *ptr1, far *ptr2;
546 #define WRITEGAP 4 /* 1 for no gaps */
547 /* scan back to also write any preceding dirty blocks, skipping small gaps */
548 ptr1 = cache_lru;
549 offset = ptr1->offset;
550 i = 0;
551 while (++i <= WRITEGAP) {
552 if ((ptr2 = find_cache(offset -= BLOCKLEN)) != NULL && ptr2->dirty) {
553 ptr1 = ptr2;
554 i = 0;
555 }
556 }
557 /* write all consecutive dirty blocks (often whole cache in 1pass modes) */
558 /* keep going past small gaps */
559 write_seek:
560 mem_seek(ptr1->offset >> pixelshift);
561 write_stuff:
562 pixelptr = &ptr1->pixel[0];
563 switch (pixelshift) {
564 case 0:
565 for (i = 0; i < BLOCKLEN; ++i)
566 mem_putc(*(pixelptr++));
567 break;
568 case 1:
569 for (i = 0; i < BLOCKLEN/2; ++i) {
570 tmpchar = (BYTE)(*(pixelptr++) << 4);
571 tmpchar = (BYTE)(tmpchar + *(pixelptr++));
572 mem_putc(tmpchar);
573 }
574 break;
575 case 2:
576 for (i = 0; i < BLOCKLEN/4; ++i) {
577 for (j = 6; j >= 0; j -= 2)
578 tmpchar = (BYTE)((tmpchar << 2) + *(pixelptr++));
579 mem_putc(tmpchar);
580 }
581 break;
582 case 3:
583 for (i = 0; i < BLOCKLEN/8; ++i) {
584 mem_putc((BYTE)
585 ((((((((((((((*pixelptr
586 << 1)
587 | *(pixelptr+1) )
588 << 1)
589 | *(pixelptr+2) )
590 << 1)
591 | *(pixelptr+3) )
592 << 1)
593 | *(pixelptr+4) )
594 << 1)
595 | *(pixelptr+5) )
596 << 1)
597 | *(pixelptr+6) )
598 << 1)
599 | *(pixelptr+7)));
600 pixelptr += 8;
601 }
602 break;
603 }
604 ptr1->dirty = 0;
605 offset = ptr1->offset + BLOCKLEN;
606 if ((ptr1 = find_cache(offset)) != NULL && ptr1->dirty != 0)
607 goto write_stuff;
608 i = 1;
609 while (++i <= WRITEGAP) {
610 if ((ptr1 = find_cache(offset += BLOCKLEN)) != NULL && ptr1->dirty != 0)
611 goto write_seek;
612 }
613 seek_offset = -1; /* force a seek before next read */
614 }
615
616 /* Seek, mem_getc, mem_putc routines follow.
617 Note that the calling logic always separates mem_getc and mem_putc
618 sequences with a seek between them. A mem_getc is never followed by
619 a mem_putc nor v.v. without a seek between them.
620 */
621
mem_seek(long offset)622 static void _fastcall near mem_seek(long offset) /* mem seek */
623 {
624 offset += headerlength;
625 memoffset = offset >> BLOCKSHIFT;
626 if (memoffset != oldmemoffset) {
627 MoveToMemory(membuf, (U16)BLOCKLEN, 1L, oldmemoffset, dv_handle);
628 MoveFromMemory(membuf, (U16)BLOCKLEN, 1L, memoffset, dv_handle);
629 }
630 oldmemoffset = memoffset;
631 membufptr = membuf + (offset & (BLOCKLEN - 1));
632 }
633
mem_getc()634 static BYTE near mem_getc() /* memory get_char */
635 {
636 if (membufptr - membuf >= BLOCKLEN) {
637 MoveToMemory(membuf, (U16)BLOCKLEN, 1L, memoffset, dv_handle);
638 memoffset++;
639 MoveFromMemory(membuf, (U16)BLOCKLEN, 1L, memoffset, dv_handle);
640 membufptr = membuf;
641 oldmemoffset = memoffset;
642 }
643 return (*(membufptr++));
644 }
645
mem_putc(BYTE c)646 static void _fastcall near mem_putc(BYTE c) /* memory get_char */
647 {
648 if (membufptr - membuf >= BLOCKLEN) {
649 MoveToMemory(membuf, (U16)BLOCKLEN, 1L, memoffset, dv_handle);
650 memoffset++;
651 MoveFromMemory(membuf, (U16)BLOCKLEN, 1L, memoffset, dv_handle);
652 membufptr = membuf;
653 oldmemoffset = memoffset;
654 }
655 *(membufptr++) = c;
656 }
657
658
dvid_status(int line,char far * msg)659 void dvid_status(int line,char far *msg)
660 {
661 char buf[41];
662 int attrib;
663 memset(buf,' ',40);
664 far_memcpy(buf,msg,far_strlen(msg));
665 buf[40] = 0;
666 attrib = C_DVID_HI;
667 if (line >= 100) {
668 line -= 100;
669 attrib = C_STOP_ERR;
670 }
671 putstring(BOXROW+10+line,BOXCOL+12,attrib,buf);
672 movecursor(25,80);
673 }
674
675