NetCDF  4.3.2
 All Data Structures Files Functions Variables Typedefs Macros Modules Pages
ncdump.c
1 /*
2 
3 Copyright 2011 University Corporation for Atmospheric
4 Research/Unidata. See \ref copyright file for more info. */
5 
6 #include <config.h>
7 #include <stdio.h>
8 #ifdef HAVE_GETOPT_H
9 #include <getopt.h>
10 #endif
11 #ifndef _WIN32
12 #include <unistd.h>
13 #endif
14 
15 #ifdef _MSC_VER
16 #define snprintf _snprintf
17 #include "XGetopt.h"
18 int opterr;
19 int optind;
20 #endif
21 
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <assert.h>
26 #include <math.h>
27 #ifdef HAVE_LOCALE_H
28 #include <locale.h>
29 #endif /* HAVE_LOCALE_H */
30 #include <netcdf.h>
31 #include "utils.h"
32 #include "nccomps.h"
33 #include "nctime0.h" /* new iso time and calendar stuff */
34 #include "dumplib.h"
35 #include "ncdump.h"
36 #include "vardata.h"
37 #include "indent.h"
38 #include "isnan.h"
39 #include "cdl.h"
40 
41 #define int64_t long long
42 #define uint64_t unsigned long long
43 
44 /* globals */
45 char *progname;
46 fspec_t formatting_specs = /* defaults, overridden by command-line options */
47 {
48  0, /* construct netcdf name from file name */
49  false, /* print header info only, no data? */
50  false, /* just print coord vars? */
51  false, /* brief comments in data section? */
52  false, /* full annotations in data section? */
53  false, /* human-readable output for date-time values? */
54  false, /* use 'T' separator between date and time values as strings? */
55  false, /* output special attributes, eg chunking? */
56  LANG_C, /* language conventions for indices */
57  false, /* for DAP URLs, client-side cache used */
58  0, /* if -v specified, number of variables in list */
59  0, /* if -v specified, list of variable names */
60  0, /* if -g specified, number of groups names in list */
61  0, /* if -g specified, list of group names */
62  0, /* if -g specified, list of matching grpids */
63  0 /* kind of netCDF file */
64 };
65 
66 static void
67 usage(void)
68 {
69 #define USAGE "\
70  [-c] Coordinate variable data and header information\n\
71  [-h] Header information only, no data\n\
72  [-v var1[,...]] Data for variable(s) <var1>,... only\n\
73  [-b [c|f]] Brief annotations for C or Fortran indices in data\n\
74  [-f [c|f]] Full annotations for C or Fortran indices in data\n\
75  [-l len] Line length maximum in data section (default 80)\n\
76  [-n name] Name for netCDF (default derived from file name)\n\
77  [-p n[,n]] Display floating-point values with less precision\n\
78  [-k] Output kind of netCDF file\n\
79  [-s] Output special (virtual) attributes\n\
80  [-t] Output time data as date-time strings\n\
81  [-i] Output time data as date-time strings with ISO-8601 'T' separator\n\
82  [-g grp1[,...]] Data and metadata for group(s) <grp1>,... only\n\
83  [-w] With client-side caching of variables for DAP URLs\n\
84  [-x] Output XML (NcML) instead of CDL\n\
85  file Name of netCDF file (or URL if DAP access enabled)\n"
86 
87  (void) fprintf(stderr,
88  "%s [-c|-h] [-v ...] [[-b|-f] [c|f]] [-l len] [-n name] [-p n[,n]] [-k] [-x] [-s] [-t|-i] [-g ...] [-w] file\n%s",
89  progname,
90  USAGE);
91 
92  (void) fprintf(stderr,
93  "netcdf library version %s\n",
94  nc_inq_libvers());
95 }
96 
97 
98 /*
99  * convert pathname of netcdf file into name for cdl unit, by taking
100  * last component of path and stripping off any extension.
101  * DMH: add code to handle OPeNDAP url.
102  * DMH: I think this also works for UTF8.
103  */
104 static char *
105 name_path(const char *path)
106 {
107  const char *cp;
108  char *new;
109  char *sp;
110 
111 #ifdef vms
112 #define FILE_DELIMITER ']'
113 #endif
114 #if defined(WIN32) || defined(msdos)
115 #define FILE_DELIMITER '\\'
116 #endif
117 #ifndef FILE_DELIMITER /* default to unix */
118 #define FILE_DELIMITER '/'
119 #endif
120 
121 #ifdef USE_DAP
122  /* See if this is a url */
123  {
124  char* base;
125 
126  extern int nc__testurl(const char*,char**);
127 
128 
129  if(nc__testurl(path,&base)) {
130  return base; /* Looks like a url */
131  }
132  /* else fall thru and treat like a file path */
133  }
134 #endif /*USE_DAP*/
135 
136  cp = strrchr(path, FILE_DELIMITER);
137  if (cp == 0) /* no delimiter */
138  cp = path;
139  else /* skip delimeter */
140  cp++;
141  new = (char *) emalloc((unsigned) (strlen(cp)+1));
142  (void) strncpy(new, cp, strlen(cp) + 1); /* copy last component of path */
143  if ((sp = strrchr(new, '.')) != NULL)
144  *sp = '\0'; /* strip off any extension */
145  return new;
146 }
147 
148 /* Return primitive type name */
149 static const char *
150 prim_type_name(nc_type type)
151 {
152  switch (type) {
153  case NC_BYTE:
154  return "byte";
155  case NC_CHAR:
156  return "char";
157  case NC_SHORT:
158  return "short";
159  case NC_INT:
160  return "int";
161  case NC_FLOAT:
162  return "float";
163  case NC_DOUBLE:
164  return "double";
165 #ifdef USE_NETCDF4
166  case NC_UBYTE:
167  return "ubyte";
168  case NC_USHORT:
169  return "ushort";
170  case NC_UINT:
171  return "uint";
172  case NC_INT64:
173  return "int64";
174  case NC_UINT64:
175  return "uint64";
176  case NC_STRING:
177  return "string";
178  case NC_VLEN:
179  return "vlen";
180  case NC_OPAQUE:
181  return "opaque";
182  case NC_COMPOUND:
183  return "compound";
184 #endif /* USE_NETCDF4 */
185  default:
186  error("prim_type_name: bad type %d", type);
187  return "bogus";
188  }
189 }
190 
191 
192 /*
193  * Remove trailing zeros (after decimal point) but not trailing decimal
194  * point from ss, a string representation of a floating-point number that
195  * might include an exponent part.
196  */
197 static void
198 tztrim(char *ss)
199 {
200  char *cp, *ep;
201 
202  cp = ss;
203  if (*cp == '-')
204  cp++;
205  while(isdigit((int)*cp) || *cp == '.')
206  cp++;
207  if (*--cp == '.')
208  return;
209  ep = cp+1;
210  while (*cp == '0')
211  cp--;
212  cp++;
213  if (cp == ep)
214  return;
215  while (*ep)
216  *cp++ = *ep++;
217  *cp = '\0';
218  return;
219 }
220 
221 
222 /* Return file type string */
223 static const char *
224 kind_string(int kind)
225 {
226  switch (kind) {
227  case NC_FORMAT_CLASSIC:
228  return "classic";
229  case NC_FORMAT_64BIT:
230  return "64-bit offset";
231  case NC_FORMAT_NETCDF4:
232  return "netCDF-4";
234  return "netCDF-4 classic model";
235  default:
236  error("unrecognized file format: %d");
237  return "unrecognized";
238  }
239 }
240 
241 
242 /* Return extended format string */
243 static const char *
244 kind_string_extended(int kind, int mode)
245 {
246  static char text[1024];
247  switch (kind) {
248  case NC_FORMAT_NC3:
249  if(mode & NC_64BIT_OFFSET)
250  snprintf(text,sizeof(text),"%s mode=%08x", "64-bit offset",mode);
251  else
252  snprintf(text,sizeof(text),"%s mode=%08x", "classic",mode);
253  break;
254  case NC_FORMAT_NC_HDF5:
255  snprintf(text,sizeof(text),"%s mode=%08x", "HDF5",mode);
256  break;
257  case NC_FORMAT_NC_HDF4:
258  snprintf(text,sizeof(text),"%s mode=%08x", "HDF4",mode);
259  break;
260  case NC_FORMAT_PNETCDF:
261  snprintf(text,sizeof(text),"%s mode=%08x", "PNETCDF",mode);
262  break;
263  case NC_FORMAT_DAP2:
264  snprintf(text,sizeof(text),"%s mode=%08x", "DAP2",mode);
265  break;
266  case NC_FORMAT_DAP4:
267  snprintf(text,sizeof(text),"%s mode=%08x", "DAP4",mode);
268  break;
269  case NC_FORMAT_UNDEFINED:
270  snprintf(text,sizeof(text),"%s mode=%08x", "unknown",mode);
271  break;
272  default:
273  error("unrecognized extended format: %d",kind);
274  snprintf(text,sizeof(text),"%s mode=%08x", "unrecognized",mode);
275  break;
276  }
277  return text;
278 }
279 
280 
281 /*
282  * Emit initial line of output for NcML
283  */
284 static void
285 pr_initx(int ncid, const char *path)
286 {
287  printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<netcdf xmlns=\"http://www.unidata.ucar.edu/namespaces/netcdf/ncml-2.2\" location=\"%s\">\n",
288  path);
289 }
290 
291 
292 /*
293  * Print attribute string, for text attributes.
294  */
295 static void
296 pr_att_string(
297  int kind,
298  size_t len,
299  const char *string
300  )
301 {
302  int iel;
303  const char *cp;
304  const char *sp;
305  unsigned char uc;
306 
307  cp = string;
308  printf ("\"");
309  /* adjust len so trailing nulls don't get printed */
310  sp = cp + len - 1;
311  while (len != 0 && *sp-- == '\0')
312  len--;
313  for (iel = 0; iel < len; iel++)
314  switch (uc = *cp++ & 0377) {
315  case '\b':
316  printf ("\\b");
317  break;
318  case '\f':
319  printf ("\\f");
320  break;
321  case '\n':
322  /* Only generate linebreaks after embedded newlines for
323  * classic, 64-bit offset, or classic model files. For
324  * netCDF-4 files, don't generate linebreaks, because that
325  * would create an extra string in a list of strings. */
326  if (kind != NC_FORMAT_NETCDF4) {
327  printf ("\\n\",\n\t\t\t\"");
328  } else {
329  printf("\\n");
330  }
331  break;
332  case '\r':
333  printf ("\\r");
334  break;
335  case '\t':
336  printf ("\\t");
337  break;
338  case '\v':
339  printf ("\\v");
340  break;
341  case '\\':
342  printf ("\\\\");
343  break;
344  case '\'':
345  printf ("\\\'");
346  break;
347  case '\"':
348  printf ("\\\"");
349  break;
350  default:
351  if (iscntrl(uc))
352  printf ("\\%03o",uc);
353  else
354  printf ("%c",uc);
355  break;
356  }
357  printf ("\"");
358 
359 }
360 
361 
362 /*
363  * Print NcML attribute string, for text attributes.
364  */
365 static void
366 pr_attx_string(
367  size_t len,
368  const char *string
369  )
370 {
371  int iel;
372  const char *cp;
373  const char *sp;
374  unsigned char uc;
375 
376  cp = string;
377  printf ("\"");
378  /* adjust len so trailing nulls don't get printed */
379  sp = cp + len - 1;
380  while (len != 0 && *sp-- == '\0')
381  len--;
382  for (iel = 0; iel < len; iel++)
383  switch (uc = *cp++ & 0377) {
384  case '\"':
385  printf ("&quot;");
386  break;
387  case '<':
388  printf ("&lt;");
389  break;
390  case '>':
391  printf ("&gt;");
392  break;
393  case '&':
394  printf ("&amp;");
395  break;
396  case '\n':
397  printf ("&#xA;");
398  break;
399  case '\r':
400  printf ("&#xD;");
401  break;
402  case '\t':
403  printf ("&#x9;");
404  break;
405  default:
406  if (iscntrl(uc))
407  printf ("&#%d;",uc);
408  else
409  printf ("%c",uc);
410  break;
411  }
412  printf ("\"");
413 
414 }
415 
416 
417 /*
418  * Print list of attribute values, for attributes of primitive types.
419  * Attribute values must be printed with explicit type tags for
420  * netCDF-3 primitive types, because CDL doesn't require explicit
421  * syntax to declare such attribute types.
422  */
423 static void
424 pr_att_valgs(
425  int kind,
426  nc_type type,
427  size_t len,
428  const void *vals
429  )
430 {
431  int iel;
432  signed char sc;
433  short ss;
434  int ii;
435  char gps[PRIM_LEN];
436  float ff;
437  double dd;
438 #ifdef USE_NETCDF4
439  unsigned char uc;
440  unsigned short us;
441  unsigned int ui;
442  int64_t i64;
443  uint64_t ui64;
444  char *stringp;
445 #endif /* USE_NETCDF4 */
446  char *delim = ", "; /* delimiter between output values */
447 
448  if (type == NC_CHAR) {
449  char *cp = (char *) vals;
450  pr_att_string(kind, len, cp);
451  return;
452  }
453  /* else */
454  for (iel = 0; iel < len; iel++) {
455  if (iel == len - 1)
456  delim = "";
457  switch (type) {
458  case NC_BYTE:
459  sc = ((signed char *) vals)[iel];
460  printf ("%db%s", sc, delim);
461  break;
462  case NC_SHORT:
463  ss = ((short *) vals)[iel];
464  printf ("%ds%s", ss, delim);
465  break;
466  case NC_INT:
467  ii = ((int *) vals)[iel];
468  printf ("%d%s", ii, delim);
469  break;
470  case NC_FLOAT:
471  ff = ((float *) vals)[iel];
472  if(isfinite(ff)) {
473  int res;
474  res = snprintf(gps, PRIM_LEN, float_att_fmt, ff);
475  assert(res < PRIM_LEN);
476  tztrim(gps); /* trim trailing 0's after '.' */
477  printf ("%s%s", gps, delim);
478  } else {
479  if(isnan(ff)) {
480  printf("NaNf%s", delim);
481  } else if(isinf(ff)) {
482  if(ff < 0.0f) {
483  printf("-");
484  }
485  printf("Infinityf%s", delim);
486  }
487  }
488  break;
489  case NC_DOUBLE:
490  dd = ((double *) vals)[iel];
491  if(isfinite(dd)) {
492  int res;
493  res = snprintf(gps, PRIM_LEN, double_att_fmt, dd);
494  assert(res < PRIM_LEN);
495  tztrim(gps);
496  printf ("%s%s", gps, delim);
497  } else {
498  if(isnan(dd)) {
499  printf("NaN%s", delim);
500  } else if(isinf(dd)) {
501  if(dd < 0.0) {
502  printf("-");
503  }
504  printf("Infinity%s", delim);
505  }
506  }
507  break;
508 #ifdef USE_NETCDF4
509  case NC_UBYTE:
510  uc = ((unsigned char *) vals)[iel];
511  printf ("%uUB%s", uc, delim);
512  break;
513  case NC_USHORT:
514  us = ((unsigned short *) vals)[iel];
515  printf ("%huUS%s", us, delim);
516  break;
517  case NC_UINT:
518  ui = ((unsigned int *) vals)[iel];
519  printf ("%uU%s", ui, delim);
520  break;
521  case NC_INT64:
522  i64 = ((int64_t *) vals)[iel];
523  printf ("%lldL%s", i64, delim);
524  break;
525  case NC_UINT64:
526  ui64 = ((uint64_t *) vals)[iel];
527  printf ("%lluUL%s", ui64, delim);
528  break;
529  case NC_STRING:
530  stringp = ((char **) vals)[iel];
531  if(stringp)
532  pr_att_string(kind, strlen(stringp), stringp);
533  else
534  printf("NIL");
535  printf("%s", delim);
536  break;
537 #endif /* USE_NETCDF4 */
538  default:
539  error("pr_att_vals: bad type");
540  }
541  }
542 }
543 
544 
545 /*
546  * Print list of numeric attribute values to string for use in NcML output.
547  * Unlike CDL, NcML makes type explicit, so don't need type suffixes.
548  */
549 static void
550 pr_att_valsx(
551  nc_type type,
552  size_t len,
553  const double *vals,
554  char *attvals, /* returned string */
555  size_t attvalslen /* size of attvals buffer, assumed
556  large enough to hold all len
557  blank-separated values */
558  )
559 {
560  int iel;
561  float ff;
562  double dd;
563  int ii;
564 #ifdef USE_NETCDF4
565  unsigned int ui;
566  int64_t i64;
567  uint64_t ui64;
568 #endif /* USE_NETCDF4 */
569 
570  attvals[0]='\0';
571  if (len == 0)
572  return;
573  for (iel = 0; iel < len; iel++) {
574  char gps[PRIM_LEN];
575  int res;
576  switch (type) {
577  case NC_BYTE:
578  case NC_SHORT:
579  case NC_INT:
580  ii = vals[iel];
581  res = snprintf(gps, PRIM_LEN, "%d", ii);
582  assert(res < PRIM_LEN);
583  (void) strlcat(attvals, gps, attvalslen);
584  (void) strlcat(attvals, iel < len-1 ? " " : "", attvalslen);
585  break;
586 #ifdef USE_NETCDF4
587  case NC_UBYTE:
588  case NC_USHORT:
589  case NC_UINT:
590  ui = vals[iel];
591  res = snprintf(gps, PRIM_LEN, "%u", ui);
592  assert(res < PRIM_LEN);
593  (void) strlcat(attvals, gps, attvalslen);
594  (void) strlcat(attvals, iel < len-1 ? " " : "", attvalslen);
595  break;
596  case NC_INT64:
597  i64 = vals[iel];
598  res = snprintf(gps, PRIM_LEN, "%lld", i64);
599  assert(res < PRIM_LEN);
600  (void) strlcat(attvals, gps, attvalslen);
601  (void) strlcat(attvals, iel < len-1 ? " " : "", attvalslen);
602  break;
603  case NC_UINT64:
604  ui64 = vals[iel];
605  res = snprintf(gps, PRIM_LEN, "%llu", ui64);
606  assert(res < PRIM_LEN);
607  (void) strlcat(attvals, gps, attvalslen);
608  (void) strlcat(attvals, iel < len-1 ? " " : "", attvalslen);
609  break;
610 #endif /* USE_NETCDF4 */
611  case NC_FLOAT:
612  ff = vals[iel];
613  res = snprintf(gps, PRIM_LEN, float_attx_fmt, ff);
614  assert(res < PRIM_LEN);
615  tztrim(gps); /* trim trailing 0's after '.' */
616  (void) strlcat(attvals, gps, attvalslen);
617  (void) strlcat(attvals, iel < len-1 ? " " : "", attvalslen);
618  break;
619  case NC_DOUBLE:
620  dd = vals[iel];
621  res = snprintf(gps, PRIM_LEN, double_att_fmt, dd);
622  assert(res < PRIM_LEN);
623  tztrim(gps); /* trim trailing 0's after '.' */
624  (void) strlcat(attvals, gps, attvalslen);
625  (void) strlcat(attvals, iel < len-1 ? " " : "", attvalslen);
626  break;
627  default:
628  error("pr_att_valsx: bad type");
629  }
630  }
631 }
632 
633 /*
634  * Print a variable attribute
635  */
636 static void
637 pr_att(
638  int ncid,
639  int kind,
640  int varid,
641  const char *varname,
642  int ia
643  )
644 {
645  ncatt_t att; /* attribute */
646 
647  NC_CHECK( nc_inq_attname(ncid, varid, ia, att.name) );
648  NC_CHECK( nc_inq_att(ncid, varid, att.name, &att.type, &att.len) );
649  att.tinfo = get_typeinfo(att.type);
650 
651  indent_out();
652  printf ("\t\t");
653 #ifdef USE_NETCDF4
654  if (is_user_defined_type(att.type) || att.type == NC_STRING)
655 #else
656  if (is_user_defined_type(att.type))
657 #endif
658  {
659  /* TODO: omit next two lines if att_type_name not needed
660  * because print_type_name() looks it up */
661  char att_type_name[NC_MAX_NAME + 1];
662  get_type_name(ncid, att.type, att_type_name);
663 
664  /* printf ("\t\t%s ", att_type_name); */
665  /* ... but handle special characters in CDL names with escapes */
666  print_type_name(ncid, att.type);
667  printf(" ");
668  }
669  /* printf ("\t\t%s:%s = ", varname, att.name); */
670  print_name(varname);
671  printf(":");
672  print_name(att.name);
673  printf(" = ");
674 
675  if (att.len == 0) { /* show 0-length attributes as empty strings */
676  att.type = NC_CHAR;
677  }
678 
679  if (! is_user_defined_type(att.type) ) {
680  att.valgp = (void *) emalloc((att.len + 1) * att.tinfo->size );
681  NC_CHECK( nc_get_att(ncid, varid, att.name, att.valgp ) );
682  if(att.type == NC_CHAR) /* null-terminate retrieved text att value */
683  ((char *)att.valgp)[att.len] = '\0';
684 /* (1) Print normal list of attribute values. */
685  pr_att_valgs(kind, att.type, att.len, att.valgp);
686  printf (" ;"); /* terminator for normal list */
687 /* (2) If -t option, add list of date/time strings as CDL comments. */
688  if(formatting_specs.string_times) {
689  /* Prints text after semicolon and before final newline.
690  * Prints nothing if not qualified for time interpretation.
691  * Will include line breaks for longer lists. */
692  print_att_times(ncid, varid, &att);
693  if(is_bounds_att(&att)) {
694  insert_bounds_info(ncid, varid, &att);
695  }
696  }
697 #ifdef USE_NETCDF4
698  /* If NC_STRING, need to free all the strings also */
699  if(att.type == NC_STRING) {
700  nc_free_string(att.len, att.valgp);
701  }
702 #endif /* USE_NETCDF4 */
703  free(att.valgp);
704  }
705 #ifdef USE_NETCDF4
706  else /* User-defined type. */
707  {
708  char type_name[NC_MAX_NAME + 1];
709  size_t type_size, nfields;
710  nc_type base_nc_type;
711  int class, i;
712  void *data;
713 
714  NC_CHECK( nc_inq_user_type(ncid, att.type, type_name, &type_size,
715  &base_nc_type, &nfields, &class));
716  switch(class)
717  {
718  case NC_VLEN:
719  /* because size returned for vlen is base type size, but we
720  * need space to read array of vlen structs into ... */
721  data = emalloc((att.len + 1) * sizeof(nc_vlen_t));
722  break;
723  case NC_OPAQUE:
724  data = emalloc((att.len + 1) * type_size);
725  break;
726  case NC_ENUM:
727  /* a long long is ample for all base types */
728  data = emalloc((att.len + 1) * sizeof(int64_t));
729  break;
730  case NC_COMPOUND:
731  data = emalloc((att.len + 1) * type_size);
732  break;
733  default:
734  error("unrecognized class of user defined type: %d", class);
735  }
736 
737  NC_CHECK( nc_get_att(ncid, varid, att.name, data));
738 
739  switch(class) {
740  case NC_VLEN:
741  pr_any_att_vals(&att, data);
742  free(data);
743  break;
744  case NC_OPAQUE: {
745  char *sout = emalloc(2 * type_size + strlen("0X") + 1);
746  unsigned char *cp = data;
747  for (i = 0; i < att.len; i++) {
748  (void) ncopaque_val_as_hex(type_size, sout, cp);
749  printf("%s%s", sout, i < att.len-1 ? ", " : "");
750  cp += type_size;
751  }
752  free(sout);
753  }
754  break;
755  case NC_ENUM: {
756  int64_t value;
757  for (i = 0; i < att.len; i++) {
758  char enum_name[NC_MAX_NAME + 1];
759  switch(base_nc_type)
760  {
761  case NC_BYTE:
762  value = *((char *)data + i);
763  break;
764  case NC_UBYTE:
765  value = *((unsigned char *)data + i);
766  break;
767  case NC_SHORT:
768  value = *((short *)data + i);
769  break;
770  case NC_USHORT:
771  value = *((unsigned short *)data + i);
772  break;
773  case NC_INT:
774  value = *((int *)data + i);
775  break;
776  case NC_UINT:
777  value = *((unsigned int *)data + i);
778  break;
779  case NC_INT64:
780  value = *((int64_t *)data + i);
781  break;
782  case NC_UINT64:
783  value = *((uint64_t *)data + i);
784  break;
785  default:
786  error("enum must have an integer base type: %d", base_nc_type);
787  }
788  NC_CHECK( nc_inq_enum_ident(ncid, att.type, value,
789  enum_name));
790 /* printf("%s%s", enum_name, i < att.len-1 ? ", " : ""); */
791  print_name(enum_name);
792  printf("%s", i < att.len-1 ? ", " : "");
793  }
794  }
795  break;
796  case NC_COMPOUND:
797  pr_any_att_vals(&att, data);
798  free(data);
799  break;
800  default:
801  error("unrecognized class of user defined type: %d", class);
802  }
803  printf (" ;"); /* terminator for user defined types */
804  }
805 #endif /* USE_NETCDF4 */
806 
807  printf ("\n"); /* final newline for all attribute types */
808 }
809 
810 /* Common code for printing attribute name */
811 static void
812 pr_att_name(
813  int ncid,
814  const char *varname,
815  const char *attname
816  )
817 {
818  indent_out();
819  printf ("\t\t");
820  print_name(varname);
821  printf(":");
822  print_name(attname);
823 }
824 
825 /*
826  * Print special _Format global attribute, a virtual attribute not
827  * actually stored in the file.
828  */
829 static void
830 pr_att_global_format(
831  int ncid,
832  int kind
833  )
834 {
835  pr_att_name(ncid, "", NC_ATT_FORMAT);
836  printf(" = ");
837  printf("\"%s\"", kind_string(kind));
838  printf (" ;\n");
839 }
840 
841 
842 #ifdef USE_NETCDF4
843 /*
844  * Print special reserved variable attributes, such as _Chunking,
845  * _DeflateLevel, ... These are virtual, not real, attributes
846  * generated from the result of inquire calls. They are of primitive
847  * type to fit into the classic model. Currently, these only exist
848  * for netCDF-4 data.
849  */
850 static void
851 pr_att_specials(
852  int ncid,
853  int kind,
854  int varid,
855  const ncvar_t *varp
856  )
857 {
858  /* No special variable attributes for classic or 64-bit offset data */
859  if(kind == 1 || kind == 2)
860  return;
861  /* _Chunking */
862  if (varp->ndims > 0) { /* no chunking for scalar variables */
863  int contig = 0;
864  NC_CHECK( nc_inq_var_chunking(ncid, varid, &contig, NULL ) );
865  if(contig == 1) {
866  pr_att_name(ncid, varp->name, NC_ATT_STORAGE);
867  printf(" = \"contiguous\" ;\n");
868  } else {
869  size_t *chunkp;
870  int i;
871  pr_att_name(ncid, varp->name, NC_ATT_STORAGE);
872  printf(" = \"chunked\" ;\n");
873  chunkp = (size_t *) emalloc(sizeof(size_t) * (varp->ndims + 1) );
874  NC_CHECK( nc_inq_var_chunking(ncid, varid, NULL, chunkp) );
875  /* print chunking, even if it is default */
876  pr_att_name(ncid, varp->name, NC_ATT_CHUNKING);
877  printf(" = ");
878  for(i = 0; i < varp->ndims; i++) {
879  printf("%lu%s", (unsigned long)chunkp[i], i+1 < varp->ndims ? ", " : " ;\n");
880  }
881  free(chunkp);
882  }
883  }
884 
885  /*_Deflate, _Shuffle */
886  {
887  int shuffle=NC_NOSHUFFLE, deflate=0, deflate_level=0;
888  NC_CHECK( nc_inq_var_deflate(ncid, varid, &shuffle,
889  &deflate, &deflate_level) );
890  if(deflate != 0) {
891  pr_att_name(ncid, varp->name, NC_ATT_DEFLATE);
892  printf(" = %d ;\n", deflate_level);
893  }
894  if(shuffle != NC_NOSHUFFLE) {
895  pr_att_name(ncid, varp->name, NC_ATT_SHUFFLE);
896  printf(" = \"true\" ;\n");
897  }
898  }
899  /* _Checksum */
900  {
901  int fletcher32 = 0;
902  NC_CHECK( nc_inq_var_fletcher32(ncid, varid, &fletcher32) );
903  if(fletcher32 != 0) {
904  pr_att_name(ncid, varp->name, NC_ATT_CHECKSUM);
905  printf(" = \"true\" ;\n");
906  }
907  }
908  /* _Endianness */
909  if(varp->tinfo->size > 1) /* Endianness is meaningless for 1-byte types */
910  {
911  int endianness = 0;
912  NC_CHECK( nc_inq_var_endian(ncid, varid, &endianness) );
913  if (endianness != NC_ENDIAN_NATIVE) { /* NC_ENDIAN_NATIVE is the default */
914  pr_att_name(ncid, varp->name, NC_ATT_ENDIANNESS);
915  printf(" = ");
916  switch (endianness) {
917  case NC_ENDIAN_LITTLE:
918  printf("\"little\"");
919  break;
920  case NC_ENDIAN_BIG:
921  printf("\"big\"");
922  break;
923  default:
924  error("pr_att_specials: bad endianness: %d", endianness);
925  break;
926  }
927  printf(" ;\n");
928  }
929  }
930  {
931  int no_fill = 0;
932  /* Don't get the fill_value, it's set explicitly with
933  * _FillValue attribute, because nc_def_var_fill() creates a
934  * _FillValue attribute, if needed, and it's value gets
935  * displayed elsewhere as a normal (not special virtual)
936  * attribute. */
937  NC_CHECK( nc_inq_var_fill(ncid, varid, &no_fill, NULL) );
938  if(no_fill != 0) {
939  pr_att_name(ncid, varp->name, NC_ATT_NOFILL);
940  printf(" = \"true\" ;\n");
941  }
942  }
943  /* TODO: handle _Nbit when inquire function is available */
944 
945  /* TODO: handle _ScaleOffset when inquire is available */
946 
947  /* TODO: handle _Szip when szip inquire function is available */
948 }
949 #endif /* USE_NETCDF4 */
950 
951 
952 /*
953  * Print a variable attribute for NcML
954  */
955 static void
956 pr_attx(
957  int ncid,
958  int varid,
959  int ia
960  )
961 {
962  ncatt_t att; /* attribute */
963  char *attvals = NULL;
964  int attvalslen = 0;
965 
966  NC_CHECK( nc_inq_attname(ncid, varid, ia, att.name) );
967  NC_CHECK( nc_inq_att(ncid, varid, att.name, &att.type, &att.len) );
968 
969  /* Put attribute values into a single string, with blanks in between */
970 
971  switch (att.type) {
972  case NC_CHAR:
973  attvals = (char *) emalloc(att.len + 1);
974  attvalslen = att.len;
975  attvals[att.len] = '\0';
976  NC_CHECK( nc_get_att_text(ncid, varid, att.name, attvals ) );
977  break;
978 #ifdef USE_NETCDF4
979  case NC_STRING:
980  /* TODO: this only prints first string value, need to handle
981  multiple strings? */
982  attvals = (char *) emalloc(att.len + 1);
983  attvals[att.len] = '\0';
984  NC_CHECK( nc_get_att_text(ncid, varid, att.name, attvals ) );
985  break;
986  case NC_VLEN:
987  /* TODO */
988  break;
989  case NC_OPAQUE:
990  /* TODO */
991  break;
992  case NC_COMPOUND:
993  /* TODO */
994  break;
995 #endif /* USE_NETCDF4 */
996  default:
997  att.vals = (double *) emalloc((att.len + 1) * sizeof(double));
998  NC_CHECK( nc_get_att_double(ncid, varid, att.name, att.vals ) );
999  attvalslen = 20*att.len; /* max 20 chars for each value and blank separator */
1000  attvals = (char *) emalloc(attvalslen + 1);
1001  pr_att_valsx(att.type, att.len, att.vals, attvals, attvalslen);
1002  free(att.vals);
1003  break;
1004  }
1005 
1006  /* Don't output type for string attributes, since that's default type */
1007  if(att.type == NC_CHAR
1008 #ifdef USE_NETCDF4
1009  || att.type == NC_CHAR
1010 #endif /* USE_NETCDF4 */
1011  ) {
1012  /* TODO: XML-ish escapes for special chars in names */
1013  printf ("%s <attribute name=\"%s\" value=",
1014  varid != NC_GLOBAL ? " " : "",
1015  att.name);
1016  /* print attvals as a string with XML escapes */
1017  pr_attx_string(attvalslen, attvals);
1018  } else { /* non-string attribute */
1019  char att_type_name[NC_MAX_NAME + 1];
1020  get_type_name(ncid, att.type, att_type_name);
1021  /* TODO: print full type name with group prefix, when needed */
1022  printf ("%s <attribute name=\"%s\" type=\"%s\" value=\"",
1023  varid != NC_GLOBAL ? " " : "",
1024  att.name,
1025  att_type_name);
1026  printf("%s\"",attvals);
1027  }
1028  printf (" />\n");
1029  if(attvals != NULL)
1030  free (attvals);
1031 }
1032 
1033 
1034 /* Print optional NcML attribute for a variable's shape */
1035 static void
1036 pr_shape(ncvar_t* varp, ncdim_t *dims)
1037 {
1038  char *shape;
1039  int shapelen = 0;
1040  int id;
1041 
1042  if (varp->ndims == 0)
1043  return;
1044  for (id = 0; id < varp->ndims; id++) {
1045  shapelen += strlen(dims[varp->dims[id]].name) + 1;
1046  }
1047  shape = (char *) emalloc(shapelen + 1);
1048  shape[0] = '\0';
1049  for (id = 0; id < varp->ndims; id++) {
1050  /* TODO: XML-ish escapes for special chars in dim names */
1051  strlcat(shape, dims[varp->dims[id]].name, shapelen);
1052  strlcat(shape, id < varp->ndims-1 ? " " : "", shapelen);
1053  }
1054  printf (" shape=\"%s\"", shape);
1055  free(shape);
1056 }
1057 
1058 #ifdef USE_NETCDF4
1059 
1060 
1061 /* Print an enum type declaration */
1062 static void
1063 print_enum_type(int ncid, nc_type typeid) {
1064  char type_name[NC_MAX_NAME + 1];
1065  size_t type_size;
1066  nc_type base_nc_type;
1067  size_t type_nfields;
1068  int type_class;
1069  char base_type_name[NC_MAX_NAME + 1];
1070  int f;
1071  int64_t memval;
1072  char memname[NC_MAX_NAME + 1];
1073  /* extra space for escapes, and punctuation */
1074 #define SAFE_BUF_LEN 4*NC_MAX_NAME+30
1075  char safe_buf[SAFE_BUF_LEN];
1076  char *delim;
1077  int64_t data; /* space for data of any primitive type */
1078  char *esc_btn;
1079  char *esc_tn;
1080  char *esc_mn;
1081  int res;
1082 
1083  NC_CHECK( nc_inq_user_type(ncid, typeid, type_name, &type_size, &base_nc_type,
1084  &type_nfields, &type_class) );
1085 
1086  get_type_name(ncid, base_nc_type, base_type_name);
1087  indent_out();
1088  esc_btn = escaped_name(base_type_name);
1089  esc_tn = escaped_name(type_name);
1090  res = snprintf(safe_buf, SAFE_BUF_LEN,"%s enum %s {", esc_btn, esc_tn);
1091  assert(res < SAFE_BUF_LEN);
1092  free(esc_btn);
1093  free(esc_tn);
1094  lput(safe_buf);
1095  delim = ", ";
1096  for (f = 0; f < type_nfields; f++) {
1097  if (f == type_nfields - 1)
1098  delim = "} ;\n";
1099  NC_CHECK( nc_inq_enum_member(ncid, typeid, f, memname, &data) );
1100  switch (base_nc_type) {
1101  case NC_BYTE:
1102  memval = *(char *)&data;
1103  break;
1104  case NC_SHORT:
1105  memval = *(short *)&data;
1106  break;
1107  case NC_INT:
1108  memval = *(int *)&data;
1109  break;
1110 #ifdef USE_NETCDF4
1111  case NC_UBYTE:
1112  memval = *(unsigned char *)&data;
1113  break;
1114  case NC_USHORT:
1115  memval = *(unsigned short *)&data;
1116  break;
1117  case NC_UINT:
1118  memval = *(unsigned int *)&data;
1119  break;
1120  case NC_INT64:
1121  memval = *(int64_t *)&data;
1122  break;
1123  case NC_UINT64:
1124  memval = *(uint64_t *)&data;
1125  break;
1126 #endif /* USE_NETCDF4 */
1127  default:
1128  error("Bad base type for enum!");
1129  break;
1130  }
1131  esc_mn = escaped_name(memname);
1132  res = snprintf(safe_buf, SAFE_BUF_LEN, "%s = %lld%s", esc_mn,
1133  memval, delim);
1134  assert(res < SAFE_BUF_LEN);
1135  free(esc_mn);
1136  lput(safe_buf);
1137  }
1138 }
1139 
1140 
1141 /* Print a user-defined type declaration */
1142 static void
1143 print_ud_type(int ncid, nc_type typeid) {
1144 
1145  char type_name[NC_MAX_NAME + 1];
1146  char base_type_name[NC_MAX_NAME + 1];
1147  size_t type_nfields, type_size;
1148  nc_type base_nc_type;
1149  int f, type_class;
1150 
1151  NC_CHECK( nc_inq_user_type(ncid, typeid, type_name, &type_size, &base_nc_type,
1152  &type_nfields, &type_class) );
1153  switch(type_class) {
1154  case NC_VLEN:
1155  /* TODO: don't bother getting base_type_name if
1156  * print_type_name looks it up anyway */
1157  get_type_name(ncid, base_nc_type, base_type_name);
1158  indent_out();
1159 /* printf("%s(*) %s ;\n", base_type_name, type_name); */
1160  print_type_name(ncid, base_nc_type);
1161  printf("(*) ");
1162  print_type_name(ncid, typeid);
1163  printf(" ;\n");
1164  break;
1165  case NC_OPAQUE:
1166  indent_out();
1167 /* printf("opaque(%d) %s ;\n", (int)type_size, type_name); */
1168  printf("opaque(%d) ", (int)type_size);
1169  print_type_name(ncid, typeid);
1170  printf(" ;\n");
1171  break;
1172  case NC_ENUM:
1173  print_enum_type(ncid, typeid);
1174  break;
1175  case NC_COMPOUND:
1176  {
1177  char field_name[NC_MAX_NAME + 1];
1178  char field_type_name[NC_MAX_NAME + 1];
1179  size_t field_offset;
1180  nc_type field_type;
1181  int field_ndims;
1182  int d;
1183 
1184  indent_out();
1185 /* printf("compound %s {\n", type_name); */
1186  printf("compound ");
1187  print_type_name(ncid, typeid);
1188  printf(" {\n");
1189  for (f = 0; f < type_nfields; f++)
1190  {
1191  NC_CHECK( nc_inq_compound_field(ncid, typeid, f, field_name,
1192  &field_offset, &field_type,
1193  &field_ndims, NULL) );
1194  /* TODO: don't bother if field_type_name not needed here */
1195  get_type_name(ncid, field_type, field_type_name);
1196  indent_out();
1197 /* printf(" %s %s", field_type_name, field_name); */
1198  printf(" ");
1199  print_type_name(ncid, field_type);
1200  printf(" ");
1201  print_name(field_name);
1202  if (field_ndims > 0) {
1203  int *field_dim_sizes = (int *) emalloc((field_ndims + 1) * sizeof(int));
1204  NC_CHECK( nc_inq_compound_field(ncid, typeid, f, NULL,
1205  NULL, NULL, NULL,
1206  field_dim_sizes) );
1207  printf("(");
1208  for (d = 0; d < field_ndims-1; d++)
1209  printf("%d, ", field_dim_sizes[d]);
1210  printf("%d)", field_dim_sizes[field_ndims-1]);
1211  free(field_dim_sizes);
1212  }
1213  printf(" ;\n");
1214  }
1215  indent_out();
1216 /* printf("}; // %s\n", type_name); */
1217  printf("}; // ");
1218  print_type_name(ncid, typeid);
1219  printf("\n");
1220  }
1221  break;
1222  default:
1223  error("Unknown class of user-defined type!");
1224  }
1225 }
1226 #endif /* USE_NETCDF4 */
1227 
1228 static void
1229 get_fill_info(int ncid, int varid, ncvar_t *vp) {
1230  ncatt_t att; /* attribute */
1231  int nc_status; /* return from netcdf calls */
1232  void *fillvalp = NULL;
1233 
1234  vp->has_fillval = 1; /* by default, but turn off for bytes */
1235 
1236  /* get _FillValue attribute */
1237  nc_status = nc_inq_att(ncid,varid,_FillValue,&att.type,&att.len);
1238  fillvalp = emalloc(vp->tinfo->size + 1);
1239  if(nc_status == NC_NOERR &&
1240  att.type == vp->type && att.len == 1) {
1241  NC_CHECK(nc_get_att(ncid, varid, _FillValue, fillvalp));
1242  } else {
1243  switch (vp->type) {
1244  case NC_BYTE:
1245  /* don't do default fill-values for bytes, too risky */
1246  vp->has_fillval = 0;
1247  free(fillvalp);
1248  fillvalp = 0;
1249  break;
1250  case NC_CHAR:
1251  *(char *)fillvalp = NC_FILL_CHAR;
1252  break;
1253  case NC_SHORT:
1254  *(short *)fillvalp = NC_FILL_SHORT;
1255  break;
1256  case NC_INT:
1257  *(int *)fillvalp = NC_FILL_INT;
1258  break;
1259  case NC_FLOAT:
1260  *(float *)fillvalp = NC_FILL_FLOAT;
1261  break;
1262  case NC_DOUBLE:
1263  *(double *)fillvalp = NC_FILL_DOUBLE;
1264  break;
1265 #ifdef USE_NETCDF4
1266  case NC_UBYTE:
1267  /* don't do default fill-values for bytes, too risky */
1268  vp->has_fillval = 0;
1269  free(fillvalp);
1270  fillvalp = 0;
1271  break;
1272  case NC_USHORT:
1273  *(unsigned short *)fillvalp = NC_FILL_USHORT;
1274  break;
1275  case NC_UINT:
1276  *(unsigned int *)fillvalp = NC_FILL_UINT;
1277  break;
1278  case NC_INT64:
1279  *(int64_t *)fillvalp = NC_FILL_INT64;
1280  break;
1281  case NC_UINT64:
1282  *(uint64_t *)fillvalp = NC_FILL_UINT64;
1283  break;
1284  case NC_STRING:
1285  *((char **)fillvalp) = strdup(NC_FILL_STRING);
1286  break;
1287 #endif /* USE_NETCDF4 */
1288  default: /* no default fill values for NC_NAT
1289  or user-defined types */
1290  vp->has_fillval = 0;
1291  free(fillvalp);
1292  fillvalp = 0;
1293  break;
1294  }
1295  }
1296  vp->fillvalp = fillvalp;
1297 }
1298 
1299 
1300 /* Recursively dump the contents of a group. (Only netcdf-4 format
1301  * files can have groups, so recursion will not take place for classic
1302  * format files.)
1303  *
1304  * ncid: id of open file (first call) or group (subsequent recursive calls)
1305  * path: file path name (first call)
1306  */
1307 static void
1308 do_ncdump_rec(int ncid, const char *path)
1309 {
1310  int ndims; /* number of dimensions */
1311  int nvars; /* number of variables */
1312  int ngatts; /* number of global attributes */
1313  int xdimid; /* id of unlimited dimension */
1314  int varid; /* variable id */
1315  ncdim_t *dims; /* dimensions */
1316  size_t *vdims=0; /* dimension sizes for a single variable */
1317  ncvar_t var; /* variable */
1318  int id; /* dimension number per variable */
1319  int ia; /* attribute number */
1320  int iv; /* variable number */
1321  idnode_t* vlist = NULL; /* list for vars specified with -v option */
1322  char type_name[NC_MAX_NAME + 1];
1323  int kind; /* strings output differently for nc4 files */
1324  char dim_name[NC_MAX_NAME + 1];
1325 #ifdef USE_NETCDF4
1326  int *dimids_grp; /* dimids of the dims in this group. */
1327  int *unlimids; /* dimids of unlimited dimensions in this group */
1328  int d_grp, ndims_grp;
1329  int ntypes, *typeids;
1330  int nunlim;
1331 #else
1332  int dimid; /* dimension id */
1333 #endif /* USE_NETCDF4 */
1334  int is_root = 1; /* true if ncid is root group or if netCDF-3 */
1335 
1336 #ifdef USE_NETCDF4
1337  if (nc_inq_grp_parent(ncid, NULL) != NC_ENOGRP)
1338  is_root = 0;
1339 #endif /* USE_NETCDF4 */
1340 
1341  /*
1342  * If any vars were specified with -v option, get list of
1343  * associated variable ids relative to this group. Assume vars
1344  * specified with syntax like "grp1/grp2/varname" or
1345  * "/grp1/grp2/varname" if they are in groups.
1346  */
1347  if (formatting_specs.nlvars > 0) {
1348  vlist = newidlist(); /* list for vars specified with -v option */
1349  for (iv=0; iv < formatting_specs.nlvars; iv++) {
1350  if(nc_inq_gvarid(ncid, formatting_specs.lvars[iv], &varid) == NC_NOERR)
1351  idadd(vlist, varid);
1352  }
1353  }
1354 
1355 #ifdef USE_NETCDF4
1356  /* Are there any user defined types in this group? */
1357  NC_CHECK( nc_inq_typeids(ncid, &ntypes, NULL) );
1358  if (ntypes)
1359  {
1360  int t;
1361 
1362  typeids = emalloc((ntypes + 1) * sizeof(int));
1363  NC_CHECK( nc_inq_typeids(ncid, &ntypes, typeids) );
1364  indent_out();
1365  printf("types:\n");
1366  indent_more();
1367  for (t = 0; t < ntypes; t++)
1368  {
1369  print_ud_type(ncid, typeids[t]); /* print declaration of user-defined type */
1370  }
1371  indent_less();
1372  free(typeids);
1373  }
1374 #endif /* USE_NETCDF4 */
1375 
1376  /*
1377  * get number of dimensions, number of variables, number of global
1378  * atts, and dimension id of unlimited dimension, if any
1379  */
1380  NC_CHECK( nc_inq(ncid, &ndims, &nvars, &ngatts, &xdimid) );
1381  /* get dimension info */
1382  dims = (ncdim_t *) emalloc((ndims + 1) * sizeof(ncdim_t));
1383  if (ndims > 0) {
1384  indent_out();
1385  printf ("dimensions:\n");
1386  }
1387 
1388 #ifdef USE_NETCDF4
1389  /* In netCDF-4 files, dimids will not be sequential because they
1390  * may be defined in various groups, and we are only looking at one
1391  * group at a time. */
1392 
1393  /* Find the number of dimids defined in this group. */
1394  NC_CHECK( nc_inq_ndims(ncid, &ndims_grp) );
1395  dimids_grp = (int *)emalloc((ndims_grp + 1) * sizeof(int));
1396 
1397  /* Find the dimension ids in this group. */
1398  NC_CHECK( nc_inq_dimids(ncid, 0, dimids_grp, 0) );
1399 
1400  /* Find the number of unlimited dimensions and get their IDs */
1401  NC_CHECK( nc_inq_unlimdims(ncid, &nunlim, NULL) );
1402  unlimids = (int *)emalloc((nunlim + 1) * sizeof(int));
1403  NC_CHECK( nc_inq_unlimdims(ncid, &nunlim, unlimids) );
1404 
1405  /* For each dimension defined in this group, get and print out info. */
1406  for (d_grp = 0; d_grp < ndims_grp; d_grp++)
1407  {
1408  int dimid = dimids_grp[d_grp];
1409  int is_unlimited = 0;
1410  int uld;
1411  int stat;
1412 
1413  for (uld = 0; uld < nunlim; uld++) {
1414  if(dimid == unlimids[uld]) {
1415  is_unlimited = 1;
1416  break;
1417  }
1418  }
1419  stat = nc_inq_dim(ncid, dimid, dims[d_grp].name, &dims[d_grp].size);
1420  if (stat == NC_EDIMSIZE && SIZEOF_SIZE_T < 8) {
1421  error("dimension \"%s\" too large for 32-bit platform, try 64-bit version", dims[d_grp].name);
1422  } else {
1423  NC_CHECK (stat);
1424  }
1425  indent_out();
1426  printf ("\t");
1427  print_name(dims[d_grp].name);
1428  printf (" = ");
1429  if(SIZEOF_SIZE_T >= 8) {
1430  if (is_unlimited) {
1431  printf ("UNLIMITED ; // (%lu currently)\n",
1432  (unsigned long)dims[d_grp].size);
1433  } else {
1434  printf ("%lu ;\n", (unsigned long)dims[d_grp].size);
1435  }
1436  } else { /* 32-bit platform */
1437  if (is_unlimited) {
1438  printf ("UNLIMITED ; // (%u currently)\n",
1439  (unsigned int)dims[d_grp].size);
1440  } else {
1441  printf ("%u ;\n", (unsigned int)dims[d_grp].size);
1442  }
1443  }
1444  }
1445  if(unlimids)
1446  free(unlimids);
1447  if(dimids_grp)
1448  free(dimids_grp);
1449 #else /* not using netCDF-4 */
1450  for (dimid = 0; dimid < ndims; dimid++) {
1451  NC_CHECK( nc_inq_dim(ncid, dimid, dims[dimid].name, &dims[dimid].size) );
1452  indent_out();
1453  printf ("\t");
1454  print_name(dims[dimid].name);
1455  printf (" = ");
1456  if (dimid == xdimid) {
1457  printf ("UNLIMITED ; // (%u currently)\n",
1458  (unsigned int)dims[dimid].size);
1459  } else {
1460  printf ("%u ;\n", (unsigned int)dims[dimid].size);
1461  }
1462  }
1463 #endif /* USE_NETCDF4 */
1464 
1465  if (nvars > 0) {
1466  indent_out();
1467  printf ("variables:\n");
1468  }
1469  /* Because netCDF-4 can have a string attribute with multiple
1470  * string values, we can't output strings with embedded newlines
1471  * as what look like multiple strings, as we do for classic and
1472  * 64-bit offset files. So we need to know the output file type
1473  * to know how to print strings with embedded newlines. */
1474  NC_CHECK( nc_inq_format(ncid, &kind) );
1475 
1476  /* For each var, get and print out info. */
1477 
1478  memset((void*)&var,0,sizeof(var));
1479 
1480  for (varid = 0; varid < nvars; varid++) {
1481  NC_CHECK( nc_inq_varndims(ncid, varid, &var.ndims) );
1482  if(var.dims != NULL) free(var.dims);
1483  var.dims = (int *) emalloc((var.ndims + 1) * sizeof(int));
1484  NC_CHECK( nc_inq_var(ncid, varid, var.name, &var.type, 0,
1485  var.dims, &var.natts) );
1486  /* TODO: don't bother if type name not needed here */
1487  get_type_name(ncid, var.type, type_name);
1488  var.tinfo = get_typeinfo(var.type);
1489  indent_out();
1490 /* printf ("\t%s %s", type_name, var.name); */
1491  printf ("\t");
1492  /* TODO: if duplicate type name and not just inherited, print
1493  * full type name. */
1494  print_type_name (ncid, var.type);
1495  printf (" ");
1496  print_name (var.name);
1497  if (var.ndims > 0)
1498  printf ("(");
1499  for (id = 0; id < var.ndims; id++) {
1500  /* This dim may be in a parent group, so let's look up the
1501  * name. */
1502  NC_CHECK( nc_inq_dimname(ncid, var.dims[id], dim_name) );
1503 #ifdef USE_NETCDF4
1504  /* Subtlety: The following code block is needed because
1505  * nc_inq_dimname() currently returns only a simple dimension
1506  * name, without a prefix identifying the group it came from.
1507  * That's OK unless the dimid identifies a dimension in an
1508  * ancestor group that has the same simple name as a
1509  * dimension in the current group (or some intermediate
1510  * group), in which case the simple name is ambiguous. This
1511  * code tests for that case and provides an absolute dimname
1512  * only in the case where a simple name would be
1513  * ambiguous. */
1514  {
1515  int dimid_test; /* to see if dimname is ambiguous */
1516  int locid; /* group id where dimension is defined */
1517  NC_CHECK( nc_inq_dimid(ncid, dim_name, &dimid_test) );
1518  locid = ncid;
1519  while(var.dims[id] != dimid_test) { /* not in locid, try ancestors */
1520  int parent_id;
1521  NC_CHECK( nc_inq_grp_parent(locid, &parent_id) );
1522  locid = parent_id;
1523  NC_CHECK( nc_inq_dimid(locid, dim_name, &dimid_test) );
1524  }
1525  /* dimid is in group locid, prefix dimname with group name if needed */
1526  if(locid != ncid) {
1527  size_t len;
1528  char *locname; /* the group name */
1529  NC_CHECK( nc_inq_grpname_full(locid, &len, NULL) );
1530  locname = emalloc(len + 1);
1531  NC_CHECK( nc_inq_grpname_full(locid, &len, locname) );
1532  print_name (locname);
1533  if(strcmp("/", locname) != 0) { /* not the root group */
1534  printf("/"); /* ensure a trailing slash */
1535  }
1536  free(locname);
1537  }
1538  }
1539 #endif /* USE_NETCDF4 */
1540  print_name (dim_name);
1541  printf ("%s", id < var.ndims-1 ? ", " : ")");
1542  }
1543  printf (" ;\n");
1544 
1545  /* print variable attributes */
1546  for (ia = 0; ia < var.natts; ia++) { /* print ia-th attribute */
1547  pr_att(ncid, kind, varid, var.name, ia);
1548  }
1549 #ifdef USE_NETCDF4
1550  /* Print special (virtual) attributes, if option specified */
1551  if (formatting_specs.special_atts) {
1552  pr_att_specials(ncid, kind, varid, &var);
1553  }
1554 #endif /* USE_NETCDF4 */
1555  }
1556 
1557  /* get global attributes */
1558  if (ngatts > 0 || formatting_specs.special_atts) {
1559  printf ("\n");
1560  indent_out();
1561  if (is_root)
1562  printf("// global attributes:\n");
1563  else
1564  printf("// group attributes:\n");
1565  }
1566  for (ia = 0; ia < ngatts; ia++) { /* print ia-th global attribute */
1567  pr_att(ncid, kind, NC_GLOBAL, "", ia);
1568  }
1569  if (is_root && formatting_specs.special_atts) { /* output special attribute
1570  * for format variant */
1571  pr_att_global_format(ncid, kind);
1572  }
1573 
1574  /* output variable data, unless "-h" option specified header only
1575  * or this group is not in list of groups specified by "-g"
1576  * option */
1577  if (! formatting_specs.header_only &&
1578  group_wanted(ncid, formatting_specs.nlgrps, formatting_specs.grpids) ) {
1579  if (nvars > 0) {
1580  indent_out();
1581  printf ("data:\n");
1582  }
1583  for (varid = 0; varid < nvars; varid++) {
1584  int no_data;
1585  /* if var list specified, test for membership */
1586  if (formatting_specs.nlvars > 0 && ! idmember(vlist, varid))
1587  continue;
1588  NC_CHECK( nc_inq_varndims(ncid, varid, &var.ndims) );
1589  if(var.dims != NULL) free(var.dims);
1590  var.dims = (int *) emalloc((var.ndims + 1) * sizeof(int));
1591  NC_CHECK( nc_inq_var(ncid, varid, var.name, &var.type, 0,
1592  var.dims, &var.natts) );
1593  var.tinfo = get_typeinfo(var.type);
1594  /* If coords-only option specified, don't get data for
1595  * non-coordinate vars */
1596  if (formatting_specs.coord_vals && !iscoordvar(ncid,varid)) {
1597  continue;
1598  }
1599  /* Collect variable's dim sizes */
1600  if (vdims) {
1601  free(vdims);
1602  vdims = 0;
1603  }
1604  vdims = (size_t *) emalloc((var.ndims + 1) * SIZEOF_SIZE_T);
1605  no_data = 0;
1606  for (id = 0; id < var.ndims; id++) {
1607  size_t len;
1608  NC_CHECK( nc_inq_dimlen(ncid, var.dims[id], &len) );
1609  if(len == 0) {
1610  no_data = 1;
1611  }
1612  vdims[id] = len;
1613  }
1614  /* Don't get data for record variables if no records have
1615  * been written yet */
1616  if (no_data) {
1617  free(vdims);
1618  vdims = 0;
1619  continue;
1620  }
1621  if(var.fillvalp != NULL) free(var.fillvalp);
1622  get_fill_info(ncid, varid, &var); /* sets has_fillval, fillvalp mmbrs */
1623  if(var.timeinfo != NULL) {
1624  if(var.timeinfo->units) free(var.timeinfo->units);
1625  free(var.timeinfo);
1626  }
1627  get_timeinfo(ncid, varid, &var); /* sets has_timeval, timeinfo mmbrs */
1628  /* printf format used to print each value */
1629  var.fmt = get_fmt(ncid, varid, var.type);
1630  var.locid = ncid;
1631  set_tostring_func(&var);
1632  if (vardata(&var, vdims, ncid, varid) == -1) {
1633  error("can't output data for variable %s", var.name);
1634  goto done;
1635  }
1636  }
1637  if (vdims) {
1638  free(vdims);
1639  vdims = 0;
1640  }
1641  }
1642 
1643 #ifdef USE_NETCDF4
1644  /* For netCDF-4 compiles, check to see if the file has any
1645  * groups. If it does, this function is called recursively on each
1646  * of them. */
1647  {
1648  int g, numgrps, *ncids;
1649  char group_name[NC_MAX_NAME + 1];
1650 
1651  /* See how many groups there are. */
1652  NC_CHECK( nc_inq_grps(ncid, &numgrps, NULL) );
1653 
1654  /* Allocate memory to hold the list of group ids. */
1655  ncids = emalloc((numgrps + 1) * sizeof(int));
1656 
1657  /* Get the list of group ids. */
1658  NC_CHECK( nc_inq_grps(ncid, NULL, ncids) );
1659 
1660  /* Call this function for each group. */
1661  for (g = 0; g < numgrps; g++)
1662  {
1663  NC_CHECK( nc_inq_grpname(ncids[g], group_name) );
1664  printf ("\n");
1665  indent_out();
1666 /* printf ("group: %s {\n", group_name); */
1667  printf ("group: ");
1668  print_name (group_name);
1669  printf (" {\n");
1670  indent_more();
1671  do_ncdump_rec(ncids[g], NULL);
1672  indent_out();
1673 /* printf ("} // group %s\n", group_name); */
1674  printf ("} // group ");
1675  print_name (group_name);
1676  printf ("\n");
1677  indent_less();
1678  }
1679 
1680  free(ncids);
1681  }
1682 #endif /* USE_NETCDF4 */
1683 
1684 done:
1685  if(var.dims != NULL) free(var.dims);
1686  if(var.fillvalp != NULL) free(var.fillvalp);
1687  if(var.timeinfo != NULL) {
1688  if(var.timeinfo->units) free(var.timeinfo->units);
1689  free(var.timeinfo);
1690  }
1691  if (dims)
1692  free(dims);
1693  if (vlist)
1694  freeidlist(vlist);
1695 }
1696 
1697 
1698 static void
1699 do_ncdump(int ncid, const char *path)
1700 {
1701  char* esc_specname;
1702  /* output initial line */
1703  indent_init();
1704  indent_out();
1705  esc_specname=escaped_name(formatting_specs.name);
1706  printf ("netcdf %s {\n", esc_specname);
1707  free(esc_specname);
1708  do_ncdump_rec(ncid, path);
1709  indent_out();
1710  printf ("}\n");
1711 }
1712 
1713 
1714 static void
1715 do_ncdumpx(int ncid, const char *path)
1716 {
1717  int ndims; /* number of dimensions */
1718  int nvars; /* number of variables */
1719  int ngatts; /* number of global attributes */
1720  int xdimid; /* id of unlimited dimension */
1721  int dimid; /* dimension id */
1722  int varid; /* variable id */
1723  ncdim_t *dims; /* dimensions */
1724  ncvar_t var; /* variable */
1725  int ia; /* attribute number */
1726  int iv; /* variable number */
1727  idnode_t* vlist = NULL; /* list for vars specified with -v option */
1728 
1729  /*
1730  * If any vars were specified with -v option, get list of associated
1731  * variable ids
1732  */
1733  if (formatting_specs.nlvars > 0) {
1734  vlist = newidlist(); /* list for vars specified with -v option */
1735  for (iv=0; iv < formatting_specs.nlvars; iv++) {
1736  NC_CHECK( nc_inq_varid(ncid, formatting_specs.lvars[iv], &varid) );
1737  idadd(vlist, varid);
1738  }
1739  }
1740 
1741  /* output initial line */
1742  pr_initx(ncid, path);
1743 
1744  /*
1745  * get number of dimensions, number of variables, number of global
1746  * atts, and dimension id of unlimited dimension, if any
1747  */
1748  /* TODO: print names with XML-ish escapes fopr special chars */
1749  NC_CHECK( nc_inq(ncid, &ndims, &nvars, &ngatts, &xdimid) );
1750  /* get dimension info */
1751  dims = (ncdim_t *) emalloc((ndims + 1) * sizeof(ncdim_t));
1752  for (dimid = 0; dimid < ndims; dimid++) {
1753  NC_CHECK( nc_inq_dim(ncid, dimid, dims[dimid].name, &dims[dimid].size) );
1754  if (dimid == xdimid)
1755  printf(" <dimension name=\"%s\" length=\"%d\" isUnlimited=\"true\" />\n",
1756  dims[dimid].name, (int)dims[dimid].size);
1757  else
1758  printf (" <dimension name=\"%s\" length=\"%d\" />\n",
1759  dims[dimid].name, (int)dims[dimid].size);
1760  }
1761 
1762  /* get global attributes */
1763  for (ia = 0; ia < ngatts; ia++)
1764  pr_attx(ncid, NC_GLOBAL, ia); /* print ia-th global attribute */
1765 
1766  /* get variable info, with variable attributes */
1767  memset((void*)&var,0,sizeof(var));
1768  for (varid = 0; varid < nvars; varid++) {
1769  NC_CHECK( nc_inq_varndims(ncid, varid, &var.ndims) );
1770  if(var.dims != NULL) free(var.dims);
1771  var.dims = (int *) emalloc((var.ndims + 1) * sizeof(int));
1772  NC_CHECK( nc_inq_var(ncid, varid, var.name, &var.type, 0,
1773  var.dims, &var.natts) );
1774  printf (" <variable name=\"%s\"", var.name);
1775  pr_shape(&var, dims);
1776 
1777  /* handle one-line variable elements that aren't containers
1778  for attributes or data values, since they need to be
1779  rendered as <variable ... /> instead of <variable ..>
1780  ... </variable> */
1781  if (var.natts == 0) {
1782  if (
1783  /* header-only specified */
1784  (formatting_specs.header_only) ||
1785  /* list of variables specified and this variable not in list */
1786  (formatting_specs.nlvars > 0 && !idmember(vlist, varid)) ||
1787  /* coordinate vars only and this is not a coordinate variable */
1788  (formatting_specs.coord_vals && !iscoordvar(ncid, varid)) ||
1789  /* this is a record variable, but no records have been written */
1790  (isrecvar(ncid,varid) && dims[xdimid].size == 0)
1791  ) {
1792  printf (" type=\"%s\" />\n", prim_type_name(var.type));
1793  continue;
1794  }
1795  }
1796 
1797  /* else nest attributes values, data values in <variable> ... </variable> */
1798  printf (" type=\"%s\">\n", prim_type_name(var.type));
1799 
1800  /* get variable attributes */
1801  for (ia = 0; ia < var.natts; ia++) {
1802  pr_attx(ncid, varid, ia); /* print ia-th attribute */
1803  }
1804  printf (" </variable>\n");
1805  }
1806 
1807  printf ("</netcdf>\n");
1808  if (vlist)
1809  freeidlist(vlist);
1810  if(dims)
1811  free(dims);
1812 }
1813 
1814 /*
1815  * Extract the significant-digits specifiers from the (deprecated and
1816  * undocumented) -d argument on the command-line and update the
1817  * default data formats appropriately. This only exists because an
1818  * old version of ncdump supported the "-d" flag which did not
1819  * override the C_format attributes (if any).
1820  */
1821 static void
1822 set_sigdigs(const char *optarg)
1823 {
1824  char *ptr1 = 0;
1825  char *ptr2 = 0;
1826  int flt_digits = FLT_DIGITS; /* default floating-point digits */
1827  int dbl_digits = DBL_DIGITS; /* default double-precision digits */
1828 
1829  if (optarg != 0 && (int) strlen(optarg) > 0 && optarg[0] != ',')
1830  flt_digits = (int)strtol(optarg, &ptr1, 10);
1831 
1832  if (flt_digits < 1 || flt_digits > 20) {
1833  error("unreasonable value for float significant digits: %d",
1834  flt_digits);
1835  }
1836  if (ptr1 && *ptr1 == ',') {
1837  dbl_digits = (int)strtol(ptr1+1, &ptr2, 10);
1838  if (ptr2 == ptr1+1 || dbl_digits < 1 || dbl_digits > 20) {
1839  error("unreasonable value for double significant digits: %d",
1840  dbl_digits);
1841  }
1842  }
1843  set_formats(flt_digits, dbl_digits);
1844 }
1845 
1846 
1847 /*
1848  * Extract the significant-digits specifiers from the -p argument on the
1849  * command-line, set flags so we can override C_format attributes (if any),
1850  * and update the default data formats appropriately.
1851  */
1852 static void
1853 set_precision(const char *optarg)
1854 {
1855  char *ptr1 = 0;
1856  char *ptr2 = 0;
1857  int flt_digits = FLT_DIGITS; /* default floating-point digits */
1858  int dbl_digits = DBL_DIGITS; /* default double-precision digits */
1859 
1860  if (optarg != 0 && (int) strlen(optarg) > 0 && optarg[0] != ',') {
1861  flt_digits = (int)strtol(optarg, &ptr1, 10);
1862  float_precision_specified = 1;
1863  }
1864 
1865  if (flt_digits < 1 || flt_digits > 20) {
1866  error("unreasonable value for float significant digits: %d",
1867  flt_digits);
1868  }
1869  if (ptr1 && *ptr1 == ',') {
1870  dbl_digits = (int) strtol(ptr1+1, &ptr2, 10);
1871  double_precision_specified = 1;
1872  if (ptr2 == ptr1+1 || dbl_digits < 1 || dbl_digits > 20) {
1873  error("unreasonable value for double significant digits: %d",
1874  dbl_digits);
1875  }
1876  }
1877  set_formats(flt_digits, dbl_digits);
1878 }
1879 
1880 
1881 #ifdef USE_DAP
1882 #define DAP_CLIENT_CACHE_DIRECTIVE "[cache]"
1883 /* replace path string with same string prefixed by
1884  * DAP_CLIENT_NCDUMP_DIRECTIVE */
1885 static
1886 void adapt_url_for_cache(char **pathp) {
1887  char prefix[] = DAP_CLIENT_CACHE_DIRECTIVE;
1888  char* path = *pathp;
1889  char *tmp_path = strdup(path);
1890  path = (char *)emalloc(strlen(prefix) + strlen(tmp_path) + 1);
1891  path[0] = '\0';
1892  strncat(path, prefix, strlen(prefix));
1893  strncat(path, tmp_path, strlen(tmp_path));
1894  free(tmp_path);
1895  *pathp = path;
1896  return;
1897 }
1898 #endif
1899 
1900 int
1901 main(int argc, char *argv[])
1902 {
1903  int c;
1904  int i;
1905  int max_len = 80; /* default maximum line length */
1906  int nameopt = 0;
1907  bool_t xml_out = false; /* if true, output NcML instead of CDL */
1908  bool_t kind_out = false; /* if true, just output kind of netCDF file */
1909  bool_t kind_out_extended = false; /* output inq_format vs inq_format_extended */
1910 
1911 #if defined(WIN32) || defined(msdos) || defined(WIN64)
1912  putenv("PRINTF_EXPONENT_DIGITS=2"); /* Enforce unix/linux style exponent formatting. */
1913 #endif
1914 
1915 #ifdef HAVE_LOCALE_H
1916  setlocale(LC_ALL, "C"); /* CDL may be ambiguous with other locales */
1917 #endif /* HAVE_LOCALE_H */
1918  opterr = 1;
1919  progname = argv[0];
1920  set_formats(FLT_DIGITS, DBL_DIGITS); /* default for float, double data */
1921 
1922  /* If the user called ncdump without arguments, print the usage
1923  * message and return peacefully. */
1924  if (argc <= 1)
1925  {
1926  usage();
1927  exit(EXIT_SUCCESS);
1928  }
1929 
1930  while ((c = getopt(argc, argv, "b:cd:f:g:hikl:n:p:stv:xwK")) != EOF)
1931  switch(c) {
1932  case 'h': /* dump header only, no data */
1933  formatting_specs.header_only = true;
1934  break;
1935  case 'c': /* header, data only for coordinate dims */
1936  formatting_specs.coord_vals = true;
1937  break;
1938  case 'n': /*
1939  * provide different name than derived from
1940  * file name
1941  */
1942  formatting_specs.name = optarg;
1943  nameopt = 1;
1944  break;
1945  case 'b': /* brief comments in data section */
1946  formatting_specs.brief_data_cmnts = true;
1947  switch (tolower((int)optarg[0])) {
1948  case 'c':
1949  formatting_specs.data_lang = LANG_C;
1950  break;
1951  case 'f':
1952  formatting_specs.data_lang = LANG_F;
1953  break;
1954  default:
1955  error("invalid value for -b option: %s", optarg);
1956  }
1957  break;
1958  case 'f': /* full comments in data section */
1959  formatting_specs.full_data_cmnts = true;
1960  switch (tolower((int)optarg[0])) {
1961  case 'c':
1962  formatting_specs.data_lang = LANG_C;
1963  break;
1964  case 'f':
1965  formatting_specs.data_lang = LANG_F;
1966  break;
1967  default:
1968  error("invalid value for -f option: %s", optarg);
1969  }
1970  break;
1971  case 'l': /* maximum line length */
1972  max_len = (int) strtol(optarg, 0, 0);
1973  if (max_len < 10) {
1974  error("unreasonably small line length specified: %d", max_len);
1975  }
1976  break;
1977  case 'v': /* variable names */
1978  /* make list of names of variables specified */
1979  make_lvars (optarg, &formatting_specs.nlvars, &formatting_specs.lvars);
1980  break;
1981  case 'g': /* group names */
1982  /* make list of names of groups specified */
1983  make_lgrps (optarg, &formatting_specs.nlgrps, &formatting_specs.lgrps,
1984  &formatting_specs.grpids);
1985  break;
1986  case 'd': /* specify precision for floats (deprecated, undocumented) */
1987  set_sigdigs(optarg);
1988  break;
1989  case 'p': /* specify precision for floats, overrides attribute specs */
1990  set_precision(optarg);
1991  break;
1992  case 'x': /* XML output (NcML) */
1993  xml_out = true;
1994  break;
1995  case 'k': /* just output what kind of netCDF file */
1996  kind_out = true;
1997  break;
1998  case 'K': /* extended format info */
1999  kind_out_extended = true;
2000  break;
2001  case 't': /* human-readable strings for date-time values */
2002  formatting_specs.string_times = true;
2003  formatting_specs.iso_separator = false;
2004  break;
2005  case 'i': /* human-readable strings for data-time values with 'T' separator */
2006  formatting_specs.string_times = true;
2007  formatting_specs.iso_separator = true;
2008  break;
2009  case 's': /* output special (virtual) attributes for
2010  * netCDF-4 files and variables, including
2011  * _DeflateLevel, _Chunking, _Endianness,
2012  * _Format, _Checksum, _NoFill */
2013  formatting_specs.special_atts = true;
2014  break;
2015  case 'w': /* with client-side cache for DAP URLs */
2016  formatting_specs.with_cache = true;
2017  break;
2018  case '?':
2019  usage();
2020  exit(EXIT_FAILURE);
2021  }
2022 
2023  set_max_len(max_len);
2024 
2025  argc -= optind;
2026  argv += optind;
2027 
2028  /* If no file arguments left or more than one, print usage message. */
2029  if (argc != 1)
2030  {
2031  usage();
2032  exit(EXIT_FAILURE);
2033  }
2034 
2035  i = 0;
2036 
2037  init_epsilons();
2038 
2039  {
2040  char *path = strdup(argv[i]);
2041  if(!path)
2042  error("out of memory copying argument %s", argv[i]);
2043  if (!nameopt)
2044  formatting_specs.name = name_path(path);
2045  if (argc > 0) {
2046  int ncid, nc_status;
2047  /* If path is a URL, prefix with client-side directive to
2048  * make ncdump reasonably efficient */
2049 #ifdef USE_DAP
2050  if(formatting_specs.with_cache) /* by default, don't use cache directive */
2051  {
2052  extern int nc__testurl(const char*,char**);
2053  /* See if this is a url */
2054  if(nc__testurl(path, NULL)) {
2055  adapt_url_for_cache(&path);
2056  }
2057  /* else fall thru and treat like a file path */
2058  }
2059 #endif /*USE_DAP*/
2060  nc_status = nc_open(path, NC_NOWRITE, &ncid);
2061  if (nc_status != NC_NOERR) {
2062  error("%s: %s", path, nc_strerror(nc_status));
2063  }
2064  NC_CHECK( nc_inq_format(ncid, &formatting_specs.nc_kind) );
2065  NC_CHECK( nc_inq_format_extended(ncid,
2066  &formatting_specs.nc_extended,
2067  &formatting_specs.nc_mode) );
2068  if (kind_out) {
2069  printf ("%s\n", kind_string(formatting_specs.nc_kind));
2070  } else if (kind_out_extended) {
2071  printf ("%s\n", kind_string_extended(formatting_specs.nc_extended,formatting_specs.nc_mode));
2072  } else {
2073  /* Initialize list of types. */
2074  init_types(ncid);
2075  /* Check if any vars in -v don't exist */
2076  if(missing_vars(ncid, formatting_specs.nlvars, formatting_specs.lvars))
2077  exit(EXIT_FAILURE);
2078  if(formatting_specs.nlgrps > 0) {
2079  if(formatting_specs.nc_kind != NC_FORMAT_NETCDF4) {
2080  error("Group list (-g ...) only permitted for netCDF-4 file");
2081  exit(EXIT_FAILURE);
2082  }
2083  /* Check if any grps in -g don't exist */
2084  if(grp_matches(ncid, formatting_specs.nlgrps, formatting_specs.lgrps, formatting_specs.grpids) == 0)
2085  exit(EXIT_FAILURE);
2086  }
2087  if (xml_out) {
2088  if(formatting_specs.nc_kind == NC_FORMAT_NETCDF4) {
2089  error("NcML output (-x) currently only permitted for netCDF classic model");
2090  exit(EXIT_FAILURE);
2091  }
2092  do_ncdumpx(ncid, path);
2093  } else {
2094  do_ncdump(ncid, path);
2095  }
2096  }
2097  NC_CHECK( nc_close(ncid) );
2098  }
2099  free(path);
2100  }
2101  exit(EXIT_SUCCESS);
2102 }
2103 END_OF_MAIN();
#define _FillValue
Name of fill value attribute.
Definition: netcdf.h:117
EXTERNL int nc_inq_var_endian(int ncid, int varid, int *endianp)
Find the endianness of a variable.
Definition: dvarinq.c:506
#define NC_CHAR
ISO/ASCII character.
Definition: netcdf.h:38
EXTERNL int nc_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, size_t *lenp)
Return information about a netCDF attribute.
Definition: dattinq.c:72
#define NC_FILL_CHAR
Default fill value.
Definition: netcdf.h:69
#define NC_UBYTE
unsigned 1 byte int
Definition: netcdf.h:44
#define NC_FILL_UINT
Default fill value.
Definition: netcdf.h:76
#define NC_UINT
unsigned 4-byte int
Definition: netcdf.h:46
EXTERNL const char * nc_inq_libvers(void)
Return the library version.
Definition: derror.c:23
#define NC_OPAQUE
opaque types
Definition: netcdf.h:56
Main header file for the C API.
#define NC_INT64
signed 8-byte int
Definition: netcdf.h:47
EXTERNL int nc_inq_var_chunking(int ncid, int varid, int *storagep, size_t *chunksizesp)
This is a wrapper for nc_inq_var_all().
Definition: dvarinq.c:424
#define NC_STRING
string
Definition: netcdf.h:49
#define NC_DOUBLE
double precision floating point number
Definition: netcdf.h:43
#define NC_FILL_UINT64
Default fill value.
Definition: netcdf.h:78
EXTERNL int nc_inq_varndims(int ncid, int varid, int *ndimsp)
Learn how many dimensions are associated with a variable.
Definition: dvarinq.c:191
#define NC_FORMAT_PNETCDF
Extended format specifier returned by nc_inq_format_extended() Added in version 4.3.1.
Definition: netcdf.h:191
EXTERNL int nc_inq_format(int ncid, int *formatp)
Inquire about the binary format of a netCDF file as presented by the API.
Definition: dfile.c:1278
EXTERNL int nc_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp)
Inquire about a file or group.
Definition: dfile.c:1365
int nc_type
The nc_type type is just an int.
Definition: netcdf.h:27
#define NC_64BIT_OFFSET
Use large (64-bit) file offsets.
Definition: netcdf.h:136
#define NC_FILL_STRING
Default fill value.
Definition: netcdf.h:79
#define NC_NOWRITE
Set read-only access for nc_open().
Definition: netcdf.h:126
#define NC_BYTE
signed 1 byte integer
Definition: netcdf.h:37
EXTERNL int nc_inq_format_extended(int ncid, int *formatp, int *modep)
Obtain more detailed (vis-a-vis nc_inq_format) format information about an open dataset.
Definition: dfile.c:1312
#define NC_EDIMSIZE
Invalid dimension size.
Definition: netcdf.h:355
#define NC_FILL_INT
Default fill value.
Definition: netcdf.h:71
#define NC_ENDIAN_LITTLE
In HDF5 files you can set the endianness of variables with nc_def_var_endian().
Definition: netcdf.h:242
#define NC_ENOGRP
No group found.
Definition: netcdf.h:410
EXTERNL int nc_close(int ncid)
Close an open netCDF dataset.
Definition: dfile.c:1093
#define NC_VLEN
vlen (variable-length) types
Definition: netcdf.h:55
#define NC_NOSHUFFLE
Control the HDF5 shuffle filter.
Definition: netcdf.h:268
EXTERNL int nc_inq_compound_field(int ncid, nc_type xtype, int fieldid, char *name, size_t *offsetp, nc_type *field_typeidp, int *ndimsp, int *dim_sizesp)
Get information about one of the fields of a compound type.
Definition: dcompound.c:287
EXTERNL int nc_get_att(int ncid, int varid, const char *name, void *ip)
Get an attribute of any type.
Definition: dattget.c:41
#define NC_FORMAT_NC_HDF4
Extended format specifier returned by nc_inq_format_extended() Added in version 4.3.1.
Definition: netcdf.h:190
#define NC_FORMAT_NC_HDF5
Extended format specifier returned by nc_inq_format_extended() Added in version 4.3.1.
Definition: netcdf.h:189
EXTERNL int nc_get_att_text(int ncid, int varid, const char *name, char *ip)
Get an attribute.
Definition: dattget.c:132
#define NC_FORMAT_64BIT
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:166
EXTERNL int nc_inq_dimname(int ncid, int dimid, char *name)
Find out the name of a dimension.
Definition: ddim.c:338
This is the type of arrays of vlens.
Definition: netcdf.h:624
EXTERNL int nc_inq_var_fletcher32(int ncid, int varid, int *fletcher32p)
Learn the checksum settings for a variable.
Definition: dvarinq.c:375
#define NC_INT
signed 4 byte integer
Definition: netcdf.h:40
#define NC_ENDIAN_BIG
In HDF5 files you can set the endianness of variables with nc_def_var_endian().
Definition: netcdf.h:243
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:231
EXTERNL int nc_free_string(size_t len, char **data)
Free string space allocated by the library.
Definition: dvar.c:530
#define NC_USHORT
unsigned 2-byte int
Definition: netcdf.h:45
#define NC_FORMAT_NC3
Extended format specifier returned by nc_inq_format_extended() Added in version 4.3.1.
Definition: netcdf.h:188
#define NC_FORMAT_NETCDF4_CLASSIC
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:168
#define NC_FILL_FLOAT
Default fill value.
Definition: netcdf.h:72
#define NC_FORMAT_UNDEFINED
Extended format specifier returned by nc_inq_format_extended() Added in version 4.3.1.
Definition: netcdf.h:194
#define NC_FORMAT_NETCDF4
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:167
EXTERNL int nc_inq_varid(int ncid, const char *name, int *varidp)
Find the ID of a variable, from the name.
Definition: dvarinq.c:52
#define NC_FORMAT_DAP2
Extended format specifier returned by nc_inq_format_extended() Added in version 4.3.1.
Definition: netcdf.h:192
EXTERNL int nc_inq_enum_member(int ncid, nc_type xtype, int idx, char *name, void *value)
Learn about a about a member of an enum type.
Definition: denum.c:140
#define NC_SHORT
signed 2 byte integer
Definition: netcdf.h:39
#define NC_ENDIAN_NATIVE
In HDF5 files you can set the endianness of variables with nc_def_var_endian().
Definition: netcdf.h:241
EXTERNL int nc_inq_enum_ident(int ncid, nc_type xtype, long long value, char *identifier)
Get the name which is associated with an enum member value.
Definition: denum.c:168
EXTERNL int nc_inq_var_deflate(int ncid, int varid, int *shufflep, int *deflatep, int *deflate_levelp)
Learn the storage and deflate settings for a variable.
Definition: dvarinq.c:273
EXTERNL int nc_inq_unlimdims(int ncid, int *nunlimdimsp, int *unlimdimidsp)
Return number and list of unlimited dimensions.
Definition: dvarinq.c:563
EXTERNL int nc_inq_var(int ncid, int varid, char *name, nc_type *xtypep, int *ndimsp, int *dimidsp, int *nattsp)
Learn about a variable.
Definition: dvarinq.c:116
#define NC_NOERR
No Error.
Definition: netcdf.h:278
#define NC_ENUM
enum types
Definition: netcdf.h:57
#define NC_FORMAT_DAP4
Extended format specifier returned by nc_inq_format_extended() Added in version 4.3.1.
Definition: netcdf.h:193
EXTERNL int nc_open(const char *path, int mode, int *ncidp)
Open an existing netCDF file.
Definition: dfile.c:588
EXTERNL int nc_inq_dimid(int ncid, const char *name, int *idp)
Find the ID of a dimension from the name.
Definition: ddim.c:96
EXTERNL int nc_inq_ndims(int ncid, int *ndimsp)
Find the number of dimensions.
Definition: ddim.c:250
#define NC_FILL_SHORT
Default fill value.
Definition: netcdf.h:70
#define NC_FILL_DOUBLE
Default fill value.
Definition: netcdf.h:73
#define NC_COMPOUND
compound types
Definition: netcdf.h:58
int nc_get_att_double(int ncid, int varid, const char *name, double *value)
Get an attribute.
Definition: dattget.c:195
EXTERNL int nc_inq_dimlen(int ncid, int dimid, size_t *lenp)
Find the length of a dimension.
Definition: ddim.c:394
#define NC_FILL_USHORT
Default fill value.
Definition: netcdf.h:75
EXTERNL int nc_inq_user_type(int ncid, nc_type xtype, char *name, size_t *size, nc_type *base_nc_typep, size_t *nfieldsp, int *classp)
Learn about a user defined type.
Definition: dtype.c:102
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition: netcdf.h:207
EXTERNL int nc_inq_var_fill(int ncid, int varid, int *no_fill, void *fill_valuep)
Learn the fill mode of a variable.
Definition: dvarinq.c:458
#define NC_FLOAT
single precision floating point number
Definition: netcdf.h:42
#define NC_FORMAT_CLASSIC
Format specifier for nc_set_default_format() and returned by nc_inq_format.
Definition: netcdf.h:165
#define END_OF_MAIN()
NO_NETCDF_2.
Definition: netcdf.h:1918
#define NC_FILL_INT64
Default fill value.
Definition: netcdf.h:77
#define NC_UINT64
unsigned 8-byte int
Definition: netcdf.h:48
EXTERNL int nc_inq_dim(int ncid, int dimid, char *name, size_t *lenp)
Find the name and length of a dimension.
Definition: ddim.c:159
EXTERNL int nc_inq_attname(int ncid, int varid, int attnum, char *name)
Find the name of an attribute.
Definition: dattinq.c:129

Return to the Main Unidata NetCDF page.
Generated on Sun Nov 23 2014 16:17:49 for NetCDF. NetCDF is a Unidata library.