File: tmplist.c

package info (click to toggle)
dosemu-freedos 1%3A0.0.b9r5a%2Betch.1-0etch1
  • links: PTS
  • area: contrib
  • in suites: etch
  • size: 19,744 kB
  • ctags: 23,279
  • sloc: ansic: 143,864; asm: 20,397; makefile: 3,868; perl: 1,106; yacc: 690; sh: 553; pascal: 297; xml: 150; cpp: 67
file content (602 lines) | stat: -rw-r--r-- 14,963 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
/*
    LIB - a librarian for compatible OBJ/LIB files
    Copyright (C) 1995,1996  Steffen Kaiser

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $RCSfile: TMPLIST.C $
   $Locker: ska $	$Name: v3_2 $	$State: Rel $

	Temporary list file.

	Holds the information pair Symbol/Page#.

	File structure:
	struct {
		unsigned flags;
		unsigned pageNr;
		byte symLen;
		char symbol[];
	};
	The symbol is terminated by an additional '\0', which is NOT
	counted within symLen.


*/

#ifndef _MICROC_
#include <malloc.h>
#include <assert.h>
#include <string.h>
#include <dos.h>
#include <io.h>
#else
#include <file.h>
#endif
#include <stdio.h>
#include <ctype.h>
#include <fmemory.h>
#include "tmplist.h"
#include "lib.h"
#include "list.h"
#include "types.h"
#include "yerror.h"

extern char *mktmp(char *str);

#ifndef lint
static char const rcsid[] = 
	"$Id: TMPLIST.C 3.3 1999/02/17 05:18:08 ska Rel ska $";
#endif

static char *fname = NULL;
static FILEP fp;
unsigned maxName = 0;	/* max length of a symbol's name */
unsigned minPages = 1;			/* min amount of dir Pages required */
static int pageLeft = PAGELEFT;	/* mount of bytes, left on current page */
word maxOBJ;			/* maximum page size so far */
word cntOBJ;			/* number of OBJs processed so far */
word Msegment, Moffset, Mitems;
FLAG Mcounter;
unsigned dispInfo = 0;	/* maximal count for search heuristic (disabled) */
dword padbytes;			/* number of pad bytes calculated by pages() */

void Sclose(void)
/* close & delete temporary list file */
{	DB_ENTER("Sclose");

	if(fname) {
		chkHeap()
		Close(fp);
		unlink(fname);
		U_free(fname);
		fname = NULL;
		maxName = 0;
		chkHeap()
	}

	DB_EXIT
}

void Sopen(void)
/* open the temporary list file.
   This file holds the symbol names and the page on which this symbol
   starts. 
*/
{	DB_ENTER("Sopen");
	if((fname = mktmp(NULL)) == NULL)
		error(E_creatTmp);
#ifdef _MICROC_
	if((fp = open(fname, F_READ | F_WRITE)) == 0)
#else
	if((fp = fopen(fname, "w+b")) == NULL)
#endif
		fatal(E_openFile, fname);
	chkHeap()
	cntOBJ = maxOBJ = 0;
	DB_EXIT
}

void Swrite(struct tmpList *h)
/* write the symbol/page# information into the temp list file.
*/
{	int len;
#define p (cS(struct tmpList *)ybuf)

	DB_ENTER("Swrite");

	if(skipModule)	/* this information is to be ignored */
		DB_EXIT

	if(upCaseIt) {	/* case-insensitve directory */
		len = h->symLen;
		while(len--) h->symbol[len] = toupper(h->symbol[len]);
	}

	DB_PRINT("arg", ("module = %s", h->symbol));

	len = h->symLen;
	chkHeap()
	if(h->flags & TL_THEADR) {	/* add the trailing '!' */
		memcpy(p, h, len + sizeof(struct tmpList));
		memcpy(&(h = p)->symbol[p->symLen++], "!", 2);
	}
	chkHeap()
	len = h->symLen;
	if(ww(h, sizeof(struct tmpList) + len, fp))
		fatal(E_writeFile, fname);

	if(len > maxName) maxName = len;

	/* calculate min page amount */
	if(++len & 1) ++len;	/* must have even length */
	if(len > pageLeft) {		/* page breaK */
#ifndef NDEBUG
		informative("Min dir pages: %u", minPages);
#endif
		++minPages;
		pageLeft = PAGELEFT - PAGECALCSKIP - len + pageLeft;
	}
	else pageLeft -= len;
#undef p
	DB_EXIT
}

void Srewind(void)
{	DB_ENTER("Srewind");
	Rewind(fp, fname);
	chkHeap()
	DB_EXIT
}

