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

« back to all changes in this revision

Viewing changes to terps/agility/filename.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
/* filename.c-- Low level file i/o and routines to deal  */
 
2
/*  with filename.                                       */
 
3
/* Copyright (C) 1996-1999,2001  Robert Masenten          */
 
4
/* This program may be redistributed under the terms of the
 
5
   GNU General Public License, version 2; see agility.h for details. */
 
6
/*                                                       */
 
7
/* This is part of the source for both AGiliTy: the (Mostly) Universal */
 
8
/*       AGT Interpreter and for the Magx adventure game compiler.    */
 
9
 
 
10
/* Notes for docs:
 
11
   file_type_id must be a type that can be set to 0.
 
12
 */
 
13
 
 
14
#include <stdlib.h>
 
15
#include <errno.h>
 
16
#include <stdio.h>
 
17
#include <assert.h>
 
18
#include <ctype.h>
 
19
 
 
20
#include "agility.h"
 
21
 
 
22
#ifdef force16
 
23
#undef int
 
24
#endif
 
25
 
 
26
#ifdef UNIX_IO
 
27
#include <fcntl.h>
 
28
#include <sys/stat.h>  /* Needed only for file permission bits */
 
29
 
 
30
#ifdef __STRICT_ANSI__
 
31
int fileno(FILE *f);
 
32
FILE *popen(char *s,char *how);
 
33
int pclose(FILE *p);
 
34
#endif
 
35
 
 
36
#ifdef MSDOS16
 
37
#include <io.h>
 
38
#endif
 
39
#endif /* UNIX_IO */
 
40
 
 
41
#ifdef force16
 
42
#define int short
 
43
#endif
 
44
 
 
45
 
 
46
/*----------------------------------------------------------------------*/
 
47
/*  Filetype Data                                                       */
 
48
/*----------------------------------------------------------------------*/
 
49
const char *extname[]={
 
50
  "", 
 
51
  DA1, DA2, DA3, DA4, DA5, DA6, DSS,
 
52
  pHNT, pOPT, pTTL, 
 
53
  pSAV, pSCR, pLOG,
 
54
  pAGX, pINS, pVOC, pCFG,
 
55
  pAGT, pDAT, pMSG, pCMD, pSTD, AGTpSTD};
 
56
 
 
57
 
 
58
#ifdef PATH_SEP
 
59
static const char *path_sep=PATH_SEP;
 
60
#else
 
61
static const char *path_sep=NULL;
 
62
#endif
 
63
 
 
64
/* This returns the options to use when opening the given file type */
 
65
/* rw is true if we are writing, false if we are reading. */
 
66
const char *filetype_info(filetype ft, rbool rw)
 
67
{
 
68
  if (ft<fTTL) return "rb";
 
69
  if (ft==fAGX) return rw ? "wb" : "rb";
 
70
  if (ft==fSAV) return (rw ? "wb" : "rb");
 
71
  if (ft==fTTL || ft==fINS || ft==fVOC) return  "rb";
 
72
#ifdef OPEN_AS_TEXT
 
73
  if (ft>=fCFG) return (open_as_binary ? "rb" : "r");
 
74
#else
 
75
  if (ft>=fCFG) return "rb";
 
76
#endif
 
77
  if (ft==fSCR) {
 
78
    if (rw) 
 
79
      return (BATCH_MODE || make_test) ? "w" : "a";
 
80
    else return "r";
 
81
  }
 
82
  if (ft==fLOG) return rw ? "w" : "r";
 
83
  fatal("INTERNAL ERROR: Invalid filetype.");
 
84
  return NULL;
 
85
}
 
86
 
 
87
 
 
88
/* Returns true if ft is a possible extension in general context ft_base */
 
89
static rbool compat_ext(filetype ft, filetype ft_base)
 
90
{
 
91
  if (ft_base==fNONE || ft_base==fDA1 || ft_base==fAGX) {  /* Game file */
 
92
    return ( ft>=fDA1 && ft<=fDSS)
 
93
      || ft==fOPT || ft==fTTL 
 
94
      || (ft>=fAGX && ft<=fCFG);
 
95
  }
 
96
 
 
97
  if (ft_base==fSAV || ft_base==fSCR || ft_base==fLOG)
 
98
    return (ft==ft_base);
 
99
 
 
100
  if (ft_base==fAGT) {  /* Source code */
 
101
    return (ft>=fAGT && ft<=fCMD) 
 
102
      || ft==fTTL || ft==fCFG;
 
103
  }
 
104
 
 
105
  fatal("INTERNAL ERROR: Invalid file class.");
 
106
  return 0;
 
107
}
 
