~ubuntu-branches/ubuntu/wily/gargoyle-free/wily-proposed

« back to all changes in this revision

Viewing changes to tads/tads2/fiowrt.c

  • Committer: Bazaar Package Importer
  • Author(s): Sylvain Beucler
  • Date: 2009-09-11 20:09:43 UTC
  • Revision ID: james.westby@ubuntu.com-20090911200943-idgzoyupq6650zpn
Tags: upstream-2009-08-25
ImportĀ upstreamĀ versionĀ 2009-08-25

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ifdef RCSID
 
2
static char RCSid[] =
 
3
"$Header: d:/cvsroot/tads/TADS2/FIOWRT.C,v 1.3 1999/07/11 00:46:29 MJRoberts Exp $";
 
4
#endif
 
5
 
 
6
/* 
 
7
 *   Copyright (c) 1992, 2002 Michael J. Roberts.  All Rights Reserved.
 
8
 *   
 
9
 *   Please see the accompanying license file, LICENSE.TXT, for information
 
10
 *   on using and copying this software.  
 
11
 */
 
12
/*
 
13
Name
 
14
  fiowrt.c - write game to binary file
 
15
Function
 
16
  Writes a game to binary file.  Separated from fio.c so that run-time
 
17
  doesn't have to link in this function, which is unnecessary for playing
 
18
  a game.
 
19
Notes
 
20
  None
 
21
Modified
 
22
  09/14/92 MJRoberts     - note location of undefined objects in errors
 
23
  04/11/92 MJRoberts     - creation
 
24
*/
 
25
 
 
26
#include <stdlib.h>
 
27
#include <string.h>
 
28
#include <time.h>
 
29
#include "os.h"
 
30
#include "std.h"
 
31
#include "mch.h"
 
32
#include "mcm.h"
 
33
#include "mcl.h"
 
34
#include "tok.h"
 
35
#include "obj.h"
 
36
#include "voc.h"
 
37
#include "fio.h"
 
38
#include "dat.h"
 
39
#include "sup.h"
 
40
#include "cmap.h"
 
41
 
 
42
 
 
43
/* write a resource header; returns pointer to next-res field in file */
 
44
static ulong fiowhd(osfildef *fp, errcxdef *ec, char *resname)
 
45
{
 
46
    ulong ret;
 
47
 
 
48
    if (osfwb(fp, resname, (int)(resname[0] + 1))) errsig(ec, ERR_WRTGAM);
 
49
    ret = osfpos(fp);
 
50
    if (osfwb(fp, "\000\000\000\000", 4)) errsig(ec, ERR_WRTGAM);
 
51
    return(ret);
 
52
}
 
53
 
 
54
/* close a resource by writing next-res pointer */
 
55
static void fiowcls(osfildef *fp, errcxdef *ec, ulong respos)
 
56
{
 
57
    ulong endpos;
 
58
    char  buf[4];
 
59
    
 
60
    endpos = osfpos(fp);
 
61
    osfseek(fp, respos, OSFSK_SET);
 
62
    oswp4(buf, endpos);
 
63
    if (osfwb(fp, buf, 4)) errsig(ec, ERR_WRTGAM);
 
64
    osfseek(fp, endpos, OSFSK_SET);
 
65
}
 
66
 
 
67
/* write a required object (just an object number) */
 
68
static void fiowrq(errcxdef *ec, osfildef *fp, objnum objn)
 
69
{
 
70
    uchar buf[2];
 
71
    
 
72
    oswp2(buf, objn);
 
73
    if (osfwb(fp, buf, 2)) errsig(ec, ERR_WRTGAM);
 
74
}
 
75
 
 
76
/* context for fiowrtobj callback */
 
77
struct fiowcxdef
 
78
{
 
79
    mcmcxdef *fiowcxmem;
 
80
    errcxdef *fiowcxerr;
 
81
    osfildef *fiowcxfp;
 
82
    uint      fiowcxflg;
 
83
    int       fiowcxund;
 
84
    osfildef *fiowcxffp;
 
85
    uint      fiowcxseed;
 
86
    uint      fiowcxinc;
 
87
    int       fiowcxdebug;
 
88
};
 
89
typedef struct fiowcxdef fiowcxdef;
 
