source: trunk/emx/src/libomflib/omflibcr.c@ 2446

Last change on this file since 2446 was 1992, checked in by bird, 20 years ago

Allow multiple modules by the same basename. This is not in tradition with other librarians, but it solves incompatible behaviour between emxomfar and ar.

  • Property cvs2svn:cvs-rev set to 1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 6.5 KB
Line 
1/* omflibcr.c (emx+gcc) -- Copyright (c) 1993-1996 by Eberhard Mattes */
2
3/* Create a new OMFLIB. */
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <errno.h>
9#include "omflib0.h"
10#include <sys/omflib.h>
11
12
13struct omflib *omflib_create (const char *fname, int page_size, char *error)
14{
15 struct omflib *p;
16 FILE *f;
17
18 if (page_size < 16 || page_size > 32768
19 || (page_size & (page_size - 1)) != 0)
20 {
21 strcpy (error, "Invalid page size");
22 return NULL;
23 }
24 f = fopen (fname, "wb");
25 if (f == NULL)
26 {
27 strcpy (error, strerror (errno));
28 return NULL;
29 }
30 p = malloc (sizeof (struct omflib));
31 if (p == NULL)
32 {
33 errno = ENOMEM;
34 strcpy (error, strerror (errno));
35 fclose (f);
36 remove (fname);
37 return NULL;
38 }
39 p->f = f;
40 p->page_size = page_size;
41 p->dict_offset = 0;
42 p->dict_blocks = 0;
43 p->flags = 1;
44 p->mod_tab = NULL;
45 p->mod_alloc = 0;
46 p->mod_count = -1;
47 p->dict = NULL;
48 p->pub_tab = NULL;
49 p->pub_alloc = 0;
50 p->pub_count = 0;
51 p->output = TRUE;
52 p->state = OS_EMPTY;
53 p->mod_page = 0;
54 p->mod_name[0] = 0;
55 return p;
56}
57
58
59int omflib_header (struct omflib *p, char *error)
60{
61 fseek (p->f, 0, SEEK_SET);
62 return omflib_pad (p->f, p->page_size, TRUE, error);
63}
64
65
66static int omflib_add_dict (struct omflib *p, const char *name, int page,
67 char *error)
68{
69 int block_index, bucket_index;
70 int bv, len, bucket_count;
71 byte *block, *ptr;
72 byte buf[257];
73 int (*compare)(const void *s1, const void *s2, size_t n);
74
75 len = strlen (name);
76 if (len > 255)
77 {
78 strcpy (error, "Symbol name too long");
79 return -1;
80 }
81 buf[0] = (byte)len;
82 memcpy (buf+1, name, len);
83 omflib_hash (p, buf);
84 block_index = p->block_index;
85 bucket_index = p->bucket_index;
86 compare = (p->flags & 1 ? memcmp : memicmp);
87 bucket_count = 37;
88 block = p->dict + 512 * block_index;
89 for (;;)
90 {
91 bv = block[bucket_index];
92 if (bv == 0)
93 {
94 if (block[37] == 0xff)
95 bucket_count = 0;
96 else if (2 * block[37] + len + 4 > 512)
97 {
98 block[37] = 0xff;
99 bucket_count = 0;
100 }
101 else
102 {
103 block[bucket_index] = block[37];
104 ptr = block + 2 * block[37];
105 memcpy (ptr, buf, len+1);
106 ptr[len+1] = (byte)page;
107 ptr[len+2] = (byte)(page >> 8);
108 block[37] = (2 * block[37] + len + 3 + 1) / 2;
109 if (block[37] == 0) block[37] = 0xff;
110 return 0;
111 }
112 }
113 else
114 {
115 ptr = block + 2 * bv;
116 if (*ptr == len && compare (ptr+1, buf+1, len) == 0)
117 {
118 if (buf[len] != '!')
119 {
120 strcpy (error, "Symbol multiply defined: ");
121 strcat (error, name);
122 return -1;
123 }
124 else
125 {
126 /* Ignore multiply defined modules. This isn't correct behaviour,
127 but it helps emxomfar being more compatible with ar. */
128 return 0;
129 }
130 }
131 }
132 if (bucket_count != 0)
133 {
134 bucket_index += p->bucket_index_delta;
135 if (bucket_index >= 37)
136 bucket_index -= 37;
137 --bucket_count;
138 }
139 if (bucket_count == 0)
140 {
141 block_index += p->block_index_delta;
142 if (block_index >= p->dict_blocks)
143 block_index -= p->dict_blocks;
144 if (block_index == p->block_index)
145 return 1;
146 bucket_count = 37;
147 block = p->dict + 512 * block_index;
148 }
149 }
150}
151
152
153static int omflib_build_dict (struct omflib *p, char *error)
154{
155 int i, ret;
156
157 p->dict = realloc (p->dict, p->dict_blocks * 512);
158 if (p->dict == NULL)
159 {
160 errno = ENOMEM;
161 return omflib_set_error (error);
162 }
163 memset (p->dict, 0, p->dict_blocks * 512);
164 for (i = 0; i < p->dict_blocks; ++i)
165 p->dict[i * 512 + 37] = 38 / 2;
166 for (i = 0; i < p->pub_count; ++i)
167 {
168 ret = omflib_add_dict (p, p->pub_tab[i].name, p->pub_tab[i].page, error);
169 if (ret != 0)
170 return ret;
171 }
172 return 0;
173}
174
175
176static unsigned isqrt (unsigned x)
177{
178 unsigned a, r, e, i;
179
180 a = r = e = 0;
181 for (i = 0; i < 32 / 2; ++i)
182 {
183 r = (r << 2) | (x >> (32-2));
184 x <<= 2; a <<= 1;
185 e = (a << 1) | 1;
186 if (r >= e)
187 {
188 r -= e;
189 a |= 1;
190 }
191 }
192 return a;
193}
194
195
196/* Speed doesn't matter here. */
197
198static int is_prime (unsigned n)
199{
200 unsigned i, q;
201
202 q = isqrt (n);
203 for (i = 3; i <= q; i += 2)
204 if (n % i == 0)
205 return 0;
206 return 1;
207}
208
209
210static unsigned next_prime (unsigned n)
211{
212 if (n <= 1)
213 return 2;
214 if (n % 2 == 0)
215 --n;
216 do
217 {
218 n += 2;
219 } while (!is_prime (n));
220 return n;
221}
222
223
224int omflib_finish (struct omflib *p, char *error)
225{
226 struct lib_header hdr;
227 int len, i, blocks;
228 unsigned prime;
229 long pos;
230 struct omf_rec rec;
231
232 if (!p->output)
233 return 0;
234 len = 0;
235 for (i = 0; i < p->pub_count; ++i)
236 len += strlen (p->pub_tab[i].name) + 3;
237 blocks = (len + 511) / 512;
238 blocks += (blocks * 128) / 512;
239 ++blocks;
240 prime = blocks;
241 for (;;)
242 {
243 prime = next_prime (prime);
244 if (prime > 65535)
245 {
246 strcpy (error, "Too many dictionary blocks");
247 return -1;
248 }
249 p->dict_blocks = prime;
250 i = omflib_build_dict (p, error);
251 if (i < 0)
252 return i;
253 if (i == 0)
254 break;
255 }
256 pos = ftell (p->f) + 3;
257 rec.rec_type = LIBEND;
258 if ((pos & 511) == 0)
259 rec.rec_len = 0;
260 else
261 rec.rec_len = (word)(((pos | 511) + 1) - pos);
262 if (fwrite (&rec, sizeof (rec), 1, p->f) != 1)
263 return omflib_set_error (error);
264 if (omflib_pad (p->f, 512, FALSE, error) != 0)
265 return -1;
266 hdr.rec_type = LIBHDR;
267 hdr.rec_len = p->page_size - 3;
268 hdr.dict_offset = ftell (p->f);
269 hdr.dict_blocks = p->dict_blocks;
270 hdr.flags = (byte)p->flags;
271 fseek (p->f, 0, SEEK_SET);
272 if (fwrite (&hdr, sizeof (hdr), 1, p->f) != 1)
273 return omflib_set_error (error);
274 fseek (p->f, hdr.dict_offset, SEEK_SET);
275 if (fwrite (p->dict, 512, p->dict_blocks, p->f) != p->dict_blocks)
276 return omflib_set_error (error);
277 return 0;
278}
279
280
281int omflib_pad (FILE *f, int size, int force, char *error)
282{
283 long pos;
284
285 pos = ftell (f);
286 while ((pos & (size-1)) != 0 || force)
287 {
288 force = FALSE;
289 if (fputc (0, f) != 0)
290 return omflib_set_error (error);
291 ++pos;
292 }
293 return 0;
294}
Note: See TracBrowser for help on using the repository browser.