1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
|
/*
This file is part of netcdf-4, a netCDF-like interface for HDF5, or a
HDF5 backend for netCDF, depending on your point of view.
This file handles the nc4 dimension functions.
Copyright 2003-5, University Corporation for Atmospheric Research. See
the COPYRIGHT file for copying and redistribution conditions.
$Id: nc4dim.c,v 1.41 2010/05/25 17:54:23 dmh Exp $
*/
#include "nc4internal.h"
#ifdef USE_PNETCDF
#include <pnetcdf.h>
#endif
/* Netcdf-4 files might have more than one unlimited dimension, but
return the first one anyway. */
/* Note that this code is inconsistent with nc_inq */
int
NC4_inq_unlimdim(int ncid, int *unlimdimidp)
{
NC_FILE_INFO_T *nc;
NC_GRP_INFO_T *grp, *g;
NC_HDF5_FILE_INFO_T *h5;
NC_DIM_INFO_T *dim;
int found = 0;
int retval;
LOG((2, "called nc_inq_unlimdim"));
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
return retval;
#ifdef USE_PNETCDF
/* Take care of files created/opened with parallel-netcdf library. */
if (nc->pnetcdf_file)
return ncmpi_inq_unlimdim(nc->int_ncid, unlimdimidp);
#endif /* USE_PNETCDF */
/* Take care of netcdf-3 files. */
assert(h5);
/* According to netcdf-3 manual, return -1 if there is no unlimited
dimension. */
*unlimdimidp = -1;
for (g = grp; g && !found; g = g->parent)
{
for (dim = g->dim; dim; dim = dim->next)
{
if (dim->unlimited)
{
*unlimdimidp = dim->dimid;
found++;
break;
}
}
}
return NC_NOERR;
}
/* Dimensions are defined in attributes attached to the appropriate
group in the data file. */
int
NC4_def_dim(int ncid, const char *name, size_t len, int *idp)
{
NC_FILE_INFO_T *nc;
NC_GRP_INFO_T *grp;
NC_HDF5_FILE_INFO_T *h5;
NC_DIM_INFO_T *dim;
char norm_name[NC_MAX_NAME + 1];
int retval = NC_NOERR;
LOG((2, "nc_def_dim: ncid 0x%x name %s len %d", ncid, name,
(int)len));
/* Find our global metadata structure. */
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
return retval;
#ifdef USE_PNETCDF
/* Take care of files created/opened with parallel-netcdf library. */
if (nc->pnetcdf_file)
return ncmpi_def_dim(nc->int_ncid, name, len, idp);
#endif /* USE_PNETCDF */
/* Take care of netcdf-3 files. */
assert(h5);
assert(h5 && nc && grp);
/* If the file is read-only, return an error. */
if (h5->no_write)
return NC_EPERM;
/* Check some stuff if strict nc3 rules are in effect. */
if (h5->cmode & NC_CLASSIC_MODEL)
{
/* Only one limited dimenson for strict nc3. */
if (len == NC_UNLIMITED)
for (dim = grp->dim; dim; dim = dim->next)
if (dim->unlimited)
return NC_EUNLIMIT;
/* Must be in define mode for stict nc3. */
if (!(h5->flags & NC_INDEF))
return NC_ENOTINDEFINE;
}
/* If it's not in define mode, enter define mode. */
if (!(h5->flags & NC_INDEF))
if ((retval = nc_redef(ncid)))
return retval;
/* Make sure this is a valid netcdf name. */
if ((retval = nc4_check_name(name, norm_name)))
return retval;
/* For classic model, stick with the classic format restriction:
* dim length has to fit in a 32-bit signed int. For 64-bit offset,
* it has to fit in a 32-bit unsigned int. */
if (h5->cmode & NC_CLASSIC_MODEL)
if((unsigned long) len > X_INT_MAX) /* Backward compat */
return NC_EDIMSIZE;
/* Make sure the name is not already in use. */
for (dim = grp->dim; dim; dim = dim->next)
if (!strncmp(dim->name, norm_name, NC_MAX_NAME))
return NC_ENAMEINUSE;
/* Add a dimension to the list. The ID must come from the file
* information, since dimids are visible in more than one group. */
nc4_dim_list_add(&grp->dim);
grp->dim->dimid = grp->file->nc4_info->next_dimid++;
/* Initialize the metadata for this dimension. */
if (!(grp->dim->name = malloc((strlen(norm_name) + 1) * sizeof(char))))
return NC_ENOMEM;
strcpy(grp->dim->name, norm_name);
grp->dim->len = len;
grp->dim->dirty++;
if (len == NC_UNLIMITED)
grp->dim->unlimited++;
/* Pass back the dimid. */
if (idp)
*idp = grp->dim->dimid;
return retval;
}
/* Given dim name, find its id. */
int
NC4_inq_dimid(int ncid, const char *name, int *idp)
{
NC_FILE_INFO_T *nc;
NC_GRP_INFO_T *grp, *g;
NC_HDF5_FILE_INFO_T *h5;
NC_DIM_INFO_T *dim;
char norm_name[NC_MAX_NAME + 1];
int finished = 0;
int retval;
LOG((2, "nc_inq_dimid: ncid 0x%x name %s", ncid, name));
/* Find metadata for this file. */
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
return retval;
#ifdef USE_PNETCDF
/* Take care of files created/opened with parallel-netcdf library. */
if (nc->pnetcdf_file)
return ncmpi_inq_dimid(nc->int_ncid, name, idp);
#endif /* USE_PNETCDF */
/* Handle netcdf-3 files. */
assert(h5);
assert(nc && grp);
/* Normalize name. */
if ((retval = nc4_normalize_name(name, norm_name)))
return retval;
/* Go through each dim and check for a name match. */
for (g = grp; g && !finished; g = g->parent)
for (dim = g->dim; dim; dim = dim->next)
if (!strncmp(dim->name, norm_name, NC_MAX_NAME))
{
if (idp)
*idp = dim->dimid;
finished++;
return NC_NOERR;
}
return NC_EBADDIM;
}
/* Find out name and len of a dim. For an unlimited dimension, the
length is the largest lenght so far written. If the name of lenp
pointers are NULL, they will be ignored. */
int
NC4_inq_dim(int ncid, int dimid, char *name, size_t *lenp)
{
NC_FILE_INFO_T *nc;
NC_HDF5_FILE_INFO_T *h5;
NC_GRP_INFO_T *grp, *dim_grp;
NC_DIM_INFO_T *dim;
int ret = NC_NOERR;
LOG((2, "nc_inq_dim: ncid 0x%x dimid %d", ncid, dimid));
/* Find our global metadata structure. */
if ((ret = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
return ret;
#ifdef USE_PNETCDF
/* Take care of files created/opened with parallel-netcdf library. */
if (nc->pnetcdf_file)
{
MPI_Offset mpi_len;
if ((ret = ncmpi_inq_dim(nc->int_ncid, dimid, name, &mpi_len)))
return ret;
if (lenp)
*lenp = mpi_len;
}
#endif /* USE_PNETCDF */
/* Take care of netcdf-3 files. */
assert(h5);
assert(nc && grp);
/* Find the dimension and its home group. */
if ((ret = nc4_find_dim(grp, dimid, &dim, &dim_grp)))
return ret;
assert(dim);
/* Return the dimension name, if the caller wants it. */
if (name && dim->name)
strcpy(name, dim->name);
/* Return the dimension length, if the caller wants it. */
if (lenp)
{
if (dim->unlimited)
{
/* Since this is an unlimited dimension, go to the file
and see how many records there are. Take the max number
of records from all the vars that share this
dimension. */
*lenp = 0;
if ((ret = nc4_find_dim_len(dim_grp, dimid, &lenp)))
return ret;
}
else
{
if (dim->too_long)
{
ret = NC_EDIMSIZE;
*lenp = NC_MAX_UINT;
}
else
*lenp = dim->len;
}
}
return ret;
}
/* Rename a dimension, for those who like to prevaricate. */
int
NC4_rename_dim(int ncid, int dimid, const char *name)
{
NC_FILE_INFO_T *nc;
NC_GRP_INFO_T *grp;
NC_HDF5_FILE_INFO_T *h5;
NC_DIM_INFO_T *dim;
char norm_name[NC_MAX_NAME + 1];
int retval;
if (!name)
return NC_EINVAL;
LOG((2, "nc_rename_dim: ncid 0x%x dimid %d name %s", ncid,
dimid, name));
/* Find info for this file and group, and set pointer to each. */
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
return retval;
assert(nc);
#ifdef USE_PNETCDF
/* Take care of files created/opened with parallel-netcdf library. */
if (nc->pnetcdf_file)
return ncmpi_rename_dim(nc->int_ncid, dimid, name);
#endif /* USE_PNETCDF */
/* Handle netcdf-3 cases. */
assert(h5);
assert(h5 && grp);
/* Trying to write to a read-only file? No way, Jose! */
if (h5->no_write)
return NC_EPERM;
/* Make sure this is a valid netcdf name. */
if ((retval = nc4_check_name(name, norm_name)))
return retval;
/* Make sure the new name is not already in use in this group. */
for (dim = grp->dim; dim; dim = dim->next)
if (!strncmp(dim->name, norm_name, NC_MAX_NAME))
return NC_ENAMEINUSE;
/* Find the dim. */
for (dim = grp->dim; dim; dim = dim->next)
if (dim->dimid == dimid)
break;
if (!dim)
return NC_EBADDIM;
/* If not in define mode, switch to it, unless the new name is
* shorter. (This is in accordance with the v3 interface.) */
/* if (!(h5->flags & NC_INDEF) && strlen(name) > strlen(dim->name)) */
/* { */
/* if (h5->cmode & NC_CLASSIC_MODEL) */
/* return NC_ENOTINDEFINE; */
/* if ((retval = nc_redef(ncid))) */
/* return retval; */
/* } */
/* Save the old name, we'll need it to rename this object when we
* sync to HDF5 file. But if there already is an old_name saved,
* just stick with what we've got, since the user might be renaming
* the crap out of this thing, without ever syncing with the
* file. When the sync does take place, we only need the original
* name of the dim, not any of the intermediate ones. If the user
* could just make up his mind, we could all get on to writing some
* data... */
if (!dim->old_name)
{
if (!(dim->old_name = malloc((strlen(dim->name) + 1) * sizeof(char))))
return NC_ENOMEM;
strcpy(dim->old_name, dim->name);
}
/* Give the dimension its new name in metadata. UTF8 normalization
* has been done. */
free(dim->name);
if (!(dim->name = malloc((strlen(norm_name) + 1) * sizeof(char))))
return NC_ENOMEM;
strcpy(dim->name, norm_name);
return NC_NOERR;
}
/* Returns an array of unlimited dimension ids.The user can get the
number of unlimited dimensions by first calling this with NULL for
the second pointer.
*/
int
NC4_inq_unlimdims(int ncid, int *nunlimdimsp, int *unlimdimidsp)
{
NC_DIM_INFO_T *dim;
NC_GRP_INFO_T *grp;
NC_FILE_INFO_T *nc;
NC_HDF5_FILE_INFO_T *h5;
int num_unlim = 0;
int retval;
LOG((2, "nc_inq_unlimdims: ncid 0x%x", ncid));
/* Find info for this file and group, and set pointer to each. */
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
return retval;
/* Get our dim info. */
assert(h5);
{
for (dim=grp->dim; dim; dim=dim->next)
{
if (dim->unlimited)
{
if (unlimdimidsp)
unlimdimidsp[num_unlim] = dim->dimid;
num_unlim++;
}
}
}
/* Give the number if the user wants it. */
if (nunlimdimsp)
*nunlimdimsp = num_unlim;
return NC_NOERR;
}
|