90
 
 
91
/* write out a symbol table entry */
 
92
static void fiowrtsym(void *ctx0, toksdef *t)
 
93
{
 
94
    fiowcxdef  *ctx = (fiowcxdef *)ctx0;
 
95
    uchar       buf[TOKNAMMAX + 50];
 
96
    errcxdef   *ec = ctx->fiowcxerr;
 
97
    osfildef   *fp = ctx->fiowcxfp;
 
98
 
 
99
    buf[0] = t->tokslen;
 
100
    buf[1] = t->tokstyp;
 
101
    oswp2(buf + 2, t->toksval);
 
102
    memcpy(buf + 4, t->toksnam, (size_t)buf[0]);
 
103
    if (osfwb(fp, buf, 4 + t->tokslen)) errsig(ec, ERR_WRTGAM);
 
104
}
 
105
 
 
106
/* write an object given by a symbol table entry */
 
107
static void fiowrtobj(void *ctx0, toksdef *t)
 
108
{
 
109
    fiowcxdef *ctx = (fiowcxdef *)ctx0;
 
110
    uchar      buf[TOKNAMMAX + 50];
 
111
    mcmon      obj;
 
112
    mcmcxdef  *mctx = ctx->fiowcxmem;
 
113
    errcxdef  *ec = ctx->fiowcxerr;
 
114
    osfildef  *fp = ctx->fiowcxfp;
 
115
    uint       flags = ctx->fiowcxflg;
 
116
    uchar     *p;
 
117
    uint       siz;
 
118
    uint       used;
 
119
    int        err = 0;
 
120
    ulong      startpos = osfpos(fp);
 
121
    
 
122
    /* set up start of buffer to write */
 
123
    buf[0] = t->tokstyp;
 
124
    obj = t->toksval;
 
125
    oswp2(buf + 1, obj);
 
126
    
 
127
    switch(t->tokstyp)
 
128
    {
 
129
    case TOKSTOBJ:
 
130
        /* 
 
131
         *   Mark object as finished with compilation.  Note that we must
 
132
         *   do this even though tcdmain() does this as well, because
 
133
         *   running preinit() might have updated properties since the
 
134
         *   last time we marked objects.  
 
135
         */
 
136
        objcomp(mctx, (objnum)obj, ctx->fiowcxdebug);
 
137
 
 
138
        /* get the object's size information */
 
139
        p = mcmlck(mctx, (mcmon)obj);
 
140
        siz = mcmobjsiz(mctx, (mcmon)obj);         /* size in cache */
 
141
        used = objfree(p);          /* size actually used in object */
 
142
        if (objflg(p) & OBJFINDEX) used += objnprop(p) * 4;
 
143
        goto write_func_or_obj;
 
144
                
 
145
    case TOKSTFUNC:
 
146
        /* size of function is entire object */
 
147
        p = mcmlck(mctx, (mcmon)obj);
 
148
        siz = used = mcmobjsiz(mctx, (mcmon)obj);
 
149
 
 
150
    write_func_or_obj:
 
151
        /* write type(OBJ) + objnum + size + sizeused */
 
152
        oswp2(buf+3, siz);
 
153
        oswp2(buf+5, used);
 
154
        if (osfwb(fp, buf, 7)) err = ERR_WRTGAM;
 
155
                
 
156
        /* write contents of object */
 
157
        if (flags & FIOFCRYPT)
 
158
            fioxor(p, used, ctx->fiowcxseed, ctx->fiowcxinc);
 
159
        if (osfwb(fp, p, used)) err = ERR_WRTGAM;
 
160
        
 
161
        /* write fast-load record if applicable */
 
162
        if (ctx->fiowcxffp)
 
163
        {
 
164
            oswp4(buf + 7, startpos);
 
165
            if (osfwb(ctx->fiowcxffp, buf, 11)) err = ERR_WRTGAM;
 
166
        }
 
167
                
 
168
        /*
 
169
         *   We're done with the object - delete it so that
 
170
         *   it doesn't have to be swapped out (which would
 
171
         *   be pointless, since we'll never need it again).
 
172
         */
 
173
        mcmunlck(mctx, (mcmon)obj);
 
174
        mcmfre(mctx, (mcmon)obj);
 
175
        break;
 
176
                
 
177
    case TOKSTEXTERN:
 
178
        /* all we must write is the name & number of ext func */
 
179
        buf[3] = t->tokslen;
 
180
        memcpy(buf + 4, t->toksnam, (size_t)t->tokslen);
 
181
        if (osfwb(fp, buf, t->tokslen + 4)) err = ERR_WRTGAM;
 
182
        
 
183
        /* write fast-load record if applicable */
 
184
        if (ctx->fiowcxffp
 
185
            && osfwb(ctx->fiowcxffp, buf, t->tokslen + 4)) err = ERR_WRTGAM;
 
186
        break;
 
187
                
 
188
    case TOKSTFWDOBJ:
 
189
    case TOKSTFWDFN:
 
190
        {
 
191
            int  e = (t->tokstyp == TOKSTFWDFN ? ERR_UNDEFF : ERR_UNDEFO);
 
192
 
 
193
            if (flags & FIOFBIN)
 
194
            {
 
195
                /* write record for the forward reference */
 
196
                p = mcmlck(mctx, (mcmon)obj);
 
197
                siz = mcmobjsiz(mctx, (mcmon)obj);
 
198
                oswp2(buf+3, siz);
 
199
                if (osfwb(fp, buf, 5)
 
200
                    || osfwb(fp, p, siz))
 
201
                    err = ERR_WRTGAM;
 
202
            }
 
203
            else
 
204
            {
 
205
                /* log the undefined-object error */
 
206
                sup_log_undefobj(mctx, ec, e,
 
207
                                 t->toksnam, (int)t->tokslen, obj);
 
208
 
 
209
                /* count the undefined object */
 
210
                ++(ctx->fiowcxund);
 
211
 
 
212
                /*
 
213
                 *   we don't need this object any longer - delete it so
 
214
                 *   that we don't have to bother swapping it in or out
 
215
                 */
 
216
                mcmfre(mctx, (mcmon)obj);
 
217
            }
 
218
        }
 
219
        break;
 
220
    }
 
221
                    
 
222
    /* if an error occurred, signal it */
 
223
    if (err) errsig(ec, err);
 
224
}
 
