Use "unsigned __int{16,32}" types for Windows in load_{16,32}_n, per Kevin
[krb5.git] / src / include / k5-platform.h
1 /*
2  * k5-platform.h
3  *
4  * Copyright 2003, 2004, 2005 Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  * 
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  * 
26  *
27  * Some platform-dependent definitions to sync up the C support level.
28  * Some to a C99-ish level, some related utility code.
29  *
30  * Currently:
31  * + make "static inline" work
32  * + 64-bit types and load/store code
33  * + SIZE_MAX
34  * + shared library init/fini hooks
35  * + consistent getpwnam/getpwuid interfaces
36  */
37
38 #ifndef K5_PLATFORM_H
39 #define K5_PLATFORM_H
40
41 #include "autoconf.h"
42 /* for memcpy */
43 #include <string.h>
44
45 /* Initialization and finalization function support for libraries.
46
47    At top level, before the functions are defined or even declared:
48    MAKE_INIT_FUNCTION(init_fn);
49    MAKE_FINI_FUNCTION(fini_fn);
50    Then:
51    int init_fn(void) { ... }
52    void fini_fn(void) { if (INITIALIZER_RAN(init_fn)) ... }
53    In code, in the same file:
54    err = CALL_INIT_FUNCTION(init_fn);
55
56    To trigger or verify the initializer invocation from another file,
57    a helper function must be created.
58
59    This model handles both the load-time execution (Windows) and
60    delayed execution (pthread_once) approaches, and should be able to
61    guarantee in both cases that the init function is run once, in one
62    thread, before other stuff in the library is done; furthermore, the
63    finalization code should only run if the initialization code did.
64    (Maybe I could've made the "if INITIALIZER_RAN" test implicit, via
65    another function hidden in macros, but this is hairy enough
66    already.)
67
68    The init_fn and fini_fn names should be chosen such that any
69    exported names staring with those names, and optionally followed by
70    additional characters, fits in with any namespace constraints on
71    the library in question.
72
73
74    There's also PROGRAM_EXITING() currently always defined as zero.
75    If there's some trivial way to find out if the fini function is
76    being called because the program that the library is linked into is
77    exiting, we can just skip all the work because the resources are
78    about to be freed up anyways.  Generally this is likely to be the
79    same as distinguishing whether the library was loaded dynamically
80    while the program was running, or loaded as part of program
81    startup.  On most platforms, I don't think we can distinguish these
82    cases easily, and it's probably not worth expending any significant
83    effort.  (Note in particular that atexit() won't do, because if the
84    library is explicitly loaded and unloaded, it would have to be able
85    to deregister the atexit callback function.  Also, the system limit
86    on atexit callbacks may be small.)
87
88
89    Implementation outline:
90
91    Windows: MAKE_FINI_FUNCTION creates a symbol with a magic name that
92    is sought at library build time, and code is added to invoke the
93    function when the library is unloaded.  MAKE_INIT_FUNCTION does
94    likewise, but the function is invoked when the library is loaded,
95    and an extra variable is declared to hold an error code and a "yes
96    the initializer ran" flag.  CALL_INIT_FUNCTION blows up if the flag
97    isn't set, otherwise returns the error code.
98
99    UNIX: MAKE_INIT_FUNCTION creates and initializes a variable with a
100    name derived from the function name, containing a k5_once_t
101    (pthread_once_t or int), an error code, and a pointer to the
102    function.  The function itself is declared static, but the
103    associated variable has external linkage.  CALL_INIT_FUNCTION
104    ensures thath the function is called exactly once (pthread_once or
105    just check the flag) and returns the stored error code (or the
106    pthread_once error).
107
108    (That's the basic idea.  With some debugging assert() calls and
109    such, it's a bit more complicated.  And we also need to handle
110    doing the pthread test at run time on systems where that works, so
111    we use the k5_once_t stuff instead.)
112
113    UNIX, with compiler support: MAKE_FINI_FUNCTION declares the
114    function as a destructor, and the run time linker support or
115    whatever will cause it to be invoked when the library is unloaded,
116    the program ends, etc.
117
118    UNIX, with linker support: MAKE_FINI_FUNCTION creates a symbol with
119    a magic name that is sought at library build time, and linker
120    options are used to mark it as a finalization function for the
121    library.  The symbol must be exported.
122
123    UNIX, no library finalization support: The finalization function
124    never runs, and we leak memory.  Tough.
125
126    DELAY_INITIALIZER will be defined by the configure script if we
127    want to use k5_once instead of load-time initialization.  That'll
128    be the preferred method on most systems except Windows, where we
129    have to initialize some mutexes.
130
131
132
133
134    For maximum flexibility in defining the macros, the function name
135    parameter should be a simple name, not even a macro defined as
136    another name.  The function should have a unique name, and should
137    conform to whatever namespace is used by the library in question.
138    (We do have export lists, but (1) they're not used for all
139    platforms, and (2) they're not used for static libraries.)
140
141    If the macro expansion needs the function to have been declared, it
142    must include a declaration.  If it is not necessary for the symbol
143    name to be exported from the object file, the macro should declare
144    it as "static".  Hence the signature must exactly match "void
145    foo(void)".  (ANSI C allows a static declaration followed by a
146    non-static one; the result is internal linkage.)  The macro
147    expansion has to come before the function, because gcc apparently
148    won't act on "__attribute__((constructor))" if it comes after the
149    function definition.
150
151    This is going to be compiler- and environment-specific, and may
152    require some support at library build time, and/or "asm"
153    statements.  But through macro expansion and auxiliary functions,
154    we should be able to handle most things except #pragma.
155
156    It's okay for this code to require that the library be built
157    with the same compiler and compiler options throughout, but
158    we shouldn't require that the library and application use the
159    same compiler.
160
161    For static libraries, we don't really care about cleanup too much,
162    since it's all memory handling and mutex allocation which will all
163    be cleaned up when the program exits.  Thus, it's okay if gcc-built
164    static libraries don't play nicely with cc-built executables when
165    it comes to static constructors, just as long as it doesn't cause
166    linking to fail.
167
168    For dynamic libraries on UNIX, we'll use pthread_once-type support
169    to do delayed initialization, so if finalization can't be made to
170    work, we'll only have memory leaks in a load/use/unload cycle.  If
171    anyone (like, say, the OS vendor) complains about this, they can
172    tell us how to get a shared library finalization function invoked
173    automatically.
174
175    Currently there's --disable-delayed-initialization for preventing
176    the initialization from being delayed on UNIX, but that's mainly
177    just for testing the linker options for initialization, and will
178    probably be removed at some point.  */
179
180 /* Helper macros.  */
181
182 # define JOIN__2_2(A,B) A ## _ ## _ ## B
183 # define JOIN__2(A,B) JOIN__2_2(A,B)
184
185 /* XXX Should test USE_LINKER_INIT_OPTION early, and if it's set,
186    always provide a function by the expected name, even if we're
187    delaying initialization.  */
188
189 #if defined(DELAY_INITIALIZER)
190
191 /* Run the initialization code during program execution, at the latest
192    possible moment.  This means multiple threads may be active.  */
193 # include "k5-thread.h"
194 typedef struct { k5_once_t once; int error, did_run; void (*fn)(void); } k5_init_t;
195 # ifdef USE_LINKER_INIT_OPTION
196 #  define MAYBE_DUMMY_INIT(NAME)                \
197         void JOIN__2(NAME, auxinit) () { }
198 # else
199 #  define MAYBE_DUMMY_INIT(NAME)
200 # endif
201 # ifdef __GNUC__
202 /* Do it in macro form so we get the file/line of the invocation if
203    the assertion fails.  */
204 #  define k5_call_init_function(I)                                      \
205         (__extension__ ({                                               \
206                 k5_init_t *k5int_i = (I);                               \
207                 int k5int_err = k5_once(&k5int_i->once, k5int_i->fn);   \
208                 (k5int_err                                              \
209                  ? k5int_err                                            \
210                  : (assert(k5int_i->did_run != 0), k5int_i->error));    \
211             }))
212 #  define MAYBE_DEFINE_CALLINIT_FUNCTION
213 # else
214 #  define MAYBE_DEFINE_CALLINIT_FUNCTION                        \
215         static inline int k5_call_init_function(k5_init_t *i)   \
216         {                                                       \
217             int err;                                            \
218             err = k5_once(&i->once, i->fn);                     \
219             if (err)                                            \
220                 return err;                                     \
221             assert (i->did_run != 0);                           \
222             return i->error;                                    \
223         }
224 # endif
225 # define MAKE_INIT_FUNCTION(NAME)                               \
226         static int NAME(void);                                  \
227         MAYBE_DUMMY_INIT(NAME)                                  \
228         /* forward declaration for use in initializer */        \
229         static void JOIN__2(NAME, aux) (void);                  \
230         static k5_init_t JOIN__2(NAME, once) =                  \
231                 { K5_ONCE_INIT, 0, 0, JOIN__2(NAME, aux) };     \
232         MAYBE_DEFINE_CALLINIT_FUNCTION                          \
233         static void JOIN__2(NAME, aux) (void)                   \
234         {                                                       \
235             JOIN__2(NAME, once).did_run = 1;                    \
236             JOIN__2(NAME, once).error = NAME();                 \
237         }                                                       \
238         /* so ';' following macro use won't get error */        \
239         static int NAME(void)
240 # define CALL_INIT_FUNCTION(NAME)       \
241         k5_call_init_function(& JOIN__2(NAME, once))
242 /* This should be called in finalization only, so we shouldn't have
243    multiple active threads mucking around in our library at this
244    point.  So ignore the once_t object and just look at the flag.
245
246    XXX Could we have problems with memory coherence between processors
247    if we don't invoke mutex/once routines?  Probably not, the
248    application code should already be coordinating things such that
249    the library code is not in use by this point, and memory
250    synchronization will be needed there.  */
251 # define INITIALIZER_RAN(NAME)  \
252         (JOIN__2(NAME, once).did_run && JOIN__2(NAME, once).error == 0)
253
254 # define PROGRAM_EXITING()              (0)
255
256 #elif defined(__GNUC__) && !defined(_WIN32) && defined(CONSTRUCTOR_ATTR_WORKS)
257
258 /* Run initializer at load time, via GCC/C++ hook magic.  */
259
260 # ifdef USE_LINKER_INIT_OPTION
261      /* Both gcc and linker option??  Favor gcc.  */
262 #  define MAYBE_DUMMY_INIT(NAME)                \
263         void JOIN__2(NAME, auxinit) () { }
264 # else
265 #  define MAYBE_DUMMY_INIT(NAME)
266 # endif
267
268 typedef struct { int error; unsigned char did_run; } k5_init_t;
269 # define MAKE_INIT_FUNCTION(NAME)               \
270         MAYBE_DUMMY_INIT(NAME)                  \
271         static k5_init_t JOIN__2(NAME, ran)     \
272                 = { 0, 2 };                     \
273         static void JOIN__2(NAME, aux)(void)    \
274             __attribute__((constructor));       \
275         static int NAME(void);                  \
276         static void JOIN__2(NAME, aux)(void)    \
277         {                                       \
278             JOIN__2(NAME, ran).error = NAME();  \
279             JOIN__2(NAME, ran).did_run = 3;     \
280         }                                       \
281         static int NAME(void)
282 # define CALL_INIT_FUNCTION(NAME)               \
283         (JOIN__2(NAME, ran).did_run == 3        \
284          ? JOIN__2(NAME, ran).error             \
285          : (abort(),0))
286 # define INITIALIZER_RAN(NAME)  (JOIN__2(NAME,ran).did_run == 3 && JOIN__2(NAME, ran).error == 0)
287
288 # define PROGRAM_EXITING()              (0)
289
290 #elif defined(USE_LINKER_INIT_OPTION) || defined(_WIN32)
291
292 /* Run initializer at load time, via linker magic, or in the
293    case of WIN32, win_glue.c hard-coded knowledge.  */
294 typedef struct { int error; unsigned char did_run; } k5_init_t;
295 # define MAKE_INIT_FUNCTION(NAME)               \
296         static k5_init_t JOIN__2(NAME, ran)     \
297                 = { 0, 2 };                     \
298         static int NAME(void);                  \
299         void JOIN__2(NAME, auxinit)()           \
300         {                                       \
301             JOIN__2(NAME, ran).error = NAME();  \
302             JOIN__2(NAME, ran).did_run = 3;     \
303         }                                       \
304         static int NAME(void)
305 # define CALL_INIT_FUNCTION(NAME)               \
306         (JOIN__2(NAME, ran).did_run == 3        \
307          ? JOIN__2(NAME, ran).error             \
308          : (abort(),0))
309 # define INITIALIZER_RAN(NAME)  \
310         (JOIN__2(NAME, ran).error == 0)
311
312 # define PROGRAM_EXITING()              (0)
313
314 #else
315
316 # error "Don't know how to do load-time initializers for this configuration."
317
318 # define PROGRAM_EXITING()              (0)
319
320 #endif
321
322
323
324 #if defined(USE_LINKER_FINI_OPTION) || defined(_WIN32)
325 /* If we're told the linker option will be used, it doesn't really
326    matter what compiler we're using.  Do it the same way
327    regardless.  */
328
329 # ifdef __hpux
330
331      /* On HP-UX, we need this auxiliary function.  At dynamic load or
332         unload time (but *not* program startup and termination for
333         link-time specified libraries), the linker-indicated function
334         is called with a handle on the library and a flag indicating
335         whether it's being loaded or unloaded.
336
337         The "real" fini function doesn't need to be exported, so
338         declare it static.
339
340         As usual, the final declaration is just for syntactic
341         convenience, so the top-level invocation of this macro can be
342         followed by a semicolon.  */
343
344 #  include <dl.h>
345 #  define MAKE_FINI_FUNCTION(NAME)                                          \
346         static void NAME(void);                                             \
347         void JOIN__2(NAME, auxfini)(shl_t, int); /* silence gcc warnings */ \
348         void JOIN__2(NAME, auxfini)(shl_t h, int l) { if (!l) NAME(); }     \
349         static void NAME(void)
350
351 # else /* not hpux */
352
353 #  define MAKE_FINI_FUNCTION(NAME)      \
354         void NAME(void)
355
356 # endif
357
358 #elif defined(__GNUC__) && defined(DESTRUCTOR_ATTR_WORKS)
359 /* If we're using gcc, if the C++ support works, the compiler should
360    build executables and shared libraries that support the use of
361    static constructors and destructors.  The C compiler supports a
362    function attribute that makes use of the same facility as C++.
363
364    XXX How do we know if the C++ support actually works?  */
365 # define MAKE_FINI_FUNCTION(NAME)       \
366         static void NAME(void) __attribute__((destructor))
367
368 #elif !defined(SHARED)
369
370 /* In this case, we just don't care about finalization.
371
372    The code will still define the function, but we won't do anything
373    with it.  Annoying: This may generate unused-function warnings.  */
374
375 # define MAKE_FINI_FUNCTION(NAME)       \
376         static void NAME(void)
377
378 #else
379
380 # error "Don't know how to do unload-time finalization for this configuration."
381
382 #endif
383
384
385 /* 64-bit support: krb5_ui_8 and krb5_int64.
386
387    This should move to krb5.h eventually, but without the namespace
388    pollution from the autoconf macros.  */
389 #if defined(HAVE_STDINT_H) || defined(HAVE_INTTYPES_H)
390 # ifdef HAVE_STDINT_H
391 #  include <stdint.h>
392 # endif
393 # ifdef HAVE_INTTYPES_H
394 #  include <inttypes.h>
395 # endif
396 # define INT64_TYPE int64_t
397 # define UINT64_TYPE uint64_t
398 #elif defined(_WIN32)
399 # define INT64_TYPE signed __int64
400 # define UINT64_TYPE unsigned __int64
401 #else /* not Windows, and neither stdint.h nor inttypes.h */
402 # define INT64_TYPE signed long long
403 # define UINT64_TYPE unsigned long long
404 #endif
405
406 #include <limits.h>
407 #ifndef SIZE_MAX
408 # define SIZE_MAX ((size_t)((size_t)0 - 1))
409 #endif
410
411 /* Read and write integer values as (unaligned) octet strings in
412    specific byte orders.  Add per-platform optimizations as
413    needed.  */
414
415 #if HAVE_ENDIAN_H
416 # include <endian.h>
417 #elif HAVE_MACHINE_ENDIAN_H
418 # include <machine/endian.h>
419 #endif
420 /* Check for BIG/LITTLE_ENDIAN macros.  If exactly one is defined, use
421    it.  If both are defined, then BYTE_ORDER should be defined and
422    match one of them.  Try those symbols, then try again with an
423    underscore prefix.  */
424 #if defined(BIG_ENDIAN) && defined(LITTLE_ENDIAN)
425 # if BYTE_ORDER == BIG_ENDIAN
426 #  define K5_BE
427 # endif
428 # if BYTE_ORDER == LITTLE_ENDIAN
429 #  define K5_LE
430 # endif
431 #elif defined(BIG_ENDIAN)
432 # define K5_BE
433 #elif defined(LITTLE_ENDIAN)
434 # define K5_LE
435 #elif defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN)
436 # if _BYTE_ORDER == _BIG_ENDIAN
437 #  define K5_BE
438 # endif
439 # if _BYTE_ORDER == _LITTLE_ENDIAN
440 #  define K5_LE
441 # endif
442 #elif defined(_BIG_ENDIAN)
443 # define K5_BE
444 #elif defined(_LITTLE_ENDIAN)
445 # define K5_LE
446 #endif
447 #if !defined(K5_BE) && !defined(K5_LE)
448 /* Look for some architectures we know about.
449
450    MIPS can use either byte order, but the preprocessor tells us which
451    mode we're compiling for.  The GCC config files indicate that
452    variants of Alpha and IA64 might be out there with both byte
453    orders, but until we encounter the "wrong" ones in the real world,
454    just go with the default (unless there are cpp predefines to help
455    us there too).
456
457    As far as I know, only PDP11 and ARM (which we don't handle here)
458    have strange byte orders where an 8-byte value isn't laid out as
459    either 12345678 or 87654321.  */
460 # if defined(__i386__) || defined(_MIPSEL) || defined(__alpha__) || defined(__ia64__)
461 #  define K5_LE
462 # endif
463 # if defined(__hppa__) || defined(__rs6000__) || defined(__sparc__) || defined(_MIPSEB) || defined(__m68k__) || defined(__sparc64__) || defined(__ppc__) || defined(__ppc64__)
464 #  define K5_BE
465 # endif
466 #endif
467 #if defined(K5_BE) && defined(K5_LE)
468 # error "oops, check the byte order macros"
469 #endif
470
471 /* Optimize for GCC on platforms with known byte orders.
472
473    GCC's packed structures can be written to with any alignment; the
474    compiler will use byte operations, unaligned-word operations, or
475    normal memory ops as appropriate for the architecture.
476
477    This assumes the availability of uint##_t types, which should work
478    on most of our platforms except Windows, where we're not using
479    GCC.  */
480 #ifdef __GNUC__
481 # define PUT(SIZE,PTR,VAL)      (((struct { uint##SIZE##_t i; } __attribute__((packed)) *)(PTR))->i = (VAL))
482 # define GET(SIZE,PTR)          (((const struct { uint##SIZE##_t i; } __attribute__((packed)) *)(PTR))->i)
483 # define PUTSWAPPED(SIZE,PTR,VAL)       PUT(SIZE,PTR,SWAP##SIZE(VAL))
484 # define GETSWAPPED(SIZE,PTR)           SWAP##SIZE(GET(SIZE,PTR))
485 #endif
486 /* To do: Define SWAP16, SWAP32, SWAP64 macros to byte-swap values
487    with the indicated numbers of bits.
488
489    Linux: byteswap.h, bswap_16 etc.
490    Solaris 10: none
491    Mac OS X: machine/endian.h or byte_order.h, NXSwap{Short,Int,LongLong}
492    NetBSD: sys/bswap.h, bswap16 etc.  */
493
494 #if defined(HAVE_BYTESWAP_H) && defined(HAVE_BSWAP_16)
495 # include <byteswap.h>
496 # define SWAP16                 bswap_16
497 # define SWAP32                 bswap_32
498 # ifdef HAVE_BSWAP_64
499 #  define SWAP64                bswap_64
500 # endif
501 #endif
502
503 static inline void
504 store_16_be (unsigned int val, unsigned char *p)
505 {
506 #if defined(__GNUC__) && defined(K5_BE)
507     PUT(16,p,val);
508 #elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP16)
509     PUTSWAPPED(16,p,val);
510 #else
511     p[0] = (val >>  8) & 0xff;
512     p[1] = (val      ) & 0xff;
513 #endif
514 }
515 static inline void
516 store_32_be (unsigned int val, unsigned char *p)
517 {
518 #if defined(__GNUC__) && defined(K5_BE)
519     PUT(32,p,val);
520 #elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP32)
521     PUTSWAPPED(32,p,val);
522 #else
523     p[0] = (val >> 24) & 0xff;
524     p[1] = (val >> 16) & 0xff;
525     p[2] = (val >>  8) & 0xff;
526     p[3] = (val      ) & 0xff;
527 #endif
528 }
529 static inline void
530 store_64_be (UINT64_TYPE val, unsigned char *p)
531 {
532 #if defined(__GNUC__) && defined(K5_BE)
533     PUT(64,p,val);
534 #elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP64)
535     PUTSWAPPED(64,p,val);
536 #else
537     p[0] = (unsigned char)((val >> 56) & 0xff);
538     p[1] = (unsigned char)((val >> 48) & 0xff);
539     p[2] = (unsigned char)((val >> 40) & 0xff);
540     p[3] = (unsigned char)((val >> 32) & 0xff);
541     p[4] = (unsigned char)((val >> 24) & 0xff);
542     p[5] = (unsigned char)((val >> 16) & 0xff);
543     p[6] = (unsigned char)((val >>  8) & 0xff);
544     p[7] = (unsigned char)((val      ) & 0xff);
545 #endif
546 }
547 static inline unsigned short
548 load_16_be (const unsigned char *p)
549 {
550 #if defined(__GNUC__) && defined(K5_BE)
551     return GET(16,p);
552 #elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP16)
553     return GETSWAPPED(16,p);
554 #else
555     return (p[1] | (p[0] << 8));
556 #endif
557 }
558 static inline unsigned int
559 load_32_be (const unsigned char *p)
560 {
561 #if defined(__GNUC__) && defined(K5_BE)
562     return GET(32,p);
563 #elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP32)
564     return GETSWAPPED(32,p);
565 #else
566     return (p[3] | (p[2] << 8)
567             | ((uint32_t) p[1] << 16)
568             | ((uint32_t) p[0] << 24));
569 #endif
570 }
571 static inline UINT64_TYPE
572 load_64_be (const unsigned char *p)
573 {
574 #if defined(__GNUC__) && defined(K5_BE)
575     return GET(64,p);
576 #elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP64)
577     return GETSWAPPED(64,p);
578 #else
579     return ((UINT64_TYPE)load_32_be(p) << 32) | load_32_be(p+4);
580 #endif
581 }
582 static inline void
583 store_16_le (unsigned int val, unsigned char *p)
584 {
585 #if defined(__GNUC__) && defined(K5_LE)
586     PUT(16,p,val);
587 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16)
588     PUTSWAPPED(16,p,val);
589 #else
590     p[1] = (val >>  8) & 0xff;
591     p[0] = (val      ) & 0xff;
592 #endif
593 }
594 static inline void
595 store_32_le (unsigned int val, unsigned char *p)
596 {
597 #if defined(__GNUC__) && defined(K5_LE)
598     PUT(32,p,val);
599 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32)
600     PUTSWAPPED(32,p,val);
601 #else
602     p[3] = (val >> 24) & 0xff;
603     p[2] = (val >> 16) & 0xff;
604     p[1] = (val >>  8) & 0xff;
605     p[0] = (val      ) & 0xff;
606 #endif
607 }
608 static inline void
609 store_64_le (UINT64_TYPE val, unsigned char *p)
610 {
611 #if defined(__GNUC__) && defined(K5_LE)
612     PUT(64,p,val);
613 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64)
614     PUTSWAPPED(64,p,val);
615 #else
616     p[7] = (unsigned char)((val >> 56) & 0xff);
617     p[6] = (unsigned char)((val >> 48) & 0xff);
618     p[5] = (unsigned char)((val >> 40) & 0xff);
619     p[4] = (unsigned char)((val >> 32) & 0xff);
620     p[3] = (unsigned char)((val >> 24) & 0xff);
621     p[2] = (unsigned char)((val >> 16) & 0xff);
622     p[1] = (unsigned char)((val >>  8) & 0xff);
623     p[0] = (unsigned char)((val      ) & 0xff);
624 #endif
625 }
626 static inline unsigned short
627 load_16_le (const unsigned char *p)
628 {
629 #if defined(__GNUC__) && defined(K5_LE)
630     return GET(16,p);
631 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16)
632     return GETSWAPPED(16,p);
633 #else
634     return (p[0] | (p[1] << 8));
635 #endif
636 }
637 static inline unsigned int
638 load_32_le (const unsigned char *p)
639 {
640 #if defined(__GNUC__) && defined(K5_LE)
641     return GET(32,p);
642 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32)
643     return GETSWAPPED(32,p);
644 #else
645     return (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24));
646 #endif
647 }
648 static inline UINT64_TYPE
649 load_64_le (const unsigned char *p)
650 {
651 #if defined(__GNUC__) && defined(K5_LE)
652     return GET(64,p);
653 #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64)
654     return GETSWAPPED(64,p);
655 #else
656     return ((UINT64_TYPE)load_32_le(p+4) << 32) | load_32_le(p);
657 #endif
658 }
659
660 static inline unsigned short
661 load_16_n (const unsigned char *p)
662 {
663 #ifdef _WIN32
664     unsigned __int16 n;
665 #else
666     uint16_t n;
667 #endif
668     memcpy(&n, p, 2);
669     return n;
670 }
671 static inline unsigned int
672 load_32_n (const unsigned char *p)
673 {
674 #ifdef _WIN32
675     unsigned __int32 n;
676 #else
677     uint32_t n;
678 #endif
679     memcpy(&n, p, 4);
680     return n;
681 }
682 static inline UINT64_TYPE
683 load_64_n (const unsigned char *p)
684 {
685     UINT64_TYPE n;
686     memcpy(&n, p, 8);
687     return n;
688 }
689
690 /* Make the interfaces to getpwnam and getpwuid consistent.
691    Model the wrappers on the POSIX thread-safe versions, but
692    use the unsafe system versions if the safe ones don't exist
693    or we can't figure out their interfaces.  */
694
695 /* int k5_getpwnam_r(const char *, blah blah) */
696 #ifdef HAVE_GETPWNAM_R
697 # ifndef GETPWNAM_R_4_ARGS
698 /* POSIX */
699 #  define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT)   \
700         (getpwnam_r(NAME,REC,BUF,BUFSIZE,OUT) == 0      \
701          ? (*(OUT) == NULL ? -1 : 0) : -1)
702 # else
703 /* POSIX drafts? */
704 #  ifdef GETPWNAM_R_RETURNS_INT
705 #   define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT)  \
706         (getpwnam_r(NAME,REC,BUF,BUFSIZE) == 0          \
707          ? (*(OUT) = REC, 0)                            \
708          : (*(OUT) = NULL, -1))
709 #  else
710 #   define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT)  \
711         (*(OUT) = getpwnam_r(NAME,REC,BUF,BUFSIZE), *(OUT) == NULL ? -1 : 0)
712 #  endif
713 # endif
714 #else /* no getpwnam_r, or can't figure out #args or return type */
715 /* Will get warnings about unused variables.  */
716 # define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT) \
717         (*(OUT) = getpwnam(NAME), *(OUT) == NULL ? -1 : 0)
718 #endif
719
720 /* int k5_getpwuid_r(uid_t, blah blah) */
721 #ifdef HAVE_GETPWUID_R
722 # ifndef GETPWUID_R_4_ARGS
723 /* POSIX */
724 #  define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT)    \
725         (getpwuid_r(UID,REC,BUF,BUFSIZE,OUT) == 0       \
726          ? (*(OUT) == NULL ? -1 : 0) : -1)
727 # else
728 /* POSIX drafts?  Yes, I mean to test GETPWNAM... here.  Less junk to
729    do at configure time.  */
730 #  ifdef GETPWNAM_R_RETURNS_INT
731 #   define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT)   \
732         (getpwuid_r(UID,REC,BUF,BUFSIZE) == 0           \
733          ? (*(OUT) = REC, 0)                            \
734          : (*(OUT) = NULL, -1))
735 #  else
736 #   define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT)  \
737         (*(OUT) = getpwuid_r(UID,REC,BUF,BUFSIZE), *(OUT) == NULL ? -1 : 0)
738 #  endif
739 # endif
740 #else /* no getpwuid_r, or can't figure out #args or return type */
741 /* Will get warnings about unused variables.  */
742 # define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT) \
743         (*(OUT) = getpwuid(UID), *(OUT) == NULL ? -1 : 0)
744 #endif
745
746
747 #endif /* K5_PLATFORM_H */