int Sread(struct tmpList *h)
/* Read the next symbol entry from the temporary list file.
   Emit en error message if failed.
   Return:
   	*h filled with the entry;
   	== 0 if no entry found
*/
{	DB_ENTER("Sread");
	do {
		chkHeap()
		if(rr(h, sizeof(struct tmpList), fp))
			DB_RETURN( NUL);
	} while(h->flags & TL_SIZE);
	chkHeap()
	if(rr(&(h->symbol[1]), h->symLen, fp))
		fatal(E_readFile, fname);
	DB_PRINT("inf", ("symbol = %s", h->symbol));
	chkHeap()
	DB_RETURN( !NUL);
}

#ifdef _MICROC_
void SwriteSize(dword *size)
#else
void SwriteSize(dword size)
#endif
/* write a record into the temporary list holding the size of the
	OBJ module immediately above. */
{	struct tmpList h;

	DB_ENTER("SwriteSize");
	DB_PRINT("arg", ("size = %lu", size));

	h.flags = TL_SIZE;
#ifdef _MICROC_
	longcpy(&h.pageNr, size);
	if(size->hi)				/* pages are limited to 64kB */
		maxOBJ = 0xffff;
	else if(size->lo > maxOBJ)				/* longest OBJ? */
		maxOBJ = size->lo;
#else
	*(dword*)&h.pageNr = size;
	if(size > 0xfffful)				/* pages are limited to 64kB */
		maxOBJ = 0xffff;
	else if((word)size > maxOBJ)				/* longest OBJ? */
		maxOBJ = (word)size;
#endif
	++cntOBJ;
	if(ww(aS(h), sizeof(h), fp))
		fatal(E_writeFile, fname);
	DB_EXIT
}

int SgetSize(dword *size, int saveFPos)
{	struct tmpList h;
	FLAG found;

#ifdef _MICROC_
	unsigned high, low;			/* current file pointer */

	if(saveFPos && ltell(fp, &high, &low))
#else
	long fpos;

	DB_ENTER("SgetSize");

	if(saveFPos && (fpos = ftell(fp)) == -1l)
#endif
		DB_RETURN( 0);

	found = NUL;

	while(!rr(aS(h), sizeof(h), fp))
		if(h.flags & TL_SIZE) {
#ifdef _MICROC_
			longcpy(size, &h.pageNr);
#else
			*size = *(dword*)&h.pageNr;
#endif
			found = !NUL;
			break;
		}
		else	/* skip the symbol name */
#ifdef _MICROC_
			if(lseek(fp, 0, h.symLen, 1))
#else
			if(fseek(fp, h.symLen, 1))
#endif
				break;

#ifdef _MICROC_
	if(saveFPos && lseek(fp, high, low, 0))
#else
	if(saveFPos && fseek(fp, fpos, 0))
#endif
		fatal(E_accessFile, fname);

	DB_RETURN( found);
}

void mkLstFile(char *fnam)
/* Construct the list file from the temporary file.
	The extension defaults to "LST". */
{	struct tmpList *h;
	FILE *lst;
	FLAG module;
	dword modLen;
	char *dr, *path, *name, *ext;

	DB_ENTER("mkLstFile");

	h = getmem(sizeof(struct tmpList) + maxName);
	Srewind();
	chkHeap()
	if(!fsplit(fnam, &dr, &path, &name, &ext, 0)
	 || (!ext && (fnam = fmerge(NULL, dr, path, name, "LST")) == NULL))
	 	fatal(E_noMem);
	chkHeap()
	informative(M_createLstFile, fnam);
	if((lst = fopen(fnam, "wt")) == NULL)
		error(E_openFile, fnam);
	chkHeap()
	while(Sread(h)) {
		if(!(module = h->flags & TL_THEADR))	/* not a module name */
			fputc('\t', lst);			/* indent */
		fwrite(&(h->symbol[0]), h->symLen - (module? 1: 0), 1, lst);
		if(h->flags & TL_THEADR) {				/* search the size record */
			fputs("\t\tsize = ", lst);
			if(SgetSize(aS(modLen), 1)) {
#ifdef _MICROC_
				ltoa(modLen, ybuf, 10);
				fputs(ybuf, lst);
#else
				fprintf(lst, "%lu", modLen);
#endif
			}
			else fputs("???", lst);
		}
		fputc('\n', lst);
	}
	chkHeap()
	if(ferror(lst))
		fatal(E_writeFile, fnam);
	fclose(lst);
	U_free(h);
	chkHeap()
	if(!ext) U_free(fnam);
	chkHeap()
	U_free(dr); U_free(path); U_free(name); U_free(ext);
	chkHeap()
	DB_EXIT
}

