00001 
00002 
00003 
00004 
00005 
00006 
00007 #include <stdio.h>
00008 #include <stdlib.h>
00009 #include <string.h>
00010 #include <ctype.h>
00011 #include <stdlib.h>
00012 
00013 #include <netcdf.h>
00014 #include "ncdump.h"
00015 #include "dumplib.h"
00016 #include "vardata.h"
00017 
00018 static void usage(void);
00019 static char* name_path(const char* path);
00020 static char* type_name(nc_type  type);
00021 static void tztrim(char* ss);
00022 static void pr_att_string(size_t len, const char* string);
00023 static void pr_att_vals(nc_type  type, size_t len, const double* vals);
00024 static void pr_att(int ncid, int varid, const char *varname, int ia);
00025 static void do_ncdump(const char* path, struct fspec* specp);
00026 static void make_lvars(char* optarg, struct fspec* fspecp);
00027 static void set_sigdigs( const char* optarg);
00028 static void set_precision( const char *optarg);
00029 int main(int argc, char** argv);
00030 
00031 #define STREQ(a, b)     (*(a) == *(b) && strcmp((a), (b)) == 0)
00032 
00033 char *progname;
00034 
00035 static void
00036 usage(void)
00037 {
00038 #define USAGE   "\
00039   [-c]             Coordinate variable data and header information\n\
00040   [-h]             Header information only, no data\n\
00041   [-v var1[,...]]  Data for variable(s) <var1>,... only\n\
00042   [-b [c|f]]       Brief annotations for C or Fortran indices in data\n\
00043   [-f [c|f]]       Full annotations for C or Fortran indices in data\n\
00044   [-l len]         Line length maximum in data section (default 80)\n\
00045   [-n name]        Name for netCDF (default derived from file name)\n\
00046   [-p n[,n]]       Display floating-point values with less precision\n\
00047   file             File name of input netCDF file\n"
00048 
00049     (void) fprintf(stderr,
00050                    "%s [-c|-h] [-v ...] [[-b|-f] [c|f]] [-l len] [-n name] [-p n[,n]] file\n%s",
00051                    progname,
00052                    USAGE);
00053     
00054     (void) fprintf(stderr,
00055                  "netcdf library version %s\n",
00056                  nc_inq_libvers());
00057     exit(EXIT_FAILURE);
00058 }
00059 
00060 
00061 
00062 
00063 
00064 
00065 static char *
00066 name_path(const char *path)
00067 {
00068     const char *cp;
00069     char *newName;
00070     char *sp;
00071 
00072 #ifdef vms
00073 #define FILE_DELIMITER ']'
00074 #endif    
00075 #ifdef MSDOS
00076 #define FILE_DELIMITER '\\'
00077 #endif    
00078 #ifndef FILE_DELIMITER 
00079 #define FILE_DELIMITER '/'
00080 #endif
00081     cp = strrchr(path, FILE_DELIMITER);
00082     if (cp == 0)                
00083       cp = path;
00084     else                        
00085       cp++;
00086     newName = (char *) malloc((unsigned) (strlen(cp)+1));
00087     if (newName == 0) {
00088         error("out of memory!");
00089     }
00090     (void) strcpy(newName, cp); 
00091     if ((sp = strrchr(newName, '.')) != NULL)
00092       *sp = '\0';               
00093     return newName;
00094 }
00095 
00096 
00097 static char *
00098 type_name(nc_type type)
00099 {
00100     switch (type) {
00101       case NC_BYTE:
00102         return "byte";
00103       case NC_CHAR:
00104         return "char";
00105       case NC_SHORT:
00106         return "short";
00107       case NC_INT:
00108         return "int";
00109       case NC_FLOAT:
00110         return "float";
00111       case NC_DOUBLE:
00112         return "double";
00113       default:
00114         error("type_name: bad type %d", type);
00115         return "bogus";
00116     }
00117 }
00118 
00119 
00120 
00121 
00122 
00123 
00124 
00125 static void
00126 tztrim(char *ss)
00127 {
00128     char *cp, *ep;
00129     
00130     cp = ss;
00131     if (*cp == '-')
00132       cp++;
00133     while(isdigit((int)*cp) || *cp == '.')
00134       cp++;
00135     if (*--cp == '.')
00136       return;
00137     ep = cp+1;
00138     while (*cp == '0')
00139       cp--;
00140     cp++;
00141     if (cp == ep)
00142       return;
00143     while (*ep)
00144       *cp++ = *ep++;
00145     *cp = '\0';
00146     return;
00147 }
00148 
00149 
00150 
00151 
00152 
00153 static void
00154 pr_att_string(
00155      size_t len,
00156      const char *string
00157      )
00158 {
00159     int iel;
00160     const char *cp;
00161     const char *sp;
00162     unsigned char uc;
00163 
00164     cp = string;
00165     Printf ("\"");
00166     
00167     sp = cp + len - 1;
00168     while (len != 0 && *sp-- == '\0')
00169         len--;
00170     for (iel = 0; iel < len; iel++)
00171         switch (uc = *cp++ & 0377) {
00172         case '\b':
00173             Printf ("\\b");
00174             break;
00175         case '\f':
00176             Printf ("\\f");
00177             break;
00178         case '\n':              
00179             Printf ("\\n\",\n    \"");
00180             break;
00181         case '\r':
00182             Printf ("\\r");
00183             break;
00184         case '\t':
00185             Printf ("\\t");
00186             break;
00187         case '\v':
00188             Printf ("\\v");
00189             break;
00190         case '\\':
00191             Printf ("\\\\");
00192             break;
00193         case '\'':
00194             Printf ("\\'");
00195             break;
00196         case '\"':
00197             Printf ("\\\"");
00198             break;
00199         default:
00200             Printf ("%c",uc);
00201             break;
00202         }
00203     Printf ("\"");
00204 
00205 }
00206 
00207 
00208 
00209 
00210 
00211 
00212 
00213 static void
00214 pr_att_vals(
00215      nc_type type,
00216      size_t len,
00217      const double *vals
00218      )
00219 {
00220     int iel;
00221     signed char sc;
00222     short ss;
00223     int ii;
00224     char gps[30];
00225     float ff;
00226     double dd;
00227 
00228     if (len == 0)
00229         return;
00230     for (iel = 0; iel < len-1; iel++) {
00231         switch (type) {
00232         case NC_BYTE:
00233             sc = (signed char) vals[iel] & 0377;
00234             Printf ("%db, ", sc);
00235             break;
00236         case NC_SHORT:
00237             ss = vals[iel];
00238             Printf ("%ds, ", ss);
00239             break;
00240         case NC_INT:
00241             ii = (int) vals[iel];
00242             Printf ("%d, ", ii);
00243             break;
00244         case NC_FLOAT:
00245             ff = vals[iel];
00246             (void) sprintf(gps, float_att_fmt, ff);
00247             tztrim(gps);        
00248             Printf ("%s, ", gps);
00249             break;
00250         case NC_DOUBLE:
00251             dd = vals[iel];
00252             (void) sprintf(gps, double_att_fmt, dd);
00253             tztrim(gps);
00254             Printf ("%s, ", gps);
00255             break;
00256         default:
00257             error("pr_att_vals: bad type");
00258         }
00259     }
00260     switch (type) {
00261     case NC_BYTE:
00262         sc = (signed char) vals[iel] & 0377;
00263         Printf ("%db", sc);
00264         break;
00265     case NC_SHORT:
00266         ss = vals[iel];
00267         Printf ("%ds", ss);
00268         break;
00269     case NC_INT:
00270         ii = (int) vals[iel];
00271         Printf ("%d", ii);
00272         break;
00273     case NC_FLOAT:
00274         ff = vals[iel];
00275         (void) sprintf(gps, float_att_fmt, ff);
00276         tztrim(gps);
00277         Printf ("%s", gps);
00278         break;
00279     case NC_DOUBLE:
00280         dd = vals[iel];
00281         (void) sprintf(gps, double_att_fmt, dd);
00282         tztrim(gps);
00283         Printf ("%s", gps);
00284         break;
00285     default:
00286         error("pr_att_vals: bad type");
00287     }
00288 }
00289 
00290 
00291 static void
00292 pr_att(
00293     int ncid,
00294     int varid,
00295     const char *varname,
00296     int ia
00297     )
00298 {
00299     struct ncatt att;           
00300             
00301     NC_CHECK( nc_inq_attname(ncid, varid, ia, att.name) );
00302 
00303     Printf ("\t\t%s:%s = ", varname, att.name);
00304 
00305     NC_CHECK( nc_inq_att(ncid, varid, att.name, &att.type, &att.len) );
00306 
00307     if (att.len == 0) { 
00308         att.type = NC_CHAR;
00309         att.len = 1;
00310     }
00311     switch (att.type) {
00312     case NC_CHAR:
00313         att.string = (char *) malloc(att.len);
00314         if (!att.string) {
00315             error("Out of memory!");
00316             NC_CHECK( nc_close(ncid) );
00317             return;
00318         }
00319         NC_CHECK( nc_get_att_text(ncid, varid, att.name, att.string ) );
00320         pr_att_string(att.len, att.string);
00321         free(att.string);
00322         break;
00323     default:
00324         att.vals = (double *) malloc(att.len * sizeof(double));
00325         if (!att.vals) {
00326             error("Out of memory!");
00327             NC_CHECK( nc_close(ncid) );
00328             return;
00329         }
00330         NC_CHECK( nc_get_att_double(ncid, varid, att.name, att.vals ) );
00331         pr_att_vals(att.type, att.len, att.vals);
00332         free(att.vals);
00333         break;
00334     }
00335     Printf (" ;\n");
00336 }
00337 
00338 
00339 static void
00340 do_ncdump(const char *path, struct fspec* specp)
00341 {
00342     int ndims;                  
00343     int nvars;                  
00344     int ngatts;                 
00345     int xdimid;                 
00346     int dimid;                  
00347     int varid;                  
00348     struct ncdim dims[NC_MAX_DIMS]; 
00349     size_t vdims[NC_MAX_DIMS];  
00350     struct ncvar var;           
00351     struct ncatt att;           
00352     int id;                     
00353     int ia;                     
00354     int iv;                     
00355     int is_coord;               
00356     int ncid;                   
00357     vnode* vlist = 0;           
00358     int nc_status;              
00359 
00360     nc_status = nc_open(path, NC_NOWRITE, &ncid);
00361     if (nc_status != NC_NOERR) {
00362         error("%s: %s", path, nc_strerror(nc_status));
00363     }
00364     
00365 
00366 
00367 
00368     if (specp->nlvars > 0) {
00369         vlist = newvlist();     
00370         for (iv=0; iv < specp->nlvars; iv++) {
00371             NC_CHECK( nc_inq_varid(ncid, specp->lvars[iv], &varid) );
00372             varadd(vlist, varid);
00373         }
00374     }
00375 
00376     
00377     if (specp->name == (char *)0) {
00378         specp->name = name_path (path);
00379     }
00380 
00381     Printf ("netcdf %s {\n", specp->name);
00382     
00383 
00384 
00385 
00386     NC_CHECK( nc_inq(ncid, &ndims, &nvars, &ngatts, &xdimid) );
00387     
00388     if (ndims > 0)
00389       Printf ("dimensions:\n");
00390     for (dimid = 0; dimid < ndims; dimid++) {
00391         NC_CHECK( nc_inq_dim(ncid, dimid, dims[dimid].name, &dims[dimid].size) );
00392         if (dimid == xdimid)
00393           Printf ("\t%s = %s ; // (%ld currently)\n",dims[dimid].name,
00394                   "UNLIMITED", (long)dims[dimid].size);
00395         else
00396           Printf ("\t%s = %ld ;\n", dims[dimid].name, (long)dims[dimid].size);
00397     }
00398 
00399     if (nvars > 0)
00400         Printf ("variables:\n");
00401     
00402     for (varid = 0; varid < nvars; varid++) {
00403         NC_CHECK( nc_inq_var(ncid, varid, var.name, &var.type, &var.ndims,
00404                              var.dims, &var.natts) );
00405         Printf ("\t%s %s", type_name(var.type), var.name);
00406         if (var.ndims > 0)
00407           Printf ("(");
00408         for (id = 0; id < var.ndims; id++) {
00409             Printf ("%s%s",
00410                     dims[var.dims[id]].name,
00411                     id < var.ndims-1 ? ", " : ")");
00412         }
00413         Printf (" ;\n");
00414 
00415         
00416         for (ia = 0; ia < var.natts; ia++)
00417             pr_att(ncid, varid, var.name, ia); 
00418     }
00419 
00420 
00421     
00422     if (ngatts > 0)
00423       Printf ("\n// global attributes:\n");
00424     for (ia = 0; ia < ngatts; ia++)
00425         pr_att(ncid, NC_GLOBAL, "", ia); 
00426     
00427     if (! specp->header_only) {
00428         if (nvars > 0) {
00429             Printf ("data:\n");
00430         }
00431         
00432         for (varid = 0; varid < nvars; varid++) {
00433             
00434             if (specp->nlvars > 0 && ! varmember(vlist, varid))
00435               continue;
00436             NC_CHECK( nc_inq_var(ncid, varid, var.name, &var.type, &var.ndims,
00437                             var.dims, &var.natts) );
00438             if (specp->coord_vals) {
00439                 
00440                 is_coord = 0;
00441                 for (dimid = 0; dimid < ndims; dimid++) {
00442                     if (strcmp(dims[dimid].name, var.name) == 0 &&
00443                         var.ndims == 1) {
00444                         is_coord = 1;
00445                         break;
00446                     }
00447                 }
00448                 if (! is_coord) 
00449                   continue;
00450             }
00451             
00452 
00453 
00454 
00455 
00456             if (var.ndims == 0
00457                 || var.dims[0] != xdimid
00458                 || dims[xdimid].size != 0) {
00459 
00460                 
00461                 for (id = 0; id < var.ndims; id++)
00462                   vdims[id] = dims[var.dims[id]].size;
00463                 var.has_fillval = 1; 
00464 
00465                 
00466                 nc_status = nc_inq_att(ncid,varid,_FillValue,&att.type,&att.len);
00467                 if(nc_status == NC_NOERR &&
00468                    att.type == var.type && att.len == 1) {
00469                     if(var.type == NC_CHAR) {
00470                         char fillc;
00471                         NC_CHECK( nc_get_att_text(ncid, varid, _FillValue,
00472                                                   &fillc ) );
00473                         var.fillval = fillc;
00474                     } else {
00475                         NC_CHECK( nc_get_att_double(ncid, varid, _FillValue,
00476                                                     &var.fillval) );
00477                     }
00478                 } else {
00479                     switch (var.type) {
00480                     case NC_BYTE:
00481                         
00482                         var.has_fillval = 0;
00483                         break;
00484                     case NC_CHAR:
00485                         var.fillval = NC_FILL_CHAR;
00486                         break;
00487                     case NC_SHORT:
00488                         var.fillval = NC_FILL_SHORT;
00489                         break;
00490                     case NC_INT:
00491                         var.fillval = NC_FILL_INT;
00492                         break;
00493                     case NC_FLOAT:
00494                         var.fillval = NC_FILL_FLOAT;
00495                         break;
00496                     case NC_DOUBLE:
00497                         var.fillval = NC_FILL_DOUBLE;
00498                         break;
00499                     default:
00500                         break;
00501                     }
00502                 }
00503                 if (vardata(&var, vdims, ncid, varid, specp) == -1) {
00504                     error("can't output data for variable %s", var.name);
00505                     NC_CHECK(
00506                         nc_close(ncid) );
00507                     if (vlist)
00508                         free(vlist);
00509                     return;
00510                 }
00511             }
00512         }
00513     }
00514     
00515     Printf ("}\n");
00516     NC_CHECK(
00517         nc_close(ncid) );
00518     if (vlist)
00519         free(vlist);
00520 }
00521 
00522 
00523 static void
00524 make_lvars(char *optarg, struct fspec* fspecp)
00525 {
00526     char *cp = optarg;
00527     int nvars = 1;
00528     char ** cpp;
00529 
00530     
00531     fspecp->nlvars = 1;
00532     while (*cp++)
00533       if (*cp == ',')
00534         nvars++;
00535 
00536     fspecp->lvars = (char **) malloc(nvars * sizeof(char*));
00537     if (!fspecp->lvars) {
00538         error("out of memory");
00539     }
00540 
00541     cpp = fspecp->lvars;
00542     
00543     for (cp = strtok(optarg, ",");
00544          cp != NULL;
00545          cp = strtok((char *) NULL, ",")) {
00546         
00547         *cpp = (char *) malloc(strlen(cp) + 1);
00548         if (!*cpp) {
00549             error("out of memory");
00550         }
00551         strcpy(*cpp, cp);
00552         cpp++;
00553     }
00554     fspecp->nlvars = nvars;
00555 }
00556 
00557 
00558 
00559 
00560 
00561 
00562 static void
00563 set_sigdigs(const char *optarg)
00564 {
00565     char *ptr1 = 0;
00566     char *ptr2 = 0;
00567     int flt_digits = FLT_DIGITS; 
00568     int dbl_digits = DBL_DIGITS; 
00569 
00570     if (optarg != 0 && (int) strlen(optarg) > 0 && optarg[0] != ',')
00571         flt_digits = (int)strtol(optarg, &ptr1, 10);
00572 
00573     if (flt_digits < 1 || flt_digits > 20) {
00574         error("unreasonable value for float significant digits: %d",
00575               flt_digits);
00576     }
00577     if (*ptr1 == ',')
00578       dbl_digits = (int)strtol(ptr1+1, &ptr2, 10);
00579     if (ptr2 == ptr1+1 || dbl_digits < 1 || dbl_digits > 20) {
00580         error("unreasonable value for double significant digits: %d",
00581               dbl_digits);
00582     }
00583     set_formats(flt_digits, dbl_digits);
00584 }
00585 
00586 
00587 
00588 
00589 
00590 
00591 
00592 static void
00593 set_precision(const char *optarg)
00594 {
00595     char *ptr1 = 0;
00596     char *ptr2 = 0;
00597     int flt_digits = FLT_DIGITS;        
00598     int dbl_digits = DBL_DIGITS;        
00599 
00600     if (optarg != 0 && (int) strlen(optarg) > 0 && optarg[0] != ',') {
00601         flt_digits = (int)strtol(optarg, &ptr1, 10);
00602         float_precision_specified = 1;
00603     }
00604 
00605     if (flt_digits < 1 || flt_digits > 20) {
00606         error("unreasonable value for float significant digits: %d",
00607               flt_digits);
00608     }
00609     if (*ptr1 == ',') {
00610         dbl_digits = (int) strtol(ptr1+1, &ptr2, 10);
00611         double_precision_specified = 1;
00612     }
00613     if (ptr2 == ptr1+1 || dbl_digits < 1 || dbl_digits > 20) {
00614         error("unreasonable value for double significant digits: %d",
00615               dbl_digits);
00616     }
00617     set_formats(flt_digits, dbl_digits);
00618 }
00619 
00620 
00621 int
00622 main(int argc, char *argv[])
00623 {
00624     extern int optind;
00625     extern int opterr;
00626     extern char *optarg;
00627     static struct fspec fspec = 
00628       {
00629           0,                    
00630           false,                
00631           false,                
00632           false,                
00633           false,                
00634           LANG_C,               
00635           0,                    
00636           0                     
00637           };
00638     int c;
00639     int i;
00640     int max_len = 80;           
00641     int nameopt = 0;
00642 
00643     opterr = 1;
00644     progname = argv[0];
00645     set_formats(FLT_DIGITS, DBL_DIGITS); 
00646 
00647     while ((c = getopt(argc, argv, "b:cf:hl:n:v:d:p:")) != EOF)
00648       switch(c) {
00649         case 'h':               
00650           fspec.header_only = true;
00651           break;
00652         case 'c':               
00653           fspec.coord_vals = true;
00654           break;
00655         case 'n':               
00656 
00657 
00658 
00659           fspec.name = optarg;
00660           nameopt = 1;
00661           break;
00662         case 'b':               
00663           fspec.brief_data_cmnts = true;
00664           switch (tolower(optarg[0])) {
00665             case 'c':
00666               fspec.data_lang = LANG_C;
00667               break;
00668             case 'f':
00669               fspec.data_lang = LANG_F;
00670               break;
00671             default:
00672               error("invalid value for -b option: %s", optarg);
00673           }
00674           break;
00675         case 'f':               
00676           fspec.full_data_cmnts = true;
00677           switch (tolower(optarg[0])) {
00678             case 'c':
00679               fspec.data_lang = LANG_C;
00680               break;
00681             case 'f':
00682               fspec.data_lang = LANG_F;
00683               break;
00684             default:
00685               error("invalid value for -f option: %s", optarg);
00686           }
00687           break;
00688         case 'l':               
00689           max_len = (int) strtol(optarg, 0, 0);
00690           if (max_len < 10) {
00691               error("unreasonably small line length specified: %d", max_len);
00692           }
00693           break;
00694         case 'v':               
00695           
00696           make_lvars (optarg, &fspec);
00697           break;
00698         case 'd':               
00699           set_sigdigs(optarg);
00700           break;
00701         case 'p':               
00702           set_precision(optarg);
00703           break;
00704         case '?':
00705           usage();
00706           break;
00707       }
00708 
00709     set_max_len(max_len);
00710     
00711     argc -= optind;
00712     argv += optind;
00713 
00714     i = 0;
00715 
00716     do {                
00717         if (!nameopt) fspec.name = (char *)0;
00718         if (argc > 0)
00719           do_ncdump(argv[i], &fspec);
00720     } while (++i < argc);
00721 #ifdef vms
00722     exit(EXIT_SUCCESS);
00723 #else
00724     return EXIT_SUCCESS;
00725 #endif
00726 }