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