ncdf4a13/ncdump/ncdump.c

Go to the documentation of this file.
00001 /*********************************************************************
00002  *   Copyright 1993, University Corporation for Atmospheric Research
00003  *   See netcdf/README file for copying and redistribution conditions.
00004  *   $Header: /upc/share/CVS/netcdf-3/ncdump/ncdump.c,v 1.26 2006/01/11 17:00:06 ed Exp $
00005  *********************************************************************/
00006 
00007 #include <config.h>
00008 #include <stdio.h>
00009 #include <stdlib.h>
00010 #include <string.h>
00011 #include <ctype.h>
00012 #include <stdlib.h>
00013 
00014 #include <netcdf.h>
00015 #include "ncdump.h"
00016 #include "dumplib.h"
00017 #include "vardata.h"
00018 
00019 #define int64_t long long
00020 #define uint64_t unsigned long long
00021 
00022 static void usage(void);
00023 static char* name_path(const char* path);
00024 static const char* type_name(nc_type  type);
00025 static void tztrim(char* ss);
00026 static void pr_att_string(size_t len, const char* string);
00027 static void pr_att_vals(nc_type  type, size_t len, const double* vals);
00028 static void pr_att(int ncid, int varid, const char *varname, int ia);
00029 static void pr_attx(int ncid, int varid, int ia);
00030 static void do_ncdump(const char* path, fspec_t* specp);
00031 static void do_ncdumpx(const char* path, fspec_t* specp);
00032 static void make_lvars(char* optarg, fspec_t* fspecp);
00033 static void set_sigdigs( const char* optarg);
00034 static void set_precision( const char *optarg);
00035 int main(int argc, char** argv);
00036 
00037 #define STREQ(a, b)     (*(a) == *(b) && strcmp((a), (b)) == 0)
00038 
00039 char *progname;
00040 
00041 static void
00042 usage(void)
00043 {
00044 #define USAGE   "\
00045   [-c]             Coordinate variable data and header information\n\
00046   [-h]             Header information only, no data\n\
00047   [-v var1[,...]]  Data for variable(s) <var1>,... only\n\
00048   [-b [c|f]]       Brief annotations for C or Fortran indices in data\n\
00049   [-f [c|f]]       Full annotations for C or Fortran indices in data\n\
00050   [-l len]         Line length maximum in data section (default 80)\n\
00051   [-n name]        Name for netCDF (default derived from file name)\n\
00052   [-p n[,n]]       Display floating-point values with less precision\n\
00053   [-x]             Output XML (NcML) instead of CDL\n\
00054   file             Name of netCDF file\n"
00055 
00056     (void) fprintf(stderr,
00057                    "%s [-c|-h] [-v ...] [[-b|-f] [c|f]] [-l len] [-n name] [-p n[,n]] [-x] file\n%s",
00058                    progname,
00059                    USAGE);
00060     
00061     (void) fprintf(stderr,
00062                  "netcdf library version %s\n",
00063                  nc_inq_libvers());
00064     exit(EXIT_FAILURE);
00065 }
00066 
00067 
00068 /* 
00069  * convert pathname of netcdf file into name for cdl unit, by taking 
00070  * last component of path and stripping off any extension.
00071  */
00072 static char *
00073 name_path(const char *path)
00074 {
00075     const char *cp;
00076     char *new;
00077     char *sp;
00078 
00079 #ifdef vms
00080 #define FILE_DELIMITER ']'
00081 #endif    
00082 #ifdef MSDOS
00083 #define FILE_DELIMITER '\\'
00084 #endif    
00085 #ifndef FILE_DELIMITER /* default to unix */
00086 #define FILE_DELIMITER '/'
00087 #endif
00088     cp = strrchr(path, FILE_DELIMITER);
00089     if (cp == 0)                /* no delimiter */
00090       cp = path;
00091     else                        /* skip delimeter */
00092       cp++;
00093     new = (char *) emalloc((unsigned) (strlen(cp)+1));
00094     (void) strcpy(new, cp);     /* copy last component of path */
00095     if ((sp = strrchr(new, '.')) != NULL)
00096       *sp = '\0';               /* strip off any extension */
00097     return new;
00098 }
00099 
00100 
00101 static const char *
00102 type_name(nc_type type)
00103 {
00104     switch (type) {
00105       case NC_BYTE:
00106         return "byte";
00107       case NC_CHAR:
00108         return "char";
00109       case NC_SHORT:
00110         return "short";
00111       case NC_INT:
00112         return "int";
00113       case NC_FLOAT:
00114         return "float";
00115       case NC_DOUBLE:
00116         return "double";
00117 #ifdef USE_NETCDF4
00118       case NC_UBYTE:
00119         return "ubyte";
00120       case NC_USHORT:
00121         return "ushort";
00122       case NC_UINT:
00123         return "uint";
00124       case NC_INT64:
00125         return "long";
00126       case NC_UINT64:
00127         return "ulong";
00128       case NC_STRING:
00129         return "string";
00130       case NC_VLEN:
00131         return "vlen";
00132       case NC_OPAQUE:
00133         return "opaque";
00134       case NC_COMPOUND:
00135         return "compound";
00136 #endif
00137       default:
00138         error("type_name: bad type %d", type);
00139         return "bogus";
00140     }
00141 }
00142 
00143 
00144 /*
00145  * Remove trailing zeros (after decimal point) but not trailing decimal
00146  * point from ss, a string representation of a floating-point number that
00147  * might include an exponent part.
00148  */
00149 static void
00150 tztrim(char *ss)
00151 {
00152     char *cp, *ep;
00153     
00154     cp = ss;
00155     if (*cp == '-')
00156       cp++;
00157     while(isdigit((int)*cp) || *cp == '.')
00158       cp++;
00159     if (*--cp == '.')
00160       return;
00161     ep = cp+1;
00162     while (*cp == '0')
00163       cp--;
00164     cp++;
00165     if (cp == ep)
00166       return;
00167     while (*ep)
00168       *cp++ = *ep++;
00169     *cp = '\0';
00170     return;
00171 }
00172 
00173 
00174 /* 
00175  * Emit initial line of output for CDL, including format variant
00176  */
00177 void pr_fmtvariant(int ncid, const char *path, const fspec_t* specp)
00178 {
00179     int format_version;
00180     char *format_str;
00181     
00182     NC_CHECK( nc_inq_format(ncid, &format_version) );
00183     switch(format_version) {
00184     case NC_FORMAT_CLASSIC:
00185         format_str = "classic";
00186         break;
00187     case NC_FORMAT_64BIT:
00188         format_str = "64bit";
00189         break;
00190     case NC_FORMAT_NETCDF4:
00191         format_str = "netCDF4";
00192         break;
00193     case NC_FORMAT_NETCDF4_CLASSIC:
00194         format_str = " netCDF4_classic";
00195         break;
00196     default:
00197         error("unrecognized format: %s", path);
00198         break;
00199     }
00200     if (format_version == NC_FORMAT_CLASSIC) {
00201         Printf ("netcdf %s {\n", specp->name);
00202     } else {
00203         Printf ("netcdf %s { // format variant: %s \n", specp->name, format_str);
00204     }
00205 }
00206 
00207 
00208 /* 
00209  * Emit initial line of output for NcML, including format variant
00210  */
00211 void pr_fmtvariantx(int ncid, const char *path)
00212 {
00213     int format_version;
00214     char *format_str;
00215     
00216     NC_CHECK( nc_inq_format(ncid, &format_version) );
00217     switch(format_version) {
00218     case NC_FORMAT_CLASSIC:
00219         format_str = "classic";
00220         break;
00221     case NC_FORMAT_64BIT:
00222         format_str = "64bit";
00223         break;
00224     case NC_FORMAT_NETCDF4:
00225         format_str = "netCDF4";
00226         break;
00227     case NC_FORMAT_NETCDF4_CLASSIC:
00228         format_str = " netCDF4_classic";
00229         break;
00230     default:
00231         error("unrecognized format: %s", path);
00232         break;
00233     }
00234 
00235     Printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<netcdf xmlns=\"http://www.unidata.ucar.edu/namespaces/netcdf/ncml-2.2\" format=\"%s\" location=\"%s\">\n", 
00236            format_str, path);
00237 }
00238 
00239 
00240 /*
00241  * Print attribute string, for text attributes.
00242  */
00243 static void
00244 pr_att_string(
00245      size_t len,
00246      const char *string
00247      )
00248 {
00249     int iel;
00250     const char *cp;
00251     const char *sp;
00252     unsigned char uc;
00253 
00254     cp = string;
00255     Printf ("\"");
00256     /* adjust len so trailing nulls don't get printed */
00257     sp = cp + len - 1;
00258     while (len != 0 && *sp-- == '\0')
00259         len--;
00260     for (iel = 0; iel < len; iel++)
00261         switch (uc = *cp++ & 0377) {
00262         case '\b':
00263             Printf ("\\b");
00264             break;
00265         case '\f':
00266             Printf ("\\f");
00267             break;
00268         case '\n':              /* generate linebreaks after new-lines */
00269             Printf ("\\n\",\n\t\t\t\"");
00270             break;
00271         case '\r':
00272             Printf ("\\r");
00273             break;
00274         case '\t':
00275             Printf ("\\t");
00276             break;
00277         case '\v':
00278             Printf ("\\v");
00279             break;
00280         case '\\':
00281             Printf ("\\\\");
00282             break;
00283         case '\'':
00284             Printf ("\\'");
00285             break;
00286         case '\"':
00287             Printf ("\\\"");
00288             break;
00289         default:
00290             if (iscntrl(uc))
00291                 Printf ("\\%03o",uc);
00292             else
00293                 Printf ("%c",uc);
00294             break;
00295         }
00296     Printf ("\"");
00297 
00298 }
00299 
00300 
00301 /*
00302  * Print list of attribute values, for numeric attributes.  Attribute values
00303  * must be printed with explicit type tags, because CDL doesn't have explicit
00304  * syntax to declare an attribute type.
00305  */
00306 static void
00307 pr_att_vals(
00308      nc_type type,
00309      size_t len,
00310      const double *vals
00311      )
00312 {
00313     int iel;
00314     signed char sc;
00315     short ss;
00316     int ii;
00317     char gps[30];
00318     float ff;
00319     double dd;
00320 #ifdef USE_NETCDF4
00321     unsigned char uc;
00322     unsigned short us;
00323     unsigned int ui;
00324     int64_t i64;
00325     uint64_t ui64;
00326 #endif /* USE_NETCDF4 */
00327     if (len == 0)
00328         return;
00329     for (iel = 0; iel < len-1; iel++) {
00330         switch (type) {
00331         case NC_BYTE:
00332             sc = (signed char) vals[iel] & 0377;
00333             Printf ("%db, ", sc);
00334             break;
00335         case NC_SHORT:
00336             ss = vals[iel];
00337             Printf ("%ds, ", ss);
00338             break;
00339         case NC_INT:
00340             ii = (int) vals[iel];
00341             Printf ("%d, ", ii);
00342             break;
00343         case NC_FLOAT:
00344             ff = vals[iel];
00345             (void) sprintf(gps, float_att_fmt, ff);
00346             tztrim(gps);        /* trim trailing 0's after '.' */
00347             Printf ("%s, ", gps);
00348             break;
00349         case NC_DOUBLE:
00350             dd = vals[iel];
00351             (void) sprintf(gps, double_att_fmt, dd);
00352             tztrim(gps);
00353             Printf ("%s, ", gps);
00354             break;
00355 #ifdef USE_NETCDF4
00356         case NC_UBYTE:
00357             uc = vals[iel];
00358             Printf ("%udub, ", uc);
00359             break;
00360         case NC_USHORT:
00361             us = vals[iel];
00362             Printf ("%huus, ", us);
00363             break;
00364         case NC_UINT:
00365             ui = vals[iel];
00366             Printf ("%u, ", ui);
00367             break;
00368         case NC_INT64:
00369             i64 = vals[iel];
00370             Printf ("%lldL, ", i64);
00371             break;
00372         case NC_UINT64:
00373             ui64 = vals[iel];
00374             Printf ("%lluUL, ", ui64);
00375             break;
00376 #endif
00377         default:
00378             error("pr_att_vals: bad type");
00379         }
00380     }
00381     switch (type) {
00382     case NC_BYTE:
00383         sc = (signed char) vals[iel] & 0377;
00384         Printf ("%db", sc);
00385         break;
00386     case NC_SHORT:
00387         ss = vals[iel];
00388         Printf ("%ds", ss);
00389         break;
00390     case NC_INT:
00391         ii = (int) vals[iel];
00392         Printf ("%d", ii);
00393         break;
00394     case NC_FLOAT:
00395         ff = vals[iel];
00396         (void) sprintf(gps, float_att_fmt, ff);
00397         tztrim(gps);
00398         Printf ("%s", gps);
00399         break;
00400     case NC_DOUBLE:
00401         dd = vals[iel];
00402         (void) sprintf(gps, double_att_fmt, dd);
00403         tztrim(gps);
00404         Printf ("%s", gps);
00405         break;
00406 #ifdef USE_NETCDF4
00407         case NC_UBYTE:
00408             uc = vals[iel];
00409             Printf ("%udub", uc);
00410             break;
00411         case NC_USHORT:
00412             us = vals[iel];
00413             Printf ("%huus", us);
00414             break;
00415         case NC_UINT:
00416             ui = vals[iel];
00417             Printf ("%u", ui);
00418             break;
00419         case NC_INT64:
00420             i64 = vals[iel];
00421             Printf ("%lldL", i64);
00422             break;
00423         case NC_UINT64:
00424             ui64 = vals[iel];
00425             Printf ("%lluUL", ui64);
00426             break;
00427 #endif
00428     default:
00429         error("pr_att_vals: bad type");
00430     }
00431 }
00432 
00433 #ifndef HAVE_STRLCAT
00434 /*      $OpenBSD: strlcat.c,v 1.12 2005/03/30 20:13:52 otto Exp $       */
00435 
00436 /*
00437  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
00438  *
00439  * Permission to use, copy, modify, and distribute this software for any
00440  * purpose with or without fee is hereby granted, provided that the above
00441  * copyright notice and this permission notice appear in all copies.
00442  *
00443  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00444  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00445  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00446  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00447  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00448  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00449  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00450  */
00451 
00452 /*
00453  * Appends src to string dst of size siz (unlike strncat, siz is the
00454  * full size of dst, not space left).  At most siz-1 characters
00455  * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
00456  * Returns strlen(src) + MIN(siz, strlen(initial dst)).
00457  * If retval >= siz, truncation occurred.
00458  */
00459 size_t
00460 strlcat(char *dst, const char *src, size_t siz)
00461 {
00462         char *d = dst;
00463         const char *s = src;
00464         size_t n = siz;
00465         size_t dlen;
00466 
00467         /* Find the end of dst and adjust bytes left but don't go past end */
00468         while (n-- != 0 && *d != '\0')
00469                 d++;
00470         dlen = d - dst;
00471         n = siz - dlen;
00472 
00473         if (n == 0)
00474                 return(dlen + strlen(s));
00475         while (*s != '\0') {
00476                 if (n != 1) {
00477                         *d++ = *s;
00478                         n--;
00479                 }
00480                 s++;
00481         }
00482         *d = '\0';
00483 
00484         return(dlen + (s - src));       /* count does not include NUL */
00485 }
00486 #endif /* ! HAVE_STRLCAT */
00487 
00488 
00489 /*
00490  * Print list of numeric attribute values to string for use in NcML output.
00491  */
00492 static void
00493 pr_att_valsx(
00494      nc_type type,
00495      size_t len,
00496      const double *vals,
00497      char *attvals,             /* returned string */
00498      size_t attvalslen          /* size of attvals buffer, assumed
00499                                    large enough to hold all len
00500                                    blank-separated values */
00501      )
00502 {
00503     int iel;
00504     double dd;
00505     int ii;
00506 #ifdef USE_NETCDF4
00507     unsigned int ui;
00508     int64_t i64;
00509     uint64_t ui64;
00510 #endif /* USE_NETCDF4 */
00511 
00512     attvals[0]='\0';
00513     if (len == 0)
00514         return;
00515     for (iel = 0; iel < len; iel++) {
00516         char gps[50];
00517         switch (type) {
00518         case NC_BYTE:
00519         case NC_SHORT:
00520         case NC_INT:
00521             ii = vals[iel];
00522             (void) sprintf(gps, "%d", ii);
00523             (void) strlcat(attvals, gps, attvalslen);
00524             (void) strlcat(attvals, iel < len-1 ? " " : "", attvalslen);
00525             break;
00526 #ifdef USE_NETCDF4
00527         case NC_UBYTE:
00528         case NC_USHORT:
00529         case NC_UINT:
00530             ui = vals[iel];
00531             (void) sprintf(gps, "%u", ui);
00532             (void) strlcat(attvals, gps, attvalslen);
00533             (void) strlcat(attvals, iel < len-1 ? " " : "", attvalslen);
00534             break;
00535         case NC_INT64:
00536             /* TODO, can't really store a 64-bit int in a double so need different function */
00537             i64 = vals[iel];
00538             (void) sprintf(gps, "%lld", i64);
00539             (void) strlcat(attvals, gps, attvalslen);
00540             (void) strlcat(attvals, iel < len-1 ? " " : "", attvalslen);
00541             break;
00542         case NC_UINT64:
00543             /* TODO, can't really store a 64-bit int in a double so need different function */
00544             ui64 = vals[iel];
00545             (void) sprintf(gps, "%llu", ui64);
00546             (void) strlcat(attvals, gps, attvalslen);
00547             (void) strlcat(attvals, iel < len-1 ? " " : "", attvalslen);
00548             break;
00549 #endif /* USE_NETCDF4 */
00550         case NC_FLOAT:
00551         case NC_DOUBLE:
00552             dd = vals[iel];
00553             (void) sprintf(gps, double_att_fmt, dd);
00554             (void) strlcat(attvals, gps, attvalslen);
00555             (void) strlcat(attvals, iel < len-1 ? " " : "", attvalslen);
00556             break;
00557         default:
00558             error("pr_att_valsx: bad type");
00559         }
00560     }
00561 }
00562 
00563 
00564 static void
00565 pr_att(
00566     int ncid,
00567     int varid,
00568     const char *varname,
00569     int ia
00570     )
00571 {
00572     ncatt_t att;                        /* attribute */
00573             
00574     NC_CHECK( nc_inq_attname(ncid, varid, ia, att.name) );
00575 
00576     Printf ("\t\t%s:%s = ", varname, att.name);
00577 
00578     NC_CHECK( nc_inq_att(ncid, varid, att.name, &att.type, &att.len) );
00579 
00580     if (att.len == 0) { /* show 0-length attributes as empty strings */
00581         att.type = NC_CHAR;
00582     }
00583     switch (att.type) {
00584     case NC_CHAR:
00585         att.string = (char *) emalloc(att.len + 1);
00586         NC_CHECK( nc_get_att_text(ncid, varid, att.name, att.string ) );
00587         pr_att_string(att.len, att.string);
00588         free(att.string);
00589         break;
00590     default:
00591         att.vals = (double *) emalloc((att.len + 1) * sizeof(double));
00592         NC_CHECK( nc_get_att_double(ncid, varid, att.name, att.vals ) );
00593         pr_att_vals(att.type, att.len, att.vals);
00594         free(att.vals);
00595         break;
00596     }
00597     Printf (" ;\n");
00598 }
00599 
00600 
00601 static void
00602 pr_attx(
00603     int ncid,
00604     int varid,
00605     int ia
00606     )
00607 {
00608     ncatt_t att;                        /* attribute */
00609     char *attvals;
00610     int attvalslen = 0;
00611 
00612     NC_CHECK( nc_inq_attname(ncid, varid, ia, att.name) );
00613     NC_CHECK( nc_inq_att(ncid, varid, att.name, &att.type, &att.len) );
00614 
00615     /* Put attribute values into a single string, with blanks in between */
00616 
00617     switch (att.type) {
00618     case NC_CHAR:
00619 #ifdef USE_NETCDF4
00620         /* fall through */
00621     case NC_STRING:
00622 #endif
00623         attvals = (char *) emalloc(att.len + 1);
00624         NC_CHECK( nc_get_att_text(ncid, varid, att.name, attvals ) );
00625         break;
00626 #ifdef USE_NETCDF4
00627         /* TODO
00628            case NC_VLEN:
00629            case NC_OPAQUE:
00630            case NC_COMPOUND:
00631         */
00632 #endif
00633 
00634     default:
00635         att.vals = (double *) emalloc((att.len + 1) * sizeof(double));
00636         NC_CHECK( nc_get_att_double(ncid, varid, att.name, att.vals ) );
00637         attvalslen = 20*att.len; /* max 20 chars for each value and blank separator */
00638         attvals = (char *) emalloc(attvalslen + 1);
00639         pr_att_valsx(att.type, att.len, att.vals, attvals, attvalslen);
00640         free(att.vals); 
00641         free (attvals);
00642         break;
00643     }
00644 
00645     Printf ("%s  <attribute name=\"%s\" type=\"%s\" value=\"%s\" />\n", 
00646             varid != NC_GLOBAL ? "  " : "", 
00647             att.name, 
00648             att.type == NC_CHAR ? "String" : type_name(att.type), 
00649             attvals);
00650 }
00651 
00652 
00653 /* Print optional NcML attribute for a variable's shape */
00654 static void
00655 pr_shape(ncvar_t* varp, ncdim_t *dims)
00656 {
00657     char *shape;
00658     int shapelen = 0;
00659     int id;
00660 
00661     if (varp->ndims == 0)
00662         return;
00663     for (id = 0; id < varp->ndims; id++) {
00664         shapelen += strlen(dims[varp->dims[id]].name) + 1;
00665     }
00666     shape = (char *) emalloc(shapelen);
00667     for (id = 0; id < varp->ndims; id++) {
00668         strlcat(shape, dims[varp->dims[id]].name, shapelen);
00669         strlcat(shape, id < varp->ndims-1 ? " " : "", shapelen);
00670     }
00671     Printf (" shape=\"%s\"", shape);
00672     free(shape);
00673 }
00674 
00675 /* Recursively dump the contents of a group. (Recall that only
00676  * netcdf-4 format files can have groups. On all other formats, there
00677  * is just a root group, so recursion will not take place.) */
00678 static void
00679 do_ncdump_rec(int ncid, const char *path, fspec_t* specp)
00680 {
00681     int ndims;                  /* number of dimensions */
00682     int nvars;                  /* number of variables */
00683     int ngatts;                 /* number of global attributes */
00684     int xdimid;                 /* id of unlimited dimension */
00685     int dimid;                  /* dimension id */
00686     int varid;                  /* variable id */
00687     ncdim_t dims[NC_MAX_DIMS];  /* dimensions */
00688     size_t vdims[NC_MAX_DIMS];  /* dimension sizes for a single variable */
00689     ncvar_t var;                        /* variable */
00690     ncatt_t att;                        /* attribute */
00691     int id;                     /* dimension number per variable */
00692     int ia;                     /* attribute number */
00693     int iv;                     /* variable number */
00694     vnode* vlist = 0;           /* list for vars specified with -v option */
00695     int nc_status;              /* return from netcdf calls */
00696 
00697     /*
00698      * If any vars were specified with -v option, get list of associated
00699      * variable ids
00700      */
00701     if (specp->nlvars > 0) {
00702         vlist = newvlist();     /* list for vars specified with -v option */
00703         for (iv=0; iv < specp->nlvars; iv++) {
00704             NC_CHECK( nc_inq_varid(ncid, specp->lvars[iv], &varid) );
00705             varadd(vlist, varid);
00706         }
00707     }
00708 
00709     /* output initial line, including format variant */
00710     if (path)
00711        pr_fmtvariant(ncid, path, specp);
00712 
00713     /*
00714      * get number of dimensions, number of variables, number of global
00715      * atts, and dimension id of unlimited dimension, if any
00716      */
00717     NC_CHECK( nc_inq(ncid, &ndims, &nvars, &ngatts, &xdimid) );
00718     /* get dimension info */
00719     if (ndims > 0)
00720       Printf ("dimensions:\n");
00721     for (dimid = 0; dimid < ndims; dimid++) {
00722         NC_CHECK( nc_inq_dim(ncid, dimid, dims[dimid].name, &dims[dimid].size) );
00723         if (dimid == xdimid)
00724           Printf ("\t%s = %s ; // (%u currently)\n",dims[dimid].name,
00725                   "UNLIMITED", (unsigned int)dims[dimid].size);
00726         else
00727            Printf ("\t%s = %u ;\n", dims[dimid].name, (unsigned int)dims[dimid].size);
00728     }
00729 
00730     if (nvars > 0)
00731         Printf ("variables:\n");
00732     /* get variable info, with variable attributes */
00733     for (varid = 0; varid < nvars; varid++) {
00734         NC_CHECK( nc_inq_varndims(ncid, varid, &var.ndims) );
00735         var.dims = (int *) emalloc((var.ndims + 1) * sizeof(int));
00736         NC_CHECK( nc_inq_var(ncid, varid, var.name, &var.type, 0,
00737                              var.dims, &var.natts) );
00738         Printf ("\t%s %s", type_name(var.type), var.name);
00739         if (var.ndims > 0)
00740           Printf ("(");
00741         for (id = 0; id < var.ndims; id++) {
00742             Printf ("%s%s",
00743                     dims[var.dims[id]].name,
00744                     id < var.ndims-1 ? ", " : ")");
00745         }
00746         Printf (" ;\n");
00747 
00748         /* get variable attributes */
00749         for (ia = 0; ia < var.natts; ia++)
00750             pr_att(ncid, varid, var.name, ia); /* print ia-th attribute */
00751         free(var.dims);
00752     }
00753 
00754 
00755     /* get global attributes */
00756     if (ngatts > 0)
00757       Printf ("\n// global attributes:\n");
00758     for (ia = 0; ia < ngatts; ia++)
00759         pr_att(ncid, NC_GLOBAL, "", ia); /* print ia-th global attribute */
00760     
00761     if (! specp->header_only) {
00762         if (nvars > 0) {
00763             Printf ("data:\n");
00764         }
00765         /* output variable data */
00766         for (varid = 0; varid < nvars; varid++) {
00767             /* if var list specified, test for membership */
00768             if (specp->nlvars > 0 && ! varmember(vlist, varid))
00769               continue;
00770             NC_CHECK( nc_inq_varndims(ncid, varid, &var.ndims) );
00771             var.dims = (int *) emalloc((var.ndims + 1) * sizeof(int));
00772             NC_CHECK( nc_inq_var(ncid, varid, var.name, &var.type, 0,
00773                             var.dims, &var.natts) );
00774 
00775             /* If coords-only option specified, don't get data for
00776              * non-coordinate vars */
00777             if (specp->coord_vals && !iscoordvar(ncid,varid)) {
00778                 continue;
00779             }
00780 
00781             /* Don't get data for record variables if no records have
00782              * been written yet */
00783             if (isrecvar(ncid, varid) && dims[xdimid].size == 0) {
00784                 continue;
00785             }
00786                 
00787             /* Collect variable's dim sizes */
00788             for (id = 0; id < var.ndims; id++)
00789                 vdims[id] = dims[var.dims[id]].size;
00790             var.has_fillval = 1; /* by default, but turn off for bytes */
00791             
00792             /* get _FillValue attribute */
00793             nc_status = nc_inq_att(ncid,varid,_FillValue,&att.type,&att.len);
00794             if(nc_status == NC_NOERR &&
00795                att.type == var.type && att.len == 1) {
00796                 if(var.type == NC_CHAR) {
00797                     char fillc;
00798                     NC_CHECK( nc_get_att_text(ncid, varid, _FillValue,
00799                                               &fillc ) );
00800                     var.fillval = fillc;
00801                 } else {
00802                     NC_CHECK( nc_get_att_double(ncid, varid, _FillValue,
00803                                                 &var.fillval) );
00804                 }
00805             } else {
00806                 switch (var.type) {
00807                 case NC_BYTE:
00808                     /* don't do default fill-values for bytes, too risky */
00809                     var.has_fillval = 0;
00810                     break;
00811                 case NC_CHAR:
00812                     var.fillval = NC_FILL_CHAR;
00813                     break;
00814                 case NC_SHORT:
00815                     var.fillval = NC_FILL_SHORT;
00816                     break;
00817                 case NC_INT:
00818                     var.fillval = NC_FILL_INT;
00819                     break;
00820                 case NC_FLOAT:
00821                     var.fillval = NC_FILL_FLOAT;
00822                     break;
00823                 case NC_DOUBLE:
00824                     var.fillval = NC_FILL_DOUBLE;
00825                     break;
00826                 default:
00827                     break;
00828                 }
00829             }
00830             if (vardata(&var, vdims, ncid, varid, specp) == -1) {
00831                 error("can't output data for variable %s", var.name);
00832                 NC_CHECK(
00833                          nc_close(ncid) );
00834                 if (vlist)
00835                     free(vlist);
00836                 return;
00837             }
00838         }
00839     }
00840     
00841 #ifdef USE_NETCDF4
00842    /* For netCDF-4 compiles, check to see if the file has any
00843     * groups. If it does, this function is called recursively on each
00844     * of them. */
00845    {
00846       int g, numgrps, *ncids, format;
00847       char group_name[NC_MAX_NAME + 1];
00848 
00849       /* Only netCDF-4 files have groups. */
00850       if ((nc_status = nc_inq_format(ncid, &format)))
00851          error("can't get format"); 
00852 
00853       if (format == NC_FORMAT_NETCDF4)
00854       {
00855          /* See how many groups there are. */
00856          if ((nc_status = nc_inq_grps(ncid, &numgrps, NULL))) 
00857             error("can't read groups"); 
00858          
00859          /* Allocate memory to hold the list of group ids. */
00860          if (!(ncids = malloc(numgrps * sizeof(int))))
00861             error("out of memory");
00862          
00863          /* Get the list of group ids. */
00864          nc_status = nc_inq_grps(ncid, NULL, ncids);
00865          
00866          /* Call this function for each group. */
00867          for (g = 0; g < numgrps; g++)
00868          {
00869             if (nc_inq_grpname(ncids[g], group_name))
00870                error("can't find group's name");               
00871             Printf ("\ngroup: %s {\n", group_name);
00872             do_ncdump_rec(ncids[g], NULL, specp);
00873          }
00874          
00875          free(ncids);
00876       }
00877    }
00878 #endif /* USE_NETCDF4 */
00879 
00880     Printf ("}\n");
00881     if (vlist)
00882         free(vlist);
00883 }
00884 
00885 
00886 static void
00887 do_ncdump(const char *path, fspec_t* specp)
00888 {
00889    int nc_status;
00890    int ncid;
00891 
00892    nc_status = nc_open(path, NC_NOWRITE, &ncid);
00893    if (nc_status != NC_NOERR) {
00894       error("%s: %s", path, nc_strerror(nc_status));
00895    }
00896 
00897    do_ncdump_rec(ncid, path, specp);
00898    NC_CHECK( nc_close(ncid) );
00899 }
00900 
00901 static void
00902 do_ncdumpx(const char *path, fspec_t* specp)
00903 {
00904     int ndims;                  /* number of dimensions */
00905     int nvars;                  /* number of variables */
00906     int ngatts;                 /* number of global attributes */
00907     int xdimid;                 /* id of unlimited dimension */
00908     int dimid;                  /* dimension id */
00909     int varid;                  /* variable id */
00910     ncdim_t dims[NC_MAX_DIMS]; /* dimensions */
00911     size_t vdims[NC_MAX_DIMS];  /* dimension sizes for a single variable */
00912     ncvar_t var;                /* variable */
00913     ncatt_t att;                /* attribute */
00914     int id;                     /* dimension number per variable */
00915     int ia;                     /* attribute number */
00916     int iv;                     /* variable number */
00917     int ncid;                   /* netCDF id */
00918     vnode* vlist = 0;           /* list for vars specified with -v option */
00919     int nc_status;              /* return from netcdf calls */
00920 
00921     nc_status = nc_open(path, NC_NOWRITE, &ncid);
00922     if (nc_status != NC_NOERR) {
00923         error("%s: %s", path, nc_strerror(nc_status));
00924     }
00925     /*
00926      * If any vars were specified with -v option, get list of associated
00927      * variable ids
00928      */
00929     if (specp->nlvars > 0) {
00930         vlist = newvlist();     /* list for vars specified with -v option */
00931         for (iv=0; iv < specp->nlvars; iv++) {
00932             NC_CHECK( nc_inq_varid(ncid, specp->lvars[iv], &varid) );
00933             varadd(vlist, varid);
00934         }
00935     }
00936 
00937     /* output initial line, including format variant */
00938     pr_fmtvariantx(ncid, path);
00939 
00940     /*
00941      * get number of dimensions, number of variables, number of global
00942      * atts, and dimension id of unlimited dimension, if any
00943      */
00944     NC_CHECK( nc_inq(ncid, &ndims, &nvars, &ngatts, &xdimid) );
00945     /* get dimension info */
00946     for (dimid = 0; dimid < ndims; dimid++) {
00947         NC_CHECK( nc_inq_dim(ncid, dimid, dims[dimid].name, &dims[dimid].size) );
00948         if (dimid == xdimid)
00949           Printf("  <dimension name=\"%s\" length=\"%d\" isUnlimited=\"true\" />\n", 
00950                  dims[dimid].name, (int)dims[dimid].size);
00951         else
00952           Printf ("  <dimension name=\"%s\" length=\"%d\" />\n", 
00953                   dims[dimid].name, (int)dims[dimid].size);
00954     }
00955 
00956     /* get global attributes */
00957     for (ia = 0; ia < ngatts; ia++)
00958         pr_attx(ncid, NC_GLOBAL, ia); /* print ia-th global attribute */
00959 
00960     /* get variable info, with variable attributes */
00961     for (varid = 0; varid < nvars; varid++) {
00962         NC_CHECK( nc_inq_varndims(ncid, varid, &var.ndims) );
00963         var.dims = (int *) emalloc((var.ndims + 1) * sizeof(int));
00964         NC_CHECK( nc_inq_var(ncid, varid, var.name, &var.type, 0,
00965                              var.dims, &var.natts) );
00966         Printf ("  <variable name=\"%s\"", var.name);
00967         pr_shape(&var, dims);
00968 
00969         /* handle one-line variable elements that aren't containers
00970            for attributes or data values, since they need to be
00971            rendered as <variable ... /> instead of <variable ..>
00972            ... </variable> */
00973         if (var.natts == 0) {
00974             if (
00975                 /* header-only specified */
00976                 (specp->header_only) ||
00977                 /* list of variables specified and this variable not in list */
00978                 (specp->nlvars > 0 && !varmember(vlist, varid)) ||
00979                 /* coordinate vars only and this is not a coordinate variable */
00980                 (specp->coord_vals && !iscoordvar(ncid, varid)) ||
00981                 /* this is a record variable, but no records have been written */
00982                 (isrecvar(ncid,varid) && dims[xdimid].size == 0)
00983                 ) {
00984                 Printf (" type=\"%s\" />\n", type_name(var.type));
00985                 continue;
00986             }
00987         }
00988 
00989         /* else nest attributes values, data values in <variable> ... </variable> */
00990         Printf (" type=\"%s\">\n", type_name(var.type));
00991 
00992         /* get variable attributes */
00993         for (ia = 0; ia < var.natts; ia++) {
00994             pr_attx(ncid, varid, ia); /* print ia-th attribute */
00995         }
00996         if (! specp->header_only) {
00997             /* if var list specified, test for membership */
00998             if (specp->nlvars > 0 && ! varmember(vlist, varid)) {
00999                 continue;
01000             }
01001             /* output variable data */
01002             if (specp->coord_vals) {
01003                 /* don't get data for non-coordinate vars */
01004                 if (!iscoordvar(ncid, varid)) {
01005                     continue;
01006                 }
01007             }
01008             /*
01009              * Only get data for variable if it is not a record variable,
01010              * or if it is a record variable and at least one record has
01011              * been written.
01012              */
01013             if (var.ndims == 0
01014                 || var.dims[0] != xdimid
01015                 || dims[xdimid].size != 0) {
01016                 
01017                 /* Collect variable's dim sizes */
01018                 for (id = 0; id < var.ndims; id++)
01019                     vdims[id] = dims[var.dims[id]].size;
01020                 var.has_fillval = 1; /* by default, but turn off for bytes */
01021 
01022                 /* get _FillValue attribute */
01023                 nc_status = nc_inq_att(ncid,varid,_FillValue,&att.type,&att.len);
01024                 if(nc_status == NC_NOERR &&
01025                    att.type == var.type && att.len == 1) {
01026                     if(var.type == NC_CHAR) {
01027                         char fillc;
01028                         NC_CHECK( nc_get_att_text(ncid, varid, _FillValue,
01029                                                   &fillc ) );
01030                         var.fillval = fillc;
01031                     } else {
01032                         NC_CHECK( nc_get_att_double(ncid, varid, _FillValue,
01033                                                     &var.fillval) );
01034                     }
01035                 } else {
01036                     switch (var.type) {
01037                     case NC_BYTE:
01038                         /* don't do default fill-values for bytes, too risky */
01039                         var.has_fillval = 0;
01040                         break;
01041                     case NC_CHAR:
01042                         var.fillval = NC_FILL_CHAR;
01043                         break;
01044                     case NC_SHORT:
01045                         var.fillval = NC_FILL_SHORT;
01046                         break;
01047                     case NC_INT:
01048                         var.fillval = NC_FILL_INT;
01049                         break;
01050                     case NC_FLOAT:
01051                         var.fillval = NC_FILL_FLOAT;
01052                         break;
01053                     case NC_DOUBLE:
01054                         var.fillval = NC_FILL_DOUBLE;
01055                         break;
01056                     default:
01057                         break;
01058                     }
01059                 }
01060                 if (vardatax(&var, vdims, ncid, varid, specp) == -1) {
01061                     error("can't output data for variable %s", var.name);
01062                     NC_CHECK(nc_close(ncid) );
01063                     if (vlist)
01064                         free(vlist);
01065                     return;
01066                 }
01067             }
01068         }
01069         Printf ("  </variable>\n");
01070     }
01071     
01072     Printf ("</netcdf>\n");
01073     NC_CHECK(
01074         nc_close(ncid) );
01075     if (vlist)
01076         free(vlist);
01077 }
01078 
01079 
01080 static void
01081 make_lvars(char *optarg, fspec_t* fspecp)
01082 {
01083     char *cp = optarg;
01084     int nvars = 1;
01085     char ** cpp;
01086 
01087     /* compute number of variable names in comma-delimited list */
01088     fspecp->nlvars = 1;
01089     while (*cp++)
01090       if (*cp == ',')
01091         nvars++;
01092 
01093     fspecp->lvars = (char **) emalloc(nvars * sizeof(char*));
01094 
01095     cpp = fspecp->lvars;
01096     /* copy variable names into list */
01097     for (cp = strtok(optarg, ",");
01098          cp != NULL;
01099          cp = strtok((char *) NULL, ",")) {
01100         
01101         *cpp = (char *) emalloc(strlen(cp) + 1);
01102         strcpy(*cpp, cp);
01103         cpp++;
01104     }
01105     fspecp->nlvars = nvars;
01106 }
01107 
01108 
01109 /*
01110  * Extract the significant-digits specifiers from the -d argument on the
01111  * command-line and update the default data formats appropriately.
01112  */
01113 static void
01114 set_sigdigs(const char *optarg)
01115 {
01116     char *ptr1 = 0;
01117     char *ptr2 = 0;
01118     int flt_digits = FLT_DIGITS; /* default floating-point digits */
01119     int dbl_digits = DBL_DIGITS; /* default double-precision digits */
01120 
01121     if (optarg != 0 && (int) strlen(optarg) > 0 && optarg[0] != ',')
01122         flt_digits = (int)strtol(optarg, &ptr1, 10);
01123 
01124     if (flt_digits < 1 || flt_digits > 20) {
01125         error("unreasonable value for float significant digits: %d",
01126               flt_digits);
01127     }
01128     if (*ptr1 == ',')
01129       dbl_digits = (int)strtol(ptr1+1, &ptr2, 10);
01130     if (ptr2 == ptr1+1 || dbl_digits < 1 || dbl_digits > 20) {
01131         error("unreasonable value for double significant digits: %d",
01132               dbl_digits);
01133     }
01134     set_formats(flt_digits, dbl_digits);
01135 }
01136 
01137 
01138 /*
01139  * Extract the significant-digits specifiers from the -p argument on the
01140  * command-line, set flags so we can override C_format attributes (if any),
01141  * and update the default data formats appropriately.
01142  */
01143 static void
01144 set_precision(const char *optarg)
01145 {
01146     char *ptr1 = 0;
01147     char *ptr2 = 0;
01148     int flt_digits = FLT_DIGITS;        /* default floating-point digits */
01149     int dbl_digits = DBL_DIGITS;        /* default double-precision digits */
01150 
01151     if (optarg != 0 && (int) strlen(optarg) > 0 && optarg[0] != ',') {
01152         flt_digits = (int)strtol(optarg, &ptr1, 10);
01153         float_precision_specified = 1;
01154     }
01155 
01156     if (flt_digits < 1 || flt_digits > 20) {
01157         error("unreasonable value for float significant digits: %d",
01158               flt_digits);
01159     }
01160     if (*ptr1 == ',') {
01161         dbl_digits = (int) strtol(ptr1+1, &ptr2, 10);
01162         double_precision_specified = 1;
01163     }
01164     if (ptr2 == ptr1+1 || dbl_digits < 1 || dbl_digits > 20) {
01165         error("unreasonable value for double significant digits: %d",
01166               dbl_digits);
01167     }
01168     set_formats(flt_digits, dbl_digits);
01169 }
01170 
01171 
01172 int
01173 main(int argc, char *argv[])
01174 {
01175     extern int optind;
01176     extern int opterr;
01177     extern char *optarg;
01178     static fspec_t fspec =      /* defaults, overridden on command line */
01179       {
01180           0,                    /* construct netcdf name from file name */
01181           false,                /* print header info only, no data? */
01182           false,                /* just print coord vars? */
01183           false,                /* brief  comments in data section? */
01184           false,                /* full annotations in data section?  */
01185           LANG_C,               /* language conventions for indices */
01186           0,                    /* if -v specified, number of variables */
01187           0                     /* if -v specified, list of variable names */
01188           };
01189     int c;
01190     int i;
01191     int max_len = 80;           /* default maximum line length */
01192     int nameopt = 0;
01193     boolean xml_out = false;    /* if true, output NcML instead of CDL */
01194 
01195     opterr = 1;
01196     progname = argv[0];
01197     set_formats(FLT_DIGITS, DBL_DIGITS); /* default for float, double data */
01198 
01199     while ((c = getopt(argc, argv, "b:cf:hl:n:v:d:p:x")) != EOF)
01200       switch(c) {
01201         case 'h':               /* dump header only, no data */
01202           fspec.header_only = true;
01203           break;
01204         case 'c':               /* header, data only for coordinate dims */
01205           fspec.coord_vals = true;
01206           break;
01207         case 'n':               /*
01208                                  * provide different name than derived from
01209                                  * file name
01210                                  */
01211           fspec.name = optarg;
01212           nameopt = 1;
01213           break;
01214         case 'b':               /* brief comments in data section */
01215           fspec.brief_data_cmnts = true;
01216           switch (tolower(optarg[0])) {
01217             case 'c':
01218               fspec.data_lang = LANG_C;
01219               break;
01220             case 'f':
01221               fspec.data_lang = LANG_F;
01222               break;
01223             default:
01224               error("invalid value for -b option: %s", optarg);
01225           }
01226           break;
01227         case 'f':               /* full comments in data section */
01228           fspec.full_data_cmnts = true;
01229           switch (tolower(optarg[0])) {
01230             case 'c':
01231               fspec.data_lang = LANG_C;
01232               break;
01233             case 'f':
01234               fspec.data_lang = LANG_F;
01235               break;
01236             default:
01237               error("invalid value for -f option: %s", optarg);
01238           }
01239           break;
01240         case 'l':               /* maximum line length */
01241           max_len = (int) strtol(optarg, 0, 0);
01242           if (max_len < 10) {
01243               error("unreasonably small line length specified: %d", max_len);
01244           }
01245           break;
01246         case 'v':               /* variable names */
01247           /* make list of names of variables specified */
01248           make_lvars (optarg, &fspec);
01249           break;
01250         case 'd':               /* specify precision for floats (old option) */
01251           set_sigdigs(optarg);
01252           break;
01253         case 'p':               /* specify precision for floats */
01254           set_precision(optarg);
01255           break;
01256         case 'x':               /* XML output (NcML) */
01257           xml_out = true;
01258           break;
01259         case '?':
01260           usage();
01261           break;
01262       }
01263 
01264     set_max_len(max_len);
01265     
01266     argc -= optind;
01267     argv += optind;
01268 
01269     i = 0;
01270 
01271     do {                
01272         if (!nameopt) 
01273             fspec.name = name_path(argv[i]);
01274         if (argc > 0) {
01275             if (xml_out) {
01276                 do_ncdumpx(argv[i], &fspec);
01277             } else {
01278                 do_ncdump(argv[i], &fspec);
01279             }
01280         }
01281     } while (++i < argc);
01282 #ifdef vms
01283     exit(EXIT_SUCCESS);
01284 #else
01285     return EXIT_SUCCESS;
01286 #endif
01287 }

Generated on Thu Mar 16 18:10:13 2006 for nco by  doxygen 1.4.4