source: XIOS/dev/dev_olga/src/extern/src_netcdf4/ncx.c @ 1022

Last change on this file since 1022 was 1022, checked in by mhnguyen, 7 years ago
File size: 194.1 KB
Line 
1/* Do not edit this file. It is produced from the corresponding .m4 source */
2/*
3 *      Copyright 1996, University Corporation for Atmospheric Research
4 *      See netcdf/COPYRIGHT file for copying and redistribution conditions.
5 *     
6 *      This file contains some routines derived from code
7 *      which is copyrighted by Sun Microsystems, Inc.
8 *      The "#ifdef vax" versions of
9 *               ncx_put_float_float()
10 *               ncx_get_float_float()
11 *               ncx_put_double_double()
12 *               ncx_get_double_double()
13 *               ncx_putn_float_float()
14 *               ncx_getn_float_float()
15 *               ncx_putn_double_double()
16 *               ncx_getn_double_double()
17 *      are derived from xdr_float() and xdr_double() routines
18 *      in the freely available, copyrighted Sun RPCSRC 3.9
19 *      distribution, xdr_float.c.
20 *      Our "value added" is that these are always memory to memory,
21 *      they handle IEEE subnormals properly, and their "n" versions
22 *      operate speedily on arrays.
23 */
24/* $Id: ncx.m4,v 2.58 2010/05/26 18:11:08 dmh Exp $ */
25
26/*
27 * An external data representation interface.
28 */
29
30#include "ncx.h"
31#include "nc3dispatch.h"
32#include <string.h>
33#include <limits.h>
34
35/* alias poorly named limits.h macros */
36#define  SHORT_MAX  SHRT_MAX
37#define  SHORT_MIN  SHRT_MIN
38#define USHORT_MAX USHRT_MAX
39#ifndef LLONG_MAX
40#   define LLONG_MAX    9223372036854775807LL
41#   define LLONG_MIN    (-LLONG_MAX - 1LL)
42#   define ULLONG_MAX   18446744073709551615ULL
43#endif
44#define LONG_LONG_MAX LLONG_MAX
45#define LONG_LONG_MIN LLONG_MIN
46#define ULONG_LONG_MAX ULLONG_MAX
47#include <float.h>
48#ifndef FLT_MAX /* This POSIX macro missing on some systems */
49# ifndef NO_IEEE_FLOAT
50# define FLT_MAX 3.40282347e+38f
51# else
52# error "You will need to define FLT_MAX"
53# endif
54#endif
55/* alias poorly named float.h macros */
56#define FLOAT_MAX FLT_MAX
57#define FLOAT_MIN (-FLT_MAX)
58#define DOUBLE_MAX DBL_MAX
59#define DOUBLE_MIN (-DBL_MAX)
60#define FLOAT_MAX_EXP FLT_MAX_EXP
61#define DOUBLE_MAX_EXP DBL_MAX_EXP
62#include <assert.h>
63#define UCHAR_MIN 0
64#define Min(a,b) ((a) < (b) ? (a) : (b))
65#define Max(a,b) ((a) > (b) ? (a) : (b))
66
67/*
68 * If the machine's float domain is "smaller" than the external one
69 * use the machine domain
70 */
71#if defined(FLT_MAX_EXP) && FLT_MAX_EXP < 128 /* 128 is X_FLT_MAX_EXP */
72#undef X_FLOAT_MAX
73# define X_FLOAT_MAX FLT_MAX
74#undef X_FLOAT_MIN
75# define X_FLOAT_MIN (-X_FLOAT_MAX)
76#endif
77
78#if _SX /* NEC SUPER UX */
79#define LOOPCNT 256    /* must be no longer than hardware vector length */
80#if _INT64
81#undef  INT_MAX /* workaround cpp bug */
82#define INT_MAX  X_INT_MAX
83#undef  INT_MIN /* workaround cpp bug */
84#define INT_MIN  X_INT_MIN
85#undef  LONG_MAX /* workaround cpp bug */
86#define LONG_MAX  X_INT_MAX
87#undef  LONG_MIN /* workaround cpp bug */
88#define LONG_MIN  X_INT_MIN
89#elif _LONG64
90#undef  LONG_MAX /* workaround cpp bug */
91#define LONG_MAX  4294967295L
92#undef  LONG_MIN /* workaround cpp bug */
93#define LONG_MIN -4294967295L
94#endif
95#if !_FLOAT0
96#error "FLOAT1 and FLOAT2 not supported"
97#endif
98#endif /* _SX */
99
100static const char nada[X_ALIGN] = {0, 0, 0, 0};
101
102#ifndef WORDS_BIGENDIAN
103/* LITTLE_ENDIAN: DEC and intel */
104/*
105 * Routines to convert to BIGENDIAN.
106 * Optimize the swapn?b() and swap?b() routines aggressivly.
107 */
108
109#define SWAP2(a) ( (((a) & 0xff) << 8) | \
110                (((a) >> 8) & 0xff) )
111
112#define SWAP4(a) ( ((a) << 24) | \
113                (((a) <<  8) & 0x00ff0000) | \
114                (((a) >>  8) & 0x0000ff00) | \
115                (((a) >> 24) & 0x000000ff) )
116
117
118static void
119swapn2b(void *dst, const void *src, size_t nn)
120{
121        char *op = dst;
122        const char *ip = src;
123
124/* unroll the following to reduce loop overhead
125 *
126 *      while(nn-- != 0)
127 *      {
128 *              *op++ = *(++ip);
129 *              *op++ = *(ip++ -1);
130 *      }                                       
131 */
132        while(nn > 3)
133        {
134                *op++ = *(++ip);
135                *op++ = *(ip++ -1);
136                *op++ = *(++ip);
137                *op++ = *(ip++ -1);
138                *op++ = *(++ip);
139                *op++ = *(ip++ -1);
140                *op++ = *(++ip);
141                *op++ = *(ip++ -1);
142                nn -= 4;
143        }
144        while(nn-- != 0)
145        {
146                *op++ = *(++ip);
147                *op++ = *(ip++ -1);
148        }
149}
150
151# ifndef vax
152static void
153swap4b(void *dst, const void *src)
154{
155        char *op = dst;
156        const char *ip = src;
157        op[0] = ip[3];
158        op[1] = ip[2];
159        op[2] = ip[1];
160        op[3] = ip[0];
161}
162# endif /* !vax */
163
164static void
165swapn4b(void *dst, const void *src, size_t nn)
166{
167        char *op = dst;
168        const char *ip = src;
169
170/* unroll the following to reduce loop overhead
171 *      while(nn-- != 0)
172 *      {
173 *              op[0] = ip[3];
174 *              op[1] = ip[2];
175 *              op[2] = ip[1];
176 *              op[3] = ip[0];
177 *              op += 4;
178 *              ip += 4;
179 *      }
180 */
181        while(nn > 3)
182        {
183                op[0] = ip[3];
184                op[1] = ip[2];
185                op[2] = ip[1];
186                op[3] = ip[0];
187                op[4] = ip[7];
188                op[5] = ip[6];
189                op[6] = ip[5];
190                op[7] = ip[4];
191                op[8] = ip[11];
192                op[9] = ip[10];
193                op[10] = ip[9];
194                op[11] = ip[8];
195                op[12] = ip[15];
196                op[13] = ip[14];
197                op[14] = ip[13];
198                op[15] = ip[12];
199                op += 16;
200                ip += 16;
201                nn -= 4;
202        }
203        while(nn-- != 0)
204        {
205                op[0] = ip[3];
206                op[1] = ip[2];
207                op[2] = ip[1];
208                op[3] = ip[0];
209                op += 4;
210                ip += 4;
211        }
212}
213
214# ifndef vax
215static void
216swap8b(void *dst, const void *src)
217{
218        char *op = dst;
219        const char *ip = src;
220#  ifndef FLOAT_WORDS_BIGENDIAN
221        op[0] = ip[7];
222        op[1] = ip[6];
223        op[2] = ip[5];
224        op[3] = ip[4];
225        op[4] = ip[3];
226        op[5] = ip[2];
227        op[6] = ip[1];
228        op[7] = ip[0];
229#  else
230        op[0] = ip[3];
231        op[1] = ip[2];
232        op[2] = ip[1];
233        op[3] = ip[0];
234        op[4] = ip[7];
235        op[5] = ip[6];
236        op[6] = ip[5];
237        op[7] = ip[4];
238#  endif
239}
240# endif /* !vax */
241
242# ifndef vax
243static void
244swapn8b(void *dst, const void *src, size_t nn)
245{
246        char *op = dst;
247        const char *ip = src;
248
249/* unroll the following to reduce loop overhead
250 *      while(nn-- != 0)
251 *      {
252 *              op[0] = ip[7];
253 *              op[1] = ip[6];
254 *              op[2] = ip[5];
255 *              op[3] = ip[4];
256 *              op[4] = ip[3];
257 *              op[5] = ip[2];
258 *              op[6] = ip[1];
259 *              op[7] = ip[0];
260 *              op += 8;
261 *              ip += 8;
262 *      }
263 */
264#  ifndef FLOAT_WORDS_BIGENDIAN
265        while(nn > 1)
266        {
267                op[0] = ip[7];
268                op[1] = ip[6];
269                op[2] = ip[5];
270                op[3] = ip[4];
271                op[4] = ip[3];
272                op[5] = ip[2];
273                op[6] = ip[1];
274                op[7] = ip[0];
275                op[8] = ip[15];
276                op[9] = ip[14];
277                op[10] = ip[13];
278                op[11] = ip[12];
279                op[12] = ip[11];
280                op[13] = ip[10];
281                op[14] = ip[9];
282                op[15] = ip[8];
283                op += 16;
284                ip += 16;
285                nn -= 2;
286        }
287        while(nn-- != 0)
288        {
289                op[0] = ip[7];
290                op[1] = ip[6];
291                op[2] = ip[5];
292                op[3] = ip[4];
293                op[4] = ip[3];
294                op[5] = ip[2];
295                op[6] = ip[1];
296                op[7] = ip[0];
297                op += 8;
298                ip += 8;
299        }
300#  else
301        while(nn-- != 0)
302        {
303                op[0] = ip[3];
304                op[1] = ip[2];
305                op[2] = ip[1];
306                op[3] = ip[0];
307                op[4] = ip[7];
308                op[5] = ip[6];
309                op[6] = ip[5];
310                op[7] = ip[4];
311                op += 8;
312                ip += 8;
313        }
314#  endif
315}
316# endif /* !vax */
317
318#endif /* LITTLE_ENDIAN */
319
320
321/*
322 * Primitive numeric conversion functions.
323 */
324
325/* x_schar */
326
327/* We don't implement any x_schar primitives. */
328
329
330/* x_short */
331
332#if SHORT_MAX == X_SHORT_MAX
333typedef short ix_short;
334#define SIZEOF_IX_SHORT SIZEOF_SHORT
335#define IX_SHORT_MAX SHORT_MAX
336#elif INT_MAX >= X_SHORT_MAX
337typedef int ix_short;
338#define SIZEOF_IX_SHORT SIZEOF_INT
339#define IX_SHORT_MAX INT_MAX
340#elif LONG_MAX >= X_SHORT_MAX
341typedef long ix_short;
342#define SIZEOF_IX_SHORT SIZEOF_LONG
343#define IX_SHORT_MAX LONG_MAX
344#elif LLONG_MAX >= X_SHORT_MAX
345typedef long long ix_short;
346#define SIZEOF_IX_SHORT SIZEOF_LONG_LONG
347#define IX_SHORT_MAX LLONG_MAX
348#else
349#error "ix_short implementation"
350#endif
351
352static void
353get_ix_short(const void *xp, ix_short *ip)
354{
355        const uchar *cp = (const uchar *) xp;
356        *ip = *cp++ << 8;
357#if SIZEOF_IX_SHORT > X_SIZEOF_SHORT
358        if(*ip & 0x8000)
359        {
360                /* extern is negative */
361                *ip |= (~(0xffff)); /* N.B. Assumes "twos complement" */
362        }
363#endif
364        *ip |= *cp; 
365}
366
367static void
368put_ix_short(void *xp, const ix_short *ip)
369{
370        uchar *cp = (uchar *) xp;
371        *cp++ = (*ip) >> 8;
372        *cp = (*ip) & 0xff;
373}
374
375
376int
377ncx_get_short_schar(const void *xp, schar *ip)
378{
379        ix_short xx;
380        get_ix_short(xp, &xx);
381        *ip = xx;
382        if(xx > SCHAR_MAX || xx < SCHAR_MIN)
383                return NC_ERANGE;
384        return ENOERR;
385}
386
387int
388ncx_get_short_uchar(const void *xp, uchar *ip)
389{
390        ix_short xx;
391        get_ix_short(xp, &xx);
392        *ip = xx;
393        if(xx > UCHAR_MAX || xx < 0)
394                return NC_ERANGE;
395        return ENOERR;
396}
397
398int
399ncx_get_short_short(const void *xp, short *ip)
400{
401#if SIZEOF_IX_SHORT == SIZEOF_SHORT && IX_SHORT_MAX == SHORT_MAX
402        get_ix_short(xp, (ix_short *)ip);
403        return ENOERR;
404#else
405        ix_short xx;
406        get_ix_short(xp, &xx);
407        *ip = xx;
408#   if IX_SHORT_MAX > SHORT_MAX
409        if(xx > SHORT_MAX || xx < SHORT_MIN)
410                return NC_ERANGE;
411#   endif
412        return ENOERR;
413#endif
414}
415
416int
417ncx_get_short_int(const void *xp, int *ip)
418{
419#if SIZEOF_IX_SHORT == SIZEOF_INT && IX_SHORT_MAX == INT_MAX
420        get_ix_short(xp, (ix_short *)ip);
421        return ENOERR;
422#else
423        ix_short xx;
424        get_ix_short(xp, &xx);
425        *ip = xx;
426#   if IX_SHORT_MAX > INT_MAX
427        if(xx > INT_MAX || xx < INT_MIN)
428                return NC_ERANGE;
429#   endif
430        return ENOERR;
431#endif
432}
433
434int
435ncx_get_short_uint(const void *xp, unsigned int *ip)
436{
437#if SIZEOF_IX_SHORT == SIZEOF_INT && IX_SHORT_MAX == INT_MAX
438        get_ix_short(xp, (ix_short *)ip);
439        return ENOERR;
440#else
441        ix_short xx;
442        get_ix_short(xp, &xx);
443        *ip = xx;
444#   if IX_SHORT_MAX > INT_MAX
445        if(xx > UINT_MAX || xx < 0)
446                return NC_ERANGE;
447#   endif
448        return ENOERR;
449#endif
450}
451
452int
453ncx_get_short_longlong(const void *xp, long long *ip)
454{
455#if SIZEOF_IX_SHORT == SIZEOF_LONG_LONG && IX_SHORT_MAX == LONG_LONG_MAX
456        get_ix_short(xp, (ix_short *)ip);
457        return ENOERR;
458#else
459        /* assert(LONG_LONG_MAX >= X_SHORT_MAX); */
460        ix_short xx;
461        get_ix_short(xp, &xx);
462        *ip = xx;
463        return ENOERR;
464#endif
465}
466
467int
468ncx_get_short_ulonglong(const void *xp, unsigned long long *ip)
469{
470#if SIZEOF_IX_SHORT == SIZEOF_LONG && IX_SHORT_MAX == LONG_MAX
471        get_ix_short(xp, (ix_short *)ip);
472        return ENOERR;
473#else
474        /* assert(LONG_LONG_MAX >= X_SHORT_MAX); */
475        ix_short xx;
476        get_ix_short(xp, &xx);
477        *ip = xx;
478        if(xx < 0)
479                return NC_ERANGE;
480        return ENOERR;
481#endif
482}
483
484int
485ncx_get_short_float(const void *xp, float *ip)
486{
487        ix_short xx;
488        get_ix_short(xp, &xx);
489        *ip = xx;
490#if 0   /* TODO: determine when necessary */
491        if(xx > FLT_MAX || xx < (-FLT_MAX))
492                return NC_ERANGE;
493#endif
494        return ENOERR;
495}
496
497int
498ncx_get_short_double(const void *xp, double *ip)
499{
500        /* assert(DBL_MAX >= X_SHORT_MAX); */
501        ix_short xx;
502        get_ix_short(xp, &xx);
503        *ip = xx;
504        return ENOERR;
505}
506
507int
508ncx_put_short_schar(void *xp, const schar *ip)
509{
510        uchar *cp = (uchar *) xp;
511        if(*ip & 0x80)
512                *cp++ = 0xff;
513        else
514                *cp++ = 0;
515        *cp = (uchar)*ip;
516        return ENOERR;
517}
518
519int
520ncx_put_short_uchar(void *xp, const uchar *ip)
521{
522        uchar *cp = (uchar *) xp;
523        *cp++ = 0;
524        *cp = *ip;
525        return ENOERR;
526}
527
528int
529ncx_put_short_short(void *xp, const short *ip)
530{
531#if SIZEOF_IX_SHORT == SIZEOF_SHORT && X_SHORT_MAX == SHORT_MAX
532        put_ix_short(xp, (const ix_short *)ip);
533        return ENOERR;
534#else
535        ix_short xx = (ix_short)*ip;
536        put_ix_short(xp, &xx);
537# if X_SHORT_MAX < SHORT_MAX
538        if(*ip > X_SHORT_MAX || *ip < X_SHORT_MIN)
539                return NC_ERANGE;
540# endif
541        return ENOERR;
542#endif
543}
544
545int
546ncx_put_short_int(void *xp, const int *ip)
547{
548#if SIZEOF_IX_SHORT == SIZEOF_INT && X_SHORT_MAX == INT_MAX
549        put_ix_short(xp, (const ix_short *)ip);
550        return ENOERR;
551#else
552        ix_short xx = (ix_short)*ip;
553        put_ix_short(xp, &xx);
554# if X_SHORT_MAX < INT_MAX
555        if(*ip > X_SHORT_MAX || *ip < X_SHORT_MIN)
556                return NC_ERANGE;
557# endif
558        return ENOERR;
559#endif
560}
561
562int
563ncx_put_short_uint(void *xp, const unsigned int *ip)
564{
565#if SIZEOF_IX_SHORT == SIZEOF_INT && X_SHORT_MAX == INT_MAX
566        put_ix_short(xp, (const ix_short *)ip);
567        return ENOERR;
568#else
569        ix_short xx = (ix_short)*ip;
570        put_ix_short(xp, &xx);
571# if X_SHORT_MAX < INT_MAX
572        if(*ip > X_SHORT_MAX)
573                return NC_ERANGE;
574# endif
575        return ENOERR;
576#endif
577}
578
579int
580ncx_put_short_longlong(void *xp, const long long *ip)
581{
582#if SIZEOF_IX_SHORT == SIZEOF_LONG_LONG && X_SHORT_MAX == LONG_LONG_MAX
583        put_ix_short(xp, (const ix_short *)ip);
584        return ENOERR;
585#else
586        ix_short xx = (ix_short)*ip;
587        put_ix_short(xp, &xx);
588# if X_SHORT_MAX < LONG_LONG_MAX
589        if(*ip > X_SHORT_MAX || *ip < X_SHORT_MIN)
590                return NC_ERANGE;
591# endif
592        return ENOERR;
593#endif
594}
595
596int
597ncx_put_short_ulonglong(void *xp, const unsigned long long *ip)
598{
599#if SIZEOF_IX_SHORT == SIZEOF_LONG_LONG && X_SHORT_MAX == LONG_LONG_MAX
600        put_ix_short(xp, (const ix_short *)ip);
601        return ENOERR;
602#else
603        ix_short xx = (ix_short)*ip;
604        put_ix_short(xp, &xx);
605# if X_SHORT_MAX < LONG_LONG_MAX
606        if(*ip > X_SHORT_MAX)
607                return NC_ERANGE;
608# endif
609        return ENOERR;
610#endif
611}
612
613int
614ncx_put_short_float(void *xp, const float *ip)
615{
616        ix_short xx = *ip;
617        put_ix_short(xp, &xx);
618        if(*ip > X_SHORT_MAX || *ip < X_SHORT_MIN)
619                return NC_ERANGE;
620        return ENOERR;
621}
622
623int
624ncx_put_short_double(void *xp, const double *ip)
625{
626        ix_short xx = *ip;
627        put_ix_short(xp, &xx);
628        if(*ip > X_SHORT_MAX || *ip < X_SHORT_MIN)
629                return NC_ERANGE;
630        return ENOERR;
631}
632
633/* x_int */
634
635#if SHORT_MAX == X_INT_MAX
636typedef short ix_int;
637#define SIZEOF_IX_INT SIZEOF_SHORT
638#define IX_INT_MAX SHORT_MAX
639#elif INT_MAX  >= X_INT_MAX
640typedef int ix_int;
641#define SIZEOF_IX_INT SIZEOF_INT
642#define IX_INT_MAX INT_MAX
643#elif LONG_MAX  >= X_INT_MAX
644typedef long ix_int;
645#define SIZEOF_IX_INT SIZEOF_LONG
646#define IX_INT_MAX LONG_MAX
647#else
648#error "ix_int implementation"
649#endif
650
651
652static void
653get_ix_int(const void *xp, ix_int *ip)
654{
655        const uchar *cp = (const uchar *) xp;
656
657        *ip = *cp++ << 24;
658#if SIZEOF_IX_INT > X_SIZEOF_INT
659        if(*ip & 0x80000000)
660        {
661                /* extern is negative */
662                *ip |= (~(0xffffffff)); /* N.B. Assumes "twos complement" */
663        }
664#endif
665        *ip |= (*cp++ << 16);
666        *ip |= (*cp++ << 8);
667        *ip |= *cp; 
668}
669
670static void
671put_ix_int(void *xp, const ix_int *ip)
672{
673        uchar *cp = (uchar *) xp;
674
675        *cp++ = (*ip) >> 24;
676        *cp++ = ((*ip) & 0x00ff0000) >> 16;
677        *cp++ = ((*ip) & 0x0000ff00) >>  8;
678        *cp   = ((*ip) & 0x000000ff);
679}
680
681
682int
683ncx_get_int_schar(const void *xp, schar *ip)
684{
685        ix_int xx;
686        get_ix_int(xp, &xx);
687        *ip = xx;
688        if(xx > SCHAR_MAX || xx < SCHAR_MIN)
689                return NC_ERANGE;
690        return ENOERR;
691}
692
693int
694ncx_get_int_uchar(const void *xp, uchar *ip)
695{
696        ix_int xx;
697        get_ix_int(xp, &xx);
698        *ip = xx;
699        if(xx > UCHAR_MAX || xx < 0)
700                return NC_ERANGE;
701        return ENOERR;
702}
703
704int
705ncx_get_int_short(const void *xp, short *ip)
706{
707#if SIZEOF_IX_INT == SIZEOF_SHORT && IX_INT_MAX == SHORT_MAX
708        get_ix_int(xp, (ix_int *)ip);
709        return ENOERR;
710#else
711        ix_int xx;
712        get_ix_int(xp, &xx);
713        *ip = xx;
714#  if IX_INT_MAX > SHORT_MAX
715        if(xx > SHORT_MAX || xx < SHORT_MIN)
716                return NC_ERANGE;
717#  endif
718        return ENOERR;
719#endif
720}
721
722int
723ncx_get_int_int(const void *xp, int *ip)
724{
725#if SIZEOF_IX_INT == SIZEOF_INT && IX_INT_MAX == INT_MAX
726        get_ix_int(xp, (ix_int *)ip);
727        return ENOERR;
728#else
729        ix_int xx;
730        get_ix_int(xp, &xx);
731        *ip = xx;
732#  if IX_INT_MAX > INT_MAX
733        if(xx > INT_MAX || xx < INT_MIN)
734                return NC_ERANGE;
735#  endif
736        return ENOERR;
737#endif
738}
739
740int
741ncx_get_int_uint(const void *xp, unsigned int *ip)
742{
743        ix_int xx;
744        get_ix_int(xp, &xx);
745        *ip = xx;
746        if(xx > UINT_MAX || xx < 0)
747                return NC_ERANGE;
748        return ENOERR;
749}
750
751int
752ncx_get_int_longlong(const void *xp, long long *ip)
753{
754        ix_int xx;
755        get_ix_int(xp, &xx);
756        *ip = xx;
757        return ENOERR;
758}
759
760int
761ncx_get_int_ulonglong(const void *xp, unsigned long long *ip)
762{
763        ix_int xx;
764        get_ix_int(xp, &xx);
765        *ip = xx;
766        if(xx < 0)
767              return NC_ERANGE;
768        return ENOERR;
769}
770
771int
772ncx_get_int_float(const void *xp, float *ip)
773{
774        ix_int xx;
775        get_ix_int(xp, &xx);
776        *ip = xx;
777#if 0   /* TODO: determine when necessary */
778        if(xx > FLT_MAX || xx < (-FLT_MAX))
779                return NC_ERANGE;
780#endif
781        return ENOERR;
782}
783
784int
785ncx_get_int_double(const void *xp, double *ip)
786{
787        /* assert((DBL_MAX >= X_INT_MAX); */
788        ix_int xx;
789        get_ix_int(xp, &xx);
790        *ip = xx;
791        return ENOERR;
792}
793
794int
795ncx_put_int_schar(void *xp, const schar *ip)
796{
797        uchar *cp = (uchar *) xp;
798        if(*ip & 0x80)
799        {
800                *cp++ = 0xff;
801                *cp++ = 0xff;
802                *cp++ = 0xff;
803        }
804        else
805        {
806                *cp++ = 0x00;
807                *cp++ = 0x00;
808                *cp++ = 0x00;
809        }
810        *cp = (uchar)*ip;
811        return ENOERR;
812}
813
814int
815ncx_put_int_uchar(void *xp, const uchar *ip)
816{
817        uchar *cp = (uchar *) xp;
818        *cp++ = 0x00;
819        *cp++ = 0x00;
820        *cp++ = 0x00;
821        *cp   = *ip;
822        return ENOERR;
823}
824
825int
826ncx_put_int_short(void *xp, const short *ip)
827{
828#if SIZEOF_IX_INT == SIZEOF_SHORT && IX_INT_MAX == SHORT_MAX
829        put_ix_int(xp, (ix_int *)ip);
830        return ENOERR;
831#else
832        ix_int xx = (ix_int)(*ip);
833        put_ix_int(xp, &xx);
834#   if IX_INT_MAX < SHORT_MAX
835        if(*ip > X_INT_MAX || *ip < X_INT_MIN)
836                return NC_ERANGE;
837#   endif
838        return ENOERR;
839#endif
840}
841
842int
843ncx_put_int_int(void *xp, const int *ip)
844{
845#if SIZEOF_IX_INT == SIZEOF_INT && IX_INT_MAX == INT_MAX
846        put_ix_int(xp, (ix_int *)ip);
847        return ENOERR;
848#else
849        ix_int xx = (ix_int)(*ip);
850        put_ix_int(xp, &xx);
851#   if IX_INT_MAX < INT_MAX
852        if(*ip > X_INT_MAX || *ip < X_INT_MIN)
853                return NC_ERANGE;
854#   endif
855        return ENOERR;
856#endif
857}
858
859int
860ncx_put_int_uint(void *xp, const unsigned int *ip)
861{
862#if SIZEOF_IX_INT == SIZEOF_INT && IX_INT_MAX == INT_MAX
863        put_ix_int(xp, (ix_int *)ip);
864        return ENOERR;
865#else
866        ix_int xx = (ix_int)(*ip);
867        put_ix_int(xp, &xx);
868        if(*ip > X_UINT_MAX)
869                return NC_ERANGE;
870        return ENOERR;
871#endif
872}
873
874int
875ncx_put_int_longlong(void *xp, const longlong *ip)
876{
877#if SIZEOF_IX_INT == SIZEOF_LONG && IX_INT_MAX == LONG_MAX
878        put_ix_int(xp, (ix_int *)ip);
879        return ENOERR;
880#else
881        ix_int xx = (ix_int)(*ip);
882        put_ix_int(xp, &xx);
883#   if IX_INT_MAX < LONG_LONG_MAX
884        if(*ip > X_INT_MAX || *ip < X_INT_MIN)
885                return NC_ERANGE;
886#   endif
887        return ENOERR;
888#endif
889}
890
891int
892ncx_put_int_ulonglong(void *xp, const unsigned long long *ip)
893{
894#if SIZEOF_IX_INT == SIZEOF_LONG && IX_INT_MAX == LONG_MAX
895        put_ix_int(xp, (ix_int *)ip);
896        return ENOERR;
897#else
898        ix_int xx = (ix_int)(*ip);
899        put_ix_int(xp, &xx);
900#   if IX_INT_MAX < LONG_MAX
901        if(*ip > X_INT_MAX)
902                return NC_ERANGE;
903#   endif
904        return ENOERR;
905#endif
906}
907
908int
909ncx_put_int_float(void *xp, const float *ip)
910{
911        ix_int xx = (ix_int)(*ip);
912        put_ix_int(xp, &xx);
913        if(*ip > (double)X_INT_MAX || *ip < (double)X_INT_MIN)
914                return NC_ERANGE;
915        return ENOERR;
916}
917
918int
919ncx_put_int_double(void *xp, const double *ip)
920{
921        ix_int xx = (ix_int)(*ip);
922        put_ix_int(xp, &xx);
923        if(*ip > X_INT_MAX || *ip < X_INT_MIN)
924                return NC_ERANGE;
925        return ENOERR;
926}
927 
928
929/* x_float */
930
931#if X_SIZEOF_FLOAT == SIZEOF_FLOAT && !defined(NO_IEEE_FLOAT)
932
933static void
934get_ix_float(const void *xp, float *ip)
935{
936#ifdef WORDS_BIGENDIAN
937        (void) memcpy(ip, xp, sizeof(float));
938#else
939        swap4b(ip, xp);
940#endif
941}
942
943static void
944put_ix_float(void *xp, const float *ip)
945{
946#ifdef WORDS_BIGENDIAN
947        (void) memcpy(xp, ip, X_SIZEOF_FLOAT);
948#else
949        swap4b(xp, ip);
950#endif
951}
952
953#elif vax
954
955/* What IEEE single precision floating point looks like on a Vax */
956struct  ieee_single {
957        unsigned int    exp_hi       : 7;
958        unsigned int    sign         : 1;
959        unsigned int    mant_hi      : 7;
960        unsigned int    exp_lo       : 1;
961        unsigned int    mant_lo_hi   : 8;
962        unsigned int    mant_lo_lo   : 8;
963};
964
965/* Vax single precision floating point */
966struct  vax_single {
967        unsigned int    mantissa1 : 7;
968        unsigned int    exp       : 8;
969        unsigned int    sign      : 1;
970        unsigned int    mantissa2 : 16;
971};
972
973#define VAX_SNG_BIAS    0x81
974#define IEEE_SNG_BIAS   0x7f
975
976static struct sgl_limits {
977        struct vax_single s;
978        struct ieee_single ieee;
979} max = {
980        { 0x7f, 0xff, 0x0, 0xffff },    /* Max Vax */
981        { 0x7f, 0x0, 0x0, 0x1, 0x0, 0x0 }               /* Max IEEE */
982};
983static struct sgl_limits min = {
984        { 0x0, 0x0, 0x0, 0x0 }, /* Min Vax */
985        { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }                /* Min IEEE */
986};
987
988static void
989get_ix_float(const void *xp, float *ip)
990{
991                struct vax_single *const vsp = (struct vax_single *) ip;
992                const struct ieee_single *const isp =
993                         (const struct ieee_single *) xp;
994                unsigned exp = isp->exp_hi << 1 | isp->exp_lo;
995
996                switch(exp) {
997                case 0 :
998                        /* ieee subnormal */
999                        if(isp->mant_hi == min.ieee.mant_hi
1000                                && isp->mant_lo_hi == min.ieee.mant_lo_hi
1001                                && isp->mant_lo_lo == min.ieee.mant_lo_lo)
1002                        {
1003                                *vsp = min.s;
1004                        }
1005                        else
1006                        {
1007                                unsigned mantissa = (isp->mant_hi << 16)
1008                                         | isp->mant_lo_hi << 8
1009                                         | isp->mant_lo_lo;
1010                                unsigned tmp = mantissa >> 20;
1011                                if(tmp >= 4) {
1012                                        vsp->exp = 2;
1013                                } else if (tmp >= 2) {
1014                                        vsp->exp = 1;
1015                                } else {
1016                                        *vsp = min.s;
1017                                        break;
1018                                } /* else */
1019                                tmp = mantissa - (1 << (20 + vsp->exp ));
1020                                tmp <<= 3 - vsp->exp;
1021                                vsp->mantissa2 = tmp;
1022                                vsp->mantissa1 = (tmp >> 16);
1023                        }
1024                        break;
1025                case 0xfe :
1026                case 0xff :
1027                        *vsp = max.s;
1028                        break;
1029                default :
1030                        vsp->exp = exp - IEEE_SNG_BIAS + VAX_SNG_BIAS;
1031                        vsp->mantissa2 = isp->mant_lo_hi << 8 | isp->mant_lo_lo;
1032                        vsp->mantissa1 = isp->mant_hi;
1033                }
1034
1035                vsp->sign = isp->sign;
1036
1037}
1038
1039
1040static void
1041put_ix_float(void *xp, const float *ip)
1042{
1043                const struct vax_single *const vsp =
1044                         (const struct vax_single *)ip;
1045                struct ieee_single *const isp = (struct ieee_single *) xp;
1046
1047                switch(vsp->exp){
1048                case 0 :
1049                        /* all vax float with zero exponent map to zero */
1050                        *isp = min.ieee;
1051                        break;
1052                case 2 :
1053                case 1 :
1054                {
1055                        /* These will map to subnormals */
1056                        unsigned mantissa = (vsp->mantissa1 << 16)
1057                                         | vsp->mantissa2;
1058                        mantissa >>= 3 - vsp->exp;
1059                        mantissa += (1 << (20 + vsp->exp));
1060                        isp->mant_lo_lo = mantissa;
1061                        isp->mant_lo_hi = mantissa >> 8;
1062                        isp->mant_hi = mantissa >> 16;
1063                        isp->exp_lo = 0;
1064                        isp->exp_hi = 0;
1065                }
1066                        break;
1067                case 0xff : /* max.s.exp */
1068                        if( vsp->mantissa2 == max.s.mantissa2
1069                                && vsp->mantissa1 == max.s.mantissa1)
1070                        {
1071                                /* map largest vax float to ieee infinity */
1072                                *isp = max.ieee;
1073                                break;
1074                        } /* else, fall thru */
1075                default :
1076                {
1077                        unsigned exp = vsp->exp - VAX_SNG_BIAS + IEEE_SNG_BIAS;
1078                        isp->exp_hi = exp >> 1;
1079                        isp->exp_lo = exp;
1080                        isp->mant_lo_lo = vsp->mantissa2;
1081                        isp->mant_lo_hi = vsp->mantissa2 >> 8;
1082                        isp->mant_hi = vsp->mantissa1;
1083                }
1084                }
1085
1086                isp->sign = vsp->sign;
1087
1088}
1089
1090        /* vax */
1091#elif defined(_CRAY) && !defined(__crayx1)
1092
1093/*
1094 * Return the number of bytes until the next "word" boundary
1095 * N.B. This is based on the very wierd YMP address structure,
1096 * which puts the address within a word in the leftmost 3 bits
1097 * of the address.
1098 */
1099static size_t
1100word_align(const void *vp)
1101{
1102        const size_t rem = ((size_t)vp >> (64 - 3)) & 0x7;
1103        return (rem != 0);
1104}
1105
1106struct ieee_single_hi {
1107        unsigned int    sign    : 1;
1108        unsigned int     exp    : 8;
1109        unsigned int    mant    :23;
1110        unsigned int    pad     :32;
1111};
1112typedef struct ieee_single_hi ieee_single_hi;
1113
1114struct ieee_single_lo {
1115        unsigned int    pad     :32;
1116        unsigned int    sign    : 1;
1117        unsigned int     exp    : 8;
1118        unsigned int    mant    :23;
1119};
1120typedef struct ieee_single_lo ieee_single_lo;
1121
1122static const int ieee_single_bias = 0x7f;
1123
1124struct ieee_double {
1125        unsigned int    sign    : 1;
1126        unsigned int     exp    :11;
1127        unsigned int    mant    :52;
1128};
1129typedef struct ieee_double ieee_double;
1130
1131static const int ieee_double_bias = 0x3ff;
1132
1133#if defined(NO_IEEE_FLOAT)
1134
1135struct cray_single {
1136        unsigned int    sign    : 1;
1137        unsigned int     exp    :15;
1138        unsigned int    mant    :48;
1139};
1140typedef struct cray_single cray_single;
1141
1142static const int cs_ieis_bias = 0x4000 - 0x7f;
1143
1144static const int cs_id_bias = 0x4000 - 0x3ff;
1145
1146
1147static void
1148get_ix_float(const void *xp, float *ip)
1149{
1150
1151        if(word_align(xp) == 0)
1152        {
1153                const ieee_single_hi *isp = (const ieee_single_hi *) xp;
1154                cray_single *csp = (cray_single *) ip;
1155
1156                if(isp->exp == 0)
1157                {
1158                        /* ieee subnormal */
1159                        *ip = (double)isp->mant;
1160                        if(isp->mant != 0)
1161                        {
1162                                csp->exp -= (ieee_single_bias + 22);
1163                        }
1164                }
1165                else
1166                {
1167                        csp->exp  = isp->exp + cs_ieis_bias + 1;
1168                        csp->mant = isp->mant << (48 - 1 - 23);
1169                        csp->mant |= (1 << (48 - 1));
1170                }
1171                csp->sign = isp->sign;
1172
1173
1174        }
1175        else
1176        {
1177                const ieee_single_lo *isp = (const ieee_single_lo *) xp;
1178                cray_single *csp = (cray_single *) ip;
1179
1180                if(isp->exp == 0)
1181                {
1182                        /* ieee subnormal */
1183                        *ip = (double)isp->mant;
1184                        if(isp->mant != 0)
1185                        {
1186                                csp->exp -= (ieee_single_bias + 22);
1187                        }
1188                }
1189                else
1190                {
1191                        csp->exp  = isp->exp + cs_ieis_bias + 1;
1192                        csp->mant = isp->mant << (48 - 1 - 23);
1193                        csp->mant |= (1 << (48 - 1));
1194                }
1195                csp->sign = isp->sign;
1196
1197
1198        }
1199}
1200
1201static void
1202put_ix_float(void *xp, const float *ip)
1203{
1204        if(word_align(xp) == 0)
1205        {
1206                ieee_single_hi *isp = (ieee_single_hi*)xp;
1207        const cray_single *csp = (const cray_single *) ip;
1208        int ieee_exp = csp->exp - cs_ieis_bias -1;
1209
1210        isp->sign = csp->sign;
1211
1212        if(ieee_exp >= 0xff)
1213        {
1214                /* NC_ERANGE => ieee Inf */
1215                isp->exp = 0xff;
1216                isp->mant = 0x0;
1217        }
1218        else if(ieee_exp > 0)
1219        {
1220                /* normal ieee representation */
1221                isp->exp  = ieee_exp;
1222                /* assumes cray rep is in normal form */
1223                assert(csp->mant & 0x800000000000);
1224                isp->mant = (((csp->mant << 1) &
1225                                0xffffffffffff) >> (48 - 23));
1226        }
1227        else if(ieee_exp > -23)
1228        {
1229                /* ieee subnormal, right shift */
1230                const int rshift = (48 - 23 - ieee_exp);
1231
1232                isp->mant = csp->mant >> rshift;
1233
1234#if 0
1235                if(csp->mant & (1 << (rshift -1)))
1236                {
1237                        /* round up */
1238                        isp->mant++;
1239                }
1240#endif
1241
1242                isp->exp  = 0;
1243        }
1244        else
1245        {
1246                /* smaller than ieee can represent */
1247                isp->exp = 0;
1248                isp->mant = 0;
1249        }
1250
1251        }
1252        else
1253        {
1254                ieee_single_lo *isp = (ieee_single_lo*)xp;
1255        const cray_single *csp = (const cray_single *) ip;
1256        int ieee_exp = csp->exp - cs_ieis_bias -1;
1257
1258        isp->sign = csp->sign;
1259
1260        if(ieee_exp >= 0xff)
1261        {
1262                /* NC_ERANGE => ieee Inf */
1263                isp->exp = 0xff;
1264                isp->mant = 0x0;
1265        }
1266        else if(ieee_exp > 0)
1267        {
1268                /* normal ieee representation */
1269                isp->exp  = ieee_exp;
1270                /* assumes cray rep is in normal form */
1271                assert(csp->mant & 0x800000000000);
1272                isp->mant = (((csp->mant << 1) &
1273                                0xffffffffffff) >> (48 - 23));
1274        }
1275        else if(ieee_exp > -23)
1276        {
1277                /* ieee subnormal, right shift */
1278                const int rshift = (48 - 23 - ieee_exp);
1279
1280                isp->mant = csp->mant >> rshift;
1281
1282#if 0
1283                if(csp->mant & (1 << (rshift -1)))
1284                {
1285                        /* round up */
1286                        isp->mant++;
1287                }
1288#endif
1289
1290                isp->exp  = 0;
1291        }
1292        else
1293        {
1294                /* smaller than ieee can represent */
1295                isp->exp = 0;
1296                isp->mant = 0;
1297        }
1298
1299        }
1300}
1301
1302#else
1303        /* IEEE Cray with only doubles */
1304static void
1305get_ix_float(const void *xp, float *ip)
1306{
1307
1308        ieee_double *idp = (ieee_double *) ip;
1309
1310        if(word_align(xp) == 0)
1311        {
1312                const ieee_single_hi *isp = (const ieee_single_hi *) xp;
1313                if(isp->exp == 0 && isp->mant == 0)
1314                {
1315                        idp->exp = 0;
1316                        idp->mant = 0;
1317                }
1318                else
1319                {
1320                        idp->exp = isp->exp + (ieee_double_bias - ieee_single_bias);
1321                        idp->mant = isp->mant << (52 - 23);
1322                }
1323                idp->sign = isp->sign;
1324        }
1325        else
1326        {
1327                const ieee_single_lo *isp = (const ieee_single_lo *) xp;
1328                if(isp->exp == 0 && isp->mant == 0)
1329                {
1330                        idp->exp = 0;
1331                        idp->mant = 0;
1332                }
1333                else
1334                {
1335                        idp->exp = isp->exp + (ieee_double_bias - ieee_single_bias);
1336                        idp->mant = isp->mant << (52 - 23);
1337                }
1338                idp->sign = isp->sign;
1339        }
1340}
1341
1342static void
1343put_ix_float(void *xp, const float *ip)
1344{
1345        const ieee_double *idp = (const ieee_double *) ip;
1346        if(word_align(xp) == 0)
1347        {
1348                ieee_single_hi *isp = (ieee_single_hi*)xp;
1349                if(idp->exp > (ieee_double_bias - ieee_single_bias))
1350                        isp->exp = idp->exp - (ieee_double_bias - ieee_single_bias);
1351                else
1352                        isp->exp = 0;
1353                isp->mant = idp->mant >> (52 - 23);
1354                isp->sign = idp->sign;
1355        }
1356        else
1357        {
1358                ieee_single_lo *isp = (ieee_single_lo*)xp;
1359                if(idp->exp > (ieee_double_bias - ieee_single_bias))
1360                        isp->exp = idp->exp - (ieee_double_bias - ieee_single_bias);
1361                else
1362                        isp->exp = 0;
1363                isp->mant = idp->mant >> (52 - 23);
1364                isp->sign = idp->sign;
1365        }
1366}
1367#endif
1368
1369#else
1370#error "ix_float implementation"
1371#endif
1372
1373
1374int
1375ncx_get_float_schar(const void *xp, schar *ip)
1376{
1377        float xx;
1378        get_ix_float(xp, &xx);
1379        *ip = (schar) xx;
1380        if(xx > SCHAR_MAX || xx < SCHAR_MIN)
1381                return NC_ERANGE;
1382        return ENOERR;
1383}
1384
1385int
1386ncx_get_float_uchar(const void *xp, uchar *ip)
1387{
1388        float xx;
1389        get_ix_float(xp, &xx);
1390        *ip = (uchar) xx;
1391        if(xx > UCHAR_MAX || xx < 0)
1392                return NC_ERANGE;
1393        return ENOERR;
1394}
1395
1396int
1397ncx_get_float_short(const void *xp, short *ip)
1398{
1399        float xx;
1400        get_ix_float(xp, &xx);
1401        *ip = (short) xx;
1402        if(xx > SHORT_MAX || xx < SHORT_MIN)
1403                return NC_ERANGE;
1404        return ENOERR;
1405}
1406
1407int
1408ncx_get_float_int(const void *xp, int *ip)
1409{
1410        float xx;
1411        get_ix_float(xp, &xx);
1412        *ip = (int) xx;
1413        if(xx > (double)INT_MAX || xx < (double)INT_MIN)
1414                return NC_ERANGE;
1415        return ENOERR;
1416}
1417
1418int
1419ncx_get_float_uint(const void *xp, unsigned int *ip)
1420{
1421        float xx;
1422        get_ix_float(xp, &xx);
1423        *ip = (unsigned int) xx;
1424        if(xx > (double)UINT_MAX || xx < 0)
1425                return NC_ERANGE;
1426        return ENOERR;
1427}
1428
1429int
1430ncx_get_float_longlong(const void *xp, longlong *ip)
1431{
1432        float xx;
1433        get_ix_float(xp, &xx);
1434        *ip = (longlong) xx;
1435        if(xx > (double)LONG_LONG_MAX || xx < (double)LONG_LONG_MIN)
1436                return NC_ERANGE;
1437        return ENOERR;
1438}
1439
1440int
1441ncx_get_float_ulonglong(const void *xp, unsigned long long *ip)
1442{
1443        float xx;
1444        get_ix_float(xp, &xx);
1445        *ip = (longlong) xx;
1446        if(xx > (double)ULONG_LONG_MAX || xx < 0)
1447                return NC_ERANGE;
1448        return ENOERR;
1449}
1450
1451int
1452ncx_get_float_float(const void *xp, float *ip)
1453{
1454        /* TODO */
1455        get_ix_float(xp, ip);
1456        return ENOERR;
1457}
1458
1459int
1460ncx_get_float_double(const void *xp, double *ip)
1461{
1462        /* TODO */
1463        float xx;
1464        get_ix_float(xp, &xx);
1465        *ip = xx;
1466        return ENOERR;
1467}
1468
1469
1470int
1471ncx_put_float_schar(void *xp, const schar *ip)
1472{
1473        float xx = (float) *ip;
1474        put_ix_float(xp, &xx);
1475        return ENOERR;
1476}
1477
1478int
1479ncx_put_float_uchar(void *xp, const uchar *ip)
1480{
1481        float xx = (float) *ip;
1482        put_ix_float(xp, &xx);
1483        return ENOERR;
1484}
1485
1486int
1487ncx_put_float_short(void *xp, const short *ip)
1488{
1489        float xx = (float) *ip;
1490        put_ix_float(xp, &xx);
1491#if 0   /* TODO: figure this out */
1492        if((float)(*ip) > X_FLOAT_MAX || (float)(*ip) < X_FLOAT_MIN)
1493                return NC_ERANGE;
1494#endif
1495        return ENOERR;
1496}
1497
1498int
1499ncx_put_float_int(void *xp, const int *ip)
1500{
1501        float xx = (float) *ip;
1502        put_ix_float(xp, &xx);
1503#if 1   /* TODO: figure this out */
1504        if((float)(*ip) > X_FLOAT_MAX || (float)(*ip) < X_FLOAT_MIN)
1505                return NC_ERANGE;
1506#endif
1507        return ENOERR;
1508}
1509
1510int
1511ncx_put_float_uint(void *xp, const unsigned int *ip)
1512{
1513        float xx = (float) *ip;
1514        put_ix_float(xp, &xx);
1515#if 1   /* TODO: figure this out */
1516        if((float)(*ip) > X_FLOAT_MAX)
1517                return NC_ERANGE;
1518#endif
1519        return ENOERR;
1520}
1521
1522int
1523ncx_put_float_longlong(void *xp, const longlong *ip)
1524{
1525        float xx = (float) *ip;
1526        put_ix_float(xp, &xx);
1527#if 1   /* TODO: figure this out */
1528        if((float)(*ip) > X_FLOAT_MAX || (float)(*ip) < X_FLOAT_MIN)
1529                return NC_ERANGE;
1530#endif
1531        return ENOERR;
1532}
1533
1534int
1535ncx_put_float_ulonglong(void *xp, const unsigned long long *ip)
1536{
1537        float xx = (float) *ip;
1538        put_ix_float(xp, &xx);
1539#if 1   /* TODO: figure this out */
1540        if((float)(*ip) > X_FLOAT_MAX)
1541                return NC_ERANGE;
1542#endif
1543        return ENOERR;
1544}
1545
1546int
1547ncx_put_float_float(void *xp, const float *ip)
1548{
1549        put_ix_float(xp, ip);
1550#ifdef NO_IEEE_FLOAT
1551        if(*ip > X_FLOAT_MAX || *ip < X_FLOAT_MIN)
1552                return NC_ERANGE;
1553#endif
1554        return ENOERR;
1555}
1556
1557int
1558ncx_put_float_double(void *xp, const double *ip)
1559{
1560        float xx = (float) *ip;
1561        put_ix_float(xp, &xx);
1562        if(*ip > X_FLOAT_MAX || *ip < X_FLOAT_MIN)
1563                return NC_ERANGE;
1564        return ENOERR;
1565}
1566
1567/* x_double */
1568
1569#if X_SIZEOF_DOUBLE == SIZEOF_DOUBLE  && !defined(NO_IEEE_FLOAT)
1570
1571static void
1572get_ix_double(const void *xp, double *ip)
1573{
1574#ifdef WORDS_BIGENDIAN
1575        (void) memcpy(ip, xp, sizeof(double));
1576#else
1577        swap8b(ip, xp);
1578#endif
1579}
1580
1581static void
1582put_ix_double(void *xp, const double *ip)
1583{
1584#ifdef WORDS_BIGENDIAN
1585        (void) memcpy(xp, ip, X_SIZEOF_DOUBLE);
1586#else
1587        swap8b(xp, ip);
1588#endif
1589}
1590
1591#elif vax
1592
1593/* What IEEE double precision floating point looks like on a Vax */
1594struct  ieee_double {
1595        unsigned int    exp_hi   : 7;
1596        unsigned int    sign     : 1;
1597        unsigned int    mant_6   : 4;
1598        unsigned int    exp_lo   : 4;
1599        unsigned int    mant_5   : 8;
1600        unsigned int    mant_4   : 8;
1601
1602        unsigned int    mant_lo  : 32;
1603};
1604
1605/* Vax double precision floating point */
1606struct  vax_double {
1607        unsigned int    mantissa1 : 7;
1608        unsigned int    exp       : 8;
1609        unsigned int    sign      : 1;
1610        unsigned int    mantissa2 : 16;
1611        unsigned int    mantissa3 : 16;
1612        unsigned int    mantissa4 : 16;
1613};
1614
1615#define VAX_DBL_BIAS    0x81
1616#define IEEE_DBL_BIAS   0x3ff
1617#define MASK(nbits)     ((1 << nbits) - 1)
1618
1619static const struct dbl_limits {
1620        struct  vax_double d;
1621        struct  ieee_double ieee;
1622} dbl_limits[2] = {
1623        {{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff },   /* Max Vax */
1624        { 0x7f, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0}}, /* Max IEEE */
1625        {{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},               /* Min Vax */
1626        { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}, /* Min IEEE */
1627};
1628
1629
1630static void
1631get_ix_double(const void *xp, double *ip)
1632{
1633        struct vax_double *const vdp =
1634                         (struct vax_double *)ip;
1635        const struct ieee_double *const idp =
1636                         (const struct ieee_double *) xp;
1637        {
1638                const struct dbl_limits *lim;
1639                int ii;
1640                for (ii = 0, lim = dbl_limits;
1641                        ii < sizeof(dbl_limits)/sizeof(struct dbl_limits);
1642                        ii++, lim++)
1643                {
1644                        if ((idp->mant_lo == lim->ieee.mant_lo)
1645                                && (idp->mant_4 == lim->ieee.mant_4)
1646                                && (idp->mant_5 == lim->ieee.mant_5)
1647                                && (idp->mant_6 == lim->ieee.mant_6)
1648                                && (idp->exp_lo == lim->ieee.exp_lo)
1649                                && (idp->exp_hi == lim->ieee.exp_hi)
1650                                )
1651                        {
1652                                *vdp = lim->d;
1653                                goto doneit;
1654                        }
1655                }
1656        }
1657        {
1658                unsigned exp = idp->exp_hi << 4 | idp->exp_lo;
1659                vdp->exp = exp - IEEE_DBL_BIAS + VAX_DBL_BIAS;
1660        }
1661        {
1662                unsigned mant_hi = ((idp->mant_6 << 16)
1663                                 | (idp->mant_5 << 8)
1664                                 | idp->mant_4);
1665                unsigned mant_lo = SWAP4(idp->mant_lo);
1666                vdp->mantissa1 = (mant_hi >> 13);
1667                vdp->mantissa2 = ((mant_hi & MASK(13)) << 3)
1668                                | (mant_lo >> 29);
1669                vdp->mantissa3 = (mant_lo >> 13);
1670                vdp->mantissa4 = (mant_lo << 3);
1671        }
1672        doneit:
1673                vdp->sign = idp->sign;
1674
1675}
1676
1677
1678static void
1679put_ix_double(void *xp, const double *ip)
1680{
1681        const struct vax_double *const vdp = 
1682                        (const struct vax_double *)ip;
1683        struct ieee_double *const idp =
1684                         (struct ieee_double *) xp;
1685
1686        if ((vdp->mantissa4 > (dbl_limits[0].d.mantissa4 - 3)) &&
1687                (vdp->mantissa3 == dbl_limits[0].d.mantissa3) &&
1688                (vdp->mantissa2 == dbl_limits[0].d.mantissa2) &&
1689                (vdp->mantissa1 == dbl_limits[0].d.mantissa1) &&
1690                (vdp->exp == dbl_limits[0].d.exp))
1691        {
1692                *idp = dbl_limits[0].ieee;
1693                goto shipit;
1694        }
1695        if ((vdp->mantissa4 == dbl_limits[1].d.mantissa4) &&
1696                (vdp->mantissa3 == dbl_limits[1].d.mantissa3) &&
1697                (vdp->mantissa2 == dbl_limits[1].d.mantissa2) &&
1698                (vdp->mantissa1 == dbl_limits[1].d.mantissa1) &&
1699                (vdp->exp == dbl_limits[1].d.exp))
1700        {
1701                *idp = dbl_limits[1].ieee;
1702                goto shipit;
1703        }
1704
1705        {
1706                unsigned exp = vdp->exp - VAX_DBL_BIAS + IEEE_DBL_BIAS;
1707
1708                unsigned mant_lo = ((vdp->mantissa2 & MASK(3)) << 29) |
1709                        (vdp->mantissa3 << 13) |
1710                        ((vdp->mantissa4 >> 3) & MASK(13));
1711
1712                unsigned mant_hi = (vdp->mantissa1 << 13)
1713                                 | (vdp->mantissa2 >> 3);
1714
1715                if((vdp->mantissa4 & 7) > 4)
1716                {
1717                        /* round up */
1718                        mant_lo++;
1719                        if(mant_lo == 0)
1720                        {
1721                                mant_hi++;
1722                                if(mant_hi > 0xffffff)
1723                                {
1724                                        mant_hi = 0;
1725                                        exp++;
1726                                }
1727                        }
1728                }
1729
1730                idp->mant_lo = SWAP4(mant_lo);
1731                idp->mant_6 = mant_hi >> 16;
1732                idp->mant_5 = (mant_hi & 0xff00) >> 8;
1733                idp->mant_4 = mant_hi;
1734                idp->exp_hi = exp >> 4;
1735                idp->exp_lo = exp;
1736        }
1737               
1738        shipit:
1739                idp->sign = vdp->sign;
1740
1741}
1742
1743        /* vax */
1744#elif defined(_CRAY) && !defined(__crayx1)
1745
1746static void
1747get_ix_double(const void *xp, double *ip)
1748{
1749        const ieee_double *idp = (const ieee_double *) xp;
1750        cray_single *csp = (cray_single *) ip;
1751
1752        if(idp->exp == 0)
1753        {
1754                /* ieee subnormal */
1755                *ip = (double)idp->mant;
1756                if(idp->mant != 0)
1757                {
1758                        csp->exp -= (ieee_double_bias + 51);
1759                }
1760        }
1761        else
1762        {
1763                csp->exp  = idp->exp + cs_id_bias + 1;
1764                csp->mant = idp->mant >> (52 - 48 + 1);
1765                csp->mant |= (1 << (48 - 1));
1766        }
1767        csp->sign = idp->sign;
1768}
1769
1770static void
1771put_ix_double(void *xp, const double *ip)
1772{
1773        ieee_double *idp = (ieee_double *) xp;
1774        const cray_single *csp = (const cray_single *) ip;
1775
1776        int ieee_exp = csp->exp - cs_id_bias -1;
1777
1778        idp->sign = csp->sign;
1779
1780        if(ieee_exp >= 0x7ff)
1781        {
1782                /* NC_ERANGE => ieee Inf */
1783                idp->exp = 0x7ff;
1784                idp->mant = 0x0;
1785        }
1786        else if(ieee_exp > 0)
1787        {
1788                /* normal ieee representation */
1789                idp->exp  = ieee_exp;
1790                /* assumes cray rep is in normal form */
1791                assert(csp->mant & 0x800000000000);
1792                idp->mant = (((csp->mant << 1) &
1793                                0xffffffffffff) << (52 - 48));
1794        }
1795        else if(ieee_exp >= (-(52 -48)))
1796        {
1797                /* ieee subnormal, left shift */
1798                const int lshift = (52 - 48) + ieee_exp;
1799                idp->mant = csp->mant << lshift;
1800                idp->exp  = 0;
1801        }
1802        else if(ieee_exp >= -52)
1803        {
1804                /* ieee subnormal, right shift */
1805                const int rshift = (- (52 - 48) - ieee_exp);
1806
1807                idp->mant = csp->mant >> rshift;
1808
1809#if 0
1810                if(csp->mant & (1 << (rshift -1)))
1811                {
1812                        /* round up */
1813                        idp->mant++;
1814                }
1815#endif
1816
1817                idp->exp  = 0;
1818        }
1819        else
1820        {
1821                /* smaller than ieee can represent */
1822                idp->exp = 0;
1823                idp->mant = 0;
1824        }
1825}
1826#else
1827#error "ix_double implementation"
1828#endif
1829
1830int
1831ncx_get_double_schar(const void *xp, schar *ip)
1832{
1833        double xx;
1834        get_ix_double(xp, &xx);
1835        *ip = (schar) xx;
1836        if(xx > SCHAR_MAX || xx < SCHAR_MIN)
1837                return NC_ERANGE;
1838        return ENOERR;
1839}
1840
1841int
1842ncx_get_double_uchar(const void *xp, uchar *ip)
1843{
1844        double xx;
1845        get_ix_double(xp, &xx);
1846        *ip = (uchar) xx;
1847        if(xx > UCHAR_MAX || xx < 0)
1848                return NC_ERANGE;
1849        return ENOERR;
1850}
1851
1852int
1853ncx_get_double_short(const void *xp, short *ip)
1854{
1855        double xx;
1856        get_ix_double(xp, &xx);
1857        *ip = (short) xx;
1858        if(xx > SHORT_MAX || xx < SHORT_MIN)
1859                return NC_ERANGE;
1860        return ENOERR;
1861}
1862
1863int
1864ncx_get_double_int(const void *xp, int *ip)
1865{
1866        double xx;
1867        get_ix_double(xp, &xx);
1868        *ip = (int) xx;
1869        if(xx > INT_MAX || xx < INT_MIN)
1870                return NC_ERANGE;
1871        return ENOERR;
1872}
1873
1874int
1875ncx_get_double_uint(const void *xp, unsigned int *ip)
1876{
1877        double xx;
1878        get_ix_double(xp, &xx);
1879        *ip = (unsigned int) xx;
1880        if(xx > UINT_MAX || xx < 0)
1881                return NC_ERANGE;
1882        return ENOERR;
1883}
1884
1885int
1886ncx_get_double_longlong(const void *xp, longlong *ip)
1887{
1888        double xx;
1889        get_ix_double(xp, &xx);
1890        *ip = (longlong) xx;
1891        if(xx > LONG_LONG_MAX || xx < LONG_LONG_MIN)
1892                return NC_ERANGE;
1893        return ENOERR;
1894}
1895
1896int
1897ncx_get_double_ulonglong(const void *xp, unsigned long long *ip)
1898{
1899        double xx;
1900        get_ix_double(xp, &xx);
1901        *ip = (unsigned longlong) xx;
1902        if(xx > ULONG_LONG_MAX || xx < 0)
1903                return NC_ERANGE;
1904        return ENOERR;
1905}
1906
1907int
1908ncx_get_double_float(const void *xp, float *ip)
1909{
1910        double xx;
1911        get_ix_double(xp, &xx);
1912        if(xx > FLT_MAX)
1913        {
1914                *ip = FLT_MAX;
1915                return NC_ERANGE;
1916        }
1917        if(xx < (-FLT_MAX))
1918        {
1919                *ip = (-FLT_MAX);
1920                return NC_ERANGE;
1921        }
1922        *ip = (float) xx;
1923        return ENOERR;
1924}
1925
1926int
1927ncx_get_double_double(const void *xp, double *ip)
1928{
1929        /* TODO */
1930        get_ix_double(xp, ip);
1931        return ENOERR;
1932}
1933
1934
1935int
1936ncx_put_double_schar(void *xp, const schar *ip)
1937{
1938        double xx = (double) *ip;
1939        put_ix_double(xp, &xx);
1940        return ENOERR;
1941}
1942
1943int
1944ncx_put_double_uchar(void *xp, const uchar *ip)
1945{
1946        double xx = (double) *ip;
1947        put_ix_double(xp, &xx);
1948        return ENOERR;
1949}
1950
1951int
1952ncx_put_double_short(void *xp, const short *ip)
1953{
1954        double xx = (double) *ip;
1955        put_ix_double(xp, &xx);
1956#if 0   /* TODO: figure this out */
1957        if((double)(*ip) > X_DOUBLE_MAX || (double)(*ip) < X_DOUBLE_MIN)
1958                return NC_ERANGE;
1959#endif
1960        return ENOERR;
1961}
1962
1963int
1964ncx_put_double_int(void *xp, const int *ip)
1965{
1966        double xx = (double) *ip;
1967        put_ix_double(xp, &xx);
1968#if 0   /* TODO: figure this out */
1969        if((double)(*ip) > X_DOUBLE_MAX || (double)(*ip) < X_DOUBLE_MIN)
1970                return NC_ERANGE;
1971#endif
1972        return ENOERR;
1973}
1974
1975int
1976ncx_put_double_uint(void *xp, const unsigned int *ip)
1977{
1978        double xx = (double) *ip;
1979        put_ix_double(xp, &xx);
1980#if 0   /* TODO: figure this out */
1981        if((double)(*ip) > X_DOUBLE_MAX)
1982                return NC_ERANGE;
1983#endif
1984        return ENOERR;
1985}
1986
1987int
1988ncx_put_double_longlong(void *xp, const longlong *ip)
1989{
1990        double xx = (double) *ip;
1991        put_ix_double(xp, &xx);
1992#if 1   /* TODO: figure this out */
1993        if((double)(*ip) > X_DOUBLE_MAX || (double)(*ip) < X_DOUBLE_MIN)
1994                return NC_ERANGE;
1995#endif
1996        return ENOERR;
1997}
1998
1999int
2000ncx_put_double_ulonglong(void *xp, const unsigned long long *ip)
2001{
2002        double xx = (double) *ip;
2003        put_ix_double(xp, &xx);
2004#if 1   /* TODO: figure this out */
2005        if((double)(*ip) > X_DOUBLE_MAX)
2006                return NC_ERANGE;
2007#endif
2008        return ENOERR;
2009}
2010
2011int
2012ncx_put_double_float(void *xp, const float *ip)
2013{
2014        double xx = (double) *ip;
2015        put_ix_double(xp, &xx);
2016#if 1   /* TODO: figure this out */
2017        if((double)(*ip) > X_DOUBLE_MAX || (double)(*ip) < X_DOUBLE_MIN)
2018                return NC_ERANGE;
2019#endif
2020        return ENOERR;
2021}
2022
2023int
2024ncx_put_double_double(void *xp, const double *ip)
2025{
2026        put_ix_double(xp, ip);
2027#ifdef NO_IEEE_FLOAT
2028        if(*ip > X_DOUBLE_MAX || *ip < X_DOUBLE_MIN)
2029                return NC_ERANGE;
2030#endif
2031        return ENOERR;
2032}
2033
2034
2035/* x_size_t */
2036
2037#if SIZEOF_SIZE_T < X_SIZEOF_SIZE_T
2038#error "x_size_t implementation"
2039/* netcdf requires size_t which can hold a values from 0 to 2^32 -1 */
2040#endif
2041
2042int
2043ncx_put_size_t(void **xpp, const size_t *ulp)
2044{
2045        /* similar to put_ix_int() */
2046        uchar *cp = (uchar *) *xpp;
2047        assert(*ulp <= X_SIZE_MAX);
2048
2049        *cp++ = (uchar)((*ulp) >> 24);
2050        *cp++ = (uchar)(((*ulp) & 0x00ff0000) >> 16);
2051        *cp++ = (uchar)(((*ulp) & 0x0000ff00) >>  8);
2052        *cp   = (uchar)((*ulp) & 0x000000ff);
2053
2054        *xpp = (void *)((char *)(*xpp) + X_SIZEOF_SIZE_T);
2055        return ENOERR;
2056}
2057
2058int
2059ncx_get_size_t(const void **xpp,  size_t *ulp)
2060{
2061        /* similar to get_ix_int */
2062        const uchar *cp = (const uchar *) *xpp;
2063
2064        *ulp = (unsigned)(*cp++ << 24);
2065        *ulp |= (*cp++ << 16);
2066        *ulp |= (*cp++ << 8);
2067        *ulp |= *cp; 
2068
2069        *xpp = (const void *)((const char *)(*xpp) + X_SIZEOF_SIZE_T);
2070        return ENOERR;
2071}
2072
2073/* x_off_t */
2074
2075int
2076ncx_put_off_t(void **xpp, const off_t *lp, size_t sizeof_off_t)
2077{
2078        /* similar to put_ix_int() */
2079        uchar *cp = (uchar *) *xpp;
2080                /* No negative offsets stored in netcdf */
2081        if (*lp < 0) {
2082          /* Assume this is an overflow of a 32-bit int... */
2083          return ERANGE;
2084        }
2085         
2086        assert(sizeof_off_t == 4 || sizeof_off_t == 8);
2087
2088        if (sizeof_off_t == 4) {
2089                *cp++ = (uchar) ((*lp)               >> 24);
2090                *cp++ = (uchar)(((*lp) & 0x00ff0000) >> 16);
2091                *cp++ = (uchar)(((*lp) & 0x0000ff00) >>  8);
2092                *cp   = (uchar)( (*lp) & 0x000000ff);
2093        } else {
2094#if SIZEOF_OFF_T == 4
2095/* Write a 64-bit offset on a system with only a 32-bit offset */
2096                *cp++ = (uchar)0;
2097                *cp++ = (uchar)0;
2098                *cp++ = (uchar)0;
2099                *cp++ = (uchar)0;
2100
2101                *cp++ = (uchar)(((*lp) & 0xff000000) >> 24);
2102                *cp++ = (uchar)(((*lp) & 0x00ff0000) >> 16);
2103                *cp++ = (uchar)(((*lp) & 0x0000ff00) >>  8);
2104                *cp   = (uchar)( (*lp) & 0x000000ff);
2105#else
2106                *cp++ = (uchar) ((*lp)                          >> 56);
2107                *cp++ = (uchar)(((*lp) & 0x00ff000000000000ULL) >> 48);
2108                *cp++ = (uchar)(((*lp) & 0x0000ff0000000000ULL) >> 40);
2109                *cp++ = (uchar)(((*lp) & 0x000000ff00000000ULL) >> 32);
2110                *cp++ = (uchar)(((*lp) & 0x00000000ff000000ULL) >> 24);
2111                *cp++ = (uchar)(((*lp) & 0x0000000000ff0000ULL) >> 16);
2112                *cp++ = (uchar)(((*lp) & 0x000000000000ff00ULL) >>  8);
2113                *cp   = (uchar)( (*lp) & 0x00000000000000ffULL);
2114#endif
2115        }
2116        *xpp = (void *)((char *)(*xpp) + sizeof_off_t);
2117        return ENOERR;
2118}
2119
2120int
2121ncx_get_off_t(const void **xpp, off_t *lp, size_t sizeof_off_t)
2122{
2123        /* similar to get_ix_int() */
2124        const uchar *cp = (const uchar *) *xpp;
2125        assert(sizeof_off_t == 4 || sizeof_off_t == 8);
2126
2127        if (sizeof_off_t == 4) {
2128                *lp = *cp++ << 24;
2129                *lp |= (*cp++ << 16);
2130                *lp |= (*cp++ <<  8);
2131                *lp |= *cp; 
2132        } else {
2133#if SIZEOF_OFF_T == 4
2134/* Read a 64-bit offset on a system with only a 32-bit offset */
2135/* If the offset overflows, set an error code and return */
2136                *lp =  ((off_t)(*cp++) << 24);
2137                *lp |= ((off_t)(*cp++) << 16);
2138                *lp |= ((off_t)(*cp++) <<  8);
2139                *lp |= ((off_t)(*cp++));
2140/*
2141 * lp now contains the upper 32-bits of the 64-bit offset.  if lp is
2142 * not zero, then the dataset is larger than can be represented
2143 * on this system.  Set an error code and return.
2144 */
2145                if (*lp != 0) {
2146                  return ERANGE;
2147                }
2148
2149                *lp  = ((off_t)(*cp++) << 24);
2150                *lp |= ((off_t)(*cp++) << 16);
2151                *lp |= ((off_t)(*cp++) <<  8);
2152                *lp |=  (off_t)*cp;
2153
2154                if (*lp < 0) {
2155                  /*
2156                   * If this fails, then the offset is >2^31, but less
2157                   * than 2^32 which is not allowed, but is not caught
2158                   * by the previous check
2159                   */
2160                  return ERANGE;
2161                }
2162#else
2163                *lp =  ((off_t)(*cp++) << 56);
2164                *lp |= ((off_t)(*cp++) << 48);
2165                *lp |= ((off_t)(*cp++) << 40);
2166                *lp |= ((off_t)(*cp++) << 32);
2167                *lp |= ((off_t)(*cp++) << 24);
2168                *lp |= ((off_t)(*cp++) << 16);
2169                *lp |= ((off_t)(*cp++) <<  8);
2170                *lp |=  (off_t)*cp;
2171#endif
2172        }
2173        *xpp = (const void *)((const char *)(*xpp) + sizeof_off_t);
2174        return ENOERR;
2175}
2176
2177
2178/*
2179 * Aggregate numeric conversion functions.
2180 */
2181
2182
2183
2184/* schar */
2185
2186int
2187ncx_getn_schar_schar(const void **xpp, size_t nelems, schar *tp)
2188{
2189                (void) memcpy(tp, *xpp, nelems);
2190        *xpp = (void *)((char *)(*xpp) + nelems);
2191        return ENOERR;
2192
2193}
2194int
2195ncx_getn_schar_uchar(const void **xpp, size_t nelems, uchar *tp)
2196{
2197                (void) memcpy(tp, *xpp, nelems);
2198        *xpp = (void *)((char *)(*xpp) + nelems);
2199        return ENOERR;
2200
2201}
2202int
2203ncx_getn_schar_short(const void **xpp, size_t nelems, short *tp)
2204{
2205        schar *xp = (schar *)(*xpp);
2206
2207        while(nelems-- != 0)
2208        {
2209                *tp++ = *xp++;
2210        }
2211
2212        *xpp = (const void *)xp;
2213        return ENOERR;
2214}
2215
2216int
2217ncx_getn_schar_int(const void **xpp, size_t nelems, int *tp)
2218{
2219        schar *xp = (schar *)(*xpp);
2220
2221        while(nelems-- != 0)
2222        {
2223                *tp++ = *xp++;
2224        }
2225
2226        *xpp = (const void *)xp;
2227        return ENOERR;
2228}
2229
2230int
2231ncx_getn_schar_float(const void **xpp, size_t nelems, float *tp)
2232{
2233        schar *xp = (schar *)(*xpp);
2234
2235        while(nelems-- != 0)
2236        {
2237                *tp++ = *xp++;
2238        }
2239
2240        *xpp = (const void *)xp;
2241        return ENOERR;
2242}
2243
2244int
2245ncx_getn_schar_double(const void **xpp, size_t nelems, double *tp)
2246{
2247        schar *xp = (schar *)(*xpp);
2248
2249        while(nelems-- != 0)
2250        {
2251                *tp++ = *xp++;
2252        }
2253
2254        *xpp = (const void *)xp;
2255        return ENOERR;
2256}
2257
2258int
2259ncx_getn_schar_uint(const void **xpp, size_t nelems, uint *tp)
2260{
2261        schar *xp = (schar *)(*xpp);
2262
2263        while(nelems-- != 0)
2264        {
2265                *tp++ = *xp++;
2266        }
2267
2268        *xpp = (const void *)xp;
2269        return ENOERR;
2270}
2271
2272int
2273ncx_getn_schar_longlong(const void **xpp, size_t nelems, longlong *tp)
2274{
2275        schar *xp = (schar *)(*xpp);
2276
2277        while(nelems-- != 0)
2278        {
2279                *tp++ = *xp++;
2280        }
2281
2282        *xpp = (const void *)xp;
2283        return ENOERR;
2284}
2285
2286int
2287ncx_getn_schar_ulonglong(const void **xpp, size_t nelems, ulonglong *tp)
2288{
2289        schar *xp = (schar *)(*xpp);
2290
2291        while(nelems-- != 0)
2292        {
2293                *tp++ = *xp++;
2294        }
2295
2296        *xpp = (const void *)xp;
2297        return ENOERR;
2298}
2299
2300
2301int
2302ncx_pad_getn_schar_schar(const void **xpp, size_t nelems, schar *tp)
2303{
2304                size_t rndup = nelems % X_ALIGN;
2305
2306        if(rndup)
2307                rndup = X_ALIGN - rndup;
2308
2309        (void) memcpy(tp, *xpp, nelems);
2310        *xpp = (void *)((char *)(*xpp) + nelems + rndup);
2311
2312        return ENOERR;
2313
2314}
2315int
2316ncx_pad_getn_schar_uchar(const void **xpp, size_t nelems, uchar *tp)
2317{
2318                size_t rndup = nelems % X_ALIGN;
2319
2320        if(rndup)
2321                rndup = X_ALIGN - rndup;
2322
2323        (void) memcpy(tp, *xpp, nelems);
2324        *xpp = (void *)((char *)(*xpp) + nelems + rndup);
2325
2326        return ENOERR;
2327
2328}
2329int
2330ncx_pad_getn_schar_short(const void **xpp, size_t nelems, short *tp)
2331{
2332        size_t rndup = nelems % X_ALIGN;
2333        schar *xp = (schar *) *xpp;
2334
2335        if(rndup)
2336                rndup = X_ALIGN - rndup;
2337
2338        while(nelems-- != 0)
2339        {
2340                *tp++ = *xp++;
2341        }
2342
2343        *xpp = (void *)(xp + rndup);
2344        return ENOERR;
2345}
2346
2347int
2348ncx_pad_getn_schar_int(const void **xpp, size_t nelems, int *tp)
2349{
2350        size_t rndup = nelems % X_ALIGN;
2351        schar *xp = (schar *) *xpp;
2352
2353        if(rndup)
2354                rndup = X_ALIGN - rndup;
2355
2356        while(nelems-- != 0)
2357        {
2358                *tp++ = *xp++;
2359        }
2360
2361        *xpp = (void *)(xp + rndup);
2362        return ENOERR;
2363}
2364
2365int
2366ncx_pad_getn_schar_float(const void **xpp, size_t nelems, float *tp)
2367{
2368        size_t rndup = nelems % X_ALIGN;
2369        schar *xp = (schar *) *xpp;
2370
2371        if(rndup)
2372                rndup = X_ALIGN - rndup;
2373
2374        while(nelems-- != 0)
2375        {
2376                *tp++ = *xp++;
2377        }
2378
2379        *xpp = (void *)(xp + rndup);
2380        return ENOERR;
2381}
2382
2383int
2384ncx_pad_getn_schar_double(const void **xpp, size_t nelems, double *tp)
2385{
2386        size_t rndup = nelems % X_ALIGN;
2387        schar *xp = (schar *) *xpp;
2388
2389        if(rndup)
2390                rndup = X_ALIGN - rndup;
2391
2392        while(nelems-- != 0)
2393        {
2394                *tp++ = *xp++;
2395        }
2396
2397        *xpp = (void *)(xp + rndup);
2398        return ENOERR;
2399}
2400
2401int
2402ncx_pad_getn_schar_uint(const void **xpp, size_t nelems, uint *tp)
2403{
2404        size_t rndup = nelems % X_ALIGN;
2405        schar *xp = (schar *) *xpp;
2406
2407        if(rndup)
2408                rndup = X_ALIGN - rndup;
2409
2410        while(nelems-- != 0)
2411        {
2412                *tp++ = *xp++;
2413        }
2414
2415        *xpp = (void *)(xp + rndup);
2416        return ENOERR;
2417}
2418
2419int
2420ncx_pad_getn_schar_longlong(const void **xpp, size_t nelems, longlong *tp)
2421{
2422        size_t rndup = nelems % X_ALIGN;
2423        schar *xp = (schar *) *xpp;
2424
2425        if(rndup)
2426                rndup = X_ALIGN - rndup;
2427
2428        while(nelems-- != 0)
2429        {
2430                *tp++ = *xp++;
2431        }
2432
2433        *xpp = (void *)(xp + rndup);
2434        return ENOERR;
2435}
2436
2437int
2438ncx_pad_getn_schar_ulonglong(const void **xpp, size_t nelems, ulonglong *tp)
2439{
2440        size_t rndup = nelems % X_ALIGN;
2441        schar *xp = (schar *) *xpp;
2442
2443        if(rndup)
2444                rndup = X_ALIGN - rndup;
2445
2446        while(nelems-- != 0)
2447        {
2448                *tp++ = *xp++;
2449        }
2450
2451        *xpp = (void *)(xp + rndup);
2452        return ENOERR;
2453}
2454
2455
2456int
2457ncx_putn_schar_schar(void **xpp, size_t nelems, const schar *tp)
2458{
2459                (void) memcpy(*xpp, tp, nelems);
2460        *xpp = (void *)((char *)(*xpp) + nelems);
2461
2462        return ENOERR;
2463
2464}
2465int
2466ncx_putn_schar_uchar(void **xpp, size_t nelems, const uchar *tp)
2467{
2468                (void) memcpy(*xpp, tp, nelems);
2469        *xpp = (void *)((char *)(*xpp) + nelems);
2470
2471        return ENOERR;
2472
2473}
2474int
2475ncx_putn_schar_short(void **xpp, size_t nelems, const short *tp)
2476{
2477        int status = ENOERR;
2478        schar *xp = (schar *) *xpp;
2479
2480        while(nelems-- != 0)
2481        {
2482                if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN)
2483                        status = NC_ERANGE;
2484                *xp++ = (schar) *tp++;
2485        }
2486
2487        *xpp = (void *)xp;
2488        return status;
2489}
2490
2491int
2492ncx_putn_schar_int(void **xpp, size_t nelems, const int *tp)
2493{
2494        int status = ENOERR;
2495        schar *xp = (schar *) *xpp;
2496
2497        while(nelems-- != 0)
2498        {
2499                if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN)
2500                        status = NC_ERANGE;
2501                *xp++ = (schar) *tp++;
2502        }
2503
2504        *xpp = (void *)xp;
2505        return status;
2506}
2507
2508int
2509ncx_putn_schar_float(void **xpp, size_t nelems, const float *tp)
2510{
2511        int status = ENOERR;
2512        schar *xp = (schar *) *xpp;
2513
2514        while(nelems-- != 0)
2515        {
2516                if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN)
2517                        status = NC_ERANGE;
2518                *xp++ = (schar) *tp++;
2519        }
2520
2521        *xpp = (void *)xp;
2522        return status;
2523}
2524
2525int
2526ncx_putn_schar_double(void **xpp, size_t nelems, const double *tp)
2527{
2528        int status = ENOERR;
2529        schar *xp = (schar *) *xpp;
2530
2531        while(nelems-- != 0)
2532        {
2533                if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN)
2534                        status = NC_ERANGE;
2535                *xp++ = (schar) *tp++;
2536        }
2537
2538        *xpp = (void *)xp;
2539        return status;
2540}
2541
2542int
2543ncx_putn_schar_uint(void **xpp, size_t nelems, const uint *tp)
2544{
2545        int status = ENOERR;
2546        schar *xp = (schar *) *xpp;
2547
2548        while(nelems-- != 0)
2549        {
2550                if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN)
2551                        status = NC_ERANGE;
2552                *xp++ = (schar) *tp++;
2553        }
2554
2555        *xpp = (void *)xp;
2556        return status;
2557}
2558
2559int
2560ncx_putn_schar_longlong(void **xpp, size_t nelems, const longlong *tp)
2561{
2562        int status = ENOERR;
2563        schar *xp = (schar *) *xpp;
2564
2565        while(nelems-- != 0)
2566        {
2567                if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN)
2568                        status = NC_ERANGE;
2569                *xp++ = (schar) *tp++;
2570        }
2571
2572        *xpp = (void *)xp;
2573        return status;
2574}
2575
2576int
2577ncx_putn_schar_ulonglong(void **xpp, size_t nelems, const ulonglong *tp)
2578{
2579        int status = ENOERR;
2580        schar *xp = (schar *) *xpp;
2581
2582        while(nelems-- != 0)
2583        {
2584                if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN)
2585                        status = NC_ERANGE;
2586                *xp++ = (schar) *tp++;
2587        }
2588
2589        *xpp = (void *)xp;
2590        return status;
2591}
2592
2593
2594int
2595ncx_pad_putn_schar_schar(void **xpp, size_t nelems, const schar *tp)
2596{
2597                size_t rndup = nelems % X_ALIGN;
2598
2599        if(rndup)
2600                rndup = X_ALIGN - rndup;
2601
2602        (void) memcpy(*xpp, tp, nelems);
2603        *xpp = (void *)((char *)(*xpp) + nelems);
2604
2605        if(rndup)
2606        {
2607                (void) memcpy(*xpp, nada, rndup);
2608                *xpp = (void *)((char *)(*xpp) + rndup);
2609        }
2610       
2611        return ENOERR;
2612
2613}
2614int
2615ncx_pad_putn_schar_uchar(void **xpp, size_t nelems, const uchar *tp)
2616{
2617                size_t rndup = nelems % X_ALIGN;
2618
2619        if(rndup)
2620                rndup = X_ALIGN - rndup;
2621
2622        (void) memcpy(*xpp, tp, nelems);
2623        *xpp = (void *)((char *)(*xpp) + nelems);
2624
2625        if(rndup)
2626        {
2627                (void) memcpy(*xpp, nada, rndup);
2628                *xpp = (void *)((char *)(*xpp) + rndup);
2629        }
2630       
2631        return ENOERR;
2632
2633}
2634int
2635ncx_pad_putn_schar_short(void **xpp, size_t nelems, const short *tp)
2636{
2637        int status = ENOERR;
2638        size_t rndup = nelems % X_ALIGN;
2639        schar *xp = (schar *) *xpp;
2640
2641        if(rndup)
2642                rndup = X_ALIGN - rndup;
2643
2644        while(nelems-- != 0)
2645        {
2646                /* N.B. schar as signed */
2647                if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN)
2648                        status = NC_ERANGE;
2649                *xp++ = (schar) *tp++;
2650        }
2651
2652
2653        if(rndup)
2654        {
2655                (void) memcpy(xp, nada, rndup);
2656                xp += rndup;
2657        }
2658
2659        *xpp = (void *)xp;
2660        return status;
2661}
2662
2663int
2664ncx_pad_putn_schar_int(void **xpp, size_t nelems, const int *tp)
2665{
2666        int status = ENOERR;
2667        size_t rndup = nelems % X_ALIGN;
2668        schar *xp = (schar *) *xpp;
2669
2670        if(rndup)
2671                rndup = X_ALIGN - rndup;
2672
2673        while(nelems-- != 0)
2674        {
2675                /* N.B. schar as signed */
2676                if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN)
2677                        status = NC_ERANGE;
2678                *xp++ = (schar) *tp++;
2679        }
2680
2681
2682        if(rndup)
2683        {
2684                (void) memcpy(xp, nada, rndup);
2685                xp += rndup;
2686        }
2687
2688        *xpp = (void *)xp;
2689        return status;
2690}
2691
2692int
2693ncx_pad_putn_schar_float(void **xpp, size_t nelems, const float *tp)
2694{
2695        int status = ENOERR;
2696        size_t rndup = nelems % X_ALIGN;
2697        schar *xp = (schar *) *xpp;
2698
2699        if(rndup)
2700                rndup = X_ALIGN - rndup;
2701
2702        while(nelems-- != 0)
2703        {
2704                /* N.B. schar as signed */
2705                if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN)
2706                        status = NC_ERANGE;
2707                *xp++ = (schar) *tp++;
2708        }
2709
2710
2711        if(rndup)
2712        {
2713                (void) memcpy(xp, nada, rndup);
2714                xp += rndup;
2715        }
2716
2717        *xpp = (void *)xp;
2718        return status;
2719}
2720
2721int
2722ncx_pad_putn_schar_double(void **xpp, size_t nelems, const double *tp)
2723{
2724        int status = ENOERR;
2725        size_t rndup = nelems % X_ALIGN;
2726        schar *xp = (schar *) *xpp;
2727
2728        if(rndup)
2729                rndup = X_ALIGN - rndup;
2730
2731        while(nelems-- != 0)
2732        {
2733                /* N.B. schar as signed */
2734                if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN)
2735                        status = NC_ERANGE;
2736                *xp++ = (schar) *tp++;
2737        }
2738
2739
2740        if(rndup)
2741        {
2742                (void) memcpy(xp, nada, rndup);
2743                xp += rndup;
2744        }
2745
2746        *xpp = (void *)xp;
2747        return status;
2748}
2749
2750int
2751ncx_pad_putn_schar_uint(void **xpp, size_t nelems, const uint *tp)
2752{
2753        int status = ENOERR;
2754        size_t rndup = nelems % X_ALIGN;
2755        schar *xp = (schar *) *xpp;
2756
2757        if(rndup)
2758                rndup = X_ALIGN - rndup;
2759
2760        while(nelems-- != 0)
2761        {
2762                /* N.B. schar as signed */
2763                if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN)
2764                        status = NC_ERANGE;
2765                *xp++ = (schar) *tp++;
2766        }
2767
2768
2769        if(rndup)
2770        {
2771                (void) memcpy(xp, nada, rndup);
2772                xp += rndup;
2773        }
2774
2775        *xpp = (void *)xp;
2776        return status;
2777}
2778
2779int
2780ncx_pad_putn_schar_longlong(void **xpp, size_t nelems, const longlong *tp)
2781{
2782        int status = ENOERR;
2783        size_t rndup = nelems % X_ALIGN;
2784        schar *xp = (schar *) *xpp;
2785
2786        if(rndup)
2787                rndup = X_ALIGN - rndup;
2788
2789        while(nelems-- != 0)
2790        {
2791                /* N.B. schar as signed */
2792                if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN)
2793                        status = NC_ERANGE;
2794                *xp++ = (schar) *tp++;
2795        }
2796
2797
2798        if(rndup)
2799        {
2800                (void) memcpy(xp, nada, rndup);
2801                xp += rndup;
2802        }
2803
2804        *xpp = (void *)xp;
2805        return status;
2806}
2807
2808int
2809ncx_pad_putn_schar_ulonglong(void **xpp, size_t nelems, const ulonglong *tp)
2810{
2811        int status = ENOERR;
2812        size_t rndup = nelems % X_ALIGN;
2813        schar *xp = (schar *) *xpp;
2814
2815        if(rndup)
2816                rndup = X_ALIGN - rndup;
2817
2818        while(nelems-- != 0)
2819        {
2820                /* N.B. schar as signed */
2821                if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN)
2822                        status = NC_ERANGE;
2823                *xp++ = (schar) *tp++;
2824        }
2825
2826
2827        if(rndup)
2828        {
2829                (void) memcpy(xp, nada, rndup);
2830                xp += rndup;
2831        }
2832
2833        *xpp = (void *)xp;
2834        return status;
2835}
2836
2837
2838
2839/* short */
2840
2841int
2842ncx_getn_short_schar(const void **xpp, size_t nelems, schar *tp)
2843{
2844#if _SX && \
2845           X_SIZEOF_SHORT == SIZEOF_SHORT
2846
2847 /* basic algorithm is:
2848  *   - ensure sane alignment of input data
2849  *   - copy (conversion happens automatically) input data
2850  *     to output
2851  *   - update xpp to point at next unconverted input, and tp to point
2852  *     at next location for converted output
2853  */
2854  long i, j, ni;
2855  short tmp[LOOPCNT];        /* in case input is misaligned */
2856  short *xp;
2857  int nrange = 0;         /* number of range errors */
2858  int realign = 0;        /* "do we need to fix input data alignment?" */
2859  long cxp = (long) *((char**)xpp);
2860
2861  realign = (cxp & 7) % SIZEOF_SHORT;
2862  /* sjl: manually stripmine so we can limit amount of
2863   * vector work space reserved to LOOPCNT elements. Also
2864   * makes vectorisation easy */
2865  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
2866    ni=Min(nelems-j,LOOPCNT);
2867    if (realign) {
2868      memcpy(tmp, *xpp, ni*SIZEOF_SHORT);
2869      xp = tmp;
2870    } else {
2871      xp = (short *) *xpp;
2872    }
2873   /* copy the next block */
2874#pragma cdir loopcnt=LOOPCNT
2875#pragma cdir shortloop
2876    for (i=0; i<ni; i++) {
2877      tp[i] = (schar) Max( SCHAR_MIN, Min(SCHAR_MAX, (schar) xp[i]));
2878     /* test for range errors (not always needed but do it anyway) */
2879      nrange += xp[i] < SCHAR_MIN || xp[i] > SCHAR_MAX;
2880    }
2881   /* update xpp and tp */
2882    if (realign) xp = (short *) *xpp;
2883    xp += ni;
2884    tp += ni;
2885    *xpp = (void*)xp;
2886  }
2887  return nrange == 0 ? ENOERR : NC_ERANGE;
2888
2889#else   /* not SX */
2890        const char *xp = (const char *) *xpp;
2891        int status = ENOERR;
2892
2893        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
2894        {
2895                const int lstatus = ncx_get_short_schar(xp, tp);
2896                if(lstatus != ENOERR)
2897                        status = lstatus;
2898        }
2899
2900        *xpp = (const void *)xp;
2901        return status;
2902#  endif
2903}
2904
2905int
2906ncx_getn_short_uchar(const void **xpp, size_t nelems, uchar *tp)
2907{
2908#if _SX && \
2909           X_SIZEOF_SHORT == SIZEOF_SHORT
2910
2911 /* basic algorithm is:
2912  *   - ensure sane alignment of input data
2913  *   - copy (conversion happens automatically) input data
2914  *     to output
2915  *   - update xpp to point at next unconverted input, and tp to point
2916  *     at next location for converted output
2917  */
2918  long i, j, ni;
2919  short tmp[LOOPCNT];        /* in case input is misaligned */
2920  short *xp;
2921  int nrange = 0;         /* number of range errors */
2922  int realign = 0;        /* "do we need to fix input data alignment?" */
2923  long cxp = (long) *((char**)xpp);
2924
2925  realign = (cxp & 7) % SIZEOF_SHORT;
2926  /* sjl: manually stripmine so we can limit amount of
2927   * vector work space reserved to LOOPCNT elements. Also
2928   * makes vectorisation easy */
2929  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
2930    ni=Min(nelems-j,LOOPCNT);
2931    if (realign) {
2932      memcpy(tmp, *xpp, ni*SIZEOF_SHORT);
2933      xp = tmp;
2934    } else {
2935      xp = (short *) *xpp;
2936    }
2937   /* copy the next block */
2938#pragma cdir loopcnt=LOOPCNT
2939#pragma cdir shortloop
2940    for (i=0; i<ni; i++) {
2941      tp[i] = (uchar) Max( UCHAR_MIN, Min(UCHAR_MAX, (uchar) xp[i]));
2942     /* test for range errors (not always needed but do it anyway) */
2943      nrange += xp[i] < UCHAR_MIN || xp[i] > UCHAR_MAX;
2944    }
2945   /* update xpp and tp */
2946    if (realign) xp = (short *) *xpp;
2947    xp += ni;
2948    tp += ni;
2949    *xpp = (void*)xp;
2950  }
2951  return nrange == 0 ? ENOERR : NC_ERANGE;
2952
2953#else   /* not SX */
2954        const char *xp = (const char *) *xpp;
2955        int status = ENOERR;
2956
2957        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
2958        {
2959                const int lstatus = ncx_get_short_uchar(xp, tp);
2960                if(lstatus != ENOERR)
2961                        status = lstatus;
2962        }
2963
2964        *xpp = (const void *)xp;
2965        return status;
2966#  endif
2967}
2968
2969#if X_SIZEOF_SHORT == SIZEOF_SHORT
2970/* optimized version */
2971int
2972ncx_getn_short_short(const void **xpp, size_t nelems, short *tp)
2973{
2974#ifdef WORDS_BIGENDIAN
2975        (void) memcpy(tp, *xpp, nelems * sizeof(short));
2976# else
2977        swapn2b(tp, *xpp, nelems);
2978# endif
2979        *xpp = (const void *)((const char *)(*xpp) + nelems * X_SIZEOF_SHORT);
2980        return ENOERR;
2981}
2982#else
2983int
2984ncx_getn_short_short(const void **xpp, size_t nelems, short *tp)
2985{
2986#if _SX && \
2987           X_SIZEOF_SHORT == SIZEOF_SHORT
2988
2989 /* basic algorithm is:
2990  *   - ensure sane alignment of input data
2991  *   - copy (conversion happens automatically) input data
2992  *     to output
2993  *   - update xpp to point at next unconverted input, and tp to point
2994  *     at next location for converted output
2995  */
2996  long i, j, ni;
2997  short tmp[LOOPCNT];        /* in case input is misaligned */
2998  short *xp;
2999  int nrange = 0;         /* number of range errors */
3000  int realign = 0;        /* "do we need to fix input data alignment?" */
3001  long cxp = (long) *((char**)xpp);
3002
3003  realign = (cxp & 7) % SIZEOF_SHORT;
3004  /* sjl: manually stripmine so we can limit amount of
3005   * vector work space reserved to LOOPCNT elements. Also
3006   * makes vectorisation easy */
3007  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
3008    ni=Min(nelems-j,LOOPCNT);
3009    if (realign) {
3010      memcpy(tmp, *xpp, ni*SIZEOF_SHORT);
3011      xp = tmp;
3012    } else {
3013      xp = (short *) *xpp;
3014    }
3015   /* copy the next block */
3016#pragma cdir loopcnt=LOOPCNT
3017#pragma cdir shortloop
3018    for (i=0; i<ni; i++) {
3019      tp[i] = (short) Max( SHORT_MIN, Min(SHORT_MAX, (short) xp[i]));
3020     /* test for range errors (not always needed but do it anyway) */
3021      nrange += xp[i] < SHORT_MIN || xp[i] > SHORT_MAX;
3022    }
3023   /* update xpp and tp */
3024    if (realign) xp = (short *) *xpp;
3025    xp += ni;
3026    tp += ni;
3027    *xpp = (void*)xp;
3028  }
3029  return nrange == 0 ? ENOERR : NC_ERANGE;
3030
3031#else   /* not SX */
3032        const char *xp = (const char *) *xpp;
3033        int status = ENOERR;
3034
3035        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3036        {
3037                const int lstatus = ncx_get_short_short(xp, tp);
3038                if(lstatus != ENOERR)
3039                        status = lstatus;
3040        }
3041
3042        *xpp = (const void *)xp;
3043        return status;
3044#  endif
3045}
3046
3047#endif
3048int
3049ncx_getn_short_int(const void **xpp, size_t nelems, int *tp)
3050{
3051#if _SX && \
3052           X_SIZEOF_SHORT == SIZEOF_SHORT
3053
3054 /* basic algorithm is:
3055  *   - ensure sane alignment of input data
3056  *   - copy (conversion happens automatically) input data
3057  *     to output
3058  *   - update xpp to point at next unconverted input, and tp to point
3059  *     at next location for converted output
3060  */
3061  long i, j, ni;
3062  short tmp[LOOPCNT];        /* in case input is misaligned */
3063  short *xp;
3064  int nrange = 0;         /* number of range errors */
3065  int realign = 0;        /* "do we need to fix input data alignment?" */
3066  long cxp = (long) *((char**)xpp);
3067
3068  realign = (cxp & 7) % SIZEOF_SHORT;
3069  /* sjl: manually stripmine so we can limit amount of
3070   * vector work space reserved to LOOPCNT elements. Also
3071   * makes vectorisation easy */
3072  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
3073    ni=Min(nelems-j,LOOPCNT);
3074    if (realign) {
3075      memcpy(tmp, *xpp, ni*SIZEOF_SHORT);
3076      xp = tmp;
3077    } else {
3078      xp = (short *) *xpp;
3079    }
3080   /* copy the next block */
3081#pragma cdir loopcnt=LOOPCNT
3082#pragma cdir shortloop
3083    for (i=0; i<ni; i++) {
3084      tp[i] = (int) Max( INT_MIN, Min(INT_MAX, (int) xp[i]));
3085     /* test for range errors (not always needed but do it anyway) */
3086      nrange += xp[i] < INT_MIN || xp[i] > INT_MAX;
3087    }
3088   /* update xpp and tp */
3089    if (realign) xp = (short *) *xpp;
3090    xp += ni;
3091    tp += ni;
3092    *xpp = (void*)xp;
3093  }
3094  return nrange == 0 ? ENOERR : NC_ERANGE;
3095
3096#else   /* not SX */
3097        const char *xp = (const char *) *xpp;
3098        int status = ENOERR;
3099
3100        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3101        {
3102                const int lstatus = ncx_get_short_int(xp, tp);
3103                if(lstatus != ENOERR)
3104                        status = lstatus;
3105        }
3106
3107        *xpp = (const void *)xp;
3108        return status;
3109#  endif
3110}
3111
3112int
3113ncx_getn_short_float(const void **xpp, size_t nelems, float *tp)
3114{
3115#if _SX && \
3116           X_SIZEOF_SHORT == SIZEOF_SHORT
3117
3118 /* basic algorithm is:
3119  *   - ensure sane alignment of input data
3120  *   - copy (conversion happens automatically) input data
3121  *     to output
3122  *   - update xpp to point at next unconverted input, and tp to point
3123  *     at next location for converted output
3124  */
3125  long i, j, ni;
3126  short tmp[LOOPCNT];        /* in case input is misaligned */
3127  short *xp;
3128  int nrange = 0;         /* number of range errors */
3129  int realign = 0;        /* "do we need to fix input data alignment?" */
3130  long cxp = (long) *((char**)xpp);
3131
3132  realign = (cxp & 7) % SIZEOF_SHORT;
3133  /* sjl: manually stripmine so we can limit amount of
3134   * vector work space reserved to LOOPCNT elements. Also
3135   * makes vectorisation easy */
3136  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
3137    ni=Min(nelems-j,LOOPCNT);
3138    if (realign) {
3139      memcpy(tmp, *xpp, ni*SIZEOF_SHORT);
3140      xp = tmp;
3141    } else {
3142      xp = (short *) *xpp;
3143    }
3144   /* copy the next block */
3145#pragma cdir loopcnt=LOOPCNT
3146#pragma cdir shortloop
3147    for (i=0; i<ni; i++) {
3148      tp[i] = (float) Max( FLOAT_MIN, Min(FLOAT_MAX, (float) xp[i]));
3149     /* test for range errors (not always needed but do it anyway) */
3150      nrange += xp[i] < FLOAT_MIN || xp[i] > FLOAT_MAX;
3151    }
3152   /* update xpp and tp */
3153    if (realign) xp = (short *) *xpp;
3154    xp += ni;
3155    tp += ni;
3156    *xpp = (void*)xp;
3157  }
3158  return nrange == 0 ? ENOERR : NC_ERANGE;
3159
3160#else   /* not SX */
3161        const char *xp = (const char *) *xpp;
3162        int status = ENOERR;
3163
3164        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3165        {
3166                const int lstatus = ncx_get_short_float(xp, tp);
3167                if(lstatus != ENOERR)
3168                        status = lstatus;
3169        }
3170
3171        *xpp = (const void *)xp;
3172        return status;
3173#  endif
3174}
3175
3176int
3177ncx_getn_short_double(const void **xpp, size_t nelems, double *tp)
3178{
3179#if _SX && \
3180           X_SIZEOF_SHORT == SIZEOF_SHORT
3181
3182 /* basic algorithm is:
3183  *   - ensure sane alignment of input data
3184  *   - copy (conversion happens automatically) input data
3185  *     to output
3186  *   - update xpp to point at next unconverted input, and tp to point
3187  *     at next location for converted output
3188  */
3189  long i, j, ni;
3190  short tmp[LOOPCNT];        /* in case input is misaligned */
3191  short *xp;
3192  int nrange = 0;         /* number of range errors */
3193  int realign = 0;        /* "do we need to fix input data alignment?" */
3194  long cxp = (long) *((char**)xpp);
3195
3196  realign = (cxp & 7) % SIZEOF_SHORT;
3197  /* sjl: manually stripmine so we can limit amount of
3198   * vector work space reserved to LOOPCNT elements. Also
3199   * makes vectorisation easy */
3200  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
3201    ni=Min(nelems-j,LOOPCNT);
3202    if (realign) {
3203      memcpy(tmp, *xpp, ni*SIZEOF_SHORT);
3204      xp = tmp;
3205    } else {
3206      xp = (short *) *xpp;
3207    }
3208   /* copy the next block */
3209#pragma cdir loopcnt=LOOPCNT
3210#pragma cdir shortloop
3211    for (i=0; i<ni; i++) {
3212      tp[i] = (double) Max( DOUBLE_MIN, Min(DOUBLE_MAX, (double) xp[i]));
3213     /* test for range errors (not always needed but do it anyway) */
3214      nrange += xp[i] < DOUBLE_MIN || xp[i] > DOUBLE_MAX;
3215    }
3216   /* update xpp and tp */
3217    if (realign) xp = (short *) *xpp;
3218    xp += ni;
3219    tp += ni;
3220    *xpp = (void*)xp;
3221  }
3222  return nrange == 0 ? ENOERR : NC_ERANGE;
3223
3224#else   /* not SX */
3225        const char *xp = (const char *) *xpp;
3226        int status = ENOERR;
3227
3228        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3229        {
3230                const int lstatus = ncx_get_short_double(xp, tp);
3231                if(lstatus != ENOERR)
3232                        status = lstatus;
3233        }
3234
3235        *xpp = (const void *)xp;
3236        return status;
3237#  endif
3238}
3239
3240int
3241ncx_getn_short_uint(const void **xpp, size_t nelems, uint *tp)
3242{
3243#if _SX && \
3244           X_SIZEOF_SHORT == SIZEOF_SHORT
3245
3246 /* basic algorithm is:
3247  *   - ensure sane alignment of input data
3248  *   - copy (conversion happens automatically) input data
3249  *     to output
3250  *   - update xpp to point at next unconverted input, and tp to point
3251  *     at next location for converted output
3252  */
3253  long i, j, ni;
3254  short tmp[LOOPCNT];        /* in case input is misaligned */
3255  short *xp;
3256  int nrange = 0;         /* number of range errors */
3257  int realign = 0;        /* "do we need to fix input data alignment?" */
3258  long cxp = (long) *((char**)xpp);
3259
3260  realign = (cxp & 7) % SIZEOF_SHORT;
3261  /* sjl: manually stripmine so we can limit amount of
3262   * vector work space reserved to LOOPCNT elements. Also
3263   * makes vectorisation easy */
3264  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
3265    ni=Min(nelems-j,LOOPCNT);
3266    if (realign) {
3267      memcpy(tmp, *xpp, ni*SIZEOF_SHORT);
3268      xp = tmp;
3269    } else {
3270      xp = (short *) *xpp;
3271    }
3272   /* copy the next block */
3273#pragma cdir loopcnt=LOOPCNT
3274#pragma cdir shortloop
3275    for (i=0; i<ni; i++) {
3276      tp[i] = (uint) Max( UINT_MIN, Min(UINT_MAX, (uint) xp[i]));
3277     /* test for range errors (not always needed but do it anyway) */
3278      nrange += xp[i] < UINT_MIN || xp[i] > UINT_MAX;
3279    }
3280   /* update xpp and tp */
3281    if (realign) xp = (short *) *xpp;
3282    xp += ni;
3283    tp += ni;
3284    *xpp = (void*)xp;
3285  }
3286  return nrange == 0 ? ENOERR : NC_ERANGE;
3287
3288#else   /* not SX */
3289        const char *xp = (const char *) *xpp;
3290        int status = ENOERR;
3291
3292        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3293        {
3294                const int lstatus = ncx_get_short_uint(xp, tp);
3295                if(lstatus != ENOERR)
3296                        status = lstatus;
3297        }
3298
3299        *xpp = (const void *)xp;
3300        return status;
3301#  endif
3302}
3303
3304int
3305ncx_getn_short_longlong(const void **xpp, size_t nelems, longlong *tp)
3306{
3307#if _SX && \
3308           X_SIZEOF_SHORT == SIZEOF_SHORT
3309
3310 /* basic algorithm is:
3311  *   - ensure sane alignment of input data
3312  *   - copy (conversion happens automatically) input data
3313  *     to output
3314  *   - update xpp to point at next unconverted input, and tp to point
3315  *     at next location for converted output
3316  */
3317  long i, j, ni;
3318  short tmp[LOOPCNT];        /* in case input is misaligned */
3319  short *xp;
3320  int nrange = 0;         /* number of range errors */
3321  int realign = 0;        /* "do we need to fix input data alignment?" */
3322  long cxp = (long) *((char**)xpp);
3323
3324  realign = (cxp & 7) % SIZEOF_SHORT;
3325  /* sjl: manually stripmine so we can limit amount of
3326   * vector work space reserved to LOOPCNT elements. Also
3327   * makes vectorisation easy */
3328  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
3329    ni=Min(nelems-j,LOOPCNT);
3330    if (realign) {
3331      memcpy(tmp, *xpp, ni*SIZEOF_SHORT);
3332      xp = tmp;
3333    } else {
3334      xp = (short *) *xpp;
3335    }
3336   /* copy the next block */
3337#pragma cdir loopcnt=LOOPCNT
3338#pragma cdir shortloop
3339    for (i=0; i<ni; i++) {
3340      tp[i] = (longlong) Max( LONGLONG_MIN, Min(LONGLONG_MAX, (longlong) xp[i]));
3341     /* test for range errors (not always needed but do it anyway) */
3342      nrange += xp[i] < LONGLONG_MIN || xp[i] > LONGLONG_MAX;
3343    }
3344   /* update xpp and tp */
3345    if (realign) xp = (short *) *xpp;
3346    xp += ni;
3347    tp += ni;
3348    *xpp = (void*)xp;
3349  }
3350  return nrange == 0 ? ENOERR : NC_ERANGE;
3351
3352#else   /* not SX */
3353        const char *xp = (const char *) *xpp;
3354        int status = ENOERR;
3355
3356        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3357        {
3358                const int lstatus = ncx_get_short_longlong(xp, tp);
3359                if(lstatus != ENOERR)
3360                        status = lstatus;
3361        }
3362
3363        *xpp = (const void *)xp;
3364        return status;
3365#  endif
3366}
3367
3368int
3369ncx_getn_short_ulonglong(const void **xpp, size_t nelems, ulonglong *tp)
3370{
3371#if _SX && \
3372           X_SIZEOF_SHORT == SIZEOF_SHORT
3373
3374 /* basic algorithm is:
3375  *   - ensure sane alignment of input data
3376  *   - copy (conversion happens automatically) input data
3377  *     to output
3378  *   - update xpp to point at next unconverted input, and tp to point
3379  *     at next location for converted output
3380  */
3381  long i, j, ni;
3382  short tmp[LOOPCNT];        /* in case input is misaligned */
3383  short *xp;
3384  int nrange = 0;         /* number of range errors */
3385  int realign = 0;        /* "do we need to fix input data alignment?" */
3386  long cxp = (long) *((char**)xpp);
3387
3388  realign = (cxp & 7) % SIZEOF_SHORT;
3389  /* sjl: manually stripmine so we can limit amount of
3390   * vector work space reserved to LOOPCNT elements. Also
3391   * makes vectorisation easy */
3392  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
3393    ni=Min(nelems-j,LOOPCNT);
3394    if (realign) {
3395      memcpy(tmp, *xpp, ni*SIZEOF_SHORT);
3396      xp = tmp;
3397    } else {
3398      xp = (short *) *xpp;
3399    }
3400   /* copy the next block */
3401#pragma cdir loopcnt=LOOPCNT
3402#pragma cdir shortloop
3403    for (i=0; i<ni; i++) {
3404      tp[i] = (ulonglong) Max( ULONGLONG_MIN, Min(ULONGLONG_MAX, (ulonglong) xp[i]));
3405     /* test for range errors (not always needed but do it anyway) */
3406      nrange += xp[i] < ULONGLONG_MIN || xp[i] > ULONGLONG_MAX;
3407    }
3408   /* update xpp and tp */
3409    if (realign) xp = (short *) *xpp;
3410    xp += ni;
3411    tp += ni;
3412    *xpp = (void*)xp;
3413  }
3414  return nrange == 0 ? ENOERR : NC_ERANGE;
3415
3416#else   /* not SX */
3417        const char *xp = (const char *) *xpp;
3418        int status = ENOERR;
3419
3420        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3421        {
3422                const int lstatus = ncx_get_short_ulonglong(xp, tp);
3423                if(lstatus != ENOERR)
3424                        status = lstatus;
3425        }
3426
3427        *xpp = (const void *)xp;
3428        return status;
3429#  endif
3430}
3431
3432
3433int
3434ncx_pad_getn_short_schar(const void **xpp, size_t nelems, schar *tp)
3435{
3436        const size_t rndup = nelems % 2;
3437
3438        const char *xp = (const char *) *xpp;
3439        int status = ENOERR;
3440
3441        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3442        {
3443                const int lstatus = ncx_get_short_schar(xp, tp);
3444                if(lstatus != ENOERR)
3445                        status = lstatus;
3446        }
3447
3448        if(rndup != 0)
3449                xp += X_SIZEOF_SHORT;
3450               
3451        *xpp = (void *)xp;
3452        return status;
3453}
3454
3455int
3456ncx_pad_getn_short_uchar(const void **xpp, size_t nelems, uchar *tp)
3457{
3458        const size_t rndup = nelems % 2;
3459
3460        const char *xp = (const char *) *xpp;
3461        int status = ENOERR;
3462
3463        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3464        {
3465                const int lstatus = ncx_get_short_uchar(xp, tp);
3466                if(lstatus != ENOERR)
3467                        status = lstatus;
3468        }
3469
3470        if(rndup != 0)
3471                xp += X_SIZEOF_SHORT;
3472               
3473        *xpp = (void *)xp;
3474        return status;
3475}
3476
3477int
3478ncx_pad_getn_short_short(const void **xpp, size_t nelems, short *tp)
3479{
3480        const size_t rndup = nelems % 2;
3481
3482        const char *xp = (const char *) *xpp;
3483        int status = ENOERR;
3484
3485        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3486        {
3487                const int lstatus = ncx_get_short_short(xp, tp);
3488                if(lstatus != ENOERR)
3489                        status = lstatus;
3490        }
3491
3492        if(rndup != 0)
3493                xp += X_SIZEOF_SHORT;
3494               
3495        *xpp = (void *)xp;
3496        return status;
3497}
3498
3499int
3500ncx_pad_getn_short_int(const void **xpp, size_t nelems, int *tp)
3501{
3502        const size_t rndup = nelems % 2;
3503
3504        const char *xp = (const char *) *xpp;
3505        int status = ENOERR;
3506
3507        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3508        {
3509                const int lstatus = ncx_get_short_int(xp, tp);
3510                if(lstatus != ENOERR)
3511                        status = lstatus;
3512        }
3513
3514        if(rndup != 0)
3515                xp += X_SIZEOF_SHORT;
3516               
3517        *xpp = (void *)xp;
3518        return status;
3519}
3520
3521int
3522ncx_pad_getn_short_float(const void **xpp, size_t nelems, float *tp)
3523{
3524        const size_t rndup = nelems % 2;
3525
3526        const char *xp = (const char *) *xpp;
3527        int status = ENOERR;
3528
3529        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3530        {
3531                const int lstatus = ncx_get_short_float(xp, tp);
3532                if(lstatus != ENOERR)
3533                        status = lstatus;
3534        }
3535
3536        if(rndup != 0)
3537                xp += X_SIZEOF_SHORT;
3538               
3539        *xpp = (void *)xp;
3540        return status;
3541}
3542
3543int
3544ncx_pad_getn_short_double(const void **xpp, size_t nelems, double *tp)
3545{
3546        const size_t rndup = nelems % 2;
3547
3548        const char *xp = (const char *) *xpp;
3549        int status = ENOERR;
3550
3551        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3552        {
3553                const int lstatus = ncx_get_short_double(xp, tp);
3554                if(lstatus != ENOERR)
3555                        status = lstatus;
3556        }
3557
3558        if(rndup != 0)
3559                xp += X_SIZEOF_SHORT;
3560               
3561        *xpp = (void *)xp;
3562        return status;
3563}
3564
3565int
3566ncx_pad_getn_short_uint(const void **xpp, size_t nelems, uint *tp)
3567{
3568        const size_t rndup = nelems % 2;
3569
3570        const char *xp = (const char *) *xpp;
3571        int status = ENOERR;
3572
3573        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3574        {
3575                const int lstatus = ncx_get_short_uint(xp, tp);
3576                if(lstatus != ENOERR)
3577                        status = lstatus;
3578        }
3579
3580        if(rndup != 0)
3581                xp += X_SIZEOF_SHORT;
3582               
3583        *xpp = (void *)xp;
3584        return status;
3585}
3586
3587int
3588ncx_pad_getn_short_longlong(const void **xpp, size_t nelems, longlong *tp)
3589{
3590        const size_t rndup = nelems % 2;
3591
3592        const char *xp = (const char *) *xpp;
3593        int status = ENOERR;
3594
3595        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3596        {
3597                const int lstatus = ncx_get_short_longlong(xp, tp);
3598                if(lstatus != ENOERR)
3599                        status = lstatus;
3600        }
3601
3602        if(rndup != 0)
3603                xp += X_SIZEOF_SHORT;
3604               
3605        *xpp = (void *)xp;
3606        return status;
3607}
3608
3609int
3610ncx_pad_getn_short_ulonglong(const void **xpp, size_t nelems, ulonglong *tp)
3611{
3612        const size_t rndup = nelems % 2;
3613
3614        const char *xp = (const char *) *xpp;
3615        int status = ENOERR;
3616
3617        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3618        {
3619                const int lstatus = ncx_get_short_ulonglong(xp, tp);
3620                if(lstatus != ENOERR)
3621                        status = lstatus;
3622        }
3623
3624        if(rndup != 0)
3625                xp += X_SIZEOF_SHORT;
3626               
3627        *xpp = (void *)xp;
3628        return status;
3629}
3630
3631
3632int
3633ncx_putn_short_schar(void **xpp, size_t nelems, const schar *tp)
3634{
3635#if _SX && \
3636           X_SIZEOF_SHORT == SIZEOF_SHORT
3637
3638 /* basic algorithm is:
3639  *   - ensure sane alignment of output data
3640  *   - copy (conversion happens automatically) input data
3641  *     to output
3642  *   - update tp to point at next unconverted input, and xpp to point
3643  *     at next location for converted output
3644  */
3645  long i, j, ni;
3646  short tmp[LOOPCNT];        /* in case input is misaligned */
3647  short *xp;
3648  int nrange = 0;         /* number of range errors */
3649  int realign = 0;        /* "do we need to fix input data alignment?" */
3650  long cxp = (long) *((char**)xpp);
3651
3652  realign = (cxp & 7) % SIZEOF_SHORT;
3653  /* sjl: manually stripmine so we can limit amount of
3654   * vector work space reserved to LOOPCNT elements. Also
3655   * makes vectorisation easy */
3656  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
3657    ni=Min(nelems-j,LOOPCNT);
3658    if (realign) {
3659      xp = tmp;
3660    } else {
3661      xp = (short *) *xpp;
3662    }
3663   /* copy the next block */
3664#pragma cdir loopcnt=LOOPCNT
3665#pragma cdir shortloop
3666    for (i=0; i<ni; i++) {
3667      /* the normal case: */
3668      xp[i] = (short) Max( X_SHORT_MIN, Min(X_SHORT_MAX, (short) tp[i]));
3669     /* test for range errors (not always needed but do it anyway) */
3670      nrange += tp[i] < X_SHORT_MIN || tp[i] > X_SHORT_MAX;
3671    }
3672   /* copy workspace back if necessary */ 
3673    if (realign) {
3674      memcpy(*xpp, tmp, ni*X_SIZEOF_SHORT);
3675      xp = (short *) *xpp;
3676    }
3677   /* update xpp and tp */
3678    xp += ni;
3679    tp += ni;
3680    *xpp = (void*)xp;
3681  }
3682  return nrange == 0 ? ENOERR : NC_ERANGE;
3683
3684#else   /* not SX */
3685
3686        char *xp = (char *) *xpp;
3687        int status = ENOERR;
3688
3689        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3690        {
3691                int lstatus = ncx_put_short_schar(xp, tp);
3692                if(lstatus != ENOERR)
3693                        status = lstatus;
3694        }
3695
3696        *xpp = (void *)xp;
3697        return status;
3698#endif
3699}
3700
3701int
3702ncx_putn_short_uchar(void **xpp, size_t nelems, const uchar *tp)
3703{
3704#if _SX && \
3705           X_SIZEOF_SHORT == SIZEOF_SHORT
3706
3707 /* basic algorithm is:
3708  *   - ensure sane alignment of output data
3709  *   - copy (conversion happens automatically) input data
3710  *     to output
3711  *   - update tp to point at next unconverted input, and xpp to point
3712  *     at next location for converted output
3713  */
3714  long i, j, ni;
3715  short tmp[LOOPCNT];        /* in case input is misaligned */
3716  short *xp;
3717  int nrange = 0;         /* number of range errors */
3718  int realign = 0;        /* "do we need to fix input data alignment?" */
3719  long cxp = (long) *((char**)xpp);
3720
3721  realign = (cxp & 7) % SIZEOF_SHORT;
3722  /* sjl: manually stripmine so we can limit amount of
3723   * vector work space reserved to LOOPCNT elements. Also
3724   * makes vectorisation easy */
3725  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
3726    ni=Min(nelems-j,LOOPCNT);
3727    if (realign) {
3728      xp = tmp;
3729    } else {
3730      xp = (short *) *xpp;
3731    }
3732   /* copy the next block */
3733#pragma cdir loopcnt=LOOPCNT
3734#pragma cdir shortloop
3735    for (i=0; i<ni; i++) {
3736      /* the normal case: */
3737      xp[i] = (short) Max( X_SHORT_MIN, Min(X_SHORT_MAX, (short) tp[i]));
3738     /* test for range errors (not always needed but do it anyway) */
3739      nrange += tp[i] < X_SHORT_MIN || tp[i] > X_SHORT_MAX;
3740    }
3741   /* copy workspace back if necessary */ 
3742    if (realign) {
3743      memcpy(*xpp, tmp, ni*X_SIZEOF_SHORT);
3744      xp = (short *) *xpp;
3745    }
3746   /* update xpp and tp */
3747    xp += ni;
3748    tp += ni;
3749    *xpp = (void*)xp;
3750  }
3751  return nrange == 0 ? ENOERR : NC_ERANGE;
3752
3753#else   /* not SX */
3754
3755        char *xp = (char *) *xpp;
3756        int status = ENOERR;
3757
3758        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3759        {
3760                int lstatus = ncx_put_short_uchar(xp, tp);
3761                if(lstatus != ENOERR)
3762                        status = lstatus;
3763        }
3764
3765        *xpp = (void *)xp;
3766        return status;
3767#endif
3768}
3769
3770#if X_SIZEOF_SHORT == SIZEOF_SHORT
3771/* optimized version */
3772int
3773ncx_putn_short_short(void **xpp, size_t nelems, const short *tp)
3774{
3775#ifdef WORDS_BIGENDIAN
3776        (void) memcpy(*xpp, tp, nelems * X_SIZEOF_SHORT);
3777# else
3778        swapn2b(*xpp, tp, nelems);
3779# endif
3780        *xpp = (void *)((char *)(*xpp) + nelems * X_SIZEOF_SHORT);
3781        return ENOERR;
3782}
3783#else
3784int
3785ncx_putn_short_short(void **xpp, size_t nelems, const short *tp)
3786{
3787#if _SX && \
3788           X_SIZEOF_SHORT == SIZEOF_SHORT
3789
3790 /* basic algorithm is:
3791  *   - ensure sane alignment of output data
3792  *   - copy (conversion happens automatically) input data
3793  *     to output
3794  *   - update tp to point at next unconverted input, and xpp to point
3795  *     at next location for converted output
3796  */
3797  long i, j, ni;
3798  short tmp[LOOPCNT];        /* in case input is misaligned */
3799  short *xp;
3800  int nrange = 0;         /* number of range errors */
3801  int realign = 0;        /* "do we need to fix input data alignment?" */
3802  long cxp = (long) *((char**)xpp);
3803
3804  realign = (cxp & 7) % SIZEOF_SHORT;
3805  /* sjl: manually stripmine so we can limit amount of
3806   * vector work space reserved to LOOPCNT elements. Also
3807   * makes vectorisation easy */
3808  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
3809    ni=Min(nelems-j,LOOPCNT);
3810    if (realign) {
3811      xp = tmp;
3812    } else {
3813      xp = (short *) *xpp;
3814    }
3815   /* copy the next block */
3816#pragma cdir loopcnt=LOOPCNT
3817#pragma cdir shortloop
3818    for (i=0; i<ni; i++) {
3819      /* the normal case: */
3820      xp[i] = (short) Max( X_SHORT_MIN, Min(X_SHORT_MAX, (short) tp[i]));
3821     /* test for range errors (not always needed but do it anyway) */
3822      nrange += tp[i] < X_SHORT_MIN || tp[i] > X_SHORT_MAX;
3823    }
3824   /* copy workspace back if necessary */ 
3825    if (realign) {
3826      memcpy(*xpp, tmp, ni*X_SIZEOF_SHORT);
3827      xp = (short *) *xpp;
3828    }
3829   /* update xpp and tp */
3830    xp += ni;
3831    tp += ni;
3832    *xpp = (void*)xp;
3833  }
3834  return nrange == 0 ? ENOERR : NC_ERANGE;
3835
3836#else   /* not SX */
3837
3838        char *xp = (char *) *xpp;
3839        int status = ENOERR;
3840
3841        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3842        {
3843                int lstatus = ncx_put_short_short(xp, tp);
3844                if(lstatus != ENOERR)
3845                        status = lstatus;
3846        }
3847
3848        *xpp = (void *)xp;
3849        return status;
3850#endif
3851}
3852
3853#endif
3854int
3855ncx_putn_short_int(void **xpp, size_t nelems, const int *tp)
3856{
3857#if _SX && \
3858           X_SIZEOF_SHORT == SIZEOF_SHORT
3859
3860 /* basic algorithm is:
3861  *   - ensure sane alignment of output data
3862  *   - copy (conversion happens automatically) input data
3863  *     to output
3864  *   - update tp to point at next unconverted input, and xpp to point
3865  *     at next location for converted output
3866  */
3867  long i, j, ni;
3868  short tmp[LOOPCNT];        /* in case input is misaligned */
3869  short *xp;
3870  int nrange = 0;         /* number of range errors */
3871  int realign = 0;        /* "do we need to fix input data alignment?" */
3872  long cxp = (long) *((char**)xpp);
3873
3874  realign = (cxp & 7) % SIZEOF_SHORT;
3875  /* sjl: manually stripmine so we can limit amount of
3876   * vector work space reserved to LOOPCNT elements. Also
3877   * makes vectorisation easy */
3878  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
3879    ni=Min(nelems-j,LOOPCNT);
3880    if (realign) {
3881      xp = tmp;
3882    } else {
3883      xp = (short *) *xpp;
3884    }
3885   /* copy the next block */
3886#pragma cdir loopcnt=LOOPCNT
3887#pragma cdir shortloop
3888    for (i=0; i<ni; i++) {
3889      /* the normal case: */
3890      xp[i] = (short) Max( X_SHORT_MIN, Min(X_SHORT_MAX, (short) tp[i]));
3891     /* test for range errors (not always needed but do it anyway) */
3892      nrange += tp[i] < X_SHORT_MIN || tp[i] > X_SHORT_MAX;
3893    }
3894   /* copy workspace back if necessary */ 
3895    if (realign) {
3896      memcpy(*xpp, tmp, ni*X_SIZEOF_SHORT);
3897      xp = (short *) *xpp;
3898    }
3899   /* update xpp and tp */
3900    xp += ni;
3901    tp += ni;
3902    *xpp = (void*)xp;
3903  }
3904  return nrange == 0 ? ENOERR : NC_ERANGE;
3905
3906#else   /* not SX */
3907
3908        char *xp = (char *) *xpp;
3909        int status = ENOERR;
3910
3911        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3912        {
3913                int lstatus = ncx_put_short_int(xp, tp);
3914                if(lstatus != ENOERR)
3915                        status = lstatus;
3916        }
3917
3918        *xpp = (void *)xp;
3919        return status;
3920#endif
3921}
3922
3923int
3924ncx_putn_short_float(void **xpp, size_t nelems, const float *tp)
3925{
3926#if _SX && \
3927           X_SIZEOF_SHORT == SIZEOF_SHORT
3928
3929 /* basic algorithm is:
3930  *   - ensure sane alignment of output data
3931  *   - copy (conversion happens automatically) input data
3932  *     to output
3933  *   - update tp to point at next unconverted input, and xpp to point
3934  *     at next location for converted output
3935  */
3936  long i, j, ni;
3937  short tmp[LOOPCNT];        /* in case input is misaligned */
3938  short *xp;
3939  int nrange = 0;         /* number of range errors */
3940  int realign = 0;        /* "do we need to fix input data alignment?" */
3941  long cxp = (long) *((char**)xpp);
3942
3943  realign = (cxp & 7) % SIZEOF_SHORT;
3944  /* sjl: manually stripmine so we can limit amount of
3945   * vector work space reserved to LOOPCNT elements. Also
3946   * makes vectorisation easy */
3947  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
3948    ni=Min(nelems-j,LOOPCNT);
3949    if (realign) {
3950      xp = tmp;
3951    } else {
3952      xp = (short *) *xpp;
3953    }
3954   /* copy the next block */
3955#pragma cdir loopcnt=LOOPCNT
3956#pragma cdir shortloop
3957    for (i=0; i<ni; i++) {
3958      /* the normal case: */
3959      xp[i] = (short) Max( X_SHORT_MIN, Min(X_SHORT_MAX, (short) tp[i]));
3960     /* test for range errors (not always needed but do it anyway) */
3961      nrange += tp[i] < X_SHORT_MIN || tp[i] > X_SHORT_MAX;
3962    }
3963   /* copy workspace back if necessary */ 
3964    if (realign) {
3965      memcpy(*xpp, tmp, ni*X_SIZEOF_SHORT);
3966      xp = (short *) *xpp;
3967    }
3968   /* update xpp and tp */
3969    xp += ni;
3970    tp += ni;
3971    *xpp = (void*)xp;
3972  }
3973  return nrange == 0 ? ENOERR : NC_ERANGE;
3974
3975#else   /* not SX */
3976
3977        char *xp = (char *) *xpp;
3978        int status = ENOERR;
3979
3980        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
3981        {
3982                int lstatus = ncx_put_short_float(xp, tp);
3983                if(lstatus != ENOERR)
3984                        status = lstatus;
3985        }
3986
3987        *xpp = (void *)xp;
3988        return status;
3989#endif
3990}
3991
3992int
3993ncx_putn_short_double(void **xpp, size_t nelems, const double *tp)
3994{
3995#if _SX && \
3996           X_SIZEOF_SHORT == SIZEOF_SHORT
3997
3998 /* basic algorithm is:
3999  *   - ensure sane alignment of output data
4000  *   - copy (conversion happens automatically) input data
4001  *     to output
4002  *   - update tp to point at next unconverted input, and xpp to point
4003  *     at next location for converted output
4004  */
4005  long i, j, ni;
4006  short tmp[LOOPCNT];        /* in case input is misaligned */
4007  short *xp;
4008  int nrange = 0;         /* number of range errors */
4009  int realign = 0;        /* "do we need to fix input data alignment?" */
4010  long cxp = (long) *((char**)xpp);
4011
4012  realign = (cxp & 7) % SIZEOF_SHORT;
4013  /* sjl: manually stripmine so we can limit amount of
4014   * vector work space reserved to LOOPCNT elements. Also
4015   * makes vectorisation easy */
4016  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
4017    ni=Min(nelems-j,LOOPCNT);
4018    if (realign) {
4019      xp = tmp;
4020    } else {
4021      xp = (short *) *xpp;
4022    }
4023   /* copy the next block */
4024#pragma cdir loopcnt=LOOPCNT
4025#pragma cdir shortloop
4026    for (i=0; i<ni; i++) {
4027      /* the normal case: */
4028      xp[i] = (short) Max( X_SHORT_MIN, Min(X_SHORT_MAX, (short) tp[i]));
4029     /* test for range errors (not always needed but do it anyway) */
4030      nrange += tp[i] < X_SHORT_MIN || tp[i] > X_SHORT_MAX;
4031    }
4032   /* copy workspace back if necessary */ 
4033    if (realign) {
4034      memcpy(*xpp, tmp, ni*X_SIZEOF_SHORT);
4035      xp = (short *) *xpp;
4036    }
4037   /* update xpp and tp */
4038    xp += ni;
4039    tp += ni;
4040    *xpp = (void*)xp;
4041  }
4042  return nrange == 0 ? ENOERR : NC_ERANGE;
4043
4044#else   /* not SX */
4045
4046        char *xp = (char *) *xpp;
4047        int status = ENOERR;
4048
4049        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
4050        {
4051                int lstatus = ncx_put_short_double(xp, tp);
4052                if(lstatus != ENOERR)
4053                        status = lstatus;
4054        }
4055
4056        *xpp = (void *)xp;
4057        return status;
4058#endif
4059}
4060
4061int
4062ncx_putn_short_uint(void **xpp, size_t nelems, const uint *tp)
4063{
4064#if _SX && \
4065           X_SIZEOF_SHORT == SIZEOF_SHORT
4066
4067 /* basic algorithm is:
4068  *   - ensure sane alignment of output data
4069  *   - copy (conversion happens automatically) input data
4070  *     to output
4071  *   - update tp to point at next unconverted input, and xpp to point
4072  *     at next location for converted output
4073  */
4074  long i, j, ni;
4075  short tmp[LOOPCNT];        /* in case input is misaligned */
4076  short *xp;
4077  int nrange = 0;         /* number of range errors */
4078  int realign = 0;        /* "do we need to fix input data alignment?" */
4079  long cxp = (long) *((char**)xpp);
4080
4081  realign = (cxp & 7) % SIZEOF_SHORT;
4082  /* sjl: manually stripmine so we can limit amount of
4083   * vector work space reserved to LOOPCNT elements. Also
4084   * makes vectorisation easy */
4085  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
4086    ni=Min(nelems-j,LOOPCNT);
4087    if (realign) {
4088      xp = tmp;
4089    } else {
4090      xp = (short *) *xpp;
4091    }
4092   /* copy the next block */
4093#pragma cdir loopcnt=LOOPCNT
4094#pragma cdir shortloop
4095    for (i=0; i<ni; i++) {
4096      /* the normal case: */
4097      xp[i] = (short) Max( X_SHORT_MIN, Min(X_SHORT_MAX, (short) tp[i]));
4098     /* test for range errors (not always needed but do it anyway) */
4099      nrange += tp[i] < X_SHORT_MIN || tp[i] > X_SHORT_MAX;
4100    }
4101   /* copy workspace back if necessary */ 
4102    if (realign) {
4103      memcpy(*xpp, tmp, ni*X_SIZEOF_SHORT);
4104      xp = (short *) *xpp;
4105    }
4106   /* update xpp and tp */
4107    xp += ni;
4108    tp += ni;
4109    *xpp = (void*)xp;
4110  }
4111  return nrange == 0 ? ENOERR : NC_ERANGE;
4112
4113#else   /* not SX */
4114
4115        char *xp = (char *) *xpp;
4116        int status = ENOERR;
4117
4118        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
4119        {
4120                int lstatus = ncx_put_short_uint(xp, tp);
4121                if(lstatus != ENOERR)
4122                        status = lstatus;
4123        }
4124
4125        *xpp = (void *)xp;
4126        return status;
4127#endif
4128}
4129
4130int
4131ncx_putn_short_longlong(void **xpp, size_t nelems, const longlong *tp)
4132{
4133#if _SX && \
4134           X_SIZEOF_SHORT == SIZEOF_SHORT
4135
4136 /* basic algorithm is:
4137  *   - ensure sane alignment of output data
4138  *   - copy (conversion happens automatically) input data
4139  *     to output
4140  *   - update tp to point at next unconverted input, and xpp to point
4141  *     at next location for converted output
4142  */
4143  long i, j, ni;
4144  short tmp[LOOPCNT];        /* in case input is misaligned */
4145  short *xp;
4146  int nrange = 0;         /* number of range errors */
4147  int realign = 0;        /* "do we need to fix input data alignment?" */
4148  long cxp = (long) *((char**)xpp);
4149
4150  realign = (cxp & 7) % SIZEOF_SHORT;
4151  /* sjl: manually stripmine so we can limit amount of
4152   * vector work space reserved to LOOPCNT elements. Also
4153   * makes vectorisation easy */
4154  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
4155    ni=Min(nelems-j,LOOPCNT);
4156    if (realign) {
4157      xp = tmp;
4158    } else {
4159      xp = (short *) *xpp;
4160    }
4161   /* copy the next block */
4162#pragma cdir loopcnt=LOOPCNT
4163#pragma cdir shortloop
4164    for (i=0; i<ni; i++) {
4165      /* the normal case: */
4166      xp[i] = (short) Max( X_SHORT_MIN, Min(X_SHORT_MAX, (short) tp[i]));
4167     /* test for range errors (not always needed but do it anyway) */
4168      nrange += tp[i] < X_SHORT_MIN || tp[i] > X_SHORT_MAX;
4169    }
4170   /* copy workspace back if necessary */ 
4171    if (realign) {
4172      memcpy(*xpp, tmp, ni*X_SIZEOF_SHORT);
4173      xp = (short *) *xpp;
4174    }
4175   /* update xpp and tp */
4176    xp += ni;
4177    tp += ni;
4178    *xpp = (void*)xp;
4179  }
4180  return nrange == 0 ? ENOERR : NC_ERANGE;
4181
4182#else   /* not SX */
4183
4184        char *xp = (char *) *xpp;
4185        int status = ENOERR;
4186
4187        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
4188        {
4189                int lstatus = ncx_put_short_longlong(xp, tp);
4190                if(lstatus != ENOERR)
4191                        status = lstatus;
4192        }
4193
4194        *xpp = (void *)xp;
4195        return status;
4196#endif
4197}
4198
4199int
4200ncx_putn_short_ulonglong(void **xpp, size_t nelems, const ulonglong *tp)
4201{
4202#if _SX && \
4203           X_SIZEOF_SHORT == SIZEOF_SHORT
4204
4205 /* basic algorithm is:
4206  *   - ensure sane alignment of output data
4207  *   - copy (conversion happens automatically) input data
4208  *     to output
4209  *   - update tp to point at next unconverted input, and xpp to point
4210  *     at next location for converted output
4211  */
4212  long i, j, ni;
4213  short tmp[LOOPCNT];        /* in case input is misaligned */
4214  short *xp;
4215  int nrange = 0;         /* number of range errors */
4216  int realign = 0;        /* "do we need to fix input data alignment?" */
4217  long cxp = (long) *((char**)xpp);
4218
4219  realign = (cxp & 7) % SIZEOF_SHORT;
4220  /* sjl: manually stripmine so we can limit amount of
4221   * vector work space reserved to LOOPCNT elements. Also
4222   * makes vectorisation easy */
4223  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
4224    ni=Min(nelems-j,LOOPCNT);
4225    if (realign) {
4226      xp = tmp;
4227    } else {
4228      xp = (short *) *xpp;
4229    }
4230   /* copy the next block */
4231#pragma cdir loopcnt=LOOPCNT
4232#pragma cdir shortloop
4233    for (i=0; i<ni; i++) {
4234      /* the normal case: */
4235      xp[i] = (short) Max( X_SHORT_MIN, Min(X_SHORT_MAX, (short) tp[i]));
4236     /* test for range errors (not always needed but do it anyway) */
4237      nrange += tp[i] < X_SHORT_MIN || tp[i] > X_SHORT_MAX;
4238    }
4239   /* copy workspace back if necessary */ 
4240    if (realign) {
4241      memcpy(*xpp, tmp, ni*X_SIZEOF_SHORT);
4242      xp = (short *) *xpp;
4243    }
4244   /* update xpp and tp */
4245    xp += ni;
4246    tp += ni;
4247    *xpp = (void*)xp;
4248  }
4249  return nrange == 0 ? ENOERR : NC_ERANGE;
4250
4251#else   /* not SX */
4252
4253        char *xp = (char *) *xpp;
4254        int status = ENOERR;
4255
4256        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
4257        {
4258                int lstatus = ncx_put_short_ulonglong(xp, tp);
4259                if(lstatus != ENOERR)
4260                        status = lstatus;
4261        }
4262
4263        *xpp = (void *)xp;
4264        return status;
4265#endif
4266}
4267
4268
4269int
4270ncx_pad_putn_short_schar(void **xpp, size_t nelems, const schar *tp)
4271{
4272        const size_t rndup = nelems % 2;
4273
4274        char *xp = (char *) *xpp;
4275        int status = ENOERR;
4276
4277        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
4278        {
4279                int lstatus = ncx_put_short_schar(xp, tp);
4280                if(lstatus != ENOERR)
4281                        status = lstatus;
4282        }
4283
4284        if(rndup != 0)
4285        {
4286                (void) memcpy(xp, nada, X_SIZEOF_SHORT);
4287                xp += X_SIZEOF_SHORT;   
4288        }
4289               
4290        *xpp = (void *)xp;
4291        return status;
4292}
4293
4294int
4295ncx_pad_putn_short_uchar(void **xpp, size_t nelems, const uchar *tp)
4296{
4297        const size_t rndup = nelems % 2;
4298
4299        char *xp = (char *) *xpp;
4300        int status = ENOERR;
4301
4302        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
4303        {
4304                int lstatus = ncx_put_short_uchar(xp, tp);
4305                if(lstatus != ENOERR)
4306                        status = lstatus;
4307        }
4308
4309        if(rndup != 0)
4310        {
4311                (void) memcpy(xp, nada, X_SIZEOF_SHORT);
4312                xp += X_SIZEOF_SHORT;   
4313        }
4314               
4315        *xpp = (void *)xp;
4316        return status;
4317}
4318
4319int
4320ncx_pad_putn_short_short(void **xpp, size_t nelems, const short *tp)
4321{
4322        const size_t rndup = nelems % 2;
4323
4324        char *xp = (char *) *xpp;
4325        int status = ENOERR;
4326
4327        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
4328        {
4329                int lstatus = ncx_put_short_short(xp, tp);
4330                if(lstatus != ENOERR)
4331                        status = lstatus;
4332        }
4333
4334        if(rndup != 0)
4335        {
4336                (void) memcpy(xp, nada, X_SIZEOF_SHORT);
4337                xp += X_SIZEOF_SHORT;   
4338        }
4339               
4340        *xpp = (void *)xp;
4341        return status;
4342}
4343
4344int
4345ncx_pad_putn_short_int(void **xpp, size_t nelems, const int *tp)
4346{
4347        const size_t rndup = nelems % 2;
4348
4349        char *xp = (char *) *xpp;
4350        int status = ENOERR;
4351
4352        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
4353        {
4354                int lstatus = ncx_put_short_int(xp, tp);
4355                if(lstatus != ENOERR)
4356                        status = lstatus;
4357        }
4358
4359        if(rndup != 0)
4360        {
4361                (void) memcpy(xp, nada, X_SIZEOF_SHORT);
4362                xp += X_SIZEOF_SHORT;   
4363        }
4364               
4365        *xpp = (void *)xp;
4366        return status;
4367}
4368
4369int
4370ncx_pad_putn_short_float(void **xpp, size_t nelems, const float *tp)
4371{
4372        const size_t rndup = nelems % 2;
4373
4374        char *xp = (char *) *xpp;
4375        int status = ENOERR;
4376
4377        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
4378        {
4379                int lstatus = ncx_put_short_float(xp, tp);
4380                if(lstatus != ENOERR)
4381                        status = lstatus;
4382        }
4383
4384        if(rndup != 0)
4385        {
4386                (void) memcpy(xp, nada, X_SIZEOF_SHORT);
4387                xp += X_SIZEOF_SHORT;   
4388        }
4389               
4390        *xpp = (void *)xp;
4391        return status;
4392}
4393
4394int
4395ncx_pad_putn_short_double(void **xpp, size_t nelems, const double *tp)
4396{
4397        const size_t rndup = nelems % 2;
4398
4399        char *xp = (char *) *xpp;
4400        int status = ENOERR;
4401
4402        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
4403        {
4404                int lstatus = ncx_put_short_double(xp, tp);
4405                if(lstatus != ENOERR)
4406                        status = lstatus;
4407        }
4408
4409        if(rndup != 0)
4410        {
4411                (void) memcpy(xp, nada, X_SIZEOF_SHORT);
4412                xp += X_SIZEOF_SHORT;   
4413        }
4414               
4415        *xpp = (void *)xp;
4416        return status;
4417}
4418
4419int
4420ncx_pad_putn_short_uint(void **xpp, size_t nelems, const uint *tp)
4421{
4422        const size_t rndup = nelems % 2;
4423
4424        char *xp = (char *) *xpp;
4425        int status = ENOERR;
4426
4427        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
4428        {
4429                int lstatus = ncx_put_short_uint(xp, tp);
4430                if(lstatus != ENOERR)
4431                        status = lstatus;
4432        }
4433
4434        if(rndup != 0)
4435        {
4436                (void) memcpy(xp, nada, X_SIZEOF_SHORT);
4437                xp += X_SIZEOF_SHORT;   
4438        }
4439               
4440        *xpp = (void *)xp;
4441        return status;
4442}
4443
4444int
4445ncx_pad_putn_short_longlong(void **xpp, size_t nelems, const longlong *tp)
4446{
4447        const size_t rndup = nelems % 2;
4448
4449        char *xp = (char *) *xpp;
4450        int status = ENOERR;
4451
4452        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
4453        {
4454                int lstatus = ncx_put_short_longlong(xp, tp);
4455                if(lstatus != ENOERR)
4456                        status = lstatus;
4457        }
4458
4459        if(rndup != 0)
4460        {
4461                (void) memcpy(xp, nada, X_SIZEOF_SHORT);
4462                xp += X_SIZEOF_SHORT;   
4463        }
4464               
4465        *xpp = (void *)xp;
4466        return status;
4467}
4468
4469int
4470ncx_pad_putn_short_ulonglong(void **xpp, size_t nelems, const ulonglong *tp)
4471{
4472        const size_t rndup = nelems % 2;
4473
4474        char *xp = (char *) *xpp;
4475        int status = ENOERR;
4476
4477        for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++)
4478        {
4479                int lstatus = ncx_put_short_ulonglong(xp, tp);
4480                if(lstatus != ENOERR)
4481                        status = lstatus;
4482        }
4483
4484        if(rndup != 0)
4485        {
4486                (void) memcpy(xp, nada, X_SIZEOF_SHORT);
4487                xp += X_SIZEOF_SHORT;   
4488        }
4489               
4490        *xpp = (void *)xp;
4491        return status;
4492}
4493
4494
4495
4496/* int */
4497
4498int
4499ncx_getn_int_schar(const void **xpp, size_t nelems, schar *tp)
4500{
4501#if _SX && \
4502           X_SIZEOF_INT == SIZEOF_INT
4503
4504 /* basic algorithm is:
4505  *   - ensure sane alignment of input data
4506  *   - copy (conversion happens automatically) input data
4507  *     to output
4508  *   - update xpp to point at next unconverted input, and tp to point
4509  *     at next location for converted output
4510  */
4511  long i, j, ni;
4512  int tmp[LOOPCNT];        /* in case input is misaligned */
4513  int *xp;
4514  int nrange = 0;         /* number of range errors */
4515  int realign = 0;        /* "do we need to fix input data alignment?" */
4516  long cxp = (long) *((char**)xpp);
4517
4518  realign = (cxp & 7) % SIZEOF_INT;
4519  /* sjl: manually stripmine so we can limit amount of
4520   * vector work space reserved to LOOPCNT elements. Also
4521   * makes vectorisation easy */
4522  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
4523    ni=Min(nelems-j,LOOPCNT);
4524    if (realign) {
4525      memcpy(tmp, *xpp, ni*SIZEOF_INT);
4526      xp = tmp;
4527    } else {
4528      xp = (int *) *xpp;
4529    }
4530   /* copy the next block */
4531#pragma cdir loopcnt=LOOPCNT
4532#pragma cdir shortloop
4533    for (i=0; i<ni; i++) {
4534      tp[i] = (schar) Max( SCHAR_MIN, Min(SCHAR_MAX, (schar) xp[i]));
4535     /* test for range errors (not always needed but do it anyway) */
4536      nrange += xp[i] < SCHAR_MIN || xp[i] > SCHAR_MAX;
4537    }
4538   /* update xpp and tp */
4539    if (realign) xp = (int *) *xpp;
4540    xp += ni;
4541    tp += ni;
4542    *xpp = (void*)xp;
4543  }
4544  return nrange == 0 ? ENOERR : NC_ERANGE;
4545
4546#else   /* not SX */
4547        const char *xp = (const char *) *xpp;
4548        int status = ENOERR;
4549
4550        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
4551        {
4552                const int lstatus = ncx_get_int_schar(xp, tp);
4553                if(lstatus != ENOERR)
4554                        status = lstatus;
4555        }
4556
4557        *xpp = (const void *)xp;
4558        return status;
4559#  endif
4560}
4561
4562int
4563ncx_getn_int_uchar(const void **xpp, size_t nelems, uchar *tp)
4564{
4565#if _SX && \
4566           X_SIZEOF_INT == SIZEOF_INT
4567
4568 /* basic algorithm is:
4569  *   - ensure sane alignment of input data
4570  *   - copy (conversion happens automatically) input data
4571  *     to output
4572  *   - update xpp to point at next unconverted input, and tp to point
4573  *     at next location for converted output
4574  */
4575  long i, j, ni;
4576  int tmp[LOOPCNT];        /* in case input is misaligned */
4577  int *xp;
4578  int nrange = 0;         /* number of range errors */
4579  int realign = 0;        /* "do we need to fix input data alignment?" */
4580  long cxp = (long) *((char**)xpp);
4581
4582  realign = (cxp & 7) % SIZEOF_INT;
4583  /* sjl: manually stripmine so we can limit amount of
4584   * vector work space reserved to LOOPCNT elements. Also
4585   * makes vectorisation easy */
4586  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
4587    ni=Min(nelems-j,LOOPCNT);
4588    if (realign) {
4589      memcpy(tmp, *xpp, ni*SIZEOF_INT);
4590      xp = tmp;
4591    } else {
4592      xp = (int *) *xpp;
4593    }
4594   /* copy the next block */
4595#pragma cdir loopcnt=LOOPCNT
4596#pragma cdir shortloop
4597    for (i=0; i<ni; i++) {
4598      tp[i] = (uchar) Max( UCHAR_MIN, Min(UCHAR_MAX, (uchar) xp[i]));
4599     /* test for range errors (not always needed but do it anyway) */
4600      nrange += xp[i] < UCHAR_MIN || xp[i] > UCHAR_MAX;
4601    }
4602   /* update xpp and tp */
4603    if (realign) xp = (int *) *xpp;
4604    xp += ni;
4605    tp += ni;
4606    *xpp = (void*)xp;
4607  }
4608  return nrange == 0 ? ENOERR : NC_ERANGE;
4609
4610#else   /* not SX */
4611        const char *xp = (const char *) *xpp;
4612        int status = ENOERR;
4613
4614        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
4615        {
4616                const int lstatus = ncx_get_int_uchar(xp, tp);
4617                if(lstatus != ENOERR)
4618                        status = lstatus;
4619        }
4620
4621        *xpp = (const void *)xp;
4622        return status;
4623#  endif
4624}
4625
4626int
4627ncx_getn_int_short(const void **xpp, size_t nelems, short *tp)
4628{
4629#if _SX && \
4630           X_SIZEOF_INT == SIZEOF_INT
4631
4632 /* basic algorithm is:
4633  *   - ensure sane alignment of input data
4634  *   - copy (conversion happens automatically) input data
4635  *     to output
4636  *   - update xpp to point at next unconverted input, and tp to point
4637  *     at next location for converted output
4638  */
4639  long i, j, ni;
4640  int tmp[LOOPCNT];        /* in case input is misaligned */
4641  int *xp;
4642  int nrange = 0;         /* number of range errors */
4643  int realign = 0;        /* "do we need to fix input data alignment?" */
4644  long cxp = (long) *((char**)xpp);
4645
4646  realign = (cxp & 7) % SIZEOF_INT;
4647  /* sjl: manually stripmine so we can limit amount of
4648   * vector work space reserved to LOOPCNT elements. Also
4649   * makes vectorisation easy */
4650  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
4651    ni=Min(nelems-j,LOOPCNT);
4652    if (realign) {
4653      memcpy(tmp, *xpp, ni*SIZEOF_INT);
4654      xp = tmp;
4655    } else {
4656      xp = (int *) *xpp;
4657    }
4658   /* copy the next block */
4659#pragma cdir loopcnt=LOOPCNT
4660#pragma cdir shortloop
4661    for (i=0; i<ni; i++) {
4662      tp[i] = (short) Max( SHORT_MIN, Min(SHORT_MAX, (short) xp[i]));
4663     /* test for range errors (not always needed but do it anyway) */
4664      nrange += xp[i] < SHORT_MIN || xp[i] > SHORT_MAX;
4665    }
4666   /* update xpp and tp */
4667    if (realign) xp = (int *) *xpp;
4668    xp += ni;
4669    tp += ni;
4670    *xpp = (void*)xp;
4671  }
4672  return nrange == 0 ? ENOERR : NC_ERANGE;
4673
4674#else   /* not SX */
4675        const char *xp = (const char *) *xpp;
4676        int status = ENOERR;
4677
4678        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
4679        {
4680                const int lstatus = ncx_get_int_short(xp, tp);
4681                if(lstatus != ENOERR)
4682                        status = lstatus;
4683        }
4684
4685        *xpp = (const void *)xp;
4686        return status;
4687#  endif
4688}
4689
4690#if X_SIZEOF_INT == SIZEOF_INT
4691/* optimized version */
4692int
4693ncx_getn_int_int(const void **xpp, size_t nelems, int *tp)
4694{
4695#ifdef WORDS_BIGENDIAN
4696        (void) memcpy(tp, *xpp, nelems * sizeof(int));
4697# else
4698        swapn4b(tp, *xpp, nelems);
4699# endif
4700        *xpp = (const void *)((const char *)(*xpp) + nelems * X_SIZEOF_INT);
4701        return ENOERR;
4702}
4703int
4704ncx_getn_int_uint(const void **xpp, size_t nelems, unsigned int *tp)
4705{
4706#ifdef WORDS_BIGENDIAN
4707        (void) memcpy(tp, *xpp, nelems * sizeof(int));
4708# else
4709        swapn4b(tp, *xpp, nelems);
4710# endif
4711        *xpp = (const void *)((const char *)(*xpp) + nelems * X_SIZEOF_INT);
4712        return ENOERR;
4713}
4714#else
4715int
4716ncx_getn_int_int(const void **xpp, size_t nelems, int *tp)
4717{
4718#if _SX && \
4719           X_SIZEOF_INT == SIZEOF_INT
4720
4721 /* basic algorithm is:
4722  *   - ensure sane alignment of input data
4723  *   - copy (conversion happens automatically) input data
4724  *     to output
4725  *   - update xpp to point at next unconverted input, and tp to point
4726  *     at next location for converted output
4727  */
4728  long i, j, ni;
4729  int tmp[LOOPCNT];        /* in case input is misaligned */
4730  int *xp;
4731  int nrange = 0;         /* number of range errors */
4732  int realign = 0;        /* "do we need to fix input data alignment?" */
4733  long cxp = (long) *((char**)xpp);
4734
4735  realign = (cxp & 7) % SIZEOF_INT;
4736  /* sjl: manually stripmine so we can limit amount of
4737   * vector work space reserved to LOOPCNT elements. Also
4738   * makes vectorisation easy */
4739  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
4740    ni=Min(nelems-j,LOOPCNT);
4741    if (realign) {
4742      memcpy(tmp, *xpp, ni*SIZEOF_INT);
4743      xp = tmp;
4744    } else {
4745      xp = (int *) *xpp;
4746    }
4747   /* copy the next block */
4748#pragma cdir loopcnt=LOOPCNT
4749#pragma cdir shortloop
4750    for (i=0; i<ni; i++) {
4751      tp[i] = (int) Max( INT_MIN, Min(INT_MAX, (int) xp[i]));
4752     /* test for range errors (not always needed but do it anyway) */
4753      nrange += xp[i] < INT_MIN || xp[i] > INT_MAX;
4754    }
4755   /* update xpp and tp */
4756    if (realign) xp = (int *) *xpp;
4757    xp += ni;
4758    tp += ni;
4759    *xpp = (void*)xp;
4760  }
4761  return nrange == 0 ? ENOERR : NC_ERANGE;
4762
4763#else   /* not SX */
4764        const char *xp = (const char *) *xpp;
4765        int status = ENOERR;
4766
4767        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
4768        {
4769                const int lstatus = ncx_get_int_int(xp, tp);
4770                if(lstatus != ENOERR)
4771                        status = lstatus;
4772        }
4773
4774        *xpp = (const void *)xp;
4775        return status;
4776#  endif
4777}
4778
4779int
4780ncx_getn_int_uint(const void **xpp, size_t nelems, uint *tp)
4781{
4782#if _SX && \
4783           X_SIZEOF_INT == SIZEOF_INT
4784
4785 /* basic algorithm is:
4786  *   - ensure sane alignment of input data
4787  *   - copy (conversion happens automatically) input data
4788  *     to output
4789  *   - update xpp to point at next unconverted input, and tp to point
4790  *     at next location for converted output
4791  */
4792  long i, j, ni;
4793  int tmp[LOOPCNT];        /* in case input is misaligned */
4794  int *xp;
4795  int nrange = 0;         /* number of range errors */
4796  int realign = 0;        /* "do we need to fix input data alignment?" */
4797  long cxp = (long) *((char**)xpp);
4798
4799  realign = (cxp & 7) % SIZEOF_INT;
4800  /* sjl: manually stripmine so we can limit amount of
4801   * vector work space reserved to LOOPCNT elements. Also
4802   * makes vectorisation easy */
4803  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
4804    ni=Min(nelems-j,LOOPCNT);
4805    if (realign) {
4806      memcpy(tmp, *xpp, ni*SIZEOF_INT);
4807      xp = tmp;
4808    } else {
4809      xp = (int *) *xpp;
4810    }
4811   /* copy the next block */
4812#pragma cdir loopcnt=LOOPCNT
4813#pragma cdir shortloop
4814    for (i=0; i<ni; i++) {
4815      tp[i] = (uint) Max( UINT_MIN, Min(UINT_MAX, (uint) xp[i]));
4816     /* test for range errors (not always needed but do it anyway) */
4817      nrange += xp[i] < UINT_MIN || xp[i] > UINT_MAX;
4818    }
4819   /* update xpp and tp */
4820    if (realign) xp = (int *) *xpp;
4821    xp += ni;
4822    tp += ni;
4823    *xpp = (void*)xp;
4824  }
4825  return nrange == 0 ? ENOERR : NC_ERANGE;
4826
4827#else   /* not SX */
4828        const char *xp = (const char *) *xpp;
4829        int status = ENOERR;
4830
4831        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
4832        {
4833                const int lstatus = ncx_get_int_uint(xp, tp);
4834                if(lstatus != ENOERR)
4835                        status = lstatus;
4836        }
4837
4838        *xpp = (const void *)xp;
4839        return status;
4840#  endif
4841}
4842
4843#endif
4844
4845int
4846ncx_getn_int_longlong(const void **xpp, size_t nelems, longlong *tp)
4847{
4848#if _SX && \
4849           X_SIZEOF_INT == SIZEOF_INT
4850
4851 /* basic algorithm is:
4852  *   - ensure sane alignment of input data
4853  *   - copy (conversion happens automatically) input data
4854  *     to output
4855  *   - update xpp to point at next unconverted input, and tp to point
4856  *     at next location for converted output
4857  */
4858  long i, j, ni;
4859  int tmp[LOOPCNT];        /* in case input is misaligned */
4860  int *xp;
4861  int nrange = 0;         /* number of range errors */
4862  int realign = 0;        /* "do we need to fix input data alignment?" */
4863  long cxp = (long) *((char**)xpp);
4864
4865  realign = (cxp & 7) % SIZEOF_INT;
4866  /* sjl: manually stripmine so we can limit amount of
4867   * vector work space reserved to LOOPCNT elements. Also
4868   * makes vectorisation easy */
4869  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
4870    ni=Min(nelems-j,LOOPCNT);
4871    if (realign) {
4872      memcpy(tmp, *xpp, ni*SIZEOF_INT);
4873      xp = tmp;
4874    } else {
4875      xp = (int *) *xpp;
4876    }
4877   /* copy the next block */
4878#pragma cdir loopcnt=LOOPCNT
4879#pragma cdir shortloop
4880    for (i=0; i<ni; i++) {
4881      tp[i] = (longlong) Max( LONGLONG_MIN, Min(LONGLONG_MAX, (longlong) xp[i]));
4882     /* test for range errors (not always needed but do it anyway) */
4883      nrange += xp[i] < LONGLONG_MIN || xp[i] > LONGLONG_MAX;
4884    }
4885   /* update xpp and tp */
4886    if (realign) xp = (int *) *xpp;
4887    xp += ni;
4888    tp += ni;
4889    *xpp = (void*)xp;
4890  }
4891  return nrange == 0 ? ENOERR : NC_ERANGE;
4892
4893#else   /* not SX */
4894        const char *xp = (const char *) *xpp;
4895        int status = ENOERR;
4896
4897        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
4898        {
4899                const int lstatus = ncx_get_int_longlong(xp, tp);
4900                if(lstatus != ENOERR)
4901                        status = lstatus;
4902        }
4903
4904        *xpp = (const void *)xp;
4905        return status;
4906#  endif
4907}
4908
4909int
4910ncx_getn_int_ulonglong(const void **xpp, size_t nelems, ulonglong *tp)
4911{
4912#if _SX && \
4913           X_SIZEOF_INT == SIZEOF_INT
4914
4915 /* basic algorithm is:
4916  *   - ensure sane alignment of input data
4917  *   - copy (conversion happens automatically) input data
4918  *     to output
4919  *   - update xpp to point at next unconverted input, and tp to point
4920  *     at next location for converted output
4921  */
4922  long i, j, ni;
4923  int tmp[LOOPCNT];        /* in case input is misaligned */
4924  int *xp;
4925  int nrange = 0;         /* number of range errors */
4926  int realign = 0;        /* "do we need to fix input data alignment?" */
4927  long cxp = (long) *((char**)xpp);
4928
4929  realign = (cxp & 7) % SIZEOF_INT;
4930  /* sjl: manually stripmine so we can limit amount of
4931   * vector work space reserved to LOOPCNT elements. Also
4932   * makes vectorisation easy */
4933  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
4934    ni=Min(nelems-j,LOOPCNT);
4935    if (realign) {
4936      memcpy(tmp, *xpp, ni*SIZEOF_INT);
4937      xp = tmp;
4938    } else {
4939      xp = (int *) *xpp;
4940    }
4941   /* copy the next block */
4942#pragma cdir loopcnt=LOOPCNT
4943#pragma cdir shortloop
4944    for (i=0; i<ni; i++) {
4945      tp[i] = (ulonglong) Max( ULONGLONG_MIN, Min(ULONGLONG_MAX, (ulonglong) xp[i]));
4946     /* test for range errors (not always needed but do it anyway) */
4947      nrange += xp[i] < ULONGLONG_MIN || xp[i] > ULONGLONG_MAX;
4948    }
4949   /* update xpp and tp */
4950    if (realign) xp = (int *) *xpp;
4951    xp += ni;
4952    tp += ni;
4953    *xpp = (void*)xp;
4954  }
4955  return nrange == 0 ? ENOERR : NC_ERANGE;
4956
4957#else   /* not SX */
4958        const char *xp = (const char *) *xpp;
4959        int status = ENOERR;
4960
4961        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
4962        {
4963                const int lstatus = ncx_get_int_ulonglong(xp, tp);
4964                if(lstatus != ENOERR)
4965                        status = lstatus;
4966        }
4967
4968        *xpp = (const void *)xp;
4969        return status;
4970#  endif
4971}
4972
4973
4974int
4975ncx_getn_int_float(const void **xpp, size_t nelems, float *tp)
4976{
4977#if _SX && \
4978           X_SIZEOF_INT == SIZEOF_INT
4979
4980 /* basic algorithm is:
4981  *   - ensure sane alignment of input data
4982  *   - copy (conversion happens automatically) input data
4983  *     to output
4984  *   - update xpp to point at next unconverted input, and tp to point
4985  *     at next location for converted output
4986  */
4987  long i, j, ni;
4988  int tmp[LOOPCNT];        /* in case input is misaligned */
4989  int *xp;
4990  int nrange = 0;         /* number of range errors */
4991  int realign = 0;        /* "do we need to fix input data alignment?" */
4992  long cxp = (long) *((char**)xpp);
4993
4994  realign = (cxp & 7) % SIZEOF_INT;
4995  /* sjl: manually stripmine so we can limit amount of
4996   * vector work space reserved to LOOPCNT elements. Also
4997   * makes vectorisation easy */
4998  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
4999    ni=Min(nelems-j,LOOPCNT);
5000    if (realign) {
5001      memcpy(tmp, *xpp, ni*SIZEOF_INT);
5002      xp = tmp;
5003    } else {
5004      xp = (int *) *xpp;
5005    }
5006   /* copy the next block */
5007#pragma cdir loopcnt=LOOPCNT
5008#pragma cdir shortloop
5009    for (i=0; i<ni; i++) {
5010      tp[i] = (float) Max( FLOAT_MIN, Min(FLOAT_MAX, (float) xp[i]));
5011     /* test for range errors (not always needed but do it anyway) */
5012      nrange += xp[i] < FLOAT_MIN || xp[i] > FLOAT_MAX;
5013    }
5014   /* update xpp and tp */
5015    if (realign) xp = (int *) *xpp;
5016    xp += ni;
5017    tp += ni;
5018    *xpp = (void*)xp;
5019  }
5020  return nrange == 0 ? ENOERR : NC_ERANGE;
5021
5022#else   /* not SX */
5023        const char *xp = (const char *) *xpp;
5024        int status = ENOERR;
5025
5026        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
5027        {
5028                const int lstatus = ncx_get_int_float(xp, tp);
5029                if(lstatus != ENOERR)
5030                        status = lstatus;
5031        }
5032
5033        *xpp = (const void *)xp;
5034        return status;
5035#  endif
5036}
5037
5038int
5039ncx_getn_int_double(const void **xpp, size_t nelems, double *tp)
5040{
5041#if _SX && \
5042           X_SIZEOF_INT == SIZEOF_INT
5043
5044 /* basic algorithm is:
5045  *   - ensure sane alignment of input data
5046  *   - copy (conversion happens automatically) input data
5047  *     to output
5048  *   - update xpp to point at next unconverted input, and tp to point
5049  *     at next location for converted output
5050  */
5051  long i, j, ni;
5052  int tmp[LOOPCNT];        /* in case input is misaligned */
5053  int *xp;
5054  int nrange = 0;         /* number of range errors */
5055  int realign = 0;        /* "do we need to fix input data alignment?" */
5056  long cxp = (long) *((char**)xpp);
5057
5058  realign = (cxp & 7) % SIZEOF_INT;
5059  /* sjl: manually stripmine so we can limit amount of
5060   * vector work space reserved to LOOPCNT elements. Also
5061   * makes vectorisation easy */
5062  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
5063    ni=Min(nelems-j,LOOPCNT);
5064    if (realign) {
5065      memcpy(tmp, *xpp, ni*SIZEOF_INT);
5066      xp = tmp;
5067    } else {
5068      xp = (int *) *xpp;
5069    }
5070   /* copy the next block */
5071#pragma cdir loopcnt=LOOPCNT
5072#pragma cdir shortloop
5073    for (i=0; i<ni; i++) {
5074      tp[i] = (double) Max( DOUBLE_MIN, Min(DOUBLE_MAX, (double) xp[i]));
5075     /* test for range errors (not always needed but do it anyway) */
5076      nrange += xp[i] < DOUBLE_MIN || xp[i] > DOUBLE_MAX;
5077    }
5078   /* update xpp and tp */
5079    if (realign) xp = (int *) *xpp;
5080    xp += ni;
5081    tp += ni;
5082    *xpp = (void*)xp;
5083  }
5084  return nrange == 0 ? ENOERR : NC_ERANGE;
5085
5086#else   /* not SX */
5087        const char *xp = (const char *) *xpp;
5088        int status = ENOERR;
5089
5090        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
5091        {
5092                const int lstatus = ncx_get_int_double(xp, tp);
5093                if(lstatus != ENOERR)
5094                        status = lstatus;
5095        }
5096
5097        *xpp = (const void *)xp;
5098        return status;
5099#  endif
5100}
5101
5102
5103int
5104ncx_putn_int_schar(void **xpp, size_t nelems, const schar *tp)
5105{
5106#if _SX && \
5107           X_SIZEOF_INT == SIZEOF_INT
5108
5109 /* basic algorithm is:
5110  *   - ensure sane alignment of output data
5111  *   - copy (conversion happens automatically) input data
5112  *     to output
5113  *   - update tp to point at next unconverted input, and xpp to point
5114  *     at next location for converted output
5115  */
5116  long i, j, ni;
5117  int tmp[LOOPCNT];        /* in case input is misaligned */
5118  int *xp;
5119  int nrange = 0;         /* number of range errors */
5120  int realign = 0;        /* "do we need to fix input data alignment?" */
5121  long cxp = (long) *((char**)xpp);
5122
5123  realign = (cxp & 7) % SIZEOF_INT;
5124  /* sjl: manually stripmine so we can limit amount of
5125   * vector work space reserved to LOOPCNT elements. Also
5126   * makes vectorisation easy */
5127  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
5128    ni=Min(nelems-j,LOOPCNT);
5129    if (realign) {
5130      xp = tmp;
5131    } else {
5132      xp = (int *) *xpp;
5133    }
5134   /* copy the next block */
5135#pragma cdir loopcnt=LOOPCNT
5136#pragma cdir shortloop
5137    for (i=0; i<ni; i++) {
5138      /* the normal case: */
5139      xp[i] = (int) Max( X_INT_MIN, Min(X_INT_MAX, (int) tp[i]));
5140     /* test for range errors (not always needed but do it anyway) */
5141      nrange += tp[i] < X_INT_MIN || tp[i] > X_INT_MAX;
5142    }
5143   /* copy workspace back if necessary */ 
5144    if (realign) {
5145      memcpy(*xpp, tmp, ni*X_SIZEOF_INT);
5146      xp = (int *) *xpp;
5147    }
5148   /* update xpp and tp */
5149    xp += ni;
5150    tp += ni;
5151    *xpp = (void*)xp;
5152  }
5153  return nrange == 0 ? ENOERR : NC_ERANGE;
5154
5155#else   /* not SX */
5156
5157        char *xp = (char *) *xpp;
5158        int status = ENOERR;
5159
5160        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
5161        {
5162                int lstatus = ncx_put_int_schar(xp, tp);
5163                if(lstatus != ENOERR)
5164                        status = lstatus;
5165        }
5166
5167        *xpp = (void *)xp;
5168        return status;
5169#endif
5170}
5171
5172int
5173ncx_putn_int_uchar(void **xpp, size_t nelems, const uchar *tp)
5174{
5175#if _SX && \
5176           X_SIZEOF_INT == SIZEOF_INT
5177
5178 /* basic algorithm is:
5179  *   - ensure sane alignment of output data
5180  *   - copy (conversion happens automatically) input data
5181  *     to output
5182  *   - update tp to point at next unconverted input, and xpp to point
5183  *     at next location for converted output
5184  */
5185  long i, j, ni;
5186  int tmp[LOOPCNT];        /* in case input is misaligned */
5187  int *xp;
5188  int nrange = 0;         /* number of range errors */
5189  int realign = 0;        /* "do we need to fix input data alignment?" */
5190  long cxp = (long) *((char**)xpp);
5191
5192  realign = (cxp & 7) % SIZEOF_INT;
5193  /* sjl: manually stripmine so we can limit amount of
5194   * vector work space reserved to LOOPCNT elements. Also
5195   * makes vectorisation easy */
5196  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
5197    ni=Min(nelems-j,LOOPCNT);
5198    if (realign) {
5199      xp = tmp;
5200    } else {
5201      xp = (int *) *xpp;
5202    }
5203   /* copy the next block */
5204#pragma cdir loopcnt=LOOPCNT
5205#pragma cdir shortloop
5206    for (i=0; i<ni; i++) {
5207      /* the normal case: */
5208      xp[i] = (int) Max( X_INT_MIN, Min(X_INT_MAX, (int) tp[i]));
5209     /* test for range errors (not always needed but do it anyway) */
5210      nrange += tp[i] < X_INT_MIN || tp[i] > X_INT_MAX;
5211    }
5212   /* copy workspace back if necessary */ 
5213    if (realign) {
5214      memcpy(*xpp, tmp, ni*X_SIZEOF_INT);
5215      xp = (int *) *xpp;
5216    }
5217   /* update xpp and tp */
5218    xp += ni;
5219    tp += ni;
5220    *xpp = (void*)xp;
5221  }
5222  return nrange == 0 ? ENOERR : NC_ERANGE;
5223
5224#else   /* not SX */
5225
5226        char *xp = (char *) *xpp;
5227        int status = ENOERR;
5228
5229        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
5230        {
5231                int lstatus = ncx_put_int_uchar(xp, tp);
5232                if(lstatus != ENOERR)
5233                        status = lstatus;
5234        }
5235
5236        *xpp = (void *)xp;
5237        return status;
5238#endif
5239}
5240
5241int
5242ncx_putn_int_short(void **xpp, size_t nelems, const short *tp)
5243{
5244#if _SX && \
5245           X_SIZEOF_INT == SIZEOF_INT
5246
5247 /* basic algorithm is:
5248  *   - ensure sane alignment of output data
5249  *   - copy (conversion happens automatically) input data
5250  *     to output
5251  *   - update tp to point at next unconverted input, and xpp to point
5252  *     at next location for converted output
5253  */
5254  long i, j, ni;
5255  int tmp[LOOPCNT];        /* in case input is misaligned */
5256  int *xp;
5257  int nrange = 0;         /* number of range errors */
5258  int realign = 0;        /* "do we need to fix input data alignment?" */
5259  long cxp = (long) *((char**)xpp);
5260
5261  realign = (cxp & 7) % SIZEOF_INT;
5262  /* sjl: manually stripmine so we can limit amount of
5263   * vector work space reserved to LOOPCNT elements. Also
5264   * makes vectorisation easy */
5265  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
5266    ni=Min(nelems-j,LOOPCNT);
5267    if (realign) {
5268      xp = tmp;
5269    } else {
5270      xp = (int *) *xpp;
5271    }
5272   /* copy the next block */
5273#pragma cdir loopcnt=LOOPCNT
5274#pragma cdir shortloop
5275    for (i=0; i<ni; i++) {
5276      /* the normal case: */
5277      xp[i] = (int) Max( X_INT_MIN, Min(X_INT_MAX, (int) tp[i]));
5278     /* test for range errors (not always needed but do it anyway) */
5279      nrange += tp[i] < X_INT_MIN || tp[i] > X_INT_MAX;
5280    }
5281   /* copy workspace back if necessary */ 
5282    if (realign) {
5283      memcpy(*xpp, tmp, ni*X_SIZEOF_INT);
5284      xp = (int *) *xpp;
5285    }
5286   /* update xpp and tp */
5287    xp += ni;
5288    tp += ni;
5289    *xpp = (void*)xp;
5290  }
5291  return nrange == 0 ? ENOERR : NC_ERANGE;
5292
5293#else   /* not SX */
5294
5295        char *xp = (char *) *xpp;
5296        int status = ENOERR;
5297
5298        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
5299        {
5300                int lstatus = ncx_put_int_short(xp, tp);
5301                if(lstatus != ENOERR)
5302                        status = lstatus;
5303        }
5304
5305        *xpp = (void *)xp;
5306        return status;
5307#endif
5308}
5309
5310#if X_SIZEOF_INT == SIZEOF_INT
5311/* optimized version */
5312int
5313ncx_putn_int_int(void **xpp, size_t nelems, const int *tp)
5314{
5315#ifdef WORDS_BIGENDIAN
5316        (void) memcpy(*xpp, tp, nelems * X_SIZEOF_INT);
5317# else
5318        swapn4b(*xpp, tp, nelems);
5319# endif
5320        *xpp = (void *)((char *)(*xpp) + nelems * X_SIZEOF_INT);
5321        return ENOERR;
5322}
5323int
5324ncx_putn_int_uint(void **xpp, size_t nelems, const unsigned int *tp)
5325{
5326#ifdef WORDS_BIGENDIAN
5327        (void) memcpy(*xpp, tp, nelems * X_SIZEOF_INT);
5328# else
5329        swapn4b(*xpp, tp, nelems);
5330# endif
5331        *xpp = (void *)((char *)(*xpp) + nelems * X_SIZEOF_INT);
5332        return ENOERR;
5333}
5334#else
5335int
5336ncx_putn_int_int(void **xpp, size_t nelems, const int *tp)
5337{
5338#if _SX && \
5339           X_SIZEOF_INT == SIZEOF_INT
5340
5341 /* basic algorithm is:
5342  *   - ensure sane alignment of output data
5343  *   - copy (conversion happens automatically) input data
5344  *     to output
5345  *   - update tp to point at next unconverted input, and xpp to point
5346  *     at next location for converted output
5347  */
5348  long i, j, ni;
5349  int tmp[LOOPCNT];        /* in case input is misaligned */
5350  int *xp;
5351  int nrange = 0;         /* number of range errors */
5352  int realign = 0;        /* "do we need to fix input data alignment?" */
5353  long cxp = (long) *((char**)xpp);
5354
5355  realign = (cxp & 7) % SIZEOF_INT;
5356  /* sjl: manually stripmine so we can limit amount of
5357   * vector work space reserved to LOOPCNT elements. Also
5358   * makes vectorisation easy */
5359  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
5360    ni=Min(nelems-j,LOOPCNT);
5361    if (realign) {
5362      xp = tmp;
5363    } else {
5364      xp = (int *) *xpp;
5365    }
5366   /* copy the next block */
5367#pragma cdir loopcnt=LOOPCNT
5368#pragma cdir shortloop
5369    for (i=0; i<ni; i++) {
5370      /* the normal case: */
5371      xp[i] = (int) Max( X_INT_MIN, Min(X_INT_MAX, (int) tp[i]));
5372     /* test for range errors (not always needed but do it anyway) */
5373      nrange += tp[i] < X_INT_MIN || tp[i] > X_INT_MAX;
5374    }
5375   /* copy workspace back if necessary */ 
5376    if (realign) {
5377      memcpy(*xpp, tmp, ni*X_SIZEOF_INT);
5378      xp = (int *) *xpp;
5379    }
5380   /* update xpp and tp */
5381    xp += ni;
5382    tp += ni;
5383    *xpp = (void*)xp;
5384  }
5385  return nrange == 0 ? ENOERR : NC_ERANGE;
5386
5387#else   /* not SX */
5388
5389        char *xp = (char *) *xpp;
5390        int status = ENOERR;
5391
5392        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
5393        {
5394                int lstatus = ncx_put_int_int(xp, tp);
5395                if(lstatus != ENOERR)
5396                        status = lstatus;
5397        }
5398
5399        *xpp = (void *)xp;
5400        return status;
5401#endif
5402}
5403
5404int
5405ncx_putn_int_uint(void **xpp, size_t nelems, const uint *tp)
5406{
5407#if _SX && \
5408           X_SIZEOF_INT == SIZEOF_INT
5409
5410 /* basic algorithm is:
5411  *   - ensure sane alignment of output data
5412  *   - copy (conversion happens automatically) input data
5413  *     to output
5414  *   - update tp to point at next unconverted input, and xpp to point
5415  *     at next location for converted output
5416  */
5417  long i, j, ni;
5418  int tmp[LOOPCNT];        /* in case input is misaligned */
5419  int *xp;
5420  int nrange = 0;         /* number of range errors */
5421  int realign = 0;        /* "do we need to fix input data alignment?" */
5422  long cxp = (long) *((char**)xpp);
5423
5424  realign = (cxp & 7) % SIZEOF_INT;
5425  /* sjl: manually stripmine so we can limit amount of
5426   * vector work space reserved to LOOPCNT elements. Also
5427   * makes vectorisation easy */
5428  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
5429    ni=Min(nelems-j,LOOPCNT);
5430    if (realign) {
5431      xp = tmp;
5432    } else {
5433      xp = (int *) *xpp;
5434    }
5435   /* copy the next block */
5436#pragma cdir loopcnt=LOOPCNT
5437#pragma cdir shortloop
5438    for (i=0; i<ni; i++) {
5439      /* the normal case: */
5440      xp[i] = (int) Max( X_INT_MIN, Min(X_INT_MAX, (int) tp[i]));
5441     /* test for range errors (not always needed but do it anyway) */
5442      nrange += tp[i] < X_INT_MIN || tp[i] > X_INT_MAX;
5443    }
5444   /* copy workspace back if necessary */ 
5445    if (realign) {
5446      memcpy(*xpp, tmp, ni*X_SIZEOF_INT);
5447      xp = (int *) *xpp;
5448    }
5449   /* update xpp and tp */
5450    xp += ni;
5451    tp += ni;
5452    *xpp = (void*)xp;
5453  }
5454  return nrange == 0 ? ENOERR : NC_ERANGE;
5455
5456#else   /* not SX */
5457
5458        char *xp = (char *) *xpp;
5459        int status = ENOERR;
5460
5461        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
5462        {
5463                int lstatus = ncx_put_int_uint(xp, tp);
5464                if(lstatus != ENOERR)
5465                        status = lstatus;
5466        }
5467
5468        *xpp = (void *)xp;
5469        return status;
5470#endif
5471}
5472
5473#endif
5474
5475int
5476ncx_putn_int_longlong(void **xpp, size_t nelems, const longlong *tp)
5477{
5478#if _SX && \
5479           X_SIZEOF_INT == SIZEOF_INT
5480
5481 /* basic algorithm is:
5482  *   - ensure sane alignment of output data
5483  *   - copy (conversion happens automatically) input data
5484  *     to output
5485  *   - update tp to point at next unconverted input, and xpp to point
5486  *     at next location for converted output
5487  */
5488  long i, j, ni;
5489  int tmp[LOOPCNT];        /* in case input is misaligned */
5490  int *xp;
5491  int nrange = 0;         /* number of range errors */
5492  int realign = 0;        /* "do we need to fix input data alignment?" */
5493  long cxp = (long) *((char**)xpp);
5494
5495  realign = (cxp & 7) % SIZEOF_INT;
5496  /* sjl: manually stripmine so we can limit amount of
5497   * vector work space reserved to LOOPCNT elements. Also
5498   * makes vectorisation easy */
5499  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
5500    ni=Min(nelems-j,LOOPCNT);
5501    if (realign) {
5502      xp = tmp;
5503    } else {
5504      xp = (int *) *xpp;
5505    }
5506   /* copy the next block */
5507#pragma cdir loopcnt=LOOPCNT
5508#pragma cdir shortloop
5509    for (i=0; i<ni; i++) {
5510      /* the normal case: */
5511      xp[i] = (int) Max( X_INT_MIN, Min(X_INT_MAX, (int) tp[i]));
5512     /* test for range errors (not always needed but do it anyway) */
5513      nrange += tp[i] < X_INT_MIN || tp[i] > X_INT_MAX;
5514    }
5515   /* copy workspace back if necessary */ 
5516    if (realign) {
5517      memcpy(*xpp, tmp, ni*X_SIZEOF_INT);
5518      xp = (int *) *xpp;
5519    }
5520   /* update xpp and tp */
5521    xp += ni;
5522    tp += ni;
5523    *xpp = (void*)xp;
5524  }
5525  return nrange == 0 ? ENOERR : NC_ERANGE;
5526
5527#else   /* not SX */
5528
5529        char *xp = (char *) *xpp;
5530        int status = ENOERR;
5531
5532        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
5533        {
5534                int lstatus = ncx_put_int_longlong(xp, tp);
5535                if(lstatus != ENOERR)
5536                        status = lstatus;
5537        }
5538
5539        *xpp = (void *)xp;
5540        return status;
5541#endif
5542}
5543
5544int
5545ncx_putn_int_ulonglong(void **xpp, size_t nelems, const ulonglong *tp)
5546{
5547#if _SX && \
5548           X_SIZEOF_INT == SIZEOF_INT
5549
5550 /* basic algorithm is:
5551  *   - ensure sane alignment of output data
5552  *   - copy (conversion happens automatically) input data
5553  *     to output
5554  *   - update tp to point at next unconverted input, and xpp to point
5555  *     at next location for converted output
5556  */
5557  long i, j, ni;
5558  int tmp[LOOPCNT];        /* in case input is misaligned */
5559  int *xp;
5560  int nrange = 0;         /* number of range errors */
5561  int realign = 0;        /* "do we need to fix input data alignment?" */
5562  long cxp = (long) *((char**)xpp);
5563
5564  realign = (cxp & 7) % SIZEOF_INT;
5565  /* sjl: manually stripmine so we can limit amount of
5566   * vector work space reserved to LOOPCNT elements. Also
5567   * makes vectorisation easy */
5568  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
5569    ni=Min(nelems-j,LOOPCNT);
5570    if (realign) {
5571      xp = tmp;
5572    } else {
5573      xp = (int *) *xpp;
5574    }
5575   /* copy the next block */
5576#pragma cdir loopcnt=LOOPCNT
5577#pragma cdir shortloop
5578    for (i=0; i<ni; i++) {
5579      /* the normal case: */
5580      xp[i] = (int) Max( X_INT_MIN, Min(X_INT_MAX, (int) tp[i]));
5581     /* test for range errors (not always needed but do it anyway) */
5582      nrange += tp[i] < X_INT_MIN || tp[i] > X_INT_MAX;
5583    }
5584   /* copy workspace back if necessary */ 
5585    if (realign) {
5586      memcpy(*xpp, tmp, ni*X_SIZEOF_INT);
5587      xp = (int *) *xpp;
5588    }
5589   /* update xpp and tp */
5590    xp += ni;
5591    tp += ni;
5592    *xpp = (void*)xp;
5593  }
5594  return nrange == 0 ? ENOERR : NC_ERANGE;
5595
5596#else   /* not SX */
5597
5598        char *xp = (char *) *xpp;
5599        int status = ENOERR;
5600
5601        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
5602        {
5603                int lstatus = ncx_put_int_ulonglong(xp, tp);
5604                if(lstatus != ENOERR)
5605                        status = lstatus;
5606        }
5607
5608        *xpp = (void *)xp;
5609        return status;
5610#endif
5611}
5612
5613int
5614ncx_putn_int_float(void **xpp, size_t nelems, const float *tp)
5615{
5616#if _SX && \
5617           X_SIZEOF_INT == SIZEOF_INT
5618
5619 /* basic algorithm is:
5620  *   - ensure sane alignment of output data
5621  *   - copy (conversion happens automatically) input data
5622  *     to output
5623  *   - update tp to point at next unconverted input, and xpp to point
5624  *     at next location for converted output
5625  */
5626  long i, j, ni;
5627  int tmp[LOOPCNT];        /* in case input is misaligned */
5628  int *xp;
5629  double d;               /* special case for ncx_putn_int_float */
5630  int nrange = 0;         /* number of range errors */
5631  int realign = 0;        /* "do we need to fix input data alignment?" */
5632  long cxp = (long) *((char**)xpp);
5633
5634  realign = (cxp & 7) % SIZEOF_INT;
5635  /* sjl: manually stripmine so we can limit amount of
5636   * vector work space reserved to LOOPCNT elements. Also
5637   * makes vectorisation easy */
5638  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
5639    ni=Min(nelems-j,LOOPCNT);
5640    if (realign) {
5641      xp = tmp;
5642    } else {
5643      xp = (int *) *xpp;
5644    }
5645   /* copy the next block */
5646#pragma cdir loopcnt=LOOPCNT
5647#pragma cdir shortloop
5648    for (i=0; i<ni; i++) {
5649      /* for some reason int to float, for putn, requires a special case */ 
5650      d = tp[i];
5651      xp[i] = (int) Max( X_INT_MIN, Min(X_INT_MAX, (int) d));
5652      nrange += d < X_INT_MIN || d > X_INT_MAX;
5653    }
5654   /* copy workspace back if necessary */ 
5655    if (realign) {
5656      memcpy(*xpp, tmp, ni*X_SIZEOF_INT);
5657      xp = (int *) *xpp;
5658    }
5659   /* update xpp and tp */
5660    xp += ni;
5661    tp += ni;
5662    *xpp = (void*)xp;
5663  }
5664  return nrange == 0 ? ENOERR : NC_ERANGE;
5665
5666#else   /* not SX */
5667
5668        char *xp = (char *) *xpp;
5669        int status = ENOERR;
5670
5671        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
5672        {
5673                int lstatus = ncx_put_int_float(xp, tp);
5674                if(lstatus != ENOERR)
5675                        status = lstatus;
5676        }
5677
5678        *xpp = (void *)xp;
5679        return status;
5680#endif
5681}
5682
5683int
5684ncx_putn_int_double(void **xpp, size_t nelems, const double *tp)
5685{
5686#if _SX && \
5687           X_SIZEOF_INT == SIZEOF_INT
5688
5689 /* basic algorithm is:
5690  *   - ensure sane alignment of output data
5691  *   - copy (conversion happens automatically) input data
5692  *     to output
5693  *   - update tp to point at next unconverted input, and xpp to point
5694  *     at next location for converted output
5695  */
5696  long i, j, ni;
5697  int tmp[LOOPCNT];        /* in case input is misaligned */
5698  int *xp;
5699  int nrange = 0;         /* number of range errors */
5700  int realign = 0;        /* "do we need to fix input data alignment?" */
5701  long cxp = (long) *((char**)xpp);
5702
5703  realign = (cxp & 7) % SIZEOF_INT;
5704  /* sjl: manually stripmine so we can limit amount of
5705   * vector work space reserved to LOOPCNT elements. Also
5706   * makes vectorisation easy */
5707  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
5708    ni=Min(nelems-j,LOOPCNT);
5709    if (realign) {
5710      xp = tmp;
5711    } else {
5712      xp = (int *) *xpp;
5713    }
5714   /* copy the next block */
5715#pragma cdir loopcnt=LOOPCNT
5716#pragma cdir shortloop
5717    for (i=0; i<ni; i++) {
5718      /* the normal case: */
5719      xp[i] = (int) Max( X_INT_MIN, Min(X_INT_MAX, (int) tp[i]));
5720     /* test for range errors (not always needed but do it anyway) */
5721      nrange += tp[i] < X_INT_MIN || tp[i] > X_INT_MAX;
5722    }
5723   /* copy workspace back if necessary */ 
5724    if (realign) {
5725      memcpy(*xpp, tmp, ni*X_SIZEOF_INT);
5726      xp = (int *) *xpp;
5727    }
5728   /* update xpp and tp */
5729    xp += ni;
5730    tp += ni;
5731    *xpp = (void*)xp;
5732  }
5733  return nrange == 0 ? ENOERR : NC_ERANGE;
5734
5735#else   /* not SX */
5736
5737        char *xp = (char *) *xpp;
5738        int status = ENOERR;
5739
5740        for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++)
5741        {
5742                int lstatus = ncx_put_int_double(xp, tp);
5743                if(lstatus != ENOERR)
5744                        status = lstatus;
5745        }
5746
5747        *xpp = (void *)xp;
5748        return status;
5749#endif
5750}
5751
5752
5753
5754/* float */
5755
5756int
5757ncx_getn_float_schar(const void **xpp, size_t nelems, schar *tp)
5758{
5759#if _SX && \
5760           X_SIZEOF_FLOAT == SIZEOF_FLOAT
5761
5762 /* basic algorithm is:
5763  *   - ensure sane alignment of input data
5764  *   - copy (conversion happens automatically) input data
5765  *     to output
5766  *   - update xpp to point at next unconverted input, and tp to point
5767  *     at next location for converted output
5768  */
5769  long i, j, ni;
5770  float tmp[LOOPCNT];        /* in case input is misaligned */
5771  float *xp;
5772  int nrange = 0;         /* number of range errors */
5773  int realign = 0;        /* "do we need to fix input data alignment?" */
5774  long cxp = (long) *((char**)xpp);
5775
5776  realign = (cxp & 7) % SIZEOF_FLOAT;
5777  /* sjl: manually stripmine so we can limit amount of
5778   * vector work space reserved to LOOPCNT elements. Also
5779   * makes vectorisation easy */
5780  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
5781    ni=Min(nelems-j,LOOPCNT);
5782    if (realign) {
5783      memcpy(tmp, *xpp, ni*SIZEOF_FLOAT);
5784      xp = tmp;
5785    } else {
5786      xp = (float *) *xpp;
5787    }
5788   /* copy the next block */
5789#pragma cdir loopcnt=LOOPCNT
5790#pragma cdir shortloop
5791    for (i=0; i<ni; i++) {
5792      tp[i] = (schar) Max( SCHAR_MIN, Min(SCHAR_MAX, (schar) xp[i]));
5793     /* test for range errors (not always needed but do it anyway) */
5794      nrange += xp[i] < SCHAR_MIN || xp[i] > SCHAR_MAX;
5795    }
5796   /* update xpp and tp */
5797    if (realign) xp = (float *) *xpp;
5798    xp += ni;
5799    tp += ni;
5800    *xpp = (void*)xp;
5801  }
5802  return nrange == 0 ? ENOERR : NC_ERANGE;
5803
5804#else   /* not SX */
5805        const char *xp = (const char *) *xpp;
5806        int status = ENOERR;
5807
5808        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
5809        {
5810                const int lstatus = ncx_get_float_schar(xp, tp);
5811                if(lstatus != ENOERR)
5812                        status = lstatus;
5813        }
5814
5815        *xpp = (const void *)xp;
5816        return status;
5817#  endif
5818}
5819
5820int
5821ncx_getn_float_uchar(const void **xpp, size_t nelems, uchar *tp)
5822{
5823#if _SX && \
5824           X_SIZEOF_FLOAT == SIZEOF_FLOAT
5825
5826 /* basic algorithm is:
5827  *   - ensure sane alignment of input data
5828  *   - copy (conversion happens automatically) input data
5829  *     to output
5830  *   - update xpp to point at next unconverted input, and tp to point
5831  *     at next location for converted output
5832  */
5833  long i, j, ni;
5834  float tmp[LOOPCNT];        /* in case input is misaligned */
5835  float *xp;
5836  int nrange = 0;         /* number of range errors */
5837  int realign = 0;        /* "do we need to fix input data alignment?" */
5838  long cxp = (long) *((char**)xpp);
5839
5840  realign = (cxp & 7) % SIZEOF_FLOAT;
5841  /* sjl: manually stripmine so we can limit amount of
5842   * vector work space reserved to LOOPCNT elements. Also
5843   * makes vectorisation easy */
5844  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
5845    ni=Min(nelems-j,LOOPCNT);
5846    if (realign) {
5847      memcpy(tmp, *xpp, ni*SIZEOF_FLOAT);
5848      xp = tmp;
5849    } else {
5850      xp = (float *) *xpp;
5851    }
5852   /* copy the next block */
5853#pragma cdir loopcnt=LOOPCNT
5854#pragma cdir shortloop
5855    for (i=0; i<ni; i++) {
5856      tp[i] = (uchar) Max( UCHAR_MIN, Min(UCHAR_MAX, (uchar) xp[i]));
5857     /* test for range errors (not always needed but do it anyway) */
5858      nrange += xp[i] < UCHAR_MIN || xp[i] > UCHAR_MAX;
5859    }
5860   /* update xpp and tp */
5861    if (realign) xp = (float *) *xpp;
5862    xp += ni;
5863    tp += ni;
5864    *xpp = (void*)xp;
5865  }
5866  return nrange == 0 ? ENOERR : NC_ERANGE;
5867
5868#else   /* not SX */
5869        const char *xp = (const char *) *xpp;
5870        int status = ENOERR;
5871
5872        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
5873        {
5874                const int lstatus = ncx_get_float_uchar(xp, tp);
5875                if(lstatus != ENOERR)
5876                        status = lstatus;
5877        }
5878
5879        *xpp = (const void *)xp;
5880        return status;
5881#  endif
5882}
5883
5884int
5885ncx_getn_float_short(const void **xpp, size_t nelems, short *tp)
5886{
5887#if _SX && \
5888           X_SIZEOF_FLOAT == SIZEOF_FLOAT
5889
5890 /* basic algorithm is:
5891  *   - ensure sane alignment of input data
5892  *   - copy (conversion happens automatically) input data
5893  *     to output
5894  *   - update xpp to point at next unconverted input, and tp to point
5895  *     at next location for converted output
5896  */
5897  long i, j, ni;
5898  float tmp[LOOPCNT];        /* in case input is misaligned */
5899  float *xp;
5900  int nrange = 0;         /* number of range errors */
5901  int realign = 0;        /* "do we need to fix input data alignment?" */
5902  long cxp = (long) *((char**)xpp);
5903
5904  realign = (cxp & 7) % SIZEOF_FLOAT;
5905  /* sjl: manually stripmine so we can limit amount of
5906   * vector work space reserved to LOOPCNT elements. Also
5907   * makes vectorisation easy */
5908  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
5909    ni=Min(nelems-j,LOOPCNT);
5910    if (realign) {
5911      memcpy(tmp, *xpp, ni*SIZEOF_FLOAT);
5912      xp = tmp;
5913    } else {
5914      xp = (float *) *xpp;
5915    }
5916   /* copy the next block */
5917#pragma cdir loopcnt=LOOPCNT
5918#pragma cdir shortloop
5919    for (i=0; i<ni; i++) {
5920      tp[i] = (short) Max( SHORT_MIN, Min(SHORT_MAX, (short) xp[i]));
5921     /* test for range errors (not always needed but do it anyway) */
5922      nrange += xp[i] < SHORT_MIN || xp[i] > SHORT_MAX;
5923    }
5924   /* update xpp and tp */
5925    if (realign) xp = (float *) *xpp;
5926    xp += ni;
5927    tp += ni;
5928    *xpp = (void*)xp;
5929  }
5930  return nrange == 0 ? ENOERR : NC_ERANGE;
5931
5932#else   /* not SX */
5933        const char *xp = (const char *) *xpp;
5934        int status = ENOERR;
5935
5936        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
5937        {
5938                const int lstatus = ncx_get_float_short(xp, tp);
5939                if(lstatus != ENOERR)
5940                        status = lstatus;
5941        }
5942
5943        *xpp = (const void *)xp;
5944        return status;
5945#  endif
5946}
5947
5948int
5949ncx_getn_float_int(const void **xpp, size_t nelems, int *tp)
5950{
5951#if _SX && \
5952           X_SIZEOF_FLOAT == SIZEOF_FLOAT
5953
5954 /* basic algorithm is:
5955  *   - ensure sane alignment of input data
5956  *   - copy (conversion happens automatically) input data
5957  *     to output
5958  *   - update xpp to point at next unconverted input, and tp to point
5959  *     at next location for converted output
5960  */
5961  long i, j, ni;
5962  float tmp[LOOPCNT];        /* in case input is misaligned */
5963  float *xp;
5964  int nrange = 0;         /* number of range errors */
5965  int realign = 0;        /* "do we need to fix input data alignment?" */
5966  long cxp = (long) *((char**)xpp);
5967
5968  realign = (cxp & 7) % SIZEOF_FLOAT;
5969  /* sjl: manually stripmine so we can limit amount of
5970   * vector work space reserved to LOOPCNT elements. Also
5971   * makes vectorisation easy */
5972  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
5973    ni=Min(nelems-j,LOOPCNT);
5974    if (realign) {
5975      memcpy(tmp, *xpp, ni*SIZEOF_FLOAT);
5976      xp = tmp;
5977    } else {
5978      xp = (float *) *xpp;
5979    }
5980   /* copy the next block */
5981#pragma cdir loopcnt=LOOPCNT
5982#pragma cdir shortloop
5983    for (i=0; i<ni; i++) {
5984      tp[i] = (int) Max( INT_MIN, Min(INT_MAX, (int) xp[i]));
5985     /* test for range errors (not always needed but do it anyway) */
5986      nrange += xp[i] < INT_MIN || xp[i] > INT_MAX;
5987    }
5988   /* update xpp and tp */
5989    if (realign) xp = (float *) *xpp;
5990    xp += ni;
5991    tp += ni;
5992    *xpp = (void*)xp;
5993  }
5994  return nrange == 0 ? ENOERR : NC_ERANGE;
5995
5996#else   /* not SX */
5997        const char *xp = (const char *) *xpp;
5998        int status = ENOERR;
5999
6000        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
6001        {
6002                const int lstatus = ncx_get_float_int(xp, tp);
6003                if(lstatus != ENOERR)
6004                        status = lstatus;
6005        }
6006
6007        *xpp = (const void *)xp;
6008        return status;
6009#  endif
6010}
6011
6012#if X_SIZEOF_FLOAT == SIZEOF_FLOAT && !defined(NO_IEEE_FLOAT)
6013/* optimized version */
6014int
6015ncx_getn_float_float(const void **xpp, size_t nelems, float *tp)
6016{
6017#ifdef WORDS_BIGENDIAN
6018        (void) memcpy(tp, *xpp, nelems * sizeof(float));
6019# else
6020        swapn4b(tp, *xpp, nelems);
6021# endif
6022        *xpp = (const void *)((const char *)(*xpp) + nelems * X_SIZEOF_FLOAT);
6023        return ENOERR;
6024}
6025#elif vax
6026int
6027ncx_getn_float_float(const void **xpp, size_t nfloats, float *ip)
6028{
6029        float *const end = ip + nfloats;
6030
6031        while(ip < end)
6032        {
6033                struct vax_single *const vsp = (struct vax_single *) ip;
6034                const struct ieee_single *const isp =
6035                         (const struct ieee_single *) (*xpp);
6036                unsigned exp = isp->exp_hi << 1 | isp->exp_lo;
6037
6038                switch(exp) {
6039                case 0 :
6040                        /* ieee subnormal */
6041                        if(isp->mant_hi == min.ieee.mant_hi
6042                                && isp->mant_lo_hi == min.ieee.mant_lo_hi
6043                                && isp->mant_lo_lo == min.ieee.mant_lo_lo)
6044                        {
6045                                *vsp = min.s;
6046                        }
6047                        else
6048                        {
6049                                unsigned mantissa = (isp->mant_hi << 16)
6050                                         | isp->mant_lo_hi << 8
6051                                         | isp->mant_lo_lo;
6052                                unsigned tmp = mantissa >> 20;
6053                                if(tmp >= 4) {
6054                                        vsp->exp = 2;
6055                                } else if (tmp >= 2) {
6056                                        vsp->exp = 1;
6057                                } else {
6058                                        *vsp = min.s;
6059                                        break;
6060                                } /* else */
6061                                tmp = mantissa - (1 << (20 + vsp->exp ));
6062                                tmp <<= 3 - vsp->exp;
6063                                vsp->mantissa2 = tmp;
6064                                vsp->mantissa1 = (tmp >> 16);
6065                        }
6066                        break;
6067                case 0xfe :
6068                case 0xff :
6069                        *vsp = max.s;
6070                        break;
6071                default :
6072                        vsp->exp = exp - IEEE_SNG_BIAS + VAX_SNG_BIAS;
6073                        vsp->mantissa2 = isp->mant_lo_hi << 8 | isp->mant_lo_lo;
6074                        vsp->mantissa1 = isp->mant_hi;
6075                }
6076
6077                vsp->sign = isp->sign;
6078
6079
6080                ip++;
6081                *xpp = (char *)(*xpp) + X_SIZEOF_FLOAT;
6082        }
6083        return ENOERR;
6084}
6085#else
6086int
6087ncx_getn_float_float(const void **xpp, size_t nelems, float *tp)
6088{
6089        const char *xp = *xpp;
6090        int status = ENOERR;
6091
6092        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
6093        {
6094                const int lstatus = ncx_get_float_float(xp, tp);
6095                if(lstatus != ENOERR)
6096                        status = lstatus;
6097        }
6098
6099        *xpp = (const void *)xp;
6100        return status;
6101}
6102
6103#endif
6104int
6105ncx_getn_float_double(const void **xpp, size_t nelems, double *tp)
6106{
6107#if _SX && \
6108           X_SIZEOF_FLOAT == SIZEOF_FLOAT
6109
6110 /* basic algorithm is:
6111  *   - ensure sane alignment of input data
6112  *   - copy (conversion happens automatically) input data
6113  *     to output
6114  *   - update xpp to point at next unconverted input, and tp to point
6115  *     at next location for converted output
6116  */
6117  long i, j, ni;
6118  float tmp[LOOPCNT];        /* in case input is misaligned */
6119  float *xp;
6120  int nrange = 0;         /* number of range errors */
6121  int realign = 0;        /* "do we need to fix input data alignment?" */
6122  long cxp = (long) *((char**)xpp);
6123
6124  realign = (cxp & 7) % SIZEOF_FLOAT;
6125  /* sjl: manually stripmine so we can limit amount of
6126   * vector work space reserved to LOOPCNT elements. Also
6127   * makes vectorisation easy */
6128  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
6129    ni=Min(nelems-j,LOOPCNT);
6130    if (realign) {
6131      memcpy(tmp, *xpp, ni*SIZEOF_FLOAT);
6132      xp = tmp;
6133    } else {
6134      xp = (float *) *xpp;
6135    }
6136   /* copy the next block */
6137#pragma cdir loopcnt=LOOPCNT
6138#pragma cdir shortloop
6139    for (i=0; i<ni; i++) {
6140      tp[i] = (double) Max( DOUBLE_MIN, Min(DOUBLE_MAX, (double) xp[i]));
6141     /* test for range errors (not always needed but do it anyway) */
6142      nrange += xp[i] < DOUBLE_MIN || xp[i] > DOUBLE_MAX;
6143    }
6144   /* update xpp and tp */
6145    if (realign) xp = (float *) *xpp;
6146    xp += ni;
6147    tp += ni;
6148    *xpp = (void*)xp;
6149  }
6150  return nrange == 0 ? ENOERR : NC_ERANGE;
6151
6152#else   /* not SX */
6153        const char *xp = (const char *) *xpp;
6154        int status = ENOERR;
6155
6156        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
6157        {
6158                const int lstatus = ncx_get_float_double(xp, tp);
6159                if(lstatus != ENOERR)
6160                        status = lstatus;
6161        }
6162
6163        *xpp = (const void *)xp;
6164        return status;
6165#  endif
6166}
6167
6168int
6169ncx_getn_float_uint(const void **xpp, size_t nelems, uint *tp)
6170{
6171#if _SX && \
6172           X_SIZEOF_FLOAT == SIZEOF_FLOAT
6173
6174 /* basic algorithm is:
6175  *   - ensure sane alignment of input data
6176  *   - copy (conversion happens automatically) input data
6177  *     to output
6178  *   - update xpp to point at next unconverted input, and tp to point
6179  *     at next location for converted output
6180  */
6181  long i, j, ni;
6182  float tmp[LOOPCNT];        /* in case input is misaligned */
6183  float *xp;
6184  int nrange = 0;         /* number of range errors */
6185  int realign = 0;        /* "do we need to fix input data alignment?" */
6186  long cxp = (long) *((char**)xpp);
6187
6188  realign = (cxp & 7) % SIZEOF_FLOAT;
6189  /* sjl: manually stripmine so we can limit amount of
6190   * vector work space reserved to LOOPCNT elements. Also
6191   * makes vectorisation easy */
6192  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
6193    ni=Min(nelems-j,LOOPCNT);
6194    if (realign) {
6195      memcpy(tmp, *xpp, ni*SIZEOF_FLOAT);
6196      xp = tmp;
6197    } else {
6198      xp = (float *) *xpp;
6199    }
6200   /* copy the next block */
6201#pragma cdir loopcnt=LOOPCNT
6202#pragma cdir shortloop
6203    for (i=0; i<ni; i++) {
6204      tp[i] = (uint) Max( UINT_MIN, Min(UINT_MAX, (uint) xp[i]));
6205     /* test for range errors (not always needed but do it anyway) */
6206      nrange += xp[i] < UINT_MIN || xp[i] > UINT_MAX;
6207    }
6208   /* update xpp and tp */
6209    if (realign) xp = (float *) *xpp;
6210    xp += ni;
6211    tp += ni;
6212    *xpp = (void*)xp;
6213  }
6214  return nrange == 0 ? ENOERR : NC_ERANGE;
6215
6216#else   /* not SX */
6217        const char *xp = (const char *) *xpp;
6218        int status = ENOERR;
6219
6220        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
6221        {
6222                const int lstatus = ncx_get_float_uint(xp, tp);
6223                if(lstatus != ENOERR)
6224                        status = lstatus;
6225        }
6226
6227        *xpp = (const void *)xp;
6228        return status;
6229#  endif
6230}
6231
6232int
6233ncx_getn_float_longlong(const void **xpp, size_t nelems, longlong *tp)
6234{
6235#if _SX && \
6236           X_SIZEOF_FLOAT == SIZEOF_FLOAT
6237
6238 /* basic algorithm is:
6239  *   - ensure sane alignment of input data
6240  *   - copy (conversion happens automatically) input data
6241  *     to output
6242  *   - update xpp to point at next unconverted input, and tp to point
6243  *     at next location for converted output
6244  */
6245  long i, j, ni;
6246  float tmp[LOOPCNT];        /* in case input is misaligned */
6247  float *xp;
6248  int nrange = 0;         /* number of range errors */
6249  int realign = 0;        /* "do we need to fix input data alignment?" */
6250  long cxp = (long) *((char**)xpp);
6251
6252  realign = (cxp & 7) % SIZEOF_FLOAT;
6253  /* sjl: manually stripmine so we can limit amount of
6254   * vector work space reserved to LOOPCNT elements. Also
6255   * makes vectorisation easy */
6256  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
6257    ni=Min(nelems-j,LOOPCNT);
6258    if (realign) {
6259      memcpy(tmp, *xpp, ni*SIZEOF_FLOAT);
6260      xp = tmp;
6261    } else {
6262      xp = (float *) *xpp;
6263    }
6264   /* copy the next block */
6265#pragma cdir loopcnt=LOOPCNT
6266#pragma cdir shortloop
6267    for (i=0; i<ni; i++) {
6268      tp[i] = (longlong) Max( LONGLONG_MIN, Min(LONGLONG_MAX, (longlong) xp[i]));
6269     /* test for range errors (not always needed but do it anyway) */
6270      nrange += xp[i] < LONGLONG_MIN || xp[i] > LONGLONG_MAX;
6271    }
6272   /* update xpp and tp */
6273    if (realign) xp = (float *) *xpp;
6274    xp += ni;
6275    tp += ni;
6276    *xpp = (void*)xp;
6277  }
6278  return nrange == 0 ? ENOERR : NC_ERANGE;
6279
6280#else   /* not SX */
6281        const char *xp = (const char *) *xpp;
6282        int status = ENOERR;
6283
6284        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
6285        {
6286                const int lstatus = ncx_get_float_longlong(xp, tp);
6287                if(lstatus != ENOERR)
6288                        status = lstatus;
6289        }
6290
6291        *xpp = (const void *)xp;
6292        return status;
6293#  endif
6294}
6295
6296int
6297ncx_getn_float_ulonglong(const void **xpp, size_t nelems, ulonglong *tp)
6298{
6299#if _SX && \
6300           X_SIZEOF_FLOAT == SIZEOF_FLOAT
6301
6302 /* basic algorithm is:
6303  *   - ensure sane alignment of input data
6304  *   - copy (conversion happens automatically) input data
6305  *     to output
6306  *   - update xpp to point at next unconverted input, and tp to point
6307  *     at next location for converted output
6308  */
6309  long i, j, ni;
6310  float tmp[LOOPCNT];        /* in case input is misaligned */
6311  float *xp;
6312  int nrange = 0;         /* number of range errors */
6313  int realign = 0;        /* "do we need to fix input data alignment?" */
6314  long cxp = (long) *((char**)xpp);
6315
6316  realign = (cxp & 7) % SIZEOF_FLOAT;
6317  /* sjl: manually stripmine so we can limit amount of
6318   * vector work space reserved to LOOPCNT elements. Also
6319   * makes vectorisation easy */
6320  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
6321    ni=Min(nelems-j,LOOPCNT);
6322    if (realign) {
6323      memcpy(tmp, *xpp, ni*SIZEOF_FLOAT);
6324      xp = tmp;
6325    } else {
6326      xp = (float *) *xpp;
6327    }
6328   /* copy the next block */
6329#pragma cdir loopcnt=LOOPCNT
6330#pragma cdir shortloop
6331    for (i=0; i<ni; i++) {
6332      tp[i] = (ulonglong) Max( ULONGLONG_MIN, Min(ULONGLONG_MAX, (ulonglong) xp[i]));
6333     /* test for range errors (not always needed but do it anyway) */
6334      nrange += xp[i] < ULONGLONG_MIN || xp[i] > ULONGLONG_MAX;
6335    }
6336   /* update xpp and tp */
6337    if (realign) xp = (float *) *xpp;
6338    xp += ni;
6339    tp += ni;
6340    *xpp = (void*)xp;
6341  }
6342  return nrange == 0 ? ENOERR : NC_ERANGE;
6343
6344#else   /* not SX */
6345        const char *xp = (const char *) *xpp;
6346        int status = ENOERR;
6347
6348        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
6349        {
6350                const int lstatus = ncx_get_float_ulonglong(xp, tp);
6351                if(lstatus != ENOERR)
6352                        status = lstatus;
6353        }
6354
6355        *xpp = (const void *)xp;
6356        return status;
6357#  endif
6358}
6359
6360
6361int
6362ncx_putn_float_schar(void **xpp, size_t nelems, const schar *tp)
6363{
6364#if _SX && \
6365           X_SIZEOF_FLOAT == SIZEOF_FLOAT
6366
6367 /* basic algorithm is:
6368  *   - ensure sane alignment of output data
6369  *   - copy (conversion happens automatically) input data
6370  *     to output
6371  *   - update tp to point at next unconverted input, and xpp to point
6372  *     at next location for converted output
6373  */
6374  long i, j, ni;
6375  float tmp[LOOPCNT];        /* in case input is misaligned */
6376  float *xp;
6377  int nrange = 0;         /* number of range errors */
6378  int realign = 0;        /* "do we need to fix input data alignment?" */
6379  long cxp = (long) *((char**)xpp);
6380
6381  realign = (cxp & 7) % SIZEOF_FLOAT;
6382  /* sjl: manually stripmine so we can limit amount of
6383   * vector work space reserved to LOOPCNT elements. Also
6384   * makes vectorisation easy */
6385  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
6386    ni=Min(nelems-j,LOOPCNT);
6387    if (realign) {
6388      xp = tmp;
6389    } else {
6390      xp = (float *) *xpp;
6391    }
6392   /* copy the next block */
6393#pragma cdir loopcnt=LOOPCNT
6394#pragma cdir shortloop
6395    for (i=0; i<ni; i++) {
6396      /* the normal case: */
6397      xp[i] = (float) Max( X_FLOAT_MIN, Min(X_FLOAT_MAX, (float) tp[i]));
6398     /* test for range errors (not always needed but do it anyway) */
6399      nrange += tp[i] < X_FLOAT_MIN || tp[i] > X_FLOAT_MAX;
6400    }
6401   /* copy workspace back if necessary */ 
6402    if (realign) {
6403      memcpy(*xpp, tmp, ni*X_SIZEOF_FLOAT);
6404      xp = (float *) *xpp;
6405    }
6406   /* update xpp and tp */
6407    xp += ni;
6408    tp += ni;
6409    *xpp = (void*)xp;
6410  }
6411  return nrange == 0 ? ENOERR : NC_ERANGE;
6412
6413#else   /* not SX */
6414
6415        char *xp = (char *) *xpp;
6416        int status = ENOERR;
6417
6418        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
6419        {
6420                int lstatus = ncx_put_float_schar(xp, tp);
6421                if(lstatus != ENOERR)
6422                        status = lstatus;
6423        }
6424
6425        *xpp = (void *)xp;
6426        return status;
6427#endif
6428}
6429
6430int
6431ncx_putn_float_uchar(void **xpp, size_t nelems, const uchar *tp)
6432{
6433#if _SX && \
6434           X_SIZEOF_FLOAT == SIZEOF_FLOAT
6435
6436 /* basic algorithm is:
6437  *   - ensure sane alignment of output data
6438  *   - copy (conversion happens automatically) input data
6439  *     to output
6440  *   - update tp to point at next unconverted input, and xpp to point
6441  *     at next location for converted output
6442  */
6443  long i, j, ni;
6444  float tmp[LOOPCNT];        /* in case input is misaligned */
6445  float *xp;
6446  int nrange = 0;         /* number of range errors */
6447  int realign = 0;        /* "do we need to fix input data alignment?" */
6448  long cxp = (long) *((char**)xpp);
6449
6450  realign = (cxp & 7) % SIZEOF_FLOAT;
6451  /* sjl: manually stripmine so we can limit amount of
6452   * vector work space reserved to LOOPCNT elements. Also
6453   * makes vectorisation easy */
6454  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
6455    ni=Min(nelems-j,LOOPCNT);
6456    if (realign) {
6457      xp = tmp;
6458    } else {
6459      xp = (float *) *xpp;
6460    }
6461   /* copy the next block */
6462#pragma cdir loopcnt=LOOPCNT
6463#pragma cdir shortloop
6464    for (i=0; i<ni; i++) {
6465      /* the normal case: */
6466      xp[i] = (float) Max( X_FLOAT_MIN, Min(X_FLOAT_MAX, (float) tp[i]));
6467     /* test for range errors (not always needed but do it anyway) */
6468      nrange += tp[i] < X_FLOAT_MIN || tp[i] > X_FLOAT_MAX;
6469    }
6470   /* copy workspace back if necessary */ 
6471    if (realign) {
6472      memcpy(*xpp, tmp, ni*X_SIZEOF_FLOAT);
6473      xp = (float *) *xpp;
6474    }
6475   /* update xpp and tp */
6476    xp += ni;
6477    tp += ni;
6478    *xpp = (void*)xp;
6479  }
6480  return nrange == 0 ? ENOERR : NC_ERANGE;
6481
6482#else   /* not SX */
6483
6484        char *xp = (char *) *xpp;
6485        int status = ENOERR;
6486
6487        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
6488        {
6489                int lstatus = ncx_put_float_uchar(xp, tp);
6490                if(lstatus != ENOERR)
6491                        status = lstatus;
6492        }
6493
6494        *xpp = (void *)xp;
6495        return status;
6496#endif
6497}
6498
6499int
6500ncx_putn_float_short(void **xpp, size_t nelems, const short *tp)
6501{
6502#if _SX && \
6503           X_SIZEOF_FLOAT == SIZEOF_FLOAT
6504
6505 /* basic algorithm is:
6506  *   - ensure sane alignment of output data
6507  *   - copy (conversion happens automatically) input data
6508  *     to output
6509  *   - update tp to point at next unconverted input, and xpp to point
6510  *     at next location for converted output
6511  */
6512  long i, j, ni;
6513  float tmp[LOOPCNT];        /* in case input is misaligned */
6514  float *xp;
6515  int nrange = 0;         /* number of range errors */
6516  int realign = 0;        /* "do we need to fix input data alignment?" */
6517  long cxp = (long) *((char**)xpp);
6518
6519  realign = (cxp & 7) % SIZEOF_FLOAT;
6520  /* sjl: manually stripmine so we can limit amount of
6521   * vector work space reserved to LOOPCNT elements. Also
6522   * makes vectorisation easy */
6523  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
6524    ni=Min(nelems-j,LOOPCNT);
6525    if (realign) {
6526      xp = tmp;
6527    } else {
6528      xp = (float *) *xpp;
6529    }
6530   /* copy the next block */
6531#pragma cdir loopcnt=LOOPCNT
6532#pragma cdir shortloop
6533    for (i=0; i<ni; i++) {
6534      /* the normal case: */
6535      xp[i] = (float) Max( X_FLOAT_MIN, Min(X_FLOAT_MAX, (float) tp[i]));
6536     /* test for range errors (not always needed but do it anyway) */
6537      nrange += tp[i] < X_FLOAT_MIN || tp[i] > X_FLOAT_MAX;
6538    }
6539   /* copy workspace back if necessary */ 
6540    if (realign) {
6541      memcpy(*xpp, tmp, ni*X_SIZEOF_FLOAT);
6542      xp = (float *) *xpp;
6543    }
6544   /* update xpp and tp */
6545    xp += ni;
6546    tp += ni;
6547    *xpp = (void*)xp;
6548  }
6549  return nrange == 0 ? ENOERR : NC_ERANGE;
6550
6551#else   /* not SX */
6552
6553        char *xp = (char *) *xpp;
6554        int status = ENOERR;
6555
6556        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
6557        {
6558                int lstatus = ncx_put_float_short(xp, tp);
6559                if(lstatus != ENOERR)
6560                        status = lstatus;
6561        }
6562
6563        *xpp = (void *)xp;
6564        return status;
6565#endif
6566}
6567
6568int
6569ncx_putn_float_int(void **xpp, size_t nelems, const int *tp)
6570{
6571#if _SX && \
6572           X_SIZEOF_FLOAT == SIZEOF_FLOAT
6573
6574 /* basic algorithm is:
6575  *   - ensure sane alignment of output data
6576  *   - copy (conversion happens automatically) input data
6577  *     to output
6578  *   - update tp to point at next unconverted input, and xpp to point
6579  *     at next location for converted output
6580  */
6581  long i, j, ni;
6582  float tmp[LOOPCNT];        /* in case input is misaligned */
6583  float *xp;
6584  int nrange = 0;         /* number of range errors */
6585  int realign = 0;        /* "do we need to fix input data alignment?" */
6586  long cxp = (long) *((char**)xpp);
6587
6588  realign = (cxp & 7) % SIZEOF_FLOAT;
6589  /* sjl: manually stripmine so we can limit amount of
6590   * vector work space reserved to LOOPCNT elements. Also
6591   * makes vectorisation easy */
6592  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
6593    ni=Min(nelems-j,LOOPCNT);
6594    if (realign) {
6595      xp = tmp;
6596    } else {
6597      xp = (float *) *xpp;
6598    }
6599   /* copy the next block */
6600#pragma cdir loopcnt=LOOPCNT
6601#pragma cdir shortloop
6602    for (i=0; i<ni; i++) {
6603      /* the normal case: */
6604      xp[i] = (float) Max( X_FLOAT_MIN, Min(X_FLOAT_MAX, (float) tp[i]));
6605     /* test for range errors (not always needed but do it anyway) */
6606      nrange += tp[i] < X_FLOAT_MIN || tp[i] > X_FLOAT_MAX;
6607    }
6608   /* copy workspace back if necessary */ 
6609    if (realign) {
6610      memcpy(*xpp, tmp, ni*X_SIZEOF_FLOAT);
6611      xp = (float *) *xpp;
6612    }
6613   /* update xpp and tp */
6614    xp += ni;
6615    tp += ni;
6616    *xpp = (void*)xp;
6617  }
6618  return nrange == 0 ? ENOERR : NC_ERANGE;
6619
6620#else   /* not SX */
6621
6622        char *xp = (char *) *xpp;
6623        int status = ENOERR;
6624
6625        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
6626        {
6627                int lstatus = ncx_put_float_int(xp, tp);
6628                if(lstatus != ENOERR)
6629                        status = lstatus;
6630        }
6631
6632        *xpp = (void *)xp;
6633        return status;
6634#endif
6635}
6636
6637#if X_SIZEOF_FLOAT == SIZEOF_FLOAT && !defined(NO_IEEE_FLOAT)
6638/* optimized version */
6639int
6640ncx_putn_float_float(void **xpp, size_t nelems, const float *tp)
6641{
6642#ifdef WORDS_BIGENDIAN
6643        (void) memcpy(*xpp, tp, nelems * X_SIZEOF_FLOAT);
6644# else
6645        swapn4b(*xpp, tp, nelems);
6646# endif
6647        *xpp = (void *)((char *)(*xpp) + nelems * X_SIZEOF_FLOAT);
6648        return ENOERR;
6649}
6650#elif vax
6651int
6652ncx_putn_float_float(void **xpp, size_t nfloats, const float *ip)
6653{
6654        const float *const end = ip + nfloats;
6655
6656        while(ip < end)
6657        {
6658                const struct vax_single *const vsp =
6659                         (const struct vax_single *)ip;
6660                struct ieee_single *const isp = (struct ieee_single *) (*xpp);
6661
6662                switch(vsp->exp){
6663                case 0 :
6664                        /* all vax float with zero exponent map to zero */
6665                        *isp = min.ieee;
6666                        break;
6667                case 2 :
6668                case 1 :
6669                {
6670                        /* These will map to subnormals */
6671                        unsigned mantissa = (vsp->mantissa1 << 16)
6672                                         | vsp->mantissa2;
6673                        mantissa >>= 3 - vsp->exp;
6674                        mantissa += (1 << (20 + vsp->exp));
6675                        isp->mant_lo_lo = mantissa;
6676                        isp->mant_lo_hi = mantissa >> 8;
6677                        isp->mant_hi = mantissa >> 16;
6678                        isp->exp_lo = 0;
6679                        isp->exp_hi = 0;
6680                }
6681                        break;
6682                case 0xff : /* max.s.exp */
6683                        if( vsp->mantissa2 == max.s.mantissa2
6684                                && vsp->mantissa1 == max.s.mantissa1)
6685                        {
6686                                /* map largest vax float to ieee infinity */
6687                                *isp = max.ieee;
6688                                break;
6689                        } /* else, fall thru */
6690                default :
6691                {
6692                        unsigned exp = vsp->exp - VAX_SNG_BIAS + IEEE_SNG_BIAS;
6693                        isp->exp_hi = exp >> 1;
6694                        isp->exp_lo = exp;
6695                        isp->mant_lo_lo = vsp->mantissa2;
6696                        isp->mant_lo_hi = vsp->mantissa2 >> 8;
6697                        isp->mant_hi = vsp->mantissa1;
6698                }
6699                }
6700
6701                isp->sign = vsp->sign;
6702
6703       
6704                ip++;
6705                *xpp = (char *)(*xpp) + X_SIZEOF_FLOAT;
6706        }
6707        return ENOERR;
6708}
6709#else
6710int
6711ncx_putn_float_float(void **xpp, size_t nelems, const float *tp)
6712{
6713        char *xp = *xpp;
6714        int status = ENOERR;
6715
6716        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
6717        {
6718                int lstatus = ncx_put_float_float(xp, tp);
6719                if(lstatus != ENOERR)
6720                        status = lstatus;
6721        }
6722
6723        *xpp = (void *)xp;
6724        return status;
6725}
6726
6727#endif
6728int
6729ncx_putn_float_double(void **xpp, size_t nelems, const double *tp)
6730{
6731#if _SX && \
6732           X_SIZEOF_FLOAT == SIZEOF_FLOAT
6733
6734 /* basic algorithm is:
6735  *   - ensure sane alignment of output data
6736  *   - copy (conversion happens automatically) input data
6737  *     to output
6738  *   - update tp to point at next unconverted input, and xpp to point
6739  *     at next location for converted output
6740  */
6741  long i, j, ni;
6742  float tmp[LOOPCNT];        /* in case input is misaligned */
6743  float *xp;
6744  int nrange = 0;         /* number of range errors */
6745  int realign = 0;        /* "do we need to fix input data alignment?" */
6746  long cxp = (long) *((char**)xpp);
6747
6748  realign = (cxp & 7) % SIZEOF_FLOAT;
6749  /* sjl: manually stripmine so we can limit amount of
6750   * vector work space reserved to LOOPCNT elements. Also
6751   * makes vectorisation easy */
6752  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
6753    ni=Min(nelems-j,LOOPCNT);
6754    if (realign) {
6755      xp = tmp;
6756    } else {
6757      xp = (float *) *xpp;
6758    }
6759   /* copy the next block */
6760#pragma cdir loopcnt=LOOPCNT
6761#pragma cdir shortloop
6762    for (i=0; i<ni; i++) {
6763      /* the normal case: */
6764      xp[i] = (float) Max( X_FLOAT_MIN, Min(X_FLOAT_MAX, (float) tp[i]));
6765     /* test for range errors (not always needed but do it anyway) */
6766      nrange += tp[i] < X_FLOAT_MIN || tp[i] > X_FLOAT_MAX;
6767    }
6768   /* copy workspace back if necessary */ 
6769    if (realign) {
6770      memcpy(*xpp, tmp, ni*X_SIZEOF_FLOAT);
6771      xp = (float *) *xpp;
6772    }
6773   /* update xpp and tp */
6774    xp += ni;
6775    tp += ni;
6776    *xpp = (void*)xp;
6777  }
6778  return nrange == 0 ? ENOERR : NC_ERANGE;
6779
6780#else   /* not SX */
6781
6782        char *xp = (char *) *xpp;
6783        int status = ENOERR;
6784
6785        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
6786        {
6787                int lstatus = ncx_put_float_double(xp, tp);
6788                if(lstatus != ENOERR)
6789                        status = lstatus;
6790        }
6791
6792        *xpp = (void *)xp;
6793        return status;
6794#endif
6795}
6796
6797int
6798ncx_putn_float_uint(void **xpp, size_t nelems, const uint *tp)
6799{
6800#if _SX && \
6801           X_SIZEOF_FLOAT == SIZEOF_FLOAT
6802
6803 /* basic algorithm is:
6804  *   - ensure sane alignment of output data
6805  *   - copy (conversion happens automatically) input data
6806  *     to output
6807  *   - update tp to point at next unconverted input, and xpp to point
6808  *     at next location for converted output
6809  */
6810  long i, j, ni;
6811  float tmp[LOOPCNT];        /* in case input is misaligned */
6812  float *xp;
6813  int nrange = 0;         /* number of range errors */
6814  int realign = 0;        /* "do we need to fix input data alignment?" */
6815  long cxp = (long) *((char**)xpp);
6816
6817  realign = (cxp & 7) % SIZEOF_FLOAT;
6818  /* sjl: manually stripmine so we can limit amount of
6819   * vector work space reserved to LOOPCNT elements. Also
6820   * makes vectorisation easy */
6821  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
6822    ni=Min(nelems-j,LOOPCNT);
6823    if (realign) {
6824      xp = tmp;
6825    } else {
6826      xp = (float *) *xpp;
6827    }
6828   /* copy the next block */
6829#pragma cdir loopcnt=LOOPCNT
6830#pragma cdir shortloop
6831    for (i=0; i<ni; i++) {
6832      /* the normal case: */
6833      xp[i] = (float) Max( X_FLOAT_MIN, Min(X_FLOAT_MAX, (float) tp[i]));
6834     /* test for range errors (not always needed but do it anyway) */
6835      nrange += tp[i] < X_FLOAT_MIN || tp[i] > X_FLOAT_MAX;
6836    }
6837   /* copy workspace back if necessary */ 
6838    if (realign) {
6839      memcpy(*xpp, tmp, ni*X_SIZEOF_FLOAT);
6840      xp = (float *) *xpp;
6841    }
6842   /* update xpp and tp */
6843    xp += ni;
6844    tp += ni;
6845    *xpp = (void*)xp;
6846  }
6847  return nrange == 0 ? ENOERR : NC_ERANGE;
6848
6849#else   /* not SX */
6850
6851        char *xp = (char *) *xpp;
6852        int status = ENOERR;
6853
6854        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
6855        {
6856                int lstatus = ncx_put_float_uint(xp, tp);
6857                if(lstatus != ENOERR)
6858                        status = lstatus;
6859        }
6860
6861        *xpp = (void *)xp;
6862        return status;
6863#endif
6864}
6865
6866int
6867ncx_putn_float_longlong(void **xpp, size_t nelems, const longlong *tp)
6868{
6869#if _SX && \
6870           X_SIZEOF_FLOAT == SIZEOF_FLOAT
6871
6872 /* basic algorithm is:
6873  *   - ensure sane alignment of output data
6874  *   - copy (conversion happens automatically) input data
6875  *     to output
6876  *   - update tp to point at next unconverted input, and xpp to point
6877  *     at next location for converted output
6878  */
6879  long i, j, ni;
6880  float tmp[LOOPCNT];        /* in case input is misaligned */
6881  float *xp;
6882  int nrange = 0;         /* number of range errors */
6883  int realign = 0;        /* "do we need to fix input data alignment?" */
6884  long cxp = (long) *((char**)xpp);
6885
6886  realign = (cxp & 7) % SIZEOF_FLOAT;
6887  /* sjl: manually stripmine so we can limit amount of
6888   * vector work space reserved to LOOPCNT elements. Also
6889   * makes vectorisation easy */
6890  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
6891    ni=Min(nelems-j,LOOPCNT);
6892    if (realign) {
6893      xp = tmp;
6894    } else {
6895      xp = (float *) *xpp;
6896    }
6897   /* copy the next block */
6898#pragma cdir loopcnt=LOOPCNT
6899#pragma cdir shortloop
6900    for (i=0; i<ni; i++) {
6901      /* the normal case: */
6902      xp[i] = (float) Max( X_FLOAT_MIN, Min(X_FLOAT_MAX, (float) tp[i]));
6903     /* test for range errors (not always needed but do it anyway) */
6904      nrange += tp[i] < X_FLOAT_MIN || tp[i] > X_FLOAT_MAX;
6905    }
6906   /* copy workspace back if necessary */ 
6907    if (realign) {
6908      memcpy(*xpp, tmp, ni*X_SIZEOF_FLOAT);
6909      xp = (float *) *xpp;
6910    }
6911   /* update xpp and tp */
6912    xp += ni;
6913    tp += ni;
6914    *xpp = (void*)xp;
6915  }
6916  return nrange == 0 ? ENOERR : NC_ERANGE;
6917
6918#else   /* not SX */
6919
6920        char *xp = (char *) *xpp;
6921        int status = ENOERR;
6922
6923        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
6924        {
6925                int lstatus = ncx_put_float_longlong(xp, tp);
6926                if(lstatus != ENOERR)
6927                        status = lstatus;
6928        }
6929
6930        *xpp = (void *)xp;
6931        return status;
6932#endif
6933}
6934
6935int
6936ncx_putn_float_ulonglong(void **xpp, size_t nelems, const ulonglong *tp)
6937{
6938#if _SX && \
6939           X_SIZEOF_FLOAT == SIZEOF_FLOAT
6940
6941 /* basic algorithm is:
6942  *   - ensure sane alignment of output data
6943  *   - copy (conversion happens automatically) input data
6944  *     to output
6945  *   - update tp to point at next unconverted input, and xpp to point
6946  *     at next location for converted output
6947  */
6948  long i, j, ni;
6949  float tmp[LOOPCNT];        /* in case input is misaligned */
6950  float *xp;
6951  int nrange = 0;         /* number of range errors */
6952  int realign = 0;        /* "do we need to fix input data alignment?" */
6953  long cxp = (long) *((char**)xpp);
6954
6955  realign = (cxp & 7) % SIZEOF_FLOAT;
6956  /* sjl: manually stripmine so we can limit amount of
6957   * vector work space reserved to LOOPCNT elements. Also
6958   * makes vectorisation easy */
6959  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
6960    ni=Min(nelems-j,LOOPCNT);
6961    if (realign) {
6962      xp = tmp;
6963    } else {
6964      xp = (float *) *xpp;
6965    }
6966   /* copy the next block */
6967#pragma cdir loopcnt=LOOPCNT
6968#pragma cdir shortloop
6969    for (i=0; i<ni; i++) {
6970      /* the normal case: */
6971      xp[i] = (float) Max( X_FLOAT_MIN, Min(X_FLOAT_MAX, (float) tp[i]));
6972     /* test for range errors (not always needed but do it anyway) */
6973      nrange += tp[i] < X_FLOAT_MIN || tp[i] > X_FLOAT_MAX;
6974    }
6975   /* copy workspace back if necessary */ 
6976    if (realign) {
6977      memcpy(*xpp, tmp, ni*X_SIZEOF_FLOAT);
6978      xp = (float *) *xpp;
6979    }
6980   /* update xpp and tp */
6981    xp += ni;
6982    tp += ni;
6983    *xpp = (void*)xp;
6984  }
6985  return nrange == 0 ? ENOERR : NC_ERANGE;
6986
6987#else   /* not SX */
6988
6989        char *xp = (char *) *xpp;
6990        int status = ENOERR;
6991
6992        for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++)
6993        {
6994                int lstatus = ncx_put_float_ulonglong(xp, tp);
6995                if(lstatus != ENOERR)
6996                        status = lstatus;
6997        }
6998
6999        *xpp = (void *)xp;
7000        return status;
7001#endif
7002}
7003
7004
7005/* double */
7006
7007int
7008ncx_getn_double_schar(const void **xpp, size_t nelems, schar *tp)
7009{
7010#if _SX && \
7011           X_SIZEOF_DOUBLE == SIZEOF_DOUBLE
7012
7013 /* basic algorithm is:
7014  *   - ensure sane alignment of input data
7015  *   - copy (conversion happens automatically) input data
7016  *     to output
7017  *   - update xpp to point at next unconverted input, and tp to point
7018  *     at next location for converted output
7019  */
7020  long i, j, ni;
7021  double tmp[LOOPCNT];        /* in case input is misaligned */
7022  double *xp;
7023  int nrange = 0;         /* number of range errors */
7024  int realign = 0;        /* "do we need to fix input data alignment?" */
7025  long cxp = (long) *((char**)xpp);
7026
7027  realign = (cxp & 7) % SIZEOF_DOUBLE;
7028  /* sjl: manually stripmine so we can limit amount of
7029   * vector work space reserved to LOOPCNT elements. Also
7030   * makes vectorisation easy */
7031  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
7032    ni=Min(nelems-j,LOOPCNT);
7033    if (realign) {
7034      memcpy(tmp, *xpp, ni*SIZEOF_DOUBLE);
7035      xp = tmp;
7036    } else {
7037      xp = (double *) *xpp;
7038    }
7039   /* copy the next block */
7040#pragma cdir loopcnt=LOOPCNT
7041#pragma cdir shortloop
7042    for (i=0; i<ni; i++) {
7043      tp[i] = (schar) Max( SCHAR_MIN, Min(SCHAR_MAX, (schar) xp[i]));
7044     /* test for range errors (not always needed but do it anyway) */
7045      nrange += xp[i] < SCHAR_MIN || xp[i] > SCHAR_MAX;
7046    }
7047   /* update xpp and tp */
7048    if (realign) xp = (double *) *xpp;
7049    xp += ni;
7050    tp += ni;
7051    *xpp = (void*)xp;
7052  }
7053  return nrange == 0 ? ENOERR : NC_ERANGE;
7054
7055#else   /* not SX */
7056        const char *xp = (const char *) *xpp;
7057        int status = ENOERR;
7058
7059        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
7060        {
7061                const int lstatus = ncx_get_double_schar(xp, tp);
7062                if(lstatus != ENOERR)
7063                        status = lstatus;
7064        }
7065
7066        *xpp = (const void *)xp;
7067        return status;
7068#  endif
7069}
7070
7071int
7072ncx_getn_double_uchar(const void **xpp, size_t nelems, uchar *tp)
7073{
7074#if _SX && \
7075           X_SIZEOF_DOUBLE == SIZEOF_DOUBLE
7076
7077 /* basic algorithm is:
7078  *   - ensure sane alignment of input data
7079  *   - copy (conversion happens automatically) input data
7080  *     to output
7081  *   - update xpp to point at next unconverted input, and tp to point
7082  *     at next location for converted output
7083  */
7084  long i, j, ni;
7085  double tmp[LOOPCNT];        /* in case input is misaligned */
7086  double *xp;
7087  int nrange = 0;         /* number of range errors */
7088  int realign = 0;        /* "do we need to fix input data alignment?" */
7089  long cxp = (long) *((char**)xpp);
7090
7091  realign = (cxp & 7) % SIZEOF_DOUBLE;
7092  /* sjl: manually stripmine so we can limit amount of
7093   * vector work space reserved to LOOPCNT elements. Also
7094   * makes vectorisation easy */
7095  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
7096    ni=Min(nelems-j,LOOPCNT);
7097    if (realign) {
7098      memcpy(tmp, *xpp, ni*SIZEOF_DOUBLE);
7099      xp = tmp;
7100    } else {
7101      xp = (double *) *xpp;
7102    }
7103   /* copy the next block */
7104#pragma cdir loopcnt=LOOPCNT
7105#pragma cdir shortloop
7106    for (i=0; i<ni; i++) {
7107      tp[i] = (uchar) Max( UCHAR_MIN, Min(UCHAR_MAX, (uchar) xp[i]));
7108     /* test for range errors (not always needed but do it anyway) */
7109      nrange += xp[i] < UCHAR_MIN || xp[i] > UCHAR_MAX;
7110    }
7111   /* update xpp and tp */
7112    if (realign) xp = (double *) *xpp;
7113    xp += ni;
7114    tp += ni;
7115    *xpp = (void*)xp;
7116  }
7117  return nrange == 0 ? ENOERR : NC_ERANGE;
7118
7119#else   /* not SX */
7120        const char *xp = (const char *) *xpp;
7121        int status = ENOERR;
7122
7123        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
7124        {
7125                const int lstatus = ncx_get_double_uchar(xp, tp);
7126                if(lstatus != ENOERR)
7127                        status = lstatus;
7128        }
7129
7130        *xpp = (const void *)xp;
7131        return status;
7132#  endif
7133}
7134
7135int
7136ncx_getn_double_short(const void **xpp, size_t nelems, short *tp)
7137{
7138#if _SX && \
7139           X_SIZEOF_DOUBLE == SIZEOF_DOUBLE
7140
7141 /* basic algorithm is:
7142  *   - ensure sane alignment of input data
7143  *   - copy (conversion happens automatically) input data
7144  *     to output
7145  *   - update xpp to point at next unconverted input, and tp to point
7146  *     at next location for converted output
7147  */
7148  long i, j, ni;
7149  double tmp[LOOPCNT];        /* in case input is misaligned */
7150  double *xp;
7151  int nrange = 0;         /* number of range errors */
7152  int realign = 0;        /* "do we need to fix input data alignment?" */
7153  long cxp = (long) *((char**)xpp);
7154
7155  realign = (cxp & 7) % SIZEOF_DOUBLE;
7156  /* sjl: manually stripmine so we can limit amount of
7157   * vector work space reserved to LOOPCNT elements. Also
7158   * makes vectorisation easy */
7159  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
7160    ni=Min(nelems-j,LOOPCNT);
7161    if (realign) {
7162      memcpy(tmp, *xpp, ni*SIZEOF_DOUBLE);
7163      xp = tmp;
7164    } else {
7165      xp = (double *) *xpp;
7166    }
7167   /* copy the next block */
7168#pragma cdir loopcnt=LOOPCNT
7169#pragma cdir shortloop
7170    for (i=0; i<ni; i++) {
7171      tp[i] = (short) Max( SHORT_MIN, Min(SHORT_MAX, (short) xp[i]));
7172     /* test for range errors (not always needed but do it anyway) */
7173      nrange += xp[i] < SHORT_MIN || xp[i] > SHORT_MAX;
7174    }
7175   /* update xpp and tp */
7176    if (realign) xp = (double *) *xpp;
7177    xp += ni;
7178    tp += ni;
7179    *xpp = (void*)xp;
7180  }
7181  return nrange == 0 ? ENOERR : NC_ERANGE;
7182
7183#else   /* not SX */
7184        const char *xp = (const char *) *xpp;
7185        int status = ENOERR;
7186
7187        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
7188        {
7189                const int lstatus = ncx_get_double_short(xp, tp);
7190                if(lstatus != ENOERR)
7191                        status = lstatus;
7192        }
7193
7194        *xpp = (const void *)xp;
7195        return status;
7196#  endif
7197}
7198
7199int
7200ncx_getn_double_int(const void **xpp, size_t nelems, int *tp)
7201{
7202#if _SX && \
7203           X_SIZEOF_DOUBLE == SIZEOF_DOUBLE
7204
7205 /* basic algorithm is:
7206  *   - ensure sane alignment of input data
7207  *   - copy (conversion happens automatically) input data
7208  *     to output
7209  *   - update xpp to point at next unconverted input, and tp to point
7210  *     at next location for converted output
7211  */
7212  long i, j, ni;
7213  double tmp[LOOPCNT];        /* in case input is misaligned */
7214  double *xp;
7215  int nrange = 0;         /* number of range errors */
7216  int realign = 0;        /* "do we need to fix input data alignment?" */
7217  long cxp = (long) *((char**)xpp);
7218
7219  realign = (cxp & 7) % SIZEOF_DOUBLE;
7220  /* sjl: manually stripmine so we can limit amount of
7221   * vector work space reserved to LOOPCNT elements. Also
7222   * makes vectorisation easy */
7223  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
7224    ni=Min(nelems-j,LOOPCNT);
7225    if (realign) {
7226      memcpy(tmp, *xpp, ni*SIZEOF_DOUBLE);
7227      xp = tmp;
7228    } else {
7229      xp = (double *) *xpp;
7230    }
7231   /* copy the next block */
7232#pragma cdir loopcnt=LOOPCNT
7233#pragma cdir shortloop
7234    for (i=0; i<ni; i++) {
7235      tp[i] = (int) Max( INT_MIN, Min(INT_MAX, (int) xp[i]));
7236     /* test for range errors (not always needed but do it anyway) */
7237      nrange += xp[i] < INT_MIN || xp[i] > INT_MAX;
7238    }
7239   /* update xpp and tp */
7240    if (realign) xp = (double *) *xpp;
7241    xp += ni;
7242    tp += ni;
7243    *xpp = (void*)xp;
7244  }
7245  return nrange == 0 ? ENOERR : NC_ERANGE;
7246
7247#else   /* not SX */
7248        const char *xp = (const char *) *xpp;
7249        int status = ENOERR;
7250
7251        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
7252        {
7253                const int lstatus = ncx_get_double_int(xp, tp);
7254                if(lstatus != ENOERR)
7255                        status = lstatus;
7256        }
7257
7258        *xpp = (const void *)xp;
7259        return status;
7260#  endif
7261}
7262
7263int
7264ncx_getn_double_float(const void **xpp, size_t nelems, float *tp)
7265{
7266#if _SX && \
7267           X_SIZEOF_DOUBLE == SIZEOF_DOUBLE
7268
7269 /* basic algorithm is:
7270  *   - ensure sane alignment of input data
7271  *   - copy (conversion happens automatically) input data
7272  *     to output
7273  *   - update xpp to point at next unconverted input, and tp to point
7274  *     at next location for converted output
7275  */
7276  long i, j, ni;
7277  double tmp[LOOPCNT];        /* in case input is misaligned */
7278  double *xp;
7279  int nrange = 0;         /* number of range errors */
7280  int realign = 0;        /* "do we need to fix input data alignment?" */
7281  long cxp = (long) *((char**)xpp);
7282
7283  realign = (cxp & 7) % SIZEOF_DOUBLE;
7284  /* sjl: manually stripmine so we can limit amount of
7285   * vector work space reserved to LOOPCNT elements. Also
7286   * makes vectorisation easy */
7287  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
7288    ni=Min(nelems-j,LOOPCNT);
7289    if (realign) {
7290      memcpy(tmp, *xpp, ni*SIZEOF_DOUBLE);
7291      xp = tmp;
7292    } else {
7293      xp = (double *) *xpp;
7294    }
7295   /* copy the next block */
7296#pragma cdir loopcnt=LOOPCNT
7297#pragma cdir shortloop
7298    for (i=0; i<ni; i++) {
7299      tp[i] = (float) Max( FLOAT_MIN, Min(FLOAT_MAX, (float) xp[i]));
7300     /* test for range errors (not always needed but do it anyway) */
7301      nrange += xp[i] < FLOAT_MIN || xp[i] > FLOAT_MAX;
7302    }
7303   /* update xpp and tp */
7304    if (realign) xp = (double *) *xpp;
7305    xp += ni;
7306    tp += ni;
7307    *xpp = (void*)xp;
7308  }
7309  return nrange == 0 ? ENOERR : NC_ERANGE;
7310
7311#else   /* not SX */
7312        const char *xp = (const char *) *xpp;
7313        int status = ENOERR;
7314
7315        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
7316        {
7317                const int lstatus = ncx_get_double_float(xp, tp);
7318                if(lstatus != ENOERR)
7319                        status = lstatus;
7320        }
7321
7322        *xpp = (const void *)xp;
7323        return status;
7324#  endif
7325}
7326
7327int
7328ncx_getn_double_uint(const void **xpp, size_t nelems, uint *tp)
7329{
7330#if _SX && \
7331           X_SIZEOF_DOUBLE == SIZEOF_DOUBLE
7332
7333 /* basic algorithm is:
7334  *   - ensure sane alignment of input data
7335  *   - copy (conversion happens automatically) input data
7336  *     to output
7337  *   - update xpp to point at next unconverted input, and tp to point
7338  *     at next location for converted output
7339  */
7340  long i, j, ni;
7341  double tmp[LOOPCNT];        /* in case input is misaligned */
7342  double *xp;
7343  int nrange = 0;         /* number of range errors */
7344  int realign = 0;        /* "do we need to fix input data alignment?" */
7345  long cxp = (long) *((char**)xpp);
7346
7347  realign = (cxp & 7) % SIZEOF_DOUBLE;
7348  /* sjl: manually stripmine so we can limit amount of
7349   * vector work space reserved to LOOPCNT elements. Also
7350   * makes vectorisation easy */
7351  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
7352    ni=Min(nelems-j,LOOPCNT);
7353    if (realign) {
7354      memcpy(tmp, *xpp, ni*SIZEOF_DOUBLE);
7355      xp = tmp;
7356    } else {
7357      xp = (double *) *xpp;
7358    }
7359   /* copy the next block */
7360#pragma cdir loopcnt=LOOPCNT
7361#pragma cdir shortloop
7362    for (i=0; i<ni; i++) {
7363      tp[i] = (uint) Max( UINT_MIN, Min(UINT_MAX, (uint) xp[i]));
7364     /* test for range errors (not always needed but do it anyway) */
7365      nrange += xp[i] < UINT_MIN || xp[i] > UINT_MAX;
7366    }
7367   /* update xpp and tp */
7368    if (realign) xp = (double *) *xpp;
7369    xp += ni;
7370    tp += ni;
7371    *xpp = (void*)xp;
7372  }
7373  return nrange == 0 ? ENOERR : NC_ERANGE;
7374
7375#else   /* not SX */
7376        const char *xp = (const char *) *xpp;
7377        int status = ENOERR;
7378
7379        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
7380        {
7381                const int lstatus = ncx_get_double_uint(xp, tp);
7382                if(lstatus != ENOERR)
7383                        status = lstatus;
7384        }
7385
7386        *xpp = (const void *)xp;
7387        return status;
7388#  endif
7389}
7390
7391int
7392ncx_getn_double_longlong(const void **xpp, size_t nelems, longlong *tp)
7393{
7394#if _SX && \
7395           X_SIZEOF_DOUBLE == SIZEOF_DOUBLE
7396
7397 /* basic algorithm is:
7398  *   - ensure sane alignment of input data
7399  *   - copy (conversion happens automatically) input data
7400  *     to output
7401  *   - update xpp to point at next unconverted input, and tp to point
7402  *     at next location for converted output
7403  */
7404  long i, j, ni;
7405  double tmp[LOOPCNT];        /* in case input is misaligned */
7406  double *xp;
7407  int nrange = 0;         /* number of range errors */
7408  int realign = 0;        /* "do we need to fix input data alignment?" */
7409  long cxp = (long) *((char**)xpp);
7410
7411  realign = (cxp & 7) % SIZEOF_DOUBLE;
7412  /* sjl: manually stripmine so we can limit amount of
7413   * vector work space reserved to LOOPCNT elements. Also
7414   * makes vectorisation easy */
7415  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
7416    ni=Min(nelems-j,LOOPCNT);
7417    if (realign) {
7418      memcpy(tmp, *xpp, ni*SIZEOF_DOUBLE);
7419      xp = tmp;
7420    } else {
7421      xp = (double *) *xpp;
7422    }
7423   /* copy the next block */
7424#pragma cdir loopcnt=LOOPCNT
7425#pragma cdir shortloop
7426    for (i=0; i<ni; i++) {
7427      tp[i] = (longlong) Max( LONGLONG_MIN, Min(LONGLONG_MAX, (longlong) xp[i]));
7428     /* test for range errors (not always needed but do it anyway) */
7429      nrange += xp[i] < LONGLONG_MIN || xp[i] > LONGLONG_MAX;
7430    }
7431   /* update xpp and tp */
7432    if (realign) xp = (double *) *xpp;
7433    xp += ni;
7434    tp += ni;
7435    *xpp = (void*)xp;
7436  }
7437  return nrange == 0 ? ENOERR : NC_ERANGE;
7438
7439#else   /* not SX */
7440        const char *xp = (const char *) *xpp;
7441        int status = ENOERR;
7442
7443        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
7444        {
7445                const int lstatus = ncx_get_double_longlong(xp, tp);
7446                if(lstatus != ENOERR)
7447                        status = lstatus;
7448        }
7449
7450        *xpp = (const void *)xp;
7451        return status;
7452#  endif
7453}
7454
7455int
7456ncx_getn_double_ulonglong(const void **xpp, size_t nelems, ulonglong *tp)
7457{
7458#if _SX && \
7459           X_SIZEOF_DOUBLE == SIZEOF_DOUBLE
7460
7461 /* basic algorithm is:
7462  *   - ensure sane alignment of input data
7463  *   - copy (conversion happens automatically) input data
7464  *     to output
7465  *   - update xpp to point at next unconverted input, and tp to point
7466  *     at next location for converted output
7467  */
7468  long i, j, ni;
7469  double tmp[LOOPCNT];        /* in case input is misaligned */
7470  double *xp;
7471  int nrange = 0;         /* number of range errors */
7472  int realign = 0;        /* "do we need to fix input data alignment?" */
7473  long cxp = (long) *((char**)xpp);
7474
7475  realign = (cxp & 7) % SIZEOF_DOUBLE;
7476  /* sjl: manually stripmine so we can limit amount of
7477   * vector work space reserved to LOOPCNT elements. Also
7478   * makes vectorisation easy */
7479  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
7480    ni=Min(nelems-j,LOOPCNT);
7481    if (realign) {
7482      memcpy(tmp, *xpp, ni*SIZEOF_DOUBLE);
7483      xp = tmp;
7484    } else {
7485      xp = (double *) *xpp;
7486    }
7487   /* copy the next block */
7488#pragma cdir loopcnt=LOOPCNT
7489#pragma cdir shortloop
7490    for (i=0; i<ni; i++) {
7491      tp[i] = (ulonglong) Max( ULONGLONG_MIN, Min(ULONGLONG_MAX, (ulonglong) xp[i]));
7492     /* test for range errors (not always needed but do it anyway) */
7493      nrange += xp[i] < ULONGLONG_MIN || xp[i] > ULONGLONG_MAX;
7494    }
7495   /* update xpp and tp */
7496    if (realign) xp = (double *) *xpp;
7497    xp += ni;
7498    tp += ni;
7499    *xpp = (void*)xp;
7500  }
7501  return nrange == 0 ? ENOERR : NC_ERANGE;
7502
7503#else   /* not SX */
7504        const char *xp = (const char *) *xpp;
7505        int status = ENOERR;
7506
7507        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
7508        {
7509                const int lstatus = ncx_get_double_ulonglong(xp, tp);
7510                if(lstatus != ENOERR)
7511                        status = lstatus;
7512        }
7513
7514        *xpp = (const void *)xp;
7515        return status;
7516#  endif
7517}
7518
7519#if X_SIZEOF_DOUBLE == SIZEOF_DOUBLE && !defined(NO_IEEE_FLOAT)
7520/* optimized version */
7521int
7522ncx_getn_double_double(const void **xpp, size_t nelems, double *tp)
7523{
7524#ifdef WORDS_BIGENDIAN
7525        (void) memcpy(tp, *xpp, nelems * sizeof(double));
7526# else
7527        swapn8b(tp, *xpp, nelems);
7528# endif
7529        *xpp = (const void *)((const char *)(*xpp) + nelems * X_SIZEOF_DOUBLE);
7530        return ENOERR;
7531}
7532#elif vax
7533int
7534ncx_getn_double_double(const void **xpp, size_t ndoubles, double *ip)
7535{
7536        double *const end = ip + ndoubles;
7537
7538        while(ip < end)
7539        {
7540        struct vax_double *const vdp =
7541                         (struct vax_double *)ip;
7542        const struct ieee_double *const idp =
7543                         (const struct ieee_double *) (*xpp);
7544        {
7545                const struct dbl_limits *lim;
7546                int ii;
7547                for (ii = 0, lim = dbl_limits;
7548                        ii < sizeof(dbl_limits)/sizeof(struct dbl_limits);
7549                        ii++, lim++)
7550                {
7551                        if ((idp->mant_lo == lim->ieee.mant_lo)
7552                                && (idp->mant_4 == lim->ieee.mant_4)
7553                                && (idp->mant_5 == lim->ieee.mant_5)
7554                                && (idp->mant_6 == lim->ieee.mant_6)
7555                                && (idp->exp_lo == lim->ieee.exp_lo)
7556                                && (idp->exp_hi == lim->ieee.exp_hi)
7557                                )
7558                        {
7559                                *vdp = lim->d;
7560                                goto doneit;
7561                        }
7562                }
7563        }
7564        {
7565                unsigned exp = idp->exp_hi << 4 | idp->exp_lo;
7566                vdp->exp = exp - IEEE_DBL_BIAS + VAX_DBL_BIAS;
7567        }
7568        {
7569                unsigned mant_hi = ((idp->mant_6 << 16)
7570                                 | (idp->mant_5 << 8)
7571                                 | idp->mant_4);
7572                unsigned mant_lo = SWAP4(idp->mant_lo);
7573                vdp->mantissa1 = (mant_hi >> 13);
7574                vdp->mantissa2 = ((mant_hi & MASK(13)) << 3)
7575                                | (mant_lo >> 29);
7576                vdp->mantissa3 = (mant_lo >> 13);
7577                vdp->mantissa4 = (mant_lo << 3);
7578        }
7579        doneit:
7580                vdp->sign = idp->sign;
7581
7582                ip++;
7583                *xpp = (char *)(*xpp) + X_SIZEOF_DOUBLE;
7584        }
7585        return ENOERR;
7586}
7587        /* vax */
7588#else
7589int
7590ncx_getn_double_double(const void **xpp, size_t nelems, double *tp)
7591{
7592        const char *xp = *xpp;
7593        int status = ENOERR;
7594
7595        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
7596        {
7597                const int lstatus = ncx_get_double_double(xp, tp);
7598                if(lstatus != ENOERR)
7599                        status = lstatus;
7600        }
7601
7602        *xpp = (const void *)xp;
7603        return status;
7604}
7605
7606#endif
7607
7608int
7609ncx_putn_double_schar(void **xpp, size_t nelems, const schar *tp)
7610{
7611#if _SX && \
7612           X_SIZEOF_DOUBLE == SIZEOF_DOUBLE
7613
7614 /* basic algorithm is:
7615  *   - ensure sane alignment of output data
7616  *   - copy (conversion happens automatically) input data
7617  *     to output
7618  *   - update tp to point at next unconverted input, and xpp to point
7619  *     at next location for converted output
7620  */
7621  long i, j, ni;
7622  double tmp[LOOPCNT];        /* in case input is misaligned */
7623  double *xp;
7624  int nrange = 0;         /* number of range errors */
7625  int realign = 0;        /* "do we need to fix input data alignment?" */
7626  long cxp = (long) *((char**)xpp);
7627
7628  realign = (cxp & 7) % SIZEOF_DOUBLE;
7629  /* sjl: manually stripmine so we can limit amount of
7630   * vector work space reserved to LOOPCNT elements. Also
7631   * makes vectorisation easy */
7632  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
7633    ni=Min(nelems-j,LOOPCNT);
7634    if (realign) {
7635      xp = tmp;
7636    } else {
7637      xp = (double *) *xpp;
7638    }
7639   /* copy the next block */
7640#pragma cdir loopcnt=LOOPCNT
7641#pragma cdir shortloop
7642    for (i=0; i<ni; i++) {
7643      /* the normal case: */
7644      xp[i] = (double) Max( X_DOUBLE_MIN, Min(X_DOUBLE_MAX, (double) tp[i]));
7645     /* test for range errors (not always needed but do it anyway) */
7646      nrange += tp[i] < X_DOUBLE_MIN || tp[i] > X_DOUBLE_MAX;
7647    }
7648   /* copy workspace back if necessary */ 
7649    if (realign) {
7650      memcpy(*xpp, tmp, ni*X_SIZEOF_DOUBLE);
7651      xp = (double *) *xpp;
7652    }
7653   /* update xpp and tp */
7654    xp += ni;
7655    tp += ni;
7656    *xpp = (void*)xp;
7657  }
7658  return nrange == 0 ? ENOERR : NC_ERANGE;
7659
7660#else   /* not SX */
7661
7662        char *xp = (char *) *xpp;
7663        int status = ENOERR;
7664
7665        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
7666        {
7667                int lstatus = ncx_put_double_schar(xp, tp);
7668                if(lstatus != ENOERR)
7669                        status = lstatus;
7670        }
7671
7672        *xpp = (void *)xp;
7673        return status;
7674#endif
7675}
7676
7677int
7678ncx_putn_double_uchar(void **xpp, size_t nelems, const uchar *tp)
7679{
7680#if _SX && \
7681           X_SIZEOF_DOUBLE == SIZEOF_DOUBLE
7682
7683 /* basic algorithm is:
7684  *   - ensure sane alignment of output data
7685  *   - copy (conversion happens automatically) input data
7686  *     to output
7687  *   - update tp to point at next unconverted input, and xpp to point
7688  *     at next location for converted output
7689  */
7690  long i, j, ni;
7691  double tmp[LOOPCNT];        /* in case input is misaligned */
7692  double *xp;
7693  int nrange = 0;         /* number of range errors */
7694  int realign = 0;        /* "do we need to fix input data alignment?" */
7695  long cxp = (long) *((char**)xpp);
7696
7697  realign = (cxp & 7) % SIZEOF_DOUBLE;
7698  /* sjl: manually stripmine so we can limit amount of
7699   * vector work space reserved to LOOPCNT elements. Also
7700   * makes vectorisation easy */
7701  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
7702    ni=Min(nelems-j,LOOPCNT);
7703    if (realign) {
7704      xp = tmp;
7705    } else {
7706      xp = (double *) *xpp;
7707    }
7708   /* copy the next block */
7709#pragma cdir loopcnt=LOOPCNT
7710#pragma cdir shortloop
7711    for (i=0; i<ni; i++) {
7712      /* the normal case: */
7713      xp[i] = (double) Max( X_DOUBLE_MIN, Min(X_DOUBLE_MAX, (double) tp[i]));
7714     /* test for range errors (not always needed but do it anyway) */
7715      nrange += tp[i] < X_DOUBLE_MIN || tp[i] > X_DOUBLE_MAX;
7716    }
7717   /* copy workspace back if necessary */ 
7718    if (realign) {
7719      memcpy(*xpp, tmp, ni*X_SIZEOF_DOUBLE);
7720      xp = (double *) *xpp;
7721    }
7722   /* update xpp and tp */
7723    xp += ni;
7724    tp += ni;
7725    *xpp = (void*)xp;
7726  }
7727  return nrange == 0 ? ENOERR : NC_ERANGE;
7728
7729#else   /* not SX */
7730
7731        char *xp = (char *) *xpp;
7732        int status = ENOERR;
7733
7734        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
7735        {
7736                int lstatus = ncx_put_double_uchar(xp, tp);
7737                if(lstatus != ENOERR)
7738                        status = lstatus;
7739        }
7740
7741        *xpp = (void *)xp;
7742        return status;
7743#endif
7744}
7745
7746int
7747ncx_putn_double_short(void **xpp, size_t nelems, const short *tp)
7748{
7749#if _SX && \
7750           X_SIZEOF_DOUBLE == SIZEOF_DOUBLE
7751
7752 /* basic algorithm is:
7753  *   - ensure sane alignment of output data
7754  *   - copy (conversion happens automatically) input data
7755  *     to output
7756  *   - update tp to point at next unconverted input, and xpp to point
7757  *     at next location for converted output
7758  */
7759  long i, j, ni;
7760  double tmp[LOOPCNT];        /* in case input is misaligned */
7761  double *xp;
7762  int nrange = 0;         /* number of range errors */
7763  int realign = 0;        /* "do we need to fix input data alignment?" */
7764  long cxp = (long) *((char**)xpp);
7765
7766  realign = (cxp & 7) % SIZEOF_DOUBLE;
7767  /* sjl: manually stripmine so we can limit amount of
7768   * vector work space reserved to LOOPCNT elements. Also
7769   * makes vectorisation easy */
7770  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
7771    ni=Min(nelems-j,LOOPCNT);
7772    if (realign) {
7773      xp = tmp;
7774    } else {
7775      xp = (double *) *xpp;
7776    }
7777   /* copy the next block */
7778#pragma cdir loopcnt=LOOPCNT
7779#pragma cdir shortloop
7780    for (i=0; i<ni; i++) {
7781      /* the normal case: */
7782      xp[i] = (double) Max( X_DOUBLE_MIN, Min(X_DOUBLE_MAX, (double) tp[i]));
7783     /* test for range errors (not always needed but do it anyway) */
7784      nrange += tp[i] < X_DOUBLE_MIN || tp[i] > X_DOUBLE_MAX;
7785    }
7786   /* copy workspace back if necessary */ 
7787    if (realign) {
7788      memcpy(*xpp, tmp, ni*X_SIZEOF_DOUBLE);
7789      xp = (double *) *xpp;
7790    }
7791   /* update xpp and tp */
7792    xp += ni;
7793    tp += ni;
7794    *xpp = (void*)xp;
7795  }
7796  return nrange == 0 ? ENOERR : NC_ERANGE;
7797
7798#else   /* not SX */
7799
7800        char *xp = (char *) *xpp;
7801        int status = ENOERR;
7802
7803        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
7804        {
7805                int lstatus = ncx_put_double_short(xp, tp);
7806                if(lstatus != ENOERR)
7807                        status = lstatus;
7808        }
7809
7810        *xpp = (void *)xp;
7811        return status;
7812#endif
7813}
7814
7815int
7816ncx_putn_double_int(void **xpp, size_t nelems, const int *tp)
7817{
7818#if _SX && \
7819           X_SIZEOF_DOUBLE == SIZEOF_DOUBLE
7820
7821 /* basic algorithm is:
7822  *   - ensure sane alignment of output data
7823  *   - copy (conversion happens automatically) input data
7824  *     to output
7825  *   - update tp to point at next unconverted input, and xpp to point
7826  *     at next location for converted output
7827  */
7828  long i, j, ni;
7829  double tmp[LOOPCNT];        /* in case input is misaligned */
7830  double *xp;
7831  int nrange = 0;         /* number of range errors */
7832  int realign = 0;        /* "do we need to fix input data alignment?" */
7833  long cxp = (long) *((char**)xpp);
7834
7835  realign = (cxp & 7) % SIZEOF_DOUBLE;
7836  /* sjl: manually stripmine so we can limit amount of
7837   * vector work space reserved to LOOPCNT elements. Also
7838   * makes vectorisation easy */
7839  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
7840    ni=Min(nelems-j,LOOPCNT);
7841    if (realign) {
7842      xp = tmp;
7843    } else {
7844      xp = (double *) *xpp;
7845    }
7846   /* copy the next block */
7847#pragma cdir loopcnt=LOOPCNT
7848#pragma cdir shortloop
7849    for (i=0; i<ni; i++) {
7850      /* the normal case: */
7851      xp[i] = (double) Max( X_DOUBLE_MIN, Min(X_DOUBLE_MAX, (double) tp[i]));
7852     /* test for range errors (not always needed but do it anyway) */
7853      nrange += tp[i] < X_DOUBLE_MIN || tp[i] > X_DOUBLE_MAX;
7854    }
7855   /* copy workspace back if necessary */ 
7856    if (realign) {
7857      memcpy(*xpp, tmp, ni*X_SIZEOF_DOUBLE);
7858      xp = (double *) *xpp;
7859    }
7860   /* update xpp and tp */
7861    xp += ni;
7862    tp += ni;
7863    *xpp = (void*)xp;
7864  }
7865  return nrange == 0 ? ENOERR : NC_ERANGE;
7866
7867#else   /* not SX */
7868
7869        char *xp = (char *) *xpp;
7870        int status = ENOERR;
7871
7872        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
7873        {
7874                int lstatus = ncx_put_double_int(xp, tp);
7875                if(lstatus != ENOERR)
7876                        status = lstatus;
7877        }
7878
7879        *xpp = (void *)xp;
7880        return status;
7881#endif
7882}
7883
7884int
7885ncx_putn_double_float(void **xpp, size_t nelems, const float *tp)
7886{
7887#if _SX && \
7888           X_SIZEOF_DOUBLE == SIZEOF_DOUBLE
7889
7890 /* basic algorithm is:
7891  *   - ensure sane alignment of output data
7892  *   - copy (conversion happens automatically) input data
7893  *     to output
7894  *   - update tp to point at next unconverted input, and xpp to point
7895  *     at next location for converted output
7896  */
7897  long i, j, ni;
7898  double tmp[LOOPCNT];        /* in case input is misaligned */
7899  double *xp;
7900  int nrange = 0;         /* number of range errors */
7901  int realign = 0;        /* "do we need to fix input data alignment?" */
7902  long cxp = (long) *((char**)xpp);
7903
7904  realign = (cxp & 7) % SIZEOF_DOUBLE;
7905  /* sjl: manually stripmine so we can limit amount of
7906   * vector work space reserved to LOOPCNT elements. Also
7907   * makes vectorisation easy */
7908  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
7909    ni=Min(nelems-j,LOOPCNT);
7910    if (realign) {
7911      xp = tmp;
7912    } else {
7913      xp = (double *) *xpp;
7914    }
7915   /* copy the next block */
7916#pragma cdir loopcnt=LOOPCNT
7917#pragma cdir shortloop
7918    for (i=0; i<ni; i++) {
7919      /* the normal case: */
7920      xp[i] = (double) Max( X_DOUBLE_MIN, Min(X_DOUBLE_MAX, (double) tp[i]));
7921     /* test for range errors (not always needed but do it anyway) */
7922      nrange += tp[i] < X_DOUBLE_MIN || tp[i] > X_DOUBLE_MAX;
7923    }
7924   /* copy workspace back if necessary */ 
7925    if (realign) {
7926      memcpy(*xpp, tmp, ni*X_SIZEOF_DOUBLE);
7927      xp = (double *) *xpp;
7928    }
7929   /* update xpp and tp */
7930    xp += ni;
7931    tp += ni;
7932    *xpp = (void*)xp;
7933  }
7934  return nrange == 0 ? ENOERR : NC_ERANGE;
7935
7936#else   /* not SX */
7937
7938        char *xp = (char *) *xpp;
7939        int status = ENOERR;
7940
7941        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
7942        {
7943                int lstatus = ncx_put_double_float(xp, tp);
7944                if(lstatus != ENOERR)
7945                        status = lstatus;
7946        }
7947
7948        *xpp = (void *)xp;
7949        return status;
7950#endif
7951}
7952
7953int
7954ncx_putn_double_uint(void **xpp, size_t nelems, const uint *tp)
7955{
7956#if _SX && \
7957           X_SIZEOF_DOUBLE == SIZEOF_DOUBLE
7958
7959 /* basic algorithm is:
7960  *   - ensure sane alignment of output data
7961  *   - copy (conversion happens automatically) input data
7962  *     to output
7963  *   - update tp to point at next unconverted input, and xpp to point
7964  *     at next location for converted output
7965  */
7966  long i, j, ni;
7967  double tmp[LOOPCNT];        /* in case input is misaligned */
7968  double *xp;
7969  int nrange = 0;         /* number of range errors */
7970  int realign = 0;        /* "do we need to fix input data alignment?" */
7971  long cxp = (long) *((char**)xpp);
7972
7973  realign = (cxp & 7) % SIZEOF_DOUBLE;
7974  /* sjl: manually stripmine so we can limit amount of
7975   * vector work space reserved to LOOPCNT elements. Also
7976   * makes vectorisation easy */
7977  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
7978    ni=Min(nelems-j,LOOPCNT);
7979    if (realign) {
7980      xp = tmp;
7981    } else {
7982      xp = (double *) *xpp;
7983    }
7984   /* copy the next block */
7985#pragma cdir loopcnt=LOOPCNT
7986#pragma cdir shortloop
7987    for (i=0; i<ni; i++) {
7988      /* the normal case: */
7989      xp[i] = (double) Max( X_DOUBLE_MIN, Min(X_DOUBLE_MAX, (double) tp[i]));
7990     /* test for range errors (not always needed but do it anyway) */
7991      nrange += tp[i] < X_DOUBLE_MIN || tp[i] > X_DOUBLE_MAX;
7992    }
7993   /* copy workspace back if necessary */ 
7994    if (realign) {
7995      memcpy(*xpp, tmp, ni*X_SIZEOF_DOUBLE);
7996      xp = (double *) *xpp;
7997    }
7998   /* update xpp and tp */
7999    xp += ni;
8000    tp += ni;
8001    *xpp = (void*)xp;
8002  }
8003  return nrange == 0 ? ENOERR : NC_ERANGE;
8004
8005#else   /* not SX */
8006
8007        char *xp = (char *) *xpp;
8008        int status = ENOERR;
8009
8010        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
8011        {
8012                int lstatus = ncx_put_double_uint(xp, tp);
8013                if(lstatus != ENOERR)
8014                        status = lstatus;
8015        }
8016
8017        *xpp = (void *)xp;
8018        return status;
8019#endif
8020}
8021
8022int
8023ncx_putn_double_longlong(void **xpp, size_t nelems, const longlong *tp)
8024{
8025#if _SX && \
8026           X_SIZEOF_DOUBLE == SIZEOF_DOUBLE
8027
8028 /* basic algorithm is:
8029  *   - ensure sane alignment of output data
8030  *   - copy (conversion happens automatically) input data
8031  *     to output
8032  *   - update tp to point at next unconverted input, and xpp to point
8033  *     at next location for converted output
8034  */
8035  long i, j, ni;
8036  double tmp[LOOPCNT];        /* in case input is misaligned */
8037  double *xp;
8038  int nrange = 0;         /* number of range errors */
8039  int realign = 0;        /* "do we need to fix input data alignment?" */
8040  long cxp = (long) *((char**)xpp);
8041
8042  realign = (cxp & 7) % SIZEOF_DOUBLE;
8043  /* sjl: manually stripmine so we can limit amount of
8044   * vector work space reserved to LOOPCNT elements. Also
8045   * makes vectorisation easy */
8046  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
8047    ni=Min(nelems-j,LOOPCNT);
8048    if (realign) {
8049      xp = tmp;
8050    } else {
8051      xp = (double *) *xpp;
8052    }
8053   /* copy the next block */
8054#pragma cdir loopcnt=LOOPCNT
8055#pragma cdir shortloop
8056    for (i=0; i<ni; i++) {
8057      /* the normal case: */
8058      xp[i] = (double) Max( X_DOUBLE_MIN, Min(X_DOUBLE_MAX, (double) tp[i]));
8059     /* test for range errors (not always needed but do it anyway) */
8060      nrange += tp[i] < X_DOUBLE_MIN || tp[i] > X_DOUBLE_MAX;
8061    }
8062   /* copy workspace back if necessary */ 
8063    if (realign) {
8064      memcpy(*xpp, tmp, ni*X_SIZEOF_DOUBLE);
8065      xp = (double *) *xpp;
8066    }
8067   /* update xpp and tp */
8068    xp += ni;
8069    tp += ni;
8070    *xpp = (void*)xp;
8071  }
8072  return nrange == 0 ? ENOERR : NC_ERANGE;
8073
8074#else   /* not SX */
8075
8076        char *xp = (char *) *xpp;
8077        int status = ENOERR;
8078
8079        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
8080        {
8081                int lstatus = ncx_put_double_longlong(xp, tp);
8082                if(lstatus != ENOERR)
8083                        status = lstatus;
8084        }
8085
8086        *xpp = (void *)xp;
8087        return status;
8088#endif
8089}
8090
8091int
8092ncx_putn_double_ulonglong(void **xpp, size_t nelems, const ulonglong *tp)
8093{
8094#if _SX && \
8095           X_SIZEOF_DOUBLE == SIZEOF_DOUBLE
8096
8097 /* basic algorithm is:
8098  *   - ensure sane alignment of output data
8099  *   - copy (conversion happens automatically) input data
8100  *     to output
8101  *   - update tp to point at next unconverted input, and xpp to point
8102  *     at next location for converted output
8103  */
8104  long i, j, ni;
8105  double tmp[LOOPCNT];        /* in case input is misaligned */
8106  double *xp;
8107  int nrange = 0;         /* number of range errors */
8108  int realign = 0;        /* "do we need to fix input data alignment?" */
8109  long cxp = (long) *((char**)xpp);
8110
8111  realign = (cxp & 7) % SIZEOF_DOUBLE;
8112  /* sjl: manually stripmine so we can limit amount of
8113   * vector work space reserved to LOOPCNT elements. Also
8114   * makes vectorisation easy */
8115  for (j=0; j<nelems && nrange==0; j+=LOOPCNT) {
8116    ni=Min(nelems-j,LOOPCNT);
8117    if (realign) {
8118      xp = tmp;
8119    } else {
8120      xp = (double *) *xpp;
8121    }
8122   /* copy the next block */
8123#pragma cdir loopcnt=LOOPCNT
8124#pragma cdir shortloop
8125    for (i=0; i<ni; i++) {
8126      /* the normal case: */
8127      xp[i] = (double) Max( X_DOUBLE_MIN, Min(X_DOUBLE_MAX, (double) tp[i]));
8128     /* test for range errors (not always needed but do it anyway) */
8129      nrange += tp[i] < X_DOUBLE_MIN || tp[i] > X_DOUBLE_MAX;
8130    }
8131   /* copy workspace back if necessary */ 
8132    if (realign) {
8133      memcpy(*xpp, tmp, ni*X_SIZEOF_DOUBLE);
8134      xp = (double *) *xpp;
8135    }
8136   /* update xpp and tp */
8137    xp += ni;
8138    tp += ni;
8139    *xpp = (void*)xp;
8140  }
8141  return nrange == 0 ? ENOERR : NC_ERANGE;
8142
8143#else   /* not SX */
8144
8145        char *xp = (char *) *xpp;
8146        int status = ENOERR;
8147
8148        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
8149        {
8150                int lstatus = ncx_put_double_ulonglong(xp, tp);
8151                if(lstatus != ENOERR)
8152                        status = lstatus;
8153        }
8154
8155        *xpp = (void *)xp;
8156        return status;
8157#endif
8158}
8159
8160#if X_SIZEOF_DOUBLE == SIZEOF_DOUBLE && !defined(NO_IEEE_FLOAT)
8161/* optimized version */
8162int
8163ncx_putn_double_double(void **xpp, size_t nelems, const double *tp)
8164{
8165#ifdef WORDS_BIGENDIAN
8166        (void) memcpy(*xpp, tp, nelems * X_SIZEOF_DOUBLE);
8167# else
8168        swapn8b(*xpp, tp, nelems);
8169# endif
8170        *xpp = (void *)((char *)(*xpp) + nelems * X_SIZEOF_DOUBLE);
8171        return ENOERR;
8172}
8173#elif vax
8174int
8175ncx_putn_double_double(void **xpp, size_t ndoubles, const double *ip)
8176{
8177        const double *const end = ip + ndoubles;
8178
8179        while(ip < end)
8180        {
8181        const struct vax_double *const vdp = 
8182                        (const struct vax_double *)ip;
8183        struct ieee_double *const idp =
8184                         (struct ieee_double *) (*xpp);
8185
8186        if ((vdp->mantissa4 > (dbl_limits[0].d.mantissa4 - 3)) &&
8187                (vdp->mantissa3 == dbl_limits[0].d.mantissa3) &&
8188                (vdp->mantissa2 == dbl_limits[0].d.mantissa2) &&
8189                (vdp->mantissa1 == dbl_limits[0].d.mantissa1) &&
8190                (vdp->exp == dbl_limits[0].d.exp))
8191        {
8192                *idp = dbl_limits[0].ieee;
8193                goto shipit;
8194        }
8195        if ((vdp->mantissa4 == dbl_limits[1].d.mantissa4) &&
8196                (vdp->mantissa3 == dbl_limits[1].d.mantissa3) &&
8197                (vdp->mantissa2 == dbl_limits[1].d.mantissa2) &&
8198                (vdp->mantissa1 == dbl_limits[1].d.mantissa1) &&
8199                (vdp->exp == dbl_limits[1].d.exp))
8200        {
8201                *idp = dbl_limits[1].ieee;
8202                goto shipit;
8203        }
8204
8205        {
8206                unsigned exp = vdp->exp - VAX_DBL_BIAS + IEEE_DBL_BIAS;
8207
8208                unsigned mant_lo = ((vdp->mantissa2 & MASK(3)) << 29) |
8209                        (vdp->mantissa3 << 13) |
8210                        ((vdp->mantissa4 >> 3) & MASK(13));
8211
8212                unsigned mant_hi = (vdp->mantissa1 << 13)
8213                                 | (vdp->mantissa2 >> 3);
8214
8215                if((vdp->mantissa4 & 7) > 4)
8216                {
8217                        /* round up */
8218                        mant_lo++;
8219                        if(mant_lo == 0)
8220                        {
8221                                mant_hi++;
8222                                if(mant_hi > 0xffffff)
8223                                {
8224                                        mant_hi = 0;
8225                                        exp++;
8226                                }
8227                        }
8228                }
8229
8230                idp->mant_lo = SWAP4(mant_lo);
8231                idp->mant_6 = mant_hi >> 16;
8232                idp->mant_5 = (mant_hi & 0xff00) >> 8;
8233                idp->mant_4 = mant_hi;
8234                idp->exp_hi = exp >> 4;
8235                idp->exp_lo = exp;
8236        }
8237               
8238        shipit:
8239                idp->sign = vdp->sign;
8240
8241                ip++;
8242                *xpp = (char *)(*xpp) + X_SIZEOF_DOUBLE;
8243        }
8244        return ENOERR;
8245}
8246        /* vax */
8247#else
8248int
8249ncx_putn_double_double(void **xpp, size_t nelems, const double *tp)
8250{
8251        char *xp = *xpp;
8252        int status = ENOERR;
8253
8254        for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++)
8255        {
8256                int lstatus = ncx_put_double_double(xp, tp);
8257                if(lstatus != ENOERR)
8258                        status = lstatus;
8259        }
8260
8261        *xpp = (void *)xp;
8262        return status;
8263}
8264
8265#endif
8266
8267
8268/*
8269 * Other aggregate conversion functions.
8270 */
8271
8272/* text */
8273
8274int
8275ncx_getn_text(const void **xpp, size_t nelems, char *tp)
8276{
8277        (void) memcpy(tp, *xpp, nelems);
8278        *xpp = (void *)((char *)(*xpp) + nelems);
8279        return ENOERR;
8280
8281}
8282
8283int
8284ncx_pad_getn_text(const void **xpp, size_t nelems, char *tp)
8285{
8286        size_t rndup = nelems % X_ALIGN;
8287
8288        if(rndup)
8289                rndup = X_ALIGN - rndup;
8290
8291        (void) memcpy(tp, *xpp, nelems);
8292        *xpp = (void *)((char *)(*xpp) + nelems + rndup);
8293
8294        return ENOERR;
8295
8296}
8297
8298int
8299ncx_putn_text(void **xpp, size_t nelems, const char *tp)
8300{
8301        (void) memcpy(*xpp, tp, nelems);
8302        *xpp = (void *)((char *)(*xpp) + nelems);
8303
8304        return ENOERR;
8305
8306}
8307
8308int
8309ncx_pad_putn_text(void **xpp, size_t nelems, const char *tp)
8310{
8311        size_t rndup = nelems % X_ALIGN;
8312
8313        if(rndup)
8314                rndup = X_ALIGN - rndup;
8315
8316        (void) memcpy(*xpp, tp, nelems);
8317        *xpp = (void *)((char *)(*xpp) + nelems);
8318
8319        if(rndup)
8320        {
8321                (void) memcpy(*xpp, nada, rndup);
8322                *xpp = (void *)((char *)(*xpp) + rndup);
8323        }
8324       
8325        return ENOERR;
8326
8327}
8328
8329
8330/* opaque */
8331
8332int
8333ncx_getn_void(const void **xpp, size_t nelems, void *tp)
8334{
8335        (void) memcpy(tp, *xpp, nelems);
8336        *xpp = (void *)((char *)(*xpp) + nelems);
8337        return ENOERR;
8338
8339}
8340
8341int
8342ncx_pad_getn_void(const void **xpp, size_t nelems, void *tp)
8343{
8344        size_t rndup = nelems % X_ALIGN;
8345
8346        if(rndup)
8347                rndup = X_ALIGN - rndup;
8348
8349        (void) memcpy(tp, *xpp, nelems);
8350        *xpp = (void *)((char *)(*xpp) + nelems + rndup);
8351
8352        return ENOERR;
8353
8354}
8355
8356int
8357ncx_putn_void(void **xpp, size_t nelems, const void *tp)
8358{
8359        (void) memcpy(*xpp, tp, nelems);
8360        *xpp = (void *)((char *)(*xpp) + nelems);
8361
8362        return ENOERR;
8363
8364}
8365
8366int
8367ncx_pad_putn_void(void **xpp, size_t nelems, const void *tp)
8368{
8369        size_t rndup = nelems % X_ALIGN;
8370
8371        if(rndup)
8372                rndup = X_ALIGN - rndup;
8373
8374        (void) memcpy(*xpp, tp, nelems);
8375        *xpp = (void *)((char *)(*xpp) + nelems);
8376
8377        if(rndup)
8378        {
8379                (void) memcpy(*xpp, nada, rndup);
8380                *xpp = (void *)((char *)(*xpp) + rndup);
8381        }
8382       
8383        return ENOERR;
8384
8385}
Note: See TracBrowser for help on using the repository browser.