108
 
 
109
 
 
110
 
 
111
/*----------------------------------------------------------------------*/
 
112
/*  Misc. utilities                                                     */
 
113
/*----------------------------------------------------------------------*/
 
114
 
 
115
char *assemble_filename(const char *path, const char *root,
 
116
                               const char *ext)
 
117
{
 
118
  int len1, len2, len3;
 
119
  char *name;
 
120
 
 
121
  len1=len2=len3=0;
 
122
  if (path!=NULL) len1=strlen(path); 
 
123
  if (root!=NULL) len2=strlen(root); 
 
124
  if (ext!=NULL) len3=strlen(ext);
 
125
  name=rmalloc(len1+len2+len3+1);
 
126
  if (path!=NULL) memcpy(name,path,len1);
 
127
#ifdef PREFIX_EXT
 
128
  if (ext!=NULL) memcpy(name+len1,ext,len3);
 
129
  if (root!=NULL) memcpy(name+len1+len3,root,len2);
 
130
#else
 
131
  if (root!=NULL) memcpy(name+len1,root,len2);
 
132
  if (ext!=NULL) memcpy(name+len1+len2,ext,len3);
 
133
#endif
 
134
  name[len1+len2+len3]=0;
 
135
  return name;
 
136
}
 
137
 
 
138
/* This works for binary files; we don't care about non-binary
 
139
   files since this only used to search for game files. */
 
140
static rbool file_exist(const char *fname)
 
141
{
 
142
  FILE *f;
 
143
  f=fopen(fname,"rb");
 
144
  if (f==NULL) return 0;
 
145
  fclose(f);
 
146
  return 1;
 
147
}
 
148
 
 
149
 
 
150
 
 
151
/* This checks to see if c matches any of the characters in matchset */
 
152
static rbool smatch(char c, const char *matchset)
 
153
{
 
154
  for(;*matchset!=0;matchset++) 
 
155
    if (*matchset==c) return 1;
 
156
  return 0;
 
157
}
 
158
 
 
159
 
 
160
 
 
161
/*----------------------------------------------------------------------*/
 
162
/*  Taking Apart the Filename                                           */
 
163
/*----------------------------------------------------------------------*/
 
164
 
 
165
static int find_path_sep(const char *name)
 
166
{
 
167
  int i;
 
168
 
 
169
  if (path_sep==NULL) 
 
170
    return -1;
 
171
  for(i=strlen(name)-1;i>=0;i--)
 
172
    if (smatch(name[i],path_sep)) break;
 
173
  return i;
 
174
}
 
175
 
 
176
 
 
177
/* Checks to see if the filename (which must be path-free)
 
178
   has an extension. Returns the length of the extensions
 
179
   and writes the extension type in pft */
 
180
static int search_for_ext(const char *name, filetype base_ft,
 
181
                          filetype *pft)
 
182
{
 
183
  filetype t;
 
184
  int xlen,len;
 
185
 
 
186
  *pft=fNONE;
 
187
  len=strlen(name);
 
188
  if (len==0) return 0;
 
189
  for(t=fNONE+1;t<=fSTD;t++) 
 
190
    if (compat_ext(t,base_ft)) {
 
191
      xlen=strlen(extname[t]);
 
192
      if (xlen==0 || xlen>len) continue;
 
193
#ifdef PREFIX_EXT
 
194
      if (strncasecmp(name,extname[t],xlen)==0) 
 
195
#else
 
196
      if (fnamecmp(name+len-xlen,extname[t])==0)
 
197
#endif
 
198
        {
 
199
          *pft=t;
 
200
          return xlen;
 
201
        }
 
202
    }
 
203
#ifdef UNIX_IO
 
204
  /* This is code to make the Unix/etc ports easier to use under
 
205
     tab-completing shells (which often complete "gamename._" or
 
206
     "gamename.ag_" since there are other files in the directory
 
207
     with the same root.) */
 
208
  assert(*pft==fNONE);
 
209
  if (name[len-1]=='.') return 1;
 
210
  if (fnamecmp(name+len-3,".ag")==0) {
 
211
    if (base_ft==fDA1 || base_ft==fAGX) *pft=fAGX;
 
212
    if (base_ft==fAGT) *pft=fAGT;
 
213
  }
 
214
  if (fnamecmp(name+len-3,".da")==0) {
 
215
    if (base_ft==fDA1 || base_ft==fAGX) *pft=fDA1;
 
216
    if (base_ft==fAGT) *pft=fAGT;
 
217
  }
 
218
  if (*pft!=fNONE) return 3;
 
219
#endif
 
220
  return 0;
 
221
}
 
