1 /*********************************************************************
2  *   Copyright 1993, University Corporation for Atmospheric Research
3  *   See netcdf/README file for copying and redistribution conditions.
4  *   $Header: /private-cvsroot/minc/progs/mincdump/dumplib.c,v 1.4 2008-01-12 19:08:15 stever Exp $
5  *********************************************************************/
6 
7 #if HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10 
11 /*
12  * We potentially include <stdarg.h> before <stdio.h> in order to obtain a
13  * definition for va_list from the GNU C compiler.
14  */
15 #include <stdarg.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 
20 #include <minc.h>
21 #include "dumplib.h"
22 
23 static char* has_c_format_att(int ncid, int varid);
24 static vnode* newvnode(void);
25 
26 int float_precision_specified = 0; /* -p option specified float precision */
27 int double_precision_specified = 0; /* -p option specified double precision */
28 char float_var_fmt[] = "%.NNg";
29 char double_var_fmt[] = "%.NNg";
30 char float_att_fmt[] = "%#.NNgf";
31 char double_att_fmt[] = "%#.NNg";
32 
33 /*
34  * Print error message to stderr and exit
35  */
36 void
error(const char * fmt,...)37 error(const char *fmt, ...)
38 {
39     va_list args ;
40 
41     (void) fprintf(stderr,"%s: ", progname);
42     va_start(args, fmt) ;
43     (void) vfprintf(stderr,fmt,args) ;
44     va_end(args) ;
45 
46     (void) fprintf(stderr, "\n") ;
47     (void) fflush(stderr);	/* to ensure log files are current */
48     exit(EXIT_FAILURE);
49 }
50 
51 #define LINEPIND	"    "	/* indent of continued lines */
52 
53 static int linep;
54 static int max_line_len;
55 
56 void
set_indent(int in)57 set_indent(int in)
58 {
59     linep = in;
60 }
61 
62 
63 void
set_max_len(int len)64 set_max_len(int len)
65 {
66     max_line_len = len-2;
67 }
68 
69 
70 void
lput(const char * cp)71 lput(const char *cp)
72 {
73     size_t nn = strlen(cp);
74 
75     if (nn+linep > max_line_len && nn > 2) {
76 	(void) fputs("\n", stdout);
77 	(void) fputs(LINEPIND, stdout);
78 	linep = (int)strlen(LINEPIND);
79     }
80     (void) fputs(cp,stdout);
81     linep += nn;
82 }
83 
84 /* In case different formats specified with -d option, set them here. */
85 void
set_formats(int float_digits,int double_digits)86 set_formats(int float_digits, int double_digits)
87 {
88     (void) sprintf(float_var_fmt, "%%.%dg", float_digits);
89     (void) sprintf(double_var_fmt, "%%.%dg", double_digits);
90     (void) sprintf(float_att_fmt, "%%#.%dgf", float_digits);
91     (void) sprintf(double_att_fmt, "%%#.%dg", double_digits);
92 }
93 
94 
95 static char *
has_c_format_att(int ncid,int varid)96 has_c_format_att(
97     int ncid,			/* netcdf id */
98     int varid			/* variable id */
99     )
100 {
101     nc_type cfmt_type;
102     int cfmt_len;
103 #define C_FMT_NAME	"C_format" /* name of C format attribute */
104 #define	MAX_CFMT_LEN	100	/* max length of C format attribute */
105     static char cfmt[MAX_CFMT_LEN];
106 
107     /* we expect nc_inq_att to fail if there is no "C_format" attribute */
108     int old_nc_opts;
109     int nc_stat;
110 
111     old_nc_opts = ncopts;
112     ncopts = 0;
113     nc_stat = ncattinq(ncid, varid, "C_format", &cfmt_type, &cfmt_len);
114     ncopts = old_nc_opts;
115 
116     if (nc_stat == -1) {
117         return 0;
118     }
119 
120     if (cfmt_type == NC_CHAR && cfmt_len != 0 && cfmt_len < MAX_CFMT_LEN) {
121         nc_stat = ncattget(ncid, varid, "C_format", cfmt);
122         if(nc_stat != 1)
123             nc_advise("Getting 'C_format' attribute", nc_stat, "");
124         return &cfmt[0];
125     }
126     return 0;
127 }
128 
129 
130 /*
131  * Determine print format to use for each value for this variable.  Use value
132  * of attribute C_format if it exists, otherwise a sensible default.
133  */
134 char *
get_fmt(int ncid,int varid,nc_type type)135 get_fmt(
136      int ncid,			/* netcdf id */
137      int varid,			/* variable id */
138      nc_type type		/* netCDF data type */
139      )
140 {
141     char *c_format_att;
142 
143     /* float or double precision specified with -p option overrides any
144        C_format attribute value, so check for that first. */
145 
146     if (float_precision_specified && type == NC_FLOAT)
147 	return float_var_fmt;
148 
149     if (double_precision_specified && type == NC_DOUBLE)
150 	return double_var_fmt;
151 
152     /* If C_format attribute exists, return it */
153     c_format_att = has_c_format_att(ncid, varid);
154     if (c_format_att)
155       return c_format_att;
156 
157     /* Otherwise return sensible default. */
158     switch (type) {
159       case NC_BYTE:
160 	return "%d";
161       case NC_CHAR:
162 	return "%s";
163       case NC_SHORT:
164 	return "%d";
165       case NC_INT:
166  	return "%d";
167       case NC_FLOAT:
168 	return float_var_fmt;
169       case NC_DOUBLE:
170 	return double_var_fmt;
171       default:
172 	error("pr_vals: bad type");
173     }
174 
175     return 0;
176 }
177 
178 
179 static vnode*
newvnode(void)180 newvnode(void)
181 {
182     vnode *newvp = (vnode*) malloc(sizeof(vnode));
183 
184     if (!newvp) {
185 	error("out of memory!");
186     }
187     return newvp;
188 }
189 
190 
191 /*
192  * Get a new, empty variable list.
193  */
194 vnode*
newvlist(void)195 newvlist(void)
196 {
197     vnode *vp = newvnode();
198 
199     vp -> next = 0;
200     vp -> id = -1;		/* bad id */
201 
202     return vp;
203 }
204 
205 
206 void
varadd(vnode * vlist,int varid)207 varadd(vnode* vlist, int varid)
208 {
209     vnode *newvp = newvnode();
210 
211     newvp -> next = vlist -> next;
212     newvp -> id = varid;
213     vlist -> next = newvp;
214 }
215 
216 
217 int
varmember(const vnode * vlist,int varid)218 varmember(const vnode* vlist, int varid)
219 {
220     vnode *vp = vlist -> next;
221 
222     for (; vp ; vp = vp->next)
223       if (vp->id == varid)
224 	return 1;
225     return 0;
226 }
227 
228 
229