225
 
 
226
/* write game to binary file */
 
227
static void fiowrt1(mcmcxdef *mctx, voccxdef *vctx, tokcxdef *tokctx,
 
228
                    tokthdef *tab, uchar *fmts, uint fmtl, osfildef *fp,
 
229
                    uint flags, objnum preinit, int extc, uint prpcnt,
 
230
                    char *filever)
 
231
{
 
232
    int         i;
 
233
    int         j;
 
234
    int         k;
 
235
    uchar       buf[TOKNAMMAX + 50];
 
236
    errcxdef   *ec = vctx->voccxerr;
 
237
    ulong       fpos;
 
238
    int         obj;
 
239
    vocidef  ***vpg;
 
240
    vocidef   **v;
 
241
    objnum     *sc;
 
242
    vocdef     *voc;
 
243
    vocwdef    *vw;
 
244
    vocdef    **vhsh;
 
245
    struct tm  *tblock;
 
246
    time_t      timer;
 
247
    fiowcxdef   cbctx;                    /* callback context for toktheach */
 
248
    uint        xor_seed = 63;
 
249
    uint        xor_inc = 64;
 
250
    char       *vsnhdr;
 
251
    uint        vsnlen;
 
252
    char        fastnamebuf[OSFNMAX];    /* fast-load record temp file name */
 
253
    long        flag_seek;
 
254
 
 
255
    /* generate appropriate file version */
 
256
    switch(filever[0])
 
257
    {
 
258
    case 'a':          /* generate .GAM compatible with pre-2.0.15 runtimes */
 
259
        vsnhdr = FIOVSNHDR2;
 
260
        vsnlen = sizeof(FIOVSNHDR2);
 
261
        xor_seed = 17;                                /* use old xor values */
 
262
        xor_inc = 29;
 
263
        break;
 
264
 
 
265
    case 'b':                                    /* generate 2.0.15+ format */
 
266
        vsnhdr = FIOVSNHDR3;
 
267
        vsnlen = sizeof(FIOVSNHDR3);
 
268
        break;
 
269
 
 
270
    case 'c':
 
271
    case '*':                                            /* current version */
 
272
        vsnhdr = FIOVSNHDR;
 
273
        vsnlen = sizeof(FIOVSNHDR);
 
274
        break;
 
275
 
 
276
    default:
 
277
        errsig(ec, ERR_WRTVSN);
 
278
    }
 
279
 
 
280
    /* write file header and version header */
 
281
    if (osfwb(fp, FIOFILHDR, sizeof(FIOFILHDR))
 
282
          || osfwb(fp, vsnhdr, vsnlen))
 
283
        errsig(ec, ERR_WRTGAM);
 
284
 
 
285
    /* 
 
286
     *   write the flags - remember where we wrote it in case we need to
 
287
     *   change the flags later 
 
288
     */
 
289
    flag_seek = osfpos(fp);
 
290
    oswp2(buf, flags);
 
291
    if (osfwb(fp, buf, 2))
 
292
        errsig(ec, ERR_WRTGAM);
 
293
 
 
294
    /* write the timestamp */
 
295
    timer = time(NULL);
 
296
    tblock = localtime(&timer);
 
297
    strcpy(vctx->voccxtim, asctime(tblock));
 
298
    if (osfwb(fp, vctx->voccxtim, (size_t)26))
 
299
        errsig(ec, ERR_WRTGAM);
 
300
 
 
301
    /* write xor parameters if generating post 2.0.15 .GAM file */
 
302
    if (filever[0] != 'a')
 
303
    {
 
304
        fpos = fiowhd(fp, ec, "\003XSI");
 
305
        buf[0] = xor_seed;
 
306
        buf[1] = xor_inc;
 
307
        if (osfwb(fp, buf, 2)) errsig(ec, ERR_WRTGAM);
 
308
        fiowcls(fp, ec, fpos);
 
309
    }
 
310
    
 
311
    /* write count of external functions */
 
312
    if (extc)
 
313
    {
 
314
        fpos = fiowhd(fp, ec, "\006EXTCNT");
 
315
        oswp2(buf, extc);              /* write the external function count */
 
316
        if (osfwb(fp, buf, 2)) errsig(ec, ERR_WRTGAM);
 
317
 
 
318
        /* write XFCN-seek-location header if post 2.0.15 file version */
 
319
        if (filever[0] != 'a')
 
320
        {
 
321
            oswp4(buf, 0);      /* placeholder - TADSRSC sets this up later */
 
322
            if (osfwb(fp, buf, 4)) errsig(ec, ERR_WRTGAM);
 
323
        }
 
324
 
 
325
        /* close the resource */
 
326
        fiowcls(fp, ec, fpos);
 
327
    }
 
328
    
 
329
    /* 
 
330
     *   write the character set information, if a character set was
 
331
     *   specified 
 
332
     */
 
333
    if (G_cmap_id[0] != '\0')
 
334
    {
 
335
        size_t len;
 
336
 
 
337
        /* this is not allowed with explicit file versions a, b, or c */
 
338
        if (filever[0] == 'a' || filever[0] == 'b' || filever[0] == 'c')
 
339
            errsig(ec, ERR_VNOCTAB);
 
340
 
 
341
        /* write out the CHRSET resource header */
 
342
        fpos = fiowhd(fp, ec, "\006CHRSET");
 
343
 
 
344
        /* write out the ID and LDESC of the internal character set */
 
345
        len = strlen(G_cmap_ldesc) + 1;
 
346
        oswp2(buf, len);
 
347
        if (osfwb(fp, G_cmap_id, 4)
 
348
            || osfwb(fp, buf, 2)
 
349
            || osfwb(fp, G_cmap_ldesc, len))
 
350
            errsig(ec, ERR_WRTGAM);
 
351
 
 
352
        /* close the resource */
 
353
        fiowcls(fp, ec, fpos);
 
354
    }
 
355
 
 
356
    /* write OBJ resource header */
 
357
    fpos = fiowhd(fp, ec, "\003OBJ");
 
358
 
 
359
    /* set up the symbol table callback context for writing the objects */
 
360
    cbctx.fiowcxmem = mctx;
 
361
    cbctx.fiowcxerr = ec;
 
362
    cbctx.fiowcxfp  = fp;
 
363
    cbctx.fiowcxund = 0;
 
364
    cbctx.fiowcxseed = xor_seed;
 
365
    cbctx.fiowcxinc = xor_inc;
 
366
    cbctx.fiowcxdebug = (flags & FIOFSYM);
 
367
    if (flags & FIOFFAST)
 
368
    {
 
369
        /* try creating the temp file */
 
370
        cbctx.fiowcxffp = os_create_tempfile(0, fastnamebuf);
 
371
 
 
372
        /* if that failed, we don't have a fast-load table after all */
 
373
        if (cbctx.fiowcxffp == 0)
 
374
        {
 
375
            long curpos;
 
376
            char flag_buf[2];
 
377
            
 
378
            /* clear the fast-load flag */
 
379
            flags &= ~FIOFFAST;
 
380
 
 
381
            /* 
 
382
             *   go back to the flags we wrote to the .gam file header, and
 
383
             *   re-write the new flags without the fast-load bit - since
 
384
             *   we're not going to write a fast-load table, we don't want
 
385
             *   readers thinking they're going to find one 
 
386
             */
 
387
 
 
388
            /* first, remember where we are right now */
 
389
            curpos = osfpos(fp);
 
390
 
 
391
            /* seek back to the flags and re-write the new flags */
 
392
            osfseek(fp, flag_seek, OSFSK_SET);
 
393
            oswp2(flag_buf, flags);
 
394
            if (osfwb(fp, flag_buf, 2))
 
395
                errsig(ec, ERR_WRTGAM);
 
396
 
 
397
            /* seek back to where we started */
 
398
            osfseek(fp, curpos, OSFSK_SET);
 
399
        }
 
400
    }
 
401
    else
 
402
        cbctx.fiowcxffp = (osfildef *)0;
 
403
    cbctx.fiowcxflg = flags;
 
404
 
 
405
    /* go through symbol table, and write each object */
 
406
    toktheach((toktdef *)tab, fiowrtobj, &cbctx);
 
407
 
 
408
    /* also write all objects created with 'new' */
 
409
    for (vpg = vctx->voccxinh, i = 0 ; i < VOCINHMAX ; ++vpg, ++i)
 
410
    {
 
411
        objnum obj;
 
412
 
 
413
        if (!*vpg) continue;
 
414
        for (v = *vpg, obj = (i << 8), j = 0 ; j < 256 ; ++v, ++obj, ++j)
 
415
        {
 
416
            /* if the object was dynamically allocated, write it out */
 
417
            if (*v && (*v)->vociflg & VOCIFNEW)
 
418
            {
 
419
                toksdef t;
 
420
 
 
421
                /* clear the 'new' flag, as this is a static object now */
 
422
                (*v)->vociflg &= ~VOCIFNEW;
 
423
 
 
424
                /* set up a toksdef, and write it out */
 
425
                t.tokstyp = TOKSTOBJ;
 
426
                t.toksval = obj;
 
427
                fiowrtobj(&cbctx, &t);
 
428
            }
 
429
        }
 
430
    }
 
431
                    
 
432
    /* close the resource */
 
433
    fiowcls(fp, ec, fpos);
 
434
    
 
435
    /* copy fast-load records to output file if applicable */
 
436
    if (cbctx.fiowcxffp)
 
437
    {
 
438
        osfildef *fp2 = cbctx.fiowcxffp;
 
439
        char      copybuf[1024];
 
440
        ulong     len;
 
441
        ulong     curlen;
 
442
        
 
443
        /* start with resource header for fast-load records */
 
444
        fpos = fiowhd(fp, ec, "\003FST");
 
445
 
 
446
        /* get length of temp file, then rewind it */
 
447
        len = osfpos(fp2);
 
448
        osfseek(fp2, 0L, OSFSK_SET);
 
449
 
 
450
        /* copy the whole thing to the output file */
 
451
        while (len)
 
452
        {
 
453
            curlen = (len > sizeof(copybuf) ? sizeof(copybuf) : len);
 
454
            if (osfrb(fp2, copybuf, (size_t)curlen)
 
455
                || osfwb(fp, copybuf, (size_t)curlen))
 
456
                errsig(ec, ERR_WRTGAM);
 
457
            len -= curlen;
 
458
        }
 
459
 
 
460
        /* close the fast-load resource */
 
461
        fiowcls(fp, ec, fpos);
 
462
        
 
463
        /* close and delete temp file */
 
464
        osfcls(fp2);
 
465
        osfdel_temp(fastnamebuf);
 
466
    }
 
467
    
 
468
    /* write vocabulary inheritance records - start with header */
 
469
    fpos = fiowhd(fp, ec, "\003INH");
 
470
    
 
471
    /* go through inheritance records and write to file */
 
472
    for (vpg = vctx->voccxinh, i = 0 ; i < VOCINHMAX ; ++vpg, ++i)
 
473
    {
 
474
        if (!*vpg) continue;
 
475
        for (v = *vpg, obj = (i << 8), j = 0 ; j < 256 ; ++v, ++obj, ++j)
 
476
        {
 
477
            if (*v)
 
478
            {
 
479
                buf[0] = (*v)->vociflg;
 
480
                oswp2(buf + 1, obj);
 
481
                oswp2(buf + 3, (*v)->vociloc);
 
482
                oswp2(buf + 5, (*v)->vociilc);
 
483
                oswp2(buf + 7, (*v)->vocinsc);
 
484
                for (k = 0, sc = (*v)->vocisc ; k < (*v)->vocinsc ; ++sc, ++k)
 
485
                {
 
486
                    if (k + 9 >= sizeof(buf)) errsig(ec, ERR_FIOMSC);
 
487
                    oswp2(buf + 9 + (k << 1), (*sc));
 
488
                }
 
489
                if (osfwb(fp, buf, 9 + (2 * (*v)->vocinsc)))
 
490
                    errsig(ec, ERR_WRTGAM);
 
491
            }
 
492
        }
 
493
    }
 
494
    
 
495
    /* close resource */
 
496
    fiowcls(fp, ec, fpos);
 
497
    
 
498
    /* write format strings */
 
499
    if (fmtl)
 
500
    {
 
501
        fpos = fiowhd(fp, ec, "\006FMTSTR");
 
502
        oswp2(buf, fmtl);
 
503
        if (flags & FIOFCRYPT) fioxor(fmts, fmtl, xor_seed, xor_inc);
 
504
        if (osfwb(fp, buf, 2) || osfwb(fp, fmts, fmtl))
 
505
            errsig(ec, ERR_WRTGAM);
 
506
        fiowcls(fp, ec, fpos);
 
507
    }
 
508
    
 
509
    /* write preinit if preinit object was specified */
 
510
    if (flags & FIOFPRE)
 
511
    {
 
512
        fpos = fiowhd(fp, ec, "\007PREINIT");
 
513
        oswp2(buf, preinit);
 
514
        if (osfwb(fp, buf, 2)) errsig(ec, ERR_WRTGAM);
 
515
        fiowcls(fp, ec, fpos);
 
516
    }
 
517
    
 
518
    /* write required objects out of voccxdef */
 
519
    fpos = fiowhd(fp, ec, "\003REQ");
 
520
    fiowrq(ec, fp, vctx->voccxme);
 
521
    fiowrq(ec, fp, vctx->voccxvtk);
 
522
    fiowrq(ec, fp, vctx->voccxstr);
 
523
    fiowrq(ec, fp, vctx->voccxnum);
 
524
    fiowrq(ec, fp, vctx->voccxprd);
 
525
    fiowrq(ec, fp, vctx->voccxvag);
 
526
    fiowrq(ec, fp, vctx->voccxini);
 
527
    fiowrq(ec, fp, vctx->voccxpre);
 
528
    fiowrq(ec, fp, vctx->voccxper);
 
529
    fiowrq(ec, fp, vctx->voccxprom);
 
530
    fiowrq(ec, fp, vctx->voccxpdis);
 
531
    fiowrq(ec, fp, vctx->voccxper2);
 
532
    fiowrq(ec, fp, vctx->voccxpdef);
 
533
    fiowrq(ec, fp, vctx->voccxpask);
 
534
    fiowrq(ec, fp, vctx->voccxppc);
 
535
    fiowrq(ec, fp, vctx->voccxpask2);
 
536
    fiowrq(ec, fp, vctx->voccxperp);
 
537
    fiowrq(ec, fp, vctx->voccxpostprom);
 
538
    fiowrq(ec, fp, vctx->voccxinitrestore);
 
539
    fiowrq(ec, fp, vctx->voccxpuv);
 
540
    fiowrq(ec, fp, vctx->voccxpnp);
 
541
    fiowrq(ec, fp, vctx->voccxpostact);
 
542
    fiowrq(ec, fp, vctx->voccxendcmd);
 
543
    fiowrq(ec, fp, vctx->voccxprecmd);
 
544
    fiowrq(ec, fp, vctx->voccxpask3);
 
545
    fiowrq(ec, fp, vctx->voccxpre2);
 
546
    fiowrq(ec, fp, vctx->voccxpdef2);
 
547
    fiowcls(fp, ec, fpos);
 
548
    
 
549
    /* write compound words */
 
550
    if (vctx->voccxcpl)
 
551
    {
 
552
        fpos = fiowhd(fp, ec, "\004CMPD");
 
553
        oswp2(buf, vctx->voccxcpl);
 
554
        if (flags & FIOFCRYPT)
 
555
            fioxor((uchar *)vctx->voccxcpp, (uint)vctx->voccxcpl,
 
556
                   xor_seed, xor_inc);
 
557
        if (osfwb(fp, buf, 2)
 
558
            || osfwb(fp, vctx->voccxcpp, (uint)vctx->voccxcpl))
 
559
            errsig(ec, ERR_WRTGAM);
 
560
        fiowcls(fp, ec, fpos);
 
561
    }
 
562
    
 
563
    /* write special words */
 
564
    if (vctx->voccxspl)
 
565
    {
 
566
        fpos = fiowhd(fp, ec, "\010SPECWORD");
 
567
        oswp2(buf, vctx->voccxspl);
 
568
        if (flags & FIOFCRYPT)
 
569
            fioxor((uchar *)vctx->voccxspp, (uint)vctx->voccxspl,
 
570
                   xor_seed, xor_inc);
 
571
        if (osfwb(fp, buf, 2)
 
572
            || osfwb(fp, vctx->voccxspp, (uint)vctx->voccxspl))
 
573
            errsig(ec, ERR_WRTGAM);
 
574
        fiowcls(fp, ec, fpos);
 
575
    }
 
576
    
 
577
    /* write vocabulary */
 
578
    fpos = fiowhd(fp, ec, "\003VOC");
 
579
 
 
580
    /* go through each hash chain */
 
581
    for (i = 0, vhsh = vctx->voccxhsh ; i < VOCHASHSIZ ; ++i, ++vhsh)
 
582
    {
 
583
        /* go through each word in this hash chain */
 
584
        for (voc = *vhsh ; voc ; voc = voc->vocnxt)
 
585
        {
 
586
            /* encrypt the word if desired */
 
587
            if (flags & FIOFCRYPT)
 
588
                fioxor(voc->voctxt, (uint)(voc->voclen + voc->vocln2),
 
589
                       xor_seed, xor_inc);
 
590
 
 
591
            /* go through each object relation attached to the word */
 
592
            for (vw = vocwget(vctx, voc->vocwlst) ; vw ;
 
593
                 vw = vocwget(vctx, vw->vocwnxt))
 
594
            {
 
595
                /* clear the 'new' flag, as this is a static object now */
 
596
                vw->vocwflg &= ~VOCFNEW;
 
597
 
 
598
                /* write out this object relation */
 
599
                oswp2(buf, voc->voclen);
 
600
                oswp2(buf+2, voc->vocln2);
 
601
                oswp2(buf+4, vw->vocwtyp);
 
602
                oswp2(buf+6, vw->vocwobj);
 
603
                oswp2(buf+8, vw->vocwflg);
 
604
                if (osfwb(fp, buf, 10)
 
605
                    || osfwb(fp, voc->voctxt, voc->voclen + voc->vocln2))
 
606
                    errsig(ec, ERR_WRTGAM);
 
607
            }
 
608
        }
 
609
    }
 
610
    fiowcls(fp, ec, fpos);
 
611
    
 
612
    /* write the symbol table, if desired */
 
613
    if (flags & FIOFSYM)
 
614
    {
 
615
        fpos = fiowhd(fp, ec, "\006SYMTAB");
 
616
        toktheach((toktdef *)tab, fiowrtsym, &cbctx);
 
617
 
 
618
        /* indicate last symbol with a length of zero */
 
619
        buf[0] = 0;
 
620
        if (osfwb(fp, buf, 4)) errsig(ec, ERR_WRTGAM);
 
621
        fiowcls(fp, ec, fpos);
 
622
    }
 
623
    
 
624
    /* write line source chain, if desired */
 
625
    if ((flags & (FIOFLIN | FIOFLIN2)) != 0 && vctx->voccxrun->runcxdbg != 0)
 
626
    {
 
627
        lindef *lin;
 
628
 
 
629
        /* write the SRC header */
 
630
        fpos = fiowhd(fp, ec, "\003SRC");
 
631
 
 
632
        /* write the line records */
 
633
        for (lin = vctx->voccxrun->runcxdbg->dbgcxlin ; lin ;
 
634
             lin = lin->linnxt)
 
635
        {
 
636
            /* write this record */
 
637
            if (linwrt(lin, fp))
 
638
                errsig(ec, ERR_WRTGAM);
 
639
        }
 
640
 
 
641
        /* done with this section */
 
642
        fiowcls(fp, ec, fpos);
 
643
 
 
644
        /* 
 
645
         *   if we have new-style line records, put a SRC2 header (with no
 
646
         *   block contents) in the file, so that the debugger realizes
 
647
         *   that it has new-style line records (with line numbers rather
 
648
         *   than seek offsets) 
 
649
         */
 
650
        if ((flags & FIOFLIN2) != 0)
 
651
        {
 
652
            fpos = fiowhd(fp, ec, "\004SRC2");
 
653
            fiowcls(fp, ec, fpos);
 
654
        }
 
655
    }
 
656
 
 
657
    /* if writing a precompiled header, write some more information */
 
658
    if (flags & FIOFBIN)
 
659
    {
 
660
        /* write property count */
 
661
        fpos = fiowhd(fp, ec, "\006PRPCNT");
 
662
        oswp2(buf, prpcnt);
 
663
        if (osfwb(fp, buf, 2)) errsig(ec, ERR_WRTGAM);
 
664
        fiowcls(fp, ec, fpos);
 
665
 
 
666
        /* write preprocessor symbol table */
 
667
        fpos = fiowhd(fp, ec, "\006TADSPP");
 
668
        tok_write_defines(tokctx, fp, ec);
 
669
        fiowcls(fp, ec, fpos);
 
670
    }
 
671
 
 
672
    /* write end-of-file resource header */
 
673
    (void)fiowhd(fp, ec, "\004$EOF");
 
674
    osfcls(fp);
 
675
    
 
676
    /* if there are undefined functions/objects, signal an error */
 
677
    if (cbctx.fiowcxund) errsig(ec, ERR_UNDEF);
 
678
}
 
679
 
 
680
/* write game to binary file */
 
681
void fiowrt(mcmcxdef *mctx, voccxdef *vctx, tokcxdef *tokctx, tokthdef *tab,
 
682
            uchar *fmts, uint fmtl, char *fname, uint flags, objnum preinit,
 
683
            int extc, uint prpcnt, char *filever)
 
684
{
 
685
    osfildef *fp;
 
686
    
 
687
    /* open the file */
 
688
    if (!(fp = osfoprwtb(fname, OSFTGAME)))
 
689
        errsig(vctx->voccxerr, ERR_OPWGAM);
 
690
    
 
691
    ERRBEGIN(vctx->voccxerr)
 
692
    
 
693
    /* write the file */
 
694
    fiowrt1(mctx, vctx, tokctx, tab, fmts, fmtl, fp, flags, preinit,
 
695
            extc, prpcnt, filever);
 
696
    os_settype(fname, OSFTGAME);
 
697
   
 
698
    ERRCLEAN(vctx->voccxerr)
 
699
        /* clean up by closing the file */
 
700
        osfcls(fp);
 
701
    ERRENDCLN(vctx->voccxerr)
 
702
}