/src/netcdf-c/libdispatch/ddispatch.c
| Line | Count | Source | 
| 1 |  | /* | 
| 2 |  | Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata | 
| 3 |  | See LICENSE.txt for license information. | 
| 4 |  | */ | 
| 5 |  |  | 
| 6 |  | #include "config.h" | 
| 7 |  | #include "ncdispatch.h" | 
| 8 |  | #include "ncuri.h" | 
| 9 |  | #include "nclog.h" | 
| 10 |  | #include "ncbytes.h" | 
| 11 |  | #include "ncrc.h" | 
| 12 |  | #include "ncoffsets.h" | 
| 13 |  | #include "ncpathmgr.h" | 
| 14 |  | #include "ncxml.h" | 
| 15 |  | #include "nc4internal.h" | 
| 16 |  |  | 
| 17 |  | /* Required for getcwd, other functions. */ | 
| 18 |  | #ifdef HAVE_UNISTD_H | 
| 19 |  | #include <unistd.h> | 
| 20 |  | #endif | 
| 21 |  |  | 
| 22 |  | /* Required for getcwd, other functions. */ | 
| 23 |  | #ifdef _WIN32 | 
| 24 |  | #include <direct.h> | 
| 25 |  | #endif | 
| 26 |  |  | 
| 27 |  | #if defined(NETCDF_ENABLE_BYTERANGE) || defined(NETCDF_ENABLE_DAP) || defined(NETCDF_ENABLE_DAP4) | 
| 28 |  | #include <curl/curl.h> | 
| 29 |  | #endif | 
| 30 |  |  | 
| 31 |  | #ifdef NETCDF_ENABLE_S3 | 
| 32 |  | #include "ncs3sdk.h" | 
| 33 |  | #endif | 
| 34 |  |  | 
| 35 | 0 | #define MAXPATH 1024 | 
| 36 |  |  | 
| 37 |  | /* Define vectors of zeros and ones for use with various nc_get_varX functions */ | 
| 38 |  | /* Note, this form of initialization fails under Cygwin */ | 
| 39 |  | size_t NC_coord_zero[NC_MAX_VAR_DIMS] = {0}; | 
| 40 |  | size_t NC_coord_one[NC_MAX_VAR_DIMS] = {1}; | 
| 41 |  | ptrdiff_t NC_stride_one[NC_MAX_VAR_DIMS] = {1}; | 
| 42 |  |  | 
| 43 |  | /* | 
| 44 |  | static nc_type longtype = (sizeof(long) == sizeof(int)?NC_INT:NC_INT64); | 
| 45 |  | static nc_type ulongtype = (sizeof(unsigned long) == sizeof(unsigned int)?NC_UINT:NC_UINT64); | 
| 46 |  | */ | 
| 47 |  |  | 
| 48 |  | /* Allow dispatch to do general initialization and finalization */ | 
| 49 |  | int | 
| 50 |  | NCDISPATCH_initialize(void) | 
| 51 | 1 | { | 
| 52 | 1 |     int status = NC_NOERR; | 
| 53 | 1 |     int i; | 
| 54 | 1 |     NCglobalstate* globalstate = NULL; | 
| 55 |  |  | 
| 56 | 1.02k |     for(i=0;i<NC_MAX_VAR_DIMS;i++) { | 
| 57 | 1.02k |         NC_coord_zero[i] = 0; | 
| 58 | 1.02k |         NC_coord_one[i]  = 1; | 
| 59 | 1.02k |         NC_stride_one[i] = 1; | 
| 60 | 1.02k |     } | 
| 61 |  |  | 
| 62 | 1 |     globalstate = NC_getglobalstate(); /* will allocate and clear */ | 
| 63 |  |  | 
| 64 |  |     /* Capture temp dir*/ | 
| 65 | 1 |     { | 
| 66 | 1 |   char* tempdir = NULL; | 
| 67 |  | #if defined _WIN32 || defined __MSYS__ || defined __CYGWIN__ | 
| 68 |  |         tempdir = getenv("TEMP"); | 
| 69 |  | #else | 
| 70 | 1 |   tempdir = "/tmp"; | 
| 71 | 1 | #endif | 
| 72 | 1 |         if(tempdir == NULL) { | 
| 73 | 0 |       fprintf(stderr,"Cannot find a temp dir; using ./\n"); | 
| 74 | 0 |       tempdir = "."; | 
| 75 | 0 |   } | 
| 76 | 1 |   globalstate->tempdir= strdup(tempdir); | 
| 77 | 1 |     } | 
| 78 |  |  | 
| 79 |  |     /* Capture $HOME */ | 
| 80 | 1 |     { | 
| 81 |  | #if defined(_WIN32) && !defined(__MINGW32__) | 
| 82 |  |         char* home = getenv("USERPROFILE"); | 
| 83 |  | #else | 
| 84 | 1 |         char* home = getenv("HOME"); | 
| 85 | 1 | #endif | 
| 86 | 1 |         if(home == NULL) { | 
| 87 |  |       /* use cwd */ | 
| 88 | 0 |       home = malloc(MAXPATH+1); | 
| 89 | 0 |       NCgetcwd(home,MAXPATH); | 
| 90 | 0 |         } else | 
| 91 | 1 |       home = strdup(home); /* make it always free'able */ | 
| 92 | 1 |   assert(home != NULL); | 
| 93 | 1 |         NCpathcanonical(home,&globalstate->home); | 
| 94 | 1 |   nullfree(home); | 
| 95 | 1 |     } | 
| 96 |  |   | 
| 97 |  |     /* Capture $CWD */ | 
| 98 | 1 |     { | 
| 99 | 1 |         char cwdbuf[4096]; | 
| 100 |  |  | 
| 101 | 1 |         cwdbuf[0] = '\0'; | 
| 102 | 1 |   (void)NCgetcwd(cwdbuf,sizeof(cwdbuf)); | 
| 103 |  |  | 
| 104 | 1 |         if(strlen(cwdbuf) == 0) { | 
| 105 |  |       /* use tempdir */ | 
| 106 | 0 |       strcpy(cwdbuf, globalstate->tempdir); | 
| 107 | 0 |   } | 
| 108 | 1 |         globalstate->cwd = strdup(cwdbuf); | 
| 109 | 1 |     } | 
| 110 |  |  | 
| 111 | 1 |     ncloginit(); | 
| 112 |  |  | 
| 113 |  |     /* Now load RC Files */ | 
| 114 | 1 |     ncrc_initialize(); | 
| 115 |  |  | 
| 116 |  |     /* Compute type alignments */ | 
| 117 | 1 |     NC_compute_alignments(); | 
| 118 |  |  | 
| 119 |  | #if defined(NETCDF_ENABLE_BYTERANGE) || defined(NETCDF_ENABLE_DAP) || defined(NETCDF_ENABLE_DAP4) | 
| 120 |  |     /* Initialize curl if it is being used */ | 
| 121 |  |     { | 
| 122 |  |         CURLcode cstat = curl_global_init(CURL_GLOBAL_ALL); | 
| 123 |  |   if(cstat != CURLE_OK) | 
| 124 |  |       status = NC_ECURL; | 
| 125 |  |     } | 
| 126 |  | #endif | 
| 127 |  |  | 
| 128 | 1 |     return status; | 
| 129 | 1 | } | 
| 130 |  |  | 
| 131 |  | int | 
| 132 |  | NCDISPATCH_finalize(void) | 
| 133 | 1 | { | 
| 134 | 1 |     int status = NC_NOERR; | 
| 135 |  | #if defined(NETCDF_ENABLE_BYTERANGE) || defined(NETCDF_ENABLE_DAP) || defined(NETCDF_ENABLE_DAP4) | 
| 136 |  |     curl_global_cleanup(); | 
| 137 |  | #endif | 
| 138 |  | #if defined(NETCDF_ENABLE_DAP4) | 
| 139 |  |    ncxml_finalize(); | 
| 140 |  | #endif | 
| 141 | 1 |     NC_freeglobalstate(); /* should be one of the last things done */ | 
| 142 | 1 |     return status; | 
| 143 | 1 | } | 
| 144 |  |  | 
| 145 |  | /**************************************************/ | 
| 146 |  | /* Global State constants and state */ | 
| 147 |  |  | 
| 148 |  | /* The singleton global state object */ | 
| 149 |  | static NCglobalstate* nc_globalstate = NULL; | 
| 150 |  |  | 
| 151 |  | /* Forward */ | 
| 152 |  | static int NC_createglobalstate(void); | 
| 153 |  |  | 
| 154 |  | /** \defgroup global_state Global state functions. */ | 
| 155 |  | /** \{ | 
| 156 |  |  | 
| 157 |  | \ingroup global_state | 
| 158 |  | */ | 
| 159 |  |  | 
| 160 |  | /* NCglobal state management */ | 
| 161 |  |  | 
| 162 |  | static int | 
| 163 |  | NC_createglobalstate(void) | 
| 164 | 1 | { | 
| 165 | 1 |     int stat = NC_NOERR; | 
| 166 | 1 |     const char* tmp = NULL; | 
| 167 |  |      | 
| 168 | 1 |     if(nc_globalstate == NULL) { | 
| 169 | 1 |         nc_globalstate = calloc(1,sizeof(NCglobalstate)); | 
| 170 | 1 |     } | 
| 171 |  |     /* Initialize struct pointers */ | 
| 172 | 1 |     if((nc_globalstate->rcinfo = calloc(1,sizeof(struct NCRCinfo)))==NULL) | 
| 173 | 0 |             {stat = NC_ENOMEM; goto done;} | 
| 174 | 1 |     if((nc_globalstate->rcinfo->entries = nclistnew())==NULL) | 
| 175 | 0 |             {stat = NC_ENOMEM; goto done;} | 
| 176 | 1 |     if((nc_globalstate->rcinfo->s3profiles = nclistnew())==NULL) | 
| 177 | 0 |             {stat = NC_ENOMEM; goto done;} | 
| 178 |  |  | 
| 179 |  |     /* Get environment variables */ | 
| 180 | 1 |     if(getenv(NCRCENVIGNORE) != NULL) | 
| 181 | 0 |         nc_globalstate->rcinfo->ignore = 1; | 
| 182 | 1 |     tmp = getenv(NCRCENVRC); | 
| 183 | 1 |     if(tmp != NULL && strlen(tmp) > 0) | 
| 184 | 0 |         nc_globalstate->rcinfo->rcfile = strdup(tmp); | 
| 185 |  |     /* Initialize chunk cache defaults */ | 
| 186 | 1 |     nc_globalstate->chunkcache.size = DEFAULT_CHUNK_CACHE_SIZE;       /**< Default chunk cache size. */ | 
| 187 | 1 |     nc_globalstate->chunkcache.nelems = DEFAULT_CHUNKS_IN_CACHE;     /**< Default chunk cache number of elements. */ | 
| 188 | 1 |     nc_globalstate->chunkcache.preemption = DEFAULT_CHUNK_CACHE_PREEMPTION; /**< Default chunk cache preemption. */ | 
| 189 |  |      | 
| 190 | 1 | done: | 
| 191 | 1 |     return stat; | 
| 192 | 1 | } | 
| 193 |  |  | 
| 194 |  | /* Get global state */ | 
| 195 |  | NCglobalstate* | 
| 196 |  | NC_getglobalstate(void) | 
| 197 | 11 | { | 
| 198 | 11 |     if(nc_globalstate == NULL) | 
| 199 | 1 |         NC_createglobalstate(); | 
| 200 | 11 |     return nc_globalstate; | 
| 201 | 11 | } | 
| 202 |  |  | 
| 203 |  | void | 
| 204 |  | NC_freeglobalstate(void) | 
| 205 | 1 | { | 
| 206 | 1 |     if(nc_globalstate != NULL) { | 
| 207 | 1 |         nullfree(nc_globalstate->tempdir); | 
| 208 | 1 |         nullfree(nc_globalstate->home); | 
| 209 | 1 |         nullfree(nc_globalstate->cwd); | 
| 210 | 1 |   nullfree(nc_globalstate->aws.default_region); | 
| 211 | 1 |   nullfree(nc_globalstate->aws.config_file); | 
| 212 | 1 |   nullfree(nc_globalstate->aws.profile); | 
| 213 | 1 |   nullfree(nc_globalstate->aws.access_key_id); | 
| 214 | 1 |   nullfree(nc_globalstate->aws.secret_access_key); | 
| 215 | 1 |         if(nc_globalstate->rcinfo) { | 
| 216 | 1 |       NC_rcclear(nc_globalstate->rcinfo); | 
| 217 | 1 |       free(nc_globalstate->rcinfo); | 
| 218 | 1 |   } | 
| 219 | 1 |   nclistfree(nc_globalstate->pluginpaths); | 
| 220 | 1 |   free(nc_globalstate); | 
| 221 | 1 |   nc_globalstate = NULL; | 
| 222 | 1 |     } | 
| 223 | 1 | } | 
| 224 |  |  | 
| 225 |  | /** \} */ | 
| 226 |  |  | 
| 227 |  | /**************************************************/ | 
| 228 |  | /** \defgroup atomic_types Atomic Type functions */ | 
| 229 |  | /** \{ | 
| 230 |  |  | 
| 231 |  | \ingroup atomic_types | 
| 232 |  | */ | 
| 233 |  |  | 
| 234 |  | /* The sizes of types may vary from platform to platform, but within | 
| 235 |  |  * netCDF files, type sizes are fixed. */ | 
| 236 |  | #define NC_CHAR_LEN sizeof(char)      /**< @internal Size of char. */ | 
| 237 |  | #define NC_STRING_LEN sizeof(char *)  /**< @internal Size of char *. */ | 
| 238 |  | #define NC_BYTE_LEN 1     /**< @internal Size of byte. */ | 
| 239 |  | #define NC_SHORT_LEN 2    /**< @internal Size of short. */ | 
| 240 |  | #define NC_INT_LEN 4      /**< @internal Size of int. */ | 
| 241 |  | #define NC_FLOAT_LEN 4    /**< @internal Size of float. */ | 
| 242 |  | #define NC_DOUBLE_LEN 8   /**< @internal Size of double. */ | 
| 243 |  | #define NC_INT64_LEN 8    /**< @internal Size of int64. */ | 
| 244 |  |  | 
| 245 |  | /** @internal Names of atomic types. */ | 
| 246 |  | const char* nc4_atomic_name[NUM_ATOMIC_TYPES] = {"none", "byte", "char", | 
| 247 |  |                                            "short", "int", "float", | 
| 248 |  |                                            "double", "ubyte", | 
| 249 |  |                                            "ushort", "uint", | 
| 250 |  |                                            "int64", "uint64", "string"}; | 
| 251 |  | static const size_t nc4_atomic_size[NUM_ATOMIC_TYPES] = {0, NC_BYTE_LEN, NC_CHAR_LEN, NC_SHORT_LEN, | 
| 252 |  |                                                       NC_INT_LEN, NC_FLOAT_LEN, NC_DOUBLE_LEN, | 
| 253 |  |                                                       NC_BYTE_LEN, NC_SHORT_LEN, NC_INT_LEN, NC_INT64_LEN, | 
| 254 |  |                                                       NC_INT64_LEN, NC_STRING_LEN}; | 
| 255 |  |  | 
| 256 |  | /** | 
| 257 |  |  * @internal Get the name and size of an atomic type. For strings, 1 is | 
| 258 |  |  * returned. | 
| 259 |  |  * | 
| 260 |  |  * @param typeid1 Type ID. | 
| 261 |  |  * @param name Gets the name of the type. | 
| 262 |  |  * @param size Gets the size of one element of the type in bytes. | 
| 263 |  |  * | 
| 264 |  |  * @return ::NC_NOERR No error. | 
| 265 |  |  * @return ::NC_EBADID Bad ncid. | 
| 266 |  |  * @return ::NC_EBADTYPE Type not found. | 
| 267 |  |  * @author Dennis Heimbigner | 
| 268 |  |  */ | 
| 269 |  | int | 
| 270 |  | NC4_inq_atomic_type(nc_type typeid1, char *name, size_t *size) | 
| 271 | 0 | { | 
| 272 | 0 |     if (typeid1 >= NUM_ATOMIC_TYPES) | 
| 273 | 0 |   return NC_EBADTYPE; | 
| 274 | 0 |     if (name) | 
| 275 | 0 |             strcpy(name, nc4_atomic_name[typeid1]); | 
| 276 | 0 |     if (size) | 
| 277 | 0 |             *size = nc4_atomic_size[typeid1]; | 
| 278 | 0 |     return NC_NOERR; | 
| 279 | 0 | } | 
| 280 |  |  | 
| 281 |  | /** | 
| 282 |  |  * @internal Get the id and size of an atomic type by name. | 
| 283 |  |  * | 
| 284 |  |  * @param name [in] the name of the type. | 
| 285 |  |  * @param idp [out] the type index of the type. | 
| 286 |  |  * @param sizep [out] the size of one element of the type in bytes. | 
| 287 |  |  * | 
| 288 |  |  * @return ::NC_NOERR No error. | 
| 289 |  |  * @return ::NC_EBADID Bad ncid. | 
| 290 |  |  * @return ::NC_EBADTYPE Type not found. | 
| 291 |  |  * @author Dennis Heimbigner | 
| 292 |  |  */ | 
| 293 |  | int | 
| 294 |  | NC4_lookup_atomic_type(const char *name, nc_type* idp, size_t *sizep) | 
| 295 | 0 | { | 
| 296 | 0 |     int i; | 
| 297 |  | 
 | 
| 298 | 0 |     if (name == NULL || strlen(name) == 0) | 
| 299 | 0 |   return NC_EBADTYPE; | 
| 300 | 0 |     for(i=0;i<NUM_ATOMIC_TYPES;i++) { | 
| 301 | 0 |   if(strcasecmp(name,nc4_atomic_name[i])==0) {  | 
| 302 | 0 |       if(idp) *idp = i; | 
| 303 | 0 |             if(sizep) *sizep = nc4_atomic_size[i]; | 
| 304 | 0 |       return NC_NOERR; | 
| 305 | 0 |         } | 
| 306 | 0 |     } | 
| 307 | 0 |     return NC_EBADTYPE; | 
| 308 | 0 | } | 
| 309 |  |  | 
| 310 |  | /** | 
| 311 |  |  * @internal Get the id of an atomic type from the name. | 
| 312 |  |  * | 
| 313 |  |  * @param ncid File and group ID. | 
| 314 |  |  * @param name Name of type | 
| 315 |  |  * @param typeidp Pointer that will get the type ID. | 
| 316 |  |  * | 
| 317 |  |  * @return ::NC_NOERR No error. | 
| 318 |  |  * @return ::NC_EBADTYPE Type not found. | 
| 319 |  |  * @author Ed Hartnett | 
| 320 |  |  */ | 
| 321 |  | int | 
| 322 |  | NC4_inq_atomic_typeid(int ncid, const char *name, nc_type *typeidp) | 
| 323 | 0 | { | 
| 324 | 0 |     int i; | 
| 325 |  | 
 | 
| 326 | 0 |     NC_UNUSED(ncid); | 
| 327 |  |  | 
| 328 |  |     /* Handle atomic types. */ | 
| 329 | 0 |     for (i = 0; i < NUM_ATOMIC_TYPES; i++) { | 
| 330 | 0 |         if (!strcmp(name, nc4_atomic_name[i])) | 
| 331 | 0 |         { | 
| 332 | 0 |             if (typeidp) | 
| 333 | 0 |                 *typeidp = i; | 
| 334 | 0 |       return NC_NOERR; | 
| 335 | 0 |         } | 
| 336 | 0 |     } | 
| 337 | 0 |     return NC_EBADTYPE; | 
| 338 | 0 | } | 
| 339 |  |  | 
| 340 |  | /** | 
| 341 |  |  * @internal Get the class of a type | 
| 342 |  |  * | 
| 343 |  |  * @param xtype NetCDF type ID. | 
| 344 |  |  * @param type_class Pointer that gets class of type, NC_INT, | 
| 345 |  |  * NC_FLOAT, NC_CHAR, or NC_STRING, NC_ENUM, NC_VLEN, NC_COMPOUND, or | 
| 346 |  |  * NC_OPAQUE. | 
| 347 |  |  * | 
| 348 |  |  * @return ::NC_NOERR No error. | 
| 349 |  |  * @author Ed Hartnett, Dennis Heimbigner | 
| 350 |  |  */ | 
| 351 |  | int | 
| 352 |  | NC4_get_atomic_typeclass(nc_type xtype, int *type_class) | 
| 353 | 0 | { | 
| 354 | 0 |     assert(type_class); | 
| 355 | 0 |     switch (xtype) { | 
| 356 | 0 |         case NC_BYTE: | 
| 357 | 0 |         case NC_UBYTE: | 
| 358 | 0 |         case NC_SHORT: | 
| 359 | 0 |         case NC_USHORT: | 
| 360 | 0 |         case NC_INT: | 
| 361 | 0 |         case NC_UINT: | 
| 362 | 0 |         case NC_INT64: | 
| 363 | 0 |         case NC_UINT64: | 
| 364 |  |             /* NC_INT is class used for all integral types */ | 
| 365 | 0 |             *type_class = NC_INT; | 
| 366 | 0 |             break; | 
| 367 | 0 |         case NC_FLOAT: | 
| 368 | 0 |         case NC_DOUBLE: | 
| 369 |  |             /* NC_FLOAT is class used for all floating-point types */ | 
| 370 | 0 |             *type_class = NC_FLOAT; | 
| 371 | 0 |             break; | 
| 372 | 0 |         case NC_CHAR: | 
| 373 | 0 |             *type_class = NC_CHAR; | 
| 374 | 0 |             break; | 
| 375 | 0 |         case NC_STRING: | 
| 376 | 0 |             *type_class = NC_STRING; | 
| 377 | 0 |             break; | 
| 378 | 0 |         default: | 
| 379 | 0 |      return NC_EBADTYPE; | 
| 380 | 0 |         } | 
| 381 | 0 |     return NC_NOERR; | 
| 382 | 0 | } | 
| 383 |  |  | 
| 384 |  | /** \} */ | 
| 385 |  |  | 
| 386 |  | /**************************************************/ | 
| 387 |  | /** \defgroup alignment Alignment functions. */ | 
| 388 |  |  | 
| 389 |  | /** \{ | 
| 390 |  |  | 
| 391 |  | \ingroup alignment | 
| 392 |  | */ | 
| 393 |  |  | 
| 394 |  | /** | 
| 395 |  | Provide a function to store global data alignment | 
| 396 |  | information. | 
| 397 |  | Repeated calls to nc_set_alignment will overwrite any existing values. | 
| 398 |  |  | 
| 399 |  | If defined, then for every file created or opened after the call to | 
| 400 |  | nc_set_alignment, and for every new variable added to the file, the | 
| 401 |  | most recently set threshold and alignment values will be applied | 
| 402 |  | to that variable. | 
| 403 |  |  | 
| 404 |  | The nc_set_alignment function causes new data written to a | 
| 405 |  | netCDF-4 file to be aligned on disk to a specified block | 
| 406 |  | size. To be effective, alignment should be the system disk block | 
| 407 |  | size, or a multiple of it. This setting is effective with MPI | 
| 408 |  | I/O and other parallel systems. | 
| 409 |  |  | 
| 410 |  | This is a trade-off of write speed versus file size. Alignment | 
| 411 |  | leaves holes between file objects. The default of no alignment | 
| 412 |  | writes file objects contiguously, without holes. Alignment has | 
| 413 |  | no impact on file readability. | 
| 414 |  |  | 
| 415 |  | Alignment settings apply only indirectly, through the file open | 
| 416 |  | functions. Call nc_set_alignment first, then nc_create or | 
| 417 |  | nc_open for one or more files. Current alignment settings are | 
| 418 |  | locked in when each file is opened, then forgotten when the same | 
| 419 |  | file is closed. For illustration, it is possible to write | 
| 420 |  | different files at the same time with different alignments, by | 
| 421 |  | interleaving nc_set_alignment and nc_open calls. | 
| 422 |  |  | 
| 423 |  | Alignment applies to all newly written low-level file objects at | 
| 424 |  | or above the threshold size, including chunks of variables, | 
| 425 |  | attributes, and internal infrastructure. Alignment is not locked | 
| 426 |  | in to a data variable. It can change between data chunks of the | 
| 427 |  | same variable, based on a file's history. | 
| 428 |  |  | 
| 429 |  | Refer to H5Pset_alignment in HDF5 documentation for more | 
| 430 |  | specific details, interactions, and additional rules. | 
| 431 |  |  | 
| 432 |  | @param threshold The minimum size to which alignment is applied. | 
| 433 |  | @param alignment The alignment value. | 
| 434 |  |  | 
| 435 |  | @return ::NC_NOERR No error. | 
| 436 |  | @return ::NC_EINVAL Invalid input. | 
| 437 |  | @author Dennis Heimbigner | 
| 438 |  | @ingroup datasets | 
| 439 |  | */ | 
| 440 |  | int | 
| 441 |  | nc_set_alignment(int threshold, int alignment) | 
| 442 | 0 | { | 
| 443 | 0 |     NCglobalstate* gs = NC_getglobalstate(); | 
| 444 | 0 |     gs->alignment.threshold = threshold; | 
| 445 | 0 |     gs->alignment.alignment = alignment; | 
| 446 | 0 |     gs->alignment.defined = 1; | 
| 447 | 0 |     return NC_NOERR; | 
| 448 | 0 | } | 
| 449 |  |  | 
| 450 |  | /** | 
| 451 |  | Provide get function to retrieve global data alignment | 
| 452 |  | information. | 
| 453 |  |  | 
| 454 |  | The nc_get_alignment function return the last values set by | 
| 455 |  | nc_set_alignment.  If nc_set_alignment has not been called, then | 
| 456 |  | it returns the value 0 for both threshold and alignment. | 
| 457 |  |  | 
| 458 |  | @param thresholdp Return the current minimum size to which alignment is applied or zero. | 
| 459 |  | @param alignmentp Return the current alignment value or zero. | 
| 460 |  |  | 
| 461 |  | @return ::NC_NOERR No error. | 
| 462 |  | @return ::NC_EINVAL Invalid input. | 
| 463 |  | @author Dennis Heimbigner | 
| 464 |  | @ingroup datasets | 
| 465 |  | */ | 
| 466 |  |  | 
| 467 |  | int | 
| 468 |  | nc_get_alignment(int* thresholdp, int* alignmentp) | 
| 469 | 0 | { | 
| 470 | 0 |     NCglobalstate* gs = NC_getglobalstate(); | 
| 471 | 0 |     if(thresholdp) *thresholdp = gs->alignment.threshold; | 
| 472 | 0 |     if(alignmentp) *alignmentp = gs->alignment.alignment; | 
| 473 | 0 |     return NC_NOERR; | 
| 474 | 0 | } | 
| 475 |  |  | 
| 476 |  | /** \} */ |