Merge pull request #60 from philburk/usefromjuce
[debian/pforth] / csrc / pf_save.c
1 /* @(#) pf_save.c 98/01/26 1.3 */
2 /***************************************************************
3 ** Save and Load Dictionary
4 ** for PForth based on 'C'
5 **
6 ** Compile file based version or static data based version
7 ** depending on PF_NO_FILEIO switch.
8 **
9 ** Author: Phil Burk
10 ** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom
11 **
12 ** The pForth software code is dedicated to the public domain,
13 ** and any third party may reproduce, distribute and modify
14 ** the pForth software code or any derivative works thereof
15 ** without any compensation or license.  The pForth software
16 ** code is provided on an "as is" basis without any warranty
17 ** of any kind, including, without limitation, the implied
18 ** warranties of merchantability and fitness for a particular
19 ** purpose and their equivalents under the laws of any jurisdiction.
20 **
21 ****************************************************************
22 ** 940225 PLB Fixed CodePtr save, was using NAMEREL instead of CODEREL
23 **            This would only work if the relative location
24 **            of names and code was the same when saved and reloaded.
25 ** 940228 PLB Added PF_NO_FILEIO version
26 ** 961204 PLB Added PF_STATIC_DIC
27 ** 000623 PLB Cast chars as ucell_t before shifting for 16 bit systems.
28 ***************************************************************/
29
30 #include <assert.h>
31
32 #include "pf_all.h"
33
34 /* If no File I/O, then force static dictionary. */
35 #ifdef PF_NO_FILEIO
36     #ifndef PF_STATIC_DIC
37         #define PF_STATIC_DIC
38     #endif
39 #endif
40
41 #ifdef PF_STATIC_DIC
42     #include "pfdicdat.h"
43 #endif
44
45 /*
46 Dictionary File Format based on IFF standard.
47 The chunk IDs, sizes, and data values are all Big Endian in conformance with the IFF standard.
48 The dictionaries may be big or little endian.
49     'FORM'
50     size
51     'P4TH'  -  Form Identifier
52
53 Chunks
54     'P4DI'
55     size
56     struct DictionaryInfoChunk
57
58     'P4NM'
59     size
60     Name and Header portion of dictionary. (Big or Little Endian) (Optional)
61
62     'P4CD'
63     size
64     Code portion of dictionary. (Big or Little Endian)
65 */
66
67
68 /***************************************************************/
69 /* Endian-ness tools. */
70 ucell_t ReadCellBigEndian( const uint8_t *addr )
71 {
72     ucell_t temp = (ucell_t)addr[0];
73     temp = (temp << 8) | ((ucell_t)addr[1]);
74     temp = (temp << 8) | ((ucell_t)addr[2]);
75     temp = (temp << 8) | ((ucell_t)addr[3]);
76     if( sizeof(ucell_t) == 8 )
77     {
78         temp = (temp << 8) | ((ucell_t)addr[4]);
79         temp = (temp << 8) | ((ucell_t)addr[5]);
80         temp = (temp << 8) | ((ucell_t)addr[6]);
81         temp = (temp << 8) | ((ucell_t)addr[7]);
82     }
83
84     return temp;
85 }
86 /***************************************************************/
87 /* Endian-ness tools. */
88 uint32_t Read32BigEndian( const uint8_t *addr )
89 {
90     uint32_t temp = (uint32_t)addr[0];
91     temp = (temp << 8) | ((uint32_t)addr[1]);
92     temp = (temp << 8) | ((uint32_t)addr[2]);
93     temp = (temp << 8) | ((uint32_t)addr[3]);
94     return temp;
95 }
96
97 /***************************************************************/
98 uint16_t Read16BigEndian( const uint8_t *addr )
99 {
100     return (uint16_t) ((addr[0]<<8) | addr[1]);
101 }
102
103 /***************************************************************/
104 ucell_t ReadCellLittleEndian( const uint8_t *addr )
105 {
106     ucell_t temp = 0;
107     if( sizeof(ucell_t) == 8 )
108     {
109         temp = (temp << 8) | ((uint32_t)addr[7]);
110         temp = (temp << 8) | ((uint32_t)addr[6]);
111         temp = (temp << 8) | ((uint32_t)addr[5]);
112         temp = (temp << 8) | ((uint32_t)addr[4]);
113     }
114     temp = (temp << 8) | ((uint32_t)addr[3]);
115     temp = (temp << 8) | ((uint32_t)addr[2]);
116     temp = (temp << 8) | ((uint32_t)addr[1]);
117     temp = (temp << 8) | ((uint32_t)addr[0]);
118     return temp;
119 }
120
121 /***************************************************************/
122 uint32_t Read32LittleEndian( const uint8_t *addr )
123 {
124     uint32_t temp = (uint32_t)addr[3];
125     temp = (temp << 8) | ((uint32_t)addr[2]);
126     temp = (temp << 8) | ((uint32_t)addr[1]);
127     temp = (temp << 8) | ((uint32_t)addr[0]);
128     return temp;
129 }
130
131 /***************************************************************/
132 uint16_t Read16LittleEndian( const uint8_t *addr )
133 {
134     const unsigned char *bp = (const unsigned char *) addr;
135     return (uint16_t) ((bp[1]<<8) | bp[0]);
136 }
137
138 #ifdef PF_SUPPORT_FP
139
140 /***************************************************************/
141 static void ReverseCopyFloat( const PF_FLOAT *src, PF_FLOAT *dst );
142
143 static void ReverseCopyFloat( const PF_FLOAT *src, PF_FLOAT *dst )
144 {
145     int i;
146     unsigned char *d = (unsigned char *) dst;
147     const unsigned char *s = (const unsigned char *) src;
148
149     for( i=0; i<sizeof(PF_FLOAT); i++ )
150     {
151         d[i] = s[sizeof(PF_FLOAT) - 1 - i];
152     }
153 }
154
155 /***************************************************************/
156 void WriteFloatBigEndian( PF_FLOAT *addr, PF_FLOAT data )
157 {
158     if( IsHostLittleEndian() )
159     {
160         ReverseCopyFloat( &data, addr );
161     }
162     else
163     {
164         *addr = data;
165     }
166 }
167
168 /***************************************************************/
169 PF_FLOAT ReadFloatBigEndian( const PF_FLOAT *addr )
170 {
171     PF_FLOAT data;
172     if( IsHostLittleEndian() )
173     {
174         ReverseCopyFloat( addr, &data );
175         return data;
176     }
177     else
178     {
179         return *addr;
180     }
181 }
182
183 /***************************************************************/
184 void WriteFloatLittleEndian( PF_FLOAT *addr, PF_FLOAT data )
185 {
186     if( IsHostLittleEndian() )
187     {
188         *addr = data;
189     }
190     else
191     {
192         ReverseCopyFloat( &data, addr );
193     }
194 }
195
196 /***************************************************************/
197 PF_FLOAT ReadFloatLittleEndian( const PF_FLOAT *addr )
198 {
199     PF_FLOAT data;
200     if( IsHostLittleEndian() )
201     {
202         return *addr;
203     }
204     else
205     {
206         ReverseCopyFloat( addr, &data );
207         return data;
208     }
209 }
210
211 #endif /* PF_SUPPORT_FP */
212
213 /***************************************************************/
214 void WriteCellBigEndian( uint8_t *addr, ucell_t data )
215 {
216     /* Write should be in order of increasing address
217      * to optimize for burst writes to DRAM. */
218     if( sizeof(ucell_t) == 8 )
219     {
220         *addr++ = (uint8_t) (data>>56);
221         *addr++ = (uint8_t) (data>>48);
222         *addr++ = (uint8_t) (data>>40);
223         *addr++ = (uint8_t) (data>>32);
224     }
225     *addr++ = (uint8_t) (data>>24);
226     *addr++ = (uint8_t) (data>>16);
227     *addr++ = (uint8_t) (data>>8);
228     *addr = (uint8_t) (data);
229 }
230
231 /***************************************************************/
232 void Write32BigEndian( uint8_t *addr, uint32_t data )
233 {
234     *addr++ = (uint8_t) (data>>24);
235     *addr++ = (uint8_t) (data>>16);
236     *addr++ = (uint8_t) (data>>8);
237     *addr = (uint8_t) (data);
238 }
239
240 /***************************************************************/
241 void Write16BigEndian( uint8_t *addr, uint16_t data )
242 {
243     *addr++ = (uint8_t) (data>>8);
244     *addr = (uint8_t) (data);
245 }
246
247 /***************************************************************/
248 void WriteCellLittleEndian( uint8_t *addr, ucell_t data )
249 {
250     /* Write should be in order of increasing address
251      * to optimize for burst writes to DRAM. */
252     if( sizeof(ucell_t) == 8 )
253     {
254         *addr++ = (uint8_t) data;  /* LSB at near end */
255         data = data >> 8;
256         *addr++ = (uint8_t) data;
257         data = data >> 8;
258         *addr++ = (uint8_t) data;
259         data = data >> 8;
260         *addr++ = (uint8_t) data;
261         data = data >> 8;
262     }
263     *addr++ = (uint8_t) data;
264     data = data >> 8;
265     *addr++ = (uint8_t) data;
266     data = data >> 8;
267     *addr++ = (uint8_t) data;
268     data = data >> 8;
269     *addr = (uint8_t) data;
270 }
271 /***************************************************************/
272 void Write32LittleEndian( uint8_t *addr, uint32_t data )
273 {
274     *addr++ = (uint8_t) data;
275     data = data >> 8;
276     *addr++ = (uint8_t) data;
277     data = data >> 8;
278     *addr++ = (uint8_t) data;
279     data = data >> 8;
280     *addr = (uint8_t) data;
281 }
282
283 /***************************************************************/
284 void Write16LittleEndian( uint8_t *addr, uint16_t data )
285 {
286     *addr++ = (uint8_t) data;
287     data = data >> 8;
288     *addr = (uint8_t) data;
289 }
290
291 /***************************************************************/
292 /* Return 1 if host CPU is Little Endian */
293 int IsHostLittleEndian( void )
294 {
295     static int gEndianCheck = 1;
296     unsigned char *bp = (unsigned char *) &gEndianCheck;
297     return (int) (*bp); /* Return byte pointed to by address. If LSB then == 1 */
298 }
299
300 #if defined(PF_NO_FILEIO) || defined(PF_NO_SHELL)
301
302 cell_t ffSaveForth( const char *FileName, ExecToken EntryPoint, cell_t NameSize, cell_t CodeSize)
303 {
304     TOUCH(FileName);
305     TOUCH(EntryPoint);
306     TOUCH(NameSize);
307     TOUCH(CodeSize);
308
309     pfReportError("ffSaveForth", PF_ERR_NOT_SUPPORTED);
310     return -1;
311 }
312
313 #else /* PF_NO_FILEIO or PF_NO_SHELL */
314
315 /***************************************************************/
316 static int Write32ToFile( FileStream *fid, uint32_t Val )
317 {
318     size_t numw;
319     uint8_t pad[4];
320
321     Write32BigEndian(pad,Val);
322     numw = sdWriteFile( pad, 1, sizeof(pad), fid );
323     if( numw != sizeof(pad) ) return -1;
324     return 0;
325 }
326
327 /***************************************************************/
328 static cell_t WriteChunkToFile( FileStream *fid, cell_t ID, char *Data, int32_t NumBytes )
329 {
330     cell_t numw;
331     cell_t EvenNumW;
332
333     EvenNumW = EVENUP(NumBytes);
334
335     assert(ID <= UINT32_MAX);
336     if( Write32ToFile( fid, (uint32_t)ID ) < 0 ) goto error;
337     assert(EvenNumW <= UINT32_MAX);
338     if( Write32ToFile( fid, (uint32_t)EvenNumW ) < 0 ) goto error;
339
340     numw = sdWriteFile( Data, 1, EvenNumW, fid );
341     if( numw != EvenNumW ) goto error;
342     return 0;
343 error:
344     pfReportError("WriteChunkToFile", PF_ERR_WRITE_FILE);
345     return -1;
346 }
347
348 /* Convert dictionary info chunk between native and on-disk (big-endian). */
349 static void
350 convertDictionaryInfoWrite (DictionaryInfoChunk *sd)
351 {
352 /* Convert all fields in DictionaryInfoChunk from Native to BigEndian.
353  * This assumes they are all 32-bit integers.
354  */
355     int   i;
356     uint32_t *p = (uint32_t *) sd;
357     for (i=0; i<((int)(sizeof(*sd)/sizeof(uint32_t))); i++)
358     {
359         Write32BigEndian( (uint8_t *)&p[i], p[i] );
360     }
361 }
362
363 static void
364 convertDictionaryInfoRead (DictionaryInfoChunk *sd)
365 {
366 /* Convert all fields in structure from BigEndian to Native. */
367     int   i;
368     uint32_t *p = (uint32_t *) sd;
369     for (i=0; i<((int)(sizeof(*sd)/sizeof(uint32_t))); i++)
370     {
371         p[i] = Read32BigEndian( (uint8_t *)&p[i] );
372     }
373 }
374
375 /****************************************************************
376 ** Save Dictionary in File.
377 ** If EntryPoint is NULL, save as development environment.
378 ** If EntryPoint is non-NULL, save as turnKey environment with no names.
379 */
380 cell_t ffSaveForth( const char *FileName, ExecToken EntryPoint, cell_t NameSize, cell_t CodeSize)
381 {
382     FileStream *fid;
383     DictionaryInfoChunk SD;
384     uint32_t FormSize;
385     uint32_t NameChunkSize = 0;
386     uint32_t CodeChunkSize;
387     uint32_t relativeCodePtr;
388
389     fid = sdOpenFile( FileName, "wb" );
390     if( fid == NULL )
391     {
392         pfReportError("pfSaveDictionary", PF_ERR_OPEN_FILE);
393         return -1;
394     }
395
396 /* Save in uninitialized form. */
397     pfExecIfDefined("AUTO.TERM");
398
399 /* Write FORM Header ---------------------------- */
400     if( Write32ToFile( fid, ID_FORM ) < 0 ) goto error;
401     if( Write32ToFile( fid, 0 ) < 0 ) goto error;
402     if( Write32ToFile( fid, ID_P4TH ) < 0 ) goto error;
403
404 /* Write P4DI Dictionary Info  ------------------ */
405     SD.sd_Version = PF_FILE_VERSION;
406
407     relativeCodePtr = ABS_TO_CODEREL(gCurrentDictionary->dic_CodePtr.Byte); /* 940225 */
408     SD.sd_RelCodePtr = relativeCodePtr;
409     SD.sd_UserStackSize = sizeof(cell_t) * (gCurrentTask->td_StackBase - gCurrentTask->td_StackLimit);
410     SD.sd_ReturnStackSize = sizeof(cell_t) * (gCurrentTask->td_ReturnBase - gCurrentTask->td_ReturnLimit);
411     SD.sd_NumPrimitives = gNumPrimitives;  /* Must match compiled dictionary. */
412
413 #ifdef PF_SUPPORT_FP
414     SD.sd_FloatSize = sizeof(PF_FLOAT);  /* Must match compiled dictionary. */
415 #else
416     SD.sd_FloatSize = 0;
417 #endif
418
419     SD.sd_CellSize = sizeof(cell_t);
420
421 /* Set bit that specifies whether dictionary is BIG or LITTLE Endian. */
422     {
423 #if defined(PF_BIG_ENDIAN_DIC)
424         int eflag = SD_F_BIG_ENDIAN_DIC;
425 #elif defined(PF_LITTLE_ENDIAN_DIC)
426         int eflag = 0;
427 #else
428         int eflag = IsHostLittleEndian() ? 0 : SD_F_BIG_ENDIAN_DIC;
429 #endif
430         SD.sd_Flags = eflag;
431     }
432
433     if( EntryPoint )
434     {
435         SD.sd_EntryPoint = EntryPoint;  /* Turnkey! */
436     }
437     else
438     {
439         SD.sd_EntryPoint = 0;
440     }
441
442 /* Do we save names? */
443     if( NameSize == 0 )
444     {
445         SD.sd_RelContext = 0;
446         SD.sd_RelHeaderPtr = 0;
447         SD.sd_NameSize = 0;
448     }
449     else
450     {
451         uint32_t relativeHeaderPtr;
452 /* Development mode. */
453         SD.sd_RelContext = ABS_TO_NAMEREL(gVarContext);
454         relativeHeaderPtr = ABS_TO_NAMEREL(gCurrentDictionary->dic_HeaderPtr);
455         SD.sd_RelHeaderPtr = relativeHeaderPtr;
456
457 /* How much real name space is there? */
458         NameChunkSize = QUADUP(relativeHeaderPtr);  /* Align */
459
460 /* NameSize must be 0 or greater than NameChunkSize + 1K */
461         NameSize = QUADUP(NameSize);  /* Align */
462         if( NameSize > 0 )
463         {
464             NameSize = MAX( (ucell_t)NameSize, (NameChunkSize + 1024) );
465         }
466         SD.sd_NameSize = NameSize;
467     }
468
469 /* How much real code is there? */
470     CodeChunkSize = QUADUP(relativeCodePtr);
471     CodeSize = QUADUP(CodeSize);  /* Align */
472     CodeSize = MAX( (ucell_t)CodeSize, (CodeChunkSize + 2048) );
473     SD.sd_CodeSize = CodeSize;
474
475
476     convertDictionaryInfoWrite (&SD);
477
478     if( WriteChunkToFile( fid, ID_P4DI, (char *) &SD, sizeof(DictionaryInfoChunk) ) < 0 ) goto error;
479
480 /* Write Name Fields if NameSize non-zero ------- */
481     if( NameSize > 0 )
482     {
483         if( WriteChunkToFile( fid, ID_P4NM, (char *) NAME_BASE,
484             NameChunkSize ) < 0 ) goto error;
485     }
486
487 /* Write Code Fields ---------------------------- */
488     if( WriteChunkToFile( fid, ID_P4CD, (char *) CODE_BASE,
489         CodeChunkSize ) < 0 ) goto error;
490
491     FormSize = (uint32_t) sdTellFile( fid ) - 8;
492     sdSeekFile( fid, 4, PF_SEEK_SET );
493     if( Write32ToFile( fid, FormSize ) < 0 ) goto error;
494
495     sdCloseFile( fid );
496
497 /* Restore initialization. */
498     pfExecIfDefined("AUTO.INIT");
499     return 0;
500
501 error:
502     sdSeekFile( fid, 0, PF_SEEK_SET );
503     Write32ToFile( fid, ID_BADF ); /* Mark file as bad. */
504     sdCloseFile( fid );
505
506 /* Restore initialization. */
507     pfExecIfDefined("AUTO.INIT");
508
509     return -1;
510 }
511
512 #endif /* !PF_NO_FILEIO and !PF_NO_SHELL */
513
514
515 #ifndef PF_NO_FILEIO
516
517 /***************************************************************/
518 static int32_t Read32FromFile( FileStream *fid, uint32_t *ValPtr )
519 {
520     cell_t numr;
521     uint8_t pad[4];
522     numr = sdReadFile( pad, 1, sizeof(pad), fid );
523     if( numr != sizeof(pad) ) return -1;
524     *ValPtr = Read32BigEndian( pad );
525     return 0;
526 }
527
528 /***************************************************************/
529 PForthDictionary pfLoadDictionary( const char *FileName, ExecToken *EntryPointPtr )
530 {
531     pfDictionary_t *dic = NULL;
532     FileStream *fid;
533     DictionaryInfoChunk *sd;
534     uint32_t ChunkID;
535     uint32_t ChunkSize;
536     uint32_t FormSize;
537     uint32_t BytesLeft;
538     cell_t numr;
539     int   isDicBigEndian;
540
541 DBUG(("pfLoadDictionary( %s )\n", FileName ));
542
543 /* Open file. */
544     fid = sdOpenFile( FileName, "rb" );
545     if( fid == NULL )
546     {
547         pfReportError("pfLoadDictionary", PF_ERR_OPEN_FILE);
548         goto xt_error;
549     }
550
551 /* Read FORM, Size, ID */
552     if (Read32FromFile( fid, &ChunkID ) < 0) goto read_error;
553     if( ChunkID != ID_FORM )
554     {
555         pfReportError("pfLoadDictionary", PF_ERR_WRONG_FILE);
556         goto error;
557     }
558
559     if (Read32FromFile( fid, &FormSize ) < 0) goto read_error;
560     BytesLeft = FormSize;
561
562     if (Read32FromFile( fid, &ChunkID ) < 0) goto read_error;
563     BytesLeft -= 4;
564     if( ChunkID != ID_P4TH )
565     {
566         pfReportError("pfLoadDictionary", PF_ERR_BAD_FILE);
567         goto error;
568     }
569
570 /* Scan and parse all chunks in file. */
571     while( BytesLeft > 0 )
572     {
573         if (Read32FromFile( fid, &ChunkID ) < 0) goto read_error;
574         if (Read32FromFile( fid, &ChunkSize ) < 0) goto read_error;
575         BytesLeft -= 8;
576
577         DBUG(("ChunkID = %4s, Size = %d\n", (char *)&ChunkID, ChunkSize ));
578
579         switch( ChunkID )
580         {
581         case ID_P4DI:
582             sd = (DictionaryInfoChunk *) pfAllocMem( ChunkSize );
583             if( sd == NULL ) goto nomem_error;
584
585             numr = sdReadFile( sd, 1, ChunkSize, fid );
586             if( numr != ChunkSize ) goto read_error;
587             BytesLeft -= ChunkSize;
588
589             convertDictionaryInfoRead (sd);
590
591             isDicBigEndian = sd->sd_Flags & SD_F_BIG_ENDIAN_DIC;
592
593             if( !gVarQuiet )
594             {
595                 MSG("pForth loading dictionary from file "); MSG(FileName);
596                     EMIT_CR;
597                 MSG_NUM_D("     File format version is ", sd->sd_Version );
598                 MSG_NUM_D("     Name space size = ", sd->sd_NameSize );
599                 MSG_NUM_D("     Code space size = ", sd->sd_CodeSize );
600                 MSG_NUM_D("     Entry Point     = ", sd->sd_EntryPoint );
601                 MSG_NUM_D("     Cell Size       = ", sd->sd_CellSize );
602                 MSG( (isDicBigEndian ? "     Big Endian Dictionary" :
603                                        "     Little  Endian Dictionary") );
604                 if( isDicBigEndian == IsHostLittleEndian() ) MSG(" !!!!");
605                     EMIT_CR;
606             }
607
608             if( sd->sd_Version > PF_FILE_VERSION )
609             {
610                 pfReportError("pfLoadDictionary", PF_ERR_VERSION_FUTURE );
611                 goto error;
612             }
613             if( sd->sd_Version < PF_EARLIEST_FILE_VERSION )
614             {
615                 pfReportError("pfLoadDictionary", PF_ERR_VERSION_PAST );
616                 goto error;
617             }
618             if( sd->sd_CellSize != sizeof(cell_t) )
619             {
620                 pfReportError("pfLoadDictionary", PF_ERR_CELL_SIZE_CONFLICT );
621                 goto error;
622             }
623             if( sd->sd_NumPrimitives > NUM_PRIMITIVES )
624             {
625                 pfReportError("pfLoadDictionary", PF_ERR_NOT_SUPPORTED );
626                 goto error;
627             }
628
629 /* Check to make sure that EndianNess of dictionary matches mode of pForth. */
630 #if defined(PF_BIG_ENDIAN_DIC)
631             if(isDicBigEndian == 0)
632 #elif defined(PF_LITTLE_ENDIAN_DIC)
633             if(isDicBigEndian == 1)
634 #else
635             if( isDicBigEndian == IsHostLittleEndian() )
636 #endif
637             {
638                 pfReportError("pfLoadDictionary", PF_ERR_ENDIAN_CONFLICT );
639                 goto error;
640             }
641
642 /* Check for compatible float size. */
643 #ifdef PF_SUPPORT_FP
644             if( sd->sd_FloatSize != sizeof(PF_FLOAT) )
645 #else
646             if( sd->sd_FloatSize != 0 )
647 #endif
648             {
649                 pfReportError("pfLoadDictionary", PF_ERR_FLOAT_CONFLICT );
650                 goto error;
651             }
652
653             dic = pfCreateDictionary( sd->sd_NameSize, sd->sd_CodeSize );
654             if( dic == NULL ) goto nomem_error;
655             gCurrentDictionary = dic;
656             if( sd->sd_NameSize > 0 )
657             {
658                 gVarContext = NAMEREL_TO_ABS(sd->sd_RelContext); /* Restore context. */
659                 gCurrentDictionary->dic_HeaderPtr = (ucell_t)(uint8_t *)
660                     NAMEREL_TO_ABS(sd->sd_RelHeaderPtr);
661             }
662             else
663             {
664                 gVarContext = 0;
665                 gCurrentDictionary->dic_HeaderPtr = (ucell_t)NULL;
666             }
667             gCurrentDictionary->dic_CodePtr.Byte = (uint8_t *) CODEREL_TO_ABS(sd->sd_RelCodePtr);
668             gNumPrimitives = sd->sd_NumPrimitives;  /* Must match compiled dictionary. */
669 /* Pass EntryPoint back to caller. */
670             if( EntryPointPtr != NULL ) *EntryPointPtr = sd->sd_EntryPoint;
671             pfFreeMem(sd);
672             break;
673
674         case ID_P4NM:
675 #ifdef PF_NO_SHELL
676             pfReportError("pfLoadDictionary", PF_ERR_NO_SHELL );
677             goto error;
678 #else
679             if( NAME_BASE == 0 )
680             {
681                 pfReportError("pfLoadDictionary", PF_ERR_NO_NAMES );
682                 goto error;
683             }
684             if( gCurrentDictionary == NULL )
685             {
686                 pfReportError("pfLoadDictionary", PF_ERR_BAD_FILE );
687                 goto error;
688             }
689             if( ChunkSize > NAME_SIZE )
690             {
691                 pfReportError("pfLoadDictionary", PF_ERR_TOO_BIG);
692                 goto error;
693             }
694             numr = sdReadFile( (char *) NAME_BASE, 1, ChunkSize, fid );
695             if( numr != ChunkSize ) goto read_error;
696             BytesLeft -= ChunkSize;
697 #endif /* PF_NO_SHELL */
698             break;
699
700         case ID_P4CD:
701             if( gCurrentDictionary == NULL )
702             {
703                 pfReportError("pfLoadDictionary", PF_ERR_BAD_FILE );
704                 goto error;
705             }
706             if( ChunkSize > CODE_SIZE )
707             {
708                 pfReportError("pfLoadDictionary", PF_ERR_TOO_BIG);
709                 goto error;
710             }
711             numr = sdReadFile( (uint8_t *) CODE_BASE, 1, ChunkSize, fid );
712             if( numr != ChunkSize ) goto read_error;
713             BytesLeft -= ChunkSize;
714             break;
715
716         default:
717             pfReportError("pfLoadDictionary", PF_ERR_BAD_FILE );
718             sdSeekFile( fid, ChunkSize, PF_SEEK_CUR );
719             break;
720         }
721     }
722
723     sdCloseFile( fid );
724
725     if( NAME_BASE != 0)
726     {
727         cell_t Result;
728 /* Find special words in dictionary for global XTs. */
729         if( (Result = FindSpecialXTs()) < 0 )
730         {
731             pfReportError("pfLoadDictionary: FindSpecialXTs", (Err)Result);
732             goto error;
733         }
734     }
735
736 DBUG(("pfLoadDictionary: return %p\n", dic));
737     return (PForthDictionary) dic;
738
739 nomem_error:
740     pfReportError("pfLoadDictionary", PF_ERR_NO_MEM);
741     sdCloseFile( fid );
742     return NULL;
743
744 read_error:
745     pfReportError("pfLoadDictionary", PF_ERR_READ_FILE);
746 error:
747     sdCloseFile( fid );
748 xt_error:
749     return NULL;
750 }
751
752 #else
753
754 PForthDictionary pfLoadDictionary( const char *FileName, ExecToken *EntryPointPtr )
755 {
756     (void) FileName;
757     (void) EntryPointPtr;
758     return NULL;
759 }
760 #endif /* !PF_NO_FILEIO */
761
762
763
764 /***************************************************************/
765 PForthDictionary pfLoadStaticDictionary( void )
766 {
767 #ifdef PF_STATIC_DIC
768     cell_t Result;
769     pfDictionary_t *dic;
770     cell_t NewNameSize, NewCodeSize;
771
772     if( IF_LITTLE_ENDIAN != IsHostLittleEndian() )
773     {
774         MSG( (IF_LITTLE_ENDIAN ?
775                  "Little Endian Dictionary on " :
776                  "Big Endian Dictionary on ") );
777         MSG( (IsHostLittleEndian() ?
778                  "Little Endian CPU" :
779                  "Big Endian CPU") );
780         EMIT_CR;
781     }
782
783 /* Check to make sure that EndianNess of dictionary matches mode of pForth. */
784 #if defined(PF_BIG_ENDIAN_DIC)
785     if(IF_LITTLE_ENDIAN == 1)
786 #elif defined(PF_LITTLE_ENDIAN_DIC)
787     if(IF_LITTLE_ENDIAN == 0)
788 #else /* Code is native endian! */
789     if( IF_LITTLE_ENDIAN != IsHostLittleEndian() )
790 #endif
791     {
792         pfReportError("pfLoadStaticDictionary", PF_ERR_ENDIAN_CONFLICT );
793         goto error;
794     }
795
796
797 #ifndef PF_EXTRA_HEADERS
798     #define PF_EXTRA_HEADERS  (20000)
799 #endif
800 #ifndef PF_EXTRA_CODE
801     #define PF_EXTRA_CODE  (40000)
802 #endif
803
804 /* Copy static const data to allocated dictionaries. */
805     NewNameSize = sizeof(MinDicNames) + PF_EXTRA_HEADERS;
806     NewCodeSize = sizeof(MinDicCode) + PF_EXTRA_CODE;
807
808     DBUG_NUM_D( "static dic name size = ", NewNameSize );
809     DBUG_NUM_D( "static dic code size = ", NewCodeSize );
810
811     gCurrentDictionary = dic = pfCreateDictionary( NewNameSize, NewCodeSize );
812     if( !dic ) goto nomem_error;
813
814     pfCopyMemory( (uint8_t *) dic->dic_HeaderBase, MinDicNames, sizeof(MinDicNames) );
815     pfCopyMemory( (uint8_t *) dic->dic_CodeBase, MinDicCode, sizeof(MinDicCode) );
816     DBUG(("Static data copied to newly allocated dictionaries.\n"));
817
818     dic->dic_CodePtr.Byte = (uint8_t *) CODEREL_TO_ABS(CODEPTR);
819     gNumPrimitives = NUM_PRIMITIVES;
820
821     if( NAME_BASE != 0)
822     {
823 /* Setup name space. */
824         dic->dic_HeaderPtr = (ucell_t)(uint8_t *) NAMEREL_TO_ABS(HEADERPTR);
825         gVarContext = NAMEREL_TO_ABS(RELCONTEXT); /* Restore context. */
826
827 /* Find special words in dictionary for global XTs. */
828         if( (Result = FindSpecialXTs()) < 0 )
829         {
830             pfReportError("pfLoadStaticDictionary: FindSpecialXTs", Result);
831             goto error;
832         }
833     }
834
835     return (PForthDictionary) dic;
836
837 error:
838     return NULL;
839
840 nomem_error:
841     pfReportError("pfLoadStaticDictionary", PF_ERR_NO_MEM);
842 #endif /* PF_STATIC_DIC */
843
844     return NULL;
845 }
846