222
 
 
223
 
 
224
/* Extract root filename or extension  from
 
225
   pathless name, given that the extension is of length extlen. */
 
226
/* If isext is true, extract the extension. If isext is false, 
 
227
   then extrac the root. */
 
228
static char *extract_piece(const char *name, int extlen, rbool isext)
 
229
{
 
230
  char *root;
 
231
  int len, xlen;
 
232
  rbool first;  /* If true, extract from beginning; if false, extract
 
233
                   from end */
 
234
 
 
235
  len=strlen(name)-extlen;
 
236
  xlen=extlen;
 
237
  if (isext) {
 
238
    int tmp;
 
239
    tmp=len; len=xlen; xlen=tmp;
 
240
  }
 
241
  if (len==0) return NULL;
 
242
  root=rmalloc((len+1)*sizeof(char));
 
243
#ifdef PREFIX_EXT
 
244
  first=isext ? 1 : 0;  
 
245
#else
 
246
  first=isext ? 0 : 1;
 
247
#endif  
 
248
  if (first) {
 
249
    memcpy(root,name,len);
 
250
    root[len]=0;
 
251
  } else {
 
252
    memcpy(root,name+xlen,len);
 
253
    root[len]=0;
 
254
  }
 
255
  return root;
 
256
}
 
257
 
 
258
 
 
259
/* This returns true if "path" is absolute, false otherwise.
 
260
   This is _very_ platform dependent. */
 
261
static rbool absolute_path(char *path)
 
262
{
 
263
#ifdef pathtest
 
264
  return pathtest(path); 
 
265
#else
 
266
  return 1;
 
267
#endif
 
268
}
 
269
 
 
270
/*----------------------------------------------------------------------*/
 
271
/*  Basic routines for dealing with file contexts                       */
 
272
/*----------------------------------------------------------------------*/
 
273
 
 
274
#define FC(x) ((file_context_rec*)(x))
 
275
 
 
276
/* formal_name is used to get filenames for diagnostic messages, etc. */
 
277
char *formal_name(fc_type fc, filetype ft)
 
278
{
 
279
  if (FC(fc)->special) return FC(fc)->gamename;
 
280
  if (ft==fNONE)
 
281
    return rstrdup(FC(fc)->shortname);
 
282
  if (ft==fAGT_STD)
 
283
    return rstrdup(AGTpSTD);
 
284
  return assemble_filename("",FC(fc)->shortname,extname[ft]);
 
285
}
 
286
 
 
287
#ifdef PATH_SEP
 
288
static rbool test_file(const char *path, const char *root, const char *ext)
 
289
{
 
290
  char *name;
 
291
  rbool tmp;
 
292
 
 
293
  name=assemble_filename(path,root,ext);
 
294
  tmp=file_exist(name);
 
295
  rfree(name);
 
296
  return tmp;
 
297
}
 
298
 
 
299
/* This does a path search for the game files. */
 
300
static void fix_path(file_context_rec *fc)
 
301
{
 
302
  char **ppath;
 
303
 
 
304
 
 
305
  if (gamepath==NULL) return;
 
306
  for(ppath=gamepath;*ppath!=NULL;ppath++) 
 
307
    if (test_file(*ppath,fc->shortname,fc->ext)
 
308
        || test_file(*ppath,fc->shortname,pAGX)
 
309
        || test_file(*ppath,fc->shortname,DA1))
 
310
      {
 
311
        fc->path=rstrdup(*ppath);
 
312
        return;
 
313
      }  
 
314
}
 
315
#endif
 
316
 
 
317
 
 
318
/* This creates a new file context based on gamename. */
 
