bes  Updated for version 3.20.8
FONcAttributes.cc
1 // FONcAttributes.cc
2 
3 // This file is part of BES Netcdf File Out Module
4 
5 // Copyright (c) 2004,2005 University Corporation for Atmospheric Research
6 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 //
22 // You can contact University Corporation for Atmospheric Research at
23 // 3080 Center Green Drive, Boulder, CO 80301
24 
25 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
26 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
27 //
28 // Authors:
29 // pwest Patrick West <pwest@ucar.edu>
30 // jgarcia Jose Garcia <jgarcia@ucar.edu>
31 
32 #include <sstream>
33 
34 using std::istringstream;
35 
36 #include <netcdf.h>
37 
38 #include <BESDebug.h>
39 #include <BESInternalError.h>
40 #include <BESUtil.h>
41 #include <cstdlib>
42 
43 #include "DapFunctionUtils.h"
44 
45 #include "FONcAttributes.h"
46 #include "FONcUtils.h"
47 
79 void FONcAttributes::add_variable_attributes(int ncid, int varid, BaseType *b, bool is_nc_enhanced,bool is_dap4) {
80  string emb_name;
81  BaseType *parent = b->get_parent();
82  if (parent) {
83  //BESDEBUG("dap", "FONcAttributes::parent name is "<< parent->name() <<endl);
84  //BESDEBUG("dap", "FONcAttributes::parent type is "<< parent->type() <<endl);
85  if(true != is_dap4 || parent->type()!=dods_group_c)
86  FONcAttributes::add_variable_attributes_worker(ncid, varid, parent, emb_name, is_nc_enhanced,is_dap4);
87  }
88  // addattrs_workerA(ncid, varid, b, "");
89  // Add DAP4 attribute support by using attributes().
90 
91  BESDEBUG("dap", "FONcAttributes::add_variable_attributes() after parent "<<endl);
92  if(is_dap4)
93  add_dap4_attributes(ncid, varid, b->attributes(), b->name(), "", is_nc_enhanced);
94  else
95  add_attributes(ncid, varid, b->get_attr_table(), b->name(), "", is_nc_enhanced);
96 
97 }
98 
113 void FONcAttributes::add_variable_attributes_worker(int ncid, int varid, BaseType *b, string &emb_name,
114  bool is_nc_enhanced,bool is_dap4) {
115 
116  BaseType *parent = b->get_parent();
117  if (parent) {
118  FONcAttributes::add_variable_attributes_worker(ncid, varid, parent, emb_name, is_nc_enhanced,is_dap4);
119  }
120  if (!emb_name.empty()) {
121  emb_name += FONC_EMBEDDED_SEPARATOR;
122  }
123  emb_name += b->name();
124  // addattrs_workerA(ncid, varid, b, emb_name);
125  if(is_dap4)
126  add_dap4_attributes(ncid, varid, b->attributes(), b->name(), emb_name, is_nc_enhanced);
127  else
128  add_attributes(ncid, varid, b->get_attr_table(), b->name(), emb_name, is_nc_enhanced);
129 }
130 
131 
146 void FONcAttributes::add_attributes(int ncid, int varid, AttrTable &attrs, const string &var_name,
147  const string &prepend_attr, bool is_nc_enhanced) {
148 
149  unsigned int num_attrs = attrs.get_size();
150  if (num_attrs) {
151  AttrTable::Attr_iter i = attrs.attr_begin();
152  AttrTable::Attr_iter e = attrs.attr_end();
153  for (; i != e; i++) {
154  unsigned int num_vals = attrs.get_attr_num(i);
155  if (num_vals) {
156  add_attributes_worker(ncid, varid, var_name, attrs, i, prepend_attr, is_nc_enhanced);
157  }
158  }
159  }
160 }
161 
176 //void FONcAttributes::add_dap4_attributes(int ncid, int varid, AttrTable &attrs, const string &var_name,
177 void FONcAttributes::add_dap4_attributes(int ncid, int varid, D4Attributes *d4_attrs, const string &var_name,
178  const string &prepend_attr, bool is_nc_enhanced) {
179 
180 #if 0
181  unsigned int num_attrs = attrs.get_size();
182  if (num_attrs) {
183  AttrTable::Attr_iter i = attrs.attr_begin();
184  AttrTable::Attr_iter e = attrs.attr_end();
185  for (; i != e; i++) {
186  unsigned int num_vals = attrs.get_attr_num(i);
187  if (num_vals) {
188  add_dap4_attributes_worker(ncid, varid, var_name, attrs, i, prepend_attr, is_nc_enhanced);
189  }
190  }
191  }
192 #endif
193 
194  BESDEBUG("dap", "FONcAttributes::add_dap4_attributes() number of attributes "<< d4_attrs <<endl);
195  for (D4Attributes::D4AttributesIter ii = d4_attrs->attribute_begin(), ee = d4_attrs->attribute_end(); ii != ee; ++ii) {
196  string name = (*ii)->name();
197  //BESDEBUG("dap", "FONcAttributes:: attribute name is "<<name <<endl);
198  unsigned int num_vals = (*ii)->num_values();
199  //BESDEBUG("dap", "FONcAttributes:: num_vals is "<<num_vals <<endl);
200  // d4_attrs includes all the global containers' attributes, which is not right.
201  if (num_vals || varid == NC_GLOBAL)
202  add_dap4_attributes_worker(ncid, varid, var_name, *ii, prepend_attr, is_nc_enhanced);
203  }
204 }
205 
219 void FONcAttributes::add_attributes_worker(int ncid, int varid, const string &var_name,
220  AttrTable &attrs, AttrTable::Attr_iter &attr,
221  const string &prepend_attr, bool is_nc_enhanced) {
222 
223  AttrType attrType = attrs.get_attr_type(attr);
224 
225  string attr_name = attrs.get_name(attr);
226  string new_attr_name("");
227  if (!prepend_attr.empty()) {
228  new_attr_name = prepend_attr + FONC_EMBEDDED_SEPARATOR + attr_name;
229  } else {
230 
231  // If we're doing global attributes AND it's an attr table, and its name is "special"
232  // (ends with "_GLOBAL"), then we suppress the use of the attrTable name in
233  // the NetCDF Attributes name.
234  if (varid == NC_GLOBAL && attrType == Attr_container && BESUtil::endsWith(attr_name, "_GLOBAL")) {
235  BESDEBUG("fonc",
236  "Suppressing global AttributeTable name '" << attr_name
237  << "' from inclusion in NetCDF attributes namespace chain."
238  << endl);
239  new_attr_name = "";
240  } else {
241  new_attr_name = attr_name;
242  }
243  }
244 
245 #if 0
246  // This was the old way of doing it and it polluted the attribute names
247  // by prepending full qualified variable names to the attribute name..
248  string new_name = new_attr_name;
249  if (!var_name.empty()) {
250  new_name = var_name + FONC_ATTRIBUTE_SEPARATOR + new_attr_name;
251  }
252 
253  // BESDEBUG("fonc","new_name: " << new_name << " new_attr_name: " << new_attr_name << " var_name: " << var_name << endl);
254 
255  new_name = FONcUtils::id2netcdf(new_name);
256 #endif
257 
258  string new_name = FONcUtils::id2netcdf(new_attr_name);;
259 
260 
261  if (varid == NC_GLOBAL) {
262  BESDEBUG("fonc", "FONcAttributes::addattrs() - Adding global attributes " << attr_name << endl);
263  } else {
264  BESDEBUG("fonc", "FONcAttributes::addattrs() - Adding attribute " << new_name << endl);
265  }
266 
267  // If we want to map the attributes of the datatypes to those of netCDF-4, KY 2020-02-14
268  if (is_nc_enhanced == true)
269  write_attrs_for_nc4_types(ncid, varid, var_name, new_attr_name, new_name, attrs, attr, is_nc_enhanced);
270  else {
271  int stax = NC_NOERR;
272  unsigned int attri = 0;
273  unsigned int num_vals = attrs.get_attr_num(attr);
274  switch (attrType) {
275  case Attr_container: {
276  // flatten
277  BESDEBUG("fonc",
278  "Attribute " << attr_name << " is an attribute container. new_attr_name: \"" << new_attr_name
279  << "\"" << endl);
280  AttrTable *container = attrs.get_attr_table(attr);
281  if (container) {
282  add_attributes(ncid, varid, *container, var_name, new_attr_name, is_nc_enhanced);
283  }
284  }
285  break;
286  case Attr_byte: {
287  // unsigned char
288  vector<unsigned char>vals;
289  vals.resize(num_vals);
290  for (attri = 0; attri < num_vals; attri++) {
291  string val = attrs.get_attr(attr, attri);
292  istringstream is(val);
293  unsigned int uival = 0;
294  is >> uival;
295  vals[attri] = (unsigned char) uival;
296  }
297  stax = nc_put_att_uchar(ncid, varid, new_name.c_str(), NC_BYTE,
298  num_vals, &vals[0]);
299  if (stax != NC_NOERR) {
300  string err = (string) "File out netcdf, "
301  + "failed to write byte attribute " + new_name;
302  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
303  }
304  }
305  break;
306  case Attr_int16: {
307  // short
308  vector<short>vals;
309  vals.resize(num_vals);
310  for (attri = 0; attri < num_vals; attri++) {
311  string val = attrs.get_attr(attr, attri);
312  istringstream is(val);
313  short sval = 0;
314  is >> sval;
315  vals[attri] = sval;
316  }
317  stax = nc_put_att_short(ncid, varid, new_name.c_str(), NC_SHORT,
318  num_vals, &vals[0]);
319  if (stax != NC_NOERR) {
320  string err = (string) "File out netcdf, "
321  + "failed to write short attribute " + new_name;
322  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
323  }
324  }
325  break;
326  case Attr_uint16: {
327  // unsigned short
328  // (needs to be big enough to store an unsigned short
329  vector<int>vals;
330  vals.resize(num_vals);
331  for (attri = 0; attri < num_vals; attri++) {
332  string val = attrs.get_attr(attr, attri);
333  istringstream is(val);
334  int ival = 0;
335  is >> ival;
336  vals[attri] = ival;
337  }
338  stax = nc_put_att_int(ncid, varid, new_name.c_str(), NC_INT, num_vals,
339  &vals[0]);
340  if (stax != NC_NOERR) {
341  string err = (string) "File out netcdf, "
342  + "failed to write unsinged short attribute " + new_name;
343  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
344  }
345  }
346  break;
347  case Attr_int32: {
348  // int
349  vector<int> vals;
350  vals.resize(num_vals);
351  for (attri = 0; attri < num_vals; attri++) {
352  string val = attrs.get_attr(attr, attri);
353  istringstream is(val);
354  int ival = 0;
355  is >> ival;
356  vals[attri] = ival;
357  }
358  stax = nc_put_att_int(ncid, varid, new_name.c_str(), NC_INT, num_vals,
359  &vals[0]);
360  if (stax != NC_NOERR) {
361  string err = (string) "File out netcdf, "
362  + "failed to write int attribute " + new_name;
363  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
364  }
365  }
366  break;
367  case Attr_uint32: {
368  // uint
369  // needs to be big enough to store an unsigned int
370  vector<int>vals;
371  vals.resize(num_vals);
372  for (attri = 0; attri < num_vals; attri++) {
373  string val = attrs.get_attr(attr, attri);
374  istringstream is(val);
375  int lval = 0;
376  is >> lval;
377  vals[attri] = lval;
378  }
379  stax = nc_put_att_int(ncid, varid, new_name.c_str(), NC_INT, num_vals,
380  &vals[0]);
381  if (stax != NC_NOERR) {
382  string err = (string) "File out netcdf, "
383  + "failed to write unsigned int attribute " + new_name;
384  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
385  }
386  }
387  break;
388  case Attr_float32: {
389  // float
390  vector<float> vals;
391  vals.resize(num_vals);
392  for (attri = 0; attri < num_vals; attri++) {
393  string val = attrs.get_attr(attr, attri);
394  const char *cval = val.c_str();
395  //istringstream is(val);
396  float fval = 0;
397  fval = strtod(cval,NULL);
398  //is >> fval;
399  vals[attri] = fval;
400  }
401  stax = nc_put_att_float(ncid, varid, new_name.c_str(), NC_FLOAT,
402  num_vals, &vals[0]);
403  if (stax != NC_NOERR) {
404  string err = (string) "File out netcdf, "
405  + "failed to write float attribute " + new_name;
406  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
407  }
408  }
409  break;
410  case Attr_float64: {
411  // double
412  vector<double>vals;
413  vals.resize(num_vals);
414  for (attri = 0; attri < num_vals; attri++) {
415  string val = attrs.get_attr(attr, attri);
416  const char *cval = val.c_str();
417  //istringstream is(val);
418  double dval = 0;
419  dval = strtod(cval,NULL);
420  //is >> dval;
421  vals[attri] = dval;
422  }
423  stax = nc_put_att_double(ncid, varid, new_name.c_str(), NC_DOUBLE,
424  num_vals, &vals[0]);
425  if (stax != NC_NOERR) {
426  string err = (string) "File out netcdf, "
427  + "failed to write double attribute " + new_name;
428  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
429  }
430  }
431  break;
432  case Attr_string:
433  case Attr_url:
434  case Attr_other_xml: // Added. jhrg 12.27.2011
435  {
436  // string
437  string val = attrs.get_attr(attr, 0);
438  for (attri = 1; attri < num_vals; attri++) {
439  val += "\n" + attrs.get_attr(attr, attri);
440  }
441  if (attr_name != _FillValue) {
442  stax = nc_put_att_text(ncid, varid, new_name.c_str(), val.length(), val.c_str());
443  } else {
444  BESDEBUG("fonc",
445  "FONcAttributes::add_attributes_worker - Original attribute value is first character: "
446  << val.c_str()[0] << endl);
447  stax = nc_put_att_text(ncid, varid, new_name.c_str(), 1, val.c_str());
448  if (stax == NC_NOERR) {
449  // New name for attribute _FillValue with original value
450  string new_name_fillvalue = "Orig_FillValue";
451  BESDEBUG("fonc",
452  "FONcAttributes::add_attributes_worker - New attribute value is original value: "
453  << val.c_str() << endl);
454  // This line causes the segmentation fault since attrs is changed and the original iterator of attrs doesn't exist anymore.
455  // So it causes the segmentation fault when next attribute is fetched in the for loop of the add_attributes(). KY 2019-12-13
456 #if 0
457  attrs.append_attr(new_name_fillvalue,"String", val);
458 #endif
459  stax = nc_put_att_text(ncid, varid, new_name_fillvalue.c_str(), val.length(), val.c_str());
460  }
461  }
462 
463  if (stax != NC_NOERR) {
464  string err = (string) "File out netcdf, "
465  + "failed to write string attribute " + new_name;
466  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
467  }
468  }
469  break;
470 
471  case Attr_unknown: {
472  string err = (string) "File out netcdf, "
473  + "failed to write unknown type of attribute " + new_name;
474  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
475  }
476  break;
477  }
478  }
479 }
480 
493 void FONcAttributes::add_dap4_attributes_worker(int ncid, int varid, const string &var_name,
494  D4Attribute* attr,
495  const string &prepend_attr, bool is_nc_enhanced) {
496  D4AttributeType d4_attr_type = attr->type();
497 
498  string d4_attr_name = attr->name();
499  BESDEBUG("dap", "FONcAttributes:: D4 attribute name is "<<d4_attr_name <<endl);
500  string new_attr_name("");
501  if (!prepend_attr.empty()) {
502  new_attr_name = prepend_attr + FONC_EMBEDDED_SEPARATOR + d4_attr_name;
503  BESDEBUG("dap", "FONcAttributes:: D4 new attribute name is "<<new_attr_name <<endl);
504 
505  } else {
506 
507  // If we're doing global attributes AND it's an attr table, and its name is "special"
508  // (ends with "_GLOBAL"), then we suppress the use of the attrTable name in
509  // the NetCDF Attributes name.
510  if (varid == NC_GLOBAL && d4_attr_type == attr_container_c && (BESUtil::endsWith(d4_attr_name, "_GLOBAL") ||
511  BESUtil::endsWith(d4_attr_name, "HDF5_GLOBAL_integer_64"))) {
512  BESDEBUG("fonc",
513  "Suppressing global AttributeTable name '" << d4_attr_name
514  << "' from inclusion in NetCDF attributes namespace chain."
515  << endl);
516  new_attr_name = "";
517  } else {
518  new_attr_name = d4_attr_name;
519  }
520  }
521 
522 #if 0
523  // This was the old way of doing it and it polluted the attribute names
524  // by prepending full qualified variable names to the attribute name..
525  string new_name = new_attr_name;
526  if (!var_name.empty()) {
527  new_name = var_name + FONC_ATTRIBUTE_SEPARATOR + new_attr_name;
528  }
529 
530  // BESDEBUG("fonc","new_name: " << new_name << " new_attr_name: " << new_attr_name << " var_name: " << var_name << endl);
531 
532  new_name = FONcUtils::id2netcdf(new_name);
533 #endif
534 
535  string new_name = FONcUtils::id2netcdf(new_attr_name);;
536 
537 #if 0
538  if (varid == NC_GLOBAL) {
539  BESDEBUG("fonc", "FONcAttributes::addattrs() - Adding global attributes " << d4_attr_name << endl);
540  } else {
541  BESDEBUG("fonc", "FONcAttributes::addattrs() - Adding attribute " << new_name << endl);
542  }
543 #endif
544 
545  // If we want to map the attributes of the datatypes to those of netCDF-4, KY 2020-02-14
546  if (is_nc_enhanced == true)
547  //write_dap4_attrs_for_nc4_types(ncid, varid, var_name, new_attr_name, new_name, d4_attrs, attr, is_nc_enhanced);
548  write_dap4_attrs_for_nc4_types(ncid, varid, var_name, new_attr_name, new_name, attr, is_nc_enhanced);
549  else {
550  int stax = NC_NOERR;
551  string attr_type = "unknown"; // Used for error messages. jhrg 6/18/20
552  unsigned int attri = 0;
553  //unsigned int num_vals = attrs.get_attr_num(attr);
554  unsigned int num_vals = attr->num_values();
555  switch (d4_attr_type) {
556  case attr_container_c: {
557  // flatten
558  BESDEBUG("fonc",
559  "Attribute " << d4_attr_name << " is an attribute container. new_attr_name: \""
560  << new_attr_name
561  << "\"" << endl);
562  D4Attributes *c_attributes = attr->attributes();
563  if (c_attributes) {
564  add_dap4_attributes(ncid, varid, c_attributes, var_name, new_attr_name, is_nc_enhanced);
565  }
566 
567  break;
568  }
569 
570  case attr_byte_c:
571  case attr_uint8_c: {
572  // unsigned char
573  attr_type = "byte";
574  unsigned char vals[num_vals];
575  attri = 0;
576  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
577  string val = *vi;
578  istringstream is(val);
579  unsigned int uival = 0;
580  is >> uival;
581  vals[attri] = (unsigned char) uival;
582  ++attri;
583  }
584 #if 0
585  for (attri = 0; attri < num_vals; attri++) {
586  string val = attrs.get_attr(attr, attri);
587  istringstream is(val);
588  unsigned int uival = 0;
589  is >> uival;
590  vals[attri] = (unsigned char) uival;
591  }
592 #endif
593  stax = nc_put_att_uchar(ncid, varid, new_name.c_str(), NC_UBYTE, num_vals, vals);
594 
595  break;
596  }
597 
598  case attr_int16_c: {
599  // short
600  attr_type = "short";
601  short vals[num_vals];
602  attri = 0;
603  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
604  string val = *vi;
605  istringstream is(val);
606  short sval = 0;
607  is >> sval;
608  vals[attri] = sval;
609  ++attri;
610  }
611 
612 #if 0
613  for (attri = 0; attri < num_vals; attri++) {
614  string val = attrs.get_attr(attr, attri);
615  istringstream is(val);
616  short sval = 0;
617  is >> sval;
618  vals[attri] = sval;
619  }
620 #endif
621  stax = nc_put_att_short(ncid, varid, new_name.c_str(), NC_SHORT, num_vals, vals);
622 
623  break;
624  }
625 
626  case attr_uint16_c: {
627  // unsigned short
628  // (needs to be big enough to store an unsigned short
629  attr_type = "unsigned short";
630  attri = 0;
631  int vals[num_vals];
632  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
633  string val = *vi;
634  istringstream is(val);
635  int ival = 0;
636  is >> ival;
637  vals[attri] = ival;
638  ++attri;
639  }
640 
641 #if 0
642  for (attri = 0; attri < num_vals; attri++) {
643  string val = attrs.get_attr(attr, attri);
644  istringstream is(val);
645  int ival = 0;
646  is >> ival;
647  vals[attri] = ival;
648  }
649 #endif
650  stax = nc_put_att_int(ncid, varid, new_name.c_str(), NC_INT, num_vals, vals);
651 
652  break;
653  }
654 
655  case attr_int32_c: {
656  // int
657  attr_type = "int";
658  int vals[num_vals];
659  attri = 0;
660  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
661  string val = *vi;
662  istringstream is(val);
663  int sval = 0;
664  is >> sval;
665  vals[attri] = sval;
666  ++attri;
667  }
668 
669 #if 0
670  for (attri = 0; attri < num_vals; attri++) {
671  string val = attrs.get_attr(attr, attri);
672  istringstream is(val);
673  int ival = 0;
674  is >> ival;
675  vals[attri] = ival;
676  }
677 #endif
678  stax = nc_put_att_int(ncid, varid, new_name.c_str(), NC_INT, num_vals, vals);
679 
680  break;
681  }
682 
683  case attr_uint32_c: {
684  // uint
685  // needs to be big enough to store an unsigned int
686  attr_type = "unsigned int";
687  int vals[num_vals];
688  attri = 0;
689  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
690  string val = *vi;
691  istringstream is(val);
692  int sval = 0;
693  is >> sval;
694  vals[attri] = sval;
695  ++attri;
696  }
697 
698 #if 0
699  for (attri = 0; attri < num_vals; attri++) {
700  string val = attrs.get_attr(attr, attri);
701  istringstream is(val);
702  int lval = 0;
703  is >> lval;
704  vals[attri] = lval;
705  }
706 #endif
707  stax = nc_put_att_int(ncid, varid, new_name.c_str(), NC_INT, num_vals, vals);
708 
709  break;
710  }
711 
712  case attr_float32_c: {
713  // float
714  attr_type = "float";
715  float vals[num_vals];
716  attri = 0;
717  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
718  string val = *vi;
719  const char *cval = val.c_str();
720  //istringstream is(val);
721  float sval = 0;
722  sval = strtod(cval,NULL);
723  //is >> sval;
724  vals[attri] = sval;
725  ++attri;
726  }
727 
728 #if 0
729  for (attri = 0; attri < num_vals; attri++) {
730  string val = attrs.get_attr(attr, attri);
731  istringstream is(val);
732  float fval = 0;
733  is >> fval;
734  vals[attri] = fval;
735  }
736 #endif
737  stax = nc_put_att_float(ncid, varid, new_name.c_str(), NC_FLOAT, num_vals, vals);
738 
739  break;
740  }
741 
742  case attr_float64_c: {
743  // double
744  attr_type = "float64";
745  double vals[num_vals];
746  attri = 0;
747  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
748  string val = *vi;
749  const char *cval = val.c_str();
750  //istringstream is(val);
751  double sval = 0;
752  sval = strtod(cval,NULL);
753  //is >> sval;
754  vals[attri] = sval;
755  ++attri;
756  }
757 #if 0
758  for (attri = 0; attri < num_vals; attri++) {
759  string val = attrs.get_attr(attr, attri);
760  istringstream is(val);
761  double dval = 0;
762  is >> dval;
763  vals[attri] = dval;
764  }
765 #endif
766  stax = nc_put_att_double(ncid, varid, new_name.c_str(), NC_DOUBLE, num_vals, vals);
767 
768  break;
769  }
770 
771  case attr_str_c:
772  case attr_url_c:
773  case attr_otherxml_c: { // Added. jhrg 12.27.2011
774  attr_type = "string";
775  D4Attribute::D4AttributeIter vi, ve;
776  vi = attr->value_begin();
777  ve = attr->value_end();
778 
779  string val = (*vi);
780 
781  vi++;
782  for (; vi != ve; vi++) {
783  val += "\n" + *vi;
784  }
785 
786 #if 0
787  for (D4Attribute::D4AttributeIter vi = (*i)->value_begin(), ve = (*i)->value_end(); vi != ve; vi++) {
788  string val = *vi;
789  istringstream is(val);
790  unsigned int uival = 0;
791  is >> uival;
792  vals[attri] = (unsigned char) uival;
793  ++attri;
794  }
795 
796 
797  // string
798  string val = attrs.get_attr(attr, 0);
799  for (attri = 1; attri < num_vals; attri++) {
800  val += "\n" + attrs.get_attr(attr, attri);
801  }
802 #endif
803 
804  if (d4_attr_name != _FillValue) {
805  stax = nc_put_att_text(ncid, varid, new_name.c_str(), val.length(), val.c_str());
806  }
807  else {
808  BESDEBUG("fonc",
809  "FONcAttributes::add_attributes_worker - Original attribute value is first character: "
810  << val.c_str()[0] << endl);
811  stax = nc_put_att_text(ncid, varid, new_name.c_str(), 1, val.c_str());
812  if (stax == NC_NOERR) {
813  // New name for attribute _FillValue with original value
814  string new_name_fillvalue = "Orig_FillValue";
815  BESDEBUG("fonc",
816  "FONcAttributes::add_attributes_worker - New attribute value is original value: "
817  << val.c_str() << endl);
818  // This line causes the segmentation fault since attrs is changed and the original iterator of attrs doesn't exist anymore.
819  // So it causes the segmentation fault when next attribute is fetched in the for loop of the add_attributes(). KY 2019-12-13
820 #if 0
821  attrs.append_attr(new_name_fillvalue,"String", val);
822 #endif
823  stax = nc_put_att_text(ncid, varid, new_name_fillvalue.c_str(), val.length(), val.c_str());
824  }
825  }
826 
827  break;
828  }
829 
830  case attr_null_c:
831  case attr_int8_c:
832  case attr_int64_c:
833  case attr_uint64_c:
834  case attr_enum_c:
835  case attr_opaque_c:
836  default: {
837  // Temporarily don't support these types.TODO: add the support.
838  string err = (string) "File out netcdf, failed to write unknown/unsupported type of attribute " + new_name;
839  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
840  break;
841  }
842  }
843 
844  if (stax != NC_NOERR) {
845  string err = (string) "File out netcdf, failed to write " + attr_type + " attribute " + new_name;
846  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
847  }
848  }
849 }
850 
851 
865 void FONcAttributes::add_original_name(int ncid, int varid,
866  const string &var_name, const string &orig) {
867  if (var_name != orig) {
868  string attr_name = FONC_ORIGINAL_NAME;
869  int stax = nc_put_att_text(ncid, varid, attr_name.c_str(),
870  orig.length(), orig.c_str());
871  if (stax != NC_NOERR) {
872  string err = (string) "File out netcdf, "
873  + "failed to write change of name attribute for "
874  + var_name;
875  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
876  }
877  }
878 }
892 void
893 FONcAttributes::write_attrs_for_nc4_types(int ncid, int varid, const string &var_name, const string &global_attr_name,
894  const string &var_attr_name, AttrTable attrs, AttrTable::Attr_iter &attr,
895  bool is_nc_enhanced) {
896 
897  int stax = NC_NOERR;
898  string attr_type = "unknown"; // Used for error messages. jhrg 6/18/20
899  AttrType attrType = attrs.get_attr_type(attr);
900  unsigned int attri = 0;
901  unsigned int num_vals = attrs.get_attr_num(attr);
902  switch (attrType) {
903  case Attr_container: {
904  // flatten
905  BESDEBUG("fonc", "This is an attribute container. attr_name: \"" << global_attr_name << "\"" << endl);
906  AttrTable *container = attrs.get_attr_table(attr);
907  if (container) {
908  add_attributes(ncid, varid, *container, var_name, global_attr_name, is_nc_enhanced);
909  }
910  break;
911  }
912 
913  case Attr_byte: {
914  // unsigned char
915  //unsigned char vals[num_vals];
916  vector<unsigned char> vals;
917  vals.resize(num_vals);
918  for (attri = 0; attri < num_vals; attri++) {
919  string val = attrs.get_attr(attr, attri);
920  istringstream is(val);
921  unsigned int uival = 0;
922  is >> uival;
923  vals[attri] = (unsigned char) uival;
924  }
925  stax = nc_put_att_uchar(ncid, varid, var_attr_name.c_str(), NC_UBYTE,
926  num_vals, &vals[0]);
927 #if 0
928  if (stax != NC_NOERR) {
929  string err = (string) "File out netcdf, "
930  + "failed to write byte attribute " + var_attr_name;
931  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
932  }
933 #endif
934  break;
935  }
936 
937  case Attr_int16: {
938  // short
939  //short vals[num_vals];
940  vector<short> vals;
941  vals.resize(num_vals);
942  for (attri = 0; attri < num_vals; attri++) {
943  string val = attrs.get_attr(attr, attri);
944  istringstream is(val);
945  short sval = 0;
946  is >> sval;
947  vals[attri] = sval;
948  }
949  stax = nc_put_att_short(ncid, varid, var_attr_name.c_str(), NC_SHORT, num_vals, &vals[0]);
950 #if 0
951  if (stax != NC_NOERR) {
952  string err = (string) "File out netcdf, "
953  + "failed to write short attribute " + var_attr_name;
954  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
955  }
956 #endif
957 
958  break;
959  }
960 
961  case Attr_uint16: {
962  // unsigned short
963  // (needs to be big enough to store an unsigned short
964  //unsigned short vals[num_vals];
965  vector<unsigned short> vals;
966  vals.resize(num_vals);
967  for (attri = 0; attri < num_vals; attri++) {
968  string val = attrs.get_attr(attr, attri);
969  istringstream is(val);
970  unsigned short ival = 0;
971  is >> ival;
972  vals[attri] = ival;
973  }
974  stax = nc_put_att_ushort(ncid, varid, var_attr_name.c_str(), NC_USHORT, num_vals,
975  &vals[0]);
976 #if 0
977  if (stax != NC_NOERR) {
978  string err = (string) "File out netcdf, "
979  + "failed to write unsinged short attribute " + var_attr_name;
980  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
981  }
982 #endif
983 
984  break;
985  }
986 
987  case Attr_int32: {
988  // int
989  //int vals[num_vals];
990  vector<int> vals;
991  vals.resize(num_vals);
992  for (attri = 0; attri < num_vals; attri++) {
993  string val = attrs.get_attr(attr, attri);
994  istringstream is(val);
995  int ival = 0;
996  is >> ival;
997  vals[attri] = ival;
998  }
999  stax = nc_put_att_int(ncid, varid, var_attr_name.c_str(), NC_INT, num_vals, &vals[0]);
1000 
1001 #if 0
1002  if (stax != NC_NOERR) {
1003  string err = (string) "File out netcdf, "
1004  + "failed to write int attribute " + var_attr_name;
1005  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1006  }
1007 #endif
1008 
1009  break;
1010  }
1011 
1012  case Attr_uint32: {
1013  // uint
1014  //unsigned int vals[num_vals];
1015  vector<unsigned int> vals;
1016  vals.resize(num_vals);
1017  for (attri = 0; attri < num_vals; attri++) {
1018  string val = attrs.get_attr(attr, attri);
1019  istringstream is(val);
1020  unsigned int lval = 0;
1021  is >> lval;
1022  vals[attri] = lval;
1023  }
1024  stax = nc_put_att_uint(ncid, varid, var_attr_name.c_str(), NC_UINT, num_vals,
1025  &vals[0]);
1026 #if 0
1027  if (stax != NC_NOERR) {
1028  string err = (string) "File out netcdf, "
1029  + "failed to write byte attribute " + var_attr_name;
1030  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1031  }
1032 #endif
1033 
1034  break;
1035  }
1036 
1037  case Attr_float32: {
1038  // float
1039  //float vals[num_vals];
1040  vector<float> vals;
1041  vals.resize(num_vals);
1042  for (attri = 0; attri < num_vals; attri++) {
1043  string val = attrs.get_attr(attr, attri);
1044  const char *cval = val.c_str();
1045  //istringstream is(val);
1046  float fval = 0;
1047  fval = strtod(cval,NULL);
1048  //is >> fval;
1049  vals[attri] = fval;
1050  }
1051  stax = nc_put_att_float(ncid, varid, var_attr_name.c_str(), NC_FLOAT, num_vals, &vals[0]);
1052 
1053 #if 0
1054  if (stax != NC_NOERR) {
1055  string err = (string) "File out netcdf, "
1056  + "failed to write float attribute " + var_attr_name;
1057  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1058  }
1059 #endif
1060 
1061  break;
1062  }
1063 
1064  case Attr_float64: {
1065  // double
1066  //double vals[num_vals];
1067  vector<double> vals;
1068  vals.resize(num_vals);
1069  for (attri = 0; attri < num_vals; attri++) {
1070  string val = attrs.get_attr(attr, attri);
1071  const char *cval = val.c_str();
1072  //istringstream is(val);
1073  double dval = 0;
1074  dval = strtod(cval,NULL);
1075  //is >> dval;
1076  vals[attri] = dval;
1077  }
1078  stax = nc_put_att_double(ncid, varid, var_attr_name.c_str(), NC_DOUBLE, num_vals, &vals[0]);
1079 
1080 #if 0
1081  if (stax != NC_NOERR) {
1082  string err = (string) "File out netcdf, "
1083  + "failed to write double attribute " + var_attr_name;
1084  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1085  }
1086 #endif
1087 
1088  break;
1089  }
1090 
1091  case Attr_string:
1092  case Attr_url:
1093  case Attr_other_xml: { // Added. jhrg 12.27.2011
1094  // string
1095  string val = attrs.get_attr(attr, 0);
1096  for (attri = 1; attri < num_vals; attri++) {
1097  val += "\n" + attrs.get_attr(attr, attri);
1098  }
1099  string attr_name = attrs.get_name(attr);
1100  if (attr_name != _FillValue) {
1101  stax = nc_put_att_text(ncid, varid, var_attr_name.c_str(), val.length(), val.c_str());
1102  }
1103  else {
1104  BESDEBUG("fonc",
1105  "FONcAttributes::add_attributes_worker - Original attribute value is first character: "
1106  << val.c_str()[0] << endl);
1107  stax = nc_put_att_text(ncid, varid, var_attr_name.c_str(), 1, val.c_str());
1108  if (stax == NC_NOERR) {
1109  // New name for attribute _FillValue with original value
1110  string var_attr_name_fillvalue = "Orig_FillValue";
1111  BESDEBUG("fonc",
1112  "FONcAttributes::add_attributes_worker - New attribute value is original value: "
1113  << val.c_str() << endl);
1114  // This line causes the segmentation fault since attrs is changed and the original iterator of attrs doesn't exist anymore.
1115  // So it causes the segmentation fault when next attribute is fetched in the for loop of the add_attributes(). KY 2019-12-13
1116 #if 0
1117  attrs.append_attr(var_attr_name_fillvalue,"String", val);
1118 #endif
1119  stax = nc_put_att_text(ncid, varid, var_attr_name_fillvalue.c_str(), val.length(), val.c_str());
1120  }
1121  }
1122 
1123 #if 0
1124  if (stax != NC_NOERR) {
1125  string err = (string) "File out netcdf, "
1126  + "failed to write string attribute " + var_attr_name;
1127  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1128  }
1129 #endif
1130 
1131  break;
1132  }
1133 
1134 
1135  case Attr_unknown:
1136  default: {
1137  string err = (string) "File out netcdf, failed to write unknown type of attribute " + var_attr_name;
1138  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1139  break; // Not actually needed since FONcUtils::handle_error throws
1140  }
1141  }
1142 
1143  if (stax != NC_NOERR) {
1144  string err = (string) "File out netcdf, failed to write " + attr_type + " attribute " + var_attr_name;
1145  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1146  }
1147 }
1148 
1161 void
1163  int varid,
1164  const string &var_name,
1165  const string &global_attr_name,
1166  const string &var_attr_name,
1167  D4Attribute* attr,
1168  bool is_nc_enhanced) {
1169 
1170  D4AttributeType d4_attr_type = attr->type();
1171  int stax = NC_NOERR;
1172  unsigned int attri = 0;
1173  unsigned int num_vals = attr->num_values();
1174  switch (d4_attr_type) {
1175  case attr_container_c: {
1176  // flatten
1177  BESDEBUG("fonc", "This is an attribute container. attr_name: \"" << global_attr_name << "\"" << endl);
1178  D4Attributes *c_attributes = attr->attributes();
1179  if (c_attributes) {
1180  add_dap4_attributes(ncid, varid, c_attributes, var_name, global_attr_name, is_nc_enhanced);
1181  }
1182  }
1183  break;
1184  case attr_byte_c:
1185  case attr_uint8_c:{
1186  // unsigned char
1187  vector<unsigned char> vals;
1188  vals.resize(num_vals);
1189  attri = 0;
1190  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1191  string val = *vi;
1192  istringstream is(val);
1193  unsigned int uival = 0;
1194  is >> uival;
1195  vals[attri] = (unsigned char) uival;
1196  ++attri;
1197  }
1198  stax = nc_put_att_uchar(ncid, varid, var_attr_name.c_str(), NC_UBYTE,
1199  num_vals, &vals[0]);
1200  if (stax != NC_NOERR) {
1201  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1202  + "failed to write byte attribute " + var_attr_name;
1203  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1204  }
1205  }
1206  break;
1207  case attr_int8_c:{
1208  // 8-bit integer
1209  vector<int8_t> vals;
1210  vals.resize(num_vals);
1211  attri = 0;
1212  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1213  string val = *vi;
1214  istringstream is(val);
1215  int uival = 0;
1216  is >> uival;
1217  vals[attri] = (int8_t) uival;
1218  ++attri;
1219  }
1220  stax = nc_put_att_schar(ncid, varid, var_attr_name.c_str(), NC_BYTE,
1221  num_vals, &vals[0]);
1222  if (stax != NC_NOERR) {
1223  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1224  + "failed to write signed 8-bit integer attribute " + var_attr_name;
1225  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1226  }
1227  }
1228  break;
1229  case attr_int16_c: {
1230  // short
1231  vector<short> vals;
1232  vals.resize(num_vals);
1233  attri = 0;
1234  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1235  string val = *vi;
1236  istringstream is(val);
1237  short sval = 0;
1238  is >> sval;
1239  vals[attri] = sval;
1240  ++attri;
1241  }
1242 
1243  stax = nc_put_att_short(ncid, varid, var_attr_name.c_str(), NC_SHORT,
1244  num_vals, &vals[0]);
1245  if (stax != NC_NOERR) {
1246  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1247  + "failed to write short attribute " + var_attr_name;
1248  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1249  }
1250  }
1251  break;
1252  case attr_uint16_c: {
1253  // unsigned short
1254  attri = 0;
1255  vector<unsigned short>vals;
1256  vals.resize(num_vals);
1257  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1258  string val = *vi;
1259  istringstream is(val);
1260  unsigned short ival = 0;
1261  is >> ival;
1262  vals[attri] = ival;
1263  ++attri;
1264  }
1265 
1266  stax = nc_put_att_ushort(ncid, varid, var_attr_name.c_str(), NC_USHORT, num_vals,
1267  &vals[0]);
1268  if (stax != NC_NOERR) {
1269  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1270  + "failed to write unsigned short attribute " + var_attr_name;
1271  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1272  }
1273  }
1274  break;
1275  case attr_int32_c: {
1276  vector<int> vals;
1277  vals.resize(num_vals);
1278  attri = 0;
1279  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1280  string val = *vi;
1281  istringstream is(val);
1282  int sval = 0;
1283  is >> sval;
1284  vals[attri] = sval;
1285  ++attri;
1286  }
1287 
1288  stax = nc_put_att_int(ncid, varid, var_attr_name.c_str(), NC_INT, num_vals,
1289  &vals[0]);
1290  if (stax != NC_NOERR) {
1291  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1292  + "failed to write int attribute " + var_attr_name;
1293  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1294  }
1295  }
1296  break;
1297  case attr_uint32_c: {
1298  // uint
1299  vector<unsigned int> vals;
1300  vals.resize(num_vals);
1301  attri = 0;
1302  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1303  string val = *vi;
1304  istringstream is(val);
1305  unsigned int sval = 0;
1306  is >> sval;
1307  vals[attri] = sval;
1308  ++attri;
1309  }
1310 
1311  stax = nc_put_att_uint(ncid, varid, var_attr_name.c_str(), NC_UINT, num_vals,
1312  &vals[0]);
1313  if (stax != NC_NOERR) {
1314  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1315  + "failed to write unsigned int attribute " + var_attr_name;
1316  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1317  }
1318  }
1319  break;
1320  case attr_int64_c: {
1321  vector<long long> vals;
1322  vals.resize(num_vals);
1323  attri = 0;
1324  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1325  string val = *vi;
1326  istringstream is(val);
1327  long long sval = 0;
1328  is >> sval;
1329  vals[attri] = sval;
1330  ++attri;
1331  }
1332 
1333  stax = nc_put_att_longlong(ncid, varid, var_attr_name.c_str(), NC_INT64, num_vals,
1334  &vals[0]);
1335  if (stax != NC_NOERR) {
1336  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1337  + "failed to write 64-bit int attribute " + var_attr_name;
1338  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1339  }
1340  }
1341  break;
1342  case attr_uint64_c: {
1343  vector<unsigned long long> vals;
1344  vals.resize(num_vals);
1345  attri = 0;
1346  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1347  string val = *vi;
1348  istringstream is(val);
1349  unsigned long long sval = 0;
1350  is >> sval;
1351  vals[attri] = sval;
1352  ++attri;
1353  }
1354 
1355  stax = nc_put_att_ulonglong(ncid, varid, var_attr_name.c_str(), NC_UINT64, num_vals,
1356  &vals[0]);
1357  if (stax != NC_NOERR) {
1358  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1359  + "failed to write unsigned 64-bit int attribute " + var_attr_name;
1360  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1361  }
1362  }
1363  break;
1364 
1365  case attr_float32_c: {
1366  vector<float>vals;
1367  vals.resize(num_vals);
1368  attri = 0;
1369  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1370  string val = *vi;
1371  const char *cval = val.c_str();
1372  //istringstream is(val);
1373  float sval = 0;
1374  sval = strtod(cval,NULL);
1375  //is >> sval;
1376  vals[attri] = sval;
1377  ++attri;
1378  }
1379 
1380  stax = nc_put_att_float(ncid, varid, var_attr_name.c_str(), NC_FLOAT,
1381  num_vals, &vals[0]);
1382  if (stax != NC_NOERR) {
1383  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1384  + "failed to write float attribute " + var_attr_name;
1385  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1386  }
1387  }
1388  break;
1389  case attr_float64_c: {
1390  vector<double> vals;
1391  vals.resize(num_vals);
1392  attri = 0;
1393  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1394  string val = *vi;
1395  const char *cval = val.c_str();
1396  //istringstream is(val);
1397  double sval = 0;
1398  sval = strtod(cval,NULL);
1399  //is >> sval;
1400  vals[attri] = sval;
1401  ++attri;
1402  }
1403  stax = nc_put_att_double(ncid, varid, var_attr_name.c_str(), NC_DOUBLE,
1404  num_vals, &vals[0]);
1405  if (stax != NC_NOERR) {
1406  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1407  + "failed to write double attribute " + var_attr_name;
1408  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1409  }
1410  }
1411  break;
1412  case attr_str_c:
1413  case attr_url_c:
1414  case attr_otherxml_c: // Added. jhrg 12.27.2011
1415  {
1416 
1417  D4Attribute::D4AttributeIter vi,ve;
1418  vi = attr->value_begin();
1419  ve = attr->value_end();
1420 
1421  string val = (*vi);
1422 
1423  vi++;
1424  for (; vi != ve; vi++) {
1425  val += "\n" + *vi;
1426  }
1427 
1428  if (var_attr_name != _FillValue) {
1429  stax = nc_put_att_text(ncid, varid, var_attr_name.c_str(), val.length(), val.c_str());
1430  } else {
1431  BESDEBUG("fonc",
1432  "FONcAttributes::add_attributes_worker - Original attribute value is first character: "
1433  << val.c_str()[0] << endl);
1434  stax = nc_put_att_text(ncid, varid, var_attr_name.c_str(), 1, val.c_str());
1435  if (stax == NC_NOERR) {
1436  // New name for attribute _FillValue with original value
1437  string var_attr_name_fillvalue = "Orig_FillValue";
1438  BESDEBUG("fonc",
1439  "FONcAttributes::add_attributes_worker - New attribute value is original value: "
1440  << val.c_str() << endl);
1441  // This line causes the segmentation fault since attrs is changed and the original iterator of attrs doesn't exist anymore.
1442  // So it causes the segmentation fault when next attribute is fetched in the for loop of the add_attributes(). KY 2019-12-13
1443 #if 0
1444  attrs.append_attr(var_attr_name_fillvalue,"String", val);
1445 #endif
1446  stax = nc_put_att_text(ncid, varid, var_attr_name_fillvalue.c_str(), val.length(), val.c_str());
1447  }
1448  }
1449 
1450  if (stax != NC_NOERR) {
1451  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1452  + "failed to write string attribute " + var_attr_name;
1453  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1454  }
1455  }
1456  break;
1457 
1458  case attr_null_c:
1459  case attr_enum_c:
1460  case attr_opaque_c:
1461  {
1462  string err = (string) "File out netcdf, "
1463  + "failed to write unknown type of attribute " + var_attr_name;
1464  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1465  }
1466  break;
1467  }
1468 }
1469 //#endif
1470 
1471 #if 0
1472  int stax = NC_NOERR;
1473  AttrType attrType = attrs.get_attr_type(attr);
1474  unsigned int attri = 0;
1475  unsigned int num_vals = attrs.get_attr_num(attr);
1476  switch (attrType) {
1477  case Attr_container: {
1478  // flatten
1479  BESDEBUG("fonc", "This is an attribute container. attr_name: \"" << global_attr_name << "\"" << endl);
1480  AttrTable *container = attrs.get_attr_table(attr);
1481  if (container) {
1482  add_attributes(ncid, varid, *container, var_name, global_attr_name, is_nc_enhanced);
1483  }
1484  }
1485  break;
1486  case Attr_byte: {
1487  // unsigned char
1488  //unsigned char vals[num_vals];
1489  vector<unsigned char> vals;
1490  vals.resize(num_vals);
1491  for (attri = 0; attri < num_vals; attri++) {
1492  string val = attrs.get_attr(attr, attri);
1493  istringstream is(val);
1494  unsigned int uival = 0;
1495  is >> uival;
1496  vals[attri] = (unsigned char) uival;
1497  }
1498  stax = nc_put_att_uchar(ncid, varid, var_attr_name.c_str(), NC_UBYTE,
1499  num_vals, &vals[0]);
1500  if (stax != NC_NOERR) {
1501  string err = (string) "File out netcdf, "
1502  + "failed to write byte attribute " + var_attr_name;
1503  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1504  }
1505  }
1506  break;
1507  case Attr_int16: {
1508  // short
1509  //short vals[num_vals];
1510  vector<short> vals;
1511  vals.resize(num_vals);
1512  for (attri = 0; attri < num_vals; attri++) {
1513  string val = attrs.get_attr(attr, attri);
1514  istringstream is(val);
1515  short sval = 0;
1516  is >> sval;
1517  vals[attri] = sval;
1518  }
1519  stax = nc_put_att_short(ncid, varid, var_attr_name.c_str(), NC_SHORT,
1520  num_vals, &vals[0]);
1521  if (stax != NC_NOERR) {
1522  string err = (string) "File out netcdf, "
1523  + "failed to write short attribute " + var_attr_name;
1524  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1525  }
1526  }
1527  break;
1528  case Attr_uint16: {
1529  // unsigned short
1530  // (needs to be big enough to store an unsigned short
1531  //unsigned short vals[num_vals];
1532  vector<unsigned short> vals;
1533  vals.resize(num_vals);
1534  for (attri = 0; attri < num_vals; attri++) {
1535  string val = attrs.get_attr(attr, attri);
1536  istringstream is(val);
1537  unsigned short ival = 0;
1538  is >> ival;
1539  vals[attri] = ival;
1540  }
1541  stax = nc_put_att_ushort(ncid, varid, var_attr_name.c_str(), NC_USHORT, num_vals,
1542  &vals[0]);
1543  if (stax != NC_NOERR) {
1544  string err = (string) "File out netcdf, "
1545  + "failed to write unsinged short attribute " + var_attr_name;
1546  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1547  }
1548  }
1549  break;
1550  case Attr_int32: {
1551  // int
1552  //int vals[num_vals];
1553  vector<int> vals;
1554  vals.resize(num_vals);
1555  for (attri = 0; attri < num_vals; attri++) {
1556  string val = attrs.get_attr(attr, attri);
1557  istringstream is(val);
1558  int ival = 0;
1559  is >> ival;
1560  vals[attri] = ival;
1561  }
1562  stax = nc_put_att_int(ncid, varid, var_attr_name.c_str(), NC_INT, num_vals,
1563  &vals[0]);
1564  if (stax != NC_NOERR) {
1565  string err = (string) "File out netcdf, "
1566  + "failed to write int attribute " + var_attr_name;
1567  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1568  }
1569  }
1570  break;
1571  case Attr_uint32: {
1572  // uint
1573  //unsigned int vals[num_vals];
1574  vector<unsigned int> vals;
1575  vals.resize(num_vals);
1576  for (attri = 0; attri < num_vals; attri++) {
1577  string val = attrs.get_attr(attr, attri);
1578  istringstream is(val);
1579  unsigned int lval = 0;
1580  is >> lval;
1581  vals[attri] = lval;
1582  }
1583  stax = nc_put_att_uint(ncid, varid, var_attr_name.c_str(), NC_UINT, num_vals,
1584  &vals[0]);
1585  if (stax != NC_NOERR) {
1586  string err = (string) "File out netcdf, "
1587  + "failed to write byte attribute " + var_attr_name;
1588  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1589  }
1590  }
1591  break;
1592  case Attr_float32: {
1593  // float
1594  //float vals[num_vals];
1595  vector<float> vals;
1596  vals.resize(num_vals);
1597  for (attri = 0; attri < num_vals; attri++) {
1598  string val = attrs.get_attr(attr, attri);
1599  const char *cval = val.c_str();
1600  //istringstream is(val);
1601  float fval = 0;
1602  fval = strtod(cval,NULL);
1603  //is >> fval;
1604  vals[attri] = fval;
1605  }
1606  stax = nc_put_att_float(ncid, varid, var_attr_name.c_str(), NC_FLOAT,
1607  num_vals, &vals[0]);
1608  if (stax != NC_NOERR) {
1609  string err = (string) "File out netcdf, "
1610  + "failed to write float attribute " + var_attr_name;
1611  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1612  }
1613  }
1614  break;
1615  case Attr_float64: {
1616  // double
1617  //double vals[num_vals];
1618  vector<double> vals;
1619  vals.resize(num_vals);
1620  for (attri = 0; attri < num_vals; attri++) {
1621  string val = attrs.get_attr(attr, attri);
1622  const char *cval = val.c_str();
1623  //istringstream is(val);
1624  double dval = 0;
1625  dval = strtod(cval,NULL);
1626  //is >> dval;
1627  vals[attri] = dval;
1628  }
1629  stax = nc_put_att_double(ncid, varid, var_attr_name.c_str(), NC_DOUBLE,
1630  num_vals, &vals[0]);
1631  if (stax != NC_NOERR) {
1632  string err = (string) "File out netcdf, "
1633  + "failed to write double attribute " + var_attr_name;
1634  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1635  }
1636  }
1637  break;
1638  case Attr_string:
1639  case Attr_url:
1640  case Attr_other_xml: // Added. jhrg 12.27.2011
1641  {
1642  // string
1643  string val = attrs.get_attr(attr, 0);
1644  for (attri = 1; attri < num_vals; attri++) {
1645  val += "\n" + attrs.get_attr(attr, attri);
1646  }
1647  string attr_name = attrs.get_name(attr);
1648  if (attr_name != _FillValue) {
1649  stax = nc_put_att_text(ncid, varid, var_attr_name.c_str(), val.length(), val.c_str());
1650  } else {
1651  BESDEBUG("fonc",
1652  "FONcAttributes::add_attributes_worker - Original attribute value is first character: "
1653  << val.c_str()[0] << endl);
1654  stax = nc_put_att_text(ncid, varid, var_attr_name.c_str(), 1, val.c_str());
1655  if (stax == NC_NOERR) {
1656  // New name for attribute _FillValue with original value
1657  string var_attr_name_fillvalue = "Orig_FillValue";
1658  BESDEBUG("fonc",
1659  "FONcAttributes::add_attributes_worker - New attribute value is original value: "
1660  << val.c_str() << endl);
1661  // This line causes the segmentation fault since attrs is changed and the original iterator of attrs doesn't exist anymore.
1662  // So it causes the segmentation fault when next attribute is fetched in the for loop of the add_attributes(). KY 2019-12-13
1663 #if 0
1664  attrs.append_attr(var_attr_name_fillvalue,"String", val);
1665 #endif
1666  stax = nc_put_att_text(ncid, varid, var_attr_name_fillvalue.c_str(), val.length(), val.c_str());
1667  }
1668  }
1669 
1670  if (stax != NC_NOERR) {
1671  string err = (string) "File out netcdf, "
1672  + "failed to write string attribute " + var_attr_name;
1673  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1674  }
1675  }
1676  break;
1677 
1678  case Attr_unknown: {
1679  string err = (string) "File out netcdf, "
1680  + "failed to write unknown type of attribute " + var_attr_name;
1681  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1682  }
1683  break;
1684  }
1685 
1686 #endif
1687 
static bool endsWith(std::string const &fullString, std::string const &ending)
Definition: BESUtil.cc:942
static void add_dap4_attributes(int ncid, int varid, D4Attributes *d4_attrs, const string &var_name, const string &prepend_attr, bool is_netCDF_enhanced)
add_dap4_attributes
static void write_dap4_attrs_for_nc4_types(int ncid, int varid, const string &var_name, const string &global_attr_name, const string &var_attr_name, D4Attribute *attr, bool is_nc_enhanced)
writes out a single attribute that maps the dap4 datatype to netCDF-4
static void add_original_name(int ncid, int varid, const string &var_name, const string &orig)
Adds an attribute for the variable if the variable name had to be modified in any way.
static void add_attributes(int ncid, int varid, AttrTable &attrs, const string &var_name, const string &prepend_attr, bool is_netCDF_enhanced)
helper function for add_attributes
static void write_attrs_for_nc4_types(int ncid, int varid, const string &var_name, const string &global_attr_name, const string &var_attr_name, AttrTable attrs, AttrTable::Attr_iter &attr, bool is_nc_enhanced)
writes out a single attribute that maps the datatype to netCDF-4
static void add_variable_attributes(int ncid, int varid, BaseType *b, bool is_netCDF_enhanced, bool is_dap4)
Add the attributes for an OPeNDAP variable to the netcdf file.
static void handle_error(int stax, const string &err, const string &file, int line)
handle any netcdf errors
Definition: FONcUtils.cc:399
static string id2netcdf(string in)
convert the provided string to a netcdf allowed identifier.
Definition: FONcUtils.cc:84