int NC3_del_att(int ncid, int varid, const char *uname) { int status; NC *ncp; NC_attrarray *ncap; NC_attr **attrpp; NC_attr *old = NULL; int attrid; size_t slen; status = NC_check_id(ncid, &ncp); if(status != NC_NOERR) return status; if(!NC_indef(ncp)) return NC_ENOTINDEFINE; ncap = NC_attrarray0(ncp, varid); if(ncap == NULL) return NC_ENOTVAR; { char *name = (char *)utf8proc_NFC((const unsigned char *)uname); if(name == NULL) return NC_ENOMEM; /* sortof inline NC_findattr() */ slen = strlen(name); attrpp = (NC_attr **) ncap->value; for(attrid = 0; (size_t) attrid < ncap->nelems; attrid++, attrpp++) { if( slen == (*attrpp)->name->nchars && strncmp(name, (*attrpp)->name->cp, slen) == 0) { old = *attrpp; break; } } free(name); } if( (size_t) attrid == ncap->nelems ) return NC_ENOTATT; /* end inline NC_findattr() */ /* shuffle down */ for(attrid++; (size_t) attrid < ncap->nelems; attrid++) { *attrpp = *(attrpp + 1); attrpp++; } *attrpp = NULL; /* decrement count */ ncap->nelems--; free_NC_attr(old); return NC_NOERR; }
/* Read a NC_attr from the header */ static int v1h_get_NC_attr(v1hs *gsp, NC_attr **attrpp) { NC_string *strp; int status; nc_type type; size_t nelems; NC_attr *attrp; status = v1h_get_NC_string(gsp, &strp); if(status != ENOERR) return status; status = v1h_get_nc_type(gsp, &type); if(status != ENOERR) goto unwind_name; status = v1h_get_size_t(gsp, &nelems); if(status != ENOERR) goto unwind_name; attrp = new_x_NC_attr(strp, type, nelems); if(attrp == NULL) { status = NC_ENOMEM; goto unwind_name; } status = v1h_get_NC_attrV(gsp, attrp); if(status != ENOERR) { free_NC_attr(attrp); /* frees strp */ return status; } *attrpp = attrp; return ENOERR; unwind_name: free_NC_string(strp); return status; }
/* * Free the stuff "in" (referred to by) an NC_attrarray. * Leaves the array itself allocated. */ void free_NC_attrarrayV0(NC_attrarray *ncap) { assert(ncap != NULL); if(ncap->nelems == 0) return; assert(ncap->value != NULL); { NC_attr **app = ncap->value; NC_attr *const *const end = &app[ncap->nelems]; for( /*NADA*/; app < end; app++) { free_NC_attr(*app); *app = NULL; } } ncap->nelems = 0; }
int nc_copy_att(int ncid_in, int varid_in, const char *name, int ncid_out, int ovarid) { int status; NC_attr *iattrp; NC *ncp; NC_attrarray *ncap; NC_attr **attrpp; NC_attr *old = NULL; NC_attr *attrp; status = NC_lookupattr(ncid_in, varid_in, name, &iattrp); if(status != NC_NOERR) return status; status = NC_check_id(ncid_out, &ncp); if(status != NC_NOERR) return status; if(NC_readonly(ncp)) return NC_EPERM; ncap = NC_attrarray0(ncp, ovarid); if(ncap == NULL) return NC_ENOTVAR; attrpp = NC_findattr(ncap, name); if(attrpp != NULL) /* name in use */ { if(!NC_indef(ncp) ) { attrp = *attrpp; /* convenience */ if(iattrp->xsz > attrp->xsz) return NC_ENOTINDEFINE; /* else, we can reuse existing without redef */ attrp->xsz = iattrp->xsz; attrp->type = iattrp->type; attrp->nelems = iattrp->nelems; (void) memcpy(attrp->xvalue, iattrp->xvalue, iattrp->xsz); set_NC_hdirty(ncp); if(NC_doHsync(ncp)) { status = NC_sync(ncp); if(status != NC_NOERR) return status; } return NC_NOERR; } /* else, redefine using existing array slot */ old = *attrpp; } else { if(!NC_indef(ncp)) return NC_ENOTINDEFINE; if(ncap->nelems >= NC_MAX_ATTRS) return NC_EMAXATTS; } attrp = new_NC_attr(name, iattrp->type, iattrp->nelems); if(attrp == NULL) return NC_ENOMEM; (void) memcpy(attrp->xvalue, iattrp->xvalue, iattrp->xsz); if(attrpp != NULL) { assert(old != NULL); *attrpp = attrp; free_NC_attr(old); } else { status = incr_NC_attrarray(ncap, attrp); if(status != NC_NOERR) { free_NC_attr(attrp); return status; } } return NC_NOERR; }
int nc_put_att_double(int ncid, int varid, const char *name, nc_type type, size_t nelems, const double *value) { int status; NC *ncp; NC_attrarray *ncap; NC_attr **attrpp; NC_attr *old = NULL; NC_attr *attrp; status = NC_check_id(ncid, &ncp); if(status != NC_NOERR) return status; if(NC_readonly(ncp)) return NC_EPERM; ncap = NC_attrarray0(ncp, varid); if(ncap == NULL) return NC_ENOTVAR; status = nc_cktype(type); if(status != NC_NOERR) return status; if(type == NC_CHAR) return NC_ECHAR; /* cast needed for braindead systems with signed size_t */ if((unsigned long) nelems > X_INT_MAX) /* backward compat */ return NC_EINVAL; /* Invalid nelems */ if(nelems != 0 && value == NULL) return NC_EINVAL; /* Null arg */ attrpp = NC_findattr(ncap, name); if(attrpp != NULL) /* name in use */ { if(!NC_indef(ncp) ) { const size_t xsz = ncx_len_NC_attrV(type, nelems); attrp = *attrpp; /* convenience */ if(xsz > attrp->xsz) return NC_ENOTINDEFINE; /* else, we can reuse existing without redef */ attrp->xsz = xsz; attrp->type = type; attrp->nelems = nelems; if(nelems != 0) { void *xp = attrp->xvalue; status = ncx_pad_putn_Idouble(&xp, nelems, value, type); } set_NC_hdirty(ncp); if(NC_doHsync(ncp)) { const int lstatus = NC_sync(ncp); /* * N.B.: potentially overrides NC_ERANGE * set by ncx_pad_putn_Idouble */ if(lstatus != ENOERR) return lstatus; } return status; } /* else, redefine using existing array slot */ old = *attrpp; } else { if(!NC_indef(ncp)) return NC_ENOTINDEFINE; if(ncap->nelems >= NC_MAX_ATTRS) return NC_EMAXATTS; } status = NC_check_name(name); if(status != NC_NOERR) return status; attrp = new_NC_attr(name, type, nelems); if(attrp == NULL) return NC_ENOMEM; if(nelems != 0) { void *xp = attrp->xvalue; status = ncx_pad_putn_Idouble(&xp, nelems, value, type); } if(attrpp != NULL) { assert(old != NULL); *attrpp = attrp; free_NC_attr(old); } else { const int lstatus = incr_NC_attrarray(ncap, attrp); /* * N.B.: potentially overrides NC_ERANGE * set by ncx_pad_putn_Idouble */ if(lstatus != NC_NOERR) { free_NC_attr(attrp); return lstatus; } } return status; }
int NC3_put_att( int ncid, int varid, const char *name, nc_type type, size_t nelems, const void *value, nc_type memtype) { int status; NC *nc; NC3_INFO* ncp; NC_attrarray *ncap; NC_attr **attrpp; NC_attr *old = NULL; NC_attr *attrp; unsigned char fill[8]; /* fill value in internal representation */ status = NC_check_id(ncid, &nc); if(status != NC_NOERR) return status; ncp = NC3_DATA(nc); if(NC_readonly(ncp)) return NC_EPERM; ncap = NC_attrarray0(ncp, varid); if(ncap == NULL) return NC_ENOTVAR; if (name == NULL) return NC_EBADNAME; /* check NC_EBADTYPE */ status = nc3_cktype(nc->mode, type); if(status != NC_NOERR) return status; if(memtype == NC_NAT) memtype = type; if(memtype != NC_CHAR && type == NC_CHAR) return NC_ECHAR; if(memtype == NC_CHAR && type != NC_CHAR) return NC_ECHAR; /* cast needed for braindead systems with signed size_t */ if((unsigned long) nelems > X_INT_MAX) /* backward compat */ return NC_EINVAL; /* Invalid nelems */ if(nelems != 0 && value == NULL) return NC_EINVAL; /* Null arg */ /* Temporarily removed to preserve extant workflows (NCO based and others). See https://github.com/Unidata/netcdf-c/issues/843 for more information. */ // if (varid != NC_GLOBAL && !strcmp(name, _FillValue)) { // /* Fill value must be of the same data type */ // if (type != ncp->vars.value[varid]->type) return NC_EBADTYPE; // // /* Fill value must have exactly one value */ // if (nelems != 1) return NC_EINVAL; // // /* Only allow for variables defined in initial define mode */ // if (ncp->old != NULL && varid < ncp->old->vars.nelems) // return NC_ELATEFILL; /* try put attribute for an old variable */ // } attrpp = NC_findattr(ncap, name); /* 4 cases: exists X indef */ status = NC3_inq_default_fill_value(type, &fill); if (status != NC_NOERR) return status; if(attrpp != NULL) { /* name in use */ if(!NC_indef(ncp)) { const size_t xsz = ncx_len_NC_attrV(type, nelems); attrp = *attrpp; /* convenience */ if(xsz > attrp->xsz) return NC_ENOTINDEFINE; /* else, we can reuse existing without redef */ attrp->xsz = xsz; attrp->type = type; attrp->nelems = nelems; if(nelems != 0) { void *xp = attrp->xvalue; /* for CDF-1 and CDF-2, NC_BYTE is treated the same type as uchar memtype */ if (!fIsSet(ncp->flags,NC_64BIT_DATA) && type == NC_BYTE && memtype == NC_UBYTE) { status = NC3_inq_default_fill_value(NC_UBYTE, &fill); if (status != NC_NOERR) return status; status = dispatchput(&xp, nelems, value, memtype, memtype, &fill); } else status = dispatchput(&xp, nelems, value, type, memtype, &fill); } set_NC_hdirty(ncp); if(NC_doHsync(ncp)) { const int lstatus = NC_sync(ncp); /* * N.B.: potentially overrides NC_ERANGE * set by ncx_pad_putn_I$1 */ if(lstatus != NC_NOERR) return lstatus; } return status; } /* else, redefine using existing array slot */ old = *attrpp; } else { if(!NC_indef(ncp)) return NC_ENOTINDEFINE; } status = NC_check_name(name); if(status != NC_NOERR) return status; attrp = new_NC_attr(name, type, nelems); if(attrp == NULL) return NC_ENOMEM; if(nelems != 0) { void *xp = attrp->xvalue; /* for CDF-1 and CDF-2, NC_BYTE is treated the same type as uchar memtype */ if (!fIsSet(ncp->flags,NC_64BIT_DATA) && type == NC_BYTE && memtype == NC_UBYTE) { status = NC3_inq_default_fill_value(NC_UBYTE, &fill); if (status != NC_NOERR) return status; status = dispatchput(&xp, nelems, (const void*)value, memtype, memtype, &fill); } else status = dispatchput(&xp, nelems, (const void*)value, type, memtype, &fill); } if(attrpp != NULL) { *attrpp = attrp; if(old != NULL) free_NC_attr(old); } else { const int lstatus = incr_NC_attrarray(ncap, attrp); /* * N.B.: potentially overrides NC_ERANGE * set by ncx_pad_putn_I$1 */ if(lstatus != NC_NOERR) { free_NC_attr(attrp); return lstatus; } } return status; }