319
/* ft indicates the rough use it will be put towards:
 
320
     ft=fNONE indicates it's the first pass read, before PATH has been
 
321
         read in, and so the fc shouldn't be filled out until
 
322
         fix_file_context() is called.
 
323
     ft=pDA1 indicates that name refers to the game files.
 
324
     ft=pAGX indicates the name of the AGX file to be written to.
 
325
     ft=pSAV,pLOG,pSCR all indicate that name corresponds to the
 
326
         related type of file. */
 
327
fc_type init_file_context(const char *name,filetype ft)
 
328
{
 
329
  file_context_rec *fc;
 
330
  int p, x;  /* Path and extension markers */
 
331
 
 
332
  fc=rmalloc(sizeof(file_context_rec));
 
333
  fc->special=0;
 
334
 
 
335
#ifdef UNIX
 
336
  if (name[0]=='|') {  /* Output pipe */
 
337
    name++;
 
338
    fc->special=1;
 
339
  }
 
340
#endif
 
341
 
 
342
  fc->gamename=rstrdup(name);  
 
343
 
 
344
#ifdef UNIX
 
345
  x=strlen(fc->gamename);
 
346
  if (fc->gamename[x-1]=='|') {  /* Input pipe */
 
347
    fc->gamename[x-1]=0;
 
348
    fc->special|=2;
 
349
  }
 
350
  if (fc->special) {
 
351
    fc->path=fc->shortname=fc->ext=NULL;
 
352
    return fc;
 
353
  }
 
354
#endif
 
355
 
 
356
  p=find_path_sep(fc->gamename);
 
357
  if (p<0) 
 
358
    fc->path=NULL;
 
359
  else {
 
360
    fc->path=rmalloc((p+2)*sizeof(char));    
 
361
    memcpy(fc->path,fc->gamename,p+1);
 
362
    fc->path[p+1]='\0';
 
363
  }
 
364
  x=search_for_ext(fc->gamename+p+1,ft,&fc->ft);
 
365
  fc->shortname=extract_piece(fc->gamename+p+1,x,0);
 
366
  fc->ext=extract_piece(fc->gamename+p+1,x,1);
 
367
 
 
368
#ifdef PATH_SEP
 
369
  if (fc->path==NULL && ft==fDA1) 
 
370
    fix_path(fc);
 
371
#endif
 
372
  return fc;
 
373
}
 
374
 
 
375
 
 
376
void fix_file_context(fc_type fc,filetype ft)
 
377
{
 
378
#ifdef PATH_SEP
 
379
  if (FC(fc)->path==NULL && ft==fDA1)   
 
380
    fix_path(FC(fc));
 
381
#endif
 
382
}
 
383
 
 
384
 
 
385
/* This creates new file contexts from old. */
 
386
/* This is used to create save/log/script filenames from the game name,
 
387
   and to create include files in the same directory as the source file. */
 
388
fc_type convert_file_context(fc_type fc,filetype ft,const char *name)
 
389
{
 
390
  file_context_rec *nfc;
 
391
  rbool local_ftype; /* Indicates file should be in working directory,
 
392
                        not game directory. */
 
393
 
 
394
  local_ftype=(ft==fSAV || ft==fSCR || ft==fLOG );
 
395
  if (BATCH_MODE || make_test) local_ftype=0;
 
396
 
 
397
  if (name==NULL) {
 
398
    nfc=rmalloc(sizeof(file_context_rec));
 
399
    nfc->gamename=NULL;
 
400
    nfc->path=NULL;
 
401
    nfc->shortname=rstrdup(fc->shortname);
 
402
    nfc->ext=NULL;
 
403
    nfc->ft=fNONE;
 
404
    nfc->special=0;  
 
405
  } else {
 
406
    nfc=init_file_context(name,ft);
 
407
  }   
 
408
 
 
409
  /* If path already defined, then combine paths. */
 
410
  if (!local_ftype && nfc->path!=NULL && !absolute_path(nfc->path)) {
 
411
    char *newpath;
 
412
    newpath=nfc->path;
 
413
    newpath=assemble_filename(fc->path,nfc->path,"");
 
414
    rfree(nfc->path);
 
415
    nfc->path=newpath;
 
416
  }
 
417
 
 
418
  /* scripts, save-games and logs should go in  the working directory, 
 
419
     not the game directory, so leave nfc->path equal to NULL for them. */
 
420
  if (!local_ftype && nfc->path==NULL)
 
421
    nfc->path=rstrdup(fc->path); /* Put files in game directory */
 
422
  return nfc;
 
423
}
 
