]> git.sur5r.net Git - cc65/blob - src/ld65/config.c
Fixed a bug
[cc65] / src / ld65 / config.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 config.c                                  */
4 /*                                                                           */
5 /*               Target configuration file for the ld65 linker               */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2002 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <errno.h>
40
41 /* common */
42 #include "check.h"
43 #include "bitops.h"
44 #include "print.h"
45 #include "xmalloc.h"
46 #include "xsprintf.h"
47
48 /* ld65 */
49 #include "bin.h"
50 #include "binfmt.h"
51 #include "condes.h"
52 #include "error.h"
53 #include "exports.h"
54 #include "global.h"
55 #include "o65.h"
56 #include "scanner.h"
57 #include "config.h"
58
59
60
61 /*****************************************************************************/
62 /*                                   Data                                    */
63 /*****************************************************************************/
64
65
66
67 /* File list */
68 static File*            FileList;       /* Single linked list */
69 static unsigned         FileCount;      /* Number of entries in the list */
70
71
72
73 /* Memory list */
74 static Memory*          MemoryList;     /* Single linked list */
75 static Memory*          MemoryLast;     /* Last element in list */
76 static unsigned         MemoryCount;    /* Number of entries in the list */
77
78 /* Memory attributes */
79 #define MA_START        0x0001
80 #define MA_SIZE         0x0002
81 #define MA_TYPE         0x0004
82 #define MA_FILE         0x0008
83 #define MA_DEFINE       0x0010
84 #define MA_FILL         0x0020
85 #define MA_FILLVAL      0x0040
86
87
88
89 /* Segment list */
90 SegDesc*                SegDescList;    /* Single linked list */
91 unsigned                SegDescCount;   /* Number of entries in list */
92
93 /* Segment attributes */
94 #define SA_TYPE         0x0001
95 #define SA_LOAD         0x0002
96 #define SA_RUN          0x0004
97 #define SA_ALIGN        0x0008
98 #define SA_DEFINE       0x0010
99 #define SA_OFFSET       0x0020
100 #define SA_START        0x0040
101
102
103
104 /* Descriptor holding information about the binary formats */
105 static BinDesc* BinFmtDesc      = 0;
106 static O65Desc* O65FmtDesc      = 0;
107
108
109
110 /*****************************************************************************/
111 /*                                 Forwards                                  */
112 /*****************************************************************************/
113
114
115
116 static File* NewFile (const char* Name);
117 /* Create a new file descriptor and insert it into the list */
118
119
120
121 /*****************************************************************************/
122 /*                              List management                              */
123 /*****************************************************************************/
124
125
126
127 static File* FindFile (const char* Name)
128 /* Find a file with a given name. */
129 {
130     File* F = FileList;
131     while (F) {
132         if (strcmp (F->Name, Name) == 0) {
133             return F;
134         }
135         F = F->Next;
136     }
137     return 0;
138 }
139
140
141
142 static File* GetFile (const char* Name)
143 /* Get a file entry with the given name. Create a new one if needed. */
144 {
145     File* F = FindFile (Name);
146     if (F == 0) {
147         /* Create a new one */
148         F = NewFile (Name);
149     }
150     return F;
151 }
152
153
154
155 static void FileInsert (File* F, Memory* M)
156 /* Insert the memory area into the files list */
157 {
158     M->F = F;
159     if (F->MemList == 0) {
160         /* First entry */
161         F->MemList = M;
162     } else {
163         F->MemLast->FNext = M;
164     }
165     F->MemLast = M;
166 }
167
168
169
170 static Memory* CfgFindMemory (const char* Name)
171 /* Find the memory are with the given name. Return NULL if not found */
172 {
173     Memory* M = MemoryList;
174     while (M) {
175         if (strcmp (M->Name, Name) == 0) {
176             return M;
177         }
178         M = M->Next;
179     }
180     return 0;
181 }
182
183
184
185 static Memory* CfgGetMemory (const char* Name)
186 /* Find the memory are with the given name. Print an error on an invalid name */
187 {
188     Memory* M = CfgFindMemory (Name);
189     if (M == 0) {
190         CfgError ("Invalid memory area `%s'", Name);
191     }
192     return M;
193 }
194
195
196
197 static SegDesc* CfgFindSegDesc (const char* Name)
198 /* Find the segment descriptor with the given name, return NULL if not found. */
199 {
200     SegDesc* S = SegDescList;
201     while (S) {
202         if (strcmp (S->Name, Name) == 0) {
203             /* Found */
204             return S;
205         }
206         S = S->Next;
207     }
208
209     /* Not found */
210     return 0;
211 }
212
213
214
215 static void SegDescInsert (SegDesc* S)
216 /* Insert a segment descriptor into the list of segment descriptors */
217 {
218     /* Insert the struct into the list */
219     S->Next = SegDescList;
220     SegDescList = S;
221     ++SegDescCount;
222 }
223
224
225
226 static void MemoryInsert (Memory* M, SegDesc* S)
227 /* Insert the segment descriptor into the memory area list */
228 {
229     /* Create a new node for the entry */
230     MemListNode* N = xmalloc (sizeof (MemListNode));
231     N->Seg  = S;
232     N->Next = 0;
233
234     if (M->SegLast == 0) {
235         /* First entry */
236         M->SegList = N;
237     } else {
238         M->SegLast->Next = N;
239     }
240     M->SegLast = N;
241 }
242
243
244
245 /*****************************************************************************/
246 /*                         Constructors/Destructors                          */
247 /*****************************************************************************/
248
249
250
251 static File* NewFile (const char* Name)
252 /* Create a new file descriptor and insert it into the list */
253 {
254     /* Get the length of the name */
255     unsigned Len = strlen (Name);
256
257     /* Allocate memory */
258     File* F = xmalloc (sizeof (File) + Len);
259
260     /* Initialize the fields */
261     F->Flags   = 0;
262     F->Format  = BINFMT_DEFAULT;
263     F->MemList = 0;
264     F->MemLast = 0;
265     memcpy (F->Name, Name, Len);
266     F->Name [Len] = '\0';
267
268     /* Insert the struct into the list */
269     F->Next  = FileList;
270     FileList = F;
271     ++FileCount;
272
273     /* ...and return it */
274     return F;
275 }
276
277
278
279 static Memory* NewMemory (const char* Name)
280 /* Create a new memory section and insert it into the list */
281 {
282     /* Get the length of the name */
283     unsigned Len = strlen (Name);
284
285     /* Check for duplicate names */
286     Memory* M = CfgFindMemory (Name);
287     if (M) {
288         CfgError ("Memory area `%s' defined twice", Name);
289     }
290
291     /* Allocate memory */
292     M = xmalloc (sizeof (Memory) + Len);
293
294     /* Initialize the fields */
295     M->Next      = 0;
296     M->FNext     = 0;
297     M->Attr      = 0;
298     M->Flags     = 0;
299     M->Start     = 0;
300     M->Size      = 0;
301     M->FillLevel = 0;
302     M->FillVal   = 0;
303     M->SegList   = 0;
304     M->SegLast   = 0;
305     M->F         = 0;
306     memcpy (M->Name, Name, Len);
307     M->Name [Len] = '\0';
308
309     /* Insert the struct into the list */
310     if (MemoryLast == 0) {
311         /* First element */
312         MemoryList = M;
313     } else {
314         MemoryLast->Next = M;
315     }
316     MemoryLast = M;
317     ++MemoryCount;
318
319     /* ...and return it */
320     return M;
321 }
322
323
324
325 static SegDesc* NewSegDesc (const char* Name)
326 /* Create a segment descriptor */
327 {
328     Segment* Seg;
329
330     /* Get the length of the name */
331     unsigned Len = strlen (Name);
332
333     /* Check for duplicate names */
334     SegDesc* S = CfgFindSegDesc (Name);
335     if (S) {
336         CfgError ("Segment `%s' defined twice", Name);
337     }
338
339     /* Verify that the given segment does really exist */
340     Seg = SegFind (Name);
341     if (Seg == 0) {
342         CfgWarning ("Segment `%s' does not exist", Name);
343     }
344
345     /* Allocate memory */
346     S = xmalloc (sizeof (SegDesc) + Len);
347
348     /* Initialize the fields */
349     S->Next    = 0;
350     S->Seg     = Seg;
351     S->Attr    = 0;
352     S->Flags   = 0;
353     S->Align   = 0;
354     memcpy (S->Name, Name, Len);
355     S->Name [Len] = '\0';
356
357     /* ...and return it */
358     return S;
359 }
360
361
362
363 static void FreeSegDesc (SegDesc* S)
364 /* Free a segment descriptor */
365 {
366     xfree (S);
367 }
368
369
370
371 /*****************************************************************************/
372 /*                                   Code                                    */
373 /*****************************************************************************/
374
375
376
377 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
378 /* Check if the item is already defined. Print an error if so. If not, set
379  * the marker that we have a definition now.
380  */
381 {
382     if (*Flags & Mask) {
383         CfgError ("%s is already defined", Name);
384     }
385     *Flags |= Mask;
386 }
387
388
389
390 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
391 /* Check that a mandatory attribute was given */
392 {
393     if ((Attr & Mask) == 0) {
394         CfgError ("%s attribute is missing", Name);
395     }
396 }
397
398
399
400 static void ParseMemory (void)
401 /* Parse a MEMORY section */
402 {
403     static const IdentTok Attributes [] = {
404         {   "START",    CFGTOK_START    },
405         {   "SIZE",     CFGTOK_SIZE     },
406         {   "TYPE",     CFGTOK_TYPE     },
407         {   "FILE",     CFGTOK_FILE     },
408         {   "DEFINE",   CFGTOK_DEFINE   },
409         {   "FILL",     CFGTOK_FILL     },
410         {   "FILLVAL",  CFGTOK_FILLVAL  },
411     };
412     static const IdentTok Types [] = {
413         {   "RO",       CFGTOK_RO       },
414         {   "RW",       CFGTOK_RW       },
415     };
416
417     while (CfgTok == CFGTOK_IDENT) {
418
419         /* Create a new entry on the heap */
420         Memory* M = NewMemory (CfgSVal);
421
422         /* Skip the name and the following colon */
423         CfgNextTok ();
424         CfgConsumeColon ();
425
426         /* Read the attributes */
427         while (CfgTok == CFGTOK_IDENT) {
428
429             /* Map the identifier to a token */
430             cfgtok_t AttrTok;
431             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
432             AttrTok = CfgTok;
433
434             /* An optional assignment follows */
435             CfgNextTok ();
436             CfgOptionalAssign ();
437
438             /* Check which attribute was given */
439             switch (AttrTok) {
440
441                 case CFGTOK_START:
442                     FlagAttr (&M->Attr, MA_START, "START");
443                     CfgAssureInt ();
444                     M->Start = CfgIVal;
445                     break;
446
447                 case CFGTOK_SIZE:
448                     FlagAttr (&M->Attr, MA_SIZE, "SIZE");
449                     CfgAssureInt ();
450                     M->Size = CfgIVal;
451                     break;
452
453                 case CFGTOK_TYPE:
454                     FlagAttr (&M->Attr, MA_TYPE, "TYPE");
455                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
456                     if (CfgTok == CFGTOK_RO) {
457                         M->Flags |= MF_RO;
458                     }
459                     break;
460
461                 case CFGTOK_FILE:
462                     FlagAttr (&M->Attr, MA_FILE, "FILE");
463                     CfgAssureStr ();
464                     /* Get the file entry and insert the memory area */
465                     FileInsert (GetFile (CfgSVal), M);
466                     break;
467
468                 case CFGTOK_DEFINE:
469                     FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
470                     /* Map the token to a boolean */
471                     CfgBoolToken ();
472                     if (CfgTok == CFGTOK_TRUE) {
473                         M->Flags |= MF_DEFINE;
474                     }
475                     break;
476
477                 case CFGTOK_FILL:
478                     FlagAttr (&M->Attr, MA_FILL, "FILL");
479                     /* Map the token to a boolean */
480                     CfgBoolToken ();
481                     if (CfgTok == CFGTOK_TRUE) {
482                         M->Flags |= MF_FILL;
483                     }
484                     break;
485
486                 case CFGTOK_FILLVAL:
487                     FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
488                     CfgAssureInt ();
489                     CfgRangeCheck (0, 0xFF);
490                     M->FillVal = (unsigned char) CfgIVal;
491                     break;
492
493                 default:
494                     FAIL ("Unexpected attribute token");
495
496             }
497
498             /* Skip the attribute value and an optional comma */
499             CfgNextTok ();
500             CfgOptionalComma ();
501         }
502
503         /* Skip the semicolon */
504         CfgConsumeSemi ();
505
506         /* Check for mandatory parameters */
507         AttrCheck (M->Attr, MA_START, "START");
508         AttrCheck (M->Attr, MA_SIZE, "SIZE");
509
510         /* If we don't have a file name for output given, use the default
511          * file name.
512          */
513         if ((M->Attr & MA_FILE) == 0) {
514             FileInsert (GetFile (OutputName), M);
515         }
516     }
517 }
518
519
520
521 static void ParseFiles (void)
522 /* Parse a FILES section */
523 {
524     static const IdentTok Attributes [] = {
525         {   "FORMAT",   CFGTOK_FORMAT   },
526     };
527     static const IdentTok Formats [] = {
528         {   "O65",      CFGTOK_O65           },
529         {   "BIN",      CFGTOK_BIN      },
530         {   "BINARY",   CFGTOK_BIN      },
531     };
532
533
534     /* Parse all files */
535     while (CfgTok != CFGTOK_RCURLY) {
536
537         File* F;
538
539         /* We expect a string value here */
540         CfgAssureStr ();
541
542         /* Search for the file, it must exist */
543         F = FindFile (CfgSVal);
544         if (F == 0) {
545             CfgError ("No such file: `%s'", CfgSVal);
546         }
547
548         /* Skip the token and the following colon */
549         CfgNextTok ();
550         CfgConsumeColon ();
551
552         /* Read the attributes */
553         while (CfgTok == CFGTOK_IDENT) {
554
555             /* Map the identifier to a token */
556             cfgtok_t AttrTok;
557             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
558             AttrTok = CfgTok;
559
560             /* An optional assignment follows */
561             CfgNextTok ();
562             CfgOptionalAssign ();
563
564             /* Check which attribute was given */
565             switch (AttrTok) {
566
567                 case CFGTOK_FORMAT:
568                     if (F->Format != BINFMT_DEFAULT) {
569                         /* We've set the format already! */
570                         Error ("Cannot set a file format twice");
571                     }
572                     /* Read the format token */
573                     CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
574                     switch (CfgTok) {
575
576                         case CFGTOK_BIN:
577                             F->Format = BINFMT_BINARY;
578                             break;
579
580                         case CFGTOK_O65:
581                             F->Format = BINFMT_O65;
582                             break;
583
584                         default:
585                             Error ("Unexpected format token");
586                     }
587                     break;
588
589                 default:
590                     FAIL ("Unexpected attribute token");
591
592             }
593
594             /* Skip the attribute value and an optional comma */
595             CfgNextTok ();
596             CfgOptionalComma ();
597         }
598
599         /* Skip the semicolon */
600         CfgConsumeSemi ();
601
602     }
603 }
604
605
606
607 static void ParseSegments (void)
608 /* Parse a SEGMENTS section */
609 {
610     static const IdentTok Attributes [] = {
611         {   "LOAD",     CFGTOK_LOAD     },
612         {   "RUN",      CFGTOK_RUN      },
613         {   "TYPE",     CFGTOK_TYPE     },
614         {   "ALIGN",    CFGTOK_ALIGN    },
615         {   "DEFINE",   CFGTOK_DEFINE   },
616         {   "OFFSET",   CFGTOK_OFFSET   },
617         {   "START",    CFGTOK_START    },
618     };
619     static const IdentTok Types [] = {
620         {   "RO",       CFGTOK_RO       },
621         {   "RW",       CFGTOK_RW       },
622         {   "BSS",      CFGTOK_BSS      },
623         {   "ZP",       CFGTOK_ZP       },
624         {   "WP",       CFGTOK_WPROT    },
625         {   "WPROT",    CFGTOK_WPROT    },
626     };
627
628     unsigned Count;
629
630     while (CfgTok == CFGTOK_IDENT) {
631
632         SegDesc* S;
633
634         /* Create a new entry on the heap */
635         S = NewSegDesc (CfgSVal);
636
637         /* Skip the name and the following colon */
638         CfgNextTok ();
639         CfgConsumeColon ();
640
641         /* Read the attributes */
642         while (CfgTok == CFGTOK_IDENT) {
643
644             /* Map the identifier to a token */
645             cfgtok_t AttrTok;
646             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
647             AttrTok = CfgTok;
648
649             /* An optional assignment follows */
650             CfgNextTok ();
651             CfgOptionalAssign ();
652
653             /* Check which attribute was given */
654             switch (AttrTok) {
655
656                 case CFGTOK_LOAD:
657                     FlagAttr (&S->Attr, SA_LOAD, "LOAD");
658                     S->Load = CfgGetMemory (CfgSVal);
659                     break;
660
661                 case CFGTOK_RUN:
662                     FlagAttr (&S->Attr, SA_RUN, "RUN");
663                     S->Run = CfgGetMemory (CfgSVal);
664                     break;
665
666                 case CFGTOK_TYPE:
667                     FlagAttr (&S->Attr, SA_TYPE, "TYPE");
668                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
669                     switch (CfgTok) {
670                         case CFGTOK_RO:    S->Flags |= SF_RO;               break;
671                         case CFGTOK_RW:    /* Default */                    break;
672                         case CFGTOK_BSS:   S->Flags |= SF_BSS;              break;
673                         case CFGTOK_ZP:    S->Flags |= (SF_BSS | SF_ZP);    break;
674                         case CFGTOK_WPROT: S->Flags |= (SF_RO | SF_WPROT);  break;
675                         default:           Internal ("Unexpected token: %d", CfgTok);
676                     }
677                     break;
678
679                 case CFGTOK_ALIGN:
680                     CfgAssureInt ();
681                     FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
682                     CfgRangeCheck (1, 0x10000);
683                     S->Align = BitFind (CfgIVal);
684                     if ((0x01UL << S->Align) != CfgIVal) {
685                         CfgError ("Alignment must be a power of 2");
686                     }
687                     S->Flags |= SF_ALIGN;
688                     break;
689
690                 case CFGTOK_DEFINE:
691                     FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
692                     /* Map the token to a boolean */
693                     CfgBoolToken ();
694                     if (CfgTok == CFGTOK_TRUE) {
695                         S->Flags |= SF_DEFINE;
696                     }
697                     break;
698
699                 case CFGTOK_OFFSET:
700                     CfgAssureInt ();
701                     FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
702                     CfgRangeCheck (1, 0x1000000);
703                     S->Addr   = CfgIVal;
704                     S->Flags |= SF_OFFSET;
705                     break;
706
707                 case CFGTOK_START:
708                     CfgAssureInt ();
709                     FlagAttr (&S->Attr, SA_START, "START");
710                     CfgRangeCheck (1, 0x1000000);
711                     S->Addr   = CfgIVal;
712                     S->Flags |= SF_START;
713                     break;
714
715                 default:
716                     FAIL ("Unexpected attribute token");
717
718             }
719
720             /* Skip the attribute value and an optional comma */
721             CfgNextTok ();
722             CfgOptionalComma ();
723         }
724
725         /* Check for mandatory parameters */
726         AttrCheck (S->Attr, SA_LOAD, "LOAD");
727
728         /* Set defaults for stuff not given */
729         if ((S->Attr & SA_RUN) == 0) {
730             S->Attr |= SA_RUN;
731             S->Run = S->Load;
732         } else {
733             /* Both attributes given */
734             S->Flags |= SF_LOAD_AND_RUN;
735         }
736         if ((S->Attr & SA_ALIGN) == 0) {
737             S->Attr |= SA_ALIGN;
738             S->Align = 0;
739         }
740
741         /* If the segment is marked as BSS style, and if the segment exists 
742          * in any of the object file, check that there's no initialized data 
743          * in the segment.
744          */
745         if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
746             Warning ("%s(%u): Segment with type `bss' contains initialized data",
747                      CfgGetName (), CfgErrorLine);
748         }
749
750         /* If the segment is marked as BSS style, it may not have separate
751          * load and run memory areas, because it's is never written to disk.
752          */
753         if ((S->Flags & SF_BSS) != 0 && (S->Flags & SF_LOAD_AND_RUN) != 0) {
754             Warning ("%s(%u): Segment with type `bss' has both LOAD and RUN "
755                      "memory areas assigned", CfgGetName (), CfgErrorLine);
756         }
757
758         /* Don't allow read/write data to be put into a readonly area */
759         if ((S->Flags & SF_RO) == 0) {
760             if (S->Run->Flags & MF_RO) {
761                 CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'",
762                           S->Name, S->Run->Name);
763             }
764         }
765
766         /* Only one of ALIGN, START and OFFSET may be used */
767         Count = ((S->Flags & SF_ALIGN)  != 0) +
768                 ((S->Flags & SF_OFFSET) != 0) +
769                 ((S->Flags & SF_START)  != 0);
770         if (Count > 1) {
771             CfgError ("Only one of ALIGN, START, OFFSET may be used");
772         }
773
774         /* If this segment does exist in any of the object files, insert the
775          * descriptor into the list of segment descriptors. Otherwise discard
776          * it silently, because the segment pointer in the descriptor is
777          * invalid.
778          */
779         if (S->Seg != 0) {
780             /* Insert the descriptor into the list of all descriptors */
781             SegDescInsert (S);
782             /* Insert the segment into the memory area list */
783             MemoryInsert (S->Run, S);
784             if ((S->Flags & SF_LOAD_AND_RUN) != 0) {
785                 /* We have a separate RUN area given */
786                 MemoryInsert (S->Load, S);
787             }
788         } else {
789             /* Segment does not exist, discard the descriptor */
790             FreeSegDesc (S);
791         }
792
793         /* Skip the semicolon */
794         CfgConsumeSemi ();
795     }
796 }
797
798
799
800 static void ParseO65 (void)
801 /* Parse the o65 format section */
802 {
803     static const IdentTok Attributes [] = {
804         {   "EXPORT",   CFGTOK_EXPORT           },
805         {   "IMPORT",   CFGTOK_IMPORT           },
806         {   "TYPE",     CFGTOK_TYPE             },
807         {   "OS",       CFGTOK_OS               },
808         {   "ID",       CFGTOK_ID               },
809         {   "VERSION",  CFGTOK_VERSION          },
810     };
811     static const IdentTok Types [] = {
812         {   "SMALL",    CFGTOK_SMALL            },
813         {   "LARGE",    CFGTOK_LARGE            },
814     };
815     static const IdentTok OperatingSystems [] = {
816         {   "LUNIX",    CFGTOK_LUNIX            },
817         {   "OSA65",    CFGTOK_OSA65            },
818         {   "CC65",     CFGTOK_CC65             },
819     };
820
821     /* Bitmask to remember the attributes we got already */
822     enum {
823         atNone          = 0x0000,
824         atOS            = 0x0001,
825         atOSVersion     = 0x0002,
826         atType          = 0x0004,
827         atImport        = 0x0008,
828         atExport        = 0x0010,
829         atID            = 0x0020,
830         atVersion       = 0x0040
831     };
832     unsigned AttrFlags = atNone;
833
834     /* Remember the attributes read */
835     unsigned OS = 0;            /* Initialize to keep gcc happy */
836     unsigned Version = 0;
837
838     /* Read the attributes */
839     while (CfgTok == CFGTOK_IDENT) {
840
841         /* Map the identifier to a token */
842         cfgtok_t AttrTok;
843         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
844         AttrTok = CfgTok;
845
846         /* An optional assignment follows */
847         CfgNextTok ();
848         CfgOptionalAssign ();
849
850         /* Check which attribute was given */
851         switch (AttrTok) {
852
853             case CFGTOK_EXPORT:
854                 /* Remember we had this token (maybe more than once) */
855                 AttrFlags |= atExport;
856                 /* We expect an identifier */
857                 CfgAssureIdent ();
858                 /* Check if the export symbol is also defined as an import. */
859                 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
860                     CfgError ("Exported symbol `%s' cannot be an import", CfgSVal);
861                 }
862                 /* Check if we have this symbol defined already. The entry
863                  * routine will check this also, but we get a more verbose
864                  * error message when checking it here.
865                  */
866                 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
867                     CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
868                 }
869                 /* Insert the symbol into the table */
870                 O65SetExport (O65FmtDesc, CfgSVal);
871                 break;
872
873             case CFGTOK_IMPORT:
874                 /* Remember we had this token (maybe more than once) */
875                 AttrFlags |= atImport;
876                 /* We expect an identifier */
877                 CfgAssureIdent ();
878                 /* Check if the imported symbol is also defined as an export. */
879                 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
880                     CfgError ("Imported symbol `%s' cannot be an export", CfgSVal);
881                 }
882                 /* Check if we have this symbol defined already. The entry
883                  * routine will check this also, but we get a more verbose
884                  * error message when checking it here.
885                  */
886                 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
887                     CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
888                 }
889                 /* Insert the symbol into the table */
890                 O65SetImport (O65FmtDesc, CfgSVal);
891                 break;
892
893             case CFGTOK_TYPE:
894                 /* Cannot have this attribute twice */
895                 FlagAttr (&AttrFlags, atType, "TYPE");
896                 /* Get the type of the executable */
897                 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
898                 switch (CfgTok) {
899
900                     case CFGTOK_SMALL:
901                         O65SetSmallModel (O65FmtDesc);
902                         break;
903
904                     case CFGTOK_LARGE:
905                         O65SetLargeModel (O65FmtDesc);
906                         break;
907
908                     default:
909                         CfgError ("Unexpected type token");
910                 }
911                 break;
912
913             case CFGTOK_OS:
914                 /* Cannot use this attribute twice */
915                 FlagAttr (&AttrFlags, atOS, "OS");
916                 /* Get the operating system */
917                 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
918                 switch (CfgTok) {
919                     case CFGTOK_LUNIX:  OS = O65OS_LUNIX;       break;
920                     case CFGTOK_OSA65:  OS = O65OS_OSA65;       break;
921                     case CFGTOK_CC65:   OS = O65OS_CC65;        break;
922                     default:            CfgError ("Unexpected OS token");
923                 }
924                 break;
925
926             case CFGTOK_ID:
927                 /* Cannot have this attribute twice */
928                 FlagAttr (&AttrFlags, atID, "ID");
929                 /* We're expecting a number in the 0..$FFFF range*/
930                 CfgAssureInt ();
931                 CfgRangeCheck (0, 0xFFFF);
932                 ModuleId = (unsigned) CfgIVal;
933                 break;
934
935             case CFGTOK_VERSION:
936                 /* Cannot have this attribute twice */
937                 FlagAttr (&AttrFlags, atVersion, "VERSION");
938                 /* We're expecting a number in byte range */
939                 CfgAssureInt ();
940                 CfgRangeCheck (0, 0xFF);
941                 Version = (unsigned) CfgIVal;
942                 break;
943
944             default:
945                 FAIL ("Unexpected attribute token");
946
947         }
948
949         /* Skip the attribute value and an optional comma */
950         CfgNextTok ();
951         CfgOptionalComma ();
952     }
953
954     /* Check if we have all mandatory attributes */
955     AttrCheck (AttrFlags, atOS, "OS");
956
957     /* Check for attributes that may not be combined */
958     if (OS == O65OS_CC65) {
959         if ((AttrFlags & (atImport | atExport)) != 0) {
960             CfgError ("OS type CC65 may not have imports or exports");
961         }
962     } else {
963         if (AttrFlags & atID) {
964             CfgError ("Operating system does not support the ID attribute");
965         }
966     }
967
968     /* Set the O65 operating system to use */
969     O65SetOS (O65FmtDesc, OS, Version, ModuleId);
970 }
971
972
973
974 static void ParseFormats (void)
975 /* Parse a target format section */
976 {
977     static const IdentTok Formats [] = {
978         {   "O65",      CFGTOK_O65      },
979         {   "BIN",      CFGTOK_BIN      },
980         {   "BINARY",   CFGTOK_BIN      },
981     };
982
983     while (CfgTok == CFGTOK_IDENT) {
984
985         /* Map the identifier to a token */
986         cfgtok_t FormatTok;
987         CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
988         FormatTok = CfgTok;
989
990         /* Skip the name and the following colon */
991         CfgNextTok ();
992         CfgConsumeColon ();
993
994         /* Parse the format options */
995         switch (FormatTok) {
996
997             case CFGTOK_O65:
998                 ParseO65 ();
999                 break;
1000
1001             case CFGTOK_BIN:
1002                 /* No attribibutes available */
1003                 break;
1004
1005             default:
1006                 Error ("Unexpected format token");
1007         }
1008
1009         /* Skip the semicolon */
1010         CfgConsumeSemi ();
1011     }
1012 }
1013
1014
1015
1016 static void ParseConDes (void)
1017 /* Parse the CONDES feature */
1018 {
1019     static const IdentTok Attributes [] = {
1020         {   "SEGMENT",          CFGTOK_SEGMENT          },
1021         {   "LABEL",            CFGTOK_LABEL            },
1022         {   "COUNT",            CFGTOK_COUNT            },
1023         {   "TYPE",             CFGTOK_TYPE             },
1024         {   "ORDER",            CFGTOK_ORDER            },
1025     };
1026
1027     static const IdentTok Types [] = {
1028         {   "CONSTRUCTOR",      CFGTOK_CONSTRUCTOR      },
1029         {   "DESTRUCTOR",       CFGTOK_DESTRUCTOR       },
1030     };
1031
1032     static const IdentTok Orders [] = {
1033         {   "DECREASING",       CFGTOK_DECREASING       },
1034         {   "INCREASING",       CFGTOK_INCREASING       },
1035     };
1036
1037     /* Attribute values. */
1038     char SegName[sizeof (CfgSVal)];
1039     char Label[sizeof (CfgSVal)];
1040     char Count[sizeof (CfgSVal)];
1041     /* Initialize to avoid gcc warnings: */
1042     int Type = -1;
1043     ConDesOrder Order = cdIncreasing;
1044
1045     /* Bitmask to remember the attributes we got already */
1046     enum {
1047         atNone          = 0x0000,
1048         atSegName       = 0x0001,
1049         atLabel         = 0x0002,
1050         atCount         = 0x0004,
1051         atType          = 0x0008,
1052         atOrder         = 0x0010
1053     };
1054     unsigned AttrFlags = atNone;
1055
1056     /* Parse the attributes */
1057     while (1) {
1058
1059         /* Map the identifier to a token */
1060         cfgtok_t AttrTok;
1061         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1062         AttrTok = CfgTok;
1063
1064         /* An optional assignment follows */
1065         CfgNextTok ();
1066         CfgOptionalAssign ();
1067
1068         /* Check which attribute was given */
1069         switch (AttrTok) {
1070
1071             case CFGTOK_SEGMENT:
1072                 /* Don't allow this twice */
1073                 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1074                 /* We expect an identifier */
1075                 CfgAssureIdent ();
1076                 /* Remember the value for later */
1077                 strcpy (SegName, CfgSVal);
1078                 break;
1079
1080             case CFGTOK_LABEL:
1081                 /* Don't allow this twice */
1082                 FlagAttr (&AttrFlags, atLabel, "LABEL");
1083                 /* We expect an identifier */
1084                 CfgAssureIdent ();
1085                 /* Remember the value for later */
1086                 strcpy (Label, CfgSVal);
1087                 break;
1088
1089             case CFGTOK_COUNT:
1090                 /* Don't allow this twice */
1091                 FlagAttr (&AttrFlags, atCount, "COUNT");
1092                 /* We expect an identifier */
1093                 CfgAssureIdent ();
1094                 /* Remember the value for later */
1095                 strcpy (Count, CfgSVal);
1096                 break;
1097
1098             case CFGTOK_TYPE:
1099                 /* Don't allow this twice */
1100                 FlagAttr (&AttrFlags, atType, "TYPE");
1101                 /* The type may be given as id or numerical */
1102                 if (CfgTok == CFGTOK_INTCON) {
1103                     CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1104                     Type = (int) CfgIVal;
1105                 } else {
1106                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1107                     switch (CfgTok) {
1108                         case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON;    break;
1109                         case CFGTOK_DESTRUCTOR:  Type = CD_TYPE_DES;    break;
1110                         default: FAIL ("Unexpected type token");
1111                     }
1112                 }
1113                 break;
1114
1115             case CFGTOK_ORDER:
1116                 /* Don't allow this twice */
1117                 FlagAttr (&AttrFlags, atOrder, "ORDER");
1118                 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1119                 switch (CfgTok) {
1120                     case CFGTOK_DECREASING: Order = cdDecreasing;       break;
1121                     case CFGTOK_INCREASING: Order = cdIncreasing;       break;
1122                     default: FAIL ("Unexpected order token");
1123                 }
1124                 break;
1125
1126             default:
1127                 FAIL ("Unexpected attribute token");
1128
1129         }
1130
1131         /* Skip the attribute value */
1132         CfgNextTok ();
1133
1134         /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1135         if (CfgTok == CFGTOK_SEMI) {
1136             break;
1137         } else if (CfgTok == CFGTOK_COMMA) {
1138             CfgNextTok ();
1139         }
1140     }
1141
1142     /* Check if we have all mandatory attributes */
1143     AttrCheck (AttrFlags, atSegName, "SEGMENT");
1144     AttrCheck (AttrFlags, atLabel, "LABEL");
1145     AttrCheck (AttrFlags, atType, "TYPE");
1146
1147     /* Check if the condes has already attributes defined */
1148     if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1149         CfgError ("CONDES attributes for type %d are already defined", Type);
1150     }
1151
1152     /* Define the attributes */
1153     ConDesSetSegName (Type, SegName);
1154     ConDesSetLabel (Type, Label);
1155     if (AttrFlags & atCount) {
1156         ConDesSetCountSym (Type, Count);
1157     }
1158     if (AttrFlags & atOrder) {
1159         ConDesSetOrder (Type, Order);
1160     }
1161 }
1162
1163
1164
1165 static void ParseStartAddress (void)
1166 /* Parse the STARTADDRESS feature */
1167 {
1168     static const IdentTok Attributes [] = {
1169         {   "DEFAULT",  CFGTOK_DEFAULT },
1170     };
1171
1172
1173     /* Attribute values. */
1174     unsigned long DefStartAddr = 0;
1175
1176     /* Bitmask to remember the attributes we got already */
1177     enum {
1178         atNone          = 0x0000,
1179         atDefault       = 0x0001
1180     };
1181     unsigned AttrFlags = atNone;
1182
1183     /* Parse the attributes */
1184     while (1) {
1185
1186         /* Map the identifier to a token */
1187         cfgtok_t AttrTok;
1188         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1189         AttrTok = CfgTok;
1190
1191         /* An optional assignment follows */
1192         CfgNextTok ();
1193         CfgOptionalAssign ();
1194
1195         /* Check which attribute was given */
1196         switch (AttrTok) {
1197
1198             case CFGTOK_DEFAULT:
1199                 /* Don't allow this twice */
1200                 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1201                 /* We expect a number */
1202                 CfgAssureInt ();
1203                 CfgRangeCheck (0, 0xFFFFFF);
1204                 /* Remember the value for later */
1205                 DefStartAddr = CfgIVal;
1206                 break;
1207
1208             default:
1209                 FAIL ("Unexpected attribute token");
1210
1211         }
1212
1213         /* Skip the attribute value */
1214         CfgNextTok ();
1215
1216         /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1217         if (CfgTok == CFGTOK_SEMI) {
1218             break;
1219         } else if (CfgTok == CFGTOK_COMMA) {
1220             CfgNextTok ();
1221         }
1222     }
1223
1224     /* Check if we have all mandatory attributes */
1225     AttrCheck (AttrFlags, atDefault, "DEFAULT");
1226
1227     /* If no start address was given on the command line, use the one given
1228      * here
1229      */
1230     if (!HaveStartAddr) {
1231         StartAddr = DefStartAddr;
1232     }
1233 }
1234
1235
1236
1237 static void ParseFeatures (void)
1238 /* Parse a features section */
1239 {
1240     static const IdentTok Features [] = {
1241         {   "CONDES",       CFGTOK_CONDES       },
1242         {   "STARTADDRESS", CFGTOK_STARTADDRESS },
1243     };
1244
1245     while (CfgTok == CFGTOK_IDENT) {
1246
1247         /* Map the identifier to a token */
1248         cfgtok_t FeatureTok;
1249         CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1250         FeatureTok = CfgTok;
1251
1252         /* Skip the name and the following colon */
1253         CfgNextTok ();
1254         CfgConsumeColon ();
1255
1256         /* Parse the format options */
1257         switch (FeatureTok) {
1258
1259             case CFGTOK_CONDES:
1260                 ParseConDes ();
1261                 break;
1262
1263             case CFGTOK_STARTADDRESS:
1264                 ParseStartAddress ();
1265                 break;
1266
1267
1268             default:
1269                 Error ("Unexpected feature token");
1270         }
1271
1272         /* Skip the semicolon */
1273         CfgConsumeSemi ();
1274     }
1275 }
1276
1277
1278
1279 static void ParseSymbols (void)
1280 /* Parse a symbols section */
1281 {
1282     while (CfgTok == CFGTOK_IDENT) {
1283
1284         long Val;
1285
1286         /* Remember the name */
1287         char Name [sizeof (CfgSVal)];
1288         strcpy (Name, CfgSVal);
1289         CfgNextTok ();
1290
1291         /* Allow an optional assignment */
1292         CfgOptionalAssign ();
1293
1294         /* Make sure the next token is an integer, read and skip it */
1295         CfgAssureInt ();
1296         Val = CfgIVal;
1297         CfgNextTok ();
1298
1299         /* Generate an export with the given value */
1300         CreateConstExport (Name, Val);
1301
1302         /* Skip the semicolon */
1303         CfgConsumeSemi ();
1304     }
1305 }
1306
1307
1308
1309 static void ParseConfig (void)
1310 /* Parse the config file */
1311 {
1312     static const IdentTok BlockNames [] = {
1313         {   "MEMORY",   CFGTOK_MEMORY   },
1314         {   "FILES",    CFGTOK_FILES    },
1315         {   "SEGMENTS", CFGTOK_SEGMENTS },
1316         {   "FORMATS",  CFGTOK_FORMATS  },
1317         {   "FEATURES", CFGTOK_FEATURES },
1318         {   "SYMBOLS",  CFGTOK_SYMBOLS  },
1319     };
1320     cfgtok_t BlockTok;
1321
1322     do {
1323
1324         /* Read the block ident */
1325         CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1326         BlockTok = CfgTok;
1327         CfgNextTok ();
1328
1329         /* Expected a curly brace */
1330         CfgConsume (CFGTOK_LCURLY, "`{' expected");
1331
1332         /* Read the block */
1333         switch (BlockTok) {
1334
1335             case CFGTOK_MEMORY:
1336                 ParseMemory ();
1337                 break;
1338
1339             case CFGTOK_FILES:
1340                 ParseFiles ();
1341                 break;
1342
1343             case CFGTOK_SEGMENTS:
1344                 ParseSegments ();
1345                 break;
1346
1347             case CFGTOK_FORMATS:
1348                 ParseFormats ();
1349                 break;
1350
1351             case CFGTOK_FEATURES:
1352                 ParseFeatures ();
1353                 break;
1354
1355             case CFGTOK_SYMBOLS:
1356                 ParseSymbols ();
1357                 break;
1358
1359             default:
1360                 FAIL ("Unexpected block token");
1361
1362         }
1363
1364         /* Skip closing brace */
1365         CfgConsume (CFGTOK_RCURLY, "`}' expected");
1366
1367     } while (CfgTok != CFGTOK_EOF);
1368 }
1369
1370
1371
1372 void CfgRead (void)
1373 /* Read the configuration */
1374 {
1375     /* Create the descriptors for the binary formats */
1376     BinFmtDesc = NewBinDesc ();
1377     O65FmtDesc = NewO65Desc ();
1378
1379     /* If we have a config name given, open the file, otherwise we will read
1380      * from a buffer.
1381      */
1382     CfgOpenInput ();
1383
1384     /* Parse the file */
1385     ParseConfig ();
1386
1387     /* Close the input file */
1388     CfgCloseInput ();
1389 }
1390
1391
1392
1393 static void CreateRunDefines (SegDesc* S)
1394 /* Create the defines for a RUN segment */
1395 {
1396     char Buf [256];
1397
1398     xsprintf (Buf, sizeof (Buf), "__%s_RUN__", S->Name);
1399     CreateSegmentExport (Buf, S->Seg, 0);
1400     xsprintf (Buf, sizeof (Buf), "__%s_SIZE__", S->Name);
1401     CreateConstExport (Buf, S->Seg->Size);
1402     S->Flags |= SF_RUN_DEF;
1403 }
1404
1405
1406
1407 static void CreateLoadDefines (Memory* M, SegDesc* S)
1408 /* Create the defines for a LOAD segment */
1409 {
1410     char Buf [256];
1411
1412     xsprintf (Buf, sizeof (Buf), "__%s_LOAD__", S->Name);
1413     CreateMemoryExport (Buf, M, S->Seg->PC - M->Start);
1414     S->Flags |= SF_LOAD_DEF;
1415 }
1416
1417
1418
1419 void CfgAssignSegments (void)
1420 /* Assign segments, define linker symbols where requested */
1421 {
1422     /* Walk through each of the memory sections. Add up the sizes and check
1423      * for an overflow of the section. Assign the start addresses of the
1424      * segments while doing this.
1425      */
1426     Memory* M = MemoryList;
1427     while (M) {
1428
1429         /* Get the start address of this memory area */
1430         unsigned long Addr = M->Start;
1431
1432         /* Walk through the segments in this memory area */
1433         MemListNode* N = M->SegList;
1434         while (N) {
1435
1436             /* Get the segment from the node */
1437             SegDesc* S = N->Seg;
1438
1439             /* Handle ALIGN and OFFSET/START */
1440             if (S->Flags & SF_ALIGN) {
1441                 /* Align the address */
1442                 unsigned long Val = (0x01UL << S->Align) - 1;
1443                 Addr = (Addr + Val) & ~Val;
1444             } else if (S->Flags & (SF_OFFSET | SF_START)) {
1445                 /* Give the segment a fixed starting address */
1446                 unsigned long NewAddr = S->Addr;
1447                 if (S->Flags & SF_OFFSET) {
1448                     /* An offset was given, no address, make an address */
1449                     NewAddr += M->Start;
1450                 }
1451                 if (Addr > NewAddr) {
1452                     /* Offset already too large */
1453                     if (S->Flags & SF_OFFSET) {
1454                         Error ("Offset too small in `%s', segment `%s'",
1455                                M->Name, S->Name);
1456                     } else {
1457                         Error ("Start address too low in `%s', segment `%s'",
1458                                M->Name, S->Name);
1459                     }
1460                 }
1461                 Addr = NewAddr;
1462             }
1463
1464             /* If this is the run area, set the start address of this segment */
1465             if (S->Run == M) {
1466                 S->Seg->PC = Addr;
1467             }
1468
1469             /* Increment the fill level of the memory area and check for an
1470              * overflow.
1471              */
1472             M->FillLevel = Addr + S->Seg->Size - M->Start;
1473             if (M->FillLevel > M->Size) {
1474                 Error ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1475                        M->Name, S->Name, M->FillLevel - M->Size);
1476             }
1477
1478             /* If requested, define symbols for the start and size of the
1479              * segment.
1480              */
1481             if (S->Flags & SF_DEFINE) {
1482                 if ((S->Flags & SF_LOAD_AND_RUN) && S->Run == S->Load) {
1483                     /* RUN and LOAD given and in one memory area.
1484                      * Be careful: We will encounter this code twice, the
1485                      * first time when walking the RUN list, second time when
1486                      * walking the LOAD list. Be sure to define only the
1487                      * relevant symbols on each walk.
1488                      */
1489                     if (S->Load == M) {
1490                         if ((S->Flags & SF_LOAD_DEF) == 0) {
1491                             CreateLoadDefines (M, S);
1492                         } else {
1493                             CHECK ((S->Flags & SF_RUN_DEF) == 0);
1494                             CreateRunDefines (S);
1495                         }
1496                     }
1497                 } else {
1498                     /* RUN and LOAD in different memory areas, or RUN not
1499                      * given, so RUN defaults to LOAD. In the latter case, we
1500                      * have only one copy of the segment in the area.
1501                      */
1502                     if (S->Run == M) {
1503                         CreateRunDefines (S);
1504                     }
1505                     if (S->Load == M) {
1506                         CreateLoadDefines (M, S);
1507                     }
1508                 }
1509             }
1510
1511             /* Calculate the new address */
1512             Addr += S->Seg->Size;
1513
1514             /* Next segment */
1515             N = N->Next;
1516         }
1517
1518         /* If requested, define symbols for start and size of the memory area */
1519         if (M->Flags & MF_DEFINE) {
1520             char Buf [256];
1521             sprintf (Buf, "__%s_START__", M->Name);
1522             CreateMemoryExport (Buf, M, 0);
1523             sprintf (Buf, "__%s_SIZE__", M->Name);
1524             CreateConstExport (Buf, M->Size);
1525             sprintf (Buf, "__%s_LAST__", M->Name);
1526             CreateConstExport (Buf, M->FillLevel);
1527         }
1528
1529         /* Next memory area */
1530         M = M->Next;
1531     }
1532 }
1533
1534
1535
1536 void CfgWriteTarget (void)
1537 /* Write the target file(s) */
1538 {
1539     Memory* M;
1540
1541     /* Walk through the files list */
1542     File* F = FileList;
1543     while (F) {
1544         /* We don't need to look at files with no memory areas */
1545         if (F->MemList) {
1546
1547             /* Is there an output file? */
1548             if (strlen (F->Name) > 0) {
1549
1550                 /* Assign a proper binary format */
1551                 if (F->Format == BINFMT_DEFAULT) {
1552                     F->Format = DefaultBinFmt;
1553                 }
1554
1555                 /* Call the apropriate routine for the binary format */
1556                 switch (F->Format) {
1557
1558                     case BINFMT_BINARY:
1559                         BinWriteTarget (BinFmtDesc, F);
1560                         break;
1561
1562                     case BINFMT_O65:
1563                         O65WriteTarget (O65FmtDesc, F);
1564                         break;
1565
1566                     default:
1567                         Internal ("Invalid binary format: %u", F->Format);
1568
1569                 }
1570
1571             } else {
1572
1573                 /* No output file. Walk through the list and mark all segments
1574                  * loading into these memory areas in this file as dumped.
1575                  */
1576                 M = F->MemList;
1577                 while (M) {
1578
1579                     MemListNode* N;
1580
1581                     /* Debugging */
1582                     Print (stdout, 2, "Skipping `%s'...\n", M->Name);
1583
1584                     /* Walk throught the segments */
1585                     N = M->SegList;
1586                     while (N) {
1587                         if (N->Seg->Load == M) {
1588                             /* Load area - mark the segment as dumped */
1589                             N->Seg->Seg->Dumped = 1;
1590                         }
1591
1592                         /* Next segment node */
1593                         N = N->Next;
1594                     }
1595                     /* Next memory area */
1596                     M = M->FNext;
1597                 }
1598             }
1599         }
1600
1601         /* Next file */
1602         F = F->Next;
1603     }
1604 }
1605
1606
1607