1/*********************************************************************
2 *   Copyright 1993, UCAR/Unidata
3 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 *   $Header: /upc/share/CVS/netcdf-3/ncdump/vardata.c,v 1.48 2010/05/05 22:15:39 dmh Exp $
5 *********************************************************************/
6
7#include <config.h>
8#include <stdio.h>
9#include <ctype.h>
10#include <stdlib.h>
11#include <string.h>
12#include <assert.h>
13#include <netcdf.h>
14#include "utils.h"
15#include "nccomps.h"
16#include "dumplib.h"
17#include "ncdump.h"
18#include "indent.h"
19#include "vardata.h"
20
21/* maximum len of string needed for one value of a primitive type */
22#define MAX_OUTPUT_LEN 100
23
24#define LINEPIND "    " /* indent of continued lines */
25
26extern fspec_t formatting_specs; /* set from command-line options */
27
28/* Only read this many values at a time, if last dimension is larger
29  than this */
30#define VALBUFSIZ 10000
31
32static int linep; /* line position, not counting global indent */
33static int max_line_len; /* max chars per line, not counting global indent */
34
35
36/* set position in line before lput() calls */
37static void
38set_indent(int in) {
39    linep = in;
40}
41
42
43void
44set_max_len(int len) {
45    max_line_len = len-2;
46}
47
48
49/*
50 * Output a string that should not be split across lines.  If it would
51 * make current line too long, first output a newline and current
52 * (nested group) indentation, then continuation indentation, then
53 * output string.  If string ends with a newline to force short line,
54 * reset indentation after output.
55 */
56void
57lput(const char *cp) {
58    size_t nn = strlen(cp);
59
60    if (nn+linep > max_line_len && nn > 2) {
61 (void) fputs("\n", stdout);
62 indent_out();
63 (void) fputs(LINEPINDstdout);
64 linep = (int)strlen(LINEPIND) + indent_get();
65    }
66    (void) fputs(cp,stdout);
67    if (nn > 0 && cp[nn - 1] == '\n') {
68 linep = indent_get();
69    } else
70 linep += nn;
71}
72
73
74/*--------------------------------------------------------------------------*/
75
76/* Support function for print_att_times.
77 * Output a string that should not be split across lines.
78 * Keep track of position on print line.
79 * Wrap print lines as needed to keep within requested line length.
80 * Start CDL comment on each new line.
81 * Handle line indentation.
82 *
83 * This function is like lput in vardata.c, with variations.
84 * Hopefully this function will later be absorbed into a more
85 * general lput-type function.
86 */
87
88#define CDL_COMMENT_PREFIX "// "
89void
90lput2(
91    const char *cp, /* string to print */
92    bool_t first_item, /* identify first item in list */
93    bool_t wrap /* line wrap control: true=enable,
94      * false=stay on same line  */
95    )
96{
97    static int linep; /* current line position (number of */
98     /*   chars); saved between calls    */
99    int len_prefix = strlen (CDL_COMMENT_PREFIX);
100    bool_t make_newline;
101
102    size_t len1 = strlen(cp); /* length of input string */
103
104    assert (len1 > 0);
105
106/* (1) Single space or newline/indent sequence, as needed. */
107
108    linep = linep + 1 + len1; /* new line position, without newline */
109     /* add 1 extra for preceding space   */
110
111    make_newline = (wrap && (first_item || linep > max_line_len + 2));
112     /* NEVER new line in no-wrap mode */
113
114    if (make_newline) { /* start new line, if needed */
115        printf ("\n");
116 indent_out(); /* same exact indentation as pr_att */
117 printf ("\t\t"); /* (possible problem here) */
118        printf ("  "); /* add indent for CDL comment */
119 linep = 16 + 2 + len1; /* recompute new line position */
120         /* with newline + indents      */
121    } else {
122 printf (" "); /* always one space, if not newline */
123    }
124
125/* (2) Add CDL comment prefix, if needed. */
126
127    if (len_prefix > 0) {
128 if (first_item || make_newline) {
129     printf (CDL_COMMENT_PREFIX);
130            linep = linep + len_prefix;
131 }
132    }
133
134/* (3) Output caller's string value. */
135
136    printf ("%s", cp);
137}
138
139
140/*
141 * Output a value of an attribute.
142 */
143static void
144print_any_att_val (
145    struct safebuf_t *sb, /* string where output goes */
146    const ncatt_t *attp, /* attrbute */
147    const void *valp /* pointer to the value */
148     ) {
149    nctype_t *typ = attp->tinfo;
150    (*typ->typ_tostring)(typsbvalp);
151}
152
153
154/*
155 * Output a value of a variable, except if there is a fill value for
156 * the variable and the value is the fill value, print the fill-value string
157 * instead.  (Floating-point fill values need only be within machine epsilon of
158 * defined fill value.)
159 */
160static void
161print_any_val(
162    safebuf_t *sb, /* string where output goes */
163    const ncvar_t *varp, /* variable */
164    const void *valp /* pointer to the value */
165     )
166{
167    if (varp->has_fillval &&
168 (*(varp->tinfo->val_equals))((const nctype_t *)varp->tinfo,
169      (const void*)varp->fillvalpvalp) ) {
170 sbuf_cpy(sbFILL_STRING);
171    } else {
172 (*varp->val_tostring)(varpsbvalp);
173    }
174}
175
176/*
177 * print last delimiter in each line before annotation (, or ;)
178 */
179static void
180lastdelim (bool_t morebool_t lastrow)
181{
182    if (more) {
183 printf(", ");
184    } else {
185 if(lastrow) {
186     printf(";");
187 } else {
188     printf(",");
189 }
190    }
191}
192
193/*
194 * print last delimiter in each line before annotation (, or ;)
195 */
196static void
197lastdelim2 (bool_t morebool_t lastrow)
198{
199    if (more) {
200 lput(", ");
201    } else {
202 if(lastrow) {
203     lput(" ;");
204     lput("\n");
205 } else {
206     lput(",\n");
207     lput("  ");
208 }
209    }
210}
211
212
213/*
214 * Print a number of attribute values
215 */
216void
217pr_any_att_vals(
218     const ncatt_t *ap, /* attribute */
219     const void *vals /* pointer to block of values */
220     )
221{
222    size_t iel;
223    size_t len = ap->len; /* number of values to print */
224    const char *valp = (const char *)vals;
225    safebuf_t *sb = sbuf_new();
226
227    for (iel = 0; iel < len - 1; iel++) {
228 print_any_att_val(sbap, (void *)valp);
229 valp += ap->tinfo->size; /* next value according to type */
230 sbuf_cat(sbiel == len - 1 ? "" : ", ");
231 lput(sbuf_str(sb));
232    }
233    print_any_att_val(sbap, (void *)valp);
234    lput(sbuf_str(sb));
235    sbuf_free(sb);
236}
237
238/*
239 * Prints brief annotation for a row of data values
240 */
241static void
242annotate_brief(
243    const ncvar_t *vp, /* variable */
244    const size_t *cor, /* corner coordinates */
245    size_t vdims[] /* variable dimension sizes */
246    )
247{
248    int vrank = vp->ndims;
249    int id;
250    printf ("// ");
251    print_name(vp->name);
252    printf("(");
253
254    switch (formatting_specs.data_lang) {
255    case LANG_C:
256 /* print brief comment with C variable indices */
257 for (id = 0; id < vrank-1; id++)
258     printf("%lu,", (unsigned long)cor[id]);
259 if (vdims[vrank-1] == 1)
260     printf("0");
261 else
262     printf(" 0-%lu", (unsigned long)vdims[vrank-1]-1);
263 break;
264    case LANG_F:
265 /* print brief comment with Fortran variable indices */
266 if (vdims[vrank-1] == 1)
267     printf("1");
268 else
269     printf("1-%lu ", (unsigned long)vdims[vrank-1]);
270 for (id = vrank-2; id >=0 ; id--) {
271     printf(",%lu", (unsigned long)(1 + cor[id]));
272 }
273 break;
274    }
275    printf(")\n");
276    indent_out();
277    printf("    ");
278    set_indent(4 + indent_get());
279}
280
281/*
282 * Annotates a value in data section with var name and indices in comment
283 */
284static void
285annotate(
286     const ncvar_t *vp, /* variable */
287     const size_t *cor, /* corner coordinates */
288     long iel /* which element in current row */
289     )
290{
291    int vrank = vp->ndims;
292    int id;
293
294    /* print indices according to data_lang */
295/*     printf("  // %s(", vp->name); */
296    printf("  // ");
297    print_name(vp->name);
298    printf("(");
299    switch (formatting_specs.data_lang) {
300      case LANG_C:
301 /* C variable indices */
302 for (id = 0; id < vrank-1; id++)
303   printf("%lu,", (unsigned long) cor[id]);
304 printf("%lu", (unsigned long) cor[id] + iel);
305 break;
306      case LANG_F:
307 /* Fortran variable indices */
308 printf("%lu", (unsigned long) cor[vrank-1] + iel + 1);
309 for (id = vrank-2; id >=0 ; id--) {
310     printf(",%lu", 1 + (unsigned long) cor[id]);
311 }
312 break;
313    }
314    printf(")\n    ");
315}
316
317/*
318 * Print a number of char variable values as a text string, where the
319 * optional comments for each value identify the variable, and each
320 * dimension index.
321 */
322static void
323pr_tvals(
324     const ncvar_t *vp, /* variable */
325     size_t len, /* number of values to print */
326     const char *vals, /* pointer to block of values */
327     const size_t *cor /* corner coordinates */
328     )
329{
330    long iel;
331    const char *sp;
332
333    printf("\"");
334    /* adjust len so trailing nulls don't get printed */
335    sp = vals + len;
336    while (len != 0 && *--sp == '\0')
337 len--;
338    for (iel = 0; iel < leniel++) {
339 unsigned char uc;
340 switch (uc = *vals++ & 0377) {
341 case '\b':
342     printf("\\b");
343     break;
344 case '\f':
345     printf("\\f");
346     break;
347 case '\n': /* generate linebreaks after new-lines */
348     printf("\\n\",\n    \"");
349     break;
350 case '\r':
351     printf("\\r");
352     break;
353 case '\t':
354     printf("\\t");
355     break;
356 case '\v':
357     printf("\\v");
358     break;
359 case '\\':
360     printf("\\\\");
361     break;
362 case '\'':
363     printf("\\\'");
364     break;
365 case '\"':
366     printf("\\\"");
367     break;
368 default:
369     if (isprint(uc))
370 printf("%c",uc);
371     else
372 printf("\\%.3o",uc);
373     break;
374 }
375    }
376    printf("\"");
377    /* if (formatting_specs.full_data_cmnts) { */
378    /*  lastdelim (0, lastrow); */
379    /*  annotate (vp,  (size_t *)cor, 0L); */
380    /* }  */
381}
382
383
384/*
385 * Updates a vector of ints, odometer style.  Returns 0 if odometer
386 * overflowed, else 1.
387 */
388static int
389upcorner(
390     const size_t *dims, /* The "odometer" limits for each dimension */
391     int ndims, /* Number of dimensions */
392     size_t* odom, /* The "odometer" vector to be updated */
393     const size_t* add /* A vector to "add" to odom on each update */
394     )
395{
396    int id;
397    int ret = 1;
398
399    for (id = ndims-1; id > 0; id--) {
400 odom[id] += add[id];
401 if(odom[id] >= dims[id]) {
402     odom[id-1]++;
403     odom[id] -= dims[id];
404 }
405    }
406    odom[0] += add[0];
407    if (odom[0] >= dims[0])
408      ret = 0;
409    return ret;
410}
411
412/*  Print data values for variable varid.
413 *
414 * Recursive to handle possibility of variables with multiple
415 * unlimited dimensions, for which the CDL syntax requires use of "{"
416 * and "}" in data section to disambiguate the size of nested records
417 * in a simple linear list of values.
418 */
419static int
420print_rows(
421    int level,          /* 0 at top-level, incremented for each recursive level */
422    int ncid, /* netcdf id */
423    int varid, /* variable id */
424    const ncvar_t *vp, /* variable */
425    size_t vdims[],     /* variable dimension sizes */
426    size_t cor[],       /* corner coordinates */
427    size_t edg[],       /* edges of hypercube */
428    void *vals,    /* allocated buffer for ncols values in a row */
429    int marks_pending /* number of pending closing "}" record markers */
430    )
431{
432    int rank = vp->ndims;
433    size_t ncols = rank > 0 ? vdims[rank - 1] : 1; /* number of values in a row */
434    int d0 = 0;
435    size_t inc = 1;
436    int i;
437    bool_t mark_record = (level > 0 && is_unlim_dim(ncidvp->dims[level]));
438    safebuf_t *sb = sbuf_new();
439    if (rank > 0)
440 d0 = vdims[level];
441    for(i = level + 1; i < ranki++) {
442 inc *= vdims[i];
443    }
444    if(mark_record) { /* the whole point of this recursion is printing these "{}" */
445 lput("{");
446 marks_pending++; /* matching "}"s to emit after last "row" */
447    }
448    if(rank - level > 1) {      /* this level is just d0 next levels */
449 size_t *local_cor = emalloc((rank + 1) * sizeof(size_t));
450 size_t *local_edg = emalloc((rank + 1) * sizeof(size_t));
451 for(i = 0; i < ranki++) {
452     local_cor[i] = cor[i];
453     local_edg[i] = edg[i];
454 }
455 local_cor[level] = 0;
456 local_edg[level] = 1;
457 for(i = 0; i < d0 - 1; i++) {
458     print_rows(level + 1, ncidvaridvpvdims,
459        local_corlocal_edgvals, 0);
460     local_cor[level] += 1;
461 }
462 print_rows(level + 1, ncidvaridvpvdims,
463    local_corlocal_edgvalsmarks_pending);
464 free(local_edg);
465 free(local_cor);
466    } else { /* bottom out of recursion */
467 char *valp = vals;
468 bool_t lastrow;
469 int j;
470 if(formatting_specs.brief_data_cmnts && rank > 1 && ncols > 0) {
471     annotate_brief(vpcorvdims);
472 }
473 NC_CHECK(nc_get_vara(ncidvaridcoredg, (void *)valp));
474
475 /* Test if we should treat array of chars as strings along last dimension  */
476 if(vp->type == NC_CHAR && (vp->fmt == 0 || STREQ(vp->fmt,"%s") || STREQ(vp->fmt,""))) {
477     pr_tvals(vpncolsvalscor);
478 } else { /* for non-text variables */
479     for(i=0; i < d0 - 1; i++) {
480 print_any_val(sbvp, (void *)valp);
481 valp += vp->tinfo->size; /* next value according to type */
482 if (formatting_specs.full_data_cmnts) {
483     printf("%s, ", sb->buf);
484     annotate (vpcori);
485 } else {
486     sbuf_cat(sb, ", ");
487     lput(sbuf_str(sb));
488 }
489     }
490     print_any_val(sbvp, (void *)valp);
491 }
492 /* determine if this is the last row */
493 lastrow = true;
494 for(j = 0; j < rank - 1; j++) {
495      if (cor[j] != vdims[j] - 1) {
496 lastrow = false;
497 break;
498      }
499 }
500 if (formatting_specs.full_data_cmnts) {
501      for (j = 0; j < marks_pendingj++) {
502 sbuf_cat(sb, "}");
503      }
504      printf("%s", sbuf_str(sb));
505      lastdelim (0, lastrow);
506      annotate (vpcord0-1);
507 } else {
508      for (j = 0; j < marks_pendingj++) {
509 sbuf_cat(sb, "}");
510      }
511      lput(sbuf_str(sb));
512      lastdelim2 (0, lastrow);
513 }
514    }
515    sbuf_free(sb);
516    return NC_NOERR;
517}
518
519/* Output the data for a single variable, in CDL syntax. */
520int
521vardata(
522     const ncvar_t *vp, /* variable */
523     size_t vdims[], /* variable dimension sizes */
524     int ncid, /* netcdf id */
525     int varid /* variable id */
526     )
527{
528    size_t *cor;      /* corner coordinates */
529    size_t *edg;      /* edges of hypercube */
530    size_t *add;      /* "odometer" increment to next "row"  */
531    void *vals;
532
533    int id;
534    size_t nels;
535    size_t ncols;
536    size_t nrows;
537    int vrank = vp->ndims;
538
539    int level = 0;
540    int marks_pending = 0;
541
542    cor = (size_t *) emalloc((1 + vrank) * sizeof(size_t));
543    edg = (size_t *) emalloc((1 + vrank) * sizeof(size_t));
544    add = (size_t *) emalloc((1 + vrank) * sizeof(size_t));
545
546    nels = 1;
547    if(vrank == 0) { /*scalar*/
548 cor[0] = 0;
549 edg[0] = 1;
550    } else {
551 for (id = 0; id < vrankid++) {
552     cor[id] = 0;
553     edg[id] = 1;
554     nels *= vdims[id]; /* total number of values for variable */
555 }
556    }
557    printf("\n");
558    indent_out();
559    printf(" ");
560    print_name(vp->name);
561    if (vrank <= 1) {
562 printf(" = ");
563 set_indent ((int)strlen(vp->name) + 4 + indent_get());
564    } else {
565 printf(" =\n  ");
566 set_indent (2 + indent_get());
567    }
568
569    if (vrank == 0) {
570 ncols = 1;
571    } else {
572 ncols = vdims[vrank-1]; /* size of "row" along last dimension */
573 edg[vrank-1] = ncols;
574 for (id = 0; id < vrankid++)
575   add[id] = 0;
576 if (vrank > 1)
577   add[vrank-2] = 1;
578    }
579    nrows = nels/ncols; /* number of "rows" */
580    vals = emalloc(ncols * vp->tinfo->size);
581
582    NC_CHECK(print_rows(levelncidvaridvpvdimscoredgvalsmarks_pending));
583    free(vals);
584    free(cor);
585    free(edg);
586    free(add);
587
588    return 0;
589}
590
591
592/*
593 * print last delimiter in each line before annotation (, or ;)
594 */
595static void
596lastdelim2x (bool_t morebool_t lastrow)
597{
598    if (more) {
599 lput(" ");
600    } else {
601 if(lastrow) {
602     lput("\n   ");
603 } else {
604     lput("\n     ");
605 }
606    }
607}
608
609
610/*
611 * Print a number of char variable values as a text string for NcML
612 */
613static void
614pr_tvalsx(
615     const ncvar_t *vp, /* variable */
616     size_t len, /* number of values to print */
617     bool_t more, /* true if more data for this row will
618  * follow, so add trailing comma */
619     bool_t lastrow, /* true if this is the last row for this
620  * variable, so terminate with ";" instead
621  * of "," */
622     const char *vals /* pointer to block of values */
623     )
624{
625    long iel;
626    const char *sp;
627
628    printf("\"");
629    /* adjust len so trailing nulls don't get printed */
630    sp = vals + len;
631    while (len != 0 && *--sp == '\0')
632 len--;
633    for (iel = 0; iel < leniel++) {
634 unsigned char uc;
635 switch (uc = *vals++ & 0377) {
636 case '\b':
637     printf("\\b");
638     break;
639 case '\f':
640     printf("\\f");
641     break;
642 case '\n': /* generate linebreaks after new-lines */
643     printf("\\n\",\n    \"");
644     break;
645 case '\r':
646     printf("\\r");
647     break;
648 case '\t':
649     printf("\\t");
650     break;
651 case '\v':
652     printf("\\v");
653     break;
654 case '\\':
655     printf("\\\\");
656     break;
657 case '\'':
658     printf("\\\'");
659     break;
660 case '\"':
661     printf("\\\"");
662     break;
663 default:
664     if (isprint(uc))
665 printf("%c",uc);
666     else
667 printf("\\%.3o",uc);
668     break;
669 }
670    }
671    printf("\"");
672    lastdelim2x (morelastrow);
673}
674
675
676/*
677 * Print a number of variable values for NcML
678 */
679static void
680pr_any_valsx(
681     const ncvar_t *vp, /* variable */
682     size_t len, /* number of values to print */
683     bool_t more, /* true if more data for this row will
684  * follow, so add trailing comma */
685     bool_t lastrow, /* true if this is the last row for this
686  * variable, so terminate with ";" instead
687  * of "," */
688     const void *vals /* pointer to block of values */
689     )
690{
691    long iel;
692    safebuf_t *sb = sbuf_new();
693    const char *valp = (const char *)vals;
694
695    for (iel = 0; iel < len-1; iel++) {
696 print_any_val(sbvp, (void *)valp);
697 valp += vp->tinfo->size; /* next value according to type */
698 sbuf_cat(sb, " ");
699 lput(sbuf_str(sb));
700    }
701    print_any_val(sbvp, (void *)valp);
702    lput(sbuf_str(sb));
703    lastdelim2x (morelastrow);
704    sbuf_free(sb);
705}
706
707
708/* Output the data for a single variable, in NcML syntax.
709 *  TODO: currently not called, need option for NcML with values ... */
710int
711vardatax(
712     const ncvar_t *vp, /* variable */
713     size_t vdims[], /* variable dimension sizes */
714     int ncid, /* netcdf id */
715     int varid /* variable id */
716     )
717{
718    size_t *cor;      /* corner coordinates */
719    size_t *edg;      /* edges of hypercube */
720    size_t *add;      /* "odometer" increment to next "row"  */
721    void *vals;
722
723    int id;
724    int ir;
725    size_t nels;
726    size_t ncols;
727    size_t nrows;
728    int vrank = vp->ndims;
729
730    cor = (size_t *) emalloc((vrank + 1) * sizeof(size_t));
731    edg = (size_t *) emalloc((vrank + 1) * sizeof(size_t));
732    add = (size_t *) emalloc((vrank + 1) * sizeof(size_t));
733
734    nels = 1;
735    for (id = 0; id < vrankid++) {
736 cor[id] = 0;
737 edg[id] = 1;
738 nels *= vdims[id]; /* total number of values for variable */
739    }
740
741    printf("    <values>\n     ");
742    set_indent (7);
743
744    if (vrank < 1) {
745 ncols = 1;
746    } else {
747 ncols = vdims[vrank-1]; /* size of "row" along last dimension */
748 edg[vrank-1] = vdims[vrank-1];
749 for (id = 0; id < vrankid++)
750   add[id] = 0;
751 if (vrank > 1)
752   add[vrank-2] = 1;
753    }
754    nrows = nels/ncols; /* number of "rows" */
755    vals = emalloc(ncols * vp->tinfo->size);
756
757    for (ir = 0; ir < nrowsir++) {
758 size_t corsav = 0;
759 bool_t lastrow;
760
761 if (vrank > 0) {
762     corsav = cor[vrank-1];
763 }
764 lastrow = (bool_t)(ir == nrows-1);
765
766 if (vrank > 0)
767     edg[vrank-1] = ncols;
768 NC_CHECK(nc_get_vara(ncidvaridcoredgvals) );
769 /* Test if we should treat array of chars as a string  */
770 if(vp->type == NC_CHAR &&
771    (vp->fmt == 0 || STREQ(vp->fmt,"%s") || STREQ(vp->fmt,""))) {
772     pr_tvalsx(vpncols, 0, lastrow, (char *) vals);
773 } else {
774     pr_any_valsx(vpncols, 0, lastrowvals);
775 }
776
777 if (vrank > 0)
778     cor[vrank-1] += ncols;
779
780 if (vrank > 0)
781   cor[vrank-1] = corsav;
782 if (ir < nrows-1)
783   if (!upcorner(vdims,vp->ndims,cor,add))
784     error("vardata: odometer overflowed!");
785 set_indent(2);
786    }
787    printf(" </values>\n");
788    free(vals);
789    free(cor);
790    free(edg);
791    free(add);
792    return 0;
793}


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed