Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

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: /misc/elrond0/share/cvs/AFNI/src/netcdf-3.5.0/src/ncdump/ncdump.c,v 1.6 2004/04/02 15:12:42 rwcox Exp $
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  * convert pathname of netcdf file into name for cdl unit, by taking 
00063  * last component of path and stripping off any extension.
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 /* default to unix */
00079 #define FILE_DELIMITER '/'
00080 #endif
00081     cp = strrchr(path, FILE_DELIMITER);
00082     if (cp == 0)                /* no delimiter */
00083       cp = path;
00084     else                        /* skip delimeter */
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); /* copy last component of path */
00091     if ((sp = strrchr(newName, '.')) != NULL)
00092       *sp = '\0';               /* strip off any extension */
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  * Remove trailing zeros (after decimal point) but not trailing decimal
00122  * point from ss, a string representation of a floating-point number that
00123  * might include an exponent part.
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  * Print attribute string, for text attributes.
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     /* adjust len so trailing nulls don't get printed */
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':              /* generate linebreaks after new-lines */
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  * Print list of attribute values, for numeric attributes.  Attribute values
00210  * must be printed with explicit type tags, because CDL doesn't have explicit
00211  * syntax to declare an attribute type.
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);        /* trim trailing 0's after '.' */
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;           /* attribute */
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) { /* show 0-length attributes as empty strings */
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;                  /* number of dimensions */
00343     int nvars;                  /* number of variables */
00344     int ngatts;                 /* number of global attributes */
00345     int xdimid;                 /* id of unlimited dimension */
00346     int dimid;                  /* dimension id */
00347     int varid;                  /* variable id */
00348     struct ncdim dims[NC_MAX_DIMS]; /* dimensions */
00349     size_t vdims[NC_MAX_DIMS];  /* dimension sizes for a single variable */
00350     struct ncvar var;           /* variable */
00351     struct ncatt att;           /* attribute */
00352     int id;                     /* dimension number per variable */
00353     int ia;                     /* attribute number */
00354     int iv;                     /* variable number */
00355     int is_coord;               /* true if variable is a coordinate variable */
00356     int ncid;                   /* netCDF id */
00357     vnode* vlist = 0;           /* list for vars specified with -v option */
00358     int nc_status;              /* return from netcdf calls */
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      * If any vars were specified with -v option, get list of associated
00366      * variable ids
00367      */
00368     if (specp->nlvars > 0) {
00369         vlist = newvlist();     /* list for vars specified with -v option */
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     /* if name not specified, derive it from path */
00377     if (specp->name == (char *)0) {
00378         specp->name = name_path (path);
00379     }
00380 
00381     Printf ("netcdf %s {\n", specp->name);
00382     /*
00383      * get number of dimensions, number of variables, number of global
00384      * atts, and dimension id of unlimited dimension, if any
00385      */
00386     NC_CHECK( nc_inq(ncid, &ndims, &nvars, &ngatts, &xdimid) );
00387     /* get dimension info */
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     /* get variable info, with variable attributes */
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         /* get variable attributes */
00416         for (ia = 0; ia < var.natts; ia++)
00417             pr_att(ncid, varid, var.name, ia); /* print ia-th attribute */
00418     }
00419 
00420 
00421     /* get global attributes */
00422     if (ngatts > 0)
00423       Printf ("\n// global attributes:\n");
00424     for (ia = 0; ia < ngatts; ia++)
00425         pr_att(ncid, NC_GLOBAL, "", ia); /* print ia-th global attribute */
00426     
00427     if (! specp->header_only) {
00428         if (nvars > 0) {
00429             Printf ("data:\n");
00430         }
00431         /* output variable data */
00432         for (varid = 0; varid < nvars; varid++) {
00433             /* if var list specified, test for membership */
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                 /* Find out if this is a coordinate variable */
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) /* don't get data for non-coordinate vars */
00449                   continue;
00450             }
00451             /*
00452              * Only get data for variable if it is not a record variable,
00453              * or if it is a record variable and at least one record has
00454              * been written.
00455              */
00456             if (var.ndims == 0
00457                 || var.dims[0] != xdimid
00458                 || dims[xdimid].size != 0) {
00459 
00460                 /* Collect variable's dim sizes */
00461                 for (id = 0; id < var.ndims; id++)
00462                   vdims[id] = dims[var.dims[id]].size;
00463                 var.has_fillval = 1; /* by default, but turn off for bytes */
00464 
00465                 /* get _FillValue attribute */
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                         /* don't do default fill-values for bytes, too risky */
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     /* compute number of variable names in comma-delimited list */
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     /* copy variable names into list */
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  * Extract the significant-digits specifiers from the -d argument on the
00560  * command-line and update the default data formats appropriately.
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; /* default floating-point digits */
00568     int dbl_digits = DBL_DIGITS; /* default double-precision 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  * Extract the significant-digits specifiers from the -p argument on the
00589  * command-line, set flags so we can override C_format attributes (if any),
00590  * and update the default data formats appropriately.
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;        /* default floating-point digits */
00598     int dbl_digits = DBL_DIGITS;        /* default double-precision 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 = /* defaults, overridden on command line */
00628       {
00629           0,                    /* construct netcdf name from file name */
00630           false,                /* print header info only, no data? */
00631           false,                /* just print coord vars? */
00632           false,                /* brief  comments in data section? */
00633           false,                /* full annotations in data section?  */
00634           LANG_C,               /* language conventions for indices */
00635           0,                    /* if -v specified, number of variables */
00636           0                     /* if -v specified, list of variable names */
00637           };
00638     int c;
00639     int i;
00640     int max_len = 80;           /* default maximum line length */
00641     int nameopt = 0;
00642 
00643     opterr = 1;
00644     progname = argv[0];
00645     set_formats(FLT_DIGITS, DBL_DIGITS); /* default for float, double data */
00646 
00647     while ((c = getopt(argc, argv, "b:cf:hl:n:v:d:p:")) != EOF)
00648       switch(c) {
00649         case 'h':               /* dump header only, no data */
00650           fspec.header_only = true;
00651           break;
00652         case 'c':               /* header, data only for coordinate dims */
00653           fspec.coord_vals = true;
00654           break;
00655         case 'n':               /*
00656                                  * provide different name than derived from
00657                                  * file name
00658                                  */
00659           fspec.name = optarg;
00660           nameopt = 1;
00661           break;
00662         case 'b':               /* brief comments in data section */
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':               /* full comments in data section */
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':               /* maximum line length */
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':               /* variable names */
00695           /* make list of names of variables specified */
00696           make_lvars (optarg, &fspec);
00697           break;
00698         case 'd':               /* specify precision for floats (old option) */
00699           set_sigdigs(optarg);
00700           break;
00701         case 'p':               /* specify precision for floats */
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 }
 

Powered by Plone

This site conforms to the following standards: