dim.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. /*
  2. * Copyright 1996, University Corporation for Atmospheric Research
  3. * See netcdf/COPYRIGHT file for copying and redistribution conditions.
  4. */
  5. /* $Id: dim.c,v 1.83 2010/05/25 17:54:15 dmh Exp $ */
  6. #include "nc.h"
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <assert.h>
  10. #include "ncx.h"
  11. #include "fbits.h"
  12. #include "utf8proc.h"
  13. /*
  14. * Free dim
  15. * Formerly
  16. NC_free_dim(dim)
  17. */
  18. void
  19. free_NC_dim(NC_dim *dimp)
  20. {
  21. if(dimp == NULL)
  22. return;
  23. free_NC_string(dimp->name);
  24. free(dimp);
  25. }
  26. NC_dim *
  27. new_x_NC_dim(NC_string *name)
  28. {
  29. NC_dim *dimp;
  30. dimp = (NC_dim *) malloc(sizeof(NC_dim));
  31. if(dimp == NULL)
  32. return NULL;
  33. dimp->name = name;
  34. dimp->hash = hash_fast(name->cp, strlen(name->cp));
  35. dimp->size = 0;
  36. return(dimp);
  37. }
  38. /*
  39. * Formerly
  40. NC_new_dim(const char *uname, long size)
  41. */
  42. static NC_dim *
  43. new_NC_dim(const char *uname, size_t size)
  44. {
  45. NC_string *strp;
  46. NC_dim *dimp;
  47. char *name = (char *)utf8proc_NFC((const unsigned char *)uname);
  48. if(name == NULL)
  49. return NULL;
  50. strp = new_NC_string(strlen(name), name);
  51. free(name);
  52. if(strp == NULL)
  53. return NULL;
  54. dimp = new_x_NC_dim(strp);
  55. if(dimp == NULL)
  56. {
  57. free_NC_string(strp);
  58. return NULL;
  59. }
  60. dimp->size = size;
  61. return(dimp);
  62. }
  63. static NC_dim *
  64. dup_NC_dim(const NC_dim *dimp)
  65. {
  66. return new_NC_dim(dimp->name->cp, dimp->size);
  67. }
  68. /*
  69. * Step thru NC_DIMENSION array, seeking the UNLIMITED dimension.
  70. * Return dimid or -1 on not found.
  71. * *dimpp is set to the appropriate NC_dim.
  72. * The loop structure is odd. In order to parallelize,
  73. * we moved a clearer 'break' inside the loop body to the loop test.
  74. */
  75. int
  76. find_NC_Udim(const NC_dimarray *ncap, NC_dim **dimpp)
  77. {
  78. assert(ncap != NULL);
  79. if(ncap->nelems == 0)
  80. return -1;
  81. {
  82. int dimid = 0;
  83. NC_dim **loc = ncap->value;
  84. for(; (size_t) dimid < ncap->nelems
  85. && (*loc)->size != NC_UNLIMITED; dimid++, loc++)
  86. {
  87. /*EMPTY*/
  88. }
  89. if(dimid >= ncap->nelems)
  90. return(-1); /* not found */
  91. /* else, normal return */
  92. if(dimpp != NULL)
  93. *dimpp = *loc;
  94. return dimid;
  95. }
  96. }
  97. /*
  98. * Step thru NC_DIMENSION array, seeking match on uname.
  99. * Return dimid or -1 on not found.
  100. * *dimpp is set to the appropriate NC_dim.
  101. * The loop structure is odd. In order to parallelize,
  102. * we moved a clearer 'break' inside the loop body to the loop test.
  103. */
  104. static int
  105. NC_finddim(const NC_dimarray *ncap, const char *uname, NC_dim **dimpp)
  106. {
  107. int dimid;
  108. uint32_t shash;
  109. NC_dim ** loc;
  110. char *name;
  111. assert(ncap != NULL);
  112. if(ncap->nelems == 0)
  113. return -1;
  114. {
  115. dimid = 0;
  116. loc = (NC_dim **) ncap->value;
  117. /* normalized version of uname */
  118. name = (char *)utf8proc_NFC((const unsigned char *)uname);
  119. if(name == NULL)
  120. return NC_ENOMEM;
  121. shash = hash_fast(name, strlen(name));
  122. for(; (size_t) dimid < ncap->nelems
  123. && ((*loc)->hash != shash
  124. || strncmp((*loc)->name->cp, name, strlen(name)) != 0);
  125. dimid++, loc++)
  126. {
  127. /*EMPTY*/
  128. }
  129. free(name);
  130. if(dimid >= ncap->nelems)
  131. return(-1); /* not found */
  132. /* else, normal return */
  133. if(dimpp != NULL)
  134. *dimpp = *loc;
  135. return(dimid);
  136. }
  137. }
  138. /* dimarray */
  139. /*
  140. * Free the stuff "in" (referred to by) an NC_dimarray.
  141. * Leaves the array itself allocated.
  142. */
  143. void
  144. free_NC_dimarrayV0(NC_dimarray *ncap)
  145. {
  146. assert(ncap != NULL);
  147. if(ncap->nelems == 0)
  148. return;
  149. assert(ncap->value != NULL);
  150. {
  151. NC_dim **dpp = ncap->value;
  152. NC_dim *const *const end = &dpp[ncap->nelems];
  153. for( /*NADA*/; dpp < end; dpp++)
  154. {
  155. free_NC_dim(*dpp);
  156. *dpp = NULL;
  157. }
  158. }
  159. ncap->nelems = 0;
  160. }
  161. /*
  162. * Free NC_dimarray values.
  163. * formerly
  164. NC_free_array()
  165. */
  166. void
  167. free_NC_dimarrayV(NC_dimarray *ncap)
  168. {
  169. assert(ncap != NULL);
  170. if(ncap->nalloc == 0)
  171. return;
  172. assert(ncap->value != NULL);
  173. free_NC_dimarrayV0(ncap);
  174. free(ncap->value);
  175. ncap->value = NULL;
  176. ncap->nalloc = 0;
  177. }
  178. int
  179. dup_NC_dimarrayV(NC_dimarray *ncap, const NC_dimarray *ref)
  180. {
  181. int status = NC_NOERR;
  182. assert(ref != NULL);
  183. assert(ncap != NULL);
  184. if(ref->nelems != 0)
  185. {
  186. const size_t sz = ref->nelems * sizeof(NC_dim *);
  187. ncap->value = (NC_dim **) malloc(sz);
  188. if(ncap->value == NULL)
  189. return NC_ENOMEM;
  190. (void) memset(ncap->value, 0, sz);
  191. ncap->nalloc = ref->nelems;
  192. }
  193. ncap->nelems = 0;
  194. {
  195. NC_dim **dpp = ncap->value;
  196. const NC_dim **drpp = (const NC_dim **)ref->value;
  197. NC_dim *const *const end = &dpp[ref->nelems];
  198. for( /*NADA*/; dpp < end; drpp++, dpp++, ncap->nelems++)
  199. {
  200. *dpp = dup_NC_dim(*drpp);
  201. if(*dpp == NULL)
  202. {
  203. status = NC_ENOMEM;
  204. break;
  205. }
  206. }
  207. }
  208. if(status != NC_NOERR)
  209. {
  210. free_NC_dimarrayV(ncap);
  211. return status;
  212. }
  213. assert(ncap->nelems == ref->nelems);
  214. return NC_NOERR;
  215. }
  216. /*
  217. * Add a new handle on the end of an array of handles
  218. * Formerly
  219. NC_incr_array(array, tail)
  220. */
  221. static int
  222. incr_NC_dimarray(NC_dimarray *ncap, NC_dim *newelemp)
  223. {
  224. NC_dim **vp;
  225. assert(ncap != NULL);
  226. if(ncap->nalloc == 0)
  227. {
  228. assert(ncap->nelems == 0);
  229. vp = (NC_dim **) malloc(NC_ARRAY_GROWBY * sizeof(NC_dim *));
  230. if(vp == NULL)
  231. return NC_ENOMEM;
  232. ncap->value = vp;
  233. ncap->nalloc = NC_ARRAY_GROWBY;
  234. }
  235. else if(ncap->nelems +1 > ncap->nalloc)
  236. {
  237. vp = (NC_dim **) realloc(ncap->value,
  238. (ncap->nalloc + NC_ARRAY_GROWBY) * sizeof(NC_dim *));
  239. if(vp == NULL)
  240. return NC_ENOMEM;
  241. ncap->value = vp;
  242. ncap->nalloc += NC_ARRAY_GROWBY;
  243. }
  244. if(newelemp != NULL)
  245. {
  246. ncap->value[ncap->nelems] = newelemp;
  247. ncap->nelems++;
  248. }
  249. return NC_NOERR;
  250. }
  251. NC_dim *
  252. elem_NC_dimarray(const NC_dimarray *ncap, size_t elem)
  253. {
  254. assert(ncap != NULL);
  255. /* cast needed for braindead systems with signed size_t */
  256. if(ncap->nelems == 0 || (unsigned long) elem >= ncap->nelems)
  257. return NULL;
  258. assert(ncap->value != NULL);
  259. return ncap->value[elem];
  260. }
  261. /* Public */
  262. int
  263. NC3_def_dim(int ncid, const char *name, size_t size, int *dimidp)
  264. {
  265. int status;
  266. NC *ncp;
  267. int dimid;
  268. NC_dim *dimp;
  269. status = NC_check_id(ncid, &ncp);
  270. if(status != NC_NOERR)
  271. return status;
  272. if(!NC_indef(ncp))
  273. return NC_ENOTINDEFINE;
  274. status = NC_check_name(name);
  275. if(status != NC_NOERR)
  276. return status;
  277. if ((ncp->flags & NC_64BIT_OFFSET) && sizeof(off_t) > 4) {
  278. /* CDF2 format and LFS */
  279. if(size > X_UINT_MAX - 3) /* "- 3" handles rounded-up size */
  280. return NC_EDIMSIZE;
  281. } else {
  282. /* CDF1 format */
  283. if(size > X_INT_MAX - 3)
  284. return NC_EDIMSIZE;
  285. }
  286. if(size == NC_UNLIMITED)
  287. {
  288. dimid = find_NC_Udim(&ncp->dims, &dimp);
  289. if(dimid != -1)
  290. {
  291. assert(dimid != -1);
  292. return NC_EUNLIMIT;
  293. }
  294. }
  295. if(ncp->dims.nelems >= NC_MAX_DIMS)
  296. return NC_EMAXDIMS;
  297. dimid = NC_finddim(&ncp->dims, name, &dimp);
  298. if(dimid != -1)
  299. return NC_ENAMEINUSE;
  300. dimp = new_NC_dim(name, size);
  301. if(dimp == NULL)
  302. return NC_ENOMEM;
  303. status = incr_NC_dimarray(&ncp->dims, dimp);
  304. if(status != NC_NOERR)
  305. {
  306. free_NC_dim(dimp);
  307. return status;
  308. }
  309. if(dimidp != NULL)
  310. *dimidp = (int)ncp->dims.nelems -1;
  311. return NC_NOERR;
  312. }
  313. int
  314. NC3_inq_dimid(int ncid, const char *name, int *dimid_ptr)
  315. {
  316. int status;
  317. NC *ncp;
  318. int dimid;
  319. status = NC_check_id(ncid, &ncp);
  320. if(status != NC_NOERR)
  321. return status;
  322. dimid = NC_finddim(&ncp->dims, name, NULL);
  323. if(dimid == -1)
  324. return NC_EBADDIM;
  325. if (dimid_ptr)
  326. *dimid_ptr = dimid;
  327. return NC_NOERR;
  328. }
  329. int
  330. NC3_inq_dim(int ncid, int dimid, char *name, size_t *sizep)
  331. {
  332. int status;
  333. NC *ncp;
  334. NC_dim *dimp;
  335. status = NC_check_id(ncid, &ncp);
  336. if(status != NC_NOERR)
  337. return status;
  338. dimp = elem_NC_dimarray(&ncp->dims, (size_t)dimid);
  339. if(dimp == NULL)
  340. return NC_EBADDIM;
  341. if(name != NULL)
  342. {
  343. (void)strncpy(name, dimp->name->cp,
  344. dimp->name->nchars);
  345. name[dimp->name->nchars] = 0;
  346. }
  347. if(sizep != NULL)
  348. {
  349. if(dimp->size == NC_UNLIMITED)
  350. *sizep = NC_get_numrecs(ncp);
  351. else
  352. *sizep = dimp->size;
  353. }
  354. return NC_NOERR;
  355. }
  356. int
  357. NC3_rename_dim( int ncid, int dimid, const char *unewname)
  358. {
  359. int status;
  360. NC *ncp;
  361. int existid;
  362. NC_dim *dimp;
  363. char *newname; /* normalized */
  364. status = NC_check_id(ncid, &ncp);
  365. if(status != NC_NOERR)
  366. return status;
  367. if(NC_readonly(ncp))
  368. return NC_EPERM;
  369. status = NC_check_name(unewname);
  370. if(status != NC_NOERR)
  371. return status;
  372. existid = NC_finddim(&ncp->dims, unewname, &dimp);
  373. if(existid != -1)
  374. return NC_ENAMEINUSE;
  375. dimp = elem_NC_dimarray(&ncp->dims, (size_t)dimid);
  376. if(dimp == NULL)
  377. return NC_EBADDIM;
  378. newname = (char *)utf8proc_NFC((const unsigned char *)unewname);
  379. if(newname == NULL)
  380. return NC_ENOMEM;
  381. if(NC_indef(ncp))
  382. {
  383. NC_string *old = dimp->name;
  384. NC_string *newStr = new_NC_string(strlen(newname), newname);
  385. free(newname);
  386. if(newStr == NULL)
  387. return NC_ENOMEM;
  388. dimp->name = newStr;
  389. dimp->hash = hash_fast(newStr->cp, strlen(newStr->cp));
  390. free_NC_string(old);
  391. return NC_NOERR;
  392. }
  393. /* else, not in define mode */
  394. status = set_NC_string(dimp->name, newname);
  395. dimp->hash = hash_fast(newname, strlen(newname));
  396. free(newname);
  397. if(status != NC_NOERR)
  398. return status;
  399. set_NC_hdirty(ncp);
  400. if(NC_doHsync(ncp))
  401. {
  402. status = NC_sync(ncp);
  403. if(status != NC_NOERR)
  404. return status;
  405. }
  406. return NC_NOERR;
  407. }