Instead of hardcoding PF_SEEK_* constants use SEEK_* values from stdio.h.
[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     int 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     if( Write32ToFile( fid, ID ) < 0 ) goto error;
336     if( Write32ToFile( fid, EvenNumW ) < 0 ) goto error;
337
338     numw = sdWriteFile( Data, 1, EvenNumW, fid );
339     if( numw != EvenNumW ) goto error;
340     return 0;
341 error:
342     pfReportError("WriteChunkToFile", PF_ERR_WRITE_FILE);
343     return -1;
344 }
345
346 /* Convert dictionary info chunk between native and on-disk (big-endian). */
347 static void
348 convertDictionaryInfoWrite (DictionaryInfoChunk *sd)
349 {
350 /* Convert all fields in DictionaryInfoChunk from Native to BigEndian.
351  * This assumes they are all 32-bit integers.
352  */
353     int   i;
354     uint32_t *p = (uint32_t *) sd;
355     for (i=0; i<((int)(sizeof(*sd)/sizeof(uint32_t))); i++)
356     {
357         Write32BigEndian( (uint8_t *)&p[i], p[i] );
358     }
359 }
360
361 static void
362 convertDictionaryInfoRead (DictionaryInfoChunk *sd)
363 {
364 /* Convert all fields in structure from BigEndian to Native. */
365     int   i;
366     uint32_t *p = (uint32_t *) sd;
367     for (i=0; i<((int)(sizeof(*sd)/sizeof(uint32_t))); i++)
368     {
369         p[i] = Read32BigEndian( (uint8_t *)&p[i] );
370     }
371 }
372
373 /****************************************************************
374 ** Save Dictionary in File.
375 ** If EntryPoint is NULL, save as development environment.
376 ** If EntryPoint is non-NULL, save as turnKey environment with no names.
377 */
378 cell_t ffSaveForth( const char *FileName, ExecToken EntryPoint, cell_t NameSize, cell_t CodeSize)
379 {
380     FileStream *fid;
381     DictionaryInfoChunk SD;
382     uint32_t FormSize;
383     uint32_t NameChunkSize = 0;
384     uint32_t CodeChunkSize;
385     uint32_t relativeCodePtr;
386
387     fid = sdOpenFile( FileName, "wb" );
388     if( fid == NULL )
389     {
390         pfReportError("pfSaveDictionary", PF_ERR_OPEN_FILE);
391         return -1;
392     }
393
394 /* Save in uninitialized form. */
395     pfExecIfDefined("AUTO.TERM");
396
397 /* Write FORM Header ---------------------------- */
398     if( Write32ToFile( fid, ID_FORM ) < 0 ) goto error;
399     if( Write32ToFile( fid, 0 ) < 0 ) goto error;
400     if( Write32ToFile( fid, ID_P4TH ) < 0 ) goto error;
401
402 /* Write P4DI Dictionary Info  ------------------ */
403     SD.sd_Version = PF_FILE_VERSION;
404
405     relativeCodePtr = ABS_TO_CODEREL(gCurrentDictionary->dic_CodePtr.Byte); /* 940225 */
406     SD.sd_RelCodePtr = relativeCodePtr;
407     SD.sd_UserStackSize = sizeof(cell_t) * (gCurrentTask->td_StackBase - gCurrentTask->td_StackLimit);
408     SD.sd_ReturnStackSize = sizeof(cell_t) * (gCurrentTask->td_ReturnBase - gCurrentTask->td_ReturnLimit);
409     SD.sd_NumPrimitives = gNumPrimitives;  /* Must match compiled dictionary. */
410
411 #ifdef PF_SUPPORT_FP
412     SD.sd_FloatSize = sizeof(PF_FLOAT);  /* Must match compiled dictionary. */
413 #else
414     SD.sd_FloatSize = 0;
415 #endif
416
417     SD.sd_CellSize = sizeof(cell_t);
418
419 /* Set bit that specifies whether dictionary is BIG or LITTLE Endian. */
420     {
421 #if defined(PF_BIG_ENDIAN_DIC)
422         int eflag = SD_F_BIG_ENDIAN_DIC;
423 #elif defined(PF_LITTLE_ENDIAN_DIC)
424         int eflag = 0;
425 #else
426         int eflag = IsHostLittleEndian() ? 0 : SD_F_BIG_ENDIAN_DIC;
427 #endif
428         SD.sd_Flags = eflag;
429     }
430
431     if( EntryPoint )
432     {
433         SD.sd_EntryPoint = EntryPoint;  /* Turnkey! */
434     }
435     else
436     {
437         SD.sd_EntryPoint = 0;
438     }
439
440 /* Do we save names? */
441     if( NameSize == 0 )
442     {
443         SD.sd_RelContext = 0;
444         SD.sd_RelHeaderPtr = 0;
445         SD.sd_NameSize = 0;
446     }
447     else
448     {
449         uint32_t relativeHeaderPtr;
450 /* Development mode. */
451         SD.sd_RelContext = ABS_TO_NAMEREL(gVarContext);
452         relativeHeaderPtr = ABS_TO_NAMEREL(gCurrentDictionary->dic_HeaderPtr);
453         SD.sd_RelHeaderPtr = relativeHeaderPtr;
454
455 /* How much real name space is there? */
456         NameChunkSize = QUADUP(relativeHeaderPtr);  /* Align */
457
458 /* NameSize must be 0 or greater than NameChunkSize + 1K */
459         NameSize = QUADUP(NameSize);  /* Align */
460         if( NameSize > 0 )
461         {
462             NameSize = MAX( NameSize, (NameChunkSize + 1024) );
463         }
464         SD.sd_NameSize = NameSize;
465     }
466
467 /* How much real code is there? */
468     CodeChunkSize = QUADUP(relativeCodePtr);
469     CodeSize = QUADUP(CodeSize);  /* Align */
470     CodeSize = MAX( CodeSize, (CodeChunkSize + 2048) );
471     SD.sd_CodeSize = CodeSize;
472
473
474     convertDictionaryInfoWrite (&SD);
475
476     if( WriteChunkToFile( fid, ID_P4DI, (char *) &SD, sizeof(DictionaryInfoChunk) ) < 0 ) goto error;
477
478 /* Write Name Fields if NameSize non-zero ------- */
479     if( NameSize > 0 )
480     {
481         if( WriteChunkToFile( fid, ID_P4NM, (char *) NAME_BASE,
482             NameChunkSize ) < 0 ) goto error;
483     }
484
485 /* Write Code Fields ---------------------------- */
486     if( WriteChunkToFile( fid, ID_P4CD, (char *) CODE_BASE,
487         CodeChunkSize ) < 0 ) goto error;
488
489     FormSize = (uint32_t) sdTellFile( fid ) - 8;
490     sdSeekFile( fid, 4, PF_SEEK_SET );
491     if( Write32ToFile( fid, FormSize ) < 0 ) goto error;
492
493     sdCloseFile( fid );
494
495 /* Restore initialization. */
496     pfExecIfDefined("AUTO.INIT");
497     return 0;
498
499 error:
500     sdSeekFile( fid, 0, PF_SEEK_SET );
501     Write32ToFile( fid, ID_BADF ); /* Mark file as bad. */
502     sdCloseFile( fid );
503
504 /* Restore initialization. */
505     pfExecIfDefined("AUTO.INIT");
506
507     return -1;
508 }
509
510 #endif /* !PF_NO_FILEIO and !PF_NO_SHELL */
511
512
513 #ifndef PF_NO_FILEIO
514
515 /***************************************************************/
516 static int32_t Read32FromFile( FileStream *fid, uint32_t *ValPtr )
517 {
518     int32_t numr;
519     uint8_t pad[4];
520     numr = sdReadFile( pad, 1, sizeof(pad), fid );
521     if( numr != sizeof(pad) ) return -1;
522     *ValPtr = Read32BigEndian( pad );
523     return 0;
524 }
525
526 /***************************************************************/
527 PForthDictionary pfLoadDictionary( const char *FileName, ExecToken *EntryPointPtr )
528 {
529     pfDictionary_t *dic = NULL;
530     FileStream *fid;
531     DictionaryInfoChunk *sd;
532     uint32_t ChunkID;
533     uint32_t ChunkSize;
534     uint32_t FormSize;
535     uint32_t BytesLeft;
536     uint32_t numr;
537     int   isDicBigEndian;
538
539 DBUG(("pfLoadDictionary( %s )\n", FileName ));
540
541 /* Open file. */
542     fid = sdOpenFile( FileName, "rb" );
543     if( fid == NULL )
544     {
545         pfReportError("pfLoadDictionary", PF_ERR_OPEN_FILE);
546         goto xt_error;
547     }
548
549 /* Read FORM, Size, ID */
550     if (Read32FromFile( fid, &ChunkID ) < 0) goto read_error;
551     if( ChunkID != ID_FORM )
552     {
553         pfReportError("pfLoadDictionary", PF_ERR_WRONG_FILE);
554         goto error;
555     }
556
557     if (Read32FromFile( fid, &FormSize ) < 0) goto read_error;
558     BytesLeft = FormSize;
559
560     if (Read32FromFile( fid, &ChunkID ) < 0) goto read_error;
561     BytesLeft -= 4;
562     if( ChunkID != ID_P4TH )
563     {
564         pfReportError("pfLoadDictionary", PF_ERR_BAD_FILE);
565         goto error;
566     }
567
568 /* Scan and parse all chunks in file. */
569     while( BytesLeft > 0 )
570     {
571         if (Read32FromFile( fid, &ChunkID ) < 0) goto read_error;
572         if (Read32FromFile( fid, &ChunkSize ) < 0) goto read_error;
573         BytesLeft -= 8;
574
575         DBUG(("ChunkID = %4s, Size = %d\n", (char *)&ChunkID, ChunkSize ));
576
577         switch( ChunkID )
578         {
579         case ID_P4DI:
580             sd = (DictionaryInfoChunk *) pfAllocMem( ChunkSize );
581             if( sd == NULL ) goto nomem_error;
582
583             numr = sdReadFile( sd, 1, ChunkSize, fid );
584             if( numr != ChunkSize ) goto read_error;
585             BytesLeft -= ChunkSize;
586
587             convertDictionaryInfoRead (sd);
588
589             isDicBigEndian = sd->sd_Flags & SD_F_BIG_ENDIAN_DIC;
590
591             if( !gVarQuiet )
592             {
593                 MSG("pForth loading dictionary from file "); MSG(FileName);
594                     EMIT_CR;
595                 MSG_NUM_D("     File format version is ", sd->sd_Version );
596                 MSG_NUM_D("     Name space size = ", sd->sd_NameSize );
597                 MSG_NUM_D("     Code space size = ", sd->sd_CodeSize );
598                 MSG_NUM_D("     Entry Point     = ", sd->sd_EntryPoint );
599                 MSG_NUM_D("     Cell Size       = ", sd->sd_CellSize );
600                 MSG( (isDicBigEndian ? "     Big Endian Dictionary" :
601                                        "     Little  Endian Dictionary") );
602                 if( isDicBigEndian == IsHostLittleEndian() ) MSG(" !!!!");
603                     EMIT_CR;
604             }
605
606             if( sd->sd_Version > PF_FILE_VERSION )
607             {
608                 pfReportError("pfLoadDictionary", PF_ERR_VERSION_FUTURE );
609                 goto error;
610             }
611             if( sd->sd_Version < PF_EARLIEST_FILE_VERSION )
612             {
613                 pfReportError("pfLoadDictionary", PF_ERR_VERSION_PAST );
614                 goto error;
615             }
616             if( sd->sd_CellSize != sizeof(cell_t) )
617             {
618                 pfReportError("pfLoadDictionary", PF_ERR_CELL_SIZE_CONFLICT );
619                 goto error;
620             }
621             if( sd->sd_NumPrimitives > NUM_PRIMITIVES )
622             {
623                 pfReportError("pfLoadDictionary", PF_ERR_NOT_SUPPORTED );
624                 goto error;
625             }
626
627 /* Check to make sure that EndianNess of dictionary matches mode of pForth. */
628 #if defined(PF_BIG_ENDIAN_DIC)
629             if(isDicBigEndian == 0)
630 #elif defined(PF_LITTLE_ENDIAN_DIC)
631             if(isDicBigEndian == 1)
632 #else
633             if( isDicBigEndian == IsHostLittleEndian() )
634 #endif
635             {
636                 pfReportError("pfLoadDictionary", PF_ERR_ENDIAN_CONFLICT );
637                 goto error;
638             }
639
640 /* Check for compatible float size. */
641 #ifdef PF_SUPPORT_FP
642             if( sd->sd_FloatSize != sizeof(PF_FLOAT) )
643 #else
644             if( sd->sd_FloatSize != 0 )
645 #endif
646             {
647                 pfReportError("pfLoadDictionary", PF_ERR_FLOAT_CONFLICT );
648                 goto error;
649             }
650
651             dic = pfCreateDictionary( sd->sd_NameSize, sd->sd_CodeSize );
652             if( dic == NULL ) goto nomem_error;
653             gCurrentDictionary = dic;
654             if( sd->sd_NameSize > 0 )
655             {
656                 gVarContext = NAMEREL_TO_ABS(sd->sd_RelContext); /* Restore context. */
657                 gCurrentDictionary->dic_HeaderPtr = (ucell_t)(uint8_t *)
658                     NAMEREL_TO_ABS(sd->sd_RelHeaderPtr);
659             }
660             else
661             {
662                 gVarContext = 0;
663                 gCurrentDictionary->dic_HeaderPtr = (ucell_t)NULL;
664             }
665             gCurrentDictionary->dic_CodePtr.Byte = (uint8_t *) CODEREL_TO_ABS(sd->sd_RelCodePtr);
666             gNumPrimitives = sd->sd_NumPrimitives;  /* Must match compiled dictionary. */
667 /* Pass EntryPoint back to caller. */
668             if( EntryPointPtr != NULL ) *EntryPointPtr = sd->sd_EntryPoint;
669             pfFreeMem(sd);
670             break;
671
672         case ID_P4NM:
673 #ifdef PF_NO_SHELL
674             pfReportError("pfLoadDictionary", PF_ERR_NO_SHELL );
675             goto error;
676 #else
677             if( NAME_BASE == 0 )
678             {
679                 pfReportError("pfLoadDictionary", PF_ERR_NO_NAMES );
680                 goto error;
681             }
682             if( gCurrentDictionary == NULL )
683             {
684                 pfReportError("pfLoadDictionary", PF_ERR_BAD_FILE );
685                 goto error;
686             }
687             if( ChunkSize > NAME_SIZE )
688             {
689                 pfReportError("pfLoadDictionary", PF_ERR_TOO_BIG);
690                 goto error;
691             }
692             numr = sdReadFile( (char *) NAME_BASE, 1, ChunkSize, fid );
693             if( numr != ChunkSize ) goto read_error;
694             BytesLeft -= ChunkSize;
695 #endif /* PF_NO_SHELL */
696             break;
697
698         case ID_P4CD:
699             if( gCurrentDictionary == NULL )
700             {
701                 pfReportError("pfLoadDictionary", PF_ERR_BAD_FILE );
702                 goto error;
703             }
704             if( ChunkSize > CODE_SIZE )
705             {
706                 pfReportError("pfLoadDictionary", PF_ERR_TOO_BIG);
707                 goto error;
708             }
709             numr = sdReadFile( (uint8_t *) CODE_BASE, 1, ChunkSize, fid );
710             if( numr != ChunkSize ) goto read_error;
711             BytesLeft -= ChunkSize;
712             break;
713
714         default:
715             pfReportError("pfLoadDictionary", PF_ERR_BAD_FILE );
716             sdSeekFile( fid, ChunkSize, PF_SEEK_CUR );
717             break;
718         }
719     }
720
721     sdCloseFile( fid );
722
723     if( NAME_BASE != 0)
724     {
725         cell_t Result;
726 /* Find special words in dictionary for global XTs. */
727         if( (Result = FindSpecialXTs()) < 0 )
728         {
729             pfReportError("pfLoadDictionary: FindSpecialXTs", Result);
730             goto error;
731         }
732     }
733
734 DBUG(("pfLoadDictionary: return %p\n", dic));
735     return (PForthDictionary) dic;
736
737 nomem_error:
738     pfReportError("pfLoadDictionary", PF_ERR_NO_MEM);
739     sdCloseFile( fid );
740     return NULL;
741
742 read_error:
743     pfReportError("pfLoadDictionary", PF_ERR_READ_FILE);
744 error:
745     sdCloseFile( fid );
746 xt_error:
747     return NULL;
748 }
749
750 #else
751
752 PForthDictionary pfLoadDictionary( const char *FileName, ExecToken *EntryPointPtr )
753 {
754     (void) FileName;
755     (void) EntryPointPtr;
756     return NULL;
757 }
758 #endif /* !PF_NO_FILEIO */
759
760
761
762 /***************************************************************/
763 PForthDictionary pfLoadStaticDictionary( void )
764 {
765 #ifdef PF_STATIC_DIC
766     cell_t Result;
767     pfDictionary_t *dic;
768     cell_t NewNameSize, NewCodeSize;
769
770     if( IF_LITTLE_ENDIAN != IsHostLittleEndian() )
771     {
772         MSG( (IF_LITTLE_ENDIAN ?
773                  "Little Endian Dictionary on " :
774                  "Big Endian Dictionary on ") );
775         MSG( (IsHostLittleEndian() ?
776                  "Little Endian CPU" :
777                  "Big Endian CPU") );
778         EMIT_CR;
779     }
780
781 /* Check to make sure that EndianNess of dictionary matches mode of pForth. */
782 #if defined(PF_BIG_ENDIAN_DIC)
783     if(IF_LITTLE_ENDIAN == 1)
784 #elif defined(PF_LITTLE_ENDIAN_DIC)
785     if(IF_LITTLE_ENDIAN == 0)
786 #else /* Code is native endian! */
787     if( IF_LITTLE_ENDIAN != IsHostLittleEndian() )
788 #endif
789     {
790         pfReportError("pfLoadStaticDictionary", PF_ERR_ENDIAN_CONFLICT );
791         goto error;
792     }
793
794
795 #ifndef PF_EXTRA_HEADERS
796     #define PF_EXTRA_HEADERS  (20000)
797 #endif
798 #ifndef PF_EXTRA_CODE
799     #define PF_EXTRA_CODE  (40000)
800 #endif
801
802 /* Copy static const data to allocated dictionaries. */
803     NewNameSize = sizeof(MinDicNames) + PF_EXTRA_HEADERS;
804     NewCodeSize = sizeof(MinDicCode) + PF_EXTRA_CODE;
805
806     DBUG_NUM_D( "static dic name size = ", NewNameSize );
807     DBUG_NUM_D( "static dic code size = ", NewCodeSize );
808
809     gCurrentDictionary = dic = pfCreateDictionary( NewNameSize, NewCodeSize );
810     if( !dic ) goto nomem_error;
811
812     pfCopyMemory( (uint8_t *) dic->dic_HeaderBase, MinDicNames, sizeof(MinDicNames) );
813     pfCopyMemory( (uint8_t *) dic->dic_CodeBase, MinDicCode, sizeof(MinDicCode) );
814     DBUG(("Static data copied to newly allocated dictionaries.\n"));
815
816     dic->dic_CodePtr.Byte = (uint8_t *) CODEREL_TO_ABS(CODEPTR);
817     gNumPrimitives = NUM_PRIMITIVES;
818
819     if( NAME_BASE != 0)
820     {
821 /* Setup name space. */
822         dic->dic_HeaderPtr = (ucell_t)(uint8_t *) NAMEREL_TO_ABS(HEADERPTR);
823         gVarContext = NAMEREL_TO_ABS(RELCONTEXT); /* Restore context. */
824
825 /* Find special words in dictionary for global XTs. */
826         if( (Result = FindSpecialXTs()) < 0 )
827         {
828             pfReportError("pfLoadStaticDictionary: FindSpecialXTs", Result);
829             goto error;
830         }
831     }
832
833     return (PForthDictionary) dic;
834
835 error:
836     return NULL;
837
838 nomem_error:
839     pfReportError("pfLoadStaticDictionary", PF_ERR_NO_MEM);
840 #endif /* PF_STATIC_DIC */
841
842     return NULL;
843 }
844