diff options
author | Jean-Baptiste Queru <jbq@google.com> | 2009-11-12 18:45:14 -0800 |
---|---|---|
committer | Jean-Baptiste Queru <jbq@google.com> | 2009-11-12 18:45:14 -0800 |
commit | 194d3fa048cf909ca592dd56fa538dc9cd3f5ddb (patch) | |
tree | 3a00bb9e267cf952d7d1140ff9a39ca07ee6c994 | |
parent | fde8642fc43bdd224e43e5ee9583a49a758fb03c (diff) | |
download | bionic-194d3fa048cf909ca592dd56fa538dc9cd3f5ddb.zip bionic-194d3fa048cf909ca592dd56fa538dc9cd3f5ddb.tar.gz bionic-194d3fa048cf909ca592dd56fa538dc9cd3f5ddb.tar.bz2 |
eclair snapshot
50 files changed, 5185 insertions, 3218 deletions
diff --git a/libc/Android.mk b/libc/Android.mk index 59a4c6b..5718d18 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -288,6 +288,7 @@ libc_common_src_files += \ arch-arm/bionic/clone.S \ arch-arm/bionic/ffs.S \ arch-arm/bionic/kill.S \ + arch-arm/bionic/libgcc_compat.c \ arch-arm/bionic/tkill.S \ arch-arm/bionic/memcmp.S \ arch-arm/bionic/memcmp16.S \ @@ -366,6 +367,16 @@ endif ifeq ($(TARGET_ARCH),arm) libc_common_cflags += -fstrict-aliasing libc_crt_target_cflags := -mthumb-interwork + # + # Define HAVE_ARM_TLS_REGISTER macro to indicate to the C library + # that it should access the hardware TLS register directly in + # private/bionic_tls.h + # + # The value must match your kernel configuration + # + ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true) + libc_common_cflags += -DHAVE_ARM_TLS_REGISTER + endif else # !arm ifeq ($(TARGET_ARCH),x86) libc_crt_target_cflags := -m32 diff --git a/libc/arch-arm/bionic/atomics_arm.S b/libc/arch-arm/bionic/atomics_arm.S index b2da09f..f8b23e6 100644 --- a/libc/arch-arm/bionic/atomics_arm.S +++ b/libc/arch-arm/bionic/atomics_arm.S @@ -41,6 +41,8 @@ .equ kernel_cmpxchg, 0xFFFF0FC0 .equ kernel_atomic_base, 0xFFFF0FFF __atomic_dec: + .fnstart + .save {r4, lr} stmdb sp!, {r4, lr} mov r2, r0 1: @ atomic_dec @@ -53,8 +55,11 @@ __atomic_dec: add r0, r1, #1 ldmia sp!, {r4, lr} bx lr + .fnend __atomic_inc: + .fnstart + .save {r4, lr} stmdb sp!, {r4, lr} mov r2, r0 1: @ atomic_inc @@ -67,9 +72,12 @@ __atomic_inc: sub r0, r1, #1 ldmia sp!, {r4, lr} bx lr + .fnend /* r0(old) r1(new) r2(addr) -> r0(zero_if_succeeded) */ __atomic_cmpxchg: + .fnstart + .save {r4, lr} stmdb sp!, {r4, lr} mov r4, r0 /* r4 = save oldvalue */ 1: @ atomic_cmpxchg @@ -84,6 +92,7 @@ __atomic_cmpxchg: 2: @ atomic_cmpxchg ldmia sp!, {r4, lr} bx lr + .fnend #else #define KUSER_CMPXCHG 0xffffffc0 diff --git a/libc/arch-arm/bionic/libgcc_compat.c b/libc/arch-arm/bionic/libgcc_compat.c new file mode 100644 index 0000000..886d025 --- /dev/null +++ b/libc/arch-arm/bionic/libgcc_compat.c @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* This file contains dummy references to libgcc.a functions to force the + * dynamic linker to copy their definition into the final libc.so binary. + * + * They are required to ensure backwards binary compatibility with + * Android 1.5 and Android 1.6 system images. Some applications built + * using the NDK require them to be here. + * + * Now, for a more elaborate description of the issue: + * + * libgcc.a is a compiler-specific library containing various helper + * functions used to implement certain operations that are not necessarily + * supported by the target CPU. For example, integer division doesn't have a + * corresponding CPU instruction on ARMv5, and is instead implemented in the + * compiler-generated machine code as a call to an __idiv helper function. + * + * Normally, one has to place libgcc.a in the link command used to generate + * target binaries (shared libraries and executables) after all objects and + * static libraries, but before dependent shared libraries, i.e. something + * like: + * gcc <options> -o libfoo.so foo.a libgcc.a -lc -lm + * + * This ensures that any helper function needed by the code in foo.a is copied + * into the final libfoo.so. Unfortunately, the Android build system has been + * using this instead: + * + * gcc <options> -o libfoo.so foo.a -lc -lm libgcc.a + * + * The problem with this is that if one helper function needed by foo.a has + * already been copied into libc.so or libm.so, then nothing will be copied + * into libfoo.so. Instead, a symbol import definition will be added to it + * so libfoo.so can directly call the one in libc.so at runtime. + * + * When changing toolchains for 2.0, the set of helper functions copied to + * libc.so changed, which resulted in some native shared libraries generated + * with the NDK to fail to load properly. + * + * The NDK has been fixed after 1.6_r1 to use the correct link command, so + * any native shared library generated with it should now be safe from that + * problem. On the other hand, existing shared libraries distributed with + * applications that were generated with a previous version of the NDK + * still need all 1.5/1.6 helper functions in libc.so and libn.so + * + * Final note: some of the functions below should really be in libm.so to + * completely reflect the state of 1.5/1.6 system images. However, + * since libm.so depends on libc.so, it's easier to put all of + * these in libc.so instead, since the dynamic linker will always + * search in libc.so before libm.so for dependencies. + */ + +#define COMPAT_FUNCTIONS_LIST \ + XX(__adddf3) \ + XX(__addsf3) \ + XX(__aeabi_cdcmpeq) \ + XX(__aeabi_cdcmple) \ + XX(__aeabi_cdrcmple) \ + XX(__aeabi_d2f) \ + XX(__aeabi_d2iz) \ + XX(__aeabi_dadd) \ + XX(__aeabi_dcmpeq) \ + XX(__aeabi_dcmpge) \ + XX(__aeabi_dcmpgt) \ + XX(__aeabi_dcmple) \ + XX(__aeabi_dcmplt) \ + XX(__aeabi_dcmpun) \ + XX(__aeabi_ddiv) \ + XX(__aeabi_dmul) \ + XX(__aeabi_drsub) \ + XX(__aeabi_dsub) \ + XX(__aeabi_f2d) \ + XX(__aeabi_f2iz) \ + XX(__aeabi_fadd) \ + XX(__aeabi_fcmpun) \ + XX(__aeabi_fdiv) \ + XX(__aeabi_fmul) \ + XX(__aeabi_frsub) \ + XX(__aeabi_fsub) \ + XX(__aeabi_i2d) \ + XX(__aeabi_i2f) \ + XX(__aeabi_l2d) \ + XX(__aeabi_l2f) \ + XX(__aeabi_lmul) \ + XX(__aeabi_ui2d) \ + XX(__aeabi_ui2f) \ + XX(__aeabi_ul2d) \ + XX(__aeabi_ul2f) \ + XX(__cmpdf2) \ + XX(__divdf3) \ + XX(__divsf3) \ + XX(__eqdf2) \ + XX(__extendsfdf2) \ + XX(__fixdfsi) \ + XX(__fixsfsi) \ + XX(__floatdidf) \ + XX(__floatdisf) \ + XX(__floatsidf) \ + XX(__floatsisf) \ + XX(__floatundidf) \ + XX(__floatundisf) \ + XX(__floatunsidf) \ + XX(__floatunsisf) \ + XX(__gedf2) \ + XX(__gtdf2) \ + XX(__ledf2) \ + XX(__ltdf2) \ + XX(__muldf3) \ + XX(__muldi3) \ + XX(__mulsf3) \ + XX(__nedf2) \ + XX(__subdf3) \ + XX(__subsf3) \ + XX(__truncdfsf2) \ + XX(__unorddf2) \ + XX(__unordsf2) \ + +#define XX(f) extern void f(void); +COMPAT_FUNCTIONS_LIST +#undef XX + +void __bionic_libgcc_compat_hooks(void) +{ +#define XX(f) f(); +COMPAT_FUNCTIONS_LIST +#undef XX +} diff --git a/libc/arch-arm/bionic/memcmp.S b/libc/arch-arm/bionic/memcmp.S index f45b56b..67dcddc 100644 --- a/libc/arch-arm/bionic/memcmp.S +++ b/libc/arch-arm/bionic/memcmp.S @@ -44,6 +44,7 @@ */ memcmp: + .fnstart PLD (r0, #0) PLD (r1, #0) @@ -53,6 +54,7 @@ memcmp: moveq r0, #0 bxeq lr + .save {r4, lr} /* save registers */ stmfd sp!, {r4, lr} @@ -174,6 +176,7 @@ memcmp: 9: /* restore registers and return */ ldmfd sp!, {r4, lr} bx lr + .fnend diff --git a/libc/arch-arm/bionic/memcmp16.S b/libc/arch-arm/bionic/memcmp16.S index 38d8b62..f398588 100644 --- a/libc/arch-arm/bionic/memcmp16.S +++ b/libc/arch-arm/bionic/memcmp16.S @@ -44,6 +44,7 @@ */ __memcmp16: + .fnstart PLD (r0, #0) PLD (r1, #0) @@ -79,6 +80,7 @@ __memcmp16: bx lr + .save {r4, lr} /* save registers */ 0: stmfd sp!, {r4, lr} @@ -93,6 +95,7 @@ __memcmp16: /* restore registers and return */ ldmnefd sp!, {r4, lr} bxne lr + .fnend diff --git a/libc/arch-arm/bionic/memcpy.S b/libc/arch-arm/bionic/memcpy.S index fcb58cd..024d885 100644 --- a/libc/arch-arm/bionic/memcpy.S +++ b/libc/arch-arm/bionic/memcpy.S @@ -28,6 +28,127 @@ #include <machine/cpu-features.h> +#if __ARM_ARCH__ == 7 || defined(__ARM_NEON__) + + .text + .fpu neon + + .global memcpy + .type memcpy, %function + .align 4 + +/* a prefetch distance of 4 cache-lines works best experimentally */ +#define CACHE_LINE_SIZE 64 +#define PREFETCH_DISTANCE (CACHE_LINE_SIZE*4) + +memcpy: + .fnstart + .save {r0, lr} + stmfd sp!, {r0, lr} + + /* start preloading as early as possible */ + pld [r1, #(CACHE_LINE_SIZE*0)] + pld [r1, #(CACHE_LINE_SIZE*1)] + + /* do we have at least 16-bytes to copy (needed for alignment below) */ + cmp r2, #16 + blo 5f + + /* align destination to half cache-line for the write-buffer */ + rsb r3, r0, #0 + ands r3, r3, #0xF + beq 0f + + /* copy up to 15-bytes (count in r3) */ + sub r2, r2, r3 + movs ip, r3, lsl #31 + ldrmib lr, [r1], #1 + strmib lr, [r0], #1 + ldrcsb ip, [r1], #1 + ldrcsb lr, [r1], #1 + strcsb ip, [r0], #1 + strcsb lr, [r0], #1 + movs ip, r3, lsl #29 + bge 1f + // copies 4 bytes, destination 32-bits aligned + vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]! + vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0, :32]! +1: bcc 2f + // copies 8 bytes, destination 64-bits aligned + vld1.8 {d0}, [r1]! + vst1.8 {d0}, [r0, :64]! +2: + +0: /* preload immediately the next cache line, which we may need */ + pld [r1, #(CACHE_LINE_SIZE*0)] + pld [r1, #(CACHE_LINE_SIZE*1)] + + /* make sure we have at least 64 bytes to copy */ + subs r2, r2, #64 + blo 2f + + /* preload all the cache lines we need. + * NOTE: the number of pld below depends on PREFETCH_DISTANCE, + * ideally would would increase the distance in the main loop to + * avoid the goofy code below. In practice this doesn't seem to make + * a big difference. + */ + pld [r1, #(CACHE_LINE_SIZE*2)] + pld [r1, #(CACHE_LINE_SIZE*3)] + pld [r1, #(PREFETCH_DISTANCE)] + +1: /* The main loop copies 64 bytes at a time */ + vld1.8 {d0 - d3}, [r1]! + vld1.8 {d4 - d7}, [r1]! + pld [r1, #(PREFETCH_DISTANCE)] + subs r2, r2, #64 + vst1.8 {d0 - d3}, [r0, :128]! + vst1.8 {d4 - d7}, [r0, :128]! + bhs 1b + +2: /* fix-up the remaining count and make sure we have >= 32 bytes left */ + add r2, r2, #64 + subs r2, r2, #32 + blo 4f + +3: /* 32 bytes at a time. These cache lines were already preloaded */ + vld1.8 {d0 - d3}, [r1]! + subs r2, r2, #32 + vst1.8 {d0 - d3}, [r0, :128]! + bhs 3b + +4: /* less than 32 left */ + add r2, r2, #32 + tst r2, #0x10 + beq 5f + // copies 16 bytes, 128-bits aligned + vld1.8 {d0, d1}, [r1]! + vst1.8 {d0, d1}, [r0, :128]! + +5: /* copy up to 15-bytes (count in r2) */ + movs ip, r2, lsl #29 + bcc 1f + vld1.8 {d0}, [r1]! + vst1.8 {d0}, [r0]! +1: bge 2f + vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]! + vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0]! +2: movs ip, r2, lsl #31 + ldrmib r3, [r1], #1 + ldrcsb ip, [r1], #1 + ldrcsb lr, [r1], #1 + strmib r3, [r0], #1 + strcsb ip, [r0], #1 + strcsb lr, [r0], #1 + + ldmfd sp!, {r0, lr} + bx lr + .fnend + + +#else /* __ARM_ARCH__ < 7 */ + + .text .global memcpy @@ -40,9 +161,9 @@ * note that memcpy() always returns the destination pointer, * so we have to preserve R0. */ - -memcpy: - /* The stack must always be 64-bits aligned to be compliant with the + +memcpy: + /* The stack must always be 64-bits aligned to be compliant with the * ARM ABI. Since we have to save R0, we might as well save R4 * which we can use for better pipelining of the reads below */ @@ -82,10 +203,10 @@ memcpy: strmib r3, [r0], #1 strcsb r4, [r0], #1 strcsb r12,[r0], #1 - + src_aligned: - /* see if src and dst are aligned together (congruent) */ + /* see if src and dst are aligned together (congruent) */ eor r12, r0, r1 tst r12, #3 bne non_congruent @@ -103,7 +224,7 @@ src_aligned: andhi r3, r2, #0x1C /* conditionnaly copies 0 to 7 words (length in r3) */ - movs r12, r3, lsl #28 + movs r12, r3, lsl #28 ldmcsia r1!, {r4, r5, r6, r7} /* 16 bytes */ ldmmiia r1!, {r8, r9} /* 8 bytes */ stmcsia r0!, {r4, r5, r6, r7} @@ -124,7 +245,7 @@ cached_aligned32: /* * We preload a cache-line up to 64 bytes ahead. On the 926, this will - * stall only until the requested world is fetched, but the linefill + * stall only until the requested world is fetched, but the linefill * continues in the the background. * While the linefill is going, we write our previous cache-line * into the write-buffer (which should have some free space). @@ -150,19 +271,19 @@ cached_aligned32: // NOTE: if r12 is more than 64 ahead of r1, the following ldrhi // for ARM9 preload will not be safely guarded by the preceding subs. - // When it is safely guarded the only possibility to have SIGSEGV here + // When it is safely guarded the only possibility to have SIGSEGV here // is because the caller overstates the length. ldrhi r3, [r12], #32 /* cheap ARM9 preload */ stmia r0!, { r4-r11 } bhs 1b - + add r2, r2, #32 less_than_32_left: - /* + /* * less than 32 bytes left at this point (length in r2) */ @@ -174,7 +295,7 @@ less_than_32_left: beq 1f /* conditionnaly copies 0 to 31 bytes */ - movs r12, r2, lsl #28 + movs r12, r2, lsl #28 ldmcsia r1!, {r4, r5, r6, r7} /* 16 bytes */ ldmmiia r1!, {r8, r9} /* 8 bytes */ stmcsia r0!, {r4, r5, r6, r7} @@ -182,7 +303,7 @@ less_than_32_left: movs r12, r2, lsl #30 ldrcs r3, [r1], #4 /* 4 bytes */ ldrmih r4, [r1], #2 /* 2 bytes */ - strcs r3, [r0], #4 + strcs r3, [r0], #4 strmih r4, [r0], #2 tst r2, #0x1 ldrneb r3, [r1] /* last byte */ @@ -200,34 +321,34 @@ non_congruent: * here source is aligned to 4 bytes * but destination is not. * - * in the code below r2 is the number of bytes read + * in the code below r2 is the number of bytes read * (the number of bytes written is always smaller, because we have * partial words in the shift queue) */ cmp r2, #4 blo copy_last_3_and_return - + /* Use post-incriment mode for stm to spill r5-r11 to reserved stack * frame. Don't update sp. */ stmea sp, {r5-r11} - + /* compute shifts needed to align src to dest */ rsb r5, r0, #0 and r5, r5, #3 /* r5 = # bytes in partial words */ - mov r12, r5, lsl #3 /* r12 = right */ + mov r12, r5, lsl #3 /* r12 = right */ rsb lr, r12, #32 /* lr = left */ - + /* read the first word */ ldr r3, [r1], #4 sub r2, r2, #4 - + /* write a partial word (0 to 3 bytes), such that destination * becomes aligned to 32 bits (r5 = nb of words to copy for alignment) */ movs r5, r5, lsl #31 strmib r3, [r0], #1 - movmi r3, r3, lsr #8 + movmi r3, r3, lsr #8 strcsb r3, [r0], #1 movcs r3, r3, lsr #8 strcsb r3, [r0], #1 @@ -235,7 +356,7 @@ non_congruent: cmp r2, #4 blo partial_word_tail - + /* Align destination to 32 bytes (cache line boundary) */ 1: tst r0, #0x1c beq 2f @@ -366,7 +487,7 @@ partial_word_tail: strcsb r3, [r0], #1 movcs r3, r3, lsr #8 strcsb r3, [r0], #1 - + /* Refill spilled registers from the stack. Don't update sp. */ ldmfd sp, {r5-r11} @@ -385,3 +506,5 @@ copy_last_3_and_return: bx lr .fnend + +#endif /* __ARM_ARCH__ < 7 */ diff --git a/libc/arch-arm/bionic/memset.S b/libc/arch-arm/bionic/memset.S index d52d622..93abe15 100644 --- a/libc/arch-arm/bionic/memset.S +++ b/libc/arch-arm/bionic/memset.S @@ -80,7 +80,7 @@ memset: rsb r3, r0, #0 ands r3, r3, #0x1C - beq aligned32 + beq 3f cmp r3, r2 andhi r3, r2, #0x1C sub r2, r2, r3 @@ -93,7 +93,7 @@ memset: movs r3, r3, lsl #2 strcs r1, [r0], #4 -aligned32: +3: subs r2, r2, #32 mov r3, r1 bmi 2f diff --git a/libc/arch-arm/include/machine/cpu-features.h b/libc/arch-arm/include/machine/cpu-features.h index f836006..925067e 100644 --- a/libc/arch-arm/include/machine/cpu-features.h +++ b/libc/arch-arm/include/machine/cpu-features.h @@ -149,7 +149,6 @@ # define __ARM_HAVE_PC_INTERWORK #endif - /* Assembly-only macros */ /* define a handy PLD(address) macro since the cache preload diff --git a/libc/bionic/dlmalloc.c b/libc/bionic/dlmalloc.c index 78f20c0..f6f878e 100644 --- a/libc/bionic/dlmalloc.c +++ b/libc/bionic/dlmalloc.c @@ -1154,6 +1154,23 @@ void mspace_free(mspace msp, void* mem); */ void* mspace_realloc(mspace msp, void* mem, size_t newsize); +#if ANDROID /* Added for Android, not part of dlmalloc as released */ +/* + mspace_merge_objects will merge allocated memory mema and memb + together, provided memb immediately follows mema. It is roughly as + if memb has been freed and mema has been realloced to a larger size. + On successfully merging, mema will be returned. If either argument + is null or memb does not immediately follow mema, null will be + returned. + + Both mema and memb should have been previously allocated using + malloc or a related routine such as realloc. If either mema or memb + was not malloced or was previously freed, the result is undefined, + but like mspace_free, the default is to abort the program. +*/ +void* mspace_merge_objects(mspace msp, void* mema, void* memb); +#endif + /* mspace_calloc behaves as calloc, but operates within the given space. @@ -4872,6 +4889,62 @@ void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) { } } +#if ANDROID +void* mspace_merge_objects(mspace msp, void* mema, void* memb) +{ + /* PREACTION/POSTACTION aren't necessary because we are only + modifying fields of inuse chunks owned by the current thread, in + which case no other malloc operations can touch them. + */ + if (mema == NULL || memb == NULL) { + return NULL; + } + mchunkptr pa = mem2chunk(mema); + mchunkptr pb = mem2chunk(memb); + +#if FOOTERS + mstate fm = get_mstate_for(pa); +#else /* FOOTERS */ + mstate fm = (mstate)msp; +#endif /* FOOTERS */ + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, pa); + return NULL; + } + check_inuse_chunk(fm, pa); + if (RTCHECK(ok_address(fm, pa) && ok_cinuse(pa))) { + if (next_chunk(pa) != pb) { + /* Since pb may not be in fm, we can't check ok_address(fm, pb); + since ok_cinuse(pb) would be unsafe before an address check, + return NULL rather than invoke USAGE_ERROR_ACTION if pb is not + in use or is a bogus address. + */ + return NULL; + } + /* Since b follows a, they share the mspace. */ +#if FOOTERS + assert(fm == get_mstate_for(pb)); +#endif /* FOOTERS */ + check_inuse_chunk(fm, pb); + if (RTCHECK(ok_address(fm, pb) && ok_cinuse(pb))) { + size_t sz = chunksize(pb); + pa->head += sz; + /* Make sure pa still passes. */ + check_inuse_chunk(fm, pa); + return mema; + } + else { + USAGE_ERROR_ACTION(fm, pb); + return NULL; + } + } + else { + USAGE_ERROR_ACTION(fm, pa); + return NULL; + } +} +#endif /* ANDROID */ + void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) { mstate ms = (mstate)msp; if (!ok_magic(ms)) { diff --git a/libc/bionic/dlmalloc.h b/libc/bionic/dlmalloc.h index 75b5e1f..e5f7d4a 100644 --- a/libc/bionic/dlmalloc.h +++ b/libc/bionic/dlmalloc.h @@ -547,6 +547,21 @@ void mspace_free(mspace msp, void* mem); void* mspace_realloc(mspace msp, void* mem, size_t newsize); /* + mspace_merge_objects will merge allocated memory mema and memb + together, provided memb immediately follows mema. It is roughly as + if memb has been freed and mema has been realloced to a larger size. + On successfully merging, mema will be returned. If either argument + is null or memb does not immediately follow mema, null will be + returned. + + Both mema and memb should have been previously allocated using + malloc or a related routine such as realloc. If either mema or memb + was not malloced or was previously freed, the result is undefined, + but like mspace_free, the default is to abort the program. +*/ +void* mspace_merge_objects(mspace msp, void* mema, void* memb); + +/* mspace_calloc behaves as calloc, but operates within the given space. */ diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c index ec3c459..42f5f4c 100644 --- a/libc/bionic/pthread.c +++ b/libc/bionic/pthread.c @@ -441,7 +441,7 @@ int pthread_attr_setstackaddr(pthread_attr_t * attr, void * stack_addr) int pthread_attr_getstackaddr(pthread_attr_t const * attr, void ** stack_addr) { - *stack_addr = attr->stack_base + attr->stack_size; + *stack_addr = (char*)attr->stack_base + attr->stack_size; return 0; } @@ -789,7 +789,18 @@ int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) if (!attr) return EINVAL; - return (pshared == PTHREAD_PROCESS_PRIVATE) ? 0 : ENOTSUP; + switch (pshared) { + case PTHREAD_PROCESS_PRIVATE: + case PTHREAD_PROCESS_SHARED: + /* our current implementation of pthread actually supports shared + * mutexes but won't cleanup if a process dies with the mutex held. + * Nevertheless, it's better than nothing. Shared mutexes are used + * by surfaceflinger and audioflinger. + */ + return 0; + } + + return ENOTSUP; } int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared) @@ -1114,6 +1125,135 @@ int pthread_mutex_trylock(pthread_mutex_t *mutex) } +/* initialize 'ts' with the difference between 'abstime' and the current time + * according to 'clock'. Returns -1 if abstime already expired, or 0 otherwise. + */ +static int +__timespec_to_absolute(struct timespec* ts, const struct timespec* abstime, clockid_t clock) +{ + clock_gettime(clock, ts); + ts->tv_sec = abstime->tv_sec - ts->tv_sec; + ts->tv_nsec = abstime->tv_nsec - ts->tv_nsec; + if (ts->tv_nsec < 0) { + ts->tv_sec--; + ts->tv_nsec += 1000000000; + } + if ((ts->tv_nsec < 0) || (ts->tv_sec < 0)) + return -1; + + return 0; +} + +/* initialize 'abstime' to the current time according to 'clock' plus 'msecs' + * milliseconds. + */ +static void +__timespec_to_relative_msec(struct timespec* abstime, unsigned msecs, clockid_t clock) +{ + clock_gettime(clock, abstime); + abstime->tv_sec += msecs/1000; + abstime->tv_nsec += (msecs%1000)*1000000; + if (abstime->tv_nsec >= 1000000000) { + abstime->tv_sec++; + abstime->tv_nsec -= 1000000000; + } +} + +int pthread_mutex_lock_timeout_np(pthread_mutex_t *mutex, unsigned msecs) +{ + clockid_t clock = CLOCK_MONOTONIC; + struct timespec abstime; + struct timespec ts; + + /* compute absolute expiration time */ + __timespec_to_relative_msec(&abstime, msecs, clock); + + if (__likely(mutex != NULL)) + { + int mtype = (mutex->value & MUTEX_TYPE_MASK); + + if ( __likely(mtype == MUTEX_TYPE_NORMAL) ) + { + /* fast path for unconteded lock */ + if (__atomic_cmpxchg(0, 1, &mutex->value) == 0) + return 0; + + /* loop while needed */ + while (__atomic_swap(2, &mutex->value) != 0) { + if (__timespec_to_absolute(&ts, &abstime, clock) < 0) + return EBUSY; + + __futex_wait(&mutex->value, 2, &ts); + } + return 0; + } + else + { + int tid = __get_thread()->kernel_id; + int oldv; + + if ( tid == MUTEX_OWNER(mutex) ) + { + int oldv, counter; + + if (mtype == MUTEX_TYPE_ERRORCHECK) { + /* already locked by ourselves */ + return EDEADLK; + } + + _recursive_lock(); + oldv = mutex->value; + counter = (oldv + (1 << MUTEX_COUNTER_SHIFT)) & MUTEX_COUNTER_MASK; + mutex->value = (oldv & ~MUTEX_COUNTER_MASK) | counter; + _recursive_unlock(); + return 0; + } + else + { + /* + * If the new lock is available immediately, we grab it in + * the "uncontended" state. + */ + int new_lock_type = 1; + + for (;;) { + int oldv; + struct timespec ts; + + _recursive_lock(); + oldv = mutex->value; + if (oldv == mtype) { /* uncontended released lock => 1 or 2 */ + mutex->value = ((tid << 16) | mtype | new_lock_type); + } else if ((oldv & 3) == 1) { /* locked state 1 => state 2 */ + oldv ^= 3; + mutex->value = oldv; + } + _recursive_unlock(); + + if (oldv == mtype) + break; + + /* + * The lock was held, possibly contended by others. From + * now on, if we manage to acquire the lock, we have to + * assume that others are still contending for it so that + * we'll wake them when we unlock it. + */ + new_lock_type = 2; + + if (__timespec_to_absolute(&ts, &abstime, clock) < 0) + return EBUSY; + + __futex_wait( &mutex->value, oldv, &ts ); + } + return 0; + } + } + } + return EINVAL; +} + + /* XXX *technically* there is a race condition that could allow * XXX a signal to be missed. If thread A is preempted in _wait() * XXX after unlocking the mutex and before waiting, and if other @@ -1178,16 +1318,8 @@ int __pthread_cond_timedwait(pthread_cond_t *cond, struct timespec * tsp; if (abstime != NULL) { - clock_gettime(clock, &ts); - ts.tv_sec = abstime->tv_sec - ts.tv_sec; - ts.tv_nsec = abstime->tv_nsec - ts.tv_nsec; - if (ts.tv_nsec < 0) { - ts.tv_sec--; - ts.tv_nsec += 1000000000; - } - if((ts.tv_nsec < 0) || (ts.tv_sec < 0)) { + if (__timespec_to_absolute(&ts, abstime, clock) < 0) return ETIMEDOUT; - } tsp = &ts; } else { tsp = NULL; @@ -1204,6 +1336,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, } +/* this one exists only for backward binary compatibility */ int pthread_cond_timedwait_monotonic(pthread_cond_t *cond, pthread_mutex_t * mutex, const struct timespec *abstime) @@ -1211,6 +1344,20 @@ int pthread_cond_timedwait_monotonic(pthread_cond_t *cond, return __pthread_cond_timedwait(cond, mutex, abstime, CLOCK_MONOTONIC); } +int pthread_cond_timedwait_monotonic_np(pthread_cond_t *cond, + pthread_mutex_t * mutex, + const struct timespec *abstime) +{ + return __pthread_cond_timedwait(cond, mutex, abstime, CLOCK_MONOTONIC); +} + +int pthread_cond_timedwait_relative_np(pthread_cond_t *cond, + pthread_mutex_t * mutex, + const struct timespec *reltime) +{ + return __pthread_cond_timedwait_relative(cond, mutex, reltime); +} + int pthread_cond_timeout_np(pthread_cond_t *cond, pthread_mutex_t * mutex, unsigned msecs) diff --git a/libc/docs/OVERVIEW.TXT b/libc/docs/OVERVIEW.TXT index 4c153b1..753e48a 100644 --- a/libc/docs/OVERVIEW.TXT +++ b/libc/docs/OVERVIEW.TXT @@ -63,6 +63,18 @@ time_t: Instead, Bionic provides a <time64.h> header that defines a time64_t type, and related functions like mktime64(), localtime64(), etc... + strftime() uses time64_t internally, so the '%s' format (seconds since the + epoch) is supported for dates >= 2038. + + +strftime_tz(): + + Bionic also provides the non-standard strftime_tz() function, a variant + of strftime() which also accepts a time locale descriptor as defined + by "struct strftime_locale" in <time.h>. + + This function is used by the low-level framework code in Android. + Timezone management: diff --git a/libc/include/arpa/inet.h b/libc/include/arpa/inet.h index 3ebb872..e78e7c5 100644 --- a/libc/include/arpa/inet.h +++ b/libc/include/arpa/inet.h @@ -31,7 +31,6 @@ #include <stdint.h> #include <sys/types.h> #include <netinet/in.h> -#include <netinet/in6.h> __BEGIN_DECLS diff --git a/libc/include/netinet/in.h b/libc/include/netinet/in.h index 77ae506..0ebd926 100644 --- a/libc/include/netinet/in.h +++ b/libc/include/netinet/in.h @@ -32,6 +32,7 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/in6.h> +#include <netinet/in6.h> __BEGIN_DECLS @@ -39,6 +40,9 @@ __BEGIN_DECLS extern int bindresvport (int sd, struct sockaddr_in *sin); +static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; +static const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; + __END_DECLS #endif /* _NETINET_IN_H_ */ diff --git a/libc/include/netinet/in6.h b/libc/include/netinet/in6.h index e645c48..2f5fee1 100644 --- a/libc/include/netinet/in6.h +++ b/libc/include/netinet/in6.h @@ -90,4 +90,12 @@ #define INET6_ADDRSTRLEN 46 +#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP +#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP + +#define IN6ADDR_ANY_INIT {{{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}} + +#define ipv6mr_interface ipv6mr_ifindex + + #endif /* _NETINET_IN6_H */ diff --git a/libc/include/pthread.h b/libc/include/pthread.h index e3afdae..6603b3f 100644 --- a/libc/include/pthread.h +++ b/libc/include/pthread.h @@ -179,14 +179,41 @@ int pthread_cond_timedwait(pthread_cond_t *cond, * to the CLOCK_MONOTONIC clock instead, to avoid any problems when * the wall-clock time is changed brutally */ +int pthread_cond_timedwait_monotonic_np(pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime); + +/* BIONIC: DEPRECATED. same as pthread_cond_timedwait_monotonic_np() + * unfortunately pthread_cond_timedwait_monotonic has shipped already + */ int pthread_cond_timedwait_monotonic(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); +#define HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC 1 + +/* BIONIC: same as pthread_cond_timedwait, except the 'reltime' given refers + * is relative to the current time. + */ +int pthread_cond_timedwait_relative_np(pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec *reltime); + +#define HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE 1 + + + int pthread_cond_timeout_np(pthread_cond_t *cond, pthread_mutex_t * mutex, unsigned msecs); +/* same as pthread_mutex_lock(), but will wait up to 'msecs' milli-seconds + * before returning. same return values than pthread_mutex_trylock though, i.e. + * returns EBUSY if the lock could not be acquired after the timeout + * expired. + */ +int pthread_mutex_lock_timeout_np(pthread_mutex_t *mutex, unsigned msecs); + int pthread_key_create(pthread_key_t *key, void (*destructor_function)(void *)); int pthread_key_delete (pthread_key_t); int pthread_setspecific(pthread_key_t key, const void *value); diff --git a/libc/include/time.h b/libc/include/time.h index 35c2358..5d1a0e2 100644 --- a/libc/include/time.h +++ b/libc/include/time.h @@ -79,9 +79,29 @@ extern struct tm* gmtime_r(const time_t *timep, struct tm *result); extern char* strptime(const char *buf, const char *fmt, struct tm *tm); extern size_t strftime(char *s, size_t max, const char *format, const struct tm *tm); +/* ANDROID-BEGIN */ +struct strftime_locale { + const char * mon[12]; + const char * month[12]; + const char * standalone_month[12]; + const char * wday[7]; + const char * weekday[7]; + const char * X_fmt; + const char * x_fmt; + const char * c_fmt; + const char * am; + const char * pm; + const char * date_fmt; +}; + +extern size_t strftime_tz(char *s, size_t max, const char *format, const struct tm *tm, const struct strftime_locale* lc); +/* ANDROID-END */ + extern char *ctime(const time_t *timep); extern char *ctime_r(const time_t *timep, char *buf); +extern void tzset(void); + /* global includes */ extern char* tzname[]; extern int daylight; @@ -89,7 +109,7 @@ extern long int timezone; #define CLOCKS_PER_SEC 1000000 -extern clock_t clock(); +extern clock_t clock(void); /* BIONIC: extra linux clock goodies */ extern int clock_getres(int, struct timespec *); diff --git a/libc/kernel/common/linux/akm8973.h b/libc/kernel/common/linux/akm8973.h new file mode 100644 index 0000000..2892f72 --- /dev/null +++ b/libc/kernel/common/linux/akm8973.h @@ -0,0 +1,45 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + **************************************************************************** + ****************************************************************************/ +#ifndef AKM8973_H +#define AKM8973_H + +#include <linux/ioctl.h> + +#define AKMIO 0xA1 + +#define ECS_IOCTL_WRITE _IOW(AKMIO, 0x01, char[5]) +#define ECS_IOCTL_READ _IOWR(AKMIO, 0x02, char[5]) +#define ECS_IOCTL_RESET _IO(AKMIO, 0x03) +#define ECS_IOCTL_SET_MODE _IOW(AKMIO, 0x04, short) +#define ECS_IOCTL_GETDATA _IOR(AKMIO, 0x05, char[RBUFF_SIZE+1]) +#define ECS_IOCTL_SET_YPR _IOW(AKMIO, 0x06, short[12]) +#define ECS_IOCTL_GET_OPEN_STATUS _IOR(AKMIO, 0x07, int) +#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(AKMIO, 0x08, int) +#define ECS_IOCTL_GET_DELAY _IOR(AKMIO, 0x30, short) + +#define ECS_IOCTL_APP_SET_MODE _IOW(AKMIO, 0x10, short) +#define ECS_IOCTL_APP_SET_MFLAG _IOW(AKMIO, 0x11, short) +#define ECS_IOCTL_APP_GET_MFLAG _IOW(AKMIO, 0x12, short) +#define ECS_IOCTL_APP_SET_AFLAG _IOW(AKMIO, 0x13, short) +#define ECS_IOCTL_APP_GET_AFLAG _IOR(AKMIO, 0x14, short) +#define ECS_IOCTL_APP_SET_TFLAG _IOR(AKMIO, 0x15, short) +#define ECS_IOCTL_APP_GET_TFLAG _IOR(AKMIO, 0x16, short) +#define ECS_IOCTL_APP_RESET_PEDOMETER _IO(AKMIO, 0x17) +#define ECS_IOCTL_APP_SET_DELAY _IOW(AKMIO, 0x18, short) +#define ECS_IOCTL_APP_GET_DELAY ECS_IOCTL_GET_DELAY +#define ECS_IOCTL_APP_SET_MVFLAG _IOW(AKMIO, 0x19, short) +#define ECS_IOCTL_APP_GET_MVFLAG _IOR(AKMIO, 0x1A, short) + +#define ECS_IOCTL_SET_STEP_CNT _IOW(AKMIO, 0x20, short) +#endif + + diff --git a/libc/kernel/common/linux/android_pmem.h b/libc/kernel/common/linux/android_pmem.h index 858857e..bdf3aba 100644 --- a/libc/kernel/common/linux/android_pmem.h +++ b/libc/kernel/common/linux/android_pmem.h @@ -12,40 +12,36 @@ #ifndef _ANDROID_PMEM_H_ #define _ANDROID_PMEM_H_ -#include <stdint.h> - -#ifndef __user -#define __user -#endif - -struct pmem_region { - unsigned long offset; - unsigned long len; -}; - #define PMEM_IOCTL_MAGIC 'p' -#define PMEM_GET_PHYS _IOW(PMEM_IOCTL_MAGIC, 1, struct pmem_region *) -#define PMEM_MAP _IOW(PMEM_IOCTL_MAGIC, 2, struct pmem_region *) -#define PMEM_GET_SIZE _IOW(PMEM_IOCTL_MAGIC, 3, struct pmem_region *) -#define PMEM_UNMAP _IOW(PMEM_IOCTL_MAGIC, 4, struct pmem_region *) +#define PMEM_GET_PHYS _IOW(PMEM_IOCTL_MAGIC, 1, unsigned int) +#define PMEM_MAP _IOW(PMEM_IOCTL_MAGIC, 2, unsigned int) +#define PMEM_GET_SIZE _IOW(PMEM_IOCTL_MAGIC, 3, unsigned int) +#define PMEM_UNMAP _IOW(PMEM_IOCTL_MAGIC, 4, unsigned int) #define PMEM_ALLOCATE _IOW(PMEM_IOCTL_MAGIC, 5, unsigned int) #define PMEM_CONNECT _IOW(PMEM_IOCTL_MAGIC, 6, unsigned int) -#define PMEM_GET_TOTAL_SIZE _IOW(PMEM_IOCTL_MAGIC, 7, struct pmem_region *) +#define PMEM_GET_TOTAL_SIZE _IOW(PMEM_IOCTL_MAGIC, 7, unsigned int) + +struct android_pmem_platform_data +{ + const char* name; -#define HW3D_REVOKE_GPU _IOW(PMEM_IOCTL_MAGIC, 8, unsigned int) -#define HW3D_GRANT_GPU _IOW(PMEM_IOCTL_MAGIC, 9, unsigned int) -#define HW3D_WAIT_IRQ _IOW(PMEM_IOCTL_MAGIC,10, unsigned int) + unsigned long start; -struct android_pmem_platform_data; -struct pmem_file_operations { - int (*mmap) (struct file *, struct vm_area_struct *); - int (*open) (struct inode *, struct file *); - ssize_t (*read) (struct file *, char __user *, size_t, long long *); - int (*release) (struct inode *, struct file *); - long (*ioctl) (struct file *, unsigned int, unsigned long); + unsigned long size; + + unsigned no_allocator; + + unsigned cached; + + unsigned buffered; +}; + +struct pmem_region { + unsigned long offset; + unsigned long len; }; #endif diff --git a/libc/kernel/common/linux/capella_cm3602.h b/libc/kernel/common/linux/capella_cm3602.h new file mode 100644 index 0000000..6391e8a --- /dev/null +++ b/libc/kernel/common/linux/capella_cm3602.h @@ -0,0 +1,23 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + **************************************************************************** + ****************************************************************************/ +#ifndef __LINUX_CAPELLA_CM3602_H +#define __LINUX_CAPELLA_CM3602_H + +#include <linux/types.h> +#include <linux/ioctl.h> + +#define CAPELLA_CM3602_IOCTL_MAGIC 'c' +#define CAPELLA_CM3602_IOCTL_GET_ENABLED _IOR(CAPELLA_CM3602_IOCTL_MAGIC, 1, int *) +#define CAPELLA_CM3602_IOCTL_ENABLE _IOW(CAPELLA_CM3602_IOCTL_MAGIC, 2, int *) + +#endif + diff --git a/libc/kernel/common/linux/ethtool.h b/libc/kernel/common/linux/ethtool.h new file mode 100644 index 0000000..7a5b3cd --- /dev/null +++ b/libc/kernel/common/linux/ethtool.h @@ -0,0 +1,321 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + **************************************************************************** + ****************************************************************************/ +#ifndef _LINUX_ETHTOOL_H +#define _LINUX_ETHTOOL_H + +#include <linux/types.h> + +struct ethtool_cmd { + __u32 cmd; + __u32 supported; + __u32 advertising; + __u16 speed; + __u8 duplex; + __u8 port; + __u8 phy_address; + __u8 transceiver; + __u8 autoneg; + __u32 maxtxpkt; + __u32 maxrxpkt; + __u16 speed_hi; + __u16 reserved2; + __u32 reserved[3]; +}; + +#define ETHTOOL_BUSINFO_LEN 32 +struct ethtool_drvinfo { + __u32 cmd; + char driver[32]; + char version[32]; + char fw_version[32]; + char bus_info[ETHTOOL_BUSINFO_LEN]; + char reserved1[32]; + char reserved2[12]; + __u32 n_priv_flags; + __u32 n_stats; + __u32 testinfo_len; + __u32 eedump_len; + __u32 regdump_len; +}; + +#define SOPASS_MAX 6 + +struct ethtool_wolinfo { + __u32 cmd; + __u32 supported; + __u32 wolopts; + __u8 sopass[SOPASS_MAX]; +}; + +struct ethtool_value { + __u32 cmd; + __u32 data; +}; + +struct ethtool_regs { + __u32 cmd; + __u32 version; + __u32 len; + __u8 data[0]; +}; + +struct ethtool_eeprom { + __u32 cmd; + __u32 magic; + __u32 offset; + __u32 len; + __u8 data[0]; +}; + +struct ethtool_coalesce { + __u32 cmd; + + __u32 rx_coalesce_usecs; + + __u32 rx_max_coalesced_frames; + + __u32 rx_coalesce_usecs_irq; + __u32 rx_max_coalesced_frames_irq; + + __u32 tx_coalesce_usecs; + + __u32 tx_max_coalesced_frames; + + __u32 tx_coalesce_usecs_irq; + __u32 tx_max_coalesced_frames_irq; + + __u32 stats_block_coalesce_usecs; + + __u32 use_adaptive_rx_coalesce; + __u32 use_adaptive_tx_coalesce; + + __u32 pkt_rate_low; + __u32 rx_coalesce_usecs_low; + __u32 rx_max_coalesced_frames_low; + __u32 tx_coalesce_usecs_low; + __u32 tx_max_coalesced_frames_low; + + __u32 pkt_rate_high; + __u32 rx_coalesce_usecs_high; + __u32 rx_max_coalesced_frames_high; + __u32 tx_coalesce_usecs_high; + __u32 tx_max_coalesced_frames_high; + + __u32 rate_sample_interval; +}; + +struct ethtool_ringparam { + __u32 cmd; + + __u32 rx_max_pending; + __u32 rx_mini_max_pending; + __u32 rx_jumbo_max_pending; + __u32 tx_max_pending; + + __u32 rx_pending; + __u32 rx_mini_pending; + __u32 rx_jumbo_pending; + __u32 tx_pending; +}; + +struct ethtool_pauseparam { + __u32 cmd; + + __u32 autoneg; + __u32 rx_pause; + __u32 tx_pause; +}; + +#define ETH_GSTRING_LEN 32 +enum ethtool_stringset { + ETH_SS_TEST = 0, + ETH_SS_STATS, + ETH_SS_PRIV_FLAGS, +}; + +struct ethtool_gstrings { + __u32 cmd; + __u32 string_set; + __u32 len; + __u8 data[0]; +}; + +enum ethtool_test_flags { + ETH_TEST_FL_OFFLINE = (1 << 0), + ETH_TEST_FL_FAILED = (1 << 1), +}; + +struct ethtool_test { + __u32 cmd; + __u32 flags; + __u32 reserved; + __u32 len; + __u64 data[0]; +}; + +struct ethtool_stats { + __u32 cmd; + __u32 n_stats; + __u64 data[0]; +}; + +struct ethtool_perm_addr { + __u32 cmd; + __u32 size; + __u8 data[0]; +}; + +enum ethtool_flags { + ETH_FLAG_LRO = (1 << 15), +}; + +struct ethtool_rxnfc { + __u32 cmd; + __u32 flow_type; + __u64 data; +}; + +#define ETHTOOL_GSET 0x00000001 +#define ETHTOOL_SSET 0x00000002 +#define ETHTOOL_GDRVINFO 0x00000003 +#define ETHTOOL_GREGS 0x00000004 +#define ETHTOOL_GWOL 0x00000005 +#define ETHTOOL_SWOL 0x00000006 +#define ETHTOOL_GMSGLVL 0x00000007 +#define ETHTOOL_SMSGLVL 0x00000008 +#define ETHTOOL_NWAY_RST 0x00000009 +#define ETHTOOL_GLINK 0x0000000a +#define ETHTOOL_GEEPROM 0x0000000b +#define ETHTOOL_SEEPROM 0x0000000c +#define ETHTOOL_GCOALESCE 0x0000000e +#define ETHTOOL_SCOALESCE 0x0000000f +#define ETHTOOL_GRINGPARAM 0x00000010 +#define ETHTOOL_SRINGPARAM 0x00000011 +#define ETHTOOL_GPAUSEPARAM 0x00000012 +#define ETHTOOL_SPAUSEPARAM 0x00000013 +#define ETHTOOL_GRXCSUM 0x00000014 +#define ETHTOOL_SRXCSUM 0x00000015 +#define ETHTOOL_GTXCSUM 0x00000016 +#define ETHTOOL_STXCSUM 0x00000017 +#define ETHTOOL_GSG 0x00000018 +#define ETHTOOL_SSG 0x00000019 +#define ETHTOOL_TEST 0x0000001a +#define ETHTOOL_GSTRINGS 0x0000001b +#define ETHTOOL_PHYS_ID 0x0000001c +#define ETHTOOL_GSTATS 0x0000001d +#define ETHTOOL_GTSO 0x0000001e +#define ETHTOOL_STSO 0x0000001f +#define ETHTOOL_GPERMADDR 0x00000020 +#define ETHTOOL_GUFO 0x00000021 +#define ETHTOOL_SUFO 0x00000022 +#define ETHTOOL_GGSO 0x00000023 +#define ETHTOOL_SGSO 0x00000024 +#define ETHTOOL_GFLAGS 0x00000025 +#define ETHTOOL_SFLAGS 0x00000026 +#define ETHTOOL_GPFLAGS 0x00000027 +#define ETHTOOL_SPFLAGS 0x00000028 + +#define ETHTOOL_GRXFH 0x00000029 +#define ETHTOOL_SRXFH 0x0000002a +#define ETHTOOL_GGRO 0x0000002b +#define ETHTOOL_SGRO 0x0000002c + +#define SPARC_ETH_GSET ETHTOOL_GSET +#define SPARC_ETH_SSET ETHTOOL_SSET + +#define SUPPORTED_10baseT_Half (1 << 0) +#define SUPPORTED_10baseT_Full (1 << 1) +#define SUPPORTED_100baseT_Half (1 << 2) +#define SUPPORTED_100baseT_Full (1 << 3) +#define SUPPORTED_1000baseT_Half (1 << 4) +#define SUPPORTED_1000baseT_Full (1 << 5) +#define SUPPORTED_Autoneg (1 << 6) +#define SUPPORTED_TP (1 << 7) +#define SUPPORTED_AUI (1 << 8) +#define SUPPORTED_MII (1 << 9) +#define SUPPORTED_FIBRE (1 << 10) +#define SUPPORTED_BNC (1 << 11) +#define SUPPORTED_10000baseT_Full (1 << 12) +#define SUPPORTED_Pause (1 << 13) +#define SUPPORTED_Asym_Pause (1 << 14) +#define SUPPORTED_2500baseX_Full (1 << 15) + +#define ADVERTISED_10baseT_Half (1 << 0) +#define ADVERTISED_10baseT_Full (1 << 1) +#define ADVERTISED_100baseT_Half (1 << 2) +#define ADVERTISED_100baseT_Full (1 << 3) +#define ADVERTISED_1000baseT_Half (1 << 4) +#define ADVERTISED_1000baseT_Full (1 << 5) +#define ADVERTISED_Autoneg (1 << 6) +#define ADVERTISED_TP (1 << 7) +#define ADVERTISED_AUI (1 << 8) +#define ADVERTISED_MII (1 << 9) +#define ADVERTISED_FIBRE (1 << 10) +#define ADVERTISED_BNC (1 << 11) +#define ADVERTISED_10000baseT_Full (1 << 12) +#define ADVERTISED_Pause (1 << 13) +#define ADVERTISED_Asym_Pause (1 << 14) +#define ADVERTISED_2500baseX_Full (1 << 15) + +#define SPEED_10 10 +#define SPEED_100 100 +#define SPEED_1000 1000 +#define SPEED_2500 2500 +#define SPEED_10000 10000 + +#define DUPLEX_HALF 0x00 +#define DUPLEX_FULL 0x01 + +#define PORT_TP 0x00 +#define PORT_AUI 0x01 +#define PORT_MII 0x02 +#define PORT_FIBRE 0x03 +#define PORT_BNC 0x04 + +#define XCVR_INTERNAL 0x00 +#define XCVR_EXTERNAL 0x01 +#define XCVR_DUMMY1 0x02 +#define XCVR_DUMMY2 0x03 +#define XCVR_DUMMY3 0x04 + +#define AUTONEG_DISABLE 0x00 +#define AUTONEG_ENABLE 0x01 + +#define WAKE_PHY (1 << 0) +#define WAKE_UCAST (1 << 1) +#define WAKE_MCAST (1 << 2) +#define WAKE_BCAST (1 << 3) +#define WAKE_ARP (1 << 4) +#define WAKE_MAGIC (1 << 5) +#define WAKE_MAGICSECURE (1 << 6) + +#define TCP_V4_FLOW 0x01 +#define UDP_V4_FLOW 0x02 +#define SCTP_V4_FLOW 0x03 +#define AH_ESP_V4_FLOW 0x04 +#define TCP_V6_FLOW 0x05 +#define UDP_V6_FLOW 0x06 +#define SCTP_V6_FLOW 0x07 +#define AH_ESP_V6_FLOW 0x08 + +#define RXH_DEV_PORT (1 << 0) +#define RXH_L2DA (1 << 1) +#define RXH_VLAN (1 << 2) +#define RXH_L3_PROTO (1 << 3) +#define RXH_IP_SRC (1 << 4) +#define RXH_IP_DST (1 << 5) +#define RXH_L4_B_0_1 (1 << 6) +#define RXH_L4_B_2_3 (1 << 7) +#define RXH_DISCARD (1 << 31) + +#endif + diff --git a/libc/kernel/common/linux/lightsensor.h b/libc/kernel/common/linux/lightsensor.h new file mode 100644 index 0000000..70257ed --- /dev/null +++ b/libc/kernel/common/linux/lightsensor.h @@ -0,0 +1,24 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + **************************************************************************** + ****************************************************************************/ +#ifndef __LINUX_LIGHTSENSOR_H +#define __LINUX_LIGHTSENSOR_H + +#include <linux/types.h> +#include <linux/ioctl.h> + +#define LIGHTSENSOR_IOCTL_MAGIC 'l' + +#define LIGHTSENSOR_IOCTL_GET_ENABLED _IOR(LIGHTSENSOR_IOCTL_MAGIC, 1, int *) +#define LIGHTSENSOR_IOCTL_ENABLE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 2, int *) + +#endif + diff --git a/libc/kernel/common/linux/lis331dlh.h b/libc/kernel/common/linux/lis331dlh.h new file mode 100644 index 0000000..49d1b12 --- /dev/null +++ b/libc/kernel/common/linux/lis331dlh.h @@ -0,0 +1,30 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + **************************************************************************** + ****************************************************************************/ +#ifndef __LIS331DLH_H__ +#define __LIS331DLH_H__ + +#include <linux/ioctl.h> + +#define LIS331DLH_IOCTL_BASE 77 + +#define LIS331DLH_IOCTL_SET_DELAY _IOW(LIS331DLH_IOCTL_BASE, 0, int) +#define LIS331DLH_IOCTL_GET_DELAY _IOR(LIS331DLH_IOCTL_BASE, 1, int) +#define LIS331DLH_IOCTL_SET_ENABLE _IOW(LIS331DLH_IOCTL_BASE, 2, int) +#define LIS331DLH_IOCTL_GET_ENABLE _IOR(LIS331DLH_IOCTL_BASE, 3, int) +#define LIS331DLH_IOCTL_SET_G_RANGE _IOW(LIS331DLH_IOCTL_BASE, 4, int) + +#define LIS331DLH_G_2G 0x00 +#define LIS331DLH_G_4G 0x10 +#define LIS331DLH_G_8G 0x30 + +#endif + diff --git a/libc/kernel/common/linux/msm_hw3d.h b/libc/kernel/common/linux/msm_hw3d.h new file mode 100644 index 0000000..3d05106 --- /dev/null +++ b/libc/kernel/common/linux/msm_hw3d.h @@ -0,0 +1,44 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + **************************************************************************** + ****************************************************************************/ +#ifndef _MSM_HW3D_H_ +#define _MSM_HW3D_H_ + +#include <linux/fs.h> +#include <linux/ioctl.h> + +struct hw3d_region; + +#define HW3D_IOCTL_MAGIC 'h' +#define HW3D_WAIT_FOR_REVOKE _IO(HW3D_IOCTL_MAGIC, 0x80) +#define HW3D_WAIT_FOR_INTERRUPT _IO(HW3D_IOCTL_MAGIC, 0x81) +#define HW3D_GET_REGIONS _IOR(HW3D_IOCTL_MAGIC, 0x82, struct hw3d_region *) + +#define HW3D_REGION_OFFSET(id) ((((uint32_t)(id)) & 0xf) << 28) +#define HW3D_REGION_ID(addr) (((uint32_t)(addr) >> 28) & 0xf) +#define HW3D_OFFSET_IN_REGION(addr) ((uint32_t)(addr) & ~(0xfUL << 28)) + +enum { + HW3D_EBI = 0, + HW3D_SMI = 1, + HW3D_REGS = 2, + + HW3D_NUM_REGIONS = HW3D_REGS + 1, +}; + +struct hw3d_region { + unsigned long phys; + unsigned long map_offset; + unsigned long len; +}; + +#endif + diff --git a/libc/kernel/common/linux/msm_kgsl.h b/libc/kernel/common/linux/msm_kgsl.h new file mode 100644 index 0000000..d717e57 --- /dev/null +++ b/libc/kernel/common/linux/msm_kgsl.h @@ -0,0 +1,192 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + **************************************************************************** + ****************************************************************************/ +#ifndef _MSM_KGSL_H +#define _MSM_KGSL_H + +#define KGSL_CONTEXT_SAVE_GMEM 1 +#define KGSL_CONTEXT_NO_GMEM_ALLOC 2 + +#define KGSL_FLAGS_NORMALMODE 0x00000000 +#define KGSL_FLAGS_SAFEMODE 0x00000001 +#define KGSL_FLAGS_INITIALIZED0 0x00000002 +#define KGSL_FLAGS_INITIALIZED 0x00000004 +#define KGSL_FLAGS_STARTED 0x00000008 +#define KGSL_FLAGS_ACTIVE 0x00000010 +#define KGSL_FLAGS_RESERVED0 0x00000020 +#define KGSL_FLAGS_RESERVED1 0x00000040 +#define KGSL_FLAGS_RESERVED2 0x00000080 + +enum kgsl_deviceid { + KGSL_DEVICE_ANY = 0x00000000, + KGSL_DEVICE_YAMATO = 0x00000001, + KGSL_DEVICE_G12 = 0x00000002, + KGSL_DEVICE_MAX = 0x00000002 +}; + +struct kgsl_devinfo { + + unsigned int device_id; + + unsigned int chip_id; + unsigned int mmu_enabled; + unsigned int gmem_gpubaseaddr; + + unsigned int gmem_hostbaseaddr; + unsigned int gmem_sizebytes; +}; + +struct kgsl_devmemstore { + volatile unsigned int soptimestamp; + unsigned int sbz; + volatile unsigned int eoptimestamp; + unsigned int sbz2; +}; + +#define KGSL_DEVICE_MEMSTORE_OFFSET(field) offsetof(struct kgsl_devmemstore, field) + +enum kgsl_timestamp_type { + KGSL_TIMESTAMP_CONSUMED = 0x00000001, + KGSL_TIMESTAMP_RETIRED = 0x00000002, + KGSL_TIMESTAMP_MAX = 0x00000002, +}; + +enum kgsl_property_type { + KGSL_PROP_DEVICE_INFO = 0x00000001, + KGSL_PROP_DEVICE_SHADOW = 0x00000002, + KGSL_PROP_DEVICE_POWER = 0x00000003, + KGSL_PROP_SHMEM = 0x00000004, + KGSL_PROP_SHMEM_APERTURES = 0x00000005, + KGSL_PROP_MMU_ENABLE = 0x00000006 +}; + +struct kgsl_shadowprop { + unsigned int gpuaddr; + unsigned int size; + unsigned int flags; +}; + +#define KGSL_IOC_TYPE 0x09 + +struct kgsl_device_getproperty { + unsigned int type; + void *value; + unsigned int sizebytes; +}; + +#define IOCTL_KGSL_DEVICE_GETPROPERTY _IOWR(KGSL_IOC_TYPE, 0x2, struct kgsl_device_getproperty) + +struct kgsl_device_regread { + unsigned int offsetwords; + unsigned int value; +}; + +#define IOCTL_KGSL_DEVICE_REGREAD _IOWR(KGSL_IOC_TYPE, 0x3, struct kgsl_device_regread) + +struct kgsl_device_waittimestamp { + unsigned int timestamp; + unsigned int timeout; +}; + +#define IOCTL_KGSL_DEVICE_WAITTIMESTAMP _IOW(KGSL_IOC_TYPE, 0x6, struct kgsl_device_waittimestamp) + +struct kgsl_ringbuffer_issueibcmds { + unsigned int drawctxt_id; + unsigned int ibaddr; + unsigned int sizedwords; + unsigned int timestamp; + unsigned int flags; +}; + +#define IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS _IOWR(KGSL_IOC_TYPE, 0x10, struct kgsl_ringbuffer_issueibcmds) + +struct kgsl_cmdstream_readtimestamp { + unsigned int type; + unsigned int timestamp; +}; + +#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP _IOR(KGSL_IOC_TYPE, 0x11, struct kgsl_cmdstream_readtimestamp) + +struct kgsl_cmdstream_freememontimestamp { + unsigned int gpuaddr; + unsigned int type; + unsigned int timestamp; +}; + +#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP _IOR(KGSL_IOC_TYPE, 0x12, struct kgsl_cmdstream_freememontimestamp) + +struct kgsl_drawctxt_create { + unsigned int flags; + unsigned int drawctxt_id; +}; + +#define IOCTL_KGSL_DRAWCTXT_CREATE _IOWR(KGSL_IOC_TYPE, 0x13, struct kgsl_drawctxt_create) + +struct kgsl_drawctxt_destroy { + unsigned int drawctxt_id; +}; + +#define IOCTL_KGSL_DRAWCTXT_DESTROY _IOW(KGSL_IOC_TYPE, 0x14, struct kgsl_drawctxt_destroy) + +struct kgsl_sharedmem_from_pmem { + int pmem_fd; + unsigned int gpuaddr; +}; + +#define IOCTL_KGSL_SHAREDMEM_FROM_PMEM _IOWR(KGSL_IOC_TYPE, 0x20, struct kgsl_sharedmem_from_pmem) + +struct kgsl_sharedmem_free { + unsigned int gpuaddr; +}; + +#define IOCTL_KGSL_SHAREDMEM_FREE _IOW(KGSL_IOC_TYPE, 0x21, struct kgsl_sharedmem_free) + +struct kgsl_gmem_desc { + unsigned int x; + unsigned int y; + unsigned int width; + unsigned int height; + unsigned int pitch; +}; + +struct kgsl_buffer_desc { + void *hostptr; + unsigned int gpuaddr; + int size; + unsigned int format; + unsigned int pitch; + unsigned int enabled; +}; + +struct kgsl_bind_gmem_shadow { + unsigned int drawctxt_id; + struct kgsl_gmem_desc gmem_desc; + unsigned int shadow_x; + unsigned int shadow_y; + struct kgsl_buffer_desc shadow_buffer; + unsigned int buffer_id; +}; + +#define IOCTL_KGSL_DRAWCTXT_BIND_GMEM_SHADOW _IOW(KGSL_IOC_TYPE, 0x22, struct kgsl_bind_gmem_shadow) + +struct kgsl_sharedmem_from_vmalloc { + unsigned int gpuaddr; + unsigned int hostptr; + + int force_no_low_watermark; +}; + +#define IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC _IOWR(KGSL_IOC_TYPE, 0x23, struct kgsl_sharedmem_from_vmalloc) + +#define IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE _IOW(KGSL_IOC_TYPE, 0x24, struct kgsl_sharedmem_free) + +#endif + diff --git a/libc/kernel/common/linux/msm_mdp.h b/libc/kernel/common/linux/msm_mdp.h index 43fdac3..c355218 100644 --- a/libc/kernel/common/linux/msm_mdp.h +++ b/libc/kernel/common/linux/msm_mdp.h @@ -30,6 +30,7 @@ enum { MDP_Y_CBCR_H2V1, MDP_RGBA_8888, MDP_BGRA_8888, + MDP_RGBX_8888, MDP_IMGTYPE_LIMIT }; @@ -46,6 +47,7 @@ enum { #define MDP_ROT_270 (MDP_ROT_90|MDP_FLIP_UD|MDP_FLIP_LR) #define MDP_DITHER 0x8 #define MDP_BLUR 0x10 +#define MDP_BLEND_FG_PREMULT 0x20000 #define MDP_TRANSP_NOP 0xffffffff #define MDP_ALPHA_NOP 0xff @@ -81,3 +83,4 @@ struct mdp_blit_req_list { }; #endif + diff --git a/libc/kernel/common/linux/msm_q6vdec.h b/libc/kernel/common/linux/msm_q6vdec.h new file mode 100644 index 0000000..0182bfb --- /dev/null +++ b/libc/kernel/common/linux/msm_q6vdec.h @@ -0,0 +1,212 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + **************************************************************************** + ****************************************************************************/ +#ifndef _MSM_VDEC_H_ +#define _MSM_VDEC_H_ + +#include <linux/types.h> + +#define VDEC_IOCTL_MAGIC 'v' + +#define VDEC_IOCTL_INITIALIZE _IOWR(VDEC_IOCTL_MAGIC, 1, struct vdec_init) +#define VDEC_IOCTL_SETBUFFERS _IOW(VDEC_IOCTL_MAGIC, 2, struct vdec_buffer) +#define VDEC_IOCTL_QUEUE _IOWR(VDEC_IOCTL_MAGIC, 3, struct vdec_input_buf) +#define VDEC_IOCTL_REUSEFRAMEBUFFER _IOW(VDEC_IOCTL_MAGIC, 4, unsigned int) +#define VDEC_IOCTL_FLUSH _IOW(VDEC_IOCTL_MAGIC, 5, unsigned int) +#define VDEC_IOCTL_EOS _IO(VDEC_IOCTL_MAGIC, 6) +#define VDEC_IOCTL_GETMSG _IOR(VDEC_IOCTL_MAGIC, 7, struct vdec_msg) +#define VDEC_IOCTL_CLOSE _IO(VDEC_IOCTL_MAGIC, 8) +#define VDEC_IOCTL_FREEBUFFERS _IOW(VDEC_IOCTL_MAGIC, 9, struct vdec_buf_info) +#define VDEC_IOCTL_GETDECATTRIBUTES _IOR(VDEC_IOCTL_MAGIC, 10, struct vdec_dec_attributes) + +enum { + VDEC_FRAME_DECODE_OK, + VDEC_FRAME_DECODE_ERR, + VDEC_FATAL_ERR, + VDEC_FLUSH_FINISH, + VDEC_EOS, + VDEC_FRAME_FLUSH, + VDEC_STREAM_SWITCH, + VDEC_SUSPEND_FINISH, + VDEC_BUFFER_CONSUMED +}; + +enum { + VDEC_FLUSH_INPUT, + VDEC_FLUSH_OUTPUT, + VDEC_FLUSH_ALL +}; + +enum { + VDEC_BUFFER_TYPE_INPUT, + VDEC_BUFFER_TYPE_OUTPUT, + VDEC_BUFFER_TYPE_INTERNAL1, + VDEC_BUFFER_TYPE_INTERNAL2, +}; + +enum { + VDEC_QUEUE_SUCCESS, + VDEC_QUEUE_FAILED, + VDEC_QUEUE_BADSTATE, +}; + +struct vdec_input_buf_info { + u32 offset; + u32 data; + u32 size; + int timestamp_lo; + int timestamp_hi; + int avsync_state; + u32 flags; +}; + +struct vdec_buf_desc { + u32 bufsize; + u32 num_min_buffers; + u32 num_max_buffers; +}; + +struct vdec_buf_req { + u32 max_input_queue_size; + struct vdec_buf_desc input; + struct vdec_buf_desc output; + struct vdec_buf_desc dec_req1; + struct vdec_buf_desc dec_req2; +}; + +struct vdec_region_info { + u32 src_id; + u32 offset; + u32 size; +}; + +struct vdec_config { + u32 fourcc; + u32 width; + u32 height; + u32 order; + u32 notify_enable; + u32 vc1_rowbase; + u32 h264_startcode_detect; + u32 h264_nal_len_size; + u32 postproc_flag; + u32 fruc_enable; + u32 reserved; +}; + +struct vdec_vc1_panscan_regions { + int num; + int width[4]; + int height[4]; + int xoffset[4]; + int yoffset[4]; +}; + +struct vdec_cropping_window { + u32 x1; + u32 y1; + u32 x2; + u32 y2; +}; + +struct vdec_frame_info { + u32 status; + u32 offset; + u32 data1; + u32 data2; + int timestamp_lo; + int timestamp_hi; + int cal_timestamp_lo; + int cal_timestamp_hi; + u32 dec_width; + u32 dec_height; + struct vdec_cropping_window cwin; + u32 picture_type[2]; + u32 picture_format; + u32 vc1_rangeY; + u32 vc1_rangeUV; + u32 picture_resolution; + u32 frame_disp_repeat; + u32 repeat_first_field; + u32 top_field_first; + u32 interframe_interp; + struct vdec_vc1_panscan_regions panscan; + u32 concealed_macblk_num; + u32 flags; + u32 performance_stats; + u32 data3; +}; + +struct vdec_buf_info { + u32 buf_type; + struct vdec_region_info region; + u32 num_buf; + u32 islast; +}; + +struct vdec_buffer { + u32 pmem_id; + struct vdec_buf_info buf; +}; + +struct vdec_sequence { + u8 *header; + u32 len; +}; + +struct vdec_config_sps { + struct vdec_config cfg; + struct vdec_sequence seq; +}; + +#define VDEC_MSG_REUSEINPUTBUFFER 1 +#define VDEC_MSG_FRAMEDONE 2 + +struct vdec_msg { + u32 id; + + union { + + u32 buf_id; + + struct vdec_frame_info vfr_info; + }; +}; + +struct vdec_init { + struct vdec_config_sps sps_cfg; + struct vdec_buf_req *buf_req; +}; + +struct vdec_input_buf { + u32 pmem_id; + struct vdec_input_buf_info buffer; + struct vdec_queue_status *queue_status; +}; + +struct vdec_queue_status { + u32 status; +}; + +struct vdec_dec_attributes { + u32 fourcc; + u32 profile; + u32 level; + u32 dec_pic_width; + u32 dec_pic_height; + struct vdec_buf_desc input; + struct vdec_buf_desc output; + struct vdec_buf_desc dec_req1; + struct vdec_buf_desc dec_req2; +}; + +#endif + diff --git a/libc/kernel/common/linux/msm_q6venc.h b/libc/kernel/common/linux/msm_q6venc.h new file mode 100755 index 0000000..5b63680 --- /dev/null +++ b/libc/kernel/common/linux/msm_q6venc.h @@ -0,0 +1,109 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + **************************************************************************** + ****************************************************************************/ +#ifndef _MSM_VENC_H_ +#define _MSM_VENC_H_ + +#include <linux/types.h> + +struct venc_buf { + unsigned int src_id; + int fd; + unsigned long offset; + unsigned long size; +}; + +struct q6_init_config { + unsigned short venc_standard; + unsigned short partial_run_length_flag; + unsigned short h263_annex_ispt; + unsigned short h263_annex_jspt; + unsigned short h263_annex_tspt; + unsigned short rc_flag; + unsigned short one_mv_flag; + unsigned short acdc_pred_enable; + unsigned short rounding_bit_ctrl; + unsigned short rotation_flag; + unsigned short max_mvx; + unsigned short max_mvy; + unsigned short enc_frame_height_inmb; + unsigned short enc_frame_width_inmb; + unsigned short dvs_frame_height; + unsigned short dvs_frame_width; + + unsigned int ref_frame_buf1_phy; + unsigned int ref_frame_buf2_phy; + unsigned int rlc_buf1_phy; + unsigned int rlc_buf2_phy; + unsigned int rlc_buf_length; +}; + +struct init_config { + struct venc_buf ref_frame_buf1; + struct venc_buf ref_frame_buf2; + struct venc_buf rlc_buf1; + struct venc_buf rlc_buf2; + struct q6_init_config q6_init_config; +}; + +struct q6_encode_param { + unsigned int luma_addr; + unsigned int chroma_addr; + unsigned int x_offset; + unsigned int y_offset; + unsigned int frame_rho_budget; + unsigned int frame_type; + unsigned int qp; +}; + +struct encode_param { + struct venc_buf y_addr; + unsigned long uv_offset; + struct q6_encode_param q6_encode_param; +}; + +struct intra_refresh { + unsigned int intra_refresh_enable; + unsigned int intra_mb_num; +}; + +struct rc_config { + unsigned short max_frame_qp_up_delta; + unsigned short max_frame_qp_down_delta; + unsigned short min_frame_qp; + unsigned short max_frame_qp; +}; + +struct q6_frame_type { + unsigned int frame_type; + unsigned int frame_len; + unsigned int frame_addr; + unsigned int map_table; +}; + +struct frame_type { + struct venc_buf frame_addr; + struct q6_frame_type q6_frame_type; +}; + +#define VENC_IOCTL_MAGIC 'V' + +#define VENC_IOCTL_INITIALIZE _IOW(VENC_IOCTL_MAGIC, 1, struct init_config) +#define VENC_IOCTL_ENCODE _IOW(VENC_IOCTL_MAGIC, 2, struct encode_param) +#define VENC_IOCTL_INTRA_REFRESH _IOW(VENC_IOCTL_MAGIC, 3, struct intra_refresh) +#define VENC_IOCTL_RC_CONFIG _IOW(VENC_IOCTL_MAGIC, 4, struct rc_config) +#define VENC_IOCTL_ENCODE_CONFIG _IOW(VENC_IOCTL_MAGIC, 5, struct init_config) +#define VENC_IOCTL_STOP _IO(VENC_IOCTL_MAGIC, 6) +#define VENC_IOCTL_WAIT_FOR_ENCODE _IOR(VENC_IOCTL_MAGIC, 7, struct frame_type) +#define VENC_IOCTL_STOP_ENCODE _IO(VENC_IOCTL_MAGIC, 8) + +#endif + diff --git a/libc/kernel/common/linux/sfh7743.h b/libc/kernel/common/linux/sfh7743.h new file mode 100644 index 0000000..b6c363d --- /dev/null +++ b/libc/kernel/common/linux/sfh7743.h @@ -0,0 +1,22 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + **************************************************************************** + ****************************************************************************/ +#ifndef _LINUX_SFH7743_H_ +#define _LINUX_SFH7743_H_ + +#include <linux/ioctl.h> + +#define SFH7743_IO 0xA2 + +#define SFH7743_IOCTL_GET_ENABLE _IOR(SFH7743_IO, 0x00, char) +#define SFH7743_IOCTL_SET_ENABLE _IOW(SFH7743_IO, 0x01, char) + +#endif diff --git a/libc/kernel/common/linux/videodev.h b/libc/kernel/common/linux/videodev.h index 1f37fde..5a95f82 100644 --- a/libc/kernel/common/linux/videodev.h +++ b/libc/kernel/common/linux/videodev.h @@ -12,8 +12,25 @@ #ifndef __LINUX_VIDEODEV_H #define __LINUX_VIDEODEV_H +#include <linux/types.h> +#include <linux/ioctl.h> #include <linux/videodev2.h> +#define VID_TYPE_CAPTURE 1 +#define VID_TYPE_TUNER 2 +#define VID_TYPE_TELETEXT 4 +#define VID_TYPE_OVERLAY 8 +#define VID_TYPE_CHROMAKEY 16 +#define VID_TYPE_CLIPPING 32 +#define VID_TYPE_FRAMERAM 64 +#define VID_TYPE_SCALES 128 +#define VID_TYPE_MONOCHROME 256 +#define VID_TYPE_SUBCAPTURE 512 +#define VID_TYPE_MPEG_DECODER 1024 +#define VID_TYPE_MPEG_ENCODER 2048 +#define VID_TYPE_MJPEG_DECODER 4096 +#define VID_TYPE_MJPEG_ENCODER 8192 + struct video_capability { char name[32]; @@ -283,45 +300,6 @@ struct video_code #define VID_PLAY_RESET 13 #define VID_PLAY_END_MARK 14 -#define VID_HARDWARE_BT848 1 -#define VID_HARDWARE_QCAM_BW 2 -#define VID_HARDWARE_PMS 3 -#define VID_HARDWARE_QCAM_C 4 -#define VID_HARDWARE_PSEUDO 5 -#define VID_HARDWARE_SAA5249 6 -#define VID_HARDWARE_AZTECH 7 -#define VID_HARDWARE_SF16MI 8 -#define VID_HARDWARE_RTRACK 9 -#define VID_HARDWARE_ZOLTRIX 10 -#define VID_HARDWARE_SAA7146 11 -#define VID_HARDWARE_VIDEUM 12 -#define VID_HARDWARE_RTRACK2 13 -#define VID_HARDWARE_PERMEDIA2 14 -#define VID_HARDWARE_RIVA128 15 -#define VID_HARDWARE_PLANB 16 -#define VID_HARDWARE_BROADWAY 17 -#define VID_HARDWARE_GEMTEK 18 -#define VID_HARDWARE_TYPHOON 19 -#define VID_HARDWARE_VINO 20 -#define VID_HARDWARE_CADET 21 -#define VID_HARDWARE_TRUST 22 -#define VID_HARDWARE_TERRATEC 23 -#define VID_HARDWARE_CPIA 24 -#define VID_HARDWARE_ZR36120 25 -#define VID_HARDWARE_ZR36067 26 -#define VID_HARDWARE_OV511 27 -#define VID_HARDWARE_ZR356700 28 -#define VID_HARDWARE_W9966 29 -#define VID_HARDWARE_SE401 30 -#define VID_HARDWARE_PWC 31 -#define VID_HARDWARE_MEYE 32 -#define VID_HARDWARE_CPIA2 33 -#define VID_HARDWARE_VICAM 34 -#define VID_HARDWARE_SF16FMR2 35 -#define VID_HARDWARE_W9968CF 36 -#define VID_HARDWARE_SAA7114H 37 -#define VID_HARDWARE_SN9C102 38 -#define VID_HARDWARE_ARV 39 - #endif + diff --git a/libc/kernel/common/linux/videodev2.h b/libc/kernel/common/linux/videodev2.h index dae4e93..3a91510 100644 --- a/libc/kernel/common/linux/videodev2.h +++ b/libc/kernel/common/linux/videodev2.h @@ -11,7 +11,10 @@ ****************************************************************************/ #ifndef __LINUX_VIDEODEV2_H #define __LINUX_VIDEODEV2_H -#define __user + +#include <sys/time.h> +#include <linux/compiler.h> +#include <linux/ioctl.h> #include <linux/types.h> #define VIDEO_MAX_FRAME 32 @@ -31,7 +34,7 @@ #define VID_TYPE_MJPEG_DECODER 4096 #define VID_TYPE_MJPEG_ENCODER 8192 -#define v4l2_fourcc(a,b,c,d) (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24)) +#define v4l2_fourcc(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24)) enum v4l2_field { V4L2_FIELD_ANY = 0, @@ -42,10 +45,12 @@ enum v4l2_field { V4L2_FIELD_SEQ_TB = 5, V4L2_FIELD_SEQ_BT = 6, V4L2_FIELD_ALTERNATE = 7, + V4L2_FIELD_INTERLACED_TB = 8, + V4L2_FIELD_INTERLACED_BT = 9, }; -#define V4L2_FIELD_HAS_TOP(field) ((field) == V4L2_FIELD_TOP || (field) == V4L2_FIELD_INTERLACED || (field) == V4L2_FIELD_SEQ_TB || (field) == V4L2_FIELD_SEQ_BT) -#define V4L2_FIELD_HAS_BOTTOM(field) ((field) == V4L2_FIELD_BOTTOM || (field) == V4L2_FIELD_INTERLACED || (field) == V4L2_FIELD_SEQ_TB || (field) == V4L2_FIELD_SEQ_BT) -#define V4L2_FIELD_HAS_BOTH(field) ((field) == V4L2_FIELD_INTERLACED || (field) == V4L2_FIELD_SEQ_TB || (field) == V4L2_FIELD_SEQ_BT) +#define V4L2_FIELD_HAS_TOP(field) ((field) == V4L2_FIELD_TOP || (field) == V4L2_FIELD_INTERLACED || (field) == V4L2_FIELD_INTERLACED_TB || (field) == V4L2_FIELD_INTERLACED_BT || (field) == V4L2_FIELD_SEQ_TB || (field) == V4L2_FIELD_SEQ_BT) +#define V4L2_FIELD_HAS_BOTTOM(field) ((field) == V4L2_FIELD_BOTTOM || (field) == V4L2_FIELD_INTERLACED || (field) == V4L2_FIELD_INTERLACED_TB || (field) == V4L2_FIELD_INTERLACED_BT || (field) == V4L2_FIELD_SEQ_TB || (field) == V4L2_FIELD_SEQ_BT) +#define V4L2_FIELD_HAS_BOTH(field) ((field) == V4L2_FIELD_INTERLACED || (field) == V4L2_FIELD_INTERLACED_TB || (field) == V4L2_FIELD_INTERLACED_BT || (field) == V4L2_FIELD_SEQ_TB || (field) == V4L2_FIELD_SEQ_BT) enum v4l2_buf_type { V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, @@ -53,9 +58,10 @@ enum v4l2_buf_type { V4L2_BUF_TYPE_VIDEO_OVERLAY = 3, V4L2_BUF_TYPE_VBI_CAPTURE = 4, V4L2_BUF_TYPE_VBI_OUTPUT = 5, - V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6, V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7, + + V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8, V4L2_BUF_TYPE_PRIVATE = 0x80, }; @@ -118,8 +124,7 @@ struct v4l2_fract { __u32 denominator; }; -struct v4l2_capability -{ +struct v4l2_capability { __u8 driver[16]; __u8 card[32]; __u8 bus_info[32]; @@ -136,6 +141,8 @@ struct v4l2_capability #define V4L2_CAP_SLICED_VBI_CAPTURE 0x00000040 #define V4L2_CAP_SLICED_VBI_OUTPUT 0x00000080 #define V4L2_CAP_RDS_CAPTURE 0x00000100 +#define V4L2_CAP_VIDEO_OUTPUT_OVERLAY 0x00000200 +#define V4L2_CAP_HW_FREQ_SEEK 0x00000400 #define V4L2_CAP_TUNER 0x00010000 #define V4L2_CAP_AUDIO 0x00020000 @@ -145,8 +152,7 @@ struct v4l2_capability #define V4L2_CAP_ASYNCIO 0x02000000 #define V4L2_CAP_STREAMING 0x04000000 -struct v4l2_pix_format -{ +struct v4l2_pix_format { __u32 width; __u32 height; __u32 pixelformat; @@ -157,48 +163,71 @@ struct v4l2_pix_format __u32 priv; }; -#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') -#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') -#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') -#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') -#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R','G','B','R') -#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B','G','R','3') -#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R','G','B','3') -#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B','G','R','4') -#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R','G','B','4') -#define V4L2_PIX_FMT_GREY v4l2_fourcc('G','R','E','Y') -#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y','V','U','9') -#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2') -#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y','U','Y','V') -#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U','Y','V','Y') -#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') -#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') -#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y','4','1','P') - -#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N','V','1','2') -#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N','V','2','1') - -#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y','U','V','9') -#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y','U','1','2') -#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') -#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') -#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H','M','1','2') - -#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') - -#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M','J','P','G') -#define V4L2_PIX_FMT_JPEG v4l2_fourcc('J','P','E','G') -#define V4L2_PIX_FMT_DV v4l2_fourcc('d','v','s','d') -#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M','P','E','G') - -#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') -#define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S','9','1','0') -#define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P','W','C','1') -#define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P','W','C','2') -#define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E','6','2','5') - -struct v4l2_fmtdesc -{ +#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R', 'G', 'B', '1') +#define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R', '4', '4', '4') +#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R', 'G', 'B', 'O') +#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R', 'G', 'B', 'P') +#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') +#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') +#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3') +#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3') +#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4') +#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R', 'G', 'B', '4') +#define V4L2_PIX_FMT_GREY v4l2_fourcc('G', 'R', 'E', 'Y') +#define V4L2_PIX_FMT_Y16 v4l2_fourcc('Y', '1', '6', ' ') +#define V4L2_PIX_FMT_PAL8 v4l2_fourcc('P', 'A', 'L', '8') +#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y', 'V', 'U', '9') +#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y', 'V', '1', '2') +#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y', 'U', 'Y', 'V') +#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U', 'Y', 'V', 'Y') +#define V4L2_PIX_FMT_VYUY v4l2_fourcc('V', 'Y', 'U', 'Y') +#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') +#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4', '1', '1', 'P') +#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y', '4', '1', 'P') +#define V4L2_PIX_FMT_YUV444 v4l2_fourcc('Y', '4', '4', '4') +#define V4L2_PIX_FMT_YUV555 v4l2_fourcc('Y', 'U', 'V', 'O') +#define V4L2_PIX_FMT_YUV565 v4l2_fourcc('Y', 'U', 'V', 'P') +#define V4L2_PIX_FMT_YUV32 v4l2_fourcc('Y', 'U', 'V', '4') + +#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') +#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') +#define V4L2_PIX_FMT_NV16 v4l2_fourcc('N', 'V', '1', '6') +#define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') + +#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y', 'U', 'V', '9') +#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y', 'U', '1', '2') +#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y', 'Y', 'U', 'V') +#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') +#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') + +#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') +#define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') + +#define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') + +#define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0') +#define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') +#define V4L2_PIX_FMT_W1S_PATT v4l2_fourcc('P', 'A', 'T', '1') + +#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M', 'J', 'P', 'G') +#define V4L2_PIX_FMT_JPEG v4l2_fourcc('J', 'P', 'E', 'G') +#define V4L2_PIX_FMT_DV v4l2_fourcc('d', 'v', 's', 'd') +#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M', 'P', 'E', 'G') + +#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W', 'N', 'V', 'A') +#define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S', '9', '1', '0') +#define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P', 'W', 'C', '1') +#define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P', 'W', 'C', '2') +#define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E', '6', '2', '5') +#define V4L2_PIX_FMT_SPCA501 v4l2_fourcc('S', '5', '0', '1') +#define V4L2_PIX_FMT_SPCA505 v4l2_fourcc('S', '5', '0', '5') +#define V4L2_PIX_FMT_SPCA508 v4l2_fourcc('S', '5', '0', '8') +#define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S', '5', '6', '1') +#define V4L2_PIX_FMT_PAC207 v4l2_fourcc('P', '2', '0', '7') +#define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') +#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') + +struct v4l2_fmtdesc { __u32 index; enum v4l2_buf_type type; __u32 flags; @@ -209,8 +238,67 @@ struct v4l2_fmtdesc #define V4L2_FMT_FLAG_COMPRESSED 0x0001 -struct v4l2_timecode -{ +enum v4l2_frmsizetypes { + V4L2_FRMSIZE_TYPE_DISCRETE = 1, + V4L2_FRMSIZE_TYPE_CONTINUOUS = 2, + V4L2_FRMSIZE_TYPE_STEPWISE = 3, +}; + +struct v4l2_frmsize_discrete { + __u32 width; + __u32 height; +}; + +struct v4l2_frmsize_stepwise { + __u32 min_width; + __u32 max_width; + __u32 step_width; + __u32 min_height; + __u32 max_height; + __u32 step_height; +}; + +struct v4l2_frmsizeenum { + __u32 index; + __u32 pixel_format; + __u32 type; + + union { + struct v4l2_frmsize_discrete discrete; + struct v4l2_frmsize_stepwise stepwise; + }; + + __u32 reserved[2]; +}; + +enum v4l2_frmivaltypes { + V4L2_FRMIVAL_TYPE_DISCRETE = 1, + V4L2_FRMIVAL_TYPE_CONTINUOUS = 2, + V4L2_FRMIVAL_TYPE_STEPWISE = 3, +}; + +struct v4l2_frmival_stepwise { + struct v4l2_fract min; + struct v4l2_fract max; + struct v4l2_fract step; +}; + +struct v4l2_frmivalenum { + __u32 index; + __u32 pixel_format; + __u32 width; + __u32 height; + __u32 type; + + union { + struct v4l2_fract discrete; + struct v4l2_frmival_stepwise stepwise; + }; + + __u32 reserved[2]; +}; + +struct v4l2_timecode { __u32 type; __u32 flags; __u8 frames; @@ -232,8 +320,7 @@ struct v4l2_timecode #define V4L2_TC_USERBITS_USERDEFINED 0x0000 #define V4L2_TC_USERBITS_8BITCHARS 0x0008 -struct v4l2_jpegcompression -{ +struct v4l2_jpegcompression { int quality; int APPn; @@ -252,16 +339,14 @@ struct v4l2_jpegcompression #define V4L2_JPEG_MARKER_APP (1<<7) }; -struct v4l2_requestbuffers -{ +struct v4l2_requestbuffers { __u32 count; enum v4l2_buf_type type; enum v4l2_memory memory; __u32 reserved[2]; }; -struct v4l2_buffer -{ +struct v4l2_buffer { __u32 index; enum v4l2_buf_type type; __u32 bytesused; @@ -290,12 +375,11 @@ struct v4l2_buffer #define V4L2_BUF_FLAG_TIMECODE 0x0100 #define V4L2_BUF_FLAG_INPUT 0x0200 -struct v4l2_framebuffer -{ +struct v4l2_framebuffer { __u32 capability; __u32 flags; - void* base; + void *base; struct v4l2_pix_format fmt; }; @@ -303,29 +387,35 @@ struct v4l2_framebuffer #define V4L2_FBUF_CAP_CHROMAKEY 0x0002 #define V4L2_FBUF_CAP_LIST_CLIPPING 0x0004 #define V4L2_FBUF_CAP_BITMAP_CLIPPING 0x0008 +#define V4L2_FBUF_CAP_LOCAL_ALPHA 0x0010 +#define V4L2_FBUF_CAP_GLOBAL_ALPHA 0x0020 +#define V4L2_FBUF_CAP_LOCAL_INV_ALPHA 0x0040 +#define V4L2_FBUF_CAP_SRC_CHROMAKEY 0x0080 #define V4L2_FBUF_FLAG_PRIMARY 0x0001 #define V4L2_FBUF_FLAG_OVERLAY 0x0002 #define V4L2_FBUF_FLAG_CHROMAKEY 0x0004 +#define V4L2_FBUF_FLAG_LOCAL_ALPHA 0x0008 +#define V4L2_FBUF_FLAG_GLOBAL_ALPHA 0x0010 +#define V4L2_FBUF_FLAG_LOCAL_INV_ALPHA 0x0020 +#define V4L2_FBUF_FLAG_SRC_CHROMAKEY 0x0040 -struct v4l2_clip -{ +struct v4l2_clip { struct v4l2_rect c; struct v4l2_clip __user *next; }; -struct v4l2_window -{ +struct v4l2_window { struct v4l2_rect w; enum v4l2_field field; __u32 chromakey; struct v4l2_clip __user *clips; __u32 clipcount; void __user *bitmap; + __u8 global_alpha; }; -struct v4l2_captureparm -{ +struct v4l2_captureparm { __u32 capability; __u32 capturemode; struct v4l2_fract timeperframe; @@ -337,8 +427,7 @@ struct v4l2_captureparm #define V4L2_MODE_HIGHQUALITY 0x0001 #define V4L2_CAP_TIMEPERFRAME 0x1000 -struct v4l2_outputparm -{ +struct v4l2_outputparm { __u32 capability; __u32 outputmode; struct v4l2_fract timeperframe; @@ -411,8 +500,7 @@ typedef __u64 v4l2_std_id; #define V4L2_STD_UNKNOWN 0 #define V4L2_STD_ALL (V4L2_STD_525_60 | V4L2_STD_625_50) -struct v4l2_standard -{ +struct v4l2_standard { __u32 index; v4l2_std_id id; __u8 name[24]; @@ -421,8 +509,7 @@ struct v4l2_standard __u32 reserved[4]; }; -struct v4l2_input -{ +struct v4l2_input { __u32 index; __u8 name[32]; __u32 type; @@ -451,8 +538,7 @@ struct v4l2_input #define V4L2_IN_ST_NO_ACCESS 0x02000000 #define V4L2_IN_ST_VTR 0x04000000 -struct v4l2_output -{ +struct v4l2_output { __u32 index; __u8 name[32]; __u32 type; @@ -466,14 +552,12 @@ struct v4l2_output #define V4L2_OUTPUT_TYPE_ANALOG 2 #define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 -struct v4l2_control -{ +struct v4l2_control { __u32 id; __s32 value; }; -struct v4l2_ext_control -{ +struct v4l2_ext_control { __u32 id; __u32 reserved2[2]; union { @@ -483,8 +567,7 @@ struct v4l2_ext_control }; } __attribute__ ((packed)); -struct v4l2_ext_controls -{ +struct v4l2_ext_controls { __u32 ctrl_class; __u32 count; __u32 error_idx; @@ -494,13 +577,13 @@ struct v4l2_ext_controls #define V4L2_CTRL_CLASS_USER 0x00980000 #define V4L2_CTRL_CLASS_MPEG 0x00990000 +#define V4L2_CTRL_CLASS_CAMERA 0x009a0000 #define V4L2_CTRL_ID_MASK (0x0fffffff) #define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL) #define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000) -struct v4l2_queryctrl -{ +struct v4l2_queryctrl { __u32 id; enum v4l2_ctrl_type type; __u8 name[32]; @@ -512,8 +595,7 @@ struct v4l2_queryctrl __u32 reserved[2]; }; -struct v4l2_querymenu -{ +struct v4l2_querymenu { __u32 id; __u32 index; __u8 name[32]; @@ -545,7 +627,7 @@ struct v4l2_querymenu #define V4L2_CID_AUDIO_TREBLE (V4L2_CID_BASE+8) #define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9) #define V4L2_CID_AUDIO_LOUDNESS (V4L2_CID_BASE+10) -#define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11) +#define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11) #define V4L2_CID_AUTO_WHITE_BALANCE (V4L2_CID_BASE+12) #define V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13) #define V4L2_CID_RED_BALANCE (V4L2_CID_BASE+14) @@ -557,9 +639,31 @@ struct v4l2_querymenu #define V4L2_CID_GAIN (V4L2_CID_BASE+19) #define V4L2_CID_HFLIP (V4L2_CID_BASE+20) #define V4L2_CID_VFLIP (V4L2_CID_BASE+21) + #define V4L2_CID_HCENTER (V4L2_CID_BASE+22) #define V4L2_CID_VCENTER (V4L2_CID_BASE+23) -#define V4L2_CID_LASTP1 (V4L2_CID_BASE+24) + +#define V4L2_CID_POWER_LINE_FREQUENCY (V4L2_CID_BASE+24) +enum v4l2_power_line_frequency { + V4L2_CID_POWER_LINE_FREQUENCY_DISABLED = 0, + V4L2_CID_POWER_LINE_FREQUENCY_50HZ = 1, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ = 2, +}; +#define V4L2_CID_HUE_AUTO (V4L2_CID_BASE+25) +#define V4L2_CID_WHITE_BALANCE_TEMPERATURE (V4L2_CID_BASE+26) +#define V4L2_CID_SHARPNESS (V4L2_CID_BASE+27) +#define V4L2_CID_BACKLIGHT_COMPENSATION (V4L2_CID_BASE+28) +#define V4L2_CID_CHROMA_AGC (V4L2_CID_BASE+29) +#define V4L2_CID_COLOR_KILLER (V4L2_CID_BASE+30) +#define V4L2_CID_COLORFX (V4L2_CID_BASE+31) +#define V4L2_CID_ROTATE (V4L2_CID_BASE+32) +#define V4L2_CID_BG_COLOR (V4L2_CID_BASE+33) +#define V4L2_CID_LASTP1 (V4L2_CID_BASE+34) +enum v4l2_colorfx { + V4L2_COLORFX_NONE = 0, + V4L2_COLORFX_BW = 1, + V4L2_COLORFX_SEPIA = 2, +}; #define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900) #define V4L2_CID_MPEG_CLASS (V4L2_CTRL_CLASS_MPEG | 1) @@ -596,6 +700,8 @@ enum v4l2_mpeg_audio_encoding { V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0, V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1, V4L2_MPEG_AUDIO_ENCODING_LAYER_3 = 2, + V4L2_MPEG_AUDIO_ENCODING_AAC = 3, + V4L2_MPEG_AUDIO_ENCODING_AC3 = 4, }; #define V4L2_CID_MPEG_AUDIO_L1_BITRATE (V4L2_CID_MPEG_BASE+102) enum v4l2_mpeg_audio_l1_bitrate { @@ -673,11 +779,36 @@ enum v4l2_mpeg_audio_crc { V4L2_MPEG_AUDIO_CRC_NONE = 0, V4L2_MPEG_AUDIO_CRC_CRC16 = 1, }; +#define V4L2_CID_MPEG_AUDIO_MUTE (V4L2_CID_MPEG_BASE+109) +#define V4L2_CID_MPEG_AUDIO_AAC_BITRATE (V4L2_CID_MPEG_BASE+110) +#define V4L2_CID_MPEG_AUDIO_AC3_BITRATE (V4L2_CID_MPEG_BASE+111) +enum v4l2_mpeg_audio_ac3_bitrate { + V4L2_MPEG_AUDIO_AC3_BITRATE_32K = 0, + V4L2_MPEG_AUDIO_AC3_BITRATE_40K = 1, + V4L2_MPEG_AUDIO_AC3_BITRATE_48K = 2, + V4L2_MPEG_AUDIO_AC3_BITRATE_56K = 3, + V4L2_MPEG_AUDIO_AC3_BITRATE_64K = 4, + V4L2_MPEG_AUDIO_AC3_BITRATE_80K = 5, + V4L2_MPEG_AUDIO_AC3_BITRATE_96K = 6, + V4L2_MPEG_AUDIO_AC3_BITRATE_112K = 7, + V4L2_MPEG_AUDIO_AC3_BITRATE_128K = 8, + V4L2_MPEG_AUDIO_AC3_BITRATE_160K = 9, + V4L2_MPEG_AUDIO_AC3_BITRATE_192K = 10, + V4L2_MPEG_AUDIO_AC3_BITRATE_224K = 11, + V4L2_MPEG_AUDIO_AC3_BITRATE_256K = 12, + V4L2_MPEG_AUDIO_AC3_BITRATE_320K = 13, + V4L2_MPEG_AUDIO_AC3_BITRATE_384K = 14, + V4L2_MPEG_AUDIO_AC3_BITRATE_448K = 15, + V4L2_MPEG_AUDIO_AC3_BITRATE_512K = 16, + V4L2_MPEG_AUDIO_AC3_BITRATE_576K = 17, + V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18, +}; #define V4L2_CID_MPEG_VIDEO_ENCODING (V4L2_CID_MPEG_BASE+200) enum v4l2_mpeg_video_encoding { V4L2_MPEG_VIDEO_ENCODING_MPEG_1 = 0, V4L2_MPEG_VIDEO_ENCODING_MPEG_2 = 1, + V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC = 2, }; #define V4L2_CID_MPEG_VIDEO_ASPECT (V4L2_CID_MPEG_BASE+201) enum v4l2_mpeg_video_aspect { @@ -698,6 +829,8 @@ enum v4l2_mpeg_video_bitrate_mode { #define V4L2_CID_MPEG_VIDEO_BITRATE (V4L2_CID_MPEG_BASE+207) #define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK (V4L2_CID_MPEG_BASE+208) #define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209) +#define V4L2_CID_MPEG_VIDEO_MUTE (V4L2_CID_MPEG_BASE+210) +#define V4L2_CID_MPEG_VIDEO_MUTE_YUV (V4L2_CID_MPEG_BASE+211) #define V4L2_CID_MPEG_CX2341X_BASE (V4L2_CTRL_CLASS_MPEG | 0x1000) #define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+0) @@ -737,9 +870,40 @@ enum v4l2_mpeg_cx2341x_video_median_filter_type { #define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+8) #define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+9) #define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+10) +#define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS (V4L2_CID_MPEG_CX2341X_BASE+11) + +#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900) +#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1) + +#define V4L2_CID_EXPOSURE_AUTO (V4L2_CID_CAMERA_CLASS_BASE+1) +enum v4l2_exposure_auto_type { + V4L2_EXPOSURE_AUTO = 0, + V4L2_EXPOSURE_MANUAL = 1, + V4L2_EXPOSURE_SHUTTER_PRIORITY = 2, + V4L2_EXPOSURE_APERTURE_PRIORITY = 3 +}; +#define V4L2_CID_EXPOSURE_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+2) +#define V4L2_CID_EXPOSURE_AUTO_PRIORITY (V4L2_CID_CAMERA_CLASS_BASE+3) -struct v4l2_tuner -{ +#define V4L2_CID_PAN_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+4) +#define V4L2_CID_TILT_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+5) +#define V4L2_CID_PAN_RESET (V4L2_CID_CAMERA_CLASS_BASE+6) +#define V4L2_CID_TILT_RESET (V4L2_CID_CAMERA_CLASS_BASE+7) + +#define V4L2_CID_PAN_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+8) +#define V4L2_CID_TILT_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+9) + +#define V4L2_CID_FOCUS_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+10) +#define V4L2_CID_FOCUS_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+11) +#define V4L2_CID_FOCUS_AUTO (V4L2_CID_CAMERA_CLASS_BASE+12) + +#define V4L2_CID_ZOOM_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+13) +#define V4L2_CID_ZOOM_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+14) +#define V4L2_CID_ZOOM_CONTINUOUS (V4L2_CID_CAMERA_CLASS_BASE+15) + +#define V4L2_CID_PRIVACY (V4L2_CID_CAMERA_CLASS_BASE+16) + +struct v4l2_tuner { __u32 index; __u8 name[32]; enum v4l2_tuner_type type; @@ -753,8 +917,7 @@ struct v4l2_tuner __u32 reserved[4]; }; -struct v4l2_modulator -{ +struct v4l2_modulator { __u32 index; __u8 name[32]; __u32 capability; @@ -784,16 +947,22 @@ struct v4l2_modulator #define V4L2_TUNER_MODE_LANG1 0x0003 #define V4L2_TUNER_MODE_LANG1_LANG2 0x0004 -struct v4l2_frequency -{ +struct v4l2_frequency { __u32 tuner; enum v4l2_tuner_type type; __u32 frequency; __u32 reserved[8]; }; -struct v4l2_audio -{ +struct v4l2_hw_freq_seek { + __u32 tuner; + enum v4l2_tuner_type type; + __u32 seek_upward; + __u32 wrap_around; + __u32 reserved[8]; +}; + +struct v4l2_audio { __u32 index; __u8 name[32]; __u32 capability; @@ -806,8 +975,7 @@ struct v4l2_audio #define V4L2_AUDMODE_AVL 0x00001 -struct v4l2_audioout -{ +struct v4l2_audioout { __u32 index; __u8 name[32]; __u32 capability; @@ -815,8 +983,45 @@ struct v4l2_audioout __u32 reserved[2]; }; -struct v4l2_vbi_format -{ +#define V4L2_ENC_IDX_FRAME_I (0) +#define V4L2_ENC_IDX_FRAME_P (1) +#define V4L2_ENC_IDX_FRAME_B (2) +#define V4L2_ENC_IDX_FRAME_MASK (0xf) + +struct v4l2_enc_idx_entry { + __u64 offset; + __u64 pts; + __u32 length; + __u32 flags; + __u32 reserved[2]; +}; + +#define V4L2_ENC_IDX_ENTRIES (64) +struct v4l2_enc_idx { + __u32 entries; + __u32 entries_cap; + __u32 reserved[4]; + struct v4l2_enc_idx_entry entry[V4L2_ENC_IDX_ENTRIES]; +}; + +#define V4L2_ENC_CMD_START (0) +#define V4L2_ENC_CMD_STOP (1) +#define V4L2_ENC_CMD_PAUSE (2) +#define V4L2_ENC_CMD_RESUME (3) + +#define V4L2_ENC_CMD_STOP_AT_GOP_END (1 << 0) + +struct v4l2_encoder_cmd { + __u32 cmd; + __u32 flags; + union { + struct { + __u32 data[8]; + } raw; + }; +}; + +struct v4l2_vbi_format { __u32 sampling_rate; __u32 offset; __u32 samples_per_line; @@ -827,11 +1032,10 @@ struct v4l2_vbi_format __u32 reserved[2]; }; -#define V4L2_VBI_UNSYNC (1<< 0) -#define V4L2_VBI_INTERLACED (1<< 1) +#define V4L2_VBI_UNSYNC (1 << 0) +#define V4L2_VBI_INTERLACED (1 << 1) -struct v4l2_sliced_vbi_format -{ +struct v4l2_sliced_vbi_format { __u16 service_set; __u16 service_lines[2][24]; @@ -850,16 +1054,15 @@ struct v4l2_sliced_vbi_format #define V4L2_SLICED_VBI_525 (V4L2_SLICED_CAPTION_525) #define V4L2_SLICED_VBI_625 (V4L2_SLICED_TELETEXT_B | V4L2_SLICED_VPS | V4L2_SLICED_WSS_625) -struct v4l2_sliced_vbi_cap -{ +struct v4l2_sliced_vbi_cap { __u16 service_set; __u16 service_lines[2][24]; - __u32 reserved[4]; + enum v4l2_buf_type type; + __u32 reserved[3]; }; -struct v4l2_sliced_vbi_data -{ +struct v4l2_sliced_vbi_data { __u32 id; __u32 field; __u32 line; @@ -867,11 +1070,9 @@ struct v4l2_sliced_vbi_data __u8 data[48]; }; -struct v4l2_format -{ +struct v4l2_format { enum v4l2_buf_type type; - union - { + union { struct v4l2_pix_format pix; struct v4l2_window win; struct v4l2_vbi_format vbi; @@ -880,81 +1081,126 @@ struct v4l2_format } fmt; }; -struct v4l2_streamparm -{ +struct v4l2_streamparm { enum v4l2_buf_type type; - union - { + union { struct v4l2_captureparm capture; struct v4l2_outputparm output; __u8 raw_data[200]; } parm; }; -#define VIDIOC_QUERYCAP _IOR ('V', 0, struct v4l2_capability) -#define VIDIOC_RESERVED _IO ('V', 1) -#define VIDIOC_ENUM_FMT _IOWR ('V', 2, struct v4l2_fmtdesc) -#define VIDIOC_G_FMT _IOWR ('V', 4, struct v4l2_format) -#define VIDIOC_S_FMT _IOWR ('V', 5, struct v4l2_format) -#define VIDIOC_REQBUFS _IOWR ('V', 8, struct v4l2_requestbuffers) -#define VIDIOC_QUERYBUF _IOWR ('V', 9, struct v4l2_buffer) -#define VIDIOC_G_FBUF _IOR ('V', 10, struct v4l2_framebuffer) -#define VIDIOC_S_FBUF _IOW ('V', 11, struct v4l2_framebuffer) -#define VIDIOC_OVERLAY _IOW ('V', 14, int) -#define VIDIOC_QBUF _IOWR ('V', 15, struct v4l2_buffer) -#define VIDIOC_DQBUF _IOWR ('V', 17, struct v4l2_buffer) -#define VIDIOC_STREAMON _IOW ('V', 18, int) -#define VIDIOC_STREAMOFF _IOW ('V', 19, int) -#define VIDIOC_G_PARM _IOWR ('V', 21, struct v4l2_streamparm) -#define VIDIOC_S_PARM _IOWR ('V', 22, struct v4l2_streamparm) -#define VIDIOC_G_STD _IOR ('V', 23, v4l2_std_id) -#define VIDIOC_S_STD _IOW ('V', 24, v4l2_std_id) -#define VIDIOC_ENUMSTD _IOWR ('V', 25, struct v4l2_standard) -#define VIDIOC_ENUMINPUT _IOWR ('V', 26, struct v4l2_input) -#define VIDIOC_G_CTRL _IOWR ('V', 27, struct v4l2_control) -#define VIDIOC_S_CTRL _IOWR ('V', 28, struct v4l2_control) -#define VIDIOC_G_TUNER _IOWR ('V', 29, struct v4l2_tuner) -#define VIDIOC_S_TUNER _IOW ('V', 30, struct v4l2_tuner) -#define VIDIOC_G_AUDIO _IOR ('V', 33, struct v4l2_audio) -#define VIDIOC_S_AUDIO _IOW ('V', 34, struct v4l2_audio) -#define VIDIOC_QUERYCTRL _IOWR ('V', 36, struct v4l2_queryctrl) -#define VIDIOC_QUERYMENU _IOWR ('V', 37, struct v4l2_querymenu) -#define VIDIOC_G_INPUT _IOR ('V', 38, int) -#define VIDIOC_S_INPUT _IOWR ('V', 39, int) -#define VIDIOC_G_OUTPUT _IOR ('V', 46, int) -#define VIDIOC_S_OUTPUT _IOWR ('V', 47, int) -#define VIDIOC_ENUMOUTPUT _IOWR ('V', 48, struct v4l2_output) -#define VIDIOC_G_AUDOUT _IOR ('V', 49, struct v4l2_audioout) -#define VIDIOC_S_AUDOUT _IOW ('V', 50, struct v4l2_audioout) -#define VIDIOC_G_MODULATOR _IOWR ('V', 54, struct v4l2_modulator) -#define VIDIOC_S_MODULATOR _IOW ('V', 55, struct v4l2_modulator) -#define VIDIOC_G_FREQUENCY _IOWR ('V', 56, struct v4l2_frequency) -#define VIDIOC_S_FREQUENCY _IOW ('V', 57, struct v4l2_frequency) -#define VIDIOC_CROPCAP _IOWR ('V', 58, struct v4l2_cropcap) -#define VIDIOC_G_CROP _IOWR ('V', 59, struct v4l2_crop) -#define VIDIOC_S_CROP _IOW ('V', 60, struct v4l2_crop) -#define VIDIOC_G_JPEGCOMP _IOR ('V', 61, struct v4l2_jpegcompression) -#define VIDIOC_S_JPEGCOMP _IOW ('V', 62, struct v4l2_jpegcompression) -#define VIDIOC_QUERYSTD _IOR ('V', 63, v4l2_std_id) -#define VIDIOC_TRY_FMT _IOWR ('V', 64, struct v4l2_format) -#define VIDIOC_ENUMAUDIO _IOWR ('V', 65, struct v4l2_audio) -#define VIDIOC_ENUMAUDOUT _IOWR ('V', 66, struct v4l2_audioout) -#define VIDIOC_G_PRIORITY _IOR ('V', 67, enum v4l2_priority) -#define VIDIOC_S_PRIORITY _IOW ('V', 68, enum v4l2_priority) -#define VIDIOC_G_SLICED_VBI_CAP _IOR ('V', 69, struct v4l2_sliced_vbi_cap) -#define VIDIOC_LOG_STATUS _IO ('V', 70) -#define VIDIOC_G_EXT_CTRLS _IOWR ('V', 71, struct v4l2_ext_controls) -#define VIDIOC_S_EXT_CTRLS _IOWR ('V', 72, struct v4l2_ext_controls) -#define VIDIOC_TRY_EXT_CTRLS _IOWR ('V', 73, struct v4l2_ext_controls) +#define V4L2_CHIP_MATCH_HOST 0 +#define V4L2_CHIP_MATCH_I2C_DRIVER 1 +#define V4L2_CHIP_MATCH_I2C_ADDR 2 +#define V4L2_CHIP_MATCH_AC97 3 + +struct v4l2_dbg_match { + __u32 type; + union { + __u32 addr; + char name[32]; + }; +} __attribute__ ((packed)); + +struct v4l2_dbg_register { + struct v4l2_dbg_match match; + __u32 size; + __u64 reg; + __u64 val; +} __attribute__ ((packed)); + +struct v4l2_dbg_chip_ident { + struct v4l2_dbg_match match; + __u32 ident; + __u32 revision; +} __attribute__ ((packed)); + +struct v4l2_chip_ident_old { + __u32 match_type; + __u32 match_chip; + __u32 ident; + __u32 revision; +}; + +#define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability) +#define VIDIOC_RESERVED _IO('V', 1) +#define VIDIOC_ENUM_FMT _IOWR('V', 2, struct v4l2_fmtdesc) +#define VIDIOC_G_FMT _IOWR('V', 4, struct v4l2_format) +#define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format) +#define VIDIOC_REQBUFS _IOWR('V', 8, struct v4l2_requestbuffers) +#define VIDIOC_QUERYBUF _IOWR('V', 9, struct v4l2_buffer) +#define VIDIOC_G_FBUF _IOR('V', 10, struct v4l2_framebuffer) +#define VIDIOC_S_FBUF _IOW('V', 11, struct v4l2_framebuffer) +#define VIDIOC_OVERLAY _IOW('V', 14, int) +#define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer) +#define VIDIOC_DQBUF _IOWR('V', 17, struct v4l2_buffer) +#define VIDIOC_STREAMON _IOW('V', 18, int) +#define VIDIOC_STREAMOFF _IOW('V', 19, int) +#define VIDIOC_G_PARM _IOWR('V', 21, struct v4l2_streamparm) +#define VIDIOC_S_PARM _IOWR('V', 22, struct v4l2_streamparm) +#define VIDIOC_G_STD _IOR('V', 23, v4l2_std_id) +#define VIDIOC_S_STD _IOW('V', 24, v4l2_std_id) +#define VIDIOC_ENUMSTD _IOWR('V', 25, struct v4l2_standard) +#define VIDIOC_ENUMINPUT _IOWR('V', 26, struct v4l2_input) +#define VIDIOC_G_CTRL _IOWR('V', 27, struct v4l2_control) +#define VIDIOC_S_CTRL _IOWR('V', 28, struct v4l2_control) +#define VIDIOC_G_TUNER _IOWR('V', 29, struct v4l2_tuner) +#define VIDIOC_S_TUNER _IOW('V', 30, struct v4l2_tuner) +#define VIDIOC_G_AUDIO _IOR('V', 33, struct v4l2_audio) +#define VIDIOC_S_AUDIO _IOW('V', 34, struct v4l2_audio) +#define VIDIOC_QUERYCTRL _IOWR('V', 36, struct v4l2_queryctrl) +#define VIDIOC_QUERYMENU _IOWR('V', 37, struct v4l2_querymenu) +#define VIDIOC_G_INPUT _IOR('V', 38, int) +#define VIDIOC_S_INPUT _IOWR('V', 39, int) +#define VIDIOC_G_OUTPUT _IOR('V', 46, int) +#define VIDIOC_S_OUTPUT _IOWR('V', 47, int) +#define VIDIOC_ENUMOUTPUT _IOWR('V', 48, struct v4l2_output) +#define VIDIOC_G_AUDOUT _IOR('V', 49, struct v4l2_audioout) +#define VIDIOC_S_AUDOUT _IOW('V', 50, struct v4l2_audioout) +#define VIDIOC_G_MODULATOR _IOWR('V', 54, struct v4l2_modulator) +#define VIDIOC_S_MODULATOR _IOW('V', 55, struct v4l2_modulator) +#define VIDIOC_G_FREQUENCY _IOWR('V', 56, struct v4l2_frequency) +#define VIDIOC_S_FREQUENCY _IOW('V', 57, struct v4l2_frequency) +#define VIDIOC_CROPCAP _IOWR('V', 58, struct v4l2_cropcap) +#define VIDIOC_G_CROP _IOWR('V', 59, struct v4l2_crop) +#define VIDIOC_S_CROP _IOW('V', 60, struct v4l2_crop) +#define VIDIOC_G_JPEGCOMP _IOR('V', 61, struct v4l2_jpegcompression) +#define VIDIOC_S_JPEGCOMP _IOW('V', 62, struct v4l2_jpegcompression) +#define VIDIOC_QUERYSTD _IOR('V', 63, v4l2_std_id) +#define VIDIOC_TRY_FMT _IOWR('V', 64, struct v4l2_format) +#define VIDIOC_ENUMAUDIO _IOWR('V', 65, struct v4l2_audio) +#define VIDIOC_ENUMAUDOUT _IOWR('V', 66, struct v4l2_audioout) +#define VIDIOC_G_PRIORITY _IOR('V', 67, enum v4l2_priority) +#define VIDIOC_S_PRIORITY _IOW('V', 68, enum v4l2_priority) +#define VIDIOC_G_SLICED_VBI_CAP _IOWR('V', 69, struct v4l2_sliced_vbi_cap) +#define VIDIOC_LOG_STATUS _IO('V', 70) +#define VIDIOC_G_EXT_CTRLS _IOWR('V', 71, struct v4l2_ext_controls) +#define VIDIOC_S_EXT_CTRLS _IOWR('V', 72, struct v4l2_ext_controls) +#define VIDIOC_TRY_EXT_CTRLS _IOWR('V', 73, struct v4l2_ext_controls) +#define VIDIOC_ENUM_FRAMESIZES _IOWR('V', 74, struct v4l2_frmsizeenum) +#define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct v4l2_frmivalenum) +#define VIDIOC_G_ENC_INDEX _IOR('V', 76, struct v4l2_enc_idx) +#define VIDIOC_ENCODER_CMD _IOWR('V', 77, struct v4l2_encoder_cmd) +#define VIDIOC_TRY_ENCODER_CMD _IOWR('V', 78, struct v4l2_encoder_cmd) + +#define VIDIOC_DBG_S_REGISTER _IOW('V', 79, struct v4l2_dbg_register) +#define VIDIOC_DBG_G_REGISTER _IOWR('V', 80, struct v4l2_dbg_register) + +#define VIDIOC_DBG_G_CHIP_IDENT _IOWR('V', 81, struct v4l2_dbg_chip_ident) + +#define VIDIOC_G_CHIP_IDENT_OLD _IOWR('V', 81, struct v4l2_chip_ident_old) + +#define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) #ifdef __OLD_VIDIOC_ -#define VIDIOC_OVERLAY_OLD _IOWR ('V', 14, int) -#define VIDIOC_S_PARM_OLD _IOW ('V', 22, struct v4l2_streamparm) -#define VIDIOC_S_CTRL_OLD _IOW ('V', 28, struct v4l2_control) -#define VIDIOC_G_AUDIO_OLD _IOWR ('V', 33, struct v4l2_audio) -#define VIDIOC_G_AUDOUT_OLD _IOWR ('V', 49, struct v4l2_audioout) -#define VIDIOC_CROPCAP_OLD _IOR ('V', 58, struct v4l2_cropcap) +#define VIDIOC_OVERLAY_OLD _IOWR('V', 14, int) +#define VIDIOC_S_PARM_OLD _IOW('V', 22, struct v4l2_streamparm) +#define VIDIOC_S_CTRL_OLD _IOW('V', 28, struct v4l2_control) +#define VIDIOC_G_AUDIO_OLD _IOWR('V', 33, struct v4l2_audio) +#define VIDIOC_G_AUDOUT_OLD _IOWR('V', 49, struct v4l2_audioout) +#define VIDIOC_CROPCAP_OLD _IOR('V', 58, struct v4l2_cropcap) #endif #define BASE_VIDIOC_PRIVATE 192 diff --git a/libc/kernel/common/media/msm_camera.h b/libc/kernel/common/media/msm_camera.h index 6596d6b..a0b4a24 100644 --- a/libc/kernel/common/media/msm_camera.h +++ b/libc/kernel/common/media/msm_camera.h @@ -54,9 +54,9 @@ #define MSM_CAM_IOCTL_SET_CROP _IOW(MSM_CAM_IOCTL_MAGIC, 18, struct crop_info *) -#define MSM_CAM_IOCTL_PICT_PP _IOW(MSM_CAM_IOCTL_MAGIC, 19, uint8_t *) +#define MSM_CAM_IOCTL_PP _IOW(MSM_CAM_IOCTL_MAGIC, 19, uint8_t *) -#define MSM_CAM_IOCTL_PICT_PP_DONE _IOW(MSM_CAM_IOCTL_MAGIC, 20, struct msm_snapshot_pp_status *) +#define MSM_CAM_IOCTL_PP_DONE _IOW(MSM_CAM_IOCTL_MAGIC, 20, struct msm_snapshot_pp_status *) #define MSM_CAM_IOCTL_SENSOR_IO_CFG _IOW(MSM_CAM_IOCTL_MAGIC, 21, struct sensor_cfg_data *) @@ -73,6 +73,11 @@ #define MAX_SENSOR_NUM 3 #define MAX_SENSOR_NAME 32 +#define PP_SNAP 1 +#define PP_RAW_SNAP (1<<1) +#define PP_PREV (1<<2) +#define PP_MASK (PP_SNAP|PP_RAW_SNAP|PP_PREV) + #define MSM_CAM_CTRL_CMD_DONE 0 #define MSM_CAM_SENSOR_VFE_CMD 1 @@ -130,11 +135,12 @@ struct msm_camera_cfg_cmd { #define CMD_SNAP_BUF_RELEASE 11 #define CMD_SNAP_BUF_CFG 12 #define CMD_STATS_DISABLE 13 -#define CMD_STATS_ENABLE 14 +#define CMD_STATS_AEC_AWB_ENABLE 14 #define CMD_STATS_AF_ENABLE 15 #define CMD_STATS_BUF_RELEASE 16 #define CMD_STATS_AF_BUF_RELEASE 17 -#define UPDATE_STATS_INVALID 18 +#define CMD_STATS_ENABLE 18 +#define UPDATE_STATS_INVALID 19 struct msm_vfe_cfg_cmd { int cmd_type; @@ -150,7 +156,7 @@ struct camera_enable_cmd { #define MSM_PMEM_OUTPUT1 0 #define MSM_PMEM_OUTPUT2 1 #define MSM_PMEM_OUTPUT1_OUTPUT2 2 -#define MSM_PMEM_THUMBAIL 3 +#define MSM_PMEM_THUMBNAIL 3 #define MSM_PMEM_MAINIMG 4 #define MSM_PMEM_RAW_MAINIMG 5 #define MSM_PMEM_AEC_AWB 6 diff --git a/libc/kernel/tools/clean_header.py b/libc/kernel/tools/clean_header.py index de4bf85..28cb05e 100755 --- a/libc/kernel/tools/clean_header.py +++ b/libc/kernel/tools/clean_header.py @@ -96,7 +96,7 @@ if __name__ == "__main__": sys.exit(1) try: - optlist, args = getopt.getopt( sys.argv[1:], 'uv' ) + optlist, args = getopt.getopt( sys.argv[1:], 'uvk:' ) except: # unrecognized option sys.stderr.write( "error: unrecognized option\n" ) @@ -108,6 +108,8 @@ if __name__ == "__main__": elif opt == '-v': verbose = 1 D_setlevel(1) + elif opt == '-k': + kernel_original_path = arg if len(args) == 0: usage() diff --git a/libc/netbsd/net/getaddrinfo.c b/libc/netbsd/net/getaddrinfo.c index f2189fb..1233cb8 100644 --- a/libc/netbsd/net/getaddrinfo.c +++ b/libc/netbsd/net/getaddrinfo.c @@ -335,6 +335,36 @@ str2number(const char *p) return -1; } +/* Determine whether IPv6 connectivity is available. */ +static int +_have_ipv6() { + /* + * Connect a UDP socket to an global unicast IPv6 address. This will + * cause no network traffic, but will fail fast if the system has no or + * limited IPv6 connectivity (e.g., only a link-local address). + */ + static const struct sockaddr_in6 sin6_test = { + /* family, port, flow label */ + AF_INET6, 0, 0, + /* 2000:: */ + {{{ 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}}, + /* scope ID */ + 0}; + static const struct sockaddr *sa_test = (struct sockaddr *) &sin6_test; + int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (s < 0) + return 0; + int ret; + do { + ret = connect(s, sa_test, sizeof(sin6_test)); + } while (ret < 0 && errno == EINTR); + int have_ipv6 = (ret == 0); + do { + ret = close(s); + } while (ret < 0 && errno == EINTR); + return have_ipv6; +} + int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) @@ -1274,7 +1304,6 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap) name = va_arg(ap, char *); pai = va_arg(ap, const struct addrinfo *); - //fprintf(stderr, "_dns_getaddrinfo() name = '%s'\n", name); memset(&q, 0, sizeof(q)); @@ -1299,15 +1328,20 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap) /* prefer IPv6 */ q.name = name; q.qclass = C_IN; - q.qtype = T_AAAA; q.answer = buf->buf; q.anslen = sizeof(buf->buf); - q.next = &q2; - q2.name = name; - q2.qclass = C_IN; - q2.qtype = T_A; - q2.answer = buf2->buf; - q2.anslen = sizeof(buf2->buf); + /* If AI_ADDRCONFIG, lookup IPv6 only if we have connectivity */ + if (!(pai->ai_flags & AI_ADDRCONFIG) || _have_ipv6()) { + q.qtype = T_AAAA; + q.next = &q2; + q2.name = name; + q2.qclass = C_IN; + q2.qtype = T_A; + q2.answer = buf2->buf; + q2.anslen = sizeof(buf2->buf); + } else { + q.qtype = T_A; + } break; case AF_INET: q.name = name; diff --git a/libc/netbsd/resolv/res_send.c b/libc/netbsd/resolv/res_send.c index 3aca760..696f8cf 100644 --- a/libc/netbsd/resolv/res_send.c +++ b/libc/netbsd/resolv/res_send.c @@ -95,7 +95,6 @@ __RCSID("$NetBSD: res_send.c,v 1.9 2006/01/24 17:41:25 christos Exp $"); #include <sys/uio.h> #include <netinet/in.h> -#include <netinet/in6.h> #include "arpa_nameser.h" #include <arpa/inet.h> diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h index 82c8cd9..2e7a82b 100644 --- a/libc/private/bionic_tls.h +++ b/libc/private/bionic_tls.h @@ -88,7 +88,18 @@ extern int __set_tls(void *ptr); /* get the TLS */ #ifdef __arm__ -# define __get_tls() ( *((volatile void **) 0xffff0ff0) ) +/* For performance reasons, avoid calling the kernel helper + * Note that HAVE_ARM_TLS_REGISTER is build-specific + * (it must match your kernel configuration) + */ +# ifdef HAVE_ARM_TLS_REGISTER +# define __get_tls() \ + ({ register unsigned int __val asm("r0"); \ + asm ("mrc p15, 0, r0, c13, c0, 3" : "=r"(__val) ); \ + (volatile void*)__val; }) +# else /* !HAVE_ARM_TLS_REGISTER */ +# define __get_tls() ( *((volatile void **) 0xffff0ff0) ) +# endif #else extern void* __get_tls( void ); #endif diff --git a/libc/tzcode/asctime.c b/libc/tzcode/asctime.c index e0804f1..22bba34 100644 --- a/libc/tzcode/asctime.c +++ b/libc/tzcode/asctime.c @@ -11,7 +11,7 @@ #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)asctime.c 8.2"; +static char elsieid[] = "@(#)asctime.c 8.2"; #endif /* !defined NOID */ #endif /* !defined lint */ @@ -39,9 +39,9 @@ static char elsieid[] = "@(#)asctime.c 8.2"; ** but many implementations pad anyway; most likely the standards are buggy. */ #ifdef __GNUC__ -#define ASCTIME_FMT "%.3s %.3s%3d %2.2d:%2.2d:%2.2d %-4s\n" +#define ASCTIME_FMT "%.3s %.3s%3d %2.2d:%2.2d:%2.2d %-4s\n" #else /* !defined __GNUC__ */ -#define ASCTIME_FMT "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %-4s\n" +#define ASCTIME_FMT "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %-4s\n" #endif /* !defined __GNUC__ */ /* ** For years that are more than four digits we put extra spaces before the year @@ -50,12 +50,12 @@ static char elsieid[] = "@(#)asctime.c 8.2"; ** that no output is better than wrong output). */ #ifdef __GNUC__ -#define ASCTIME_FMT_B "%.3s %.3s%3d %2.2d:%2.2d:%2.2d %s\n" +#define ASCTIME_FMT_B "%.3s %.3s%3d %2.2d:%2.2d:%2.2d %s\n" #else /* !defined __GNUC__ */ -#define ASCTIME_FMT_B "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %s\n" +#define ASCTIME_FMT_B "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %s\n" #endif /* !defined __GNUC__ */ -#define STD_ASCTIME_BUF_SIZE 26 +#define STD_ASCTIME_BUF_SIZE 26 /* ** Big enough for something such as ** ??? ???-2147483648 -2147483648:-2147483648:-2147483648 -2147483648\n @@ -66,9 +66,9 @@ static char elsieid[] = "@(#)asctime.c 8.2"; ** as an example; the define below calculates the maximum for the system at ** hand. */ -#define MAX_ASCTIME_BUF_SIZE (2*3+5*INT_STRLEN_MAXIMUM(int)+7+2+1+1) +#define MAX_ASCTIME_BUF_SIZE (2*3+5*INT_STRLEN_MAXIMUM(int)+7+2+1+1) -static char buf_asctime[MAX_ASCTIME_BUF_SIZE]; +static char buf_asctime[MAX_ASCTIME_BUF_SIZE]; /* ** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, 2004 Edition. @@ -76,54 +76,54 @@ static char buf_asctime[MAX_ASCTIME_BUF_SIZE]; char * asctime_r(timeptr, buf) -register const struct tm * timeptr; -char * buf; +register const struct tm * timeptr; +char * buf; { - static const char wday_name[][3] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" - }; - static const char mon_name[][3] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - register const char * wn; - register const char * mn; - char year[INT_STRLEN_MAXIMUM(int) + 2]; - char result[MAX_ASCTIME_BUF_SIZE]; + static const char wday_name[][3] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + static const char mon_name[][3] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + register const char * wn; + register const char * mn; + char year[INT_STRLEN_MAXIMUM(int) + 2]; + char result[MAX_ASCTIME_BUF_SIZE]; - if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK) - wn = "???"; - else wn = wday_name[timeptr->tm_wday]; - if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR) - mn = "???"; - else mn = mon_name[timeptr->tm_mon]; - /* - ** Use strftime's %Y to generate the year, to avoid overflow problems - ** when computing timeptr->tm_year + TM_YEAR_BASE. - ** Assume that strftime is unaffected by other out-of-range members - ** (e.g., timeptr->tm_mday) when processing "%Y". - */ - (void) strftime(year, sizeof year, "%Y", timeptr); - /* - ** We avoid using snprintf since it's not available on all systems. - */ - (void) sprintf(result, - ((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B), - wn, mn, - timeptr->tm_mday, timeptr->tm_hour, - timeptr->tm_min, timeptr->tm_sec, - year); - if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime) { - (void) strcpy(buf, result); - return buf; - } else { + if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK) + wn = "???"; + else wn = wday_name[timeptr->tm_wday]; + if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR) + mn = "???"; + else mn = mon_name[timeptr->tm_mon]; + /* + ** Use strftime's %Y to generate the year, to avoid overflow problems + ** when computing timeptr->tm_year + TM_YEAR_BASE. + ** Assume that strftime is unaffected by other out-of-range members + ** (e.g., timeptr->tm_mday) when processing "%Y". + */ + (void) strftime(year, sizeof year, "%Y", timeptr); + /* + ** We avoid using snprintf since it's not available on all systems. + */ + (void) sprintf(result, + ((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B), + wn, mn, + timeptr->tm_mday, timeptr->tm_hour, + timeptr->tm_min, timeptr->tm_sec, + year); + if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime) { + (void) strcpy(buf, result); + return buf; + } else { #ifdef EOVERFLOW - errno = EOVERFLOW; + errno = EOVERFLOW; #else /* !defined EOVERFLOW */ - errno = EINVAL; + errno = EINVAL; #endif /* !defined EOVERFLOW */ - return NULL; - } + return NULL; + } } /* @@ -132,7 +132,7 @@ char * buf; char * asctime(timeptr) -register const struct tm * timeptr; +register const struct tm * timeptr; { - return asctime_r(timeptr, buf_asctime); + return asctime_r(timeptr, buf_asctime); } diff --git a/libc/tzcode/difftime.c b/libc/tzcode/difftime.c index da77977..f7581a4 100644 --- a/libc/tzcode/difftime.c +++ b/libc/tzcode/difftime.c @@ -5,61 +5,61 @@ #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)difftime.c 8.1"; +static char elsieid[] = "@(#)difftime.c 8.1"; #endif /* !defined NOID */ #endif /* !defined lint */ /*LINTLIBRARY*/ -#include "private.h" /* for time_t, TYPE_INTEGRAL, and TYPE_SIGNED */ +#include "private.h" /* for time_t, TYPE_INTEGRAL, and TYPE_SIGNED */ double difftime(time1, time0) -const time_t time1; -const time_t time0; +const time_t time1; +const time_t time0; { - /* - ** If (sizeof (double) > sizeof (time_t)) simply convert and subtract - ** (assuming that the larger type has more precision). - ** This is the common real-world case circa 2004. - */ - if (sizeof (double) > sizeof (time_t)) - return (double) time1 - (double) time0; - if (!TYPE_INTEGRAL(time_t)) { - /* - ** time_t is floating. - */ - return time1 - time0; - } - if (!TYPE_SIGNED(time_t)) { - /* - ** time_t is integral and unsigned. - ** The difference of two unsigned values can't overflow - ** if the minuend is greater than or equal to the subtrahend. - */ - if (time1 >= time0) - return time1 - time0; - else return -((double) (time0 - time1)); - } - /* - ** time_t is integral and signed. - ** Handle cases where both time1 and time0 have the same sign - ** (meaning that their difference cannot overflow). - */ - if ((time1 < 0) == (time0 < 0)) - return time1 - time0; - /* - ** time1 and time0 have opposite signs. - ** Punt if unsigned long is too narrow. - */ - if (sizeof (unsigned long) < sizeof (time_t)) - return (double) time1 - (double) time0; - /* - ** Stay calm...decent optimizers will eliminate the complexity below. - */ - if (time1 >= 0 /* && time0 < 0 */) - return (unsigned long) time1 + - (unsigned long) (-(time0 + 1)) + 1; - return -(double) ((unsigned long) time0 + - (unsigned long) (-(time1 + 1)) + 1); + /* + ** If (sizeof (double) > sizeof (time_t)) simply convert and subtract + ** (assuming that the larger type has more precision). + ** This is the common real-world case circa 2004. + */ + if (sizeof (double) > sizeof (time_t)) + return (double) time1 - (double) time0; + if (!TYPE_INTEGRAL(time_t)) { + /* + ** time_t is floating. + */ + return time1 - time0; + } + if (!TYPE_SIGNED(time_t)) { + /* + ** time_t is integral and unsigned. + ** The difference of two unsigned values can't overflow + ** if the minuend is greater than or equal to the subtrahend. + */ + if (time1 >= time0) + return time1 - time0; + else return -((double) (time0 - time1)); + } + /* + ** time_t is integral and signed. + ** Handle cases where both time1 and time0 have the same sign + ** (meaning that their difference cannot overflow). + */ + if ((time1 < 0) == (time0 < 0)) + return time1 - time0; + /* + ** time1 and time0 have opposite signs. + ** Punt if unsigned long is too narrow. + */ + if (sizeof (unsigned long) < sizeof (time_t)) + return (double) time1 - (double) time0; + /* + ** Stay calm...decent optimizers will eliminate the complexity below. + */ + if (time1 >= 0 /* && time0 < 0 */) + return (unsigned long) time1 + + (unsigned long) (-(time0 + 1)) + 1; + return -(double) ((unsigned long) time0 + + (unsigned long) (-(time1 + 1)) + 1); } diff --git a/libc/tzcode/localtime.c b/libc/tzcode/localtime.c index 19d0fbc..83c1011 100644 --- a/libc/tzcode/localtime.c +++ b/libc/tzcode/localtime.c @@ -5,7 +5,7 @@ #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)localtime.c 8.3"; +static char elsieid[] = "@(#)localtime.c 8.3"; #endif /* !defined NOID */ #endif /* !defined lint */ @@ -19,21 +19,22 @@ static char elsieid[] = "@(#)localtime.c 8.3"; #include "private.h" #include "tzfile.h" #include "fcntl.h" -#include "float.h" /* for FLT_MAX and DBL_MAX */ +#include "float.h" /* for FLT_MAX and DBL_MAX */ +#include "thread_private.h" #include <sys/system_properties.h> #ifndef TZ_ABBR_MAX_LEN -#define TZ_ABBR_MAX_LEN 16 +#define TZ_ABBR_MAX_LEN 16 #endif /* !defined TZ_ABBR_MAX_LEN */ #ifndef TZ_ABBR_CHAR_SET #define TZ_ABBR_CHAR_SET \ - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" #endif /* !defined TZ_ABBR_CHAR_SET */ #ifndef TZ_ABBR_ERR_CHAR -#define TZ_ABBR_ERR_CHAR '_' +#define TZ_ABBR_ERR_CHAR '_' #endif /* !defined TZ_ABBR_ERR_CHAR */ #define INDEXFILE "/system/usr/share/zoneinfo/zoneinfo.idx" @@ -47,10 +48,10 @@ static char elsieid[] = "@(#)localtime.c 8.3"; */ #ifdef O_BINARY -#define OPEN_MODE (O_RDONLY | O_BINARY) +#define OPEN_MODE (O_RDONLY | O_BINARY) #endif /* defined O_BINARY */ #ifndef O_BINARY -#define OPEN_MODE O_RDONLY +#define OPEN_MODE O_RDONLY #endif /* !defined O_BINARY */ #if 0 @@ -59,19 +60,58 @@ static char elsieid[] = "@(#)localtime.c 8.3"; # define XLOG(x) do{}while (0) #endif +/* THREAD-SAFETY SUPPORT GOES HERE */ +static pthread_mutex_t _tzMutex = PTHREAD_MUTEX_INITIALIZER; + +static __inline__ void _tzLock(void) +{ + if (__isthreaded) + pthread_mutex_lock(&_tzMutex); +} + +static __inline__ void _tzUnlock(void) +{ + if (__isthreaded) + pthread_mutex_unlock(&_tzMutex); +} + +/* Complex computations to determine the min/max of time_t depending + * on TYPE_BIT / TYPE_SIGNED / TYPE_INTEGRAL. + * These macros cannot be used in pre-processor directives, so we + * let the C compiler do the work, which makes things a bit funky. + */ +static const time_t TIME_T_MAX = + TYPE_INTEGRAL(time_t) ? + ( TYPE_SIGNED(time_t) ? + ~((time_t)1 << (TYPE_BIT(time_t)-1)) + : + ~(time_t)0 + ) + : /* if time_t is a floating point number */ + ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MAX : (time_t)FLT_MAX ); + +static const time_t TIME_T_MIN = + TYPE_INTEGRAL(time_t) ? + ( TYPE_SIGNED(time_t) ? + ((time_t)1 << (TYPE_BIT(time_t)-1)) + : + 0 + ) + : + ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MIN : (time_t)FLT_MIN ); #ifndef WILDABBR /* ** Someone might make incorrect use of a time zone abbreviation: -** 1. They might reference tzname[0] before calling tzset (explicitly -** or implicitly). -** 2. They might reference tzname[1] before calling tzset (explicitly -** or implicitly). -** 3. They might reference tzname[1] after setting to a time zone -** in which Daylight Saving Time is never observed. -** 4. They might reference tzname[0] after setting to a time zone -** in which Standard Time is never observed. -** 5. They might reference tm.TM_ZONE after calling offtime. +** 1. They might reference tzname[0] before calling tzset (explicitly +** or implicitly). +** 2. They might reference tzname[1] before calling tzset (explicitly +** or implicitly). +** 3. They might reference tzname[1] after setting to a time zone +** in which Daylight Saving Time is never observed. +** 4. They might reference tzname[0] after setting to a time zone +** in which Standard Time is never observed. +** 5. They might reference tm.TM_ZONE after calling offtime. ** What's best to do in the above cases is open to debate; ** for now, we just set things up so that in any of the five cases ** WILDABBR is used. Another possibility: initialize tzname[0] to the @@ -80,12 +120,12 @@ static char elsieid[] = "@(#)localtime.c 8.3"; ** manual page of what this "time zone abbreviation" means (doing this so ** that tzname[0] has the "normal" length of three characters). */ -#define WILDABBR " " +#define WILDABBR " " #endif /* !defined WILDABBR */ -static char wildabbr[] = WILDABBR; +static char wildabbr[] = WILDABBR; -static const char gmt[] = "GMT"; +static const char gmt[] = "GMT"; /* ** The DST rules to use if TZ has no rules and we can't load TZDEFRULES. @@ -98,251 +138,257 @@ static const char gmt[] = "GMT"; #define TZDEFRULESTRING ",M4.1.0,M10.5.0" #endif /* !defined TZDEFDST */ -struct ttinfo { /* time type information */ - long tt_gmtoff; /* UTC offset in seconds */ - int tt_isdst; /* used to set tm_isdst */ - int tt_abbrind; /* abbreviation list index */ - int tt_ttisstd; /* TRUE if transition is std time */ - int tt_ttisgmt; /* TRUE if transition is UTC */ +struct ttinfo { /* time type information */ + long tt_gmtoff; /* UTC offset in seconds */ + int tt_isdst; /* used to set tm_isdst */ + int tt_abbrind; /* abbreviation list index */ + int tt_ttisstd; /* TRUE if transition is std time */ + int tt_ttisgmt; /* TRUE if transition is UTC */ }; -struct lsinfo { /* leap second information */ - time_t ls_trans; /* transition time */ - long ls_corr; /* correction to apply */ +struct lsinfo { /* leap second information */ + time_t ls_trans; /* transition time */ + long ls_corr; /* correction to apply */ }; -#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) +#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) #ifdef TZNAME_MAX -#define MY_TZNAME_MAX TZNAME_MAX +#define MY_TZNAME_MAX TZNAME_MAX #endif /* defined TZNAME_MAX */ #ifndef TZNAME_MAX -#define MY_TZNAME_MAX 255 +#define MY_TZNAME_MAX 255 #endif /* !defined TZNAME_MAX */ +/* XXX: This code should really use time64_t instead of time_t + * but we can't change it without re-generating the index + * file first with the correct data. + */ struct state { - int leapcnt; - int timecnt; - int typecnt; - int charcnt; - int goback; - int goahead; - time_t ats[TZ_MAX_TIMES]; - unsigned char types[TZ_MAX_TIMES]; - struct ttinfo ttis[TZ_MAX_TYPES]; - char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), - (2 * (MY_TZNAME_MAX + 1)))]; - struct lsinfo lsis[TZ_MAX_LEAPS]; + int leapcnt; + int timecnt; + int typecnt; + int charcnt; + int goback; + int goahead; + time_t ats[TZ_MAX_TIMES]; + unsigned char types[TZ_MAX_TIMES]; + struct ttinfo ttis[TZ_MAX_TYPES]; + char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), + (2 * (MY_TZNAME_MAX + 1)))]; + struct lsinfo lsis[TZ_MAX_LEAPS]; }; struct rule { - int r_type; /* type of rule--see below */ - int r_day; /* day number of rule */ - int r_week; /* week number of rule */ - int r_mon; /* month number of rule */ - long r_time; /* transition time of rule */ + int r_type; /* type of rule--see below */ + int r_day; /* day number of rule */ + int r_week; /* week number of rule */ + int r_mon; /* month number of rule */ + long r_time; /* transition time of rule */ }; -#define JULIAN_DAY 0 /* Jn - Julian day */ -#define DAY_OF_YEAR 1 /* n - day of year */ -#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ +#define JULIAN_DAY 0 /* Jn - Julian day */ +#define DAY_OF_YEAR 1 /* n - day of year */ +#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ /* ** Prototypes for static functions. */ -static long detzcode P((const char * codep)); -static time_t detzcode64 P((const char * codep)); -static int differ_by_repeat P((time_t t1, time_t t0)); -static const char * getzname P((const char * strp)); -static const char * getqzname P((const char * strp, const int delim)); -static const char * getnum P((const char * strp, int * nump, int min, - int max)); -static const char * getsecs P((const char * strp, long * secsp)); -static const char * getoffset P((const char * strp, long * offsetp)); -static const char * getrule P((const char * strp, struct rule * rulep)); -static void gmtload P((struct state * sp)); -static struct tm * gmtsub P((const time_t * timep, long offset, - struct tm * tmp)); -static struct tm * localsub P((const time_t * timep, long offset, - struct tm * tmp)); -static int increment_overflow P((int * number, int delta)); -static int leaps_thru_end_of P((int y)); -static int long_increment_overflow P((long * number, int delta)); -static int long_normalize_overflow P((long * tensptr, - int * unitsptr, int base)); -static int normalize_overflow P((int * tensptr, int * unitsptr, - int base)); -static void settzname P((void)); -static time_t time1 P((struct tm * tmp, - struct tm * (*funcp) P((const time_t *, - long, struct tm *)), - long offset)); -static time_t time2 P((struct tm *tmp, - struct tm * (*funcp) P((const time_t *, - long, struct tm*)), - long offset, int * okayp)); -static time_t time2sub P((struct tm *tmp, - struct tm * (*funcp) P((const time_t *, - long, struct tm*)), - long offset, int * okayp, int do_norm_secs)); -static struct tm * timesub P((const time_t * timep, long offset, - const struct state * sp, struct tm * tmp)); -static int tmcomp P((const struct tm * atmp, - const struct tm * btmp)); -static time_t transtime P((time_t janfirst, int year, - const struct rule * rulep, long offset)); -static int tzload P((const char * name, struct state * sp, - int doextend)); -static int tzparse P((const char * name, struct state * sp, - int lastditch)); +/* NOTE: all internal functions assume that _tzLock() was already called */ + +static long detzcode P((const char * codep)); +static time_t detzcode64 P((const char * codep)); +static int differ_by_repeat P((time_t t1, time_t t0)); +static const char * getzname P((const char * strp)); +static const char * getqzname P((const char * strp, const int delim)); +static const char * getnum P((const char * strp, int * nump, int min, + int max)); +static const char * getsecs P((const char * strp, long * secsp)); +static const char * getoffset P((const char * strp, long * offsetp)); +static const char * getrule P((const char * strp, struct rule * rulep)); +static void gmtload P((struct state * sp)); +static struct tm * gmtsub P((const time_t * timep, long offset, + struct tm * tmp)); +static struct tm * localsub P((const time_t * timep, long offset, + struct tm * tmp)); +static int increment_overflow P((int * number, int delta)); +static int leaps_thru_end_of P((int y)); +static int long_increment_overflow P((long * number, int delta)); +static int long_normalize_overflow P((long * tensptr, + int * unitsptr, int base)); +static int normalize_overflow P((int * tensptr, int * unitsptr, + int base)); +static void settzname P((void)); +static time_t time1 P((struct tm * tmp, + struct tm * (*funcp) P((const time_t *, + long, struct tm *)), + long offset)); +static time_t time2 P((struct tm *tmp, + struct tm * (*funcp) P((const time_t *, + long, struct tm*)), + long offset, int * okayp)); +static time_t time2sub P((struct tm *tmp, + struct tm * (*funcp) P((const time_t *, + long, struct tm*)), + long offset, int * okayp, int do_norm_secs)); +static struct tm * timesub P((const time_t * timep, long offset, + const struct state * sp, struct tm * tmp)); +static int tmcomp P((const struct tm * atmp, + const struct tm * btmp)); +static time_t transtime P((time_t janfirst, int year, + const struct rule * rulep, long offset)); +static int tzload P((const char * name, struct state * sp, + int doextend)); +static int tzparse P((const char * name, struct state * sp, + int lastditch)); #ifdef ALL_STATE -static struct state * lclptr; -static struct state * gmtptr; +static struct state * lclptr; +static struct state * gmtptr; #endif /* defined ALL_STATE */ #ifndef ALL_STATE -static struct state lclmem; -static struct state gmtmem; -#define lclptr (&lclmem) -#define gmtptr (&gmtmem) +static struct state lclmem; +static struct state gmtmem; +#define lclptr (&lclmem) +#define gmtptr (&gmtmem) #endif /* State Farm */ #ifndef TZ_STRLEN_MAX #define TZ_STRLEN_MAX 255 #endif /* !defined TZ_STRLEN_MAX */ -static char lcl_TZname[TZ_STRLEN_MAX + 1]; -static int lcl_is_set; -static int gmt_is_set; +static char lcl_TZname[TZ_STRLEN_MAX + 1]; +static int lcl_is_set; +static int gmt_is_set; -char * tzname[2] = { - wildabbr, - wildabbr +char * tzname[2] = { + wildabbr, + wildabbr }; /* ** Section 4.12.3 of X3.159-1989 requires that -** Except for the strftime function, these functions [asctime, -** ctime, gmtime, localtime] return values in one of two static -** objects: a broken-down time structure and an array of char. +** Except for the strftime function, these functions [asctime, +** ctime, gmtime, localtime] return values in one of two static +** objects: a broken-down time structure and an array of char. ** Thanks to Paul Eggert for noting this. */ -static struct tm tm; +static struct tm tmGlobal; #ifdef USG_COMPAT -time_t timezone = 0; -int daylight = 0; +time_t timezone = 0; +int daylight = 0; #endif /* defined USG_COMPAT */ #ifdef ALTZONE -time_t altzone = 0; +time_t altzone = 0; #endif /* defined ALTZONE */ static long detzcode(codep) -const char * const codep; +const char * const codep; { - register long result; - register int i; + register long result; + register int i; - result = (codep[0] & 0x80) ? ~0L : 0; - for (i = 0; i < 4; ++i) - result = (result << 8) | (codep[i] & 0xff); - return result; + result = (codep[0] & 0x80) ? ~0L : 0; + for (i = 0; i < 4; ++i) + result = (result << 8) | (codep[i] & 0xff); + return result; } static time_t detzcode64(codep) -const char * const codep; +const char * const codep; { - register time_t result; - register int i; + register time_t result; + register int i; - result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0; - for (i = 0; i < 8; ++i) - result = result * 256 + (codep[i] & 0xff); - return result; + result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0; + for (i = 0; i < 8; ++i) + result = result * 256 + (codep[i] & 0xff); + return result; } static void settzname P((void)) { - register struct state * const sp = lclptr; - register int i; + register struct state * const sp = lclptr; + register int i; - tzname[0] = wildabbr; - tzname[1] = wildabbr; + tzname[0] = wildabbr; + tzname[1] = wildabbr; #ifdef USG_COMPAT - daylight = 0; - timezone = 0; + daylight = 0; + timezone = 0; #endif /* defined USG_COMPAT */ #ifdef ALTZONE - altzone = 0; + altzone = 0; #endif /* defined ALTZONE */ #ifdef ALL_STATE - if (sp == NULL) { - tzname[0] = tzname[1] = gmt; - return; - } + if (sp == NULL) { + tzname[0] = tzname[1] = gmt; + return; + } #endif /* defined ALL_STATE */ - for (i = 0; i < sp->typecnt; ++i) { - register const struct ttinfo * const ttisp = &sp->ttis[i]; + for (i = 0; i < sp->typecnt; ++i) { + register const struct ttinfo * const ttisp = &sp->ttis[i]; - tzname[ttisp->tt_isdst] = - &sp->chars[ttisp->tt_abbrind]; + tzname[ttisp->tt_isdst] = + &sp->chars[ttisp->tt_abbrind]; #ifdef USG_COMPAT - if (ttisp->tt_isdst) - daylight = 1; - if (i == 0 || !ttisp->tt_isdst) - timezone = -(ttisp->tt_gmtoff); + if (ttisp->tt_isdst) + daylight = 1; + if (i == 0 || !ttisp->tt_isdst) + timezone = -(ttisp->tt_gmtoff); #endif /* defined USG_COMPAT */ #ifdef ALTZONE - if (i == 0 || ttisp->tt_isdst) - altzone = -(ttisp->tt_gmtoff); + if (i == 0 || ttisp->tt_isdst) + altzone = -(ttisp->tt_gmtoff); #endif /* defined ALTZONE */ - } - /* - ** And to get the latest zone names into tzname. . . - */ - for (i = 0; i < sp->timecnt; ++i) { - register const struct ttinfo * const ttisp = - &sp->ttis[ - sp->types[i]]; - - tzname[ttisp->tt_isdst] = - &sp->chars[ttisp->tt_abbrind]; - } - /* - ** Finally, scrub the abbreviations. - ** First, replace bogus characters. - */ - for (i = 0; i < sp->charcnt; ++i) - if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL) - sp->chars[i] = TZ_ABBR_ERR_CHAR; - /* - ** Second, truncate long abbreviations. - */ - for (i = 0; i < sp->typecnt; ++i) { - register const struct ttinfo * const ttisp = &sp->ttis[i]; - register char * cp = &sp->chars[ttisp->tt_abbrind]; - - if (strlen(cp) > TZ_ABBR_MAX_LEN && - strcmp(cp, GRANDPARENTED) != 0) - *(cp + TZ_ABBR_MAX_LEN) = '\0'; - } + } + /* + ** And to get the latest zone names into tzname. . . + */ + for (i = 0; i < sp->timecnt; ++i) { + register const struct ttinfo * const ttisp = + &sp->ttis[ + sp->types[i]]; + + tzname[ttisp->tt_isdst] = + &sp->chars[ttisp->tt_abbrind]; + } + /* + ** Finally, scrub the abbreviations. + ** First, replace bogus characters. + */ + for (i = 0; i < sp->charcnt; ++i) + if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL) + sp->chars[i] = TZ_ABBR_ERR_CHAR; + /* + ** Second, truncate long abbreviations. + */ + for (i = 0; i < sp->typecnt; ++i) { + register const struct ttinfo * const ttisp = &sp->ttis[i]; + register char * cp = &sp->chars[ttisp->tt_abbrind]; + + if (strlen(cp) > TZ_ABBR_MAX_LEN && + strcmp(cp, GRANDPARENTED) != 0) + *(cp + TZ_ABBR_MAX_LEN) = '\0'; + } } static int differ_by_repeat(t1, t0) -const time_t t1; -const time_t t0; +const time_t t1; +const time_t t0; { - if (TYPE_INTEGRAL(time_t) && - TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS) - return 0; + if (TYPE_INTEGRAL(time_t) && + TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS) + return 0; return (t1 - t0) == SECSPERREPEAT; } @@ -352,66 +398,66 @@ static int toint(unsigned char *s) { static int tzload(name, sp, doextend) -register const char * name; -register struct state * const sp; -register const int doextend; +register const char * name; +register struct state * const sp; +register const int doextend; { - register const char * p; - register int i; - register int fid; - register int stored; - register int nread; - union { - struct tzhead tzhead; - char buf[2 * sizeof(struct tzhead) + - 2 * sizeof *sp + - 4 * TZ_MAX_TIMES]; - } u; + register const char * p; + register int i; + register int fid; + register int stored; + register int nread; + union { + struct tzhead tzhead; + char buf[2 * sizeof(struct tzhead) + + 2 * sizeof *sp + + 4 * TZ_MAX_TIMES]; + } u; int toread = sizeof u.buf; if (name == NULL && (name = TZDEFAULT) == NULL) { XLOG(("tzload: null 'name' parameter\n" )); return -1; } - { - register int doaccess; - /* - ** Section 4.9.1 of the C standard says that - ** "FILENAME_MAX expands to an integral constant expression - ** that is the size needed for an array of char large enough - ** to hold the longest file name string that the implementation - ** guarantees can be opened." - */ - char fullname[FILENAME_MAX + 1]; - char *origname = (char*) name; - - if (name[0] == ':') - ++name; - doaccess = name[0] == '/'; - if (!doaccess) { - if ((p = TZDIR) == NULL) { - XLOG(("tzload: null TZDIR macro ?\n" )); - return -1; - } - if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) { - XLOG(( "tzload: path too long: %s/%s\n", p, name )); - return -1; - } - (void) strcpy(fullname, p); - (void) strcat(fullname, "/"); - (void) strcat(fullname, name); - /* - ** Set doaccess if '.' (as in "../") shows up in name. - */ - if (strchr(name, '.') != NULL) - doaccess = TRUE; - name = fullname; - } - if (doaccess && access(name, R_OK) != 0) { - XLOG(( "tzload: could not find '%s'\n", name )); - return -1; - } - if ((fid = open(name, OPEN_MODE)) == -1) { + { + register int doaccess; + /* + ** Section 4.9.1 of the C standard says that + ** "FILENAME_MAX expands to an integral constant expression + ** that is the size needed for an array of char large enough + ** to hold the longest file name string that the implementation + ** guarantees can be opened." + */ + char fullname[FILENAME_MAX + 1]; + char *origname = (char*) name; + + if (name[0] == ':') + ++name; + doaccess = name[0] == '/'; + if (!doaccess) { + if ((p = TZDIR) == NULL) { + XLOG(("tzload: null TZDIR macro ?\n" )); + return -1; + } + if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) { + XLOG(( "tzload: path too long: %s/%s\n", p, name )); + return -1; + } + (void) strcpy(fullname, p); + (void) strcat(fullname, "/"); + (void) strcat(fullname, name); + /* + ** Set doaccess if '.' (as in "../") shows up in name. + */ + if (strchr(name, '.') != NULL) + doaccess = TRUE; + name = fullname; + } + if (doaccess && access(name, R_OK) != 0) { + XLOG(( "tzload: could not find '%s'\n", name )); + return -1; + } + if ((fid = open(name, OPEN_MODE)) == -1) { char buf[READLEN]; char name[NAMELEN + 1]; int fidix = open(INDEXFILE, OPEN_MODE); @@ -453,197 +499,197 @@ register const int doextend; return -1; } } - } - nread = read(fid, u.buf, toread); + } + nread = read(fid, u.buf, toread); if (close(fid) < 0 || nread <= 0) { - XLOG(( "tzload: could not read content of '%s'\n", DATAFILE )); - return -1; + XLOG(( "tzload: could not read content of '%s'\n", DATAFILE )); + return -1; + } + for (stored = 4; stored <= 8; stored *= 2) { + int ttisstdcnt; + int ttisgmtcnt; + + ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt); + ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt); + sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt); + sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt); + sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt); + sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt); + p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt; + if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || + sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || + sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || + sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || + (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) || + (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) + return -1; + if (nread - (p - u.buf) < + sp->timecnt * stored + /* ats */ + sp->timecnt + /* types */ + sp->typecnt * 6 + /* ttinfos */ + sp->charcnt + /* chars */ + sp->leapcnt * (stored + 4) + /* lsinfos */ + ttisstdcnt + /* ttisstds */ + ttisgmtcnt) /* ttisgmts */ + return -1; + for (i = 0; i < sp->timecnt; ++i) { + sp->ats[i] = (stored == 4) ? + detzcode(p) : detzcode64(p); + p += stored; + } + for (i = 0; i < sp->timecnt; ++i) { + sp->types[i] = (unsigned char) *p++; + if (sp->types[i] >= sp->typecnt) + return -1; + } + for (i = 0; i < sp->typecnt; ++i) { + register struct ttinfo * ttisp; + + ttisp = &sp->ttis[i]; + ttisp->tt_gmtoff = detzcode(p); + p += 4; + ttisp->tt_isdst = (unsigned char) *p++; + if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) + return -1; + ttisp->tt_abbrind = (unsigned char) *p++; + if (ttisp->tt_abbrind < 0 || + ttisp->tt_abbrind > sp->charcnt) + return -1; + } + for (i = 0; i < sp->charcnt; ++i) + sp->chars[i] = *p++; + sp->chars[i] = '\0'; /* ensure '\0' at end */ + for (i = 0; i < sp->leapcnt; ++i) { + register struct lsinfo * lsisp; + + lsisp = &sp->lsis[i]; + lsisp->ls_trans = (stored == 4) ? + detzcode(p) : detzcode64(p); + p += stored; + lsisp->ls_corr = detzcode(p); + p += 4; + } + for (i = 0; i < sp->typecnt; ++i) { + register struct ttinfo * ttisp; + + ttisp = &sp->ttis[i]; + if (ttisstdcnt == 0) + ttisp->tt_ttisstd = FALSE; + else { + ttisp->tt_ttisstd = *p++; + if (ttisp->tt_ttisstd != TRUE && + ttisp->tt_ttisstd != FALSE) + return -1; + } + } + for (i = 0; i < sp->typecnt; ++i) { + register struct ttinfo * ttisp; + + ttisp = &sp->ttis[i]; + if (ttisgmtcnt == 0) + ttisp->tt_ttisgmt = FALSE; + else { + ttisp->tt_ttisgmt = *p++; + if (ttisp->tt_ttisgmt != TRUE && + ttisp->tt_ttisgmt != FALSE) + return -1; + } } - for (stored = 4; stored <= 8; stored *= 2) { - int ttisstdcnt; - int ttisgmtcnt; - - ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt); - ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt); - sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt); - sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt); - sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt); - sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt); - p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt; - if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || - sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || - sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || - sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || - (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) || - (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) - return -1; - if (nread - (p - u.buf) < - sp->timecnt * stored + /* ats */ - sp->timecnt + /* types */ - sp->typecnt * 6 + /* ttinfos */ - sp->charcnt + /* chars */ - sp->leapcnt * (stored + 4) + /* lsinfos */ - ttisstdcnt + /* ttisstds */ - ttisgmtcnt) /* ttisgmts */ - return -1; - for (i = 0; i < sp->timecnt; ++i) { - sp->ats[i] = (stored == 4) ? - detzcode(p) : detzcode64(p); - p += stored; - } - for (i = 0; i < sp->timecnt; ++i) { - sp->types[i] = (unsigned char) *p++; - if (sp->types[i] >= sp->typecnt) - return -1; - } - for (i = 0; i < sp->typecnt; ++i) { - register struct ttinfo * ttisp; - - ttisp = &sp->ttis[i]; - ttisp->tt_gmtoff = detzcode(p); - p += 4; - ttisp->tt_isdst = (unsigned char) *p++; - if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) - return -1; - ttisp->tt_abbrind = (unsigned char) *p++; - if (ttisp->tt_abbrind < 0 || - ttisp->tt_abbrind > sp->charcnt) - return -1; - } - for (i = 0; i < sp->charcnt; ++i) - sp->chars[i] = *p++; - sp->chars[i] = '\0'; /* ensure '\0' at end */ - for (i = 0; i < sp->leapcnt; ++i) { - register struct lsinfo * lsisp; - - lsisp = &sp->lsis[i]; - lsisp->ls_trans = (stored == 4) ? - detzcode(p) : detzcode64(p); - p += stored; - lsisp->ls_corr = detzcode(p); - p += 4; - } - for (i = 0; i < sp->typecnt; ++i) { - register struct ttinfo * ttisp; - - ttisp = &sp->ttis[i]; - if (ttisstdcnt == 0) - ttisp->tt_ttisstd = FALSE; - else { - ttisp->tt_ttisstd = *p++; - if (ttisp->tt_ttisstd != TRUE && - ttisp->tt_ttisstd != FALSE) - return -1; - } - } - for (i = 0; i < sp->typecnt; ++i) { - register struct ttinfo * ttisp; - - ttisp = &sp->ttis[i]; - if (ttisgmtcnt == 0) - ttisp->tt_ttisgmt = FALSE; - else { - ttisp->tt_ttisgmt = *p++; - if (ttisp->tt_ttisgmt != TRUE && - ttisp->tt_ttisgmt != FALSE) - return -1; - } - } - /* - ** Out-of-sort ats should mean we're running on a - ** signed time_t system but using a data file with - ** unsigned values (or vice versa). - */ - for (i = 0; i < sp->timecnt - 2; ++i) - if (sp->ats[i] > sp->ats[i + 1]) { - ++i; - if (TYPE_SIGNED(time_t)) { - /* - ** Ignore the end (easy). - */ - sp->timecnt = i; - } else { - /* - ** Ignore the beginning (harder). - */ - register int j; - - for (j = 0; j + i < sp->timecnt; ++j) { - sp->ats[j] = sp->ats[j + i]; - sp->types[j] = sp->types[j + i]; - } - sp->timecnt = j; - } - break; - } - /* - ** If this is an old file, we're done. - */ - if (u.tzhead.tzh_version[0] == '\0') - break; - nread -= p - u.buf; - for (i = 0; i < nread; ++i) - u.buf[i] = p[i]; - /* - ** If this is a narrow integer time_t system, we're done. - */ - if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t)) - break; - } - if (doextend && nread > 2 && - u.buf[0] == '\n' && u.buf[nread - 1] == '\n' && - sp->typecnt + 2 <= TZ_MAX_TYPES) { - struct state ts; - register int result; - - u.buf[nread - 1] = '\0'; - result = tzparse(&u.buf[1], &ts, FALSE); - if (result == 0 && ts.typecnt == 2 && - sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) { - for (i = 0; i < 2; ++i) - ts.ttis[i].tt_abbrind += - sp->charcnt; - for (i = 0; i < ts.charcnt; ++i) - sp->chars[sp->charcnt++] = - ts.chars[i]; - i = 0; - while (i < ts.timecnt && - ts.ats[i] <= - sp->ats[sp->timecnt - 1]) - ++i; - while (i < ts.timecnt && - sp->timecnt < TZ_MAX_TIMES) { - sp->ats[sp->timecnt] = - ts.ats[i]; - sp->types[sp->timecnt] = - sp->typecnt + - ts.types[i]; - ++sp->timecnt; - ++i; - } - sp->ttis[sp->typecnt++] = ts.ttis[0]; - sp->ttis[sp->typecnt++] = ts.ttis[1]; - } - } - i = 2 * YEARSPERREPEAT; - sp->goback = sp->goahead = sp->timecnt > i; - sp->goback &= sp->types[i] == sp->types[0] && - differ_by_repeat(sp->ats[i], sp->ats[0]); - sp->goahead &= - sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] && - differ_by_repeat(sp->ats[sp->timecnt - 1], - sp->ats[sp->timecnt - 1 - i]); + /* + ** Out-of-sort ats should mean we're running on a + ** signed time_t system but using a data file with + ** unsigned values (or vice versa). + */ + for (i = 0; i < sp->timecnt - 2; ++i) + if (sp->ats[i] > sp->ats[i + 1]) { + ++i; + if (TYPE_SIGNED(time_t)) { + /* + ** Ignore the end (easy). + */ + sp->timecnt = i; + } else { + /* + ** Ignore the beginning (harder). + */ + register int j; + + for (j = 0; j + i < sp->timecnt; ++j) { + sp->ats[j] = sp->ats[j + i]; + sp->types[j] = sp->types[j + i]; + } + sp->timecnt = j; + } + break; + } + /* + ** If this is an old file, we're done. + */ + if (u.tzhead.tzh_version[0] == '\0') + break; + nread -= p - u.buf; + for (i = 0; i < nread; ++i) + u.buf[i] = p[i]; + /* + ** If this is a narrow integer time_t system, we're done. + */ + if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t)) + break; + } + if (doextend && nread > 2 && + u.buf[0] == '\n' && u.buf[nread - 1] == '\n' && + sp->typecnt + 2 <= TZ_MAX_TYPES) { + struct state ts; + register int result; + + u.buf[nread - 1] = '\0'; + result = tzparse(&u.buf[1], &ts, FALSE); + if (result == 0 && ts.typecnt == 2 && + sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) { + for (i = 0; i < 2; ++i) + ts.ttis[i].tt_abbrind += + sp->charcnt; + for (i = 0; i < ts.charcnt; ++i) + sp->chars[sp->charcnt++] = + ts.chars[i]; + i = 0; + while (i < ts.timecnt && + ts.ats[i] <= + sp->ats[sp->timecnt - 1]) + ++i; + while (i < ts.timecnt && + sp->timecnt < TZ_MAX_TIMES) { + sp->ats[sp->timecnt] = + ts.ats[i]; + sp->types[sp->timecnt] = + sp->typecnt + + ts.types[i]; + ++sp->timecnt; + ++i; + } + sp->ttis[sp->typecnt++] = ts.ttis[0]; + sp->ttis[sp->typecnt++] = ts.ttis[1]; + } + } + i = 2 * YEARSPERREPEAT; + sp->goback = sp->goahead = sp->timecnt > i; + sp->goback &= sp->types[i] == sp->types[0] && + differ_by_repeat(sp->ats[i], sp->ats[0]); + sp->goahead &= + sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] && + differ_by_repeat(sp->ats[sp->timecnt - 1], + sp->ats[sp->timecnt - 1 - i]); XLOG(( "tzload: load ok !!\n" )); - return 0; + return 0; } -static const int mon_lengths[2][MONSPERYEAR] = { - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +static const int mon_lengths[2][MONSPERYEAR] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; -static const int year_lengths[2] = { - DAYSPERNYEAR, DAYSPERLYEAR +static const int year_lengths[2] = { + DAYSPERNYEAR, DAYSPERLYEAR }; /* @@ -654,14 +700,14 @@ static const int year_lengths[2] = { static const char * getzname(strp) -register const char * strp; +register const char * strp; { - register char c; + register char c; - while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && - c != '+') - ++strp; - return strp; + while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && + c != '+') + ++strp; + return strp; } /* @@ -676,11 +722,11 @@ register const char * strp; static const char * getqzname(register const char *strp, const int delim) { - register int c; + register int c; - while ((c = *strp) != '\0' && c != delim) - ++strp; - return strp; + while ((c = *strp) != '\0' && c != delim) + ++strp; + return strp; } /* @@ -692,27 +738,27 @@ getqzname(register const char *strp, const int delim) static const char * getnum(strp, nump, min, max) -register const char * strp; -int * const nump; -const int min; -const int max; +register const char * strp; +int * const nump; +const int min; +const int max; { - register char c; - register int num; - - if (strp == NULL || !is_digit(c = *strp)) - return NULL; - num = 0; - do { - num = num * 10 + (c - '0'); - if (num > max) - return NULL; /* illegal value */ - c = *++strp; - } while (is_digit(c)); - if (num < min) - return NULL; /* illegal value */ - *nump = num; - return strp; + register char c; + register int num; + + if (strp == NULL || !is_digit(c = *strp)) + return NULL; + num = 0; + do { + num = num * 10 + (c - '0'); + if (num > max) + return NULL; /* illegal value */ + c = *++strp; + } while (is_digit(c)); + if (num < min) + return NULL; /* illegal value */ + *nump = num; + return strp; } /* @@ -725,37 +771,37 @@ const int max; static const char * getsecs(strp, secsp) -register const char * strp; -long * const secsp; +register const char * strp; +long * const secsp; { - int num; - - /* - ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like - ** "M10.4.6/26", which does not conform to Posix, - ** but which specifies the equivalent of - ** ``02:00 on the first Sunday on or after 23 Oct''. - */ - strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); - if (strp == NULL) - return NULL; - *secsp = num * (long) SECSPERHOUR; - if (*strp == ':') { - ++strp; - strp = getnum(strp, &num, 0, MINSPERHOUR - 1); - if (strp == NULL) - return NULL; - *secsp += num * SECSPERMIN; - if (*strp == ':') { - ++strp; - /* `SECSPERMIN' allows for leap seconds. */ - strp = getnum(strp, &num, 0, SECSPERMIN); - if (strp == NULL) - return NULL; - *secsp += num; - } - } - return strp; + int num; + + /* + ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like + ** "M10.4.6/26", which does not conform to Posix, + ** but which specifies the equivalent of + ** ``02:00 on the first Sunday on or after 23 Oct''. + */ + strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); + if (strp == NULL) + return NULL; + *secsp = num * (long) SECSPERHOUR; + if (*strp == ':') { + ++strp; + strp = getnum(strp, &num, 0, MINSPERHOUR - 1); + if (strp == NULL) + return NULL; + *secsp += num * SECSPERMIN; + if (*strp == ':') { + ++strp; + /* `SECSPERMIN' allows for leap seconds. */ + strp = getnum(strp, &num, 0, SECSPERMIN); + if (strp == NULL) + return NULL; + *secsp += num; + } + } + return strp; } /* @@ -767,22 +813,22 @@ long * const secsp; static const char * getoffset(strp, offsetp) -register const char * strp; -long * const offsetp; +register const char * strp; +long * const offsetp; { - register int neg = 0; - - if (*strp == '-') { - neg = 1; - ++strp; - } else if (*strp == '+') - ++strp; - strp = getsecs(strp, offsetp); - if (strp == NULL) - return NULL; /* illegal time */ - if (neg) - *offsetp = -*offsetp; - return strp; + register int neg = 0; + + if (*strp == '-') { + neg = 1; + ++strp; + } else if (*strp == '+') + ++strp; + strp = getsecs(strp, offsetp); + if (strp == NULL) + return NULL; /* illegal time */ + if (neg) + *offsetp = -*offsetp; + return strp; } /* @@ -794,50 +840,50 @@ long * const offsetp; static const char * getrule(strp, rulep) -const char * strp; -register struct rule * const rulep; +const char * strp; +register struct rule * const rulep; { - if (*strp == 'J') { - /* - ** Julian day. - */ - rulep->r_type = JULIAN_DAY; - ++strp; - strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); - } else if (*strp == 'M') { - /* - ** Month, week, day. - */ - rulep->r_type = MONTH_NTH_DAY_OF_WEEK; - ++strp; - strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); - if (strp == NULL) - return NULL; - if (*strp++ != '.') - return NULL; - strp = getnum(strp, &rulep->r_week, 1, 5); - if (strp == NULL) - return NULL; - if (*strp++ != '.') - return NULL; - strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); - } else if (is_digit(*strp)) { - /* - ** Day of year. - */ - rulep->r_type = DAY_OF_YEAR; - strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); - } else return NULL; /* invalid format */ - if (strp == NULL) - return NULL; - if (*strp == '/') { - /* - ** Time specified. - */ - ++strp; - strp = getsecs(strp, &rulep->r_time); - } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ - return strp; + if (*strp == 'J') { + /* + ** Julian day. + */ + rulep->r_type = JULIAN_DAY; + ++strp; + strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); + } else if (*strp == 'M') { + /* + ** Month, week, day. + */ + rulep->r_type = MONTH_NTH_DAY_OF_WEEK; + ++strp; + strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); + if (strp == NULL) + return NULL; + if (*strp++ != '.') + return NULL; + strp = getnum(strp, &rulep->r_week, 1, 5); + if (strp == NULL) + return NULL; + if (*strp++ != '.') + return NULL; + strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); + } else if (is_digit(*strp)) { + /* + ** Day of year. + */ + rulep->r_type = DAY_OF_YEAR; + strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); + } else return NULL; /* invalid format */ + if (strp == NULL) + return NULL; + if (*strp == '/') { + /* + ** Time specified. + */ + ++strp; + strp = getsecs(strp, &rulep->r_time); + } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ + return strp; } /* @@ -848,92 +894,92 @@ register struct rule * const rulep; static time_t transtime(janfirst, year, rulep, offset) -const time_t janfirst; -const int year; -register const struct rule * const rulep; -const long offset; +const time_t janfirst; +const int year; +register const struct rule * const rulep; +const long offset; { - register int leapyear; - register time_t value; - register int i; - int d, m1, yy0, yy1, yy2, dow; - - INITIALIZE(value); - leapyear = isleap(year); - switch (rulep->r_type) { - - case JULIAN_DAY: - /* - ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap - ** years. - ** In non-leap years, or if the day number is 59 or less, just - ** add SECSPERDAY times the day number-1 to the time of - ** January 1, midnight, to get the day. - */ - value = janfirst + (rulep->r_day - 1) * SECSPERDAY; - if (leapyear && rulep->r_day >= 60) - value += SECSPERDAY; - break; - - case DAY_OF_YEAR: - /* - ** n - day of year. - ** Just add SECSPERDAY times the day number to the time of - ** January 1, midnight, to get the day. - */ - value = janfirst + rulep->r_day * SECSPERDAY; - break; - - case MONTH_NTH_DAY_OF_WEEK: - /* - ** Mm.n.d - nth "dth day" of month m. - */ - value = janfirst; - for (i = 0; i < rulep->r_mon - 1; ++i) - value += mon_lengths[leapyear][i] * SECSPERDAY; - - /* - ** Use Zeller's Congruence to get day-of-week of first day of - ** month. - */ - m1 = (rulep->r_mon + 9) % 12 + 1; - yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; - yy1 = yy0 / 100; - yy2 = yy0 % 100; - dow = ((26 * m1 - 2) / 10 + - 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; - if (dow < 0) - dow += DAYSPERWEEK; - - /* - ** "dow" is the day-of-week of the first day of the month. Get - ** the day-of-month (zero-origin) of the first "dow" day of the - ** month. - */ - d = rulep->r_day - dow; - if (d < 0) - d += DAYSPERWEEK; - for (i = 1; i < rulep->r_week; ++i) { - if (d + DAYSPERWEEK >= - mon_lengths[leapyear][rulep->r_mon - 1]) - break; - d += DAYSPERWEEK; - } - - /* - ** "d" is the day-of-month (zero-origin) of the day we want. - */ - value += d * SECSPERDAY; - break; - } - - /* - ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in - ** question. To get the Epoch-relative time of the specified local - ** time on that day, add the transition time and the current offset - ** from UTC. - */ - return value + rulep->r_time + offset; + register int leapyear; + register time_t value; + register int i; + int d, m1, yy0, yy1, yy2, dow; + + INITIALIZE(value); + leapyear = isleap(year); + switch (rulep->r_type) { + + case JULIAN_DAY: + /* + ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap + ** years. + ** In non-leap years, or if the day number is 59 or less, just + ** add SECSPERDAY times the day number-1 to the time of + ** January 1, midnight, to get the day. + */ + value = janfirst + (rulep->r_day - 1) * SECSPERDAY; + if (leapyear && rulep->r_day >= 60) + value += SECSPERDAY; + break; + + case DAY_OF_YEAR: + /* + ** n - day of year. + ** Just add SECSPERDAY times the day number to the time of + ** January 1, midnight, to get the day. + */ + value = janfirst + rulep->r_day * SECSPERDAY; + break; + + case MONTH_NTH_DAY_OF_WEEK: + /* + ** Mm.n.d - nth "dth day" of month m. + */ + value = janfirst; + for (i = 0; i < rulep->r_mon - 1; ++i) + value += mon_lengths[leapyear][i] * SECSPERDAY; + + /* + ** Use Zeller's Congruence to get day-of-week of first day of + ** month. + */ + m1 = (rulep->r_mon + 9) % 12 + 1; + yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; + yy1 = yy0 / 100; + yy2 = yy0 % 100; + dow = ((26 * m1 - 2) / 10 + + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; + if (dow < 0) + dow += DAYSPERWEEK; + + /* + ** "dow" is the day-of-week of the first day of the month. Get + ** the day-of-month (zero-origin) of the first "dow" day of the + ** month. + */ + d = rulep->r_day - dow; + if (d < 0) + d += DAYSPERWEEK; + for (i = 1; i < rulep->r_week; ++i) { + if (d + DAYSPERWEEK >= + mon_lengths[leapyear][rulep->r_mon - 1]) + break; + d += DAYSPERWEEK; + } + + /* + ** "d" is the day-of-month (zero-origin) of the day we want. + */ + value += d * SECSPERDAY; + break; + } + + /* + ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in + ** question. To get the Epoch-relative time of the specified local + ** time on that day, add the transition time and the current offset + ** from UTC. + */ + return value + rulep->r_time + offset; } /* @@ -943,322 +989,323 @@ const long offset; static int tzparse(name, sp, lastditch) -const char * name; -register struct state * const sp; -const int lastditch; +const char * name; +register struct state * const sp; +const int lastditch; { - const char * stdname; - const char * dstname; - size_t stdlen; - size_t dstlen; - long stdoffset; - long dstoffset; - register time_t * atp; - register unsigned char * typep; - register char * cp; - register int load_result; - - INITIALIZE(dstname); - stdname = name; - if (lastditch) { - stdlen = strlen(name); /* length of standard zone name */ - name += stdlen; - if (stdlen >= sizeof sp->chars) - stdlen = (sizeof sp->chars) - 1; - stdoffset = 0; - } else { - if (*name == '<') { - name++; - stdname = name; - name = getqzname(name, '>'); - if (*name != '>') - return (-1); - stdlen = name - stdname; - name++; - } else { - name = getzname(name); - stdlen = name - stdname; - } - if (*name == '\0') - return -1; - name = getoffset(name, &stdoffset); - if (name == NULL) - return -1; - } - load_result = tzload(TZDEFRULES, sp, FALSE); - if (load_result != 0) - sp->leapcnt = 0; /* so, we're off a little */ - sp->timecnt = 0; - if (*name != '\0') { - if (*name == '<') { - dstname = ++name; - name = getqzname(name, '>'); - if (*name != '>') - return -1; - dstlen = name - dstname; - name++; - } else { - dstname = name; - name = getzname(name); - dstlen = name - dstname; /* length of DST zone name */ - } - if (*name != '\0' && *name != ',' && *name != ';') { - name = getoffset(name, &dstoffset); - if (name == NULL) - return -1; - } else dstoffset = stdoffset - SECSPERHOUR; - if (*name == '\0' && load_result != 0) - name = TZDEFRULESTRING; - if (*name == ',' || *name == ';') { - struct rule start; - struct rule end; - register int year; - register time_t janfirst; - time_t starttime; - time_t endtime; - - ++name; - if ((name = getrule(name, &start)) == NULL) - return -1; - if (*name++ != ',') - return -1; - if ((name = getrule(name, &end)) == NULL) - return -1; - if (*name != '\0') - return -1; - sp->typecnt = 2; /* standard time and DST */ - /* - ** Two transitions per year, from EPOCH_YEAR forward. - */ - sp->ttis[0].tt_gmtoff = -dstoffset; - sp->ttis[0].tt_isdst = 1; - sp->ttis[0].tt_abbrind = stdlen + 1; - sp->ttis[1].tt_gmtoff = -stdoffset; - sp->ttis[1].tt_isdst = 0; - sp->ttis[1].tt_abbrind = 0; - atp = sp->ats; - typep = sp->types; - janfirst = 0; - for (year = EPOCH_YEAR; - sp->timecnt + 2 <= TZ_MAX_TIMES; - ++year) { - time_t newfirst; - - starttime = transtime(janfirst, year, &start, - stdoffset); - endtime = transtime(janfirst, year, &end, - dstoffset); - if (starttime > endtime) { - *atp++ = endtime; - *typep++ = 1; /* DST ends */ - *atp++ = starttime; - *typep++ = 0; /* DST begins */ - } else { - *atp++ = starttime; - *typep++ = 0; /* DST begins */ - *atp++ = endtime; - *typep++ = 1; /* DST ends */ - } - sp->timecnt += 2; - newfirst = janfirst; - newfirst += year_lengths[isleap(year)] * - SECSPERDAY; - if (newfirst <= janfirst) - break; - janfirst = newfirst; - } - } else { - register long theirstdoffset; - register long theirdstoffset; - register long theiroffset; - register int isdst; - register int i; - register int j; - - if (*name != '\0') - return -1; - /* - ** Initial values of theirstdoffset and theirdstoffset. - */ - theirstdoffset = 0; - for (i = 0; i < sp->timecnt; ++i) { - j = sp->types[i]; - if (!sp->ttis[j].tt_isdst) { - theirstdoffset = - -sp->ttis[j].tt_gmtoff; - break; - } - } - theirdstoffset = 0; - for (i = 0; i < sp->timecnt; ++i) { - j = sp->types[i]; - if (sp->ttis[j].tt_isdst) { - theirdstoffset = - -sp->ttis[j].tt_gmtoff; - break; - } - } - /* - ** Initially we're assumed to be in standard time. - */ - isdst = FALSE; - theiroffset = theirstdoffset; - /* - ** Now juggle transition times and types - ** tracking offsets as you do. - */ - for (i = 0; i < sp->timecnt; ++i) { - j = sp->types[i]; - sp->types[i] = sp->ttis[j].tt_isdst; - if (sp->ttis[j].tt_ttisgmt) { - /* No adjustment to transition time */ - } else { - /* - ** If summer time is in effect, and the - ** transition time was not specified as - ** standard time, add the summer time - ** offset to the transition time; - ** otherwise, add the standard time - ** offset to the transition time. - */ - /* - ** Transitions from DST to DDST - ** will effectively disappear since - ** POSIX provides for only one DST - ** offset. - */ - if (isdst && !sp->ttis[j].tt_ttisstd) { - sp->ats[i] += dstoffset - - theirdstoffset; - } else { - sp->ats[i] += stdoffset - - theirstdoffset; - } - } - theiroffset = -sp->ttis[j].tt_gmtoff; - if (sp->ttis[j].tt_isdst) - theirdstoffset = theiroffset; - else theirstdoffset = theiroffset; - } - /* - ** Finally, fill in ttis. - ** ttisstd and ttisgmt need not be handled. - */ - sp->ttis[0].tt_gmtoff = -stdoffset; - sp->ttis[0].tt_isdst = FALSE; - sp->ttis[0].tt_abbrind = 0; - sp->ttis[1].tt_gmtoff = -dstoffset; - sp->ttis[1].tt_isdst = TRUE; - sp->ttis[1].tt_abbrind = stdlen + 1; - sp->typecnt = 2; - } - } else { - dstlen = 0; - sp->typecnt = 1; /* only standard time */ - sp->timecnt = 0; - sp->ttis[0].tt_gmtoff = -stdoffset; - sp->ttis[0].tt_isdst = 0; - sp->ttis[0].tt_abbrind = 0; - } - sp->charcnt = stdlen + 1; - if (dstlen != 0) - sp->charcnt += dstlen + 1; - if ((size_t) sp->charcnt > sizeof sp->chars) - return -1; - cp = sp->chars; - (void) strncpy(cp, stdname, stdlen); - cp += stdlen; - *cp++ = '\0'; - if (dstlen != 0) { - (void) strncpy(cp, dstname, dstlen); - *(cp + dstlen) = '\0'; - } - return 0; + const char * stdname; + const char * dstname; + size_t stdlen; + size_t dstlen; + long stdoffset; + long dstoffset; + register time_t * atp; + register unsigned char * typep; + register char * cp; + register int load_result; + + INITIALIZE(dstname); + stdname = name; + if (lastditch) { + stdlen = strlen(name); /* length of standard zone name */ + name += stdlen; + if (stdlen >= sizeof sp->chars) + stdlen = (sizeof sp->chars) - 1; + stdoffset = 0; + } else { + if (*name == '<') { + name++; + stdname = name; + name = getqzname(name, '>'); + if (*name != '>') + return (-1); + stdlen = name - stdname; + name++; + } else { + name = getzname(name); + stdlen = name - stdname; + } + if (*name == '\0') + return -1; + name = getoffset(name, &stdoffset); + if (name == NULL) + return -1; + } + load_result = tzload(TZDEFRULES, sp, FALSE); + if (load_result != 0) + sp->leapcnt = 0; /* so, we're off a little */ + sp->timecnt = 0; + if (*name != '\0') { + if (*name == '<') { + dstname = ++name; + name = getqzname(name, '>'); + if (*name != '>') + return -1; + dstlen = name - dstname; + name++; + } else { + dstname = name; + name = getzname(name); + dstlen = name - dstname; /* length of DST zone name */ + } + if (*name != '\0' && *name != ',' && *name != ';') { + name = getoffset(name, &dstoffset); + if (name == NULL) + return -1; + } else dstoffset = stdoffset - SECSPERHOUR; + if (*name == '\0' && load_result != 0) + name = TZDEFRULESTRING; + if (*name == ',' || *name == ';') { + struct rule start; + struct rule end; + register int year; + register time_t janfirst; + time_t starttime; + time_t endtime; + + ++name; + if ((name = getrule(name, &start)) == NULL) + return -1; + if (*name++ != ',') + return -1; + if ((name = getrule(name, &end)) == NULL) + return -1; + if (*name != '\0') + return -1; + sp->typecnt = 2; /* standard time and DST */ + /* + ** Two transitions per year, from EPOCH_YEAR forward. + */ + sp->ttis[0].tt_gmtoff = -dstoffset; + sp->ttis[0].tt_isdst = 1; + sp->ttis[0].tt_abbrind = stdlen + 1; + sp->ttis[1].tt_gmtoff = -stdoffset; + sp->ttis[1].tt_isdst = 0; + sp->ttis[1].tt_abbrind = 0; + atp = sp->ats; + typep = sp->types; + janfirst = 0; + for (year = EPOCH_YEAR; + sp->timecnt + 2 <= TZ_MAX_TIMES; + ++year) { + time_t newfirst; + + starttime = transtime(janfirst, year, &start, + stdoffset); + endtime = transtime(janfirst, year, &end, + dstoffset); + if (starttime > endtime) { + *atp++ = endtime; + *typep++ = 1; /* DST ends */ + *atp++ = starttime; + *typep++ = 0; /* DST begins */ + } else { + *atp++ = starttime; + *typep++ = 0; /* DST begins */ + *atp++ = endtime; + *typep++ = 1; /* DST ends */ + } + sp->timecnt += 2; + newfirst = janfirst; + newfirst += year_lengths[isleap(year)] * + SECSPERDAY; + if (newfirst <= janfirst) + break; + janfirst = newfirst; + } + } else { + register long theirstdoffset; + register long theirdstoffset; + register long theiroffset; + register int isdst; + register int i; + register int j; + + if (*name != '\0') + return -1; + /* + ** Initial values of theirstdoffset and theirdstoffset. + */ + theirstdoffset = 0; + for (i = 0; i < sp->timecnt; ++i) { + j = sp->types[i]; + if (!sp->ttis[j].tt_isdst) { + theirstdoffset = + -sp->ttis[j].tt_gmtoff; + break; + } + } + theirdstoffset = 0; + for (i = 0; i < sp->timecnt; ++i) { + j = sp->types[i]; + if (sp->ttis[j].tt_isdst) { + theirdstoffset = + -sp->ttis[j].tt_gmtoff; + break; + } + } + /* + ** Initially we're assumed to be in standard time. + */ + isdst = FALSE; + theiroffset = theirstdoffset; + /* + ** Now juggle transition times and types + ** tracking offsets as you do. + */ + for (i = 0; i < sp->timecnt; ++i) { + j = sp->types[i]; + sp->types[i] = sp->ttis[j].tt_isdst; + if (sp->ttis[j].tt_ttisgmt) { + /* No adjustment to transition time */ + } else { + /* + ** If summer time is in effect, and the + ** transition time was not specified as + ** standard time, add the summer time + ** offset to the transition time; + ** otherwise, add the standard time + ** offset to the transition time. + */ + /* + ** Transitions from DST to DDST + ** will effectively disappear since + ** POSIX provides for only one DST + ** offset. + */ + if (isdst && !sp->ttis[j].tt_ttisstd) { + sp->ats[i] += dstoffset - + theirdstoffset; + } else { + sp->ats[i] += stdoffset - + theirstdoffset; + } + } + theiroffset = -sp->ttis[j].tt_gmtoff; + if (sp->ttis[j].tt_isdst) + theirdstoffset = theiroffset; + else theirstdoffset = theiroffset; + } + /* + ** Finally, fill in ttis. + ** ttisstd and ttisgmt need not be handled. + */ + sp->ttis[0].tt_gmtoff = -stdoffset; + sp->ttis[0].tt_isdst = FALSE; + sp->ttis[0].tt_abbrind = 0; + sp->ttis[1].tt_gmtoff = -dstoffset; + sp->ttis[1].tt_isdst = TRUE; + sp->ttis[1].tt_abbrind = stdlen + 1; + sp->typecnt = 2; + } + } else { + dstlen = 0; + sp->typecnt = 1; /* only standard time */ + sp->timecnt = 0; + sp->ttis[0].tt_gmtoff = -stdoffset; + sp->ttis[0].tt_isdst = 0; + sp->ttis[0].tt_abbrind = 0; + } + sp->charcnt = stdlen + 1; + if (dstlen != 0) + sp->charcnt += dstlen + 1; + if ((size_t) sp->charcnt > sizeof sp->chars) + return -1; + cp = sp->chars; + (void) strncpy(cp, stdname, stdlen); + cp += stdlen; + *cp++ = '\0'; + if (dstlen != 0) { + (void) strncpy(cp, dstname, dstlen); + *(cp + dstlen) = '\0'; + } + return 0; } static void gmtload(sp) -struct state * const sp; +struct state * const sp; { - if (tzload(gmt, sp, TRUE) != 0) - (void) tzparse(gmt, sp, TRUE); + if (tzload(gmt, sp, TRUE) != 0) + (void) tzparse(gmt, sp, TRUE); } -#ifndef STD_INSPIRED -/* -** A non-static declaration of tzsetwall in a system header file -** may cause a warning about this upcoming static declaration... -*/ -static -#endif /* !defined STD_INSPIRED */ -void +static void tzsetwall P((void)) { - if (lcl_is_set < 0) - return; - lcl_is_set = -1; + if (lcl_is_set < 0) + return; + lcl_is_set = -1; #ifdef ALL_STATE - if (lclptr == NULL) { - lclptr = (struct state *) malloc(sizeof *lclptr); - if (lclptr == NULL) { - settzname(); /* all we can do */ - return; - } - } + if (lclptr == NULL) { + lclptr = (struct state *) malloc(sizeof *lclptr); + if (lclptr == NULL) { + settzname(); /* all we can do */ + return; + } + } #endif /* defined ALL_STATE */ - if (tzload((char *) NULL, lclptr, TRUE) != 0) - gmtload(lclptr); - settzname(); + if (tzload((char *) NULL, lclptr, TRUE) != 0) + gmtload(lclptr); + settzname(); } -void -tzset P((void)) +static void +tzset_locked P((void)) { - register const char * name = NULL; + register const char * name = NULL; static char buf[PROP_VALUE_MAX]; - name = getenv("TZ"); + name = getenv("TZ"); - // try the "persist.sys.timezone" system property first - if (name == NULL && __system_property_get("persist.sys.timezone", buf) > 0) - name = buf; + // try the "persist.sys.timezone" system property first + if (name == NULL && __system_property_get("persist.sys.timezone", buf) > 0) + name = buf; - if (name == NULL) { - tzsetwall(); - return; - } + if (name == NULL) { + tzsetwall(); + return; + } - if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) - return; - lcl_is_set = strlen(name) < sizeof lcl_TZname; - if (lcl_is_set) - (void) strcpy(lcl_TZname, name); + if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) + return; + lcl_is_set = strlen(name) < sizeof lcl_TZname; + if (lcl_is_set) + (void) strcpy(lcl_TZname, name); #ifdef ALL_STATE - if (lclptr == NULL) { - lclptr = (struct state *) malloc(sizeof *lclptr); - if (lclptr == NULL) { - settzname(); /* all we can do */ - return; - } - } + if (lclptr == NULL) { + lclptr = (struct state *) malloc(sizeof *lclptr); + if (lclptr == NULL) { + settzname(); /* all we can do */ + return; + } + } #endif /* defined ALL_STATE */ - if (*name == '\0') { - /* - ** User wants it fast rather than right. - */ - lclptr->leapcnt = 0; /* so, we're off a little */ - lclptr->timecnt = 0; - lclptr->typecnt = 0; - lclptr->ttis[0].tt_isdst = 0; - lclptr->ttis[0].tt_gmtoff = 0; - lclptr->ttis[0].tt_abbrind = 0; - (void) strcpy(lclptr->chars, gmt); - } else if (tzload(name, lclptr, TRUE) != 0) - if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) - (void) gmtload(lclptr); - settzname(); + if (*name == '\0') { + /* + ** User wants it fast rather than right. + */ + lclptr->leapcnt = 0; /* so, we're off a little */ + lclptr->timecnt = 0; + lclptr->typecnt = 0; + lclptr->ttis[0].tt_isdst = 0; + lclptr->ttis[0].tt_gmtoff = 0; + lclptr->ttis[0].tt_abbrind = 0; + (void) strcpy(lclptr->chars, gmt); + } else if (tzload(name, lclptr, TRUE) != 0) + if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) + (void) gmtload(lclptr); + settzname(); +} + +void +tzset P((void)) +{ + _tzLock(); + tzset_locked(); + _tzUnlock(); } /* @@ -1273,102 +1320,101 @@ tzset P((void)) /*ARGSUSED*/ static struct tm * localsub(timep, offset, tmp) -const time_t * const timep; -const long offset; -struct tm * const tmp; +const time_t * const timep; +const long offset; +struct tm * const tmp; { - register struct state * sp; - register const struct ttinfo * ttisp; - register int i; - register struct tm * result; - const time_t t = *timep; + register struct state * sp; + register const struct ttinfo * ttisp; + register int i; + register struct tm * result; + const time_t t = *timep; - sp = lclptr; + sp = lclptr; #ifdef ALL_STATE - if (sp == NULL) - return gmtsub(timep, offset, tmp); + if (sp == NULL) + return gmtsub(timep, offset, tmp); #endif /* defined ALL_STATE */ - if ((sp->goback && t < sp->ats[0]) || - (sp->goahead && t > sp->ats[sp->timecnt - 1])) { - time_t newt = t; - register time_t seconds; - register time_t tcycles; - register int_fast64_t icycles; - - if (t < sp->ats[0]) - seconds = sp->ats[0] - t; - else seconds = t - sp->ats[sp->timecnt - 1]; - --seconds; - tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR; - ++tcycles; - icycles = tcycles; - if (tcycles - icycles >= 1 || icycles - tcycles >= 1) - return NULL; - seconds = icycles; - seconds *= YEARSPERREPEAT; - seconds *= AVGSECSPERYEAR; - if (t < sp->ats[0]) - newt += seconds; - else newt -= seconds; - if (newt < sp->ats[0] || - newt > sp->ats[sp->timecnt - 1]) - return NULL; /* "cannot happen" */ - result = localsub(&newt, offset, tmp); - if (result == tmp) { - register time_t newy; - - newy = tmp->tm_year; - if (t < sp->ats[0]) - newy -= icycles * YEARSPERREPEAT; - else newy += icycles * YEARSPERREPEAT; - tmp->tm_year = newy; - if (tmp->tm_year != newy) - return NULL; - } - return result; - } - if (sp->timecnt == 0 || t < sp->ats[0]) { - i = 0; - while (sp->ttis[i].tt_isdst) - if (++i >= sp->typecnt) { - i = 0; - break; - } - } else { - register int lo = 1; - register int hi = sp->timecnt; - - while (lo < hi) { - register int mid = (lo + hi) >> 1; - - if (t < sp->ats[mid]) - hi = mid; - else lo = mid + 1; - } - i = (int) sp->types[lo - 1]; - } - ttisp = &sp->ttis[i]; - /* - ** To get (wrong) behavior that's compatible with System V Release 2.0 - ** you'd replace the statement below with - ** t += ttisp->tt_gmtoff; - ** timesub(&t, 0L, sp, tmp); - */ - result = timesub(&t, ttisp->tt_gmtoff, sp, tmp); - tmp->tm_isdst = ttisp->tt_isdst; - tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; + if ((sp->goback && t < sp->ats[0]) || + (sp->goahead && t > sp->ats[sp->timecnt - 1])) { + time_t newt = t; + register time_t seconds; + register time_t tcycles; + register int_fast64_t icycles; + + if (t < sp->ats[0]) + seconds = sp->ats[0] - t; + else seconds = t - sp->ats[sp->timecnt - 1]; + --seconds; + tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR; + ++tcycles; + icycles = tcycles; + if (tcycles - icycles >= 1 || icycles - tcycles >= 1) + return NULL; + seconds = icycles; + seconds *= YEARSPERREPEAT; + seconds *= AVGSECSPERYEAR; + if (t < sp->ats[0]) + newt += seconds; + else newt -= seconds; + if (newt < sp->ats[0] || + newt > sp->ats[sp->timecnt - 1]) + return NULL; /* "cannot happen" */ + result = localsub(&newt, offset, tmp); + if (result == tmp) { + register time_t newy; + + newy = tmp->tm_year; + if (t < sp->ats[0]) + newy -= icycles * YEARSPERREPEAT; + else newy += icycles * YEARSPERREPEAT; + tmp->tm_year = newy; + if (tmp->tm_year != newy) + return NULL; + } + return result; + } + if (sp->timecnt == 0 || t < sp->ats[0]) { + i = 0; + while (sp->ttis[i].tt_isdst) + if (++i >= sp->typecnt) { + i = 0; + break; + } + } else { + register int lo = 1; + register int hi = sp->timecnt; + + while (lo < hi) { + register int mid = (lo + hi) >> 1; + + if (t < sp->ats[mid]) + hi = mid; + else lo = mid + 1; + } + i = (int) sp->types[lo - 1]; + } + ttisp = &sp->ttis[i]; + /* + ** To get (wrong) behavior that's compatible with System V Release 2.0 + ** you'd replace the statement below with + ** t += ttisp->tt_gmtoff; + ** timesub(&t, 0L, sp, tmp); + */ + result = timesub(&t, ttisp->tt_gmtoff, sp, tmp); + tmp->tm_isdst = ttisp->tt_isdst; + tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; #ifdef TM_ZONE - tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; + tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; #endif /* defined TM_ZONE */ - return result; + return result; } struct tm * localtime(timep) -const time_t * const timep; +const time_t * const timep; { - tzset(); - return localsub(timep, 0L, &tm); + return localtime_r(timep, &tmGlobal); } /* @@ -1377,11 +1423,17 @@ const time_t * const timep; struct tm * localtime_r(timep, tmp) -const time_t * const timep; -struct tm * tmp; +const time_t * const timep; +struct tm * tmp; { - tzset(); - return localsub(timep, 0L, tmp); + struct tm* result; + + _tzLock(); + tzset_locked(); + result = localsub(timep, 0L, tmp); + _tzUnlock(); + + return result; } /* @@ -1390,48 +1442,48 @@ struct tm * tmp; static struct tm * gmtsub(timep, offset, tmp) -const time_t * const timep; -const long offset; -struct tm * const tmp; +const time_t * const timep; +const long offset; +struct tm * const tmp; { - register struct tm * result; + register struct tm * result; - if (!gmt_is_set) { - gmt_is_set = TRUE; + if (!gmt_is_set) { + gmt_is_set = TRUE; #ifdef ALL_STATE - gmtptr = (struct state *) malloc(sizeof *gmtptr); - if (gmtptr != NULL) + gmtptr = (struct state *) malloc(sizeof *gmtptr); + if (gmtptr != NULL) #endif /* defined ALL_STATE */ - gmtload(gmtptr); - } - result = timesub(timep, offset, gmtptr, tmp); + gmtload(gmtptr); + } + result = timesub(timep, offset, gmtptr, tmp); #ifdef TM_ZONE - /* - ** Could get fancy here and deliver something such as - ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero, - ** but this is no time for a treasure hunt. - */ - if (offset != 0) - tmp->TM_ZONE = wildabbr; - else { + /* + ** Could get fancy here and deliver something such as + ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero, + ** but this is no time for a treasure hunt. + */ + if (offset != 0) + tmp->TM_ZONE = wildabbr; + else { #ifdef ALL_STATE - if (gmtptr == NULL) - tmp->TM_ZONE = gmt; - else tmp->TM_ZONE = gmtptr->chars; + if (gmtptr == NULL) + tmp->TM_ZONE = gmt; + else tmp->TM_ZONE = gmtptr->chars; #endif /* defined ALL_STATE */ #ifndef ALL_STATE - tmp->TM_ZONE = gmtptr->chars; + tmp->TM_ZONE = gmtptr->chars; #endif /* State Farm */ - } + } #endif /* defined TM_ZONE */ - return result; + return result; } struct tm * gmtime(timep) -const time_t * const timep; +const time_t * const timep; { - return gmtsub(timep, 0L, &tm); + return gmtime_r(timep, &tmGlobal); } /* @@ -1440,20 +1492,26 @@ const time_t * const timep; struct tm * gmtime_r(timep, tmp) -const time_t * const timep; -struct tm * tmp; +const time_t * const timep; +struct tm * tmp; { - return gmtsub(timep, 0L, tmp); + struct tm* result; + + _tzLock(); + result = gmtsub(timep, 0L, tmp); + _tzUnlock(); + + return result; } #ifdef STD_INSPIRED struct tm * offtime(timep, offset) -const time_t * const timep; -const long offset; +const time_t * const timep; +const long offset; { - return gmtsub(timep, offset, &tm); + return gmtsub(timep, offset, &tmGlobal); } #endif /* defined STD_INSPIRED */ @@ -1465,180 +1523,180 @@ const long offset; static int leaps_thru_end_of(y) -register const int y; +register const int y; { - return (y >= 0) ? (y / 4 - y / 100 + y / 400) : - -(leaps_thru_end_of(-(y + 1)) + 1); + return (y >= 0) ? (y / 4 - y / 100 + y / 400) : + -(leaps_thru_end_of(-(y + 1)) + 1); } static struct tm * timesub(timep, offset, sp, tmp) -const time_t * const timep; -const long offset; -register const struct state * const sp; -register struct tm * const tmp; +const time_t * const timep; +const long offset; +register const struct state * const sp; +register struct tm * const tmp; { - register const struct lsinfo * lp; - register time_t tdays; - register int idays; /* unsigned would be so 2003 */ - register long rem; - int y; - register const int * ip; - register long corr; - register int hit; - register int i; - - corr = 0; - hit = 0; + register const struct lsinfo * lp; + register time_t tdays; + register int idays; /* unsigned would be so 2003 */ + register long rem; + int y; + register const int * ip; + register long corr; + register int hit; + register int i; + + corr = 0; + hit = 0; #ifdef ALL_STATE - i = (sp == NULL) ? 0 : sp->leapcnt; + i = (sp == NULL) ? 0 : sp->leapcnt; #endif /* defined ALL_STATE */ #ifndef ALL_STATE - i = sp->leapcnt; + i = sp->leapcnt; #endif /* State Farm */ - while (--i >= 0) { - lp = &sp->lsis[i]; - if (*timep >= lp->ls_trans) { - if (*timep == lp->ls_trans) { - hit = ((i == 0 && lp->ls_corr > 0) || - lp->ls_corr > sp->lsis[i - 1].ls_corr); - if (hit) - while (i > 0 && - sp->lsis[i].ls_trans == - sp->lsis[i - 1].ls_trans + 1 && - sp->lsis[i].ls_corr == - sp->lsis[i - 1].ls_corr + 1) { - ++hit; - --i; - } - } - corr = lp->ls_corr; - break; - } - } - y = EPOCH_YEAR; - tdays = *timep / SECSPERDAY; - rem = *timep - tdays * SECSPERDAY; - while (tdays < 0 || tdays >= year_lengths[isleap(y)]) { - int newy; - register time_t tdelta; - register int idelta; - register int leapdays; - - tdelta = tdays / DAYSPERLYEAR; - idelta = tdelta; - if (tdelta - idelta >= 1 || idelta - tdelta >= 1) - return NULL; - if (idelta == 0) - idelta = (tdays < 0) ? -1 : 1; - newy = y; - if (increment_overflow(&newy, idelta)) - return NULL; - leapdays = leaps_thru_end_of(newy - 1) - - leaps_thru_end_of(y - 1); - tdays -= ((time_t) newy - y) * DAYSPERNYEAR; - tdays -= leapdays; - y = newy; - } - { - register long seconds; - - seconds = tdays * SECSPERDAY + 0.5; - tdays = seconds / SECSPERDAY; - rem += seconds - tdays * SECSPERDAY; - } - /* - ** Given the range, we can now fearlessly cast... - */ - idays = tdays; - rem += offset - corr; - while (rem < 0) { - rem += SECSPERDAY; - --idays; - } - while (rem >= SECSPERDAY) { - rem -= SECSPERDAY; - ++idays; - } - while (idays < 0) { - if (increment_overflow(&y, -1)) - return NULL; - idays += year_lengths[isleap(y)]; - } - while (idays >= year_lengths[isleap(y)]) { - idays -= year_lengths[isleap(y)]; - if (increment_overflow(&y, 1)) - return NULL; - } - tmp->tm_year = y; - if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE)) - return NULL; - tmp->tm_yday = idays; - /* - ** The "extra" mods below avoid overflow problems. - */ - tmp->tm_wday = EPOCH_WDAY + - ((y - EPOCH_YEAR) % DAYSPERWEEK) * - (DAYSPERNYEAR % DAYSPERWEEK) + - leaps_thru_end_of(y - 1) - - leaps_thru_end_of(EPOCH_YEAR - 1) + - idays; - tmp->tm_wday %= DAYSPERWEEK; - if (tmp->tm_wday < 0) - tmp->tm_wday += DAYSPERWEEK; - tmp->tm_hour = (int) (rem / SECSPERHOUR); - rem %= SECSPERHOUR; - tmp->tm_min = (int) (rem / SECSPERMIN); - /* - ** A positive leap second requires a special - ** representation. This uses "... ??:59:60" et seq. - */ - tmp->tm_sec = (int) (rem % SECSPERMIN) + hit; - ip = mon_lengths[isleap(y)]; - for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon)) - idays -= ip[tmp->tm_mon]; - tmp->tm_mday = (int) (idays + 1); - tmp->tm_isdst = 0; + while (--i >= 0) { + lp = &sp->lsis[i]; + if (*timep >= lp->ls_trans) { + if (*timep == lp->ls_trans) { + hit = ((i == 0 && lp->ls_corr > 0) || + lp->ls_corr > sp->lsis[i - 1].ls_corr); + if (hit) + while (i > 0 && + sp->lsis[i].ls_trans == + sp->lsis[i - 1].ls_trans + 1 && + sp->lsis[i].ls_corr == + sp->lsis[i - 1].ls_corr + 1) { + ++hit; + --i; + } + } + corr = lp->ls_corr; + break; + } + } + y = EPOCH_YEAR; + tdays = *timep / SECSPERDAY; + rem = *timep - tdays * SECSPERDAY; + while (tdays < 0 || tdays >= year_lengths[isleap(y)]) { + int newy; + register time_t tdelta; + register int idelta; + register int leapdays; + + tdelta = tdays / DAYSPERLYEAR; + idelta = tdelta; + if (tdelta - idelta >= 1 || idelta - tdelta >= 1) + return NULL; + if (idelta == 0) + idelta = (tdays < 0) ? -1 : 1; + newy = y; + if (increment_overflow(&newy, idelta)) + return NULL; + leapdays = leaps_thru_end_of(newy - 1) - + leaps_thru_end_of(y - 1); + tdays -= ((time_t) newy - y) * DAYSPERNYEAR; + tdays -= leapdays; + y = newy; + } + { + register long seconds; + + seconds = tdays * SECSPERDAY + 0.5; + tdays = seconds / SECSPERDAY; + rem += seconds - tdays * SECSPERDAY; + } + /* + ** Given the range, we can now fearlessly cast... + */ + idays = tdays; + rem += offset - corr; + while (rem < 0) { + rem += SECSPERDAY; + --idays; + } + while (rem >= SECSPERDAY) { + rem -= SECSPERDAY; + ++idays; + } + while (idays < 0) { + if (increment_overflow(&y, -1)) + return NULL; + idays += year_lengths[isleap(y)]; + } + while (idays >= year_lengths[isleap(y)]) { + idays -= year_lengths[isleap(y)]; + if (increment_overflow(&y, 1)) + return NULL; + } + tmp->tm_year = y; + if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE)) + return NULL; + tmp->tm_yday = idays; + /* + ** The "extra" mods below avoid overflow problems. + */ + tmp->tm_wday = EPOCH_WDAY + + ((y - EPOCH_YEAR) % DAYSPERWEEK) * + (DAYSPERNYEAR % DAYSPERWEEK) + + leaps_thru_end_of(y - 1) - + leaps_thru_end_of(EPOCH_YEAR - 1) + + idays; + tmp->tm_wday %= DAYSPERWEEK; + if (tmp->tm_wday < 0) + tmp->tm_wday += DAYSPERWEEK; + tmp->tm_hour = (int) (rem / SECSPERHOUR); + rem %= SECSPERHOUR; + tmp->tm_min = (int) (rem / SECSPERMIN); + /* + ** A positive leap second requires a special + ** representation. This uses "... ??:59:60" et seq. + */ + tmp->tm_sec = (int) (rem % SECSPERMIN) + hit; + ip = mon_lengths[isleap(y)]; + for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon)) + idays -= ip[tmp->tm_mon]; + tmp->tm_mday = (int) (idays + 1); + tmp->tm_isdst = 0; #ifdef TM_GMTOFF - tmp->TM_GMTOFF = offset; + tmp->TM_GMTOFF = offset; #endif /* defined TM_GMTOFF */ - return tmp; + return tmp; } char * ctime(timep) -const time_t * const timep; +const time_t * const timep; { /* ** Section 4.12.3.2 of X3.159-1989 requires that -** The ctime function converts the calendar time pointed to by timer -** to local time in the form of a string. It is equivalent to -** asctime(localtime(timer)) +** The ctime function converts the calendar time pointed to by timer +** to local time in the form of a string. It is equivalent to +** asctime(localtime(timer)) */ - return asctime(localtime(timep)); + return asctime(localtime(timep)); } char * ctime_r(timep, buf) -const time_t * const timep; -char * buf; +const time_t * const timep; +char * buf; { - struct tm mytm; + struct tm mytm; - return asctime_r(localtime_r(timep, &mytm), buf); + return asctime_r(localtime_r(timep, &mytm), buf); } /* ** Adapted from code provided by Robert Elz, who writes: -** The "best" way to do mktime I think is based on an idea of Bob -** Kridle's (so its said...) from a long time ago. -** It does a binary search of the time_t space. Since time_t's are -** just 32 bits, its a max of 32 iterations (even at 64 bits it -** would still be very reasonable). +** The "best" way to do mktime I think is based on an idea of Bob +** Kridle's (so its said...) from a long time ago. +** It does a binary search of the time_t space. Since time_t's are +** just 32 bits, its a max of 32 iterations (even at 64 bits it +** would still be very reasonable). */ #ifndef WRONG -#define WRONG (-1) +#define WRONG (-1) #endif /* !defined WRONG */ /* @@ -1647,56 +1705,66 @@ char * buf; static int increment_overflow(number, delta) -int * number; -int delta; +int * number; +int delta; { - int number0; + unsigned number0 = (unsigned)*number; + unsigned number1 = (unsigned)(number0 + delta); + + *number = (int)number1; - number0 = *number; - *number += delta; - return (*number < number0) != (delta < 0); + if (delta >= 0) { + return ((int)number1 < (int)number0); + } else { + return ((int)number1 > (int)number0); + } } static int long_increment_overflow(number, delta) -long * number; -int delta; +long * number; +int delta; { - long number0; + unsigned long number0 = (unsigned long)*number; + unsigned long number1 = (unsigned long)(number0 + delta); + + *number = (long)number1; - number0 = *number; - *number += delta; - return (*number < number0) != (delta < 0); + if (delta >= 0) { + return ((long)number1 < (long)number0); + } else { + return ((long)number1 > (long)number0); + } } static int normalize_overflow(tensptr, unitsptr, base) -int * const tensptr; -int * const unitsptr; -const int base; +int * const tensptr; +int * const unitsptr; +const int base; { - register int tensdelta; + register int tensdelta; - tensdelta = (*unitsptr >= 0) ? - (*unitsptr / base) : - (-1 - (-1 - *unitsptr) / base); - *unitsptr -= tensdelta * base; - return increment_overflow(tensptr, tensdelta); + tensdelta = (*unitsptr >= 0) ? + (*unitsptr / base) : + (-1 - (-1 - *unitsptr) / base); + *unitsptr -= tensdelta * base; + return increment_overflow(tensptr, tensdelta); } static int long_normalize_overflow(tensptr, unitsptr, base) -long * const tensptr; -int * const unitsptr; -const int base; +long * const tensptr; +int * const unitsptr; +const int base; { - register int tensdelta; + register int tensdelta; - tensdelta = (*unitsptr >= 0) ? - (*unitsptr / base) : - (-1 - (-1 - *unitsptr) / base); - *unitsptr -= tensdelta * base; - return long_increment_overflow(tensptr, tensdelta); + tensdelta = (*unitsptr >= 0) ? + (*unitsptr / base) : + (-1 - (-1 - *unitsptr) / base); + *unitsptr -= tensdelta * base; + return long_increment_overflow(tensptr, tensdelta); } static int @@ -1704,333 +1772,349 @@ tmcomp(atmp, btmp) register const struct tm * const atmp; register const struct tm * const btmp; { - register int result; - - if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && - (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && - (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && - (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && - (result = (atmp->tm_min - btmp->tm_min)) == 0) - result = atmp->tm_sec - btmp->tm_sec; - return result; + register int result; + + if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && + (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && + (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && + (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && + (result = (atmp->tm_min - btmp->tm_min)) == 0) + result = atmp->tm_sec - btmp->tm_sec; + return result; } static time_t time2sub(tmp, funcp, offset, okayp, do_norm_secs) -struct tm * const tmp; -struct tm * (* const funcp) P((const time_t*, long, struct tm*)); -const long offset; -int * const okayp; -const int do_norm_secs; +struct tm * const tmp; +struct tm * (* const funcp) P((const time_t*, long, struct tm*)); +const long offset; +int * const okayp; +const int do_norm_secs; { - register const struct state * sp; - register int dir; - register int i, j; - register int saved_seconds; - register long li; - register time_t lo; - register time_t hi; - long y; - time_t newt; - time_t t; - struct tm yourtm, mytm; - - *okayp = FALSE; - yourtm = *tmp; - if (do_norm_secs) { - if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, - SECSPERMIN)) - return WRONG; - } - if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) - return WRONG; - if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) - return WRONG; - y = yourtm.tm_year; - if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR)) - return WRONG; - /* - ** Turn y into an actual year number for now. - ** It is converted back to an offset from TM_YEAR_BASE later. - */ - if (long_increment_overflow(&y, TM_YEAR_BASE)) - return WRONG; - while (yourtm.tm_mday <= 0) { - if (long_increment_overflow(&y, -1)) - return WRONG; - li = y + (1 < yourtm.tm_mon); - yourtm.tm_mday += year_lengths[isleap(li)]; - } - while (yourtm.tm_mday > DAYSPERLYEAR) { - li = y + (1 < yourtm.tm_mon); - yourtm.tm_mday -= year_lengths[isleap(li)]; - if (long_increment_overflow(&y, 1)) - return WRONG; - } - for ( ; ; ) { - i = mon_lengths[isleap(y)][yourtm.tm_mon]; - if (yourtm.tm_mday <= i) - break; - yourtm.tm_mday -= i; - if (++yourtm.tm_mon >= MONSPERYEAR) { - yourtm.tm_mon = 0; - if (long_increment_overflow(&y, 1)) - return WRONG; - } - } - if (long_increment_overflow(&y, -TM_YEAR_BASE)) - return WRONG; - yourtm.tm_year = y; - if (yourtm.tm_year != y) - return WRONG; - if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) - saved_seconds = 0; - else if (y + TM_YEAR_BASE < EPOCH_YEAR) { - /* - ** We can't set tm_sec to 0, because that might push the - ** time below the minimum representable time. - ** Set tm_sec to 59 instead. - ** This assumes that the minimum representable time is - ** not in the same minute that a leap second was deleted from, - ** which is a safer assumption than using 58 would be. - */ - if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) - return WRONG; - saved_seconds = yourtm.tm_sec; - yourtm.tm_sec = SECSPERMIN - 1; - } else { - saved_seconds = yourtm.tm_sec; - yourtm.tm_sec = 0; - } - /* - ** Do a binary search (this works whatever time_t's type is). - */ - if (!TYPE_SIGNED(time_t)) { - lo = 0; - hi = lo - 1; - } else if (!TYPE_INTEGRAL(time_t)) { - if (sizeof(time_t) > sizeof(float)) - hi = (time_t) DBL_MAX; - else hi = (time_t) FLT_MAX; - lo = -hi; - } else { - lo = 1; - for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i) - lo *= 2; - hi = -(lo + 1); - } - for ( ; ; ) { - t = lo / 2 + hi / 2; - if (t < lo) - t = lo; - else if (t > hi) - t = hi; - if ((*funcp)(&t, offset, &mytm) == NULL) { - /* - ** Assume that t is too extreme to be represented in - ** a struct tm; arrange things so that it is less - ** extreme on the next pass. - */ - dir = (t > 0) ? 1 : -1; - } else dir = tmcomp(&mytm, &yourtm); - if (dir != 0) { - if (t == lo) { - ++t; - if (t <= lo) - return WRONG; - ++lo; - } else if (t == hi) { - --t; - if (t >= hi) - return WRONG; - --hi; - } - if (lo > hi) - return WRONG; - if (dir > 0) - hi = t; - else lo = t; - continue; - } - if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) - break; - /* - ** Right time, wrong type. - ** Hunt for right time, right type. - ** It's okay to guess wrong since the guess - ** gets checked. - */ - /* - ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. - */ - sp = (const struct state *) - (((void *) funcp == (void *) localsub) ? - lclptr : gmtptr); + register const struct state * sp; + register int dir; + register int i, j; + register int saved_seconds; + register long li; + register time_t lo; + register time_t hi; + long y; + time_t newt; + time_t t; + struct tm yourtm, mytm; + + *okayp = FALSE; + yourtm = *tmp; + if (do_norm_secs) { + if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, + SECSPERMIN)) + return WRONG; + } + if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) + return WRONG; + if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) + return WRONG; + y = yourtm.tm_year; + if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR)) + return WRONG; + /* + ** Turn y into an actual year number for now. + ** It is converted back to an offset from TM_YEAR_BASE later. + */ + if (long_increment_overflow(&y, TM_YEAR_BASE)) + return WRONG; + while (yourtm.tm_mday <= 0) { + if (long_increment_overflow(&y, -1)) + return WRONG; + li = y + (1 < yourtm.tm_mon); + yourtm.tm_mday += year_lengths[isleap(li)]; + } + while (yourtm.tm_mday > DAYSPERLYEAR) { + li = y + (1 < yourtm.tm_mon); + yourtm.tm_mday -= year_lengths[isleap(li)]; + if (long_increment_overflow(&y, 1)) + return WRONG; + } + for ( ; ; ) { + i = mon_lengths[isleap(y)][yourtm.tm_mon]; + if (yourtm.tm_mday <= i) + break; + yourtm.tm_mday -= i; + if (++yourtm.tm_mon >= MONSPERYEAR) { + yourtm.tm_mon = 0; + if (long_increment_overflow(&y, 1)) + return WRONG; + } + } + if (long_increment_overflow(&y, -TM_YEAR_BASE)) + return WRONG; + yourtm.tm_year = y; + if (yourtm.tm_year != y) + return WRONG; + if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) + saved_seconds = 0; + else if (y + TM_YEAR_BASE < EPOCH_YEAR) { + /* + ** We can't set tm_sec to 0, because that might push the + ** time below the minimum representable time. + ** Set tm_sec to 59 instead. + ** This assumes that the minimum representable time is + ** not in the same minute that a leap second was deleted from, + ** which is a safer assumption than using 58 would be. + */ + if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) + return WRONG; + saved_seconds = yourtm.tm_sec; + yourtm.tm_sec = SECSPERMIN - 1; + } else { + saved_seconds = yourtm.tm_sec; + yourtm.tm_sec = 0; + } + /* + ** Do a binary search (this works whatever time_t's type is). + */ + if (!TYPE_SIGNED(time_t)) { + lo = 0; + hi = lo - 1; + } else if (!TYPE_INTEGRAL(time_t)) { + if (sizeof(time_t) > sizeof(float)) + hi = (time_t) DBL_MAX; + else hi = (time_t) FLT_MAX; + lo = -hi; + } else { + lo = 1; + for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i) + lo *= 2; + hi = -(lo + 1); + } + for ( ; ; ) { + t = lo / 2 + hi / 2; + if (t < lo) + t = lo; + else if (t > hi) + t = hi; + if ((*funcp)(&t, offset, &mytm) == NULL) { + /* + ** Assume that t is too extreme to be represented in + ** a struct tm; arrange things so that it is less + ** extreme on the next pass. + */ + dir = (t > 0) ? 1 : -1; + } else dir = tmcomp(&mytm, &yourtm); + if (dir != 0) { + if (t == lo) { + if (t == TIME_T_MAX) + return WRONG; + ++t; + ++lo; + } else if (t == hi) { + if (t == TIME_T_MIN) + return WRONG; + --t; + --hi; + } + if (lo > hi) + return WRONG; + if (dir > 0) + hi = t; + else lo = t; + continue; + } + if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) + break; + /* + ** Right time, wrong type. + ** Hunt for right time, right type. + ** It's okay to guess wrong since the guess + ** gets checked. + */ + /* + ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. + */ + sp = (const struct state *) + (((void *) funcp == (void *) localsub) ? + lclptr : gmtptr); #ifdef ALL_STATE - if (sp == NULL) - return WRONG; + if (sp == NULL) + return WRONG; #endif /* defined ALL_STATE */ - for (i = sp->typecnt - 1; i >= 0; --i) { - if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) - continue; - for (j = sp->typecnt - 1; j >= 0; --j) { - if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) - continue; - newt = t + sp->ttis[j].tt_gmtoff - - sp->ttis[i].tt_gmtoff; - if ((*funcp)(&newt, offset, &mytm) == NULL) - continue; - if (tmcomp(&mytm, &yourtm) != 0) - continue; - if (mytm.tm_isdst != yourtm.tm_isdst) - continue; - /* - ** We have a match. - */ - t = newt; - goto label; - } - } - return WRONG; - } + for (i = sp->typecnt - 1; i >= 0; --i) { + if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) + continue; + for (j = sp->typecnt - 1; j >= 0; --j) { + if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) + continue; + newt = t + sp->ttis[j].tt_gmtoff - + sp->ttis[i].tt_gmtoff; + if ((*funcp)(&newt, offset, &mytm) == NULL) + continue; + if (tmcomp(&mytm, &yourtm) != 0) + continue; + if (mytm.tm_isdst != yourtm.tm_isdst) + continue; + /* + ** We have a match. + */ + t = newt; + goto label; + } + } + return WRONG; + } label: - newt = t + saved_seconds; - if ((newt < t) != (saved_seconds < 0)) - return WRONG; - t = newt; - if ((*funcp)(&t, offset, tmp)) - *okayp = TRUE; - return t; + newt = t + saved_seconds; + if ((newt < t) != (saved_seconds < 0)) + return WRONG; + t = newt; + if ((*funcp)(&t, offset, tmp)) + *okayp = TRUE; + return t; } static time_t time2(tmp, funcp, offset, okayp) -struct tm * const tmp; -struct tm * (* const funcp) P((const time_t*, long, struct tm*)); -const long offset; -int * const okayp; +struct tm * const tmp; +struct tm * (* const funcp) P((const time_t*, long, struct tm*)); +const long offset; +int * const okayp; { - time_t t; - - /* - ** First try without normalization of seconds - ** (in case tm_sec contains a value associated with a leap second). - ** If that fails, try with normalization of seconds. - */ - t = time2sub(tmp, funcp, offset, okayp, FALSE); - return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE); + time_t t; + + /* + ** First try without normalization of seconds + ** (in case tm_sec contains a value associated with a leap second). + ** If that fails, try with normalization of seconds. + */ + t = time2sub(tmp, funcp, offset, okayp, FALSE); + return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE); } static time_t time1(tmp, funcp, offset) -struct tm * const tmp; -struct tm * (* const funcp) P((const time_t *, long, struct tm *)); -const long offset; +struct tm * const tmp; +struct tm * (* const funcp) P((const time_t *, long, struct tm *)); +const long offset; { - register time_t t; - register const struct state * sp; - register int samei, otheri; - register int sameind, otherind; - register int i; - register int nseen; - int seen[TZ_MAX_TYPES]; - int types[TZ_MAX_TYPES]; - int okay; - - if (tmp->tm_isdst > 1) - tmp->tm_isdst = 1; - t = time2(tmp, funcp, offset, &okay); + register time_t t; + register const struct state * sp; + register int samei, otheri; + register int sameind, otherind; + register int i; + register int nseen; + int seen[TZ_MAX_TYPES]; + int types[TZ_MAX_TYPES]; + int okay; + + if (tmp->tm_isdst > 1) + tmp->tm_isdst = 1; + t = time2(tmp, funcp, offset, &okay); #ifdef PCTS - /* - ** PCTS code courtesy Grant Sullivan. - */ - if (okay) - return t; - if (tmp->tm_isdst < 0) - tmp->tm_isdst = 0; /* reset to std and try again */ + /* + ** PCTS code courtesy Grant Sullivan. + */ + if (okay) + return t; + if (tmp->tm_isdst < 0) + tmp->tm_isdst = 0; /* reset to std and try again */ #endif /* defined PCTS */ #ifndef PCTS - if (okay || tmp->tm_isdst < 0) - return t; + if (okay || tmp->tm_isdst < 0) + return t; #endif /* !defined PCTS */ - /* - ** We're supposed to assume that somebody took a time of one type - ** and did some math on it that yielded a "struct tm" that's bad. - ** We try to divine the type they started from and adjust to the - ** type they need. - */ - /* - ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. - */ - sp = (const struct state *) (((void *) funcp == (void *) localsub) ? - lclptr : gmtptr); + /* + ** We're supposed to assume that somebody took a time of one type + ** and did some math on it that yielded a "struct tm" that's bad. + ** We try to divine the type they started from and adjust to the + ** type they need. + */ + /* + ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. + */ + sp = (const struct state *) (((void *) funcp == (void *) localsub) ? + lclptr : gmtptr); #ifdef ALL_STATE - if (sp == NULL) - return WRONG; + if (sp == NULL) + return WRONG; #endif /* defined ALL_STATE */ - for (i = 0; i < sp->typecnt; ++i) - seen[i] = FALSE; - nseen = 0; - for (i = sp->timecnt - 1; i >= 0; --i) - if (!seen[sp->types[i]]) { - seen[sp->types[i]] = TRUE; - types[nseen++] = sp->types[i]; - } - for (sameind = 0; sameind < nseen; ++sameind) { - samei = types[sameind]; - if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) - continue; - for (otherind = 0; otherind < nseen; ++otherind) { - otheri = types[otherind]; - if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) - continue; - tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - - sp->ttis[samei].tt_gmtoff; - tmp->tm_isdst = !tmp->tm_isdst; - t = time2(tmp, funcp, offset, &okay); - if (okay) - return t; - tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - - sp->ttis[samei].tt_gmtoff; - tmp->tm_isdst = !tmp->tm_isdst; - } - } - return WRONG; + for (i = 0; i < sp->typecnt; ++i) + seen[i] = FALSE; + nseen = 0; + for (i = sp->timecnt - 1; i >= 0; --i) + if (!seen[sp->types[i]]) { + seen[sp->types[i]] = TRUE; + types[nseen++] = sp->types[i]; + } + for (sameind = 0; sameind < nseen; ++sameind) { + samei = types[sameind]; + if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) + continue; + for (otherind = 0; otherind < nseen; ++otherind) { + otheri = types[otherind]; + if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) + continue; + tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - + sp->ttis[samei].tt_gmtoff; + tmp->tm_isdst = !tmp->tm_isdst; + t = time2(tmp, funcp, offset, &okay); + if (okay) + return t; + tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - + sp->ttis[samei].tt_gmtoff; + tmp->tm_isdst = !tmp->tm_isdst; + } + } + return WRONG; } time_t mktime(tmp) -struct tm * const tmp; +struct tm * const tmp; { - tzset(); - return time1(tmp, localsub, 0L); + time_t result; + _tzLock(); + tzset_locked(); + result = time1(tmp, localsub, 0L); + _tzUnlock(); + return result; } #ifdef STD_INSPIRED time_t timelocal(tmp) -struct tm * const tmp; +struct tm * const tmp; { - tmp->tm_isdst = -1; /* in case it wasn't initialized */ - return mktime(tmp); + tmp->tm_isdst = -1; /* in case it wasn't initialized */ + return mktime(tmp); } time_t timegm(tmp) -struct tm * const tmp; +struct tm * const tmp; { - tmp->tm_isdst = 0; - return time1(tmp, gmtsub, 0L); + time_t result; + + tmp->tm_isdst = 0; + _tzLock(); + result = time1(tmp, gmtsub, 0L); + _tzUnlock(); + + return result; } time_t timeoff(tmp, offset) -struct tm * const tmp; -const long offset; +struct tm * const tmp; +const long offset; { - tmp->tm_isdst = 0; - return time1(tmp, gmtsub, offset); + time_t result; + + tmp->tm_isdst = 0; + _tzLock(); + result = time1(tmp, gmtsub, offset); + _tzUnlock(); + + return result; } #endif /* defined STD_INSPIRED */ @@ -2044,13 +2128,13 @@ const long offset; long gtime(tmp) -struct tm * const tmp; +struct tm * const tmp; { - const time_t t = mktime(tmp); + const time_t t = mktime(tmp); - if (t == WRONG) - return -1; - return t; + if (t == WRONG) + return -1; + return t; } #endif /* defined CMUCS */ @@ -2071,62 +2155,62 @@ struct tm * const tmp; static long leapcorr(timep) -time_t * timep; +time_t * timep; { - register struct state * sp; - register struct lsinfo * lp; - register int i; - - sp = lclptr; - i = sp->leapcnt; - while (--i >= 0) { - lp = &sp->lsis[i]; - if (*timep >= lp->ls_trans) - return lp->ls_corr; - } - return 0; + register struct state * sp; + register struct lsinfo * lp; + register int i; + + sp = lclptr; + i = sp->leapcnt; + while (--i >= 0) { + lp = &sp->lsis[i]; + if (*timep >= lp->ls_trans) + return lp->ls_corr; + } + return 0; } time_t time2posix(t) -time_t t; +time_t t; { - tzset(); - return t - leapcorr(&t); + tzset(); + return t - leapcorr(&t); } time_t posix2time(t) -time_t t; +time_t t; { - time_t x; - time_t y; - - tzset(); - /* - ** For a positive leap second hit, the result - ** is not unique. For a negative leap second - ** hit, the corresponding time doesn't exist, - ** so we return an adjacent second. - */ - x = t + leapcorr(&t); - y = x - leapcorr(&x); - if (y < t) { - do { - x++; - y = x - leapcorr(&x); - } while (y < t); - if (t != y) - return x - 1; - } else if (y > t) { - do { - --x; - y = x - leapcorr(&x); - } while (y > t); - if (t != y) - return x + 1; - } - return x; + time_t x; + time_t y; + + tzset(); + /* + ** For a positive leap second hit, the result + ** is not unique. For a negative leap second + ** hit, the corresponding time doesn't exist, + ** so we return an adjacent second. + */ + x = t + leapcorr(&t); + y = x - leapcorr(&x); + if (y < t) { + do { + x++; + y = x - leapcorr(&x); + } while (y < t); + if (t != y) + return x - 1; + } else if (y > t) { + do { + --x; + y = x - leapcorr(&x); + } while (y > t); + if (t != y) + return x + 1; + } + return x; } #endif /* defined STD_INSPIRED */ diff --git a/libc/tzcode/private.h b/libc/tzcode/private.h index 2837b70..e82a655 100644 --- a/libc/tzcode/private.h +++ b/libc/tzcode/private.h @@ -21,11 +21,11 @@ #ifndef lint #ifndef NOID -static char privatehid[] = "@(#)private.h 8.2"; +static char privatehid[] = "@(#)private.h 8.2"; #endif /* !defined NOID */ #endif /* !defined lint */ -#define GRANDPARENTED "Local time zone must be set--see zic manual page" +#define GRANDPARENTED "Local time zone must be set--see zic manual page" /* ** Defaults for preprocessor symbols. @@ -33,49 +33,45 @@ static char privatehid[] = "@(#)private.h 8.2"; */ #ifndef HAVE_ADJTIME -#define HAVE_ADJTIME 1 +#define HAVE_ADJTIME 1 #endif /* !defined HAVE_ADJTIME */ #ifndef HAVE_GETTEXT -#define HAVE_GETTEXT 0 +#define HAVE_GETTEXT 0 #endif /* !defined HAVE_GETTEXT */ #ifndef HAVE_INCOMPATIBLE_CTIME_R -#define HAVE_INCOMPATIBLE_CTIME_R 0 +#define HAVE_INCOMPATIBLE_CTIME_R 0 #endif /* !defined INCOMPATIBLE_CTIME_R */ #ifndef HAVE_SETTIMEOFDAY -#define HAVE_SETTIMEOFDAY 3 +#define HAVE_SETTIMEOFDAY 3 #endif /* !defined HAVE_SETTIMEOFDAY */ #ifndef HAVE_STRERROR -#define HAVE_STRERROR 1 +#define HAVE_STRERROR 1 #endif /* !defined HAVE_STRERROR */ #ifndef HAVE_SYMLINK -#define HAVE_SYMLINK 1 +#define HAVE_SYMLINK 1 #endif /* !defined HAVE_SYMLINK */ #ifndef HAVE_SYS_STAT_H -#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_STAT_H 1 #endif /* !defined HAVE_SYS_STAT_H */ #ifndef HAVE_SYS_WAIT_H -#define HAVE_SYS_WAIT_H 1 +#define HAVE_SYS_WAIT_H 1 #endif /* !defined HAVE_SYS_WAIT_H */ #ifndef HAVE_UNISTD_H -#define HAVE_UNISTD_H 1 +#define HAVE_UNISTD_H 1 #endif /* !defined HAVE_UNISTD_H */ #ifndef HAVE_UTMPX_H -#define HAVE_UTMPX_H 0 +#define HAVE_UTMPX_H 0 #endif /* !defined HAVE_UTMPX_H */ -#ifndef LOCALE_HOME -#define LOCALE_HOME "/usr/lib/locale" -#endif /* !defined LOCALE_HOME */ - #if HAVE_INCOMPATIBLE_CTIME_R #define asctime_r _incompatible_asctime_r #define ctime_r _incompatible_ctime_r @@ -85,11 +81,11 @@ static char privatehid[] = "@(#)private.h 8.2"; ** Nested includes */ -#include "sys/types.h" /* for time_t */ +#include "sys/types.h" /* for time_t */ #include "stdio.h" #include "errno.h" #include "string.h" -#include "limits.h" /* for CHAR_BIT et al. */ +#include "limits.h" /* for CHAR_BIT et al. */ #include "time.h" #include "stdlib.h" @@ -98,26 +94,26 @@ static char privatehid[] = "@(#)private.h 8.2"; #endif /* HAVE_GETTEXT */ #if HAVE_SYS_WAIT_H -#include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */ +#include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */ #endif /* HAVE_SYS_WAIT_H */ #ifndef WIFEXITED -#define WIFEXITED(status) (((status) & 0xff) == 0) +#define WIFEXITED(status) (((status) & 0xff) == 0) #endif /* !defined WIFEXITED */ #ifndef WEXITSTATUS -#define WEXITSTATUS(status) (((status) >> 8) & 0xff) +#define WEXITSTATUS(status) (((status) >> 8) & 0xff) #endif /* !defined WEXITSTATUS */ #if HAVE_UNISTD_H -#include "unistd.h" /* for F_OK and R_OK */ +#include "unistd.h" /* for F_OK and R_OK */ #endif /* HAVE_UNISTD_H */ #if !HAVE_UNISTD_H #ifndef F_OK -#define F_OK 0 +#define F_OK 0 #endif /* !defined F_OK */ #ifndef R_OK -#define R_OK 4 +#define R_OK 4 #endif /* !defined R_OK */ #endif /* !HAVE_UNISTD_H */ @@ -132,8 +128,8 @@ static char privatehid[] = "@(#)private.h 8.2"; */ #ifndef HAVE_STDINT_H #define HAVE_STDINT_H \ - (199901 <= __STDC_VERSION__ || \ - 2 < (__GLIBC__ + (0 < __GLIBC_MINOR__))) + (199901 <= __STDC_VERSION__ || \ + 2 < (__GLIBC__ + (0 < __GLIBC_MINOR__))) #endif /* !defined HAVE_STDINT_H */ #if HAVE_STDINT_H @@ -143,13 +139,13 @@ static char privatehid[] = "@(#)private.h 8.2"; #ifndef INT_FAST64_MAX /* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */ #if defined LLONG_MAX || defined __LONG_LONG_MAX__ -typedef long long int_fast64_t; +typedef long long int_fast64_t; #else /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */ #if (LONG_MAX >> 31) < 0xffffffff Please use a compiler that supports a 64-bit integer type (or wider); you may need to compile with "-DHAVE_STDINT_H". #endif /* (LONG_MAX >> 31) < 0xffffffff */ -typedef long int_fast64_t; +typedef long int_fast64_t; #endif /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */ #endif /* !defined INT_FAST64_MAX */ @@ -169,7 +165,7 @@ typedef long int_fast64_t; */ #ifndef P -#define P(x) x +#define P(x) x #endif /* !defined P */ /* @@ -177,7 +173,7 @@ typedef long int_fast64_t; */ #ifndef EXIT_SUCCESS -#define EXIT_SUCCESS 0 +#define EXIT_SUCCESS 0 #endif /* !defined EXIT_SUCCESS */ /* @@ -185,7 +181,7 @@ typedef long int_fast64_t; */ #ifndef EXIT_FAILURE -#define EXIT_FAILURE 1 +#define EXIT_FAILURE 1 #endif /* !defined EXIT_FAILURE */ /* @@ -201,10 +197,10 @@ typedef long int_fast64_t; #endif /* !defined MAXPATHLEN */ #ifdef MAXPATHLEN -#define FILENAME_MAX MAXPATHLEN +#define FILENAME_MAX MAXPATHLEN #endif /* defined MAXPATHLEN */ #ifndef MAXPATHLEN -#define FILENAME_MAX 1024 /* Pure guesswork */ +#define FILENAME_MAX 1024 /* Pure guesswork */ #endif /* !defined MAXPATHLEN */ #endif /* !defined FILENAME_MAX */ @@ -214,8 +210,8 @@ typedef long int_fast64_t; */ #ifndef remove -extern int unlink P((const char * filename)); -#define remove unlink +extern int unlink P((const char * filename)); +#define remove unlink #endif /* !defined remove */ /* @@ -235,36 +231,36 @@ extern int errno; */ #ifndef asctime_r -extern char * asctime_r(); +extern char * asctime_r(); #endif /* ** Private function declarations. */ -char * icalloc P((int nelem, int elsize)); -char * icatalloc P((char * old, const char * new)); -char * icpyalloc P((const char * string)); -char * imalloc P((int n)); -void * irealloc P((void * pointer, int size)); -void icfree P((char * pointer)); -void ifree P((char * pointer)); -const char * scheck P((const char * string, const char * format)); +char * icalloc P((int nelem, int elsize)); +char * icatalloc P((char * old, const char * new)); +char * icpyalloc P((const char * string)); +char * imalloc P((int n)); +void * irealloc P((void * pointer, int size)); +void icfree P((char * pointer)); +void ifree P((char * pointer)); +const char * scheck P((const char * string, const char * format)); /* ** Finally, some convenience items. */ #ifndef TRUE -#define TRUE 1 +#define TRUE 1 #endif /* !defined TRUE */ #ifndef FALSE -#define FALSE 0 +#define FALSE 0 #endif /* !defined FALSE */ #ifndef TYPE_BIT -#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT) +#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT) #endif /* !defined TYPE_BIT */ #ifndef TYPE_SIGNED @@ -288,8 +284,8 @@ const char * scheck P((const char * string, const char * format)); ** add one more for a minus sign if the type is signed. */ #define INT_STRLEN_MAXIMUM(type) \ - ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \ - 1 + TYPE_SIGNED(type)) + ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \ + 1 + TYPE_SIGNED(type)) #endif /* !defined INT_STRLEN_MAXIMUM */ /* @@ -309,7 +305,7 @@ const char * scheck P((const char * string, const char * format)); #ifndef INITIALIZE #ifdef GNUC_or_lint -#define INITIALIZE(x) ((x) = 0) +#define INITIALIZE(x) ((x) = 0) #endif /* defined GNUC_or_lint */ #ifndef GNUC_or_lint #define INITIALIZE(x) @@ -342,7 +338,7 @@ char *ctime_r P((time_t const *, char *)); #endif /* HAVE_INCOMPATIBLE_CTIME_R */ #ifndef YEARSPERREPEAT -#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */ +#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */ #endif /* !defined YEARSPERREPEAT */ /* @@ -350,15 +346,15 @@ char *ctime_r P((time_t const *, char *)); */ #ifndef AVGSECSPERYEAR -#define AVGSECSPERYEAR 31556952L +#define AVGSECSPERYEAR 31556952L #endif /* !defined AVGSECSPERYEAR */ #ifndef SECSPERREPEAT -#define SECSPERREPEAT ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR) +#define SECSPERREPEAT ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR) #endif /* !defined SECSPERREPEAT */ #ifndef SECSPERREPEAT_BITS -#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */ +#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */ #endif /* !defined SECSPERREPEAT_BITS */ /* diff --git a/libc/tzcode/strftime.c b/libc/tzcode/strftime.c index 946c91c..ab713fb 100644 --- a/libc/tzcode/strftime.c +++ b/libc/tzcode/strftime.c @@ -1,6 +1,6 @@ #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)strftime.c 8.1"; +static char elsieid[] = "@(#)strftime.c 8.1"; /* ** Based on the UCB version with the ID appearing below. ** This is ANSIish only when "multibyte character == plain character". @@ -29,7 +29,7 @@ static char elsieid[] = "@(#)strftime.c 8.1"; #ifndef LIBC_SCCS #ifndef lint -static const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89"; +static const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89"; #endif /* !defined lint */ #endif /* !defined LIBC_SCCS */ @@ -37,132 +37,143 @@ static const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89"; #include "fcntl.h" #include "locale.h" #include <ctype.h> - +#include <time64.h> + +/* struct lc_time_T is now defined as strftime_locale + * in <time.h> + */ +#if 1 +#define lc_time_T strftime_locale +#else struct lc_time_T { - const char * mon[MONSPERYEAR]; - const char * month[MONSPERYEAR]; - const char * wday[DAYSPERWEEK]; - const char * weekday[DAYSPERWEEK]; - const char * X_fmt; - const char * x_fmt; - const char * c_fmt; - const char * am; - const char * pm; - const char * date_fmt; + const char * mon[MONSPERYEAR]; + const char * month[MONSPERYEAR]; + const char * wday[DAYSPERWEEK]; + const char * weekday[DAYSPERWEEK]; + const char * X_fmt; + const char * x_fmt; + const char * c_fmt; + const char * am; + const char * pm; + const char * date_fmt; }; - -#ifdef LOCALE_HOME -#include "sys/stat.h" -static struct lc_time_T localebuf; -static struct lc_time_T * _loc P((void)); -#define Locale _loc() -#endif /* defined LOCALE_HOME */ -#ifndef LOCALE_HOME -#define Locale (&C_time_locale) -#endif /* !defined LOCALE_HOME */ - -static const struct lc_time_T C_time_locale = { - { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }, { - "January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December" - }, { - "Sun", "Mon", "Tue", "Wed", - "Thu", "Fri", "Sat" - }, { - "Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday" - }, - - /* X_fmt */ - "%H:%M:%S", - - /* - ** x_fmt - ** C99 requires this format. - ** Using just numbers (as here) makes Quakers happier; - ** it's also compatible with SVR4. - */ - "%m/%d/%y", - - /* - ** c_fmt - ** C99 requires this format. - ** Previously this code used "%D %X", but we now conform to C99. - ** Note that - ** "%a %b %d %H:%M:%S %Y" - ** is used by Solaris 2.3. - */ - "%a %b %e %T %Y", - - /* am */ - "AM", - - /* pm */ - "PM", - - /* date_fmt */ - "%a %b %e %H:%M:%S %Z %Y" +#endif + +#define Locale (&C_time_locale) + +static const struct lc_time_T C_time_locale = { + { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }, { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + }, { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + }, { + "Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat" + }, { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" + }, + + /* X_fmt */ + "%H:%M:%S", + + /* + ** x_fmt + ** C99 requires this format. + ** Using just numbers (as here) makes Quakers happier; + ** it's also compatible with SVR4. + */ + "%m/%d/%y", + + /* + ** c_fmt + ** C99 requires this format. + ** Previously this code used "%D %X", but we now conform to C99. + ** Note that + ** "%a %b %d %H:%M:%S %Y" + ** is used by Solaris 2.3. + */ + "%a %b %e %T %Y", + + /* am */ + "AM", + + /* pm */ + "PM", + + /* date_fmt */ + "%a %b %e %H:%M:%S %Z %Y" }; -static char * _add P((const char *, char *, const char *, int)); -static char * _conv P((int, const char *, char *, const char *)); -static char * _fmt P((const char *, const struct tm *, char *, const char *, - int *)); -static char * _yconv P((int, int, int, int, char *, const char *, int)); -static char * getformat P((int, char *, char *, char *, char *)); +static char * _add P((const char *, char *, const char *, int)); +static char * _conv P((int, const char *, char *, const char *)); +static char * _fmt P((const char *, const struct tm *, char *, const char *, + int *, const struct strftime_locale*)); +static char * _yconv P((int, int, int, int, char *, const char *, int)); +static char * getformat P((int, char *, char *, char *, char *)); -extern char * tzname[]; +extern char * tzname[]; #ifndef YEAR_2000_NAME -#define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS" +#define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS" #endif /* !defined YEAR_2000_NAME */ -#define IN_NONE 0 -#define IN_SOME 1 -#define IN_THIS 2 -#define IN_ALL 3 +#define IN_NONE 0 +#define IN_SOME 1 +#define IN_THIS 2 +#define IN_ALL 3 #define FORCE_LOWER_CASE 0x100 size_t strftime(s, maxsize, format, t) -char * const s; -const size_t maxsize; -const char * const format; -const struct tm * const t; +char * const s; +const size_t maxsize; +const char * const format; +const struct tm * const t; { - char * p; - int warn; - - tzset(); -#ifdef LOCALE_HOME - localebuf.mon[0] = 0; -#endif /* defined LOCALE_HOME */ - warn = IN_NONE; - p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn); -#ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU - if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) { - (void) fprintf(stderr, "\n"); - if (format == NULL) - (void) fprintf(stderr, "NULL strftime format "); - else (void) fprintf(stderr, "strftime format \"%s\" ", - format); - (void) fprintf(stderr, "yields only two digits of years in "); - if (warn == IN_SOME) - (void) fprintf(stderr, "some locales"); - else if (warn == IN_THIS) - (void) fprintf(stderr, "the current locale"); - else (void) fprintf(stderr, "all locales"); - (void) fprintf(stderr, "\n"); - } + return strftime_tz(s, maxsize, format, t, Locale); +} + +size_t +strftime_tz(s, maxsize, format, t, locale) +char * const s; +const size_t maxsize; +const char * const format; +const struct tm * const t; +const struct strftime_locale *locale; +{ + char * p; + int warn; + + tzset(); + warn = IN_NONE; + p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, locale); +#if 0 /* ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */ + if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) { + (void) fprintf(stderr, "\n"); + if (format == NULL) + (void) fprintf(stderr, "NULL strftime format "); + else (void) fprintf(stderr, "strftime format \"%s\" ", + format); + (void) fprintf(stderr, "yields only two digits of years in "); + if (warn == IN_SOME) + (void) fprintf(stderr, "some locales"); + else if (warn == IN_THIS) + (void) fprintf(stderr, "the current locale"); + else (void) fprintf(stderr, "all locales"); + (void) fprintf(stderr, "\n"); + } #endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */ - if (p == s + maxsize) - return 0; - *p = '\0'; - return p - s; + if (p == s + maxsize) + return 0; + *p = '\0'; + return p - s; } static char *getformat(int modifier, char *normal, char *underscore, @@ -182,89 +193,97 @@ static char *getformat(int modifier, char *normal, char *underscore, } static char * -_fmt(format, t, pt, ptlim, warnp) -const char * format; -const struct tm * const t; -char * pt; -const char * const ptlim; -int * warnp; +_fmt(format, t, pt, ptlim, warnp, locale) +const char * format; +const struct tm * const t; +char * pt; +const char * const ptlim; +int * warnp; +const struct strftime_locale* locale; { - for ( ; *format; ++format) { - if (*format == '%') { + for ( ; *format; ++format) { + if (*format == '%') { int modifier = 0; label: - switch (*++format) { - case '\0': - --format; - break; - case 'A': - pt = _add((t->tm_wday < 0 || - t->tm_wday >= DAYSPERWEEK) ? - "?" : Locale->weekday[t->tm_wday], - pt, ptlim, modifier); - continue; - case 'a': - pt = _add((t->tm_wday < 0 || - t->tm_wday >= DAYSPERWEEK) ? - "?" : Locale->wday[t->tm_wday], - pt, ptlim, modifier); - continue; - case 'B': - pt = _add((t->tm_mon < 0 || - t->tm_mon >= MONSPERYEAR) ? - "?" : Locale->month[t->tm_mon], - pt, ptlim, modifier); - continue; - case 'b': - case 'h': - pt = _add((t->tm_mon < 0 || - t->tm_mon >= MONSPERYEAR) ? - "?" : Locale->mon[t->tm_mon], - pt, ptlim, modifier); - continue; - case 'C': - /* - ** %C used to do a... - ** _fmt("%a %b %e %X %Y", t); - ** ...whereas now POSIX 1003.2 calls for - ** something completely different. - ** (ado, 1993-05-24) - */ - pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0, - pt, ptlim, modifier); - continue; - case 'c': - { - int warn2 = IN_SOME; - - pt = _fmt(Locale->c_fmt, t, pt, ptlim, warnp); - if (warn2 == IN_ALL) - warn2 = IN_THIS; - if (warn2 > *warnp) - *warnp = warn2; - } - continue; - case 'D': - pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp); - continue; - case 'd': + switch (*++format) { + case '\0': + --format; + break; + case 'A': + pt = _add((t->tm_wday < 0 || + t->tm_wday >= DAYSPERWEEK) ? + "?" : locale->weekday[t->tm_wday], + pt, ptlim, modifier); + continue; + case 'a': + pt = _add((t->tm_wday < 0 || + t->tm_wday >= DAYSPERWEEK) ? + "?" : locale->wday[t->tm_wday], + pt, ptlim, modifier); + continue; + case 'B': + if (modifier == '-') { + pt = _add((t->tm_mon < 0 || + t->tm_mon >= MONSPERYEAR) ? + "?" : locale->standalone_month[t->tm_mon], + pt, ptlim, modifier); + } else { + pt = _add((t->tm_mon < 0 || + t->tm_mon >= MONSPERYEAR) ? + "?" : locale->month[t->tm_mon], + pt, ptlim, modifier); + } + continue; + case 'b': + case 'h': + pt = _add((t->tm_mon < 0 || + t->tm_mon >= MONSPERYEAR) ? + "?" : locale->mon[t->tm_mon], + pt, ptlim, modifier); + continue; + case 'C': + /* + ** %C used to do a... + ** _fmt("%a %b %e %X %Y", t); + ** ...whereas now POSIX 1003.2 calls for + ** something completely different. + ** (ado, 1993-05-24) + */ + pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0, + pt, ptlim, modifier); + continue; + case 'c': + { + int warn2 = IN_SOME; + + pt = _fmt(locale->c_fmt, t, pt, ptlim, warnp, locale); + if (warn2 == IN_ALL) + warn2 = IN_THIS; + if (warn2 > *warnp) + *warnp = warn2; + } + continue; + case 'D': + pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, locale); + continue; + case 'd': pt = _conv(t->tm_mday, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim); - continue; - case 'E': - case 'O': - /* - ** C99 locale modifiers. - ** The sequences - ** %Ec %EC %Ex %EX %Ey %EY - ** %Od %oe %OH %OI %Om %OM - ** %OS %Ou %OU %OV %Ow %OW %Oy - ** are supposed to provide alternate - ** representations. - */ - goto label; + continue; + case 'E': + case 'O': + /* + ** C99 locale modifiers. + ** The sequences + ** %Ec %EC %Ex %EX %Ey %EY + ** %Od %oe %OH %OI %Om %OM + ** %OS %Ou %OU %OV %Ow %OW %Oy + ** are supposed to provide alternate + ** representations. + */ + goto label; case '_': case '-': case '0': @@ -272,155 +291,155 @@ label: case '#': modifier = *format; goto label; - case 'e': - pt = _conv(t->tm_mday, + case 'e': + pt = _conv(t->tm_mday, getformat(modifier, "%2d", "%2d", "%d", "%02d"), pt, ptlim); - continue; - case 'F': - pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp); - continue; - case 'H': - pt = _conv(t->tm_hour, + continue; + case 'F': + pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, locale); + continue; + case 'H': + pt = _conv(t->tm_hour, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim); - continue; - case 'I': - pt = _conv((t->tm_hour % 12) ? - (t->tm_hour % 12) : 12, - getformat(modifier, "%02d", + continue; + case 'I': + pt = _conv((t->tm_hour % 12) ? + (t->tm_hour % 12) : 12, + getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim); - continue; - case 'j': - pt = _conv(t->tm_yday + 1, + continue; + case 'j': + pt = _conv(t->tm_yday + 1, getformat(modifier, "%03d", "%3d", "%d", "%03d"), pt, ptlim); - continue; - case 'k': - /* - ** This used to be... - ** _conv(t->tm_hour % 12 ? - ** t->tm_hour % 12 : 12, 2, ' '); - ** ...and has been changed to the below to - ** match SunOS 4.1.1 and Arnold Robbins' - ** strftime version 3.0. That is, "%k" and - ** "%l" have been swapped. - ** (ado, 1993-05-24) - */ - pt = _conv(t->tm_hour, + continue; + case 'k': + /* + ** This used to be... + ** _conv(t->tm_hour % 12 ? + ** t->tm_hour % 12 : 12, 2, ' '); + ** ...and has been changed to the below to + ** match SunOS 4.1.1 and Arnold Robbins' + ** strftime version 3.0. That is, "%k" and + ** "%l" have been swapped. + ** (ado, 1993-05-24) + */ + pt = _conv(t->tm_hour, getformat(modifier, "%2d", "%2d", "%d", "%02d"), pt, ptlim); - continue; + continue; #ifdef KITCHEN_SINK - case 'K': - /* - ** After all this time, still unclaimed! - */ - pt = _add("kitchen sink", pt, ptlim, modifier); - continue; + case 'K': + /* + ** After all this time, still unclaimed! + */ + pt = _add("kitchen sink", pt, ptlim, modifier); + continue; #endif /* defined KITCHEN_SINK */ - case 'l': - /* - ** This used to be... - ** _conv(t->tm_hour, 2, ' '); - ** ...and has been changed to the below to - ** match SunOS 4.1.1 and Arnold Robbin's - ** strftime version 3.0. That is, "%k" and - ** "%l" have been swapped. - ** (ado, 1993-05-24) - */ - pt = _conv((t->tm_hour % 12) ? - (t->tm_hour % 12) : 12, - getformat(modifier, "%2d", + case 'l': + /* + ** This used to be... + ** _conv(t->tm_hour, 2, ' '); + ** ...and has been changed to the below to + ** match SunOS 4.1.1 and Arnold Robbin's + ** strftime version 3.0. That is, "%k" and + ** "%l" have been swapped. + ** (ado, 1993-05-24) + */ + pt = _conv((t->tm_hour % 12) ? + (t->tm_hour % 12) : 12, + getformat(modifier, "%2d", "%2d", "%d", "%02d"), pt, ptlim); - continue; - case 'M': - pt = _conv(t->tm_min, + continue; + case 'M': + pt = _conv(t->tm_min, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim); - continue; - case 'm': - pt = _conv(t->tm_mon + 1, + continue; + case 'm': + pt = _conv(t->tm_mon + 1, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim); - continue; - case 'n': - pt = _add("\n", pt, ptlim, modifier); - continue; - case 'p': - pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ? - Locale->pm : - Locale->am, - pt, ptlim, modifier); - continue; - case 'P': - pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ? - Locale->pm : - Locale->am, - pt, ptlim, FORCE_LOWER_CASE); - continue; - case 'R': - pt = _fmt("%H:%M", t, pt, ptlim, warnp); - continue; - case 'r': - pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp); - continue; - case 'S': - pt = _conv(t->tm_sec, + continue; + case 'n': + pt = _add("\n", pt, ptlim, modifier); + continue; + case 'p': + pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ? + locale->pm : + locale->am, + pt, ptlim, modifier); + continue; + case 'P': + pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ? + locale->pm : + locale->am, + pt, ptlim, FORCE_LOWER_CASE); + continue; + case 'R': + pt = _fmt("%H:%M", t, pt, ptlim, warnp, locale); + continue; + case 'r': + pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp, locale); + continue; + case 'S': + pt = _conv(t->tm_sec, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim); - continue; - case 's': - { - struct tm tm; - char buf[INT_STRLEN_MAXIMUM( - time_t) + 1]; - time_t mkt; - - tm = *t; - mkt = mktime(&tm); - if (TYPE_SIGNED(time_t)) - (void) sprintf(buf, "%ld", - (long) mkt); - else (void) sprintf(buf, "%lu", - (unsigned long) mkt); - pt = _add(buf, pt, ptlim, modifier); - } - continue; - case 'T': - pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp); - continue; - case 't': - pt = _add("\t", pt, ptlim, modifier); - continue; - case 'U': - pt = _conv((t->tm_yday + DAYSPERWEEK - - t->tm_wday) / DAYSPERWEEK, - getformat(modifier, "%02d", + continue; + case 's': + { + struct tm tm; + char buf[INT_STRLEN_MAXIMUM( + time64_t) + 1]; + time64_t mkt; + + tm = *t; + mkt = mktime64(&tm); + if (TYPE_SIGNED(time64_t)) + (void) sprintf(buf, "%lld", + (long long) mkt); + else (void) sprintf(buf, "%llu", + (unsigned long long) mkt); + pt = _add(buf, pt, ptlim, modifier); + } + continue; + case 'T': + pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, locale); + continue; + case 't': + pt = _add("\t", pt, ptlim, modifier); + continue; + case 'U': + pt = _conv((t->tm_yday + DAYSPERWEEK - + t->tm_wday) / DAYSPERWEEK, + getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim); - continue; - case 'u': - /* - ** From Arnold Robbins' strftime version 3.0: - ** "ISO 8601: Weekday as a decimal number - ** [1 (Monday) - 7]" - ** (ado, 1993-05-24) - */ - pt = _conv((t->tm_wday == 0) ? - DAYSPERWEEK : t->tm_wday, "%d", pt, ptlim); - continue; - case 'V': /* ISO 8601 week number */ - case 'G': /* ISO 8601 year (four digits) */ - case 'g': /* ISO 8601 year (two digits) */ + continue; + case 'u': + /* + ** From Arnold Robbins' strftime version 3.0: + ** "ISO 8601: Weekday as a decimal number + ** [1 (Monday) - 7]" + ** (ado, 1993-05-24) + */ + pt = _conv((t->tm_wday == 0) ? + DAYSPERWEEK : t->tm_wday, "%d", pt, ptlim); + continue; + case 'V': /* ISO 8601 week number */ + case 'G': /* ISO 8601 year (four digits) */ + case 'g': /* ISO 8601 year (two digits) */ /* ** From Arnold Robbins' strftime version 3.0: "the week number of the ** year (the first Monday as the first day of week 1) as a decimal number @@ -439,232 +458,232 @@ label: ** 1997 lasts from 1996-12-30 to 1997-01-05..." ** (ado, 1996-01-02) */ - { - int year; - int base; - int yday; - int wday; - int w; - - year = t->tm_year; - base = TM_YEAR_BASE; - yday = t->tm_yday; - wday = t->tm_wday; - for ( ; ; ) { - int len; - int bot; - int top; - - len = isleap_sum(year, base) ? - DAYSPERLYEAR : - DAYSPERNYEAR; - /* - ** What yday (-3 ... 3) does - ** the ISO year begin on? - */ - bot = ((yday + 11 - wday) % - DAYSPERWEEK) - 3; - /* - ** What yday does the NEXT - ** ISO year begin on? - */ - top = bot - - (len % DAYSPERWEEK); - if (top < -3) - top += DAYSPERWEEK; - top += len; - if (yday >= top) { - ++base; - w = 1; - break; - } - if (yday >= bot) { - w = 1 + ((yday - bot) / - DAYSPERWEEK); - break; - } - --base; - yday += isleap_sum(year, base) ? - DAYSPERLYEAR : - DAYSPERNYEAR; - } + { + int year; + int base; + int yday; + int wday; + int w; + + year = t->tm_year; + base = TM_YEAR_BASE; + yday = t->tm_yday; + wday = t->tm_wday; + for ( ; ; ) { + int len; + int bot; + int top; + + len = isleap_sum(year, base) ? + DAYSPERLYEAR : + DAYSPERNYEAR; + /* + ** What yday (-3 ... 3) does + ** the ISO year begin on? + */ + bot = ((yday + 11 - wday) % + DAYSPERWEEK) - 3; + /* + ** What yday does the NEXT + ** ISO year begin on? + */ + top = bot - + (len % DAYSPERWEEK); + if (top < -3) + top += DAYSPERWEEK; + top += len; + if (yday >= top) { + ++base; + w = 1; + break; + } + if (yday >= bot) { + w = 1 + ((yday - bot) / + DAYSPERWEEK); + break; + } + --base; + yday += isleap_sum(year, base) ? + DAYSPERLYEAR : + DAYSPERNYEAR; + } #ifdef XPG4_1994_04_09 - if ((w == 52 && - t->tm_mon == TM_JANUARY) || - (w == 1 && - t->tm_mon == TM_DECEMBER)) - w = 53; + if ((w == 52 && + t->tm_mon == TM_JANUARY) || + (w == 1 && + t->tm_mon == TM_DECEMBER)) + w = 53; #endif /* defined XPG4_1994_04_09 */ - if (*format == 'V') - pt = _conv(w, + if (*format == 'V') + pt = _conv(w, getformat(modifier, "%02d", "%2d", "%d", "%02d"), - pt, ptlim); - else if (*format == 'g') { - *warnp = IN_ALL; - pt = _yconv(year, base, 0, 1, - pt, ptlim, modifier); - } else pt = _yconv(year, base, 1, 1, - pt, ptlim, modifier); - } - continue; - case 'v': - /* - ** From Arnold Robbins' strftime version 3.0: - ** "date as dd-bbb-YYYY" - ** (ado, 1993-05-24) - */ - pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp); - continue; - case 'W': - pt = _conv((t->tm_yday + DAYSPERWEEK - - (t->tm_wday ? - (t->tm_wday - 1) : - (DAYSPERWEEK - 1))) / DAYSPERWEEK, - getformat(modifier, "%02d", + pt, ptlim); + else if (*format == 'g') { + *warnp = IN_ALL; + pt = _yconv(year, base, 0, 1, + pt, ptlim, modifier); + } else pt = _yconv(year, base, 1, 1, + pt, ptlim, modifier); + } + continue; + case 'v': + /* + ** From Arnold Robbins' strftime version 3.0: + ** "date as dd-bbb-YYYY" + ** (ado, 1993-05-24) + */ + pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, locale); + continue; + case 'W': + pt = _conv((t->tm_yday + DAYSPERWEEK - + (t->tm_wday ? + (t->tm_wday - 1) : + (DAYSPERWEEK - 1))) / DAYSPERWEEK, + getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim); - continue; - case 'w': - pt = _conv(t->tm_wday, "%d", pt, ptlim); - continue; - case 'X': - pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp); - continue; - case 'x': - { - int warn2 = IN_SOME; - - pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2); - if (warn2 == IN_ALL) - warn2 = IN_THIS; - if (warn2 > *warnp) - *warnp = warn2; - } - continue; - case 'y': - *warnp = IN_ALL; - pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1, - pt, ptlim, modifier); - continue; - case 'Y': - pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1, - pt, ptlim, modifier); - continue; - case 'Z': + continue; + case 'w': + pt = _conv(t->tm_wday, "%d", pt, ptlim); + continue; + case 'X': + pt = _fmt(locale->X_fmt, t, pt, ptlim, warnp, locale); + continue; + case 'x': + { + int warn2 = IN_SOME; + + pt = _fmt(locale->x_fmt, t, pt, ptlim, &warn2, locale); + if (warn2 == IN_ALL) + warn2 = IN_THIS; + if (warn2 > *warnp) + *warnp = warn2; + } + continue; + case 'y': + *warnp = IN_ALL; + pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1, + pt, ptlim, modifier); + continue; + case 'Y': + pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1, + pt, ptlim, modifier); + continue; + case 'Z': #ifdef TM_ZONE - if (t->TM_ZONE != NULL) - pt = _add(t->TM_ZONE, pt, ptlim, + if (t->TM_ZONE != NULL) + pt = _add(t->TM_ZONE, pt, ptlim, modifier); - else + else #endif /* defined TM_ZONE */ - if (t->tm_isdst >= 0) - pt = _add(tzname[t->tm_isdst != 0], - pt, ptlim, modifier); - /* - ** C99 says that %Z must be replaced by the - ** empty string if the time zone is not - ** determinable. - */ - continue; - case 'z': - { - int diff; - char const * sign; - - if (t->tm_isdst < 0) - continue; + if (t->tm_isdst >= 0) + pt = _add(tzname[t->tm_isdst != 0], + pt, ptlim, modifier); + /* + ** C99 says that %Z must be replaced by the + ** empty string if the time zone is not + ** determinable. + */ + continue; + case 'z': + { + int diff; + char const * sign; + + if (t->tm_isdst < 0) + continue; #ifdef TM_GMTOFF - diff = t->TM_GMTOFF; + diff = t->TM_GMTOFF; #else /* !defined TM_GMTOFF */ - /* - ** C99 says that the UTC offset must - ** be computed by looking only at - ** tm_isdst. This requirement is - ** incorrect, since it means the code - ** must rely on magic (in this case - ** altzone and timezone), and the - ** magic might not have the correct - ** offset. Doing things correctly is - ** tricky and requires disobeying C99; - ** see GNU C strftime for details. - ** For now, punt and conform to the - ** standard, even though it's incorrect. - ** - ** C99 says that %z must be replaced by the - ** empty string if the time zone is not - ** determinable, so output nothing if the - ** appropriate variables are not available. - */ - if (t->tm_isdst == 0) + /* + ** C99 says that the UTC offset must + ** be computed by looking only at + ** tm_isdst. This requirement is + ** incorrect, since it means the code + ** must rely on magic (in this case + ** altzone and timezone), and the + ** magic might not have the correct + ** offset. Doing things correctly is + ** tricky and requires disobeying C99; + ** see GNU C strftime for details. + ** For now, punt and conform to the + ** standard, even though it's incorrect. + ** + ** C99 says that %z must be replaced by the + ** empty string if the time zone is not + ** determinable, so output nothing if the + ** appropriate variables are not available. + */ + if (t->tm_isdst == 0) #ifdef USG_COMPAT - diff = -timezone; + diff = -timezone; #else /* !defined USG_COMPAT */ - continue; + continue; #endif /* !defined USG_COMPAT */ - else + else #ifdef ALTZONE - diff = -altzone; + diff = -altzone; #else /* !defined ALTZONE */ - continue; + continue; #endif /* !defined ALTZONE */ #endif /* !defined TM_GMTOFF */ - if (diff < 0) { - sign = "-"; - diff = -diff; - } else sign = "+"; - pt = _add(sign, pt, ptlim, modifier); - diff /= SECSPERMIN; - diff = (diff / MINSPERHOUR) * 100 + - (diff % MINSPERHOUR); - pt = _conv(diff, + if (diff < 0) { + sign = "-"; + diff = -diff; + } else sign = "+"; + pt = _add(sign, pt, ptlim, modifier); + diff /= SECSPERMIN; + diff = (diff / MINSPERHOUR) * 100 + + (diff % MINSPERHOUR); + pt = _conv(diff, getformat(modifier, "%04d", "%4d", "%d", "%04d"), pt, ptlim); - } - continue; - case '+': - pt = _fmt(Locale->date_fmt, t, pt, ptlim, - warnp); - continue; - case '%': - /* - ** X311J/88-090 (4.12.3.5): if conversion char is - ** undefined, behavior is undefined. Print out the - ** character itself as printf(3) also does. - */ - default: - break; - } - } - if (pt == ptlim) - break; - *pt++ = *format; - } - return pt; + } + continue; + case '+': + pt = _fmt(locale->date_fmt, t, pt, ptlim, + warnp, locale); + continue; + case '%': + /* + ** X311J/88-090 (4.12.3.5): if conversion char is + ** undefined, behavior is undefined. Print out the + ** character itself as printf(3) also does. + */ + default: + break; + } + } + if (pt == ptlim) + break; + *pt++ = *format; + } + return pt; } static char * _conv(n, format, pt, ptlim) -const int n; -const char * const format; -char * const pt; -const char * const ptlim; +const int n; +const char * const format; +char * const pt; +const char * const ptlim; { - char buf[INT_STRLEN_MAXIMUM(int) + 1]; + char buf[INT_STRLEN_MAXIMUM(int) + 1]; - (void) sprintf(buf, format, n); - return _add(buf, pt, ptlim, 0); + (void) snprintf(buf, sizeof(buf), format, n); + return _add(buf, pt, ptlim, 0); } static char * _add(str, pt, ptlim, modifier) -const char * str; -char * pt; -const char * const ptlim; +const char * str; +char * pt; +const char * const ptlim; int modifier; { int c; @@ -701,7 +720,7 @@ int modifier; } } - return pt; + return pt; } /* @@ -714,159 +733,38 @@ int modifier; static char * _yconv(a, b, convert_top, convert_yy, pt, ptlim, modifier) -const int a; -const int b; -const int convert_top; -const int convert_yy; -char * pt; -const char * const ptlim; +const int a; +const int b; +const int convert_top; +const int convert_yy; +char * pt; +const char * const ptlim; int modifier; { - register int lead; - register int trail; - -#define DIVISOR 100 - trail = a % DIVISOR + b % DIVISOR; - lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR; - trail %= DIVISOR; - if (trail < 0 && lead > 0) { - trail += DIVISOR; - --lead; - } else if (lead < 0 && trail > 0) { - trail -= DIVISOR; - ++lead; - } - if (convert_top) { - if (lead == 0 && trail < 0) - pt = _add("-0", pt, ptlim, modifier); - else pt = _conv(lead, getformat(modifier, "%02d", + register int lead; + register int trail; + +#define DIVISOR 100 + trail = a % DIVISOR + b % DIVISOR; + lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR; + trail %= DIVISOR; + if (trail < 0 && lead > 0) { + trail += DIVISOR; + --lead; + } else if (lead < 0 && trail > 0) { + trail -= DIVISOR; + ++lead; + } + if (convert_top) { + if (lead == 0 && trail < 0) + pt = _add("-0", pt, ptlim, modifier); + else pt = _conv(lead, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim); - } - if (convert_yy) - pt = _conv(((trail < 0) ? -trail : trail), + } + if (convert_yy) + pt = _conv(((trail < 0) ? -trail : trail), getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim); - return pt; -} - -#ifdef LOCALE_HOME -static struct lc_time_T * -_loc P((void)) -{ - static const char locale_home[] = LOCALE_HOME; - static const char lc_time[] = "LC_TIME"; - static char * locale_buf; - - int fd; - int oldsun; /* "...ain't got nothin' to do..." */ - char * lbuf; - char * name; - char * p; - const char ** ap; - const char * plim; - char filename[FILENAME_MAX]; - struct stat st; - size_t namesize; - size_t bufsize; - - /* - ** Use localebuf.mon[0] to signal whether locale is already set up. - */ - if (localebuf.mon[0]) - return &localebuf; - name = setlocale(LC_TIME, (char *) NULL); - if (name == NULL || *name == '\0') - goto no_locale; - /* - ** If the locale name is the same as our cache, use the cache. - */ - lbuf = locale_buf; - if (lbuf != NULL && strcmp(name, lbuf) == 0) { - p = lbuf; - for (ap = (const char **) &localebuf; - ap < (const char **) (&localebuf + 1); - ++ap) - *ap = p += strlen(p) + 1; - return &localebuf; - } - /* - ** Slurp the locale file into the cache. - */ - namesize = strlen(name) + 1; - if (sizeof filename < - ((sizeof locale_home) + namesize + (sizeof lc_time))) - goto no_locale; - oldsun = 0; - (void) sprintf(filename, "%s/%s/%s", locale_home, name, lc_time); - fd = open(filename, O_RDONLY); - if (fd < 0) { - /* - ** Old Sun systems have a different naming and data convention. - */ - oldsun = 1; - (void) sprintf(filename, "%s/%s/%s", locale_home, - lc_time, name); - fd = open(filename, O_RDONLY); - if (fd < 0) - goto no_locale; - } - if (fstat(fd, &st) != 0) - goto bad_locale; - if (st.st_size <= 0) - goto bad_locale; - bufsize = namesize + st.st_size; - locale_buf = NULL; - lbuf = (lbuf == NULL) ? malloc(bufsize) : realloc(lbuf, bufsize); - if (lbuf == NULL) - goto bad_locale; - (void) strcpy(lbuf, name); - p = lbuf + namesize; - plim = p + st.st_size; - if (read(fd, p, (size_t) st.st_size) != st.st_size) - goto bad_lbuf; - if (close(fd) != 0) - goto bad_lbuf; - /* - ** Parse the locale file into localebuf. - */ - if (plim[-1] != '\n') - goto bad_lbuf; - for (ap = (const char **) &localebuf; - ap < (const char **) (&localebuf + 1); - ++ap) { - if (p == plim) - goto bad_lbuf; - *ap = p; - while (*p != '\n') - ++p; - *p++ = '\0'; - } - if (oldsun) { - /* - ** SunOS 4 used an obsolescent format; see localdtconv(3). - ** c_fmt had the ``short format for dates and times together'' - ** (SunOS 4 date, "%a %b %e %T %Z %Y" in the C locale); - ** date_fmt had the ``long format for dates'' - ** (SunOS 4 strftime %C, "%A, %B %e, %Y" in the C locale). - ** Discard the latter in favor of the former. - */ - localebuf.date_fmt = localebuf.c_fmt; - } - /* - ** Record the successful parse in the cache. - */ - locale_buf = lbuf; - - return &localebuf; - -bad_lbuf: - free(lbuf); -bad_locale: - (void) close(fd); -no_locale: - localebuf = C_time_locale; - locale_buf = NULL; - return &localebuf; + return pt; } -#endif /* defined LOCALE_HOME */ diff --git a/libc/tzcode/strptime.c b/libc/tzcode/strptime.c index 982daf4..1f481c9 100644 --- a/libc/tzcode/strptime.c +++ b/libc/tzcode/strptime.c @@ -1,5 +1,5 @@ -/* $OpenBSD: strptime.c,v 1.11 2005/08/08 08:05:38 espie Exp $ */ -/* $NetBSD: strptime.c,v 1.12 1998/01/20 21:39:40 mycroft Exp $ */ +/* $OpenBSD: strptime.c,v 1.11 2005/08/08 08:05:38 espie Exp $ */ +/* $NetBSD: strptime.c,v 1.12 1998/01/20 21:39:40 mycroft Exp $ */ /*- * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. @@ -44,387 +44,387 @@ #include "tzfile.h" static const struct { - const char *abday[7]; - const char *day[7]; - const char *abmon[12]; - const char *mon[12]; - const char *am_pm[2]; - const char *d_t_fmt; - const char *d_fmt; - const char *t_fmt; - const char *t_fmt_ampm; + const char *abday[7]; + const char *day[7]; + const char *abmon[12]; + const char *mon[12]; + const char *am_pm[2]; + const char *d_t_fmt; + const char *d_fmt; + const char *t_fmt; + const char *t_fmt_ampm; } _DefaultTimeLocale = { - { - "Sun","Mon","Tue","Wed","Thu","Fri","Sat", - }, - { - "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", - "Friday", "Saturday" - }, - { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }, - { - "January", "February", "March", "April", "May", "June", "July", - "August", "September", "October", "November", "December" - }, - { - "AM", "PM" - }, - "%a %b %d %H:%M:%S %Y", - "%m/%d/%y", - "%H:%M:%S", - "%I:%M:%S %p" + { + "Sun","Mon","Tue","Wed","Thu","Fri","Sat", + }, + { + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", + "Friday", "Saturday" + }, + { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }, + { + "January", "February", "March", "April", "May", "June", "July", + "August", "September", "October", "November", "December" + }, + { + "AM", "PM" + }, + "%a %b %d %H:%M:%S %Y", + "%m/%d/%y", + "%H:%M:%S", + "%I:%M:%S %p" }; -#define _ctloc(x) (_DefaultTimeLocale.x) +#define _ctloc(x) (_DefaultTimeLocale.x) /* * We do not implement alternate representations. However, we always * check whether a given modifier is allowed for a certain conversion. */ -#define _ALT_E 0x01 -#define _ALT_O 0x02 -#define _LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); } +#define _ALT_E 0x01 +#define _ALT_O 0x02 +#define _LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); } -static int _conv_num(const unsigned char **, int *, int, int); -static char *_strptime(const char *, const char *, struct tm *, int); +static int _conv_num(const unsigned char **, int *, int, int); +static unsigned char *_strptime(const unsigned char *, const char *, struct tm *, int); char * strptime(const char *buf, const char *fmt, struct tm *tm) { - return(_strptime(buf, fmt, tm, 1)); + return (char*)(_strptime((const unsigned char*)buf, fmt, tm, 1)); } -static char * -_strptime(const char *buf, const char *fmt, struct tm *tm, int initialize) +static unsigned char * +_strptime(const unsigned char *buf, const char *fmt, struct tm *tm, int initialize) { - unsigned char c; - const unsigned char *bp; - size_t len; - int alt_format, i; - static int century, relyear; - - if (initialize) { - century = TM_YEAR_BASE; - relyear = -1; - } - - bp = (unsigned char *)buf; - while ((c = *fmt) != '\0') { - /* Clear `alternate' modifier prior to new conversion. */ - alt_format = 0; - - /* Eat up white-space. */ - if (isspace(c)) { - while (isspace(*bp)) - bp++; - - fmt++; - continue; - } - - if ((c = *fmt++) != '%') - goto literal; - - -again: switch (c = *fmt++) { - case '%': /* "%%" is converted to "%". */ + unsigned char c; + const unsigned char *bp; + size_t len = 0; + int alt_format, i; + static int century, relyear; + + if (initialize) { + century = TM_YEAR_BASE; + relyear = -1; + } + + bp = (unsigned char *)buf; + while ((c = *fmt) != '\0') { + /* Clear `alternate' modifier prior to new conversion. */ + alt_format = 0; + + /* Eat up white-space. */ + if (isspace(c)) { + while (isspace(*bp)) + bp++; + + fmt++; + continue; + } + + if ((c = *fmt++) != '%') + goto literal; + + +again: switch (c = *fmt++) { + case '%': /* "%%" is converted to "%". */ literal: - if (c != *bp++) - return (NULL); - - break; - - /* - * "Alternative" modifiers. Just set the appropriate flag - * and start over again. - */ - case 'E': /* "%E?" alternative conversion modifier. */ - _LEGAL_ALT(0); - alt_format |= _ALT_E; - goto again; - - case 'O': /* "%O?" alternative conversion modifier. */ - _LEGAL_ALT(0); - alt_format |= _ALT_O; - goto again; - - /* - * "Complex" conversion rules, implemented through recursion. - */ - case 'c': /* Date and time, using the locale's format. */ - _LEGAL_ALT(_ALT_E); - if (!(bp = _strptime(bp, _ctloc(d_t_fmt), tm, 0))) - return (NULL); - break; - - case 'D': /* The date as "%m/%d/%y". */ - _LEGAL_ALT(0); - if (!(bp = _strptime(bp, "%m/%d/%y", tm, 0))) - return (NULL); - break; - - case 'R': /* The time as "%H:%M". */ - _LEGAL_ALT(0); - if (!(bp = _strptime(bp, "%H:%M", tm, 0))) - return (NULL); - break; - - case 'r': /* The time as "%I:%M:%S %p". */ - _LEGAL_ALT(0); - if (!(bp = _strptime(bp, "%I:%M:%S %p", tm, 0))) - return (NULL); - break; - - case 'T': /* The time as "%H:%M:%S". */ - _LEGAL_ALT(0); - if (!(bp = _strptime(bp, "%H:%M:%S", tm, 0))) - return (NULL); - break; - - case 'X': /* The time, using the locale's format. */ - _LEGAL_ALT(_ALT_E); - if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, 0))) - return (NULL); - break; - - case 'x': /* The date, using the locale's format. */ - _LEGAL_ALT(_ALT_E); - if (!(bp = _strptime(bp, _ctloc(d_fmt), tm, 0))) - return (NULL); - break; - - /* - * "Elementary" conversion rules. - */ - case 'A': /* The day of week, using the locale's form. */ - case 'a': - _LEGAL_ALT(0); - for (i = 0; i < 7; i++) { - /* Full name. */ - len = strlen(_ctloc(day[i])); - if (strncasecmp(_ctloc(day[i]), bp, len) == 0) - break; - - /* Abbreviated name. */ - len = strlen(_ctloc(abday[i])); - if (strncasecmp(_ctloc(abday[i]), bp, len) == 0) - break; - } - - /* Nothing matched. */ - if (i == 7) - return (NULL); - - tm->tm_wday = i; - bp += len; - break; - - case 'B': /* The month, using the locale's form. */ - case 'b': - case 'h': - _LEGAL_ALT(0); - for (i = 0; i < 12; i++) { - /* Full name. */ - len = strlen(_ctloc(mon[i])); - if (strncasecmp(_ctloc(mon[i]), bp, len) == 0) - break; - - /* Abbreviated name. */ - len = strlen(_ctloc(abmon[i])); - if (strncasecmp(_ctloc(abmon[i]), bp, len) == 0) - break; - } - - /* Nothing matched. */ - if (i == 12) - return (NULL); - - tm->tm_mon = i; - bp += len; - break; - - case 'C': /* The century number. */ - _LEGAL_ALT(_ALT_E); - if (!(_conv_num(&bp, &i, 0, 99))) - return (NULL); - - century = i * 100; - break; - - case 'd': /* The day of month. */ - case 'e': - _LEGAL_ALT(_ALT_O); - if (!(_conv_num(&bp, &tm->tm_mday, 1, 31))) - return (NULL); - break; - - case 'k': /* The hour (24-hour clock representation). */ - _LEGAL_ALT(0); - /* FALLTHROUGH */ - case 'H': - _LEGAL_ALT(_ALT_O); - if (!(_conv_num(&bp, &tm->tm_hour, 0, 23))) - return (NULL); - break; - - case 'l': /* The hour (12-hour clock representation). */ - _LEGAL_ALT(0); - /* FALLTHROUGH */ - case 'I': - _LEGAL_ALT(_ALT_O); - if (!(_conv_num(&bp, &tm->tm_hour, 1, 12))) - return (NULL); - break; - - case 'j': /* The day of year. */ - _LEGAL_ALT(0); - if (!(_conv_num(&bp, &tm->tm_yday, 1, 366))) - return (NULL); - tm->tm_yday--; - break; - - case 'M': /* The minute. */ - _LEGAL_ALT(_ALT_O); - if (!(_conv_num(&bp, &tm->tm_min, 0, 59))) - return (NULL); - break; - - case 'm': /* The month. */ - _LEGAL_ALT(_ALT_O); - if (!(_conv_num(&bp, &tm->tm_mon, 1, 12))) - return (NULL); - tm->tm_mon--; - break; - - case 'p': /* The locale's equivalent of AM/PM. */ - _LEGAL_ALT(0); - /* AM? */ - len = strlen(_ctloc(am_pm[0])); - if (strncasecmp(_ctloc(am_pm[0]), bp, len) == 0) { - if (tm->tm_hour > 12) /* i.e., 13:00 AM ?! */ - return (NULL); - else if (tm->tm_hour == 12) - tm->tm_hour = 0; - - bp += len; - break; - } - /* PM? */ - len = strlen(_ctloc(am_pm[1])); - if (strncasecmp(_ctloc(am_pm[1]), bp, len) == 0) { - if (tm->tm_hour > 12) /* i.e., 13:00 PM ?! */ - return (NULL); - else if (tm->tm_hour < 12) - tm->tm_hour += 12; - - bp += len; - break; - } - - /* Nothing matched. */ - return (NULL); - - case 'S': /* The seconds. */ - _LEGAL_ALT(_ALT_O); - if (!(_conv_num(&bp, &tm->tm_sec, 0, 61))) - return (NULL); - break; - - case 'U': /* The week of year, beginning on sunday. */ - case 'W': /* The week of year, beginning on monday. */ - _LEGAL_ALT(_ALT_O); - /* - * XXX This is bogus, as we can not assume any valid - * information present in the tm structure at this - * point to calculate a real value, so just check the - * range for now. - */ - if (!(_conv_num(&bp, &i, 0, 53))) - return (NULL); - break; - - case 'w': /* The day of week, beginning on sunday. */ - _LEGAL_ALT(_ALT_O); - if (!(_conv_num(&bp, &tm->tm_wday, 0, 6))) - return (NULL); - break; - - case 'Y': /* The year. */ - _LEGAL_ALT(_ALT_E); - if (!(_conv_num(&bp, &i, 0, 9999))) - return (NULL); - - relyear = -1; - tm->tm_year = i - TM_YEAR_BASE; - break; - - case 'y': /* The year within the century (2 digits). */ - _LEGAL_ALT(_ALT_E | _ALT_O); - if (!(_conv_num(&bp, &relyear, 0, 99))) - return (NULL); - break; - - /* - * Miscellaneous conversions. - */ - case 'n': /* Any kind of white-space. */ - case 't': - _LEGAL_ALT(0); - while (isspace(*bp)) - bp++; - break; - - - default: /* Unknown/unsupported conversion. */ - return (NULL); - } - - - } - - /* - * We need to evaluate the two digit year spec (%y) - * last as we can get a century spec (%C) at any time. - */ - if (relyear != -1) { - if (century == TM_YEAR_BASE) { - if (relyear <= 68) - tm->tm_year = relyear + 2000 - TM_YEAR_BASE; - else - tm->tm_year = relyear + 1900 - TM_YEAR_BASE; - } else { - tm->tm_year = relyear + century - TM_YEAR_BASE; - } - } - - return ((char *)bp); + if (c != *bp++) + return (NULL); + + break; + + /* + * "Alternative" modifiers. Just set the appropriate flag + * and start over again. + */ + case 'E': /* "%E?" alternative conversion modifier. */ + _LEGAL_ALT(0); + alt_format |= _ALT_E; + goto again; + + case 'O': /* "%O?" alternative conversion modifier. */ + _LEGAL_ALT(0); + alt_format |= _ALT_O; + goto again; + + /* + * "Complex" conversion rules, implemented through recursion. + */ + case 'c': /* Date and time, using the locale's format. */ + _LEGAL_ALT(_ALT_E); + if (!(bp = _strptime(bp, _ctloc(d_t_fmt), tm, 0))) + return (NULL); + break; + + case 'D': /* The date as "%m/%d/%y". */ + _LEGAL_ALT(0); + if (!(bp = _strptime(bp, "%m/%d/%y", tm, 0))) + return (NULL); + break; + + case 'R': /* The time as "%H:%M". */ + _LEGAL_ALT(0); + if (!(bp = _strptime(bp, "%H:%M", tm, 0))) + return (NULL); + break; + + case 'r': /* The time as "%I:%M:%S %p". */ + _LEGAL_ALT(0); + if (!(bp = _strptime(bp, "%I:%M:%S %p", tm, 0))) + return (NULL); + break; + + case 'T': /* The time as "%H:%M:%S". */ + _LEGAL_ALT(0); + if (!(bp = _strptime(bp, "%H:%M:%S", tm, 0))) + return (NULL); + break; + + case 'X': /* The time, using the locale's format. */ + _LEGAL_ALT(_ALT_E); + if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, 0))) + return (NULL); + break; + + case 'x': /* The date, using the locale's format. */ + _LEGAL_ALT(_ALT_E); + if (!(bp = _strptime(bp, _ctloc(d_fmt), tm, 0))) + return (NULL); + break; + + /* + * "Elementary" conversion rules. + */ + case 'A': /* The day of week, using the locale's form. */ + case 'a': + _LEGAL_ALT(0); + for (i = 0; i < 7; i++) { + /* Full name. */ + len = strlen(_ctloc(day[i])); + if (strncasecmp(_ctloc(day[i]), (const char*)bp, len) == 0) + break; + + /* Abbreviated name. */ + len = strlen(_ctloc(abday[i])); + if (strncasecmp(_ctloc(abday[i]), (const char*)bp, len) == 0) + break; + } + + /* Nothing matched. */ + if (i == 7) + return (NULL); + + tm->tm_wday = i; + bp += len; + break; + + case 'B': /* The month, using the locale's form. */ + case 'b': + case 'h': + _LEGAL_ALT(0); + for (i = 0; i < 12; i++) { + /* Full name. */ + len = strlen(_ctloc(mon[i])); + if (strncasecmp(_ctloc(mon[i]), (const char*)bp, len) == 0) + break; + + /* Abbreviated name. */ + len = strlen(_ctloc(abmon[i])); + if (strncasecmp(_ctloc(abmon[i]), (const char*)bp, len) == 0) + break; + } + + /* Nothing matched. */ + if (i == 12) + return (NULL); + + tm->tm_mon = i; + bp += len; + break; + + case 'C': /* The century number. */ + _LEGAL_ALT(_ALT_E); + if (!(_conv_num(&bp, &i, 0, 99))) + return (NULL); + + century = i * 100; + break; + + case 'd': /* The day of month. */ + case 'e': + _LEGAL_ALT(_ALT_O); + if (!(_conv_num(&bp, &tm->tm_mday, 1, 31))) + return (NULL); + break; + + case 'k': /* The hour (24-hour clock representation). */ + _LEGAL_ALT(0); + /* FALLTHROUGH */ + case 'H': + _LEGAL_ALT(_ALT_O); + if (!(_conv_num(&bp, &tm->tm_hour, 0, 23))) + return (NULL); + break; + + case 'l': /* The hour (12-hour clock representation). */ + _LEGAL_ALT(0); + /* FALLTHROUGH */ + case 'I': + _LEGAL_ALT(_ALT_O); + if (!(_conv_num(&bp, &tm->tm_hour, 1, 12))) + return (NULL); + break; + + case 'j': /* The day of year. */ + _LEGAL_ALT(0); + if (!(_conv_num(&bp, &tm->tm_yday, 1, 366))) + return (NULL); + tm->tm_yday--; + break; + + case 'M': /* The minute. */ + _LEGAL_ALT(_ALT_O); + if (!(_conv_num(&bp, &tm->tm_min, 0, 59))) + return (NULL); + break; + + case 'm': /* The month. */ + _LEGAL_ALT(_ALT_O); + if (!(_conv_num(&bp, &tm->tm_mon, 1, 12))) + return (NULL); + tm->tm_mon--; + break; + + case 'p': /* The locale's equivalent of AM/PM. */ + _LEGAL_ALT(0); + /* AM? */ + len = strlen(_ctloc(am_pm[0])); + if (strncasecmp(_ctloc(am_pm[0]), (const char*)bp, len) == 0) { + if (tm->tm_hour > 12) /* i.e., 13:00 AM ?! */ + return (NULL); + else if (tm->tm_hour == 12) + tm->tm_hour = 0; + + bp += len; + break; + } + /* PM? */ + len = strlen(_ctloc(am_pm[1])); + if (strncasecmp(_ctloc(am_pm[1]), (const char*)bp, len) == 0) { + if (tm->tm_hour > 12) /* i.e., 13:00 PM ?! */ + return (NULL); + else if (tm->tm_hour < 12) + tm->tm_hour += 12; + + bp += len; + break; + } + + /* Nothing matched. */ + return (NULL); + + case 'S': /* The seconds. */ + _LEGAL_ALT(_ALT_O); + if (!(_conv_num(&bp, &tm->tm_sec, 0, 61))) + return (NULL); + break; + + case 'U': /* The week of year, beginning on sunday. */ + case 'W': /* The week of year, beginning on monday. */ + _LEGAL_ALT(_ALT_O); + /* + * XXX This is bogus, as we can not assume any valid + * information present in the tm structure at this + * point to calculate a real value, so just check the + * range for now. + */ + if (!(_conv_num(&bp, &i, 0, 53))) + return (NULL); + break; + + case 'w': /* The day of week, beginning on sunday. */ + _LEGAL_ALT(_ALT_O); + if (!(_conv_num(&bp, &tm->tm_wday, 0, 6))) + return (NULL); + break; + + case 'Y': /* The year. */ + _LEGAL_ALT(_ALT_E); + if (!(_conv_num(&bp, &i, 0, 9999))) + return (NULL); + + relyear = -1; + tm->tm_year = i - TM_YEAR_BASE; + break; + + case 'y': /* The year within the century (2 digits). */ + _LEGAL_ALT(_ALT_E | _ALT_O); + if (!(_conv_num(&bp, &relyear, 0, 99))) + return (NULL); + break; + + /* + * Miscellaneous conversions. + */ + case 'n': /* Any kind of white-space. */ + case 't': + _LEGAL_ALT(0); + while (isspace(*bp)) + bp++; + break; + + + default: /* Unknown/unsupported conversion. */ + return (NULL); + } + + + } + + /* + * We need to evaluate the two digit year spec (%y) + * last as we can get a century spec (%C) at any time. + */ + if (relyear != -1) { + if (century == TM_YEAR_BASE) { + if (relyear <= 68) + tm->tm_year = relyear + 2000 - TM_YEAR_BASE; + else + tm->tm_year = relyear + 1900 - TM_YEAR_BASE; + } else { + tm->tm_year = relyear + century - TM_YEAR_BASE; + } + } + + return (unsigned char*)bp; } static int _conv_num(const unsigned char **buf, int *dest, int llim, int ulim) { - int result = 0; - int rulim = ulim; + int result = 0; + int rulim = ulim; - if (**buf < '0' || **buf > '9') - return (0); + if (**buf < '0' || **buf > '9') + return (0); - /* we use rulim to break out of the loop when we run out of digits */ - do { - result *= 10; - result += *(*buf)++ - '0'; - rulim /= 10; - } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9'); + /* we use rulim to break out of the loop when we run out of digits */ + do { + result *= 10; + result += *(*buf)++ - '0'; + rulim /= 10; + } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9'); - if (result < llim || result > ulim) - return (0); + if (result < llim || result > ulim) + return (0); - *dest = result; - return (1); + *dest = result; + return (1); } diff --git a/libc/tzcode/tzfile.h b/libc/tzcode/tzfile.h index 480682e..f6c9a05 100644 --- a/libc/tzcode/tzfile.h +++ b/libc/tzcode/tzfile.h @@ -21,7 +21,7 @@ #ifndef lint #ifndef NOID -static char tzfilehid[] = "@(#)tzfile.h 8.1"; +static char tzfilehid[] = "@(#)tzfile.h 8.1"; #endif /* !defined NOID */ #endif /* !defined lint */ @@ -34,54 +34,54 @@ static char tzfilehid[] = "@(#)tzfile.h 8.1"; #endif /* !defined TZDIR */ #ifndef TZDEFAULT -#define TZDEFAULT "localtime" +#define TZDEFAULT "localtime" #endif /* !defined TZDEFAULT */ #ifndef TZDEFRULES -#define TZDEFRULES "posixrules" +#define TZDEFRULES "posixrules" #endif /* !defined TZDEFRULES */ /* ** Each file begins with. . . */ -#define TZ_MAGIC "TZif" +#define TZ_MAGIC "TZif" struct tzhead { - char tzh_magic[4]; /* TZ_MAGIC */ - char tzh_version[1]; /* '\0' or '2' as of 2005 */ - char tzh_reserved[15]; /* reserved--must be zero */ - char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ - char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ - char tzh_leapcnt[4]; /* coded number of leap seconds */ - char tzh_timecnt[4]; /* coded number of transition times */ - char tzh_typecnt[4]; /* coded number of local time types */ - char tzh_charcnt[4]; /* coded number of abbr. chars */ + char tzh_magic[4]; /* TZ_MAGIC */ + char tzh_version[1]; /* '\0' or '2' as of 2005 */ + char tzh_reserved[15]; /* reserved--must be zero */ + char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ + char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ + char tzh_leapcnt[4]; /* coded number of leap seconds */ + char tzh_timecnt[4]; /* coded number of transition times */ + char tzh_typecnt[4]; /* coded number of local time types */ + char tzh_charcnt[4]; /* coded number of abbr. chars */ }; /* ** . . .followed by. . . ** -** tzh_timecnt (char [4])s coded transition times a la time(2) -** tzh_timecnt (unsigned char)s types of local time starting at above -** tzh_typecnt repetitions of -** one (char [4]) coded UTC offset in seconds -** one (unsigned char) used to set tm_isdst -** one (unsigned char) that's an abbreviation list index -** tzh_charcnt (char)s '\0'-terminated zone abbreviations -** tzh_leapcnt repetitions of -** one (char [4]) coded leap second transition times -** one (char [4]) total correction after above -** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition -** time is standard time, if FALSE, -** transition time is wall clock time -** if absent, transition times are -** assumed to be wall clock time -** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition -** time is UTC, if FALSE, -** transition time is local time -** if absent, transition times are -** assumed to be local time +** tzh_timecnt (char [4])s coded transition times a la time(2) +** tzh_timecnt (unsigned char)s types of local time starting at above +** tzh_typecnt repetitions of +** one (char [4]) coded UTC offset in seconds +** one (unsigned char) used to set tm_isdst +** one (unsigned char) that's an abbreviation list index +** tzh_charcnt (char)s '\0'-terminated zone abbreviations +** tzh_leapcnt repetitions of +** one (char [4]) coded leap second transition times +** one (char [4]) total correction after above +** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition +** time is standard time, if FALSE, +** transition time is wall clock time +** if absent, transition times are +** assumed to be wall clock time +** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition +** time is UTC, if FALSE, +** transition time is local time +** if absent, transition times are +** assumed to be local time */ /* @@ -100,81 +100,81 @@ struct tzhead { */ #ifndef TZ_MAX_TIMES -#define TZ_MAX_TIMES 1200 +#define TZ_MAX_TIMES 1200 #endif /* !defined TZ_MAX_TIMES */ #ifndef TZ_MAX_TYPES #ifndef NOSOLAR -#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ +#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ #endif /* !defined NOSOLAR */ #ifdef NOSOLAR /* ** Must be at least 14 for Europe/Riga as of Jan 12 1995, ** as noted by Earl Chew. */ -#define TZ_MAX_TYPES 20 /* Maximum number of local time types */ +#define TZ_MAX_TYPES 20 /* Maximum number of local time types */ #endif /* !defined NOSOLAR */ #endif /* !defined TZ_MAX_TYPES */ #ifndef TZ_MAX_CHARS -#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ - /* (limited by what unsigned chars can hold) */ +#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ + /* (limited by what unsigned chars can hold) */ #endif /* !defined TZ_MAX_CHARS */ #ifndef TZ_MAX_LEAPS -#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ +#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ #endif /* !defined TZ_MAX_LEAPS */ -#define SECSPERMIN 60 -#define MINSPERHOUR 60 -#define HOURSPERDAY 24 -#define DAYSPERWEEK 7 -#define DAYSPERNYEAR 365 -#define DAYSPERLYEAR 366 -#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) -#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) -#define MONSPERYEAR 12 - -#define TM_SUNDAY 0 -#define TM_MONDAY 1 -#define TM_TUESDAY 2 -#define TM_WEDNESDAY 3 -#define TM_THURSDAY 4 -#define TM_FRIDAY 5 -#define TM_SATURDAY 6 - -#define TM_JANUARY 0 -#define TM_FEBRUARY 1 -#define TM_MARCH 2 -#define TM_APRIL 3 -#define TM_MAY 4 -#define TM_JUNE 5 -#define TM_JULY 6 -#define TM_AUGUST 7 -#define TM_SEPTEMBER 8 -#define TM_OCTOBER 9 -#define TM_NOVEMBER 10 -#define TM_DECEMBER 11 - -#define TM_YEAR_BASE 1900 - -#define EPOCH_YEAR 1970 -#define EPOCH_WDAY TM_THURSDAY +#define SECSPERMIN 60 +#define MINSPERHOUR 60 +#define HOURSPERDAY 24 +#define DAYSPERWEEK 7 +#define DAYSPERNYEAR 365 +#define DAYSPERLYEAR 366 +#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) +#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) +#define MONSPERYEAR 12 + +#define TM_SUNDAY 0 +#define TM_MONDAY 1 +#define TM_TUESDAY 2 +#define TM_WEDNESDAY 3 +#define TM_THURSDAY 4 +#define TM_FRIDAY 5 +#define TM_SATURDAY 6 + +#define TM_JANUARY 0 +#define TM_FEBRUARY 1 +#define TM_MARCH 2 +#define TM_APRIL 3 +#define TM_MAY 4 +#define TM_JUNE 5 +#define TM_JULY 6 +#define TM_AUGUST 7 +#define TM_SEPTEMBER 8 +#define TM_OCTOBER 9 +#define TM_NOVEMBER 10 +#define TM_DECEMBER 11 + +#define TM_YEAR_BASE 1900 + +#define EPOCH_YEAR 1970 +#define EPOCH_WDAY TM_THURSDAY #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) /* ** Since everything in isleap is modulo 400 (or a factor of 400), we know that -** isleap(y) == isleap(y % 400) +** isleap(y) == isleap(y % 400) ** and so -** isleap(a + b) == isleap((a + b) % 400) +** isleap(a + b) == isleap((a + b) % 400) ** or -** isleap(a + b) == isleap(a % 400 + b % 400) +** isleap(a + b) == isleap(a % 400 + b % 400) ** This is true even if % means modulo rather than Fortran remainder ** (which is allowed by C89 but not C99). ** We use this to avoid addition overflow problems. */ -#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) +#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) #endif /* !defined TZFILE_H */ diff --git a/libc/unistd/abort.c b/libc/unistd/abort.c index d4e40e1..3e3aab0 100644 --- a/libc/unistd/abort.c +++ b/libc/unistd/abort.c @@ -39,8 +39,13 @@ #define debug_log(format, ...) \ __libc_android_log_print(ANDROID_LOG_DEBUG, "libc-abort", (format), ##__VA_ARGS__ ) +#ifdef __arm__ +void +__libc_android_abort(void) +#else void abort(void) +#endif { struct atexit *p = __atexit; static int cleanup_called = 0; @@ -73,10 +78,8 @@ abort(void) } /* temporary, for bug hunting */ - debug_log("abort() called in pid %d\n", getpid()); /* seg fault seems to produce better debuggerd results than SIGABRT */ *((char*)0xdeadbaad) = 39; - debug_log("somehow we're not dead?\n"); /* -- */ (void)kill(getpid(), SIGABRT); @@ -99,3 +102,29 @@ abort(void) (void)kill(getpid(), SIGABRT); _exit(1); } + +#ifdef __arm__ +/* + * abort() does not return, which gcc interprets to mean that it doesn't + * need to preserve any of the callee-save registers. Unfortunately this + * includes the link register, so if LR is used there is no way to determine + * which function called abort(). + * + * We work around this by inserting a trivial stub that doesn't alter + * any of the "interesting" registers and thus doesn't need to save them. + * We can't just call __libc_android_abort from C because gcc uses "bl" + * without first saving LR, so we use an asm statement. This also has + * the side-effect of replacing abort() with __libc_android_abort() in + * the stack trace. + * + * Ideally __libc_android_abort would be static, but I haven't figured out + * how to tell gcc to call a static function from an asm statement. + */ +void +abort(void) +{ + asm ("b __libc_android_abort"); + _exit(1); /* suppress gcc noreturn warnings */ +} +#endif + diff --git a/libstdc++/include/cstring b/libstdc++/include/cstring index 4ff7a6f..80473cc 100644 --- a/libstdc++/include/cstring +++ b/libstdc++/include/cstring @@ -39,59 +39,28 @@ namespace std { -using ::memccpy; using ::memchr; -using ::memrchr; using ::memcmp; using ::memcpy; using ::memmove; using ::memset; -using ::memmem; -// In string.h but not part of the std -// using ::memswap; - -using ::index; -using ::rindex; +using ::strcat; using ::strchr; -using ::strrchr; - -using ::strlen; using ::strcmp; +using ::strcoll; using ::strcpy; -using ::strcat; - -using ::strcasecmp; -using ::strncasecmp; -using ::strdup; - -using ::strstr; -using ::strcasestr; -using ::strtok; -using ::strtok_r; - +using ::strcspn; using ::strerror; -using ::strerror_r; - -using ::strnlen; +using ::strlen; using ::strncat; -using ::strndup; using ::strncmp; using ::strncpy; - -// In string.h but not part of the std -// using ::strlcat; -// using ::strlcpy; - -using ::strcspn; using ::strpbrk; -using ::strsep; +using ::strrchr; using ::strspn; - -using ::strsignal; - -using ::strcoll; +using ::strstr; +using ::strtok; using ::strxfrm; - } // namespace std #endif // BIONIC_LIBSTDCPP_INCLUDE_CSTRING__ diff --git a/linker/ba.c b/linker/ba.c index bea6f84..db49c4b 100644 --- a/linker/ba.c +++ b/linker/ba.c @@ -30,65 +30,41 @@ #include "linker_debug.h" #include "ba.h" -struct ba_bits { - unsigned allocated:1; /* 1 if allocated, 0 if free */ - unsigned order:7; /* size of the region in ba space */ -}; - -struct ba_info { - /* start address of the ba space */ - unsigned long base; - /* total size of the ba space */ - unsigned long size; - /* number of entries in the ba space */ - int num_entries; - /* the bitmap for the region indicating which entries are allocated - * and which are free */ - struct ba_bits *bitmap; -}; - #undef min #define min(a,b) ((a)<(b)?(a):(b)) -#define BA_MIN_ALLOC LIBINC -#define BA_MAX_ORDER 128 -#define BA_START LIBBASE -#define BA_SIZE (LIBLAST - LIBBASE) - -#define BA_IS_FREE(index) (!(ba.bitmap[index].allocated)) -#define BA_ORDER(index) ba.bitmap[index].order +#define BA_IS_FREE(index) (!(ba->bitmap[index].allocated)) +#define BA_ORDER(index) ba->bitmap[index].order #define BA_BUDDY_INDEX(index) ((index) ^ (1 << BA_ORDER(index))) #define BA_NEXT_INDEX(index) ((index) + (1 << BA_ORDER(index))) -#define BA_OFFSET(index) ((index) * BA_MIN_ALLOC) -#define BA_START_ADDR(index) (BA_OFFSET(index) + ba.base) -#define BA_LEN(index) ((1 << BA_ORDER(index)) * BA_MIN_ALLOC) - -static struct ba_bits ba_bitmap[BA_SIZE / BA_MIN_ALLOC]; +#define BA_OFFSET(index) ((index) * ba->min_alloc) +#define BA_START_ADDR(index) (BA_OFFSET(index) + ba->base) +#define BA_LEN(index) ((1 << BA_ORDER(index)) * ba->min_alloc) -static struct ba_info ba = { - .base = BA_START, - .size = BA_SIZE, - .bitmap = ba_bitmap, - .num_entries = sizeof(ba_bitmap)/sizeof(ba_bitmap[0]), -}; +static unsigned long ba_order(struct ba *ba, unsigned long len); -void ba_init(void) +void ba_init(struct ba *ba) { int i, index = 0; - for (i = sizeof(ba.num_entries) * 8 - 1; i >= 0; i--) { - if (ba.num_entries & 1<<i) { + + unsigned long max_order = ba_order(ba, ba->size); + if (ba->max_order == 0 || ba->max_order > max_order) + ba->max_order = max_order; + + for (i = sizeof(ba->num_entries) * 8 - 1; i >= 0; i--) { + if (ba->num_entries & 1<<i) { BA_ORDER(index) = i; index = BA_NEXT_INDEX(index); } } } -int ba_free(int index) +int ba_free(struct ba *ba, int index) { int buddy, curr = index; /* clean up the bitmap, merging any buddies */ - ba.bitmap[curr].allocated = 0; + ba->bitmap[curr].allocated = 0; /* find a slots buddy Buddy# = Slot# ^ (1 << order) * if the buddy is also free merge them * repeat until the buddy is not free or end of the bitmap is reached @@ -103,16 +79,16 @@ int ba_free(int index) } else { break; } - } while (curr < ba.num_entries); + } while (curr < ba->num_entries); return 0; } -static unsigned long ba_order(unsigned long len) +static unsigned long ba_order(struct ba *ba, unsigned long len) { unsigned long i; - len = (len + BA_MIN_ALLOC - 1) / BA_MIN_ALLOC; + len = (len + ba->min_alloc - 1) / ba->min_alloc; len--; for (i = 0; i < sizeof(len)*8; i++) if (len >> i == 0) @@ -120,14 +96,14 @@ static unsigned long ba_order(unsigned long len) return i; } -int ba_allocate(unsigned long len) +int ba_allocate(struct ba *ba, unsigned long len) { int curr = 0; - int end = ba.num_entries; + int end = ba->num_entries; int best_fit = -1; - unsigned long order = ba_order(len); + unsigned long order = ba_order(ba, len); - if (order > BA_MAX_ORDER) + if (order > ba->max_order) return -1; /* look through the bitmap: @@ -165,16 +141,16 @@ int ba_allocate(unsigned long len) buddy = BA_BUDDY_INDEX(best_fit); BA_ORDER(buddy) = BA_ORDER(best_fit); } - ba.bitmap[best_fit].allocated = 1; + ba->bitmap[best_fit].allocated = 1; return best_fit; } -unsigned long ba_start_addr(int index) +unsigned long ba_start_addr(struct ba *ba, int index) { return BA_START_ADDR(index); } -unsigned long ba_len(int index) +unsigned long ba_len(struct ba *ba, int index) { return BA_LEN(index); } diff --git a/linker/ba.h b/linker/ba.h index 78f4626..c11017b 100644 --- a/linker/ba.h +++ b/linker/ba.h @@ -29,10 +29,31 @@ #ifndef __LINKER_BA_H #define __LINKER_BA_H -extern void ba_init(void); -extern int ba_allocate(unsigned long len); -extern int ba_free(int index); -extern unsigned long ba_start_addr(int index); -extern unsigned long ba_len(int index); +struct ba_bits { + unsigned allocated:1; /* 1 if allocated, 0 if free */ + unsigned order:7; /* size of the region in ba space */ +}; + +struct ba { + /* start address of the ba space */ + unsigned long base; + /* total size of the ba space */ + unsigned long size; + /* the smaller allocation that can be made */ + unsigned long min_alloc; + /* the order of the largest allocation that can be made */ + unsigned long max_order; + /* number of entries in the ba space */ + int num_entries; + /* the bitmap for the region indicating which entries are allocated + * and which are free */ + struct ba_bits *bitmap; +}; + +extern void ba_init(struct ba *ba); +extern int ba_allocate(struct ba *ba, unsigned long len); +extern int ba_free(struct ba *ba, int index); +extern unsigned long ba_start_addr(struct ba *ba, int index); +extern unsigned long ba_len(struct ba *ba, int index); #endif diff --git a/linker/dlfcn.c b/linker/dlfcn.c index b54674f..053713c 100644 --- a/linker/dlfcn.c +++ b/linker/dlfcn.c @@ -74,7 +74,7 @@ const char *dlerror(void) void *dlsym(void *handle, const char *symbol) { - unsigned base; + soinfo *found; Elf32_Sym *sym; unsigned bind; @@ -90,19 +90,19 @@ void *dlsym(void *handle, const char *symbol) } if(handle == RTLD_DEFAULT) { - sym = lookup(symbol, &base); + sym = lookup(symbol, &found); } else if(handle == RTLD_NEXT) { - sym = lookup(symbol, &base); + sym = lookup(symbol, &found); } else { - sym = lookup_in_library((soinfo*) handle, symbol); - base = ((soinfo*) handle)->base; + found = (soinfo*)handle; + sym = lookup_in_library(found, symbol); } if(likely(sym != 0)) { bind = ELF32_ST_BIND(sym->st_info); if(likely((bind == STB_GLOBAL) && (sym->st_shndx != 0))) { - unsigned ret = sym->st_value + base; + unsigned ret = sym->st_value + found->base; pthread_mutex_unlock(&dl_lock); return (void*)ret; } diff --git a/linker/linker.c b/linker/linker.c index 789a828..5090b11 100644 --- a/linker/linker.c +++ b/linker/linker.c @@ -51,6 +51,7 @@ #include "ba.h" +#define ALLOW_SYMBOLS_FROM_MAIN 1 #define SO_MAX 96 /* Assume average path length of 64 and max 8 paths */ @@ -86,6 +87,27 @@ static soinfo sopool[SO_MAX]; static soinfo *freelist = NULL; static soinfo *solist = &libdl_info; static soinfo *sonext = &libdl_info; +#if ALLOW_SYMBOLS_FROM_MAIN +static soinfo *somain; /* main process, always the one after libdl_info */ +#endif + + +/* Set up for the buddy allocator managing the prelinked libraries. */ +static struct ba_bits ba_prelink_bitmap[(LIBLAST - LIBBASE) / LIBINC]; +static struct ba ba_prelink = { + .base = LIBBASE, + .size = LIBLAST - LIBBASE, + .min_alloc = LIBINC, + /* max_order will be determined automatically */ + .bitmap = ba_prelink_bitmap, + .num_entries = sizeof(ba_prelink_bitmap)/sizeof(ba_prelink_bitmap[0]), +}; + +static inline int validate_soinfo(soinfo *si) +{ + return (si >= sopool && si < sopool + SO_MAX) || + si == &libdl_info; +} static char ldpaths_buf[LDPATH_BUFSIZE]; static const char *ldpaths[LDPATH_MAX + 1]; @@ -421,41 +443,92 @@ _do_lookup_in_so(soinfo *si, const char *name, unsigned *elf_hash) return _elf_lookup (si, *elf_hash, name); } -/* This is used by dl_sym() */ +static Elf32_Sym * +_do_lookup(soinfo *si, const char *name, unsigned *base) +{ + unsigned elf_hash = 0; + Elf32_Sym *s; + unsigned *d; + soinfo *lsi = si; + + /* Look for symbols in the local scope first (the object who is + * searching). This happens with C++ templates on i386 for some + * reason. */ + s = _do_lookup_in_so(si, name, &elf_hash); + if(s != NULL) + goto done; + + for(d = si->dynamic; *d; d += 2) { + if(d[0] == DT_NEEDED){ + lsi = (soinfo *)d[1]; + if (!validate_soinfo(lsi)) { + DL_ERR("%5d bad DT_NEEDED pointer in %s", + pid, si->name); + return 0; + } + + DEBUG("%5d %s: looking up %s in %s\n", + pid, si->name, name, lsi->name); + s = _do_lookup_in_so(lsi, name, &elf_hash); + if(s != NULL) + goto done; + } + } + +#if ALLOW_SYMBOLS_FROM_MAIN + /* If we are resolving relocations while dlopen()ing a library, it's OK for + * the library to resolve a symbol that's defined in the executable itself, + * although this is rare and is generally a bad idea. + */ + if (somain) { + lsi = somain; + DEBUG("%5d %s: looking up %s in executable %s\n", + pid, si->name, name, lsi->name); + s = _do_lookup_in_so(lsi, name, &elf_hash); + } +#endif + +done: + if(s != NULL) { + TRACE_TYPE(LOOKUP, "%5d si %s sym %s s->st_value = 0x%08x, " + "found in %s, base = 0x%08x\n", + pid, si->name, name, s->st_value, lsi->name, lsi->base); + *base = lsi->base; + return s; + } + + return 0; +} + +/* This is used by dl_sym(). It performs symbol lookup only within the + specified soinfo object and not in any of its dependencies. + */ Elf32_Sym *lookup_in_library(soinfo *si, const char *name) { unsigned unused = 0; return _do_lookup_in_so(si, name, &unused); } -static Elf32_Sym * -_do_lookup(soinfo *user_si, const char *name, unsigned *base) +/* This is used by dl_sym(). It performs a global symbol lookup. + */ +Elf32_Sym *lookup(const char *name, soinfo **found) { unsigned elf_hash = 0; Elf32_Sym *s = NULL; soinfo *si; - /* Look for symbols in the local scope first (the object who is - * searching). This happens with C++ templates on i386 for some - * reason. */ - if (user_si) { - s = _do_lookup_in_so(user_si, name, &elf_hash); - if (s != NULL) - *base = user_si->base; - } - for(si = solist; (s == NULL) && (si != NULL); si = si->next) { - if((si->flags & FLAG_ERROR) || (si == user_si)) + if(si->flags & FLAG_ERROR) continue; s = _do_lookup_in_so(si, name, &elf_hash); if (s != NULL) { - *base = si->base; + *found = si; break; } } - if (s != NULL) { + if(s != NULL) { TRACE_TYPE(LOOKUP, "%5d %s s->st_value = 0x%08x, " "si->base = 0x%08x\n", pid, name, s->st_value, si->base); return s; @@ -464,12 +537,6 @@ _do_lookup(soinfo *user_si, const char *name, unsigned *base) return 0; } -/* This is used by dl_sym() */ -Elf32_Sym *lookup(const char *name, unsigned *base) -{ - return _do_lookup(NULL, name, base); -} - #if 0 static void dump(soinfo *si) { @@ -728,14 +795,14 @@ alloc_mem_region(soinfo *si) for it from the buddy allocator, which manages the area between LIBBASE and LIBLAST. */ - si->ba_index = ba_allocate(si->size); + si->ba_index = ba_allocate(&ba_prelink, si->size); if(si->ba_index >= 0) { - si->base = ba_start_addr(si->ba_index); + si->base = ba_start_addr(&ba_prelink, si->ba_index); PRINT("%5d mapping library '%s' at %08x (index %d) " \ "through buddy allocator.\n", pid, si->name, si->base, si->ba_index); if (reserve_mem_region(si) < 0) { - ba_free(si->ba_index); + ba_free(&ba_prelink, si->ba_index); si->ba_index = -1; si->base = 0; goto err; @@ -1031,7 +1098,7 @@ load_library(const char *name) /* Now actually load the library's segments into right places in memory */ if (load_segments(fd, &__header[0], si) < 0) { if (si->ba_index >= 0) { - ba_free(si->ba_index); + ba_free(&ba_prelink, si->ba_index); si->ba_index = -1; } goto fail; @@ -1085,7 +1152,10 @@ soinfo *find_library(const char *name) for(si = solist; si != 0; si = si->next){ if(!strcmp(bname, si->name)) { - if(si->flags & FLAG_ERROR) return 0; + if(si->flags & FLAG_ERROR) { + DL_ERR("%5d '%s' failed to load previously", pid, bname); + return NULL; + } if(si->flags & FLAG_LINKED) return si; DL_ERR("OOPS: %5d recursive link to '%s'", pid, si->name); return NULL; @@ -1113,14 +1183,16 @@ unsigned unload_library(soinfo *si) for(d = si->dynamic; *d; d += 2) { if(d[0] == DT_NEEDED){ - TRACE("%5d %s needs to unload %s\n", pid, - si->name, si->strtab + d[1]); - soinfo *lsi = find_library(si->strtab + d[1]); - if(lsi) + soinfo *lsi = (soinfo *)d[1]; + d[1] = 0; + if (validate_soinfo(lsi)) { + TRACE("%5d %s needs to unload %s\n", pid, + si->name, lsi->name); unload_library(lsi); + } else - DL_ERR("%5d could not unload '%s'", - pid, si->strtab + d[1]); + DL_ERR("%5d %s: could not unload dependent library", + pid, si->name); } } @@ -1129,7 +1201,7 @@ unsigned unload_library(soinfo *si) PRINT("%5d releasing library '%s' address space at %08x "\ "through buddy allocator.\n", pid, si->name, si->base); - ba_free(si->ba_index); + ba_free(&ba_prelink, si->ba_index); } notify_gdb_of_unload(si); free_info(si); @@ -1180,9 +1252,13 @@ static int reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count) return -1; } #endif - if ((s->st_shndx == SHN_UNDEF) && (s->st_value != 0)) { - DL_ERR("%5d In '%s', shndx=%d && value=0x%08x. We do not " - "handle this yet", pid, si->name, s->st_shndx, + // st_shndx==SHN_UNDEF means an undefined symbol. + // st_value should be 0 then, except that the low bit of st_value is + // used to indicate whether the symbol points to an ARM or thumb function, + // and should be ignored in the following check. + if ((s->st_shndx == SHN_UNDEF) && ((s->st_value & ~1) != 0)) { + DL_ERR("%5d In '%s', symbol=%s shndx=%d && value=0x%08x. We do not " + "handle this yet", pid, si->name, sym_name, s->st_shndx, s->st_value); return -1; } @@ -1638,6 +1714,14 @@ static int link_image(soinfo *si, unsigned wr_offset) pid, si->strtab + d[1], si->name, tmp_err_buf); goto fail; } + /* Save the soinfo of the loaded DT_NEEDED library in the payload + of the DT_NEEDED entry itself, so that we can retrieve the + soinfo directly later from the dynamic segment. This is a hack, + but it allows us to map from DT_NEEDED to soinfo efficiently + later on when we resolve relocations, trying to look up a symgol + with dlsym(). + */ + d[1] = (unsigned)lsi; lsi->refcount++; } } @@ -1825,7 +1909,7 @@ unsigned __linker_init(unsigned **elfdata) vecs += 2; } - ba_init(); + ba_init(&ba_prelink); si->base = 0; si->dynamic = (unsigned *)-1; @@ -1843,6 +1927,14 @@ unsigned __linker_init(unsigned **elfdata) exit(-1); } +#if ALLOW_SYMBOLS_FROM_MAIN + /* Set somain after we've loaded all the libraries in order to prevent + * linking of symbols back to the main image, which is not set up at that + * point yet. + */ + somain = si; +#endif + #if TIMING gettimeofday(&t1,NULL); PRINT("LINKER TIME: %s: %d microseconds\n", argv[0], (int) ( diff --git a/linker/linker.h b/linker/linker.h index 69042c0..d289c81 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -203,7 +203,7 @@ extern soinfo libdl_info; soinfo *find_library(const char *name); unsigned unload_library(soinfo *si); Elf32_Sym *lookup_in_library(soinfo *si, const char *name); -Elf32_Sym *lookup(const char *name, unsigned *base); +Elf32_Sym *lookup(const char *name, soinfo **found); const char *linker_get_error(void); #ifdef ANDROID_ARM_LINKER |