424
 
 
425
void release_file_context(fc_type *pfc)
 
426
{
 
427
  file_context_rec *fc;
 
428
  fc=FC(*pfc);
 
429
  rfree(fc->gamename);
 
430
  rfree(fc->path);
 
431
  rfree(fc->shortname);
 
432
  rfree(fc->ext);
 
433
  rfree(fc);
 
434
}
 
435
 
 
436
 
 
437
/*----------------------------------------------------------------------*/
 
438
/*   Routines for Finding Files                                         */
 
439
/*----------------------------------------------------------------------*/
 
440
 
 
441
#ifdef UNIX
 
442
/* This requires that no two sav/scr/log files be open at the same time. */
 
443
static int pipecnt=0;
 
444
static FILE *pipelist[6];
 
445
 
 
446
static genfile try_open_pipe(fc_type fc, filetype ft, rbool rw)
 
447
{
 
448
  FILE *f;
 
449
 
 
450
  errno=0;
 
451
  if (ft!=fSAV && ft!=fSCR && ft!=fLOG) return NULL;
 
452
  if (rw && fc->special!=1) return NULL; 
 
453
  if (!rw && fc->special!=2) return NULL;
 
454
  if (pipecnt>=6) return NULL;
 
455
 
 
456
  f=popen(fc->gamename,rw ? "w" : "r"); /* Need to indicate this is a pipe */
 
457
  pipelist[pipecnt++]=f;
 
458
  return f;
 
459
}
 
460
#endif
 
461
 
 
462
 
 
463
static genfile try_open_file(const char *path, const char *root, 
 
464
                             const char *ext, const char *how,
 
465
                             rbool nofix)
 
466
{
 
467
  char *name;
 
468
  FILE *f;
 
469
 
 
470
  name=assemble_filename(path,root,ext);
 
471
  f=fopen(name,how);
 
472
#ifndef MSDOS
 
473
#ifndef GLK
 
474
  if (f==NULL && !nofix) { /* Try uppercasing it. */
 
475
    char *s;
 
476
    for(s=name;*s!=0;s++)
 
477
      *s=toupper(*s);
 
478
    f=fopen(name,how);
 
479
  }
 
480
#else
 
481
  /*
 
482
   * Try converting just the file name extension to uppercase.  This
 
483
   * helps us to handle cases where AGT games are unzipped without
 
484
   * filename case conversions - in these cases, the files will carry
 
485
   * extensions .TTL, .DA1, and so on, whereas we'll be looking for
 
486
   * files with extensions .ttl, .da1, etc.  This is one part of
 
487
   * being file name case insensitive - the other part is to define
 
488
   * fnamecmp as strcasecmp, which we do in config.h.
 
489
   */
 
490
  if (f == NULL && !nofix && ext != NULL) {
 
491
    char *uc_ext;
 
492
    int  i;
 
493
 
 
494
    /* Free the existing name. */
 
495
    rfree (name);
 
496
 
 
497
    /* Convert the extension to uppercase. */
 
498
    uc_ext = rmalloc (strlen (ext) + 1);
 
499
    for (i = 0; i < strlen (ext); i++)
 
500
      uc_ext[i] = toupper (ext[i]);
 
501
    uc_ext[strlen (ext)] = '\0';
 
502
 
 
503
    /* Form a new filename and try to open that one. */
 
504
    name = assemble_filename (path, root, uc_ext);
 
505
    rfree (uc_ext);
 
506
    f = fopen (name, how);
 
507
  }
 
508
#endif
 
509
#endif
 
510
  rfree(name);
 
511
  return f;
 
512
}
 
513
 
 
514
 
 
515
static genfile findread(file_context_rec *fc, filetype ft)
 
516
{
 
517
  genfile f;
 
518
 
 
519
  f=NULL;
 
520
 
 
521
#ifdef UNIX
 
522
  if (fc->special) {  /* It's a pipe */
 
523
    f=try_open_pipe(fc,ft,0);
 
524
    return f;
 
525
  }
 
526
#endif
 
527
  if (ft==fAGT_STD) {
 
528
    f=try_open_file(fc->path,AGTpSTD,"",filetype_info(ft,0),0);
 
529
    return f;
 
530
  }
 
531
  if (ft==fAGX || ft==fNONE)  /* Try opening w/o added extension */
 
532
    f=try_open_file(fc->path,fc->shortname,fc->ext,filetype_info(ft,0),0);
 
533
  if (f==NULL)
 
534
    f=try_open_file(fc->path,fc->shortname,extname[ft],filetype_info(ft,0),0);
 
535
  return f;
 
536
}
 
