miriad 4.1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/hio.c ADDED
@@ -0,0 +1,1515 @@
1
+ /*
2
+ The routines to manipulate the file hierarchy.
3
+
4
+ 6-dec-89 pjt extended bug() messages
5
+ 30-apr-90 rjs Support for zero-length items. Added hdelete.
6
+ 15-jul-91 rjs Check for valid item names in hopen and hdelete.
7
+ Some mods to some error messages.
8
+ 18-jul-91 rjs Fixed the name checking to accept the "." file.
9
+ 2-aug-91 rjs Fixed the name checking to accept '-'.
10
+ 16-oct-91 rjs Truncated an item when it is opened for rewriting.
11
+ 12-oct-92 rjs Changed "roundup" macro definition, for pjt.
12
+ 3-mar-93 rjs Add hflush.
13
+ 10-aug-93 rjs Add hexists.
14
+ 26-aug-93 rjs Add habort,hrm.
15
+ 30-aug-93 rjs Add hseek, htell.
16
+ 7-sep-93 rjs Bug fix in habort.
17
+ 23-dec-93 rjs hexists did not handle tno==0 correctly.
18
+ 5-jan-93 rjs Added hmode to check access mode of dataset.
19
+ 4-nov-94 rjs Changes to the way trees and items are stored.
20
+ 15-nov-94 rjs Fixed bug affecting small items being rewritten
21
+ before the dataset is closed.
22
+ 27-dec-94 pjt Fixed (?) bug in hexist for regular files
23
+ and documented this feature
24
+ 13-mar-95 rjs Increase max number of open items.
25
+ 30-jun-95 rjs Declaration to appease gcc.
26
+ 15-may-96 rjs More fiddles with roundup macro.
27
+ 18-mar-97 rjs Remove alignment restriction on hio_c.
28
+ 21-mar-97 rjs Make some previously dynamic allocations static.
29
+ 30-sep-97 rjs Start ntree off at 1 (rather than 0).
30
+ 28-nov-97 rjs Change to cope with text files which do not end with
31
+ a newline char.
32
+ 09-may-00 rjs Get rid of spurious error message in hrm_c. Why didn't
33
+ I see this ages ago?
34
+ 10-jun-02 pjt MIR4 changes to handle 2GB+ files and new int8 types
35
+ 15-jan-03 pjt fix a few prototypes for Const's
36
+ 30-jan-03 pjt allow itemnames to contain _ (e.g. for cd1_1)
37
+ 23-feb-03 pjt merged MIR4
38
+ 22-jul-04 jwr changed type of "size" in hexists_c() from int to size_t
39
+ 05-nov-04 jwr changed file sizes from size_t to off_t
40
+ 01-jan-05 pjt a few bug_c() -> bugv_c()
41
+ 03-jan-05 pjt/rjs hreada/hwritea off_t -> size_t for length
42
+ */
43
+
44
+ #include <stdlib.h>
45
+ #include <string.h>
46
+
47
+ #include "hio.h"
48
+ #include "miriad.h"
49
+
50
+ #define private static
51
+ #if !defined(NULL)
52
+ # define NULL 0
53
+ #endif
54
+
55
+ #define MAXNAME 9
56
+ #define CACHESIZE 64 /* Max size of items to cache. */
57
+ #define CACHE_ENT 16 /* Alignment of cache items. */
58
+
59
+ #define IO_VALID 0 /* Set if the i/o buffer is valid. */
60
+ #define IO_ACTIVE 1
61
+ #define IO_MODIFIED 2
62
+ #define ITEM_READ 0x1
63
+ #define ITEM_WRITE 0x2
64
+ #define ITEM_SCRATCH 0x4
65
+ #define ITEM_APPEND 0x8
66
+ #define ACCESS_MODE (ITEM_READ|ITEM_WRITE|ITEM_SCRATCH|ITEM_APPEND)
67
+ #define ITEM_CACHE 0x10
68
+ #define ITEM_NOCACHE 0x20
69
+
70
+ #define TREE_CACHEMOD 0x1
71
+ #define TREE_NEW 0x2
72
+
73
+ #define RDWR_UNKNOWN 0
74
+ #define RDWR_RDONLY 1
75
+ #define RDWR_RDWR 2
76
+
77
+ typedef struct { /* buffer for I/O operations */
78
+ off_t offset;
79
+ size_t length;
80
+ int state;
81
+ char *buf;
82
+ } IOB;
83
+
84
+ typedef struct item {
85
+ char *name;
86
+ int handle,flags,fd,last;
87
+ off_t size;
88
+ size_t bsize; /* bsize can technicall be an int, since it's an internal buffer size */
89
+ off_t offset;
90
+ struct tree *tree;
91
+ IOB io[2];
92
+ struct item *fwd;
93
+ } ITEM;
94
+
95
+ typedef struct tree {
96
+ char *name;
97
+ int handle,flags,rdwr,wriostat;
98
+ ITEM *itemlist;
99
+ } TREE;
100
+
101
+ static TREE foreign = {"",0,0,0,0,NULL};
102
+ #define MAXITEM 1024
103
+
104
+ private int nitem,ntree;
105
+ private TREE *tree_addr[MAXOPEN];
106
+ private ITEM *item_addr[MAXITEM];
107
+
108
+ #define hget_tree(tno) (tree_addr[tno])
109
+ #define hget_item(tno) (item_addr[tno])
110
+
111
+ private int header_ok,expansion[MAXTYPES],align_size[MAXTYPES];
112
+ private char align_buf[BUFSIZE];
113
+ private int first=TRUE;
114
+
115
+ /* Macro to wait for I/O to complete. If its a synchronous i/o system,
116
+ never bother calling the routine to wait for i/o completion. */
117
+
118
+ #if BUFDBUFF
119
+ #define WAIT(item,iostat) \
120
+ if((item)->io[0].state == IO_ACTIVE){ \
121
+ dwait_c((item)->fd,iostat); \
122
+ (item)->io[0].state = IO_VALID; \
123
+ } else if((item)->io[1].state == IO_ACTIVE){ \
124
+ dwait_c((item)->fd,iostat); \
125
+ (item)->io[1].state = IO_VALID; \
126
+ }
127
+ #else
128
+ #define WAIT(a,b)
129
+ #define dwait_c(a,b)
130
+ #endif
131
+
132
+ /* Declare our private routines. */
133
+
134
+ static void hinit_c(void);
135
+ static int hfind_nl(char *buf, int len);
136
+ static void hcheckbuf_c(ITEM *item, off_t next, int *iostat);
137
+ static void hwrite_fill_c(ITEM *item, IOB *iob, int next, int *iostat);
138
+ static void hcache_create_c(TREE *t, int *iostat);
139
+ static void hcache_read_c(TREE *t, int *iostat);
140
+ static int hname_check(char *name);
141
+ static void hdir_c(ITEM *item);
142
+ static void hrelease_item_c(ITEM *item);
143
+ static ITEM *hcreate_item_c(TREE *tree, char *name);
144
+ static TREE *hcreate_tree_c(char *name);
145
+
146
+ #define check(iostat) if(iostat) bugno_c('f',iostat)
147
+ #define Malloc(a) malloc((size_t)(a))
148
+ #define Realloc(a,b) realloc((a),(size_t)(b))
149
+ #define Strcpy (void)strcpy
150
+ #define Strcat (void)strcat
151
+ #define Memcpy (void)memcpy
152
+
153
+ /************************************************************************/
154
+ void hopen_c(int *tno,Const char *name,Const char *status,int *iostat)
155
+ /**hopen -- Open a data set. */
156
+ /*&pjt */
157
+ /*:low-level-i/o */
158
+ /*+ FORTRAN call sequence
159
+
160
+ subroutine hopen(tno,name,status,iostat)
161
+ integer tno,iostat
162
+ character name*(*),status*(*)
163
+
164
+ This opens a Miriad data-set, and readies it to be read or written.
165
+
166
+ Input:
167
+ name The name of the data set.
168
+ status Either 'old' or 'new'.
169
+ Output:
170
+ tno The file handle of the opened data set.
171
+ iostat I/O status indicator. 0 indicates success. Other values
172
+ are standard system error numbers. */
173
+ /*-- */
174
+ /*----------------------------------------------------------------------*/
175
+ {
176
+ char path[MAXPATH];
177
+ TREE *t;
178
+
179
+ /* Initialise if its the first time through. */
180
+
181
+ if(first)hinit_c();
182
+
183
+ /* Find a spare slot, and set the name etc. */
184
+
185
+ dtrans_c((char *)name,path,iostat);
186
+ if(*iostat)return;
187
+ t = hcreate_tree_c(path);
188
+
189
+ /* Either open an old cache, or create a new cache. */
190
+
191
+ if(!strcmp(status,"old")){
192
+ hcache_read_c(t,iostat);
193
+ t->rdwr = RDWR_UNKNOWN;
194
+ } else if(!strcmp(status,"new")){
195
+ dmkdir_c(path,iostat);
196
+ if(!*iostat)hcache_create_c(t,iostat);
197
+ t->flags |= TREE_NEW;
198
+ t->rdwr = RDWR_RDWR;
199
+ } else *iostat = -1;
200
+
201
+ /* Tidy up before we return. Make sure things are tidy if an error
202
+ occurred during the operation. */
203
+
204
+ *tno = t->handle;
205
+ if(*iostat) hclose_c(*tno);
206
+
207
+ }
208
+ /************************************************************************/
209
+ private void hinit_c()
210
+ /*
211
+ Initialise everthing the first time through.
212
+ ------------------------------------------------------------------------*/
213
+ {
214
+ int i;
215
+
216
+ nitem = 0;
217
+ ntree = 1;
218
+ for(i=0; i < MAXITEM; i++)item_addr[i] = NULL;
219
+ for(i=0; i < MAXOPEN; i++)tree_addr[i] = NULL;
220
+
221
+ /* Tree-0 is a special tree used for "foreign" files. */
222
+
223
+ tree_addr[0] = &foreign;
224
+
225
+ expansion[H_BYTE] = 1;
226
+ expansion[H_INT] = sizeof(int)/H_INT_SIZE;
227
+ expansion[H_INT2] = sizeof(int2)/H_INT2_SIZE;
228
+ expansion[H_INT8] = sizeof(int8)/H_INT8_SIZE;
229
+ expansion[H_REAL] = sizeof(float)/H_REAL_SIZE;
230
+ expansion[H_DBLE] = sizeof(double)/H_DBLE_SIZE;
231
+ expansion[H_CMPLX] = 2*sizeof(float)/H_CMPLX_SIZE;
232
+ expansion[H_TXT] = 1;
233
+
234
+ align_size[H_BYTE] = 1;
235
+ align_size[H_INT] = H_INT_SIZE;
236
+ align_size[H_INT2] = H_INT2_SIZE;
237
+ align_size[H_INT8] = H_INT8_SIZE;
238
+ align_size[H_REAL] = H_REAL_SIZE;
239
+ align_size[H_DBLE] = H_DBLE_SIZE;
240
+ align_size[H_CMPLX] =H_REAL_SIZE;
241
+ align_size[H_TXT] = 1;
242
+ first = FALSE;
243
+ header_ok = FALSE;
244
+ }
245
+ /************************************************************************/
246
+ void hflush_c(int tno,int *iostat)
247
+ /**hflush -- Close a Miriad data set. */
248
+ /*&pjt */
249
+ /*:low-level-i/o */
250
+ /*+ FORTRAN call sequence
251
+
252
+ subroutine hflush(tno,iostat)
253
+ integer tno,iostat
254
+
255
+ Write to disk any changed items.
256
+
257
+ Input:
258
+ tno The handle of the Miriad data set. */
259
+ /*-- */
260
+ /*----------------------------------------------------------------------*/
261
+ {
262
+ TREE *t;
263
+ ITEM *item;
264
+ char s[CACHE_ENT];
265
+ int offset,i,ihandle;
266
+
267
+ t = hget_tree(tno);
268
+ *iostat = 0;
269
+
270
+ /* Determine whether the cache needs to be rewritten, and write out
271
+ any modified buffers. */
272
+
273
+ for(item = t->itemlist; item != NULL ; item = item->fwd){
274
+ if(!item->fd && !(item->flags & ITEM_NOCACHE) ){
275
+ if(item->io[0].state == IO_MODIFIED) t->flags |= TREE_CACHEMOD;
276
+ } else if(item->fd && !(item->flags & ITEM_SCRATCH) ){
277
+ for(i=0; i<2; i++){
278
+ if(item->io[i].state == IO_MODIFIED){
279
+ WAIT(item,iostat);
280
+ if(*iostat)return;
281
+ dwrite_c( item->fd, item->io[i].buf, item->io[i].offset,
282
+ item->io[i].length, iostat);
283
+ if(*iostat)return;
284
+ item->io[i].state = IO_ACTIVE;
285
+ }
286
+ }
287
+ }
288
+ }
289
+
290
+ /* If the cache has been modified, rewrite the cache. */
291
+
292
+ if(t->flags & TREE_CACHEMOD){
293
+ header_ok = TRUE;
294
+ haccess_c(tno,&ihandle,"header","write",iostat);
295
+ header_ok = FALSE; if(*iostat)return;
296
+ for(i=0; i < CACHE_ENT; i++)s[i] = 0;
297
+
298
+ offset = 0;
299
+ for(item = t->itemlist; item != NULL; item = item->fwd){
300
+ if(!item->fd && !(item->flags & ITEM_NOCACHE)){
301
+ Strcpy(s,item->name);
302
+ s[CACHE_ENT-1] = item->size;
303
+ hwriteb_c(ihandle,s,offset,CACHE_ENT,iostat); if(*iostat)return;
304
+ offset += CACHE_ENT;
305
+ if(item->size > 0){
306
+ hwriteb_c(ihandle,item->io[0].buf,offset,item->size,iostat);
307
+ if(*iostat)return;
308
+ }
309
+ item->io[0].state = IO_VALID;
310
+ item->flags |= ITEM_CACHE;
311
+ offset += mroundup(item->size,CACHE_ENT);
312
+ }
313
+ }
314
+ hdaccess_c(ihandle,iostat); if(*iostat)return;
315
+ t->flags &= ~TREE_CACHEMOD;
316
+ }
317
+ *iostat = 0;
318
+ }
319
+ /************************************************************************/
320
+ void habort_c()
321
+ /**habort -- Abort handling of all open data-sets. */
322
+ /*&pjt */
323
+ /*:low-level-i/o */
324
+ /*+ FORTRAN call sequence
325
+
326
+ subroutine habort()
327
+
328
+ This closes all open Miriad data-sets, and deletes any new ones. No
329
+ buffers are flushed. */
330
+ /*-- */
331
+ /*----------------------------------------------------------------------*/
332
+ {
333
+ int i,iostat;
334
+ TREE *t;
335
+ ITEM *it,*itfwd;
336
+ char name[MAXPATH];
337
+
338
+ /* Don't do anything if the hio routines have never been called. */
339
+
340
+ if(first)return;
341
+
342
+ /* Flush everything belonging to tree 0. */
343
+
344
+ hflush_c(0,&iostat);
345
+
346
+ /* Check each possible tree. */
347
+
348
+ for( i=0; i < MAXOPEN; i++){
349
+ if( (t = hget_tree(i) ) != NULL){
350
+ it = t->itemlist;
351
+ while(it != NULL){
352
+ itfwd = it->fwd;
353
+
354
+ /* Wait for any i/o to complete, and prevent further flushing of the buffers
355
+ by pretending that nothing has been modified. */
356
+
357
+ WAIT(it,&iostat);
358
+ it->io[0].state = IO_VALID;
359
+ it->io[1].state = IO_VALID;
360
+
361
+ /* If its an item opened in WRITE mode, remember its name. */
362
+
363
+ if(it->flags & ITEM_WRITE)Strcpy(name,it->name);
364
+ else name[0] = 0;
365
+
366
+ /* If the item is open, close it. */
367
+ /* If it was in write mode, and the name was known, delete it. */
368
+
369
+ if(it->flags & ACCESS_MODE)hdaccess_c(it->handle,&iostat);
370
+ if(*name)hdelete_c(t->handle,name,&iostat);
371
+ it = itfwd;
372
+ }
373
+
374
+ /* Pretend the cache has not changed and finish up. Completely delete
375
+ trees that were opened as NEW. Otherwise finish up. */
376
+
377
+ t->flags &= ~TREE_CACHEMOD;
378
+ if(t->flags & TREE_NEW)hrm_c(t->handle);
379
+ else if(i != 0)hclose_c(t->handle);
380
+ }
381
+ }
382
+ }
383
+ /************************************************************************/
384
+ void hrm_c(int tno)
385
+ /**hrm -- Remove a data-set. */
386
+ /*&pjt */
387
+ /*:low-level-i/o */
388
+ /*+ FORTRAN call sequence
389
+
390
+ subroutine hrm(tno)
391
+
392
+ integer tno
393
+
394
+ This completely removes a Miriad data-set.
395
+
396
+ Input:
397
+ tno The file handle of the open data-set. */
398
+ /*-- */
399
+ /*----------------------------------------------------------------------*/
400
+ {
401
+ char name[MAXPATH];
402
+ int iostat,ihandle;
403
+ TREE *t;
404
+
405
+ haccess_c(tno,&ihandle,".","read",&iostat);
406
+ if(iostat == 0){
407
+ hreada_c(ihandle,name,MAXPATH,&iostat);
408
+ while(iostat == 0){
409
+ hdelete_c(tno,name,&iostat);
410
+ hreada_c(ihandle,name,MAXPATH,&iostat);
411
+ }
412
+ hdaccess_c(ihandle,&iostat);
413
+ }
414
+
415
+ /* Delete the "header" item. */
416
+
417
+ header_ok = TRUE;
418
+ hdelete_c(tno,"header",&iostat);
419
+ header_ok = FALSE;
420
+
421
+ /* Delete the directory itself. */
422
+
423
+ t = hget_tree(tno);
424
+ t->flags &= ~TREE_CACHEMOD;
425
+ drmdir_c(t->name,&iostat);
426
+ hclose_c(tno);
427
+ }
428
+ /************************************************************************/
429
+ void hclose_c(int tno)
430
+ /**hclose -- Close a Miriad data set. */
431
+ /*&pjt */
432
+ /*:low-level-i/o */
433
+ /*+ FORTRAN call sequence
434
+
435
+ subroutine hclose(tno)
436
+ integer tno
437
+
438
+ This closes a Miriad data set. The data set cannot be accessed after the
439
+ close.
440
+
441
+ Input:
442
+ tno The handle of the Miriad data set. */
443
+ /*-- */
444
+ /*----------------------------------------------------------------------*/
445
+ {
446
+ TREE *t;
447
+ ITEM *item,*it1,*it2;
448
+ int iostat;
449
+
450
+ /* Close any open items. */
451
+
452
+ t = hget_tree(tno);
453
+ for(item=t->itemlist; item != NULL; item = item->fwd){
454
+ if(item->flags & ACCESS_MODE){
455
+ bugv_c('w',"Closing item -- %s",item->name);
456
+ hdaccess_c(item->handle,&iostat); check(iostat);
457
+ }
458
+ }
459
+
460
+ /* Flush out the header, if needed. */
461
+
462
+ hflush_c(tno,&iostat); check(iostat);
463
+
464
+ /* Release all allocated stuff. */
465
+
466
+ it1 = t->itemlist;
467
+ while(it1 != NULL){
468
+ it2 = it1->fwd;
469
+ hrelease_item_c(it1);
470
+ it1 = it2;
471
+ }
472
+ tree_addr[tno] = NULL;
473
+ free(t->name);
474
+ free((char *)t);
475
+ ntree--;
476
+ }
477
+ /************************************************************************/
478
+ void hdelete_c(int tno,Const char *keyword,int *iostat)
479
+ /**hdelete -- Delete an item from a data-set. */
480
+ /*&pjt */
481
+ /*:low-level-i/o */
482
+ /*+ FORTRAN call sequence
483
+
484
+ subroutine hdelete(tno,keyword,iostat)
485
+ integer tno,iostat
486
+ character keyword*(*)
487
+
488
+
489
+ This deletes an item from a Miriad data-set. The item must not be "accessed"
490
+ when the hdelete routine is called.
491
+
492
+ Input:
493
+ tno The handle of the data set.
494
+ keyword The name of the item.
495
+ Output:
496
+ iostat I/O status indicator. 0 indicates success. Other values
497
+ are standard system error numbers. */
498
+ /*-- */
499
+ /*----------------------------------------------------------------------*/
500
+ {
501
+ char path[MAXPATH];
502
+ ITEM *item;
503
+ TREE *t;
504
+ int ent_del;
505
+
506
+ if(first)hinit_c();
507
+
508
+ if(tno != 0) if( (*iostat = hname_check((char *)keyword)) ) return;
509
+
510
+ /* Check if the item is aleady here abouts. */
511
+
512
+ t = hget_tree(tno);
513
+
514
+ ent_del = FALSE;
515
+ item = NULL;
516
+ if(tno != 0)
517
+ for(item=t->itemlist; item != NULL; item = item->fwd)
518
+ if(!strcmp(keyword,item->name))break;
519
+
520
+ /* Delete the entry for this item, if there was one. */
521
+
522
+ if(item != NULL){
523
+ if(item->flags & ACCESS_MODE)
524
+ bugv_c('f',"hdelete: Attempt to delete accessed item: %s",keyword);
525
+ if(item->flags & ITEM_CACHE) t->flags |= TREE_CACHEMOD;
526
+ hrelease_item_c(item);
527
+ ent_del = TRUE;
528
+ }
529
+
530
+ /* Always try to delete a file associated with the item. */
531
+
532
+ Strcpy(path,t->name);
533
+ Strcat(path,keyword);
534
+ ddelete_c(path,iostat);
535
+
536
+ /* If we have deleted it once already, do not give any errors if the
537
+ second attempt failed. */
538
+
539
+ if(ent_del) *iostat = 0;
540
+ }
541
+ /************************************************************************/
542
+ void haccess_c(int tno,int *ihandle,Const char *keyword,Const char *status,int *iostat)
543
+ /**haccess -- Open an item of a data set for access. */
544
+ /*&pjt */
545
+ /*:low-level-i/o */
546
+ /*+ FORTRAN call sequence
547
+
548
+ subroutine haccess(tno,itno,keyword,status,iostat)
549
+ integer tno,itno,iostat
550
+ character keyword*(*),status*(*)
551
+
552
+ Miriad data sets consist of a collection of items. Before an item within
553
+ a data set can be read/written, etc, it must be "opened" with the haccess
554
+ routine.
555
+
556
+ Input:
557
+ tno The handle of the data set.
558
+ keyword The name of the item.
559
+ status This can be 'read', 'write', 'append' or 'scratch'.
560
+ 'scratch' files are using $TMPDIR, if present, else current.
561
+ Output:
562
+ itno The handle of the opened item. Note that item handles are
563
+ quite distinct from data-set handles.
564
+ iostat I/O status indicator. 0 indicates success. Other values
565
+ are standard system error numbers. */
566
+ /*-- */
567
+ /*----------------------------------------------------------------------*/
568
+ {
569
+ char path[MAXPATH];
570
+ ITEM *item;
571
+ TREE *t;
572
+ int mode=0;
573
+ char string[3];
574
+
575
+ if(first)hinit_c();
576
+
577
+ if(!strcmp("read",status)) mode = ITEM_READ;
578
+ else if(!strcmp("write",status)) mode = ITEM_WRITE;
579
+ else if(!strcmp("scratch",status))mode = ITEM_SCRATCH;
580
+ else if(!strcmp("append",status)) mode = ITEM_APPEND;
581
+ else bugv_c('f',"haccess_c: unrecognised STATUS=%d",status);
582
+
583
+ if(!strcmp("header",keyword) || !strcmp(".",keyword) ||
584
+ !strcmp("history",keyword)|| tno == 0 ||
585
+ (mode & ITEM_SCRATCH) )mode |= ITEM_NOCACHE;
586
+
587
+ if(tno != 0) if( (*iostat = hname_check((char *)keyword)) )return;
588
+ t = hget_tree(tno);
589
+
590
+ /* If we are writing, check whether we have write permission. */
591
+
592
+ if( !(mode & ITEM_READ) && !(mode & ITEM_NOCACHE) ){
593
+ if(t->rdwr == RDWR_UNKNOWN)hmode_c(tno,string);
594
+ *iostat = t->wriostat;
595
+ if(*iostat) return;
596
+ }
597
+
598
+ /* Check if the item is aleady here abouts. */
599
+
600
+ item = NULL;
601
+ if(tno != 0)
602
+ for(item = t->itemlist; item != NULL; item = item->fwd)
603
+ if(!strcmp(keyword,item->name))break;
604
+
605
+ /* If the item does not exist, create it. Otherwise the item must
606
+ be cacheable, in which case we truncate its length to zero if needed. */
607
+
608
+ if(item == NULL)item = hcreate_item_c(t,(char *)keyword);
609
+ else if((mode & (ITEM_WRITE|ITEM_SCRATCH)) && item->size != 0){
610
+ item->size = 0;
611
+ item->io[0].length = item->io[1].length = 0;
612
+ if(item->flags & ITEM_CACHE) t->flags |= TREE_CACHEMOD;
613
+ }
614
+
615
+ /* Check and set the read/write flags. */
616
+
617
+ if(item->flags & ACCESS_MODE)
618
+ bugv_c('f',"haccess_c: Multiple access to item %s",keyword);
619
+ item->flags |= mode;
620
+
621
+ /* Open the file if necessary. */
622
+
623
+ *iostat = 0;
624
+ item->offset = 0;
625
+ if(!strcmp(keyword,".")){
626
+ hdir_c(item);
627
+ } else if(item->size == 0 && (!(mode & ITEM_WRITE) || (mode & ITEM_NOCACHE))
628
+ && !(item->flags & ITEM_CACHE)){
629
+ Strcpy(path,t->name);
630
+ Strcat(path,keyword);
631
+ dopen_c(&(item->fd),path,(char *)status,&(item->size),iostat);
632
+
633
+ item->bsize = BUFSIZE;
634
+ item->io[0].buf = Malloc(BUFSIZE);
635
+ if(BUFDBUFF)item->io[1].buf = Malloc(BUFSIZE);
636
+ if(mode & ITEM_APPEND) item->offset = item->size;
637
+
638
+ /* If we have opened a file in write mode, remember that this dataset is
639
+ writeable. */
640
+
641
+ if(!(mode & ITEM_READ)){
642
+ if(*iostat == 0) t->rdwr = RDWR_RDWR;
643
+ else t->rdwr = RDWR_RDONLY;
644
+ t->wriostat = *iostat;
645
+ }
646
+ }
647
+ *ihandle = item->handle;
648
+ if(*iostat)hrelease_item_c(item);
649
+ }
650
+ /************************************************************************/
651
+ void hmode_c(int tno,char *mode)
652
+ /* */
653
+ /**hmode -- Return access modes of a dataset. */
654
+ /*&pjt */
655
+ /*:low-level-i/o */
656
+ /*+ FORTRAN call sequence
657
+
658
+ subroutine hmode(tno,mode)
659
+ integer tno
660
+ character mode*(*)
661
+
662
+ Determine the access modes of a data-set
663
+
664
+ Input:
665
+ tno The handle of the data set.
666
+ Output:
667
+ mode This will be either "" (unknown access mode),
668
+ "r" (read-only)
669
+ "rw" (read-write). */
670
+ /*-- */
671
+ /*----------------------------------------------------------------------*/
672
+ {
673
+ int iostat;
674
+ int ihandle;
675
+ TREE *t;
676
+
677
+ /* If its tno==0, give up. */
678
+
679
+ *mode = 0;
680
+ if(tno == 0)return;
681
+
682
+ /* If we do not already know the read/write access, determine it the hard
683
+ way. */
684
+
685
+ t = hget_tree(tno);
686
+ if(t->rdwr == RDWR_UNKNOWN){
687
+ header_ok = TRUE;
688
+ haccess_c(tno,&ihandle,"header","append",&iostat);
689
+ header_ok = FALSE;
690
+ if(!iostat)hdaccess_c(ihandle,&iostat);
691
+ }
692
+
693
+ /* Return the info. */
694
+
695
+ if(t->rdwr == RDWR_RDONLY) Strcpy(mode,"r");
696
+ else if(t->rdwr == RDWR_RDWR) Strcpy(mode,"rw");
697
+ else bugv_c('f',"hmode_c: Algorithmic failure rdwr=%d",t->rdwr);
698
+
699
+ }
700
+ /************************************************************************/
701
+ int hexists_c(int tno,Const char *keyword)
702
+ /**hexists -- Check if an item exists. */
703
+ /*&pjt */
704
+ /*:low-level-i/o */
705
+ /*+ FORTRAN call sequence
706
+
707
+ logical function hexists(tno,keyword)
708
+ integer tno
709
+ character keyword*(*)
710
+
711
+ Check if a particular item exists in a Miriad data-set.
712
+ By setting the input 'tno' to 0, one can also check for
713
+ existence of any regular file.
714
+
715
+ Input:
716
+ tno The handle of the data set. 0 also allowed.
717
+ keyword The name of the item or filename to check.
718
+ Output:
719
+ hexists True if the item exists. */
720
+ /*-- */
721
+ /*----------------------------------------------------------------------*/
722
+ {
723
+ char path[MAXPATH];
724
+ int iostat,fd;
725
+ off_t size;
726
+ ITEM *item;
727
+ TREE *t;
728
+
729
+ /* Check for an invalid name. */
730
+
731
+ if(tno != 0) if(hname_check((char *)keyword)) return(FALSE);
732
+
733
+ /* Check if the item is aleady here abouts. */
734
+
735
+ if(tno != 0){ /* miriad dataset */
736
+ item = NULL;
737
+ t = hget_tree(tno);
738
+ for(item = t->itemlist; item != NULL; item = item->fwd)
739
+ if(!strcmp(keyword,item->name))return(TRUE);
740
+ Strcpy(path,t->name);
741
+ Strcat(path,keyword);
742
+ } else {
743
+ Strcpy(path,keyword); /* regular filename */
744
+ }
745
+
746
+ /* It was not found in the items currently opened, nor the items that
747
+ live in "header". Now try and open a file with this name. */
748
+
749
+
750
+ dopen_c(&fd,path,"read",&size,&iostat);
751
+ if(iostat)return FALSE;
752
+ dclose_c(fd,&iostat);
753
+ if(iostat != 0)bugv_c('f',"hexists_c: Error closing item %s",keyword);
754
+ return TRUE;
755
+ }
756
+ /************************************************************************/
757
+ void hdaccess_c(int ihandle,int *iostat)
758
+ /**hdaccess -- Finish up access to an item. */
759
+ /*&pjt */
760
+ /*:low-level-i/o */
761
+ /*+ FORTRAN call sequence
762
+
763
+ subroutine hdaccess(itno,iostat)
764
+ integer itno,iostat
765
+
766
+ This releases an item. It flushes buffers and waits for i/o to complete.
767
+ For small items that are entirely in memory, these are saved until
768
+ the whole tree is closed before they are written out.
769
+
770
+ Input:
771
+ itno The handle of the item to close up.
772
+ iostat I/O status indicator. 0 indicates success. Other values
773
+ are standard system error numbers. */
774
+ /*-- */
775
+ /*----------------------------------------------------------------------*/
776
+ {
777
+ ITEM *item;
778
+ int i,stat;
779
+
780
+ /* If it has an associated file, flush anything remaining to the file
781
+ and close it up. */
782
+
783
+ item = hget_item(ihandle);
784
+
785
+ /* May be a binary file. Flush modified buffers, wait for i/o to complete,
786
+ and close up. */
787
+
788
+ *iostat = 0;
789
+ stat = 0;
790
+ if(item->fd != 0){
791
+ for(i=0; i<2 && !stat; i++){
792
+ if(item->io[i].state == IO_MODIFIED && !(item->flags & ITEM_SCRATCH)){
793
+ WAIT(item,&stat);
794
+ if(!stat)dwrite_c( item->fd, item->io[i].buf, item->io[i].offset,
795
+ item->io[i].length, &stat);
796
+ item->io[i].state = IO_ACTIVE;
797
+ }
798
+ }
799
+ *iostat = stat;
800
+ WAIT(item,&stat);
801
+ if(stat) *iostat = stat;
802
+ dclose_c(item->fd,&stat);
803
+ if(stat) *iostat = stat;
804
+ hrelease_item_c(item);
805
+
806
+ } else if(item->flags & ITEM_NOCACHE){
807
+ hrelease_item_c(item);
808
+
809
+ /* If it has not associated file, it must be small. Do not release it,
810
+ as it will need to be written to the cache later on. */
811
+
812
+ } else{
813
+ item->flags &= ~ACCESS_MODE;
814
+ if(item->io[0].state == IO_MODIFIED)item->tree->flags |= TREE_CACHEMOD;
815
+ item->io[0].state = IO_VALID;
816
+ }
817
+ }
818
+ /************************************************************************/
819
+ off_t hsize_c(int ihandle)
820
+ /**hsize -- Determine the size (in bytes) of an item. */
821
+ /*&pjt */
822
+ /*:low-level-i/o */
823
+ /*+ FORTRAN call sequence
824
+
825
+ integer function hsize(itno)
826
+ integer itno
827
+
828
+ This returns the size of an item, in bytes.
829
+
830
+ Input:
831
+ itno The handle of the item of interest.
832
+ Output:
833
+ hsize The size of the item in bytes. */
834
+ /*-- */
835
+ /*----------------------------------------------------------------------*/
836
+ {
837
+ ITEM *item;
838
+ item = hget_item(ihandle);
839
+ return item->size;
840
+ }
841
+ /************************************************************************/
842
+ void hio_c(int ihandle,int dowrite,int type,char *buf,
843
+ off_t offset, size_t length,int *iostat)
844
+ /**hread,hwrite -- Read and write items. */
845
+ /*&pjt */
846
+ /*:low-level-i/o */
847
+ /*+ FORTRAN call sequence
848
+
849
+ subroutine hreada(itno,abuf,iostat)
850
+ subroutine hreadb(itno,bbuf,offset,length,iostat)
851
+ subroutine hreadj(itno,jbuf,offset,length,iostat)
852
+ subroutine hreadi(itno,ibuf,offset,length,iostat)
853
+ subroutine hreadr(itno,rbuf,offset,length,iostat)
854
+ subroutine hreadd(itno,dbuf,offset,length,iostat)
855
+ subroutine hwritea(itno,abuf,iostat)
856
+ subroutine hwriteb(itno,bbuf,offset,length,iostat)
857
+ subroutine hwritej(itno,jbuf,offset,length,iostat)
858
+ subroutine hwritei(itno,ibuf,offset,length,iostat)
859
+ subroutine hwriter(itno,rbuf,offset,length,iostat)
860
+ subroutine hwrited(itno,dbuf,offset,length,iostat)
861
+ integer itno,offset,length,iostat
862
+ character abuf*(*),bbuf*(length)
863
+ integer jbuf(*),ibuf(*)
864
+ real rbuf(*)
865
+ double precision dbuf(*)
866
+
867
+ These routines read and write items of a Miriad data set. They
868
+ differ in the sort of element that they read or write.
869
+ hreada,hwritea I/O on ascii text data (terminated by newline char).
870
+ hreadb,hwriteb I/O on ascii data.
871
+ hreadj,hwritej I/O on data stored externally as 16 bit integers.
872
+ hreadi,hwritei I/O on data stored externally as 32 bit integers.
873
+ hreadr,hwriter I/O on data stored externally as IEEE 32 bit reals.
874
+ hreadd,hwrited I/O on data stored externally as IEEE 64 bit reals.
875
+
876
+ Note that hreada and hreadb differ in that:
877
+ * hreada reads sequentially, terminating a read on a newline character.
878
+ The output buffer is blank padded.
879
+ * hreadb performs random reads. Newline characters have no special
880
+ meaning to it. A fixed number of bytes are read, and the buffer is
881
+ not blank padded.
882
+ Hwritea and hwriteb differ in similar ways.
883
+
884
+ Inputs:
885
+ itno The handle of the item to perform I/O on.
886
+ offset The byte offset into the item, where I/O is to be
887
+ performed.
888
+ length The number of bytes to be read.
889
+
890
+ "Offset" and "length" are offsets and lengths into the external file, always
891
+ given in bytes.
892
+
893
+ Note that "offset" and "length" must obey an alignment requirement. Both
894
+ must be a multiple of the size of the element they are performing I/O on.
895
+ For example, they must be a multiple of 2 for hreadj,hwritej; a multiple
896
+ of 4 for hreadi,hwritei,hreadr,hwriter; a multiple of 8 for hreadd,hwrited.
897
+
898
+ Inputs(hwrite) or Outputs(hread):
899
+ abuf,bbuf,jbuf,ibuf,rbuf,dbuf The buffer containing, or to receive,
900
+ the data.
901
+ Outputs:
902
+ iostat I/O status indicator. 0 indicates success. -1 indicates
903
+ end-of-file. Other values are standard system
904
+ error numbers. */
905
+ /*-- */
906
+ /*----------------------------------------------------------------------*/
907
+ /*
908
+ This performs either a read or write operation. It is somewhat involved,
909
+ as it has to handle buffering. Possibly either one or two buffers are
910
+ used (system dependent). Read-ahead, write-behind are attempted for
911
+ systems which can perform this.
912
+
913
+ This is intended to work in both a VMS and UNIX environment, which makes
914
+ it quite involved (because of VMS).
915
+
916
+ Because of caching of small items, buffers are not allocated until the
917
+ last moment. */
918
+
919
+ /* Define a macro to determine if a offset maps into a buffer. */
920
+
921
+ #define WITHIN_BUF(b) ( (item->io[b].length > 0) && \
922
+ (offset >= item->io[b].offset) && \
923
+ (offset < item->io[b].offset + \
924
+ (dowrite ? item->bsize : item->io[b].length)))
925
+
926
+ {
927
+ char *s;
928
+ int b; /* 0 or 1, pointing in one of two IOB buffers */
929
+ off_t next, off;
930
+ size_t size, len;
931
+ IOB *iob1,*iob2;
932
+ ITEM *item;
933
+
934
+ item = hget_item(ihandle);
935
+ size = align_size[type];
936
+
937
+ /* Check various end-of-file conditions and for adequate buffers. */
938
+
939
+ next = offset + (off_t) (!dowrite && type == H_TXT ? 1 : length );
940
+ /* if(!dowrite && type == H_TXT) length = min(length, item->size - offset); */
941
+ *iostat = -1;
942
+ if(!dowrite && next > item->size)return;
943
+ *iostat = 0;
944
+ if(item->bsize < BUFSIZE && item->bsize < next)hcheckbuf_c(item,next,iostat);
945
+ if(*iostat)return;
946
+
947
+ /*----------------------------------------------------------------------*/
948
+ /* */
949
+ /* Loop until we have processed all the data required. */
950
+ /* First determine which of the (possibly) two i/o buffers */
951
+ /* to use. If we have only one buffer, we have no choice. If our */
952
+ /* data is within the last used buffer, use that. Otherwise use */
953
+ /* the least recent used buffer. */
954
+ /* */
955
+ /*----------------------------------------------------------------------*/
956
+
957
+ while(length > 0){
958
+
959
+ b = item->last;
960
+ if(item->io[1].buf == NULL) b = 0;
961
+ else if(WITHIN_BUF(b)){
962
+ if(WITHIN_BUF(1-b)) b = ( item->io[0].offset > item->io[1].offset ? 0 : 1);
963
+ } else b = 1 - b;
964
+ iob1 = &(item->io[b]);
965
+ iob2 = &(item->io[1-b]);
966
+
967
+ /*----------------------------------------------------------------------*/
968
+ /* */
969
+ /* Handle the case of a miss. Flush the i/o buffer if it has been */
970
+ /* modified and read in any needed new data. */
971
+ /* */
972
+ /*----------------------------------------------------------------------*/
973
+
974
+ if(!WITHIN_BUF(b)){
975
+ if(iob1->state == IO_MODIFIED){
976
+ next = iob1->offset + iob1->length;
977
+ if(iob1->length%BUFALIGN && next < item->size)
978
+ {hwrite_fill_c(item,iob1,next,iostat); if(*iostat) return;}
979
+ WAIT(item,iostat); if(*iostat) return;
980
+ dwrite_c(item->fd,iob1->buf,iob1->offset,iob1->length,iostat);
981
+ iob1->state = IO_ACTIVE; if(*iostat) return;
982
+ }
983
+ iob1->offset = (offset/BUFALIGN) * BUFALIGN;
984
+ iob1->length = 0;
985
+ if(!dowrite){
986
+ WAIT(item,iostat); if(*iostat) return;
987
+ iob1->length = min(item->bsize,item->size-iob1->offset);
988
+ if(iob2->buf != NULL && iob1->offset < iob2->offset)
989
+ iob1->length = min(iob1->length, iob2->offset - iob1->offset);
990
+ dread_c(item->fd,iob1->buf,iob1->offset,iob1->length,iostat);
991
+ iob1->state = IO_ACTIVE; if(*iostat) return;
992
+ }
993
+ }
994
+
995
+ /*----------------------------------------------------------------------*/
996
+ /* */
997
+ /* Wait for any i/o and perform a read ahead or write-behind, */
998
+ /* so that we are ready next time. Do this before we copy the */
999
+ /* data to/from the callers buffer, so that we can overlap */
1000
+ /* the copy and i/o operations. The next section is skipped if */
1001
+ /* the underlying i/o is synchronous. */
1002
+ /* */
1003
+ /*----------------------------------------------------------------------*/
1004
+
1005
+ #if BUFDBUFF
1006
+ if(iob1->state == IO_ACTIVE)
1007
+ {WAIT(item,iostat); if(*iostat)return;}
1008
+
1009
+ if(iob2->buf != NULL && iob2->state != IO_ACTIVE){
1010
+ next = iob1->offset + iob1->length;
1011
+
1012
+ /* Write behind. */
1013
+ if(iob2->state == IO_MODIFIED && (!(iob2->length%BUFALIGN) ||
1014
+ iob2->offset + iob2->length == item->size)){
1015
+ dwrite_c(item->fd,iob2->buf,iob2->offset,iob2->length,iostat);
1016
+ iob2->state = IO_ACTIVE;
1017
+
1018
+ /* Read ahead. */
1019
+ } else if(!dowrite && next < item->size && next != iob2->offset){
1020
+ iob2->offset = next;
1021
+ iob2->length = min( BUFSIZE, item->size - iob2->offset );
1022
+ dread_c (item->fd,iob2->buf,iob2->offset,iob2->length,iostat);
1023
+ iob2->state = IO_ACTIVE;
1024
+ }
1025
+ }
1026
+ #endif
1027
+
1028
+ /*----------------------------------------------------------------------*/
1029
+ /* */
1030
+ /* If its a write operation, possibly update the file size, and */
1031
+ /* handle possible non-aligned non-sequential write operations. */
1032
+ /* */
1033
+ /*----------------------------------------------------------------------*/
1034
+
1035
+ if(dowrite){
1036
+ if(iob1->offset + iob1->length < offset &&
1037
+ iob1->offset + iob1->length < item->size)
1038
+ {hwrite_fill_c(item,iob1,offset,iostat); if(*iostat) return;}
1039
+ iob1->state = IO_MODIFIED;
1040
+ iob1->length = max(iob1->length,
1041
+ min(length + offset - iob1->offset, item->bsize));
1042
+ item->size = max(item->size,iob1->offset + iob1->length);
1043
+ }
1044
+
1045
+ /*----------------------------------------------------------------------*/
1046
+ /* */
1047
+ /* Copy between the i/o buffer and users buffer. */
1048
+ /* */
1049
+ /*----------------------------------------------------------------------*/
1050
+
1051
+ off = offset - iob1->offset;
1052
+ len = min(length, iob1->length - off);
1053
+ s = ( ( off % size ) ? align_buf : iob1->buf + off );
1054
+ if(dowrite){
1055
+ switch(type){
1056
+ case H_BYTE: Memcpy(s,buf,len);
1057
+ break;
1058
+ case H_INT: pack32_c((int *)buf, s,len/H_INT_SIZE);
1059
+ break;
1060
+ case H_INT2: pack16_c((int2 *)buf,s,len/H_INT2_SIZE);
1061
+ break;
1062
+ case H_INT8: pack64_c((int8 *)buf,s,len/H_INT8_SIZE);
1063
+ break;
1064
+ case H_REAL: packr_c((float *)buf,s,len/H_REAL_SIZE);
1065
+ break;
1066
+ case H_DBLE: packd_c((double *)buf,s,len/H_DBLE_SIZE);
1067
+ break;
1068
+ case H_CMPLX: packr_c((float *)buf,s,(2*len)/H_CMPLX_SIZE);
1069
+ break;
1070
+ case H_TXT: Memcpy(s,buf,len);
1071
+ if(*(buf+len-1) == 0)*(iob1->buf+off+len-1) = '\n';
1072
+ break;
1073
+ default: bugv_c('f',"hio_c: Unrecognised write type %d",type);
1074
+ }
1075
+ if(off % size) Memcpy(iob1->buf+off,align_buf,len);
1076
+ } else {
1077
+
1078
+ /* If the data are not aligned, copy to an alignment buffer for processing. */
1079
+
1080
+ if(off % size) Memcpy(align_buf,iob1->buf+off,len);
1081
+ switch(type){
1082
+ case H_BYTE: Memcpy(buf,s,len);
1083
+ break;
1084
+ case H_INT: unpack32_c(s,(int *)buf,len/H_INT_SIZE);
1085
+ break;
1086
+ case H_INT2: unpack16_c(s,(int2 *)buf,len/H_INT2_SIZE);
1087
+ break;
1088
+ case H_INT8: unpack64_c(s,(int8 *)buf,len/H_INT8_SIZE);
1089
+ break;
1090
+ case H_REAL: unpackr_c(s,(float *)buf,len/H_REAL_SIZE);
1091
+ break;
1092
+ case H_DBLE: unpackd_c(s,(double *)buf,len/H_DBLE_SIZE);
1093
+ break;
1094
+ case H_CMPLX: unpackr_c(s,(float *)buf,(2*len)/H_CMPLX_SIZE);
1095
+ break;
1096
+ case H_TXT: len = hfind_nl(s,len);
1097
+ Memcpy(buf,s,len);
1098
+ if(*(s+len-1) == '\n'){
1099
+ length = len;
1100
+ *(buf+len-1) = 0;
1101
+ }else if(offset+len == item->size && len < length){
1102
+ length = ++len;
1103
+ *(buf+len-1) = 0;
1104
+ }
1105
+ break;
1106
+ default: bugv_c('f',"hio_c: Unrecognised read type %d",type);
1107
+ }
1108
+ }
1109
+ buf += expansion[type] * len;
1110
+ length -= len;
1111
+ offset += len;
1112
+ item->offset = offset;
1113
+ item->last = b;
1114
+ }
1115
+ }
1116
+ /************************************************************************/
1117
+ private int hfind_nl(char *buf,int len)
1118
+ /*
1119
+ Return the character number of the first new-line character.
1120
+ ------------------------------------------------------------------------*/
1121
+ {
1122
+ int i;
1123
+ for(i=1;i <= len; i++)if(*buf++ == '\n')return(i);
1124
+ return(len);
1125
+ }
1126
+ /************************************************************************/
1127
+ private void hcheckbuf_c(ITEM *item,off_t next,int *iostat)
1128
+ /*
1129
+ Check to determine that we have adequate buffer space, and a file,
1130
+ if needed.
1131
+ ------------------------------------------------------------------------*/
1132
+ {
1133
+ char *s,path[MAXPATH];
1134
+ TREE *t;
1135
+
1136
+ *iostat = 0;
1137
+ /* Allocate a small buffer if needed. */
1138
+
1139
+ if(item->bsize < next && next <= CACHESIZE){
1140
+ s = Malloc(CACHESIZE);
1141
+ item->bsize = CACHESIZE;
1142
+ if(item->io[0].length > 0)Memcpy(s,item->io[0].buf,item->io[0].length);
1143
+ if(item->io[0].buf != NULL) free(item->io[0].buf);
1144
+ item->io[0].buf = s;
1145
+
1146
+ /* Allocate full sized buffers if needed. */
1147
+
1148
+ } else if(item->bsize <= CACHESIZE && next > CACHESIZE){
1149
+ s = Malloc(BUFSIZE);
1150
+ item->bsize = BUFSIZE;
1151
+ if(item->io[0].length > 0)Memcpy(s,item->io[0].buf,item->io[0].length);
1152
+ if(item->io[0].buf != NULL) free(item->io[0].buf);
1153
+ item->io[0].buf = s;
1154
+ if(BUFDBUFF)item->io[1].buf = Malloc(BUFSIZE);
1155
+ }
1156
+
1157
+ /* Open a file if needed. */
1158
+
1159
+ if(item->fd == 0 && item->bsize > CACHESIZE && !(item->flags & ITEM_NOCACHE)){
1160
+ t = item->tree;
1161
+ if(item->flags & ITEM_CACHE) t->flags |= TREE_CACHEMOD;
1162
+ item->flags &= ~ITEM_CACHE;
1163
+ Strcpy(path,t->name);
1164
+ Strcat(path,item->name);
1165
+ dopen_c(&(item->fd),path,"write",&(item->size),iostat);
1166
+ if(*iostat == 0) t->rdwr = RDWR_RDWR;
1167
+ else t->rdwr = RDWR_RDONLY;
1168
+ t->wriostat = *iostat;
1169
+ }
1170
+ }
1171
+ /************************************************************************/
1172
+ private void hwrite_fill_c(ITEM *item,IOB *iob,int next,int *iostat)
1173
+ /*
1174
+ A nonaligned nonsequential write operation has been requested. Read in the
1175
+ portion that we are missing. We need to fill the i/o buffer up to at
1176
+ least offset - 1.
1177
+
1178
+ Inputs:
1179
+ item Descriptor of the thingo we are reading in.
1180
+ iob Structure of the i/o buffer.
1181
+ next Fill up to at least byte (next-1).
1182
+
1183
+ Output:
1184
+ iostat I/O status.
1185
+ ------------------------------------------------------------------------*/
1186
+ {
1187
+ char buffer[BUFSIZE];
1188
+ int offset,length;
1189
+
1190
+ offset = BUFALIGN * ((iob->offset + iob->length) / BUFALIGN);
1191
+ length = BUFALIGN * ((next-1)/BUFALIGN + 1) - offset;
1192
+ length = min(length, item->size - offset);
1193
+
1194
+ WAIT(item,iostat); if(*iostat)return;
1195
+ dread_c(item->fd,buffer,offset,length,iostat); if(*iostat)return;
1196
+ dwait_c(item->fd,iostat); if(*iostat)return;
1197
+ offset = iob->offset + iob->length - offset;
1198
+ length -= offset;
1199
+ Memcpy(iob->buf+iob->length,buffer+offset,length);
1200
+ iob->length += length;
1201
+ }
1202
+ /************************************************************************/
1203
+ void hseek_c(int ihandle,off_t offset)
1204
+ /**hseek -- Set default offset (in bytes) of an item. */
1205
+ /*&pjt */
1206
+ /*:low-level-i/o */
1207
+ /*+ FORTRAN call sequence
1208
+
1209
+ integer function hseek(itno,offset)
1210
+ integer itno,offset
1211
+
1212
+ This sets the default access point of an item. This Can be used to
1213
+ reposition an item when reading/writing using hreada/hwritea.
1214
+
1215
+ Input:
1216
+ itno The handle of the item of interest.
1217
+ offset The new offset. */
1218
+ /*-- */
1219
+ /*----------------------------------------------------------------------*/
1220
+ {
1221
+ ITEM *item;
1222
+
1223
+ item = hget_item(ihandle);
1224
+ item->offset = offset;
1225
+ }
1226
+ /************************************************************************/
1227
+ off_t htell_c(int ihandle)
1228
+ /**htell -- Return the default offset (in bytes) of an item. */
1229
+ /*&pjt */
1230
+ /*:low-level-i/o */
1231
+ /*+ FORTRAN call sequence
1232
+
1233
+ integer function htell(itno)
1234
+ integer itno
1235
+
1236
+ This returns the current default offset of an item, which is used
1237
+ when reading/writing using hreada/hwritea.
1238
+
1239
+ Input:
1240
+ itno The handle of the item of interest. */
1241
+ /*-- */
1242
+ /*----------------------------------------------------------------------*/
1243
+ {
1244
+ ITEM *item;
1245
+
1246
+ item = hget_item(ihandle);
1247
+ return(item->offset);
1248
+ }
1249
+ /************************************************************************/
1250
+ void hreada_c(int ihandle,char *line,size_t length,int *iostat)
1251
+ /*----------------------------------------------------------------------*/
1252
+ {
1253
+ ITEM *item;
1254
+
1255
+ item = hget_item(ihandle);
1256
+ hio_c( ihandle, FALSE, H_TXT, line, item->offset, length, iostat);
1257
+ }
1258
+ /************************************************************************/
1259
+ void hwritea_c(int ihandle,Const char *line,size_t length,int *iostat)
1260
+ /*----------------------------------------------------------------------*/
1261
+ {
1262
+ ITEM *item;
1263
+
1264
+ item = hget_item(ihandle);
1265
+ hio_c( ihandle ,TRUE, H_TXT, (char *)line, item->offset, length, iostat);
1266
+ }
1267
+ /************************************************************************/
1268
+ private void hcache_create_c(TREE *t,int *iostat)
1269
+ /*
1270
+ Create a cache.
1271
+ ------------------------------------------------------------------------*/
1272
+ {
1273
+ int ihandle;
1274
+ header_ok = TRUE;
1275
+ haccess_c(t->handle,&ihandle,"header","write",iostat);
1276
+ header_ok = FALSE;
1277
+ if(!*iostat) hdaccess_c(ihandle,iostat);
1278
+ }
1279
+ /************************************************************************/
1280
+ private void hcache_read_c(TREE *t,int *iostat)
1281
+ /*
1282
+ Read in all small items, which are stored in the file "header".
1283
+ Errors should never happen when reading the cache. If they do,
1284
+ abort completely.
1285
+ ------------------------------------------------------------------------*/
1286
+ {
1287
+ int offset;
1288
+ ITEM *item;
1289
+ char s[CACHE_ENT];
1290
+ int ihandle;
1291
+
1292
+ header_ok = TRUE;
1293
+ haccess_c(t->handle,&ihandle,"header","read",iostat);
1294
+ header_ok = FALSE; if(*iostat)return;
1295
+
1296
+ offset = 0;
1297
+ while(hreadb_c(ihandle,s,offset,CACHE_ENT,iostat),!*iostat){
1298
+ offset += CACHE_ENT;
1299
+ item = hcreate_item_c(t,s);
1300
+ item->size = *(s+CACHE_ENT-1);
1301
+ item->bsize = item->size;
1302
+ item->flags = ITEM_CACHE;
1303
+ item->io[0].offset = 0;
1304
+ item->io[0].length = item->size;
1305
+ item->io[0].state = IO_VALID;
1306
+ item->io[0].buf = Malloc(item->size);
1307
+ hreadb_c(ihandle,item->io[0].buf,offset,item->size,iostat); check(*iostat);
1308
+ offset += mroundup(item->size,CACHE_ENT);
1309
+ }
1310
+ if(*iostat != -1) bug_c('f',"hcache_read_c: Something wrong reading cache");
1311
+ hdaccess_c(ihandle,iostat);
1312
+ }
1313
+ /************************************************************************/
1314
+ private int hname_check(char *name)
1315
+ /*
1316
+ This checks if the name of an item is OK. Generally an item must be 1 to
1317
+ 8 characters, alphanumeric, starting with an alpha. Only lower case
1318
+ alpha is allowed. The name "header" is generally reserved.
1319
+ ------------------------------------------------------------------------*/
1320
+ {
1321
+ int length,i;
1322
+ char c;
1323
+
1324
+ length = strlen(name);
1325
+ if(length <= 0 || length >= MAXNAME) return(-1);
1326
+ if(length == 1 && *name == '.')return(0);
1327
+ if(*name < 'a' || *name > 'z')return(-1);
1328
+ if(!header_ok && length == 6 && !strcmp("header",name))return(-1);
1329
+ for(i=0; i < length; i++){
1330
+ c = *name++;
1331
+ if((c < 'a' || c > 'z') && (c < '0' || c > '9') && (c != '-') && (c != '_'))
1332
+ return(-1);
1333
+ }
1334
+ return 0 ;
1335
+ }
1336
+ /************************************************************************/
1337
+ private void hdir_c(ITEM *item)
1338
+ /*
1339
+ Read the directory contents into a buffer (make it look like a text
1340
+ file.
1341
+ ------------------------------------------------------------------------*/
1342
+ {
1343
+ int length,plength,len;
1344
+ char *context,*s;
1345
+ ITEM *it;
1346
+ TREE *t;
1347
+
1348
+ #define MINLENGTH 128
1349
+
1350
+ /* Mark this item as not cachable. */
1351
+
1352
+ item->flags |= ITEM_NOCACHE | ITEM_SCRATCH;
1353
+
1354
+ /* Get a buffer size which is guaranteed to hold all the items that come
1355
+ from the "header" file. */
1356
+
1357
+ plength = 0;
1358
+ t = item->tree;
1359
+ for(it = t->itemlist; it != NULL; it = it->fwd)
1360
+ plength += strlen(it->name) + 1;
1361
+ plength = max(plength,2*MINLENGTH);
1362
+ s = Malloc(plength);
1363
+
1364
+ /* Copy the names of all the "header" items to this buffer. Exclude the "."
1365
+ itself. */
1366
+
1367
+ length = 0;
1368
+ for(it=t->itemlist; it != NULL; it = it->fwd){
1369
+ if(it->fd == 0 && !(it->flags & ITEM_NOCACHE)){
1370
+ Strcpy(s+length,it->name);
1371
+ length += strlen(it->name);
1372
+ *(s+length++) = '\n';
1373
+ }
1374
+ }
1375
+
1376
+ /* Now read through the directory to get all external files. Skip the
1377
+ "header" file. The size of the buffer is doubled as we go, when it
1378
+ gets too small. */
1379
+
1380
+ dopendir_c(&context,t->name);
1381
+ do{
1382
+ if(plength - length < MINLENGTH){
1383
+ plength *= 2;
1384
+ s = Realloc(s, plength);
1385
+ }
1386
+ dreaddir_c(context,s+length,plength-length);
1387
+ len = strlen(s+length);
1388
+ if(len > 0 && strcmp(s+length,"header")){
1389
+ length += len;
1390
+ *(s+length++) = '\n';
1391
+ }
1392
+ }while(len > 0);
1393
+ dclosedir_c(context);
1394
+
1395
+ /* Finish initialising the item now. */
1396
+
1397
+ item->size = length;
1398
+ item->io[0].buf = s;
1399
+ item->io[0].offset = 0;
1400
+ item->io[0].length = length;
1401
+ item->bsize = plength;
1402
+ }
1403
+ /************************************************************************/
1404
+ private void hrelease_item_c(ITEM *item)
1405
+ /*
1406
+ Release the item on the top of the list.
1407
+ ------------------------------------------------------------------------*/
1408
+ {
1409
+ ITEM *it1,*it2;
1410
+ TREE *t;
1411
+
1412
+ /* Find the item. Less than attractive code. */
1413
+
1414
+ t = item->tree;
1415
+ it2 = t->itemlist;
1416
+ if(item != it2){
1417
+ do{
1418
+ it1 = it2;
1419
+ it2 = it1->fwd;
1420
+ }while(item != it2);
1421
+
1422
+ it1->fwd = it2->fwd;
1423
+ } else t->itemlist = item->fwd;
1424
+
1425
+ /* Release any memory associated with the item. */
1426
+
1427
+ if(item->io[0].buf != NULL) free(item->io[0].buf);
1428
+ if(item->io[1].buf != NULL) free(item->io[1].buf);
1429
+
1430
+ item_addr[item->handle] = NULL;
1431
+ free(item->name);
1432
+ free((char *)item);
1433
+ nitem--;
1434
+ }
1435
+ /************************************************************************/
1436
+ private ITEM *hcreate_item_c(TREE *tree,char *name)
1437
+ /*
1438
+ Create an item, and initialise as much of it as possible.
1439
+ ------------------------------------------------------------------------*/
1440
+ {
1441
+ ITEM *item;
1442
+ int i,hash;
1443
+ char *s;
1444
+
1445
+ /* Hash the name. */
1446
+
1447
+ s = name;
1448
+ hash = nitem++;
1449
+ if(nitem > MAXITEM)
1450
+ bugv_c('f',"Item address table overflow, in hio; nitem=%d MAXITEM=%d",nitem,MAXITEM);
1451
+ while(*s) hash += *s++;
1452
+ hash %= MAXITEM;
1453
+
1454
+ /* Find a slot in the list of addresses, and allocate it. */
1455
+
1456
+ while(hget_item(hash) != NULL) hash = (hash+1) % MAXITEM;
1457
+ item_addr[hash] = (ITEM *)Malloc(sizeof(ITEM));
1458
+
1459
+ /* Initialise it now. */
1460
+
1461
+ item = hget_item(hash);
1462
+ item->name = Malloc(strlen(name) + 1);
1463
+ Strcpy(item->name,name);
1464
+ item->handle = hash;
1465
+ item->size = 0;
1466
+ item->flags = 0;
1467
+ item->fd = 0;
1468
+ item->last = 0;
1469
+ item->offset = 0;
1470
+ item->bsize = 0;
1471
+ item->tree = tree;
1472
+ for(i=0; i<2; i++){
1473
+ item->io[i].offset = 0;
1474
+ item->io[i].length = 0;
1475
+ item->io[i].state = 0;
1476
+ item->io[i].buf = NULL;
1477
+ }
1478
+ item->fwd = tree->itemlist;
1479
+ tree->itemlist = item;
1480
+ return(item);
1481
+ }
1482
+ /************************************************************************/
1483
+ private TREE *hcreate_tree_c(char *name)
1484
+ /*
1485
+ Create an item, and initialise as much of it as possible.
1486
+ ------------------------------------------------------------------------*/
1487
+ {
1488
+ TREE *t;
1489
+ int hash;
1490
+ char *s;
1491
+
1492
+ /* Hash the name. */
1493
+
1494
+ s = name;
1495
+ hash = ntree++;
1496
+ if(ntree > MAXOPEN)
1497
+ bugv_c('f',"Tree address table overflow, in hio, ntree=%d MAXOPEN=%d",ntree,MAXOPEN);
1498
+ while(*s) hash += *s++;
1499
+ hash %= MAXOPEN;
1500
+
1501
+ /* Find a slot in the list of addresses, and allocate it. */
1502
+
1503
+ while(hget_tree(hash) != NULL) hash = (hash+1) % MAXOPEN;
1504
+ tree_addr[hash] = (TREE *)Malloc(sizeof(TREE));
1505
+
1506
+ /* Initialise it. */
1507
+
1508
+ t = hget_tree(hash);
1509
+ t->name = Malloc(strlen(name) + 1);
1510
+ Strcpy(t->name,name);
1511
+ t->handle = hash;
1512
+ t->flags = 0;
1513
+ t->itemlist = NULL;
1514
+ return t;
1515
+ }