Home My Page Projects Code Snippets Project Openings SML/NJ
Summary Activity Forums Tracker Lists Tasks Docs Surveys News SCM Files

SCM Repository

[smlnj] Annotation of /sml/trunk/src/runtime/kernel/boot.c
ViewVC logotype

Annotation of /sml/trunk/src/runtime/kernel/boot.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 418 - (view) (download) (as text)
Original Path: sml/branches/SMLNJ/src/runtime/kernel/boot.c

1 : monnier 249 /* boot.c
2 :     *
3 :     * COPYRIGHT (c) 1993 by AT&T Bell Laboratories.
4 :     *
5 :     * This is the bootstrap loader for booting from .bin files.
6 :     */
7 :    
8 :     #include "ml-osdep.h"
9 :     #include <stdio.h>
10 : monnier 418 #include <string.h>
11 :     #include <stdlib.h>
12 : monnier 249 #include "ml-base.h"
13 :     #include "ml-limits.h"
14 :     #include "cache-flush.h"
15 :     #include "bin-file.h"
16 :     #include "ml-objects.h"
17 :     #include "gc.h"
18 :     #include "ml-globals.h"
19 :    
20 :     #ifndef SEEK_SET
21 :     # define SEEK_SET 0
22 :     #endif
23 :    
24 :     /** The names of the boot and binary file lists **/
25 :     PVT char *FileLists[] = {
26 :     "BOOTLIST", "PERVLIST", "COMPLIST"
27 :     };
28 :     #define NUM_FILE_LISTS (sizeof(FileLists) / sizeof(char *))
29 :    
30 :    
31 :     pers_id_t RunTimePerID = {RUNTIME_PERID};
32 :    
33 :    
34 :     /* The persistent ID list is stored in the PervStruct refcell. It has
35 :     * the following ML type:
36 :     *
37 :     * datatype runDynEnv
38 :     * = NILrde
39 :     * | CONSrde of (Word8Vector.vector * Object.object * runDynEnv)
40 :     */
41 :     #define PerIDList (*PTR_MLtoC(ml_val_t, PervStruct))
42 :    
43 :     PVT ml_val_t BinFileList = LIST_nil; /* A list of bin files to load */
44 :    
45 :    
46 :     /* local routines */
47 :     PVT ml_val_t BuildFileList (ml_state_t *msp, const char *binDir);
48 :     PVT FILE *OpenBinFile (const char *binDir, const char *fname, bool_t isBinary);
49 :     PVT void ReadBinFile (
50 :     FILE *file, void *buf, int nbytes,
51 :     const char *binDir, const char *fname
52 :     );
53 : monnier 418 PVT void LoadBinFile (ml_state_t *msp, const char *binDir, char *fname);
54 : monnier 249 PVT void EnterPerID (ml_state_t *msp, pers_id_t *perID, ml_val_t obj);
55 :     PVT ml_val_t LookupPerID (pers_id_t *perID);
56 :     PVT void ShowPerID (char *buf, pers_id_t *perID);
57 :    
58 : monnier 418 # define HEX(c) (isdigit(c) ? (c) - '0' : (c) - 'a' + 10)
59 : monnier 249
60 :     /* BootML:
61 :     *
62 :     * Boot the system using the .bin files from binDir.
63 :     */
64 : monnier 418 void BootML (const char *binDir, heap_params_t *heapParams,
65 :     const char *rtpid_spec)
66 : monnier 249 {
67 :     ml_state_t *msp;
68 :     char fname[512];
69 :    
70 : monnier 418 if (rtpid_spec) {
71 :     int i, l = strlen (rtpid_spec);
72 :     for (i = 0; i < PERID_LEN; i++) {
73 :     int i2 = 2 * i;
74 :     if (i2 + 1 < l) {
75 :     int c1 = rtpid_spec [i2];
76 :     int c2 = rtpid_spec [i2 + 1];
77 :     RunTimePerID.bytes[i] = HEX (c1) * 16 + HEX (c2);
78 :     }
79 :     }
80 :     }
81 :    
82 : monnier 249 msp = AllocMLState (TRUE, heapParams);
83 :    
84 :     #ifdef HEAP_MONITOR
85 :     if (HeapMon_Init(CmdLineArgs, msp->ml_heap) == FAILURE)
86 :     Die("unable to start heap monitor");
87 :     #endif
88 :    
89 :     InitFaultHandlers ();
90 :     AllocGlobals (msp);
91 :    
92 :     /* Enter the runtime system binding */
93 :     EnterPerID (msp, &RunTimePerID, RunTimeCompUnit);
94 :    
95 :     /* construct the list of files to be loaded */
96 :     BinFileList = BuildFileList (msp, binDir);
97 :    
98 :     /* boot the system */
99 :     while (BinFileList != LIST_nil) {
100 :     strcpy(fname, STR_MLtoC(LIST_hd(BinFileList)));
101 :     BinFileList = LIST_tl(BinFileList);
102 :     LoadBinFile (msp, binDir, fname);
103 :     }
104 :    
105 :     } /* end of BootML */
106 :    
107 :    
108 :     /* BuildFileList:
109 :     *
110 :     * Given the directory path, build a list of the .bin files in the
111 :     * heap.
112 :     */
113 :     PVT ml_val_t BuildFileList (ml_state_t *msp, const char *binDir)
114 :     {
115 :     FILE *listF;
116 :     ml_val_t fileNames[MAX_NUM_BOOT_FILES];
117 :     int i, j, numFiles;
118 :     char nameBuf[MAX_BOOT_PATH_LEN];
119 :     ml_val_t fileList;
120 :    
121 :     for (numFiles = 0, i = 0; i < NUM_FILE_LISTS; i++) {
122 :     listF = OpenBinFile (binDir, FileLists[i], FALSE);
123 :     if (listF == NULL)
124 :     continue;
125 :     /* read in the file names, converting them to ML strings. */
126 :     while (fgets (nameBuf, MAX_BOOT_PATH_LEN, listF) != NIL(char *)) {
127 :     j = strlen(nameBuf)-1;
128 :     if (nameBuf[j] == '\n') nameBuf[j] = '\0'; /* remove "\n" */
129 :     if (numFiles < MAX_NUM_BOOT_FILES)
130 :     fileNames[numFiles++] = ML_CString(msp, nameBuf);
131 :     else
132 :     Die ("too many files\n");
133 :     }
134 :     fclose (listF);
135 :     }
136 :    
137 :     /* create the in-heap list */
138 :     for (fileList = LIST_nil, i = numFiles; --i >= 0; ) {
139 :     LIST_cons(msp, fileList, fileNames[i], fileList);
140 :     }
141 :    
142 :     return fileList;
143 :    
144 :     } /* end of BuildFileList */
145 :    
146 :    
147 :     /* OpenBinFile:
148 :     *
149 :     * Open a file in the bin file directory.
150 :     */
151 :     PVT FILE *OpenBinFile (const char *binDir, const char *fname, bool_t isBinary)
152 :     {
153 :     char path[MAX_BOOT_PATH_LEN];
154 :     FILE *file;
155 :    
156 :     sprintf(path, "%s%c%s", binDir, PATH_ARC_SEP, fname);
157 :    
158 :     if ((file = fopen(path, isBinary ? "rb" : "r")) == NULL)
159 :     Error ("unable to open \"%s\"\n", path);
160 :    
161 :     return file;
162 :    
163 :     } /* end of OpenBinFile */
164 :    
165 :     /*
166 :     * BINFILE FORMAT description:
167 :     *
168 :     *************** The following really belongs in the header file ****************
169 :     * Every 4-byte integer field is stored in big-endian format.
170 :     *
171 :     * Start Size Purpose
172 :     * ----BEGIN OF HEADER----
173 :     * 0 16 magic string
174 :     * 16 4 number of import values (importCnt)
175 :     * 20 4 number of exports (exportCnt = currently always 0 or 1)
176 :     * 24 4 size of CM-specific info in bytes (cmInfoSzB)
177 :     * 28 4 size of pickled lambda-expression in bytes (lambdaSzB)
178 :     * 32 4 size of reserved area 1 in bytes (reserved1)
179 :     * 36 4 size of reserved area 2 in bytes (reserved2)
180 :     * 40 4 size of code area in bytes (codeSzB)
181 :     * 44 4 size of pickled environment in bytes (envSzB)
182 :     * 48 i import trees [This area contains pickled import trees --
183 :     * see below. The total number of leaves in these trees is
184 :     * importCnt. The size impSzB of this area depends on the
185 :     * shape of the trees.]
186 :     * i+48 ex export pids [Each export pid occupies 16 bytes. Thus, the
187 :     * size ex of this area is 16*exportCnt (0 or 16).]
188 :     * ex+i+48 cm CM info [Currently a list of pid-pairs.] (cm = cmInfoSzB)
189 :     * ----END OF HEADER----
190 :     * 0 h HEADER (h = 48+cm+ex+i)
191 :     * h l pickle of exported lambda-expr. (l = lambdaSzB)
192 :     * l+h r reserved areas (r = reserved1+reserved2)
193 :     * r+l+h c code area (c = codeSzB) [Structured into several
194 :     * segments -- see below.]
195 :     * c+r+l+h e pickle of static environment (e = envSzB)
196 :     * e+c+r+l+h - END OF BINFILE
197 :     *
198 :     * IMPORT TREE FORMAT description:
199 :     *
200 :     * The import tree area contains a list of (pid * tree) pairs.
201 :     * The pids are stored directly as 16-byte strings.
202 :     * Trees are constructed according to the following ML-datatype:
203 :     * datatype tree = NODE of (int * tree) list
204 :     * Leaves in this tree have the form (NODE []).
205 :     * Trees are written recursively -- (NODE l) is represented by n (= the
206 :     * length of l) followed by n (int * node) subcomponents. Each component
207 :     * consists of the integer selector followed by the corresponding tree.
208 :     *
209 :     * The size of the import tree area is only given implicitly. When reading
210 :     * this area, the reader must count the number of leaves and compare it
211 :     * with importCnt.
212 :     *
213 :     * Integer values in the import tree area (lengths and selectors) are
214 :     * written in "packed" integer format. In particular, this means that
215 :     * Values in the range 0..127 are represented by only 1 byte.
216 :     * Conceptually, the following pickling routine is used:
217 :     *
218 :     * void recur_write_ul (unsigned long l, FILE *file)
219 :     * {
220 :     * if (l != 0) {
221 :     * recur_write_ul (l >> 7, file);
222 :     * putc ((l & 0x7f) | 0x80, file);
223 :     * }
224 :     * }
225 :     *
226 :     * void write_ul (unsigned long l, FILE *file)
227 :     * {
228 :     * recur_write_ul (l >> 7, file);
229 :     * putc (l & 0x7f, file);
230 :     * }
231 :     *
232 :     * CODE AREA FORMAT description:
233 :     *
234 :     * The code area contains multiple code segements. There will be at least
235 :     * two. The very first segment is the "data" segment -- responsible for
236 :     * creating literal constants on the heap. The idea is that code in the
237 :     * data segment will be executed only once at link-time. Thus, it can
238 :     * then be garbage-collected immediatly. (In the future it is possible that
239 :     * the data segment will not contain executable code at all but some form
240 :     * of bytecode that is to be interpreted separately.)
241 :     *
242 :     * In the binfile, each code segment is represented by its size s (in
243 :     * bytes -- written as a 4-byte big-endian integer) followed by s bytes of
244 :     * machine- (or byte-) code. The total length of all code segments
245 :     * (including the bytes spent on representing individual sizes) is codeSzB.
246 :     *
247 :     * LINKING CONVENTIONS:
248 :     *
249 :     * Linking is achieved by executing all code segments in sequential order.
250 :     *
251 :     * The first code segment (i.e., the "data" segment) receives unit as
252 :     * its single argument.
253 :     *
254 :     * The second code segment receives a record as its single argument.
255 :     * This record has (importCnt+1) components. The first importCnt
256 :     * components correspond to the leaves of the import trees. The final
257 :     * component is the result from executing the data segment.
258 :     *
259 :     * All other code segments receive a single argument which is the result
260 :     * of the preceding segment.
261 :     *
262 :     * The result of the last segment represents the exports of the compilation
263 :     * unit. It is to be paired up with the export pid and stored in the
264 :     * dynamic environment. If there is no export pid, then the final result
265 :     * will be thrown away.
266 :     *
267 :     * The import trees are used for constructing the argument record for the
268 :     * second code segment. The pid at the root of each tree is the key for
269 :     * looking up a value in the existing dynamic environment. In general,
270 :     * that value will be a record. The selector fields of the import tree
271 :     * associated with the pid are used to recursively fetch components of that
272 :     * record.
273 :     */
274 :    
275 :     /* ReadBinFile:
276 :     */
277 :     PVT void ReadBinFile (
278 :     FILE *file, void *buf, int nbytes, const char *binDir, const char *fname
279 :     )
280 :     {
281 :     if (fread(buf, nbytes, 1, file) == -1)
282 :     Die ("cannot read file \"%s%c%s\"", binDir, PATH_ARC_SEP, fname);
283 :    
284 :     } /* end of ReadBinFile */
285 :    
286 :     /* ReadPackedInt32:
287 :     *
288 :     * Read an integer in "packed" format. (Small numbers only require 1 byte.)
289 :     */
290 :     PVT Int32_t ReadPackedInt32 (FILE *file, const char *binDir, const char *fname)
291 :     {
292 :     Unsigned32_t n;
293 :     Byte_t c;
294 :    
295 :     n = 0;
296 :     do {
297 :     ReadBinFile (file, &c, sizeof(c), binDir, fname);
298 :     n = (n << 7) | (c & 0x7f);
299 :     } while ((c & 0x80) != 0);
300 :    
301 :     return ((Int32_t)n);
302 :    
303 :     } /* end of ReadPackedInt32 */
304 :    
305 :     /* ImportSelection:
306 :     *
307 :     * Select out the interesting bits from the imported object.
308 :     */
309 :     PVT void ImportSelection (
310 :     ml_state_t *msp,
311 :     FILE *file,
312 :     const char *binDir,
313 :     const char *fname,
314 :     int *importVecPos,
315 :     ml_val_t tree)
316 :     {
317 :     Int32_t cnt = ReadPackedInt32 (file, binDir, fname);
318 :     if (cnt == 0) {
319 :     ML_AllocWrite (msp, *importVecPos, tree);
320 :     (*importVecPos)++;
321 :     }
322 :     else {
323 :     while (cnt-- > 0) {
324 :     Int32_t selector = ReadPackedInt32 (file, binDir, fname);
325 :     ImportSelection (
326 :     msp, file, binDir, fname, importVecPos,
327 :     REC_SEL(tree, selector));
328 :     }
329 :     }
330 :    
331 :     } /* end of ImportSelection */
332 :    
333 :     /* LoadBinFile:
334 :     */
335 : monnier 418 PVT void LoadBinFile (ml_state_t *msp, const char *binDir, char *fname)
336 : monnier 249 {
337 :     FILE *file;
338 :     int i, exportSzB, remainingCode, importRecLen;
339 :     bool_t isDataSeg;
340 :     ml_val_t codeObj, importRec, closure, val;
341 :     binfile_hdr_t hdr;
342 :     pers_id_t exportPerID;
343 :     Int32_t thisSzB;
344 : monnier 418 size_t archive_offset;
345 :     char *atptr, *colonptr;
346 :     char *objname = fname;
347 :    
348 : monnier 249
349 : monnier 418 if ((atptr = strchr (fname, '@')) == NULL)
350 :     archive_offset = 0;
351 :     else {
352 :     if ((colonptr = strchr (atptr + 1, ':')) != NULL) {
353 :     objname = colonptr + 1;
354 :     *colonptr = '\0';
355 :     }
356 :     /* not a lot of extensive checking here... */
357 :     archive_offset = strtoul (atptr + 1, NULL, 0);
358 :     *atptr = '\0';
359 :     }
360 :    
361 :     Say ("[Loading %s]\n", objname);
362 :    
363 : monnier 249 /* open the file */
364 :     file = OpenBinFile (binDir, fname, TRUE);
365 :     if (file == NULL)
366 :     Exit (1);
367 :    
368 : monnier 418 /* if an offset is given (i.e., we are probably dealing with a stable
369 :     * archive), then seek to the beginning of the section that contains
370 :     * the binfile */
371 :     if (archive_offset)
372 :     if (fseek (file, archive_offset, SEEK_SET) == -1)
373 :     Die ("cannot seek on archive file \"%s%c%s@%ul\"",
374 :     binDir, PATH_ARC_SEP, fname, (unsigned long) archive_offset);
375 :    
376 : monnier 249 /* get the header */
377 :     ReadBinFile (file, &hdr, sizeof(binfile_hdr_t), binDir, fname);
378 :    
379 :     /* get header byte order right */
380 :     hdr.importCnt = BIGENDIAN_TO_HOST(hdr.importCnt);
381 :     hdr.exportCnt = BIGENDIAN_TO_HOST(hdr.exportCnt);
382 :     hdr.importSzB = BIGENDIAN_TO_HOST(hdr.importSzB);
383 :     hdr.cmInfoSzB = BIGENDIAN_TO_HOST(hdr.cmInfoSzB);
384 :     hdr.lambdaSzB = BIGENDIAN_TO_HOST(hdr.lambdaSzB);
385 :     hdr.reserved1 = BIGENDIAN_TO_HOST(hdr.reserved1);
386 :     hdr.reserved2 = BIGENDIAN_TO_HOST(hdr.reserved2);
387 :     hdr.codeSzB = BIGENDIAN_TO_HOST(hdr.codeSzB);
388 :     hdr.envSzB = BIGENDIAN_TO_HOST(hdr.envSzB);
389 :    
390 :     /* read the import PerIDs, and create the import vector */
391 :     {
392 :     int importVecPos;
393 :    
394 :     importRecLen = hdr.importCnt + 1;
395 :    
396 :     if (NeedGC (msp, REC_SZB(importRecLen)))
397 :     InvokeGCWithRoots (msp, 0, &BinFileList, NIL(ml_val_t *));
398 :    
399 :     ML_AllocWrite (msp, 0, MAKE_DESC(importRecLen, DTAG_record));
400 :     for (importVecPos = 1; importVecPos < importRecLen; ) {
401 :     pers_id_t importPid;
402 :     ReadBinFile (file, &importPid, sizeof(pers_id_t), binDir, fname);
403 :     ImportSelection (
404 :     msp, file, binDir, fname, &importVecPos,
405 :     LookupPerID(&importPid));
406 :     }
407 :     ML_AllocWrite(msp, importRecLen, ML_nil);
408 :     importRec = ML_Alloc(msp, importRecLen);
409 :     }
410 :    
411 :     /* read the export PerID */
412 :     if (hdr.exportCnt == 1) {
413 :     exportSzB = sizeof(pers_id_t);
414 :     ReadBinFile (file, &exportPerID, exportSzB, binDir, fname);
415 :     }
416 :     else if (hdr.exportCnt != 0)
417 :     Die ("# of export pids is %d (should be 0 or 1)", (int)hdr.exportCnt);
418 :     else
419 :     exportSzB = 0;
420 :    
421 :     /* seek to code section */
422 :     {
423 : monnier 418 long off = archive_offset
424 :     + sizeof(binfile_hdr_t)
425 : monnier 249 + hdr.importSzB
426 :     + exportSzB
427 :     + hdr.cmInfoSzB
428 :     + hdr.lambdaSzB
429 :     + hdr.reserved1 + hdr.reserved2;
430 :    
431 :     if (fseek(file, off, SEEK_SET) == -1)
432 : monnier 418 Die ("cannot seek on bin file \"%s%c%s\"",
433 :     binDir, PATH_ARC_SEP, fname);
434 : monnier 249 }
435 :    
436 :     /* Read code objects and run them. The first code object will be the
437 :     * data segment. We add a comment string to each code object to mark
438 :     * which bin file it came from. This code should be the same as that
439 :     * in ../c-libs/smlnj-runtime/mkcode.c.
440 :     */
441 :    
442 :     remainingCode = hdr.codeSzB;
443 :    
444 :     /* read the size for the data object */
445 :     ReadBinFile (file, &thisSzB, sizeof(Int32_t), binDir, fname);
446 :     thisSzB = BIGENDIAN_TO_HOST(thisSzB);
447 :    
448 :     remainingCode -= thisSzB + sizeof(Int32_t);
449 :     if (remainingCode < 0)
450 :     Die ("format error (data size mismatch) in bin file \"%s%c%s\"",
451 :     binDir, PATH_ARC_SEP, fname);
452 :    
453 :     if (thisSzB > 0) {
454 :     Byte_t *dataObj = NEW_VEC(Byte_t, thisSzB);
455 :    
456 :     ReadBinFile (file, dataObj, thisSzB, binDir, fname);
457 :     SaveCState (msp, &BinFileList, &importRec, NIL(ml_val_t *));
458 :     val = BuildLiterals (msp, dataObj, thisSzB);
459 :     FREE(dataObj);
460 :     RestoreCState (msp, &BinFileList, &importRec, NIL(ml_val_t *));
461 :     }
462 :     else {
463 :     val = ML_unit;
464 :     }
465 :     /* do a functional update of the last element of the importRec. */
466 :     for (i = 0; i < importRecLen; i++)
467 :     ML_AllocWrite(msp, i, PTR_MLtoC(ml_val_t, importRec)[i-1]);
468 :     ML_AllocWrite(msp, importRecLen, val);
469 :     val = ML_Alloc(msp, importRecLen);
470 :     /* do a GC, if necessary */
471 :     if (NeedGC (msp, PERID_LEN+REC_SZB(5)))
472 :     InvokeGCWithRoots (msp, 0, &BinFileList, &val, NIL(ml_val_t *));
473 :    
474 :     while (remainingCode > 0) {
475 :     int strLen, padLen, extraLen;
476 :    
477 :     /* read the size for this code object */
478 :     ReadBinFile (file, &thisSzB, sizeof(Int32_t), binDir, fname);
479 :     thisSzB = BIGENDIAN_TO_HOST(thisSzB);
480 :    
481 :     /* We use one byte for the length, so the longest string is 255
482 :     * characters. We need padding so that the code + string +
483 :     * length byte is WORD_SZB bytes. The padding is inserted between
484 :     * the code and the string.
485 :     */
486 : monnier 418 strLen = strlen(objname);
487 : monnier 249 if (strLen > 255)
488 :     strLen = 255;
489 :     extraLen = strLen+1; /* include byte for length */
490 :     padLen = ROUNDUP(thisSzB+extraLen, WORD_SZB) - (thisSzB+extraLen);
491 :     extraLen += padLen;
492 :    
493 :     /* how much more? */
494 :     remainingCode -= thisSzB + sizeof(Int32_t);
495 :     if (remainingCode < 0)
496 :     Die ("format error (code size mismatch) in bin file \"%s%c%s\"",
497 :     binDir, PATH_ARC_SEP, fname);
498 :    
499 :     /* allocate space and read code object */
500 :     codeObj = ML_AllocCode (msp, thisSzB+extraLen);
501 :     ReadBinFile (file, PTR_MLtoC(char, codeObj), thisSzB, binDir, fname);
502 :    
503 :     /* tack on the bin-file name as a comment string. */
504 : monnier 418 memcpy (PTR_MLtoC(char, codeObj)+thisSzB+padLen, objname, strLen);
505 : monnier 249 *(PTR_MLtoC(Byte_t, codeObj)+thisSzB+extraLen-1) = (Byte_t)strLen;
506 :    
507 :     FlushICache (PTR_MLtoC(char, codeObj), thisSzB);
508 :    
509 :     /* create closure */
510 :     REC_ALLOC1 (msp, closure, codeObj);
511 :    
512 :     /* apply the closure to the import PerID vector */
513 :     SaveCState (msp, &BinFileList, NIL(ml_val_t *));
514 :     val = ApplyMLFn (msp, closure, val, TRUE);
515 :     RestoreCState (msp, &BinFileList, NIL(ml_val_t *));
516 :    
517 :     /* do a GC, if necessary */
518 :     if (NeedGC (msp, PERID_LEN+REC_SZB(5)))
519 :     InvokeGCWithRoots (msp, 0, &BinFileList, &val, NIL(ml_val_t *));
520 :     }
521 :    
522 :     /* record the resulting exported PerID */
523 :     if (exportSzB != 0)
524 :     EnterPerID (msp, &exportPerID, val);
525 :    
526 :     fclose (file);
527 :    
528 :     } /* end of LoadBinFile */
529 :    
530 :     /* EnterPerID:
531 :     *
532 :     * Enter a PerID/object binding in the heap allocated list of PerIDs.
533 :     */
534 :     PVT void EnterPerID (ml_state_t *msp, pers_id_t *perID, ml_val_t obj)
535 :     {
536 :     ml_val_t mlPerID;
537 :    
538 :     /* Allocate space for the PerID */
539 :     mlPerID = ML_AllocString (msp, PERID_LEN);
540 :     memcpy (STR_MLtoC(mlPerID), (char *)perID, PERID_LEN);
541 :    
542 :     /* Allocate the list element */
543 :     REC_ALLOC3(msp, PerIDList, mlPerID, obj, PerIDList);
544 :    
545 :     }
546 :    
547 :     /* LookupPerID:
548 :     */
549 :     PVT ml_val_t LookupPerID (pers_id_t *perID)
550 :     {
551 :     ml_val_t p, id;
552 :    
553 :     for (p = PerIDList; p != ML_unit; p = REC_SEL(p, 2)) {
554 :     id = REC_SEL(p, 0);
555 :     if (memcmp((char *)perID, STR_MLtoC(id), PERID_LEN) == 0)
556 :     return (REC_SEL(p, 1));
557 :     }
558 :    
559 :     {
560 :     char buf[64];
561 :     ShowPerID (buf, perID);
562 :     Die ("unable to find PerID %s", buf);
563 :     }
564 :    
565 :     } /* end of LookupPerID */
566 :    
567 :    
568 :     /* ShowPerID:
569 :     */
570 :     PVT void ShowPerID (char *buf, pers_id_t *perID)
571 :     {
572 :     char *cp = buf;
573 :     int i;
574 :    
575 :     *cp++ = '[';
576 :     for (i = 0; i < PERID_LEN; i++) {
577 :     sprintf (cp, "%02x", perID->bytes[i]);
578 :     cp += 2;
579 :     }
580 :     *cp++ = ']';
581 :     *cp++ = '\0';
582 :    
583 :     } /* end of ShowPerID */

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0