537
 
 
538
 
 
539
/*----------------------------------------------------------------------*/
 
540
/*  File IO Routines                                                    */
 
541
/*----------------------------------------------------------------------*/
 
542
 
 
543
genfile readopen(fc_type fc, filetype ft, char **errstr)
 
544
{
 
545
  genfile f;
 
546
 
 
547
  *errstr=NULL;
 
548
  f=findread(fc,ft);
 
549
  if (f==NULL) {
 
550
    const char *s, *t;
 
551
#ifdef UNIX
 
552
    if (errno==0 && fc->special) { /* Bad pipe type */
 
553
      *errstr=rstrdup("Invalid pipe request.");
 
554
      return f;
 
555
    }
 
556
#endif    
 
557
    s=strerror(errno);
 
558
    t=formal_name(fc,ft);
 
559
    *errstr=rmalloc(30+strlen(t)+strlen(s));
 
560
    sprintf(*errstr,"Cannot open file %s: %s.",t,s);
 
561
  }
 
562
  return f;
 
563
}
 
564
 
 
565
rbool fileexist(fc_type fc, filetype ft)
 
566
{
 
567
  genfile f;
 
568
 
 
569
  if (fc->special) return 0;
 
570
  f=try_open_file(fc->path,fc->shortname,extname[ft],filetype_info(ft,0),1);
 
571
  if (f!=NULL) { /* File already exists */
 
572
    readclose(f);
 
573
    return 1;
 
574
  }
 
575
  return 0;
 
576
}
 
577
 
 
578
 
 
579
genfile writeopen(fc_type fc, filetype ft, 
 
580
                  file_id_type *pfileid, char **errstr)
 
581
{
 
582
  char *name;
 
583
  genfile f;
 
584
 
 
585
  *errstr=NULL;
 
586
  name=NULL;
 
587
 
 
588
#ifdef UNIX
 
589
  if (fc->special) {  /* It's a pipe */
 
590
    f=try_open_pipe(fc,ft,1);
 
591
    if (f==NULL && errno==0) {
 
592
      *errstr=rstrdup("Invalid pipe request.");
 
593
      return f;
 
594
    }
 
595
    if (f==NULL)  /* For error messages */
 
596
      name=rstrdup(fc->gamename);
 
597
  } else
 
598
#endif
 
599
    {
 
600
      name=assemble_filename(FC(fc)->path,FC(fc)->shortname,extname[ft]);
 
601
      f=fopen(name,filetype_info(ft,1));
 
602
    }
 
603
  if (f==NULL) {
 
604
    const char *s;
 
605
    s=strerror(errno);
 
606
    *errstr=rmalloc(30+strlen(name)+strlen(s));
 
607
    sprintf(*errstr,"Cannot open file %s: %s.",name,s);
 
608
  }
 
609
  if (pfileid==NULL)
 
610
    rfree(name);
 
611
  else 
 
612
    *pfileid=(void*)name;
 
613
  return f;
 
614
}
 
615
 
 
616
 
 
617
rbool filevalid(genfile f, filetype ft)
 
618
{
 
619
  return (f!=NULL);
 
620
}
 
621
 
 
622
 
 
623
 
 
624
void binseek(genfile f, long offset)
 
625
{
 
626
  assert(f!=NULL);
 
627
  assert(offset>=0);
 
628
#ifdef UNIX_IO
 
629
  if (lseek(fileno(f),offset,SEEK_SET)==-1) 
 
630
#else
 
631
  if (fseek(f,offset,SEEK_SET)!=0) 
 
632
#endif
 
633
    fatal(strerror(errno));
 
634
}
 
635
 
 
636
 
 
637
/* This returns the number of bytes read, or 0 if there was an error. */
 
638
long varread(genfile f, void *buff, long recsize, long recnum, char **errstr)
 
