1 /**
2 * Copyright 1981-2016 ECMWF.
3 *
4 * This software is licensed under the terms of the Apache Licence
5 * Version 2.0 which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6 *
7 * In applying this licence, ECMWF does not waive the privileges and immunities
8 * granted to it by virtue of its status as an intergovernmental organisation
9 * nor does it submit to any jurisdiction.
10 */
11
12 /*
13 // pbio.c
14 */
15 #include <unistd.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21 #include <ctype.h>
22
23 #ifdef PTHREADS
24 #include <pthread.h>
25 #endif
26
27 #ifdef FOPEN64
28 #define OFF_T off64_t
29 extern FILE *fopen64(const char *, const char *);
30 #else
31 #define OFF_T off_t
32 #endif
33
34 static FILE** fptable = NULL;
35 static int fptableSize = 0;
36
37 #ifdef PTHREADS
38 static pthread_mutex_t fpTableBusy = PTHREAD_MUTEX_INITIALIZER;
39 #endif
40 #define BUFFLEN 4096
41
42 /*
43 // Default buffer size for I/O operations (set via setvbuf)
44 */
45 #define SIZE BUFSIZ
46 static long size = SIZE;
47 static int sizeSet = 0;
48 static char * envSize;
49 static char** fileBuffer = NULL;
50
51 /*
52 // Debug flags.
53 */
54 #define DEBUGOFF 1
55 #define DEBUG (debugSet > DEBUGOFF )
56 static char * debugLevel;
57 static int debugSet = 0;
58
59 #include "bufrgrib.h"
60 #include "fort2c.h"
61 #include "common/fortint.h"
62 #include "fileRead.h"
63
64 #define NAMEBUFFLEN 256
65 #define MODEBUFFLEN 10
66
67 #define CURRENT_FILE (fptable[*unit])
68
pbfp(long index)69 FILE* pbfp(long index) {
70 if( (fptable == NULL) || ((int)index < 0) || ((int)index >= fptableSize) )
71 return (FILE *) NULL;
72 else
73 return fptable[index];
74 }
75
76 /*
77 //------------------------------------------------------------------------
78 // PBOPEN - Open file (from FORTRAN)
79 //------------------------------------------------------------------------
80 */
81 #if defined hpR64 || defined hpiaR64
pbopen_(fortint * unit,_fcd name,_fcd mode,fortint * iret,long l1,long l2)82 void pbopen_(fortint* unit,_fcd name,_fcd mode,fortint* iret,long l1,long l2) {
83 #else
84 void pbopen_(fortint* unit,_fcd name,_fcd mode,fortint* iret,fortint l1,fortint l2) {
85 #endif
86 /*
87 // Purpose:
88 // Opens file, returns the index of a UNIX FILE pointer held in
89 // an internal table (fptable).
90 //
91 // First time through, reads value in environment variable PBIO_BUFSIZE
92 // (if it is set) and uses it as the size to be used for internal file
93 // buffers; the value is passed to setvbuf. If PBIO_BUFSIZE is not set,
94 // a default value is used.
95 //
96 // Function accepts:
97 // name = filename
98 // mode = r, r+, w
99 //
100 // Note: l1 and l2 are the lengths of the FORTRAN character strings
101 // in name and mode.
102 //
103 // Function returns:
104 // INTEGER iret:
105 // -1 = Could not open file.
106 // -2 = Invalid file name.
107 // -3 = Invalid open mode specified
108 // 0 = OK.
109 */
110 int n;
111 char *p;
112 char flags[4];
113
114 #if (!defined CRAY) && (!defined VAX)
115 char namebuff[NAMEBUFFLEN+1], modebuff[MODEBUFFLEN+1];
116 #else
117 char * namebuff, * modebuff;
118 #endif
119
120 /*
121 // See if DEBUG switched on.
122 */
123 if( ! debugSet ) {
124 debugLevel = getenv("PBIO_DEBUG");
125 if( debugLevel == NULL )
126 debugSet = DEBUGOFF; /* off */
127 else {
128 int loop;
129 for( loop = 0; loop < strlen(debugLevel) ; loop++ ) {
130 if( ! isdigit(debugLevel[loop]) ) {
131 printf("Invalid number string in PBIO_DEBUG: %s\n", debugLevel);
132 printf("PBIO_DEBUG must comprise only digits [0-9].\n");
133 debugSet = DEBUGOFF;
134 }
135 }
136 debugSet = DEBUGOFF + atol( debugLevel );
137 }
138 if( DEBUG ) printf("PBIO_PBOPEN: debug switched on\n");
139 }
140
141 #if (!defined CRAY) && (!defined VAX)
142 /*
143 // Put the character strings into buffers and ensure that there is a
144 // null terminator (for SGI case when FORTRAN CHARACTER variable is full
145 // right to end with characters
146 */
147 {
148 int n1, n2;
149
150 n1 = (l1>NAMEBUFFLEN) ? NAMEBUFFLEN : l1;
151 n2 = (l2>MODEBUFFLEN) ? MODEBUFFLEN : l2;
152
153 strncpy( namebuff, name, n1);
154 strncpy( modebuff, mode, n2);
155 namebuff[n1] = '\0';
156 modebuff[n2] = '\0';
157 }
158 #else
159 if(!(namebuff = fcd2char(name))) {
160 *iret = -2;
161 return;
162 }
163 if(!(modebuff = fcd2char(mode))) {
164 free(namebuff);
165 *iret = -2;
166 return;
167 }
168 #endif
169
170 strcpy(flags,"");
171
172 /* *unit = (fortint) NULL; sami bug fix */
173 *unit = 0;
174 *iret = 0;
175
176 /*
177 // Strip trailing blanks
178 */
179 p = namebuff + strlen(namebuff) - 1 ;
180 while(*p == ' ') {
181 *p = 0;
182 p--;
183 }
184 if( DEBUG ) printf("PBIO_PBOPEN: filename = %s\n", namebuff);
185 /*
186 // Build open flags from "modes"
187 */
188 p = modebuff;
189
190 switch(*p) {
191
192 case 'a':
193 case 'A': strcat(flags, "a");
194 break;
195
196 case 'c':
197 case 'C':
198 case 'w':
199 case 'W': strcat(flags, "w");
200 break;
201
202 case 'r':
203 case 'R':
204 if( *(p+1) == '+' )
205 strcat(flags, "r+");
206 else
207 strcat(flags, "r");
208 break;
209
210 default: *iret = -3;
211 return;
212
213 }
214 if( DEBUG ) printf("PBIO_PBOPEN: file open mode = %s\n", flags);
215
216 /*
217 // Look for a free slot in fptable.
218 // (Create the table the first time through).
219 */
220 #ifdef PTHREADS
221 /*
222 // Wait if another thread opening a file
223 */
224 pthread_mutex_lock(&fpTableBusy);
225 #endif
226
227 n = 0;
228 if( fptableSize == 0 ) {
229 int i;
230 fptableSize = 2;
231 fptable = (FILE **) malloc(fptableSize*sizeof(FILE *));
232 if( fptable == NULL ) {
233 perror("Unable to allocate space for table of FILE pointers");
234 exit(1);
235 }
236
237 fileBuffer = (char **) malloc(fptableSize*sizeof(char *));
238 if( fileBuffer == NULL ) {
239 perror("Unable to allocate space for FILE buffers");
240 exit(1);
241 }
242
243 for( i = 0; i < fptableSize; i++ ) {
244 fptable[i] = 0;
245 fileBuffer[i] = NULL;
246 }
247 }
248 else {
249 while( n < fptableSize ) {
250 if(fptable[n]==0) {
251 *unit = n;
252 break;
253 }
254 n++;
255 }
256 }
257 /*
258 // If the table overflows, double its size.
259 */
260 if( n == fptableSize) {
261 int i;
262 fptableSize = 2*fptableSize;
263 fptable = (FILE **) realloc(fptable, fptableSize*sizeof(FILE *));
264 if( fptable == NULL ) {
265 perror("Unable to reallocate space for table of FILE pointers");
266 exit(1);
267 }
268 n = fptableSize/2;
269
270 fileBuffer = (char **) realloc(fileBuffer, fptableSize*sizeof(char *));
271 if( fileBuffer == NULL ) {
272 perror("Unable to allocate space for FILE buffers");
273 exit(1);
274 }
275
276 n = fptableSize/2;
277 for( i = n; i < fptableSize; i++ ) {
278 fptable[i] = 0;
279 fileBuffer[i] = NULL;
280 }
281
282 *unit = n;
283 }
284
285 if( DEBUG ) printf("PBIO_PBOPEN: fptable slot = %d\n", *unit);
286
287 #ifdef FOPEN64
288 if( DEBUG ) printf("PBIO_PBOPEN: using fopen64\n");
289 fptable[n] = fopen64(namebuff, flags );
290 #else
291 if( DEBUG ) printf("PBIO_PBOPEN: using fopen\n");
292 fptable[n] = fopen(namebuff, flags );
293 #endif
294
295 if(fptable[n] == NULL) {
296 perror(namebuff);
297 *iret = -1;
298 #if (defined CRAY) || (defined VAX)
299 free(namebuff);
300 free(modebuff);
301 #endif
302 #ifdef PTHREADS
303 pthread_mutex_unlock(&fpTableBusy);
304 #endif
305 return;
306 }
307
308 /*
309 // Now allocate a buffer for the file, if necessary.
310 */
311 if( ! sizeSet ) {
312 envSize = getenv("PBIO_BUFSIZE");
313 if( envSize == NULL )
314 size = SIZE; /* default */
315 else {
316 int loop;
317 for( loop = 0; loop < strlen(envSize) ; loop++ ) {
318 if( ! isdigit(envSize[loop]) ) {
319 printf("Invalid number string in PBIO_BUFSIZE: %s\n", envSize);
320 printf("PBIO_BUFSIZE must comprise only digits [0-9].\n");
321 exit(1);
322 }
323 }
324 size = atol( envSize );
325 }
326 if( size <= 0 ) {
327 printf("Invalid buffer size in PBIO_BUFSIZE: %s\n", envSize);
328 printf("Buffer size defined by PBIO_BUFSIZE must be positive.\n");
329 exit(1);
330 }
331 sizeSet = 1;
332 }
333
334 if( DEBUG ) printf("PBIO_PBOPEN: file buffer size = %d\n", size);
335
336 if( fileBuffer[n] == NULL ) {
337 fileBuffer[n] = (char *) malloc(size);
338 }
339
340 if( setvbuf(CURRENT_FILE, fileBuffer[*unit], _IOFBF, size) ) {
341 perror("setvbuf failed");
342 *iret = -1;
343 }
344
345 #ifdef PTHREADS
346 pthread_mutex_unlock(&fpTableBusy);
347 #endif
348
349 #if (defined CRAY) || (defined VAX)
350 free(namebuff);
351 free(modebuff);
352 #endif
353
354 }
355
356 #if (defined hpR64) || (defined hpiaR64)
357 void pbopen(fortint* unit,_fcd name,_fcd mode,fortint* iret,long l1,long l2) {
358 #else
359 void pbopen(fortint* unit,_fcd name,_fcd mode,fortint* iret,fortint l1,fortint l2) {
360 #endif
361
362 pbopen_(unit,name,mode,iret,l1,l2);
363 }
364
365 /*
366 //------------------------------------------------------------------------
367 // PBSEEK - Seek (from FORTRAN)
368 //------------------------------------------------------------------------
369 */
370 void pbseek_(fortint* unit,fortint* offset,fortint* whence,fortint* iret) {
371 /*
372 //
373 // Purpose:
374 // Seeks to a specified location in file.
375 //
376 // Function accepts:
377 // unit = the index of a UNIX FILE pointer held in
378 // an internal table (fptable).
379 //
380 // offset = byte count
381 //
382 // whence = 0, from start of file
383 // = 1, from current position
384 // = 2, from end of file.
385 //
386 // Returns:
387 // iret:
388 // -2 = error in handling file,
389 // -1 = end-of-file
390 // otherwise, = byte offset from start of file.
391 */
392 int my_offset = (int) *offset;
393 int my_whence = (int) *whence;
394
395 /*
396 // Must use negative offset if working from end-of-file
397 */
398 if( DEBUG ) {
399 printf("PBIO_PBSEEK: fptable slot = %d\n", *unit);
400 printf("PBIO_PBSEEK: Offset = %d\n", my_offset);
401 printf("PBIO_PBSEEK: Type of offset = %d\n", my_whence);
402 }
403
404 if( my_whence == 2) my_offset = - abs(my_offset);
405
406 *iret = fileTell(CURRENT_FILE);
407 if( DEBUG ) printf("PBIO_PBSEEK: current position = %d\n", *iret);
408 if( *iret == my_offset && my_whence == 0)
409 *iret = 0;
410 else
411 *iret = fileSeek(CURRENT_FILE, my_offset, my_whence);
412
413 if( DEBUG ) printf("PBIO_PBSEEK: fileSeek return code = %d\n",*iret);
414
415 if( *iret != 0 ) {
416 if( ! feof(CURRENT_FILE) ) {
417 *iret = -2; /* error in file-handling */
418 perror("pbseek");
419 }
420 else
421 *iret = -1; /* end-of-file */
422
423 clearerr(CURRENT_FILE);
424 return;
425 }
426
427 /*
428 // Return the byte offset from start of file
429 */
430 *iret = fileTell(CURRENT_FILE);
431
432 if( DEBUG )
433 printf("PBIO_PBSEEK: byte offset from start of file = %d\n",*iret);
434
435 return;
436
437 }
438
439 void pbseek(fortint* unit,fortint* offset,fortint* whence,fortint* iret) {
440
441 pbseek_(unit,offset,whence,iret);
442 }
443
444
445 void pbseek64_(fortint* unit,long long* offset,fortint* whence,long long* iret) {
446 /*
447 //
448 // Purpose:
449 // Seeks to a specified location in file.
450 //
451 // Function accepts:
452 // unit = the index of a UNIX FILE pointer held in
453 // an internal table (fptable).
454 //
455 // offset = byte count
456 //
457 // whence = 0, from start of file
458 // = 1, from current position
459 // = 2, from end of file.
460 //
461 // Returns:
462 // iret:
463 // -2 = error in handling file,
464 // -1 = end-of-file
465 // otherwise, = byte offset from start of file.
466 */
467 long long my_offset = (long long) *offset;
468 int my_whence = (int) *whence;
469
470 /*
471 // Must use negative offset if working from end-of-file
472 */
473 if( DEBUG ) {
474 printf("PBIO_PBSEEK: fptable slot = %d\n", *unit);
475 printf("PBIO_PBSEEK: Offset = %d\n", my_offset);
476 printf("PBIO_PBSEEK: Type of offset = %d\n", my_whence);
477 }
478
479 if( my_whence == 2) my_offset = - abs(my_offset);
480
481 *iret = fileTell(CURRENT_FILE);
482 if( DEBUG ) printf("PBIO_PBSEEK: current position = %d\n", *iret);
483 if( *iret == my_offset && my_whence == 0)
484 *iret = 0;
485 else
486 *iret = fileSeek(CURRENT_FILE, my_offset, my_whence);
487
488 if( DEBUG ) printf("PBIO_PBSEEK: fileSeek return code = %d\n",*iret);
489
490 if( *iret != 0 ) {
491 if( ! feof(CURRENT_FILE) ) {
492 *iret = -2; /* error in file-handling */
493 perror("pbseek");
494 }
495 else
496 *iret = -1; /* end-of-file */
497
498 clearerr(CURRENT_FILE);
499 return;
500 }
501
502 /*
503 // Return the byte offset from start of file
504 */
505 *iret = fileTell(CURRENT_FILE);
506
507 if( DEBUG )
508 printf("PBIO_PBSEEK: byte offset from start of file = %d\n",*iret);
509
510 return;
511
512 }
513
514 void pbseek64(fortint* unit,long long* offset,fortint* whence,long long* iret) {
515
516 pbseek64_(unit,offset,whence,iret);
517 }
518
519 /*
520 //------------------------------------------------------------------------
521 // PBTELL - Tells current file position (from FORTRAN)
522 //------------------------------------------------------------------------
523 */
524 void pbtell_(fortint* unit,fortint* iret) {
525 /*
526 //
527 // Purpose:
528 // Tells current byte offset in file.
529 //
530 // Function accepts:
531 // unit = the index of a UNIX FILE pointer held in
532 // an internal table (fptable).
533 //
534 // Returns:
535 // iret:
536 // -2 = error in handling file,
537 // otherwise, = byte offset from start of file.
538 */
539
540
541 /*
542 // Return the byte offset from start of file
543 */
544 *iret = fileTell(CURRENT_FILE);
545
546 if( *iret < 0 ) {
547 if( DEBUG ) { /* error in file-handling */
548 printf("PBIO_PBTELL: fptable slot = %d. ", *unit);
549 printf("Error status = %d\n", *iret);
550 }
551 perror("pbtell");
552 *iret = -2;
553 }
554
555 if( DEBUG ) {
556 printf("PBIO_PBTELL: fptable slot = %d. ", *unit);
557 printf("Byte offset from start of file = %d\n",*iret);
558 }
559
560 return;
561 }
562
563 void pbtell(fortint* unit,fortint* iret) {
564
565 pbtell_(unit,iret);
566 }
567
568 /*
569 //------------------------------------------------------------------------
570 // PBTELL64 - Tells current file position (from FORTRAN)
571 //------------------------------------------------------------------------
572 */
573 void pbtell64_(fortint* unit,long long* iret) {
574 /*
575 //
576 // Purpose:
577 // Tells current byte offset in file.
578 //
579 // Function accepts:
580 // unit = the index of a UNIX FILE pointer held in
581 // an internal table (fptable).
582 //
583 // Returns:
584 // iret:
585 // -2 = error in handling file,
586 // otherwise, = byte offset from start of file.
587 */
588
589
590 /*
591 // Return the byte offset from start of file
592 */
593 *iret = fileTell(CURRENT_FILE);
594
595 if( *iret < 0 ) {
596 if( DEBUG ) { /* error in file-handling */
597 printf("PBIO_PBTELL64: fptable slot = %d. ", *unit);
598 printf("Error status = %d\n", *iret);
599 }
600 perror("pbtell64");
601 *iret = -2;
602 }
603
604 if( DEBUG ) {
605 printf("PBIO_PBTELL: fptable slot = %d. ", *unit);
606 printf("Byte offset from start of file = %d\n",*iret);
607 }
608
609 return;
610 }
611
612 void pbtell64(fortint* unit,long long* iret) {
613
614 pbtell64_(unit,iret);
615 }
616
617 /*
618 //------------------------------------------------------------------------
619 // PBREAD - Read (from FORTRAN)
620 //------------------------------------------------------------------------
621 */
622 void pbread_(fortint* unit,char* buffer,fortint* nbytes,fortint* iret) {
623 /*
624 // Purpose:
625 // Reads a block of bytes from a file..
626 //
627 // Function accepts:
628 // unit = the index of a UNIX FILE pointer held in
629 // an internal table (fptable).
630 //
631 // nbytes = number of bytes to read.
632 //
633 // Returns:
634 // iret:
635 // -2 = error in reading file,
636 // -1 = end-of-file,
637 // otherwise, = number of bytes read.
638 */
639 if( DEBUG ) {
640 printf("PBIO_READ: fptable slot = %d. ", *unit);
641 printf("Number of bytes to read = %d\n", *nbytes);
642 }
643
644 if( (*iret = fread(buffer, 1, *nbytes, CURRENT_FILE) ) != *nbytes) {
645 if( ! feof(CURRENT_FILE) ) {
646 *iret = -2; /* error in file-handling */
647 perror("pbread");
648 clearerr(CURRENT_FILE);
649 return;
650 }
651 else {
652 *iret = -1; /* end-of-file */
653 clearerr(CURRENT_FILE);
654 }
655 }
656
657 if( DEBUG ) {
658 printf("PBIO_READ: fptable slot = %d. ", *unit);
659 printf("Number of bytes read = %d\n", *nbytes);
660 }
661
662 return;
663 }
664
665 void pbread(fortint* unit,char* buffer,fortint* nbytes,fortint* iret) {
666
667 pbread_(unit,buffer,nbytes,iret);
668 }
669
670 /*
671 //------------------------------------------------------------------------
672 // PBREAD2 - Read (from FORTRAN)
673 //------------------------------------------------------------------------
674 */
675 void pbread2_(fortint* unit,char* buffer,fortint* nbytes,fortint* iret) {
676 /*
677 // Purpose:
678 // Reads a block of bytes from a file..
679 //
680 // Function accepts:
681 // unit = the index of a UNIX FILE pointer held in
682 // an internal table (fptable).
683 //
684 // nbytes = number of bytes to read.
685 //
686 // Returns:
687 // iret:
688 // -2 = error in reading file,
689 // -1 = end-of-file,
690 // otherwise, = number of bytes read.
691 */
692 if( DEBUG ) {
693 printf("PBIO_READ2: fptable slot = %d. ", *unit);
694 printf("Number of bytes to read = %d\n", *nbytes);
695 }
696
697 if( (*iret = fread(buffer, 1, *nbytes, CURRENT_FILE) ) != *nbytes) {
698 if( ! feof(CURRENT_FILE) ) {
699 *iret = -2; /* error in file-handling */
700 perror("pbread2");
701 clearerr(CURRENT_FILE);
702 }
703 }
704
705 if( DEBUG )
706 printf("PBIO_READ2: Number of bytes read = %d\n", *iret);
707
708 return;
709 }
710
711 void pbread2(fortint* unit,char* buffer,fortint* nbytes,fortint* iret) {
712
713 pbread2_(unit,buffer,nbytes,iret);
714 }
715
716 /*
717 //------------------------------------------------------------------------
718 // PBWRITE - Write (from FORTRAN)
719 //------------------------------------------------------------------------
720 */
721 void pbwrite_(fortint* unit,char* buffer,fortint* nbytes,fortint* iret) {
722 /*
723 // Purpose:
724 // Writes a block of bytes to a file.
725 //
726 // Function accepts:
727 // unit = the index of a UNIX FILE pointer held in
728 // an internal table (fptable).
729 //
730 // nbytes = number of bytes to write.
731 //
732 // Returns:
733 // iret:
734 // -1 = Could not write to file.
735 // >=0 = Number of bytes written.
736 */
737 if( DEBUG ) {
738 printf("PBIO_WRITE: fptable slot = %d. ", *unit);
739 printf("Number of bytes to write = %d\n", *nbytes);
740 }
741
742 if( (*iret = fwrite(buffer, 1, *nbytes, CURRENT_FILE) ) != *nbytes) {
743 perror("pbwrite");
744 *iret = -1;
745 }
746
747 if( DEBUG ) {
748 printf("PBIO_WRITE: fptable slot = %d. ", *unit);
749 printf("PBIO_WRITE: number of bytes written = %d\n", *iret);
750 }
751
752 return;
753 }
754
755 void pbwrite(fortint* unit,char* buffer,fortint* nbytes,fortint* iret) {
756
757 pbwrite_(unit,buffer,nbytes,iret);
758 }
759
760 /*
761 //------------------------------------------------------------------------
762 // PBCLOSE - close (from FORTRAN)
763 //------------------------------------------------------------------------
764 */
765 void pbclose_(fortint* unit,fortint* iret) {
766 /*
767 // Purpose:
768 // Closes file.
769 //
770 // Function accepts:
771 // unit = the index of a UNIX FILE pointer held in
772 // an internal table (fptable).
773 //// Returns:
774 // iret:
775 // 0 = OK.
776 // otherwise = error in handling file.
777 */
778 if( DEBUG )
779 printf("PBIO_CLOSE: fptable slot = %d\n", *unit);
780
781 if( ( *iret = fclose(CURRENT_FILE) ) != 0 ) perror("pbclose");
782 CURRENT_FILE = 0;
783
784 return;
785 }
786
787 void pbclose(fortint* unit,fortint* iret) {
788
789 pbclose_(unit,iret);
790 }
791
792 /*
793 //------------------------------------------------------------------------
794 // PBFLUSH - flush (from FORTRAN)
795 //------------------------------------------------------------------------
796 */
797 void pbflush_(fortint * unit) {
798 /*
799 // Purpose: Flushes file.
800 */
801 if( DEBUG )
802 printf("PBIO_FLUSH: fptable slot = %d\n", *unit);
803
804 fflush(CURRENT_FILE);
805 }
806
807 void pbflush(fortint * unit) {
808
809 pbflush_(unit);
810 }
811
812 /*
813 //------------------------------------------------------------------------
814 // PBREAD3 - read (from FORTRAN)
815 //------------------------------------------------------------------------
816 */
817 void pbread3_(fortint* unit,char* buffer,fortint* nbytes,fortint* iret) {
818 /*
819 // Purpose:
820 // Reads a block of bytes from a file..
821 //
822 // Function returns:
823 // status : -2 = error in reading file,
824 // -1 = end-of-file,
825 // otherwise, = number of bytes read.
826 */
827 if( DEBUG )
828 printf("PBIO_READ3: number of bytes to read = %d\n", *nbytes);
829
830 *iret = read(*unit, buffer, *nbytes);
831
832 if( DEBUG )
833 printf("PBIO_READ3: number of bytes read = %d\n", *iret);
834 /*
835 // Error in file-handling
836 */
837 if(*iret == -1) {
838 *iret = -2;
839 perror("pbread3");
840 return;
841 }
842 /*
843 // Read problem
844 */
845 else if(*iret != *nbytes) {
846 printf("EOF; pbread3; bytes requested %d; read in: %d\n",
847 *nbytes,*iret);
848 *iret = -1;
849 return;
850 }
851
852 }
853
854 void pbread3(fortint* unit,char* buffer,fortint* nbytes,fortint* iret) {
855
856 pbread3_(unit,buffer,nbytes,iret);
857 }
858
859 void pbread4_(fortint* unit,char* buffer,size_t* nbytes,size_t* iret) {
860 /*
861 // Purpose:
862 // Reads a block of bytes from a file..
863 //
864 // Function returns:
865 // status : -2 = error in reading file,
866 // -1 = end-of-file,
867 // otherwise, = number of bytes read.
868 printf("PBIO_READ4: sizeof = %ld\n", sizeof(buffer));
869 */
870 /* if( DEBUG ) */
871 printf("PBIO_READ4: number of bytes to read = %ld\n", *nbytes);
872
873 /* Is 4MB ok ? */
874 size_t left = *nbytes;
875 size_t len = 0;
876 size_t chunk = 4*1024*1024; /* Is 4MB ok ? */
877 size_t pos = 0;
878
879 while((left > 0) && (len = read(*unit,(buffer+pos),chunk)) > 0)
880 {
881 left -= len;
882 pos += len;
883 if(left < chunk)
884 chunk = left;
885 }
886 if(len>0)
887 *iret = pos;
888 else
889 *iret = len;
890
891 if( DEBUG )
892 printf("PBIO_READ4: number of bytes READ = %ld\n", pos);
893
894 if(*iret == -1) {
895 *iret = -2;
896 perror("pbread4");
897 return;
898 }
899 /*
900 // Read problem
901 */
902 else if(pos != *nbytes) {
903 printf("EOF; pbread4; bytes requested %ld; read in: %ld\n",
904 *nbytes,pos);
905 *iret = -1;
906 return;
907 }
908 printf("PBIO_READ4: number of bytes read = %ld\n", pos);
909 printf("PBIO_READ4: return code *iret = %ld\n", *iret);
910
911 }
912
913 void pbread4(fortint* unit,char* buffer,size_t* nbytes,size_t* iret) {
914
915 pbread4_(unit,buffer,nbytes,iret);
916 }
917 void pbread5_(fortint* unit,char* buffer,size_t* nbytes,size_t* iret) {
918 /*
919 // Purpose:
920 // Reads a block of bytes from a file..
921 //
922 // Function returns:
923 // status : -2 = error in reading file,
924 // -1 = end-of-file,
925 // otherwise, = number of bytes read.
926 */
927 if( DEBUG )
928 printf("PBIO_READ5: number of bytes to read = %lu\n", *nbytes);
929
930 *iret = read(*unit, buffer, *nbytes);
931
932 if( DEBUG )
933 printf("PBIO_READ5: number of bytes read = %lun", *iret);
934 /*
935 // Error in file-handling
936 */
937 if(*iret == -1) {
938 *iret = -2;
939 perror("pbread5");
940 return;
941 }
942 /*
943 // Read problem
944 */
945 else if(*iret != *nbytes) {
946 printf("EOF; pbread5; bytes requested %lu; read in: %lu\n",
947 *nbytes,*iret);
948 *iret = -1;
949 return;
950 }
951
952 }
953
954 void pbread5(fortint* unit,char* buffer,size_t* nbytes,size_t* iret) {
955 pbread5_(unit,buffer,nbytes,iret);
956 }
957
958 /*
959 //------------------------------------------------------------------------
960 // oct_bin3
961 //------------------------------------------------------------------------
962 */
963 static int oct_bin3(int onum) {
964 /*
965 // Converts an integer to octal digits
966 */
967 char tmp[20];
968 int rc;
969
970 sprintf(tmp,"%d",onum);
971 sscanf(tmp,"%o",&rc);
972 return rc;
973 }
974
975 /*
976 //------------------------------------------------------------------------
977 // PBOPEN3 - Open file (from FORTRAN)
978 //------------------------------------------------------------------------
979 */
980 void pbopen3_(fortint* unit,_fcd name,_fcd mode,fortint* iret,fortint l1,fortint l2) {
981 /*
982 // Purpose:
983 // Opens file, return UNIX FILE pointer.
984 //
985 // Function returns:
986 // iret: -1 = Could not open file.
987 // -2 = Invalid file name.
988 // -3 = Invalid open mode specified
989 // 0 = OK.
990 //
991 // Note: l1 and l2 are the lengths of the character strings in
992 // name and mode on SGI.
993 */
994 char *p;
995 int oflag;
996 int dmas;
997 int filemode;
998 char flags[4];
999
1000 #if (!defined CRAY) && (!defined VAX)
1001 char namebuff[NAMEBUFFLEN], modebuff[MODEBUFFLEN];
1002 #else
1003 char * namebuff, * modebuff;
1004 #endif
1005
1006 /*
1007 // See if DEBUG switched on.
1008 */
1009 if( ! debugSet ) {
1010 debugLevel = getenv("PBIO_DEBUG");
1011 if( debugLevel == NULL )
1012 debugSet = DEBUGOFF; /* off */
1013 else {
1014 int loop;
1015 for( loop = 0; loop < strlen(debugLevel) ; loop++ ) {
1016 if( ! isdigit(debugLevel[loop]) ) {
1017 printf("Invalid number string in PBIO_DEBUG: %s\n", debugLevel);
1018 printf("PBIO_DEBUG must comprise only digits [0-9].\n");
1019 debugSet = DEBUGOFF;
1020 }
1021 }
1022 debugSet = DEBUGOFF + atol( debugLevel );
1023 }
1024 if( DEBUG ) printf("PBIO_PBOPEN3: debug switched on\n");
1025 }
1026
1027 #if (!defined CRAY) && (!defined VAX)
1028 /*
1029 // Put the character strings into buffers and ensure that there is a
1030 // null terminator (for SGI case when FORTRAN CHARACTER variable is full
1031 // right to end with characters
1032 */
1033 {
1034 int n1, n2;
1035
1036 n1 = (l1>NAMEBUFFLEN) ? NAMEBUFFLEN : l1;
1037 n2 = (l2>MODEBUFFLEN) ? MODEBUFFLEN : l2;
1038
1039 strncpy( namebuff, name, n1);
1040 strncpy( modebuff, mode, n2);
1041 namebuff[n1] = '\0';
1042 modebuff[n2] = '\0';
1043 }
1044 #else
1045 if(!(namebuff = fcd2char(name))) {
1046 *iret = -2;
1047 return;
1048 }
1049 if(!(modebuff = fcd2char(mode))) {
1050 free(namebuff);
1051 *iret = -2;
1052 return;
1053 }
1054 #endif
1055
1056 strcpy(flags,"");
1057
1058 *unit = 0;
1059 *iret = 0;
1060
1061 /*
1062 // Strip trailing blanks
1063 */
1064 p = namebuff + strlen(namebuff) - 1 ;
1065
1066 while(*p == ' ') {
1067 *p = 0;
1068 p--;
1069 }
1070 if( DEBUG ) printf("PBIO_PBOPEN: filename = %s\n", namebuff);
1071
1072 /*
1073 // Build open flags from "modes"
1074 */
1075 p = modebuff;
1076
1077 switch(*p) {
1078
1079 case 'a':
1080 case 'A': oflag = 0x100 | O_CREAT | 2 | 0x08;
1081 filemode = 766;
1082 break;
1083
1084 case 'c':
1085 case 'C':
1086 case 'w':
1087 case 'W': oflag = 0x100 | O_CREAT | 1;
1088 filemode = 766;
1089 break;
1090
1091 case 'r':
1092 case 'R': oflag = 0;
1093 filemode = 444;
1094 break;
1095
1096 default: *iret = -3;
1097 return;
1098
1099 }
1100
1101 if( DEBUG ) printf("PBIO_PBOPEN: file open mode = %s\n", modebuff);
1102
1103 dmas = umask(000);
1104 *unit = open(namebuff, oflag, oct_bin3(filemode));
1105 umask(dmas);
1106
1107 if(*unit == -1) {
1108 perror(namebuff);
1109 perror("pbopen3");
1110 *iret = -2;
1111 }
1112
1113 if( DEBUG ) printf("PBIO_PBOPEN3: file pointer = %0x\n", *unit);
1114
1115 #if (defined CRAY) || (defined VAX)
1116 free(namebuff);
1117 free(modebuff);
1118 #endif
1119
1120 }
1121
1122 void pbopen3(fortint* unit,_fcd name,_fcd mode,fortint* iret,fortint l1,fortint l2) {
1123
1124 pbopen3_(unit,name,mode,iret,l1,l2);
1125 }
1126
1127 /*
1128 //------------------------------------------------------------------------
1129 // PBCLOSE3 - Close file (from FORTRAN)
1130 //------------------------------------------------------------------------
1131 */
1132 void pbclose3_(fortint* unit,fortint* iret) {
1133 /*
1134 //
1135 // Purpose: Closes file.
1136 //
1137 // Function returns:
1138 // status : non-0 = error in handling file.
1139 // 0 = OK.
1140 */
1141 if( DEBUG ) printf("PBIO_PBCLOSE3: file pointer = %0x\n", *unit);
1142
1143 *iret = close(*unit);
1144
1145 if(*iret != 0) perror("pbclose3");
1146 }
1147
1148 void pbclose3(fortint* unit,fortint* iret) {
1149
1150 pbclose3_(unit,iret);
1151 }
1152
1153 /*
1154 //------------------------------------------------------------------------
1155 // PBSEEK3 - Seek (from FORTRAN)
1156 //------------------------------------------------------------------------
1157 */
1158 void pbseek3_(fortint* unit,fortint* offset,fortint* whence,fortint* iret) {
1159 /*
1160 //
1161 // Purpose: Seeks to specified location in file.
1162 //
1163 // Function returns:
1164 // status: -2 = error in handling file,
1165 // -1 = end-of-file
1166 // otherwise, = byte offset from start of file.
1167 //
1168 // whence = 0, from start of file
1169 // = 1, from current position
1170 // = 2, from end of file.
1171 */
1172 fortint my_offset = *offset;
1173 int my_whence;
1174
1175 if( DEBUG ) {
1176 printf("PBIO_PBSEEK3: file pointer = %0x\n", *unit);
1177 printf("PBIO_PBSEEK3: offset = %d\n", my_offset);
1178 printf("PBIO_PBSEEK3: type of offset = %d\n", *whence);
1179 }
1180
1181 /*
1182 // Must use negative offset if working from end-of-file
1183 */
1184 if( *whence == 2) {
1185 my_offset = - abs(my_offset);
1186 my_whence = 2;
1187 }
1188 else if(*whence == 0)
1189 {
1190 my_whence = 0;
1191 }
1192 else
1193 {
1194 my_whence = 1;
1195 }
1196
1197 if((*iret=lseek(*unit, my_offset, my_whence)) < 0) {
1198 perror("pbseek3;");
1199 *iret = -1; /* end-of-file */
1200 }
1201
1202 if( DEBUG )
1203 printf("PBIO_PBSEEK3: byte offset from start of file = %d\n",*iret);
1204
1205 }
1206
1207 void pbseek3(fortint* unit,fortint* offset,fortint* whence,fortint* iret) {
1208
1209 pbseek3_(unit,offset,whence,iret);
1210 }
1211
1212 /*
1213 //------------------------------------------------------------------------
1214 // PBWRITE3 - Write (from FORTRAN)
1215 //------------------------------------------------------------------------
1216 */
1217 void pbwrite3_(fortint* unit,char* buffer,fortint* nbytes,fortint* iret) {
1218 /*
1219 // Purpose: Writes a block of bytes to a file.
1220 //
1221 // Function returns:
1222 // status: -1 = Could not write to file.
1223 // >=0 = Number of bytes written.
1224 */
1225 if( DEBUG ) {
1226 printf("PBIO_PBWRITE3: file pointer = %0x\n", *unit);
1227 printf("PBIO_WRITE#: number of bytes to write = %d\n", *nbytes);
1228 }
1229
1230 *iret = write(*unit, buffer, *nbytes);
1231 if( DEBUG )
1232 printf("PBIO_WRITE3: number of bytes written = %d\n", *iret);
1233
1234 if( *iret != *nbytes ) {
1235 perror("pbwrite3: ");
1236 *iret = -1;
1237 }
1238
1239 }
1240
1241 void pbwrite3(fortint* unit,char* buffer,fortint* nbytes,fortint* iret) {
1242
1243 pbwrite3_(unit,buffer,nbytes,iret);
1244 }
1245
1246 /*
1247 //------------------------------------------------------------------------
1248 // GRIBREAD
1249 //------------------------------------------------------------------------
1250 */
1251 void gribread_(
1252 char* buffer,fortint* buffsize,fortint* readsize,fortint* status,fortint* unit){
1253 /*
1254 // Called as a FORTRAN subroutine:
1255 //
1256 // CALL GRIBREAD( KARRAY, KINLEN, KOUTLEN, IRET, KUNIT )
1257 //
1258 */
1259 fortint holdsize = *buffsize;
1260
1261 /*
1262 // Read GRIB product
1263 */
1264
1265 *status = readprod("GRIB",buffer,&holdsize,fileRead,fileSeek,fileTell,
1266 CURRENT_FILE);
1267 *readsize = abs(holdsize );
1268
1269 if( DEBUG ) {
1270 printf("PBIO_GRIBREAD: fptable slot = %d. ", *unit);
1271 printf("Number of bytes read = %d\n", *readsize);
1272 }
1273
1274 return;
1275 }
1276
1277 void gribread(
1278 char* buffer,fortint* buffsize,fortint* readsize,fortint* status,fortint* unit){
1279
1280 gribread_(buffer,buffsize,readsize,status,unit);
1281 }
1282
1283 /*
1284 //------------------------------------------------------------------------
1285 // BUFRREAD
1286 //------------------------------------------------------------------------
1287 */
1288 void bufrread_(
1289 char* buffer,fortint* buffsize,fortint* readsize,fortint* status,fortint* unit){
1290 /*
1291 // Called as a FORTRAN subroutine:
1292 //
1293 // CALL BUFRREAD( KARRAY, KINLEN, KOUTLEN, IRET, KUNIT )
1294 //
1295 */
1296 fortint holdsize = *buffsize;
1297
1298 /*
1299 // Read BUFR product
1300 */
1301 *status = readprod("BUFR",buffer,&holdsize,fileRead,fileSeek,fileTell,
1302 CURRENT_FILE);
1303 *readsize = abs(holdsize );
1304
1305 if( DEBUG ) {
1306 printf("PBIO_BUFRREAD: fptable slot = %d. ", *unit);
1307 printf("Number of bytes read = %d\n", *readsize);
1308 }
1309
1310 return;
1311 }
1312
1313 void bufrread(
1314 char* buffer,fortint* buffsize,fortint* readsize,fortint* status,fortint* unit){
1315
1316 bufrread_(buffer,buffsize,readsize,status,unit);
1317 }
1318
1319 /*
1320 //------------------------------------------------------------------------
1321 // PSEUREAD
1322 //------------------------------------------------------------------------
1323 */
1324 void pseuread_(
1325 char* buffer,fortint* buffsize,fortint* readsize,fortint* status,fortint* unit){
1326 /*
1327 // Called as a FORTRAN subroutine:
1328 //
1329 // CALL PSEUREAD( KARRAY, KINLEN, KOUTLEN, IRET, KUNIT )
1330 //
1331 */
1332 fortint holdsize = *buffsize;
1333
1334 /*
1335 // Read GRIB product
1336 */
1337 *status = readprod(NULL,buffer,&holdsize,fileRead,fileSeek,fileTell,
1338 CURRENT_FILE);
1339 *readsize = abs(holdsize );
1340
1341 if( DEBUG ) {
1342 printf("PBIO_PSEUREAD: fptable slot = %d. ", *unit);
1343 printf("Number of bytes read = %d\n", *readsize);
1344 }
1345
1346 return;
1347 }
1348
1349 void pseuread(
1350 char* buffer,fortint* buffsize,fortint* readsize,fortint* status,fortint* unit){
1351
1352 pseuread_(buffer,buffsize,readsize,status,unit);
1353 }
1354
1355 /*
1356 //------------------------------------------------------------------------
1357 // PBSIZE
1358 //------------------------------------------------------------------------
1359 */
1360 void pbsize_(fortint* unit,fortint* plen) {
1361 /*
1362 // Returns the size in bytes of the next GRIB, BUFR, TIDE, BUDG, DIAG
1363 // product.
1364 //
1365 // Called from FORTRAN:
1366 // CALL PBSIZE( KUNIT, LENGTH)
1367 //
1368 // unit = file id returned from PBOPEN.
1369 // plen = size in bytes of the next product.
1370 // = -2 if error allocating memory for internal buffer.
1371 //
1372 // The input file is left positioned where it started.
1373 */
1374 fortint iret;
1375 char statbuff[BUFFLEN];
1376 char * buff;
1377 long offset, loop = 1;
1378
1379 /*
1380 // Use a smallish buffer for processing; this should suffice for all cases
1381 // except versions -1 and 0 of GRIB and large BUFR products
1382 */
1383 offset = (fortint) fileTell( CURRENT_FILE);
1384 if( DEBUG ) {
1385 printf("PBIO_SIZE: fptable slot = %d. ", *unit);
1386 printf("Current file position = %lu\n", offset);
1387 }
1388
1389 *plen = BUFFLEN;
1390 if( DEBUG )
1391 printf("PBIO_SIZE: current buffer size = %d\n", *plen);
1392
1393 iret = readprod(NULL,statbuff,plen,fileRead,fileSeek,fileTell,CURRENT_FILE);
1394 if( iret == -2 ) {
1395 printf("readprod error %d\n", iret);
1396 *plen = -2;
1397 return;
1398 }
1399 /*
1400 // If the smallish buffer is too small, progressively increase it until
1401 // big enough
1402 */
1403 while ( iret == -4 ) {
1404 loop++;
1405 buff = (char *) malloc( BUFFLEN*loop);
1406 if( buff == NULL) {
1407 perror("malloc failed in PBSIZE");
1408 *plen = -2;
1409 return;
1410 }
1411 *plen = BUFFLEN*loop;
1412 if( DEBUG )
1413 printf("PBIO_SIZE: buffer size increased to: %d\n", *plen);
1414
1415 offset = (fortint) fileSeek( CURRENT_FILE, offset, SEEK_SET);
1416 offset = (fortint) fileTell( CURRENT_FILE);
1417 iret = readprod(NULL,buff,plen,fileRead,fileSeek,fileTell,CURRENT_FILE);
1418 free(buff);
1419 }
1420
1421 if( iret == -2 ) {
1422 printf("readprod error %d\n", iret);
1423 *plen = -2;
1424 }
1425 /*
1426 // Put the file pointer back where it started
1427 */
1428 if( DEBUG ) {
1429 printf("PBIO_SIZE: file pointer set back to: %lu\n", offset);
1430 printf("PBIO_SIZE: Product size = %d\n", *plen);
1431 }
1432 offset = (fortint) fileSeek( CURRENT_FILE, offset, SEEK_SET);
1433
1434 return ;
1435 }
1436
1437 void pbsize(fortint* unit,fortint* plen) {
1438
1439 pbsize_(unit,plen);
1440 }
1441
1442 /*
1443 //------------------------------------------------------------------------
1444 // CREXRD
1445 //------------------------------------------------------------------------
1446 */
1447 #define END_OF_FILE -1
1448 #define FILE_READ_ERROR -2
1449 #define USER_BUFFER_TOO_SMALL -3
1450 #define FILE_TOO_SMALL -5
1451 #define MINIMUM_CREX_SIZE 13
1452 #define CREX 0x43524558
1453
1454 typedef char * String;
1455
1456 void crexrd_(String buffer,int* bufflen,int* size,int* status,fortint * unit) {
1457 /*
1458 // Called from FORTRAN:
1459 // CALL CREXRD( KARRAY, KINLEN, NREAD, IRET, KUNIT )
1460 */
1461 int loop;
1462 OFF_T foundPosition;
1463 int number, crexFound = 0, endFound = 0;
1464 String endBuffer;
1465 String next;
1466 char plplcrcrlf7777[10] = {0,0,0,0,0,0,0,0,0,0};
1467 char PlPlCrCrLf7777[10] = {0x2b,0x2b,0x0d,0x0d,0x0a,0x37,0x37,0x37,0x37,0x00};
1468
1469 /*
1470 // Check buffer big enough for CREX search
1471 */
1472 if( *bufflen < MINIMUM_CREX_SIZE ) {
1473 *status = USER_BUFFER_TOO_SMALL;
1474 return;
1475 }
1476
1477 /*
1478 // Look for CREX
1479 */
1480 for( loop = 0; loop <= 4; loop++) buffer[loop] = '\0';
1481
1482 while( !crexFound ) {
1483 buffer[0] = buffer[1];
1484 buffer[1] = buffer[2];
1485 buffer[2] = buffer[3];
1486 number = fread((buffer+3), 1, 1, CURRENT_FILE);
1487 if( feof(CURRENT_FILE) ) {
1488 *status = END_OF_FILE;
1489 return;
1490 }
1491 if( (number != 1) || ferror(CURRENT_FILE) ) {
1492 perror("crexrd file read error");
1493 *status = FILE_READ_ERROR;
1494 return;
1495 }
1496 if( strcmp(buffer,"CREX") == 0 ) {
1497 crexFound = 1;
1498 #ifdef FOPEN64
1499 foundPosition = ftello64(CURRENT_FILE) - 4;
1500 #else
1501 foundPosition = ftell(CURRENT_FILE) - 4;
1502 #endif
1503 }
1504 }
1505
1506 /*
1507 // Read some more characters into the buffer
1508 */
1509 number = fread((buffer+4), 1, ((*bufflen)-4), CURRENT_FILE);
1510 if( ferror(CURRENT_FILE) ) {
1511 perror("crexrd file read error");
1512 *status = FILE_READ_ERROR;
1513 return;
1514 }
1515 endBuffer = buffer + number + 3;
1516
1517 /*
1518 // Look for ++CrCrLf7777 at end of product
1519 */
1520 next = buffer+4;
1521 endFound = 0;
1522 for( loop = 0; loop < 8; loop++ )
1523 plplcrcrlf7777[loop] = *(next++);
1524 plplcrcrlf7777[9] = '\0';
1525
1526 while( (!endFound) && (next<=endBuffer) ) {
1527 plplcrcrlf7777[8] = *(next++);
1528 if( strcmp(plplcrcrlf7777,PlPlCrCrLf7777) == 0 ) {
1529 endFound = 1;
1530 *size = (int) (next - buffer);
1531 }
1532
1533 for( loop = 0; loop < 8; loop++ )
1534 plplcrcrlf7777[loop] = plplcrcrlf7777[loop+1];
1535 }
1536
1537 if( !endFound ) {
1538 if( feof(CURRENT_FILE) )
1539 *status = END_OF_FILE;
1540 else
1541 *status = USER_BUFFER_TOO_SMALL;
1542 return;
1543 }
1544
1545 /*
1546 // Position file at end of CREX product
1547 */
1548 #ifdef FOPEN64
1549 *status = fseeko64(CURRENT_FILE, (foundPosition+(*size)), 0);
1550 #else
1551 *status = fseek(CURRENT_FILE, (foundPosition+(*size)), 0);
1552 #endif
1553
1554 }
1555
1556 void crexrd(String buffer,int* bufflen,int* size,int* status,fortint * unit) {
1557
1558 crexrd_(buffer,bufflen,size,status,unit);
1559 }
1560