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 }