void Mclose(void)
{	DB_ENTER("Mclose");
	DB_PRINT("arg", ("cache deallocated"));
	clrList();
	DB_EXIT
}

static void Minit(void)
/* The module size cache is a buffer system to hold the sizes in memory
	if possible, but have the interface if this failed.

	Initialize the cache.
*/
{	USEREGS
	dword size;

	DB_ENTER("Minit");

	Mclose();		/* Remove a possibly active cache */

	/* Create cache */
	/* Per stored OBJ 4 bytes are necessary, allocation unit is 16 bytes ->
			cachesize = cntOBJ * 4 / 16 + 1 
		The additional paragraphe is for the number of elements modulo 4
		and 2 bytes for the far block chaining. */
	if(!(Msegment = Falloc((cntOBJ >> 2) + 1))) {	/* Failed */
		warning(W_lowMemMinit);
		Mcounter = !NUL;
		DB_EXIT
	}

	DB_PRINT("inf", ("cache initialized"));

	/* Copy the sizes into the segment */
	Srewind();
	Moffset = 2;		/* skip over the far block chaining word */
	while(SgetSize(aS(size), 0)) {
		_fmemcpy(MK_FP(Msegment, Moffset), TO_FP(aS(size)), 4);
		if((Moffset += 4) & 0x8000)
			Moffset &= 0x7fff, Msegment += 0x800;
	}
	Mcounter = NUL;
	DB_EXIT
}

static void Mrewind(void)
{	if((Msegment = farBlkHead) != 0)
		Moffset = 2, Mitems = cntOBJ;
	else Srewind();
}

static int Mread(dword *size)
/* Get next entry */
{	if(farBlkHead) {
		if(Mitems--) {
			_fmemcpy(TO_FP(size), MK_FP(Msegment, Moffset), 4);
			if((Moffset += 4) & 0x8000)
				Moffset &= 0x7fff, Msegment += 0x800;
			return 1;
		}
	}
	else return SgetSize(size, 0);
	return 0;
}

static word pages(word PageSize)
/* Calculates the amount of pages needed in order to store all the OBJ
	modules in a library with a page size of PageSize.
	Return:	0: failure
			otherwise: amount of pages
*/
{	dword size;
#ifdef _MICROC_
	dword libPages, pageCnt;

	longsetu(pageCnt, PageSize);
#else
	word libPages;
#define pageCnt PageSize
#endif

	longsetu(libPages, 2);			/* the two standard LIB frame pages */
	longsetu(padbytes, PageSize - MINPAGESIZE);
	Mrewind();
	while(Mread(aS(size))) {
#ifdef _MICROC_
		longdiv(size, pageCnt);
		if(longtst(Longreg)) {	/* last page is not fully-filled */
			if(!++size.lo)		/* ++size overflow of 0xffff */
				break;
			longadd(padbytes, Longreg);
		}
		longadd(libPages, size);
		if(size.hi || libPages.hi)
			return 0;		/* OBJ module too large for the LIB */
#else
		padbytes += size % pageCnt;
		size = size / pageCnt + (size % pageCnt != 0);
		if(size > 0xffff || (size += libPages) > 0xffff) 
			return 0;
		libPages = (word)size;
#undef pageCnt
#endif
	}
#ifdef _MICROC_
	return libPages.lo;
#else
	return libPages;
#endif
}

static void dispPS(MSGID id, word pagesize)
/* display the information derived from a page size.
	The size of the data area of a library counts one page less than
	returned by pages(), because the last page will be dynamically filled
	to align to the library directory. */
{	dword size;
	word slackarea;
#define xbuf ybuf+64
#ifdef _MICROC_
	dword ps;

	size.hi = ps.hi = 0;
	size.lo = pages(ps.lo = pagesize) - 1;
	longmul(size, ps);
	ps.lo = 3; 				/* the minimum size of the last page */
	/* calculate the amount of bytes to the next 512 byte boundary */
	slackarea = DIR_PAGE_SIZE - size.lo % DIR_PAGE_SIZE;
	if(alignDir) {
		ps.lo = slackarea;
		longadd(size, ps);
	}
	ltoa(size, ybuf, 10);
	ltoa(padbytes, xbuf, 10);
#else
	DB_ENTER("dispPS");

	/* The last page has always 3 bytes, the rest is the slack area */
	size = (long)pagesize * (pages(pagesize) - 1) + 3;
	slackarea = DIR_PAGE_SIZE - (word)size % DIR_PAGE_SIZE;
	if(alignDir) size += slackarea;
	sprintf(ybuf, "%ld", size);
	sprintf(xbuf, "%ld", padbytes);
#endif

	beautify(ybuf);
	beautify(xbuf);

	message(stdout, alignDir? M_aliPageSize: M_pageSize
	 , msgLock(id), pagesize, ybuf, slackarea, xbuf);
	msgUnlock(id);
#undef xbuf
	DB_EXIT
}

