1 /******************************************************************************
2 *
3 * NSSDC/CDF CDF `create' operations.
4 *
5 * Version 1.5b, 20-Oct-97, Hughes STX.
6 *
7 * Modification history:
8 *
9 * V1.0 20-May-92, J Love Original version (was part of `cdflib.c').
10 * V1.1 29-Sep-92, J Love CDF V2.3 (shareable/NeXT/zVar).
11 * V1.2 24-Jan-94, J Love CDF V2.4. Added readonly mode.
12 * V1.3 15-Dec-94, J Love CDF V2.5.
13 * V1.3a 9-Jan-95, J Love Encode/decode changes. More cache-residency.
14 * V1.3b 24-Feb-95, J Love Solaris 2.3 IDL i/f.
15 * V1.4 21-Mar-95, J Love POSIX.
16 * V1.4a 7-Sep-95, J Love CDFexport-related changes. Fixed cleanup when
17 * a CDF is aborted.
18 * V1.5 15-Aug-96, J Love CDF V2.6.
19 * V1.5a 21-Feb-97, J Love Removed RICE.
20 * V1.5b 11-Sep-97, J Love Magic numbers are now uInt32.
21 * V1.5c 20-Oct-97, J Love Properly cast the uInt32 magic numbers.
22 * V1.6 8-Apr-04, M Liu Save the currently created variable's offset.
23 * V1.7 13-Oct-06, M Liu Changed to allow upper and lower case CDF
24 * name to be used on win32.
25 *
26 ******************************************************************************/
27
28 #include "cdflib.h"
29 #include "cdflib64.h"
30 #include "cdfrev.h"
31
32 /******************************************************************************
33 * CDFcre.
34 ******************************************************************************/
35
CDFcre(Va,Cur)36 STATICforIDL CDFstatus CDFcre (Va, Cur)
37 struct VAstruct *Va;
38 struct CurStruct *Cur;
39 {
40 CDFstatus tStatus, pStatus = CDF_OK;
41
42 switch (Va->item) {
43 /****************************************************************************
44 * CDF_, create a new CDF.
45 ****************************************************************************/
46 case CDF_: {
47 long numDims, *dimSizes;
48 char CDFnameT[CDF_PATHNAME_LEN+1], CDFnameX[DU_MAX_PATH_LEN+1], *CDFnameP;
49 char CDFnameTx[CDF_PATHNAME_LEN+1];
50 char copyRight[CDF_COPYRIGHT_LEN+1];
51 CDFid *id;
52 struct CDFstruct *CDF;
53 struct CDRstruct CDR;
54 struct GDRstruct GDR;
55 vFILE *dotFp;
56 int dimN;
57 #if defined(vms) || defined(dos)
58 Logical upper_case_ext = TRUE;
59 #else /* Unix, POSIX, & Macintosh */
60 Logical upper_case_ext = FALSE;
61 #endif
62 Logical version_numbers = FALSE;
63 Logical no_append = FALSE;
64 uInt32 magicNumber1 = V2magicNUMBER_1;
65 uInt32 magicNumber2u = V2magicNUMBER_2u;
66 /**************************************************************************
67 * Get arguments for this operation/item.
68 **************************************************************************/
69 CDFnameP = va_arg (Va->ap, char *);
70 numDims = va_arg (Va->ap, long);
71 dimSizes = va_arg (Va->ap, long *);
72 id = va_arg (Va->ap, CDFid *);
73 *id = (CDFid) NULL;
74 /**************************************************************************
75 * Validate arguments.
76 **************************************************************************/
77 #if BUILD_READ_ONLY_DISTRIBUTION
78 if (!sX(READ_ONLY_DISTRIBUTION,&pStatus)) return pStatus;
79 #endif
80 if (numDims < 0 || numDims > CDF_MAX_DIMS) return BAD_NUM_DIMS;
81 for (dimN = 0; dimN < numDims; dimN++) {
82 if (dimSizes[dimN] < 1) return BAD_DIM_SIZE;
83 }
84 if (strlen(CDFnameP) > (size_t) CDF_PATHNAME_LEN) {
85 if (!sX(CDF_NAME_TRUNC,&pStatus)) return pStatus;
86 }
87 strcpyX (CDFnameT, CDFnameP, CDF_PATHNAME_LEN);
88 #if STRIP_TRAILING_BLANKS_FROM_CDFPATH
89 StripTrailingBlanks (CDFnameT);
90 #endif
91 #if defined(vms) || defined(dos)
92 MakeUpperString (CDFnameT);
93 #endif
94 RemoveCDFFileExtension(CDFnameT, CDFnameTx);
95 if (!ValidCDFname(CDFnameTx)) return BAD_CDF_NAME;
96 BuildFilePath (CDFt, CDFnameTx, no_append, upper_case_ext, version_numbers,
97 INT32_ZERO, CDFnameX);
98 if (IsReg(CDFnameX)) return CDF_EXISTS;
99 /**************************************************************************
100 * Create CDF file.
101 **************************************************************************/
102 dotFp = V_open (CDFnameX, WRITE_PLUS_a_mode);
103 if (dotFp == NULL) return CDF_CREATE_ERROR;
104 /**************************************************************************
105 * Allocate/initialize CDF structure.
106 **************************************************************************/
107 CDF = (struct CDFstruct *) cdf_AllocateMemory (sizeof(struct CDFstruct), NULL);
108 if (CDF == NULL) {
109 V_close (dotFp, NULL, NULL);
110 DeleteFile (CDFnameX);
111 return BAD_MALLOC;
112 }
113 CDF->CDFname = (char *) cdf_AllocateMemory (strlen(CDFnameTx) + 1, NULL);
114 if (CDF->CDFname == NULL) {
115 V_close (dotFp, NULL, NULL);
116 DeleteFile (CDFnameX);
117 cdf_FreeMemory (CDF, NULL);
118 return BAD_MALLOC;
119 }
120 else
121 strcpyX (CDF->CDFname, CDFnameTx, 0);
122 CDF->magic = VALIDid_MAGIC_NUMBER;
123 CDF->largeFile = FALSE;
124 CDF->CDRoffset = V2_CDR_OFFSET;
125 CDF->GDRoffset = NO_OFFSET; /* Reset below when GDR is written. */
126 CDF->readOnly = FALSE;
127 CDF->zMode = zMODEoff;
128 CDF->decoding = HOST_DECODING;
129 CDF->negToPosFp0 = FALSE;
130 CDF->status = READ_WRITE;
131 CDF->dotFp = dotFp;
132 CDF->uDotFp = NULL;
133 CDF->fp = dotFp;
134 CDF->pseudo_clock = 0;
135 CDF->upper_case_ext = upper_case_ext;
136 CDF->version_numbers = version_numbers;
137 CDF->no_append = no_append;
138 CDF->fakeEPOCH = FALSE;
139 CDF->wastedSpace = FALSE;
140 CDF->badEOF = FALSE;
141 CDF->badTerminatingOffsets = FALSE;
142 CDF->assumedScopes = FALSE;
143 CDF->NrVars = 0;
144 CDF->NzVars = 0;
145 CDF->MAXrVars = 0;
146 CDF->MAXzVars = 0;
147 CDF->rVars = NULL;
148 CDF->zVars = NULL;
149 CDF->encoding = BOO(DEFAULT_TO_HOST_ENCODING,
150 HostEncoding(),NETWORK_ENCODING);
151 CDF->rowMajor = DEFAULT_TO_ROW_MAJOR;
152 CDF->singleFile = DEFAULT_TO_SINGLE_FILE;
153 CDF->rMaxRec = NO_RECORD;
154 CDF->rNumDims = numDims;
155 for (dimN = 0; dimN < numDims; dimN++) {
156 CDF->rDimSizes[dimN] = dimSizes[dimN];
157 }
158 CDF->stage.fp = NULL;
159 CDF->stage.mark = ZERO_OFFSET;
160 CDF->stage.cacheSize = NUMcacheSTAGE;
161 CDF->compressFp = NULL;
162 CDF->scratchDir = NULL;
163 CDF->workingCacheSize = BOO(CDF->singleFile,NUMcacheSINGLE,NUMcacheMULTI);
164 CDF->compressCacheSize = NUMcacheCOMPRESS;
165 CDF->checksum = BOO(CDFgetChecksumEnvVar()<=0,NONE_CHECKSUM,MD5_CHECKSUM);
166 InitCURobjectsStates (CDF);
167 AddTOvStats (&CDF->dotCDFvStats, NULL);
168 AddTOvStats (&CDF->uDotCDFvStats, NULL);
169 /**************************************************************************
170 * Set number of cache buffers based on the CDF's format.
171 **************************************************************************/
172 if (!CACHEv(CDF->fp,CDF->workingCacheSize)) {
173 AbortAccess (CDF, noUPDATE, DELETE);
174 cdf_FreeMemory (CDF, NULL);
175 return BAD_CACHE_SIZE;
176 }
177 /**************************************************************************
178 * Write magic numbers.
179 **************************************************************************/
180 if (!Write32(CDF->fp,(Int32 *)&magicNumber1)) {
181 AbortAccess (CDF, noUPDATE, DELETE);
182 cdf_FreeMemory (CDF, NULL);
183 return CDF_WRITE_ERROR;
184 }
185 if (!Write32(CDF->fp,(Int32 *)&magicNumber2u)) {
186 AbortAccess (CDF, noUPDATE, DELETE);
187 cdf_FreeMemory (CDF, NULL);
188 return CDF_WRITE_ERROR;
189 }
190 /**************************************************************************
191 * Write CDR.
192 **************************************************************************/
193 CDR.RecordSize = CDR_BASE_SIZE + CDF_COPYRIGHT_LEN;
194 CDR.RecordType = CDR_;
195 CDR.GDRoffset = CDF->CDRoffset + CDR.RecordSize;
196 if (CDFgetFileBackward()) {
197 CDR.Version = 2;
198 CDR.Release = 7;
199 CDR.Increment = 2;
200 } else {
201 CDR.Version = CDF_LIBRARY_VERSION;
202 CDR.Release = CDF_LIBRARY_RELEASE;
203 CDR.Increment = CDF_LIBRARY_INCREMENT;
204 }
205 CDR.Encoding = CDF->encoding;
206 CDR.Flags = 0;
207 if (CDF->rowMajor) SetBit32 (&(CDR.Flags), CDR_MAJORITY_BIT);
208 if (CDF->singleFile) SetBit32 (&(CDR.Flags), CDR_FORMAT_BIT);
209 CDR.rfuA = 0;
210 CDR.rfuB = 0;
211 CDR.rfuD = -1;
212 CDR.rfuE = -1;
213 CDFcopyRight (copyRight);
214 NulPad (copyRight, CDF_COPYRIGHT_LEN);
215 if (!sX(WriteCDR(CDF->fp,V2_CDR_OFFSET,
216 CDR_RECORD,&CDR,copyRight,
217 CDR_NULL),&pStatus)) {
218 AbortAccess (CDF, noUPDATE, DELETE);
219 cdf_FreeMemory (CDF, NULL);
220 return pStatus;
221 }
222 /**************************************************************************
223 * Write GDR.
224 **************************************************************************/
225 CDF->GDRoffset = CDR.GDRoffset;
226 GDR.RecordSize = GDR_BASE_SIZE + (numDims * sizeof(Int32));
227 GDR.RecordType = GDR_;
228 GDR.rVDRhead = 0;
229 GDR.zVDRhead = 0;
230 GDR.ADRhead = 0;
231 GDR.eof = CDR.GDRoffset + GDR.RecordSize;
232 GDR.NrVars = CDF->NrVars;
233 GDR.NumAttr = 0;
234 GDR.rMaxRec = CDF->rMaxRec;
235 GDR.rNumDims = CDF->rNumDims;
236 GDR.NzVars = CDF->NzVars;
237 GDR.UIRhead = 0;
238 GDR.rfuC = 0;
239 GDR.rfuD = -1;
240 GDR.rfuE = -1;
241 for (dimN = 0; dimN < CDF->rNumDims; dimN++) {
242 GDR.rDimSizes[dimN] = CDF->rDimSizes[dimN];
243 }
244 if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset,
245 GDR_RECORD,&GDR,
246 GDR_NULL),&pStatus)) {
247 AbortAccess (CDF, noUPDATE, DELETE);
248 cdf_FreeMemory (CDF, NULL);
249 return pStatus;
250 }
251 /**************************************************************************
252 * Select current CDF and pass back CDFid.
253 **************************************************************************/
254 Cur->cdf = CDF;
255 *id = (CDFid) CDF;
256 if (CDF->checksum > 0) {
257 if (!sX(CDFsetChecksum(*id, CDF->checksum),&pStatus)) return pStatus;
258 }
259 break;
260 }
261
262 /****************************************************************************
263 * rVAR_/zVAR_, create a new variable.
264 ****************************************************************************/
265
266 case rVAR_:
267 case zVAR_: {
268 Logical zOp = (Va->item == zVAR_);
269 long *numOut, zNumDims, *zDimSizes, recVariance,
270 *dimVariances, newVarNum, numDims;
271 char *name, Tname[CDF_VAR_NAME_LEN+1], pathnameX[DU_MAX_PATH_LEN+1];
272 struct CDFstruct *CDF;
273 struct VDRstruct VDR;
274 struct VarStruct ***vars;
275 vFILE *varFp;
276 Int32 offset, ntlOffset, VDRhead, nVars;
277 Int32 dataType, numElements;
278 int dimN, *max;
279 name = va_arg (Va->ap, char *);
280 dataType = (Int32) va_arg (Va->ap, long);
281 numElements = (Int32) va_arg (Va->ap, long);
282 if (zOp) {
283 zNumDims = va_arg (Va->ap, long);
284 zDimSizes = va_arg (Va->ap, long *);
285 }
286 recVariance = va_arg (Va->ap, long);
287 dimVariances = va_arg (Va->ap, long *);
288 numOut = va_arg (Va->ap, long *);
289 /**************************************************************************
290 * Get current CDF.
291 **************************************************************************/
292 SelectCDF (Cur->cdf, CDF)
293 /**************************************************************************
294 * Read GDR fields.
295 **************************************************************************/
296 if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
297 BOO(zOp,GDR_zVDRHEAD,GDR_rVDRHEAD),&VDRhead,
298 BOO(zOp,GDR_NzVARS,GDR_NrVARS),&nVars,
299 GDR_NULL),&pStatus)) {
300 AbortAccess (CDF, UPDATE, noDELETE);
301 return pStatus;
302 }
303 /**************************************************************************
304 * Validate arguments.
305 **************************************************************************/
306 if (BADzOP(CDF,!zOp)) return ILLEGAL_IN_zMODE;
307 if (!ValidDataType(dataType)) return BAD_DATA_TYPE;
308 if (numElements < 1) return BAD_NUM_ELEMS;
309 if (!STRINGdataType(dataType) && numElements != 1) return BAD_NUM_ELEMS;
310 if (zOp) {
311 if (zNumDims < 0 || zNumDims > CDF_MAX_DIMS) return BAD_NUM_DIMS;
312 for (dimN = 0; dimN < zNumDims; dimN++)
313 if (zDimSizes[dimN] < 1) return BAD_DIM_SIZE;
314 }
315 if (strlen(name) > (size_t) CDF_VAR_NAME_LEN) {
316 if (!sX(VAR_NAME_TRUNC,&pStatus)) return pStatus;
317 }
318 strcpyX (Tname, name, CDF_VAR_NAME_LEN);
319 #if LIMITof64K
320 if (TOObigIBMpc(CDFelemSize(dataType)*numElements)) return IBM_PC_OVERFLOW;
321 #endif
322 if (!ValidVarName(Tname)) return BAD_VAR_NAME;
323 tStatus = FindVarByName (CDF, Tname, NULL, NULL, NULL);
324 switch (tStatus) {
325 case NO_SUCH_VAR:
326 break;
327 case CDF_OK:
328 return VAR_EXISTS;
329 default:
330 AbortAccess (CDF, UPDATE, noDELETE);
331 return tStatus;
332 }
333 newVarNum = nVars;
334 nVars++;
335 #if defined(dos)
336 if (!CDF->singleFile && newVarNum > 99) return TOO_MANY_VARS;
337 #endif
338 /**************************************************************************
339 * Switch to read-write access if necessary.
340 **************************************************************************/
341 if (!WriteAccess(CDF,FALSE,&pStatus)) return pStatus;
342 /**************************************************************************
343 * Allocate initial/additional pointers to variable data structures.
344 **************************************************************************/
345 max = BOO(zOp,&(CDF->MAXzVars),&(CDF->MAXrVars));
346 vars = BOO(zOp,&(CDF->zVars),&(CDF->rVars));
347 if (newVarNum >= *max) {
348 int newMaxVars = (int) (VARs_INCREMENT * ((newVarNum/VARs_INCREMENT)+1));
349 int varN;
350 size_t nBytes = newMaxVars * sizeof(struct VarStruct *);
351 void *ptr;
352 if (*max > 0)
353 ptr = (struct VarStruct **) cdf_ReallocateMemory (*vars, nBytes, NULL);
354 else
355 ptr = (struct VarStruct **) cdf_AllocateMemory (nBytes, NULL);
356 if (ptr == NULL) return BAD_MALLOC;
357 *vars = ptr;
358 for (varN = *max; varN < newMaxVars; varN++) (*vars)[varN] = NULL;
359 *max = newMaxVars;
360 }
361 /**************************************************************************
362 * Create variable file (if multi-file CDF).
363 **************************************************************************/
364 if (!CDF->singleFile) {
365 BuildFilePath (BOO(zOp,Zt,Vt), CDF->CDFname, CDF->no_append,
366 CDF->upper_case_ext, CDF->version_numbers,
367 (Int32) newVarNum, pathnameX);
368 varFp = V_open (pathnameX, WRITE_PLUS_a_mode);
369 if (varFp == NULL) {
370 if (!sX(CloseLRUvar(CDF),&pStatus)) return pStatus;
371 varFp = V_open (pathnameX, WRITE_PLUS_a_mode);
372 if (varFp == NULL) return VAR_CREATE_ERROR;
373 }
374 if (!CLOSEv(varFp,NULL, NULL)) {
375 DeleteFile (pathnameX);
376 return VAR_CREATE_ERROR;
377 }
378 }
379 /**************************************************************************
380 * Write rVDR/zVDR.
381 **************************************************************************/
382 VDR.RecordSize = BOO(zOp,zVDR_BASE_SIZE,rVDR_BASE_SIZE) +
383 BOO(zOp,zNumDims,0)*sizeof(Int32) + /*DimSizes.*/
384 BOO(zOp,zNumDims,
385 CDF->rNumDims)*sizeof(Int32); /*DimVarys.*/
386 VDR.RecordType = BOO(zOp,zVDR_,rVDR_);
387 VDR.VDRnext = 0;
388 VDR.DataType = dataType;
389 VDR.MaxRec = NO_RECORD;
390 VDR.VXRhead = 0;
391 VDR.VXRtail = 0;
392 VDR.Flags = 0;
393 if (recVariance) SetBit32 (&(VDR.Flags), VDR_RECVARY_BIT);
394 VDR.sRecords = NO_SPARSERECORDS;
395 VDR.rfuB = 0;
396 VDR.rfuC = -1;
397 VDR.rfuF = -1;
398 VDR.NumElems = numElements;
399 VDR.Num = newVarNum;
400 VDR.CPRorSPRoffset = NO_OFFSET;
401 VDR.blockingFactor = 0;
402 strcpyX (VDR.Name, Tname, CDF_VAR_NAME_LEN);
403 NulPad (VDR.Name, CDF_VAR_NAME_LEN);
404 if (zOp) {
405 VDR.zNumDims = zNumDims;
406 for (dimN = 0; dimN < zNumDims; dimN++)
407 VDR.zDimSizes[dimN] = zDimSizes[dimN];
408 }
409 for (dimN = 0, numDims = BOO(zOp,zNumDims,CDF->rNumDims);
410 dimN < numDims; dimN++) {
411 VDR.DimVarys[dimN] = BOO(dimVariances[dimN],VARY,NOVARY);
412 }
413 if (!sX(AllocateIR(CDF,VDR.RecordSize,&offset),&pStatus)) {
414 DeleteFile (pathnameX);
415 AbortAccess (CDF, UPDATE, noDELETE);
416 return pStatus;
417 }
418 if (!sX(WriteVDR(CDF,CDF->fp,offset,zOp,
419 VDR_RECORD,&VDR,NULL,
420 VDR_NULL),&pStatus)) {
421 DeleteFile (pathnameX);
422 AbortAccess (CDF, UPDATE, noDELETE);
423 return pStatus;
424 }
425 /**************************************************************************
426 * Point next-to-last rVDR/zVDR (or GDR) to this rVDR/zVDR.
427 **************************************************************************/
428 if (newVarNum != 0) {
429 if (!sX(FindVarByNumber(CDF,(Int32)(newVarNum-1),
430 zOp,&ntlOffset),&pStatus)) {
431 AbortAccess (CDF, UPDATE, noDELETE);
432 return pStatus;
433 }
434 if (!sX(WriteVDR(CDF,CDF->fp,ntlOffset,zOp,
435 VDR_VDRNEXT,&offset,
436 VDR_NULL),&pStatus)) {
437 AbortAccess (CDF, UPDATE, noDELETE);
438 return pStatus;
439 }
440 }
441 else
442 VDRhead = offset;
443 /**************************************************************************
444 * Update GDR fields that may have been modified.
445 **************************************************************************/
446 if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset,
447 BOO(zOp,GDR_zVDRHEAD,GDR_rVDRHEAD),&VDRhead,
448 BOO(zOp,GDR_NzVARS,GDR_NrVARS),&nVars,
449 GDR_NULL),&pStatus)) {
450 AbortAccess (CDF, UPDATE, noDELETE);
451 return pStatus;
452 }
453 /**************************************************************************
454 * Update the appropriate variable count held in memory for efficiency.
455 **************************************************************************/
456 if (zOp)
457 CDF->NzVars = nVars;
458 else
459 CDF->NrVars = nVars;
460 /**************************************************************************
461 * Select current variable and determine variable number to be passed back
462 * (based on zMode).
463 **************************************************************************/
464 if (zModeON(CDF)) {
465 long varN = CDF->NrVars + newVarNum;
466 CDF->CURzVarNum = varN;
467 CDF->CURzVarOffset = offset;
468 *numOut = varN;
469 }
470 else {
471 if (zOp) {
472 CDF->CURzVarNum = newVarNum;
473 CDF->CURzVarOffset = offset;
474 } else {
475 CDF->CURrVarNum = newVarNum;
476 CDF->CURrVarOffset = offset;
477 }
478 *numOut = newVarNum;
479 }
480 break;
481 }
482 /****************************************************************************
483 * ATTR_,
484 ****************************************************************************/
485 case ATTR_: {
486 long *attrNumOut, scope;
487 char *attrName, truncName[CDF_ATTR_NAME_LEN+1];
488 struct CDFstruct *CDF;
489 struct ADRstruct ADR;
490 Int32 offset, numAttr, ADRhead;
491 /**************************************************************************
492 * Get arguments for this operation/item.
493 **************************************************************************/
494 attrName = va_arg (Va->ap, char *);
495 scope = va_arg (Va->ap, long);
496 attrNumOut = va_arg (Va->ap, long *);
497 /**************************************************************************
498 * Select current CDF.
499 **************************************************************************/
500 SelectCDF (Cur->cdf, CDF)
501 /**************************************************************************
502 * Validate arguments.
503 **************************************************************************/
504 if (!ValidAttrScope((Int32)scope)) return BAD_SCOPE;
505 if (strlen(attrName) > (size_t) CDF_ATTR_NAME_LEN) {
506 if (!sX(ATTR_NAME_TRUNC,&pStatus)) return pStatus;
507 }
508 strcpyX (truncName, attrName, CDF_ATTR_NAME_LEN);
509 if (!ValidAttrName(truncName)) return BAD_ATTR_NAME;
510 tStatus = FindAttrByName (CDF, truncName, NULL);
511 switch (tStatus) {
512 case NO_SUCH_ATTR:
513 break;
514 case CDF_OK:
515 return ATTR_EXISTS;
516 default:
517 AbortAccess (CDF, UPDATE, noDELETE);
518 return tStatus;
519 }
520 /**************************************************************************
521 * Switch to read-write access if necessary.
522 **************************************************************************/
523 if (!WriteAccess(CDF,FALSE,&pStatus)) return pStatus;
524 /**************************************************************************
525 * Read GDR fields.
526 **************************************************************************/
527 if (!sX(ReadGDR(CDF->fp,CDF->GDRoffset,
528 GDR_NUMATTR,&numAttr,
529 GDR_ADRHEAD,&ADRhead,
530 GDR_NULL),&pStatus)) return pStatus;
531 /**************************************************************************
532 * Write ADR.
533 **************************************************************************/
534 ADR.RecordSize = ADR_BASE_SIZE;
535 ADR.RecordType = ADR_;
536 ADR.ADRnext = 0;
537 ADR.AgrEDRhead = 0;
538 ADR.Scope = scope;
539 ADR.Num = numAttr;
540 ADR.NgrEntries = 0;
541 ADR.MAXgrEntry = NO_ENTRY;
542 ADR.rfuA = 0;
543 ADR.AzEDRhead = 0;
544 ADR.NzEntries = 0;
545 ADR.MAXzEntry = NO_ENTRY;
546 ADR.rfuE = -1;
547 strcpyX (ADR.Name, truncName, CDF_ATTR_NAME_LEN);
548 NulPad (ADR.Name, CDF_ATTR_NAME_LEN);
549 if (!sX(AllocateIR(CDF,ADR.RecordSize,&offset),&pStatus)) {
550 AbortAccess (CDF, UPDATE, noDELETE);
551 return pStatus;
552 }
553 if (!sX(WriteADR(CDF->fp,offset,
554 ADR_RECORD,&ADR,
555 ADR_NULL),&pStatus)) {
556 AbortAccess (CDF, UPDATE, noDELETE);
557 return pStatus;
558 }
559 /**************************************************************************
560 * Point last ADR (or GDR) to this ADR.
561 **************************************************************************/
562 if (numAttr == 0)
563 ADRhead = offset;
564 else {
565 Int32 lastOffset;
566 if (!sX(FindLastAttr(CDF,&lastOffset),&pStatus)) {
567 AbortAccess (CDF, UPDATE, noDELETE);
568 return pStatus;
569 }
570 if (!sX(WriteADR(CDF->fp,lastOffset,
571 ADR_ADRNEXT,&offset,
572 ADR_NULL),&pStatus)) {
573 AbortAccess (CDF, UPDATE, noDELETE);
574 return pStatus;
575 }
576 }
577 /**************************************************************************
578 * Update GDR fields.
579 **************************************************************************/
580 numAttr++;
581 if (!sX(WriteGDR(CDF->fp,CDF->GDRoffset,
582 GDR_NUMATTR,&numAttr,
583 GDR_ADRHEAD,&ADRhead,
584 GDR_NULL),&pStatus)) {
585 AbortAccess (CDF, UPDATE, noDELETE);
586 return pStatus;
587 }
588 /**************************************************************************
589 * Select current attribute and entry offsets and pass back attribute
590 * number.
591 **************************************************************************/
592 CDF->CURattrOffset = offset;
593 CDF->CURgrEntryOffset = RESERVED_ENTRYOFFSET;
594 CDF->CURzEntryOffset = RESERVED_ENTRYOFFSET;
595 *attrNumOut = ADR.Num;
596 break;
597 }
598 /****************************************************************************
599 * Unknown item, must be the next function.
600 ****************************************************************************/
601 default: {
602 Va->fnc = Va->item;
603 break;
604 }
605 }
606 return pStatus;
607 }
608