639
{
 
640
  long num;
 
641
 
 
642
  *errstr=NULL;
 
643
  assert(f!=NULL);
 
644
#ifdef UNIX_IO
 
645
#ifdef MSDOS16
 
646
  num=(unsigned int)read(fileno(f),buff,recsize*recnum);
 
647
  if (num==(unsigned int)-1) 
 
648
#else
 
649
    num=read(fileno(f),buff,recsize*recnum);
 
650
    if (num==-1) 
 
651
#endif
 
652
    {
 
653
      *errstr=rstrdup(strerror(errno));
 
654
      return 0;
 
655
    }
 
656
#else
 
657
    errno=0;
 
658
    num=fread(buff,recsize,recnum,f);
 
659
    if (num!=recnum && errno!=0)
 
660
      *errstr=rstrdup(strerror(errno));
 
661
    num=num*recsize;
 
662
#endif
 
663
    return num;
 
664
}
 
665
 
 
666
rbool binread(genfile f, void *buff, long recsize, long recnum, char **errstr)
 
667
{
 
668
  long num;
 
669
 
 
670
  num=varread(f,buff,recsize,recnum,errstr);
 
671
  if (num<recsize*recnum && *errstr==NULL) 
 
672
    *errstr=rstrdup("Unexpected end of file.");
 
673
  return (*errstr==NULL);
 
674
}
 
675
 
 
676
 
 
677
rbool binwrite(genfile f, void *buff, long recsize, long recnum, rbool ferr)
 
678
{
 
679
  assert(f!=NULL);
 
680
#ifdef UNIX_IO
 
681
  if (write(fileno(f),buff,recsize*recnum)==-1)
 
682
#else
 
683
  if (fwrite(buff,recsize,recnum,f)!=recnum)
 
684
#endif
 
685
    {
 
686
    if (ferr) fatal(strerror(errno));
 
687
    return 0;
 
688
  }
 
689
  return 1;
 
690
}
 
691
 
 
692
#ifdef UNIX 
 
693
static rbool closepipe(genfile f)
 
694
{
 
695
  int i;
 
696
  for(i=0;i<pipecnt;i++) 
 
697
    if (pipelist[i]==f) {
 
698
      pclose(f);
 
699
      for(;i<pipecnt-1;i++) 
 
700
        pipelist[i]=pipelist[i+1];
 
701
      pipecnt--;
 
702
      return 1;
 
703
    }
 
704
  return 0;
 
705
}
 
706
#endif
 
707
 
 
708
void readclose(genfile f)
 
709
{
 
710
  assert(f!=NULL);
 
711
#ifdef UNIX
 
712
  if (closepipe(f)) return;
 
713
#endif
 
714
  if (fclose(f)==EOF)
 
715
    fatal(strerror(errno));
 
716
}
 
717
 
 
718
void writeclose(genfile f, file_id_type fileid)
 
719
{
 
720
  assert(f!=NULL);
 
721
  rfree(fileid);  
 
722
#ifdef UNIX
 
723
  if (closepipe(f)) return;
 
724
#endif
 
725
  fclose(f);
 
726
}
 
727
 
 
728
void binremove(genfile f, file_id_type fileid) 
 
729
{
 
730
  assert(f!=NULL); assert(fileid!=NULL);
 
731
  fclose(f);
 
732
  remove((char*)fileid);
 
733
  rfree(fileid);
 
734
}
 
735
 
 
736
long binsize(genfile f)
 
737
/* Returns the size of a binary file */
 
738
{
 
739
  long pos, leng;
 
740
 
 
741
  assert(f!=NULL);
 
742
#ifdef UNIX_IO
 
743
  {
 
744
    long fd;
 
745
 
 
746
    fd=fileno(f);
 
747
    pos=lseek(fd,0,SEEK_CUR);
 
748
    leng=lseek(fd,0,SEEK_END);
 
749
    lseek(fd,pos,SEEK_SET);
 
750
  }
 
751
#else
 
752
  pos=ftell(f);
 
753
  fseek(f,0,SEEK_END);
 
754
  leng=ftell(f);
 
755
  fseek(f,pos,SEEK_SET);
 
756
#endif
 
757
  return leng;
 
758
}
 
759
 
 
760
rbool textrewind(genfile f)
 
761
{
 
762
  assert(f!=NULL);
 
763
  rewind(f);
 
764
  return 0;
 
765
}
 
766
 
 
767
 
 
768
genfile badfile(filetype ft)
 
769
{
 
770
  return NULL;
 
771
}