void dispPageInfo(int update)
/* determine the optimal page size.
	If update is !NUL, this amount is placed into pageSizeNew */
{	dword size, optSize;
	word minPage, maxPage;
	word pageCnt, optPages;
#ifdef _MICROC_
	dword libPages;

	longclr(libPages);
	optSize.lo = 0xffff;
	optSize.hi = 0x7fff;
#else
	word libPages;

	DB_ENTER("dispPageInfo");

	optSize = 0x7ffffffful;
#endif

	if(update && pageSizeNew == 0xffff)	/* this is the absolutely maximum */
		error(E_libTooLong);

	informative(M_pageInfo);

	Minit();

	if(dispInfo == 0xffff) {		/* brute force, bypass heuristic */
		minPage = MINPAGESIZE;
		maxPage = maxOBJ;
	}
	else {
		/* The heuristic shall limit the amount of pages sizes that
			will be tested in a brute force method.
			The lowest page size is determined, which allows to create
			the library. From there dispInfo sizes will be tested.

			Determining will start with the current page size, if it
			allows the creation, the range MINPAGESIZE .. pagesize; if
			it doesn't allow the creation, the range pagesize .. maxOBJ
			is checked.

			The range will be halfed as long as the first possible
			page size is determined.
		*/
		if(pages(pageSizeNew)) {	/* current page size OK */
			maxPage = pageSizeNew;
			minPage = MINPAGESIZE;
		}
		else {						/* current page size to small */
			minPage = pageSizeNew;
			if(!pages(maxPage = maxOBJ)) {
				if(update) error(E_libTooLong);
				warning(E_libTooLong);
				return;
			}
		}

		while(minPage != maxPage) {
			/* optPage := middest page size, to avoid integer overflow
				don't calculate with (maxPage + pageCnt) >> 1 */
			optPages = ((maxPage - minPage) >> 1) + minPage;
			if(optPages == minPage)
				break;
			if(pages(optPages)) /* OK */
				maxPage = optPages;
			else minPage = optPages;
		}
	}
	while(!pages(minPage))
		++minPage;

	maxPage = (maxOBJ - minPage < dispInfo)? maxOBJ: minPage + dispInfo;

	if(!isatty(fileno(stdout)) || !dispDoing
	 || getNoiseLevel(ENoise_informative) != NOISE_ALLOW)
		/* output redirected or output suppressed, no counter */
		Mcounter = NUL;
	else if(dispInfo > PAGEINFO_COUNTER)	/* display the counter? */
		Mcounter = !NUL;

	for(pageCnt = minPage - 1, optPages = 0; ++pageCnt <= maxPage;) {
		/* calculate library size */
		if(Mcounter)
			printf("%u \r", maxPage - pageCnt);

#ifdef _MICROC_
		if(libPages.lo = pages(pageCnt)) {
			longsetu(size, pageCnt);
			longmul(size, libPages);
			if(longcmp(size, optSize) < 0) {
				/* verify, if this is better */
#else
		if((libPages = pages(pageCnt)) != NULL) {		/* OBJs fit into library */
			size = (dword)libPages * pageCnt;
			if(size < optSize) {
#endif
				/* yes, set it */
				optPages = pageCnt;
				longcpy(optSize, size);
			}
		}
	}

	if(Mcounter)		/* overwrite the counter on the display */
		fputs("        \r", stdout);

	message(stdout, M_HeadPageSize);
	if(pageSizeNew != pageSizeOld && pageSizeOld)
		dispPS(M__Original, pageSizeOld);
	dispPS(M__Current, pageSizeNew);
	dispPS(M__Minimal, minPage);
	if(maxOBJ)
		dispPS(M__Maximal, maxOBJ);
	if(optPages) {
		if(dispInfo != 1)
			dispPS(M__Optimal, optPages);
	}
	else
		if(update) error(E_libTooLong);
		else warning(E_libTooLong);
	message(stdout, M_dirSize, dirPagesNew);
	if(update)
		pageSizeNew = (optPages <= pageSizeNew)	/* Hmm, the best page size
				 lays below the current one; assume a constant difference */
			? (((unsigned)pageSizeNew <= 0xffff - CONST_RESTART)
				? pageSizeNew + CONST_RESTART: 0xffff)
			: optPages;
	Mclose();
	DB_EXIT
}