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