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