NCEPLIBS-g2c 2.0.0
Loading...
Searching...
No Matches
g2cfile.c
Go to the documentation of this file.
1
7#include "grib2_int.h"
8
11
14
16#define MIN(a, b) ((a) < (b) ? (a) : (b))
17
19#define READ_BUF_SIZE 4092
20
22#define BYTES_TO_DISCIPLINE 6
23
26
27#define G2C_SEEKMSG_BUFSIZE 4092
31
55int
56g2c_seekmsg(int g2cid, size_t skip, size_t *offset, size_t *msglen)
57{
58 size_t k4;
59 int k, lim;
60 int end;
61 unsigned char *cbuf;
62 size_t bytes_read = G2C_SEEKMSG_BUFSIZE;
63 size_t my_msglen = 0, my_offset = 0, ipos;
64
65 /* Find the open file struct. */
66 if (g2c_file[g2cid].g2cid != g2cid)
67 return G2C_EBADID;
68
69 LOG((3, "g2c_seekgb skip %ld", skip));
70
71 /* Get memory to read in some of the file. */
72 if (!(cbuf = malloc(G2C_SEEKMSG_BUFSIZE)))
73 return G2C_ENOMEM;
74
75 ipos = skip;
76
77 /* Loop until grib message is found. */
78 while (my_msglen == 0 && bytes_read == G2C_SEEKMSG_BUFSIZE)
79 {
80 /* Read partial section. */
81 if (fseek(g2c_file[g2cid].f, ipos, SEEK_SET))
82 {
83 free(cbuf);
84 return G2C_EFILE;
85 }
86 bytes_read = fread(cbuf, sizeof(unsigned char), G2C_SEEKMSG_BUFSIZE, g2c_file[g2cid].f);
87 lim = bytes_read - 8;
88
89 /* Look for 'GRIB...2' in partial section. */
90 for (k = 0; k < lim; k++)
91 {
92 if (!strncmp((char *)&cbuf[k], G2C_MAGIC_HEADER, strlen(G2C_MAGIC_HEADER)) && cbuf[k + 7] == 2)
93 {
94 /* Find the length of the message. This is stored as
95 * an 8-byte big-endian integer starting at positon
96 * 8 in cbuf. */
97 my_msglen = hton64(*(size_t *)&cbuf[k + 8]);
98
99 LOG((4, "my_msglen %ld", my_msglen));
100
101 /* Read the last 4 bytes of the message. */
102 if (fseek(g2c_file[g2cid].f, ipos + k + my_msglen - 4, SEEK_SET))
103 {
104 free(cbuf);
105 return G2C_EFILE;
106 }
107
108 if ((k4 = fread(&end, 4, 1, g2c_file[g2cid].f)) != 1)
109 {
110 free(cbuf);
111 return G2C_EFILE;
112 }
113
114 /* Look for '7777' at end of grib message. */
115 if (k4 == 1 && end == 926365495)
116 {
117 /* GRIB message found. */
118 my_offset = ipos + k;
119 LOG((4, "found end of message my_offset %ld", my_offset));
120 break;
121 }
122 }
123 }
124 ipos = ipos + lim;
125 }
126
127 /* Free resources. */
128 free(cbuf);
129
130 /* Return information to the caller. */
131 if (offset)
132 *offset = my_offset;
133 if (msglen)
134 *msglen = my_msglen;
135
136 return G2C_NOERROR;
137}
138
163int
164g2c_find_msg2(int g2cid, size_t skip_bytes, size_t max_bytes, size_t *bytes_to_msg,
165 size_t *bytes_in_msg)
166{
167 size_t bytes_to_read = MIN(READ_BUF_SIZE, max_bytes);
168 size_t bytes_read;
169 unsigned char *buf;
170 int grib_version;
171 int eof = 0;
172 int msg_found = 0;
173 size_t num_blocks;
174 size_t ftell_pos;
175 int i;
176 int done = 0;
177 int ret = G2C_NOERROR;
178
179 /* Check inputs. */
180 if (!bytes_to_msg || !bytes_in_msg)
181 return G2C_EINVAL;
182
183 /* Find the open file struct. */
184 if (g2c_file[g2cid].g2cid != g2cid)
185 return G2C_EBADID;
186
187 /* Skip some bytes if desired. */
188 if (fseek(g2c_file[g2cid].f, (off_t)skip_bytes, SEEK_SET))
189 return G2C_ERROR;
190
191 /* Allocate storage to read into. */
192 if (!(buf = calloc(bytes_to_read, sizeof(char))))
193 return G2C_ENOMEM;
194
195 for (num_blocks = 0; !eof && !done; num_blocks++)
196 {
197 /* Read some bytes. If we don't get the number expected, either a
198 * read error occured, or we reached the end of file. */
199 if ((ftell_pos = ftell(g2c_file[g2cid].f)) == -1)
200 return G2C_EFILE;
201 LOG((4, "before read ftell() is %ld (0x%x) reading %ld bytes", ftell_pos,
202 ftell_pos, bytes_to_read));
203 if ((bytes_read = fread(buf, 1, bytes_to_read, g2c_file[g2cid].f)) != bytes_to_read)
204 {
205 if (ferror(g2c_file[g2cid].f))
206 ret = G2C_EFILE;
207 eof++;
208 }
209
210 /* Scan for 'GRIB2' in the bytes we have read. */
211 if (!ret)
212 {
213 for (i = 0; i < bytes_read; i++)
214 {
215#ifdef LOGGING
216 /* if (i < 10) LOG((3, "buf[%ld] = %2.2x", i, buf[i])); */
217#endif
218 /* Find the beginning of a GRIB message. */
219 if (buf[i] == 'G' && i < bytes_read - G2C_MAGIC_HEADER_LEN && buf[i + 1] == 'R' && buf[i + 2] == 'I' && buf[i + 3] == 'B')
220 {
221 msg_found++;
222 *bytes_to_msg = ftell_pos + i;
223 grib_version = buf[i + 7];
224 LOG((3, "bytes_to_msg %ld grib_version %d", *bytes_to_msg, grib_version));
225 if (grib_version != 1 && grib_version != 2)
226 {
227 ret = G2C_EMSG;
228 done++;
229 break;
230 }
231 }
232
233 /* Find the end of a GRIB message. And then we're done. */
234 if (msg_found && buf[i] == '7' && i < bytes_read - G2C_MAGIC_HEADER_LEN && buf[i + 1] == '7' && buf[i + 2] == '7' && buf[i + 3] == '7')
235 {
236 msg_found--;
237 *bytes_in_msg = ftell_pos + i - *bytes_to_msg + 4;
238 LOG((3, "bytes_in_msg %ld", *bytes_in_msg));
239 ret = G2C_NOERROR;
240 done++;
241 break;
242 }
243 }
244 }
245
246 /* Back up 8 bytes in case the "GRIB" magic header occurred
247 * within the last 8 bytes of the previous read. */
248 if (!done)
249 if (fseek(g2c_file[g2cid].f, (off_t)(ftell(g2c_file[g2cid].f) - G2C_MAGIC_HEADER_LEN),
250 SEEK_SET))
251 return G2C_ERROR;
252 }
253
254 /* Free storage. */
255 free(buf);
256
257 return ret;
258}
259
290int
291g2c_get_msg(int g2cid, size_t skip_bytes, size_t max_bytes, size_t *bytes_to_msg,
292 size_t *bytes_in_msg, unsigned char **cbuf)
293{
294 size_t bytes_read;
295 int ret = G2C_NOERROR;
296
297 /* Check inputs. */
298 if (!bytes_to_msg || !bytes_in_msg || !cbuf || max_bytes < G2C_MIN_MAX_BYTES)
299 return G2C_EINVAL;
300
301 LOG((2, "g2c_get_msg g2cid %d skip_bytes %ld max_bytes %ld", g2cid, skip_bytes,
302 max_bytes));
303
304 /* Find the open file struct. */
305 if (g2c_file[g2cid].g2cid != g2cid)
306 return G2C_EBADID;
307
308 /* Find the start and length of the GRIB message. */
309 {
310 g2int bytes_to_msg_g, bytes_in_msg_g;
311 seekgb(g2c_file[g2cid].f, (g2int)skip_bytes, (g2int)max_bytes, &bytes_to_msg_g,
312 &bytes_in_msg_g);
313 *bytes_to_msg = bytes_to_msg_g;
314 *bytes_in_msg = bytes_in_msg_g;
315 }
316 LOG((4, "*bytes_to_msg %ld *bytes_in_msg %ld", *bytes_to_msg, *bytes_in_msg));
317
318 /* If no message was found, return an error. */
319 if (*bytes_in_msg == 0)
320 return G2C_ENOMSG;
321
322 /* Allocate storage for the GRIB message. */
323 if (!(*cbuf = malloc(*bytes_in_msg)))
324 return G2C_ENOMEM;
325
326 /* Position file at start of GRIB message. */
327 if (fseek(g2c_file[g2cid].f, (off_t)*bytes_to_msg, SEEK_SET))
328 {
329#ifdef LOGGING
330 int my_errno = errno;
331 LOG((0, "fseek error %s", strerror(my_errno)));
332#endif
333 return G2C_ERROR;
334 }
335
336 /* Read the message from the file into the buffer. */
337 if ((bytes_read = fread(*cbuf, 1, *bytes_in_msg, g2c_file[g2cid].f)) != *bytes_in_msg)
338 return G2C_EFILE;
339
340#ifdef LOGGING
341 {
342 int i;
343 for (i = 0; i < 10; i++)
344 LOG((4, "cbuf[%d] = %2x", i, (*cbuf)[i]));
345 }
346#endif
347
348 return ret;
349}
350
362static int
364{
365 int i;
366 int ret;
367
368 /* Check input. */
369 if (!g2cid)
370 return G2C_EINVAL;
371
372 /* Find a new g2cid. */
373 for (i = 0; i < G2C_MAX_FILES + 1; i++)
374 {
375 int id = (i + g2c_next_g2cid) % (G2C_MAX_FILES + 1);
376
377 /* Is this ID available? If so, we're done. */
378 if (!g2c_file[id].g2cid)
379 {
380 *g2cid = id;
381 g2c_next_g2cid = id + 1;
382 ret = G2C_NOERROR;
383 break;
384 }
385 }
386
387 /* If we couldn't find one, all available files are already
388 * open. */
389 if (i == G2C_MAX_FILES + 1)
390 ret = G2C_ETOOMANYFILES;
391
392 return ret;
393}
394
414static int
416{
417 G2C_DIM_INFO_T *d0, *d1;
418 G2C_SECTION3_INFO_T *sec3_info;
419 int d;
420
421 sec3_info = (G2C_SECTION3_INFO_T *)(sec->sec_info);
422 d0 = &(sec3_info->dim[0]);
423 d1 = &(sec3_info->dim[1]);
424
425 /* Based on the grid definition template number, and the contents
426 * of the template, decide the len, name, and values of the two
427 * dimensions. */
428 switch (sec3_info->grid_def)
429 {
430 case 0:
431 LOG((5, "determine_dim allocating storage for lat/lon values"));
432 d0->len = sec->template[8];
433 strncpy(d0->name, LATITUDE, G2C_MAX_NAME);
434 if (!(d0->value = malloc(d0->len * sizeof(float))))
435 return G2C_ENOMEM;
436 d0->value[0] = sec->template[11];
437 for (d = 1; d < d0->len; d++)
438 d0->value[d] = d0->value[d - 1] - sec->template[16];
439
440 d1->len = sec->template[7];
441 strncpy(d1->name, LONGITUDE, G2C_MAX_NAME);
442 if (!(d1->value = malloc(d1->len * sizeof(float))))
443 return G2C_ENOMEM;
444 d1->value[0] = sec->template[12];
445 for (d = 1; d < d1->len; d++)
446 d1->value[d] = d1->value[d - 1] - sec->template[17];
447 break;
448 default:
449 break;
450 }
451
452 return G2C_NOERROR;
453}
454
477int
479{
480 G2C_SECTION3_INFO_T *sec3_info = NULL;
481 int maplen, needsext, map[G2C_MAX_GDS_TEMPLATE_MAPLEN];
482 int t;
483 int ret;
484
485 /* Check input. */
486 if (!f || !sec)
487 return G2C_EINVAL;
488 if (!rw_flag && sec->sec_num != 3)
489 return G2C_EINVAL;
490
491 LOG((6, "g2c_rw_section3_metadata starting to %s section 3 at file position %ld",
492 rw_flag ? "write" : "read", ftell(f)));
493
494 /* If reading, allocate storage for a new section 3. */
495 if (!rw_flag)
496 {
497 if (!(sec3_info = calloc(sizeof(G2C_SECTION3_INFO_T), 1)))
498 return G2C_ENOMEM;
499 }
500 else
501 sec3_info = sec->sec_info;
502
503 /* Read or write section 3. */
504 if ((ret = g2c_file_io_ubyte(f, rw_flag, &sec3_info->source_grid_def)))
505 return ret;
506 if ((ret = g2c_file_io_uint(f, rw_flag, &sec3_info->num_data_points)))
507 return ret;
508 if ((ret = g2c_file_io_ubyte(f, rw_flag, &sec3_info->num_opt)))
509 return ret;
510 if ((ret = g2c_file_io_ubyte(f, rw_flag, &sec3_info->interp_list)))
511 return ret;
512 if ((ret = g2c_file_io_ushort(f, rw_flag, &sec3_info->grid_def)))
513 return ret;
514 LOG((5, "rw_section3_metadata source_grid_def %d num_data_points %d num_opt %d interp_list %d grid_def %d",
515 sec3_info->source_grid_def, sec3_info->num_data_points, sec3_info->num_opt, sec3_info->interp_list,
516 sec3_info->grid_def));
517
518 /* Look up the information about this grid. */
519 if ((ret = g2c_get_grid_template(sec3_info->grid_def, &maplen, map, &needsext)))
520 return ret;
521
522 /* When reading, allocate space to hold the template info. */
523 if (!rw_flag)
524 {
525 sec->template_len = maplen;
526 if (!(sec->template = calloc(sizeof(long long int) * maplen, 1)))
527 return G2C_ENOMEM;
528 }
529
530 /* Read or write the template info. */
531 for (t = 0; t < maplen; t++)
532 {
533 if ((ret = g2c_file_io_template(f, rw_flag, map[t], &sec->template[t])))
534 return ret;
535 LOG((7, "template[%d] %d", t, sec->template[t]));
536 }
537
538 /* Attach sec3_info to our section data. */
539 if (!rw_flag)
540 sec->sec_info = sec3_info;
541
542 /* Figure out the dimensions, if we can. */
543 if (!rw_flag)
544 if ((ret = determine_dims(sec)))
545 return ret;
546
547 LOG((6, "finished reading or writing section 3 at file position %ld", ftell(f)));
548 return G2C_NOERROR;
549}
550
573int
575{
576 G2C_SECTION4_INFO_T *sec4_info;
577 int maplen, needsext, map[G2C_MAX_PDS_TEMPLATE_MAPLEN];
578 int t;
579 int ret;
580
581 /* Check input. */
582 if (!f || !sec)
583 return G2C_EINVAL;
584 if (!rw_flag && sec->sec_num != 4)
585 return G2C_EINVAL;
586
587 LOG((3, "read_section4_metadata rw_flag %d", rw_flag));
588
589 /* When reading, allocate storage for a new section 4. */
590 if (!rw_flag)
591 {
592 if (!(sec4_info = calloc(sizeof(G2C_SECTION4_INFO_T), 1)))
593 return G2C_ENOMEM;
594 }
595 else
596 sec4_info = sec->sec_info;
597
598 /* When reading, assign a number to this field, and count the
599 * number of fields in the message. */
600 if (!rw_flag)
601 sec4_info->field_num = sec->msg->num_fields++;
602
603 LOG((6, "reading section 4 starting at file position %ld", ftell(f)));
604
605 /* Read section 4. */
606 if ((ret = g2c_file_io_ushort(f, rw_flag, &sec4_info->num_coord)))
607 return ret;
608 if ((ret = g2c_file_io_ushort(f, rw_flag, &sec4_info->prod_def)))
609 return ret;
610 LOG((5, "read_section4_metadata num_coord %d prod_def %d", sec4_info->num_coord, sec4_info->prod_def));
611
612 /* Look up the information about this grid. */
613 if ((ret = g2c_get_pds_template(sec4_info->prod_def, &maplen, map, &needsext)))
614 return ret;
615 LOG((5, "pds template maplen %d", maplen));
616
617 /* When reading, allocate space to hold the template info. */
618 if (!rw_flag)
619 {
620 sec->template_len = maplen;
621 if (!(sec->template = calloc(sizeof(long long int) * maplen, 1)))
622 return G2C_ENOMEM;
623 }
624
625 /* Read or write the template info. */
626 for (t = 0; t < maplen; t++)
627 {
628 if ((ret = g2c_file_io_template(f, rw_flag, map[t], &sec->template[t])))
629 return ret;
630 LOG((7, "template[%d] %d", t, sec->template[t]));
631 }
632
633 /* When reading, attach sec4_info to our section data. */
634 if (!rw_flag)
635 sec->sec_info = sec4_info;
636
637 return G2C_NOERROR;
638}
639
662int
664{
665 G2C_SECTION5_INFO_T *sec5_info;
666 int maplen, needsext, map[G2C_MAX_PDS_TEMPLATE_MAPLEN];
667 int t;
668 int ret;
669
670 /* Check input. */
671 if (!f || !sec)
672 return G2C_EINVAL;
673 LOG((5, "g2c_rw_section5_metadata rw_flag %d at file position %ld", rw_flag,
674 ftell(f)));
675
676 /* When reading, allocate storage for a new section 5. When
677 * writing, get a pointer to the exitsing sec5_info. */
678 if (!rw_flag)
679 {
680 if (!(sec5_info = calloc(sizeof(G2C_SECTION5_INFO_T), 1)))
681 return G2C_ENOMEM;
682 }
683 else
684 sec5_info = sec->sec_info;
685
686 /* Read section 5. */
687 if ((ret = g2c_file_io_uint(f, rw_flag, &sec5_info->num_data_points)))
688 return ret;
689 if ((ret = g2c_file_io_ushort(f, rw_flag, &sec5_info->data_def)))
690 return ret;
691 LOG((5, "g2c_rw_section5_metadata num_data_points %d data_def %d",
692 sec5_info->num_data_points, sec5_info->data_def));
693
694 /* Look up the information about this grid. */
695 if ((ret = g2c_get_drs_template(sec5_info->data_def, &maplen, map, &needsext)))
696 return ret;
697 LOG((5, "grid template maplen %d", maplen));
698
699 /* WHen reading, allocate space to hold the template info. */
700 if (!rw_flag)
701 {
702 sec->template_len = maplen;
703 if (!(sec->template = calloc(sizeof(long long int) * maplen, 1)))
704 return G2C_ENOMEM;
705 }
706
707 /* Read or write the template info. */
708 for (t = 0; t < maplen; t++)
709 {
710 if ((ret = g2c_file_io_template(f, rw_flag, map[t], &sec->template[t])))
711 return ret;
712 LOG((7, "template[%d] %d", t, sec->template[t]));
713 }
714
715 /* When reading, attach sec5_info to our section data. */
716 if (!rw_flag)
717 sec->sec_info = sec5_info;
718
719 return G2C_NOERROR;
720}
721
744int
746{
747 G2C_SECTION6_INFO_T *sec6_info;
748 int ret;
749
750 /* Check input. */
751 if (!f || !sec)
752 return G2C_EINVAL;
753 LOG((4, "g2c_rw_section6_metadata rw_flag %d at file position %ld", rw_flag,
754 ftell(f)));
755
756 /* When reading, allocate storage for a new section 6. When
757 * writing, get a pointer to the exitsing sec6_info. */
758 if (!rw_flag)
759 {
760 if (!(sec6_info = calloc(sizeof(G2C_SECTION6_INFO_T), 1)))
761 return G2C_ENOMEM;
762 }
763 else
764 sec6_info = sec->sec_info;
765
766 /* Read or write section 6. */
767 if ((ret = g2c_file_io_ubyte(f, rw_flag, &sec6_info->indicator)))
768 return ret;
769 LOG((4, "g2c_rw_section6_metadata indicator %d", sec6_info->indicator));
770
771 /* When reading, attach sec6_info to our section data. */
772 if (!rw_flag)
773 sec->sec_info = sec6_info;
774
775 return G2C_NOERROR;
776}
777
793int
794add_section(FILE *f, G2C_MESSAGE_INFO_T *msg, int sec_id, unsigned int sec_len,
795 size_t bytes_to_sec, unsigned char sec_num)
796{
798 int ret;
799
800 LOG((4, "add_section sec_id %d sec_len %d, bytes_to_sec %ld, sec_num %d",
801 sec_id, sec_len, bytes_to_sec, sec_num));
802
803 /* Allocate storage for a new section. */
804 if (!(sec = calloc(sizeof(G2C_SECTION_INFO_T), 1)))
805 return G2C_ENOMEM;
806
807 /* Add sec to end of linked list. */
808 if (!msg->sec)
809 msg->sec = sec;
810 else
811 {
813
814 for (s = msg->sec; s->next; s = s->next)
815 ;
816 s->next = sec;
817 sec->prev = s;
818 }
819
820 /* Remember values. */
821 sec->msg = msg;
822 sec->sec_id = sec_id;
823 sec->sec_len = sec_len;
824 sec->sec_num = sec_num;
825 sec->bytes_to_sec = bytes_to_sec;
826
827 switch (sec_num)
828 {
829 case 1:
830 break;
831 case 2:
832 msg->num_local++;
833 break;
834 case 3:
835 if ((ret = g2c_rw_section3_metadata(f, G2C_FILE_READ, sec)))
836 return ret;
837 break;
838 case 4:
839 if ((ret = g2c_rw_section4_metadata(f, G2C_FILE_READ, sec)))
840 return ret;
841 break;
842 case 5:
843 if ((ret = g2c_rw_section5_metadata(f, G2C_FILE_READ, sec)))
844 return ret;
845 break;
846 case 6:
847 if ((ret = g2c_rw_section6_metadata(f, G2C_FILE_READ, sec)))
848 return ret;
849 break;
850 case 7:
851 break;
852 default:
853 return G2C_EBADSECTION;
854 }
855
856 return G2C_NOERROR;
857}
858
873int
875{
876 unsigned char sec_num = 1;
877 int ret;
878
879 LOG((3, "g2c_rw_section1_metadata rw_flag %d", rw_flag));
880
881 /* Read the section. */
882 if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)&msg->sec1_len)))
883 return ret;
884
885 if ((ret = g2c_file_io_ubyte(f, rw_flag, &sec_num)))
886 return ret;
887 if (!rw_flag && sec_num != 1) /* When reading sec num must be 1. */
888 return G2C_ENOSECTION;
889 if ((ret = g2c_file_io_short(f, rw_flag, &msg->center)))
890 return ret;
891 if ((ret = g2c_file_io_short(f, rw_flag, &msg->subcenter)))
892 return ret;
893 if ((ret = g2c_file_io_ubyte(f, rw_flag, &msg->master_version)))
894 return ret;
895 if ((ret = g2c_file_io_ubyte(f, rw_flag, &msg->local_version)))
896 return ret;
897 if ((ret = g2c_file_io_ubyte(f, rw_flag, &msg->sig_ref_time)))
898 return ret;
899 if ((ret = g2c_file_io_short(f, rw_flag, &msg->year)))
900 return ret;
901 if ((ret = g2c_file_io_ubyte(f, rw_flag, &msg->month)))
902 return ret;
903 if ((ret = g2c_file_io_ubyte(f, rw_flag, &msg->day)))
904 return ret;
905 if ((ret = g2c_file_io_ubyte(f, rw_flag, &msg->hour)))
906 return ret;
907 if ((ret = g2c_file_io_ubyte(f, rw_flag, &msg->minute)))
908 return ret;
909 if ((ret = g2c_file_io_ubyte(f, rw_flag, &msg->second)))
910 return ret;
911 if ((ret = g2c_file_io_ubyte(f, rw_flag, &msg->status)))
912 return ret;
913 if ((ret = g2c_file_io_ubyte(f, rw_flag, &msg->type)))
914 return ret;
915
916 /* Section 1 may contain optional numbers at the end of the
917 * section. The sec1_len tells us if there are extra values. If
918 * so, skip them. */
919 if (msg->sec1_len > G2C_SECTION1_BYTES)
920 fseek(f, msg->sec1_len - G2C_SECTION1_BYTES, SEEK_CUR);
921
922 return G2C_NOERROR;
923}
924
936static int
938{
939 int total_read = G2C_SECTION0_BYTES;
940 int sec_id = 0;
941 int ret;
942
943 LOG((6, "read_msg_metadata file position %ld", ftell(msg->file->f)));
944
945 /* Read section 0. */
946 if (fseek(msg->file->f, msg->bytes_to_msg + BYTES_TO_DISCIPLINE, SEEK_SET))
947 return G2C_EFILE;
948 if ((fread(&msg->discipline, ONE_BYTE, 1, msg->file->f)) != 1)
949 return G2C_EFILE;
950
951 /* Skip to section 1. */
952 if (fseek(msg->file->f, 9, SEEK_CUR))
953 return G2C_EFILE;
954
955 /* Read section 1. */
956 if ((ret = g2c_rw_section1_metadata(msg->file->f, G2C_FILE_READ, msg)))
957 return ret;
958 total_read += msg->sec1_len;
959
960 /* Read the sections. */
961 while (total_read < msg->bytes_in_msg - FOUR_BYTES)
962 {
963 unsigned int sec_len;
964 unsigned char sec_num;
965
966 LOG((4, "reading new section at file position %ld", ftell(msg->file->f)));
967
968 /* Read section length. */
969 if ((ret = g2c_file_io_uint(msg->file->f, G2C_FILE_READ, &sec_len)))
970 return ret;
971
972 /* A section length of 926365495 indicates we've reached
973 * section 8, the end of the message. */
974 if (sec_len != 926365495)
975 {
976 /* Read section number. */
977 if ((ret = g2c_file_io_ubyte(msg->file->f, G2C_FILE_READ, &sec_num)))
978 return ret;
979 LOG((4, "sec_len %d sec_num %d", sec_len, sec_num));
980
981 /* Add a new section to our list of sections. */
982 if ((ret = add_section(msg->file->f, msg, sec_id++, sec_len, total_read, sec_num)))
983 return G2C_EBADSECTION;
984
985 /* Skip to next section. */
986 total_read += sec_len;
987 LOG((4, "total_read %d", total_read));
988 if (fseek(msg->file->f, msg->bytes_to_msg + total_read, SEEK_SET))
989 return G2C_EFILE;
990 }
991 else
992 break;
993 }
994
995 return G2C_NOERROR;
996}
997
1016int
1017add_msg(G2C_FILE_INFO_T *file, int msg_num, size_t bytes_to_msg, size_t bytes_in_msg,
1018 int read_file, G2C_MESSAGE_INFO_T **msg)
1019{
1020 G2C_MESSAGE_INFO_T *my_msg;
1021 int ret;
1022
1023 LOG((4, "add_msg msg_num %d bytes_to_msg %ld bytes_in_msg %ld read_file %d",
1024 msg_num, bytes_to_msg, bytes_in_msg, read_file));
1025
1026 /* Allocate storage for a new message. */
1027 if (!(my_msg = calloc(sizeof(G2C_MESSAGE_INFO_T), 1)))
1028 return G2C_ENOMEM;
1029
1030 /* Add my_msg to end of linked list. */
1031 if (!file->msg)
1032 file->msg = my_msg;
1033 else
1034 {
1036
1037 for (m = file->msg; m->next; m = m->next)
1038 ;
1039 m->next = my_msg;
1040 }
1041
1042 /* Remember values. */
1043 my_msg->msg_num = msg_num;
1044 my_msg->bytes_to_msg = bytes_to_msg;
1045 my_msg->bytes_in_msg = bytes_in_msg;
1046 my_msg->file = file;
1047
1048 /* Read message metadata. We do this if we are opening a GRIB2
1049 * data file, but not if we are reading a GRIB2 index file. */
1050 if (read_file)
1051 if ((ret = read_msg_metadata(my_msg)))
1052 return ret;
1053
1054 /* Increment number of messages in the file. */
1055 my_msg->file->num_messages++;
1056
1057 /* Return pointer to caller, if desired. */
1058 if (msg)
1059 *msg = my_msg;
1060
1061 return G2C_NOERROR;
1062}
1063
1078static int
1080{
1081 size_t msg_num;
1082 size_t file_pos = 0;
1083 size_t bytes_to_msg, bytes_in_msg;
1084 int ret = G2C_NOERROR;
1085
1086 /* Find the open file struct. */
1087 if (g2c_file[g2cid].g2cid != g2cid)
1088 return G2C_EBADID;
1089
1090 LOG((4, "read_metadata g2cid %d", g2cid));
1091
1092 /* Read each message in the file. */
1093 for (msg_num = 0; !ret; msg_num++)
1094 {
1095 /* Find the message. */
1096 if ((ret = g2c_seekmsg(g2cid, file_pos, &bytes_to_msg, &bytes_in_msg)))
1097 return ret;
1098 LOG((5, "msg_num %d bytes_to_msg %ld bytes_in_msg %ld", msg_num, bytes_to_msg,
1099 bytes_in_msg));
1100
1101 /* When there are 0 bytes_in_msg, we are done. */
1102 if (!bytes_in_msg)
1103 break;
1104
1105 /* Add new message to our list of messages. */
1106 if ((ret = add_msg(&g2c_file[g2cid], msg_num, bytes_to_msg, bytes_in_msg,
1107 1, NULL)))
1108 return ret;
1109
1110 /* Move the file position to the end of this message, ready to
1111 * scan for the next message. */
1112 file_pos = bytes_to_msg + bytes_in_msg;
1113 LOG((6, "file_pos %ld", file_pos));
1114 }
1115
1116 /* If we read some messages, then run out, that's success. */
1117 if (ret == G2C_ENOMSG && msg_num)
1118 ret = G2C_NOERROR;
1119
1120#ifdef LOGGING
1121 /* Print the file contents for library debugging. */
1122 g2c_log_file(g2cid);
1123#endif
1124
1125 return ret;
1126}
1127
1142int
1143g2c_add_file(const char *path, int mode, int *g2cid)
1144{
1145 int ret;
1146
1147 /* Check inputs. */
1148 if (strlen(path) > G2C_MAX_NAME)
1149 return G2C_ENAMETOOLONG;
1150 if (!g2cid)
1151 return G2C_EINVAL;
1152
1153 LOG((3, "g2c_add_file path %s mode %d", path, mode));
1154
1155 /* Find a file ID. */
1156 if ((ret = find_available_g2cid(g2cid)))
1157 return ret;
1158
1159 /* Open the file. */
1160 if (!(g2c_file[*g2cid].f = fopen(path, (mode & G2C_WRITE ? "rb+" : "rb"))))
1161 return G2C_EFILE;
1162
1163 /* Copy the path. */
1164 strncpy(g2c_file[*g2cid].path, path, G2C_MAX_NAME);
1165
1166 /* Remember the id. */
1167 g2c_file[*g2cid].g2cid = *g2cid;
1168
1169 /* Initialize other values in struct. */
1170 g2c_file[*g2cid].msg = NULL;
1171 g2c_file[*g2cid].num_messages = 0;
1172
1173 return G2C_NOERROR;
1174}
1175
1189int
1190g2c_open(const char *path, int mode, int *g2cid)
1191{
1192 int ret;
1193
1194 LOG((2, "g2c_open path %s mode %d", path, mode));
1195
1196 /* If using threading, lock the mutex. */
1197 MUTEX_LOCK(m);
1198
1199 /* Open the file and add it to the list of open files. */
1200 ret = g2c_add_file(path, mode, g2cid);
1201
1202 /* Read the metadata. */
1203 if (!ret)
1204 ret = read_metadata(*g2cid);
1205
1206 /* If using threading, unlock the mutex. */
1207 MUTEX_UNLOCK(m);
1208
1209 return ret;
1210}
1211
1212#if 0
1225int
1226g2c_create(const char *path, int cmode, int *g2cid)
1227{
1228 int my_g2cid;
1229 int ret;
1230
1231 /* Check inputs. */
1232 if (strlen(path) > G2C_MAX_NAME)
1233 return G2C_ENAMETOOLONG;
1234 if (!g2cid)
1235 return G2C_EINVAL;
1236
1237 LOG((2, "g2c_create path %s cmode %d", path, cmode));
1238
1239 /* If NOCLOBBER, check if file exists. */
1240 if (cmode & G2C_NOCLOBBER)
1241 {
1242 FILE *f;
1243 if ((f = fopen(path, "r")))
1244 {
1245 fclose(f);
1246 return G2C_EFILE;
1247 }
1248 }
1249
1250 /* If using threading, lock the mutex. */
1251 MUTEX_LOCK(m);
1252
1253 /* Find a file ID. */
1254 ret = find_available_g2cid(&my_g2cid);
1255
1256 /* Create the file. */
1257 if (!ret)
1258 if (!(g2c_file[my_g2cid].f = fopen(path, "bw+")))
1259 ret = G2C_EFILE;
1260
1261 if (!ret)
1262 {
1263 /* Read the metadata. */
1264
1265 /* Copy the path. */
1266 strncpy(g2c_file[my_g2cid].path, path, G2C_MAX_NAME);
1267
1268 /* Remember the id. */
1269 g2c_file[my_g2cid].g2cid = my_g2cid;
1270
1271 /* Pass id back to user. */
1272 *g2cid = my_g2cid;
1273 }
1274
1275 /* If using threading, unlock the mutex. */
1276 MUTEX_UNLOCK(m);
1277
1278 return G2C_NOERROR;
1279}
1280#endif
1281
1292static int
1294{
1295 G2C_MESSAGE_INFO_T *msg;
1296
1297 /* Check input. */
1298 if (g2cid > G2C_MAX_FILES)
1299 return G2C_EBADID;
1300 if (g2c_file[g2cid].g2cid != g2cid)
1301 return G2C_EBADID;
1302
1303 /* Free message resources. */
1304 msg = g2c_file[g2cid].msg;
1305 while (msg)
1306 {
1307 G2C_MESSAGE_INFO_T *mtmp;
1308 G2C_SECTION_INFO_T *sec;
1309
1310 /* Free section metadata. */
1311 sec = msg->sec;
1312 while (sec)
1313 {
1314 G2C_SECTION_INFO_T *stmp;
1315
1316 stmp = sec->next;
1317 if (sec->template)
1318 free(sec->template);
1319 /* Free dim info in section 3. */
1320 if (sec->sec_num == 3)
1321 {
1322 LOG((5, "free_metadata freeing storage for lat/lon values"));
1323 float *v0 = ((G2C_SECTION3_INFO_T *)(sec->sec_info))->dim[0].value;
1324 float *v1 = ((G2C_SECTION3_INFO_T *)(sec->sec_info))->dim[1].value;
1325 if (v0)
1326 free(v0);
1327 if (v1)
1328 free(v1);
1329 }
1330 if (sec->sec_info)
1331 free(sec->sec_info);
1332 free(sec);
1333 sec = stmp;
1334 }
1335
1336 /* Free message. */
1337 mtmp = msg->next;
1338 free(msg);
1339 msg = mtmp;
1340 }
1341
1342 return G2C_NOERROR;
1343}
1344
1355int
1356g2c_close(int g2cid)
1357{
1358 int ret = G2C_NOERROR;
1359
1360 /* Check input. */
1361 if (g2cid > G2C_MAX_FILES)
1362 return G2C_EBADID;
1363
1364 /* If using threading, lock the mutex. */
1365 MUTEX_LOCK(m);
1366
1367 if (g2c_file[g2cid].g2cid != g2cid)
1368 ret = G2C_EBADID;
1369
1370 LOG((2, "g2c_close %d", g2cid));
1371
1372 /* Free resources. */
1373 if (!ret)
1374 ret = free_metadata(g2cid);
1375
1376 /* Close the file. */
1377 if (!ret)
1378 if (fclose(g2c_file[g2cid].f))
1379 ret = G2C_EFILE;
1380
1381 /* Reset the file data. */
1382 if (!ret)
1383 {
1384 g2c_file[g2cid].path[0] = 0;
1385 g2c_file[g2cid].g2cid = 0;
1386 g2c_file[g2cid].num_messages = 0;
1387 g2c_file[g2cid].f = NULL;
1388 }
1389
1390 /* If using threading, unlock the mutex. */
1391 MUTEX_UNLOCK(m);
1392
1393 return ret;
1394}
int g2c_get_drs_template(int drs_template_num, int *maplen, int *map, int *needext)
Get DRS template information.
int g2c_open(const char *path, int mode, int *g2cid)
Open an existing GRIB2 file.
Definition g2cfile.c:1190
#define MIN(a, b)
Find a minimum.
Definition g2cfile.c:16
#define READ_BUF_SIZE
Default size of read-buffer.
Definition g2cfile.c:19
static int determine_dims(G2C_SECTION_INFO_T *sec)
Determine the dimension information from the section 3 metadata.
Definition g2cfile.c:415
static int read_msg_metadata(G2C_MESSAGE_INFO_T *msg)
Read the file to get metadata about a message.
Definition g2cfile.c:937
int g2c_rw_section6_metadata(FILE *f, int rw_flag, G2C_SECTION_INFO_T *sec)
Read or write the metadata from section 6 (Data Representation Section) of a GRIB2 message.
Definition g2cfile.c:745
int g2c_close(int g2cid)
Close a GRIB2 file, freeing resources.
Definition g2cfile.c:1356
G2C_FILE_INFO_T g2c_file[G2C_MAX_FILES+1]
Global file information.
Definition g2cfile.c:10
int add_msg(G2C_FILE_INFO_T *file, int msg_num, size_t bytes_to_msg, size_t bytes_in_msg, int read_file, G2C_MESSAGE_INFO_T **msg)
Add new message to linked list.
Definition g2cfile.c:1017
int g2c_get_msg(int g2cid, size_t skip_bytes, size_t max_bytes, size_t *bytes_to_msg, size_t *bytes_in_msg, unsigned char **cbuf)
Search a file for the next GRIB1 or GRIB2 message, and read it, allocating space in memory to hold th...
Definition g2cfile.c:291
int add_section(FILE *f, G2C_MESSAGE_INFO_T *msg, int sec_id, unsigned int sec_len, size_t bytes_to_sec, unsigned char sec_num)
Add metadata about a new section 3, 4, 5, 6, or 7.
Definition g2cfile.c:794
#define BYTES_TO_DISCIPLINE
Number of bytes to discipline field in GRIB2 message.
Definition g2cfile.c:22
int g2c_find_msg2(int g2cid, size_t skip_bytes, size_t max_bytes, size_t *bytes_to_msg, size_t *bytes_in_msg)
Search a file for the next GRIB1 or GRIB2 message.
Definition g2cfile.c:164
static int free_metadata(int g2cid)
Free resources holding the file metadata.
Definition g2cfile.c:1293
int g2c_rw_section5_metadata(FILE *f, int rw_flag, G2C_SECTION_INFO_T *sec)
Read or write the metadata from section 5 (Data Representation Section) of a GRIB2 message.
Definition g2cfile.c:663
static int read_metadata(int g2cid)
Read metadata from a GRIB2 file being opened with g2c_open().
Definition g2cfile.c:1079
int g2c_rw_section1_metadata(FILE *f, int rw_flag, G2C_MESSAGE_INFO_T *msg)
Read Section 1.
Definition g2cfile.c:874
int g2c_add_file(const char *path, int mode, int *g2cid)
Open a GRIB2 file and add it to the list of open files.
Definition g2cfile.c:1143
static int find_available_g2cid(int *g2cid)
Find a g2cid to use for a newly opened or created file.
Definition g2cfile.c:363
int g2c_seekmsg(int g2cid, size_t skip, size_t *offset, size_t *msglen)
Search a file for the next GRIB2 Message.
Definition g2cfile.c:56
int g2c_rw_section3_metadata(FILE *f, int rw_flag, G2C_SECTION_INFO_T *sec)
Read the metadata from section 3 (Grid Definition Section) of a GRIB2 message.
Definition g2cfile.c:478
int g2c_rw_section4_metadata(FILE *f, int rw_flag, G2C_SECTION_INFO_T *sec)
Read or write the metadata from section 4 (Product Definition Section) of a GRIB2 message.
Definition g2cfile.c:574
#define G2C_SEEKMSG_BUFSIZE
Size of buffer used in g2c_seekmsg().
Definition g2cfile.c:27
int g2c_next_g2cid
Next g2cid file ID - used when opening or creating a file.
Definition g2cfile.c:13
int g2c_file_io_ushort(FILE *f, int write, unsigned short *var)
Read or write a big-endian unsigned short to an open GRIB2 file, with conversion between native and b...
Definition g2cio.c:294
int g2c_file_io_template(FILE *f, int rw_flag, int map, long long int *template_value)
Read or write a big-endian 4-byte int or unsigned int from or to an open file, with conversion betwee...
Definition g2cio.c:408
int g2c_file_io_short(FILE *f, int write, short *var)
Read or write a big-endian signed short to an open GRIB2 file, with conversion between native and big...
Definition g2cio.c:273
int g2c_file_io_ubyte(FILE *f, int write, unsigned char *var)
Read or write a big-endian unsigned byte to an open GRIB2 file, with conversion between native and bi...
Definition g2cio.c:337
int g2c_file_io_uint(FILE *f, int write, unsigned int *var)
Read or write a big-endian 4-byte unsigned int to an open GRIB2 file, with conversion between native ...
Definition g2cio.c:251
int g2c_log_file(int g2cid)
Print a summary of the contents of an open GRIB2 file.
Definition g2cutil.c:189
#define G2C_EMSG
Error decoding GRIB message.
Definition grib2.h:486
#define G2C_MAX_FILES
Maximum number of open files.
Definition grib2.h:273
#define G2C_NOCLOBBER
Don't destroy existing file.
Definition grib2.h:278
#define G2C_ENOMSG
No GRIB message found.
Definition grib2.h:487
#define G2C_ENAMETOOLONG
Name too long.
Definition grib2.h:480
#define G2C_WRITE
Set read-write access for g2c_open().
Definition grib2.h:276
#define G2C_ENOSECTION
Cannot find section.
Definition grib2.h:491
#define G2C_EFILE
File I/O error.
Definition grib2.h:482
#define G2C_MAX_GDS_TEMPLATE_MAPLEN
Maximum grid template map length.
Definition grib2.h:293
#define G2C_ENOMEM
Out of memory.
Definition grib2.h:485
#define G2C_ERROR
General error code, returned for some test errors.
Definition grib2.h:477
#define G2C_MAX_NAME
Maximum length of a name.
Definition grib2.h:274
#define G2C_EINVAL
Invalid input.
Definition grib2.h:481
#define G2C_ETOOMANYFILES
Trying to open too many files.
Definition grib2.h:484
#define G2C_EBADSECTION
Invalid section number.
Definition grib2.h:494
#define G2C_MAX_PDS_TEMPLATE_MAPLEN
Maximum template map length.
Definition grib2.h:295
#define G2C_SECTION0_BYTES
Number of bytes in section 0.
Definition grib2.h:282
int64_t g2int
Long integer type.
Definition grib2.h:32
#define G2C_EBADID
Bad ID.
Definition grib2.h:483
#define G2C_NOERROR
No error.
Definition grib2.h:476
#define G2C_SECTION1_BYTES
Number of bytes in section 1 (not including reserved, optional data at the end of the section).
Definition grib2.h:286
Header file with internal function prototypes NCEPLIBS-g2c library.
#define G2C_FILE_READ
Read.
Definition grib2_int.h:131
struct g2c_section_info * next
Pointer to next in list.
Definition grib2_int.h:178
struct g2c_section_info * sec
List of section metadata.
Definition grib2_int.h:164
size_t len
Length of dimension.
Definition grib2_int.h:188
short subcenter
Originating subcenter.
Definition grib2_int.h:152
int sec_id
ID of the section (0-based).
Definition grib2_int.h:172
#define G2C_MAGIC_HEADER_LEN
Full length of magic header string (includes GRIB version byte).
Definition grib2_int.h:42
G2C_DIM_INFO_T dim[2]
Dimension information.
Definition grib2_int.h:203
unsigned char master_version
GRIB master tables version number.
Definition grib2_int.h:153
#define FOUR_BYTES
Four bytes.
Definition grib2_int.h:52
#define MUTEX_UNLOCK(m)
Pthreads not enabled, so do nothing.
Definition grib2_int.h:119
char path[G2C_MAX_NAME+1]
Path of the file.
Definition grib2_int.h:240
unsigned char type
Type of processed data in this GRIB message.
Definition grib2_int.h:163
unsigned short grid_def
Grid definition template number (= N) (See Table 3.1).
Definition grib2_int.h:201
unsigned char hour
Hour.
Definition grib2_int.h:159
#define G2C_MAGIC_HEADER
GRIB magic header string.
Definition grib2_int.h:39
unsigned char minute
Minute.
Definition grib2_int.h:160
unsigned int num_data_points
Number of data points.
Definition grib2_int.h:198
size_t num_messages
Number of messages in the file.
Definition grib2_int.h:242
unsigned short num_coord
Number of coordinate values after template.
Definition grib2_int.h:211
int num_local
Number of local sections in the message.
Definition grib2_int.h:143
unsigned char sig_ref_time
Significance of reference time.
Definition grib2_int.h:155
#define LATITUDE
Latitude.
Definition grib2_int.h:56
unsigned char num_opt
Number of octets for optional list of numbers defining number of points.
Definition grib2_int.h:199
unsigned char discipline
Discipline from section 0.
Definition grib2_int.h:140
int g2cid
ID of the file.
Definition grib2_int.h:239
char name[G2C_MAX_NAME+1]
Name of dimension.
Definition grib2_int.h:189
unsigned char interp_list
Interpetation of list of numbers defining number of points (See Table 3.11).
Definition grib2_int.h:200
size_t bytes_in_msg
Number of bytes in this message.
Definition grib2_int.h:139
struct g2c_section_info * prev
Pointer to previous in list.
Definition grib2_int.h:179
#define MUTEX(m)
Pthreads not enabled, so do nothing.
Definition grib2_int.h:110
int num_fields
Number of fields in the message.
Definition grib2_int.h:142
unsigned char sec_num
Section number.
Definition grib2_int.h:175
#define G2C_MIN_MAX_BYTES
Minimum acceptable value for max_bytes parameter of g2c_get_msg().
Definition grib2_int.h:36
unsigned int num_data_points
Number of data points where one or more values are specified in Section 7 when a bit map is present,...
Definition grib2_int.h:223
void * sec_info
Pointer to struct specific for section 3, 4, 5, 6, or 7.
Definition grib2_int.h:177
float * value
Array of dimension values.
Definition grib2_int.h:190
unsigned char indicator
Bit map indicator.
Definition grib2_int.h:233
unsigned int sec_len
Length of the section (in bytes).
Definition grib2_int.h:173
short year
Year.
Definition grib2_int.h:156
size_t bytes_to_sec
Number of bytes from start of message to this section.
Definition grib2_int.h:174
unsigned char status
Production Status of Processed data in the GRIB message.
Definition grib2_int.h:162
#define LONGITUDE
Longitude.
Definition grib2_int.h:59
G2C_MESSAGE_INFO_T * msg
Information about each message in the file.
Definition grib2_int.h:243
#define ONE_BYTE
One byte.
Definition grib2_int.h:50
#define LOG(e)
Ignore logging to stdout.
Definition grib2_int.h:428
unsigned char second
Second.
Definition grib2_int.h:161
unsigned char day
Day.
Definition grib2_int.h:158
FILE * f
FILE pointer to open file.
Definition grib2_int.h:241
unsigned char source_grid_def
Source of grid definition (See Table 3.0).
Definition grib2_int.h:197
int template_len
Number of entries in template.
Definition grib2_int.h:181
unsigned char local_version
Version number of GRIB local tables used to augment Master Tables.
Definition grib2_int.h:154
#define hton64(y)
Byte swap 64-bit ints.
Definition grib2_int.h:129
unsigned char month
Month.
Definition grib2_int.h:157
size_t msg_num
Number of message in file (0-based).
Definition grib2_int.h:137
unsigned short data_def
Data representation template number (See Table 5.0).
Definition grib2_int.h:224
size_t bytes_to_msg
Number of bytes to skip in the file, to get to this message.
Definition grib2_int.h:138
#define MUTEX_LOCK(m)
Pthreads not enabled, so do nothing.
Definition grib2_int.h:116
long long int * template
Grid, product, or data template.
Definition grib2_int.h:180
int sec1_len
Length of section 1.
Definition grib2_int.h:150
struct g2c_message_info * next
Pointer to next in list.
Definition grib2_int.h:166
G2C_MESSAGE_INFO_T * msg
Pointer to contianing message.
Definition grib2_int.h:176
short center
Originating center.
Definition grib2_int.h:151
struct g2c_file_info * file
Pointer to containing file.
Definition grib2_int.h:165
unsigned short prod_def
Product definition template number (See Table 4.0).
Definition grib2_int.h:212
Keep information about dimensions defined in section 3.
Definition grib2_int.h:186
This is the information about each open file.
Definition grib2_int.h:238
This is the information about each message.
Definition grib2_int.h:136
Information about Section 3 GRID DEFINITION SECTION.
Definition grib2_int.h:196
Information about Section 4 PRODUCT DEFINITION SECTION.
Definition grib2_int.h:209
Information about Section 5 DATA REPRESENTATION SECTION.
Definition grib2_int.h:219
Information about Section 6 BIT-MAP SECTION.
Definition grib2_int.h:230
Information about a section 3 through 7 in a GRIB2 message.
Definition grib2_int.h:171
int g2c_get_grid_template(int grid_template_num, int *maplen, int *map, int *needext)
Get grid template information.
int g2c_get_pds_template(int pds_template_num, int *maplen, int *map, int *needext)
Get PDS template information.
void seekgb(FILE *lugb, g2int iseek, g2int mseek, g2int *lskip, g2int *lgrib)
Search a file for the next GRIB Message.
Definition seekgb.c:46