openldap-2.5.11+dfsg/0000755000175000017500000000000014172327167013037 5ustar ryanryanopenldap-2.5.11+dfsg/libraries/0000755000175000017500000000000014172327167015013 5ustar ryanryanopenldap-2.5.11+dfsg/libraries/liblmdb/0000755000175000017500000000000014172327167016420 5ustar ryanryanopenldap-2.5.11+dfsg/libraries/liblmdb/mdb_load.c0000644000175000017500000002651614172327167020337 0ustar ryanryan/* mdb_load.c - memory-mapped database load tool */ /* * Copyright 2011-2021 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include #include #include #include #include #include #include "lmdb.h" #define PRINT 1 #define NOHDR 2 static int mode; static char *subname = NULL; static size_t lineno; static int version; static int flags; static char *prog; static int Eof; static MDB_envinfo info; static MDB_val kbuf, dbuf; static MDB_val k0buf; #ifdef _WIN32 #define Z "I" #else #define Z "z" #endif #define STRLENOF(s) (sizeof(s)-1) typedef struct flagbit { int bit; char *name; int len; } flagbit; #define S(s) s, STRLENOF(s) flagbit dbflags[] = { { MDB_REVERSEKEY, S("reversekey") }, { MDB_DUPSORT, S("dupsort") }, { MDB_INTEGERKEY, S("integerkey") }, { MDB_DUPFIXED, S("dupfixed") }, { MDB_INTEGERDUP, S("integerdup") }, { MDB_REVERSEDUP, S("reversedup") }, { 0, NULL, 0 } }; static void readhdr(void) { char *ptr; flags = 0; while (fgets(dbuf.mv_data, dbuf.mv_size, stdin) != NULL) { lineno++; if (!strncmp(dbuf.mv_data, "VERSION=", STRLENOF("VERSION="))) { version=atoi((char *)dbuf.mv_data+STRLENOF("VERSION=")); if (version > 3) { fprintf(stderr, "%s: line %" Z "d: unsupported VERSION %d\n", prog, lineno, version); exit(EXIT_FAILURE); } } else if (!strncmp(dbuf.mv_data, "HEADER=END", STRLENOF("HEADER=END"))) { break; } else if (!strncmp(dbuf.mv_data, "format=", STRLENOF("format="))) { if (!strncmp((char *)dbuf.mv_data+STRLENOF("FORMAT="), "print", STRLENOF("print"))) mode |= PRINT; else if (strncmp((char *)dbuf.mv_data+STRLENOF("FORMAT="), "bytevalue", STRLENOF("bytevalue"))) { fprintf(stderr, "%s: line %" Z "d: unsupported FORMAT %s\n", prog, lineno, (char *)dbuf.mv_data+STRLENOF("FORMAT=")); exit(EXIT_FAILURE); } } else if (!strncmp(dbuf.mv_data, "database=", STRLENOF("database="))) { ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size); if (ptr) *ptr = '\0'; if (subname) free(subname); subname = strdup((char *)dbuf.mv_data+STRLENOF("database=")); } else if (!strncmp(dbuf.mv_data, "type=", STRLENOF("type="))) { if (strncmp((char *)dbuf.mv_data+STRLENOF("type="), "btree", STRLENOF("btree"))) { fprintf(stderr, "%s: line %" Z "d: unsupported type %s\n", prog, lineno, (char *)dbuf.mv_data+STRLENOF("type=")); exit(EXIT_FAILURE); } } else if (!strncmp(dbuf.mv_data, "mapaddr=", STRLENOF("mapaddr="))) { int i; ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size); if (ptr) *ptr = '\0'; i = sscanf((char *)dbuf.mv_data+STRLENOF("mapaddr="), "%p", &info.me_mapaddr); if (i != 1) { fprintf(stderr, "%s: line %" Z "d: invalid mapaddr %s\n", prog, lineno, (char *)dbuf.mv_data+STRLENOF("mapaddr=")); exit(EXIT_FAILURE); } } else if (!strncmp(dbuf.mv_data, "mapsize=", STRLENOF("mapsize="))) { int i; ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size); if (ptr) *ptr = '\0'; i = sscanf((char *)dbuf.mv_data+STRLENOF("mapsize="), "%" Z "u", &info.me_mapsize); if (i != 1) { fprintf(stderr, "%s: line %" Z "d: invalid mapsize %s\n", prog, lineno, (char *)dbuf.mv_data+STRLENOF("mapsize=")); exit(EXIT_FAILURE); } } else if (!strncmp(dbuf.mv_data, "maxreaders=", STRLENOF("maxreaders="))) { int i; ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size); if (ptr) *ptr = '\0'; i = sscanf((char *)dbuf.mv_data+STRLENOF("maxreaders="), "%u", &info.me_maxreaders); if (i != 1) { fprintf(stderr, "%s: line %" Z "d: invalid maxreaders %s\n", prog, lineno, (char *)dbuf.mv_data+STRLENOF("maxreaders=")); exit(EXIT_FAILURE); } } else { int i; for (i=0; dbflags[i].bit; i++) { if (!strncmp(dbuf.mv_data, dbflags[i].name, dbflags[i].len) && ((char *)dbuf.mv_data)[dbflags[i].len] == '=') { flags |= dbflags[i].bit; break; } } if (!dbflags[i].bit) { ptr = memchr(dbuf.mv_data, '=', dbuf.mv_size); if (!ptr) { fprintf(stderr, "%s: line %" Z "d: unexpected format\n", prog, lineno); exit(EXIT_FAILURE); } else { *ptr = '\0'; fprintf(stderr, "%s: line %" Z "d: unrecognized keyword ignored: %s\n", prog, lineno, (char *)dbuf.mv_data); } } } } } static void badend(void) { fprintf(stderr, "%s: line %" Z "d: unexpected end of input\n", prog, lineno); } static int unhex(unsigned char *c2) { int x, c; x = *c2++ & 0x4f; if (x & 0x40) x -= 55; c = x << 4; x = *c2 & 0x4f; if (x & 0x40) x -= 55; c |= x; return c; } static int readline(MDB_val *out, MDB_val *buf) { unsigned char *c1, *c2, *end; size_t len, l2; int c; if (!(mode & NOHDR)) { c = fgetc(stdin); if (c == EOF) { Eof = 1; return EOF; } if (c != ' ') { lineno++; if (fgets(buf->mv_data, buf->mv_size, stdin) == NULL) { badend: Eof = 1; badend(); return EOF; } if (c == 'D' && !strncmp(buf->mv_data, "ATA=END", STRLENOF("ATA=END"))) return EOF; goto badend; } } if (fgets(buf->mv_data, buf->mv_size, stdin) == NULL) { Eof = 1; return EOF; } lineno++; c1 = buf->mv_data; len = strlen((char *)c1); l2 = len; /* Is buffer too short? */ while (c1[len-1] != '\n') { buf->mv_data = realloc(buf->mv_data, buf->mv_size*2); if (!buf->mv_data) { Eof = 1; fprintf(stderr, "%s: line %" Z "d: out of memory, line too long\n", prog, lineno); return EOF; } c1 = buf->mv_data; c1 += l2; if (fgets((char *)c1, buf->mv_size+1, stdin) == NULL) { Eof = 1; badend(); return EOF; } buf->mv_size *= 2; len = strlen((char *)c1); l2 += len; } c1 = c2 = buf->mv_data; len = l2; c1[--len] = '\0'; end = c1 + len; if (mode & PRINT) { while (c2 < end) { if (*c2 == '\\') { if (c2[1] == '\\') { *c1++ = *c2; } else { if (c2+3 > end || !isxdigit(c2[1]) || !isxdigit(c2[2])) { Eof = 1; badend(); return EOF; } *c1++ = unhex(++c2); } c2 += 2; } else { /* copies are redundant when no escapes were used */ *c1++ = *c2++; } } } else { /* odd length not allowed */ if (len & 1) { Eof = 1; badend(); return EOF; } while (c2 < end) { if (!isxdigit(*c2) || !isxdigit(c2[1])) { Eof = 1; badend(); return EOF; } *c1++ = unhex(c2); c2 += 2; } } c2 = out->mv_data = buf->mv_data; out->mv_size = c1 - c2; return 0; } static void usage(void) { fprintf(stderr, "usage: %s [-V] [-a] [-f input] [-n] [-s name] [-N] [-T] dbpath\n", prog); exit(EXIT_FAILURE); } static int greater(const MDB_val *a, const MDB_val *b) { return 1; } int main(int argc, char *argv[]) { int i, rc; MDB_env *env; MDB_txn *txn; MDB_cursor *mc; MDB_dbi dbi; char *envname; int envflags = MDB_NOSYNC, putflags = 0; int dohdr = 0, append = 0; MDB_val prevk; prog = argv[0]; if (argc < 2) { usage(); } /* -a: append records in input order * -f: load file instead of stdin * -n: use NOSUBDIR flag on env_open * -s: load into named subDB * -N: use NOOVERWRITE on puts * -T: read plaintext * -V: print version and exit */ while ((i = getopt(argc, argv, "af:ns:NTV")) != EOF) { switch(i) { case 'V': printf("%s\n", MDB_VERSION_STRING); exit(0); break; case 'a': append = 1; break; case 'f': if (freopen(optarg, "r", stdin) == NULL) { fprintf(stderr, "%s: %s: reopen: %s\n", prog, optarg, strerror(errno)); exit(EXIT_FAILURE); } break; case 'n': envflags |= MDB_NOSUBDIR; break; case 's': subname = strdup(optarg); break; case 'N': putflags = MDB_NOOVERWRITE|MDB_NODUPDATA; break; case 'T': mode |= NOHDR | PRINT; break; default: usage(); } } if (optind != argc - 1) usage(); dbuf.mv_size = 4096; dbuf.mv_data = malloc(dbuf.mv_size); if (!(mode & NOHDR)) readhdr(); envname = argv[optind]; rc = mdb_env_create(&env); if (rc) { fprintf(stderr, "mdb_env_create failed, error %d %s\n", rc, mdb_strerror(rc)); return EXIT_FAILURE; } mdb_env_set_maxdbs(env, 2); if (info.me_maxreaders) mdb_env_set_maxreaders(env, info.me_maxreaders); if (info.me_mapsize) mdb_env_set_mapsize(env, info.me_mapsize); if (info.me_mapaddr) envflags |= MDB_FIXEDMAP; rc = mdb_env_open(env, envname, envflags, 0664); if (rc) { fprintf(stderr, "mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc)); goto env_close; } kbuf.mv_size = mdb_env_get_maxkeysize(env) * 2 + 2; kbuf.mv_data = malloc(kbuf.mv_size * 2); k0buf.mv_size = kbuf.mv_size; k0buf.mv_data = (char *)kbuf.mv_data + kbuf.mv_size; prevk.mv_data = k0buf.mv_data; while(!Eof) { MDB_val key, data; int batch = 0; flags = 0; int appflag; if (!dohdr) { dohdr = 1; } else if (!(mode & NOHDR)) readhdr(); rc = mdb_txn_begin(env, NULL, 0, &txn); if (rc) { fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc)); goto env_close; } rc = mdb_open(txn, subname, flags|MDB_CREATE, &dbi); if (rc) { fprintf(stderr, "mdb_open failed, error %d %s\n", rc, mdb_strerror(rc)); goto txn_abort; } prevk.mv_size = 0; if (append) { mdb_set_compare(txn, dbi, greater); if (flags & MDB_DUPSORT) mdb_set_dupsort(txn, dbi, greater); } rc = mdb_cursor_open(txn, dbi, &mc); if (rc) { fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc)); goto txn_abort; } while(1) { rc = readline(&key, &kbuf); if (rc) /* rc == EOF */ break; rc = readline(&data, &dbuf); if (rc) { fprintf(stderr, "%s: line %" Z "d: failed to read key value\n", prog, lineno); goto txn_abort; } if (append) { appflag = MDB_APPEND; if (flags & MDB_DUPSORT) { if (prevk.mv_size == key.mv_size && !memcmp(prevk.mv_data, key.mv_data, key.mv_size)) appflag = MDB_CURRENT|MDB_APPENDDUP; else { memcpy(prevk.mv_data, key.mv_data, key.mv_size); prevk.mv_size = key.mv_size; } } } else { appflag = 0; } rc = mdb_cursor_put(mc, &key, &data, putflags|appflag); if (rc == MDB_KEYEXIST && putflags) continue; if (rc) { fprintf(stderr, "mdb_cursor_put failed, error %d %s\n", rc, mdb_strerror(rc)); goto txn_abort; } batch++; if (batch == 100) { rc = mdb_txn_commit(txn); if (rc) { fprintf(stderr, "%s: line %" Z "d: txn_commit: %s\n", prog, lineno, mdb_strerror(rc)); goto env_close; } rc = mdb_txn_begin(env, NULL, 0, &txn); if (rc) { fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc)); goto env_close; } rc = mdb_cursor_open(txn, dbi, &mc); if (rc) { fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc)); goto txn_abort; } if (appflag & MDB_APPENDDUP) { MDB_val k, d; mdb_cursor_get(mc, &k, &d, MDB_LAST); } batch = 0; } } rc = mdb_txn_commit(txn); txn = NULL; if (rc) { fprintf(stderr, "%s: line %" Z "d: txn_commit: %s\n", prog, lineno, mdb_strerror(rc)); goto env_close; } mdb_dbi_close(env, dbi); } txn_abort: mdb_txn_abort(txn); env_close: mdb_env_close(env); return rc ? EXIT_FAILURE : EXIT_SUCCESS; } openldap-2.5.11+dfsg/libraries/liblmdb/mdb.c0000644000175000017500000107136114172327167017337 0ustar ryanryan/** @file mdb.c * @brief Lightning memory-mapped database library * * A Btree-based database management library modeled loosely on the * BerkeleyDB API, but much simplified. */ /* * Copyright 2011-2021 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . * * This code is derived from btree.c written by Martin Hedenfalk. * * Copyright (c) 2009, 2010 Martin Hedenfalk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #if defined(__WIN64__) #define _FILE_OFFSET_BITS 64 #endif #ifdef _WIN32 #include #include #include /* get wcscpy() */ /** getpid() returns int; MinGW defines pid_t but MinGW64 typedefs it * as int64 which is wrong. MSVC doesn't define it at all, so just * don't use it. */ #define MDB_PID_T int #define MDB_THR_T DWORD #include #include #ifdef __GNUC__ # include #else # define LITTLE_ENDIAN 1234 # define BIG_ENDIAN 4321 # define BYTE_ORDER LITTLE_ENDIAN # ifndef SSIZE_MAX # define SSIZE_MAX INT_MAX # endif #endif #else #include #include #define MDB_PID_T pid_t #define MDB_THR_T pthread_t #include #include #include #ifdef HAVE_SYS_FILE_H #include #endif #include #endif #if defined(__mips) && defined(__linux) /* MIPS has cache coherency issues, requires explicit cache control */ #include extern int cacheflush(char *addr, int nbytes, int cache); #define CACHEFLUSH(addr, bytes, cache) cacheflush(addr, bytes, cache) #else #define CACHEFLUSH(addr, bytes, cache) #endif #if defined(__linux) && !defined(MDB_FDATASYNC_WORKS) /** fdatasync is broken on ext3/ext4fs on older kernels, see * description in #mdb_env_open2 comments. You can safely * define MDB_FDATASYNC_WORKS if this code will only be run * on kernels 3.6 and newer. */ #define BROKEN_FDATASYNC #endif #include #include #include #include #include #include #include #include #ifdef _MSC_VER #include typedef SSIZE_T ssize_t; #else #include #endif #if defined(__sun) || defined(ANDROID) /* Most platforms have posix_memalign, older may only have memalign */ #define HAVE_MEMALIGN 1 #include /* On Solaris, we need the POSIX sigwait function */ #if defined (__sun) # define _POSIX_PTHREAD_SEMANTICS 1 #endif #endif #if !(defined(BYTE_ORDER) || defined(__BYTE_ORDER)) #include #include /* defines BYTE_ORDER on HPUX and Solaris */ #endif #if defined(__FreeBSD__) && defined(__FreeBSD_version) && __FreeBSD_version >= 1100110 # define MDB_USE_POSIX_MUTEX 1 # define MDB_USE_ROBUST 1 #elif defined(__APPLE__) || defined (BSD) || defined(__FreeBSD_kernel__) # define MDB_USE_POSIX_SEM 1 # define MDB_FDATASYNC fsync #elif defined(ANDROID) # define MDB_FDATASYNC fsync #endif #ifndef _WIN32 #include #include #ifdef MDB_USE_POSIX_SEM # define MDB_USE_HASH 1 #include #else #define MDB_USE_POSIX_MUTEX 1 #endif #endif #if defined(_WIN32) + defined(MDB_USE_POSIX_SEM) \ + defined(MDB_USE_POSIX_MUTEX) != 1 # error "Ambiguous shared-lock implementation" #endif #ifdef USE_VALGRIND #include #define VGMEMP_CREATE(h,r,z) VALGRIND_CREATE_MEMPOOL(h,r,z) #define VGMEMP_ALLOC(h,a,s) VALGRIND_MEMPOOL_ALLOC(h,a,s) #define VGMEMP_FREE(h,a) VALGRIND_MEMPOOL_FREE(h,a) #define VGMEMP_DESTROY(h) VALGRIND_DESTROY_MEMPOOL(h) #define VGMEMP_DEFINED(a,s) VALGRIND_MAKE_MEM_DEFINED(a,s) #else #define VGMEMP_CREATE(h,r,z) #define VGMEMP_ALLOC(h,a,s) #define VGMEMP_FREE(h,a) #define VGMEMP_DESTROY(h) #define VGMEMP_DEFINED(a,s) #endif #ifndef BYTE_ORDER # if (defined(_LITTLE_ENDIAN) || defined(_BIG_ENDIAN)) && !(defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)) /* Solaris just defines one or the other */ # define LITTLE_ENDIAN 1234 # define BIG_ENDIAN 4321 # ifdef _LITTLE_ENDIAN # define BYTE_ORDER LITTLE_ENDIAN # else # define BYTE_ORDER BIG_ENDIAN # endif # else # define BYTE_ORDER __BYTE_ORDER # endif #endif #ifndef LITTLE_ENDIAN #define LITTLE_ENDIAN __LITTLE_ENDIAN #endif #ifndef BIG_ENDIAN #define BIG_ENDIAN __BIG_ENDIAN #endif #if defined(__i386) || defined(__x86_64) || defined(_M_IX86) #define MISALIGNED_OK 1 #endif #include "lmdb.h" #include "midl.h" #if (BYTE_ORDER == LITTLE_ENDIAN) == (BYTE_ORDER == BIG_ENDIAN) # error "Unknown or unsupported endianness (BYTE_ORDER)" #elif (-6 & 5) || CHAR_BIT != 8 || UINT_MAX < 0xffffffff || ULONG_MAX % 0xFFFF # error "Two's complement, reasonably sized integer types, please" #endif #ifdef __GNUC__ /** Put infrequently used env functions in separate section */ # ifdef __APPLE__ # define ESECT __attribute__ ((section("__TEXT,text_env"))) # else # define ESECT __attribute__ ((section("text_env"))) # endif #else #define ESECT #endif #ifdef _WIN32 #define CALL_CONV WINAPI #else #define CALL_CONV #endif /** @defgroup internal LMDB Internals * @{ */ /** @defgroup compat Compatibility Macros * A bunch of macros to minimize the amount of platform-specific ifdefs * needed throughout the rest of the code. When the features this library * needs are similar enough to POSIX to be hidden in a one-or-two line * replacement, this macro approach is used. * @{ */ /** Features under development */ #ifndef MDB_DEVEL #define MDB_DEVEL 0 #endif /** Wrapper around __func__, which is a C99 feature */ #if __STDC_VERSION__ >= 199901L # define mdb_func_ __func__ #elif __GNUC__ >= 2 || _MSC_VER >= 1300 # define mdb_func_ __FUNCTION__ #else /* If a debug message says (), update the #if statements above */ # define mdb_func_ "" #endif /* Internal error codes, not exposed outside liblmdb */ #define MDB_NO_ROOT (MDB_LAST_ERRCODE + 10) #ifdef _WIN32 #define MDB_OWNERDEAD ((int) WAIT_ABANDONED) #elif defined(MDB_USE_POSIX_MUTEX) && defined(EOWNERDEAD) #define MDB_OWNERDEAD EOWNERDEAD /**< #LOCK_MUTEX0() result if dead owner */ #endif #ifdef __GLIBC__ #define GLIBC_VER ((__GLIBC__ << 16 )| __GLIBC_MINOR__) #endif /** Some platforms define the EOWNERDEAD error code * even though they don't support Robust Mutexes. * Compile with -DMDB_USE_ROBUST=0, or use some other * mechanism like -DMDB_USE_POSIX_SEM instead of * -DMDB_USE_POSIX_MUTEX. * (Posix semaphores are not robust.) */ #ifndef MDB_USE_ROBUST /* Android currently lacks Robust Mutex support. So does glibc < 2.4. */ # if defined(MDB_USE_POSIX_MUTEX) && (defined(ANDROID) || \ (defined(__GLIBC__) && GLIBC_VER < 0x020004)) # define MDB_USE_ROBUST 0 # else # define MDB_USE_ROBUST 1 # endif #endif /* !MDB_USE_ROBUST */ #if defined(MDB_USE_POSIX_MUTEX) && (MDB_USE_ROBUST) /* glibc < 2.12 only provided _np API */ # if (defined(__GLIBC__) && GLIBC_VER < 0x02000c) || \ (defined(PTHREAD_MUTEX_ROBUST_NP) && !defined(PTHREAD_MUTEX_ROBUST)) # define PTHREAD_MUTEX_ROBUST PTHREAD_MUTEX_ROBUST_NP # define pthread_mutexattr_setrobust(attr, flag) pthread_mutexattr_setrobust_np(attr, flag) # define pthread_mutex_consistent(mutex) pthread_mutex_consistent_np(mutex) # endif #endif /* MDB_USE_POSIX_MUTEX && MDB_USE_ROBUST */ #if defined(MDB_OWNERDEAD) && (MDB_USE_ROBUST) #define MDB_ROBUST_SUPPORTED 1 #endif #ifdef _WIN32 #define MDB_USE_HASH 1 #define MDB_PIDLOCK 0 #define THREAD_RET DWORD #define pthread_t HANDLE #define pthread_mutex_t HANDLE #define pthread_cond_t HANDLE typedef HANDLE mdb_mutex_t, mdb_mutexref_t; #define pthread_key_t DWORD #define pthread_self() GetCurrentThreadId() #define pthread_key_create(x,y) \ ((*(x) = TlsAlloc()) == TLS_OUT_OF_INDEXES ? ErrCode() : 0) #define pthread_key_delete(x) TlsFree(x) #define pthread_getspecific(x) TlsGetValue(x) #define pthread_setspecific(x,y) (TlsSetValue(x,y) ? 0 : ErrCode()) #define pthread_mutex_unlock(x) ReleaseMutex(*x) #define pthread_mutex_lock(x) WaitForSingleObject(*x, INFINITE) #define pthread_cond_signal(x) SetEvent(*x) #define pthread_cond_wait(cond,mutex) do{SignalObjectAndWait(*mutex, *cond, INFINITE, FALSE); WaitForSingleObject(*mutex, INFINITE);}while(0) #define THREAD_CREATE(thr,start,arg) \ (((thr) = CreateThread(NULL, 0, start, arg, 0, NULL)) ? 0 : ErrCode()) #define THREAD_FINISH(thr) \ (WaitForSingleObject(thr, INFINITE) ? ErrCode() : 0) #define LOCK_MUTEX0(mutex) WaitForSingleObject(mutex, INFINITE) #define UNLOCK_MUTEX(mutex) ReleaseMutex(mutex) #define mdb_mutex_consistent(mutex) 0 #define getpid() GetCurrentProcessId() #define MDB_FDATASYNC(fd) (!FlushFileBuffers(fd)) #define MDB_MSYNC(addr,len,flags) (!FlushViewOfFile(addr,len)) #define ErrCode() GetLastError() #define GET_PAGESIZE(x) {SYSTEM_INFO si; GetSystemInfo(&si); (x) = si.dwPageSize;} #define close(fd) (CloseHandle(fd) ? 0 : -1) #define munmap(ptr,len) UnmapViewOfFile(ptr) #ifdef PROCESS_QUERY_LIMITED_INFORMATION #define MDB_PROCESS_QUERY_LIMITED_INFORMATION PROCESS_QUERY_LIMITED_INFORMATION #else #define MDB_PROCESS_QUERY_LIMITED_INFORMATION 0x1000 #endif #define Z "I" #else #define THREAD_RET void * #define THREAD_CREATE(thr,start,arg) pthread_create(&thr,NULL,start,arg) #define THREAD_FINISH(thr) pthread_join(thr,NULL) #define Z "z" /**< printf format modifier for size_t */ /** For MDB_LOCK_FORMAT: True if readers take a pid lock in the lockfile */ #define MDB_PIDLOCK 1 #ifdef MDB_USE_POSIX_SEM typedef sem_t *mdb_mutex_t, *mdb_mutexref_t; #define LOCK_MUTEX0(mutex) mdb_sem_wait(mutex) #define UNLOCK_MUTEX(mutex) sem_post(mutex) static int mdb_sem_wait(sem_t *sem) { int rc; while ((rc = sem_wait(sem)) && (rc = errno) == EINTR) ; return rc; } #else /* MDB_USE_POSIX_MUTEX: */ /** Shared mutex/semaphore as the original is stored. * * Not for copies. Instead it can be assigned to an #mdb_mutexref_t. * When mdb_mutexref_t is a pointer and mdb_mutex_t is not, then it * is array[size 1] so it can be assigned to the pointer. */ typedef pthread_mutex_t mdb_mutex_t[1]; /** Reference to an #mdb_mutex_t */ typedef pthread_mutex_t *mdb_mutexref_t; /** Lock the reader or writer mutex. * Returns 0 or a code to give #mdb_mutex_failed(), as in #LOCK_MUTEX(). */ #define LOCK_MUTEX0(mutex) pthread_mutex_lock(mutex) /** Unlock the reader or writer mutex. */ #define UNLOCK_MUTEX(mutex) pthread_mutex_unlock(mutex) /** Mark mutex-protected data as repaired, after death of previous owner. */ #define mdb_mutex_consistent(mutex) pthread_mutex_consistent(mutex) #endif /* MDB_USE_POSIX_SEM */ /** Get the error code for the last failed system function. */ #define ErrCode() errno /** An abstraction for a file handle. * On POSIX systems file handles are small integers. On Windows * they're opaque pointers. */ #define HANDLE int /** A value for an invalid file handle. * Mainly used to initialize file variables and signify that they are * unused. */ #define INVALID_HANDLE_VALUE (-1) /** Get the size of a memory page for the system. * This is the basic size that the platform's memory manager uses, and is * fundamental to the use of memory-mapped files. */ #define GET_PAGESIZE(x) ((x) = sysconf(_SC_PAGE_SIZE)) #endif #if defined(_WIN32) || defined(MDB_USE_POSIX_SEM) #define MNAME_LEN 32 #else #define MNAME_LEN (sizeof(pthread_mutex_t)) #endif /** @} */ #ifdef MDB_ROBUST_SUPPORTED /** Lock mutex, handle any error, set rc = result. * Return 0 on success, nonzero (not rc) on error. */ #define LOCK_MUTEX(rc, env, mutex) \ (((rc) = LOCK_MUTEX0(mutex)) && \ ((rc) = mdb_mutex_failed(env, mutex, rc))) static int mdb_mutex_failed(MDB_env *env, mdb_mutexref_t mutex, int rc); #else #define LOCK_MUTEX(rc, env, mutex) ((rc) = LOCK_MUTEX0(mutex)) #define mdb_mutex_failed(env, mutex, rc) (rc) #endif #ifndef _WIN32 /** A flag for opening a file and requesting synchronous data writes. * This is only used when writing a meta page. It's not strictly needed; * we could just do a normal write and then immediately perform a flush. * But if this flag is available it saves us an extra system call. * * @note If O_DSYNC is undefined but exists in /usr/include, * preferably set some compiler flag to get the definition. */ #ifndef MDB_DSYNC # ifdef O_DSYNC # define MDB_DSYNC O_DSYNC # else # define MDB_DSYNC O_SYNC # endif #endif #endif /** Function for flushing the data of a file. Define this to fsync * if fdatasync() is not supported. */ #ifndef MDB_FDATASYNC # define MDB_FDATASYNC fdatasync #endif #ifndef MDB_MSYNC # define MDB_MSYNC(addr,len,flags) msync(addr,len,flags) #endif #ifndef MS_SYNC #define MS_SYNC 1 #endif #ifndef MS_ASYNC #define MS_ASYNC 0 #endif /** A page number in the database. * Note that 64 bit page numbers are overkill, since pages themselves * already represent 12-13 bits of addressable memory, and the OS will * always limit applications to a maximum of 63 bits of address space. * * @note In the #MDB_node structure, we only store 48 bits of this value, * which thus limits us to only 60 bits of addressable data. */ typedef MDB_ID pgno_t; /** A transaction ID. * See struct MDB_txn.mt_txnid for details. */ typedef MDB_ID txnid_t; /** @defgroup debug Debug Macros * @{ */ #ifndef MDB_DEBUG /** Enable debug output. Needs variable argument macros (a C99 feature). * Set this to 1 for copious tracing. Set to 2 to add dumps of all IDLs * read from and written to the database (used for free space management). */ #define MDB_DEBUG 0 #endif #if MDB_DEBUG static int mdb_debug; static txnid_t mdb_debug_start; /** Print a debug message with printf formatting. * Requires double parenthesis around 2 or more args. */ # define DPRINTF(args) ((void) ((mdb_debug) && DPRINTF0 args)) # define DPRINTF0(fmt, ...) \ fprintf(stderr, "%s:%d " fmt "\n", mdb_func_, __LINE__, __VA_ARGS__) #else # define DPRINTF(args) ((void) 0) #endif /** Print a debug string. * The string is printed literally, with no format processing. */ #define DPUTS(arg) DPRINTF(("%s", arg)) /** Debugging output value of a cursor DBI: Negative in a sub-cursor. */ #define DDBI(mc) \ (((mc)->mc_flags & C_SUB) ? -(int)(mc)->mc_dbi : (int)(mc)->mc_dbi) /** @} */ /** @brief The maximum size of a database page. * * It is 32k or 64k, since value-PAGEBASE must fit in * #MDB_page.%mp_upper. * * LMDB will use database pages < OS pages if needed. * That causes more I/O in write transactions: The OS must * know (read) the whole page before writing a partial page. * * Note that we don't currently support Huge pages. On Linux, * regular data files cannot use Huge pages, and in general * Huge pages aren't actually pageable. We rely on the OS * demand-pager to read our data and page it out when memory * pressure from other processes is high. So until OSs have * actual paging support for Huge pages, they're not viable. */ #define MAX_PAGESIZE (PAGEBASE ? 0x10000 : 0x8000) /** The minimum number of keys required in a database page. * Setting this to a larger value will place a smaller bound on the * maximum size of a data item. Data items larger than this size will * be pushed into overflow pages instead of being stored directly in * the B-tree node. This value used to default to 4. With a page size * of 4096 bytes that meant that any item larger than 1024 bytes would * go into an overflow page. That also meant that on average 2-3KB of * each overflow page was wasted space. The value cannot be lower than * 2 because then there would no longer be a tree structure. With this * value, items larger than 2KB will go into overflow pages, and on * average only 1KB will be wasted. */ #define MDB_MINKEYS 2 /** A stamp that identifies a file as an LMDB file. * There's nothing special about this value other than that it is easily * recognizable, and it will reflect any byte order mismatches. */ #define MDB_MAGIC 0xBEEFC0DE /** The version number for a database's datafile format. */ #define MDB_DATA_VERSION ((MDB_DEVEL) ? 999 : 1) /** The version number for a database's lockfile format. */ #define MDB_LOCK_VERSION 1 /** @brief The max size of a key we can write, or 0 for computed max. * * This macro should normally be left alone or set to 0. * Note that a database with big keys or dupsort data cannot be * reliably modified by a liblmdb which uses a smaller max. * The default is 511 for backwards compat, or 0 when #MDB_DEVEL. * * Other values are allowed, for backwards compat. However: * A value bigger than the computed max can break if you do not * know what you are doing, and liblmdb <= 0.9.10 can break when * modifying a DB with keys/dupsort data bigger than its max. * * Data items in an #MDB_DUPSORT database are also limited to * this size, since they're actually keys of a sub-DB. Keys and * #MDB_DUPSORT data items must fit on a node in a regular page. */ #ifndef MDB_MAXKEYSIZE #define MDB_MAXKEYSIZE ((MDB_DEVEL) ? 0 : 511) #endif /** The maximum size of a key we can write to the environment. */ #if MDB_MAXKEYSIZE #define ENV_MAXKEY(env) (MDB_MAXKEYSIZE) #else #define ENV_MAXKEY(env) ((env)->me_maxkey) #endif /** @brief The maximum size of a data item. * * We only store a 32 bit value for node sizes. */ #define MAXDATASIZE 0xffffffffUL #if MDB_DEBUG /** Key size which fits in a #DKBUF. * @ingroup debug */ #define DKBUF_MAXKEYSIZE ((MDB_MAXKEYSIZE) > 0 ? (MDB_MAXKEYSIZE) : 511) /** A key buffer. * @ingroup debug * This is used for printing a hex dump of a key's contents. */ #define DKBUF char kbuf[DKBUF_MAXKEYSIZE*2+1] /** Display a key in hex. * @ingroup debug * Invoke a function to display a key in hex. */ #define DKEY(x) mdb_dkey(x, kbuf) #else #define DKBUF #define DKEY(x) 0 #endif /** An invalid page number. * Mainly used to denote an empty tree. */ #define P_INVALID (~(pgno_t)0) /** Test if the flags \b f are set in a flag word \b w. */ #define F_ISSET(w, f) (((w) & (f)) == (f)) /** Round \b n up to an even number. */ #define EVEN(n) (((n) + 1U) & -2) /* sign-extending -2 to match n+1U */ /** Used for offsets within a single page. * Since memory pages are typically 4 or 8KB in size, 12-13 bits, * this is plenty. */ typedef uint16_t indx_t; /** Default size of memory map. * This is certainly too small for any actual applications. Apps should always set * the size explicitly using #mdb_env_set_mapsize(). */ #define DEFAULT_MAPSIZE 1048576 /** @defgroup readers Reader Lock Table * Readers don't acquire any locks for their data access. Instead, they * simply record their transaction ID in the reader table. The reader * mutex is needed just to find an empty slot in the reader table. The * slot's address is saved in thread-specific data so that subsequent read * transactions started by the same thread need no further locking to proceed. * * If #MDB_NOTLS is set, the slot address is not saved in thread-specific data. * * No reader table is used if the database is on a read-only filesystem, or * if #MDB_NOLOCK is set. * * Since the database uses multi-version concurrency control, readers don't * actually need any locking. This table is used to keep track of which * readers are using data from which old transactions, so that we'll know * when a particular old transaction is no longer in use. Old transactions * that have discarded any data pages can then have those pages reclaimed * for use by a later write transaction. * * The lock table is constructed such that reader slots are aligned with the * processor's cache line size. Any slot is only ever used by one thread. * This alignment guarantees that there will be no contention or cache * thrashing as threads update their own slot info, and also eliminates * any need for locking when accessing a slot. * * A writer thread will scan every slot in the table to determine the oldest * outstanding reader transaction. Any freed pages older than this will be * reclaimed by the writer. The writer doesn't use any locks when scanning * this table. This means that there's no guarantee that the writer will * see the most up-to-date reader info, but that's not required for correct * operation - all we need is to know the upper bound on the oldest reader, * we don't care at all about the newest reader. So the only consequence of * reading stale information here is that old pages might hang around a * while longer before being reclaimed. That's actually good anyway, because * the longer we delay reclaiming old pages, the more likely it is that a * string of contiguous pages can be found after coalescing old pages from * many old transactions together. * @{ */ /** Number of slots in the reader table. * This value was chosen somewhat arbitrarily. 126 readers plus a * couple mutexes fit exactly into 8KB on my development machine. * Applications should set the table size using #mdb_env_set_maxreaders(). */ #define DEFAULT_READERS 126 /** The size of a CPU cache line in bytes. We want our lock structures * aligned to this size to avoid false cache line sharing in the * lock table. * This value works for most CPUs. For Itanium this should be 128. */ #ifndef CACHELINE #define CACHELINE 64 #endif /** The information we store in a single slot of the reader table. * In addition to a transaction ID, we also record the process and * thread ID that owns a slot, so that we can detect stale information, * e.g. threads or processes that went away without cleaning up. * @note We currently don't check for stale records. We simply re-init * the table when we know that we're the only process opening the * lock file. */ typedef struct MDB_rxbody { /** Current Transaction ID when this transaction began, or (txnid_t)-1. * Multiple readers that start at the same time will probably have the * same ID here. Again, it's not important to exclude them from * anything; all we need to know is which version of the DB they * started from so we can avoid overwriting any data used in that * particular version. */ volatile txnid_t mrb_txnid; /** The process ID of the process owning this reader txn. */ volatile MDB_PID_T mrb_pid; /** The thread ID of the thread owning this txn. */ volatile MDB_THR_T mrb_tid; } MDB_rxbody; /** The actual reader record, with cacheline padding. */ typedef struct MDB_reader { union { MDB_rxbody mrx; /** shorthand for mrb_txnid */ #define mr_txnid mru.mrx.mrb_txnid #define mr_pid mru.mrx.mrb_pid #define mr_tid mru.mrx.mrb_tid /** cache line alignment */ char pad[(sizeof(MDB_rxbody)+CACHELINE-1) & ~(CACHELINE-1)]; } mru; } MDB_reader; /** The header for the reader table. * The table resides in a memory-mapped file. (This is a different file * than is used for the main database.) * * For POSIX the actual mutexes reside in the shared memory of this * mapped file. On Windows, mutexes are named objects allocated by the * kernel; we store the mutex names in this mapped file so that other * processes can grab them. This same approach is also used on * MacOSX/Darwin (using named semaphores) since MacOSX doesn't support * process-shared POSIX mutexes. For these cases where a named object * is used, the object name is derived from a 64 bit FNV hash of the * environment pathname. As such, naming collisions are extremely * unlikely. If a collision occurs, the results are unpredictable. */ typedef struct MDB_txbody { /** Stamp identifying this as an LMDB file. It must be set * to #MDB_MAGIC. */ uint32_t mtb_magic; /** Format of this lock file. Must be set to #MDB_LOCK_FORMAT. */ uint32_t mtb_format; #if defined(_WIN32) || defined(MDB_USE_POSIX_SEM) char mtb_rmname[MNAME_LEN]; #else /** Mutex protecting access to this table. * This is the reader table lock used with LOCK_MUTEX(). */ mdb_mutex_t mtb_rmutex; #endif /** The ID of the last transaction committed to the database. * This is recorded here only for convenience; the value can always * be determined by reading the main database meta pages. */ volatile txnid_t mtb_txnid; /** The number of slots that have been used in the reader table. * This always records the maximum count, it is not decremented * when readers release their slots. */ volatile unsigned mtb_numreaders; } MDB_txbody; /** The actual reader table definition. */ typedef struct MDB_txninfo { union { MDB_txbody mtb; #define mti_magic mt1.mtb.mtb_magic #define mti_format mt1.mtb.mtb_format #define mti_rmutex mt1.mtb.mtb_rmutex #define mti_rmname mt1.mtb.mtb_rmname #define mti_txnid mt1.mtb.mtb_txnid #define mti_numreaders mt1.mtb.mtb_numreaders char pad[(sizeof(MDB_txbody)+CACHELINE-1) & ~(CACHELINE-1)]; } mt1; union { #if defined(_WIN32) || defined(MDB_USE_POSIX_SEM) char mt2_wmname[MNAME_LEN]; #define mti_wmname mt2.mt2_wmname #else mdb_mutex_t mt2_wmutex; #define mti_wmutex mt2.mt2_wmutex #endif char pad[(MNAME_LEN+CACHELINE-1) & ~(CACHELINE-1)]; } mt2; MDB_reader mti_readers[1]; } MDB_txninfo; /** Lockfile format signature: version, features and field layout */ #define MDB_LOCK_FORMAT \ ((uint32_t) \ ((MDB_LOCK_VERSION) \ /* Flags which describe functionality */ \ + (((MDB_PIDLOCK) != 0) << 16))) /** @} */ /** Common header for all page types. The page type depends on #mp_flags. * * #P_BRANCH and #P_LEAF pages have unsorted '#MDB_node's at the end, with * sorted #mp_ptrs[] entries referring to them. Exception: #P_LEAF2 pages * omit mp_ptrs and pack sorted #MDB_DUPFIXED values after the page header. * * #P_OVERFLOW records occupy one or more contiguous pages where only the * first has a page header. They hold the real data of #F_BIGDATA nodes. * * #P_SUBP sub-pages are small leaf "pages" with duplicate data. * A node with flag #F_DUPDATA but not #F_SUBDATA contains a sub-page. * (Duplicate data can also go in sub-databases, which use normal pages.) * * #P_META pages contain #MDB_meta, the start point of an LMDB snapshot. * * Each non-metapage up to #MDB_meta.%mm_last_pg is reachable exactly once * in the snapshot: Either used by a database or listed in a freeDB record. */ typedef struct MDB_page { #define mp_pgno mp_p.p_pgno #define mp_next mp_p.p_next union { pgno_t p_pgno; /**< page number */ struct MDB_page *p_next; /**< for in-memory list of freed pages */ } mp_p; uint16_t mp_pad; /**< key size if this is a LEAF2 page */ /** @defgroup mdb_page Page Flags * @ingroup internal * Flags for the page headers. * @{ */ #define P_BRANCH 0x01 /**< branch page */ #define P_LEAF 0x02 /**< leaf page */ #define P_OVERFLOW 0x04 /**< overflow page */ #define P_META 0x08 /**< meta page */ #define P_DIRTY 0x10 /**< dirty page, also set for #P_SUBP pages */ #define P_LEAF2 0x20 /**< for #MDB_DUPFIXED records */ #define P_SUBP 0x40 /**< for #MDB_DUPSORT sub-pages */ #define P_LOOSE 0x4000 /**< page was dirtied then freed, can be reused */ #define P_KEEP 0x8000 /**< leave this page alone during spill */ /** @} */ uint16_t mp_flags; /**< @ref mdb_page */ #define mp_lower mp_pb.pb.pb_lower #define mp_upper mp_pb.pb.pb_upper #define mp_pages mp_pb.pb_pages union { struct { indx_t pb_lower; /**< lower bound of free space */ indx_t pb_upper; /**< upper bound of free space */ } pb; uint32_t pb_pages; /**< number of overflow pages */ } mp_pb; indx_t mp_ptrs[1]; /**< dynamic size */ } MDB_page; /** Size of the page header, excluding dynamic data at the end */ #define PAGEHDRSZ ((unsigned) offsetof(MDB_page, mp_ptrs)) /** Address of first usable data byte in a page, after the header */ #define METADATA(p) ((void *)((char *)(p) + PAGEHDRSZ)) /** ITS#7713, change PAGEBASE to handle 65536 byte pages */ #define PAGEBASE ((MDB_DEVEL) ? PAGEHDRSZ : 0) /** Number of nodes on a page */ #define NUMKEYS(p) (((p)->mp_lower - (PAGEHDRSZ-PAGEBASE)) >> 1) /** The amount of space remaining in the page */ #define SIZELEFT(p) (indx_t)((p)->mp_upper - (p)->mp_lower) /** The percentage of space used in the page, in tenths of a percent. */ #define PAGEFILL(env, p) (1000L * ((env)->me_psize - PAGEHDRSZ - SIZELEFT(p)) / \ ((env)->me_psize - PAGEHDRSZ)) /** The minimum page fill factor, in tenths of a percent. * Pages emptier than this are candidates for merging. */ #define FILL_THRESHOLD 250 /** Test if a page is a leaf page */ #define IS_LEAF(p) F_ISSET((p)->mp_flags, P_LEAF) /** Test if a page is a LEAF2 page */ #define IS_LEAF2(p) F_ISSET((p)->mp_flags, P_LEAF2) /** Test if a page is a branch page */ #define IS_BRANCH(p) F_ISSET((p)->mp_flags, P_BRANCH) /** Test if a page is an overflow page */ #define IS_OVERFLOW(p) F_ISSET((p)->mp_flags, P_OVERFLOW) /** Test if a page is a sub page */ #define IS_SUBP(p) F_ISSET((p)->mp_flags, P_SUBP) /** The number of overflow pages needed to store the given size. */ #define OVPAGES(size, psize) ((PAGEHDRSZ-1 + (size)) / (psize) + 1) /** Link in #MDB_txn.%mt_loose_pgs list. * Kept outside the page header, which is needed when reusing the page. */ #define NEXT_LOOSE_PAGE(p) (*(MDB_page **)((p) + 2)) /** Header for a single key/data pair within a page. * Used in pages of type #P_BRANCH and #P_LEAF without #P_LEAF2. * We guarantee 2-byte alignment for 'MDB_node's. * * #mn_lo and #mn_hi are used for data size on leaf nodes, and for child * pgno on branch nodes. On 64 bit platforms, #mn_flags is also used * for pgno. (Branch nodes have no flags). Lo and hi are in host byte * order in case some accesses can be optimized to 32-bit word access. * * Leaf node flags describe node contents. #F_BIGDATA says the node's * data part is the page number of an overflow page with actual data. * #F_DUPDATA and #F_SUBDATA can be combined giving duplicate data in * a sub-page/sub-database, and named databases (just #F_SUBDATA). */ typedef struct MDB_node { /** part of data size or pgno * @{ */ #if BYTE_ORDER == LITTLE_ENDIAN unsigned short mn_lo, mn_hi; #else unsigned short mn_hi, mn_lo; #endif /** @} */ /** @defgroup mdb_node Node Flags * @ingroup internal * Flags for node headers. * @{ */ #define F_BIGDATA 0x01 /**< data put on overflow page */ #define F_SUBDATA 0x02 /**< data is a sub-database */ #define F_DUPDATA 0x04 /**< data has duplicates */ /** valid flags for #mdb_node_add() */ #define NODE_ADD_FLAGS (F_DUPDATA|F_SUBDATA|MDB_RESERVE|MDB_APPEND) /** @} */ unsigned short mn_flags; /**< @ref mdb_node */ unsigned short mn_ksize; /**< key size */ char mn_data[1]; /**< key and data are appended here */ } MDB_node; /** Size of the node header, excluding dynamic data at the end */ #define NODESIZE offsetof(MDB_node, mn_data) /** Bit position of top word in page number, for shifting mn_flags */ #define PGNO_TOPWORD ((pgno_t)-1 > 0xffffffffu ? 32 : 0) /** Size of a node in a branch page with a given key. * This is just the node header plus the key, there is no data. */ #define INDXSIZE(k) (NODESIZE + ((k) == NULL ? 0 : (k)->mv_size)) /** Size of a node in a leaf page with a given key and data. * This is node header plus key plus data size. */ #define LEAFSIZE(k, d) (NODESIZE + (k)->mv_size + (d)->mv_size) /** Address of node \b i in page \b p */ #define NODEPTR(p, i) ((MDB_node *)((char *)(p) + (p)->mp_ptrs[i] + PAGEBASE)) /** Address of the key for the node */ #define NODEKEY(node) (void *)((node)->mn_data) /** Address of the data for a node */ #define NODEDATA(node) (void *)((char *)(node)->mn_data + (node)->mn_ksize) /** Get the page number pointed to by a branch node */ #define NODEPGNO(node) \ ((node)->mn_lo | ((pgno_t) (node)->mn_hi << 16) | \ (PGNO_TOPWORD ? ((pgno_t) (node)->mn_flags << PGNO_TOPWORD) : 0)) /** Set the page number in a branch node */ #define SETPGNO(node,pgno) do { \ (node)->mn_lo = (pgno) & 0xffff; (node)->mn_hi = (pgno) >> 16; \ if (PGNO_TOPWORD) (node)->mn_flags = (pgno) >> PGNO_TOPWORD; } while(0) /** Get the size of the data in a leaf node */ #define NODEDSZ(node) ((node)->mn_lo | ((unsigned)(node)->mn_hi << 16)) /** Set the size of the data for a leaf node */ #define SETDSZ(node,size) do { \ (node)->mn_lo = (size) & 0xffff; (node)->mn_hi = (size) >> 16;} while(0) /** The size of a key in a node */ #define NODEKSZ(node) ((node)->mn_ksize) /** Copy a page number from src to dst */ #ifdef MISALIGNED_OK #define COPY_PGNO(dst,src) dst = src #else #if SIZE_MAX > 4294967295UL #define COPY_PGNO(dst,src) do { \ unsigned short *s, *d; \ s = (unsigned short *)&(src); \ d = (unsigned short *)&(dst); \ *d++ = *s++; \ *d++ = *s++; \ *d++ = *s++; \ *d = *s; \ } while (0) #else #define COPY_PGNO(dst,src) do { \ unsigned short *s, *d; \ s = (unsigned short *)&(src); \ d = (unsigned short *)&(dst); \ *d++ = *s++; \ *d = *s; \ } while (0) #endif #endif /** The address of a key in a LEAF2 page. * LEAF2 pages are used for #MDB_DUPFIXED sorted-duplicate sub-DBs. * There are no node headers, keys are stored contiguously. */ #define LEAF2KEY(p, i, ks) ((char *)(p) + PAGEHDRSZ + ((i)*(ks))) /** Set the \b node's key into \b keyptr, if requested. */ #define MDB_GET_KEY(node, keyptr) { if ((keyptr) != NULL) { \ (keyptr)->mv_size = NODEKSZ(node); (keyptr)->mv_data = NODEKEY(node); } } /** Set the \b node's key into \b key. */ #define MDB_GET_KEY2(node, key) { key.mv_size = NODEKSZ(node); key.mv_data = NODEKEY(node); } /** Information about a single database in the environment. */ typedef struct MDB_db { uint32_t md_pad; /**< also ksize for LEAF2 pages */ uint16_t md_flags; /**< @ref mdb_dbi_open */ uint16_t md_depth; /**< depth of this tree */ pgno_t md_branch_pages; /**< number of internal pages */ pgno_t md_leaf_pages; /**< number of leaf pages */ pgno_t md_overflow_pages; /**< number of overflow pages */ size_t md_entries; /**< number of data items */ pgno_t md_root; /**< the root page of this tree */ } MDB_db; #define MDB_VALID 0x8000 /**< DB handle is valid, for me_dbflags */ #define PERSISTENT_FLAGS (0xffff & ~(MDB_VALID)) /** #mdb_dbi_open() flags */ #define VALID_FLAGS (MDB_REVERSEKEY|MDB_DUPSORT|MDB_INTEGERKEY|MDB_DUPFIXED|\ MDB_INTEGERDUP|MDB_REVERSEDUP|MDB_CREATE) /** Handle for the DB used to track free pages. */ #define FREE_DBI 0 /** Handle for the default DB. */ #define MAIN_DBI 1 /** Number of DBs in metapage (free and main) - also hardcoded elsewhere */ #define CORE_DBS 2 /** Number of meta pages - also hardcoded elsewhere */ #define NUM_METAS 2 /** Meta page content. * A meta page is the start point for accessing a database snapshot. * Pages 0-1 are meta pages. Transaction N writes meta page #(N % 2). */ typedef struct MDB_meta { /** Stamp identifying this as an LMDB file. It must be set * to #MDB_MAGIC. */ uint32_t mm_magic; /** Version number of this file. Must be set to #MDB_DATA_VERSION. */ uint32_t mm_version; void *mm_address; /**< address for fixed mapping */ size_t mm_mapsize; /**< size of mmap region */ MDB_db mm_dbs[CORE_DBS]; /**< first is free space, 2nd is main db */ /** The size of pages used in this DB */ #define mm_psize mm_dbs[FREE_DBI].md_pad /** Any persistent environment flags. @ref mdb_env */ #define mm_flags mm_dbs[FREE_DBI].md_flags /** Last used page in the datafile. * Actually the file may be shorter if the freeDB lists the final pages. */ pgno_t mm_last_pg; volatile txnid_t mm_txnid; /**< txnid that committed this page */ } MDB_meta; /** Buffer for a stack-allocated meta page. * The members define size and alignment, and silence type * aliasing warnings. They are not used directly; that could * mean incorrectly using several union members in parallel. */ typedef union MDB_metabuf { MDB_page mb_page; struct { char mm_pad[PAGEHDRSZ]; MDB_meta mm_meta; } mb_metabuf; } MDB_metabuf; /** Auxiliary DB info. * The information here is mostly static/read-only. There is * only a single copy of this record in the environment. */ typedef struct MDB_dbx { MDB_val md_name; /**< name of the database */ MDB_cmp_func *md_cmp; /**< function for comparing keys */ MDB_cmp_func *md_dcmp; /**< function for comparing data items */ MDB_rel_func *md_rel; /**< user relocate function */ void *md_relctx; /**< user-provided context for md_rel */ } MDB_dbx; /** A database transaction. * Every operation requires a transaction handle. */ struct MDB_txn { MDB_txn *mt_parent; /**< parent of a nested txn */ /** Nested txn under this txn, set together with flag #MDB_TXN_HAS_CHILD */ MDB_txn *mt_child; pgno_t mt_next_pgno; /**< next unallocated page */ /** The ID of this transaction. IDs are integers incrementing from 1. * Only committed write transactions increment the ID. If a transaction * aborts, the ID may be re-used by the next writer. */ txnid_t mt_txnid; MDB_env *mt_env; /**< the DB environment */ /** The list of pages that became unused during this transaction. */ MDB_IDL mt_free_pgs; /** The list of loose pages that became unused and may be reused * in this transaction, linked through #NEXT_LOOSE_PAGE(page). */ MDB_page *mt_loose_pgs; /** Number of loose pages (#mt_loose_pgs) */ int mt_loose_count; /** The sorted list of dirty pages we temporarily wrote to disk * because the dirty list was full. page numbers in here are * shifted left by 1, deleted slots have the LSB set. */ MDB_IDL mt_spill_pgs; union { /** For write txns: Modified pages. Sorted when not MDB_WRITEMAP. */ MDB_ID2L dirty_list; /** For read txns: This thread/txn's reader table slot, or NULL. */ MDB_reader *reader; } mt_u; /** Array of records for each DB known in the environment. */ MDB_dbx *mt_dbxs; /** Array of MDB_db records for each known DB */ MDB_db *mt_dbs; /** Array of sequence numbers for each DB handle */ unsigned int *mt_dbiseqs; /** @defgroup mt_dbflag Transaction DB Flags * @ingroup internal * @{ */ #define DB_DIRTY 0x01 /**< DB was written in this txn */ #define DB_STALE 0x02 /**< Named-DB record is older than txnID */ #define DB_NEW 0x04 /**< Named-DB handle opened in this txn */ #define DB_VALID 0x08 /**< DB handle is valid, see also #MDB_VALID */ #define DB_USRVALID 0x10 /**< As #DB_VALID, but not set for #FREE_DBI */ #define DB_DUPDATA 0x20 /**< DB is #MDB_DUPSORT data */ /** @} */ /** In write txns, array of cursors for each DB */ MDB_cursor **mt_cursors; /** Array of flags for each DB */ unsigned char *mt_dbflags; /** Number of DB records in use, or 0 when the txn is finished. * This number only ever increments until the txn finishes; we * don't decrement it when individual DB handles are closed. */ MDB_dbi mt_numdbs; /** @defgroup mdb_txn Transaction Flags * @ingroup internal * @{ */ /** #mdb_txn_begin() flags */ #define MDB_TXN_BEGIN_FLAGS MDB_RDONLY #define MDB_TXN_RDONLY MDB_RDONLY /**< read-only transaction */ /* internal txn flags */ #define MDB_TXN_WRITEMAP MDB_WRITEMAP /**< copy of #MDB_env flag in writers */ #define MDB_TXN_FINISHED 0x01 /**< txn is finished or never began */ #define MDB_TXN_ERROR 0x02 /**< txn is unusable after an error */ #define MDB_TXN_DIRTY 0x04 /**< must write, even if dirty list is empty */ #define MDB_TXN_SPILLS 0x08 /**< txn or a parent has spilled pages */ #define MDB_TXN_HAS_CHILD 0x10 /**< txn has an #MDB_txn.%mt_child */ /** most operations on the txn are currently illegal */ #define MDB_TXN_BLOCKED (MDB_TXN_FINISHED|MDB_TXN_ERROR|MDB_TXN_HAS_CHILD) /** @} */ unsigned int mt_flags; /**< @ref mdb_txn */ /** #dirty_list room: Array size - \#dirty pages visible to this txn. * Includes ancestor txns' dirty pages not hidden by other txns' * dirty/spilled pages. Thus commit(nested txn) has room to merge * dirty_list into mt_parent after freeing hidden mt_parent pages. */ unsigned int mt_dirty_room; }; /** Enough space for 2^32 nodes with minimum of 2 keys per node. I.e., plenty. * At 4 keys per node, enough for 2^64 nodes, so there's probably no need to * raise this on a 64 bit machine. */ #define CURSOR_STACK 32 struct MDB_xcursor; /** Cursors are used for all DB operations. * A cursor holds a path of (page pointer, key index) from the DB * root to a position in the DB, plus other state. #MDB_DUPSORT * cursors include an xcursor to the current data item. Write txns * track their cursors and keep them up to date when data moves. * Exception: An xcursor's pointer to a #P_SUBP page can be stale. * (A node with #F_DUPDATA but no #F_SUBDATA contains a subpage). */ struct MDB_cursor { /** Next cursor on this DB in this txn */ MDB_cursor *mc_next; /** Backup of the original cursor if this cursor is a shadow */ MDB_cursor *mc_backup; /** Context used for databases with #MDB_DUPSORT, otherwise NULL */ struct MDB_xcursor *mc_xcursor; /** The transaction that owns this cursor */ MDB_txn *mc_txn; /** The database handle this cursor operates on */ MDB_dbi mc_dbi; /** The database record for this cursor */ MDB_db *mc_db; /** The database auxiliary record for this cursor */ MDB_dbx *mc_dbx; /** The @ref mt_dbflag for this database */ unsigned char *mc_dbflag; unsigned short mc_snum; /**< number of pushed pages */ unsigned short mc_top; /**< index of top page, normally mc_snum-1 */ /** @defgroup mdb_cursor Cursor Flags * @ingroup internal * Cursor state flags. * @{ */ #define C_INITIALIZED 0x01 /**< cursor has been initialized and is valid */ #define C_EOF 0x02 /**< No more data */ #define C_SUB 0x04 /**< Cursor is a sub-cursor */ #define C_DEL 0x08 /**< last op was a cursor_del */ #define C_UNTRACK 0x40 /**< Un-track cursor when closing */ /** @} */ unsigned int mc_flags; /**< @ref mdb_cursor */ MDB_page *mc_pg[CURSOR_STACK]; /**< stack of pushed pages */ indx_t mc_ki[CURSOR_STACK]; /**< stack of page indices */ }; /** Context for sorted-dup records. * We could have gone to a fully recursive design, with arbitrarily * deep nesting of sub-databases. But for now we only handle these * levels - main DB, optional sub-DB, sorted-duplicate DB. */ typedef struct MDB_xcursor { /** A sub-cursor for traversing the Dup DB */ MDB_cursor mx_cursor; /** The database record for this Dup DB */ MDB_db mx_db; /** The auxiliary DB record for this Dup DB */ MDB_dbx mx_dbx; /** The @ref mt_dbflag for this Dup DB */ unsigned char mx_dbflag; } MDB_xcursor; /** Check if there is an inited xcursor */ #define XCURSOR_INITED(mc) \ ((mc)->mc_xcursor && ((mc)->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) /** Update the xcursor's sub-page pointer, if any, in \b mc. Needed * when the node which contains the sub-page may have moved. Called * with leaf page \b mp = mc->mc_pg[\b top]. */ #define XCURSOR_REFRESH(mc, top, mp) do { \ MDB_page *xr_pg = (mp); \ MDB_node *xr_node; \ if (!XCURSOR_INITED(mc) || (mc)->mc_ki[top] >= NUMKEYS(xr_pg)) break; \ xr_node = NODEPTR(xr_pg, (mc)->mc_ki[top]); \ if ((xr_node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA) \ (mc)->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(xr_node); \ } while (0) /** State of FreeDB old pages, stored in the MDB_env */ typedef struct MDB_pgstate { pgno_t *mf_pghead; /**< Reclaimed freeDB pages, or NULL before use */ txnid_t mf_pglast; /**< ID of last used record, or 0 if !mf_pghead */ } MDB_pgstate; /** The database environment. */ struct MDB_env { HANDLE me_fd; /**< The main data file */ HANDLE me_lfd; /**< The lock file */ HANDLE me_mfd; /**< For writing and syncing the meta pages */ /** Failed to update the meta page. Probably an I/O error. */ #define MDB_FATAL_ERROR 0x80000000U /** Some fields are initialized. */ #define MDB_ENV_ACTIVE 0x20000000U /** me_txkey is set */ #define MDB_ENV_TXKEY 0x10000000U /** fdatasync is unreliable */ #define MDB_FSYNCONLY 0x08000000U uint32_t me_flags; /**< @ref mdb_env */ unsigned int me_psize; /**< DB page size, inited from me_os_psize */ unsigned int me_os_psize; /**< OS page size, from #GET_PAGESIZE */ unsigned int me_maxreaders; /**< size of the reader table */ /** Max #MDB_txninfo.%mti_numreaders of interest to #mdb_env_close() */ volatile int me_close_readers; MDB_dbi me_numdbs; /**< number of DBs opened */ MDB_dbi me_maxdbs; /**< size of the DB table */ MDB_PID_T me_pid; /**< process ID of this env */ char *me_path; /**< path to the DB files */ char *me_map; /**< the memory map of the data file */ MDB_txninfo *me_txns; /**< the memory map of the lock file or NULL */ MDB_meta *me_metas[NUM_METAS]; /**< pointers to the two meta pages */ void *me_pbuf; /**< scratch area for DUPSORT put() */ MDB_txn *me_txn; /**< current write transaction */ MDB_txn *me_txn0; /**< prealloc'd write transaction */ size_t me_mapsize; /**< size of the data memory map */ off_t me_size; /**< current file size */ pgno_t me_maxpg; /**< me_mapsize / me_psize */ MDB_dbx *me_dbxs; /**< array of static DB info */ uint16_t *me_dbflags; /**< array of flags from MDB_db.md_flags */ unsigned int *me_dbiseqs; /**< array of dbi sequence numbers */ pthread_key_t me_txkey; /**< thread-key for readers */ txnid_t me_pgoldest; /**< ID of oldest reader last time we looked */ MDB_pgstate me_pgstate; /**< state of old pages from freeDB */ # define me_pglast me_pgstate.mf_pglast # define me_pghead me_pgstate.mf_pghead MDB_page *me_dpages; /**< list of malloc'd blocks for re-use */ /** IDL of pages that became unused in a write txn */ MDB_IDL me_free_pgs; /** ID2L of pages written during a write txn. Length MDB_IDL_UM_SIZE. */ MDB_ID2L me_dirty_list; /** Max number of freelist items that can fit in a single overflow page */ int me_maxfree_1pg; /** Max size of a node on a page */ unsigned int me_nodemax; #if !(MDB_MAXKEYSIZE) unsigned int me_maxkey; /**< max size of a key */ #endif int me_live_reader; /**< have liveness lock in reader table */ #ifdef _WIN32 int me_pidquery; /**< Used in OpenProcess */ #endif #ifdef MDB_USE_POSIX_MUTEX /* Posix mutexes reside in shared mem */ # define me_rmutex me_txns->mti_rmutex /**< Shared reader lock */ # define me_wmutex me_txns->mti_wmutex /**< Shared writer lock */ #else mdb_mutex_t me_rmutex; mdb_mutex_t me_wmutex; #endif void *me_userctx; /**< User-settable context */ MDB_assert_func *me_assert_func; /**< Callback for assertion failures */ }; /** Nested transaction */ typedef struct MDB_ntxn { MDB_txn mnt_txn; /**< the transaction */ MDB_pgstate mnt_pgstate; /**< parent transaction's saved freestate */ } MDB_ntxn; /** max number of pages to commit in one writev() call */ #define MDB_COMMIT_PAGES 64 #if defined(IOV_MAX) && IOV_MAX < MDB_COMMIT_PAGES #undef MDB_COMMIT_PAGES #define MDB_COMMIT_PAGES IOV_MAX #endif /** max bytes to write in one call */ #define MAX_WRITE (0x40000000U >> (sizeof(ssize_t) == 4)) /** Check \b txn and \b dbi arguments to a function */ #define TXN_DBI_EXIST(txn, dbi, validity) \ ((txn) && (dbi)<(txn)->mt_numdbs && ((txn)->mt_dbflags[dbi] & (validity))) /** Check for misused \b dbi handles */ #define TXN_DBI_CHANGED(txn, dbi) \ ((txn)->mt_dbiseqs[dbi] != (txn)->mt_env->me_dbiseqs[dbi]) static int mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp); static int mdb_page_new(MDB_cursor *mc, uint32_t flags, int num, MDB_page **mp); static int mdb_page_touch(MDB_cursor *mc); #define MDB_END_NAMES {"committed", "empty-commit", "abort", "reset", \ "reset-tmp", "fail-begin", "fail-beginchild"} enum { /* mdb_txn_end operation number, for logging */ MDB_END_COMMITTED, MDB_END_EMPTY_COMMIT, MDB_END_ABORT, MDB_END_RESET, MDB_END_RESET_TMP, MDB_END_FAIL_BEGIN, MDB_END_FAIL_BEGINCHILD }; #define MDB_END_OPMASK 0x0F /**< mask for #mdb_txn_end() operation number */ #define MDB_END_UPDATE 0x10 /**< update env state (DBIs) */ #define MDB_END_FREE 0x20 /**< free txn unless it is #MDB_env.%me_txn0 */ #define MDB_END_SLOT MDB_NOTLS /**< release any reader slot if #MDB_NOTLS */ static void mdb_txn_end(MDB_txn *txn, unsigned mode); static int mdb_page_get(MDB_cursor *mc, pgno_t pgno, MDB_page **mp, int *lvl); static int mdb_page_search_root(MDB_cursor *mc, MDB_val *key, int modify); #define MDB_PS_MODIFY 1 #define MDB_PS_ROOTONLY 2 #define MDB_PS_FIRST 4 #define MDB_PS_LAST 8 static int mdb_page_search(MDB_cursor *mc, MDB_val *key, int flags); static int mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst); #define MDB_SPLIT_REPLACE MDB_APPENDDUP /**< newkey is not new */ static int mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno, unsigned int nflags); static int mdb_env_read_header(MDB_env *env, MDB_meta *meta); static MDB_meta *mdb_env_pick_meta(const MDB_env *env); static int mdb_env_write_meta(MDB_txn *txn); #if defined(MDB_USE_POSIX_MUTEX) && !defined(MDB_ROBUST_SUPPORTED) /* Drop unused excl arg */ # define mdb_env_close0(env, excl) mdb_env_close1(env) #endif static void mdb_env_close0(MDB_env *env, int excl); static MDB_node *mdb_node_search(MDB_cursor *mc, MDB_val *key, int *exactp); static int mdb_node_add(MDB_cursor *mc, indx_t indx, MDB_val *key, MDB_val *data, pgno_t pgno, unsigned int flags); static void mdb_node_del(MDB_cursor *mc, int ksize); static void mdb_node_shrink(MDB_page *mp, indx_t indx); static int mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft); static int mdb_node_read(MDB_cursor *mc, MDB_node *leaf, MDB_val *data); static size_t mdb_leaf_size(MDB_env *env, MDB_val *key, MDB_val *data); static size_t mdb_branch_size(MDB_env *env, MDB_val *key); static int mdb_rebalance(MDB_cursor *mc); static int mdb_update_key(MDB_cursor *mc, MDB_val *key); static void mdb_cursor_pop(MDB_cursor *mc); static int mdb_cursor_push(MDB_cursor *mc, MDB_page *mp); static int mdb_cursor_del0(MDB_cursor *mc); static int mdb_del0(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data, unsigned flags); static int mdb_cursor_sibling(MDB_cursor *mc, int move_right); static int mdb_cursor_next(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op); static int mdb_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op); static int mdb_cursor_set(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op, int *exactp); static int mdb_cursor_first(MDB_cursor *mc, MDB_val *key, MDB_val *data); static int mdb_cursor_last(MDB_cursor *mc, MDB_val *key, MDB_val *data); static void mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx); static void mdb_xcursor_init0(MDB_cursor *mc); static void mdb_xcursor_init1(MDB_cursor *mc, MDB_node *node); static void mdb_xcursor_init2(MDB_cursor *mc, MDB_xcursor *src_mx, int force); static int mdb_drop0(MDB_cursor *mc, int subs); static void mdb_default_cmp(MDB_txn *txn, MDB_dbi dbi); static int mdb_reader_check0(MDB_env *env, int rlocked, int *dead); /** @cond */ static MDB_cmp_func mdb_cmp_memn, mdb_cmp_memnr, mdb_cmp_int, mdb_cmp_cint, mdb_cmp_long; /** @endcond */ /** Compare two items pointing at size_t's of unknown alignment. */ #ifdef MISALIGNED_OK # define mdb_cmp_clong mdb_cmp_long #else # define mdb_cmp_clong mdb_cmp_cint #endif #ifdef _WIN32 static SECURITY_DESCRIPTOR mdb_null_sd; static SECURITY_ATTRIBUTES mdb_all_sa; static int mdb_sec_inited; struct MDB_name; static int utf8_to_utf16(const char *src, struct MDB_name *dst, int xtra); #endif /** Return the library version info. */ char * ESECT mdb_version(int *major, int *minor, int *patch) { if (major) *major = MDB_VERSION_MAJOR; if (minor) *minor = MDB_VERSION_MINOR; if (patch) *patch = MDB_VERSION_PATCH; return MDB_VERSION_STRING; } /** Table of descriptions for LMDB @ref errors */ static char *const mdb_errstr[] = { "MDB_KEYEXIST: Key/data pair already exists", "MDB_NOTFOUND: No matching key/data pair found", "MDB_PAGE_NOTFOUND: Requested page not found", "MDB_CORRUPTED: Located page was wrong type", "MDB_PANIC: Update of meta page failed or environment had fatal error", "MDB_VERSION_MISMATCH: Database environment version mismatch", "MDB_INVALID: File is not an LMDB file", "MDB_MAP_FULL: Environment mapsize limit reached", "MDB_DBS_FULL: Environment maxdbs limit reached", "MDB_READERS_FULL: Environment maxreaders limit reached", "MDB_TLS_FULL: Thread-local storage keys full - too many environments open", "MDB_TXN_FULL: Transaction has too many dirty pages - transaction too big", "MDB_CURSOR_FULL: Internal error - cursor stack limit reached", "MDB_PAGE_FULL: Internal error - page has no more space", "MDB_MAP_RESIZED: Database contents grew beyond environment mapsize", "MDB_INCOMPATIBLE: Operation and DB incompatible, or DB flags changed", "MDB_BAD_RSLOT: Invalid reuse of reader locktable slot", "MDB_BAD_TXN: Transaction must abort, has a child, or is invalid", "MDB_BAD_VALSIZE: Unsupported size of key/DB name/data, or wrong DUPFIXED size", "MDB_BAD_DBI: The specified DBI handle was closed/changed unexpectedly", }; char * mdb_strerror(int err) { #ifdef _WIN32 /** HACK: pad 4KB on stack over the buf. Return system msgs in buf. * This works as long as no function between the call to mdb_strerror * and the actual use of the message uses more than 4K of stack. */ #define MSGSIZE 1024 #define PADSIZE 4096 char buf[MSGSIZE+PADSIZE], *ptr = buf; #endif int i; if (!err) return ("Successful return: 0"); if (err >= MDB_KEYEXIST && err <= MDB_LAST_ERRCODE) { i = err - MDB_KEYEXIST; return mdb_errstr[i]; } #ifdef _WIN32 /* These are the C-runtime error codes we use. The comment indicates * their numeric value, and the Win32 error they would correspond to * if the error actually came from a Win32 API. A major mess, we should * have used LMDB-specific error codes for everything. */ switch(err) { case ENOENT: /* 2, FILE_NOT_FOUND */ case EIO: /* 5, ACCESS_DENIED */ case ENOMEM: /* 12, INVALID_ACCESS */ case EACCES: /* 13, INVALID_DATA */ case EBUSY: /* 16, CURRENT_DIRECTORY */ case EINVAL: /* 22, BAD_COMMAND */ case ENOSPC: /* 28, OUT_OF_PAPER */ return strerror(err); default: ; } buf[0] = 0; FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 0, ptr, MSGSIZE, (va_list *)buf+MSGSIZE); return ptr; #else return strerror(err); #endif } /** assert(3) variant in cursor context */ #define mdb_cassert(mc, expr) mdb_assert0((mc)->mc_txn->mt_env, expr, #expr) /** assert(3) variant in transaction context */ #define mdb_tassert(txn, expr) mdb_assert0((txn)->mt_env, expr, #expr) /** assert(3) variant in environment context */ #define mdb_eassert(env, expr) mdb_assert0(env, expr, #expr) #ifndef NDEBUG # define mdb_assert0(env, expr, expr_txt) ((expr) ? (void)0 : \ mdb_assert_fail(env, expr_txt, mdb_func_, __FILE__, __LINE__)) static void ESECT mdb_assert_fail(MDB_env *env, const char *expr_txt, const char *func, const char *file, int line) { char buf[400]; sprintf(buf, "%.100s:%d: Assertion '%.200s' failed in %.40s()", file, line, expr_txt, func); if (env->me_assert_func) env->me_assert_func(env, buf); fprintf(stderr, "%s\n", buf); abort(); } #else # define mdb_assert0(env, expr, expr_txt) ((void) 0) #endif /* NDEBUG */ #if MDB_DEBUG /** Return the page number of \b mp which may be sub-page, for debug output */ static pgno_t mdb_dbg_pgno(MDB_page *mp) { pgno_t ret; COPY_PGNO(ret, mp->mp_pgno); return ret; } /** Display a key in hexadecimal and return the address of the result. * @param[in] key the key to display * @param[in] buf the buffer to write into. Should always be #DKBUF. * @return The key in hexadecimal form. */ char * mdb_dkey(MDB_val *key, char *buf) { char *ptr = buf; unsigned char *c = key->mv_data; unsigned int i; if (!key) return ""; if (key->mv_size > DKBUF_MAXKEYSIZE) return "MDB_MAXKEYSIZE"; /* may want to make this a dynamic check: if the key is mostly * printable characters, print it as-is instead of converting to hex. */ #if 1 buf[0] = '\0'; for (i=0; imv_size; i++) ptr += sprintf(ptr, "%02x", *c++); #else sprintf(buf, "%.*s", key->mv_size, key->mv_data); #endif return buf; } static const char * mdb_leafnode_type(MDB_node *n) { static char *const tp[2][2] = {{"", ": DB"}, {": sub-page", ": sub-DB"}}; return F_ISSET(n->mn_flags, F_BIGDATA) ? ": overflow page" : tp[F_ISSET(n->mn_flags, F_DUPDATA)][F_ISSET(n->mn_flags, F_SUBDATA)]; } /** Display all the keys in the page. */ void mdb_page_list(MDB_page *mp) { pgno_t pgno = mdb_dbg_pgno(mp); const char *type, *state = (mp->mp_flags & P_DIRTY) ? ", dirty" : ""; MDB_node *node; unsigned int i, nkeys, nsize, total = 0; MDB_val key; DKBUF; switch (mp->mp_flags & (P_BRANCH|P_LEAF|P_LEAF2|P_META|P_OVERFLOW|P_SUBP)) { case P_BRANCH: type = "Branch page"; break; case P_LEAF: type = "Leaf page"; break; case P_LEAF|P_SUBP: type = "Sub-page"; break; case P_LEAF|P_LEAF2: type = "LEAF2 page"; break; case P_LEAF|P_LEAF2|P_SUBP: type = "LEAF2 sub-page"; break; case P_OVERFLOW: fprintf(stderr, "Overflow page %"Z"u pages %u%s\n", pgno, mp->mp_pages, state); return; case P_META: fprintf(stderr, "Meta-page %"Z"u txnid %"Z"u\n", pgno, ((MDB_meta *)METADATA(mp))->mm_txnid); return; default: fprintf(stderr, "Bad page %"Z"u flags 0x%X\n", pgno, mp->mp_flags); return; } nkeys = NUMKEYS(mp); fprintf(stderr, "%s %"Z"u numkeys %d%s\n", type, pgno, nkeys, state); for (i=0; imp_pad; key.mv_data = LEAF2KEY(mp, i, nsize); total += nsize; fprintf(stderr, "key %d: nsize %d, %s\n", i, nsize, DKEY(&key)); continue; } node = NODEPTR(mp, i); key.mv_size = node->mn_ksize; key.mv_data = node->mn_data; nsize = NODESIZE + key.mv_size; if (IS_BRANCH(mp)) { fprintf(stderr, "key %d: page %"Z"u, %s\n", i, NODEPGNO(node), DKEY(&key)); total += nsize; } else { if (F_ISSET(node->mn_flags, F_BIGDATA)) nsize += sizeof(pgno_t); else nsize += NODEDSZ(node); total += nsize; nsize += sizeof(indx_t); fprintf(stderr, "key %d: nsize %d, %s%s\n", i, nsize, DKEY(&key), mdb_leafnode_type(node)); } total = EVEN(total); } fprintf(stderr, "Total: header %d + contents %d + unused %d\n", IS_LEAF2(mp) ? PAGEHDRSZ : PAGEBASE + mp->mp_lower, total, SIZELEFT(mp)); } void mdb_cursor_chk(MDB_cursor *mc) { unsigned int i; MDB_node *node; MDB_page *mp; if (!mc->mc_snum || !(mc->mc_flags & C_INITIALIZED)) return; for (i=0; imc_top; i++) { mp = mc->mc_pg[i]; node = NODEPTR(mp, mc->mc_ki[i]); if (NODEPGNO(node) != mc->mc_pg[i+1]->mp_pgno) printf("oops!\n"); } if (mc->mc_ki[i] >= NUMKEYS(mc->mc_pg[i])) printf("ack!\n"); if (XCURSOR_INITED(mc)) { node = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); if (((node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA) && mc->mc_xcursor->mx_cursor.mc_pg[0] != NODEDATA(node)) { printf("blah!\n"); } } } #endif #if (MDB_DEBUG) > 2 /** Count all the pages in each DB and in the freelist * and make sure it matches the actual number of pages * being used. * All named DBs must be open for a correct count. */ static void mdb_audit(MDB_txn *txn) { MDB_cursor mc; MDB_val key, data; MDB_ID freecount, count; MDB_dbi i; int rc; freecount = 0; mdb_cursor_init(&mc, txn, FREE_DBI, NULL); while ((rc = mdb_cursor_get(&mc, &key, &data, MDB_NEXT)) == 0) freecount += *(MDB_ID *)data.mv_data; mdb_tassert(txn, rc == MDB_NOTFOUND); count = 0; for (i = 0; imt_numdbs; i++) { MDB_xcursor mx; if (!(txn->mt_dbflags[i] & DB_VALID)) continue; mdb_cursor_init(&mc, txn, i, &mx); if (txn->mt_dbs[i].md_root == P_INVALID) continue; count += txn->mt_dbs[i].md_branch_pages + txn->mt_dbs[i].md_leaf_pages + txn->mt_dbs[i].md_overflow_pages; if (txn->mt_dbs[i].md_flags & MDB_DUPSORT) { rc = mdb_page_search(&mc, NULL, MDB_PS_FIRST); for (; rc == MDB_SUCCESS; rc = mdb_cursor_sibling(&mc, 1)) { unsigned j; MDB_page *mp; mp = mc.mc_pg[mc.mc_top]; for (j=0; jmn_flags & F_SUBDATA) { MDB_db db; memcpy(&db, NODEDATA(leaf), sizeof(db)); count += db.md_branch_pages + db.md_leaf_pages + db.md_overflow_pages; } } } mdb_tassert(txn, rc == MDB_NOTFOUND); } } if (freecount + count + NUM_METAS != txn->mt_next_pgno) { fprintf(stderr, "audit: %"Z"u freecount: %"Z"u count: %"Z"u total: %"Z"u next_pgno: %"Z"u\n", txn->mt_txnid, freecount, count+NUM_METAS, freecount+count+NUM_METAS, txn->mt_next_pgno); } } #endif int mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b) { return txn->mt_dbxs[dbi].md_cmp(a, b); } int mdb_dcmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b) { MDB_cmp_func *dcmp = txn->mt_dbxs[dbi].md_dcmp; #if UINT_MAX < SIZE_MAX if (dcmp == mdb_cmp_int && a->mv_size == sizeof(size_t)) dcmp = mdb_cmp_clong; #endif return dcmp(a, b); } /** Allocate memory for a page. * Re-use old malloc'd pages first for singletons, otherwise just malloc. * Set #MDB_TXN_ERROR on failure. */ static MDB_page * mdb_page_malloc(MDB_txn *txn, unsigned num) { MDB_env *env = txn->mt_env; MDB_page *ret = env->me_dpages; size_t psize = env->me_psize, sz = psize, off; /* For ! #MDB_NOMEMINIT, psize counts how much to init. * For a single page alloc, we init everything after the page header. * For multi-page, we init the final page; if the caller needed that * many pages they will be filling in at least up to the last page. */ if (num == 1) { if (ret) { VGMEMP_ALLOC(env, ret, sz); VGMEMP_DEFINED(ret, sizeof(ret->mp_next)); env->me_dpages = ret->mp_next; return ret; } psize -= off = PAGEHDRSZ; } else { sz *= num; off = sz - psize; } if ((ret = malloc(sz)) != NULL) { VGMEMP_ALLOC(env, ret, sz); if (!(env->me_flags & MDB_NOMEMINIT)) { memset((char *)ret + off, 0, psize); ret->mp_pad = 0; } } else { txn->mt_flags |= MDB_TXN_ERROR; } return ret; } /** Free a single page. * Saves single pages to a list, for future reuse. * (This is not used for multi-page overflow pages.) */ static void mdb_page_free(MDB_env *env, MDB_page *mp) { mp->mp_next = env->me_dpages; VGMEMP_FREE(env, mp); env->me_dpages = mp; } /** Free a dirty page */ static void mdb_dpage_free(MDB_env *env, MDB_page *dp) { if (!IS_OVERFLOW(dp) || dp->mp_pages == 1) { mdb_page_free(env, dp); } else { /* large pages just get freed directly */ VGMEMP_FREE(env, dp); free(dp); } } /** Return all dirty pages to dpage list */ static void mdb_dlist_free(MDB_txn *txn) { MDB_env *env = txn->mt_env; MDB_ID2L dl = txn->mt_u.dirty_list; unsigned i, n = dl[0].mid; for (i = 1; i <= n; i++) { mdb_dpage_free(env, dl[i].mptr); } dl[0].mid = 0; } /** Loosen or free a single page. * Saves single pages to a list for future reuse * in this same txn. It has been pulled from the freeDB * and already resides on the dirty list, but has been * deleted. Use these pages first before pulling again * from the freeDB. * * If the page wasn't dirtied in this txn, just add it * to this txn's free list. */ static int mdb_page_loose(MDB_cursor *mc, MDB_page *mp) { int loose = 0; pgno_t pgno = mp->mp_pgno; MDB_txn *txn = mc->mc_txn; if ((mp->mp_flags & P_DIRTY) && mc->mc_dbi != FREE_DBI) { if (txn->mt_parent) { MDB_ID2 *dl = txn->mt_u.dirty_list; /* If txn has a parent, make sure the page is in our * dirty list. */ if (dl[0].mid) { unsigned x = mdb_mid2l_search(dl, pgno); if (x <= dl[0].mid && dl[x].mid == pgno) { if (mp != dl[x].mptr) { /* bad cursor? */ mc->mc_flags &= ~(C_INITIALIZED|C_EOF); txn->mt_flags |= MDB_TXN_ERROR; return MDB_CORRUPTED; } /* ok, it's ours */ loose = 1; } } } else { /* no parent txn, so it's just ours */ loose = 1; } } if (loose) { DPRINTF(("loosen db %d page %"Z"u", DDBI(mc), mp->mp_pgno)); NEXT_LOOSE_PAGE(mp) = txn->mt_loose_pgs; txn->mt_loose_pgs = mp; txn->mt_loose_count++; mp->mp_flags |= P_LOOSE; } else { int rc = mdb_midl_append(&txn->mt_free_pgs, pgno); if (rc) return rc; } return MDB_SUCCESS; } /** Set or clear P_KEEP in dirty, non-overflow, non-sub pages watched by txn. * @param[in] mc A cursor handle for the current operation. * @param[in] pflags Flags of the pages to update: * P_DIRTY to set P_KEEP, P_DIRTY|P_KEEP to clear it. * @param[in] all No shortcuts. Needed except after a full #mdb_page_flush(). * @return 0 on success, non-zero on failure. */ static int mdb_pages_xkeep(MDB_cursor *mc, unsigned pflags, int all) { enum { Mask = P_SUBP|P_DIRTY|P_LOOSE|P_KEEP }; MDB_txn *txn = mc->mc_txn; MDB_cursor *m3, *m0 = mc; MDB_xcursor *mx; MDB_page *dp, *mp; MDB_node *leaf; unsigned i, j; int rc = MDB_SUCCESS, level; /* Mark pages seen by cursors */ if (mc->mc_flags & C_UNTRACK) mc = NULL; /* will find mc in mt_cursors */ for (i = txn->mt_numdbs;; mc = txn->mt_cursors[--i]) { for (; mc; mc=mc->mc_next) { if (!(mc->mc_flags & C_INITIALIZED)) continue; for (m3 = mc;; m3 = &mx->mx_cursor) { mp = NULL; for (j=0; jmc_snum; j++) { mp = m3->mc_pg[j]; if ((mp->mp_flags & Mask) == pflags) mp->mp_flags ^= P_KEEP; } mx = m3->mc_xcursor; /* Proceed to mx if it is at a sub-database */ if (! (mx && (mx->mx_cursor.mc_flags & C_INITIALIZED))) break; if (! (mp && (mp->mp_flags & P_LEAF))) break; leaf = NODEPTR(mp, m3->mc_ki[j-1]); if (!(leaf->mn_flags & F_SUBDATA)) break; } } if (i == 0) break; } if (all) { /* Mark dirty root pages */ for (i=0; imt_numdbs; i++) { if (txn->mt_dbflags[i] & DB_DIRTY) { pgno_t pgno = txn->mt_dbs[i].md_root; if (pgno == P_INVALID) continue; if ((rc = mdb_page_get(m0, pgno, &dp, &level)) != MDB_SUCCESS) break; if ((dp->mp_flags & Mask) == pflags && level <= 1) dp->mp_flags ^= P_KEEP; } } } return rc; } static int mdb_page_flush(MDB_txn *txn, int keep); /** Spill pages from the dirty list back to disk. * This is intended to prevent running into #MDB_TXN_FULL situations, * but note that they may still occur in a few cases: * 1) our estimate of the txn size could be too small. Currently this * seems unlikely, except with a large number of #MDB_MULTIPLE items. * 2) child txns may run out of space if their parents dirtied a * lot of pages and never spilled them. TODO: we probably should do * a preemptive spill during #mdb_txn_begin() of a child txn, if * the parent's dirty_room is below a given threshold. * * Otherwise, if not using nested txns, it is expected that apps will * not run into #MDB_TXN_FULL any more. The pages are flushed to disk * the same way as for a txn commit, e.g. their P_DIRTY flag is cleared. * If the txn never references them again, they can be left alone. * If the txn only reads them, they can be used without any fuss. * If the txn writes them again, they can be dirtied immediately without * going thru all of the work of #mdb_page_touch(). Such references are * handled by #mdb_page_unspill(). * * Also note, we never spill DB root pages, nor pages of active cursors, * because we'll need these back again soon anyway. And in nested txns, * we can't spill a page in a child txn if it was already spilled in a * parent txn. That would alter the parent txns' data even though * the child hasn't committed yet, and we'd have no way to undo it if * the child aborted. * * @param[in] m0 cursor A cursor handle identifying the transaction and * database for which we are checking space. * @param[in] key For a put operation, the key being stored. * @param[in] data For a put operation, the data being stored. * @return 0 on success, non-zero on failure. */ static int mdb_page_spill(MDB_cursor *m0, MDB_val *key, MDB_val *data) { MDB_txn *txn = m0->mc_txn; MDB_page *dp; MDB_ID2L dl = txn->mt_u.dirty_list; unsigned int i, j, need; int rc; if (m0->mc_flags & C_SUB) return MDB_SUCCESS; /* Estimate how much space this op will take */ i = m0->mc_db->md_depth; /* Named DBs also dirty the main DB */ if (m0->mc_dbi >= CORE_DBS) i += txn->mt_dbs[MAIN_DBI].md_depth; /* For puts, roughly factor in the key+data size */ if (key) i += (LEAFSIZE(key, data) + txn->mt_env->me_psize) / txn->mt_env->me_psize; i += i; /* double it for good measure */ need = i; if (txn->mt_dirty_room > i) return MDB_SUCCESS; if (!txn->mt_spill_pgs) { txn->mt_spill_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX); if (!txn->mt_spill_pgs) return ENOMEM; } else { /* purge deleted slots */ MDB_IDL sl = txn->mt_spill_pgs; unsigned int num = sl[0]; j=0; for (i=1; i<=num; i++) { if (!(sl[i] & 1)) sl[++j] = sl[i]; } sl[0] = j; } /* Preserve pages which may soon be dirtied again */ if ((rc = mdb_pages_xkeep(m0, P_DIRTY, 1)) != MDB_SUCCESS) goto done; /* Less aggressive spill - we originally spilled the entire dirty list, * with a few exceptions for cursor pages and DB root pages. But this * turns out to be a lot of wasted effort because in a large txn many * of those pages will need to be used again. So now we spill only 1/8th * of the dirty pages. Testing revealed this to be a good tradeoff, * better than 1/2, 1/4, or 1/10. */ if (need < MDB_IDL_UM_MAX / 8) need = MDB_IDL_UM_MAX / 8; /* Save the page IDs of all the pages we're flushing */ /* flush from the tail forward, this saves a lot of shifting later on. */ for (i=dl[0].mid; i && need; i--) { MDB_ID pn = dl[i].mid << 1; dp = dl[i].mptr; if (dp->mp_flags & (P_LOOSE|P_KEEP)) continue; /* Can't spill twice, make sure it's not already in a parent's * spill list. */ if (txn->mt_parent) { MDB_txn *tx2; for (tx2 = txn->mt_parent; tx2; tx2 = tx2->mt_parent) { if (tx2->mt_spill_pgs) { j = mdb_midl_search(tx2->mt_spill_pgs, pn); if (j <= tx2->mt_spill_pgs[0] && tx2->mt_spill_pgs[j] == pn) { dp->mp_flags |= P_KEEP; break; } } } if (tx2) continue; } if ((rc = mdb_midl_append(&txn->mt_spill_pgs, pn))) goto done; need--; } mdb_midl_sort(txn->mt_spill_pgs); /* Flush the spilled part of dirty list */ if ((rc = mdb_page_flush(txn, i)) != MDB_SUCCESS) goto done; /* Reset any dirty pages we kept that page_flush didn't see */ rc = mdb_pages_xkeep(m0, P_DIRTY|P_KEEP, i); done: txn->mt_flags |= rc ? MDB_TXN_ERROR : MDB_TXN_SPILLS; return rc; } /** Find oldest txnid still referenced. Expects txn->mt_txnid > 0. */ static txnid_t mdb_find_oldest(MDB_txn *txn) { int i; txnid_t mr, oldest = txn->mt_txnid - 1; if (txn->mt_env->me_txns) { MDB_reader *r = txn->mt_env->me_txns->mti_readers; for (i = txn->mt_env->me_txns->mti_numreaders; --i >= 0; ) { if (r[i].mr_pid) { mr = r[i].mr_txnid; if (oldest > mr) oldest = mr; } } } return oldest; } /** Add a page to the txn's dirty list */ static void mdb_page_dirty(MDB_txn *txn, MDB_page *mp) { MDB_ID2 mid; int rc, (*insert)(MDB_ID2L, MDB_ID2 *); if (txn->mt_flags & MDB_TXN_WRITEMAP) { insert = mdb_mid2l_append; } else { insert = mdb_mid2l_insert; } mid.mid = mp->mp_pgno; mid.mptr = mp; rc = insert(txn->mt_u.dirty_list, &mid); mdb_tassert(txn, rc == 0); txn->mt_dirty_room--; } /** Allocate page numbers and memory for writing. Maintain me_pglast, * me_pghead and mt_next_pgno. Set #MDB_TXN_ERROR on failure. * * If there are free pages available from older transactions, they * are re-used first. Otherwise allocate a new page at mt_next_pgno. * Do not modify the freedB, just merge freeDB records into me_pghead[] * and move me_pglast to say which records were consumed. Only this * function can create me_pghead and move me_pglast/mt_next_pgno. * @param[in] mc cursor A cursor handle identifying the transaction and * database for which we are allocating. * @param[in] num the number of pages to allocate. * @param[out] mp Address of the allocated page(s). Requests for multiple pages * will always be satisfied by a single contiguous chunk of memory. * @return 0 on success, non-zero on failure. */ static int mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp) { #ifdef MDB_PARANOID /* Seems like we can ignore this now */ /* Get at most more freeDB records once me_pghead * has enough pages. If not enough, use new pages from the map. * If and mc is updating the freeDB, only get new * records if me_pghead is empty. Then the freelist cannot play * catch-up with itself by growing while trying to save it. */ enum { Paranoid = 1, Max_retries = 500 }; #else enum { Paranoid = 0, Max_retries = INT_MAX /*infinite*/ }; #endif int rc, retry = num * 60; MDB_txn *txn = mc->mc_txn; MDB_env *env = txn->mt_env; pgno_t pgno, *mop = env->me_pghead; unsigned i, j, mop_len = mop ? mop[0] : 0, n2 = num-1; MDB_page *np; txnid_t oldest = 0, last; MDB_cursor_op op; MDB_cursor m2; int found_old = 0; /* If there are any loose pages, just use them */ if (num == 1 && txn->mt_loose_pgs) { np = txn->mt_loose_pgs; txn->mt_loose_pgs = NEXT_LOOSE_PAGE(np); txn->mt_loose_count--; DPRINTF(("db %d use loose page %"Z"u", DDBI(mc), np->mp_pgno)); *mp = np; return MDB_SUCCESS; } *mp = NULL; /* If our dirty list is already full, we can't do anything */ if (txn->mt_dirty_room == 0) { rc = MDB_TXN_FULL; goto fail; } for (op = MDB_FIRST;; op = MDB_NEXT) { MDB_val key, data; MDB_node *leaf; pgno_t *idl; /* Seek a big enough contiguous page range. Prefer * pages at the tail, just truncating the list. */ if (mop_len > n2) { i = mop_len; do { pgno = mop[i]; if (mop[i-n2] == pgno+n2) goto search_done; } while (--i > n2); if (--retry < 0) break; } if (op == MDB_FIRST) { /* 1st iteration */ /* Prepare to fetch more and coalesce */ last = env->me_pglast; oldest = env->me_pgoldest; mdb_cursor_init(&m2, txn, FREE_DBI, NULL); if (last) { op = MDB_SET_RANGE; key.mv_data = &last; /* will look up last+1 */ key.mv_size = sizeof(last); } if (Paranoid && mc->mc_dbi == FREE_DBI) retry = -1; } if (Paranoid && retry < 0 && mop_len) break; last++; /* Do not fetch more if the record will be too recent */ if (oldest <= last) { if (!found_old) { oldest = mdb_find_oldest(txn); env->me_pgoldest = oldest; found_old = 1; } if (oldest <= last) break; } rc = mdb_cursor_get(&m2, &key, NULL, op); if (rc) { if (rc == MDB_NOTFOUND) break; goto fail; } last = *(txnid_t*)key.mv_data; if (oldest <= last) { if (!found_old) { oldest = mdb_find_oldest(txn); env->me_pgoldest = oldest; found_old = 1; } if (oldest <= last) break; } np = m2.mc_pg[m2.mc_top]; leaf = NODEPTR(np, m2.mc_ki[m2.mc_top]); if ((rc = mdb_node_read(&m2, leaf, &data)) != MDB_SUCCESS) goto fail; idl = (MDB_ID *) data.mv_data; i = idl[0]; if (!mop) { if (!(env->me_pghead = mop = mdb_midl_alloc(i))) { rc = ENOMEM; goto fail; } } else { if ((rc = mdb_midl_need(&env->me_pghead, i)) != 0) goto fail; mop = env->me_pghead; } env->me_pglast = last; #if (MDB_DEBUG) > 1 DPRINTF(("IDL read txn %"Z"u root %"Z"u num %u", last, txn->mt_dbs[FREE_DBI].md_root, i)); for (j = i; j; j--) DPRINTF(("IDL %"Z"u", idl[j])); #endif /* Merge in descending sorted order */ mdb_midl_xmerge(mop, idl); mop_len = mop[0]; } /* Use new pages from the map when nothing suitable in the freeDB */ i = 0; pgno = txn->mt_next_pgno; if (pgno + num >= env->me_maxpg) { DPUTS("DB size maxed out"); rc = MDB_MAP_FULL; goto fail; } search_done: if (env->me_flags & MDB_WRITEMAP) { np = (MDB_page *)(env->me_map + env->me_psize * pgno); } else { if (!(np = mdb_page_malloc(txn, num))) { rc = ENOMEM; goto fail; } } if (i) { mop[0] = mop_len -= num; /* Move any stragglers down */ for (j = i-num; j < mop_len; ) mop[++j] = mop[++i]; } else { txn->mt_next_pgno = pgno + num; } np->mp_pgno = pgno; mdb_page_dirty(txn, np); *mp = np; return MDB_SUCCESS; fail: txn->mt_flags |= MDB_TXN_ERROR; return rc; } /** Copy the used portions of a non-overflow page. * @param[in] dst page to copy into * @param[in] src page to copy from * @param[in] psize size of a page */ static void mdb_page_copy(MDB_page *dst, MDB_page *src, unsigned int psize) { enum { Align = sizeof(pgno_t) }; indx_t upper = src->mp_upper, lower = src->mp_lower, unused = upper-lower; /* If page isn't full, just copy the used portion. Adjust * alignment so memcpy may copy words instead of bytes. */ if ((unused &= -Align) && !IS_LEAF2(src)) { upper = (upper + PAGEBASE) & -Align; memcpy(dst, src, (lower + PAGEBASE + (Align-1)) & -Align); memcpy((pgno_t *)((char *)dst+upper), (pgno_t *)((char *)src+upper), psize - upper); } else { memcpy(dst, src, psize - unused); } } /** Pull a page off the txn's spill list, if present. * If a page being referenced was spilled to disk in this txn, bring * it back and make it dirty/writable again. * @param[in] txn the transaction handle. * @param[in] mp the page being referenced. It must not be dirty. * @param[out] ret the writable page, if any. ret is unchanged if * mp wasn't spilled. */ static int mdb_page_unspill(MDB_txn *txn, MDB_page *mp, MDB_page **ret) { MDB_env *env = txn->mt_env; const MDB_txn *tx2; unsigned x; pgno_t pgno = mp->mp_pgno, pn = pgno << 1; for (tx2 = txn; tx2; tx2=tx2->mt_parent) { if (!tx2->mt_spill_pgs) continue; x = mdb_midl_search(tx2->mt_spill_pgs, pn); if (x <= tx2->mt_spill_pgs[0] && tx2->mt_spill_pgs[x] == pn) { MDB_page *np; int num; if (txn->mt_dirty_room == 0) return MDB_TXN_FULL; if (IS_OVERFLOW(mp)) num = mp->mp_pages; else num = 1; if (env->me_flags & MDB_WRITEMAP) { np = mp; } else { np = mdb_page_malloc(txn, num); if (!np) return ENOMEM; if (num > 1) memcpy(np, mp, num * env->me_psize); else mdb_page_copy(np, mp, env->me_psize); } if (tx2 == txn) { /* If in current txn, this page is no longer spilled. * If it happens to be the last page, truncate the spill list. * Otherwise mark it as deleted by setting the LSB. */ if (x == txn->mt_spill_pgs[0]) txn->mt_spill_pgs[0]--; else txn->mt_spill_pgs[x] |= 1; } /* otherwise, if belonging to a parent txn, the * page remains spilled until child commits */ mdb_page_dirty(txn, np); np->mp_flags |= P_DIRTY; *ret = np; break; } } return MDB_SUCCESS; } /** Touch a page: make it dirty and re-insert into tree with updated pgno. * Set #MDB_TXN_ERROR on failure. * @param[in] mc cursor pointing to the page to be touched * @return 0 on success, non-zero on failure. */ static int mdb_page_touch(MDB_cursor *mc) { MDB_page *mp = mc->mc_pg[mc->mc_top], *np; MDB_txn *txn = mc->mc_txn; MDB_cursor *m2, *m3; pgno_t pgno; int rc; if (!F_ISSET(mp->mp_flags, P_DIRTY)) { if (txn->mt_flags & MDB_TXN_SPILLS) { np = NULL; rc = mdb_page_unspill(txn, mp, &np); if (rc) goto fail; if (np) goto done; } if ((rc = mdb_midl_need(&txn->mt_free_pgs, 1)) || (rc = mdb_page_alloc(mc, 1, &np))) goto fail; pgno = np->mp_pgno; DPRINTF(("touched db %d page %"Z"u -> %"Z"u", DDBI(mc), mp->mp_pgno, pgno)); mdb_cassert(mc, mp->mp_pgno != pgno); mdb_midl_xappend(txn->mt_free_pgs, mp->mp_pgno); /* Update the parent page, if any, to point to the new page */ if (mc->mc_top) { MDB_page *parent = mc->mc_pg[mc->mc_top-1]; MDB_node *node = NODEPTR(parent, mc->mc_ki[mc->mc_top-1]); SETPGNO(node, pgno); } else { mc->mc_db->md_root = pgno; } } else if (txn->mt_parent && !IS_SUBP(mp)) { MDB_ID2 mid, *dl = txn->mt_u.dirty_list; pgno = mp->mp_pgno; /* If txn has a parent, make sure the page is in our * dirty list. */ if (dl[0].mid) { unsigned x = mdb_mid2l_search(dl, pgno); if (x <= dl[0].mid && dl[x].mid == pgno) { if (mp != dl[x].mptr) { /* bad cursor? */ mc->mc_flags &= ~(C_INITIALIZED|C_EOF); txn->mt_flags |= MDB_TXN_ERROR; return MDB_CORRUPTED; } return 0; } } mdb_cassert(mc, dl[0].mid < MDB_IDL_UM_MAX); /* No - copy it */ np = mdb_page_malloc(txn, 1); if (!np) return ENOMEM; mid.mid = pgno; mid.mptr = np; rc = mdb_mid2l_insert(dl, &mid); mdb_cassert(mc, rc == 0); } else { return 0; } mdb_page_copy(np, mp, txn->mt_env->me_psize); np->mp_pgno = pgno; np->mp_flags |= P_DIRTY; done: /* Adjust cursors pointing to mp */ mc->mc_pg[mc->mc_top] = np; m2 = txn->mt_cursors[mc->mc_dbi]; if (mc->mc_flags & C_SUB) { for (; m2; m2=m2->mc_next) { m3 = &m2->mc_xcursor->mx_cursor; if (m3->mc_snum < mc->mc_snum) continue; if (m3->mc_pg[mc->mc_top] == mp) m3->mc_pg[mc->mc_top] = np; } } else { for (; m2; m2=m2->mc_next) { if (m2->mc_snum < mc->mc_snum) continue; if (m2 == mc) continue; if (m2->mc_pg[mc->mc_top] == mp) { m2->mc_pg[mc->mc_top] = np; if (IS_LEAF(np)) XCURSOR_REFRESH(m2, mc->mc_top, np); } } } return 0; fail: txn->mt_flags |= MDB_TXN_ERROR; return rc; } int mdb_env_sync(MDB_env *env, int force) { int rc = 0; if (env->me_flags & MDB_RDONLY) return EACCES; if (force || !F_ISSET(env->me_flags, MDB_NOSYNC)) { if (env->me_flags & MDB_WRITEMAP) { int flags = ((env->me_flags & MDB_MAPASYNC) && !force) ? MS_ASYNC : MS_SYNC; if (MDB_MSYNC(env->me_map, env->me_mapsize, flags)) rc = ErrCode(); #ifdef _WIN32 else if (flags == MS_SYNC && MDB_FDATASYNC(env->me_fd)) rc = ErrCode(); #endif } else { #ifdef BROKEN_FDATASYNC if (env->me_flags & MDB_FSYNCONLY) { if (fsync(env->me_fd)) rc = ErrCode(); } else #endif if (MDB_FDATASYNC(env->me_fd)) rc = ErrCode(); } } return rc; } /** Back up parent txn's cursors, then grab the originals for tracking */ static int mdb_cursor_shadow(MDB_txn *src, MDB_txn *dst) { MDB_cursor *mc, *bk; MDB_xcursor *mx; size_t size; int i; for (i = src->mt_numdbs; --i >= 0; ) { if ((mc = src->mt_cursors[i]) != NULL) { size = sizeof(MDB_cursor); if (mc->mc_xcursor) size += sizeof(MDB_xcursor); for (; mc; mc = bk->mc_next) { bk = malloc(size); if (!bk) return ENOMEM; *bk = *mc; mc->mc_backup = bk; mc->mc_db = &dst->mt_dbs[i]; /* Kill pointers into src to reduce abuse: The * user may not use mc until dst ends. But we need a valid * txn pointer here for cursor fixups to keep working. */ mc->mc_txn = dst; mc->mc_dbflag = &dst->mt_dbflags[i]; if ((mx = mc->mc_xcursor) != NULL) { *(MDB_xcursor *)(bk+1) = *mx; mx->mx_cursor.mc_txn = dst; } mc->mc_next = dst->mt_cursors[i]; dst->mt_cursors[i] = mc; } } } return MDB_SUCCESS; } /** Close this write txn's cursors, give parent txn's cursors back to parent. * @param[in] txn the transaction handle. * @param[in] merge true to keep changes to parent cursors, false to revert. * @return 0 on success, non-zero on failure. */ static void mdb_cursors_close(MDB_txn *txn, unsigned merge) { MDB_cursor **cursors = txn->mt_cursors, *mc, *next, *bk; MDB_xcursor *mx; int i; for (i = txn->mt_numdbs; --i >= 0; ) { for (mc = cursors[i]; mc; mc = next) { next = mc->mc_next; if ((bk = mc->mc_backup) != NULL) { if (merge) { /* Commit changes to parent txn */ mc->mc_next = bk->mc_next; mc->mc_backup = bk->mc_backup; mc->mc_txn = bk->mc_txn; mc->mc_db = bk->mc_db; mc->mc_dbflag = bk->mc_dbflag; if ((mx = mc->mc_xcursor) != NULL) mx->mx_cursor.mc_txn = bk->mc_txn; } else { /* Abort nested txn */ *mc = *bk; if ((mx = mc->mc_xcursor) != NULL) *mx = *(MDB_xcursor *)(bk+1); } mc = bk; } /* Only malloced cursors are permanently tracked. */ free(mc); } cursors[i] = NULL; } } #if !(MDB_PIDLOCK) /* Currently the same as defined(_WIN32) */ enum Pidlock_op { Pidset, Pidcheck }; #else enum Pidlock_op { Pidset = F_SETLK, Pidcheck = F_GETLK }; #endif /** Set or check a pid lock. Set returns 0 on success. * Check returns 0 if the process is certainly dead, nonzero if it may * be alive (the lock exists or an error happened so we do not know). * * On Windows Pidset is a no-op, we merely check for the existence * of the process with the given pid. On POSIX we use a single byte * lock on the lockfile, set at an offset equal to the pid. */ static int mdb_reader_pid(MDB_env *env, enum Pidlock_op op, MDB_PID_T pid) { #if !(MDB_PIDLOCK) /* Currently the same as defined(_WIN32) */ int ret = 0; HANDLE h; if (op == Pidcheck) { h = OpenProcess(env->me_pidquery, FALSE, pid); /* No documented "no such process" code, but other program use this: */ if (!h) return ErrCode() != ERROR_INVALID_PARAMETER; /* A process exists until all handles to it close. Has it exited? */ ret = WaitForSingleObject(h, 0) != 0; CloseHandle(h); } return ret; #else for (;;) { int rc; struct flock lock_info; memset(&lock_info, 0, sizeof(lock_info)); lock_info.l_type = F_WRLCK; lock_info.l_whence = SEEK_SET; lock_info.l_start = pid; lock_info.l_len = 1; if ((rc = fcntl(env->me_lfd, op, &lock_info)) == 0) { if (op == F_GETLK && lock_info.l_type != F_UNLCK) rc = -1; } else if ((rc = ErrCode()) == EINTR) { continue; } return rc; } #endif } /** Common code for #mdb_txn_begin() and #mdb_txn_renew(). * @param[in] txn the transaction handle to initialize * @return 0 on success, non-zero on failure. */ static int mdb_txn_renew0(MDB_txn *txn) { MDB_env *env = txn->mt_env; MDB_txninfo *ti = env->me_txns; MDB_meta *meta; unsigned int i, nr, flags = txn->mt_flags; uint16_t x; int rc, new_notls = 0; if ((flags &= MDB_TXN_RDONLY) != 0) { if (!ti) { meta = mdb_env_pick_meta(env); txn->mt_txnid = meta->mm_txnid; txn->mt_u.reader = NULL; } else { MDB_reader *r = (env->me_flags & MDB_NOTLS) ? txn->mt_u.reader : pthread_getspecific(env->me_txkey); if (r) { if (r->mr_pid != env->me_pid || r->mr_txnid != (txnid_t)-1) return MDB_BAD_RSLOT; } else { MDB_PID_T pid = env->me_pid; MDB_THR_T tid = pthread_self(); mdb_mutexref_t rmutex = env->me_rmutex; if (!env->me_live_reader) { rc = mdb_reader_pid(env, Pidset, pid); if (rc) return rc; env->me_live_reader = 1; } if (LOCK_MUTEX(rc, env, rmutex)) return rc; nr = ti->mti_numreaders; for (i=0; imti_readers[i].mr_pid == 0) break; if (i == env->me_maxreaders) { UNLOCK_MUTEX(rmutex); return MDB_READERS_FULL; } r = &ti->mti_readers[i]; /* Claim the reader slot, carefully since other code * uses the reader table un-mutexed: First reset the * slot, next publish it in mti_numreaders. After * that, it is safe for mdb_env_close() to touch it. * When it will be closed, we can finally claim it. */ r->mr_pid = 0; r->mr_txnid = (txnid_t)-1; r->mr_tid = tid; if (i == nr) ti->mti_numreaders = ++nr; env->me_close_readers = nr; r->mr_pid = pid; UNLOCK_MUTEX(rmutex); new_notls = (env->me_flags & MDB_NOTLS); if (!new_notls && (rc=pthread_setspecific(env->me_txkey, r))) { r->mr_pid = 0; return rc; } } do /* LY: Retry on a race, ITS#7970. */ r->mr_txnid = ti->mti_txnid; while(r->mr_txnid != ti->mti_txnid); txn->mt_txnid = r->mr_txnid; txn->mt_u.reader = r; meta = env->me_metas[txn->mt_txnid & 1]; } } else { /* Not yet touching txn == env->me_txn0, it may be active */ if (ti) { if (LOCK_MUTEX(rc, env, env->me_wmutex)) return rc; txn->mt_txnid = ti->mti_txnid; meta = env->me_metas[txn->mt_txnid & 1]; } else { meta = mdb_env_pick_meta(env); txn->mt_txnid = meta->mm_txnid; } txn->mt_txnid++; #if MDB_DEBUG if (txn->mt_txnid == mdb_debug_start) mdb_debug = 1; #endif txn->mt_child = NULL; txn->mt_loose_pgs = NULL; txn->mt_loose_count = 0; txn->mt_dirty_room = MDB_IDL_UM_MAX; txn->mt_u.dirty_list = env->me_dirty_list; txn->mt_u.dirty_list[0].mid = 0; txn->mt_free_pgs = env->me_free_pgs; txn->mt_free_pgs[0] = 0; txn->mt_spill_pgs = NULL; env->me_txn = txn; memcpy(txn->mt_dbiseqs, env->me_dbiseqs, env->me_maxdbs * sizeof(unsigned int)); } /* Copy the DB info and flags */ memcpy(txn->mt_dbs, meta->mm_dbs, CORE_DBS * sizeof(MDB_db)); /* Moved to here to avoid a data race in read TXNs */ txn->mt_next_pgno = meta->mm_last_pg+1; txn->mt_flags = flags; /* Setup db info */ txn->mt_numdbs = env->me_numdbs; for (i=CORE_DBS; imt_numdbs; i++) { x = env->me_dbflags[i]; txn->mt_dbs[i].md_flags = x & PERSISTENT_FLAGS; txn->mt_dbflags[i] = (x & MDB_VALID) ? DB_VALID|DB_USRVALID|DB_STALE : 0; } txn->mt_dbflags[MAIN_DBI] = DB_VALID|DB_USRVALID; txn->mt_dbflags[FREE_DBI] = DB_VALID; if (env->me_flags & MDB_FATAL_ERROR) { DPUTS("environment had fatal error, must shutdown!"); rc = MDB_PANIC; } else if (env->me_maxpg < txn->mt_next_pgno) { rc = MDB_MAP_RESIZED; } else { return MDB_SUCCESS; } mdb_txn_end(txn, new_notls /*0 or MDB_END_SLOT*/ | MDB_END_FAIL_BEGIN); return rc; } int mdb_txn_renew(MDB_txn *txn) { int rc; if (!txn || !F_ISSET(txn->mt_flags, MDB_TXN_RDONLY|MDB_TXN_FINISHED)) return EINVAL; rc = mdb_txn_renew0(txn); if (rc == MDB_SUCCESS) { DPRINTF(("renew txn %"Z"u%c %p on mdbenv %p, root page %"Z"u", txn->mt_txnid, (txn->mt_flags & MDB_TXN_RDONLY) ? 'r' : 'w', (void *)txn, (void *)txn->mt_env, txn->mt_dbs[MAIN_DBI].md_root)); } return rc; } int mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **ret) { MDB_txn *txn; MDB_ntxn *ntxn; int rc, size, tsize; flags &= MDB_TXN_BEGIN_FLAGS; flags |= env->me_flags & MDB_WRITEMAP; if (env->me_flags & MDB_RDONLY & ~flags) /* write txn in RDONLY env */ return EACCES; if (parent) { /* Nested transactions: Max 1 child, write txns only, no writemap */ flags |= parent->mt_flags; if (flags & (MDB_RDONLY|MDB_WRITEMAP|MDB_TXN_BLOCKED)) { return (parent->mt_flags & MDB_TXN_RDONLY) ? EINVAL : MDB_BAD_TXN; } /* Child txns save MDB_pgstate and use own copy of cursors */ size = env->me_maxdbs * (sizeof(MDB_db)+sizeof(MDB_cursor *)+1); size += tsize = sizeof(MDB_ntxn); } else if (flags & MDB_RDONLY) { size = env->me_maxdbs * (sizeof(MDB_db)+1); size += tsize = sizeof(MDB_txn); } else { /* Reuse preallocated write txn. However, do not touch it until * mdb_txn_renew0() succeeds, since it currently may be active. */ txn = env->me_txn0; goto renew; } if ((txn = calloc(1, size)) == NULL) { DPRINTF(("calloc: %s", strerror(errno))); return ENOMEM; } txn->mt_dbxs = env->me_dbxs; /* static */ txn->mt_dbs = (MDB_db *) ((char *)txn + tsize); txn->mt_dbflags = (unsigned char *)txn + size - env->me_maxdbs; txn->mt_flags = flags; txn->mt_env = env; if (parent) { unsigned int i; txn->mt_cursors = (MDB_cursor **)(txn->mt_dbs + env->me_maxdbs); txn->mt_dbiseqs = parent->mt_dbiseqs; txn->mt_u.dirty_list = malloc(sizeof(MDB_ID2)*MDB_IDL_UM_SIZE); if (!txn->mt_u.dirty_list || !(txn->mt_free_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX))) { free(txn->mt_u.dirty_list); free(txn); return ENOMEM; } txn->mt_txnid = parent->mt_txnid; txn->mt_dirty_room = parent->mt_dirty_room; txn->mt_u.dirty_list[0].mid = 0; txn->mt_spill_pgs = NULL; txn->mt_next_pgno = parent->mt_next_pgno; parent->mt_flags |= MDB_TXN_HAS_CHILD; parent->mt_child = txn; txn->mt_parent = parent; txn->mt_numdbs = parent->mt_numdbs; memcpy(txn->mt_dbs, parent->mt_dbs, txn->mt_numdbs * sizeof(MDB_db)); /* Copy parent's mt_dbflags, but clear DB_NEW */ for (i=0; imt_numdbs; i++) txn->mt_dbflags[i] = parent->mt_dbflags[i] & ~DB_NEW; rc = 0; ntxn = (MDB_ntxn *)txn; ntxn->mnt_pgstate = env->me_pgstate; /* save parent me_pghead & co */ if (env->me_pghead) { size = MDB_IDL_SIZEOF(env->me_pghead); env->me_pghead = mdb_midl_alloc(env->me_pghead[0]); if (env->me_pghead) memcpy(env->me_pghead, ntxn->mnt_pgstate.mf_pghead, size); else rc = ENOMEM; } if (!rc) rc = mdb_cursor_shadow(parent, txn); if (rc) mdb_txn_end(txn, MDB_END_FAIL_BEGINCHILD); } else { /* MDB_RDONLY */ txn->mt_dbiseqs = env->me_dbiseqs; renew: rc = mdb_txn_renew0(txn); } if (rc) { if (txn != env->me_txn0) free(txn); } else { txn->mt_flags |= flags; /* could not change txn=me_txn0 earlier */ *ret = txn; DPRINTF(("begin txn %"Z"u%c %p on mdbenv %p, root page %"Z"u", txn->mt_txnid, (flags & MDB_RDONLY) ? 'r' : 'w', (void *) txn, (void *) env, txn->mt_dbs[MAIN_DBI].md_root)); } return rc; } MDB_env * mdb_txn_env(MDB_txn *txn) { if(!txn) return NULL; return txn->mt_env; } size_t mdb_txn_id(MDB_txn *txn) { if(!txn) return 0; return txn->mt_txnid; } /** Export or close DBI handles opened in this txn. */ static void mdb_dbis_update(MDB_txn *txn, int keep) { int i; MDB_dbi n = txn->mt_numdbs; MDB_env *env = txn->mt_env; unsigned char *tdbflags = txn->mt_dbflags; for (i = n; --i >= CORE_DBS;) { if (tdbflags[i] & DB_NEW) { if (keep) { env->me_dbflags[i] = txn->mt_dbs[i].md_flags | MDB_VALID; } else { char *ptr = env->me_dbxs[i].md_name.mv_data; if (ptr) { env->me_dbxs[i].md_name.mv_data = NULL; env->me_dbxs[i].md_name.mv_size = 0; env->me_dbflags[i] = 0; env->me_dbiseqs[i]++; free(ptr); } } } } if (keep && env->me_numdbs < n) env->me_numdbs = n; } /** End a transaction, except successful commit of a nested transaction. * May be called twice for readonly txns: First reset it, then abort. * @param[in] txn the transaction handle to end * @param[in] mode why and how to end the transaction */ static void mdb_txn_end(MDB_txn *txn, unsigned mode) { MDB_env *env = txn->mt_env; #if MDB_DEBUG static const char *const names[] = MDB_END_NAMES; #endif /* Export or close DBI handles opened in this txn */ mdb_dbis_update(txn, mode & MDB_END_UPDATE); DPRINTF(("%s txn %"Z"u%c %p on mdbenv %p, root page %"Z"u", names[mode & MDB_END_OPMASK], txn->mt_txnid, (txn->mt_flags & MDB_TXN_RDONLY) ? 'r' : 'w', (void *) txn, (void *)env, txn->mt_dbs[MAIN_DBI].md_root)); if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) { if (txn->mt_u.reader) { txn->mt_u.reader->mr_txnid = (txnid_t)-1; if (!(env->me_flags & MDB_NOTLS)) { txn->mt_u.reader = NULL; /* txn does not own reader */ } else if (mode & MDB_END_SLOT) { txn->mt_u.reader->mr_pid = 0; txn->mt_u.reader = NULL; } /* else txn owns the slot until it does MDB_END_SLOT */ } txn->mt_numdbs = 0; /* prevent further DBI activity */ txn->mt_flags |= MDB_TXN_FINISHED; } else if (!F_ISSET(txn->mt_flags, MDB_TXN_FINISHED)) { pgno_t *pghead = env->me_pghead; if (!(mode & MDB_END_UPDATE)) /* !(already closed cursors) */ mdb_cursors_close(txn, 0); if (!(env->me_flags & MDB_WRITEMAP)) { mdb_dlist_free(txn); } txn->mt_numdbs = 0; txn->mt_flags = MDB_TXN_FINISHED; if (!txn->mt_parent) { mdb_midl_shrink(&txn->mt_free_pgs); env->me_free_pgs = txn->mt_free_pgs; /* me_pgstate: */ env->me_pghead = NULL; env->me_pglast = 0; env->me_txn = NULL; mode = 0; /* txn == env->me_txn0, do not free() it */ /* The writer mutex was locked in mdb_txn_begin. */ if (env->me_txns) UNLOCK_MUTEX(env->me_wmutex); } else { txn->mt_parent->mt_child = NULL; txn->mt_parent->mt_flags &= ~MDB_TXN_HAS_CHILD; env->me_pgstate = ((MDB_ntxn *)txn)->mnt_pgstate; mdb_midl_free(txn->mt_free_pgs); free(txn->mt_u.dirty_list); } mdb_midl_free(txn->mt_spill_pgs); mdb_midl_free(pghead); } if (mode & MDB_END_FREE) free(txn); } void mdb_txn_reset(MDB_txn *txn) { if (txn == NULL) return; /* This call is only valid for read-only txns */ if (!(txn->mt_flags & MDB_TXN_RDONLY)) return; mdb_txn_end(txn, MDB_END_RESET); } void mdb_txn_abort(MDB_txn *txn) { if (txn == NULL) return; if (txn->mt_child) mdb_txn_abort(txn->mt_child); mdb_txn_end(txn, MDB_END_ABORT|MDB_END_SLOT|MDB_END_FREE); } /** Save the freelist as of this transaction to the freeDB. * This changes the freelist. Keep trying until it stabilizes. */ static int mdb_freelist_save(MDB_txn *txn) { /* env->me_pghead[] can grow and shrink during this call. * env->me_pglast and txn->mt_free_pgs[] can only grow. * Page numbers cannot disappear from txn->mt_free_pgs[]. */ MDB_cursor mc; MDB_env *env = txn->mt_env; int rc, maxfree_1pg = env->me_maxfree_1pg, more = 1; txnid_t pglast = 0, head_id = 0; pgno_t freecnt = 0, *free_pgs, *mop; ssize_t head_room = 0, total_room = 0, mop_len, clean_limit; mdb_cursor_init(&mc, txn, FREE_DBI, NULL); if (env->me_pghead) { /* Make sure first page of freeDB is touched and on freelist */ rc = mdb_page_search(&mc, NULL, MDB_PS_FIRST|MDB_PS_MODIFY); if (rc && rc != MDB_NOTFOUND) return rc; } if (!env->me_pghead && txn->mt_loose_pgs) { /* Put loose page numbers in mt_free_pgs, since * we may be unable to return them to me_pghead. */ MDB_page *mp = txn->mt_loose_pgs; MDB_ID2 *dl = txn->mt_u.dirty_list; unsigned x; if ((rc = mdb_midl_need(&txn->mt_free_pgs, txn->mt_loose_count)) != 0) return rc; for (; mp; mp = NEXT_LOOSE_PAGE(mp)) { mdb_midl_xappend(txn->mt_free_pgs, mp->mp_pgno); /* must also remove from dirty list */ if (txn->mt_flags & MDB_TXN_WRITEMAP) { for (x=1; x<=dl[0].mid; x++) if (dl[x].mid == mp->mp_pgno) break; mdb_tassert(txn, x <= dl[0].mid); } else { x = mdb_mid2l_search(dl, mp->mp_pgno); mdb_tassert(txn, dl[x].mid == mp->mp_pgno); mdb_dpage_free(env, mp); } dl[x].mptr = NULL; } { /* squash freed slots out of the dirty list */ unsigned y; for (y=1; dl[y].mptr && y <= dl[0].mid; y++); if (y <= dl[0].mid) { for(x=y, y++;;) { while (!dl[y].mptr && y <= dl[0].mid) y++; if (y > dl[0].mid) break; dl[x++] = dl[y++]; } dl[0].mid = x-1; } else { /* all slots freed */ dl[0].mid = 0; } } txn->mt_loose_pgs = NULL; txn->mt_loose_count = 0; } /* MDB_RESERVE cancels meminit in ovpage malloc (when no WRITEMAP) */ clean_limit = (env->me_flags & (MDB_NOMEMINIT|MDB_WRITEMAP)) ? SSIZE_MAX : maxfree_1pg; for (;;) { /* Come back here after each Put() in case freelist changed */ MDB_val key, data; pgno_t *pgs; ssize_t j; /* If using records from freeDB which we have not yet * deleted, delete them and any we reserved for me_pghead. */ while (pglast < env->me_pglast) { rc = mdb_cursor_first(&mc, &key, NULL); if (rc) return rc; pglast = head_id = *(txnid_t *)key.mv_data; total_room = head_room = 0; mdb_tassert(txn, pglast <= env->me_pglast); rc = mdb_cursor_del(&mc, 0); if (rc) return rc; } /* Save the IDL of pages freed by this txn, to a single record */ if (freecnt < txn->mt_free_pgs[0]) { if (!freecnt) { /* Make sure last page of freeDB is touched and on freelist */ rc = mdb_page_search(&mc, NULL, MDB_PS_LAST|MDB_PS_MODIFY); if (rc && rc != MDB_NOTFOUND) return rc; } free_pgs = txn->mt_free_pgs; /* Write to last page of freeDB */ key.mv_size = sizeof(txn->mt_txnid); key.mv_data = &txn->mt_txnid; do { freecnt = free_pgs[0]; data.mv_size = MDB_IDL_SIZEOF(free_pgs); rc = mdb_cursor_put(&mc, &key, &data, MDB_RESERVE); if (rc) return rc; /* Retry if mt_free_pgs[] grew during the Put() */ free_pgs = txn->mt_free_pgs; } while (freecnt < free_pgs[0]); mdb_midl_sort(free_pgs); memcpy(data.mv_data, free_pgs, data.mv_size); #if (MDB_DEBUG) > 1 { unsigned int i = free_pgs[0]; DPRINTF(("IDL write txn %"Z"u root %"Z"u num %u", txn->mt_txnid, txn->mt_dbs[FREE_DBI].md_root, i)); for (; i; i--) DPRINTF(("IDL %"Z"u", free_pgs[i])); } #endif continue; } mop = env->me_pghead; mop_len = (mop ? mop[0] : 0) + txn->mt_loose_count; /* Reserve records for me_pghead[]. Split it if multi-page, * to avoid searching freeDB for a page range. Use keys in * range [1,me_pglast]: Smaller than txnid of oldest reader. */ if (total_room >= mop_len) { if (total_room == mop_len || --more < 0) break; } else if (head_room >= maxfree_1pg && head_id > 1) { /* Keep current record (overflow page), add a new one */ head_id--; head_room = 0; } /* (Re)write {key = head_id, IDL length = head_room} */ total_room -= head_room; head_room = mop_len - total_room; if (head_room > maxfree_1pg && head_id > 1) { /* Overflow multi-page for part of me_pghead */ head_room /= head_id; /* amortize page sizes */ head_room += maxfree_1pg - head_room % (maxfree_1pg + 1); } else if (head_room < 0) { /* Rare case, not bothering to delete this record */ head_room = 0; } key.mv_size = sizeof(head_id); key.mv_data = &head_id; data.mv_size = (head_room + 1) * sizeof(pgno_t); rc = mdb_cursor_put(&mc, &key, &data, MDB_RESERVE); if (rc) return rc; /* IDL is initially empty, zero out at least the length */ pgs = (pgno_t *)data.mv_data; j = head_room > clean_limit ? head_room : 0; do { pgs[j] = 0; } while (--j >= 0); total_room += head_room; } /* Return loose page numbers to me_pghead, though usually none are * left at this point. The pages themselves remain in dirty_list. */ if (txn->mt_loose_pgs) { MDB_page *mp = txn->mt_loose_pgs; unsigned count = txn->mt_loose_count; MDB_IDL loose; /* Room for loose pages + temp IDL with same */ if ((rc = mdb_midl_need(&env->me_pghead, 2*count+1)) != 0) return rc; mop = env->me_pghead; loose = mop + MDB_IDL_ALLOCLEN(mop) - count; for (count = 0; mp; mp = NEXT_LOOSE_PAGE(mp)) loose[ ++count ] = mp->mp_pgno; loose[0] = count; mdb_midl_sort(loose); mdb_midl_xmerge(mop, loose); txn->mt_loose_pgs = NULL; txn->mt_loose_count = 0; mop_len = mop[0]; } /* Fill in the reserved me_pghead records */ rc = MDB_SUCCESS; if (mop_len) { MDB_val key, data; mop += mop_len; rc = mdb_cursor_first(&mc, &key, &data); for (; !rc; rc = mdb_cursor_next(&mc, &key, &data, MDB_NEXT)) { txnid_t id = *(txnid_t *)key.mv_data; ssize_t len = (ssize_t)(data.mv_size / sizeof(MDB_ID)) - 1; MDB_ID save; mdb_tassert(txn, len >= 0 && id <= env->me_pglast); key.mv_data = &id; if (len > mop_len) { len = mop_len; data.mv_size = (len + 1) * sizeof(MDB_ID); } data.mv_data = mop -= len; save = mop[0]; mop[0] = len; rc = mdb_cursor_put(&mc, &key, &data, MDB_CURRENT); mop[0] = save; if (rc || !(mop_len -= len)) break; } } return rc; } /** Flush (some) dirty pages to the map, after clearing their dirty flag. * @param[in] txn the transaction that's being committed * @param[in] keep number of initial pages in dirty_list to keep dirty. * @return 0 on success, non-zero on failure. */ static int mdb_page_flush(MDB_txn *txn, int keep) { MDB_env *env = txn->mt_env; MDB_ID2L dl = txn->mt_u.dirty_list; unsigned psize = env->me_psize, j; int i, pagecount = dl[0].mid, rc; size_t size = 0, pos = 0; pgno_t pgno = 0; MDB_page *dp = NULL; #ifdef _WIN32 OVERLAPPED ov; #else struct iovec iov[MDB_COMMIT_PAGES]; ssize_t wpos = 0, wsize = 0, wres; size_t next_pos = 1; /* impossible pos, so pos != next_pos */ int n = 0; #endif j = i = keep; if (env->me_flags & MDB_WRITEMAP) { /* Clear dirty flags */ while (++i <= pagecount) { dp = dl[i].mptr; /* Don't flush this page yet */ if (dp->mp_flags & (P_LOOSE|P_KEEP)) { dp->mp_flags &= ~P_KEEP; dl[++j] = dl[i]; continue; } dp->mp_flags &= ~P_DIRTY; } goto done; } /* Write the pages */ for (;;) { if (++i <= pagecount) { dp = dl[i].mptr; /* Don't flush this page yet */ if (dp->mp_flags & (P_LOOSE|P_KEEP)) { dp->mp_flags &= ~P_KEEP; dl[i].mid = 0; continue; } pgno = dl[i].mid; /* clear dirty flag */ dp->mp_flags &= ~P_DIRTY; pos = pgno * psize; size = psize; if (IS_OVERFLOW(dp)) size *= dp->mp_pages; } #ifdef _WIN32 else break; /* Windows actually supports scatter/gather I/O, but only on * unbuffered file handles. Since we're relying on the OS page * cache for all our data, that's self-defeating. So we just * write pages one at a time. We use the ov structure to set * the write offset, to at least save the overhead of a Seek * system call. */ DPRINTF(("committing page %"Z"u", pgno)); memset(&ov, 0, sizeof(ov)); ov.Offset = pos & 0xffffffff; ov.OffsetHigh = pos >> 16 >> 16; if (!WriteFile(env->me_fd, dp, size, NULL, &ov)) { rc = ErrCode(); DPRINTF(("WriteFile: %d", rc)); return rc; } #else /* Write up to MDB_COMMIT_PAGES dirty pages at a time. */ if (pos!=next_pos || n==MDB_COMMIT_PAGES || wsize+size>MAX_WRITE) { if (n) { retry_write: /* Write previous page(s) */ #ifdef MDB_USE_PWRITEV wres = pwritev(env->me_fd, iov, n, wpos); #else if (n == 1) { wres = pwrite(env->me_fd, iov[0].iov_base, wsize, wpos); } else { retry_seek: if (lseek(env->me_fd, wpos, SEEK_SET) == -1) { rc = ErrCode(); if (rc == EINTR) goto retry_seek; DPRINTF(("lseek: %s", strerror(rc))); return rc; } wres = writev(env->me_fd, iov, n); } #endif if (wres != wsize) { if (wres < 0) { rc = ErrCode(); if (rc == EINTR) goto retry_write; DPRINTF(("Write error: %s", strerror(rc))); } else { rc = EIO; /* TODO: Use which error code? */ DPUTS("short write, filesystem full?"); } return rc; } n = 0; } if (i > pagecount) break; wpos = pos; wsize = 0; } DPRINTF(("committing page %"Z"u", pgno)); next_pos = pos + size; iov[n].iov_len = size; iov[n].iov_base = (char *)dp; wsize += size; n++; #endif /* _WIN32 */ } /* MIPS has cache coherency issues, this is a no-op everywhere else * Note: for any size >= on-chip cache size, entire on-chip cache is * flushed. */ CACHEFLUSH(env->me_map, txn->mt_next_pgno * env->me_psize, DCACHE); for (i = keep; ++i <= pagecount; ) { dp = dl[i].mptr; /* This is a page we skipped above */ if (!dl[i].mid) { dl[++j] = dl[i]; dl[j].mid = dp->mp_pgno; continue; } mdb_dpage_free(env, dp); } done: i--; txn->mt_dirty_room += i - j; dl[0].mid = j; return MDB_SUCCESS; } int mdb_txn_commit(MDB_txn *txn) { int rc; unsigned int i, end_mode; MDB_env *env; if (txn == NULL) return EINVAL; /* mdb_txn_end() mode for a commit which writes nothing */ end_mode = MDB_END_EMPTY_COMMIT|MDB_END_UPDATE|MDB_END_SLOT|MDB_END_FREE; if (txn->mt_child) { rc = mdb_txn_commit(txn->mt_child); if (rc) goto fail; } env = txn->mt_env; if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) { goto done; } if (txn->mt_flags & (MDB_TXN_FINISHED|MDB_TXN_ERROR)) { DPUTS("txn has failed/finished, can't commit"); if (txn->mt_parent) txn->mt_parent->mt_flags |= MDB_TXN_ERROR; rc = MDB_BAD_TXN; goto fail; } if (txn->mt_parent) { MDB_txn *parent = txn->mt_parent; MDB_page **lp; MDB_ID2L dst, src; MDB_IDL pspill; unsigned x, y, len, ps_len; /* Append our free list to parent's */ rc = mdb_midl_append_list(&parent->mt_free_pgs, txn->mt_free_pgs); if (rc) goto fail; mdb_midl_free(txn->mt_free_pgs); /* Failures after this must either undo the changes * to the parent or set MDB_TXN_ERROR in the parent. */ parent->mt_next_pgno = txn->mt_next_pgno; parent->mt_flags = txn->mt_flags; /* Merge our cursors into parent's and close them */ mdb_cursors_close(txn, 1); /* Update parent's DB table. */ memcpy(parent->mt_dbs, txn->mt_dbs, txn->mt_numdbs * sizeof(MDB_db)); parent->mt_numdbs = txn->mt_numdbs; parent->mt_dbflags[FREE_DBI] = txn->mt_dbflags[FREE_DBI]; parent->mt_dbflags[MAIN_DBI] = txn->mt_dbflags[MAIN_DBI]; for (i=CORE_DBS; imt_numdbs; i++) { /* preserve parent's DB_NEW status */ x = parent->mt_dbflags[i] & DB_NEW; parent->mt_dbflags[i] = txn->mt_dbflags[i] | x; } dst = parent->mt_u.dirty_list; src = txn->mt_u.dirty_list; /* Remove anything in our dirty list from parent's spill list */ if ((pspill = parent->mt_spill_pgs) && (ps_len = pspill[0])) { x = y = ps_len; pspill[0] = (pgno_t)-1; /* Mark our dirty pages as deleted in parent spill list */ for (i=0, len=src[0].mid; ++i <= len; ) { MDB_ID pn = src[i].mid << 1; while (pn > pspill[x]) x--; if (pn == pspill[x]) { pspill[x] = 1; y = --x; } } /* Squash deleted pagenums if we deleted any */ for (x=y; ++x <= ps_len; ) if (!(pspill[x] & 1)) pspill[++y] = pspill[x]; pspill[0] = y; } /* Remove anything in our spill list from parent's dirty list */ if (txn->mt_spill_pgs && txn->mt_spill_pgs[0]) { for (i=1; i<=txn->mt_spill_pgs[0]; i++) { MDB_ID pn = txn->mt_spill_pgs[i]; if (pn & 1) continue; /* deleted spillpg */ pn >>= 1; y = mdb_mid2l_search(dst, pn); if (y <= dst[0].mid && dst[y].mid == pn) { free(dst[y].mptr); while (y < dst[0].mid) { dst[y] = dst[y+1]; y++; } dst[0].mid--; } } } /* Find len = length of merging our dirty list with parent's */ x = dst[0].mid; dst[0].mid = 0; /* simplify loops */ if (parent->mt_parent) { len = x + src[0].mid; y = mdb_mid2l_search(src, dst[x].mid + 1) - 1; for (i = x; y && i; y--) { pgno_t yp = src[y].mid; while (yp < dst[i].mid) i--; if (yp == dst[i].mid) { i--; len--; } } } else { /* Simplify the above for single-ancestor case */ len = MDB_IDL_UM_MAX - txn->mt_dirty_room; } /* Merge our dirty list with parent's */ y = src[0].mid; for (i = len; y; dst[i--] = src[y--]) { pgno_t yp = src[y].mid; while (yp < dst[x].mid) dst[i--] = dst[x--]; if (yp == dst[x].mid) free(dst[x--].mptr); } mdb_tassert(txn, i == x); dst[0].mid = len; free(txn->mt_u.dirty_list); parent->mt_dirty_room = txn->mt_dirty_room; if (txn->mt_spill_pgs) { if (parent->mt_spill_pgs) { /* TODO: Prevent failure here, so parent does not fail */ rc = mdb_midl_append_list(&parent->mt_spill_pgs, txn->mt_spill_pgs); if (rc) parent->mt_flags |= MDB_TXN_ERROR; mdb_midl_free(txn->mt_spill_pgs); mdb_midl_sort(parent->mt_spill_pgs); } else { parent->mt_spill_pgs = txn->mt_spill_pgs; } } /* Append our loose page list to parent's */ for (lp = &parent->mt_loose_pgs; *lp; lp = &NEXT_LOOSE_PAGE(*lp)) ; *lp = txn->mt_loose_pgs; parent->mt_loose_count += txn->mt_loose_count; parent->mt_child = NULL; mdb_midl_free(((MDB_ntxn *)txn)->mnt_pgstate.mf_pghead); free(txn); return rc; } if (txn != env->me_txn) { DPUTS("attempt to commit unknown transaction"); rc = EINVAL; goto fail; } mdb_cursors_close(txn, 0); if (!txn->mt_u.dirty_list[0].mid && !(txn->mt_flags & (MDB_TXN_DIRTY|MDB_TXN_SPILLS))) goto done; DPRINTF(("committing txn %"Z"u %p on mdbenv %p, root page %"Z"u", txn->mt_txnid, (void*)txn, (void*)env, txn->mt_dbs[MAIN_DBI].md_root)); /* Update DB root pointers */ if (txn->mt_numdbs > CORE_DBS) { MDB_cursor mc; MDB_dbi i; MDB_val data; data.mv_size = sizeof(MDB_db); mdb_cursor_init(&mc, txn, MAIN_DBI, NULL); for (i = CORE_DBS; i < txn->mt_numdbs; i++) { if (txn->mt_dbflags[i] & DB_DIRTY) { if (TXN_DBI_CHANGED(txn, i)) { rc = MDB_BAD_DBI; goto fail; } data.mv_data = &txn->mt_dbs[i]; rc = mdb_cursor_put(&mc, &txn->mt_dbxs[i].md_name, &data, F_SUBDATA); if (rc) goto fail; } } } rc = mdb_freelist_save(txn); if (rc) goto fail; mdb_midl_free(env->me_pghead); env->me_pghead = NULL; mdb_midl_shrink(&txn->mt_free_pgs); #if (MDB_DEBUG) > 2 mdb_audit(txn); #endif if ((rc = mdb_page_flush(txn, 0)) || (rc = mdb_env_sync(env, 0)) || (rc = mdb_env_write_meta(txn))) goto fail; end_mode = MDB_END_COMMITTED|MDB_END_UPDATE; done: mdb_txn_end(txn, end_mode); return MDB_SUCCESS; fail: mdb_txn_abort(txn); return rc; } /** Read the environment parameters of a DB environment before * mapping it into memory. * @param[in] env the environment handle * @param[out] meta address of where to store the meta information * @return 0 on success, non-zero on failure. */ static int ESECT mdb_env_read_header(MDB_env *env, MDB_meta *meta) { MDB_metabuf pbuf; MDB_page *p; MDB_meta *m; int i, rc, off; enum { Size = sizeof(pbuf) }; /* We don't know the page size yet, so use a minimum value. * Read both meta pages so we can use the latest one. */ for (i=off=0; imm_psize) { #ifdef _WIN32 DWORD len; OVERLAPPED ov; memset(&ov, 0, sizeof(ov)); ov.Offset = off; rc = ReadFile(env->me_fd, &pbuf, Size, &len, &ov) ? (int)len : -1; if (rc == -1 && ErrCode() == ERROR_HANDLE_EOF) rc = 0; #else rc = pread(env->me_fd, &pbuf, Size, off); #endif if (rc != Size) { if (rc == 0 && off == 0) return ENOENT; rc = rc < 0 ? (int) ErrCode() : MDB_INVALID; DPRINTF(("read: %s", mdb_strerror(rc))); return rc; } p = (MDB_page *)&pbuf; if (!F_ISSET(p->mp_flags, P_META)) { DPRINTF(("page %"Z"u not a meta page", p->mp_pgno)); return MDB_INVALID; } m = METADATA(p); if (m->mm_magic != MDB_MAGIC) { DPUTS("meta has invalid magic"); return MDB_INVALID; } if (m->mm_version != MDB_DATA_VERSION) { DPRINTF(("database is version %u, expected version %u", m->mm_version, MDB_DATA_VERSION)); return MDB_VERSION_MISMATCH; } if (off == 0 || m->mm_txnid > meta->mm_txnid) *meta = *m; } return 0; } /** Fill in most of the zeroed #MDB_meta for an empty database environment */ static void ESECT mdb_env_init_meta0(MDB_env *env, MDB_meta *meta) { meta->mm_magic = MDB_MAGIC; meta->mm_version = MDB_DATA_VERSION; meta->mm_mapsize = env->me_mapsize; meta->mm_psize = env->me_psize; meta->mm_last_pg = NUM_METAS-1; meta->mm_flags = env->me_flags & 0xffff; meta->mm_flags |= MDB_INTEGERKEY; /* this is mm_dbs[FREE_DBI].md_flags */ meta->mm_dbs[FREE_DBI].md_root = P_INVALID; meta->mm_dbs[MAIN_DBI].md_root = P_INVALID; } /** Write the environment parameters of a freshly created DB environment. * @param[in] env the environment handle * @param[in] meta the #MDB_meta to write * @return 0 on success, non-zero on failure. */ static int ESECT mdb_env_init_meta(MDB_env *env, MDB_meta *meta) { MDB_page *p, *q; int rc; unsigned int psize; #ifdef _WIN32 DWORD len; OVERLAPPED ov; memset(&ov, 0, sizeof(ov)); #define DO_PWRITE(rc, fd, ptr, size, len, pos) do { \ ov.Offset = pos; \ rc = WriteFile(fd, ptr, size, &len, &ov); } while(0) #else int len; #define DO_PWRITE(rc, fd, ptr, size, len, pos) do { \ len = pwrite(fd, ptr, size, pos); \ if (len == -1 && ErrCode() == EINTR) continue; \ rc = (len >= 0); break; } while(1) #endif DPUTS("writing new meta page"); psize = env->me_psize; p = calloc(NUM_METAS, psize); if (!p) return ENOMEM; p->mp_pgno = 0; p->mp_flags = P_META; *(MDB_meta *)METADATA(p) = *meta; q = (MDB_page *)((char *)p + psize); q->mp_pgno = 1; q->mp_flags = P_META; *(MDB_meta *)METADATA(q) = *meta; DO_PWRITE(rc, env->me_fd, p, psize * NUM_METAS, len, 0); if (!rc) rc = ErrCode(); else if ((unsigned) len == psize * NUM_METAS) rc = MDB_SUCCESS; else rc = ENOSPC; free(p); return rc; } /** Update the environment info to commit a transaction. * @param[in] txn the transaction that's being committed * @return 0 on success, non-zero on failure. */ static int mdb_env_write_meta(MDB_txn *txn) { MDB_env *env; MDB_meta meta, metab, *mp; unsigned flags; size_t mapsize; off_t off; int rc, len, toggle; char *ptr; HANDLE mfd; #ifdef _WIN32 OVERLAPPED ov; #else int r2; #endif toggle = txn->mt_txnid & 1; DPRINTF(("writing meta page %d for root page %"Z"u", toggle, txn->mt_dbs[MAIN_DBI].md_root)); env = txn->mt_env; flags = env->me_flags; mp = env->me_metas[toggle]; mapsize = env->me_metas[toggle ^ 1]->mm_mapsize; /* Persist any increases of mapsize config */ if (mapsize < env->me_mapsize) mapsize = env->me_mapsize; if (flags & MDB_WRITEMAP) { mp->mm_mapsize = mapsize; mp->mm_dbs[FREE_DBI] = txn->mt_dbs[FREE_DBI]; mp->mm_dbs[MAIN_DBI] = txn->mt_dbs[MAIN_DBI]; mp->mm_last_pg = txn->mt_next_pgno - 1; #if (__GNUC__ * 100 + __GNUC_MINOR__ >= 404) && /* TODO: portability */ \ !(defined(__i386__) || defined(__x86_64__)) /* LY: issue a memory barrier, if not x86. ITS#7969 */ __sync_synchronize(); #endif mp->mm_txnid = txn->mt_txnid; if (!(flags & (MDB_NOMETASYNC|MDB_NOSYNC))) { unsigned meta_size = env->me_psize; rc = (env->me_flags & MDB_MAPASYNC) ? MS_ASYNC : MS_SYNC; ptr = (char *)mp - PAGEHDRSZ; #ifndef _WIN32 /* POSIX msync() requires ptr = start of OS page */ r2 = (ptr - env->me_map) & (env->me_os_psize - 1); ptr -= r2; meta_size += r2; #endif if (MDB_MSYNC(ptr, meta_size, rc)) { rc = ErrCode(); goto fail; } } goto done; } metab.mm_txnid = mp->mm_txnid; metab.mm_last_pg = mp->mm_last_pg; meta.mm_mapsize = mapsize; meta.mm_dbs[FREE_DBI] = txn->mt_dbs[FREE_DBI]; meta.mm_dbs[MAIN_DBI] = txn->mt_dbs[MAIN_DBI]; meta.mm_last_pg = txn->mt_next_pgno - 1; meta.mm_txnid = txn->mt_txnid; off = offsetof(MDB_meta, mm_mapsize); ptr = (char *)&meta + off; len = sizeof(MDB_meta) - off; off += (char *)mp - env->me_map; /* Write to the SYNC fd unless MDB_NOSYNC/MDB_NOMETASYNC. * (me_mfd goes to the same file as me_fd, but writing to it * also syncs to disk. Avoids a separate fdatasync() call.) */ mfd = (flags & (MDB_NOSYNC|MDB_NOMETASYNC)) ? env->me_fd : env->me_mfd; #ifdef _WIN32 { memset(&ov, 0, sizeof(ov)); ov.Offset = off; if (!WriteFile(mfd, ptr, len, (DWORD *)&rc, &ov)) rc = -1; } #else retry_write: rc = pwrite(mfd, ptr, len, off); #endif if (rc != len) { rc = rc < 0 ? ErrCode() : EIO; #ifndef _WIN32 if (rc == EINTR) goto retry_write; #endif DPUTS("write failed, disk error?"); /* On a failure, the pagecache still contains the new data. * Write some old data back, to prevent it from being used. * Use the non-SYNC fd; we know it will fail anyway. */ meta.mm_last_pg = metab.mm_last_pg; meta.mm_txnid = metab.mm_txnid; #ifdef _WIN32 memset(&ov, 0, sizeof(ov)); ov.Offset = off; WriteFile(env->me_fd, ptr, len, NULL, &ov); #else r2 = pwrite(env->me_fd, ptr, len, off); (void)r2; /* Silence warnings. We don't care about pwrite's return value */ #endif fail: env->me_flags |= MDB_FATAL_ERROR; return rc; } /* MIPS has cache coherency issues, this is a no-op everywhere else */ CACHEFLUSH(env->me_map + off, len, DCACHE); done: /* Memory ordering issues are irrelevant; since the entire writer * is wrapped by wmutex, all of these changes will become visible * after the wmutex is unlocked. Since the DB is multi-version, * readers will get consistent data regardless of how fresh or * how stale their view of these values is. */ if (env->me_txns) env->me_txns->mti_txnid = txn->mt_txnid; return MDB_SUCCESS; } /** Check both meta pages to see which one is newer. * @param[in] env the environment handle * @return newest #MDB_meta. */ static MDB_meta * mdb_env_pick_meta(const MDB_env *env) { MDB_meta *const *metas = env->me_metas; return metas[ metas[0]->mm_txnid < metas[1]->mm_txnid ]; } int ESECT mdb_env_create(MDB_env **env) { MDB_env *e; e = calloc(1, sizeof(MDB_env)); if (!e) return ENOMEM; e->me_maxreaders = DEFAULT_READERS; e->me_maxdbs = e->me_numdbs = CORE_DBS; e->me_fd = INVALID_HANDLE_VALUE; e->me_lfd = INVALID_HANDLE_VALUE; e->me_mfd = INVALID_HANDLE_VALUE; #ifdef MDB_USE_POSIX_SEM e->me_rmutex = SEM_FAILED; e->me_wmutex = SEM_FAILED; #endif e->me_pid = getpid(); GET_PAGESIZE(e->me_os_psize); VGMEMP_CREATE(e,0,0); *env = e; return MDB_SUCCESS; } static int ESECT mdb_env_map(MDB_env *env, void *addr) { MDB_page *p; unsigned int flags = env->me_flags; #ifdef _WIN32 int rc; HANDLE mh; LONG sizelo, sizehi; size_t msize; if (flags & MDB_RDONLY) { /* Don't set explicit map size, use whatever exists */ msize = 0; sizelo = 0; sizehi = 0; } else { msize = env->me_mapsize; sizelo = msize & 0xffffffff; sizehi = msize >> 16 >> 16; /* only needed on Win64 */ /* Windows won't create mappings for zero length files. * and won't map more than the file size. * Just set the maxsize right now. */ if (!(flags & MDB_WRITEMAP) && (SetFilePointer(env->me_fd, sizelo, &sizehi, 0) != (DWORD)sizelo || !SetEndOfFile(env->me_fd) || SetFilePointer(env->me_fd, 0, NULL, 0) != 0)) return ErrCode(); } mh = CreateFileMapping(env->me_fd, NULL, flags & MDB_WRITEMAP ? PAGE_READWRITE : PAGE_READONLY, sizehi, sizelo, NULL); if (!mh) return ErrCode(); env->me_map = MapViewOfFileEx(mh, flags & MDB_WRITEMAP ? FILE_MAP_WRITE : FILE_MAP_READ, 0, 0, msize, addr); rc = env->me_map ? 0 : ErrCode(); CloseHandle(mh); if (rc) return rc; #else int mmap_flags = MAP_SHARED; int prot = PROT_READ; #ifdef MAP_NOSYNC /* Used on FreeBSD */ if (flags & MDB_NOSYNC) mmap_flags |= MAP_NOSYNC; #endif if (flags & MDB_WRITEMAP) { prot |= PROT_WRITE; if (ftruncate(env->me_fd, env->me_mapsize) < 0) return ErrCode(); } env->me_map = mmap(addr, env->me_mapsize, prot, mmap_flags, env->me_fd, 0); if (env->me_map == MAP_FAILED) { env->me_map = NULL; return ErrCode(); } if (flags & MDB_NORDAHEAD) { /* Turn off readahead. It's harmful when the DB is larger than RAM. */ #ifdef MADV_RANDOM madvise(env->me_map, env->me_mapsize, MADV_RANDOM); #else #ifdef POSIX_MADV_RANDOM posix_madvise(env->me_map, env->me_mapsize, POSIX_MADV_RANDOM); #endif /* POSIX_MADV_RANDOM */ #endif /* MADV_RANDOM */ } #endif /* _WIN32 */ /* Can happen because the address argument to mmap() is just a * hint. mmap() can pick another, e.g. if the range is in use. * The MAP_FIXED flag would prevent that, but then mmap could * instead unmap existing pages to make room for the new map. */ if (addr && env->me_map != addr) return EBUSY; /* TODO: Make a new MDB_* error code? */ p = (MDB_page *)env->me_map; env->me_metas[0] = METADATA(p); env->me_metas[1] = (MDB_meta *)((char *)env->me_metas[0] + env->me_psize); return MDB_SUCCESS; } int ESECT mdb_env_set_mapsize(MDB_env *env, size_t size) { /* If env is already open, caller is responsible for making * sure there are no active txns. */ if (env->me_map) { int rc; MDB_meta *meta; void *old; if (env->me_txn) return EINVAL; meta = mdb_env_pick_meta(env); if (!size) size = meta->mm_mapsize; { /* Silently round up to minimum if the size is too small */ size_t minsize = (meta->mm_last_pg + 1) * env->me_psize; if (size < minsize) size = minsize; } munmap(env->me_map, env->me_mapsize); env->me_mapsize = size; old = (env->me_flags & MDB_FIXEDMAP) ? env->me_map : NULL; rc = mdb_env_map(env, old); if (rc) return rc; } env->me_mapsize = size; if (env->me_psize) env->me_maxpg = env->me_mapsize / env->me_psize; return MDB_SUCCESS; } int ESECT mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs) { if (env->me_map) return EINVAL; env->me_maxdbs = dbs + CORE_DBS; return MDB_SUCCESS; } int ESECT mdb_env_set_maxreaders(MDB_env *env, unsigned int readers) { if (env->me_map || readers < 1) return EINVAL; env->me_maxreaders = readers; return MDB_SUCCESS; } int ESECT mdb_env_get_maxreaders(MDB_env *env, unsigned int *readers) { if (!env || !readers) return EINVAL; *readers = env->me_maxreaders; return MDB_SUCCESS; } static int ESECT mdb_fsize(HANDLE fd, size_t *size) { #ifdef _WIN32 LARGE_INTEGER fsize; if (!GetFileSizeEx(fd, &fsize)) return ErrCode(); *size = fsize.QuadPart; #else struct stat st; if (fstat(fd, &st)) return ErrCode(); *size = st.st_size; #endif return MDB_SUCCESS; } #ifdef _WIN32 typedef wchar_t mdb_nchar_t; # define MDB_NAME(str) L##str # define mdb_name_cpy wcscpy #else /** Character type for file names: char on Unix, wchar_t on Windows */ typedef char mdb_nchar_t; # define MDB_NAME(str) str /**< #mdb_nchar_t[] string literal */ # define mdb_name_cpy strcpy /**< Copy name (#mdb_nchar_t string) */ #endif /** Filename - string of #mdb_nchar_t[] */ typedef struct MDB_name { int mn_len; /**< Length */ int mn_alloced; /**< True if #mn_val was malloced */ mdb_nchar_t *mn_val; /**< Contents */ } MDB_name; /** Filename suffixes [datafile,lockfile][without,with MDB_NOSUBDIR] */ static const mdb_nchar_t *const mdb_suffixes[2][2] = { { MDB_NAME("/data.mdb"), MDB_NAME("") }, { MDB_NAME("/lock.mdb"), MDB_NAME("-lock") } }; #define MDB_SUFFLEN 9 /**< Max string length in #mdb_suffixes[] */ /** Set up filename + scratch area for filename suffix, for opening files. * It should be freed with #mdb_fname_destroy(). * On Windows, paths are converted from char *UTF-8 to wchar_t *UTF-16. * * @param[in] path Pathname for #mdb_env_open(). * @param[in] envflags Whether a subdir and/or lockfile will be used. * @param[out] fname Resulting filename, with room for a suffix if necessary. */ static int ESECT mdb_fname_init(const char *path, unsigned envflags, MDB_name *fname) { int no_suffix = F_ISSET(envflags, MDB_NOSUBDIR|MDB_NOLOCK); fname->mn_alloced = 0; #ifdef _WIN32 return utf8_to_utf16(path, fname, no_suffix ? 0 : MDB_SUFFLEN); #else fname->mn_len = strlen(path); if (no_suffix) fname->mn_val = (char *) path; else if ((fname->mn_val = malloc(fname->mn_len + MDB_SUFFLEN+1)) != NULL) { fname->mn_alloced = 1; strcpy(fname->mn_val, path); } else return ENOMEM; return MDB_SUCCESS; #endif } /** Destroy \b fname from #mdb_fname_init() */ #define mdb_fname_destroy(fname) \ do { if ((fname).mn_alloced) free((fname).mn_val); } while (0) #ifdef O_CLOEXEC /* POSIX.1-2008: Set FD_CLOEXEC atomically at open() */ # define MDB_CLOEXEC O_CLOEXEC #else # define MDB_CLOEXEC 0 #endif /** File type, access mode etc. for #mdb_fopen() */ enum mdb_fopen_type { #ifdef _WIN32 MDB_O_RDONLY, MDB_O_RDWR, MDB_O_META, MDB_O_COPY, MDB_O_LOCKS #else /* A comment in mdb_fopen() explains some O_* flag choices. */ MDB_O_RDONLY= O_RDONLY, /**< for RDONLY me_fd */ MDB_O_RDWR = O_RDWR |O_CREAT, /**< for me_fd */ MDB_O_META = O_WRONLY|MDB_DSYNC |MDB_CLOEXEC, /**< for me_mfd */ MDB_O_COPY = O_WRONLY|O_CREAT|O_EXCL|MDB_CLOEXEC, /**< for #mdb_env_copy() */ /** Bitmask for open() flags in enum #mdb_fopen_type. The other bits * distinguish otherwise-equal MDB_O_* constants from each other. */ MDB_O_MASK = MDB_O_RDWR|MDB_CLOEXEC | MDB_O_RDONLY|MDB_O_META|MDB_O_COPY, MDB_O_LOCKS = MDB_O_RDWR|MDB_CLOEXEC | ((MDB_O_MASK+1) & ~MDB_O_MASK) /**< for me_lfd */ #endif }; /** Open an LMDB file. * @param[in] env The LMDB environment. * @param[in,out] fname Path from from #mdb_fname_init(). A suffix is * appended if necessary to create the filename, without changing mn_len. * @param[in] which Determines file type, access mode, etc. * @param[in] mode The Unix permissions for the file, if we create it. * @param[out] res Resulting file handle. * @return 0 on success, non-zero on failure. */ static int ESECT mdb_fopen(const MDB_env *env, MDB_name *fname, enum mdb_fopen_type which, mdb_mode_t mode, HANDLE *res) { int rc = MDB_SUCCESS; HANDLE fd; #ifdef _WIN32 DWORD acc, share, disp, attrs; #else int flags; #endif if (fname->mn_alloced) /* modifiable copy */ mdb_name_cpy(fname->mn_val + fname->mn_len, mdb_suffixes[which==MDB_O_LOCKS][F_ISSET(env->me_flags, MDB_NOSUBDIR)]); /* The directory must already exist. Usually the file need not. * MDB_O_META requires the file because we already created it using * MDB_O_RDWR. MDB_O_COPY must not overwrite an existing file. * * With MDB_O_COPY we do not want the OS to cache the writes, since * the source data is already in the OS cache. * * The lockfile needs FD_CLOEXEC (close file descriptor on exec*()) * to avoid the flock() issues noted under Caveats in lmdb.h. * Also set it for other filehandles which the user cannot get at * and close himself, which he may need after fork(). I.e. all but * me_fd, which programs do use via mdb_env_get_fd(). */ #ifdef _WIN32 acc = GENERIC_READ|GENERIC_WRITE; share = FILE_SHARE_READ|FILE_SHARE_WRITE; disp = OPEN_ALWAYS; attrs = FILE_ATTRIBUTE_NORMAL; switch (which) { case MDB_O_RDONLY: /* read-only datafile */ acc = GENERIC_READ; disp = OPEN_EXISTING; break; case MDB_O_META: /* for writing metapages */ acc = GENERIC_WRITE; disp = OPEN_EXISTING; attrs = FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH; break; case MDB_O_COPY: /* mdb_env_copy() & co */ acc = GENERIC_WRITE; share = 0; disp = CREATE_NEW; attrs = FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH; break; default: break; /* silence gcc -Wswitch (not all enum values handled) */ } fd = CreateFileW(fname->mn_val, acc, share, NULL, disp, attrs, NULL); #else fd = open(fname->mn_val, which & MDB_O_MASK, mode); #endif if (fd == INVALID_HANDLE_VALUE) rc = ErrCode(); #ifndef _WIN32 else { if (which != MDB_O_RDONLY && which != MDB_O_RDWR) { /* Set CLOEXEC if we could not pass it to open() */ if (!MDB_CLOEXEC && (flags = fcntl(fd, F_GETFD)) != -1) (void) fcntl(fd, F_SETFD, flags | FD_CLOEXEC); } if (which == MDB_O_COPY && env->me_psize >= env->me_os_psize) { /* This may require buffer alignment. There is no portable * way to ask how much, so we require OS pagesize alignment. */ # ifdef F_NOCACHE /* __APPLE__ */ (void) fcntl(fd, F_NOCACHE, 1); # elif defined O_DIRECT /* open(...O_DIRECT...) would break on filesystems without * O_DIRECT support (ITS#7682). Try to set it here instead. */ if ((flags = fcntl(fd, F_GETFL)) != -1) (void) fcntl(fd, F_SETFL, flags | O_DIRECT); # endif } } #endif /* !_WIN32 */ *res = fd; return rc; } #ifdef BROKEN_FDATASYNC #include #include #endif /** Further setup required for opening an LMDB environment */ static int ESECT mdb_env_open2(MDB_env *env) { unsigned int flags = env->me_flags; int i, newenv = 0, rc; MDB_meta meta; #ifdef _WIN32 /* See if we should use QueryLimited */ rc = GetVersion(); if ((rc & 0xff) > 5) env->me_pidquery = MDB_PROCESS_QUERY_LIMITED_INFORMATION; else env->me_pidquery = PROCESS_QUERY_INFORMATION; #endif /* _WIN32 */ #ifdef BROKEN_FDATASYNC /* ext3/ext4 fdatasync is broken on some older Linux kernels. * https://lkml.org/lkml/2012/9/3/83 * Kernels after 3.6-rc6 are known good. * https://lkml.org/lkml/2012/9/10/556 * See if the DB is on ext3/ext4, then check for new enough kernel * Kernels 2.6.32.60, 2.6.34.15, 3.2.30, and 3.5.4 are also known * to be patched. */ { struct statfs st; fstatfs(env->me_fd, &st); while (st.f_type == 0xEF53) { struct utsname uts; int i; uname(&uts); if (uts.release[0] < '3') { if (!strncmp(uts.release, "2.6.32.", 7)) { i = atoi(uts.release+7); if (i >= 60) break; /* 2.6.32.60 and newer is OK */ } else if (!strncmp(uts.release, "2.6.34.", 7)) { i = atoi(uts.release+7); if (i >= 15) break; /* 2.6.34.15 and newer is OK */ } } else if (uts.release[0] == '3') { i = atoi(uts.release+2); if (i > 5) break; /* 3.6 and newer is OK */ if (i == 5) { i = atoi(uts.release+4); if (i >= 4) break; /* 3.5.4 and newer is OK */ } else if (i == 2) { i = atoi(uts.release+4); if (i >= 30) break; /* 3.2.30 and newer is OK */ } } else { /* 4.x and newer is OK */ break; } env->me_flags |= MDB_FSYNCONLY; break; } } #endif if ((i = mdb_env_read_header(env, &meta)) != 0) { if (i != ENOENT) return i; DPUTS("new mdbenv"); newenv = 1; env->me_psize = env->me_os_psize; if (env->me_psize > MAX_PAGESIZE) env->me_psize = MAX_PAGESIZE; memset(&meta, 0, sizeof(meta)); mdb_env_init_meta0(env, &meta); meta.mm_mapsize = DEFAULT_MAPSIZE; } else { env->me_psize = meta.mm_psize; } /* Was a mapsize configured? */ if (!env->me_mapsize) { env->me_mapsize = meta.mm_mapsize; } { /* Make sure mapsize >= committed data size. Even when using * mm_mapsize, which could be broken in old files (ITS#7789). */ size_t minsize = (meta.mm_last_pg + 1) * meta.mm_psize; if (env->me_mapsize < minsize) env->me_mapsize = minsize; } meta.mm_mapsize = env->me_mapsize; if (newenv && !(flags & MDB_FIXEDMAP)) { /* mdb_env_map() may grow the datafile. Write the metapages * first, so the file will be valid if initialization fails. * Except with FIXEDMAP, since we do not yet know mm_address. * We could fill in mm_address later, but then a different * program might end up doing that - one with a memory layout * and map address which does not suit the main program. */ rc = mdb_env_init_meta(env, &meta); if (rc) return rc; newenv = 0; } rc = mdb_env_map(env, (flags & MDB_FIXEDMAP) ? meta.mm_address : NULL); if (rc) return rc; if (newenv) { if (flags & MDB_FIXEDMAP) meta.mm_address = env->me_map; i = mdb_env_init_meta(env, &meta); if (i != MDB_SUCCESS) { return i; } } env->me_maxfree_1pg = (env->me_psize - PAGEHDRSZ) / sizeof(pgno_t) - 1; env->me_nodemax = (((env->me_psize - PAGEHDRSZ) / MDB_MINKEYS) & -2) - sizeof(indx_t); #if !(MDB_MAXKEYSIZE) env->me_maxkey = env->me_nodemax - (NODESIZE + sizeof(MDB_db)); #endif env->me_maxpg = env->me_mapsize / env->me_psize; #if MDB_DEBUG { MDB_meta *meta = mdb_env_pick_meta(env); MDB_db *db = &meta->mm_dbs[MAIN_DBI]; DPRINTF(("opened database version %u, pagesize %u", meta->mm_version, env->me_psize)); DPRINTF(("using meta page %d", (int) (meta->mm_txnid & 1))); DPRINTF(("depth: %u", db->md_depth)); DPRINTF(("entries: %"Z"u", db->md_entries)); DPRINTF(("branch pages: %"Z"u", db->md_branch_pages)); DPRINTF(("leaf pages: %"Z"u", db->md_leaf_pages)); DPRINTF(("overflow pages: %"Z"u", db->md_overflow_pages)); DPRINTF(("root: %"Z"u", db->md_root)); } #endif return MDB_SUCCESS; } /** Release a reader thread's slot in the reader lock table. * This function is called automatically when a thread exits. * @param[in] ptr This points to the slot in the reader lock table. */ static void mdb_env_reader_dest(void *ptr) { MDB_reader *reader = ptr; #ifndef _WIN32 if (reader->mr_pid == getpid()) /* catch pthread_exit() in child process */ #endif /* We omit the mutex, so do this atomically (i.e. skip mr_txnid) */ reader->mr_pid = 0; } #ifdef _WIN32 /** Junk for arranging thread-specific callbacks on Windows. This is * necessarily platform and compiler-specific. Windows supports up * to 1088 keys. Let's assume nobody opens more than 64 environments * in a single process, for now. They can override this if needed. */ #ifndef MAX_TLS_KEYS #define MAX_TLS_KEYS 64 #endif static pthread_key_t mdb_tls_keys[MAX_TLS_KEYS]; static int mdb_tls_nkeys; static void NTAPI mdb_tls_callback(PVOID module, DWORD reason, PVOID ptr) { int i; switch(reason) { case DLL_PROCESS_ATTACH: break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: for (i=0; ime_txns->mti_txnid = meta->mm_txnid; #ifdef _WIN32 { OVERLAPPED ov; /* First acquire a shared lock. The Unlock will * then release the existing exclusive lock. */ memset(&ov, 0, sizeof(ov)); if (!LockFileEx(env->me_lfd, 0, 0, 1, 0, &ov)) { rc = ErrCode(); } else { UnlockFile(env->me_lfd, 0, 0, 1, 0); *excl = 0; } } #else { struct flock lock_info; /* The shared lock replaces the existing lock */ memset((void *)&lock_info, 0, sizeof(lock_info)); lock_info.l_type = F_RDLCK; lock_info.l_whence = SEEK_SET; lock_info.l_start = 0; lock_info.l_len = 1; while ((rc = fcntl(env->me_lfd, F_SETLK, &lock_info)) && (rc = ErrCode()) == EINTR) ; *excl = rc ? -1 : 0; /* error may mean we lost the lock */ } #endif return rc; } /** Try to get exclusive lock, otherwise shared. * Maintain *excl = -1: no/unknown lock, 0: shared, 1: exclusive. */ static int ESECT mdb_env_excl_lock(MDB_env *env, int *excl) { int rc = 0; #ifdef _WIN32 if (LockFile(env->me_lfd, 0, 0, 1, 0)) { *excl = 1; } else { OVERLAPPED ov; memset(&ov, 0, sizeof(ov)); if (LockFileEx(env->me_lfd, 0, 0, 1, 0, &ov)) { *excl = 0; } else { rc = ErrCode(); } } #else struct flock lock_info; memset((void *)&lock_info, 0, sizeof(lock_info)); lock_info.l_type = F_WRLCK; lock_info.l_whence = SEEK_SET; lock_info.l_start = 0; lock_info.l_len = 1; while ((rc = fcntl(env->me_lfd, F_SETLK, &lock_info)) && (rc = ErrCode()) == EINTR) ; if (!rc) { *excl = 1; } else # ifndef MDB_USE_POSIX_MUTEX if (*excl < 0) /* always true when MDB_USE_POSIX_MUTEX */ # endif { lock_info.l_type = F_RDLCK; while ((rc = fcntl(env->me_lfd, F_SETLKW, &lock_info)) && (rc = ErrCode()) == EINTR) ; if (rc == 0) *excl = 0; } #endif return rc; } #ifdef MDB_USE_HASH /* * hash_64 - 64 bit Fowler/Noll/Vo-0 FNV-1a hash code * * @(#) $Revision: 5.1 $ * @(#) $Id: hash_64a.c,v 5.1 2009/06/30 09:01:38 chongo Exp $ * @(#) $Source: /usr/local/src/cmd/fnv/RCS/hash_64a.c,v $ * * http://www.isthe.com/chongo/tech/comp/fnv/index.html * *** * * Please do not copyright this code. This code is in the public domain. * * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * By: * chongo /\oo/\ * http://www.isthe.com/chongo/ * * Share and Enjoy! :-) */ typedef unsigned long long mdb_hash_t; #define MDB_HASH_INIT ((mdb_hash_t)0xcbf29ce484222325ULL) /** perform a 64 bit Fowler/Noll/Vo FNV-1a hash on a buffer * @param[in] val value to hash * @param[in] hval initial value for hash * @return 64 bit hash * * NOTE: To use the recommended 64 bit FNV-1a hash, use MDB_HASH_INIT as the * hval arg on the first call. */ static mdb_hash_t mdb_hash_val(MDB_val *val, mdb_hash_t hval) { unsigned char *s = (unsigned char *)val->mv_data; /* unsigned string */ unsigned char *end = s + val->mv_size; /* * FNV-1a hash each octet of the string */ while (s < end) { /* xor the bottom with the current octet */ hval ^= (mdb_hash_t)*s++; /* multiply by the 64 bit FNV magic prime mod 2^64 */ hval += (hval << 1) + (hval << 4) + (hval << 5) + (hval << 7) + (hval << 8) + (hval << 40); } /* return our new hash value */ return hval; } /** Hash the string and output the encoded hash. * This uses modified RFC1924 Ascii85 encoding to accommodate systems with * very short name limits. We don't care about the encoding being reversible, * we just want to preserve as many bits of the input as possible in a * small printable string. * @param[in] str string to hash * @param[out] encbuf an array of 11 chars to hold the hash */ static const char mdb_a85[]= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"; static void ESECT mdb_pack85(unsigned long l, char *out) { int i; for (i=0; i<5; i++) { *out++ = mdb_a85[l % 85]; l /= 85; } } static void ESECT mdb_hash_enc(MDB_val *val, char *encbuf) { mdb_hash_t h = mdb_hash_val(val, MDB_HASH_INIT); mdb_pack85(h, encbuf); mdb_pack85(h>>32, encbuf+5); encbuf[10] = '\0'; } #endif /** Open and/or initialize the lock region for the environment. * @param[in] env The LMDB environment. * @param[in] fname Filename + scratch area, from #mdb_fname_init(). * @param[in] mode The Unix permissions for the file, if we create it. * @param[in,out] excl In -1, out lock type: -1 none, 0 shared, 1 exclusive * @return 0 on success, non-zero on failure. */ static int ESECT mdb_env_setup_locks(MDB_env *env, MDB_name *fname, int mode, int *excl) { #ifdef _WIN32 # define MDB_ERRCODE_ROFS ERROR_WRITE_PROTECT #else # define MDB_ERRCODE_ROFS EROFS #endif int rc; off_t size, rsize; rc = mdb_fopen(env, fname, MDB_O_LOCKS, mode, &env->me_lfd); if (rc) { /* Omit lockfile if read-only env on read-only filesystem */ if (rc == MDB_ERRCODE_ROFS && (env->me_flags & MDB_RDONLY)) { return MDB_SUCCESS; } goto fail; } if (!(env->me_flags & MDB_NOTLS)) { rc = pthread_key_create(&env->me_txkey, mdb_env_reader_dest); if (rc) goto fail; env->me_flags |= MDB_ENV_TXKEY; #ifdef _WIN32 /* Windows TLS callbacks need help finding their TLS info. */ if (mdb_tls_nkeys >= MAX_TLS_KEYS) { rc = MDB_TLS_FULL; goto fail; } mdb_tls_keys[mdb_tls_nkeys++] = env->me_txkey; #endif } /* Try to get exclusive lock. If we succeed, then * nobody is using the lock region and we should initialize it. */ if ((rc = mdb_env_excl_lock(env, excl))) goto fail; #ifdef _WIN32 size = GetFileSize(env->me_lfd, NULL); #else size = lseek(env->me_lfd, 0, SEEK_END); if (size == -1) goto fail_errno; #endif rsize = (env->me_maxreaders-1) * sizeof(MDB_reader) + sizeof(MDB_txninfo); if (size < rsize && *excl > 0) { #ifdef _WIN32 if (SetFilePointer(env->me_lfd, rsize, NULL, FILE_BEGIN) != (DWORD)rsize || !SetEndOfFile(env->me_lfd)) goto fail_errno; #else if (ftruncate(env->me_lfd, rsize) != 0) goto fail_errno; #endif } else { rsize = size; size = rsize - sizeof(MDB_txninfo); env->me_maxreaders = size/sizeof(MDB_reader) + 1; } { #ifdef _WIN32 HANDLE mh; mh = CreateFileMapping(env->me_lfd, NULL, PAGE_READWRITE, 0, 0, NULL); if (!mh) goto fail_errno; env->me_txns = MapViewOfFileEx(mh, FILE_MAP_WRITE, 0, 0, rsize, NULL); CloseHandle(mh); if (!env->me_txns) goto fail_errno; #else void *m = mmap(NULL, rsize, PROT_READ|PROT_WRITE, MAP_SHARED, env->me_lfd, 0); if (m == MAP_FAILED) goto fail_errno; env->me_txns = m; #endif } if (*excl > 0) { #ifdef _WIN32 BY_HANDLE_FILE_INFORMATION stbuf; struct { DWORD volume; DWORD nhigh; DWORD nlow; } idbuf; MDB_val val; char encbuf[11]; if (!mdb_sec_inited) { InitializeSecurityDescriptor(&mdb_null_sd, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(&mdb_null_sd, TRUE, 0, FALSE); mdb_all_sa.nLength = sizeof(SECURITY_ATTRIBUTES); mdb_all_sa.bInheritHandle = FALSE; mdb_all_sa.lpSecurityDescriptor = &mdb_null_sd; mdb_sec_inited = 1; } if (!GetFileInformationByHandle(env->me_lfd, &stbuf)) goto fail_errno; idbuf.volume = stbuf.dwVolumeSerialNumber; idbuf.nhigh = stbuf.nFileIndexHigh; idbuf.nlow = stbuf.nFileIndexLow; val.mv_data = &idbuf; val.mv_size = sizeof(idbuf); mdb_hash_enc(&val, encbuf); sprintf(env->me_txns->mti_rmname, "Global\\MDBr%s", encbuf); sprintf(env->me_txns->mti_wmname, "Global\\MDBw%s", encbuf); env->me_rmutex = CreateMutexA(&mdb_all_sa, FALSE, env->me_txns->mti_rmname); if (!env->me_rmutex) goto fail_errno; env->me_wmutex = CreateMutexA(&mdb_all_sa, FALSE, env->me_txns->mti_wmname); if (!env->me_wmutex) goto fail_errno; #elif defined(MDB_USE_POSIX_SEM) struct stat stbuf; struct { dev_t dev; ino_t ino; } idbuf; MDB_val val; char encbuf[11]; #if defined(__NetBSD__) #define MDB_SHORT_SEMNAMES 1 /* limited to 14 chars */ #endif if (fstat(env->me_lfd, &stbuf)) goto fail_errno; idbuf.dev = stbuf.st_dev; idbuf.ino = stbuf.st_ino; val.mv_data = &idbuf; val.mv_size = sizeof(idbuf); mdb_hash_enc(&val, encbuf); #ifdef MDB_SHORT_SEMNAMES encbuf[9] = '\0'; /* drop name from 15 chars to 14 chars */ #endif sprintf(env->me_txns->mti_rmname, "/MDBr%s", encbuf); sprintf(env->me_txns->mti_wmname, "/MDBw%s", encbuf); /* Clean up after a previous run, if needed: Try to * remove both semaphores before doing anything else. */ sem_unlink(env->me_txns->mti_rmname); sem_unlink(env->me_txns->mti_wmname); env->me_rmutex = sem_open(env->me_txns->mti_rmname, O_CREAT|O_EXCL, mode, 1); if (env->me_rmutex == SEM_FAILED) goto fail_errno; env->me_wmutex = sem_open(env->me_txns->mti_wmname, O_CREAT|O_EXCL, mode, 1); if (env->me_wmutex == SEM_FAILED) goto fail_errno; #else /* MDB_USE_POSIX_MUTEX: */ pthread_mutexattr_t mattr; /* Solaris needs this before initing a robust mutex. Otherwise * it may skip the init and return EBUSY "seems someone already * inited" or EINVAL "it was inited differently". */ memset(env->me_txns->mti_rmutex, 0, sizeof(*env->me_txns->mti_rmutex)); memset(env->me_txns->mti_wmutex, 0, sizeof(*env->me_txns->mti_wmutex)); if ((rc = pthread_mutexattr_init(&mattr))) goto fail; rc = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED); #ifdef MDB_ROBUST_SUPPORTED if (!rc) rc = pthread_mutexattr_setrobust(&mattr, PTHREAD_MUTEX_ROBUST); #endif if (!rc) rc = pthread_mutex_init(env->me_txns->mti_rmutex, &mattr); if (!rc) rc = pthread_mutex_init(env->me_txns->mti_wmutex, &mattr); pthread_mutexattr_destroy(&mattr); if (rc) goto fail; #endif /* _WIN32 || MDB_USE_POSIX_SEM */ env->me_txns->mti_magic = MDB_MAGIC; env->me_txns->mti_format = MDB_LOCK_FORMAT; env->me_txns->mti_txnid = 0; env->me_txns->mti_numreaders = 0; } else { if (env->me_txns->mti_magic != MDB_MAGIC) { DPUTS("lock region has invalid magic"); rc = MDB_INVALID; goto fail; } if (env->me_txns->mti_format != MDB_LOCK_FORMAT) { DPRINTF(("lock region has format+version 0x%x, expected 0x%x", env->me_txns->mti_format, MDB_LOCK_FORMAT)); rc = MDB_VERSION_MISMATCH; goto fail; } rc = ErrCode(); if (rc && rc != EACCES && rc != EAGAIN) { goto fail; } #ifdef _WIN32 env->me_rmutex = OpenMutexA(SYNCHRONIZE, FALSE, env->me_txns->mti_rmname); if (!env->me_rmutex) goto fail_errno; env->me_wmutex = OpenMutexA(SYNCHRONIZE, FALSE, env->me_txns->mti_wmname); if (!env->me_wmutex) goto fail_errno; #elif defined(MDB_USE_POSIX_SEM) env->me_rmutex = sem_open(env->me_txns->mti_rmname, 0); if (env->me_rmutex == SEM_FAILED) goto fail_errno; env->me_wmutex = sem_open(env->me_txns->mti_wmname, 0); if (env->me_wmutex == SEM_FAILED) goto fail_errno; #endif } return MDB_SUCCESS; fail_errno: rc = ErrCode(); fail: return rc; } /** Only a subset of the @ref mdb_env flags can be changed * at runtime. Changing other flags requires closing the * environment and re-opening it with the new flags. */ #define CHANGEABLE (MDB_NOSYNC|MDB_NOMETASYNC|MDB_MAPASYNC|MDB_NOMEMINIT) #define CHANGELESS (MDB_FIXEDMAP|MDB_NOSUBDIR|MDB_RDONLY| \ MDB_WRITEMAP|MDB_NOTLS|MDB_NOLOCK|MDB_NORDAHEAD) #if VALID_FLAGS & PERSISTENT_FLAGS & (CHANGEABLE|CHANGELESS) # error "Persistent DB flags & env flags overlap, but both go in mm_flags" #endif int ESECT mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode) { int rc, excl = -1; MDB_name fname; if (env->me_fd!=INVALID_HANDLE_VALUE || (flags & ~(CHANGEABLE|CHANGELESS))) return EINVAL; flags |= env->me_flags; rc = mdb_fname_init(path, flags, &fname); if (rc) return rc; if (flags & MDB_RDONLY) { /* silently ignore WRITEMAP when we're only getting read access */ flags &= ~MDB_WRITEMAP; } else { if (!((env->me_free_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX)) && (env->me_dirty_list = calloc(MDB_IDL_UM_SIZE, sizeof(MDB_ID2))))) rc = ENOMEM; } env->me_flags = flags |= MDB_ENV_ACTIVE; if (rc) goto leave; env->me_path = strdup(path); env->me_dbxs = calloc(env->me_maxdbs, sizeof(MDB_dbx)); env->me_dbflags = calloc(env->me_maxdbs, sizeof(uint16_t)); env->me_dbiseqs = calloc(env->me_maxdbs, sizeof(unsigned int)); if (!(env->me_dbxs && env->me_path && env->me_dbflags && env->me_dbiseqs)) { rc = ENOMEM; goto leave; } env->me_dbxs[FREE_DBI].md_cmp = mdb_cmp_long; /* aligned MDB_INTEGERKEY */ /* For RDONLY, get lockfile after we know datafile exists */ if (!(flags & (MDB_RDONLY|MDB_NOLOCK))) { rc = mdb_env_setup_locks(env, &fname, mode, &excl); if (rc) goto leave; } rc = mdb_fopen(env, &fname, (flags & MDB_RDONLY) ? MDB_O_RDONLY : MDB_O_RDWR, mode, &env->me_fd); if (rc) goto leave; if ((flags & (MDB_RDONLY|MDB_NOLOCK)) == MDB_RDONLY) { rc = mdb_env_setup_locks(env, &fname, mode, &excl); if (rc) goto leave; } if ((rc = mdb_env_open2(env)) == MDB_SUCCESS) { if (!(flags & (MDB_RDONLY|MDB_WRITEMAP))) { /* Synchronous fd for meta writes. Needed even with * MDB_NOSYNC/MDB_NOMETASYNC, in case these get reset. */ rc = mdb_fopen(env, &fname, MDB_O_META, mode, &env->me_mfd); if (rc) goto leave; } DPRINTF(("opened dbenv %p", (void *) env)); if (excl > 0) { rc = mdb_env_share_locks(env, &excl); if (rc) goto leave; } if (!(flags & MDB_RDONLY)) { MDB_txn *txn; int tsize = sizeof(MDB_txn), size = tsize + env->me_maxdbs * (sizeof(MDB_db)+sizeof(MDB_cursor *)+sizeof(unsigned int)+1); if ((env->me_pbuf = calloc(1, env->me_psize)) && (txn = calloc(1, size))) { txn->mt_dbs = (MDB_db *)((char *)txn + tsize); txn->mt_cursors = (MDB_cursor **)(txn->mt_dbs + env->me_maxdbs); txn->mt_dbiseqs = (unsigned int *)(txn->mt_cursors + env->me_maxdbs); txn->mt_dbflags = (unsigned char *)(txn->mt_dbiseqs + env->me_maxdbs); txn->mt_env = env; txn->mt_dbxs = env->me_dbxs; txn->mt_flags = MDB_TXN_FINISHED; env->me_txn0 = txn; } else { rc = ENOMEM; } } } leave: if (rc) { mdb_env_close0(env, excl); } mdb_fname_destroy(fname); return rc; } /** Destroy resources from mdb_env_open(), clear our readers & DBIs */ static void ESECT mdb_env_close0(MDB_env *env, int excl) { int i; if (!(env->me_flags & MDB_ENV_ACTIVE)) return; /* Doing this here since me_dbxs may not exist during mdb_env_close */ if (env->me_dbxs) { for (i = env->me_maxdbs; --i >= CORE_DBS; ) free(env->me_dbxs[i].md_name.mv_data); free(env->me_dbxs); } free(env->me_pbuf); free(env->me_dbiseqs); free(env->me_dbflags); free(env->me_path); free(env->me_dirty_list); free(env->me_txn0); mdb_midl_free(env->me_free_pgs); if (env->me_flags & MDB_ENV_TXKEY) { pthread_key_delete(env->me_txkey); #ifdef _WIN32 /* Delete our key from the global list */ for (i=0; ime_txkey) { mdb_tls_keys[i] = mdb_tls_keys[mdb_tls_nkeys-1]; mdb_tls_nkeys--; break; } #endif } if (env->me_map) { munmap(env->me_map, env->me_mapsize); } if (env->me_mfd != INVALID_HANDLE_VALUE) (void) close(env->me_mfd); if (env->me_fd != INVALID_HANDLE_VALUE) (void) close(env->me_fd); if (env->me_txns) { MDB_PID_T pid = getpid(); /* Clearing readers is done in this function because * me_txkey with its destructor must be disabled first. * * We skip the the reader mutex, so we touch only * data owned by this process (me_close_readers and * our readers), and clear each reader atomically. */ for (i = env->me_close_readers; --i >= 0; ) if (env->me_txns->mti_readers[i].mr_pid == pid) env->me_txns->mti_readers[i].mr_pid = 0; #ifdef _WIN32 if (env->me_rmutex) { CloseHandle(env->me_rmutex); if (env->me_wmutex) CloseHandle(env->me_wmutex); } /* Windows automatically destroys the mutexes when * the last handle closes. */ #elif defined(MDB_USE_POSIX_SEM) if (env->me_rmutex != SEM_FAILED) { sem_close(env->me_rmutex); if (env->me_wmutex != SEM_FAILED) sem_close(env->me_wmutex); /* If we have the filelock: If we are the * only remaining user, clean up semaphores. */ if (excl == 0) mdb_env_excl_lock(env, &excl); if (excl > 0) { sem_unlink(env->me_txns->mti_rmname); sem_unlink(env->me_txns->mti_wmname); } } #elif defined(MDB_ROBUST_SUPPORTED) /* If we have the filelock: If we are the * only remaining user, clean up robust * mutexes. */ if (excl == 0) mdb_env_excl_lock(env, &excl); if (excl > 0) { pthread_mutex_destroy(env->me_txns->mti_rmutex); pthread_mutex_destroy(env->me_txns->mti_wmutex); } #endif munmap((void *)env->me_txns, (env->me_maxreaders-1)*sizeof(MDB_reader)+sizeof(MDB_txninfo)); } if (env->me_lfd != INVALID_HANDLE_VALUE) { #ifdef _WIN32 if (excl >= 0) { /* Unlock the lockfile. Windows would have unlocked it * after closing anyway, but not necessarily at once. */ UnlockFile(env->me_lfd, 0, 0, 1, 0); } #endif (void) close(env->me_lfd); } env->me_flags &= ~(MDB_ENV_ACTIVE|MDB_ENV_TXKEY); } void ESECT mdb_env_close(MDB_env *env) { MDB_page *dp; if (env == NULL) return; VGMEMP_DESTROY(env); while ((dp = env->me_dpages) != NULL) { VGMEMP_DEFINED(&dp->mp_next, sizeof(dp->mp_next)); env->me_dpages = dp->mp_next; free(dp); } mdb_env_close0(env, 0); free(env); } /** Compare two items pointing at aligned size_t's */ static int mdb_cmp_long(const MDB_val *a, const MDB_val *b) { return (*(size_t *)a->mv_data < *(size_t *)b->mv_data) ? -1 : *(size_t *)a->mv_data > *(size_t *)b->mv_data; } /** Compare two items pointing at aligned unsigned int's. * * This is also set as #MDB_INTEGERDUP|#MDB_DUPFIXED's #MDB_dbx.%md_dcmp, * but #mdb_cmp_clong() is called instead if the data type is size_t. */ static int mdb_cmp_int(const MDB_val *a, const MDB_val *b) { return (*(unsigned int *)a->mv_data < *(unsigned int *)b->mv_data) ? -1 : *(unsigned int *)a->mv_data > *(unsigned int *)b->mv_data; } /** Compare two items pointing at unsigned ints of unknown alignment. * Nodes and keys are guaranteed to be 2-byte aligned. */ static int mdb_cmp_cint(const MDB_val *a, const MDB_val *b) { #if BYTE_ORDER == LITTLE_ENDIAN unsigned short *u, *c; int x; u = (unsigned short *) ((char *) a->mv_data + a->mv_size); c = (unsigned short *) ((char *) b->mv_data + a->mv_size); do { x = *--u - *--c; } while(!x && u > (unsigned short *)a->mv_data); return x; #else unsigned short *u, *c, *end; int x; end = (unsigned short *) ((char *) a->mv_data + a->mv_size); u = (unsigned short *)a->mv_data; c = (unsigned short *)b->mv_data; do { x = *u++ - *c++; } while(!x && u < end); return x; #endif } /** Compare two items lexically */ static int mdb_cmp_memn(const MDB_val *a, const MDB_val *b) { int diff; ssize_t len_diff; unsigned int len; len = a->mv_size; len_diff = (ssize_t) a->mv_size - (ssize_t) b->mv_size; if (len_diff > 0) { len = b->mv_size; len_diff = 1; } diff = memcmp(a->mv_data, b->mv_data, len); return diff ? diff : len_diff<0 ? -1 : len_diff; } /** Compare two items in reverse byte order */ static int mdb_cmp_memnr(const MDB_val *a, const MDB_val *b) { const unsigned char *p1, *p2, *p1_lim; ssize_t len_diff; int diff; p1_lim = (const unsigned char *)a->mv_data; p1 = (const unsigned char *)a->mv_data + a->mv_size; p2 = (const unsigned char *)b->mv_data + b->mv_size; len_diff = (ssize_t) a->mv_size - (ssize_t) b->mv_size; if (len_diff > 0) { p1_lim += len_diff; len_diff = 1; } while (p1 > p1_lim) { diff = *--p1 - *--p2; if (diff) return diff; } return len_diff<0 ? -1 : len_diff; } /** Search for key within a page, using binary search. * Returns the smallest entry larger or equal to the key. * If exactp is non-null, stores whether the found entry was an exact match * in *exactp (1 or 0). * Updates the cursor index with the index of the found entry. * If no entry larger or equal to the key is found, returns NULL. */ static MDB_node * mdb_node_search(MDB_cursor *mc, MDB_val *key, int *exactp) { unsigned int i = 0, nkeys; int low, high; int rc = 0; MDB_page *mp = mc->mc_pg[mc->mc_top]; MDB_node *node = NULL; MDB_val nodekey; MDB_cmp_func *cmp; DKBUF; nkeys = NUMKEYS(mp); DPRINTF(("searching %u keys in %s %spage %"Z"u", nkeys, IS_LEAF(mp) ? "leaf" : "branch", IS_SUBP(mp) ? "sub-" : "", mdb_dbg_pgno(mp))); low = IS_LEAF(mp) ? 0 : 1; high = nkeys - 1; cmp = mc->mc_dbx->md_cmp; /* Branch pages have no data, so if using integer keys, * alignment is guaranteed. Use faster mdb_cmp_int. */ if (cmp == mdb_cmp_cint && IS_BRANCH(mp)) { if (NODEPTR(mp, 1)->mn_ksize == sizeof(size_t)) cmp = mdb_cmp_long; else cmp = mdb_cmp_int; } if (IS_LEAF2(mp)) { nodekey.mv_size = mc->mc_db->md_pad; node = NODEPTR(mp, 0); /* fake */ while (low <= high) { i = (low + high) >> 1; nodekey.mv_data = LEAF2KEY(mp, i, nodekey.mv_size); rc = cmp(key, &nodekey); DPRINTF(("found leaf index %u [%s], rc = %i", i, DKEY(&nodekey), rc)); if (rc == 0) break; if (rc > 0) low = i + 1; else high = i - 1; } } else { while (low <= high) { i = (low + high) >> 1; node = NODEPTR(mp, i); nodekey.mv_size = NODEKSZ(node); nodekey.mv_data = NODEKEY(node); rc = cmp(key, &nodekey); #if MDB_DEBUG if (IS_LEAF(mp)) DPRINTF(("found leaf index %u [%s], rc = %i", i, DKEY(&nodekey), rc)); else DPRINTF(("found branch index %u [%s -> %"Z"u], rc = %i", i, DKEY(&nodekey), NODEPGNO(node), rc)); #endif if (rc == 0) break; if (rc > 0) low = i + 1; else high = i - 1; } } if (rc > 0) { /* Found entry is less than the key. */ i++; /* Skip to get the smallest entry larger than key. */ if (!IS_LEAF2(mp)) node = NODEPTR(mp, i); } if (exactp) *exactp = (rc == 0 && nkeys > 0); /* store the key index */ mc->mc_ki[mc->mc_top] = i; if (i >= nkeys) /* There is no entry larger or equal to the key. */ return NULL; /* nodeptr is fake for LEAF2 */ return node; } #if 0 static void mdb_cursor_adjust(MDB_cursor *mc, func) { MDB_cursor *m2; for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2=m2->mc_next) { if (m2->mc_pg[m2->mc_top] == mc->mc_pg[mc->mc_top]) { func(mc, m2); } } } #endif /** Pop a page off the top of the cursor's stack. */ static void mdb_cursor_pop(MDB_cursor *mc) { if (mc->mc_snum) { DPRINTF(("popping page %"Z"u off db %d cursor %p", mc->mc_pg[mc->mc_top]->mp_pgno, DDBI(mc), (void *) mc)); mc->mc_snum--; if (mc->mc_snum) { mc->mc_top--; } else { mc->mc_flags &= ~C_INITIALIZED; } } } /** Push a page onto the top of the cursor's stack. * Set #MDB_TXN_ERROR on failure. */ static int mdb_cursor_push(MDB_cursor *mc, MDB_page *mp) { DPRINTF(("pushing page %"Z"u on db %d cursor %p", mp->mp_pgno, DDBI(mc), (void *) mc)); if (mc->mc_snum >= CURSOR_STACK) { mc->mc_txn->mt_flags |= MDB_TXN_ERROR; return MDB_CURSOR_FULL; } mc->mc_top = mc->mc_snum++; mc->mc_pg[mc->mc_top] = mp; mc->mc_ki[mc->mc_top] = 0; return MDB_SUCCESS; } /** Find the address of the page corresponding to a given page number. * Set #MDB_TXN_ERROR on failure. * @param[in] mc the cursor accessing the page. * @param[in] pgno the page number for the page to retrieve. * @param[out] ret address of a pointer where the page's address will be stored. * @param[out] lvl dirty_list inheritance level of found page. 1=current txn, 0=mapped page. * @return 0 on success, non-zero on failure. */ static int mdb_page_get(MDB_cursor *mc, pgno_t pgno, MDB_page **ret, int *lvl) { MDB_txn *txn = mc->mc_txn; MDB_env *env = txn->mt_env; MDB_page *p = NULL; int level; if (! (txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_WRITEMAP))) { MDB_txn *tx2 = txn; level = 1; do { MDB_ID2L dl = tx2->mt_u.dirty_list; unsigned x; /* Spilled pages were dirtied in this txn and flushed * because the dirty list got full. Bring this page * back in from the map (but don't unspill it here, * leave that unless page_touch happens again). */ if (tx2->mt_spill_pgs) { MDB_ID pn = pgno << 1; x = mdb_midl_search(tx2->mt_spill_pgs, pn); if (x <= tx2->mt_spill_pgs[0] && tx2->mt_spill_pgs[x] == pn) { p = (MDB_page *)(env->me_map + env->me_psize * pgno); goto done; } } if (dl[0].mid) { unsigned x = mdb_mid2l_search(dl, pgno); if (x <= dl[0].mid && dl[x].mid == pgno) { p = dl[x].mptr; goto done; } } level++; } while ((tx2 = tx2->mt_parent) != NULL); } if (pgno < txn->mt_next_pgno) { level = 0; p = (MDB_page *)(env->me_map + env->me_psize * pgno); } else { DPRINTF(("page %"Z"u not found", pgno)); txn->mt_flags |= MDB_TXN_ERROR; return MDB_PAGE_NOTFOUND; } done: *ret = p; if (lvl) *lvl = level; return MDB_SUCCESS; } /** Finish #mdb_page_search() / #mdb_page_search_lowest(). * The cursor is at the root page, set up the rest of it. */ static int mdb_page_search_root(MDB_cursor *mc, MDB_val *key, int flags) { MDB_page *mp = mc->mc_pg[mc->mc_top]; int rc; DKBUF; while (IS_BRANCH(mp)) { MDB_node *node; indx_t i; DPRINTF(("branch page %"Z"u has %u keys", mp->mp_pgno, NUMKEYS(mp))); /* Don't assert on branch pages in the FreeDB. We can get here * while in the process of rebalancing a FreeDB branch page; we must * let that proceed. ITS#8336 */ mdb_cassert(mc, !mc->mc_dbi || NUMKEYS(mp) > 1); DPRINTF(("found index 0 to page %"Z"u", NODEPGNO(NODEPTR(mp, 0)))); if (flags & (MDB_PS_FIRST|MDB_PS_LAST)) { i = 0; if (flags & MDB_PS_LAST) { i = NUMKEYS(mp) - 1; /* if already init'd, see if we're already in right place */ if (mc->mc_flags & C_INITIALIZED) { if (mc->mc_ki[mc->mc_top] == i) { mc->mc_top = mc->mc_snum++; mp = mc->mc_pg[mc->mc_top]; goto ready; } } } } else { int exact; node = mdb_node_search(mc, key, &exact); if (node == NULL) i = NUMKEYS(mp) - 1; else { i = mc->mc_ki[mc->mc_top]; if (!exact) { mdb_cassert(mc, i > 0); i--; } } DPRINTF(("following index %u for key [%s]", i, DKEY(key))); } mdb_cassert(mc, i < NUMKEYS(mp)); node = NODEPTR(mp, i); if ((rc = mdb_page_get(mc, NODEPGNO(node), &mp, NULL)) != 0) return rc; mc->mc_ki[mc->mc_top] = i; if ((rc = mdb_cursor_push(mc, mp))) return rc; ready: if (flags & MDB_PS_MODIFY) { if ((rc = mdb_page_touch(mc)) != 0) return rc; mp = mc->mc_pg[mc->mc_top]; } } if (!IS_LEAF(mp)) { DPRINTF(("internal error, index points to a %02X page!?", mp->mp_flags)); mc->mc_txn->mt_flags |= MDB_TXN_ERROR; return MDB_CORRUPTED; } DPRINTF(("found leaf page %"Z"u for key [%s]", mp->mp_pgno, key ? DKEY(key) : "null")); mc->mc_flags |= C_INITIALIZED; mc->mc_flags &= ~C_EOF; return MDB_SUCCESS; } /** Search for the lowest key under the current branch page. * This just bypasses a NUMKEYS check in the current page * before calling mdb_page_search_root(), because the callers * are all in situations where the current page is known to * be underfilled. */ static int mdb_page_search_lowest(MDB_cursor *mc) { MDB_page *mp = mc->mc_pg[mc->mc_top]; MDB_node *node = NODEPTR(mp, 0); int rc; if ((rc = mdb_page_get(mc, NODEPGNO(node), &mp, NULL)) != 0) return rc; mc->mc_ki[mc->mc_top] = 0; if ((rc = mdb_cursor_push(mc, mp))) return rc; return mdb_page_search_root(mc, NULL, MDB_PS_FIRST); } /** Search for the page a given key should be in. * Push it and its parent pages on the cursor stack. * @param[in,out] mc the cursor for this operation. * @param[in] key the key to search for, or NULL for first/last page. * @param[in] flags If MDB_PS_MODIFY is set, visited pages in the DB * are touched (updated with new page numbers). * If MDB_PS_FIRST or MDB_PS_LAST is set, find first or last leaf. * This is used by #mdb_cursor_first() and #mdb_cursor_last(). * If MDB_PS_ROOTONLY set, just fetch root node, no further lookups. * @return 0 on success, non-zero on failure. */ static int mdb_page_search(MDB_cursor *mc, MDB_val *key, int flags) { int rc; pgno_t root; /* Make sure the txn is still viable, then find the root from * the txn's db table and set it as the root of the cursor's stack. */ if (mc->mc_txn->mt_flags & MDB_TXN_BLOCKED) { DPUTS("transaction may not be used now"); return MDB_BAD_TXN; } else { /* Make sure we're using an up-to-date root */ if (*mc->mc_dbflag & DB_STALE) { MDB_cursor mc2; if (TXN_DBI_CHANGED(mc->mc_txn, mc->mc_dbi)) return MDB_BAD_DBI; mdb_cursor_init(&mc2, mc->mc_txn, MAIN_DBI, NULL); rc = mdb_page_search(&mc2, &mc->mc_dbx->md_name, 0); if (rc) return rc; { MDB_val data; int exact = 0; uint16_t flags; MDB_node *leaf = mdb_node_search(&mc2, &mc->mc_dbx->md_name, &exact); if (!exact) return MDB_NOTFOUND; if ((leaf->mn_flags & (F_DUPDATA|F_SUBDATA)) != F_SUBDATA) return MDB_INCOMPATIBLE; /* not a named DB */ rc = mdb_node_read(&mc2, leaf, &data); if (rc) return rc; memcpy(&flags, ((char *) data.mv_data + offsetof(MDB_db, md_flags)), sizeof(uint16_t)); /* The txn may not know this DBI, or another process may * have dropped and recreated the DB with other flags. */ if ((mc->mc_db->md_flags & PERSISTENT_FLAGS) != flags) return MDB_INCOMPATIBLE; memcpy(mc->mc_db, data.mv_data, sizeof(MDB_db)); } *mc->mc_dbflag &= ~DB_STALE; } root = mc->mc_db->md_root; if (root == P_INVALID) { /* Tree is empty. */ DPUTS("tree is empty"); return MDB_NOTFOUND; } } mdb_cassert(mc, root > 1); if (!mc->mc_pg[0] || mc->mc_pg[0]->mp_pgno != root) if ((rc = mdb_page_get(mc, root, &mc->mc_pg[0], NULL)) != 0) return rc; mc->mc_snum = 1; mc->mc_top = 0; DPRINTF(("db %d root page %"Z"u has flags 0x%X", DDBI(mc), root, mc->mc_pg[0]->mp_flags)); if (flags & MDB_PS_MODIFY) { if ((rc = mdb_page_touch(mc))) return rc; } if (flags & MDB_PS_ROOTONLY) return MDB_SUCCESS; return mdb_page_search_root(mc, key, flags); } static int mdb_ovpage_free(MDB_cursor *mc, MDB_page *mp) { MDB_txn *txn = mc->mc_txn; pgno_t pg = mp->mp_pgno; unsigned x = 0, ovpages = mp->mp_pages; MDB_env *env = txn->mt_env; MDB_IDL sl = txn->mt_spill_pgs; MDB_ID pn = pg << 1; int rc; DPRINTF(("free ov page %"Z"u (%d)", pg, ovpages)); /* If the page is dirty or on the spill list we just acquired it, * so we should give it back to our current free list, if any. * Otherwise put it onto the list of pages we freed in this txn. * * Won't create me_pghead: me_pglast must be inited along with it. * Unsupported in nested txns: They would need to hide the page * range in ancestor txns' dirty and spilled lists. */ if (env->me_pghead && !txn->mt_parent && ((mp->mp_flags & P_DIRTY) || (sl && (x = mdb_midl_search(sl, pn)) <= sl[0] && sl[x] == pn))) { unsigned i, j; pgno_t *mop; MDB_ID2 *dl, ix, iy; rc = mdb_midl_need(&env->me_pghead, ovpages); if (rc) return rc; if (!(mp->mp_flags & P_DIRTY)) { /* This page is no longer spilled */ if (x == sl[0]) sl[0]--; else sl[x] |= 1; goto release; } /* Remove from dirty list */ dl = txn->mt_u.dirty_list; x = dl[0].mid--; for (ix = dl[x]; ix.mptr != mp; ix = iy) { if (x > 1) { x--; iy = dl[x]; dl[x] = ix; } else { mdb_cassert(mc, x > 1); j = ++(dl[0].mid); dl[j] = ix; /* Unsorted. OK when MDB_TXN_ERROR. */ txn->mt_flags |= MDB_TXN_ERROR; return MDB_CORRUPTED; } } txn->mt_dirty_room++; if (!(env->me_flags & MDB_WRITEMAP)) mdb_dpage_free(env, mp); release: /* Insert in me_pghead */ mop = env->me_pghead; j = mop[0] + ovpages; for (i = mop[0]; i && mop[i] < pg; i--) mop[j--] = mop[i]; while (j>i) mop[j--] = pg++; mop[0] += ovpages; } else { rc = mdb_midl_append_range(&txn->mt_free_pgs, pg, ovpages); if (rc) return rc; } mc->mc_db->md_overflow_pages -= ovpages; return 0; } /** Return the data associated with a given node. * @param[in] mc The cursor for this operation. * @param[in] leaf The node being read. * @param[out] data Updated to point to the node's data. * @return 0 on success, non-zero on failure. */ static int mdb_node_read(MDB_cursor *mc, MDB_node *leaf, MDB_val *data) { MDB_page *omp; /* overflow page */ pgno_t pgno; int rc; if (!F_ISSET(leaf->mn_flags, F_BIGDATA)) { data->mv_size = NODEDSZ(leaf); data->mv_data = NODEDATA(leaf); return MDB_SUCCESS; } /* Read overflow data. */ data->mv_size = NODEDSZ(leaf); memcpy(&pgno, NODEDATA(leaf), sizeof(pgno)); if ((rc = mdb_page_get(mc, pgno, &omp, NULL)) != 0) { DPRINTF(("read overflow page %"Z"u failed", pgno)); return rc; } data->mv_data = METADATA(omp); return MDB_SUCCESS; } int mdb_get(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data) { MDB_cursor mc; MDB_xcursor mx; int exact = 0; DKBUF; DPRINTF(("===> get db %u key [%s]", dbi, DKEY(key))); if (!key || !data || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) return EINVAL; if (txn->mt_flags & MDB_TXN_BLOCKED) return MDB_BAD_TXN; mdb_cursor_init(&mc, txn, dbi, &mx); return mdb_cursor_set(&mc, key, data, MDB_SET, &exact); } /** Find a sibling for a page. * Replaces the page at the top of the cursor's stack with the * specified sibling, if one exists. * @param[in] mc The cursor for this operation. * @param[in] move_right Non-zero if the right sibling is requested, * otherwise the left sibling. * @return 0 on success, non-zero on failure. */ static int mdb_cursor_sibling(MDB_cursor *mc, int move_right) { int rc; MDB_node *indx; MDB_page *mp; if (mc->mc_snum < 2) { return MDB_NOTFOUND; /* root has no siblings */ } mdb_cursor_pop(mc); DPRINTF(("parent page is page %"Z"u, index %u", mc->mc_pg[mc->mc_top]->mp_pgno, mc->mc_ki[mc->mc_top])); if (move_right ? (mc->mc_ki[mc->mc_top] + 1u >= NUMKEYS(mc->mc_pg[mc->mc_top])) : (mc->mc_ki[mc->mc_top] == 0)) { DPRINTF(("no more keys left, moving to %s sibling", move_right ? "right" : "left")); if ((rc = mdb_cursor_sibling(mc, move_right)) != MDB_SUCCESS) { /* undo cursor_pop before returning */ mc->mc_top++; mc->mc_snum++; return rc; } } else { if (move_right) mc->mc_ki[mc->mc_top]++; else mc->mc_ki[mc->mc_top]--; DPRINTF(("just moving to %s index key %u", move_right ? "right" : "left", mc->mc_ki[mc->mc_top])); } mdb_cassert(mc, IS_BRANCH(mc->mc_pg[mc->mc_top])); indx = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); if ((rc = mdb_page_get(mc, NODEPGNO(indx), &mp, NULL)) != 0) { /* mc will be inconsistent if caller does mc_snum++ as above */ mc->mc_flags &= ~(C_INITIALIZED|C_EOF); return rc; } mdb_cursor_push(mc, mp); if (!move_right) mc->mc_ki[mc->mc_top] = NUMKEYS(mp)-1; return MDB_SUCCESS; } /** Move the cursor to the next data item. */ static int mdb_cursor_next(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op) { MDB_page *mp; MDB_node *leaf; int rc; if ((mc->mc_flags & C_DEL && op == MDB_NEXT_DUP)) return MDB_NOTFOUND; if (!(mc->mc_flags & C_INITIALIZED)) return mdb_cursor_first(mc, key, data); mp = mc->mc_pg[mc->mc_top]; if (mc->mc_flags & C_EOF) { if (mc->mc_ki[mc->mc_top] >= NUMKEYS(mp)-1) return MDB_NOTFOUND; mc->mc_flags ^= C_EOF; } if (mc->mc_db->md_flags & MDB_DUPSORT) { leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { if (op == MDB_NEXT || op == MDB_NEXT_DUP) { rc = mdb_cursor_next(&mc->mc_xcursor->mx_cursor, data, NULL, MDB_NEXT); if (op != MDB_NEXT || rc != MDB_NOTFOUND) { if (rc == MDB_SUCCESS) MDB_GET_KEY(leaf, key); return rc; } } } else { mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); if (op == MDB_NEXT_DUP) return MDB_NOTFOUND; } } DPRINTF(("cursor_next: top page is %"Z"u in cursor %p", mdb_dbg_pgno(mp), (void *) mc)); if (mc->mc_flags & C_DEL) { mc->mc_flags ^= C_DEL; goto skip; } if (mc->mc_ki[mc->mc_top] + 1u >= NUMKEYS(mp)) { DPUTS("=====> move to next sibling page"); if ((rc = mdb_cursor_sibling(mc, 1)) != MDB_SUCCESS) { mc->mc_flags |= C_EOF; return rc; } mp = mc->mc_pg[mc->mc_top]; DPRINTF(("next page is %"Z"u, key index %u", mp->mp_pgno, mc->mc_ki[mc->mc_top])); } else mc->mc_ki[mc->mc_top]++; skip: DPRINTF(("==> cursor points to page %"Z"u with %u keys, key index %u", mdb_dbg_pgno(mp), NUMKEYS(mp), mc->mc_ki[mc->mc_top])); if (IS_LEAF2(mp)) { key->mv_size = mc->mc_db->md_pad; key->mv_data = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->mv_size); return MDB_SUCCESS; } mdb_cassert(mc, IS_LEAF(mp)); leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { mdb_xcursor_init1(mc, leaf); rc = mdb_cursor_first(&mc->mc_xcursor->mx_cursor, data, NULL); if (rc != MDB_SUCCESS) return rc; } else if (data) { if ((rc = mdb_node_read(mc, leaf, data)) != MDB_SUCCESS) return rc; } MDB_GET_KEY(leaf, key); return MDB_SUCCESS; } /** Move the cursor to the previous data item. */ static int mdb_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op) { MDB_page *mp; MDB_node *leaf; int rc; if (!(mc->mc_flags & C_INITIALIZED)) { rc = mdb_cursor_last(mc, key, data); if (rc) return rc; mc->mc_ki[mc->mc_top]++; } mp = mc->mc_pg[mc->mc_top]; if ((mc->mc_db->md_flags & MDB_DUPSORT) && mc->mc_ki[mc->mc_top] < NUMKEYS(mp)) { leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { if (op == MDB_PREV || op == MDB_PREV_DUP) { rc = mdb_cursor_prev(&mc->mc_xcursor->mx_cursor, data, NULL, MDB_PREV); if (op != MDB_PREV || rc != MDB_NOTFOUND) { if (rc == MDB_SUCCESS) { MDB_GET_KEY(leaf, key); mc->mc_flags &= ~C_EOF; } return rc; } } } else { mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); if (op == MDB_PREV_DUP) return MDB_NOTFOUND; } } DPRINTF(("cursor_prev: top page is %"Z"u in cursor %p", mdb_dbg_pgno(mp), (void *) mc)); mc->mc_flags &= ~(C_EOF|C_DEL); if (mc->mc_ki[mc->mc_top] == 0) { DPUTS("=====> move to prev sibling page"); if ((rc = mdb_cursor_sibling(mc, 0)) != MDB_SUCCESS) { return rc; } mp = mc->mc_pg[mc->mc_top]; mc->mc_ki[mc->mc_top] = NUMKEYS(mp) - 1; DPRINTF(("prev page is %"Z"u, key index %u", mp->mp_pgno, mc->mc_ki[mc->mc_top])); } else mc->mc_ki[mc->mc_top]--; DPRINTF(("==> cursor points to page %"Z"u with %u keys, key index %u", mdb_dbg_pgno(mp), NUMKEYS(mp), mc->mc_ki[mc->mc_top])); if (!IS_LEAF(mp)) return MDB_CORRUPTED; if (IS_LEAF2(mp)) { key->mv_size = mc->mc_db->md_pad; key->mv_data = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->mv_size); return MDB_SUCCESS; } leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { mdb_xcursor_init1(mc, leaf); rc = mdb_cursor_last(&mc->mc_xcursor->mx_cursor, data, NULL); if (rc != MDB_SUCCESS) return rc; } else if (data) { if ((rc = mdb_node_read(mc, leaf, data)) != MDB_SUCCESS) return rc; } MDB_GET_KEY(leaf, key); return MDB_SUCCESS; } /** Set the cursor on a specific data item. */ static int mdb_cursor_set(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op, int *exactp) { int rc; MDB_page *mp; MDB_node *leaf = NULL; DKBUF; if (key->mv_size == 0) return MDB_BAD_VALSIZE; if (mc->mc_xcursor) mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); /* See if we're already on the right page */ if (mc->mc_flags & C_INITIALIZED) { MDB_val nodekey; mp = mc->mc_pg[mc->mc_top]; if (!NUMKEYS(mp)) { mc->mc_ki[mc->mc_top] = 0; return MDB_NOTFOUND; } if (mp->mp_flags & P_LEAF2) { nodekey.mv_size = mc->mc_db->md_pad; nodekey.mv_data = LEAF2KEY(mp, 0, nodekey.mv_size); } else { leaf = NODEPTR(mp, 0); MDB_GET_KEY2(leaf, nodekey); } rc = mc->mc_dbx->md_cmp(key, &nodekey); if (rc == 0) { /* Probably happens rarely, but first node on the page * was the one we wanted. */ mc->mc_ki[mc->mc_top] = 0; if (exactp) *exactp = 1; goto set1; } if (rc > 0) { unsigned int i; unsigned int nkeys = NUMKEYS(mp); if (nkeys > 1) { if (mp->mp_flags & P_LEAF2) { nodekey.mv_data = LEAF2KEY(mp, nkeys-1, nodekey.mv_size); } else { leaf = NODEPTR(mp, nkeys-1); MDB_GET_KEY2(leaf, nodekey); } rc = mc->mc_dbx->md_cmp(key, &nodekey); if (rc == 0) { /* last node was the one we wanted */ mc->mc_ki[mc->mc_top] = nkeys-1; if (exactp) *exactp = 1; goto set1; } if (rc < 0) { if (mc->mc_ki[mc->mc_top] < NUMKEYS(mp)) { /* This is definitely the right page, skip search_page */ if (mp->mp_flags & P_LEAF2) { nodekey.mv_data = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], nodekey.mv_size); } else { leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); MDB_GET_KEY2(leaf, nodekey); } rc = mc->mc_dbx->md_cmp(key, &nodekey); if (rc == 0) { /* current node was the one we wanted */ if (exactp) *exactp = 1; goto set1; } } rc = 0; mc->mc_flags &= ~C_EOF; goto set2; } } /* If any parents have right-sibs, search. * Otherwise, there's nothing further. */ for (i=0; imc_top; i++) if (mc->mc_ki[i] < NUMKEYS(mc->mc_pg[i])-1) break; if (i == mc->mc_top) { /* There are no other pages */ mc->mc_ki[mc->mc_top] = nkeys; return MDB_NOTFOUND; } } if (!mc->mc_top) { /* There are no other pages */ mc->mc_ki[mc->mc_top] = 0; if (op == MDB_SET_RANGE && !exactp) { rc = 0; goto set1; } else return MDB_NOTFOUND; } } else { mc->mc_pg[0] = 0; } rc = mdb_page_search(mc, key, 0); if (rc != MDB_SUCCESS) return rc; mp = mc->mc_pg[mc->mc_top]; mdb_cassert(mc, IS_LEAF(mp)); set2: leaf = mdb_node_search(mc, key, exactp); if (exactp != NULL && !*exactp) { /* MDB_SET specified and not an exact match. */ return MDB_NOTFOUND; } if (leaf == NULL) { DPUTS("===> inexact leaf not found, goto sibling"); if ((rc = mdb_cursor_sibling(mc, 1)) != MDB_SUCCESS) { mc->mc_flags |= C_EOF; return rc; /* no entries matched */ } mp = mc->mc_pg[mc->mc_top]; mdb_cassert(mc, IS_LEAF(mp)); leaf = NODEPTR(mp, 0); } set1: mc->mc_flags |= C_INITIALIZED; mc->mc_flags &= ~C_EOF; if (IS_LEAF2(mp)) { if (op == MDB_SET_RANGE || op == MDB_SET_KEY) { key->mv_size = mc->mc_db->md_pad; key->mv_data = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->mv_size); } return MDB_SUCCESS; } if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { mdb_xcursor_init1(mc, leaf); if (op == MDB_SET || op == MDB_SET_KEY || op == MDB_SET_RANGE) { rc = mdb_cursor_first(&mc->mc_xcursor->mx_cursor, data, NULL); } else { int ex2, *ex2p; if (op == MDB_GET_BOTH) { ex2p = &ex2; ex2 = 0; } else { ex2p = NULL; } rc = mdb_cursor_set(&mc->mc_xcursor->mx_cursor, data, NULL, MDB_SET_RANGE, ex2p); if (rc != MDB_SUCCESS) return rc; } } else if (data) { if (op == MDB_GET_BOTH || op == MDB_GET_BOTH_RANGE) { MDB_val olddata; MDB_cmp_func *dcmp; if ((rc = mdb_node_read(mc, leaf, &olddata)) != MDB_SUCCESS) return rc; dcmp = mc->mc_dbx->md_dcmp; #if UINT_MAX < SIZE_MAX if (dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t)) dcmp = mdb_cmp_clong; #endif rc = dcmp(data, &olddata); if (rc) { if (op == MDB_GET_BOTH || rc > 0) return MDB_NOTFOUND; rc = 0; } *data = olddata; } else { if (mc->mc_xcursor) mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); if ((rc = mdb_node_read(mc, leaf, data)) != MDB_SUCCESS) return rc; } } /* The key already matches in all other cases */ if (op == MDB_SET_RANGE || op == MDB_SET_KEY) MDB_GET_KEY(leaf, key); DPRINTF(("==> cursor placed on key [%s]", DKEY(key))); return rc; } /** Move the cursor to the first item in the database. */ static int mdb_cursor_first(MDB_cursor *mc, MDB_val *key, MDB_val *data) { int rc; MDB_node *leaf; if (mc->mc_xcursor) mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); if (!(mc->mc_flags & C_INITIALIZED) || mc->mc_top) { rc = mdb_page_search(mc, NULL, MDB_PS_FIRST); if (rc != MDB_SUCCESS) return rc; } mdb_cassert(mc, IS_LEAF(mc->mc_pg[mc->mc_top])); leaf = NODEPTR(mc->mc_pg[mc->mc_top], 0); mc->mc_flags |= C_INITIALIZED; mc->mc_flags &= ~C_EOF; mc->mc_ki[mc->mc_top] = 0; if (IS_LEAF2(mc->mc_pg[mc->mc_top])) { if ( key ) { key->mv_size = mc->mc_db->md_pad; key->mv_data = LEAF2KEY(mc->mc_pg[mc->mc_top], 0, key->mv_size); } return MDB_SUCCESS; } if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { mdb_xcursor_init1(mc, leaf); rc = mdb_cursor_first(&mc->mc_xcursor->mx_cursor, data, NULL); if (rc) return rc; } else if (data) { if ((rc = mdb_node_read(mc, leaf, data)) != MDB_SUCCESS) return rc; } MDB_GET_KEY(leaf, key); return MDB_SUCCESS; } /** Move the cursor to the last item in the database. */ static int mdb_cursor_last(MDB_cursor *mc, MDB_val *key, MDB_val *data) { int rc; MDB_node *leaf; if (mc->mc_xcursor) mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); if (!(mc->mc_flags & C_INITIALIZED) || mc->mc_top) { rc = mdb_page_search(mc, NULL, MDB_PS_LAST); if (rc != MDB_SUCCESS) return rc; } mdb_cassert(mc, IS_LEAF(mc->mc_pg[mc->mc_top])); mc->mc_ki[mc->mc_top] = NUMKEYS(mc->mc_pg[mc->mc_top]) - 1; mc->mc_flags |= C_INITIALIZED|C_EOF; leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); if (IS_LEAF2(mc->mc_pg[mc->mc_top])) { if (key) { key->mv_size = mc->mc_db->md_pad; key->mv_data = LEAF2KEY(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top], key->mv_size); } return MDB_SUCCESS; } if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { mdb_xcursor_init1(mc, leaf); rc = mdb_cursor_last(&mc->mc_xcursor->mx_cursor, data, NULL); if (rc) return rc; } else if (data) { if ((rc = mdb_node_read(mc, leaf, data)) != MDB_SUCCESS) return rc; } MDB_GET_KEY(leaf, key); return MDB_SUCCESS; } int mdb_cursor_get(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op) { int rc; int exact = 0; int (*mfunc)(MDB_cursor *mc, MDB_val *key, MDB_val *data); if (mc == NULL) return EINVAL; if (mc->mc_txn->mt_flags & MDB_TXN_BLOCKED) return MDB_BAD_TXN; switch (op) { case MDB_GET_CURRENT: if (!(mc->mc_flags & C_INITIALIZED)) { rc = EINVAL; } else { MDB_page *mp = mc->mc_pg[mc->mc_top]; int nkeys = NUMKEYS(mp); if (!nkeys || mc->mc_ki[mc->mc_top] >= nkeys) { mc->mc_ki[mc->mc_top] = nkeys; rc = MDB_NOTFOUND; break; } rc = MDB_SUCCESS; if (IS_LEAF2(mp)) { key->mv_size = mc->mc_db->md_pad; key->mv_data = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->mv_size); } else { MDB_node *leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); MDB_GET_KEY(leaf, key); if (data) { if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { rc = mdb_cursor_get(&mc->mc_xcursor->mx_cursor, data, NULL, MDB_GET_CURRENT); } else { rc = mdb_node_read(mc, leaf, data); } } } } break; case MDB_GET_BOTH: case MDB_GET_BOTH_RANGE: if (data == NULL) { rc = EINVAL; break; } if (mc->mc_xcursor == NULL) { rc = MDB_INCOMPATIBLE; break; } /* FALLTHRU */ case MDB_SET: case MDB_SET_KEY: case MDB_SET_RANGE: if (key == NULL) { rc = EINVAL; } else { rc = mdb_cursor_set(mc, key, data, op, op == MDB_SET_RANGE ? NULL : &exact); } break; case MDB_GET_MULTIPLE: if (data == NULL || !(mc->mc_flags & C_INITIALIZED)) { rc = EINVAL; break; } if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) { rc = MDB_INCOMPATIBLE; break; } rc = MDB_SUCCESS; if (!(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) || (mc->mc_xcursor->mx_cursor.mc_flags & C_EOF)) break; goto fetchm; case MDB_NEXT_MULTIPLE: if (data == NULL) { rc = EINVAL; break; } if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) { rc = MDB_INCOMPATIBLE; break; } rc = mdb_cursor_next(mc, key, data, MDB_NEXT_DUP); if (rc == MDB_SUCCESS) { if (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) { MDB_cursor *mx; fetchm: mx = &mc->mc_xcursor->mx_cursor; data->mv_size = NUMKEYS(mx->mc_pg[mx->mc_top]) * mx->mc_db->md_pad; data->mv_data = METADATA(mx->mc_pg[mx->mc_top]); mx->mc_ki[mx->mc_top] = NUMKEYS(mx->mc_pg[mx->mc_top])-1; } else { rc = MDB_NOTFOUND; } } break; case MDB_PREV_MULTIPLE: if (data == NULL) { rc = EINVAL; break; } if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) { rc = MDB_INCOMPATIBLE; break; } if (!(mc->mc_flags & C_INITIALIZED)) rc = mdb_cursor_last(mc, key, data); else rc = MDB_SUCCESS; if (rc == MDB_SUCCESS) { MDB_cursor *mx = &mc->mc_xcursor->mx_cursor; if (mx->mc_flags & C_INITIALIZED) { rc = mdb_cursor_sibling(mx, 0); if (rc == MDB_SUCCESS) goto fetchm; } else { rc = MDB_NOTFOUND; } } break; case MDB_NEXT: case MDB_NEXT_DUP: case MDB_NEXT_NODUP: rc = mdb_cursor_next(mc, key, data, op); break; case MDB_PREV: case MDB_PREV_DUP: case MDB_PREV_NODUP: rc = mdb_cursor_prev(mc, key, data, op); break; case MDB_FIRST: rc = mdb_cursor_first(mc, key, data); break; case MDB_FIRST_DUP: mfunc = mdb_cursor_first; mmove: if (data == NULL || !(mc->mc_flags & C_INITIALIZED)) { rc = EINVAL; break; } if (mc->mc_xcursor == NULL) { rc = MDB_INCOMPATIBLE; break; } if (mc->mc_ki[mc->mc_top] >= NUMKEYS(mc->mc_pg[mc->mc_top])) { mc->mc_ki[mc->mc_top] = NUMKEYS(mc->mc_pg[mc->mc_top]); rc = MDB_NOTFOUND; break; } { MDB_node *leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) { MDB_GET_KEY(leaf, key); rc = mdb_node_read(mc, leaf, data); break; } } if (!(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) { rc = EINVAL; break; } rc = mfunc(&mc->mc_xcursor->mx_cursor, data, NULL); break; case MDB_LAST: rc = mdb_cursor_last(mc, key, data); break; case MDB_LAST_DUP: mfunc = mdb_cursor_last; goto mmove; default: DPRINTF(("unhandled/unimplemented cursor operation %u", op)); rc = EINVAL; break; } if (mc->mc_flags & C_DEL) mc->mc_flags ^= C_DEL; return rc; } /** Touch all the pages in the cursor stack. Set mc_top. * Makes sure all the pages are writable, before attempting a write operation. * @param[in] mc The cursor to operate on. */ static int mdb_cursor_touch(MDB_cursor *mc) { int rc = MDB_SUCCESS; if (mc->mc_dbi >= CORE_DBS && !(*mc->mc_dbflag & (DB_DIRTY|DB_DUPDATA))) { /* Touch DB record of named DB */ MDB_cursor mc2; MDB_xcursor mcx; if (TXN_DBI_CHANGED(mc->mc_txn, mc->mc_dbi)) return MDB_BAD_DBI; mdb_cursor_init(&mc2, mc->mc_txn, MAIN_DBI, &mcx); rc = mdb_page_search(&mc2, &mc->mc_dbx->md_name, MDB_PS_MODIFY); if (rc) return rc; *mc->mc_dbflag |= DB_DIRTY; } mc->mc_top = 0; if (mc->mc_snum) { do { rc = mdb_page_touch(mc); } while (!rc && ++(mc->mc_top) < mc->mc_snum); mc->mc_top = mc->mc_snum-1; } return rc; } /** Do not spill pages to disk if txn is getting full, may fail instead */ #define MDB_NOSPILL 0x8000 int mdb_cursor_put(MDB_cursor *mc, MDB_val *key, MDB_val *data, unsigned int flags) { MDB_env *env; MDB_node *leaf = NULL; MDB_page *fp, *mp, *sub_root = NULL; uint16_t fp_flags; MDB_val xdata, *rdata, dkey, olddata; MDB_db dummy; int do_sub = 0, insert_key, insert_data; unsigned int mcount = 0, dcount = 0, nospill; size_t nsize; int rc, rc2; unsigned int nflags; DKBUF; if (mc == NULL || key == NULL) return EINVAL; env = mc->mc_txn->mt_env; /* Check this first so counter will always be zero on any * early failures. */ if (flags & MDB_MULTIPLE) { dcount = data[1].mv_size; data[1].mv_size = 0; if (!F_ISSET(mc->mc_db->md_flags, MDB_DUPFIXED)) return MDB_INCOMPATIBLE; } nospill = flags & MDB_NOSPILL; flags &= ~MDB_NOSPILL; if (mc->mc_txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED)) return (mc->mc_txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN; if (key->mv_size-1 >= ENV_MAXKEY(env)) return MDB_BAD_VALSIZE; #if SIZE_MAX > MAXDATASIZE if (data->mv_size > ((mc->mc_db->md_flags & MDB_DUPSORT) ? ENV_MAXKEY(env) : MAXDATASIZE)) return MDB_BAD_VALSIZE; #else if ((mc->mc_db->md_flags & MDB_DUPSORT) && data->mv_size > ENV_MAXKEY(env)) return MDB_BAD_VALSIZE; #endif DPRINTF(("==> put db %d key [%s], size %"Z"u, data size %"Z"u", DDBI(mc), DKEY(key), key ? key->mv_size : 0, data->mv_size)); dkey.mv_size = 0; if (flags & MDB_CURRENT) { if (!(mc->mc_flags & C_INITIALIZED)) return EINVAL; rc = MDB_SUCCESS; } else if (mc->mc_db->md_root == P_INVALID) { /* new database, cursor has nothing to point to */ mc->mc_snum = 0; mc->mc_top = 0; mc->mc_flags &= ~C_INITIALIZED; rc = MDB_NO_ROOT; } else { int exact = 0; MDB_val d2; if (flags & MDB_APPEND) { MDB_val k2; rc = mdb_cursor_last(mc, &k2, &d2); if (rc == 0) { rc = mc->mc_dbx->md_cmp(key, &k2); if (rc > 0) { rc = MDB_NOTFOUND; mc->mc_ki[mc->mc_top]++; } else { /* new key is <= last key */ rc = MDB_KEYEXIST; } } } else { rc = mdb_cursor_set(mc, key, &d2, MDB_SET, &exact); } if ((flags & MDB_NOOVERWRITE) && rc == 0) { DPRINTF(("duplicate key [%s]", DKEY(key))); *data = d2; return MDB_KEYEXIST; } if (rc && rc != MDB_NOTFOUND) return rc; } if (mc->mc_flags & C_DEL) mc->mc_flags ^= C_DEL; /* Cursor is positioned, check for room in the dirty list */ if (!nospill) { if (flags & MDB_MULTIPLE) { rdata = &xdata; xdata.mv_size = data->mv_size * dcount; } else { rdata = data; } if ((rc2 = mdb_page_spill(mc, key, rdata))) return rc2; } if (rc == MDB_NO_ROOT) { MDB_page *np; /* new database, write a root leaf page */ DPUTS("allocating new root leaf page"); if ((rc2 = mdb_page_new(mc, P_LEAF, 1, &np))) { return rc2; } mdb_cursor_push(mc, np); mc->mc_db->md_root = np->mp_pgno; mc->mc_db->md_depth++; *mc->mc_dbflag |= DB_DIRTY; if ((mc->mc_db->md_flags & (MDB_DUPSORT|MDB_DUPFIXED)) == MDB_DUPFIXED) np->mp_flags |= P_LEAF2; mc->mc_flags |= C_INITIALIZED; } else { /* make sure all cursor pages are writable */ rc2 = mdb_cursor_touch(mc); if (rc2) return rc2; } insert_key = insert_data = rc; if (insert_key) { /* The key does not exist */ DPRINTF(("inserting key at index %i", mc->mc_ki[mc->mc_top])); if ((mc->mc_db->md_flags & MDB_DUPSORT) && LEAFSIZE(key, data) > env->me_nodemax) { /* Too big for a node, insert in sub-DB. Set up an empty * "old sub-page" for prep_subDB to expand to a full page. */ fp_flags = P_LEAF|P_DIRTY; fp = env->me_pbuf; fp->mp_pad = data->mv_size; /* used if MDB_DUPFIXED */ fp->mp_lower = fp->mp_upper = (PAGEHDRSZ-PAGEBASE); olddata.mv_size = PAGEHDRSZ; goto prep_subDB; } } else { /* there's only a key anyway, so this is a no-op */ if (IS_LEAF2(mc->mc_pg[mc->mc_top])) { char *ptr; unsigned int ksize = mc->mc_db->md_pad; if (key->mv_size != ksize) return MDB_BAD_VALSIZE; ptr = LEAF2KEY(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top], ksize); memcpy(ptr, key->mv_data, ksize); fix_parent: /* if overwriting slot 0 of leaf, need to * update branch key if there is a parent page */ if (mc->mc_top && !mc->mc_ki[mc->mc_top]) { unsigned short dtop = 1; mc->mc_top--; /* slot 0 is always an empty key, find real slot */ while (mc->mc_top && !mc->mc_ki[mc->mc_top]) { mc->mc_top--; dtop++; } if (mc->mc_ki[mc->mc_top]) rc2 = mdb_update_key(mc, key); else rc2 = MDB_SUCCESS; mc->mc_top += dtop; if (rc2) return rc2; } return MDB_SUCCESS; } more: leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); olddata.mv_size = NODEDSZ(leaf); olddata.mv_data = NODEDATA(leaf); /* DB has dups? */ if (F_ISSET(mc->mc_db->md_flags, MDB_DUPSORT)) { /* Prepare (sub-)page/sub-DB to accept the new item, * if needed. fp: old sub-page or a header faking * it. mp: new (sub-)page. offset: growth in page * size. xdata: node data with new page or DB. */ unsigned i, offset = 0; mp = fp = xdata.mv_data = env->me_pbuf; mp->mp_pgno = mc->mc_pg[mc->mc_top]->mp_pgno; /* Was a single item before, must convert now */ if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) { MDB_cmp_func *dcmp; /* Just overwrite the current item */ if (flags == MDB_CURRENT) goto current; dcmp = mc->mc_dbx->md_dcmp; #if UINT_MAX < SIZE_MAX if (dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t)) dcmp = mdb_cmp_clong; #endif /* does data match? */ if (!dcmp(data, &olddata)) { if (flags & (MDB_NODUPDATA|MDB_APPENDDUP)) return MDB_KEYEXIST; /* overwrite it */ goto current; } /* Back up original data item */ dkey.mv_size = olddata.mv_size; dkey.mv_data = memcpy(fp+1, olddata.mv_data, olddata.mv_size); /* Make sub-page header for the dup items, with dummy body */ fp->mp_flags = P_LEAF|P_DIRTY|P_SUBP; fp->mp_lower = (PAGEHDRSZ-PAGEBASE); xdata.mv_size = PAGEHDRSZ + dkey.mv_size + data->mv_size; if (mc->mc_db->md_flags & MDB_DUPFIXED) { fp->mp_flags |= P_LEAF2; fp->mp_pad = data->mv_size; xdata.mv_size += 2 * data->mv_size; /* leave space for 2 more */ } else { xdata.mv_size += 2 * (sizeof(indx_t) + NODESIZE) + (dkey.mv_size & 1) + (data->mv_size & 1); } fp->mp_upper = xdata.mv_size - PAGEBASE; olddata.mv_size = xdata.mv_size; /* pretend olddata is fp */ } else if (leaf->mn_flags & F_SUBDATA) { /* Data is on sub-DB, just store it */ flags |= F_DUPDATA|F_SUBDATA; goto put_sub; } else { /* Data is on sub-page */ fp = olddata.mv_data; switch (flags) { default: if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) { offset = EVEN(NODESIZE + sizeof(indx_t) + data->mv_size); break; } offset = fp->mp_pad; if (SIZELEFT(fp) < offset) { offset *= 4; /* space for 4 more */ break; } /* FALLTHRU */ /* Big enough MDB_DUPFIXED sub-page */ case MDB_CURRENT: fp->mp_flags |= P_DIRTY; COPY_PGNO(fp->mp_pgno, mp->mp_pgno); mc->mc_xcursor->mx_cursor.mc_pg[0] = fp; flags |= F_DUPDATA; goto put_sub; } xdata.mv_size = olddata.mv_size + offset; } fp_flags = fp->mp_flags; if (NODESIZE + NODEKSZ(leaf) + xdata.mv_size > env->me_nodemax) { /* Too big for a sub-page, convert to sub-DB */ fp_flags &= ~P_SUBP; prep_subDB: if (mc->mc_db->md_flags & MDB_DUPFIXED) { fp_flags |= P_LEAF2; dummy.md_pad = fp->mp_pad; dummy.md_flags = MDB_DUPFIXED; if (mc->mc_db->md_flags & MDB_INTEGERDUP) dummy.md_flags |= MDB_INTEGERKEY; } else { dummy.md_pad = 0; dummy.md_flags = 0; } dummy.md_depth = 1; dummy.md_branch_pages = 0; dummy.md_leaf_pages = 1; dummy.md_overflow_pages = 0; dummy.md_entries = NUMKEYS(fp); xdata.mv_size = sizeof(MDB_db); xdata.mv_data = &dummy; if ((rc = mdb_page_alloc(mc, 1, &mp))) return rc; offset = env->me_psize - olddata.mv_size; flags |= F_DUPDATA|F_SUBDATA; dummy.md_root = mp->mp_pgno; sub_root = mp; } if (mp != fp) { mp->mp_flags = fp_flags | P_DIRTY; mp->mp_pad = fp->mp_pad; mp->mp_lower = fp->mp_lower; mp->mp_upper = fp->mp_upper + offset; if (fp_flags & P_LEAF2) { memcpy(METADATA(mp), METADATA(fp), NUMKEYS(fp) * fp->mp_pad); } else { memcpy((char *)mp + mp->mp_upper + PAGEBASE, (char *)fp + fp->mp_upper + PAGEBASE, olddata.mv_size - fp->mp_upper - PAGEBASE); memcpy((char *)(&mp->mp_ptrs), (char *)(&fp->mp_ptrs), NUMKEYS(fp) * sizeof(mp->mp_ptrs[0])); for (i=0; imp_ptrs[i] += offset; } } rdata = &xdata; flags |= F_DUPDATA; do_sub = 1; if (!insert_key) mdb_node_del(mc, 0); goto new_sub; } current: /* LMDB passes F_SUBDATA in 'flags' to write a DB record */ if ((leaf->mn_flags ^ flags) & F_SUBDATA) return MDB_INCOMPATIBLE; /* overflow page overwrites need special handling */ if (F_ISSET(leaf->mn_flags, F_BIGDATA)) { MDB_page *omp; pgno_t pg; int level, ovpages, dpages = OVPAGES(data->mv_size, env->me_psize); memcpy(&pg, olddata.mv_data, sizeof(pg)); if ((rc2 = mdb_page_get(mc, pg, &omp, &level)) != 0) return rc2; ovpages = omp->mp_pages; /* Is the ov page large enough? */ if (ovpages >= dpages) { if (!(omp->mp_flags & P_DIRTY) && (level || (env->me_flags & MDB_WRITEMAP))) { rc = mdb_page_unspill(mc->mc_txn, omp, &omp); if (rc) return rc; level = 0; /* dirty in this txn or clean */ } /* Is it dirty? */ if (omp->mp_flags & P_DIRTY) { /* yes, overwrite it. Note in this case we don't * bother to try shrinking the page if the new data * is smaller than the overflow threshold. */ if (level > 1) { /* It is writable only in a parent txn */ size_t sz = (size_t) env->me_psize * ovpages, off; MDB_page *np = mdb_page_malloc(mc->mc_txn, ovpages); MDB_ID2 id2; if (!np) return ENOMEM; id2.mid = pg; id2.mptr = np; /* Note - this page is already counted in parent's dirty_room */ rc2 = mdb_mid2l_insert(mc->mc_txn->mt_u.dirty_list, &id2); mdb_cassert(mc, rc2 == 0); /* Currently we make the page look as with put() in the * parent txn, in case the user peeks at MDB_RESERVEd * or unused parts. Some users treat ovpages specially. */ if (!(flags & MDB_RESERVE)) { /* Skip the part where LMDB will put *data. * Copy end of page, adjusting alignment so * compiler may copy words instead of bytes. */ off = (PAGEHDRSZ + data->mv_size) & -sizeof(size_t); memcpy((size_t *)((char *)np + off), (size_t *)((char *)omp + off), sz - off); sz = PAGEHDRSZ; } memcpy(np, omp, sz); /* Copy beginning of page */ omp = np; } SETDSZ(leaf, data->mv_size); if (F_ISSET(flags, MDB_RESERVE)) data->mv_data = METADATA(omp); else memcpy(METADATA(omp), data->mv_data, data->mv_size); return MDB_SUCCESS; } } if ((rc2 = mdb_ovpage_free(mc, omp)) != MDB_SUCCESS) return rc2; } else if (data->mv_size == olddata.mv_size) { /* same size, just replace it. Note that we could * also reuse this node if the new data is smaller, * but instead we opt to shrink the node in that case. */ if (F_ISSET(flags, MDB_RESERVE)) data->mv_data = olddata.mv_data; else if (!(mc->mc_flags & C_SUB)) memcpy(olddata.mv_data, data->mv_data, data->mv_size); else { memcpy(NODEKEY(leaf), key->mv_data, key->mv_size); goto fix_parent; } return MDB_SUCCESS; } mdb_node_del(mc, 0); } rdata = data; new_sub: nflags = flags & NODE_ADD_FLAGS; nsize = IS_LEAF2(mc->mc_pg[mc->mc_top]) ? key->mv_size : mdb_leaf_size(env, key, rdata); if (SIZELEFT(mc->mc_pg[mc->mc_top]) < nsize) { if (( flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA ) nflags &= ~MDB_APPEND; /* sub-page may need room to grow */ if (!insert_key) nflags |= MDB_SPLIT_REPLACE; rc = mdb_page_split(mc, key, rdata, P_INVALID, nflags); } else { /* There is room already in this leaf page. */ rc = mdb_node_add(mc, mc->mc_ki[mc->mc_top], key, rdata, 0, nflags); if (rc == 0) { /* Adjust other cursors pointing to mp */ MDB_cursor *m2, *m3; MDB_dbi dbi = mc->mc_dbi; unsigned i = mc->mc_top; MDB_page *mp = mc->mc_pg[i]; for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { if (mc->mc_flags & C_SUB) m3 = &m2->mc_xcursor->mx_cursor; else m3 = m2; if (m3 == mc || m3->mc_snum < mc->mc_snum || m3->mc_pg[i] != mp) continue; if (m3->mc_ki[i] >= mc->mc_ki[i] && insert_key) { m3->mc_ki[i]++; } XCURSOR_REFRESH(m3, i, mp); } } } if (rc == MDB_SUCCESS) { /* Now store the actual data in the child DB. Note that we're * storing the user data in the keys field, so there are strict * size limits on dupdata. The actual data fields of the child * DB are all zero size. */ if (do_sub) { int xflags, new_dupdata; size_t ecount; put_sub: xdata.mv_size = 0; xdata.mv_data = ""; leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); if ((flags & (MDB_CURRENT|MDB_APPENDDUP)) == MDB_CURRENT) { xflags = MDB_CURRENT|MDB_NOSPILL; } else { mdb_xcursor_init1(mc, leaf); xflags = (flags & MDB_NODUPDATA) ? MDB_NOOVERWRITE|MDB_NOSPILL : MDB_NOSPILL; } if (sub_root) mc->mc_xcursor->mx_cursor.mc_pg[0] = sub_root; new_dupdata = (int)dkey.mv_size; /* converted, write the original data first */ if (dkey.mv_size) { rc = mdb_cursor_put(&mc->mc_xcursor->mx_cursor, &dkey, &xdata, xflags); if (rc) goto bad_sub; /* we've done our job */ dkey.mv_size = 0; } if (!(leaf->mn_flags & F_SUBDATA) || sub_root) { /* Adjust other cursors pointing to mp */ MDB_cursor *m2; MDB_xcursor *mx = mc->mc_xcursor; unsigned i = mc->mc_top; MDB_page *mp = mc->mc_pg[i]; for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2=m2->mc_next) { if (m2 == mc || m2->mc_snum < mc->mc_snum) continue; if (!(m2->mc_flags & C_INITIALIZED)) continue; if (m2->mc_pg[i] == mp) { if (m2->mc_ki[i] == mc->mc_ki[i]) { mdb_xcursor_init2(m2, mx, new_dupdata); } else if (!insert_key) { XCURSOR_REFRESH(m2, i, mp); } } } } ecount = mc->mc_xcursor->mx_db.md_entries; if (flags & MDB_APPENDDUP) xflags |= MDB_APPEND; rc = mdb_cursor_put(&mc->mc_xcursor->mx_cursor, data, &xdata, xflags); if (flags & F_SUBDATA) { void *db = NODEDATA(leaf); memcpy(db, &mc->mc_xcursor->mx_db, sizeof(MDB_db)); } insert_data = mc->mc_xcursor->mx_db.md_entries - ecount; } /* Increment count unless we just replaced an existing item. */ if (insert_data) mc->mc_db->md_entries++; if (insert_key) { /* Invalidate txn if we created an empty sub-DB */ if (rc) goto bad_sub; /* If we succeeded and the key didn't exist before, * make sure the cursor is marked valid. */ mc->mc_flags |= C_INITIALIZED; } if (flags & MDB_MULTIPLE) { if (!rc) { mcount++; /* let caller know how many succeeded, if any */ data[1].mv_size = mcount; if (mcount < dcount) { data[0].mv_data = (char *)data[0].mv_data + data[0].mv_size; insert_key = insert_data = 0; goto more; } } } return rc; bad_sub: if (rc == MDB_KEYEXIST) /* should not happen, we deleted that item */ rc = MDB_CORRUPTED; } mc->mc_txn->mt_flags |= MDB_TXN_ERROR; return rc; } int mdb_cursor_del(MDB_cursor *mc, unsigned int flags) { MDB_node *leaf; MDB_page *mp; int rc; if (mc->mc_txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED)) return (mc->mc_txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN; if (!(mc->mc_flags & C_INITIALIZED)) return EINVAL; if (mc->mc_ki[mc->mc_top] >= NUMKEYS(mc->mc_pg[mc->mc_top])) return MDB_NOTFOUND; if (!(flags & MDB_NOSPILL) && (rc = mdb_page_spill(mc, NULL, NULL))) return rc; rc = mdb_cursor_touch(mc); if (rc) return rc; mp = mc->mc_pg[mc->mc_top]; if (!IS_LEAF(mp)) return MDB_CORRUPTED; if (IS_LEAF2(mp)) goto del_key; leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { if (flags & MDB_NODUPDATA) { /* mdb_cursor_del0() will subtract the final entry */ mc->mc_db->md_entries -= mc->mc_xcursor->mx_db.md_entries - 1; mc->mc_xcursor->mx_cursor.mc_flags &= ~C_INITIALIZED; } else { if (!F_ISSET(leaf->mn_flags, F_SUBDATA)) { mc->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(leaf); } rc = mdb_cursor_del(&mc->mc_xcursor->mx_cursor, MDB_NOSPILL); if (rc) return rc; /* If sub-DB still has entries, we're done */ if (mc->mc_xcursor->mx_db.md_entries) { if (leaf->mn_flags & F_SUBDATA) { /* update subDB info */ void *db = NODEDATA(leaf); memcpy(db, &mc->mc_xcursor->mx_db, sizeof(MDB_db)); } else { MDB_cursor *m2; /* shrink fake page */ mdb_node_shrink(mp, mc->mc_ki[mc->mc_top]); leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); mc->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(leaf); /* fix other sub-DB cursors pointed at fake pages on this page */ for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2=m2->mc_next) { if (m2 == mc || m2->mc_snum < mc->mc_snum) continue; if (!(m2->mc_flags & C_INITIALIZED)) continue; if (m2->mc_pg[mc->mc_top] == mp) { XCURSOR_REFRESH(m2, mc->mc_top, mp); } } } mc->mc_db->md_entries--; return rc; } else { mc->mc_xcursor->mx_cursor.mc_flags &= ~C_INITIALIZED; } /* otherwise fall thru and delete the sub-DB */ } if (leaf->mn_flags & F_SUBDATA) { /* add all the child DB's pages to the free list */ rc = mdb_drop0(&mc->mc_xcursor->mx_cursor, 0); if (rc) goto fail; } } /* LMDB passes F_SUBDATA in 'flags' to delete a DB record */ else if ((leaf->mn_flags ^ flags) & F_SUBDATA) { rc = MDB_INCOMPATIBLE; goto fail; } /* add overflow pages to free list */ if (F_ISSET(leaf->mn_flags, F_BIGDATA)) { MDB_page *omp; pgno_t pg; memcpy(&pg, NODEDATA(leaf), sizeof(pg)); if ((rc = mdb_page_get(mc, pg, &omp, NULL)) || (rc = mdb_ovpage_free(mc, omp))) goto fail; } del_key: return mdb_cursor_del0(mc); fail: mc->mc_txn->mt_flags |= MDB_TXN_ERROR; return rc; } /** Allocate and initialize new pages for a database. * Set #MDB_TXN_ERROR on failure. * @param[in] mc a cursor on the database being added to. * @param[in] flags flags defining what type of page is being allocated. * @param[in] num the number of pages to allocate. This is usually 1, * unless allocating overflow pages for a large record. * @param[out] mp Address of a page, or NULL on failure. * @return 0 on success, non-zero on failure. */ static int mdb_page_new(MDB_cursor *mc, uint32_t flags, int num, MDB_page **mp) { MDB_page *np; int rc; if ((rc = mdb_page_alloc(mc, num, &np))) return rc; DPRINTF(("allocated new mpage %"Z"u, page size %u", np->mp_pgno, mc->mc_txn->mt_env->me_psize)); np->mp_flags = flags | P_DIRTY; np->mp_lower = (PAGEHDRSZ-PAGEBASE); np->mp_upper = mc->mc_txn->mt_env->me_psize - PAGEBASE; if (IS_BRANCH(np)) mc->mc_db->md_branch_pages++; else if (IS_LEAF(np)) mc->mc_db->md_leaf_pages++; else if (IS_OVERFLOW(np)) { mc->mc_db->md_overflow_pages += num; np->mp_pages = num; } *mp = np; return 0; } /** Calculate the size of a leaf node. * The size depends on the environment's page size; if a data item * is too large it will be put onto an overflow page and the node * size will only include the key and not the data. Sizes are always * rounded up to an even number of bytes, to guarantee 2-byte alignment * of the #MDB_node headers. * @param[in] env The environment handle. * @param[in] key The key for the node. * @param[in] data The data for the node. * @return The number of bytes needed to store the node. */ static size_t mdb_leaf_size(MDB_env *env, MDB_val *key, MDB_val *data) { size_t sz; sz = LEAFSIZE(key, data); if (sz > env->me_nodemax) { /* put on overflow page */ sz -= data->mv_size - sizeof(pgno_t); } return EVEN(sz + sizeof(indx_t)); } /** Calculate the size of a branch node. * The size should depend on the environment's page size but since * we currently don't support spilling large keys onto overflow * pages, it's simply the size of the #MDB_node header plus the * size of the key. Sizes are always rounded up to an even number * of bytes, to guarantee 2-byte alignment of the #MDB_node headers. * @param[in] env The environment handle. * @param[in] key The key for the node. * @return The number of bytes needed to store the node. */ static size_t mdb_branch_size(MDB_env *env, MDB_val *key) { size_t sz; sz = INDXSIZE(key); if (sz > env->me_nodemax) { /* put on overflow page */ /* not implemented */ /* sz -= key->size - sizeof(pgno_t); */ } return sz + sizeof(indx_t); } /** Add a node to the page pointed to by the cursor. * Set #MDB_TXN_ERROR on failure. * @param[in] mc The cursor for this operation. * @param[in] indx The index on the page where the new node should be added. * @param[in] key The key for the new node. * @param[in] data The data for the new node, if any. * @param[in] pgno The page number, if adding a branch node. * @param[in] flags Flags for the node. * @return 0 on success, non-zero on failure. Possible errors are: *
    *
  • ENOMEM - failed to allocate overflow pages for the node. *
  • MDB_PAGE_FULL - there is insufficient room in the page. This error * should never happen since all callers already calculate the * page's free space before calling this function. *
*/ static int mdb_node_add(MDB_cursor *mc, indx_t indx, MDB_val *key, MDB_val *data, pgno_t pgno, unsigned int flags) { unsigned int i; size_t node_size = NODESIZE; ssize_t room; indx_t ofs; MDB_node *node; MDB_page *mp = mc->mc_pg[mc->mc_top]; MDB_page *ofp = NULL; /* overflow page */ void *ndata; DKBUF; mdb_cassert(mc, mp->mp_upper >= mp->mp_lower); DPRINTF(("add to %s %spage %"Z"u index %i, data size %"Z"u key size %"Z"u [%s]", IS_LEAF(mp) ? "leaf" : "branch", IS_SUBP(mp) ? "sub-" : "", mdb_dbg_pgno(mp), indx, data ? data->mv_size : 0, key ? key->mv_size : 0, key ? DKEY(key) : "null")); if (IS_LEAF2(mp)) { /* Move higher keys up one slot. */ int ksize = mc->mc_db->md_pad, dif; char *ptr = LEAF2KEY(mp, indx, ksize); dif = NUMKEYS(mp) - indx; if (dif > 0) memmove(ptr+ksize, ptr, dif*ksize); /* insert new key */ memcpy(ptr, key->mv_data, ksize); /* Just using these for counting */ mp->mp_lower += sizeof(indx_t); mp->mp_upper -= ksize - sizeof(indx_t); return MDB_SUCCESS; } room = (ssize_t)SIZELEFT(mp) - (ssize_t)sizeof(indx_t); if (key != NULL) node_size += key->mv_size; if (IS_LEAF(mp)) { mdb_cassert(mc, key && data); if (F_ISSET(flags, F_BIGDATA)) { /* Data already on overflow page. */ node_size += sizeof(pgno_t); } else if (node_size + data->mv_size > mc->mc_txn->mt_env->me_nodemax) { int ovpages = OVPAGES(data->mv_size, mc->mc_txn->mt_env->me_psize); int rc; /* Put data on overflow page. */ DPRINTF(("data size is %"Z"u, node would be %"Z"u, put data on overflow page", data->mv_size, node_size+data->mv_size)); node_size = EVEN(node_size + sizeof(pgno_t)); if ((ssize_t)node_size > room) goto full; if ((rc = mdb_page_new(mc, P_OVERFLOW, ovpages, &ofp))) return rc; DPRINTF(("allocated overflow page %"Z"u", ofp->mp_pgno)); flags |= F_BIGDATA; goto update; } else { node_size += data->mv_size; } } node_size = EVEN(node_size); if ((ssize_t)node_size > room) goto full; update: /* Move higher pointers up one slot. */ for (i = NUMKEYS(mp); i > indx; i--) mp->mp_ptrs[i] = mp->mp_ptrs[i - 1]; /* Adjust free space offsets. */ ofs = mp->mp_upper - node_size; mdb_cassert(mc, ofs >= mp->mp_lower + sizeof(indx_t)); mp->mp_ptrs[indx] = ofs; mp->mp_upper = ofs; mp->mp_lower += sizeof(indx_t); /* Write the node data. */ node = NODEPTR(mp, indx); node->mn_ksize = (key == NULL) ? 0 : key->mv_size; node->mn_flags = flags; if (IS_LEAF(mp)) SETDSZ(node,data->mv_size); else SETPGNO(node,pgno); if (key) memcpy(NODEKEY(node), key->mv_data, key->mv_size); if (IS_LEAF(mp)) { ndata = NODEDATA(node); if (ofp == NULL) { if (F_ISSET(flags, F_BIGDATA)) memcpy(ndata, data->mv_data, sizeof(pgno_t)); else if (F_ISSET(flags, MDB_RESERVE)) data->mv_data = ndata; else memcpy(ndata, data->mv_data, data->mv_size); } else { memcpy(ndata, &ofp->mp_pgno, sizeof(pgno_t)); ndata = METADATA(ofp); if (F_ISSET(flags, MDB_RESERVE)) data->mv_data = ndata; else memcpy(ndata, data->mv_data, data->mv_size); } } return MDB_SUCCESS; full: DPRINTF(("not enough room in page %"Z"u, got %u ptrs", mdb_dbg_pgno(mp), NUMKEYS(mp))); DPRINTF(("upper-lower = %u - %u = %"Z"d", mp->mp_upper,mp->mp_lower,room)); DPRINTF(("node size = %"Z"u", node_size)); mc->mc_txn->mt_flags |= MDB_TXN_ERROR; return MDB_PAGE_FULL; } /** Delete the specified node from a page. * @param[in] mc Cursor pointing to the node to delete. * @param[in] ksize The size of a node. Only used if the page is * part of a #MDB_DUPFIXED database. */ static void mdb_node_del(MDB_cursor *mc, int ksize) { MDB_page *mp = mc->mc_pg[mc->mc_top]; indx_t indx = mc->mc_ki[mc->mc_top]; unsigned int sz; indx_t i, j, numkeys, ptr; MDB_node *node; char *base; DPRINTF(("delete node %u on %s page %"Z"u", indx, IS_LEAF(mp) ? "leaf" : "branch", mdb_dbg_pgno(mp))); numkeys = NUMKEYS(mp); mdb_cassert(mc, indx < numkeys); if (IS_LEAF2(mp)) { int x = numkeys - 1 - indx; base = LEAF2KEY(mp, indx, ksize); if (x) memmove(base, base + ksize, x * ksize); mp->mp_lower -= sizeof(indx_t); mp->mp_upper += ksize - sizeof(indx_t); return; } node = NODEPTR(mp, indx); sz = NODESIZE + node->mn_ksize; if (IS_LEAF(mp)) { if (F_ISSET(node->mn_flags, F_BIGDATA)) sz += sizeof(pgno_t); else sz += NODEDSZ(node); } sz = EVEN(sz); ptr = mp->mp_ptrs[indx]; for (i = j = 0; i < numkeys; i++) { if (i != indx) { mp->mp_ptrs[j] = mp->mp_ptrs[i]; if (mp->mp_ptrs[i] < ptr) mp->mp_ptrs[j] += sz; j++; } } base = (char *)mp + mp->mp_upper + PAGEBASE; memmove(base + sz, base, ptr - mp->mp_upper); mp->mp_lower -= sizeof(indx_t); mp->mp_upper += sz; } /** Compact the main page after deleting a node on a subpage. * @param[in] mp The main page to operate on. * @param[in] indx The index of the subpage on the main page. */ static void mdb_node_shrink(MDB_page *mp, indx_t indx) { MDB_node *node; MDB_page *sp, *xp; char *base; indx_t delta, nsize, len, ptr; int i; node = NODEPTR(mp, indx); sp = (MDB_page *)NODEDATA(node); delta = SIZELEFT(sp); nsize = NODEDSZ(node) - delta; /* Prepare to shift upward, set len = length(subpage part to shift) */ if (IS_LEAF2(sp)) { len = nsize; if (nsize & 1) return; /* do not make the node uneven-sized */ } else { xp = (MDB_page *)((char *)sp + delta); /* destination subpage */ for (i = NUMKEYS(sp); --i >= 0; ) xp->mp_ptrs[i] = sp->mp_ptrs[i] - delta; len = PAGEHDRSZ; } sp->mp_upper = sp->mp_lower; COPY_PGNO(sp->mp_pgno, mp->mp_pgno); SETDSZ(node, nsize); /* Shift upward */ base = (char *)mp + mp->mp_upper + PAGEBASE; memmove(base + delta, base, (char *)sp + len - base); ptr = mp->mp_ptrs[indx]; for (i = NUMKEYS(mp); --i >= 0; ) { if (mp->mp_ptrs[i] <= ptr) mp->mp_ptrs[i] += delta; } mp->mp_upper += delta; } /** Initial setup of a sorted-dups cursor. * Sorted duplicates are implemented as a sub-database for the given key. * The duplicate data items are actually keys of the sub-database. * Operations on the duplicate data items are performed using a sub-cursor * initialized when the sub-database is first accessed. This function does * the preliminary setup of the sub-cursor, filling in the fields that * depend only on the parent DB. * @param[in] mc The main cursor whose sorted-dups cursor is to be initialized. */ static void mdb_xcursor_init0(MDB_cursor *mc) { MDB_xcursor *mx = mc->mc_xcursor; mx->mx_cursor.mc_xcursor = NULL; mx->mx_cursor.mc_txn = mc->mc_txn; mx->mx_cursor.mc_db = &mx->mx_db; mx->mx_cursor.mc_dbx = &mx->mx_dbx; mx->mx_cursor.mc_dbi = mc->mc_dbi; mx->mx_cursor.mc_dbflag = &mx->mx_dbflag; mx->mx_cursor.mc_snum = 0; mx->mx_cursor.mc_top = 0; mx->mx_cursor.mc_flags = C_SUB; mx->mx_dbx.md_name.mv_size = 0; mx->mx_dbx.md_name.mv_data = NULL; mx->mx_dbx.md_cmp = mc->mc_dbx->md_dcmp; mx->mx_dbx.md_dcmp = NULL; mx->mx_dbx.md_rel = mc->mc_dbx->md_rel; } /** Final setup of a sorted-dups cursor. * Sets up the fields that depend on the data from the main cursor. * @param[in] mc The main cursor whose sorted-dups cursor is to be initialized. * @param[in] node The data containing the #MDB_db record for the * sorted-dup database. */ static void mdb_xcursor_init1(MDB_cursor *mc, MDB_node *node) { MDB_xcursor *mx = mc->mc_xcursor; if (node->mn_flags & F_SUBDATA) { memcpy(&mx->mx_db, NODEDATA(node), sizeof(MDB_db)); mx->mx_cursor.mc_pg[0] = 0; mx->mx_cursor.mc_snum = 0; mx->mx_cursor.mc_top = 0; mx->mx_cursor.mc_flags = C_SUB; } else { MDB_page *fp = NODEDATA(node); mx->mx_db.md_pad = 0; mx->mx_db.md_flags = 0; mx->mx_db.md_depth = 1; mx->mx_db.md_branch_pages = 0; mx->mx_db.md_leaf_pages = 1; mx->mx_db.md_overflow_pages = 0; mx->mx_db.md_entries = NUMKEYS(fp); COPY_PGNO(mx->mx_db.md_root, fp->mp_pgno); mx->mx_cursor.mc_snum = 1; mx->mx_cursor.mc_top = 0; mx->mx_cursor.mc_flags = C_INITIALIZED|C_SUB; mx->mx_cursor.mc_pg[0] = fp; mx->mx_cursor.mc_ki[0] = 0; if (mc->mc_db->md_flags & MDB_DUPFIXED) { mx->mx_db.md_flags = MDB_DUPFIXED; mx->mx_db.md_pad = fp->mp_pad; if (mc->mc_db->md_flags & MDB_INTEGERDUP) mx->mx_db.md_flags |= MDB_INTEGERKEY; } } DPRINTF(("Sub-db -%u root page %"Z"u", mx->mx_cursor.mc_dbi, mx->mx_db.md_root)); mx->mx_dbflag = DB_VALID|DB_USRVALID|DB_DUPDATA; #if UINT_MAX < SIZE_MAX if (mx->mx_dbx.md_cmp == mdb_cmp_int && mx->mx_db.md_pad == sizeof(size_t)) mx->mx_dbx.md_cmp = mdb_cmp_clong; #endif } /** Fixup a sorted-dups cursor due to underlying update. * Sets up some fields that depend on the data from the main cursor. * Almost the same as init1, but skips initialization steps if the * xcursor had already been used. * @param[in] mc The main cursor whose sorted-dups cursor is to be fixed up. * @param[in] src_mx The xcursor of an up-to-date cursor. * @param[in] new_dupdata True if converting from a non-#F_DUPDATA item. */ static void mdb_xcursor_init2(MDB_cursor *mc, MDB_xcursor *src_mx, int new_dupdata) { MDB_xcursor *mx = mc->mc_xcursor; if (new_dupdata) { mx->mx_cursor.mc_snum = 1; mx->mx_cursor.mc_top = 0; mx->mx_cursor.mc_flags |= C_INITIALIZED; mx->mx_cursor.mc_ki[0] = 0; mx->mx_dbflag = DB_VALID|DB_USRVALID|DB_DUPDATA; #if UINT_MAX < SIZE_MAX mx->mx_dbx.md_cmp = src_mx->mx_dbx.md_cmp; #endif } else if (!(mx->mx_cursor.mc_flags & C_INITIALIZED)) { return; } mx->mx_db = src_mx->mx_db; mx->mx_cursor.mc_pg[0] = src_mx->mx_cursor.mc_pg[0]; DPRINTF(("Sub-db -%u root page %"Z"u", mx->mx_cursor.mc_dbi, mx->mx_db.md_root)); } /** Initialize a cursor for a given transaction and database. */ static void mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx) { mc->mc_next = NULL; mc->mc_backup = NULL; mc->mc_dbi = dbi; mc->mc_txn = txn; mc->mc_db = &txn->mt_dbs[dbi]; mc->mc_dbx = &txn->mt_dbxs[dbi]; mc->mc_dbflag = &txn->mt_dbflags[dbi]; mc->mc_snum = 0; mc->mc_top = 0; mc->mc_pg[0] = 0; mc->mc_ki[0] = 0; mc->mc_flags = 0; if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) { mdb_tassert(txn, mx != NULL); mc->mc_xcursor = mx; mdb_xcursor_init0(mc); } else { mc->mc_xcursor = NULL; } if (*mc->mc_dbflag & DB_STALE) { mdb_page_search(mc, NULL, MDB_PS_ROOTONLY); } } int mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **ret) { MDB_cursor *mc; size_t size = sizeof(MDB_cursor); if (!ret || !TXN_DBI_EXIST(txn, dbi, DB_VALID)) return EINVAL; if (txn->mt_flags & MDB_TXN_BLOCKED) return MDB_BAD_TXN; if (dbi == FREE_DBI && !F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) return EINVAL; if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) size += sizeof(MDB_xcursor); if ((mc = malloc(size)) != NULL) { mdb_cursor_init(mc, txn, dbi, (MDB_xcursor *)(mc + 1)); if (txn->mt_cursors) { mc->mc_next = txn->mt_cursors[dbi]; txn->mt_cursors[dbi] = mc; mc->mc_flags |= C_UNTRACK; } } else { return ENOMEM; } *ret = mc; return MDB_SUCCESS; } int mdb_cursor_renew(MDB_txn *txn, MDB_cursor *mc) { if (!mc || !TXN_DBI_EXIST(txn, mc->mc_dbi, DB_VALID)) return EINVAL; if ((mc->mc_flags & C_UNTRACK) || txn->mt_cursors) return EINVAL; if (txn->mt_flags & MDB_TXN_BLOCKED) return MDB_BAD_TXN; mdb_cursor_init(mc, txn, mc->mc_dbi, mc->mc_xcursor); return MDB_SUCCESS; } /* Return the count of duplicate data items for the current key */ int mdb_cursor_count(MDB_cursor *mc, size_t *countp) { MDB_node *leaf; if (mc == NULL || countp == NULL) return EINVAL; if (mc->mc_xcursor == NULL) return MDB_INCOMPATIBLE; if (mc->mc_txn->mt_flags & MDB_TXN_BLOCKED) return MDB_BAD_TXN; if (!(mc->mc_flags & C_INITIALIZED)) return EINVAL; if (!mc->mc_snum) return MDB_NOTFOUND; if (mc->mc_flags & C_EOF) { if (mc->mc_ki[mc->mc_top] >= NUMKEYS(mc->mc_pg[mc->mc_top])) return MDB_NOTFOUND; mc->mc_flags ^= C_EOF; } leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) { *countp = 1; } else { if (!(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) return EINVAL; *countp = mc->mc_xcursor->mx_db.md_entries; } return MDB_SUCCESS; } void mdb_cursor_close(MDB_cursor *mc) { if (mc && !mc->mc_backup) { /* remove from txn, if tracked */ if ((mc->mc_flags & C_UNTRACK) && mc->mc_txn->mt_cursors) { MDB_cursor **prev = &mc->mc_txn->mt_cursors[mc->mc_dbi]; while (*prev && *prev != mc) prev = &(*prev)->mc_next; if (*prev == mc) *prev = mc->mc_next; } free(mc); } } MDB_txn * mdb_cursor_txn(MDB_cursor *mc) { if (!mc) return NULL; return mc->mc_txn; } MDB_dbi mdb_cursor_dbi(MDB_cursor *mc) { return mc->mc_dbi; } /** Replace the key for a branch node with a new key. * Set #MDB_TXN_ERROR on failure. * @param[in] mc Cursor pointing to the node to operate on. * @param[in] key The new key to use. * @return 0 on success, non-zero on failure. */ static int mdb_update_key(MDB_cursor *mc, MDB_val *key) { MDB_page *mp; MDB_node *node; char *base; size_t len; int delta, ksize, oksize; indx_t ptr, i, numkeys, indx; DKBUF; indx = mc->mc_ki[mc->mc_top]; mp = mc->mc_pg[mc->mc_top]; node = NODEPTR(mp, indx); ptr = mp->mp_ptrs[indx]; #if MDB_DEBUG { MDB_val k2; char kbuf2[DKBUF_MAXKEYSIZE*2+1]; k2.mv_data = NODEKEY(node); k2.mv_size = node->mn_ksize; DPRINTF(("update key %u (ofs %u) [%s] to [%s] on page %"Z"u", indx, ptr, mdb_dkey(&k2, kbuf2), DKEY(key), mp->mp_pgno)); } #endif /* Sizes must be 2-byte aligned. */ ksize = EVEN(key->mv_size); oksize = EVEN(node->mn_ksize); delta = ksize - oksize; /* Shift node contents if EVEN(key length) changed. */ if (delta) { if (delta > 0 && SIZELEFT(mp) < delta) { pgno_t pgno; /* not enough space left, do a delete and split */ DPRINTF(("Not enough room, delta = %d, splitting...", delta)); pgno = NODEPGNO(node); mdb_node_del(mc, 0); return mdb_page_split(mc, key, NULL, pgno, MDB_SPLIT_REPLACE); } numkeys = NUMKEYS(mp); for (i = 0; i < numkeys; i++) { if (mp->mp_ptrs[i] <= ptr) mp->mp_ptrs[i] -= delta; } base = (char *)mp + mp->mp_upper + PAGEBASE; len = ptr - mp->mp_upper + NODESIZE; memmove(base - delta, base, len); mp->mp_upper -= delta; node = NODEPTR(mp, indx); } /* But even if no shift was needed, update ksize */ if (node->mn_ksize != key->mv_size) node->mn_ksize = key->mv_size; if (key->mv_size) memcpy(NODEKEY(node), key->mv_data, key->mv_size); return MDB_SUCCESS; } static void mdb_cursor_copy(const MDB_cursor *csrc, MDB_cursor *cdst); /** Perform \b act while tracking temporary cursor \b mn */ #define WITH_CURSOR_TRACKING(mn, act) do { \ MDB_cursor dummy, *tracked, **tp = &(mn).mc_txn->mt_cursors[mn.mc_dbi]; \ if ((mn).mc_flags & C_SUB) { \ dummy.mc_flags = C_INITIALIZED; \ dummy.mc_xcursor = (MDB_xcursor *)&(mn); \ tracked = &dummy; \ } else { \ tracked = &(mn); \ } \ tracked->mc_next = *tp; \ *tp = tracked; \ { act; } \ *tp = tracked->mc_next; \ } while (0) /** Move a node from csrc to cdst. */ static int mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft) { MDB_node *srcnode; MDB_val key, data; pgno_t srcpg; MDB_cursor mn; int rc; unsigned short flags; DKBUF; /* Mark src and dst as dirty. */ if ((rc = mdb_page_touch(csrc)) || (rc = mdb_page_touch(cdst))) return rc; if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) { key.mv_size = csrc->mc_db->md_pad; key.mv_data = LEAF2KEY(csrc->mc_pg[csrc->mc_top], csrc->mc_ki[csrc->mc_top], key.mv_size); data.mv_size = 0; data.mv_data = NULL; srcpg = 0; flags = 0; } else { srcnode = NODEPTR(csrc->mc_pg[csrc->mc_top], csrc->mc_ki[csrc->mc_top]); mdb_cassert(csrc, !((size_t)srcnode & 1)); srcpg = NODEPGNO(srcnode); flags = srcnode->mn_flags; if (csrc->mc_ki[csrc->mc_top] == 0 && IS_BRANCH(csrc->mc_pg[csrc->mc_top])) { unsigned int snum = csrc->mc_snum; MDB_node *s2; /* must find the lowest key below src */ rc = mdb_page_search_lowest(csrc); if (rc) return rc; if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) { key.mv_size = csrc->mc_db->md_pad; key.mv_data = LEAF2KEY(csrc->mc_pg[csrc->mc_top], 0, key.mv_size); } else { s2 = NODEPTR(csrc->mc_pg[csrc->mc_top], 0); key.mv_size = NODEKSZ(s2); key.mv_data = NODEKEY(s2); } csrc->mc_snum = snum--; csrc->mc_top = snum; } else { key.mv_size = NODEKSZ(srcnode); key.mv_data = NODEKEY(srcnode); } data.mv_size = NODEDSZ(srcnode); data.mv_data = NODEDATA(srcnode); } mn.mc_xcursor = NULL; if (IS_BRANCH(cdst->mc_pg[cdst->mc_top]) && cdst->mc_ki[cdst->mc_top] == 0) { unsigned int snum = cdst->mc_snum; MDB_node *s2; MDB_val bkey; /* must find the lowest key below dst */ mdb_cursor_copy(cdst, &mn); rc = mdb_page_search_lowest(&mn); if (rc) return rc; if (IS_LEAF2(mn.mc_pg[mn.mc_top])) { bkey.mv_size = mn.mc_db->md_pad; bkey.mv_data = LEAF2KEY(mn.mc_pg[mn.mc_top], 0, bkey.mv_size); } else { s2 = NODEPTR(mn.mc_pg[mn.mc_top], 0); bkey.mv_size = NODEKSZ(s2); bkey.mv_data = NODEKEY(s2); } mn.mc_snum = snum--; mn.mc_top = snum; mn.mc_ki[snum] = 0; rc = mdb_update_key(&mn, &bkey); if (rc) return rc; } DPRINTF(("moving %s node %u [%s] on page %"Z"u to node %u on page %"Z"u", IS_LEAF(csrc->mc_pg[csrc->mc_top]) ? "leaf" : "branch", csrc->mc_ki[csrc->mc_top], DKEY(&key), csrc->mc_pg[csrc->mc_top]->mp_pgno, cdst->mc_ki[cdst->mc_top], cdst->mc_pg[cdst->mc_top]->mp_pgno)); /* Add the node to the destination page. */ rc = mdb_node_add(cdst, cdst->mc_ki[cdst->mc_top], &key, &data, srcpg, flags); if (rc != MDB_SUCCESS) return rc; /* Delete the node from the source page. */ mdb_node_del(csrc, key.mv_size); { /* Adjust other cursors pointing to mp */ MDB_cursor *m2, *m3; MDB_dbi dbi = csrc->mc_dbi; MDB_page *mpd, *mps; mps = csrc->mc_pg[csrc->mc_top]; /* If we're adding on the left, bump others up */ if (fromleft) { mpd = cdst->mc_pg[csrc->mc_top]; for (m2 = csrc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { if (csrc->mc_flags & C_SUB) m3 = &m2->mc_xcursor->mx_cursor; else m3 = m2; if (!(m3->mc_flags & C_INITIALIZED) || m3->mc_top < csrc->mc_top) continue; if (m3 != cdst && m3->mc_pg[csrc->mc_top] == mpd && m3->mc_ki[csrc->mc_top] >= cdst->mc_ki[csrc->mc_top]) { m3->mc_ki[csrc->mc_top]++; } if (m3 !=csrc && m3->mc_pg[csrc->mc_top] == mps && m3->mc_ki[csrc->mc_top] == csrc->mc_ki[csrc->mc_top]) { m3->mc_pg[csrc->mc_top] = cdst->mc_pg[cdst->mc_top]; m3->mc_ki[csrc->mc_top] = cdst->mc_ki[cdst->mc_top]; m3->mc_ki[csrc->mc_top-1]++; } if (IS_LEAF(mps)) XCURSOR_REFRESH(m3, csrc->mc_top, m3->mc_pg[csrc->mc_top]); } } else /* Adding on the right, bump others down */ { for (m2 = csrc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { if (csrc->mc_flags & C_SUB) m3 = &m2->mc_xcursor->mx_cursor; else m3 = m2; if (m3 == csrc) continue; if (!(m3->mc_flags & C_INITIALIZED) || m3->mc_top < csrc->mc_top) continue; if (m3->mc_pg[csrc->mc_top] == mps) { if (!m3->mc_ki[csrc->mc_top]) { m3->mc_pg[csrc->mc_top] = cdst->mc_pg[cdst->mc_top]; m3->mc_ki[csrc->mc_top] = cdst->mc_ki[cdst->mc_top]; m3->mc_ki[csrc->mc_top-1]--; } else { m3->mc_ki[csrc->mc_top]--; } if (IS_LEAF(mps)) XCURSOR_REFRESH(m3, csrc->mc_top, m3->mc_pg[csrc->mc_top]); } } } } /* Update the parent separators. */ if (csrc->mc_ki[csrc->mc_top] == 0) { if (csrc->mc_ki[csrc->mc_top-1] != 0) { if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) { key.mv_data = LEAF2KEY(csrc->mc_pg[csrc->mc_top], 0, key.mv_size); } else { srcnode = NODEPTR(csrc->mc_pg[csrc->mc_top], 0); key.mv_size = NODEKSZ(srcnode); key.mv_data = NODEKEY(srcnode); } DPRINTF(("update separator for source page %"Z"u to [%s]", csrc->mc_pg[csrc->mc_top]->mp_pgno, DKEY(&key))); mdb_cursor_copy(csrc, &mn); mn.mc_snum--; mn.mc_top--; /* We want mdb_rebalance to find mn when doing fixups */ WITH_CURSOR_TRACKING(mn, rc = mdb_update_key(&mn, &key)); if (rc) return rc; } if (IS_BRANCH(csrc->mc_pg[csrc->mc_top])) { MDB_val nullkey; indx_t ix = csrc->mc_ki[csrc->mc_top]; nullkey.mv_size = 0; csrc->mc_ki[csrc->mc_top] = 0; rc = mdb_update_key(csrc, &nullkey); csrc->mc_ki[csrc->mc_top] = ix; mdb_cassert(csrc, rc == MDB_SUCCESS); } } if (cdst->mc_ki[cdst->mc_top] == 0) { if (cdst->mc_ki[cdst->mc_top-1] != 0) { if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) { key.mv_data = LEAF2KEY(cdst->mc_pg[cdst->mc_top], 0, key.mv_size); } else { srcnode = NODEPTR(cdst->mc_pg[cdst->mc_top], 0); key.mv_size = NODEKSZ(srcnode); key.mv_data = NODEKEY(srcnode); } DPRINTF(("update separator for destination page %"Z"u to [%s]", cdst->mc_pg[cdst->mc_top]->mp_pgno, DKEY(&key))); mdb_cursor_copy(cdst, &mn); mn.mc_snum--; mn.mc_top--; /* We want mdb_rebalance to find mn when doing fixups */ WITH_CURSOR_TRACKING(mn, rc = mdb_update_key(&mn, &key)); if (rc) return rc; } if (IS_BRANCH(cdst->mc_pg[cdst->mc_top])) { MDB_val nullkey; indx_t ix = cdst->mc_ki[cdst->mc_top]; nullkey.mv_size = 0; cdst->mc_ki[cdst->mc_top] = 0; rc = mdb_update_key(cdst, &nullkey); cdst->mc_ki[cdst->mc_top] = ix; mdb_cassert(cdst, rc == MDB_SUCCESS); } } return MDB_SUCCESS; } /** Merge one page into another. * The nodes from the page pointed to by \b csrc will * be copied to the page pointed to by \b cdst and then * the \b csrc page will be freed. * @param[in] csrc Cursor pointing to the source page. * @param[in] cdst Cursor pointing to the destination page. * @return 0 on success, non-zero on failure. */ static int mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst) { MDB_page *psrc, *pdst; MDB_node *srcnode; MDB_val key, data; unsigned nkeys; int rc; indx_t i, j; psrc = csrc->mc_pg[csrc->mc_top]; pdst = cdst->mc_pg[cdst->mc_top]; DPRINTF(("merging page %"Z"u into %"Z"u", psrc->mp_pgno, pdst->mp_pgno)); mdb_cassert(csrc, csrc->mc_snum > 1); /* can't merge root page */ mdb_cassert(csrc, cdst->mc_snum > 1); /* Mark dst as dirty. */ if ((rc = mdb_page_touch(cdst))) return rc; /* get dst page again now that we've touched it. */ pdst = cdst->mc_pg[cdst->mc_top]; /* Move all nodes from src to dst. */ j = nkeys = NUMKEYS(pdst); if (IS_LEAF2(psrc)) { key.mv_size = csrc->mc_db->md_pad; key.mv_data = METADATA(psrc); for (i = 0; i < NUMKEYS(psrc); i++, j++) { rc = mdb_node_add(cdst, j, &key, NULL, 0, 0); if (rc != MDB_SUCCESS) return rc; key.mv_data = (char *)key.mv_data + key.mv_size; } } else { for (i = 0; i < NUMKEYS(psrc); i++, j++) { srcnode = NODEPTR(psrc, i); if (i == 0 && IS_BRANCH(psrc)) { MDB_cursor mn; MDB_node *s2; mdb_cursor_copy(csrc, &mn); mn.mc_xcursor = NULL; /* must find the lowest key below src */ rc = mdb_page_search_lowest(&mn); if (rc) return rc; if (IS_LEAF2(mn.mc_pg[mn.mc_top])) { key.mv_size = mn.mc_db->md_pad; key.mv_data = LEAF2KEY(mn.mc_pg[mn.mc_top], 0, key.mv_size); } else { s2 = NODEPTR(mn.mc_pg[mn.mc_top], 0); key.mv_size = NODEKSZ(s2); key.mv_data = NODEKEY(s2); } } else { key.mv_size = srcnode->mn_ksize; key.mv_data = NODEKEY(srcnode); } data.mv_size = NODEDSZ(srcnode); data.mv_data = NODEDATA(srcnode); rc = mdb_node_add(cdst, j, &key, &data, NODEPGNO(srcnode), srcnode->mn_flags); if (rc != MDB_SUCCESS) return rc; } } DPRINTF(("dst page %"Z"u now has %u keys (%.1f%% filled)", pdst->mp_pgno, NUMKEYS(pdst), (float)PAGEFILL(cdst->mc_txn->mt_env, pdst) / 10)); /* Unlink the src page from parent and add to free list. */ csrc->mc_top--; mdb_node_del(csrc, 0); if (csrc->mc_ki[csrc->mc_top] == 0) { key.mv_size = 0; rc = mdb_update_key(csrc, &key); if (rc) { csrc->mc_top++; return rc; } } csrc->mc_top++; psrc = csrc->mc_pg[csrc->mc_top]; /* If not operating on FreeDB, allow this page to be reused * in this txn. Otherwise just add to free list. */ rc = mdb_page_loose(csrc, psrc); if (rc) return rc; if (IS_LEAF(psrc)) csrc->mc_db->md_leaf_pages--; else csrc->mc_db->md_branch_pages--; { /* Adjust other cursors pointing to mp */ MDB_cursor *m2, *m3; MDB_dbi dbi = csrc->mc_dbi; unsigned int top = csrc->mc_top; for (m2 = csrc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { if (csrc->mc_flags & C_SUB) m3 = &m2->mc_xcursor->mx_cursor; else m3 = m2; if (m3 == csrc) continue; if (m3->mc_snum < csrc->mc_snum) continue; if (m3->mc_pg[top] == psrc) { m3->mc_pg[top] = pdst; m3->mc_ki[top] += nkeys; m3->mc_ki[top-1] = cdst->mc_ki[top-1]; } else if (m3->mc_pg[top-1] == csrc->mc_pg[top-1] && m3->mc_ki[top-1] > csrc->mc_ki[top-1]) { m3->mc_ki[top-1]--; } if (IS_LEAF(psrc)) XCURSOR_REFRESH(m3, top, m3->mc_pg[top]); } } { unsigned int snum = cdst->mc_snum; uint16_t depth = cdst->mc_db->md_depth; mdb_cursor_pop(cdst); rc = mdb_rebalance(cdst); /* Did the tree height change? */ if (depth != cdst->mc_db->md_depth) snum += cdst->mc_db->md_depth - depth; cdst->mc_snum = snum; cdst->mc_top = snum-1; } return rc; } /** Copy the contents of a cursor. * @param[in] csrc The cursor to copy from. * @param[out] cdst The cursor to copy to. */ static void mdb_cursor_copy(const MDB_cursor *csrc, MDB_cursor *cdst) { unsigned int i; cdst->mc_txn = csrc->mc_txn; cdst->mc_dbi = csrc->mc_dbi; cdst->mc_db = csrc->mc_db; cdst->mc_dbx = csrc->mc_dbx; cdst->mc_snum = csrc->mc_snum; cdst->mc_top = csrc->mc_top; cdst->mc_flags = csrc->mc_flags; for (i=0; imc_snum; i++) { cdst->mc_pg[i] = csrc->mc_pg[i]; cdst->mc_ki[i] = csrc->mc_ki[i]; } } /** Rebalance the tree after a delete operation. * @param[in] mc Cursor pointing to the page where rebalancing * should begin. * @return 0 on success, non-zero on failure. */ static int mdb_rebalance(MDB_cursor *mc) { MDB_node *node; int rc, fromleft; unsigned int ptop, minkeys, thresh; MDB_cursor mn; indx_t oldki; if (IS_BRANCH(mc->mc_pg[mc->mc_top])) { minkeys = 2; thresh = 1; } else { minkeys = 1; thresh = FILL_THRESHOLD; } DPRINTF(("rebalancing %s page %"Z"u (has %u keys, %.1f%% full)", IS_LEAF(mc->mc_pg[mc->mc_top]) ? "leaf" : "branch", mdb_dbg_pgno(mc->mc_pg[mc->mc_top]), NUMKEYS(mc->mc_pg[mc->mc_top]), (float)PAGEFILL(mc->mc_txn->mt_env, mc->mc_pg[mc->mc_top]) / 10)); if (PAGEFILL(mc->mc_txn->mt_env, mc->mc_pg[mc->mc_top]) >= thresh && NUMKEYS(mc->mc_pg[mc->mc_top]) >= minkeys) { DPRINTF(("no need to rebalance page %"Z"u, above fill threshold", mdb_dbg_pgno(mc->mc_pg[mc->mc_top]))); return MDB_SUCCESS; } if (mc->mc_snum < 2) { MDB_page *mp = mc->mc_pg[0]; if (IS_SUBP(mp)) { DPUTS("Can't rebalance a subpage, ignoring"); return MDB_SUCCESS; } if (NUMKEYS(mp) == 0) { DPUTS("tree is completely empty"); mc->mc_db->md_root = P_INVALID; mc->mc_db->md_depth = 0; mc->mc_db->md_leaf_pages = 0; rc = mdb_midl_append(&mc->mc_txn->mt_free_pgs, mp->mp_pgno); if (rc) return rc; /* Adjust cursors pointing to mp */ mc->mc_snum = 0; mc->mc_top = 0; mc->mc_flags &= ~C_INITIALIZED; { MDB_cursor *m2, *m3; MDB_dbi dbi = mc->mc_dbi; for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { if (mc->mc_flags & C_SUB) m3 = &m2->mc_xcursor->mx_cursor; else m3 = m2; if (!(m3->mc_flags & C_INITIALIZED) || (m3->mc_snum < mc->mc_snum)) continue; if (m3->mc_pg[0] == mp) { m3->mc_snum = 0; m3->mc_top = 0; m3->mc_flags &= ~C_INITIALIZED; } } } } else if (IS_BRANCH(mp) && NUMKEYS(mp) == 1) { int i; DPUTS("collapsing root page!"); rc = mdb_midl_append(&mc->mc_txn->mt_free_pgs, mp->mp_pgno); if (rc) return rc; mc->mc_db->md_root = NODEPGNO(NODEPTR(mp, 0)); rc = mdb_page_get(mc, mc->mc_db->md_root, &mc->mc_pg[0], NULL); if (rc) return rc; mc->mc_db->md_depth--; mc->mc_db->md_branch_pages--; mc->mc_ki[0] = mc->mc_ki[1]; for (i = 1; imc_db->md_depth; i++) { mc->mc_pg[i] = mc->mc_pg[i+1]; mc->mc_ki[i] = mc->mc_ki[i+1]; } { /* Adjust other cursors pointing to mp */ MDB_cursor *m2, *m3; MDB_dbi dbi = mc->mc_dbi; for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { if (mc->mc_flags & C_SUB) m3 = &m2->mc_xcursor->mx_cursor; else m3 = m2; if (m3 == mc) continue; if (!(m3->mc_flags & C_INITIALIZED)) continue; if (m3->mc_pg[0] == mp) { for (i=0; imc_db->md_depth; i++) { m3->mc_pg[i] = m3->mc_pg[i+1]; m3->mc_ki[i] = m3->mc_ki[i+1]; } m3->mc_snum--; m3->mc_top--; } } } } else DPUTS("root page doesn't need rebalancing"); return MDB_SUCCESS; } /* The parent (branch page) must have at least 2 pointers, * otherwise the tree is invalid. */ ptop = mc->mc_top-1; mdb_cassert(mc, NUMKEYS(mc->mc_pg[ptop]) > 1); /* Leaf page fill factor is below the threshold. * Try to move keys from left or right neighbor, or * merge with a neighbor page. */ /* Find neighbors. */ mdb_cursor_copy(mc, &mn); mn.mc_xcursor = NULL; oldki = mc->mc_ki[mc->mc_top]; if (mc->mc_ki[ptop] == 0) { /* We're the leftmost leaf in our parent. */ DPUTS("reading right neighbor"); mn.mc_ki[ptop]++; node = NODEPTR(mc->mc_pg[ptop], mn.mc_ki[ptop]); rc = mdb_page_get(mc, NODEPGNO(node), &mn.mc_pg[mn.mc_top], NULL); if (rc) return rc; mn.mc_ki[mn.mc_top] = 0; mc->mc_ki[mc->mc_top] = NUMKEYS(mc->mc_pg[mc->mc_top]); fromleft = 0; } else { /* There is at least one neighbor to the left. */ DPUTS("reading left neighbor"); mn.mc_ki[ptop]--; node = NODEPTR(mc->mc_pg[ptop], mn.mc_ki[ptop]); rc = mdb_page_get(mc, NODEPGNO(node), &mn.mc_pg[mn.mc_top], NULL); if (rc) return rc; mn.mc_ki[mn.mc_top] = NUMKEYS(mn.mc_pg[mn.mc_top]) - 1; mc->mc_ki[mc->mc_top] = 0; fromleft = 1; } DPRINTF(("found neighbor page %"Z"u (%u keys, %.1f%% full)", mn.mc_pg[mn.mc_top]->mp_pgno, NUMKEYS(mn.mc_pg[mn.mc_top]), (float)PAGEFILL(mc->mc_txn->mt_env, mn.mc_pg[mn.mc_top]) / 10)); /* If the neighbor page is above threshold and has enough keys, * move one key from it. Otherwise we should try to merge them. * (A branch page must never have less than 2 keys.) */ if (PAGEFILL(mc->mc_txn->mt_env, mn.mc_pg[mn.mc_top]) >= thresh && NUMKEYS(mn.mc_pg[mn.mc_top]) > minkeys) { rc = mdb_node_move(&mn, mc, fromleft); if (fromleft) { /* if we inserted on left, bump position up */ oldki++; } } else { if (!fromleft) { rc = mdb_page_merge(&mn, mc); } else { oldki += NUMKEYS(mn.mc_pg[mn.mc_top]); mn.mc_ki[mn.mc_top] += mc->mc_ki[mn.mc_top] + 1; /* We want mdb_rebalance to find mn when doing fixups */ WITH_CURSOR_TRACKING(mn, rc = mdb_page_merge(mc, &mn)); mdb_cursor_copy(&mn, mc); } mc->mc_flags &= ~C_EOF; } mc->mc_ki[mc->mc_top] = oldki; return rc; } /** Complete a delete operation started by #mdb_cursor_del(). */ static int mdb_cursor_del0(MDB_cursor *mc) { int rc; MDB_page *mp; indx_t ki; unsigned int nkeys; MDB_cursor *m2, *m3; MDB_dbi dbi = mc->mc_dbi; ki = mc->mc_ki[mc->mc_top]; mp = mc->mc_pg[mc->mc_top]; mdb_node_del(mc, mc->mc_db->md_pad); mc->mc_db->md_entries--; { /* Adjust other cursors pointing to mp */ for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { m3 = (mc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2; if (! (m2->mc_flags & m3->mc_flags & C_INITIALIZED)) continue; if (m3 == mc || m3->mc_snum < mc->mc_snum) continue; if (m3->mc_pg[mc->mc_top] == mp) { if (m3->mc_ki[mc->mc_top] == ki) { m3->mc_flags |= C_DEL; if (mc->mc_db->md_flags & MDB_DUPSORT) { /* Sub-cursor referred into dataset which is gone */ m3->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); } continue; } else if (m3->mc_ki[mc->mc_top] > ki) { m3->mc_ki[mc->mc_top]--; } XCURSOR_REFRESH(m3, mc->mc_top, mp); } } } rc = mdb_rebalance(mc); if (rc) goto fail; /* DB is totally empty now, just bail out. * Other cursors adjustments were already done * by mdb_rebalance and aren't needed here. */ if (!mc->mc_snum) { mc->mc_flags |= C_EOF; return rc; } mp = mc->mc_pg[mc->mc_top]; nkeys = NUMKEYS(mp); /* Adjust other cursors pointing to mp */ for (m2 = mc->mc_txn->mt_cursors[dbi]; !rc && m2; m2=m2->mc_next) { m3 = (mc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2; if (!(m2->mc_flags & m3->mc_flags & C_INITIALIZED)) continue; if (m3->mc_snum < mc->mc_snum) continue; if (m3->mc_pg[mc->mc_top] == mp) { if (m3->mc_ki[mc->mc_top] >= mc->mc_ki[mc->mc_top]) { /* if m3 points past last node in page, find next sibling */ if (m3->mc_ki[mc->mc_top] >= nkeys) { rc = mdb_cursor_sibling(m3, 1); if (rc == MDB_NOTFOUND) { m3->mc_flags |= C_EOF; rc = MDB_SUCCESS; continue; } if (rc) goto fail; } if (m3->mc_xcursor && !(m3->mc_flags & C_EOF)) { MDB_node *node = NODEPTR(m3->mc_pg[m3->mc_top], m3->mc_ki[m3->mc_top]); /* If this node has dupdata, it may need to be reinited * because its data has moved. * If the xcursor was not initd it must be reinited. * Else if node points to a subDB, nothing is needed. * Else (xcursor was initd, not a subDB) needs mc_pg[0] reset. */ if (node->mn_flags & F_DUPDATA) { if (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) { if (!(node->mn_flags & F_SUBDATA)) m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(node); } else { mdb_xcursor_init1(m3, node); rc = mdb_cursor_first(&m3->mc_xcursor->mx_cursor, NULL, NULL); if (rc) goto fail; } } m3->mc_xcursor->mx_cursor.mc_flags |= C_DEL; } } } } mc->mc_flags |= C_DEL; fail: if (rc) mc->mc_txn->mt_flags |= MDB_TXN_ERROR; return rc; } int mdb_del(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data) { if (!key || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) return EINVAL; if (txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED)) return (txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN; if (!F_ISSET(txn->mt_dbs[dbi].md_flags, MDB_DUPSORT)) { /* must ignore any data */ data = NULL; } return mdb_del0(txn, dbi, key, data, 0); } static int mdb_del0(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data, unsigned flags) { MDB_cursor mc; MDB_xcursor mx; MDB_cursor_op op; MDB_val rdata, *xdata; int rc, exact = 0; DKBUF; DPRINTF(("====> delete db %u key [%s]", dbi, DKEY(key))); mdb_cursor_init(&mc, txn, dbi, &mx); if (data) { op = MDB_GET_BOTH; rdata = *data; xdata = &rdata; } else { op = MDB_SET; xdata = NULL; flags |= MDB_NODUPDATA; } rc = mdb_cursor_set(&mc, key, xdata, op, &exact); if (rc == 0) { /* let mdb_page_split know about this cursor if needed: * delete will trigger a rebalance; if it needs to move * a node from one page to another, it will have to * update the parent's separator key(s). If the new sepkey * is larger than the current one, the parent page may * run out of space, triggering a split. We need this * cursor to be consistent until the end of the rebalance. */ mc.mc_flags |= C_UNTRACK; mc.mc_next = txn->mt_cursors[dbi]; txn->mt_cursors[dbi] = &mc; rc = mdb_cursor_del(&mc, flags); txn->mt_cursors[dbi] = mc.mc_next; } return rc; } /** Split a page and insert a new node. * Set #MDB_TXN_ERROR on failure. * @param[in,out] mc Cursor pointing to the page and desired insertion index. * The cursor will be updated to point to the actual page and index where * the node got inserted after the split. * @param[in] newkey The key for the newly inserted node. * @param[in] newdata The data for the newly inserted node. * @param[in] newpgno The page number, if the new node is a branch node. * @param[in] nflags The #NODE_ADD_FLAGS for the new node. * @return 0 on success, non-zero on failure. */ static int mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno, unsigned int nflags) { unsigned int flags; int rc = MDB_SUCCESS, new_root = 0, did_split = 0; indx_t newindx; pgno_t pgno = 0; int i, j, split_indx, nkeys, pmax; MDB_env *env = mc->mc_txn->mt_env; MDB_node *node; MDB_val sepkey, rkey, xdata, *rdata = &xdata; MDB_page *copy = NULL; MDB_page *mp, *rp, *pp; int ptop; MDB_cursor mn; DKBUF; mp = mc->mc_pg[mc->mc_top]; newindx = mc->mc_ki[mc->mc_top]; nkeys = NUMKEYS(mp); DPRINTF(("-----> splitting %s page %"Z"u and adding [%s] at index %i/%i", IS_LEAF(mp) ? "leaf" : "branch", mp->mp_pgno, DKEY(newkey), mc->mc_ki[mc->mc_top], nkeys)); /* Create a right sibling. */ if ((rc = mdb_page_new(mc, mp->mp_flags, 1, &rp))) return rc; rp->mp_pad = mp->mp_pad; DPRINTF(("new right sibling: page %"Z"u", rp->mp_pgno)); /* Usually when splitting the root page, the cursor * height is 1. But when called from mdb_update_key, * the cursor height may be greater because it walks * up the stack while finding the branch slot to update. */ if (mc->mc_top < 1) { if ((rc = mdb_page_new(mc, P_BRANCH, 1, &pp))) goto done; /* shift current top to make room for new parent */ for (i=mc->mc_snum; i>0; i--) { mc->mc_pg[i] = mc->mc_pg[i-1]; mc->mc_ki[i] = mc->mc_ki[i-1]; } mc->mc_pg[0] = pp; mc->mc_ki[0] = 0; mc->mc_db->md_root = pp->mp_pgno; DPRINTF(("root split! new root = %"Z"u", pp->mp_pgno)); new_root = mc->mc_db->md_depth++; /* Add left (implicit) pointer. */ if ((rc = mdb_node_add(mc, 0, NULL, NULL, mp->mp_pgno, 0)) != MDB_SUCCESS) { /* undo the pre-push */ mc->mc_pg[0] = mc->mc_pg[1]; mc->mc_ki[0] = mc->mc_ki[1]; mc->mc_db->md_root = mp->mp_pgno; mc->mc_db->md_depth--; goto done; } mc->mc_snum++; mc->mc_top++; ptop = 0; } else { ptop = mc->mc_top-1; DPRINTF(("parent branch page is %"Z"u", mc->mc_pg[ptop]->mp_pgno)); } mdb_cursor_copy(mc, &mn); mn.mc_xcursor = NULL; mn.mc_pg[mn.mc_top] = rp; mn.mc_ki[ptop] = mc->mc_ki[ptop]+1; if (nflags & MDB_APPEND) { mn.mc_ki[mn.mc_top] = 0; sepkey = *newkey; split_indx = newindx; nkeys = 0; } else { split_indx = (nkeys+1) / 2; if (IS_LEAF2(rp)) { char *split, *ins; int x; unsigned int lsize, rsize, ksize; /* Move half of the keys to the right sibling */ x = mc->mc_ki[mc->mc_top] - split_indx; ksize = mc->mc_db->md_pad; split = LEAF2KEY(mp, split_indx, ksize); rsize = (nkeys - split_indx) * ksize; lsize = (nkeys - split_indx) * sizeof(indx_t); mp->mp_lower -= lsize; rp->mp_lower += lsize; mp->mp_upper += rsize - lsize; rp->mp_upper -= rsize - lsize; sepkey.mv_size = ksize; if (newindx == split_indx) { sepkey.mv_data = newkey->mv_data; } else { sepkey.mv_data = split; } if (x<0) { ins = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], ksize); memcpy(rp->mp_ptrs, split, rsize); sepkey.mv_data = rp->mp_ptrs; memmove(ins+ksize, ins, (split_indx - mc->mc_ki[mc->mc_top]) * ksize); memcpy(ins, newkey->mv_data, ksize); mp->mp_lower += sizeof(indx_t); mp->mp_upper -= ksize - sizeof(indx_t); } else { if (x) memcpy(rp->mp_ptrs, split, x * ksize); ins = LEAF2KEY(rp, x, ksize); memcpy(ins, newkey->mv_data, ksize); memcpy(ins+ksize, split + x * ksize, rsize - x * ksize); rp->mp_lower += sizeof(indx_t); rp->mp_upper -= ksize - sizeof(indx_t); mc->mc_ki[mc->mc_top] = x; } } else { int psize, nsize, k; /* Maximum free space in an empty page */ pmax = env->me_psize - PAGEHDRSZ; if (IS_LEAF(mp)) nsize = mdb_leaf_size(env, newkey, newdata); else nsize = mdb_branch_size(env, newkey); nsize = EVEN(nsize); /* grab a page to hold a temporary copy */ copy = mdb_page_malloc(mc->mc_txn, 1); if (copy == NULL) { rc = ENOMEM; goto done; } copy->mp_pgno = mp->mp_pgno; copy->mp_flags = mp->mp_flags; copy->mp_lower = (PAGEHDRSZ-PAGEBASE); copy->mp_upper = env->me_psize - PAGEBASE; /* prepare to insert */ for (i=0, j=0; imp_ptrs[j++] = 0; } copy->mp_ptrs[j++] = mp->mp_ptrs[i]; } /* When items are relatively large the split point needs * to be checked, because being off-by-one will make the * difference between success or failure in mdb_node_add. * * It's also relevant if a page happens to be laid out * such that one half of its nodes are all "small" and * the other half of its nodes are "large." If the new * item is also "large" and falls on the half with * "large" nodes, it also may not fit. * * As a final tweak, if the new item goes on the last * spot on the page (and thus, onto the new page), bias * the split so the new page is emptier than the old page. * This yields better packing during sequential inserts. */ if (nkeys < 32 || nsize > pmax/16 || newindx >= nkeys) { /* Find split point */ psize = 0; if (newindx <= split_indx || newindx >= nkeys) { i = 0; j = 1; k = newindx >= nkeys ? nkeys : split_indx+1+IS_LEAF(mp); } else { i = nkeys; j = -1; k = split_indx-1; } for (; i!=k; i+=j) { if (i == newindx) { psize += nsize; node = NULL; } else { node = (MDB_node *)((char *)mp + copy->mp_ptrs[i] + PAGEBASE); psize += NODESIZE + NODEKSZ(node) + sizeof(indx_t); if (IS_LEAF(mp)) { if (F_ISSET(node->mn_flags, F_BIGDATA)) psize += sizeof(pgno_t); else psize += NODEDSZ(node); } psize = EVEN(psize); } if (psize > pmax || i == k-j) { split_indx = i + (j<0); break; } } } if (split_indx == newindx) { sepkey.mv_size = newkey->mv_size; sepkey.mv_data = newkey->mv_data; } else { node = (MDB_node *)((char *)mp + copy->mp_ptrs[split_indx] + PAGEBASE); sepkey.mv_size = node->mn_ksize; sepkey.mv_data = NODEKEY(node); } } } DPRINTF(("separator is %d [%s]", split_indx, DKEY(&sepkey))); /* Copy separator key to the parent. */ if (SIZELEFT(mn.mc_pg[ptop]) < mdb_branch_size(env, &sepkey)) { int snum = mc->mc_snum; mn.mc_snum--; mn.mc_top--; did_split = 1; /* We want other splits to find mn when doing fixups */ WITH_CURSOR_TRACKING(mn, rc = mdb_page_split(&mn, &sepkey, NULL, rp->mp_pgno, 0)); if (rc) goto done; /* root split? */ if (mc->mc_snum > snum) { ptop++; } /* Right page might now have changed parent. * Check if left page also changed parent. */ if (mn.mc_pg[ptop] != mc->mc_pg[ptop] && mc->mc_ki[ptop] >= NUMKEYS(mc->mc_pg[ptop])) { for (i=0; imc_pg[i] = mn.mc_pg[i]; mc->mc_ki[i] = mn.mc_ki[i]; } mc->mc_pg[ptop] = mn.mc_pg[ptop]; if (mn.mc_ki[ptop]) { mc->mc_ki[ptop] = mn.mc_ki[ptop] - 1; } else { /* find right page's left sibling */ mc->mc_ki[ptop] = mn.mc_ki[ptop]; mdb_cursor_sibling(mc, 0); } } } else { mn.mc_top--; rc = mdb_node_add(&mn, mn.mc_ki[ptop], &sepkey, NULL, rp->mp_pgno, 0); mn.mc_top++; } if (rc != MDB_SUCCESS) { goto done; } if (nflags & MDB_APPEND) { mc->mc_pg[mc->mc_top] = rp; mc->mc_ki[mc->mc_top] = 0; rc = mdb_node_add(mc, 0, newkey, newdata, newpgno, nflags); if (rc) goto done; for (i=0; imc_top; i++) mc->mc_ki[i] = mn.mc_ki[i]; } else if (!IS_LEAF2(mp)) { /* Move nodes */ mc->mc_pg[mc->mc_top] = rp; i = split_indx; j = 0; do { if (i == newindx) { rkey.mv_data = newkey->mv_data; rkey.mv_size = newkey->mv_size; if (IS_LEAF(mp)) { rdata = newdata; } else pgno = newpgno; flags = nflags; /* Update index for the new key. */ mc->mc_ki[mc->mc_top] = j; } else { node = (MDB_node *)((char *)mp + copy->mp_ptrs[i] + PAGEBASE); rkey.mv_data = NODEKEY(node); rkey.mv_size = node->mn_ksize; if (IS_LEAF(mp)) { xdata.mv_data = NODEDATA(node); xdata.mv_size = NODEDSZ(node); rdata = &xdata; } else pgno = NODEPGNO(node); flags = node->mn_flags; } if (!IS_LEAF(mp) && j == 0) { /* First branch index doesn't need key data. */ rkey.mv_size = 0; } rc = mdb_node_add(mc, j, &rkey, rdata, pgno, flags); if (rc) goto done; if (i == nkeys) { i = 0; j = 0; mc->mc_pg[mc->mc_top] = copy; } else { i++; j++; } } while (i != split_indx); nkeys = NUMKEYS(copy); for (i=0; imp_ptrs[i] = copy->mp_ptrs[i]; mp->mp_lower = copy->mp_lower; mp->mp_upper = copy->mp_upper; memcpy(NODEPTR(mp, nkeys-1), NODEPTR(copy, nkeys-1), env->me_psize - copy->mp_upper - PAGEBASE); /* reset back to original page */ if (newindx < split_indx) { mc->mc_pg[mc->mc_top] = mp; } else { mc->mc_pg[mc->mc_top] = rp; mc->mc_ki[ptop]++; /* Make sure mc_ki is still valid. */ if (mn.mc_pg[ptop] != mc->mc_pg[ptop] && mc->mc_ki[ptop] >= NUMKEYS(mc->mc_pg[ptop])) { for (i=0; i<=ptop; i++) { mc->mc_pg[i] = mn.mc_pg[i]; mc->mc_ki[i] = mn.mc_ki[i]; } } } if (nflags & MDB_RESERVE) { node = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); if (!(node->mn_flags & F_BIGDATA)) newdata->mv_data = NODEDATA(node); } } else { if (newindx >= split_indx) { mc->mc_pg[mc->mc_top] = rp; mc->mc_ki[ptop]++; /* Make sure mc_ki is still valid. */ if (mn.mc_pg[ptop] != mc->mc_pg[ptop] && mc->mc_ki[ptop] >= NUMKEYS(mc->mc_pg[ptop])) { for (i=0; i<=ptop; i++) { mc->mc_pg[i] = mn.mc_pg[i]; mc->mc_ki[i] = mn.mc_ki[i]; } } } } { /* Adjust other cursors pointing to mp */ MDB_cursor *m2, *m3; MDB_dbi dbi = mc->mc_dbi; nkeys = NUMKEYS(mp); for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { if (mc->mc_flags & C_SUB) m3 = &m2->mc_xcursor->mx_cursor; else m3 = m2; if (m3 == mc) continue; if (!(m2->mc_flags & m3->mc_flags & C_INITIALIZED)) continue; if (new_root) { int k; /* sub cursors may be on different DB */ if (m3->mc_pg[0] != mp) continue; /* root split */ for (k=new_root; k>=0; k--) { m3->mc_ki[k+1] = m3->mc_ki[k]; m3->mc_pg[k+1] = m3->mc_pg[k]; } if (m3->mc_ki[0] >= nkeys) { m3->mc_ki[0] = 1; } else { m3->mc_ki[0] = 0; } m3->mc_pg[0] = mc->mc_pg[0]; m3->mc_snum++; m3->mc_top++; } if (m3->mc_top >= mc->mc_top && m3->mc_pg[mc->mc_top] == mp) { if (m3->mc_ki[mc->mc_top] >= newindx && !(nflags & MDB_SPLIT_REPLACE)) m3->mc_ki[mc->mc_top]++; if (m3->mc_ki[mc->mc_top] >= nkeys) { m3->mc_pg[mc->mc_top] = rp; m3->mc_ki[mc->mc_top] -= nkeys; for (i=0; imc_top; i++) { m3->mc_ki[i] = mn.mc_ki[i]; m3->mc_pg[i] = mn.mc_pg[i]; } } } else if (!did_split && m3->mc_top >= ptop && m3->mc_pg[ptop] == mc->mc_pg[ptop] && m3->mc_ki[ptop] >= mc->mc_ki[ptop]) { m3->mc_ki[ptop]++; } if (IS_LEAF(mp)) XCURSOR_REFRESH(m3, mc->mc_top, m3->mc_pg[mc->mc_top]); } } DPRINTF(("mp left: %d, rp left: %d", SIZELEFT(mp), SIZELEFT(rp))); done: if (copy) /* tmp page */ mdb_page_free(env, copy); if (rc) mc->mc_txn->mt_flags |= MDB_TXN_ERROR; return rc; } int mdb_put(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data, unsigned int flags) { MDB_cursor mc; MDB_xcursor mx; int rc; if (!key || !data || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) return EINVAL; if (flags & ~(MDB_NOOVERWRITE|MDB_NODUPDATA|MDB_RESERVE|MDB_APPEND|MDB_APPENDDUP)) return EINVAL; if (txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED)) return (txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN; mdb_cursor_init(&mc, txn, dbi, &mx); mc.mc_next = txn->mt_cursors[dbi]; txn->mt_cursors[dbi] = &mc; rc = mdb_cursor_put(&mc, key, data, flags); txn->mt_cursors[dbi] = mc.mc_next; return rc; } #ifndef MDB_WBUF #define MDB_WBUF (1024*1024) #endif #define MDB_EOF 0x10 /**< #mdb_env_copyfd1() is done reading */ /** State needed for a double-buffering compacting copy. */ typedef struct mdb_copy { MDB_env *mc_env; MDB_txn *mc_txn; pthread_mutex_t mc_mutex; pthread_cond_t mc_cond; /**< Condition variable for #mc_new */ char *mc_wbuf[2]; char *mc_over[2]; int mc_wlen[2]; int mc_olen[2]; pgno_t mc_next_pgno; HANDLE mc_fd; int mc_toggle; /**< Buffer number in provider */ int mc_new; /**< (0-2 buffers to write) | (#MDB_EOF at end) */ /** Error code. Never cleared if set. Both threads can set nonzero * to fail the copy. Not mutex-protected, LMDB expects atomic int. */ volatile int mc_error; } mdb_copy; /** Dedicated writer thread for compacting copy. */ static THREAD_RET ESECT CALL_CONV mdb_env_copythr(void *arg) { mdb_copy *my = arg; char *ptr; int toggle = 0, wsize, rc; #ifdef _WIN32 DWORD len; #define DO_WRITE(rc, fd, ptr, w2, len) rc = WriteFile(fd, ptr, w2, &len, NULL) #else int len; #define DO_WRITE(rc, fd, ptr, w2, len) len = write(fd, ptr, w2); rc = (len >= 0) #ifdef SIGPIPE sigset_t set; sigemptyset(&set); sigaddset(&set, SIGPIPE); if ((rc = pthread_sigmask(SIG_BLOCK, &set, NULL)) != 0) my->mc_error = rc; #endif #endif pthread_mutex_lock(&my->mc_mutex); for(;;) { while (!my->mc_new) pthread_cond_wait(&my->mc_cond, &my->mc_mutex); if (my->mc_new == 0 + MDB_EOF) /* 0 buffers, just EOF */ break; wsize = my->mc_wlen[toggle]; ptr = my->mc_wbuf[toggle]; again: rc = MDB_SUCCESS; while (wsize > 0 && !my->mc_error) { DO_WRITE(rc, my->mc_fd, ptr, wsize, len); if (!rc) { rc = ErrCode(); #if defined(SIGPIPE) && !defined(_WIN32) if (rc == EPIPE) { /* Collect the pending SIGPIPE, otherwise at least OS X * gives it to the process on thread-exit (ITS#8504). */ int tmp; sigwait(&set, &tmp); } #endif break; } else if (len > 0) { rc = MDB_SUCCESS; ptr += len; wsize -= len; continue; } else { rc = EIO; break; } } if (rc) { my->mc_error = rc; } /* If there's an overflow page tail, write it too */ if (my->mc_olen[toggle]) { wsize = my->mc_olen[toggle]; ptr = my->mc_over[toggle]; my->mc_olen[toggle] = 0; goto again; } my->mc_wlen[toggle] = 0; toggle ^= 1; /* Return the empty buffer to provider */ my->mc_new--; pthread_cond_signal(&my->mc_cond); } pthread_mutex_unlock(&my->mc_mutex); return (THREAD_RET)0; #undef DO_WRITE } /** Give buffer and/or #MDB_EOF to writer thread, await unused buffer. * * @param[in] my control structure. * @param[in] adjust (1 to hand off 1 buffer) | (MDB_EOF when ending). */ static int ESECT mdb_env_cthr_toggle(mdb_copy *my, int adjust) { pthread_mutex_lock(&my->mc_mutex); my->mc_new += adjust; pthread_cond_signal(&my->mc_cond); while (my->mc_new & 2) /* both buffers in use */ pthread_cond_wait(&my->mc_cond, &my->mc_mutex); pthread_mutex_unlock(&my->mc_mutex); my->mc_toggle ^= (adjust & 1); /* Both threads reset mc_wlen, to be safe from threading errors */ my->mc_wlen[my->mc_toggle] = 0; return my->mc_error; } /** Depth-first tree traversal for compacting copy. * @param[in] my control structure. * @param[in,out] pg database root. * @param[in] flags includes #F_DUPDATA if it is a sorted-duplicate sub-DB. */ static int ESECT mdb_env_cwalk(mdb_copy *my, pgno_t *pg, int flags) { MDB_cursor mc = {0}; MDB_node *ni; MDB_page *mo, *mp, *leaf; char *buf, *ptr; int rc, toggle; unsigned int i; /* Empty DB, nothing to do */ if (*pg == P_INVALID) return MDB_SUCCESS; mc.mc_snum = 1; mc.mc_txn = my->mc_txn; rc = mdb_page_get(&mc, *pg, &mc.mc_pg[0], NULL); if (rc) return rc; rc = mdb_page_search_root(&mc, NULL, MDB_PS_FIRST); if (rc) return rc; /* Make cursor pages writable */ buf = ptr = malloc(my->mc_env->me_psize * mc.mc_snum); if (buf == NULL) return ENOMEM; for (i=0; imc_env->me_psize); mc.mc_pg[i] = (MDB_page *)ptr; ptr += my->mc_env->me_psize; } /* This is writable space for a leaf page. Usually not needed. */ leaf = (MDB_page *)ptr; toggle = my->mc_toggle; while (mc.mc_snum > 0) { unsigned n; mp = mc.mc_pg[mc.mc_top]; n = NUMKEYS(mp); if (IS_LEAF(mp)) { if (!IS_LEAF2(mp) && !(flags & F_DUPDATA)) { for (i=0; imn_flags & F_BIGDATA) { MDB_page *omp; pgno_t pg; /* Need writable leaf */ if (mp != leaf) { mc.mc_pg[mc.mc_top] = leaf; mdb_page_copy(leaf, mp, my->mc_env->me_psize); mp = leaf; ni = NODEPTR(mp, i); } memcpy(&pg, NODEDATA(ni), sizeof(pg)); memcpy(NODEDATA(ni), &my->mc_next_pgno, sizeof(pgno_t)); rc = mdb_page_get(&mc, pg, &omp, NULL); if (rc) goto done; if (my->mc_wlen[toggle] >= MDB_WBUF) { rc = mdb_env_cthr_toggle(my, 1); if (rc) goto done; toggle = my->mc_toggle; } mo = (MDB_page *)(my->mc_wbuf[toggle] + my->mc_wlen[toggle]); memcpy(mo, omp, my->mc_env->me_psize); mo->mp_pgno = my->mc_next_pgno; my->mc_next_pgno += omp->mp_pages; my->mc_wlen[toggle] += my->mc_env->me_psize; if (omp->mp_pages > 1) { my->mc_olen[toggle] = my->mc_env->me_psize * (omp->mp_pages - 1); my->mc_over[toggle] = (char *)omp + my->mc_env->me_psize; rc = mdb_env_cthr_toggle(my, 1); if (rc) goto done; toggle = my->mc_toggle; } } else if (ni->mn_flags & F_SUBDATA) { MDB_db db; /* Need writable leaf */ if (mp != leaf) { mc.mc_pg[mc.mc_top] = leaf; mdb_page_copy(leaf, mp, my->mc_env->me_psize); mp = leaf; ni = NODEPTR(mp, i); } memcpy(&db, NODEDATA(ni), sizeof(db)); my->mc_toggle = toggle; rc = mdb_env_cwalk(my, &db.md_root, ni->mn_flags & F_DUPDATA); if (rc) goto done; toggle = my->mc_toggle; memcpy(NODEDATA(ni), &db, sizeof(db)); } } } } else { mc.mc_ki[mc.mc_top]++; if (mc.mc_ki[mc.mc_top] < n) { pgno_t pg; again: ni = NODEPTR(mp, mc.mc_ki[mc.mc_top]); pg = NODEPGNO(ni); rc = mdb_page_get(&mc, pg, &mp, NULL); if (rc) goto done; mc.mc_top++; mc.mc_snum++; mc.mc_ki[mc.mc_top] = 0; if (IS_BRANCH(mp)) { /* Whenever we advance to a sibling branch page, * we must proceed all the way down to its first leaf. */ mdb_page_copy(mc.mc_pg[mc.mc_top], mp, my->mc_env->me_psize); goto again; } else mc.mc_pg[mc.mc_top] = mp; continue; } } if (my->mc_wlen[toggle] >= MDB_WBUF) { rc = mdb_env_cthr_toggle(my, 1); if (rc) goto done; toggle = my->mc_toggle; } mo = (MDB_page *)(my->mc_wbuf[toggle] + my->mc_wlen[toggle]); mdb_page_copy(mo, mp, my->mc_env->me_psize); mo->mp_pgno = my->mc_next_pgno++; my->mc_wlen[toggle] += my->mc_env->me_psize; if (mc.mc_top) { /* Update parent if there is one */ ni = NODEPTR(mc.mc_pg[mc.mc_top-1], mc.mc_ki[mc.mc_top-1]); SETPGNO(ni, mo->mp_pgno); mdb_cursor_pop(&mc); } else { /* Otherwise we're done */ *pg = mo->mp_pgno; break; } } done: free(buf); return rc; } /** Copy environment with compaction. */ static int ESECT mdb_env_copyfd1(MDB_env *env, HANDLE fd) { MDB_meta *mm; MDB_page *mp; mdb_copy my = {0}; MDB_txn *txn = NULL; pthread_t thr; pgno_t root, new_root; int rc = MDB_SUCCESS; #ifdef _WIN32 if (!(my.mc_mutex = CreateMutex(NULL, FALSE, NULL)) || !(my.mc_cond = CreateEvent(NULL, FALSE, FALSE, NULL))) { rc = ErrCode(); goto done; } my.mc_wbuf[0] = _aligned_malloc(MDB_WBUF*2, env->me_os_psize); if (my.mc_wbuf[0] == NULL) { /* _aligned_malloc() sets errno, but we use Windows error codes */ rc = ERROR_NOT_ENOUGH_MEMORY; goto done; } #else if ((rc = pthread_mutex_init(&my.mc_mutex, NULL)) != 0) return rc; if ((rc = pthread_cond_init(&my.mc_cond, NULL)) != 0) goto done2; #ifdef HAVE_MEMALIGN my.mc_wbuf[0] = memalign(env->me_os_psize, MDB_WBUF*2); if (my.mc_wbuf[0] == NULL) { rc = errno; goto done; } #else { void *p; if ((rc = posix_memalign(&p, env->me_os_psize, MDB_WBUF*2)) != 0) goto done; my.mc_wbuf[0] = p; } #endif #endif memset(my.mc_wbuf[0], 0, MDB_WBUF*2); my.mc_wbuf[1] = my.mc_wbuf[0] + MDB_WBUF; my.mc_next_pgno = NUM_METAS; my.mc_env = env; my.mc_fd = fd; rc = THREAD_CREATE(thr, mdb_env_copythr, &my); if (rc) goto done; rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn); if (rc) goto finish; mp = (MDB_page *)my.mc_wbuf[0]; memset(mp, 0, NUM_METAS * env->me_psize); mp->mp_pgno = 0; mp->mp_flags = P_META; mm = (MDB_meta *)METADATA(mp); mdb_env_init_meta0(env, mm); mm->mm_address = env->me_metas[0]->mm_address; mp = (MDB_page *)(my.mc_wbuf[0] + env->me_psize); mp->mp_pgno = 1; mp->mp_flags = P_META; *(MDB_meta *)METADATA(mp) = *mm; mm = (MDB_meta *)METADATA(mp); /* Set metapage 1 with current main DB */ root = new_root = txn->mt_dbs[MAIN_DBI].md_root; if (root != P_INVALID) { /* Count free pages + freeDB pages. Subtract from last_pg * to find the new last_pg, which also becomes the new root. */ MDB_ID freecount = 0; MDB_cursor mc; MDB_val key, data; mdb_cursor_init(&mc, txn, FREE_DBI, NULL); while ((rc = mdb_cursor_get(&mc, &key, &data, MDB_NEXT)) == 0) freecount += *(MDB_ID *)data.mv_data; if (rc != MDB_NOTFOUND) goto finish; freecount += txn->mt_dbs[FREE_DBI].md_branch_pages + txn->mt_dbs[FREE_DBI].md_leaf_pages + txn->mt_dbs[FREE_DBI].md_overflow_pages; new_root = txn->mt_next_pgno - 1 - freecount; mm->mm_last_pg = new_root; mm->mm_dbs[MAIN_DBI] = txn->mt_dbs[MAIN_DBI]; mm->mm_dbs[MAIN_DBI].md_root = new_root; } else { /* When the DB is empty, handle it specially to * fix any breakage like page leaks from ITS#8174. */ mm->mm_dbs[MAIN_DBI].md_flags = txn->mt_dbs[MAIN_DBI].md_flags; } if (root != P_INVALID || mm->mm_dbs[MAIN_DBI].md_flags) { mm->mm_txnid = 1; /* use metapage 1 */ } my.mc_wlen[0] = env->me_psize * NUM_METAS; my.mc_txn = txn; rc = mdb_env_cwalk(&my, &root, 0); if (rc == MDB_SUCCESS && root != new_root) { rc = MDB_INCOMPATIBLE; /* page leak or corrupt DB */ } finish: if (rc) my.mc_error = rc; mdb_env_cthr_toggle(&my, 1 | MDB_EOF); rc = THREAD_FINISH(thr); mdb_txn_abort(txn); done: #ifdef _WIN32 if (my.mc_wbuf[0]) _aligned_free(my.mc_wbuf[0]); if (my.mc_cond) CloseHandle(my.mc_cond); if (my.mc_mutex) CloseHandle(my.mc_mutex); #else free(my.mc_wbuf[0]); pthread_cond_destroy(&my.mc_cond); done2: pthread_mutex_destroy(&my.mc_mutex); #endif return rc ? rc : my.mc_error; } /** Copy environment as-is. */ static int ESECT mdb_env_copyfd0(MDB_env *env, HANDLE fd) { MDB_txn *txn = NULL; mdb_mutexref_t wmutex = NULL; int rc; size_t wsize, w3; char *ptr; #ifdef _WIN32 DWORD len, w2; #define DO_WRITE(rc, fd, ptr, w2, len) rc = WriteFile(fd, ptr, w2, &len, NULL) #else ssize_t len; size_t w2; #define DO_WRITE(rc, fd, ptr, w2, len) len = write(fd, ptr, w2); rc = (len >= 0) #endif /* Do the lock/unlock of the reader mutex before starting the * write txn. Otherwise other read txns could block writers. */ rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn); if (rc) return rc; if (env->me_txns) { /* We must start the actual read txn after blocking writers */ mdb_txn_end(txn, MDB_END_RESET_TMP); /* Temporarily block writers until we snapshot the meta pages */ wmutex = env->me_wmutex; if (LOCK_MUTEX(rc, env, wmutex)) goto leave; rc = mdb_txn_renew0(txn); if (rc) { UNLOCK_MUTEX(wmutex); goto leave; } } wsize = env->me_psize * NUM_METAS; ptr = env->me_map; w2 = wsize; while (w2 > 0) { DO_WRITE(rc, fd, ptr, w2, len); if (!rc) { rc = ErrCode(); break; } else if (len > 0) { rc = MDB_SUCCESS; ptr += len; w2 -= len; continue; } else { /* Non-blocking or async handles are not supported */ rc = EIO; break; } } if (wmutex) UNLOCK_MUTEX(wmutex); if (rc) goto leave; w3 = txn->mt_next_pgno * env->me_psize; { size_t fsize = 0; if ((rc = mdb_fsize(env->me_fd, &fsize))) goto leave; if (w3 > fsize) w3 = fsize; } wsize = w3 - wsize; while (wsize > 0) { if (wsize > MAX_WRITE) w2 = MAX_WRITE; else w2 = wsize; DO_WRITE(rc, fd, ptr, w2, len); if (!rc) { rc = ErrCode(); break; } else if (len > 0) { rc = MDB_SUCCESS; ptr += len; wsize -= len; continue; } else { rc = EIO; break; } } leave: mdb_txn_abort(txn); return rc; } int ESECT mdb_env_copyfd2(MDB_env *env, HANDLE fd, unsigned int flags) { if (flags & MDB_CP_COMPACT) return mdb_env_copyfd1(env, fd); else return mdb_env_copyfd0(env, fd); } int ESECT mdb_env_copyfd(MDB_env *env, HANDLE fd) { return mdb_env_copyfd2(env, fd, 0); } int ESECT mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags) { int rc; MDB_name fname; HANDLE newfd = INVALID_HANDLE_VALUE; rc = mdb_fname_init(path, env->me_flags | MDB_NOLOCK, &fname); if (rc == MDB_SUCCESS) { rc = mdb_fopen(env, &fname, MDB_O_COPY, 0666, &newfd); mdb_fname_destroy(fname); } if (rc == MDB_SUCCESS) { rc = mdb_env_copyfd2(env, newfd, flags); if (close(newfd) < 0 && rc == MDB_SUCCESS) rc = ErrCode(); } return rc; } int ESECT mdb_env_copy(MDB_env *env, const char *path) { return mdb_env_copy2(env, path, 0); } int ESECT mdb_env_set_flags(MDB_env *env, unsigned int flag, int onoff) { if (flag & ~CHANGEABLE) return EINVAL; if (onoff) env->me_flags |= flag; else env->me_flags &= ~flag; return MDB_SUCCESS; } int ESECT mdb_env_get_flags(MDB_env *env, unsigned int *arg) { if (!env || !arg) return EINVAL; *arg = env->me_flags & (CHANGEABLE|CHANGELESS); return MDB_SUCCESS; } int ESECT mdb_env_set_userctx(MDB_env *env, void *ctx) { if (!env) return EINVAL; env->me_userctx = ctx; return MDB_SUCCESS; } void * ESECT mdb_env_get_userctx(MDB_env *env) { return env ? env->me_userctx : NULL; } int ESECT mdb_env_set_assert(MDB_env *env, MDB_assert_func *func) { if (!env) return EINVAL; #ifndef NDEBUG env->me_assert_func = func; #endif return MDB_SUCCESS; } int ESECT mdb_env_get_path(MDB_env *env, const char **arg) { if (!env || !arg) return EINVAL; *arg = env->me_path; return MDB_SUCCESS; } int ESECT mdb_env_get_fd(MDB_env *env, mdb_filehandle_t *arg) { if (!env || !arg) return EINVAL; *arg = env->me_fd; return MDB_SUCCESS; } /** Common code for #mdb_stat() and #mdb_env_stat(). * @param[in] env the environment to operate in. * @param[in] db the #MDB_db record containing the stats to return. * @param[out] arg the address of an #MDB_stat structure to receive the stats. * @return 0, this function always succeeds. */ static int ESECT mdb_stat0(MDB_env *env, MDB_db *db, MDB_stat *arg) { arg->ms_psize = env->me_psize; arg->ms_depth = db->md_depth; arg->ms_branch_pages = db->md_branch_pages; arg->ms_leaf_pages = db->md_leaf_pages; arg->ms_overflow_pages = db->md_overflow_pages; arg->ms_entries = db->md_entries; return MDB_SUCCESS; } int ESECT mdb_env_stat(MDB_env *env, MDB_stat *arg) { MDB_meta *meta; if (env == NULL || arg == NULL) return EINVAL; meta = mdb_env_pick_meta(env); return mdb_stat0(env, &meta->mm_dbs[MAIN_DBI], arg); } int ESECT mdb_env_info(MDB_env *env, MDB_envinfo *arg) { MDB_meta *meta; if (env == NULL || arg == NULL) return EINVAL; meta = mdb_env_pick_meta(env); arg->me_mapaddr = meta->mm_address; arg->me_last_pgno = meta->mm_last_pg; arg->me_last_txnid = meta->mm_txnid; arg->me_mapsize = env->me_mapsize; arg->me_maxreaders = env->me_maxreaders; arg->me_numreaders = env->me_txns ? env->me_txns->mti_numreaders : 0; return MDB_SUCCESS; } /** Set the default comparison functions for a database. * Called immediately after a database is opened to set the defaults. * The user can then override them with #mdb_set_compare() or * #mdb_set_dupsort(). * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] dbi A database handle returned by #mdb_dbi_open() */ static void mdb_default_cmp(MDB_txn *txn, MDB_dbi dbi) { uint16_t f = txn->mt_dbs[dbi].md_flags; txn->mt_dbxs[dbi].md_cmp = (f & MDB_REVERSEKEY) ? mdb_cmp_memnr : (f & MDB_INTEGERKEY) ? mdb_cmp_cint : mdb_cmp_memn; txn->mt_dbxs[dbi].md_dcmp = !(f & MDB_DUPSORT) ? 0 : ((f & MDB_INTEGERDUP) ? ((f & MDB_DUPFIXED) ? mdb_cmp_int : mdb_cmp_cint) : ((f & MDB_REVERSEDUP) ? mdb_cmp_memnr : mdb_cmp_memn)); } int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *dbi) { MDB_val key, data; MDB_dbi i; MDB_cursor mc; MDB_db dummy; int rc, dbflag, exact; unsigned int unused = 0, seq; char *namedup; size_t len; if (flags & ~VALID_FLAGS) return EINVAL; if (txn->mt_flags & MDB_TXN_BLOCKED) return MDB_BAD_TXN; /* main DB? */ if (!name) { *dbi = MAIN_DBI; if (flags & PERSISTENT_FLAGS) { uint16_t f2 = flags & PERSISTENT_FLAGS; /* make sure flag changes get committed */ if ((txn->mt_dbs[MAIN_DBI].md_flags | f2) != txn->mt_dbs[MAIN_DBI].md_flags) { txn->mt_dbs[MAIN_DBI].md_flags |= f2; txn->mt_flags |= MDB_TXN_DIRTY; } } mdb_default_cmp(txn, MAIN_DBI); return MDB_SUCCESS; } if (txn->mt_dbxs[MAIN_DBI].md_cmp == NULL) { mdb_default_cmp(txn, MAIN_DBI); } /* Is the DB already open? */ len = strlen(name); for (i=CORE_DBS; imt_numdbs; i++) { if (!txn->mt_dbxs[i].md_name.mv_size) { /* Remember this free slot */ if (!unused) unused = i; continue; } if (len == txn->mt_dbxs[i].md_name.mv_size && !strncmp(name, txn->mt_dbxs[i].md_name.mv_data, len)) { *dbi = i; return MDB_SUCCESS; } } /* If no free slot and max hit, fail */ if (!unused && txn->mt_numdbs >= txn->mt_env->me_maxdbs) return MDB_DBS_FULL; /* Cannot mix named databases with some mainDB flags */ if (txn->mt_dbs[MAIN_DBI].md_flags & (MDB_DUPSORT|MDB_INTEGERKEY)) return (flags & MDB_CREATE) ? MDB_INCOMPATIBLE : MDB_NOTFOUND; /* Find the DB info */ dbflag = DB_NEW|DB_VALID|DB_USRVALID; exact = 0; key.mv_size = len; key.mv_data = (void *)name; mdb_cursor_init(&mc, txn, MAIN_DBI, NULL); rc = mdb_cursor_set(&mc, &key, &data, MDB_SET, &exact); if (rc == MDB_SUCCESS) { /* make sure this is actually a DB */ MDB_node *node = NODEPTR(mc.mc_pg[mc.mc_top], mc.mc_ki[mc.mc_top]); if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) != F_SUBDATA) return MDB_INCOMPATIBLE; } else { if (rc != MDB_NOTFOUND || !(flags & MDB_CREATE)) return rc; if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) return EACCES; } /* Done here so we cannot fail after creating a new DB */ if ((namedup = strdup(name)) == NULL) return ENOMEM; if (rc) { /* MDB_NOTFOUND and MDB_CREATE: Create new DB */ data.mv_size = sizeof(MDB_db); data.mv_data = &dummy; memset(&dummy, 0, sizeof(dummy)); dummy.md_root = P_INVALID; dummy.md_flags = flags & PERSISTENT_FLAGS; WITH_CURSOR_TRACKING(mc, rc = mdb_cursor_put(&mc, &key, &data, F_SUBDATA)); dbflag |= DB_DIRTY; } if (rc) { free(namedup); } else { /* Got info, register DBI in this txn */ unsigned int slot = unused ? unused : txn->mt_numdbs; txn->mt_dbxs[slot].md_name.mv_data = namedup; txn->mt_dbxs[slot].md_name.mv_size = len; txn->mt_dbxs[slot].md_rel = NULL; txn->mt_dbflags[slot] = dbflag; /* txn-> and env-> are the same in read txns, use * tmp variable to avoid undefined assignment */ seq = ++txn->mt_env->me_dbiseqs[slot]; txn->mt_dbiseqs[slot] = seq; memcpy(&txn->mt_dbs[slot], data.mv_data, sizeof(MDB_db)); *dbi = slot; mdb_default_cmp(txn, slot); if (!unused) { txn->mt_numdbs++; } } return rc; } int ESECT mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *arg) { if (!arg || !TXN_DBI_EXIST(txn, dbi, DB_VALID)) return EINVAL; if (txn->mt_flags & MDB_TXN_BLOCKED) return MDB_BAD_TXN; if (txn->mt_dbflags[dbi] & DB_STALE) { MDB_cursor mc; MDB_xcursor mx; /* Stale, must read the DB's root. cursor_init does it for us. */ mdb_cursor_init(&mc, txn, dbi, &mx); } return mdb_stat0(txn->mt_env, &txn->mt_dbs[dbi], arg); } void mdb_dbi_close(MDB_env *env, MDB_dbi dbi) { char *ptr; if (dbi < CORE_DBS || dbi >= env->me_maxdbs) return; ptr = env->me_dbxs[dbi].md_name.mv_data; /* If there was no name, this was already closed */ if (ptr) { env->me_dbxs[dbi].md_name.mv_data = NULL; env->me_dbxs[dbi].md_name.mv_size = 0; env->me_dbflags[dbi] = 0; env->me_dbiseqs[dbi]++; free(ptr); } } int mdb_dbi_flags(MDB_txn *txn, MDB_dbi dbi, unsigned int *flags) { /* We could return the flags for the FREE_DBI too but what's the point? */ if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) return EINVAL; *flags = txn->mt_dbs[dbi].md_flags & PERSISTENT_FLAGS; return MDB_SUCCESS; } /** Add all the DB's pages to the free list. * @param[in] mc Cursor on the DB to free. * @param[in] subs non-Zero to check for sub-DBs in this DB. * @return 0 on success, non-zero on failure. */ static int mdb_drop0(MDB_cursor *mc, int subs) { int rc; rc = mdb_page_search(mc, NULL, MDB_PS_FIRST); if (rc == MDB_SUCCESS) { MDB_txn *txn = mc->mc_txn; MDB_node *ni; MDB_cursor mx; unsigned int i; /* DUPSORT sub-DBs have no ovpages/DBs. Omit scanning leaves. * This also avoids any P_LEAF2 pages, which have no nodes. * Also if the DB doesn't have sub-DBs and has no overflow * pages, omit scanning leaves. */ if ((mc->mc_flags & C_SUB) || (!subs && !mc->mc_db->md_overflow_pages)) mdb_cursor_pop(mc); mdb_cursor_copy(mc, &mx); while (mc->mc_snum > 0) { MDB_page *mp = mc->mc_pg[mc->mc_top]; unsigned n = NUMKEYS(mp); if (IS_LEAF(mp)) { for (i=0; imn_flags & F_BIGDATA) { MDB_page *omp; pgno_t pg; memcpy(&pg, NODEDATA(ni), sizeof(pg)); rc = mdb_page_get(mc, pg, &omp, NULL); if (rc != 0) goto done; mdb_cassert(mc, IS_OVERFLOW(omp)); rc = mdb_midl_append_range(&txn->mt_free_pgs, pg, omp->mp_pages); if (rc) goto done; mc->mc_db->md_overflow_pages -= omp->mp_pages; if (!mc->mc_db->md_overflow_pages && !subs) break; } else if (subs && (ni->mn_flags & F_SUBDATA)) { mdb_xcursor_init1(mc, ni); rc = mdb_drop0(&mc->mc_xcursor->mx_cursor, 0); if (rc) goto done; } } if (!subs && !mc->mc_db->md_overflow_pages) goto pop; } else { if ((rc = mdb_midl_need(&txn->mt_free_pgs, n)) != 0) goto done; for (i=0; imt_free_pgs, pg); } } if (!mc->mc_top) break; mc->mc_ki[mc->mc_top] = i; rc = mdb_cursor_sibling(mc, 1); if (rc) { if (rc != MDB_NOTFOUND) goto done; /* no more siblings, go back to beginning * of previous level. */ pop: mdb_cursor_pop(mc); mc->mc_ki[0] = 0; for (i=1; imc_snum; i++) { mc->mc_ki[i] = 0; mc->mc_pg[i] = mx.mc_pg[i]; } } } /* free it */ rc = mdb_midl_append(&txn->mt_free_pgs, mc->mc_db->md_root); done: if (rc) txn->mt_flags |= MDB_TXN_ERROR; } else if (rc == MDB_NOTFOUND) { rc = MDB_SUCCESS; } mc->mc_flags &= ~C_INITIALIZED; return rc; } int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del) { MDB_cursor *mc, *m2; int rc; if ((unsigned)del > 1 || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) return EINVAL; if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) return EACCES; if (TXN_DBI_CHANGED(txn, dbi)) return MDB_BAD_DBI; rc = mdb_cursor_open(txn, dbi, &mc); if (rc) return rc; rc = mdb_drop0(mc, mc->mc_db->md_flags & MDB_DUPSORT); /* Invalidate the dropped DB's cursors */ for (m2 = txn->mt_cursors[dbi]; m2; m2 = m2->mc_next) m2->mc_flags &= ~(C_INITIALIZED|C_EOF); if (rc) goto leave; /* Can't delete the main DB */ if (del && dbi >= CORE_DBS) { rc = mdb_del0(txn, MAIN_DBI, &mc->mc_dbx->md_name, NULL, F_SUBDATA); if (!rc) { txn->mt_dbflags[dbi] = DB_STALE; mdb_dbi_close(txn->mt_env, dbi); } else { txn->mt_flags |= MDB_TXN_ERROR; } } else { /* reset the DB record, mark it dirty */ txn->mt_dbflags[dbi] |= DB_DIRTY; txn->mt_dbs[dbi].md_depth = 0; txn->mt_dbs[dbi].md_branch_pages = 0; txn->mt_dbs[dbi].md_leaf_pages = 0; txn->mt_dbs[dbi].md_overflow_pages = 0; txn->mt_dbs[dbi].md_entries = 0; txn->mt_dbs[dbi].md_root = P_INVALID; txn->mt_flags |= MDB_TXN_DIRTY; } leave: mdb_cursor_close(mc); return rc; } int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp) { if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) return EINVAL; txn->mt_dbxs[dbi].md_cmp = cmp; return MDB_SUCCESS; } int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp) { if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) return EINVAL; txn->mt_dbxs[dbi].md_dcmp = cmp; return MDB_SUCCESS; } int mdb_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel) { if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) return EINVAL; txn->mt_dbxs[dbi].md_rel = rel; return MDB_SUCCESS; } int mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx) { if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) return EINVAL; txn->mt_dbxs[dbi].md_relctx = ctx; return MDB_SUCCESS; } int ESECT mdb_env_get_maxkeysize(MDB_env *env) { return ENV_MAXKEY(env); } int ESECT mdb_reader_list(MDB_env *env, MDB_msg_func *func, void *ctx) { unsigned int i, rdrs; MDB_reader *mr; char buf[64]; int rc = 0, first = 1; if (!env || !func) return -1; if (!env->me_txns) { return func("(no reader locks)\n", ctx); } rdrs = env->me_txns->mti_numreaders; mr = env->me_txns->mti_readers; for (i=0; i> 1; cursor = base + pivot + 1; val = pid - ids[cursor]; if( val < 0 ) { n = pivot; } else if ( val > 0 ) { base = cursor; n -= pivot + 1; } else { /* found, so it's a duplicate */ return -1; } } if( val > 0 ) { ++cursor; } ids[0]++; for (n = ids[0]; n > cursor; n--) ids[n] = ids[n-1]; ids[n] = pid; return 0; } int ESECT mdb_reader_check(MDB_env *env, int *dead) { if (!env) return EINVAL; if (dead) *dead = 0; return env->me_txns ? mdb_reader_check0(env, 0, dead) : MDB_SUCCESS; } /** As #mdb_reader_check(). \b rlocked is set if caller locked #me_rmutex. */ static int ESECT mdb_reader_check0(MDB_env *env, int rlocked, int *dead) { mdb_mutexref_t rmutex = rlocked ? NULL : env->me_rmutex; unsigned int i, j, rdrs; MDB_reader *mr; MDB_PID_T *pids, pid; int rc = MDB_SUCCESS, count = 0; rdrs = env->me_txns->mti_numreaders; pids = malloc((rdrs+1) * sizeof(MDB_PID_T)); if (!pids) return ENOMEM; pids[0] = 0; mr = env->me_txns->mti_readers; for (i=0; ime_pid) { if (mdb_pid_insert(pids, pid) == 0) { if (!mdb_reader_pid(env, Pidcheck, pid)) { /* Stale reader found */ j = i; if (rmutex) { if ((rc = LOCK_MUTEX0(rmutex)) != 0) { if ((rc = mdb_mutex_failed(env, rmutex, rc))) break; rdrs = 0; /* the above checked all readers */ } else { /* Recheck, a new process may have reused pid */ if (mdb_reader_pid(env, Pidcheck, pid)) j = rdrs; } } for (; jme_rmutex); if (!rlocked) { /* Keep mti_txnid updated, otherwise next writer can * overwrite data which latest meta page refers to. */ meta = mdb_env_pick_meta(env); env->me_txns->mti_txnid = meta->mm_txnid; /* env is hosed if the dead thread was ours */ if (env->me_txn) { env->me_flags |= MDB_FATAL_ERROR; env->me_txn = NULL; rc = MDB_PANIC; } } DPRINTF(("%cmutex owner died, %s", (rlocked ? 'r' : 'w'), (rc ? "this process' env is hosed" : "recovering"))); rc2 = mdb_reader_check0(env, rlocked, NULL); if (rc2 == 0) rc2 = mdb_mutex_consistent(mutex); if (rc || (rc = rc2)) { DPRINTF(("LOCK_MUTEX recovery failed, %s", mdb_strerror(rc))); UNLOCK_MUTEX(mutex); } } else { #ifdef _WIN32 rc = ErrCode(); #endif DPRINTF(("LOCK_MUTEX failed, %s", mdb_strerror(rc))); } return rc; } #endif /* MDB_ROBUST_SUPPORTED */ #if defined(_WIN32) /** Convert \b src to new wchar_t[] string with room for \b xtra extra chars */ static int ESECT utf8_to_utf16(const char *src, MDB_name *dst, int xtra) { int rc, need = 0; wchar_t *result = NULL; for (;;) { /* malloc result, then fill it in */ need = MultiByteToWideChar(CP_UTF8, 0, src, -1, result, need); if (!need) { rc = ErrCode(); free(result); return rc; } if (!result) { result = malloc(sizeof(wchar_t) * (need + xtra)); if (!result) return ENOMEM; continue; } dst->mn_alloced = 1; dst->mn_len = need - 1; dst->mn_val = result; return MDB_SUCCESS; } } #endif /* defined(_WIN32) */ /** @} */ openldap-2.5.11+dfsg/libraries/liblmdb/sample-bdb.txt0000644000175000017500000000374414172327167021177 0ustar ryanryan/* sample-bdb.txt - BerkeleyDB toy/sample * * Do a line-by-line comparison of this and sample-mdb.txt */ /* * Copyright 2012-2021 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include #include #include int main(int argc,char * argv[]) { int rc; DB_ENV *env; DB *dbi; DBT key, data; DB_TXN *txn; DBC *cursor; char sval[32], kval[32]; /* Note: Most error checking omitted for simplicity */ #define FLAGS (DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_INIT_MPOOL|DB_CREATE|DB_THREAD) rc = db_env_create(&env, 0); rc = env->open(env, "./testdb", FLAGS, 0664); rc = db_create(&dbi, env, 0); rc = env->txn_begin(env, NULL, &txn, 0); rc = dbi->open(dbi, txn, "test.bdb", NULL, DB_BTREE, DB_CREATE, 0664); memset(&key, 0, sizeof(DBT)); memset(&data, 0, sizeof(DBT)); key.size = sizeof(int); key.data = sval; data.size = sizeof(sval); data.data = sval; sprintf(sval, "%03x %d foo bar", 32, 3141592); rc = dbi->put(dbi, txn, &key, &data, 0); rc = txn->commit(txn, 0); if (rc) { fprintf(stderr, "txn->commit: (%d) %s\n", rc, db_strerror(rc)); goto leave; } rc = env->txn_begin(env, NULL, &txn, 0); rc = dbi->cursor(dbi, txn, &cursor, 0); key.flags = DB_DBT_USERMEM; key.data = kval; key.ulen = sizeof(kval); data.flags = DB_DBT_USERMEM; data.data = sval; data.ulen = sizeof(sval); while ((rc = cursor->c_get(cursor, &key, &data, DB_NEXT)) == 0) { printf("key: %p %.*s, data: %p %.*s\n", key.data, (int) key.size, (char *) key.data, data.data, (int) data.size, (char *) data.data); } rc = cursor->c_close(cursor); rc = txn->abort(txn); leave: rc = dbi->close(dbi, 0); rc = env->close(env, 0); return rc; } openldap-2.5.11+dfsg/libraries/liblmdb/mtest3.c0000644000175000017500000000717014172327167020010 0ustar ryanryan/* mtest3.c - memory-mapped database tester/toy */ /* * Copyright 2011-2021 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Tests for sorted duplicate DBs */ #include #include #include #include #include "lmdb.h" #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) int main(int argc,char * argv[]) { int i = 0, j = 0, rc; MDB_env *env; MDB_dbi dbi; MDB_val key, data; MDB_txn *txn; MDB_stat mst; MDB_cursor *cursor; int count; int *values; char sval[32]; char kval[sizeof(int)]; srand(time(NULL)); memset(sval, 0, sizeof(sval)); count = (rand()%384) + 64; values = (int *)malloc(count*sizeof(int)); for(i = 0;i -1; i-= (rand()%5)) { j++; txn=NULL; E(mdb_txn_begin(env, NULL, 0, &txn)); sprintf(kval, "%03x", values[i & ~0x0f]); sprintf(sval, "%03x %d foo bar", values[i], values[i]); key.mv_size = sizeof(int); key.mv_data = kval; data.mv_size = sizeof(sval); data.mv_data = sval; if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) { j--; mdb_txn_abort(txn); } else { E(mdb_txn_commit(txn)); } } free(values); printf("Deleted %d values\n", j); E(mdb_env_stat(env, &mst)); E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); E(mdb_cursor_open(txn, dbi, &cursor)); printf("Cursor next\n"); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { printf("key: %.*s, data: %.*s\n", (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); } CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); printf("Cursor prev\n"); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { printf("key: %.*s, data: %.*s\n", (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); } CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); mdb_cursor_close(cursor); mdb_txn_abort(txn); mdb_dbi_close(env, dbi); mdb_env_close(env); return 0; } openldap-2.5.11+dfsg/libraries/liblmdb/mtest.c0000644000175000017500000001266014172327167017725 0ustar ryanryan/* mtest.c - memory-mapped database tester/toy */ /* * Copyright 2011-2021 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include #include #include #include "lmdb.h" #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) int main(int argc,char * argv[]) { int i = 0, j = 0, rc; MDB_env *env; MDB_dbi dbi; MDB_val key, data; MDB_txn *txn; MDB_stat mst; MDB_cursor *cursor, *cur2; MDB_cursor_op op; int count; int *values; char sval[32] = ""; srand(time(NULL)); count = (rand()%384) + 64; values = (int *)malloc(count*sizeof(int)); for(i = 0;i in each iteration, since MDB_NOOVERWRITE may modify it */ data.mv_size = sizeof(sval); data.mv_data = sval; if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE))) { j++; data.mv_size = sizeof(sval); data.mv_data = sval; } } if (j) printf("%d duplicates skipped\n", j); E(mdb_txn_commit(txn)); E(mdb_env_stat(env, &mst)); E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); E(mdb_cursor_open(txn, dbi, &cursor)); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { printf("key: %p %.*s, data: %p %.*s\n", key.mv_data, (int) key.mv_size, (char *) key.mv_data, data.mv_data, (int) data.mv_size, (char *) data.mv_data); } CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); mdb_cursor_close(cursor); mdb_txn_abort(txn); j=0; key.mv_data = sval; for (i= count - 1; i > -1; i-= (rand()%5)) { j++; txn=NULL; E(mdb_txn_begin(env, NULL, 0, &txn)); sprintf(sval, "%03x ", values[i]); if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, NULL))) { j--; mdb_txn_abort(txn); } else { E(mdb_txn_commit(txn)); } } free(values); printf("Deleted %d values\n", j); E(mdb_env_stat(env, &mst)); E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); E(mdb_cursor_open(txn, dbi, &cursor)); printf("Cursor next\n"); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { printf("key: %.*s, data: %.*s\n", (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); } CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); printf("Cursor last\n"); E(mdb_cursor_get(cursor, &key, &data, MDB_LAST)); printf("key: %.*s, data: %.*s\n", (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); printf("Cursor prev\n"); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { printf("key: %.*s, data: %.*s\n", (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); } CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); printf("Cursor last/prev\n"); E(mdb_cursor_get(cursor, &key, &data, MDB_LAST)); printf("key: %.*s, data: %.*s\n", (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); E(mdb_cursor_get(cursor, &key, &data, MDB_PREV)); printf("key: %.*s, data: %.*s\n", (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); mdb_cursor_close(cursor); mdb_txn_abort(txn); printf("Deleting with cursor\n"); E(mdb_txn_begin(env, NULL, 0, &txn)); E(mdb_cursor_open(txn, dbi, &cur2)); for (i=0; i<50; i++) { if (RES(MDB_NOTFOUND, mdb_cursor_get(cur2, &key, &data, MDB_NEXT))) break; printf("key: %p %.*s, data: %p %.*s\n", key.mv_data, (int) key.mv_size, (char *) key.mv_data, data.mv_data, (int) data.mv_size, (char *) data.mv_data); E(mdb_del(txn, dbi, &key, NULL)); } printf("Restarting cursor in txn\n"); for (op=MDB_FIRST, i=0; i<=32; op=MDB_NEXT, i++) { if (RES(MDB_NOTFOUND, mdb_cursor_get(cur2, &key, &data, op))) break; printf("key: %p %.*s, data: %p %.*s\n", key.mv_data, (int) key.mv_size, (char *) key.mv_data, data.mv_data, (int) data.mv_size, (char *) data.mv_data); } mdb_cursor_close(cur2); E(mdb_txn_commit(txn)); printf("Restarting cursor outside txn\n"); E(mdb_txn_begin(env, NULL, 0, &txn)); E(mdb_cursor_open(txn, dbi, &cursor)); for (op=MDB_FIRST, i=0; i<=32; op=MDB_NEXT, i++) { if (RES(MDB_NOTFOUND, mdb_cursor_get(cursor, &key, &data, op))) break; printf("key: %p %.*s, data: %p %.*s\n", key.mv_data, (int) key.mv_size, (char *) key.mv_data, data.mv_data, (int) data.mv_size, (char *) data.mv_data); } mdb_cursor_close(cursor); mdb_txn_abort(txn); mdb_dbi_close(env, dbi); mdb_env_close(env); return 0; } openldap-2.5.11+dfsg/libraries/liblmdb/mdb_dump.10000644000175000017500000000422514172327167020274 0ustar ryanryan.TH MDB_DUMP 1 "2015/09/30" "LMDB 0.9.17" .\" Copyright 2014-2021 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME mdb_dump \- LMDB environment export tool .SH SYNOPSIS .B mdb_dump [\c .BR \-V ] [\c .BI \-f \ file\fR] [\c .BR \-l ] [\c .BR \-n ] [\c .BR \-p ] [\c .BR \-a \ | .BI \-s \ subdb\fR] .BR \ envpath .SH DESCRIPTION The .B mdb_dump utility reads a database and writes its contents to the standard output using a portable flat-text format understood by the .BR mdb_load (1) utility. .SH OPTIONS .TP .BR \-V Write the library version number to the standard output, and exit. .TP .BR \-f \ file Write to the specified file instead of to the standard output. .TP .BR \-l List the databases stored in the environment. Just the names will be listed, no data will be output. .TP .BR \-n Dump an LMDB database which does not use subdirectories. .TP .BR \-p If characters in either the key or data items are printing characters (as defined by isprint(3)), output them directly. This option permits users to use standard text editors and tools to modify the contents of databases. Note: different systems may have different notions about what characters are considered printing characters, and databases dumped in this manner may be less portable to external systems. .TP .BR \-a Dump all of the subdatabases in the environment. .TP .BR \-s \ subdb Dump a specific subdatabase. If no database is specified, only the main database is dumped. .SH DIAGNOSTICS Exit status is zero if no errors occur. Errors result in a non-zero exit status and a diagnostic message being written to standard error. Dumping and reloading databases that use user-defined comparison functions will result in new databases that use the default comparison functions. \fBIn this case it is quite likely that the reloaded database will be damaged beyond repair permitting neither record storage nor retrieval.\fP The only available workaround is to modify the source for the .BR mdb_load (1) utility to load the database using the correct comparison functions. .SH "SEE ALSO" .BR mdb_load (1) .SH AUTHOR Howard Chu of Symas Corporation openldap-2.5.11+dfsg/libraries/liblmdb/intro.doc0000644000175000017500000002046714172327167020253 0ustar ryanryan/* * Copyright 2015-2021 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /** @page starting Getting Started LMDB is compact, fast, powerful, and robust and implements a simplified variant of the BerkeleyDB (BDB) API. (BDB is also very powerful, and verbosely documented in its own right.) After reading this page, the main \ref mdb documentation should make sense. Thanks to Bert Hubert for creating the initial version of this writeup. Everything starts with an environment, created by #mdb_env_create(). Once created, this environment must also be opened with #mdb_env_open(). #mdb_env_open() gets passed a name which is interpreted as a directory path. Note that this directory must exist already, it is not created for you. Within that directory, a lock file and a storage file will be generated. If you don't want to use a directory, you can pass the #MDB_NOSUBDIR option, in which case the path you provided is used directly as the data file, and another file with a "-lock" suffix added will be used for the lock file. Once the environment is open, a transaction can be created within it using #mdb_txn_begin(). Transactions may be read-write or read-only, and read-write transactions may be nested. A transaction must only be used by one thread at a time. Transactions are always required, even for read-only access. The transaction provides a consistent view of the data. Once a transaction has been created, a database can be opened within it using #mdb_dbi_open(). If only one database will ever be used in the environment, a NULL can be passed as the database name. For named databases, the #MDB_CREATE flag must be used to create the database if it doesn't already exist. Also, #mdb_env_set_maxdbs() must be called after #mdb_env_create() and before #mdb_env_open() to set the maximum number of named databases you want to support. Note: a single transaction can open multiple databases. Generally databases should only be opened once, by the first transaction in the process. After the first transaction completes, the database handles can freely be used by all subsequent transactions. Within a transaction, #mdb_get() and #mdb_put() can store single key/value pairs if that is all you need to do (but see \ref Cursors below if you want to do more). A key/value pair is expressed as two #MDB_val structures. This struct has two fields, \c mv_size and \c mv_data. The data is a \c void pointer to an array of \c mv_size bytes. Because LMDB is very efficient (and usually zero-copy), the data returned in an #MDB_val structure may be memory-mapped straight from disk. In other words look but do not touch (or free() for that matter). Once a transaction is closed, the values can no longer be used, so make a copy if you need to keep them after that. @section Cursors Cursors To do more powerful things, we must use a cursor. Within the transaction, a cursor can be created with #mdb_cursor_open(). With this cursor we can store/retrieve/delete (multiple) values using #mdb_cursor_get(), #mdb_cursor_put(), and #mdb_cursor_del(). #mdb_cursor_get() positions itself depending on the cursor operation requested, and for some operations, on the supplied key. For example, to list all key/value pairs in a database, use operation #MDB_FIRST for the first call to #mdb_cursor_get(), and #MDB_NEXT on subsequent calls, until the end is hit. To retrieve all keys starting from a specified key value, use #MDB_SET. For more cursor operations, see the \ref mdb docs. When using #mdb_cursor_put(), either the function will position the cursor for you based on the \b key, or you can use operation #MDB_CURRENT to use the current position of the cursor. Note that \b key must then match the current position's key. @subsection summary Summarizing the Opening So we have a cursor in a transaction which opened a database in an environment which is opened from a filesystem after it was separately created. Or, we create an environment, open it from a filesystem, create a transaction within it, open a database within that transaction, and create a cursor within all of the above. Got it? @section thrproc Threads and Processes LMDB uses POSIX locks on files, and these locks have issues if one process opens a file multiple times. Because of this, do not #mdb_env_open() a file multiple times from a single process. Instead, share the LMDB environment that has opened the file across all threads. Otherwise, if a single process opens the same environment multiple times, closing it once will remove all the locks held on it, and the other instances will be vulnerable to corruption from other processes. Also note that a transaction is tied to one thread by default using Thread Local Storage. If you want to pass read-only transactions across threads, you can use the #MDB_NOTLS option on the environment. @section txns Transactions, Rollbacks, etc. To actually get anything done, a transaction must be committed using #mdb_txn_commit(). Alternatively, all of a transaction's operations can be discarded using #mdb_txn_abort(). In a read-only transaction, any cursors will \b not automatically be freed. In a read-write transaction, all cursors will be freed and must not be used again. For read-only transactions, obviously there is nothing to commit to storage. The transaction still must eventually be aborted to close any database handle(s) opened in it, or committed to keep the database handles around for reuse in new transactions. In addition, as long as a transaction is open, a consistent view of the database is kept alive, which requires storage. A read-only transaction that no longer requires this consistent view should be terminated (committed or aborted) when the view is no longer needed (but see below for an optimization). There can be multiple simultaneously active read-only transactions but only one that can write. Once a single read-write transaction is opened, all further attempts to begin one will block until the first one is committed or aborted. This has no effect on read-only transactions, however, and they may continue to be opened at any time. @section dupkeys Duplicate Keys #mdb_get() and #mdb_put() respectively have no and only some support for multiple key/value pairs with identical keys. If there are multiple values for a key, #mdb_get() will only return the first value. When multiple values for one key are required, pass the #MDB_DUPSORT flag to #mdb_dbi_open(). In an #MDB_DUPSORT database, by default #mdb_put() will not replace the value for a key if the key existed already. Instead it will add the new value to the key. In addition, #mdb_del() will pay attention to the value field too, allowing for specific values of a key to be deleted. Finally, additional cursor operations become available for traversing through and retrieving duplicate values. @section optim Some Optimization If you frequently begin and abort read-only transactions, as an optimization, it is possible to only reset and renew a transaction. #mdb_txn_reset() releases any old copies of data kept around for a read-only transaction. To reuse this reset transaction, call #mdb_txn_renew() on it. Any cursors in this transaction must also be renewed using #mdb_cursor_renew(). Note that #mdb_txn_reset() is similar to #mdb_txn_abort() and will close any databases you opened within the transaction. To permanently free a transaction, reset or not, use #mdb_txn_abort(). @section cleanup Cleaning Up For read-only transactions, any cursors created within it must be closed using #mdb_cursor_close(). It is very rarely necessary to close a database handle, and in general they should just be left open. @section onward The Full API The full \ref mdb documentation lists further details, like how to: \li size a database (the default limits are intentionally small) \li drop and clean a database \li detect and report errors \li optimize (bulk) loading speed \li (temporarily) reduce robustness to gain even more speed \li gather statistics about the database \li define custom sort orders */ openldap-2.5.11+dfsg/libraries/liblmdb/mtest4.c0000644000175000017500000001126714172327167020013 0ustar ryanryan/* mtest4.c - memory-mapped database tester/toy */ /* * Copyright 2011-2021 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Tests for sorted duplicate DBs with fixed-size keys */ #include #include #include #include #include "lmdb.h" #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) int main(int argc,char * argv[]) { int i = 0, j = 0, rc; MDB_env *env; MDB_dbi dbi; MDB_val key, data; MDB_txn *txn; MDB_stat mst; MDB_cursor *cursor; int count; int *values; char sval[8]; char kval[sizeof(int)]; memset(sval, 0, sizeof(sval)); count = 510; values = (int *)malloc(count*sizeof(int)); for(i = 0;i -1; i-= (rand()%3)) { j++; txn=NULL; E(mdb_txn_begin(env, NULL, 0, &txn)); sprintf(sval, "%07x", values[i]); key.mv_size = sizeof(int); key.mv_data = kval; data.mv_size = sizeof(sval); data.mv_data = sval; if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) { j--; mdb_txn_abort(txn); } else { E(mdb_txn_commit(txn)); } } free(values); printf("Deleted %d values\n", j); E(mdb_env_stat(env, &mst)); E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); E(mdb_cursor_open(txn, dbi, &cursor)); printf("Cursor next\n"); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { printf("key: %.*s, data: %.*s\n", (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); } CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); printf("Cursor prev\n"); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { printf("key: %.*s, data: %.*s\n", (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); } CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); mdb_cursor_close(cursor); mdb_txn_abort(txn); mdb_dbi_close(env, dbi); mdb_env_close(env); return 0; } openldap-2.5.11+dfsg/libraries/liblmdb/Doxyfile0000644000175000017500000020463314172327167020136 0ustar ryanryan# Doxyfile 1.7.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = LMDB # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this # tag. The format is ext=language, where ext is a file extension, and language # is one of the parsers supported by doxygen: IDL, Java, JavaScript, CSharp, C, # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = YES # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES INLINE_GROUPED_CLASSES = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = YES # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penality. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will rougly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = NO # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. The create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = lmdb.h midl.h mdb.c midl.c intro.doc # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the stylesheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANSPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using JavaScript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvances is that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = YES # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = DEBUG=2 __GNUC__=1 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = tooltag=./man1 # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = FreeSans.ttf # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = YES # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES openldap-2.5.11+dfsg/libraries/liblmdb/LICENSE0000644000175000017500000000424614172327167017433 0ustar ryanryanThe OpenLDAP Public License Version 2.8, 17 August 2003 Redistribution and use of this software and associated documentation ("Software"), with or without modification, are permitted provided that the following conditions are met: 1. Redistributions in source form must retain copyright statements and notices, 2. Redistributions in binary form must reproduce applicable copyright statements and notices, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution, and 3. Redistributions must contain a verbatim copy of this document. The OpenLDAP Foundation may revise this license from time to time. Each revision is distinguished by a version number. You may use this Software under terms of this license revision or under the terms of any subsequent revision of the license. THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED 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 OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S) OR OWNER(S) OF THE SOFTWARE 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. The names of the authors and copyright holders must not be used in advertising or otherwise to promote the sale, use or other dealing in this Software without specific, written prior permission. Title to copyright in this Software shall at all times remain with copyright holders. OpenLDAP is a registered trademark of the OpenLDAP Foundation. Copyright 1999-2003 The OpenLDAP Foundation, Redwood City, California, USA. All Rights Reserved. Permission to copy and distribute verbatim copies of this document is granted. openldap-2.5.11+dfsg/libraries/liblmdb/mdb_copy.10000644000175000017500000000277514172327167020311 0ustar ryanryan.TH MDB_COPY 1 "2014/07/01" "LMDB 0.9.14" .\" Copyright 2012-2021 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME mdb_copy \- LMDB environment copy tool .SH SYNOPSIS .B mdb_copy [\c .BR \-V ] [\c .BR \-c ] [\c .BR \-n ] .B srcpath [\c .BR dstpath ] .SH DESCRIPTION The .B mdb_copy utility copies an LMDB environment. The environment can be copied regardless of whether it is currently in use. No lockfile is created, since it gets recreated at need. If .I dstpath is specified it must be the path of an empty directory for storing the backup. Otherwise, the backup will be written to stdout. .SH OPTIONS .TP .BR \-V Write the library version number to the standard output, and exit. .TP .BR \-c Compact while copying. Only current data pages will be copied; freed or unused pages will be omitted from the copy. This option will slow down the backup process as it is more CPU-intensive. Currently it fails if the environment has suffered a page leak. .TP .BR \-n Open LDMB environment(s) which do not use subdirectories. .SH DIAGNOSTICS Exit status is zero if no errors occur. Errors result in a non-zero exit status and a diagnostic message being written to standard error. .SH CAVEATS This utility can trigger significant file size growth if run in parallel with write transactions, because pages which they free during copying cannot be reused until the copy is done. .SH "SEE ALSO" .BR mdb_stat (1) .SH AUTHOR Howard Chu of Symas Corporation openldap-2.5.11+dfsg/libraries/liblmdb/mdb_copy.c0000644000175000017500000000364214172327167020365 0ustar ryanryan/* mdb_copy.c - memory-mapped database backup tool */ /* * Copyright 2012-2021 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #ifdef _WIN32 #include #define MDB_STDOUT GetStdHandle(STD_OUTPUT_HANDLE) #else #define MDB_STDOUT 1 #endif #include #include #include #include "lmdb.h" static void sighandle(int sig) { } int main(int argc,char * argv[]) { int rc; MDB_env *env; const char *progname = argv[0], *act; unsigned flags = MDB_RDONLY; unsigned cpflags = 0; for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) { if (argv[1][1] == 'n' && argv[1][2] == '\0') flags |= MDB_NOSUBDIR; else if (argv[1][1] == 'c' && argv[1][2] == '\0') cpflags |= MDB_CP_COMPACT; else if (argv[1][1] == 'V' && argv[1][2] == '\0') { printf("%s\n", MDB_VERSION_STRING); exit(0); } else argc = 0; } if (argc<2 || argc>3) { fprintf(stderr, "usage: %s [-V] [-c] [-n] srcpath [dstpath]\n", progname); exit(EXIT_FAILURE); } #ifdef SIGPIPE signal(SIGPIPE, sighandle); #endif #ifdef SIGHUP signal(SIGHUP, sighandle); #endif signal(SIGINT, sighandle); signal(SIGTERM, sighandle); act = "opening environment"; rc = mdb_env_create(&env); if (rc == MDB_SUCCESS) { rc = mdb_env_open(env, argv[1], flags, 0600); } if (rc == MDB_SUCCESS) { act = "copying"; if (argc == 2) rc = mdb_env_copyfd2(env, MDB_STDOUT, cpflags); else rc = mdb_env_copy2(env, argv[2], cpflags); } if (rc) fprintf(stderr, "%s: %s failed, error %d (%s)\n", progname, act, rc, mdb_strerror(rc)); mdb_env_close(env); return rc ? EXIT_FAILURE : EXIT_SUCCESS; } openldap-2.5.11+dfsg/libraries/liblmdb/mtest2.c0000644000175000017500000000663614172327167020015 0ustar ryanryan/* mtest2.c - memory-mapped database tester/toy */ /* * Copyright 2011-2021 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Just like mtest.c, but using a subDB instead of the main DB */ #include #include #include #include "lmdb.h" #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) int main(int argc,char * argv[]) { int i = 0, j = 0, rc; MDB_env *env; MDB_dbi dbi; MDB_val key, data; MDB_txn *txn; MDB_stat mst; MDB_cursor *cursor; int count; int *values; char sval[32] = ""; srand(time(NULL)); count = (rand()%384) + 64; values = (int *)malloc(count*sizeof(int)); for(i = 0;i -1; i-= (rand()%5)) { j++; txn=NULL; E(mdb_txn_begin(env, NULL, 0, &txn)); sprintf(sval, "%03x ", values[i]); if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, NULL))) { j--; mdb_txn_abort(txn); } else { E(mdb_txn_commit(txn)); } } free(values); printf("Deleted %d values\n", j); E(mdb_env_stat(env, &mst)); E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); E(mdb_cursor_open(txn, dbi, &cursor)); printf("Cursor next\n"); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { printf("key: %.*s, data: %.*s\n", (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); } CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); printf("Cursor prev\n"); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { printf("key: %.*s, data: %.*s\n", (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); } CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); mdb_cursor_close(cursor); mdb_txn_abort(txn); mdb_dbi_close(env, dbi); mdb_env_close(env); return 0; } openldap-2.5.11+dfsg/libraries/liblmdb/tooltag0000644000175000017500000000115714172327167020020 0ustar ryanryan mdb_copy_1 mdb_copy - environment copy tool mdb_copy.1 mdb_dump_1 mdb_dump - environment export tool mdb_dump.1 mdb_load_1 mdb_load - environment import tool mdb_load.1 mdb_stat_1 mdb_stat - environment status tool mdb_stat.1 openldap-2.5.11+dfsg/libraries/liblmdb/mtest5.c0000644000175000017500000000732114172327167020010 0ustar ryanryan/* mtest5.c - memory-mapped database tester/toy */ /* * Copyright 2011-2021 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Tests for sorted duplicate DBs using cursor_put */ #include #include #include #include #include "lmdb.h" #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) int main(int argc,char * argv[]) { int i = 0, j = 0, rc; MDB_env *env; MDB_dbi dbi; MDB_val key, data; MDB_txn *txn; MDB_stat mst; MDB_cursor *cursor; int count; int *values; char sval[32]; char kval[sizeof(int)]; srand(time(NULL)); memset(sval, 0, sizeof(sval)); count = (rand()%384) + 64; values = (int *)malloc(count*sizeof(int)); for(i = 0;i -1; i-= (rand()%5)) { j++; txn=NULL; E(mdb_txn_begin(env, NULL, 0, &txn)); sprintf(kval, "%03x", values[i & ~0x0f]); sprintf(sval, "%03x %d foo bar", values[i], values[i]); key.mv_size = sizeof(int); key.mv_data = kval; data.mv_size = sizeof(sval); data.mv_data = sval; if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) { j--; mdb_txn_abort(txn); } else { E(mdb_txn_commit(txn)); } } free(values); printf("Deleted %d values\n", j); E(mdb_env_stat(env, &mst)); E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); E(mdb_cursor_open(txn, dbi, &cursor)); printf("Cursor next\n"); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { printf("key: %.*s, data: %.*s\n", (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); } CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); printf("Cursor prev\n"); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { printf("key: %.*s, data: %.*s\n", (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); } CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); mdb_cursor_close(cursor); mdb_txn_abort(txn); mdb_dbi_close(env, dbi); mdb_env_close(env); return 0; } openldap-2.5.11+dfsg/libraries/liblmdb/Makefile0000644000175000017500000000640214172327167020062 0ustar ryanryan# Makefile for liblmdb (Lightning memory-mapped database library). ######################################################################## # Configuration. The compiler options must enable threaded compilation. # # Preprocessor macros (for CPPFLAGS) of interest... # Note that the defaults should already be correct for most # platforms; you should not need to change any of these. # Read their descriptions in mdb.c if you do: # # - MDB_USE_POSIX_SEM # - MDB_DSYNC # - MDB_FDATASYNC # - MDB_FDATASYNC_WORKS # - MDB_USE_PWRITEV # - MDB_USE_ROBUST # # There may be other macros in mdb.c of interest. You should # read mdb.c before changing any of them. # CC = gcc AR = ar W = -W -Wall -Wno-unused-parameter -Wbad-function-cast -Wuninitialized THREADS = -pthread OPT = -O2 -g CFLAGS = $(THREADS) $(OPT) $(W) $(XCFLAGS) LDLIBS = SOLIBS = SOEXT = .so prefix = /usr/local exec_prefix = $(prefix) bindir = $(exec_prefix)/bin libdir = $(exec_prefix)/lib includedir = $(prefix)/include datarootdir = $(prefix)/share mandir = $(datarootdir)/man ######################################################################## IHDRS = lmdb.h ILIBS = liblmdb.a liblmdb$(SOEXT) IPROGS = mdb_stat mdb_copy mdb_dump mdb_load IDOCS = mdb_stat.1 mdb_copy.1 mdb_dump.1 mdb_load.1 PROGS = $(IPROGS) mtest mtest2 mtest3 mtest4 mtest5 all: $(ILIBS) $(PROGS) install: $(ILIBS) $(IPROGS) $(IHDRS) mkdir -p $(DESTDIR)$(bindir) mkdir -p $(DESTDIR)$(libdir) mkdir -p $(DESTDIR)$(includedir) mkdir -p $(DESTDIR)$(mandir)/man1 for f in $(IPROGS); do cp $$f $(DESTDIR)$(bindir); done for f in $(ILIBS); do cp $$f $(DESTDIR)$(libdir); done for f in $(IHDRS); do cp $$f $(DESTDIR)$(includedir); done for f in $(IDOCS); do cp $$f $(DESTDIR)$(mandir)/man1; done clean: rm -rf $(PROGS) *.[ao] *.[ls]o *~ testdb test: all rm -rf testdb && mkdir testdb ./mtest && ./mdb_stat testdb liblmdb.a: mdb.o midl.o $(AR) rs $@ mdb.o midl.o liblmdb$(SOEXT): mdb.lo midl.lo # $(CC) $(LDFLAGS) -pthread -shared -Wl,-Bsymbolic -o $@ mdb.o midl.o $(SOLIBS) $(CC) $(LDFLAGS) -pthread -shared -o $@ mdb.lo midl.lo $(SOLIBS) mdb_stat: mdb_stat.o liblmdb.a mdb_copy: mdb_copy.o liblmdb.a mdb_dump: mdb_dump.o liblmdb.a mdb_load: mdb_load.o liblmdb.a mtest: mtest.o liblmdb.a mtest2: mtest2.o liblmdb.a mtest3: mtest3.o liblmdb.a mtest4: mtest4.o liblmdb.a mtest5: mtest5.o liblmdb.a mtest6: mtest6.o liblmdb.a mdb.o: mdb.c lmdb.h midl.h $(CC) $(CFLAGS) $(CPPFLAGS) -c mdb.c midl.o: midl.c midl.h $(CC) $(CFLAGS) $(CPPFLAGS) -c midl.c mdb.lo: mdb.c lmdb.h midl.h $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c mdb.c -o $@ midl.lo: midl.c midl.h $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c midl.c -o $@ %: %.o $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@ %.o: %.c lmdb.h $(CC) $(CFLAGS) $(CPPFLAGS) -c $< COV_FLAGS=-fprofile-arcs -ftest-coverage COV_OBJS=xmdb.o xmidl.o coverage: xmtest for i in mtest*.c [0-9]*.c; do j=`basename \$$i .c`; $(MAKE) $$j.o; \ gcc -o x$$j $$j.o $(COV_OBJS) -pthread $(COV_FLAGS); \ rm -rf testdb; mkdir testdb; ./x$$j; done gcov xmdb.c gcov xmidl.c xmtest: mtest.o xmdb.o xmidl.o gcc -o xmtest mtest.o xmdb.o xmidl.o -pthread $(COV_FLAGS) xmdb.o: mdb.c lmdb.h midl.h $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -O0 $(COV_FLAGS) -c mdb.c -o $@ xmidl.o: midl.c midl.h $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -O0 $(COV_FLAGS) -c midl.c -o $@ openldap-2.5.11+dfsg/libraries/liblmdb/mtest6.c0000644000175000017500000000756114172327167020017 0ustar ryanryan/* mtest6.c - memory-mapped database tester/toy */ /* * Copyright 2011-2021 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Tests for DB splits and merges */ #include #include #include #include #include "lmdb.h" #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) char dkbuf[1024]; int main(int argc,char * argv[]) { int i = 0, j = 0, rc; MDB_env *env; MDB_dbi dbi; MDB_val key, data, sdata; MDB_txn *txn; MDB_stat mst; MDB_cursor *cursor; int count; int *values; long kval; char *sval; srand(time(NULL)); E(mdb_env_create(&env)); E(mdb_env_set_mapsize(env, 10485760)); E(mdb_env_set_maxdbs(env, 4)); E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); E(mdb_txn_begin(env, NULL, 0, &txn)); E(mdb_dbi_open(txn, "id6", MDB_CREATE|MDB_INTEGERKEY, &dbi)); E(mdb_cursor_open(txn, dbi, &cursor)); E(mdb_stat(txn, dbi, &mst)); sval = calloc(1, mst.ms_psize / 4); key.mv_size = sizeof(long); key.mv_data = &kval; sdata.mv_size = mst.ms_psize / 4 - 30; sdata.mv_data = sval; printf("Adding 12 values, should yield 3 splits\n"); for (i=0;i<12;i++) { kval = i*5; sprintf(sval, "%08x", kval); data = sdata; (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); } printf("Adding 12 more values, should yield 3 splits\n"); for (i=0;i<12;i++) { kval = i*5+4; sprintf(sval, "%08x", kval); data = sdata; (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); } printf("Adding 12 more values, should yield 3 splits\n"); for (i=0;i<12;i++) { kval = i*5+1; sprintf(sval, "%08x", kval); data = sdata; (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); } E(mdb_cursor_get(cursor, &key, &data, MDB_FIRST)); do { printf("key: %p %s, data: %p %.*s\n", key.mv_data, mdb_dkey(&key, dkbuf), data.mv_data, (int) data.mv_size, (char *) data.mv_data); } while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0); CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); mdb_cursor_close(cursor); mdb_txn_commit(txn); #if 0 j=0; for (i= count - 1; i > -1; i-= (rand()%5)) { j++; txn=NULL; E(mdb_txn_begin(env, NULL, 0, &txn)); sprintf(kval, "%03x", values[i & ~0x0f]); sprintf(sval, "%03x %d foo bar", values[i], values[i]); key.mv_size = sizeof(int); key.mv_data = kval; data.mv_size = sizeof(sval); data.mv_data = sval; if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) { j--; mdb_txn_abort(txn); } else { E(mdb_txn_commit(txn)); } } free(values); printf("Deleted %d values\n", j); E(mdb_env_stat(env, &mst)); E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); E(mdb_cursor_open(txn, dbi, &cursor)); printf("Cursor next\n"); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { printf("key: %.*s, data: %.*s\n", (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); } CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); printf("Cursor prev\n"); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { printf("key: %.*s, data: %.*s\n", (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); } CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); mdb_cursor_close(cursor); mdb_txn_abort(txn); mdb_dbi_close(env, dbi); #endif mdb_env_close(env); return 0; } openldap-2.5.11+dfsg/libraries/liblmdb/COPYRIGHT0000644000175000017500000000131314172327167017711 0ustar ryanryanCopyright 2011-2021 Howard Chu, Symas Corp. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted only as authorized by the OpenLDAP Public License. A copy of this license is available in the file LICENSE in the top-level directory of the distribution or, alternatively, at . OpenLDAP is a registered trademark of the OpenLDAP Foundation. Individual files and/or contributed packages may be copyright by other parties and/or subject to additional restrictions. This work also contains materials derived from public sources. Additional information about OpenLDAP can be obtained at . openldap-2.5.11+dfsg/libraries/liblmdb/midl.h0000644000175000017500000001311714172327167017521 0ustar ryanryan/** @file midl.h * @brief LMDB ID List header file. * * This file was originally part of back-bdb but has been * modified for use in libmdb. Most of the macros defined * in this file are unused, just left over from the original. * * This file is only used internally in libmdb and its definitions * are not exposed publicly. */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * Portions Copyright 2001-2021 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #ifndef _MDB_MIDL_H_ #define _MDB_MIDL_H_ #include #ifdef __cplusplus extern "C" { #endif /** @defgroup internal LMDB Internals * @{ */ /** @defgroup idls ID List Management * @{ */ /** A generic unsigned ID number. These were entryIDs in back-bdb. * Preferably it should have the same size as a pointer. */ typedef size_t MDB_ID; /** An IDL is an ID List, a sorted array of IDs. The first * element of the array is a counter for how many actual * IDs are in the list. In the original back-bdb code, IDLs are * sorted in ascending order. For libmdb IDLs are sorted in * descending order. */ typedef MDB_ID *MDB_IDL; /* IDL sizes - likely should be even bigger * limiting factors: sizeof(ID), thread stack size */ #define MDB_IDL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */ #define MDB_IDL_DB_SIZE (1<. * * Copyright 2000-2022 The OpenLDAP Foundation. * Portions Copyright 2001-2021 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include #include #include #include #include #include "midl.h" /** @defgroup internal LMDB Internals * @{ */ /** @defgroup idls ID List Management * @{ */ #define CMP(x,y) ( (x) < (y) ? -1 : (x) > (y) ) unsigned mdb_midl_search( MDB_IDL ids, MDB_ID id ) { /* * binary search of id in ids * if found, returns position of id * if not found, returns first position greater than id */ unsigned base = 0; unsigned cursor = 1; int val = 0; unsigned n = ids[0]; while( 0 < n ) { unsigned pivot = n >> 1; cursor = base + pivot + 1; val = CMP( ids[cursor], id ); if( val < 0 ) { n = pivot; } else if ( val > 0 ) { base = cursor; n -= pivot + 1; } else { return cursor; } } if( val > 0 ) { ++cursor; } return cursor; } #if 0 /* superseded by append/sort */ int mdb_midl_insert( MDB_IDL ids, MDB_ID id ) { unsigned x, i; x = mdb_midl_search( ids, id ); assert( x > 0 ); if( x < 1 ) { /* internal error */ return -2; } if ( x <= ids[0] && ids[x] == id ) { /* duplicate */ assert(0); return -1; } if ( ++ids[0] >= MDB_IDL_DB_MAX ) { /* no room */ --ids[0]; return -2; } else { /* insert id */ for (i=ids[0]; i>x; i--) ids[i] = ids[i-1]; ids[x] = id; } return 0; } #endif MDB_IDL mdb_midl_alloc(int num) { MDB_IDL ids = malloc((num+2) * sizeof(MDB_ID)); if (ids) { *ids++ = num; *ids = 0; } return ids; } void mdb_midl_free(MDB_IDL ids) { if (ids) free(ids-1); } void mdb_midl_shrink( MDB_IDL *idp ) { MDB_IDL ids = *idp; if (*(--ids) > MDB_IDL_UM_MAX && (ids = realloc(ids, (MDB_IDL_UM_MAX+2) * sizeof(MDB_ID)))) { *ids++ = MDB_IDL_UM_MAX; *idp = ids; } } static int mdb_midl_grow( MDB_IDL *idp, int num ) { MDB_IDL idn = *idp-1; /* grow it */ idn = realloc(idn, (*idn + num + 2) * sizeof(MDB_ID)); if (!idn) return ENOMEM; *idn++ += num; *idp = idn; return 0; } int mdb_midl_need( MDB_IDL *idp, unsigned num ) { MDB_IDL ids = *idp; num += ids[0]; if (num > ids[-1]) { num = (num + num/4 + (256 + 2)) & -256; if (!(ids = realloc(ids-1, num * sizeof(MDB_ID)))) return ENOMEM; *ids++ = num - 2; *idp = ids; } return 0; } int mdb_midl_append( MDB_IDL *idp, MDB_ID id ) { MDB_IDL ids = *idp; /* Too big? */ if (ids[0] >= ids[-1]) { if (mdb_midl_grow(idp, MDB_IDL_UM_MAX)) return ENOMEM; ids = *idp; } ids[0]++; ids[ids[0]] = id; return 0; } int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app ) { MDB_IDL ids = *idp; /* Too big? */ if (ids[0] + app[0] >= ids[-1]) { if (mdb_midl_grow(idp, app[0])) return ENOMEM; ids = *idp; } memcpy(&ids[ids[0]+1], &app[1], app[0] * sizeof(MDB_ID)); ids[0] += app[0]; return 0; } int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n ) { MDB_ID *ids = *idp, len = ids[0]; /* Too big? */ if (len + n > ids[-1]) { if (mdb_midl_grow(idp, n | MDB_IDL_UM_MAX)) return ENOMEM; ids = *idp; } ids[0] = len + n; ids += len; while (n) ids[n--] = id++; return 0; } void mdb_midl_xmerge( MDB_IDL idl, MDB_IDL merge ) { MDB_ID old_id, merge_id, i = merge[0], j = idl[0], k = i+j, total = k; idl[0] = (MDB_ID)-1; /* delimiter for idl scan below */ old_id = idl[j]; while (i) { merge_id = merge[i--]; for (; old_id < merge_id; old_id = idl[--j]) idl[k--] = old_id; idl[k--] = merge_id; } idl[0] = total; } /* Quicksort + Insertion sort for small arrays */ #define SMALL 8 #define MIDL_SWAP(a,b) { itmp=(a); (a)=(b); (b)=itmp; } void mdb_midl_sort( MDB_IDL ids ) { /* Max possible depth of int-indexed tree * 2 items/level */ int istack[sizeof(int)*CHAR_BIT * 2]; int i,j,k,l,ir,jstack; MDB_ID a, itmp; ir = (int)ids[0]; l = 1; jstack = 0; for(;;) { if (ir - l < SMALL) { /* Insertion sort */ for (j=l+1;j<=ir;j++) { a = ids[j]; for (i=j-1;i>=1;i--) { if (ids[i] >= a) break; ids[i+1] = ids[i]; } ids[i+1] = a; } if (jstack == 0) break; ir = istack[jstack--]; l = istack[jstack--]; } else { k = (l + ir) >> 1; /* Choose median of left, center, right */ MIDL_SWAP(ids[k], ids[l+1]); if (ids[l] < ids[ir]) { MIDL_SWAP(ids[l], ids[ir]); } if (ids[l+1] < ids[ir]) { MIDL_SWAP(ids[l+1], ids[ir]); } if (ids[l] < ids[l+1]) { MIDL_SWAP(ids[l], ids[l+1]); } i = l+1; j = ir; a = ids[l+1]; for(;;) { do i++; while(ids[i] > a); do j--; while(ids[j] < a); if (j < i) break; MIDL_SWAP(ids[i],ids[j]); } ids[l+1] = ids[j]; ids[j] = a; jstack += 2; if (ir-i+1 >= j-l) { istack[jstack] = ir; istack[jstack-1] = i; ir = j-1; } else { istack[jstack] = j-1; istack[jstack-1] = l; l = i; } } } } unsigned mdb_mid2l_search( MDB_ID2L ids, MDB_ID id ) { /* * binary search of id in ids * if found, returns position of id * if not found, returns first position greater than id */ unsigned base = 0; unsigned cursor = 1; int val = 0; unsigned n = (unsigned)ids[0].mid; while( 0 < n ) { unsigned pivot = n >> 1; cursor = base + pivot + 1; val = CMP( id, ids[cursor].mid ); if( val < 0 ) { n = pivot; } else if ( val > 0 ) { base = cursor; n -= pivot + 1; } else { return cursor; } } if( val > 0 ) { ++cursor; } return cursor; } int mdb_mid2l_insert( MDB_ID2L ids, MDB_ID2 *id ) { unsigned x, i; x = mdb_mid2l_search( ids, id->mid ); if( x < 1 ) { /* internal error */ return -2; } if ( x <= ids[0].mid && ids[x].mid == id->mid ) { /* duplicate */ return -1; } if ( ids[0].mid >= MDB_IDL_UM_MAX ) { /* too big */ return -2; } else { /* insert id */ ids[0].mid++; for (i=(unsigned)ids[0].mid; i>x; i--) ids[i] = ids[i-1]; ids[x] = *id; } return 0; } int mdb_mid2l_append( MDB_ID2L ids, MDB_ID2 *id ) { /* Too big? */ if (ids[0].mid >= MDB_IDL_UM_MAX) { return -2; } ids[0].mid++; ids[ids[0].mid] = *id; return 0; } /** @} */ /** @} */ openldap-2.5.11+dfsg/libraries/liblmdb/mdb_dump.c0000644000175000017500000001437714172327167020367 0ustar ryanryan/* mdb_dump.c - memory-mapped database dump tool */ /* * Copyright 2011-2021 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include #include #include #include #include #include #include #include "lmdb.h" #ifdef _WIN32 #define Z "I" #else #define Z "z" #endif #define PRINT 1 static int mode; typedef struct flagbit { int bit; char *name; } flagbit; flagbit dbflags[] = { { MDB_REVERSEKEY, "reversekey" }, { MDB_DUPSORT, "dupsort" }, { MDB_INTEGERKEY, "integerkey" }, { MDB_DUPFIXED, "dupfixed" }, { MDB_INTEGERDUP, "integerdup" }, { MDB_REVERSEDUP, "reversedup" }, { 0, NULL } }; static volatile sig_atomic_t gotsig; static void dumpsig( int sig ) { gotsig=1; } static const char hexc[] = "0123456789abcdef"; static void hex(unsigned char c) { putchar(hexc[c >> 4]); putchar(hexc[c & 0xf]); } static void text(MDB_val *v) { unsigned char *c, *end; putchar(' '); c = v->mv_data; end = c + v->mv_size; while (c < end) { if (isprint(*c)) { if (*c == '\\') putchar('\\'); putchar(*c); } else { putchar('\\'); hex(*c); } c++; } putchar('\n'); } static void byte(MDB_val *v) { unsigned char *c, *end; putchar(' '); c = v->mv_data; end = c + v->mv_size; while (c < end) { hex(*c++); } putchar('\n'); } /* Dump in BDB-compatible format */ static int dumpit(MDB_txn *txn, MDB_dbi dbi, char *name) { MDB_cursor *mc; MDB_stat ms; MDB_val key, data; MDB_envinfo info; unsigned int flags; int rc, i; rc = mdb_dbi_flags(txn, dbi, &flags); if (rc) return rc; rc = mdb_stat(txn, dbi, &ms); if (rc) return rc; rc = mdb_env_info(mdb_txn_env(txn), &info); if (rc) return rc; printf("VERSION=3\n"); printf("format=%s\n", mode & PRINT ? "print" : "bytevalue"); if (name) printf("database=%s\n", name); printf("type=btree\n"); printf("mapsize=%" Z "u\n", info.me_mapsize); if (info.me_mapaddr) printf("mapaddr=%p\n", info.me_mapaddr); printf("maxreaders=%u\n", info.me_maxreaders); if (flags & MDB_DUPSORT) printf("duplicates=1\n"); for (i=0; dbflags[i].bit; i++) if (flags & dbflags[i].bit) printf("%s=1\n", dbflags[i].name); printf("db_pagesize=%d\n", ms.ms_psize); printf("HEADER=END\n"); rc = mdb_cursor_open(txn, dbi, &mc); if (rc) return rc; while ((rc = mdb_cursor_get(mc, &key, &data, MDB_NEXT) == MDB_SUCCESS)) { if (gotsig) { rc = EINTR; break; } if (mode & PRINT) { text(&key); text(&data); } else { byte(&key); byte(&data); } } printf("DATA=END\n"); if (rc == MDB_NOTFOUND) rc = MDB_SUCCESS; return rc; } static void usage(char *prog) { fprintf(stderr, "usage: %s [-V] [-f output] [-l] [-n] [-p] [-a|-s subdb] dbpath\n", prog); exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { int i, rc; MDB_env *env; MDB_txn *txn; MDB_dbi dbi; char *prog = argv[0]; char *envname; char *subname = NULL; int alldbs = 0, envflags = 0, list = 0; if (argc < 2) { usage(prog); } /* -a: dump main DB and all subDBs * -s: dump only the named subDB * -n: use NOSUBDIR flag on env_open * -p: use printable characters * -f: write to file instead of stdout * -V: print version and exit * (default) dump only the main DB */ while ((i = getopt(argc, argv, "af:lnps:V")) != EOF) { switch(i) { case 'V': printf("%s\n", MDB_VERSION_STRING); exit(0); break; case 'l': list = 1; /*FALLTHROUGH*/; case 'a': if (subname) usage(prog); alldbs++; break; case 'f': if (freopen(optarg, "w", stdout) == NULL) { fprintf(stderr, "%s: %s: reopen: %s\n", prog, optarg, strerror(errno)); exit(EXIT_FAILURE); } break; case 'n': envflags |= MDB_NOSUBDIR; break; case 'p': mode |= PRINT; break; case 's': if (alldbs) usage(prog); subname = optarg; break; default: usage(prog); } } if (optind != argc - 1) usage(prog); #ifdef SIGPIPE signal(SIGPIPE, dumpsig); #endif #ifdef SIGHUP signal(SIGHUP, dumpsig); #endif signal(SIGINT, dumpsig); signal(SIGTERM, dumpsig); envname = argv[optind]; rc = mdb_env_create(&env); if (rc) { fprintf(stderr, "mdb_env_create failed, error %d %s\n", rc, mdb_strerror(rc)); return EXIT_FAILURE; } if (alldbs || subname) { mdb_env_set_maxdbs(env, 2); } rc = mdb_env_open(env, envname, envflags | MDB_RDONLY, 0664); if (rc) { fprintf(stderr, "mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc)); goto env_close; } rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn); if (rc) { fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc)); goto env_close; } rc = mdb_open(txn, subname, 0, &dbi); if (rc) { fprintf(stderr, "mdb_open failed, error %d %s\n", rc, mdb_strerror(rc)); goto txn_abort; } if (alldbs) { MDB_cursor *cursor; MDB_val key; int count = 0; rc = mdb_cursor_open(txn, dbi, &cursor); if (rc) { fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc)); goto txn_abort; } while ((rc = mdb_cursor_get(cursor, &key, NULL, MDB_NEXT_NODUP)) == 0) { char *str; MDB_dbi db2; if (memchr(key.mv_data, '\0', key.mv_size)) continue; count++; str = malloc(key.mv_size+1); memcpy(str, key.mv_data, key.mv_size); str[key.mv_size] = '\0'; rc = mdb_open(txn, str, 0, &db2); if (rc == MDB_SUCCESS) { if (list) { printf("%s\n", str); list++; } else { rc = dumpit(txn, db2, str); if (rc) break; } mdb_close(env, db2); } free(str); if (rc) continue; } mdb_cursor_close(cursor); if (!count) { fprintf(stderr, "%s: %s does not contain multiple databases\n", prog, envname); rc = MDB_NOTFOUND; } else if (rc == MDB_NOTFOUND) { rc = MDB_SUCCESS; } } else { rc = dumpit(txn, dbi, subname); } if (rc && rc != MDB_NOTFOUND) fprintf(stderr, "%s: %s: %s\n", prog, envname, mdb_strerror(rc)); mdb_close(env, dbi); txn_abort: mdb_txn_abort(txn); env_close: mdb_env_close(env); return rc ? EXIT_FAILURE : EXIT_SUCCESS; } openldap-2.5.11+dfsg/libraries/liblmdb/mdb_load.10000644000175000017500000000511414172327167020244 0ustar ryanryan.TH MDB_LOAD 1 "2015/09/30" "LMDB 0.9.17" .\" Copyright 2014-2021 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME mdb_load \- LMDB environment import tool .SH SYNOPSIS .B mdb_load [\c .BR \-V ] [\c .BI \-f \ file\fR] [\c .BR \-n ] [\c .BI \-s \ subdb\fR] [\c .BR \-N ] [\c .BR \-T ] .BR \ envpath .SH DESCRIPTION The .B mdb_load utility reads from the standard input and loads it into the LMDB environment .BR envpath . The input to .B mdb_load must be in the output format specified by the .BR mdb_dump (1) utility or as specified by the .B -T option below. .SH OPTIONS .TP .BR \-V Write the library version number to the standard output, and exit. .TP .BR \-a Append all records in the order they appear in the input. The input is assumed to already be in correctly sorted order and no sorting or checking for redundant values will be performed. This option must be used to reload data that was produced by running .B mdb_dump on a database that uses custom compare functions. .TP .BR \-f \ file Read from the specified file instead of from the standard input. .TP .BR \-n Load an LMDB database which does not use subdirectories. .TP .BR \-s \ subdb Load a specific subdatabase. If no database is specified, data is loaded into the main database. .TP .BR \-N Don't overwrite existing records when loading into an already existing database; just skip them. .TP .BR \-T Load data from simple text files. The input must be paired lines of text, where the first line of the pair is the key item, and the second line of the pair is its corresponding data item. A simple escape mechanism, where newline and backslash (\\) characters are special, is applied to the text input. Newline characters are interpreted as record separators. Backslash characters in the text will be interpreted in one of two ways: If the backslash character precedes another backslash character, the pair will be interpreted as a literal backslash. If the backslash character precedes any other character, the two characters following the backslash will be interpreted as a hexadecimal specification of a single character; for example, \\0a is a newline character in the ASCII character set. For this reason, any backslash or newline characters that naturally occur in the text input must be escaped to avoid misinterpretation by .BR mdb_load . .SH DIAGNOSTICS Exit status is zero if no errors occur. Errors result in a non-zero exit status and a diagnostic message being written to standard error. .SH "SEE ALSO" .BR mdb_dump (1) .SH AUTHOR Howard Chu of Symas Corporation openldap-2.5.11+dfsg/libraries/liblmdb/lmdb.h0000644000175000017500000022043614172327167017516 0ustar ryanryan/** @file lmdb.h * @brief Lightning memory-mapped database library * * @mainpage Lightning Memory-Mapped Database Manager (LMDB) * * @section intro_sec Introduction * LMDB is a Btree-based database management library modeled loosely on the * BerkeleyDB API, but much simplified. The entire database is exposed * in a memory map, and all data fetches return data directly * from the mapped memory, so no malloc's or memcpy's occur during * data fetches. As such, the library is extremely simple because it * requires no page caching layer of its own, and it is extremely high * performance and memory-efficient. It is also fully transactional with * full ACID semantics, and when the memory map is read-only, the * database integrity cannot be corrupted by stray pointer writes from * application code. * * The library is fully thread-aware and supports concurrent read/write * access from multiple processes and threads. Data pages use a copy-on- * write strategy so no active data pages are ever overwritten, which * also provides resistance to corruption and eliminates the need of any * special recovery procedures after a system crash. Writes are fully * serialized; only one write transaction may be active at a time, which * guarantees that writers can never deadlock. The database structure is * multi-versioned so readers run with no locks; writers cannot block * readers, and readers don't block writers. * * Unlike other well-known database mechanisms which use either write-ahead * transaction logs or append-only data writes, LMDB requires no maintenance * during operation. Both write-ahead loggers and append-only databases * require periodic checkpointing and/or compaction of their log or database * files otherwise they grow without bound. LMDB tracks free pages within * the database and re-uses them for new write operations, so the database * size does not grow without bound in normal use. * * The memory map can be used as a read-only or read-write map. It is * read-only by default as this provides total immunity to corruption. * Using read-write mode offers much higher write performance, but adds * the possibility for stray application writes thru pointers to silently * corrupt the database. Of course if your application code is known to * be bug-free (...) then this is not an issue. * * If this is your first time using a transactional embedded key/value * store, you may find the \ref starting page to be helpful. * * @section caveats_sec Caveats * Troubleshooting the lock file, plus semaphores on BSD systems: * * - A broken lockfile can cause sync issues. * Stale reader transactions left behind by an aborted program * cause further writes to grow the database quickly, and * stale locks can block further operation. * * Fix: Check for stale readers periodically, using the * #mdb_reader_check function or the \ref mdb_stat_1 "mdb_stat" tool. * Stale writers will be cleared automatically on some systems: * - Windows - automatic * - Linux, systems using POSIX mutexes with Robust option - automatic * - not on BSD, systems using POSIX semaphores. * Otherwise just make all programs using the database close it; * the lockfile is always reset on first open of the environment. * * - On BSD systems or others configured with MDB_USE_POSIX_SEM, * startup can fail due to semaphores owned by another userid. * * Fix: Open and close the database as the user which owns the * semaphores (likely last user) or as root, while no other * process is using the database. * * Restrictions/caveats (in addition to those listed for some functions): * * - Only the database owner should normally use the database on * BSD systems or when otherwise configured with MDB_USE_POSIX_SEM. * Multiple users can cause startup to fail later, as noted above. * * - There is normally no pure read-only mode, since readers need write * access to locks and lock file. Exceptions: On read-only filesystems * or with the #MDB_NOLOCK flag described under #mdb_env_open(). * * - An LMDB configuration will often reserve considerable \b unused * memory address space and maybe file size for future growth. * This does not use actual memory or disk space, but users may need * to understand the difference so they won't be scared off. * * - By default, in versions before 0.9.10, unused portions of the data * file might receive garbage data from memory freed by other code. * (This does not happen when using the #MDB_WRITEMAP flag.) As of * 0.9.10 the default behavior is to initialize such memory before * writing to the data file. Since there may be a slight performance * cost due to this initialization, applications may disable it using * the #MDB_NOMEMINIT flag. Applications handling sensitive data * which must not be written should not use this flag. This flag is * irrelevant when using #MDB_WRITEMAP. * * - A thread can only use one transaction at a time, plus any child * transactions. Each transaction belongs to one thread. See below. * The #MDB_NOTLS flag changes this for read-only transactions. * * - Use an MDB_env* in the process which opened it, not after fork(). * * - Do not have open an LMDB database twice in the same process at * the same time. Not even from a plain open() call - close()ing it * breaks fcntl() advisory locking. (It is OK to reopen it after * fork() - exec*(), since the lockfile has FD_CLOEXEC set.) * * - Avoid long-lived transactions. Read transactions prevent * reuse of pages freed by newer write transactions, thus the * database can grow quickly. Write transactions prevent * other write transactions, since writes are serialized. * * - Avoid suspending a process with active transactions. These * would then be "long-lived" as above. Also read transactions * suspended when writers commit could sometimes see wrong data. * * ...when several processes can use a database concurrently: * * - Avoid aborting a process with an active transaction. * The transaction becomes "long-lived" as above until a check * for stale readers is performed or the lockfile is reset, * since the process may not remove it from the lockfile. * * This does not apply to write transactions if the system clears * stale writers, see above. * * - If you do that anyway, do a periodic check for stale readers. Or * close the environment once in a while, so the lockfile can get reset. * * - Do not use LMDB databases on remote filesystems, even between * processes on the same host. This breaks flock() on some OSes, * possibly memory map sync, and certainly sync between programs * on different hosts. * * - Opening a database can fail if another process is opening or * closing it at exactly the same time. * * @author Howard Chu, Symas Corporation. * * @copyright Copyright 2011-2021 Howard Chu, Symas Corp. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . * * @par Derived From: * This code is derived from btree.c written by Martin Hedenfalk. * * Copyright (c) 2009, 2010 Martin Hedenfalk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _LMDB_H_ #define _LMDB_H_ #include #ifdef __cplusplus extern "C" { #endif /** Unix permissions for creating files, or dummy definition for Windows */ #ifdef _MSC_VER typedef int mdb_mode_t; #else typedef mode_t mdb_mode_t; #endif /** An abstraction for a file handle. * On POSIX systems file handles are small integers. On Windows * they're opaque pointers. */ #ifdef _WIN32 typedef void *mdb_filehandle_t; #else typedef int mdb_filehandle_t; #endif /** @defgroup mdb LMDB API * @{ * @brief OpenLDAP Lightning Memory-Mapped Database Manager */ /** @defgroup Version Version Macros * @{ */ /** Library major version */ #define MDB_VERSION_MAJOR 0 /** Library minor version */ #define MDB_VERSION_MINOR 9 /** Library patch version */ #define MDB_VERSION_PATCH 29 /** Combine args a,b,c into a single integer for easy version comparisons */ #define MDB_VERINT(a,b,c) (((a) << 24) | ((b) << 16) | (c)) /** The full library version as a single integer */ #define MDB_VERSION_FULL \ MDB_VERINT(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH) /** The release date of this library version */ #define MDB_VERSION_DATE "March 16, 2021" /** A stringifier for the version info */ #define MDB_VERSTR(a,b,c,d) "LMDB " #a "." #b "." #c ": (" d ")" /** A helper for the stringifier macro */ #define MDB_VERFOO(a,b,c,d) MDB_VERSTR(a,b,c,d) /** The full library version as a C string */ #define MDB_VERSION_STRING \ MDB_VERFOO(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH,MDB_VERSION_DATE) /** @} */ /** @brief Opaque structure for a database environment. * * A DB environment supports multiple databases, all residing in the same * shared-memory map. */ typedef struct MDB_env MDB_env; /** @brief Opaque structure for a transaction handle. * * All database operations require a transaction handle. Transactions may be * read-only or read-write. */ typedef struct MDB_txn MDB_txn; /** @brief A handle for an individual database in the DB environment. */ typedef unsigned int MDB_dbi; /** @brief Opaque structure for navigating through a database */ typedef struct MDB_cursor MDB_cursor; /** @brief Generic structure used for passing keys and data in and out * of the database. * * Values returned from the database are valid only until a subsequent * update operation, or the end of the transaction. Do not modify or * free them, they commonly point into the database itself. * * Key sizes must be between 1 and #mdb_env_get_maxkeysize() inclusive. * The same applies to data sizes in databases with the #MDB_DUPSORT flag. * Other data items can in theory be from 0 to 0xffffffff bytes long. */ typedef struct MDB_val { size_t mv_size; /**< size of the data item */ void *mv_data; /**< address of the data item */ } MDB_val; /** @brief A callback function used to compare two keys in a database */ typedef int (MDB_cmp_func)(const MDB_val *a, const MDB_val *b); /** @brief A callback function used to relocate a position-dependent data item * in a fixed-address database. * * The \b newptr gives the item's desired address in * the memory map, and \b oldptr gives its previous address. The item's actual * data resides at the address in \b item. This callback is expected to walk * through the fields of the record in \b item and modify any * values based at the \b oldptr address to be relative to the \b newptr address. * @param[in,out] item The item that is to be relocated. * @param[in] oldptr The previous address. * @param[in] newptr The new address to relocate to. * @param[in] relctx An application-provided context, set by #mdb_set_relctx(). * @todo This feature is currently unimplemented. */ typedef void (MDB_rel_func)(MDB_val *item, void *oldptr, void *newptr, void *relctx); /** @defgroup mdb_env Environment Flags * @{ */ /** mmap at a fixed address (experimental) */ #define MDB_FIXEDMAP 0x01 /** no environment directory */ #define MDB_NOSUBDIR 0x4000 /** don't fsync after commit */ #define MDB_NOSYNC 0x10000 /** read only */ #define MDB_RDONLY 0x20000 /** don't fsync metapage after commit */ #define MDB_NOMETASYNC 0x40000 /** use writable mmap */ #define MDB_WRITEMAP 0x80000 /** use asynchronous msync when #MDB_WRITEMAP is used */ #define MDB_MAPASYNC 0x100000 /** tie reader locktable slots to #MDB_txn objects instead of to threads */ #define MDB_NOTLS 0x200000 /** don't do any locking, caller must manage their own locks */ #define MDB_NOLOCK 0x400000 /** don't do readahead (no effect on Windows) */ #define MDB_NORDAHEAD 0x800000 /** don't initialize malloc'd memory before writing to datafile */ #define MDB_NOMEMINIT 0x1000000 /** @} */ /** @defgroup mdb_dbi_open Database Flags * @{ */ /** use reverse string keys */ #define MDB_REVERSEKEY 0x02 /** use sorted duplicates */ #define MDB_DUPSORT 0x04 /** numeric keys in native byte order: either unsigned int or size_t. * The keys must all be of the same size. */ #define MDB_INTEGERKEY 0x08 /** with #MDB_DUPSORT, sorted dup items have fixed size */ #define MDB_DUPFIXED 0x10 /** with #MDB_DUPSORT, dups are #MDB_INTEGERKEY-style integers */ #define MDB_INTEGERDUP 0x20 /** with #MDB_DUPSORT, use reverse string dups */ #define MDB_REVERSEDUP 0x40 /** create DB if not already existing */ #define MDB_CREATE 0x40000 /** @} */ /** @defgroup mdb_put Write Flags * @{ */ /** For put: Don't write if the key already exists. */ #define MDB_NOOVERWRITE 0x10 /** Only for #MDB_DUPSORT
* For put: don't write if the key and data pair already exist.
* For mdb_cursor_del: remove all duplicate data items. */ #define MDB_NODUPDATA 0x20 /** For mdb_cursor_put: overwrite the current key/data pair */ #define MDB_CURRENT 0x40 /** For put: Just reserve space for data, don't copy it. Return a * pointer to the reserved space. */ #define MDB_RESERVE 0x10000 /** Data is being appended, don't split full pages. */ #define MDB_APPEND 0x20000 /** Duplicate data is being appended, don't split full pages. */ #define MDB_APPENDDUP 0x40000 /** Store multiple data items in one call. Only for #MDB_DUPFIXED. */ #define MDB_MULTIPLE 0x80000 /* @} */ /** @defgroup mdb_copy Copy Flags * @{ */ /** Compacting copy: Omit free space from copy, and renumber all * pages sequentially. */ #define MDB_CP_COMPACT 0x01 /* @} */ /** @brief Cursor Get operations. * * This is the set of all operations for retrieving data * using a cursor. */ typedef enum MDB_cursor_op { MDB_FIRST, /**< Position at first key/data item */ MDB_FIRST_DUP, /**< Position at first data item of current key. Only for #MDB_DUPSORT */ MDB_GET_BOTH, /**< Position at key/data pair. Only for #MDB_DUPSORT */ MDB_GET_BOTH_RANGE, /**< position at key, nearest data. Only for #MDB_DUPSORT */ MDB_GET_CURRENT, /**< Return key/data at current cursor position */ MDB_GET_MULTIPLE, /**< Return up to a page of duplicate data items from current cursor position. Move cursor to prepare for #MDB_NEXT_MULTIPLE. Only for #MDB_DUPFIXED */ MDB_LAST, /**< Position at last key/data item */ MDB_LAST_DUP, /**< Position at last data item of current key. Only for #MDB_DUPSORT */ MDB_NEXT, /**< Position at next data item */ MDB_NEXT_DUP, /**< Position at next data item of current key. Only for #MDB_DUPSORT */ MDB_NEXT_MULTIPLE, /**< Return up to a page of duplicate data items from next cursor position. Move cursor to prepare for #MDB_NEXT_MULTIPLE. Only for #MDB_DUPFIXED */ MDB_NEXT_NODUP, /**< Position at first data item of next key */ MDB_PREV, /**< Position at previous data item */ MDB_PREV_DUP, /**< Position at previous data item of current key. Only for #MDB_DUPSORT */ MDB_PREV_NODUP, /**< Position at last data item of previous key */ MDB_SET, /**< Position at specified key */ MDB_SET_KEY, /**< Position at specified key, return key + data */ MDB_SET_RANGE, /**< Position at first key greater than or equal to specified key. */ MDB_PREV_MULTIPLE /**< Position at previous page and return up to a page of duplicate data items. Only for #MDB_DUPFIXED */ } MDB_cursor_op; /** @defgroup errors Return Codes * * BerkeleyDB uses -30800 to -30999, we'll go under them * @{ */ /** Successful result */ #define MDB_SUCCESS 0 /** key/data pair already exists */ #define MDB_KEYEXIST (-30799) /** key/data pair not found (EOF) */ #define MDB_NOTFOUND (-30798) /** Requested page not found - this usually indicates corruption */ #define MDB_PAGE_NOTFOUND (-30797) /** Located page was wrong type */ #define MDB_CORRUPTED (-30796) /** Update of meta page failed or environment had fatal error */ #define MDB_PANIC (-30795) /** Environment version mismatch */ #define MDB_VERSION_MISMATCH (-30794) /** File is not a valid LMDB file */ #define MDB_INVALID (-30793) /** Environment mapsize reached */ #define MDB_MAP_FULL (-30792) /** Environment maxdbs reached */ #define MDB_DBS_FULL (-30791) /** Environment maxreaders reached */ #define MDB_READERS_FULL (-30790) /** Too many TLS keys in use - Windows only */ #define MDB_TLS_FULL (-30789) /** Txn has too many dirty pages */ #define MDB_TXN_FULL (-30788) /** Cursor stack too deep - internal error */ #define MDB_CURSOR_FULL (-30787) /** Page has not enough space - internal error */ #define MDB_PAGE_FULL (-30786) /** Database contents grew beyond environment mapsize */ #define MDB_MAP_RESIZED (-30785) /** Operation and DB incompatible, or DB type changed. This can mean: *
    *
  • The operation expects an #MDB_DUPSORT / #MDB_DUPFIXED database. *
  • Opening a named DB when the unnamed DB has #MDB_DUPSORT / #MDB_INTEGERKEY. *
  • Accessing a data record as a database, or vice versa. *
  • The database was dropped and recreated with different flags. *
*/ #define MDB_INCOMPATIBLE (-30784) /** Invalid reuse of reader locktable slot */ #define MDB_BAD_RSLOT (-30783) /** Transaction must abort, has a child, or is invalid */ #define MDB_BAD_TXN (-30782) /** Unsupported size of key/DB name/data, or wrong DUPFIXED size */ #define MDB_BAD_VALSIZE (-30781) /** The specified DBI was changed unexpectedly */ #define MDB_BAD_DBI (-30780) /** The last defined error code */ #define MDB_LAST_ERRCODE MDB_BAD_DBI /** @} */ /** @brief Statistics for a database in the environment */ typedef struct MDB_stat { unsigned int ms_psize; /**< Size of a database page. This is currently the same for all databases. */ unsigned int ms_depth; /**< Depth (height) of the B-tree */ size_t ms_branch_pages; /**< Number of internal (non-leaf) pages */ size_t ms_leaf_pages; /**< Number of leaf pages */ size_t ms_overflow_pages; /**< Number of overflow pages */ size_t ms_entries; /**< Number of data items */ } MDB_stat; /** @brief Information about the environment */ typedef struct MDB_envinfo { void *me_mapaddr; /**< Address of map, if fixed */ size_t me_mapsize; /**< Size of the data memory map */ size_t me_last_pgno; /**< ID of the last used page */ size_t me_last_txnid; /**< ID of the last committed transaction */ unsigned int me_maxreaders; /**< max reader slots in the environment */ unsigned int me_numreaders; /**< max reader slots used in the environment */ } MDB_envinfo; /** @brief Return the LMDB library version information. * * @param[out] major if non-NULL, the library major version number is copied here * @param[out] minor if non-NULL, the library minor version number is copied here * @param[out] patch if non-NULL, the library patch version number is copied here * @retval "version string" The library version as a string */ char *mdb_version(int *major, int *minor, int *patch); /** @brief Return a string describing a given error code. * * This function is a superset of the ANSI C X3.159-1989 (ANSI C) strerror(3) * function. If the error code is greater than or equal to 0, then the string * returned by the system function strerror(3) is returned. If the error code * is less than 0, an error string corresponding to the LMDB library error is * returned. See @ref errors for a list of LMDB-specific error codes. * @param[in] err The error code * @retval "error message" The description of the error */ char *mdb_strerror(int err); /** @brief Create an LMDB environment handle. * * This function allocates memory for a #MDB_env structure. To release * the allocated memory and discard the handle, call #mdb_env_close(). * Before the handle may be used, it must be opened using #mdb_env_open(). * Various other options may also need to be set before opening the handle, * e.g. #mdb_env_set_mapsize(), #mdb_env_set_maxreaders(), #mdb_env_set_maxdbs(), * depending on usage requirements. * @param[out] env The address where the new handle will be stored * @return A non-zero error value on failure and 0 on success. */ int mdb_env_create(MDB_env **env); /** @brief Open an environment handle. * * If this function fails, #mdb_env_close() must be called to discard the #MDB_env handle. * @param[in] env An environment handle returned by #mdb_env_create() * @param[in] path The directory in which the database files reside. This * directory must already exist and be writable. * @param[in] flags Special options for this environment. This parameter * must be set to 0 or by bitwise OR'ing together one or more of the * values described here. * Flags set by mdb_env_set_flags() are also used. *
    *
  • #MDB_FIXEDMAP * use a fixed address for the mmap region. This flag must be specified * when creating the environment, and is stored persistently in the environment. * If successful, the memory map will always reside at the same virtual address * and pointers used to reference data items in the database will be constant * across multiple invocations. This option may not always work, depending on * how the operating system has allocated memory to shared libraries and other uses. * The feature is highly experimental. *
  • #MDB_NOSUBDIR * By default, LMDB creates its environment in a directory whose * pathname is given in \b path, and creates its data and lock files * under that directory. With this option, \b path is used as-is for * the database main data file. The database lock file is the \b path * with "-lock" appended. *
  • #MDB_RDONLY * Open the environment in read-only mode. No write operations will be * allowed. LMDB will still modify the lock file - except on read-only * filesystems, where LMDB does not use locks. *
  • #MDB_WRITEMAP * Use a writeable memory map unless MDB_RDONLY is set. This uses * fewer mallocs but loses protection from application bugs * like wild pointer writes and other bad updates into the database. * This may be slightly faster for DBs that fit entirely in RAM, but * is slower for DBs larger than RAM. * Incompatible with nested transactions. * Do not mix processes with and without MDB_WRITEMAP on the same * environment. This can defeat durability (#mdb_env_sync etc). *
  • #MDB_NOMETASYNC * Flush system buffers to disk only once per transaction, omit the * metadata flush. Defer that until the system flushes files to disk, * or next non-MDB_RDONLY commit or #mdb_env_sync(). This optimization * maintains database integrity, but a system crash may undo the last * committed transaction. I.e. it preserves the ACI (atomicity, * consistency, isolation) but not D (durability) database property. * This flag may be changed at any time using #mdb_env_set_flags(). *
  • #MDB_NOSYNC * Don't flush system buffers to disk when committing a transaction. * This optimization means a system crash can corrupt the database or * lose the last transactions if buffers are not yet flushed to disk. * The risk is governed by how often the system flushes dirty buffers * to disk and how often #mdb_env_sync() is called. However, if the * filesystem preserves write order and the #MDB_WRITEMAP flag is not * used, transactions exhibit ACI (atomicity, consistency, isolation) * properties and only lose D (durability). I.e. database integrity * is maintained, but a system crash may undo the final transactions. * Note that (#MDB_NOSYNC | #MDB_WRITEMAP) leaves the system with no * hint for when to write transactions to disk, unless #mdb_env_sync() * is called. (#MDB_MAPASYNC | #MDB_WRITEMAP) may be preferable. * This flag may be changed at any time using #mdb_env_set_flags(). *
  • #MDB_MAPASYNC * When using #MDB_WRITEMAP, use asynchronous flushes to disk. * As with #MDB_NOSYNC, a system crash can then corrupt the * database or lose the last transactions. Calling #mdb_env_sync() * ensures on-disk database integrity until next commit. * This flag may be changed at any time using #mdb_env_set_flags(). *
  • #MDB_NOTLS * Don't use Thread-Local Storage. Tie reader locktable slots to * #MDB_txn objects instead of to threads. I.e. #mdb_txn_reset() keeps * the slot reserved for the #MDB_txn object. A thread may use parallel * read-only transactions. A read-only transaction may span threads if * the user synchronizes its use. Applications that multiplex many * user threads over individual OS threads need this option. Such an * application must also serialize the write transactions in an OS * thread, since LMDB's write locking is unaware of the user threads. *
  • #MDB_NOLOCK * Don't do any locking. If concurrent access is anticipated, the * caller must manage all concurrency itself. For proper operation * the caller must enforce single-writer semantics, and must ensure * that no readers are using old transactions while a writer is * active. The simplest approach is to use an exclusive lock so that * no readers may be active at all when a writer begins. *
  • #MDB_NORDAHEAD * Turn off readahead. Most operating systems perform readahead on * read requests by default. This option turns it off if the OS * supports it. Turning it off may help random read performance * when the DB is larger than RAM and system RAM is full. * The option is not implemented on Windows. *
  • #MDB_NOMEMINIT * Don't initialize malloc'd memory before writing to unused spaces * in the data file. By default, memory for pages written to the data * file is obtained using malloc. While these pages may be reused in * subsequent transactions, freshly malloc'd pages will be initialized * to zeroes before use. This avoids persisting leftover data from other * code (that used the heap and subsequently freed the memory) into the * data file. Note that many other system libraries may allocate * and free memory from the heap for arbitrary uses. E.g., stdio may * use the heap for file I/O buffers. This initialization step has a * modest performance cost so some applications may want to disable * it using this flag. This option can be a problem for applications * which handle sensitive data like passwords, and it makes memory * checkers like Valgrind noisy. This flag is not needed with #MDB_WRITEMAP, * which writes directly to the mmap instead of using malloc for pages. The * initialization is also skipped if #MDB_RESERVE is used; the * caller is expected to overwrite all of the memory that was * reserved in that case. * This flag may be changed at any time using #mdb_env_set_flags(). *
* @param[in] mode The UNIX permissions to set on created files and semaphores. * This parameter is ignored on Windows. * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • #MDB_VERSION_MISMATCH - the version of the LMDB library doesn't match the * version that created the database environment. *
  • #MDB_INVALID - the environment file headers are corrupted. *
  • ENOENT - the directory specified by the path parameter doesn't exist. *
  • EACCES - the user didn't have permission to access the environment files. *
  • EAGAIN - the environment was locked by another process. *
*/ int mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode); /** @brief Copy an LMDB environment to the specified path. * * This function may be used to make a backup of an existing environment. * No lockfile is created, since it gets recreated at need. * @note This call can trigger significant file size growth if run in * parallel with write transactions, because it employs a read-only * transaction. See long-lived transactions under @ref caveats_sec. * @param[in] env An environment handle returned by #mdb_env_create(). It * must have already been opened successfully. * @param[in] path The directory in which the copy will reside. This * directory must already exist and be writable but must otherwise be * empty. * @return A non-zero error value on failure and 0 on success. */ int mdb_env_copy(MDB_env *env, const char *path); /** @brief Copy an LMDB environment to the specified file descriptor. * * This function may be used to make a backup of an existing environment. * No lockfile is created, since it gets recreated at need. * @note This call can trigger significant file size growth if run in * parallel with write transactions, because it employs a read-only * transaction. See long-lived transactions under @ref caveats_sec. * @param[in] env An environment handle returned by #mdb_env_create(). It * must have already been opened successfully. * @param[in] fd The filedescriptor to write the copy to. It must * have already been opened for Write access. * @return A non-zero error value on failure and 0 on success. */ int mdb_env_copyfd(MDB_env *env, mdb_filehandle_t fd); /** @brief Copy an LMDB environment to the specified path, with options. * * This function may be used to make a backup of an existing environment. * No lockfile is created, since it gets recreated at need. * @note This call can trigger significant file size growth if run in * parallel with write transactions, because it employs a read-only * transaction. See long-lived transactions under @ref caveats_sec. * @param[in] env An environment handle returned by #mdb_env_create(). It * must have already been opened successfully. * @param[in] path The directory in which the copy will reside. This * directory must already exist and be writable but must otherwise be * empty. * @param[in] flags Special options for this operation. This parameter * must be set to 0 or by bitwise OR'ing together one or more of the * values described here. *
    *
  • #MDB_CP_COMPACT - Perform compaction while copying: omit free * pages and sequentially renumber all pages in output. This option * consumes more CPU and runs more slowly than the default. * Currently it fails if the environment has suffered a page leak. *
* @return A non-zero error value on failure and 0 on success. */ int mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags); /** @brief Copy an LMDB environment to the specified file descriptor, * with options. * * This function may be used to make a backup of an existing environment. * No lockfile is created, since it gets recreated at need. See * #mdb_env_copy2() for further details. * @note This call can trigger significant file size growth if run in * parallel with write transactions, because it employs a read-only * transaction. See long-lived transactions under @ref caveats_sec. * @param[in] env An environment handle returned by #mdb_env_create(). It * must have already been opened successfully. * @param[in] fd The filedescriptor to write the copy to. It must * have already been opened for Write access. * @param[in] flags Special options for this operation. * See #mdb_env_copy2() for options. * @return A non-zero error value on failure and 0 on success. */ int mdb_env_copyfd2(MDB_env *env, mdb_filehandle_t fd, unsigned int flags); /** @brief Return statistics about the LMDB environment. * * @param[in] env An environment handle returned by #mdb_env_create() * @param[out] stat The address of an #MDB_stat structure * where the statistics will be copied */ int mdb_env_stat(MDB_env *env, MDB_stat *stat); /** @brief Return information about the LMDB environment. * * @param[in] env An environment handle returned by #mdb_env_create() * @param[out] stat The address of an #MDB_envinfo structure * where the information will be copied */ int mdb_env_info(MDB_env *env, MDB_envinfo *stat); /** @brief Flush the data buffers to disk. * * Data is always written to disk when #mdb_txn_commit() is called, * but the operating system may keep it buffered. LMDB always flushes * the OS buffers upon commit as well, unless the environment was * opened with #MDB_NOSYNC or in part #MDB_NOMETASYNC. This call is * not valid if the environment was opened with #MDB_RDONLY. * @param[in] env An environment handle returned by #mdb_env_create() * @param[in] force If non-zero, force a synchronous flush. Otherwise * if the environment has the #MDB_NOSYNC flag set the flushes * will be omitted, and with #MDB_MAPASYNC they will be asynchronous. * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EACCES - the environment is read-only. *
  • EINVAL - an invalid parameter was specified. *
  • EIO - an error occurred during synchronization. *
*/ int mdb_env_sync(MDB_env *env, int force); /** @brief Close the environment and release the memory map. * * Only a single thread may call this function. All transactions, databases, * and cursors must already be closed before calling this function. Attempts to * use any such handles after calling this function will cause a SIGSEGV. * The environment handle will be freed and must not be used again after this call. * @param[in] env An environment handle returned by #mdb_env_create() */ void mdb_env_close(MDB_env *env); /** @brief Set environment flags. * * This may be used to set some flags in addition to those from * #mdb_env_open(), or to unset these flags. If several threads * change the flags at the same time, the result is undefined. * @param[in] env An environment handle returned by #mdb_env_create() * @param[in] flags The flags to change, bitwise OR'ed together * @param[in] onoff A non-zero value sets the flags, zero clears them. * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_env_set_flags(MDB_env *env, unsigned int flags, int onoff); /** @brief Get environment flags. * * @param[in] env An environment handle returned by #mdb_env_create() * @param[out] flags The address of an integer to store the flags * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_env_get_flags(MDB_env *env, unsigned int *flags); /** @brief Return the path that was used in #mdb_env_open(). * * @param[in] env An environment handle returned by #mdb_env_create() * @param[out] path Address of a string pointer to contain the path. This * is the actual string in the environment, not a copy. It should not be * altered in any way. * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_env_get_path(MDB_env *env, const char **path); /** @brief Return the filedescriptor for the given environment. * * This function may be called after fork(), so the descriptor can be * closed before exec*(). Other LMDB file descriptors have FD_CLOEXEC. * (Until LMDB 0.9.18, only the lockfile had that.) * * @param[in] env An environment handle returned by #mdb_env_create() * @param[out] fd Address of a mdb_filehandle_t to contain the descriptor. * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_env_get_fd(MDB_env *env, mdb_filehandle_t *fd); /** @brief Set the size of the memory map to use for this environment. * * The size should be a multiple of the OS page size. The default is * 10485760 bytes. The size of the memory map is also the maximum size * of the database. The value should be chosen as large as possible, * to accommodate future growth of the database. * This function should be called after #mdb_env_create() and before #mdb_env_open(). * It may be called at later times if no transactions are active in * this process. Note that the library does not check for this condition, * the caller must ensure it explicitly. * * The new size takes effect immediately for the current process but * will not be persisted to any others until a write transaction has been * committed by the current process. Also, only mapsize increases are * persisted into the environment. * * If the mapsize is increased by another process, and data has grown * beyond the range of the current mapsize, #mdb_txn_begin() will * return #MDB_MAP_RESIZED. This function may be called with a size * of zero to adopt the new size. * * Any attempt to set a size smaller than the space already consumed * by the environment will be silently changed to the current size of the used space. * @param[in] env An environment handle returned by #mdb_env_create() * @param[in] size The size in bytes * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - an invalid parameter was specified, or the environment has * an active write transaction. *
*/ int mdb_env_set_mapsize(MDB_env *env, size_t size); /** @brief Set the maximum number of threads/reader slots for the environment. * * This defines the number of slots in the lock table that is used to track readers in the * the environment. The default is 126. * Starting a read-only transaction normally ties a lock table slot to the * current thread until the environment closes or the thread exits. If * MDB_NOTLS is in use, #mdb_txn_begin() instead ties the slot to the * MDB_txn object until it or the #MDB_env object is destroyed. * This function may only be called after #mdb_env_create() and before #mdb_env_open(). * @param[in] env An environment handle returned by #mdb_env_create() * @param[in] readers The maximum number of reader lock table slots * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - an invalid parameter was specified, or the environment is already open. *
*/ int mdb_env_set_maxreaders(MDB_env *env, unsigned int readers); /** @brief Get the maximum number of threads/reader slots for the environment. * * @param[in] env An environment handle returned by #mdb_env_create() * @param[out] readers Address of an integer to store the number of readers * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_env_get_maxreaders(MDB_env *env, unsigned int *readers); /** @brief Set the maximum number of named databases for the environment. * * This function is only needed if multiple databases will be used in the * environment. Simpler applications that use the environment as a single * unnamed database can ignore this option. * This function may only be called after #mdb_env_create() and before #mdb_env_open(). * * Currently a moderate number of slots are cheap but a huge number gets * expensive: 7-120 words per transaction, and every #mdb_dbi_open() * does a linear search of the opened slots. * @param[in] env An environment handle returned by #mdb_env_create() * @param[in] dbs The maximum number of databases * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - an invalid parameter was specified, or the environment is already open. *
*/ int mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs); /** @brief Get the maximum size of keys and #MDB_DUPSORT data we can write. * * Depends on the compile-time constant #MDB_MAXKEYSIZE. Default 511. * See @ref MDB_val. * @param[in] env An environment handle returned by #mdb_env_create() * @return The maximum size of a key we can write */ int mdb_env_get_maxkeysize(MDB_env *env); /** @brief Set application information associated with the #MDB_env. * * @param[in] env An environment handle returned by #mdb_env_create() * @param[in] ctx An arbitrary pointer for whatever the application needs. * @return A non-zero error value on failure and 0 on success. */ int mdb_env_set_userctx(MDB_env *env, void *ctx); /** @brief Get the application information associated with the #MDB_env. * * @param[in] env An environment handle returned by #mdb_env_create() * @return The pointer set by #mdb_env_set_userctx(). */ void *mdb_env_get_userctx(MDB_env *env); /** @brief A callback function for most LMDB assert() failures, * called before printing the message and aborting. * * @param[in] env An environment handle returned by #mdb_env_create(). * @param[in] msg The assertion message, not including newline. */ typedef void MDB_assert_func(MDB_env *env, const char *msg); /** Set or reset the assert() callback of the environment. * Disabled if liblmdb is built with NDEBUG. * @note This hack should become obsolete as lmdb's error handling matures. * @param[in] env An environment handle returned by #mdb_env_create(). * @param[in] func An #MDB_assert_func function, or 0. * @return A non-zero error value on failure and 0 on success. */ int mdb_env_set_assert(MDB_env *env, MDB_assert_func *func); /** @brief Create a transaction for use with the environment. * * The transaction handle may be discarded using #mdb_txn_abort() or #mdb_txn_commit(). * @note A transaction and its cursors must only be used by a single * thread, and a thread may only have a single transaction at a time. * If #MDB_NOTLS is in use, this does not apply to read-only transactions. * @note Cursors may not span transactions. * @param[in] env An environment handle returned by #mdb_env_create() * @param[in] parent If this parameter is non-NULL, the new transaction * will be a nested transaction, with the transaction indicated by \b parent * as its parent. Transactions may be nested to any level. A parent * transaction and its cursors may not issue any other operations than * mdb_txn_commit and mdb_txn_abort while it has active child transactions. * @param[in] flags Special options for this transaction. This parameter * must be set to 0 or by bitwise OR'ing together one or more of the * values described here. *
    *
  • #MDB_RDONLY * This transaction will not perform any write operations. *
* @param[out] txn Address where the new #MDB_txn handle will be stored * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • #MDB_PANIC - a fatal error occurred earlier and the environment * must be shut down. *
  • #MDB_MAP_RESIZED - another process wrote data beyond this MDB_env's * mapsize and this environment's map must be resized as well. * See #mdb_env_set_mapsize(). *
  • #MDB_READERS_FULL - a read-only transaction was requested and * the reader lock table is full. See #mdb_env_set_maxreaders(). *
  • ENOMEM - out of memory. *
*/ int mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **txn); /** @brief Returns the transaction's #MDB_env * * @param[in] txn A transaction handle returned by #mdb_txn_begin() */ MDB_env *mdb_txn_env(MDB_txn *txn); /** @brief Return the transaction's ID. * * This returns the identifier associated with this transaction. For a * read-only transaction, this corresponds to the snapshot being read; * concurrent readers will frequently have the same transaction ID. * * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @return A transaction ID, valid if input is an active transaction. */ size_t mdb_txn_id(MDB_txn *txn); /** @brief Commit all the operations of a transaction into the database. * * The transaction handle is freed. It and its cursors must not be used * again after this call, except with #mdb_cursor_renew(). * @note Earlier documentation incorrectly said all cursors would be freed. * Only write-transactions free cursors. * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - an invalid parameter was specified. *
  • ENOSPC - no more disk space. *
  • EIO - a low-level I/O error occurred while writing. *
  • ENOMEM - out of memory. *
*/ int mdb_txn_commit(MDB_txn *txn); /** @brief Abandon all the operations of the transaction instead of saving them. * * The transaction handle is freed. It and its cursors must not be used * again after this call, except with #mdb_cursor_renew(). * @note Earlier documentation incorrectly said all cursors would be freed. * Only write-transactions free cursors. * @param[in] txn A transaction handle returned by #mdb_txn_begin() */ void mdb_txn_abort(MDB_txn *txn); /** @brief Reset a read-only transaction. * * Abort the transaction like #mdb_txn_abort(), but keep the transaction * handle. #mdb_txn_renew() may reuse the handle. This saves allocation * overhead if the process will start a new read-only transaction soon, * and also locking overhead if #MDB_NOTLS is in use. The reader table * lock is released, but the table slot stays tied to its thread or * #MDB_txn. Use mdb_txn_abort() to discard a reset handle, and to free * its lock table slot if MDB_NOTLS is in use. * Cursors opened within the transaction must not be used * again after this call, except with #mdb_cursor_renew(). * Reader locks generally don't interfere with writers, but they keep old * versions of database pages allocated. Thus they prevent the old pages * from being reused when writers commit new data, and so under heavy load * the database size may grow much more rapidly than otherwise. * @param[in] txn A transaction handle returned by #mdb_txn_begin() */ void mdb_txn_reset(MDB_txn *txn); /** @brief Renew a read-only transaction. * * This acquires a new reader lock for a transaction handle that had been * released by #mdb_txn_reset(). It must be called before a reset transaction * may be used again. * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • #MDB_PANIC - a fatal error occurred earlier and the environment * must be shut down. *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_txn_renew(MDB_txn *txn); /** Compat with version <= 0.9.4, avoid clash with libmdb from MDB Tools project */ #define mdb_open(txn,name,flags,dbi) mdb_dbi_open(txn,name,flags,dbi) /** Compat with version <= 0.9.4, avoid clash with libmdb from MDB Tools project */ #define mdb_close(env,dbi) mdb_dbi_close(env,dbi) /** @brief Open a database in the environment. * * A database handle denotes the name and parameters of a database, * independently of whether such a database exists. * The database handle may be discarded by calling #mdb_dbi_close(). * The old database handle is returned if the database was already open. * The handle may only be closed once. * * The database handle will be private to the current transaction until * the transaction is successfully committed. If the transaction is * aborted the handle will be closed automatically. * After a successful commit the handle will reside in the shared * environment, and may be used by other transactions. * * This function must not be called from multiple concurrent * transactions in the same process. A transaction that uses * this function must finish (either commit or abort) before * any other transaction in the process may use this function. * * To use named databases (with name != NULL), #mdb_env_set_maxdbs() * must be called before opening the environment. Database names are * keys in the unnamed database, and may be read but not written. * * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] name The name of the database to open. If only a single * database is needed in the environment, this value may be NULL. * @param[in] flags Special options for this database. This parameter * must be set to 0 or by bitwise OR'ing together one or more of the * values described here. *
    *
  • #MDB_REVERSEKEY * Keys are strings to be compared in reverse order, from the end * of the strings to the beginning. By default, Keys are treated as strings and * compared from beginning to end. *
  • #MDB_DUPSORT * Duplicate keys may be used in the database. (Or, from another perspective, * keys may have multiple data items, stored in sorted order.) By default * keys must be unique and may have only a single data item. *
  • #MDB_INTEGERKEY * Keys are binary integers in native byte order, either unsigned int * or size_t, and will be sorted as such. * The keys must all be of the same size. *
  • #MDB_DUPFIXED * This flag may only be used in combination with #MDB_DUPSORT. This option * tells the library that the data items for this database are all the same * size, which allows further optimizations in storage and retrieval. When * all data items are the same size, the #MDB_GET_MULTIPLE, #MDB_NEXT_MULTIPLE * and #MDB_PREV_MULTIPLE cursor operations may be used to retrieve multiple * items at once. *
  • #MDB_INTEGERDUP * This option specifies that duplicate data items are binary integers, * similar to #MDB_INTEGERKEY keys. *
  • #MDB_REVERSEDUP * This option specifies that duplicate data items should be compared as * strings in reverse order. *
  • #MDB_CREATE * Create the named database if it doesn't exist. This option is not * allowed in a read-only transaction or a read-only environment. *
* @param[out] dbi Address where the new #MDB_dbi handle will be stored * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • #MDB_NOTFOUND - the specified database doesn't exist in the environment * and #MDB_CREATE was not specified. *
  • #MDB_DBS_FULL - too many databases have been opened. See #mdb_env_set_maxdbs(). *
*/ int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *dbi); /** @brief Retrieve statistics for a database. * * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] dbi A database handle returned by #mdb_dbi_open() * @param[out] stat The address of an #MDB_stat structure * where the statistics will be copied * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *stat); /** @brief Retrieve the DB flags for a database handle. * * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] dbi A database handle returned by #mdb_dbi_open() * @param[out] flags Address where the flags will be returned. * @return A non-zero error value on failure and 0 on success. */ int mdb_dbi_flags(MDB_txn *txn, MDB_dbi dbi, unsigned int *flags); /** @brief Close a database handle. Normally unnecessary. Use with care: * * This call is not mutex protected. Handles should only be closed by * a single thread, and only if no other threads are going to reference * the database handle or one of its cursors any further. Do not close * a handle if an existing transaction has modified its database. * Doing so can cause misbehavior from database corruption to errors * like MDB_BAD_VALSIZE (since the DB name is gone). * * Closing a database handle is not necessary, but lets #mdb_dbi_open() * reuse the handle value. Usually it's better to set a bigger * #mdb_env_set_maxdbs(), unless that value would be large. * * @param[in] env An environment handle returned by #mdb_env_create() * @param[in] dbi A database handle returned by #mdb_dbi_open() */ void mdb_dbi_close(MDB_env *env, MDB_dbi dbi); /** @brief Empty or delete+close a database. * * See #mdb_dbi_close() for restrictions about closing the DB handle. * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] dbi A database handle returned by #mdb_dbi_open() * @param[in] del 0 to empty the DB, 1 to delete it from the * environment and close the DB handle. * @return A non-zero error value on failure and 0 on success. */ int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del); /** @brief Set a custom key comparison function for a database. * * The comparison function is called whenever it is necessary to compare a * key specified by the application with a key currently stored in the database. * If no comparison function is specified, and no special key flags were specified * with #mdb_dbi_open(), the keys are compared lexically, with shorter keys collating * before longer keys. * @warning This function must be called before any data access functions are used, * otherwise data corruption may occur. The same comparison function must be used by every * program accessing the database, every time the database is used. * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] dbi A database handle returned by #mdb_dbi_open() * @param[in] cmp A #MDB_cmp_func function * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp); /** @brief Set a custom data comparison function for a #MDB_DUPSORT database. * * This comparison function is called whenever it is necessary to compare a data * item specified by the application with a data item currently stored in the database. * This function only takes effect if the database was opened with the #MDB_DUPSORT * flag. * If no comparison function is specified, and no special key flags were specified * with #mdb_dbi_open(), the data items are compared lexically, with shorter items collating * before longer items. * @warning This function must be called before any data access functions are used, * otherwise data corruption may occur. The same comparison function must be used by every * program accessing the database, every time the database is used. * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] dbi A database handle returned by #mdb_dbi_open() * @param[in] cmp A #MDB_cmp_func function * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp); /** @brief Set a relocation function for a #MDB_FIXEDMAP database. * * @todo The relocation function is called whenever it is necessary to move the data * of an item to a different position in the database (e.g. through tree * balancing operations, shifts as a result of adds or deletes, etc.). It is * intended to allow address/position-dependent data items to be stored in * a database in an environment opened with the #MDB_FIXEDMAP option. * Currently the relocation feature is unimplemented and setting * this function has no effect. * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] dbi A database handle returned by #mdb_dbi_open() * @param[in] rel A #MDB_rel_func function * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel); /** @brief Set a context pointer for a #MDB_FIXEDMAP database's relocation function. * * See #mdb_set_relfunc and #MDB_rel_func for more details. * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] dbi A database handle returned by #mdb_dbi_open() * @param[in] ctx An arbitrary pointer for whatever the application needs. * It will be passed to the callback function set by #mdb_set_relfunc * as its \b relctx parameter whenever the callback is invoked. * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx); /** @brief Get items from a database. * * This function retrieves key/data pairs from the database. The address * and length of the data associated with the specified \b key are returned * in the structure to which \b data refers. * If the database supports duplicate keys (#MDB_DUPSORT) then the * first data item for the key will be returned. Retrieval of other * items requires the use of #mdb_cursor_get(). * * @note The memory pointed to by the returned values is owned by the * database. The caller need not dispose of the memory, and may not * modify it in any way. For values returned in a read-only transaction * any modification attempts will cause a SIGSEGV. * @note Values returned from the database are valid only until a * subsequent update operation, or the end of the transaction. * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] dbi A database handle returned by #mdb_dbi_open() * @param[in] key The key to search for in the database * @param[out] data The data corresponding to the key * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • #MDB_NOTFOUND - the key was not in the database. *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_get(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data); /** @brief Store items into a database. * * This function stores key/data pairs in the database. The default behavior * is to enter the new key/data pair, replacing any previously existing key * if duplicates are disallowed, or adding a duplicate data item if * duplicates are allowed (#MDB_DUPSORT). * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] dbi A database handle returned by #mdb_dbi_open() * @param[in] key The key to store in the database * @param[in,out] data The data to store * @param[in] flags Special options for this operation. This parameter * must be set to 0 or by bitwise OR'ing together one or more of the * values described here. *
    *
  • #MDB_NODUPDATA - enter the new key/data pair only if it does not * already appear in the database. This flag may only be specified * if the database was opened with #MDB_DUPSORT. The function will * return #MDB_KEYEXIST if the key/data pair already appears in the * database. *
  • #MDB_NOOVERWRITE - enter the new key/data pair only if the key * does not already appear in the database. The function will return * #MDB_KEYEXIST if the key already appears in the database, even if * the database supports duplicates (#MDB_DUPSORT). The \b data * parameter will be set to point to the existing item. *
  • #MDB_RESERVE - reserve space for data of the given size, but * don't copy the given data. Instead, return a pointer to the * reserved space, which the caller can fill in later - before * the next update operation or the transaction ends. This saves * an extra memcpy if the data is being generated later. * LMDB does nothing else with this memory, the caller is expected * to modify all of the space requested. This flag must not be * specified if the database was opened with #MDB_DUPSORT. *
  • #MDB_APPEND - append the given key/data pair to the end of the * database. This option allows fast bulk loading when keys are * already known to be in the correct order. Loading unsorted keys * with this flag will cause a #MDB_KEYEXIST error. *
  • #MDB_APPENDDUP - as above, but for sorted dup data. *
* @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • #MDB_MAP_FULL - the database is full, see #mdb_env_set_mapsize(). *
  • #MDB_TXN_FULL - the transaction has too many dirty pages. *
  • EACCES - an attempt was made to write in a read-only transaction. *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_put(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data, unsigned int flags); /** @brief Delete items from a database. * * This function removes key/data pairs from the database. * If the database does not support sorted duplicate data items * (#MDB_DUPSORT) the data parameter is ignored. * If the database supports sorted duplicates and the data parameter * is NULL, all of the duplicate data items for the key will be * deleted. Otherwise, if the data parameter is non-NULL * only the matching data item will be deleted. * This function will return #MDB_NOTFOUND if the specified key/data * pair is not in the database. * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] dbi A database handle returned by #mdb_dbi_open() * @param[in] key The key to delete from the database * @param[in] data The data to delete * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EACCES - an attempt was made to write in a read-only transaction. *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_del(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data); /** @brief Create a cursor handle. * * A cursor is associated with a specific transaction and database. * A cursor cannot be used when its database handle is closed. Nor * when its transaction has ended, except with #mdb_cursor_renew(). * It can be discarded with #mdb_cursor_close(). * A cursor in a write-transaction can be closed before its transaction * ends, and will otherwise be closed when its transaction ends. * A cursor in a read-only transaction must be closed explicitly, before * or after its transaction ends. It can be reused with * #mdb_cursor_renew() before finally closing it. * @note Earlier documentation said that cursors in every transaction * were closed when the transaction committed or aborted. * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] dbi A database handle returned by #mdb_dbi_open() * @param[out] cursor Address where the new #MDB_cursor handle will be stored * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **cursor); /** @brief Close a cursor handle. * * The cursor handle will be freed and must not be used again after this call. * Its transaction must still be live if it is a write-transaction. * @param[in] cursor A cursor handle returned by #mdb_cursor_open() */ void mdb_cursor_close(MDB_cursor *cursor); /** @brief Renew a cursor handle. * * A cursor is associated with a specific transaction and database. * Cursors that are only used in read-only * transactions may be re-used, to avoid unnecessary malloc/free overhead. * The cursor may be associated with a new read-only transaction, and * referencing the same database handle as it was created with. * This may be done whether the previous transaction is live or dead. * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] cursor A cursor handle returned by #mdb_cursor_open() * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_cursor_renew(MDB_txn *txn, MDB_cursor *cursor); /** @brief Return the cursor's transaction handle. * * @param[in] cursor A cursor handle returned by #mdb_cursor_open() */ MDB_txn *mdb_cursor_txn(MDB_cursor *cursor); /** @brief Return the cursor's database handle. * * @param[in] cursor A cursor handle returned by #mdb_cursor_open() */ MDB_dbi mdb_cursor_dbi(MDB_cursor *cursor); /** @brief Retrieve by cursor. * * This function retrieves key/data pairs from the database. The address and length * of the key are returned in the object to which \b key refers (except for the * case of the #MDB_SET option, in which the \b key object is unchanged), and * the address and length of the data are returned in the object to which \b data * refers. * See #mdb_get() for restrictions on using the output values. * @param[in] cursor A cursor handle returned by #mdb_cursor_open() * @param[in,out] key The key for a retrieved item * @param[in,out] data The data of a retrieved item * @param[in] op A cursor operation #MDB_cursor_op * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • #MDB_NOTFOUND - no matching key found. *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_cursor_get(MDB_cursor *cursor, MDB_val *key, MDB_val *data, MDB_cursor_op op); /** @brief Store by cursor. * * This function stores key/data pairs into the database. * The cursor is positioned at the new item, or on failure usually near it. * @note Earlier documentation incorrectly said errors would leave the * state of the cursor unchanged. * @param[in] cursor A cursor handle returned by #mdb_cursor_open() * @param[in] key The key operated on. * @param[in] data The data operated on. * @param[in] flags Options for this operation. This parameter * must be set to 0 or one of the values described here. *
    *
  • #MDB_CURRENT - replace the item at the current cursor position. * The \b key parameter must still be provided, and must match it. * If using sorted duplicates (#MDB_DUPSORT) the data item must still * sort into the same place. This is intended to be used when the * new data is the same size as the old. Otherwise it will simply * perform a delete of the old record followed by an insert. *
  • #MDB_NODUPDATA - enter the new key/data pair only if it does not * already appear in the database. This flag may only be specified * if the database was opened with #MDB_DUPSORT. The function will * return #MDB_KEYEXIST if the key/data pair already appears in the * database. *
  • #MDB_NOOVERWRITE - enter the new key/data pair only if the key * does not already appear in the database. The function will return * #MDB_KEYEXIST if the key already appears in the database, even if * the database supports duplicates (#MDB_DUPSORT). *
  • #MDB_RESERVE - reserve space for data of the given size, but * don't copy the given data. Instead, return a pointer to the * reserved space, which the caller can fill in later - before * the next update operation or the transaction ends. This saves * an extra memcpy if the data is being generated later. This flag * must not be specified if the database was opened with #MDB_DUPSORT. *
  • #MDB_APPEND - append the given key/data pair to the end of the * database. No key comparisons are performed. This option allows * fast bulk loading when keys are already known to be in the * correct order. Loading unsorted keys with this flag will cause * a #MDB_KEYEXIST error. *
  • #MDB_APPENDDUP - as above, but for sorted dup data. *
  • #MDB_MULTIPLE - store multiple contiguous data elements in a * single request. This flag may only be specified if the database * was opened with #MDB_DUPFIXED. The \b data argument must be an * array of two MDB_vals. The mv_size of the first MDB_val must be * the size of a single data element. The mv_data of the first MDB_val * must point to the beginning of the array of contiguous data elements. * The mv_size of the second MDB_val must be the count of the number * of data elements to store. On return this field will be set to * the count of the number of elements actually written. The mv_data * of the second MDB_val is unused. *
* @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • #MDB_MAP_FULL - the database is full, see #mdb_env_set_mapsize(). *
  • #MDB_TXN_FULL - the transaction has too many dirty pages. *
  • EACCES - an attempt was made to write in a read-only transaction. *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_cursor_put(MDB_cursor *cursor, MDB_val *key, MDB_val *data, unsigned int flags); /** @brief Delete current key/data pair * * This function deletes the key/data pair to which the cursor refers. * This does not invalidate the cursor, so operations such as MDB_NEXT * can still be used on it. * Both MDB_NEXT and MDB_GET_CURRENT will return the same record after * this operation. * @param[in] cursor A cursor handle returned by #mdb_cursor_open() * @param[in] flags Options for this operation. This parameter * must be set to 0 or one of the values described here. *
    *
  • #MDB_NODUPDATA - delete all of the data items for the current key. * This flag may only be specified if the database was opened with #MDB_DUPSORT. *
* @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EACCES - an attempt was made to write in a read-only transaction. *
  • EINVAL - an invalid parameter was specified. *
*/ int mdb_cursor_del(MDB_cursor *cursor, unsigned int flags); /** @brief Return count of duplicates for current key. * * This call is only valid on databases that support sorted duplicate * data items #MDB_DUPSORT. * @param[in] cursor A cursor handle returned by #mdb_cursor_open() * @param[out] countp Address where the count will be stored * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
    *
  • EINVAL - cursor is not initialized, or an invalid parameter was specified. *
*/ int mdb_cursor_count(MDB_cursor *cursor, size_t *countp); /** @brief Compare two data items according to a particular database. * * This returns a comparison as if the two data items were keys in the * specified database. * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] dbi A database handle returned by #mdb_dbi_open() * @param[in] a The first item to compare * @param[in] b The second item to compare * @return < 0 if a < b, 0 if a == b, > 0 if a > b */ int mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b); /** @brief Compare two data items according to a particular database. * * This returns a comparison as if the two items were data items of * the specified database. The database must have the #MDB_DUPSORT flag. * @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] dbi A database handle returned by #mdb_dbi_open() * @param[in] a The first item to compare * @param[in] b The second item to compare * @return < 0 if a < b, 0 if a == b, > 0 if a > b */ int mdb_dcmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b); /** @brief A callback function used to print a message from the library. * * @param[in] msg The string to be printed. * @param[in] ctx An arbitrary context pointer for the callback. * @return < 0 on failure, >= 0 on success. */ typedef int (MDB_msg_func)(const char *msg, void *ctx); /** @brief Dump the entries in the reader lock table. * * @param[in] env An environment handle returned by #mdb_env_create() * @param[in] func A #MDB_msg_func function * @param[in] ctx Anything the message function needs * @return < 0 on failure, >= 0 on success. */ int mdb_reader_list(MDB_env *env, MDB_msg_func *func, void *ctx); /** @brief Check for stale entries in the reader lock table. * * @param[in] env An environment handle returned by #mdb_env_create() * @param[out] dead Number of stale slots that were cleared * @return 0 on success, non-zero on failure. */ int mdb_reader_check(MDB_env *env, int *dead); /** @} */ #ifdef __cplusplus } #endif /** @page tools LMDB Command Line Tools The following describes the command line tools that are available for LMDB. \li \ref mdb_copy_1 \li \ref mdb_dump_1 \li \ref mdb_load_1 \li \ref mdb_stat_1 */ #endif /* _LMDB_H_ */ openldap-2.5.11+dfsg/libraries/liblmdb/CHANGES0000644000175000017500000002203114172327167017411 0ustar ryanryanLMDB 0.9 Change Log LMDB 0.9.29 Release (2021/03/16) ITS#9461 refix ITS#9376 ITS#9500 fix regression from ITS#8662 LMDB 0.9.28 Release (2021/02/04) ITS#8662 add -a append option to mdb_load LMDB 0.9.27 Release (2020/10/26) ITS#9376 fix repeated DUPSORT cursor deletes LMDB 0.9.26 Release (2020/08/11) ITS#9278 fix robust mutex cleanup for FreeBSD LMDB 0.9.25 Release (2020/01/30) ITS#9068 fix mdb_dump/load backslashes in printable content ITS#9118 add MAP_NOSYNC for FreeBSD ITS#9155 free mt_spill_pgs in non-nested txn on end LMDB 0.9.24 Release (2019/07/24) ITS#8969 Tweak mdb_page_split ITS#8975 WIN32 fix writemap set_mapsize crash ITS#9007 Fix loose pages in WRITEMAP LMDB 0.9.23 Release (2018/12/19) ITS#8756 Fix loose pages in dirty list ITS#8831 Fix mdb_load flag init ITS#8844 Fix mdb_env_close in forked process Documentation ITS#8857 mdb_cursor_del doesn't invalidate cursor ITS#8908 GET_MULTIPLE etc don't change passed in key LMDB 0.9.22 Release (2018/03/22) Fix MDB_DUPSORT alignment bug (ITS#8819) Fix regression with new db from 0.9.19 (ITS#8760) Fix liblmdb to build on Solaris (ITS#8612) Fix delete behavior with DUPSORT DB (ITS#8622) Fix mdb_cursor_get/mdb_cursor_del behavior (ITS#8722) LMDB 0.9.21 Release (2017/06/01) Fix xcursor after cursor_del (ITS#8622) LMDB 0.9.20 (Withdrawn) Fix mdb_load with escaped plaintext (ITS#8558) Fix mdb_cursor_last / mdb_put interaction (ITS#8557) LMDB 0.9.19 Release (2016/12/28) Fix mdb_env_cwalk cursor init (ITS#8424) Fix robust mutexes on Solaris 10/11 (ITS#8339) Tweak Win32 error message buffer Fix MDB_GET_BOTH on non-dup record (ITS#8393) Optimize mdb_drop Fix xcursors after mdb_cursor_del (ITS#8406) Fix MDB_NEXT_DUP after mdb_cursor_del (ITS#8412) Fix mdb_cursor_put resetting C_EOF (ITS#8489) Fix mdb_env_copyfd2 to return EPIPE on SIGPIPE (ITS#8504) Fix mdb_env_copy with empty DB (ITS#8209) Fix behaviors with fork (ITS#8505) Fix mdb_dbi_open with mainDB cursors (ITS#8542) Fix robust mutexes on kFreeBSD (ITS#8554) Fix utf8_to_utf16 error checks (ITS#7992) Fix F_NOCACHE on MacOS, error is non-fatal (ITS#7682) Build Make shared lib suffix overridable (ITS#8481) Documentation Cleanup doxygen nits Note reserved vs actual mem/disk usage LMDB 0.9.18 Release (2016/02/05) Fix robust mutex detection on glibc 2.10-11 (ITS#8330) Fix page_search_root assert on FreeDB (ITS#8336) Fix MDB_APPENDDUP vs. rewrite(single item) (ITS#8334) Fix mdb_copy of large files on Windows Fix subcursor move after delete (ITS#8355) Fix mdb_midl_shirnk off-by-one (ITS#8363) Check for utf8_to_utf16 failures (ITS#7992) Catch strdup failure in mdb_dbi_open Build Additional makefile var tweaks (ITS#8169) Documentation Add Getting Started page Update WRITEMAP description LMDB 0.9.17 Release (2015/11/30) Fix ITS#7377 catch calloc failure Fix ITS#8237 regression from ITS#7589 Fix ITS#8238 page_split for DUPFIXED pages Fix ITS#8221 MDB_PAGE_FULL on delete/rebalance Fix ITS#8258 rebalance/split assert Fix ITS#8263 cursor_put cursor tracking Fix ITS#8264 cursor_del cursor tracking Fix ITS#8310 cursor_del cursor tracking Fix ITS#8299 mdb_del cursor tracking Fix ITS#8300 mdb_del cursor tracking Fix ITS#8304 mdb_del cursor tracking Fix ITS#7771 fakepage cursor tracking Fix ITS#7789 ensure mapsize >= pages in use Fix ITS#7971 mdb_txn_renew0() new reader slots Fix ITS#7969 use __sync_synchronize on non-x86 Fix ITS#8311 page_split from update_key Fix ITS#8312 loose pages in nested txn Fix ITS#8313 mdb_rebalance dummy cursor Fix ITS#8315 dirty_room in nested txn Fix ITS#8323 dirty_list in nested txn Fix ITS#8316 page_merge cursor tracking Fix ITS#8321 cursor tracking Fix ITS#8319 mdb_load error messages Fix ITS#8320 mdb_load plaintext input Added mdb_txn_id() (ITS#7994) Added robust mutex support Miscellaneous cleanup/simplification Build Create install dirs if needed (ITS#8256) Fix ThreadProc decl on Win32/MSVC (ITS#8270) Added ssize_t typedef for MSVC (ITS#8067) Use ANSI apis on Windows (ITS#8069) Use O_SYNC if O_DSYNC,MDB_DSYNC are not defined (ITS#7209) Allow passing AR to make (ITS#8168) Allow passing mandir to make install (ITS#8169) LMDB 0.9.16 Release (2015/08/14) Fix cursor EOF bug (ITS#8190) Fix handling of subDB records (ITS#8181) Fix mdb_midl_shrink() usage (ITS#8200) LMDB 0.9.15 Release (2015/06/19) Fix txn init (ITS#7961,#7987) Fix MDB_PREV_DUP (ITS#7955,#7671) Fix compact of empty env (ITS#7956) Fix mdb_copy file mode Fix mdb_env_close() after failed mdb_env_open() Fix mdb_rebalance collapsing root (ITS#8062) Fix mdb_load with large values (ITS#8066) Fix to retry writes on EINTR (ITS#8106) Fix mdb_cursor_del on empty DB (ITS#8109) Fix MDB_INTEGERDUP key compare (ITS#8117) Fix error handling (ITS#7959,#8157,etc.) Fix race conditions (ITS#7969,7970) Added workaround for fdatasync bug in ext3fs Build Don't use -fPIC for static lib Update .gitignore (ITS#7952,#7953) Cleanup for "make test" (ITS#7841), "make clean", mtest*.c Misc. Android/Windows cleanup Documentation Fix MDB_APPEND doc Fix MDB_MAXKEYSIZE doc (ITS#8156) Fix mdb_cursor_put,mdb_cursor_del EACCES description Fix mdb_env_sync(MDB_RDONLY env) doc (ITS#8021) Clarify MDB_WRITEMAP doc (ITS#8021) Clarify mdb_env_open doc Clarify mdb_dbi_open doc LMDB 0.9.14 Release (2014/09/20) Fix to support 64K page size (ITS#7713) Fix to persist decreased as well as increased mapsizes (ITS#7789) Fix cursor bug when deleting last node of a DUPSORT key Fix mdb_env_info to return FIXEDMAP address Fix ambiguous error code from writing to closed DBI (ITS#7825) Fix mdb_copy copying past end of file (ITS#7886) Fix cursor bugs from page_merge/rebalance Fix to dirty fewer pages in deletes (mdb_page_loose()) Fix mdb_dbi_open creating subDBs (ITS#7917) Fix mdb_cursor_get(_DUP) with single value (ITS#7913) Fix Windows compat issues in mtests (ITS#7879) Add compacting variant of mdb_copy Add BigEndian integer key compare code Add mdb_dump/mdb_load utilities LMDB 0.9.13 Release (2014/06/18) Fix mdb_page_alloc unlimited overflow page search Documentation Re-fix MDB_CURRENT doc (ITS#7793) Fix MDB_GET_MULTIPLE/MDB_NEXT_MULTIPLE doc LMDB 0.9.12 Release (2014/06/13) Fix MDB_GET_BOTH regression (ITS#7875,#7681) Fix MDB_MULTIPLE writing multiple keys (ITS#7834) Fix mdb_rebalance (ITS#7829) Fix mdb_page_split (ITS#7815) Fix md_entries count (ITS#7861,#7828,#7793) Fix MDB_CURRENT (ITS#7793) Fix possible crash on Windows DLL detach Misc code cleanup Documentation mdb_cursor_put: cursor moves on error (ITS#7771) LMDB 0.9.11 Release (2014/01/15) Add mdb_env_set_assert() (ITS#7775) Fix: invalidate txn on page allocation errors (ITS#7377) Fix xcursor tracking in mdb_cursor_del0() (ITS#7771) Fix corruption from deletes (ITS#7756) Fix Windows/MSVC build issues Raise safe limit of max MDB_MAXKEYSIZE Misc code cleanup Documentation Remove spurious note about non-overlapping flags (ITS#7665) LMDB 0.9.10 Release (2013/11/12) Add MDB_NOMEMINIT option Fix mdb_page_split() again (ITS#7589) Fix MDB_NORDAHEAD definition (ITS#7734) Fix mdb_cursor_del() positioning (ITS#7733) Partial fix for larger page sizes (ITS#7713) Fix Windows64/MSVC build issues LMDB 0.9.9 Release (2013/10/24) Add mdb_env_get_fd() Add MDB_NORDAHEAD option Add MDB_NOLOCK option Avoid wasting space in mdb_page_split() (ITS#7589) Fix mdb_page_merge() cursor fixup (ITS#7722) Fix mdb_cursor_del() on last delete (ITS#7718) Fix adding WRITEMAP on existing env (ITS#7715) Fix nested txns (ITS#7515) Fix mdb_env_copy() O_DIRECT bug (ITS#7682) Fix mdb_cursor_set(SET_RANGE) return code (ITS#7681) Fix mdb_rebalance() cursor fixup (ITS#7701) Misc code cleanup Documentation Note that by default, readers need write access LMDB 0.9.8 Release (2013/09/09) Allow mdb_env_set_mapsize() on an open environment Fix mdb_dbi_flags() (ITS#7672) Fix mdb_page_unspill() in nested txns Fix mdb_cursor_get(CURRENT|NEXT) after a delete Fix mdb_cursor_get(DUP) to always return key (ITS#7671) Fix mdb_cursor_del() to always advance to next item (ITS#7670) Fix mdb_cursor_set(SET_RANGE) for tree with single page (ITS#7681) Fix mdb_env_copy() retry open if O_DIRECT fails (ITS#7682) Tweak mdb_page_spill() to be less aggressive Documentation Update caveats since mdb_reader_check() added in 0.9.7 LMDB 0.9.7 Release (2013/08/17) Don't leave stale lockfile on failed RDONLY open (ITS#7664) Fix mdb_page_split() ref beyond cursor depth Fix read txn data race (ITS#7635) Fix mdb_rebalance (ITS#7536, #7538) Fix mdb_drop() (ITS#7561) Misc DEBUG macro fixes Add MDB_NOTLS envflag Add mdb_env_copyfd() Add mdb_txn_env() (ITS#7660) Add mdb_dbi_flags() (ITS#7661) Add mdb_env_get_maxkeysize() Add mdb_env_reader_list()/mdb_env_reader_check() Add mdb_page_spill/unspill, remove hard txn size limit Use shorter names for semaphores (ITS#7615) Build Fix install target (ITS#7656) Documentation Misc updates for cursors, DB handles, data lifetime LMDB 0.9.6 Release (2013/02/25) Many fixes/enhancements LMDB 0.9.5 Release (2012/11/30) Renamed from libmdb to liblmdb Many fixes/enhancements openldap-2.5.11+dfsg/libraries/liblmdb/mdb_stat.10000644000175000017500000000336414172327167020305 0ustar ryanryan.TH MDB_STAT 1 "2015/09/30" "LMDB 0.9.17" .\" Copyright 2012-2021 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME mdb_stat \- LMDB environment status tool .SH SYNOPSIS .B mdb_stat [\c .BR \-V ] [\c .BR \-e ] [\c .BR \-f [ f [ f ]]] [\c .BR \-n ] [\c .BR \-r [ r ]] [\c .BR \-a \ | .BI \-s \ subdb\fR] .BR \ envpath .SH DESCRIPTION The .B mdb_stat utility displays the status of an LMDB environment. .SH OPTIONS .TP .BR \-V Write the library version number to the standard output, and exit. .TP .BR \-e Display information about the database environment. .TP .BR \-f Display information about the environment freelist. If \fB\-ff\fP is given, summarize each freelist entry. If \fB\-fff\fP is given, display the full list of page IDs in the freelist. .TP .BR \-n Display the status of an LMDB database which does not use subdirectories. .TP .BR \-r Display information about the environment reader table. Shows the process ID, thread ID, and transaction ID for each active reader slot. The process ID and transaction ID are in decimal, the thread ID is in hexadecimal. The transaction ID is displayed as "-" if the reader does not currently have a read transaction open. If \fB\-rr\fP is given, check for stale entries in the reader table and clear them. The reader table will be printed again after the check is performed. .TP .BR \-a Display the status of all of the subdatabases in the environment. .TP .BR \-s \ subdb Display the status of a specific subdatabase. .SH DIAGNOSTICS Exit status is zero if no errors occur. Errors result in a non-zero exit status and a diagnostic message being written to standard error. .SH "SEE ALSO" .BR mdb_copy (1) .SH AUTHOR Howard Chu of Symas Corporation openldap-2.5.11+dfsg/libraries/liblmdb/mdb_stat.c0000644000175000017500000001440114172327167020361 0ustar ryanryan/* mdb_stat.c - memory-mapped database status tool */ /* * Copyright 2011-2021 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include #include #include #include #include "lmdb.h" #ifdef _WIN32 #define Z "I" #else #define Z "z" #endif static void prstat(MDB_stat *ms) { #if 0 printf(" Page size: %u\n", ms->ms_psize); #endif printf(" Tree depth: %u\n", ms->ms_depth); printf(" Branch pages: %"Z"u\n", ms->ms_branch_pages); printf(" Leaf pages: %"Z"u\n", ms->ms_leaf_pages); printf(" Overflow pages: %"Z"u\n", ms->ms_overflow_pages); printf(" Entries: %"Z"u\n", ms->ms_entries); } static void usage(char *prog) { fprintf(stderr, "usage: %s [-V] [-n] [-e] [-r[r]] [-f[f[f]]] [-a|-s subdb] dbpath\n", prog); exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { int i, rc; MDB_env *env; MDB_txn *txn; MDB_dbi dbi; MDB_stat mst; MDB_envinfo mei; char *prog = argv[0]; char *envname; char *subname = NULL; int alldbs = 0, envinfo = 0, envflags = 0, freinfo = 0, rdrinfo = 0; if (argc < 2) { usage(prog); } /* -a: print stat of main DB and all subDBs * -s: print stat of only the named subDB * -e: print env info * -f: print freelist info * -r: print reader info * -n: use NOSUBDIR flag on env_open * -V: print version and exit * (default) print stat of only the main DB */ while ((i = getopt(argc, argv, "Vaefnrs:")) != EOF) { switch(i) { case 'V': printf("%s\n", MDB_VERSION_STRING); exit(0); break; case 'a': if (subname) usage(prog); alldbs++; break; case 'e': envinfo++; break; case 'f': freinfo++; break; case 'n': envflags |= MDB_NOSUBDIR; break; case 'r': rdrinfo++; break; case 's': if (alldbs) usage(prog); subname = optarg; break; default: usage(prog); } } if (optind != argc - 1) usage(prog); envname = argv[optind]; rc = mdb_env_create(&env); if (rc) { fprintf(stderr, "mdb_env_create failed, error %d %s\n", rc, mdb_strerror(rc)); return EXIT_FAILURE; } if (alldbs || subname) { mdb_env_set_maxdbs(env, 4); } rc = mdb_env_open(env, envname, envflags | MDB_RDONLY, 0664); if (rc) { fprintf(stderr, "mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc)); goto env_close; } if (envinfo) { (void)mdb_env_stat(env, &mst); (void)mdb_env_info(env, &mei); printf("Environment Info\n"); printf(" Map address: %p\n", mei.me_mapaddr); printf(" Map size: %"Z"u\n", mei.me_mapsize); printf(" Page size: %u\n", mst.ms_psize); printf(" Max pages: %"Z"u\n", mei.me_mapsize / mst.ms_psize); printf(" Number of pages used: %"Z"u\n", mei.me_last_pgno+1); printf(" Last transaction ID: %"Z"u\n", mei.me_last_txnid); printf(" Max readers: %u\n", mei.me_maxreaders); printf(" Number of readers used: %u\n", mei.me_numreaders); } if (rdrinfo) { printf("Reader Table Status\n"); rc = mdb_reader_list(env, (MDB_msg_func *)fputs, stdout); if (rdrinfo > 1) { int dead; mdb_reader_check(env, &dead); printf(" %d stale readers cleared.\n", dead); rc = mdb_reader_list(env, (MDB_msg_func *)fputs, stdout); } if (!(subname || alldbs || freinfo)) goto env_close; } rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn); if (rc) { fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc)); goto env_close; } if (freinfo) { MDB_cursor *cursor; MDB_val key, data; size_t pages = 0, *iptr; printf("Freelist Status\n"); dbi = 0; rc = mdb_cursor_open(txn, dbi, &cursor); if (rc) { fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc)); goto txn_abort; } rc = mdb_stat(txn, dbi, &mst); if (rc) { fprintf(stderr, "mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc)); goto txn_abort; } prstat(&mst); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { iptr = data.mv_data; pages += *iptr; if (freinfo > 1) { char *bad = ""; size_t pg, prev; ssize_t i, j, span = 0; j = *iptr++; for (i = j, prev = 1; --i >= 0; ) { pg = iptr[i]; if (pg <= prev) bad = " [bad sequence]"; prev = pg; pg += span; for (; i >= span && iptr[i-span] == pg; span++, pg++) ; } printf(" Transaction %"Z"u, %"Z"d pages, maxspan %"Z"d%s\n", *(size_t *)key.mv_data, j, span, bad); if (freinfo > 2) { for (--j; j >= 0; ) { pg = iptr[j]; for (span=1; --j >= 0 && iptr[j] == pg+span; span++) ; printf(span>1 ? " %9"Z"u[%"Z"d]\n" : " %9"Z"u\n", pg, span); } } } } mdb_cursor_close(cursor); printf(" Free pages: %"Z"u\n", pages); } rc = mdb_open(txn, subname, 0, &dbi); if (rc) { fprintf(stderr, "mdb_open failed, error %d %s\n", rc, mdb_strerror(rc)); goto txn_abort; } rc = mdb_stat(txn, dbi, &mst); if (rc) { fprintf(stderr, "mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc)); goto txn_abort; } printf("Status of %s\n", subname ? subname : "Main DB"); prstat(&mst); if (alldbs) { MDB_cursor *cursor; MDB_val key; rc = mdb_cursor_open(txn, dbi, &cursor); if (rc) { fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc)); goto txn_abort; } while ((rc = mdb_cursor_get(cursor, &key, NULL, MDB_NEXT_NODUP)) == 0) { char *str; MDB_dbi db2; if (memchr(key.mv_data, '\0', key.mv_size)) continue; str = malloc(key.mv_size+1); memcpy(str, key.mv_data, key.mv_size); str[key.mv_size] = '\0'; rc = mdb_open(txn, str, 0, &db2); if (rc == MDB_SUCCESS) printf("Status of %s\n", str); free(str); if (rc) continue; rc = mdb_stat(txn, db2, &mst); if (rc) { fprintf(stderr, "mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc)); goto txn_abort; } prstat(&mst); mdb_close(env, db2); } mdb_cursor_close(cursor); } if (rc == MDB_NOTFOUND) rc = MDB_SUCCESS; mdb_close(env, dbi); txn_abort: mdb_txn_abort(txn); env_close: mdb_env_close(env); return rc ? EXIT_FAILURE : EXIT_SUCCESS; } openldap-2.5.11+dfsg/libraries/liblmdb/sample-mdb.txt0000644000175000017500000000320414172327167021201 0ustar ryanryan/* sample-mdb.txt - MDB toy/sample * * Do a line-by-line comparison of this and sample-bdb.txt */ /* * Copyright 2012-2021 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include #include "lmdb.h" int main(int argc,char * argv[]) { int rc; MDB_env *env; MDB_dbi dbi; MDB_val key, data; MDB_txn *txn; MDB_cursor *cursor; char sval[32]; /* Note: Most error checking omitted for simplicity */ rc = mdb_env_create(&env); rc = mdb_env_open(env, "./testdb", 0, 0664); rc = mdb_txn_begin(env, NULL, 0, &txn); rc = mdb_dbi_open(txn, NULL, 0, &dbi); key.mv_size = sizeof(int); key.mv_data = sval; data.mv_size = sizeof(sval); data.mv_data = sval; sprintf(sval, "%03x %d foo bar", 32, 3141592); rc = mdb_put(txn, dbi, &key, &data, 0); rc = mdb_txn_commit(txn); if (rc) { fprintf(stderr, "mdb_txn_commit: (%d) %s\n", rc, mdb_strerror(rc)); goto leave; } rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn); rc = mdb_cursor_open(txn, dbi, &cursor); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { printf("key: %p %.*s, data: %p %.*s\n", key.mv_data, (int) key.mv_size, (char *) key.mv_data, data.mv_data, (int) data.mv_size, (char *) data.mv_data); } mdb_cursor_close(cursor); mdb_txn_abort(txn); leave: mdb_dbi_close(env, dbi); mdb_env_close(env); return 0; } openldap-2.5.11+dfsg/libraries/liblber/0000755000175000017500000000000014172327167016426 5ustar ryanryanopenldap-2.5.11+dfsg/libraries/liblber/decode.c0000644000175000017500000005261514172327167020026 0ustar ryanryan/* decode.c - ber input decoding routines */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ /* ACKNOWLEDGEMENTS: * This work was originally developed by the University of Michigan * (as part of U-MICH LDAP). */ #include "portable.h" #include #include #include #include #include #include "lber-int.h" /* out->bv_len should be the buffer size on input */ int ber_decode_oid( BerValue *in, BerValue *out ) { const unsigned char *der; unsigned long val; unsigned val1; ber_len_t i; char *ptr; assert( in != NULL ); assert( out != NULL ); /* need 4 chars/inbyte + \0 for input={7f 7f 7f...} */ if ( !out->bv_val || (out->bv_len+3)/4 <= in->bv_len ) return -1; ptr = NULL; der = (unsigned char *) in->bv_val; val = 0; for ( i=0; i < in->bv_len; i++ ) { val |= der[i] & 0x7f; if ( !( der[i] & 0x80 )) { if ( ptr == NULL ) { /* Initial "x.y": val=x*40+y, x<=2, y<40 if x<2 */ ptr = out->bv_val; val1 = (val < 80 ? val/40 : 2); val -= val1*40; ptr += sprintf( ptr, "%u", val1 ); } ptr += sprintf( ptr, ".%lu", val ); val = 0; } else if ( val - 1UL < LBER_OID_COMPONENT_MAX >> 7 ) { val <<= 7; } else { /* val would overflow, or is 0 from invalid initial 0x80 octet */ return -1; } } if ( ptr == NULL || val != 0 ) return -1; out->bv_len = ptr - out->bv_val; return 0; } /* Return tag, with *bv = rest of element (starting at length octets) */ static ber_tag_t ber_tag_and_rest( const BerElement *ber, struct berval *bv ) { ber_tag_t tag; ptrdiff_t rest; unsigned char *ptr; assert( ber != NULL ); assert( LBER_VALID( ber ) ); ptr = (unsigned char *) ber->ber_ptr; rest = (unsigned char *) ber->ber_end - ptr; if ( rest <= 0 ) { goto fail; } tag = ber->ber_tag; if ( (char *) ptr == ber->ber_buf ) { tag = *ptr; } ptr++; rest--; if ( (tag & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) { goto done; } do { if ( rest <= 0 ) { break; } tag <<= 8; tag |= *ptr++ & 0xffU; rest--; if ( ! (tag & LBER_MORE_TAG_MASK) ) { goto done; } } while ( tag <= (ber_tag_t)-1 / 256 ); fail: /* Error or unsupported tag size */ tag = LBER_DEFAULT; done: bv->bv_len = rest; bv->bv_val = (char *) ptr; return tag; } /* Return the tag - LBER_DEFAULT returned means trouble */ ber_tag_t ber_get_tag( BerElement *ber ) { struct berval bv; ber_tag_t tag = ber_tag_and_rest( ber, &bv ); ber->ber_ptr = bv.bv_val; return tag; } /* Return next element's tag and point *bv at its contents in-place */ ber_tag_t ber_peek_element( const BerElement *ber, struct berval *bv ) { ber_tag_t tag; ber_len_t len, rest; unsigned i; unsigned char *ptr; assert( bv != NULL ); /* * Any ber element looks like this: tag length contents. * Assuming everything's ok, we return the tag, and point * bv at the contents. * * Assumptions: * 1) definite lengths * 2) primitive encodings used whenever possible */ len = 0; /* * First, we read the tag. */ tag = ber_tag_and_rest( ber, bv ); rest = bv->bv_len; ptr = (unsigned char *) bv->bv_val; if ( tag == LBER_DEFAULT || rest == 0 ) { goto fail; } /* * Next, read the length. The first octet determines the length * of the length. If bit 8 is 0, the length is the short form, * otherwise if the octet != 0x80 it's the long form, otherwise * the ber element has the unsupported indefinite-length format. * Lengths that do not fit in a ber_len_t are not accepted. */ len = *ptr++; rest--; if ( len & 0x80U ) { len &= 0x7fU; if ( len - 1U > sizeof(ber_len_t) - 1U || rest < len ) { /* Indefinite-length/too long length/not enough data */ goto fail; } rest -= len; i = len; for( len = *ptr++ & 0xffU; --i; len |= *ptr++ & 0xffU ) { len <<= 8; } } /* BER element should have enough data left */ if( len > rest ) { fail: tag = LBER_DEFAULT; } bv->bv_len = len; bv->bv_val = (char *) ptr; return tag; } /* Move past next element, point *bv at it in-place, and return its tag. * The caller may \0-terminate *bv, as next octet is saved in ber->ber_tag. * Similar to ber_get_stringbv(ber, bv, LBER_BV_NOTERM) except on error. */ ber_tag_t ber_skip_element( BerElement *ber, struct berval *bv ) { ber_tag_t tag = ber_peek_element( ber, bv ); if ( tag != LBER_DEFAULT ) { ber->ber_ptr = bv->bv_val + bv->bv_len; ber->ber_tag = *(unsigned char *) ber->ber_ptr; } return tag; } /* Move past next element, point *bv at the complete element in-place, and * return its tag. The caller may \0-terminate *bv, as next octet is saved in * ber->ber_tag. Similar to ber_skip_element(ber, bv) except the tag+length * header is also included in *bv. */ ber_tag_t ber_skip_raw( BerElement *ber, struct berval *bv ) { char *val = ber->ber_ptr; ber_tag_t tag = ber_skip_element( ber, bv ); if ( tag != LBER_DEFAULT ) { bv->bv_len += bv->bv_val - val; bv->bv_val = val; } return tag; } ber_tag_t ber_peek_tag( BerElement *ber, ber_len_t *len ) { struct berval bv; ber_tag_t tag = ber_peek_element( ber, &bv ); *len = bv.bv_len; return tag; } ber_tag_t ber_skip_tag( BerElement *ber, ber_len_t *lenp ) { struct berval bv; ber_tag_t tag = ber_peek_element( ber, &bv ); ber->ber_ptr = bv.bv_val; ber->ber_tag = *(unsigned char *) ber->ber_ptr; *lenp = bv.bv_len; return tag; } ber_tag_t ber_get_int( BerElement *ber, ber_int_t *num ) { struct berval bv; ber_tag_t tag = ber_skip_element( ber, &bv ); if ( tag == LBER_DEFAULT ) { return tag; } return ber_decode_int( &bv, num ) ? LBER_DEFAULT : tag; } int ber_decode_int( const struct berval *bv, ber_int_t *num ) { ber_len_t len = bv->bv_len; if ( len > sizeof(ber_int_t) ) return -1; assert( num != NULL ); /* parse two's complement integer */ if( len ) { unsigned char *buf = (unsigned char *) bv->bv_val; ber_len_t i; ber_int_t netnum = buf[0] & 0xff; /* sign extend */ netnum = (netnum ^ 0x80) - 0x80; /* shift in the bytes */ for( i = 1; i < len; i++ ) { netnum = (netnum << 8 ) | buf[i]; } *num = netnum; } else { *num = 0; } return 0; } ber_tag_t ber_get_enum( BerElement *ber, ber_int_t *num ) { return ber_get_int( ber, num ); } ber_tag_t ber_get_stringb( BerElement *ber, char *buf, ber_len_t *len ) { struct berval bv; ber_tag_t tag; if ( (tag = ber_skip_element( ber, &bv )) == LBER_DEFAULT ) { return LBER_DEFAULT; } /* must fit within allocated space with termination */ if ( bv.bv_len >= *len ) { return LBER_DEFAULT; } memcpy( buf, bv.bv_val, bv.bv_len ); buf[bv.bv_len] = '\0'; *len = bv.bv_len; return tag; } /* Definitions for get_string vector * * ChArray, BvArray, and BvVec are self-explanatory. * BvOff is a struct berval embedded in an array of larger structures * of siz bytes at off bytes from the beginning of the struct. */ enum bgbvc { ChArray, BvArray, BvVec, BvOff }; /* Use this single cookie for state, to keep actual * stack use to the absolute minimum. */ typedef struct bgbvr { const enum bgbvc choice; const int option; /* (ALLOC unless BvOff) | (STRING if ChArray) */ ber_len_t siz; /* input array element size, output count */ ber_len_t off; /* BvOff offset to the struct berval */ void *result; } bgbvr; static ber_tag_t ber_get_stringbvl( BerElement *ber, bgbvr *b ) { int i = 0, n; ber_tag_t tag; ber_len_t tot_size = 0, siz = b->siz; char *last, *orig; struct berval bv, *bvp = NULL; union stringbvl_u { char **ca; /* ChArray */ BerVarray ba; /* BvArray */ struct berval **bv; /* BvVec */ char *bo; /* BvOff */ } res; tag = ber_skip_tag( ber, &bv.bv_len ); if ( tag != LBER_DEFAULT ) { tag = 0; orig = ber->ber_ptr; last = orig + bv.bv_len; for ( ; ber->ber_ptr < last; i++, tot_size += siz ) { if ( ber_skip_element( ber, &bv ) == LBER_DEFAULT ) break; } if ( ber->ber_ptr != last ) { i = 0; tag = LBER_DEFAULT; } ber->ber_ptr = orig; ber->ber_tag = *(unsigned char *) orig; } b->siz = i; if ( i == 0 ) { return tag; } /* Allocate and NULL-terminate the result vector */ b->result = ber_memalloc_x( tot_size + siz, ber->ber_memctx ); if ( b->result == NULL ) { return LBER_DEFAULT; } switch (b->choice) { case ChArray: res.ca = b->result; res.ca[i] = NULL; break; case BvArray: res.ba = b->result; res.ba[i].bv_val = NULL; break; case BvVec: res.bv = b->result; res.bv[i] = NULL; break; case BvOff: res.bo = (char *) b->result + b->off; ((struct berval *) (res.bo + tot_size))->bv_val = NULL; tot_size = 0; break; } n = 0; do { tag = ber_get_stringbv( ber, &bv, b->option ); if ( tag == LBER_DEFAULT ) { goto failed; } /* store my result */ switch (b->choice) { case ChArray: res.ca[n] = bv.bv_val; break; case BvArray: res.ba[n] = bv; break; case BvVec: bvp = ber_memalloc_x( sizeof( struct berval ), ber->ber_memctx ); if ( !bvp ) { ber_memfree_x( bv.bv_val, ber->ber_memctx ); goto failed; } res.bv[n] = bvp; *bvp = bv; break; case BvOff: *(struct berval *)(res.bo + tot_size) = bv; tot_size += siz; break; } } while (++n < i); return tag; failed: if (b->choice != BvOff) { /* BvOff does not have LBER_BV_ALLOC set */ while (--n >= 0) { switch(b->choice) { case ChArray: ber_memfree_x(res.ca[n], ber->ber_memctx); break; case BvArray: ber_memfree_x(res.ba[n].bv_val, ber->ber_memctx); break; case BvVec: ber_memfree_x(res.bv[n]->bv_val, ber->ber_memctx); ber_memfree_x(res.bv[n], ber->ber_memctx); break; default: break; } } } ber_memfree_x(b->result, ber->ber_memctx); b->result = NULL; return LBER_DEFAULT; } ber_tag_t ber_get_stringbv( BerElement *ber, struct berval *bv, int option ) { ber_tag_t tag; char *data; tag = ber_skip_element( ber, bv ); if ( tag == LBER_DEFAULT || (( option & LBER_BV_STRING ) && bv->bv_len && memchr( bv->bv_val, 0, bv->bv_len - 1 ))) { bv->bv_val = NULL; return LBER_DEFAULT; } data = bv->bv_val; if ( option & LBER_BV_ALLOC ) { bv->bv_val = (char *) ber_memalloc_x( bv->bv_len + 1, ber->ber_memctx ); if ( bv->bv_val == NULL ) { return LBER_DEFAULT; } if ( bv->bv_len != 0 ) { memcpy( bv->bv_val, data, bv->bv_len ); } data = bv->bv_val; } if ( !( option & LBER_BV_NOTERM )) data[bv->bv_len] = '\0'; return tag; } ber_tag_t ber_get_stringbv_null( BerElement *ber, struct berval *bv, int option ) { ber_tag_t tag; char *data; tag = ber_skip_element( ber, bv ); if ( tag == LBER_DEFAULT || bv->bv_len == 0 ) { bv->bv_val = NULL; return tag; } if (( option & LBER_BV_STRING ) && memchr( bv->bv_val, 0, bv->bv_len - 1 )) { bv->bv_val = NULL; return LBER_DEFAULT; } data = bv->bv_val; if ( option & LBER_BV_ALLOC ) { bv->bv_val = (char *) ber_memalloc_x( bv->bv_len + 1, ber->ber_memctx ); if ( bv->bv_val == NULL ) { return LBER_DEFAULT; } memcpy( bv->bv_val, data, bv->bv_len ); data = bv->bv_val; } if ( !( option & LBER_BV_NOTERM )) data[bv->bv_len] = '\0'; return tag; } ber_tag_t ber_get_stringa( BerElement *ber, char **buf ) { BerValue bv; ber_tag_t tag; assert( buf != NULL ); tag = ber_get_stringbv( ber, &bv, LBER_BV_ALLOC | LBER_BV_STRING ); *buf = bv.bv_val; return tag; } ber_tag_t ber_get_stringa_null( BerElement *ber, char **buf ) { BerValue bv; ber_tag_t tag; assert( buf != NULL ); tag = ber_get_stringbv_null( ber, &bv, LBER_BV_ALLOC | LBER_BV_STRING ); *buf = bv.bv_val; return tag; } ber_tag_t ber_get_stringal( BerElement *ber, struct berval **bv ) { ber_tag_t tag; assert( ber != NULL ); assert( bv != NULL ); *bv = (struct berval *) ber_memalloc_x( sizeof(struct berval), ber->ber_memctx ); if ( *bv == NULL ) { return LBER_DEFAULT; } tag = ber_get_stringbv( ber, *bv, LBER_BV_ALLOC ); if ( tag == LBER_DEFAULT ) { ber_memfree_x( *bv, ber->ber_memctx ); *bv = NULL; } return tag; } ber_tag_t ber_get_bitstringa( BerElement *ber, char **buf, ber_len_t *blen ) { ber_tag_t tag; struct berval data; unsigned char unusedbits; assert( buf != NULL ); assert( blen != NULL ); if ( (tag = ber_skip_element( ber, &data )) == LBER_DEFAULT ) { goto fail; } if ( --data.bv_len > (ber_len_t)-1 / 8 ) { goto fail; } unusedbits = *(unsigned char *) data.bv_val++; if ( unusedbits > 7 ) { goto fail; } if ( memchr( data.bv_val, 0, data.bv_len )) { goto fail; } *buf = (char *) ber_memalloc_x( data.bv_len, ber->ber_memctx ); if ( *buf == NULL ) { return LBER_DEFAULT; } memcpy( *buf, data.bv_val, data.bv_len ); *blen = data.bv_len * 8 - unusedbits; return tag; fail: *buf = NULL; return LBER_DEFAULT; } ber_tag_t ber_get_null( BerElement *ber ) { ber_len_t len; ber_tag_t tag = ber_skip_tag( ber, &len ); return( len == 0 ? tag : LBER_DEFAULT ); } ber_tag_t ber_get_boolean( BerElement *ber, ber_int_t *boolval ) { return ber_get_int( ber, boolval ); } ber_tag_t ber_first_element( BerElement *ber, ber_len_t *len, char **last ) { assert( last != NULL ); /* skip the sequence header, use the len to mark where to stop */ if ( ber_skip_tag( ber, len ) == LBER_DEFAULT ) { *last = NULL; return LBER_DEFAULT; } *last = ber->ber_ptr + *len; if ( *len == 0 ) { return LBER_DEFAULT; } return ber_peek_tag( ber, len ); } ber_tag_t ber_next_element( BerElement *ber, ber_len_t *len, LDAP_CONST char *last ) { assert( ber != NULL ); assert( last != NULL ); assert( LBER_VALID( ber ) ); if ( ber->ber_ptr >= last ) { return LBER_DEFAULT; } return ber_peek_tag( ber, len ); } /* VARARGS */ ber_tag_t ber_scanf ( BerElement *ber, LDAP_CONST char *fmt, ... ) { va_list ap; LDAP_CONST char *fmt_reset; char *s, **ss, ***sss; struct berval data, *bval, **bvp, ***bvpp; ber_int_t *i; ber_len_t *l; ber_tag_t *t; ber_tag_t rc; ber_len_t len; va_start( ap, fmt ); assert( ber != NULL ); assert( fmt != NULL ); assert( LBER_VALID( ber ) ); fmt_reset = fmt; if ( ber->ber_debug & (LDAP_DEBUG_TRACE|LDAP_DEBUG_BER)) { ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug, "ber_scanf fmt (%s) ber:\n", fmt ); ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 ); } for ( rc = 0; *fmt && rc != LBER_DEFAULT; fmt++ ) { /* When this is modified, remember to update * the error-cleanup code below accordingly. */ switch ( *fmt ) { case '!': { /* Hook */ BERDecodeCallback *f; void *p; f = va_arg( ap, BERDecodeCallback * ); p = va_arg( ap, void * ); rc = (*f)( ber, p, 0 ); } break; case 'a': /* octet string - allocate storage as needed */ ss = va_arg( ap, char ** ); rc = ber_get_stringa( ber, ss ); break; case 'A': /* octet string - allocate storage as needed, * but return NULL if len == 0 */ ss = va_arg( ap, char ** ); rc = ber_get_stringa_null( ber, ss ); break; case 'b': /* boolean */ i = va_arg( ap, ber_int_t * ); rc = ber_get_boolean( ber, i ); break; case 'B': /* bit string - allocate storage as needed */ ss = va_arg( ap, char ** ); l = va_arg( ap, ber_len_t * ); /* for length, in bits */ rc = ber_get_bitstringa( ber, ss, l ); break; case 'e': /* enumerated */ case 'i': /* integer */ i = va_arg( ap, ber_int_t * ); rc = ber_get_int( ber, i ); break; case 'l': /* length of next item */ l = va_arg( ap, ber_len_t * ); rc = ber_peek_tag( ber, l ); break; case 'm': /* octet string in berval, in-place */ bval = va_arg( ap, struct berval * ); rc = ber_get_stringbv( ber, bval, 0 ); break; case 'M': /* bvoffarray - must include address of * a record len, and record offset. * number of records will be returned thru * len ptr on finish. parsed in-place. */ { bgbvr cookie = { BvOff, 0 }; bvp = va_arg( ap, struct berval ** ); l = va_arg( ap, ber_len_t * ); cookie.siz = *l; cookie.off = va_arg( ap, ber_len_t ); rc = ber_get_stringbvl( ber, &cookie ); *bvp = cookie.result; *l = cookie.siz; break; } case 'n': /* null */ rc = ber_get_null( ber ); break; case 'o': /* octet string in a supplied berval */ bval = va_arg( ap, struct berval * ); rc = ber_get_stringbv( ber, bval, LBER_BV_ALLOC ); break; case 'O': /* octet string - allocate & include length */ bvp = va_arg( ap, struct berval ** ); rc = ber_get_stringal( ber, bvp ); break; case 's': /* octet string - in a buffer */ s = va_arg( ap, char * ); l = va_arg( ap, ber_len_t * ); rc = ber_get_stringb( ber, s, l ); break; case 't': /* tag of next item */ t = va_arg( ap, ber_tag_t * ); *t = rc = ber_peek_tag( ber, &len ); break; case 'T': /* skip tag of next item */ t = va_arg( ap, ber_tag_t * ); *t = rc = ber_skip_tag( ber, &len ); break; case 'v': /* sequence of strings */ { bgbvr cookie = { ChArray, LBER_BV_ALLOC | LBER_BV_STRING, sizeof( char * ) }; rc = ber_get_stringbvl( ber, &cookie ); *(va_arg( ap, char *** )) = cookie.result; break; } case 'V': /* sequence of strings + lengths */ { bgbvr cookie = { BvVec, LBER_BV_ALLOC, sizeof( struct berval * ) }; rc = ber_get_stringbvl( ber, &cookie ); *(va_arg( ap, struct berval *** )) = cookie.result; break; } case 'W': /* bvarray */ { bgbvr cookie = { BvArray, LBER_BV_ALLOC, sizeof( struct berval ) }; rc = ber_get_stringbvl( ber, &cookie ); *(va_arg( ap, struct berval ** )) = cookie.result; break; } case 'x': /* skip the next element - whatever it is */ rc = ber_skip_element( ber, &data ); break; case '{': /* begin sequence */ case '[': /* begin set */ switch ( fmt[1] ) { case 'v': case 'V': case 'W': case 'M': break; default: rc = ber_skip_tag( ber, &len ); break; } break; case '}': /* end sequence */ case ']': /* end set */ break; default: if( ber->ber_debug ) { ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug, "ber_scanf: unknown fmt %c\n", *fmt ); } rc = LBER_DEFAULT; break; } } va_end( ap ); if ( rc == LBER_DEFAULT ) { /* * Error. Reclaim malloced memory that was given to the caller. * Set allocated pointers to NULL, "data length" outvalues to 0. */ va_start( ap, fmt ); for ( ; fmt_reset < fmt; fmt_reset++ ) { switch ( *fmt_reset ) { case '!': { /* Hook */ BERDecodeCallback *f; void *p; f = va_arg( ap, BERDecodeCallback * ); p = va_arg( ap, void * ); (void) (*f)( ber, p, 1 ); } break; case 'a': /* octet string - allocate storage as needed */ case 'A': ss = va_arg( ap, char ** ); ber_memfree_x( *ss, ber->ber_memctx ); *ss = NULL; break; case 'b': /* boolean */ case 'e': /* enumerated */ case 'i': /* integer */ (void) va_arg( ap, ber_int_t * ); break; case 'l': /* length of next item */ *(va_arg( ap, ber_len_t * )) = 0; break; case 'm': /* berval in-place */ bval = va_arg( ap, struct berval * ); BER_BVZERO( bval ); break; case 'M': /* BVoff array in-place */ bvp = va_arg( ap, struct berval ** ); ber_memfree_x( *bvp, ber->ber_memctx ); *bvp = NULL; *(va_arg( ap, ber_len_t * )) = 0; (void) va_arg( ap, ber_len_t ); break; case 'o': /* octet string in a supplied berval */ bval = va_arg( ap, struct berval * ); ber_memfree_x( bval->bv_val, ber->ber_memctx ); BER_BVZERO( bval ); break; case 'O': /* octet string - allocate & include length */ bvp = va_arg( ap, struct berval ** ); ber_bvfree_x( *bvp, ber->ber_memctx ); *bvp = NULL; break; case 's': /* octet string - in a buffer */ (void) va_arg( ap, char * ); *(va_arg( ap, ber_len_t * )) = 0; break; case 't': /* tag of next item */ case 'T': /* skip tag of next item */ (void) va_arg( ap, ber_tag_t * ); break; case 'B': /* bit string - allocate storage as needed */ ss = va_arg( ap, char ** ); ber_memfree_x( *ss, ber->ber_memctx ); *ss = NULL; *(va_arg( ap, ber_len_t * )) = 0; /* for length, in bits */ break; case 'v': /* sequence of strings */ sss = va_arg( ap, char *** ); ber_memvfree_x( (void **) *sss, ber->ber_memctx ); *sss = NULL; break; case 'V': /* sequence of strings + lengths */ bvpp = va_arg( ap, struct berval *** ); ber_bvecfree_x( *bvpp, ber->ber_memctx ); *bvpp = NULL; break; case 'W': /* BerVarray */ bvp = va_arg( ap, struct berval ** ); ber_bvarray_free_x( *bvp, ber->ber_memctx ); *bvp = NULL; break; case 'n': /* null */ case 'x': /* skip the next element - whatever it is */ case '{': /* begin sequence */ case '[': /* begin set */ case '}': /* end sequence */ case ']': /* end set */ break; default: /* format should be good */ assert( 0 ); } } va_end( ap ); } return rc; } openldap-2.5.11+dfsg/libraries/liblber/bprint.c0000644000175000017500000001275714172327167020104 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* * Copyright (c) 1991 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ /* ACKNOWLEDGEMENTS: * This work was originally developed by the University of Michigan * (as part of U-MICH LDAP). */ #include "portable.h" #include #include #include #include #include "lber-int.h" #define ber_log_check(errlvl, loglvl) ((errlvl) & (loglvl)) BER_LOG_FN ber_int_log_proc = NULL; /* * We don't just set ber_pvt_err_file to stderr here, because in NT, * stderr is a symbol imported from a DLL. As such, the compiler * doesn't recognize the symbol as having a constant address. Thus * we set ber_pvt_err_file to stderr later, when it first gets * referenced. */ FILE *ber_pvt_err_file = NULL; /* * ber errno */ BER_ERRNO_FN ber_int_errno_fn = NULL; int * ber_errno_addr(void) { static int ber_int_errno = LBER_ERROR_NONE; if( ber_int_errno_fn ) { return (*ber_int_errno_fn)(); } return &ber_int_errno; } /* * Print stuff */ void ber_error_print( LDAP_CONST char *data ) { assert( data != NULL ); if (!ber_pvt_err_file) ber_pvt_err_file = stderr; fputs( data, ber_pvt_err_file ); /* Print to both streams */ if (ber_pvt_err_file != stderr) { fputs( data, stderr ); fflush( stderr ); } fflush( ber_pvt_err_file ); } BER_LOG_PRINT_FN ber_pvt_log_print = ber_error_print; /* * lber log */ int ber_pvt_log_output( const char *subsystem, int level, const char *fmt, ... ) { char buf[1024]; va_list vl; va_start( vl, fmt ); if ( ber_int_log_proc != NULL ) { ber_int_log_proc( ber_pvt_err_file, subsystem, level, fmt, vl ); } else { int level; ber_get_option( NULL, LBER_OPT_BER_DEBUG, &level ); buf[sizeof(buf) - 1] = '\0'; vsnprintf( buf, sizeof(buf)-1, fmt, vl ); if ( ber_log_check( LDAP_DEBUG_BER, level ) ) { (*ber_pvt_log_print)( buf ); } } va_end(vl); return 1; } int ber_pvt_log_printf( int errlvl, int loglvl, const char *fmt, ... ) { char buf[1024]; va_list ap; assert( fmt != NULL ); if ( !ber_log_check( errlvl, loglvl )) { return 0; } va_start( ap, fmt ); buf[sizeof(buf) - 1] = '\0'; vsnprintf( buf, sizeof(buf)-1, fmt, ap ); va_end(ap); (*ber_pvt_log_print)( buf ); return 1; } #if 0 static int ber_log_puts(int errlvl, int loglvl, char *buf) { assert( buf != NULL ); if ( !ber_log_check( errlvl, loglvl )) { return 0; } (*ber_pvt_log_print)( buf ); return 1; } #endif /* * Print arbitrary stuff, for debugging. */ int ber_log_bprint(int errlvl, int loglvl, const char *data, ber_len_t len ) { assert( data != NULL ); if ( !ber_log_check( errlvl, loglvl )) { return 0; } ber_bprint(data, len); return 1; } void ber_bprint( LDAP_CONST char *data, ber_len_t len ) { static const char hexdig[] = "0123456789abcdef"; #define BP_OFFSET 9 #define BP_GRAPH 60 #define BP_LEN 80 char line[BP_LEN]; ber_len_t i; assert( data != NULL ); /* in case len is zero */ line[0] = '\n'; line[1] = '\0'; for ( i = 0 ; i < len ; i++ ) { int n = i % 16; unsigned off; if( !n ) { if( i ) (*ber_pvt_log_print)( line ); memset( line, ' ', sizeof(line)-2 ); line[sizeof(line)-2] = '\n'; line[sizeof(line)-1] = '\0'; off = i % 0x0ffffU; line[2] = hexdig[0x0f & (off >> 12)]; line[3] = hexdig[0x0f & (off >> 8)]; line[4] = hexdig[0x0f & (off >> 4)]; line[5] = hexdig[0x0f & off]; line[6] = ':'; } off = BP_OFFSET + n*3 + ((n >= 8)?1:0); line[off] = hexdig[0x0f & ( data[i] >> 4 )]; line[off+1] = hexdig[0x0f & data[i]]; off = BP_GRAPH + n + ((n >= 8)?1:0); if ( isprint( (unsigned char) data[i] )) { line[BP_GRAPH + n] = data[i]; } else { line[BP_GRAPH + n] = '.'; } } (*ber_pvt_log_print)( line ); } int ber_log_dump( int errlvl, int loglvl, BerElement *ber, int inout ) { assert( ber != NULL ); assert( LBER_VALID( ber ) ); if ( !ber_log_check( errlvl, loglvl )) { return 0; } ber_dump(ber, inout); return 1; } void ber_dump( BerElement *ber, int inout ) { char buf[132]; ber_len_t len; assert( ber != NULL ); assert( LBER_VALID( ber ) ); if ( inout == 1 ) { len = ber_pvt_ber_remaining(ber); } else { len = ber_pvt_ber_write(ber); } sprintf( buf, "ber_dump: buf=%p ptr=%p end=%p len=%ld\n", ber->ber_buf, ber->ber_ptr, ber->ber_end, (long) len ); (void) (*ber_pvt_log_print)( buf ); ber_bprint( ber->ber_ptr, len ); } typedef struct seqorset Seqorset; /* Exists for binary compatibility with OpenLDAP 2.4.17-- */ int ber_log_sos_dump( int errlvl, int loglvl, Seqorset *sos ) { return 0; } /* Exists for binary compatibility with OpenLDAP 2.4.17-- */ void ber_sos_dump( Seqorset *sos ) { } openldap-2.5.11+dfsg/libraries/liblber/io.c0000644000175000017500000003774314172327167017217 0ustar ryanryan/* io.c - ber general i/o routines */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ /* ACKNOWLEDGEMENTS: * This work was originally developed by the University of Michigan * (as part of U-MICH LDAP). */ #include "portable.h" #include #include #include #include #include #include #include #ifdef HAVE_IO_H #include #endif #include "lber-int.h" #include "ldap_log.h" ber_slen_t ber_skip_data( BerElement *ber, ber_len_t len ) { ber_len_t actuallen, nleft; assert( ber != NULL ); assert( LBER_VALID( ber ) ); nleft = ber_pvt_ber_remaining( ber ); actuallen = nleft < len ? nleft : len; ber->ber_ptr += actuallen; ber->ber_tag = *(unsigned char *)ber->ber_ptr; return( (ber_slen_t) actuallen ); } /* * Read from the ber buffer. The caller must maintain ber->ber_tag. * Do not use to read whole tags. See ber_get_tag() and ber_skip_data(). */ ber_slen_t ber_read( BerElement *ber, char *buf, ber_len_t len ) { ber_len_t actuallen, nleft; assert( ber != NULL ); assert( buf != NULL ); assert( LBER_VALID( ber ) ); nleft = ber_pvt_ber_remaining( ber ); actuallen = nleft < len ? nleft : len; AC_MEMCPY( buf, ber->ber_ptr, actuallen ); ber->ber_ptr += actuallen; return( (ber_slen_t) actuallen ); } /* * Write to the ber buffer. * Note that ber_start_seqorset/ber_put_seqorset() bypass ber_write(). */ ber_slen_t ber_write( BerElement *ber, LDAP_CONST char *buf, ber_len_t len, int zero ) /* nonzero is unsupported from OpenLDAP 2.4.18 */ { char **p; assert( ber != NULL ); assert( buf != NULL ); assert( LBER_VALID( ber ) ); if ( zero != 0 ) { ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug, "%s", "ber_write: nonzero 4th argument not supported\n" ); return( -1 ); } p = ber->ber_sos_ptr == NULL ? &ber->ber_ptr : &ber->ber_sos_ptr; if ( len > (ber_len_t) (ber->ber_end - *p) ) { if ( ber_realloc( ber, len ) != 0 ) return( -1 ); } AC_MEMCPY( *p, buf, len ); *p += len; return( (ber_slen_t) len ); } /* Resize the ber buffer */ int ber_realloc( BerElement *ber, ber_len_t len ) { ber_len_t total, offset, sos_offset, rw_offset; char *buf; assert( ber != NULL ); assert( LBER_VALID( ber ) ); /* leave room for ber_flatten() to \0-terminate ber_buf */ if ( ++len == 0 ) { return( -1 ); } total = ber_pvt_ber_total( ber ); #define LBER_EXBUFSIZ 4060 /* a few words less than 2^N for binary buddy */ #if defined( LBER_EXBUFSIZ ) && LBER_EXBUFSIZ > 0 # ifndef notdef /* don't realloc by small amounts */ total += len < LBER_EXBUFSIZ ? LBER_EXBUFSIZ : len; # else { /* not sure what value this adds. reduce fragmentation? */ ber_len_t have = (total + (LBER_EXBUFSIZE - 1)) / LBER_EXBUFSIZ; ber_len_t need = (len + (LBER_EXBUFSIZ - 1)) / LBER_EXBUFSIZ; total = ( have + need ) * LBER_EXBUFSIZ; } # endif #else total += len; /* realloc just what's needed */ #endif if ( total < len || total > (ber_len_t)-1 / 2 /* max ber_slen_t */ ) { return( -1 ); } buf = ber->ber_buf; offset = ber->ber_ptr - buf; sos_offset = ber->ber_sos_ptr ? ber->ber_sos_ptr - buf : 0; /* if ber_sos_ptr != NULL, it is > ber_buf so that sos_offset > 0 */ rw_offset = ber->ber_rwptr ? ber->ber_rwptr - buf : 0; buf = (char *) ber_memrealloc_x( buf, total, ber->ber_memctx ); if ( buf == NULL ) { return( -1 ); } ber->ber_buf = buf; ber->ber_end = buf + total; ber->ber_ptr = buf + offset; if ( sos_offset ) ber->ber_sos_ptr = buf + sos_offset; if ( ber->ber_rwptr ) ber->ber_rwptr = buf + rw_offset; return( 0 ); } void ber_free_buf( BerElement *ber ) { assert( LBER_VALID( ber ) ); if ( ber->ber_buf) ber_memfree_x( ber->ber_buf, ber->ber_memctx ); ber->ber_buf = NULL; ber->ber_sos_ptr = NULL; ber->ber_valid = LBER_UNINITIALIZED; } void ber_free( BerElement *ber, int freebuf ) { if( ber == NULL ) { LDAP_MEMORY_DEBUG_ASSERT( ber != NULL ); return; } if( freebuf ) ber_free_buf( ber ); ber_memfree_x( (char *) ber, ber->ber_memctx ); } int ber_flush( Sockbuf *sb, BerElement *ber, int freeit ) { return ber_flush2( sb, ber, freeit ? LBER_FLUSH_FREE_ON_SUCCESS : LBER_FLUSH_FREE_NEVER ); } int ber_flush2( Sockbuf *sb, BerElement *ber, int freeit ) { ber_len_t towrite; ber_slen_t rc; assert( sb != NULL ); assert( ber != NULL ); assert( SOCKBUF_VALID( sb ) ); assert( LBER_VALID( ber ) ); if ( ber->ber_rwptr == NULL ) { ber->ber_rwptr = ber->ber_buf; } towrite = ber->ber_ptr - ber->ber_rwptr; if ( sb->sb_debug ) { ber_log_printf( LDAP_DEBUG_TRACE, sb->sb_debug, "ber_flush2: %ld bytes to sd %ld%s\n", towrite, (long) sb->sb_fd, ber->ber_rwptr != ber->ber_buf ? " (re-flush)" : "" ); ber_log_bprint( LDAP_DEBUG_BER, sb->sb_debug, ber->ber_rwptr, towrite ); } while ( towrite > 0 ) { #ifdef LBER_TRICKLE sleep(1); rc = ber_int_sb_write( sb, ber->ber_rwptr, 1 ); #else rc = ber_int_sb_write( sb, ber->ber_rwptr, towrite ); #endif if ( rc <= 0 ) { if ( freeit & LBER_FLUSH_FREE_ON_ERROR ) ber_free( ber, 1 ); return -1; } towrite -= rc; ber->ber_rwptr += rc; } if ( freeit & LBER_FLUSH_FREE_ON_SUCCESS ) ber_free( ber, 1 ); return 0; } BerElement * ber_alloc_t( int options ) { BerElement *ber; ber = (BerElement *) LBER_CALLOC( 1, sizeof(BerElement) ); if ( ber == NULL ) { return NULL; } ber->ber_valid = LBER_VALID_BERELEMENT; ber->ber_tag = LBER_DEFAULT; ber->ber_options = options; ber->ber_debug = ber_int_debug; assert( LBER_VALID( ber ) ); return ber; } BerElement * ber_alloc( void ) /* deprecated */ { return ber_alloc_t( 0 ); } BerElement * der_alloc( void ) /* deprecated */ { return ber_alloc_t( LBER_USE_DER ); } BerElement * ber_dup( BerElement *ber ) { BerElement *new; assert( ber != NULL ); assert( LBER_VALID( ber ) ); if ( (new = ber_alloc_t( ber->ber_options )) == NULL ) { return NULL; } *new = *ber; assert( LBER_VALID( new ) ); return( new ); } void ber_init2( BerElement *ber, struct berval *bv, int options ) { assert( ber != NULL ); (void) memset( (char *)ber, '\0', sizeof( BerElement )); ber->ber_valid = LBER_VALID_BERELEMENT; ber->ber_tag = LBER_DEFAULT; ber->ber_options = (char) options; ber->ber_debug = ber_int_debug; if ( bv != NULL ) { ber->ber_buf = bv->bv_val; ber->ber_ptr = ber->ber_buf; ber->ber_end = ber->ber_buf + bv->bv_len; } assert( LBER_VALID( ber ) ); } /* OLD U-Mich ber_init() */ void ber_init_w_nullc( BerElement *ber, int options ) { ber_init2( ber, NULL, options ); } /* New C-API ber_init() */ /* This function constructs a BerElement containing a copy ** of the data in the bv argument. */ BerElement * ber_init( struct berval *bv ) { BerElement *ber; assert( bv != NULL ); if ( bv == NULL ) { return NULL; } ber = ber_alloc_t( 0 ); if( ber == NULL ) { /* allocation failed */ return NULL; } /* copy the data */ if ( ((ber_len_t) ber_write ( ber, bv->bv_val, bv->bv_len, 0 )) != bv->bv_len ) { /* write failed, so free and return NULL */ ber_free( ber, 1 ); return NULL; } ber_reset( ber, 1 ); /* reset the pointer to the start of the buffer */ return ber; } /* New C-API ber_flatten routine */ /* This routine allocates a struct berval whose contents are a BER ** encoding taken from the ber argument. The bvPtr pointer points to ** the returned berval. ** ** ber_flatten2 is the same, but uses a struct berval passed by ** the caller. If alloc is 0 the returned bv uses the ber buf directly. */ int ber_flatten2( BerElement *ber, struct berval *bv, int alloc ) { assert( bv != NULL ); if ( bv == NULL ) { return -1; } if ( ber == NULL ) { /* ber is null, create an empty berval */ bv->bv_val = NULL; bv->bv_len = 0; } else if ( ber->ber_sos_ptr != NULL ) { /* unmatched "{" and "}" */ return -1; } else { /* copy the berval */ ber_len_t len = ber_pvt_ber_write( ber ); if ( alloc ) { bv->bv_val = (char *) ber_memalloc_x( len + 1, ber->ber_memctx ); if ( bv->bv_val == NULL ) { return -1; } AC_MEMCPY( bv->bv_val, ber->ber_buf, len ); bv->bv_val[len] = '\0'; } else if ( ber->ber_buf != NULL ) { bv->bv_val = ber->ber_buf; bv->bv_val[len] = '\0'; } else { bv->bv_val = ""; } bv->bv_len = len; } return 0; } int ber_flatten( BerElement *ber, struct berval **bvPtr) { struct berval *bv; int rc; assert( bvPtr != NULL ); if(bvPtr == NULL) { return -1; } bv = ber_memalloc_x( sizeof(struct berval), ber->ber_memctx ); if ( bv == NULL ) { return -1; } rc = ber_flatten2(ber, bv, 1); if (rc == -1) { ber_memfree_x(bv, ber->ber_memctx); } else { *bvPtr = bv; } return rc; } void ber_reset( BerElement *ber, int was_writing ) { assert( ber != NULL ); assert( LBER_VALID( ber ) ); if ( was_writing ) { ber->ber_end = ber->ber_ptr; ber->ber_ptr = ber->ber_buf; } else { ber->ber_ptr = ber->ber_end; } ber->ber_rwptr = NULL; } /* * A rewrite of ber_get_next that can safely be called multiple times * for the same packet. It will simply continue where it stopped until * a full packet is read. */ #define LENSIZE 4 ber_tag_t ber_get_next( Sockbuf *sb, ber_len_t *len, BerElement *ber ) { assert( sb != NULL ); assert( len != NULL ); assert( ber != NULL ); assert( SOCKBUF_VALID( sb ) ); assert( LBER_VALID( ber ) ); if ( ber->ber_debug & LDAP_DEBUG_TRACE ) { ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug, "ber_get_next\n" ); } /* * Any ber element looks like this: tag length contents. * Assuming everything's ok, we return the tag byte (we * can assume a single byte), return the length in len, * and the rest of the undecoded element in buf. * * Assumptions: * 1) small tags (less than 128) * 2) definite lengths * 3) primitive encodings used whenever possible * * The code also handles multi-byte tags. The first few bytes * of the message are read to check for multi-byte tags and * lengths. These bytes are temporarily stored in the ber_tag, * ber_len, and ber_usertag fields of the berelement until * tag/len parsing is complete. After this parsing, any leftover * bytes and the rest of the message are copied into the ber_buf. * * We expect tag and len to be at most 32 bits wide. */ if (ber->ber_rwptr == NULL) { assert( ber->ber_buf == NULL ); ber->ber_rwptr = (char *) &ber->ber_len-1; ber->ber_ptr = ber->ber_rwptr; ber->ber_tag = 0; } while (ber->ber_rwptr > (char *)&ber->ber_tag && ber->ber_rwptr < (char *)&ber->ber_len + LENSIZE*2) { ber_slen_t sblen; char buf[sizeof(ber->ber_len)-1]; ber_len_t tlen = 0; /* The tag & len can be at most 9 bytes; we try to read up to 8 here */ sock_errset(0); sblen=((char *)&ber->ber_len + LENSIZE*2 - 1)-ber->ber_rwptr; /* Trying to read the last len byte of a 9 byte tag+len */ if (sblen<1) sblen = 1; sblen=ber_int_sb_read( sb, ber->ber_rwptr, sblen ); if (sblen<=0) return LBER_DEFAULT; ber->ber_rwptr += sblen; /* We got at least one byte, try to parse the tag. */ if (ber->ber_ptr == (char *)&ber->ber_len-1) { ber_tag_t tag; unsigned char *p = (unsigned char *)ber->ber_ptr; tag = *p++; if ((tag & LBER_BIG_TAG_MASK) == LBER_BIG_TAG_MASK) { ber_len_t i; for (i=1; (char *)pber_rwptr; i++) { tag <<= 8; tag |= *p++; if (!(tag & LBER_MORE_TAG_MASK)) break; /* Is the tag too big? */ if (i == sizeof(ber_tag_t)-1) { sock_errset(ERANGE); return LBER_DEFAULT; } } /* Did we run out of bytes? */ if ((char *)p == ber->ber_rwptr) { sock_errset(EWOULDBLOCK); return LBER_DEFAULT; } } ber->ber_tag = tag; ber->ber_ptr = (char *)p; } if ( ber->ber_ptr == ber->ber_rwptr ) { sock_errset(EWOULDBLOCK); return LBER_DEFAULT; } /* Now look for the length */ if (*ber->ber_ptr & 0x80) { /* multi-byte */ int i; unsigned char *p = (unsigned char *)ber->ber_ptr; int llen = *p++ & 0x7f; if (llen > LENSIZE) { sock_errset(ERANGE); return LBER_DEFAULT; } /* Not enough bytes? */ if (ber->ber_rwptr - (char *)p < llen) { sock_errset(EWOULDBLOCK); return LBER_DEFAULT; } for (i=0; iber_ptr = (char *)p; } else { tlen = *(unsigned char *)ber->ber_ptr++; } /* Are there leftover data bytes inside ber->ber_len? */ if (ber->ber_ptr < (char *)&ber->ber_usertag) { if (ber->ber_rwptr < (char *)&ber->ber_usertag) { sblen = ber->ber_rwptr - ber->ber_ptr; } else { sblen = (char *)&ber->ber_usertag - ber->ber_ptr; } AC_MEMCPY(buf, ber->ber_ptr, sblen); ber->ber_ptr += sblen; } else { sblen = 0; } ber->ber_len = tlen; /* now fill the buffer. */ /* make sure length is reasonable */ if ( ber->ber_len == 0 ) { sock_errset(ERANGE); return LBER_DEFAULT; } if ( sb->sb_max_incoming && ber->ber_len > sb->sb_max_incoming ) { ber_log_printf( LDAP_DEBUG_CONNS, ber->ber_debug, "ber_get_next: sockbuf_max_incoming exceeded " "(%ld > %ld)\n", ber->ber_len, sb->sb_max_incoming ); sock_errset(ERANGE); return LBER_DEFAULT; } if (ber->ber_buf==NULL) { ber_len_t l = ber->ber_rwptr - ber->ber_ptr; /* ber->ber_ptr is always <= ber->ber->ber_rwptr. * make sure ber->ber_len agrees with what we've * already read. */ if ( ber->ber_len < sblen + l ) { sock_errset(ERANGE); return LBER_DEFAULT; } ber->ber_buf = (char *) ber_memalloc_x( ber->ber_len + 1, ber->ber_memctx ); if (ber->ber_buf==NULL) { return LBER_DEFAULT; } ber->ber_end = ber->ber_buf + ber->ber_len; if (sblen) { AC_MEMCPY(ber->ber_buf, buf, sblen); } if (l > 0) { AC_MEMCPY(ber->ber_buf + sblen, ber->ber_ptr, l); sblen += l; } *ber->ber_end = '\0'; ber->ber_ptr = ber->ber_buf; ber->ber_usertag = 0; if ((ber_len_t)sblen == ber->ber_len) { goto done; } ber->ber_rwptr = ber->ber_buf + sblen; } } if ((ber->ber_rwptr>=ber->ber_buf) && (ber->ber_rwptrber_end)) { ber_slen_t res; ber_slen_t to_go; to_go = ber->ber_end - ber->ber_rwptr; /* unsigned/signed overflow */ if (to_go<0) return LBER_DEFAULT; sock_errset(0); res = ber_int_sb_read( sb, ber->ber_rwptr, to_go ); if (res<=0) return LBER_DEFAULT; ber->ber_rwptr+=res; if (resber_rwptr = NULL; *len = ber->ber_len; if ( ber->ber_debug ) { ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug, "ber_get_next: tag 0x%lx len %ld contents:\n", ber->ber_tag, ber->ber_len ); ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 ); } return (ber->ber_tag); } /* invalid input */ return LBER_DEFAULT; } char * ber_start( BerElement* ber ) { return ber->ber_buf; } int ber_len( BerElement* ber ) { return ( ber->ber_end - ber->ber_buf ); } int ber_ptrlen( BerElement* ber ) { return ( ber->ber_ptr - ber->ber_buf ); } void ber_rewind ( BerElement * ber ) { ber->ber_rwptr = NULL; ber->ber_sos_ptr = NULL; ber->ber_end = ber->ber_ptr; ber->ber_ptr = ber->ber_buf; #if 0 /* TODO: Should we add this? */ ber->ber_tag = LBER_DEFAULT; ber->ber_usertag = 0; #endif } int ber_remaining( BerElement * ber ) { return ber_pvt_ber_remaining( ber ); } openldap-2.5.11+dfsg/libraries/liblber/options.c0000644000175000017500000001333214172327167020267 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include "lber-int.h" char ber_pvt_opt_on; /* used to get a non-NULL address for *_OPT_ON */ struct lber_options ber_int_options = { LBER_UNINITIALIZED, 0, 0 }; static BerMemoryFunctions ber_int_memory_fns_datum; int ber_get_option( void *item, int option, void *outvalue) { const BerElement *ber; const Sockbuf *sb; if(outvalue == NULL) { /* no place to get to */ ber_errno = LBER_ERROR_PARAM; return LBER_OPT_ERROR; } if(item == NULL) { switch ( option ) { case LBER_OPT_BER_DEBUG: * (int *) outvalue = ber_int_debug; return LBER_OPT_SUCCESS; case LBER_OPT_MEMORY_INUSE: /* The memory inuse is a global variable on kernel implementations. * This means that memory debug is shared by all LDAP processes * so for this variable to have much meaning, only one LDAP process * should be running and memory inuse should be initialized to zero * using the lber_set_option() function during startup. * The counter is not accurate for multithreaded ldap applications. */ #ifdef LDAP_MEMORY_DEBUG * (int *) outvalue = ber_int_meminuse; return LBER_OPT_SUCCESS; #else return LBER_OPT_ERROR; #endif case LBER_OPT_LOG_PRINT_FILE: *((FILE**)outvalue) = (FILE*)ber_pvt_err_file; return LBER_OPT_SUCCESS; case LBER_OPT_LOG_PRINT_FN: *(BER_LOG_PRINT_FN *)outvalue = ber_pvt_log_print; return LBER_OPT_SUCCESS; } ber_errno = LBER_ERROR_PARAM; return LBER_OPT_ERROR; } ber = item; sb = item; switch(option) { case LBER_OPT_BER_OPTIONS: assert( LBER_VALID( ber ) ); * (int *) outvalue = ber->ber_options; return LBER_OPT_SUCCESS; case LBER_OPT_BER_DEBUG: assert( LBER_VALID( ber ) ); * (int *) outvalue = ber->ber_debug; return LBER_OPT_SUCCESS; case LBER_OPT_BER_REMAINING_BYTES: assert( LBER_VALID( ber ) ); *((ber_len_t *) outvalue) = ber_pvt_ber_remaining(ber); return LBER_OPT_SUCCESS; case LBER_OPT_BER_TOTAL_BYTES: assert( LBER_VALID( ber ) ); *((ber_len_t *) outvalue) = ber_pvt_ber_total(ber); return LBER_OPT_SUCCESS; case LBER_OPT_BER_BYTES_TO_WRITE: assert( LBER_VALID( ber ) ); *((ber_len_t *) outvalue) = ber_pvt_ber_write(ber); return LBER_OPT_SUCCESS; case LBER_OPT_BER_MEMCTX: assert( LBER_VALID( ber ) ); *((void **) outvalue) = ber->ber_memctx; return LBER_OPT_SUCCESS; default: /* bad param */ ber_errno = LBER_ERROR_PARAM; break; } return LBER_OPT_ERROR; } int ber_set_option( void *item, int option, LDAP_CONST void *invalue) { BerElement *ber; Sockbuf *sb; if(invalue == NULL) { /* no place to set from */ ber_errno = LBER_ERROR_PARAM; return LBER_OPT_ERROR; } if(item == NULL) { switch ( option ) { case LBER_OPT_BER_DEBUG: ber_int_debug = * (const int *) invalue; return LBER_OPT_SUCCESS; case LBER_OPT_LOG_PRINT_FN: ber_pvt_log_print = (BER_LOG_PRINT_FN) invalue; return LBER_OPT_SUCCESS; case LBER_OPT_LOG_PRINT_FILE: ber_pvt_err_file = (void *) invalue; return LBER_OPT_SUCCESS; case LBER_OPT_MEMORY_INUSE: /* The memory inuse is a global variable on kernel implementations. * This means that memory debug is shared by all LDAP processes * so for this variable to have much meaning, only one LDAP process * should be running and memory inuse should be initialized to zero * using the lber_set_option() function during startup. * The counter is not accurate for multithreaded applications. */ #ifdef LDAP_MEMORY_DEBUG ber_int_meminuse = * (int *) invalue; return LBER_OPT_SUCCESS; #else return LBER_OPT_ERROR; #endif case LBER_OPT_MEMORY_FNS: if ( ber_int_memory_fns == NULL ) { const BerMemoryFunctions *f = (const BerMemoryFunctions *) invalue; /* make sure all functions are provided */ if(!( f->bmf_malloc && f->bmf_calloc && f->bmf_realloc && f->bmf_free )) { ber_errno = LBER_ERROR_PARAM; return LBER_OPT_ERROR; } ber_int_memory_fns = &ber_int_memory_fns_datum; AC_MEMCPY(ber_int_memory_fns, f, sizeof(BerMemoryFunctions)); return LBER_OPT_SUCCESS; } break; case LBER_OPT_LOG_PROC: ber_int_log_proc = (BER_LOG_FN)invalue; return LBER_OPT_SUCCESS; } ber_errno = LBER_ERROR_PARAM; return LBER_OPT_ERROR; } ber = item; sb = item; switch(option) { case LBER_OPT_BER_OPTIONS: assert( LBER_VALID( ber ) ); ber->ber_options = * (const int *) invalue; return LBER_OPT_SUCCESS; case LBER_OPT_BER_DEBUG: assert( LBER_VALID( ber ) ); ber->ber_debug = * (const int *) invalue; return LBER_OPT_SUCCESS; case LBER_OPT_BER_REMAINING_BYTES: assert( LBER_VALID( ber ) ); ber->ber_end = &ber->ber_ptr[* (const ber_len_t *) invalue]; return LBER_OPT_SUCCESS; case LBER_OPT_BER_TOTAL_BYTES: assert( LBER_VALID( ber ) ); ber->ber_end = &ber->ber_buf[* (const ber_len_t *) invalue]; return LBER_OPT_SUCCESS; case LBER_OPT_BER_BYTES_TO_WRITE: assert( LBER_VALID( ber ) ); ber->ber_ptr = &ber->ber_buf[* (const ber_len_t *) invalue]; return LBER_OPT_SUCCESS; case LBER_OPT_BER_MEMCTX: assert( LBER_VALID( ber ) ); ber->ber_memctx = *(void **)invalue; return LBER_OPT_SUCCESS; default: /* bad param */ ber_errno = LBER_ERROR_PARAM; break; } return LBER_OPT_ERROR; } openldap-2.5.11+dfsg/libraries/liblber/lber-int.h0000644000175000017500000001446114172327167020321 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ #ifndef _LBER_INT_H #define _LBER_INT_H #include "lber.h" #define LDAP_INT_DEBUG #include "ldap_log.h" #include "lber_pvt.h" #include "ldap_queue.h" LDAP_BEGIN_DECL typedef void (*BER_LOG_FN)(FILE *file, const char *subsys, int level, const char *fmt, ... ); LBER_V (BER_ERRNO_FN) ber_int_errno_fn; #ifdef LDAP_MEMORY_TRACE # ifndef LDAP_MEMORY_DEBUG # define LDAP_MEMORY_DEBUG 1 # endif #endif #ifdef LDAP_MEMORY_DEBUG LBER_V (long) ber_int_meminuse; #endif #if defined(LDAP_MEMORY_DEBUG) && ((LDAP_MEMORY_DEBUG +0) & 2) # define LDAP_MEMORY_DEBUG_ASSERT assert #else # define LDAP_MEMORY_DEBUG_ASSERT(expr) ((void) 0) #endif struct lber_options { short lbo_valid; unsigned short lbo_options; int lbo_debug; }; LBER_F( int ) ber_pvt_log_output( const char *subsystem, int level, const char *fmt, ... ); #define LBER_UNINITIALIZED 0x0 #define LBER_INITIALIZED 0x1 #define LBER_VALID_BERELEMENT 0x2 #define LBER_VALID_SOCKBUF 0x3 LBER_V (struct lber_options) ber_int_options; #define ber_int_debug ber_int_options.lbo_debug /* Data encoded in ASN.1 BER format */ struct berelement { struct lber_options ber_opts; #define ber_valid ber_opts.lbo_valid #define ber_options ber_opts.lbo_options #define ber_debug ber_opts.lbo_debug /* * The members below, when not NULL/LBER_DEFAULT/etc, are: * ber_buf Data buffer. Other pointers normally point into it. * ber_rwptr Read/write cursor for Sockbuf I/O. * ber_memctx Context passed to ber_memalloc() & co. * When decoding data (reading it from the BerElement): * ber_end End of BER data. * ber_ptr Read cursor, except for 1st octet of tags. * ber_tag 1st octet of next tag, saved from *ber_ptr when * ber_ptr may be pointing at a tag and is >ber_buf. * The octet *ber_ptr itself may get overwritten with * a \0, to terminate the preceding element. * When encoding data (writing it to the BerElement): * ber_end End of allocated buffer - 1 (allowing a final \0). * ber_ptr Last complete BER element (normally write cursor). * ber_sos_ptr NULL or write cursor for incomplete sequence or set. * ber_sos_inner offset(seq/set length octets) if ber_sos_ptr!=NULL. * ber_tag Default tag for next ber_printf() element. * ber_usertag Boolean set by ber_printf "!" if it sets ber_tag. * ber_len Reused for ber_sos_inner. * When output to a Sockbuf: * ber_ptr End of encoded data to write. * When input from a Sockbuf: * See ber_get_next(). */ /* Do not change the order of these 3 fields! see ber_get_next */ ber_tag_t ber_tag; ber_len_t ber_len; ber_tag_t ber_usertag; char *ber_buf; char *ber_ptr; char *ber_end; char *ber_sos_ptr; # define ber_sos_inner ber_len /* reused for binary compat */ char *ber_rwptr; void *ber_memctx; }; #define LBER_VALID(ber) ((ber)->ber_valid==LBER_VALID_BERELEMENT) #define ber_pvt_ber_remaining(ber) ((ber)->ber_end - (ber)->ber_ptr) #define ber_pvt_ber_total(ber) ((ber)->ber_end - (ber)->ber_buf) #define ber_pvt_ber_write(ber) ((ber)->ber_ptr - (ber)->ber_buf) struct sockbuf { struct lber_options sb_opts; Sockbuf_IO_Desc *sb_iod; /* I/O functions */ #define sb_valid sb_opts.lbo_valid #define sb_options sb_opts.lbo_options #define sb_debug sb_opts.lbo_debug ber_socket_t sb_fd; ber_len_t sb_max_incoming; unsigned int sb_trans_needs_read:1; unsigned int sb_trans_needs_write:1; #ifdef LDAP_PF_LOCAL_SENDMSG char sb_ungetlen; char sb_ungetbuf[8]; #endif }; #define SOCKBUF_VALID( sb ) ( (sb)->sb_valid == LBER_VALID_SOCKBUF ) /* * decode.c, encode.c */ /* Simplest OID max-DER-component to implement in both decode and encode */ #define LBER_OID_COMPONENT_MAX ((unsigned long)-1 - 128) /* * io.c */ LBER_F( int ) ber_realloc LDAP_P(( BerElement *ber, ber_len_t len )); LBER_F (char *) ber_start LDAP_P(( BerElement * )); LBER_F (int) ber_len LDAP_P(( BerElement * )); LBER_F (int) ber_ptrlen LDAP_P(( BerElement * )); LBER_F (void) ber_rewind LDAP_P(( BerElement * )); /* * bprint.c */ #define ber_log_printf ber_pvt_log_printf LBER_F( int ) ber_log_bprint LDAP_P(( int errlvl, int loglvl, const char *data, ber_len_t len )); LBER_F( int ) ber_log_dump LDAP_P(( int errlvl, int loglvl, BerElement *ber, int inout )); LBER_V (BER_LOG_FN) ber_int_log_proc; LBER_V (FILE *) ber_pvt_err_file; /* memory.c */ /* simple macros to realloc for now */ LBER_V (BerMemoryFunctions *) ber_int_memory_fns; LBER_F (char *) ber_strndup( LDAP_CONST char *, ber_len_t ); LBER_F (char *) ber_strndup_x( LDAP_CONST char *, ber_len_t, void *ctx ); #define LBER_MALLOC(s) ber_memalloc((s)) #define LBER_CALLOC(n,s) ber_memcalloc((n),(s)) #define LBER_REALLOC(p,s) ber_memrealloc((p),(s)) #define LBER_FREE(p) ber_memfree((p)) #define LBER_VFREE(v) ber_memvfree((void**)(v)) #define LBER_STRDUP(s) ber_strdup((s)) #define LBER_STRNDUP(s,l) ber_strndup((s),(l)) /* sockbuf.c */ LBER_F( int ) ber_int_sb_init LDAP_P(( Sockbuf *sb )); LBER_F( int ) ber_int_sb_close LDAP_P(( Sockbuf *sb )); LBER_F( int ) ber_int_sb_destroy LDAP_P(( Sockbuf *sb )); LBER_F( ber_slen_t ) ber_int_sb_read LDAP_P(( Sockbuf *sb, void *buf, ber_len_t len )); LBER_F( ber_slen_t ) ber_int_sb_write LDAP_P(( Sockbuf *sb, void *buf, ber_len_t len )); LDAP_END_DECL #endif /* _LBER_INT_H */ openldap-2.5.11+dfsg/libraries/liblber/idtest.c0000644000175000017500000000445514172327167020076 0ustar ryanryan/* idtest.c - ber decoding test program using isode libraries */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ /* ACKNOWLEDGEMENTS: * This work was originally developed by the University of Michigan * (as part of U-MICH LDAP). */ #include "portable.h" #include #include #ifdef HAVE_PSAP_H #include #include #endif int main( int argc, char **argv ) { #ifdef HAVE_PSAP_H PE pe; PS psin, psout, pserr; /* read the pe from standard in */ if ( (psin = ps_alloc( std_open )) == NULLPS ) { perror( "ps_alloc" ); exit( EXIT_FAILURE ); } if ( std_setup( psin, stdin ) == NOTOK ) { perror( "std_setup" ); exit( EXIT_FAILURE ); } /* write the pe to standard out */ if ( (psout = ps_alloc( std_open )) == NULLPS ) { perror( "ps_alloc" ); exit( EXIT_FAILURE ); } if ( std_setup( psout, stdout ) == NOTOK ) { perror( "std_setup" ); exit( EXIT_FAILURE ); } /* pretty print it to standard error */ if ( (pserr = ps_alloc( std_open )) == NULLPS ) { perror( "ps_alloc" ); exit( EXIT_FAILURE ); } if ( std_setup( pserr, stderr ) == NOTOK ) { perror( "std_setup" ); exit( EXIT_FAILURE ); } while ( (pe = ps2pe( psin )) != NULLPE ) { pe2pl( pserr, pe ); pe2ps( psout, pe ); } exit( EXIT_SUCCESS ); #else fprintf(stderr, "requires ISODE X.500 distribution.\n"); return( EXIT_FAILURE ); #endif } openldap-2.5.11+dfsg/libraries/liblber/stdio.c0000644000175000017500000001400714172327167017716 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #if !defined(HAVE_VSNPRINTF) && !defined(HAVE_EBCDIC) /* Write at most n characters to the buffer in str, return the * number of chars written or -1 if the buffer would have been * overflowed. * * This is portable to any POSIX-compliant system. We use pipe() * to create a valid file descriptor, and then fdopen() it to get * a valid FILE pointer. The user's buffer and size are assigned * to the FILE pointer using setvbuf. Then we close the read side * of the pipe to invalidate the descriptor. * * If the write arguments all fit into size n, the write will * return successfully. If the write is too large, the stdio * buffer will need to be flushed to the underlying file descriptor. * The flush will fail because it is attempting to write to a * broken pipe, and the write will be terminated. * -- hyc, 2002-07-19 */ /* This emulation uses vfprintf; on OS/390 we're also emulating * that function so it's more efficient just to have a separate * version of vsnprintf there. */ #include int ber_pvt_vsnprintf( char *str, size_t n, const char *fmt, va_list ap ) { int fds[2], res; FILE *f; RETSIGTYPE (*sig)(); if (pipe( fds )) return -1; f = fdopen( fds[1], "w" ); if ( !f ) { close( fds[1] ); close( fds[0] ); return -1; } setvbuf( f, str, _IOFBF, n ); sig = signal( SIGPIPE, SIG_IGN ); close( fds[0] ); res = vfprintf( f, fmt, ap ); fclose( f ); signal( SIGPIPE, sig ); if ( res > 0 && res < n ) { res = vsprintf( str, fmt, ap ); } return res; } #endif #ifndef HAVE_SNPRINTF int ber_pvt_snprintf( char *str, size_t n, const char *fmt, ... ) { va_list ap; int res; va_start( ap, fmt ); res = vsnprintf( str, n, fmt, ap ); va_end( ap ); return res; } #endif /* !HAVE_SNPRINTF */ #ifdef HAVE_EBCDIC /* stdio replacements with ASCII/EBCDIC translation for OS/390. * The OS/390 port depends on the CONVLIT compiler option being * used to force character and string literals to be compiled in * ISO8859-1, and the __LIBASCII cpp symbol to be defined to use the * OS/390 ASCII-compatibility library. This library only supplies * an ASCII version of sprintf, so other needed functions are * provided here. * * All of the internal character manipulation is done in ASCII, * but file I/O is EBCDIC, so we catch any stdio reading/writing * of files here and do the translations. */ #undef fputs #undef fgets char *ber_pvt_fgets( char *s, int n, FILE *fp ) { s = (char *)fgets( s, n, fp ); if ( s ) __etoa( s ); return s; } int ber_pvt_fputs( const char *str, FILE *fp ) { char buf[8192]; strncpy( buf, str, sizeof(buf) ); __atoe( buf ); return fputs( buf, fp ); } /* The __LIBASCII doesn't include a working vsprintf, so we make do * using just sprintf. This is a very simplistic parser that looks for * format strings and uses sprintf to process them one at a time. * Literal text is just copied straight to the destination. * The result is appended to the destination string. The parser * recognizes field-width specifiers and the 'l' qualifier; it * may need to be extended to recognize other qualifiers but so * far this seems to be enough. */ int ber_pvt_vsnprintf( char *str, size_t n, const char *fmt, va_list ap ) { char *ptr, *pct, *s2, *f2, *end; char fm2[64]; int len, rem; ptr = (char *)fmt; s2 = str; fm2[0] = '%'; if (n) { end = str + n; } else { end = NULL; } for (pct = strchr(ptr, '%'); pct; pct = strchr(ptr, '%')) { len = pct-ptr; if (end) { rem = end-s2; if (rem < 1) return -1; if (rem < len) len = rem; } s2 = lutil_strncopy( s2, ptr, len ); /* Did we cheat the length above? If so, bail out */ if (len < pct-ptr) return -1; for (pct++, f2 = fm2+1; isdigit(*pct);) *f2++ = *pct++; if (*pct == 'l') *f2++ = *pct++; if (*pct == '%') { *s2++ = '%'; } else { *f2++ = *pct; *f2 = '\0'; if (*pct == 's') { char *ss = va_arg(ap, char *); /* Attempt to limit sprintf output. This * may be thrown off if field widths were * specified for this string. * * If it looks like the string is too * long for the remaining buffer, bypass * sprintf and just copy what fits, then * quit. */ if (end && strlen(ss) > (rem=end-s2)) { strncpy(s2, ss, rem); return -1; } else { s2 += sprintf(s2, fm2, ss); } } else { s2 += sprintf(s2, fm2, va_arg(ap, int)); } } ptr = pct + 1; } if (end) { rem = end-s2; if (rem > 0) { len = strlen(ptr); s2 = lutil_strncopy( s2, ptr, rem ); rem -= len; } if (rem < 0) return -1; } else { s2 = lutil_strcopy( s2, ptr ); } return s2 - str; } int ber_pvt_vsprintf( char *str, const char *fmt, va_list ap ) { return vsnprintf( str, 0, fmt, ap ); } /* The fixed buffer size here is a problem, we don't know how * to flush the buffer and keep printing if the msg is too big. * Hopefully we never try to write something bigger than this * in a log msg... */ int ber_pvt_vfprintf( FILE *fp, const char *fmt, va_list ap ) { char buf[8192]; int res; vsnprintf( buf, sizeof(buf), fmt, ap ); __atoe( buf ); res = fputs( buf, fp ); if (res == EOF) res = -1; return res; } int ber_pvt_printf( const char *fmt, ... ) { va_list ap; int res; va_start( ap, fmt ); res = ber_pvt_vfprintf( stdout, fmt, ap ); va_end( ap ); return res; } int ber_pvt_fprintf( FILE *fp, const char *fmt, ... ) { va_list ap; int res; va_start( ap, fmt ); res = ber_pvt_vfprintf( fp, fmt, ap ); va_end( ap ); return res; } #endif openldap-2.5.11+dfsg/libraries/liblber/Makefile.in0000644000175000017500000000274614172327167020504 0ustar ryanryan# LIBLBER # $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . LIBRARY = liblber.la NT_SRCS = nt_err.c NT_OBJS = nt_err.lo UNIX_SRCS = stdio.c UNIX_OBJS = stdio.lo LIB_DEFS = -DLBER_LIBRARY SRCS= assert.c decode.c encode.c io.c bprint.c debug.c \ memory.c options.c sockbuf.c $(@PLAT@_SRCS) OBJS= assert.lo decode.lo encode.lo io.lo bprint.lo debug.lo \ memory.lo options.lo sockbuf.lo $(@PLAT@_OBJS) XSRCS= version.c PROGRAMS= dtest etest idtest LDAP_INCDIR= ../../include LDAP_LIBDIR= ../../libraries XLIBS = $(LIBRARY) $(LDAP_LIBLUTIL_A) XXLIBS = NT_LINK_LIBS = $(AC_LIBS) UNIX_LINK_LIBS = $(AC_LIBS) ifneq (,$(OL_VERSIONED_SYMBOLS)) SYMBOL_VERSION_FLAGS=$(OL_VERSIONED_SYMBOLS)$(LDAP_LIBDIR)/liblber/liblber.vers endif dtest: $(XLIBS) dtest.o $(LTLINK) -o $@ dtest.o $(LIBS) etest: $(XLIBS) etest.o $(LTLINK) -o $@ etest.o $(LIBS) idtest: $(XLIBS) idtest.o $(LTLINK) -o $@ idtest.o $(LIBS) install-local: FORCE -$(MKDIR) $(DESTDIR)$(libdir) $(LTINSTALL) $(INSTALLFLAGS) -m 644 $(LIBRARY) $(DESTDIR)$(libdir) $(LTFINISH) $(DESTDIR)$(libdir) openldap-2.5.11+dfsg/libraries/liblber/encode.c0000644000175000017500000003643114172327167020036 0ustar ryanryan/* encode.c - ber output encoding routines */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ /* ACKNOWLEDGEMENTS: * This work was originally developed by the University of Michigan * (as part of U-MICH LDAP). */ #include "portable.h" #include #include #include #include #include #include #include #include "lber-int.h" #define OCTET_SIZE(type) ((ber_len_t) (sizeof(type)*CHAR_BIT + 7) / 8) #define TAGBUF_SIZE OCTET_SIZE(ber_tag_t) #define LENBUF_SIZE (1 + OCTET_SIZE(ber_len_t)) #define HEADER_SIZE (TAGBUF_SIZE + LENBUF_SIZE) /* * BER element size constrains: * * - We traditionally support a length of max 0xffffffff. However * some functions return an int length so that is their max. * MAXINT_BERSIZE is the max for those functions. * * - MAXINT_BERSIZE must fit in MAXINT_BERSIZE_OCTETS octets. * * - sizeof(ber_elem_size_t) is normally MAXINT_BERSIZE_OCTETS: * Big enough for MAXINT_BERSIZE, but not more. (Larger wastes * space in the working encoding and DER encoding of a sequence * or set. Smaller further limits sizes near a sequence/set.) * * ber_len_t is mostly unrelated to this. Which may be for the best, * since it is also used for lengths of data that are never encoded. */ #define MAXINT_BERSIZE \ (INT_MAX>0xffffffffUL ? (ber_len_t) 0xffffffffUL : INT_MAX-HEADER_SIZE) #define MAXINT_BERSIZE_OCTETS 4 typedef ber_uint_t ber_elem_size_t; /* normally 32 bits */ /* Prepend tag to ptr, which points to the end of a tag buffer */ static unsigned char * ber_prepend_tag( unsigned char *ptr, ber_tag_t tag ) { do { *--ptr = (unsigned char) tag & 0xffU; } while ( (tag >>= 8) != 0 ); return ptr; } /* Prepend ber length to ptr, which points to the end of a length buffer */ static unsigned char * ber_prepend_len( unsigned char *ptr, ber_len_t len ) { /* * short len if it's less than 128 - one byte giving the len, * with bit 8 0. * long len otherwise - one byte with bit 8 set, giving the * length of the length, followed by the length itself. */ *--ptr = (unsigned char) len & 0xffU; if ( len >= 0x80 ) { unsigned char *endptr = ptr--; while ( (len >>= 8) != 0 ) { *ptr-- = (unsigned char) len & 0xffU; } *ptr = (unsigned char) (endptr - ptr) + 0x80U; } return ptr; } /* out->bv_len should be the buffer size on input */ int ber_encode_oid( BerValue *in, BerValue *out ) { unsigned char *der; unsigned long val1, val; int i, j, len; char *ptr, *end, *inend; assert( in != NULL ); assert( out != NULL ); if ( !out->bv_val || out->bv_len < in->bv_len/2 ) return -1; der = (unsigned char *) out->bv_val; ptr = in->bv_val; inend = ptr + in->bv_len; /* OIDs start with <0-1>.<0-39> or 2., DER-encoded 40*val1+val2 */ if ( !isdigit( (unsigned char) *ptr )) return -1; val1 = strtoul( ptr, &end, 10 ); if ( end == ptr || val1 > 2 ) return -1; if ( *end++ != '.' || !isdigit( (unsigned char) *end )) return -1; val = strtoul( end, &ptr, 10 ); if ( ptr == end ) return -1; if ( val > (val1 < 2 ? 39 : LBER_OID_COMPONENT_MAX - 80) ) return -1; val += val1 * 40; for (;;) { if ( ptr > inend ) return -1; /* Write the OID component little-endian, then reverse it */ len = 0; do { der[len++] = (val & 0xff) | 0x80; } while ( (val >>= 7) != 0 ); der[0] &= 0x7f; for ( i = 0, j = len; i < --j; i++ ) { unsigned char tmp = der[i]; der[i] = der[j]; der[j] = tmp; } der += len; if ( ptr == inend ) break; if ( *ptr++ != '.' ) return -1; if ( !isdigit( (unsigned char) *ptr )) return -1; val = strtoul( ptr, &end, 10 ); if ( end == ptr || val > LBER_OID_COMPONENT_MAX ) return -1; ptr = end; } out->bv_len = (char *)der - out->bv_val; return 0; } static int ber_put_int_or_enum( BerElement *ber, ber_int_t num, ber_tag_t tag ) { ber_uint_t unum; unsigned char sign, data[TAGBUF_SIZE+1 + OCTET_SIZE(ber_int_t)], *ptr; sign = 0; unum = num; /* Bit fiddling should be done with unsigned values */ if ( num < 0 ) { sign = 0xffU; unum = ~unum; } for ( ptr = &data[sizeof(data) - 1] ;; unum >>= 8 ) { *ptr-- = (sign ^ (unsigned char) unum) & 0xffU; if ( unum < 0x80 ) /* top bit at *ptr is sign bit */ break; } *ptr = (unsigned char) (&data[sizeof(data) - 1] - ptr); /* length */ ptr = ber_prepend_tag( ptr, tag ); return ber_write( ber, (char *) ptr, &data[sizeof(data)] - ptr, 0 ); } int ber_put_enum( BerElement *ber, ber_int_t num, ber_tag_t tag ) { if ( tag == LBER_DEFAULT ) { tag = LBER_ENUMERATED; } return ber_put_int_or_enum( ber, num, tag ); } int ber_put_int( BerElement *ber, ber_int_t num, ber_tag_t tag ) { if ( tag == LBER_DEFAULT ) { tag = LBER_INTEGER; } return ber_put_int_or_enum( ber, num, tag ); } int ber_put_ostring( BerElement *ber, LDAP_CONST char *str, ber_len_t len, ber_tag_t tag ) { int rc; unsigned char header[HEADER_SIZE], *ptr; if ( tag == LBER_DEFAULT ) { tag = LBER_OCTETSTRING; } if ( len > MAXINT_BERSIZE ) { return -1; } ptr = ber_prepend_len( &header[sizeof(header)], len ); ptr = ber_prepend_tag( ptr, tag ); rc = ber_write( ber, (char *) ptr, &header[sizeof(header)] - ptr, 0 ); if ( rc >= 0 && ber_write( ber, str, len, 0 ) >= 0 ) { /* length(tag + length + contents) */ return rc + (int) len; } return -1; } int ber_put_berval( BerElement *ber, struct berval *bv, ber_tag_t tag ) { if( bv == NULL || bv->bv_len == 0 ) { return ber_put_ostring( ber, "", (ber_len_t) 0, tag ); } return ber_put_ostring( ber, bv->bv_val, bv->bv_len, tag ); } int ber_put_string( BerElement *ber, LDAP_CONST char *str, ber_tag_t tag ) { assert( str != NULL ); return ber_put_ostring( ber, str, strlen( str ), tag ); } int ber_put_bitstring( BerElement *ber, LDAP_CONST char *str, ber_len_t blen /* in bits */, ber_tag_t tag ) { int rc; ber_len_t len; unsigned char unusedbits, header[HEADER_SIZE + 1], *ptr; if ( tag == LBER_DEFAULT ) { tag = LBER_BITSTRING; } unusedbits = (unsigned char) -blen & 7; len = blen / 8 + (unusedbits != 0); /* (blen+7)/8 without overflow */ if ( len >= MAXINT_BERSIZE ) { return -1; } header[sizeof(header) - 1] = unusedbits; ptr = ber_prepend_len( &header[sizeof(header) - 1], len + 1 ); ptr = ber_prepend_tag( ptr, tag ); rc = ber_write( ber, (char *) ptr, &header[sizeof(header)] - ptr, 0 ); if ( rc >= 0 && ber_write( ber, str, len, 0 ) >= 0 ) { /* length(tag + length + unused bit count + bitstring) */ return rc + (int) len; } return -1; } int ber_put_null( BerElement *ber, ber_tag_t tag ) { unsigned char data[TAGBUF_SIZE + 1], *ptr; if ( tag == LBER_DEFAULT ) { tag = LBER_NULL; } data[sizeof(data) - 1] = 0; /* length */ ptr = ber_prepend_tag( &data[sizeof(data) - 1], tag ); return ber_write( ber, (char *) ptr, &data[sizeof(data)] - ptr, 0 ); } int ber_put_boolean( BerElement *ber, ber_int_t boolval, ber_tag_t tag ) { unsigned char data[TAGBUF_SIZE + 2], *ptr; if ( tag == LBER_DEFAULT ) tag = LBER_BOOLEAN; data[sizeof(data) - 1] = boolval ? 0xff : 0; data[sizeof(data) - 2] = 1; /* length */ ptr = ber_prepend_tag( &data[sizeof(data) - 2], tag ); return ber_write( ber, (char *) ptr, &data[sizeof(data)] - ptr, 0 ); } /* Max number of length octets in a sequence or set, normally 5 */ #define SOS_LENLEN (1 + (sizeof(ber_elem_size_t) > MAXINT_BERSIZE_OCTETS ? \ (ber_len_t) sizeof(ber_elem_size_t) : MAXINT_BERSIZE_OCTETS)) /* Header of incomplete sequence or set */ typedef struct seqorset_header { char xtagbuf[TAGBUF_SIZE + 1]; /* room for tag + len(tag or len) */ union { ber_elem_size_t offset; /* enclosing sequence/set */ char padding[SOS_LENLEN-1]; /* for final length encoding */ } next_sos; # define SOS_TAG_END(header) ((unsigned char *) &(header).next_sos - 1) } Seqorset_header; /* Start a sequence or set */ static int ber_start_seqorset( BerElement *ber, ber_tag_t tag ) { /* * Write the tag and SOS_LENLEN octets reserved for length, to ber. * For now, length octets = (tag length, previous ber_sos_inner). * * Update ber_sos_inner and the write-cursor ber_sos_ptr. ber_ptr * will not move until the outermost sequence or set is complete. */ Seqorset_header header; unsigned char *headptr; ber_len_t taglen, headlen; char *dest, **p; assert( ber != NULL ); assert( LBER_VALID( ber ) ); if ( ber->ber_sos_ptr == NULL ) { /* outermost sequence/set? */ header.next_sos.offset = 0; p = &ber->ber_ptr; } else { if ( (ber_len_t) -1 > (ber_elem_size_t) -1 ) { if ( ber->ber_sos_inner > (ber_elem_size_t) -1 ) return -1; } header.next_sos.offset = ber->ber_sos_inner; p = &ber->ber_sos_ptr; } headptr = ber_prepend_tag( SOS_TAG_END(header), tag ); *SOS_TAG_END(header) = taglen = SOS_TAG_END(header) - headptr; headlen = taglen + SOS_LENLEN; /* As ber_write(,headptr,headlen,) except update ber_sos_ptr, not *p */ if ( headlen > (ber_len_t) (ber->ber_end - *p) ) { if ( ber_realloc( ber, headlen ) != 0 ) return -1; } dest = *p; AC_MEMCPY( dest, headptr, headlen ); ber->ber_sos_ptr = dest + headlen; ber->ber_sos_inner = dest + taglen - ber->ber_buf; /* * Do not return taglen + SOS_LENLEN here - then ber_put_seqorset() * should return lenlen - SOS_LENLEN + len, which can be < 0. */ return 0; } int ber_start_seq( BerElement *ber, ber_tag_t tag ) { if ( tag == LBER_DEFAULT ) { tag = LBER_SEQUENCE; } return ber_start_seqorset( ber, tag ); } int ber_start_set( BerElement *ber, ber_tag_t tag ) { if ( tag == LBER_DEFAULT ) { tag = LBER_SET; } return ber_start_seqorset( ber, tag ); } /* End a sequence or set */ static int ber_put_seqorset( BerElement *ber ) { Seqorset_header header; unsigned char *lenptr; /* length octets in the sequence/set */ ber_len_t len; /* length(contents) */ ber_len_t xlen; /* len + length(length) */ assert( ber != NULL ); assert( LBER_VALID( ber ) ); if ( ber->ber_sos_ptr == NULL ) return -1; lenptr = (unsigned char *) ber->ber_buf + ber->ber_sos_inner; xlen = ber->ber_sos_ptr - (char *) lenptr; if ( xlen > MAXINT_BERSIZE + SOS_LENLEN ) { return -1; } /* Extract sequence/set information from length octets */ memcpy( SOS_TAG_END(header), lenptr, SOS_LENLEN ); /* Store length, and close gap of leftover reserved length octets */ len = xlen - SOS_LENLEN; if ( !(ber->ber_options & LBER_USE_DER) ) { int i; lenptr[0] = SOS_LENLEN - 1 + 0x80; /* length(length)-1 */ for( i = SOS_LENLEN; --i > 0; len >>= 8 ) { lenptr[i] = len & 0xffU; } } else { unsigned char *p = ber_prepend_len( lenptr + SOS_LENLEN, len ); ber_len_t unused = p - lenptr; if ( unused != 0 ) { /* length(length) < the reserved SOS_LENLEN bytes */ xlen -= unused; AC_MEMCPY( lenptr, p, xlen ); ber->ber_sos_ptr = (char *) lenptr + xlen; } } ber->ber_sos_inner = header.next_sos.offset; if ( header.next_sos.offset == 0 ) { /* outermost sequence/set? */ /* The ber_ptr is at the set/seq start - move it to the end */ ber->ber_ptr = ber->ber_sos_ptr; ber->ber_sos_ptr = NULL; } return xlen + *SOS_TAG_END(header); /* lenlen + len + taglen */ } int ber_put_seq( BerElement *ber ) { return ber_put_seqorset( ber ); } int ber_put_set( BerElement *ber ) { return ber_put_seqorset( ber ); } /* N tag */ static ber_tag_t lber_int_null = 0; /* VARARGS */ int ber_printf( BerElement *ber, LDAP_CONST char *fmt, ... ) { va_list ap; char *s, **ss; struct berval *bv, **bvp; int rc; ber_int_t i; ber_len_t len; assert( ber != NULL ); assert( fmt != NULL ); assert( LBER_VALID( ber ) ); va_start( ap, fmt ); for ( rc = 0; *fmt && rc != -1; fmt++ ) { switch ( *fmt ) { case '!': { /* hook */ BEREncodeCallback *f; void *p; ber->ber_usertag = 0; f = va_arg( ap, BEREncodeCallback * ); p = va_arg( ap, void * ); rc = (*f)( ber, p ); if ( ber->ber_usertag ) { goto next; } } break; case 'b': /* boolean */ i = va_arg( ap, ber_int_t ); rc = ber_put_boolean( ber, i, ber->ber_tag ); break; case 'i': /* int */ i = va_arg( ap, ber_int_t ); rc = ber_put_int( ber, i, ber->ber_tag ); break; case 'e': /* enumeration */ i = va_arg( ap, ber_int_t ); rc = ber_put_enum( ber, i, ber->ber_tag ); break; case 'n': /* null */ rc = ber_put_null( ber, ber->ber_tag ); break; case 'N': /* Debug NULL */ rc = 0; if( lber_int_null != 0 ) { /* Insert NULL to ensure peer ignores unknown tags */ rc = ber_put_null( ber, lber_int_null ); } break; case 'o': /* octet string (non-null terminated) */ s = va_arg( ap, char * ); len = va_arg( ap, ber_len_t ); rc = ber_put_ostring( ber, s, len, ber->ber_tag ); break; case 'O': /* berval octet string */ bv = va_arg( ap, struct berval * ); if( bv == NULL ) break; rc = ber_put_berval( ber, bv, ber->ber_tag ); break; case 's': /* string */ s = va_arg( ap, char * ); rc = ber_put_string( ber, s, ber->ber_tag ); break; case 'B': /* bit string */ case 'X': /* bit string (deprecated) */ s = va_arg( ap, char * ); len = va_arg( ap, ber_len_t ); /* in bits */ rc = ber_put_bitstring( ber, s, len, ber->ber_tag ); break; case 't': /* tag for the next element */ ber->ber_tag = va_arg( ap, ber_tag_t ); goto next; case 'v': /* vector of strings */ if ( (ss = va_arg( ap, char ** )) == NULL ) break; for ( i = 0; ss[i] != NULL; i++ ) { if ( (rc = ber_put_string( ber, ss[i], ber->ber_tag )) == -1 ) break; } break; case 'V': /* sequences of strings + lengths */ if ( (bvp = va_arg( ap, struct berval ** )) == NULL ) break; for ( i = 0; bvp[i] != NULL; i++ ) { if ( (rc = ber_put_berval( ber, bvp[i], ber->ber_tag )) == -1 ) break; } break; case 'W': /* BerVarray */ if ( (bv = va_arg( ap, BerVarray )) == NULL ) break; for ( i = 0; bv[i].bv_val != NULL; i++ ) { if ( (rc = ber_put_berval( ber, &bv[i], ber->ber_tag )) == -1 ) break; } break; case '{': /* begin sequence */ rc = ber_start_seq( ber, ber->ber_tag ); break; case '}': /* end sequence */ rc = ber_put_seqorset( ber ); break; case '[': /* begin set */ rc = ber_start_set( ber, ber->ber_tag ); break; case ']': /* end set */ rc = ber_put_seqorset( ber ); break; default: if( ber->ber_debug ) { ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug, "ber_printf: unknown fmt %c\n", *fmt ); } rc = -1; break; } ber->ber_tag = LBER_DEFAULT; next:; } va_end( ap ); return rc; } openldap-2.5.11+dfsg/libraries/liblber/sockbuf.c0000644000175000017500000005000714172327167020230 0ustar ryanryan/* sockbuf.c - i/o routines with support for adding i/o layers. */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include #include #ifdef HAVE_IO_H #include #endif /* HAVE_IO_H */ #if defined( HAVE_FCNTL_H ) #include #endif #if defined( HAVE_SYS_FILIO_H ) #include #elif defined( HAVE_SYS_IOCTL_H ) #include #endif #include "lber-int.h" #ifndef LBER_MIN_BUFF_SIZE #define LBER_MIN_BUFF_SIZE 4096 #endif #ifndef LBER_MAX_BUFF_SIZE #define LBER_MAX_BUFF_SIZE (65536*256) #endif #ifndef LBER_DEFAULT_READAHEAD #define LBER_DEFAULT_READAHEAD 16384 #endif Sockbuf * ber_sockbuf_alloc( void ) { Sockbuf *sb; sb = LBER_CALLOC( 1, sizeof( Sockbuf ) ); if( sb == NULL ) return NULL; ber_int_sb_init( sb ); return sb; } void ber_sockbuf_free( Sockbuf *sb ) { assert( sb != NULL ); assert( SOCKBUF_VALID( sb ) ); ber_int_sb_close( sb ); ber_int_sb_destroy( sb ); LBER_FREE( sb ); } /* Return values: -1: error, 0: no operation performed or the answer is false, * 1: successful operation or the answer is true */ int ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg ) { Sockbuf_IO_Desc *p; int ret = 0; assert( sb != NULL ); assert( SOCKBUF_VALID( sb ) ); switch ( opt ) { case LBER_SB_OPT_HAS_IO: p = sb->sb_iod; while ( p && p->sbiod_io != (Sockbuf_IO *)arg ) { p = p->sbiod_next; } if ( p ) { ret = 1; } break; case LBER_SB_OPT_GET_FD: if ( arg != NULL ) { *((ber_socket_t *)arg) = sb->sb_fd; } ret = ( sb->sb_fd == AC_SOCKET_INVALID ? -1 : 1); break; case LBER_SB_OPT_SET_FD: sb->sb_fd = *((ber_socket_t *)arg); ret = 1; break; case LBER_SB_OPT_SET_NONBLOCK: ret = ber_pvt_socket_set_nonblock( sb->sb_fd, arg != NULL) ? -1 : 1; break; case LBER_SB_OPT_DRAIN: { /* Drain the data source to enable possible errors (e.g. * TLS) to be propagated to the upper layers */ char buf[LBER_MIN_BUFF_SIZE]; do { ret = ber_int_sb_read( sb, buf, sizeof( buf ) ); } while ( ret == sizeof( buf ) ); ret = 1; } break; case LBER_SB_OPT_NEEDS_READ: ret = ( sb->sb_trans_needs_read ? 1 : 0 ); break; case LBER_SB_OPT_NEEDS_WRITE: ret = ( sb->sb_trans_needs_write ? 1 : 0 ); break; case LBER_SB_OPT_GET_MAX_INCOMING: if ( arg != NULL ) { *((ber_len_t *)arg) = sb->sb_max_incoming; } ret = 1; break; case LBER_SB_OPT_SET_MAX_INCOMING: sb->sb_max_incoming = *((ber_len_t *)arg); ret = 1; break; case LBER_SB_OPT_UNGET_BUF: #ifdef LDAP_PF_LOCAL_SENDMSG sb->sb_ungetlen = ((struct berval *)arg)->bv_len; if ( sb->sb_ungetlen <= sizeof( sb->sb_ungetbuf )) { AC_MEMCPY( sb->sb_ungetbuf, ((struct berval *)arg)->bv_val, sb->sb_ungetlen ); ret = 1; } else { sb->sb_ungetlen = 0; ret = -1; } #endif break; default: ret = sb->sb_iod->sbiod_io->sbi_ctrl( sb->sb_iod, opt, arg ); break; } return ret; } int ber_sockbuf_add_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer, void *arg ) { Sockbuf_IO_Desc *d, *p, **q; assert( sb != NULL ); assert( SOCKBUF_VALID( sb ) ); if ( sbio == NULL ) { return -1; } q = &sb->sb_iod; p = *q; while ( p && p->sbiod_level > layer ) { q = &p->sbiod_next; p = *q; } d = LBER_MALLOC( sizeof( *d ) ); if ( d == NULL ) { return -1; } d->sbiod_level = layer; d->sbiod_sb = sb; d->sbiod_io = sbio; memset( &d->sbiod_pvt, '\0', sizeof( d->sbiod_pvt ) ); d->sbiod_next = p; *q = d; if ( sbio->sbi_setup != NULL && ( sbio->sbi_setup( d, arg ) < 0 ) ) { return -1; } return 0; } int ber_sockbuf_remove_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer ) { Sockbuf_IO_Desc *p, **q; assert( sb != NULL ); assert( SOCKBUF_VALID( sb ) ); if ( sb->sb_iod == NULL ) { return -1; } q = &sb->sb_iod; while ( *q != NULL ) { p = *q; if ( layer == p->sbiod_level && p->sbiod_io == sbio ) { if ( p->sbiod_io->sbi_remove != NULL && p->sbiod_io->sbi_remove( p ) < 0 ) { return -1; } *q = p->sbiod_next; LBER_FREE( p ); break; } q = &p->sbiod_next; } return 0; } void ber_pvt_sb_buf_init( Sockbuf_Buf *buf ) { buf->buf_base = NULL; buf->buf_ptr = 0; buf->buf_end = 0; buf->buf_size = 0; } void ber_pvt_sb_buf_destroy( Sockbuf_Buf *buf ) { assert( buf != NULL); if (buf->buf_base) { LBER_FREE( buf->buf_base ); } ber_pvt_sb_buf_init( buf ); } int ber_pvt_sb_grow_buffer( Sockbuf_Buf *buf, ber_len_t minsize ) { ber_len_t pw; char *p; assert( buf != NULL ); for ( pw = LBER_MIN_BUFF_SIZE; pw < minsize; pw <<= 1 ) { if (pw > LBER_MAX_BUFF_SIZE) return -1; } if ( buf->buf_size < pw ) { p = LBER_REALLOC( buf->buf_base, pw ); if ( p == NULL ) return -1; buf->buf_base = p; buf->buf_size = pw; } return 0; } ber_len_t ber_pvt_sb_copy_out( Sockbuf_Buf *sbb, char *buf, ber_len_t len ) { ber_len_t max; assert( buf != NULL ); assert( sbb != NULL ); #if 0 assert( sbb->buf_size > 0 ); #endif max = sbb->buf_end - sbb->buf_ptr; max = ( max < len) ? max : len; if ( max ) { AC_MEMCPY( buf, sbb->buf_base + sbb->buf_ptr, max ); sbb->buf_ptr += max; if ( sbb->buf_ptr >= sbb->buf_end ) { sbb->buf_ptr = sbb->buf_end = 0; } } return max; } ber_slen_t ber_pvt_sb_do_write( Sockbuf_IO_Desc *sbiod, Sockbuf_Buf *buf_out ) { ber_len_t to_go; ber_slen_t ret; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); to_go = buf_out->buf_end - buf_out->buf_ptr; assert( to_go > 0 ); for(;;) { ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf_out->buf_base + buf_out->buf_ptr, to_go ); #ifdef EINTR if ((ret<0) && (errno==EINTR)) continue; #endif break; } if ( ret <= 0 ) return ret; buf_out->buf_ptr += ret; if (buf_out->buf_ptr == buf_out->buf_end) { buf_out->buf_end = buf_out->buf_ptr = 0; } return ret; } int ber_pvt_socket_set_nonblock( ber_socket_t sd, int nb ) { #ifdef HAVE_FCNTL int flags = fcntl( sd, F_GETFL); if( nb ) { flags |= O_NONBLOCK; } else { flags &= ~O_NONBLOCK; } return fcntl( sd, F_SETFL, flags ); #elif defined( FIONBIO ) ioctl_t status = nb ? 1 : 0; return ioctl( sd, FIONBIO, &status ); #endif } int ber_int_sb_init( Sockbuf *sb ) { assert( sb != NULL); sb->sb_valid=LBER_VALID_SOCKBUF; sb->sb_options = 0; sb->sb_debug = ber_int_debug; sb->sb_fd = AC_SOCKET_INVALID; sb->sb_iod = NULL; sb->sb_trans_needs_read = 0; sb->sb_trans_needs_write = 0; assert( SOCKBUF_VALID( sb ) ); return 0; } int ber_int_sb_close( Sockbuf *sb ) { Sockbuf_IO_Desc *p; assert( sb != NULL); p = sb->sb_iod; while ( p ) { if ( p->sbiod_io->sbi_close && p->sbiod_io->sbi_close( p ) < 0 ) { return -1; } p = p->sbiod_next; } sb->sb_fd = AC_SOCKET_INVALID; return 0; } int ber_int_sb_destroy( Sockbuf *sb ) { Sockbuf_IO_Desc *p; assert( sb != NULL); assert( SOCKBUF_VALID( sb ) ); while ( sb->sb_iod ) { p = sb->sb_iod->sbiod_next; ber_sockbuf_remove_io( sb, sb->sb_iod->sbiod_io, sb->sb_iod->sbiod_level ); sb->sb_iod = p; } return ber_int_sb_init( sb ); } ber_slen_t ber_int_sb_read( Sockbuf *sb, void *buf, ber_len_t len ) { ber_slen_t ret; assert( buf != NULL ); assert( sb != NULL); assert( sb->sb_iod != NULL ); assert( SOCKBUF_VALID( sb ) ); for (;;) { ret = sb->sb_iod->sbiod_io->sbi_read( sb->sb_iod, buf, len ); #ifdef EINTR if ( ( ret < 0 ) && ( errno == EINTR ) ) continue; #endif break; } return ret; } ber_slen_t ber_int_sb_write( Sockbuf *sb, void *buf, ber_len_t len ) { ber_slen_t ret; assert( buf != NULL ); assert( sb != NULL); assert( sb->sb_iod != NULL ); assert( SOCKBUF_VALID( sb ) ); for (;;) { ret = sb->sb_iod->sbiod_io->sbi_write( sb->sb_iod, buf, len ); #ifdef EINTR if ( ( ret < 0 ) && ( errno == EINTR ) ) continue; #endif break; } return ret; } /* * Support for TCP */ static ber_slen_t sb_stream_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { assert( sbiod != NULL); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); #if defined(MACOS) /* * MacTCP/OpenTransport */ return tcpread( sbiod->sbiod_sb->sb_fd, 0, (unsigned char *)buf, len, NULL ); #elif defined( HAVE_PCNFS ) || \ defined( HAVE_WINSOCK ) || defined ( __BEOS__ ) /* * PCNFS (under DOS) */ /* * Windows Socket API (under DOS/Windows 3.x) */ /* * 32-bit Windows Socket API (under Windows NT or Windows 95) */ return recv( sbiod->sbiod_sb->sb_fd, buf, len, 0 ); #elif defined( HAVE_NCSA ) /* * NCSA Telnet TCP/IP stack (under DOS) */ return nread( sbiod->sbiod_sb->sb_fd, buf, len ); #else return read( sbiod->sbiod_sb->sb_fd, buf, len ); #endif } static ber_slen_t sb_stream_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { assert( sbiod != NULL); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); #if defined(MACOS) /* * MacTCP/OpenTransport */ #define MAX_WRITE 65535 return tcpwrite( sbiod->sbiod_sb->sb_fd, (unsigned char *)buf, (lensbiod_sb->sb_fd, buf, len, 0 ); #elif defined(HAVE_NCSA) return netwrite( sbiod->sbiod_sb->sb_fd, buf, len ); #elif defined(VMS) /* * VMS -- each write must be 64K or smaller */ #define MAX_WRITE 65535 return write( sbiod->sbiod_sb->sb_fd, buf, (lensbiod_sb->sb_fd, buf, len ); #endif } static int sb_stream_close( Sockbuf_IO_Desc *sbiod ) { assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); if ( sbiod->sbiod_sb->sb_fd != AC_SOCKET_INVALID ) tcp_close( sbiod->sbiod_sb->sb_fd ); return 0; } /* The argument is a pointer to the socket descriptor */ static int sb_stream_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { assert( sbiod != NULL ); if ( arg != NULL ) { sbiod->sbiod_sb->sb_fd = *((int *)arg); } return 0; } static int sb_stream_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { /* This is an end IO descriptor */ return 0; } Sockbuf_IO ber_sockbuf_io_tcp = { sb_stream_setup, /* sbi_setup */ NULL, /* sbi_remove */ sb_stream_ctrl, /* sbi_ctrl */ sb_stream_read, /* sbi_read */ sb_stream_write, /* sbi_write */ sb_stream_close /* sbi_close */ }; /* * Support for readahead (UDP needs it) */ static int sb_rdahead_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { Sockbuf_Buf *p; assert( sbiod != NULL ); p = LBER_MALLOC( sizeof( *p ) ); if ( p == NULL ) return -1; ber_pvt_sb_buf_init( p ); if ( arg == NULL ) { ber_pvt_sb_grow_buffer( p, LBER_DEFAULT_READAHEAD ); } else { ber_pvt_sb_grow_buffer( p, *((int *)arg) ); } sbiod->sbiod_pvt = p; return 0; } static int sb_rdahead_remove( Sockbuf_IO_Desc *sbiod ) { Sockbuf_Buf *p; assert( sbiod != NULL ); p = (Sockbuf_Buf *)sbiod->sbiod_pvt; if ( p->buf_ptr != p->buf_end ) return -1; ber_pvt_sb_buf_destroy( (Sockbuf_Buf *)(sbiod->sbiod_pvt) ); LBER_FREE( sbiod->sbiod_pvt ); sbiod->sbiod_pvt = NULL; return 0; } static ber_slen_t sb_rdahead_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { Sockbuf_Buf *p; ber_slen_t bufptr = 0, ret, max; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); assert( sbiod->sbiod_next != NULL ); p = (Sockbuf_Buf *)sbiod->sbiod_pvt; assert( p->buf_size > 0 ); /* Are there anything left in the buffer? */ ret = ber_pvt_sb_copy_out( p, buf, len ); bufptr += ret; len -= ret; if ( len == 0 ) return bufptr; max = p->buf_size - p->buf_end; ret = 0; while ( max > 0 ) { ret = LBER_SBIOD_READ_NEXT( sbiod, p->buf_base + p->buf_end, max ); #ifdef EINTR if ( ( ret < 0 ) && ( errno == EINTR ) ) continue; #endif break; } if ( ret < 0 ) { return ( bufptr ? bufptr : ret ); } p->buf_end += ret; bufptr += ber_pvt_sb_copy_out( p, (char *) buf + bufptr, len ); return bufptr; } static ber_slen_t sb_rdahead_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { assert( sbiod != NULL ); assert( sbiod->sbiod_next != NULL ); return LBER_SBIOD_WRITE_NEXT( sbiod, buf, len ); } static int sb_rdahead_close( Sockbuf_IO_Desc *sbiod ) { assert( sbiod != NULL ); /* Just erase the buffer */ ber_pvt_sb_buf_destroy((Sockbuf_Buf *)sbiod->sbiod_pvt); return 0; } static int sb_rdahead_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { Sockbuf_Buf *p; p = (Sockbuf_Buf *)sbiod->sbiod_pvt; if ( opt == LBER_SB_OPT_DATA_READY ) { if ( p->buf_ptr != p->buf_end ) { return 1; } } else if ( opt == LBER_SB_OPT_SET_READAHEAD ) { if ( p->buf_size >= *((ber_len_t *)arg) ) { return 0; } return ( ber_pvt_sb_grow_buffer( p, *((int *)arg) ) ? -1 : 1 ); } return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); } Sockbuf_IO ber_sockbuf_io_readahead = { sb_rdahead_setup, /* sbi_setup */ sb_rdahead_remove, /* sbi_remove */ sb_rdahead_ctrl, /* sbi_ctrl */ sb_rdahead_read, /* sbi_read */ sb_rdahead_write, /* sbi_write */ sb_rdahead_close /* sbi_close */ }; /* * Support for simple file IO */ static ber_slen_t sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { assert( sbiod != NULL); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); #ifdef LDAP_PF_LOCAL_SENDMSG if ( sbiod->sbiod_sb->sb_ungetlen ) { ber_len_t blen = sbiod->sbiod_sb->sb_ungetlen; if ( blen > len ) blen = len; AC_MEMCPY( buf, sbiod->sbiod_sb->sb_ungetbuf, blen ); buf = (char *) buf + blen; len -= blen; sbiod->sbiod_sb->sb_ungetlen -= blen; if ( sbiod->sbiod_sb->sb_ungetlen ) { AC_MEMCPY( sbiod->sbiod_sb->sb_ungetbuf, sbiod->sbiod_sb->sb_ungetbuf+blen, sbiod->sbiod_sb->sb_ungetlen ); } if ( len == 0 ) return blen; } #endif return read( sbiod->sbiod_sb->sb_fd, buf, len ); } static ber_slen_t sb_fd_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { assert( sbiod != NULL); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); return write( sbiod->sbiod_sb->sb_fd, buf, len ); } static int sb_fd_close( Sockbuf_IO_Desc *sbiod ) { assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); if ( sbiod->sbiod_sb->sb_fd != AC_SOCKET_INVALID ) close( sbiod->sbiod_sb->sb_fd ); return 0; } /* The argument is a pointer to the file descriptor */ static int sb_fd_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { assert( sbiod != NULL ); if ( arg != NULL ) sbiod->sbiod_sb->sb_fd = *((int *)arg); return 0; } static int sb_fd_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { /* This is an end IO descriptor */ return 0; } Sockbuf_IO ber_sockbuf_io_fd = { sb_fd_setup, /* sbi_setup */ NULL, /* sbi_remove */ sb_fd_ctrl, /* sbi_ctrl */ sb_fd_read, /* sbi_read */ sb_fd_write, /* sbi_write */ sb_fd_close /* sbi_close */ }; /* * Debugging layer */ static int sb_debug_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { assert( sbiod != NULL ); if ( arg == NULL ) arg = "sockbuf_"; sbiod->sbiod_pvt = LBER_MALLOC( strlen( arg ) + 1 ); if ( sbiod->sbiod_pvt == NULL ) return -1; strcpy( (char *)sbiod->sbiod_pvt, (char *)arg ); return 0; } static int sb_debug_remove( Sockbuf_IO_Desc *sbiod ) { assert( sbiod != NULL ); assert( sbiod->sbiod_pvt != NULL ); LBER_FREE( sbiod->sbiod_pvt ); sbiod->sbiod_pvt = NULL; return 0; } static int sb_debug_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); } static ber_slen_t sb_debug_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { ber_slen_t ret; char ebuf[128]; ret = LBER_SBIOD_READ_NEXT( sbiod, buf, len ); if (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS) { int err = sock_errno(); if ( ret < 0 ) { ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, "%sread: want=%ld error=%s\n", (char *)sbiod->sbiod_pvt, (long)len, AC_STRERROR_R( err, ebuf, sizeof ebuf ) ); } else { ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, "%sread: want=%ld, got=%ld\n", (char *)sbiod->sbiod_pvt, (long)len, (long)ret ); ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, (const char *)buf, ret ); } sock_errset(err); } return ret; } static ber_slen_t sb_debug_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { ber_slen_t ret; char ebuf[128]; ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf, len ); if (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS) { int err = sock_errno(); if ( ret < 0 ) { ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, "%swrite: want=%ld error=%s\n", (char *)sbiod->sbiod_pvt, (long)len, AC_STRERROR_R( err, ebuf, sizeof ebuf ) ); } else { ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, "%swrite: want=%ld, written=%ld\n", (char *)sbiod->sbiod_pvt, (long)len, (long)ret ); ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, (const char *)buf, ret ); } sock_errset(err); } return ret; } Sockbuf_IO ber_sockbuf_io_debug = { sb_debug_setup, /* sbi_setup */ sb_debug_remove, /* sbi_remove */ sb_debug_ctrl, /* sbi_ctrl */ sb_debug_read, /* sbi_read */ sb_debug_write, /* sbi_write */ NULL /* sbi_close */ }; #ifdef LDAP_CONNECTIONLESS /* * Support for UDP (CLDAP) * * All I/O at this level must be atomic. For ease of use, the sb_readahead * must be used above this module. All data reads and writes are prefixed * with a sockaddr_storage containing the address of the remote entity. Upper levels * must read and write this sockaddr_storage before doing the usual ber_printf/scanf * operations on LDAP messages. */ static int sb_dgram_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { assert( sbiod != NULL); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); if ( arg != NULL ) sbiod->sbiod_sb->sb_fd = *((int *)arg); return 0; } static ber_slen_t sb_dgram_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { ber_slen_t rc; ber_socklen_t addrlen; struct sockaddr *src; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); assert( buf != NULL ); addrlen = sizeof( struct sockaddr_storage ); src = buf; buf = (char *) buf + addrlen; len -= addrlen; rc = recvfrom( sbiod->sbiod_sb->sb_fd, buf, len, 0, src, &addrlen ); return rc > 0 ? rc+sizeof(struct sockaddr_storage) : rc; } static ber_slen_t sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { ber_slen_t rc; struct sockaddr *dst; socklen_t dstsize; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); assert( buf != NULL ); dst = buf; buf = (char *) buf + sizeof( struct sockaddr_storage ); len -= sizeof( struct sockaddr_storage ); dstsize = dst->sa_family == AF_INET ? sizeof( struct sockaddr_in ) #ifdef LDAP_PF_INET6 : dst->sa_family == AF_INET6 ? sizeof( struct sockaddr_in6 ) #endif : sizeof( struct sockaddr_storage ); rc = sendto( sbiod->sbiod_sb->sb_fd, buf, len, 0, dst, dstsize ); if ( rc < 0 ) return -1; /* fake error if write was not atomic */ if (rc < len) { # ifdef EMSGSIZE errno = EMSGSIZE; # endif return -1; } rc = len + sizeof(struct sockaddr_storage); return rc; } static int sb_dgram_close( Sockbuf_IO_Desc *sbiod ) { assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); if ( sbiod->sbiod_sb->sb_fd != AC_SOCKET_INVALID ) tcp_close( sbiod->sbiod_sb->sb_fd ); return 0; } static int sb_dgram_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { /* This is an end IO descriptor */ return 0; } Sockbuf_IO ber_sockbuf_io_udp = { sb_dgram_setup, /* sbi_setup */ NULL, /* sbi_remove */ sb_dgram_ctrl, /* sbi_ctrl */ sb_dgram_read, /* sbi_read */ sb_dgram_write, /* sbi_write */ sb_dgram_close /* sbi_close */ }; #endif /* LDAP_CONNECTIONLESS */ openldap-2.5.11+dfsg/libraries/liblber/memory.c0000644000175000017500000004012314172327167020102 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include "lber-int.h" #ifdef LDAP_MEMORY_TRACE #include #endif #ifdef LDAP_MEMORY_DEBUG /* * LDAP_MEMORY_DEBUG should only be enabled for the purposes of * debugging memory management within OpenLDAP libraries and slapd. * * It should only be enabled by an experienced developer as it causes * the inclusion of numerous assert()'s, many of which may be triggered * by a perfectly valid program. If LDAP_MEMORY_DEBUG & 2 is true, * that includes asserts known to break both slapd and current clients. * * The code behind this macro is subject to change as needed to * support this testing. */ struct ber_mem_hdr { ber_int_t bm_top; /* Pattern to detect buf overrun from prev buffer */ ber_int_t bm_length; /* Length of user allocated area */ #ifdef LDAP_MEMORY_TRACE ber_int_t bm_sequence; /* Allocation sequence number */ #endif union bmu_align_u { /* Force alignment, pattern to detect back clobber */ ber_len_t bmu_len_t; ber_tag_t bmu_tag_t; ber_int_t bmu_int_t; size_t bmu_size_t; void * bmu_voidp; double bmu_double; long bmu_long; long (*bmu_funcp)( double ); unsigned char bmu_char[4]; } ber_align; #define bm_junk ber_align.bmu_len_t #define bm_data ber_align.bmu_char[1] #define bm_char ber_align.bmu_char }; /* Pattern at top of allocated space */ #define LBER_MEM_JUNK ((ber_int_t) 0xdeaddada) static const struct ber_mem_hdr ber_int_mem_hdr = { LBER_MEM_JUNK }; /* Note sequence and ber_int_meminuse are counters, but are not * thread safe. If you want to use these values for multithreaded applications, * you must put mutexes around them, otherwise they will have incorrect values. * When debugging, if you sort the debug output, the sequence number will * put allocations/frees together. It is then a simple matter to write a script * to find any allocations that don't have a buffer free function. */ long ber_int_meminuse = 0; #ifdef LDAP_MEMORY_TRACE static ber_int_t sequence = 0; #endif /* Pattern placed just before user data */ static unsigned char toppattern[4] = { 0xde, 0xad, 0xba, 0xde }; /* Pattern placed just after user data */ static unsigned char endpattern[4] = { 0xd1, 0xed, 0xde, 0xca }; #define mbu_len sizeof(ber_int_mem_hdr.ber_align) /* Test if pattern placed just before user data is good */ #define testdatatop(val) ( \ *(val->bm_char+mbu_len-4)==toppattern[0] && \ *(val->bm_char+mbu_len-3)==toppattern[1] && \ *(val->bm_char+mbu_len-2)==toppattern[2] && \ *(val->bm_char+mbu_len-1)==toppattern[3] ) /* Place pattern just before user data */ #define setdatatop(val) *(val->bm_char+mbu_len-4)=toppattern[0]; \ *(val->bm_char+mbu_len-3)=toppattern[1]; \ *(val->bm_char+mbu_len-2)=toppattern[2]; \ *(val->bm_char+mbu_len-1)=toppattern[3]; /* Test if pattern placed just after user data is good */ #define testend(val) ( *((unsigned char *)val+0)==endpattern[0] && \ *((unsigned char *)val+1)==endpattern[1] && \ *((unsigned char *)val+2)==endpattern[2] && \ *((unsigned char *)val+3)==endpattern[3] ) /* Place pattern just after user data */ #define setend(val) *((unsigned char *)val+0)=endpattern[0]; \ *((unsigned char *)val+1)=endpattern[1]; \ *((unsigned char *)val+2)=endpattern[2]; \ *((unsigned char *)val+3)=endpattern[3]; #define BER_MEM_BADADDR ((void *) &ber_int_mem_hdr.bm_data) #define BER_MEM_VALID(p) do { \ assert( (p) != BER_MEM_BADADDR ); \ assert( (p) != (void *) &ber_int_mem_hdr ); \ } while(0) #else #define BER_MEM_VALID(p) /* no-op */ #endif BerMemoryFunctions *ber_int_memory_fns = NULL; void ber_memfree_x( void *p, void *ctx ) { if( p == NULL ) { return; } BER_MEM_VALID( p ); if( ber_int_memory_fns == NULL || ctx == NULL ) { #ifdef LDAP_MEMORY_DEBUG struct ber_mem_hdr *mh = (struct ber_mem_hdr *) ((char *)p - sizeof(struct ber_mem_hdr)); assert( mh->bm_top == LBER_MEM_JUNK); assert( testdatatop( mh)); assert( testend( (char *)&mh[1] + mh->bm_length) ); ber_int_meminuse -= mh->bm_length; #ifdef LDAP_MEMORY_TRACE fprintf(stderr, "0x%08lx 0x%08lx -f- %ld ber_memfree %ld\n", (long)mh->bm_sequence, (long)mh, (long)mh->bm_length, ber_int_meminuse); #endif /* Fill the free space with poison */ memset( mh, 0xff, mh->bm_length + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t)); free( mh ); #else free( p ); #endif return; } assert( ber_int_memory_fns->bmf_free != 0 ); (*ber_int_memory_fns->bmf_free)( p, ctx ); } void ber_memfree( void *p ) { ber_memfree_x(p, NULL); } void ber_memvfree_x( void **vec, void *ctx ) { int i; if( vec == NULL ) { return; } BER_MEM_VALID( vec ); for ( i = 0; vec[i] != NULL; i++ ) { ber_memfree_x( vec[i], ctx ); } ber_memfree_x( vec, ctx ); } void ber_memvfree( void **vec ) { ber_memvfree_x( vec, NULL ); } void * ber_memalloc_x( ber_len_t s, void *ctx ) { void *new; if( s == 0 ) { LDAP_MEMORY_DEBUG_ASSERT( s != 0 ); return NULL; } if( ber_int_memory_fns == NULL || ctx == NULL ) { #ifdef LDAP_MEMORY_DEBUG new = malloc(s + sizeof(struct ber_mem_hdr) + sizeof( ber_int_t)); if( new ) { struct ber_mem_hdr *mh = new; mh->bm_top = LBER_MEM_JUNK; mh->bm_length = s; setdatatop( mh); setend( (char *)&mh[1] + mh->bm_length ); ber_int_meminuse += mh->bm_length; /* Count mem inuse */ #ifdef LDAP_MEMORY_TRACE mh->bm_sequence = sequence++; fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memalloc %ld\n", (long)mh->bm_sequence, (long)mh, (long)mh->bm_length, ber_int_meminuse); #endif /* poison new memory */ memset( (char *)&mh[1], 0xff, s); BER_MEM_VALID( &mh[1] ); new = &mh[1]; } #else new = malloc( s ); #endif } else { new = (*ber_int_memory_fns->bmf_malloc)( s, ctx ); } if( new == NULL ) { ber_errno = LBER_ERROR_MEMORY; } return new; } void * ber_memalloc( ber_len_t s ) { return ber_memalloc_x( s, NULL ); } void * ber_memcalloc_x( ber_len_t n, ber_len_t s, void *ctx ) { void *new; if( n == 0 || s == 0 ) { LDAP_MEMORY_DEBUG_ASSERT( n != 0 && s != 0); return NULL; } if( ber_int_memory_fns == NULL || ctx == NULL ) { #ifdef LDAP_MEMORY_DEBUG new = n < (-sizeof(struct ber_mem_hdr) - sizeof(ber_int_t)) / s ? calloc(1, n*s + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t)) : NULL; if( new ) { struct ber_mem_hdr *mh = new; mh->bm_top = LBER_MEM_JUNK; mh->bm_length = n*s; setdatatop( mh); setend( (char *)&mh[1] + mh->bm_length ); ber_int_meminuse += mh->bm_length; #ifdef LDAP_MEMORY_TRACE mh->bm_sequence = sequence++; fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memcalloc %ld\n", (long)mh->bm_sequence, (long)mh, (long)mh->bm_length, ber_int_meminuse); #endif BER_MEM_VALID( &mh[1] ); new = &mh[1]; } #else new = calloc( n, s ); #endif } else { new = (*ber_int_memory_fns->bmf_calloc)( n, s, ctx ); } if( new == NULL ) { ber_errno = LBER_ERROR_MEMORY; } return new; } void * ber_memcalloc( ber_len_t n, ber_len_t s ) { return ber_memcalloc_x( n, s, NULL ); } void * ber_memrealloc_x( void* p, ber_len_t s, void *ctx ) { void *new = NULL; /* realloc(NULL,s) -> malloc(s) */ if( p == NULL ) { return ber_memalloc_x( s, ctx ); } /* realloc(p,0) -> free(p) */ if( s == 0 ) { ber_memfree_x( p, ctx ); return NULL; } BER_MEM_VALID( p ); if( ber_int_memory_fns == NULL || ctx == NULL ) { #ifdef LDAP_MEMORY_DEBUG ber_int_t oldlen; struct ber_mem_hdr *mh = (struct ber_mem_hdr *) ((char *)p - sizeof(struct ber_mem_hdr)); assert( mh->bm_top == LBER_MEM_JUNK); assert( testdatatop( mh)); assert( testend( (char *)&mh[1] + mh->bm_length) ); oldlen = mh->bm_length; p = realloc( mh, s + sizeof(struct ber_mem_hdr) + sizeof(ber_int_t) ); if( p == NULL ) { ber_errno = LBER_ERROR_MEMORY; return NULL; } mh = p; mh->bm_length = s; setend( (char *)&mh[1] + mh->bm_length ); if( s > oldlen ) { /* poison any new memory */ memset( (char *)&mh[1] + oldlen, 0xff, s - oldlen); } assert( mh->bm_top == LBER_MEM_JUNK); assert( testdatatop( mh)); ber_int_meminuse += s - oldlen; #ifdef LDAP_MEMORY_TRACE fprintf(stderr, "0x%08lx 0x%08lx -a- %ld ber_memrealloc %ld\n", (long)mh->bm_sequence, (long)mh, (long)mh->bm_length, ber_int_meminuse); #endif BER_MEM_VALID( &mh[1] ); return &mh[1]; #else new = realloc( p, s ); #endif } else { new = (*ber_int_memory_fns->bmf_realloc)( p, s, ctx ); } if( new == NULL ) { ber_errno = LBER_ERROR_MEMORY; } return new; } void * ber_memrealloc( void* p, ber_len_t s ) { return ber_memrealloc_x( p, s, NULL ); } void ber_bvfree_x( struct berval *bv, void *ctx ) { if( bv == NULL ) { return; } BER_MEM_VALID( bv ); if ( bv->bv_val != NULL ) { ber_memfree_x( bv->bv_val, ctx ); } ber_memfree_x( (char *) bv, ctx ); } void ber_bvfree( struct berval *bv ) { ber_bvfree_x( bv, NULL ); } void ber_bvecfree_x( struct berval **bv, void *ctx ) { int i; if( bv == NULL ) { return; } BER_MEM_VALID( bv ); /* count elements */ for ( i = 0; bv[i] != NULL; i++ ) ; /* free in reverse order */ for ( i--; i >= 0; i-- ) { ber_bvfree_x( bv[i], ctx ); } ber_memfree_x( (char *) bv, ctx ); } void ber_bvecfree( struct berval **bv ) { ber_bvecfree_x( bv, NULL ); } int ber_bvecadd_x( struct berval ***bvec, struct berval *bv, void *ctx ) { ber_len_t i; struct berval **new; if( *bvec == NULL ) { if( bv == NULL ) { /* nothing to add */ return 0; } *bvec = ber_memalloc_x( 2 * sizeof(struct berval *), ctx ); if( *bvec == NULL ) { return -1; } (*bvec)[0] = bv; (*bvec)[1] = NULL; return 1; } BER_MEM_VALID( bvec ); /* count entries */ for ( i = 0; (*bvec)[i] != NULL; i++ ) { /* EMPTY */; } if( bv == NULL ) { return i; } new = ber_memrealloc_x( *bvec, (i+2) * sizeof(struct berval *), ctx); if( new == NULL ) { return -1; } *bvec = new; (*bvec)[i++] = bv; (*bvec)[i] = NULL; return i; } int ber_bvecadd( struct berval ***bvec, struct berval *bv ) { return ber_bvecadd_x( bvec, bv, NULL ); } struct berval * ber_dupbv_x( struct berval *dst, struct berval *src, void *ctx ) { struct berval *new, tmp; if( src == NULL ) { ber_errno = LBER_ERROR_PARAM; return NULL; } if ( dst ) { new = &tmp; } else { if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) { return NULL; } } if ( src->bv_val == NULL ) { new->bv_val = NULL; new->bv_len = 0; } else { if(( new->bv_val = ber_memalloc_x( src->bv_len + 1, ctx )) == NULL ) { if ( !dst ) ber_memfree_x( new, ctx ); return NULL; } AC_MEMCPY( new->bv_val, src->bv_val, src->bv_len ); new->bv_val[src->bv_len] = '\0'; new->bv_len = src->bv_len; } if ( dst ) { *dst = *new; new = dst; } return new; } struct berval * ber_dupbv( struct berval *dst, struct berval *src ) { return ber_dupbv_x( dst, src, NULL ); } struct berval * ber_bvdup( struct berval *src ) { return ber_dupbv_x( NULL, src, NULL ); } struct berval * ber_str2bv_x( LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv, void *ctx) { struct berval *new; if( s == NULL ) { ber_errno = LBER_ERROR_PARAM; return NULL; } if( bv ) { new = bv; } else { if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) { return NULL; } } new->bv_len = len ? len : strlen( s ); if ( dup ) { if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) { if ( !bv ) ber_memfree_x( new, ctx ); return NULL; } AC_MEMCPY( new->bv_val, s, new->bv_len ); new->bv_val[new->bv_len] = '\0'; } else { new->bv_val = (char *) s; } return( new ); } struct berval * ber_str2bv( LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv) { return ber_str2bv_x( s, len, dup, bv, NULL ); } struct berval * ber_mem2bv_x( LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv, void *ctx) { struct berval *new; if( s == NULL ) { ber_errno = LBER_ERROR_PARAM; return NULL; } if( bv ) { new = bv; } else { if(( new = ber_memalloc_x( sizeof(struct berval), ctx )) == NULL ) { return NULL; } } new->bv_len = len; if ( dup ) { if ( (new->bv_val = ber_memalloc_x( new->bv_len+1, ctx )) == NULL ) { if ( !bv ) { ber_memfree_x( new, ctx ); } return NULL; } AC_MEMCPY( new->bv_val, s, new->bv_len ); new->bv_val[new->bv_len] = '\0'; } else { new->bv_val = (char *) s; } return( new ); } struct berval * ber_mem2bv( LDAP_CONST char *s, ber_len_t len, int dup, struct berval *bv) { return ber_mem2bv_x( s, len, dup, bv, NULL ); } char * ber_strdup_x( LDAP_CONST char *s, void *ctx ) { char *p; size_t len; #ifdef LDAP_MEMORY_DEBUG assert(s != NULL); /* bv damn better point to something */ #endif if( s == NULL ) { ber_errno = LBER_ERROR_PARAM; return NULL; } len = strlen( s ) + 1; if ( (p = ber_memalloc_x( len, ctx )) != NULL ) { AC_MEMCPY( p, s, len ); } return p; } char * ber_strdup( LDAP_CONST char *s ) { return ber_strdup_x( s, NULL ); } ber_len_t ber_strnlen( LDAP_CONST char *s, ber_len_t len ) { ber_len_t l; for ( l = 0; l < len && s[l] != '\0'; l++ ) ; return l; } char * ber_strndup_x( LDAP_CONST char *s, ber_len_t l, void *ctx ) { char *p; size_t len; #ifdef LDAP_MEMORY_DEBUG assert(s != NULL); /* bv damn better point to something */ #endif if( s == NULL ) { ber_errno = LBER_ERROR_PARAM; return NULL; } len = ber_strnlen( s, l ); if ( (p = ber_memalloc_x( len + 1, ctx )) != NULL ) { AC_MEMCPY( p, s, len ); p[len] = '\0'; } return p; } char * ber_strndup( LDAP_CONST char *s, ber_len_t l ) { return ber_strndup_x( s, l, NULL ); } /* * dst is resized as required by src and the value of src is copied into dst * dst->bv_val must be NULL (and dst->bv_len must be 0), or it must be * alloc'ed with the context ctx */ struct berval * ber_bvreplace_x( struct berval *dst, LDAP_CONST struct berval *src, void *ctx ) { assert( dst != NULL ); assert( !BER_BVISNULL( src ) ); if ( BER_BVISNULL( dst ) || dst->bv_len < src->bv_len ) { dst->bv_val = ber_memrealloc_x( dst->bv_val, src->bv_len + 1, ctx ); } AC_MEMCPY( dst->bv_val, src->bv_val, src->bv_len + 1 ); dst->bv_len = src->bv_len; return dst; } struct berval * ber_bvreplace( struct berval *dst, LDAP_CONST struct berval *src ) { return ber_bvreplace_x( dst, src, NULL ); } void ber_bvarray_free_x( BerVarray a, void *ctx ) { int i; if (a) { BER_MEM_VALID( a ); /* count elements */ for (i=0; a[i].bv_val; i++) ; /* free in reverse order */ for (i--; i>=0; i--) { ber_memfree_x(a[i].bv_val, ctx); } ber_memfree_x(a, ctx); } } void ber_bvarray_free( BerVarray a ) { ber_bvarray_free_x(a, NULL); } int ber_bvarray_dup_x( BerVarray *dst, BerVarray src, void *ctx ) { int i, j; BerVarray new; if ( !src ) { *dst = NULL; return 0; } for (i=0; !BER_BVISNULL( &src[i] ); i++) ; new = ber_memalloc_x(( i+1 ) * sizeof(BerValue), ctx ); if ( !new ) return -1; for (j=0; j. * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #ifdef LDAP_NEED_ASSERT #include /* * helper for our private assert() macro * * note: if assert() doesn't exist, like abort() or raise() won't either. * could use kill() but that might be problematic. I'll just ignore this * issue for now. */ void ber_pvt_assert( const char *file, int line, const char *test ) { fprintf(stderr, _("Assertion failed: %s, file %s, line %d\n"), test, file, line); abort(); } #endif openldap-2.5.11+dfsg/libraries/liblber/nt_err.c0000644000175000017500000000524314172327167020067 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #ifdef HAVE_WINSOCK2 #include #elif defined(HAVE_WINSOCK) #include #endif /* HAVE_WINSOCK(2) */ #define LBER_RETSTR( x ) case x: return #x; char *ber_pvt_wsa_err2string( int err ) { switch( err ) { LBER_RETSTR( WSAEINTR ) LBER_RETSTR( WSAEBADF ) LBER_RETSTR( WSAEACCES ) LBER_RETSTR( WSAEFAULT ) LBER_RETSTR( WSAEINVAL ) LBER_RETSTR( WSAEMFILE ) LBER_RETSTR( WSAEWOULDBLOCK ) LBER_RETSTR( WSAEINPROGRESS ) LBER_RETSTR( WSAEALREADY ) LBER_RETSTR( WSAENOTSOCK ) LBER_RETSTR( WSAEDESTADDRREQ ) LBER_RETSTR( WSAEMSGSIZE ) LBER_RETSTR( WSAEPROTOTYPE ) LBER_RETSTR( WSAENOPROTOOPT ) LBER_RETSTR( WSAEPROTONOSUPPORT ) LBER_RETSTR( WSAESOCKTNOSUPPORT ) LBER_RETSTR( WSAEOPNOTSUPP ) LBER_RETSTR( WSAEPFNOSUPPORT ) LBER_RETSTR( WSAEAFNOSUPPORT ) LBER_RETSTR( WSAEADDRINUSE ) LBER_RETSTR( WSAEADDRNOTAVAIL ) LBER_RETSTR( WSAENETDOWN ) LBER_RETSTR( WSAENETUNREACH ) LBER_RETSTR( WSAENETRESET ) LBER_RETSTR( WSAECONNABORTED ) LBER_RETSTR( WSAECONNRESET ) LBER_RETSTR( WSAENOBUFS ) LBER_RETSTR( WSAEISCONN ) LBER_RETSTR( WSAENOTCONN ) LBER_RETSTR( WSAESHUTDOWN ) LBER_RETSTR( WSAETOOMANYREFS ) LBER_RETSTR( WSAETIMEDOUT ) LBER_RETSTR( WSAECONNREFUSED ) LBER_RETSTR( WSAELOOP ) LBER_RETSTR( WSAENAMETOOLONG ) LBER_RETSTR( WSAEHOSTDOWN ) LBER_RETSTR( WSAEHOSTUNREACH ) LBER_RETSTR( WSAENOTEMPTY ) LBER_RETSTR( WSAEPROCLIM ) LBER_RETSTR( WSAEUSERS ) LBER_RETSTR( WSAEDQUOT ) LBER_RETSTR( WSAESTALE ) LBER_RETSTR( WSAEREMOTE ) LBER_RETSTR( WSASYSNOTREADY ) LBER_RETSTR( WSAVERNOTSUPPORTED ) LBER_RETSTR( WSANOTINITIALISED ) LBER_RETSTR( WSAEDISCON ) #ifdef HAVE_WINSOCK2 LBER_RETSTR( WSAENOMORE ) LBER_RETSTR( WSAECANCELLED ) LBER_RETSTR( WSAEINVALIDPROCTABLE ) LBER_RETSTR( WSAEINVALIDPROVIDER ) LBER_RETSTR( WSASYSCALLFAILURE ) LBER_RETSTR( WSASERVICE_NOT_FOUND ) LBER_RETSTR( WSATYPE_NOT_FOUND ) LBER_RETSTR( WSA_E_NO_MORE ) LBER_RETSTR( WSA_E_CANCELLED ) LBER_RETSTR( WSAEREFUSED ) #endif /* HAVE_WINSOCK2 */ LBER_RETSTR( WSAHOST_NOT_FOUND ) LBER_RETSTR( WSATRY_AGAIN ) LBER_RETSTR( WSANO_RECOVERY ) LBER_RETSTR( WSANO_DATA ) } return "unknown WSA error"; } openldap-2.5.11+dfsg/libraries/liblber/lber.pc.in0000644000175000017500000000044614172327167020307 0ustar ryanryanprefix=@prefix@ exec_prefix=@exec_prefix@ includedir=@includedir@ libdir=@libdir@ Name: lber (@PACKAGE@) Description: OpenLDAP Lightweight ASN.1 Basic Encoding Rules library URL: https://www.openldap.org Version: @VERSION@ Cflags: -I${includedir} Libs: -L${libdir} -llber Libs.private: @LIBS@ openldap-2.5.11+dfsg/libraries/liblber/debug.c0000644000175000017500000000307314172327167017663 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include #ifdef LDAP_SYSLOG #include #endif #include "ldap_log.h" #include "ldap_defaults.h" #include "lber.h" #include "ldap_pvt.h" int lutil_debug_file( FILE *file ) { ber_set_option( NULL, LBER_OPT_LOG_PRINT_FILE, file ); return 0; } void (lutil_debug)( int debug, int level, const char *fmt, ... ) { char buffer[4096]; va_list vl; if ( !(level & debug ) ) return; va_start( vl, fmt ); vsnprintf( buffer, sizeof(buffer), fmt, vl ); va_end( vl ); ber_pvt_log_print( buffer ); } #if defined(HAVE_EBCDIC) && defined(LDAP_SYSLOG) #undef syslog void eb_syslog( int pri, const char *fmt, ... ) { char buffer[4096]; va_list vl; va_start( vl, fmt ); vsnprintf( buffer, sizeof(buffer), fmt, vl ); buffer[sizeof(buffer)-1] = '\0'; /* The syslog function appears to only work with pure EBCDIC */ __atoe(buffer); #pragma convlit(suspend) syslog( pri, "%s", buffer ); #pragma convlit(resume) va_end( vl ); } #endif openldap-2.5.11+dfsg/libraries/liblber/etest.c0000644000175000017500000000765514172327167017733 0ustar ryanryan/* etest.c - lber encoding test program */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ /* ACKNOWLEDGEMENTS: * This work was originally developed by the University of Michigan * (as part of U-MICH LDAP). */ #include "portable.h" #include #include #include #include #include #ifdef HAVE_CONSOLE_H #include #endif /* HAVE_CONSOLE_H */ #include "lber.h" static void usage( const char *name ) { fprintf( stderr, "usage: %s fmtstring\n", name ); } static char* getbuf( void ) { char *p; static char buf[1024]; if ( fgets( buf, sizeof(buf), stdin ) == NULL ) return NULL; if ( (p = strchr( buf, '\n' )) != NULL ) *p = '\0'; return buf; } int main( int argc, char **argv ) { char *s; int tag; int fd, rc; BerElement *ber; Sockbuf *sb; /* enable debugging */ int ival = -1; ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &ival ); if ( argc < 2 ) { usage( argv[0] ); return( EXIT_FAILURE ); } #ifdef HAVE_CONSOLE_H ccommand( &argv ); cshow( stdout ); if (( fd = open( "lber-test", O_WRONLY|O_CREAT|O_TRUNC|O_BINARY )) < 0 ) { perror( "open" ); return( EXIT_FAILURE ); } #else fd = fileno(stdout); #endif sb = ber_sockbuf_alloc(); ber_sockbuf_add_io( sb, &ber_sockbuf_io_fd, LBER_SBIOD_LEVEL_PROVIDER, (void *)&fd ); if( sb == NULL ) { perror( "ber_sockbuf_alloc_fd" ); return( EXIT_FAILURE ); } if ( (ber = ber_alloc_t( LBER_USE_DER )) == NULL ) { perror( "ber_alloc" ); return( EXIT_FAILURE ); } fprintf(stderr, "encode: start\n" ); if( ber_printf( ber, "{" /*}*/ ) ) { perror( "ber_printf {" /*}*/ ); return( EXIT_FAILURE ); } for ( s = argv[1]; *s; s++ ) { char *buf; char fmt[2]; fmt[0] = *s; fmt[1] = '\0'; fprintf(stderr, "encode: %s\n", fmt ); switch ( *s ) { case 'i': /* int */ case 'b': /* boolean */ case 'e': /* enumeration */ buf = getbuf(); rc = ber_printf( ber, fmt, atoi(buf) ); break; case 'n': /* null */ case '{': /* begin sequence */ case '}': /* end sequence */ case '[': /* begin set */ case ']': /* end set */ rc = ber_printf( ber, fmt ); break; case 'o': /* octet string (non-null terminated) */ case 'B': /* bit string */ buf = getbuf(); rc = ber_printf( ber, fmt, buf, strlen(buf) ); break; case 's': /* string */ buf = getbuf(); rc = ber_printf( ber, fmt, buf ); break; case 't': /* tag for the next element */ buf = getbuf(); tag = atoi(buf); rc = ber_printf( ber, fmt, tag ); break; default: fprintf( stderr, "encode: unknown fmt %c\n", *fmt ); rc = -1; break; } if( rc == -1 ) { perror( "ber_printf" ); return( EXIT_FAILURE ); } } fprintf(stderr, "encode: end\n" ); if( ber_printf( ber, /*{*/ "N}" ) == -1 ) { perror( /*{*/ "ber_printf }" ); return( EXIT_FAILURE ); } if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) == -1 ) { perror( "ber_flush2" ); return( EXIT_FAILURE ); } ber_sockbuf_free( sb ); return( EXIT_SUCCESS ); } openldap-2.5.11+dfsg/libraries/liblber/liblber.vers.in0000644000175000017500000000023214172327167021344 0ustar ryanryanHIDDEN { local: __*; _rest*; _save*; }; OPENLDAP_@OPENLDAP_LIBRELEASE@ { global: ber_*; der_alloc*; lutil_*; local: *; }; openldap-2.5.11+dfsg/libraries/liblber/dtest.c0000644000175000017500000000530314172327167017716 0ustar ryanryan/* dtest.c - lber decoding test program */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ /* ACKNOWLEDGEMENTS: * This work was originally developed by the University of Michigan * (as part of U-MICH LDAP). */ #include "portable.h" #include #include #include #include #include #include #ifdef HAVE_CONSOLE_H #include #endif #include static void usage( const char *name ) { fprintf( stderr, "usage: %s fmt\n", name ); } int main( int argc, char **argv ) { char *s; ber_tag_t tag; ber_len_t len; BerElement *ber; Sockbuf *sb; int fd; /* enable debugging */ int ival = -1; ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &ival ); if ( argc < 2 ) { usage( argv[0] ); return( EXIT_FAILURE ); } #ifdef HAVE_CONSOLE_H ccommand( &argv ); cshow( stdout ); #endif sb = ber_sockbuf_alloc(); fd = fileno( stdin ); ber_sockbuf_add_io( sb, &ber_sockbuf_io_fd, LBER_SBIOD_LEVEL_PROVIDER, (void *)&fd ); ber = ber_alloc_t(LBER_USE_DER); if( ber == NULL ) { perror( "ber_alloc_t" ); return( EXIT_FAILURE ); } for (;;) { tag = ber_get_next( sb, &len, ber); if( tag != LBER_ERROR ) break; if( errno == EWOULDBLOCK ) continue; if( errno == EAGAIN ) continue; perror( "ber_get_next" ); return( EXIT_FAILURE ); } printf("decode: message tag 0x%lx and length %ld\n", (unsigned long) tag, (long) len ); for( s = argv[1]; *s; s++ ) { char buf[128]; char fmt[2]; fmt[0] = *s; fmt[1] = '\0'; printf("decode: format %s\n", fmt ); len = sizeof(buf); tag = ber_scanf( ber, fmt, &buf[0], &len ); if( tag == LBER_ERROR ) { perror( "ber_scanf" ); return( EXIT_FAILURE ); } } ber_sockbuf_free( sb ); return( EXIT_SUCCESS ); } openldap-2.5.11+dfsg/libraries/Makefile.in0000644000175000017500000000146114172327167017062 0ustar ryanryan# Libraries Makefile for OpenLDAP # $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . SUBDIRS= \ liblutil \ liblber \ liblunicode \ libldap \ librewrite PKGCONFIG_DIR=$(DESTDIR)$(libdir)/pkgconfig PKGCONFIG_SRCDIRS=liblber libldap install-local: @$(MKDIR) $(PKGCONFIG_DIR) @for i in $(PKGCONFIG_SRCDIRS); do \ $(INSTALL_DATA) $$i/*.pc $(PKGCONFIG_DIR); \ done openldap-2.5.11+dfsg/libraries/librewrite/0000755000175000017500000000000014172327167017163 5ustar ryanryanopenldap-2.5.11+dfsg/libraries/librewrite/map.c0000644000175000017500000002574314172327167020117 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #include #include #ifdef HAVE_PWD_H #include #endif #include "rewrite-int.h" #include "rewrite-map.h" static int num_mappers; static const rewrite_mapper **mappers; #define MAPPER_ALLOC 8 struct rewrite_map * rewrite_map_parse( struct rewrite_info *info, const char *string, const char **currpos ) { struct rewrite_map *map = NULL; struct rewrite_subst *subst = NULL; char *s, *begin = NULL, *end; const char *p; int l, cnt, mtx = 0, rc = 0; assert( info != NULL ); assert( string != NULL ); assert( currpos != NULL ); *currpos = NULL; /* * Go to the end of the map invocation (the right closing brace) */ for ( p = string, cnt = 1; p[ 0 ] != '\0' && cnt > 0; p++ ) { if ( IS_REWRITE_SUBMATCH_ESCAPE( p[ 0 ] ) ) { /* * '%' marks the beginning of a new map */ if ( p[ 1 ] == '{' ) { cnt++; /* * '%' followed by a digit may mark the beginning * of an old map */ } else if ( isdigit( (unsigned char) p[ 1 ] ) && p[ 2 ] == '{' ) { cnt++; p++; } if ( p[ 1 ] != '\0' ) { p++; } } else if ( p[ 0 ] == '}' ) { cnt--; } } if ( cnt != 0 ) { return NULL; } *currpos = p; /* * Copy the map invocation */ l = p - string - 1; s = calloc( sizeof( char ), l + 1 ); if ( s == NULL ) { return NULL; } AC_MEMCPY( s, string, l ); s[ l ] = 0; /* * Isolate the map name (except for variable deref) */ switch ( s[ 0 ] ) { case REWRITE_OPERATOR_VARIABLE_GET: case REWRITE_OPERATOR_PARAM_GET: break; default: begin = strchr( s, '(' ); if ( begin == NULL ) { rc = -1; goto cleanup; } begin[ 0 ] = '\0'; begin++; break; } /* * Check for special map types */ p = s; switch ( p[ 0 ] ) { case REWRITE_OPERATOR_SUBCONTEXT: case REWRITE_OPERATOR_COMMAND: case REWRITE_OPERATOR_VARIABLE_SET: case REWRITE_OPERATOR_VARIABLE_GET: case REWRITE_OPERATOR_PARAM_GET: p++; break; } /* * Variable set and get may be repeated to indicate session-wide * instead of operation-wide variables */ switch ( p[ 0 ] ) { case REWRITE_OPERATOR_VARIABLE_SET: case REWRITE_OPERATOR_VARIABLE_GET: p++; break; } /* * Variable get token can be appended to variable set to mean store * AND rewrite */ if ( p[ 0 ] == REWRITE_OPERATOR_VARIABLE_GET ) { p++; } /* * Check the syntax of the variable name */ if ( !isalpha( (unsigned char) p[ 0 ] ) ) { rc = -1; goto cleanup; } for ( p++; p[ 0 ] != '\0'; p++ ) { if ( !isalnum( (unsigned char) p[ 0 ] ) ) { rc = -1; goto cleanup; } } /* * Isolate the argument of the map (except for variable deref) */ switch ( s[ 0 ] ) { case REWRITE_OPERATOR_VARIABLE_GET: case REWRITE_OPERATOR_PARAM_GET: break; default: end = strrchr( begin, ')' ); if ( end == NULL ) { rc = -1; goto cleanup; } end[ 0 ] = '\0'; /* * Compile the substitution pattern of the map argument */ subst = rewrite_subst_compile( info, begin ); if ( subst == NULL ) { rc = -1; goto cleanup; } break; } /* * Create the map */ map = calloc( sizeof( struct rewrite_map ), 1 ); if ( map == NULL ) { rc = -1; goto cleanup; } memset( map, 0, sizeof( struct rewrite_map ) ); #ifdef USE_REWRITE_LDAP_PVT_THREADS if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) { rc = -1; goto cleanup; } ++mtx; #endif /* USE_REWRITE_LDAP_PVT_THREADS */ /* * No subst for variable deref */ switch ( s[ 0 ] ) { case REWRITE_OPERATOR_VARIABLE_GET: case REWRITE_OPERATOR_PARAM_GET: break; default: map->lm_subst = subst; break; } /* * Parses special map types */ switch ( s[ 0 ] ) { /* * Subcontext */ case REWRITE_OPERATOR_SUBCONTEXT: /* '>' */ /* * Fetch the rewrite context * it MUST have been defined previously */ map->lm_type = REWRITE_MAP_SUBCONTEXT; map->lm_name = strdup( s + 1 ); if ( map->lm_name == NULL ) { rc = -1; goto cleanup; } map->lm_data = rewrite_context_find( info, s + 1 ); if ( map->lm_data == NULL ) { rc = -1; goto cleanup; } break; /* * External command (not implemented yet) */ case REWRITE_OPERATOR_COMMAND: /* '|' */ rc = -1; goto cleanup; /* * Variable set */ case REWRITE_OPERATOR_VARIABLE_SET: /* '&' */ if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_SET ) { if ( s[ 2 ] == REWRITE_OPERATOR_VARIABLE_GET ) { map->lm_type = REWRITE_MAP_SETW_SESN_VAR; map->lm_name = strdup( s + 3 ); } else { map->lm_type = REWRITE_MAP_SET_SESN_VAR; map->lm_name = strdup( s + 2 ); } } else { if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_GET ) { map->lm_type = REWRITE_MAP_SETW_OP_VAR; map->lm_name = strdup( s + 2 ); } else { map->lm_type = REWRITE_MAP_SET_OP_VAR; map->lm_name = strdup( s + 1 ); } } if ( map->lm_name == NULL ) { rc = -1; goto cleanup; } break; /* * Variable dereference */ case REWRITE_OPERATOR_VARIABLE_GET: /* '*' */ if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_GET ) { map->lm_type = REWRITE_MAP_GET_SESN_VAR; map->lm_name = strdup( s + 2 ); } else { map->lm_type = REWRITE_MAP_GET_OP_VAR; map->lm_name = strdup( s + 1 ); } if ( map->lm_name == NULL ) { rc = -1; goto cleanup; } break; /* * Parameter */ case REWRITE_OPERATOR_PARAM_GET: /* '$' */ map->lm_type = REWRITE_MAP_GET_PARAM; map->lm_name = strdup( s + 1 ); if ( map->lm_name == NULL ) { rc = -1; goto cleanup; } break; /* * Built-in map */ default: map->lm_type = REWRITE_MAP_BUILTIN; map->lm_name = strdup( s ); if ( map->lm_name == NULL ) { rc = -1; goto cleanup; } map->lm_data = rewrite_builtin_map_find( info, s ); if ( map->lm_data == NULL ) { rc = -1; goto cleanup; } break; } cleanup: free( s ); if ( rc ) { if ( subst != NULL ) { free( subst ); } if ( map ) { #ifdef USE_REWRITE_LDAP_PVT_THREADS if ( mtx ) { ldap_pvt_thread_mutex_destroy( &map->lm_mutex ); } #endif /* USE_REWRITE_LDAP_PVT_THREADS */ if ( map->lm_name ) { free( map->lm_name ); map->lm_name = NULL; } free( map ); map = NULL; } } return map; } /* * Applies the new map type */ int rewrite_map_apply( struct rewrite_info *info, struct rewrite_op *op, struct rewrite_map *map, struct berval *key, struct berval *val ) { int rc = REWRITE_SUCCESS; assert( info != NULL ); assert( op != NULL ); assert( map != NULL ); assert( key != NULL ); assert( val != NULL ); val->bv_val = NULL; val->bv_len = 0; switch ( map->lm_type ) { case REWRITE_MAP_SUBCONTEXT: rc = rewrite_context_apply( info, op, ( struct rewrite_context * )map->lm_data, key->bv_val, &val->bv_val ); if ( val->bv_val != NULL ) { if ( val->bv_val == key->bv_val ) { val->bv_len = key->bv_len; key->bv_val = NULL; } else { val->bv_len = strlen( val->bv_val ); } } break; case REWRITE_MAP_SET_OP_VAR: case REWRITE_MAP_SETW_OP_VAR: rc = rewrite_var_set( &op->lo_vars, map->lm_name, key->bv_val, 1 ) ? REWRITE_SUCCESS : REWRITE_ERR; if ( rc == REWRITE_SUCCESS ) { if ( map->lm_type == REWRITE_MAP_SET_OP_VAR ) { val->bv_val = strdup( "" ); } else { val->bv_val = strdup( key->bv_val ); val->bv_len = key->bv_len; } if ( val->bv_val == NULL ) { rc = REWRITE_ERR; } } break; case REWRITE_MAP_GET_OP_VAR: { struct rewrite_var *var; var = rewrite_var_find( op->lo_vars, map->lm_name ); if ( var == NULL ) { rc = REWRITE_ERR; } else { val->bv_val = strdup( var->lv_value.bv_val ); val->bv_len = var->lv_value.bv_len; if ( val->bv_val == NULL ) { rc = REWRITE_ERR; } } break; } case REWRITE_MAP_SET_SESN_VAR: case REWRITE_MAP_SETW_SESN_VAR: if ( op->lo_cookie == NULL ) { rc = REWRITE_ERR; break; } rc = rewrite_session_var_set( info, op->lo_cookie, map->lm_name, key->bv_val ); if ( rc == REWRITE_SUCCESS ) { if ( map->lm_type == REWRITE_MAP_SET_SESN_VAR ) { val->bv_val = strdup( "" ); } else { val->bv_val = strdup( key->bv_val ); val->bv_len = key->bv_len; } if ( val->bv_val == NULL ) { rc = REWRITE_ERR; } } break; case REWRITE_MAP_GET_SESN_VAR: rc = rewrite_session_var_get( info, op->lo_cookie, map->lm_name, val ); break; case REWRITE_MAP_GET_PARAM: rc = rewrite_param_get( info, map->lm_name, val ); break; case REWRITE_MAP_BUILTIN: { struct rewrite_builtin_map *bmap = map->lm_data; if ( bmap->lb_mapper && bmap->lb_mapper->rm_apply ) rc = bmap->lb_mapper->rm_apply( bmap->lb_private, key->bv_val, val ); else rc = REWRITE_ERR; break; } default: rc = REWRITE_ERR; break; } return rc; } void rewrite_builtin_map_free( void *tmp ) { struct rewrite_builtin_map *map = ( struct rewrite_builtin_map * )tmp; assert( map != NULL ); if ( map->lb_mapper && map->lb_mapper->rm_destroy ) map->lb_mapper->rm_destroy( map->lb_private ); free( map->lb_name ); free( map ); } int rewrite_map_destroy( struct rewrite_map **pmap ) { struct rewrite_map *map; assert( pmap != NULL ); assert( *pmap != NULL ); map = *pmap; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_lock( &map->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ if ( map->lm_name ) { free( map->lm_name ); map->lm_name = NULL; } if ( map->lm_subst ) { rewrite_subst_destroy( &map->lm_subst ); } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); ldap_pvt_thread_mutex_destroy( &map->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ free( map ); *pmap = NULL; return 0; } /* ldapmap.c */ extern const rewrite_mapper rewrite_ldap_mapper; const rewrite_mapper * rewrite_mapper_find( const char *name ) { int i; if ( !strcasecmp( name, "ldap" )) return &rewrite_ldap_mapper; for (i=0; irm_name )) return mappers[i]; return NULL; } int rewrite_mapper_register( const rewrite_mapper *map ) { if ( num_mappers % MAPPER_ALLOC == 0 ) { const rewrite_mapper **mnew; mnew = realloc( mappers, (num_mappers + MAPPER_ALLOC) * sizeof( rewrite_mapper * )); if ( mnew ) mappers = mnew; else return -1; } mappers[num_mappers++] = map; return 0; } int rewrite_mapper_unregister( const rewrite_mapper *map ) { int i; for (i = 0; i. * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #include #include "rewrite-int.h" /* * Compiles a substitution pattern */ struct rewrite_subst * rewrite_subst_compile( struct rewrite_info *info, const char *str ) { size_t subs_len; struct berval *subs = NULL, *tmps; struct rewrite_submatch *submatch = NULL, *tmpsm; struct rewrite_subst *s = NULL; char *result, *begin, *p; int nsub = 0, l; assert( info != NULL ); assert( str != NULL ); result = strdup( str ); if ( result == NULL ) { return NULL; } /* * Take care of substitution string */ for ( p = begin = result, subs_len = 0; p[ 0 ] != '\0'; p++ ) { /* * Keep only single escapes '%' */ if ( !IS_REWRITE_SUBMATCH_ESCAPE( p[ 0 ] ) ) { continue; } if ( IS_REWRITE_SUBMATCH_ESCAPE( p[ 1 ] ) ) { /* Pull &p[1] over p, including the trailing '\0' */ AC_MEMCPY((char *)p, &p[ 1 ], strlen( p ) ); continue; } tmps = ( struct berval * )realloc( subs, sizeof( struct berval )*( nsub + 1 ) ); if ( tmps == NULL ) { goto cleanup; } subs = tmps; subs[ nsub ].bv_val = NULL; tmpsm = ( struct rewrite_submatch * )realloc( submatch, sizeof( struct rewrite_submatch )*( nsub + 1 ) ); if ( tmpsm == NULL ) { goto cleanup; } submatch = tmpsm; submatch[ nsub ].ls_map = NULL; /* * I think an `if l > 0' at runtime is better outside than * inside a function call ... */ l = p - begin; if ( l > 0 ) { subs_len += l; subs[ nsub ].bv_len = l; subs[ nsub ].bv_val = malloc( l + 1 ); if ( subs[ nsub ].bv_val == NULL ) { goto cleanup; } AC_MEMCPY( subs[ nsub ].bv_val, begin, l ); subs[ nsub ].bv_val[ l ] = '\0'; } else { subs[ nsub ].bv_val = NULL; subs[ nsub ].bv_len = 0; } /* * Substitution pattern */ if ( isdigit( (unsigned char) p[ 1 ] ) ) { int d = p[ 1 ] - '0'; /* * Add a new value substitution scheme */ submatch[ nsub ].ls_submatch = d; /* * If there is no argument, use default * (substitute substring as is) */ if ( p[ 2 ] != '{' ) { submatch[ nsub ].ls_type = REWRITE_SUBMATCH_ASIS; submatch[ nsub ].ls_map = NULL; begin = ++p + 1; } else { struct rewrite_map *map; submatch[ nsub ].ls_type = REWRITE_SUBMATCH_XMAP; map = rewrite_xmap_parse( info, p + 3, (const char **)&begin ); if ( map == NULL ) { goto cleanup; } submatch[ nsub ].ls_map = map; p = begin - 1; } /* * Map with args ... */ } else if ( p[ 1 ] == '{' ) { struct rewrite_map *map; map = rewrite_map_parse( info, p + 2, (const char **)&begin ); if ( map == NULL ) { goto cleanup; } p = begin - 1; /* * Add a new value substitution scheme */ submatch[ nsub ].ls_type = REWRITE_SUBMATCH_MAP_W_ARG; submatch[ nsub ].ls_map = map; /* * Escape '%' ... */ } else if ( p[ 1 ] == '%' ) { AC_MEMCPY( &p[ 1 ], &p[ 2 ], strlen( &p[ 1 ] ) ); continue; } else { goto cleanup; } nsub++; } /* * Last part of string */ tmps = (struct berval * )realloc( subs, sizeof( struct berval )*( nsub + 1 ) ); if ( tmps == NULL ) { /* * XXX need to free the value subst stuff! */ free( subs ); goto cleanup; } subs = tmps; l = p - begin; if ( l > 0 ) { subs_len += l; subs[ nsub ].bv_len = l; subs[ nsub ].bv_val = malloc( l + 1 ); if ( subs[ nsub ].bv_val == NULL ) { goto cleanup; } AC_MEMCPY( subs[ nsub ].bv_val, begin, l ); subs[ nsub ].bv_val[ l ] = '\0'; } else { subs[ nsub ].bv_val = NULL; subs[ nsub ].bv_len = 0; } s = calloc( sizeof( struct rewrite_subst ), 1 ); if ( s == NULL ) { goto cleanup; } s->lt_subs_len = subs_len; s->lt_subs = subs; s->lt_num_submatch = nsub; s->lt_submatch = submatch; subs = NULL; submatch = NULL; cleanup:; if ( subs ) { for ( l=0; lls_type == REWRITE_SUBMATCH_ASIS || submatch->ls_type == REWRITE_SUBMATCH_XMAP ); assert( string != NULL ); assert( match != NULL ); assert( val != NULL ); assert( val->bv_val == NULL ); c = submatch->ls_submatch; s = string + match[ c ].rm_so; l = match[ c ].rm_eo - match[ c ].rm_so; val->bv_len = l; val->bv_val = malloc( l + 1 ); if ( val->bv_val == NULL ) { return REWRITE_ERR; } AC_MEMCPY( val->bv_val, s, l ); val->bv_val[ l ] = '\0'; return REWRITE_SUCCESS; } /* * Substitutes a portion of rewritten string according to substitution * pattern using submatches */ int rewrite_subst_apply( struct rewrite_info *info, struct rewrite_op *op, struct rewrite_subst *subst, const char *string, const regmatch_t *match, struct berval *val ) { struct berval *submatch = NULL; char *res = NULL; int n = 0, l, cl; int rc = REWRITE_REGEXEC_OK; assert( info != NULL ); assert( op != NULL ); assert( subst != NULL ); assert( string != NULL ); assert( match != NULL ); assert( val != NULL ); assert( val->bv_val == NULL ); val->bv_val = NULL; val->bv_len = 0; /* * Prepare room for submatch expansion */ if ( subst->lt_num_submatch > 0 ) { submatch = calloc( sizeof( struct berval ), subst->lt_num_submatch ); if ( submatch == NULL ) { return REWRITE_REGEXEC_ERR; } } /* * Resolve submatches (simple subst, map expansion and so). */ for ( n = 0, l = 0; n < subst->lt_num_submatch; n++ ) { struct berval key = { 0, NULL }; submatch[ n ].bv_val = NULL; /* * Get key */ switch ( subst->lt_submatch[ n ].ls_type ) { case REWRITE_SUBMATCH_ASIS: case REWRITE_SUBMATCH_XMAP: rc = submatch_copy( &subst->lt_submatch[ n ], string, match, &key ); if ( rc != REWRITE_SUCCESS ) { rc = REWRITE_REGEXEC_ERR; goto cleanup; } break; case REWRITE_SUBMATCH_MAP_W_ARG: switch ( subst->lt_submatch[ n ].ls_map->lm_type ) { case REWRITE_MAP_GET_OP_VAR: case REWRITE_MAP_GET_SESN_VAR: case REWRITE_MAP_GET_PARAM: rc = REWRITE_SUCCESS; break; default: rc = rewrite_subst_apply( info, op, subst->lt_submatch[ n ].ls_map->lm_subst, string, match, &key); } if ( rc != REWRITE_SUCCESS ) { goto cleanup; } break; default: Debug( LDAP_DEBUG_ANY, "Not Implemented\n" ); rc = REWRITE_ERR; break; } if ( rc != REWRITE_SUCCESS ) { rc = REWRITE_REGEXEC_ERR; goto cleanup; } /* * Resolve key */ switch ( subst->lt_submatch[ n ].ls_type ) { case REWRITE_SUBMATCH_ASIS: submatch[ n ] = key; rc = REWRITE_SUCCESS; break; case REWRITE_SUBMATCH_XMAP: rc = rewrite_xmap_apply( info, op, subst->lt_submatch[ n ].ls_map, &key, &submatch[ n ] ); free( key.bv_val ); key.bv_val = NULL; break; case REWRITE_SUBMATCH_MAP_W_ARG: rc = rewrite_map_apply( info, op, subst->lt_submatch[ n ].ls_map, &key, &submatch[ n ] ); free( key.bv_val ); key.bv_val = NULL; break; default: /* * When implemented, this might return the * exit status of a rewrite context, * which may include a stop, or an * unwilling to perform */ rc = REWRITE_ERR; break; } if ( rc != REWRITE_SUCCESS ) { rc = REWRITE_REGEXEC_ERR; goto cleanup; } /* * Increment the length of the resulting string */ l += submatch[ n ].bv_len; } /* * Alloc result buffer */ l += subst->lt_subs_len; res = malloc( l + 1 ); if ( res == NULL ) { rc = REWRITE_REGEXEC_ERR; goto cleanup; } /* * Apply submatches (possibly resolved thru maps) */ for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) { if ( subst->lt_subs[ n ].bv_val != NULL ) { AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val, subst->lt_subs[ n ].bv_len ); cl += subst->lt_subs[ n ].bv_len; } AC_MEMCPY( res + cl, submatch[ n ].bv_val, submatch[ n ].bv_len ); cl += submatch[ n ].bv_len; } if ( subst->lt_subs[ n ].bv_val != NULL ) { AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val, subst->lt_subs[ n ].bv_len ); cl += subst->lt_subs[ n ].bv_len; } res[ cl ] = '\0'; val->bv_val = res; val->bv_len = l; cleanup:; if ( submatch ) { for ( ; --n >= 0; ) { if ( submatch[ n ].bv_val ) { free( submatch[ n ].bv_val ); } } free( submatch ); } return rc; } /* * frees data */ int rewrite_subst_destroy( struct rewrite_subst **psubst ) { int n; struct rewrite_subst *subst; assert( psubst != NULL ); assert( *psubst != NULL ); subst = *psubst; for ( n = 0; n < subst->lt_num_submatch; n++ ) { if ( subst->lt_subs[ n ].bv_val ) { free( subst->lt_subs[ n ].bv_val ); subst->lt_subs[ n ].bv_val = NULL; } switch ( subst->lt_submatch[ n ].ls_type ) { case REWRITE_SUBMATCH_ASIS: break; case REWRITE_SUBMATCH_XMAP: rewrite_xmap_destroy( &subst->lt_submatch[ n ].ls_map ); break; case REWRITE_SUBMATCH_MAP_W_ARG: rewrite_map_destroy( &subst->lt_submatch[ n ].ls_map ); break; default: break; } } free( subst->lt_submatch ); subst->lt_submatch = NULL; /* last one */ if ( subst->lt_subs[ n ].bv_val ) { free( subst->lt_subs[ n ].bv_val ); subst->lt_subs[ n ].bv_val = NULL; } free( subst->lt_subs ); subst->lt_subs = NULL; free( subst ); *psubst = NULL; return 0; } openldap-2.5.11+dfsg/libraries/librewrite/params.c0000644000175000017500000000625514172327167020622 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #include #include "rewrite-int.h" /* * Defines and inits a variable with global scope */ int rewrite_param_set( struct rewrite_info *info, const char *name, const char *value ) { struct rewrite_var *var; int rc = REWRITE_SUCCESS; assert( info != NULL ); assert( name != NULL ); assert( value != NULL ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wlock( &info->li_params_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ var = rewrite_var_find( info->li_params, name ); if ( var != NULL ) { assert( var->lv_value.bv_val != NULL ); free( var->lv_value.bv_val ); var->lv_value.bv_val = strdup( value ); var->lv_value.bv_len = strlen( value ); } else { var = rewrite_var_insert( &info->li_params, name, value ); } if ( var == NULL || var->lv_value.bv_val == NULL ) { rc = REWRITE_ERR; } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &info->li_params_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return rc; } /* * Gets a var with global scope */ int rewrite_param_get( struct rewrite_info *info, const char *name, struct berval *value ) { struct rewrite_var *var; int rc = REWRITE_SUCCESS; assert( info != NULL ); assert( name != NULL ); assert( value != NULL ); value->bv_val = NULL; value->bv_len = 0; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_rlock( &info->li_params_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ var = rewrite_var_find( info->li_params, name ); if ( var != NULL ) { value->bv_val = strdup( var->lv_value.bv_val ); value->bv_len = var->lv_value.bv_len; } if ( var == NULL || value->bv_val == NULL ) { rc = REWRITE_ERR; } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_runlock( &info->li_params_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return rc; } static void rewrite_param_free( void *tmp ) { struct rewrite_var *var = ( struct rewrite_var * )tmp; assert( var != NULL ); assert( var->lv_name != NULL ); assert( var->lv_value.bv_val != NULL ); free( var->lv_name ); free( var->lv_value.bv_val ); free( var ); } /* * Destroys the parameter tree */ int rewrite_param_destroy( struct rewrite_info *info ) { assert( info != NULL ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wlock( &info->li_params_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ ldap_avl_free( info->li_params, rewrite_param_free ); info->li_params = NULL; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &info->li_params_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return REWRITE_SUCCESS; } openldap-2.5.11+dfsg/libraries/librewrite/rule.c0000644000175000017500000002270314172327167020302 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #include #include "rewrite-int.h" /* * Appends a rule to the double linked list of rules * Helper for rewrite_rule_compile */ static int append_rule( struct rewrite_context *context, struct rewrite_rule *rule ) { struct rewrite_rule *r; assert( context != NULL ); assert( context->lc_rule != NULL ); assert( rule != NULL ); for ( r = context->lc_rule; r->lr_next != NULL; r = r->lr_next ); r->lr_next = rule; rule->lr_prev = r; return REWRITE_SUCCESS; } /* * Appends an action to the linked list of actions * Helper for rewrite_rule_compile */ static int append_action( struct rewrite_action **pbase, struct rewrite_action *action ) { struct rewrite_action **pa; assert( pbase != NULL ); assert( action != NULL ); for ( pa = pbase; *pa != NULL; pa = &(*pa)->la_next ); *pa = action; return REWRITE_SUCCESS; } static int destroy_action( struct rewrite_action **paction ) { struct rewrite_action *action; assert( paction != NULL ); assert( *paction != NULL ); action = *paction; /* do something */ switch ( action->la_type ) { case REWRITE_FLAG_GOTO: case REWRITE_FLAG_USER: { int *pi = (int *)action->la_args; if ( pi ) { free( pi ); } break; } default: break; } free( action ); *paction = NULL; return 0; } static void destroy_actions( struct rewrite_action *paction ) { struct rewrite_action *next; for (; paction; paction = next) { next = paction->la_next; destroy_action( &paction ); } } /* */ int rewrite_rule_compile( struct rewrite_info *info, struct rewrite_context *context, const char *pattern, const char *result, const char *flagstring ) { int flags = REWRITE_REGEX_EXTENDED | REWRITE_REGEX_ICASE; int mode = REWRITE_RECURSE; int max_passes; struct rewrite_rule *rule = NULL; struct rewrite_subst *subst = NULL; struct rewrite_action *action = NULL, *first_action = NULL; const char *p; assert( info != NULL ); assert( context != NULL ); assert( pattern != NULL ); assert( result != NULL ); /* * A null flagstring should be allowed */ max_passes = info->li_max_passes_per_rule; /* * Take care of substitution string */ subst = rewrite_subst_compile( info, result ); if ( subst == NULL ) { return REWRITE_ERR; } /* * Take care of flags */ for ( p = flagstring; p[ 0 ] != '\0'; p++ ) { switch( p[ 0 ] ) { /* * REGEX flags */ case REWRITE_FLAG_HONORCASE: /* 'C' */ /* * Honor case (default is case insensitive) */ flags &= ~REWRITE_REGEX_ICASE; break; case REWRITE_FLAG_BASICREGEX: /* 'R' */ /* * Use POSIX Basic Regular Expression syntax * instead of POSIX Extended Regular Expression * syntax (default) */ flags &= ~REWRITE_REGEX_EXTENDED; break; /* * Execution mode flags */ case REWRITE_FLAG_EXECONCE: /* ':' */ /* * Apply rule once only */ mode &= ~REWRITE_RECURSE; mode |= REWRITE_EXEC_ONCE; break; /* * Special action flags */ case REWRITE_FLAG_STOP: /* '@' */ /* * Bail out after applying rule */ action = calloc( sizeof( struct rewrite_action ), 1 ); if ( action == NULL ) { goto fail; } action->la_type = REWRITE_ACTION_STOP; break; case REWRITE_FLAG_UNWILLING: /* '#' */ /* * Matching objs will be marked as gone! */ action = calloc( sizeof( struct rewrite_action ), 1 ); if ( action == NULL ) { goto fail; } mode &= ~REWRITE_RECURSE; mode |= REWRITE_EXEC_ONCE; action->la_type = REWRITE_ACTION_UNWILLING; break; case REWRITE_FLAG_GOTO: /* 'G' */ /* * After applying rule, jump N rules */ case REWRITE_FLAG_USER: { /* 'U' */ /* * After applying rule, return user-defined * error code */ char *next = NULL; int *d; if ( p[ 1 ] != '{' ) { goto fail; } d = malloc( sizeof( int ) ); if ( d == NULL ) { goto fail; } d[ 0 ] = strtol( &p[ 2 ], &next, 0 ); if ( next == &p[ 2 ] || next[0] != '}' ) { free( d ); goto fail; } action = calloc( sizeof( struct rewrite_action ), 1 ); if ( action == NULL ) { free( d ); goto fail; } switch ( p[ 0 ] ) { case REWRITE_FLAG_GOTO: action->la_type = REWRITE_ACTION_GOTO; break; case REWRITE_FLAG_USER: action->la_type = REWRITE_ACTION_USER; break; default: assert(0); } action->la_args = (void *)d; p = next; /* p is incremented by the for ... */ break; } case REWRITE_FLAG_MAX_PASSES: { /* 'U' */ /* * Set the number of max passes per rule */ char *next = NULL; if ( p[ 1 ] != '{' ) { goto fail; } max_passes = strtol( &p[ 2 ], &next, 0 ); if ( next == &p[ 2 ] || next[0] != '}' ) { goto fail; } if ( max_passes < 1 ) { /* FIXME: nonsense ... */ max_passes = 1; } p = next; /* p is incremented by the for ... */ break; } case REWRITE_FLAG_IGNORE_ERR: /* 'I' */ /* * Ignore errors! */ action = calloc( sizeof( struct rewrite_action ), 1 ); if ( action == NULL ) { goto fail; } action->la_type = REWRITE_ACTION_IGNORE_ERR; break; /* * Other flags ... */ default: /* * Unimplemented feature (complain only) */ break; } /* * Stupid way to append to a list ... */ if ( action != NULL ) { append_action( &first_action, action ); action = NULL; } } /* * Finally, rule allocation */ rule = calloc( sizeof( struct rewrite_rule ), 1 ); if ( rule == NULL ) { goto fail; } /* * REGEX compilation (luckily I don't need to take care of this ...) */ if ( regcomp( &rule->lr_regex, ( char * )pattern, flags ) != 0 ) { goto fail; } /* * Just to remember them ... */ rule->lr_pattern = strdup( pattern ); rule->lr_subststring = strdup( result ); rule->lr_flagstring = strdup( flagstring ); if ( rule->lr_pattern == NULL || rule->lr_subststring == NULL || rule->lr_flagstring == NULL ) { goto fail; } /* * Load compiled data into rule */ rule->lr_subst = subst; /* * Set various parameters */ rule->lr_flags = flags; /* don't really need any longer ... */ rule->lr_mode = mode; rule->lr_max_passes = max_passes; rule->lr_action = first_action; /* * Append rule at the end of the rewrite context */ append_rule( context, rule ); return REWRITE_SUCCESS; fail: if ( rule ) { if ( rule->lr_pattern ) free( rule->lr_pattern ); if ( rule->lr_subststring ) free( rule->lr_subststring ); if ( rule->lr_flagstring ) free( rule->lr_flagstring ); free( rule ); } destroy_actions( first_action ); free( subst ); return REWRITE_ERR; } /* * Rewrites string according to rule; may return: * OK: fine; if *result != NULL rule matched and rewrite succeeded. * STOP: fine, rule matched; stop processing following rules * UNWILL: rule matched; force 'unwilling to perform' */ int rewrite_rule_apply( struct rewrite_info *info, struct rewrite_op *op, struct rewrite_rule *rule, const char *arg, char **result ) { size_t nmatch = REWRITE_MAX_MATCH; regmatch_t match[ REWRITE_MAX_MATCH ]; int rc = REWRITE_SUCCESS; char *string; int strcnt = 0; struct berval val = { 0, NULL }; assert( info != NULL ); assert( op != NULL ); assert( rule != NULL ); assert( arg != NULL ); assert( result != NULL ); *result = NULL; string = (char *)arg; /* * In case recursive match is required (default) */ recurse:; Debug( LDAP_DEBUG_TRACE, "==> rewrite_rule_apply" " rule='%s' string='%s' [%d pass(es)]\n", rule->lr_pattern, string, strcnt + 1 ); op->lo_num_passes++; rc = regexec( &rule->lr_regex, string, nmatch, match, 0 ); if ( rc != 0 ) { if ( *result == NULL && string != arg ) { free( string ); } /* * No match is OK; *result = NULL means no match */ return REWRITE_REGEXEC_OK; } rc = rewrite_subst_apply( info, op, rule->lr_subst, string, match, &val ); *result = val.bv_val; val.bv_val = NULL; if ( string != arg ) { free( string ); string = NULL; } if ( rc != REWRITE_REGEXEC_OK ) { return rc; } if ( ( rule->lr_mode & REWRITE_RECURSE ) == REWRITE_RECURSE && op->lo_num_passes < info->li_max_passes && ++strcnt < rule->lr_max_passes ) { string = *result; goto recurse; } return REWRITE_REGEXEC_OK; } int rewrite_rule_destroy( struct rewrite_rule **prule ) { struct rewrite_rule *rule; assert( prule != NULL ); assert( *prule != NULL ); rule = *prule; if ( rule->lr_pattern ) { free( rule->lr_pattern ); rule->lr_pattern = NULL; } if ( rule->lr_subststring ) { free( rule->lr_subststring ); rule->lr_subststring = NULL; } if ( rule->lr_flagstring ) { free( rule->lr_flagstring ); rule->lr_flagstring = NULL; } if ( rule->lr_subst ) { rewrite_subst_destroy( &rule->lr_subst ); } regfree( &rule->lr_regex ); destroy_actions( rule->lr_action ); free( rule ); *prule = NULL; return 0; } openldap-2.5.11+dfsg/libraries/librewrite/Makefile.in0000644000175000017500000000217014172327167021230 0ustar ryanryan# LIBREWRITE # $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . ## ## Copyright 2000-2001 Pierangelo Masarati ## SRCS = config.c context.c info.c ldapmap.c map.c params.c rule.c \ session.c subst.c var.c xmap.c \ parse.c rewrite.c XSRCS = version.c OBJS = config.o context.o info.o ldapmap.o map.o params.o rule.o \ session.o subst.o var.o xmap.o LDAP_INCDIR= ../../include LDAP_LIBDIR= ../../libraries LIBRARY = librewrite.a PROGRAMS = rewrite XLIBS = $(LIBRARY) $(LDAP_LIBLUTIL_A) \ $(LDAP_LIBLDAP_LA) $(LDAP_LIBLBER_LA) XXLIBS = $(SECURITY_LIBS) $(LUTIL_LIBS) XXXLIBS = $(LTHREAD_LIBS) rewrite: $(XLIBS) rewrite.o parse.o $(LTLINK) -o $@ rewrite.o parse.o $(LIBS) openldap-2.5.11+dfsg/libraries/librewrite/RATIONALE0000644000175000017500000000015514172327167020425 0ustar ryanryanThe workings of the rewrite library are described in the REWRITING section of the slapd-meta(5) manual page. openldap-2.5.11+dfsg/libraries/librewrite/session.c0000644000175000017500000002346114172327167021020 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #include #include "rewrite-int.h" /* * Compares two cookies */ static int rewrite_cookie_cmp( const void *c1, const void *c2 ) { const struct rewrite_session *s1, *s2; s1 = ( const struct rewrite_session * )c1; s2 = ( const struct rewrite_session * )c2; assert( s1 != NULL ); assert( s2 != NULL ); assert( s1->ls_cookie != NULL ); assert( s2->ls_cookie != NULL ); return ( ( s1->ls_cookie < s2->ls_cookie ) ? -1 : ( ( s1->ls_cookie > s2->ls_cookie ) ? 1 : 0 ) ); } /* * Duplicate cookies? */ static int rewrite_cookie_dup( void *c1, void *c2 ) { struct rewrite_session *s1, *s2; s1 = ( struct rewrite_session * )c1; s2 = ( struct rewrite_session * )c2; assert( s1 != NULL ); assert( s2 != NULL ); assert( s1->ls_cookie != NULL ); assert( s2->ls_cookie != NULL ); assert( s1->ls_cookie != s2->ls_cookie ); return ( ( s1->ls_cookie == s2->ls_cookie ) ? -1 : 0 ); } /* * Inits a session */ struct rewrite_session * rewrite_session_init( struct rewrite_info *info, const void *cookie ) { struct rewrite_session *session, tmp; int rc; assert( info != NULL ); assert( cookie != NULL ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ tmp.ls_cookie = ( void * )cookie; session = ( struct rewrite_session * )ldap_avl_find( info->li_cookies, ( caddr_t )&tmp, rewrite_cookie_cmp ); if ( session ) { session->ls_count++; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return session; } session = calloc( sizeof( struct rewrite_session ), 1 ); if ( session == NULL ) { #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return NULL; } session->ls_cookie = ( void * )cookie; session->ls_count = 1; #ifdef USE_REWRITE_LDAP_PVT_THREADS if ( ldap_pvt_thread_mutex_init( &session->ls_mutex ) ) { free( session ); ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex ); return NULL; } if ( ldap_pvt_thread_rdwr_init( &session->ls_vars_mutex ) ) { ldap_pvt_thread_mutex_destroy( &session->ls_mutex ); free( session ); ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex ); return NULL; } #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rc = ldap_avl_insert( &info->li_cookies, ( caddr_t )session, rewrite_cookie_cmp, rewrite_cookie_dup ); info->li_num_cookies++; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ if ( rc != 0 ) { #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_destroy( &session->ls_vars_mutex ); ldap_pvt_thread_mutex_destroy( &session->ls_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ free( session ); return NULL; } return session; } /* * Fetches a session */ struct rewrite_session * rewrite_session_find( struct rewrite_info *info, const void *cookie ) { struct rewrite_session *session, tmp; assert( info != NULL ); assert( cookie != NULL ); tmp.ls_cookie = ( void * )cookie; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_rlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ session = ( struct rewrite_session * )ldap_avl_find( info->li_cookies, ( caddr_t )&tmp, rewrite_cookie_cmp ); #ifdef USE_REWRITE_LDAP_PVT_THREADS if ( session ) { ldap_pvt_thread_mutex_lock( &session->ls_mutex ); session->ls_count++; } ldap_pvt_thread_rdwr_runlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return session; } /* * Returns a session */ void rewrite_session_return( struct rewrite_info *info, struct rewrite_session *session ) { assert( session != NULL ); session->ls_count--; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_unlock( &session->ls_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ } /* * Defines and inits a var with session scope */ int rewrite_session_var_set_f( struct rewrite_info *info, const void *cookie, const char *name, const char *value, int flags ) { struct rewrite_session *session; struct rewrite_var *var; assert( info != NULL ); assert( cookie != NULL ); assert( name != NULL ); assert( value != NULL ); session = rewrite_session_find( info, cookie ); if ( session == NULL ) { session = rewrite_session_init( info, cookie ); if ( session == NULL ) { return REWRITE_ERR; } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_lock( &session->ls_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wlock( &session->ls_vars_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ var = rewrite_var_find( session->ls_vars, name ); if ( var != NULL ) { assert( var->lv_value.bv_val != NULL ); (void)rewrite_var_replace( var, value, flags ); } else { var = rewrite_var_insert_f( &session->ls_vars, name, value, flags ); if ( var == NULL ) { #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &session->ls_vars_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rewrite_session_return( info, session ); return REWRITE_ERR; } } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &session->ls_vars_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rewrite_session_return( info, session ); return REWRITE_SUCCESS; } /* * Gets a var with session scope */ int rewrite_session_var_get( struct rewrite_info *info, const void *cookie, const char *name, struct berval *value ) { struct rewrite_session *session; struct rewrite_var *var; int rc = REWRITE_SUCCESS; assert( info != NULL ); assert( cookie != NULL ); assert( name != NULL ); assert( value != NULL ); value->bv_val = NULL; value->bv_len = 0; if ( cookie == NULL ) { return REWRITE_ERR; } session = rewrite_session_find( info, cookie ); if ( session == NULL ) { return REWRITE_ERR; } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_rlock( &session->ls_vars_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ var = rewrite_var_find( session->ls_vars, name ); if ( var != NULL ) { value->bv_val = strdup( var->lv_value.bv_val ); value->bv_len = var->lv_value.bv_len; } if ( var == NULL || value->bv_val == NULL ) { rc = REWRITE_ERR; } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_runlock( &session->ls_vars_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rewrite_session_return( info, session ); return rc; } static void rewrite_session_clean( void *v_session ) { struct rewrite_session *session = (struct rewrite_session *)v_session; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wlock( &session->ls_vars_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rewrite_var_delete( session->ls_vars ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &session->ls_vars_mutex ); ldap_pvt_thread_rdwr_destroy( &session->ls_vars_mutex ); ldap_pvt_thread_mutex_unlock( &session->ls_mutex ); ldap_pvt_thread_mutex_destroy( &session->ls_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ } static void rewrite_session_free( void *v_session ) { struct rewrite_session *session = (struct rewrite_session *)v_session; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_lock( &session->ls_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rewrite_session_clean( v_session ); free( v_session ); } /* * Deletes a session */ int rewrite_session_delete( struct rewrite_info *info, const void *cookie ) { struct rewrite_session *session, tmp = { 0 }; assert( info != NULL ); assert( cookie != NULL ); session = rewrite_session_find( info, cookie ); if ( session == NULL ) { return REWRITE_SUCCESS; } if ( --session->ls_count > 0 ) { rewrite_session_return( info, session ); return REWRITE_SUCCESS; } rewrite_session_clean( session ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ assert( info->li_num_cookies > 0 ); info->li_num_cookies--; /* * There is nothing to delete in the return value */ tmp.ls_cookie = ( void * )cookie; ldap_avl_delete( &info->li_cookies, ( caddr_t )&tmp, rewrite_cookie_cmp ); free( session ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return REWRITE_SUCCESS; } /* * Destroys the cookie tree */ int rewrite_session_destroy( struct rewrite_info *info ) { int count; assert( info != NULL ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ /* * Should call per-session destruction routine ... */ count = ldap_avl_free( info->li_cookies, rewrite_session_free ); info->li_cookies = NULL; #if 0 fprintf( stderr, "count = %d; num_cookies = %d\n", count, info->li_num_cookies ); #endif assert( count == info->li_num_cookies ); info->li_num_cookies = 0; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return REWRITE_SUCCESS; } openldap-2.5.11+dfsg/libraries/librewrite/parse.c0000644000175000017500000000466214172327167020451 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #include #include #include "rewrite-int.h" static int parse_line( char **argv, int *argc, int maxargs, char *buf ) { char *p, *begin; int in_quoted_field = 0, cnt = 0; char quote = '\0'; for ( p = buf; isspace( (unsigned char) p[ 0 ] ); p++ ); if ( p[ 0 ] == '#' ) { return 0; } for ( begin = p; p[ 0 ] != '\0'; p++ ) { if ( p[ 0 ] == '\\' && p[ 1 ] != '\0' ) { p++; } else if ( p[ 0 ] == '\'' || p[ 0 ] == '\"') { if ( in_quoted_field && p[ 0 ] == quote ) { in_quoted_field = 1 - in_quoted_field; quote = '\0'; p[ 0 ] = '\0'; argv[ cnt ] = begin; if ( ++cnt == maxargs ) { *argc = cnt; return 1; } for ( p++; isspace( (unsigned char) p[ 0 ] ); p++ ); begin = p; p--; } else if ( !in_quoted_field ) { if ( p != begin ) { return -1; } begin++; in_quoted_field = 1 - in_quoted_field; quote = p[ 0 ]; } } else if ( isspace( (unsigned char) p[ 0 ] ) && !in_quoted_field ) { p[ 0 ] = '\0'; argv[ cnt ] = begin; if ( ++cnt == maxargs ) { *argc = cnt; return 1; } for ( p++; isspace( (unsigned char) p[ 0 ] ); p++ ); begin = p; p--; } } *argc = cnt; return 1; } int rewrite_read( FILE *fin, struct rewrite_info *info ) { char buf[ 1024 ]; char *argv[11]; int argc, lineno; /* * Empty rule at the beginning of the context */ for ( lineno = 0; fgets( buf, sizeof( buf ), fin ); lineno++ ) { switch ( parse_line( argv, &argc, sizeof( argv ) - 1, buf ) ) { case -1: return REWRITE_ERR; case 0: break; case 1: if ( strncasecmp( argv[ 0 ], "rewrite", 7 ) == 0 ) { int rc; rc = rewrite_parse( info, "file", lineno, argc, argv ); if ( rc != REWRITE_SUCCESS ) { return rc; } } break; } } return REWRITE_SUCCESS; } openldap-2.5.11+dfsg/libraries/librewrite/rewrite-map.h0000644000175000017500000000153314172327167021572 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #ifndef MAP_H #define MAP_H /* * Retrieves a builtin map */ LDAP_REWRITE_F (struct rewrite_builtin_map *) rewrite_builtin_map_find( struct rewrite_info *info, const char *name ); #endif /* MAP_H */ openldap-2.5.11+dfsg/libraries/librewrite/info.c0000644000175000017500000001402214172327167020261 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #include #include "rewrite-int.h" /* * Global data */ /* * This becomes the running context for subsequent calls to * rewrite_parse; it can be altered only by a * rewriteContext config line or by a change in info. */ struct rewrite_context *rewrite_int_curr_context = NULL; /* * Inits the info */ struct rewrite_info * rewrite_info_init( int mode ) { struct rewrite_info *info; struct rewrite_context *context; switch ( mode ) { case REWRITE_MODE_ERR: case REWRITE_MODE_OK: case REWRITE_MODE_COPY_INPUT: case REWRITE_MODE_USE_DEFAULT: break; default: mode = REWRITE_MODE_USE_DEFAULT; break; /* return NULL */ } /* * Resets the running context for parsing ... */ rewrite_int_curr_context = NULL; info = calloc( sizeof( struct rewrite_info ), 1 ); if ( info == NULL ) { return NULL; } info->li_state = REWRITE_DEFAULT; info->li_max_passes = REWRITE_MAX_PASSES; info->li_max_passes_per_rule = REWRITE_MAX_PASSES; info->li_rewrite_mode = mode; /* * Add the default (empty) rule */ context = rewrite_context_create( info, REWRITE_DEFAULT_CONTEXT ); if ( context == NULL ) { free( info ); return NULL; } #ifdef USE_REWRITE_LDAP_PVT_THREADS if ( ldap_pvt_thread_rdwr_init( &info->li_cookies_mutex ) ) { ldap_avl_free( info->li_context, rewrite_context_free ); free( info ); return NULL; } if ( ldap_pvt_thread_rdwr_init( &info->li_params_mutex ) ) { ldap_pvt_thread_rdwr_destroy( &info->li_cookies_mutex ); ldap_avl_free( info->li_context, rewrite_context_free ); free( info ); return NULL; } #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return info; } /* * Cleans up the info structure */ int rewrite_info_delete( struct rewrite_info **pinfo ) { struct rewrite_info *info; assert( pinfo != NULL ); assert( *pinfo != NULL ); info = *pinfo; if ( info->li_context ) { ldap_avl_free( info->li_context, rewrite_context_free ); } info->li_context = NULL; if ( info->li_maps ) { ldap_avl_free( info->li_maps, rewrite_builtin_map_free ); } info->li_maps = NULL; rewrite_session_destroy( info ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_destroy( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rewrite_param_destroy( info ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_destroy( &info->li_params_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ free( info ); *pinfo = NULL; return REWRITE_SUCCESS; } /* * Rewrites a string according to context. * If the engine is off, OK is returned, but the return string will be NULL. * In case of 'unwilling to perform', UNWILLING is returned, and the * return string will also be null. The same in case of error. * Otherwise, OK is returned, and result will hold a newly allocated string * with the rewriting. * * What to do in case of non-existing rewrite context is still an issue. * Four possibilities: * - error, * - ok with NULL result, * - ok with copy of string as result, * - use the default rewrite context. */ int rewrite( struct rewrite_info *info, const char *rewriteContext, const char *string, char **result ) { return rewrite_session( info, rewriteContext, string, NULL, result ); } int rewrite_session( struct rewrite_info *info, const char *rewriteContext, const char *string, const void *cookie, char **result ) { struct rewrite_context *context; struct rewrite_op op = { 0, 0, NULL, NULL, NULL }; int rc; assert( info != NULL ); assert( rewriteContext != NULL ); assert( string != NULL ); assert( result != NULL ); /* * cookie can be null; means: don't care about session stuff */ *result = NULL; op.lo_cookie = cookie; /* * Engine not on means no failure, but explicit no rewriting */ if ( info->li_state != REWRITE_ON ) { rc = REWRITE_REGEXEC_OK; goto rc_return; } /* * Undefined context means no rewriting also * (conservative, are we sure it's what we want?) */ context = rewrite_context_find( info, rewriteContext ); if ( context == NULL ) { switch ( info->li_rewrite_mode ) { case REWRITE_MODE_ERR: rc = REWRITE_REGEXEC_ERR; goto rc_return; case REWRITE_MODE_OK: rc = REWRITE_REGEXEC_OK; goto rc_return; case REWRITE_MODE_COPY_INPUT: *result = strdup( string ); rc = ( *result != NULL ) ? REWRITE_REGEXEC_OK : REWRITE_REGEXEC_ERR; goto rc_return; case REWRITE_MODE_USE_DEFAULT: context = rewrite_context_find( info, REWRITE_DEFAULT_CONTEXT ); break; } } #if 0 /* FIXME: not used anywhere! (debug? then, why strdup?) */ op.lo_string = strdup( string ); if ( op.lo_string == NULL ) { rc = REWRITE_REGEXEC_ERR; goto rc_return; } #endif /* * Applies rewrite context */ rc = rewrite_context_apply( info, &op, context, string, result ); assert( op.lo_depth == 0 ); #if 0 /* FIXME: not used anywhere! (debug? then, why strdup?) */ free( op.lo_string ); #endif switch ( rc ) { /* * Success */ case REWRITE_REGEXEC_OK: case REWRITE_REGEXEC_STOP: /* * If rewrite succeeded return OK regardless of how * the successful rewriting was obtained! */ rc = REWRITE_REGEXEC_OK; break; /* * Internal or forced error, return = NULL; rc already OK. */ case REWRITE_REGEXEC_UNWILLING: case REWRITE_REGEXEC_ERR: if ( *result != NULL ) { if ( *result != string ) { free( *result ); } *result = NULL; } default: break; } rc_return:; if ( op.lo_vars ) { rewrite_var_delete( op.lo_vars ); } return rc; } openldap-2.5.11+dfsg/libraries/librewrite/context.c0000644000175000017500000002325614172327167021023 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #include #include "rewrite-int.h" /* * Compares two struct rewrite_context based on the name; * used by avl stuff */ static int rewrite_context_cmp( const void *c1, const void *c2 ) { const struct rewrite_context *lc1, *lc2; lc1 = (const struct rewrite_context *)c1; lc2 = (const struct rewrite_context *)c2; assert( c1 != NULL ); assert( c2 != NULL ); assert( lc1->lc_name != NULL ); assert( lc2->lc_name != NULL ); return strcasecmp( lc1->lc_name, lc2->lc_name ); } /* * Returns -1 in case a duplicate struct rewrite_context * has been inserted; used by avl stuff */ static int rewrite_context_dup( void *c1, void *c2 ) { struct rewrite_context *lc1, *lc2; lc1 = (struct rewrite_context *)c1; lc2 = (struct rewrite_context *)c2; assert( c1 != NULL ); assert( c2 != NULL ); assert( lc1->lc_name != NULL ); assert( lc2->lc_name != NULL ); return( strcasecmp( lc1->lc_name, lc2->lc_name) == 0 ? -1 : 0 ); } /* * Finds the context named rewriteContext in the context tree */ struct rewrite_context * rewrite_context_find( struct rewrite_info *info, const char *rewriteContext ) { struct rewrite_context *context, c; assert( info != NULL ); assert( rewriteContext != NULL ); /* * Fetches the required rewrite context */ c.lc_name = (char *)rewriteContext; context = (struct rewrite_context *)ldap_avl_find( info->li_context, (caddr_t)&c, rewrite_context_cmp ); if ( context == NULL ) { return NULL; } /* * De-aliases the context if required */ if ( context->lc_alias ) { return context->lc_alias; } return context; } /* * Creates a new context called rewriteContext and stores in into the tree */ struct rewrite_context * rewrite_context_create( struct rewrite_info *info, const char *rewriteContext ) { struct rewrite_context *context; int rc; assert( info != NULL ); assert( rewriteContext != NULL ); context = calloc( sizeof( struct rewrite_context ), 1 ); if ( context == NULL ) { return NULL; } /* * Context name */ context->lc_name = strdup( rewriteContext ); if ( context->lc_name == NULL ) { free( context ); return NULL; } /* * The first, empty rule */ context->lc_rule = calloc( sizeof( struct rewrite_rule ), 1 ); if ( context->lc_rule == NULL ) { free( context->lc_name ); free( context ); return NULL; } memset( context->lc_rule, 0, sizeof( struct rewrite_rule ) ); /* * Add context to tree */ rc = ldap_avl_insert( &info->li_context, (caddr_t)context, rewrite_context_cmp, rewrite_context_dup ); if ( rc == -1 ) { free( context->lc_rule ); free( context->lc_name ); free( context ); return NULL; } return context; } /* * Finds the next rule according to a goto action statement, * or null in case of error. * Helper for rewrite_context_apply. */ static struct rewrite_rule * rewrite_action_goto( struct rewrite_action *action, struct rewrite_rule *rule ) { int n; assert( action != NULL ); assert( action->la_args != NULL ); assert( rule != NULL ); n = ((int *)action->la_args)[ 0 ]; if ( n > 0 ) { for ( ; n > 1 && rule != NULL ; n-- ) { rule = rule->lr_next; } } else if ( n <= 0 ) { for ( ; n < 1 && rule != NULL ; n++ ) { rule = rule->lr_prev; } } return rule; } /* * Rewrites string according to context; may return: * OK: fine; if *result != NULL rule matched and rewrite succeeded. * STOP: fine, rule matched; stop processing following rules * UNWILL: rule matched; force 'unwilling to perform' */ int rewrite_context_apply( struct rewrite_info *info, struct rewrite_op *op, struct rewrite_context *context, const char *string, char **result ) { struct rewrite_rule *rule; char *s, *res = NULL; int return_code = REWRITE_REGEXEC_OK; assert( info != NULL ); assert( op != NULL ); assert( context != NULL ); assert( context->lc_rule != NULL ); assert( string != NULL ); assert( result != NULL ); op->lo_depth++; Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply" " [depth=%d] string='%s'\n", op->lo_depth, string ); assert( op->lo_depth > 0 ); s = (char *)string; for ( rule = context->lc_rule->lr_next; rule != NULL && op->lo_num_passes < info->li_max_passes; rule = rule->lr_next, op->lo_num_passes++ ) { int rc; /* * Apply a single rule */ rc = rewrite_rule_apply( info, op, rule, s, &res ); /* * A rule may return: * OK with result != NULL if matched * ERR if anything was wrong * UNWILLING if the server should drop the request * the latter case in honored immediately; * the other two may require some special actions to take * place. */ switch ( rc ) { case REWRITE_REGEXEC_ERR: Debug( LDAP_DEBUG_ANY, "==> rewrite_context_apply" " error ...\n" ); /* * Checks for special actions to be taken * in case of error ... */ if ( rule->lr_action != NULL ) { struct rewrite_action *action; int do_continue = 0; for ( action = rule->lr_action; action != NULL; action = action->la_next ) { switch ( action->la_type ) { /* * This action takes precedence * over the others in case of failure */ case REWRITE_ACTION_IGNORE_ERR: Debug( LDAP_DEBUG_ANY, "==> rewrite_context_apply" " ignoring error ...\n" ); do_continue = 1; break; /* * Goto is honored only if it comes * after ignore error */ case REWRITE_ACTION_GOTO: if ( do_continue ) { rule = rewrite_action_goto( action, rule ); if ( rule == NULL ) { return_code = REWRITE_REGEXEC_ERR; goto rc_end_of_context; } } break; /* * Other actions are ignored */ default: break; } } if ( do_continue ) { if ( rule->lr_next == NULL ) { res = s; } goto rc_continue; } } /* * Default behavior is to bail out ... */ return_code = REWRITE_REGEXEC_ERR; goto rc_end_of_context; /* * OK means there were no errors or special return codes; * if res is defined, it means the rule matched and we * got a successful rewriting */ case REWRITE_REGEXEC_OK: /* * It matched! Check for actions ... */ if ( res != NULL ) { struct rewrite_action *action; if ( s != string && s != res ) { free( s ); } s = res; for ( action = rule->lr_action; action != NULL; action = action->la_next ) { switch ( action->la_type ) { /* * This ends the rewrite context * successfully */ case REWRITE_ACTION_STOP: goto rc_end_of_context; /* * This instructs the server to return * an `unwilling to perform' error * message */ case REWRITE_ACTION_UNWILLING: return_code = REWRITE_REGEXEC_UNWILLING; goto rc_end_of_context; /* * This causes the processing to * jump n rules back and forth */ case REWRITE_ACTION_GOTO: rule = rewrite_action_goto( action, rule ); if ( rule == NULL ) { return_code = REWRITE_REGEXEC_ERR; goto rc_end_of_context; } break; /* * This ends the rewrite context * and returns a user-defined * error code */ case REWRITE_ACTION_USER: return_code = ((int *)action->la_args)[ 0 ]; goto rc_end_of_context; default: /* ... */ break; } } /* * If result was OK and string didn't match, * in case of last rule we need to set the * result back to the string */ } else if ( rule->lr_next == NULL ) { res = s; } break; /* * A STOP has propagated ... */ case REWRITE_REGEXEC_STOP: goto rc_end_of_context; /* * This will instruct the server to return * an `unwilling to perform' error message */ case REWRITE_REGEXEC_UNWILLING: return_code = REWRITE_REGEXEC_UNWILLING; goto rc_end_of_context; /* * A user-defined error code has propagated ... */ default: assert( rc >= REWRITE_REGEXEC_USER ); goto rc_end_of_context; } rc_continue:; /* sent here by actions that require to continue */ } rc_end_of_context:; *result = res; Debug( LDAP_DEBUG_TRACE, "==> rewrite_context_apply" " [depth=%d] res={%d,'%s'}\n", op->lo_depth, return_code, ( res ? res : "NULL" ) ); assert( op->lo_depth > 0 ); op->lo_depth--; return return_code; } void rewrite_context_free( void *tmp ) { struct rewrite_context *context = (struct rewrite_context *)tmp; assert( tmp != NULL ); rewrite_context_destroy( &context ); } int rewrite_context_destroy( struct rewrite_context **pcontext ) { struct rewrite_context *context; struct rewrite_rule *r; assert( pcontext != NULL ); assert( *pcontext != NULL ); context = *pcontext; assert( context->lc_rule != NULL ); for ( r = context->lc_rule->lr_next; r; ) { struct rewrite_rule *cr = r; r = r->lr_next; rewrite_rule_destroy( &cr ); } free( context->lc_rule ); context->lc_rule = NULL; assert( context->lc_name != NULL ); free( context->lc_name ); context->lc_name = NULL; free( context ); *pcontext = NULL; return 0; } openldap-2.5.11+dfsg/libraries/librewrite/config.c0000644000175000017500000002343714172327167020605 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #include #include "rewrite-int.h" #include "rewrite-map.h" /* * Parses a plugin map */ static int rewrite_parse_builtin_map( struct rewrite_info *info, const char *fname, int lineno, int argc, char **argv ); /* * Parses a config line and takes actions to fit content in rewrite structure; * lines handled are of the form: * * rewriteEngine {on|off} * rewriteMaxPasses numPasses [numPassesPerRule] * rewriteContext contextName [alias aliasedContextName] * rewriteRule pattern substPattern [ruleFlags] * rewriteMap mapType mapName [mapArgs] * rewriteParam paramName paramValue */ int rewrite_parse( struct rewrite_info *info, const char *fname, int lineno, int argc, char **argv ) { int rc = -1; assert( info != NULL ); assert( fname != NULL ); assert( argv != NULL ); assert( argc > 0 ); /* * Switch on the rewrite engine */ if ( strcasecmp( argv[ 0 ], "rewriteEngine" ) == 0 ) { if ( argc < 2 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteEngine needs 'state'\n", fname, lineno ); return -1; } else if ( argc > 2 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] extra fields in rewriteEngine" " will be discarded\n", fname, lineno ); } if ( strcasecmp( argv[ 1 ], "on" ) == 0 ) { info->li_state = REWRITE_ON; } else if ( strcasecmp( argv[ 1 ], "off" ) == 0 ) { info->li_state = REWRITE_OFF; } else { Debug( LDAP_DEBUG_ANY, "[%s:%d] unknown 'state' in rewriteEngine;" " assuming 'on'\n", fname, lineno ); info->li_state = REWRITE_ON; } rc = REWRITE_SUCCESS; /* * Alter max passes */ } else if ( strcasecmp( argv[ 0 ], "rewriteMaxPasses" ) == 0 ) { if ( argc < 2 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteMaxPasses needs 'value'\n", fname, lineno ); return -1; } if ( lutil_atoi( &info->li_max_passes, argv[ 1 ] ) != 0 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] unable to parse rewriteMaxPasses=\"%s\"\n", fname, lineno, argv[ 1 ] ); return -1; } if ( info->li_max_passes <= 0 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] negative or null rewriteMaxPasses\n", fname, lineno ); return -1; } if ( argc > 2 ) { if ( lutil_atoi( &info->li_max_passes_per_rule, argv[ 2 ] ) != 0 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] unable to parse rewriteMaxPassesPerRule=\"%s\"\n", fname, lineno, argv[ 2 ] ); return -1; } if ( info->li_max_passes_per_rule <= 0 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] negative or null rewriteMaxPassesPerRule\n", fname, lineno ); return -1; } } else { info->li_max_passes_per_rule = info->li_max_passes; } rc = REWRITE_SUCCESS; /* * Start a new rewrite context and set current context */ } else if ( strcasecmp( argv[ 0 ], "rewriteContext" ) == 0 ) { if ( argc < 2 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteContext needs 'name'\n", fname, lineno ); return -1; } /* * Checks for existence (lots of contexts should be * available by default ...) */ rewrite_int_curr_context = rewrite_context_find( info, argv[ 1 ] ); if ( rewrite_int_curr_context == NULL ) { rewrite_int_curr_context = rewrite_context_create( info, argv[ 1 ] ); } if ( rewrite_int_curr_context == NULL ) { return -1; } if ( argc > 2 ) { /* * A context can alias another (e.g., the `builtin' * contexts for backend operations, if not defined, * alias the `default' rewrite context (with the * notable exception of the searchResult context, * which can be undefined) */ if ( strcasecmp( argv[ 2 ], "alias" ) == 0 ) { struct rewrite_context *aliased; if ( argc == 3 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteContext" " needs 'name' after" " 'alias'\n", fname, lineno ); return -1; } else if ( argc > 4 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] extra fields in" " rewriteContext" " after aliased name" " will be" " discarded\n", fname, lineno ); } aliased = rewrite_context_find( info, argv[ 3 ] ); if ( aliased == NULL ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] aliased" " rewriteContext '%s'" " does not exists\n", fname, lineno, argv[ 3 ] ); return -1; } rewrite_int_curr_context->lc_alias = aliased; rewrite_int_curr_context = aliased; } else { Debug( LDAP_DEBUG_ANY, "[%s:%d] extra fields" " in rewriteContext" " will be discarded\n", fname, lineno ); } } rc = REWRITE_SUCCESS; /* * Compile a rule in current context */ } else if ( strcasecmp( argv[ 0 ], "rewriteRule" ) == 0 ) { if ( argc < 3 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteRule needs 'pattern'" " 'subst' ['flags']\n", fname, lineno ); return -1; } else if ( argc > 4 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] extra fields in rewriteRule" " will be discarded\n", fname, lineno ); } if ( rewrite_int_curr_context == NULL ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteRule outside a" " context; will add to default\n", fname, lineno ); rewrite_int_curr_context = rewrite_context_find( info, REWRITE_DEFAULT_CONTEXT ); /* * Default context MUST exist in a properly initialized * struct rewrite_info */ assert( rewrite_int_curr_context != NULL ); } rc = rewrite_rule_compile( info, rewrite_int_curr_context, argv[ 1 ], argv[ 2 ], ( argc == 4 ? argv[ 3 ] : "" ) ); /* * Add a plugin map to the map tree */ } else if ( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 ) { if ( argc < 3 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteMap needs at least 'type'" " and 'name' ['args']\n", fname, lineno ); return -1; } rc = rewrite_parse_builtin_map( info, fname, lineno, argc, argv ); /* * Set the value of a global scope parameter */ } else if ( strcasecmp( argv[ 0 ], "rewriteParam" ) == 0 ) { if ( argc < 3 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteParam needs 'name'" " and 'value'\n", fname, lineno ); return -1; } rc = rewrite_param_set( info, argv[ 1 ], argv[ 2 ] ); /* * Error */ } else { Debug( LDAP_DEBUG_ANY, "[%s:%d] unknown command '%s'\n", fname, lineno, argv[ 0 ] ); return -1; } return rc; } /* * Compares two maps */ static int rewrite_builtin_map_cmp( const void *c1, const void *c2 ) { const struct rewrite_builtin_map *m1, *m2; m1 = ( const struct rewrite_builtin_map * )c1; m2 = ( const struct rewrite_builtin_map * )c2; assert( m1 != NULL ); assert( m2 != NULL ); assert( m1->lb_name != NULL ); assert( m2->lb_name != NULL ); return strcasecmp( m1->lb_name, m2->lb_name ); } /* * Duplicate map ? */ static int rewrite_builtin_map_dup( void *c1, void *c2 ) { struct rewrite_builtin_map *m1, *m2; m1 = ( struct rewrite_builtin_map * )c1; m2 = ( struct rewrite_builtin_map * )c2; assert( m1 != NULL ); assert( m2 != NULL ); assert( m1->lb_name != NULL ); assert( m2->lb_name != NULL ); return ( strcasecmp( m1->lb_name, m2->lb_name ) == 0 ? -1 : 0 ); } /* * Adds a map to the info map tree */ static int rewrite_builtin_map_insert( struct rewrite_info *info, struct rewrite_builtin_map *map ) { /* * May need a mutex? */ return ldap_avl_insert( &info->li_maps, ( caddr_t )map, rewrite_builtin_map_cmp, rewrite_builtin_map_dup ); } /* * Retrieves a map */ struct rewrite_builtin_map * rewrite_builtin_map_find( struct rewrite_info *info, const char *name ) { struct rewrite_builtin_map tmp; assert( info != NULL ); assert( name != NULL ); tmp.lb_name = ( char * )name; return ( struct rewrite_builtin_map * )ldap_avl_find( info->li_maps, ( caddr_t )&tmp, rewrite_builtin_map_cmp ); } /* * Parses a plugin map */ static int rewrite_parse_builtin_map( struct rewrite_info *info, const char *fname, int lineno, int argc, char **argv ) { struct rewrite_builtin_map *map; #define MAP_TYPE 1 #define MAP_NAME 2 assert( info != NULL ); assert( fname != NULL ); assert( argc > 2 ); assert( argv != NULL ); assert( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 ); map = calloc( sizeof( struct rewrite_builtin_map ), 1 ); if ( map == NULL ) { return REWRITE_ERR; } map->lb_name = strdup( argv[ MAP_NAME ] ); if ( map->lb_name == NULL ) { free( map ); return REWRITE_ERR; } /* * Built-in ldap map */ if (( map->lb_mapper = rewrite_mapper_find( argv[ MAP_TYPE ] ))) { map->lb_type = REWRITE_BUILTIN_MAP; #ifdef USE_REWRITE_LDAP_PVT_THREADS if ( ldap_pvt_thread_mutex_init( & map->lb_mutex ) ) { free( map->lb_name ); free( map ); return REWRITE_ERR; } #endif /* USE_REWRITE_LDAP_PVT_THREADS */ map->lb_private = map->lb_mapper->rm_config( fname, lineno, argc - 3, argv + 3 ); /* * Error */ } else { free( map ); Debug( LDAP_DEBUG_ANY, "[%s:%d] unknown map type\n", fname, lineno ); return -1; } return rewrite_builtin_map_insert( info, map ); } openldap-2.5.11+dfsg/libraries/librewrite/ldapmap.c0000644000175000017500000002340014172327167020744 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #include #define LDAP_DEPRECATED 1 #include "rewrite-int.h" #include "rewrite-map.h" typedef enum { MAP_LDAP_UNKNOWN, MAP_LDAP_EVERYTIME, MAP_LDAP_NOW, MAP_LDAP_LATER } bindwhen_t; /* * LDAP map data structure */ struct ldap_map_data { char *lm_url; LDAPURLDesc *lm_lud; int lm_version; char *lm_binddn; struct berval lm_cred; bindwhen_t lm_when; LDAP *lm_ld; int lm_wantdn; char *lm_attrs[ 2 ]; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_t lm_mutex; #endif /* USE_REWRITE_LDAP_PVT_THREADS */ }; static void map_ldap_free( struct ldap_map_data *data ) { assert( data != NULL ); if ( data->lm_url != NULL ) { free( data->lm_url ); } if ( data->lm_lud != NULL ) { ldap_free_urldesc( data->lm_lud ); } if ( data->lm_binddn != NULL ) { free( data->lm_binddn ); } if ( data->lm_cred.bv_val != NULL ) { memset( data->lm_cred.bv_val, 0, data->lm_cred.bv_len ); free( data->lm_cred.bv_val ); data->lm_cred.bv_val = NULL; data->lm_cred.bv_len = 0; } if ( data->lm_when != MAP_LDAP_EVERYTIME && data->lm_ld != NULL ) { ldap_unbind_ext( data->lm_ld, NULL, NULL ); } free( data ); } static void * map_ldap_parse( const char *fname, int lineno, int argc, char **argv ) { struct ldap_map_data *data; char *p, *uri; assert( fname != NULL ); assert( argv != NULL ); data = calloc( sizeof( struct ldap_map_data ), 1 ); if ( data == NULL ) { return NULL; } if ( argc < 1 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] ldap map needs URI\n", fname, lineno ); free( data ); return NULL; } uri = argv[ 0 ]; if ( strncasecmp( uri, "uri=", STRLENOF( "uri=" ) ) == 0 ) { uri += STRLENOF( "uri=" ); } data->lm_url = strdup( uri ); if ( data->lm_url == NULL ) { map_ldap_free( data ); return NULL; } if ( ldap_url_parse( uri, &data->lm_lud ) != REWRITE_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] illegal URI '%s'\n", fname, lineno, argv[ 0 ] ); map_ldap_free( data ); return NULL; } /* trim everything after [host][:port] */ p = strchr( data->lm_url, '/' ); assert( p[ 1 ] == '/' ); if ( ( p = strchr( p + 2, '/' ) ) != NULL ) { p[ 0 ] = '\0'; } if ( data->lm_lud->lud_attrs == NULL ) { data->lm_attrs[ 0 ] = LDAP_NO_ATTRS; data->lm_wantdn = 1; } else { if ( data->lm_lud->lud_attrs[ 1 ] != NULL ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] only one attribute allowed in URI\n", fname, lineno ); map_ldap_free( data ); return NULL; } if ( strcasecmp( data->lm_lud->lud_attrs[ 0 ], "dn" ) == 0 || strcasecmp( data->lm_lud->lud_attrs[ 0 ], "entryDN" ) == 0 ) { ldap_memfree( data->lm_lud->lud_attrs[ 0 ] ); ldap_memfree( data->lm_lud->lud_attrs ); data->lm_lud->lud_attrs = NULL; data->lm_attrs[ 0 ] = LDAP_NO_ATTRS; data->lm_wantdn = 1; } else { data->lm_attrs[ 0 ] = data->lm_lud->lud_attrs[ 0 ]; } } data->lm_attrs[ 1 ] = NULL; /* safe defaults */ data->lm_version = LDAP_VERSION3; for ( argc--, argv++; argc > 0; argc--, argv++ ) { if ( strncasecmp( argv[ 0 ], "binddn=", STRLENOF( "binddn=" ) ) == 0 ) { char *p = argv[ 0 ] + STRLENOF( "binddn=" ); int l; if ( p[ 0 ] == '\"' || p [ 0 ] == '\'' ) { l = strlen( p ) - 2; p++; if ( p[ l ] != p[ 0 ] ) { map_ldap_free( data ); return NULL; } } else { l = strlen( p ); } data->lm_binddn = strdup( p ); if ( data->lm_binddn == NULL ) { map_ldap_free( data ); return NULL; } if ( data->lm_binddn[ l ] == '\"' || data->lm_binddn[ l ] == '\'' ) { data->lm_binddn[ l ] = '\0'; } /* deprecated */ } else if ( strncasecmp( argv[ 0 ], "bindpw=", STRLENOF( "bindpw=" ) ) == 0 ) { ber_str2bv( argv[ 0 ] + STRLENOF( "bindpw=" ), 0, 1, &data->lm_cred ); if ( data->lm_cred.bv_val == NULL ) { map_ldap_free( data ); return NULL; } } else if ( strncasecmp( argv[ 0 ], "credentials=", STRLENOF( "credentials=" ) ) == 0 ) { ber_str2bv( argv[ 0 ] + STRLENOF( "credentials=" ), 0, 1, &data->lm_cred ); if ( data->lm_cred.bv_val == NULL ) { map_ldap_free( data ); return NULL; } } else if ( strncasecmp( argv[ 0 ], "bindwhen=", STRLENOF( "bindwhen=" ) ) == 0 ) { char *p = argv[ 0 ] + STRLENOF( "bindwhen=" ); if ( strcasecmp( p, "now" ) == 0 ) { int rc; data->lm_when = MAP_LDAP_NOW; /* * Init LDAP handler ... */ rc = ldap_initialize( &data->lm_ld, data->lm_url ); if ( rc != LDAP_SUCCESS ) { map_ldap_free( data ); return NULL; } ldap_set_option( data->lm_ld, LDAP_OPT_PROTOCOL_VERSION, (void *)&data->lm_version ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_init( &data->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ } else if ( strcasecmp( p, "later" ) == 0 ) { data->lm_when = MAP_LDAP_LATER; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_init( &data->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ } else if ( strcasecmp( p, "everytime" ) == 0 ) { data->lm_when = MAP_LDAP_EVERYTIME; } else { /* ignore ... */ } } else if ( strncasecmp( argv[ 0 ], "version=", STRLENOF( "version=" ) ) == 0 ) { if ( lutil_atoi( &data->lm_version, argv[ 0 ] + STRLENOF( "version=" ) ) ) { map_ldap_free( data ); return NULL; } switch ( data->lm_version ) { case LDAP_VERSION2: case LDAP_VERSION3: break; default: Debug( LDAP_DEBUG_ANY, "[%s:%d] unknown version %s\n", fname, lineno, p ); map_ldap_free( data ); return NULL; } } else { Debug( LDAP_DEBUG_ANY, "[%s:%d] unknown option %s (ignored)\n", fname, lineno, argv[0] ); } } if ( data->lm_when == MAP_LDAP_UNKNOWN ) { data->lm_when = MAP_LDAP_EVERYTIME; } return ( void * )data; } static int map_ldap_apply( void *private, const char *filter, struct berval *val ) { LDAP *ld; LDAPMessage *res = NULL, *entry; int rc; struct ldap_map_data *data = private; LDAPURLDesc *lud = data->lm_lud; int first_try = 1, set_version = 0; assert( private != NULL ); assert( filter != NULL ); assert( val != NULL ); val->bv_val = NULL; val->bv_len = 0; if ( data->lm_when == MAP_LDAP_EVERYTIME ) { rc = ldap_initialize( &ld, data->lm_url ); set_version = 1; } else { #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_lock( &data->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rc = LDAP_SUCCESS; if ( data->lm_when == MAP_LDAP_LATER && data->lm_ld == NULL ) { rc = ldap_initialize( &data->lm_ld, data->lm_url ); set_version = 1; } ld = data->lm_ld; } if ( rc != LDAP_SUCCESS ) { rc = REWRITE_ERR; goto rc_return; } do_bind:; if ( set_version ) { ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (void *)&data->lm_version ); set_version = 0; } if ( data->lm_binddn != NULL ) { rc = ldap_sasl_bind_s( ld, data->lm_binddn, LDAP_SASL_SIMPLE, &data->lm_cred, NULL, NULL, NULL ); if ( rc == LDAP_SERVER_DOWN && first_try ) { first_try = 0; if ( ldap_initialize( &ld, data->lm_url ) != LDAP_SUCCESS ) { rc = REWRITE_ERR; goto rc_return; } set_version = 1; goto do_bind; } else if ( rc != REWRITE_SUCCESS ) { rc = REWRITE_ERR; goto rc_return; } } rc = ldap_search_ext_s( ld, lud->lud_dn, lud->lud_scope, ( char * )filter, data->lm_attrs, 0, NULL, NULL, NULL, 1, &res ); if ( rc == LDAP_SERVER_DOWN && first_try ) { first_try = 0; if ( ldap_initialize( &ld, data->lm_url ) != LDAP_SUCCESS ) { rc = REWRITE_ERR; goto rc_return; } set_version = 1; goto do_bind; } else if ( rc != LDAP_SUCCESS ) { rc = REWRITE_ERR; goto rc_return; } if ( ldap_count_entries( ld, res ) != 1 ) { ldap_msgfree( res ); rc = REWRITE_ERR; goto rc_return; } entry = ldap_first_entry( ld, res ); assert( entry != NULL ); if ( data->lm_wantdn == 1 ) { /* * dn is newly allocated, so there's no need to strdup it */ val->bv_val = ldap_get_dn( ld, entry ); val->bv_len = strlen( val->bv_val ); } else { struct berval **values; values = ldap_get_values_len( ld, entry, data->lm_attrs[ 0 ] ); if ( values != NULL ) { if ( values[ 0 ] != NULL && values[ 0 ]->bv_val != NULL ) { #if 0 /* NOTE: in principle, multiple values * should not be acceptable according * to the current API; ignore by now */ if ( values[ 1 ] != NULL ) { /* error */ } #endif ber_dupbv( val, values[ 0 ] ); } ldap_value_free_len( values ); } } ldap_msgfree( res ); if ( val->bv_val == NULL ) { rc = REWRITE_ERR; goto rc_return; } rc_return:; if ( data->lm_when == MAP_LDAP_EVERYTIME ) { if ( ld != NULL ) { ldap_unbind_ext( ld, NULL, NULL ); } } else { data->lm_ld = ld; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_unlock( &data->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ } return rc; } static int map_ldap_destroy( void *private ) { struct ldap_map_data *data = private; assert( private != NULL ); map_ldap_free( data ); return 0; } const rewrite_mapper rewrite_ldap_mapper = { "ldap", map_ldap_parse, map_ldap_apply, map_ldap_destroy }; openldap-2.5.11+dfsg/libraries/librewrite/var.c0000644000175000017500000001164114172327167020122 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #include #include "rewrite-int.h" /* * Compares two vars */ static int rewrite_var_cmp( const void *c1, const void *c2 ) { const struct rewrite_var *v1, *v2; v1 = ( const struct rewrite_var * )c1; v2 = ( const struct rewrite_var * )c2; assert( v1 != NULL ); assert( v2 != NULL ); assert( v1->lv_name != NULL ); assert( v2->lv_name != NULL ); return strcasecmp( v1->lv_name, v2->lv_name ); } /* * Duplicate var ? */ static int rewrite_var_dup( void *c1, void *c2 ) { struct rewrite_var *v1, *v2; v1 = ( struct rewrite_var * )c1; v2 = ( struct rewrite_var * )c2; assert( v1 != NULL ); assert( v2 != NULL ); assert( v1->lv_name != NULL ); assert( v2->lv_name != NULL ); return ( strcasecmp( v1->lv_name, v2->lv_name ) == 0 ? -1 : 0 ); } /* * Frees a var */ static void rewrite_var_free( void *v_var ) { struct rewrite_var *var = v_var; assert( var != NULL ); assert( var->lv_name != NULL ); assert( var->lv_value.bv_val != NULL ); if ( var->lv_flags & REWRITE_VAR_COPY_NAME ) free( var->lv_name ); if ( var->lv_flags & REWRITE_VAR_COPY_VALUE ) free( var->lv_value.bv_val ); free( var ); } /* * Deletes a var tree */ int rewrite_var_delete( Avlnode *tree ) { ldap_avl_free( tree, rewrite_var_free ); return REWRITE_SUCCESS; } /* * Finds a var */ struct rewrite_var * rewrite_var_find( Avlnode *tree, const char *name ) { struct rewrite_var var; assert( name != NULL ); var.lv_name = ( char * )name; return ( struct rewrite_var * )ldap_avl_find( tree, ( caddr_t )&var, rewrite_var_cmp ); } int rewrite_var_replace( struct rewrite_var *var, const char *value, int flags ) { ber_len_t len; assert( value != NULL ); len = strlen( value ); if ( var->lv_flags & REWRITE_VAR_COPY_VALUE ) { if ( flags & REWRITE_VAR_COPY_VALUE ) { if ( len <= var->lv_value.bv_len ) { AC_MEMCPY(var->lv_value.bv_val, value, len + 1); } else { free( var->lv_value.bv_val ); var->lv_value.bv_val = strdup( value ); } } else { free( var->lv_value.bv_val ); var->lv_value.bv_val = (char *)value; var->lv_flags &= ~REWRITE_VAR_COPY_VALUE; } } else { if ( flags & REWRITE_VAR_COPY_VALUE ) { var->lv_value.bv_val = strdup( value ); var->lv_flags |= REWRITE_VAR_COPY_VALUE; } else { var->lv_value.bv_val = (char *)value; } } if ( var->lv_value.bv_val == NULL ) { return -1; } var->lv_value.bv_len = len; return 0; } /* * Inserts a newly created var */ struct rewrite_var * rewrite_var_insert_f( Avlnode **tree, const char *name, const char *value, int flags ) { struct rewrite_var *var; int rc = 0; assert( tree != NULL ); assert( name != NULL ); assert( value != NULL ); var = rewrite_var_find( *tree, name ); if ( var != NULL ) { if ( flags & REWRITE_VAR_UPDATE ) { (void)rewrite_var_replace( var, value, flags ); goto cleanup; } rc = -1; goto cleanup; } var = calloc( sizeof( struct rewrite_var ), 1 ); if ( var == NULL ) { return NULL; } memset( var, 0, sizeof( struct rewrite_var ) ); if ( flags & REWRITE_VAR_COPY_NAME ) { var->lv_name = strdup( name ); if ( var->lv_name == NULL ) { rc = -1; goto cleanup; } var->lv_flags |= REWRITE_VAR_COPY_NAME; } else { var->lv_name = (char *)name; } if ( flags & REWRITE_VAR_COPY_VALUE ) { var->lv_value.bv_val = strdup( value ); if ( var->lv_value.bv_val == NULL ) { rc = -1; goto cleanup; } var->lv_flags |= REWRITE_VAR_COPY_VALUE; } else { var->lv_value.bv_val = (char *)value; } var->lv_value.bv_len = strlen( value ); rc = ldap_avl_insert( tree, ( caddr_t )var, rewrite_var_cmp, rewrite_var_dup ); cleanup:; if ( rc != 0 && var ) { ldap_avl_delete( tree, ( caddr_t )var, rewrite_var_cmp ); rewrite_var_free( var ); var = NULL; } return var; } /* * Sets/inserts a var */ struct rewrite_var * rewrite_var_set_f( Avlnode **tree, const char *name, const char *value, int flags ) { struct rewrite_var *var; assert( tree != NULL ); assert( name != NULL ); assert( value != NULL ); var = rewrite_var_find( *tree, name ); if ( var == NULL ) { if ( flags & REWRITE_VAR_INSERT ) { return rewrite_var_insert_f( tree, name, value, flags ); } else { return NULL; } } else { assert( var->lv_value.bv_val != NULL ); (void)rewrite_var_replace( var, value, flags ); } return var; } openldap-2.5.11+dfsg/libraries/librewrite/rewrite-int.h0000644000175000017500000003307114172327167021611 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #ifndef REWRITE_INT_H #define REWRITE_INT_H /* * These are required by every file of the library, so they're included here */ #include #include #include #include #include #include #include #include #include #define LDAP_DEFINE_LDAP_DEBUG #include #include #include #include #define malloc(x) ber_memalloc(x) #define calloc(x,y) ber_memcalloc(x,y) #define realloc(x,y) ber_memrealloc(x,y) #define free(x) ber_memfree(x) #undef strdup #define strdup(x) ber_strdup(x) #ifndef NO_THREADS #define USE_REWRITE_LDAP_PVT_THREADS #include #endif /* * For details, see RATIONALE. */ #define REWRITE_MAX_MATCH 11 /* 0: overall string; 1-9: submatches */ #define REWRITE_MAX_PASSES 100 /* * Submatch escape char */ /* the '\' conflicts with slapd.conf parsing */ /* #define REWRITE_SUBMATCH_ESCAPE '\\' */ #define REWRITE_SUBMATCH_ESCAPE_ORIG '%' #define REWRITE_SUBMATCH_ESCAPE '$' #define IS_REWRITE_SUBMATCH_ESCAPE(c) \ ((c) == REWRITE_SUBMATCH_ESCAPE || (c) == REWRITE_SUBMATCH_ESCAPE_ORIG) /* * REGEX flags */ #define REWRITE_FLAG_HONORCASE 'C' #define REWRITE_FLAG_BASICREGEX 'R' /* * Action flags */ #define REWRITE_FLAG_EXECONCE ':' #define REWRITE_FLAG_STOP '@' #define REWRITE_FLAG_UNWILLING '#' #define REWRITE_FLAG_GOTO 'G' /* requires an arg */ #define REWRITE_FLAG_USER 'U' /* requires an arg */ #define REWRITE_FLAG_MAX_PASSES 'M' /* requires an arg */ #define REWRITE_FLAG_IGNORE_ERR 'I' /* * Map operators */ #define REWRITE_OPERATOR_SUBCONTEXT '>' #define REWRITE_OPERATOR_COMMAND '|' #define REWRITE_OPERATOR_VARIABLE_SET '&' #define REWRITE_OPERATOR_VARIABLE_GET '*' #define REWRITE_OPERATOR_PARAM_GET '$' /*********** * PRIVATE * ***********/ /* * Action */ struct rewrite_action { struct rewrite_action *la_next; #define REWRITE_ACTION_STOP 0x0001 #define REWRITE_ACTION_UNWILLING 0x0002 #define REWRITE_ACTION_GOTO 0x0003 #define REWRITE_ACTION_IGNORE_ERR 0x0004 #define REWRITE_ACTION_USER 0x0005 int la_type; void *la_args; }; /* * Map */ struct rewrite_map { /* * Legacy stuff */ #define REWRITE_MAP_XFILEMAP 0x0001 /* Rough implementation! */ #define REWRITE_MAP_XPWDMAP 0x0002 /* uid -> gecos */ #define REWRITE_MAP_XLDAPMAP 0x0003 /* Not implemented yet! */ /* * Maps with args */ #define REWRITE_MAP_SUBCONTEXT 0x0101 #define REWRITE_MAP_SET_OP_VAR 0x0102 #define REWRITE_MAP_SETW_OP_VAR 0x0103 #define REWRITE_MAP_GET_OP_VAR 0x0104 #define REWRITE_MAP_SET_SESN_VAR 0x0105 #define REWRITE_MAP_SETW_SESN_VAR 0x0106 #define REWRITE_MAP_GET_SESN_VAR 0x0107 #define REWRITE_MAP_GET_PARAM 0x0108 #define REWRITE_MAP_BUILTIN 0x0109 int lm_type; char *lm_name; void *lm_data; /* * Old maps store private data in _lm_args; * new maps store the substitution pattern in _lm_subst */ union { void *_lm_args; struct rewrite_subst *_lm_subst; } lm_union; #define lm_args lm_union._lm_args #define lm_subst lm_union._lm_subst #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_t lm_mutex; #endif /* USE_REWRITE_LDAP_PVT_THREADS */ }; /* * Builtin maps */ struct rewrite_builtin_map { #define REWRITE_BUILTIN_MAP 0x0200 int lb_type; char *lb_name; void *lb_private; const rewrite_mapper *lb_mapper; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_t lb_mutex; #endif /* USE_REWRITE_LDAP_PVT_THREADS */ }; /* * Submatch substitution */ struct rewrite_submatch { #define REWRITE_SUBMATCH_ASIS 0x0000 #define REWRITE_SUBMATCH_XMAP 0x0001 #define REWRITE_SUBMATCH_MAP_W_ARG 0x0002 int ls_type; struct rewrite_map *ls_map; int ls_submatch; /* * The first one represents the index of the submatch in case * the map has single submatch as argument; * the latter represents the map argument scheme in case * the map has substitution string argument form */ }; /* * Pattern substitution */ struct rewrite_subst { size_t lt_subs_len; struct berval *lt_subs; int lt_num_submatch; struct rewrite_submatch *lt_submatch; }; /* * Rule */ struct rewrite_rule { struct rewrite_rule *lr_next; struct rewrite_rule *lr_prev; char *lr_pattern; char *lr_subststring; char *lr_flagstring; regex_t lr_regex; /* * I was thinking about some kind of per-rule mutex, but there's * probably no need, because rules after compilation are only read; * however, I need to check whether regexec is reentrant ... */ struct rewrite_subst *lr_subst; #define REWRITE_REGEX_ICASE REG_ICASE #define REWRITE_REGEX_EXTENDED REG_EXTENDED int lr_flags; #define REWRITE_RECURSE 0x0001 #define REWRITE_EXEC_ONCE 0x0002 int lr_mode; int lr_max_passes; struct rewrite_action *lr_action; }; /* * Rewrite Context (set of rules) */ struct rewrite_context { char *lc_name; struct rewrite_context *lc_alias; struct rewrite_rule *lc_rule; }; /* * Session */ struct rewrite_session { void *ls_cookie; Avlnode *ls_vars; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_t ls_vars_mutex; ldap_pvt_thread_mutex_t ls_mutex; #endif /* USE_REWRITE_LDAP_PVT_THREADS */ int ls_count; }; /* * Variable */ struct rewrite_var { char *lv_name; int lv_flags; struct berval lv_value; }; /* * Operation */ struct rewrite_op { int lo_num_passes; int lo_depth; #if 0 /* FIXME: not used anywhere! (debug? then, why strdup?) */ char *lo_string; #endif char *lo_result; Avlnode *lo_vars; const void *lo_cookie; }; /********** * PUBLIC * **********/ /* * Rewrite info */ struct rewrite_info { Avlnode *li_context; Avlnode *li_maps; /* * No global mutex because maps are read only at * config time */ Avlnode *li_params; Avlnode *li_cookies; int li_num_cookies; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_t li_params_mutex; ldap_pvt_thread_rdwr_t li_cookies_mutex; #endif /* USE_REWRITE_LDAP_PVT_THREADS */ /* * Default to `off'; * use `rewriteEngine {on|off}' directive to alter */ int li_state; /* * Defaults to REWRITE_MAXPASSES; * use `rewriteMaxPasses numPasses' directive to alter */ #define REWRITE_MAXPASSES 100 int li_max_passes; int li_max_passes_per_rule; /* * Behavior in case a NULL or non-existent context is required */ int li_rewrite_mode; }; /*********** * PRIVATE * ***********/ LDAP_REWRITE_V (struct rewrite_context*) rewrite_int_curr_context; /* * Maps */ /* * Parses a map (also in legacy 'x' version) */ LDAP_REWRITE_F (struct rewrite_map *) rewrite_map_parse( struct rewrite_info *info, const char *s, const char **end ); LDAP_REWRITE_F (struct rewrite_map *) rewrite_xmap_parse( struct rewrite_info *info, const char *s, const char **end ); /* * Resolves key in val by means of map (also in legacy 'x' version) */ LDAP_REWRITE_F (int) rewrite_map_apply( struct rewrite_info *info, struct rewrite_op *op, struct rewrite_map *map, struct berval *key, struct berval *val ); LDAP_REWRITE_F (int) rewrite_xmap_apply( struct rewrite_info *info, struct rewrite_op *op, struct rewrite_map *map, struct berval *key, struct berval *val ); LDAP_REWRITE_F (int) rewrite_map_destroy( struct rewrite_map **map ); LDAP_REWRITE_F (int) rewrite_xmap_destroy( struct rewrite_map **map ); LDAP_REWRITE_F (void) rewrite_builtin_map_free( void *map ); /* * Submatch substitution */ /* * Compiles a substitution pattern */ LDAP_REWRITE_F (struct rewrite_subst *) rewrite_subst_compile( struct rewrite_info *info, const char *result ); /* * Substitutes a portion of rewritten string according to substitution * pattern using submatches */ LDAP_REWRITE_F (int) rewrite_subst_apply( struct rewrite_info *info, struct rewrite_op *op, struct rewrite_subst *subst, const char *string, const regmatch_t *match, struct berval *val ); LDAP_REWRITE_F (int) rewrite_subst_destroy( struct rewrite_subst **subst ); /* * Rules */ /* * Compiles the rule and appends it at the running context */ LDAP_REWRITE_F (int) rewrite_rule_compile( struct rewrite_info *info, struct rewrite_context *context, const char *pattern, const char *result, const char *flagstring ); /* * Rewrites string according to rule; may return: * REWRITE_REGEXEC_OK: fine; if *result != NULL rule matched * and rewrite succeeded. * REWRITE_REGEXEC_STOP: fine, rule matched; stop processing * following rules * REWRITE_REGEXEC_UNWILL: rule matched; force 'unwilling to perform' * REWRITE_REGEXEC_ERR: an error occurred */ LDAP_REWRITE_F (int) rewrite_rule_apply( struct rewrite_info *info, struct rewrite_op *op, struct rewrite_rule *rule, const char *string, char **result ); LDAP_REWRITE_F (int) rewrite_rule_destroy( struct rewrite_rule **rule ); /* * Sessions */ /* * Fetches a struct rewrite_session */ LDAP_REWRITE_F (struct rewrite_session *) rewrite_session_find( struct rewrite_info *info, const void *cookie ); /* * Defines and inits a variable with session scope */ LDAP_REWRITE_F (int) rewrite_session_var_set_f( struct rewrite_info *info, const void *cookie, const char *name, const char *value, int flags ); /* * Gets a var with session scope */ LDAP_REWRITE_F (int) rewrite_session_var_get( struct rewrite_info *info, const void *cookie, const char *name, struct berval *val ); /* * Deletes a session */ LDAP_REWRITE_F (int) rewrite_session_delete( struct rewrite_info *info, const void *cookie ); /* * Destroys the cookie tree */ LDAP_REWRITE_F (int) rewrite_session_destroy( struct rewrite_info *info ); /* * Vars */ /* * Finds a var */ LDAP_REWRITE_F (struct rewrite_var *) rewrite_var_find( Avlnode *tree, const char *name ); /* * Replaces the value of a variable */ LDAP_REWRITE_F (int) rewrite_var_replace( struct rewrite_var *var, const char *value, int flags ); /* * Inserts a newly created var */ LDAP_REWRITE_F (struct rewrite_var *) rewrite_var_insert_f( Avlnode **tree, const char *name, const char *value, int flags ); #define rewrite_var_insert(tree, name, value) \ rewrite_var_insert_f((tree), (name), (value), \ REWRITE_VAR_UPDATE|REWRITE_VAR_COPY_NAME|REWRITE_VAR_COPY_VALUE) /* * Sets/inserts a var */ LDAP_REWRITE_F (struct rewrite_var *) rewrite_var_set_f( Avlnode **tree, const char *name, const char *value, int flags ); #define rewrite_var_set(tree, name, value, insert) \ rewrite_var_set_f((tree), (name), (value), \ REWRITE_VAR_UPDATE|REWRITE_VAR_COPY_NAME|REWRITE_VAR_COPY_VALUE|((insert)? REWRITE_VAR_INSERT : 0)) /* * Deletes a var tree */ LDAP_REWRITE_F (int) rewrite_var_delete( Avlnode *tree ); /* * Contexts */ /* * Finds the context named rewriteContext in the context tree */ LDAP_REWRITE_F (struct rewrite_context *) rewrite_context_find( struct rewrite_info *info, const char *rewriteContext ); /* * Creates a new context called rewriteContext and stores in into the tree */ LDAP_REWRITE_F (struct rewrite_context *) rewrite_context_create( struct rewrite_info *info, const char *rewriteContext ); /* * Rewrites string according to context; may return: * OK: fine; if *result != NULL rule matched and rewrite succeeded. * STOP: fine, rule matched; stop processing following rules * UNWILL: rule matched; force 'unwilling to perform' */ LDAP_REWRITE_F (int) rewrite_context_apply( struct rewrite_info *info, struct rewrite_op *op, struct rewrite_context *context, const char *string, char **result ); LDAP_REWRITE_F (int) rewrite_context_destroy( struct rewrite_context **context ); LDAP_REWRITE_F (void) rewrite_context_free( void *tmp ); #endif /* REWRITE_INT_H */ openldap-2.5.11+dfsg/libraries/librewrite/Copyright0000644000175000017500000000200714172327167021055 0ustar ryanryan/****************************************************************************** * * Copyright (C) 2000 Pierangelo Masarati, * All rights reserved. * * Permission is granted to anyone to use this software for any purpose * on any computer system, and to alter it and redistribute it, subject * to the following restrictions: * * 1. The author is not responsible for the consequences of use of this * software, no matter how awful, even if they arise from flaws in it. * * 2. The origin of this software must not be misrepresented, either by * explicit claim or by omission. Since few users ever read sources, * credits should appear in the documentation. * * 3. Altered versions must be plainly marked as such, and must not be * misrepresented as being the original software. Since few users * ever read sources, credits should appear in the documentation. * * 4. This notice may not be removed or altered. * ******************************************************************************/ openldap-2.5.11+dfsg/libraries/librewrite/xmap.c0000644000175000017500000002430414172327167020277 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #include #include #ifdef HAVE_PWD_H #include #endif #define LDAP_DEPRECATED 1 #include "rewrite-int.h" #include "rewrite-map.h" /* * Global data */ #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_t xpasswd_mutex; static int xpasswd_mutex_init = 0; #endif /* USE_REWRITE_LDAP_PVT_THREADS */ /* * Map parsing * NOTE: these are old-fashion maps; new maps will be parsed on separate * config lines, and referred by name. */ struct rewrite_map * rewrite_xmap_parse( struct rewrite_info *info, const char *s, const char **currpos ) { struct rewrite_map *map; assert( info != NULL ); assert( s != NULL ); assert( currpos != NULL ); Debug( LDAP_DEBUG_ARGS, "rewrite_xmap_parse: %s\n", s ); *currpos = NULL; map = calloc( sizeof( struct rewrite_map ), 1 ); if ( map == NULL ) { Debug( LDAP_DEBUG_ANY, "rewrite_xmap_parse:" " calloc failed\n" ); return NULL; } /* * Experimental passwd map: * replaces the uid with the matching gecos from /etc/passwd file */ if ( strncasecmp(s, "xpasswd", 7 ) == 0 ) { map->lm_type = REWRITE_MAP_XPWDMAP; map->lm_name = strdup( "xpasswd" ); if ( map->lm_name == NULL ) { free( map ); return NULL; } assert( s[7] == '}' ); *currpos = s + 8; #ifdef USE_REWRITE_LDAP_PVT_THREADS if ( !xpasswd_mutex_init ) { if ( ldap_pvt_thread_mutex_init( &xpasswd_mutex ) ) { free( map ); return NULL; } } ++xpasswd_mutex_init; #endif /* USE_REWRITE_LDAP_PVT_THREADS */ /* Don't really care if fails */ return map; /* * Experimental file map: * looks up key in a `key value' ascii file */ } else if ( strncasecmp( s, "xfile", 5 ) == 0 ) { char *filename; const char *p; int l; int c = 5; map->lm_type = REWRITE_MAP_XFILEMAP; if ( s[ c ] != '(' ) { free( map ); return NULL; } /* Must start with '/' for security concerns */ c++; if ( s[ c ] != '/' ) { free( map ); return NULL; } for ( p = s + c; p[ 0 ] != '\0' && p[ 0 ] != ')'; p++ ); if ( p[ 0 ] != ')' ) { free( map ); return NULL; } l = p - s - c; filename = calloc( sizeof( char ), l + 1 ); if ( filename == NULL ) { free( map ); return NULL; } AC_MEMCPY( filename, s + c, l ); filename[ l ] = '\0'; map->lm_args = ( void * )fopen( filename, "r" ); free( filename ); if ( map->lm_args == NULL ) { free( map ); return NULL; } *currpos = p + 1; #ifdef USE_REWRITE_LDAP_PVT_THREADS if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) { fclose( ( FILE * )map->lm_args ); free( map ); return NULL; } #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return map; /* * Experimental ldap map: * looks up key on the fly (not implemented!) */ } else if ( strncasecmp(s, "xldap", 5 ) == 0 ) { char *p; char *url; int l, rc; int c = 5; LDAPURLDesc *lud; if ( s[ c ] != '(' ) { free( map ); return NULL; } c++; p = strchr( s, '}' ); if ( p == NULL ) { free( map ); return NULL; } p--; *currpos = p + 2; /* * Add two bytes for urlencoding of '%s' */ l = p - s - c; url = calloc( sizeof( char ), l + 3 ); if ( url == NULL ) { free( map ); return NULL; } AC_MEMCPY( url, s + c, l ); url[ l ] = '\0'; /* * Urlencodes the '%s' for ldap_url_parse */ p = strchr( url, '%' ); if ( p != NULL ) { AC_MEMCPY( p + 3, p + 1, strlen( p + 1 ) + 1 ); p[ 1 ] = '2'; p[ 2 ] = '5'; } rc = ldap_url_parse( url, &lud ); free( url ); if ( rc != LDAP_SUCCESS ) { free( map ); return NULL; } assert( lud != NULL ); map->lm_args = ( void * )lud; map->lm_type = REWRITE_MAP_XLDAPMAP; #ifdef USE_REWRITE_LDAP_PVT_THREADS if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) { ldap_free_urldesc( lud ); free( map ); return NULL; } #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return map; /* Unhandled map */ } free( map ); return NULL; } /* * Map key -> value resolution * NOTE: these are old-fashion maps; new maps will be parsed on separate * config lines, and referred by name. */ int rewrite_xmap_apply( struct rewrite_info *info, struct rewrite_op *op, struct rewrite_map *map, struct berval *key, struct berval *val ) { int rc = REWRITE_SUCCESS; assert( info != NULL ); assert( op != NULL ); assert( map != NULL ); assert( key != NULL ); assert( val != NULL ); val->bv_val = NULL; val->bv_len = 0; switch ( map->lm_type ) { #ifdef HAVE_GETPWNAM case REWRITE_MAP_XPWDMAP: { struct passwd *pwd; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_lock( &xpasswd_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ pwd = getpwnam( key->bv_val ); if ( pwd == NULL ) { #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_unlock( &xpasswd_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rc = LDAP_NO_SUCH_OBJECT; break; } #ifdef HAVE_STRUCT_PASSWD_PW_GECOS if ( pwd->pw_gecos != NULL && pwd->pw_gecos[0] != '\0' ) { int l = strlen( pwd->pw_gecos ); val->bv_val = strdup( pwd->pw_gecos ); val->bv_len = l; } else #endif /* HAVE_STRUCT_PASSWD_PW_GECOS */ { val->bv_val = strdup( key->bv_val ); val->bv_len = key->bv_len; } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_unlock( &xpasswd_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ if ( val->bv_val == NULL ) { rc = REWRITE_ERR; } break; } #endif /* HAVE_GETPWNAM*/ case REWRITE_MAP_XFILEMAP: { char buf[1024]; if ( map->lm_args == NULL ) { rc = REWRITE_ERR; break; } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_lock( &map->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rewind( ( FILE * )map->lm_args ); while ( fgets( buf, sizeof( buf ), ( FILE * )map->lm_args ) ) { char *p; int blen; blen = strlen( buf ); if ( buf[ blen - 1 ] == '\n' ) { buf[ blen - 1 ] = '\0'; } p = strtok( buf, " " ); if ( p == NULL ) { #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rc = REWRITE_ERR; goto rc_return; } if ( strcasecmp( p, key->bv_val ) == 0 && ( p = strtok( NULL, "" ) ) ) { val->bv_val = strdup( p ); if ( val->bv_val == NULL ) { #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rc = REWRITE_ERR; goto rc_return; } val->bv_len = strlen( p ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ goto rc_return; } } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rc = REWRITE_ERR; break; } case REWRITE_MAP_XLDAPMAP: { LDAP *ld; char filter[1024]; LDAPMessage *res = NULL, *entry; LDAPURLDesc *lud = ( LDAPURLDesc * )map->lm_args; int attrsonly = 0; char **values; assert( lud != NULL ); /* * No mutex because there is no write on the map data */ ld = ldap_init( lud->lud_host, lud->lud_port ); if ( ld == NULL ) { rc = REWRITE_ERR; goto rc_return; } snprintf( filter, sizeof( filter ), lud->lud_filter, key->bv_val ); if ( strcasecmp( lud->lud_attrs[ 0 ], "dn" ) == 0 ) { attrsonly = 1; } rc = ldap_search_s( ld, lud->lud_dn, lud->lud_scope, filter, lud->lud_attrs, attrsonly, &res ); if ( rc != LDAP_SUCCESS ) { ldap_unbind( ld ); rc = REWRITE_ERR; goto rc_return; } if ( ldap_count_entries( ld, res ) != 1 ) { ldap_unbind( ld ); rc = REWRITE_ERR; goto rc_return; } entry = ldap_first_entry( ld, res ); if ( entry == NULL ) { ldap_msgfree( res ); ldap_unbind( ld ); rc = REWRITE_ERR; goto rc_return; } if ( attrsonly == 1 ) { val->bv_val = ldap_get_dn( ld, entry ); } else { values = ldap_get_values( ld, entry, lud->lud_attrs[0] ); if ( values != NULL ) { val->bv_val = strdup( values[ 0 ] ); ldap_value_free( values ); } } ldap_msgfree( res ); ldap_unbind( ld ); if ( val->bv_val == NULL ) { rc = REWRITE_ERR; goto rc_return; } val->bv_len = strlen( val->bv_val ); rc = REWRITE_SUCCESS; } break; } rc_return:; return rc; } int rewrite_xmap_destroy( struct rewrite_map **pmap ) { struct rewrite_map *map; assert( pmap != NULL ); assert( *pmap != NULL ); map = *pmap; switch ( map->lm_type ) { case REWRITE_MAP_XPWDMAP: #ifdef USE_REWRITE_LDAP_PVT_THREADS --xpasswd_mutex_init; if ( !xpasswd_mutex_init ) { ldap_pvt_thread_mutex_destroy( &xpasswd_mutex ); } #endif /* USE_REWRITE_LDAP_PVT_THREADS */ break; case REWRITE_MAP_XFILEMAP: #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_lock( &map->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ if ( map->lm_args ) { fclose( ( FILE * )map->lm_args ); map->lm_args = NULL; } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); ldap_pvt_thread_mutex_destroy( &map->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ break; case REWRITE_MAP_XLDAPMAP: #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_lock( &map->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ if ( map->lm_args ) { ldap_free_urldesc( ( LDAPURLDesc * )map->lm_args ); map->lm_args = NULL; } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); ldap_pvt_thread_mutex_destroy( &map->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ break; default: break; } free( map->lm_name ); free( map ); *pmap = NULL; return 0; } openldap-2.5.11+dfsg/libraries/librewrite/rewrite.c0000644000175000017500000000737314172327167021022 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #include #include #include #include #include #include #include #include #include #include #include #include #include int ldap_debug; int ldap_syslog; int ldap_syslog_level; static void apply( FILE *fin, const char *rewriteContext, const char *arg ) { struct rewrite_info *info; char *string, *sep, *result = NULL; int rc; void *cookie = &info; info = rewrite_info_init( REWRITE_MODE_ERR ); if ( rewrite_read( fin, info ) != 0 ) { exit( EXIT_FAILURE ); } rewrite_param_set( info, "prog", "rewrite" ); rewrite_session_init( info, cookie ); string = (char *)arg; for ( sep = strchr( rewriteContext, ',' ); rewriteContext != NULL; rewriteContext = sep, sep ? sep = strchr( rewriteContext, ',' ) : NULL ) { char *errmsg = ""; if ( sep != NULL ) { sep[ 0 ] = '\0'; sep++; } /* rc = rewrite( info, rewriteContext, string, &result ); */ rc = rewrite_session( info, rewriteContext, string, cookie, &result ); switch ( rc ) { case REWRITE_REGEXEC_OK: errmsg = "ok"; break; case REWRITE_REGEXEC_ERR: errmsg = "error"; break; case REWRITE_REGEXEC_STOP: errmsg = "stop"; break; case REWRITE_REGEXEC_UNWILLING: errmsg = "unwilling to perform"; break; default: if (rc >= REWRITE_REGEXEC_USER) { errmsg = "user-defined"; } else { errmsg = "unknown"; } break; } fprintf( stdout, "%s -> %s [%d:%s]\n", string, ( result ? result : "(null)" ), rc, errmsg ); if ( result == NULL ) { break; } if ( string != arg && string != result ) { free( string ); } string = result; } if ( result && result != arg ) { free( result ); } rewrite_session_delete( info, cookie ); rewrite_info_delete( &info ); } int main( int argc, char *argv[] ) { FILE *fin = NULL; char *rewriteContext = REWRITE_DEFAULT_CONTEXT; int debug = 0; while ( 1 ) { int opt = getopt( argc, argv, "d:f:hr:" ); if ( opt == EOF ) { break; } switch ( opt ) { case 'd': if ( lutil_atoi( &debug, optarg ) != 0 ) { fprintf( stderr, "illegal log level '%s'\n", optarg ); exit( EXIT_FAILURE ); } break; case 'f': fin = fopen( optarg, "r" ); if ( fin == NULL ) { fprintf( stderr, "unable to open file '%s'\n", optarg ); exit( EXIT_FAILURE ); } break; case 'h': fprintf( stderr, "usage: rewrite [options] string\n" "\n" "\t\t-f file\t\tconfiguration file\n" "\t\t-r rule[s]\tlist of comma-separated rules\n" "\n" "\tsyntax:\n" "\t\trewriteEngine\t{on|off}\n" "\t\trewriteContext\tcontextName [alias aliasedContextName]\n" "\t\trewriteRule\tpattern subst [flags]\n" "\n" ); exit( EXIT_SUCCESS ); case 'r': rewriteContext = optarg; break; } } if ( debug != 0 ) { ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &debug); ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &debug); } if ( optind >= argc ) { return -1; } apply( ( fin ? fin : stdin ), rewriteContext, argv[ optind ] ); if ( fin ) { fclose( fin ); } return 0; } openldap-2.5.11+dfsg/libraries/liblutil/0000755000175000017500000000000014172327167016633 5ustar ryanryanopenldap-2.5.11+dfsg/libraries/liblutil/sockpair.c0000644000175000017500000000371414172327167020617 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include /* Return a pair of socket descriptors that are connected to each other. * The returned descriptors are suitable for use with select(). The two * descriptors may or may not be identical; the function may return * the same descriptor number in both slots. It is guaranteed that * data written on sds[1] will be readable on sds[0]. The returned * descriptors may be datagram oriented, so data should be written * in reasonably small pieces and read all at once. On Unix systems * this function is best implemented using a single pipe() call. */ int lutil_pair( ber_socket_t sds[2] ) { #ifdef USE_PIPE return pipe( sds ); #else struct sockaddr_in si; int rc; ber_socklen_t len = sizeof(si); ber_socket_t sd; sd = socket( AF_INET, SOCK_DGRAM, 0 ); if ( sd == AC_SOCKET_INVALID ) { return sd; } (void) memset( (void*) &si, '\0', len ); si.sin_family = AF_INET; si.sin_port = 0; si.sin_addr.s_addr = htonl( INADDR_LOOPBACK ); rc = bind( sd, (struct sockaddr *)&si, len ); if ( rc == AC_SOCKET_ERROR ) { tcp_close(sd); return rc; } rc = getsockname( sd, (struct sockaddr *)&si, &len ); if ( rc == AC_SOCKET_ERROR ) { tcp_close(sd); return rc; } rc = connect( sd, (struct sockaddr *)&si, len ); if ( rc == AC_SOCKET_ERROR ) { tcp_close(sd); return rc; } sds[0] = sd; #if !HAVE_WINSOCK sds[1] = dup( sds[0] ); #else sds[1] = sds[0]; #endif return 0; #endif } openldap-2.5.11+dfsg/libraries/liblutil/signal.c0000644000175000017500000000167314172327167020263 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #ifdef HAVE_SIGACTION #include #include lutil_sig_t lutil_sigaction(int sig, lutil_sig_t func) { struct sigaction action, oaction; memset( &action, '\0', sizeof(action) ); action.sa_handler = func; sigemptyset( &action.sa_mask ); #ifdef SA_RESTART action.sa_flags |= SA_RESTART; #endif if( sigaction( sig, &action, &oaction ) != 0 ) { return NULL; } return oaction.sa_handler; } #endif openldap-2.5.11+dfsg/libraries/liblutil/getpeereid.c0000644000175000017500000001172414172327167021121 0ustar ryanryan/* getpeereid.c */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 /* Needed for glibc struct ucred */ #endif #include "portable.h" #ifndef HAVE_GETPEEREID #include #include #include #include #ifdef HAVE_GETPEERUCRED #include #endif #ifdef LDAP_PF_LOCAL_SENDMSG #include #ifdef HAVE_SYS_UIO_H #include #endif #include #endif #ifdef HAVE_SYS_UCRED_H #ifdef HAVE_GRP_H #include /* for NGROUPS on Tru64 5.1 */ #endif #include #endif #include int lutil_getpeereid( int s, uid_t *euid, gid_t *egid #ifdef LDAP_PF_LOCAL_SENDMSG , struct berval *peerbv #endif ) { #ifdef LDAP_PF_LOCAL #if defined( HAVE_GETPEERUCRED ) ucred_t *uc = NULL; if( getpeerucred( s, &uc ) == 0 ) { *euid = ucred_geteuid( uc ); *egid = ucred_getegid( uc ); ucred_free( uc ); return 0; } #elif defined( SO_PEERCRED ) struct ucred peercred; ber_socklen_t peercredlen = sizeof peercred; if(( getsockopt( s, SOL_SOCKET, SO_PEERCRED, (void *)&peercred, &peercredlen ) == 0 ) && ( peercredlen == sizeof peercred )) { *euid = peercred.uid; *egid = peercred.gid; return 0; } #elif defined( LOCAL_PEERCRED ) struct xucred peercred; ber_socklen_t peercredlen = sizeof peercred; if(( getsockopt( s, LOCAL_PEERCRED, 1, (void *)&peercred, &peercredlen ) == 0 ) && ( peercred.cr_version == XUCRED_VERSION )) { *euid = peercred.cr_uid; *egid = peercred.cr_gid; return 0; } #elif defined( LDAP_PF_LOCAL_SENDMSG ) && defined( MSG_WAITALL ) int err, fd; struct iovec iov; struct msghdr msg = {0}; # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL # ifndef CMSG_SPACE # define CMSG_SPACE(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len)) # endif # ifndef CMSG_LEN # define CMSG_LEN(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len)) # endif struct { struct cmsghdr cm; int fd; } control_st; struct cmsghdr *cmsg; # endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ struct stat st; struct sockaddr_un lname, rname; ber_socklen_t llen, rlen; rlen = sizeof(rname); llen = sizeof(lname); memset( &lname, 0, sizeof( lname )); getsockname(s, (struct sockaddr *)&lname, &llen); iov.iov_base = peerbv->bv_val; iov.iov_len = peerbv->bv_len; msg.msg_iov = &iov; msg.msg_iovlen = 1; peerbv->bv_len = 0; # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg.msg_control = &control_st; msg.msg_controllen = sizeof( struct cmsghdr ) + sizeof( int ); /* no padding! */ cmsg = CMSG_FIRSTHDR( &msg ); # else msg.msg_accrights = (char *)&fd; msg.msg_accrightslen = sizeof(fd); # endif /* * AIX returns a bogus file descriptor if recvmsg() is * called with MSG_PEEK (is this a bug?). Hence we need * to receive the Abandon PDU. */ err = recvmsg( s, &msg, MSG_WAITALL ); if( err >= 0 && # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL cmsg->cmsg_len == CMSG_LEN( sizeof(int) ) && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS # else msg.msg_accrightslen == sizeof(int) # endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL*/ ) { int mode = S_IFIFO|S_ISUID|S_IRWXU; /* We must receive a valid descriptor, it must be a pipe, * it must only be accessible by its owner, and it must * have the name of our socket written on it. */ peerbv->bv_len = err; # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL fd = (*(int *)CMSG_DATA( cmsg )); # endif err = fstat( fd, &st ); if ( err == 0 ) rlen = read(fd, &rname, rlen); close(fd); if( err == 0 && st.st_mode == mode && llen == rlen && !memcmp(&lname, &rname, llen)) { *euid = st.st_uid; *egid = st.st_gid; return 0; } } #elif defined(SOCKCREDSIZE) struct msghdr msg; ber_socklen_t crmsgsize; void *crmsg; struct cmsghdr *cmp; struct sockcred *sc; memset(&msg, 0, sizeof msg); crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS)); if (crmsgsize == 0) goto sc_err; crmsg = malloc(crmsgsize); if (crmsg == NULL) goto sc_err; memset(crmsg, 0, crmsgsize); msg.msg_control = crmsg; msg.msg_controllen = crmsgsize; if (recvmsg(s, &msg, 0) < 0) { free(crmsg); goto sc_err; } if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) { free(crmsg); goto sc_err; } cmp = CMSG_FIRSTHDR(&msg); if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) { printf("nocreds\n"); goto sc_err; } sc = (struct sockcred *)(void *)CMSG_DATA(cmp); *euid = sc->sc_euid; *egid = sc->sc_egid; free(crmsg); return 0; sc_err: #endif #endif /* LDAP_PF_LOCAL */ return -1; } #endif /* HAVE_GETPEEREID */ openldap-2.5.11+dfsg/libraries/liblutil/meter.c0000644000175000017500000001757214172327167020127 0ustar ryanryan/* meter.c - lutil_meter meters */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright (c) 2009 by Emily Backes, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This work was initially developed by Emily Backes for inclusion * in OpenLDAP software. */ #include "portable.h" #include "lutil_meter.h" #include #include int lutil_time_string ( char *dest, int duration, int max_terms) { static const int time_div[] = {31556952, 604800, 86400, 3600, 60, 1, 0}; const int * time_divp = time_div; static const char * time_name_ch = "ywdhms"; const char * time_name_chp = time_name_ch; int term_count = 0; char *buf = dest; int time_quot; assert ( max_terms >= 2 ); /* room for "none" message */ if ( duration < 0 ) { *dest = '\0'; return 1; } if ( duration == 0 ) { strcpy( dest, "none" ); return 0; } while ( term_count < max_terms && duration > 0 ) { if (duration > *time_divp) { time_quot = duration / *time_divp; duration %= *time_divp; if (time_quot > 99) { return 1; } else { *(buf++) = time_quot / 10 + '0'; *(buf++) = time_quot % 10 + '0'; *(buf++) = *time_name_chp; ++term_count; } } if ( *(++time_divp) == 0) duration = 0; ++time_name_chp; } *buf = '\0'; return 0; } int lutil_get_now (double *now) { #ifdef HAVE_GETTIMEOFDAY struct timeval tv; assert( now ); gettimeofday( &tv, NULL ); *now = ((double) tv.tv_sec) + (((double) tv.tv_usec) / 1000000.0); return 0; #else time_t tm; assert( now ); time( &tm ); *now = (double) tm; return 0; #endif } int lutil_meter_open ( lutil_meter_t *meter, const lutil_meter_display_t *display, const lutil_meter_estimator_t *estimator, size_t goal_value) { int rc; assert( meter != NULL ); assert( display != NULL ); assert( estimator != NULL ); if (goal_value < 1) return -1; memset( (void*) meter, 0, sizeof( lutil_meter_t )); meter->display = display; meter->estimator = estimator; lutil_get_now( &meter->start_time ); meter->last_update = meter->start_time; meter->goal_value = goal_value; meter->last_position = 0; rc = meter->display->display_open( &meter->display_data ); if( rc != 0 ) return rc; rc = meter->estimator->estimator_open( &meter->estimator_data ); if( rc != 0 ) { meter->display->display_close( &meter->display_data ); return rc; } return 0; } int lutil_meter_update ( lutil_meter_t *meter, size_t position, int force) { static const double display_rate = 0.5; double frac, cycle_length, speed, now; time_t remaining_time, elapsed; int rc; assert( meter != NULL ); lutil_get_now( &now ); if ( !force && now - meter->last_update < display_rate ) return 0; frac = ((double)position) / ((double) meter->goal_value); elapsed = now - meter->start_time; if (frac <= 0.0 || elapsed == 0) return 0; if (frac >= 1.0) { rc = meter->display->display_update( &meter->display_data, 1.0, 0, (time_t) elapsed, ((double)position) / elapsed); } else { rc = meter->estimator->estimator_update( &meter->estimator_data, meter->start_time, frac, &remaining_time ); if ( rc == 0 ) { cycle_length = now - meter->last_update; speed = cycle_length > 0.0 ? ((double)(position - meter->last_position)) / cycle_length : 0.0; rc = meter->display->display_update( &meter->display_data, frac, remaining_time, (time_t) elapsed, speed); if ( rc == 0 ) { meter->last_update = now; meter->last_position = position; } } } return rc; } int lutil_meter_close (lutil_meter_t *meter) { meter->estimator->estimator_close( &meter->estimator_data ); meter->display->display_close( &meter->display_data ); return 0; } /* Default display and estimator */ typedef struct { int buffer_length; char * buffer; int need_eol; int phase; FILE *output; } text_display_state_t; static int text_open (void ** display_datap) { static const int default_buffer_length = 81; text_display_state_t *data; assert( display_datap != NULL ); data = calloc( 1, sizeof( text_display_state_t )); assert( data != NULL ); data->buffer_length = default_buffer_length; data->buffer = calloc( 1, default_buffer_length ); assert( data->buffer != NULL ); data->output = stderr; *display_datap = data; return 0; } static int text_update ( void **display_datap, double frac, time_t remaining_time, time_t elapsed, double byte_rate) { text_display_state_t *data; char *buf, *buf_end; assert( display_datap != NULL ); assert( *display_datap != NULL ); data = (text_display_state_t*) *display_datap; if ( data->output == NULL ) return 1; buf = data->buffer; buf_end = buf + data->buffer_length - 1; /* |#################### 100.00% eta 1d19h elapsed 23w 7d23h15m12s spd nnnn.n M/s */ { /* spinner */ static const int phase_mod = 8; static const char phase_char[] = "_.-*\"*-."; *buf++ = phase_char[data->phase % phase_mod]; data->phase++; } { /* bar */ static const int bar_length = 20; static const double bar_lengthd = 20.0; static const char fill_char = '#'; static const char blank_char = ' '; char *bar_end = buf + bar_length; char *bar_pos = frac < 0.0 ? buf : frac < 1.0 ? buf + (int) (bar_lengthd * frac) : bar_end; assert( (buf_end - buf) > bar_length ); while ( buf < bar_end ) { *buf = buf < bar_pos ? fill_char : blank_char; ++buf; } } { /* percent */ (void) snprintf( buf, buf_end-buf, "%7.2f%%", 100.0*frac ); buf += 8; } { /* eta and elapsed */ char time_buffer[19]; int rc; rc = lutil_time_string( time_buffer, remaining_time, 2); if (rc == 0) snprintf( buf, buf_end-buf, " eta %6s", time_buffer ); buf += 5+6; rc = lutil_time_string( time_buffer, elapsed, 5); if (rc == 0) snprintf( buf, buf_end-buf, " elapsed %15s", time_buffer ); buf += 9+15; } { /* speed */ static const char prefixes[] = " kMGTPEZY"; const char *prefix_chp = prefixes; while (*prefix_chp && byte_rate >= 1024.0) { byte_rate /= 1024.0; ++prefix_chp; } if ( byte_rate >= 1024.0 ) { snprintf( buf, buf_end-buf, " fast!" ); buf += 6; } else { snprintf( buf, buf_end-buf, " spd %5.1f %c/s", byte_rate, *prefix_chp); buf += 5+6+4; } } (void) fprintf( data->output, "\r%-79s", data->buffer ); data->need_eol = 1; return 0; } static int text_close (void ** display_datap) { text_display_state_t *data; if (display_datap) { if (*display_datap) { data = (text_display_state_t*) *display_datap; if (data->output && data->need_eol) fputs ("\n", data->output); if (data->buffer) free( data->buffer ); free( data ); } *display_datap = NULL; } return 0; } static int null_open_close (void **datap) { assert( datap ); *datap = NULL; return 0; } static int linear_update ( void **estimator_datap, double start, double frac, time_t *remaining) { double now; double elapsed; assert( estimator_datap != NULL ); assert( *estimator_datap == NULL ); assert( start > 0.0 ); assert( frac >= 0.0 ); assert( frac <= 1.0 ); assert( remaining != NULL ); lutil_get_now( &now ); elapsed = now-start; assert( elapsed >= 0.0 ); if ( frac == 0.0 ) { return 1; } else if ( frac >= 1.0 ) { *remaining = 0; return 0; } else { *remaining = (time_t) (elapsed/frac-elapsed+0.5); return 0; } } const lutil_meter_display_t lutil_meter_text_display = { text_open, text_update, text_close }; const lutil_meter_estimator_t lutil_meter_linear_estimator = { null_open_close, linear_update, null_open_close }; openldap-2.5.11+dfsg/libraries/liblutil/Makefile.in0000644000175000017500000000263314172327167020704 0ustar ryanryan# Makefile for -llutil # $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . LIBRARY = liblutil.a LDAP_INCDIR= ../../include LDAP_LIBDIR= ../../libraries NT_SRCS = ntservice.c NT_OBJS = ntservice.o slapdmsg.res UNIX_SRCS = detach.c UNIX_OBJS = detach.o XLIBS = $(LIBRARY) $(LDAP_LIBLBER_LA) SRCS = base64.c entropy.c sasl.c signal.c hash.c passfile.c \ md5.c passwd.c sha1.c getpass.c lockf.c utils.c uuid.c sockpair.c \ meter.c \ @LIBSRCS@ $(@PLAT@_SRCS) OBJS = base64.o entropy.o sasl.o signal.o hash.o passfile.o \ md5.o passwd.o sha1.o getpass.o lockf.o utils.o uuid.o sockpair.o \ meter.o \ @LIBOBJS@ $(@PLAT@_OBJS) # These rules are for a Mingw32 build, specifically. # It's ok for them to be here because the clean rule is harmless, and # slapdmsg.res won't get built unless it's declared in OBJS. RC = @RC@ slapdmsg.bin: FORCE @if [ ! -f $@ ]; then cp $(srcdir)/$@ .; fi slapdmsg.res: slapdmsg.rc slapdmsg.bin $(RC) $< -O coff -o $@ clean-local: $(RM) *.res openldap-2.5.11+dfsg/libraries/liblutil/hash.c0000644000175000017500000000502214172327167017721 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * Portions Copyright 2000-2003 Kurt D. Zeilenga. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* This implements the Fowler / Noll / Vo (FNV-1) hash algorithm. * A summary of the algorithm can be found at: * http://www.isthe.com/chongo/tech/comp/fnv/index.html */ #include "portable.h" #include /* offset and prime for 32-bit FNV-1 */ #define HASH_OFFSET 0x811c9dc5U #define HASH_PRIME 16777619 /* * Initialize context */ void lutil_HASHInit( lutil_HASH_CTX *ctx ) { ctx->hash = HASH_OFFSET; } /* * Update hash */ void lutil_HASHUpdate( lutil_HASH_CTX *ctx, const unsigned char *buf, ber_len_t len ) { const unsigned char *p, *e; ber_uint_t h; p = buf; e = &buf[len]; h = ctx->hash; while( p < e ) { h *= HASH_PRIME; h ^= *p++; } ctx->hash = h; } /* * Save hash */ void lutil_HASHFinal( unsigned char *digest, lutil_HASH_CTX *ctx ) { ber_uint_t h = ctx->hash; digest[0] = h & 0xffU; digest[1] = (h>>8) & 0xffU; digest[2] = (h>>16) & 0xffU; digest[3] = (h>>24) & 0xffU; } #ifdef HAVE_LONG_LONG /* 64 bit Fowler/Noll/Vo-O FNV-1a hash code */ #define HASH64_OFFSET 0xcbf29ce484222325ULL /* * Initialize context */ void lutil_HASH64Init( lutil_HASH_CTX *ctx ) { ctx->hash64 = HASH64_OFFSET; } /* * Update hash */ void lutil_HASH64Update( lutil_HASH_CTX *ctx, const unsigned char *buf, ber_len_t len ) { const unsigned char *p, *e; unsigned long long h; p = buf; e = &buf[len]; h = ctx->hash64; while( p < e ) { /* xor the bottom with the current octet */ h ^= *p++; /* multiply by the 64 bit FNV magic prime mod 2^64 */ h += (h << 1) + (h << 4) + (h << 5) + (h << 7) + (h << 8) + (h << 40); } ctx->hash64 = h; } /* * Save hash */ void lutil_HASH64Final( unsigned char *digest, lutil_HASH_CTX *ctx ) { unsigned long long h = ctx->hash64; digest[0] = h & 0xffU; digest[1] = (h>>8) & 0xffU; digest[2] = (h>>16) & 0xffU; digest[3] = (h>>24) & 0xffU; digest[4] = (h>>32) & 0xffU; digest[5] = (h>>40) & 0xffU; digest[6] = (h>>48) & 0xffU; digest[7] = (h>>56) & 0xffU; } #endif /* HAVE_LONG_LONG */ openldap-2.5.11+dfsg/libraries/liblutil/uuid.c0000644000175000017500000002360614172327167017754 0ustar ryanryan/* uuid.c -- Universally Unique Identifier routines */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2022 The OpenLDAP Foundation. * Portions Copyright 2000-2003 Kurt D. Zeilenga. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright 2000, John E. Schimmel, All rights reserved. * This software is not subject to any license of Mirapoint, Inc. * * This is free software; you can redistribute and use it * under the same terms as OpenLDAP itself. */ /* This work was initially developed by John E. Schimmel and adapted * for inclusion in OpenLDAP Software by Kurt D. Zeilenga. */ /* * Sorry this file is so scary, but it needs to run on a wide range of * platforms. The only exported routine is lutil_uuidstr() which is all * that LDAP cares about. It generates a new uuid and returns it in * in string form. */ #include "portable.h" #include #include #include #include #include /* get memcmp() */ #ifdef HAVE_UUID_TO_STR # include #elif defined( HAVE_UUID_GENERATE ) # include #elif defined( _WIN32 ) # include #else # include # include # ifdef HAVE_SYS_SYSCTL_H # include # include # include # endif #endif #include /* not needed for Windows */ #if !defined(HAVE_UUID_TO_STR) && !defined(HAVE_UUID_GENERATE) && !defined(_WIN32) static unsigned char * lutil_eaddr( void ) { static unsigned char zero[6]; static unsigned char eaddr[6]; #ifdef HAVE_SYS_SYSCTL_H size_t needed; int mib[6]; char *buf, *next, *lim; struct if_msghdr *ifm; struct sockaddr_dl *sdl; if (memcmp(eaddr, zero, sizeof(eaddr))) { return eaddr; } mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[3] = 0; mib[3] = 0; mib[4] = NET_RT_IFLIST; mib[5] = 0; if (sysctl(mib, sizeof(mib), NULL, &needed, NULL, 0) < 0) { return NULL; } buf = malloc(needed); if( buf == NULL ) return NULL; if (sysctl(mib, sizeof(mib), buf, &needed, NULL, 0) < 0) { free(buf); return NULL; } lim = buf + needed; for (next = buf; next < lim; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *)next; sdl = (struct sockaddr_dl *)(ifm + 1); if ( sdl->sdl_family != AF_LINK || sdl->sdl_alen == 6 ) { AC_MEMCPY(eaddr, (unsigned char *)sdl->sdl_data + sdl->sdl_nlen, sizeof(eaddr)); free(buf); return eaddr; } } free(buf); return NULL; #elif defined( SIOCGIFADDR ) && defined( AFLINK ) char buf[sizeof(struct ifreq) * 32]; struct ifconf ifc; struct ifreq *ifr; struct sockaddr *sa; struct sockaddr_dl *sdl; unsigned char *p; int s, i; if (memcmp(eaddr, zero, sizeof(eaddr))) { return eaddr; } s = socket( AF_INET, SOCK_DGRAM, 0 ); if ( s < 0 ) { return NULL; } ifc.ifc_len = sizeof( buf ); ifc.ifc_buf = buf; memset( buf, 0, sizeof( buf ) ); i = ioctl( s, SIOCGIFCONF, (char *)&ifc ); close( s ); if( i < 0 ) { return NULL; } for ( i = 0; i < ifc.ifc_len; ) { ifr = (struct ifreq *)&ifc.ifc_buf[i]; sa = &ifr->ifr_addr; if ( sa->sa_len > sizeof( ifr->ifr_addr ) ) { i += sizeof( ifr->ifr_name ) + sa->sa_len; } else { i += sizeof( *ifr ); } if ( sa->sa_family != AF_LINK ) { continue; } sdl = (struct sockaddr_dl *)sa; if ( sdl->sdl_alen == 6 ) { AC_MEMCPY(eaddr, (unsigned char *)sdl->sdl_data + sdl->sdl_nlen, sizeof(eaddr)); return eaddr; } } return NULL; #else if (memcmp(eaddr, zero, sizeof(eaddr)) == 0) { /* XXX - who knows? */ lutil_entropy( eaddr, sizeof(eaddr) ); eaddr[0] |= 0x01; /* turn it into a multicast address */ } return eaddr; #endif } #if (ULONG_MAX >> 31 >> 31) > 1 || defined HAVE_LONG_LONG #if (ULONG_MAX >> 31 >> 31) > 1 typedef unsigned long UI64; /* 100 usec intervals from 10/10/1582 to 1/1/1970 */ # define UUID_TPLUS 0x01B21DD2138140ul #else typedef unsigned long long UI64; # define UUID_TPLUS 0x01B21DD2138140ull #endif #define high32(i) ((unsigned long) ((i) >> 32)) #define low32(i) ((unsigned long) (i) & 0xFFFFFFFFul) #define set_add64(res, i) ((res) += (i)) #define set_add64l(res, i) ((res) += (i)) #define mul64ll(i1, i2) ((UI64) (i1) * (i2)) #else /* ! (ULONG_MAX >= 64 bits || HAVE_LONG_LONG) */ typedef struct { unsigned long high, low; } UI64; static const UI64 UUID_TPLUS = { 0x01B21Dul, 0xD2138140ul }; #define high32(i) ((i).high) #define low32(i) ((i).low) /* res += ui64 */ #define set_add64(res, ui64) \ { \ res.high += ui64.high; \ res.low = (res.low + ui64.low) & 0xFFFFFFFFul; \ if (res.low < ui64.low) res.high++; \ } /* res += ul32 */ #define set_add64l(res, ul32) \ { \ res.low = (res.low + ul32) & 0xFFFFFFFFul; \ if (res.low < ul32) res.high++; \ } /* compute i1 * i2 */ static UI64 mul64ll(unsigned long i1, unsigned long i2) { const unsigned int high1 = (i1 >> 16), low1 = (i1 & 0xffff); const unsigned int high2 = (i2 >> 16), low2 = (i2 & 0xffff); UI64 res; unsigned long tmp; res.high = (unsigned long) high1 * high2; res.low = (unsigned long) low1 * low2; tmp = (unsigned long) low1 * high2; res.high += (tmp >> 16); tmp = (tmp << 16) & 0xFFFFFFFFul; res.low = (res.low + tmp) & 0xFFFFFFFFul; if (res.low < tmp) res.high++; tmp = (unsigned long) low2 * high1; res.high += (tmp >> 16); tmp = (tmp << 16) & 0xFFFFFFFFul; res.low = (res.low + tmp) & 0xFFFFFFFFul; if (res.low < tmp) res.high++; return res; } #endif /* ULONG_MAX >= 64 bits || HAVE_LONG_LONG */ #endif /* !HAVE_UUID_TO_STR && !HAVE_UUID_GENERATE && !_WIN32 */ /* ** All we really care about is an ISO UUID string. The format of a UUID is: ** field octet note ** time_low 0-3 low field of the timestamp ** time_mid 4-5 middle field of timestamp ** time_hi_and_version 6-7 high field of timestamp and ** version number ** clock_seq_hi_and_resv 8 high field of clock sequence ** and variant ** clock_seq_low 9 low field of clock sequence ** node 10-15 spacially unique identifier ** ** We use DCE version one, and the DCE variant. Our unique identifier is ** the first ethernet address on the system. */ size_t lutil_uuidstr( char *buf, size_t len ) { #ifdef HAVE_UUID_TO_STR uuid_t uu = {0}; unsigned rc; char *s; size_t l; uuid_create( &uu, &rc ); if ( rc != uuid_s_ok ) { return 0; } uuid_to_str( &uu, &s, &rc ); if ( rc != uuid_s_ok ) { return 0; } l = strlen( s ); if ( l >= len ) { free( s ); return 0; } strncpy( buf, s, len ); free( s ); return l; #elif defined( HAVE_UUID_GENERATE ) uuid_t uu; uuid_generate( uu ); uuid_unparse_lower( uu, buf ); return strlen( buf ); #elif defined( _WIN32 ) UUID uuid; unsigned char *uuidstr; size_t uuidlen; if( UuidCreate( &uuid ) != RPC_S_OK ) { return 0; } if( UuidToString( &uuid, &uuidstr ) != RPC_S_OK ) { return 0; } uuidlen = strlen( uuidstr ); if( uuidlen >= len ) { return 0; } strncpy( buf, uuidstr, len ); RpcStringFree( &uuidstr ); return uuidlen; #else struct timeval tv; UI64 tl; unsigned char *nl; unsigned short t2, t3, s1; unsigned long t1, tl_high; unsigned int rc; /* * Theoretically we should delay if seq wraps within 100usec but for now * systems are not fast enough to worry about it. */ static int inited = 0; static unsigned short seq; if (!inited) { lutil_entropy( (unsigned char *) &seq, sizeof(seq) ); inited++; } #ifdef HAVE_GETTIMEOFDAY gettimeofday( &tv, 0 ); #else time( &tv.tv_sec ); tv.tv_usec = 0; #endif tl = mul64ll(tv.tv_sec, 10000000UL); set_add64l(tl, tv.tv_usec * 10UL); set_add64(tl, UUID_TPLUS); nl = lutil_eaddr(); t1 = low32(tl); /* time_low */ tl_high = high32(tl); t2 = tl_high & 0xffff; /* time_mid */ t3 = ((tl_high >> 16) & 0x0fff) | 0x1000; /* time_hi_and_version */ s1 = ( ++seq & 0x1fff ) | 0x8000; /* clock_seq_and_reserved */ rc = snprintf( buf, len, "%08lx-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", t1, (unsigned) t2, (unsigned) t3, (unsigned) s1, (unsigned) nl[0], (unsigned) nl[1], (unsigned) nl[2], (unsigned) nl[3], (unsigned) nl[4], (unsigned) nl[5] ); return rc < len ? rc : 0; #endif } int lutil_uuidstr_from_normalized( char *uuid, size_t uuidlen, char *buf, size_t buflen ) { unsigned char nibble; int i, d = 0; assert( uuid != NULL ); assert( buf != NULL ); if ( uuidlen != 16 ) return -1; if ( buflen < 36 ) return -1; for ( i = 0; i < 16; i++ ) { if ( i == 4 || i == 6 || i == 8 || i == 10 ) { buf[(i<<1)+d] = '-'; d += 1; } nibble = (uuid[i] >> 4) & 0xF; if ( nibble < 10 ) { buf[(i<<1)+d] = nibble + '0'; } else { buf[(i<<1)+d] = nibble - 10 + 'a'; } nibble = (uuid[i]) & 0xF; if ( nibble < 10 ) { buf[(i<<1)+d+1] = nibble + '0'; } else { buf[(i<<1)+d+1] = nibble - 10 + 'a'; } } if ( buflen > 36 ) buf[36] = '\0'; return 36; } #ifdef TEST int main(int argc, char **argv) { char buf1[8], buf2[64]; #ifndef HAVE_UUID_TO_STR unsigned char *p = lutil_eaddr(); if( p ) { printf( "Ethernet Address: %02x:%02x:%02x:%02x:%02x:%02x\n", (unsigned) p[0], (unsigned) p[1], (unsigned) p[2], (unsigned) p[3], (unsigned) p[4], (unsigned) p[5]); } #endif if ( lutil_uuidstr( buf1, sizeof( buf1 ) ) ) { printf( "UUID: %s\n", buf1 ); } else { fprintf( stderr, "too short: %ld\n", (long) sizeof( buf1 ) ); } if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) { printf( "UUID: %s\n", buf2 ); } else { fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) ); } if ( lutil_uuidstr( buf2, sizeof( buf2 ) ) ) { printf( "UUID: %s\n", buf2 ); } else { fprintf( stderr, "too short: %ld\n", (long) sizeof( buf2 ) ); } return 0; } #endif openldap-2.5.11+dfsg/libraries/liblutil/entropy.c0000644000175000017500000000760714172327167020511 0ustar ryanryan/* entropy.c -- routines for providing pseudo-random data */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1999-2022 The OpenLDAP Foundation. * Portions Copyright 1999-2003 Kurt D. Zeilenga. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* This work was initially developed by Kurt D. Zeilenga for * inclusion in OpenLDAP Software based, in part, on publicly * available works (as noted below). */ #include "portable.h" #include #include #include #ifdef HAVE_PROCESS_H #include #endif #include #include #include /* * lutil_entropy() provides nbytes of entropy in buf. * Quality offered is suitable for one-time uses, such as "once" keys. * Values may not be suitable for multi-time uses. * * Note: Callers are encouraged to provide additional bytes of * of entropy in the buf argument. This information is used in * fallback mode to improve the quality of bytes returned. * * This routinue should be extended to support additional sources * of entropy. */ int lutil_entropy( unsigned char *buf, ber_len_t nbytes ) { if( nbytes == 0 ) return 0; #ifdef URANDOM_DEVICE #define URANDOM_NREADS 4 /* Linux and *BSD offer a urandom device */ { int rc, fd, n=0; fd = open( URANDOM_DEVICE, O_RDONLY ); if( fd < 0 ) return -1; do { rc = read( fd, buf, nbytes ); if( rc <= 0 ) break; buf+=rc; nbytes-=rc; if( ++n >= URANDOM_NREADS ) break; } while( nbytes > 0 ); close(fd); return nbytes > 0 ? -1 : 0; } #elif defined(PROV_RSA_FULL) { /* Not used since _WIN32_WINNT not set... */ HCRYPTPROV hProv = 0; /* Get handle to user default provider */ if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) { return -1; } /* Generate random initialization vector */ if(!CryptGenRandom(hProv, (DWORD) nbytes, (BYTE *) buf)) { return -1; } /* Release provider handle */ if(hProv != 0) CryptReleaseContext(hProv, 0); return 0; } #else { /* based upon Phil Karn's "practical randomness" idea * but implementation 100% OpenLDAP. So don't blame Phil. * * Worse case is that this is a MD5 hash of a counter, if * MD5 is a strong cryptographic hash, this should be fairly * resistant to attack */ /* * the caller may need to provide external synchronization OR * provide entropy (in buf) to ensure quality results as * access to this counter may not be atomic. */ static int counter = 0; ber_len_t n; struct rdata_s { int counter; unsigned char *buf; struct rdata_s *stack; pid_t pid; #ifdef HAVE_GETTIMEOFDAY struct timeval tv; #else time_t time; #endif unsigned long junk; /* purposely not initialized */ } rdata; /* make sure rdata differs for each process */ rdata.pid = getpid(); /* make sure rdata differs for each program */ rdata.buf = buf; rdata.stack = &rdata; for( n = 0; n < nbytes; n += 16 ) { struct lutil_MD5Context ctx; unsigned char digest[16]; /* poor resolution */ #ifdef HAVE_GETTIMEOFDAY (void) gettimeofday( &rdata.tv, NULL ); #else (void) time( &rdata.time ); #endif /* make sure rdata differs */ rdata.counter = ++counter; rdata.pid++; rdata.junk++; lutil_MD5Init( &ctx ); lutil_MD5Update( &ctx, (unsigned char *) &rdata, sizeof( rdata ) ); /* allow caller to provided additional entropy */ lutil_MD5Update( &ctx, buf, nbytes ); lutil_MD5Final( digest, &ctx ); AC_MEMCPY( &buf[n], digest, nbytes - n >= 16 ? 16 : nbytes - n ); } return 0; } #endif return -1; } openldap-2.5.11+dfsg/libraries/liblutil/getopt.c0000644000175000017500000000537114172327167020307 0ustar ryanryan/* getopt.c -- replacement getopt(3) routines */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * Portions Copyright 1998-2003 Kurt D. Zeilenga. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* This work is based upon the public-domain getopt(3) routines * developed by AT&T. Modified by Kurt D. Zeilenga for inclusion * into OpenLDAP Software. Significant contributors include: * Howard Chu */ #include "portable.h" #ifndef HAVE_GETOPT #include #include #include #ifdef HAVE_IO_H #include #endif #include "lutil.h" #ifndef STDERR_FILENO #define STDERR_FILENO 2 #endif int opterr = 1; int optind = 1; int optopt; char * optarg; #ifdef HAVE_EBCDIC extern int _trans_argv; #endif static void ERR (char * const argv[], const char * s, char c) { #ifdef DF_TRACE_DEBUG printf("DF_TRACE_DEBUG: static void ERR () in getopt.c\n"); #endif if (opterr) { char *ptr, outbuf[4096]; ptr = lutil_strncopy(outbuf, argv[0], sizeof(outbuf) - 2); ptr = lutil_strncopy(ptr, s, sizeof(outbuf)-2 -(ptr-outbuf)); *ptr++ = c; *ptr++ = '\n'; #ifdef HAVE_EBCDIC __atoe_l(outbuf, ptr - outbuf); #endif (void) write(STDERR_FILENO,outbuf,ptr - outbuf); } } int getopt (int argc, char * const argv [], const char * opts) { static int sp = 1, error = (int) '?'; static char sw = '-', eos = '\0', arg = ':'; register char c, * cp; #ifdef DF_TRACE_DEBUG printf("DF_TRACE_DEBUG: int getopt () in getopt.c\n"); #endif #ifdef HAVE_EBCDIC if (_trans_argv) { int i; for (i=0; i= argc || argv[optind][0] != sw || argv[optind][1] == eos) return EOF; else if (strcmp(argv[optind],"--") == 0) { optind++; return EOF; } } c = argv[optind][sp]; optopt = (int) c; if (c == arg || (cp = strchr(opts,c)) == NULL) { ERR(argv,_(": illegal option--"),c); if (argv[optind][++sp] == eos) { optind++; sp = 1; } return error; } else if (*++cp == arg) { if (argv[optind][sp + 1] != eos) optarg = &argv[optind++][sp + 1]; else if (++optind >= argc) { ERR(argv,_(": option requires an argument--"),c); sp = 1; return error; } else optarg = argv[optind++]; sp = 1; } else { if (argv[optind][++sp] == eos) { sp = 1; optind++; } optarg = NULL; } return (int) c; } #endif /* HAVE_GETOPT */ openldap-2.5.11+dfsg/libraries/liblutil/slapdmsg.bin0000644000175000017500000000016414172327167021140 0ustar ryanryan@@DOpenLDAP service started. debuglevel=%1, conffile=%2, urls=%3 OpenLDAP service stopped. openldap-2.5.11+dfsg/libraries/liblutil/getpass.c0000644000175000017500000000614214172327167020450 0ustar ryanryan/* getpass.c -- get password from user */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * Portions Copyright 1998-2003 Kurt D. Zeilenga. * Portions Copyright 2009 Howard Chu. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1992, 1993 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ /* This work was originally developed by the University of Michigan * and distributed as part of U-MICH LDAP. It was adapted for use in * -llutil by Kurt D. Zeilenga and subsequently rewritten by Howard Chu. */ #include "portable.h" #include #include #include #include #include #include #include #include #ifndef HAVE_GETPASSPHRASE #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_CONIO_H #include #endif #include #include #include "ldap_defaults.h" #define PBUF 512 #ifdef HAVE_WINSOCK #define TTY "con:" #else #define TTY "/dev/tty" #endif char * lutil_getpass( const char *prompt ) { static char pbuf[PBUF]; FILE *fi; int c; unsigned i; #if defined(HAVE_TERMIOS_H) || defined(HAVE_SGTTY_H) TERMIO_TYPE ttyb; TERMFLAG_TYPE flags; RETSIGTYPE (*sig)( int sig ); #endif if( prompt == NULL ) prompt = _("Password: "); #ifdef DEBUG if (debug & D_TRACE) printf("->getpass(%s)\n", prompt); #endif #if defined(HAVE_TERMIOS_H) || defined(HAVE_SGTTY_H) if ((fi = fopen(TTY, "r")) == NULL) fi = stdin; else setbuf(fi, (char *)NULL); if (fi != stdin) { if (GETATTR(fileno(fi), &ttyb) < 0) perror("GETATTR"); sig = SIGNAL (SIGINT, SIG_IGN); flags = GETFLAGS( ttyb ); SETFLAGS( ttyb, flags & ~ECHO ); if (SETATTR(fileno(fi), &ttyb) < 0) perror("SETATTR"); } #else fi = stdin; #endif fprintf(stderr, "%s", prompt); fflush(stderr); i = 0; while ( (c = getc(fi)) != EOF && c != '\n' && c != '\r' ) if ( i < (sizeof(pbuf)-1) ) pbuf[i++] = c; #if defined(HAVE_TERMIOS_H) || defined(HAVE_SGTTY_H) /* tidy up */ if (fi != stdin) { fprintf(stderr, "\n"); fflush(stderr); SETFLAGS( ttyb, flags ); if (SETATTR(fileno(fi), &ttyb) < 0) perror("SETATTR"); (void) SIGNAL (SIGINT, sig); (void) fclose(fi); } #endif if ( c == EOF ) return( NULL ); pbuf[i] = '\0'; return (pbuf); } #endif /* !NEED_GETPASSPHRASE */ openldap-2.5.11+dfsg/libraries/liblutil/passwd.c0000644000175000017500000005055014172327167020305 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* * int lutil_passwd( * const struct berval *passwd, * const struct berval *cred, * const char **schemes ) * * Returns true if user supplied credentials (cred) matches * the stored password (passwd). * * Due to the use of the crypt(3) function * this routine is NOT thread-safe. */ #include "portable.h" #include #include #include #include #include #ifdef SLAPD_CRYPT # include # if defined( HAVE_GETPWNAM ) && defined( HAVE_STRUCT_PASSWD_PW_PASSWD ) # ifdef HAVE_SHADOW_H # include # endif # ifdef HAVE_PWD_H # include # endif # ifdef HAVE_AIX_SECURITY # include # endif # endif #endif #include #include "ldap_pvt.h" #include "lber_pvt.h" #include "lutil_md5.h" #include "lutil_sha1.h" #include "lutil.h" static const unsigned char crypt64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890./"; #ifdef SLAPD_CRYPT static char *salt_format = NULL; static lutil_cryptfunc lutil_crypt; lutil_cryptfunc *lutil_cryptptr = lutil_crypt; #endif /* KLUDGE: * chk_fn is NULL iff name is {CLEARTEXT} * otherwise, things will break */ struct pw_scheme { struct berval name; LUTIL_PASSWD_CHK_FUNC *chk_fn; LUTIL_PASSWD_HASH_FUNC *hash_fn; }; struct pw_slist { struct pw_slist *next; struct pw_scheme s; }; /* password check routines */ #define SALT_SIZE 4 static LUTIL_PASSWD_CHK_FUNC chk_md5; static LUTIL_PASSWD_CHK_FUNC chk_smd5; static LUTIL_PASSWD_HASH_FUNC hash_smd5; static LUTIL_PASSWD_HASH_FUNC hash_md5; #ifdef LUTIL_SHA1_BYTES static LUTIL_PASSWD_CHK_FUNC chk_ssha1; static LUTIL_PASSWD_CHK_FUNC chk_sha1; static LUTIL_PASSWD_HASH_FUNC hash_sha1; static LUTIL_PASSWD_HASH_FUNC hash_ssha1; #endif #ifdef SLAPD_CRYPT static LUTIL_PASSWD_CHK_FUNC chk_crypt; static LUTIL_PASSWD_HASH_FUNC hash_crypt; #if defined( HAVE_GETPWNAM ) && defined( HAVE_STRUCT_PASSWD_PW_PASSWD ) static LUTIL_PASSWD_CHK_FUNC chk_unix; #endif #endif /* password hash routines */ #ifdef SLAPD_CLEARTEXT static LUTIL_PASSWD_HASH_FUNC hash_clear; #endif static struct pw_slist *pw_schemes; static int pw_inited; static const struct pw_scheme pw_schemes_default[] = { #ifdef LUTIL_SHA1_BYTES { BER_BVC("{SSHA}"), chk_ssha1, hash_ssha1 }, { BER_BVC("{SHA}"), chk_sha1, hash_sha1 }, #endif { BER_BVC("{SMD5}"), chk_smd5, hash_smd5 }, { BER_BVC("{MD5}"), chk_md5, hash_md5 }, #ifdef SLAPD_CRYPT { BER_BVC("{CRYPT}"), chk_crypt, hash_crypt }, # if defined( HAVE_GETPWNAM ) && defined( HAVE_STRUCT_PASSWD_PW_PASSWD ) { BER_BVC("{UNIX}"), chk_unix, NULL }, # endif #endif #ifdef SLAPD_CLEARTEXT /* pseudo scheme */ { BER_BVC("{CLEARTEXT}"), NULL, hash_clear }, #endif { BER_BVNULL, NULL, NULL } }; int lutil_passwd_add( struct berval *scheme, LUTIL_PASSWD_CHK_FUNC *chk, LUTIL_PASSWD_HASH_FUNC *hash ) { struct pw_slist *ptr; if (!pw_inited) lutil_passwd_init(); ptr = ber_memalloc( sizeof( struct pw_slist )); if (!ptr) return -1; ptr->next = pw_schemes; ptr->s.name = *scheme; ptr->s.chk_fn = chk; ptr->s.hash_fn = hash; pw_schemes = ptr; return 0; } void lutil_passwd_init() { struct pw_scheme *s; pw_inited = 1; for( s=(struct pw_scheme *)pw_schemes_default; s->name.bv_val; s++) { if ( lutil_passwd_add( &s->name, s->chk_fn, s->hash_fn ) ) break; } } void lutil_passwd_destroy() { struct pw_slist *ptr, *next; for( ptr=pw_schemes; ptr; ptr=next ) { next = ptr->next; ber_memfree( ptr ); } } static const struct pw_scheme *get_scheme( const char* scheme ) { struct pw_slist *pws; struct berval bv; if (!pw_inited) lutil_passwd_init(); bv.bv_val = strchr( scheme, '}' ); if ( !bv.bv_val ) return NULL; bv.bv_len = bv.bv_val - scheme + 1; bv.bv_val = (char *) scheme; for( pws=pw_schemes; pws; pws=pws->next ) { if ( ber_bvstrcasecmp(&bv, &pws->s.name ) == 0 ) { return &(pws->s); } } return NULL; } int lutil_passwd_scheme( const char* scheme ) { if( scheme == NULL ) { return 0; } return get_scheme(scheme) != NULL; } static int is_allowed_scheme( const char* scheme, const char** schemes ) { int i; if( schemes == NULL ) return 1; for( i=0; schemes[i] != NULL; i++ ) { if( strcasecmp( scheme, schemes[i] ) == 0 ) { return 1; } } return 0; } static struct berval *passwd_scheme( const struct pw_scheme *scheme, const struct berval * passwd, struct berval *bv, const char** allowed ) { if( !is_allowed_scheme( scheme->name.bv_val, allowed ) ) { return NULL; } if( passwd->bv_len >= scheme->name.bv_len ) { if( strncasecmp( passwd->bv_val, scheme->name.bv_val, scheme->name.bv_len ) == 0 ) { bv->bv_val = &passwd->bv_val[scheme->name.bv_len]; bv->bv_len = passwd->bv_len - scheme->name.bv_len; return bv; } } return NULL; } /* * Return 0 if creds are good. */ int lutil_passwd( const struct berval *passwd, /* stored passwd */ const struct berval *cred, /* user cred */ const char **schemes, const char **text ) { struct pw_slist *pws; if ( text ) *text = NULL; if (cred == NULL || cred->bv_len == 0 || passwd == NULL || passwd->bv_len == 0 ) { return -1; } if (!pw_inited) lutil_passwd_init(); for( pws=pw_schemes; pws; pws=pws->next ) { if( pws->s.chk_fn ) { struct berval x; struct berval *p = passwd_scheme( &(pws->s), passwd, &x, schemes ); if( p != NULL ) { return (pws->s.chk_fn)( &(pws->s.name), p, cred, text ); } } } #ifdef SLAPD_CLEARTEXT /* Do we think there is a scheme specifier here that we * didn't recognize? Assume a scheme name is at least 1 character. */ if (( passwd->bv_val[0] == '{' ) && ( ber_bvchr( passwd, '}' ) > passwd->bv_val+1 )) { return 1; } if( is_allowed_scheme("{CLEARTEXT}", schemes ) ) { return ( passwd->bv_len == cred->bv_len ) ? memcmp( passwd->bv_val, cred->bv_val, passwd->bv_len ) : 1; } #endif return 1; } int lutil_passwd_generate( struct berval *pw, ber_len_t len ) { if( len < 1 ) return -1; pw->bv_len = len; pw->bv_val = ber_memalloc( len + 1 ); if( pw->bv_val == NULL ) { return -1; } if( lutil_entropy( (unsigned char *) pw->bv_val, pw->bv_len) < 0 ) { return -1; } for( len = 0; len < pw->bv_len; len++ ) { pw->bv_val[len] = crypt64[ pw->bv_val[len] % (sizeof(crypt64)-1) ]; } pw->bv_val[len] = '\0'; return 0; } int lutil_passwd_hash( const struct berval * passwd, const char * method, struct berval *hash, const char **text ) { const struct pw_scheme *sc = get_scheme( method ); hash->bv_val = NULL; hash->bv_len = 0; if( sc == NULL ) { if( text ) *text = "scheme not recognized"; return -1; } if( ! sc->hash_fn ) { if( text ) *text = "scheme provided no hash function"; return -1; } if( text ) *text = NULL; return (sc->hash_fn)( &sc->name, passwd, hash, text ); } /* pw_string is only called when SLAPD_CRYPT is defined */ #if defined(SLAPD_CRYPT) static int pw_string( const struct berval *sc, struct berval *passwd ) { struct berval pw; pw.bv_len = sc->bv_len + passwd->bv_len; pw.bv_val = ber_memalloc( pw.bv_len + 1 ); if( pw.bv_val == NULL ) { return LUTIL_PASSWD_ERR; } AC_MEMCPY( pw.bv_val, sc->bv_val, sc->bv_len ); AC_MEMCPY( &pw.bv_val[sc->bv_len], passwd->bv_val, passwd->bv_len ); pw.bv_val[pw.bv_len] = '\0'; *passwd = pw; return LUTIL_PASSWD_OK; } #endif /* SLAPD_CRYPT */ int lutil_passwd_string64( const struct berval *sc, const struct berval *hash, struct berval *b64, const struct berval *salt ) { int rc; struct berval string; size_t b64len; if( salt ) { /* need to base64 combined string */ string.bv_len = hash->bv_len + salt->bv_len; string.bv_val = ber_memalloc( string.bv_len + 1 ); if( string.bv_val == NULL ) { return LUTIL_PASSWD_ERR; } AC_MEMCPY( string.bv_val, hash->bv_val, hash->bv_len ); AC_MEMCPY( &string.bv_val[hash->bv_len], salt->bv_val, salt->bv_len ); string.bv_val[string.bv_len] = '\0'; } else { string = *hash; } b64len = LUTIL_BASE64_ENCODE_LEN( string.bv_len ) + 1; b64->bv_len = b64len + sc->bv_len; b64->bv_val = ber_memalloc( b64->bv_len + 1 ); if( b64->bv_val == NULL ) { if( salt ) ber_memfree( string.bv_val ); return LUTIL_PASSWD_ERR; } AC_MEMCPY(b64->bv_val, sc->bv_val, sc->bv_len); rc = lutil_b64_ntop( (unsigned char *) string.bv_val, string.bv_len, &b64->bv_val[sc->bv_len], b64len ); if( salt ) ber_memfree( string.bv_val ); if( rc < 0 ) { return LUTIL_PASSWD_ERR; } /* recompute length */ b64->bv_len = sc->bv_len + rc; assert( strlen(b64->bv_val) == b64->bv_len ); return LUTIL_PASSWD_OK; } /* PASSWORD CHECK ROUTINES */ #ifdef LUTIL_SHA1_BYTES static int chk_ssha1( const struct berval *sc, const struct berval * passwd, const struct berval * cred, const char **text ) { lutil_SHA1_CTX SHA1context; unsigned char SHA1digest[LUTIL_SHA1_BYTES]; int rc; unsigned char *orig_pass = NULL; size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); /* safety check -- must have some salt */ if (decode_len <= sizeof(SHA1digest)) { return LUTIL_PASSWD_ERR; } /* decode base64 password */ orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); if( orig_pass == NULL ) return LUTIL_PASSWD_ERR; rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); /* safety check -- must have some salt */ if (rc <= (int)(sizeof(SHA1digest))) { ber_memfree(orig_pass); return LUTIL_PASSWD_ERR; } /* hash credentials with salt */ lutil_SHA1Init(&SHA1context); lutil_SHA1Update(&SHA1context, (const unsigned char *) cred->bv_val, cred->bv_len); lutil_SHA1Update(&SHA1context, (const unsigned char *) &orig_pass[sizeof(SHA1digest)], rc - sizeof(SHA1digest)); lutil_SHA1Final(SHA1digest, &SHA1context); /* compare */ rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest)); ber_memfree(orig_pass); return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; } static int chk_sha1( const struct berval *sc, const struct berval * passwd, const struct berval * cred, const char **text ) { lutil_SHA1_CTX SHA1context; unsigned char SHA1digest[LUTIL_SHA1_BYTES]; int rc; unsigned char *orig_pass = NULL; size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); /* safety check */ if (decode_len < sizeof(SHA1digest)) { return LUTIL_PASSWD_ERR; } /* base64 un-encode password */ orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); if( orig_pass == NULL ) return LUTIL_PASSWD_ERR; rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); if( rc != sizeof(SHA1digest) ) { ber_memfree(orig_pass); return LUTIL_PASSWD_ERR; } /* hash credentials with salt */ lutil_SHA1Init(&SHA1context); lutil_SHA1Update(&SHA1context, (const unsigned char *) cred->bv_val, cred->bv_len); lutil_SHA1Final(SHA1digest, &SHA1context); /* compare */ rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest)); ber_memfree(orig_pass); return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; } #endif static int chk_smd5( const struct berval *sc, const struct berval * passwd, const struct berval * cred, const char **text ) { lutil_MD5_CTX MD5context; unsigned char MD5digest[LUTIL_MD5_BYTES]; int rc; unsigned char *orig_pass = NULL; size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); /* safety check */ if (decode_len <= sizeof(MD5digest)) { return LUTIL_PASSWD_ERR; } /* base64 un-encode password */ orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); if( orig_pass == NULL ) return LUTIL_PASSWD_ERR; rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); if (rc <= (int)(sizeof(MD5digest))) { ber_memfree(orig_pass); return LUTIL_PASSWD_ERR; } /* hash credentials with salt */ lutil_MD5Init(&MD5context); lutil_MD5Update(&MD5context, (const unsigned char *) cred->bv_val, cred->bv_len ); lutil_MD5Update(&MD5context, &orig_pass[sizeof(MD5digest)], rc - sizeof(MD5digest)); lutil_MD5Final(MD5digest, &MD5context); /* compare */ rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest)); ber_memfree(orig_pass); return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; } static int chk_md5( const struct berval *sc, const struct berval * passwd, const struct berval * cred, const char **text ) { lutil_MD5_CTX MD5context; unsigned char MD5digest[LUTIL_MD5_BYTES]; int rc; unsigned char *orig_pass = NULL; size_t decode_len = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); /* safety check */ if (decode_len < sizeof(MD5digest)) { return LUTIL_PASSWD_ERR; } /* base64 un-encode password */ orig_pass = (unsigned char *) ber_memalloc(decode_len + 1); if( orig_pass == NULL ) return LUTIL_PASSWD_ERR; rc = lutil_b64_pton(passwd->bv_val, orig_pass, decode_len); if ( rc != sizeof(MD5digest) ) { ber_memfree(orig_pass); return LUTIL_PASSWD_ERR; } /* hash credentials with salt */ lutil_MD5Init(&MD5context); lutil_MD5Update(&MD5context, (const unsigned char *) cred->bv_val, cred->bv_len ); lutil_MD5Final(MD5digest, &MD5context); /* compare */ rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest)); ber_memfree(orig_pass); return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; } #ifdef SLAPD_CRYPT static int lutil_crypt( const char *key, const char *salt, char **hash ) { char *cr = crypt( key, salt ); int rc; if( cr == NULL || cr[0] == '\0' ) { /* salt must have been invalid */ rc = LUTIL_PASSWD_ERR; } else { if ( hash ) { *hash = ber_strdup( cr ); rc = LUTIL_PASSWD_OK; } else { rc = strcmp( salt, cr ) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; } } return rc; } static int chk_crypt( const struct berval *sc, const struct berval * passwd, const struct berval * cred, const char **text ) { unsigned int i; for( i=0; ibv_len; i++) { if(cred->bv_val[i] == '\0') { return LUTIL_PASSWD_ERR; /* NUL character in password */ } } if( cred->bv_val[i] != '\0' ) { return LUTIL_PASSWD_ERR; /* cred must behave like a string */ } if( passwd->bv_len < 2 ) { return LUTIL_PASSWD_ERR; /* passwd must be at least two characters long */ } for( i=0; ibv_len; i++) { if(passwd->bv_val[i] == '\0') { return LUTIL_PASSWD_ERR; /* NUL character in password */ } } if( passwd->bv_val[i] != '\0' ) { return LUTIL_PASSWD_ERR; /* passwd must behave like a string */ } return lutil_cryptptr( cred->bv_val, passwd->bv_val, NULL ); } # if defined( HAVE_GETPWNAM ) && defined( HAVE_STRUCT_PASSWD_PW_PASSWD ) static int chk_unix( const struct berval *sc, const struct berval * passwd, const struct berval * cred, const char **text ) { unsigned int i; char *pw; for( i=0; ibv_len; i++) { if(cred->bv_val[i] == '\0') { return LUTIL_PASSWD_ERR; /* NUL character in password */ } } if( cred->bv_val[i] != '\0' ) { return LUTIL_PASSWD_ERR; /* cred must behave like a string */ } for( i=0; ibv_len; i++) { if(passwd->bv_val[i] == '\0') { return LUTIL_PASSWD_ERR; /* NUL character in password */ } } if( passwd->bv_val[i] != '\0' ) { return LUTIL_PASSWD_ERR; /* passwd must behave like a string */ } { struct passwd *pwd = getpwnam(passwd->bv_val); if(pwd == NULL) { return LUTIL_PASSWD_ERR; /* not found */ } pw = pwd->pw_passwd; } # ifdef HAVE_GETSPNAM { struct spwd *spwd = getspnam(passwd->bv_val); if(spwd != NULL) { pw = spwd->sp_pwdp; } } # endif # ifdef HAVE_AIX_SECURITY { struct userpw *upw = getuserpw(passwd->bv_val); if (upw != NULL) { pw = upw->upw_passwd; } } # endif if( pw == NULL || pw[0] == '\0' || pw[1] == '\0' ) { /* password must must be at least two characters long */ return LUTIL_PASSWD_ERR; } return lutil_cryptptr( cred->bv_val, pw, NULL ); } # endif #endif /* PASSWORD GENERATION ROUTINES */ #ifdef LUTIL_SHA1_BYTES static int hash_ssha1( const struct berval *scheme, const struct berval *passwd, struct berval *hash, const char **text ) { lutil_SHA1_CTX SHA1context; unsigned char SHA1digest[LUTIL_SHA1_BYTES]; char saltdata[SALT_SIZE]; struct berval digest; struct berval salt; digest.bv_val = (char *) SHA1digest; digest.bv_len = sizeof(SHA1digest); salt.bv_val = saltdata; salt.bv_len = sizeof(saltdata); if( lutil_entropy( (unsigned char *) salt.bv_val, salt.bv_len) < 0 ) { return LUTIL_PASSWD_ERR; } lutil_SHA1Init( &SHA1context ); lutil_SHA1Update( &SHA1context, (const unsigned char *)passwd->bv_val, passwd->bv_len ); lutil_SHA1Update( &SHA1context, (const unsigned char *)salt.bv_val, salt.bv_len ); lutil_SHA1Final( SHA1digest, &SHA1context ); return lutil_passwd_string64( scheme, &digest, hash, &salt); } static int hash_sha1( const struct berval *scheme, const struct berval *passwd, struct berval *hash, const char **text ) { lutil_SHA1_CTX SHA1context; unsigned char SHA1digest[LUTIL_SHA1_BYTES]; struct berval digest; digest.bv_val = (char *) SHA1digest; digest.bv_len = sizeof(SHA1digest); lutil_SHA1Init( &SHA1context ); lutil_SHA1Update( &SHA1context, (const unsigned char *)passwd->bv_val, passwd->bv_len ); lutil_SHA1Final( SHA1digest, &SHA1context ); return lutil_passwd_string64( scheme, &digest, hash, NULL); } #endif static int hash_smd5( const struct berval *scheme, const struct berval *passwd, struct berval *hash, const char **text ) { lutil_MD5_CTX MD5context; unsigned char MD5digest[LUTIL_MD5_BYTES]; char saltdata[SALT_SIZE]; struct berval digest; struct berval salt; digest.bv_val = (char *) MD5digest; digest.bv_len = sizeof(MD5digest); salt.bv_val = saltdata; salt.bv_len = sizeof(saltdata); if( lutil_entropy( (unsigned char *) salt.bv_val, salt.bv_len) < 0 ) { return LUTIL_PASSWD_ERR; } lutil_MD5Init( &MD5context ); lutil_MD5Update( &MD5context, (const unsigned char *) passwd->bv_val, passwd->bv_len ); lutil_MD5Update( &MD5context, (const unsigned char *) salt.bv_val, salt.bv_len ); lutil_MD5Final( MD5digest, &MD5context ); return lutil_passwd_string64( scheme, &digest, hash, &salt ); } static int hash_md5( const struct berval *scheme, const struct berval *passwd, struct berval *hash, const char **text ) { lutil_MD5_CTX MD5context; unsigned char MD5digest[LUTIL_MD5_BYTES]; struct berval digest; digest.bv_val = (char *) MD5digest; digest.bv_len = sizeof(MD5digest); lutil_MD5Init( &MD5context ); lutil_MD5Update( &MD5context, (const unsigned char *) passwd->bv_val, passwd->bv_len ); lutil_MD5Final( MD5digest, &MD5context ); return lutil_passwd_string64( scheme, &digest, hash, NULL ); ; } #ifdef SLAPD_CRYPT static int hash_crypt( const struct berval *scheme, const struct berval *passwd, struct berval *hash, const char **text ) { unsigned char salt[32]; /* salt suitable for most anything */ unsigned int i; char *save; int rc; for( i=0; ibv_len; i++) { if(passwd->bv_val[i] == '\0') { return LUTIL_PASSWD_ERR; /* NUL character in password */ } } if( passwd->bv_val[i] != '\0' ) { return LUTIL_PASSWD_ERR; /* passwd must behave like a string */ } if( lutil_entropy( salt, sizeof( salt ) ) < 0 ) { return LUTIL_PASSWD_ERR; } for( i=0; i< ( sizeof(salt) - 1 ); i++ ) { salt[i] = crypt64[ salt[i] % (sizeof(crypt64)-1) ]; } salt[sizeof( salt ) - 1 ] = '\0'; if( salt_format != NULL ) { /* copy the salt we made into entropy before snprintfing it back into the salt */ char entropy[sizeof(salt)]; strcpy( entropy, (char *) salt ); snprintf( (char *) salt, sizeof(entropy), salt_format, entropy ); } rc = lutil_cryptptr( passwd->bv_val, (char *) salt, &hash->bv_val ); if ( rc != LUTIL_PASSWD_OK ) return rc; if( hash->bv_val == NULL ) return -1; hash->bv_len = strlen( hash->bv_val ); save = hash->bv_val; if( hash->bv_len == 0 ) { rc = LUTIL_PASSWD_ERR; } else { rc = pw_string( scheme, hash ); } ber_memfree( save ); return rc; } #endif int lutil_salt_format(const char *format) { #ifdef SLAPD_CRYPT ber_memfree( salt_format ); salt_format = format != NULL ? ber_strdup( format ) : NULL; #endif return 0; } #ifdef SLAPD_CLEARTEXT static int hash_clear( const struct berval *scheme, const struct berval *passwd, struct berval *hash, const char **text ) { ber_dupbv( hash, (struct berval *)passwd ); return LUTIL_PASSWD_OK; } #endif openldap-2.5.11+dfsg/libraries/liblutil/slapdmsg.h0000644000175000017500000000315614172327167020623 0ustar ryanryan// // This file contains message strings for the OpenLDAP slapd service. // // This file should be compiled as follows // mc -v slapdmsg.mc -r $(IntDir) // rc /v /r $(IntDir)\slapdmsg.rc // The mc (message compiler) command generates the .rc and .h files from this file. The // rc (resource compiler) takes the .rc file and produces a .res file that can be linked // with the final executable application. The application is then registered as a message // source with by creating the appropriate entries in the system registry. // // // Values are 32 bit values laid out as follows: // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // +---+-+-+-----------------------+-------------------------------+ // |Sev|C|R| Facility | Code | // +---+-+-+-----------------------+-------------------------------+ // // where // // Sev - is the severity code // // 00 - Success // 01 - Informational // 10 - Warning // 11 - Error // // C - is the Customer code flag // // R - is a reserved bit // // Facility - is the facility code // // Code - is the facility's status code // // // Define the facility codes // // // Define the severity codes // // // MessageId: MSG_SVC_STARTED // // MessageText: // // OpenLDAP service started. debuglevel=%1, conffile=%2, urls=%3 // #define MSG_SVC_STARTED 0x40000500L // // MessageId: MSG_SVC_STOPPED // // MessageText: // // OpenLDAP service stopped. // #define MSG_SVC_STOPPED 0x40000501L openldap-2.5.11+dfsg/libraries/liblutil/passfile.c0000644000175000017500000000427114172327167020611 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #ifdef HAVE_FSTAT #include #include #endif /* HAVE_FSTAT */ #include #include /* Get a password from a file. */ int lutil_get_filed_password( const char *filename, struct berval *passwd ) { size_t nread, nleft, nr; FILE *f = fopen( filename, "r" ); if( f == NULL ) { perror( filename ); return -1; } passwd->bv_val = NULL; passwd->bv_len = 4096; #ifdef HAVE_FSTAT { struct stat sb; if ( fstat( fileno( f ), &sb ) == 0 ) { if( sb.st_mode & 006 ) { fprintf( stderr, _("Warning: Password file %s" " is publicly readable/writeable\n"), filename ); } if ( sb.st_size ) passwd->bv_len = sb.st_size; } } #endif /* HAVE_FSTAT */ passwd->bv_val = (char *) ber_memalloc( passwd->bv_len + 1 ); if( passwd->bv_val == NULL ) { perror( filename ); fclose( f ); return -1; } nread = 0; nleft = passwd->bv_len; do { if( nleft == 0 ) { /* double the buffer size */ char *p = (char *) ber_memrealloc( passwd->bv_val, 2 * passwd->bv_len + 1 ); if( p == NULL ) { ber_memfree( passwd->bv_val ); passwd->bv_val = NULL; passwd->bv_len = 0; fclose( f ); return -1; } nleft = passwd->bv_len; passwd->bv_len *= 2; passwd->bv_val = p; } nr = fread( &passwd->bv_val[nread], 1, nleft, f ); if( nr < nleft && ferror( f ) ) { ber_memfree( passwd->bv_val ); passwd->bv_val = NULL; passwd->bv_len = 0; fclose( f ); return -1; } nread += nr; nleft -= nr; } while ( !feof(f) ); passwd->bv_len = nread; passwd->bv_val[nread] = '\0'; fclose( f ); return 0; } openldap-2.5.11+dfsg/libraries/liblutil/detach.c0000644000175000017500000000601514172327167020231 0ustar ryanryan/* detach.c -- routines to daemonize a process */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* * Copyright (c) 1990, 1994 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ /* This work was originally developed by the University of Michigan * and distributed as part of U-MICH LDAP. */ #include "portable.h" #include #include #include #include #include #include #include #ifdef HAVE_SYS_FILE_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #include "lutil.h" int lutil_detach( int debug, int do_close ) { int i, sd, nbits, pid; #ifdef HAVE_SYSCONF nbits = sysconf( _SC_OPEN_MAX ); #elif defined(HAVE_GETDTABLESIZE) nbits = getdtablesize(); #else nbits = FD_SETSIZE; #endif #ifdef FD_SETSIZE if ( nbits > FD_SETSIZE ) { nbits = FD_SETSIZE; } #endif /* FD_SETSIZE */ if ( debug == 0 ) { for ( i = 0; i < 5; i++ ) { #ifdef HAVE_THR pid = fork1(); #else pid = fork(); #endif switch ( pid ) { case -1: sleep( 5 ); continue; case 0: break; default: return pid; } break; } if ( (sd = open( "/dev/null", O_RDWR )) == -1 && (sd = open( "/dev/null", O_RDONLY )) == -1 && /* Panic -- open *something* */ (sd = open( "/", O_RDONLY )) == -1 ) { perror("/dev/null"); } else { /* redirect stdin, stdout, stderr to /dev/null */ dup2( sd, STDIN_FILENO ); dup2( sd, STDOUT_FILENO ); dup2( sd, STDERR_FILENO ); switch( sd ) { default: close( sd ); case STDIN_FILENO: case STDOUT_FILENO: case STDERR_FILENO: break; } } if ( do_close ) { /* close everything else */ for ( i = 0; i < nbits; i++ ) { if( i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO ) { close( i ); } } } #ifdef CHDIR_TO_ROOT (void) chdir( "/" ); #endif #ifdef HAVE_SETSID (void) setsid(); #elif defined(TIOCNOTTY) if ( (sd = open( "/dev/tty", O_RDWR )) != -1 ) { (void) ioctl( sd, TIOCNOTTY, NULL ); (void) close( sd ); } #endif } #ifdef SIGPIPE (void) SIGNAL( SIGPIPE, SIG_IGN ); #endif return 0; } openldap-2.5.11+dfsg/libraries/liblutil/md5.c0000644000175000017500000002340214172327167017465 0ustar ryanryan/* md5.c -- MD5 message-digest algorithm */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* This work was adapted for inclusion in OpenLDAP Software by * Kurt D. Zeilenga based upon code developed by Colin Plumb * and subsequently modified by Jim Kingdon. */ /* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ /* This code was modified in 1997 by Jim Kingdon of Cyclic Software to not require an integer type which is exactly 32 bits. This work draws on the changes for the same purpose by Tatu Ylonen as part of SSH, but since I didn't actually use that code, there is no copyright issue. I hereby disclaim copyright in any changes I have made; this code remains in the public domain. */ #include "portable.h" #include /* include socket.h to get sys/types.h and/or winsock2.h */ #include #include /* Little-endian byte-swapping routines. Note that these do not depend on the size of datatypes such as ber_uint_t, nor do they require us to detect the endianness of the machine we are running on. It is possible they should be macros for speed, but I would be surprised if they were a performance bottleneck for MD5. */ static ber_uint_t getu32( const unsigned char *addr ) { return (((((unsigned long)addr[3] << 8) | addr[2]) << 8) | addr[1]) << 8 | addr[0]; } static void putu32( ber_uint_t data, unsigned char *addr ) { addr[0] = (unsigned char)data; addr[1] = (unsigned char)(data >> 8); addr[2] = (unsigned char)(data >> 16); addr[3] = (unsigned char)(data >> 24); } /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void lutil_MD5Init( struct lutil_MD5Context *ctx ) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void lutil_MD5Update( struct lutil_MD5Context *ctx, const unsigned char *buf, ber_len_t len ) { ber_uint_t t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = (t + ((ber_uint_t)len << 3)) & 0xffffffff) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if ( t ) { unsigned char *p = ctx->in + t; t = 64-t; if (len < t) { AC_MEMCPY(p, buf, len); return; } AC_MEMCPY(p, buf, t); lutil_MD5Transform(ctx->buf, ctx->in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { AC_MEMCPY(ctx->in, buf, 64); lutil_MD5Transform(ctx->buf, ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ AC_MEMCPY(ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void lutil_MD5Final( unsigned char *digest, struct lutil_MD5Context *ctx ) { unsigned count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, '\0', count); lutil_MD5Transform(ctx->buf, ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in, '\0', 56); } else { /* Pad block to 56 bytes */ memset(p, '\0', count-8); } /* Append length in bits and transform */ putu32(ctx->bits[0], ctx->in + 56); putu32(ctx->bits[1], ctx->in + 60); lutil_MD5Transform(ctx->buf, ctx->in); putu32(ctx->buf[0], digest); putu32(ctx->buf[1], digest + 4); putu32(ctx->buf[2], digest + 8); putu32(ctx->buf[3], digest + 12); memset(ctx, '\0', sizeof(*ctx)); /* In case it's sensitive */ } #ifndef ASM_MD5 /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w &= 0xffffffff, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ void lutil_MD5Transform( ber_uint_t *buf, const unsigned char *inraw ) { register ber_uint_t a, b, c, d; ber_uint_t in[16]; int i; for (i = 0; i < 16; ++i) in[i] = getu32 (inraw + 4 * i); a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } #endif #ifdef TEST /* Simple test program. Can use it to manually run the tests from RFC1321 for example. */ #include int main (int argc, char **argv ) { struct lutil_MD5Context context; unsigned char checksum[LUTIL_MD5_BYTES]; int i; int j; if (argc < 2) { fprintf (stderr, "usage: %s string-to-hash\n", argv[0]); return EXIT_FAILURE; } for (j = 1; j < argc; ++j) { printf ("MD5 (\"%s\") = ", argv[j]); lutil_MD5Init (&context); lutil_MD5Update (&context, argv[j], strlen (argv[j])); lutil_MD5Final (checksum, &context); for (i = 0; i < LUTIL_MD5_BYTES; i++) { printf ("%02x", (unsigned int) checksum[i]); } printf ("\n"); } return EXIT_SUCCESS; } #endif /* TEST */ openldap-2.5.11+dfsg/libraries/liblutil/ptest.c0000644000175000017500000000432214172327167020137 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include #include #include #include "lutil.h" /* * Password Test Program */ static char *hash[] = { #ifdef SLAP_AUTHPASSWD "SHA1", "MD5", #else #ifdef SLAPD_CRYPT "{CRYPT}", #endif "{SSHA}", "{SMD5}", "{SHA}", "{MD5}", "{BOGUS}", #endif NULL }; static struct berval pw[] = { { sizeof("secret")-1, "secret" }, { sizeof("binary\0secret")-1, "binary\0secret" }, { 0, NULL } }; int main( int argc, char *argv[] ) { int i, j, rc; struct berval *passwd; #ifdef SLAP_AUTHPASSWD struct berval *salt; #endif struct berval bad; bad.bv_val = "bad password"; bad.bv_len = sizeof("bad password")-1; for( i= 0; hash[i]; i++ ) { for( j = 0; pw[j].bv_len; j++ ) { #ifdef SLAP_AUTHPASSWD rc = lutil_authpasswd_hash( &pw[j], &passwd, &salt, hash[i] ); if( rc ) #else passwd = lutil_passwd_hash( &pw[j], hash[i] ); if( passwd == NULL ) #endif { printf("%s generate fail: %s (%d)\n", hash[i], pw[j].bv_val, pw[j].bv_len ); continue; } #ifdef SLAP_AUTHPASSWD rc = lutil_authpasswd( &pw[j], passwd, salt, NULL ); #else rc = lutil_passwd( passwd, &pw[j], NULL ); #endif printf("%s (%d): %s (%d)\t(%d) %s\n", pw[j].bv_val, pw[j].bv_len, passwd->bv_val, passwd->bv_len, rc, rc == 0 ? "OKAY" : "BAD" ); #ifdef SLAP_AUTHPASSWD rc = lutil_authpasswd( passwd, salt, &bad, NULL ); #else rc = lutil_passwd( passwd, &bad, NULL ); #endif printf("%s (%d): %s (%d)\t(%d) %s\n", bad.bv_val, bad.bv_len, passwd->bv_val, passwd->bv_len, rc, rc != 0 ? "OKAY" : "BAD" ); } printf("\n"); } return EXIT_SUCCESS; } openldap-2.5.11+dfsg/libraries/liblutil/utils.c0000644000175000017500000005052714172327167020150 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include #include #include #include #ifdef HAVE_IO_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #ifdef _WIN32 #include #endif #include "lutil.h" #include "ldap_defaults.h" #include "ldap_pvt.h" #include "lber_pvt.h" #ifdef HAVE_EBCDIC int _trans_argv = 1; #endif #ifdef _WIN32 /* Some Windows versions accept both forward and backslashes in * directory paths, but we always use backslashes when generating * and parsing... */ void lutil_slashpath( char *path ) { char *c, *p; p = path; while (( c=strchr( p, '/' ))) { *c++ = '\\'; p = c; } } #endif char* lutil_progname( const char* name, int argc, char *argv[] ) { char *progname; if(argc == 0) { return (char *)name; } #ifdef HAVE_EBCDIC if (_trans_argv) { int i; for (i=0; i 4 && strcasecmp( &progname[len - 4], ".exe" ) == 0 ) progname[len - 4] = '\0'; } #endif return progname; } #if 0 size_t lutil_gentime( char *s, size_t smax, const struct tm *tm ) { size_t ret; #ifdef HAVE_EBCDIC /* We've been compiling in ASCII so far, but we want EBCDIC now since * strftime only understands EBCDIC input. */ #pragma convlit(suspend) #endif ret = strftime( s, smax, "%Y%m%d%H%M%SZ", tm ); #ifdef HAVE_EBCDIC #pragma convlit(resume) __etoa( s ); #endif return ret; } #endif size_t lutil_localtime( char *s, size_t smax, const struct tm *tm, long delta ) { size_t ret; char *p; if ( smax < 16 ) { /* YYYYmmddHHMMSSZ */ return 0; } #ifdef HAVE_EBCDIC /* We've been compiling in ASCII so far, but we want EBCDIC now since * strftime only understands EBCDIC input. */ #pragma convlit(suspend) #endif ret = strftime( s, smax, "%Y%m%d%H%M%SZ", tm ); #ifdef HAVE_EBCDIC #pragma convlit(resume) __etoa( s ); #endif if ( delta == 0 || ret == 0 ) { return ret; } if ( smax < 20 ) { /* YYYYmmddHHMMSS+HHMM */ return 0; } p = s + 14; if ( delta < 0 ) { p[ 0 ] = '-'; delta = -delta; } else { p[ 0 ] = '+'; } p++; snprintf( p, smax - 15, "%02ld%02ld", delta / 3600, ( delta % 3600 ) / 60 ); return ret + 4; } int lutil_tm2time( struct lutil_tm *tm, struct lutil_timet *tt ) { static int moffset[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; int sec; tt->tt_nsec = tm->tm_nsec; /* special case 0000/01/01+00:00:00 is returned as zero */ if ( tm->tm_year == -1900 && tm->tm_mon == 0 && tm->tm_mday == 1 && tm->tm_hour == 0 && tm->tm_min == 0 && tm->tm_sec == 0 ) { tt->tt_sec = 0; tt->tt_gsec = 0; return 0; } /* tm->tm_year is years since 1900 */ /* calculate days from years since 1970 (epoch) */ tt->tt_sec = tm->tm_year - 70; tt->tt_sec *= 365L; /* count leap days in preceding years */ tt->tt_sec += ((tm->tm_year -69) >> 2); /* calculate days from months */ tt->tt_sec += moffset[tm->tm_mon]; /* add in this year's leap day, if any */ if (((tm->tm_year & 3) == 0) && (tm->tm_mon > 1)) { tt->tt_sec ++; } /* add in days in this month */ tt->tt_sec += (tm->tm_mday - 1); /* this function can handle a range of about 17408 years... */ /* 86400 seconds in a day, divided by 128 = 675 */ tt->tt_sec *= 675; /* move high 7 bits into tt_gsec */ tt->tt_gsec = tt->tt_sec >> 25; tt->tt_sec -= tt->tt_gsec << 25; /* get hours */ sec = tm->tm_hour; /* convert to minutes */ sec *= 60L; sec += tm->tm_min; /* convert to seconds */ sec *= 60L; sec += tm->tm_sec; /* add remaining seconds */ tt->tt_sec <<= 7; tt->tt_sec += sec; /* return success */ return 0; } /* Proleptic Gregorian Calendar, 1BCE = year 0 */ int lutil_tm2gtime( struct lutil_tm *tm, struct lutil_timet *tt ) { static int moffset[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; int sec, year; long tmp; tt->tt_nsec = tm->tm_nsec; /* tm->tm_year is years since 1900 */ /* calculate days from 0000 */ year = tm->tm_year + 1900; tmp = year * 365; /* add in leap days */ sec = (year - 1) / 4; tmp += sec; sec /= 25; tmp -= sec; sec /= 4; tmp += sec; /* Year 0000 was a leap year */ if (year > 0) tmp++; /* calculate days from months */ tmp += moffset[tm->tm_mon]; /* add in this year's leap day, if any */ if (tm->tm_mon > 1) { sec = (year % 4) ? 0 : (year % 100) ? 1 : (year % 400) ? 0 : 1; tmp += sec; } /* add in days in this month */ tmp += (tm->tm_mday - 1); /* this function can handle a range of about 17408 years... */ /* 86400 seconds in a day, divided by 128 = 675 */ tmp *= 675; /* move high 7 bits into tt_gsec */ tt->tt_gsec = tmp >> 25; tmp -= tt->tt_gsec << 25; /* toggle sign bit, keep positive greater than negative */ tt->tt_gsec &= 0x7f; tt->tt_gsec ^= 0x40; /* get hours */ sec = tm->tm_hour; /* convert to minutes */ sec *= 60L; sec += tm->tm_min; /* convert to seconds */ sec *= 60L; sec += tm->tm_sec; /* add remaining seconds */ tmp <<= 7; tmp += sec; tt->tt_sec = tmp; /* return success */ return 0; } int lutil_parsetime( char *atm, struct lutil_tm *tm ) { while (atm && tm) { char *ptr; unsigned i, fracs; int neg = 0; if (*atm == '-') { neg = 1; atm++; } ptr = atm; /* Is the stamp reasonably long? */ for (i=0; isdigit((unsigned char) atm[i]); i++); if (i < sizeof("00000101000000")-1) break; /* * parse the time into a struct tm */ /* 4 digit year to year - 1900 */ tm->tm_year = *ptr++ - '0'; tm->tm_year *= 10; tm->tm_year += *ptr++ - '0'; tm->tm_year *= 10; tm->tm_year += *ptr++ - '0'; tm->tm_year *= 10; tm->tm_year += *ptr++ - '0'; if (neg) tm->tm_year = -tm->tm_year; tm->tm_year -= 1900; /* month 01-12 to 0-11 */ tm->tm_mon = *ptr++ - '0'; tm->tm_mon *=10; tm->tm_mon += *ptr++ - '0'; if (tm->tm_mon < 1 || tm->tm_mon > 12) break; tm->tm_mon--; /* day of month 01-31 */ tm->tm_mday = *ptr++ - '0'; tm->tm_mday *=10; tm->tm_mday += *ptr++ - '0'; if (tm->tm_mday < 1 || tm->tm_mday > 31) break; /* Hour 00-23 */ tm->tm_hour = *ptr++ - '0'; tm->tm_hour *=10; tm->tm_hour += *ptr++ - '0'; if (tm->tm_hour < 0 || tm->tm_hour > 23) break; /* Minute 00-59 */ tm->tm_min = *ptr++ - '0'; tm->tm_min *=10; tm->tm_min += *ptr++ - '0'; if (tm->tm_min < 0 || tm->tm_min > 59) break; /* Second 00-61 */ tm->tm_sec = *ptr++ - '0'; tm->tm_sec *=10; tm->tm_sec += *ptr++ - '0'; if (tm->tm_sec < 0 || tm->tm_sec > 61) break; /* Fractions of seconds */ if ( *ptr == '.' ) { ptr++; for (i = 0, fracs = 0; isdigit((unsigned char) *ptr); ) { i*=10; i+= *ptr++ - '0'; fracs++; } tm->tm_nsec = i; if (i) { for (i = fracs; i<9; i++) tm->tm_nsec *= 10; } } else { tm->tm_nsec = 0; } tm->tm_usub = 0; /* Must be UTC */ if (*ptr != 'Z') break; return 0; } return -1; } /* strcopy is like strcpy except it returns a pointer to the trailing NUL of * the result string. This allows fast construction of catenated strings * without the overhead of strlen/strcat. */ char * lutil_strcopy( char *a, const char *b ) { if (!a || !b) return a; while ((*a++ = *b++)) ; return a-1; } /* strncopy is like strcpy except it returns a pointer to the trailing NUL of * the result string. This allows fast construction of catenated strings * without the overhead of strlen/strcat. */ char * lutil_strncopy( char *a, const char *b, size_t n ) { if (!a || !b || n == 0) return a; while ((*a++ = *b++) && n-- > 0) ; return a-1; } /* memcopy is like memcpy except it returns a pointer to the byte past * the end of the result buffer, set to NULL. This allows fast construction * of catenated buffers. Provided for API consistency with lutil_str*copy(). */ char * lutil_memcopy( char *a, const char *b, size_t n ) { AC_MEMCPY(a, b, n); return a + n; } #ifndef HAVE_MKSTEMP int mkstemp( char * template ) { #ifdef HAVE_MKTEMP return open ( mktemp ( template ), O_RDWR|O_CREAT|O_EXCL, 0600 ); #else return -1; #endif } #endif #ifdef _MSC_VER /* Equivalent of MS CRT's _dosmaperr(). * @param lastError[in] Result of GetLastError(). */ static errno_t win2errno(DWORD lastError) { const struct { DWORD windows_code; errno_t errno_code; } WIN2ERRNO_TABLE[] = { { ERROR_SUCCESS, 0 }, { ERROR_FILE_NOT_FOUND, ENOENT }, { ERROR_PATH_NOT_FOUND, ENOENT }, { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, { ERROR_ACCESS_DENIED, EACCES }, { ERROR_INVALID_HANDLE, EBADF }, { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, { ERROR_LOCK_VIOLATION, EACCES }, { ERROR_FILE_EXISTS, EEXIST }, { ERROR_INVALID_PARAMETER, EINVAL }, { ERROR_FILENAME_EXCED_RANGE, ENAMETOOLONG }, }; const unsigned int WIN2ERRNO_TABLE_SIZE = sizeof(WIN2ERRNO_TABLE) / sizeof(WIN2ERRNO_TABLE[0]); const errno_t DEFAULT_ERRNO_ERROR = -1; unsigned int i; for (i = 0; i < WIN2ERRNO_TABLE_SIZE; ++i) { if (WIN2ERRNO_TABLE[i].windows_code == lastError) { return WIN2ERRNO_TABLE[i].errno_code; } } return DEFAULT_ERRNO_ERROR; } struct dirent { char *d_name; }; typedef struct DIR { HANDLE dir; struct dirent data; int first; char buf[MAX_PATH+1]; } DIR; DIR *opendir( char *path ) { char tmp[32768]; int len = strlen(path); DIR *d; HANDLE h; WIN32_FIND_DATA data; if (len+3 >= sizeof(tmp)) { errno = ENAMETOOLONG; return NULL; } strcpy(tmp, path); tmp[len++] = '\\'; tmp[len++] = '*'; tmp[len] = '\0'; h = FindFirstFile( tmp, &data ); if ( h == INVALID_HANDLE_VALUE ) { errno = win2errno( GetLastError()); return NULL; } d = ber_memalloc( sizeof(DIR) ); if ( !d ) return NULL; d->dir = h; d->data.d_name = d->buf; d->first = 1; strcpy(d->data.d_name, data.cFileName); return d; } struct dirent *readdir(DIR *dir) { WIN32_FIND_DATA data; if (dir->first) { dir->first = 0; } else { if (!FindNextFile(dir->dir, &data)) return NULL; strcpy(dir->data.d_name, data.cFileName); } return &dir->data; } int closedir(DIR *dir) { (void) FindClose(dir->dir); ber_memfree(dir); return 0; } #endif /* * Memory Reverse Search */ void * (lutil_memrchr)(const void *b, int c, size_t n) { if (n != 0) { const unsigned char *s, *bb = b, cc = c; for ( s = bb + n; s > bb; ) { if ( *--s == cc ) { return (void *) s; } } } return NULL; } int lutil_atoix( int *v, const char *s, int x ) { char *next; long i; assert( s != NULL ); assert( v != NULL ); i = strtol( s, &next, x ); if ( next == s || next[ 0 ] != '\0' ) { return -1; } if ( (long)(int)i != i ) { return 1; } *v = (int)i; return 0; } int lutil_atoux( unsigned *v, const char *s, int x ) { char *next; unsigned long u; assert( s != NULL ); assert( v != NULL ); /* strtoul() has an odd interface */ if ( s[ 0 ] == '-' ) { return -1; } u = strtoul( s, &next, x ); if ( next == s || next[ 0 ] != '\0' ) { return -1; } if ( (unsigned long)(unsigned)u != u ) { return 1; } *v = u; return 0; } int lutil_atolx( long *v, const char *s, int x ) { char *next; long l; int save_errno; assert( s != NULL ); assert( v != NULL ); if ( isspace( s[ 0 ] ) ) { return -1; } errno = 0; l = strtol( s, &next, x ); save_errno = errno; if ( next == s || next[ 0 ] != '\0' ) { return -1; } if ( ( l == LONG_MIN || l == LONG_MAX ) && save_errno != 0 ) { return -1; } *v = l; return 0; } int lutil_atoulx( unsigned long *v, const char *s, int x ) { char *next; unsigned long ul; int save_errno; assert( s != NULL ); assert( v != NULL ); /* strtoul() has an odd interface */ if ( s[ 0 ] == '-' || isspace( s[ 0 ] ) ) { return -1; } errno = 0; ul = strtoul( s, &next, x ); save_errno = errno; if ( next == s || next[ 0 ] != '\0' ) { return -1; } if ( ( ul == 0 || ul == ULONG_MAX ) && save_errno != 0 ) { return -1; } *v = ul; return 0; } #ifdef HAVE_LONG_LONG #if defined(HAVE_STRTOLL) || defined(HAVE_STRTOQ) int lutil_atollx( long long *v, const char *s, int x ) { char *next; long long ll; int save_errno; assert( s != NULL ); assert( v != NULL ); if ( isspace( s[ 0 ] ) ) { return -1; } errno = 0; #ifdef HAVE_STRTOLL ll = strtoll( s, &next, x ); #else /* HAVE_STRTOQ */ ll = (unsigned long long)strtoq( s, &next, x ); #endif /* HAVE_STRTOQ */ save_errno = errno; if ( next == s || next[ 0 ] != '\0' ) { return -1; } /* LLONG_MIN, LLONG_MAX are C99 only */ #if defined (LLONG_MIN) && defined(LLONG_MAX) if ( ( ll == LLONG_MIN || ll == LLONG_MAX ) && save_errno != 0 ) { return -1; } #endif /* LLONG_MIN && LLONG_MAX */ *v = ll; return 0; } #endif /* HAVE_STRTOLL || HAVE_STRTOQ */ #if defined(HAVE_STRTOULL) || defined(HAVE_STRTOUQ) int lutil_atoullx( unsigned long long *v, const char *s, int x ) { char *next; unsigned long long ull; int save_errno; assert( s != NULL ); assert( v != NULL ); /* strtoull() has an odd interface */ if ( s[ 0 ] == '-' || isspace( s[ 0 ] ) ) { return -1; } errno = 0; #ifdef HAVE_STRTOULL ull = strtoull( s, &next, x ); #else /* HAVE_STRTOUQ */ ull = (unsigned long long)strtouq( s, &next, x ); #endif /* HAVE_STRTOUQ */ save_errno = errno; if ( next == s || next[ 0 ] != '\0' ) { return -1; } /* ULLONG_MAX is C99 only */ #if defined(ULLONG_MAX) if ( ( ull == 0 || ull == ULLONG_MAX ) && save_errno != 0 ) { return -1; } #endif /* ULLONG_MAX */ *v = ull; return 0; } #endif /* HAVE_STRTOULL || HAVE_STRTOUQ */ #endif /* HAVE_LONG_LONG */ /* Multiply an integer by 100000000 and add new */ typedef struct lutil_int_decnum { unsigned char *buf; int bufsiz; int beg; int len; } lutil_int_decnum; #define FACTOR1 (100000000&0xffff) #define FACTOR2 (100000000>>16) static void scale( int new, lutil_int_decnum *prev, unsigned char *tmp ) { int i, j; unsigned char *in = prev->buf+prev->beg; unsigned int part; unsigned char *out = tmp + prev->bufsiz - prev->len; memset( tmp, 0, prev->bufsiz ); if ( prev->len ) { for ( i = prev->len-1; i>=0; i-- ) { part = in[i] * FACTOR1; for ( j = i; part; j-- ) { part += out[j]; out[j] = part & 0xff; part >>= 8; } part = in[i] * FACTOR2; for ( j = i-2; part; j-- ) { part += out[j]; out[j] = part & 0xff; part >>= 8; } } j++; prev->beg += j; prev->len -= j; } out = tmp + prev->bufsiz; i = 0; do { i--; new += out[i]; out[i] = new & 0xff; new >>= 8; } while ( new ); i = -i; if ( prev->len < i ) { prev->beg = prev->bufsiz - i; prev->len = i; } AC_MEMCPY( prev->buf+prev->beg, tmp+prev->beg, prev->len ); } /* Convert unlimited length decimal or hex string to binary. * Output buffer must be provided, bv_len must indicate buffer size * Hex input can be "0x1234" or "'1234'H" * * Note: High bit of binary form is always the sign bit. If the number * is supposed to be positive but has the high bit set, a zero byte * is prepended. It is assumed that this has already been handled on * any hex input. */ int lutil_str2bin( struct berval *in, struct berval *out, void *ctx ) { char *pin, *pout; char *end; int i, chunk, len, rc = 0, hex = 0; if ( !out || !out->bv_val || out->bv_len < in->bv_len ) return -1; pout = out->bv_val; /* Leading "0x" for hex input */ if ( in->bv_len > 2 && in->bv_val[0] == '0' && ( in->bv_val[1] == 'x' || in->bv_val[1] == 'X' ) ) { len = in->bv_len - 2; pin = in->bv_val + 2; hex = 1; } else if ( in->bv_len > 3 && in->bv_val[0] == '\'' && in->bv_val[in->bv_len-2] == '\'' && in->bv_val[in->bv_len-1] == 'H' ) { len = in->bv_len - 3; pin = in->bv_val + 1; hex = 1; } if ( hex ) { #define HEXMAX (2 * sizeof(long)) unsigned long l; char tbuf[HEXMAX+1]; /* Convert a longword at a time, but handle leading * odd bytes first */ chunk = len % HEXMAX; if ( !chunk ) chunk = HEXMAX; while ( len ) { int ochunk; memcpy( tbuf, pin, chunk ); tbuf[chunk] = '\0'; errno = 0; l = strtoul( tbuf, &end, 16 ); if ( errno ) return -1; ochunk = (chunk + 1)/2; for ( i = ochunk - 1; i >= 0; i-- ) { pout[i] = l & 0xff; l >>= 8; } pin += chunk; pout += ochunk; len -= chunk; chunk = HEXMAX; } out->bv_len = pout - out->bv_val; } else { /* Decimal */ #define DECMAX 8 /* 8 digits at a time */ char tmpbuf[64], *tmp; lutil_int_decnum num; int neg = 0; long l; char tbuf[DECMAX+1]; len = in->bv_len; pin = in->bv_val; num.buf = (unsigned char *)out->bv_val; num.bufsiz = out->bv_len; num.beg = num.bufsiz-1; num.len = 0; if ( pin[0] == '-' ) { neg = 0xff; len--; pin++; } /* tmp must be at least as large as outbuf */ if ( out->bv_len > sizeof(tmpbuf)) { tmp = ber_memalloc_x( out->bv_len, ctx ); } else { tmp = tmpbuf; } chunk = len & (DECMAX-1); if ( !chunk ) chunk = DECMAX; while ( len ) { memcpy( tbuf, pin, chunk ); tbuf[chunk] = '\0'; errno = 0; l = strtol( tbuf, &end, 10 ); if ( errno ) { rc = -1; goto decfail; } scale( l, &num, (unsigned char *)tmp ); pin += chunk; len -= chunk; chunk = DECMAX; } /* Negate the result */ if ( neg ) { unsigned char *ptr; ptr = num.buf+num.beg; /* flip all bits */ for ( i=0; ibv_len = num.len; decfail: if ( tmp != tmpbuf ) { ber_memfree_x( tmp, ctx ); } } return rc; } static char time_unit[] = "dhms"; /* Used to parse and unparse time intervals, not timestamps */ int lutil_parse_time( const char *in, unsigned long *tp ) { unsigned long t = 0; char *s, *next; int sofar = -1, scale[] = { 86400, 3600, 60, 1 }; *tp = 0; for ( s = (char *)in; s[ 0 ] != '\0'; ) { unsigned long u; char *what; /* strtoul() has an odd interface */ if ( s[ 0 ] == '-' ) { return -1; } u = strtoul( s, &next, 10 ); if ( next == s ) { return -1; } if ( next[ 0 ] == '\0' ) { /* assume seconds */ t += u; break; } what = strchr( time_unit, next[ 0 ] ); if ( what == NULL ) { return -1; } if ( what - time_unit <= sofar ) { return -1; } sofar = what - time_unit; t += u * scale[ sofar ]; s = &next[ 1 ]; } *tp = t; return 0; } int lutil_unparse_time( char *buf, size_t buflen, unsigned long t ) { int len, i; unsigned long v[ 4 ]; char *ptr = buf; v[ 0 ] = t/86400; v[ 1 ] = (t%86400)/3600; v[ 2 ] = (t%3600)/60; v[ 3 ] = t%60; for ( i = 0; i < 4; i++ ) { if ( v[i] > 0 || ( i == 3 && ptr == buf ) ) { len = snprintf( ptr, buflen, "%lu%c", v[ i ], time_unit[ i ] ); if ( len < 0 || (unsigned)len >= buflen ) { return -1; } buflen -= len; ptr += len; } } return 0; } /* * formatted print to string * * - if return code < 0, the error code returned by vsnprintf(3) is returned * * - if return code > 0, the buffer was not long enough; * - if next is not NULL, *next will be set to buf + bufsize - 1 * - if len is not NULL, *len will contain the required buffer length * * - if return code == 0, the buffer was long enough; * - if next is not NULL, *next will point to the end of the string printed so far * - if len is not NULL, *len will contain the length of the string printed so far */ int lutil_snprintf( char *buf, ber_len_t bufsize, char **next, ber_len_t *len, LDAP_CONST char *fmt, ... ) { va_list ap; int ret; assert( buf != NULL ); assert( bufsize > 0 ); assert( fmt != NULL ); va_start( ap, fmt ); ret = vsnprintf( buf, bufsize, fmt, ap ); va_end( ap ); if ( ret < 0 ) { return ret; } if ( len ) { *len = ret; } if ( (unsigned) ret >= bufsize ) { if ( next ) { *next = &buf[ bufsize - 1 ]; } return 1; } if ( next ) { *next = &buf[ ret ]; } return 0; } openldap-2.5.11+dfsg/libraries/liblutil/memcmp.c0000644000175000017500000000145514172327167020262 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include /* * Memory Compare */ int (lutil_memcmp)(const void *v1, const void *v2, size_t n) { if (n != 0) { const unsigned char *s1=v1, *s2=v2; do { if (*s1++ != *s2++) return *--s1 - *--s2; } while (--n != 0); } return 0; } openldap-2.5.11+dfsg/libraries/liblutil/ntservice.c0000644000175000017500000003545514172327167021015 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* * NT Service manager utilities for OpenLDAP services */ #include "portable.h" #ifdef HAVE_NT_SERVICE_MANAGER #include #include #include #include #include #include #include "ldap_pvt_thread.h" #include "ldap_defaults.h" #include "slapdmsg.h" #define SCM_NOTIFICATION_INTERVAL 5000 #define THIRTY_SECONDS (30 * 1000) int is_NT_Service; /* is this is an NT service? */ SERVICE_STATUS lutil_ServiceStatus; SERVICE_STATUS_HANDLE hlutil_ServiceStatus; ldap_pvt_thread_cond_t started_event, stopped_event; ldap_pvt_thread_t start_status_tid, stop_status_tid; void (*stopfunc)(int); static char *GetLastErrorString( void ); int lutil_srv_install(LPCTSTR lpszServiceName, LPCTSTR lpszDisplayName, LPCTSTR lpszBinaryPathName, int auto_start) { HKEY hKey; DWORD dwValue, dwDisposition; SC_HANDLE schSCManager, schService; char *sp = strrchr( lpszBinaryPathName, '\\'); if ( sp ) sp = strchr(sp, ' '); if ( sp ) *sp = '\0'; fprintf( stderr, "The install path is %s.\n", lpszBinaryPathName ); if ( sp ) *sp = ' '; if ((schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_CONNECT|SC_MANAGER_CREATE_SERVICE ) ) != NULL ) { if ((schService = CreateService( schSCManager, lpszServiceName, lpszDisplayName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, auto_start ? SERVICE_AUTO_START : SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, lpszBinaryPathName, NULL, NULL, NULL, NULL, NULL)) != NULL) { char regpath[132]; CloseServiceHandle(schService); CloseServiceHandle(schSCManager); snprintf( regpath, sizeof regpath, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s", lpszServiceName ); /* Create the registry key for event logging to the Windows NT event log. */ if ( RegCreateKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, "REG_SZ", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS) { fprintf( stderr, "RegCreateKeyEx() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() ); RegCloseKey(hKey); return(0); } if ( sp ) *sp = '\0'; if ( RegSetValueEx(hKey, "EventMessageFile", 0, REG_EXPAND_SZ, lpszBinaryPathName, strlen(lpszBinaryPathName) + 1) != ERROR_SUCCESS) { fprintf( stderr, "RegSetValueEx(EventMessageFile) failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() ); RegCloseKey(hKey); return(0); } dwValue = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; if ( RegSetValueEx(hKey, "TypesSupported", 0, REG_DWORD, (LPBYTE) &dwValue, sizeof(DWORD)) != ERROR_SUCCESS) { fprintf( stderr, "RegCreateKeyEx(TypesSupported) failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() ); RegCloseKey(hKey); return(0); } RegCloseKey(hKey); return(1); } else { fprintf( stderr, "CreateService() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() ); CloseServiceHandle(schSCManager); return(0); } } else fprintf( stderr, "OpenSCManager() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() ); return(0); } int lutil_srv_remove(LPCTSTR lpszServiceName, LPCTSTR lpszBinaryPathName) { SC_HANDLE schSCManager, schService; fprintf( stderr, "The installed path is %s.\n", lpszBinaryPathName ); if ((schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT|SC_MANAGER_CREATE_SERVICE)) != NULL ) { if ((schService = OpenService(schSCManager, lpszServiceName, DELETE)) != NULL) { if ( DeleteService(schService) == TRUE) { CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return(1); } else { fprintf( stderr, "DeleteService() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() ); fprintf( stderr, "The %s service has not been removed.\n", lpszBinaryPathName); CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return(0); } } else { fprintf( stderr, "OpenService() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() ); CloseServiceHandle(schSCManager); return(0); } } else fprintf( stderr, "OpenSCManager() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() ); return(0); } #if 0 /* unused */ DWORD svc_installed (LPTSTR lpszServiceName, LPTSTR lpszBinaryPathName) { char buf[256]; HKEY key; DWORD rc; DWORD type; long len; strcpy(buf, TEXT("SYSTEM\\CurrentControlSet\\Services\\")); strcat(buf, lpszServiceName); if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) return(-1); rc = 0; if (lpszBinaryPathName) { len = sizeof(buf); if (RegQueryValueEx(key, "ImagePath", NULL, &type, buf, &len) == ERROR_SUCCESS) { if (strcmp(lpszBinaryPathName, buf)) rc = -1; } } RegCloseKey(key); return(rc); } DWORD svc_running (LPTSTR lpszServiceName) { SC_HANDLE service; SC_HANDLE scm; DWORD rc; SERVICE_STATUS ss; if (!(scm = OpenSCManager(NULL, NULL, GENERIC_READ))) return(GetLastError()); rc = 1; service = OpenService(scm, lpszServiceName, SERVICE_QUERY_STATUS); if (service) { if (!QueryServiceStatus(service, &ss)) rc = GetLastError(); else if (ss.dwCurrentState != SERVICE_STOPPED) rc = 0; CloseServiceHandle(service); } CloseServiceHandle(scm); return(rc); } #endif static void *start_status_routine( void *ptr ) { DWORD wait_result; int done = 0; while ( !done ) { wait_result = WaitForSingleObject( started_event, SCM_NOTIFICATION_INTERVAL ); switch ( wait_result ) { case WAIT_ABANDONED: case WAIT_OBJECT_0: /* the object that we were waiting for has been destroyed (ABANDONED) or * signalled (TIMEOUT_0). We can assume that the startup process is * complete and tell the Service Control Manager that we are now runnng */ lutil_ServiceStatus.dwCurrentState = SERVICE_RUNNING; lutil_ServiceStatus.dwWin32ExitCode = NO_ERROR; lutil_ServiceStatus.dwCheckPoint++; lutil_ServiceStatus.dwWaitHint = 1000; SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus); done = 1; break; case WAIT_TIMEOUT: /* We've waited for the required time, so send an update to the Service Control * Manager saying to wait again. */ lutil_ServiceStatus.dwCheckPoint++; lutil_ServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL * 2; SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus); break; case WAIT_FAILED: /* there's been some problem with WaitForSingleObject so tell the Service * Control Manager to wait 30 seconds before deploying its assassin and * then leave the thread. */ lutil_ServiceStatus.dwCheckPoint++; lutil_ServiceStatus.dwWaitHint = THIRTY_SECONDS; SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus); done = 1; break; } } ldap_pvt_thread_exit(NULL); return NULL; } static void *stop_status_routine( void *ptr ) { DWORD wait_result; int done = 0; while ( !done ) { wait_result = WaitForSingleObject( stopped_event, SCM_NOTIFICATION_INTERVAL ); switch ( wait_result ) { case WAIT_ABANDONED: case WAIT_OBJECT_0: /* the object that we were waiting for has been destroyed (ABANDONED) or * signalled (TIMEOUT_0). The shutting down process is therefore complete * and the final SERVICE_STOPPED message will be sent to the service control * manager prior to the process terminating. */ done = 1; break; case WAIT_TIMEOUT: /* We've waited for the required time, so send an update to the Service Control * Manager saying to wait again. */ lutil_ServiceStatus.dwCheckPoint++; lutil_ServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL * 2; SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus); break; case WAIT_FAILED: /* there's been some problem with WaitForSingleObject so tell the Service * Control Manager to wait 30 seconds before deploying its assassin and * then leave the thread. */ lutil_ServiceStatus.dwCheckPoint++; lutil_ServiceStatus.dwWaitHint = THIRTY_SECONDS; SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus); done = 1; break; } } ldap_pvt_thread_exit(NULL); return NULL; } static void WINAPI lutil_ServiceCtrlHandler( IN DWORD Opcode) { switch (Opcode) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: lutil_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; lutil_ServiceStatus.dwCheckPoint++; lutil_ServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL * 2; SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus); ldap_pvt_thread_cond_init( &stopped_event ); if ( stopped_event == NULL ) { /* the event was not created. We will ask the service control manager for 30 * seconds to shutdown */ lutil_ServiceStatus.dwCheckPoint++; lutil_ServiceStatus.dwWaitHint = THIRTY_SECONDS; SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus); } else { /* start a thread to report the progress to the service control manager * until the stopped_event is fired. */ if ( ldap_pvt_thread_create( &stop_status_tid, 0, stop_status_routine, NULL ) == 0 ) { } else { /* failed to create the thread that tells the Service Control Manager that the * service stopping is proceeding. * tell the Service Control Manager to wait another 30 seconds before deploying its * assassin. */ lutil_ServiceStatus.dwCheckPoint++; lutil_ServiceStatus.dwWaitHint = THIRTY_SECONDS; SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus); } } stopfunc( -1 ); break; case SERVICE_CONTROL_INTERROGATE: SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus); break; } return; } void *lutil_getRegParam( char *svc, char *value ) { HKEY hkey; char path[255]; DWORD vType; static char vValue[1024]; DWORD valLen = sizeof( vValue ); if ( svc != NULL ) snprintf ( path, sizeof path, "SOFTWARE\\%s", svc ); else snprintf ( path, sizeof path, "SOFTWARE\\OpenLDAP\\Parameters" ); if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &hkey ) != ERROR_SUCCESS ) { return NULL; } if ( RegQueryValueEx( hkey, value, NULL, &vType, vValue, &valLen ) != ERROR_SUCCESS ) { RegCloseKey( hkey ); return NULL; } RegCloseKey( hkey ); switch ( vType ) { case REG_BINARY: case REG_DWORD: return (void*)&vValue; case REG_SZ: return (void*)&vValue; } return (void*)NULL; } void lutil_LogStartedEvent( char *svc, int slap_debug, char *configfile, char *urls ) { char *Inserts[5]; WORD i = 0, j; HANDLE hEventLog; hEventLog = RegisterEventSource( NULL, svc ); Inserts[i] = (char *)malloc( 20 ); itoa( slap_debug, Inserts[i++], 10 ); Inserts[i++] = strdup( configfile ); Inserts[i++] = strdup( urls ? urls : "ldap:///" ); ReportEvent( hEventLog, EVENTLOG_INFORMATION_TYPE, 0, MSG_SVC_STARTED, NULL, i, 0, (LPCSTR *) Inserts, NULL ); for ( j = 0; j < i; j++ ) ldap_memfree( Inserts[j] ); DeregisterEventSource( hEventLog ); } void lutil_LogStoppedEvent( char *svc ) { HANDLE hEventLog; hEventLog = RegisterEventSource( NULL, svc ); ReportEvent( hEventLog, EVENTLOG_INFORMATION_TYPE, 0, MSG_SVC_STOPPED, NULL, 0, 0, NULL, NULL ); DeregisterEventSource( hEventLog ); } void lutil_CommenceStartupProcessing( char *lpszServiceName, void (*stopper)(int) ) { hlutil_ServiceStatus = RegisterServiceCtrlHandler( lpszServiceName, (LPHANDLER_FUNCTION)lutil_ServiceCtrlHandler); stopfunc = stopper; /* initialize the Service Status structure */ lutil_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; lutil_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; lutil_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; lutil_ServiceStatus.dwWin32ExitCode = NO_ERROR; lutil_ServiceStatus.dwServiceSpecificExitCode = 0; lutil_ServiceStatus.dwCheckPoint = 1; lutil_ServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL * 2; SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus); /* start up a thread to keep sending SERVICE_START_PENDING to the Service Control Manager * until the slapd listener is completed and listening. Only then should we send * SERVICE_RUNNING to the Service Control Manager. */ ldap_pvt_thread_cond_init( &started_event ); if ( started_event == NULL) { /* failed to create the event to determine when the startup process is complete so * tell the Service Control Manager to wait another 30 seconds before deploying its * assassin */ lutil_ServiceStatus.dwCheckPoint++; lutil_ServiceStatus.dwWaitHint = THIRTY_SECONDS; SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus); } else { /* start a thread to report the progress to the service control manager * until the started_event is fired. */ if ( ldap_pvt_thread_create( &start_status_tid, 0, start_status_routine, NULL ) == 0 ) { } else { /* failed to create the thread that tells the Service Control Manager that the * service startup is proceeding. * tell the Service Control Manager to wait another 30 seconds before deploying its * assassin. */ lutil_ServiceStatus.dwCheckPoint++; lutil_ServiceStatus.dwWaitHint = THIRTY_SECONDS; SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus); } } } void lutil_ReportShutdownComplete( ) { if ( is_NT_Service ) { /* stop sending SERVICE_STOP_PENDING messages to the Service Control Manager */ ldap_pvt_thread_cond_signal( &stopped_event ); ldap_pvt_thread_cond_destroy( &stopped_event ); /* wait for the thread sending the SERVICE_STOP_PENDING messages to the Service Control Manager to die. * if the wait fails then put ourselves to sleep for half the Service Control Manager update interval */ if (ldap_pvt_thread_join( stop_status_tid, (void *) NULL ) == -1) ldap_pvt_thread_sleep( SCM_NOTIFICATION_INTERVAL / 2 ); lutil_ServiceStatus.dwCurrentState = SERVICE_STOPPED; lutil_ServiceStatus.dwCheckPoint++; lutil_ServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL; SetServiceStatus(hlutil_ServiceStatus, &lutil_ServiceStatus); } } static char *GetErrorString( int err ) { static char msgBuf[1024]; FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), msgBuf, 1024, NULL ); return msgBuf; } static char *GetLastErrorString( void ) { return GetErrorString( GetLastError() ); } #endif openldap-2.5.11+dfsg/libraries/liblutil/lockf.c0000644000175000017500000000464114172327167020102 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* * File Locking Routines * * Implementations (in order of preference) * - lockf * - fcntl * - flock * * Other implementations will be added as needed. * * NOTE: lutil_lockf() MUST block until an exclusive lock is acquired. */ #include "portable.h" #include #include #undef LOCK_API #if defined(HAVE_LOCKF) && defined(F_LOCK) # define USE_LOCKF 1 # define LOCK_API "lockf" #endif #if !defined(LOCK_API) && defined(HAVE_FCNTL) # ifdef HAVE_FCNTL_H # include # endif # ifdef F_WRLCK # define USE_FCNTL 1 # define LOCK_API "fcntl" # endif #endif #if !defined(LOCK_API) && defined(HAVE_FLOCK) # ifdef HAVE_SYS_FILE_H # include # endif # define USE_FLOCK 1 # define LOCK_API "flock" #endif #if !defined(USE_LOCKF) && !defined(USE_FCNTL) && !defined(USE_FLOCK) int lutil_lockf ( int fd ) { fd = fd; return 0; } int lutil_unlockf ( int fd ) { fd = fd; return 0; } #endif #ifdef USE_LOCKF int lutil_lockf ( int fd ) { /* use F_LOCK instead of F_TLOCK, ie: block */ return lockf( fd, F_LOCK, 0 ); } int lutil_unlockf ( int fd ) { return lockf( fd, F_ULOCK, 0 ); } #endif #ifdef USE_FCNTL int lutil_lockf ( int fd ) { struct flock file_lock; memset( &file_lock, '\0', sizeof( file_lock ) ); file_lock.l_type = F_WRLCK; file_lock.l_whence = SEEK_SET; file_lock.l_start = 0; file_lock.l_len = 0; /* use F_SETLKW instead of F_SETLK, ie: block */ return( fcntl( fd, F_SETLKW, &file_lock ) ); } int lutil_unlockf ( int fd ) { struct flock file_lock; memset( &file_lock, '\0', sizeof( file_lock ) ); file_lock.l_type = F_UNLCK; file_lock.l_whence = SEEK_SET; file_lock.l_start = 0; file_lock.l_len = 0; return( fcntl ( fd, F_SETLKW, &file_lock ) ); } #endif #ifdef USE_FLOCK int lutil_lockf ( int fd ) { /* use LOCK_EX instead of LOCK_EX|LOCK_NB, ie: block */ return flock( fd, LOCK_EX ); } int lutil_unlockf ( int fd ) { return flock( fd, LOCK_UN ); } #endif openldap-2.5.11+dfsg/libraries/liblutil/base64.c0000644000175000017500000002311514172327167020065 0ustar ryanryan/* base64.c -- routines to encode/decode base64 data */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * Portions Copyright 1998-2003 Kurt D. Zeilenga. * Portions Copyright 1995 IBM Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1996, 1998 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* This work is based upon Base64 routines (developed by IBM) found * Berkeley Internet Name Daemon (BIND) as distributed by ISC. They * were adapted for inclusion in OpenLDAP Software by Kurt D. Zeilenga. */ #include "portable.h" #include #include #include #include /* include socket.h to get sys/types.h and/or winsock2.h */ #include #include "lutil.h" static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) The following encoding technique is taken from RFC 1521 by Borenstein and Freed. It is reproduced here in a slightly edited form for convenience. A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable character. (The extra 65th character, "=", is used to signify a special processing function.) The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which is translated into a single digit in the base64 alphabet. Each 6-bit group is used as an index into an array of 64 printable characters. The character referenced by the index is placed in the output string. Table 1: The Base64 Alphabet Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y Special processing is performed if fewer than 24 bits are available at the end of the data being encoded. A full encoding quantum is always completed at the end of a quantity. When fewer than 24 input bits are available in an input group, zero bits are added (on the right) to form an integral number of 6-bit groups. Padding at the end of the data is performed using the '=' character. Since all base64 input is an integral number of octets, only the ------------------------------------------------- following cases can arise: (1) the final quantum of encoding input is an integral multiple of 24 bits; here, the final unit of encoded output will be an integral multiple of 4 characters with no "=" padding, (2) the final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by two "=" padding characters, or (3) the final quantum of encoding input is exactly 16 bits; here, the final unit of encoded output will be three characters followed by one "=" padding character. */ int lutil_b64_ntop( u_char const *src, size_t srclength, char *target, size_t targsize) { size_t datalength = 0; u_char input[3]; u_char output[4]; size_t i; while (2 < srclength) { input[0] = *src++; input[1] = *src++; input[2] = *src++; srclength -= 3; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); output[3] = input[2] & 0x3f; assert(output[0] < 64); assert(output[1] < 64); assert(output[2] < 64); assert(output[3] < 64); if (datalength + 4 > targsize) return (-1); target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; target[datalength++] = Base64[output[2]]; target[datalength++] = Base64[output[3]]; } /* Now we worry about padding. */ if (0 != srclength) { /* Get what's left. */ input[0] = input[1] = input[2] = '\0'; for (i = 0; i < srclength; i++) input[i] = *src++; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); assert(output[0] < 64); assert(output[1] < 64); assert(output[2] < 64); if (datalength + 4 > targsize) return (-1); target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; if (srclength == 1) target[datalength++] = Pad64; else target[datalength++] = Base64[output[2]]; target[datalength++] = Pad64; } if (datalength >= targsize) return (-1); target[datalength] = '\0'; /* Returned value doesn't count \0. */ return (datalength); } /* skips all whitespace anywhere. converts characters, four at a time, starting at (or after) src from base - 64 numbers into three 8 bit bytes in the target area. it returns the number of data bytes stored at the target, or -1 on error. */ int lutil_b64_pton( char const *src, u_char *target, size_t targsize) { int tarindex, state, ch; char *pos; state = 0; tarindex = 0; while ((ch = *src++) != '\0') { if (isascii(ch) && isspace(ch)) /* Skip whitespace anywhere. */ continue; if (ch == Pad64) break; pos = strchr(Base64, ch); if (pos == 0) /* A non-base64 character. */ return (-1); switch (state) { case 0: if (target) { if ((size_t)tarindex >= targsize) return (-1); target[tarindex] = (pos - Base64) << 2; } state = 1; break; case 1: if (target) { if ((size_t)tarindex + 1 >= targsize) return (-1); target[tarindex] |= (pos - Base64) >> 4; target[tarindex+1] = ((pos - Base64) & 0x0f) << 4 ; } tarindex++; state = 2; break; case 2: if (target) { if ((size_t)tarindex + 1 >= targsize) return (-1); target[tarindex] |= (pos - Base64) >> 2; target[tarindex+1] = ((pos - Base64) & 0x03) << 6; } tarindex++; state = 3; break; case 3: if (target) { if ((size_t)tarindex >= targsize) return (-1); target[tarindex] |= (pos - Base64); } tarindex++; state = 0; break; default: abort(); } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = *src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for ((void)NULL; ch != '\0'; ch = *src++) if (! (isascii(ch) && isspace(ch))) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = *src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for ((void)NULL; ch != '\0'; ch = *src++) if (! (isascii(ch) && isspace(ch))) return (-1); /* * Now make sure for cases 2 and 3 that the "extra" * bits that slopped past the last full byte were * zeros. If we don't check them, they become a * subliminal channel. */ if (target && target[tarindex] != 0) return (-1); } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } openldap-2.5.11+dfsg/libraries/liblutil/sasl.c0000644000175000017500000001147314172327167017747 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #ifdef HAVE_CYRUS_SASL #include #include #include #include #ifdef HAVE_SASL_SASL_H #include #else #include #endif #include #include "ldap_pvt.h" #include "lutil_ldap.h" typedef struct lutil_sasl_defaults_s { char *mech; char *realm; char *authcid; char *passwd; char *authzid; char **resps; int nresps; } lutilSASLdefaults; void lutil_sasl_freedefs( void *defaults ) { lutilSASLdefaults *defs = defaults; assert( defs != NULL ); if (defs->mech) ber_memfree(defs->mech); if (defs->realm) ber_memfree(defs->realm); if (defs->authcid) ber_memfree(defs->authcid); if (defs->passwd) ber_memfree(defs->passwd); if (defs->authzid) ber_memfree(defs->authzid); if (defs->resps) ldap_charray_free(defs->resps); ber_memfree(defs); } void * lutil_sasl_defaults( LDAP *ld, char *mech, char *realm, char *authcid, char *passwd, char *authzid ) { lutilSASLdefaults *defaults; defaults = ber_memalloc( sizeof( lutilSASLdefaults ) ); if( defaults == NULL ) return NULL; defaults->mech = mech ? ber_strdup(mech) : NULL; defaults->realm = realm ? ber_strdup(realm) : NULL; defaults->authcid = authcid ? ber_strdup(authcid) : NULL; defaults->passwd = passwd ? ber_strdup(passwd) : NULL; defaults->authzid = authzid ? ber_strdup(authzid) : NULL; if( defaults->mech == NULL ) { ldap_get_option( ld, LDAP_OPT_X_SASL_MECH, &defaults->mech ); } if( defaults->realm == NULL ) { ldap_get_option( ld, LDAP_OPT_X_SASL_REALM, &defaults->realm ); } if( defaults->authcid == NULL ) { ldap_get_option( ld, LDAP_OPT_X_SASL_AUTHCID, &defaults->authcid ); } if( defaults->authzid == NULL ) { ldap_get_option( ld, LDAP_OPT_X_SASL_AUTHZID, &defaults->authzid ); } defaults->resps = NULL; defaults->nresps = 0; return defaults; } static int interaction( unsigned flags, sasl_interact_t *interact, lutilSASLdefaults *defaults ) { const char *dflt = interact->defresult; char input[1024]; int noecho=0; int challenge=0; switch( interact->id ) { case SASL_CB_GETREALM: if( defaults ) dflt = defaults->realm; break; case SASL_CB_AUTHNAME: if( defaults ) dflt = defaults->authcid; break; case SASL_CB_PASS: if( defaults ) dflt = defaults->passwd; noecho = 1; break; case SASL_CB_USER: if( defaults ) dflt = defaults->authzid; break; case SASL_CB_NOECHOPROMPT: noecho = 1; challenge = 1; break; case SASL_CB_ECHOPROMPT: challenge = 1; break; } if( dflt && !*dflt ) dflt = NULL; if( flags != LDAP_SASL_INTERACTIVE && ( dflt || interact->id == SASL_CB_USER ) ) { goto use_default; } if( flags == LDAP_SASL_QUIET ) { /* don't prompt */ return LDAP_OTHER; } if( challenge ) { if( interact->challenge ) { fprintf( stderr, _("Challenge: %s\n"), interact->challenge ); } } if( dflt ) { fprintf( stderr, _("Default: %s\n"), dflt ); } snprintf( input, sizeof input, "%s: ", interact->prompt ? interact->prompt : _("Interact") ); if( noecho ) { interact->result = (char *) getpassphrase( input ); interact->len = interact->result ? strlen( interact->result ) : 0; } else { /* prompt user */ fputs( input, stderr ); /* get input */ interact->result = fgets( input, sizeof(input), stdin ); if( interact->result == NULL ) { interact->len = 0; return LDAP_UNAVAILABLE; } /* len of input */ interact->len = strlen(input); if( interact->len > 0 && input[interact->len - 1] == '\n' ) { /* input includes '\n', trim it */ interact->len--; input[interact->len] = '\0'; } } if( interact->len > 0 ) { /* duplicate */ char *p = (char *)interact->result; ldap_charray_add(&defaults->resps, interact->result); interact->result = defaults->resps[defaults->nresps++]; /* zap */ memset( p, '\0', interact->len ); } else { use_default: /* input must be empty */ interact->result = (dflt && *dflt) ? dflt : ""; interact->len = strlen( interact->result ); } return LDAP_SUCCESS; } int lutil_sasl_interact( LDAP *ld, unsigned flags, void *defaults, void *in ) { sasl_interact_t *interact = in; if( flags == LDAP_SASL_INTERACTIVE ) { fputs( _("SASL Interaction\n"), stderr ); } while( interact->id != SASL_CB_LIST_END ) { int rc = interaction( flags, interact, defaults ); if( rc ) return rc; interact++; } return LDAP_SUCCESS; } #endif openldap-2.5.11+dfsg/libraries/liblutil/slapdmsg.mc0000644000175000017500000000153414172327167020771 0ustar ryanryan;// ;// This file contains message strings for the OpenLDAP slapd service. ;// ;// This file should be compiled as follows ;// mc -v slapdmsg.mc -r $(IntDir) ;// rc /v /r $(IntDir)\slapdmsg.rc ;// The mc (message compiler) command generates the .rc and .h files from this file. The ;// rc (resource compiler) takes the .rc file and produces a .res file that can be linked ;// with the final executable application. The application is then registered as a message ;// source with by creating the appropriate entries in the system registry. ;// MessageID=0x500 Severity=Informational SymbolicName=MSG_SVC_STARTED Facility=Application Language=English OpenLDAP service started. debuglevel=%1, conffile=%2, urls=%3 . MessageID=0x501 Severity=Informational SymbolicName=MSG_SVC_STOPPED Facility=Application Language=English OpenLDAP service stopped. . openldap-2.5.11+dfsg/libraries/liblutil/slapdmsg.rc0000644000175000017500000000004314172327167020770 0ustar ryanryanLANGUAGE 0x9,0x1 1 11 slapdmsg.bin openldap-2.5.11+dfsg/libraries/liblutil/sha1.c0000644000175000017500000002005414172327167017634 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* This work was derived from code developed by Steve Reid and * adapted for use in OpenLDAP by Kurt D. Zeilenga. */ /* Acquired from: * $OpenBSD: sha1.c,v 1.9 1997/07/23 21:12:32 kstailey Exp $ */ /* * SHA-1 in C * By Steve Reid * 100% Public Domain * * Test Vectors (from FIPS PUB 180-1) * "abc" * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 * A million repetitions of "a" * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F */ /* * This code assumes uint32 is 32 bits and char is 8 bits */ #include "portable.h" #include #include #include #include #include "lutil_sha1.h" #ifdef LUTIL_SHA1_BYTES /* undefining this will cause pointer alignment errors */ #define SHA1HANDSOFF /* Copies data before messing with it. */ #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /* * blk0() and blk() perform the initial expand. * I got the idea of expanding during the round function from SSLeay */ #if BYTE_ORDER == LITTLE_ENDIAN # define blk0(i) (block[i] = (rol(block[i],24)&0xFF00FF00) \ |(rol(block[i],8)&0x00FF00FF)) #else # define blk0(i) block[i] #endif #define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \ ^block[(i+2)&15]^block[i&15],1)) /* * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1 */ #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); /* * Hash a single 512-bit block. This is the core of the algorithm. */ void lutil_SHA1Transform( uint32 *state, const unsigned char *buffer ) { uint32 a, b, c, d, e; #ifdef SHA1HANDSOFF uint32 block[16]; (void)AC_MEMCPY(block, buffer, 64); #else uint32 *block = (u_int32 *) buffer; #endif /* Copy context->state[] to working vars */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; /* 4 rounds of 20 operations each. Loop unrolled. */ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; /* Wipe variables */ a = b = c = d = e = 0; } /* * lutil_SHA1Init - Initialize new context */ void lutil_SHA1Init( lutil_SHA1_CTX *context ) { /* SHA1 initialization constants */ context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; context->state[4] = 0xC3D2E1F0; context->count[0] = context->count[1] = 0; } /* * Run your data through this. */ void lutil_SHA1Update( lutil_SHA1_CTX *context, const unsigned char *data, uint32 len ) { u_int i, j; j = context->count[0]; if ((context->count[0] += len << 3) < j) context->count[1] += (len>>29)+1; j = (j >> 3) & 63; if ((j + len) > 63) { (void)AC_MEMCPY(&context->buffer[j], data, (i = 64-j)); lutil_SHA1Transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64) lutil_SHA1Transform(context->state, &data[i]); j = 0; } else { i = 0; } (void)AC_MEMCPY(&context->buffer[j], &data[i], len - i); } /* * Add padding and return the message digest. */ void lutil_SHA1Final( unsigned char *digest, lutil_SHA1_CTX *context ) { u_int i; unsigned char finalcount[8]; for (i = 0; i < 8; i++) { finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ } lutil_SHA1Update(context, (unsigned char *)"\200", 1); while ((context->count[0] & 504) != 448) lutil_SHA1Update(context, (unsigned char *)"\0", 1); lutil_SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ if (digest) { for (i = 0; i < 20; i++) digest[i] = (unsigned char) ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); } } /* sha1hl.c * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- */ #if defined(LIBC_SCCS) && !defined(lint) static char rcsid[] = "$OpenBSD: sha1hl.c,v 1.1 1997/07/12 20:06:03 millert Exp $"; #endif /* LIBC_SCCS and not lint */ #include #include #include #include #ifdef HAVE_SYS_FILE_H #include #endif #ifdef HAVE_IO_H #include #endif #ifdef HAVE_FCNTL_H #include #endif /* ARGSUSED */ char * lutil_SHA1End( lutil_SHA1_CTX *ctx, char *buf ) { int i; char *p = buf; unsigned char digest[20]; static const char hex[]="0123456789abcdef"; if (p == NULL && (p = malloc(41)) == NULL) return 0; lutil_SHA1Final(digest,ctx); for (i = 0; i < 20; i++) { p[i + i] = hex[digest[i] >> 4]; p[i + i + 1] = hex[digest[i] & 0x0f]; } p[i + i] = '\0'; return(p); } char * lutil_SHA1File( char *filename, char *buf ) { unsigned char buffer[BUFSIZ]; lutil_SHA1_CTX ctx; int fd, num, oerrno; lutil_SHA1Init(&ctx); if ((fd = open(filename,O_RDONLY)) < 0) return(0); while ((num = read(fd, buffer, sizeof(buffer))) > 0) lutil_SHA1Update(&ctx, buffer, num); oerrno = errno; close(fd); errno = oerrno; return(num < 0 ? 0 : lutil_SHA1End(&ctx, buf)); } char * lutil_SHA1Data( const unsigned char *data, size_t len, char *buf ) { lutil_SHA1_CTX ctx; lutil_SHA1Init(&ctx); lutil_SHA1Update(&ctx, data, len); return(lutil_SHA1End(&ctx, buf)); } #endif openldap-2.5.11+dfsg/libraries/libldap/0000755000175000017500000000000014172327167016422 5ustar ryanryanopenldap-2.5.11+dfsg/libraries/libldap/free.c0000644000175000017500000000373514172327167017517 0ustar ryanryan/* free.c */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1994 The Regents of the University of Michigan. * All rights reserved. */ /* * free.c - some free routines are included here to avoid having to * link in lots of extra code when not using certain features */ #include "portable.h" #include #include #include #include #include "ldap-int.h" /* * C-API deallocator */ void ldap_memfree( void *p ) { LDAP_FREE( p ); } void ldap_memvfree( void **v ) { LDAP_VFREE( v ); } void * ldap_memalloc( ber_len_t s ) { return LDAP_MALLOC( s ); } void * ldap_memcalloc( ber_len_t n, ber_len_t s ) { return LDAP_CALLOC( n, s ); } void * ldap_memrealloc( void* p, ber_len_t s ) { return LDAP_REALLOC( p, s ); } char * ldap_strdup( LDAP_CONST char *p ) { return LDAP_STRDUP( p ); } /* * free a null-terminated array of pointers to mod structures. the * structures are freed, not the array itself, unless the freemods * flag is set. */ void ldap_mods_free( LDAPMod **mods, int freemods ) { int i; if ( mods == NULL ) return; for ( i = 0; mods[i] != NULL; i++ ) { if ( mods[i]->mod_op & LDAP_MOD_BVALUES ) { if( mods[i]->mod_bvalues != NULL ) ber_bvecfree( mods[i]->mod_bvalues ); } else if( mods[i]->mod_values != NULL ) { LDAP_VFREE( mods[i]->mod_values ); } if ( mods[i]->mod_type != NULL ) { LDAP_FREE( mods[i]->mod_type ); } LDAP_FREE( (char *) mods[i] ); } if ( freemods ) { LDAP_FREE( (char *) mods ); } } openldap-2.5.11+dfsg/libraries/libldap/utf-8-conv.c0000644000175000017500000003220614172327167020477 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved. * * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. *--- * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License * can be found in the file "build/LICENSE-2.0.1" in this distribution * of OpenLDAP Software. */ /* * UTF-8 Conversion Routines * * These routines convert between Wide Character and UTF-8, * or between MultiByte and UTF-8 encodings. * * Both single character and string versions of the functions are provided. * All functions return -1 if the character or string cannot be converted. */ #include "portable.h" #if SIZEOF_WCHAR_T >= 4 /* These routines assume ( sizeof(wchar_t) >= 4 ) */ #include #include /* For wctomb, wcstombs, mbtowc, mbstowcs */ #include #include /* for time_t */ #include "ldap-int.h" #include static unsigned char mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; /*----------------------------------------------------------------------------- UTF-8 Format Summary ASCII chars 7 bits 0xxxxxxx 2-character UTF-8 sequence: 11 bits 110xxxxx 10xxxxxx 3-character UTF-8 16 bits 1110xxxx 10xxxxxx 10xxxxxx 4-char UTF-8 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 5-char UTF-8 26 bits 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 6-char UTF-8 31 bits 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx Unicode address space (0 - 0x10FFFF) 21 bits ISO-10646 address space (0 - 0x7FFFFFFF) 31 bits Note: This code does not prevent UTF-8 sequences which are longer than necessary from being decoded. */ /*----------------------------------------------------------------------------- Convert a UTF-8 character to a wide char. Return the length of the UTF-8 input character in bytes. */ int ldap_x_utf8_to_wc ( wchar_t *wchar, const char *utf8char ) { int utflen, i; wchar_t ch; if (utf8char == NULL) return -1; /* Get UTF-8 sequence length from 1st byte */ utflen = LDAP_UTF8_CHARLEN2(utf8char, utflen); if( utflen==0 || utflen > (int)LDAP_MAX_UTF8_LEN ) return -1; /* First byte minus length tag */ ch = (wchar_t)(utf8char[0] & mask[utflen]); for(i=1; i < utflen; i++) { /* Subsequent bytes must start with 10 */ if ((utf8char[i] & 0xc0) != 0x80) return -1; ch <<= 6; /* 6 bits of data in each subsequent byte */ ch |= (wchar_t)(utf8char[i] & 0x3f); } if (wchar) *wchar = ch; return utflen; } /*----------------------------------------------------------------------------- Convert a UTF-8 string to a wide char string. No more than 'count' wide chars will be written to the output buffer. Return the size of the converted string in wide chars, excl null terminator. */ int ldap_x_utf8s_to_wcs ( wchar_t *wcstr, const char *utf8str, size_t count ) { size_t wclen = 0; int utflen, i; wchar_t ch; /* If input ptr is NULL or empty... */ if (utf8str == NULL || !*utf8str) { if ( wcstr ) *wcstr = 0; return 0; } /* Examine next UTF-8 character. If output buffer is NULL, ignore count */ while ( *utf8str && (wcstr==NULL || wclen (int)LDAP_MAX_UTF8_LEN ) return -1; /* First byte minus length tag */ ch = (wchar_t)(utf8str[0] & mask[utflen]); for(i=1; i < utflen; i++) { /* Subsequent bytes must start with 10 */ if ((utf8str[i] & 0xc0) != 0x80) return -1; ch <<= 6; /* 6 bits of data in each subsequent byte */ ch |= (wchar_t)(utf8str[i] & 0x3f); } if (wcstr) wcstr[wclen] = ch; utf8str += utflen; /* Move to next UTF-8 character */ wclen++; /* Count number of wide chars stored/required */ } /* Add null terminator if there's room in the buffer. */ if (wcstr && wclen < count) wcstr[wclen] = 0; return wclen; } /*----------------------------------------------------------------------------- Convert one wide char to a UTF-8 character. Return the length of the converted UTF-8 character in bytes. No more than 'count' bytes will be written to the output buffer. */ int ldap_x_wc_to_utf8 ( char *utf8char, wchar_t wchar, size_t count ) { int len=0; if (utf8char == NULL) /* Just determine the required UTF-8 char length. */ { /* Ignore count */ if( wchar < 0 ) return -1; if( wchar < 0x80 ) return 1; if( wchar < 0x800 ) return 2; if( wchar < 0x10000 ) return 3; if( wchar < 0x200000 ) return 4; if( wchar < 0x4000000 ) return 5; #if SIZEOF_WCHAR_T > 4 /* UL is not strictly needed by ANSI C */ if( wchar < (wchar_t)0x80000000UL ) #endif /* SIZEOF_WCHAR_T > 4 */ return 6; return -1; } if ( wchar < 0 ) { /* Invalid wide character */ len = -1; } else if( wchar < 0x80 ) { if (count >= 1) { utf8char[len++] = (char)wchar; } } else if( wchar < 0x800 ) { if (count >=2) { utf8char[len++] = 0xc0 | ( wchar >> 6 ); utf8char[len++] = 0x80 | ( wchar & 0x3f ); } } else if( wchar < 0x10000 ) { if (count >= 3) { utf8char[len++] = 0xe0 | ( wchar >> 12 ); utf8char[len++] = 0x80 | ( (wchar >> 6) & 0x3f ); utf8char[len++] = 0x80 | ( wchar & 0x3f ); } } else if( wchar < 0x200000 ) { if (count >= 4) { utf8char[len++] = 0xf0 | ( wchar >> 18 ); utf8char[len++] = 0x80 | ( (wchar >> 12) & 0x3f ); utf8char[len++] = 0x80 | ( (wchar >> 6) & 0x3f ); utf8char[len++] = 0x80 | ( wchar & 0x3f ); } } else if( wchar < 0x4000000 ) { if (count >= 5) { utf8char[len++] = 0xf8 | ( wchar >> 24 ); utf8char[len++] = 0x80 | ( (wchar >> 18) & 0x3f ); utf8char[len++] = 0x80 | ( (wchar >> 12) & 0x3f ); utf8char[len++] = 0x80 | ( (wchar >> 6) & 0x3f ); utf8char[len++] = 0x80 | ( wchar & 0x3f ); } } else #if SIZEOF_WCHAR_T > 4 /* UL is not strictly needed by ANSI C */ if( wchar < (wchar_t)0x80000000UL ) #endif /* SIZEOF_WCHAR_T > 4 */ { if (count >= 6) { utf8char[len++] = 0xfc | ( wchar >> 30 ); utf8char[len++] = 0x80 | ( (wchar >> 24) & 0x3f ); utf8char[len++] = 0x80 | ( (wchar >> 18) & 0x3f ); utf8char[len++] = 0x80 | ( (wchar >> 12) & 0x3f ); utf8char[len++] = 0x80 | ( (wchar >> 6) & 0x3f ); utf8char[len++] = 0x80 | ( wchar & 0x3f ); } #if SIZEOF_WCHAR_T > 4 } else { len = -1; #endif /* SIZEOF_WCHAR_T > 4 */ } return len; } /*----------------------------------------------------------------------------- Convert a wide char string to a UTF-8 string. No more than 'count' bytes will be written to the output buffer. Return the # of bytes written to the output buffer, excl null terminator. */ int ldap_x_wcs_to_utf8s ( char *utf8str, const wchar_t *wcstr, size_t count ) { int len = 0; int n; char *p = utf8str; wchar_t empty = 0; /* To avoid use of L"" construct */ if (wcstr == NULL) /* Treat input ptr NULL as an empty string */ wcstr = ∅ if (utf8str == NULL) /* Just compute size of output, excl null */ { while (*wcstr) { /* Get UTF-8 size of next wide char */ n = ldap_x_wc_to_utf8( NULL, *wcstr++, LDAP_MAX_UTF8_LEN); if (n == -1) return -1; len += n; } return len; } /* Do the actual conversion. */ n = 1; /* In case of empty wcstr */ while (*wcstr) { n = ldap_x_wc_to_utf8( p, *wcstr++, count); if (n <= 0) /* If encoding error (-1) or won't fit (0), quit */ break; p += n; count -= n; /* Space left in output buffer */ } /* If not enough room for last character, pad remainder with null so that return value = original count, indicating buffer full. */ if (n == 0) { while (count--) *p++ = 0; } /* Add a null terminator if there's room. */ else if (count) *p = 0; if (n == -1) /* Conversion encountered invalid wide char. */ return -1; /* Return the number of bytes written to output buffer, excl null. */ return (p - utf8str); } #ifdef ANDROID int wctomb(char *s, wchar_t wc) { return wcrtomb(s,wc,NULL); } int mbtowc(wchar_t *pwc, const char *s, size_t n) { return mbrtowc(pwc, s, n, NULL); } #endif /*----------------------------------------------------------------------------- Convert a UTF-8 character to a MultiByte character. Return the size of the converted character in bytes. */ int ldap_x_utf8_to_mb ( char *mbchar, const char *utf8char, int (*f_wctomb)(char *mbchar, wchar_t wchar) ) { wchar_t wchar; int n; char tmp[6]; /* Large enough for biggest multibyte char */ if (f_wctomb == NULL) /* If no conversion function was given... */ f_wctomb = wctomb; /* use the local ANSI C function */ /* First convert UTF-8 char to a wide char */ n = ldap_x_utf8_to_wc( &wchar, utf8char); if (n == -1) return -1; /* Invalid UTF-8 character */ if (mbchar == NULL) n = f_wctomb( tmp, wchar ); else n = f_wctomb( mbchar, wchar); return n; } /*----------------------------------------------------------------------------- Convert a UTF-8 string to a MultiByte string. No more than 'count' bytes will be written to the output buffer. Return the size of the converted string in bytes, excl null terminator. */ int ldap_x_utf8s_to_mbs ( char *mbstr, const char *utf8str, size_t count, size_t (*f_wcstombs)(char *mbstr, const wchar_t *wcstr, size_t count) ) { wchar_t *wcs; size_t wcsize; int n; if (f_wcstombs == NULL) /* If no conversion function was given... */ f_wcstombs = wcstombs; /* use the local ANSI C function */ if (utf8str == NULL || *utf8str == 0) /* NULL or empty input string */ { if (mbstr) *mbstr = 0; return 0; } /* Allocate memory for the maximum size wchar string that we could get. */ wcsize = strlen(utf8str) + 1; wcs = (wchar_t *)LDAP_MALLOC(wcsize * sizeof(wchar_t)); if (wcs == NULL) return -1; /* Memory allocation failure. */ /* First convert the UTF-8 string to a wide char string */ n = ldap_x_utf8s_to_wcs( wcs, utf8str, wcsize); /* Then convert wide char string to multi-byte string */ if (n != -1) { n = f_wcstombs(mbstr, wcs, count); } LDAP_FREE(wcs); return n; } /*----------------------------------------------------------------------------- Convert a MultiByte character to a UTF-8 character. 'mbsize' indicates the number of bytes of 'mbchar' to check. Returns the number of bytes written to the output character. */ int ldap_x_mb_to_utf8 ( char *utf8char, const char *mbchar, size_t mbsize, int (*f_mbtowc)(wchar_t *wchar, const char *mbchar, size_t count) ) { wchar_t wchar; int n; if (f_mbtowc == NULL) /* If no conversion function was given... */ f_mbtowc = mbtowc; /* use the local ANSI C function */ if (mbsize == 0) /* 0 is not valid. */ return -1; if (mbchar == NULL || *mbchar == 0) { if (utf8char) *utf8char = 0; return 1; } /* First convert the MB char to a Wide Char */ n = f_mbtowc( &wchar, mbchar, mbsize); if (n == -1) return -1; /* Convert the Wide Char to a UTF-8 character. */ n = ldap_x_wc_to_utf8( utf8char, wchar, LDAP_MAX_UTF8_LEN); return n; } /*----------------------------------------------------------------------------- Convert a MultiByte string to a UTF-8 string. No more than 'count' bytes will be written to the output buffer. Return the size of the converted string in bytes, excl null terminator. */ int ldap_x_mbs_to_utf8s ( char *utf8str, const char *mbstr, size_t count, size_t (*f_mbstowcs)(wchar_t *wcstr, const char *mbstr, size_t count) ) { wchar_t *wcs; int n; size_t wcsize; if (mbstr == NULL) /* Treat NULL input string as an empty string */ mbstr = ""; if (f_mbstowcs == NULL) /* If no conversion function was given... */ f_mbstowcs = mbstowcs; /* use the local ANSI C function */ /* Allocate memory for the maximum size wchar string that we could get. */ wcsize = strlen(mbstr) + 1; wcs = (wchar_t *)LDAP_MALLOC( wcsize * sizeof(wchar_t) ); if (wcs == NULL) return -1; /* First convert multi-byte string to a wide char string */ n = f_mbstowcs(wcs, mbstr, wcsize); /* Convert wide char string to UTF-8 string */ if (n != -1) { n = ldap_x_wcs_to_utf8s( utf8str, wcs, count); } LDAP_FREE(wcs); return n; } #endif /* SIZEOF_WCHAR_T >= 4 */ openldap-2.5.11+dfsg/libraries/libldap/getattr.c0000644000175000017500000000653014172327167020244 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" char * ldap_first_attribute( LDAP *ld, LDAPMessage *entry, BerElement **berout ) { int rc; ber_tag_t tag; ber_len_t len = 0; char *attr; BerElement *ber; Debug0( LDAP_DEBUG_TRACE, "ldap_first_attribute\n" ); assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( entry != NULL ); assert( berout != NULL ); *berout = NULL; ber = ldap_alloc_ber_with_options( ld ); if( ber == NULL ) { return NULL; } *ber = *entry->lm_ber; /* * Skip past the sequence, dn, sequence of sequence leaving * us at the first attribute. */ tag = ber_scanf( ber, "{xl{" /*}}*/, &len ); if( tag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 0 ); return NULL; } /* set the length to avoid overrun */ rc = ber_set_option( ber, LBER_OPT_REMAINING_BYTES, &len ); if( rc != LBER_OPT_SUCCESS ) { ld->ld_errno = LDAP_LOCAL_ERROR; ber_free( ber, 0 ); return NULL; } if ( ber_pvt_ber_remaining( ber ) == 0 ) { assert( len == 0 ); ber_free( ber, 0 ); return NULL; } assert( len != 0 ); /* snatch the first attribute */ tag = ber_scanf( ber, "{ax}", &attr ); if( tag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 0 ); return NULL; } *berout = ber; return attr; } /* ARGSUSED */ char * ldap_next_attribute( LDAP *ld, LDAPMessage *entry, BerElement *ber ) { ber_tag_t tag; char *attr; Debug0( LDAP_DEBUG_TRACE, "ldap_next_attribute\n" ); assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( entry != NULL ); assert( ber != NULL ); if ( ber_pvt_ber_remaining( ber ) == 0 ) { return NULL; } /* skip sequence, snarf attribute type, skip values */ tag = ber_scanf( ber, "{ax}", &attr ); if( tag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; return NULL; } return attr; } /* Fetch attribute type and optionally fetch values. The type * and values are referenced in-place from the BerElement, they are * not dup'd into malloc'd memory. */ /* ARGSUSED */ int ldap_get_attribute_ber( LDAP *ld, LDAPMessage *entry, BerElement *ber, BerValue *attr, BerVarray *vals ) { ber_tag_t tag; int rc = LDAP_SUCCESS; Debug0( LDAP_DEBUG_TRACE, "ldap_get_attribute_ber\n" ); assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( entry != NULL ); assert( ber != NULL ); assert( attr != NULL ); attr->bv_val = NULL; attr->bv_len = 0; if ( ber_pvt_ber_remaining( ber ) ) { ber_len_t siz = sizeof( BerValue ); /* skip sequence, snarf attribute type */ tag = ber_scanf( ber, vals ? "{mM}" : "{mx}", attr, vals, &siz, (ber_len_t)0 ); if( tag == LBER_ERROR ) { rc = ld->ld_errno = LDAP_DECODING_ERROR; } } return rc; } openldap-2.5.11+dfsg/libraries/libldap/modify.c0000644000175000017500000001345114172327167020061 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ #include "portable.h" #include #include #include #include #include "ldap-int.h" /* A modify request/response looks like this: * ModifyRequest ::= [APPLICATION 6] SEQUENCE { * object LDAPDN, * changes SEQUENCE OF change SEQUENCE { * operation ENUMERATED { * add (0), * delete (1), * replace (2), * ... }, * modification PartialAttribute } } * * PartialAttribute ::= SEQUENCE { * type AttributeDescription, * vals SET OF value AttributeValue } * * AttributeDescription ::= LDAPString * -- Constrained to [RFC4512] * * AttributeValue ::= OCTET STRING * * ModifyResponse ::= [APPLICATION 7] LDAPResult * * (Source: RFC 4511) */ BerElement * ldap_build_modify_req( LDAP *ld, LDAP_CONST char *dn, LDAPMod **mods, LDAPControl **sctrls, LDAPControl **cctrls, ber_int_t *msgidp ) { BerElement *ber; int i, rc; /* create a message to send */ if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { return( NULL ); } LDAP_NEXT_MSGID( ld, *msgidp ); rc = ber_printf( ber, "{it{s{" /*}}}*/, *msgidp, LDAP_REQ_MODIFY, dn ); if ( rc == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } /* allow mods to be NULL ("touch") */ if ( mods ) { /* for each modification to be performed... */ for ( i = 0; mods[i] != NULL; i++ ) { if (( mods[i]->mod_op & LDAP_MOD_BVALUES) != 0 ) { rc = ber_printf( ber, "{e{s[V]N}N}", (ber_int_t) ( mods[i]->mod_op & ~LDAP_MOD_BVALUES ), mods[i]->mod_type, mods[i]->mod_bvalues ); } else { rc = ber_printf( ber, "{e{s[v]N}N}", (ber_int_t) mods[i]->mod_op, mods[i]->mod_type, mods[i]->mod_values ); } if ( rc == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } } } if ( ber_printf( ber, /*{{*/ "N}N}" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } /* Put Server Controls */ if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return( NULL ); } if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } return( ber ); } /* * ldap_modify_ext - initiate an ldap extended modify operation. * * Parameters: * * ld LDAP descriptor * dn DN of the object to modify * mods List of modifications to make. This is null-terminated * array of struct ldapmod's, specifying the modifications * to perform. * sctrls Server Controls * cctrls Client Controls * msgidp Message ID pointer * * Example: * LDAPMod *mods[] = { * { LDAP_MOD_ADD, "cn", { "babs jensen", "babs", 0 } }, * { LDAP_MOD_REPLACE, "sn", { "babs jensen", "babs", 0 } }, * { LDAP_MOD_DELETE, "ou", 0 }, * { LDAP_MOD_INCREMENT, "uidNumber, { "1", 0 } } * 0 * } * rc= ldap_modify_ext( ld, dn, mods, sctrls, cctrls, &msgid ); */ int ldap_modify_ext( LDAP *ld, LDAP_CONST char *dn, LDAPMod **mods, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp ) { BerElement *ber; int rc; ber_int_t id; Debug0( LDAP_DEBUG_TRACE, "ldap_modify_ext\n" ); /* check client controls */ rc = ldap_int_client_controls( ld, cctrls ); if( rc != LDAP_SUCCESS ) return rc; ber = ldap_build_modify_req( ld, dn, mods, sctrls, cctrls, &id ); if( !ber ) return ld->ld_errno; /* send the message */ *msgidp = ldap_send_initial_request( ld, LDAP_REQ_MODIFY, dn, ber, id ); return( *msgidp < 0 ? ld->ld_errno : LDAP_SUCCESS ); } /* * ldap_modify - initiate an ldap modify operation. * * Parameters: * * ld LDAP descriptor * dn DN of the object to modify * mods List of modifications to make. This is null-terminated * array of struct ldapmod's, specifying the modifications * to perform. * * Example: * LDAPMod *mods[] = { * { LDAP_MOD_ADD, "cn", { "babs jensen", "babs", 0 } }, * { LDAP_MOD_REPLACE, "sn", { "babs jensen", "babs", 0 } }, * { LDAP_MOD_DELETE, "ou", 0 }, * { LDAP_MOD_INCREMENT, "uidNumber, { "1", 0 } } * 0 * } * msgid = ldap_modify( ld, dn, mods ); */ int ldap_modify( LDAP *ld, LDAP_CONST char *dn, LDAPMod **mods ) { int rc, msgid; Debug0( LDAP_DEBUG_TRACE, "ldap_modify\n" ); rc = ldap_modify_ext( ld, dn, mods, NULL, NULL, &msgid ); if ( rc != LDAP_SUCCESS ) return -1; return msgid; } int ldap_modify_ext_s( LDAP *ld, LDAP_CONST char *dn, LDAPMod **mods, LDAPControl **sctrl, LDAPControl **cctrl ) { int rc; int msgid; LDAPMessage *res; rc = ldap_modify_ext( ld, dn, mods, sctrl, cctrl, &msgid ); if ( rc != LDAP_SUCCESS ) return( rc ); if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, &res ) == -1 || !res ) return( ld->ld_errno ); return( ldap_result2error( ld, res, 1 ) ); } int ldap_modify_s( LDAP *ld, LDAP_CONST char *dn, LDAPMod **mods ) { return ldap_modify_ext_s( ld, dn, mods, NULL, NULL ); } openldap-2.5.11+dfsg/libraries/libldap/account_usability.c0000644000175000017500000000653614172327167022321 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2004-2022 The OpenLDAP Foundation. * Portions Copyright 2004 Hewlett-Packard Company. * Portions Copyright 2004 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This work was developed by Howard Chu for inclusion in * OpenLDAP Software, based on prior work by Neil Dunbar (HP). * This work was sponsored by the Hewlett-Packard Company. */ #include "portable.h" #include "ldap-int.h" #ifdef LDAP_CONTROL_X_ACCOUNT_USABILITY int ldap_create_accountusability_control( LDAP *ld, LDAPControl **ctrlp ) { assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( ctrlp != NULL ); ld->ld_errno = ldap_control_create( LDAP_CONTROL_X_ACCOUNT_USABILITY, 0, NULL, 0, ctrlp ); return ld->ld_errno; } int ldap_parse_accountusability_control( LDAP *ld, LDAPControl *ctrl, int *availablep, LDAPAccountUsability *usabilityp ) { BerElement *ber; int available = 0; ber_tag_t tag; ber_len_t berLen; char *last; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( ctrl != NULL ); if ( !ctrl->ldctl_value.bv_val ) { ld->ld_errno = LDAP_DECODING_ERROR; return(ld->ld_errno); } /* Create a BerElement from the berval returned in the control. */ ber = ber_init(&ctrl->ldctl_value); if (ber == NULL) { ld->ld_errno = LDAP_NO_MEMORY; return(ld->ld_errno); } tag = ber_peek_tag( ber, &berLen ); if ( tag == LDAP_TAG_X_ACCOUNT_USABILITY_AVAILABLE ) { available = 1; if ( usabilityp != NULL ) { if (ber_get_int( ber, &usabilityp->seconds_remaining ) == LBER_DEFAULT) goto exit; } } else if ( tag == LDAP_TAG_X_ACCOUNT_USABILITY_NOT_AVAILABLE ) { available = 0; LDAPAccountUsabilityMoreInfo more_info = { 0, 0, 0, -1, -1 }; ber_skip_tag( ber, &berLen ); while ( (tag = ber_peek_tag( ber, &berLen )) != LBER_DEFAULT ) { switch (tag) { case LDAP_TAG_X_ACCOUNT_USABILITY_INACTIVE: if (ber_get_boolean( ber, &more_info.inactive ) == LBER_DEFAULT) goto exit; break; case LDAP_TAG_X_ACCOUNT_USABILITY_RESET: if (ber_get_boolean( ber, &more_info.reset ) == LBER_DEFAULT) goto exit; break; case LDAP_TAG_X_ACCOUNT_USABILITY_EXPIRED: if (ber_get_boolean( ber, &more_info.expired ) == LBER_DEFAULT) goto exit; break; case LDAP_TAG_X_ACCOUNT_USABILITY_REMAINING_GRACE: if (ber_get_int( ber, &more_info.remaining_grace ) == LBER_DEFAULT) goto exit; break; case LDAP_TAG_X_ACCOUNT_USABILITY_UNTIL_UNLOCK: if (ber_get_int( ber, &more_info.seconds_before_unlock ) == LBER_DEFAULT) goto exit; break; default: goto exit; } } if ( usabilityp != NULL ) { usabilityp->more_info = more_info; } } else { goto exit; } if ( availablep != NULL ) { *availablep = available; } ber_free(ber, 1); ld->ld_errno = LDAP_SUCCESS; return(ld->ld_errno); exit: ber_free(ber, 1); ld->ld_errno = LDAP_DECODING_ERROR; return(ld->ld_errno); } #endif /* LDAP_CONTROL_X_ACCOUNT_USABILITY */ openldap-2.5.11+dfsg/libraries/libldap/vc.c0000644000175000017500000002035614172327167017204 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This program was originally developed by Kurt D. Zeilenga for inclusion in * OpenLDAP Software. */ #include "portable.h" #include #include #include #include #include "ldap-int.h" /* * LDAP Verify Credentials operation * * The request is an extended request with OID 1.3.6.1.4.1.4203.666.6.5 with value of * the BER encoding of: * * VCRequest ::= SEQUENCE { * cookie [0] OCTET STRING OPTIONAL, * name LDAPDN, * authentication AuthenticationChoice, * controls [2] Controls OPTIONAL * } * * where LDAPDN, AuthenticationChoice, and Controls are as defined in RFC 4511. * * The response is an extended response with no OID and a value of the BER encoding of * * VCResponse ::= SEQUENCE { * resultCode ResultCode, * diagnosticMessage LDAPString, * cookie [0] OCTET STRING OPTIONAL, * serverSaslCreds [1] OCTET STRING OPTIONAL, * controls [2] Controls OPTIONAL * } * * where ResultCode is the result code enumeration from RFC 4511, and LDAPString and Controls are as * defined in RFC 4511. */ int ldap_parse_verify_credentials( LDAP *ld, LDAPMessage *res, int * code, char ** diagmsg, struct berval **cookie, struct berval **screds, LDAPControl ***ctrls) { int rc; char *retoid = NULL; struct berval *retdata = NULL; assert(ld != NULL); assert(LDAP_VALID(ld)); assert(res != NULL); assert(code != NULL); assert(diagmsg != NULL); rc = ldap_parse_extended_result(ld, res, &retoid, &retdata, 0); if( rc != LDAP_SUCCESS ) { ldap_perror(ld, "ldap_parse_verify_credentials"); return rc; } if (retdata) { ber_tag_t tag; ber_len_t len; ber_int_t i; BerElement * ber = ber_init(retdata); struct berval diagmsg_bv = BER_BVNULL; if (!ber) { rc = ld->ld_errno = LDAP_NO_MEMORY; goto done; } rc = LDAP_DECODING_ERROR; if (ber_scanf(ber, "{im" /*"}"*/, &i, &diagmsg_bv) == LBER_ERROR) { goto ber_done; } if ( diagmsg != NULL ) { *diagmsg = LDAP_MALLOC( diagmsg_bv.bv_len + 1 ); AC_MEMCPY( *diagmsg, diagmsg_bv.bv_val, diagmsg_bv.bv_len ); (*diagmsg)[diagmsg_bv.bv_len] = '\0'; } *code = i; tag = ber_peek_tag(ber, &len); if (tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE) { if (ber_scanf(ber, "O", cookie) == LBER_ERROR) goto ber_done; tag = ber_peek_tag(ber, &len); } if (tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_SCREDS) { if (ber_scanf(ber, "O", screds) == LBER_ERROR) goto ber_done; tag = ber_peek_tag(ber, &len); } if (tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_CONTROLS) { int nctrls = 0; char * opaque; *ctrls = LDAP_MALLOC(1 * sizeof(LDAPControl *)); if (!*ctrls) { rc = LDAP_NO_MEMORY; goto ber_done; } *ctrls[nctrls] = NULL; for(tag = ber_first_element(ber, &len, &opaque); tag != LBER_ERROR; tag = ber_next_element(ber, &len, opaque)) { LDAPControl *tctrl; LDAPControl **tctrls; tctrl = LDAP_CALLOC(1, sizeof(LDAPControl)); /* allocate pointer space for current controls (nctrls) * + this control + extra NULL */ tctrls = !tctrl ? NULL : LDAP_REALLOC(*ctrls, (nctrls+2) * sizeof(LDAPControl *)); if (!tctrls) { /* allocation failure */ if (tctrl) LDAP_FREE(tctrl); ldap_controls_free(*ctrls); *ctrls = NULL; rc = LDAP_NO_MEMORY; goto ber_done; } tctrls[nctrls++] = tctrl; tctrls[nctrls] = NULL; tag = ber_scanf(ber, "{a" /*"}"*/, &tctrl->ldctl_oid); if (tag == LBER_ERROR) { *ctrls = NULL; ldap_controls_free(tctrls); goto ber_done; } tag = ber_peek_tag(ber, &len); if (tag == LBER_BOOLEAN) { ber_int_t crit; tag = ber_scanf(ber, "b", &crit); tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0; tag = ber_peek_tag(ber, &len); } if (tag == LBER_OCTETSTRING) { tag = ber_scanf( ber, "o", &tctrl->ldctl_value ); } else { BER_BVZERO( &tctrl->ldctl_value ); } *ctrls = tctrls; } } rc = LDAP_SUCCESS; ber_done: ber_free(ber, 1); } done: ber_bvfree(retdata); ber_memfree(retoid); return rc; } int ldap_verify_credentials(LDAP *ld, struct berval *cookie, LDAP_CONST char *dn, LDAP_CONST char *mechanism, struct berval *cred, LDAPControl **vcctrls, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp) { int rc; BerElement *ber; struct berval reqdata; assert(ld != NULL); assert(LDAP_VALID(ld)); assert(msgidp != NULL); ber = ber_alloc_t(LBER_USE_DER); if (dn == NULL) dn = ""; if (mechanism == LDAP_SASL_SIMPLE) { assert(!cookie); rc = ber_printf(ber, "{stO" /*"}"*/, dn, LDAP_AUTH_SIMPLE, cred); } else { if (!cred || BER_BVISNULL(cred)) { if (cookie) { rc = ber_printf(ber, "{tOst{sN}" /*"}"*/, LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE, cookie, dn, LDAP_AUTH_SASL, mechanism); } else { rc = ber_printf(ber, "{st{sN}N" /*"}"*/, dn, LDAP_AUTH_SASL, mechanism); } } else { if (cookie) { rc = ber_printf(ber, "{tOst{sON}" /*"}"*/, LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE, cookie, dn, LDAP_AUTH_SASL, mechanism, cred); } else { rc = ber_printf(ber, "{st{sON}" /*"}"*/, dn, LDAP_AUTH_SASL, mechanism, cred); } } } if (rc < 0) { rc = ld->ld_errno = LDAP_ENCODING_ERROR; goto done; } if (vcctrls && *vcctrls) { LDAPControl *const *c; rc = ber_printf(ber, "t{" /*"}"*/, LDAP_TAG_EXOP_VERIFY_CREDENTIALS_CONTROLS); for (c=vcctrls; *c; c++) { rc = ldap_pvt_put_control(*c, ber); if (rc != LDAP_SUCCESS) { rc = ld->ld_errno = LDAP_ENCODING_ERROR; goto done; } } rc = ber_printf(ber, /*"{{"*/ "}N}"); } else { rc = ber_printf(ber, /*"{"*/ "N}"); } if (rc < 0) { rc = ld->ld_errno = LDAP_ENCODING_ERROR; goto done; } rc = ber_flatten2(ber, &reqdata, 0); if (rc < 0) { rc = ld->ld_errno = LDAP_ENCODING_ERROR; goto done; } rc = ldap_extended_operation(ld, LDAP_EXOP_VERIFY_CREDENTIALS, &reqdata, sctrls, cctrls, msgidp); done: ber_free(ber, 1); return rc; } int ldap_verify_credentials_s( LDAP *ld, struct berval *cookie, LDAP_CONST char *dn, LDAP_CONST char *mechanism, struct berval *cred, LDAPControl **vcictrls, LDAPControl **sctrls, LDAPControl **cctrls, int *rcode, char **diagmsg, struct berval **scookie, struct berval **scred, LDAPControl ***vcoctrls) { int rc; int msgid; LDAPMessage *res; rc = ldap_verify_credentials(ld, cookie, dn, mechanism, cred, vcictrls, sctrls, cctrls, &msgid); if (rc != LDAP_SUCCESS) return rc; if (ldap_result(ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, &res) == -1 || !res) { return ld->ld_errno; } rc = ldap_parse_verify_credentials(ld, res, rcode, diagmsg, scookie, scred, vcoctrls); if (rc != LDAP_SUCCESS) { ldap_msgfree(res); return rc; } return( ldap_result2error(ld, res, 1)); } #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS_INTERACTIVE int ldap_verify_credentials_interactive ( LDAP *ld, LDAP_CONST char *dn, /* usually NULL */ LDAP_CONST char *mech, LDAPControl **vcControls, LDAPControl **serverControls, LDAPControl **clientControls, /* should be client controls */ unsigned flags, LDAP_SASL_INTERACT_PROC *proc, void *defaults, void *context; /* as obtained from ldap_result() */ LDAPMessage *result, /* returned during bind processing */ const char **rmech, int *msgid ) { if (!ld && context) { assert(!dn); assert(!mech); assert(!vcControls); assert(!serverControls); assert(!defaults); assert(!result); assert(!rmech); assert(!msgid); /* special case to avoid having to expose a separate dispose context API */ sasl_dispose((sasl_conn_t)context); return LDAP_SUCCESS; } ld->ld_errno = LDAP_NOT_SUPPORTED; return ld->ld_errno; } #endif openldap-2.5.11+dfsg/libraries/libldap/unbind.c0000644000175000017500000001644014172327167020052 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" /* An Unbind Request looks like this: * * UnbindRequest ::= [APPLICATION 2] NULL * * and has no response. (Source: RFC 4511) */ int ldap_unbind_ext( LDAP *ld, LDAPControl **sctrls, LDAPControl **cctrls ) { int rc; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); /* check client controls */ rc = ldap_int_client_controls( ld, cctrls ); if( rc != LDAP_SUCCESS ) return rc; return ldap_ld_free( ld, 1, sctrls, cctrls ); } int ldap_unbind_ext_s( LDAP *ld, LDAPControl **sctrls, LDAPControl **cctrls ) { return ldap_unbind_ext( ld, sctrls, cctrls ); } int ldap_unbind( LDAP *ld ) { Debug0( LDAP_DEBUG_TRACE, "ldap_unbind\n" ); return( ldap_unbind_ext( ld, NULL, NULL ) ); } int ldap_ld_free( LDAP *ld, int close, LDAPControl **sctrls, LDAPControl **cctrls ) { LDAPMessage *lm, *next; int err = LDAP_SUCCESS; LDAP_MUTEX_LOCK( &ld->ld_ldcmutex ); /* Someone else is still using this ld. */ if (ld->ld_ldcrefcnt > 1) { /* but not last thread */ /* clean up self only */ ld->ld_ldcrefcnt--; if ( ld->ld_error != NULL ) { LDAP_FREE( ld->ld_error ); ld->ld_error = NULL; } if ( ld->ld_matched != NULL ) { LDAP_FREE( ld->ld_matched ); ld->ld_matched = NULL; } if ( ld->ld_referrals != NULL) { LDAP_VFREE(ld->ld_referrals); ld->ld_referrals = NULL; } LDAP_MUTEX_UNLOCK( &ld->ld_ldcmutex ); LDAP_FREE( (char *) ld ); return( err ); } /* This ld is the last thread. */ LDAP_MUTEX_UNLOCK( &ld->ld_ldcmutex ); /* free LDAP structure and outstanding requests/responses */ LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); ldap_tavl_free( ld->ld_requests, ldap_do_free_request ); ld->ld_requests = NULL; LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); /* free and unbind from all open connections */ while ( ld->ld_conns != NULL ) { ldap_free_connection( ld, ld->ld_conns, 1, close ); } LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); for ( lm = ld->ld_responses; lm != NULL; lm = next ) { next = lm->lm_next; ldap_msgfree( lm ); } if ( ld->ld_abandoned != NULL ) { LDAP_FREE( ld->ld_abandoned ); ld->ld_abandoned = NULL; } LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); /* Should already be closed by ldap_free_connection which knows not to free * this one */ ber_int_sb_destroy( ld->ld_sb ); LBER_FREE( ld->ld_sb ); LDAP_MUTEX_LOCK( &ld->ld_ldopts_mutex ); /* final close callbacks */ { ldaplist *ll, *next; for ( ll = ld->ld_options.ldo_conn_cbs; ll; ll = next ) { ldap_conncb *cb = ll->ll_data; next = ll->ll_next; cb->lc_del( ld, NULL, cb ); LDAP_FREE( ll ); } } if ( ld->ld_error != NULL ) { LDAP_FREE( ld->ld_error ); ld->ld_error = NULL; } if ( ld->ld_matched != NULL ) { LDAP_FREE( ld->ld_matched ); ld->ld_matched = NULL; } if ( ld->ld_referrals != NULL) { LDAP_VFREE(ld->ld_referrals); ld->ld_referrals = NULL; } if ( ld->ld_selectinfo != NULL ) { ldap_free_select_info( ld->ld_selectinfo ); ld->ld_selectinfo = NULL; } if ( ld->ld_options.ldo_defludp != NULL ) { ldap_free_urllist( ld->ld_options.ldo_defludp ); ld->ld_options.ldo_defludp = NULL; } if ( ld->ld_options.ldo_local_ip_addrs.local_ip_addrs ) { LDAP_FREE( ld->ld_options.ldo_local_ip_addrs.local_ip_addrs ); memset( & ld->ld_options.ldo_local_ip_addrs, 0, sizeof( ldapsourceip ) ); } #ifdef LDAP_CONNECTIONLESS if ( ld->ld_options.ldo_peer != NULL ) { LDAP_FREE( ld->ld_options.ldo_peer ); ld->ld_options.ldo_peer = NULL; } if ( ld->ld_options.ldo_cldapdn != NULL ) { LDAP_FREE( ld->ld_options.ldo_cldapdn ); ld->ld_options.ldo_cldapdn = NULL; } #endif if ( ld->ld_options.ldo_defbase != NULL ) { LDAP_FREE( ld->ld_options.ldo_defbase ); ld->ld_options.ldo_defbase = NULL; } #ifdef HAVE_CYRUS_SASL if ( ld->ld_options.ldo_def_sasl_mech != NULL ) { LDAP_FREE( ld->ld_options.ldo_def_sasl_mech ); ld->ld_options.ldo_def_sasl_mech = NULL; } if ( ld->ld_options.ldo_def_sasl_realm != NULL ) { LDAP_FREE( ld->ld_options.ldo_def_sasl_realm ); ld->ld_options.ldo_def_sasl_realm = NULL; } if ( ld->ld_options.ldo_def_sasl_authcid != NULL ) { LDAP_FREE( ld->ld_options.ldo_def_sasl_authcid ); ld->ld_options.ldo_def_sasl_authcid = NULL; } if ( ld->ld_options.ldo_def_sasl_authzid != NULL ) { LDAP_FREE( ld->ld_options.ldo_def_sasl_authzid ); ld->ld_options.ldo_def_sasl_authzid = NULL; } #endif #ifdef HAVE_TLS ldap_int_tls_destroy( &ld->ld_options ); #endif if ( ld->ld_options.ldo_sctrls != NULL ) { ldap_controls_free( ld->ld_options.ldo_sctrls ); ld->ld_options.ldo_sctrls = NULL; } if ( ld->ld_options.ldo_cctrls != NULL ) { ldap_controls_free( ld->ld_options.ldo_cctrls ); ld->ld_options.ldo_cctrls = NULL; } LDAP_MUTEX_UNLOCK( &ld->ld_ldopts_mutex ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_destroy( &ld->ld_msgid_mutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_conn_mutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_req_mutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_res_mutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_abandon_mutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_ldopts_mutex ); ldap_pvt_thread_mutex_destroy( &ld->ld_ldcmutex ); #endif #ifndef NDEBUG LDAP_TRASH(ld); #endif LDAP_FREE( (char *) ld->ldc ); LDAP_FREE( (char *) ld ); return( err ); } int ldap_destroy( LDAP *ld ) { return ( ldap_ld_free( ld, 1, NULL, NULL ) ); } int ldap_unbind_s( LDAP *ld ) { return( ldap_unbind_ext( ld, NULL, NULL ) ); } /* FIXME: this function is called only by ldap_free_connection(), * which, most of the times, is called with ld_req_mutex locked */ int ldap_send_unbind( LDAP *ld, Sockbuf *sb, LDAPControl **sctrls, LDAPControl **cctrls ) { BerElement *ber; ber_int_t id; Debug0( LDAP_DEBUG_TRACE, "ldap_send_unbind\n" ); #ifdef LDAP_CONNECTIONLESS if (LDAP_IS_UDP(ld)) return LDAP_SUCCESS; #endif /* create a message to send */ if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { return( ld->ld_errno ); } LDAP_NEXT_MSGID(ld, id); /* fill it in */ if ( ber_printf( ber, "{itn" /*}*/, id, LDAP_REQ_UNBIND ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( ld->ld_errno ); } /* Put Server Controls */ if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return ld->ld_errno; } if ( ber_printf( ber, /*{*/ "N}", LDAP_REQ_UNBIND ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( ld->ld_errno ); } ld->ld_errno = LDAP_SUCCESS; /* send the message */ if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) == -1 ) { ld->ld_errno = LDAP_SERVER_DOWN; } return( ld->ld_errno ); } openldap-2.5.11+dfsg/libraries/libldap/urltest.c0000644000175000017500000000530614172327167020274 0ustar ryanryan/* urltest.c -- OpenLDAP URL API Test Program */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This program was initially developed by Pierangelo Masarati * for inclusion in OpenLDAP Software. */ /* * This program is designed to test the ldap_url_* functions */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" #include "ldap_defaults.h" int main(int argc, char *argv[]) { const char *url, *scope = NULL; LDAPURLDesc *lud; enum { IS_LDAP = 0, IS_LDAPS, IS_LDAPI } type = IS_LDAP; int rc; if ( argc != 2 ) { fprintf( stderr, "usage: urltest \n" ); exit( EXIT_FAILURE ); } url = argv[ 1 ]; if ( ldap_is_ldaps_url( url ) ) { fprintf( stdout, "LDAPS url\n" ); type = IS_LDAPS; } else if ( ldap_is_ldapi_url( url ) ) { fprintf( stdout, "LDAPI url\n" ); type = IS_LDAPI; } else if ( ldap_is_ldap_url( url ) ) { fprintf( stdout, "generic LDAP url\n" ); } else { fprintf( stderr, "Need a valid LDAP url\n" ); exit( EXIT_FAILURE ); } rc = ldap_url_parse( url, &lud ); if ( rc != LDAP_URL_SUCCESS ) { fprintf( stderr, "ldap_url_parse(%s) failed (%d)\n", url, rc ); exit( EXIT_FAILURE ); } fprintf( stdout, "PROTO: %s\n", lud->lud_scheme ); switch ( type ) { case IS_LDAPI: fprintf( stdout, "PATH: %s\n", lud->lud_host ); break; default: fprintf( stdout, "HOST: %s\n", lud->lud_host ); if ( lud->lud_port != 0 ) { fprintf( stdout, "PORT: %d\n", lud->lud_port ); } } if ( lud->lud_dn && lud->lud_dn[ 0 ] ) { fprintf( stdout, "DN: %s\n", lud->lud_dn ); } if ( lud->lud_attrs ) { int i; fprintf( stdout, "ATTRS:\n" ); for ( i = 0; lud->lud_attrs[ i ]; i++ ) { fprintf( stdout, "\t%s\n", lud->lud_attrs[ i ] ); } } scope = ldap_pvt_scope2str( lud->lud_scope ); if ( scope ) { fprintf( stdout, "SCOPE: %s\n", scope ); } if ( lud->lud_filter ) { fprintf( stdout, "FILTER: %s\n", lud->lud_filter ); } if ( lud->lud_exts ) { int i; fprintf( stdout, "EXTS:\n" ); for ( i = 0; lud->lud_exts[ i ]; i++ ) { fprintf( stdout, "\t%s\n", lud->lud_exts[ i ] ); } } fprintf( stdout, "URL: %s\n", ldap_url_desc2str( lud )); return EXIT_SUCCESS; } openldap-2.5.11+dfsg/libraries/libldap/tls_o.c0000644000175000017500000011411614172327167017712 0ustar ryanryan/* tls_o.c - Handle tls/ssl using OpenSSL */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2008-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: Rewritten by Howard Chu */ #include "portable.h" #ifdef HAVE_OPENSSL #include "ldap_config.h" #include #include #include #include #include #include #include #include #include #include #include "ldap-int.h" #include "ldap-tls.h" #ifdef HAVE_OPENSSL_SSL_H #include #include #include #include #include #include #include #include #endif #if OPENSSL_VERSION_NUMBER >= 0x10100000 #define ASN1_STRING_data(x) ASN1_STRING_get0_data(x) #endif typedef SSL_CTX tlso_ctx; typedef SSL tlso_session; static BIO_METHOD * tlso_bio_method = NULL; static BIO_METHOD * tlso_bio_setup( void ); static int tlso_opt_trace = 1; static void tlso_report_error( void ); static void tlso_info_cb( const SSL *ssl, int where, int ret ); static int tlso_verify_cb( int ok, X509_STORE_CTX *ctx ); static int tlso_verify_ok( int ok, X509_STORE_CTX *ctx ); static int tlso_seed_PRNG( const char *randfile ); #if OPENSSL_VERSION_NUMBER < 0x10100000 /* * OpenSSL 1.1 API and later has new locking code */ static RSA * tlso_tmp_rsa_cb( SSL *ssl, int is_export, int key_length ); #ifdef LDAP_R_COMPILE /* * provide mutexes for the OpenSSL library. */ static ldap_pvt_thread_mutex_t tlso_mutexes[CRYPTO_NUM_LOCKS]; static void tlso_locking_cb( int mode, int type, const char *file, int line ) { if ( mode & CRYPTO_LOCK ) { ldap_pvt_thread_mutex_lock( &tlso_mutexes[type] ); } else { ldap_pvt_thread_mutex_unlock( &tlso_mutexes[type] ); } } #if OPENSSL_VERSION_NUMBER >= 0x0909000 static void tlso_thread_self( CRYPTO_THREADID *id ) { CRYPTO_THREADID_set_pointer( id, (void *)ldap_pvt_thread_self() ); } #define CRYPTO_set_id_callback(foo) CRYPTO_THREADID_set_callback(foo) #else static unsigned long tlso_thread_self( void ) { /* FIXME: CRYPTO_set_id_callback only works when ldap_pvt_thread_t * is an integral type that fits in an unsigned long */ /* force an error if the ldap_pvt_thread_t type is too large */ enum { ok = sizeof( ldap_pvt_thread_t ) <= sizeof( unsigned long ) }; typedef struct { int dummy: ok ? 1 : -1; } Check[ok ? 1 : -1]; return (unsigned long) ldap_pvt_thread_self(); } #endif static void tlso_thr_init( void ) { int i; for( i=0; i< CRYPTO_NUM_LOCKS ; i++ ) { ldap_pvt_thread_mutex_init( &tlso_mutexes[i] ); } CRYPTO_set_locking_callback( tlso_locking_cb ); CRYPTO_set_id_callback( tlso_thread_self ); } #endif /* LDAP_R_COMPILE */ #else #ifdef LDAP_R_COMPILE static void tlso_thr_init( void ) {} #endif #endif /* OpenSSL 1.1 */ #if OPENSSL_VERSION_NUMBER < 0x10100000 /* * OpenSSL 1.1 API and later makes the BIO method concrete types internal. */ static BIO_METHOD * BIO_meth_new( int type, const char *name ) { BIO_METHOD *method = LDAP_MALLOC( sizeof(BIO_METHOD) ); memset( method, 0, sizeof(BIO_METHOD) ); method->type = type; method->name = name; return method; } static void BIO_meth_free( BIO_METHOD *meth ) { if ( meth == NULL ) { return; } LDAP_FREE( meth ); } #define BIO_meth_set_write(m, f) (m)->bwrite = (f) #define BIO_meth_set_read(m, f) (m)->bread = (f) #define BIO_meth_set_puts(m, f) (m)->bputs = (f) #define BIO_meth_set_gets(m, f) (m)->bgets = (f) #define BIO_meth_set_ctrl(m, f) (m)->ctrl = (f) #define BIO_meth_set_create(m, f) (m)->create = (f) #define BIO_meth_set_destroy(m, f) (m)->destroy = (f) #endif /* OpenSSL 1.1 */ static STACK_OF(X509_NAME) * tlso_ca_list( char * bundle, char * dir, X509 *cert ) { STACK_OF(X509_NAME) *ca_list = NULL; if ( bundle ) { ca_list = SSL_load_client_CA_file( bundle ); } #if defined(HAVE_DIRENT_H) || defined(dirent) if ( dir ) { int freeit = 0; if ( !ca_list ) { ca_list = sk_X509_NAME_new_null(); freeit = 1; } if ( !SSL_add_dir_cert_subjects_to_stack( ca_list, dir ) && freeit ) { sk_X509_NAME_free( ca_list ); ca_list = NULL; } } #endif if ( cert ) { X509_NAME *xn = X509_get_subject_name( cert ); xn = X509_NAME_dup( xn ); if ( !ca_list ) ca_list = sk_X509_NAME_new_null(); if ( xn && ca_list ) sk_X509_NAME_push( ca_list, xn ); } return ca_list; } /* * Initialize TLS subsystem. Should be called only once. */ static int tlso_init( void ) { struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT(); #ifdef HAVE_EBCDIC { char *file = LDAP_STRDUP( lo->ldo_tls_randfile ); if ( file ) __atoe( file ); (void) tlso_seed_PRNG( file ); LDAP_FREE( file ); } #else (void) tlso_seed_PRNG( lo->ldo_tls_randfile ); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 SSL_load_error_strings(); SSL_library_init(); OpenSSL_add_all_digests(); #else OPENSSL_init_ssl(0, NULL); #endif /* FIXME: mod_ssl does this */ X509V3_add_standard_extensions(); tlso_bio_method = tlso_bio_setup(); return 0; } /* * Tear down the TLS subsystem. Should only be called once. */ static void tlso_destroy( void ) { struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT(); BIO_meth_free( tlso_bio_method ); #if OPENSSL_VERSION_NUMBER < 0x10100000 EVP_cleanup(); ERR_remove_thread_state(NULL); ERR_free_strings(); #endif if ( lo->ldo_tls_randfile ) { LDAP_FREE( lo->ldo_tls_randfile ); lo->ldo_tls_randfile = NULL; } } static tls_ctx * tlso_ctx_new( struct ldapoptions *lo ) { return (tls_ctx *) SSL_CTX_new( SSLv23_method() ); } static void tlso_ctx_ref( tls_ctx *ctx ) { tlso_ctx *c = (tlso_ctx *)ctx; #if OPENSSL_VERSION_NUMBER < 0x10100000 #define SSL_CTX_up_ref(ctx) CRYPTO_add( &(ctx->references), 1, CRYPTO_LOCK_SSL_CTX ) #endif SSL_CTX_up_ref( c ); } static void tlso_ctx_free ( tls_ctx *ctx ) { tlso_ctx *c = (tlso_ctx *)ctx; SSL_CTX_free( c ); } #if OPENSSL_VERSION_NUMBER >= 0x10101000 static char * tlso_stecpy( char *dst, const char *src, const char *end ) { while ( dst < end && *src ) *dst++ = *src++; if ( dst < end ) *dst = '\0'; return dst; } /* OpenSSL 1.1.1 uses a separate API for TLS1.3 ciphersuites. * Try to find any TLS1.3 ciphers in the given list of suites. */ static void tlso_ctx_cipher13( tlso_ctx *ctx, char *suites ) { char tls13_suites[1024], *ts = tls13_suites, *te = tls13_suites + sizeof(tls13_suites); char *ptr, *colon, *nptr; char sname[128]; STACK_OF(SSL_CIPHER) *cs; SSL *s = SSL_new( ctx ); int ret; if ( !s ) return; *ts = '\0'; /* check individual suites in a separate SSL handle before * mucking with the provided ctx. Init it to a known * mostly-empty state. */ SSL_set_ciphersuites( s, "" ); SSL_set_cipher_list( s, SSL3_TXT_RSA_NULL_SHA ); for ( ptr = suites;; ) { colon = strchr( ptr, ':' ); if ( colon ) { int len = colon - ptr; if ( len > 63 ) len = 63; strncpy( sname, ptr, len ); sname[len] = '\0'; nptr = sname; } else { nptr = ptr; } if ( SSL_set_ciphersuites( s, nptr )) { cs = SSL_get_ciphers( s ); if ( cs ) { const char *ver = SSL_CIPHER_get_version( sk_SSL_CIPHER_value( cs, 0 )); if ( !strncmp( ver, "TLSv", 4 ) && strncmp( ver+4, "1.3", 3 ) >= 0 ) { if ( tls13_suites[0] ) ts = tlso_stecpy( ts, ":", te ); ts = tlso_stecpy( ts, sname, te ); } } } if ( !colon || ts >= te ) break; ptr = colon+1; } SSL_free( s ); /* If no TLS1.3 ciphersuites were specified, leave current settings untouched. */ if ( tls13_suites[0] ) SSL_CTX_set_ciphersuites( ctx, tls13_suites ); } #endif /* OpenSSL 1.1.1 */ /* * initialize a new TLS context */ static int tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) { tlso_ctx *ctx = (tlso_ctx *)lo->ldo_tls_ctx; int i; if ( is_server ) { SSL_CTX_set_session_id_context( ctx, (const unsigned char *) "OpenLDAP", sizeof("OpenLDAP")-1 ); } if ( lo->ldo_tls_protocol_min ) { int opt = 0; if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL2 ) { opt |= SSL_OP_NO_SSLv2; SSL_CTX_clear_options( ctx, SSL_OP_NO_SSLv3 ); } if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL3 ) opt |= SSL_OP_NO_SSLv3; #ifdef SSL_OP_NO_TLSv1 if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_TLS1_0 ) opt |= SSL_OP_NO_TLSv1; #endif #ifdef SSL_OP_NO_TLSv1_1 if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_TLS1_1 ) opt |= SSL_OP_NO_TLSv1_1; #endif #ifdef SSL_OP_NO_TLSv1_2 if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_TLS1_2 ) opt |= SSL_OP_NO_TLSv1_2; #endif #ifdef SSL_OP_NO_TLSv1_3 if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_TLS1_3 ) opt |= SSL_OP_NO_TLSv1_3; #endif if ( opt ) SSL_CTX_set_options( ctx, opt ); } if ( lo->ldo_tls_protocol_max ) { int opt = 0; #ifdef SSL_OP_NO_TLSv1_3 if ( lo->ldo_tls_protocol_max < LDAP_OPT_X_TLS_PROTOCOL_TLS1_3 ) opt |= SSL_OP_NO_TLSv1_3; #endif #ifdef SSL_OP_NO_TLSv1_2 if ( lo->ldo_tls_protocol_max < LDAP_OPT_X_TLS_PROTOCOL_TLS1_2 ) opt |= SSL_OP_NO_TLSv1_2; #endif #ifdef SSL_OP_NO_TLSv1_1 if ( lo->ldo_tls_protocol_max < LDAP_OPT_X_TLS_PROTOCOL_TLS1_1 ) opt |= SSL_OP_NO_TLSv1_1; #endif #ifdef SSL_OP_NO_TLSv1 if ( lo->ldo_tls_protocol_max < LDAP_OPT_X_TLS_PROTOCOL_TLS1_0 ) opt |= SSL_OP_NO_TLSv1; #endif if ( lo->ldo_tls_protocol_max < LDAP_OPT_X_TLS_PROTOCOL_SSL3 ) opt |= SSL_OP_NO_SSLv3; if ( opt ) SSL_CTX_set_options( ctx, opt ); } if ( lo->ldo_tls_ciphersuite ) { #if OPENSSL_VERSION_NUMBER >= 0x10101000 tlso_ctx_cipher13( ctx, lt->lt_ciphersuite ); #endif if ( !SSL_CTX_set_cipher_list( ctx, lt->lt_ciphersuite ) ) { Debug1( LDAP_DEBUG_ANY, "TLS: could not set cipher list %s.\n", lo->ldo_tls_ciphersuite ); tlso_report_error(); return -1; } } if ( lo->ldo_tls_cacertfile == NULL && lo->ldo_tls_cacertdir == NULL && lo->ldo_tls_cacert.bv_val == NULL ) { if ( !SSL_CTX_set_default_verify_paths( ctx ) ) { Debug0( LDAP_DEBUG_ANY, "TLS: " "could not use default certificate paths" ); tlso_report_error(); return -1; } } else { X509 *cert = NULL; if ( lo->ldo_tls_cacert.bv_val ) { const unsigned char *pp = (const unsigned char *) (lo->ldo_tls_cacert.bv_val); cert = d2i_X509( NULL, &pp, lo->ldo_tls_cacert.bv_len ); X509_STORE *store = SSL_CTX_get_cert_store( ctx ); if ( !X509_STORE_add_cert( store, cert )) { Debug0( LDAP_DEBUG_ANY, "TLS: " "could not use CA certificate" ); tlso_report_error(); return -1; } } if (( lt->lt_cacertfile || lt->lt_cacertdir ) && !SSL_CTX_load_verify_locations( ctx, lt->lt_cacertfile, lt->lt_cacertdir ) ) { Debug2( LDAP_DEBUG_ANY, "TLS: " "could not load verify locations (file:`%s',dir:`%s').\n", lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "", lo->ldo_tls_cacertdir ? lo->ldo_tls_cacertdir : "" ); tlso_report_error(); return -1; } if ( is_server ) { STACK_OF(X509_NAME) *calist; /* List of CA names to send to a client */ calist = tlso_ca_list( lt->lt_cacertfile, lt->lt_cacertdir, cert ); if ( !calist ) { Debug2( LDAP_DEBUG_ANY, "TLS: " "could not load client CA list (file:`%s',dir:`%s').\n", lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "", lo->ldo_tls_cacertdir ? lo->ldo_tls_cacertdir : "" ); tlso_report_error(); return -1; } SSL_CTX_set_client_CA_list( ctx, calist ); } if ( cert ) X509_free( cert ); } if ( lo->ldo_tls_cert.bv_val ) { const unsigned char *pp = (const unsigned char *) (lo->ldo_tls_cert.bv_val); X509 *cert = d2i_X509( NULL, &pp, lo->ldo_tls_cert.bv_len ); if ( !SSL_CTX_use_certificate( ctx, cert )) { Debug0( LDAP_DEBUG_ANY, "TLS: could not use certificate.\n" ); tlso_report_error(); return -1; } X509_free( cert ); } else if ( lo->ldo_tls_certfile && !SSL_CTX_use_certificate_chain_file( ctx, lt->lt_certfile) ) { Debug1( LDAP_DEBUG_ANY, "TLS: could not use certificate file `%s'.\n", lo->ldo_tls_certfile ); tlso_report_error(); return -1; } /* Key validity is checked automatically if cert has already been set */ if ( lo->ldo_tls_key.bv_val ) { const unsigned char *pp = (const unsigned char *) (lo->ldo_tls_key.bv_val); EVP_PKEY *pkey = d2i_AutoPrivateKey( NULL, &pp, lo->ldo_tls_key.bv_len ); if ( !SSL_CTX_use_PrivateKey( ctx, pkey )) { Debug0( LDAP_DEBUG_ANY, "TLS: could not use private key.\n" ); tlso_report_error(); return -1; } EVP_PKEY_free( pkey ); } else if ( lo->ldo_tls_keyfile && !SSL_CTX_use_PrivateKey_file( ctx, lt->lt_keyfile, SSL_FILETYPE_PEM ) ) { Debug1( LDAP_DEBUG_ANY, "TLS: could not use key file `%s'.\n", lo->ldo_tls_keyfile ); tlso_report_error(); return -1; } if ( is_server && lo->ldo_tls_dhfile ) { DH *dh; BIO *bio; if (( bio=BIO_new_file( lt->lt_dhfile,"r" )) == NULL ) { Debug1( LDAP_DEBUG_ANY, "TLS: could not use DH parameters file `%s'.\n", lo->ldo_tls_dhfile ); tlso_report_error(); return -1; } if (!( dh=PEM_read_bio_DHparams( bio, NULL, NULL, NULL ))) { Debug1( LDAP_DEBUG_ANY, "TLS: could not read DH parameters file `%s'.\n", lo->ldo_tls_dhfile ); tlso_report_error(); BIO_free( bio ); return -1; } BIO_free( bio ); SSL_CTX_set_tmp_dh( ctx, dh ); SSL_CTX_set_options( ctx, SSL_OP_SINGLE_DH_USE ); DH_free( dh ); } if ( lo->ldo_tls_ecname ) { #ifdef OPENSSL_NO_EC Debug0( LDAP_DEBUG_ANY, "TLS: Elliptic Curves not supported.\n" ); return -1; #else if ( !SSL_CTX_set1_curves_list( ctx, lt->lt_ecname )) { Debug1( LDAP_DEBUG_ANY, "TLS: could not set EC name `%s'.\n", lo->ldo_tls_ecname ); tlso_report_error(); return -1; } /* * This is a NOP in OpenSSL 1.1.0 and later, where curves are always * auto-negotiated. */ #if OPENSSL_VERSION_NUMBER < 0x10100000UL if ( SSL_CTX_set_ecdh_auto( ctx, 1 ) <= 0 ) { Debug0( LDAP_DEBUG_ANY, "TLS: could not enable automatic EC negotiation.\n" ); } #endif #endif /* OPENSSL_NO_EC */ } if ( tlso_opt_trace ) { SSL_CTX_set_info_callback( ctx, tlso_info_cb ); } i = SSL_VERIFY_NONE; if ( lo->ldo_tls_require_cert ) { i = SSL_VERIFY_PEER; if ( lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_DEMAND || lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_HARD ) { i |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; } } SSL_CTX_set_verify( ctx, i, lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_ALLOW ? tlso_verify_ok : tlso_verify_cb ); #if OPENSSL_VERSION_NUMBER < 0x10100000 SSL_CTX_set_tmp_rsa_callback( ctx, tlso_tmp_rsa_cb ); #endif if ( lo->ldo_tls_crlcheck ) { X509_STORE *x509_s = SSL_CTX_get_cert_store( ctx ); if ( lo->ldo_tls_crlcheck == LDAP_OPT_X_TLS_CRL_PEER ) { X509_STORE_set_flags( x509_s, X509_V_FLAG_CRL_CHECK ); } else if ( lo->ldo_tls_crlcheck == LDAP_OPT_X_TLS_CRL_ALL ) { X509_STORE_set_flags( x509_s, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL ); } } /* Explicitly honor the server side cipher suite preference */ SSL_CTX_set_options( ctx, SSL_OP_CIPHER_SERVER_PREFERENCE ); return 0; } static tls_session * tlso_session_new( tls_ctx *ctx, int is_server ) { tlso_ctx *c = (tlso_ctx *)ctx; return (tls_session *)SSL_new( c ); } static int tlso_session_connect( LDAP *ld, tls_session *sess, const char *name_in ) { tlso_session *s = (tlso_session *)sess; int rc; #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME if ( name_in ) { rc = SSL_set_tlsext_host_name( s, name_in ); if ( !rc ) /* can fail to strdup the name */ return -1; } #endif /* Caller expects 0 = success, OpenSSL returns 1 = success */ rc = SSL_connect( s ) - 1; return rc; } static int tlso_session_accept( tls_session *sess ) { tlso_session *s = (tlso_session *)sess; /* Caller expects 0 = success, OpenSSL returns 1 = success */ return SSL_accept( s ) - 1; } static int tlso_session_upflags( Sockbuf *sb, tls_session *sess, int rc ) { tlso_session *s = (tlso_session *)sess; /* 1 was subtracted above, offset it back now */ rc = SSL_get_error(s, rc+1); if (rc == SSL_ERROR_WANT_READ) { sb->sb_trans_needs_read = 1; return 1; } else if (rc == SSL_ERROR_WANT_WRITE) { sb->sb_trans_needs_write = 1; return 1; } else if (rc == SSL_ERROR_WANT_CONNECT) { return 1; } return 0; } static char * tlso_session_errmsg( tls_session *sess, int rc, char *buf, size_t len ) { char err[256] = ""; const char *certerr=NULL; tlso_session *s = (tlso_session *)sess; rc = ERR_peek_error(); if ( rc ) { ERR_error_string_n( rc, err, sizeof(err) ); if ( ( ERR_GET_LIB(rc) == ERR_LIB_SSL ) && ( ERR_GET_REASON(rc) == SSL_R_CERTIFICATE_VERIFY_FAILED ) ) { int certrc = SSL_get_verify_result(s); certerr = (char *)X509_verify_cert_error_string(certrc); } snprintf(buf, len, "%s%s%s%s", err, certerr ? " (" :"", certerr ? certerr : "", certerr ? ")" : "" ); return buf; } return NULL; } static int tlso_session_my_dn( tls_session *sess, struct berval *der_dn ) { tlso_session *s = (tlso_session *)sess; X509 *x; X509_NAME *xn; x = SSL_get_certificate( s ); if (!x) return LDAP_INVALID_CREDENTIALS; xn = X509_get_subject_name(x); #if OPENSSL_VERSION_NUMBER < 0x10100000 der_dn->bv_len = i2d_X509_NAME( xn, NULL ); der_dn->bv_val = xn->bytes->data; #else { size_t len = 0; der_dn->bv_val = NULL; X509_NAME_get0_der( xn, (const unsigned char **)&der_dn->bv_val, &len ); der_dn->bv_len = len; } #endif /* Don't X509_free, the session is still using it */ return 0; } static X509 * tlso_get_cert( SSL *s ) { /* If peer cert was bad, treat as if no cert was given */ if (SSL_get_verify_result(s)) { return NULL; } return SSL_get_peer_certificate(s); } static int tlso_session_peer_dn( tls_session *sess, struct berval *der_dn ) { tlso_session *s = (tlso_session *)sess; X509 *x = tlso_get_cert( s ); X509_NAME *xn; if ( !x ) return LDAP_INVALID_CREDENTIALS; xn = X509_get_subject_name(x); #if OPENSSL_VERSION_NUMBER < 0x10100000 der_dn->bv_len = i2d_X509_NAME( xn, NULL ); der_dn->bv_val = xn->bytes->data; #else { size_t len = 0; der_dn->bv_val = NULL; X509_NAME_get0_der( xn, (const unsigned char **)&der_dn->bv_val, &len ); der_dn->bv_len = len; } #endif X509_free(x); return 0; } /* what kind of hostname were we given? */ #define IS_DNS 0 #define IS_IP4 1 #define IS_IP6 2 static int tlso_session_chkhost( LDAP *ld, tls_session *sess, const char *name_in ) { tlso_session *s = (tlso_session *)sess; int i, ret = LDAP_LOCAL_ERROR; int chkSAN = ld->ld_options.ldo_tls_require_san, gotSAN = 0; X509 *x; const char *name; char *ptr; int ntype = IS_DNS, nlen; #ifdef LDAP_PF_INET6 struct in6_addr addr; #else struct in_addr addr; #endif if( ldap_int_hostname && ( !name_in || !strcasecmp( name_in, "localhost" ) ) ) { name = ldap_int_hostname; } else { name = name_in; } nlen = strlen(name); x = tlso_get_cert(s); if (!x) { Debug0( LDAP_DEBUG_ANY, "TLS: unable to get peer certificate.\n" ); /* If this was a fatal condition, things would have * aborted long before now. */ return LDAP_SUCCESS; } #ifdef LDAP_PF_INET6 if (inet_pton(AF_INET6, name, &addr)) { ntype = IS_IP6; } else #endif if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) { if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4; } if (chkSAN) { i = X509_get_ext_by_NID(x, NID_subject_alt_name, -1); if (i >= 0) { X509_EXTENSION *ex; STACK_OF(GENERAL_NAME) *alt; ex = X509_get_ext(x, i); alt = X509V3_EXT_d2i(ex); if (alt) { int n, len2 = 0; char *domain = NULL; GENERAL_NAME *gn; gotSAN = 1; if (ntype == IS_DNS) { domain = strchr(name, '.'); if (domain) { len2 = nlen - (domain-name); } } n = sk_GENERAL_NAME_num(alt); for (i=0; itype == GEN_DNS) { if (ntype != IS_DNS) continue; sn = (char *) ASN1_STRING_data(gn->d.ia5); sl = ASN1_STRING_length(gn->d.ia5); /* ignore empty */ if (sl == 0) continue; /* Is this an exact match? */ if ((nlen == sl) && !strncasecmp(name, sn, nlen)) { break; } /* Is this a wildcard match? */ if (domain && (sn[0] == '*') && (sn[1] == '.') && (len2 == sl-1) && !strncasecmp(domain, &sn[1], len2)) { break; } } else if (gn->type == GEN_IPADD) { if (ntype == IS_DNS) continue; sn = (char *) ASN1_STRING_data(gn->d.ia5); sl = ASN1_STRING_length(gn->d.ia5); #ifdef LDAP_PF_INET6 if (ntype == IS_IP6 && sl != sizeof(struct in6_addr)) { continue; } else #endif if (ntype == IS_IP4 && sl != sizeof(struct in_addr)) { continue; } if (!memcmp(sn, &addr, sl)) { break; } } } GENERAL_NAMES_free(alt); if (i < n) { /* Found a match */ ret = LDAP_SUCCESS; } } } } if (ret != LDAP_SUCCESS && chkSAN) { switch(chkSAN) { case LDAP_OPT_X_TLS_DEMAND: case LDAP_OPT_X_TLS_HARD: if (!gotSAN) { Debug0( LDAP_DEBUG_ANY, "TLS: unable to get subjectAltName from peer certificate.\n" ); ret = LDAP_CONNECT_ERROR; if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } ld->ld_error = LDAP_STRDUP( _("TLS: unable to get subjectAltName from peer certificate")); goto done; } /* FALLTHRU */ case LDAP_OPT_X_TLS_TRY: if (gotSAN) { Debug1( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " "subjectAltName in certificate.\n", name ); ret = LDAP_CONNECT_ERROR; if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } ld->ld_error = LDAP_STRDUP( _("TLS: hostname does not match subjectAltName in peer certificate")); goto done; } break; case LDAP_OPT_X_TLS_ALLOW: break; } } if (ret != LDAP_SUCCESS) { X509_NAME *xn; X509_NAME_ENTRY *ne; ASN1_OBJECT *obj; ASN1_STRING *cn = NULL; int navas; /* find the last CN */ obj = OBJ_nid2obj( NID_commonName ); if ( !obj ) goto no_cn; /* should never happen */ xn = X509_get_subject_name(x); navas = X509_NAME_entry_count( xn ); for ( i=navas-1; i>=0; i-- ) { ne = X509_NAME_get_entry( xn, i ); if ( !OBJ_cmp( X509_NAME_ENTRY_get_object(ne), obj )) { cn = X509_NAME_ENTRY_get_data( ne ); break; } } if( !cn ) { no_cn: Debug0( LDAP_DEBUG_ANY, "TLS: unable to get common name from peer certificate.\n" ); ret = LDAP_CONNECT_ERROR; if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } ld->ld_error = LDAP_STRDUP( _("TLS: unable to get CN from peer certificate")); } else if ( cn->length == nlen && strncasecmp( name, (char *) cn->data, nlen ) == 0 ) { ret = LDAP_SUCCESS; } else if (( cn->data[0] == '*' ) && ( cn->data[1] == '.' )) { char *domain = strchr(name, '.'); if( domain ) { int dlen; dlen = nlen - (domain-name); /* Is this a wildcard match? */ if ((dlen == cn->length-1) && !strncasecmp(domain, (char *) &cn->data[1], dlen)) { ret = LDAP_SUCCESS; } } } if( ret == LDAP_LOCAL_ERROR ) { Debug3( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " "common name in certificate (%.*s).\n", name, cn->length, cn->data ); ret = LDAP_CONNECT_ERROR; if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } ld->ld_error = LDAP_STRDUP( _("TLS: hostname does not match name in peer certificate")); } } done: X509_free(x); return ret; } static int tlso_session_strength( tls_session *sess ) { tlso_session *s = (tlso_session *)sess; return SSL_CIPHER_get_bits(SSL_get_current_cipher(s), NULL); } static int tlso_session_unique( tls_session *sess, struct berval *buf, int is_server) { tlso_session *s = (tlso_session *)sess; /* Usually the client sends the finished msg. But if the * session was resumed, the server sent the msg. */ if (SSL_session_reused(s) ^ !is_server) buf->bv_len = SSL_get_finished(s, buf->bv_val, buf->bv_len); else buf->bv_len = SSL_get_peer_finished(s, buf->bv_val, buf->bv_len); return buf->bv_len; } static int tlso_session_endpoint( tls_session *sess, struct berval *buf, int is_server ) { tlso_session *s = (tlso_session *)sess; const EVP_MD *md; unsigned int md_len; X509 *cert; if ( buf->bv_len < EVP_MAX_MD_SIZE ) return 0; if ( is_server ) cert = SSL_get_certificate( s ); else cert = SSL_get_peer_certificate( s ); if ( cert == NULL ) return 0; #if OPENSSL_VERSION_NUMBER >= 0x10100000 md = EVP_get_digestbynid( X509_get_signature_nid( cert )); #else md = EVP_get_digestbynid(OBJ_obj2nid( cert->sig_alg->algorithm )); #endif /* See RFC 5929 */ if ( md == NULL || md == EVP_md_null() || #ifndef OPENSSL_NO_MD2 md == EVP_md2() || #endif md == EVP_md4() || md == EVP_md5() || md == EVP_sha1() ) md = EVP_sha256(); if ( !X509_digest( cert, md, (unsigned char *) (buf->bv_val), &md_len )) md_len = 0; buf->bv_len = md_len; if ( !is_server ) X509_free( cert ); return md_len; } static const char * tlso_session_version( tls_session *sess ) { tlso_session *s = (tlso_session *)sess; return SSL_get_version(s); } static const char * tlso_session_cipher( tls_session *sess ) { tlso_session *s = (tlso_session *)sess; return SSL_CIPHER_get_name(SSL_get_current_cipher(s)); } static int tlso_session_peercert( tls_session *sess, struct berval *der ) { tlso_session *s = (tlso_session *)sess; int ret = -1; X509 *x = SSL_get_peer_certificate(s); if ( x ) { der->bv_len = i2d_X509(x, NULL); der->bv_val = LDAP_MALLOC(der->bv_len); if ( der->bv_val ) { unsigned char *ptr = (unsigned char *) (der->bv_val); i2d_X509(x, &ptr); ret = 0; } X509_free( x ); } return ret; } static int tlso_session_pinning( LDAP *ld, tls_session *sess, char *hashalg, struct berval *hash ) { tlso_session *s = (tlso_session *)sess; unsigned char *tmp, digest[EVP_MAX_MD_SIZE]; struct berval key, keyhash = { sizeof(digest), (char *) digest }; X509 *cert = SSL_get_peer_certificate(s); int len, rc = LDAP_SUCCESS; if ( !cert ) return -1; len = i2d_X509_PUBKEY( X509_get_X509_PUBKEY(cert), NULL ); tmp = LDAP_MALLOC( len ); key.bv_val = (char *) tmp; if ( !key.bv_val ) { rc = -1; goto done; } key.bv_len = i2d_X509_PUBKEY( X509_get_X509_PUBKEY(cert), &tmp ); if ( hashalg ) { const EVP_MD *md; EVP_MD_CTX *mdctx; unsigned int len = keyhash.bv_len; md = EVP_get_digestbyname( hashalg ); if ( !md ) { Debug1( LDAP_DEBUG_TRACE, "tlso_session_pinning: " "hash %s not recognised by OpenSSL\n", hashalg ); rc = -1; goto done; } #if OPENSSL_VERSION_NUMBER >= 0x10100000 mdctx = EVP_MD_CTX_new(); #else mdctx = EVP_MD_CTX_create(); #endif if ( !mdctx ) { rc = -1; goto done; } EVP_DigestInit_ex( mdctx, md, NULL ); EVP_DigestUpdate( mdctx, key.bv_val, key.bv_len ); EVP_DigestFinal_ex( mdctx, (unsigned char *)keyhash.bv_val, &len ); keyhash.bv_len = len; #if OPENSSL_VERSION_NUMBER >= 0x10100000 EVP_MD_CTX_free( mdctx ); #else EVP_MD_CTX_destroy( mdctx ); #endif } else { keyhash = key; } if ( ber_bvcmp( hash, &keyhash ) ) { rc = LDAP_CONNECT_ERROR; Debug0( LDAP_DEBUG_ANY, "tlso_session_pinning: " "public key hash does not match provided pin.\n" ); if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } ld->ld_error = LDAP_STRDUP( _("TLS: public key hash does not match provided pin")); } done: LDAP_FREE( key.bv_val ); X509_free( cert ); return rc; } /* * TLS support for LBER Sockbufs */ struct tls_data { tlso_session *session; Sockbuf_IO_Desc *sbiod; }; #if OPENSSL_VERSION_NUMBER < 0x10100000 #define BIO_set_init(b, x) b->init = x #define BIO_set_data(b, x) b->ptr = x #define BIO_clear_flags(b, x) b->flags &= ~(x) #define BIO_get_data(b) b->ptr #endif static int tlso_bio_create( BIO *b ) { BIO_set_init( b, 1 ); BIO_set_data( b, NULL ); BIO_clear_flags( b, ~0 ); return 1; } static int tlso_bio_destroy( BIO *b ) { if ( b == NULL ) return 0; BIO_set_data( b, NULL ); /* sb_tls_remove() will free it */ BIO_set_init( b, 0 ); BIO_clear_flags( b, ~0 ); return 1; } static int tlso_bio_read( BIO *b, char *buf, int len ) { struct tls_data *p; int ret; if ( buf == NULL || len <= 0 ) return 0; p = (struct tls_data *)BIO_get_data(b); if ( p == NULL || p->sbiod == NULL ) { return 0; } ret = LBER_SBIOD_READ_NEXT( p->sbiod, buf, len ); BIO_clear_retry_flags( b ); if ( ret < 0 ) { int err = sock_errno(); if ( err == EAGAIN || err == EWOULDBLOCK ) { BIO_set_retry_read( b ); } } return ret; } static int tlso_bio_write( BIO *b, const char *buf, int len ) { struct tls_data *p; int ret; if ( buf == NULL || len <= 0 ) return 0; p = (struct tls_data *)BIO_get_data(b); if ( p == NULL || p->sbiod == NULL ) { return 0; } ret = LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len ); BIO_clear_retry_flags( b ); if ( ret < 0 ) { int err = sock_errno(); if ( err == EAGAIN || err == EWOULDBLOCK ) { BIO_set_retry_write( b ); } } return ret; } static long tlso_bio_ctrl( BIO *b, int cmd, long num, void *ptr ) { if ( cmd == BIO_CTRL_FLUSH ) { /* The OpenSSL library needs this */ return 1; } return 0; } static int tlso_bio_gets( BIO *b, char *buf, int len ) { return -1; } static int tlso_bio_puts( BIO *b, const char *str ) { return tlso_bio_write( b, str, strlen( str ) ); } static BIO_METHOD * tlso_bio_setup( void ) { /* it's a source/sink BIO */ BIO_METHOD * method = BIO_meth_new( 100 | 0x400, "sockbuf glue" ); BIO_meth_set_write( method, tlso_bio_write ); BIO_meth_set_read( method, tlso_bio_read ); BIO_meth_set_puts( method, tlso_bio_puts ); BIO_meth_set_gets( method, tlso_bio_gets ); BIO_meth_set_ctrl( method, tlso_bio_ctrl ); BIO_meth_set_create( method, tlso_bio_create ); BIO_meth_set_destroy( method, tlso_bio_destroy ); return method; } static int tlso_sb_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { struct tls_data *p; BIO *bio; assert( sbiod != NULL ); p = LBER_MALLOC( sizeof( *p ) ); if ( p == NULL ) { return -1; } p->session = arg; p->sbiod = sbiod; bio = BIO_new( tlso_bio_method ); BIO_set_data( bio, p ); SSL_set_bio( p->session, bio, bio ); sbiod->sbiod_pvt = p; return 0; } static int tlso_sb_remove( Sockbuf_IO_Desc *sbiod ) { struct tls_data *p; assert( sbiod != NULL ); assert( sbiod->sbiod_pvt != NULL ); p = (struct tls_data *)sbiod->sbiod_pvt; SSL_free( p->session ); LBER_FREE( sbiod->sbiod_pvt ); sbiod->sbiod_pvt = NULL; return 0; } static int tlso_sb_close( Sockbuf_IO_Desc *sbiod ) { struct tls_data *p; assert( sbiod != NULL ); assert( sbiod->sbiod_pvt != NULL ); p = (struct tls_data *)sbiod->sbiod_pvt; SSL_shutdown( p->session ); return 0; } static int tlso_sb_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { struct tls_data *p; assert( sbiod != NULL ); assert( sbiod->sbiod_pvt != NULL ); p = (struct tls_data *)sbiod->sbiod_pvt; if ( opt == LBER_SB_OPT_GET_SSL ) { *((tlso_session **)arg) = p->session; return 1; } else if ( opt == LBER_SB_OPT_DATA_READY ) { if( SSL_pending( p->session ) > 0 ) { return 1; } } return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); } static ber_slen_t tlso_sb_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) { struct tls_data *p; ber_slen_t ret; int err; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); p = (struct tls_data *)sbiod->sbiod_pvt; ret = SSL_read( p->session, (char *)buf, len ); #ifdef HAVE_WINSOCK errno = WSAGetLastError(); #endif err = SSL_get_error( p->session, ret ); if (err == SSL_ERROR_WANT_READ ) { sbiod->sbiod_sb->sb_trans_needs_read = 1; sock_errset(EWOULDBLOCK); } else sbiod->sbiod_sb->sb_trans_needs_read = 0; return ret; } static ber_slen_t tlso_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) { struct tls_data *p; ber_slen_t ret; int err; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); p = (struct tls_data *)sbiod->sbiod_pvt; ret = SSL_write( p->session, (char *)buf, len ); #ifdef HAVE_WINSOCK errno = WSAGetLastError(); #endif err = SSL_get_error( p->session, ret ); if (err == SSL_ERROR_WANT_WRITE ) { sbiod->sbiod_sb->sb_trans_needs_write = 1; sock_errset(EWOULDBLOCK); } else { sbiod->sbiod_sb->sb_trans_needs_write = 0; } return ret; } static Sockbuf_IO tlso_sbio = { tlso_sb_setup, /* sbi_setup */ tlso_sb_remove, /* sbi_remove */ tlso_sb_ctrl, /* sbi_ctrl */ tlso_sb_read, /* sbi_read */ tlso_sb_write, /* sbi_write */ tlso_sb_close /* sbi_close */ }; /* Derived from openssl/apps/s_cb.c */ static void tlso_info_cb( const SSL *ssl, int where, int ret ) { int w; char *op; char *state = (char *) SSL_state_string_long( (SSL *)ssl ); w = where & ~SSL_ST_MASK; if ( w & SSL_ST_CONNECT ) { op = "SSL_connect"; } else if ( w & SSL_ST_ACCEPT ) { op = "SSL_accept"; } else { op = "undefined"; } #ifdef HAVE_EBCDIC if ( state ) { state = LDAP_STRDUP( state ); __etoa( state ); } #endif if ( where & SSL_CB_LOOP ) { Debug2( LDAP_DEBUG_TRACE, "TLS trace: %s:%s\n", op, state ); } else if ( where & SSL_CB_ALERT ) { char *atype = (char *) SSL_alert_type_string_long( ret ); char *adesc = (char *) SSL_alert_desc_string_long( ret ); op = ( where & SSL_CB_READ ) ? "read" : "write"; #ifdef HAVE_EBCDIC if ( atype ) { atype = LDAP_STRDUP( atype ); __etoa( atype ); } if ( adesc ) { adesc = LDAP_STRDUP( adesc ); __etoa( adesc ); } #endif Debug3( LDAP_DEBUG_TRACE, "TLS trace: SSL3 alert %s:%s:%s\n", op, atype, adesc ); #ifdef HAVE_EBCDIC if ( atype ) LDAP_FREE( atype ); if ( adesc ) LDAP_FREE( adesc ); #endif } else if ( where & SSL_CB_EXIT ) { if ( ret == 0 ) { Debug2( LDAP_DEBUG_TRACE, "TLS trace: %s:failed in %s\n", op, state ); } else if ( ret < 0 ) { Debug2( LDAP_DEBUG_TRACE, "TLS trace: %s:error in %s\n", op, state ); } } #ifdef HAVE_EBCDIC if ( state ) LDAP_FREE( state ); #endif } static int tlso_verify_cb( int ok, X509_STORE_CTX *ctx ) { X509 *cert; int errnum; int errdepth; X509_NAME *subject; X509_NAME *issuer; char *sname; char *iname; char *certerr = NULL; cert = X509_STORE_CTX_get_current_cert( ctx ); errnum = X509_STORE_CTX_get_error( ctx ); errdepth = X509_STORE_CTX_get_error_depth( ctx ); /* * X509_get_*_name return pointers to the internal copies of * those things requested. So do not free them. */ subject = X509_get_subject_name( cert ); issuer = X509_get_issuer_name( cert ); /* X509_NAME_oneline, if passed a NULL buf, allocate memory */ sname = X509_NAME_oneline( subject, NULL, 0 ); iname = X509_NAME_oneline( issuer, NULL, 0 ); if ( !ok ) certerr = (char *)X509_verify_cert_error_string( errnum ); #ifdef HAVE_EBCDIC if ( sname ) __etoa( sname ); if ( iname ) __etoa( iname ); if ( certerr ) { certerr = LDAP_STRDUP( certerr ); __etoa( certerr ); } #endif Debug3( LDAP_DEBUG_TRACE, "TLS certificate verification: depth: %d, err: %d, subject: %s,", errdepth, errnum, sname ? sname : "-unknown-" ); Debug1( LDAP_DEBUG_TRACE, " issuer: %s\n", iname ? iname : "-unknown-" ); if ( !ok ) { Debug1( LDAP_DEBUG_ANY, "TLS certificate verification: Error, %s\n", certerr ); } if ( sname ) OPENSSL_free ( sname ); if ( iname ) OPENSSL_free ( iname ); #ifdef HAVE_EBCDIC if ( certerr ) LDAP_FREE( certerr ); #endif return ok; } static int tlso_verify_ok( int ok, X509_STORE_CTX *ctx ) { (void) tlso_verify_cb( ok, ctx ); return 1; } /* Inspired by ERR_print_errors in OpenSSL */ static void tlso_report_error( void ) { unsigned long l; char buf[200]; const char *file; int line; while ( ( l = ERR_get_error_line( &file, &line ) ) != 0 ) { ERR_error_string_n( l, buf, sizeof( buf ) ); #ifdef HAVE_EBCDIC if ( file ) { file = LDAP_STRDUP( file ); __etoa( (char *)file ); } __etoa( buf ); #endif Debug3( LDAP_DEBUG_ANY, "TLS: %s %s:%d\n", buf, file, line ); #ifdef HAVE_EBCDIC if ( file ) LDAP_FREE( (void *)file ); #endif } } #if OPENSSL_VERSION_NUMBER < 0x10100000 static RSA * tlso_tmp_rsa_cb( SSL *ssl, int is_export, int key_length ) { RSA *tmp_rsa; /* FIXME: Pregenerate the key on startup */ /* FIXME: Who frees the key? */ BIGNUM *bn = BN_new(); tmp_rsa = NULL; if ( bn ) { if ( BN_set_word( bn, RSA_F4 )) { tmp_rsa = RSA_new(); if ( tmp_rsa && !RSA_generate_key_ex( tmp_rsa, key_length, bn, NULL )) { RSA_free( tmp_rsa ); tmp_rsa = NULL; } } BN_free( bn ); } if ( !tmp_rsa ) { Debug2( LDAP_DEBUG_ANY, "TLS: Failed to generate temporary %d-bit %s RSA key\n", key_length, is_export ? "export" : "domestic" ); } return tmp_rsa; } #endif /* OPENSSL_VERSION_NUMBER < 1.1 */ static int tlso_seed_PRNG( const char *randfile ) { #ifndef URANDOM_DEVICE /* no /dev/urandom (or equiv) */ long total=0; char buffer[MAXPATHLEN]; if (randfile == NULL) { /* The seed file is $RANDFILE if defined, otherwise $HOME/.rnd. * If $HOME is not set or buffer too small to hold the pathname, * an error occurs. - From RAND_file_name() man page. * The fact is that when $HOME is NULL, .rnd is used. */ randfile = RAND_file_name( buffer, sizeof( buffer ) ); } #ifndef OPENSSL_NO_EGD else if (RAND_egd(randfile) > 0) { /* EGD socket */ return 0; } #endif if (randfile == NULL) { Debug0( LDAP_DEBUG_ANY, "TLS: Use configuration file or $RANDFILE to define seed PRNG\n" ); return -1; } total = RAND_load_file(randfile, -1); if (RAND_status() == 0) { Debug0( LDAP_DEBUG_ANY, "TLS: PRNG not been seeded with enough data\n" ); return -1; } /* assume if there was enough bits to seed that it's okay * to write derived bits to the file */ RAND_write_file(randfile); #endif return 0; } tls_impl ldap_int_tls_impl = { "OpenSSL", tlso_init, tlso_destroy, tlso_ctx_new, tlso_ctx_ref, tlso_ctx_free, tlso_ctx_init, tlso_session_new, tlso_session_connect, tlso_session_accept, tlso_session_upflags, tlso_session_errmsg, tlso_session_my_dn, tlso_session_peer_dn, tlso_session_chkhost, tlso_session_strength, tlso_session_unique, tlso_session_endpoint, tlso_session_version, tlso_session_cipher, tlso_session_peercert, tlso_session_pinning, &tlso_sbio, #ifdef LDAP_R_COMPILE tlso_thr_init, #else NULL, #endif 0 }; #endif /* HAVE_OPENSSL */ openldap-2.5.11+dfsg/libraries/libldap/schema.c0000644000175000017500000021714514172327167020040 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* * schema.c: parsing routines used by servers and clients to process * schema definitions */ #include "portable.h" #include #include #include #include #include "ldap-int.h" #include static const char EndOfInput[] = "end of input"; static const char * choose_name( char *names[], const char *fallback ) { return (names != NULL && names[0] != NULL) ? names[0] : fallback; } LDAP_CONST char * ldap_syntax2name( LDAPSyntax * syn ) { if (!syn) return NULL; return( syn->syn_oid ); } LDAP_CONST char * ldap_matchingrule2name( LDAPMatchingRule * mr ) { if (!mr) return NULL; return( choose_name( mr->mr_names, mr->mr_oid ) ); } LDAP_CONST char * ldap_matchingruleuse2name( LDAPMatchingRuleUse * mru ) { if (!mru) return NULL; return( choose_name( mru->mru_names, mru->mru_oid ) ); } LDAP_CONST char * ldap_attributetype2name( LDAPAttributeType * at ) { if (!at) return NULL; return( choose_name( at->at_names, at->at_oid ) ); } LDAP_CONST char * ldap_objectclass2name( LDAPObjectClass * oc ) { if (!oc) return NULL; return( choose_name( oc->oc_names, oc->oc_oid ) ); } LDAP_CONST char * ldap_contentrule2name( LDAPContentRule * cr ) { if (!cr) return NULL; return( choose_name( cr->cr_names, cr->cr_oid ) ); } LDAP_CONST char * ldap_nameform2name( LDAPNameForm * nf ) { if (!nf) return NULL; return( choose_name( nf->nf_names, nf->nf_oid ) ); } LDAP_CONST char * ldap_structurerule2name( LDAPStructureRule * sr ) { if (!sr) return NULL; return( choose_name( sr->sr_names, NULL ) ); } /* * When pretty printing the entities we will be appending to a buffer. * Since checking for overflow, realloc'ing and checking if no error * is extremely boring, we will use a protection layer that will let * us blissfully ignore the error until the end. This layer is * implemented with the help of the next type. */ typedef struct safe_string { char * val; ber_len_t size; ber_len_t pos; int at_whsp; } safe_string; static safe_string * new_safe_string(int size) { safe_string * ss; ss = LDAP_MALLOC(sizeof(safe_string)); if ( !ss ) return(NULL); ss->val = LDAP_MALLOC(size); if ( !ss->val ) { LDAP_FREE(ss); return(NULL); } ss->size = size; ss->pos = 0; ss->at_whsp = 0; return ss; } static void safe_string_free(safe_string * ss) { if ( !ss ) return; LDAP_FREE(ss->val); LDAP_FREE(ss); } #if 0 /* unused */ static char * safe_string_val(safe_string * ss) { ss->val[ss->pos] = '\0'; return(ss->val); } #endif static char * safe_strdup(safe_string * ss) { char *ret = LDAP_MALLOC(ss->pos+1); if (!ret) return NULL; AC_MEMCPY(ret, ss->val, ss->pos); ret[ss->pos] = '\0'; return ret; } static int append_to_safe_string(safe_string * ss, char * s) { int l = strlen(s); char * temp; /* * Some runaway process is trying to append to a string that * overflowed and we could not extend. */ if ( !ss->val ) return -1; /* We always make sure there is at least one position available */ if ( ss->pos + l >= ss->size-1 ) { ss->size *= 2; if ( ss->pos + l >= ss->size-1 ) { ss->size = ss->pos + l + 1; } temp = LDAP_REALLOC(ss->val, ss->size); if ( !temp ) { /* Trouble, out of memory */ LDAP_FREE(ss->val); return -1; } ss->val = temp; } strncpy(&ss->val[ss->pos], s, l); ss->pos += l; if ( ss->pos > 0 && LDAP_SPACE(ss->val[ss->pos-1]) ) ss->at_whsp = 1; else ss->at_whsp = 0; return 0; } static int print_literal(safe_string *ss, char *s) { return(append_to_safe_string(ss,s)); } static int print_whsp(safe_string *ss) { if ( ss->at_whsp ) return(append_to_safe_string(ss,"")); else return(append_to_safe_string(ss," ")); } static int print_numericoid(safe_string *ss, char *s) { if ( s ) return(append_to_safe_string(ss,s)); else return(append_to_safe_string(ss,"")); } /* This one is identical to print_qdescr */ static int print_qdstring(safe_string *ss, char *s) { print_whsp(ss); print_literal(ss,"'"); append_to_safe_string(ss,s); print_literal(ss,"'"); return(print_whsp(ss)); } static int print_qdescr(safe_string *ss, char *s) { print_whsp(ss); print_literal(ss,"'"); append_to_safe_string(ss,s); print_literal(ss,"'"); return(print_whsp(ss)); } static int print_qdescrlist(safe_string *ss, char **sa) { char **sp; int ret = 0; for (sp=sa; *sp; sp++) { ret = print_qdescr(ss,*sp); } /* If the list was empty, we return zero that is potentially * incorrect, but since we will be still appending things, the * overflow will be detected later. Maybe FIX. */ return(ret); } static int print_qdescrs(safe_string *ss, char **sa) { /* The only way to represent an empty list is as a qdescrlist * so, if the list is empty we treat it as a long list. * Really, this is what the syntax mandates. We should not * be here if the list was empty, but if it happens, a label * has already been output and we cannot undo it. */ if ( !sa[0] || ( sa[0] && sa[1] ) ) { print_whsp(ss); print_literal(ss,"("/*)*/); print_qdescrlist(ss,sa); print_literal(ss,/*(*/")"); return(print_whsp(ss)); } else { return(print_qdescr(ss,*sa)); } } static int print_woid(safe_string *ss, char *s) { print_whsp(ss); append_to_safe_string(ss,s); return print_whsp(ss); } static int print_oidlist(safe_string *ss, char **sa) { char **sp; for (sp=sa; *(sp+1); sp++) { print_woid(ss,*sp); print_literal(ss,"$"); } return(print_woid(ss,*sp)); } static int print_oids(safe_string *ss, char **sa) { if ( sa[0] && sa[1] ) { print_literal(ss,"("/*)*/); print_oidlist(ss,sa); print_whsp(ss); return(print_literal(ss,/*(*/")")); } else { return(print_woid(ss,*sa)); } } static int print_noidlen(safe_string *ss, char *s, int l) { char buf[64]; int ret; ret = print_numericoid(ss,s); if ( l ) { snprintf(buf, sizeof buf, "{%d}",l); ret = print_literal(ss,buf); } return(ret); } static int print_ruleid(safe_string *ss, int rid) { char buf[64]; snprintf(buf, sizeof buf, "%d", rid); return print_literal(ss,buf); } static int print_ruleids(safe_string *ss, int n, int *rids) { int i; if( n == 1 ) { print_ruleid(ss,rids[0]); return print_whsp(ss); } else { print_literal(ss,"("/*)*/); for( i=0; ilsei_name); print_whsp(ss); /* Should be print_qdstrings */ print_qdescrs(ss, (*ext)->lsei_values); print_whsp(ss); } } return 0; } char * ldap_syntax2str( LDAPSyntax * syn ) { struct berval bv; if (ldap_syntax2bv( syn, &bv )) return(bv.bv_val); else return NULL; } struct berval * ldap_syntax2bv( LDAPSyntax * syn, struct berval *bv ) { safe_string * ss; if ( !syn || !bv ) return NULL; ss = new_safe_string(256); if ( !ss ) return NULL; print_literal(ss,"("/*)*/); print_whsp(ss); print_numericoid(ss, syn->syn_oid); print_whsp(ss); if ( syn->syn_desc ) { print_literal(ss,"DESC"); print_qdstring(ss,syn->syn_desc); } print_whsp(ss); print_extensions(ss, syn->syn_extensions); print_literal(ss,/*(*/ ")"); bv->bv_val = safe_strdup(ss); bv->bv_len = ss->pos; safe_string_free(ss); return(bv); } char * ldap_matchingrule2str( LDAPMatchingRule * mr ) { struct berval bv; if (ldap_matchingrule2bv( mr, &bv )) return(bv.bv_val); else return NULL; } struct berval * ldap_matchingrule2bv( LDAPMatchingRule * mr, struct berval *bv ) { safe_string * ss; if ( !mr || !bv ) return NULL; ss = new_safe_string(256); if ( !ss ) return NULL; print_literal(ss,"(" /*)*/); print_whsp(ss); print_numericoid(ss, mr->mr_oid); print_whsp(ss); if ( mr->mr_names ) { print_literal(ss,"NAME"); print_qdescrs(ss,mr->mr_names); } if ( mr->mr_desc ) { print_literal(ss,"DESC"); print_qdstring(ss,mr->mr_desc); } if ( mr->mr_obsolete ) { print_literal(ss, "OBSOLETE"); print_whsp(ss); } if ( mr->mr_syntax_oid ) { print_literal(ss,"SYNTAX"); print_whsp(ss); print_literal(ss, mr->mr_syntax_oid); print_whsp(ss); } print_whsp(ss); print_extensions(ss, mr->mr_extensions); print_literal(ss,/*(*/")"); bv->bv_val = safe_strdup(ss); bv->bv_len = ss->pos; safe_string_free(ss); return(bv); } char * ldap_matchingruleuse2str( LDAPMatchingRuleUse * mru ) { struct berval bv; if (ldap_matchingruleuse2bv( mru, &bv )) return(bv.bv_val); else return NULL; } struct berval * ldap_matchingruleuse2bv( LDAPMatchingRuleUse * mru, struct berval *bv ) { safe_string * ss; if ( !mru || !bv ) return NULL; ss = new_safe_string(256); if ( !ss ) return NULL; print_literal(ss,"(" /*)*/); print_whsp(ss); print_numericoid(ss, mru->mru_oid); print_whsp(ss); if ( mru->mru_names ) { print_literal(ss,"NAME"); print_qdescrs(ss,mru->mru_names); } if ( mru->mru_desc ) { print_literal(ss,"DESC"); print_qdstring(ss,mru->mru_desc); } if ( mru->mru_obsolete ) { print_literal(ss, "OBSOLETE"); print_whsp(ss); } if ( mru->mru_applies_oids ) { print_literal(ss,"APPLIES"); print_whsp(ss); print_oids(ss, mru->mru_applies_oids); print_whsp(ss); } print_whsp(ss); print_extensions(ss, mru->mru_extensions); print_literal(ss,/*(*/")"); bv->bv_val = safe_strdup(ss); bv->bv_len = ss->pos; safe_string_free(ss); return(bv); } char * ldap_objectclass2str( LDAPObjectClass * oc ) { struct berval bv; if (ldap_objectclass2bv( oc, &bv )) return(bv.bv_val); else return NULL; } struct berval * ldap_objectclass2bv( LDAPObjectClass * oc, struct berval *bv ) { safe_string * ss; if ( !oc || !bv ) return NULL; ss = new_safe_string(256); if ( !ss ) return NULL; print_literal(ss,"("/*)*/); print_whsp(ss); print_numericoid(ss, oc->oc_oid); print_whsp(ss); if ( oc->oc_names ) { print_literal(ss,"NAME"); print_qdescrs(ss,oc->oc_names); } if ( oc->oc_desc ) { print_literal(ss,"DESC"); print_qdstring(ss,oc->oc_desc); } if ( oc->oc_obsolete ) { print_literal(ss, "OBSOLETE"); print_whsp(ss); } if ( oc->oc_sup_oids ) { print_literal(ss,"SUP"); print_whsp(ss); print_oids(ss,oc->oc_sup_oids); print_whsp(ss); } switch (oc->oc_kind) { case LDAP_SCHEMA_ABSTRACT: print_literal(ss,"ABSTRACT"); break; case LDAP_SCHEMA_STRUCTURAL: print_literal(ss,"STRUCTURAL"); break; case LDAP_SCHEMA_AUXILIARY: print_literal(ss,"AUXILIARY"); break; default: print_literal(ss,"KIND-UNKNOWN"); break; } print_whsp(ss); if ( oc->oc_at_oids_must ) { print_literal(ss,"MUST"); print_whsp(ss); print_oids(ss,oc->oc_at_oids_must); print_whsp(ss); } if ( oc->oc_at_oids_may ) { print_literal(ss,"MAY"); print_whsp(ss); print_oids(ss,oc->oc_at_oids_may); print_whsp(ss); } print_whsp(ss); print_extensions(ss, oc->oc_extensions); print_literal(ss, /*(*/")"); bv->bv_val = safe_strdup(ss); bv->bv_len = ss->pos; safe_string_free(ss); return(bv); } char * ldap_contentrule2str( LDAPContentRule * cr ) { struct berval bv; if (ldap_contentrule2bv( cr, &bv )) return(bv.bv_val); else return NULL; } struct berval * ldap_contentrule2bv( LDAPContentRule * cr, struct berval *bv ) { safe_string * ss; if ( !cr || !bv ) return NULL; ss = new_safe_string(256); if ( !ss ) return NULL; print_literal(ss,"("/*)*/); print_whsp(ss); print_numericoid(ss, cr->cr_oid); print_whsp(ss); if ( cr->cr_names ) { print_literal(ss,"NAME"); print_qdescrs(ss,cr->cr_names); } if ( cr->cr_desc ) { print_literal(ss,"DESC"); print_qdstring(ss,cr->cr_desc); } if ( cr->cr_obsolete ) { print_literal(ss, "OBSOLETE"); print_whsp(ss); } if ( cr->cr_oc_oids_aux ) { print_literal(ss,"AUX"); print_whsp(ss); print_oids(ss,cr->cr_oc_oids_aux); print_whsp(ss); } if ( cr->cr_at_oids_must ) { print_literal(ss,"MUST"); print_whsp(ss); print_oids(ss,cr->cr_at_oids_must); print_whsp(ss); } if ( cr->cr_at_oids_may ) { print_literal(ss,"MAY"); print_whsp(ss); print_oids(ss,cr->cr_at_oids_may); print_whsp(ss); } if ( cr->cr_at_oids_not ) { print_literal(ss,"NOT"); print_whsp(ss); print_oids(ss,cr->cr_at_oids_not); print_whsp(ss); } print_whsp(ss); print_extensions(ss, cr->cr_extensions); print_literal(ss, /*(*/")"); bv->bv_val = safe_strdup(ss); bv->bv_len = ss->pos; safe_string_free(ss); return(bv); } char * ldap_structurerule2str( LDAPStructureRule * sr ) { struct berval bv; if (ldap_structurerule2bv( sr, &bv )) return(bv.bv_val); else return NULL; } struct berval * ldap_structurerule2bv( LDAPStructureRule * sr, struct berval *bv ) { safe_string * ss; if ( !sr || !bv ) return NULL; ss = new_safe_string(256); if ( !ss ) return NULL; print_literal(ss,"("/*)*/); print_whsp(ss); print_ruleid(ss, sr->sr_ruleid); print_whsp(ss); if ( sr->sr_names ) { print_literal(ss,"NAME"); print_qdescrs(ss,sr->sr_names); } if ( sr->sr_desc ) { print_literal(ss,"DESC"); print_qdstring(ss,sr->sr_desc); } if ( sr->sr_obsolete ) { print_literal(ss, "OBSOLETE"); print_whsp(ss); } print_literal(ss,"FORM"); print_whsp(ss); print_woid(ss,sr->sr_nameform); print_whsp(ss); if ( sr->sr_nsup_ruleids ) { print_literal(ss,"SUP"); print_whsp(ss); print_ruleids(ss,sr->sr_nsup_ruleids,sr->sr_sup_ruleids); print_whsp(ss); } print_whsp(ss); print_extensions(ss, sr->sr_extensions); print_literal(ss, /*(*/")"); bv->bv_val = safe_strdup(ss); bv->bv_len = ss->pos; safe_string_free(ss); return(bv); } char * ldap_nameform2str( LDAPNameForm * nf ) { struct berval bv; if (ldap_nameform2bv( nf, &bv )) return(bv.bv_val); else return NULL; } struct berval * ldap_nameform2bv( LDAPNameForm * nf, struct berval *bv ) { safe_string * ss; if ( !nf || !bv ) return NULL; ss = new_safe_string(256); if ( !ss ) return NULL; print_literal(ss,"("/*)*/); print_whsp(ss); print_numericoid(ss, nf->nf_oid); print_whsp(ss); if ( nf->nf_names ) { print_literal(ss,"NAME"); print_qdescrs(ss,nf->nf_names); } if ( nf->nf_desc ) { print_literal(ss,"DESC"); print_qdstring(ss,nf->nf_desc); } if ( nf->nf_obsolete ) { print_literal(ss, "OBSOLETE"); print_whsp(ss); } print_literal(ss,"OC"); print_whsp(ss); print_woid(ss,nf->nf_objectclass); print_whsp(ss); print_literal(ss,"MUST"); print_whsp(ss); print_oids(ss,nf->nf_at_oids_must); print_whsp(ss); if ( nf->nf_at_oids_may ) { print_literal(ss,"MAY"); print_whsp(ss); print_oids(ss,nf->nf_at_oids_may); print_whsp(ss); } print_whsp(ss); print_extensions(ss, nf->nf_extensions); print_literal(ss, /*(*/")"); bv->bv_val = safe_strdup(ss); bv->bv_len = ss->pos; safe_string_free(ss); return(bv); } char * ldap_attributetype2str( LDAPAttributeType * at ) { struct berval bv; if (ldap_attributetype2bv( at, &bv )) return(bv.bv_val); else return NULL; } struct berval * ldap_attributetype2bv( LDAPAttributeType * at, struct berval *bv ) { safe_string * ss; if ( !at || !bv ) return NULL; ss = new_safe_string(256); if ( !ss ) return NULL; print_literal(ss,"("/*)*/); print_whsp(ss); print_numericoid(ss, at->at_oid); print_whsp(ss); if ( at->at_names ) { print_literal(ss,"NAME"); print_qdescrs(ss,at->at_names); } if ( at->at_desc ) { print_literal(ss,"DESC"); print_qdstring(ss,at->at_desc); } if ( at->at_obsolete ) { print_literal(ss, "OBSOLETE"); print_whsp(ss); } if ( at->at_sup_oid ) { print_literal(ss,"SUP"); print_woid(ss,at->at_sup_oid); } if ( at->at_equality_oid ) { print_literal(ss,"EQUALITY"); print_woid(ss,at->at_equality_oid); } if ( at->at_ordering_oid ) { print_literal(ss,"ORDERING"); print_woid(ss,at->at_ordering_oid); } if ( at->at_substr_oid ) { print_literal(ss,"SUBSTR"); print_woid(ss,at->at_substr_oid); } if ( at->at_syntax_oid ) { print_literal(ss,"SYNTAX"); print_whsp(ss); print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len); print_whsp(ss); } if ( at->at_single_value == LDAP_SCHEMA_YES ) { print_literal(ss,"SINGLE-VALUE"); print_whsp(ss); } if ( at->at_collective == LDAP_SCHEMA_YES ) { print_literal(ss,"COLLECTIVE"); print_whsp(ss); } if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) { print_literal(ss,"NO-USER-MODIFICATION"); print_whsp(ss); } if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) { print_literal(ss,"USAGE"); print_whsp(ss); switch (at->at_usage) { case LDAP_SCHEMA_DIRECTORY_OPERATION: print_literal(ss,"directoryOperation"); break; case LDAP_SCHEMA_DISTRIBUTED_OPERATION: print_literal(ss,"distributedOperation"); break; case LDAP_SCHEMA_DSA_OPERATION: print_literal(ss,"dSAOperation"); break; default: print_literal(ss,"UNKNOWN"); break; } } print_whsp(ss); print_extensions(ss, at->at_extensions); print_literal(ss,/*(*/")"); bv->bv_val = safe_strdup(ss); bv->bv_len = ss->pos; safe_string_free(ss); return(bv); } /* * Now come the parsers. There is one parser for each entity type: * objectclasses, attributetypes, etc. * * Each of them is written as a recursive-descent parser, except that * none of them is really recursive. But the idea is kept: there * is one routine per non-terminal that either gobbles lexical tokens * or calls lower-level routines, etc. * * The scanner is implemented in the routine get_token. Actually, * get_token is more than a scanner and will return tokens that are * in fact non-terminals in the grammar. So you can see the whole * approach as the combination of a low-level bottom-up recognizer * combined with a scanner and a number of top-down parsers. Or just * consider that the real grammars recognized by the parsers are not * those of the standards. As a matter of fact, our parsers are more * liberal than the spec when there is no ambiguity. * * The difference is pretty academic (modulo bugs or incorrect * interpretation of the specs). */ typedef enum tk_t { TK_NOENDQUOTE = -2, TK_OUTOFMEM = -1, TK_EOS = 0, TK_UNEXPCHAR = 1, TK_BAREWORD = 2, TK_QDSTRING = 3, TK_LEFTPAREN = 4, TK_RIGHTPAREN = 5, TK_DOLLAR = 6, TK_QDESCR = TK_QDSTRING } tk_t; static tk_t get_token( const char ** sp, char ** token_val ) { tk_t kind; const char * p; const char * q; char * res; *token_val = NULL; switch (**sp) { case '\0': kind = TK_EOS; (*sp)++; break; case '(': kind = TK_LEFTPAREN; (*sp)++; break; case ')': kind = TK_RIGHTPAREN; (*sp)++; break; case '$': kind = TK_DOLLAR; (*sp)++; break; case '\'': kind = TK_QDSTRING; (*sp)++; p = *sp; while ( **sp != '\'' && **sp != '\0' ) (*sp)++; if ( **sp == '\'' ) { q = *sp; res = LDAP_MALLOC(q-p+1); if ( !res ) { kind = TK_OUTOFMEM; } else { strncpy(res,p,q-p); res[q-p] = '\0'; *token_val = res; } (*sp)++; } else { kind = TK_NOENDQUOTE; } break; default: kind = TK_BAREWORD; p = *sp; while ( !LDAP_SPACE(**sp) && **sp != '(' && **sp != ')' && **sp != '$' && **sp != '\'' && /* for suggested minimum upper bound on the number * of characters (RFC 4517) */ **sp != '{' && **sp != '\0' ) (*sp)++; q = *sp; res = LDAP_MALLOC(q-p+1); if ( !res ) { kind = TK_OUTOFMEM; } else { strncpy(res,p,q-p); res[q-p] = '\0'; *token_val = res; } break; /* kind = TK_UNEXPCHAR; */ /* break; */ } return kind; } /* Gobble optional whitespace */ static void parse_whsp(const char **sp) { while (LDAP_SPACE(**sp)) (*sp)++; } /* TBC:!! * General note for all parsers: to guarantee the algorithm halts they * must always advance the pointer even when an error is found. For * this one is not that important since an error here is fatal at the * upper layers, but it is a simple strategy that will not get in * endless loops. */ /* Parse a sequence of dot-separated decimal strings */ char * ldap_int_parse_numericoid(const char **sp, int *code, const int flags) { char * res = NULL; const char * start = *sp; int len; int quoted = 0; /* Netscape puts the SYNTAX value in quotes (incorrectly) */ if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && **sp == '\'' ) { quoted = 1; (*sp)++; start++; } /* Each iteration of this loop gets one decimal string */ while (**sp) { if ( !LDAP_DIGIT(**sp) ) { /* * Initial char is not a digit or char after dot is * not a digit */ *code = LDAP_SCHERR_NODIGIT; return NULL; } (*sp)++; while ( LDAP_DIGIT(**sp) ) (*sp)++; if ( **sp != '.' ) break; /* Otherwise, gobble the dot and loop again */ (*sp)++; } /* Now *sp points at the char past the numericoid. Perfect. */ len = *sp - start; if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted ) { if ( **sp == '\'' ) { (*sp)++; } else { *code = LDAP_SCHERR_UNEXPTOKEN; return NULL; } } if (flags & LDAP_SCHEMA_SKIP) { res = (char *)start; } else { res = LDAP_MALLOC(len+1); if (!res) { *code = LDAP_SCHERR_OUTOFMEM; return(NULL); } strncpy(res,start,len); res[len] = '\0'; } return(res); } /* Parse a sequence of dot-separated decimal strings */ int ldap_int_parse_ruleid(const char **sp, int *code, const int flags, int *ruleid) { *ruleid=0; if ( !LDAP_DIGIT(**sp) ) { *code = LDAP_SCHERR_NODIGIT; return -1; } *ruleid = (**sp) - '0'; (*sp)++; while ( LDAP_DIGIT(**sp) ) { *ruleid *= 10; *ruleid += (**sp) - '0'; (*sp)++; } return 0; } /* Parse a qdescr or a list of them enclosed in () */ static char ** parse_qdescrs(const char **sp, int *code) { char ** res; char ** res1; tk_t kind; char * sval; int size; int pos; parse_whsp(sp); kind = get_token(sp,&sval); if ( kind == TK_LEFTPAREN ) { /* Let's presume there will be at least 2 entries */ size = 3; res = LDAP_CALLOC(3,sizeof(char *)); if ( !res ) { *code = LDAP_SCHERR_OUTOFMEM; return NULL; } pos = 0; while (1) { parse_whsp(sp); kind = get_token(sp,&sval); if ( kind == TK_RIGHTPAREN ) break; if ( kind == TK_QDESCR ) { if ( pos == size-2 ) { size++; res1 = LDAP_REALLOC(res,size*sizeof(char *)); if ( !res1 ) { LDAP_VFREE(res); LDAP_FREE(sval); *code = LDAP_SCHERR_OUTOFMEM; return(NULL); } res = res1; } res[pos++] = sval; res[pos] = NULL; parse_whsp(sp); } else { LDAP_VFREE(res); LDAP_FREE(sval); *code = LDAP_SCHERR_UNEXPTOKEN; return(NULL); } } parse_whsp(sp); return(res); } else if ( kind == TK_QDESCR ) { res = LDAP_CALLOC(2,sizeof(char *)); if ( !res ) { *code = LDAP_SCHERR_OUTOFMEM; return NULL; } res[0] = sval; res[1] = NULL; parse_whsp(sp); return res; } else { LDAP_FREE(sval); *code = LDAP_SCHERR_BADNAME; return NULL; } } /* Parse a woid */ static char * parse_woid(const char **sp, int *code) { char * sval; tk_t kind; parse_whsp(sp); kind = get_token(sp, &sval); if ( kind != TK_BAREWORD ) { LDAP_FREE(sval); *code = LDAP_SCHERR_UNEXPTOKEN; return NULL; } parse_whsp(sp); return sval; } /* Parse a noidlen */ static char * parse_noidlen(const char **sp, int *code, int *len, int flags) { char * sval; const char *savepos; int quoted = 0; int allow_quoted = ( flags & LDAP_SCHEMA_ALLOW_QUOTED ); int allow_oidmacro = ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ); *len = 0; /* Netscape puts the SYNTAX value in quotes (incorrectly) */ if ( allow_quoted && **sp == '\'' ) { quoted = 1; (*sp)++; } savepos = *sp; sval = ldap_int_parse_numericoid(sp, code, 0); if ( !sval ) { if ( allow_oidmacro && *sp == savepos && *code == LDAP_SCHERR_NODIGIT ) { if ( get_token(sp, &sval) != TK_BAREWORD ) { if ( sval != NULL ) { LDAP_FREE(sval); } return NULL; } } else { return NULL; } } if ( **sp == '{' /*}*/ ) { (*sp)++; *len = atoi(*sp); while ( LDAP_DIGIT(**sp) ) (*sp)++; if ( **sp != /*{*/ '}' ) { *code = LDAP_SCHERR_UNEXPTOKEN; LDAP_FREE(sval); return NULL; } (*sp)++; } if ( allow_quoted && quoted ) { if ( **sp == '\'' ) { (*sp)++; } else { *code = LDAP_SCHERR_UNEXPTOKEN; LDAP_FREE(sval); return NULL; } } return sval; } /* * Next routine will accept a qdstring in place of an oid if * allow_quoted is set. This is necessary to interoperate with * Netscape Directory server that will improperly quote each oid (at * least those of the descr kind) in the SUP clause. */ /* Parse a woid or a $-separated list of them enclosed in () */ static char ** parse_oids(const char **sp, int *code, const int allow_quoted) { char ** res; char ** res1; tk_t kind; char * sval; int size; int pos; /* * Strictly speaking, doing this here accepts whsp before the * ( at the beginning of an oidlist, but this is harmless. Also, * we are very liberal in what we accept as an OID. Maybe * refine later. */ parse_whsp(sp); kind = get_token(sp,&sval); if ( kind == TK_LEFTPAREN ) { /* Let's presume there will be at least 2 entries */ size = 3; res = LDAP_CALLOC(3,sizeof(char *)); if ( !res ) { *code = LDAP_SCHERR_OUTOFMEM; return NULL; } pos = 0; parse_whsp(sp); kind = get_token(sp,&sval); if ( kind == TK_BAREWORD || ( allow_quoted && kind == TK_QDSTRING ) ) { res[pos++] = sval; res[pos] = NULL; } else if ( kind == TK_RIGHTPAREN ) { /* FIXME: be liberal in what we accept... */ parse_whsp(sp); LDAP_FREE(res); return NULL; } else { *code = LDAP_SCHERR_UNEXPTOKEN; LDAP_FREE(sval); LDAP_VFREE(res); return NULL; } parse_whsp(sp); while (1) { kind = get_token(sp,&sval); if ( kind == TK_RIGHTPAREN ) break; if ( kind == TK_DOLLAR ) { parse_whsp(sp); kind = get_token(sp,&sval); if ( kind == TK_BAREWORD || ( allow_quoted && kind == TK_QDSTRING ) ) { if ( pos == size-2 ) { size++; res1 = LDAP_REALLOC(res,size*sizeof(char *)); if ( !res1 ) { LDAP_FREE(sval); LDAP_VFREE(res); *code = LDAP_SCHERR_OUTOFMEM; return(NULL); } res = res1; } res[pos++] = sval; res[pos] = NULL; } else { *code = LDAP_SCHERR_UNEXPTOKEN; LDAP_FREE(sval); LDAP_VFREE(res); return NULL; } parse_whsp(sp); } else { *code = LDAP_SCHERR_UNEXPTOKEN; LDAP_FREE(sval); LDAP_VFREE(res); return NULL; } } parse_whsp(sp); return(res); } else if ( kind == TK_BAREWORD || ( allow_quoted && kind == TK_QDSTRING ) ) { res = LDAP_CALLOC(2,sizeof(char *)); if ( !res ) { LDAP_FREE(sval); *code = LDAP_SCHERR_OUTOFMEM; return NULL; } res[0] = sval; res[1] = NULL; parse_whsp(sp); return res; } else { LDAP_FREE(sval); *code = LDAP_SCHERR_BADNAME; return NULL; } } static int add_extension(LDAPSchemaExtensionItem ***extensions, char * name, char ** values) { int n; LDAPSchemaExtensionItem **tmp, *ext; ext = LDAP_CALLOC(1, sizeof(LDAPSchemaExtensionItem)); if ( !ext ) return 1; ext->lsei_name = name; ext->lsei_values = values; if ( !*extensions ) { *extensions = LDAP_CALLOC(2, sizeof(LDAPSchemaExtensionItem *)); if ( !*extensions ) { LDAP_FREE( ext ); return 1; } n = 0; } else { for ( n=0; (*extensions)[n] != NULL; n++ ) ; tmp = LDAP_REALLOC(*extensions, (n+2)*sizeof(LDAPSchemaExtensionItem *)); if ( !tmp ) { LDAP_FREE( ext ); return 1; } *extensions = tmp; } (*extensions)[n] = ext; (*extensions)[n+1] = NULL; return 0; } static void free_extensions(LDAPSchemaExtensionItem **extensions) { LDAPSchemaExtensionItem **ext; if ( extensions ) { for ( ext = extensions; *ext != NULL; ext++ ) { LDAP_FREE((*ext)->lsei_name); LDAP_VFREE((*ext)->lsei_values); LDAP_FREE(*ext); } LDAP_FREE(extensions); } } void ldap_syntax_free( LDAPSyntax * syn ) { if ( !syn ) return; LDAP_FREE(syn->syn_oid); if (syn->syn_names) LDAP_VFREE(syn->syn_names); if (syn->syn_desc) LDAP_FREE(syn->syn_desc); free_extensions(syn->syn_extensions); LDAP_FREE(syn); } LDAPSyntax * ldap_str2syntax( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, LDAP_CONST unsigned flags ) { tk_t kind; const char * ss = s; char * sval; int seen_name = 0; int seen_desc = 0; LDAPSyntax * syn; char ** ext_vals; if ( !s ) { *code = LDAP_SCHERR_EMPTY; *errp = ""; return NULL; } *errp = s; syn = LDAP_CALLOC(1,sizeof(LDAPSyntax)); if ( !syn ) { *code = LDAP_SCHERR_OUTOFMEM; return NULL; } kind = get_token(&ss,&sval); if ( kind != TK_LEFTPAREN ) { LDAP_FREE(sval); *code = LDAP_SCHERR_NOLEFTPAREN; ldap_syntax_free(syn); return NULL; } parse_whsp(&ss); syn->syn_oid = ldap_int_parse_numericoid(&ss,code,0); if ( !syn->syn_oid ) { *errp = ss; ldap_syntax_free(syn); return NULL; } parse_whsp(&ss); /* * Beyond this point we will be liberal and accept the items * in any order. */ while (1) { kind = get_token(&ss,&sval); switch (kind) { case TK_EOS: *code = LDAP_SCHERR_NORIGHTPAREN; *errp = EndOfInput; ldap_syntax_free(syn); return NULL; case TK_RIGHTPAREN: return syn; case TK_BAREWORD: if ( !strcasecmp(sval,"NAME") ) { LDAP_FREE(sval); if ( seen_name ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_syntax_free(syn); return(NULL); } seen_name = 1; syn->syn_names = parse_qdescrs(&ss,code); if ( !syn->syn_names ) { if ( *code != LDAP_SCHERR_OUTOFMEM ) *code = LDAP_SCHERR_BADNAME; *errp = ss; ldap_syntax_free(syn); return NULL; } } else if ( !strcasecmp(sval,"DESC") ) { LDAP_FREE(sval); if ( seen_desc ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_syntax_free(syn); return(NULL); } seen_desc = 1; parse_whsp(&ss); kind = get_token(&ss,&sval); if ( kind != TK_QDSTRING ) { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_syntax_free(syn); return NULL; } syn->syn_desc = sval; parse_whsp(&ss); } else if ( sval[0] == 'X' && sval[1] == '-' ) { /* Should be parse_qdstrings */ ext_vals = parse_qdescrs(&ss, code); if ( !ext_vals ) { *errp = ss; ldap_syntax_free(syn); return NULL; } if ( add_extension(&syn->syn_extensions, sval, ext_vals) ) { *code = LDAP_SCHERR_OUTOFMEM; *errp = ss; LDAP_FREE(sval); ldap_syntax_free(syn); return NULL; } } else { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_syntax_free(syn); return NULL; } break; default: *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_syntax_free(syn); return NULL; } } } void ldap_matchingrule_free( LDAPMatchingRule * mr ) { if (!mr) return; LDAP_FREE(mr->mr_oid); if (mr->mr_names) LDAP_VFREE(mr->mr_names); if (mr->mr_desc) LDAP_FREE(mr->mr_desc); if (mr->mr_syntax_oid) LDAP_FREE(mr->mr_syntax_oid); free_extensions(mr->mr_extensions); LDAP_FREE(mr); } LDAPMatchingRule * ldap_str2matchingrule( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, LDAP_CONST unsigned flags ) { tk_t kind; const char * ss = s; char * sval; int seen_name = 0; int seen_desc = 0; int seen_obsolete = 0; int seen_syntax = 0; LDAPMatchingRule * mr; char ** ext_vals; const char * savepos; if ( !s ) { *code = LDAP_SCHERR_EMPTY; *errp = ""; return NULL; } *errp = s; mr = LDAP_CALLOC(1,sizeof(LDAPMatchingRule)); if ( !mr ) { *code = LDAP_SCHERR_OUTOFMEM; return NULL; } kind = get_token(&ss,&sval); if ( kind != TK_LEFTPAREN ) { *code = LDAP_SCHERR_NOLEFTPAREN; LDAP_FREE(sval); ldap_matchingrule_free(mr); return NULL; } parse_whsp(&ss); savepos = ss; mr->mr_oid = ldap_int_parse_numericoid(&ss,code,flags); if ( !mr->mr_oid ) { if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) { /* Backtracking */ ss = savepos; kind = get_token(&ss,&sval); if ( kind == TK_BAREWORD ) { if ( !strcasecmp(sval, "NAME") || !strcasecmp(sval, "DESC") || !strcasecmp(sval, "OBSOLETE") || !strcasecmp(sval, "SYNTAX") || !strncasecmp(sval, "X-", 2) ) { /* Missing OID, backtrack */ ss = savepos; } else { /* Non-numerical OID, ignore */ } } LDAP_FREE(sval); } else { *errp = ss; ldap_matchingrule_free(mr); return NULL; } } parse_whsp(&ss); /* * Beyond this point we will be liberal and accept the items * in any order. */ while (1) { kind = get_token(&ss,&sval); switch (kind) { case TK_EOS: *code = LDAP_SCHERR_NORIGHTPAREN; *errp = EndOfInput; ldap_matchingrule_free(mr); return NULL; case TK_RIGHTPAREN: if( !seen_syntax ) { *code = LDAP_SCHERR_MISSING; ldap_matchingrule_free(mr); return NULL; } return mr; case TK_BAREWORD: if ( !strcasecmp(sval,"NAME") ) { LDAP_FREE(sval); if ( seen_name ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_matchingrule_free(mr); return(NULL); } seen_name = 1; mr->mr_names = parse_qdescrs(&ss,code); if ( !mr->mr_names ) { if ( *code != LDAP_SCHERR_OUTOFMEM ) *code = LDAP_SCHERR_BADNAME; *errp = ss; ldap_matchingrule_free(mr); return NULL; } } else if ( !strcasecmp(sval,"DESC") ) { LDAP_FREE(sval); if ( seen_desc ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_matchingrule_free(mr); return(NULL); } seen_desc = 1; parse_whsp(&ss); kind = get_token(&ss,&sval); if ( kind != TK_QDSTRING ) { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_matchingrule_free(mr); return NULL; } mr->mr_desc = sval; parse_whsp(&ss); } else if ( !strcasecmp(sval,"OBSOLETE") ) { LDAP_FREE(sval); if ( seen_obsolete ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_matchingrule_free(mr); return(NULL); } seen_obsolete = 1; mr->mr_obsolete = LDAP_SCHEMA_YES; parse_whsp(&ss); } else if ( !strcasecmp(sval,"SYNTAX") ) { LDAP_FREE(sval); if ( seen_syntax ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_matchingrule_free(mr); return(NULL); } seen_syntax = 1; parse_whsp(&ss); mr->mr_syntax_oid = ldap_int_parse_numericoid(&ss,code,flags); if ( !mr->mr_syntax_oid ) { *errp = ss; ldap_matchingrule_free(mr); return NULL; } parse_whsp(&ss); } else if ( sval[0] == 'X' && sval[1] == '-' ) { /* Should be parse_qdstrings */ ext_vals = parse_qdescrs(&ss, code); if ( !ext_vals ) { *errp = ss; ldap_matchingrule_free(mr); return NULL; } if ( add_extension(&mr->mr_extensions, sval, ext_vals) ) { *code = LDAP_SCHERR_OUTOFMEM; *errp = ss; LDAP_FREE(sval); ldap_matchingrule_free(mr); return NULL; } } else { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_matchingrule_free(mr); return NULL; } break; default: *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_matchingrule_free(mr); return NULL; } } } void ldap_matchingruleuse_free( LDAPMatchingRuleUse * mru ) { if (!mru) return; LDAP_FREE(mru->mru_oid); if (mru->mru_names) LDAP_VFREE(mru->mru_names); if (mru->mru_desc) LDAP_FREE(mru->mru_desc); if (mru->mru_applies_oids) LDAP_VFREE(mru->mru_applies_oids); free_extensions(mru->mru_extensions); LDAP_FREE(mru); } LDAPMatchingRuleUse * ldap_str2matchingruleuse( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, LDAP_CONST unsigned flags ) { tk_t kind; const char * ss = s; char * sval; int seen_name = 0; int seen_desc = 0; int seen_obsolete = 0; int seen_applies = 0; LDAPMatchingRuleUse * mru; char ** ext_vals; const char * savepos; if ( !s ) { *code = LDAP_SCHERR_EMPTY; *errp = ""; return NULL; } *errp = s; mru = LDAP_CALLOC(1,sizeof(LDAPMatchingRuleUse)); if ( !mru ) { *code = LDAP_SCHERR_OUTOFMEM; return NULL; } kind = get_token(&ss,&sval); if ( kind != TK_LEFTPAREN ) { *code = LDAP_SCHERR_NOLEFTPAREN; LDAP_FREE(sval); ldap_matchingruleuse_free(mru); return NULL; } parse_whsp(&ss); savepos = ss; mru->mru_oid = ldap_int_parse_numericoid(&ss,code,flags); if ( !mru->mru_oid ) { if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) { /* Backtracking */ ss = savepos; kind = get_token(&ss,&sval); if ( kind == TK_BAREWORD ) { if ( !strcasecmp(sval, "NAME") || !strcasecmp(sval, "DESC") || !strcasecmp(sval, "OBSOLETE") || !strcasecmp(sval, "APPLIES") || !strncasecmp(sval, "X-", 2) ) { /* Missing OID, backtrack */ ss = savepos; } else { /* Non-numerical OID, ignore */ } } LDAP_FREE(sval); } else { *errp = ss; ldap_matchingruleuse_free(mru); return NULL; } } parse_whsp(&ss); /* * Beyond this point we will be liberal and accept the items * in any order. */ while (1) { kind = get_token(&ss,&sval); switch (kind) { case TK_EOS: *code = LDAP_SCHERR_NORIGHTPAREN; *errp = EndOfInput; ldap_matchingruleuse_free(mru); return NULL; case TK_RIGHTPAREN: if( !seen_applies ) { *code = LDAP_SCHERR_MISSING; ldap_matchingruleuse_free(mru); return NULL; } return mru; case TK_BAREWORD: if ( !strcasecmp(sval,"NAME") ) { LDAP_FREE(sval); if ( seen_name ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_matchingruleuse_free(mru); return(NULL); } seen_name = 1; mru->mru_names = parse_qdescrs(&ss,code); if ( !mru->mru_names ) { if ( *code != LDAP_SCHERR_OUTOFMEM ) *code = LDAP_SCHERR_BADNAME; *errp = ss; ldap_matchingruleuse_free(mru); return NULL; } } else if ( !strcasecmp(sval,"DESC") ) { LDAP_FREE(sval); if ( seen_desc ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_matchingruleuse_free(mru); return(NULL); } seen_desc = 1; parse_whsp(&ss); kind = get_token(&ss,&sval); if ( kind != TK_QDSTRING ) { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_matchingruleuse_free(mru); return NULL; } mru->mru_desc = sval; parse_whsp(&ss); } else if ( !strcasecmp(sval,"OBSOLETE") ) { LDAP_FREE(sval); if ( seen_obsolete ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_matchingruleuse_free(mru); return(NULL); } seen_obsolete = 1; mru->mru_obsolete = LDAP_SCHEMA_YES; parse_whsp(&ss); } else if ( !strcasecmp(sval,"APPLIES") ) { LDAP_FREE(sval); if ( seen_applies ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_matchingruleuse_free(mru); return(NULL); } seen_applies = 1; mru->mru_applies_oids = parse_oids(&ss, code, flags); if ( !mru->mru_applies_oids && *code != LDAP_SUCCESS ) { *errp = ss; ldap_matchingruleuse_free(mru); return NULL; } } else if ( sval[0] == 'X' && sval[1] == '-' ) { /* Should be parse_qdstrings */ ext_vals = parse_qdescrs(&ss, code); if ( !ext_vals ) { *errp = ss; ldap_matchingruleuse_free(mru); return NULL; } if ( add_extension(&mru->mru_extensions, sval, ext_vals) ) { *code = LDAP_SCHERR_OUTOFMEM; *errp = ss; LDAP_FREE(sval); ldap_matchingruleuse_free(mru); return NULL; } } else { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_matchingruleuse_free(mru); return NULL; } break; default: *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_matchingruleuse_free(mru); return NULL; } } } void ldap_attributetype_free(LDAPAttributeType * at) { if (!at) return; LDAP_FREE(at->at_oid); if (at->at_names) LDAP_VFREE(at->at_names); if (at->at_desc) LDAP_FREE(at->at_desc); if (at->at_sup_oid) LDAP_FREE(at->at_sup_oid); if (at->at_equality_oid) LDAP_FREE(at->at_equality_oid); if (at->at_ordering_oid) LDAP_FREE(at->at_ordering_oid); if (at->at_substr_oid) LDAP_FREE(at->at_substr_oid); if (at->at_syntax_oid) LDAP_FREE(at->at_syntax_oid); free_extensions(at->at_extensions); LDAP_FREE(at); } LDAPAttributeType * ldap_str2attributetype( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, LDAP_CONST unsigned flags ) { tk_t kind; const char * ss = s; char * sval; int seen_name = 0; int seen_desc = 0; int seen_obsolete = 0; int seen_sup = 0; int seen_equality = 0; int seen_ordering = 0; int seen_substr = 0; int seen_syntax = 0; int seen_usage = 0; LDAPAttributeType * at; char ** ext_vals; const char * savepos; if ( !s ) { *code = LDAP_SCHERR_EMPTY; *errp = ""; return NULL; } *errp = s; at = LDAP_CALLOC(1,sizeof(LDAPAttributeType)); if ( !at ) { *code = LDAP_SCHERR_OUTOFMEM; return NULL; } kind = get_token(&ss,&sval); if ( kind != TK_LEFTPAREN ) { *code = LDAP_SCHERR_NOLEFTPAREN; LDAP_FREE(sval); ldap_attributetype_free(at); return NULL; } /* * Definitions MUST begin with an OID in the numericoid format. * However, this routine is used by clients to parse the response * from servers and very well known servers will provide an OID * in the wrong format or even no OID at all. We do our best to * extract info from those servers. */ parse_whsp(&ss); savepos = ss; at->at_oid = ldap_int_parse_numericoid(&ss,code,0); if ( !at->at_oid ) { if ( ( flags & ( LDAP_SCHEMA_ALLOW_NO_OID | LDAP_SCHEMA_ALLOW_OID_MACRO ) ) && (ss == savepos) ) { /* Backtracking */ ss = savepos; kind = get_token(&ss,&sval); if ( kind == TK_BAREWORD ) { if ( !strcasecmp(sval, "NAME") || !strcasecmp(sval, "DESC") || !strcasecmp(sval, "OBSOLETE") || !strcasecmp(sval, "SUP") || !strcasecmp(sval, "EQUALITY") || !strcasecmp(sval, "ORDERING") || !strcasecmp(sval, "SUBSTR") || !strcasecmp(sval, "SYNTAX") || !strcasecmp(sval, "SINGLE-VALUE") || !strcasecmp(sval, "COLLECTIVE") || !strcasecmp(sval, "NO-USER-MODIFICATION") || !strcasecmp(sval, "USAGE") || !strncasecmp(sval, "X-", 2) ) { /* Missing OID, backtrack */ ss = savepos; } else if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO) { /* Non-numerical OID ... */ int len = ss-savepos; at->at_oid = LDAP_MALLOC(len+1); if ( !at->at_oid ) { ldap_attributetype_free(at); return NULL; } strncpy(at->at_oid, savepos, len); at->at_oid[len] = 0; } } LDAP_FREE(sval); } else { *errp = ss; ldap_attributetype_free(at); return NULL; } } parse_whsp(&ss); /* * Beyond this point we will be liberal and accept the items * in any order. */ while (1) { kind = get_token(&ss,&sval); switch (kind) { case TK_EOS: *code = LDAP_SCHERR_NORIGHTPAREN; *errp = EndOfInput; ldap_attributetype_free(at); return NULL; case TK_RIGHTPAREN: return at; case TK_BAREWORD: if ( !strcasecmp(sval,"NAME") ) { LDAP_FREE(sval); if ( seen_name ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_attributetype_free(at); return(NULL); } seen_name = 1; at->at_names = parse_qdescrs(&ss,code); if ( !at->at_names ) { if ( *code != LDAP_SCHERR_OUTOFMEM ) *code = LDAP_SCHERR_BADNAME; *errp = ss; ldap_attributetype_free(at); return NULL; } } else if ( !strcasecmp(sval,"DESC") ) { LDAP_FREE(sval); if ( seen_desc ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_attributetype_free(at); return(NULL); } seen_desc = 1; parse_whsp(&ss); kind = get_token(&ss,&sval); if ( kind != TK_QDSTRING ) { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_attributetype_free(at); return NULL; } at->at_desc = sval; parse_whsp(&ss); } else if ( !strcasecmp(sval,"OBSOLETE") ) { LDAP_FREE(sval); if ( seen_obsolete ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_attributetype_free(at); return(NULL); } seen_obsolete = 1; at->at_obsolete = LDAP_SCHEMA_YES; parse_whsp(&ss); } else if ( !strcasecmp(sval,"SUP") ) { LDAP_FREE(sval); if ( seen_sup ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_attributetype_free(at); return(NULL); } seen_sup = 1; at->at_sup_oid = parse_woid(&ss,code); if ( !at->at_sup_oid ) { *errp = ss; ldap_attributetype_free(at); return NULL; } } else if ( !strcasecmp(sval,"EQUALITY") ) { LDAP_FREE(sval); if ( seen_equality ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_attributetype_free(at); return(NULL); } seen_equality = 1; at->at_equality_oid = parse_woid(&ss,code); if ( !at->at_equality_oid ) { *errp = ss; ldap_attributetype_free(at); return NULL; } } else if ( !strcasecmp(sval,"ORDERING") ) { LDAP_FREE(sval); if ( seen_ordering ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_attributetype_free(at); return(NULL); } seen_ordering = 1; at->at_ordering_oid = parse_woid(&ss,code); if ( !at->at_ordering_oid ) { *errp = ss; ldap_attributetype_free(at); return NULL; } } else if ( !strcasecmp(sval,"SUBSTR") ) { LDAP_FREE(sval); if ( seen_substr ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_attributetype_free(at); return(NULL); } seen_substr = 1; at->at_substr_oid = parse_woid(&ss,code); if ( !at->at_substr_oid ) { *errp = ss; ldap_attributetype_free(at); return NULL; } } else if ( !strcasecmp(sval,"SYNTAX") ) { LDAP_FREE(sval); if ( seen_syntax ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_attributetype_free(at); return(NULL); } seen_syntax = 1; parse_whsp(&ss); savepos = ss; at->at_syntax_oid = parse_noidlen(&ss, code, &at->at_syntax_len, flags); if ( !at->at_syntax_oid ) { if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) { kind = get_token(&ss,&sval); if (kind == TK_BAREWORD) { char *sp = strchr(sval, '{'); at->at_syntax_oid = sval; if (sp) { *sp++ = 0; at->at_syntax_len = atoi(sp); while ( LDAP_DIGIT(*sp) ) sp++; if ( *sp != '}' ) { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; ldap_attributetype_free(at); return NULL; } } } } else { *errp = ss; ldap_attributetype_free(at); return NULL; } } parse_whsp(&ss); } else if ( !strcasecmp(sval,"SINGLE-VALUE") ) { LDAP_FREE(sval); if ( at->at_single_value ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_attributetype_free(at); return(NULL); } at->at_single_value = LDAP_SCHEMA_YES; parse_whsp(&ss); } else if ( !strcasecmp(sval,"COLLECTIVE") ) { LDAP_FREE(sval); if ( at->at_collective ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_attributetype_free(at); return(NULL); } at->at_collective = LDAP_SCHEMA_YES; parse_whsp(&ss); } else if ( !strcasecmp(sval,"NO-USER-MODIFICATION") ) { LDAP_FREE(sval); if ( at->at_no_user_mod ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_attributetype_free(at); return(NULL); } at->at_no_user_mod = LDAP_SCHEMA_YES; parse_whsp(&ss); } else if ( !strcasecmp(sval,"USAGE") ) { LDAP_FREE(sval); if ( seen_usage ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_attributetype_free(at); return(NULL); } seen_usage = 1; parse_whsp(&ss); kind = get_token(&ss,&sval); if ( kind != TK_BAREWORD ) { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_attributetype_free(at); return NULL; } if ( !strcasecmp(sval,"userApplications") ) at->at_usage = LDAP_SCHEMA_USER_APPLICATIONS; else if ( !strcasecmp(sval,"directoryOperation") ) at->at_usage = LDAP_SCHEMA_DIRECTORY_OPERATION; else if ( !strcasecmp(sval,"distributedOperation") ) at->at_usage = LDAP_SCHEMA_DISTRIBUTED_OPERATION; else if ( !strcasecmp(sval,"dSAOperation") ) at->at_usage = LDAP_SCHEMA_DSA_OPERATION; else { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_attributetype_free(at); return NULL; } LDAP_FREE(sval); parse_whsp(&ss); } else if ( sval[0] == 'X' && sval[1] == '-' ) { /* Should be parse_qdstrings */ ext_vals = parse_qdescrs(&ss, code); if ( !ext_vals ) { *errp = ss; ldap_attributetype_free(at); return NULL; } if ( add_extension(&at->at_extensions, sval, ext_vals) ) { *code = LDAP_SCHERR_OUTOFMEM; *errp = ss; LDAP_FREE(sval); ldap_attributetype_free(at); return NULL; } } else { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_attributetype_free(at); return NULL; } break; default: *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_attributetype_free(at); return NULL; } } } void ldap_objectclass_free(LDAPObjectClass * oc) { if (!oc) return; LDAP_FREE(oc->oc_oid); if (oc->oc_names) LDAP_VFREE(oc->oc_names); if (oc->oc_desc) LDAP_FREE(oc->oc_desc); if (oc->oc_sup_oids) LDAP_VFREE(oc->oc_sup_oids); if (oc->oc_at_oids_must) LDAP_VFREE(oc->oc_at_oids_must); if (oc->oc_at_oids_may) LDAP_VFREE(oc->oc_at_oids_may); free_extensions(oc->oc_extensions); LDAP_FREE(oc); } LDAPObjectClass * ldap_str2objectclass( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, LDAP_CONST unsigned flags ) { tk_t kind; const char * ss = s; char * sval; int seen_name = 0; int seen_desc = 0; int seen_obsolete = 0; int seen_sup = 0; int seen_kind = 0; int seen_must = 0; int seen_may = 0; LDAPObjectClass * oc; char ** ext_vals; const char * savepos; if ( !s ) { *code = LDAP_SCHERR_EMPTY; *errp = ""; return NULL; } *errp = s; oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass)); if ( !oc ) { *code = LDAP_SCHERR_OUTOFMEM; return NULL; } oc->oc_kind = LDAP_SCHEMA_STRUCTURAL; kind = get_token(&ss,&sval); if ( kind != TK_LEFTPAREN ) { *code = LDAP_SCHERR_NOLEFTPAREN; LDAP_FREE(sval); ldap_objectclass_free(oc); return NULL; } /* * Definitions MUST begin with an OID in the numericoid format. * However, this routine is used by clients to parse the response * from servers and very well known servers will provide an OID * in the wrong format or even no OID at all. We do our best to * extract info from those servers. */ parse_whsp(&ss); savepos = ss; oc->oc_oid = ldap_int_parse_numericoid(&ss,code,0); if ( !oc->oc_oid ) { if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) { /* Backtracking */ ss = savepos; kind = get_token(&ss,&sval); if ( kind == TK_BAREWORD ) { if ( !strcasecmp(sval, "NAME") || !strcasecmp(sval, "DESC") || !strcasecmp(sval, "OBSOLETE") || !strcasecmp(sval, "SUP") || !strcasecmp(sval, "ABSTRACT") || !strcasecmp(sval, "STRUCTURAL") || !strcasecmp(sval, "AUXILIARY") || !strcasecmp(sval, "MUST") || !strcasecmp(sval, "MAY") || !strncasecmp(sval, "X-", 2) ) { /* Missing OID, backtrack */ ss = savepos; } else if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) { /* Non-numerical OID, ignore */ int len = ss-savepos; oc->oc_oid = LDAP_MALLOC(len+1); if ( !oc->oc_oid ) { ldap_objectclass_free(oc); return NULL; } strncpy(oc->oc_oid, savepos, len); oc->oc_oid[len] = 0; } } LDAP_FREE(sval); *code = 0; } else { *errp = ss; ldap_objectclass_free(oc); return NULL; } } parse_whsp(&ss); /* * Beyond this point we will be liberal an accept the items * in any order. */ while (1) { kind = get_token(&ss,&sval); switch (kind) { case TK_EOS: *code = LDAP_SCHERR_NORIGHTPAREN; *errp = EndOfInput; ldap_objectclass_free(oc); return NULL; case TK_RIGHTPAREN: return oc; case TK_BAREWORD: if ( !strcasecmp(sval,"NAME") ) { LDAP_FREE(sval); if ( seen_name ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_objectclass_free(oc); return(NULL); } seen_name = 1; oc->oc_names = parse_qdescrs(&ss,code); if ( !oc->oc_names ) { if ( *code != LDAP_SCHERR_OUTOFMEM ) *code = LDAP_SCHERR_BADNAME; *errp = ss; ldap_objectclass_free(oc); return NULL; } } else if ( !strcasecmp(sval,"DESC") ) { LDAP_FREE(sval); if ( seen_desc ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_objectclass_free(oc); return(NULL); } seen_desc = 1; parse_whsp(&ss); kind = get_token(&ss,&sval); if ( kind != TK_QDSTRING ) { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_objectclass_free(oc); return NULL; } oc->oc_desc = sval; parse_whsp(&ss); } else if ( !strcasecmp(sval,"OBSOLETE") ) { LDAP_FREE(sval); if ( seen_obsolete ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_objectclass_free(oc); return(NULL); } seen_obsolete = 1; oc->oc_obsolete = LDAP_SCHEMA_YES; parse_whsp(&ss); } else if ( !strcasecmp(sval,"SUP") ) { LDAP_FREE(sval); if ( seen_sup ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_objectclass_free(oc); return(NULL); } seen_sup = 1; oc->oc_sup_oids = parse_oids(&ss, code, flags); if ( !oc->oc_sup_oids && *code != LDAP_SUCCESS ) { *errp = ss; ldap_objectclass_free(oc); return NULL; } *code = 0; } else if ( !strcasecmp(sval,"ABSTRACT") ) { LDAP_FREE(sval); if ( seen_kind ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_objectclass_free(oc); return(NULL); } seen_kind = 1; oc->oc_kind = LDAP_SCHEMA_ABSTRACT; parse_whsp(&ss); } else if ( !strcasecmp(sval,"STRUCTURAL") ) { LDAP_FREE(sval); if ( seen_kind ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_objectclass_free(oc); return(NULL); } seen_kind = 1; oc->oc_kind = LDAP_SCHEMA_STRUCTURAL; parse_whsp(&ss); } else if ( !strcasecmp(sval,"AUXILIARY") ) { LDAP_FREE(sval); if ( seen_kind ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_objectclass_free(oc); return(NULL); } seen_kind = 1; oc->oc_kind = LDAP_SCHEMA_AUXILIARY; parse_whsp(&ss); } else if ( !strcasecmp(sval,"MUST") ) { LDAP_FREE(sval); if ( seen_must ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_objectclass_free(oc); return(NULL); } seen_must = 1; oc->oc_at_oids_must = parse_oids(&ss,code,0); if ( !oc->oc_at_oids_must && *code != LDAP_SUCCESS ) { *errp = ss; ldap_objectclass_free(oc); return NULL; } *code = 0; parse_whsp(&ss); } else if ( !strcasecmp(sval,"MAY") ) { LDAP_FREE(sval); if ( seen_may ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_objectclass_free(oc); return(NULL); } seen_may = 1; oc->oc_at_oids_may = parse_oids(&ss,code,0); if ( !oc->oc_at_oids_may && *code != LDAP_SUCCESS ) { *errp = ss; ldap_objectclass_free(oc); return NULL; } *code = 0; parse_whsp(&ss); } else if ( sval[0] == 'X' && sval[1] == '-' ) { /* Should be parse_qdstrings */ ext_vals = parse_qdescrs(&ss, code); *code = 0; if ( !ext_vals ) { *errp = ss; ldap_objectclass_free(oc); return NULL; } if ( add_extension(&oc->oc_extensions, sval, ext_vals) ) { *code = LDAP_SCHERR_OUTOFMEM; *errp = ss; LDAP_FREE(sval); ldap_objectclass_free(oc); return NULL; } } else { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_objectclass_free(oc); return NULL; } break; default: *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_objectclass_free(oc); return NULL; } } } void ldap_contentrule_free(LDAPContentRule * cr) { if (!cr) return; LDAP_FREE(cr->cr_oid); if (cr->cr_names) LDAP_VFREE(cr->cr_names); if (cr->cr_desc) LDAP_FREE(cr->cr_desc); if (cr->cr_oc_oids_aux) LDAP_VFREE(cr->cr_oc_oids_aux); if (cr->cr_at_oids_must) LDAP_VFREE(cr->cr_at_oids_must); if (cr->cr_at_oids_may) LDAP_VFREE(cr->cr_at_oids_may); if (cr->cr_at_oids_not) LDAP_VFREE(cr->cr_at_oids_not); free_extensions(cr->cr_extensions); LDAP_FREE(cr); } LDAPContentRule * ldap_str2contentrule( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, LDAP_CONST unsigned flags ) { tk_t kind; const char * ss = s; char * sval; int seen_name = 0; int seen_desc = 0; int seen_obsolete = 0; int seen_aux = 0; int seen_must = 0; int seen_may = 0; int seen_not = 0; LDAPContentRule * cr; char ** ext_vals; const char * savepos; if ( !s ) { *code = LDAP_SCHERR_EMPTY; *errp = ""; return NULL; } *errp = s; cr = LDAP_CALLOC(1,sizeof(LDAPContentRule)); if ( !cr ) { *code = LDAP_SCHERR_OUTOFMEM; return NULL; } kind = get_token(&ss,&sval); if ( kind != TK_LEFTPAREN ) { *code = LDAP_SCHERR_NOLEFTPAREN; LDAP_FREE(sval); ldap_contentrule_free(cr); return NULL; } /* * Definitions MUST begin with an OID in the numericoid format. */ parse_whsp(&ss); savepos = ss; cr->cr_oid = ldap_int_parse_numericoid(&ss,code,0); if ( !cr->cr_oid ) { if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) { /* Backtracking */ ss = savepos; kind = get_token(&ss,&sval); if ( kind == TK_BAREWORD ) { if ( !strcasecmp(sval, "NAME") || !strcasecmp(sval, "DESC") || !strcasecmp(sval, "OBSOLETE") || !strcasecmp(sval, "AUX") || !strcasecmp(sval, "MUST") || !strcasecmp(sval, "MAY") || !strcasecmp(sval, "NOT") || !strncasecmp(sval, "X-", 2) ) { /* Missing OID, backtrack */ ss = savepos; } else if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) { /* Non-numerical OID, ignore */ int len = ss-savepos; cr->cr_oid = LDAP_MALLOC(len+1); if ( !cr->cr_oid ) { ldap_contentrule_free(cr); return NULL; } strncpy(cr->cr_oid, savepos, len); cr->cr_oid[len] = 0; } } LDAP_FREE(sval); } else { *errp = ss; ldap_contentrule_free(cr); return NULL; } } parse_whsp(&ss); /* * Beyond this point we will be liberal an accept the items * in any order. */ while (1) { kind = get_token(&ss,&sval); switch (kind) { case TK_EOS: *code = LDAP_SCHERR_NORIGHTPAREN; *errp = EndOfInput; ldap_contentrule_free(cr); return NULL; case TK_RIGHTPAREN: return cr; case TK_BAREWORD: if ( !strcasecmp(sval,"NAME") ) { LDAP_FREE(sval); if ( seen_name ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_contentrule_free(cr); return(NULL); } seen_name = 1; cr->cr_names = parse_qdescrs(&ss,code); if ( !cr->cr_names ) { if ( *code != LDAP_SCHERR_OUTOFMEM ) *code = LDAP_SCHERR_BADNAME; *errp = ss; ldap_contentrule_free(cr); return NULL; } } else if ( !strcasecmp(sval,"DESC") ) { LDAP_FREE(sval); if ( seen_desc ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_contentrule_free(cr); return(NULL); } seen_desc = 1; parse_whsp(&ss); kind = get_token(&ss,&sval); if ( kind != TK_QDSTRING ) { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_contentrule_free(cr); return NULL; } cr->cr_desc = sval; parse_whsp(&ss); } else if ( !strcasecmp(sval,"OBSOLETE") ) { LDAP_FREE(sval); if ( seen_obsolete ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_contentrule_free(cr); return(NULL); } seen_obsolete = 1; cr->cr_obsolete = LDAP_SCHEMA_YES; parse_whsp(&ss); } else if ( !strcasecmp(sval,"AUX") ) { LDAP_FREE(sval); if ( seen_aux ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_contentrule_free(cr); return(NULL); } seen_aux = 1; cr->cr_oc_oids_aux = parse_oids(&ss,code,0); if ( !cr->cr_oc_oids_aux ) { *errp = ss; ldap_contentrule_free(cr); return NULL; } parse_whsp(&ss); } else if ( !strcasecmp(sval,"MUST") ) { LDAP_FREE(sval); if ( seen_must ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_contentrule_free(cr); return(NULL); } seen_must = 1; cr->cr_at_oids_must = parse_oids(&ss,code,0); if ( !cr->cr_at_oids_must && *code != LDAP_SUCCESS ) { *errp = ss; ldap_contentrule_free(cr); return NULL; } parse_whsp(&ss); } else if ( !strcasecmp(sval,"MAY") ) { LDAP_FREE(sval); if ( seen_may ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_contentrule_free(cr); return(NULL); } seen_may = 1; cr->cr_at_oids_may = parse_oids(&ss,code,0); if ( !cr->cr_at_oids_may && *code != LDAP_SUCCESS ) { *errp = ss; ldap_contentrule_free(cr); return NULL; } parse_whsp(&ss); } else if ( !strcasecmp(sval,"NOT") ) { LDAP_FREE(sval); if ( seen_not ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_contentrule_free(cr); return(NULL); } seen_not = 1; cr->cr_at_oids_not = parse_oids(&ss,code,0); if ( !cr->cr_at_oids_not && *code != LDAP_SUCCESS ) { *errp = ss; ldap_contentrule_free(cr); return NULL; } parse_whsp(&ss); } else if ( sval[0] == 'X' && sval[1] == '-' ) { /* Should be parse_qdstrings */ ext_vals = parse_qdescrs(&ss, code); if ( !ext_vals ) { *errp = ss; ldap_contentrule_free(cr); return NULL; } if ( add_extension(&cr->cr_extensions, sval, ext_vals) ) { *code = LDAP_SCHERR_OUTOFMEM; *errp = ss; LDAP_FREE(sval); ldap_contentrule_free(cr); return NULL; } } else { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_contentrule_free(cr); return NULL; } break; default: *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_contentrule_free(cr); return NULL; } } } void ldap_structurerule_free(LDAPStructureRule * sr) { if (!sr) return; if (sr->sr_names) LDAP_VFREE(sr->sr_names); if (sr->sr_desc) LDAP_FREE(sr->sr_desc); if (sr->sr_nameform) LDAP_FREE(sr->sr_nameform); if (sr->sr_sup_ruleids) LDAP_FREE(sr->sr_sup_ruleids); free_extensions(sr->sr_extensions); LDAP_FREE(sr); } LDAPStructureRule * ldap_str2structurerule( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, LDAP_CONST unsigned flags ) { tk_t kind; int ret; const char * ss = s; char * sval; int seen_name = 0; int seen_desc = 0; int seen_obsolete = 0; int seen_nameform = 0; LDAPStructureRule * sr; char ** ext_vals; const char * savepos; if ( !s ) { *code = LDAP_SCHERR_EMPTY; *errp = ""; return NULL; } *errp = s; sr = LDAP_CALLOC(1,sizeof(LDAPStructureRule)); if ( !sr ) { *code = LDAP_SCHERR_OUTOFMEM; return NULL; } kind = get_token(&ss,&sval); if ( kind != TK_LEFTPAREN ) { *code = LDAP_SCHERR_NOLEFTPAREN; LDAP_FREE(sval); ldap_structurerule_free(sr); return NULL; } /* * Definitions MUST begin with a ruleid. */ parse_whsp(&ss); savepos = ss; ret = ldap_int_parse_ruleid(&ss,code,0,&sr->sr_ruleid); if ( ret ) { *errp = ss; ldap_structurerule_free(sr); return NULL; } parse_whsp(&ss); /* * Beyond this point we will be liberal an accept the items * in any order. */ while (1) { kind = get_token(&ss,&sval); switch (kind) { case TK_EOS: *code = LDAP_SCHERR_NORIGHTPAREN; *errp = EndOfInput; ldap_structurerule_free(sr); return NULL; case TK_RIGHTPAREN: if( !seen_nameform ) { *code = LDAP_SCHERR_MISSING; ldap_structurerule_free(sr); return NULL; } return sr; case TK_BAREWORD: if ( !strcasecmp(sval,"NAME") ) { LDAP_FREE(sval); if ( seen_name ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_structurerule_free(sr); return(NULL); } seen_name = 1; sr->sr_names = parse_qdescrs(&ss,code); if ( !sr->sr_names ) { if ( *code != LDAP_SCHERR_OUTOFMEM ) *code = LDAP_SCHERR_BADNAME; *errp = ss; ldap_structurerule_free(sr); return NULL; } } else if ( !strcasecmp(sval,"DESC") ) { LDAP_FREE(sval); if ( seen_desc ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_structurerule_free(sr); return(NULL); } seen_desc = 1; parse_whsp(&ss); kind = get_token(&ss,&sval); if ( kind != TK_QDSTRING ) { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_structurerule_free(sr); return NULL; } sr->sr_desc = sval; parse_whsp(&ss); } else if ( !strcasecmp(sval,"OBSOLETE") ) { LDAP_FREE(sval); if ( seen_obsolete ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_structurerule_free(sr); return(NULL); } seen_obsolete = 1; sr->sr_obsolete = LDAP_SCHEMA_YES; parse_whsp(&ss); } else if ( !strcasecmp(sval,"FORM") ) { LDAP_FREE(sval); if ( seen_nameform ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_structurerule_free(sr); return(NULL); } seen_nameform = 1; sr->sr_nameform = parse_woid(&ss,code); if ( !sr->sr_nameform ) { *errp = ss; ldap_structurerule_free(sr); return NULL; } parse_whsp(&ss); } else if ( sval[0] == 'X' && sval[1] == '-' ) { /* Should be parse_qdstrings */ ext_vals = parse_qdescrs(&ss, code); if ( !ext_vals ) { *errp = ss; ldap_structurerule_free(sr); return NULL; } if ( add_extension(&sr->sr_extensions, sval, ext_vals) ) { *code = LDAP_SCHERR_OUTOFMEM; *errp = ss; LDAP_FREE(sval); ldap_structurerule_free(sr); return NULL; } } else { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_structurerule_free(sr); return NULL; } break; default: *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_structurerule_free(sr); return NULL; } } } void ldap_nameform_free(LDAPNameForm * nf) { if (!nf) return; LDAP_FREE(nf->nf_oid); if (nf->nf_names) LDAP_VFREE(nf->nf_names); if (nf->nf_desc) LDAP_FREE(nf->nf_desc); if (nf->nf_objectclass) LDAP_FREE(nf->nf_objectclass); if (nf->nf_at_oids_must) LDAP_VFREE(nf->nf_at_oids_must); if (nf->nf_at_oids_may) LDAP_VFREE(nf->nf_at_oids_may); free_extensions(nf->nf_extensions); LDAP_FREE(nf); } LDAPNameForm * ldap_str2nameform( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, LDAP_CONST unsigned flags ) { tk_t kind; const char * ss = s; char * sval; int seen_name = 0; int seen_desc = 0; int seen_obsolete = 0; int seen_class = 0; int seen_must = 0; int seen_may = 0; LDAPNameForm * nf; char ** ext_vals; const char * savepos; if ( !s ) { *code = LDAP_SCHERR_EMPTY; *errp = ""; return NULL; } *errp = s; nf = LDAP_CALLOC(1,sizeof(LDAPNameForm)); if ( !nf ) { *code = LDAP_SCHERR_OUTOFMEM; return NULL; } kind = get_token(&ss,&sval); if ( kind != TK_LEFTPAREN ) { *code = LDAP_SCHERR_NOLEFTPAREN; LDAP_FREE(sval); ldap_nameform_free(nf); return NULL; } /* * Definitions MUST begin with an OID in the numericoid format. * However, this routine is used by clients to parse the response * from servers and very well known servers will provide an OID * in the wrong format or even no OID at all. We do our best to * extract info from those servers. */ parse_whsp(&ss); savepos = ss; nf->nf_oid = ldap_int_parse_numericoid(&ss,code,0); if ( !nf->nf_oid ) { *errp = ss; ldap_nameform_free(nf); return NULL; } parse_whsp(&ss); /* * Beyond this point we will be liberal an accept the items * in any order. */ while (1) { kind = get_token(&ss,&sval); switch (kind) { case TK_EOS: *code = LDAP_SCHERR_NORIGHTPAREN; *errp = EndOfInput; ldap_nameform_free(nf); return NULL; case TK_RIGHTPAREN: if( !seen_class || !seen_must ) { *code = LDAP_SCHERR_MISSING; ldap_nameform_free(nf); return NULL; } return nf; case TK_BAREWORD: if ( !strcasecmp(sval,"NAME") ) { LDAP_FREE(sval); if ( seen_name ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_nameform_free(nf); return(NULL); } seen_name = 1; nf->nf_names = parse_qdescrs(&ss,code); if ( !nf->nf_names ) { if ( *code != LDAP_SCHERR_OUTOFMEM ) *code = LDAP_SCHERR_BADNAME; *errp = ss; ldap_nameform_free(nf); return NULL; } } else if ( !strcasecmp(sval,"DESC") ) { LDAP_FREE(sval); if ( seen_desc ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_nameform_free(nf); return(NULL); } seen_desc = 1; parse_whsp(&ss); kind = get_token(&ss,&sval); if ( kind != TK_QDSTRING ) { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_nameform_free(nf); return NULL; } nf->nf_desc = sval; parse_whsp(&ss); } else if ( !strcasecmp(sval,"OBSOLETE") ) { LDAP_FREE(sval); if ( seen_obsolete ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_nameform_free(nf); return(NULL); } seen_obsolete = 1; nf->nf_obsolete = LDAP_SCHEMA_YES; parse_whsp(&ss); } else if ( !strcasecmp(sval,"OC") ) { LDAP_FREE(sval); if ( seen_class ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_nameform_free(nf); return(NULL); } seen_class = 1; nf->nf_objectclass = parse_woid(&ss,code); if ( !nf->nf_objectclass ) { *errp = ss; ldap_nameform_free(nf); return NULL; } } else if ( !strcasecmp(sval,"MUST") ) { LDAP_FREE(sval); if ( seen_must ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_nameform_free(nf); return(NULL); } seen_must = 1; nf->nf_at_oids_must = parse_oids(&ss,code,0); if ( !nf->nf_at_oids_must && *code != LDAP_SUCCESS ) { *errp = ss; ldap_nameform_free(nf); return NULL; } parse_whsp(&ss); } else if ( !strcasecmp(sval,"MAY") ) { LDAP_FREE(sval); if ( seen_may ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; ldap_nameform_free(nf); return(NULL); } seen_may = 1; nf->nf_at_oids_may = parse_oids(&ss,code,0); if ( !nf->nf_at_oids_may && *code != LDAP_SUCCESS ) { *errp = ss; ldap_nameform_free(nf); return NULL; } parse_whsp(&ss); } else if ( sval[0] == 'X' && sval[1] == '-' ) { /* Should be parse_qdstrings */ ext_vals = parse_qdescrs(&ss, code); if ( !ext_vals ) { *errp = ss; ldap_nameform_free(nf); return NULL; } if ( add_extension(&nf->nf_extensions, sval, ext_vals) ) { *code = LDAP_SCHERR_OUTOFMEM; *errp = ss; LDAP_FREE(sval); ldap_nameform_free(nf); return NULL; } } else { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_nameform_free(nf); return NULL; } break; default: *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; LDAP_FREE(sval); ldap_nameform_free(nf); return NULL; } } } static char *const err2text[] = { N_("Success"), N_("Out of memory"), N_("Unexpected token"), N_("Missing opening parenthesis"), N_("Missing closing parenthesis"), N_("Expecting digit"), N_("Expecting a name"), N_("Bad description"), N_("Bad superiors"), N_("Duplicate option"), N_("Unexpected end of data"), N_("Missing required field"), N_("Out of order field") }; char * ldap_scherr2str(int code) { if ( code < 0 || code >= (int)(sizeof(err2text)/sizeof(char *)) ) { return _("Unknown error"); } else { return _(err2text[code]); } } openldap-2.5.11+dfsg/libraries/libldap/msctrl.c0000644000175000017500000001252114172327167020073 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * Portions Copyright 2018 Howard Chu. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This work was developed by Howard Chu for inclusion in * OpenLDAP Software. */ #include "portable.h" #include #include #include #include #include "ldap-int.h" /* MS Active Directory controls - not implemented in slapd(8) */ #ifdef LDAP_CONTROL_X_DIRSYNC int ldap_create_dirsync_value( LDAP *ld, int flags, int maxAttrCount, struct berval *cookie, struct berval *value ) { BerElement *ber = NULL; ber_tag_t tag; if ( ld == NULL || cookie == NULL || value == NULL ) { if ( ld ) { ld->ld_errno = LDAP_PARAM_ERROR; } return LDAP_PARAM_ERROR; } assert( LDAP_VALID( ld ) ); ld->ld_errno = LDAP_SUCCESS; /* maxAttrCount less than 0x100000 is treated as 0x100000 by server */ /* prepare value */ value->bv_val = NULL; value->bv_len = 0; ber = ldap_alloc_ber_with_options( ld ); if ( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } tag = ber_printf( ber, "{iiO}", flags, maxAttrCount, cookie ); if ( tag == LBER_ERROR ) { ld->ld_errno = LDAP_ENCODING_ERROR; goto done; } if ( ber_flatten2( ber, value, 1 ) == -1 ) { ld->ld_errno = LDAP_NO_MEMORY; } done:; if ( ber != NULL ) { ber_free( ber, 1 ); } return ld->ld_errno; } int ldap_create_dirsync_control( LDAP *ld, int flags, int maxAttrCount, struct berval *cookie, LDAPControl **ctrlp ) { struct berval value; if ( ctrlp == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; } ld->ld_errno = ldap_create_dirsync_value( ld, flags, maxAttrCount, cookie, &value ); if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = ldap_control_create( LDAP_CONTROL_X_DIRSYNC, 1, &value, 0, ctrlp ); if ( ld->ld_errno != LDAP_SUCCESS ) { LDAP_FREE( value.bv_val ); } } return ld->ld_errno; } int ldap_parse_dirsync_control( LDAP *ld, LDAPControl *ctrl, int *continueFlag, struct berval *cookie ) { BerElement *ber; ber_tag_t tag; ber_len_t len; int unused; if ( ld == NULL || ctrl == NULL || continueFlag == NULL || cookie == NULL ) { if ( ld ) { ld->ld_errno = LDAP_PARAM_ERROR; } /* NOTE: we want the caller to get all or nothing; * we could allow some of the pointers to be NULL, * if one does not want part of the data */ return LDAP_PARAM_ERROR; } *continueFlag = 0; BER_BVZERO( cookie ); ber = ber_init( &ctrl->ldctl_value ); if ( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } tag = ber_scanf( ber, "{iio}", continueFlag, &unused, cookie ); if ( tag == LBER_DEFAULT ) tag = LBER_ERROR; (void)ber_free( ber, 1 ); if ( tag == LBER_ERROR ) { return LDAP_DECODING_ERROR; } return ld->ld_errno; } #endif /* LDAP_CONTROL_X_DIRSYNC */ #ifdef LDAP_CONTROL_X_SHOW_DELETED int ldap_create_show_deleted_control( LDAP *ld, LDAPControl **ctrlp ) { assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( ctrlp != NULL ); ld->ld_errno = ldap_control_create( LDAP_CONTROL_X_SHOW_DELETED, 0, NULL, 0, ctrlp ); return ld->ld_errno; } #endif /* LDAP_CONTROL_X_SHOW_DELETED */ #ifdef LDAP_CONTROL_X_EXTENDED_DN int ldap_create_extended_dn_value( LDAP *ld, int flag, struct berval *value ) { BerElement *ber = NULL; ber_tag_t tag; if ( ld == NULL || value == NULL ) { if ( ld ) { ld->ld_errno = LDAP_PARAM_ERROR; } return LDAP_PARAM_ERROR; } assert( LDAP_VALID( ld ) ); ld->ld_errno = LDAP_SUCCESS; /* prepare value */ value->bv_val = NULL; value->bv_len = 0; ber = ldap_alloc_ber_with_options( ld ); if ( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } tag = ber_printf( ber, "{i}", flag ); if ( tag == LBER_ERROR ) { ld->ld_errno = LDAP_ENCODING_ERROR; goto done; } if ( ber_flatten2( ber, value, 1 ) == -1 ) { ld->ld_errno = LDAP_NO_MEMORY; } done:; if ( ber != NULL ) { ber_free( ber, 1 ); } return ld->ld_errno; } int ldap_create_extended_dn_control( LDAP *ld, int flag, LDAPControl **ctrlp ) { struct berval value; if ( ctrlp == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; } ld->ld_errno = ldap_create_extended_dn_value( ld, flag, &value ); if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = ldap_control_create( LDAP_CONTROL_X_EXTENDED_DN, 0, &value, 0, ctrlp ); if ( ld->ld_errno != LDAP_SUCCESS ) { LDAP_FREE( value.bv_val ); } } return ld->ld_errno; } #endif /* LDAP_CONTROL_X_EXTENDED_DN */ #ifdef LDAP_CONTROL_X_SERVER_NOTIFICATION int ldap_create_server_notification_control( LDAP *ld, LDAPControl **ctrlp ) { assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( ctrlp != NULL ); ld->ld_errno = ldap_control_create( LDAP_CONTROL_X_SERVER_NOTIFICATION, 0, NULL, 0, ctrlp ); return ld->ld_errno; } #endif /* LDAP_CONTROL_X_SERVER_NOTIFICATION */ openldap-2.5.11+dfsg/libraries/libldap/getentry.c0000644000175000017500000000457114172327167020436 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" /* ARGSUSED */ LDAPMessage * ldap_first_entry( LDAP *ld, LDAPMessage *chain ) { assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( chain != NULL ); return chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY ? chain : ldap_next_entry( ld, chain ); } LDAPMessage * ldap_next_entry( LDAP *ld, LDAPMessage *entry ) { assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( entry != NULL ); for( entry = entry->lm_chain; entry != NULL; entry = entry->lm_chain ) { if( entry->lm_msgtype == LDAP_RES_SEARCH_ENTRY ) { return( entry ); } } return( NULL ); } int ldap_count_entries( LDAP *ld, LDAPMessage *chain ) { int i; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); for ( i = 0; chain != NULL; chain = chain->lm_chain ) { if( chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY ) { i++; } } return( i ); } int ldap_get_entry_controls( LDAP *ld, LDAPMessage *entry, LDAPControl ***sctrls ) { int rc; BerElement be; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( entry != NULL ); assert( sctrls != NULL ); if ( entry->lm_msgtype != LDAP_RES_SEARCH_ENTRY ) { return LDAP_PARAM_ERROR; } /* make a local copy of the BerElement */ AC_MEMCPY(&be, entry->lm_ber, sizeof(be)); if ( ber_scanf( &be, "{xx" /*}*/ ) == LBER_ERROR ) { rc = LDAP_DECODING_ERROR; goto cleanup_and_return; } rc = ldap_pvt_get_controls( &be, sctrls ); cleanup_and_return: if( rc != LDAP_SUCCESS ) { ld->ld_errno = rc; if( ld->ld_matched != NULL ) { LDAP_FREE( ld->ld_matched ); ld->ld_matched = NULL; } if( ld->ld_error != NULL ) { LDAP_FREE( ld->ld_error ); ld->ld_error = NULL; } } return rc; } openldap-2.5.11+dfsg/libraries/libldap/options.c0000644000175000017500000005550014172327167020266 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" #define LDAP_OPT_REBIND_PROC 0x4e814d #define LDAP_OPT_REBIND_PARAMS 0x4e814e #define LDAP_OPT_NEXTREF_PROC 0x4e815d #define LDAP_OPT_NEXTREF_PARAMS 0x4e815e #define LDAP_OPT_URLLIST_PROC 0x4e816d #define LDAP_OPT_URLLIST_PARAMS 0x4e816e static const LDAPAPIFeatureInfo features[] = { #ifdef LDAP_API_FEATURE_X_OPENLDAP { /* OpenLDAP Extensions API Feature */ LDAP_FEATURE_INFO_VERSION, "X_OPENLDAP", LDAP_API_FEATURE_X_OPENLDAP }, #endif #ifdef LDAP_API_FEATURE_THREAD_SAFE { /* Basic Thread Safe */ LDAP_FEATURE_INFO_VERSION, "THREAD_SAFE", LDAP_API_FEATURE_THREAD_SAFE }, #endif #ifdef LDAP_API_FEATURE_SESSION_THREAD_SAFE { /* Session Thread Safe */ LDAP_FEATURE_INFO_VERSION, "SESSION_THREAD_SAFE", LDAP_API_FEATURE_SESSION_THREAD_SAFE }, #endif #ifdef LDAP_API_FEATURE_OPERATION_THREAD_SAFE { /* Operation Thread Safe */ LDAP_FEATURE_INFO_VERSION, "OPERATION_THREAD_SAFE", LDAP_API_FEATURE_OPERATION_THREAD_SAFE }, #endif #ifdef LDAP_API_FEATURE_X_OPENLDAP_REENTRANT { /* OpenLDAP Reentrant */ LDAP_FEATURE_INFO_VERSION, "X_OPENLDAP_REENTRANT", LDAP_API_FEATURE_X_OPENLDAP_REENTRANT }, #endif #ifdef LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE { /* OpenLDAP Thread Safe */ LDAP_FEATURE_INFO_VERSION, "X_OPENLDAP_THREAD_SAFE", LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE }, #endif #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS { /* V2 Referrals */ LDAP_FEATURE_INFO_VERSION, "X_OPENLDAP_V2_REFERRALS", LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS }, #endif {0, NULL, 0} }; int ldap_get_option( LDAP *ld, int option, void *outvalue) { struct ldapoptions *lo; int rc = LDAP_OPT_ERROR; /* Get pointer to global option structure */ lo = LDAP_INT_GLOBAL_OPT(); if (NULL == lo) { return LDAP_NO_MEMORY; } if( lo->ldo_valid != LDAP_INITIALIZED ) { ldap_int_initialize(lo, NULL); if ( lo->ldo_valid != LDAP_INITIALIZED ) return LDAP_LOCAL_ERROR; } if(ld != NULL) { if( !LDAP_VALID( ld ) ) { return LDAP_OPT_ERROR; } lo = &ld->ld_options; } if(outvalue == NULL) { /* no place to get to */ return LDAP_OPT_ERROR; } LDAP_MUTEX_LOCK( &lo->ldo_mutex ); switch(option) { case LDAP_OPT_API_INFO: { struct ldapapiinfo *info = (struct ldapapiinfo *) outvalue; if(info == NULL) { /* outvalue must point to an apiinfo structure */ break; /* LDAP_OPT_ERROR */ } if(info->ldapai_info_version != LDAP_API_INFO_VERSION) { /* api info version mismatch */ info->ldapai_info_version = LDAP_API_INFO_VERSION; break; /* LDAP_OPT_ERROR */ } info->ldapai_api_version = LDAP_API_VERSION; info->ldapai_protocol_version = LDAP_VERSION_MAX; if(features[0].ldapaif_name == NULL) { info->ldapai_extensions = NULL; } else { int i; info->ldapai_extensions = LDAP_MALLOC(sizeof(char *) * sizeof(features)/sizeof(LDAPAPIFeatureInfo)); if ( info->ldapai_extensions == NULL ) { rc = LDAP_NO_MEMORY; break; } for(i=0; features[i].ldapaif_name != NULL; i++) { info->ldapai_extensions[i] = LDAP_STRDUP(features[i].ldapaif_name); if ( info->ldapai_extensions[i] == NULL ) { rc = LDAP_NO_MEMORY; break; } } if ( features[i].ldapaif_name != NULL ) { break; /* LDAP_NO_MEMORY */ } info->ldapai_extensions[i] = NULL; } info->ldapai_vendor_name = LDAP_STRDUP(LDAP_VENDOR_NAME); info->ldapai_vendor_version = LDAP_VENDOR_VERSION; rc = LDAP_OPT_SUCCESS; break; } break; case LDAP_OPT_DESC: if( ld == NULL || ld->ld_sb == NULL ) { /* bad param */ break; } ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, outvalue ); rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_SOCKBUF: if( ld == NULL ) break; *(Sockbuf **)outvalue = ld->ld_sb; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_TIMEOUT: /* the caller has to free outvalue ! */ if ( lo->ldo_tm_api.tv_sec < 0 ) { *(void **)outvalue = NULL; } else if ( ldap_int_timeval_dup( outvalue, &lo->ldo_tm_api ) != 0 ) { break; /* LDAP_OPT_ERROR */ } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_NETWORK_TIMEOUT: /* the caller has to free outvalue ! */ if ( lo->ldo_tm_net.tv_sec < 0 ) { *(void **)outvalue = NULL; } else if ( ldap_int_timeval_dup( outvalue, &lo->ldo_tm_net ) != 0 ) { break; /* LDAP_OPT_ERROR */ } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_DEREF: * (int *) outvalue = lo->ldo_deref; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_SIZELIMIT: * (int *) outvalue = lo->ldo_sizelimit; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_TIMELIMIT: * (int *) outvalue = lo->ldo_timelimit; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_REFERRALS: * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_REFERRALS); rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_RESTART: * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_RESTART); rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_PROTOCOL_VERSION: * (int *) outvalue = lo->ldo_version; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_SERVER_CONTROLS: * (LDAPControl ***) outvalue = ldap_controls_dup( lo->ldo_sctrls ); rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_CLIENT_CONTROLS: * (LDAPControl ***) outvalue = ldap_controls_dup( lo->ldo_cctrls ); rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_HOST_NAME: * (char **) outvalue = ldap_url_list2hosts(lo->ldo_defludp); rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_SOCKET_BIND_ADDRESSES: if ( lo->ldo_local_ip_addrs.local_ip_addrs == NULL ) { * (void **) outvalue = NULL; } else { * (char **) outvalue = LDAP_STRDUP( lo->ldo_local_ip_addrs.local_ip_addrs ); } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_URI: * (char **) outvalue = ldap_url_list2urls(lo->ldo_defludp); rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_DEFBASE: if( lo->ldo_defbase == NULL ) { * (char **) outvalue = NULL; } else { * (char **) outvalue = LDAP_STRDUP(lo->ldo_defbase); } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_CONNECT_ASYNC: * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_CONNECT_ASYNC); rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_CONNECT_CB: { /* Getting deletes the specified callback */ ldaplist **ll = &lo->ldo_conn_cbs; for (;*ll;ll = &(*ll)->ll_next) { if ((*ll)->ll_data == outvalue) { ldaplist *lc = *ll; *ll = lc->ll_next; LDAP_FREE(lc); break; } } } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_RESULT_CODE: if(ld == NULL) { /* bad param */ break; } * (int *) outvalue = ld->ld_errno; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_DIAGNOSTIC_MESSAGE: if(ld == NULL) { /* bad param */ break; } if( ld->ld_error == NULL ) { * (char **) outvalue = NULL; } else { * (char **) outvalue = LDAP_STRDUP(ld->ld_error); } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_MATCHED_DN: if(ld == NULL) { /* bad param */ break; } if( ld->ld_matched == NULL ) { * (char **) outvalue = NULL; } else { * (char **) outvalue = LDAP_STRDUP( ld->ld_matched ); } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_REFERRAL_URLS: if(ld == NULL) { /* bad param */ break; } if( ld->ld_referrals == NULL ) { * (char ***) outvalue = NULL; } else { * (char ***) outvalue = ldap_value_dup(ld->ld_referrals); } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_API_FEATURE_INFO: { LDAPAPIFeatureInfo *info = (LDAPAPIFeatureInfo *) outvalue; int i; if(info == NULL) break; /* LDAP_OPT_ERROR */ if(info->ldapaif_info_version != LDAP_FEATURE_INFO_VERSION) { /* api info version mismatch */ info->ldapaif_info_version = LDAP_FEATURE_INFO_VERSION; break; /* LDAP_OPT_ERROR */ } if(info->ldapaif_name == NULL) break; /* LDAP_OPT_ERROR */ for(i=0; features[i].ldapaif_name != NULL; i++) { if(!strcmp(info->ldapaif_name, features[i].ldapaif_name)) { info->ldapaif_version = features[i].ldapaif_version; rc = LDAP_OPT_SUCCESS; break; } } } break; case LDAP_OPT_DEBUG_LEVEL: * (int *) outvalue = lo->ldo_debug; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_SESSION_REFCNT: if(ld == NULL) { /* bad param */ break; } LDAP_MUTEX_LOCK( &ld->ld_ldcmutex ); * (int *) outvalue = ld->ld_ldcrefcnt; LDAP_MUTEX_UNLOCK( &ld->ld_ldcmutex ); rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_KEEPCONN: * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_KEEPCONN); rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_X_KEEPALIVE_IDLE: * (int *) outvalue = lo->ldo_keepalive_idle; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_X_KEEPALIVE_PROBES: * (int *) outvalue = lo->ldo_keepalive_probes; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_X_KEEPALIVE_INTERVAL: * (int *) outvalue = lo->ldo_keepalive_interval; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_TCP_USER_TIMEOUT: * (unsigned int *) outvalue = lo->ldo_tcp_user_timeout; rc = LDAP_OPT_SUCCESS; break; default: #ifdef HAVE_TLS if ( ldap_pvt_tls_get_option( ld, option, outvalue ) == 0 ) { rc = LDAP_OPT_SUCCESS; break; } #endif #ifdef HAVE_CYRUS_SASL if ( ldap_int_sasl_get_option( ld, option, outvalue ) == 0 ) { rc = LDAP_OPT_SUCCESS; break; } #endif /* bad param */ break; } LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); return ( rc ); } int ldap_set_option( LDAP *ld, int option, LDAP_CONST void *invalue) { struct ldapoptions *lo; int *dbglvl = NULL; int rc = LDAP_OPT_ERROR; /* Get pointer to global option structure */ lo = LDAP_INT_GLOBAL_OPT(); if (lo == NULL) { return LDAP_NO_MEMORY; } /* * The architecture to turn on debugging has a chicken and egg * problem. Thus, we introduce a fix here. */ if (option == LDAP_OPT_DEBUG_LEVEL) { dbglvl = (int *) invalue; } if( lo->ldo_valid != LDAP_INITIALIZED ) { ldap_int_initialize(lo, dbglvl); if ( lo->ldo_valid != LDAP_INITIALIZED ) return LDAP_LOCAL_ERROR; } if(ld != NULL) { assert( LDAP_VALID( ld ) ); if( !LDAP_VALID( ld ) ) { return LDAP_OPT_ERROR; } lo = &ld->ld_options; } LDAP_MUTEX_LOCK( &lo->ldo_mutex ); switch ( option ) { /* options with boolean values */ case LDAP_OPT_REFERRALS: if(invalue == LDAP_OPT_OFF) { LDAP_BOOL_CLR(lo, LDAP_BOOL_REFERRALS); } else { LDAP_BOOL_SET(lo, LDAP_BOOL_REFERRALS); } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_RESTART: if(invalue == LDAP_OPT_OFF) { LDAP_BOOL_CLR(lo, LDAP_BOOL_RESTART); } else { LDAP_BOOL_SET(lo, LDAP_BOOL_RESTART); } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_CONNECT_ASYNC: if(invalue == LDAP_OPT_OFF) { LDAP_BOOL_CLR(lo, LDAP_BOOL_CONNECT_ASYNC); } else { LDAP_BOOL_SET(lo, LDAP_BOOL_CONNECT_ASYNC); } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_KEEPCONN: if(invalue == LDAP_OPT_OFF) { LDAP_BOOL_CLR(lo, LDAP_BOOL_KEEPCONN); } else { LDAP_BOOL_SET(lo, LDAP_BOOL_KEEPCONN); } rc = LDAP_OPT_SUCCESS; break; /* options which can withstand invalue == NULL */ case LDAP_OPT_SERVER_CONTROLS: { LDAPControl *const *controls = (LDAPControl *const *) invalue; if( lo->ldo_sctrls ) ldap_controls_free( lo->ldo_sctrls ); if( controls == NULL || *controls == NULL ) { lo->ldo_sctrls = NULL; rc = LDAP_OPT_SUCCESS; break; } lo->ldo_sctrls = ldap_controls_dup( controls ); if(lo->ldo_sctrls == NULL) { /* memory allocation error ? */ break; /* LDAP_OPT_ERROR */ } } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_CLIENT_CONTROLS: { LDAPControl *const *controls = (LDAPControl *const *) invalue; if( lo->ldo_cctrls ) ldap_controls_free( lo->ldo_cctrls ); if( controls == NULL || *controls == NULL ) { lo->ldo_cctrls = NULL; rc = LDAP_OPT_SUCCESS; break; } lo->ldo_cctrls = ldap_controls_dup( controls ); if(lo->ldo_cctrls == NULL) { /* memory allocation error ? */ break; /* LDAP_OPT_ERROR */ } } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_HOST_NAME: { const char *host = (const char *) invalue; LDAPURLDesc *ludlist = NULL; rc = LDAP_OPT_SUCCESS; if(host != NULL) { rc = ldap_url_parsehosts( &ludlist, host, lo->ldo_defport ? lo->ldo_defport : LDAP_PORT ); } else if(ld == NULL) { /* * must want global default returned * to initial condition. */ rc = ldap_url_parselist_ext(&ludlist, "ldap://localhost/", NULL, LDAP_PVT_URL_PARSE_NOEMPTY_HOST | LDAP_PVT_URL_PARSE_DEF_PORT ); } else { /* * must want the session default * updated to the current global default */ ludlist = ldap_url_duplist( ldap_int_global_options.ldo_defludp); if (ludlist == NULL) rc = LDAP_NO_MEMORY; } if (rc == LDAP_OPT_SUCCESS) { if (lo->ldo_defludp != NULL) ldap_free_urllist(lo->ldo_defludp); lo->ldo_defludp = ludlist; } break; } case LDAP_OPT_SOCKET_BIND_ADDRESSES: { const char *source_ip = (const char *) invalue; char **source_ip_lst = NULL; ldapsourceip temp_source_ip; memset( &temp_source_ip, 0, sizeof( ldapsourceip ) ); rc = LDAP_OPT_SUCCESS; if( source_ip == NULL ) { if ( ld->ld_options.ldo_local_ip_addrs.local_ip_addrs ) { LDAP_FREE( ld->ld_options.ldo_local_ip_addrs.local_ip_addrs ); memset( &ld->ld_options.ldo_local_ip_addrs, 0, sizeof( ldapsourceip ) ); } } else { source_ip_lst = ldap_str2charray( source_ip, " " ); if ( source_ip_lst == NULL ) rc = LDAP_NO_MEMORY; if( rc == LDAP_OPT_SUCCESS ) { rc = ldap_validate_and_fill_sourceip ( source_ip_lst, &temp_source_ip ); ldap_charray_free( source_ip_lst ); } if ( rc == LDAP_OPT_SUCCESS ) { if ( lo->ldo_local_ip_addrs.local_ip_addrs != NULL ) { LDAP_FREE( lo->ldo_local_ip_addrs.local_ip_addrs ); lo->ldo_local_ip_addrs.local_ip_addrs = NULL; } lo->ldo_local_ip_addrs = temp_source_ip; lo->ldo_local_ip_addrs.local_ip_addrs = LDAP_STRDUP( source_ip ); } } break; } case LDAP_OPT_URI: { const char *urls = (const char *) invalue; LDAPURLDesc *ludlist = NULL; rc = LDAP_OPT_SUCCESS; if(urls != NULL) { rc = ldap_url_parselist_ext(&ludlist, urls, NULL, LDAP_PVT_URL_PARSE_NOEMPTY_HOST | LDAP_PVT_URL_PARSE_DEF_PORT ); } else if(ld == NULL) { /* * must want global default returned * to initial condition. */ rc = ldap_url_parselist_ext(&ludlist, "ldap://localhost/", NULL, LDAP_PVT_URL_PARSE_NOEMPTY_HOST | LDAP_PVT_URL_PARSE_DEF_PORT ); } else { /* * must want the session default * updated to the current global default */ ludlist = ldap_url_duplist( ldap_int_global_options.ldo_defludp); if (ludlist == NULL) rc = LDAP_URL_ERR_MEM; } switch (rc) { case LDAP_URL_SUCCESS: /* Success */ rc = LDAP_SUCCESS; break; case LDAP_URL_ERR_MEM: /* can't allocate memory space */ rc = LDAP_NO_MEMORY; break; case LDAP_URL_ERR_PARAM: /* parameter is bad */ case LDAP_URL_ERR_BADSCHEME: /* URL doesn't begin with "ldap[si]://" */ case LDAP_URL_ERR_BADENCLOSURE: /* URL is missing trailing ">" */ case LDAP_URL_ERR_BADURL: /* URL is bad */ case LDAP_URL_ERR_BADHOST: /* host port is bad */ case LDAP_URL_ERR_BADATTRS: /* bad (or missing) attributes */ case LDAP_URL_ERR_BADSCOPE: /* scope string is invalid (or missing) */ case LDAP_URL_ERR_BADFILTER: /* bad or missing filter */ case LDAP_URL_ERR_BADEXTS: /* bad or missing extensions */ rc = LDAP_PARAM_ERROR; break; } if (rc == LDAP_SUCCESS) { if (lo->ldo_defludp != NULL) ldap_free_urllist(lo->ldo_defludp); lo->ldo_defludp = ludlist; } break; } case LDAP_OPT_DEFBASE: { const char *newbase = (const char *) invalue; char *defbase = NULL; if ( newbase != NULL ) { defbase = LDAP_STRDUP( newbase ); if ( defbase == NULL ) { rc = LDAP_NO_MEMORY; break; } } else if ( ld != NULL ) { defbase = LDAP_STRDUP( ldap_int_global_options.ldo_defbase ); if ( defbase == NULL ) { rc = LDAP_NO_MEMORY; break; } } if ( lo->ldo_defbase != NULL ) LDAP_FREE( lo->ldo_defbase ); lo->ldo_defbase = defbase; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_DIAGNOSTIC_MESSAGE: { const char *err = (const char *) invalue; if(ld == NULL) { /* need a struct ldap */ break; /* LDAP_OPT_ERROR */ } if( ld->ld_error ) { LDAP_FREE(ld->ld_error); ld->ld_error = NULL; } if ( err ) { ld->ld_error = LDAP_STRDUP(err); } } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_MATCHED_DN: { const char *matched = (const char *) invalue; if (ld == NULL) { /* need a struct ldap */ break; /* LDAP_OPT_ERROR */ } if( ld->ld_matched ) { LDAP_FREE(ld->ld_matched); ld->ld_matched = NULL; } if ( matched ) { ld->ld_matched = LDAP_STRDUP( matched ); } } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_REFERRAL_URLS: { char *const *referrals = (char *const *) invalue; if(ld == NULL) { /* need a struct ldap */ break; /* LDAP_OPT_ERROR */ } if( ld->ld_referrals ) { LDAP_VFREE(ld->ld_referrals); } if ( referrals ) { ld->ld_referrals = ldap_value_dup(referrals); } } rc = LDAP_OPT_SUCCESS; break; /* Only accessed from inside this function by ldap_set_rebind_proc() */ case LDAP_OPT_REBIND_PROC: { lo->ldo_rebind_proc = (LDAP_REBIND_PROC *)invalue; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_REBIND_PARAMS: { lo->ldo_rebind_params = (void *)invalue; } rc = LDAP_OPT_SUCCESS; break; /* Only accessed from inside this function by ldap_set_nextref_proc() */ case LDAP_OPT_NEXTREF_PROC: { lo->ldo_nextref_proc = (LDAP_NEXTREF_PROC *)invalue; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_NEXTREF_PARAMS: { lo->ldo_nextref_params = (void *)invalue; } rc = LDAP_OPT_SUCCESS; break; /* Only accessed from inside this function by ldap_set_urllist_proc() */ case LDAP_OPT_URLLIST_PROC: { lo->ldo_urllist_proc = (LDAP_URLLIST_PROC *)invalue; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_URLLIST_PARAMS: { lo->ldo_urllist_params = (void *)invalue; } rc = LDAP_OPT_SUCCESS; break; /* read-only options */ case LDAP_OPT_API_INFO: case LDAP_OPT_DESC: case LDAP_OPT_SOCKBUF: case LDAP_OPT_API_FEATURE_INFO: break; /* LDAP_OPT_ERROR */ /* options which cannot withstand invalue == NULL */ case LDAP_OPT_DEREF: case LDAP_OPT_SIZELIMIT: case LDAP_OPT_TIMELIMIT: case LDAP_OPT_PROTOCOL_VERSION: case LDAP_OPT_RESULT_CODE: case LDAP_OPT_DEBUG_LEVEL: case LDAP_OPT_TIMEOUT: case LDAP_OPT_NETWORK_TIMEOUT: case LDAP_OPT_CONNECT_CB: case LDAP_OPT_X_KEEPALIVE_IDLE: case LDAP_OPT_X_KEEPALIVE_PROBES : case LDAP_OPT_X_KEEPALIVE_INTERVAL : case LDAP_OPT_TCP_USER_TIMEOUT: if(invalue == NULL) { /* no place to set from */ LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); return ( LDAP_OPT_ERROR ); } break; default: #ifdef HAVE_TLS if ( ldap_pvt_tls_set_option( ld, option, (void *)invalue ) == 0 ) { LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); return ( LDAP_OPT_SUCCESS ); } #endif #ifdef HAVE_CYRUS_SASL if ( ldap_int_sasl_set_option( ld, option, (void *)invalue ) == 0 ) { LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); return ( LDAP_OPT_SUCCESS ); } #endif /* bad param */ break; /* LDAP_OPT_ERROR */ } /* options which cannot withstand invalue == NULL */ switch(option) { case LDAP_OPT_DEREF: /* FIXME: check value for protocol compliance? */ lo->ldo_deref = * (const int *) invalue; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_SIZELIMIT: /* FIXME: check value for protocol compliance? */ lo->ldo_sizelimit = * (const int *) invalue; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_TIMELIMIT: /* FIXME: check value for protocol compliance? */ lo->ldo_timelimit = * (const int *) invalue; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_TIMEOUT: { const struct timeval *tv = (const struct timeval *) invalue; lo->ldo_tm_api = *tv; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_NETWORK_TIMEOUT: { const struct timeval *tv = (const struct timeval *) invalue; lo->ldo_tm_net = *tv; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_PROTOCOL_VERSION: { int vers = * (const int *) invalue; if (vers < LDAP_VERSION_MIN || vers > LDAP_VERSION_MAX) { /* not supported */ break; } lo->ldo_version = vers; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_RESULT_CODE: { int err = * (const int *) invalue; if(ld == NULL) { /* need a struct ldap */ break; } ld->ld_errno = err; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_DEBUG_LEVEL: lo->ldo_debug = * (const int *) invalue; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_CONNECT_CB: { /* setting pushes the callback */ ldaplist *ll; ll = LDAP_MALLOC( sizeof( *ll )); if ( ll == NULL ) { rc = LDAP_NO_MEMORY; break; } ll->ll_data = (void *)invalue; ll->ll_next = lo->ldo_conn_cbs; lo->ldo_conn_cbs = ll; } rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_X_KEEPALIVE_IDLE: lo->ldo_keepalive_idle = * (const int *) invalue; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_X_KEEPALIVE_PROBES : lo->ldo_keepalive_probes = * (const int *) invalue; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_X_KEEPALIVE_INTERVAL : lo->ldo_keepalive_interval = * (const int *) invalue; rc = LDAP_OPT_SUCCESS; break; case LDAP_OPT_TCP_USER_TIMEOUT: lo->ldo_tcp_user_timeout = * (const unsigned int *) invalue; rc = LDAP_OPT_SUCCESS; break; } LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); return ( rc ); } int ldap_set_rebind_proc( LDAP *ld, LDAP_REBIND_PROC *proc, void *params ) { int rc; rc = ldap_set_option( ld, LDAP_OPT_REBIND_PROC, (void *)proc ); if( rc != LDAP_OPT_SUCCESS ) return rc; rc = ldap_set_option( ld, LDAP_OPT_REBIND_PARAMS, (void *)params ); return rc; } int ldap_set_nextref_proc( LDAP *ld, LDAP_NEXTREF_PROC *proc, void *params ) { int rc; rc = ldap_set_option( ld, LDAP_OPT_NEXTREF_PROC, (void *)proc ); if( rc != LDAP_OPT_SUCCESS ) return rc; rc = ldap_set_option( ld, LDAP_OPT_NEXTREF_PARAMS, (void *)params ); return rc; } int ldap_set_urllist_proc( LDAP *ld, LDAP_URLLIST_PROC *proc, void *params ) { int rc; rc = ldap_set_option( ld, LDAP_OPT_URLLIST_PROC, (void *)proc ); if( rc != LDAP_OPT_SUCCESS ) return rc; rc = ldap_set_option( ld, LDAP_OPT_URLLIST_PARAMS, (void *)params ); return rc; } openldap-2.5.11+dfsg/libraries/libldap/ldap-int.h0000644000175000017500000006224614172327167020315 0ustar ryanryan/* ldap-int.h - defines & prototypes internal to the LDAP library */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. */ #ifndef _LDAP_INT_H #define _LDAP_INT_H 1 #ifndef NO_THREADS #define LDAP_R_COMPILE 1 #endif #include "../liblber/lber-int.h" #include "lutil.h" #include "ldap_avl.h" #ifdef LDAP_R_COMPILE #include #endif #ifdef HAVE_CYRUS_SASL /* the need for this should be removed */ #ifdef HAVE_SASL_SASL_H #include #else #include #endif #define SASL_MAX_BUFF_SIZE (0xffffff) #define SASL_MIN_BUFF_SIZE 4096 #endif /* for struct timeval */ #include #include #undef TV2MILLISEC #define TV2MILLISEC(tv) (((tv)->tv_sec * 1000) + ((tv)->tv_usec/1000)) /* * Support needed if the library is running in the kernel */ #if LDAP_INT_IN_KERNEL /* * Platform specific function to return a pointer to the * process-specific global options. * * This function should perform the following functions: * Allocate and initialize a global options struct on a per process basis * Use callers process identifier to return its global options struct * Note: Deallocate structure when the process exits */ # define LDAP_INT_GLOBAL_OPT() ldap_int_global_opt() struct ldapoptions *ldap_int_global_opt(void); #else # define LDAP_INT_GLOBAL_OPT() (&ldap_int_global_options) #endif /* if used from server code, ldap_debug already points elsewhere */ #ifndef ldap_debug #define ldap_debug ((LDAP_INT_GLOBAL_OPT())->ldo_debug) #endif /* !ldap_debug */ #define LDAP_INT_DEBUG #include "ldap_log.h" #ifdef LDAP_DEBUG #define DebugTest( level ) \ ( ldap_debug & level ) #define Debug0( level, fmt ) \ do { if ( DebugTest( (level) ) ) \ ldap_log_printf( NULL, (level), fmt ); \ } while ( 0 ) #define Debug1( level, fmt, arg1 ) \ do { if ( DebugTest( (level) ) ) \ ldap_log_printf( NULL, (level), fmt, arg1 ); \ } while ( 0 ) #define Debug2( level, fmt, arg1, arg2 ) \ do { if ( DebugTest( (level) ) ) \ ldap_log_printf( NULL, (level), fmt, arg1, arg2 ); \ } while ( 0 ) #define Debug3( level, fmt, arg1, arg2, arg3 ) \ do { if ( DebugTest( (level) ) ) \ ldap_log_printf( NULL, (level), fmt, arg1, arg2, arg3 ); \ } while ( 0 ) #else #define DebugTest( level ) (0 == 1) #define Debug0( level, fmt ) ((void)0) #define Debug1( level, fmt, arg1 ) ((void)0) #define Debug2( level, fmt, arg1, arg2 ) ((void)0) #define Debug3( level, fmt, arg1, arg2, arg3 ) ((void)0) #endif /* LDAP_DEBUG */ #define LDAP_DEPRECATED 1 #include "ldap.h" #include "ldap_pvt.h" LDAP_BEGIN_DECL #define LDAP_URL_PREFIX "ldap://" #define LDAP_URL_PREFIX_LEN STRLENOF(LDAP_URL_PREFIX) #define PLDAP_URL_PREFIX "pldap://" #define PLDAP_URL_PREFIX_LEN STRLENOF(PLDAP_URL_PREFIX) #define LDAPS_URL_PREFIX "ldaps://" #define LDAPS_URL_PREFIX_LEN STRLENOF(LDAPS_URL_PREFIX) #define PLDAPS_URL_PREFIX "pldaps://" #define PLDAPS_URL_PREFIX_LEN STRLENOF(PLDAPS_URL_PREFIX) #define LDAPI_URL_PREFIX "ldapi://" #define LDAPI_URL_PREFIX_LEN STRLENOF(LDAPI_URL_PREFIX) #ifdef LDAP_CONNECTIONLESS #define LDAPC_URL_PREFIX "cldap://" #define LDAPC_URL_PREFIX_LEN STRLENOF(LDAPC_URL_PREFIX) #endif #define LDAP_URL_URLCOLON "URL:" #define LDAP_URL_URLCOLON_LEN STRLENOF(LDAP_URL_URLCOLON) #define LDAP_REF_STR "Referral:\n" #define LDAP_REF_STR_LEN STRLENOF(LDAP_REF_STR) #define LDAP_LDAP_REF_STR LDAP_URL_PREFIX #define LDAP_LDAP_REF_STR_LEN LDAP_URL_PREFIX_LEN #define LDAP_DEFAULT_REFHOPLIMIT 5 #define LDAP_BOOL_REFERRALS 0 #define LDAP_BOOL_RESTART 1 #define LDAP_BOOL_TLS 3 #define LDAP_BOOL_CONNECT_ASYNC 4 #define LDAP_BOOL_SASL_NOCANON 5 #define LDAP_BOOL_KEEPCONN 6 #define LDAP_BOOLEANS unsigned long #define LDAP_BOOL(n) ((LDAP_BOOLEANS)1 << (n)) #define LDAP_BOOL_GET(lo, bool) \ ((lo)->ldo_booleans & LDAP_BOOL(bool) ? -1 : 0) #define LDAP_BOOL_SET(lo, bool) ((lo)->ldo_booleans |= LDAP_BOOL(bool)) #define LDAP_BOOL_CLR(lo, bool) ((lo)->ldo_booleans &= ~LDAP_BOOL(bool)) #define LDAP_BOOL_ZERO(lo) ((lo)->ldo_booleans = 0) /* * This structure represents both ldap messages and ldap responses. * These are really the same, except in the case of search responses, * where a response has multiple messages. */ struct ldapmsg { ber_int_t lm_msgid; /* the message id */ ber_tag_t lm_msgtype; /* the message type */ BerElement *lm_ber; /* the ber encoded message contents */ struct ldapmsg *lm_chain; /* for search - next msg in the resp */ struct ldapmsg *lm_chain_tail; struct ldapmsg *lm_next; /* next response */ time_t lm_time; /* used to maintain cache */ }; #ifdef HAVE_TLS struct ldaptls { char *lt_certfile; char *lt_keyfile; char *lt_dhfile; char *lt_cacertfile; char *lt_cacertdir; char *lt_ciphersuite; char *lt_crlfile; char *lt_randfile; /* OpenSSL only */ char *lt_ecname; /* OpenSSL only */ int lt_protocol_min; int lt_protocol_max; struct berval lt_cacert; struct berval lt_cert; struct berval lt_key; }; #endif typedef struct ldaplist { struct ldaplist *ll_next; void *ll_data; } ldaplist; /* * LDAP Client Source IP structure */ typedef struct ldapsourceip { char *local_ip_addrs; struct in_addr ip4_addr; unsigned short has_ipv4; #ifdef LDAP_PF_INET6 struct in6_addr ip6_addr; unsigned short has_ipv6; #endif } ldapsourceip; /* * structure representing get/set'able options * which have global defaults. * Protect access to this struct with ldo_mutex * ldap_log.h:ldapoptions_prefix must match the head of this struct. */ struct ldapoptions { short ldo_valid; #define LDAP_UNINITIALIZED 0x0 #define LDAP_INITIALIZED 0x1 #define LDAP_VALID_SESSION 0x2 #define LDAP_TRASHED_SESSION 0xFF int ldo_debug; ber_int_t ldo_version; ber_int_t ldo_deref; ber_int_t ldo_timelimit; ber_int_t ldo_sizelimit; /* per API call timeout */ struct timeval ldo_tm_api; struct timeval ldo_tm_net; LDAPURLDesc *ldo_defludp; int ldo_defport; char* ldo_defbase; char* ldo_defbinddn; /* bind dn */ /* * Per connection tcp-keepalive settings (Linux only, * ignored where unsupported) */ ber_int_t ldo_keepalive_idle; ber_int_t ldo_keepalive_probes; ber_int_t ldo_keepalive_interval; /* * Per connection tcp user timeout (Linux >= 2.6.37 only, * ignored where unsupported) */ ber_uint_t ldo_tcp_user_timeout; int ldo_refhoplimit; /* limit on referral nesting */ /* LDAPv3 server and client controls */ LDAPControl **ldo_sctrls; LDAPControl **ldo_cctrls; /* LDAP rebind callback function */ LDAP_REBIND_PROC *ldo_rebind_proc; void *ldo_rebind_params; LDAP_NEXTREF_PROC *ldo_nextref_proc; void *ldo_nextref_params; LDAP_URLLIST_PROC *ldo_urllist_proc; void *ldo_urllist_params; /* LDAP connection callback stack */ ldaplist *ldo_conn_cbs; LDAP_BOOLEANS ldo_booleans; /* boolean options */ #define LDAP_LDO_NULLARG ,0,0,0,0 ,{0},{0} ,0,0,0,0, 0,0,0,0,0, 0,0, 0,0,0,0,0,0, 0, 0 /* LDAP user configured bind IPs */ struct ldapsourceip ldo_local_ip_addrs; #ifdef LDAP_PF_INET6 #define LDAP_LDO_SOURCEIP_NULLARG ,{0,0,0,0,0} #else #define LDAP_LDO_SOURCEIP_NULLARG ,{0,0,0} #endif #ifdef LDAP_CONNECTIONLESS #define LDAP_IS_UDP(ld) ((ld)->ld_options.ldo_is_udp) void* ldo_peer; /* struct sockaddr* */ char* ldo_cldapdn; int ldo_is_udp; #define LDAP_LDO_CONNECTIONLESS_NULLARG ,0,0,0 #else #define LDAP_LDO_CONNECTIONLESS_NULLARG #endif #ifdef HAVE_TLS /* tls context */ void *ldo_tls_ctx; LDAP_TLS_CONNECT_CB *ldo_tls_connect_cb; void* ldo_tls_connect_arg; struct ldaptls ldo_tls_info; #define ldo_tls_certfile ldo_tls_info.lt_certfile #define ldo_tls_keyfile ldo_tls_info.lt_keyfile #define ldo_tls_dhfile ldo_tls_info.lt_dhfile #define ldo_tls_ecname ldo_tls_info.lt_ecname #define ldo_tls_cacertfile ldo_tls_info.lt_cacertfile #define ldo_tls_cacertdir ldo_tls_info.lt_cacertdir #define ldo_tls_ciphersuite ldo_tls_info.lt_ciphersuite #define ldo_tls_protocol_min ldo_tls_info.lt_protocol_min #define ldo_tls_protocol_max ldo_tls_info.lt_protocol_max #define ldo_tls_crlfile ldo_tls_info.lt_crlfile #define ldo_tls_randfile ldo_tls_info.lt_randfile #define ldo_tls_cacert ldo_tls_info.lt_cacert #define ldo_tls_cert ldo_tls_info.lt_cert #define ldo_tls_key ldo_tls_info.lt_key int ldo_tls_mode; int ldo_tls_require_cert; int ldo_tls_impl; int ldo_tls_crlcheck; int ldo_tls_require_san; char *ldo_tls_pin_hashalg; struct berval ldo_tls_pin; #define LDAP_LDO_TLS_NULLARG ,0,0,0,{0,0,0,0,0,0,0,0,0},0,0,0,0,0,0,{0,0} #else #define LDAP_LDO_TLS_NULLARG #endif #ifdef HAVE_CYRUS_SASL char* ldo_def_sasl_mech; /* SASL Mechanism(s) */ char* ldo_def_sasl_realm; /* SASL realm */ char* ldo_def_sasl_authcid; /* SASL authentication identity */ char* ldo_def_sasl_authzid; /* SASL authorization identity */ /* SASL Security Properties */ struct sasl_security_properties ldo_sasl_secprops; int ldo_sasl_cbinding; #define LDAP_LDO_SASL_NULLARG ,0,0,0,0,{0},0 #else #define LDAP_LDO_SASL_NULLARG #endif #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_t ldo_mutex; #define LDAP_LDO_MUTEX_NULLARG , LDAP_PVT_MUTEX_NULL #else #define LDAP_LDO_MUTEX_NULLARG #endif }; /* * structure for representing an LDAP server connection */ typedef struct ldap_conn { Sockbuf *lconn_sb; #ifdef HAVE_CYRUS_SASL void *lconn_sasl_authctx; /* context for bind */ void *lconn_sasl_sockctx; /* for security layer */ void *lconn_sasl_cbind; /* for channel binding */ #endif int lconn_refcnt; time_t lconn_created; /* time */ time_t lconn_lastused; /* time */ int lconn_rebind_inprogress; /* set if rebind in progress */ char ***lconn_rebind_queue; /* used if rebind in progress */ int lconn_status; #define LDAP_CONNST_NEEDSOCKET 1 #define LDAP_CONNST_CONNECTING 2 #define LDAP_CONNST_CONNECTED 3 LDAPURLDesc *lconn_server; BerElement *lconn_ber; /* ber receiving on this conn. */ struct ldap_conn *lconn_next; } LDAPConn; /* * structure used to track outstanding requests */ typedef struct ldapreq { ber_int_t lr_msgid; /* the message id */ int lr_status; /* status of request */ #define LDAP_REQST_COMPLETED 0 #define LDAP_REQST_INPROGRESS 1 #define LDAP_REQST_CHASINGREFS 2 #define LDAP_REQST_NOTCONNECTED 3 #define LDAP_REQST_WRITING 4 int lr_refcnt; /* count of references */ int lr_outrefcnt; /* count of outstanding referrals */ int lr_abandoned; /* the request has been abandoned */ ber_int_t lr_origid; /* original request's message id */ int lr_parentcnt; /* count of parent requests */ ber_tag_t lr_res_msgtype; /* result message type */ ber_int_t lr_res_errno; /* result LDAP errno */ char *lr_res_error; /* result error string */ char *lr_res_matched;/* result matched DN string */ BerElement *lr_ber; /* ber encoded request contents */ LDAPConn *lr_conn; /* connection used to send request */ struct berval lr_dn; /* DN of request, in lr_ber */ struct ldapreq *lr_parent; /* request that spawned this referral */ struct ldapreq *lr_child; /* first child request */ struct ldapreq *lr_refnext; /* next referral spawned */ struct ldapreq *lr_prev; /* previous request */ struct ldapreq *lr_next; /* next request */ } LDAPRequest; /* * structure for client cache */ #define LDAP_CACHE_BUCKETS 31 /* cache hash table size */ typedef struct ldapcache { LDAPMessage *lc_buckets[LDAP_CACHE_BUCKETS];/* hash table */ LDAPMessage *lc_requests; /* unfulfilled reqs */ long lc_timeout; /* request timeout */ ber_len_t lc_maxmem; /* memory to use */ ber_len_t lc_memused; /* memory in use */ int lc_enabled; /* enabled? */ unsigned long lc_options; /* options */ #define LDAP_CACHE_OPT_CACHENOERRS 0x00000001 #define LDAP_CACHE_OPT_CACHEALLERRS 0x00000002 } LDAPCache; /* * structure containing referral request info for rebind procedure */ typedef struct ldapreqinfo { ber_len_t ri_msgid; int ri_request; char *ri_url; } LDAPreqinfo; /* * structure representing an ldap connection */ struct ldap_common { Sockbuf *ldc_sb; /* socket descriptor & buffer */ #define ld_sb ldc->ldc_sb unsigned short ldc_lberoptions; #define ld_lberoptions ldc->ldc_lberoptions /* protected by msgid_mutex */ ber_len_t ldc_msgid; #define ld_msgid ldc->ldc_msgid /* do not mess with these */ /* protected by req_mutex */ TAvlnode *ldc_requests; /* list of outstanding requests */ /* protected by res_mutex */ LDAPMessage *ldc_responses; /* list of outstanding responses */ #define ld_requests ldc->ldc_requests #define ld_responses ldc->ldc_responses /* protected by abandon_mutex */ ber_len_t ldc_nabandoned; ber_int_t *ldc_abandoned; /* array of abandoned requests */ #define ld_nabandoned ldc->ldc_nabandoned #define ld_abandoned ldc->ldc_abandoned /* unused by libldap */ LDAPCache *ldc_cache; /* non-null if cache is initialized */ #define ld_cache ldc->ldc_cache /* do not mess with the rest though */ /* protected by conn_mutex */ LDAPConn *ldc_defconn; /* default connection */ #define ld_defconn ldc->ldc_defconn LDAPConn *ldc_conns; /* list of server connections */ #define ld_conns ldc->ldc_conns void *ldc_selectinfo;/* platform specifics for select */ #define ld_selectinfo ldc->ldc_selectinfo /* ldap_common refcnt - free only if 0 */ /* protected by ldc_mutex */ unsigned int ldc_refcnt; #define ld_ldcrefcnt ldc->ldc_refcnt /* protected by ldo_mutex */ struct ldapoptions ldc_options; #define ld_options ldc->ldc_options #define ld_valid ld_options.ldo_valid #define ld_debug ld_options.ldo_debug #define ld_deref ld_options.ldo_deref #define ld_timelimit ld_options.ldo_timelimit #define ld_sizelimit ld_options.ldo_sizelimit #define ld_defbinddn ld_options.ldo_defbinddn #define ld_defbase ld_options.ldo_defbase #define ld_defhost ld_options.ldo_defhost #define ld_defport ld_options.ldo_defport #define ld_refhoplimit ld_options.ldo_refhoplimit #define ld_sctrls ld_options.ldo_sctrls #define ld_cctrls ld_options.ldo_cctrls #define ld_rebind_proc ld_options.ldo_rebind_proc #define ld_rebind_params ld_options.ldo_rebind_params #define ld_nextref_proc ld_options.ldo_nextref_proc #define ld_nextref_params ld_options.ldo_nextref_params #define ld_urllist_proc ld_options.ldo_urllist_proc #define ld_urllist_params ld_options.ldo_urllist_params #define ld_version ld_options.ldo_version #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_t ldc_mutex; ldap_pvt_thread_mutex_t ldc_msgid_mutex; ldap_pvt_thread_mutex_t ldc_conn_mutex; ldap_pvt_thread_mutex_t ldc_req_mutex; ldap_pvt_thread_mutex_t ldc_res_mutex; ldap_pvt_thread_mutex_t ldc_abandon_mutex; #define ld_ldopts_mutex ld_options.ldo_mutex #define ld_ldcmutex ldc->ldc_mutex #define ld_msgid_mutex ldc->ldc_msgid_mutex #define ld_conn_mutex ldc->ldc_conn_mutex #define ld_req_mutex ldc->ldc_req_mutex #define ld_res_mutex ldc->ldc_res_mutex #define ld_abandon_mutex ldc->ldc_abandon_mutex #endif }; struct ldap { /* thread shared */ struct ldap_common *ldc; /* thread specific */ ber_int_t ld_errno; char *ld_error; char *ld_matched; char **ld_referrals; }; #define LDAP_VALID(ld) ( (ld)->ld_valid == LDAP_VALID_SESSION ) #define LDAP_TRASHED(ld) ( (ld)->ld_valid == LDAP_TRASHED_SESSION ) #define LDAP_TRASH(ld) ( (ld)->ld_valid = LDAP_TRASHED_SESSION ) #ifdef LDAP_R_COMPILE LDAP_V ( ldap_pvt_thread_mutex_t ) ldap_int_resolv_mutex; LDAP_V ( ldap_pvt_thread_mutex_t ) ldap_int_hostname_mutex; LDAP_V ( int ) ldap_int_stackguard; #endif #ifdef LDAP_R_COMPILE #define LDAP_MUTEX_LOCK(mutex) ldap_pvt_thread_mutex_lock( mutex ) #define LDAP_MUTEX_UNLOCK(mutex) ldap_pvt_thread_mutex_unlock( mutex ) #define LDAP_ASSERT_MUTEX_OWNER(mutex) \ LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER(mutex) #else #define LDAP_MUTEX_LOCK(mutex) ((void) 0) #define LDAP_MUTEX_UNLOCK(mutex) ((void) 0) #define LDAP_ASSERT_MUTEX_OWNER(mutex) ((void) 0) #endif #define LDAP_NEXT_MSGID(ld, id) do { \ LDAP_MUTEX_LOCK( &(ld)->ld_msgid_mutex ); \ (id) = ++(ld)->ld_msgid; \ LDAP_MUTEX_UNLOCK( &(ld)->ld_msgid_mutex ); \ } while (0) /* * in abandon.c */ LDAP_F (int) ldap_int_bisect_find( ber_int_t *v, ber_len_t n, ber_int_t id, int *idxp ); LDAP_F (int) ldap_int_bisect_insert( ber_int_t **vp, ber_len_t *np, int id, int idx ); LDAP_F (int) ldap_int_bisect_delete( ber_int_t **vp, ber_len_t *np, int id, int idx ); /* * in add.c */ LDAP_F (BerElement *) ldap_build_add_req LDAP_P(( LDAP *ld, const char *dn, LDAPMod **attrs, LDAPControl **sctrls, LDAPControl **cctrls, ber_int_t *msgidp )); /* * in lbase64.c */ LDAP_F (int) ldap_int_decode_b64_inplace LDAP_P(( struct berval *value )); /* * in compare.c */ LDAP_F (BerElement *) ldap_build_compare_req LDAP_P(( LDAP *ld, const char *dn, const char *attr, struct berval *bvalue, LDAPControl **sctrls, LDAPControl **cctrls, ber_int_t *msgidp )); /* * in delete.c */ LDAP_F (BerElement *) ldap_build_delete_req LDAP_P(( LDAP *ld, const char *dn, LDAPControl **sctrls, LDAPControl **cctrls, ber_int_t *msgidp )); /* * in extended.c */ LDAP_F (BerElement *) ldap_build_extended_req LDAP_P(( LDAP *ld, const char *reqoid, struct berval *reqdata, LDAPControl **sctrls, LDAPControl **cctrls, ber_int_t *msgidp )); /* * in init.c */ LDAP_V ( struct ldapoptions ) ldap_int_global_options; LDAP_F ( void ) ldap_int_initialize LDAP_P((struct ldapoptions *, int *)); LDAP_F ( void ) ldap_int_initialize_global_options LDAP_P(( struct ldapoptions *, int *)); /* memory.c */ /* simple macros to realloc for now */ #define LDAP_MALLOC(s) (ber_memalloc_x((s),NULL)) #define LDAP_CALLOC(n,s) (ber_memcalloc_x((n),(s),NULL)) #define LDAP_REALLOC(p,s) (ber_memrealloc_x((p),(s),NULL)) #define LDAP_FREE(p) (ber_memfree_x((p),NULL)) #define LDAP_VFREE(v) (ber_memvfree_x((void **)(v),NULL)) #define LDAP_STRDUP(s) (ber_strdup_x((s),NULL)) #define LDAP_STRNDUP(s,l) (ber_strndup_x((s),(l),NULL)) #define LDAP_MALLOCX(s,x) (ber_memalloc_x((s),(x))) #define LDAP_CALLOCX(n,s,x) (ber_memcalloc_x((n),(s),(x))) #define LDAP_REALLOCX(p,s,x) (ber_memrealloc_x((p),(s),(x))) #define LDAP_FREEX(p,x) (ber_memfree_x((p),(x))) #define LDAP_VFREEX(v,x) (ber_memvfree_x((void **)(v),(x))) #define LDAP_STRDUPX(s,x) (ber_strdup_x((s),(x))) #define LDAP_STRNDUPX(s,l,x) (ber_strndup_x((s),(l),(x))) /* * in error.c */ LDAP_F (void) ldap_int_error_init( void ); /* * in modify.c */ LDAP_F (BerElement *) ldap_build_modify_req LDAP_P(( LDAP *ld, const char *dn, LDAPMod **mods, LDAPControl **sctrls, LDAPControl **cctrls, ber_int_t *msgidp )); /* * in modrdn.c */ LDAP_F (BerElement *) ldap_build_moddn_req LDAP_P(( LDAP *ld, const char *dn, const char *newrdn, const char *newSuperior, int deleteoldrdn, LDAPControl **sctrls, LDAPControl **cctrls, ber_int_t *msgidp )); /* * in unit-int.c */ LDAP_F (void) ldap_int_utils_init LDAP_P(( void )); /* * in print.c */ LDAP_F (int) ldap_log_printf LDAP_P((LDAP *ld, int level, const char *fmt, ...)) LDAP_GCCATTR((format(printf, 3, 4))); /* * in controls.c */ LDAP_F (int) ldap_int_put_controls LDAP_P(( LDAP *ld, LDAPControl *const *ctrls, BerElement *ber )); LDAP_F (int) ldap_int_client_controls LDAP_P(( LDAP *ld, LDAPControl **ctrlp )); /* * in dsparse.c */ LDAP_F (int) ldap_int_next_line_tokens LDAP_P(( char **bufp, ber_len_t *blenp, char ***toksp )); /* * in open.c */ LDAP_F (int) ldap_open_defconn( LDAP *ld ); LDAP_F (int) ldap_int_open_connection( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srvlist, int async ); LDAP_F (int) ldap_int_check_async_open( LDAP *ld, ber_socket_t sd ); /* * in os-ip.c */ #ifndef HAVE_POLL LDAP_V (int) ldap_int_tblsize; LDAP_F (void) ldap_int_ip_init( void ); #endif LDAP_F (int) ldap_int_timeval_dup( struct timeval **dest, const struct timeval *tm ); LDAP_F (int) ldap_connect_to_host( LDAP *ld, Sockbuf *sb, int proto, LDAPURLDesc *srv, int async ); LDAP_F (int) ldap_int_poll( LDAP *ld, ber_socket_t s, struct timeval *tvp, int wr ); #if defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL) LDAP_V (char *) ldap_int_hostname; LDAP_F (char *) ldap_host_connected_to( Sockbuf *sb, const char *host ); #endif LDAP_F (int) ldap_int_select( LDAP *ld, struct timeval *timeout ); LDAP_F (void *) ldap_new_select_info( void ); LDAP_F (void) ldap_free_select_info( void *sip ); LDAP_F (void) ldap_mark_select_write( LDAP *ld, Sockbuf *sb ); LDAP_F (void) ldap_mark_select_read( LDAP *ld, Sockbuf *sb ); LDAP_F (void) ldap_mark_select_clear( LDAP *ld, Sockbuf *sb ); LDAP_F (void) ldap_clear_select_write( LDAP *ld, Sockbuf *sb ); LDAP_F (int) ldap_is_read_ready( LDAP *ld, Sockbuf *sb ); LDAP_F (int) ldap_is_write_ready( LDAP *ld, Sockbuf *sb ); LDAP_F (int) ldap_validate_and_fill_sourceip ( char** source_ip_lst, ldapsourceip* temp_source_ip ); LDAP_F (int) ldap_int_connect_cbs( LDAP *ld, Sockbuf *sb, ber_socket_t *s, LDAPURLDesc *srv, struct sockaddr *addr ); /* * in os-local.c */ #ifdef LDAP_PF_LOCAL LDAP_F (int) ldap_connect_to_path( LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv, int async ); #endif /* LDAP_PF_LOCAL */ /* * in request.c */ LDAP_F (ber_int_t) ldap_send_initial_request( LDAP *ld, ber_tag_t msgtype, const char *dn, BerElement *ber, ber_int_t msgid ); LDAP_F (BerElement *) ldap_alloc_ber_with_options( LDAP *ld ); LDAP_F (void) ldap_set_ber_options( LDAP *ld, BerElement *ber ); LDAP_F (int) ldap_send_server_request( LDAP *ld, BerElement *ber, ber_int_t msgid, LDAPRequest *parentreq, LDAPURLDesc **srvlist, LDAPConn *lc, LDAPreqinfo *bind, int noconn, int m_res ); LDAP_F (LDAPConn *) ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb, int connect, LDAPreqinfo *bind, int m_req, int m_res ); LDAP_F (LDAPRequest *) ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid ); LDAP_F (void) ldap_return_request( LDAP *ld, LDAPRequest *lr, int freeit ); LDAP_F (int) ldap_req_cmp( const void *l, const void *r ); LDAP_F (void) ldap_do_free_request( void *arg ); LDAP_F (void) ldap_free_request( LDAP *ld, LDAPRequest *lr ); LDAP_F (void) ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ); LDAP_F (void) ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all ); LDAP_F (void) ldap_dump_requests_and_responses( LDAP *ld ); LDAP_F (int) ldap_chase_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, int sref, int *hadrefp ); LDAP_F (int) ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char **referralsp, int *hadrefp ); LDAP_F (int) ldap_append_referral( LDAP *ld, char **referralsp, char *s ); LDAP_F (int) ldap_int_flush_request( LDAP *ld, LDAPRequest *lr ); /* * in result.c: */ LDAP_F (const char *) ldap_int_msgtype2str( ber_tag_t tag ); /* * in search.c */ LDAP_F (BerElement *) ldap_build_search_req LDAP_P(( LDAP *ld, const char *base, ber_int_t scope, const char *filter, char **attrs, ber_int_t attrsonly, LDAPControl **sctrls, LDAPControl **cctrls, ber_int_t timelimit, ber_int_t sizelimit, ber_int_t deref, ber_int_t *msgidp)); /* * in unbind.c */ LDAP_F (int) ldap_ld_free LDAP_P(( LDAP *ld, int close, LDAPControl **sctrls, LDAPControl **cctrls )); LDAP_F (int) ldap_send_unbind LDAP_P(( LDAP *ld, Sockbuf *sb, LDAPControl **sctrls, LDAPControl **cctrls )); /* * in url.c */ LDAP_F (LDAPURLDesc *) ldap_url_dup LDAP_P(( LDAPURLDesc *ludp )); LDAP_F (LDAPURLDesc *) ldap_url_duplist LDAP_P(( LDAPURLDesc *ludlist )); LDAP_F (int) ldap_url_parsehosts LDAP_P(( LDAPURLDesc **ludlist, const char *hosts, int port )); LDAP_F (char *) ldap_url_list2hosts LDAP_P(( LDAPURLDesc *ludlist )); /* * in cyrus.c */ LDAP_F (int) ldap_int_sasl_init LDAP_P(( void )); LDAP_F (int) ldap_int_sasl_open LDAP_P(( LDAP *ld, LDAPConn *conn, const char* host )); LDAP_F (int) ldap_int_sasl_close LDAP_P(( LDAP *ld, LDAPConn *conn )); LDAP_F (int) ldap_int_sasl_external LDAP_P(( LDAP *ld, LDAPConn *conn, const char* authid, ber_len_t ssf )); LDAP_F (int) ldap_int_sasl_get_option LDAP_P(( LDAP *ld, int option, void *arg )); LDAP_F (int) ldap_int_sasl_set_option LDAP_P(( LDAP *ld, int option, void *arg )); LDAP_F (int) ldap_int_sasl_config LDAP_P(( struct ldapoptions *lo, int option, const char *arg )); LDAP_F (int) ldap_int_sasl_bind LDAP_P(( LDAP *ld, const char *, const char *, LDAPControl **, LDAPControl **, /* should be passed in client controls */ unsigned flags, LDAP_SASL_INTERACT_PROC *interact, void *defaults, LDAPMessage *result, const char **rmech, int *msgid )); /* in sasl.c */ LDAP_F (BerElement *) ldap_build_bind_req LDAP_P(( LDAP *ld, const char *dn, const char *mech, struct berval *cred, LDAPControl **sctrls, LDAPControl **cctrls, ber_int_t *msgidp )); /* in schema.c */ LDAP_F (char *) ldap_int_parse_numericoid LDAP_P(( const char **sp, int *code, const int flags )); /* * in tls.c */ LDAP_F (int) ldap_int_tls_start LDAP_P(( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv )); LDAP_F (void) ldap_int_tls_destroy LDAP_P(( struct ldapoptions *lo )); /* * in getvalues.c */ LDAP_F (char **) ldap_value_dup LDAP_P(( char *const *vals )); LDAP_END_DECL #endif /* _LDAP_INT_H */ openldap-2.5.11+dfsg/libraries/libldap/url.c0000644000175000017500000007312114172327167017374 0ustar ryanryan/* LIBLDAP url.c -- LDAP URL (RFC 4516) related routines */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1996 Regents of the University of Michigan. * All rights reserved. */ /* * LDAP URLs look like this: * [p]ldap[is]://host[:port][/[dn[?[attributes][?[scope][?[filter][?exts]]]]]] * * where: * attributes is a comma separated list * scope is one of these three strings: base one sub (default=base) * filter is an string-represented filter as in RFC 4515 * * e.g., ldap://host:port/dc=com?o,cn?base?(o=openldap)?extension * * We also tolerate URLs that look like: and */ #include "portable.h" #include #include #include #include #include #include #include "ldap-int.h" /* local functions */ static const char* skip_url_prefix LDAP_P(( const char *url, int *enclosedp, const char **scheme )); int ldap_pvt_url_scheme2proto( const char *scheme ) { assert( scheme != NULL ); if( scheme == NULL ) { return -1; } if( strcmp("ldap", scheme) == 0 || strcmp("pldap", scheme) == 0 ) { return LDAP_PROTO_TCP; } if( strcmp("ldapi", scheme) == 0 ) { return LDAP_PROTO_IPC; } if( strcmp("ldaps", scheme) == 0 || strcmp("pldaps", scheme) == 0 ) { return LDAP_PROTO_TCP; } #ifdef LDAP_CONNECTIONLESS if( strcmp("cldap", scheme) == 0 ) { return LDAP_PROTO_UDP; } #endif return -1; } int ldap_pvt_url_scheme_port( const char *scheme, int port ) { assert( scheme != NULL ); if( port ) return port; if( scheme == NULL ) return port; if( strcmp("ldap", scheme) == 0 || strcmp("pldap", scheme) == 0 ) { return LDAP_PORT; } if( strcmp("ldapi", scheme) == 0 ) { return -1; } if( strcmp("ldaps", scheme) == 0 || strcmp("pldaps", scheme) == 0 ) { return LDAPS_PORT; } #ifdef LDAP_CONNECTIONLESS if( strcmp("cldap", scheme) == 0 ) { return LDAP_PORT; } #endif return -1; } int ldap_pvt_url_scheme2tls( const char *scheme ) { assert( scheme != NULL ); if( scheme == NULL ) { return -1; } return strcmp("ldaps", scheme) == 0 || strcmp("pldaps", scheme) == 0; } int ldap_pvt_url_scheme2proxied( const char *scheme ) { assert( scheme != NULL ); if( scheme == NULL ) { return -1; } return strcmp("pldap", scheme) == 0 || strcmp("pldaps", scheme) == 0; } int ldap_is_ldap_url( LDAP_CONST char *url ) { int enclosed; const char * scheme; if( url == NULL ) { return 0; } if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) { return 0; } return 1; } int ldap_is_ldaps_url( LDAP_CONST char *url ) { int enclosed; const char * scheme; if( url == NULL ) { return 0; } if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) { return 0; } return strcmp(scheme, "ldaps") == 0 || strcmp(scheme, "pldaps") == 0; } int ldap_is_ldapi_url( LDAP_CONST char *url ) { int enclosed; const char * scheme; if( url == NULL ) { return 0; } if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) { return 0; } return strcmp(scheme, "ldapi") == 0; } #ifdef LDAP_CONNECTIONLESS int ldap_is_ldapc_url( LDAP_CONST char *url ) { int enclosed; const char * scheme; if( url == NULL ) { return 0; } if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) { return 0; } return strcmp(scheme, "cldap") == 0; } #endif static const char* skip_url_prefix( const char *url, int *enclosedp, const char **scheme ) { /* * return non-zero if this looks like a LDAP URL; zero if not * if non-zero returned, *urlp will be moved past "ldap://" part of URL */ const char *p; if ( url == NULL ) { return( NULL ); } p = url; /* skip leading '<' (if any) */ if ( *p == '<' ) { *enclosedp = 1; ++p; } else { *enclosedp = 0; } /* skip leading "URL:" (if any) */ if ( strncasecmp( p, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) { p += LDAP_URL_URLCOLON_LEN; } /* check for "ldap://" prefix */ if ( strncasecmp( p, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) == 0 ) { /* skip over "ldap://" prefix and return success */ p += LDAP_URL_PREFIX_LEN; *scheme = "ldap"; return( p ); } /* check for "pldap://" prefix */ if ( strncasecmp( p, PLDAP_URL_PREFIX, PLDAP_URL_PREFIX_LEN ) == 0 ) { /* skip over "pldap://" prefix and return success */ p += PLDAP_URL_PREFIX_LEN; *scheme = "pldap"; return( p ); } /* check for "ldaps://" prefix */ if ( strncasecmp( p, LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) { /* skip over "ldaps://" prefix and return success */ p += LDAPS_URL_PREFIX_LEN; *scheme = "ldaps"; return( p ); } /* check for "pldaps://" prefix */ if ( strncasecmp( p, PLDAPS_URL_PREFIX, PLDAPS_URL_PREFIX_LEN ) == 0 ) { /* skip over "pldaps://" prefix and return success */ p += PLDAPS_URL_PREFIX_LEN; *scheme = "pldaps"; return( p ); } /* check for "ldapi://" prefix */ if ( strncasecmp( p, LDAPI_URL_PREFIX, LDAPI_URL_PREFIX_LEN ) == 0 ) { /* skip over "ldapi://" prefix and return success */ p += LDAPI_URL_PREFIX_LEN; *scheme = "ldapi"; return( p ); } #ifdef LDAP_CONNECTIONLESS /* check for "cldap://" prefix */ if ( strncasecmp( p, LDAPC_URL_PREFIX, LDAPC_URL_PREFIX_LEN ) == 0 ) { /* skip over "cldap://" prefix and return success */ p += LDAPC_URL_PREFIX_LEN; *scheme = "cldap"; return( p ); } #endif return( NULL ); } int ldap_pvt_scope2bv( int scope, struct berval *bv ) { switch ( scope ) { case LDAP_SCOPE_BASE: BER_BVSTR( bv, "base" ); break; case LDAP_SCOPE_ONELEVEL: BER_BVSTR( bv, "one" ); break; case LDAP_SCOPE_SUBTREE: BER_BVSTR( bv, "sub" ); break; case LDAP_SCOPE_SUBORDINATE: BER_BVSTR( bv, "subordinate" ); break; default: return LDAP_OTHER; } return LDAP_SUCCESS; } const char * ldap_pvt_scope2str( int scope ) { struct berval bv; if ( ldap_pvt_scope2bv( scope, &bv ) == LDAP_SUCCESS ) { return bv.bv_val; } return NULL; } int ldap_pvt_bv2scope( struct berval *bv ) { static struct { struct berval bv; int scope; } v[] = { { BER_BVC( "one" ), LDAP_SCOPE_ONELEVEL }, { BER_BVC( "onelevel" ), LDAP_SCOPE_ONELEVEL }, { BER_BVC( "base" ), LDAP_SCOPE_BASE }, { BER_BVC( "sub" ), LDAP_SCOPE_SUBTREE }, { BER_BVC( "subtree" ), LDAP_SCOPE_SUBTREE }, { BER_BVC( "subord" ), LDAP_SCOPE_SUBORDINATE }, { BER_BVC( "subordinate" ), LDAP_SCOPE_SUBORDINATE }, { BER_BVC( "children" ), LDAP_SCOPE_SUBORDINATE }, { BER_BVNULL, -1 } }; int i; for ( i = 0; v[ i ].scope != -1; i++ ) { if ( ber_bvstrcasecmp( bv, &v[ i ].bv ) == 0 ) { return v[ i ].scope; } } return( -1 ); } int ldap_pvt_str2scope( const char *p ) { struct berval bv; ber_str2bv( p, 0, 0, &bv ); return ldap_pvt_bv2scope( &bv ); } static const char hex[] = "0123456789ABCDEF"; #define URLESC_NONE 0x0000U #define URLESC_COMMA 0x0001U #define URLESC_SLASH 0x0002U static int hex_escape_len( const char *s, unsigned list ) { int len; if ( s == NULL ) { return 0; } for ( len = 0; s[0]; s++ ) { switch ( s[0] ) { /* RFC 2396: reserved */ case '?': len += 3; break; case ',': if ( list & URLESC_COMMA ) { len += 3; } else { len++; } break; case '/': if ( list & URLESC_SLASH ) { len += 3; } else { len++; } break; case ';': case ':': case '@': case '&': case '=': case '+': case '$': /* RFC 2396: unreserved mark */ case '-': case '_': case '.': case '!': case '~': case '*': case '\'': case '(': case ')': len++; break; /* RFC 2396: unreserved alphanum */ default: if ( !isalnum( (unsigned char) s[0] ) ) { len += 3; } else { len++; } break; } } return len; } static int hex_escape( char *buf, int len, const char *s, unsigned list ) { int i; int pos; if ( s == NULL ) { return 0; } for ( pos = 0, i = 0; s[i] && pos < len; i++ ) { int escape = 0; switch ( s[i] ) { /* RFC 2396: reserved */ case '?': escape = 1; break; case ',': if ( list & URLESC_COMMA ) { escape = 1; } break; case '/': if ( list & URLESC_SLASH ) { escape = 1; } break; case ';': case ':': case '@': case '&': case '=': case '+': case '$': /* RFC 2396: unreserved mark */ case '-': case '_': case '.': case '!': case '~': case '*': case '\'': case '(': case ')': break; /* RFC 2396: unreserved alphanum */ default: if ( !isalnum( (unsigned char) s[i] ) ) { escape = 1; } break; } if ( escape ) { buf[pos++] = '%'; buf[pos++] = hex[ (s[i] >> 4) & 0x0f ]; buf[pos++] = hex[ s[i] & 0x0f ]; } else { buf[pos++] = s[i]; } } buf[pos] = '\0'; return pos; } static int hex_escape_len_list( char **s, unsigned flags ) { int len; int i; if ( s == NULL ) { return 0; } len = 0; for ( i = 0; s[i] != NULL; i++ ) { if ( len ) { len++; } len += hex_escape_len( s[i], flags ); } return len; } static int hex_escape_list( char *buf, int len, char **s, unsigned flags ) { int pos; int i; if ( s == NULL ) { return 0; } pos = 0; for ( i = 0; s[i] != NULL; i++ ) { int curlen; if ( pos ) { buf[pos++] = ','; len--; } curlen = hex_escape( &buf[pos], len, s[i], flags ); len -= curlen; pos += curlen; } return pos; } static int desc2str_len( LDAPURLDesc *u ) { int sep = 0; int len = 0; int is_ipc = 0; struct berval scope; if ( u == NULL || u->lud_scheme == NULL ) { return -1; } if ( !strcmp( "ldapi", u->lud_scheme )) { is_ipc = 1; } if ( u->lud_exts ) { len += hex_escape_len_list( u->lud_exts, URLESC_COMMA ); if ( !sep ) { sep = 5; } } if ( u->lud_filter ) { len += hex_escape_len( u->lud_filter, URLESC_NONE ); if ( !sep ) { sep = 4; } } if ( ldap_pvt_scope2bv( u->lud_scope, &scope ) == LDAP_SUCCESS ) { len += scope.bv_len; if ( !sep ) { sep = 3; } } if ( u->lud_attrs ) { len += hex_escape_len_list( u->lud_attrs, URLESC_NONE ); if ( !sep ) { sep = 2; } } if ( u->lud_dn && u->lud_dn[0] ) { len += hex_escape_len( u->lud_dn, URLESC_NONE ); if ( !sep ) { sep = 1; } }; len += sep; if ( u->lud_port ) { unsigned p = u->lud_port; if ( p > 65535 ) return -1; len += (p > 999 ? 5 + (p > 9999) : p > 99 ? 4 : 2 + (p > 9)); } if ( u->lud_host && u->lud_host[0] ) { char *ptr; len += hex_escape_len( u->lud_host, URLESC_SLASH ); if ( !is_ipc && ( ptr = strchr( u->lud_host, ':' ))) { if ( strchr( ptr+1, ':' )) len += 2; /* IPv6, [] */ } } len += strlen( u->lud_scheme ) + STRLENOF( "://" ); return len; } static int desc2str( LDAPURLDesc *u, char *s, int len ) { int i; int sep = 0; int sofar = 0; int is_v6 = 0; int is_ipc = 0; struct berval scope = BER_BVNULL; char *ptr; if ( u == NULL ) { return -1; } if ( s == NULL ) { return -1; } if ( u->lud_scheme && !strcmp( "ldapi", u->lud_scheme )) { is_ipc = 1; } ldap_pvt_scope2bv( u->lud_scope, &scope ); if ( u->lud_exts ) { sep = 5; } else if ( u->lud_filter ) { sep = 4; } else if ( !BER_BVISEMPTY( &scope ) ) { sep = 3; } else if ( u->lud_attrs ) { sep = 2; } else if ( u->lud_dn && u->lud_dn[0] ) { sep = 1; } if ( !is_ipc && u->lud_host && ( ptr = strchr( u->lud_host, ':' ))) { if ( strchr( ptr+1, ':' )) is_v6 = 1; } if ( u->lud_port ) { sofar = sprintf( s, "%s://%s%s%s:%d", u->lud_scheme, is_v6 ? "[" : "", u->lud_host ? u->lud_host : "", is_v6 ? "]" : "", u->lud_port ); len -= sofar; } else { sofar = sprintf( s, "%s://", u->lud_scheme ); len -= sofar; if ( u->lud_host && u->lud_host[0] ) { if ( is_v6 ) { s[sofar++] = '['; len--; } i = hex_escape( &s[sofar], len, u->lud_host, URLESC_SLASH ); sofar += i; len -= i; if ( is_v6 ) { s[sofar++] = ']'; len--; } } } assert( len >= 0 ); if ( sep < 1 ) { goto done; } s[sofar++] = '/'; len--; assert( len >= 0 ); if ( u->lud_dn && u->lud_dn[0] ) { i = hex_escape( &s[sofar], len, u->lud_dn, URLESC_NONE ); sofar += i; len -= i; assert( len >= 0 ); } if ( sep < 2 ) { goto done; } s[sofar++] = '?'; len--; assert( len >= 0 ); i = hex_escape_list( &s[sofar], len, u->lud_attrs, URLESC_NONE ); sofar += i; len -= i; assert( len >= 0 ); if ( sep < 3 ) { goto done; } s[sofar++] = '?'; len--; assert( len >= 0 ); if ( !BER_BVISNULL( &scope ) ) { strcpy( &s[sofar], scope.bv_val ); sofar += scope.bv_len; len -= scope.bv_len; } assert( len >= 0 ); if ( sep < 4 ) { goto done; } s[sofar++] = '?'; len--; assert( len >= 0 ); i = hex_escape( &s[sofar], len, u->lud_filter, URLESC_NONE ); sofar += i; len -= i; assert( len >= 0 ); if ( sep < 5 ) { goto done; } s[sofar++] = '?'; len--; assert( len >= 0 ); i = hex_escape_list( &s[sofar], len, u->lud_exts, URLESC_COMMA ); sofar += i; len -= i; assert( len >= 0 ); done: if ( len < 0 ) { return -1; } return sofar; } char * ldap_url_desc2str( LDAPURLDesc *u ) { int len; char *s; if ( u == NULL ) { return NULL; } len = desc2str_len( u ); if ( len < 0 ) { return NULL; } /* allocate enough to hex escape everything -- overkill */ s = LDAP_MALLOC( len + 1 ); if ( s == NULL ) { return NULL; } if ( desc2str( u, s, len ) != len ) { LDAP_FREE( s ); return NULL; } s[len] = '\0'; return s; } int ldap_url_parse_ext( LDAP_CONST char *url_in, LDAPURLDesc **ludpp, unsigned flags ) { /* * Pick apart the pieces of an LDAP URL. */ LDAPURLDesc *ludp; char *p, *q, *r; int i, enclosed, proto, is_v6 = 0; const char *scheme = NULL; const char *url_tmp; char *url; int check_dn = 1; if( url_in == NULL || ludpp == NULL ) { return LDAP_URL_ERR_PARAM; } #ifndef LDAP_INT_IN_KERNEL /* Global options may not be created yet * We can't test if the global options are initialized * because a call to LDAP_INT_GLOBAL_OPT() will try to allocate * the options and cause infinite recursion */ Debug1( LDAP_DEBUG_TRACE, "ldap_url_parse_ext(%s)\n", url_in ); #endif *ludpp = NULL; /* pessimistic */ url_tmp = skip_url_prefix( url_in, &enclosed, &scheme ); if ( url_tmp == NULL ) { return LDAP_URL_ERR_BADSCHEME; } assert( scheme != NULL ); proto = ldap_pvt_url_scheme2proto( scheme ); if ( proto == -1 ) { return LDAP_URL_ERR_BADSCHEME; } /* make working copy of the remainder of the URL */ url = LDAP_STRDUP( url_tmp ); if ( url == NULL ) { return LDAP_URL_ERR_MEM; } if ( enclosed ) { p = &url[strlen(url)-1]; if( *p != '>' ) { LDAP_FREE( url ); return LDAP_URL_ERR_BADENCLOSURE; } *p = '\0'; } /* allocate return struct */ ludp = (LDAPURLDesc *)LDAP_CALLOC( 1, sizeof( LDAPURLDesc )); if ( ludp == NULL ) { LDAP_FREE( url ); return LDAP_URL_ERR_MEM; } ludp->lud_next = NULL; ludp->lud_host = NULL; ludp->lud_port = 0; ludp->lud_dn = NULL; ludp->lud_attrs = NULL; ludp->lud_scope = ( flags & LDAP_PVT_URL_PARSE_NODEF_SCOPE ) ? LDAP_SCOPE_BASE : LDAP_SCOPE_DEFAULT; ludp->lud_filter = NULL; ludp->lud_exts = NULL; ludp->lud_scheme = LDAP_STRDUP( scheme ); if ( ludp->lud_scheme == NULL ) { LDAP_FREE( url ); ldap_free_urldesc( ludp ); return LDAP_URL_ERR_MEM; } /* scan forward for '/' that marks end of hostport and begin. of dn */ p = strchr( url, '/' ); q = NULL; if( p != NULL ) { /* terminate hostport; point to start of dn */ *p++ = '\0'; } else { /* check for Novell kludge, see below */ p = strchr( url, '?' ); if ( p ) { *p++ = '\0'; q = p; p = NULL; } } if ( proto != LDAP_PROTO_IPC ) { /* IPv6 syntax with [ip address]:port */ if ( *url == '[' ) { r = strchr( url, ']' ); if ( r == NULL ) { LDAP_FREE( url ); ldap_free_urldesc( ludp ); return LDAP_URL_ERR_BADURL; } *r++ = '\0'; q = strchr( r, ':' ); if ( q && q != r ) { LDAP_FREE( url ); ldap_free_urldesc( ludp ); return LDAP_URL_ERR_BADURL; } is_v6 = 1; } else { q = strchr( url, ':' ); } if ( q != NULL ) { char *next; *q++ = '\0'; ldap_pvt_hex_unescape( q ); if( *q == '\0' ) { LDAP_FREE( url ); ldap_free_urldesc( ludp ); return LDAP_URL_ERR_BADURL; } ludp->lud_port = strtol( q, &next, 10 ); if ( next == q || next[0] != '\0' ) { LDAP_FREE( url ); ldap_free_urldesc( ludp ); return LDAP_URL_ERR_BADURL; } /* check for Novell kludge */ if ( !p ) { if ( *next != '\0' ) { q = &next[1]; } else { q = NULL; } } } if ( ( flags & LDAP_PVT_URL_PARSE_DEF_PORT ) && ludp->lud_port == 0 ) { if ( strcmp( ludp->lud_scheme, "ldaps" ) == 0 ) { ludp->lud_port = LDAPS_PORT; } else { ludp->lud_port = LDAP_PORT; } } } ldap_pvt_hex_unescape( url ); /* If [ip address]:port syntax, url is [ip and we skip the [ */ ludp->lud_host = LDAP_STRDUP( url + is_v6 ); if( ludp->lud_host == NULL ) { LDAP_FREE( url ); ldap_free_urldesc( ludp ); return LDAP_URL_ERR_MEM; } if ( ( flags & LDAP_PVT_URL_PARSE_NOEMPTY_HOST ) && ludp->lud_host != NULL && *ludp->lud_host == '\0' ) { LDAP_FREE( ludp->lud_host ); ludp->lud_host = NULL; } /* * Kludge. ldap://111.222.333.444:389??cn=abc,o=company * * On early Novell releases, search references/referrals were returned * in this format, i.e., the dn was kind of in the scope position, * but the required slash is missing. The whole thing is illegal syntax, * but we need to account for it. Fortunately it can't be confused with * anything real. */ if( (p == NULL) && (q != NULL) && (*q == '?') ) { /* ? immediately followed by question */ q++; if( *q != '\0' ) { /* parse dn part */ ldap_pvt_hex_unescape( q ); ludp->lud_dn = LDAP_STRDUP( q ); } else if ( !( flags & LDAP_PVT_URL_PARSE_NOEMPTY_DN ) ) { ludp->lud_dn = LDAP_STRDUP( "" ); } else { check_dn = 0; } if ( check_dn && ludp->lud_dn == NULL ) { LDAP_FREE( url ); ldap_free_urldesc( ludp ); return LDAP_URL_ERR_MEM; } } if( p == NULL ) { LDAP_FREE( url ); *ludpp = ludp; return LDAP_URL_SUCCESS; } /* scan forward for '?' that may marks end of dn */ q = strchr( p, '?' ); if( q != NULL ) { /* terminate dn part */ *q++ = '\0'; } if( *p != '\0' ) { /* parse dn part */ ldap_pvt_hex_unescape( p ); ludp->lud_dn = LDAP_STRDUP( p ); } else if ( !( flags & LDAP_PVT_URL_PARSE_NOEMPTY_DN ) ) { ludp->lud_dn = LDAP_STRDUP( "" ); } else { check_dn = 0; } if( check_dn && ludp->lud_dn == NULL ) { LDAP_FREE( url ); ldap_free_urldesc( ludp ); return LDAP_URL_ERR_MEM; } if( q == NULL ) { /* no more */ LDAP_FREE( url ); *ludpp = ludp; return LDAP_URL_SUCCESS; } /* scan forward for '?' that may marks end of attributes */ p = q; q = strchr( p, '?' ); if( q != NULL ) { /* terminate attributes part */ *q++ = '\0'; } if( *p != '\0' ) { /* parse attributes */ ldap_pvt_hex_unescape( p ); ludp->lud_attrs = ldap_str2charray( p, "," ); if( ludp->lud_attrs == NULL ) { LDAP_FREE( url ); ldap_free_urldesc( ludp ); return LDAP_URL_ERR_BADATTRS; } } if ( q == NULL ) { /* no more */ LDAP_FREE( url ); *ludpp = ludp; return LDAP_URL_SUCCESS; } /* scan forward for '?' that may marks end of scope */ p = q; q = strchr( p, '?' ); if( q != NULL ) { /* terminate the scope part */ *q++ = '\0'; } if( *p != '\0' ) { /* parse the scope */ ldap_pvt_hex_unescape( p ); ludp->lud_scope = ldap_pvt_str2scope( p ); if( ludp->lud_scope == -1 ) { LDAP_FREE( url ); ldap_free_urldesc( ludp ); return LDAP_URL_ERR_BADSCOPE; } } if ( q == NULL ) { /* no more */ LDAP_FREE( url ); *ludpp = ludp; return LDAP_URL_SUCCESS; } /* scan forward for '?' that may marks end of filter */ p = q; q = strchr( p, '?' ); if( q != NULL ) { /* terminate the filter part */ *q++ = '\0'; } if( *p != '\0' ) { /* parse the filter */ ldap_pvt_hex_unescape( p ); if( ! *p ) { /* missing filter */ LDAP_FREE( url ); ldap_free_urldesc( ludp ); return LDAP_URL_ERR_BADFILTER; } ludp->lud_filter = LDAP_STRDUP( p ); if( ludp->lud_filter == NULL ) { LDAP_FREE( url ); ldap_free_urldesc( ludp ); return LDAP_URL_ERR_MEM; } } if ( q == NULL ) { /* no more */ LDAP_FREE( url ); *ludpp = ludp; return LDAP_URL_SUCCESS; } /* scan forward for '?' that may marks end of extensions */ p = q; q = strchr( p, '?' ); if( q != NULL ) { /* extra '?' */ LDAP_FREE( url ); ldap_free_urldesc( ludp ); return LDAP_URL_ERR_BADURL; } /* parse the extensions */ ludp->lud_exts = ldap_str2charray( p, "," ); if( ludp->lud_exts == NULL ) { LDAP_FREE( url ); ldap_free_urldesc( ludp ); return LDAP_URL_ERR_BADEXTS; } for( i=0; ludp->lud_exts[i] != NULL; i++ ) { ldap_pvt_hex_unescape( ludp->lud_exts[i] ); if( *ludp->lud_exts[i] == '!' ) { /* count the number of critical extensions */ ludp->lud_crit_exts++; } } if( i == 0 ) { /* must have 1 or more */ LDAP_FREE( url ); ldap_free_urldesc( ludp ); return LDAP_URL_ERR_BADEXTS; } /* no more */ *ludpp = ludp; LDAP_FREE( url ); return LDAP_URL_SUCCESS; } int ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) { return ldap_url_parse_ext( url_in, ludpp, LDAP_PVT_URL_PARSE_HISTORIC ); } LDAPURLDesc * ldap_url_dup ( LDAPURLDesc *ludp ) { LDAPURLDesc *dest; if ( ludp == NULL ) { return NULL; } dest = LDAP_MALLOC( sizeof(LDAPURLDesc) ); if (dest == NULL) return NULL; *dest = *ludp; dest->lud_scheme = NULL; dest->lud_host = NULL; dest->lud_dn = NULL; dest->lud_filter = NULL; dest->lud_attrs = NULL; dest->lud_exts = NULL; dest->lud_next = NULL; if ( ludp->lud_scheme != NULL ) { dest->lud_scheme = LDAP_STRDUP( ludp->lud_scheme ); if (dest->lud_scheme == NULL) { ldap_free_urldesc(dest); return NULL; } } if ( ludp->lud_host != NULL ) { dest->lud_host = LDAP_STRDUP( ludp->lud_host ); if (dest->lud_host == NULL) { ldap_free_urldesc(dest); return NULL; } } if ( ludp->lud_dn != NULL ) { dest->lud_dn = LDAP_STRDUP( ludp->lud_dn ); if (dest->lud_dn == NULL) { ldap_free_urldesc(dest); return NULL; } } if ( ludp->lud_filter != NULL ) { dest->lud_filter = LDAP_STRDUP( ludp->lud_filter ); if (dest->lud_filter == NULL) { ldap_free_urldesc(dest); return NULL; } } if ( ludp->lud_attrs != NULL ) { dest->lud_attrs = ldap_charray_dup( ludp->lud_attrs ); if (dest->lud_attrs == NULL) { ldap_free_urldesc(dest); return NULL; } } if ( ludp->lud_exts != NULL ) { dest->lud_exts = ldap_charray_dup( ludp->lud_exts ); if (dest->lud_exts == NULL) { ldap_free_urldesc(dest); return NULL; } } return dest; } LDAPURLDesc * ldap_url_duplist (LDAPURLDesc *ludlist) { LDAPURLDesc *dest, *tail, *ludp, *newludp; dest = NULL; tail = NULL; for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { newludp = ldap_url_dup(ludp); if (newludp == NULL) { ldap_free_urllist(dest); return NULL; } if (tail == NULL) dest = newludp; else tail->lud_next = newludp; tail = newludp; } return dest; } static int ldap_url_parselist_int (LDAPURLDesc **ludlist, const char *url, const char *sep, unsigned flags ) { int i, rc; LDAPURLDesc *ludp; char **urls; assert( ludlist != NULL ); assert( url != NULL ); *ludlist = NULL; if ( sep == NULL ) { sep = ", "; } urls = ldap_str2charray( url, sep ); if (urls == NULL) return LDAP_URL_ERR_MEM; /* count the URLs... */ for (i = 0; urls[i] != NULL; i++) ; /* ...and put them in the "stack" backward */ while (--i >= 0) { rc = ldap_url_parse_ext( urls[i], &ludp, flags ); if ( rc != 0 ) { ldap_charray_free( urls ); ldap_free_urllist( *ludlist ); *ludlist = NULL; return rc; } ludp->lud_next = *ludlist; *ludlist = ludp; } ldap_charray_free( urls ); return LDAP_URL_SUCCESS; } int ldap_url_parselist (LDAPURLDesc **ludlist, const char *url ) { return ldap_url_parselist_int( ludlist, url, ", ", LDAP_PVT_URL_PARSE_HISTORIC ); } int ldap_url_parselist_ext (LDAPURLDesc **ludlist, const char *url, const char *sep, unsigned flags ) { return ldap_url_parselist_int( ludlist, url, sep, flags ); } int ldap_url_parsehosts( LDAPURLDesc **ludlist, const char *hosts, int port ) { int i; LDAPURLDesc *ludp; char **specs, *p; assert( ludlist != NULL ); assert( hosts != NULL ); *ludlist = NULL; specs = ldap_str2charray(hosts, ", "); if (specs == NULL) return LDAP_NO_MEMORY; /* count the URLs... */ for (i = 0; specs[i] != NULL; i++) /* EMPTY */; /* ...and put them in the "stack" backward */ while (--i >= 0) { ludp = LDAP_CALLOC( 1, sizeof(LDAPURLDesc) ); if (ludp == NULL) { ldap_charray_free(specs); ldap_free_urllist(*ludlist); *ludlist = NULL; return LDAP_NO_MEMORY; } ludp->lud_port = port; ludp->lud_host = specs[i]; specs[i] = NULL; p = strchr(ludp->lud_host, ':'); if (p != NULL) { /* more than one :, IPv6 address */ if ( strchr(p+1, ':') != NULL ) { /* allow [address] and [address]:port */ if ( *ludp->lud_host == '[' ) { p = LDAP_STRDUP(ludp->lud_host+1); /* copied, make sure we free source later */ specs[i] = ludp->lud_host; ludp->lud_host = p; p = strchr( ludp->lud_host, ']' ); if ( p == NULL ) { LDAP_FREE(ludp); ldap_charray_free(specs); return LDAP_PARAM_ERROR; } *p++ = '\0'; if ( *p != ':' ) { if ( *p != '\0' ) { LDAP_FREE(ludp); ldap_charray_free(specs); return LDAP_PARAM_ERROR; } p = NULL; } } else { p = NULL; } } if (p != NULL) { char *next; *p++ = 0; ldap_pvt_hex_unescape(p); ludp->lud_port = strtol( p, &next, 10 ); if ( next == p || next[0] != '\0' ) { LDAP_FREE(ludp); ldap_charray_free(specs); return LDAP_PARAM_ERROR; } } } ldap_pvt_hex_unescape(ludp->lud_host); ludp->lud_scheme = LDAP_STRDUP("ldap"); ludp->lud_next = *ludlist; *ludlist = ludp; } /* this should be an array of NULLs now */ /* except entries starting with [ */ ldap_charray_free(specs); return LDAP_SUCCESS; } char * ldap_url_list2hosts (LDAPURLDesc *ludlist) { LDAPURLDesc *ludp; int size; char *s, *p, buf[32]; /* big enough to hold a long decimal # (overkill) */ if (ludlist == NULL) return NULL; /* figure out how big the string is */ size = 1; /* nul-term */ for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { if ( ludp->lud_host == NULL ) continue; size += strlen(ludp->lud_host) + 1; /* host and space */ if (strchr(ludp->lud_host, ':')) /* will add [ ] below */ size += 2; if (ludp->lud_port != 0) size += sprintf(buf, ":%d", ludp->lud_port); } s = LDAP_MALLOC(size); if (s == NULL) return NULL; p = s; for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { if ( ludp->lud_host == NULL ) continue; if (strchr(ludp->lud_host, ':')) { p += sprintf(p, "[%s]", ludp->lud_host); } else { strcpy(p, ludp->lud_host); p += strlen(ludp->lud_host); } if (ludp->lud_port != 0) p += sprintf(p, ":%d", ludp->lud_port); *p++ = ' '; } if (p != s) p--; /* nuke that extra space */ *p = '\0'; return s; } char * ldap_url_list2urls( LDAPURLDesc *ludlist ) { LDAPURLDesc *ludp; int size, sofar; char *s; if ( ludlist == NULL ) { return NULL; } /* figure out how big the string is */ for ( size = 0, ludp = ludlist; ludp != NULL; ludp = ludp->lud_next ) { int len = desc2str_len( ludp ); if ( len < 0 ) { return NULL; } size += len + 1; } s = LDAP_MALLOC( size ); if ( s == NULL ) { return NULL; } for ( sofar = 0, ludp = ludlist; ludp != NULL; ludp = ludp->lud_next ) { int len; len = desc2str( ludp, &s[sofar], size ); if ( len < 0 ) { LDAP_FREE( s ); return NULL; } sofar += len; size -= len; s[sofar++] = ' '; size--; assert( size >= 0 ); } s[sofar - 1] = '\0'; return s; } void ldap_free_urllist( LDAPURLDesc *ludlist ) { LDAPURLDesc *ludp, *next; for (ludp = ludlist; ludp != NULL; ludp = next) { next = ludp->lud_next; ldap_free_urldesc(ludp); } } void ldap_free_urldesc( LDAPURLDesc *ludp ) { if ( ludp == NULL ) { return; } if ( ludp->lud_scheme != NULL ) { LDAP_FREE( ludp->lud_scheme ); } if ( ludp->lud_host != NULL ) { LDAP_FREE( ludp->lud_host ); } if ( ludp->lud_dn != NULL ) { LDAP_FREE( ludp->lud_dn ); } if ( ludp->lud_filter != NULL ) { LDAP_FREE( ludp->lud_filter); } if ( ludp->lud_attrs != NULL ) { LDAP_VFREE( ludp->lud_attrs ); } if ( ludp->lud_exts != NULL ) { LDAP_VFREE( ludp->lud_exts ); } LDAP_FREE( ludp ); } static int ldap_int_is_hexpair( char *s ) { int i; for ( i = 0; i < 2; i++ ) { if ( s[i] >= '0' && s[i] <= '9' ) { continue; } if ( s[i] >= 'A' && s[i] <= 'F' ) { continue; } if ( s[i] >= 'a' && s[i] <= 'f' ) { continue; } return 0; } return 1; } static int ldap_int_unhex( int c ) { return( c >= '0' && c <= '9' ? c - '0' : c >= 'A' && c <= 'F' ? c - 'A' + 10 : c - 'a' + 10 ); } void ldap_pvt_hex_unescape( char *s ) { /* * Remove URL hex escapes from s... done in place. The basic concept for * this routine is borrowed from the WWW library HTUnEscape() routine. */ char *p, *save_s = s; for ( p = s; *s != '\0'; ++s ) { if ( *s == '%' ) { /* * FIXME: what if '%' is followed * by non-hexpair chars? */ if ( !ldap_int_is_hexpair( s + 1 ) ) { p = save_s; break; } if ( *++s == '\0' ) { break; } *p = ldap_int_unhex( *s ) << 4; if ( *++s == '\0' ) { break; } *p++ += ldap_int_unhex( *s ); } else { *p++ = *s; } } *p = '\0'; } openldap-2.5.11+dfsg/libraries/libldap/testtavl.c0000644000175000017500000001003514172327167020433 0ustar ryanryan/* testavl.c - Test Tim Howes AVL code */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1993 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ /* ACKNOWLEDGEMENTS: * This work was originally developed by the University of Michigan * (as part of U-MICH LDAP). Additional contributors include * Howard Chu */ #include "portable.h" #include #include #include #define AVL_INTERNAL #include "ldap_avl.h" static void ravl_print LDAP_P(( TAvlnode *root, int depth, int thread )); static void myprint LDAP_P(( TAvlnode *root )); static int avl_strcmp LDAP_P(( const void *s, const void *t )); int main( int argc, char **argv ) { TAvlnode *tree = NULL, *n; char command[ 10 ]; char name[ 80 ]; char *p; printf( "> " ); while ( fgets( command, sizeof( command ), stdin ) != NULL ) { switch( *command ) { case 'n': /* new tree */ ( void ) ldap_tavl_free( tree, free ); tree = NULL; break; case 'p': /* print */ ( void ) myprint( tree ); break; case 't': /* traverse with first, next */ printf( "***\n" ); for ( n = ldap_tavl_end( tree, TAVL_DIR_LEFT ); n != NULL; n = ldap_tavl_next( n, TAVL_DIR_RIGHT )) printf( "%s\n", n->avl_data ); printf( "***\n" ); break; case 'f': /* find */ printf( "data? " ); if ( fgets( name, sizeof( name ), stdin ) == NULL ) exit( EXIT_SUCCESS ); name[ strlen( name ) - 1 ] = '\0'; if ( (p = (char *) ldap_tavl_find( tree, name, avl_strcmp )) == NULL ) printf( "Not found.\n\n" ); else printf( "%s\n\n", p ); break; case 'i': /* insert */ printf( "data? " ); if ( fgets( name, sizeof( name ), stdin ) == NULL ) exit( EXIT_SUCCESS ); name[ strlen( name ) - 1 ] = '\0'; if ( ldap_tavl_insert( &tree, strdup( name ), avl_strcmp, ldap_avl_dup_error ) != 0 ) printf( "\nNot inserted!\n" ); break; case 'd': /* delete */ printf( "data? " ); if ( fgets( name, sizeof( name ), stdin ) == NULL ) exit( EXIT_SUCCESS ); name[ strlen( name ) - 1 ] = '\0'; if ( ldap_tavl_delete( &tree, name, avl_strcmp ) == NULL ) printf( "\nNot found!\n" ); break; case 'q': /* quit */ exit( EXIT_SUCCESS ); break; case '\n': break; default: printf("Commands: insert, delete, print, new, quit\n"); } printf( "> " ); } return( 0 ); } static const char bfc_array[] = "\\-/"; static const char *bfcs = bfc_array+1; static void ravl_print( TAvlnode *root, int depth, int thread ) { int i; if ( root && !thread ) ravl_print( root->avl_link[1], depth+1, root->avl_bits[1] == AVL_THREAD ); for ( i = 0; i < depth; i++ ) printf( " " ); if ( thread ) printf( "~" ); else if ( root ) printf( "%c", bfcs[root->avl_bf] ); else printf( " " ); if ( !root) { printf( ".\n" ); return; } printf( "%s\n", (char *) root->avl_data ); if ( !thread ) ravl_print( root->avl_link[0], depth+1, root->avl_bits[0] == AVL_THREAD ); } static void myprint( TAvlnode *root ) { printf( "********\n" ); if ( root == 0 ) printf( "\tNULL\n" ); else ravl_print( root, 0, 0 ); printf( "********\n" ); } static int avl_strcmp( const void *s, const void *t ) { return strcmp( s, t ); } openldap-2.5.11+dfsg/libraries/libldap/addentry.c0000644000175000017500000000305614172327167020404 0ustar ryanryan/* addentry.c */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" LDAPMessage * ldap_delete_result_entry( LDAPMessage **list, LDAPMessage *e ) { LDAPMessage *tmp, *prev = NULL; assert( list != NULL ); assert( e != NULL ); for ( tmp = *list; tmp != NULL && tmp != e; tmp = tmp->lm_chain ) prev = tmp; if ( tmp == NULL ) return( NULL ); if ( prev == NULL ) { if ( tmp->lm_chain ) tmp->lm_chain->lm_chain_tail = (*list)->lm_chain_tail; *list = tmp->lm_chain; } else { prev->lm_chain = tmp->lm_chain; if ( prev->lm_chain == NULL ) (*list)->lm_chain_tail = prev; } tmp->lm_chain = NULL; return( tmp ); } void ldap_add_result_entry( LDAPMessage **list, LDAPMessage *e ) { assert( list != NULL ); assert( e != NULL ); e->lm_chain = *list; if ( *list ) e->lm_chain_tail = (*list)->lm_chain_tail; else e->lm_chain_tail = e; *list = e; } openldap-2.5.11+dfsg/libraries/libldap/modrdn.c0000644000175000017500000001354214172327167020056 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ /* Copyright 1999, Juan C. Gomez, All rights reserved. * This software is not subject to any license of Silicon Graphics * Inc. or Purdue University. * * Redistribution and use in source and binary forms are permitted * without restriction or fee of any kind as long as this notice * is preserved. */ /* ACKNOWLEDGEMENTS: * Juan C. Gomez */ #include "portable.h" #include #include #include #include #include "ldap-int.h" /* * A modify rdn request looks like this: * ModifyRDNRequest ::= SEQUENCE { * entry DistinguishedName, * newrdn RelativeDistinguishedName, * deleteoldrdn BOOLEAN * newSuperior [0] DistinguishedName [v3 only] * } */ BerElement * ldap_build_moddn_req( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *newrdn, LDAP_CONST char *newSuperior, int deleteoldrdn, LDAPControl **sctrls, LDAPControl **cctrls, ber_int_t *msgidp ) { BerElement *ber; int rc; /* create a message to send */ if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { return( NULL ); } LDAP_NEXT_MSGID( ld, *msgidp ); if( newSuperior != NULL ) { /* must be version 3 (or greater) */ if ( ld->ld_version < LDAP_VERSION3 ) { ld->ld_errno = LDAP_NOT_SUPPORTED; ber_free( ber, 1 ); return( NULL ); } rc = ber_printf( ber, "{it{ssbtsN}", /* '}' */ *msgidp, LDAP_REQ_MODDN, dn, newrdn, (ber_int_t) deleteoldrdn, LDAP_TAG_NEWSUPERIOR, newSuperior ); } else { rc = ber_printf( ber, "{it{ssbN}", /* '}' */ *msgidp, LDAP_REQ_MODDN, dn, newrdn, (ber_int_t) deleteoldrdn ); } if ( rc < 0 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } /* Put Server Controls */ if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return( NULL ); } rc = ber_printf( ber, /*{*/ "N}" ); if ( rc < 0 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } return( ber ); } /* * ldap_rename - initiate an ldap extended modifyDN operation. * * Parameters: * ld LDAP descriptor * dn DN of the object to modify * newrdn RDN to give the object * deleteoldrdn nonzero means to delete old rdn values from the entry * newSuperior DN of the new parent if applicable * * Returns the LDAP error code. */ int ldap_rename( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *newrdn, LDAP_CONST char *newSuperior, int deleteoldrdn, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp ) { BerElement *ber; int rc; ber_int_t id; Debug0( LDAP_DEBUG_TRACE, "ldap_rename\n" ); /* check client controls */ rc = ldap_int_client_controls( ld, cctrls ); if( rc != LDAP_SUCCESS ) return rc; ber = ldap_build_moddn_req( ld, dn, newrdn, newSuperior, deleteoldrdn, sctrls, cctrls, &id ); if( !ber ) return ld->ld_errno; /* send the message */ *msgidp = ldap_send_initial_request( ld, LDAP_REQ_MODRDN, dn, ber, id ); if( *msgidp < 0 ) { return( ld->ld_errno ); } return LDAP_SUCCESS; } /* * ldap_rename2 - initiate an ldap (and X.500) modifyDN operation. Parameters: * (LDAP V3 MODIFYDN REQUEST) * ld LDAP descriptor * dn DN of the object to modify * newrdn RDN to give the object * deleteoldrdn nonzero means to delete old rdn values from the entry * newSuperior DN of the new parent if applicable * * ldap_rename2 uses a U-Mich Style API. It returns the msgid. */ int ldap_rename2( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *newrdn, LDAP_CONST char *newSuperior, int deleteoldrdn ) { int msgid; int rc; Debug0( LDAP_DEBUG_TRACE, "ldap_rename2\n" ); rc = ldap_rename( ld, dn, newrdn, newSuperior, deleteoldrdn, NULL, NULL, &msgid ); return rc == LDAP_SUCCESS ? msgid : -1; } /* * ldap_modrdn2 - initiate an ldap modifyRDN operation. Parameters: * * ld LDAP descriptor * dn DN of the object to modify * newrdn RDN to give the object * deleteoldrdn nonzero means to delete old rdn values from the entry * * Example: * msgid = ldap_modrdn( ld, dn, newrdn ); */ int ldap_modrdn2( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *newrdn, int deleteoldrdn ) { return ldap_rename2( ld, dn, newrdn, NULL, deleteoldrdn ); } int ldap_modrdn( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *newrdn ) { return( ldap_rename2( ld, dn, newrdn, NULL, 1 ) ); } int ldap_rename_s( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *newrdn, LDAP_CONST char *newSuperior, int deleteoldrdn, LDAPControl **sctrls, LDAPControl **cctrls ) { int rc; int msgid; LDAPMessage *res; rc = ldap_rename( ld, dn, newrdn, newSuperior, deleteoldrdn, sctrls, cctrls, &msgid ); if( rc != LDAP_SUCCESS ) { return rc; } rc = ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &res ); if( rc == -1 || !res ) { return ld->ld_errno; } return ldap_result2error( ld, res, 1 ); } int ldap_rename2_s( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *newrdn, LDAP_CONST char *newSuperior, int deleteoldrdn ) { return ldap_rename_s( ld, dn, newrdn, newSuperior, deleteoldrdn, NULL, NULL ); } int ldap_modrdn2_s( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *newrdn, int deleteoldrdn ) { return ldap_rename_s( ld, dn, newrdn, NULL, deleteoldrdn, NULL, NULL ); } int ldap_modrdn_s( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *newrdn ) { return ldap_rename_s( ld, dn, newrdn, NULL, 1, NULL, NULL ); } openldap-2.5.11+dfsg/libraries/libldap/util-int.c0000644000175000017500000005673514172327167020353 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * Portions Copyright 1998 A. Hartgers. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This work was initially developed by Bart Hartgers for inclusion in * OpenLDAP Software. */ /* * util-int.c Various functions to replace missing threadsafe ones. * Without the real *_r funcs, things will * work, but might not be threadsafe. */ #include "portable.h" #include #include #include #include #include #include #include "ldap-int.h" #ifndef h_errno /* newer systems declare this in for you, older ones don't. * harmless to declare it again (unless defined by a macro). */ extern int h_errno; #endif #ifdef HAVE_HSTRERROR # define HSTRERROR(e) hstrerror(e) #else # define HSTRERROR(e) hp_strerror(e) #endif #ifndef LDAP_R_COMPILE # undef HAVE_REENTRANT_FUNCTIONS # undef HAVE_CTIME_R # undef HAVE_GETHOSTBYNAME_R # undef HAVE_GETHOSTBYADDR_R #else # include ldap_pvt_thread_mutex_t ldap_int_resolv_mutex; ldap_pvt_thread_mutex_t ldap_int_hostname_mutex; static ldap_pvt_thread_mutex_t ldap_int_gettime_mutex; # if (defined( HAVE_CTIME_R ) || defined( HAVE_REENTRANT_FUNCTIONS)) \ && defined( CTIME_R_NARGS ) # define USE_CTIME_R # else static ldap_pvt_thread_mutex_t ldap_int_ctime_mutex; # endif /* USE_GMTIME_R and USE_LOCALTIME_R defined in ldap_pvt.h */ #if !defined( USE_GMTIME_R ) || !defined( USE_LOCALTIME_R ) /* we use the same mutex for gmtime(3) and localtime(3) * because implementations may use the same buffer * for both functions */ static ldap_pvt_thread_mutex_t ldap_int_gmtime_mutex; #endif # if defined(HAVE_GETHOSTBYNAME_R) && \ (GETHOSTBYNAME_R_NARGS < 5) || (6 < GETHOSTBYNAME_R_NARGS) /* Don't know how to handle this version, pretend it's not there */ # undef HAVE_GETHOSTBYNAME_R # endif # if defined(HAVE_GETHOSTBYADDR_R) && \ (GETHOSTBYADDR_R_NARGS < 7) || (8 < GETHOSTBYADDR_R_NARGS) /* Don't know how to handle this version, pretend it's not there */ # undef HAVE_GETHOSTBYADDR_R # endif #endif /* LDAP_R_COMPILE */ char *ldap_pvt_ctime( const time_t *tp, char *buf ) { #ifdef USE_CTIME_R # if (CTIME_R_NARGS > 3) || (CTIME_R_NARGS < 2) # error "CTIME_R_NARGS should be 2 or 3" # elif CTIME_R_NARGS > 2 && defined(CTIME_R_RETURNS_INT) return( ctime_r(tp,buf,26) < 0 ? 0 : buf ); # elif CTIME_R_NARGS > 2 return ctime_r(tp,buf,26); # else return ctime_r(tp,buf); # endif #else LDAP_MUTEX_LOCK( &ldap_int_ctime_mutex ); AC_MEMCPY( buf, ctime(tp), 26 ); LDAP_MUTEX_UNLOCK( &ldap_int_ctime_mutex ); return buf; #endif } #if !defined( USE_GMTIME_R ) || !defined( USE_LOCALTIME_R ) int ldap_pvt_gmtime_lock( void ) { # ifndef LDAP_R_COMPILE return 0; # else /* LDAP_R_COMPILE */ return ldap_pvt_thread_mutex_lock( &ldap_int_gmtime_mutex ); # endif /* LDAP_R_COMPILE */ } int ldap_pvt_gmtime_unlock( void ) { # ifndef LDAP_R_COMPILE return 0; # else /* LDAP_R_COMPILE */ return ldap_pvt_thread_mutex_unlock( &ldap_int_gmtime_mutex ); # endif /* LDAP_R_COMPILE */ } #endif /* !USE_GMTIME_R || !USE_LOCALTIME_R */ #ifndef USE_GMTIME_R struct tm * ldap_pvt_gmtime( const time_t *timep, struct tm *result ) { struct tm *tm_ptr; LDAP_MUTEX_LOCK( &ldap_int_gmtime_mutex ); tm_ptr = gmtime( timep ); if ( tm_ptr == NULL ) { result = NULL; } else { *result = *tm_ptr; } LDAP_MUTEX_UNLOCK( &ldap_int_gmtime_mutex ); return result; } #endif /* !USE_GMTIME_R */ #ifndef USE_LOCALTIME_R struct tm * ldap_pvt_localtime( const time_t *timep, struct tm *result ) { struct tm *tm_ptr; LDAP_MUTEX_LOCK( &ldap_int_gmtime_mutex ); tm_ptr = localtime( timep ); if ( tm_ptr == NULL ) { result = NULL; } else { *result = *tm_ptr; } LDAP_MUTEX_UNLOCK( &ldap_int_gmtime_mutex ); return result; } #endif /* !USE_LOCALTIME_R */ static int _ldap_pvt_gt_subs; #ifdef _WIN32 /* Windows SYSTEMTIME only has 10 millisecond resolution, so we * also need to use a high resolution timer to get nanoseconds. * This is pretty clunky. */ static LARGE_INTEGER _ldap_pvt_gt_freq; static LARGE_INTEGER _ldap_pvt_gt_prev; static int _ldap_pvt_gt_offset; #define SEC_TO_UNIX_EPOCH 11644473600LL #define TICKS_PER_SECOND 10000000 #define BILLION 1000000000L static int ldap_pvt_gettimensec(int *sec) { LARGE_INTEGER count; QueryPerformanceCounter( &count ); /* It shouldn't ever go backwards, but multiple CPUs might * be able to hit in the same tick. */ LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex ); /* We assume Windows has at least a vague idea of * when a second begins. So we align our nanosecond count * with the Windows millisecond count using this offset. * We retain the submillisecond portion of our own count. * * Note - this also assumes that the relationship between * the PerformanceCounter and SystemTime stays constant; * that assumption breaks if the SystemTime is adjusted by * an external action. */ if ( !_ldap_pvt_gt_freq.QuadPart ) { LARGE_INTEGER c2; ULARGE_INTEGER ut; FILETIME ft0, ft1; long long t; int nsec; /* Initialize our offset */ QueryPerformanceFrequency( &_ldap_pvt_gt_freq ); /* Wait for a tick of the system time: 10-15ms */ GetSystemTimeAsFileTime( &ft0 ); do { GetSystemTimeAsFileTime( &ft1 ); } while ( ft1.dwLowDateTime == ft0.dwLowDateTime ); ut.LowPart = ft1.dwLowDateTime; ut.HighPart = ft1.dwHighDateTime; QueryPerformanceCounter( &c2 ); /* get second and fraction portion of counter */ t = c2.QuadPart % (_ldap_pvt_gt_freq.QuadPart*10); /* convert to nanoseconds */ t *= BILLION; nsec = t / _ldap_pvt_gt_freq.QuadPart; ut.QuadPart /= 10; ut.QuadPart %= (10 * BILLION); _ldap_pvt_gt_offset = nsec - ut.QuadPart; count = c2; } if ( count.QuadPart <= _ldap_pvt_gt_prev.QuadPart ) { _ldap_pvt_gt_subs++; } else { _ldap_pvt_gt_subs = 0; _ldap_pvt_gt_prev = count; } LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex ); /* convert to nanoseconds */ count.QuadPart %= _ldap_pvt_gt_freq.QuadPart*10; count.QuadPart *= BILLION; count.QuadPart /= _ldap_pvt_gt_freq.QuadPart; count.QuadPart -= _ldap_pvt_gt_offset; /* We've extracted the 1s and nanoseconds. * The 1sec digit is used to detect wraparound in nanosecnds. */ if (count.QuadPart < 0) count.QuadPart += (10 * BILLION); else if (count.QuadPart >= (10 * BILLION)) count.QuadPart -= (10 * BILLION); *sec = count.QuadPart / BILLION; return count.QuadPart % BILLION; } /* emulate POSIX clock_gettime */ int ldap_pvt_clock_gettime( int clk_id, struct timespec *tv ) { FILETIME ft; ULARGE_INTEGER ut; int sec, sec0; GetSystemTimeAsFileTime( &ft ); ut.LowPart = ft.dwLowDateTime; ut.HighPart = ft.dwHighDateTime; /* convert to sec */ ut.QuadPart /= TICKS_PER_SECOND; tv->tv_nsec = ldap_pvt_gettimensec(&sec); tv->tv_sec = ut.QuadPart - SEC_TO_UNIX_EPOCH; /* check for carry from microseconds */ sec0 = tv->tv_sec % 10; if (sec0 < sec || (sec0 == 9 && !sec)) tv->tv_sec++; return 0; } /* emulate POSIX gettimeofday */ int ldap_pvt_gettimeofday( struct timeval *tv, void *unused ) { struct timespec ts; ldap_pvt_clock_gettime( 0, &ts ); tv->tv_sec = ts.tv_sec; tv->tv_usec = ts.tv_nsec / 1000; return 0; } /* return a broken out time, with nanoseconds */ void ldap_pvt_gettime( struct lutil_tm *tm ) { SYSTEMTIME st; int sec, sec0; static const char daysPerMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; GetSystemTime( &st ); tm->tm_nsec = ldap_pvt_gettimensec(&sec); tm->tm_usub = _ldap_pvt_gt_subs; /* any difference larger than nanoseconds is * already reflected in st */ tm->tm_sec = st.wSecond; tm->tm_min = st.wMinute; tm->tm_hour = st.wHour; tm->tm_mday = st.wDay; tm->tm_mon = st.wMonth - 1; tm->tm_year = st.wYear - 1900; /* check for carry from nanoseconds */ sec0 = tm->tm_sec % 10; if (sec0 < sec || (sec0 == 9 && !sec)) { tm->tm_sec++; /* FIXME: we don't handle leap seconds */ if (tm->tm_sec > 59) { tm->tm_sec = 0; tm->tm_min++; if (tm->tm_min > 59) { tm->tm_min = 0; tm->tm_hour++; if (tm->tm_hour > 23) { int days = daysPerMonth[tm->tm_mon]; tm->tm_hour = 0; tm->tm_mday++; /* if it's February of a leap year, * add 1 day to this month */ if (tm->tm_mon == 1 && ((!(st.wYear % 4) && (st.wYear % 100)) || !(st.wYear % 400))) days++; if (tm->tm_mday > days) { tm->tm_mday = 1; tm->tm_mon++; if (tm->tm_mon > 11) { tm->tm_mon = 0; tm->tm_year++; } } } } } } } #else #ifdef HAVE_CLOCK_GETTIME static struct timespec _ldap_pvt_gt_prevTv; #else static struct timeval _ldap_pvt_gt_prevTv; #endif void ldap_pvt_gettime( struct lutil_tm *ltm ) { struct tm tm; time_t t; #ifdef HAVE_CLOCK_GETTIME #define FRAC tv_nsec #define NSECS(x) x struct timespec tv; clock_gettime( CLOCK_REALTIME, &tv ); #else #define FRAC tv_usec #define NSECS(x) x * 1000 struct timeval tv; gettimeofday( &tv, NULL ); #endif t = tv.tv_sec; LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex ); if ( tv.tv_sec < _ldap_pvt_gt_prevTv.tv_sec || ( tv.tv_sec == _ldap_pvt_gt_prevTv.tv_sec && tv.FRAC <= _ldap_pvt_gt_prevTv.FRAC )) { _ldap_pvt_gt_subs++; } else { _ldap_pvt_gt_subs = 0; _ldap_pvt_gt_prevTv = tv; } LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex ); ltm->tm_usub = _ldap_pvt_gt_subs; ldap_pvt_gmtime( &t, &tm ); ltm->tm_sec = tm.tm_sec; ltm->tm_min = tm.tm_min; ltm->tm_hour = tm.tm_hour; ltm->tm_mday = tm.tm_mday; ltm->tm_mon = tm.tm_mon; ltm->tm_year = tm.tm_year; ltm->tm_nsec = NSECS(tv.FRAC); } #endif size_t ldap_pvt_csnstr(char *buf, size_t len, unsigned int replica, unsigned int mod) { struct lutil_tm tm; int n; ldap_pvt_gettime( &tm ); n = snprintf( buf, len, "%4d%02d%02d%02d%02d%02d.%06dZ#%06x#%03x#%06x", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_nsec / 1000, tm.tm_usub, replica, mod ); if( n < 0 ) return 0; return ( (size_t) n < len ) ? n : 0; } #define BUFSTART (1024-32) #define BUFMAX (32*1024-32) #if defined(LDAP_R_COMPILE) static char *safe_realloc( char **buf, int len ); #if !(defined(HAVE_GETHOSTBYNAME_R) && defined(HAVE_GETHOSTBYADDR_R)) static int copy_hostent( struct hostent *res, char **buf, struct hostent * src ); #endif #endif int ldap_pvt_gethostbyname_a( const char *name, struct hostent *resbuf, char **buf, struct hostent **result, int *herrno_ptr ) { #if defined( HAVE_GETHOSTBYNAME_R ) # define NEED_SAFE_REALLOC 1 int r=-1; int buflen=BUFSTART; *buf = NULL; for(;buflensa_family == AF_INET6) { struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa; addr = (char *)&sin->sin6_addr; alen = sizeof(sin->sin6_addr); } else #endif if (sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; addr = (char *)&sin->sin_addr; alen = sizeof(sin->sin_addr); } else { rc = NO_RECOVERY; *err = (char *)HSTRERROR( rc ); return rc; } #if defined( HAVE_GETHOSTBYADDR_R ) for(;buflensa_family, &hb, buf, buflen, &h_errno ); rc = (hp == NULL) ? -1 : 0; #else rc = gethostbyaddr_r( addr, alen, sa->sa_family, &hb, buf, buflen, &hp, &h_errno ); #endif #ifdef NETDB_INTERNAL if ((rc<0) && (h_errno==NETDB_INTERNAL) && (errno==ERANGE)) { buflen*=2; continue; } #endif break; } if (hp) { strncpy( name, hp->h_name, namelen ); } else { *err = (char *)HSTRERROR( h_errno ); } LDAP_FREE(buf); #else /* HAVE_GETHOSTBYADDR_R */ LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex ); hp = gethostbyaddr( addr, alen, sa->sa_family ); if (hp) { strncpy( name, hp->h_name, namelen ); rc = 0; } else { rc = h_errno; *err = (char *)HSTRERROR( h_errno ); } LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex ); #endif /* !HAVE_GETHOSTBYADDR_R */ return rc; #endif /* !HAVE_GETNAMEINFO */ } int ldap_pvt_gethostbyaddr_a( const char *addr, int len, int type, struct hostent *resbuf, char **buf, struct hostent **result, int *herrno_ptr ) { #if defined( HAVE_GETHOSTBYADDR_R ) # undef NEED_SAFE_REALLOC # define NEED_SAFE_REALLOC int r=-1; int buflen=BUFSTART; *buf = NULL; for(;buflenh_name ) + 1; if( src->h_aliases != NULL ) { for( p = src->h_aliases; (*p) != NULL; p++ ) { total_alias_len += strlen( *p ) + 1; n_alias++; } } if( src->h_addr_list != NULL ) { for( p = src->h_addr_list; (*p) != NULL; p++ ) { n_addr++; } total_addr_len = n_addr * src->h_length; } total_len = (n_alias + n_addr + 2) * sizeof( char * ) + total_addr_len + total_alias_len + name_len; if (safe_realloc( buf, total_len )) { tp = (char **) *buf; tbuf = *buf + (n_alias + n_addr + 2) * sizeof( char * ); AC_MEMCPY( res, src, sizeof( struct hostent ) ); /* first the name... */ AC_MEMCPY( tbuf, src->h_name, name_len ); res->h_name = tbuf; tbuf+=name_len; /* now the aliases */ res->h_aliases = tp; if ( src->h_aliases != NULL ) { tbuf = cpy_aliases( &tp, tbuf, src->h_aliases ); } *tp++=NULL; /* finally the addresses */ res->h_addr_list = tp; if ( src->h_addr_list != NULL ) { tbuf = cpy_addresses( &tp, tbuf, src->h_addr_list, src->h_length ); } *tp++=NULL; return 0; } return -1; } #endif #if defined( NEED_SAFE_REALLOC ) static char *safe_realloc( char **buf, int len ) { char *tmpbuf; tmpbuf = LDAP_REALLOC( *buf, len ); if (tmpbuf) { *buf=tmpbuf; } return tmpbuf; } #endif char * ldap_pvt_get_fqdn( char *name ) { #ifdef HAVE_GETADDRINFO struct addrinfo hints, *res; #else char *ha_buf; struct hostent *hp, he_buf; int local_h_errno; #endif int rc; char *fqdn, hostbuf[MAXHOSTNAMELEN+1]; if( name == NULL ) { if( gethostname( hostbuf, MAXHOSTNAMELEN ) == 0 ) { hostbuf[MAXHOSTNAMELEN] = '\0'; name = hostbuf; } else { name = "localhost"; } } #ifdef HAVE_GETADDRINFO memset( &hints, 0, sizeof( hints )); hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_CANONNAME; LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex ); rc = getaddrinfo( name, NULL, &hints, &res ); LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex ); if ( rc == 0 && res->ai_canonname ) { fqdn = LDAP_STRDUP( res->ai_canonname ); } else { fqdn = LDAP_STRDUP( name ); } if ( rc == 0 ) freeaddrinfo( res ); #else rc = ldap_pvt_gethostbyname_a( name, &he_buf, &ha_buf, &hp, &local_h_errno ); if( rc < 0 || hp == NULL || hp->h_name == NULL ) { fqdn = LDAP_STRDUP( name ); } else { fqdn = LDAP_STRDUP( hp->h_name ); } LDAP_FREE( ha_buf ); #endif return fqdn; } #if ( defined( HAVE_GETADDRINFO ) || defined( HAVE_GETNAMEINFO ) ) \ && !defined( HAVE_GAI_STRERROR ) char *ldap_pvt_gai_strerror (int code) { static struct { int code; const char *msg; } values[] = { #ifdef EAI_ADDRFAMILY { EAI_ADDRFAMILY, N_("Address family for hostname not supported") }, #endif { EAI_AGAIN, N_("Temporary failure in name resolution") }, { EAI_BADFLAGS, N_("Bad value for ai_flags") }, { EAI_FAIL, N_("Non-recoverable failure in name resolution") }, { EAI_FAMILY, N_("ai_family not supported") }, { EAI_MEMORY, N_("Memory allocation failure") }, #ifdef EAI_NODATA { EAI_NODATA, N_("No address associated with hostname") }, #endif { EAI_NONAME, N_("Name or service not known") }, { EAI_SERVICE, N_("Servname not supported for ai_socktype") }, { EAI_SOCKTYPE, N_("ai_socktype not supported") }, #ifdef EAI_SYSTEM { EAI_SYSTEM, N_("System error") }, #endif { 0, NULL } }; int i; for ( i = 0; values[i].msg != NULL; i++ ) { if ( values[i].code == code ) { return (char *) _(values[i].msg); } } return _("Unknown error"); } #endif /* format a socket address as a string */ #ifdef HAVE_TCPD # include # define SOCKADDR_STRING_UNKNOWN STRING_UNKNOWN #else /* ! TCP Wrappers */ # define SOCKADDR_STRING_UNKNOWN "unknown" #endif /* ! TCP Wrappers */ void ldap_pvt_sockaddrstr( Sockaddr *sa, struct berval *addrbuf ) { char *addr; switch( sa->sa_addr.sa_family ) { #ifdef LDAP_PF_LOCAL case AF_LOCAL: addrbuf->bv_len = snprintf( addrbuf->bv_val, addrbuf->bv_len, "PATH=%s", sa->sa_un_addr.sun_path ); break; #endif #ifdef LDAP_PF_INET6 case AF_INET6: strcpy(addrbuf->bv_val, "IP="); if ( IN6_IS_ADDR_V4MAPPED(&sa->sa_in6_addr.sin6_addr) ) { #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) addr = (char *)inet_ntop( AF_INET, ((struct in_addr *)&sa->sa_in6_addr.sin6_addr.s6_addr[12]), addrbuf->bv_val+3, addrbuf->bv_len-3 ); #else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ addr = inet_ntoa( *((struct in_addr *) &sa->sa_in6_addr.sin6_addr.s6_addr[12]) ); #endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ if ( !addr ) addr = SOCKADDR_STRING_UNKNOWN; if ( addr != addrbuf->bv_val+3 ) { addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "%s:%d", addr, (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + 3; } else { int len = strlen( addr ); addrbuf->bv_len = sprintf( addr+len, ":%d", (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + len + 3; } } else { addr = (char *)inet_ntop( AF_INET6, &sa->sa_in6_addr.sin6_addr, addrbuf->bv_val+4, addrbuf->bv_len-4 ); if ( !addr ) addr = SOCKADDR_STRING_UNKNOWN; if ( addr != addrbuf->bv_val+4 ) { addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "[%s]:%d", addr, (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + 3; } else { int len = strlen( addr ); addrbuf->bv_val[3] = '['; addrbuf->bv_len = sprintf( addr+len, "]:%d", (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + len + 4; } } break; #endif /* LDAP_PF_INET6 */ case AF_INET: strcpy(addrbuf->bv_val, "IP="); #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) addr = (char *)inet_ntop( AF_INET, &sa->sa_in_addr.sin_addr, addrbuf->bv_val+3, addrbuf->bv_len-3 ); #else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ addr = inet_ntoa( sa->sa_in_addr.sin_addr ); #endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ if ( !addr ) addr = SOCKADDR_STRING_UNKNOWN; if ( addr != addrbuf->bv_val+3 ) { addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "%s:%d", addr, (unsigned) ntohs( sa->sa_in_addr.sin_port ) ) + 3; } else { int len = strlen( addr ); addrbuf->bv_len = sprintf( addr+len, ":%d", (unsigned) ntohs( sa->sa_in_addr.sin_port ) ) + len + 3; } break; default: addrbuf->bv_val[0] = '\0'; } } openldap-2.5.11+dfsg/libraries/libldap/rdwr.c0000644000175000017500000002567714172327167017565 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* This work was initially developed by Kurt D. Zeilenga for inclusion * in OpenLDAP Software. Additional significant contributors include: * Stuart Lynne */ /* * This is an improved implementation of Reader/Writer locks does * not protect writers from starvation. That is, if a writer is * currently waiting on a reader, any new reader will get * the lock before the writer. * * Does not support cancellation nor does any status checking. */ /* Adapted from publicly available examples for: * "Programming with Posix Threads" * by David R Butenhof, Addison-Wesley * http://cseng.aw.com/bookpage.taf?ISBN=0-201-63392-2 */ #include "portable.h" #include #include #include #include #include "ldap-int.h" #ifdef LDAP_R_COMPILE #include "ldap_pvt_thread.h" /* Get the thread interface */ #define LDAP_THREAD_RDWR_IMPLEMENTATION #include "ldap_thr_debug.h" /* May rename the symbols defined below */ /* * implementations that provide their own compatible * reader/writer locks define LDAP_THREAD_HAVE_RDWR * in ldap_pvt_thread.h */ #ifndef LDAP_THREAD_HAVE_RDWR struct ldap_int_thread_rdwr_s { ldap_pvt_thread_mutex_t ltrw_mutex; ldap_pvt_thread_cond_t ltrw_read; /* wait for read */ ldap_pvt_thread_cond_t ltrw_write; /* wait for write */ int ltrw_valid; #define LDAP_PVT_THREAD_RDWR_VALID 0x0bad int ltrw_r_active; int ltrw_w_active; int ltrw_r_wait; int ltrw_w_wait; #ifdef LDAP_RDWR_DEBUG /* keep track of who has these locks */ #define MAX_READERS 32 int ltrw_more_readers; /* Set if ltrw_readers[] is incomplete */ ldap_pvt_thread_t ltrw_readers[MAX_READERS]; ldap_pvt_thread_t ltrw_writer; #endif }; int ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rwlock ) { struct ldap_int_thread_rdwr_s *rw; assert( rwlock != NULL ); rw = (struct ldap_int_thread_rdwr_s *) LDAP_CALLOC( 1, sizeof( struct ldap_int_thread_rdwr_s ) ); if ( !rw ) return LDAP_NO_MEMORY; /* we should check return results */ ldap_pvt_thread_mutex_init( &rw->ltrw_mutex ); ldap_pvt_thread_cond_init( &rw->ltrw_read ); ldap_pvt_thread_cond_init( &rw->ltrw_write ); rw->ltrw_valid = LDAP_PVT_THREAD_RDWR_VALID; *rwlock = rw; return 0; } int ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rwlock ) { struct ldap_int_thread_rdwr_s *rw; assert( rwlock != NULL ); rw = *rwlock; assert( rw != NULL ); assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID ); if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID ) return LDAP_PVT_THREAD_EINVAL; ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex ); assert( rw->ltrw_w_active >= 0 ); assert( rw->ltrw_w_wait >= 0 ); assert( rw->ltrw_r_active >= 0 ); assert( rw->ltrw_r_wait >= 0 ); /* active threads? */ if( rw->ltrw_r_active > 0 || rw->ltrw_w_active > 0) { ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex ); return LDAP_PVT_THREAD_EBUSY; } /* waiting threads? */ if( rw->ltrw_r_wait > 0 || rw->ltrw_w_wait > 0) { ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex ); return LDAP_PVT_THREAD_EBUSY; } rw->ltrw_valid = 0; ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex ); ldap_pvt_thread_mutex_destroy( &rw->ltrw_mutex ); ldap_pvt_thread_cond_destroy( &rw->ltrw_read ); ldap_pvt_thread_cond_destroy( &rw->ltrw_write ); LDAP_FREE(rw); *rwlock = NULL; return 0; } int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock ) { struct ldap_int_thread_rdwr_s *rw; assert( rwlock != NULL ); rw = *rwlock; assert( rw != NULL ); assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID ); if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID ) return LDAP_PVT_THREAD_EINVAL; ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex ); assert( rw->ltrw_w_active >= 0 ); assert( rw->ltrw_w_wait >= 0 ); assert( rw->ltrw_r_active >= 0 ); assert( rw->ltrw_r_wait >= 0 ); if( rw->ltrw_w_active > 0 ) { /* writer is active */ rw->ltrw_r_wait++; do { ldap_pvt_thread_cond_wait( &rw->ltrw_read, &rw->ltrw_mutex ); } while( rw->ltrw_w_active > 0 ); rw->ltrw_r_wait--; assert( rw->ltrw_r_wait >= 0 ); } #ifdef LDAP_RDWR_DEBUG if( rw->ltrw_r_active < MAX_READERS ) rw->ltrw_readers[rw->ltrw_r_active] = ldap_pvt_thread_self(); else rw->ltrw_more_readers = 1; #endif rw->ltrw_r_active++; ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex ); return 0; } int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock ) { struct ldap_int_thread_rdwr_s *rw; assert( rwlock != NULL ); rw = *rwlock; assert( rw != NULL ); assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID ); if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID ) return LDAP_PVT_THREAD_EINVAL; ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex ); assert( rw->ltrw_w_active >= 0 ); assert( rw->ltrw_w_wait >= 0 ); assert( rw->ltrw_r_active >= 0 ); assert( rw->ltrw_r_wait >= 0 ); if( rw->ltrw_w_active > 0) { ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex ); return LDAP_PVT_THREAD_EBUSY; } #ifdef LDAP_RDWR_DEBUG if( rw->ltrw_r_active < MAX_READERS ) rw->ltrw_readers[rw->ltrw_r_active] = ldap_pvt_thread_self(); else rw->ltrw_more_readers = 1; #endif rw->ltrw_r_active++; ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex ); return 0; } int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock ) { struct ldap_int_thread_rdwr_s *rw; assert( rwlock != NULL ); rw = *rwlock; assert( rw != NULL ); assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID ); if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID ) return LDAP_PVT_THREAD_EINVAL; ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex ); rw->ltrw_r_active--; #ifdef LDAP_RDWR_DEBUG /* Remove us from the list of readers */ { ldap_pvt_thread_t self = ldap_pvt_thread_self(); int i, j; for( i = j = rw->ltrw_r_active; i >= 0; i--) { if (rw->ltrw_readers[i] == self) { rw->ltrw_readers[i] = rw->ltrw_readers[j]; rw->ltrw_readers[j] = 0; break; } } if( !rw->ltrw_more_readers ) assert( i >= 0 ); else if( j == 0 ) rw->ltrw_more_readers = 0; } #endif assert( rw->ltrw_w_active >= 0 ); assert( rw->ltrw_w_wait >= 0 ); assert( rw->ltrw_r_active >= 0 ); assert( rw->ltrw_r_wait >= 0 ); if (rw->ltrw_r_active == 0 && rw->ltrw_w_wait > 0 ) { ldap_pvt_thread_cond_signal( &rw->ltrw_write ); } ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex ); return 0; } int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock ) { struct ldap_int_thread_rdwr_s *rw; assert( rwlock != NULL ); rw = *rwlock; assert( rw != NULL ); assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID ); if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID ) return LDAP_PVT_THREAD_EINVAL; ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex ); assert( rw->ltrw_w_active >= 0 ); assert( rw->ltrw_w_wait >= 0 ); assert( rw->ltrw_r_active >= 0 ); assert( rw->ltrw_r_wait >= 0 ); if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) { rw->ltrw_w_wait++; do { ldap_pvt_thread_cond_wait( &rw->ltrw_write, &rw->ltrw_mutex ); } while ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ); rw->ltrw_w_wait--; assert( rw->ltrw_w_wait >= 0 ); } #ifdef LDAP_RDWR_DEBUG rw->ltrw_writer = ldap_pvt_thread_self(); #endif rw->ltrw_w_active++; ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex ); return 0; } int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock ) { struct ldap_int_thread_rdwr_s *rw; assert( rwlock != NULL ); rw = *rwlock; assert( rw != NULL ); assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID ); if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID ) return LDAP_PVT_THREAD_EINVAL; ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex ); assert( rw->ltrw_w_active >= 0 ); assert( rw->ltrw_w_wait >= 0 ); assert( rw->ltrw_r_active >= 0 ); assert( rw->ltrw_r_wait >= 0 ); if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) { ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex ); return LDAP_PVT_THREAD_EBUSY; } #ifdef LDAP_RDWR_DEBUG rw->ltrw_writer = ldap_pvt_thread_self(); #endif rw->ltrw_w_active++; ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex ); return 0; } int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock ) { struct ldap_int_thread_rdwr_s *rw; assert( rwlock != NULL ); rw = *rwlock; assert( rw != NULL ); assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID ); if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID ) return LDAP_PVT_THREAD_EINVAL; ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex ); rw->ltrw_w_active--; assert( rw->ltrw_w_active >= 0 ); assert( rw->ltrw_w_wait >= 0 ); assert( rw->ltrw_r_active >= 0 ); assert( rw->ltrw_r_wait >= 0 ); if (rw->ltrw_r_wait > 0) { ldap_pvt_thread_cond_broadcast( &rw->ltrw_read ); } else if (rw->ltrw_w_wait > 0) { ldap_pvt_thread_cond_signal( &rw->ltrw_write ); } #ifdef LDAP_RDWR_DEBUG assert( rw->ltrw_writer == ldap_pvt_thread_self() ); rw->ltrw_writer = 0; #endif ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex ); return 0; } #ifdef LDAP_RDWR_DEBUG /* just for testing, * return 0 if false, suitable for assert(ldap_pvt_thread_rdwr_Xchk(rdwr)) * * Currently they don't check if the calling thread is the one * that has the lock, just that there is a reader or writer. * * Basically sufficient for testing that places that should have * a lock are caught. */ int ldap_pvt_thread_rdwr_readers(ldap_pvt_thread_rdwr_t *rwlock) { struct ldap_int_thread_rdwr_s *rw; assert( rwlock != NULL ); rw = *rwlock; assert( rw != NULL ); assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID ); assert( rw->ltrw_w_active >= 0 ); assert( rw->ltrw_w_wait >= 0 ); assert( rw->ltrw_r_active >= 0 ); assert( rw->ltrw_r_wait >= 0 ); return( rw->ltrw_r_active ); } int ldap_pvt_thread_rdwr_writers(ldap_pvt_thread_rdwr_t *rwlock) { struct ldap_int_thread_rdwr_s *rw; assert( rwlock != NULL ); rw = *rwlock; assert( rw != NULL ); assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID ); assert( rw->ltrw_w_active >= 0 ); assert( rw->ltrw_w_wait >= 0 ); assert( rw->ltrw_r_active >= 0 ); assert( rw->ltrw_r_wait >= 0 ); return( rw->ltrw_w_active ); } int ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t *rwlock) { struct ldap_int_thread_rdwr_s *rw; assert( rwlock != NULL ); rw = *rwlock; assert( rw != NULL ); assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID ); assert( rw->ltrw_w_active >= 0 ); assert( rw->ltrw_w_wait >= 0 ); assert( rw->ltrw_r_active >= 0 ); assert( rw->ltrw_r_wait >= 0 ); return(ldap_pvt_thread_rdwr_readers(rwlock) + ldap_pvt_thread_rdwr_writers(rwlock)); } #endif /* LDAP_RDWR_DEBUG */ #endif /* LDAP_THREAD_HAVE_RDWR */ #endif /* LDAP_R_COMPILE */ openldap-2.5.11+dfsg/libraries/libldap/stctrl.c0000644000175000017500000001366214172327167020111 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * Portions Copyright 2007 Pierangelo Masarati. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This work was developed by Pierangelo Masarati for inclusion in * OpenLDAP Software. */ #include "portable.h" #include #include #include #include #include "ldap-int.h" #ifdef LDAP_CONTROL_X_SESSION_TRACKING /* * Client-side of */ int ldap_create_session_tracking_value( LDAP *ld, char *sessionSourceIp, char *sessionSourceName, char *formatOID, struct berval *sessionTrackingIdentifier, struct berval *value ) { BerElement *ber = NULL; ber_tag_t tag; struct berval ip, name, oid, id; if ( ld == NULL || formatOID == NULL || value == NULL ) { param_error:; if ( ld ) { ld->ld_errno = LDAP_PARAM_ERROR; } return LDAP_PARAM_ERROR; } assert( LDAP_VALID( ld ) ); ld->ld_errno = LDAP_SUCCESS; /* check sizes according to I.D. */ if ( sessionSourceIp == NULL ) { BER_BVSTR( &ip, "" ); } else { ber_str2bv( sessionSourceIp, 0, 0, &ip ); /* NOTE: we're strict because we don't want * to send out bad data */ if ( ip.bv_len > 128 ) goto param_error; } if ( sessionSourceName == NULL ) { BER_BVSTR( &name, "" ); } else { ber_str2bv( sessionSourceName, 0, 0, &name ); /* NOTE: we're strict because we don't want * to send out bad data */ if ( name.bv_len > 65536 ) goto param_error; } ber_str2bv( formatOID, 0, 0, &oid ); /* NOTE: we're strict because we don't want * to send out bad data */ if ( oid.bv_len > 1024 ) goto param_error; if ( sessionTrackingIdentifier == NULL || sessionTrackingIdentifier->bv_val == NULL ) { BER_BVSTR( &id, "" ); } else { id = *sessionTrackingIdentifier; } /* prepare value */ value->bv_val = NULL; value->bv_len = 0; ber = ldap_alloc_ber_with_options( ld ); if ( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } tag = ber_printf( ber, "{OOOO}", &ip, &name, &oid, &id ); if ( tag == LBER_ERROR ) { ld->ld_errno = LDAP_ENCODING_ERROR; goto done; } if ( ber_flatten2( ber, value, 1 ) == -1 ) { ld->ld_errno = LDAP_NO_MEMORY; } done:; if ( ber != NULL ) { ber_free( ber, 1 ); } return ld->ld_errno; } /* * NOTE: this API is bad; it could be much more efficient... */ int ldap_create_session_tracking_control( LDAP *ld, char *sessionSourceIp, char *sessionSourceName, char *formatOID, struct berval *sessionTrackingIdentifier, LDAPControl **ctrlp ) { struct berval value; if ( ctrlp == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; } ld->ld_errno = ldap_create_session_tracking_value( ld, sessionSourceIp, sessionSourceName, formatOID, sessionTrackingIdentifier, &value ); if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = ldap_control_create( LDAP_CONTROL_X_SESSION_TRACKING, 0, &value, 0, ctrlp ); if ( ld->ld_errno != LDAP_SUCCESS ) { LDAP_FREE( value.bv_val ); } } return ld->ld_errno; } int ldap_parse_session_tracking_control( LDAP *ld, LDAPControl *ctrl, struct berval *ip, struct berval *name, struct berval *oid, struct berval *id ) { BerElement *ber; ber_tag_t tag; ber_len_t len; if ( ld == NULL || ctrl == NULL || ip == NULL || name == NULL || oid == NULL || id == NULL ) { if ( ld ) { ld->ld_errno = LDAP_PARAM_ERROR; } /* NOTE: we want the caller to get all or nothing; * we could allow some of the pointers to be NULL, * if one does not want part of the data */ return LDAP_PARAM_ERROR; } BER_BVZERO( ip ); BER_BVZERO( name ); BER_BVZERO( oid ); BER_BVZERO( id ); ber = ber_init( &ctrl->ldctl_value ); if ( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } tag = ber_skip_tag( ber, &len ); if ( tag != LBER_SEQUENCE ) { tag = LBER_ERROR; goto error; } /* sessionSourceIp */ tag = ber_peek_tag( ber, &len ); if ( tag == LBER_DEFAULT ) { tag = LBER_ERROR; goto error; } if ( len == 0 ) { tag = ber_skip_tag( ber, &len ); } else { if ( len > 128 ) { /* should be LDAP_DECODING_ERROR, * but we're liberal in what we accept */ } tag = ber_scanf( ber, "o", ip ); } /* sessionSourceName */ tag = ber_peek_tag( ber, &len ); if ( tag == LBER_DEFAULT ) { tag = LBER_ERROR; goto error; } if ( len == 0 ) { tag = ber_skip_tag( ber, &len ); } else { if ( len > 65536 ) { /* should be LDAP_DECODING_ERROR, * but we're liberal in what we accept */ } tag = ber_scanf( ber, "o", name ); } /* formatOID */ tag = ber_peek_tag( ber, &len ); if ( tag == LBER_DEFAULT ) { tag = LBER_ERROR; goto error; } if ( len == 0 ) { ld->ld_errno = LDAP_DECODING_ERROR; goto error; } else { if ( len > 1024 ) { /* should be LDAP_DECODING_ERROR, * but we're liberal in what we accept */ } tag = ber_scanf( ber, "o", oid ); } /* FIXME: should check if it is an OID... leave it to the caller */ /* sessionTrackingIdentifier */ tag = ber_peek_tag( ber, &len ); if ( tag == LBER_DEFAULT ) { tag = LBER_ERROR; goto error; } if ( len == 0 ) { tag = ber_skip_tag( ber, &len ); } else { #if 0 if ( len > 65536 ) { /* should be LDAP_DECODING_ERROR, * but we're liberal in what we accept */ } #endif tag = ber_scanf( ber, "o", id ); } /* closure */ tag = ber_skip_tag( ber, &len ); if ( tag == LBER_DEFAULT && len == 0 ) { tag = 0; } error:; (void)ber_free( ber, 1 ); if ( tag == LBER_ERROR ) { return LDAP_DECODING_ERROR; } return ld->ld_errno; } #endif /* LDAP_CONTROL_X_SESSION_TRACKING */ openldap-2.5.11+dfsg/libraries/libldap/ldap_sync.c0000644000175000017500000004637414172327167020560 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2006-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This program was originally developed by Pierangelo Masarati * for inclusion in OpenLDAP Software. */ /* * Proof-of-concept API that implement the client-side * of the "LDAP Content Sync Operation" (RFC 4533) */ #include "portable.h" #include #include "ldap-int.h" #ifdef LDAP_SYNC_TRACE static const char * ldap_sync_state2str( int state ) { switch ( state ) { case LDAP_SYNC_PRESENT: return "LDAP_SYNC_PRESENT"; case LDAP_SYNC_ADD: return "LDAP_SYNC_ADD"; case LDAP_SYNC_MODIFY: return "LDAP_SYNC_MODIFY"; case LDAP_SYNC_DELETE: return "LDAP_SYNC_DELETE"; default: return "(unknown)"; } } #endif /* * initialize the persistent search structure */ ldap_sync_t * ldap_sync_initialize( ldap_sync_t *ls_in ) { ldap_sync_t *ls = ls_in; if ( ls == NULL ) { ls = ldap_memalloc( sizeof( ldap_sync_t ) ); if ( ls == NULL ) { return NULL; } } memset( ls, 0, sizeof( ldap_sync_t ) ); ls->ls_scope = LDAP_SCOPE_SUBTREE; ls->ls_timeout = -1; return ls; } /* * destroy the persistent search structure */ void ldap_sync_destroy( ldap_sync_t *ls, int freeit ) { assert( ls != NULL ); if ( ls->ls_base != NULL ) { ldap_memfree( ls->ls_base ); ls->ls_base = NULL; } if ( ls->ls_filter != NULL ) { ldap_memfree( ls->ls_filter ); ls->ls_filter = NULL; } if ( ls->ls_attrs != NULL ) { int i; for ( i = 0; ls->ls_attrs[ i ] != NULL; i++ ) { ldap_memfree( ls->ls_attrs[ i ] ); } ldap_memfree( ls->ls_attrs ); ls->ls_attrs = NULL; } if ( ls->ls_ld != NULL ) { (void)ldap_unbind_ext( ls->ls_ld, NULL, NULL ); #ifdef LDAP_SYNC_TRACE fprintf( stderr, "ldap_unbind_ext()\n" ); #endif /* LDAP_SYNC_TRACE */ ls->ls_ld = NULL; } if ( ls->ls_cookie.bv_val != NULL ) { ldap_memfree( ls->ls_cookie.bv_val ); ls->ls_cookie.bv_val = NULL; } if ( freeit ) { ldap_memfree( ls ); } } /* * handle the LDAP_RES_SEARCH_ENTRY response */ static int ldap_sync_search_entry( ldap_sync_t *ls, LDAPMessage *res ) { LDAPControl **ctrls = NULL; int rc = LDAP_OTHER, i; BerElement *ber = NULL; struct berval entryUUID = { 0 }, cookie = { 0 }; int state = -1; ber_len_t len; ldap_sync_refresh_t phase; #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\tgot LDAP_RES_SEARCH_ENTRY\n" ); #endif /* LDAP_SYNC_TRACE */ assert( ls != NULL ); assert( res != NULL ); phase = ls->ls_refreshPhase; /* OK */ /* extract: * - data * - entryUUID * * check that: * - Sync State Control is "add" */ /* the control MUST be present */ /* extract controls */ ldap_get_entry_controls( ls->ls_ld, res, &ctrls ); if ( ctrls == NULL ) { goto done; } /* lookup the sync state control */ for ( i = 0; ctrls[ i ] != NULL; i++ ) { if ( strcmp( ctrls[ i ]->ldctl_oid, LDAP_CONTROL_SYNC_STATE ) == 0 ) { break; } } /* control must be present; there might be other... */ if ( ctrls[ i ] == NULL ) { goto done; } /* extract data */ ber = ber_init( &ctrls[ i ]->ldctl_value ); if ( ber == NULL ) { goto done; } /* scan entryUUID in-place ("m") */ if ( ber_scanf( ber, "{em" /*"}"*/, &state, &entryUUID ) == LBER_ERROR || entryUUID.bv_len == 0 ) { goto done; } if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) { /* scan cookie in-place ("m") */ if ( ber_scanf( ber, /*"{"*/ "m}", &cookie ) == LBER_ERROR ) { goto done; } if ( cookie.bv_val != NULL ) { ber_bvreplace( &ls->ls_cookie, &cookie ); } #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot cookie=%s\n", cookie.bv_val ? cookie.bv_val : "(null)" ); #endif /* LDAP_SYNC_TRACE */ } switch ( state ) { case LDAP_SYNC_PRESENT: case LDAP_SYNC_DELETE: case LDAP_SYNC_ADD: case LDAP_SYNC_MODIFY: /* NOTE: ldap_sync_refresh_t is defined * as the corresponding LDAP_SYNC_* * for the 4 above cases */ phase = state; #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot syncState=%s\n", ldap_sync_state2str( state ) ); #endif /* LDAP_SYNC_TRACE */ break; default: #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot unknown syncState=%d\n", state ); #endif /* LDAP_SYNC_TRACE */ goto done; } rc = ls->ls_search_entry ? ls->ls_search_entry( ls, res, &entryUUID, phase ) : LDAP_SUCCESS; done:; if ( ber != NULL ) { ber_free( ber, 1 ); } if ( ctrls != NULL ) { ldap_controls_free( ctrls ); } return rc; } /* * handle the LDAP_RES_SEARCH_REFERENCE response * (to be implemented yet) */ static int ldap_sync_search_reference( ldap_sync_t *ls, LDAPMessage *res ) { int rc = 0; #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\tgot LDAP_RES_SEARCH_REFERENCE\n" ); #endif /* LDAP_SYNC_TRACE */ assert( ls != NULL ); assert( res != NULL ); if ( ls->ls_search_reference ) { rc = ls->ls_search_reference( ls, res ); } return rc; } /* * handle the LDAP_RES_SEARCH_RESULT response */ static int ldap_sync_search_result( ldap_sync_t *ls, LDAPMessage *res ) { int err; char *matched = NULL, *msg = NULL; LDAPControl **ctrls = NULL; int rc; int refreshDeletes = -1; #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\tgot LDAP_RES_SEARCH_RESULT\n" ); #endif /* LDAP_SYNC_TRACE */ assert( ls != NULL ); assert( res != NULL ); /* should not happen in refreshAndPersist... */ rc = ldap_parse_result( ls->ls_ld, res, &err, &matched, &msg, NULL, &ctrls, 0 ); #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\tldap_parse_result(%d, \"%s\", \"%s\") == %d\n", err, matched ? matched : "", msg ? msg : "", rc ); #endif /* LDAP_SYNC_TRACE */ if ( rc == LDAP_SUCCESS ) { rc = err; } ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE; switch ( rc ) { case LDAP_SUCCESS: { int i; BerElement *ber = NULL; ber_len_t len; struct berval cookie = { 0 }; rc = LDAP_OTHER; /* deal with control; then fallthru to handler */ if ( ctrls == NULL ) { goto done; } /* lookup the sync state control */ for ( i = 0; ctrls[ i ] != NULL; i++ ) { if ( strcmp( ctrls[ i ]->ldctl_oid, LDAP_CONTROL_SYNC_DONE ) == 0 ) { break; } } /* control must be present; there might be other... */ if ( ctrls[ i ] == NULL ) { goto done; } /* extract data */ ber = ber_init( &ctrls[ i ]->ldctl_value ); if ( ber == NULL ) { goto done; } if ( ber_scanf( ber, "{" /*"}"*/) == LBER_ERROR ) { goto ber_done; } if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) { if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) { goto ber_done; } if ( cookie.bv_val != NULL ) { ber_bvreplace( &ls->ls_cookie, &cookie ); } #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot cookie=%s\n", cookie.bv_val ? cookie.bv_val : "(null)" ); #endif /* LDAP_SYNC_TRACE */ } refreshDeletes = 0; if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) { if ( ber_scanf( ber, "b", &refreshDeletes ) == LBER_ERROR ) { goto ber_done; } if ( refreshDeletes ) { refreshDeletes = 1; } } if ( ber_scanf( ber, /*"{"*/ "}" ) != LBER_ERROR ) { rc = LDAP_SUCCESS; } ber_done:; ber_free( ber, 1 ); if ( rc != LDAP_SUCCESS ) { break; } #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot refreshDeletes=%s\n", refreshDeletes ? "TRUE" : "FALSE" ); #endif /* LDAP_SYNC_TRACE */ /* FIXME: what should we do with the refreshDelete? */ switch ( refreshDeletes ) { case 0: ls->ls_refreshPhase = LDAP_SYNC_CAPI_PRESENTS; break; default: ls->ls_refreshPhase = LDAP_SYNC_CAPI_DELETES; break; } } /* fallthru */ case LDAP_SYNC_REFRESH_REQUIRED: /* TODO: check for Sync Done Control */ /* FIXME: perhaps the handler should be called * also in case of failure; we'll deal with this * later when implementing refreshOnly */ if ( ls->ls_search_result ) { err = ls->ls_search_result( ls, res, refreshDeletes ); } break; } done:; if ( matched != NULL ) { ldap_memfree( matched ); } if ( msg != NULL ) { ldap_memfree( msg ); } if ( ctrls != NULL ) { ldap_controls_free( ctrls ); } ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE; return rc; } /* * handle the LDAP_RES_INTERMEDIATE response */ static int ldap_sync_search_intermediate( ldap_sync_t *ls, LDAPMessage *res, int *refreshDone ) { int rc; char *retoid = NULL; struct berval *retdata = NULL; BerElement *ber = NULL; ber_len_t len; ber_tag_t syncinfo_tag; struct berval cookie; int refreshDeletes = 0; BerVarray syncUUIDs = NULL; ldap_sync_refresh_t phase; #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\tgot LDAP_RES_INTERMEDIATE\n" ); #endif /* LDAP_SYNC_TRACE */ assert( ls != NULL ); assert( res != NULL ); assert( refreshDone != NULL ); *refreshDone = 0; rc = ldap_parse_intermediate( ls->ls_ld, res, &retoid, &retdata, NULL, 0 ); #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t%sldap_parse_intermediate(%s) == %d\n", rc != LDAP_SUCCESS ? "!!! " : "", retoid == NULL ? "\"\"" : retoid, rc ); #endif /* LDAP_SYNC_TRACE */ /* parsing must be successful, and yield the OID * of the sync info intermediate response */ if ( rc != LDAP_SUCCESS ) { goto done; } rc = LDAP_OTHER; if ( retoid == NULL || strcmp( retoid, LDAP_SYNC_INFO ) != 0 ) { goto done; } /* init ber using the value in the response */ ber = ber_init( retdata ); if ( ber == NULL ) { goto done; } syncinfo_tag = ber_peek_tag( ber, &len ); switch ( syncinfo_tag ) { case LDAP_TAG_SYNC_NEW_COOKIE: if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) { goto done; } if ( cookie.bv_val != NULL ) { ber_bvreplace( &ls->ls_cookie, &cookie ); } #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot cookie=%s\n", cookie.bv_val ? cookie.bv_val : "(null)" ); #endif /* LDAP_SYNC_TRACE */ break; case LDAP_TAG_SYNC_REFRESH_DELETE: case LDAP_TAG_SYNC_REFRESH_PRESENT: if ( syncinfo_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) { #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot refreshDelete\n" ); #endif /* LDAP_SYNC_TRACE */ switch ( ls->ls_refreshPhase ) { case LDAP_SYNC_CAPI_NONE: case LDAP_SYNC_CAPI_PRESENTS: ls->ls_refreshPhase = LDAP_SYNC_CAPI_DELETES; break; default: /* TODO: impossible; handle */ goto done; } } else { #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot refreshPresent\n" ); #endif /* LDAP_SYNC_TRACE */ switch ( ls->ls_refreshPhase ) { case LDAP_SYNC_CAPI_NONE: ls->ls_refreshPhase = LDAP_SYNC_CAPI_PRESENTS; break; default: /* TODO: impossible; handle */ goto done; } } if ( ber_scanf( ber, "{" /*"}"*/ ) == LBER_ERROR ) { goto done; } if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) { if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) { goto done; } if ( cookie.bv_val != NULL ) { ber_bvreplace( &ls->ls_cookie, &cookie ); } #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot cookie=%s\n", cookie.bv_val ? cookie.bv_val : "(null)" ); #endif /* LDAP_SYNC_TRACE */ } *refreshDone = 1; if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDONE ) { if ( ber_scanf( ber, "b", refreshDone ) == LBER_ERROR ) { goto done; } } #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot refreshDone=%s\n", *refreshDone ? "TRUE" : "FALSE" ); #endif /* LDAP_SYNC_TRACE */ if ( ber_scanf( ber, /*"{"*/ "}" ) == LBER_ERROR ) { goto done; } if ( *refreshDone ) { ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE; } if ( ls->ls_intermediate ) { ls->ls_intermediate( ls, res, NULL, ls->ls_refreshPhase ); } break; case LDAP_TAG_SYNC_ID_SET: #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot syncIdSet\n" ); #endif /* LDAP_SYNC_TRACE */ if ( ber_scanf( ber, "{" /*"}"*/ ) == LBER_ERROR ) { goto done; } if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) { if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) { goto done; } if ( cookie.bv_val != NULL ) { ber_bvreplace( &ls->ls_cookie, &cookie ); } #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tgot cookie=%s\n", cookie.bv_val ? cookie.bv_val : "(null)" ); #endif /* LDAP_SYNC_TRACE */ } if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) { if ( ber_scanf( ber, "b", &refreshDeletes ) == LBER_ERROR ) { goto done; } } if ( ber_scanf( ber, /*"{"*/ "[W]}", &syncUUIDs ) == LBER_ERROR || syncUUIDs == NULL ) { goto done; } #ifdef LDAP_SYNC_TRACE { int i; fprintf( stderr, "\t\tgot refreshDeletes=%s\n", refreshDeletes ? "TRUE" : "FALSE" ); for ( i = 0; syncUUIDs[ i ].bv_val != NULL; i++ ) { char buf[ BUFSIZ ]; fprintf( stderr, "\t\t%s\n", lutil_uuidstr_from_normalized( syncUUIDs[ i ].bv_val, syncUUIDs[ i ].bv_len, buf, sizeof( buf ) ) ); } } #endif /* LDAP_SYNC_TRACE */ if ( refreshDeletes ) { phase = LDAP_SYNC_CAPI_DELETES_IDSET; } else { phase = LDAP_SYNC_CAPI_PRESENTS_IDSET; } /* FIXME: should touch ls->ls_refreshPhase? */ if ( ls->ls_intermediate ) { ls->ls_intermediate( ls, res, syncUUIDs, phase ); } ber_bvarray_free( syncUUIDs ); break; default: #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t\tunknown tag!\n" ); #endif /* LDAP_SYNC_TRACE */ goto done; } rc = LDAP_SUCCESS; done:; if ( ber != NULL ) { ber_free( ber, 1 ); } if ( retoid != NULL ) { ldap_memfree( retoid ); } if ( retdata != NULL ) { ber_bvfree( retdata ); } return rc; } /* * initialize the sync */ int ldap_sync_init( ldap_sync_t *ls, int mode ) { LDAPControl ctrl = { 0 }, *ctrls[ 2 ]; BerElement *ber = NULL; int rc; struct timeval tv = { 0 }, *tvp = NULL; LDAPMessage *res = NULL; #ifdef LDAP_SYNC_TRACE fprintf( stderr, "ldap_sync_init(%s)...\n", mode == LDAP_SYNC_REFRESH_AND_PERSIST ? "LDAP_SYNC_REFRESH_AND_PERSIST" : ( mode == LDAP_SYNC_REFRESH_ONLY ? "LDAP_SYNC_REFRESH_ONLY" : "unknown" ) ); #endif /* LDAP_SYNC_TRACE */ assert( ls != NULL ); assert( ls->ls_ld != NULL ); /* support both refreshOnly and refreshAndPersist */ switch ( mode ) { case LDAP_SYNC_REFRESH_AND_PERSIST: case LDAP_SYNC_REFRESH_ONLY: break; default: fprintf( stderr, "ldap_sync_init: unknown mode=%d\n", mode ); return LDAP_PARAM_ERROR; } /* check consistency of cookie and reloadHint at initial refresh */ if ( ls->ls_cookie.bv_val == NULL && ls->ls_reloadHint != 0 ) { fprintf( stderr, "ldap_sync_init: inconsistent cookie/rhint\n" ); return LDAP_PARAM_ERROR; } ctrls[ 0 ] = &ctrl; ctrls[ 1 ] = NULL; /* prepare the Sync Request control */ ber = ber_alloc_t( LBER_USE_DER ); #ifdef LDAP_SYNC_TRACE fprintf( stderr, "%sber_alloc_t() %s= NULL\n", ber == NULL ? "!!! " : "", ber == NULL ? "=" : "!" ); #endif /* LDAP_SYNC_TRACE */ if ( ber == NULL ) { rc = LDAP_NO_MEMORY; goto done; } ls->ls_refreshPhase = LDAP_SYNC_CAPI_NONE; if ( ls->ls_cookie.bv_val != NULL ) { ber_printf( ber, "{eOb}", mode, &ls->ls_cookie, ls->ls_reloadHint ); } else { ber_printf( ber, "{eb}", mode, ls->ls_reloadHint ); } rc = ber_flatten2( ber, &ctrl.ldctl_value, 0 ); #ifdef LDAP_SYNC_TRACE fprintf( stderr, "%sber_flatten2() == %d\n", rc ? "!!! " : "", rc ); #endif /* LDAP_SYNC_TRACE */ if ( rc < 0 ) { rc = LDAP_OTHER; goto done; } /* make the control critical, as we cannot proceed without */ ctrl.ldctl_oid = LDAP_CONTROL_SYNC; ctrl.ldctl_iscritical = 1; /* timelimit? */ if ( ls->ls_timelimit ) { tv.tv_sec = ls->ls_timelimit; tvp = &tv; } /* actually run the search */ rc = ldap_search_ext( ls->ls_ld, ls->ls_base, ls->ls_scope, ls->ls_filter, ls->ls_attrs, 0, ctrls, NULL, tvp, ls->ls_sizelimit, &ls->ls_msgid ); #ifdef LDAP_SYNC_TRACE fprintf( stderr, "%sldap_search_ext(\"%s\", %d, \"%s\") == %d\n", rc ? "!!! " : "", ls->ls_base, ls->ls_scope, ls->ls_filter, rc ); #endif /* LDAP_SYNC_TRACE */ if ( rc != LDAP_SUCCESS ) { goto done; } /* initial content/content update phase */ for ( ; ; ) { LDAPMessage *msg = NULL; /* NOTE: this very short timeout is just to let * ldap_result() yield long enough to get something */ tv.tv_sec = 0; tv.tv_usec = 100000; rc = ldap_result( ls->ls_ld, ls->ls_msgid, LDAP_MSG_RECEIVED, &tv, &res ); #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\t%sldap_result(%d) == %d\n", rc == -1 ? "!!! " : "", ls->ls_msgid, rc ); #endif /* LDAP_SYNC_TRACE */ switch ( rc ) { case 0: /* * timeout * * TODO: can do something else in the meanwhile) */ break; case -1: /* smtg bad! */ goto done; default: for ( msg = ldap_first_message( ls->ls_ld, res ); msg != NULL; msg = ldap_next_message( ls->ls_ld, msg ) ) { int refreshDone; switch ( ldap_msgtype( msg ) ) { case LDAP_RES_SEARCH_ENTRY: rc = ldap_sync_search_entry( ls, res ); break; case LDAP_RES_SEARCH_REFERENCE: rc = ldap_sync_search_reference( ls, res ); break; case LDAP_RES_SEARCH_RESULT: rc = ldap_sync_search_result( ls, res ); goto done_search; case LDAP_RES_INTERMEDIATE: rc = ldap_sync_search_intermediate( ls, res, &refreshDone ); if ( rc != LDAP_SUCCESS || refreshDone ) { goto done_search; } break; default: #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\tgot something unexpected...\n" ); #endif /* LDAP_SYNC_TRACE */ ldap_msgfree( res ); rc = LDAP_OTHER; goto done; } } ldap_msgfree( res ); res = NULL; break; } } done_search:; ldap_msgfree( res ); done:; if ( ber != NULL ) { ber_free( ber, 1 ); } return rc; } /* * initialize the refreshOnly sync */ int ldap_sync_init_refresh_only( ldap_sync_t *ls ) { return ldap_sync_init( ls, LDAP_SYNC_REFRESH_ONLY ); } /* * initialize the refreshAndPersist sync */ int ldap_sync_init_refresh_and_persist( ldap_sync_t *ls ) { return ldap_sync_init( ls, LDAP_SYNC_REFRESH_AND_PERSIST ); } /* * poll for new responses */ int ldap_sync_poll( ldap_sync_t *ls ) { struct timeval tv, *tvp = NULL; LDAPMessage *res = NULL, *msg; int rc = 0; #ifdef LDAP_SYNC_TRACE fprintf( stderr, "ldap_sync_poll...\n" ); #endif /* LDAP_SYNC_TRACE */ assert( ls != NULL ); assert( ls->ls_ld != NULL ); if ( ls->ls_timeout != -1 ) { tv.tv_sec = ls->ls_timeout; tv.tv_usec = 0; tvp = &tv; } rc = ldap_result( ls->ls_ld, ls->ls_msgid, LDAP_MSG_RECEIVED, tvp, &res ); if ( rc <= 0 ) { return rc; } for ( msg = ldap_first_message( ls->ls_ld, res ); msg; msg = ldap_next_message( ls->ls_ld, msg ) ) { int refreshDone; switch ( ldap_msgtype( msg ) ) { case LDAP_RES_SEARCH_ENTRY: rc = ldap_sync_search_entry( ls, res ); break; case LDAP_RES_SEARCH_REFERENCE: rc = ldap_sync_search_reference( ls, res ); break; case LDAP_RES_SEARCH_RESULT: rc = ldap_sync_search_result( ls, res ); goto done_search; case LDAP_RES_INTERMEDIATE: rc = ldap_sync_search_intermediate( ls, res, &refreshDone ); if ( rc != LDAP_SUCCESS || refreshDone ) { goto done_search; } break; default: #ifdef LDAP_SYNC_TRACE fprintf( stderr, "\tgot something unexpected...\n" ); #endif /* LDAP_SYNC_TRACE */ ldap_msgfree( res ); rc = LDAP_OTHER; goto done; } } done_search:; ldap_msgfree( res ); done:; return rc; } openldap-2.5.11+dfsg/libraries/libldap/turn.c0000644000175000017500000000405314172327167017560 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2005-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This program was originally developed by Kurt D. Zeilenga for inclusion in * OpenLDAP Software. */ /* * LDAPv3 Turn Operation Request */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" #include "ldap_log.h" int ldap_turn( LDAP *ld, int mutual, LDAP_CONST char* identifier, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp ) { #ifdef LDAP_EXOP_X_TURN BerElement *turnvalber = NULL; struct berval *turnvalp = NULL; int rc; turnvalber = ber_alloc_t( LBER_USE_DER ); if( mutual ) { ber_printf( turnvalber, "{bs}", mutual, identifier ); } else { ber_printf( turnvalber, "{s}", identifier ); } ber_flatten( turnvalber, &turnvalp ); rc = ldap_extended_operation( ld, LDAP_EXOP_X_TURN, turnvalp, sctrls, cctrls, msgidp ); ber_free( turnvalber, 1 ); return rc; #else return LDAP_CONTROL_NOT_FOUND; #endif } int ldap_turn_s( LDAP *ld, int mutual, LDAP_CONST char* identifier, LDAPControl **sctrls, LDAPControl **cctrls ) { #ifdef LDAP_EXOP_X_TURN BerElement *turnvalber = NULL; struct berval *turnvalp = NULL; int rc; turnvalber = ber_alloc_t( LBER_USE_DER ); if( mutual ) { ber_printf( turnvalber, "{bs}", 0xFF, identifier ); } else { ber_printf( turnvalber, "{s}", identifier ); } ber_flatten( turnvalber, &turnvalp ); rc = ldap_extended_operation_s( ld, LDAP_EXOP_X_TURN, turnvalp, sctrls, cctrls, NULL, NULL ); ber_free( turnvalber, 1 ); return rc; #else return LDAP_CONTROL_NOT_FOUND; #endif } openldap-2.5.11+dfsg/libraries/libldap/Makefile.in0000644000175000017500000000730514172327167020474 0ustar ryanryan# Makefile.in for LDAP -lldap # $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . LIBRARY = libldap.la PROGRAMS = apitest dntest ftest ltest urltest testavl SRCS = bind.c open.c result.c error.c compare.c search.c \ controls.c messages.c references.c extended.c cyrus.c \ modify.c add.c modrdn.c delete.c abandon.c \ sasl.c sbind.c unbind.c cancel.c \ filter.c free.c sort.c passwd.c whoami.c vc.c \ getdn.c getentry.c getattr.c getvalues.c addentry.c \ request.c os-ip.c url.c pagectrl.c sortctrl.c vlvctrl.c \ init.c options.c print.c string.c util-int.c schema.c \ charray.c os-local.c dnssrv.c utf-8.c utf-8-conv.c \ tls2.c tls_o.c tls_g.c \ turn.c ppolicy.c dds.c txn.c ldap_sync.c stctrl.c \ assertion.c deref.c ldifutil.c ldif.c fetch.c lbase64.c \ msctrl.c psearchctrl.c threads.c rdwr.c tpool.c rq.c \ thr_posix.c thr_thr.c thr_nt.c thr_pth.c thr_debug.c \ account_usability.c avl.c tavl.c testavl.c OBJS = bind.lo open.lo result.lo error.lo compare.lo search.lo \ controls.lo messages.lo references.lo extended.lo cyrus.lo \ modify.lo add.lo modrdn.lo delete.lo abandon.lo \ sasl.lo sbind.lo unbind.lo cancel.lo \ filter.lo free.lo sort.lo passwd.lo whoami.lo vc.lo \ getdn.lo getentry.lo getattr.lo getvalues.lo addentry.lo \ request.lo os-ip.lo url.lo pagectrl.lo sortctrl.lo vlvctrl.lo \ init.lo options.lo print.lo string.lo util-int.lo schema.lo \ charray.lo os-local.lo dnssrv.lo utf-8.lo utf-8-conv.lo \ tls2.lo tls_o.lo tls_g.lo \ turn.lo ppolicy.lo dds.lo txn.lo ldap_sync.lo stctrl.lo \ assertion.lo deref.lo ldifutil.lo ldif.lo fetch.lo lbase64.lo \ msctrl.lo psearchctrl.lo threads.lo rdwr.lo tpool.lo rq.lo \ thr_posix.lo thr_thr.lo thr_nt.lo thr_pth.lo thr_debug.lo \ account_usability.lo avl.lo tavl.lo LDAP_INCDIR= ../../include LDAP_LIBDIR= ../../libraries LIB_DEFS = -DLDAP_LIBRARY XLIBS = $(LIBRARY) $(LDAP_LIBLBER_LA) $(LDAP_LIBLUTIL_A) XXLIBS = $(SECURITY_LIBS) $(LUTIL_LIBS) NT_LINK_LIBS = $(LDAP_LIBLBER_LA) $(AC_LIBS) $(SECURITY_LIBS) UNIX_LINK_LIBS = $(LDAP_LIBLBER_LA) $(AC_LIBS) $(SECURITY_LIBS) $(LTHREAD_LIBS) ifneq (,$(OL_VERSIONED_SYMBOLS)) SYMBOL_VERSION_FLAGS=$(OL_VERSIONED_SYMBOLS)$(LDAP_LIBDIR)/libldap/libldap.vers endif apitest: $(XLIBS) apitest.o $(LTLINK) -o $@ apitest.o $(LIBS) dntest: $(XLIBS) dntest.o $(LTLINK) -o $@ dntest.o $(LIBS) ftest: $(XLIBS) ftest.o $(LTLINK) -o $@ ftest.o $(LIBS) ltest: $(XLIBS) test.o $(LTLINK) -o $@ test.o $(LIBS) testavl: $(XLIBS) testavl.o $(LTLINK) -o $@ testavl.o $(LIBS) testtavl: $(XLIBS) testtavl.o $(LTLINK) -o $@ testtavl.o $(LIBS) urltest: $(XLIBS) urltest.o $(LTLINK) -o $@ urltest.o $(LIBS) CFFILES=ldap.conf install-local: $(CFFILES) FORCE -$(MKDIR) $(DESTDIR)$(libdir) $(LTINSTALL) $(INSTALLFLAGS) -m 644 $(LIBRARY) $(DESTDIR)$(libdir) $(LTFINISH) $(DESTDIR)$(libdir) -$(MKDIR) $(DESTDIR)$(sysconfdir) @for i in $(CFFILES); do \ if test ! -f $(DESTDIR)$(sysconfdir)/$$i; then \ echo "installing $$i in $(sysconfdir)"; \ echo "$(INSTALL) $(INSTALLFLAGS) -m 644 $(srcdir)/$$i $(DESTDIR)$(sysconfdir)/$$i"; \ $(INSTALL) $(INSTALLFLAGS) -m 644 $(srcdir)/$$i $(DESTDIR)$(sysconfdir)/$$i; \ else \ echo "PRESERVING EXISTING CONFIGURATION FILE $(sysconfdir)/$$i" ; \ fi; \ $(INSTALL) $(INSTALLFLAGS) -m 644 $(srcdir)/$$i $(DESTDIR)$(sysconfdir)/$$i.default; \ done openldap-2.5.11+dfsg/libraries/libldap/references.c0000644000175000017500000000534414172327167020715 0ustar ryanryan/* references.c */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" LDAPMessage * ldap_first_reference( LDAP *ld, LDAPMessage *chain ) { assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( chain != NULL ); return chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ? chain : ldap_next_reference( ld, chain ); } LDAPMessage * ldap_next_reference( LDAP *ld, LDAPMessage *ref ) { assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( ref != NULL ); for ( ref = ref->lm_chain; ref != NULL; ref = ref->lm_chain ) { if( ref->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ) { return( ref ); } } return( NULL ); } int ldap_count_references( LDAP *ld, LDAPMessage *chain ) { int i; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); for ( i = 0; chain != NULL; chain = chain->lm_chain ) { if( chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ) { i++; } } return( i ); } int ldap_parse_reference( LDAP *ld, LDAPMessage *ref, char ***referralsp, LDAPControl ***serverctrls, int freeit) { BerElement be; char **refs = NULL; int rc; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( ref != NULL ); if( ref->lm_msgtype != LDAP_RES_SEARCH_REFERENCE ) { return LDAP_PARAM_ERROR; } /* make a private copy of BerElement */ AC_MEMCPY(&be, ref->lm_ber, sizeof(be)); if ( ber_scanf( &be, "{v" /*}*/, &refs ) == LBER_ERROR ) { rc = LDAP_DECODING_ERROR; goto free_and_return; } if ( serverctrls == NULL ) { rc = LDAP_SUCCESS; goto free_and_return; } if ( ber_scanf( &be, /*{*/ "}" ) == LBER_ERROR ) { rc = LDAP_DECODING_ERROR; goto free_and_return; } rc = ldap_pvt_get_controls( &be, serverctrls ); free_and_return: if( referralsp != NULL ) { /* provide references regardless of return code */ *referralsp = refs; } else { LDAP_VFREE( refs ); } if( freeit ) { ldap_msgfree( ref ); } if( rc != LDAP_SUCCESS ) { ld->ld_errno = rc; if( ld->ld_matched != NULL ) { LDAP_FREE( ld->ld_matched ); ld->ld_matched = NULL; } if( ld->ld_error != NULL ) { LDAP_FREE( ld->ld_error ); ld->ld_error = NULL; } } return rc; } openldap-2.5.11+dfsg/libraries/libldap/cyrus.c0000644000175000017500000007263614172327167017751 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include "ldap-int.h" #ifdef HAVE_CYRUS_SASL #include #include #include #include #include #include #include #include #ifdef HAVE_LIMITS_H #include #endif #ifndef INT_MAX #define INT_MAX 2147483647 /* 32 bit signed max */ #endif #if !defined(HOST_NAME_MAX) && defined(_POSIX_HOST_NAME_MAX) #define HOST_NAME_MAX _POSIX_HOST_NAME_MAX #endif #ifdef HAVE_SASL_SASL_H #include #else #include #endif #if SASL_VERSION_MAJOR >= 2 #define SASL_CONST const #else #define SASL_CONST #endif /* * Various Cyrus SASL related stuff. */ static const sasl_callback_t client_callbacks[] = { #ifdef SASL_CB_GETREALM { SASL_CB_GETREALM, NULL, NULL }, #endif { SASL_CB_USER, NULL, NULL }, { SASL_CB_AUTHNAME, NULL, NULL }, { SASL_CB_PASS, NULL, NULL }, { SASL_CB_ECHOPROMPT, NULL, NULL }, { SASL_CB_NOECHOPROMPT, NULL, NULL }, { SASL_CB_LIST_END, NULL, NULL } }; /* * ldap_int_initialize is responsible for calling this only once. */ int ldap_int_sasl_init( void ) { #ifdef HAVE_SASL_VERSION /* stringify the version number, sasl.h doesn't do it for us */ #define VSTR0(maj, min, pat) #maj "." #min "." #pat #define VSTR(maj, min, pat) VSTR0(maj, min, pat) #define SASL_VERSION_STRING VSTR(SASL_VERSION_MAJOR, SASL_VERSION_MINOR, \ SASL_VERSION_STEP) { int rc; sasl_version( NULL, &rc ); if ( ((rc >> 16) != ((SASL_VERSION_MAJOR << 8)|SASL_VERSION_MINOR)) || (rc & 0xffff) < SASL_VERSION_STEP) { char version[sizeof("xxx.xxx.xxxxx")]; sprintf( version, "%u.%d.%d", (unsigned)rc >> 24, (rc >> 16) & 0xff, rc & 0xffff ); Debug1( LDAP_DEBUG_ANY, "ldap_int_sasl_init: SASL library version mismatch:" " expected " SASL_VERSION_STRING "," " got %s\n", version ); return -1; } } #endif /* SASL 2 takes care of its own memory completely internally */ #if SASL_VERSION_MAJOR < 2 && !defined(CSRIMALLOC) sasl_set_alloc( ber_memalloc, ber_memcalloc, ber_memrealloc, ber_memfree ); #endif /* CSRIMALLOC */ #ifdef LDAP_R_COMPILE sasl_set_mutex( ldap_pvt_sasl_mutex_new, ldap_pvt_sasl_mutex_lock, ldap_pvt_sasl_mutex_unlock, ldap_pvt_sasl_mutex_dispose ); #endif if ( sasl_client_init( NULL ) == SASL_OK ) { return 0; } #if SASL_VERSION_MAJOR < 2 /* A no-op to make sure we link with Cyrus 1.5 */ sasl_client_auth( NULL, NULL, NULL, 0, NULL, NULL ); #endif return -1; } static void sb_sasl_cyrus_init( struct sb_sasl_generic_data *p, ber_len_t *min_send, ber_len_t *max_send, ber_len_t *max_recv) { sasl_conn_t *sasl_context = (sasl_conn_t *)p->ops_private; ber_len_t maxbuf; sasl_getprop( sasl_context, SASL_MAXOUTBUF, (SASL_CONST void **)(char *) &maxbuf ); *min_send = SASL_MIN_BUFF_SIZE; *max_send = maxbuf; *max_recv = SASL_MAX_BUFF_SIZE; } static ber_int_t sb_sasl_cyrus_encode( struct sb_sasl_generic_data *p, unsigned char *buf, ber_len_t len, Sockbuf_Buf *dst) { sasl_conn_t *sasl_context = (sasl_conn_t *)p->ops_private; ber_int_t ret; unsigned tmpsize = dst->buf_size; ret = sasl_encode( sasl_context, (char *)buf, len, (SASL_CONST char **)&dst->buf_base, &tmpsize ); dst->buf_size = tmpsize; dst->buf_end = dst->buf_size; if ( ret != SASL_OK ) { ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, "sb_sasl_cyrus_encode: failed to encode packet: %s\n", sasl_errstring( ret, NULL, NULL ) ); return -1; } return 0; } static ber_int_t sb_sasl_cyrus_decode( struct sb_sasl_generic_data *p, const Sockbuf_Buf *src, Sockbuf_Buf *dst) { sasl_conn_t *sasl_context = (sasl_conn_t *)p->ops_private; ber_int_t ret; unsigned tmpsize = dst->buf_size; ret = sasl_decode( sasl_context, src->buf_base, src->buf_end, (SASL_CONST char **)&dst->buf_base, (unsigned *)&tmpsize ); dst->buf_size = tmpsize; dst->buf_end = dst->buf_size; if ( ret != SASL_OK ) { ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, "sb_sasl_cyrus_decode: failed to decode packet: %s\n", sasl_errstring( ret, NULL, NULL ) ); return -1; } return 0; } static void sb_sasl_cyrus_reset_buf( struct sb_sasl_generic_data *p, Sockbuf_Buf *buf) { #if SASL_VERSION_MAJOR >= 2 ber_pvt_sb_buf_init( buf ); #else ber_pvt_sb_buf_destroy( buf ); #endif } static void sb_sasl_cyrus_fini( struct sb_sasl_generic_data *p) { #if SASL_VERSION_MAJOR >= 2 /* * SASLv2 encode/decode buffers are managed by * libsasl2. Ensure they are not freed by liblber. */ p->buf_in.buf_base = NULL; p->buf_out.buf_base = NULL; #endif } static const struct sb_sasl_generic_ops sb_sasl_cyrus_ops = { sb_sasl_cyrus_init, sb_sasl_cyrus_encode, sb_sasl_cyrus_decode, sb_sasl_cyrus_reset_buf, sb_sasl_cyrus_fini }; int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg ) { struct sb_sasl_generic_install install_arg; install_arg.ops = &sb_sasl_cyrus_ops; install_arg.ops_private = ctx_arg; return ldap_pvt_sasl_generic_install( sb, &install_arg ); } void ldap_pvt_sasl_remove( Sockbuf *sb ) { ldap_pvt_sasl_generic_remove( sb ); } static int sasl_err2ldap( int saslerr ) { int rc; /* map SASL errors to LDAP API errors returned by: * sasl_client_new() * SASL_OK, SASL_NOMECH, SASL_NOMEM * sasl_client_start() * SASL_OK, SASL_NOMECH, SASL_NOMEM, SASL_INTERACT * sasl_client_step() * SASL_OK, SASL_INTERACT, SASL_BADPROT, SASL_BADSERV */ switch (saslerr) { case SASL_CONTINUE: rc = LDAP_MORE_RESULTS_TO_RETURN; break; case SASL_INTERACT: rc = LDAP_LOCAL_ERROR; break; case SASL_OK: rc = LDAP_SUCCESS; break; case SASL_NOMEM: rc = LDAP_NO_MEMORY; break; case SASL_NOMECH: rc = LDAP_AUTH_UNKNOWN; break; case SASL_BADPROT: rc = LDAP_DECODING_ERROR; break; case SASL_BADSERV: rc = LDAP_AUTH_UNKNOWN; break; /* other codes */ case SASL_BADAUTH: rc = LDAP_AUTH_UNKNOWN; break; case SASL_NOAUTHZ: rc = LDAP_PARAM_ERROR; break; case SASL_FAIL: rc = LDAP_LOCAL_ERROR; break; case SASL_TOOWEAK: case SASL_ENCRYPT: rc = LDAP_AUTH_UNKNOWN; break; default: rc = LDAP_LOCAL_ERROR; break; } assert( rc == LDAP_SUCCESS || LDAP_API_ERROR( rc ) ); return rc; } int ldap_int_sasl_open( LDAP *ld, LDAPConn *lc, const char * host ) { int rc; sasl_conn_t *ctx; assert( lc->lconn_sasl_authctx == NULL ); if ( host == NULL ) { ld->ld_errno = LDAP_LOCAL_ERROR; return ld->ld_errno; } #if SASL_VERSION_MAJOR >= 2 rc = sasl_client_new( "ldap", host, NULL, NULL, client_callbacks, 0, &ctx ); #else rc = sasl_client_new( "ldap", host, client_callbacks, SASL_SECURITY_LAYER, &ctx ); #endif if ( rc != SASL_OK ) { ld->ld_errno = sasl_err2ldap( rc ); return ld->ld_errno; } Debug1( LDAP_DEBUG_TRACE, "ldap_int_sasl_open: host=%s\n", host ); lc->lconn_sasl_authctx = ctx; return LDAP_SUCCESS; } int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc ) { sasl_conn_t *ctx = lc->lconn_sasl_authctx; if( ctx != NULL ) { sasl_dispose( &ctx ); if ( lc->lconn_sasl_sockctx && lc->lconn_sasl_authctx != lc->lconn_sasl_sockctx ) { ctx = lc->lconn_sasl_sockctx; sasl_dispose( &ctx ); } lc->lconn_sasl_sockctx = NULL; lc->lconn_sasl_authctx = NULL; } if( lc->lconn_sasl_cbind ) { ldap_memfree( lc->lconn_sasl_cbind ); lc->lconn_sasl_cbind = NULL; } return LDAP_SUCCESS; } int ldap_pvt_sasl_cbinding_parse( const char *arg ) { int i = -1; if ( strcasecmp(arg, "none") == 0 ) i = LDAP_OPT_X_SASL_CBINDING_NONE; else if ( strcasecmp(arg, "tls-unique") == 0 ) i = LDAP_OPT_X_SASL_CBINDING_TLS_UNIQUE; else if ( strcasecmp(arg, "tls-endpoint") == 0 ) i = LDAP_OPT_X_SASL_CBINDING_TLS_ENDPOINT; return i; } void *ldap_pvt_sasl_cbinding( void *ssl, int type, int is_server ) { #if defined(SASL_CHANNEL_BINDING) && defined(HAVE_TLS) char unique_prefix[] = "tls-unique:"; char endpoint_prefix[] = "tls-server-end-point:"; char cbinding[ 64 ]; struct berval cbv = { 64, cbinding }; void *cb_data; /* used since cb->data is const* */ sasl_channel_binding_t *cb; char *prefix; int plen; switch (type) { case LDAP_OPT_X_SASL_CBINDING_NONE: return NULL; case LDAP_OPT_X_SASL_CBINDING_TLS_UNIQUE: if ( !ldap_pvt_tls_get_unique( ssl, &cbv, is_server )) return NULL; prefix = unique_prefix; plen = sizeof(unique_prefix) -1; break; case LDAP_OPT_X_SASL_CBINDING_TLS_ENDPOINT: if ( !ldap_pvt_tls_get_endpoint( ssl, &cbv, is_server )) return NULL; prefix = endpoint_prefix; plen = sizeof(endpoint_prefix) -1; break; default: return NULL; } cb = ldap_memalloc( sizeof(*cb) + plen + cbv.bv_len ); cb->len = plen + cbv.bv_len; cb->data = cb_data = cb+1; memcpy( cb_data, prefix, plen ); memcpy( cb_data + plen, cbv.bv_val, cbv.bv_len ); cb->name = "ldap"; cb->critical = 0; return cb; #else return NULL; #endif } int ldap_int_sasl_bind( LDAP *ld, const char *dn, const char *mechs, LDAPControl **sctrls, LDAPControl **cctrls, unsigned flags, LDAP_SASL_INTERACT_PROC *interact, void *defaults, LDAPMessage *result, const char **rmech, int *msgid ) { const char *mech; sasl_ssf_t *ssf; sasl_conn_t *ctx; sasl_interact_t *prompts = NULL; struct berval ccred = BER_BVNULL; int saslrc, rc; unsigned credlen; #if !defined(_WIN32) char my_hostname[HOST_NAME_MAX + 1]; #endif int free_saslhost = 0; Debug1( LDAP_DEBUG_TRACE, "ldap_int_sasl_bind: %s\n", mechs ? mechs : "" ); /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */ if (ld->ld_version < LDAP_VERSION3) { ld->ld_errno = LDAP_NOT_SUPPORTED; return ld->ld_errno; } /* Starting a Bind */ if ( !result ) { const char *pmech = NULL; sasl_conn_t *oldctx; ber_socket_t sd; void *ssl; rc = 0; LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd ); if ( sd == AC_SOCKET_INVALID || !ld->ld_defconn ) { /* not connected yet */ rc = ldap_open_defconn( ld ); if ( rc == 0 ) { ber_sockbuf_ctrl( ld->ld_defconn->lconn_sb, LBER_SB_OPT_GET_FD, &sd ); if( sd == AC_SOCKET_INVALID ) { ld->ld_errno = LDAP_LOCAL_ERROR; rc = ld->ld_errno; } } } if ( rc == 0 && ld->ld_defconn && ld->ld_defconn->lconn_status == LDAP_CONNST_CONNECTING ) { rc = ldap_int_check_async_open( ld, sd ); } LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); if( rc != 0 ) return ld->ld_errno; oldctx = ld->ld_defconn->lconn_sasl_authctx; /* If we already have an authentication context, clear it out */ if( oldctx ) { if ( oldctx != ld->ld_defconn->lconn_sasl_sockctx ) { sasl_dispose( &oldctx ); } ld->ld_defconn->lconn_sasl_authctx = NULL; } { char *saslhost; int nocanon = (int)LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_SASL_NOCANON ); /* If we don't need to canonicalize just use the host * from the LDAP URI. * Always use the result of gethostname() for LDAPI. * Skip for Windows which doesn't support LDAPI. */ #if !defined(_WIN32) if (ld->ld_defconn->lconn_server->lud_scheme != NULL && strcmp("ldapi", ld->ld_defconn->lconn_server->lud_scheme) == 0) { rc = gethostname(my_hostname, HOST_NAME_MAX + 1); if (rc == 0) { saslhost = my_hostname; } else { saslhost = "localhost"; } } else #endif if ( nocanon ) saslhost = ld->ld_defconn->lconn_server->lud_host; else { saslhost = ldap_host_connected_to( ld->ld_defconn->lconn_sb, "localhost" ); free_saslhost = 1; } rc = ldap_int_sasl_open( ld, ld->ld_defconn, saslhost ); if ( free_saslhost ) LDAP_FREE( saslhost ); } if ( rc != LDAP_SUCCESS ) return rc; ctx = ld->ld_defconn->lconn_sasl_authctx; #ifdef HAVE_TLS /* Check for TLS */ ssl = ldap_pvt_tls_sb_ctx( ld->ld_defconn->lconn_sb ); if ( ssl ) { struct berval authid = BER_BVNULL; ber_len_t fac; fac = ldap_pvt_tls_get_strength( ssl ); /* failure is OK, we just can't use SASL EXTERNAL */ (void) ldap_pvt_tls_get_my_dn( ssl, &authid, NULL, 0 ); (void) ldap_int_sasl_external( ld, ld->ld_defconn, authid.bv_val, fac ); LDAP_FREE( authid.bv_val ); #ifdef SASL_CHANNEL_BINDING /* 2.1.25+ */ if ( ld->ld_defconn->lconn_sasl_cbind == NULL ) { void *cb; cb = ldap_pvt_sasl_cbinding( ssl, ld->ld_options.ldo_sasl_cbinding, 0 ); if ( cb != NULL ) { sasl_setprop( ld->ld_defconn->lconn_sasl_authctx, SASL_CHANNEL_BINDING, cb ); ld->ld_defconn->lconn_sasl_cbind = cb; } } #endif } #endif #if !defined(_WIN32) /* Check for local */ if ( ldap_pvt_url_scheme2proto( ld->ld_defconn->lconn_server->lud_scheme ) == LDAP_PROTO_IPC ) { char authid[sizeof("gidNumber=4294967295+uidNumber=4294967295," "cn=peercred,cn=external,cn=auth")]; sprintf( authid, "gidNumber=%u+uidNumber=%u," "cn=peercred,cn=external,cn=auth", getegid(), geteuid() ); (void) ldap_int_sasl_external( ld, ld->ld_defconn, authid, LDAP_PVT_SASL_LOCAL_SSF ); } #endif /* (re)set security properties */ sasl_setprop( ctx, SASL_SEC_PROPS, &ld->ld_options.ldo_sasl_secprops ); mech = NULL; do { saslrc = sasl_client_start( ctx, mechs, #if SASL_VERSION_MAJOR < 2 NULL, #endif &prompts, (SASL_CONST char **)&ccred.bv_val, &credlen, &mech ); if( pmech == NULL && mech != NULL ) { pmech = mech; *rmech = mech; if( flags != LDAP_SASL_QUIET ) { fprintf(stderr, "SASL/%s authentication started\n", pmech ); } } if( saslrc == SASL_INTERACT ) { int res; if( !interact ) break; res = (interact)( ld, flags, defaults, prompts ); if( res != LDAP_SUCCESS ) break; } } while ( saslrc == SASL_INTERACT ); rc = LDAP_SASL_BIND_IN_PROGRESS; } else { /* continuing an in-progress Bind */ struct berval *scred = NULL; ctx = ld->ld_defconn->lconn_sasl_authctx; rc = ldap_parse_sasl_bind_result( ld, result, &scred, 0 ); if ( rc != LDAP_SUCCESS ) { if ( scred ) ber_bvfree( scred ); goto done; } rc = ldap_result2error( ld, result, 0 ); if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) { if( scred ) { /* and server provided us with data? */ Debug2( LDAP_DEBUG_TRACE, "ldap_int_sasl_bind: rc=%d len=%ld\n", rc, scred ? (long) scred->bv_len : -1L ); ber_bvfree( scred ); scred = NULL; } goto done; } mech = *rmech; if ( rc == LDAP_SUCCESS && mech == NULL ) { if ( scred ) ber_bvfree( scred ); goto success; } do { if( ! scred ) { /* no data! */ Debug0( LDAP_DEBUG_TRACE, "ldap_int_sasl_bind: no data in step!\n" ); } saslrc = sasl_client_step( ctx, (scred == NULL) ? NULL : scred->bv_val, (scred == NULL) ? 0 : scred->bv_len, &prompts, (SASL_CONST char **)&ccred.bv_val, &credlen ); Debug1( LDAP_DEBUG_TRACE, "sasl_client_step: %d\n", saslrc ); if( saslrc == SASL_INTERACT ) { int res; if( !interact ) break; res = (interact)( ld, flags, defaults, prompts ); if( res != LDAP_SUCCESS ) break; } } while ( saslrc == SASL_INTERACT ); ber_bvfree( scred ); } if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) { rc = ld->ld_errno = sasl_err2ldap( saslrc ); #if SASL_VERSION_MAJOR >= 2 if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } ld->ld_error = LDAP_STRDUP( sasl_errdetail( ctx ) ); #endif goto done; } if ( saslrc == SASL_OK ) *rmech = NULL; ccred.bv_len = credlen; if ( rc == LDAP_SASL_BIND_IN_PROGRESS ) { rc = ldap_sasl_bind( ld, dn, mech, &ccred, sctrls, cctrls, msgid ); if ( ccred.bv_val != NULL ) { #if SASL_VERSION_MAJOR < 2 LDAP_FREE( ccred.bv_val ); #endif ccred.bv_val = NULL; } if ( rc == LDAP_SUCCESS ) rc = LDAP_SASL_BIND_IN_PROGRESS; goto done; } success: /* Conversation was completed successfully by now */ if( flags != LDAP_SASL_QUIET ) { char *data; saslrc = sasl_getprop( ctx, SASL_USERNAME, (SASL_CONST void **)(char *) &data ); if( saslrc == SASL_OK && data && *data ) { fprintf( stderr, "SASL username: %s\n", data ); } #if SASL_VERSION_MAJOR < 2 saslrc = sasl_getprop( ctx, SASL_REALM, (SASL_CONST void **) &data ); if( saslrc == SASL_OK && data && *data ) { fprintf( stderr, "SASL realm: %s\n", data ); } #endif } ssf = NULL; saslrc = sasl_getprop( ctx, SASL_SSF, (SASL_CONST void **)(char *) &ssf ); if( saslrc == SASL_OK ) { if( flags != LDAP_SASL_QUIET ) { fprintf( stderr, "SASL SSF: %lu\n", (unsigned long) *ssf ); } if( ssf && *ssf ) { if ( ld->ld_defconn->lconn_sasl_sockctx ) { sasl_conn_t *oldctx = ld->ld_defconn->lconn_sasl_sockctx; sasl_dispose( &oldctx ); ldap_pvt_sasl_remove( ld->ld_defconn->lconn_sb ); } ldap_pvt_sasl_install( ld->ld_defconn->lconn_sb, ctx ); ld->ld_defconn->lconn_sasl_sockctx = ctx; if( flags != LDAP_SASL_QUIET ) { fprintf( stderr, "SASL data security layer installed.\n" ); } } } ld->ld_defconn->lconn_sasl_authctx = ctx; done: return rc; } int ldap_int_sasl_external( LDAP *ld, LDAPConn *conn, const char * authid, ber_len_t ssf ) { int sc; sasl_conn_t *ctx; #if SASL_VERSION_MAJOR < 2 sasl_external_properties_t extprops; #else sasl_ssf_t sasl_ssf = ssf; #endif ctx = conn->lconn_sasl_authctx; if ( ctx == NULL ) { return LDAP_LOCAL_ERROR; } #if SASL_VERSION_MAJOR >= 2 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, &sasl_ssf ); if ( sc == SASL_OK ) sc = sasl_setprop( ctx, SASL_AUTH_EXTERNAL, authid ); #else memset( &extprops, '\0', sizeof(extprops) ); extprops.ssf = ssf; extprops.auth_id = (char *) authid; sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, (void *) &extprops ); #endif if ( sc != SASL_OK ) { return LDAP_LOCAL_ERROR; } return LDAP_SUCCESS; } #define GOT_MINSSF 1 #define GOT_MAXSSF 2 #define GOT_MAXBUF 4 static struct { struct berval key; int sflag; int ival; int idef; } sprops[] = { { BER_BVC("none"), 0, 0, 0 }, { BER_BVC("nodict"), SASL_SEC_NODICTIONARY, 0, 0 }, { BER_BVC("noplain"), SASL_SEC_NOPLAINTEXT, 0, 0 }, { BER_BVC("noactive"), SASL_SEC_NOACTIVE, 0, 0 }, { BER_BVC("passcred"), SASL_SEC_PASS_CREDENTIALS, 0, 0 }, { BER_BVC("forwardsec"), SASL_SEC_FORWARD_SECRECY, 0, 0 }, { BER_BVC("noanonymous"), SASL_SEC_NOANONYMOUS, 0, 0 }, { BER_BVC("minssf="), 0, GOT_MINSSF, 0 }, { BER_BVC("maxssf="), 0, GOT_MAXSSF, INT_MAX }, { BER_BVC("maxbufsize="), 0, GOT_MAXBUF, 65536 }, { BER_BVNULL, 0, 0, 0 } }; void ldap_pvt_sasl_secprops_unparse( sasl_security_properties_t *secprops, struct berval *out ) { int i, l = 0; int comma; char *ptr; if ( secprops == NULL || out == NULL ) { return; } comma = 0; for ( i=0; !BER_BVISNULL( &sprops[i].key ); i++ ) { if ( sprops[i].ival ) { int v = 0; switch( sprops[i].ival ) { case GOT_MINSSF: v = secprops->min_ssf; break; case GOT_MAXSSF: v = secprops->max_ssf; break; case GOT_MAXBUF: v = secprops->maxbufsize; break; } /* It is the default, ignore it */ if ( v == sprops[i].idef ) continue; l += sprops[i].key.bv_len + 24; } else if ( sprops[i].sflag ) { if ( sprops[i].sflag & secprops->security_flags ) { l += sprops[i].key.bv_len; } } else if ( secprops->security_flags == 0 ) { l += sprops[i].key.bv_len; } if ( comma ) l++; comma = 1; } l++; out->bv_val = LDAP_MALLOC( l ); if ( out->bv_val == NULL ) { out->bv_len = 0; return; } ptr = out->bv_val; comma = 0; for ( i=0; !BER_BVISNULL( &sprops[i].key ); i++ ) { if ( sprops[i].ival ) { int v = 0; switch( sprops[i].ival ) { case GOT_MINSSF: v = secprops->min_ssf; break; case GOT_MAXSSF: v = secprops->max_ssf; break; case GOT_MAXBUF: v = secprops->maxbufsize; break; } /* It is the default, ignore it */ if ( v == sprops[i].idef ) continue; if ( comma ) *ptr++ = ','; ptr += sprintf(ptr, "%s%d", sprops[i].key.bv_val, v ); comma = 1; } else if ( sprops[i].sflag ) { if ( sprops[i].sflag & secprops->security_flags ) { if ( comma ) *ptr++ = ','; ptr += sprintf(ptr, "%s", sprops[i].key.bv_val ); comma = 1; } } else if ( secprops->security_flags == 0 ) { if ( comma ) *ptr++ = ','; ptr += sprintf(ptr, "%s", sprops[i].key.bv_val ); comma = 1; } } out->bv_len = ptr - out->bv_val; } int ldap_pvt_sasl_secprops( const char *in, sasl_security_properties_t *secprops ) { unsigned i, j, l; char **props; unsigned sflags = 0; int got_sflags = 0; sasl_ssf_t max_ssf = 0; int got_max_ssf = 0; sasl_ssf_t min_ssf = 0; int got_min_ssf = 0; unsigned maxbufsize = 0; int got_maxbufsize = 0; if( secprops == NULL ) { return LDAP_PARAM_ERROR; } props = ldap_str2charray( in, "," ); if( props == NULL ) { return LDAP_PARAM_ERROR; } for( i=0; props[i]; i++ ) { l = strlen( props[i] ); for ( j=0; !BER_BVISNULL( &sprops[j].key ); j++ ) { if ( l < sprops[j].key.bv_len ) continue; if ( strncasecmp( props[i], sprops[j].key.bv_val, sprops[j].key.bv_len )) continue; if ( sprops[j].ival ) { unsigned v; char *next = NULL; if ( !isdigit( (unsigned char)props[i][sprops[j].key.bv_len] )) continue; v = strtoul( &props[i][sprops[j].key.bv_len], &next, 10 ); if ( next == &props[i][sprops[j].key.bv_len] || next[0] != '\0' ) continue; switch( sprops[j].ival ) { case GOT_MINSSF: min_ssf = v; got_min_ssf++; break; case GOT_MAXSSF: max_ssf = v; got_max_ssf++; break; case GOT_MAXBUF: maxbufsize = v; got_maxbufsize++; break; } } else { if ( props[i][sprops[j].key.bv_len] ) continue; if ( sprops[j].sflag ) sflags |= sprops[j].sflag; else sflags = 0; got_sflags++; } break; } if ( BER_BVISNULL( &sprops[j].key )) { ldap_charray_free( props ); return LDAP_NOT_SUPPORTED; } } if(got_sflags) { secprops->security_flags = sflags; } if(got_min_ssf) { secprops->min_ssf = min_ssf; } if(got_max_ssf) { secprops->max_ssf = max_ssf; } if(got_maxbufsize) { secprops->maxbufsize = maxbufsize; } ldap_charray_free( props ); return LDAP_SUCCESS; } int ldap_int_sasl_config( struct ldapoptions *lo, int option, const char *arg ) { int rc, i; switch( option ) { case LDAP_OPT_X_SASL_SECPROPS: rc = ldap_pvt_sasl_secprops( arg, &lo->ldo_sasl_secprops ); if( rc == LDAP_SUCCESS ) return 0; break; case LDAP_OPT_X_SASL_CBINDING: i = ldap_pvt_sasl_cbinding_parse( arg ); if ( i >= 0 ) { lo->ldo_sasl_cbinding = i; return 0; } break; } return -1; } int ldap_int_sasl_get_option( LDAP *ld, int option, void *arg ) { if ( option == LDAP_OPT_X_SASL_MECHLIST ) { *(char ***)arg = (char **)sasl_global_listmech(); return 0; } if ( ld == NULL ) return -1; switch ( option ) { case LDAP_OPT_X_SASL_MECH: { *(char **)arg = ld->ld_options.ldo_def_sasl_mech ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_mech ) : NULL; } break; case LDAP_OPT_X_SASL_REALM: { *(char **)arg = ld->ld_options.ldo_def_sasl_realm ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_realm ) : NULL; } break; case LDAP_OPT_X_SASL_AUTHCID: { *(char **)arg = ld->ld_options.ldo_def_sasl_authcid ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authcid ) : NULL; } break; case LDAP_OPT_X_SASL_AUTHZID: { *(char **)arg = ld->ld_options.ldo_def_sasl_authzid ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authzid ) : NULL; } break; case LDAP_OPT_X_SASL_SSF: { int sc; sasl_ssf_t *ssf; sasl_conn_t *ctx; if( ld->ld_defconn == NULL ) { return -1; } ctx = ld->ld_defconn->lconn_sasl_sockctx; if ( ctx == NULL ) { return -1; } sc = sasl_getprop( ctx, SASL_SSF, (SASL_CONST void **)(char *) &ssf ); if ( sc != SASL_OK ) { return -1; } *(ber_len_t *)arg = *ssf; } break; case LDAP_OPT_X_SASL_SSF_EXTERNAL: /* this option is write only */ return -1; case LDAP_OPT_X_SASL_SSF_MIN: *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.min_ssf; break; case LDAP_OPT_X_SASL_SSF_MAX: *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.max_ssf; break; case LDAP_OPT_X_SASL_MAXBUFSIZE: *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.maxbufsize; break; case LDAP_OPT_X_SASL_NOCANON: *(int *)arg = (int) LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_SASL_NOCANON ); break; case LDAP_OPT_X_SASL_USERNAME: { int sc; char *username; sasl_conn_t *ctx; if( ld->ld_defconn == NULL ) { return -1; } ctx = ld->ld_defconn->lconn_sasl_authctx; if ( ctx == NULL ) { return -1; } sc = sasl_getprop( ctx, SASL_USERNAME, (SASL_CONST void **)(char **) &username ); if ( sc != SASL_OK ) { return -1; } *(char **)arg = username ? LDAP_STRDUP( username ) : NULL; } break; case LDAP_OPT_X_SASL_SECPROPS: /* this option is write only */ return -1; case LDAP_OPT_X_SASL_CBINDING: *(int *)arg = ld->ld_options.ldo_sasl_cbinding; break; #ifdef SASL_GSS_CREDS case LDAP_OPT_X_SASL_GSS_CREDS: { sasl_conn_t *ctx; int sc; if ( ld->ld_defconn == NULL ) return -1; ctx = ld->ld_defconn->lconn_sasl_authctx; if ( ctx == NULL ) return -1; sc = sasl_getprop( ctx, SASL_GSS_CREDS, arg ); if ( sc != SASL_OK ) return -1; } break; #endif default: return -1; } return 0; } int ldap_int_sasl_set_option( LDAP *ld, int option, void *arg ) { if ( ld == NULL ) return -1; if ( arg == NULL && option != LDAP_OPT_X_SASL_NOCANON ) return -1; switch ( option ) { case LDAP_OPT_X_SASL_SSF: case LDAP_OPT_X_SASL_USERNAME: /* This option is read-only */ return -1; case LDAP_OPT_X_SASL_SSF_EXTERNAL: { int sc; #if SASL_VERSION_MAJOR < 2 sasl_external_properties_t extprops; #else sasl_ssf_t sasl_ssf; #endif sasl_conn_t *ctx; if( ld->ld_defconn == NULL ) { return -1; } ctx = ld->ld_defconn->lconn_sasl_authctx; if ( ctx == NULL ) { return -1; } #if SASL_VERSION_MAJOR >= 2 sasl_ssf = * (ber_len_t *)arg; sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, &sasl_ssf); #else memset(&extprops, 0L, sizeof(extprops)); extprops.ssf = * (ber_len_t *) arg; sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, (void *) &extprops ); #endif if ( sc != SASL_OK ) { return -1; } } break; case LDAP_OPT_X_SASL_SSF_MIN: ld->ld_options.ldo_sasl_secprops.min_ssf = *(ber_len_t *)arg; break; case LDAP_OPT_X_SASL_SSF_MAX: ld->ld_options.ldo_sasl_secprops.max_ssf = *(ber_len_t *)arg; break; case LDAP_OPT_X_SASL_MAXBUFSIZE: ld->ld_options.ldo_sasl_secprops.maxbufsize = *(ber_len_t *)arg; break; case LDAP_OPT_X_SASL_NOCANON: if ( arg == LDAP_OPT_OFF ) { LDAP_BOOL_CLR(&ld->ld_options, LDAP_BOOL_SASL_NOCANON ); } else { LDAP_BOOL_SET(&ld->ld_options, LDAP_BOOL_SASL_NOCANON ); } break; case LDAP_OPT_X_SASL_SECPROPS: { int sc; sc = ldap_pvt_sasl_secprops( (char *) arg, &ld->ld_options.ldo_sasl_secprops ); return sc == LDAP_SUCCESS ? 0 : -1; } case LDAP_OPT_X_SASL_CBINDING: if ( !arg ) return -1; switch( *(int *) arg ) { case LDAP_OPT_X_SASL_CBINDING_NONE: case LDAP_OPT_X_SASL_CBINDING_TLS_UNIQUE: case LDAP_OPT_X_SASL_CBINDING_TLS_ENDPOINT: ld->ld_options.ldo_sasl_cbinding = *(int *) arg; return 0; } return -1; #ifdef SASL_GSS_CREDS case LDAP_OPT_X_SASL_GSS_CREDS: { sasl_conn_t *ctx; int sc; if ( ld->ld_defconn == NULL ) return -1; ctx = ld->ld_defconn->lconn_sasl_authctx; if ( ctx == NULL ) return -1; sc = sasl_setprop( ctx, SASL_GSS_CREDS, arg ); if ( sc != SASL_OK ) return -1; } break; #endif default: return -1; } return 0; } #ifdef LDAP_R_COMPILE #define LDAP_DEBUG_R_SASL void *ldap_pvt_sasl_mutex_new(void) { ldap_pvt_thread_mutex_t *mutex; mutex = (ldap_pvt_thread_mutex_t *) LDAP_CALLOC( 1, sizeof(ldap_pvt_thread_mutex_t) ); if ( ldap_pvt_thread_mutex_init( mutex ) == 0 ) { return mutex; } LDAP_FREE( mutex ); #ifndef LDAP_DEBUG_R_SASL assert( 0 ); #endif /* !LDAP_DEBUG_R_SASL */ return NULL; } int ldap_pvt_sasl_mutex_lock(void *mutex) { #ifdef LDAP_DEBUG_R_SASL if ( mutex == NULL ) { return SASL_OK; } #else /* !LDAP_DEBUG_R_SASL */ assert( mutex != NULL ); #endif /* !LDAP_DEBUG_R_SASL */ return ldap_pvt_thread_mutex_lock( (ldap_pvt_thread_mutex_t *)mutex ) ? SASL_FAIL : SASL_OK; } int ldap_pvt_sasl_mutex_unlock(void *mutex) { #ifdef LDAP_DEBUG_R_SASL if ( mutex == NULL ) { return SASL_OK; } #else /* !LDAP_DEBUG_R_SASL */ assert( mutex != NULL ); #endif /* !LDAP_DEBUG_R_SASL */ return ldap_pvt_thread_mutex_unlock( (ldap_pvt_thread_mutex_t *)mutex ) ? SASL_FAIL : SASL_OK; } void ldap_pvt_sasl_mutex_dispose(void *mutex) { #ifdef LDAP_DEBUG_R_SASL if ( mutex == NULL ) { return; } #else /* !LDAP_DEBUG_R_SASL */ assert( mutex != NULL ); #endif /* !LDAP_DEBUG_R_SASL */ (void) ldap_pvt_thread_mutex_destroy( (ldap_pvt_thread_mutex_t *)mutex ); LDAP_FREE( mutex ); } #endif #else int ldap_int_sasl_init( void ) { return LDAP_SUCCESS; } int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc ) { return LDAP_SUCCESS; } int ldap_int_sasl_bind( LDAP *ld, const char *dn, const char *mechs, LDAPControl **sctrls, LDAPControl **cctrls, unsigned flags, LDAP_SASL_INTERACT_PROC *interact, void *defaults, LDAPMessage *result, const char **rmech, int *msgid ) { return LDAP_NOT_SUPPORTED; } int ldap_int_sasl_external( LDAP *ld, LDAPConn *conn, const char * authid, ber_len_t ssf ) { return LDAP_SUCCESS; } #endif /* HAVE_CYRUS_SASL */ openldap-2.5.11+dfsg/libraries/libldap/assertion.c0000644000175000017500000000370714172327167020604 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include "ldap-int.h" int ldap_create_assertion_control_value( LDAP *ld, char *assertion, struct berval *value ) { BerElement *ber = NULL; int err; ld->ld_errno = LDAP_SUCCESS; if ( assertion == NULL || assertion[ 0 ] == '\0' ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; } if ( value == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; } BER_BVZERO( value ); ber = ldap_alloc_ber_with_options( ld ); if ( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } err = ldap_pvt_put_filter( ber, assertion ); if ( err < 0 ) { ld->ld_errno = LDAP_ENCODING_ERROR; goto done; } err = ber_flatten2( ber, value, 1 ); if ( err < 0 ) { ld->ld_errno = LDAP_NO_MEMORY; goto done; } done:; if ( ber != NULL ) { ber_free( ber, 1 ); } return ld->ld_errno; } int ldap_create_assertion_control( LDAP *ld, char *assertion, int iscritical, LDAPControl **ctrlp ) { struct berval value; if ( ctrlp == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; } ld->ld_errno = ldap_create_assertion_control_value( ld, assertion, &value ); if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = ldap_control_create( LDAP_CONTROL_ASSERT, iscritical, &value, 0, ctrlp ); if ( ld->ld_errno != LDAP_SUCCESS ) { LDAP_FREE( value.bv_val ); } } return ld->ld_errno; } openldap-2.5.11+dfsg/libraries/libldap/open.c0000644000175000017500000004052714172327167017537 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. */ #include "portable.h" #include #ifdef HAVE_LIMITS_H #include #endif #include #include #include #include #include #include #include "ldap-int.h" #include "ldap.h" #include "ldap_log.h" /* Caller must hold the conn_mutex since simultaneous accesses are possible */ int ldap_open_defconn( LDAP *ld ) { ld->ld_defconn = ldap_new_connection( ld, &ld->ld_options.ldo_defludp, 1, 1, NULL, 0, 0 ); if( ld->ld_defconn == NULL ) { ld->ld_errno = LDAP_SERVER_DOWN; return -1; } ++ld->ld_defconn->lconn_refcnt; /* so it never gets closed/freed */ return 0; } /* * ldap_connect - Connect to an ldap server. * * Example: * LDAP *ld; * ldap_initialize( &ld, url ); * ldap_connect( ld ); */ int ldap_connect( LDAP *ld ) { ber_socket_t sd = AC_SOCKET_INVALID; int rc = LDAP_SUCCESS; LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd ) == -1 ) { rc = ldap_open_defconn( ld ); } LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); return rc; } /* * ldap_open - initialize and connect to an ldap server. A magic cookie to * be used for future communication is returned on success, NULL on failure. * "host" may be a space-separated list of hosts or IP addresses * * Example: * LDAP *ld; * ld = ldap_open( hostname, port ); */ LDAP * ldap_open( LDAP_CONST char *host, int port ) { int rc; LDAP *ld; Debug2( LDAP_DEBUG_TRACE, "ldap_open(%s, %d)\n", host, port ); ld = ldap_init( host, port ); if ( ld == NULL ) { return( NULL ); } LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); rc = ldap_open_defconn( ld ); LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); if( rc < 0 ) { ldap_ld_free( ld, 0, NULL, NULL ); ld = NULL; } Debug1( LDAP_DEBUG_TRACE, "ldap_open: %s\n", ld != NULL ? "succeeded" : "failed" ); return ld; } int ldap_create( LDAP **ldp ) { LDAP *ld; struct ldapoptions *gopts; *ldp = NULL; /* Get pointer to global option structure */ if ( (gopts = LDAP_INT_GLOBAL_OPT()) == NULL) { return LDAP_NO_MEMORY; } /* Initialize the global options, if not already done. */ if( gopts->ldo_valid != LDAP_INITIALIZED ) { ldap_int_initialize(gopts, NULL); if ( gopts->ldo_valid != LDAP_INITIALIZED ) return LDAP_LOCAL_ERROR; } Debug0( LDAP_DEBUG_TRACE, "ldap_create\n" ); if ( (ld = (LDAP *) LDAP_CALLOC( 1, sizeof(LDAP) )) == NULL ) { return( LDAP_NO_MEMORY ); } if ( (ld->ldc = (struct ldap_common *) LDAP_CALLOC( 1, sizeof(struct ldap_common) )) == NULL ) { LDAP_FREE( (char *)ld ); return( LDAP_NO_MEMORY ); } /* copy the global options */ LDAP_MUTEX_LOCK( &gopts->ldo_mutex ); AC_MEMCPY(&ld->ld_options, gopts, sizeof(ld->ld_options)); #ifdef LDAP_R_COMPILE /* Properly initialize the structs mutex */ ldap_pvt_thread_mutex_init( &(ld->ld_ldopts_mutex) ); #endif #ifdef HAVE_TLS if ( ld->ld_options.ldo_tls_pin_hashalg ) { int len = strlen( gopts->ldo_tls_pin_hashalg ); ld->ld_options.ldo_tls_pin_hashalg = LDAP_MALLOC( len + 1 + gopts->ldo_tls_pin.bv_len ); if ( !ld->ld_options.ldo_tls_pin_hashalg ) goto nomem; ld->ld_options.ldo_tls_pin.bv_val = ld->ld_options.ldo_tls_pin_hashalg + len + 1; AC_MEMCPY( ld->ld_options.ldo_tls_pin_hashalg, gopts->ldo_tls_pin_hashalg, len + 1 + gopts->ldo_tls_pin.bv_len ); } else if ( !BER_BVISEMPTY(&ld->ld_options.ldo_tls_pin) ) { ber_dupbv( &ld->ld_options.ldo_tls_pin, &gopts->ldo_tls_pin ); } #endif LDAP_MUTEX_UNLOCK( &gopts->ldo_mutex ); ld->ld_valid = LDAP_VALID_SESSION; /* but not pointers to malloc'ed items */ ld->ld_options.ldo_sctrls = NULL; ld->ld_options.ldo_cctrls = NULL; ld->ld_options.ldo_defludp = NULL; ld->ld_options.ldo_conn_cbs = NULL; ld->ld_options.ldo_defbase = gopts->ldo_defbase ? LDAP_STRDUP( gopts->ldo_defbase ) : NULL; #ifdef HAVE_CYRUS_SASL ld->ld_options.ldo_def_sasl_mech = gopts->ldo_def_sasl_mech ? LDAP_STRDUP( gopts->ldo_def_sasl_mech ) : NULL; ld->ld_options.ldo_def_sasl_realm = gopts->ldo_def_sasl_realm ? LDAP_STRDUP( gopts->ldo_def_sasl_realm ) : NULL; ld->ld_options.ldo_def_sasl_authcid = gopts->ldo_def_sasl_authcid ? LDAP_STRDUP( gopts->ldo_def_sasl_authcid ) : NULL; ld->ld_options.ldo_def_sasl_authzid = gopts->ldo_def_sasl_authzid ? LDAP_STRDUP( gopts->ldo_def_sasl_authzid ) : NULL; #endif #ifdef HAVE_TLS /* We explicitly inherit the SSL_CTX, don't need the names/paths. Leave * them empty to allow new SSL_CTX's to be created from scratch. */ memset( &ld->ld_options.ldo_tls_info, 0, sizeof( ld->ld_options.ldo_tls_info )); ld->ld_options.ldo_tls_ctx = NULL; #endif if ( gopts->ldo_defludp ) { ld->ld_options.ldo_defludp = ldap_url_duplist(gopts->ldo_defludp); if ( ld->ld_options.ldo_defludp == NULL ) goto nomem; } if (( ld->ld_selectinfo = ldap_new_select_info()) == NULL ) goto nomem; ld->ld_options.ldo_local_ip_addrs.local_ip_addrs = NULL; if( gopts->ldo_local_ip_addrs.local_ip_addrs ) { ld->ld_options.ldo_local_ip_addrs.local_ip_addrs = LDAP_STRDUP( gopts->ldo_local_ip_addrs.local_ip_addrs ); if ( ld->ld_options.ldo_local_ip_addrs.local_ip_addrs == NULL ) goto nomem; } ld->ld_lberoptions = LBER_USE_DER; ld->ld_sb = ber_sockbuf_alloc( ); if ( ld->ld_sb == NULL ) goto nomem; #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_init( &ld->ld_msgid_mutex ); ldap_pvt_thread_mutex_init( &ld->ld_conn_mutex ); ldap_pvt_thread_mutex_init( &ld->ld_req_mutex ); ldap_pvt_thread_mutex_init( &ld->ld_res_mutex ); ldap_pvt_thread_mutex_init( &ld->ld_abandon_mutex ); ldap_pvt_thread_mutex_init( &ld->ld_ldcmutex ); #endif ld->ld_ldcrefcnt = 1; *ldp = ld; return LDAP_SUCCESS; nomem: ldap_free_select_info( ld->ld_selectinfo ); ldap_free_urllist( ld->ld_options.ldo_defludp ); #ifdef HAVE_CYRUS_SASL LDAP_FREE( ld->ld_options.ldo_def_sasl_authzid ); LDAP_FREE( ld->ld_options.ldo_def_sasl_authcid ); LDAP_FREE( ld->ld_options.ldo_def_sasl_realm ); LDAP_FREE( ld->ld_options.ldo_def_sasl_mech ); #endif #ifdef HAVE_TLS /* tls_pin_hashalg and tls_pin share the same buffer */ if ( ld->ld_options.ldo_tls_pin_hashalg ) { LDAP_FREE( ld->ld_options.ldo_tls_pin_hashalg ); } else { LDAP_FREE( ld->ld_options.ldo_tls_pin.bv_val ); } #endif LDAP_FREE( (char *)ld ); return LDAP_NO_MEMORY; } /* * ldap_init - initialize the LDAP library. A magic cookie to be used for * future communication is returned on success, NULL on failure. * "host" may be a space-separated list of hosts or IP addresses * * Example: * LDAP *ld; * ld = ldap_init( host, port ); */ LDAP * ldap_init( LDAP_CONST char *defhost, int defport ) { LDAP *ld; int rc; rc = ldap_create(&ld); if ( rc != LDAP_SUCCESS ) return NULL; if (defport != 0) ld->ld_options.ldo_defport = defport; if (defhost != NULL) { rc = ldap_set_option(ld, LDAP_OPT_HOST_NAME, defhost); if ( rc != LDAP_SUCCESS ) { ldap_ld_free(ld, 1, NULL, NULL); return NULL; } } return( ld ); } int ldap_initialize( LDAP **ldp, LDAP_CONST char *url ) { int rc; LDAP *ld; *ldp = NULL; rc = ldap_create(&ld); if ( rc != LDAP_SUCCESS ) return rc; if (url != NULL) { rc = ldap_set_option(ld, LDAP_OPT_URI, url); if ( rc != LDAP_SUCCESS ) { ldap_ld_free(ld, 1, NULL, NULL); return rc; } #ifdef LDAP_CONNECTIONLESS if (ldap_is_ldapc_url(url)) LDAP_IS_UDP(ld) = 1; #endif } *ldp = ld; return LDAP_SUCCESS; } int ldap_init_fd( ber_socket_t fd, int proto, LDAP_CONST char *url, LDAP **ldp ) { int rc; LDAP *ld; LDAPConn *conn; #ifdef LDAP_CONNECTIONLESS ber_socklen_t len; #endif *ldp = NULL; rc = ldap_create( &ld ); if( rc != LDAP_SUCCESS ) return( rc ); if (url != NULL) { rc = ldap_set_option(ld, LDAP_OPT_URI, url); if ( rc != LDAP_SUCCESS ) { ldap_ld_free(ld, 1, NULL, NULL); return rc; } } LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); /* Attach the passed socket as the LDAP's connection */ conn = ldap_new_connection( ld, NULL, 1, 0, NULL, 0, 0 ); if( conn == NULL ) { LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); ldap_unbind_ext( ld, NULL, NULL ); return( LDAP_NO_MEMORY ); } if( url ) conn->lconn_server = ldap_url_dup( ld->ld_options.ldo_defludp ); ber_sockbuf_ctrl( conn->lconn_sb, LBER_SB_OPT_SET_FD, &fd ); ld->ld_defconn = conn; ++ld->ld_defconn->lconn_refcnt; /* so it never gets closed/freed */ LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); switch( proto ) { case LDAP_PROTO_TCP: #ifdef LDAP_DEBUG ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_PROVIDER, (void *)"tcp_" ); #endif ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_tcp, LBER_SBIOD_LEVEL_PROVIDER, NULL ); break; #ifdef LDAP_CONNECTIONLESS case LDAP_PROTO_UDP: LDAP_IS_UDP(ld) = 1; if( ld->ld_options.ldo_peer ) ldap_memfree( ld->ld_options.ldo_peer ); ld->ld_options.ldo_peer = ldap_memcalloc( 1, sizeof( struct sockaddr_storage ) ); len = sizeof( struct sockaddr_storage ); if( getpeername ( fd, ld->ld_options.ldo_peer, &len ) < 0) { ldap_unbind_ext( ld, NULL, NULL ); return( AC_SOCKET_ERROR ); } #ifdef LDAP_DEBUG ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_PROVIDER, (void *)"udp_" ); #endif ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_udp, LBER_SBIOD_LEVEL_PROVIDER, NULL ); ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_readahead, LBER_SBIOD_LEVEL_PROVIDER, NULL ); break; #endif /* LDAP_CONNECTIONLESS */ case LDAP_PROTO_IPC: #ifdef LDAP_DEBUG ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_PROVIDER, (void *)"ipc_" ); #endif ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_fd, LBER_SBIOD_LEVEL_PROVIDER, NULL ); break; case LDAP_PROTO_EXT: /* caller must supply sockbuf handlers */ break; default: ldap_unbind_ext( ld, NULL, NULL ); return LDAP_PARAM_ERROR; } #ifdef LDAP_DEBUG ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug, INT_MAX, (void *)"ldap_" ); #endif /* Add the connection to the *LDAP's select pool */ ldap_mark_select_read( ld, conn->lconn_sb ); *ldp = ld; return LDAP_SUCCESS; } /* Protected by ld_conn_mutex */ int ldap_int_open_connection( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv, int async ) { int rc = -1; int proto; Debug0( LDAP_DEBUG_TRACE, "ldap_int_open_connection\n" ); switch ( proto = ldap_pvt_url_scheme2proto( srv->lud_scheme ) ) { case LDAP_PROTO_TCP: rc = ldap_connect_to_host( ld, conn->lconn_sb, proto, srv, async ); if ( rc == -1 ) return rc; #ifdef LDAP_DEBUG ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_PROVIDER, (void *)"tcp_" ); #endif ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_tcp, LBER_SBIOD_LEVEL_PROVIDER, NULL ); break; #ifdef LDAP_CONNECTIONLESS case LDAP_PROTO_UDP: LDAP_IS_UDP(ld) = 1; rc = ldap_connect_to_host( ld, conn->lconn_sb, proto, srv, async ); if ( rc == -1 ) return rc; #ifdef LDAP_DEBUG ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_PROVIDER, (void *)"udp_" ); #endif ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_udp, LBER_SBIOD_LEVEL_PROVIDER, NULL ); ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_readahead, LBER_SBIOD_LEVEL_PROVIDER, NULL ); break; #endif case LDAP_PROTO_IPC: #ifdef LDAP_PF_LOCAL /* only IPC mechanism supported is PF_LOCAL (PF_UNIX) */ rc = ldap_connect_to_path( ld, conn->lconn_sb, srv, async ); if ( rc == -1 ) return rc; #ifdef LDAP_DEBUG ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_PROVIDER, (void *)"ipc_" ); #endif ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_fd, LBER_SBIOD_LEVEL_PROVIDER, NULL ); break; #endif /* LDAP_PF_LOCAL */ default: return -1; break; } conn->lconn_created = time( NULL ); #ifdef LDAP_DEBUG ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug, INT_MAX, (void *)"ldap_" ); #endif #ifdef LDAP_CONNECTIONLESS if( proto == LDAP_PROTO_UDP ) return 0; #endif #ifdef HAVE_TLS if ((rc == 0 || rc == -2) && ( ld->ld_options.ldo_tls_mode == LDAP_OPT_X_TLS_HARD || strcmp( srv->lud_scheme, "ldaps" ) == 0 )) { ++conn->lconn_refcnt; /* avoid premature free */ rc = ldap_int_tls_start( ld, conn, srv ); --conn->lconn_refcnt; if (rc != LDAP_SUCCESS) { /* process connection callbacks */ { struct ldapoptions *lo; ldaplist *ll; ldap_conncb *cb; lo = &ld->ld_options; LDAP_MUTEX_LOCK( &lo->ldo_mutex ); if ( lo->ldo_conn_cbs ) { for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) { cb = ll->ll_data; cb->lc_del( ld, conn->lconn_sb, cb ); } } LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); lo = LDAP_INT_GLOBAL_OPT(); LDAP_MUTEX_LOCK( &lo->ldo_mutex ); if ( lo->ldo_conn_cbs ) { for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) { cb = ll->ll_data; cb->lc_del( ld, conn->lconn_sb, cb ); } } LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); } ber_int_sb_close( conn->lconn_sb ); return -1; } } #endif return( 0 ); } /* * ldap_open_internal_connection - open connection and set file descriptor * * note: ldap_init_fd() may be preferable */ int ldap_open_internal_connection( LDAP **ldp, ber_socket_t *fdp ) { int rc; LDAPConn *c; LDAPRequest *lr; LDAP *ld; rc = ldap_create( &ld ); if( rc != LDAP_SUCCESS ) { *ldp = NULL; return( rc ); } /* Make it appear that a search request, msgid 0, was sent */ lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest )); if( lr == NULL ) { ldap_unbind_ext( ld, NULL, NULL ); *ldp = NULL; return( LDAP_NO_MEMORY ); } memset(lr, 0, sizeof( LDAPRequest )); lr->lr_msgid = 0; lr->lr_status = LDAP_REQST_INPROGRESS; lr->lr_res_errno = LDAP_SUCCESS; /* no mutex lock needed, we just created this ld here */ rc = ldap_tavl_insert( &ld->ld_requests, lr, ldap_req_cmp, ldap_avl_dup_error ); assert( rc == LDAP_SUCCESS ); LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); /* Attach the passed socket as the *LDAP's connection */ c = ldap_new_connection( ld, NULL, 1, 0, NULL, 0, 0 ); if( c == NULL ) { ldap_unbind_ext( ld, NULL, NULL ); *ldp = NULL; LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); return( LDAP_NO_MEMORY ); } ber_sockbuf_ctrl( c->lconn_sb, LBER_SB_OPT_SET_FD, fdp ); #ifdef LDAP_DEBUG ber_sockbuf_add_io( c->lconn_sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_PROVIDER, (void *)"int_" ); #endif ber_sockbuf_add_io( c->lconn_sb, &ber_sockbuf_io_tcp, LBER_SBIOD_LEVEL_PROVIDER, NULL ); ld->ld_defconn = c; LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); /* Add the connection to the *LDAP's select pool */ ldap_mark_select_read( ld, c->lconn_sb ); /* Make this connection an LDAP V3 protocol connection */ rc = LDAP_VERSION3; ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &rc ); *ldp = ld; ++ld->ld_defconn->lconn_refcnt; /* so it never gets closed/freed */ return( LDAP_SUCCESS ); } LDAP * ldap_dup( LDAP *old ) { LDAP *ld; if ( old == NULL ) { return( NULL ); } Debug0( LDAP_DEBUG_TRACE, "ldap_dup\n" ); if ( (ld = (LDAP *) LDAP_CALLOC( 1, sizeof(LDAP) )) == NULL ) { return( NULL ); } LDAP_MUTEX_LOCK( &old->ld_ldcmutex ); ld->ldc = old->ldc; old->ld_ldcrefcnt++; LDAP_MUTEX_UNLOCK( &old->ld_ldcmutex ); return ( ld ); } int ldap_int_check_async_open( LDAP *ld, ber_socket_t sd ) { struct timeval tv = { 0 }; int rc; rc = ldap_int_poll( ld, sd, &tv, 1 ); switch ( rc ) { case 0: /* now ready to start tls */ ld->ld_defconn->lconn_status = LDAP_CONNST_CONNECTED; break; default: ld->ld_errno = LDAP_CONNECT_ERROR; return -1; case -2: /* connect not completed yet */ ld->ld_errno = LDAP_X_CONNECTING; return rc; } #ifdef HAVE_TLS if ( ld->ld_options.ldo_tls_mode == LDAP_OPT_X_TLS_HARD || !strcmp( ld->ld_defconn->lconn_server->lud_scheme, "ldaps" )) { ++ld->ld_defconn->lconn_refcnt; /* avoid premature free */ rc = ldap_int_tls_start( ld, ld->ld_defconn, ld->ld_defconn->lconn_server ); --ld->ld_defconn->lconn_refcnt; } #endif return rc; } openldap-2.5.11+dfsg/libraries/libldap/abandon.c0000644000175000017500000002207014172327167020171 0ustar ryanryan/* abandon.c */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" /* * An abandon request looks like this: * AbandonRequest ::= [APPLICATION 16] MessageID * and has no response. (Source: RFC 4511) */ #include "lutil.h" static int do_abandon( LDAP *ld, ber_int_t origid, LDAPRequest *lr, LDAPControl **sctrls, int sendabandon ); /* * ldap_abandon_ext - perform an ldap extended abandon operation. * * Parameters: * ld LDAP descriptor * msgid The message id of the operation to abandon * scntrls Server Controls * ccntrls Client Controls * * ldap_abandon_ext returns a LDAP error code. * (LDAP_SUCCESS if everything went ok) * * Example: * ldap_abandon_ext( ld, msgid, scntrls, ccntrls ); */ int ldap_abandon_ext( LDAP *ld, int msgid, LDAPControl **sctrls, LDAPControl **cctrls ) { int rc; Debug1( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid ); /* check client controls */ LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); rc = ldap_int_client_controls( ld, cctrls ); if ( rc == LDAP_SUCCESS ) { rc = do_abandon( ld, msgid, NULL, sctrls, 1 ); } LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); return rc; } /* * ldap_abandon - perform an ldap abandon operation. Parameters: * * ld LDAP descriptor * msgid The message id of the operation to abandon * * ldap_abandon returns 0 if everything went ok, -1 otherwise. * * Example: * ldap_abandon( ld, msgid ); */ int ldap_abandon( LDAP *ld, int msgid ) { Debug1( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid ); return ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS ? 0 : -1; } int ldap_pvt_discard( LDAP *ld, ber_int_t msgid ) { int rc; LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); rc = do_abandon( ld, msgid, NULL, NULL, 0 ); LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); return rc; } static int do_abandon( LDAP *ld, ber_int_t origid, LDAPRequest *lr, LDAPControl **sctrls, int sendabandon ) { BerElement *ber; int i, err; ber_int_t msgid = origid; Sockbuf *sb; LDAPRequest needle = {0}; needle.lr_msgid = origid; if ( lr != NULL ) { msgid = lr->lr_msgid; Debug2( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", origid, msgid ); } else if ( (lr = ldap_tavl_find( ld->ld_requests, &needle, ldap_req_cmp )) != NULL ) { Debug2( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", origid, msgid ); if ( lr->lr_parent != NULL ) { /* don't let caller abandon child requests! */ ld->ld_errno = LDAP_PARAM_ERROR; return( LDAP_PARAM_ERROR ); } msgid = lr->lr_msgid; } if ( lr != NULL ) { LDAPRequest **childp = &lr->lr_child; needle.lr_msgid = lr->lr_msgid; if ( lr->lr_status != LDAP_REQST_INPROGRESS ) { /* no need to send abandon message */ sendabandon = 0; } while ( *childp ) { /* Abandon children */ LDAPRequest *child = *childp; (void)do_abandon( ld, lr->lr_origid, child, sctrls, sendabandon ); if ( *childp == child ) { childp = &child->lr_refnext; } } } /* ldap_msgdelete locks the res_mutex. Give up the req_mutex * while we're in there. */ LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); err = ldap_msgdelete( ld, msgid ); LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); if ( err == 0 ) { ld->ld_errno = LDAP_SUCCESS; return LDAP_SUCCESS; } /* fetch again the request that we are abandoning */ if ( lr != NULL ) { lr = ldap_tavl_find( ld->ld_requests, &needle, ldap_req_cmp ); } err = 0; if ( sendabandon ) { if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) { /* not connected */ err = -1; ld->ld_errno = LDAP_SERVER_DOWN; } else if ( ( ber = ldap_alloc_ber_with_options( ld ) ) == NULL ) { /* BER element allocation failed */ err = -1; ld->ld_errno = LDAP_NO_MEMORY; } else { /* * We already have the mutex in LDAP_R_COMPILE, so * don't try to get it again. * LDAP_NEXT_MSGID(ld, i); */ LDAP_NEXT_MSGID(ld, i); #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP(ld) ) { struct sockaddr_storage sa = {0}; /* dummy, filled with ldo_peer in request.c */ err = ber_write( ber, (char *) &sa, sizeof(sa), 0 ); } if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2 ) { char *dn; LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); dn = ld->ld_options.ldo_cldapdn; if (!dn) dn = ""; err = ber_printf( ber, "{isti", /* '}' */ i, dn, LDAP_REQ_ABANDON, msgid ); LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); } else #endif { /* create a message to send */ err = ber_printf( ber, "{iti", /* '}' */ i, LDAP_REQ_ABANDON, msgid ); } if ( err == -1 ) { /* encoding error */ ld->ld_errno = LDAP_ENCODING_ERROR; } else { /* Put Server Controls */ if ( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { err = -1; } else { /* close '{' */ err = ber_printf( ber, /*{*/ "N}" ); if ( err == -1 ) { /* encoding error */ ld->ld_errno = LDAP_ENCODING_ERROR; } } } if ( err == -1 ) { ber_free( ber, 1 ); } else { /* send the message */ if ( lr != NULL ) { assert( lr->lr_conn != NULL ); sb = lr->lr_conn->lconn_sb; } else { sb = ld->ld_sb; } if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) != 0 ) { ld->ld_errno = LDAP_SERVER_DOWN; err = -1; } else { err = 0; } } } } if ( lr != NULL ) { LDAPConn *lc; int freeconn = 0; if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) { freeconn = 1; lc = lr->lr_conn; } if ( origid == msgid ) { ldap_free_request( ld, lr ); } else { lr->lr_abandoned = 1; } if ( freeconn ) { /* release ld_req_mutex while grabbing ld_conn_mutex to * prevent deadlock. */ LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); ldap_free_connection( ld, lc, 0, 1 ); LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); } } LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex ); /* use bisection */ i = 0; if ( ld->ld_nabandoned == 0 || ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &i ) == 0 ) { ldap_int_bisect_insert( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, i ); } if ( err != -1 ) { ld->ld_errno = LDAP_SUCCESS; } LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex ); return( ld->ld_errno ); } /* * ldap_int_bisect_find * * args: * v: array of length n (in) * n: length of array v (in) * id: value to look for (in) * idxp: pointer to location of value/insert point * * return: * 0: not found * 1: found * -1: error */ int ldap_int_bisect_find( ber_int_t *v, ber_len_t n, ber_int_t id, int *idxp ) { int begin, end, rc = 0; assert( id >= 0 ); begin = 0; end = n - 1; if ( n <= 0 || id < v[ begin ] ) { *idxp = 0; } else if ( id > v[ end ] ) { *idxp = n; } else { int pos; ber_int_t curid; do { pos = (begin + end)/2; curid = v[ pos ]; if ( id < curid ) { end = pos - 1; } else if ( id > curid ) { begin = ++pos; } else { /* already abandoned? */ rc = 1; break; } } while ( end >= begin ); *idxp = pos; } return rc; } /* * ldap_int_bisect_insert * * args: * vp: pointer to array of length *np (in/out) * np: pointer to length of array *vp (in/out) * id: value to insert (in) * idx: location of insert point (as computed by ldap_int_bisect_find()) * * return: * 0: inserted * -1: error */ int ldap_int_bisect_insert( ber_int_t **vp, ber_len_t *np, int id, int idx ) { ber_int_t *v; ber_len_t n; int i; assert( vp != NULL ); assert( np != NULL ); assert( idx >= 0 ); assert( (unsigned) idx <= *np ); n = *np; v = ber_memrealloc( *vp, sizeof( ber_int_t ) * ( n + 1 ) ); if ( v == NULL ) { return -1; } *vp = v; for ( i = n; i > idx; i-- ) { v[ i ] = v[ i - 1 ]; } v[ idx ] = id; ++(*np); return 0; } /* * ldap_int_bisect_delete * * args: * vp: pointer to array of length *np (in/out) * np: pointer to length of array *vp (in/out) * id: value to delete (in) * idx: location of value to delete (as computed by ldap_int_bisect_find()) * * return: * 0: deleted */ int ldap_int_bisect_delete( ber_int_t **vp, ber_len_t *np, int id, int idx ) { ber_int_t *v; ber_len_t i, n; assert( vp != NULL ); assert( np != NULL ); assert( idx >= 0 ); assert( (unsigned) idx < *np ); v = *vp; assert( v[ idx ] == id ); --(*np); n = *np; for ( i = idx; i < n; i++ ) { v[ i ] = v[ i + 1 ]; } return 0; } openldap-2.5.11+dfsg/libraries/libldap/add.c0000644000175000017500000001376614172327167017333 0ustar ryanryan/* add.c */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ #include "portable.h" #include #include #include #include #include "ldap-int.h" /* An LDAP Add Request/Response looks like this: * AddRequest ::= [APPLICATION 8] SEQUENCE { * entry LDAPDN, * attributes AttributeList } * * AttributeList ::= SEQUENCE OF attribute Attribute * * Attribute ::= PartialAttribute(WITH COMPONENTS { * ..., * vals (SIZE(1..MAX))}) * * PartialAttribute ::= SEQUENCE { * type AttributeDescription, * vals SET OF value AttributeValue } * * AttributeDescription ::= LDAPString * -- Constrained to [RFC4512] * * AttributeValue ::= OCTET STRING * * AddResponse ::= [APPLICATION 9] LDAPResult * (Source: RFC 4511) */ /* * ldap_add - initiate an ldap add operation. Parameters: * * ld LDAP descriptor * dn DN of the entry to add * mods List of attributes for the entry. This is a null- * terminated array of pointers to LDAPMod structures. * only the type and values in the structures need be * filled in. * * Example: * LDAPMod *attrs[] = { * { 0, "cn", { "babs jensen", "babs", 0 } }, * { 0, "sn", { "jensen", 0 } }, * { 0, "objectClass", { "person", 0 } }, * 0 * } * msgid = ldap_add( ld, dn, attrs ); */ int ldap_add( LDAP *ld, LDAP_CONST char *dn, LDAPMod **attrs ) { int rc; int msgid; rc = ldap_add_ext( ld, dn, attrs, NULL, NULL, &msgid ); if ( rc != LDAP_SUCCESS ) return -1; return msgid; } BerElement * ldap_build_add_req( LDAP *ld, const char *dn, LDAPMod **attrs, LDAPControl **sctrls, LDAPControl **cctrls, ber_int_t *msgidp ) { BerElement *ber; int i, rc; /* create a message to send */ if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { return( NULL ); } LDAP_NEXT_MSGID(ld, *msgidp); rc = ber_printf( ber, "{it{s{", /* '}}}' */ *msgidp, LDAP_REQ_ADD, dn ); if ( rc == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } /* allow attrs to be NULL ("touch"; should fail...) */ if ( attrs ) { /* for each attribute in the entry... */ for ( i = 0; attrs[i] != NULL; i++ ) { if ( ( attrs[i]->mod_op & LDAP_MOD_BVALUES) != 0 ) { int j; if ( attrs[i]->mod_bvalues == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; ber_free( ber, 1 ); return( NULL ); } for ( j = 0; attrs[i]->mod_bvalues[ j ] != NULL; j++ ) { if ( attrs[i]->mod_bvalues[ j ]->bv_val == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; ber_free( ber, 1 ); return( NULL ); } } rc = ber_printf( ber, "{s[V]N}", attrs[i]->mod_type, attrs[i]->mod_bvalues ); } else { if ( attrs[i]->mod_values == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; ber_free( ber, 1 ); return( NULL ); } rc = ber_printf( ber, "{s[v]N}", attrs[i]->mod_type, attrs[i]->mod_values ); } if ( rc == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } } } if ( ber_printf( ber, /*{{*/ "N}N}" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } /* Put Server Controls */ if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return( NULL ); } if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } return( ber ); } /* * ldap_add_ext - initiate an ldap extended add operation. Parameters: * * ld LDAP descriptor * dn DN of the entry to add * mods List of attributes for the entry. This is a null- * terminated array of pointers to LDAPMod structures. * only the type and values in the structures need be * filled in. * sctrl Server Controls * cctrl Client Controls * msgidp Message ID pointer * * Example: * LDAPMod *attrs[] = { * { 0, "cn", { "babs jensen", "babs", 0 } }, * { 0, "sn", { "jensen", 0 } }, * { 0, "objectClass", { "person", 0 } }, * 0 * } * rc = ldap_add_ext( ld, dn, attrs, NULL, NULL, &msgid ); */ int ldap_add_ext( LDAP *ld, LDAP_CONST char *dn, LDAPMod **attrs, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp ) { BerElement *ber; int rc; ber_int_t id; Debug0( LDAP_DEBUG_TRACE, "ldap_add_ext\n" ); assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( dn != NULL ); assert( msgidp != NULL ); /* check client controls */ rc = ldap_int_client_controls( ld, cctrls ); if( rc != LDAP_SUCCESS ) return rc; ber = ldap_build_add_req( ld, dn, attrs, sctrls, cctrls, &id ); if( !ber ) return ld->ld_errno; /* send the message */ *msgidp = ldap_send_initial_request( ld, LDAP_REQ_ADD, dn, ber, id ); if(*msgidp < 0) return ld->ld_errno; return LDAP_SUCCESS; } int ldap_add_ext_s( LDAP *ld, LDAP_CONST char *dn, LDAPMod **attrs, LDAPControl **sctrls, LDAPControl **cctrls ) { int msgid, rc; LDAPMessage *res; rc = ldap_add_ext( ld, dn, attrs, sctrls, cctrls, &msgid ); if ( rc != LDAP_SUCCESS ) return( rc ); if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, &res ) == -1 || !res ) return( ld->ld_errno ); return( ldap_result2error( ld, res, 1 ) ); } int ldap_add_s( LDAP *ld, LDAP_CONST char *dn, LDAPMod **attrs ) { return ldap_add_ext_s( ld, dn, attrs, NULL, NULL ); } openldap-2.5.11+dfsg/libraries/libldap/lbase64.c0000644000175000017500000000621114172327167020026 0ustar ryanryan/* lbase64.c - routines for dealing with base64 strings */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1992-1996 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. This * software is provided ``as is'' without express or implied warranty. */ /* This work was originally developed by the University of Michigan * and distributed as part of U-MICH LDAP. */ #include "portable.h" #include "ldap-int.h" #define RIGHT2 0x03 #define RIGHT4 0x0f static const unsigned char b642nib[0x80] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff }; int ldap_int_decode_b64_inplace( struct berval *value ) { char *p, *end, *byte; char nib; byte = value->bv_val; end = value->bv_val + value->bv_len; for ( p = value->bv_val, value->bv_len = 0; p < end; p += 4, value->bv_len += 3 ) { int i; for ( i = 0; i < 4; i++ ) { if ( p[i] != '=' && (p[i] & 0x80 || b642nib[ p[i] & 0x7f ] > 0x3f) ) { Debug2( LDAP_DEBUG_ANY, _("ldap_pvt_decode_b64_inplace: invalid base64 encoding" " char (%c) 0x%x\n"), p[i], p[i] ); return( -1 ); } } /* first digit */ nib = b642nib[ p[0] & 0x7f ]; byte[0] = nib << 2; /* second digit */ nib = b642nib[ p[1] & 0x7f ]; byte[0] |= nib >> 4; byte[1] = (nib & RIGHT4) << 4; /* third digit */ if ( p[2] == '=' ) { value->bv_len += 1; break; } nib = b642nib[ p[2] & 0x7f ]; byte[1] |= nib >> 2; byte[2] = (nib & RIGHT2) << 6; /* fourth digit */ if ( p[3] == '=' ) { value->bv_len += 2; break; } nib = b642nib[ p[3] & 0x7f ]; byte[2] |= nib; byte += 3; } value->bv_val[ value->bv_len ] = '\0'; return LDAP_SUCCESS; } openldap-2.5.11+dfsg/libraries/libldap/rq.c0000644000175000017500000001070414172327167017212 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2003-2022 The OpenLDAP Foundation. * Portions Copyright 2003 IBM Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* This work was initially developed by Jong Hyuk Choi for inclusion * in OpenLDAP Software. */ #include "portable.h" #include #include #include #include #include #include #include #include "ldap-int.h" #ifdef LDAP_R_COMPILE #include "ldap_pvt_thread.h" #include "ldap_queue.h" #include "ldap_rq.h" struct re_s * ldap_pvt_runqueue_insert( struct runqueue_s* rq, time_t interval, ldap_pvt_thread_start_t *routine, void *arg, char *tname, char *tspec ) { struct re_s* entry; entry = (struct re_s *) LDAP_CALLOC( 1, sizeof( struct re_s )); if ( entry ) { entry->interval.tv_sec = interval; entry->interval.tv_usec = 0; entry->next_sched.tv_sec = time( NULL ); entry->next_sched.tv_usec = 0; entry->routine = routine; entry->arg = arg; entry->tname = tname; entry->tspec = tspec; LDAP_STAILQ_INSERT_HEAD( &rq->task_list, entry, tnext ); } return entry; } struct re_s * ldap_pvt_runqueue_find( struct runqueue_s *rq, ldap_pvt_thread_start_t *routine, void *arg ) { struct re_s* e; LDAP_STAILQ_FOREACH( e, &rq->task_list, tnext ) { if ( e->routine == routine && e->arg == arg ) return e; } return NULL; } void ldap_pvt_runqueue_remove( struct runqueue_s* rq, struct re_s* entry ) { struct re_s* e; LDAP_STAILQ_FOREACH( e, &rq->task_list, tnext ) { if ( e == entry) break; } assert( e == entry ); LDAP_STAILQ_REMOVE( &rq->task_list, entry, re_s, tnext ); LDAP_FREE( entry ); } struct re_s* ldap_pvt_runqueue_next_sched( struct runqueue_s* rq, struct timeval* next_run ) { struct re_s* entry; entry = LDAP_STAILQ_FIRST( &rq->task_list ); if ( entry == NULL || entry->next_sched.tv_sec == 0 ) { return NULL; } else { *next_run = entry->next_sched; return entry; } } void ldap_pvt_runqueue_runtask( struct runqueue_s* rq, struct re_s* entry ) { LDAP_STAILQ_INSERT_TAIL( &rq->run_list, entry, rnext ); } void ldap_pvt_runqueue_stoptask( struct runqueue_s* rq, struct re_s* entry ) { LDAP_STAILQ_REMOVE( &rq->run_list, entry, re_s, rnext ); } int ldap_pvt_runqueue_isrunning( struct runqueue_s* rq, struct re_s* entry ) { struct re_s* e; LDAP_STAILQ_FOREACH( e, &rq->run_list, rnext ) { if ( e == entry ) { return 1; } } return 0; } void ldap_pvt_runqueue_resched( struct runqueue_s* rq, struct re_s* entry, int defer ) { struct re_s* prev; struct re_s* e; LDAP_STAILQ_FOREACH( e, &rq->task_list, tnext ) { if ( e == entry ) break; } assert ( e == entry ); LDAP_STAILQ_REMOVE( &rq->task_list, entry, re_s, tnext ); if ( !defer ) { entry->next_sched.tv_sec = time( NULL ) + entry->interval.tv_sec; } else { entry->next_sched.tv_sec = 0; } if ( LDAP_STAILQ_EMPTY( &rq->task_list )) { LDAP_STAILQ_INSERT_HEAD( &rq->task_list, entry, tnext ); } else if ( entry->next_sched.tv_sec == 0 ) { LDAP_STAILQ_INSERT_TAIL( &rq->task_list, entry, tnext ); } else { prev = NULL; LDAP_STAILQ_FOREACH( e, &rq->task_list, tnext ) { if ( e->next_sched.tv_sec == 0 ) { if ( prev == NULL ) { LDAP_STAILQ_INSERT_HEAD( &rq->task_list, entry, tnext ); } else { LDAP_STAILQ_INSERT_AFTER( &rq->task_list, prev, entry, tnext ); } return; } else if ( e->next_sched.tv_sec > entry->next_sched.tv_sec ) { if ( prev == NULL ) { LDAP_STAILQ_INSERT_HEAD( &rq->task_list, entry, tnext ); } else { LDAP_STAILQ_INSERT_AFTER( &rq->task_list, prev, entry, tnext ); } return; } prev = e; } LDAP_STAILQ_INSERT_TAIL( &rq->task_list, entry, tnext ); } } int ldap_pvt_runqueue_persistent_backload( struct runqueue_s* rq ) { struct re_s* e; int count = 0; ldap_pvt_thread_mutex_lock( &rq->rq_mutex ); if ( !LDAP_STAILQ_EMPTY( &rq->task_list )) { LDAP_STAILQ_FOREACH( e, &rq->task_list, tnext ) { if ( e->next_sched.tv_sec == 0 ) count++; } } ldap_pvt_thread_mutex_unlock( &rq->rq_mutex ); return count; } #endif /* LDAP_R_COMPILE */ openldap-2.5.11+dfsg/libraries/libldap/sbind.c0000644000175000017500000000521114172327167017664 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1993 Regents of the University of Michigan. * All rights reserved. */ /* * BindRequest ::= SEQUENCE { * version INTEGER, * name DistinguishedName, -- who * authentication CHOICE { * simple [0] OCTET STRING -- passwd * krbv42ldap [1] OCTET STRING -- OBSOLETE * krbv42dsa [2] OCTET STRING -- OBSOLETE * sasl [3] SaslCredentials -- LDAPv3 * } * } * * BindResponse ::= SEQUENCE { * COMPONENTS OF LDAPResult, * serverSaslCreds OCTET STRING OPTIONAL -- LDAPv3 * } * */ #include "portable.h" #include #include #include #include #include "ldap-int.h" /* * ldap_simple_bind - bind to the ldap server (and X.500). The dn and * password of the entry to which to bind are supplied. The message id * of the request initiated is returned. * * Example: * ldap_simple_bind( ld, "cn=manager, o=university of michigan, c=us", * "secret" ) */ int ldap_simple_bind( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *passwd ) { int rc; int msgid; struct berval cred; Debug0( LDAP_DEBUG_TRACE, "ldap_simple_bind\n" ); assert( ld != NULL ); assert( LDAP_VALID( ld ) ); if ( passwd != NULL ) { cred.bv_val = (char *) passwd; cred.bv_len = strlen( passwd ); } else { cred.bv_val = ""; cred.bv_len = 0; } rc = ldap_sasl_bind( ld, dn, LDAP_SASL_SIMPLE, &cred, NULL, NULL, &msgid ); return rc == LDAP_SUCCESS ? msgid : -1; } /* * ldap_simple_bind - bind to the ldap server (and X.500) using simple * authentication. The dn and password of the entry to which to bind are * supplied. LDAP_SUCCESS is returned upon success, the ldap error code * otherwise. * * Example: * ldap_simple_bind_s( ld, "cn=manager, o=university of michigan, c=us", * "secret" ) */ int ldap_simple_bind_s( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *passwd ) { struct berval cred; Debug0( LDAP_DEBUG_TRACE, "ldap_simple_bind_s\n" ); if ( passwd != NULL ) { cred.bv_val = (char *) passwd; cred.bv_len = strlen( passwd ); } else { cred.bv_val = ""; cred.bv_len = 0; } return ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL ); } openldap-2.5.11+dfsg/libraries/libldap/libldap.vers.in0000644000175000017500000000021214172327167021332 0ustar ryanryanHIDDEN { local: __*; _rest*; _save*; }; OPENLDAP_@OPENLDAP_LIBRELEASE@ { global: ldap_*; ldif_*; local: *; }; openldap-2.5.11+dfsg/libraries/libldap/ftest.c0000644000175000017500000000453614172327167017723 0ustar ryanryan/* ftest.c -- OpenLDAP Filter API Test */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include "ldap_pvt.h" #include "lber_pvt.h" #include "ldif.h" #include "lutil.h" #include "lutil_ldap.h" #include "ldap_defaults.h" static int filter2ber( char *filter ); int usage() { fprintf( stderr, "usage:\n" " ftest [-d n] filter\n" " filter - RFC 4515 string representation of an " "LDAP search filter\n" ); return EXIT_FAILURE; } int main( int argc, char *argv[] ) { int c; int debug=0; while( (c = getopt( argc, argv, "d:" )) != EOF ) { switch ( c ) { case 'd': debug = atoi( optarg ); break; default: fprintf( stderr, "ftest: unrecognized option -%c\n", optopt ); return usage(); } } if ( debug ) { if ( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) { fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug ); } if ( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug ) != LDAP_OPT_SUCCESS ) { fprintf( stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug ); } } if ( argc - optind != 1 ) { return usage(); } return filter2ber( strdup( argv[optind] ) ); } static int filter2ber( char *filter ) { int rc; struct berval bv = BER_BVNULL; BerElement *ber; printf( "Filter: %s\n", filter ); ber = ber_alloc_t( LBER_USE_DER ); if( ber == NULL ) { perror( "ber_alloc_t" ); return EXIT_FAILURE; } rc = ldap_pvt_put_filter( ber, filter ); if( rc < 0 ) { fprintf( stderr, "Filter error!\n"); return EXIT_FAILURE; } rc = ber_flatten2( ber, &bv, 0 ); if( rc < 0 ) { perror( "ber_flatten2" ); return EXIT_FAILURE; } printf( "BER encoding (len=%ld):\n", (long) bv.bv_len ); ber_bprint( bv.bv_val, bv.bv_len ); ber_free( ber, 1 ); return EXIT_SUCCESS; } openldap-2.5.11+dfsg/libraries/libldap/sort.c0000644000175000017500000000770614172327167017567 0ustar ryanryan/* sort.c -- LDAP library entry and value sort routines */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1994 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" struct entrything { char **et_vals; LDAPMessage *et_msg; int (*et_cmp_fn) LDAP_P((const char *a, const char *b)); }; static int et_cmp LDAP_P(( const void *aa, const void *bb)); int ldap_sort_strcasecmp( LDAP_CONST void *a, LDAP_CONST void *b ) { return( strcasecmp( *(char *const *)a, *(char *const *)b ) ); } static int et_cmp( const void *aa, const void *bb ) { int i, rc; const struct entrything *a = (const struct entrything *)aa; const struct entrything *b = (const struct entrything *)bb; if ( a->et_vals == NULL && b->et_vals == NULL ) return( 0 ); if ( a->et_vals == NULL ) return( -1 ); if ( b->et_vals == NULL ) return( 1 ); for ( i = 0; a->et_vals[i] && b->et_vals[i]; i++ ) { if ( (rc = a->et_cmp_fn( a->et_vals[i], b->et_vals[i] )) != 0 ) { return( rc ); } } if ( a->et_vals[i] == NULL && b->et_vals[i] == NULL ) return( 0 ); if ( a->et_vals[i] == NULL ) return( -1 ); return( 1 ); } int ldap_sort_entries( LDAP *ld, LDAPMessage **chain, LDAP_CONST char *attr, /* NULL => sort by DN */ int (*cmp) (LDAP_CONST char *, LDAP_CONST char *) ) { int i, count = 0; struct entrything *et; LDAPMessage *e, *ehead = NULL, *etail = NULL; LDAPMessage *ohead = NULL, *otail = NULL; LDAPMessage **ep; assert( ld != NULL ); /* Separate entries from non-entries */ for ( e = *chain; e; e=e->lm_chain ) { if ( e->lm_msgtype == LDAP_RES_SEARCH_ENTRY ) { count++; if ( !ehead ) ehead = e; if ( etail ) etail->lm_chain = e; etail = e; } else { if ( !ohead ) ohead = e; if ( otail ) otail->lm_chain = e; otail = e; } } if ( count < 2 ) { /* zero or one entries -- already sorted! */ if ( ehead ) { etail->lm_chain = ohead; *chain = ehead; } else { *chain = ohead; } return 0; } if ( (et = (struct entrything *) LDAP_MALLOC( count * sizeof(struct entrything) )) == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return( -1 ); } e = ehead; for ( i = 0; i < count; i++ ) { et[i].et_cmp_fn = cmp; et[i].et_msg = e; if ( attr == NULL ) { char *dn; dn = ldap_get_dn( ld, e ); et[i].et_vals = ldap_explode_dn( dn, 1 ); LDAP_FREE( dn ); } else { et[i].et_vals = ldap_get_values( ld, e, attr ); } e = e->lm_chain; } qsort( et, count, sizeof(struct entrything), et_cmp ); ep = chain; for ( i = 0; i < count; i++ ) { *ep = et[i].et_msg; ep = &(*ep)->lm_chain; LDAP_VFREE( et[i].et_vals ); } *ep = ohead; (*chain)->lm_chain_tail = otail ? otail : etail; LDAP_FREE( (char *) et ); return( 0 ); } int ldap_sort_values( LDAP *ld, char **vals, int (*cmp) (LDAP_CONST void *, LDAP_CONST void *) ) { int nel; for ( nel = 0; vals[nel] != NULL; nel++ ) ; /* NULL */ qsort( vals, nel, sizeof(char *), cmp ); return( 0 ); } openldap-2.5.11+dfsg/libraries/libldap/ldap_thr_debug.h0000644000175000017500000002055414172327167021544 0ustar ryanryan/* ldap_thr_debug.h - preprocessor magic for LDAP_THREAD_DEBUG */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2005-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #ifdef LDAP_THREAD_DEBUG /* * libldap .c files should include this file after ldap_pvt_thread.h, * with the appropriate LDAP_THREAD*_IMPLEMENTATION macro(s) defined. */ #ifndef _LDAP_PVT_THREAD_H #error "ldap_pvt_thread.h" must be included before "ldap_thr_debug.h" #endif /* * Support for thr_debug.c: * * thr_debug.c defines ldap_pvt_thread_* as wrappers around the real * ldap_pvt_thread_* implementation, which this file renames to * ldap_int_thread_*. * * Implementation: * * This file re#defines selected ldap_pvt_thread_* names to * ldap_int_thread_*, which will be used from wrappers in thr_debug.c. * Two ldap_int_*() calls are redirected to call ldap_debug_*(): These * are wrappers around the originals, whose definitions are not renamed. * This file then #includes ldap_pvt_thread.h to declare the renamed * functions/types. If #included from thr_debug.c it finally #undefines * the macros again. * * include/ldap_pvt_thread.h declares the typedefs ldap_pvt_thread*_t as * either wrapper types ldap_debug_thread*_t or their usual definitions * ldap_int_thread*_t, depending on the LDAP_THREAD_DEBUG_WRAP option. * When defining the underlying implementation, this file then redirects * the type names back to the original ldap_int_thread*_t types. * include/ldap__thread.h also do some thr_debug magic. * * So, * libldap/ thus define ldap_int_thread_*() instead * of ldap_pvt_thread_*(). * thr_debug.c defines the ldap_pvt_*() and ldap_debug_*() functions. * In thread.c, ldap_pvt_thread_() will call * ldap_debug_thread_*() instead of ldap_int_thread_*(). * In tpool.c, ldap_int_thread_pool_shutdown() has explicit thr_debug.c * support which treats ldap_pvt_thread_pool_destroy() the same way. */ #ifndef LDAP_THREAD_IMPLEMENTATION /* for first part of threads.c */ #define ldap_int_thread_initialize ldap_debug_thread_initialize #define ldap_int_thread_destroy ldap_debug_thread_destroy #else /* LDAP_THREAD_IMPLEMENTATION -- for thr_*.c and end of threads.c */ #undef ldap_int_thread_initialize #undef ldap_int_thread_destroy #ifdef LDAP_THREAD_DEBUG_WRAP /* see ldap_pvt_thread.h */ #define ldap_pvt_thread_mutex_t ldap_int_thread_mutex_t #define ldap_pvt_thread_cond_t ldap_int_thread_cond_t #endif #define ldap_pvt_thread_sleep ldap_int_thread_sleep #define ldap_pvt_thread_get_concurrency ldap_int_thread_get_concurrency #define ldap_pvt_thread_set_concurrency ldap_int_thread_set_concurrency #define ldap_pvt_thread_create ldap_int_thread_create #define ldap_pvt_thread_exit ldap_int_thread_exit #define ldap_pvt_thread_join ldap_int_thread_join #define ldap_pvt_thread_kill ldap_int_thread_kill #define ldap_pvt_thread_yield ldap_int_thread_yield #define ldap_pvt_thread_cond_init ldap_int_thread_cond_init #define ldap_pvt_thread_cond_destroy ldap_int_thread_cond_destroy #define ldap_pvt_thread_cond_signal ldap_int_thread_cond_signal #define ldap_pvt_thread_cond_broadcast ldap_int_thread_cond_broadcast #define ldap_pvt_thread_cond_wait ldap_int_thread_cond_wait #define ldap_pvt_thread_mutex_init ldap_int_thread_mutex_init #define ldap_pvt_thread_mutex_recursive_init ldap_int_thread_mutex_recursive_init #define ldap_pvt_thread_mutex_destroy ldap_int_thread_mutex_destroy #define ldap_pvt_thread_mutex_lock ldap_int_thread_mutex_lock #define ldap_pvt_thread_mutex_trylock ldap_int_thread_mutex_trylock #define ldap_pvt_thread_mutex_unlock ldap_int_thread_mutex_unlock #define ldap_pvt_thread_self ldap_int_thread_self #endif /* LDAP_THREAD_IMPLEMENTATION */ #ifdef LDAP_THREAD_RDWR_IMPLEMENTATION /* rdwr.c, thr_debug.c */ #ifdef LDAP_THREAD_DEBUG_WRAP /* see ldap_pvt_thread.h */ #define ldap_pvt_thread_rdwr_t ldap_int_thread_rdwr_t #endif #define ldap_pvt_thread_rdwr_init ldap_int_thread_rdwr_init #define ldap_pvt_thread_rdwr_destroy ldap_int_thread_rdwr_destroy #define ldap_pvt_thread_rdwr_rlock ldap_int_thread_rdwr_rlock #define ldap_pvt_thread_rdwr_rtrylock ldap_int_thread_rdwr_rtrylock #define ldap_pvt_thread_rdwr_runlock ldap_int_thread_rdwr_runlock #define ldap_pvt_thread_rdwr_wlock ldap_int_thread_rdwr_wlock #define ldap_pvt_thread_rdwr_wtrylock ldap_int_thread_rdwr_wtrylock #define ldap_pvt_thread_rdwr_wunlock ldap_int_thread_rdwr_wunlock #define ldap_pvt_thread_rdwr_readers ldap_int_thread_rdwr_readers #define ldap_pvt_thread_rdwr_writers ldap_int_thread_rdwr_writers #define ldap_pvt_thread_rdwr_active ldap_int_thread_rdwr_active #endif /* LDAP_THREAD_RDWR_IMPLEMENTATION */ #ifdef LDAP_THREAD_POOL_IMPLEMENTATION /* tpool.c, thr_debug.c */ #ifdef LDAP_THREAD_DEBUG_WRAP /* see ldap_pvt_thread.h */ #define ldap_pvt_thread_pool_t ldap_int_thread_pool_t #endif #define ldap_pvt_thread_pool_init ldap_int_thread_pool_init #define ldap_pvt_thread_pool_submit ldap_int_thread_pool_submit #define ldap_pvt_thread_pool_maxthreads ldap_int_thread_pool_maxthreads #define ldap_pvt_thread_pool_backload ldap_int_thread_pool_backload #define ldap_pvt_thread_pool_pause ldap_int_thread_pool_pause #define ldap_pvt_thread_pool_resume ldap_int_thread_pool_resume #define ldap_pvt_thread_pool_destroy ldap_int_thread_pool_destroy #define ldap_pvt_thread_pool_close ldap_int_thread_pool_close #define ldap_pvt_thread_pool_free ldap_int_thread_pool_free #define ldap_pvt_thread_pool_getkey ldap_int_thread_pool_getkey #define ldap_pvt_thread_pool_setkey ldap_int_thread_pool_setkey #define ldap_pvt_thread_pool_purgekey ldap_int_thread_pool_purgekey #define ldap_pvt_thread_pool_context ldap_int_thread_pool_context #define ldap_pvt_thread_pool_context_reset ldap_int_thread_pool_context_reset #endif /* LDAP_THREAD_POOL_IMPLEMENTATION */ #undef _LDAP_PVT_THREAD_H #include "ldap_pvt_thread.h" #ifdef LDAP_THREAD_POOL_IMPLEMENTATION /* tpool.c */ /* * tpool.c:ldap_int_thread_pool_shutdown() needs this. Could not * use it for ldap_pvt_thread.h above because of its use of LDAP_P(). */ #undef ldap_pvt_thread_pool_destroy #define ldap_pvt_thread_pool_destroy(p,r) ldap_int_thread_pool_destroy(p,r) #endif #ifdef LDAP_THREAD_DEBUG_IMPLEMENTATION /* thr_debug.c */ #undef ldap_pvt_thread_mutex_t #undef ldap_pvt_thread_cond_t #undef ldap_pvt_thread_sleep #undef ldap_pvt_thread_get_concurrency #undef ldap_pvt_thread_set_concurrency #undef ldap_pvt_thread_create #undef ldap_pvt_thread_exit #undef ldap_pvt_thread_join #undef ldap_pvt_thread_kill #undef ldap_pvt_thread_yield #undef ldap_pvt_thread_cond_init #undef ldap_pvt_thread_cond_destroy #undef ldap_pvt_thread_cond_signal #undef ldap_pvt_thread_cond_broadcast #undef ldap_pvt_thread_cond_wait #undef ldap_pvt_thread_mutex_init #undef ldap_pvt_thread_mutex_recursive_init #undef ldap_pvt_thread_mutex_destroy #undef ldap_pvt_thread_mutex_lock #undef ldap_pvt_thread_mutex_trylock #undef ldap_pvt_thread_mutex_unlock #undef ldap_pvt_thread_self /* LDAP_THREAD_RDWR_IMPLEMENTATION: */ #undef ldap_pvt_thread_rdwr_t #undef ldap_pvt_thread_rdwr_init #undef ldap_pvt_thread_rdwr_destroy #undef ldap_pvt_thread_rdwr_rlock #undef ldap_pvt_thread_rdwr_rtrylock #undef ldap_pvt_thread_rdwr_runlock #undef ldap_pvt_thread_rdwr_wlock #undef ldap_pvt_thread_rdwr_wtrylock #undef ldap_pvt_thread_rdwr_wunlock #undef ldap_pvt_thread_rdwr_readers #undef ldap_pvt_thread_rdwr_writers #undef ldap_pvt_thread_rdwr_active /* LDAP_THREAD_POOL_IMPLEMENTATION: */ #undef ldap_pvt_thread_pool_t #undef ldap_pvt_thread_pool_init #undef ldap_pvt_thread_pool_submit #undef ldap_pvt_thread_pool_maxthreads #undef ldap_pvt_thread_pool_backload #undef ldap_pvt_thread_pool_pause #undef ldap_pvt_thread_pool_resume #undef ldap_pvt_thread_pool_destroy #undef ldap_pvt_thread_pool_close #undef ldap_pvt_thread_pool_free #undef ldap_pvt_thread_pool_getkey #undef ldap_pvt_thread_pool_setkey #undef ldap_pvt_thread_pool_purgekey #undef ldap_pvt_thread_pool_context #undef ldap_pvt_thread_pool_context_reset #endif /* LDAP_THREAD_DEBUG_IMPLEMENTATION */ #endif /* LDAP_THREAD_DEBUG */ openldap-2.5.11+dfsg/libraries/libldap/getdn.c0000644000175000017500000021345414172327167017700 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1994 Regents of the University of Michigan. * All rights reserved. */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" #include "ldap_schema.h" #include "ldif.h" /* extension to UFN that turns trailing "dc=value" rdns in DNS style, * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */ #define DC_IN_UFN /* parsing/printing routines */ static int str2strval( const char *str, ber_len_t stoplen, struct berval *val, const char **next, unsigned flags, int *retFlags, void *ctx ); static int DCE2strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx ); static int IA52strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx ); static int quotedIA52strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx ); static int hexstr2binval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx ); static int hexstr2bin( const char *str, char *c ); static int byte2hexpair( const char *val, char *pair ); static int binval2hexstr( struct berval *val, char *str ); static int strval2strlen( struct berval *val, unsigned flags, ber_len_t *len ); static int strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len ); static int strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len ); static int strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len ); static int strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len ); static int strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len ); static int strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len ); static int strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len ); static int dn2domain( LDAPDN dn, struct berval *bv, int pos, int *iRDN ); /* AVA helpers */ static LDAPAVA * ldapava_new( const struct berval *attr, const struct berval *val, unsigned flags, void *ctx ); /* Higher level helpers */ static int rdn2strlen( LDAPRDN rdn, unsigned flags, ber_len_t *len, int ( *s2l )( struct berval *, unsigned, ber_len_t * ) ); static int rdn2str( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * )); static int rdn2UFNstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len ); static int rdn2UFNstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len ); static int rdn2DCEstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len ); static int rdn2DCEstr( LDAPRDN rdn, char *str, unsigned flag, ber_len_t *len, int first ); static int rdn2ADstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len ); static int rdn2ADstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first ); /* * RFC 1823 ldap_get_dn */ char * ldap_get_dn( LDAP *ld, LDAPMessage *entry ) { char *dn; BerElement tmp; Debug0( LDAP_DEBUG_TRACE, "ldap_get_dn\n" ); assert( ld != NULL ); assert( LDAP_VALID(ld) ); assert( entry != NULL ); tmp = *entry->lm_ber; /* struct copy */ if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; return( NULL ); } return( dn ); } int ldap_get_dn_ber( LDAP *ld, LDAPMessage *entry, BerElement **berout, BerValue *dn ) { BerElement tmp, *ber; ber_len_t len = 0; int rc = LDAP_SUCCESS; Debug0( LDAP_DEBUG_TRACE, "ldap_get_dn_ber\n" ); assert( ld != NULL ); assert( LDAP_VALID(ld) ); assert( entry != NULL ); assert( dn != NULL ); dn->bv_val = NULL; dn->bv_len = 0; if ( berout ) { *berout = NULL; ber = ldap_alloc_ber_with_options( ld ); if( ber == NULL ) { return LDAP_NO_MEMORY; } *berout = ber; } else { ber = &tmp; } *ber = *entry->lm_ber; /* struct copy */ if ( ber_scanf( ber, "{ml{" /*}*/, dn, &len ) == LBER_ERROR ) { rc = ld->ld_errno = LDAP_DECODING_ERROR; } if ( rc == LDAP_SUCCESS ) { /* set the length to avoid overrun */ rc = ber_set_option( ber, LBER_OPT_REMAINING_BYTES, &len ); if( rc != LBER_OPT_SUCCESS ) { rc = ld->ld_errno = LDAP_LOCAL_ERROR; } } if ( rc != LDAP_SUCCESS && berout ) { ber_free( ber, 0 ); *berout = NULL; } return rc; } /* * RFC 1823 ldap_dn2ufn */ char * ldap_dn2ufn( LDAP_CONST char *dn ) { char *out = NULL; Debug0( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n" ); ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_UFN ); return( out ); } /* * RFC 1823 ldap_explode_dn */ char ** ldap_explode_dn( LDAP_CONST char *dn, int notypes ) { LDAPDN tmpDN; char **values = NULL; int iRDN; unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3; Debug0( LDAP_DEBUG_TRACE, "ldap_explode_dn\n" ); if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP ) != LDAP_SUCCESS ) { return NULL; } if( tmpDN == NULL ) { values = LDAP_MALLOC( sizeof( char * ) ); if( values == NULL ) return NULL; values[0] = NULL; return values; } for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ); values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iRDN ) ); if ( values == NULL ) { ldap_dnfree( tmpDN ); return NULL; } for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) { ldap_rdn2str( tmpDN[ iRDN ], &values[ iRDN ], flag ); } ldap_dnfree( tmpDN ); values[ iRDN ] = NULL; return values; } char ** ldap_explode_rdn( LDAP_CONST char *rdn, int notypes ) { LDAPRDN tmpRDN; char **values = NULL; const char *p; int iAVA; Debug0( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n" ); /* * we only parse the first rdn * FIXME: we prefer efficiency over checking if the _ENTIRE_ * dn can be parsed */ if ( ldap_str2rdn( rdn, &tmpRDN, (char **) &p, LDAP_DN_FORMAT_LDAP ) != LDAP_SUCCESS ) { return( NULL ); } for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) ; values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iAVA ) ); if ( values == NULL ) { ldap_rdnfree( tmpRDN ); return( NULL ); } for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) { ber_len_t l = 0, vl, al = 0; char *str; LDAPAVA *ava = tmpRDN[ iAVA ]; if ( ava->la_flags & LDAP_AVA_BINARY ) { vl = 1 + 2 * ava->la_value.bv_len; } else { if ( strval2strlen( &ava->la_value, ava->la_flags, &vl ) ) { goto error_return; } } if ( !notypes ) { al = ava->la_attr.bv_len; l = vl + ava->la_attr.bv_len + 1; str = LDAP_MALLOC( l + 1 ); if ( str == NULL ) { goto error_return; } AC_MEMCPY( str, ava->la_attr.bv_val, ava->la_attr.bv_len ); str[ al++ ] = '='; } else { l = vl; str = LDAP_MALLOC( l + 1 ); if ( str == NULL ) { goto error_return; } } if ( ava->la_flags & LDAP_AVA_BINARY ) { str[ al++ ] = '#'; if ( binval2hexstr( &ava->la_value, &str[ al ] ) ) { goto error_return; } } else { if ( strval2str( &ava->la_value, &str[ al ], ava->la_flags, &vl ) ) { goto error_return; } } str[ l ] = '\0'; values[ iAVA ] = str; } values[ iAVA ] = NULL; ldap_rdnfree( tmpRDN ); return( values ); error_return:; LBER_VFREE( values ); ldap_rdnfree( tmpRDN ); return( NULL ); } char * ldap_dn2dcedn( LDAP_CONST char *dn ) { char *out = NULL; Debug0( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n" ); ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_DCE ); return( out ); } char * ldap_dcedn2dn( LDAP_CONST char *dce ) { char *out = NULL; Debug0( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n" ); ( void )ldap_dn_normalize( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 ); return( out ); } char * ldap_dn2ad_canonical( LDAP_CONST char *dn ) { char *out = NULL; Debug0( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n" ); ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_AD_CANONICAL ); return( out ); } /* * function that changes the string representation of dnin * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK ) * * fin can be one of: * LDAP_DN_FORMAT_LDAP (RFC 4514 liberal, plus some RFC 1779) * LDAP_DN_FORMAT_LDAPV3 (RFC 4514) * LDAP_DN_FORMAT_LDAPV2 (RFC 1779) * LDAP_DN_FORMAT_DCE (?) * * fout can be any of the above except * LDAP_DN_FORMAT_LDAP * plus: * LDAP_DN_FORMAT_UFN (RFC 1781, partial and with extensions) * LDAP_DN_FORMAT_AD_CANONICAL (?) */ int ldap_dn_normalize( LDAP_CONST char *dnin, unsigned fin, char **dnout, unsigned fout ) { int rc; LDAPDN tmpDN = NULL; Debug0( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n" ); assert( dnout != NULL ); *dnout = NULL; if ( dnin == NULL ) { return( LDAP_SUCCESS ); } rc = ldap_str2dn( dnin , &tmpDN, fin ); if ( rc != LDAP_SUCCESS ) { return( rc ); } rc = ldap_dn2str( tmpDN, dnout, fout ); ldap_dnfree( tmpDN ); return( rc ); } /* States */ #define B4AVA 0x0000 /* #define B4ATTRTYPE 0x0001 */ #define B4OIDATTRTYPE 0x0002 #define B4STRINGATTRTYPE 0x0003 #define B4AVAEQUALS 0x0100 #define B4AVASEP 0x0200 #define B4RDNSEP 0x0300 #define GOTAVA 0x0400 #define B4ATTRVALUE 0x0010 #define B4STRINGVALUE 0x0020 #define B4IA5VALUEQUOTED 0x0030 #define B4IA5VALUE 0x0040 #define B4BINARYVALUE 0x0050 /* * Helpers (mostly from slap.h) * c is assumed to Unicode in an ASCII compatible format (UTF-8) * Macros assume "C" Locale (ASCII) */ #define LDAP_DN_ASCII_SPACE(c) \ ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' ) #define LDAP_DN_ASCII_LOWER(c) LDAP_LOWER(c) #define LDAP_DN_ASCII_UPPER(c) LDAP_UPPER(c) #define LDAP_DN_ASCII_ALPHA(c) LDAP_ALPHA(c) #define LDAP_DN_ASCII_DIGIT(c) LDAP_DIGIT(c) #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) LDAP_HEXLOWER(c) #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) LDAP_HEXUPPER(c) #define LDAP_DN_ASCII_HEXDIGIT(c) LDAP_HEX(c) #define LDAP_DN_ASCII_ALNUM(c) LDAP_ALNUM(c) #define LDAP_DN_ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' ) /* attribute type */ #define LDAP_DN_OID_LEADCHAR(c) LDAP_DIGIT(c) #define LDAP_DN_DESC_LEADCHAR(c) LDAP_ALPHA(c) #define LDAP_DN_DESC_CHAR(c) LDAP_LDH(c) #define LDAP_DN_LANG_SEP(c) ( (c) == ';' ) #define LDAP_DN_ATTRDESC_CHAR(c) \ ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) ) /* special symbols */ #define LDAP_DN_AVA_EQUALS(c) ( (c) == '=' ) #define LDAP_DN_AVA_SEP(c) ( (c) == '+' ) #define LDAP_DN_RDN_SEP(c) ( (c) == ',' ) #define LDAP_DN_RDN_SEP_V2(c) ( LDAP_DN_RDN_SEP(c) || (c) == ';' ) #define LDAP_DN_OCTOTHORPE(c) ( (c) == '#' ) #define LDAP_DN_QUOTES(c) ( (c) == '\"' ) #define LDAP_DN_ESCAPE(c) ( (c) == '\\' ) #define LDAP_DN_VALUE_END(c) \ ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) ) /* NOTE: according to RFC 4514, '=' can be escaped and treated as special, * i.e. escaped both as "\" and * as "\=", but it is treated as * a regular char, i.e. it can also appear as '='. * * As such, in 2.2 we used to allow reading unescaped '=', but we always * produced escaped '\3D'; this changes since 2.3, if compatibility issues * do not arise */ #define LDAP_DN_NE(c) \ ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \ || LDAP_DN_QUOTES(c) \ || (c) == '<' || (c) == '>' ) #define LDAP_DN_MAYESCAPE(c) \ ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) \ || LDAP_DN_AVA_EQUALS(c) \ || LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) ) #define LDAP_DN_SHOULDESCAPE(c) ( LDAP_DN_AVA_EQUALS(c) ) #define LDAP_DN_NEEDESCAPE(c) \ ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) ) #define LDAP_DN_NEEDESCAPE_LEAD(c) LDAP_DN_MAYESCAPE(c) #define LDAP_DN_NEEDESCAPE_TRAIL(c) \ ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) ) #define LDAP_DN_WILLESCAPE_CHAR(c) \ ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) || LDAP_DN_ESCAPE(c) ) #define LDAP_DN_IS_PRETTY(f) ( (f) & LDAP_DN_PRETTY ) #define LDAP_DN_WILLESCAPE_HEX(f, c) \ ( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) ) /* LDAPv2 */ #define LDAP_DN_VALUE_END_V2(c) \ ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) ) /* RFC 1779 */ #define LDAP_DN_V2_SPECIAL(c) \ ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \ || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \ || LDAP_DN_OCTOTHORPE(c) ) #define LDAP_DN_V2_PAIR(c) \ ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) ) /* * DCE (mostly from Luke Howard and IBM implementation for AIX) * * From: "Application Development Guide - Directory Services" (FIXME: add link?) * Here escapes and valid chars for GDS are considered; as soon as more * specific info is found, the macros will be updated. * * Chars: 'a'-'z', 'A'-'Z', '0'-'9', * '.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '. * * Metachars: '/', ',', '=', '\'. * * the '\' is used to escape other metachars. * * Assertion: '=' * RDN separator: '/' * AVA separator: ',' * * Attribute types must start with alphabetic chars and can contain * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed. */ #define LDAP_DN_RDN_SEP_DCE(c) ( (c) == '/' ) #define LDAP_DN_AVA_SEP_DCE(c) ( (c) == ',' ) #define LDAP_DN_ESCAPE_DCE(c) ( LDAP_DN_ESCAPE(c) ) #define LDAP_DN_VALUE_END_DCE(c) \ ( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) ) #define LDAP_DN_NEEDESCAPE_DCE(c) \ ( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) ) /* AD Canonical */ #define LDAP_DN_RDN_SEP_AD(c) ( (c) == '/' ) #define LDAP_DN_ESCAPE_AD(c) ( LDAP_DN_ESCAPE(c) ) #define LDAP_DN_AVA_SEP_AD(c) ( (c) == ',' ) /* assume same as DCE */ #define LDAP_DN_VALUE_END_AD(c) \ ( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) ) #define LDAP_DN_NEEDESCAPE_AD(c) \ ( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) ) /* generics */ #define LDAP_DN_HEXPAIR(s) \ ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) ) /* better look at the AttributeDescription? */ /* FIXME: no composite rdn or non-"dc" types, right? * (what about "dc" in OID form?) */ /* FIXME: we do not allow binary values in domain, right? */ /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */ /* NOTE: don't use strcasecmp() as it is locale specific! */ #define LDAP_DC_ATTR "dc" #define LDAP_DC_ATTRU "DC" #define LDAP_DN_IS_RDN_DC( r ) \ ( (r) && (r)[0] && !(r)[1] \ && ((r)[0]->la_flags & LDAP_AVA_STRING) \ && ((r)[0]->la_attr.bv_len == 2) \ && (((r)[0]->la_attr.bv_val[0] == LDAP_DC_ATTR[0]) \ || ((r)[0]->la_attr.bv_val[0] == LDAP_DC_ATTRU[0])) \ && (((r)[0]->la_attr.bv_val[1] == LDAP_DC_ATTR[1]) \ || ((r)[0]->la_attr.bv_val[1] == LDAP_DC_ATTRU[1]))) /* Composite rules */ #define LDAP_DN_ALLOW_ONE_SPACE(f) \ ( LDAP_DN_LDAPV2(f) \ || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) ) #define LDAP_DN_ALLOW_SPACES(f) \ ( LDAP_DN_LDAPV2(f) \ || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) ) #define LDAP_DN_LDAP(f) \ ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP ) #define LDAP_DN_LDAPV3(f) \ ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 ) #define LDAP_DN_LDAPV2(f) \ ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 ) #define LDAP_DN_DCE(f) \ ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE ) #define LDAP_DN_UFN(f) \ ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN ) #define LDAP_DN_ADC(f) \ ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL ) #define LDAP_DN_FORMAT(f) ( (f) & LDAP_DN_FORMAT_MASK ) /* * LDAPAVA helpers (will become part of the API for operations * on structural representations of DNs). */ static LDAPAVA * ldapava_new( const struct berval *attr, const struct berval *val, unsigned flags, void *ctx ) { LDAPAVA *ava; assert( attr != NULL ); assert( val != NULL ); ava = LDAP_MALLOCX( sizeof( LDAPAVA ) + attr->bv_len + 1, ctx ); if ( ava ) { ava->la_attr.bv_len = attr->bv_len; ava->la_attr.bv_val = (char *)(ava+1); AC_MEMCPY( ava->la_attr.bv_val, attr->bv_val, attr->bv_len ); ava->la_attr.bv_val[attr->bv_len] = '\0'; ava->la_value = *val; ava->la_flags = flags | LDAP_AVA_FREE_VALUE; ava->la_private = NULL; } return( ava ); } static void ldapava_free( LDAPAVA *ava, void *ctx ) { assert( ava != NULL ); #if 0 /* ava's private must be freed by caller * (at present let's skip this check because la_private * basically holds static data) */ assert( ava->la_private == NULL ); #endif if (ava->la_flags & LDAP_AVA_FREE_VALUE) LDAP_FREEX( ava->la_value.bv_val, ctx ); LDAP_FREEX( ava, ctx ); } void ldap_rdnfree( LDAPRDN rdn ) { ldap_rdnfree_x( rdn, NULL ); } void ldap_rdnfree_x( LDAPRDN rdn, void *ctx ) { int iAVA; if ( rdn == NULL ) { return; } for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { ldapava_free( rdn[ iAVA ], ctx ); } LDAP_FREEX( rdn, ctx ); } void ldap_dnfree( LDAPDN dn ) { ldap_dnfree_x( dn, NULL ); } void ldap_dnfree_x( LDAPDN dn, void *ctx ) { int iRDN; if ( dn == NULL ) { return; } for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) { ldap_rdnfree_x( dn[ iRDN ], ctx ); } LDAP_FREEX( dn, ctx ); } /* * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE) * into a structural representation of the DN, by separating attribute * types and values encoded in the more appropriate form, which is * string or OID for attribute types and binary form of the BER encoded * value or Unicode string. Formats different from LDAPv3 are parsed * according to their own rules and turned into the more appropriate * form according to LDAPv3. * * NOTE: I realize the code is getting spaghettish; it is rather * experimental and will hopefully turn into something more simple * and readable as soon as it works as expected. */ /* * Default sizes of AVA and RDN static working arrays; if required * the are dynamically resized. The values can be tuned in case * of special requirements (e.g. very deep DN trees or high number * of AVAs per RDN). */ #define TMP_AVA_SLOTS 8 #define TMP_RDN_SLOTS 32 int ldap_str2dn( LDAP_CONST char *str, LDAPDN *dn, unsigned flags ) { struct berval bv; assert( str != NULL ); bv.bv_len = strlen( str ); bv.bv_val = (char *) str; return ldap_bv2dn_x( &bv, dn, flags, NULL ); } int ldap_bv2dn( struct berval *bv, LDAPDN *dn, unsigned flags ) { return ldap_bv2dn_x( bv, dn, flags, NULL ); } int ldap_bv2dn_x( struct berval *bvin, LDAPDN *dn, unsigned flags, void *ctx ) { const char *p; int rc = LDAP_DECODING_ERROR; int nrdns = 0; LDAPDN newDN = NULL; LDAPRDN newRDN = NULL, tmpDN_[TMP_RDN_SLOTS], *tmpDN = tmpDN_; int num_slots = TMP_RDN_SLOTS; char *str, *end; struct berval bvtmp, *bv = &bvtmp; assert( bvin != NULL ); assert( bvin->bv_val != NULL ); assert( dn != NULL ); *bv = *bvin; str = bv->bv_val; end = str + bv->bv_len; Debug2( LDAP_DEBUG_ARGS, "=> ldap_bv2dn(%s,%u)\n", str, flags ); *dn = NULL; switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAP: case LDAP_DN_FORMAT_LDAPV3: case LDAP_DN_FORMAT_DCE: break; /* allow DN enclosed in brackets */ case LDAP_DN_FORMAT_LDAPV2: if ( str[0] == '<' ) { if ( bv->bv_len < 2 || end[ -1 ] != '>' ) { rc = LDAP_DECODING_ERROR; goto parsing_error; } bv->bv_val++; bv->bv_len -= 2; str++; end--; } break; /* unsupported in str2dn */ case LDAP_DN_FORMAT_UFN: case LDAP_DN_FORMAT_AD_CANONICAL: return LDAP_PARAM_ERROR; case LDAP_DN_FORMAT_LBER: default: return LDAP_PARAM_ERROR; } if ( bv->bv_len == 0 ) { return LDAP_SUCCESS; } if( memchr( bv->bv_val, '\0', bv->bv_len ) != NULL ) { /* value must have embedded NULs */ return LDAP_DECODING_ERROR; } p = str; if ( LDAP_DN_DCE( flags ) ) { /* * (from Luke Howard: thnx) A RDN separator is required * at the beginning of an (absolute) DN. */ if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) { goto parsing_error; } p++; /* * actually we do not want to accept by default the DCE form, * we do not want to auto-detect it */ #if 0 } else if ( LDAP_DN_LDAP( flags ) ) { /* * if dn starts with '/' let's make it a DCE dn */ if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) { flags |= LDAP_DN_FORMAT_DCE; p++; } #endif } for ( ; p < end; p++ ) { int err; struct berval tmpbv; tmpbv.bv_len = bv->bv_len - ( p - str ); tmpbv.bv_val = (char *)p; err = ldap_bv2rdn_x( &tmpbv, &newRDN, (char **) &p, flags,ctx); if ( err != LDAP_SUCCESS ) { goto parsing_error; } /* * We expect a rdn separator */ if ( p < end && p[ 0 ] ) { switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAPV3: if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) { rc = LDAP_DECODING_ERROR; goto parsing_error; } break; case LDAP_DN_FORMAT_LDAP: case LDAP_DN_FORMAT_LDAPV2: if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) { rc = LDAP_DECODING_ERROR; goto parsing_error; } break; case LDAP_DN_FORMAT_DCE: if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) { rc = LDAP_DECODING_ERROR; goto parsing_error; } break; } } tmpDN[nrdns++] = newRDN; newRDN = NULL; /* * make the static RDN array dynamically rescalable */ if ( nrdns == num_slots ) { LDAPRDN *tmp; if ( tmpDN == tmpDN_ ) { tmp = LDAP_MALLOCX( num_slots * 2 * sizeof( LDAPRDN * ), ctx ); if ( tmp == NULL ) { rc = LDAP_NO_MEMORY; goto parsing_error; } AC_MEMCPY( tmp, tmpDN, num_slots * sizeof( LDAPRDN * ) ); } else { tmp = LDAP_REALLOCX( tmpDN, num_slots * 2 * sizeof( LDAPRDN * ), ctx ); if ( tmp == NULL ) { rc = LDAP_NO_MEMORY; goto parsing_error; } } tmpDN = tmp; num_slots *= 2; } if ( p >= end || p[ 0 ] == '\0' ) { /* * the DN is over, phew */ newDN = (LDAPDN)LDAP_MALLOCX( sizeof(LDAPRDN *) * (nrdns+1), ctx ); if ( newDN == NULL ) { rc = LDAP_NO_MEMORY; goto parsing_error; } else { int i; if ( LDAP_DN_DCE( flags ) ) { /* add in reversed order */ for ( i=0; i= 0; nrdns-- ) { ldap_rdnfree_x( tmpDN[nrdns], ctx ); } return_result:; if ( tmpDN != tmpDN_ ) { LDAP_FREEX( tmpDN, ctx ); } Debug3( LDAP_DEBUG_ARGS, "<= ldap_bv2dn(%s)=%d %s\n", str, rc, rc ? ldap_err2string( rc ) : "" ); *dn = newDN; return( rc ); } /* * ldap_str2rdn * * Parses a relative DN according to flags up to a rdn separator * or to the end of str. * Returns the rdn and a pointer to the string continuation, which * corresponds to the rdn separator or to '\0' in case the string is over. */ int ldap_str2rdn( LDAP_CONST char *str, LDAPRDN *rdn, char **n_in, unsigned flags ) { struct berval bv; assert( str != NULL ); assert( str[ 0 ] != '\0' ); /* FIXME: is this required? */ bv.bv_len = strlen( str ); bv.bv_val = (char *) str; return ldap_bv2rdn_x( &bv, rdn, n_in, flags, NULL ); } int ldap_bv2rdn( struct berval *bv, LDAPRDN *rdn, char **n_in, unsigned flags ) { return ldap_bv2rdn_x( bv, rdn, n_in, flags, NULL ); } int ldap_bv2rdn_x( struct berval *bv, LDAPRDN *rdn, char **n_in, unsigned flags, void *ctx ) { const char **n = (const char **) n_in; const char *p; int navas = 0; int state = B4AVA; int rc = LDAP_DECODING_ERROR; int attrTypeEncoding = LDAP_AVA_STRING, attrValueEncoding = LDAP_AVA_STRING; struct berval attrType = BER_BVNULL; struct berval attrValue = BER_BVNULL; LDAPRDN newRDN = NULL; LDAPAVA *tmpRDN_[TMP_AVA_SLOTS], **tmpRDN = tmpRDN_; int num_slots = TMP_AVA_SLOTS; char *str; ber_len_t stoplen; assert( bv != NULL ); assert( bv->bv_len != 0 ); assert( bv->bv_val != NULL ); assert( rdn || flags & LDAP_DN_SKIP ); assert( n != NULL ); str = bv->bv_val; stoplen = bv->bv_len; if ( rdn ) { *rdn = NULL; } *n = NULL; switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAP: case LDAP_DN_FORMAT_LDAPV3: case LDAP_DN_FORMAT_LDAPV2: case LDAP_DN_FORMAT_DCE: break; /* unsupported in str2dn */ case LDAP_DN_FORMAT_UFN: case LDAP_DN_FORMAT_AD_CANONICAL: return LDAP_PARAM_ERROR; case LDAP_DN_FORMAT_LBER: default: return LDAP_PARAM_ERROR; } if ( bv->bv_len == 0 ) { return LDAP_SUCCESS; } if( memchr( bv->bv_val, '\0', bv->bv_len ) != NULL ) { /* value must have embedded NULs */ return LDAP_DECODING_ERROR; } p = str; for ( ; p[ 0 ] || state == GOTAVA; ) { /* * The parser in principle advances one token a time, * or toggles state if preferable. */ switch (state) { /* * an AttributeType can be encoded as: * - its string representation; in detail, implementations * MUST recognize AttributeType string type names listed * in Section 3 of RFC 4514, and MAY recognize other names. * - its numeric OID (a dotted decimal string) */ case B4AVA: if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) { if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) { /* error */ goto parsing_error; } p++; } if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) { if ( !LDAP_DN_ALLOW_SPACES( flags ) ) { /* error */ goto parsing_error; } /* whitespace is allowed (and trimmed) */ p++; while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) { p++; } if ( !p[ 0 ] ) { /* error: we expected an AVA */ goto parsing_error; } } /* oid */ if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) { state = B4OIDATTRTYPE; break; } /* else must be alpha */ if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) { goto parsing_error; } /* LDAPv2 "oid." prefix */ if ( LDAP_DN_LDAPV2( flags ) ) { /* * to be overly pedantic, we only accept * "OID." or "oid." */ if ( flags & LDAP_DN_PEDANTIC ) { if ( !strncmp( p, "OID.", 4 ) || !strncmp( p, "oid.", 4 ) ) { p += 4; state = B4OIDATTRTYPE; break; } } else { if ( !strncasecmp( p, "oid.", 4 ) ) { p += 4; state = B4OIDATTRTYPE; break; } } } state = B4STRINGATTRTYPE; break; case B4OIDATTRTYPE: { int err = LDAP_SUCCESS; attrType.bv_val = ldap_int_parse_numericoid( &p, &err, LDAP_SCHEMA_SKIP); if ( err != LDAP_SUCCESS ) { goto parsing_error; } attrType.bv_len = p - attrType.bv_val; attrTypeEncoding = LDAP_AVA_BINARY; state = B4AVAEQUALS; break; } case B4STRINGATTRTYPE: { const char *startPos, *endPos = NULL; ber_len_t len; /* * the starting char has been found to be * a LDAP_DN_DESC_LEADCHAR so we don't re-check it * FIXME: DCE attr types seem to have a more * restrictive syntax (no '-' ...) */ for ( startPos = p++; p[ 0 ]; p++ ) { if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) { continue; } if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) { /* * RFC 4514 explicitly does not allow attribute * description options, such as language tags. */ if ( flags & LDAP_DN_PEDANTIC ) { goto parsing_error; } /* * we trim ';' and following lang * and so from attribute types */ endPos = p; for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] ) || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) { /* no op */ ; } break; } break; } len = ( endPos ? endPos : p ) - startPos; if ( len == 0 ) { goto parsing_error; } attrTypeEncoding = LDAP_AVA_STRING; /* * here we need to decide whether to use it as is * or turn it in OID form; as a consequence, we * need to decide whether to binary encode the value */ state = B4AVAEQUALS; if ( flags & LDAP_DN_SKIP ) { break; } attrType.bv_val = (char *)startPos; attrType.bv_len = len; break; } case B4AVAEQUALS: /* spaces may not be allowed */ if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) { if ( !LDAP_DN_ALLOW_SPACES( flags ) ) { goto parsing_error; } /* trim spaces */ for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) { /* no op */ } } /* need equal sign */ if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) { goto parsing_error; } p++; /* spaces may not be allowed */ if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) { if ( !LDAP_DN_ALLOW_SPACES( flags ) ) { goto parsing_error; } /* trim spaces */ for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) { /* no op */ } } /* * octothorpe means a BER encoded value will follow * FIXME: I don't think DCE will allow it */ if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) { p++; attrValueEncoding = LDAP_AVA_BINARY; state = B4BINARYVALUE; break; } /* STRING value expected */ /* * if we're pedantic, an attribute type in OID form * SHOULD imply a BER encoded attribute value; we * should at least issue a warning */ if ( ( flags & LDAP_DN_PEDANTIC ) && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) { /* OID attrType SHOULD use binary encoding */ goto parsing_error; } attrValueEncoding = LDAP_AVA_STRING; /* * LDAPv2 allows the attribute value to be quoted; * also, IA5 values are expected, in principle */ if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) { if ( LDAP_DN_QUOTES( p[ 0 ] ) ) { p++; state = B4IA5VALUEQUOTED; break; } if ( LDAP_DN_LDAPV2( flags ) ) { state = B4IA5VALUE; break; } } /* * here STRING means RFC 4514 string * FIXME: what about DCE strings? */ if ( !p[ 0 ] ) { /* empty value */ state = GOTAVA; } else { state = B4STRINGVALUE; } break; case B4BINARYVALUE: if ( hexstr2binval( p, &attrValue, &p, flags, ctx ) ) { goto parsing_error; } state = GOTAVA; break; case B4STRINGVALUE: switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAP: case LDAP_DN_FORMAT_LDAPV3: if ( str2strval( p, stoplen - ( p - str ), &attrValue, &p, flags, &attrValueEncoding, ctx ) ) { goto parsing_error; } break; case LDAP_DN_FORMAT_DCE: if ( DCE2strval( p, &attrValue, &p, flags, ctx ) ) { goto parsing_error; } break; default: assert( 0 ); } state = GOTAVA; break; case B4IA5VALUE: if ( IA52strval( p, &attrValue, &p, flags, ctx ) ) { goto parsing_error; } state = GOTAVA; break; case B4IA5VALUEQUOTED: /* lead quote already stripped */ if ( quotedIA52strval( p, &attrValue, &p, flags, ctx ) ) { goto parsing_error; } state = GOTAVA; break; case GOTAVA: { int rdnsep = 0; if ( !( flags & LDAP_DN_SKIP ) ) { LDAPAVA *ava; /* * we accept empty values */ ava = ldapava_new( &attrType, &attrValue, attrValueEncoding, ctx ); if ( ava == NULL ) { rc = LDAP_NO_MEMORY; goto parsing_error; } tmpRDN[navas++] = ava; attrValue.bv_val = NULL; attrValue.bv_len = 0; /* * prepare room for new AVAs if needed */ if (navas == num_slots) { LDAPAVA **tmp; if ( tmpRDN == tmpRDN_ ) { tmp = LDAP_MALLOCX( num_slots * 2 * sizeof( LDAPAVA * ), ctx ); if ( tmp == NULL ) { rc = LDAP_NO_MEMORY; goto parsing_error; } AC_MEMCPY( tmp, tmpRDN, num_slots * sizeof( LDAPAVA * ) ); } else { tmp = LDAP_REALLOCX( tmpRDN, num_slots * 2 * sizeof( LDAPAVA * ), ctx ); if ( tmp == NULL ) { rc = LDAP_NO_MEMORY; goto parsing_error; } } tmpRDN = tmp; num_slots *= 2; } } /* * if we got an AVA separator ('+', or ',' for DCE ) * we expect a new AVA for this RDN; otherwise * we add the RDN to the DN */ switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAP: case LDAP_DN_FORMAT_LDAPV3: case LDAP_DN_FORMAT_LDAPV2: if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) { rdnsep = 1; } break; case LDAP_DN_FORMAT_DCE: if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) { rdnsep = 1; } break; } if ( rdnsep ) { /* * the RDN is over, phew */ *n = p; if ( !( flags & LDAP_DN_SKIP ) ) { newRDN = (LDAPRDN)LDAP_MALLOCX( sizeof(LDAPAVA) * (navas+1), ctx ); if ( newRDN == NULL ) { rc = LDAP_NO_MEMORY; goto parsing_error; } else { AC_MEMCPY( newRDN, tmpRDN, sizeof(LDAPAVA *) * navas); newRDN[navas] = NULL; } } rc = LDAP_SUCCESS; goto return_result; } /* they should have been used in an AVA */ attrType.bv_val = NULL; attrValue.bv_val = NULL; p++; state = B4AVA; break; } default: assert( 0 ); goto parsing_error; } } *n = p; parsing_error:; /* They are set to NULL after they're used in an AVA */ if ( attrValue.bv_val ) { LDAP_FREEX( attrValue.bv_val, ctx ); } for ( navas-- ; navas >= 0; navas-- ) { ldapava_free( tmpRDN[navas], ctx ); } return_result:; if ( tmpRDN != tmpRDN_ ) { LDAP_FREEX( tmpRDN, ctx ); } if ( rdn ) { *rdn = newRDN; } return( rc ); } /* * reads in a UTF-8 string value, unescaping stuff: * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c' * '\' + HEXPAIR(p) -> unhex(p) */ static int str2strval( const char *str, ber_len_t stoplen, struct berval *val, const char **next, unsigned flags, int *retFlags, void *ctx ) { const char *p, *end, *startPos, *endPos = NULL; ber_len_t len, escapes; assert( str != NULL ); assert( val != NULL ); assert( next != NULL ); *next = NULL; end = str + stoplen; for ( startPos = p = str, escapes = 0; p < end; p++ ) { if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) { p++; if ( p[ 0 ] == '\0' ) { return( 1 ); } if ( LDAP_DN_MAYESCAPE( p[ 0 ] ) ) { escapes++; continue; } if ( LDAP_DN_HEXPAIR( p ) ) { char c; hexstr2bin( p, &c ); escapes += 2; if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) { /* * we assume the string is UTF-8 */ *retFlags = LDAP_AVA_NONPRINTABLE; } p++; continue; } if ( LDAP_DN_PEDANTIC & flags ) { return( 1 ); } /* * we do not allow escaping * of chars that don't need * to and do not belong to * HEXDIGITS */ return( 1 ); } else if ( !LDAP_DN_ASCII_PRINTABLE( p[ 0 ] ) ) { if ( p[ 0 ] == '\0' ) { return( 1 ); } *retFlags = LDAP_AVA_NONPRINTABLE; } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) { break; } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) { /* * FIXME: maybe we can add * escapes if not pedantic? */ return( 1 ); } } /* * we do allow unescaped spaces at the end * of the value only in non-pedantic mode */ if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) && !LDAP_DN_ESCAPE( p[ -2 ] ) ) { if ( flags & LDAP_DN_PEDANTIC ) { return( 1 ); } /* strip trailing (unescaped) spaces */ for ( endPos = p - 1; endPos > startPos + 1 && LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) && !LDAP_DN_ESCAPE( endPos[ -2 ] ); endPos-- ) { /* no op */ } } *next = p; if ( flags & LDAP_DN_SKIP ) { return( 0 ); } /* * FIXME: test memory? */ len = ( endPos ? endPos : p ) - startPos - escapes; val->bv_len = len; if ( escapes == 0 ) { if ( *retFlags & LDAP_AVA_NONPRINTABLE ) { val->bv_val = LDAP_MALLOCX( len + 1, ctx ); if ( val->bv_val == NULL ) { return( 1 ); } AC_MEMCPY( val->bv_val, startPos, len ); val->bv_val[ len ] = '\0'; } else { val->bv_val = LDAP_STRNDUPX( startPos, len, ctx ); } } else { ber_len_t s, d; val->bv_val = LDAP_MALLOCX( len + 1, ctx ); if ( val->bv_val == NULL ) { return( 1 ); } for ( s = 0, d = 0; d < len; ) { if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) { s++; if ( LDAP_DN_MAYESCAPE( startPos[ s ] ) ) { val->bv_val[ d++ ] = startPos[ s++ ]; } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) { char c; hexstr2bin( &startPos[ s ], &c ); val->bv_val[ d++ ] = c; s += 2; } else { /* we should never get here */ assert( 0 ); } } else { val->bv_val[ d++ ] = startPos[ s++ ]; } } val->bv_val[ d ] = '\0'; assert( d == len ); } return( 0 ); } static int DCE2strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx ) { const char *p, *startPos, *endPos = NULL; ber_len_t len, escapes; assert( str != NULL ); assert( val != NULL ); assert( next != NULL ); *next = NULL; for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) { if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) { p++; if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) { escapes++; } else { return( 1 ); } } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) { break; } /* * FIXME: can we accept anything else? I guess we need * to stop if a value is not legal */ } /* * (unescaped) trailing spaces are trimmed must be silently ignored; * so we eat them */ if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) && !LDAP_DN_ESCAPE( p[ -2 ] ) ) { if ( flags & LDAP_DN_PEDANTIC ) { return( 1 ); } /* strip trailing (unescaped) spaces */ for ( endPos = p - 1; endPos > startPos + 1 && LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) && !LDAP_DN_ESCAPE( endPos[ -2 ] ); endPos-- ) { /* no op */ } } *next = p; if ( flags & LDAP_DN_SKIP ) { return( 0 ); } len = ( endPos ? endPos : p ) - startPos - escapes; val->bv_len = len; if ( escapes == 0 ){ val->bv_val = LDAP_STRNDUPX( startPos, len, ctx ); } else { ber_len_t s, d; val->bv_val = LDAP_MALLOCX( len + 1, ctx ); if ( val->bv_val == NULL ) { return( 1 ); } for ( s = 0, d = 0; d < len; ) { /* * This point is reached only if escapes * are properly used, so all we need to * do is eat them */ if ( LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) { s++; } val->bv_val[ d++ ] = startPos[ s++ ]; } val->bv_val[ d ] = '\0'; assert( strlen( val->bv_val ) == len ); } return( 0 ); } static int IA52strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx ) { const char *p, *startPos, *endPos = NULL; ber_len_t len, escapes; assert( str != NULL ); assert( val != NULL ); assert( next != NULL ); *next = NULL; /* * LDAPv2 (RFC 1779) */ for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) { if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) { p++; if ( p[ 0 ] == '\0' ) { return( 1 ); } if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] ) && ( LDAP_DN_PEDANTIC & flags ) ) { return( 1 ); } escapes++; } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) { break; } /* * FIXME: can we accept anything else? I guess we need * to stop if a value is not legal */ } /* strip trailing (unescaped) spaces */ for ( endPos = p; endPos > startPos + 1 && LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) && !LDAP_DN_ESCAPE( endPos[ -2 ] ); endPos-- ) { /* no op */ } *next = p; if ( flags & LDAP_DN_SKIP ) { return( 0 ); } len = ( endPos ? endPos : p ) - startPos - escapes; val->bv_len = len; if ( escapes == 0 ) { val->bv_val = LDAP_STRNDUPX( startPos, len, ctx ); } else { ber_len_t s, d; val->bv_val = LDAP_MALLOCX( len + 1, ctx ); if ( val->bv_val == NULL ) { return( 1 ); } for ( s = 0, d = 0; d < len; ) { if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) { s++; } val->bv_val[ d++ ] = startPos[ s++ ]; } val->bv_val[ d ] = '\0'; assert( strlen( val->bv_val ) == len ); } return( 0 ); } static int quotedIA52strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx ) { const char *p, *startPos, *endPos = NULL; ber_len_t len; unsigned escapes = 0; assert( str != NULL ); assert( val != NULL ); assert( next != NULL ); *next = NULL; /* initial quote already eaten */ for ( startPos = p = str; p[ 0 ]; p++ ) { /* * According to RFC 1779, the quoted value can * contain escaped as well as unescaped special values; * as a consequence we tolerate escaped values * (e.g. '"\,"' -> '\,') and escape unescaped specials * (e.g. '","' -> '\,'). */ if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) { if ( p[ 1 ] == '\0' ) { return( 1 ); } p++; if ( !LDAP_DN_V2_PAIR( p[ 0 ] ) && ( LDAP_DN_PEDANTIC & flags ) ) { /* * do we allow to escape normal chars? * LDAPv2 does not allow any mechanism * for escaping chars with '\' and hex * pair */ return( 1 ); } escapes++; } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) { endPos = p; /* eat closing quotes */ p++; break; } /* * FIXME: can we accept anything else? I guess we need * to stop if a value is not legal */ } if ( endPos == NULL ) { return( 1 ); } /* Strip trailing (unescaped) spaces */ for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) { /* no op */ } *next = p; if ( flags & LDAP_DN_SKIP ) { return( 0 ); } len = endPos - startPos - escapes; assert( endPos >= startPos + escapes ); val->bv_len = len; if ( escapes == 0 ) { val->bv_val = LDAP_STRNDUPX( startPos, len, ctx ); } else { ber_len_t s, d; val->bv_val = LDAP_MALLOCX( len + 1, ctx ); if ( val->bv_val == NULL ) { return( 1 ); } val->bv_len = len; for ( s = d = 0; d < len; ) { if ( LDAP_DN_ESCAPE( str[ s ] ) ) { s++; } val->bv_val[ d++ ] = str[ s++ ]; } val->bv_val[ d ] = '\0'; assert( strlen( val->bv_val ) == len ); } return( 0 ); } static int hexstr2bin( const char *str, char *c ) { char c1, c2; assert( str != NULL ); assert( c != NULL ); c1 = str[ 0 ]; c2 = str[ 1 ]; if ( LDAP_DN_ASCII_DIGIT( c1 ) ) { *c = c1 - '0'; } else { if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c1 ) ) { *c = c1 - 'A' + 10; } else { assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) ); *c = c1 - 'a' + 10; } } *c <<= 4; if ( LDAP_DN_ASCII_DIGIT( c2 ) ) { *c += c2 - '0'; } else { if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c2 ) ) { *c += c2 - 'A' + 10; } else { assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) ); *c += c2 - 'a' + 10; } } return( 0 ); } static int hexstr2binval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx ) { const char *p, *startPos, *endPos = NULL; ber_len_t len; ber_len_t s, d; assert( str != NULL ); assert( val != NULL ); assert( next != NULL ); *next = NULL; for ( startPos = p = str; p[ 0 ]; p += 2 ) { switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAPV3: if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) { goto end_of_value; } break; case LDAP_DN_FORMAT_LDAP: case LDAP_DN_FORMAT_LDAPV2: if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) { goto end_of_value; } break; case LDAP_DN_FORMAT_DCE: if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) { goto end_of_value; } break; } if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) { if ( flags & LDAP_DN_PEDANTIC ) { return( 1 ); } endPos = p; for ( ; p[ 0 ]; p++ ) { switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAPV3: if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) { goto end_of_value; } break; case LDAP_DN_FORMAT_LDAP: case LDAP_DN_FORMAT_LDAPV2: if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) { goto end_of_value; } break; case LDAP_DN_FORMAT_DCE: if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) { goto end_of_value; } break; } } break; } if ( !LDAP_DN_HEXPAIR( p ) ) { return( 1 ); } } end_of_value:; *next = p; if ( flags & LDAP_DN_SKIP ) { return( 0 ); } len = ( ( endPos ? endPos : p ) - startPos ) / 2; /* must be even! */ assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos )); val->bv_len = len; val->bv_val = LDAP_MALLOCX( len + 1, ctx ); if ( val->bv_val == NULL ) { return( LDAP_NO_MEMORY ); } for ( s = 0, d = 0; d < len; s += 2, d++ ) { char c; hexstr2bin( &startPos[ s ], &c ); val->bv_val[ d ] = c; } val->bv_val[ d ] = '\0'; return( 0 ); } /* * convert a byte in a hexadecimal pair */ static int byte2hexpair( const char *val, char *pair ) { static const char hexdig[] = "0123456789ABCDEF"; assert( val != NULL ); assert( pair != NULL ); /* * we assume the string has enough room for the hex encoding * of the value */ pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ]; pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ]; return( 0 ); } /* * convert a binary value in hexadecimal pairs */ static int binval2hexstr( struct berval *val, char *str ) { ber_len_t s, d; assert( val != NULL ); assert( str != NULL ); if ( val->bv_len == 0 ) { return( 0 ); } /* * we assume the string has enough room for the hex encoding * of the value */ for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) { byte2hexpair( &val->bv_val[ s ], &str[ d ] ); } return( 0 ); } /* * Length of the string representation, accounting for escaped hex * of UTF-8 chars */ static int strval2strlen( struct berval *val, unsigned flags, ber_len_t *len ) { ber_len_t l, cl = 1; char *p, *end; int escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3; #ifdef PRETTY_ESCAPE int escaped_ascii_len = LDAP_DN_IS_PRETTY( flags ) ? 2 : 3; #endif /* PRETTY_ESCAPE */ assert( val != NULL ); assert( len != NULL ); *len = 0; if ( val->bv_len == 0 ) { return( 0 ); } end = val->bv_val + val->bv_len - 1; for ( l = 0, p = val->bv_val; p <= end; p += cl ) { /* * escape '%x00' */ if ( p[ 0 ] == '\0' ) { cl = 1; l += 3; continue; } cl = LDAP_UTF8_CHARLEN2( p, cl ); if ( cl == 0 ) { /* illegal utf-8 char! */ return( -1 ); } else if ( cl > 1 ) { ber_len_t cnt; for ( cnt = 1; cnt < cl; cnt++ ) { if ( ( p[ cnt ] & 0xc0 ) != 0x80 ) { return( -1 ); } } l += escaped_byte_len * cl; } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) || LDAP_DN_SHOULDESCAPE( p[ 0 ] ) || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) ) || ( p == end && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) { #ifdef PRETTY_ESCAPE #if 0 if ( LDAP_DN_WILLESCAPE_HEX( flags, p[ 0 ] ) ) { #else if ( LDAP_DN_WILLESCAPE_CHAR( p[ 0 ] ) ) { #endif /* * there might be some chars we want * to escape in form of a couple * of hexdigits for optimization purposes */ l += 3; } else { l += escaped_ascii_len; } #else /* ! PRETTY_ESCAPE */ l += 3; #endif /* ! PRETTY_ESCAPE */ } else { l++; } } *len = l; return( 0 ); } /* * convert to string representation, escaping with hex the UTF-8 stuff; * assume the destination has enough room for escaping */ static int strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len ) { ber_len_t s, d, end; assert( val != NULL ); assert( str != NULL ); assert( len != NULL ); if ( val->bv_len == 0 ) { *len = 0; return( 0 ); } /* * we assume the string has enough room for the hex encoding * of the value */ for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) { ber_len_t cl; /* * escape '%x00' */ if ( val->bv_val[ s ] == '\0' ) { cl = 1; str[ d++ ] = '\\'; str[ d++ ] = '0'; str[ d++ ] = '0'; s++; continue; } /* * The length was checked in strval2strlen(); */ cl = LDAP_UTF8_CHARLEN( &val->bv_val[ s ] ); /* * there might be some chars we want to escape in form * of a couple of hexdigits for optimization purposes */ if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) ) #ifdef PRETTY_ESCAPE #if 0 || LDAP_DN_WILLESCAPE_HEX( flags, val->bv_val[ s ] ) #else || LDAP_DN_WILLESCAPE_CHAR( val->bv_val[ s ] ) #endif #else /* ! PRETTY_ESCAPE */ || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] ) || LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] ) || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) ) || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) #endif /* ! PRETTY_ESCAPE */ ) { for ( ; cl--; ) { str[ d++ ] = '\\'; byte2hexpair( &val->bv_val[ s ], &str[ d ] ); s++; d += 2; } } else if ( cl > 1 ) { for ( ; cl--; ) { str[ d++ ] = val->bv_val[ s++ ]; } } else { #ifdef PRETTY_ESCAPE if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] ) || LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] ) || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) ) || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) { str[ d++ ] = '\\'; if ( !LDAP_DN_IS_PRETTY( flags ) ) { byte2hexpair( &val->bv_val[ s ], &str[ d ] ); s++; d += 2; continue; } } #endif /* PRETTY_ESCAPE */ str[ d++ ] = val->bv_val[ s++ ]; } } *len = d; return( 0 ); } /* * Length of the IA5 string representation (no UTF-8 allowed) */ static int strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len ) { ber_len_t l; char *p; assert( val != NULL ); assert( len != NULL ); *len = 0; if ( val->bv_len == 0 ) { return( 0 ); } if ( flags & LDAP_AVA_NONPRINTABLE ) { /* * Turn value into a binary encoded BER */ return( -1 ); } else { for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) { if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) || LDAP_DN_SHOULDESCAPE( p[ 0 ] ) || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) ) || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) { l += 2; } else { l++; } } } *len = l; return( 0 ); } /* * convert to string representation (np UTF-8) * assume the destination has enough room for escaping */ static int strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len ) { ber_len_t s, d, end; assert( val != NULL ); assert( str != NULL ); assert( len != NULL ); if ( val->bv_len == 0 ) { *len = 0; return( 0 ); } if ( flags & LDAP_AVA_NONPRINTABLE ) { /* * Turn value into a binary encoded BER */ *len = 0; return( -1 ); } else { /* * we assume the string has enough room for the hex encoding * of the value */ for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) { if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] ) || LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] ) || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) ) || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) { str[ d++ ] = '\\'; } str[ d++ ] = val->bv_val[ s++ ]; } } *len = d; return( 0 ); } /* * Length of the (supposedly) DCE string representation, * accounting for escaped hex of UTF-8 chars */ static int strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len ) { ber_len_t l; char *p; assert( val != NULL ); assert( len != NULL ); *len = 0; if ( val->bv_len == 0 ) { return( 0 ); } if ( flags & LDAP_AVA_NONPRINTABLE ) { /* * FIXME: Turn the value into a binary encoded BER? */ return( -1 ); } else { for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) { if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) { l += 2; } else { l++; } } } *len = l; return( 0 ); } /* * convert to (supposedly) DCE string representation, * escaping with hex the UTF-8 stuff; * assume the destination has enough room for escaping */ static int strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len ) { ber_len_t s, d; assert( val != NULL ); assert( str != NULL ); assert( len != NULL ); if ( val->bv_len == 0 ) { *len = 0; return( 0 ); } if ( flags & LDAP_AVA_NONPRINTABLE ) { /* * FIXME: Turn the value into a binary encoded BER? */ *len = 0; return( -1 ); } else { /* * we assume the string has enough room for the hex encoding * of the value */ for ( s = 0, d = 0; s < val->bv_len; ) { if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) { str[ d++ ] = '\\'; } str[ d++ ] = val->bv_val[ s++ ]; } } *len = d; return( 0 ); } /* * Length of the (supposedly) AD canonical string representation, * accounting for chars that need to be escaped */ static int strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len ) { ber_len_t l, cl; char *p; assert( val != NULL ); assert( len != NULL ); *len = 0; if ( val->bv_len == 0 ) { return( 0 ); } for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) { cl = LDAP_UTF8_CHARLEN2( p, cl ); if ( cl == 0 ) { /* illegal utf-8 char */ return -1; } else if ( (cl == 1) && LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) { l += 2; } else { l += cl; } } *len = l; return( 0 ); } /* * convert to (supposedly) AD string representation, * assume the destination has enough room for escaping */ static int strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len ) { ber_len_t s, d, cl; assert( val != NULL ); assert( str != NULL ); assert( len != NULL ); if ( val->bv_len == 0 ) { *len = 0; return( 0 ); } /* * we assume the string has enough room for the escaping * of the value */ for ( s = 0, d = 0; s < val->bv_len; ) { cl = LDAP_UTF8_CHARLEN2( val->bv_val+s, cl ); if ( cl == 0 ) { /* illegal utf-8 char */ return -1; } else if ( (cl == 1) && LDAP_DN_NEEDESCAPE_AD(val->bv_val[ s ]) ) { str[ d++ ] = '\\'; } for (; cl--;) { str[ d++ ] = val->bv_val[ s++ ]; } } *len = d; return( 0 ); } /* * If the DN is terminated by single-AVA RDNs with attribute type of "dc", * the first part of the AD representation of the DN is written in DNS * form, i.e. dot separated domain name components (as suggested * by Luke Howard, http://www.padl.com/~lukeh) */ static int dn2domain( LDAPDN dn, struct berval *bv, int pos, int *iRDN ) { int i; int domain = 0, first = 1; ber_len_t l = 1; /* we move the null also */ char *str; /* we are guaranteed there's enough memory in str */ /* sanity */ assert( dn != NULL ); assert( bv != NULL ); assert( iRDN != NULL ); assert( *iRDN >= 0 ); str = bv->bv_val + pos; for ( i = *iRDN; i >= 0; i-- ) { LDAPRDN rdn; LDAPAVA *ava; assert( dn[ i ] != NULL ); rdn = dn[ i ]; assert( rdn[ 0 ] != NULL ); ava = rdn[ 0 ]; if ( !LDAP_DN_IS_RDN_DC( rdn ) ) { break; } if ( ldif_is_not_printable( ava->la_value.bv_val, ava->la_value.bv_len ) ) { domain = 0; break; } domain = 1; if ( first ) { first = 0; AC_MEMCPY( str, ava->la_value.bv_val, ava->la_value.bv_len + 1); l += ava->la_value.bv_len; } else { AC_MEMCPY( str + ava->la_value.bv_len + 1, bv->bv_val + pos, l); AC_MEMCPY( str, ava->la_value.bv_val, ava->la_value.bv_len ); str[ ava->la_value.bv_len ] = '.'; l += ava->la_value.bv_len + 1; } } *iRDN = i; bv->bv_len = pos + l - 1; return( domain ); } static int rdn2strlen( LDAPRDN rdn, unsigned flags, ber_len_t *len, int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) ) { int iAVA; ber_len_t l = 0; *len = 0; for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { LDAPAVA *ava = rdn[ iAVA ]; /* len(type) + '=' + '+' | ',' */ l += ava->la_attr.bv_len + 2; if ( ava->la_flags & LDAP_AVA_BINARY ) { /* octothorpe + twice the length */ l += 1 + 2 * ava->la_value.bv_len; } else { ber_len_t vl; unsigned f = flags | ava->la_flags; if ( ( *s2l )( &ava->la_value, f, &vl ) ) { return( -1 ); } l += vl; } } *len = l; return( 0 ); } static int rdn2str( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) ) { int iAVA; ber_len_t l = 0; for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { LDAPAVA *ava = rdn[ iAVA ]; AC_MEMCPY( &str[ l ], ava->la_attr.bv_val, ava->la_attr.bv_len ); l += ava->la_attr.bv_len; str[ l++ ] = '='; if ( ava->la_flags & LDAP_AVA_BINARY ) { str[ l++ ] = '#'; if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) { return( -1 ); } l += 2 * ava->la_value.bv_len; } else { ber_len_t vl; unsigned f = flags | ava->la_flags; if ( ( *s2s )( &ava->la_value, &str[ l ], f, &vl ) ) { return( -1 ); } l += vl; } str[ l++ ] = ( rdn[ iAVA + 1] ? '+' : ',' ); } *len = l; return( 0 ); } static int rdn2DCEstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len ) { int iAVA; ber_len_t l = 0; *len = 0; for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { LDAPAVA *ava = rdn[ iAVA ]; /* len(type) + '=' + ',' | '/' */ l += ava->la_attr.bv_len + 2; if ( ava->la_flags & LDAP_AVA_BINARY ) { /* octothorpe + twice the length */ l += 1 + 2 * ava->la_value.bv_len; } else { ber_len_t vl; unsigned f = flags | ava->la_flags; if ( strval2DCEstrlen( &ava->la_value, f, &vl ) ) { return( -1 ); } l += vl; } } *len = l; return( 0 ); } static int rdn2DCEstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first ) { int iAVA; ber_len_t l = 0; for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { LDAPAVA *ava = rdn[ iAVA ]; if ( first ) { first = 0; } else { str[ l++ ] = ( iAVA ? ',' : '/' ); } AC_MEMCPY( &str[ l ], ava->la_attr.bv_val, ava->la_attr.bv_len ); l += ava->la_attr.bv_len; str[ l++ ] = '='; if ( ava->la_flags & LDAP_AVA_BINARY ) { str[ l++ ] = '#'; if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) { return( -1 ); } l += 2 * ava->la_value.bv_len; } else { ber_len_t vl; unsigned f = flags | ava->la_flags; if ( strval2DCEstr( &ava->la_value, &str[ l ], f, &vl ) ) { return( -1 ); } l += vl; } } *len = l; return( 0 ); } static int rdn2UFNstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len ) { int iAVA; ber_len_t l = 0; assert( rdn != NULL ); assert( len != NULL ); *len = 0; for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { LDAPAVA *ava = rdn[ iAVA ]; /* ' + ' | ', ' */ l += ( rdn[ iAVA + 1 ] ? 3 : 2 ); /* FIXME: are binary values allowed in UFN? */ if ( ava->la_flags & LDAP_AVA_BINARY ) { /* octothorpe + twice the value */ l += 1 + 2 * ava->la_value.bv_len; } else { ber_len_t vl; unsigned f = flags | ava->la_flags; if ( strval2strlen( &ava->la_value, f, &vl ) ) { return( -1 ); } l += vl; } } *len = l; return( 0 ); } static int rdn2UFNstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len ) { int iAVA; ber_len_t l = 0; for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { LDAPAVA *ava = rdn[ iAVA ]; if ( ava->la_flags & LDAP_AVA_BINARY ) { str[ l++ ] = '#'; if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) { return( -1 ); } l += 2 * ava->la_value.bv_len; } else { ber_len_t vl; unsigned f = flags | ava->la_flags; if ( strval2str( &ava->la_value, &str[ l ], f, &vl ) ) { return( -1 ); } l += vl; } if ( rdn[ iAVA + 1 ] ) { AC_MEMCPY( &str[ l ], " + ", 3 ); l += 3; } else { AC_MEMCPY( &str[ l ], ", ", 2 ); l += 2; } } *len = l; return( 0 ); } static int rdn2ADstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len ) { int iAVA; ber_len_t l = 0; assert( rdn != NULL ); assert( len != NULL ); *len = 0; for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { LDAPAVA *ava = rdn[ iAVA ]; /* ',' | '/' */ l++; /* FIXME: are binary values allowed in UFN? */ if ( ava->la_flags & LDAP_AVA_BINARY ) { /* octothorpe + twice the value */ l += 1 + 2 * ava->la_value.bv_len; } else { ber_len_t vl; unsigned f = flags | ava->la_flags; if ( strval2ADstrlen( &ava->la_value, f, &vl ) ) { return( -1 ); } l += vl; } } *len = l; return( 0 ); } static int rdn2ADstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first ) { int iAVA; ber_len_t l = 0; for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { LDAPAVA *ava = rdn[ iAVA ]; if ( first ) { first = 0; } else { str[ l++ ] = ( iAVA ? ',' : '/' ); } if ( ava->la_flags & LDAP_AVA_BINARY ) { str[ l++ ] = '#'; if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) { return( -1 ); } l += 2 * ava->la_value.bv_len; } else { ber_len_t vl; unsigned f = flags | ava->la_flags; if ( strval2ADstr( &ava->la_value, &str[ l ], f, &vl ) ) { return( -1 ); } l += vl; } } *len = l; return( 0 ); } /* * ldap_rdn2str * * Returns in str a string representation of rdn based on flags. * There is some duplication of code between this and ldap_dn2str; * this is wanted to reduce the allocation of temporary buffers. */ int ldap_rdn2str( LDAPRDN rdn, char **str, unsigned flags ) { struct berval bv; int rc; assert( str != NULL ); if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) { return LDAP_PARAM_ERROR; } rc = ldap_rdn2bv_x( rdn, &bv, flags, NULL ); *str = bv.bv_val; return rc; } int ldap_rdn2bv( LDAPRDN rdn, struct berval *bv, unsigned flags ) { return ldap_rdn2bv_x( rdn, bv, flags, NULL ); } int ldap_rdn2bv_x( LDAPRDN rdn, struct berval *bv, unsigned flags, void *ctx ) { int rc, back; ber_len_t l; assert( bv != NULL ); bv->bv_len = 0; bv->bv_val = NULL; if ( rdn == NULL ) { bv->bv_val = LDAP_STRDUPX( "", ctx ); return( LDAP_SUCCESS ); } /* * This routine wastes "back" bytes at the end of the string */ switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAPV3: if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) { return LDAP_DECODING_ERROR; } break; case LDAP_DN_FORMAT_LDAPV2: if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) { return LDAP_DECODING_ERROR; } break; case LDAP_DN_FORMAT_UFN: if ( rdn2UFNstrlen( rdn, flags, &l ) ) { return LDAP_DECODING_ERROR; } break; case LDAP_DN_FORMAT_DCE: if ( rdn2DCEstrlen( rdn, flags, &l ) ) { return LDAP_DECODING_ERROR; } break; case LDAP_DN_FORMAT_AD_CANONICAL: if ( rdn2ADstrlen( rdn, flags, &l ) ) { return LDAP_DECODING_ERROR; } break; default: return LDAP_PARAM_ERROR; } bv->bv_val = LDAP_MALLOCX( l + 1, ctx ); if ( bv->bv_val == NULL ) { return LDAP_NO_MEMORY; } switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAPV3: rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2str ); back = 1; break; case LDAP_DN_FORMAT_LDAPV2: rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2IA5str ); back = 1; break; case LDAP_DN_FORMAT_UFN: rc = rdn2UFNstr( rdn, bv->bv_val, flags, &l ); back = 2; break; case LDAP_DN_FORMAT_DCE: rc = rdn2DCEstr( rdn, bv->bv_val, flags, &l, 1 ); back = 0; break; case LDAP_DN_FORMAT_AD_CANONICAL: rc = rdn2ADstr( rdn, bv->bv_val, flags, &l, 1 ); back = 0; break; default: /* need at least one of the previous */ return LDAP_PARAM_ERROR; } if ( rc ) { LDAP_FREEX( bv->bv_val, ctx ); return rc; } bv->bv_len = l - back; bv->bv_val[ bv->bv_len ] = '\0'; return LDAP_SUCCESS; } /* * Very bulk implementation; many optimizations can be performed * - a NULL dn results in an empty string "" * * FIXME: doubts * a) what do we do if a UTF-8 string must be converted in LDAPv2? * we must encode it in binary form ('#' + HEXPAIRs) * b) does DCE/AD support UTF-8? * no clue; don't think so. * c) what do we do when binary values must be converted in UTF/DCE/AD? * use binary encoded BER */ int ldap_dn2str( LDAPDN dn, char **str, unsigned flags ) { struct berval bv; int rc; assert( str != NULL ); if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) { return LDAP_PARAM_ERROR; } rc = ldap_dn2bv_x( dn, &bv, flags, NULL ); *str = bv.bv_val; return rc; } int ldap_dn2bv( LDAPDN dn, struct berval *bv, unsigned flags ) { return ldap_dn2bv_x( dn, bv, flags, NULL ); } int ldap_dn2bv_x( LDAPDN dn, struct berval *bv, unsigned flags, void *ctx ) { int iRDN; int rc = LDAP_ENCODING_ERROR; ber_len_t len, l; /* stringifying helpers for LDAPv3/LDAPv2 */ int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l ); int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l ); assert( bv != NULL ); bv->bv_len = 0; bv->bv_val = NULL; Debug1( LDAP_DEBUG_ARGS, "=> ldap_dn2bv(%u)\n", flags ); /* * a null dn means an empty dn string * FIXME: better raise an error? */ if ( dn == NULL || dn[0] == NULL ) { bv->bv_val = LDAP_STRDUPX( "", ctx ); return( LDAP_SUCCESS ); } switch ( LDAP_DN_FORMAT( flags ) ) { case LDAP_DN_FORMAT_LDAPV3: sv2l = strval2strlen; sv2s = strval2str; if( 0 ) { case LDAP_DN_FORMAT_LDAPV2: sv2l = strval2IA5strlen; sv2s = strval2IA5str; } for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) { ber_len_t rdnl; if ( rdn2strlen( dn[ iRDN ], flags, &rdnl, sv2l ) ) { goto return_results; } len += rdnl; } if ( ( bv->bv_val = LDAP_MALLOCX( len + 1, ctx ) ) == NULL ) { rc = LDAP_NO_MEMORY; break; } for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) { ber_len_t rdnl; if ( rdn2str( dn[ iRDN ], &bv->bv_val[ l ], flags, &rdnl, sv2s ) ) { LDAP_FREEX( bv->bv_val, ctx ); bv->bv_val = NULL; goto return_results; } l += rdnl; } assert( l == len ); /* * trim the last ',' (the allocated memory * is one byte longer than required) */ bv->bv_len = len - 1; bv->bv_val[ bv->bv_len ] = '\0'; rc = LDAP_SUCCESS; break; case LDAP_DN_FORMAT_UFN: { /* * FIXME: quoting from RFC 1781: * To take a distinguished name, and generate a name of this format with attribute types omitted, the following steps are followed. 1. If the first attribute is of type CommonName, the type may be omitted. 2. If the last attribute is of type Country, the type may be omitted. 3. If the last attribute is of type Country, the last Organisation attribute may have the type omitted. 4. All attributes of type OrganisationalUnit may have the type omitted, unless they are after an Organisation attribute or the first attribute is of type OrganisationalUnit. * this should be the pedantic implementation. * * Here the standard implementation reflects * the one historically provided by OpenLDAP * (and UMIch, I presume), with the variant * of spaces and plusses (' + ') separating * rdn components. * * A non-standard but nice implementation could * be to turn the final "dc" attributes into a * dot-separated domain. * * Other improvements could involve the use of * friendly country names and so. */ #ifdef DC_IN_UFN int leftmost_dc = -1; int last_iRDN = -1; #endif /* DC_IN_UFN */ for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) { ber_len_t rdnl; if ( rdn2UFNstrlen( dn[ iRDN ], flags, &rdnl ) ) { goto return_results; } len += rdnl; #ifdef DC_IN_UFN if ( LDAP_DN_IS_RDN_DC( dn[ iRDN ] ) ) { if ( leftmost_dc == -1 ) { leftmost_dc = iRDN; } } else { leftmost_dc = -1; } #endif /* DC_IN_UFN */ } if ( ( bv->bv_val = LDAP_MALLOCX( len + 1, ctx ) ) == NULL ) { rc = LDAP_NO_MEMORY; break; } #ifdef DC_IN_UFN if ( leftmost_dc == -1 ) { #endif /* DC_IN_UFN */ for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) { ber_len_t vl; if ( rdn2UFNstr( dn[ iRDN ], &bv->bv_val[ l ], flags, &vl ) ) { LDAP_FREEX( bv->bv_val, ctx ); bv->bv_val = NULL; goto return_results; } l += vl; } /* * trim the last ', ' (the allocated memory * is two bytes longer than required) */ bv->bv_len = len - 2; bv->bv_val[ bv->bv_len ] = '\0'; #ifdef DC_IN_UFN } else { last_iRDN = iRDN - 1; for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) { ber_len_t vl; if ( rdn2UFNstr( dn[ iRDN ], &bv->bv_val[ l ], flags, &vl ) ) { LDAP_FREEX( bv->bv_val, ctx ); bv->bv_val = NULL; goto return_results; } l += vl; } if ( !dn2domain( dn, bv, l, &last_iRDN ) ) { LDAP_FREEX( bv->bv_val, ctx ); bv->bv_val = NULL; goto return_results; } /* the string is correctly terminated by dn2domain */ } #endif /* DC_IN_UFN */ rc = LDAP_SUCCESS; } break; case LDAP_DN_FORMAT_DCE: for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) { ber_len_t rdnl; if ( rdn2DCEstrlen( dn[ iRDN ], flags, &rdnl ) ) { goto return_results; } len += rdnl; } if ( ( bv->bv_val = LDAP_MALLOCX( len + 1, ctx ) ) == NULL ) { rc = LDAP_NO_MEMORY; break; } for ( l = 0; iRDN--; ) { ber_len_t rdnl; if ( rdn2DCEstr( dn[ iRDN ], &bv->bv_val[ l ], flags, &rdnl, 0 ) ) { LDAP_FREEX( bv->bv_val, ctx ); bv->bv_val = NULL; goto return_results; } l += rdnl; } assert( l == len ); bv->bv_len = len; bv->bv_val[ bv->bv_len ] = '\0'; rc = LDAP_SUCCESS; break; case LDAP_DN_FORMAT_AD_CANONICAL: { int trailing_slash = 1; /* * Sort of UFN for DCE DNs: a slash ('/') separated * global->local DN with no types; strictly speaking, * the naming context should be a domain, which is * written in DNS-style, e.g. dot-separated. * * Example: * * "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com" * * will read * * "microsoft.com/People/Bill,Gates" */ for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) { ber_len_t rdnl; if ( rdn2ADstrlen( dn[ iRDN ], flags, &rdnl ) ) { goto return_results; } len += rdnl; } /* reserve room for trailing '/' in case the DN * is exactly a domain */ if ( ( bv->bv_val = LDAP_MALLOCX( len + 1 + 1, ctx ) ) == NULL ) { rc = LDAP_NO_MEMORY; break; } iRDN--; if ( iRDN && dn2domain( dn, bv, 0, &iRDN ) != 0 ) { for ( l = bv->bv_len; iRDN >= 0 ; iRDN-- ) { ber_len_t rdnl; trailing_slash = 0; if ( rdn2ADstr( dn[ iRDN ], &bv->bv_val[ l ], flags, &rdnl, 0 ) ) { LDAP_FREEX( bv->bv_val, ctx ); bv->bv_val = NULL; goto return_results; } l += rdnl; } } else { int first = 1; /* * Strictly speaking, AD canonical requires * a DN to be in the form "..., dc=smtg", * i.e. terminated by a domain component */ if ( flags & LDAP_DN_PEDANTIC ) { LDAP_FREEX( bv->bv_val, ctx ); bv->bv_val = NULL; rc = LDAP_ENCODING_ERROR; break; } for ( l = 0; iRDN >= 0 ; iRDN-- ) { ber_len_t rdnl; if ( rdn2ADstr( dn[ iRDN ], &bv->bv_val[ l ], flags, &rdnl, first ) ) { LDAP_FREEX( bv->bv_val, ctx ); bv->bv_val = NULL; goto return_results; } if ( first ) { first = 0; } l += rdnl; } } if ( trailing_slash ) { /* the DN is exactly a domain -- need a trailing * slash; room was reserved in advance */ bv->bv_val[ len ] = '/'; len++; } bv->bv_len = len; bv->bv_val[ bv->bv_len ] = '\0'; rc = LDAP_SUCCESS; } break; default: return LDAP_PARAM_ERROR; } Debug3( LDAP_DEBUG_ARGS, "<= ldap_dn2bv(%s)=%d %s\n", bv->bv_val, rc, rc ? ldap_err2string( rc ) : "" ); return_results:; return( rc ); } openldap-2.5.11+dfsg/libraries/libldap/thr_posix.c0000644000175000017500000002175414172327167020616 0ustar ryanryan/* thr_posix.c - wrapper around posix and posixish thread implementations. */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #if defined( HAVE_PTHREADS ) #ifdef __GLIBC__ #undef _FEATURES_H #define _XOPEN_SOURCE 500 /* For pthread_setconcurrency() on glibc */ #endif #include #ifdef REPLACE_BROKEN_YIELD #ifndef HAVE_NANOSLEEP #include #endif #include #endif #include "ldap_pvt_thread.h" /* Get the thread interface */ #define LDAP_THREAD_IMPLEMENTATION #define LDAP_THREAD_RDWR_IMPLEMENTATION #include "ldap_thr_debug.h" /* May rename the symbols defined below */ #include /* For pthread_kill() */ extern int ldap_int_stackguard; #if HAVE_PTHREADS < 6 # define LDAP_INT_THREAD_ATTR_DEFAULT pthread_attr_default # define LDAP_INT_THREAD_CONDATTR_DEFAULT pthread_condattr_default # define LDAP_INT_THREAD_MUTEXATTR_DEFAULT pthread_mutexattr_default #else # define LDAP_INT_THREAD_ATTR_DEFAULT NULL # define LDAP_INT_THREAD_CONDATTR_DEFAULT NULL # define LDAP_INT_THREAD_MUTEXATTR_DEFAULT NULL #endif #ifdef LDAP_THREAD_DEBUG # if defined LDAP_INT_THREAD_MUTEXATTR /* May be defined in CPPFLAGS */ # elif defined HAVE_PTHREAD_KILL_OTHER_THREADS_NP /* LinuxThreads hack */ # define LDAP_INT_THREAD_MUTEXATTR PTHREAD_MUTEX_ERRORCHECK_NP # else # define LDAP_INT_THREAD_MUTEXATTR PTHREAD_MUTEX_ERRORCHECK # endif static pthread_mutexattr_t mutex_attr; # undef LDAP_INT_THREAD_MUTEXATTR_DEFAULT # define LDAP_INT_THREAD_MUTEXATTR_DEFAULT &mutex_attr #endif static pthread_mutexattr_t mutex_attr_recursive; #if HAVE_PTHREADS < 7 #define ERRVAL(val) ((val) < 0 ? errno : 0) #else #define ERRVAL(val) (val) #endif int ldap_int_thread_initialize( void ) { #ifdef LDAP_INT_THREAD_MUTEXATTR pthread_mutexattr_init( &mutex_attr ); pthread_mutexattr_settype( &mutex_attr, LDAP_INT_THREAD_MUTEXATTR ); #endif if (pthread_mutexattr_init(&mutex_attr_recursive)) return -1; if (pthread_mutexattr_settype(&mutex_attr_recursive, PTHREAD_MUTEX_RECURSIVE)) return -1; return 0; } int ldap_int_thread_destroy( void ) { #ifdef HAVE_PTHREAD_KILL_OTHER_THREADS_NP /* LinuxThreads: kill clones */ pthread_kill_other_threads_np(); #endif #ifdef LDAP_INT_THREAD_MUTEXATTR pthread_mutexattr_destroy( &mutex_attr ); #endif pthread_mutexattr_destroy( &mutex_attr_recursive ); return 0; } #ifdef LDAP_THREAD_HAVE_SETCONCURRENCY int ldap_pvt_thread_set_concurrency(int n) { #ifdef HAVE_PTHREAD_SETCONCURRENCY return pthread_setconcurrency( n ); #elif defined(HAVE_THR_SETCONCURRENCY) return thr_setconcurrency( n ); #else return 0; #endif } #endif #ifdef LDAP_THREAD_HAVE_GETCONCURRENCY int ldap_pvt_thread_get_concurrency(void) { #ifdef HAVE_PTHREAD_GETCONCURRENCY return pthread_getconcurrency(); #elif defined(HAVE_THR_GETCONCURRENCY) return thr_getconcurrency(); #else return 0; #endif } #endif /* detachstate appeared in Draft 6, but without manifest constants. * in Draft 7 they were called PTHREAD_CREATE_UNDETACHED and ...DETACHED. * in Draft 8 on, ...UNDETACHED became ...JOINABLE. */ #ifndef PTHREAD_CREATE_JOINABLE #ifdef PTHREAD_CREATE_UNDETACHED #define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED #else #define PTHREAD_CREATE_JOINABLE 0 #endif #endif #ifndef PTHREAD_CREATE_DETACHED #define PTHREAD_CREATE_DETACHED 1 #endif int ldap_pvt_thread_create( ldap_pvt_thread_t * thread, int detach, void *(*start_routine)( void * ), void *arg) { int rtn; pthread_attr_t attr; /* Always create the thread attrs, so we can set stacksize if we need to */ #if HAVE_PTHREADS > 5 pthread_attr_init(&attr); #else pthread_attr_create(&attr); #endif #ifdef LDAP_PVT_THREAD_SET_STACK_SIZE /* this should be tunable */ pthread_attr_setstacksize( &attr, LDAP_PVT_THREAD_STACK_SIZE ); if ( ldap_int_stackguard ) pthread_attr_setguardsize( &attr, LDAP_PVT_THREAD_STACK_SIZE ); #endif #if HAVE_PTHREADS > 5 detach = detach ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE; #if HAVE_PTHREADS == 6 pthread_attr_setdetachstate(&attr, &detach); #else pthread_attr_setdetachstate(&attr, detach); #endif #endif #if HAVE_PTHREADS < 5 rtn = pthread_create( thread, attr, start_routine, arg ); #else rtn = pthread_create( thread, &attr, start_routine, arg ); #endif #if HAVE_PTHREADS > 5 pthread_attr_destroy(&attr); #else pthread_attr_delete(&attr); if( detach ) { pthread_detach( thread ); } #endif #if HAVE_PTHREADS < 7 if ( rtn < 0 ) rtn = errno; #endif return rtn; } void ldap_pvt_thread_exit( void *retval ) { pthread_exit( retval ); } int ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return ) { #if HAVE_PTHREADS < 7 void *dummy; if (thread_return==NULL) thread_return=&dummy; #endif return ERRVAL( pthread_join( thread, thread_return ) ); } int ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo ) { #if defined(HAVE_PTHREAD_KILL) && HAVE_PTHREADS > 4 /* MacOS 10.1 is detected as v10 but has no pthread_kill() */ return ERRVAL( pthread_kill( thread, signo ) ); #else /* pthread package with DCE */ if (kill( getpid(), signo )<0) return errno; return 0; #endif } int ldap_pvt_thread_yield( void ) { #ifdef REPLACE_BROKEN_YIELD #ifdef HAVE_NANOSLEEP struct timespec t = { 0, 0 }; nanosleep(&t, NULL); #else struct timeval tv = {0,0}; select( 0, NULL, NULL, NULL, &tv ); #endif return 0; #elif defined(HAVE_THR_YIELD) thr_yield(); return 0; #elif HAVE_PTHREADS == 10 return sched_yield(); #elif defined(_POSIX_THREAD_IS_GNU_PTH) sched_yield(); return 0; #elif HAVE_PTHREADS == 6 pthread_yield(NULL); return 0; #else pthread_yield(); return 0; #endif } int ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond ) { return ERRVAL( pthread_cond_init( cond, LDAP_INT_THREAD_CONDATTR_DEFAULT ) ); } int ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cond ) { return ERRVAL( pthread_cond_destroy( cond ) ); } int ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond ) { return ERRVAL( pthread_cond_signal( cond ) ); } int ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cond ) { return ERRVAL( pthread_cond_broadcast( cond ) ); } int ldap_pvt_thread_cond_wait( ldap_pvt_thread_cond_t *cond, ldap_pvt_thread_mutex_t *mutex ) { return ERRVAL( pthread_cond_wait( cond, mutex ) ); } int ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex ) { return ERRVAL( pthread_mutex_init( mutex, LDAP_INT_THREAD_MUTEXATTR_DEFAULT ) ); } int ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex ) { return ERRVAL( pthread_mutex_destroy( mutex ) ); } int ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex ) { return ERRVAL( pthread_mutex_lock( mutex ) ); } int ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mutex ) { return ERRVAL( pthread_mutex_trylock( mutex ) ); } int ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex ) { return ERRVAL( pthread_mutex_unlock( mutex ) ); } int ldap_pvt_thread_mutex_recursive_init( ldap_pvt_thread_mutex_t *mutex ) { return ERRVAL( pthread_mutex_init( mutex, &mutex_attr_recursive ) ); } ldap_pvt_thread_t ldap_pvt_thread_self( void ) { return pthread_self(); } int ldap_pvt_thread_key_create( ldap_pvt_thread_key_t *key ) { return pthread_key_create( key, NULL ); } int ldap_pvt_thread_key_destroy( ldap_pvt_thread_key_t key ) { return pthread_key_delete( key ); } int ldap_pvt_thread_key_setdata( ldap_pvt_thread_key_t key, void *data ) { return pthread_setspecific( key, data ); } int ldap_pvt_thread_key_getdata( ldap_pvt_thread_key_t key, void **data ) { *data = pthread_getspecific( key ); return 0; } #ifdef LDAP_THREAD_HAVE_RDWR #ifdef HAVE_PTHREAD_RWLOCK_DESTROY int ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rw ) { return ERRVAL( pthread_rwlock_init( rw, NULL ) ); } int ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rw ) { return ERRVAL( pthread_rwlock_destroy( rw ) ); } int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rw ) { return ERRVAL( pthread_rwlock_rdlock( rw ) ); } int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rw ) { return ERRVAL( pthread_rwlock_tryrdlock( rw ) ); } int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rw ) { return ERRVAL( pthread_rwlock_unlock( rw ) ); } int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rw ) { return ERRVAL( pthread_rwlock_wrlock( rw ) ); } int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rw ) { return ERRVAL( pthread_rwlock_trywrlock( rw ) ); } int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rw ) { return ERRVAL( pthread_rwlock_unlock( rw ) ); } #endif /* HAVE_PTHREAD_RWLOCK_DESTROY */ #endif /* LDAP_THREAD_HAVE_RDWR */ #endif /* HAVE_PTHREADS */ openldap-2.5.11+dfsg/libraries/libldap/tpool.c0000644000175000017500000011074714172327167017735 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include #include #include "ldap-int.h" #ifdef LDAP_R_COMPILE #include "ldap_pvt_thread.h" /* Get the thread interface */ #include "ldap_queue.h" #define LDAP_THREAD_POOL_IMPLEMENTATION #include "ldap_thr_debug.h" /* May rename symbols defined below */ #ifndef LDAP_THREAD_HAVE_TPOOL #ifndef CACHELINE #define CACHELINE 64 #endif /* Thread-specific key with data and optional free function */ typedef struct ldap_int_tpool_key_s { void *ltk_key; void *ltk_data; ldap_pvt_thread_pool_keyfree_t *ltk_free; } ldap_int_tpool_key_t; /* Max number of thread-specific keys we store per thread. * We don't expect to use many... */ #define MAXKEYS 32 /* Max number of threads */ #define LDAP_MAXTHR 1024 /* must be a power of 2 */ /* (Theoretical) max number of pending requests */ #define MAX_PENDING (INT_MAX/2) /* INT_MAX - (room to avoid overflow) */ /* pool->ltp_pause values */ enum { NOT_PAUSED = 0, WANT_PAUSE = 1, PAUSED = 2 }; /* Context: thread ID and thread-specific key/data pairs */ typedef struct ldap_int_thread_userctx_s { struct ldap_int_thread_poolq_s *ltu_pq; ldap_pvt_thread_t ltu_id; ldap_int_tpool_key_t ltu_key[MAXKEYS]; } ldap_int_thread_userctx_t; /* Simple {thread ID -> context} hash table; key=ctx->ltu_id. * Protected by ldap_pvt_thread_pool_mutex. */ static struct { ldap_int_thread_userctx_t *ctx; /* ctx is valid when not NULL or DELETED_THREAD_CTX */ # define DELETED_THREAD_CTX (&ldap_int_main_thrctx + 1) /* dummy addr */ } thread_keys[LDAP_MAXTHR]; #define TID_HASH(tid, hash) do { \ unsigned const char *ptr_ = (unsigned const char *)&(tid); \ unsigned i_; \ for (i_ = 0, (hash) = ptr_[0]; ++i_ < sizeof(tid);) \ (hash) += ((hash) << 5) ^ ptr_[i_]; \ } while(0) /* Task for a thread to perform */ typedef struct ldap_int_thread_task_s { union { LDAP_STAILQ_ENTRY(ldap_int_thread_task_s) q; LDAP_SLIST_ENTRY(ldap_int_thread_task_s) l; } ltt_next; ldap_pvt_thread_start_t *ltt_start_routine; void *ltt_arg; struct ldap_int_thread_poolq_s *ltt_queue; } ldap_int_thread_task_t; typedef LDAP_STAILQ_HEAD(tcq, ldap_int_thread_task_s) ldap_int_tpool_plist_t; struct ldap_int_thread_poolq_s { void *ltp_free; struct ldap_int_thread_pool_s *ltp_pool; /* protect members below */ ldap_pvt_thread_mutex_t ltp_mutex; /* not paused and something to do for pool_() * Used for normal pool operation, to synch between submitter and * worker threads. Not used for pauses. In normal operation multiple * queues can rendezvous without acquiring the main pool lock. */ ldap_pvt_thread_cond_t ltp_cond; /* ltp_pause == 0 ? <p_pending_list : &empty_pending_list, * maintained to reduce work for pool_wrapper() */ ldap_int_tpool_plist_t *ltp_work_list; /* pending tasks, and unused task objects */ ldap_int_tpool_plist_t ltp_pending_list; LDAP_SLIST_HEAD(tcl, ldap_int_thread_task_s) ltp_free_list; /* Max number of threads in this queue */ int ltp_max_count; /* Max pending + paused + idle tasks, negated when ltp_finishing */ int ltp_max_pending; int ltp_pending_count; /* Pending + paused + idle tasks */ int ltp_active_count; /* Active, not paused/idle tasks */ int ltp_open_count; /* Number of threads */ int ltp_starting; /* Currently starting threads */ }; struct ldap_int_thread_pool_s { LDAP_STAILQ_ENTRY(ldap_int_thread_pool_s) ltp_next; struct ldap_int_thread_poolq_s **ltp_wqs; /* number of poolqs */ int ltp_numqs; /* protect members below */ ldap_pvt_thread_mutex_t ltp_mutex; /* paused and waiting for resume * When a pause is in effect all workers switch to waiting on * this cond instead of their per-queue cond. */ ldap_pvt_thread_cond_t ltp_cond; /* ltp_active_queues < 1 && ltp_pause */ ldap_pvt_thread_cond_t ltp_pcond; /* number of active queues */ int ltp_active_queues; /* The pool is finishing, waiting for its threads to close. * They close when ltp_pending_list is done. pool_submit() * rejects new tasks. ltp_max_pending = -(its old value). */ int ltp_finishing; /* Some active task needs to be the sole active task. * Atomic variable so ldap_pvt_thread_pool_pausing() can read it. */ volatile sig_atomic_t ltp_pause; /* Max number of threads in pool */ int ltp_max_count; /* Configured max number of threads in pool, 0 for default (LDAP_MAXTHR) */ int ltp_conf_max_count; /* Max pending + paused + idle tasks, negated when ltp_finishing */ int ltp_max_pending; }; static ldap_int_tpool_plist_t empty_pending_list = LDAP_STAILQ_HEAD_INITIALIZER(empty_pending_list); static int ldap_int_has_thread_pool = 0; static LDAP_STAILQ_HEAD(tpq, ldap_int_thread_pool_s) ldap_int_thread_pool_list = LDAP_STAILQ_HEAD_INITIALIZER(ldap_int_thread_pool_list); static ldap_pvt_thread_mutex_t ldap_pvt_thread_pool_mutex; static void *ldap_int_thread_pool_wrapper( void *pool ); static ldap_pvt_thread_key_t ldap_tpool_key; /* Context of the main thread */ static ldap_int_thread_userctx_t ldap_int_main_thrctx; int ldap_int_thread_pool_startup ( void ) { ldap_int_main_thrctx.ltu_id = ldap_pvt_thread_self(); ldap_pvt_thread_key_create( &ldap_tpool_key ); return ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex); } int ldap_int_thread_pool_shutdown ( void ) { struct ldap_int_thread_pool_s *pool; while ((pool = LDAP_STAILQ_FIRST(&ldap_int_thread_pool_list)) != NULL) { (ldap_pvt_thread_pool_destroy)(&pool, 0); /* ignore thr_debug macro */ } ldap_pvt_thread_mutex_destroy(&ldap_pvt_thread_pool_mutex); ldap_pvt_thread_key_destroy( ldap_tpool_key ); return(0); } /* Create a thread pool */ int ldap_pvt_thread_pool_init_q ( ldap_pvt_thread_pool_t *tpool, int max_threads, int max_pending, int numqs ) { ldap_pvt_thread_pool_t pool; struct ldap_int_thread_poolq_s *pq; int i, rc, rem_thr, rem_pend; /* multiple pools are currently not supported (ITS#4943) */ assert(!ldap_int_has_thread_pool); if (! (0 <= max_threads && max_threads <= LDAP_MAXTHR)) max_threads = 0; if (! (1 <= max_pending && max_pending <= MAX_PENDING)) max_pending = MAX_PENDING; *tpool = NULL; pool = (ldap_pvt_thread_pool_t) LDAP_CALLOC(1, sizeof(struct ldap_int_thread_pool_s)); if (pool == NULL) return(-1); pool->ltp_wqs = LDAP_MALLOC(numqs * sizeof(struct ldap_int_thread_poolq_s *)); if (pool->ltp_wqs == NULL) { LDAP_FREE(pool); return(-1); } for (i=0; i=0; i--) LDAP_FREE(pool->ltp_wqs[i]->ltp_free); LDAP_FREE(pool->ltp_wqs); LDAP_FREE(pool); return(-1); } pool->ltp_wqs[i] = (struct ldap_int_thread_poolq_s *)(((size_t)ptr + CACHELINE-1) & ~(CACHELINE-1)); pool->ltp_wqs[i]->ltp_free = ptr; } pool->ltp_numqs = numqs; pool->ltp_conf_max_count = max_threads; if ( !max_threads ) max_threads = LDAP_MAXTHR; rc = ldap_pvt_thread_mutex_init(&pool->ltp_mutex); if (rc != 0) { fail: for (i=0; iltp_wqs[i]->ltp_free); LDAP_FREE(pool->ltp_wqs); LDAP_FREE(pool); return(rc); } rc = ldap_pvt_thread_cond_init(&pool->ltp_cond); if (rc != 0) goto fail; rc = ldap_pvt_thread_cond_init(&pool->ltp_pcond); if (rc != 0) goto fail; rem_thr = max_threads % numqs; rem_pend = max_pending % numqs; for ( i=0; iltp_wqs[i]; pq->ltp_pool = pool; rc = ldap_pvt_thread_mutex_init(&pq->ltp_mutex); if (rc != 0) return(rc); rc = ldap_pvt_thread_cond_init(&pq->ltp_cond); if (rc != 0) return(rc); LDAP_STAILQ_INIT(&pq->ltp_pending_list); pq->ltp_work_list = &pq->ltp_pending_list; LDAP_SLIST_INIT(&pq->ltp_free_list); pq->ltp_max_count = max_threads / numqs; if ( rem_thr ) { pq->ltp_max_count++; rem_thr--; } pq->ltp_max_pending = max_pending / numqs; if ( rem_pend ) { pq->ltp_max_pending++; rem_pend--; } } ldap_int_has_thread_pool = 1; pool->ltp_max_count = max_threads; pool->ltp_max_pending = max_pending; ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex); LDAP_STAILQ_INSERT_TAIL(&ldap_int_thread_pool_list, pool, ltp_next); ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex); /* Start no threads just yet. That can break if the process forks * later, as slapd does in order to daemonize. On at least POSIX, * only the forking thread would survive in the child. Yet fork() * can't unlock/clean up other threads' locks and data structures, * unless pthread_atfork() handlers have been set up to do so. */ *tpool = pool; return(0); } int ldap_pvt_thread_pool_init ( ldap_pvt_thread_pool_t *tpool, int max_threads, int max_pending ) { return ldap_pvt_thread_pool_init_q( tpool, max_threads, max_pending, 1 ); } /* Submit a task to be performed by the thread pool */ int ldap_pvt_thread_pool_submit ( ldap_pvt_thread_pool_t *tpool, ldap_pvt_thread_start_t *start_routine, void *arg ) { return ldap_pvt_thread_pool_submit2( tpool, start_routine, arg, NULL ); } /* Submit a task to be performed by the thread pool */ int ldap_pvt_thread_pool_submit2 ( ldap_pvt_thread_pool_t *tpool, ldap_pvt_thread_start_t *start_routine, void *arg, void **cookie ) { struct ldap_int_thread_pool_s *pool; struct ldap_int_thread_poolq_s *pq; ldap_int_thread_task_t *task; ldap_pvt_thread_t thr; int i, j; if (tpool == NULL) return(-1); pool = *tpool; if (pool == NULL) return(-1); if ( pool->ltp_numqs > 1 ) { int min = pool->ltp_wqs[0]->ltp_max_pending + pool->ltp_wqs[0]->ltp_max_count; int min_x = 0, cnt; for ( i = 0; i < pool->ltp_numqs; i++ ) { /* take first queue that has nothing active */ if ( !pool->ltp_wqs[i]->ltp_active_count ) { min_x = i; break; } cnt = pool->ltp_wqs[i]->ltp_active_count + pool->ltp_wqs[i]->ltp_pending_count; if ( cnt < min ) { min = cnt; min_x = i; } } i = min_x; } else i = 0; j = i; while(1) { ldap_pvt_thread_mutex_lock(&pool->ltp_wqs[i]->ltp_mutex); if (pool->ltp_wqs[i]->ltp_pending_count < pool->ltp_wqs[i]->ltp_max_pending) { break; } ldap_pvt_thread_mutex_unlock(&pool->ltp_wqs[i]->ltp_mutex); i++; i %= pool->ltp_numqs; if ( i == j ) return -1; } pq = pool->ltp_wqs[i]; task = LDAP_SLIST_FIRST(&pq->ltp_free_list); if (task) { LDAP_SLIST_REMOVE_HEAD(&pq->ltp_free_list, ltt_next.l); } else { task = (ldap_int_thread_task_t *) LDAP_MALLOC(sizeof(*task)); if (task == NULL) goto failed; } task->ltt_start_routine = start_routine; task->ltt_arg = arg; task->ltt_queue = pq; if ( cookie ) *cookie = task; pq->ltp_pending_count++; LDAP_STAILQ_INSERT_TAIL(&pq->ltp_pending_list, task, ltt_next.q); if (pool->ltp_pause) goto done; /* should we open (create) a thread? */ if (pq->ltp_open_count < pq->ltp_active_count+pq->ltp_pending_count && pq->ltp_open_count < pq->ltp_max_count) { pq->ltp_starting++; pq->ltp_open_count++; if (0 != ldap_pvt_thread_create( &thr, 1, ldap_int_thread_pool_wrapper, pq)) { /* couldn't create thread. back out of * ltp_open_count and check for even worse things. */ pq->ltp_starting--; pq->ltp_open_count--; if (pq->ltp_open_count == 0) { /* no open threads at all?!? */ ldap_int_thread_task_t *ptr; /* let pool_close know there are no more threads */ ldap_pvt_thread_cond_signal(&pq->ltp_cond); LDAP_STAILQ_FOREACH(ptr, &pq->ltp_pending_list, ltt_next.q) if (ptr == task) break; if (ptr == task) { /* no open threads, task not handled, so * back out of ltp_pending_count, free the task, * report the error. */ pq->ltp_pending_count--; LDAP_STAILQ_REMOVE(&pq->ltp_pending_list, task, ldap_int_thread_task_s, ltt_next.q); LDAP_SLIST_INSERT_HEAD(&pq->ltp_free_list, task, ltt_next.l); goto failed; } } /* there is another open thread, so this * task will be handled eventually. */ } } ldap_pvt_thread_cond_signal(&pq->ltp_cond); done: ldap_pvt_thread_mutex_unlock(&pq->ltp_mutex); return(0); failed: ldap_pvt_thread_mutex_unlock(&pq->ltp_mutex); return(-1); } static void * no_task( void *ctx, void *arg ) { return NULL; } /* Cancel a pending task that was previously submitted. * Return 1 if the task was successfully cancelled, 0 if * not found, -1 for invalid parameters */ int ldap_pvt_thread_pool_retract ( void *cookie ) { ldap_int_thread_task_t *task, *ttmp; struct ldap_int_thread_poolq_s *pq; if (cookie == NULL) return(-1); ttmp = cookie; pq = ttmp->ltt_queue; if (pq == NULL) return(-1); ldap_pvt_thread_mutex_lock(&pq->ltp_mutex); LDAP_STAILQ_FOREACH(task, &pq->ltp_pending_list, ltt_next.q) if (task == ttmp) { /* Could LDAP_STAILQ_REMOVE the task, but that * walks ltp_pending_list again to find it. */ task->ltt_start_routine = no_task; task->ltt_arg = NULL; break; } ldap_pvt_thread_mutex_unlock(&pq->ltp_mutex); return task != NULL; } /* Walk the pool and allow tasks to be retracted, only to be called while the * pool is paused */ int ldap_pvt_thread_pool_walk( ldap_pvt_thread_pool_t *tpool, ldap_pvt_thread_start_t *start, ldap_pvt_thread_walk_t *cb, void *arg ) { struct ldap_int_thread_pool_s *pool; struct ldap_int_thread_poolq_s *pq; ldap_int_thread_task_t *task; int i; if (tpool == NULL) return(-1); pool = *tpool; if (pool == NULL) return(-1); ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); assert(pool->ltp_pause == PAUSED); ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); for (i=0; iltp_numqs; i++) { pq = pool->ltp_wqs[i]; LDAP_STAILQ_FOREACH(task, &pq->ltp_pending_list, ltt_next.q) { if ( task->ltt_start_routine == start ) { if ( cb( task->ltt_start_routine, task->ltt_arg, arg ) ) { /* retract */ task->ltt_start_routine = no_task; task->ltt_arg = NULL; } } } } return 0; } /* Set number of work queues in this pool. Should not be * more than the number of CPUs. */ int ldap_pvt_thread_pool_queues( ldap_pvt_thread_pool_t *tpool, int numqs ) { struct ldap_int_thread_pool_s *pool; struct ldap_int_thread_poolq_s *pq; int i, rc, rem_thr, rem_pend; if (numqs < 1 || tpool == NULL) return(-1); pool = *tpool; if (pool == NULL) return(-1); if (numqs < pool->ltp_numqs) { for (i=numqs; iltp_numqs; i++) pool->ltp_wqs[i]->ltp_max_count = 0; } else if (numqs > pool->ltp_numqs) { struct ldap_int_thread_poolq_s **wqs; wqs = LDAP_REALLOC(pool->ltp_wqs, numqs * sizeof(struct ldap_int_thread_poolq_s *)); if (wqs == NULL) return(-1); pool->ltp_wqs = wqs; for (i=pool->ltp_numqs; iltp_wqs[i] = NULL; return(-1); } pq = (struct ldap_int_thread_poolq_s *)(((size_t)ptr + CACHELINE-1) & ~(CACHELINE-1)); pq->ltp_free = ptr; pool->ltp_wqs[i] = pq; pq->ltp_pool = pool; rc = ldap_pvt_thread_mutex_init(&pq->ltp_mutex); if (rc != 0) return(rc); rc = ldap_pvt_thread_cond_init(&pq->ltp_cond); if (rc != 0) return(rc); LDAP_STAILQ_INIT(&pq->ltp_pending_list); pq->ltp_work_list = &pq->ltp_pending_list; LDAP_SLIST_INIT(&pq->ltp_free_list); } } rem_thr = pool->ltp_max_count % numqs; rem_pend = pool->ltp_max_pending % numqs; for ( i=0; iltp_wqs[i]; pq->ltp_max_count = pool->ltp_max_count / numqs; if ( rem_thr ) { pq->ltp_max_count++; rem_thr--; } pq->ltp_max_pending = pool->ltp_max_pending / numqs; if ( rem_pend ) { pq->ltp_max_pending++; rem_pend--; } } pool->ltp_numqs = numqs; return 0; } /* Set max #threads. value <= 0 means max supported #threads (LDAP_MAXTHR) */ int ldap_pvt_thread_pool_maxthreads( ldap_pvt_thread_pool_t *tpool, int max_threads ) { struct ldap_int_thread_pool_s *pool; struct ldap_int_thread_poolq_s *pq; int remthr, i; if (! (0 <= max_threads && max_threads <= LDAP_MAXTHR)) max_threads = 0; if (tpool == NULL) return(-1); pool = *tpool; if (pool == NULL) return(-1); pool->ltp_conf_max_count = max_threads; if ( !max_threads ) max_threads = LDAP_MAXTHR; pool->ltp_max_count = max_threads; remthr = max_threads % pool->ltp_numqs; max_threads /= pool->ltp_numqs; for (i=0; iltp_numqs; i++) { pq = pool->ltp_wqs[i]; pq->ltp_max_count = max_threads; if (remthr) { pq->ltp_max_count++; remthr--; } } return(0); } /* Inspect the pool */ int ldap_pvt_thread_pool_query( ldap_pvt_thread_pool_t *tpool, ldap_pvt_thread_pool_param_t param, void *value ) { struct ldap_int_thread_pool_s *pool; int count = -1; if ( tpool == NULL || value == NULL ) { return -1; } pool = *tpool; if ( pool == NULL ) { return 0; } switch ( param ) { case LDAP_PVT_THREAD_POOL_PARAM_MAX: count = pool->ltp_conf_max_count; break; case LDAP_PVT_THREAD_POOL_PARAM_MAX_PENDING: count = pool->ltp_max_pending; if (count < 0) count = -count; if (count == MAX_PENDING) count = 0; break; case LDAP_PVT_THREAD_POOL_PARAM_PAUSING: ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); count = (pool->ltp_pause != 0); ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); break; case LDAP_PVT_THREAD_POOL_PARAM_OPEN: case LDAP_PVT_THREAD_POOL_PARAM_STARTING: case LDAP_PVT_THREAD_POOL_PARAM_ACTIVE: case LDAP_PVT_THREAD_POOL_PARAM_PENDING: case LDAP_PVT_THREAD_POOL_PARAM_BACKLOAD: { int i; count = 0; for (i=0; iltp_numqs; i++) { struct ldap_int_thread_poolq_s *pq = pool->ltp_wqs[i]; ldap_pvt_thread_mutex_lock(&pq->ltp_mutex); switch(param) { case LDAP_PVT_THREAD_POOL_PARAM_OPEN: count += pq->ltp_open_count; break; case LDAP_PVT_THREAD_POOL_PARAM_STARTING: count += pq->ltp_starting; break; case LDAP_PVT_THREAD_POOL_PARAM_ACTIVE: count += pq->ltp_active_count; break; case LDAP_PVT_THREAD_POOL_PARAM_PENDING: count += pq->ltp_pending_count; break; case LDAP_PVT_THREAD_POOL_PARAM_BACKLOAD: count += pq->ltp_pending_count + pq->ltp_active_count; break; default: break; } ldap_pvt_thread_mutex_unlock(&pq->ltp_mutex); } if (count < 0) count = -count; } break; case LDAP_PVT_THREAD_POOL_PARAM_ACTIVE_MAX: break; case LDAP_PVT_THREAD_POOL_PARAM_PENDING_MAX: break; case LDAP_PVT_THREAD_POOL_PARAM_BACKLOAD_MAX: break; case LDAP_PVT_THREAD_POOL_PARAM_STATE: if (pool->ltp_pause) *((char **)value) = "pausing"; else if (!pool->ltp_finishing) *((char **)value) = "running"; else { int i; for (i=0; iltp_numqs; i++) if (pool->ltp_wqs[i]->ltp_pending_count) break; if (iltp_numqs) *((char **)value) = "finishing"; else *((char **)value) = "stopping"; } break; case LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN: break; } if ( count > -1 ) { *((int *)value) = count; } return ( count == -1 ? -1 : 0 ); } /* * true if pool is pausing; does not lock any mutex to check. * 0 if not pause, 1 if pause, -1 if error or no pool. */ int ldap_pvt_thread_pool_pausing( ldap_pvt_thread_pool_t *tpool ) { int rc = -1; struct ldap_int_thread_pool_s *pool; if ( tpool != NULL && (pool = *tpool) != NULL ) { rc = (pool->ltp_pause != 0); } return rc; } /* * wrapper for ldap_pvt_thread_pool_query(), left around * for backwards compatibility */ int ldap_pvt_thread_pool_backload ( ldap_pvt_thread_pool_t *tpool ) { int rc, count; rc = ldap_pvt_thread_pool_query( tpool, LDAP_PVT_THREAD_POOL_PARAM_BACKLOAD, (void *)&count ); if ( rc == 0 ) { return count; } return rc; } /* * wrapper for ldap_pvt_thread_pool_close+free(), left around * for backwards compatibility */ int ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t *tpool, int run_pending ) { int rc; if ( (rc = ldap_pvt_thread_pool_close( tpool, run_pending )) ) { return rc; } return ldap_pvt_thread_pool_free( tpool ); } /* Shut down the pool making its threads finish */ int ldap_pvt_thread_pool_close ( ldap_pvt_thread_pool_t *tpool, int run_pending ) { struct ldap_int_thread_pool_s *pool, *pptr; struct ldap_int_thread_poolq_s *pq; ldap_int_thread_task_t *task; int i; if (tpool == NULL) return(-1); pool = *tpool; if (pool == NULL) return(-1); ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex); LDAP_STAILQ_FOREACH(pptr, &ldap_int_thread_pool_list, ltp_next) if (pptr == pool) break; ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex); if (pool != pptr) return(-1); ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); pool->ltp_finishing = 1; if (pool->ltp_max_pending > 0) pool->ltp_max_pending = -pool->ltp_max_pending; ldap_pvt_thread_cond_broadcast(&pool->ltp_cond); ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); for (i=0; iltp_numqs; i++) { pq = pool->ltp_wqs[i]; ldap_pvt_thread_mutex_lock(&pq->ltp_mutex); if (pq->ltp_max_pending > 0) pq->ltp_max_pending = -pq->ltp_max_pending; if (!run_pending) { while ((task = LDAP_STAILQ_FIRST(&pq->ltp_pending_list)) != NULL) { LDAP_STAILQ_REMOVE_HEAD(&pq->ltp_pending_list, ltt_next.q); LDAP_FREE(task); } pq->ltp_pending_count = 0; } while (pq->ltp_open_count) { ldap_pvt_thread_cond_broadcast(&pq->ltp_cond); ldap_pvt_thread_cond_wait(&pq->ltp_cond, &pq->ltp_mutex); } while ((task = LDAP_SLIST_FIRST(&pq->ltp_free_list)) != NULL) { LDAP_SLIST_REMOVE_HEAD(&pq->ltp_free_list, ltt_next.l); LDAP_FREE(task); } ldap_pvt_thread_mutex_unlock(&pq->ltp_mutex); } return(0); } /* Destroy the pool, everything must have already shut down */ int ldap_pvt_thread_pool_free ( ldap_pvt_thread_pool_t *tpool ) { struct ldap_int_thread_pool_s *pool, *pptr; struct ldap_int_thread_poolq_s *pq; int i; if (tpool == NULL) return(-1); pool = *tpool; if (pool == NULL) return(-1); ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex); LDAP_STAILQ_FOREACH(pptr, &ldap_int_thread_pool_list, ltp_next) if (pptr == pool) break; if (pptr == pool) LDAP_STAILQ_REMOVE(&ldap_int_thread_pool_list, pool, ldap_int_thread_pool_s, ltp_next); ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex); if (pool != pptr) return(-1); ldap_pvt_thread_cond_destroy(&pool->ltp_pcond); ldap_pvt_thread_cond_destroy(&pool->ltp_cond); ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex); for (i=0; iltp_numqs; i++) { pq = pool->ltp_wqs[i]; assert( !pq->ltp_open_count ); assert( LDAP_SLIST_EMPTY(&pq->ltp_free_list) ); ldap_pvt_thread_cond_destroy(&pq->ltp_cond); ldap_pvt_thread_mutex_destroy(&pq->ltp_mutex); if (pq->ltp_free) { LDAP_FREE(pq->ltp_free); } } LDAP_FREE(pool->ltp_wqs); LDAP_FREE(pool); *tpool = NULL; ldap_int_has_thread_pool = 0; return(0); } /* Thread loop. Accept and handle submitted tasks. */ static void * ldap_int_thread_pool_wrapper ( void *xpool ) { struct ldap_int_thread_poolq_s *pq = xpool; struct ldap_int_thread_pool_s *pool = pq->ltp_pool; ldap_int_thread_task_t *task; ldap_int_tpool_plist_t *work_list; ldap_int_thread_userctx_t ctx, *kctx; unsigned i, keyslot, hash; int pool_lock = 0, freeme = 0; assert(pool != NULL); for ( i=0; iltp_pause) { ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); /* thread_keys[] is read-only when paused */ while (pool->ltp_pause) ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex); ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); } /* find a key slot to give this thread ID and store a * pointer to our keys there; start at the thread ID * itself (mod LDAP_MAXTHR) and look for an empty slot. */ ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex); for (keyslot = hash & (LDAP_MAXTHR-1); (kctx = thread_keys[keyslot].ctx) && kctx != DELETED_THREAD_CTX; keyslot = (keyslot+1) & (LDAP_MAXTHR-1)); thread_keys[keyslot].ctx = &ctx; ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex); ldap_pvt_thread_mutex_lock(&pq->ltp_mutex); pq->ltp_starting--; pq->ltp_active_count++; for (;;) { work_list = pq->ltp_work_list; /* help the compiler a bit */ task = LDAP_STAILQ_FIRST(work_list); if (task == NULL) { /* paused or no pending tasks */ if (--(pq->ltp_active_count) < 1) { if (pool->ltp_pause) { ldap_pvt_thread_mutex_unlock(&pq->ltp_mutex); ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); pool_lock = 1; if (--(pool->ltp_active_queues) < 1) { /* Notify pool_pause it is the sole active thread. */ ldap_pvt_thread_cond_signal(&pool->ltp_pcond); } } } do { if (pool->ltp_finishing || pq->ltp_open_count > pq->ltp_max_count) { /* Not paused, and either finishing or too many * threads running (can happen if ltp_max_count * was reduced). Let this thread die. */ goto done; } /* We could check an idle timer here, and let the * thread die if it has been inactive for a while. * Only die if there are other open threads (i.e., * always have at least one thread open). * The check should be like this: * if (pool->ltp_open_count>1 && pool->ltp_starting==0) * check timer, wait if ltp_pause, leave thread; * * Just use pthread_cond_timedwait() if we want to * check idle time. */ if (pool_lock) { ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex); if (!pool->ltp_pause) { ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); ldap_pvt_thread_mutex_lock(&pq->ltp_mutex); pool_lock = 0; } } else ldap_pvt_thread_cond_wait(&pq->ltp_cond, &pq->ltp_mutex); work_list = pq->ltp_work_list; task = LDAP_STAILQ_FIRST(work_list); } while (task == NULL); if (pool_lock) { ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); ldap_pvt_thread_mutex_lock(&pq->ltp_mutex); pool_lock = 0; } pq->ltp_active_count++; } LDAP_STAILQ_REMOVE_HEAD(work_list, ltt_next.q); pq->ltp_pending_count--; ldap_pvt_thread_mutex_unlock(&pq->ltp_mutex); task->ltt_start_routine(&ctx, task->ltt_arg); ldap_pvt_thread_mutex_lock(&pq->ltp_mutex); LDAP_SLIST_INSERT_HEAD(&pq->ltp_free_list, task, ltt_next.l); } done: ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex); /* The pool_mutex lock protects ctx->ltu_key from pool_purgekey() * during this call, since it prevents new pauses. */ ldap_pvt_thread_pool_context_reset(&ctx); thread_keys[keyslot].ctx = DELETED_THREAD_CTX; ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex); pq->ltp_open_count--; if (pq->ltp_open_count == 0) { if (pool->ltp_finishing) /* let pool_destroy know we're all done */ ldap_pvt_thread_cond_signal(&pq->ltp_cond); else freeme = 1; } if (pool_lock) ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); else ldap_pvt_thread_mutex_unlock(&pq->ltp_mutex); if (freeme) { ldap_pvt_thread_cond_destroy(&pq->ltp_cond); ldap_pvt_thread_mutex_destroy(&pq->ltp_mutex); LDAP_FREE(pq->ltp_free); pq->ltp_free = NULL; } ldap_pvt_thread_exit(NULL); return(NULL); } /* Arguments > ltp_pause to handle_pause(,PAUSE_ARG()). arg=PAUSE_ARG * ensures (arg-ltp_pause) sets GO_* at need and keeps DO_PAUSE/GO_*. */ #define GO_IDLE 8 #define GO_UNIDLE 16 #define CHECK_PAUSE 32 /* if ltp_pause: GO_IDLE; wait; GO_UNIDLE */ #define DO_PAUSE 64 /* CHECK_PAUSE; pause the pool */ #define PAUSE_ARG(a) \ ((a) | ((a) & (GO_IDLE|GO_UNIDLE) ? GO_IDLE-1 : CHECK_PAUSE)) static int handle_pause( ldap_pvt_thread_pool_t *tpool, int pause_type ) { struct ldap_int_thread_pool_s *pool; struct ldap_int_thread_poolq_s *pq; int ret = 0, pause, max_ltp_pause; if (tpool == NULL) return(-1); pool = *tpool; if (pool == NULL) return(0); if (pause_type == CHECK_PAUSE && !pool->ltp_pause) return(0); { ldap_int_thread_userctx_t *ctx = ldap_pvt_thread_pool_context(); pq = ctx->ltu_pq; if ( !pq ) return(-1); } /* Let pool_unidle() ignore requests for new pauses */ max_ltp_pause = pause_type==PAUSE_ARG(GO_UNIDLE) ? WANT_PAUSE : NOT_PAUSED; ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); pause = pool->ltp_pause; /* NOT_PAUSED, WANT_PAUSE or PAUSED */ /* If ltp_pause and not GO_IDLE|GO_UNIDLE: Set GO_IDLE,GO_UNIDLE */ pause_type -= pause; if (pause_type & GO_IDLE) { int do_pool = 0; ldap_pvt_thread_mutex_lock(&pq->ltp_mutex); pq->ltp_pending_count++; pq->ltp_active_count--; if (pause && pq->ltp_active_count < 1) { do_pool = 1; } ldap_pvt_thread_mutex_unlock(&pq->ltp_mutex); if (do_pool) { pool->ltp_active_queues--; if (pool->ltp_active_queues < 1) /* Tell the task waiting to DO_PAUSE it can proceed */ ldap_pvt_thread_cond_signal(&pool->ltp_pcond); } } if (pause_type & GO_UNIDLE) { /* Wait out pause if any, then cancel GO_IDLE */ if (pause > max_ltp_pause) { ret = 1; do { ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex); } while (pool->ltp_pause > max_ltp_pause); } ldap_pvt_thread_mutex_lock(&pq->ltp_mutex); pq->ltp_pending_count--; pq->ltp_active_count++; ldap_pvt_thread_mutex_unlock(&pq->ltp_mutex); } if (pause_type & DO_PAUSE) { int i, j; /* Tell everyone else to pause or finish, then await that */ ret = 0; assert(!pool->ltp_pause); pool->ltp_pause = WANT_PAUSE; pool->ltp_active_queues = 0; for (i=0; iltp_numqs; i++) if (pool->ltp_wqs[i] == pq) break; ldap_pvt_thread_mutex_lock(&pq->ltp_mutex); /* temporarily remove ourself from active count */ pq->ltp_active_count--; j=i; do { pq = pool->ltp_wqs[j]; if (j != i) ldap_pvt_thread_mutex_lock(&pq->ltp_mutex); /* Hide pending tasks from ldap_pvt_thread_pool_wrapper() */ pq->ltp_work_list = &empty_pending_list; if (pq->ltp_active_count > 0) pool->ltp_active_queues++; ldap_pvt_thread_mutex_unlock(&pq->ltp_mutex); if (pool->ltp_numqs > 1) { j++; j %= pool->ltp_numqs; } } while (j != i); /* Wait for this task to become the sole active task */ while (pool->ltp_active_queues > 0) ldap_pvt_thread_cond_wait(&pool->ltp_pcond, &pool->ltp_mutex); /* restore us to active count */ pool->ltp_wqs[i]->ltp_active_count++; assert(pool->ltp_pause == WANT_PAUSE); pool->ltp_pause = PAUSED; } ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); return(ret); } /* Consider this task idle: It will not block pool_pause() in other tasks. */ void ldap_pvt_thread_pool_idle( ldap_pvt_thread_pool_t *tpool ) { handle_pause(tpool, PAUSE_ARG(GO_IDLE)); } /* Cancel pool_idle(). If the pool is paused, wait it out first. */ void ldap_pvt_thread_pool_unidle( ldap_pvt_thread_pool_t *tpool ) { handle_pause(tpool, PAUSE_ARG(GO_UNIDLE)); } /* * If a pause was requested, wait for it. If several threads * are waiting to pause, let through one or more pauses. * The calling task must be active, not idle. * Return 1 if we waited, 0 if not, -1 at parameter error. */ int ldap_pvt_thread_pool_pausecheck( ldap_pvt_thread_pool_t *tpool ) { return handle_pause(tpool, PAUSE_ARG(CHECK_PAUSE)); } /* * Wait for a pause, from a non-pooled thread. */ int ldap_pvt_thread_pool_pausecheck_native( ldap_pvt_thread_pool_t *tpool ) { struct ldap_int_thread_pool_s *pool; if (tpool == NULL) return(-1); pool = *tpool; if (pool == NULL) return(0); if (!pool->ltp_pause) return(0); ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); while (pool->ltp_pause) ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex); ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); return 1; } /* * Pause the pool. The calling task must be active, not idle. * Return when all other tasks are paused or idle. */ int ldap_pvt_thread_pool_pause( ldap_pvt_thread_pool_t *tpool ) { return handle_pause(tpool, PAUSE_ARG(DO_PAUSE)); } /* End a pause */ int ldap_pvt_thread_pool_resume ( ldap_pvt_thread_pool_t *tpool ) { struct ldap_int_thread_pool_s *pool; struct ldap_int_thread_poolq_s *pq; int i; if (tpool == NULL) return(-1); pool = *tpool; if (pool == NULL) return(0); ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); assert(pool->ltp_pause == PAUSED); pool->ltp_pause = 0; for (i=0; iltp_numqs; i++) { pq = pool->ltp_wqs[i]; pq->ltp_work_list = &pq->ltp_pending_list; ldap_pvt_thread_cond_broadcast(&pq->ltp_cond); } ldap_pvt_thread_cond_broadcast(&pool->ltp_cond); ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); return(0); } /* * Get the key's data and optionally free function in the given context. */ int ldap_pvt_thread_pool_getkey( void *xctx, void *key, void **data, ldap_pvt_thread_pool_keyfree_t **kfree ) { ldap_int_thread_userctx_t *ctx = xctx; int i; if ( !ctx || !key || !data ) return EINVAL; for ( i=0; iltu_key[i].ltk_key; i++ ) { if ( ctx->ltu_key[i].ltk_key == key ) { *data = ctx->ltu_key[i].ltk_data; if ( kfree ) *kfree = ctx->ltu_key[i].ltk_free; return 0; } } return ENOENT; } static void clear_key_idx( ldap_int_thread_userctx_t *ctx, int i ) { for ( ; i < MAXKEYS-1 && ctx->ltu_key[i+1].ltk_key; i++ ) ctx->ltu_key[i] = ctx->ltu_key[i+1]; ctx->ltu_key[i].ltk_key = NULL; } /* * Set or remove data for the key in the given context. * key can be any unique pointer. * kfree() is an optional function to free the data (but not the key): * pool_context_reset() and pool_purgekey() call kfree(key, data), * but pool_setkey() does not. For pool_setkey() it is the caller's * responsibility to free any existing data with the same key. * kfree() must not call functions taking a tpool argument. */ int ldap_pvt_thread_pool_setkey( void *xctx, void *key, void *data, ldap_pvt_thread_pool_keyfree_t *kfree, void **olddatap, ldap_pvt_thread_pool_keyfree_t **oldkfreep ) { ldap_int_thread_userctx_t *ctx = xctx; int i, found; if ( !ctx || !key ) return EINVAL; for ( i=found=0; iltu_key[i].ltk_key == key ) { found = 1; break; } else if ( !ctx->ltu_key[i].ltk_key ) { break; } } if ( olddatap ) { if ( found ) { *olddatap = ctx->ltu_key[i].ltk_data; } else { *olddatap = NULL; } } if ( oldkfreep ) { if ( found ) { *oldkfreep = ctx->ltu_key[i].ltk_free; } else { *oldkfreep = 0; } } if ( data || kfree ) { if ( i>=MAXKEYS ) return ENOMEM; ctx->ltu_key[i].ltk_key = key; ctx->ltu_key[i].ltk_data = data; ctx->ltu_key[i].ltk_free = kfree; } else if ( found ) { clear_key_idx( ctx, i ); } return 0; } /* Free all elements with this key, no matter which thread they're in. * May only be called while the pool is paused. */ void ldap_pvt_thread_pool_purgekey( void *key ) { int i, j; ldap_int_thread_userctx_t *ctx; assert ( key != NULL ); ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex); for ( i=0; iltu_key[j].ltk_key; j++ ) { if ( ctx->ltu_key[j].ltk_key == key ) { if (ctx->ltu_key[j].ltk_free) ctx->ltu_key[j].ltk_free( ctx->ltu_key[j].ltk_key, ctx->ltu_key[j].ltk_data ); clear_key_idx( ctx, j ); break; } } } } ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex); } /* * Find the context of the current thread. * This is necessary if the caller does not have access to the * thread context handle (for example, a slapd plugin calling * slapi_search_internal()). No doubt it is more efficient * for the application to keep track of the thread context * handles itself. */ void *ldap_pvt_thread_pool_context( ) { void *ctx = NULL; ldap_pvt_thread_key_getdata( ldap_tpool_key, &ctx ); return ctx ? ctx : (void *) &ldap_int_main_thrctx; } /* * Free the context's keys. * Must not call functions taking a tpool argument (because this * thread already holds ltp_mutex when called from pool_wrapper()). */ void ldap_pvt_thread_pool_context_reset( void *vctx ) { ldap_int_thread_userctx_t *ctx = vctx; int i; for ( i=MAXKEYS-1; i>=0; i--) { if ( !ctx->ltu_key[i].ltk_key ) continue; if ( ctx->ltu_key[i].ltk_free ) ctx->ltu_key[i].ltk_free( ctx->ltu_key[i].ltk_key, ctx->ltu_key[i].ltk_data ); ctx->ltu_key[i].ltk_key = NULL; } } ldap_pvt_thread_t ldap_pvt_thread_pool_tid( void *vctx ) { ldap_int_thread_userctx_t *ctx = vctx; return ctx->ltu_id; } #endif /* LDAP_THREAD_HAVE_TPOOL */ #endif /* LDAP_R_COMPILE */ openldap-2.5.11+dfsg/libraries/libldap/passwd.c0000644000175000017500000000650414172327167020074 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This program was originally developed by Kurt D. Zeilenga for inclusion in * OpenLDAP Software. */ #include "portable.h" #include #include #include #include #include "ldap-int.h" /* * LDAP Password Modify (Extended) Operation (RFC 3062) */ int ldap_parse_passwd( LDAP *ld, LDAPMessage *res, struct berval *newpasswd ) { int rc; struct berval *retdata = NULL; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( res != NULL ); assert( newpasswd != NULL ); newpasswd->bv_val = NULL; newpasswd->bv_len = 0; rc = ldap_parse_extended_result( ld, res, NULL, &retdata, 0 ); if ( rc != LDAP_SUCCESS ) { return rc; } if ( retdata != NULL ) { ber_tag_t tag; BerElement *ber = ber_init( retdata ); if ( ber == NULL ) { rc = ld->ld_errno = LDAP_NO_MEMORY; goto done; } /* we should check the tag */ tag = ber_scanf( ber, "{o}", newpasswd ); ber_free( ber, 1 ); if ( tag == LBER_ERROR ) { rc = ld->ld_errno = LDAP_DECODING_ERROR; } } done:; ber_bvfree( retdata ); return rc; } int ldap_passwd( LDAP *ld, struct berval *user, struct berval *oldpw, struct berval *newpw, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp ) { int rc; struct berval bv = BER_BVNULL; BerElement *ber = NULL; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( msgidp != NULL ); if( user != NULL || oldpw != NULL || newpw != NULL ) { /* build change password control */ ber = ber_alloc_t( LBER_USE_DER ); if( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } ber_printf( ber, "{" /*}*/ ); if( user != NULL ) { ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_ID, user ); } if( oldpw != NULL ) { ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, oldpw ); } if( newpw != NULL ) { ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, newpw ); } ber_printf( ber, /*{*/ "N}" ); rc = ber_flatten2( ber, &bv, 0 ); if( rc < 0 ) { ld->ld_errno = LDAP_ENCODING_ERROR; return ld->ld_errno; } } rc = ldap_extended_operation( ld, LDAP_EXOP_MODIFY_PASSWD, bv.bv_val ? &bv : NULL, sctrls, cctrls, msgidp ); ber_free( ber, 1 ); return rc; } int ldap_passwd_s( LDAP *ld, struct berval *user, struct berval *oldpw, struct berval *newpw, struct berval *newpasswd, LDAPControl **sctrls, LDAPControl **cctrls ) { int rc; int msgid; LDAPMessage *res; rc = ldap_passwd( ld, user, oldpw, newpw, sctrls, cctrls, &msgid ); if ( rc != LDAP_SUCCESS ) { return rc; } if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, &res ) == -1 || !res ) { return ld->ld_errno; } rc = ldap_parse_passwd( ld, res, newpasswd ); if( rc != LDAP_SUCCESS ) { ldap_msgfree( res ); return rc; } return( ldap_result2error( ld, res, 1 ) ); } openldap-2.5.11+dfsg/libraries/libldap/filter.c0000644000175000017500000004756414172327167020073 0ustar ryanryan/* search.c */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" static int put_simple_vrFilter LDAP_P(( BerElement *ber, char *str )); static int put_vrFilter_list LDAP_P(( BerElement *ber, char *str )); static char *put_complex_filter LDAP_P(( BerElement *ber, char *str, ber_tag_t tag, int not )); static int put_simple_filter LDAP_P(( BerElement *ber, char *str )); static int put_substring_filter LDAP_P(( BerElement *ber, char *type, char *str, char *nextstar )); static int put_filter_list LDAP_P(( BerElement *ber, char *str, ber_tag_t tag )); static int ldap_is_oid ( const char *str ) { int i; if( LDAP_ALPHA( str[0] )) { for( i=1; str[i]; i++ ) { if( !LDAP_LDH( str[i] )) { return 0; } } return 1; } else if LDAP_DIGIT( str[0] ) { int dot=0; for( i=1; str[i]; i++ ) { if( LDAP_DIGIT( str[i] )) { dot=0; } else if ( str[i] == '.' ) { if( ++dot > 1 ) return 0; } else { return 0; } } return !dot; } return 0; } static int ldap_is_desc ( const char *str ) { int i; if( LDAP_ALPHA( str[0] )) { for( i=1; str[i]; i++ ) { if( str[i] == ';' ) { str = &str[i+1]; goto options; } if( !LDAP_LDH( str[i] )) { return 0; } } return 1; } else if LDAP_DIGIT( str[0] ) { int dot=0; for( i=1; str[i]; i++ ) { if( str[i] == ';' ) { if( dot ) return 0; str = &str[i+1]; goto options; } if( LDAP_DIGIT( str[i] )) { dot=0; } else if ( str[i] == '.' ) { if( ++dot > 1 ) return 0; } else { return 0; } } return !dot; } return 0; options: if( !LDAP_LDH( str[0] )) { return 0; } for( i=1; str[i]; i++ ) { if( str[i] == ';' ) { str = &str[i+1]; goto options; } if( !LDAP_LDH( str[i] )) { return 0; } } return 1; } static char * find_right_paren( char *s ) { int balance, escape; balance = 1; escape = 0; while ( *s && balance ) { if ( !escape ) { if ( *s == '(' ) { balance++; } else if ( *s == ')' ) { balance--; } } escape = ( *s == '\\' && !escape ); if ( balance ) s++; } return *s ? s : NULL; } static int hex2value( int c ) { if( c >= '0' && c <= '9' ) { return c - '0'; } if( c >= 'A' && c <= 'F' ) { return c + (10 - (int) 'A'); } if( c >= 'a' && c <= 'f' ) { return c + (10 - (int) 'a'); } return -1; } char * ldap_pvt_find_wildcard( const char *s ) { for( ; *s; s++ ) { switch( *s ) { case '*': /* found wildcard */ return (char *) s; case '(': case ')': return NULL; case '\\': if( s[1] == '\0' ) return NULL; if( LDAP_HEX( s[1] ) && LDAP_HEX( s[2] ) ) { s+=2; } else switch( s[1] ) { default: return NULL; /* allow RFC 1960 escapes */ case '*': case '(': case ')': case '\\': s++; } } } return (char *) s; } /* unescape filter value */ /* support both LDAP v2 and v3 escapes */ /* output can include nul characters! */ ber_slen_t ldap_pvt_filter_value_unescape( char *fval ) { ber_slen_t r, v; int v1, v2; for( r=v=0; fval[v] != '\0'; v++ ) { switch( fval[v] ) { case '(': case ')': case '*': return -1; case '\\': /* escape */ v++; if ( fval[v] == '\0' ) { /* escape at end of string */ return -1; } if (( v1 = hex2value( fval[v] )) >= 0 ) { /* LDAPv3 escape */ if (( v2 = hex2value( fval[v+1] )) < 0 ) { /* must be two digit code */ return -1; } fval[r++] = v1 * 16 + v2; v++; } else { /* LDAPv2 escape */ switch( fval[v] ) { case '(': case ')': case '*': case '\\': fval[r++] = fval[v]; break; default: /* illegal escape */ return -1; } } break; default: fval[r++] = fval[v]; } } fval[r] = '\0'; return r; } static char * put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not ) { char *next; /* * We have (x(filter)...) with str sitting on * the x. We have to find the paren matching * the one before the x and put the intervening * filters by calling put_filter_list(). */ /* put explicit tag */ if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) { return NULL; } str++; if ( (next = find_right_paren( str )) == NULL ) { return NULL; } *next = '\0'; if ( put_filter_list( ber, str, tag ) == -1 ) { return NULL; } /* close the '(' */ *next++ = ')'; /* flush explicit tagged thang */ if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) { return NULL; } return next; } int ldap_pvt_put_filter( BerElement *ber, const char *str_in ) { int rc; char *freeme; char *str; char *next; int parens, balance, escape; /* * A Filter looks like this (RFC 4511 as extended by RFC 4526): * Filter ::= CHOICE { * and [0] SET SIZE (0..MAX) OF filter Filter, * or [1] SET SIZE (0..MAX) OF filter Filter, * not [2] Filter, * equalityMatch [3] AttributeValueAssertion, * substrings [4] SubstringFilter, * greaterOrEqual [5] AttributeValueAssertion, * lessOrEqual [6] AttributeValueAssertion, * present [7] AttributeDescription, * approxMatch [8] AttributeValueAssertion, * extensibleMatch [9] MatchingRuleAssertion, * ... } * * SubstringFilter ::= SEQUENCE { * type AttributeDescription, * substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE { * initial [0] AssertionValue, -- only once * any [1] AssertionValue, * final [2] AssertionValue -- only once * } * } * * MatchingRuleAssertion ::= SEQUENCE { * matchingRule [1] MatchingRuleId OPTIONAL, * type [2] AttributeDescription OPTIONAL, * matchValue [3] AssertionValue, * dnAttributes [4] BOOLEAN DEFAULT FALSE } * * Note: tags in a CHOICE are always explicit */ Debug1( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in ); freeme = LDAP_STRDUP( str_in ); if( freeme == NULL ) return LDAP_NO_MEMORY; str = freeme; parens = 0; while ( *str ) { switch ( *str ) { case '(': /*')'*/ str++; parens++; /* skip spaces */ while( LDAP_SPACE( *str ) ) str++; switch ( *str ) { case '&': Debug0( LDAP_DEBUG_TRACE, "put_filter: AND\n" ); str = put_complex_filter( ber, str, LDAP_FILTER_AND, 0 ); if( str == NULL ) { rc = -1; goto done; } parens--; break; case '|': Debug0( LDAP_DEBUG_TRACE, "put_filter: OR\n" ); str = put_complex_filter( ber, str, LDAP_FILTER_OR, 0 ); if( str == NULL ) { rc = -1; goto done; } parens--; break; case '!': Debug0( LDAP_DEBUG_TRACE, "put_filter: NOT\n" ); str = put_complex_filter( ber, str, LDAP_FILTER_NOT, 0 ); if( str == NULL ) { rc = -1; goto done; } parens--; break; case '(': rc = -1; goto done; default: Debug0( LDAP_DEBUG_TRACE, "put_filter: simple\n" ); balance = 1; escape = 0; next = str; while ( *next && balance ) { if ( escape == 0 ) { if ( *next == '(' ) { balance++; } else if ( *next == ')' ) { balance--; } } if ( *next == '\\' && ! escape ) { escape = 1; } else { escape = 0; } if ( balance ) next++; } if ( balance != 0 ) { rc = -1; goto done; } *next = '\0'; if ( put_simple_filter( ber, str ) == -1 ) { rc = -1; goto done; } *next++ = /*'('*/ ')'; str = next; parens--; break; } break; case /*'('*/ ')': Debug0( LDAP_DEBUG_TRACE, "put_filter: end\n" ); if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) { rc = -1; goto done; } str++; parens--; break; case ' ': str++; break; default: /* assume it's a simple type=value filter */ Debug0( LDAP_DEBUG_TRACE, "put_filter: default\n" ); next = strchr( str, '\0' ); if ( put_simple_filter( ber, str ) == -1 ) { rc = -1; goto done; } str = next; break; } if ( !parens ) break; } rc = ( parens || *str ) ? -1 : 0; done: LDAP_FREE( freeme ); return rc; } /* * Put a list of filters like this "(filter1)(filter2)..." */ static int put_filter_list( BerElement *ber, char *str, ber_tag_t tag ) { char *next = NULL; char save; Debug1( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", str ); while ( *str ) { while ( *str && LDAP_SPACE( (unsigned char) *str ) ) { str++; } if ( *str == '\0' ) break; if ( (next = find_right_paren( str + 1 )) == NULL ) { return -1; } save = *++next; /* now we have "(filter)" with str pointing to it */ *next = '\0'; if ( ldap_pvt_put_filter( ber, str ) == -1 ) return -1; *next = save; str = next; if( tag == LDAP_FILTER_NOT ) break; } if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) { return -1; } return 0; } static int put_simple_filter( BerElement *ber, char *str ) { char *s; char *value; ber_tag_t ftype; int rc = -1; Debug1( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n", str ); str = LDAP_STRDUP( str ); if( str == NULL ) return -1; if ( (s = strchr( str, '=' )) == NULL ) { goto done; } value = s + 1; *s-- = '\0'; switch ( *s ) { case '<': ftype = LDAP_FILTER_LE; *s = '\0'; break; case '>': ftype = LDAP_FILTER_GE; *s = '\0'; break; case '~': ftype = LDAP_FILTER_APPROX; *s = '\0'; break; case ':': /* RFC 4515 extensible filters are off the form: * type [:dn] [:rule] := value * or [:dn]:rule := value */ ftype = LDAP_FILTER_EXT; *s = '\0'; { char *dn = strchr( str, ':' ); char *rule = NULL; if( dn != NULL ) { *dn++ = '\0'; rule = strchr( dn, ':' ); if( rule == NULL ) { /* one colon */ if ( strcasecmp(dn, "dn") == 0 ) { /* must have attribute */ if( !ldap_is_desc( str ) ) { goto done; } rule = ""; } else { rule = dn; dn = NULL; } } else { /* two colons */ *rule++ = '\0'; if ( strcasecmp(dn, "dn") != 0 ) { /* must have "dn" */ goto done; } } } if ( *str == '\0' && ( !rule || *rule == '\0' ) ) { /* must have either type or rule */ goto done; } if ( *str != '\0' && !ldap_is_desc( str ) ) { goto done; } if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) { goto done; } rc = ber_printf( ber, "t{" /*"}"*/, ftype ); if( rc != -1 && rule && *rule != '\0' ) { rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule ); } if( rc != -1 && *str != '\0' ) { rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str ); } if( rc != -1 ) { ber_slen_t len = ldap_pvt_filter_value_unescape( value ); if( len >= 0 ) { rc = ber_printf( ber, "to", LDAP_FILTER_EXT_VALUE, value, len ); } else { rc = -1; } } if( rc != -1 && dn ) { rc = ber_printf( ber, "tb", LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 ); } if( rc != -1 ) { rc = ber_printf( ber, /*"{"*/ "N}" ); } } goto done; default: if( !ldap_is_desc( str ) ) { goto done; } else { char *nextstar = ldap_pvt_find_wildcard( value ); if ( nextstar == NULL ) { goto done; } else if ( *nextstar == '\0' ) { ftype = LDAP_FILTER_EQUALITY; } else if ( strcmp( value, "*" ) == 0 ) { ftype = LDAP_FILTER_PRESENT; } else { rc = put_substring_filter( ber, str, value, nextstar ); goto done; } } break; } if( !ldap_is_desc( str ) ) goto done; if ( ftype == LDAP_FILTER_PRESENT ) { rc = ber_printf( ber, "ts", ftype, str ); } else { ber_slen_t len = ldap_pvt_filter_value_unescape( value ); if( len >= 0 ) { rc = ber_printf( ber, "t{soN}", ftype, str, value, len ); } } done: if( rc != -1 ) rc = 0; LDAP_FREE( str ); return rc; } static int put_substring_filter( BerElement *ber, char *type, char *val, char *nextstar ) { int gotstar = 0; ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS; Debug2( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", type, val ); if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) { return -1; } for( ; *val; val=nextstar ) { if ( gotstar ) nextstar = ldap_pvt_find_wildcard( val ); if ( nextstar == NULL ) { return -1; } if ( *nextstar == '\0' ) { ftype = LDAP_SUBSTRING_FINAL; } else { *nextstar++ = '\0'; if ( gotstar++ == 0 ) { ftype = LDAP_SUBSTRING_INITIAL; } else { ftype = LDAP_SUBSTRING_ANY; } } if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) { ber_slen_t len = ldap_pvt_filter_value_unescape( val ); if ( len <= 0 ) { return -1; } if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) { return -1; } } } if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) { return -1; } return 0; } static int put_vrFilter( BerElement *ber, const char *str_in ) { int rc; char *freeme; char *str; char *next; int parens, balance, escape; /* * A ValuesReturnFilter looks like this: * * ValuesReturnFilter ::= SEQUENCE OF SimpleFilterItem * SimpleFilterItem ::= CHOICE { * equalityMatch [3] AttributeValueAssertion, * substrings [4] SubstringFilter, * greaterOrEqual [5] AttributeValueAssertion, * lessOrEqual [6] AttributeValueAssertion, * present [7] AttributeType, * approxMatch [8] AttributeValueAssertion, * extensibleMatch [9] SimpleMatchingAssertion -- LDAPv3 * } * * SubstringFilter ::= SEQUENCE { * type AttributeType, * SEQUENCE OF CHOICE { * initial [0] IA5String, * any [1] IA5String, * final [2] IA5String * } * } * * SimpleMatchingAssertion ::= SEQUENCE { -- LDAPv3 * matchingRule [1] MatchingRuleId OPTIONAL, * type [2] AttributeDescription OPTIONAL, * matchValue [3] AssertionValue } * * (Source: RFC 3876) */ Debug1( LDAP_DEBUG_TRACE, "put_vrFilter: \"%s\"\n", str_in ); freeme = LDAP_STRDUP( str_in ); if( freeme == NULL ) return LDAP_NO_MEMORY; str = freeme; parens = 0; while ( *str ) { switch ( *str ) { case '(': /*')'*/ str++; parens++; /* skip spaces */ while( LDAP_SPACE( *str ) ) str++; switch ( *str ) { case '(': if ( (next = find_right_paren( str )) == NULL ) { rc = -1; goto done; } *next = '\0'; if ( put_vrFilter_list( ber, str ) == -1 ) { rc = -1; goto done; } /* close the '(' */ *next++ = ')'; str = next; parens--; break; default: Debug0( LDAP_DEBUG_TRACE, "put_vrFilter: simple\n" ); balance = 1; escape = 0; next = str; while ( *next && balance ) { if ( escape == 0 ) { if ( *next == '(' ) { balance++; } else if ( *next == ')' ) { balance--; } } if ( *next == '\\' && ! escape ) { escape = 1; } else { escape = 0; } if ( balance ) next++; } if ( balance != 0 ) { rc = -1; goto done; } *next = '\0'; if ( put_simple_vrFilter( ber, str ) == -1 ) { rc = -1; goto done; } *next++ = /*'('*/ ')'; str = next; parens--; break; } break; case /*'('*/ ')': Debug0( LDAP_DEBUG_TRACE, "put_vrFilter: end\n" ); if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) { rc = -1; goto done; } str++; parens--; break; case ' ': str++; break; default: /* assume it's a simple type=value filter */ Debug0( LDAP_DEBUG_TRACE, "put_vrFilter: default\n" ); next = strchr( str, '\0' ); if ( put_simple_vrFilter( ber, str ) == -1 ) { rc = -1; goto done; } str = next; break; } } rc = parens ? -1 : 0; done: LDAP_FREE( freeme ); return rc; } int ldap_put_vrFilter( BerElement *ber, const char *str_in ) { int rc =0; if ( ber_printf( ber, "{" /*"}"*/ ) == -1 ) { return -1; } rc = put_vrFilter( ber, str_in ); if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) { rc = -1; } return rc; } static int put_vrFilter_list( BerElement *ber, char *str ) { char *next = NULL; char save; Debug1( LDAP_DEBUG_TRACE, "put_vrFilter_list \"%s\"\n", str ); while ( *str ) { while ( *str && LDAP_SPACE( (unsigned char) *str ) ) { str++; } if ( *str == '\0' ) break; if ( (next = find_right_paren( str + 1 )) == NULL ) { return -1; } save = *++next; /* now we have "(filter)" with str pointing to it */ *next = '\0'; if ( put_vrFilter( ber, str ) == -1 ) return -1; *next = save; str = next; } return 0; } static int put_simple_vrFilter( BerElement *ber, char *str ) { char *s; char *value; ber_tag_t ftype; int rc = -1; Debug1( LDAP_DEBUG_TRACE, "put_simple_vrFilter: \"%s\"\n", str ); str = LDAP_STRDUP( str ); if( str == NULL ) return -1; if ( (s = strchr( str, '=' )) == NULL ) { goto done; } value = s + 1; *s-- = '\0'; switch ( *s ) { case '<': ftype = LDAP_FILTER_LE; *s = '\0'; break; case '>': ftype = LDAP_FILTER_GE; *s = '\0'; break; case '~': ftype = LDAP_FILTER_APPROX; *s = '\0'; break; case ':': /* According to ValuesReturnFilter control definition * extensible filters are off the form: * type [:rule] := value * or :rule := value */ ftype = LDAP_FILTER_EXT; *s = '\0'; { char *rule = strchr( str, ':' ); if( rule == NULL ) { /* must have attribute */ if( !ldap_is_desc( str ) ) { goto done; } rule = ""; } else { *rule++ = '\0'; } if ( *str == '\0' && ( !rule || *rule == '\0' ) ) { /* must have either type or rule */ goto done; } if ( *str != '\0' && !ldap_is_desc( str ) ) { goto done; } if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) { goto done; } rc = ber_printf( ber, "t{" /*"}"*/, ftype ); if( rc != -1 && rule && *rule != '\0' ) { rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule ); } if( rc != -1 && *str != '\0' ) { rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str ); } if( rc != -1 ) { ber_slen_t len = ldap_pvt_filter_value_unescape( value ); if( len >= 0 ) { rc = ber_printf( ber, "to", LDAP_FILTER_EXT_VALUE, value, len ); } else { rc = -1; } } if( rc != -1 ) { rc = ber_printf( ber, /*"{"*/ "N}" ); } } goto done; default: if( !ldap_is_desc( str ) ) { goto done; } else { char *nextstar = ldap_pvt_find_wildcard( value ); if ( nextstar == NULL ) { goto done; } else if ( *nextstar == '\0' ) { ftype = LDAP_FILTER_EQUALITY; } else if ( strcmp( value, "*" ) == 0 ) { ftype = LDAP_FILTER_PRESENT; } else { rc = put_substring_filter( ber, str, value, nextstar ); goto done; } } break; } if( !ldap_is_desc( str ) ) goto done; if ( ftype == LDAP_FILTER_PRESENT ) { rc = ber_printf( ber, "ts", ftype, str ); } else { ber_slen_t len = ldap_pvt_filter_value_unescape( value ); if( len >= 0 ) { rc = ber_printf( ber, "t{soN}", ftype, str, value, len ); } } done: if( rc != -1 ) rc = 0; LDAP_FREE( str ); return rc; } openldap-2.5.11+dfsg/libraries/libldap/getvalues.c0000644000175000017500000000766214172327167020600 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ #include "portable.h" #include #include #include #include #include #include #include "ldap-int.h" char ** ldap_get_values( LDAP *ld, LDAPMessage *entry, LDAP_CONST char *target ) { BerElement ber; char *attr; int found = 0; char **vals; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( entry != NULL ); assert( target != NULL ); Debug0( LDAP_DEBUG_TRACE, "ldap_get_values\n" ); ber = *entry->lm_ber; /* skip sequence, dn, sequence of, and snag the first attr */ if ( ber_scanf( &ber, "{x{{a" /*}}}*/, &attr ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; return( NULL ); } if ( strcasecmp( target, attr ) == 0 ) found = 1; /* break out on success, return out on error */ while ( ! found ) { LDAP_FREE(attr); attr = NULL; if ( ber_scanf( &ber, /*{*/ "x}{a" /*}*/, &attr ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; return( NULL ); } if ( strcasecmp( target, attr ) == 0 ) break; } LDAP_FREE(attr); attr = NULL; /* * if we get this far, we've found the attribute and are sitting * just before the set of values. */ if ( ber_scanf( &ber, "[v]", &vals ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; return( NULL ); } return( vals ); } struct berval ** ldap_get_values_len( LDAP *ld, LDAPMessage *entry, LDAP_CONST char *target ) { BerElement ber; char *attr; int found = 0; struct berval **vals; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( entry != NULL ); assert( target != NULL ); Debug0( LDAP_DEBUG_TRACE, "ldap_get_values_len\n" ); ber = *entry->lm_ber; /* skip sequence, dn, sequence of, and snag the first attr */ if ( ber_scanf( &ber, "{x{{a" /* }}} */, &attr ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; return( NULL ); } if ( strcasecmp( target, attr ) == 0 ) found = 1; /* break out on success, return out on error */ while ( ! found ) { LDAP_FREE( attr ); attr = NULL; if ( ber_scanf( &ber, /*{*/ "x}{a" /*}*/, &attr ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; return( NULL ); } if ( strcasecmp( target, attr ) == 0 ) break; } LDAP_FREE( attr ); attr = NULL; /* * if we get this far, we've found the attribute and are sitting * just before the set of values. */ if ( ber_scanf( &ber, "[V]", &vals ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; return( NULL ); } return( vals ); } int ldap_count_values( char **vals ) { int i; if ( vals == NULL ) return( 0 ); for ( i = 0; vals[i] != NULL; i++ ) ; /* NULL */ return( i ); } int ldap_count_values_len( struct berval **vals ) { return( ldap_count_values( (char **) vals ) ); } void ldap_value_free( char **vals ) { LDAP_VFREE( vals ); } void ldap_value_free_len( struct berval **vals ) { ber_bvecfree( vals ); } char ** ldap_value_dup( char *const *vals ) { char **new; int i; if( vals == NULL ) { return NULL; } for( i=0; vals[i]; i++ ) { ; /* Count the number of values */ } if( i == 0 ) { return NULL; } new = LDAP_MALLOC( (i+1)*sizeof(char *) ); /* Alloc array of pointers */ if( new == NULL ) { return NULL; } for( i=0; vals[i]; i++ ) { new[i] = LDAP_STRDUP( vals[i] ); /* Dup each value */ if( new[i] == NULL ) { LDAP_VFREE( new ); return NULL; } } new[i] = NULL; return new; } openldap-2.5.11+dfsg/libraries/libldap/thr_nt.c0000644000175000017500000001130314172327167020062 0ustar ryanryan/* thr_nt.c - wrapper around NT threads */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #if defined( HAVE_NT_THREADS ) #define _WIN32_WINNT 0x0400 #include #include #include "ldap_pvt_thread.h" /* Get the thread interface */ #define LDAP_THREAD_IMPLEMENTATION #include "ldap_thr_debug.h" /* May rename the symbols defined below */ typedef struct ldap_int_thread_s { long tid; HANDLE thd; } ldap_int_thread_s; #ifndef NT_MAX_THREADS #define NT_MAX_THREADS 1024 #endif static ldap_int_thread_s tids[NT_MAX_THREADS]; static int ntids; /* mingw compiler very sensitive about getting prototypes right */ typedef unsigned __stdcall thrfunc_t(void *); int ldap_int_thread_initialize( void ) { return 0; } int ldap_int_thread_destroy( void ) { return 0; } int ldap_int_mutex_firstcreate( ldap_int_thread_mutex_t *mutex ) { if ( *mutex == NULL ) { HANDLE p = CreateMutex( NULL, 0, NULL ); if ( InterlockedCompareExchangePointer((PVOID*)mutex, (PVOID)p, NULL) != NULL) CloseHandle( p ); } return 0; } int ldap_pvt_thread_create( ldap_pvt_thread_t * thread, int detach, void *(*start_routine)( void *), void *arg) { unsigned tid; HANDLE thd; int rc = -1; thd = (HANDLE) _beginthreadex(NULL, LDAP_PVT_THREAD_STACK_SIZE, (thrfunc_t *) start_routine, arg, 0, &tid); if ( thd ) { *thread = (ldap_pvt_thread_t) tid; tids[ntids].tid = tid; tids[ntids].thd = thd; ntids++; rc = 0; } return rc; } void ldap_pvt_thread_exit( void *retval ) { _endthread( ); } int ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return ) { DWORD status; int i; for (i=0; i ntids ) return -1; status = WaitForSingleObject( tids[i].thd, INFINITE ); for (; i. * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #if defined( HAVE_THR ) #include "ldap_pvt_thread.h" /* Get the thread interface */ #define LDAP_THREAD_IMPLEMENTATION #include "ldap_thr_debug.h" /* May rename the symbols defined below */ /******************* * * * Solaris Threads * * * *******************/ int ldap_int_thread_initialize( void ) { return 0; } int ldap_int_thread_destroy( void ) { return 0; } #ifdef LDAP_THREAD_HAVE_SETCONCURRENCY int ldap_pvt_thread_set_concurrency(int n) { return thr_setconcurrency( n ); } #endif #ifdef LDAP_THREAD_HAVE_GETCONCURRENCY int ldap_pvt_thread_get_concurrency(void) { return thr_getconcurrency(); } #endif int ldap_pvt_thread_create( ldap_pvt_thread_t * thread, int detach, void *(*start_routine)( void *), void *arg) { return( thr_create( NULL, LDAP_PVT_THREAD_STACK_SIZE, start_routine, arg, detach ? THR_DETACHED : 0, thread ) ); } void ldap_pvt_thread_exit( void *retval ) { thr_exit( NULL ); } int ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return ) { thr_join( thread, NULL, thread_return ); return 0; } int ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo ) { thr_kill( thread, signo ); return 0; } int ldap_pvt_thread_yield( void ) { thr_yield(); return 0; } int ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond ) { return( cond_init( cond, USYNC_THREAD, NULL ) ); } int ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond ) { return( cond_signal( cond ) ); } int ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cv ) { return( cond_broadcast( cv ) ); } int ldap_pvt_thread_cond_wait( ldap_pvt_thread_cond_t *cond, ldap_pvt_thread_mutex_t *mutex ) { return( cond_wait( cond, mutex ) ); } int ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cv ) { return( cond_destroy( cv ) ); } int ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex ) { return( mutex_init( mutex, USYNC_THREAD, NULL ) ); } int ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex ) { return( mutex_destroy( mutex ) ); } int ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex ) { return( mutex_lock( mutex ) ); } int ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex ) { return( mutex_unlock( mutex ) ); } int ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mp ) { return( mutex_trylock( mp ) ); } int ldap_pvt_thread_mutex_recursive_init( ldap_pvt_thread_mutex_t *mutex ) { return( mutex_init( mutex, USYNC_THREAD | LOCK_RECURSIVE, NULL ) ); } ldap_pvt_thread_t ldap_pvt_thread_self( void ) { return thr_self(); } int ldap_pvt_thread_key_create( ldap_pvt_thread_key_t *key ) { return thr_keycreate( key, NULL ); } int ldap_pvt_thread_key_destroy( ldap_pvt_thread_key_t key ) { return( 0 ); } int ldap_pvt_thread_key_setdata( ldap_pvt_thread_key_t key, void *data ) { return thr_setspecific( key, data ); } int ldap_pvt_thread_key_getdata( ldap_pvt_thread_key_t key, void **data ) { return thr_getspecific( key, data ); } #endif /* HAVE_THR */ openldap-2.5.11+dfsg/libraries/libldap/dntest.c0000644000175000017500000001750714172327167020101 0ustar ryanryan/* dntest.c -- OpenLDAP DN API Test Program */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This program was initially developed by Pierangelo Masarati * for inclusion in OpenLDAP Software. */ /* * This program is designed to test the ldap_str2dn/ldap_dn2str * functions */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" #include "ldif.h" #include "lutil.h" #include "lutil_ldap.h" #include "ldap_defaults.h" int main( int argc, char *argv[] ) { int rc, i, debug = 0, f2 = 0; unsigned flags[ 2 ] = { 0U, 0 }; char *strin, *str = NULL, buf[ 1024 ]; LDAPDN dn, dn2 = NULL; while ( 1 ) { int opt = getopt( argc, argv, "d:" ); if ( opt == EOF ) { break; } switch ( opt ) { case 'd': debug = atoi( optarg ); break; } } optind--; argc -= optind; argv += optind; if ( argc < 2 ) { fprintf( stderr, "usage: dntest [flags-in[,...]] [flags-out[,...]]\n\n" ); fprintf( stderr, "\tflags-in: V3,V2,DCE,\n" ); fprintf( stderr, "\tflags-out: V3,V2,UFN,DCE,AD,\n\n" ); fprintf( stderr, "\t: PRETTY,PEDANTIC,NOSPACES,NOONESPACE\n\n" ); return( 0 ); } if ( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) { fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug ); } if ( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug ) != LDAP_OPT_SUCCESS ) { fprintf( stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug ); } if ( strcmp( argv[ 1 ], "-" ) == 0 ) { size_t len = fgets( buf, sizeof( buf ), stdin ) ? strlen( buf ) : 0; if ( len == 0 || buf[ --len ] == '\n' ) { buf[ len ] = '\0'; } strin = buf; } else { strin = argv[ 1 ]; } if ( argc >= 3 ) { for ( i = 0; i < argc - 2; i++ ) { char *s, *e; for ( s = argv[ 2 + i ]; s; s = e ) { e = strchr( s, ',' ); if ( e != NULL ) { e[ 0 ] = '\0'; e++; } if ( !strcasecmp( s, "V3" ) ) { flags[ i ] |= LDAP_DN_FORMAT_LDAPV3; } else if ( !strcasecmp( s, "V2" ) ) { flags[ i ] |= LDAP_DN_FORMAT_LDAPV2; } else if ( !strcasecmp( s, "DCE" ) ) { flags[ i ] |= LDAP_DN_FORMAT_DCE; } else if ( !strcasecmp( s, "UFN" ) ) { flags[ i ] |= LDAP_DN_FORMAT_UFN; } else if ( !strcasecmp( s, "AD" ) ) { flags[ i ] |= LDAP_DN_FORMAT_AD_CANONICAL; } else if ( !strcasecmp( s, "PRETTY" ) ) { flags[ i ] |= LDAP_DN_PRETTY; } else if ( !strcasecmp( s, "PEDANTIC" ) ) { flags[ i ] |= LDAP_DN_PEDANTIC; } else if ( !strcasecmp( s, "NOSPACES" ) ) { flags[ i ] |= LDAP_DN_P_NOLEADTRAILSPACES; } else if ( !strcasecmp( s, "NOONESPACE" ) ) { flags[ i ] |= LDAP_DN_P_NOSPACEAFTERRDN; } } } } if ( flags[ 1 ] == 0 ) flags[ 1 ] = LDAP_DN_FORMAT_LDAPV3; f2 = 1; rc = ldap_str2dn( strin, &dn, flags[ 0 ] ); if ( rc == LDAP_SUCCESS ) { int i; if ( dn ) { for ( i = 0; dn[ i ]; i++ ) { LDAPRDN rdn = dn[ i ]; char *rstr = NULL; if ( ldap_rdn2str( rdn, &rstr, flags[ f2 ] ) ) { fprintf( stdout, "\tldap_rdn2str() failed\n" ); continue; } fprintf( stdout, "\tldap_rdn2str() = \"%s\"\n", rstr ); ldap_memfree( rstr ); } } else { fprintf( stdout, "\tempty DN\n" ); } } str = NULL; if ( rc == LDAP_SUCCESS && ldap_dn2str( dn, &str, flags[ f2 ] ) == LDAP_SUCCESS ) { char **values, *tmp, *tmp2, *str2 = NULL; int n; fprintf( stdout, "\nldap_dn2str(ldap_str2dn(\"%s\"))\n" "\t= \"%s\"\n", strin, str ); switch ( flags[ f2 ] & LDAP_DN_FORMAT_MASK ) { case LDAP_DN_FORMAT_UFN: case LDAP_DN_FORMAT_AD_CANONICAL: return( 0 ); case LDAP_DN_FORMAT_LDAPV3: case LDAP_DN_FORMAT_LDAPV2: n = ldap_dn2domain( strin, &tmp ); if ( n ) { fprintf( stdout, "\nldap_dn2domain(\"%s\") FAILED\n", strin ); } else { fprintf( stdout, "\nldap_dn2domain(\"%s\")\n" "\t= \"%s\"\n", strin, tmp ? tmp : "" ); } ldap_memfree( tmp ); tmp = ldap_dn2ufn( strin ); fprintf( stdout, "\nldap_dn2ufn(\"%s\")\n" "\t= \"%s\"\n", strin, tmp ? tmp : "" ); ldap_memfree( tmp ); tmp = ldap_dn2dcedn( strin ); fprintf( stdout, "\nldap_dn2dcedn(\"%s\")\n" "\t= \"%s\"\n", strin, tmp ? tmp : "" ); tmp2 = ldap_dcedn2dn( tmp ); fprintf( stdout, "\nldap_dcedn2dn(\"%s\")\n" "\t= \"%s\"\n", tmp ? tmp : "", tmp2 ? tmp2 : "" ); ldap_memfree( tmp ); ldap_memfree( tmp2 ); tmp = ldap_dn2ad_canonical( strin ); fprintf( stdout, "\nldap_dn2ad_canonical(\"%s\")\n" "\t= \"%s\"\n", strin, tmp ? tmp : "" ); ldap_memfree( tmp ); fprintf( stdout, "\nldap_explode_dn(\"%s\"):\n", str ); values = ldap_explode_dn( str, 0 ); for ( n = 0; values && values[ n ]; n++ ) { char **vv; int nn; fprintf( stdout, "\t\"%s\"\n", values[ n ] ); fprintf( stdout, "\tldap_explode_rdn(\"%s\")\n", values[ n ] ); vv = ldap_explode_rdn( values[ n ], 0 ); for ( nn = 0; vv && vv[ nn ]; nn++ ) { fprintf( stdout, "\t\t'%s'\n", vv[ nn ] ); } LDAP_VFREE( vv ); fprintf( stdout, "\tldap_explode_rdn(\"%s\")" " (no types)\n", values[ n ] ); vv = ldap_explode_rdn( values[ n ], 1 ); for ( nn = 0; vv && vv[ nn ]; nn++ ) { fprintf( stdout, "\t\t\t\"%s\"\n", vv[ nn ] ); } LDAP_VFREE( vv ); } LDAP_VFREE( values ); fprintf( stdout, "\nldap_explode_dn(\"%s\")" " (no types):\n", str ); values = ldap_explode_dn( str, 1 ); for ( n = 0; values && values[ n ]; n++ ) { fprintf( stdout, "\t\"%s\"\n", values[ n ] ); } LDAP_VFREE( values ); break; } dn2 = NULL; rc = ldap_str2dn( str, &dn2, flags[ f2 ] ); str2 = NULL; if ( rc == LDAP_SUCCESS && ldap_dn2str( dn2, &str2, flags[ f2 ] ) == LDAP_SUCCESS ) { int iRDN; fprintf( stdout, "\n\"%s\"\n\t == \"%s\" ? %s\n", str, str2, strcmp( str, str2 ) == 0 ? "yes" : "no" ); if( dn != NULL && dn2 == NULL ) { fprintf( stdout, "dn mismatch\n" ); } else if (( dn != NULL ) && (dn2 != NULL)) for ( iRDN = 0; dn[ iRDN ] && dn2[ iRDN ]; iRDN++ ) { LDAPRDN r = dn[ iRDN ]; LDAPRDN r2 = dn2[ iRDN ]; int iAVA; for ( iAVA = 0; r[ iAVA ] && r2[ iAVA ]; iAVA++ ) { LDAPAVA *a = r[ iAVA ]; LDAPAVA *a2 = r2[ iAVA ]; if ( a->la_attr.bv_len != a2->la_attr.bv_len ) { fprintf( stdout, "ava(%d), rdn(%d) attr len mismatch (%ld->%ld)\n", iAVA + 1, iRDN + 1, a->la_attr.bv_len, a2->la_attr.bv_len ); } else if ( memcmp( a->la_attr.bv_val, a2->la_attr.bv_val, a->la_attr.bv_len ) ) { fprintf( stdout, "ava(%d), rdn(%d) attr mismatch\n", iAVA + 1, iRDN + 1 ); } else if ( a->la_flags != a2->la_flags ) { fprintf( stdout, "ava(%d), rdn(%d) flag mismatch (%x->%x)\n", iAVA + 1, iRDN + 1, a->la_flags, a2->la_flags ); } else if ( a->la_value.bv_len != a2->la_value.bv_len ) { fprintf( stdout, "ava(%d), rdn(%d) value len mismatch (%ld->%ld)\n", iAVA + 1, iRDN + 1, a->la_value.bv_len, a2->la_value.bv_len ); } else if ( memcmp( a->la_value.bv_val, a2->la_value.bv_val, a->la_value.bv_len ) ) { fprintf( stdout, "ava(%d), rdn(%d) value mismatch\n", iAVA + 1, iRDN + 1 ); } } } ldap_dnfree( dn2 ); ldap_memfree( str2 ); } ldap_memfree( str ); } ldap_dnfree( dn ); /* note: dn is not freed */ return( 0 ); } openldap-2.5.11+dfsg/libraries/libldap/os-local.c0000644000175000017500000002005414172327167020300 0ustar ryanryan/* os-local.c -- platform-specific domain socket code */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. */ /* Portions (C) Copyright PADL Software Pty Ltd. 1999 * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that this notice is preserved * and that due credit is given to PADL Software Pty Ltd. This software * is provided ``as is'' without express or implied warranty. */ #include "portable.h" #ifdef LDAP_PF_LOCAL #include #include #include #include #include #include #include #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_SYS_UIO_H #include #endif #ifdef HAVE_IO_H #include #endif /* HAVE_IO_H */ #ifdef HAVE_FCNTL_H #include #endif #include "ldap-int.h" #include "ldap_defaults.h" static void ldap_pvt_set_errno(int err) { errno = err; } static int ldap_pvt_ndelay_on(LDAP *ld, int fd) { Debug1(LDAP_DEBUG_TRACE, "ldap_ndelay_on: %d\n",fd ); return ber_pvt_socket_set_nonblock( fd, 1 ); } static int ldap_pvt_ndelay_off(LDAP *ld, int fd) { Debug1(LDAP_DEBUG_TRACE, "ldap_ndelay_off: %d\n",fd ); return ber_pvt_socket_set_nonblock( fd, 0 ); } static ber_socket_t ldap_pvt_socket(LDAP *ld) { ber_socket_t s = socket(PF_LOCAL, SOCK_STREAM, 0); Debug1(LDAP_DEBUG_TRACE, "ldap_new_socket: %d\n",s ); #ifdef FD_CLOEXEC fcntl(s, F_SETFD, FD_CLOEXEC); #endif return ( s ); } static int ldap_pvt_close_socket(LDAP *ld, int s) { Debug1(LDAP_DEBUG_TRACE, "ldap_close_socket: %d\n",s ); return tcp_close(s); } #undef TRACE #define TRACE do { \ char ebuf[128]; \ int saved_errno = errno; \ Debug3(LDAP_DEBUG_TRACE, "ldap_is_socket_ready: error on socket %d: errno: %d (%s)\n", \ s, \ saved_errno, \ AC_STRERROR_R(saved_errno, ebuf, sizeof ebuf)); \ } while( 0 ) /* * check the socket for errors after select returned. */ static int ldap_pvt_is_socket_ready(LDAP *ld, int s) { Debug1(LDAP_DEBUG_TRACE, "ldap_is_sock_ready: %d\n",s ); #if defined( notyet ) /* && defined( SO_ERROR ) */ { int so_errno; ber_socklen_t dummy = sizeof(so_errno); if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy ) == AC_SOCKET_ERROR ) { return -1; } if ( so_errno ) { ldap_pvt_set_errno(so_errno); TRACE; return -1; } return 0; } #else { /* error slippery */ struct sockaddr_un sa; char ch; ber_socklen_t dummy = sizeof(sa); if ( getpeername( s, (struct sockaddr *) &sa, &dummy ) == AC_SOCKET_ERROR ) { /* XXX: needs to be replace with ber_stream_read() */ (void)read(s, &ch, 1); TRACE; return -1; } return 0; } #endif return -1; } #undef TRACE #ifdef LDAP_PF_LOCAL_SENDMSG static const char abandonPDU[] = {LDAP_TAG_MESSAGE, 6, LDAP_TAG_MSGID, 1, 0, LDAP_REQ_ABANDON, 1, 0}; #endif static int ldap_pvt_connect(LDAP *ld, ber_socket_t s, struct sockaddr_un *sa, int async) { int rc; struct timeval tv, *opt_tv = NULL; if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) { tv = ld->ld_options.ldo_tm_net; opt_tv = &tv; } Debug3(LDAP_DEBUG_TRACE, "ldap_connect_timeout: fd: %d tm: %ld async: %d\n", s, opt_tv ? tv.tv_sec : -1L, async); if ( ldap_pvt_ndelay_on(ld, s) == -1 ) return -1; if ( connect(s, (struct sockaddr *) sa, sizeof(struct sockaddr_un)) != AC_SOCKET_ERROR ) { if ( ldap_pvt_ndelay_off(ld, s) == -1 ) return -1; #ifdef LDAP_PF_LOCAL_SENDMSG /* Send a dummy message with access rights. Remote side will * obtain our uid/gid by fstat'ing this descriptor. The * descriptor permissions must match exactly, and we also * send the socket name, which must also match. */ sendcred: { int fds[2]; ber_socklen_t salen = sizeof(*sa); if (pipe(fds) == 0) { /* Abandon, noop, has no reply */ struct iovec iov; struct msghdr msg = {0}; # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL # ifndef CMSG_SPACE # define CMSG_SPACE(len) (_CMSG_ALIGN( sizeof(struct cmsghdr)) + _CMSG_ALIGN(len) ) # endif # ifndef CMSG_LEN # define CMSG_LEN(len) (_CMSG_ALIGN( sizeof(struct cmsghdr)) + (len) ) # endif union { struct cmsghdr cm; unsigned char control[CMSG_SPACE(sizeof(int))]; } control_un; struct cmsghdr *cmsg; # endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ msg.msg_name = NULL; msg.msg_namelen = 0; iov.iov_base = (char *) abandonPDU; iov.iov_len = sizeof abandonPDU; msg.msg_iov = &iov; msg.msg_iovlen = 1; # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg.msg_control = control_un.control; msg.msg_controllen = sizeof( control_un.control ); msg.msg_flags = 0; cmsg = CMSG_FIRSTHDR( &msg ); cmsg->cmsg_len = CMSG_LEN( sizeof(int) ); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; *((int *)CMSG_DATA(cmsg)) = fds[0]; # else msg.msg_accrights = (char *)fds; msg.msg_accrightslen = sizeof(int); # endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ getpeername( s, (struct sockaddr *) sa, &salen ); fchmod( fds[0], S_ISUID|S_IRWXU ); write( fds[1], sa, salen ); sendmsg( s, &msg, 0 ); close(fds[0]); close(fds[1]); } } #endif return 0; } if ( errno != EINPROGRESS && errno != EWOULDBLOCK ) return -1; #ifdef notyet if ( async ) return -2; #endif #ifdef HAVE_POLL { struct pollfd fd; int timeout = INFTIM; if( opt_tv != NULL ) timeout = TV2MILLISEC( &tv ); fd.fd = s; fd.events = POLL_WRITE; do { fd.revents = 0; rc = poll( &fd, 1, timeout ); } while( rc == AC_SOCKET_ERROR && errno == EINTR && LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART )); if( rc == AC_SOCKET_ERROR ) return rc; if( fd.revents & POLL_WRITE ) { if ( ldap_pvt_is_socket_ready(ld, s) == -1 ) return -1; if ( ldap_pvt_ndelay_off(ld, s) == -1 ) return -1; #ifdef LDAP_PF_LOCAL_SENDMSG goto sendcred; #else return ( 0 ); #endif } } #else { fd_set wfds, *z=NULL; #ifdef FD_SETSIZE if ( s >= FD_SETSIZE ) { rc = AC_SOCKET_ERROR; tcp_close( s ); ldap_pvt_set_errno( EMFILE ); return rc; } #endif do { FD_ZERO(&wfds); FD_SET(s, &wfds ); rc = select( ldap_int_tblsize, z, &wfds, z, opt_tv ? &tv : NULL ); } while( rc == AC_SOCKET_ERROR && errno == EINTR && LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART )); if( rc == AC_SOCKET_ERROR ) return rc; if ( FD_ISSET(s, &wfds) ) { if ( ldap_pvt_is_socket_ready(ld, s) == -1 ) return -1; if ( ldap_pvt_ndelay_off(ld, s) == -1 ) return -1; #ifdef LDAP_PF_LOCAL_SENDMSG goto sendcred; #else return ( 0 ); #endif } } #endif Debug0(LDAP_DEBUG_TRACE, "ldap_connect_timeout: timed out\n" ); ldap_pvt_set_errno( ETIMEDOUT ); return ( -1 ); } int ldap_connect_to_path(LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv, int async) { struct sockaddr_un server; ber_socket_t s; int rc; const char *path = srv->lud_host; Debug0(LDAP_DEBUG_TRACE, "ldap_connect_to_path\n" ); if ( path == NULL || path[0] == '\0' ) { path = LDAPI_SOCK; } else { if ( strlen(path) > (sizeof( server.sun_path ) - 1) ) { ldap_pvt_set_errno( ENAMETOOLONG ); return -1; } } s = ldap_pvt_socket( ld ); if ( s == AC_SOCKET_INVALID ) { return -1; } Debug1(LDAP_DEBUG_TRACE, "ldap_connect_to_path: Trying %s\n", path ); memset( &server, '\0', sizeof(server) ); server.sun_family = AF_LOCAL; strcpy( server.sun_path, path ); rc = ldap_pvt_connect(ld, s, &server, async); if (rc == 0) { rc = ldap_int_connect_cbs( ld, sb, &s, srv, (struct sockaddr *)&server ); } if ( rc ) { ldap_pvt_close_socket(ld, s); } return rc; } #else static int dummy; /* generate also a warning: 'dummy' defined but not used (at least here) */ #endif /* LDAP_PF_LOCAL */ openldap-2.5.11+dfsg/libraries/libldap/vlvctrl.c0000644000175000017500000002301214172327167020260 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved. * * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. *--- * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License * can be found in the file "build/LICENSE-2.0.1" in this distribution * of OpenLDAP Software. */ #include "portable.h" #include #include #include #include #include "ldap-int.h" #define LDAP_VLVBYINDEX_IDENTIFIER 0xa0L #define LDAP_VLVBYVALUE_IDENTIFIER 0x81L #define LDAP_VLVCONTEXT_IDENTIFIER 0x04L /*--- ldap_create_vlv_control Create and encode the Virtual List View control. ld (IN) An LDAP session handle. vlvinfop (IN) The address of an LDAPVLVInfo structure whose contents are used to construct the value of the control that is created. value (OUT) A struct berval that contains the value to be assigned to the ldctl_value member of an LDAPControl structure that contains the VirtualListViewRequest control. The bv_val member of the berval structure SHOULD be freed when it is no longer in use by calling ldap_memfree(). Ber encoding VirtualListViewRequest ::= SEQUENCE { beforeCount INTEGER (0 .. maxInt), afterCount INTEGER (0 .. maxInt), CHOICE { byoffset [0] SEQUENCE, { offset INTEGER (0 .. maxInt), contentCount INTEGER (0 .. maxInt) } [1] greaterThanOrEqual assertionValue } contextID OCTET STRING OPTIONAL } Note: The first time the VLV control is created, the ldvlv_context field of the LDAPVLVInfo structure should be set to NULL. The context obtained from calling ldap_parse_vlv_control() should be used as the context in the next ldap_create_vlv_control call. ---*/ int ldap_create_vlv_control_value( LDAP *ld, LDAPVLVInfo *vlvinfop, struct berval *value ) { ber_tag_t tag; BerElement *ber; if ( ld == NULL || vlvinfop == NULL || value == NULL ) { if ( ld ) ld->ld_errno = LDAP_PARAM_ERROR; return LDAP_PARAM_ERROR; } assert( LDAP_VALID( ld ) ); value->bv_val = NULL; value->bv_len = 0; ld->ld_errno = LDAP_SUCCESS; ber = ldap_alloc_ber_with_options( ld ); if ( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } tag = ber_printf( ber, "{ii" /*}*/, vlvinfop->ldvlv_before_count, vlvinfop->ldvlv_after_count ); if ( tag == LBER_ERROR ) { goto error_return; } if ( vlvinfop->ldvlv_attrvalue == NULL ) { tag = ber_printf( ber, "t{iiN}", LDAP_VLVBYINDEX_IDENTIFIER, vlvinfop->ldvlv_offset, vlvinfop->ldvlv_count ); if ( tag == LBER_ERROR ) { goto error_return; } } else { tag = ber_printf( ber, "tO", LDAP_VLVBYVALUE_IDENTIFIER, vlvinfop->ldvlv_attrvalue ); if ( tag == LBER_ERROR ) { goto error_return; } } if ( vlvinfop->ldvlv_context ) { tag = ber_printf( ber, "tO", LDAP_VLVCONTEXT_IDENTIFIER, vlvinfop->ldvlv_context ); if ( tag == LBER_ERROR ) { goto error_return; } } tag = ber_printf( ber, /*{*/ "N}" ); if ( tag == LBER_ERROR ) { goto error_return; } if ( ber_flatten2( ber, value, 1 ) == -1 ) { ld->ld_errno = LDAP_NO_MEMORY; } if ( 0 ) { error_return:; ld->ld_errno = LDAP_ENCODING_ERROR; } if ( ber != NULL ) { ber_free( ber, 1 ); } return ld->ld_errno; } /*--- ldap_create_vlv_control Create and encode the Virtual List View control. ld (IN) An LDAP session handle. vlvinfop (IN) The address of an LDAPVLVInfo structure whose contents are used to construct the value of the control that is created. ctrlp (OUT) A result parameter that will be assigned the address of an LDAPControl structure that contains the VirtualListViewRequest control created by this function. The memory occupied by the LDAPControl structure SHOULD be freed when it is no longer in use by calling ldap_control_free(). Ber encoding VirtualListViewRequest ::= SEQUENCE { beforeCount INTEGER (0 .. maxInt), afterCount INTEGER (0 .. maxInt), CHOICE { byoffset [0] SEQUENCE, { offset INTEGER (0 .. maxInt), contentCount INTEGER (0 .. maxInt) } [1] greaterThanOrEqual assertionValue } contextID OCTET STRING OPTIONAL } Note: The first time the VLV control is created, the ldvlv_context field of the LDAPVLVInfo structure should be set to NULL. The context obtained from calling ldap_parse_vlv_control() should be used as the context in the next ldap_create_vlv_control call. ---*/ int ldap_create_vlv_control( LDAP *ld, LDAPVLVInfo *vlvinfop, LDAPControl **ctrlp ) { struct berval value; if ( ctrlp == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; } ld->ld_errno = ldap_create_vlv_control_value( ld, vlvinfop, &value ); if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = ldap_control_create( LDAP_CONTROL_VLVREQUEST, 1, &value, 0, ctrlp ); if ( ld->ld_errno != LDAP_SUCCESS ) { LDAP_FREE( value.bv_val ); } } return ld->ld_errno; } /*--- ldap_parse_vlvresponse_control Decode the Virtual List View control return information. ld (IN) An LDAP session handle. ctrl (IN) The address of the LDAPControl structure. target_posp (OUT) This result parameter is filled in with the list index of the target entry. If this parameter is NULL, the target position is not returned. list_countp (OUT) This result parameter is filled in with the server's estimate of the size of the list. If this parameter is NULL, the size is not returned. contextp (OUT) This result parameter is filled in with the address of a struct berval that contains the server- generated context identifier if one was returned by the server. If the server did not return a context identifier, this parameter will be set to NULL, even if an error occurred. The returned context SHOULD be used in the next call to create a VLV sort control. The struct berval returned SHOULD be disposed of by calling ber_bvfree() when it is no longer needed. If NULL is passed for contextp, the context identifier is not returned. errcodep (OUT) This result parameter is filled in with the VLV result code. If this parameter is NULL, the result code is not returned. Ber encoding VirtualListViewResponse ::= SEQUENCE { targetPosition INTEGER (0 .. maxInt), contentCount INTEGER (0 .. maxInt), virtualListViewResult ENUMERATED { success (0), operationsError (1), unwillingToPerform (53), insufficientAccessRights (50), busy (51), timeLimitExceeded (3), adminLimitExceeded (11), sortControlMissing (60), offsetRangeError (61), other (80) }, contextID OCTET STRING OPTIONAL } ---*/ int ldap_parse_vlvresponse_control( LDAP *ld, LDAPControl *ctrl, ber_int_t *target_posp, ber_int_t *list_countp, struct berval **contextp, ber_int_t *errcodep ) { BerElement *ber; ber_int_t pos, count, err; ber_tag_t tag, berTag; ber_len_t berLen; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); if (contextp) { *contextp = NULL; /* Make sure we return a NULL if error occurs. */ } if (ctrl == NULL) { ld->ld_errno = LDAP_PARAM_ERROR; return(ld->ld_errno); } if (strcmp(LDAP_CONTROL_VLVRESPONSE, ctrl->ldctl_oid) != 0) { /* Not VLV Response control */ ld->ld_errno = LDAP_CONTROL_NOT_FOUND; return(ld->ld_errno); } /* Create a BerElement from the berval returned in the control. */ ber = ber_init(&ctrl->ldctl_value); if (ber == NULL) { ld->ld_errno = LDAP_NO_MEMORY; return(ld->ld_errno); } /* Extract the data returned in the control. */ tag = ber_scanf(ber, "{iie" /*}*/, &pos, &count, &err); if( tag == LBER_ERROR) { ber_free(ber, 1); ld->ld_errno = LDAP_DECODING_ERROR; return(ld->ld_errno); } /* Since the context is the last item encoded, if caller doesn't want it returned, don't decode it. */ if (contextp) { if (LDAP_VLVCONTEXT_IDENTIFIER == ber_peek_tag(ber, &berLen)) { tag = ber_scanf(ber, "tO", &berTag, contextp); if( tag == LBER_ERROR) { ber_free(ber, 1); ld->ld_errno = LDAP_DECODING_ERROR; return(ld->ld_errno); } } } ber_free(ber, 1); /* Return data to the caller for items that were requested. */ if (target_posp) *target_posp = pos; if (list_countp) *list_countp = count; if (errcodep) *errcodep = err; ld->ld_errno = LDAP_SUCCESS; return(ld->ld_errno); } openldap-2.5.11+dfsg/libraries/libldap/ldifutil.c0000644000175000017500000005032614172327167020410 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ /* * This file contains public API to help with parsing LDIF */ #include "portable.h" #include #include #include #include #include #include #include #include "ldap-int.h" #include "ldif.h" #define M_SEP 0x7f /* strings found in LDIF entries */ static struct berval BV_VERSION = BER_BVC("version"); static struct berval BV_DN = BER_BVC("dn"); static struct berval BV_CONTROL = BER_BVC("control"); static struct berval BV_CHANGETYPE = BER_BVC("changetype"); static struct berval BV_ADDCT = BER_BVC("add"); static struct berval BV_MODIFYCT = BER_BVC("modify"); static struct berval BV_DELETECT = BER_BVC("delete"); static struct berval BV_MODRDNCT = BER_BVC("modrdn"); static struct berval BV_MODDNCT = BER_BVC("moddn"); static struct berval BV_RENAMECT = BER_BVC("rename"); static struct berval BV_MODOPADD = BER_BVC("add"); static struct berval BV_MODOPREPLACE = BER_BVC("replace"); static struct berval BV_MODOPDELETE = BER_BVC("delete"); static struct berval BV_MODOPINCREMENT = BER_BVC("increment"); static struct berval BV_NEWRDN = BER_BVC("newrdn"); static struct berval BV_DELETEOLDRDN = BER_BVC("deleteoldrdn"); static struct berval BV_NEWSUP = BER_BVC("newsuperior"); #define BV_CASEMATCH(a, b) \ ((a)->bv_len == (b)->bv_len && 0 == strcasecmp((a)->bv_val, (b)->bv_val)) static int parse_ldif_control LDAP_P(( struct berval *bval, LDAPControl ***ppctrls )); void ldap_ldif_record_done( LDIFRecord *lr ) { int i; /* the LDAPControl stuff does not allow the use of memory contexts */ if (lr->lr_ctrls != NULL) { ldap_controls_free( lr->lr_ctrls ); } if ( lr->lr_lm != NULL ) { ber_memfree_x( lr->lr_lm, lr->lr_ctx ); } if ( lr->lr_mops != NULL ) { ber_memfree_x( lr->lr_mops, lr->lr_ctx ); } for (i=lr->lr_lines-1; i>=0; i--) if ( lr->lr_freeval[i] ) ber_memfree_x( lr->lr_vals[i].bv_val, lr->lr_ctx ); ber_memfree_x( lr->lr_btype, lr->lr_ctx ); memset( lr, 0, sizeof(LDIFRecord) ); } /* * ldap_parse_ldif_record_x() will convert an LDIF record read with ldif_read_record() * into an array of LDAPMod* and an array of LDAPControl*, suitable for passing * directly to any other LDAP API function that takes LDAPMod** and LDAPControl** * arguments, such as ldap_modify_s(). * * rbuf - the ldif record buffer returned from ldif_read_record - rbuf.bv_val must be * writable - will use ldif_getline to read from it * linenum - the ldif line number returned from ldif_read_record * - used for logging errors (e.g. error at line N) * lr - holds the data to return * errstr - a string used for logging (usually the program name e.g. "ldapmodify" * flags - 0 or some combination of LDIF_DEFAULT_ADD LDIF_ENTRIES_ONLY LDIF_NO_CONTROLS * ctx is the memory allocation context - if NULL, use the standard memory allocator */ int ldap_parse_ldif_record_x( struct berval *rbuf, unsigned long linenum, LDIFRecord *lr, const char *errstr, unsigned int flags, void *ctx ) { char *line, *dn; int rc, modop; int expect_modop, expect_sep; int ldapadd, new_entry, delete_entry, got_all, no_dn; LDAPMod **pmods; int version; LDAPControl **pctrls; int i, j, k, idn, nmods; struct berval **bvl, bv; assert( lr != NULL ); assert( rbuf != NULL ); memset( lr, 0, sizeof(LDIFRecord) ); lr->lr_ctx = ctx; /* save memory context for later */ ldapadd = flags & LDIF_DEFAULT_ADD; no_dn = flags & LDIF_NO_DN; expect_modop = flags & LDIF_MODS_ONLY; new_entry = ldapadd; rc = got_all = delete_entry = modop = 0; expect_sep = 0; version = 0; pmods = NULL; pctrls = NULL; dn = NULL; lr->lr_lines = ldif_countlines( rbuf->bv_val ); lr->lr_btype = ber_memcalloc_x( 1, (lr->lr_lines+1)*2*sizeof(struct berval)+lr->lr_lines, ctx ); if ( !lr->lr_btype ) return LDAP_NO_MEMORY; lr->lr_vals = lr->lr_btype+lr->lr_lines+1; lr->lr_freeval = (char *)(lr->lr_vals+lr->lr_lines+1); i = -1; while ( rc == 0 && ( line = ldif_getline( &rbuf->bv_val )) != NULL ) { int freev; if ( *line == '\n' || *line == '\0' ) { break; } ++i; if ( line[0] == '-' && !line[1] ) { BER_BVZERO( lr->lr_btype+i ); lr->lr_freeval[i] = 0; continue; } if ( ( rc = ldif_parse_line2( line, lr->lr_btype+i, lr->lr_vals+i, &freev ) ) < 0 ) { fprintf( stderr, _("%s: invalid format (line %lu) entry: \"%s\"\n"), errstr, linenum+i, dn == NULL ? "" : dn ); rc = LDAP_PARAM_ERROR; goto leave; } lr->lr_freeval[i] = freev; if ( dn == NULL && !no_dn ) { if ( linenum+i == 1 && BV_CASEMATCH( lr->lr_btype+i, &BV_VERSION )) { /* lutil_atoi() introduces a dependence of libldap * on liblutil; we only allow version 1 by now (ITS#6654) */ #if 0 int v; if( lr->lr_vals[i].bv_len == 0 || lutil_atoi( &v, lr->lr_vals[i].bv_val) != 0 || v != 1 ) #endif static const struct berval version1 = { 1, "1" }; if ( lr->lr_vals[i].bv_len != version1.bv_len || strncmp( lr->lr_vals[i].bv_val, version1.bv_val, version1.bv_len ) != 0 ) { fprintf( stderr, _("%s: invalid version %s, line %lu (ignored)\n"), errstr, lr->lr_vals[i].bv_val, linenum ); } version++; } else if ( BV_CASEMATCH( lr->lr_btype+i, &BV_DN )) { lr->lr_dn = lr->lr_vals[i]; dn = lr->lr_dn.bv_val; /* primarily for logging */ idn = i; } /* skip all lines until we see "dn:" */ } } /* check to make sure there was a dn: line */ if ( !dn && !no_dn ) { rc = 0; goto leave; } lr->lr_lines = i+1; if( lr->lr_lines == 0 ) { rc = 0; goto leave; } if( version && lr->lr_lines == 1 ) { rc = 0; goto leave; } if ( no_dn ) { i = 0; } else { i = idn+1; /* Check for "control" tag after dn and before changetype. */ if ( BV_CASEMATCH( lr->lr_btype+i, &BV_CONTROL )) { /* Parse and add it to the list of controls */ if ( !( flags & LDIF_NO_CONTROLS ) ) { rc = parse_ldif_control( lr->lr_vals+i, &pctrls ); if (rc != 0) { fprintf( stderr, _("%s: Error processing %s line, line %lu: %s\n"), errstr, BV_CONTROL.bv_val, linenum+i, ldap_err2string(rc) ); } } i++; if ( i>= lr->lr_lines ) { short_input: fprintf( stderr, _("%s: Expecting more input after %s line, line %lu\n"), errstr, lr->lr_btype[i-1].bv_val, linenum+i ); rc = LDAP_PARAM_ERROR; goto leave; } } } /* Check for changetype */ if ( BV_CASEMATCH( lr->lr_btype+i, &BV_CHANGETYPE )) { #ifdef LIBERAL_CHANGETYPE_MODOP /* trim trailing spaces (and log warning ...) */ int icnt; for ( icnt = lr->lr_vals[i].bv_len; --icnt > 0; ) { if ( !isspace( (unsigned char) lr->lr_vals[i].bv_val[icnt] ) ) { break; } } if ( ++icnt != lr->lr_vals[i].bv_len ) { fprintf( stderr, _("%s: illegal trailing space after" " \"%s: %s\" trimmed (line %lu, entry \"%s\")\n"), errstr, BV_CHANGETYPE.bv_val, lr->lr_vals[i].bv_val, linenum+i, dn ); lr->lr_vals[i].bv_val[icnt] = '\0'; } #endif /* LIBERAL_CHANGETYPE_MODOP */ /* if LDIF_ENTRIES_ONLY, then either the changetype must be add, or there must be no changetype, and the flag LDIF_DEFAULT_ADD must be set */ if ( flags & LDIF_ENTRIES_ONLY ) { if ( !( BV_CASEMATCH( lr->lr_vals+i, &BV_ADDCT )) ) { ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug, _("%s: skipping LDIF record beginning at line %lu: " "changetype '%.*s' found but entries only was requested\n"), errstr, linenum, (int)lr->lr_vals[i].bv_len, (const char *)lr->lr_vals[i].bv_val ); goto leave; } } if ( BV_CASEMATCH( lr->lr_vals+i, &BV_MODIFYCT )) { new_entry = 0; expect_modop = 1; } else if ( BV_CASEMATCH( lr->lr_vals+i, &BV_ADDCT )) { new_entry = 1; modop = LDAP_MOD_ADD; } else if ( BV_CASEMATCH( lr->lr_vals+i, &BV_MODRDNCT ) || BV_CASEMATCH( lr->lr_vals+i, &BV_MODDNCT ) || BV_CASEMATCH( lr->lr_vals+i, &BV_RENAMECT )) { i++; if ( i >= lr->lr_lines ) goto short_input; if ( !BV_CASEMATCH( lr->lr_btype+i, &BV_NEWRDN )) { fprintf( stderr, _("%s: expecting \"%s:\" but saw" " \"%s:\" (line %lu, entry \"%s\")\n"), errstr, BV_NEWRDN.bv_val, lr->lr_btype[i].bv_val, linenum+i, dn ); rc = LDAP_PARAM_ERROR; goto leave; } lr->lrop_newrdn = lr->lr_vals[i]; i++; if ( i >= lr->lr_lines ) goto short_input; if ( !BV_CASEMATCH( lr->lr_btype+i, &BV_DELETEOLDRDN )) { fprintf( stderr, _("%s: expecting \"%s:\" but saw" " \"%s:\" (line %lu, entry \"%s\")\n"), errstr, BV_DELETEOLDRDN.bv_val, lr->lr_btype[i].bv_val, linenum+i, dn ); rc = LDAP_PARAM_ERROR; goto leave; } lr->lrop_delold = ( lr->lr_vals[i].bv_val[0] == '0' ) ? 0 : 1; i++; if ( i < lr->lr_lines ) { if ( !BV_CASEMATCH( lr->lr_btype+i, &BV_NEWSUP )) { fprintf( stderr, _("%s: expecting \"%s:\" but saw" " \"%s:\" (line %lu, entry \"%s\")\n"), errstr, BV_NEWSUP.bv_val, lr->lr_btype[i].bv_val, linenum+i, dn ); rc = LDAP_PARAM_ERROR; goto leave; } lr->lrop_newsup = lr->lr_vals[i]; i++; } got_all = 1; } else if ( BV_CASEMATCH( lr->lr_vals+i, &BV_DELETECT )) { got_all = delete_entry = 1; } else { fprintf( stderr, _("%s: unknown %s \"%s\" (line %lu, entry \"%s\")\n"), errstr, BV_CHANGETYPE.bv_val, lr->lr_vals[i].bv_val, linenum+i, dn ); rc = LDAP_PARAM_ERROR; goto leave; } i++; } else if ( ldapadd ) { /* missing changetype => add */ new_entry = 1; modop = LDAP_MOD_ADD; } else { /* if LDIF_ENTRIES_ONLY, then either the changetype must be add, or there must be no changetype, and the flag LDIF_DEFAULT_ADD must be set */ if ( flags & LDIF_ENTRIES_ONLY ) { ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug, _("%s: skipping LDIF record beginning at line %lu: " "no changetype found but entries only was requested and " "the default setting for missing changetype is modify\n"), errstr, linenum ); goto leave; } expect_modop = 1; /* missing changetype => modify */ } if ( got_all ) { if ( i < lr->lr_lines ) { fprintf( stderr, _("%s: extra lines at end (line %lu, entry \"%s\")\n"), errstr, linenum+i, dn ); rc = LDAP_PARAM_ERROR; goto leave; } goto doit; } nmods = lr->lr_lines - i; idn = i; if ( new_entry ) { int fv; /* Make sure all attributes with multiple values are contiguous */ for (; ilr_lines; i++) { for (j=i+1; jlr_lines; j++) { if ( !lr->lr_btype[j].bv_val ) { fprintf( stderr, _("%s: missing attributeDescription (line %lu, entry \"%s\")\n"), errstr, linenum+j, dn ); rc = LDAP_PARAM_ERROR; goto leave; } if ( BV_CASEMATCH( lr->lr_btype+i, lr->lr_btype+j )) { nmods--; /* out of order, move intervening attributes down */ if ( j != i+1 ) { bv = lr->lr_vals[j]; fv = lr->lr_freeval[j]; for (k=j; k>i; k--) { lr->lr_btype[k] = lr->lr_btype[k-1]; lr->lr_vals[k] = lr->lr_vals[k-1]; lr->lr_freeval[k] = lr->lr_freeval[k-1]; } k++; lr->lr_btype[k] = lr->lr_btype[i]; lr->lr_vals[k] = bv; lr->lr_freeval[k] = fv; } i++; } } } /* Allocate space for array of mods, array of pointers to mods, * and array of pointers to values, allowing for NULL terminators * for the pointer arrays... */ lr->lr_lm = ber_memalloc_x( nmods * sizeof(LDAPMod) + (nmods+1) * sizeof(LDAPMod*) + (lr->lr_lines + nmods - idn) * sizeof(struct berval *), ctx ); if ( lr->lr_lm == NULL ) { rc = LDAP_NO_MEMORY; goto leave; } pmods = (LDAPMod **)(lr->lr_lm+nmods); bvl = (struct berval **)(pmods+nmods+1); j = 0; k = -1; BER_BVZERO(&bv); for (i=idn; ilr_lines; i++) { if ( BV_CASEMATCH( lr->lr_btype+i, &BV_DN )) { fprintf( stderr, _("%s: attributeDescription \"%s\":" " (possible missing newline" " after line %lu, entry \"%s\"?)\n"), errstr, lr->lr_btype[i].bv_val, linenum+i - 1, dn ); } if ( !BV_CASEMATCH( lr->lr_btype+i, &bv )) { bvl[k++] = NULL; bv = lr->lr_btype[i]; lr->lr_lm[j].mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES; lr->lr_lm[j].mod_type = bv.bv_val; lr->lr_lm[j].mod_bvalues = bvl+k; pmods[j] = lr->lr_lm+j; j++; } bvl[k++] = lr->lr_vals+i; } bvl[k] = NULL; pmods[j] = NULL; goto doit; } lr->lr_mops = ber_memalloc_x( lr->lr_lines+1, ctx ); if ( lr->lr_mops == NULL ) { rc = LDAP_NO_MEMORY; goto leave; } lr->lr_mops[lr->lr_lines] = M_SEP; if ( i > 0 ) lr->lr_mops[i-1] = M_SEP; for ( ; ilr_lines; i++ ) { if ( expect_modop ) { #ifdef LIBERAL_CHANGETYPE_MODOP /* trim trailing spaces (and log warning ...) */ int icnt; for ( icnt = lr->lr_vals[i].bv_len; --icnt > 0; ) { if ( !isspace( (unsigned char) lr->lr_vals[i].bv_val[icnt] ) ) break; } if ( ++icnt != lr->lr_vals[i].bv_len ) { fprintf( stderr, _("%s: illegal trailing space after" " \"%s: %s\" trimmed (line %lu, entry \"%s\")\n"), errstr, type, lr->lr_vals[i].bv_val, linenum+i, dn ); lr->lr_vals[i].bv_val[icnt] = '\0'; } #endif /* LIBERAL_CHANGETYPE_MODOP */ expect_modop = 0; expect_sep = 1; if ( BV_CASEMATCH( lr->lr_btype+i, &BV_MODOPADD )) { modop = LDAP_MOD_ADD; lr->lr_mops[i] = M_SEP; nmods--; } else if ( BV_CASEMATCH( lr->lr_btype+i, &BV_MODOPREPLACE )) { /* defer handling these since they might have no values. * Use the BVALUES flag to signal that these were * deferred. If values are provided later, this * flag will be switched off. */ modop = LDAP_MOD_REPLACE; lr->lr_mops[i] = modop | LDAP_MOD_BVALUES; lr->lr_btype[i] = lr->lr_vals[i]; } else if ( BV_CASEMATCH( lr->lr_btype+i, &BV_MODOPDELETE )) { modop = LDAP_MOD_DELETE; lr->lr_mops[i] = modop | LDAP_MOD_BVALUES; lr->lr_btype[i] = lr->lr_vals[i]; } else if ( BV_CASEMATCH( lr->lr_btype+i, &BV_MODOPINCREMENT )) { modop = LDAP_MOD_INCREMENT; lr->lr_mops[i] = M_SEP; nmods--; } else { /* no modify op: invalid LDIF */ fprintf( stderr, _("%s: modify operation type is missing at" " line %lu, entry \"%s\"\n"), errstr, linenum+i, dn ); rc = LDAP_PARAM_ERROR; goto leave; } bv = lr->lr_vals[i]; } else if ( expect_sep && BER_BVISEMPTY( lr->lr_btype+i )) { lr->lr_mops[i] = M_SEP; expect_sep = 0; expect_modop = 1; nmods--; } else { if ( !BV_CASEMATCH( lr->lr_btype+i, &bv )) { fprintf( stderr, _("%s: wrong attributeType at" " line %lu, entry \"%s\"\n"), errstr, linenum+i, dn ); rc = LDAP_PARAM_ERROR; goto leave; } lr->lr_mops[i] = modop; /* If prev op was deferred and matches this type, * clear the flag */ if ( (lr->lr_mops[i-1] & LDAP_MOD_BVALUES) && BV_CASEMATCH( lr->lr_btype+i, lr->lr_btype+i-1 )) { lr->lr_mops[i-1] = M_SEP; nmods--; } } } /* Allocate space for array of mods, array of pointers to mods, * and array of pointers to values, allowing for NULL terminators * for the pointer arrays... */ lr->lr_lm = ber_memalloc_x( nmods * sizeof(LDAPMod) + (nmods+1) * sizeof(LDAPMod*) + (lr->lr_lines + nmods - idn) * sizeof(struct berval *), ctx ); if ( lr->lr_lm == NULL ) { rc = LDAP_NO_MEMORY; goto leave; } pmods = (LDAPMod **)(lr->lr_lm+nmods); bvl = (struct berval **)(pmods+nmods+1); j = 0; k = -1; BER_BVZERO(&bv); if ( idn > 0 ) lr->lr_mops[idn-1] = M_SEP; for (i=idn; ilr_lines; i++) { if ( lr->lr_mops[i] == M_SEP ) continue; if ( lr->lr_mops[i] != lr->lr_mops[i-1] || !BV_CASEMATCH( lr->lr_btype+i, &bv )) { bvl[k++] = NULL; bv = lr->lr_btype[i]; lr->lr_lm[j].mod_op = lr->lr_mops[i] | LDAP_MOD_BVALUES; lr->lr_lm[j].mod_type = bv.bv_val; if ( lr->lr_mops[i] & LDAP_MOD_BVALUES ) { lr->lr_lm[j].mod_bvalues = NULL; } else { lr->lr_lm[j].mod_bvalues = bvl+k; } pmods[j] = lr->lr_lm+j; j++; } bvl[k++] = lr->lr_vals+i; } bvl[k] = NULL; pmods[j] = NULL; doit: /* first, set the common fields */ lr->lr_ctrls = pctrls; /* next, set the op */ if ( delete_entry ) { lr->lr_op = LDAP_REQ_DELETE; } else if ( lr->lrop_newrdn.bv_val != NULL ) { lr->lr_op = LDAP_REQ_MODDN; } else { /* for now, either add or modify */ lr->lrop_mods = pmods; if ( new_entry ) { lr->lr_op = LDAP_REQ_ADD; } else { lr->lr_op = LDAP_REQ_MODIFY; } } leave: if ( rc != LDAP_SUCCESS ) { ldap_ldif_record_done( lr ); } return( rc ); } /* Same as ldap_parse_ldif_record_x() * public API does not expose memory context */ int ldap_parse_ldif_record( struct berval *rbuf, unsigned long linenum, LDIFRecord *lr, const char *errstr, unsigned int flags ) { return ldap_parse_ldif_record_x( rbuf, linenum, lr, errstr, flags, NULL ); } /* Parse an LDIF control line of the form control: oid [true/false] [: value] or control: oid [true/false] [:: base64-value] or control: oid [true/false] [:< url] The control is added to the list of controls in *ppctrls. */ static int parse_ldif_control( struct berval *bval, LDAPControl ***ppctrls) { char *oid = NULL; int criticality = 0; /* Default is false if not present */ int i, rc=0; char *s, *oidStart; LDAPControl *newctrl = NULL; LDAPControl **pctrls = NULL; struct berval type, bv = BER_BVNULL; int freeval = 0; if (ppctrls) pctrls = *ppctrls; /* OID should come first. Validate and extract it. */ s = bval->bv_val; if (*s == 0) return ( LDAP_PARAM_ERROR ); oidStart = s; while (isdigit((unsigned char)*s) || *s == '.') { s++; /* OID should be digits or . */ } if (s == oidStart) { return ( LDAP_PARAM_ERROR ); /* OID was not present */ } if (*s) { /* End of OID should be space or NULL */ if (!isspace((unsigned char)*s)) { return ( LDAP_PARAM_ERROR ); /* else OID contained invalid chars */ } *s++ = 0; /* Replace space with null to terminate */ } oid = ber_strdup(oidStart); if (oid == NULL) return ( LDAP_NO_MEMORY ); /* Optional Criticality field is next. */ while (*s && isspace((unsigned char)*s)) { s++; /* Skip white space before criticality */ } if (strncasecmp(s, "true", 4) == 0) { criticality = 1; s += 4; } else if (strncasecmp(s, "false", 5) == 0) { criticality = 0; s += 5; } /* Optional value field is next */ while (*s && isspace((unsigned char)*s)) { s++; /* Skip white space before value */ } if (*s) { if (*s != ':') { /* If value is present, must start with : */ rc = LDAP_PARAM_ERROR; goto cleanup; } /* Back up so value is in the form a: value a:: base64-value a:< url Then we can use ldif_parse_line2 to extract and decode the value */ s--; *s = 'a'; rc = ldif_parse_line2(s, &type, &bv, &freeval); if (rc < 0) { rc = LDAP_PARAM_ERROR; goto cleanup; } } /* Create a new LDAPControl structure. */ newctrl = (LDAPControl *)ber_memalloc(sizeof(LDAPControl)); if ( newctrl == NULL ) { rc = LDAP_NO_MEMORY; goto cleanup; } newctrl->ldctl_oid = oid; oid = NULL; newctrl->ldctl_iscritical = criticality; if ( freeval ) newctrl->ldctl_value = bv; else ber_dupbv( &newctrl->ldctl_value, &bv ); /* Add the new control to the passed-in list of controls. */ i = 0; if (pctrls) { while ( pctrls[i] ) { /* Count the # of controls passed in */ i++; } } /* Allocate 1 more slot for the new control and 1 for the NULL. */ pctrls = (LDAPControl **) ber_memrealloc(pctrls, (i+2)*(sizeof(LDAPControl *))); if (pctrls == NULL) { rc = LDAP_NO_MEMORY; goto cleanup; } pctrls[i] = newctrl; newctrl = NULL; pctrls[i+1] = NULL; *ppctrls = pctrls; cleanup: if (newctrl) { if (newctrl->ldctl_oid) ber_memfree(newctrl->ldctl_oid); if (newctrl->ldctl_value.bv_val) { ber_memfree(newctrl->ldctl_value.bv_val); } ber_memfree(newctrl); } if (oid) ber_memfree(oid); return( rc ); } openldap-2.5.11+dfsg/libraries/libldap/sortctrl.c0000644000175000017500000003535714172327167020457 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved. * * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. */ /* Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License * can be found in the file "build/LICENSE-2.0.1" in this distribution * of OpenLDAP Software. */ #include "portable.h" #include #include #include #include #include "ldap-int.h" #define LDAP_MATCHRULE_IDENTIFIER 0x80L #define LDAP_REVERSEORDER_IDENTIFIER 0x81L #define LDAP_ATTRTYPES_IDENTIFIER 0x80L /* --------------------------------------------------------------------------- countKeys Internal function to determine the number of keys in the string. keyString (IN) String of items separated by whitespace. ---------------------------------------------------------------------------*/ static int countKeys(char *keyString) { char *p = keyString; int count = 0; for (;;) { while (LDAP_SPACE(*p)) /* Skip leading whitespace */ p++; if (*p == '\0') /* End of string? */ return count; count++; /* Found start of a key */ while (!LDAP_SPACE(*p)) /* Skip till next space or end of string. */ if (*p++ == '\0') return count; } } /* --------------------------------------------------------------------------- readNextKey Internal function to parse the next sort key in the string. Allocate an LDAPSortKey structure and initialize it with attribute name, reverse flag, and matching rule OID. Each sort key in the string has the format: [whitespace][-]attribute[:[OID]] pNextKey (IN/OUT) Points to the next key in the sortkey string to parse. The pointer is updated to point to the next character after the sortkey being parsed. key (OUT) Points to the address of an LDAPSortKey structure which has been allocated by this routine and initialized with information from the next sortkey. ---------------------------------------------------------------------------*/ static int readNextKey( char **pNextKey, LDAPSortKey **key) { char *p = *pNextKey; int rev = 0; char *attrStart; int attrLen; char *oidStart = NULL; int oidLen = 0; /* Skip leading white space. */ while (LDAP_SPACE(*p)) p++; if (*p == '-') /* Check if the reverse flag is present. */ { rev=1; p++; } /* We're now positioned at the start of the attribute. */ attrStart = p; /* Get the length of the attribute until the next whitespace or ":". */ attrLen = strcspn(p, " \t:"); p += attrLen; if (attrLen == 0) /* If no attribute name was present, quit. */ return LDAP_PARAM_ERROR; if (*p == ':') { oidStart = ++p; /* Start of the OID, after the colon */ oidLen = strcspn(p, " \t"); /* Get length of OID till next whitespace */ p += oidLen; } *pNextKey = p; /* Update argument to point to next key */ /* Allocate an LDAPSortKey structure */ *key = LDAP_MALLOC(sizeof(LDAPSortKey)); if (*key == NULL) return LDAP_NO_MEMORY; /* Allocate memory for the attribute and copy to it. */ (*key)->attributeType = LDAP_MALLOC(attrLen+1); if ((*key)->attributeType == NULL) { LDAP_FREE(*key); return LDAP_NO_MEMORY; } strncpy((*key)->attributeType, attrStart, attrLen); (*key)->attributeType[attrLen] = 0; /* If present, allocate memory for the OID and copy to it. */ if (oidLen) { (*key)->orderingRule = LDAP_MALLOC(oidLen+1); if ((*key)->orderingRule == NULL) { LDAP_FREE((*key)->attributeType); LDAP_FREE(*key); return LDAP_NO_MEMORY; } strncpy((*key)->orderingRule, oidStart, oidLen); (*key)->orderingRule[oidLen] = 0; } else { (*key)->orderingRule = NULL; } (*key)->reverseOrder = rev; return LDAP_SUCCESS; } /* --------------------------------------------------------------------------- ldap_create_sort_keylist Create an array of pointers to LDAPSortKey structures, containing the information specified by the string representation of one or more sort keys. sortKeyList (OUT) Points to a null-terminated array of pointers to LDAPSortKey structures allocated by this routine. This memory SHOULD be freed by the calling program using ldap_free_sort_keylist(). keyString (IN) Points to a string of one or more sort keys. ---------------------------------------------------------------------------*/ int ldap_create_sort_keylist ( LDAPSortKey ***sortKeyList, char *keyString ) { int numKeys, rc, i; char *nextKey; LDAPSortKey **keyList = NULL; assert( sortKeyList != NULL ); assert( keyString != NULL ); *sortKeyList = NULL; /* Determine the number of sort keys so we can allocate memory. */ if (( numKeys = countKeys(keyString)) == 0) { return LDAP_PARAM_ERROR; } /* Allocate the array of pointers. Initialize to NULL. */ keyList=(LDAPSortKey**)LBER_CALLOC(numKeys+1, sizeof(LDAPSortKey*)); if ( keyList == NULL) return LDAP_NO_MEMORY; /* For each sort key in the string, create an LDAPSortKey structure and add it to the list. */ nextKey = keyString; /* Points to the next key in the string */ for (i=0; i < numKeys; i++) { rc = readNextKey(&nextKey, &keyList[i]); if (rc != LDAP_SUCCESS) { ldap_free_sort_keylist(keyList); return rc; } } *sortKeyList = keyList; return LDAP_SUCCESS; } /* --------------------------------------------------------------------------- ldap_free_sort_keylist Frees the sort key structures created by ldap_create_sort_keylist(). Frees the memory referenced by the LDAPSortKey structures, the LDAPSortKey structures themselves, and the array of pointers to the structures. keyList (IN) Points to an array of pointers to LDAPSortKey structures. ---------------------------------------------------------------------------*/ void ldap_free_sort_keylist ( LDAPSortKey **keyList ) { int i; LDAPSortKey *nextKeyp; if (keyList == NULL) return; i=0; while ( 0 != (nextKeyp = keyList[i++]) ) { if (nextKeyp->attributeType) { LBER_FREE(nextKeyp->attributeType); } if (nextKeyp->orderingRule != NULL) { LBER_FREE(nextKeyp->orderingRule); } LBER_FREE(nextKeyp); } LBER_FREE(keyList); } /* --------------------------------------------------------------------------- ldap_create_sort_control_value Create and encode the value of the server-side sort control. ld (IN) An LDAP session handle, as obtained from a call to ldap_init(). keyList (IN) Points to a null-terminated array of pointers to LDAPSortKey structures, containing a description of each of the sort keys to be used. The description consists of an attribute name, ascending/descending flag, and an optional matching rule (OID) to use. value (OUT) Contains the control value; the bv_val member of the berval structure SHOULD be freed by calling ldap_memfree() when done. Ber encoding SortKeyList ::= SEQUENCE OF SEQUENCE { attributeType AttributeDescription, orderingRule [0] MatchingRuleId OPTIONAL, reverseOrder [1] BOOLEAN DEFAULT FALSE } ---------------------------------------------------------------------------*/ int ldap_create_sort_control_value( LDAP *ld, LDAPSortKey **keyList, struct berval *value ) { int i; BerElement *ber = NULL; ber_tag_t tag; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); if ( ld == NULL ) return LDAP_PARAM_ERROR; if ( keyList == NULL || value == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; return LDAP_PARAM_ERROR; } value->bv_val = NULL; value->bv_len = 0; ld->ld_errno = LDAP_SUCCESS; ber = ldap_alloc_ber_with_options( ld ); if ( ber == NULL) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } tag = ber_printf( ber, "{" /*}*/ ); if ( tag == LBER_ERROR ) { goto error_return; } for ( i = 0; keyList[i] != NULL; i++ ) { tag = ber_printf( ber, "{s" /*}*/, keyList[i]->attributeType ); if ( tag == LBER_ERROR ) { goto error_return; } if ( keyList[i]->orderingRule != NULL ) { tag = ber_printf( ber, "ts", LDAP_MATCHRULE_IDENTIFIER, keyList[i]->orderingRule ); if ( tag == LBER_ERROR ) { goto error_return; } } if ( keyList[i]->reverseOrder ) { tag = ber_printf( ber, "tb", LDAP_REVERSEORDER_IDENTIFIER, keyList[i]->reverseOrder ); if ( tag == LBER_ERROR ) { goto error_return; } } tag = ber_printf( ber, /*{*/ "N}" ); if ( tag == LBER_ERROR ) { goto error_return; } } tag = ber_printf( ber, /*{*/ "N}" ); if ( tag == LBER_ERROR ) { goto error_return; } if ( ber_flatten2( ber, value, 1 ) == -1 ) { ld->ld_errno = LDAP_NO_MEMORY; } if ( 0 ) { error_return:; ld->ld_errno = LDAP_ENCODING_ERROR; } if ( ber != NULL ) { ber_free( ber, 1 ); } return ld->ld_errno; } /* --------------------------------------------------------------------------- ldap_create_sort_control Create and encode the server-side sort control. ld (IN) An LDAP session handle, as obtained from a call to ldap_init(). keyList (IN) Points to a null-terminated array of pointers to LDAPSortKey structures, containing a description of each of the sort keys to be used. The description consists of an attribute name, ascending/descending flag, and an optional matching rule (OID) to use. isCritical (IN) 0 - Indicates the control is not critical to the operation. non-zero - The control is critical to the operation. ctrlp (OUT) Returns a pointer to the LDAPControl created. This control SHOULD be freed by calling ldap_control_free() when done. Ber encoding SortKeyList ::= SEQUENCE OF SEQUENCE { attributeType AttributeDescription, orderingRule [0] MatchingRuleId OPTIONAL, reverseOrder [1] BOOLEAN DEFAULT FALSE } ---------------------------------------------------------------------------*/ int ldap_create_sort_control( LDAP *ld, LDAPSortKey **keyList, int isCritical, LDAPControl **ctrlp ) { struct berval value; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); if ( ld == NULL ) { return LDAP_PARAM_ERROR; } if ( ctrlp == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; } ld->ld_errno = ldap_create_sort_control_value( ld, keyList, &value ); if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = ldap_control_create( LDAP_CONTROL_SORTREQUEST, isCritical, &value, 0, ctrlp ); if ( ld->ld_errno != LDAP_SUCCESS ) { LDAP_FREE( value.bv_val ); } } return ld->ld_errno; } /* --------------------------------------------------------------------------- ldap_parse_sortedresult_control Decode the server-side sort control return information. ld (IN) An LDAP session handle, as obtained from a call to ldap_init(). ctrl (IN) The address of the LDAP Control Structure. returnCode (OUT) This result parameter is filled in with the sort control result code. This parameter MUST not be NULL. attribute (OUT) If an error occurred the server may return a string indicating the first attribute in the sortkey list that was in error. If a string is returned, the memory should be freed with ldap_memfree. If this parameter is NULL, no string is returned. Ber encoding for sort control SortResult ::= SEQUENCE { sortResult ENUMERATED { success (0), -- results are sorted operationsError (1), -- server internal failure timeLimitExceeded (3), -- timelimit reached before -- sorting was completed strongAuthRequired (8), -- refused to return sorted -- results via insecure -- protocol adminLimitExceeded (11), -- too many matching entries -- for the server to sort noSuchAttribute (16), -- unrecognized attribute -- type in sort key inappropriateMatching (18), -- unrecognized or inappro- -- priate matching rule in -- sort key insufficientAccessRights (50), -- refused to return sorted -- results to this client busy (51), -- too busy to process unwillingToPerform (53), -- unable to sort other (80) }, attributeType [0] AttributeDescription OPTIONAL } ---------------------------------------------------------------------------*/ int ldap_parse_sortresponse_control( LDAP *ld, LDAPControl *ctrl, ber_int_t *returnCode, char **attribute ) { BerElement *ber; ber_tag_t tag, berTag; ber_len_t berLen; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); if (ld == NULL) { return LDAP_PARAM_ERROR; } if (ctrl == NULL) { ld->ld_errno = LDAP_PARAM_ERROR; return(ld->ld_errno); } if (attribute) { *attribute = NULL; } if ( strcmp(LDAP_CONTROL_SORTRESPONSE, ctrl->ldctl_oid) != 0 ) { /* Not sort result control */ ld->ld_errno = LDAP_CONTROL_NOT_FOUND; return(ld->ld_errno); } /* Create a BerElement from the berval returned in the control. */ ber = ber_init(&ctrl->ldctl_value); if (ber == NULL) { ld->ld_errno = LDAP_NO_MEMORY; return(ld->ld_errno); } /* Extract the result code from the control. */ tag = ber_scanf(ber, "{e" /*}*/, returnCode); if( tag == LBER_ERROR ) { ber_free(ber, 1); ld->ld_errno = LDAP_DECODING_ERROR; return(ld->ld_errno); } /* If caller wants the attribute name, and if it's present in the control, extract the attribute name which caused the error. */ if (attribute && (LDAP_ATTRTYPES_IDENTIFIER == ber_peek_tag(ber, &berLen))) { tag = ber_scanf(ber, "ta", &berTag, attribute); if (tag == LBER_ERROR ) { ber_free(ber, 1); ld->ld_errno = LDAP_DECODING_ERROR; return(ld->ld_errno); } } ber_free(ber,1); ld->ld_errno = LDAP_SUCCESS; return(ld->ld_errno); } openldap-2.5.11+dfsg/libraries/libldap/init.c0000644000175000017500000004473614172327167017547 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #ifdef HAVE_GETEUID #include #endif #include #include #include #include #ifdef HAVE_LIMITS_H #include #endif #include "ldap-int.h" #include "ldap_defaults.h" #include "lutil.h" struct ldapoptions ldap_int_global_options = { LDAP_UNINITIALIZED, LDAP_DEBUG_NONE LDAP_LDO_NULLARG LDAP_LDO_SOURCEIP_NULLARG LDAP_LDO_CONNECTIONLESS_NULLARG LDAP_LDO_TLS_NULLARG LDAP_LDO_SASL_NULLARG LDAP_LDO_MUTEX_NULLARG }; #define ATTR_NONE 0 #define ATTR_BOOL 1 #define ATTR_INT 2 #define ATTR_KV 3 #define ATTR_STRING 4 #define ATTR_OPTION 5 #define ATTR_SASL 6 #define ATTR_TLS 7 #define ATTR_OPT_TV 8 #define ATTR_OPT_INT 9 struct ol_keyvalue { const char * key; int value; }; static const struct ol_keyvalue deref_kv[] = { {"never", LDAP_DEREF_NEVER}, {"searching", LDAP_DEREF_SEARCHING}, {"finding", LDAP_DEREF_FINDING}, {"always", LDAP_DEREF_ALWAYS}, {NULL, 0} }; static const struct ol_attribute { int useronly; int type; const char * name; const void * data; size_t offset; } attrs[] = { {0, ATTR_OPT_TV, "TIMEOUT", NULL, LDAP_OPT_TIMEOUT}, {0, ATTR_OPT_TV, "NETWORK_TIMEOUT", NULL, LDAP_OPT_NETWORK_TIMEOUT}, {0, ATTR_OPT_INT, "VERSION", NULL, LDAP_OPT_PROTOCOL_VERSION}, {0, ATTR_KV, "DEREF", deref_kv, /* or &deref_kv[0] */ offsetof(struct ldapoptions, ldo_deref)}, {0, ATTR_INT, "SIZELIMIT", NULL, offsetof(struct ldapoptions, ldo_sizelimit)}, {0, ATTR_INT, "TIMELIMIT", NULL, offsetof(struct ldapoptions, ldo_timelimit)}, {1, ATTR_STRING, "BINDDN", NULL, offsetof(struct ldapoptions, ldo_defbinddn)}, {0, ATTR_STRING, "BASE", NULL, offsetof(struct ldapoptions, ldo_defbase)}, {0, ATTR_INT, "PORT", NULL, /* deprecated */ offsetof(struct ldapoptions, ldo_defport)}, {0, ATTR_OPTION, "HOST", NULL, LDAP_OPT_HOST_NAME}, /* deprecated */ {0, ATTR_OPTION, "URI", NULL, LDAP_OPT_URI}, /* replaces HOST/PORT */ {0, ATTR_OPTION, "SOCKET_BIND_ADDRESSES", NULL, LDAP_OPT_SOCKET_BIND_ADDRESSES}, {0, ATTR_BOOL, "REFERRALS", NULL, LDAP_BOOL_REFERRALS}, {0, ATTR_INT, "KEEPALIVE_IDLE", NULL, LDAP_OPT_X_KEEPALIVE_IDLE}, {0, ATTR_INT, "KEEPALIVE_PROBES", NULL, LDAP_OPT_X_KEEPALIVE_PROBES}, {0, ATTR_INT, "KEEPALIVE_INTERVAL", NULL, LDAP_OPT_X_KEEPALIVE_INTERVAL}, #if 0 /* This should only be allowed via ldap_set_option(3) */ {0, ATTR_BOOL, "RESTART", NULL, LDAP_BOOL_RESTART}, #endif #ifdef HAVE_CYRUS_SASL {0, ATTR_STRING, "SASL_MECH", NULL, offsetof(struct ldapoptions, ldo_def_sasl_mech)}, {0, ATTR_STRING, "SASL_REALM", NULL, offsetof(struct ldapoptions, ldo_def_sasl_realm)}, {1, ATTR_STRING, "SASL_AUTHCID", NULL, offsetof(struct ldapoptions, ldo_def_sasl_authcid)}, {1, ATTR_STRING, "SASL_AUTHZID", NULL, offsetof(struct ldapoptions, ldo_def_sasl_authzid)}, {0, ATTR_SASL, "SASL_SECPROPS", NULL, LDAP_OPT_X_SASL_SECPROPS}, {0, ATTR_BOOL, "SASL_NOCANON", NULL, LDAP_BOOL_SASL_NOCANON}, {0, ATTR_SASL, "SASL_CBINDING", NULL, LDAP_OPT_X_SASL_CBINDING}, #endif #ifdef HAVE_TLS {1, ATTR_TLS, "TLS_CERT", NULL, LDAP_OPT_X_TLS_CERTFILE}, {1, ATTR_TLS, "TLS_KEY", NULL, LDAP_OPT_X_TLS_KEYFILE}, {0, ATTR_TLS, "TLS_CACERT", NULL, LDAP_OPT_X_TLS_CACERTFILE}, {0, ATTR_TLS, "TLS_CACERTDIR", NULL, LDAP_OPT_X_TLS_CACERTDIR}, {0, ATTR_TLS, "TLS_REQCERT", NULL, LDAP_OPT_X_TLS_REQUIRE_CERT}, {0, ATTR_TLS, "TLS_REQSAN", NULL, LDAP_OPT_X_TLS_REQUIRE_SAN}, {0, ATTR_TLS, "TLS_RANDFILE", NULL, LDAP_OPT_X_TLS_RANDOM_FILE}, {0, ATTR_TLS, "TLS_CIPHER_SUITE", NULL, LDAP_OPT_X_TLS_CIPHER_SUITE}, {0, ATTR_TLS, "TLS_PROTOCOL_MIN", NULL, LDAP_OPT_X_TLS_PROTOCOL_MIN}, {0, ATTR_TLS, "TLS_PROTOCOL_MAX", NULL, LDAP_OPT_X_TLS_PROTOCOL_MAX}, {0, ATTR_TLS, "TLS_PEERKEY_HASH", NULL, LDAP_OPT_X_TLS_PEERKEY_HASH}, {0, ATTR_TLS, "TLS_ECNAME", NULL, LDAP_OPT_X_TLS_ECNAME}, #ifdef HAVE_OPENSSL {0, ATTR_TLS, "TLS_CRLCHECK", NULL, LDAP_OPT_X_TLS_CRLCHECK}, #endif #ifdef HAVE_GNUTLS {0, ATTR_TLS, "TLS_CRLFILE", NULL, LDAP_OPT_X_TLS_CRLFILE}, #endif #endif {0, ATTR_NONE, NULL, NULL, 0} }; #define MAX_LDAP_ATTR_LEN sizeof("SOCKET_BIND_ADDRESSES") #define MAX_LDAP_ENV_PREFIX_LEN 8 static int ldap_int_conf_option( struct ldapoptions *gopts, char *cmd, char *opt, int userconf ) { int i; for(i=0; attrs[i].type != ATTR_NONE; i++) { void *p; if( !userconf && attrs[i].useronly ) { continue; } if(strcasecmp(cmd, attrs[i].name) != 0) { continue; } switch(attrs[i].type) { case ATTR_BOOL: if((strcasecmp(opt, "on") == 0) || (strcasecmp(opt, "yes") == 0) || (strcasecmp(opt, "true") == 0)) { LDAP_BOOL_SET(gopts, attrs[i].offset); } else { LDAP_BOOL_CLR(gopts, attrs[i].offset); } break; case ATTR_INT: { char *next; long l; p = &((char *) gopts)[attrs[i].offset]; l = strtol( opt, &next, 10 ); if ( next != opt && next[ 0 ] == '\0' ) { * (int*) p = l; } } break; case ATTR_KV: { const struct ol_keyvalue *kv; for(kv = attrs[i].data; kv->key != NULL; kv++) { if(strcasecmp(opt, kv->key) == 0) { p = &((char *) gopts)[attrs[i].offset]; * (int*) p = kv->value; break; } } } break; case ATTR_STRING: p = &((char *) gopts)[attrs[i].offset]; if (* (char**) p != NULL) LDAP_FREE(* (char**) p); * (char**) p = LDAP_STRDUP(opt); break; case ATTR_OPTION: ldap_set_option( NULL, attrs[i].offset, opt ); break; case ATTR_SASL: #ifdef HAVE_CYRUS_SASL ldap_int_sasl_config( gopts, attrs[i].offset, opt ); #endif break; case ATTR_TLS: #ifdef HAVE_TLS ldap_pvt_tls_config( NULL, attrs[i].offset, opt ); #endif break; case ATTR_OPT_TV: { struct timeval tv; char *next; tv.tv_usec = 0; tv.tv_sec = strtol( opt, &next, 10 ); if ( next != opt && next[ 0 ] == '\0' && tv.tv_sec > 0 ) { (void)ldap_set_option( NULL, attrs[i].offset, (const void *)&tv ); } } break; case ATTR_OPT_INT: { long l; char *next; l = strtol( opt, &next, 10 ); if ( next != opt && next[ 0 ] == '\0' && l > 0 && (long)((int)l) == l ) { int v = (int)l; (void)ldap_set_option( NULL, attrs[i].offset, (const void *)&v ); } } break; } break; } if ( attrs[i].type == ATTR_NONE ) { Debug1( LDAP_DEBUG_TRACE, "ldap_pvt_tls_config: " "unknown option '%s'", cmd ); return 1; } return 0; } int ldap_pvt_conf_option( char *cmd, char *opt, int userconf ) { struct ldapoptions *gopts; int rc = LDAP_OPT_ERROR; /* Get pointer to global option structure */ gopts = LDAP_INT_GLOBAL_OPT(); if (NULL == gopts) { return LDAP_NO_MEMORY; } if ( gopts->ldo_valid != LDAP_INITIALIZED ) { ldap_int_initialize(gopts, NULL); if ( gopts->ldo_valid != LDAP_INITIALIZED ) return LDAP_LOCAL_ERROR; } return ldap_int_conf_option( gopts, cmd, opt, userconf ); } static void openldap_ldap_init_w_conf( const char *file, int userconf ) { char linebuf[ AC_LINE_MAX ]; FILE *fp; int i; char *cmd, *opt; char *start, *end; struct ldapoptions *gopts; if ((gopts = LDAP_INT_GLOBAL_OPT()) == NULL) { return; /* Could not allocate mem for global options */ } if (file == NULL) { /* no file name */ return; } Debug1(LDAP_DEBUG_TRACE, "ldap_init: trying %s\n", file ); fp = fopen(file, "r"); if(fp == NULL) { /* could not open file */ return; } Debug1(LDAP_DEBUG_TRACE, "ldap_init: using %s\n", file ); while((start = fgets(linebuf, sizeof(linebuf), fp)) != NULL) { /* skip lines starting with '#' */ if(*start == '#') continue; /* trim leading white space */ while((*start != '\0') && isspace((unsigned char) *start)) start++; /* anything left? */ if(*start == '\0') continue; /* trim trailing white space */ end = &start[strlen(start)-1]; while(isspace((unsigned char)*end)) end--; end[1] = '\0'; /* anything left? */ if(*start == '\0') continue; /* parse the command */ cmd=start; while((*start != '\0') && !isspace((unsigned char)*start)) { start++; } if(*start == '\0') { /* command has no argument */ continue; } *start++ = '\0'; /* we must have some whitespace to skip */ while(isspace((unsigned char)*start)) start++; opt = start; ldap_int_conf_option( gopts, cmd, opt, userconf ); } fclose(fp); } static void openldap_ldap_init_w_sysconf(const char *file) { openldap_ldap_init_w_conf( file, 0 ); } static void openldap_ldap_init_w_userconf(const char *file) { char *home; char *path = NULL; if (file == NULL) { /* no file name */ return; } home = getenv("HOME"); if (home != NULL) { Debug1(LDAP_DEBUG_TRACE, "ldap_init: HOME env is %s\n", home ); path = LDAP_MALLOC(strlen(home) + strlen(file) + sizeof( LDAP_DIRSEP ".")); } else { Debug0(LDAP_DEBUG_TRACE, "ldap_init: HOME env is NULL\n" ); } if(home != NULL && path != NULL) { /* we assume UNIX path syntax is used... */ /* try ~/file */ sprintf(path, "%s" LDAP_DIRSEP "%s", home, file); openldap_ldap_init_w_conf(path, 1); /* try ~/.file */ sprintf(path, "%s" LDAP_DIRSEP ".%s", home, file); openldap_ldap_init_w_conf(path, 1); } if(path != NULL) { LDAP_FREE(path); } /* try file */ openldap_ldap_init_w_conf(file, 1); } static void openldap_ldap_init_w_env( struct ldapoptions *gopts, const char *prefix) { char buf[MAX_LDAP_ATTR_LEN+MAX_LDAP_ENV_PREFIX_LEN]; int len; int i; void *p; char *value; if (prefix == NULL) { prefix = LDAP_ENV_PREFIX; } strncpy(buf, prefix, MAX_LDAP_ENV_PREFIX_LEN); buf[MAX_LDAP_ENV_PREFIX_LEN] = '\0'; len = strlen(buf); for(i=0; attrs[i].type != ATTR_NONE; i++) { strcpy(&buf[len], attrs[i].name); value = getenv(buf); if(value == NULL) { continue; } switch(attrs[i].type) { case ATTR_BOOL: if((strcasecmp(value, "on") == 0) || (strcasecmp(value, "yes") == 0) || (strcasecmp(value, "true") == 0)) { LDAP_BOOL_SET(gopts, attrs[i].offset); } else { LDAP_BOOL_CLR(gopts, attrs[i].offset); } break; case ATTR_INT: p = &((char *) gopts)[attrs[i].offset]; * (int*) p = atoi(value); break; case ATTR_KV: { const struct ol_keyvalue *kv; for(kv = attrs[i].data; kv->key != NULL; kv++) { if(strcasecmp(value, kv->key) == 0) { p = &((char *) gopts)[attrs[i].offset]; * (int*) p = kv->value; break; } } } break; case ATTR_STRING: p = &((char *) gopts)[attrs[i].offset]; if (* (char**) p != NULL) LDAP_FREE(* (char**) p); if (*value == '\0') { * (char**) p = NULL; } else { * (char**) p = LDAP_STRDUP(value); } break; case ATTR_OPTION: ldap_set_option( NULL, attrs[i].offset, value ); break; case ATTR_SASL: #ifdef HAVE_CYRUS_SASL ldap_int_sasl_config( gopts, attrs[i].offset, value ); #endif break; case ATTR_TLS: #ifdef HAVE_TLS ldap_pvt_tls_config( NULL, attrs[i].offset, value ); #endif break; case ATTR_OPT_TV: { struct timeval tv; char *next; tv.tv_usec = 0; tv.tv_sec = strtol( value, &next, 10 ); if ( next != value && next[ 0 ] == '\0' && tv.tv_sec > 0 ) { (void)ldap_set_option( NULL, attrs[i].offset, (const void *)&tv ); } } break; case ATTR_OPT_INT: { long l; char *next; l = strtol( value, &next, 10 ); if ( next != value && next[ 0 ] == '\0' && l > 0 && (long)((int)l) == l ) { int v = (int)l; (void)ldap_set_option( NULL, attrs[i].offset, (const void *)&v ); } } break; } } } #if defined(__GNUC__) /* Declare this function as a destructor so that it will automatically be * invoked either at program exit (if libldap is a static library) or * at unload time (if libldap is a dynamic library). * * Sorry, don't know how to handle this for non-GCC environments. */ static void ldap_int_destroy_global_options(void) __attribute__ ((destructor)); #endif static void ldap_int_destroy_global_options(void) { struct ldapoptions *gopts = LDAP_INT_GLOBAL_OPT(); if ( gopts == NULL ) return; gopts->ldo_valid = LDAP_UNINITIALIZED; if ( gopts->ldo_defludp ) { ldap_free_urllist( gopts->ldo_defludp ); gopts->ldo_defludp = NULL; } if ( gopts->ldo_local_ip_addrs.local_ip_addrs ) { LDAP_FREE( gopts->ldo_local_ip_addrs.local_ip_addrs ); gopts->ldo_local_ip_addrs.local_ip_addrs = NULL; } #if defined(HAVE_WINSOCK) || defined(HAVE_WINSOCK2) WSACleanup( ); #endif #if defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL) if ( ldap_int_hostname ) { LDAP_FREE( ldap_int_hostname ); ldap_int_hostname = NULL; } #endif #ifdef HAVE_CYRUS_SASL if ( gopts->ldo_def_sasl_authcid ) { LDAP_FREE( gopts->ldo_def_sasl_authcid ); gopts->ldo_def_sasl_authcid = NULL; } #endif #ifdef HAVE_TLS ldap_int_tls_destroy( gopts ); #endif } /* * Initialize the global options structure with default values. */ void ldap_int_initialize_global_options( struct ldapoptions *gopts, int *dbglvl ) { if (dbglvl) gopts->ldo_debug = *dbglvl; else gopts->ldo_debug = 0; gopts->ldo_version = LDAP_VERSION2; gopts->ldo_deref = LDAP_DEREF_NEVER; gopts->ldo_timelimit = LDAP_NO_LIMIT; gopts->ldo_sizelimit = LDAP_NO_LIMIT; gopts->ldo_tm_api.tv_sec = -1; gopts->ldo_tm_net.tv_sec = -1; memset( &gopts->ldo_local_ip_addrs, 0, sizeof( gopts->ldo_local_ip_addrs ) ); /* ldo_defludp will be freed by the termination handler */ ldap_url_parselist(&gopts->ldo_defludp, "ldap://localhost/"); gopts->ldo_defport = LDAP_PORT; #if !defined(__GNUC__) && !defined(PIC) /* Do this only for a static library, and only if we can't * arrange for it to be executed as a library destructor */ atexit(ldap_int_destroy_global_options); #endif gopts->ldo_refhoplimit = LDAP_DEFAULT_REFHOPLIMIT; gopts->ldo_rebind_proc = NULL; gopts->ldo_rebind_params = NULL; LDAP_BOOL_ZERO(gopts); LDAP_BOOL_SET(gopts, LDAP_BOOL_REFERRALS); #ifdef LDAP_CONNECTIONLESS gopts->ldo_peer = NULL; gopts->ldo_cldapdn = NULL; gopts->ldo_is_udp = 0; #endif #ifdef HAVE_CYRUS_SASL gopts->ldo_def_sasl_mech = NULL; gopts->ldo_def_sasl_realm = NULL; gopts->ldo_def_sasl_authcid = NULL; gopts->ldo_def_sasl_authzid = NULL; memset( &gopts->ldo_sasl_secprops, '\0', sizeof(gopts->ldo_sasl_secprops) ); gopts->ldo_sasl_secprops.max_ssf = INT_MAX; gopts->ldo_sasl_secprops.maxbufsize = SASL_MAX_BUFF_SIZE; gopts->ldo_sasl_secprops.security_flags = SASL_SEC_NOPLAINTEXT | SASL_SEC_NOANONYMOUS; #endif #ifdef HAVE_TLS gopts->ldo_tls_connect_cb = NULL; gopts->ldo_tls_connect_arg = NULL; gopts->ldo_tls_require_cert = LDAP_OPT_X_TLS_DEMAND; gopts->ldo_tls_require_san = LDAP_OPT_X_TLS_ALLOW; #endif gopts->ldo_keepalive_probes = 0; gopts->ldo_keepalive_interval = 0; gopts->ldo_keepalive_idle = 0; gopts->ldo_tcp_user_timeout = 0; #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_init( &gopts->ldo_mutex ); #endif gopts->ldo_valid = LDAP_INITIALIZED; return; } #if defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL) char * ldap_int_hostname = NULL; #endif #ifdef LDAP_R_COMPILE int ldap_int_stackguard; #endif void ldap_int_initialize( struct ldapoptions *gopts, int *dbglvl ) { #ifdef LDAP_R_COMPILE static ldap_pvt_thread_mutex_t init_mutex; LDAP_PVT_MUTEX_FIRSTCREATE( init_mutex ); LDAP_MUTEX_LOCK( &init_mutex ); #endif if ( gopts->ldo_valid == LDAP_INITIALIZED ) { /* someone else got here first */ goto done; } ldap_int_error_init(); ldap_int_utils_init(); #ifdef HAVE_WINSOCK2 { WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD( 2, 0 ); if ( WSAStartup( wVersionRequested, &wsaData ) != 0 ) { /* Tell the user that we couldn't find a usable */ /* WinSock DLL. */ goto done; } /* Confirm that the WinSock DLL supports 2.0.*/ /* Note that if the DLL supports versions greater */ /* than 2.0 in addition to 2.0, it will still return */ /* 2.0 in wVersion since that is the version we */ /* requested. */ if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0 ) { /* Tell the user that we couldn't find a usable */ /* WinSock DLL. */ WSACleanup( ); goto done; } } /* The WinSock DLL is acceptable. Proceed. */ #elif defined(HAVE_WINSOCK) { WSADATA wsaData; if ( WSAStartup( 0x0101, &wsaData ) != 0 ) { goto done; } } #endif #if defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL) LDAP_MUTEX_LOCK( &ldap_int_hostname_mutex ); { char *name = ldap_int_hostname; ldap_int_hostname = ldap_pvt_get_fqdn( name ); if ( name != NULL && name != ldap_int_hostname ) { LDAP_FREE( name ); } } LDAP_MUTEX_UNLOCK( &ldap_int_hostname_mutex ); #endif #ifndef HAVE_POLL if ( ldap_int_tblsize == 0 ) ldap_int_ip_init(); #endif #ifdef HAVE_CYRUS_SASL if ( ldap_int_sasl_init() != 0 ) { goto done; } #endif ldap_int_initialize_global_options(gopts, dbglvl); if( getenv("LDAPNOINIT") != NULL ) { goto done; } #ifdef LDAP_R_COMPILE if( getenv("LDAPSTACKGUARD") != NULL ) { ldap_int_stackguard = 1; } #endif #ifdef HAVE_CYRUS_SASL { /* set authentication identity to current user name */ char *user = getenv("USER"); if( user == NULL ) user = getenv("USERNAME"); if( user == NULL ) user = getenv("LOGNAME"); if( user != NULL ) { gopts->ldo_def_sasl_authcid = LDAP_STRDUP( user ); } } #endif openldap_ldap_init_w_sysconf(LDAP_CONF_FILE); #ifdef HAVE_GETEUID if ( geteuid() != getuid() ) goto done; #endif openldap_ldap_init_w_userconf(LDAP_USERRC_FILE); { char *altfile = getenv(LDAP_ENV_PREFIX "CONF"); if( altfile != NULL ) { Debug2(LDAP_DEBUG_TRACE, "ldap_init: %s env is %s\n", LDAP_ENV_PREFIX "CONF", altfile ); openldap_ldap_init_w_sysconf( altfile ); } else Debug1(LDAP_DEBUG_TRACE, "ldap_init: %s env is NULL\n", LDAP_ENV_PREFIX "CONF" ); } { char *altfile = getenv(LDAP_ENV_PREFIX "RC"); if( altfile != NULL ) { Debug2(LDAP_DEBUG_TRACE, "ldap_init: %s env is %s\n", LDAP_ENV_PREFIX "RC", altfile ); openldap_ldap_init_w_userconf( altfile ); } else Debug1(LDAP_DEBUG_TRACE, "ldap_init: %s env is NULL\n", LDAP_ENV_PREFIX "RC" ); } openldap_ldap_init_w_env(gopts, NULL); done:; #ifdef LDAP_R_COMPILE LDAP_MUTEX_UNLOCK( &init_mutex ); #endif } openldap-2.5.11+dfsg/libraries/libldap/ldif.c0000644000175000017500000004473214172327167017516 0ustar ryanryan/* ldif.c - routines for dealing with LDIF files */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1992-1996 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. This * software is provided ``as is'' without express or implied warranty. */ /* This work was originally developed by the University of Michigan * and distributed as part of U-MICH LDAP. */ #include "portable.h" #include #include #include #include #include #include int ldif_debug = 0; #include "ldap-int.h" #include "ldif.h" #define CONTINUED_LINE_MARKER '\r' #ifdef CSRIMALLOC #define ber_memalloc malloc #define ber_memcalloc calloc #define ber_memrealloc realloc #define ber_strdup strdup #endif static const char nib2b64[0x40] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* * ldif_parse_line - takes a line of the form "type:[:] value" and splits it * into components "type" and "value". if a double colon separates type from * value, then value is encoded in base 64, and parse_line un-decodes it * (in place) before returning. The type and value are stored in malloc'd * memory which must be freed by the caller. * * ldif_parse_line2 - operates in-place on input buffer, returning type * in-place. Will return value in-place if possible, (must malloc for * fetched URLs). If freeval is NULL, all return data will be malloc'd * and the input line will be unmodified. Otherwise freeval is set to * True if the value was malloc'd. */ int ldif_parse_line( LDAP_CONST char *line, char **typep, char **valuep, ber_len_t *vlenp ) { struct berval type, value; int rc = ldif_parse_line2( (char *)line, &type, &value, NULL ); *typep = type.bv_val; *valuep = value.bv_val; *vlenp = value.bv_len; return rc; } int ldif_parse_line2( char *line, struct berval *type, struct berval *value, int *freeval ) { char *s, *p, *d; int b64, url; BER_BVZERO( type ); BER_BVZERO( value ); /* skip any leading space */ while ( isspace( (unsigned char) *line ) ) { line++; } if ( freeval ) { *freeval = 0; } else { line = ber_strdup( line ); if( line == NULL ) { ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug, _("ldif_parse_line: line malloc failed\n")); return( -1 ); } } type->bv_val = line; s = strchr( type->bv_val, ':' ); if ( s == NULL ) { ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug, _("ldif_parse_line: missing ':' after %s\n"), type->bv_val ); if ( !freeval ) ber_memfree( line ); return( -1 ); } /* trim any space between type and : */ for ( p = &s[-1]; p > type->bv_val && isspace( * (unsigned char *) p ); p-- ) { *p = '\0'; } *s++ = '\0'; type->bv_len = s - type->bv_val - 1; url = 0; b64 = 0; if ( *s == '<' ) { s++; url = 1; } else if ( *s == ':' ) { /* base 64 encoded value */ s++; b64 = 1; } /* skip space between : and value */ while ( isspace( (unsigned char) *s ) ) { s++; } /* check for continued line markers that should be deleted */ for ( p = s, d = s; *p; p++ ) { if ( *p != CONTINUED_LINE_MARKER ) *d++ = *p; } *d = '\0'; if ( b64 ) { char *byte = s; if ( *s == '\0' ) { /* no value is present, error out */ ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug, _("ldif_parse_line: %s missing base64 value\n"), type->bv_val ); if ( !freeval ) ber_memfree( line ); return( -1 ); } value->bv_val = s; value->bv_len = d - s; if ( ldap_int_decode_b64_inplace( value ) != LDAP_SUCCESS ) { ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug, _("ldif_parse_line: %s base64 decode failed\n"), type->bv_val ); if ( !freeval ) ber_memfree( line ); return( -1 ); } } else if ( url ) { if ( *s == '\0' ) { /* no value is present, error out */ ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug, _("ldif_parse_line: %s missing URL value\n"), type->bv_val ); if ( !freeval ) ber_memfree( line ); return( -1 ); } if( ldif_fetch_url( s, &value->bv_val, &value->bv_len ) ) { ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug, _("ldif_parse_line: %s: URL \"%s\" fetch failed\n"), type->bv_val, s ); if ( !freeval ) ber_memfree( line ); return( -1 ); } if ( freeval ) *freeval = 1; } else { value->bv_val = s; value->bv_len = (int) (d - s); } if ( !freeval ) { struct berval bv = *type; ber_dupbv( type, &bv ); if( BER_BVISNULL( type )) { ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug, _("ldif_parse_line: type malloc failed\n")); if( url ) ber_memfree( value->bv_val ); ber_memfree( line ); return( -1 ); } if( !url ) { bv = *value; ber_dupbv( value, &bv ); if( BER_BVISNULL( value )) { ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug, _("ldif_parse_line: value malloc failed\n")); ber_memfree( type->bv_val ); ber_memfree( line ); return( -1 ); } } ber_memfree( line ); } return( 0 ); } /* * ldif_getline - return the next "line" (minus newline) of input from a * string buffer of lines separated by newlines, terminated by \n\n * or \0. this routine handles continued lines, bundling them into * a single big line before returning. if a line begins with a white * space character, it is a continuation of the previous line. the white * space character (nb: only one char), and preceding newline are changed * into CONTINUED_LINE_MARKER chars, to be deleted later by the * ldif_parse_line() routine above. * * ldif_getline will skip over any line which starts '#'. * * ldif_getline takes a pointer to a pointer to the buffer on the first call, * which it updates and must be supplied on subsequent calls. */ int ldif_countlines( LDAP_CONST char *buf ) { char *nl; int ret = 0; if ( !buf ) return ret; for ( nl = strchr(buf, '\n'); nl; nl = strchr(nl, '\n') ) { nl++; if ( *nl != ' ' ) ret++; } return ret; } char * ldif_getline( char **next ) { char *line; do { if ( *next == NULL || **next == '\n' || **next == '\0' ) { return( NULL ); } line = *next; while ( (*next = strchr( *next, '\n' )) != NULL ) { #if CONTINUED_LINE_MARKER != '\r' if ( (*next)[-1] == '\r' ) { (*next)[-1] = CONTINUED_LINE_MARKER; } #endif if ( (*next)[1] != ' ' ) { if ( (*next)[1] == '\r' && (*next)[2] == '\n' ) { *(*next)++ = '\0'; } *(*next)++ = '\0'; break; } **next = CONTINUED_LINE_MARKER; (*next)[1] = CONTINUED_LINE_MARKER; (*next)++; } } while( *line == '#' ); return( line ); } /* * name and OID of attributeTypes that must be base64 encoded in any case */ typedef struct must_b64_encode_s { struct berval name; struct berval oid; } must_b64_encode_s; static must_b64_encode_s default_must_b64_encode[] = { { BER_BVC( "userPassword" ), BER_BVC( "2.5.4.35" ) }, { BER_BVNULL, BER_BVNULL } }; static must_b64_encode_s *must_b64_encode = default_must_b64_encode; /* * register name and OID of attributeTypes that must always be base64 * encoded * * NOTE: this routine mallocs memory in a static struct which must * be explicitly freed when no longer required */ int ldif_must_b64_encode_register( LDAP_CONST char *name, LDAP_CONST char *oid ) { int i; ber_len_t len; assert( must_b64_encode != NULL ); assert( name != NULL ); assert( oid != NULL ); len = strlen( name ); for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ ) { if ( len != must_b64_encode[i].name.bv_len ) { continue; } if ( strcasecmp( name, must_b64_encode[i].name.bv_val ) == 0 ) { break; } } if ( !BER_BVISNULL( &must_b64_encode[i].name ) ) { return 1; } for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ ) /* just count */ ; if ( must_b64_encode == default_must_b64_encode ) { must_b64_encode = ber_memalloc( sizeof( must_b64_encode_s ) * ( i + 2 ) ); if ( must_b64_encode == NULL ) { return 1; } for ( i = 0; !BER_BVISNULL( &default_must_b64_encode[i].name ); i++ ) { ber_dupbv( &must_b64_encode[i].name, &default_must_b64_encode[i].name ); ber_dupbv( &must_b64_encode[i].oid, &default_must_b64_encode[i].oid ); } } else { must_b64_encode_s *tmp; tmp = ber_memrealloc( must_b64_encode, sizeof( must_b64_encode_s ) * ( i + 2 ) ); if ( tmp == NULL ) { return 1; } must_b64_encode = tmp; } ber_str2bv( name, len, 1, &must_b64_encode[i].name ); ber_str2bv( oid, 0, 1, &must_b64_encode[i].oid ); BER_BVZERO( &must_b64_encode[i + 1].name ); return 0; } void ldif_must_b64_encode_release( void ) { int i; assert( must_b64_encode != NULL ); if ( must_b64_encode == default_must_b64_encode ) { return; } for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ ) { ber_memfree( must_b64_encode[i].name.bv_val ); ber_memfree( must_b64_encode[i].oid.bv_val ); } ber_memfree( must_b64_encode ); must_b64_encode = default_must_b64_encode; } /* * returns 1 iff the string corresponds to the name or the OID of any * of the attributeTypes listed in must_b64_encode */ static int ldif_must_b64_encode( LDAP_CONST char *s ) { int i; struct berval bv; assert( must_b64_encode != NULL ); assert( s != NULL ); ber_str2bv( s, 0, 0, &bv ); for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ ) { if ( ber_bvstrcasecmp( &must_b64_encode[i].name, &bv ) == 0 || ber_bvcmp( &must_b64_encode[i].oid, &bv ) == 0 ) { return 1; } } return 0; } /* NOTE: only preserved for binary compatibility */ void ldif_sput( char **out, int type, LDAP_CONST char *name, LDAP_CONST char *val, ber_len_t vlen ) { ldif_sput_wrap( out, type, name, val, vlen, 0 ); } void ldif_sput_wrap( char **out, int type, LDAP_CONST char *name, LDAP_CONST char *val, ber_len_t vlen, ber_len_t wrap ) { const unsigned char *byte, *stop; unsigned char buf[3]; unsigned long bits; char *save; int pad; int namelen = 0; ber_len_t savelen; ber_len_t len=0; ber_len_t i; if ( !wrap ) wrap = LDIF_LINE_WIDTH; /* prefix */ switch( type ) { case LDIF_PUT_COMMENT: *(*out)++ = '#'; len++; if( vlen ) { *(*out)++ = ' '; len++; } break; case LDIF_PUT_SEP: *(*out)++ = '\n'; return; } /* name (attribute type) */ if( name != NULL ) { /* put the name + ":" */ namelen = strlen(name); strcpy(*out, name); *out += namelen; len += namelen; if( type != LDIF_PUT_COMMENT ) { *(*out)++ = ':'; len++; } } #ifdef LDAP_DEBUG else { assert( type == LDIF_PUT_COMMENT ); } #endif if( vlen == 0 ) { *(*out)++ = '\n'; return; } switch( type ) { case LDIF_PUT_NOVALUE: *(*out)++ = '\n'; return; case LDIF_PUT_URL: /* url value */ *(*out)++ = '<'; len++; break; case LDIF_PUT_B64: /* base64 value */ *(*out)++ = ':'; len++; break; } switch( type ) { case LDIF_PUT_TEXT: case LDIF_PUT_URL: case LDIF_PUT_B64: *(*out)++ = ' '; len++; /* fall-thru */ case LDIF_PUT_COMMENT: /* pre-encoded names */ for ( i=0; i < vlen; i++ ) { if ( len > wrap ) { *(*out)++ = '\n'; *(*out)++ = ' '; len = 1; } *(*out)++ = val[i]; len++; } *(*out)++ = '\n'; return; } save = *out; savelen = len; *(*out)++ = ' '; len++; stop = (const unsigned char *) (val + vlen); if ( type == LDIF_PUT_VALUE && isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<' && isgraph( (unsigned char) val[vlen-1] ) #ifndef LDAP_BINARY_DEBUG && strstr( name, ";binary" ) == NULL #endif #ifndef LDAP_PASSWD_DEBUG && !ldif_must_b64_encode( name ) #endif ) { int b64 = 0; for ( byte = (const unsigned char *) val; byte < stop; byte++, len++ ) { if ( !isascii( *byte ) || !isprint( *byte ) ) { b64 = 1; break; } if ( len >= wrap ) { *(*out)++ = '\n'; *(*out)++ = ' '; len = 1; } *(*out)++ = *byte; } if( !b64 ) { *(*out)++ = '\n'; return; } } *out = save; *(*out)++ = ':'; *(*out)++ = ' '; len = savelen + 2; /* convert to base 64 (3 bytes => 4 base 64 digits) */ for ( byte = (const unsigned char *) val; byte < stop - 2; byte += 3 ) { bits = (byte[0] & 0xff) << 16; bits |= (byte[1] & 0xff) << 8; bits |= (byte[2] & 0xff); for ( i = 0; i < 4; i++, len++, bits <<= 6 ) { if ( len >= wrap ) { *(*out)++ = '\n'; *(*out)++ = ' '; len = 1; } /* get b64 digit from high order 6 bits */ *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ]; } } /* add padding if necessary */ if ( byte < stop ) { for ( i = 0; byte + i < stop; i++ ) { buf[i] = byte[i]; } for ( pad = 0; i < 3; i++, pad++ ) { buf[i] = '\0'; } byte = buf; bits = (byte[0] & 0xff) << 16; bits |= (byte[1] & 0xff) << 8; bits |= (byte[2] & 0xff); for ( i = 0; i < 4; i++, len++, bits <<= 6 ) { if ( len >= wrap ) { *(*out)++ = '\n'; *(*out)++ = ' '; len = 1; } if( i + pad < 4 ) { /* get b64 digit from low order 6 bits */ *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ]; } else { *(*out)++ = '='; } } } *(*out)++ = '\n'; } /* * ldif_type_and_value return BER malloc'd, zero-terminated LDIF line */ /* NOTE: only preserved for binary compatibility */ char * ldif_put( int type, LDAP_CONST char *name, LDAP_CONST char *val, ber_len_t vlen ) { return ldif_put_wrap( type, name, val, vlen, 0 ); } char * ldif_put_wrap( int type, LDAP_CONST char *name, LDAP_CONST char *val, ber_len_t vlen, ber_len_t wrap ) { char *buf, *p; ber_len_t nlen; nlen = ( name != NULL ) ? strlen( name ) : 0; buf = (char *) ber_memalloc( LDIF_SIZE_NEEDED_WRAP( nlen, vlen, wrap ) + 1 ); if ( buf == NULL ) { ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug, _("ldif_type_and_value: malloc failed!")); return NULL; } p = buf; ldif_sput_wrap( &p, type, name, val, vlen, wrap ); *p = '\0'; return( buf ); } int ldif_is_not_printable( LDAP_CONST char *val, ber_len_t vlen ) { if( vlen == 0 || val == NULL ) { return -1; } if( isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<' && isgraph( (unsigned char) val[vlen-1] ) ) { ber_len_t i; for ( i = 0; val[i]; i++ ) { if ( !isascii( val[i] ) || !isprint( (unsigned char) val[i] ) ) { return 1; } } return 0; } return 1; } LDIFFP * ldif_open( LDAP_CONST char *file, LDAP_CONST char *mode ) { FILE *fp = fopen( file, mode ); LDIFFP *lfp = NULL; if ( fp ) { lfp = ber_memalloc( sizeof( LDIFFP )); if ( lfp == NULL ) { return NULL; } lfp->fp = fp; lfp->prev = NULL; } return lfp; } LDIFFP * ldif_open_mem( char *ldif, size_t size, LDAP_CONST char *mode ) { #ifdef HAVE_FMEMOPEN FILE *fp = fmemopen( ldif, size, mode ); LDIFFP *lfp = NULL; if ( fp ) { lfp = ber_memalloc( sizeof( LDIFFP )); lfp->fp = fp; lfp->prev = NULL; } return lfp; #else /* !HAVE_FMEMOPEN */ return NULL; #endif /* !HAVE_FMEMOPEN */ } void ldif_close( LDIFFP *lfp ) { LDIFFP *prev; while ( lfp ) { fclose( lfp->fp ); prev = lfp->prev; ber_memfree( lfp ); lfp = prev; } } #define LDIF_MAXLINE 4096 /* * ldif_read_record - read an ldif record. Return 1 for success, 0 for EOF, * -1 for error. */ int ldif_read_record( LDIFFP *lfp, unsigned long *lno, /* ptr to line number counter */ char **bufp, /* ptr to malloced output buffer */ int *buflenp ) /* ptr to length of *bufp */ { char line[LDIF_MAXLINE], *nbufp; ber_len_t lcur = 0, len; int last_ch = '\n', found_entry = 0, stop, top_comment = 0; for ( stop = 0; !stop; last_ch = line[len-1] ) { /* If we're at the end of this file, see if we should pop * back to a previous file. (return from an include) */ while ( feof( lfp->fp )) { if ( lfp->prev ) { LDIFFP *tmp = lfp->prev; fclose( lfp->fp ); *lfp = *tmp; ber_memfree( tmp ); } else { stop = 1; break; } } if ( !stop ) { if ( fgets( line, sizeof( line ), lfp->fp ) == NULL ) { stop = 1; len = 0; } else { len = strlen( line ); } } if ( stop ) { /* Add \n in case the file does not end with newline */ if (last_ch != '\n') { len = 1; line[0] = '\n'; line[1] = '\0'; goto last; } break; } /* Squash \r\n to \n */ if ( len > 1 && line[len-2] == '\r' ) { len--; line[len] = '\0'; line[len-1] = '\n'; } if ( last_ch == '\n' ) { (*lno)++; if ( line[0] == '\n' ) { if ( !found_entry ) { lcur = 0; top_comment = 0; continue; } break; } if ( !found_entry ) { if ( line[0] == '#' ) { top_comment = 1; } else if ( ! ( top_comment && line[0] == ' ' ) ) { /* Found a new entry */ found_entry = 1; if ( isdigit( (unsigned char) line[0] ) ) { /* skip index */ continue; } if ( !strncasecmp( line, "include:", STRLENOF("include:"))) { FILE *fp2; char *ptr; found_entry = 0; if ( line[len-1] == '\n' ) { len--; line[len] = '\0'; } ptr = line + STRLENOF("include:"); while (isspace((unsigned char) *ptr)) ptr++; fp2 = ldif_open_url( ptr ); if ( fp2 ) { LDIFFP *lnew = ber_memalloc( sizeof( LDIFFP )); if ( lnew == NULL ) { fclose( fp2 ); return 0; } lnew->prev = lfp->prev; lnew->fp = lfp->fp; lfp->prev = lnew; lfp->fp = fp2; line[len] = '\n'; len++; continue; } else { /* We failed to open the file, this should * be reported as an error somehow. */ ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug, _("ldif_read_record: include %s failed\n"), ptr ); return -1; } } } } } last: if ( *buflenp - lcur <= len ) { *buflenp += len + LDIF_MAXLINE; nbufp = ber_memrealloc( *bufp, *buflenp ); if( nbufp == NULL ) { return 0; } *bufp = nbufp; } strcpy( *bufp + lcur, line ); lcur += len; } return( found_entry ); } openldap-2.5.11+dfsg/libraries/libldap/tls_g.c0000644000175000017500000007156214172327167017711 0ustar ryanryan/* tls_g.c - Handle tls/ssl using GNUTLS. */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2008-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: GNUTLS support written by Howard Chu and * Emily Backes; sponsored by The Written Word (thewrittenword.com) * and Stanford University (stanford.edu). */ #include "portable.h" #ifdef HAVE_GNUTLS #include "ldap_config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "ldap-int.h" #include "ldap-tls.h" #include #include #include #include typedef struct tlsg_ctx { gnutls_certificate_credentials_t cred; gnutls_dh_params_t dh_params; unsigned long verify_depth; int refcount; int reqcert; gnutls_priority_t prios; #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_t ref_mutex; #endif } tlsg_ctx; typedef struct tlsg_session { gnutls_session_t session; tlsg_ctx *ctx; struct berval peer_der_dn; } tlsg_session; static int tlsg_parse_ciphers( tlsg_ctx *ctx, char *suites ); static int tlsg_cert_verify( tlsg_session *s ); #ifdef LDAP_R_COMPILE static void tlsg_thr_init( void ) { /* do nothing */ } #endif /* LDAP_R_COMPILE */ /* * Initialize TLS subsystem. Should be called only once. */ static int tlsg_init( void ) { gnutls_global_init(); return 0; } /* * Tear down the TLS subsystem. Should only be called once. */ static void tlsg_destroy( void ) { gnutls_global_deinit(); } static tls_ctx * tlsg_ctx_new ( struct ldapoptions *lo ) { tlsg_ctx *ctx; ctx = ber_memcalloc ( 1, sizeof (*ctx) ); if ( ctx ) { if ( gnutls_certificate_allocate_credentials( &ctx->cred )) { ber_memfree( ctx ); return NULL; } ctx->refcount = 1; gnutls_priority_init( &ctx->prios, "NORMAL", NULL ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_init( &ctx->ref_mutex ); #endif } return (tls_ctx *)ctx; } static void tlsg_ctx_ref( tls_ctx *ctx ) { tlsg_ctx *c = (tlsg_ctx *)ctx; LDAP_MUTEX_LOCK( &c->ref_mutex ); c->refcount++; LDAP_MUTEX_UNLOCK( &c->ref_mutex ); } static void tlsg_ctx_free ( tls_ctx *ctx ) { tlsg_ctx *c = (tlsg_ctx *)ctx; int refcount; if ( !c ) return; LDAP_MUTEX_LOCK( &c->ref_mutex ); refcount = --c->refcount; LDAP_MUTEX_UNLOCK( &c->ref_mutex ); if ( refcount ) return; gnutls_priority_deinit( c->prios ); gnutls_certificate_free_credentials( c->cred ); if ( c->dh_params ) gnutls_dh_params_deinit( c->dh_params ); ber_memfree ( c ); } static int tlsg_getfile( const char *path, gnutls_datum_t *buf ) { int rc = -1, fd; struct stat st; char ebuf[128]; fd = open( path, O_RDONLY ); if ( fd < 0 ) { Debug2( LDAP_DEBUG_ANY, "TLS: opening `%s' failed: %s\n", path, AC_STRERROR_R( errno, ebuf, sizeof ebuf )); return -1; } if ( fstat( fd, &st ) == 0 ) { buf->size = st.st_size; buf->data = LDAP_MALLOC( st.st_size + 1 ); if ( buf->data ) { rc = read( fd, buf->data, st.st_size ); close( fd ); if ( rc < st.st_size ) rc = -1; else rc = 0; } } return rc; } /* This is the GnuTLS default */ #define VERIFY_DEPTH 6 /* * initialize a new TLS context */ static int tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) { tlsg_ctx *ctx = lo->ldo_tls_ctx; int rc; if ( lo->ldo_tls_ciphersuite && tlsg_parse_ciphers( ctx, lt->lt_ciphersuite )) { Debug1( LDAP_DEBUG_ANY, "TLS: could not set cipher list %s.\n", lo->ldo_tls_ciphersuite ); return -1; } if (lo->ldo_tls_cacertdir != NULL) { rc = gnutls_certificate_set_x509_trust_dir( ctx->cred, lt->lt_cacertdir, GNUTLS_X509_FMT_PEM ); if ( rc > 0 ) { Debug2( LDAP_DEBUG_TRACE, "TLS: loaded %d CA certificates from directory `%s'.\n", rc, lt->lt_cacertdir ); } else { Debug1( LDAP_DEBUG_ANY, "TLS: warning: no certificate found in CA certificate directory `%s'.\n", lt->lt_cacertdir ); /* only warn, no return */ } } if (lo->ldo_tls_cacertfile != NULL) { rc = gnutls_certificate_set_x509_trust_file( ctx->cred, lt->lt_cacertfile, GNUTLS_X509_FMT_PEM ); if ( rc < 0 ) { Debug3( LDAP_DEBUG_ANY, "TLS: could not use CA certificate file `%s': %s (%d)\n", lo->ldo_tls_cacertfile, gnutls_strerror( rc ), rc ); return -1; } else if ( rc == 0 ) { Debug1( LDAP_DEBUG_ANY, "TLS: warning: no certificate loaded from CA certificate file `%s'.\n", lo->ldo_tls_cacertfile ); /* only warn, no return */ } } if (lo->ldo_tls_cacert.bv_val != NULL ) { gnutls_datum_t buf; buf.data = (unsigned char *)lo->ldo_tls_cacert.bv_val; buf.size = lo->ldo_tls_cacert.bv_len; rc = gnutls_certificate_set_x509_trust_mem( ctx->cred, &buf, GNUTLS_X509_FMT_DER ); if ( rc < 0 ) { Debug2( LDAP_DEBUG_ANY, "TLS: could not use CA certificate: %s (%d)\n", gnutls_strerror( rc ), rc ); return -1; } } if (( lo->ldo_tls_certfile && lo->ldo_tls_keyfile ) || ( lo->ldo_tls_cert.bv_val && lo->ldo_tls_key.bv_val )) { gnutls_x509_privkey_t key; gnutls_datum_t buf; gnutls_x509_crt_t certs[VERIFY_DEPTH]; unsigned int max = VERIFY_DEPTH; rc = gnutls_x509_privkey_init( &key ); if ( rc ) return -1; /* OpenSSL builds the cert chain for us, but GnuTLS * expects it to be present in the certfile. If it's * not, we have to build it ourselves. So we have to * do some special checks here... */ if ( lo->ldo_tls_key.bv_val ) { buf.data = (unsigned char *)lo->ldo_tls_key.bv_val; buf.size = lo->ldo_tls_key.bv_len; rc = gnutls_x509_privkey_import( key, &buf, GNUTLS_X509_FMT_DER ); } else { rc = tlsg_getfile( lt->lt_keyfile, &buf ); if ( rc ) { Debug1( LDAP_DEBUG_ANY, "TLS: could not use private key file `%s`.\n", lt->lt_keyfile); return -1; } rc = gnutls_x509_privkey_import( key, &buf, GNUTLS_X509_FMT_PEM ); LDAP_FREE( buf.data ); } if ( rc < 0 ) { Debug2( LDAP_DEBUG_ANY, "TLS: could not use private key: %s (%d)\n", gnutls_strerror( rc ), rc ); return rc; } if ( lo->ldo_tls_cert.bv_val ) { buf.data = (unsigned char *)lo->ldo_tls_cert.bv_val; buf.size = lo->ldo_tls_cert.bv_len; rc = gnutls_x509_crt_list_import( certs, &max, &buf, GNUTLS_X509_FMT_DER, 0 ); } else { rc = tlsg_getfile( lt->lt_certfile, &buf ); if ( rc ) { Debug1( LDAP_DEBUG_ANY, "TLS: could not use certificate file `%s`.\n", lt->lt_certfile); return -1; } rc = gnutls_x509_crt_list_import( certs, &max, &buf, GNUTLS_X509_FMT_PEM, 0 ); LDAP_FREE( buf.data ); } if ( rc < 0 ) { Debug2( LDAP_DEBUG_ANY, "TLS: could not use certificate: %s (%d)\n", gnutls_strerror( rc ), rc ); return rc; } /* If there's only one cert and it's not self-signed, * then we have to build the cert chain. */ if ( max == 1 && !gnutls_x509_crt_check_issuer( certs[0], certs[0] )) { unsigned int i; for ( i = 1; icred, certs[i-1], &certs[i], 0 )) break; max++; /* If this CA is self-signed, we're done */ if ( gnutls_x509_crt_check_issuer( certs[i], certs[i] )) break; } } rc = gnutls_certificate_set_x509_key( ctx->cred, certs, max, key ); if ( rc ) { Debug2( LDAP_DEBUG_ANY, "TLS: could not use certificate with key: %s (%d)\n", gnutls_strerror( rc ), rc ); return -1; } } else if (( lo->ldo_tls_certfile || lo->ldo_tls_keyfile )) { Debug0( LDAP_DEBUG_ANY, "TLS: only one of certfile and keyfile specified\n" ); return -1; } else if (( lo->ldo_tls_cert.bv_val || lo->ldo_tls_key.bv_val )) { Debug0( LDAP_DEBUG_ANY, "TLS: only one of cert and key specified\n" ); return -1; } if ( lo->ldo_tls_crlfile ) { rc = gnutls_certificate_set_x509_crl_file( ctx->cred, lt->lt_crlfile, GNUTLS_X509_FMT_PEM ); if ( rc < 0 ) return -1; rc = 0; } /* FIXME: ITS#5992 - this should be configurable, * and V1 CA certs should be phased out ASAP. */ gnutls_certificate_set_verify_flags( ctx->cred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT ); if ( is_server && lo->ldo_tls_dhfile ) { gnutls_datum_t buf; rc = tlsg_getfile( lo->ldo_tls_dhfile, &buf ); if ( rc ) return -1; rc = gnutls_dh_params_init( &ctx->dh_params ); if ( rc == 0 ) rc = gnutls_dh_params_import_pkcs3( ctx->dh_params, &buf, GNUTLS_X509_FMT_PEM ); LDAP_FREE( buf.data ); if ( rc ) return -1; gnutls_certificate_set_dh_params( ctx->cred, ctx->dh_params ); } ctx->reqcert = lo->ldo_tls_require_cert; return 0; } static tls_session * tlsg_session_new ( tls_ctx * ctx, int is_server ) { tlsg_ctx *c = (tlsg_ctx *)ctx; tlsg_session *session; session = ber_memcalloc ( 1, sizeof (*session) ); if ( !session ) return NULL; session->ctx = c; gnutls_init( &session->session, is_server ? GNUTLS_SERVER : GNUTLS_CLIENT ); gnutls_priority_set( session->session, c->prios ); if ( c->cred ) gnutls_credentials_set( session->session, GNUTLS_CRD_CERTIFICATE, c->cred ); if ( is_server ) { int flag = 0; if ( c->reqcert ) { flag = GNUTLS_CERT_REQUEST; if ( c->reqcert == LDAP_OPT_X_TLS_DEMAND || c->reqcert == LDAP_OPT_X_TLS_HARD ) flag = GNUTLS_CERT_REQUIRE; gnutls_certificate_server_set_request( session->session, flag ); } } return (tls_session *)session; } static int tlsg_session_accept( tls_session *session ) { tlsg_session *s = (tlsg_session *)session; int rc; rc = gnutls_handshake( s->session ); if ( rc == 0 && s->ctx->reqcert != LDAP_OPT_X_TLS_NEVER ) { const gnutls_datum_t *peer_cert_list; unsigned int list_size; peer_cert_list = gnutls_certificate_get_peers( s->session, &list_size ); if ( !peer_cert_list && s->ctx->reqcert == LDAP_OPT_X_TLS_TRY ) rc = 0; else { rc = tlsg_cert_verify( s ); if ( rc && s->ctx->reqcert == LDAP_OPT_X_TLS_ALLOW ) rc = 0; } } return rc; } static int tlsg_session_connect( LDAP *ld, tls_session *session, const char *name_in ) { tlsg_session *s = (tlsg_session *)session; int rc; if ( name_in ) { rc = gnutls_server_name_set( s->session, GNUTLS_NAME_DNS, name_in, strlen(name_in) ); if ( rc != GNUTLS_E_SUCCESS ) { return rc; } } return tlsg_session_accept( session); } static int tlsg_session_upflags( Sockbuf *sb, tls_session *session, int rc ) { tlsg_session *s = (tlsg_session *)session; if ( rc != GNUTLS_E_INTERRUPTED && rc != GNUTLS_E_AGAIN ) return 0; switch (gnutls_record_get_direction (s->session)) { case 0: sb->sb_trans_needs_read = 1; return 1; case 1: sb->sb_trans_needs_write = 1; return 1; } return 0; } static char * tlsg_session_errmsg( tls_session *sess, int rc, char *buf, size_t len ) { return (char *)gnutls_strerror( rc ); } static void tlsg_x509_cert_dn( struct berval *cert, struct berval *dn, int get_subject ) { BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; ber_tag_t tag; ber_len_t len; ber_int_t i; ber_init2( ber, cert, LBER_USE_DER ); tag = ber_skip_tag( ber, &len ); /* Sequence */ tag = ber_skip_tag( ber, &len ); /* Sequence */ tag = ber_peek_tag( ber, &len ); /* Context + Constructed (version) */ if ( tag == 0xa0 ) { /* Version is optional */ tag = ber_skip_tag( ber, &len ); tag = ber_get_int( ber, &i ); /* Int: Version */ } tag = ber_skip_tag( ber, &len ); /* Int: Serial (can be longer than ber_int_t) */ ber_skip_data( ber, len ); tag = ber_skip_tag( ber, &len ); /* Sequence: Signature */ ber_skip_data( ber, len ); if ( !get_subject ) { tag = ber_peek_tag( ber, &len ); /* Sequence: Issuer DN */ } else { tag = ber_skip_tag( ber, &len ); ber_skip_data( ber, len ); tag = ber_skip_tag( ber, &len ); /* Sequence: Validity */ ber_skip_data( ber, len ); tag = ber_peek_tag( ber, &len ); /* Sequence: Subject DN */ } len = ber_ptrlen( ber ); dn->bv_val = cert->bv_val + len; dn->bv_len = cert->bv_len - len; } static int tlsg_session_my_dn( tls_session *session, struct berval *der_dn ) { tlsg_session *s = (tlsg_session *)session; const gnutls_datum_t *x; struct berval bv; x = gnutls_certificate_get_ours( s->session ); if (!x) return LDAP_INVALID_CREDENTIALS; bv.bv_val = (char *) x->data; bv.bv_len = x->size; tlsg_x509_cert_dn( &bv, der_dn, 1 ); return 0; } static int tlsg_session_peer_dn( tls_session *session, struct berval *der_dn ) { tlsg_session *s = (tlsg_session *)session; if ( !s->peer_der_dn.bv_val ) { const gnutls_datum_t *peer_cert_list; unsigned int list_size; struct berval bv; peer_cert_list = gnutls_certificate_get_peers( s->session, &list_size ); if ( !peer_cert_list ) return LDAP_INVALID_CREDENTIALS; bv.bv_len = peer_cert_list->size; bv.bv_val = (char *) peer_cert_list->data; tlsg_x509_cert_dn( &bv, &s->peer_der_dn, 1 ); } *der_dn = s->peer_der_dn; return 0; } /* what kind of hostname were we given? */ #define IS_DNS 0 #define IS_IP4 1 #define IS_IP6 2 #define CN_OID "2.5.4.3" static int tlsg_session_chkhost( LDAP *ld, tls_session *session, const char *name_in ) { tlsg_session *s = (tlsg_session *)session; int i, ret; int chkSAN = ld->ld_options.ldo_tls_require_san, gotSAN = 0; const gnutls_datum_t *peer_cert_list; unsigned int list_size; char altname[NI_MAXHOST]; size_t altnamesize; gnutls_x509_crt_t cert; const char *name; char *ptr; char *domain = NULL; #ifdef LDAP_PF_INET6 struct in6_addr addr; #else struct in_addr addr; #endif int len1 = 0, len2 = 0; int ntype = IS_DNS; if( ldap_int_hostname && ( !name_in || !strcasecmp( name_in, "localhost" ) ) ) { name = ldap_int_hostname; } else { name = name_in; } peer_cert_list = gnutls_certificate_get_peers( s->session, &list_size ); if ( !peer_cert_list ) { Debug0( LDAP_DEBUG_ANY, "TLS: unable to get peer certificate.\n" ); /* If this was a fatal condition, things would have * aborted long before now. */ return LDAP_SUCCESS; } ret = gnutls_x509_crt_init( &cert ); if ( ret < 0 ) return LDAP_LOCAL_ERROR; ret = gnutls_x509_crt_import( cert, peer_cert_list, GNUTLS_X509_FMT_DER ); if ( ret ) { gnutls_x509_crt_deinit( cert ); return LDAP_LOCAL_ERROR; } #ifdef LDAP_PF_INET6 if (inet_pton(AF_INET6, name, &addr)) { ntype = IS_IP6; } else #endif if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) { if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4; } if (ntype == IS_DNS) { len1 = strlen(name); domain = strchr(name, '.'); if (domain) { len2 = len1 - (domain-name); } } if (chkSAN) { for ( i=0, ret=0; ret >= 0; i++ ) { altnamesize = sizeof(altname); ret = gnutls_x509_crt_get_subject_alt_name( cert, i, altname, &altnamesize, NULL ); if ( ret < 0 ) break; gotSAN = 1; /* ignore empty */ if ( altnamesize == 0 ) continue; if ( ret == GNUTLS_SAN_DNSNAME ) { if (ntype != IS_DNS) continue; /* Is this an exact match? */ if ((len1 == altnamesize) && !strncasecmp(name, altname, len1)) { break; } /* Is this a wildcard match? */ if (domain && (altname[0] == '*') && (altname[1] == '.') && (len2 == altnamesize-1) && !strncasecmp(domain, &altname[1], len2)) { break; } } else if ( ret == GNUTLS_SAN_IPADDRESS ) { if (ntype == IS_DNS) continue; #ifdef LDAP_PF_INET6 if (ntype == IS_IP6 && altnamesize != sizeof(struct in6_addr)) { continue; } else #endif if (ntype == IS_IP4 && altnamesize != sizeof(struct in_addr)) { continue; } if (!memcmp(altname, &addr, altnamesize)) { break; } } } if ( ret >= 0 ) { ret = LDAP_SUCCESS; } } if (ret != LDAP_SUCCESS && chkSAN) { switch(chkSAN) { case LDAP_OPT_X_TLS_DEMAND: case LDAP_OPT_X_TLS_HARD: if (!gotSAN) { Debug0( LDAP_DEBUG_ANY, "TLS: unable to get subjectAltName from peer certificate.\n" ); ret = LDAP_CONNECT_ERROR; if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } ld->ld_error = LDAP_STRDUP( _("TLS: unable to get subjectAltName from peer certificate")); goto done; } /* FALLTHRU */ case LDAP_OPT_X_TLS_TRY: if (gotSAN) { Debug1( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " "subjectAltName in certificate.\n", name ); ret = LDAP_CONNECT_ERROR; if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } ld->ld_error = LDAP_STRDUP( _("TLS: hostname does not match subjectAltName in peer certificate")); goto done; } break; case LDAP_OPT_X_TLS_ALLOW: break; } } if ( ret != LDAP_SUCCESS ){ /* find the last CN */ i=0; do { altnamesize = 0; ret = gnutls_x509_crt_get_dn_by_oid( cert, CN_OID, i, 1, altname, &altnamesize ); if ( ret == GNUTLS_E_SHORT_MEMORY_BUFFER ) i++; else break; } while ( 1 ); if ( i ) { altnamesize = sizeof(altname); ret = gnutls_x509_crt_get_dn_by_oid( cert, CN_OID, i-1, 0, altname, &altnamesize ); } if ( ret < 0 ) { Debug0( LDAP_DEBUG_ANY, "TLS: unable to get common name from peer certificate.\n" ); ret = LDAP_CONNECT_ERROR; if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } ld->ld_error = LDAP_STRDUP( _("TLS: unable to get CN from peer certificate")); } else { ret = LDAP_LOCAL_ERROR; if ( !len1 ) len1 = strlen( name ); if ( len1 == altnamesize && strncasecmp(name, altname, altnamesize) == 0 ) { ret = LDAP_SUCCESS; } else if (( altname[0] == '*' ) && ( altname[1] == '.' )) { /* Is this a wildcard match? */ if( domain && (len2 == altnamesize-1) && !strncasecmp(domain, &altname[1], len2)) { ret = LDAP_SUCCESS; } } } if( ret == LDAP_LOCAL_ERROR ) { altname[altnamesize] = '\0'; Debug2( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " "common name in certificate (%s).\n", name, altname ); ret = LDAP_CONNECT_ERROR; if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } ld->ld_error = LDAP_STRDUP( _("TLS: hostname does not match name in peer certificate")); } } done: gnutls_x509_crt_deinit( cert ); return ret; } static int tlsg_session_strength( tls_session *session ) { tlsg_session *s = (tlsg_session *)session; gnutls_cipher_algorithm_t c; c = gnutls_cipher_get( s->session ); return gnutls_cipher_get_key_size( c ) * 8; } static int tlsg_session_unique( tls_session *sess, struct berval *buf, int is_server) { tlsg_session *s = (tlsg_session *)sess; gnutls_datum_t cb; int rc; rc = gnutls_session_channel_binding( s->session, GNUTLS_CB_TLS_UNIQUE, &cb ); if ( rc == 0 ) { int len = cb.size; if ( len > buf->bv_len ) len = buf->bv_len; buf->bv_len = len; memcpy( buf->bv_val, cb.data, len ); return len; } return 0; } static int tlsg_session_endpoint( tls_session *sess, struct berval *buf, int is_server ) { tlsg_session *s = (tlsg_session *)sess; const gnutls_datum_t *cert_data; gnutls_x509_crt_t server_cert; gnutls_digest_algorithm_t md; int sign_algo, md_len, rc; if ( is_server ) cert_data = gnutls_certificate_get_ours( s->session ); else cert_data = gnutls_certificate_get_peers( s->session, NULL ); if ( cert_data == NULL ) return 0; rc = gnutls_x509_crt_init( &server_cert ); if ( rc != GNUTLS_E_SUCCESS ) return 0; rc = gnutls_x509_crt_import( server_cert, cert_data, GNUTLS_X509_FMT_DER ); if ( rc != GNUTLS_E_SUCCESS ) { gnutls_x509_crt_deinit( server_cert ); return 0; } sign_algo = gnutls_x509_crt_get_signature_algorithm( server_cert ); gnutls_x509_crt_deinit( server_cert ); if ( sign_algo <= GNUTLS_SIGN_UNKNOWN ) return 0; md = gnutls_sign_get_hash_algorithm( sign_algo ); if ( md == GNUTLS_DIG_UNKNOWN ) return 0; /* See RFC 5929 */ switch (md) { case GNUTLS_DIG_NULL: case GNUTLS_DIG_MD2: case GNUTLS_DIG_MD5: case GNUTLS_DIG_SHA1: md = GNUTLS_DIG_SHA256; } md_len = gnutls_hash_get_len( md ); if ( md_len == 0 || md_len > buf->bv_len ) return 0; rc = gnutls_hash_fast( md, cert_data->data, cert_data->size, buf->bv_val ); if ( rc != GNUTLS_E_SUCCESS ) return 0; buf->bv_len = md_len; return md_len; } static const char * tlsg_session_version( tls_session *sess ) { tlsg_session *s = (tlsg_session *)sess; return gnutls_protocol_get_name(gnutls_protocol_get_version( s->session )); } static const char * tlsg_session_cipher( tls_session *sess ) { tlsg_session *s = (tlsg_session *)sess; return gnutls_cipher_get_name(gnutls_cipher_get( s->session )); } static int tlsg_session_peercert( tls_session *sess, struct berval *der ) { tlsg_session *s = (tlsg_session *)sess; const gnutls_datum_t *peer_cert_list; unsigned int list_size; peer_cert_list = gnutls_certificate_get_peers( s->session, &list_size ); if (!peer_cert_list) return -1; der->bv_len = peer_cert_list[0].size; der->bv_val = LDAP_MALLOC( der->bv_len ); if (!der->bv_val) return -1; memcpy(der->bv_val, peer_cert_list[0].data, der->bv_len); return 0; } static int tlsg_session_pinning( LDAP *ld, tls_session *sess, char *hashalg, struct berval *hash ) { tlsg_session *s = (tlsg_session *)sess; const gnutls_datum_t *cert_list; unsigned int cert_list_size = 0; gnutls_x509_crt_t crt; gnutls_pubkey_t pubkey; gnutls_datum_t key = {}; gnutls_digest_algorithm_t alg; struct berval keyhash; size_t len; int rc = -1; if ( hashalg ) { alg = gnutls_digest_get_id( hashalg ); if ( alg == GNUTLS_DIG_UNKNOWN ) { Debug1( LDAP_DEBUG_ANY, "tlsg_session_pinning: " "unknown hashing algorithm for GnuTLS: '%s'\n", hashalg ); return rc; } } cert_list = gnutls_certificate_get_peers( s->session, &cert_list_size ); if ( cert_list_size == 0 ) { return rc; } if ( gnutls_x509_crt_init( &crt ) < 0 ) { return rc; } if ( gnutls_x509_crt_import( crt, &cert_list[0], GNUTLS_X509_FMT_DER ) ) { goto done; } if ( gnutls_pubkey_init( &pubkey ) ) { goto done; } if ( gnutls_pubkey_import_x509( pubkey, crt, 0 ) < 0 ) { goto done; } gnutls_pubkey_export( pubkey, GNUTLS_X509_FMT_DER, key.data, &len ); if ( len <= 0 ) { goto done; } key.data = LDAP_MALLOC( len ); if ( !key.data ) { goto done; } key.size = len; if ( gnutls_pubkey_export( pubkey, GNUTLS_X509_FMT_DER, key.data, &len ) < 0 ) { goto done; } if ( hashalg ) { keyhash.bv_len = gnutls_hash_get_len( alg ); keyhash.bv_val = LDAP_MALLOC( keyhash.bv_len ); if ( !keyhash.bv_val || gnutls_fingerprint( alg, &key, keyhash.bv_val, &keyhash.bv_len ) < 0 ) { goto done; } } else { keyhash.bv_val = (char *)key.data; keyhash.bv_len = key.size; } if ( ber_bvcmp( hash, &keyhash ) ) { rc = LDAP_CONNECT_ERROR; Debug0( LDAP_DEBUG_ANY, "tlsg_session_pinning: " "public key hash does not match provided pin.\n" ); if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } ld->ld_error = LDAP_STRDUP( _("TLS: public key hash does not match provided pin")); } else { rc = LDAP_SUCCESS; } done: if ( pubkey ) { gnutls_pubkey_deinit( pubkey ); } if ( crt ) { gnutls_x509_crt_deinit( crt ); } if ( keyhash.bv_val != (char *)key.data ) { LDAP_FREE( keyhash.bv_val ); } if ( key.data ) { LDAP_FREE( key.data ); } return rc; } /* suites is a string of colon-separated cipher suite names. */ static int tlsg_parse_ciphers( tlsg_ctx *ctx, char *suites ) { const char *err; int rc = gnutls_priority_init( &ctx->prios, suites, &err ); if ( rc ) ctx->prios = NULL; return rc; } /* * TLS support for LBER Sockbufs */ struct tls_data { tlsg_session *session; Sockbuf_IO_Desc *sbiod; }; static ssize_t tlsg_recv( gnutls_transport_ptr_t ptr, void *buf, size_t len ) { struct tls_data *p; if ( buf == NULL || len <= 0 ) return 0; p = (struct tls_data *)ptr; if ( p == NULL || p->sbiod == NULL ) { return 0; } return LBER_SBIOD_READ_NEXT( p->sbiod, buf, len ); } static ssize_t tlsg_send( gnutls_transport_ptr_t ptr, const void *buf, size_t len ) { struct tls_data *p; if ( buf == NULL || len <= 0 ) return 0; p = (struct tls_data *)ptr; if ( p == NULL || p->sbiod == NULL ) { return 0; } return LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len ); } static int tlsg_sb_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { struct tls_data *p; tlsg_session *session = arg; assert( sbiod != NULL ); p = LBER_MALLOC( sizeof( *p ) ); if ( p == NULL ) { return -1; } gnutls_transport_set_ptr( session->session, (gnutls_transport_ptr_t)p ); gnutls_transport_set_pull_function( session->session, tlsg_recv ); gnutls_transport_set_push_function( session->session, tlsg_send ); p->session = session; p->sbiod = sbiod; sbiod->sbiod_pvt = p; return 0; } static int tlsg_sb_remove( Sockbuf_IO_Desc *sbiod ) { struct tls_data *p; assert( sbiod != NULL ); assert( sbiod->sbiod_pvt != NULL ); p = (struct tls_data *)sbiod->sbiod_pvt; gnutls_deinit ( p->session->session ); LBER_FREE( p->session ); LBER_FREE( sbiod->sbiod_pvt ); sbiod->sbiod_pvt = NULL; return 0; } static int tlsg_sb_close( Sockbuf_IO_Desc *sbiod ) { struct tls_data *p; assert( sbiod != NULL ); assert( sbiod->sbiod_pvt != NULL ); p = (struct tls_data *)sbiod->sbiod_pvt; gnutls_bye ( p->session->session, GNUTLS_SHUT_WR ); return 0; } static int tlsg_sb_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { struct tls_data *p; assert( sbiod != NULL ); assert( sbiod->sbiod_pvt != NULL ); p = (struct tls_data *)sbiod->sbiod_pvt; if ( opt == LBER_SB_OPT_GET_SSL ) { *((tlsg_session **)arg) = p->session; return 1; } else if ( opt == LBER_SB_OPT_DATA_READY ) { if( gnutls_record_check_pending( p->session->session ) > 0 ) { return 1; } } return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); } static ber_slen_t tlsg_sb_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) { struct tls_data *p; ber_slen_t ret; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); p = (struct tls_data *)sbiod->sbiod_pvt; ret = gnutls_record_recv ( p->session->session, buf, len ); switch (ret) { case GNUTLS_E_INTERRUPTED: case GNUTLS_E_AGAIN: sbiod->sbiod_sb->sb_trans_needs_read = 1; sock_errset(EWOULDBLOCK); ret = 0; break; case GNUTLS_E_REHANDSHAKE: for ( ret = gnutls_handshake ( p->session->session ); ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN; ret = gnutls_handshake ( p->session->session ) ); sbiod->sbiod_sb->sb_trans_needs_read = 1; ret = 0; break; default: sbiod->sbiod_sb->sb_trans_needs_read = 0; } return ret; } static ber_slen_t tlsg_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) { struct tls_data *p; ber_slen_t ret; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); p = (struct tls_data *)sbiod->sbiod_pvt; ret = gnutls_record_send ( p->session->session, (char *)buf, len ); if ( ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN ) { sbiod->sbiod_sb->sb_trans_needs_write = 1; sock_errset(EWOULDBLOCK); ret = 0; } else { sbiod->sbiod_sb->sb_trans_needs_write = 0; } return ret; } static Sockbuf_IO tlsg_sbio = { tlsg_sb_setup, /* sbi_setup */ tlsg_sb_remove, /* sbi_remove */ tlsg_sb_ctrl, /* sbi_ctrl */ tlsg_sb_read, /* sbi_read */ tlsg_sb_write, /* sbi_write */ tlsg_sb_close /* sbi_close */ }; /* Certs are not automatically verified during the handshake */ static int tlsg_cert_verify( tlsg_session *ssl ) { unsigned int status = 0; int err; time_t now = time(0); time_t peertime; err = gnutls_certificate_verify_peers2( ssl->session, &status ); if ( err < 0 ) { Debug1( LDAP_DEBUG_ANY,"TLS: gnutls_certificate_verify_peers2 failed %d\n", err ); return -1; } if ( status ) { Debug1( LDAP_DEBUG_TRACE,"TLS: peer cert untrusted or revoked (0x%x)\n", status ); return -1; } peertime = gnutls_certificate_expiration_time_peers( ssl->session ); if ( peertime == (time_t) -1 ) { Debug0( LDAP_DEBUG_ANY, "TLS: gnutls_certificate_expiration_time_peers failed\n" ); return -1; } if ( peertime < now ) { Debug0( LDAP_DEBUG_ANY, "TLS: peer certificate is expired\n" ); return -1; } peertime = gnutls_certificate_activation_time_peers( ssl->session ); if ( peertime == (time_t) -1 ) { Debug0( LDAP_DEBUG_ANY, "TLS: gnutls_certificate_activation_time_peers failed\n" ); return -1; } if ( peertime > now ) { Debug0( LDAP_DEBUG_ANY, "TLS: peer certificate not yet active\n" ); return -1; } return 0; } tls_impl ldap_int_tls_impl = { "GnuTLS", tlsg_init, tlsg_destroy, tlsg_ctx_new, tlsg_ctx_ref, tlsg_ctx_free, tlsg_ctx_init, tlsg_session_new, tlsg_session_connect, tlsg_session_accept, tlsg_session_upflags, tlsg_session_errmsg, tlsg_session_my_dn, tlsg_session_peer_dn, tlsg_session_chkhost, tlsg_session_strength, tlsg_session_unique, tlsg_session_endpoint, tlsg_session_version, tlsg_session_cipher, tlsg_session_peercert, tlsg_session_pinning, &tlsg_sbio, #ifdef LDAP_R_COMPILE tlsg_thr_init, #else NULL, #endif 0 }; #endif /* HAVE_GNUTLS */ openldap-2.5.11+dfsg/libraries/libldap/deref.c0000644000175000017500000001336114172327167017657 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * Portions Copyright 2008 Pierangelo Masarati. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This work was initially developed by Pierangelo Masarati * for inclusion in OpenLDAP Software. */ #include "portable.h" #include #include #include #include #include "ldap-int.h" int ldap_create_deref_control_value( LDAP *ld, LDAPDerefSpec *ds, struct berval *value ) { BerElement *ber = NULL; ber_tag_t tag; int i; if ( ld == NULL || value == NULL || ds == NULL ) { if ( ld ) ld->ld_errno = LDAP_PARAM_ERROR; return LDAP_PARAM_ERROR; } assert( LDAP_VALID( ld ) ); value->bv_val = NULL; value->bv_len = 0; ld->ld_errno = LDAP_SUCCESS; ber = ldap_alloc_ber_with_options( ld ); if ( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } tag = ber_printf( ber, "{" /*}*/ ); if ( tag == LBER_ERROR ) { ld->ld_errno = LDAP_ENCODING_ERROR; goto done; } for ( i = 0; ds[i].derefAttr != NULL; i++ ) { int j; tag = ber_printf( ber, "{s{" /*}}*/ , ds[i].derefAttr ); if ( tag == LBER_ERROR ) { ld->ld_errno = LDAP_ENCODING_ERROR; goto done; } for ( j = 0; ds[i].attributes[j] != NULL; j++ ) { tag = ber_printf( ber, "s", ds[i].attributes[ j ] ); if ( tag == LBER_ERROR ) { ld->ld_errno = LDAP_ENCODING_ERROR; goto done; } } tag = ber_printf( ber, /*{{*/ "}N}" ); if ( tag == LBER_ERROR ) { ld->ld_errno = LDAP_ENCODING_ERROR; goto done; } } tag = ber_printf( ber, /*{*/ "}" ); if ( tag == LBER_ERROR ) { ld->ld_errno = LDAP_ENCODING_ERROR; goto done; } if ( ber_flatten2( ber, value, 1 ) == -1 ) { ld->ld_errno = LDAP_NO_MEMORY; } done:; if ( ber != NULL ) { ber_free( ber, 1 ); } return ld->ld_errno; } int ldap_create_deref_control( LDAP *ld, LDAPDerefSpec *ds, int iscritical, LDAPControl **ctrlp ) { struct berval value; if ( ctrlp == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; } ld->ld_errno = ldap_create_deref_control_value( ld, ds, &value ); if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = ldap_control_create( LDAP_CONTROL_X_DEREF, iscritical, &value, 0, ctrlp ); if ( ld->ld_errno != LDAP_SUCCESS ) { LDAP_FREE( value.bv_val ); } } return ld->ld_errno; } void ldap_derefresponse_free( LDAPDerefRes *dr ) { for ( ; dr; ) { LDAPDerefRes *drnext = dr->next; LDAPDerefVal *dv; LDAP_FREE( dr->derefAttr ); LDAP_FREE( dr->derefVal.bv_val ); for ( dv = dr->attrVals; dv; ) { LDAPDerefVal *dvnext = dv->next; LDAP_FREE( dv->type ); ber_bvarray_free( dv->vals ); LDAP_FREE( dv ); dv = dvnext; } LDAP_FREE( dr ); dr = drnext; } } int ldap_parse_derefresponse_control( LDAP *ld, LDAPControl *ctrl, LDAPDerefRes **drp2 ) { BerElement *ber; ber_tag_t tag; ber_len_t len; char *last; LDAPDerefRes *drhead = NULL, **drp; if ( ld == NULL || ctrl == NULL || drp2 == NULL ) { if ( ld ) ld->ld_errno = LDAP_PARAM_ERROR; return LDAP_PARAM_ERROR; } /* Create a BerElement from the berval returned in the control. */ ber = ber_init( &ctrl->ldctl_value ); if ( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } /* Extract the count and cookie from the control. */ drp = &drhead; for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT; tag = ber_next_element( ber, &len, last ) ) { LDAPDerefRes *dr; LDAPDerefVal **dvp; char *last2; dr = LDAP_CALLOC( 1, sizeof(LDAPDerefRes) ); if ( dr == NULL ) { ldap_derefresponse_free( drhead ); *drp2 = NULL; ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } dvp = &dr->attrVals; tag = ber_scanf( ber, "{ao", &dr->derefAttr, &dr->derefVal ); if ( tag == LBER_ERROR ) { goto done; } tag = ber_peek_tag( ber, &len ); if ( tag == (LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) ) { for ( tag = ber_first_element( ber, &len, &last2 ); tag != LBER_DEFAULT; tag = ber_next_element( ber, &len, last2 ) ) { LDAPDerefVal *dv; dv = LDAP_CALLOC( 1, sizeof(LDAPDerefVal) ); if ( dv == NULL ) { ldap_derefresponse_free( drhead ); LDAP_FREE( dr ); *drp2 = NULL; ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } tag = ber_scanf( ber, "{a[W]}", &dv->type, &dv->vals ); if ( tag == LBER_ERROR ) { goto done; } *dvp = dv; dvp = &dv->next; } } tag = ber_scanf( ber, "}" ); if ( tag == LBER_ERROR ) { goto done; } *drp = dr; drp = &dr->next; } tag = 0; done:; ber_free( ber, 1 ); if ( tag == LBER_ERROR ) { if ( drhead != NULL ) { ldap_derefresponse_free( drhead ); } *drp2 = NULL; ld->ld_errno = LDAP_DECODING_ERROR; } else { *drp2 = drhead; ld->ld_errno = LDAP_SUCCESS; } return ld->ld_errno; } int ldap_parse_deref_control( LDAP *ld, LDAPControl **ctrls, LDAPDerefRes **drp ) { LDAPControl *c; if ( drp == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; } *drp = NULL; if ( ctrls == NULL ) { ld->ld_errno = LDAP_CONTROL_NOT_FOUND; return ld->ld_errno; } c = ldap_control_find( LDAP_CONTROL_X_DEREF, ctrls, NULL ); if ( c == NULL ) { /* No deref control was found. */ ld->ld_errno = LDAP_CONTROL_NOT_FOUND; return ld->ld_errno; } ld->ld_errno = ldap_parse_derefresponse_control( ld, c, drp ); return ld->ld_errno; } openldap-2.5.11+dfsg/libraries/libldap/ldap-tls.h0000644000175000017500000000567514172327167020330 0ustar ryanryan/* ldap-tls.h - TLS defines & prototypes internal to the LDAP library */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2008-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #ifndef _LDAP_TLS_H #define _LDAP_TLS_H 1 struct tls_impl; struct tls_ctx; struct tls_session; typedef struct tls_ctx tls_ctx; typedef struct tls_session tls_session; typedef int (TI_tls_init)(void); typedef void (TI_tls_destroy)(void); typedef tls_ctx *(TI_ctx_new)(struct ldapoptions *lo); typedef void (TI_ctx_ref)(tls_ctx *ctx); typedef void (TI_ctx_free)(tls_ctx *ctx); typedef int (TI_ctx_init)(struct ldapoptions *lo, struct ldaptls *lt, int is_server); typedef tls_session *(TI_session_new)(tls_ctx *ctx, int is_server); typedef int (TI_session_connect)(LDAP *ld, tls_session *s, const char *name_in); typedef int (TI_session_accept)(tls_session *s); typedef int (TI_session_upflags)(Sockbuf *sb, tls_session *s, int rc); typedef char *(TI_session_errmsg)(tls_session *s, int rc, char *buf, size_t len ); typedef int (TI_session_dn)(tls_session *sess, struct berval *dn); typedef int (TI_session_chkhost)(LDAP *ld, tls_session *s, const char *name_in); typedef int (TI_session_strength)(tls_session *sess); typedef int (TI_session_unique)(tls_session *sess, struct berval *buf, int is_server); typedef int (TI_session_endpoint)(tls_session *sess, struct berval *buf, int is_server); typedef const char *(TI_session_name)(tls_session *s); typedef int (TI_session_peercert)(tls_session *s, struct berval *der); typedef int (TI_session_pinning)(LDAP *ld, tls_session *s, char *hashalg, struct berval *hash); typedef void (TI_thr_init)(void); typedef struct tls_impl { const char *ti_name; TI_tls_init *ti_tls_init; /* library initialization */ TI_tls_destroy *ti_tls_destroy; TI_ctx_new *ti_ctx_new; TI_ctx_ref *ti_ctx_ref; TI_ctx_free *ti_ctx_free; TI_ctx_init *ti_ctx_init; TI_session_new *ti_session_new; TI_session_connect *ti_session_connect; TI_session_accept *ti_session_accept; TI_session_upflags *ti_session_upflags; TI_session_errmsg *ti_session_errmsg; TI_session_dn *ti_session_my_dn; TI_session_dn *ti_session_peer_dn; TI_session_chkhost *ti_session_chkhost; TI_session_strength *ti_session_strength; TI_session_unique *ti_session_unique; TI_session_endpoint *ti_session_endpoint; TI_session_name *ti_session_version; TI_session_name *ti_session_cipher; TI_session_peercert *ti_session_peercert; TI_session_pinning *ti_session_pinning; Sockbuf_IO *ti_sbio; TI_thr_init *ti_thr_init; int ti_inited; } tls_impl; extern tls_impl ldap_int_tls_impl; #endif /* _LDAP_TLS_H */ openldap-2.5.11+dfsg/libraries/libldap/test.c0000644000175000017500000004571614172327167017562 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_FILE_H #include #endif #ifdef HAVE_IO_H #include #endif #include /* including the "internal" defs is legit and nec. since this test routine has * a-priori knowledge of libldap internal workings. * hodges@stanford.edu 5-Feb-96 */ #include "ldap-int.h" /* local functions */ static char *get_line LDAP_P(( char *line, int len, FILE *fp, const char *prompt )); static char **get_list LDAP_P(( const char *prompt )); static int file_read LDAP_P(( const char *path, struct berval *bv )); static LDAPMod **get_modlist LDAP_P(( const char *prompt1, const char *prompt2, const char *prompt3 )); static void handle_result LDAP_P(( LDAP *ld, LDAPMessage *lm )); static void print_ldap_result LDAP_P(( LDAP *ld, LDAPMessage *lm, const char *s )); static void print_search_entry LDAP_P(( LDAP *ld, LDAPMessage *res )); static void free_list LDAP_P(( char **list )); static char *dnsuffix; static char * get_line( char *line, int len, FILE *fp, const char *prompt ) { fputs(prompt, stdout); if ( fgets( line, len, fp ) == NULL ) return( NULL ); line[ strlen( line ) - 1 ] = '\0'; return( line ); } static char ** get_list( const char *prompt ) { static char buf[256]; int num; char **result; num = 0; result = (char **) 0; while ( 1 ) { get_line( buf, sizeof(buf), stdin, prompt ); if ( *buf == '\0' ) break; if ( result == (char **) 0 ) result = (char **) malloc( sizeof(char *) ); else result = (char **) realloc( result, sizeof(char *) * (num + 1) ); result[num++] = (char *) strdup( buf ); } if ( result == (char **) 0 ) return( NULL ); result = (char **) realloc( result, sizeof(char *) * (num + 1) ); result[num] = NULL; return( result ); } static void free_list( char **list ) { int i; if ( list != NULL ) { for ( i = 0; list[ i ] != NULL; ++i ) { free( list[ i ] ); } free( (char *)list ); } } static int file_read( const char *path, struct berval *bv ) { FILE *fp; ber_slen_t rlen; int eof; if (( fp = fopen( path, "r" )) == NULL ) { perror( path ); return( -1 ); } if ( fseek( fp, 0L, SEEK_END ) != 0 ) { perror( path ); fclose( fp ); return( -1 ); } bv->bv_len = ftell( fp ); if (( bv->bv_val = (char *)malloc( bv->bv_len )) == NULL ) { perror( "malloc" ); fclose( fp ); return( -1 ); } if ( fseek( fp, 0L, SEEK_SET ) != 0 ) { perror( path ); fclose( fp ); return( -1 ); } rlen = fread( bv->bv_val, 1, bv->bv_len, fp ); eof = feof( fp ); fclose( fp ); if ( (ber_len_t) rlen != bv->bv_len ) { perror( path ); free( bv->bv_val ); return( -1 ); } return( bv->bv_len ); } static LDAPMod ** get_modlist( const char *prompt1, const char *prompt2, const char *prompt3 ) { static char buf[256]; int num; LDAPMod tmp = { 0 }; LDAPMod **result; struct berval **bvals; num = 0; result = NULL; while ( 1 ) { if ( prompt1 ) { get_line( buf, sizeof(buf), stdin, prompt1 ); tmp.mod_op = atoi( buf ); if ( tmp.mod_op == -1 || buf[0] == '\0' ) break; } get_line( buf, sizeof(buf), stdin, prompt2 ); if ( buf[0] == '\0' ) break; tmp.mod_type = strdup( buf ); tmp.mod_values = get_list( prompt3 ); if ( tmp.mod_values != NULL ) { int i; for ( i = 0; tmp.mod_values[i] != NULL; ++i ) ; bvals = (struct berval **)calloc( i + 1, sizeof( struct berval *)); for ( i = 0; tmp.mod_values[i] != NULL; ++i ) { bvals[i] = (struct berval *)malloc( sizeof( struct berval )); if ( strncmp( tmp.mod_values[i], "{FILE}", 6 ) == 0 ) { if ( file_read( tmp.mod_values[i] + 6, bvals[i] ) < 0 ) { free( bvals ); for ( i = 0; ibv_val = tmp.mod_values[i]; bvals[i]->bv_len = strlen( tmp.mod_values[i] ); } } tmp.mod_bvalues = bvals; tmp.mod_op |= LDAP_MOD_BVALUES; } if ( result == NULL ) result = (LDAPMod **) malloc( sizeof(LDAPMod *) ); else result = (LDAPMod **) realloc( result, sizeof(LDAPMod *) * (num + 1) ); result[num] = (LDAPMod *) malloc( sizeof(LDAPMod) ); *(result[num]) = tmp; /* struct copy */ num++; } if ( result == NULL ) return( NULL ); result = (LDAPMod **) realloc( result, sizeof(LDAPMod *) * (num + 1) ); result[num] = NULL; return( result ); } static int bind_prompt( LDAP *ld, LDAP_CONST char *url, ber_tag_t request, ber_int_t msgid, void *params ) { static char dn[256], passwd[256]; int authmethod; printf("rebind for request=%ld msgid=%ld url=%s\n", request, (long) msgid, url ); authmethod = LDAP_AUTH_SIMPLE; get_line( dn, sizeof(dn), stdin, "re-bind dn? " ); strcat( dn, dnsuffix ); if ( authmethod == LDAP_AUTH_SIMPLE && dn[0] != '\0' ) { get_line( passwd, sizeof(passwd), stdin, "re-bind password? " ); } else { passwd[0] = '\0'; } return ldap_bind_s( ld, dn, passwd, authmethod); } int main( int argc, char **argv ) { LDAP *ld = NULL; int i, c, port, errflg, method, id, msgtype; char line[256], command1, command2, command3; char passwd[64], dn[256], rdn[64], attr[64], value[256]; char filter[256], *host, **types; char **exdn; static const char usage[] = "usage: %s [-u] [-h host] [-d level] [-s dnsuffix] [-p port] [-t file] [-T file]\n"; int bound, all, scope, attrsonly; LDAPMessage *res; LDAPMod **mods, **attrs; struct timeval timeout; char *copyfname = NULL; int copyoptions = 0; LDAPURLDesc *ludp; host = NULL; port = LDAP_PORT; dnsuffix = ""; errflg = 0; while (( c = getopt( argc, argv, "h:d:s:p:t:T:" )) != -1 ) { switch( c ) { case 'd': #ifdef LDAP_DEBUG ldap_debug = atoi( optarg ); #ifdef LBER_DEBUG if ( ldap_debug & LDAP_DEBUG_PACKETS ) { ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &ldap_debug ); } #endif #else printf( "Compile with -DLDAP_DEBUG for debugging\n" ); #endif break; case 'h': host = optarg; break; case 's': dnsuffix = optarg; break; case 'p': port = atoi( optarg ); break; case 't': /* copy ber's to given file */ copyfname = optarg; /* copyoptions = LBER_TO_FILE; */ break; case 'T': /* only output ber's to given file */ copyfname = optarg; /* copyoptions = (LBER_TO_FILE | LBER_TO_FILE_ONLY); */ break; default: ++errflg; } } if ( host == NULL && optind == argc - 1 ) { host = argv[ optind ]; ++optind; } if ( errflg || optind < argc - 1 ) { fprintf( stderr, usage, argv[ 0 ] ); exit( EXIT_FAILURE ); } printf( "ldap_init( %s, %d )\n", host == NULL ? "(null)" : host, port ); ld = ldap_init( host, port ); if ( ld == NULL ) { perror( "ldap_init" ); exit( EXIT_FAILURE ); } if ( copyfname != NULL ) { if ( ( ld->ld_sb->sb_fd = open( copyfname, O_WRONLY|O_CREAT|O_EXCL, 0600 )) == -1 ) { perror( copyfname ); exit ( EXIT_FAILURE ); } ld->ld_sb->sb_options = copyoptions; } bound = 0; timeout.tv_sec = 0; timeout.tv_usec = 0; (void) memset( line, '\0', sizeof(line) ); while ( get_line( line, sizeof(line), stdin, "\ncommand? " ) != NULL ) { command1 = line[0]; command2 = line[1]; command3 = line[2]; switch ( command1 ) { case 'a': /* add or abandon */ switch ( command2 ) { case 'd': /* add */ get_line( dn, sizeof(dn), stdin, "dn? " ); strcat( dn, dnsuffix ); if ( (attrs = get_modlist( NULL, "attr? ", "value? " )) == NULL ) break; if ( (id = ldap_add( ld, dn, attrs )) == -1 ) ldap_perror( ld, "ldap_add" ); else printf( "Add initiated with id %d\n", id ); break; case 'b': /* abandon */ get_line( line, sizeof(line), stdin, "msgid? " ); id = atoi( line ); if ( ldap_abandon( ld, id ) != 0 ) ldap_perror( ld, "ldap_abandon" ); else printf( "Abandon successful\n" ); break; default: printf( "Possibilities: [ad]d, [ab]ort\n" ); } break; case 'b': /* async bind */ method = LDAP_AUTH_SIMPLE; get_line( dn, sizeof(dn), stdin, "dn? " ); strcat( dn, dnsuffix ); if ( method == LDAP_AUTH_SIMPLE && dn[0] != '\0' ) get_line( passwd, sizeof(passwd), stdin, "password? " ); else passwd[0] = '\0'; if ( ldap_bind( ld, dn, passwd, method ) == -1 ) { fprintf( stderr, "ldap_bind failed\n" ); ldap_perror( ld, "ldap_bind" ); } else { printf( "Bind initiated\n" ); bound = 1; } break; case 'B': /* synch bind */ method = LDAP_AUTH_SIMPLE; get_line( dn, sizeof(dn), stdin, "dn? " ); strcat( dn, dnsuffix ); if ( dn[0] != '\0' ) get_line( passwd, sizeof(passwd), stdin, "password? " ); else passwd[0] = '\0'; if ( ldap_bind_s( ld, dn, passwd, method ) != LDAP_SUCCESS ) { fprintf( stderr, "ldap_bind_s failed\n" ); ldap_perror( ld, "ldap_bind_s" ); } else { printf( "Bind successful\n" ); bound = 1; } break; case 'c': /* compare */ get_line( dn, sizeof(dn), stdin, "dn? " ); strcat( dn, dnsuffix ); get_line( attr, sizeof(attr), stdin, "attr? " ); get_line( value, sizeof(value), stdin, "value? " ); if ( (id = ldap_compare( ld, dn, attr, value )) == -1 ) ldap_perror( ld, "ldap_compare" ); else printf( "Compare initiated with id %d\n", id ); break; case 'd': /* turn on debugging */ #ifdef LDAP_DEBUG get_line( line, sizeof(line), stdin, "debug level? " ); ldap_debug = atoi( line ); #ifdef LBER_DEBUG if ( ldap_debug & LDAP_DEBUG_PACKETS ) { ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &ldap_debug ); } #endif #else printf( "Compile with -DLDAP_DEBUG for debugging\n" ); #endif break; case 'E': /* explode a dn */ get_line( line, sizeof(line), stdin, "dn? " ); exdn = ldap_explode_dn( line, 0 ); for ( i = 0; exdn != NULL && exdn[i] != NULL; i++ ) { printf( "\t%s\n", exdn[i] ); } break; case 'g': /* set next msgid */ get_line( line, sizeof(line), stdin, "msgid? " ); ld->ld_msgid = atoi( line ); break; case 'v': /* set version number */ get_line( line, sizeof(line), stdin, "version? " ); ld->ld_version = atoi( line ); break; case 'm': /* modify or modifyrdn */ if ( strncmp( line, "modify", 4 ) == 0 ) { get_line( dn, sizeof(dn), stdin, "dn? " ); strcat( dn, dnsuffix ); if ( (mods = get_modlist( "mod (0=>add, 1=>delete, 2=>replace -1=>done)? ", "attribute type? ", "attribute value? " )) == NULL ) break; if ( (id = ldap_modify( ld, dn, mods )) == -1 ) ldap_perror( ld, "ldap_modify" ); else printf( "Modify initiated with id %d\n", id ); } else if ( strncmp( line, "modrdn", 4 ) == 0 ) { get_line( dn, sizeof(dn), stdin, "dn? " ); strcat( dn, dnsuffix ); get_line( rdn, sizeof(rdn), stdin, "newrdn? " ); if ( (id = ldap_modrdn( ld, dn, rdn )) == -1 ) ldap_perror( ld, "ldap_modrdn" ); else printf( "Modrdn initiated with id %d\n", id ); } else { printf( "Possibilities: [modi]fy, [modr]dn\n" ); } break; case 'q': /* quit */ ldap_unbind( ld ); exit( EXIT_SUCCESS ); break; case 'r': /* result or remove */ switch ( command3 ) { case 's': /* result */ get_line( line, sizeof(line), stdin, "msgid (-1=>any)? " ); if ( line[0] == '\0' ) id = -1; else id = atoi( line ); get_line( line, sizeof(line), stdin, "all (0=>any, 1=>all)? " ); if ( line[0] == '\0' ) all = 1; else all = atoi( line ); if (( msgtype = ldap_result( ld, id, all, &timeout, &res )) < 1 ) { ldap_perror( ld, "ldap_result" ); break; } printf( "\nresult: msgtype %d msgid %d\n", msgtype, res->lm_msgid ); handle_result( ld, res ); res = NULL; break; case 'm': /* remove */ get_line( dn, sizeof(dn), stdin, "dn? " ); strcat( dn, dnsuffix ); if ( (id = ldap_delete( ld, dn )) == -1 ) ldap_perror( ld, "ldap_delete" ); else printf( "Remove initiated with id %d\n", id ); break; default: printf( "Possibilities: [rem]ove, [res]ult\n" ); break; } break; case 's': /* search */ get_line( dn, sizeof(dn), stdin, "searchbase? " ); strcat( dn, dnsuffix ); get_line( line, sizeof(line), stdin, "scope (0=baseObject, 1=oneLevel, 2=subtree, 3=children)? " ); scope = atoi( line ); get_line( filter, sizeof(filter), stdin, "search filter (e.g. sn=jones)? " ); types = get_list( "attrs to return? " ); get_line( line, sizeof(line), stdin, "attrsonly (0=attrs&values, 1=attrs only)? " ); attrsonly = atoi( line ); if (( id = ldap_search( ld, dn, scope, filter, types, attrsonly )) == -1 ) { ldap_perror( ld, "ldap_search" ); } else { printf( "Search initiated with id %d\n", id ); } free_list( types ); break; case 't': /* set timeout value */ get_line( line, sizeof(line), stdin, "timeout? " ); timeout.tv_sec = atoi( line ); break; case 'p': /* parse LDAP URL */ get_line( line, sizeof(line), stdin, "LDAP URL? " ); if (( i = ldap_url_parse( line, &ludp )) != 0 ) { fprintf( stderr, "ldap_url_parse: error %d\n", i ); } else { printf( "\t host: " ); if ( ludp->lud_host == NULL ) { printf( "DEFAULT\n" ); } else { printf( "<%s>\n", ludp->lud_host ); } printf( "\t port: " ); if ( ludp->lud_port == 0 ) { printf( "DEFAULT\n" ); } else { printf( "%d\n", ludp->lud_port ); } printf( "\t dn: <%s>\n", ludp->lud_dn ); printf( "\t attrs:" ); if ( ludp->lud_attrs == NULL ) { printf( " ALL" ); } else { for ( i = 0; ludp->lud_attrs[ i ] != NULL; ++i ) { printf( " <%s>", ludp->lud_attrs[ i ] ); } } printf( "\n\t scope: %s\n", ludp->lud_scope == LDAP_SCOPE_BASE ? "baseObject" : ludp->lud_scope == LDAP_SCOPE_ONELEVEL ? "oneLevel" : ludp->lud_scope == LDAP_SCOPE_SUBTREE ? "subtree" #ifdef LDAP_SCOPE_SUBORDINATE : ludp->lud_scope == LDAP_SCOPE_SUBORDINATE ? "children" #endif : "**invalid**" ); printf( "\tfilter: <%s>\n", ludp->lud_filter ); ldap_free_urldesc( ludp ); } break; case 'n': /* set dn suffix, for convenience */ get_line( line, sizeof(line), stdin, "DN suffix? " ); strcpy( dnsuffix, line ); break; case 'o': /* set ldap options */ get_line( line, sizeof(line), stdin, "alias deref (0=never, 1=searching, 2=finding, 3=always)?" ); ld->ld_deref = atoi( line ); get_line( line, sizeof(line), stdin, "timelimit?" ); ld->ld_timelimit = atoi( line ); get_line( line, sizeof(line), stdin, "sizelimit?" ); ld->ld_sizelimit = atoi( line ); LDAP_BOOL_ZERO(&ld->ld_options); get_line( line, sizeof(line), stdin, "Recognize and chase referrals (0=no, 1=yes)?" ); if ( atoi( line ) != 0 ) { LDAP_BOOL_SET(&ld->ld_options, LDAP_BOOL_REFERRALS); get_line( line, sizeof(line), stdin, "Prompt for bind credentials when chasing referrals (0=no, 1=yes)?" ); if ( atoi( line ) != 0 ) { ldap_set_rebind_proc( ld, bind_prompt, NULL ); } } break; case '?': /* help */ printf( "Commands: [ad]d [ab]andon [b]ind\n" " [B]ind async [c]ompare\n" " [modi]fy [modr]dn [rem]ove\n" " [res]ult [s]earch [q]uit/unbind\n\n" " [d]ebug set ms[g]id\n" " d[n]suffix [t]imeout [v]ersion\n" " [?]help [o]ptions" " [E]xplode dn [p]arse LDAP URL\n" ); break; default: printf( "Invalid command. Type ? for help.\n" ); break; } (void) memset( line, '\0', sizeof(line) ); } return( 0 ); } static void handle_result( LDAP *ld, LDAPMessage *lm ) { switch ( lm->lm_msgtype ) { case LDAP_RES_COMPARE: printf( "Compare result\n" ); print_ldap_result( ld, lm, "compare" ); break; case LDAP_RES_SEARCH_RESULT: printf( "Search result\n" ); print_ldap_result( ld, lm, "search" ); break; case LDAP_RES_SEARCH_ENTRY: printf( "Search entry\n" ); print_search_entry( ld, lm ); break; case LDAP_RES_ADD: printf( "Add result\n" ); print_ldap_result( ld, lm, "add" ); break; case LDAP_RES_DELETE: printf( "Delete result\n" ); print_ldap_result( ld, lm, "delete" ); break; case LDAP_RES_MODRDN: printf( "ModRDN result\n" ); print_ldap_result( ld, lm, "modrdn" ); break; case LDAP_RES_BIND: printf( "Bind result\n" ); print_ldap_result( ld, lm, "bind" ); break; default: printf( "Unknown result type 0x%lx\n", (unsigned long) lm->lm_msgtype ); print_ldap_result( ld, lm, "unknown" ); } } static void print_ldap_result( LDAP *ld, LDAPMessage *lm, const char *s ) { ldap_result2error( ld, lm, 1 ); ldap_perror( ld, s ); /* if ( ld->ld_error != NULL && *ld->ld_error != '\0' ) fprintf( stderr, "Additional info: %s\n", ld->ld_error ); if ( LDAP_NAME_ERROR( ld->ld_errno ) && ld->ld_matched != NULL ) fprintf( stderr, "Matched DN: %s\n", ld->ld_matched ); */ } static void print_search_entry( LDAP *ld, LDAPMessage *res ) { LDAPMessage *e; for ( e = ldap_first_entry( ld, res ); e != NULL; e = ldap_next_entry( ld, e ) ) { BerElement *ber = NULL; char *a, *dn, *ufn; if ( e->lm_msgtype == LDAP_RES_SEARCH_RESULT ) break; dn = ldap_get_dn( ld, e ); printf( "\tDN: %s\n", dn ); ufn = ldap_dn2ufn( dn ); printf( "\tUFN: %s\n", ufn ); free( dn ); free( ufn ); for ( a = ldap_first_attribute( ld, e, &ber ); a != NULL; a = ldap_next_attribute( ld, e, ber ) ) { struct berval **vals; printf( "\t\tATTR: %s\n", a ); if ( (vals = ldap_get_values_len( ld, e, a )) == NULL ) { printf( "\t\t\t(no values)\n" ); } else { int i; for ( i = 0; vals[i] != NULL; i++ ) { int j, nonascii; nonascii = 0; for ( j = 0; (ber_len_t) j < vals[i]->bv_len; j++ ) if ( !isascii( vals[i]->bv_val[j] ) ) { nonascii = 1; break; } if ( nonascii ) { printf( "\t\t\tlength (%ld) (not ascii)\n", vals[i]->bv_len ); #ifdef BPRINT_NONASCII ber_bprint( vals[i]->bv_val, vals[i]->bv_len ); #endif /* BPRINT_NONASCII */ continue; } printf( "\t\t\tlength (%ld) %s\n", vals[i]->bv_len, vals[i]->bv_val ); } ber_bvecfree( vals ); } } if(ber != NULL) { ber_free( ber, 0 ); } } if ( res->lm_msgtype == LDAP_RES_SEARCH_RESULT || res->lm_chain != NULL ) print_ldap_result( ld, res, "search" ); } openldap-2.5.11+dfsg/libraries/libldap/ldap.conf0000644000175000017500000000036714172327167020217 0ustar ryanryan# # LDAP Defaults # # See ldap.conf(5) for details # This file should be world readable but not world writable. #BASE dc=example,dc=com #URI ldap://ldap.example.com ldap://ldap-provider.example.com:666 #SIZELIMIT 12 #TIMELIMIT 15 #DEREF never openldap-2.5.11+dfsg/libraries/libldap/dnssrv.c0000644000175000017500000002206014172327167020105 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* * locate LDAP servers using DNS SRV records. * Location code based on MIT Kerberos KDC location code. */ #include "portable.h" #include #include #include #include #include #include #include "ldap-int.h" #ifdef HAVE_ARPA_NAMESER_H #include #endif #ifdef HAVE_RESOLV_H #include #endif int ldap_dn2domain( LDAP_CONST char *dn_in, char **domainp) { int i, j; char *ndomain; LDAPDN dn = NULL; LDAPRDN rdn = NULL; LDAPAVA *ava = NULL; struct berval domain = BER_BVNULL; static const struct berval DC = BER_BVC("DC"); static const struct berval DCOID = BER_BVC("0.9.2342.19200300.100.1.25"); assert( dn_in != NULL ); assert( domainp != NULL ); *domainp = NULL; if ( ldap_str2dn( dn_in, &dn, LDAP_DN_FORMAT_LDAP ) != LDAP_SUCCESS ) { return -2; } if( dn ) for( i=0; dn[i] != NULL; i++ ) { rdn = dn[i]; for( j=0; rdn[j] != NULL; j++ ) { ava = rdn[j]; if( rdn[j+1] == NULL && (ava->la_flags & LDAP_AVA_STRING) && ava->la_value.bv_len && ( ber_bvstrcasecmp( &ava->la_attr, &DC ) == 0 || ber_bvcmp( &ava->la_attr, &DCOID ) == 0 ) ) { if( domain.bv_len == 0 ) { ndomain = LDAP_REALLOC( domain.bv_val, ava->la_value.bv_len + 1); if( ndomain == NULL ) { goto return_error; } domain.bv_val = ndomain; AC_MEMCPY( domain.bv_val, ava->la_value.bv_val, ava->la_value.bv_len ); domain.bv_len = ava->la_value.bv_len; domain.bv_val[domain.bv_len] = '\0'; } else { ndomain = LDAP_REALLOC( domain.bv_val, ava->la_value.bv_len + sizeof(".") + domain.bv_len ); if( ndomain == NULL ) { goto return_error; } domain.bv_val = ndomain; domain.bv_val[domain.bv_len++] = '.'; AC_MEMCPY( &domain.bv_val[domain.bv_len], ava->la_value.bv_val, ava->la_value.bv_len ); domain.bv_len += ava->la_value.bv_len; domain.bv_val[domain.bv_len] = '\0'; } } else { domain.bv_len = 0; } } } if( domain.bv_len == 0 && domain.bv_val != NULL ) { LDAP_FREE( domain.bv_val ); domain.bv_val = NULL; } ldap_dnfree( dn ); *domainp = domain.bv_val; return 0; return_error: ldap_dnfree( dn ); LDAP_FREE( domain.bv_val ); return -1; } int ldap_domain2dn( LDAP_CONST char *domain_in, char **dnp) { char *domain, *s, *tok_r, *dn, *dntmp; size_t loc; assert( domain_in != NULL ); assert( dnp != NULL ); domain = LDAP_STRDUP(domain_in); if (domain == NULL) { return LDAP_NO_MEMORY; } dn = NULL; loc = 0; for (s = ldap_pvt_strtok(domain, ".", &tok_r); s != NULL; s = ldap_pvt_strtok(NULL, ".", &tok_r)) { size_t len = strlen(s); dntmp = (char *) LDAP_REALLOC(dn, loc + sizeof(",dc=") + len ); if (dntmp == NULL) { if (dn != NULL) LDAP_FREE(dn); LDAP_FREE(domain); return LDAP_NO_MEMORY; } dn = dntmp; if (loc > 0) { /* not first time. */ strcpy(dn + loc, ","); loc++; } strcpy(dn + loc, "dc="); loc += sizeof("dc=")-1; strcpy(dn + loc, s); loc += len; } LDAP_FREE(domain); *dnp = dn; return LDAP_SUCCESS; } #ifdef HAVE_RES_QUERY #define DNSBUFSIZ (64*1024) #define MAXHOST 254 /* RFC 1034, max length is 253 chars */ typedef struct srv_record { u_short priority; u_short weight; u_short port; char hostname[MAXHOST]; } srv_record; /* Linear Congruential Generator - we don't need * high quality randomness, and we don't want to * interfere with anyone else's use of srand(). * * The PRNG here cycles thru 941,955 numbers. */ static float srv_seed; static void srv_srand(int seed) { srv_seed = (float)seed / (float)RAND_MAX; } static float srv_rand() { float val = 9821.0 * srv_seed + .211327; srv_seed = val - (int)val; return srv_seed; } static int srv_cmp(const void *aa, const void *bb){ srv_record *a=(srv_record *)aa; srv_record *b=(srv_record *)bb; int i = a->priority - b->priority; if (i) return i; return b->weight - a->weight; } static void srv_shuffle(srv_record *a, int n) { int i, j, total = 0, r, p; for (i=0; i1; a++, p--) { if (!total) { /* all remaining weights are zero, do a straight Fisher-Yates shuffle */ j = srv_rand() * p; } else { r = srv_rand() * total; for (j=0; j= 0) { unsigned char *p; char host[DNSBUFSIZ]; int status; u_short port, priority, weight; /* Parse out query */ p = reply; #ifdef NS_HFIXEDSZ /* Bind 8/9 interface */ p += NS_HFIXEDSZ; #elif defined(HFIXEDSZ) /* Bind 4 interface w/ HFIXEDSZ */ p += HFIXEDSZ; #else /* Bind 4 interface w/o HFIXEDSZ */ p += sizeof(HEADER); #endif status = dn_expand(reply, reply + len, p, host, sizeof(host)); if (status < 0) { goto out; } p += status; p += 4; while (p < reply + len) { int type, class, ttl, size; status = dn_expand(reply, reply + len, p, host, sizeof(host)); if (status < 0) { goto out; } p += status; type = (p[0] << 8) | p[1]; p += 2; class = (p[0] << 8) | p[1]; p += 2; ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; p += 4; size = (p[0] << 8) | p[1]; p += 2; if (type == T_SRV) { status = dn_expand(reply, reply + len, p + 6, host, sizeof(host)); if (status < 0) { goto out; } /* Get priority weight and port */ priority = (p[0] << 8) | p[1]; weight = (p[2] << 8) | p[3]; port = (p[4] << 8) | p[5]; if ( port == 0 || host[ 0 ] == '\0' ) { goto add_size; } hostent_head = (srv_record *) LDAP_REALLOC(hostent_head, (hostent_count+1)*(sizeof(srv_record))); if(hostent_head==NULL){ rc=LDAP_NO_MEMORY; goto out; } hostent_head[hostent_count].priority=priority; hostent_head[hostent_count].weight=weight; hostent_head[hostent_count].port=port; strncpy(hostent_head[hostent_count].hostname, host, MAXHOST-1); hostent_head[hostent_count].hostname[MAXHOST-1] = '\0'; hostent_count++; } add_size:; p += size; } if (!hostent_head) goto out; qsort(hostent_head, hostent_count, sizeof(srv_record), srv_cmp); if (!srv_seed) srv_srand(time(0L)); /* shuffle records of same priority */ j = 0; priority = hostent_head[0].priority; for (i=1; i 1) srv_shuffle(hostent_head+j, i-j); j = i; } } if (i-j > 1) srv_shuffle(hostent_head+j, i-j); for(i=0; i0){ hostlist[cur++]=' '; } cur += sprintf(&hostlist[cur], "%s:%hu", hostent_head[i].hostname, hostent_head[i].port); } } if (hostlist == NULL) { /* No LDAP servers found in DNS. */ rc = LDAP_UNAVAILABLE; goto out; } rc = LDAP_SUCCESS; *list = hostlist; out: LDAP_MUTEX_UNLOCK(&ldap_int_resolv_mutex); if (request != NULL) { LDAP_FREE(request); } if (hostent_head != NULL) { LDAP_FREE(hostent_head); } if (rc != LDAP_SUCCESS && hostlist != NULL) { LDAP_FREE(hostlist); } return rc; #else return LDAP_NOT_SUPPORTED; #endif /* HAVE_RES_QUERY */ } openldap-2.5.11+dfsg/libraries/libldap/ldap.pc.in0000644000175000017500000000052714172327167020277 0ustar ryanryanprefix=@prefix@ exec_prefix=@exec_prefix@ includedir=@includedir@ libdir=@libdir@ Name: ldap (@PACKAGE@) Description: OpenLDAP Lightweight Directory Access Protocol library URL: https://www.openldap.org Version: @VERSION@ Requires: lber Cflags: -I${includedir} Libs: -L${libdir} -lldap Libs.private: @LIBS@ @SASL_LIBS@ @TLS_LIBS@ @AUTH_LIBS@ openldap-2.5.11+dfsg/libraries/libldap/result.c0000644000175000017500000010660614172327167020115 0ustar ryanryan/* result.c - wait for an ldap result */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ /* This notice applies to changes, created by or for Novell, Inc., * to preexisting works for which notices appear elsewhere in this file. * * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved. * * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES. * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. *--- * Modification to OpenLDAP source by Novell, Inc. * April 2000 sfs Add code to process V3 referrals and search results *--- * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License * can be found in the file "build/LICENSE-2.0.1" in this distribution * of OpenLDAP Software. */ /* * LDAPv3 (RFC 4511) * LDAPResult ::= SEQUENCE { * resultCode ENUMERATED { ... }, * matchedDN LDAPDN, * diagnosticMessage LDAPString, * referral [3] Referral OPTIONAL * } * Referral ::= SEQUENCE OF LDAPURL (one or more) * LDAPURL ::= LDAPString (limited to URL chars) */ #include "portable.h" #include #include #include #include #include #include #include #include "ldap-int.h" #include "ldap_log.h" #include "lutil.h" static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid )); static int ldap_mark_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid )); static int wait4msg LDAP_P(( LDAP *ld, ber_int_t msgid, int all, struct timeval *timeout, LDAPMessage **result )); static ber_tag_t try_read1msg LDAP_P(( LDAP *ld, ber_int_t msgid, int all, LDAPConn *lc, LDAPMessage **result )); static ber_tag_t build_result_ber LDAP_P(( LDAP *ld, BerElement **bp, LDAPRequest *lr )); static void merge_error_info LDAP_P(( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )); static LDAPMessage * chkResponseList LDAP_P(( LDAP *ld, int msgid, int all)); #define LDAP_MSG_X_KEEP_LOOKING (-2) /* * ldap_result - wait for an ldap result response to a message from the * ldap server. If msgid is LDAP_RES_ANY (-1), any message will be * accepted. If msgid is LDAP_RES_UNSOLICITED (0), any unsolicited * message is accepted. Otherwise ldap_result will wait for a response * with msgid. If all is LDAP_MSG_ONE (0) the first message with id * msgid will be accepted, otherwise, ldap_result will wait for all * responses with id msgid and then return a pointer to the entire list * of messages. In general, this is only useful for search responses, * which can be of three message types (zero or more entries, zero or * search references, followed by an ldap result). An extension to * LDAPv3 allows partial extended responses to be returned in response * to any request. The type of the first message received is returned. * When waiting, any messages that have been abandoned/discarded are * discarded. * * Example: * ldap_result( s, msgid, all, timeout, result ) */ int ldap_result( LDAP *ld, int msgid, int all, struct timeval *timeout, LDAPMessage **result ) { int rc; assert( ld != NULL ); assert( result != NULL ); Debug2( LDAP_DEBUG_TRACE, "ldap_result ld %p msgid %d\n", (void *)ld, msgid ); if (ld->ld_errno == LDAP_LOCAL_ERROR || ld->ld_errno == LDAP_SERVER_DOWN) return -1; LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); rc = wait4msg( ld, msgid, all, timeout, result ); LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); return rc; } /* protected by res_mutex */ static LDAPMessage * chkResponseList( LDAP *ld, int msgid, int all) { LDAPMessage *lm, **lastlm, *nextlm; int cnt = 0; /* * Look through the list of responses we have received on * this association and see if the response we're interested in * is there. If it is, return it. If not, call wait4msg() to * wait until it arrives or timeout occurs. */ LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); Debug3( LDAP_DEBUG_TRACE, "ldap_chkResponseList ld %p msgid %d all %d\n", (void *)ld, msgid, all ); lastlm = &ld->ld_responses; for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) { nextlm = lm->lm_next; ++cnt; if ( ldap_abandoned( ld, lm->lm_msgid ) ) { Debug2( LDAP_DEBUG_ANY, "response list msg abandoned, " "msgid %d message type %s\n", lm->lm_msgid, ldap_int_msgtype2str( lm->lm_msgtype ) ); switch ( lm->lm_msgtype ) { case LDAP_RES_SEARCH_ENTRY: case LDAP_RES_SEARCH_REFERENCE: case LDAP_RES_INTERMEDIATE: break; default: /* there's no need to keep the id * in the abandoned list any longer */ ldap_mark_abandoned( ld, lm->lm_msgid ); break; } /* Remove this entry from list */ *lastlm = nextlm; ldap_msgfree( lm ); continue; } if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) { LDAPMessage *tmp; if ( all == LDAP_MSG_ONE || all == LDAP_MSG_RECEIVED || msgid == LDAP_RES_UNSOLICITED ) { break; } tmp = lm->lm_chain_tail; if ( tmp->lm_msgtype == LDAP_RES_SEARCH_ENTRY || tmp->lm_msgtype == LDAP_RES_SEARCH_REFERENCE || tmp->lm_msgtype == LDAP_RES_INTERMEDIATE ) { tmp = NULL; } if ( tmp == NULL ) { lm = NULL; } break; } lastlm = &lm->lm_next; } if ( lm != NULL ) { /* Found an entry, remove it from the list */ if ( all == LDAP_MSG_ONE && lm->lm_chain != NULL ) { *lastlm = lm->lm_chain; lm->lm_chain->lm_next = lm->lm_next; lm->lm_chain->lm_chain_tail = ( lm->lm_chain_tail != lm ) ? lm->lm_chain_tail : lm->lm_chain; lm->lm_chain = NULL; lm->lm_chain_tail = NULL; } else { *lastlm = lm->lm_next; } lm->lm_next = NULL; } #ifdef LDAP_DEBUG if ( lm == NULL) { Debug1( LDAP_DEBUG_TRACE, "ldap_chkResponseList returns ld %p NULL\n", (void *)ld ); } else { Debug3( LDAP_DEBUG_TRACE, "ldap_chkResponseList returns ld %p msgid %d, type 0x%02lx\n", (void *)ld, lm->lm_msgid, (unsigned long)lm->lm_msgtype ); } #endif return lm; } /* protected by res_mutex */ static int wait4msg( LDAP *ld, ber_int_t msgid, int all, struct timeval *timeout, LDAPMessage **result ) { int rc; struct timeval tv = { 0 }, tv0 = { 0 }, start_time_tv = { 0 }, *tvp = NULL; LDAPConn *lc; assert( ld != NULL ); assert( result != NULL ); LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); if ( timeout == NULL && ld->ld_options.ldo_tm_api.tv_sec >= 0 ) { tv = ld->ld_options.ldo_tm_api; timeout = &tv; } #ifdef LDAP_DEBUG if ( timeout == NULL ) { Debug2( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (infinite timeout)\n", (void *)ld, msgid ); } else { Debug3( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (timeout %ld usec)\n", (void *)ld, msgid, (long)timeout->tv_sec * 1000000 + timeout->tv_usec ); } #endif /* LDAP_DEBUG */ if ( timeout != NULL && timeout->tv_sec != -1 ) { tv0 = *timeout; tv = *timeout; tvp = &tv; #ifdef HAVE_GETTIMEOFDAY gettimeofday( &start_time_tv, NULL ); #else /* ! HAVE_GETTIMEOFDAY */ start_time_tv.tv_sec = time( NULL ); start_time_tv.tv_usec = 0; #endif /* ! HAVE_GETTIMEOFDAY */ } rc = LDAP_MSG_X_KEEP_LOOKING; while ( rc == LDAP_MSG_X_KEEP_LOOKING ) { #ifdef LDAP_DEBUG if ( ldap_debug & LDAP_DEBUG_TRACE ) { Debug3( LDAP_DEBUG_TRACE, "wait4msg continue ld %p msgid %d all %d\n", (void *)ld, msgid, all ); ldap_dump_connection( ld, ld->ld_conns, 1 ); LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); ldap_dump_requests_and_responses( ld ); LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); } #endif /* LDAP_DEBUG */ if ( ( *result = chkResponseList( ld, msgid, all ) ) != NULL ) { rc = (*result)->lm_msgtype; } else { int lc_ready = 0; LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) { if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) { lc_ready = 2; /* ready at ber level, not socket level */ break; } } if ( !lc_ready ) { int err; rc = ldap_int_select( ld, tvp ); if ( rc == -1 ) { err = sock_errno(); #ifdef LDAP_DEBUG Debug1( LDAP_DEBUG_TRACE, "ldap_int_select returned -1: errno %d\n", err ); #endif } if ( rc == 0 || ( rc == -1 && ( !LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART) || err != EINTR ) ) ) { ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN : LDAP_TIMEOUT); LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); return( rc ); } if ( rc == -1 ) { rc = LDAP_MSG_X_KEEP_LOOKING; /* select interrupted: loop */ } else { lc_ready = 1; } } if ( lc_ready ) { LDAPConn *lnext; int serviced = 0; rc = LDAP_MSG_X_KEEP_LOOKING; LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); if ( ld->ld_requests != NULL ) { TAvlnode *node = ldap_tavl_end( ld->ld_requests, TAVL_DIR_RIGHT ); LDAPRequest *lr; assert( node != NULL ); lr = node->avl_data; if ( lr->lr_status == LDAP_REQST_WRITING && ldap_is_write_ready( ld, lr->lr_conn->lconn_sb ) ) { serviced = 1; ldap_int_flush_request( ld, lr ); } } for ( lc = ld->ld_conns; rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL; lc = lnext ) { if ( lc->lconn_status == LDAP_CONNST_CONNECTED && ldap_is_read_ready( ld, lc->lconn_sb ) ) { serviced = 1; /* Don't let it get freed out from under us */ ++lc->lconn_refcnt; rc = try_read1msg( ld, msgid, all, lc, result ); lnext = lc->lconn_next; /* Only take locks if we're really freeing */ if ( lc->lconn_refcnt <= 1 ) { ldap_free_connection( ld, lc, 0, 1 ); } else { --lc->lconn_refcnt; } } else { lnext = lc->lconn_next; } } LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); /* Quit looping if no one handled any socket events */ if (!serviced && lc_ready == 1) rc = -1; } LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); } if ( rc == LDAP_MSG_X_KEEP_LOOKING && tvp != NULL ) { struct timeval curr_time_tv = { 0 }, delta_time_tv = { 0 }; #ifdef HAVE_GETTIMEOFDAY gettimeofday( &curr_time_tv, NULL ); #else /* ! HAVE_GETTIMEOFDAY */ curr_time_tv.tv_sec = time( NULL ); curr_time_tv.tv_usec = 0; #endif /* ! HAVE_GETTIMEOFDAY */ /* delta_time = tmp_time - start_time */ delta_time_tv.tv_sec = curr_time_tv.tv_sec - start_time_tv.tv_sec; delta_time_tv.tv_usec = curr_time_tv.tv_usec - start_time_tv.tv_usec; if ( delta_time_tv.tv_usec < 0 ) { delta_time_tv.tv_sec--; delta_time_tv.tv_usec += 1000000; } /* tv0 < delta_time ? */ if ( ( tv0.tv_sec < delta_time_tv.tv_sec ) || ( ( tv0.tv_sec == delta_time_tv.tv_sec ) && ( tv0.tv_usec < delta_time_tv.tv_usec ) ) ) { rc = 0; /* timed out */ ld->ld_errno = LDAP_TIMEOUT; break; } /* tv0 -= delta_time */ tv0.tv_sec -= delta_time_tv.tv_sec; tv0.tv_usec -= delta_time_tv.tv_usec; if ( tv0.tv_usec < 0 ) { tv0.tv_sec--; tv0.tv_usec += 1000000; } tv.tv_sec = tv0.tv_sec; tv.tv_usec = tv0.tv_usec; Debug3( LDAP_DEBUG_TRACE, "wait4msg ld %p %ld s %ld us to go\n", (void *)ld, (long) tv.tv_sec, (long) tv.tv_usec ); start_time_tv.tv_sec = curr_time_tv.tv_sec; start_time_tv.tv_usec = curr_time_tv.tv_usec; } } return( rc ); } /* protected by res_mutex, conn_mutex and req_mutex */ static ber_tag_t try_read1msg( LDAP *ld, ber_int_t msgid, int all, LDAPConn *lc, LDAPMessage **result ) { BerElement *ber; LDAPMessage *newmsg, *l, *prev; ber_int_t id; ber_tag_t tag; ber_len_t len; int foundit = 0; LDAPRequest *lr, *tmplr, dummy_lr = { 0 }; BerElement tmpber; int rc, refer_cnt, hadref, simple_request, err; ber_int_t lderr = -1; #ifdef LDAP_CONNECTIONLESS LDAPMessage *tmp = NULL, *chain_head = NULL; int moremsgs = 0, isv2 = 0; #endif assert( ld != NULL ); assert( lc != NULL ); LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); Debug3( LDAP_DEBUG_TRACE, "read1msg: ld %p msgid %d all %d\n", (void *)ld, msgid, all ); retry: if ( lc->lconn_ber == NULL ) { lc->lconn_ber = ldap_alloc_ber_with_options( ld ); if ( lc->lconn_ber == NULL ) { return -1; } } ber = lc->lconn_ber; assert( LBER_VALID (ber) ); /* get the next message */ sock_errset(0); #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP(ld) ) { struct sockaddr_storage from; if ( ber_int_sb_read( lc->lconn_sb, &from, sizeof(struct sockaddr_storage) ) < 0 ) goto fail; if ( ld->ld_options.ldo_version == LDAP_VERSION2 ) isv2 = 1; } nextresp3: #endif tag = ber_get_next( lc->lconn_sb, &len, ber ); switch ( tag ) { case LDAP_TAG_MESSAGE: /* * We read a complete message. * The connection should no longer need this ber. */ lc->lconn_ber = NULL; break; case LBER_DEFAULT: fail: err = sock_errno(); #ifdef LDAP_DEBUG Debug1( LDAP_DEBUG_CONNS, "ber_get_next failed, errno=%d.\n", err ); #endif if ( err == EWOULDBLOCK ) return LDAP_MSG_X_KEEP_LOOKING; if ( err == EAGAIN ) return LDAP_MSG_X_KEEP_LOOKING; ld->ld_errno = LDAP_SERVER_DOWN; if ( !LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_KEEPCONN )) { --lc->lconn_refcnt; } lc->lconn_status = 0; return -1; default: ld->ld_errno = LDAP_LOCAL_ERROR; return -1; } /* message id */ if ( ber_get_int( ber, &id ) == LBER_ERROR ) { ber_free( ber, 1 ); ld->ld_errno = LDAP_DECODING_ERROR; return( -1 ); } /* id == 0 iff unsolicited notification message (RFC 4511) */ /* id < 0 is invalid, just toss it. FIXME: should we disconnect? */ if ( id < 0 ) { goto retry_ber; } /* if it's been abandoned, toss it */ if ( id > 0 ) { if ( ldap_abandoned( ld, id ) ) { /* the message type */ tag = ber_peek_tag( ber, &len ); switch ( tag ) { case LDAP_RES_SEARCH_ENTRY: case LDAP_RES_SEARCH_REFERENCE: case LDAP_RES_INTERMEDIATE: case LBER_ERROR: break; default: /* there's no need to keep the id * in the abandoned list any longer */ ldap_mark_abandoned( ld, id ); break; } Debug3( LDAP_DEBUG_ANY, "abandoned/discarded ld %p msgid %d message type %s\n", (void *)ld, id, ldap_int_msgtype2str( tag ) ); retry_ber: ber_free( ber, 1 ); if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) { goto retry; } return( LDAP_MSG_X_KEEP_LOOKING ); /* continue looking */ } lr = ldap_find_request_by_msgid( ld, id ); if ( lr == NULL ) { const char *msg = "unknown"; /* the message type */ tag = ber_peek_tag( ber, &len ); switch ( tag ) { case LBER_ERROR: break; default: msg = ldap_int_msgtype2str( tag ); break; } Debug3( LDAP_DEBUG_ANY, "no request for response on ld %p msgid %d message type %s (tossing)\n", (void *)ld, id, msg ); goto retry_ber; } #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP(ld) && isv2 ) { ber_scanf(ber, "x{"); } nextresp2: ; #endif } /* the message type */ tag = ber_peek_tag( ber, &len ); if ( tag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 1 ); return( -1 ); } Debug3( LDAP_DEBUG_TRACE, "read1msg: ld %p msgid %d message type %s\n", (void *)ld, id, ldap_int_msgtype2str( tag ) ); if ( id == 0 ) { /* unsolicited notification message (RFC 4511) */ if ( tag != LDAP_RES_EXTENDED ) { /* toss it */ goto retry_ber; /* strictly speaking, it's an error; from RFC 4511: 4.4. Unsolicited Notification An unsolicited notification is an LDAPMessage sent from the server to the client that is not in response to any LDAPMessage received by the server. It is used to signal an extraordinary condition in the server or in the LDAP session between the client and the server. The notification is of an advisory nature, and the server will not expect any response to be returned from the client. The unsolicited notification is structured as an LDAPMessage in which the messageID is zero and protocolOp is set to the extendedResp choice using the ExtendedResponse type (See Section 4.12). The responseName field of the ExtendedResponse always contains an LDAPOID that is unique for this notification. * however, since unsolicited responses * are of advisory nature, better * toss it, right now */ #if 0 ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 1 ); return( -1 ); #endif } lr = &dummy_lr; } id = lr->lr_origid; refer_cnt = 0; hadref = simple_request = 0; rc = LDAP_MSG_X_KEEP_LOOKING; /* default is to keep looking (no response found) */ lr->lr_res_msgtype = tag; /* * Check for V3 search reference */ if ( tag == LDAP_RES_SEARCH_REFERENCE ) { if ( ld->ld_version > LDAP_VERSION2 ) { /* This is a V3 search reference */ if ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) || lr->lr_parent != NULL ) { char **refs = NULL; tmpber = *ber; /* Get the referral list */ if ( ber_scanf( &tmpber, "{v}", &refs ) == LBER_ERROR ) { rc = LDAP_DECODING_ERROR; } else { /* Note: refs array is freed by ldap_chase_v3referrals */ refer_cnt = ldap_chase_v3referrals( ld, lr, refs, 1, &lr->lr_res_error, &hadref ); if ( refer_cnt > 0 ) { /* successfully chased reference */ /* If haven't got end search, set chasing referrals */ if ( lr->lr_status != LDAP_REQST_COMPLETED ) { lr->lr_status = LDAP_REQST_CHASINGREFS; Debug1( LDAP_DEBUG_TRACE, "read1msg: search ref chased, " "mark request chasing refs, " "id = %d\n", lr->lr_msgid ); } } } } } } else if ( tag != LDAP_RES_SEARCH_ENTRY && tag != LDAP_RES_INTERMEDIATE ) { /* All results that just return a status, i.e. don't return data * go through the following code. This code also chases V2 referrals * and checks if all referrals have been chased. */ char *lr_res_error = NULL; tmpber = *ber; /* struct copy */ if ( ber_scanf( &tmpber, "{eAA", &lderr, &lr->lr_res_matched, &lr_res_error ) != LBER_ERROR ) { if ( lr_res_error != NULL ) { if ( lr->lr_res_error != NULL ) { (void)ldap_append_referral( ld, &lr->lr_res_error, lr_res_error ); LDAP_FREE( (char *)lr_res_error ); } else { lr->lr_res_error = lr_res_error; } lr_res_error = NULL; } /* Do we need to check for referrals? */ if ( tag != LDAP_RES_BIND && ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) || lr->lr_parent != NULL )) { char **refs = NULL; ber_len_t len; /* Check if V3 referral */ if ( ber_peek_tag( &tmpber, &len ) == LDAP_TAG_REFERRAL ) { if ( ld->ld_version > LDAP_VERSION2 ) { /* Get the referral list */ if ( ber_scanf( &tmpber, "{v}", &refs) == LBER_ERROR) { rc = LDAP_DECODING_ERROR; lr->lr_status = LDAP_REQST_COMPLETED; Debug2( LDAP_DEBUG_TRACE, "read1msg: referral decode error, " "mark request completed, ld %p msgid %d\n", (void *)ld, lr->lr_msgid ); } else { /* Chase the referral * refs array is freed by ldap_chase_v3referrals */ refer_cnt = ldap_chase_v3referrals( ld, lr, refs, 0, &lr->lr_res_error, &hadref ); lr->lr_status = LDAP_REQST_COMPLETED; Debug3( LDAP_DEBUG_TRACE, "read1msg: referral %s chased, " "mark request completed, ld %p msgid %d\n", refer_cnt > 0 ? "" : "not", (void *)ld, lr->lr_msgid); if ( refer_cnt < 0 ) { refer_cnt = 0; } } } } else { switch ( lderr ) { case LDAP_SUCCESS: case LDAP_COMPARE_TRUE: case LDAP_COMPARE_FALSE: break; default: if ( lr->lr_res_error == NULL ) { break; } /* pedantic, should never happen */ if ( lr->lr_res_error[ 0 ] == '\0' ) { LDAP_FREE( lr->lr_res_error ); lr->lr_res_error = NULL; break; } /* V2 referrals are in error string */ refer_cnt = ldap_chase_referrals( ld, lr, &lr->lr_res_error, -1, &hadref ); lr->lr_status = LDAP_REQST_COMPLETED; Debug1( LDAP_DEBUG_TRACE, "read1msg: V2 referral chased, " "mark request completed, id = %d\n", lr->lr_msgid ); break; } } } /* save errno, message, and matched string */ if ( !hadref || lr->lr_res_error == NULL ) { lr->lr_res_errno = lderr == LDAP_PARTIAL_RESULTS ? LDAP_SUCCESS : lderr; } else if ( ld->ld_errno != LDAP_SUCCESS ) { lr->lr_res_errno = ld->ld_errno; } else { lr->lr_res_errno = LDAP_PARTIAL_RESULTS; } } /* in any case, don't leave any lr_res_error 'round */ if ( lr_res_error ) { LDAP_FREE( lr_res_error ); } Debug2( LDAP_DEBUG_TRACE, "read1msg: ld %p %d new referrals\n", (void *)ld, refer_cnt ); if ( refer_cnt != 0 ) { /* chasing referrals */ ber_free( ber, 1 ); ber = NULL; if ( refer_cnt < 0 ) { ldap_return_request( ld, lr, 0 ); return( -1 ); /* fatal error */ } lr->lr_res_errno = LDAP_SUCCESS; /* successfully chased referral */ if ( lr->lr_res_matched ) { LDAP_FREE( lr->lr_res_matched ); lr->lr_res_matched = NULL; } } else { if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) { /* request without any referrals */ simple_request = ( hadref ? 0 : 1 ); } else { /* request with referrals or child request */ ber_free( ber, 1 ); ber = NULL; } lr->lr_status = LDAP_REQST_COMPLETED; /* declare this request done */ Debug2( LDAP_DEBUG_TRACE, "read1msg: mark request completed, ld %p msgid %d\n", (void *)ld, lr->lr_msgid ); tmplr = lr; while ( lr->lr_parent != NULL ) { merge_error_info( ld, lr->lr_parent, lr ); lr = lr->lr_parent; if ( --lr->lr_outrefcnt > 0 ) { break; /* not completely done yet */ } } /* ITS#6744: Original lr was refcounted when we retrieved it, * must release it now that we're working with the parent */ if ( tmplr->lr_parent ) { ldap_return_request( ld, tmplr, 0 ); } /* Check if all requests are finished, lr is now parent */ tmplr = lr; if ( tmplr->lr_status == LDAP_REQST_COMPLETED ) { for ( tmplr = lr->lr_child; tmplr != NULL; tmplr = tmplr->lr_refnext ) { if ( tmplr->lr_status != LDAP_REQST_COMPLETED ) break; } } /* This is the parent request if the request has referrals */ if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL && tmplr == NULL ) { id = lr->lr_msgid; tag = lr->lr_res_msgtype; Debug2( LDAP_DEBUG_TRACE, "request done: ld %p msgid %d\n", (void *)ld, id ); Debug3( LDAP_DEBUG_TRACE, "res_errno: %d, res_error: <%s>, " "res_matched: <%s>\n", lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "", lr->lr_res_matched ? lr->lr_res_matched : "" ); if ( !simple_request ) { ber_free( ber, 1 ); ber = NULL; if ( build_result_ber( ld, &ber, lr ) == LBER_ERROR ) { rc = -1; /* fatal error */ } } if ( lr != &dummy_lr ) { ldap_return_request( ld, lr, 1 ); } lr = NULL; } /* * RFC 4511 unsolicited (id == 0) responses * shouldn't necessarily end the connection */ if ( lc != NULL && id != 0 && !LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_KEEPCONN )) { --lc->lconn_refcnt; lc = NULL; } } } if ( lr != NULL ) { if ( lr != &dummy_lr ) { ldap_return_request( ld, lr, 0 ); } lr = NULL; } if ( ber == NULL ) { return( rc ); } /* try to handle unsolicited responses as appropriate */ if ( id == 0 && msgid > LDAP_RES_UNSOLICITED ) { int is_nod = 0; tag = ber_peek_tag( &tmpber, &len ); /* we have a res oid */ if ( tag == LDAP_TAG_EXOP_RES_OID ) { static struct berval bv_nod = BER_BVC( LDAP_NOTICE_OF_DISCONNECTION ); struct berval resoid = BER_BVNULL; if ( ber_scanf( &tmpber, "m", &resoid ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 1 ); return -1; } assert( !BER_BVISEMPTY( &resoid ) ); is_nod = ber_bvcmp( &resoid, &bv_nod ) == 0; tag = ber_peek_tag( &tmpber, &len ); } #if 0 /* don't need right now */ /* we have res data */ if ( tag == LDAP_TAG_EXOP_RES_VALUE ) { struct berval resdata; if ( ber_scanf( &tmpber, "m", &resdata ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 0 ); return ld->ld_errno; } /* use it... */ } #endif /* handle RFC 4511 "Notice of Disconnection" locally */ if ( is_nod ) { if ( tag == LDAP_TAG_EXOP_RES_VALUE ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 1 ); return -1; } /* get rid of the connection... */ if ( lc != NULL && !LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_KEEPCONN )) { --lc->lconn_refcnt; } /* need to return -1, because otherwise * a valid result is expected */ ld->ld_errno = lderr; return -1; } } /* make a new ldap message */ newmsg = (LDAPMessage *) LDAP_CALLOC( 1, sizeof(LDAPMessage) ); if ( newmsg == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return( -1 ); } newmsg->lm_msgid = (int)id; newmsg->lm_msgtype = tag; newmsg->lm_ber = ber; newmsg->lm_chain_tail = newmsg; #ifdef LDAP_CONNECTIONLESS /* CLDAP replies all fit in a single datagram. In LDAPv2 RFC1798 * the responses are all a sequence wrapped in one message. In * LDAPv3 each response is in its own message. The datagram must * end with a SearchResult. We can't just parse each response in * separate calls to try_read1msg because the header info is only * present at the beginning of the datagram, not at the beginning * of each response. So parse all the responses at once and queue * them up, then pull off the first response to return to the * caller when all parsing is complete. */ if ( LDAP_IS_UDP(ld) ) { /* If not a result, look for more */ if ( tag != LDAP_RES_SEARCH_RESULT ) { int ok = 0; moremsgs = 1; if (isv2) { /* LDAPv2: dup the current ber, skip past the current * response, and see if there are any more after it. */ ber = ber_dup( ber ); ber_scanf( ber, "x" ); if ( ber_peek_tag( ber, &len ) != LBER_DEFAULT ) { /* There's more - dup the ber buffer so they can all be * individually freed by ldap_msgfree. */ struct berval bv; ber_get_option( ber, LBER_OPT_BER_REMAINING_BYTES, &len ); bv.bv_val = LDAP_MALLOC( len ); if ( bv.bv_val ) { ok = 1; ber_read( ber, bv.bv_val, len ); bv.bv_len = len; ber_init2( ber, &bv, ld->ld_lberoptions ); } } } else { /* LDAPv3: Just allocate a new ber. Since this is a buffered * datagram, if the sockbuf is readable we still have data * to parse. */ ber = ldap_alloc_ber_with_options( ld ); if ( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return -1; } if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) ok = 1; } /* set up response chain */ if ( tmp == NULL ) { newmsg->lm_next = ld->ld_responses; ld->ld_responses = newmsg; chain_head = newmsg; } else { tmp->lm_chain = newmsg; } chain_head->lm_chain_tail = newmsg; tmp = newmsg; /* "ok" means there's more to parse */ if ( ok ) { if ( isv2 ) { goto nextresp2; } else { goto nextresp3; } } else { /* got to end of datagram without a SearchResult. Free * our dup'd ber, but leave any buffer alone. For v2 case, * the previous response is still using this buffer. For v3, * the new ber has no buffer to free yet. */ ber_free( ber, 0 ); return -1; } } else if ( moremsgs ) { /* got search result, and we had multiple responses in 1 datagram. * stick the result onto the end of the chain, and then pull the * first response off the head of the chain. */ tmp->lm_chain = newmsg; chain_head->lm_chain_tail = newmsg; *result = chkResponseList( ld, msgid, all ); ld->ld_errno = LDAP_SUCCESS; return( (*result)->lm_msgtype ); } } #endif /* LDAP_CONNECTIONLESS */ /* is this the one we're looking for? */ if ( msgid == LDAP_RES_ANY || id == msgid ) { if ( all == LDAP_MSG_ONE || ( newmsg->lm_msgtype != LDAP_RES_SEARCH_RESULT && newmsg->lm_msgtype != LDAP_RES_SEARCH_ENTRY && newmsg->lm_msgtype != LDAP_RES_INTERMEDIATE && newmsg->lm_msgtype != LDAP_RES_SEARCH_REFERENCE ) ) { *result = newmsg; ld->ld_errno = LDAP_SUCCESS; return( tag ); } else if ( newmsg->lm_msgtype == LDAP_RES_SEARCH_RESULT) { foundit = 1; /* return the chain later */ } } /* * if not, we must add it to the list of responses. if * the msgid is already there, it must be part of an existing * search response. */ prev = NULL; for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) { if ( l->lm_msgid == newmsg->lm_msgid ) { break; } prev = l; } /* not part of an existing search response */ if ( l == NULL ) { if ( foundit ) { *result = newmsg; goto exit; } newmsg->lm_next = ld->ld_responses; ld->ld_responses = newmsg; goto exit; } Debug3( LDAP_DEBUG_TRACE, "adding response ld %p msgid %d type %ld:\n", (void *)ld, newmsg->lm_msgid, (long) newmsg->lm_msgtype ); /* part of a search response - add to end of list of entries */ l->lm_chain_tail->lm_chain = newmsg; l->lm_chain_tail = newmsg; /* return the whole chain if that's what we were looking for */ if ( foundit ) { if ( prev == NULL ) { ld->ld_responses = l->lm_next; } else { prev->lm_next = l->lm_next; } *result = l; } exit: if ( foundit ) { ld->ld_errno = LDAP_SUCCESS; return( tag ); } if ( lc && ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) { goto retry; } return( LDAP_MSG_X_KEEP_LOOKING ); /* continue looking */ } static ber_tag_t build_result_ber( LDAP *ld, BerElement **bp, LDAPRequest *lr ) { ber_len_t len; ber_tag_t tag; ber_int_t along; BerElement *ber; *bp = NULL; ber = ldap_alloc_ber_with_options( ld ); if( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return LBER_ERROR; } if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid, lr->lr_res_msgtype, lr->lr_res_errno, lr->lr_res_matched ? lr->lr_res_matched : "", lr->lr_res_error ? lr->lr_res_error : "" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( LBER_ERROR ); } ber_reset( ber, 1 ); if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 1 ); return( LBER_ERROR ); } if ( ber_get_enum( ber, &along ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 1 ); return( LBER_ERROR ); } tag = ber_peek_tag( ber, &len ); if ( tag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 1 ); return( LBER_ERROR ); } *bp = ber; return tag; } /* * Merge error information in "lr" with "parentr" error code and string. */ static void merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr ) { if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) { parentr->lr_res_errno = lr->lr_res_errno; if ( lr->lr_res_error != NULL ) { (void)ldap_append_referral( ld, &parentr->lr_res_error, lr->lr_res_error ); } } else if ( lr->lr_res_errno != LDAP_SUCCESS && parentr->lr_res_errno == LDAP_SUCCESS ) { parentr->lr_res_errno = lr->lr_res_errno; if ( parentr->lr_res_error != NULL ) { LDAP_FREE( parentr->lr_res_error ); } parentr->lr_res_error = lr->lr_res_error; lr->lr_res_error = NULL; if ( LDAP_NAME_ERROR( lr->lr_res_errno ) ) { if ( parentr->lr_res_matched != NULL ) { LDAP_FREE( parentr->lr_res_matched ); } parentr->lr_res_matched = lr->lr_res_matched; lr->lr_res_matched = NULL; } } Debug1( LDAP_DEBUG_TRACE, "merged parent (id %d) error info: ", parentr->lr_msgid ); Debug3( LDAP_DEBUG_TRACE, "result errno %d, error <%s>, matched <%s>\n", parentr->lr_res_errno, parentr->lr_res_error ? parentr->lr_res_error : "", parentr->lr_res_matched ? parentr->lr_res_matched : "" ); } int ldap_msgtype( LDAPMessage *lm ) { assert( lm != NULL ); return ( lm != NULL ) ? (int)lm->lm_msgtype : -1; } int ldap_msgid( LDAPMessage *lm ) { assert( lm != NULL ); return ( lm != NULL ) ? lm->lm_msgid : -1; } const char * ldap_int_msgtype2str( ber_tag_t tag ) { switch( tag ) { case LDAP_RES_ADD: return "add"; case LDAP_RES_BIND: return "bind"; case LDAP_RES_COMPARE: return "compare"; case LDAP_RES_DELETE: return "delete"; case LDAP_RES_EXTENDED: return "extended-result"; case LDAP_RES_INTERMEDIATE: return "intermediate"; case LDAP_RES_MODIFY: return "modify"; case LDAP_RES_RENAME: return "rename"; case LDAP_RES_SEARCH_ENTRY: return "search-entry"; case LDAP_RES_SEARCH_REFERENCE: return "search-reference"; case LDAP_RES_SEARCH_RESULT: return "search-result"; } return "unknown"; } int ldap_msgfree( LDAPMessage *lm ) { LDAPMessage *next; int type = 0; Debug0( LDAP_DEBUG_TRACE, "ldap_msgfree\n" ); for ( ; lm != NULL; lm = next ) { next = lm->lm_chain; type = lm->lm_msgtype; ber_free( lm->lm_ber, 1 ); LDAP_FREE( (char *) lm ); } return type; } /* * ldap_msgdelete - delete a message. It returns: * 0 if the entire message was deleted * -1 if the message was not found, or only part of it was found */ int ldap_msgdelete( LDAP *ld, int msgid ) { LDAPMessage *lm, *prev; int rc = 0; assert( ld != NULL ); Debug2( LDAP_DEBUG_TRACE, "ldap_msgdelete ld=%p msgid=%d\n", (void *)ld, msgid ); LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); prev = NULL; for ( lm = ld->ld_responses; lm != NULL; lm = lm->lm_next ) { if ( lm->lm_msgid == msgid ) { break; } prev = lm; } if ( lm == NULL ) { rc = -1; } else { if ( prev == NULL ) { ld->ld_responses = lm->lm_next; } else { prev->lm_next = lm->lm_next; } } LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); if ( lm ) { switch ( ldap_msgfree( lm ) ) { case LDAP_RES_SEARCH_ENTRY: case LDAP_RES_SEARCH_REFERENCE: case LDAP_RES_INTERMEDIATE: rc = -1; break; default: break; } } return rc; } /* * ldap_abandoned * * return the location of the message id in the array of abandoned * message ids, or -1 */ static int ldap_abandoned( LDAP *ld, ber_int_t msgid ) { int ret, idx; assert( msgid >= 0 ); LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex ); ret = ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &idx ); LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex ); return ret; } /* * ldap_mark_abandoned */ static int ldap_mark_abandoned( LDAP *ld, ber_int_t msgid ) { int ret, idx; assert( msgid >= 0 ); LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex ); ret = ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &idx ); if (ret <= 0) { /* error or already deleted by another thread */ LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex ); return ret; } /* still in abandoned array, so delete */ ret = ldap_int_bisect_delete( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, idx ); LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex ); return ret; } openldap-2.5.11+dfsg/libraries/libldap/extended.c0000644000175000017500000002077414172327167020400 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" #include "ldap_log.h" BerElement * ldap_build_extended_req( LDAP *ld, LDAP_CONST char *reqoid, struct berval *reqdata, LDAPControl **sctrls, LDAPControl **cctrls, ber_int_t *msgidp ) { BerElement *ber; int rc; /* create a message to send */ if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { return( NULL ); } LDAP_NEXT_MSGID( ld, *msgidp ); if ( reqdata != NULL ) { rc = ber_printf( ber, "{it{tstON}", /* '}' */ *msgidp, LDAP_REQ_EXTENDED, LDAP_TAG_EXOP_REQ_OID, reqoid, LDAP_TAG_EXOP_REQ_VALUE, reqdata ); } else { rc = ber_printf( ber, "{it{tsN}", /* '}' */ *msgidp, LDAP_REQ_EXTENDED, LDAP_TAG_EXOP_REQ_OID, reqoid ); } if( rc == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } /* Put Server Controls */ if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return( NULL ); } if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } return( ber ); } /* * LDAPv3 Extended Operation Request * ExtendedRequest ::= [APPLICATION 23] SEQUENCE { * requestName [0] LDAPOID, * requestValue [1] OCTET STRING OPTIONAL * } * * LDAPv3 Extended Operation Response * ExtendedResponse ::= [APPLICATION 24] SEQUENCE { * COMPONENTS OF LDAPResult, * responseName [10] LDAPOID OPTIONAL, * response [11] OCTET STRING OPTIONAL * } * * (Source RFC 4511) */ int ldap_extended_operation( LDAP *ld, LDAP_CONST char *reqoid, struct berval *reqdata, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp ) { BerElement *ber; ber_int_t id; Debug0( LDAP_DEBUG_TRACE, "ldap_extended_operation\n" ); assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( reqoid != NULL && *reqoid != '\0' ); assert( msgidp != NULL ); /* must be version 3 (or greater) */ if ( ld->ld_version < LDAP_VERSION3 ) { ld->ld_errno = LDAP_NOT_SUPPORTED; return( ld->ld_errno ); } ber = ldap_build_extended_req( ld, reqoid, reqdata, sctrls, cctrls, &id ); if ( !ber ) return( ld->ld_errno ); /* send the message */ *msgidp = ldap_send_initial_request( ld, LDAP_REQ_EXTENDED, NULL, ber, id ); return( *msgidp < 0 ? ld->ld_errno : LDAP_SUCCESS ); } int ldap_extended_operation_s( LDAP *ld, LDAP_CONST char *reqoid, struct berval *reqdata, LDAPControl **sctrls, LDAPControl **cctrls, char **retoidp, struct berval **retdatap ) { int rc; int msgid; LDAPMessage *res; Debug0( LDAP_DEBUG_TRACE, "ldap_extended_operation_s\n" ); assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( reqoid != NULL && *reqoid != '\0' ); rc = ldap_extended_operation( ld, reqoid, reqdata, sctrls, cctrls, &msgid ); if ( rc != LDAP_SUCCESS ) { return( rc ); } if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, &res ) == -1 || !res ) { return( ld->ld_errno ); } if ( retoidp != NULL ) *retoidp = NULL; if ( retdatap != NULL ) *retdatap = NULL; rc = ldap_parse_extended_result( ld, res, retoidp, retdatap, 0 ); if( rc != LDAP_SUCCESS ) { ldap_msgfree( res ); return rc; } return( ldap_result2error( ld, res, 1 ) ); } /* Parse an extended result */ int ldap_parse_extended_result ( LDAP *ld, LDAPMessage *res, char **retoidp, struct berval **retdatap, int freeit ) { BerElement *ber; ber_tag_t rc; ber_tag_t tag; ber_len_t len; struct berval *resdata; ber_int_t errcode; char *resoid; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( res != NULL ); Debug0( LDAP_DEBUG_TRACE, "ldap_parse_extended_result\n" ); if( ld->ld_version < LDAP_VERSION3 ) { ld->ld_errno = LDAP_NOT_SUPPORTED; return ld->ld_errno; } if( res->lm_msgtype != LDAP_RES_EXTENDED ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; } if( retoidp != NULL ) *retoidp = NULL; if( retdatap != NULL ) *retdatap = NULL; if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); ld->ld_error = NULL; } if ( ld->ld_matched ) { LDAP_FREE( ld->ld_matched ); ld->ld_matched = NULL; } ber = ber_dup( res->lm_ber ); if ( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } rc = ber_scanf( ber, "{eAA" /*}*/, &errcode, &ld->ld_matched, &ld->ld_error ); if( rc == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 0 ); return ld->ld_errno; } resoid = NULL; resdata = NULL; tag = ber_peek_tag( ber, &len ); if( tag == LDAP_TAG_REFERRAL ) { /* skip over referral */ if( ber_scanf( ber, "x" ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 0 ); return ld->ld_errno; } tag = ber_peek_tag( ber, &len ); } if( tag == LDAP_TAG_EXOP_RES_OID ) { /* we have a resoid */ if( ber_scanf( ber, "a", &resoid ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 0 ); return ld->ld_errno; } assert( resoid[ 0 ] != '\0' ); tag = ber_peek_tag( ber, &len ); } if( tag == LDAP_TAG_EXOP_RES_VALUE ) { /* we have a resdata */ if( ber_scanf( ber, "O", &resdata ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 0 ); if( resoid != NULL ) LDAP_FREE( resoid ); return ld->ld_errno; } } ber_free( ber, 0 ); if( retoidp != NULL ) { *retoidp = resoid; } else { LDAP_FREE( resoid ); } if( retdatap != NULL ) { *retdatap = resdata; } else { ber_bvfree( resdata ); } ld->ld_errno = errcode; if( freeit ) { ldap_msgfree( res ); } return LDAP_SUCCESS; } /* Parse an extended partial */ int ldap_parse_intermediate ( LDAP *ld, LDAPMessage *res, char **retoidp, struct berval **retdatap, LDAPControl ***serverctrls, int freeit ) { BerElement *ber; ber_tag_t tag; ber_len_t len; struct berval *resdata; char *resoid; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( res != NULL ); Debug0( LDAP_DEBUG_TRACE, "ldap_parse_intermediate\n" ); if( ld->ld_version < LDAP_VERSION3 ) { ld->ld_errno = LDAP_NOT_SUPPORTED; return ld->ld_errno; } if( res->lm_msgtype != LDAP_RES_INTERMEDIATE ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; } if( retoidp != NULL ) *retoidp = NULL; if( retdatap != NULL ) *retdatap = NULL; if( serverctrls != NULL ) *serverctrls = NULL; ber = ber_dup( res->lm_ber ); if ( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } tag = ber_scanf( ber, "{" /*}*/ ); if( tag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 0 ); return ld->ld_errno; } resoid = NULL; resdata = NULL; tag = ber_peek_tag( ber, &len ); /* * NOTE: accept intermediate and extended response tag values * as older versions of slapd(8) incorrectly used extended * response tags. * Should be removed when 2.2 is moved to Historic. */ if( tag == LDAP_TAG_IM_RES_OID || tag == LDAP_TAG_EXOP_RES_OID ) { /* we have a resoid */ if( ber_scanf( ber, "a", &resoid ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 0 ); return ld->ld_errno; } assert( resoid[ 0 ] != '\0' ); tag = ber_peek_tag( ber, &len ); } if( tag == LDAP_TAG_IM_RES_VALUE || tag == LDAP_TAG_EXOP_RES_VALUE ) { /* we have a resdata */ if( ber_scanf( ber, "O", &resdata ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; ber_free( ber, 0 ); if( resoid != NULL ) LDAP_FREE( resoid ); return ld->ld_errno; } } if ( serverctrls == NULL ) { ld->ld_errno = LDAP_SUCCESS; goto free_and_return; } if ( ber_scanf( ber, /*{*/ "}" ) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; goto free_and_return; } ld->ld_errno = ldap_pvt_get_controls( ber, serverctrls ); free_and_return: ber_free( ber, 0 ); if( retoidp != NULL ) { *retoidp = resoid; } else { LDAP_FREE( resoid ); } if( retdatap != NULL ) { *retdatap = resdata; } else { ber_bvfree( resdata ); } if( freeit ) { ldap_msgfree( res ); } return ld->ld_errno; } openldap-2.5.11+dfsg/libraries/libldap/request.c0000644000175000017500000012515714172327167020271 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. */ /* This notice applies to changes, created by or for Novell, Inc., * to preexisting works for which notices appear elsewhere in this file. * * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved. * * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES. * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. *--- * Modification to OpenLDAP source by Novell, Inc. * April 2000 sfs Added code to chase V3 referrals * request.c - sending of ldap requests; handling of referrals *--- * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License * can be found in the file "build/LICENSE-2.0.1" in this distribution * of OpenLDAP Software. */ #include "portable.h" #include #include #include #include #include #include #include #include #include "ldap-int.h" #include "lber.h" /* used by ldap_send_server_request and ldap_new_connection */ #ifdef LDAP_R_COMPILE #define LDAP_CONN_LOCK_IF(nolock) \ { if (nolock) LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); } #define LDAP_CONN_UNLOCK_IF(nolock) \ { if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); } #define LDAP_REQ_LOCK_IF(nolock) \ { if (nolock) LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); } #define LDAP_REQ_UNLOCK_IF(nolock) \ { if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); } #define LDAP_RES_LOCK_IF(nolock) \ { if (nolock) LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); } #define LDAP_RES_UNLOCK_IF(nolock) \ { if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); } #else #define LDAP_CONN_LOCK_IF(nolock) #define LDAP_CONN_UNLOCK_IF(nolock) #define LDAP_REQ_LOCK_IF(nolock) #define LDAP_REQ_UNLOCK_IF(nolock) #define LDAP_RES_LOCK_IF(nolock) #define LDAP_RES_UNLOCK_IF(nolock) #endif static LDAPConn *find_connection LDAP_P(( LDAP *ld, LDAPURLDesc *srv, int any )); static void use_connection LDAP_P(( LDAP *ld, LDAPConn *lc )); static void ldap_free_request_int LDAP_P(( LDAP *ld, LDAPRequest *lr )); static BerElement * re_encode_request( LDAP *ld, BerElement *origber, ber_int_t msgid, int sref, LDAPURLDesc *srv, int *type ); BerElement * ldap_alloc_ber_with_options( LDAP *ld ) { BerElement *ber; ber = ber_alloc_t( ld->ld_lberoptions ); if ( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; } return( ber ); } void ldap_set_ber_options( LDAP *ld, BerElement *ber ) { /* ld_lberoptions is constant, hence no lock */ ber->ber_options = ld->ld_lberoptions; } /* sets needed mutexes - no mutexes set to this point */ ber_int_t ldap_send_initial_request( LDAP *ld, ber_tag_t msgtype, const char *dn, BerElement *ber, ber_int_t msgid) { int rc = 1; ber_socket_t sd = AC_SOCKET_INVALID; Debug0( LDAP_DEBUG_TRACE, "ldap_send_initial_request\n" ); LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd ) == -1 ) { /* not connected yet */ rc = ldap_open_defconn( ld ); if ( rc == 0 ) { ber_sockbuf_ctrl( ld->ld_defconn->lconn_sb, LBER_SB_OPT_GET_FD, &sd ); } } if ( ld->ld_defconn && ld->ld_defconn->lconn_status == LDAP_CONNST_CONNECTING ) rc = ldap_int_check_async_open( ld, sd ); if( rc < 0 ) { ber_free( ber, 1 ); LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); return( -1 ); } else if ( rc == 0 ) { Debug0( LDAP_DEBUG_TRACE, "ldap_open_defconn: successful\n" ); } #ifdef LDAP_CONNECTIONLESS if (LDAP_IS_UDP(ld)) { if (msgtype == LDAP_REQ_BIND) { LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); if (ld->ld_options.ldo_cldapdn) ldap_memfree(ld->ld_options.ldo_cldapdn); ld->ld_options.ldo_cldapdn = ldap_strdup(dn); ber_free( ber, 1 ); LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); return 0; } if (msgtype != LDAP_REQ_ABANDON && msgtype != LDAP_REQ_SEARCH) { ber_free( ber, 1 ); LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); return LDAP_PARAM_ERROR; } } #endif LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); rc = ldap_send_server_request( ld, ber, msgid, NULL, NULL, NULL, NULL, 0, 0 ); LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); return(rc); } /* protected by conn_mutex */ int ldap_int_flush_request( LDAP *ld, LDAPRequest *lr ) { LDAPConn *lc = lr->lr_conn; LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); if ( ber_flush2( lc->lconn_sb, lr->lr_ber, LBER_FLUSH_FREE_NEVER ) != 0 ) { if (( sock_errno() == EAGAIN ) || ( sock_errno() == ENOTCONN )) { /* ENOTCONN is returned in Solaris 10 */ /* need to continue write later */ lr->lr_status = LDAP_REQST_WRITING; ldap_mark_select_write( ld, lc->lconn_sb ); ld->ld_errno = LDAP_BUSY; return -2; } else { ld->ld_errno = LDAP_SERVER_DOWN; ldap_free_request( ld, lr ); ldap_free_connection( ld, lc, 0, 0 ); return( -1 ); } } else { if ( lr->lr_parent == NULL ) { lr->lr_ber->ber_end = lr->lr_ber->ber_ptr; lr->lr_ber->ber_ptr = lr->lr_ber->ber_buf; } lr->lr_status = LDAP_REQST_INPROGRESS; /* sent -- waiting for a response */ ldap_mark_select_read( ld, lc->lconn_sb ); ldap_clear_select_write( ld, lc->lconn_sb ); } return 0; } /* * protected by req_mutex * if m_noconn then protect using conn_lock * else already protected with conn_lock * if m_res then also protected by res_mutex */ int ldap_send_server_request( LDAP *ld, BerElement *ber, ber_int_t msgid, LDAPRequest *parentreq, LDAPURLDesc **srvlist, LDAPConn *lc, LDAPreqinfo *bind, int m_noconn, int m_res ) { LDAPRequest *lr; int incparent, rc; LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); Debug0( LDAP_DEBUG_TRACE, "ldap_send_server_request\n" ); incparent = 0; ld->ld_errno = LDAP_SUCCESS; /* optimistic */ LDAP_CONN_LOCK_IF(m_noconn); if ( lc == NULL ) { if ( srvlist == NULL ) { lc = ld->ld_defconn; } else { lc = find_connection( ld, *srvlist, 1 ); if ( lc == NULL ) { if ( (bind != NULL) && (parentreq != NULL) ) { /* Remember the bind in the parent */ incparent = 1; ++parentreq->lr_outrefcnt; } lc = ldap_new_connection( ld, srvlist, 0, 1, bind, 1, m_res ); } } } /* async connect... */ if ( lc != NULL && lc->lconn_status == LDAP_CONNST_CONNECTING ) { ber_socket_t sd = AC_SOCKET_ERROR; struct timeval tv = { 0 }; ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_GET_FD, &sd ); /* poll ... */ switch ( ldap_int_poll( ld, sd, &tv, 1 ) ) { case 0: /* go on! */ lc->lconn_status = LDAP_CONNST_CONNECTED; break; case -2: /* async only occurs if a network timeout is set */ /* honor network timeout */ LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); if ( time( NULL ) - lc->lconn_created <= ld->ld_options.ldo_tm_net.tv_sec ) { /* caller will have to call again */ ld->ld_errno = LDAP_X_CONNECTING; } LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); /* fallthru */ default: /* error */ break; } } if ( lc == NULL || lc->lconn_status != LDAP_CONNST_CONNECTED ) { if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = LDAP_SERVER_DOWN; } ber_free( ber, 1 ); if ( incparent ) { /* Forget about the bind */ --parentreq->lr_outrefcnt; } LDAP_CONN_UNLOCK_IF(m_noconn); return( -1 ); } use_connection( ld, lc ); #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP( ld )) { BerElement tmpber = *ber; ber_rewind( &tmpber ); LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); rc = ber_write( &tmpber, ld->ld_options.ldo_peer, sizeof( struct sockaddr_storage ), 0 ); LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); if ( rc == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); LDAP_CONN_UNLOCK_IF(m_noconn); return rc; } } #endif /* If we still have an incomplete write, try to finish it before * dealing with the new request. If we don't finish here, return * LDAP_BUSY and let the caller retry later. We only allow a single * request to be in WRITING state. */ rc = 0; if ( ld->ld_requests != NULL ) { TAvlnode *node = ldap_tavl_end( ld->ld_requests, TAVL_DIR_RIGHT ); LDAPRequest *lr; assert( node != NULL ); lr = node->avl_data; if ( lr->lr_status == LDAP_REQST_WRITING && ldap_int_flush_request( ld, lr ) < 0 ) { rc = -1; } } if ( rc ) { ber_free( ber, 1 ); LDAP_CONN_UNLOCK_IF(m_noconn); return rc; } lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ) ); if ( lr == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; ldap_free_connection( ld, lc, 0, 0 ); ber_free( ber, 1 ); if ( incparent ) { /* Forget about the bind */ --parentreq->lr_outrefcnt; } LDAP_CONN_UNLOCK_IF(m_noconn); return( -1 ); } lr->lr_msgid = msgid; lr->lr_status = LDAP_REQST_INPROGRESS; lr->lr_res_errno = LDAP_SUCCESS; /* optimistic */ lr->lr_ber = ber; lr->lr_conn = lc; if ( parentreq != NULL ) { /* sub-request */ if ( !incparent ) { /* Increment if we didn't do it before the bind */ ++parentreq->lr_outrefcnt; } lr->lr_origid = parentreq->lr_origid; lr->lr_parentcnt = ++parentreq->lr_parentcnt; lr->lr_parent = parentreq; lr->lr_refnext = parentreq->lr_child; parentreq->lr_child = lr; } else { /* original request */ lr->lr_origid = lr->lr_msgid; } /* Extract requestDN for future reference */ #ifdef LDAP_CONNECTIONLESS if ( !LDAP_IS_UDP(ld) ) #endif { BerElement tmpber = *ber; ber_int_t bint; ber_tag_t tag, rtag; ber_reset( &tmpber, 1 ); rtag = ber_scanf( &tmpber, "{it", /*}*/ &bint, &tag ); switch ( tag ) { case LDAP_REQ_BIND: rtag = ber_scanf( &tmpber, "{i" /*}*/, &bint ); break; case LDAP_REQ_DELETE: break; default: rtag = ber_scanf( &tmpber, "{" /*}*/ ); case LDAP_REQ_ABANDON: break; } if ( tag != LDAP_REQ_ABANDON ) { ber_skip_tag( &tmpber, &lr->lr_dn.bv_len ); lr->lr_dn.bv_val = tmpber.ber_ptr; } } rc = ldap_tavl_insert( &ld->ld_requests, lr, ldap_req_cmp, ldap_avl_dup_error ); assert( rc == LDAP_SUCCESS ); ld->ld_errno = LDAP_SUCCESS; if ( ldap_int_flush_request( ld, lr ) == -1 ) { msgid = -1; } LDAP_CONN_UNLOCK_IF(m_noconn); return( msgid ); } /* return 0 if no StartTLS ext, 1 if present, 2 if critical */ static int find_tls_ext( LDAPURLDesc *srv ) { int i, crit; char *ext; if ( !srv->lud_exts ) return 0; for (i=0; srv->lud_exts[i]; i++) { crit = 0; ext = srv->lud_exts[i]; if ( ext[0] == '!') { ext++; crit = 1; } if ( !strcasecmp( ext, "StartTLS" ) || !strcasecmp( ext, "X-StartTLS" ) || !strcmp( ext, LDAP_EXOP_START_TLS )) { return crit + 1; } } return 0; } /* * always protected by conn_mutex * optionally protected by req_mutex and res_mutex */ LDAPConn * ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb, int connect, LDAPreqinfo *bind, int m_req, int m_res ) { LDAPConn *lc; int async = 0; LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); Debug3( LDAP_DEBUG_TRACE, "ldap_new_connection %d %d %d\n", use_ldsb, connect, (bind != NULL) ); /* * make a new LDAP server connection * XXX open connection synchronously for now */ lc = (LDAPConn *)LDAP_CALLOC( 1, sizeof( LDAPConn ) ); if ( lc == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return( NULL ); } if ( use_ldsb ) { assert( ld->ld_sb != NULL ); lc->lconn_sb = ld->ld_sb; } else { lc->lconn_sb = ber_sockbuf_alloc(); if ( lc->lconn_sb == NULL ) { LDAP_FREE( (char *)lc ); ld->ld_errno = LDAP_NO_MEMORY; return( NULL ); } } if ( connect ) { LDAPURLDesc **srvp, *srv = NULL; async = LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_CONNECT_ASYNC ); for ( srvp = srvlist; *srvp != NULL; srvp = &(*srvp)->lud_next ) { int rc; rc = ldap_int_open_connection( ld, lc, *srvp, async ); if ( rc != -1 ) { srv = *srvp; /* If we fully connected, async is moot */ if ( rc == 0 ) async = 0; if ( ld->ld_urllist_proc && ( !async || rc != -2 ) ) { ld->ld_urllist_proc( ld, srvlist, srvp, ld->ld_urllist_params ); } break; } } if ( srv == NULL ) { if ( !use_ldsb ) { ber_sockbuf_free( lc->lconn_sb ); } LDAP_FREE( (char *)lc ); ld->ld_errno = LDAP_SERVER_DOWN; return( NULL ); } lc->lconn_server = ldap_url_dup( srv ); if ( !lc->lconn_server ) { if ( !use_ldsb ) ber_sockbuf_free( lc->lconn_sb ); LDAP_FREE( (char *)lc ); ld->ld_errno = LDAP_NO_MEMORY; return( NULL ); } } lc->lconn_status = async ? LDAP_CONNST_CONNECTING : LDAP_CONNST_CONNECTED; lc->lconn_next = ld->ld_conns; ld->ld_conns = lc; if ( connect ) { #ifdef HAVE_TLS if ( lc->lconn_server->lud_exts ) { int rc, ext = find_tls_ext( lc->lconn_server ); if ( ext ) { LDAPConn *savedefconn; savedefconn = ld->ld_defconn; ++lc->lconn_refcnt; /* avoid premature free */ ld->ld_defconn = lc; LDAP_REQ_UNLOCK_IF(m_req); LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); LDAP_RES_UNLOCK_IF(m_res); rc = ldap_start_tls_s( ld, NULL, NULL ); LDAP_RES_LOCK_IF(m_res); LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); LDAP_REQ_LOCK_IF(m_req); ld->ld_defconn = savedefconn; --lc->lconn_refcnt; if ( rc != LDAP_SUCCESS && ext == 2 ) { ldap_free_connection( ld, lc, 1, 0 ); return NULL; } } } #endif } if ( bind != NULL ) { int err = 0; LDAPConn *savedefconn; /* Set flag to prevent additional referrals * from being processed on this * connection until the bind has completed */ lc->lconn_rebind_inprogress = 1; /* V3 rebind function */ if ( ld->ld_rebind_proc != NULL) { LDAPURLDesc *srvfunc; srvfunc = ldap_url_dup( *srvlist ); if ( srvfunc == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; err = -1; } else { savedefconn = ld->ld_defconn; ++lc->lconn_refcnt; /* avoid premature free */ ld->ld_defconn = lc; Debug0( LDAP_DEBUG_TRACE, "Call application rebind_proc\n" ); LDAP_REQ_UNLOCK_IF(m_req); LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); LDAP_RES_UNLOCK_IF(m_res); err = (*ld->ld_rebind_proc)( ld, bind->ri_url, bind->ri_request, bind->ri_msgid, ld->ld_rebind_params ); LDAP_RES_LOCK_IF(m_res); LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); LDAP_REQ_LOCK_IF(m_req); ld->ld_defconn = savedefconn; --lc->lconn_refcnt; if ( err != 0 ) { err = -1; ldap_free_connection( ld, lc, 1, 0 ); lc = NULL; } ldap_free_urldesc( srvfunc ); } } else { int msgid, rc; struct berval passwd = BER_BVNULL; savedefconn = ld->ld_defconn; ++lc->lconn_refcnt; /* avoid premature free */ ld->ld_defconn = lc; Debug0( LDAP_DEBUG_TRACE, "anonymous rebind via ldap_sasl_bind(\"\")\n" ); LDAP_REQ_UNLOCK_IF(m_req); LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); LDAP_RES_UNLOCK_IF(m_res); rc = ldap_sasl_bind( ld, "", LDAP_SASL_SIMPLE, &passwd, NULL, NULL, &msgid ); if ( rc != LDAP_SUCCESS ) { err = -1; } else { for ( err = 1; err > 0; ) { struct timeval tv = { 0, 100000 }; LDAPMessage *res = NULL; switch ( ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res ) ) { case -1: err = -1; break; case 0: #ifdef LDAP_R_COMPILE ldap_pvt_thread_yield(); #endif break; case LDAP_RES_BIND: rc = ldap_parse_result( ld, res, &err, NULL, NULL, NULL, NULL, 1 ); if ( rc != LDAP_SUCCESS ) { err = -1; } else if ( err != LDAP_SUCCESS ) { err = -1; } /* else err == LDAP_SUCCESS == 0 */ break; default: Debug3( LDAP_DEBUG_TRACE, "ldap_new_connection %p: " "unexpected response %d " "from BIND request id=%d\n", (void *) ld, ldap_msgtype( res ), msgid ); err = -1; break; } } } LDAP_RES_LOCK_IF(m_res); LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); LDAP_REQ_LOCK_IF(m_req); ld->ld_defconn = savedefconn; --lc->lconn_refcnt; if ( err != 0 ) { ldap_free_connection( ld, lc, 1, 0 ); lc = NULL; } } if ( lc != NULL ) lc->lconn_rebind_inprogress = 0; } return( lc ); } /* protected by ld_conn_mutex */ static LDAPConn * find_connection( LDAP *ld, LDAPURLDesc *srv, int any ) /* * return an existing connection (if any) to the server srv * if "any" is non-zero, check for any server in the "srv" chain */ { LDAPConn *lc; LDAPURLDesc *lcu, *lsu; int lcu_port, lsu_port; int found = 0; LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) { lcu = lc->lconn_server; lcu_port = ldap_pvt_url_scheme_port( lcu->lud_scheme, lcu->lud_port ); for ( lsu = srv; lsu != NULL; lsu = lsu->lud_next ) { lsu_port = ldap_pvt_url_scheme_port( lsu->lud_scheme, lsu->lud_port ); if ( lsu_port == lcu_port && strcmp( lcu->lud_scheme, lsu->lud_scheme ) == 0 && lcu->lud_host != NULL && lsu->lud_host != NULL && strcasecmp( lsu->lud_host, lcu->lud_host ) == 0 ) { found = 1; break; } if ( !any ) break; } if ( found ) break; } return lc; } /* protected by ld_conn_mutex */ static void use_connection( LDAP *ld, LDAPConn *lc ) { LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); ++lc->lconn_refcnt; lc->lconn_lastused = time( NULL ); } /* protected by ld_conn_mutex */ void ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ) { LDAPConn *tmplc, *prevlc; LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); Debug2( LDAP_DEBUG_TRACE, "ldap_free_connection %d %d\n", force, unbind ); if ( force || --lc->lconn_refcnt <= 0 ) { /* remove from connections list first */ for ( prevlc = NULL, tmplc = ld->ld_conns; tmplc != NULL; tmplc = tmplc->lconn_next ) { if ( tmplc == lc ) { if ( prevlc == NULL ) { ld->ld_conns = tmplc->lconn_next; } else { prevlc->lconn_next = tmplc->lconn_next; } if ( ld->ld_defconn == lc ) { ld->ld_defconn = NULL; } break; } prevlc = tmplc; } /* process connection callbacks */ { struct ldapoptions *lo; ldaplist *ll; ldap_conncb *cb; lo = &ld->ld_options; LDAP_MUTEX_LOCK( &lo->ldo_mutex ); if ( lo->ldo_conn_cbs ) { for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) { cb = ll->ll_data; cb->lc_del( ld, lc->lconn_sb, cb ); } } LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); lo = LDAP_INT_GLOBAL_OPT(); LDAP_MUTEX_LOCK( &lo->ldo_mutex ); if ( lo->ldo_conn_cbs ) { for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) { cb = ll->ll_data; cb->lc_del( ld, lc->lconn_sb, cb ); } } LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); } if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) { ldap_mark_select_clear( ld, lc->lconn_sb ); if ( unbind ) { ldap_send_unbind( ld, lc->lconn_sb, NULL, NULL ); } } if ( lc->lconn_ber != NULL ) { ber_free( lc->lconn_ber, 1 ); } ldap_int_sasl_close( ld, lc ); ldap_free_urllist( lc->lconn_server ); /* FIXME: is this at all possible? * ldap_ld_free() in unbind.c calls ldap_free_connection() * with force == 1 __after__ explicitly calling * ldap_tavl_free on ld->ld_requests */ if ( force ) { ldap_tavl_free( ld->ld_requests, ldap_do_free_request ); ld->ld_requests = NULL; } if ( lc->lconn_sb != ld->ld_sb ) { ber_sockbuf_free( lc->lconn_sb ); } else { ber_int_sb_close( lc->lconn_sb ); } if ( lc->lconn_rebind_queue != NULL) { int i; for( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) { LDAP_VFREE( lc->lconn_rebind_queue[i] ); } LDAP_FREE( lc->lconn_rebind_queue ); } LDAP_FREE( lc ); Debug0( LDAP_DEBUG_TRACE, "ldap_free_connection: actually freed\n" ); } else { lc->lconn_lastused = time( NULL ); Debug1( LDAP_DEBUG_TRACE, "ldap_free_connection: refcnt %d\n", lc->lconn_refcnt ); } } /* Protects self with ld_conn_mutex */ #ifdef LDAP_DEBUG void ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all ) { LDAPConn *lc; char timebuf[32]; Debug2( LDAP_DEBUG_TRACE, "** ld %p Connection%s:\n", (void *)ld, all ? "s" : "" ); LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) { if ( lc->lconn_server != NULL ) { Debug3( LDAP_DEBUG_TRACE, "* host: %s port: %d%s\n", ( lc->lconn_server->lud_host == NULL ) ? "(null)" : lc->lconn_server->lud_host, lc->lconn_server->lud_port, ( lc->lconn_sb == ld->ld_sb ) ? " (default)" : "" ); } if ( lc->lconn_sb != NULL ) { char from[LDAP_IPADDRLEN]; struct berval frombv = BER_BVC(from); ber_socket_t sb; if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_GET_FD, &sb ) == 1 ) { Sockaddr sin; socklen_t len = sizeof( sin ); if ( getsockname( sb, (struct sockaddr *)&sin, &len ) == 0 ) { ldap_pvt_sockaddrstr( &sin, &frombv ); Debug1( LDAP_DEBUG_TRACE, "* from: %s\n", ( from == NULL ) ? "(null)" : from ); } } } Debug2( LDAP_DEBUG_TRACE, " refcnt: %d status: %s\n", lc->lconn_refcnt, ( lc->lconn_status == LDAP_CONNST_NEEDSOCKET ) ? "NeedSocket" : ( lc->lconn_status == LDAP_CONNST_CONNECTING ) ? "Connecting" : "Connected" ); Debug2( LDAP_DEBUG_TRACE, " last used: %s%s\n", ldap_pvt_ctime( &lc->lconn_lastused, timebuf ), lc->lconn_rebind_inprogress ? " rebind in progress" : "" ); if ( lc->lconn_rebind_inprogress ) { if ( lc->lconn_rebind_queue != NULL) { int i; for ( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) { int j; for( j = 0; lc->lconn_rebind_queue[i][j] != 0; j++ ) { Debug3( LDAP_DEBUG_TRACE, " queue %d entry %d - %s\n", i, j, lc->lconn_rebind_queue[i][j] ); } } } else { Debug0( LDAP_DEBUG_TRACE, " queue is empty\n" ); } } Debug0( LDAP_DEBUG_TRACE, "\n" ); if ( !all ) { break; } } LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); } /* protected by req_mutex and res_mutex */ void ldap_dump_requests_and_responses( LDAP *ld ) { LDAPMessage *lm, *l; TAvlnode *node; int i; Debug1( LDAP_DEBUG_TRACE, "** ld %p Outstanding Requests:\n", (void *)ld ); node = ldap_tavl_end( ld->ld_requests, TAVL_DIR_LEFT ); if ( node == NULL ) { Debug0( LDAP_DEBUG_TRACE, " Empty\n" ); } for ( i = 0 ; node != NULL; i++, node = ldap_tavl_next( node, TAVL_DIR_RIGHT ) ) { LDAPRequest *lr = node->avl_data; Debug3( LDAP_DEBUG_TRACE, " * msgid %d, origid %d, status %s\n", lr->lr_msgid, lr->lr_origid, ( lr->lr_status == LDAP_REQST_INPROGRESS ) ? "InProgress" : ( lr->lr_status == LDAP_REQST_CHASINGREFS ) ? "ChasingRefs" : ( lr->lr_status == LDAP_REQST_NOTCONNECTED ) ? "NotConnected" : ( lr->lr_status == LDAP_REQST_WRITING ) ? "Writing" : ( lr->lr_status == LDAP_REQST_COMPLETED ) ? "RequestCompleted" : "InvalidStatus" ); Debug2( LDAP_DEBUG_TRACE, " outstanding referrals %d, parent count %d\n", lr->lr_outrefcnt, lr->lr_parentcnt ); } Debug3( LDAP_DEBUG_TRACE, " ld %p request count %d (abandoned %lu)\n", (void *)ld, i, ld->ld_nabandoned ); Debug1( LDAP_DEBUG_TRACE, "** ld %p Response Queue:\n", (void *)ld ); if ( ( lm = ld->ld_responses ) == NULL ) { Debug0( LDAP_DEBUG_TRACE, " Empty\n" ); } for ( i = 0; lm != NULL; lm = lm->lm_next, i++ ) { Debug2( LDAP_DEBUG_TRACE, " * msgid %d, type %lu\n", lm->lm_msgid, (unsigned long)lm->lm_msgtype ); if ( lm->lm_chain != NULL ) { Debug0( LDAP_DEBUG_TRACE, " chained responses:\n" ); for ( l = lm->lm_chain; l != NULL; l = l->lm_chain ) { Debug2( LDAP_DEBUG_TRACE, " * msgid %d, type %lu\n", l->lm_msgid, (unsigned long)l->lm_msgtype ); } } } Debug2( LDAP_DEBUG_TRACE, " ld %p response count %d\n", (void *)ld, i ); } #endif /* LDAP_DEBUG */ /* protected by req_mutex */ void ldap_do_free_request( void *arg ) { LDAPRequest *lr = arg; Debug3( LDAP_DEBUG_TRACE, "ldap_do_free_request: " "asked to free lr %p msgid %d refcnt %d\n", lr, lr->lr_msgid, lr->lr_refcnt ); /* if lr_refcnt > 0, the request has been looked up * by ldap_find_request_by_msgid(); if in the meanwhile * the request is free()'d by someone else, just decrease * the reference count; later on, it will be freed. */ if ( lr->lr_refcnt > 0 ) { assert( lr->lr_refcnt == 1 ); lr->lr_refcnt = -lr->lr_refcnt; return; } if ( lr->lr_ber != NULL ) { ber_free( lr->lr_ber, 1 ); lr->lr_ber = NULL; } if ( lr->lr_res_error != NULL ) { LDAP_FREE( lr->lr_res_error ); lr->lr_res_error = NULL; } if ( lr->lr_res_matched != NULL ) { LDAP_FREE( lr->lr_res_matched ); lr->lr_res_matched = NULL; } LDAP_FREE( lr ); } int ldap_req_cmp( const void *l, const void *r ) { const LDAPRequest *left = l, *right = r; return left->lr_msgid - right->lr_msgid; } /* protected by req_mutex */ static void ldap_free_request_int( LDAP *ld, LDAPRequest *lr ) { LDAPRequest *removed; LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); removed = ldap_tavl_delete( &ld->ld_requests, lr, ldap_req_cmp ); assert( !removed || removed == lr ); Debug3( LDAP_DEBUG_TRACE, "ldap_free_request_int: " "lr %p msgid %d%s removed\n", lr, lr->lr_msgid, removed ? "" : " not" ); ldap_do_free_request( lr ); } /* protected by req_mutex */ void ldap_free_request( LDAP *ld, LDAPRequest *lr ) { LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); Debug2( LDAP_DEBUG_TRACE, "ldap_free_request (origid %d, msgid %d)\n", lr->lr_origid, lr->lr_msgid ); /* free all referrals (child requests) */ while ( lr->lr_child ) { ldap_free_request( ld, lr->lr_child ); } if ( lr->lr_parent != NULL ) { LDAPRequest **lrp; --lr->lr_parent->lr_outrefcnt; for ( lrp = &lr->lr_parent->lr_child; *lrp && *lrp != lr; lrp = &(*lrp)->lr_refnext ); if ( *lrp == lr ) { *lrp = lr->lr_refnext; } } ldap_free_request_int( ld, lr ); } /* * call first time with *cntp = -1 * when returns *cntp == -1, no referrals are left * * NOTE: may replace *refsp, or shuffle the contents * of the original array. */ static int ldap_int_nextref( LDAP *ld, char ***refsp, int *cntp, void *params ) { assert( refsp != NULL ); assert( *refsp != NULL ); assert( cntp != NULL ); if ( *cntp < -1 ) { *cntp = -1; return -1; } (*cntp)++; if ( (*refsp)[ *cntp ] == NULL ) { *cntp = -1; } return 0; } /* * Chase v3 referrals * * Parameters: * (IN) ld = LDAP connection handle * (IN) lr = LDAP Request structure * (IN) refs = array of pointers to referral strings that we will chase * The array will be free'd by this function when no longer needed * (IN) sref != 0 if following search reference * (OUT) errstrp = Place to return a string of referrals which could not be followed * (OUT) hadrefp = 1 if successfully followed referral * * Return value - number of referrals followed * * Protected by res_mutex, conn_mutex and req_mutex (try_read1msg) */ int ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char **errstrp, int *hadrefp ) { char *unfollowed; int unfollowedcnt = 0; LDAPRequest *origreq; LDAPURLDesc *srv = NULL; BerElement *ber; char **refarray = NULL; LDAPConn *lc; int rc, count, i, j, id; LDAPreqinfo rinfo; LDAP_NEXTREF_PROC *nextref_proc = ld->ld_nextref_proc ? ld->ld_nextref_proc : ldap_int_nextref; LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); Debug0( LDAP_DEBUG_TRACE, "ldap_chase_v3referrals\n" ); ld->ld_errno = LDAP_SUCCESS; /* optimistic */ *hadrefp = 0; unfollowed = NULL; rc = count = 0; /* If no referrals in array, return */ if ( (refs == NULL) || ( (refs)[0] == NULL) ) { rc = 0; goto done; } /* Check for hop limit exceeded */ if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) { Debug1( LDAP_DEBUG_ANY, "more than %d referral hops (dropping)\n", ld->ld_refhoplimit ); ld->ld_errno = LDAP_REFERRAL_LIMIT_EXCEEDED; rc = -1; goto done; } /* find original request */ for ( origreq = lr; origreq->lr_parent != NULL; origreq = origreq->lr_parent ) { /* empty */ ; } refarray = refs; refs = NULL; /* parse out & follow referrals */ /* NOTE: if nextref_proc == ldap_int_nextref, params is ignored */ i = -1; for ( nextref_proc( ld, &refarray, &i, ld->ld_nextref_params ); i != -1; nextref_proc( ld, &refarray, &i, ld->ld_nextref_params ) ) { /* Parse the referral URL */ rc = ldap_url_parse_ext( refarray[i], &srv, LDAP_PVT_URL_PARSE_NOEMPTY_DN ); if ( rc != LDAP_URL_SUCCESS ) { /* ldap_url_parse_ext() returns LDAP_URL_* errors * which do not map on API errors */ ld->ld_errno = LDAP_PARAM_ERROR; rc = -1; goto done; } if( srv->lud_crit_exts ) { int ok = 0; #ifdef HAVE_TLS /* If StartTLS is the only critical ext, OK. */ if ( find_tls_ext( srv ) == 2 && srv->lud_crit_exts == 1 ) ok = 1; #endif if ( !ok ) { /* we do not support any other extensions */ ld->ld_errno = LDAP_NOT_SUPPORTED; rc = -1; goto done; } } /* check connection for re-bind in progress */ if (( lc = find_connection( ld, srv, 1 )) != NULL ) { /* See if we've already requested this DN with this conn */ LDAPRequest *lp; int looped = 0; ber_len_t len = srv->lud_dn ? strlen( srv->lud_dn ) : 0; for ( lp = origreq; lp; ) { if ( lp->lr_conn == lc && len == lp->lr_dn.bv_len && len && strncmp( srv->lud_dn, lp->lr_dn.bv_val, len ) == 0 ) { looped = 1; break; } if ( lp == origreq ) { lp = lp->lr_child; } else { lp = lp->lr_refnext; } } if ( looped ) { ldap_free_urllist( srv ); srv = NULL; ld->ld_errno = LDAP_CLIENT_LOOP; rc = -1; continue; } if ( lc->lconn_rebind_inprogress ) { /* We are already chasing a referral or search reference and a * bind on that connection is in progress. We must queue * referrals on that connection, so we don't get a request * going out before the bind operation completes. This happens * if two search references come in one behind the other * for the same server with different contexts. */ Debug1( LDAP_DEBUG_TRACE, "ldap_chase_v3referrals: queue referral \"%s\"\n", refarray[i] ); if( lc->lconn_rebind_queue == NULL ) { /* Create a referral list */ lc->lconn_rebind_queue = (char ***) LDAP_MALLOC( sizeof(void *) * 2); if( lc->lconn_rebind_queue == NULL) { ld->ld_errno = LDAP_NO_MEMORY; rc = -1; goto done; } lc->lconn_rebind_queue[0] = refarray; lc->lconn_rebind_queue[1] = NULL; refarray = NULL; } else { /* Count how many referral arrays we already have */ for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++) { /* empty */; } /* Add the new referral to the list */ lc->lconn_rebind_queue = (char ***) LDAP_REALLOC( lc->lconn_rebind_queue, sizeof(void *) * (j + 2)); if( lc->lconn_rebind_queue == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; rc = -1; goto done; } lc->lconn_rebind_queue[j] = refarray; lc->lconn_rebind_queue[j+1] = NULL; refarray = NULL; } /* We have queued the referral/reference, now just return */ rc = 0; *hadrefp = 1; count = 1; /* Pretend we already followed referral */ goto done; } } /* Re-encode the request with the new starting point of the search. * Note: In the future we also need to replace the filter if one * was provided with the search reference */ /* For references we don't want old dn if new dn empty */ if ( sref && srv->lud_dn == NULL ) { srv->lud_dn = LDAP_STRDUP( "" ); } LDAP_NEXT_MSGID( ld, id ); ber = re_encode_request( ld, origreq->lr_ber, id, sref, srv, &rinfo.ri_request ); if( ber == NULL ) { ld->ld_errno = LDAP_ENCODING_ERROR; rc = -1; goto done; } Debug2( LDAP_DEBUG_TRACE, "ldap_chase_v3referral: msgid %d, url \"%s\"\n", lr->lr_msgid, refarray[i] ); /* Send the new request to the server - may require a bind */ rinfo.ri_msgid = origreq->lr_origid; rinfo.ri_url = refarray[i]; rc = ldap_send_server_request( ld, ber, id, origreq, &srv, NULL, &rinfo, 0, 1 ); if ( rc < 0 ) { /* Failure, try next referral in the list */ Debug3( LDAP_DEBUG_ANY, "Unable to chase referral \"%s\" (%d: %s)\n", refarray[i], ld->ld_errno, ldap_err2string( ld->ld_errno ) ); unfollowedcnt += ldap_append_referral( ld, &unfollowed, refarray[i] ); ldap_free_urllist( srv ); srv = NULL; ld->ld_errno = LDAP_REFERRAL; } else { /* Success, no need to try this referral list further */ rc = 0; ++count; *hadrefp = 1; /* check if there is a queue of referrals that came in during bind */ if ( lc == NULL) { lc = find_connection( ld, srv, 1 ); if ( lc == NULL ) { ld->ld_errno = LDAP_OPERATIONS_ERROR; rc = -1; LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); goto done; } } if ( lc->lconn_rebind_queue != NULL ) { /* Release resources of previous list */ LDAP_VFREE( refarray ); refarray = NULL; ldap_free_urllist( srv ); srv = NULL; /* Pull entries off end of queue so list always null terminated */ for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++ ) ; refarray = lc->lconn_rebind_queue[j - 1]; lc->lconn_rebind_queue[j-1] = NULL; /* we pulled off last entry from queue, free queue */ if ( j == 1 ) { LDAP_FREE( lc->lconn_rebind_queue ); lc->lconn_rebind_queue = NULL; } /* restart the loop the with new referral list */ i = -1; continue; } break; /* referral followed, break out of for loop */ } } /* end for loop */ done: LDAP_VFREE( refarray ); ldap_free_urllist( srv ); LDAP_FREE( *errstrp ); if( rc == 0 ) { *errstrp = NULL; LDAP_FREE( unfollowed ); return count; } else { *errstrp = unfollowed; return rc; } } /* * XXX merging of errors in this routine needs to be improved * Protected by res_mutex, conn_mutex and req_mutex (try_read1msg) */ int ldap_chase_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, int sref, int *hadrefp ) { int rc, count, id; unsigned len; char *p, *ref, *unfollowed; LDAPRequest *origreq; LDAPURLDesc *srv; BerElement *ber; LDAPreqinfo rinfo; LDAPConn *lc; LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); Debug0( LDAP_DEBUG_TRACE, "ldap_chase_referrals\n" ); ld->ld_errno = LDAP_SUCCESS; /* optimistic */ *hadrefp = 0; if ( *errstrp == NULL ) { return( 0 ); } len = strlen( *errstrp ); for ( p = *errstrp; len >= LDAP_REF_STR_LEN; ++p, --len ) { if ( strncasecmp( p, LDAP_REF_STR, LDAP_REF_STR_LEN ) == 0 ) { *p = '\0'; p += LDAP_REF_STR_LEN; break; } } if ( len < LDAP_REF_STR_LEN ) { return( 0 ); } if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) { Debug1( LDAP_DEBUG_ANY, "more than %d referral hops (dropping)\n", ld->ld_refhoplimit ); /* XXX report as error in ld->ld_errno? */ return( 0 ); } /* find original request */ for ( origreq = lr; origreq->lr_parent != NULL; origreq = origreq->lr_parent ) { /* empty */; } unfollowed = NULL; rc = count = 0; /* parse out & follow referrals */ for ( ref = p; rc == 0 && ref != NULL; ref = p ) { p = strchr( ref, '\n' ); if ( p != NULL ) { *p++ = '\0'; } rc = ldap_url_parse_ext( ref, &srv, LDAP_PVT_URL_PARSE_NOEMPTY_DN ); if ( rc != LDAP_URL_SUCCESS ) { Debug2( LDAP_DEBUG_TRACE, "ignoring %s referral <%s>\n", ref, rc == LDAP_URL_ERR_BADSCHEME ? "unknown" : "incorrect" ); rc = ldap_append_referral( ld, &unfollowed, ref ); *hadrefp = 1; continue; } Debug1( LDAP_DEBUG_TRACE, "chasing LDAP referral: <%s>\n", ref ); *hadrefp = 1; /* See if we've already been here */ if (( lc = find_connection( ld, srv, 1 )) != NULL ) { LDAPRequest *lp; int looped = 0; ber_len_t len = srv->lud_dn ? strlen( srv->lud_dn ) : 0; for ( lp = lr; lp; lp = lp->lr_parent ) { if ( lp->lr_conn == lc && len == lp->lr_dn.bv_len ) { if ( len && strncmp( srv->lud_dn, lp->lr_dn.bv_val, len ) ) continue; looped = 1; break; } } if ( looped ) { ldap_free_urllist( srv ); ld->ld_errno = LDAP_CLIENT_LOOP; rc = -1; continue; } } LDAP_NEXT_MSGID( ld, id ); ber = re_encode_request( ld, origreq->lr_ber, id, sref, srv, &rinfo.ri_request ); if ( ber == NULL ) { ldap_free_urllist( srv ); return -1 ; } /* copy the complete referral for rebind process */ rinfo.ri_url = LDAP_STRDUP( ref ); rinfo.ri_msgid = origreq->lr_origid; rc = ldap_send_server_request( ld, ber, id, lr, &srv, NULL, &rinfo, 0, 1 ); LDAP_FREE( rinfo.ri_url ); if( rc >= 0 ) { ++count; } else { Debug3( LDAP_DEBUG_ANY, "Unable to chase referral \"%s\" (%d: %s)\n", ref, ld->ld_errno, ldap_err2string( ld->ld_errno ) ); rc = ldap_append_referral( ld, &unfollowed, ref ); } ldap_free_urllist(srv); } LDAP_FREE( *errstrp ); *errstrp = unfollowed; return(( rc == 0 ) ? count : rc ); } int ldap_append_referral( LDAP *ld, char **referralsp, char *s ) { int first; if ( *referralsp == NULL ) { first = 1; *referralsp = (char *)LDAP_MALLOC( strlen( s ) + LDAP_REF_STR_LEN + 1 ); } else { first = 0; *referralsp = (char *)LDAP_REALLOC( *referralsp, strlen( *referralsp ) + strlen( s ) + 2 ); } if ( *referralsp == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return( -1 ); } if ( first ) { strcpy( *referralsp, LDAP_REF_STR ); } else { strcat( *referralsp, "\n" ); } strcat( *referralsp, s ); return( 0 ); } static BerElement * re_encode_request( LDAP *ld, BerElement *origber, ber_int_t msgid, int sref, LDAPURLDesc *srv, int *type ) { /* * XXX this routine knows way too much about how the lber library works! */ ber_int_t along; ber_tag_t tag; ber_tag_t rtag; ber_int_t ver; ber_int_t scope; int rc; BerElement tmpber, *ber; struct berval dn; Debug2( LDAP_DEBUG_TRACE, "re_encode_request: new msgid %ld, new dn <%s>\n", (long) msgid, ( srv == NULL || srv->lud_dn == NULL) ? "NONE" : srv->lud_dn ); tmpber = *origber; /* * all LDAP requests are sequences that start with a message id. * For all except delete, this is followed by a sequence that is * tagged with the operation code. For delete, the provided DN * is not wrapped by a sequence. */ rtag = ber_scanf( &tmpber, "{it", /*}*/ &along, &tag ); if ( rtag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; return( NULL ); } assert( tag != 0); if ( tag == LDAP_REQ_BIND ) { /* bind requests have a version number before the DN & other stuff */ rtag = ber_scanf( &tmpber, "{im" /*}*/, &ver, &dn ); } else if ( tag == LDAP_REQ_DELETE ) { /* delete requests don't have a DN wrapping sequence */ rtag = ber_scanf( &tmpber, "m", &dn ); } else if ( tag == LDAP_REQ_SEARCH ) { /* search requests need to be re-scope-ed */ rtag = ber_scanf( &tmpber, "{me" /*"}"*/, &dn, &scope ); if( srv->lud_scope != LDAP_SCOPE_DEFAULT ) { /* use the scope provided in reference */ scope = srv->lud_scope; } else if ( sref ) { /* use scope implied by previous operation * base -> base * one -> base * subtree -> subtree * subordinate -> subtree */ switch( scope ) { default: case LDAP_SCOPE_BASE: case LDAP_SCOPE_ONELEVEL: scope = LDAP_SCOPE_BASE; break; case LDAP_SCOPE_SUBTREE: case LDAP_SCOPE_SUBORDINATE: scope = LDAP_SCOPE_SUBTREE; break; } } } else { rtag = ber_scanf( &tmpber, "{m" /*}*/, &dn ); } if( rtag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; return NULL; } /* restore character zero'd out by ber_scanf*/ dn.bv_val[dn.bv_len] = tmpber.ber_tag; if (( ber = ldap_alloc_ber_with_options( ld )) == NULL ) { return NULL; } if ( srv->lud_dn ) { ber_str2bv( srv->lud_dn, 0, 0, &dn ); } if ( tag == LDAP_REQ_BIND ) { rc = ber_printf( ber, "{it{iO" /*}}*/, msgid, tag, ver, &dn ); } else if ( tag == LDAP_REQ_DELETE ) { rc = ber_printf( ber, "{itON}", msgid, tag, &dn ); } else if ( tag == LDAP_REQ_SEARCH ) { rc = ber_printf( ber, "{it{Oe" /*}}*/, msgid, tag, &dn, scope ); } else { rc = ber_printf( ber, "{it{O" /*}}*/, msgid, tag, &dn ); } if ( rc == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return NULL; } if ( tag != LDAP_REQ_DELETE && ( ber_write(ber, tmpber.ber_ptr, ( tmpber.ber_end - tmpber.ber_ptr ), 0) != ( tmpber.ber_end - tmpber.ber_ptr ) || ber_printf( ber, /*{{*/ "N}N}" ) == -1 ) ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return NULL; } #ifdef LDAP_DEBUG if ( ldap_debug & LDAP_DEBUG_PACKETS ) { Debug0( LDAP_DEBUG_ANY, "re_encode_request new request is:\n" ); ber_log_dump( LDAP_DEBUG_BER, ldap_debug, ber, 0 ); } #endif /* LDAP_DEBUG */ *type = tag; /* return request type */ return ber; } /* protected by req_mutex */ LDAPRequest * ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid ) { LDAPRequest *lr, needle = {0}; needle.lr_msgid = msgid; lr = ldap_tavl_find( ld->ld_requests, &needle, ldap_req_cmp ); if ( lr != NULL && lr->lr_status != LDAP_REQST_COMPLETED ) { /* lr_refcnt is only negative when we removed it from ld_requests * already, it is positive if we have sub-requests (referrals) */ assert( lr->lr_refcnt >= 0 ); lr->lr_refcnt++; Debug3( LDAP_DEBUG_TRACE, "ldap_find_request_by_msgid: " "msgid %d, lr %p lr->lr_refcnt = %d\n", msgid, lr, lr->lr_refcnt ); return lr; } Debug2( LDAP_DEBUG_TRACE, "ldap_find_request_by_msgid: " "msgid %d, lr %p\n", msgid, lr ); return NULL; } /* protected by req_mutex */ void ldap_return_request( LDAP *ld, LDAPRequest *lrx, int freeit ) { LDAPRequest *lr; lr = ldap_tavl_find( ld->ld_requests, lrx, ldap_req_cmp ); Debug2( LDAP_DEBUG_TRACE, "ldap_return_request: " "lrx %p, lr %p\n", lrx, lr ); if ( lr ) { assert( lr == lrx ); if ( lr->lr_refcnt > 0 ) { lr->lr_refcnt--; } else if ( lr->lr_refcnt < 0 ) { lr->lr_refcnt++; if ( lr->lr_refcnt == 0 ) { lr = NULL; } } } Debug3( LDAP_DEBUG_TRACE, "ldap_return_request: " "lrx->lr_msgid %d, lrx->lr_refcnt is now %d, lr is %s present\n", lrx->lr_msgid, lrx->lr_refcnt, lr ? "still" : "not" ); /* The request is not tracked anymore */ if ( lr == NULL ) { ldap_free_request_int( ld, lrx ); } else if ( freeit ) { ldap_free_request( ld, lrx ); } } openldap-2.5.11+dfsg/libraries/libldap/controls.c0000644000175000017500000002524514172327167020441 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* This notice applies to changes, created by or for Novell, Inc., * to preexisting works for which notices appear elsewhere in this file. * * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved. * * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES. * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. *--- * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License * can be found in the file "build/LICENSE-2.0.1" in this distribution * of OpenLDAP Software. */ #include "portable.h" #include #include #include #include "ldap-int.h" /* LDAPv3 Controls (RFC 4511) * * Controls ::= SEQUENCE OF control Control * * Control ::= SEQUENCE { * controlType LDAPOID, * criticality BOOLEAN DEFAULT FALSE, * controlValue OCTET STRING OPTIONAL * } */ int ldap_pvt_put_control( const LDAPControl *c, BerElement *ber ) { if ( ber_printf( ber, "{s" /*}*/, c->ldctl_oid ) == -1 ) { return LDAP_ENCODING_ERROR; } if ( c->ldctl_iscritical /* only if true */ && ( ber_printf( ber, "b", (ber_int_t) c->ldctl_iscritical ) == -1 ) ) { return LDAP_ENCODING_ERROR; } if ( !BER_BVISNULL( &c->ldctl_value ) /* only if we have a value */ && ( ber_printf( ber, "O", &c->ldctl_value ) == -1 ) ) { return LDAP_ENCODING_ERROR; } if ( ber_printf( ber, /*{*/"N}" ) == -1 ) { return LDAP_ENCODING_ERROR; } return LDAP_SUCCESS; } /* * ldap_int_put_controls */ int ldap_int_put_controls( LDAP *ld, LDAPControl *const *ctrls, BerElement *ber ) { LDAPControl *const *c; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( ber != NULL ); if( ctrls == NULL ) { /* use default server controls */ ctrls = ld->ld_sctrls; } if( ctrls == NULL || *ctrls == NULL ) { return LDAP_SUCCESS; } if ( ld->ld_version < LDAP_VERSION3 ) { /* LDAPv2 doesn't support controls, * error if any control is critical */ for( c = ctrls ; *c != NULL; c++ ) { if( (*c)->ldctl_iscritical ) { ld->ld_errno = LDAP_NOT_SUPPORTED; return ld->ld_errno; } } return LDAP_SUCCESS; } /* Controls are encoded as a sequence of sequences */ if( ber_printf( ber, "t{"/*}*/, LDAP_TAG_CONTROLS ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; return ld->ld_errno; } for( c = ctrls ; *c != NULL; c++ ) { ld->ld_errno = ldap_pvt_put_control( *c, ber ); if ( ld->ld_errno != LDAP_SUCCESS ) { return ld->ld_errno; } } if( ber_printf( ber, /*{*/ "}" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; return ld->ld_errno; } return LDAP_SUCCESS; } int ldap_pvt_get_controls( BerElement *ber, LDAPControl ***ctrls ) { int nctrls; ber_tag_t tag; ber_len_t len; char *opaque; assert( ber != NULL ); if( ctrls == NULL ) { return LDAP_SUCCESS; } *ctrls = NULL; len = ber_pvt_ber_remaining( ber ); if( len == 0) { /* no controls */ return LDAP_SUCCESS; } if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) { if( tag == LBER_ERROR ) { /* decoding error */ return LDAP_DECODING_ERROR; } /* ignore unexpected input */ return LDAP_SUCCESS; } /* set through each element */ nctrls = 0; *ctrls = LDAP_MALLOC( 1 * sizeof(LDAPControl *) ); if( *ctrls == NULL ) { return LDAP_NO_MEMORY; } *ctrls[nctrls] = NULL; for( tag = ber_first_element( ber, &len, &opaque ); tag != LBER_ERROR; tag = ber_next_element( ber, &len, opaque ) ) { LDAPControl *tctrl; LDAPControl **tctrls; tctrl = LDAP_CALLOC( 1, sizeof(LDAPControl) ); /* allocate pointer space for current controls (nctrls) * + this control + extra NULL */ tctrls = (tctrl == NULL) ? NULL : LDAP_REALLOC(*ctrls, (nctrls+2) * sizeof(LDAPControl *)); if( tctrls == NULL ) { /* one of the above allocation failed */ if( tctrl != NULL ) { LDAP_FREE( tctrl ); } ldap_controls_free(*ctrls); *ctrls = NULL; return LDAP_NO_MEMORY; } tctrls[nctrls++] = tctrl; tctrls[nctrls] = NULL; tag = ber_scanf( ber, "{a" /*}*/, &tctrl->ldctl_oid ); if( tag == LBER_ERROR ) { *ctrls = NULL; ldap_controls_free( tctrls ); return LDAP_DECODING_ERROR; } tag = ber_peek_tag( ber, &len ); if( tag == LBER_BOOLEAN ) { ber_int_t crit; tag = ber_scanf( ber, "b", &crit ); tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0; tag = ber_peek_tag( ber, &len ); } if( tag == LBER_OCTETSTRING ) { tag = ber_scanf( ber, "o", &tctrl->ldctl_value ); } else { BER_BVZERO( &tctrl->ldctl_value ); } *ctrls = tctrls; } return LDAP_SUCCESS; } /* * Free a LDAPControl */ void ldap_control_free( LDAPControl *c ) { LDAP_MEMORY_DEBUG_ASSERT( c != NULL ); if ( c != NULL ) { if( c->ldctl_oid != NULL) { LDAP_FREE( c->ldctl_oid ); } if( c->ldctl_value.bv_val != NULL ) { LDAP_FREE( c->ldctl_value.bv_val ); } LDAP_FREE( c ); } } /* * Free an array of LDAPControl's */ void ldap_controls_free( LDAPControl **controls ) { LDAP_MEMORY_DEBUG_ASSERT( controls != NULL ); if ( controls != NULL ) { int i; for( i=0; controls[i] != NULL; i++) { ldap_control_free( controls[i] ); } LDAP_FREE( controls ); } } /* * Duplicate an array of LDAPControl */ LDAPControl ** ldap_controls_dup( LDAPControl *const *controls ) { LDAPControl **new; int i; if ( controls == NULL ) { return NULL; } /* count the controls */ for(i=0; controls[i] != NULL; i++) /* empty */ ; if( i < 1 ) { /* no controls to duplicate */ return NULL; } new = (LDAPControl **) LDAP_MALLOC( (i+1) * sizeof(LDAPControl *) ); if( new == NULL ) { /* memory allocation failure */ return NULL; } /* duplicate the controls */ for(i=0; controls[i] != NULL; i++) { new[i] = ldap_control_dup( controls[i] ); if( new[i] == NULL ) { ldap_controls_free( new ); return NULL; } } new[i] = NULL; return new; } /* * Duplicate a LDAPControl */ LDAPControl * ldap_control_dup( const LDAPControl *c ) { LDAPControl *new; if ( c == NULL || c->ldctl_oid == NULL ) { return NULL; } new = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) ); if( new == NULL ) { return NULL; } new->ldctl_oid = LDAP_STRDUP( c->ldctl_oid ); if(new->ldctl_oid == NULL) { LDAP_FREE( new ); return NULL; } if( c->ldctl_value.bv_val != NULL ) { new->ldctl_value.bv_val = (char *) LDAP_MALLOC( c->ldctl_value.bv_len + 1 ); if(new->ldctl_value.bv_val == NULL) { if(new->ldctl_oid != NULL) { LDAP_FREE( new->ldctl_oid ); } LDAP_FREE( new ); return NULL; } new->ldctl_value.bv_len = c->ldctl_value.bv_len; AC_MEMCPY( new->ldctl_value.bv_val, c->ldctl_value.bv_val, c->ldctl_value.bv_len ); new->ldctl_value.bv_val[new->ldctl_value.bv_len] = '\0'; } else { new->ldctl_value.bv_len = 0; new->ldctl_value.bv_val = NULL; } new->ldctl_iscritical = c->ldctl_iscritical; return new; } /* * Find a LDAPControl - deprecated */ LDAPControl * ldap_find_control( LDAP_CONST char *oid, LDAPControl **ctrls ) { if( ctrls == NULL || *ctrls == NULL ) { return NULL; } for( ; *ctrls != NULL; ctrls++ ) { if( strcmp( (*ctrls)->ldctl_oid, oid ) == 0 ) { return *ctrls; } } return NULL; } /* * Find a LDAPControl */ LDAPControl * ldap_control_find( LDAP_CONST char *oid, LDAPControl **ctrls, LDAPControl ***nextctrlp ) { if ( oid == NULL || ctrls == NULL || *ctrls == NULL ) { return NULL; } for( ; *ctrls != NULL; ctrls++ ) { if( strcmp( (*ctrls)->ldctl_oid, oid ) == 0 ) { if ( nextctrlp != NULL ) { *nextctrlp = ctrls + 1; } return *ctrls; } } if ( nextctrlp != NULL ) { *nextctrlp = NULL; } return NULL; } /* * Create a LDAPControl, optionally from ber - deprecated */ int ldap_create_control( LDAP_CONST char *requestOID, BerElement *ber, int iscritical, LDAPControl **ctrlp ) { LDAPControl *ctrl; assert( requestOID != NULL ); assert( ctrlp != NULL ); ctrl = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) ); if ( ctrl == NULL ) { return LDAP_NO_MEMORY; } BER_BVZERO(&ctrl->ldctl_value); if ( ber && ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 )) { LDAP_FREE( ctrl ); return LDAP_NO_MEMORY; } ctrl->ldctl_oid = LDAP_STRDUP( requestOID ); ctrl->ldctl_iscritical = iscritical; if ( requestOID != NULL && ctrl->ldctl_oid == NULL ) { ldap_control_free( ctrl ); return LDAP_NO_MEMORY; } *ctrlp = ctrl; return LDAP_SUCCESS; } /* * Create a LDAPControl, optionally from value */ int ldap_control_create( LDAP_CONST char *requestOID, int iscritical, struct berval *value, int dupval, LDAPControl **ctrlp ) { LDAPControl *ctrl; assert( requestOID != NULL ); assert( ctrlp != NULL ); ctrl = (LDAPControl *) LDAP_CALLOC( sizeof(LDAPControl), 1 ); if ( ctrl == NULL ) { return LDAP_NO_MEMORY; } ctrl->ldctl_iscritical = iscritical; if ( requestOID != NULL ) { ctrl->ldctl_oid = LDAP_STRDUP( requestOID ); if ( ctrl->ldctl_oid == NULL ) { ldap_control_free( ctrl ); return LDAP_NO_MEMORY; } } if ( value && !BER_BVISNULL( value ) ) { if ( dupval ) { ber_dupbv( &ctrl->ldctl_value, value ); if ( BER_BVISNULL( &ctrl->ldctl_value ) ) { ldap_control_free( ctrl ); return LDAP_NO_MEMORY; } } else { ctrl->ldctl_value = *value; } } *ctrlp = ctrl; return LDAP_SUCCESS; } /* * check for critical client controls and bitch if present * if we ever support critical controls, we'll have to * find a means for maintaining per API call control * information. */ int ldap_int_client_controls( LDAP *ld, LDAPControl **ctrls ) { LDAPControl *const *c; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); if( ctrls == NULL ) { /* use default client controls */ ctrls = ld->ld_cctrls; } if( ctrls == NULL || *ctrls == NULL ) { return LDAP_SUCCESS; } for( c = ctrls ; *c != NULL; c++ ) { if( (*c)->ldctl_iscritical ) { ld->ld_errno = LDAP_NOT_SUPPORTED; return ld->ld_errno; } } return LDAP_SUCCESS; } openldap-2.5.11+dfsg/libraries/libldap/pagectrl.c0000644000175000017500000001564114172327167020376 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * Copyright 2006 Hans Leidekker * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include "ldap-int.h" /* --------------------------------------------------------------------------- ldap_create_page_control_value Create and encode the value of the paged results control (RFC 2696). ld (IN) An LDAP session handle pagesize (IN) Page size requested cookie (IN) Opaque structure used by the server to track its location in the search results. NULL on the first call. value (OUT) Control value, SHOULD be freed by calling ldap_memfree() when done. pagedResultsControl ::= SEQUENCE { controlType 1.2.840.113556.1.4.319, criticality BOOLEAN DEFAULT FALSE, controlValue searchControlValue } searchControlValue ::= SEQUENCE { size INTEGER (0..maxInt), -- requested page size from client -- result set size estimate from server cookie OCTET STRING } ---------------------------------------------------------------------------*/ int ldap_create_page_control_value( LDAP *ld, ber_int_t pagesize, struct berval *cookie, struct berval *value ) { BerElement *ber = NULL; ber_tag_t tag; struct berval null_cookie = { 0, NULL }; if ( ld == NULL || value == NULL || pagesize < 1 || pagesize > LDAP_MAXINT ) { if ( ld ) ld->ld_errno = LDAP_PARAM_ERROR; return LDAP_PARAM_ERROR; } assert( LDAP_VALID( ld ) ); value->bv_val = NULL; value->bv_len = 0; ld->ld_errno = LDAP_SUCCESS; if ( cookie == NULL ) { cookie = &null_cookie; } ber = ldap_alloc_ber_with_options( ld ); if ( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } tag = ber_printf( ber, "{iO}", pagesize, cookie ); if ( tag == LBER_ERROR ) { ld->ld_errno = LDAP_ENCODING_ERROR; goto done; } if ( ber_flatten2( ber, value, 1 ) == -1 ) { ld->ld_errno = LDAP_NO_MEMORY; } done:; if ( ber != NULL ) { ber_free( ber, 1 ); } return ld->ld_errno; } /* --------------------------------------------------------------------------- ldap_create_page_control Create and encode a page control. ld (IN) An LDAP session handle pagesize (IN) Page size requested cookie (IN) Opaque structure used by the server to track its location in the search results. NULL on the first call. value (OUT) Control value, SHOULD be freed by calling ldap_memfree() when done. iscritical (IN) Criticality ctrlp (OUT) LDAP control, SHOULD be freed by calling ldap_control_free() when done. pagedResultsControl ::= SEQUENCE { controlType 1.2.840.113556.1.4.319, criticality BOOLEAN DEFAULT FALSE, controlValue searchControlValue } searchControlValue ::= SEQUENCE { size INTEGER (0..maxInt), -- requested page size from client -- result set size estimate from server cookie OCTET STRING } ---------------------------------------------------------------------------*/ int ldap_create_page_control( LDAP *ld, ber_int_t pagesize, struct berval *cookie, int iscritical, LDAPControl **ctrlp ) { struct berval value; if ( ctrlp == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; } ld->ld_errno = ldap_create_page_control_value( ld, pagesize, cookie, &value ); if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = ldap_control_create( LDAP_CONTROL_PAGEDRESULTS, iscritical, &value, 0, ctrlp ); if ( ld->ld_errno != LDAP_SUCCESS ) { LDAP_FREE( value.bv_val ); } } return ld->ld_errno; } /* --------------------------------------------------------------------------- ldap_parse_pageresponse_control Decode a page control. ld (IN) An LDAP session handle ctrl (IN) The page response control count (OUT) The number of entries in the page. cookie (OUT) Opaque cookie. Use ldap_memfree() to free the bv_val member of this structure. ---------------------------------------------------------------------------*/ int ldap_parse_pageresponse_control( LDAP *ld, LDAPControl *ctrl, ber_int_t *countp, struct berval *cookie ) { BerElement *ber; ber_tag_t tag; ber_int_t count; if ( ld == NULL || ctrl == NULL || cookie == NULL ) { if ( ld ) ld->ld_errno = LDAP_PARAM_ERROR; return LDAP_PARAM_ERROR; } /* Create a BerElement from the berval returned in the control. */ ber = ber_init( &ctrl->ldctl_value ); if ( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } /* Extract the count and cookie from the control. */ tag = ber_scanf( ber, "{io}", &count, cookie ); ber_free( ber, 1 ); if ( tag == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; } else { ld->ld_errno = LDAP_SUCCESS; if ( countp != NULL ) { *countp = (unsigned long)count; } } return ld->ld_errno; } /* --------------------------------------------------------------------------- ldap_parse_page_control Decode a page control. ld (IN) An LDAP session handle ctrls (IN) Response controls count (OUT) The number of entries in the page. cookie (OUT) Opaque cookie. Use ldap_memfree() to free the bv_val member of this structure. ---------------------------------------------------------------------------*/ int ldap_parse_page_control( LDAP *ld, LDAPControl **ctrls, ber_int_t *countp, struct berval **cookiep ) { LDAPControl *c; struct berval cookie; if ( cookiep == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; } if ( ctrls == NULL ) { ld->ld_errno = LDAP_CONTROL_NOT_FOUND; return ld->ld_errno; } c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, ctrls, NULL ); if ( c == NULL ) { /* No page control was found. */ ld->ld_errno = LDAP_CONTROL_NOT_FOUND; return ld->ld_errno; } ld->ld_errno = ldap_parse_pageresponse_control( ld, c, countp, &cookie ); if ( ld->ld_errno == LDAP_SUCCESS ) { *cookiep = LDAP_MALLOC( sizeof( struct berval ) ); if ( *cookiep == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; } else { **cookiep = cookie; } } return ld->ld_errno; } openldap-2.5.11+dfsg/libraries/libldap/os-ip.c0000644000175000017500000006613514172327167017630 0ustar ryanryan/* os-ip.c -- platform-specific TCP & UDP related code */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * Portions Copyright 1999 Lars Uffmann. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. */ /* Significant additional contributors include: * Lars Uffman */ #include "portable.h" #include #include #include #include #include #include #include #ifdef HAVE_IO_H #include #endif /* HAVE_IO_H */ #ifdef HAVE_FCNTL_H #include #endif #include "ldap-int.h" #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) # ifdef LDAP_PF_INET6 int ldap_int_inet4or6 = AF_UNSPEC; # else int ldap_int_inet4or6 = AF_INET; # endif #endif static void ldap_pvt_set_errno(int err) { sock_errset(err); } int ldap_int_timeval_dup( struct timeval **dest, const struct timeval *src ) { struct timeval *new; assert( dest != NULL ); if (src == NULL) { *dest = NULL; return 0; } new = (struct timeval *) LDAP_MALLOC(sizeof(struct timeval)); if( new == NULL ) { *dest = NULL; return 1; } AC_MEMCPY( (char *) new, (const char *) src, sizeof(struct timeval)); *dest = new; return 0; } static int ldap_pvt_ndelay_on(LDAP *ld, int fd) { Debug1(LDAP_DEBUG_TRACE, "ldap_ndelay_on: %d\n",fd ); return ber_pvt_socket_set_nonblock( fd, 1 ); } static int ldap_pvt_ndelay_off(LDAP *ld, int fd) { Debug1(LDAP_DEBUG_TRACE, "ldap_ndelay_off: %d\n",fd ); return ber_pvt_socket_set_nonblock( fd, 0 ); } static ber_socket_t ldap_int_socket(LDAP *ld, int family, int type ) { ber_socket_t s = socket(family, type, 0); Debug1(LDAP_DEBUG_TRACE, "ldap_new_socket: %d\n",s ); #ifdef FD_CLOEXEC fcntl(s, F_SETFD, FD_CLOEXEC); #endif return ( s ); } static int ldap_pvt_close_socket(LDAP *ld, int s) { Debug1(LDAP_DEBUG_TRACE, "ldap_close_socket: %d\n",s ); return tcp_close(s); } static int ldap_int_prepare_socket(LDAP *ld, int s, int proto ) { Debug1(LDAP_DEBUG_TRACE, "ldap_prepare_socket: %d\n", s ); #if defined( SO_KEEPALIVE ) || defined( TCP_NODELAY ) || defined( TCP_USER_TIMEOUT ) if ( proto == LDAP_PROTO_TCP ) { int dummy = 1; #ifdef SO_KEEPALIVE if ( setsockopt( s, SOL_SOCKET, SO_KEEPALIVE, (char*) &dummy, sizeof(dummy) ) == AC_SOCKET_ERROR ) { Debug1(LDAP_DEBUG_TRACE, "ldap_prepare_socket: " "setsockopt(%d, SO_KEEPALIVE) failed (ignored).\n", s ); } if ( ld->ld_options.ldo_keepalive_idle > 0 ) { #ifdef TCP_KEEPIDLE if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPIDLE, (void*) &ld->ld_options.ldo_keepalive_idle, sizeof(ld->ld_options.ldo_keepalive_idle) ) == AC_SOCKET_ERROR ) { Debug1(LDAP_DEBUG_TRACE, "ldap_prepare_socket: " "setsockopt(%d, TCP_KEEPIDLE) failed (ignored).\n", s ); } #else Debug0(LDAP_DEBUG_TRACE, "ldap_prepare_socket: " "sockopt TCP_KEEPIDLE not supported on this system.\n" ); #endif /* TCP_KEEPIDLE */ } if ( ld->ld_options.ldo_keepalive_probes > 0 ) { #ifdef TCP_KEEPCNT if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPCNT, (void*) &ld->ld_options.ldo_keepalive_probes, sizeof(ld->ld_options.ldo_keepalive_probes) ) == AC_SOCKET_ERROR ) { Debug1(LDAP_DEBUG_TRACE, "ldap_prepare_socket: " "setsockopt(%d, TCP_KEEPCNT) failed (ignored).\n", s ); } #else Debug0(LDAP_DEBUG_TRACE, "ldap_prepare_socket: " "sockopt TCP_KEEPCNT not supported on this system.\n" ); #endif /* TCP_KEEPCNT */ } if ( ld->ld_options.ldo_keepalive_interval > 0 ) { #ifdef TCP_KEEPINTVL if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPINTVL, (void*) &ld->ld_options.ldo_keepalive_interval, sizeof(ld->ld_options.ldo_keepalive_interval) ) == AC_SOCKET_ERROR ) { Debug1(LDAP_DEBUG_TRACE, "ldap_prepare_socket: " "setsockopt(%d, TCP_KEEPINTVL) failed (ignored).\n", s ); } #else Debug0(LDAP_DEBUG_TRACE, "ldap_prepare_socket: " "sockopt TCP_KEEPINTVL not supported on this system.\n" ); #endif /* TCP_KEEPINTVL */ } #endif /* SO_KEEPALIVE */ #ifdef TCP_NODELAY if ( setsockopt( s, IPPROTO_TCP, TCP_NODELAY, (char*) &dummy, sizeof(dummy) ) == AC_SOCKET_ERROR ) { Debug1(LDAP_DEBUG_TRACE, "ldap_prepare_socket: " "setsockopt(%d, TCP_NODELAY) failed (ignored).\n", s ); } #endif /* TCP_NODELAY */ if ( ld->ld_options.ldo_tcp_user_timeout > 0 ) { #ifdef TCP_USER_TIMEOUT if ( setsockopt( s, IPPROTO_TCP, TCP_USER_TIMEOUT, (void*) &ld->ld_options.ldo_tcp_user_timeout, sizeof(ld->ld_options.ldo_tcp_user_timeout) ) == AC_SOCKET_ERROR ) { Debug1(LDAP_DEBUG_TRACE, "ldap_prepare_socket: " "setsockopt(%d, TCP_USER_TIMEOUT) failed (ignored).\n", s ); } #else Debug0(LDAP_DEBUG_TRACE, "ldap_prepare_socket: " "sockopt TCP_USER_TIMEOUT not supported on this system.\n" ); #endif /* TCP_USER_TIMEOUT */ } } #endif /* SO_KEEPALIVE || TCP_NODELAY || TCP_USER_TIMEOUT */ return 0; } #ifndef HAVE_WINSOCK #undef TRACE #define TRACE do { \ char ebuf[128]; \ int saved_errno = errno; \ Debug3(LDAP_DEBUG_TRACE, "ldap_is_socket_ready: error on socket %d: errno: %d (%s)\n", \ s, \ saved_errno, \ sock_errstr(saved_errno, ebuf, sizeof(ebuf)) ); \ } while( 0 ) /* * check the socket for errors after select returned. */ static int ldap_pvt_is_socket_ready(LDAP *ld, int s) { Debug1(LDAP_DEBUG_TRACE, "ldap_is_sock_ready: %d\n",s ); #if defined( notyet ) /* && defined( SO_ERROR ) */ { int so_errno; ber_socklen_t dummy = sizeof(so_errno); if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy ) == AC_SOCKET_ERROR ) { return -1; } if ( so_errno ) { ldap_pvt_set_errno(so_errno); TRACE; return -1; } return 0; } #else { /* error slippery */ #ifdef LDAP_PF_INET6 struct sockaddr_storage sin; #else struct sockaddr_in sin; #endif char ch; ber_socklen_t dummy = sizeof(sin); if ( getpeername( s, (struct sockaddr *) &sin, &dummy ) == AC_SOCKET_ERROR ) { /* XXX: needs to be replace with ber_stream_read() */ (void)!read(s, &ch, 1); TRACE; return -1; } return 0; } #endif return -1; } #undef TRACE #endif /* HAVE_WINSOCK */ /* NOTE: this is identical to analogous code in os-local.c */ int ldap_int_poll( LDAP *ld, ber_socket_t s, struct timeval *tvp, int wr ) { int rc; Debug2(LDAP_DEBUG_TRACE, "ldap_int_poll: fd: %d tm: %ld\n", s, tvp ? tvp->tv_sec : -1L ); #ifdef HAVE_POLL { struct pollfd fd; int timeout = INFTIM; short event = wr ? POLL_WRITE : POLL_READ; fd.fd = s; fd.events = event; if ( tvp != NULL ) { timeout = TV2MILLISEC( tvp ); } do { fd.revents = 0; rc = poll( &fd, 1, timeout ); } while ( rc == AC_SOCKET_ERROR && errno == EINTR && LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ) ); if ( rc == AC_SOCKET_ERROR ) { return rc; } if ( timeout == 0 && rc == 0 ) { return -2; } if ( fd.revents & event ) { if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) { return -1; } if ( ldap_pvt_ndelay_off( ld, s ) == -1 ) { return -1; } return 0; } } #else { fd_set wfds, *z = NULL; #ifdef HAVE_WINSOCK fd_set efds; #endif struct timeval tv = { 0 }; #if defined( FD_SETSIZE ) && !defined( HAVE_WINSOCK ) if ( s >= FD_SETSIZE ) { rc = AC_SOCKET_ERROR; tcp_close( s ); ldap_pvt_set_errno( EMFILE ); return rc; } #endif if ( tvp != NULL ) { tv = *tvp; } do { FD_ZERO(&wfds); FD_SET(s, &wfds ); #ifdef HAVE_WINSOCK FD_ZERO(&efds); FD_SET(s, &efds ); #endif rc = select( ldap_int_tblsize, z, &wfds, #ifdef HAVE_WINSOCK &efds, #else z, #endif tvp ? &tv : NULL ); } while ( rc == AC_SOCKET_ERROR && errno == EINTR && LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ) ); if ( rc == AC_SOCKET_ERROR ) { return rc; } if ( rc == 0 && tvp && tvp->tv_sec == 0 && tvp->tv_usec == 0 ) { return -2; } #ifdef HAVE_WINSOCK /* This means the connection failed */ if ( FD_ISSET(s, &efds) ) { int so_errno; ber_socklen_t dummy = sizeof(so_errno); if ( getsockopt( s, SOL_SOCKET, SO_ERROR, (char *) &so_errno, &dummy ) == AC_SOCKET_ERROR || !so_errno ) { /* impossible */ so_errno = WSAGetLastError(); } ldap_pvt_set_errno( so_errno ); Debug3(LDAP_DEBUG_TRACE, "ldap_int_poll: error on socket %d: " "errno: %d (%s)\n", s, so_errno, sock_errstr( so_errno, dummy, dummy )); return -1; } #endif if ( FD_ISSET(s, &wfds) ) { #ifndef HAVE_WINSOCK if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) { return -1; } #endif if ( ldap_pvt_ndelay_off(ld, s) == -1 ) { return -1; } return 0; } } #endif Debug0(LDAP_DEBUG_TRACE, "ldap_int_poll: timed out\n" ); ldap_pvt_set_errno( ETIMEDOUT ); return -1; } static int ldap_pvt_connect(LDAP *ld, ber_socket_t s, struct sockaddr *sin, ber_socklen_t addrlen, int async) { int rc, err; struct timeval tv, *opt_tv = NULL; #ifdef LDAP_CONNECTIONLESS /* We could do a connect() but that would interfere with * attempts to poll a broadcast address */ if (LDAP_IS_UDP(ld)) { if (ld->ld_options.ldo_peer) ldap_memfree(ld->ld_options.ldo_peer); ld->ld_options.ldo_peer=ldap_memcalloc(1, sizeof(struct sockaddr_storage)); AC_MEMCPY(ld->ld_options.ldo_peer,sin,addrlen); return ( 0 ); } #endif if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) { tv = ld->ld_options.ldo_tm_net; opt_tv = &tv; } Debug3(LDAP_DEBUG_TRACE, "ldap_pvt_connect: fd: %d tm: %ld async: %d\n", s, opt_tv ? tv.tv_sec : -1L, async); if ( opt_tv && ldap_pvt_ndelay_on(ld, s) == -1 ) return ( -1 ); do{ Debug0(LDAP_DEBUG_TRACE, "attempting to connect: \n" ); if ( connect(s, sin, addrlen) != AC_SOCKET_ERROR ) { Debug0(LDAP_DEBUG_TRACE, "connect success\n" ); if ( !async && opt_tv && ldap_pvt_ndelay_off(ld, s) == -1 ) return ( -1 ); return ( 0 ); } err = sock_errno(); Debug1(LDAP_DEBUG_TRACE, "connect errno: %d\n", err ); } while(err == EINTR && LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART )); if ( err != EINPROGRESS && err != EWOULDBLOCK ) { return ( -1 ); } if ( async ) { /* caller will call ldap_int_poll() as appropriate? */ return ( -2 ); } rc = ldap_int_poll( ld, s, opt_tv, 1 ); Debug1(LDAP_DEBUG_TRACE, "ldap_pvt_connect: %d\n", rc ); return rc; } #ifndef HAVE_INET_ATON int ldap_pvt_inet_aton( const char *host, struct in_addr *in) { unsigned long u = inet_addr( host ); #ifdef INADDR_NONE if ( u == INADDR_NONE ) return 0; #endif if ( u == 0xffffffffUL || u == (unsigned long) -1L ) return 0; in->s_addr = u; return 1; } #endif int ldap_validate_and_fill_sourceip (char** source_ip_lst, ldapsourceip* temp_source_ip ) { int i = 0; int rc = LDAP_PARAM_ERROR; for ( i = 0; source_ip_lst[i] != NULL; i++ ) { Debug1( LDAP_DEBUG_TRACE, "ldap_validate_and_fill_sourceip(%s)\n", source_ip_lst[i] ); if ( !temp_source_ip->has_ipv4 ) { if ( inet_aton( source_ip_lst[i], &temp_source_ip->ip4_addr ) ) { temp_source_ip->has_ipv4 = 1; rc = LDAP_OPT_SUCCESS; continue; } } #ifdef LDAP_PF_INET6 if ( !temp_source_ip->has_ipv6 ) { if ( inet_pton( AF_INET6, source_ip_lst[i], & temp_source_ip->ip6_addr ) ) { temp_source_ip->has_ipv6 = 1; rc = LDAP_OPT_SUCCESS; continue; } } #endif memset( temp_source_ip, 0, sizeof( * (temp_source_ip ) ) ); Debug1( LDAP_DEBUG_TRACE, "ldap_validate_and_fill_sourceip: validation failed for (%s)\n", source_ip_lst[i] ); break; } return rc; } int ldap_int_connect_cbs(LDAP *ld, Sockbuf *sb, ber_socket_t *s, LDAPURLDesc *srv, struct sockaddr *addr) { struct ldapoptions *lo; ldaplist *ll; ldap_conncb *cb; int rc; ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, s ); /* Invoke all handle-specific callbacks first */ lo = &ld->ld_options; for (ll = lo->ldo_conn_cbs; ll; ll = ll->ll_next) { cb = ll->ll_data; rc = cb->lc_add( ld, sb, srv, addr, cb ); /* on any failure, call the teardown functions for anything * that previously succeeded */ if ( rc ) { ldaplist *l2; for (l2 = lo->ldo_conn_cbs; l2 != ll; l2 = l2->ll_next) { cb = l2->ll_data; cb->lc_del( ld, sb, cb ); } /* a failure might have implicitly closed the fd */ ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, s ); return rc; } } lo = LDAP_INT_GLOBAL_OPT(); for (ll = lo->ldo_conn_cbs; ll; ll = ll->ll_next) { cb = ll->ll_data; rc = cb->lc_add( ld, sb, srv, addr, cb ); if ( rc ) { ldaplist *l2; for (l2 = lo->ldo_conn_cbs; l2 != ll; l2 = l2->ll_next) { cb = l2->ll_data; cb->lc_del( ld, sb, cb ); } lo = &ld->ld_options; for (l2 = lo->ldo_conn_cbs; l2; l2 = l2->ll_next) { cb = l2->ll_data; cb->lc_del( ld, sb, cb ); } ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, s ); return rc; } } return 0; } int ldap_connect_to_host(LDAP *ld, Sockbuf *sb, int proto, LDAPURLDesc *srv, int async ) { int rc; int socktype, port; ber_socket_t s = AC_SOCKET_INVALID; char *host; #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) char serv[7]; int err; struct addrinfo hints, *res, *sai; #else int i; int use_hp = 0; struct hostent *hp = NULL; struct hostent he_buf; struct in_addr in; char *ha_buf=NULL; #endif if ( srv->lud_host == NULL || *srv->lud_host == 0 ) { host = "localhost"; } else { host = srv->lud_host; } port = srv->lud_port; if( !port ) { if( strcmp(srv->lud_scheme, "ldaps") == 0 ) { port = LDAPS_PORT; } else { port = LDAP_PORT; } } switch(proto) { case LDAP_PROTO_TCP: socktype = SOCK_STREAM; Debug2(LDAP_DEBUG_TRACE, "ldap_connect_to_host: TCP %s:%d\n", host, port ); break; case LDAP_PROTO_UDP: socktype = SOCK_DGRAM; Debug2(LDAP_DEBUG_TRACE, "ldap_connect_to_host: UDP %s:%d\n", host, port ); break; default: Debug1(LDAP_DEBUG_TRACE, "ldap_connect_to_host: unknown proto: %d\n", proto ); return -1; } #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) memset( &hints, '\0', sizeof(hints) ); #ifdef USE_AI_ADDRCONFIG /* FIXME: configure test needed */ /* Use AI_ADDRCONFIG only on systems where its known to be needed. */ hints.ai_flags = AI_ADDRCONFIG; #endif hints.ai_family = ldap_int_inet4or6; hints.ai_socktype = socktype; snprintf(serv, sizeof serv, "%d", port ); /* most getaddrinfo(3) use non-threadsafe resolver libraries */ LDAP_MUTEX_LOCK(&ldap_int_resolv_mutex); err = getaddrinfo( host, serv, &hints, &res ); LDAP_MUTEX_UNLOCK(&ldap_int_resolv_mutex); if ( err != 0 ) { Debug1(LDAP_DEBUG_TRACE, "ldap_connect_to_host: getaddrinfo failed: %s\n", AC_GAI_STRERROR(err) ); return -1; } rc = -1; for( sai=res; sai != NULL; sai=sai->ai_next) { unsigned short bind_success = 1; if( sai->ai_addr == NULL ) { Debug0(LDAP_DEBUG_TRACE, "ldap_connect_to_host: getaddrinfo " "ai_addr is NULL?\n" ); continue; } #ifndef LDAP_PF_INET6 if ( sai->ai_family == AF_INET6 ) continue; #endif /* we assume AF_x and PF_x are equal for all x */ s = ldap_int_socket( ld, sai->ai_family, socktype ); if ( s == AC_SOCKET_INVALID ) { continue; } if ( ldap_int_prepare_socket(ld, s, proto ) == -1 ) { ldap_pvt_close_socket(ld, s); break; } switch (sai->ai_family) { #ifdef LDAP_PF_INET6 case AF_INET6: { char addr[INET6_ADDRSTRLEN]; inet_ntop( AF_INET6, &((struct sockaddr_in6 *)sai->ai_addr)->sin6_addr, addr, sizeof addr); Debug2(LDAP_DEBUG_TRACE, "ldap_connect_to_host: Trying %s %s\n", addr, serv ); if( ld->ld_options.ldo_local_ip_addrs.has_ipv6 ) { struct sockaddr_in6 ip6addr; char bind_addr[INET6_ADDRSTRLEN]; ip6addr.sin6_family = AF_INET6; ip6addr.sin6_port = 0; ip6addr.sin6_addr = ld->ld_options.ldo_local_ip_addrs.ip6_addr; inet_ntop( AF_INET6, &(ip6addr.sin6_addr), bind_addr, sizeof bind_addr ); Debug1( LDAP_DEBUG_TRACE, "ldap_connect_to_host: From source address %s\n", bind_addr ); if ( bind( s, ( struct sockaddr* ) &ip6addr, sizeof ip6addr ) != 0 ) { Debug1( LDAP_DEBUG_TRACE, "ldap_connect_to_host: Failed to bind source address %s\n", bind_addr ); bind_success = 0; } } } break; #endif case AF_INET: { char addr[INET_ADDRSTRLEN]; inet_ntop( AF_INET, &((struct sockaddr_in *)sai->ai_addr)->sin_addr, addr, sizeof addr); Debug2(LDAP_DEBUG_TRACE, "ldap_connect_to_host: Trying %s:%s\n", addr, serv ); if( ld->ld_options.ldo_local_ip_addrs.has_ipv4 ) { struct sockaddr_in ip4addr; char bind_addr[INET_ADDRSTRLEN]; ip4addr.sin_family = AF_INET; ip4addr.sin_port = 0; ip4addr.sin_addr = ld->ld_options.ldo_local_ip_addrs.ip4_addr; inet_ntop( AF_INET, &(ip4addr.sin_addr), bind_addr, sizeof bind_addr ); Debug1( LDAP_DEBUG_TRACE, "ldap_connect_to_host: From source address %s\n", bind_addr ); if ( bind(s, ( struct sockaddr* )&ip4addr, sizeof ip4addr ) != 0 ) { Debug1( LDAP_DEBUG_TRACE, "ldap_connect_to_host: Failed to bind source address %s\n", bind_addr ); bind_success = 0; } } } break; } if ( bind_success ) { rc = ldap_pvt_connect( ld, s, sai->ai_addr, sai->ai_addrlen, async ); if ( rc == 0 || rc == -2 ) { err = ldap_int_connect_cbs( ld, sb, &s, srv, sai->ai_addr ); if ( err ) rc = err; else break; } } ldap_pvt_close_socket(ld, s); } freeaddrinfo(res); #else if (! inet_aton( host, &in ) ) { int local_h_errno; rc = ldap_pvt_gethostbyname_a( host, &he_buf, &ha_buf, &hp, &local_h_errno ); if ( (rc < 0) || (hp == NULL) ) { #ifdef HAVE_WINSOCK ldap_pvt_set_errno( WSAGetLastError() ); #else /* not exactly right, but... */ ldap_pvt_set_errno( EHOSTUNREACH ); #endif if (ha_buf) LDAP_FREE(ha_buf); return -1; } use_hp = 1; } rc = s = -1; for ( i = 0; !use_hp || (hp->h_addr_list[i] != 0); ++i, rc = -1 ) { struct sockaddr_in sin; unsigned short bind_success = 1; #ifdef HAVE_INET_NTOA_B char address[INET_ADDR_LEN]; char bind_addr[INET_ADDR_LEN]; #else char *address; char *bind_addr; #endif s = ldap_int_socket( ld, PF_INET, socktype ); if ( s == AC_SOCKET_INVALID ) { /* use_hp ? continue : break; */ break; } if ( ldap_int_prepare_socket( ld, s, proto ) == -1 ) { ldap_pvt_close_socket(ld, s); break; } (void)memset((char *)&sin, '\0', sizeof sin); sin.sin_family = AF_INET; sin.sin_port = htons((unsigned short) port); if( use_hp ) { AC_MEMCPY( &sin.sin_addr, hp->h_addr_list[i], sizeof(sin.sin_addr) ); } else { AC_MEMCPY( &sin.sin_addr, &in.s_addr, sizeof(sin.sin_addr) ); } #ifdef HAVE_INET_NTOA_B /* for VxWorks */ inet_ntoa_b( sin.sin_address, address ); #else address = inet_ntoa( sin.sin_addr ); #endif Debug2( LDAP_DEBUG_TRACE, "ldap_connect_to_host: Trying %s:%d\n", address, port ); if( ld->ld_options.ldo_local_ip_addrs.has_ipv4 ) { struct sockaddr_in ip4addr; ip4addr.sin_family = AF_INET; ip4addr.sin_addr = ld->ld_options.ldo_local_ip_addrs.ip4_addr; #ifdef HAVE_INET_NTOA_B inet_ntoa_b( ip4addr.sin_address, bind_addr ); #else bind_addr = inet_ntoa( ip4addr.sin_addr ); #endif Debug1( LDAP_DEBUG_TRACE, "ldap_connect_to_host: From source address %s\n", bind_addr ); if ( bind( s, (struct sockaddr*)&ip4addr, sizeof ip4addr ) != 0 ) { Debug1( LDAP_DEBUG_TRACE, "ldap_connect_to_host: Failed to bind source address %s\n", bind_addr ); bind_success = 0; } } if ( bind_success ) { rc = ldap_pvt_connect(ld, s, (struct sockaddr *)&sin, sizeof(sin), async); if ( (rc == 0) || (rc == -2) ) { int err = ldap_int_connect_cbs( ld, sb, &s, srv, (struct sockaddr *)&sin ); if ( err ) rc = err; else break; } } ldap_pvt_close_socket(ld, s); if (!use_hp) break; } if (ha_buf) LDAP_FREE(ha_buf); #endif return rc; } #if defined( HAVE_CYRUS_SASL ) char * ldap_host_connected_to( Sockbuf *sb, const char *host ) { ber_socklen_t len; #ifdef LDAP_PF_INET6 struct sockaddr_storage sabuf; #else struct sockaddr sabuf; #endif struct sockaddr *sa = (struct sockaddr *) &sabuf; ber_socket_t sd; (void)memset( (char *)sa, '\0', sizeof sabuf ); len = sizeof sabuf; ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); if ( getpeername( sd, sa, &len ) == -1 ) { return( NULL ); } /* * do a reverse lookup on the addr to get the official hostname. * this is necessary for kerberos to work right, since the official * hostname is used as the kerberos instance. */ switch (sa->sa_family) { #ifdef LDAP_PF_LOCAL case AF_LOCAL: return LDAP_STRDUP( ldap_int_hostname ); #endif #ifdef LDAP_PF_INET6 case AF_INET6: { struct in6_addr localhost = IN6ADDR_LOOPBACK_INIT; if( memcmp ( &((struct sockaddr_in6 *)sa)->sin6_addr, &localhost, sizeof(localhost)) == 0 ) { return LDAP_STRDUP( ldap_int_hostname ); } } break; #endif case AF_INET: { struct in_addr localhost; localhost.s_addr = htonl( INADDR_ANY ); if( memcmp ( &((struct sockaddr_in *)sa)->sin_addr, &localhost, sizeof(localhost) ) == 0 ) { return LDAP_STRDUP( ldap_int_hostname ); } #ifdef INADDR_LOOPBACK localhost.s_addr = htonl( INADDR_LOOPBACK ); if( memcmp ( &((struct sockaddr_in *)sa)->sin_addr, &localhost, sizeof(localhost) ) == 0 ) { return LDAP_STRDUP( ldap_int_hostname ); } #endif } break; default: return( NULL ); break; } { char *herr; #ifdef NI_MAXHOST char hbuf[NI_MAXHOST]; #elif defined( MAXHOSTNAMELEN ) char hbuf[MAXHOSTNAMELEN]; #else char hbuf[256]; #endif hbuf[0] = 0; if (ldap_pvt_get_hname( sa, len, hbuf, sizeof(hbuf), &herr ) == 0 && hbuf[0] ) { return LDAP_STRDUP( hbuf ); } } return host ? LDAP_STRDUP( host ) : NULL; } #endif struct selectinfo { #ifdef HAVE_POLL /* for UNIX poll(2) */ int si_maxfd; struct pollfd si_fds[FD_SETSIZE]; #else /* for UNIX select(2) */ fd_set si_readfds; fd_set si_writefds; fd_set si_use_readfds; fd_set si_use_writefds; #endif }; void ldap_mark_select_write( LDAP *ld, Sockbuf *sb ) { struct selectinfo *sip; ber_socket_t sd; sip = (struct selectinfo *)ld->ld_selectinfo; ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); #ifdef HAVE_POLL /* for UNIX poll(2) */ { int empty=-1; int i; for(i=0; i < sip->si_maxfd; i++) { if( sip->si_fds[i].fd == sd ) { sip->si_fds[i].events |= POLL_WRITE; return; } if( empty==-1 && sip->si_fds[i].fd == -1 ) { empty=i; } } if( empty == -1 ) { if( sip->si_maxfd >= FD_SETSIZE ) { /* FIXME */ return; } empty = sip->si_maxfd++; } sip->si_fds[empty].fd = sd; sip->si_fds[empty].events = POLL_WRITE; } #else /* for UNIX select(2) */ if ( !FD_ISSET( sd, &sip->si_writefds )) { FD_SET( sd, &sip->si_writefds ); } #endif } void ldap_mark_select_read( LDAP *ld, Sockbuf *sb ) { struct selectinfo *sip; ber_socket_t sd; sip = (struct selectinfo *)ld->ld_selectinfo; ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); #ifdef HAVE_POLL /* for UNIX poll(2) */ { int empty=-1; int i; for(i=0; i < sip->si_maxfd; i++) { if( sip->si_fds[i].fd == sd ) { sip->si_fds[i].events |= POLL_READ; return; } if( empty==-1 && sip->si_fds[i].fd == -1 ) { empty=i; } } if( empty == -1 ) { if( sip->si_maxfd >= FD_SETSIZE ) { /* FIXME */ return; } empty = sip->si_maxfd++; } sip->si_fds[empty].fd = sd; sip->si_fds[empty].events = POLL_READ; } #else /* for UNIX select(2) */ if ( !FD_ISSET( sd, &sip->si_readfds )) { FD_SET( sd, &sip->si_readfds ); } #endif } void ldap_mark_select_clear( LDAP *ld, Sockbuf *sb ) { struct selectinfo *sip; ber_socket_t sd; sip = (struct selectinfo *)ld->ld_selectinfo; ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); #ifdef HAVE_POLL /* for UNIX poll(2) */ { int i; for(i=0; i < sip->si_maxfd; i++) { if( sip->si_fds[i].fd == sd ) { sip->si_fds[i].fd = -1; } } } #else /* for UNIX select(2) */ FD_CLR( sd, &sip->si_writefds ); FD_CLR( sd, &sip->si_readfds ); #endif } void ldap_clear_select_write( LDAP *ld, Sockbuf *sb ) { struct selectinfo *sip; ber_socket_t sd; sip = (struct selectinfo *)ld->ld_selectinfo; ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); #ifdef HAVE_POLL /* for UNIX poll(2) */ { int i; for(i=0; i < sip->si_maxfd; i++) { if( sip->si_fds[i].fd == sd ) { sip->si_fds[i].events &= ~POLL_WRITE; } } } #else /* for UNIX select(2) */ FD_CLR( sd, &sip->si_writefds ); #endif } int ldap_is_write_ready( LDAP *ld, Sockbuf *sb ) { struct selectinfo *sip; ber_socket_t sd; sip = (struct selectinfo *)ld->ld_selectinfo; ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); #ifdef HAVE_POLL /* for UNIX poll(2) */ { int i; for(i=0; i < sip->si_maxfd; i++) { if( sip->si_fds[i].fd == sd ) { return sip->si_fds[i].revents & POLL_WRITE; } } return 0; } #else /* for UNIX select(2) */ return( FD_ISSET( sd, &sip->si_use_writefds )); #endif } int ldap_is_read_ready( LDAP *ld, Sockbuf *sb ) { struct selectinfo *sip; ber_socket_t sd; sip = (struct selectinfo *)ld->ld_selectinfo; if (ber_sockbuf_ctrl( sb, LBER_SB_OPT_DATA_READY, NULL )) return 1; ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); #ifdef HAVE_POLL /* for UNIX poll(2) */ { int i; for(i=0; i < sip->si_maxfd; i++) { if( sip->si_fds[i].fd == sd ) { return sip->si_fds[i].revents & POLL_READ; } } return 0; } #else /* for UNIX select(2) */ return( FD_ISSET( sd, &sip->si_use_readfds )); #endif } void * ldap_new_select_info( void ) { struct selectinfo *sip; sip = (struct selectinfo *)LDAP_CALLOC( 1, sizeof( struct selectinfo )); if ( sip == NULL ) return NULL; #ifdef HAVE_POLL /* for UNIX poll(2) */ /* sip->si_maxfd=0 */ #else /* for UNIX select(2) */ FD_ZERO( &sip->si_readfds ); FD_ZERO( &sip->si_writefds ); #endif return( (void *)sip ); } void ldap_free_select_info( void *sip ) { LDAP_FREE( sip ); } #ifndef HAVE_POLL int ldap_int_tblsize = 0; void ldap_int_ip_init( void ) { #if defined( HAVE_SYSCONF ) long tblsize = sysconf( _SC_OPEN_MAX ); if( tblsize > INT_MAX ) tblsize = INT_MAX; #elif defined( HAVE_GETDTABLESIZE ) int tblsize = getdtablesize(); #else int tblsize = FD_SETSIZE; #endif /* !USE_SYSCONF */ #ifdef FD_SETSIZE if( tblsize > FD_SETSIZE ) tblsize = FD_SETSIZE; #endif /* FD_SETSIZE */ ldap_int_tblsize = tblsize; } #endif int ldap_int_select( LDAP *ld, struct timeval *timeout ) { int rc; struct selectinfo *sip; Debug0( LDAP_DEBUG_TRACE, "ldap_int_select\n" ); #ifndef HAVE_POLL if ( ldap_int_tblsize == 0 ) ldap_int_ip_init(); #endif sip = (struct selectinfo *)ld->ld_selectinfo; assert( sip != NULL ); #ifdef HAVE_POLL { int to = timeout ? TV2MILLISEC( timeout ) : INFTIM; rc = poll( sip->si_fds, sip->si_maxfd, to ); } #else sip->si_use_readfds = sip->si_readfds; sip->si_use_writefds = sip->si_writefds; rc = select( ldap_int_tblsize, &sip->si_use_readfds, &sip->si_use_writefds, NULL, timeout ); #endif return rc; } openldap-2.5.11+dfsg/libraries/libldap/psearchctrl.c0000644000175000017500000002413614172327167021106 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This work was developed by Howard Chu for inclusion in * OpenLDAP Software. */ #include "portable.h" #include #include #include #include #include "ldap-int.h" /* Based on draft-ietf-ldapext-c-api-psearch-00 */ /* --------------------------------------------------------------------------- ldap_create_persistentsearch_control_value Create and encode the value of the server-side sort control. ld (IN) An LDAP session handle, as obtained from a call to ldap_init(). changetypes (IN) A bit-sensitive field that indicates which kinds of changes the client wants to be informed about. Its value should be LDAP_CHANGETYPE_ANY, or any logical-OR combination of LDAP_CHANGETYPE_ADD, LDAP_CHANGETYPE_DELETE, LDAP_CHANGETYPE_MODIFY, and LDAP_CHANGETYPE_MODDN. This field corresponds to the changeType element of the BER-encoded PersistentSearch control value itself. changesonly (IN) A Boolean field that indicates whether the client wishes to only receive searchResultEntry messages for entries that have been changed. If non-zero, only entries that result from changes are returned; other- wise, all of the static entries that match the search criteria are returned before the server begins change notification. This field corresponds to the changes- Only element of the BER-encoded PersistentSearch con- trol value itself. return_echg_ctls (IN) A Boolean field that indicates whether the server should send back an Entry Change Notification control with each searchResultEntry that is returned due to a change to an entry. If non-zero, Entry Change Notification controls are requested; if zero, they are not. This field corresponds to the returnECs element of the BER-encoded PersistentSearch control value itself. value (OUT) Contains the control value; the bv_val member of the berval structure SHOULD be freed by calling ldap_memfree() when done. ---------------------------------------------------------------------------*/ int ldap_create_persistentsearch_control_value( LDAP *ld, int changetypes, int changesonly, int return_echg_ctls, struct berval *value ) { int i; BerElement *ber = NULL; ber_tag_t tag; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); if ( ld == NULL ) return LDAP_PARAM_ERROR; if ( value == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; return LDAP_PARAM_ERROR; } if (( changetypes & 0x0f ) != changetypes ) { ld->ld_errno = LDAP_PARAM_ERROR; return LDAP_PARAM_ERROR; } value->bv_val = NULL; value->bv_len = 0; ld->ld_errno = LDAP_SUCCESS; ber = ldap_alloc_ber_with_options( ld ); if ( ber == NULL) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } tag = ber_printf( ber, "{ibb}", changetypes, changesonly, return_echg_ctls ); if ( tag == LBER_ERROR ) { goto error_return; } if ( ber_flatten2( ber, value, 1 ) == -1 ) { ld->ld_errno = LDAP_NO_MEMORY; } if ( 0 ) { error_return:; ld->ld_errno = LDAP_ENCODING_ERROR; } if ( ber != NULL ) { ber_free( ber, 1 ); } return ld->ld_errno; } /* --------------------------------------------------------------------------- ldap_create_persistentsearch_control Create and encode the persistent search control. ld (IN) An LDAP session handle, as obtained from a call to ldap_init(). changetypes (IN) A bit-sensitive field that indicates which kinds of changes the client wants to be informed about. Its value should be LDAP_CHANGETYPE_ANY, or any logical-OR combination of LDAP_CHANGETYPE_ADD, LDAP_CHANGETYPE_DELETE, LDAP_CHANGETYPE_MODIFY, and LDAP_CHANGETYPE_MODDN. This field corresponds to the changeType element of the BER-encoded PersistentSearch control value itself. changesonly (IN) A Boolean field that indicates whether the client wishes to only receive searchResultEntry messages for entries that have been changed. If non-zero, only entries that result from changes are returned; other- wise, all of the static entries that match the search criteria are returned before the server begins change notification. This field corresponds to the changes- Only element of the BER-encoded PersistentSearch con- trol value itself. return_echg_ctls (IN) A Boolean field that indicates whether the server should send back an Entry Change Notification control with each searchResultEntry that is returned due to a change to an entry. If non-zero, Entry Change Notification controls are requested; if zero, they are not. This field corresponds to the returnECs element of the BER-encoded PersistentSearch control value itself. isCritical (IN) 0 - Indicates the control is not critical to the operation. non-zero - The control is critical to the operation. ctrlp (OUT) Returns a pointer to the LDAPControl created. This control SHOULD be freed by calling ldap_control_free() when done. ---------------------------------------------------------------------------*/ int ldap_create_persistentsearch_control( LDAP *ld, int changetypes, int changesonly, int return_echg_ctls, int isCritical, LDAPControl **ctrlp ) { struct berval value; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); if ( ld == NULL ) { return LDAP_PARAM_ERROR; } if ( ctrlp == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; } ld->ld_errno = ldap_create_persistentsearch_control_value( ld, changetypes, changesonly, return_echg_ctls, &value ); if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = ldap_control_create( LDAP_CONTROL_PERSIST_REQUEST, isCritical, &value, 0, ctrlp ); if ( ld->ld_errno != LDAP_SUCCESS ) { LDAP_FREE( value.bv_val ); } } return ld->ld_errno; } /* --------------------------------------------------------------------------- ldap_parse_entrychange_control Decode the entry change notification control return information. ld (IN) An LDAP session handle, as obtained from a call to ldap_init(). ctrl (IN) The address of the LDAP Control Structure. chgtypep (OUT) This result parameter is filled in with one of the following values to indicate the type of change that was made that caused the entry to be returned: LDAP_CONTROL_PERSIST_ENTRY_CHANGE_ADD (1), LDAP_CONTROL_PERSIST_ENTRY_CHANGE_DELETE (2), LDAP_CONTROL_PERSIST_ENTRY_CHANGE_MODIFY (4), or LDAP_CONTROL_PERSIST_ENTRY_CHANGE_RENAME (8). If this parameter is NULL, the change type information is not returned. prevdnp (OUT) This result parameter points to the DN the entry had before it was renamed and/or moved by a modifyDN operation. It is set to NULL for other types of changes. If this parameter is NULL, the previous DN information is not returned. The returned value is a pointer to the contents of the control; it is not a copy of the data. chgnumpresentp (OUT) This result parameter is filled in with a non-zero value if a change number was returned in the control (the change number is optional and servers MAY choose not to return it). If this parameter is NULL, no indication of whether the change number was present is returned. chgnump (OUT) This result parameter is filled in with the change number if one was returned in the control. If this parameter is NULL, the change number is not returned. ---------------------------------------------------------------------------*/ int ldap_parse_entrychange_control( LDAP *ld, LDAPControl *ctrl, int *chgtypep, struct berval *prevdnp, int *chgnumpresentp, long *chgnump ) { BerElement *ber; ber_tag_t tag, berTag; ber_len_t berLen; ber_int_t chgtype; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( ctrl != NULL ); if (ld == NULL) { return LDAP_PARAM_ERROR; } if (ctrl == NULL) { ld->ld_errno = LDAP_PARAM_ERROR; return(ld->ld_errno); } if ( !ctrl->ldctl_value.bv_val ) { ld->ld_errno = LDAP_DECODING_ERROR; return(ld->ld_errno); } /* Create a BerElement from the berval returned in the control. */ ber = ber_init(&ctrl->ldctl_value); if (ber == NULL) { ld->ld_errno = LDAP_NO_MEMORY; return(ld->ld_errno); } if ( prevdnp != NULL ) { BER_BVZERO( prevdnp ); } if ( chgnumpresentp != NULL ) *chgnumpresentp = 0; if ( chgnump != NULL ) *chgnump = 0; /* Extract the change type from the control. */ tag = ber_scanf(ber, "{e" /*}*/, &chgtype); if( tag != LBER_ENUMERATED ) { ber_free(ber, 1); ld->ld_errno = LDAP_DECODING_ERROR; return(ld->ld_errno); } if ( chgtypep != NULL ) *chgtypep = chgtype; tag = ber_peek_tag( ber, &berLen ); if ( berLen ) { if (tag == LBER_OCTETSTRING) { if (prevdnp != NULL) { tag = ber_get_stringbv( ber, prevdnp, 0 ); } else { struct berval bv; tag = ber_skip_element( ber, &bv ); } if ( tag == LBER_ERROR ) { ber_free(ber, 1); ld->ld_errno = LDAP_DECODING_ERROR; return(ld->ld_errno); } tag = ber_peek_tag( ber, &berLen ); } if ( chgnumpresentp != NULL || chgnump != NULL ) { ber_int_t chgnum = 0; int present = 0; if (tag == LBER_INTEGER) { present = 1; tag = ber_get_int( ber, &chgnum ); if ( tag == LBER_ERROR ) { ber_free(ber, 1); ld->ld_errno = LDAP_DECODING_ERROR; return(ld->ld_errno); } if ( chgnumpresentp != NULL ) *chgnumpresentp = present; if ( chgnump != NULL ) *chgnump = chgnum; } } } ber_free(ber,1); ld->ld_errno = LDAP_SUCCESS; return(ld->ld_errno); } openldap-2.5.11+dfsg/libraries/libldap/thr_pth.c0000644000175000017500000001170314172327167020240 0ustar ryanryan/* thr_pth.c - wrappers around GNU Pth */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #if defined( HAVE_GNU_PTH ) #include "ldap_pvt_thread.h" /* Get the thread interface */ #define LDAP_THREAD_IMPLEMENTATION #define LDAP_THREAD_RDWR_IMPLEMENTATION #include "ldap_thr_debug.h" /* May rename the symbols defined below */ #include /******************* * * * GNU Pth Threads * * * *******************/ static pth_attr_t detach_attr; static pth_attr_t joined_attr; int ldap_int_thread_initialize( void ) { if( !pth_init() ) { return -1; } detach_attr = pth_attr_new(); joined_attr = pth_attr_new(); #ifdef LDAP_PVT_THREAD_SET_STACK_SIZE pth_attr_set( joined_attr, PTH_ATTR_STACK_SIZE, LDAP_PVT_THREAD_STACK_SIZE ); pth_attr_set( detach_attr, PTH_ATTR_STACK_SIZE, LDAP_PVT_THREAD_STACK_SIZE ); #endif return pth_attr_set( detach_attr, PTH_ATTR_JOINABLE, FALSE ); } int ldap_int_thread_destroy( void ) { pth_attr_destroy(detach_attr); pth_kill(); return 0; } int ldap_pvt_thread_create( ldap_pvt_thread_t * thread, int detach, void *(*start_routine)( void *), void *arg) { *thread = pth_spawn( detach ? detach_attr : joined_attr, start_routine, arg ); return *thread == NULL ? errno : 0; } void ldap_pvt_thread_exit( void *retval ) { pth_exit( retval ); } int ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return ) { return pth_join( thread, thread_return ) ? 0 : errno; } int ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo ) { return pth_raise( thread, signo ) ? 0 : errno; } int ldap_pvt_thread_yield( void ) { return pth_yield(NULL) ? 0 : errno; } int ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond ) { return( pth_cond_init( cond ) ? 0 : errno ); } int ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond ) { return( pth_cond_notify( cond, 0 ) ? 0 : errno ); } int ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cond ) { return( pth_cond_notify( cond, 1 ) ? 0 : errno ); } int ldap_pvt_thread_cond_wait( ldap_pvt_thread_cond_t *cond, ldap_pvt_thread_mutex_t *mutex ) { return( pth_cond_await( cond, mutex, NULL ) ? 0 : errno ); } int ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cv ) { return 0; } int ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex ) { return( pth_mutex_init( mutex ) ? 0 : errno ); } int ldap_pvt_thread_mutex_recursive_init( ldap_pvt_thread_mutex_t *mutex ) { /* All pth mutexes are recursive */ return ldap_pvt_thread_mutex_init( mutex ); } int ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex ) { return 0; } int ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex ) { return( pth_mutex_acquire( mutex, 0, NULL ) ? 0 : errno ); } int ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex ) { return( pth_mutex_release( mutex ) ? 0 : errno ); } int ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mutex ) { return( pth_mutex_acquire( mutex, 1, NULL ) ? 0 : errno ); } ldap_pvt_thread_t ldap_pvt_thread_self( void ) { return pth_self(); } int ldap_pvt_thread_key_create( ldap_pvt_thread_key_t *key ) { return pth_key_create( key, NULL ); } int ldap_pvt_thread_key_destroy( ldap_pvt_thread_key_t key ) { return pth_key_delete( key ); } int ldap_pvt_thread_key_setdata( ldap_pvt_thread_key_t key, void *data ) { return pth_key_setdata( key, data ); } int ldap_pvt_thread_key_getdata( ldap_pvt_thread_key_t key, void **data ) { *data = pth_key_getdata( key ); return 0; } #ifdef LDAP_THREAD_HAVE_RDWR int ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rw ) { return pth_rwlock_init( rw ) ? 0 : errno; } int ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rw ) { return 0; } int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rw ) { return pth_rwlock_acquire( rw, PTH_RWLOCK_RD, 0, NULL ) ? 0 : errno; } int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rw ) { return pth_rwlock_acquire( rw, PTH_RWLOCK_RD, 1, NULL ) ? 0 : errno; } int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rw ) { return pth_rwlock_release( rw ) ? 0 : errno; } int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rw ) { return pth_rwlock_acquire( rw, PTH_RWLOCK_RW, 0, NULL ) ? 0 : errno; } int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rw ) { return pth_rwlock_acquire( rw, PTH_RWLOCK_RW, 1, NULL ) ? 0 : errno; } int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rw ) { return pth_rwlock_release( rw ) ? 0 : errno; } #endif /* LDAP_THREAD_HAVE_RDWR */ #endif /* HAVE_GNU_PTH */ openldap-2.5.11+dfsg/libraries/libldap/bind.c0000644000175000017500000000567714172327167017521 0ustar ryanryan/* bind.c */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" #include "ldap_log.h" /* * BindRequest ::= SEQUENCE { * version INTEGER, * name DistinguishedName, -- who * authentication CHOICE { * simple [0] OCTET STRING -- passwd * krbv42ldap [1] OCTET STRING -- OBSOLETE * krbv42dsa [2] OCTET STRING -- OBSOLETE * sasl [3] SaslCredentials -- LDAPv3 * } * } * * BindResponse ::= SEQUENCE { * COMPONENTS OF LDAPResult, * serverSaslCreds OCTET STRING OPTIONAL -- LDAPv3 * } * * (Source: RFC 2251) */ /* * ldap_bind - bind to the ldap server (and X.500). The dn and password * of the entry to which to bind are supplied, along with the authentication * method to use. The msgid of the bind request is returned on success, * -1 if there's trouble. ldap_result() should be called to find out the * outcome of the bind request. * * Example: * ldap_bind( ld, "cn=manager, o=university of michigan, c=us", "secret", * LDAP_AUTH_SIMPLE ) */ int ldap_bind( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *passwd, int authmethod ) { Debug0( LDAP_DEBUG_TRACE, "ldap_bind\n" ); switch ( authmethod ) { case LDAP_AUTH_SIMPLE: return( ldap_simple_bind( ld, dn, passwd ) ); case LDAP_AUTH_SASL: /* user must use ldap_sasl_bind */ /* FALL-THRU */ default: ld->ld_errno = LDAP_AUTH_UNKNOWN; return( -1 ); } } /* * ldap_bind_s - bind to the ldap server (and X.500). The dn and password * of the entry to which to bind are supplied, along with the authentication * method to use. This routine just calls whichever bind routine is * appropriate and returns the result of the bind (e.g. LDAP_SUCCESS or * some other error indication). * * Examples: * ldap_bind_s( ld, "cn=manager, o=university of michigan, c=us", * "secret", LDAP_AUTH_SIMPLE ) * ldap_bind_s( ld, "cn=manager, o=university of michigan, c=us", * NULL, LDAP_AUTH_KRBV4 ) */ int ldap_bind_s( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *passwd, int authmethod ) { Debug0( LDAP_DEBUG_TRACE, "ldap_bind_s\n" ); switch ( authmethod ) { case LDAP_AUTH_SIMPLE: return( ldap_simple_bind_s( ld, dn, passwd ) ); case LDAP_AUTH_SASL: /* user must use ldap_sasl_bind */ /* FALL-THRU */ default: return( ld->ld_errno = LDAP_AUTH_UNKNOWN ); } } openldap-2.5.11+dfsg/libraries/libldap/charray.c0000644000175000017500000001000714172327167020215 0ustar ryanryan/* charray.c - routines for dealing with char * arrays */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include "ldap-int.h" int ldap_charray_add( char ***a, const char *s ) { int n; if ( *a == NULL ) { *a = (char **) LDAP_MALLOC( 2 * sizeof(char *) ); n = 0; if( *a == NULL ) { return -1; } } else { char **new; for ( n = 0; *a != NULL && (*a)[n] != NULL; n++ ) { ; /* NULL */ } new = (char **) LDAP_REALLOC( (char *) *a, (n + 2) * sizeof(char *) ); if( new == NULL ) { /* caller is required to call ldap_charray_free(*a) */ return -1; } *a = new; } (*a)[n] = LDAP_STRDUP(s); if( (*a)[n] == NULL ) { return 1; } (*a)[++n] = NULL; return 0; } int ldap_charray_merge( char ***a, char **s ) { int i, n, nn; char **aa; for ( n = 0; *a != NULL && (*a)[n] != NULL; n++ ) { ; /* NULL */ } for ( nn = 0; s[nn] != NULL; nn++ ) { ; /* NULL */ } aa = (char **) LDAP_REALLOC( (char *) *a, (n + nn + 1) * sizeof(char *) ); if( aa == NULL ) { return -1; } *a = aa; for ( i = 0; i < nn; i++ ) { (*a)[n + i] = LDAP_STRDUP(s[i]); if( (*a)[n + i] == NULL ) { for( --i ; i >= 0 ; i-- ) { LDAP_FREE( (*a)[n + i] ); (*a)[n + i] = NULL; } return -1; } } (*a)[n + nn] = NULL; return 0; } void ldap_charray_free( char **a ) { char **p; if ( a == NULL ) { return; } for ( p = a; *p != NULL; p++ ) { if ( *p != NULL ) { LDAP_FREE( *p ); } } LDAP_FREE( (char *) a ); } int ldap_charray_inlist( char **a, const char *s ) { int i; if( a == NULL ) return 0; for ( i=0; a[i] != NULL; i++ ) { if ( strcasecmp( s, a[i] ) == 0 ) { return 1; } } return 0; } char ** ldap_charray_dup( char **a ) { int i; char **new; for ( i = 0; a[i] != NULL; i++ ) ; /* NULL */ new = (char **) LDAP_MALLOC( (i + 1) * sizeof(char *) ); if( new == NULL ) { return NULL; } for ( i = 0; a[i] != NULL; i++ ) { new[i] = LDAP_STRDUP( a[i] ); if( new[i] == NULL ) { for( --i ; i >= 0 ; i-- ) { LDAP_FREE( new[i] ); } LDAP_FREE( new ); return NULL; } } new[i] = NULL; return( new ); } char ** ldap_str2charray( const char *str_in, const char *brkstr ) { char **res; char *str, *s; char *lasts; int i; /* protect the input string from strtok */ str = LDAP_STRDUP( str_in ); if( str == NULL ) { return NULL; } i = 1; for ( s = str; ; LDAP_UTF8_INCR(s) ) { s = ldap_utf8_strpbrk( s, brkstr ); if ( !s ) break; i++; } res = (char **) LDAP_MALLOC( (i + 1) * sizeof(char *) ); if( res == NULL ) { LDAP_FREE( str ); return NULL; } i = 0; for ( s = ldap_utf8_strtok( str, brkstr, &lasts ); s != NULL; s = ldap_utf8_strtok( NULL, brkstr, &lasts ) ) { res[i] = LDAP_STRDUP( s ); if(res[i] == NULL) { for( --i ; i >= 0 ; i-- ) { LDAP_FREE( res[i] ); } LDAP_FREE( res ); LDAP_FREE( str ); return NULL; } i++; } res[i] = NULL; LDAP_FREE( str ); return( res ); } char * ldap_charray2str( char **a, const char *sep ) { char *s, **v, *p; int len; int slen; if( sep == NULL ) sep = " "; slen = strlen( sep ); len = 0; for ( v = a; *v != NULL; v++ ) { len += strlen( *v ) + slen; } if ( len == 0 ) { return NULL; } /* trim extra sep len */ len -= slen; s = LDAP_MALLOC ( len + 1 ); if ( s == NULL ) { return NULL; } p = s; for ( v = a; *v != NULL; v++ ) { if ( v != a ) { strncpy( p, sep, slen ); p += slen; } len = strlen( *v ); strncpy( p, *v, len ); p += len; } *p = '\0'; return s; } openldap-2.5.11+dfsg/libraries/libldap/tavl.c0000644000175000017500000003002214172327167017531 0ustar ryanryan/* avl.c - routines to implement an avl tree */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2005-2022 The OpenLDAP Foundation. * Portions Copyright (c) 2005 by Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This work was initially developed by Howard Chu for inclusion * in OpenLDAP software. */ #include "portable.h" #include #include #include #ifdef CSRIMALLOC #define ber_memalloc malloc #define ber_memrealloc realloc #define ber_memfree free #else #include "lber.h" #endif #define AVL_INTERNAL #include "ldap_avl.h" /* Maximum tree depth this host's address space could support */ #define MAX_TREE_DEPTH (sizeof(void *) * CHAR_BIT) static const int avl_bfs[] = {LH, RH}; /* * Threaded AVL trees - for fast in-order traversal of nodes. */ /* * ldap_tavl_insert -- insert a node containing data data into the avl tree * with root root. fcmp is a function to call to compare the data portion * of two nodes. it should take two arguments and return <, >, or == 0, * depending on whether its first argument is <, >, or == its second * argument (like strcmp, e.g.). fdup is a function to call when a duplicate * node is inserted. it should return 0, or -1 and its return value * will be the return value from ldap_avl_insert in the case of a duplicate node. * the function will be called with the original node's data as its first * argument and with the incoming duplicate node's data as its second * argument. this could be used, for example, to keep a count with each * node. * * NOTE: this routine may malloc memory */ int ldap_tavl_insert( TAvlnode ** root, void *data, AVL_CMP fcmp, AVL_DUP fdup ) { TAvlnode *t, *p, *s, *q, *r; int a, cmp, ncmp; if ( *root == NULL ) { if (( r = (TAvlnode *) ber_memalloc( sizeof( TAvlnode ))) == NULL ) { return( -1 ); } r->avl_link[0] = r->avl_link[1] = NULL; r->avl_data = data; r->avl_bf = EH; r->avl_bits[0] = r->avl_bits[1] = AVL_THREAD; *root = r; return( 0 ); } t = NULL; s = p = *root; /* find insertion point */ while (1) { cmp = fcmp( data, p->avl_data ); if ( cmp == 0 ) return (*fdup)( p->avl_data, data ); cmp = (cmp > 0); q = ldap_avl_child( p, cmp ); if (q == NULL) { /* insert */ if (( q = (TAvlnode *) ber_memalloc( sizeof( TAvlnode ))) == NULL ) { return( -1 ); } q->avl_link[cmp] = p->avl_link[cmp]; q->avl_link[!cmp] = p; q->avl_data = data; q->avl_bf = EH; q->avl_bits[0] = q->avl_bits[1] = AVL_THREAD; p->avl_link[cmp] = q; p->avl_bits[cmp] = AVL_CHILD; break; } else if ( q->avl_bf ) { t = p; s = q; } p = q; } /* adjust balance factors */ cmp = fcmp( data, s->avl_data ) > 0; r = p = s->avl_link[cmp]; a = avl_bfs[cmp]; while ( p != q ) { cmp = fcmp( data, p->avl_data ) > 0; p->avl_bf = avl_bfs[cmp]; p = p->avl_link[cmp]; } /* checks and balances */ if ( s->avl_bf == EH ) { s->avl_bf = a; return 0; } else if ( s->avl_bf == -a ) { s->avl_bf = EH; return 0; } else if ( s->avl_bf == a ) { cmp = (a > 0); ncmp = !cmp; if ( r->avl_bf == a ) { /* single rotation */ p = r; if ( r->avl_bits[ncmp] == AVL_THREAD ) { r->avl_bits[ncmp] = AVL_CHILD; s->avl_bits[cmp] = AVL_THREAD; } else { s->avl_link[cmp] = r->avl_link[ncmp]; r->avl_link[ncmp] = s; } s->avl_bf = 0; r->avl_bf = 0; } else if ( r->avl_bf == -a ) { /* double rotation */ p = r->avl_link[ncmp]; if ( p->avl_bits[cmp] == AVL_THREAD ) { p->avl_bits[cmp] = AVL_CHILD; r->avl_bits[ncmp] = AVL_THREAD; } else { r->avl_link[ncmp] = p->avl_link[cmp]; p->avl_link[cmp] = r; } if ( p->avl_bits[ncmp] == AVL_THREAD ) { p->avl_bits[ncmp] = AVL_CHILD; s->avl_link[cmp] = p; s->avl_bits[cmp] = AVL_THREAD; } else { s->avl_link[cmp] = p->avl_link[ncmp]; p->avl_link[ncmp] = s; } if ( p->avl_bf == a ) { s->avl_bf = -a; r->avl_bf = 0; } else if ( p->avl_bf == -a ) { s->avl_bf = 0; r->avl_bf = a; } else { s->avl_bf = 0; r->avl_bf = 0; } p->avl_bf = 0; } /* Update parent */ if ( t == NULL ) *root = p; else if ( s == t->avl_right ) t->avl_right = p; else t->avl_left = p; } return 0; } void* ldap_tavl_delete( TAvlnode **root, void* data, AVL_CMP fcmp ) { TAvlnode *p, *q, *r, *top; int side, side_bf, shorter, nside = -1; /* parent stack */ TAvlnode *pptr[MAX_TREE_DEPTH]; unsigned char pdir[MAX_TREE_DEPTH]; int depth = 0; if ( *root == NULL ) return NULL; p = *root; while (1) { side = fcmp( data, p->avl_data ); if ( !side ) break; side = ( side > 0 ); pdir[depth] = side; pptr[depth++] = p; if ( p->avl_bits[side] == AVL_THREAD ) return NULL; p = p->avl_link[side]; } data = p->avl_data; /* If this node has two children, swap so we are deleting a node with * at most one child. */ if ( p->avl_bits[0] == AVL_CHILD && p->avl_bits[1] == AVL_CHILD && p->avl_link[0] && p->avl_link[1] ) { /* find the immediate predecessor */ q = p->avl_link[0]; side = depth; pdir[depth++] = 0; while (q->avl_bits[1] == AVL_CHILD && q->avl_link[1]) { pdir[depth] = 1; pptr[depth++] = q; q = q->avl_link[1]; } /* swap links */ r = p->avl_link[0]; p->avl_link[0] = q->avl_link[0]; q->avl_link[0] = r; q->avl_link[1] = p->avl_link[1]; p->avl_link[1] = q; p->avl_bits[0] = q->avl_bits[0]; p->avl_bits[1] = q->avl_bits[1]; q->avl_bits[0] = q->avl_bits[1] = AVL_CHILD; q->avl_bf = p->avl_bf; /* fix stack positions: old parent of p points to q */ pptr[side] = q; if ( side ) { r = pptr[side-1]; r->avl_link[pdir[side-1]] = q; } else { *root = q; } /* new parent of p points to p */ if ( depth-side > 1 ) { r = pptr[depth-1]; r->avl_link[1] = p; } else { q->avl_link[0] = p; } /* fix right subtree: successor of p points to q */ r = q->avl_link[1]; while ( r->avl_bits[0] == AVL_CHILD && r->avl_link[0] ) r = r->avl_link[0]; r->avl_link[0] = q; } /* now

has at most one child, get it */ if ( p->avl_link[0] && p->avl_bits[0] == AVL_CHILD ) { q = p->avl_link[0]; /* Preserve thread continuity */ r = p->avl_link[1]; nside = 1; } else if ( p->avl_link[1] && p->avl_bits[1] == AVL_CHILD ) { q = p->avl_link[1]; r = p->avl_link[0]; nside = 0; } else { q = NULL; if ( depth > 0 ) r = p->avl_link[pdir[depth-1]]; else r = NULL; } ber_memfree( p ); /* Update child thread */ if ( q ) { for ( ; q->avl_bits[nside] == AVL_CHILD && q->avl_link[nside]; q = q->avl_link[nside] ) ; q->avl_link[nside] = r; } if ( !depth ) { *root = q; return data; } /* set the child into p's parent */ depth--; p = pptr[depth]; side = pdir[depth]; p->avl_link[side] = q; if ( !q ) { p->avl_bits[side] = AVL_THREAD; p->avl_link[side] = r; } top = NULL; shorter = 1; while ( shorter ) { p = pptr[depth]; side = pdir[depth]; nside = !side; side_bf = avl_bfs[side]; /* case 1: height unchanged */ if ( p->avl_bf == EH ) { /* Tree is now heavier on opposite side */ p->avl_bf = avl_bfs[nside]; shorter = 0; } else if ( p->avl_bf == side_bf ) { /* case 2: taller subtree shortened, height reduced */ p->avl_bf = EH; } else { /* case 3: shorter subtree shortened */ if ( depth ) top = pptr[depth-1]; /* p->parent; */ else top = NULL; /* set to the taller of the two subtrees of

*/ q = p->avl_link[nside]; if ( q->avl_bf == EH ) { /* case 3a: height unchanged, single rotate */ if ( q->avl_bits[side] == AVL_THREAD ) { q->avl_bits[side] = AVL_CHILD; p->avl_bits[nside] = AVL_THREAD; } else { p->avl_link[nside] = q->avl_link[side]; q->avl_link[side] = p; } shorter = 0; q->avl_bf = side_bf; p->avl_bf = (- side_bf); } else if ( q->avl_bf == p->avl_bf ) { /* case 3b: height reduced, single rotate */ if ( q->avl_bits[side] == AVL_THREAD ) { q->avl_bits[side] = AVL_CHILD; p->avl_bits[nside] = AVL_THREAD; } else { p->avl_link[nside] = q->avl_link[side]; q->avl_link[side] = p; } shorter = 1; q->avl_bf = EH; p->avl_bf = EH; } else { /* case 3c: height reduced, balance factors opposite */ r = q->avl_link[side]; if ( r->avl_bits[nside] == AVL_THREAD ) { r->avl_bits[nside] = AVL_CHILD; q->avl_bits[side] = AVL_THREAD; } else { q->avl_link[side] = r->avl_link[nside]; r->avl_link[nside] = q; } if ( r->avl_bits[side] == AVL_THREAD ) { r->avl_bits[side] = AVL_CHILD; p->avl_bits[nside] = AVL_THREAD; p->avl_link[nside] = r; } else { p->avl_link[nside] = r->avl_link[side]; r->avl_link[side] = p; } if ( r->avl_bf == side_bf ) { q->avl_bf = (- side_bf); p->avl_bf = EH; } else if ( r->avl_bf == (- side_bf)) { q->avl_bf = EH; p->avl_bf = side_bf; } else { q->avl_bf = EH; p->avl_bf = EH; } r->avl_bf = EH; q = r; } /* a rotation has caused (or in case 3c) to become * the root. let

's former parent know this. */ if ( top == NULL ) { *root = q; } else if (top->avl_link[0] == p) { top->avl_link[0] = q; } else { top->avl_link[1] = q; } /* end case 3 */ p = q; } if ( !depth ) break; depth--; } /* end while(shorter) */ return data; } /* * ldap_tavl_free -- traverse avltree root, freeing the memory it is using. * the dfree() is called to free the data portion of each node. The * number of items actually freed is returned. */ int ldap_tavl_free( TAvlnode *root, AVL_FREE dfree ) { int nleft, nright; if ( root == 0 ) return( 0 ); nleft = ldap_tavl_free( ldap_avl_lchild( root ), dfree ); nright = ldap_tavl_free( ldap_avl_rchild( root ), dfree ); if ( dfree ) (*dfree)( root->avl_data ); ber_memfree( root ); return( nleft + nright + 1 ); } /* * ldap_tavl_find -- search avltree root for a node with data data. the function * cmp is used to compare things. it is called with data as its first arg * and the current node data as its second. it should return 0 if they match, * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2. */ /* * ldap_tavl_find2 - returns TAvlnode instead of data pointer. * ldap_tavl_find3 - as above, but returns TAvlnode even if no match is found. * also set *ret = last comparison result, or -1 if root == NULL. */ TAvlnode * ldap_tavl_find3( TAvlnode *root, const void *data, AVL_CMP fcmp, int *ret ) { int cmp = -1, dir; TAvlnode *prev = root; while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) { prev = root; dir = cmp > 0; root = ldap_avl_child( root, dir ); } *ret = cmp; return root ? root : prev; } TAvlnode * ldap_tavl_find2( TAvlnode *root, const void *data, AVL_CMP fcmp ) { int cmp; while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) { cmp = cmp > 0; root = ldap_avl_child( root, cmp ); } return root; } void* ldap_tavl_find( TAvlnode *root, const void* data, AVL_CMP fcmp ) { int cmp; while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) { cmp = cmp > 0; root = ldap_avl_child( root, cmp ); } return( root ? root->avl_data : 0 ); } /* Return the leftmost or rightmost node in the tree */ TAvlnode * ldap_tavl_end( TAvlnode *root, int dir ) { if ( root ) { while ( root->avl_bits[dir] == AVL_CHILD ) root = root->avl_link[dir]; } return root; } /* Return the next node in the given direction */ TAvlnode * ldap_tavl_next( TAvlnode *root, int dir ) { if ( root ) { int c = root->avl_bits[dir]; root = root->avl_link[dir]; if ( c == AVL_CHILD ) { dir ^= 1; while ( root->avl_bits[dir] == AVL_CHILD ) root = root->avl_link[dir]; } } return root; } openldap-2.5.11+dfsg/libraries/libldap/t61.c0000644000175000017500000006103014172327167017200 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2002-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This work was initially developed by Howard Chu for inclusion in * OpenLDAP Software. */ /* * Basic T.61 <-> UTF-8 conversion * * These routines will perform a lossless translation from T.61 to UTF-8 * and a lossy translation from UTF-8 to T.61. */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" #include "ldap_utf8.h" #include "ldap_defaults.h" /* * T.61 is somewhat braindead; even in the 7-bit space it is not * completely equivalent to 7-bit US-ASCII. Our definition of the * character set comes from RFC 1345 with a slightly more readable * rendition at http://std.dkuug.dk/i18n/charmaps/T.61-8BIT. * * Even though '#' and '$' are present in the 7-bit US-ASCII space, * (x23 and x24, resp.) in T.61 they are mapped to 8-bit characters * xA6 and xA4. * * Also T.61 lacks * backslash \ (x5C) * caret ^ (x5E) * backquote ` (x60) * left brace { (x7B) * right brace } (x7D) * tilde ~ (x7E) * * In T.61, the codes xC1 to xCF (excluding xC9, unused) are non-spacing * accents of some form or another. There are predefined combinations * for certain characters, but they can also be used arbitrarily. The * table at dkuug.dk maps these accents to the E000 "private use" range * of the Unicode space, but I believe they more properly belong in the * 0300 range (non-spacing accents). The transformation is complicated * slightly because Unicode wants the non-spacing character to follow * the base character, while T.61 has the non-spacing character leading. * Also, T.61 specifically recognizes certain combined pairs as "characters" * but doesn't specify how to treat unrecognized pairs. This code will * always attempt to combine pairs when a known Unicode composite exists. */ static const wchar_t t61_tab[] = { 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f, 0x010, 0x011, 0x012, 0x013, 0x014, 0x015, 0x016, 0x017, 0x018, 0x019, 0x01a, 0x01b, 0x01c, 0x01d, 0x01e, 0x01f, 0x020, 0x021, 0x022, 0x000, 0x000, 0x025, 0x026, 0x027, 0x028, 0x029, 0x02a, 0x02b, 0x02c, 0x02d, 0x02e, 0x02f, 0x030, 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038, 0x039, 0x03a, 0x03b, 0x03c, 0x03d, 0x03e, 0x03f, 0x040, 0x041, 0x042, 0x043, 0x044, 0x045, 0x046, 0x047, 0x048, 0x049, 0x04a, 0x04b, 0x04c, 0x04d, 0x04e, 0x04f, 0x050, 0x051, 0x052, 0x053, 0x054, 0x055, 0x056, 0x057, 0x058, 0x059, 0x05a, 0x05b, 0x000, 0x05d, 0x000, 0x05f, 0x000, 0x061, 0x062, 0x063, 0x064, 0x065, 0x066, 0x067, 0x068, 0x069, 0x06a, 0x06b, 0x06c, 0x06d, 0x06e, 0x06f, 0x070, 0x071, 0x072, 0x073, 0x074, 0x075, 0x076, 0x077, 0x078, 0x079, 0x07a, 0x000, 0x07c, 0x000, 0x000, 0x07f, 0x080, 0x081, 0x082, 0x083, 0x084, 0x085, 0x086, 0x087, 0x088, 0x089, 0x08a, 0x08b, 0x08c, 0x08d, 0x08e, 0x08f, 0x090, 0x091, 0x092, 0x093, 0x094, 0x095, 0x096, 0x097, 0x098, 0x099, 0x09a, 0x09b, 0x09c, 0x09d, 0x09e, 0x09f, 0x0a0, 0x0a1, 0x0a2, 0x0a3, 0x024, 0x0a5, 0x023, 0x0a7, 0x0a4, 0x000, 0x000, 0x0ab, 0x000, 0x000, 0x000, 0x000, 0x0b0, 0x0b1, 0x0b2, 0x0b3, 0x0d7, 0x0b5, 0x0b6, 0x0b7, 0x0f7, 0x000, 0x000, 0x0bb, 0x0bc, 0x0bd, 0x0be, 0x0bf, 0x000, 0x300, 0x301, 0x302, 0x303, 0x304, 0x306, 0x307, 0x308, 0x000, 0x30a, 0x327, 0x332, 0x30b, 0x328, 0x30c, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x2126, 0xc6, 0x0d0, 0x0aa, 0x126, 0x000, 0x132, 0x13f, 0x141, 0x0d8, 0x152, 0x0ba, 0x0de, 0x166, 0x14a, 0x149, 0x138, 0x0e6, 0x111, 0x0f0, 0x127, 0x131, 0x133, 0x140, 0x142, 0x0f8, 0x153, 0x0df, 0x0fe, 0x167, 0x14b, 0x000 }; typedef wchar_t wvec16[16]; typedef wchar_t wvec32[32]; typedef wchar_t wvec64[64]; /* Substitutions when 0xc1-0xcf appears by itself or with space 0x20 */ static const wvec16 accents = { 0x000, 0x060, 0x0b4, 0x05e, 0x07e, 0x0af, 0x2d8, 0x2d9, 0x0a8, 0x000, 0x2da, 0x0b8, 0x000, 0x2dd, 0x2db, 0x2c7}; /* In the following tables, base characters commented in (parentheses) * are not defined by T.61 but are mapped anyway since their Unicode * composite exists. */ /* Grave accented chars AEIOU (NWY) */ static const wvec32 c1_vec1 = { /* Upper case */ 0, 0xc0, 0, 0, 0, 0xc8, 0, 0, 0, 0xcc, 0, 0, 0, 0, 0x1f8, 0xd2, 0, 0, 0, 0, 0, 0xd9, 0, 0x1e80, 0, 0x1ef2, 0, 0, 0, 0, 0, 0}; static const wvec32 c1_vec2 = { /* Lower case */ 0, 0xe0, 0, 0, 0, 0xe8, 0, 0, 0, 0xec, 0, 0, 0, 0, 0x1f9, 0xf2, 0, 0, 0, 0, 0, 0xf9, 0, 0x1e81, 0, 0x1ef3, 0, 0, 0, 0, 0, 0}; static const wvec32 *c1_grave[] = { NULL, NULL, &c1_vec1, &c1_vec2, NULL, NULL, NULL, NULL }; /* Acute accented chars AEIOUYCLNRSZ (GKMPW) */ static const wvec32 c2_vec1 = { /* Upper case */ 0, 0xc1, 0, 0x106, 0, 0xc9, 0, 0x1f4, 0, 0xcd, 0, 0x1e30, 0x139, 0x1e3e, 0x143, 0xd3, 0x1e54, 0, 0x154, 0x15a, 0, 0xda, 0, 0x1e82, 0, 0xdd, 0x179, 0, 0, 0, 0, 0}; static const wvec32 c2_vec2 = { /* Lower case */ 0, 0xe1, 0, 0x107, 0, 0xe9, 0, 0x1f5, 0, 0xed, 0, 0x1e31, 0x13a, 0x1e3f, 0x144, 0xf3, 0x1e55, 0, 0x155, 0x15b, 0, 0xfa, 0, 0x1e83, 0, 0xfd, 0x17a, 0, 0, 0, 0, 0}; static const wvec32 c2_vec3 = { /* (AE and ae) */ 0, 0x1fc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1fd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const wvec32 *c2_acute[] = { NULL, NULL, &c2_vec1, &c2_vec2, NULL, NULL, NULL, &c2_vec3 }; /* Circumflex AEIOUYCGHJSW (Z) */ static const wvec32 c3_vec1 = { /* Upper case */ 0, 0xc2, 0, 0x108, 0, 0xca, 0, 0x11c, 0x124, 0xce, 0x134, 0, 0, 0, 0, 0xd4, 0, 0, 0, 0x15c, 0, 0xdb, 0, 0x174, 0, 0x176, 0x1e90, 0, 0, 0, 0, 0}; static const wvec32 c3_vec2 = { /* Lower case */ 0, 0xe2, 0, 0x109, 0, 0xea, 0, 0x11d, 0x125, 0xee, 0x135, 0, 0, 0, 0, 0xf4, 0, 0, 0, 0x15d, 0, 0xfb, 0, 0x175, 0, 0x177, 0x1e91, 0, 0, 0, 0, 0}; static const wvec32 *c3_circumflex[] = { NULL, NULL, &c3_vec1, &c3_vec2, NULL, NULL, NULL, NULL }; /* Tilde AIOUN (EVY) */ static const wvec32 c4_vec1 = { /* Upper case */ 0, 0xc3, 0, 0, 0, 0x1ebc, 0, 0, 0, 0x128, 0, 0, 0, 0, 0xd1, 0xd5, 0, 0, 0, 0, 0, 0x168, 0x1e7c, 0, 0, 0x1ef8, 0, 0, 0, 0, 0, 0}; static const wvec32 c4_vec2 = { /* Lower case */ 0, 0xe3, 0, 0, 0, 0x1ebd, 0, 0, 0, 0x129, 0, 0, 0, 0, 0xf1, 0xf5, 0, 0, 0, 0, 0, 0x169, 0x1e7d, 0, 0, 0x1ef9, 0, 0, 0, 0, 0, 0}; static const wvec32 *c4_tilde[] = { NULL, NULL, &c4_vec1, &c4_vec2, NULL, NULL, NULL, NULL }; /* Macron AEIOU (YG) */ static const wvec32 c5_vec1 = { /* Upper case */ 0, 0x100, 0, 0, 0, 0x112, 0, 0x1e20, 0, 0x12a, 0, 0, 0, 0, 0, 0x14c, 0, 0, 0, 0, 0, 0x16a, 0, 0, 0, 0x232, 0, 0, 0, 0, 0, 0}; static const wvec32 c5_vec2 = { /* Lower case */ 0, 0x101, 0, 0, 0, 0x113, 0, 0x1e21, 0, 0x12b, 0, 0, 0, 0, 0, 0x14d, 0, 0, 0, 0, 0, 0x16b, 0, 0, 0, 0x233, 0, 0, 0, 0, 0, 0}; static const wvec32 c5_vec3 = { /* (AE and ae) */ 0, 0x1e2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const wvec32 *c5_macron[] = { NULL, NULL, &c5_vec1, &c5_vec2, NULL, NULL, NULL, &c5_vec3 }; /* Breve AUG (EIO) */ static const wvec32 c6_vec1 = { /* Upper case */ 0, 0x102, 0, 0, 0, 0x114, 0, 0x11e, 0, 0x12c, 0, 0, 0, 0, 0, 0x14e, 0, 0, 0, 0, 0, 0x16c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const wvec32 c6_vec2 = { /* Lower case */ 0, 0x103, 0, 0, 0, 0x115, 0, 0x11f, 0, 0x12d, 0, 0, 0, 0, 0, 0x14f, 0, 0, 0, 0, 0, 0x16d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const wvec32 *c6_breve[] = { NULL, NULL, &c6_vec1, &c6_vec2, NULL, NULL, NULL, NULL }; /* Dot Above CEGIZ (AOBDFHMNPRSTWXY) */ static const wvec32 c7_vec1 = { /* Upper case */ 0, 0x226, 0x1e02, 0x10a, 0x1e0a, 0x116, 0x1e1e, 0x120, 0x1e22, 0x130, 0, 0, 0, 0x1e40, 0x1e44, 0x22e, 0x1e56, 0, 0x1e58, 0x1e60, 0x1e6a, 0, 0, 0x1e86, 0x1e8a, 0x1e8e, 0x17b, 0, 0, 0, 0, 0}; static const wvec32 c7_vec2 = { /* Lower case */ 0, 0x227, 0x1e03, 0x10b, 0x1e0b, 0x117, 0x1e1f, 0x121, 0x1e23, 0, 0, 0, 0, 0x1e41, 0x1e45, 0x22f, 0x1e57, 0, 0x1e59, 0x1e61, 0x1e6b, 0, 0, 0x1e87, 0x1e8b, 0x1e8f, 0x17c, 0, 0, 0, 0, 0}; static const wvec32 *c7_dotabove[] = { NULL, NULL, &c7_vec1, &c7_vec2, NULL, NULL, NULL, NULL }; /* Diaeresis AEIOUY (HWXt) */ static const wvec32 c8_vec1 = { /* Upper case */ 0, 0xc4, 0, 0, 0, 0xcb, 0, 0, 0x1e26, 0xcf, 0, 0, 0, 0, 0, 0xd6, 0, 0, 0, 0, 0, 0xdc, 0, 0x1e84, 0x1e8c, 0x178, 0, 0, 0, 0, 0, 0}; static const wvec32 c8_vec2 = { /* Lower case */ 0, 0xe4, 0, 0, 0, 0xeb, 0, 0, 0x1e27, 0xef, 0, 0, 0, 0, 0, 0xf6, 0, 0, 0, 0, 0x1e97, 0xfc, 0, 0x1e85, 0x1e8d, 0xff, 0, 0, 0, 0, 0, 0}; static const wvec32 *c8_diaeresis[] = { NULL, NULL, &c8_vec1, &c8_vec2, NULL, NULL, NULL, NULL }; /* Ring Above AU (wy) */ static const wvec32 ca_vec1 = { /* Upper case */ 0, 0xc5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x16e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const wvec32 ca_vec2 = { /* Lower case */ 0, 0xe5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x16f, 0, 0x1e98, 0, 0x1e99, 0, 0, 0, 0, 0, 0}; static const wvec32 *ca_ringabove[] = { NULL, NULL, &ca_vec1, &ca_vec2, NULL, NULL, NULL, NULL }; /* Cedilla CGKLNRST (EDH) */ static const wvec32 cb_vec1 = { /* Upper case */ 0, 0, 0, 0xc7, 0x1e10, 0x228, 0, 0x122, 0x1e28, 0, 0, 0x136, 0x13b, 0, 0x145, 0, 0, 0, 0x156, 0x15e, 0x162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const wvec32 cb_vec2 = { /* Lower case */ 0, 0, 0, 0xe7, 0x1e11, 0x229, 0, 0x123, 0x1e29, 0, 0, 0x137, 0x13c, 0, 0x146, 0, 0, 0, 0x157, 0x15f, 0x163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const wvec32 *cb_cedilla[] = { NULL, NULL, &cb_vec1, &cb_vec2, NULL, NULL, NULL, NULL }; /* Double Acute Accent OU */ static const wvec32 cd_vec1 = { /* Upper case */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x150, 0, 0, 0, 0, 0, 0x170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const wvec32 cd_vec2 = { /* Lower case */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x151, 0, 0, 0, 0, 0, 0x171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const wvec32 *cd_doubleacute[] = { NULL, NULL, &cd_vec1, &cd_vec2, NULL, NULL, NULL, NULL }; /* Ogonek AEIU (O) */ static const wvec32 ce_vec1 = { /* Upper case */ 0, 0x104, 0, 0, 0, 0x118, 0, 0, 0, 0x12e, 0, 0, 0, 0, 0, 0x1ea, 0, 0, 0, 0, 0, 0x172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const wvec32 ce_vec2 = { /* Lower case */ 0, 0x105, 0, 0, 0, 0x119, 0, 0, 0, 0x12f, 0, 0, 0, 0, 0, 0x1eb, 0, 0, 0, 0, 0, 0x173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const wvec32 *ce_ogonek[] = { NULL, NULL, &ce_vec1, &ce_vec2, NULL, NULL, NULL, NULL }; /* Caron CDELNRSTZ (AIOUGKjH) */ static const wvec32 cf_vec1 = { /* Upper case */ 0, 0x1cd, 0, 0x10c, 0x10e, 0x11a, 0, 0x1e6, 0x21e, 0x1cf, 0, 0x1e8, 0x13d, 0, 0x147, 0x1d1, 0, 0, 0x158, 0x160, 0x164, 0x1d3, 0, 0, 0, 0, 0x17d, 0, 0, 0, 0, 0}; static const wvec32 cf_vec2 = { /* Lower case */ 0, 0x1ce, 0, 0x10d, 0x10f, 0x11b, 0, 0x1e7, 0x21f, 0x1d0, 0x1f0, 0x1e9, 0x13e, 0, 0x148, 0x1d2, 0, 0, 0x159, 0x161, 0x165, 0x1d4, 0, 0, 0, 0, 0x17e, 0, 0, 0, 0, 0}; static const wvec32 *cf_caron[] = { NULL, NULL, &cf_vec1, &cf_vec2, NULL, NULL, NULL, NULL }; static const wvec32 **cx_tab[] = { NULL, c1_grave, c2_acute, c3_circumflex, c4_tilde, c5_macron, c6_breve, c7_dotabove, c8_diaeresis, NULL, ca_ringabove, cb_cedilla, NULL, cd_doubleacute, ce_ogonek, cf_caron }; int ldap_t61s_valid( struct berval *str ) { unsigned char *c = (unsigned char *)str->bv_val; int i; for (i=0; i < str->bv_len; c++,i++) if (!t61_tab[*c]) return 0; return 1; } /* Transform a T.61 string to UTF-8. */ int ldap_t61s_to_utf8s( struct berval *src, struct berval *dst ) { unsigned char *c; char *d; int i, wlen = 0; /* Just count the length of the UTF-8 result first */ for (i=0,c=(unsigned char *)src->bv_val; i < src->bv_len; c++,i++) { /* Invalid T.61 characters? */ if (!t61_tab[*c]) return LDAP_INVALID_SYNTAX; if ((*c & 0xf0) == 0xc0) { int j = *c & 0x0f; /* If this is the end of the string, or if the base * character is just a space, treat this as a regular * spacing character. */ if ((!c[1] || c[1] == 0x20) && accents[j]) { wlen += ldap_x_wc_to_utf8(NULL, accents[j], 0); } else if (cx_tab[j] && cx_tab[j][c[1]>>5] && /* We have a composite mapping for this pair */ (*cx_tab[j][c[1]>>5])[c[1]&0x1f]) { wlen += ldap_x_wc_to_utf8( NULL, (*cx_tab[j][c[1]>>5])[c[1]&0x1f], 0); } else { /* No mapping, just swap it around so the base * character comes first. */ wlen += ldap_x_wc_to_utf8(NULL, c[1], 0); wlen += ldap_x_wc_to_utf8(NULL, t61_tab[*c], 0); } c++; i++; continue; } else { wlen += ldap_x_wc_to_utf8(NULL, t61_tab[*c], 0); } } /* Now transform the string */ dst->bv_len = wlen; dst->bv_val = LDAP_MALLOC( wlen+1 ); d = dst->bv_val; if (!d) return LDAP_NO_MEMORY; for (i=0,c=(unsigned char *)src->bv_val; i < src->bv_len; c++,i++) { if ((*c & 0xf0) == 0xc0) { int j = *c & 0x0f; /* If this is the end of the string, or if the base * character is just a space, treat this as a regular * spacing character. */ if ((!c[1] || c[1] == 0x20) && accents[j]) { d += ldap_x_wc_to_utf8(d, accents[j], 6); } else if (cx_tab[j] && cx_tab[j][c[1]>>5] && /* We have a composite mapping for this pair */ (*cx_tab[j][c[1]>>5])[c[1]&0x1f]) { d += ldap_x_wc_to_utf8(d, (*cx_tab[j][c[1]>>5])[c[1]&0x1f], 6); } else { /* No mapping, just swap it around so the base * character comes first. */ d += ldap_x_wc_to_utf8(d, c[1], 6); d += ldap_x_wc_to_utf8(d, t61_tab[*c], 6); } c++; i++; continue; } else { d += ldap_x_wc_to_utf8(d, t61_tab[*c], 6); } } *d = '\0'; return LDAP_SUCCESS; } /* For the reverse mapping, we just pay attention to the Latin-oriented * code blocks. These are * 0000 - 007f Basic Latin * 0080 - 00ff Latin-1 Supplement * 0100 - 017f Latin Extended-A * 0180 - 024f Latin Extended-B * 1e00 - 1eff Latin Extended Additional * * We have a special case to map Ohm U2126 back to T.61 0xe0. All other * unrecognized characters are replaced with '?' 0x3f. */ static const wvec64 u000 = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x00a6, 0x00a4, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f}; /* In this range, we've mapped caret to xc3/x20, backquote to xc1/x20, * and tilde to xc4/x20. T.61 (stupidly!) doesn't define these characters * on their own, even though it provides them as combiners for other * letters. T.61 doesn't define these pairings either, so this may just * have to be replaced with '?' 0x3f if other software can't cope with it. */ static const wvec64 u001 = { 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x003f, 0x005d, 0xc320, 0x005f, 0xc120, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x003f, 0x007c, 0x003f, 0xc420, 0x007f}; static const wvec64 u002 = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a8, 0x00a5, 0x003f, 0x00a7, 0xc820, 0x003f, 0x00e3, 0x00ab, 0x003f, 0x003f, 0x003f, 0xc520, 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0xc220, 0x00b5, 0x00b6, 0x00b7, 0xcb20, 0x003f, 0x00eb, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf}; static const wvec64 u003 = { 0xc141, 0xc241, 0xc341, 0xc441, 0xc841, 0xca41, 0x00e1, 0xcb43, 0xc145, 0xc245, 0xc345, 0xc845, 0xc149, 0xc249, 0xc349, 0xc849, 0x00e2, 0xc44e, 0xc14f, 0xc24f, 0xc34f, 0xc44f, 0xc84f, 0x00b4, 0x00e9, 0xc155, 0xc255, 0xc355, 0xc855, 0xc259, 0x00ec, 0x00fb, 0xc161, 0xc261, 0xc361, 0xc461, 0xc861, 0xca61, 0x00f1, 0xcb63, 0xc165, 0xc265, 0xc365, 0xc865, 0xc169, 0xc269, 0xc369, 0xc869, 0x00f3, 0xc46e, 0xc16f, 0xc26f, 0xc36f, 0xc46f, 0xc86f, 0x00b8, 0x00f9, 0xc175, 0xc275, 0xc375, 0xc875, 0xc279, 0x00fc, 0xc879}; /* These codes are used here but not defined by T.61: * x114 = xc6/x45, x115 = xc6/x65, x12c = xc6/x49, x12d = xc6/x69 */ static const wvec64 u010 = { 0xc541, 0xc561, 0xc641, 0xc661, 0xce41, 0xce61, 0xc243, 0xc263, 0xc343, 0xc363, 0xc743, 0xc763, 0xcf43, 0xcf63, 0xcf44, 0xcf64, 0x003f, 0x00f2, 0xc545, 0xc565, 0xc645, 0xc665, 0xc745, 0xc765, 0xce45, 0xce65, 0xcf45, 0xcf65, 0xc347, 0xc367, 0xc647, 0xc667, 0xc747, 0xc767, 0xcb47, 0xcb67, 0xc348, 0xc368, 0x00e4, 0x00f4, 0xc449, 0xc469, 0xc549, 0xc569, 0xc649, 0xc669, 0xce49, 0xce69, 0xc749, 0x00f5, 0x00e6, 0x00f6, 0xc34a, 0xc36a, 0xcb4b, 0xcb6b, 0x00f0, 0xc24c, 0xc26c, 0xcb4c, 0xcb6c, 0xcf4c, 0xcf6c, 0x00e7}; /* These codes are used here but not defined by T.61: * x14e = xc6/x4f, x14f = xc6/x6f */ static const wvec64 u011 = { 0x00f7, 0x00e8, 0x00f8, 0xc24e, 0xc26e, 0xcb4e, 0xcb6e, 0xcf4e, 0xcf6e, 0x00ef, 0x00ee, 0x00fe, 0xc54f, 0xc56f, 0xc64f, 0xc66f, 0xcd4f, 0xcd6f, 0x00ea, 0x00fa, 0xc252, 0xc272, 0xcb52, 0xcb72, 0xcf52, 0xcf72, 0xc253, 0xc273, 0xc353, 0xc373, 0xcb53, 0xcb73, 0xcf53, 0xcf73, 0xcb54, 0xcb74, 0xcf54, 0xcf74, 0x00ed, 0x00fd, 0xc455, 0xc475, 0xc555, 0xc575, 0xc655, 0xc675, 0xca55, 0xca75, 0xcd55, 0xcd75, 0xce55, 0xce75, 0xc357, 0xc377, 0xc359, 0xc379, 0xc859, 0xc25a, 0xc27a, 0xc75a, 0xc77a, 0xcf5a, 0xcf7a, 0x003f}; /* All of the codes in this block are undefined in T.61. */ static const wvec64 u013 = { 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xcf41, 0xcf61, 0xcf49, 0xcf69, 0xcf4f, 0xcf6f, 0xcf55, 0xcf75, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xc5e1, 0xc5f1, 0x003f, 0x003f, 0xcf47, 0xcf67, 0xcf4b, 0xcf6b, 0xce4f, 0xce6f, 0x003f, 0x003f, 0x003f, 0x003f, 0xcf6a, 0x003f, 0x003f, 0x003f, 0xc247, 0xc267, 0x003f, 0x003f, 0xc14e, 0xc16e, 0x003f, 0x003f, 0xc2e1, 0xc2f1, 0x003f, 0x003f}; /* All of the codes in this block are undefined in T.61. */ static const wvec64 u020 = { 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xcf48, 0xcf68, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xc741, 0xc761, 0xcb45, 0xcb65, 0x003f, 0x003f, 0x003f, 0x003f, 0xc74f, 0xc76f, 0x003f, 0x003f, 0xc559, 0xc579, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f}; static const wvec64 u023 = { 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xcf20, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xc620, 0xc720, 0xca20, 0xce20, 0x003f, 0xcd20, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f}; /* These are the non-spacing characters by themselves. They should * never appear by themselves in actual text. */ static const wvec64 u030 = { 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x003f, 0x00c6, 0x00c7, 0x00c8, 0x003f, 0x00ca, 0x00cd, 0x00cf, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x00cb, 0x00ce, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x00cc, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f}; /* None of the following blocks are defined in T.61. */ static const wvec64 u1e0 = { 0x003f, 0x003f, 0xc742, 0xc762, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xc744, 0xc764, 0x003f, 0x003f, 0x003f, 0x003f, 0xcb44, 0xcb64, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xc746, 0xc766, 0xc547, 0xc567, 0xc748, 0xc768, 0x003f, 0x003f, 0xc848, 0xc868, 0xcb48, 0xcb68, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xc24b, 0xc26b, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xc24d, 0xc26d, }; static const wvec64 u1e1 = { 0xc74d, 0xc76d, 0x003f, 0x003f, 0xc74e, 0xc76e, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xc250, 0xc270, 0xc750, 0xc770, 0xc752, 0xc772, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xc753, 0xc773, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xc754, 0xc774, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xc456, 0xc476, 0x003f, 0x003f, }; static const wvec64 u1e2 = { 0xc157, 0xc177, 0xc257, 0xc277, 0xc857, 0xc877, 0xc757, 0xc777, 0x003f, 0x003f, 0xc758, 0xc778, 0xc858, 0xc878, 0xc759, 0xc779, 0xc35a, 0xc37a, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xc874, 0xca77, 0xca79, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xc445, 0xc465, 0x003f, 0x003f, }; static const wvec64 u1e3 = { 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0xc159, 0xc179, 0x003f, 0x003f, 0x003f, 0x003f, 0xc459, 0xc479, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, }; static const wvec64 *wc00[] = { &u000, &u001, &u002, &u003, &u010, &u011, NULL, &u013, &u020, NULL, NULL, &u023, &u030, NULL, NULL, NULL}; static const wvec64 *wc1e[] = { &u1e0, &u1e1, &u1e2, &u1e3}; int ldap_utf8s_to_t61s( struct berval *src, struct berval *dst ) { char *c, *d; wchar_t tmp; int i, j, tlen = 0; /* Just count the length of the T.61 result first */ for (i=0,c=src->bv_val; i < src->bv_len;) { j = ldap_x_utf8_to_wc( &tmp, c ); if (j == -1) return LDAP_INVALID_SYNTAX; switch (tmp >> 8) { case 0x00: case 0x01: case 0x02: case 0x03: if (wc00[tmp >> 6] && ((*wc00[tmp >> 6])[tmp & 0x3f] & 0xff00)) { tlen++; } tlen++; break; case 0x1e: if ((*wc1e[(tmp >> 6) & 3])[tmp & 0x3f] & 0xff00) { tlen++; } case 0x21: default: tlen ++; break; } i += j; c += j; } dst->bv_len = tlen; dst->bv_val = LDAP_MALLOC( tlen+1 ); if (!dst->bv_val) return LDAP_NO_MEMORY; d = dst->bv_val; for (i=0,c=src->bv_val; i < src->bv_len;) { j = ldap_x_utf8_to_wc( &tmp, c ); switch (tmp >> 8) { case 0x00: case 0x01: case 0x02: if (wc00[tmp >> 6]) { tmp = (*wc00[tmp >> 6])[tmp & 0x3f]; if (tmp & 0xff00) *d++ = (tmp >> 8); *d++ = tmp & 0xff; } else { *d++ = 0x3f; } break; case 0x03: /* swap order of non-spacing characters */ if (wc00[tmp >> 6]) { wchar_t t2 = (*wc00[tmp >> 6])[tmp & 0x3f]; if (t2 != 0x3f) { d[0] = d[-1]; d[-1] = t2; d++; } else { *d++ = 0x3f; } } else { *d++ = 0x3f; } break; case 0x1e: tmp = (*wc1e[(tmp >> 6) & 3])[tmp & 0x3f]; if (tmp & 0xff00) *d++ = (tmp >> 8); *d++ = tmp & 0xff; break; case 0x21: if (tmp == 0x2126) { *d++ = 0xe0; break; } /* FALLTHRU */ default: *d++ = 0x3f; break; } i += j; c += j; } *d = '\0'; return LDAP_SUCCESS; } openldap-2.5.11+dfsg/libraries/libldap/sasl.c0000644000175000017500000004541414172327167017540 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* * BindRequest ::= SEQUENCE { * version INTEGER, * name DistinguishedName, -- who * authentication CHOICE { * simple [0] OCTET STRING -- passwd * krbv42ldap [1] OCTET STRING -- OBSOLETE * krbv42dsa [2] OCTET STRING -- OBSOLETE * sasl [3] SaslCredentials -- LDAPv3 * } * } * * BindResponse ::= SEQUENCE { * COMPONENTS OF LDAPResult, * serverSaslCreds OCTET STRING OPTIONAL -- LDAPv3 * } * */ #include "portable.h" #include #include #include #include #include #include #include "ldap-int.h" BerElement * ldap_build_bind_req( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *mechanism, struct berval *cred, LDAPControl **sctrls, LDAPControl **cctrls, ber_int_t *msgidp ) { BerElement *ber; int rc; if( mechanism == LDAP_SASL_SIMPLE ) { if( dn == NULL && cred != NULL && cred->bv_len ) { /* use default binddn */ dn = ld->ld_defbinddn; } } else if( ld->ld_version < LDAP_VERSION3 ) { ld->ld_errno = LDAP_NOT_SUPPORTED; return( NULL ); } if ( dn == NULL ) { dn = ""; } /* create a message to send */ if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { return( NULL ); } LDAP_NEXT_MSGID( ld, *msgidp ); if( mechanism == LDAP_SASL_SIMPLE ) { /* simple bind */ rc = ber_printf( ber, "{it{istON}" /*}*/, *msgidp, LDAP_REQ_BIND, ld->ld_version, dn, LDAP_AUTH_SIMPLE, cred ); } else if ( cred == NULL || cred->bv_val == NULL ) { /* SASL bind w/o credentials */ rc = ber_printf( ber, "{it{ist{sN}N}" /*}*/, *msgidp, LDAP_REQ_BIND, ld->ld_version, dn, LDAP_AUTH_SASL, mechanism ); } else { /* SASL bind w/ credentials */ rc = ber_printf( ber, "{it{ist{sON}N}" /*}*/, *msgidp, LDAP_REQ_BIND, ld->ld_version, dn, LDAP_AUTH_SASL, mechanism, cred ); } if( rc == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } /* Put Server Controls */ if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return( NULL ); } if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } return( ber ); } /* * ldap_sasl_bind - bind to the ldap server (and X.500). * The dn (usually NULL), mechanism, and credentials are provided. * The message id of the request initiated is provided upon successful * (LDAP_SUCCESS) return. * * Example: * ldap_sasl_bind( ld, NULL, "mechanism", * cred, NULL, NULL, &msgid ) */ int ldap_sasl_bind( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *mechanism, struct berval *cred, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp ) { BerElement *ber; int rc; ber_int_t id; Debug0( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n" ); assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( msgidp != NULL ); /* check client controls */ rc = ldap_int_client_controls( ld, cctrls ); if( rc != LDAP_SUCCESS ) return rc; ber = ldap_build_bind_req( ld, dn, mechanism, cred, sctrls, cctrls, &id ); if( !ber ) return ld->ld_errno; /* send the message */ *msgidp = ldap_send_initial_request( ld, LDAP_REQ_BIND, dn, ber, id ); if(*msgidp < 0) return ld->ld_errno; return LDAP_SUCCESS; } int ldap_sasl_bind_s( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *mechanism, struct berval *cred, LDAPControl **sctrls, LDAPControl **cctrls, struct berval **servercredp ) { int rc, msgid; LDAPMessage *result; struct berval *scredp = NULL; Debug0( LDAP_DEBUG_TRACE, "ldap_sasl_bind_s\n" ); /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */ if( servercredp != NULL ) { if (ld->ld_version < LDAP_VERSION3) { ld->ld_errno = LDAP_NOT_SUPPORTED; return ld->ld_errno; } *servercredp = NULL; } rc = ldap_sasl_bind( ld, dn, mechanism, cred, sctrls, cctrls, &msgid ); if ( rc != LDAP_SUCCESS ) { return( rc ); } #ifdef LDAP_CONNECTIONLESS if (LDAP_IS_UDP(ld)) { return( rc ); } #endif if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) { return( ld->ld_errno ); /* ldap_result sets ld_errno */ } /* parse the results */ scredp = NULL; if( servercredp != NULL ) { rc = ldap_parse_sasl_bind_result( ld, result, &scredp, 0 ); } if ( rc != LDAP_SUCCESS ) { ldap_msgfree( result ); return( rc ); } rc = ldap_result2error( ld, result, 1 ); if ( rc == LDAP_SUCCESS || rc == LDAP_SASL_BIND_IN_PROGRESS ) { if( servercredp != NULL ) { *servercredp = scredp; scredp = NULL; } } if ( scredp != NULL ) { ber_bvfree(scredp); } return rc; } /* * Parse BindResponse: * * BindResponse ::= [APPLICATION 1] SEQUENCE { * COMPONENTS OF LDAPResult, * serverSaslCreds [7] OCTET STRING OPTIONAL } * * LDAPResult ::= SEQUENCE { * resultCode ENUMERATED, * matchedDN LDAPDN, * errorMessage LDAPString, * referral [3] Referral OPTIONAL } */ int ldap_parse_sasl_bind_result( LDAP *ld, LDAPMessage *res, struct berval **servercredp, int freeit ) { ber_int_t errcode; struct berval* scred; ber_tag_t tag; BerElement *ber; Debug0( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n" ); assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( res != NULL ); if( servercredp != NULL ) { if( ld->ld_version < LDAP_VERSION2 ) { return LDAP_NOT_SUPPORTED; } *servercredp = NULL; } if( res->lm_msgtype != LDAP_RES_BIND ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; } scred = NULL; if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); ld->ld_error = NULL; } if ( ld->ld_matched ) { LDAP_FREE( ld->ld_matched ); ld->ld_matched = NULL; } /* parse results */ ber = ber_dup( res->lm_ber ); if( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } if ( ld->ld_version < LDAP_VERSION2 ) { tag = ber_scanf( ber, "{iA}", &errcode, &ld->ld_error ); if( tag == LBER_ERROR ) { ber_free( ber, 0 ); ld->ld_errno = LDAP_DECODING_ERROR; return ld->ld_errno; } } else { ber_len_t len; tag = ber_scanf( ber, "{eAA" /*}*/, &errcode, &ld->ld_matched, &ld->ld_error ); if( tag == LBER_ERROR ) { ber_free( ber, 0 ); ld->ld_errno = LDAP_DECODING_ERROR; return ld->ld_errno; } tag = ber_peek_tag(ber, &len); if( tag == LDAP_TAG_REFERRAL ) { /* skip 'em */ if( ber_scanf( ber, "x" ) == LBER_ERROR ) { ber_free( ber, 0 ); ld->ld_errno = LDAP_DECODING_ERROR; return ld->ld_errno; } tag = ber_peek_tag(ber, &len); } if( tag == LDAP_TAG_SASL_RES_CREDS ) { if( ber_scanf( ber, "O", &scred ) == LBER_ERROR ) { ber_free( ber, 0 ); ld->ld_errno = LDAP_DECODING_ERROR; return ld->ld_errno; } } } ber_free( ber, 0 ); if ( servercredp != NULL ) { *servercredp = scred; } else if ( scred != NULL ) { ber_bvfree( scred ); } ld->ld_errno = errcode; if ( freeit ) { ldap_msgfree( res ); } return( LDAP_SUCCESS ); } int ldap_pvt_sasl_getmechs ( LDAP *ld, char **pmechlist ) { /* we need to query the server for supported mechs anyway */ LDAPMessage *res, *e; char *attrs[] = { "supportedSASLMechanisms", NULL }; char **values, *mechlist; int rc; Debug0( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_getmech\n" ); rc = ldap_search_s( ld, "", LDAP_SCOPE_BASE, NULL, attrs, 0, &res ); if ( rc != LDAP_SUCCESS ) { return ld->ld_errno; } e = ldap_first_entry( ld, res ); if ( e == NULL ) { ldap_msgfree( res ); if ( ld->ld_errno == LDAP_SUCCESS ) { ld->ld_errno = LDAP_NO_SUCH_OBJECT; } return ld->ld_errno; } values = ldap_get_values( ld, e, "supportedSASLMechanisms" ); if ( values == NULL ) { ldap_msgfree( res ); ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE; return ld->ld_errno; } mechlist = ldap_charray2str( values, " " ); if ( mechlist == NULL ) { LDAP_VFREE( values ); ldap_msgfree( res ); ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } LDAP_VFREE( values ); ldap_msgfree( res ); *pmechlist = mechlist; return LDAP_SUCCESS; } /* * ldap_sasl_interactive_bind - interactive SASL authentication * * This routine uses interactive callbacks. * * LDAP_SUCCESS is returned upon success, the ldap error code * otherwise. LDAP_SASL_BIND_IN_PROGRESS is returned if further * calls are needed. */ int ldap_sasl_interactive_bind( LDAP *ld, LDAP_CONST char *dn, /* usually NULL */ LDAP_CONST char *mechs, LDAPControl **serverControls, LDAPControl **clientControls, unsigned flags, LDAP_SASL_INTERACT_PROC *interact, void *defaults, LDAPMessage *result, const char **rmech, int *msgid ) { char *smechs = NULL; int rc; #ifdef LDAP_CONNECTIONLESS if( LDAP_IS_UDP(ld) ) { /* Just force it to simple bind, silly to make the user * ask all the time. No, we don't ever actually bind, but I'll * let the final bind handler take care of saving the cdn. */ rc = ldap_simple_bind( ld, dn, NULL ); rc = rc < 0 ? rc : 0; goto done; } else #endif /* First time */ if ( !result ) { #ifdef HAVE_CYRUS_SASL if( mechs == NULL || *mechs == '\0' ) { mechs = ld->ld_options.ldo_def_sasl_mech; } #endif if( mechs == NULL || *mechs == '\0' ) { /* FIXME: this needs to be asynchronous too; * perhaps NULL should be disallowed for async usage? */ rc = ldap_pvt_sasl_getmechs( ld, &smechs ); if( rc != LDAP_SUCCESS ) { goto done; } Debug1( LDAP_DEBUG_TRACE, "ldap_sasl_interactive_bind: server supports: %s\n", smechs ); mechs = smechs; } else { Debug1( LDAP_DEBUG_TRACE, "ldap_sasl_interactive_bind: user selected: %s\n", mechs ); } } rc = ldap_int_sasl_bind( ld, dn, mechs, serverControls, clientControls, flags, interact, defaults, result, rmech, msgid ); done: if ( smechs ) LDAP_FREE( smechs ); return rc; } /* * ldap_sasl_interactive_bind_s - interactive SASL authentication * * This routine uses interactive callbacks. * * LDAP_SUCCESS is returned upon success, the ldap error code * otherwise. */ int ldap_sasl_interactive_bind_s( LDAP *ld, LDAP_CONST char *dn, /* usually NULL */ LDAP_CONST char *mechs, LDAPControl **serverControls, LDAPControl **clientControls, unsigned flags, LDAP_SASL_INTERACT_PROC *interact, void *defaults ) { const char *rmech = NULL; LDAPMessage *result = NULL; int rc, msgid; do { rc = ldap_sasl_interactive_bind( ld, dn, mechs, serverControls, clientControls, flags, interact, defaults, result, &rmech, &msgid ); ldap_msgfree( result ); if ( rc != LDAP_SASL_BIND_IN_PROGRESS ) break; #ifdef LDAP_CONNECTIONLESS if (LDAP_IS_UDP(ld)) { break; } #endif if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) { return( ld->ld_errno ); /* ldap_result sets ld_errno */ } } while ( rc == LDAP_SASL_BIND_IN_PROGRESS ); return rc; } #ifdef HAVE_CYRUS_SASL #ifdef HAVE_SASL_SASL_H #include #else #include #endif #endif /* HAVE_CYRUS_SASL */ static int sb_sasl_generic_remove( Sockbuf_IO_Desc *sbiod ); static int sb_sasl_generic_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { struct sb_sasl_generic_data *p; struct sb_sasl_generic_install *i; assert( sbiod != NULL ); i = (struct sb_sasl_generic_install *)arg; p = LBER_MALLOC( sizeof( *p ) ); if ( p == NULL ) return -1; p->ops = i->ops; p->ops_private = i->ops_private; p->sbiod = sbiod; p->flags = 0; ber_pvt_sb_buf_init( &p->sec_buf_in ); ber_pvt_sb_buf_init( &p->buf_in ); ber_pvt_sb_buf_init( &p->buf_out ); sbiod->sbiod_pvt = p; p->ops->init( p, &p->min_send, &p->max_send, &p->max_recv ); if ( ber_pvt_sb_grow_buffer( &p->sec_buf_in, p->min_send ) < 0 ) { sb_sasl_generic_remove( sbiod ); sock_errset(ENOMEM); return -1; } return 0; } static int sb_sasl_generic_remove( Sockbuf_IO_Desc *sbiod ) { struct sb_sasl_generic_data *p; assert( sbiod != NULL ); p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt; p->ops->fini(p); ber_pvt_sb_buf_destroy( &p->sec_buf_in ); ber_pvt_sb_buf_destroy( &p->buf_in ); ber_pvt_sb_buf_destroy( &p->buf_out ); LBER_FREE( p ); sbiod->sbiod_pvt = NULL; return 0; } static ber_len_t sb_sasl_generic_pkt_length( struct sb_sasl_generic_data *p, const unsigned char *buf, int debuglevel ) { ber_len_t size; assert( buf != NULL ); size = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; if ( size > p->max_recv ) { /* somebody is trying to mess me up. */ ber_log_printf( LDAP_DEBUG_ANY, debuglevel, "sb_sasl_generic_pkt_length: " "received illegal packet length of %lu bytes\n", (unsigned long)size ); size = 16; /* this should lead to an error. */ } return size + 4; /* include the size !!! */ } /* Drop a processed packet from the input buffer */ static void sb_sasl_generic_drop_packet ( struct sb_sasl_generic_data *p, int debuglevel ) { ber_slen_t len; len = p->sec_buf_in.buf_ptr - p->sec_buf_in.buf_end; if ( len > 0 ) AC_MEMCPY( p->sec_buf_in.buf_base, p->sec_buf_in.buf_base + p->sec_buf_in.buf_end, len ); if ( len >= 4 ) { p->sec_buf_in.buf_end = sb_sasl_generic_pkt_length(p, (unsigned char *) p->sec_buf_in.buf_base, debuglevel); } else { p->sec_buf_in.buf_end = 0; } p->sec_buf_in.buf_ptr = len; } static ber_slen_t sb_sasl_generic_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) { struct sb_sasl_generic_data *p; ber_slen_t ret, bufptr; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt; /* Are there anything left in the buffer? */ ret = ber_pvt_sb_copy_out( &p->buf_in, buf, len ); bufptr = ret; len -= ret; if ( len == 0 ) return bufptr; p->ops->reset_buf( p, &p->buf_in ); /* Read the length of the packet */ while ( p->sec_buf_in.buf_ptr < 4 ) { ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base + p->sec_buf_in.buf_ptr, 4 - p->sec_buf_in.buf_ptr ); #ifdef EINTR if ( ( ret < 0 ) && ( errno == EINTR ) ) continue; #endif if ( ret <= 0 ) return bufptr ? bufptr : ret; p->sec_buf_in.buf_ptr += ret; } /* The new packet always starts at p->sec_buf_in.buf_base */ ret = sb_sasl_generic_pkt_length(p, (unsigned char *) p->sec_buf_in.buf_base, sbiod->sbiod_sb->sb_debug ); /* Grow the packet buffer if necessary */ if ( ( p->sec_buf_in.buf_size < (ber_len_t) ret ) && ber_pvt_sb_grow_buffer( &p->sec_buf_in, ret ) < 0 ) { sock_errset(ENOMEM); return -1; } p->sec_buf_in.buf_end = ret; /* Did we read the whole encrypted packet? */ while ( p->sec_buf_in.buf_ptr < p->sec_buf_in.buf_end ) { /* No, we have got only a part of it */ ret = p->sec_buf_in.buf_end - p->sec_buf_in.buf_ptr; ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base + p->sec_buf_in.buf_ptr, ret ); #ifdef EINTR if ( ( ret < 0 ) && ( errno == EINTR ) ) continue; #endif if ( ret <= 0 ) return bufptr ? bufptr : ret; p->sec_buf_in.buf_ptr += ret; } /* Decode the packet */ ret = p->ops->decode( p, &p->sec_buf_in, &p->buf_in ); /* Drop the packet from the input buffer */ sb_sasl_generic_drop_packet( p, sbiod->sbiod_sb->sb_debug ); if ( ret != 0 ) { ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug, "sb_sasl_generic_read: failed to decode packet\n" ); sock_errset(EIO); return -1; } bufptr += ber_pvt_sb_copy_out( &p->buf_in, (char*) buf + bufptr, len ); return bufptr; } static ber_slen_t sb_sasl_generic_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) { struct sb_sasl_generic_data *p; int ret; ber_len_t len2; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt; /* Is there anything left in the buffer? */ if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) { ret = ber_pvt_sb_do_write( sbiod, &p->buf_out ); if ( ret < 0 ) return ret; /* Still have something left?? */ if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) { sock_errset(EAGAIN); return -1; } } len2 = p->max_send - 100; /* For safety margin */ len2 = len > len2 ? len2 : len; /* If we're just retrying a partial write, tell the * caller it's done. Let them call again if there's * still more left to write. */ if ( p->flags & LDAP_PVT_SASL_PARTIAL_WRITE ) { p->flags ^= LDAP_PVT_SASL_PARTIAL_WRITE; return len2; } /* now encode the next packet. */ p->ops->reset_buf( p, &p->buf_out ); ret = p->ops->encode( p, buf, len2, &p->buf_out ); if ( ret != 0 ) { ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug, "sb_sasl_generic_write: failed to encode packet\n" ); sock_errset(EIO); return -1; } ret = ber_pvt_sb_do_write( sbiod, &p->buf_out ); if ( ret < 0 ) { /* error? */ int err = sock_errno(); /* caller can retry this */ if ( err == EAGAIN || err == EWOULDBLOCK || err == EINTR ) p->flags |= LDAP_PVT_SASL_PARTIAL_WRITE; return ret; } else if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) { /* partial write? pretend nothing got written */ p->flags |= LDAP_PVT_SASL_PARTIAL_WRITE; sock_errset(EAGAIN); len2 = -1; } /* return number of bytes encoded, not written, to ensure * no byte is encoded twice (even if only sent once). */ return len2; } static int sb_sasl_generic_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { struct sb_sasl_generic_data *p; p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt; if ( opt == LBER_SB_OPT_DATA_READY ) { if ( p->buf_in.buf_ptr != p->buf_in.buf_end ) return 1; } return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); } Sockbuf_IO ldap_pvt_sockbuf_io_sasl_generic = { sb_sasl_generic_setup, /* sbi_setup */ sb_sasl_generic_remove, /* sbi_remove */ sb_sasl_generic_ctrl, /* sbi_ctrl */ sb_sasl_generic_read, /* sbi_read */ sb_sasl_generic_write, /* sbi_write */ NULL /* sbi_close */ }; int ldap_pvt_sasl_generic_install( Sockbuf *sb, struct sb_sasl_generic_install *install_arg ) { Debug0( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_generic_install\n" ); /* don't install the stuff unless security has been negotiated */ if ( !ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, &ldap_pvt_sockbuf_io_sasl_generic ) ) { #ifdef LDAP_DEBUG ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_APPLICATION, (void *)"sasl_generic_" ); #endif ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_sasl_generic, LBER_SBIOD_LEVEL_APPLICATION, install_arg ); } return LDAP_SUCCESS; } void ldap_pvt_sasl_generic_remove( Sockbuf *sb ) { ber_sockbuf_remove_io( sb, &ldap_pvt_sockbuf_io_sasl_generic, LBER_SBIOD_LEVEL_APPLICATION ); #ifdef LDAP_DEBUG ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_APPLICATION ); #endif } openldap-2.5.11+dfsg/libraries/libldap/txn.c0000644000175000017500000000552014172327167017401 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2006-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This program was originally developed by Kurt D. Zeilenga for inclusion * in OpenLDAP Software. */ /* * LDAPv3 Transactions (draft-zeilenga-ldap-txn) */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" #include "ldap_log.h" int ldap_txn_start( LDAP *ld, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp ) { return ldap_extended_operation( ld, LDAP_EXOP_TXN_START, NULL, sctrls, cctrls, msgidp ); } int ldap_txn_start_s( LDAP *ld, LDAPControl **sctrls, LDAPControl **cctrls, struct berval **txnid ) { assert( txnid != NULL ); return ldap_extended_operation_s( ld, LDAP_EXOP_TXN_START, NULL, sctrls, cctrls, NULL, txnid ); } int ldap_txn_end( LDAP *ld, int commit, struct berval *txnid, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp ) { int rc; BerElement *txnber = NULL; struct berval *txnval = NULL; assert( txnid != NULL ); txnber = ber_alloc_t( LBER_USE_DER ); if( commit ) { ber_printf( txnber, "{ON}", txnid ); } else { ber_printf( txnber, "{bON}", commit, txnid ); } ber_flatten( txnber, &txnval ); rc = ldap_extended_operation( ld, LDAP_EXOP_TXN_END, txnval, sctrls, cctrls, msgidp ); ber_free( txnber, 1 ); return rc; } int ldap_txn_end_s( LDAP *ld, int commit, struct berval *txnid, LDAPControl **sctrls, LDAPControl **cctrls, int *retidp ) { int rc; BerElement *txnber = NULL; struct berval *txnval = NULL; struct berval *retdata = NULL; if ( retidp != NULL ) *retidp = -1; txnber = ber_alloc_t( LBER_USE_DER ); if( commit ) { ber_printf( txnber, "{ON}", txnid ); } else { ber_printf( txnber, "{bON}", commit, txnid ); } ber_flatten( txnber, &txnval ); rc = ldap_extended_operation_s( ld, LDAP_EXOP_TXN_END, txnval, sctrls, cctrls, NULL, &retdata ); ber_free( txnber, 1 ); /* parse retdata */ if( retdata != NULL ) { BerElement *ber; ber_tag_t tag; ber_int_t retid; if( retidp == NULL ) goto done; ber = ber_init( retdata ); if( ber == NULL ) { rc = ld->ld_errno = LDAP_NO_MEMORY; goto done; } tag = ber_scanf( ber, "i", &retid ); ber_free( ber, 1 ); if ( tag != LBER_INTEGER ) { rc = ld->ld_errno = LDAP_DECODING_ERROR; goto done; } *retidp = (int) retid; done: ber_bvfree( retdata ); } return rc; } openldap-2.5.11+dfsg/libraries/libldap/compare.c0000644000175000017500000001047714172327167020225 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ #include "portable.h" #include #include #include #include #include "ldap-int.h" #include "ldap_log.h" /* The compare request looks like this: * CompareRequest ::= SEQUENCE { * entry DistinguishedName, * ava SEQUENCE { * type AttributeType, * value AttributeValue * } * } */ BerElement * ldap_build_compare_req( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *attr, struct berval *bvalue, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp ) { BerElement *ber; int rc; /* create a message to send */ if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { return( NULL ); } LDAP_NEXT_MSGID(ld, *msgidp); rc = ber_printf( ber, "{it{s{sON}N}", /* '}' */ *msgidp, LDAP_REQ_COMPARE, dn, attr, bvalue ); if ( rc == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } /* Put Server Controls */ if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return( NULL ); } if( ber_printf( ber, /*{*/ "N}" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } return( ber ); } /* * ldap_compare_ext - perform an ldap extended compare operation. The dn * of the entry to compare to and the attribute and value to compare (in * attr and value) are supplied. The msgid of the response is returned. * * Example: * struct berval bvalue = { "secret", sizeof("secret")-1 }; * rc = ldap_compare( ld, "c=us@cn=bob", * "userPassword", &bvalue, * sctrl, cctrl, &msgid ) */ int ldap_compare_ext( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *attr, struct berval *bvalue, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp ) { int rc; BerElement *ber; ber_int_t id; Debug0( LDAP_DEBUG_TRACE, "ldap_compare\n" ); assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( dn != NULL ); assert( attr != NULL ); assert( msgidp != NULL ); /* check client controls */ rc = ldap_int_client_controls( ld, cctrls ); if( rc != LDAP_SUCCESS ) return rc; ber = ldap_build_compare_req( ld, dn, attr, bvalue, sctrls, cctrls, &id ); if( !ber ) return ld->ld_errno; /* send the message */ *msgidp = ldap_send_initial_request( ld, LDAP_REQ_COMPARE, dn, ber, id ); return ( *msgidp < 0 ? ld->ld_errno : LDAP_SUCCESS ); } /* * ldap_compare_ext - perform an ldap extended compare operation. The dn * of the entry to compare to and the attribute and value to compare (in * attr and value) are supplied. The msgid of the response is returned. * * Example: * msgid = ldap_compare( ld, "c=us@cn=bob", "userPassword", "secret" ) */ int ldap_compare( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *attr, LDAP_CONST char *value ) { int msgid; struct berval bvalue; assert( value != NULL ); bvalue.bv_val = (char *) value; bvalue.bv_len = (value == NULL) ? 0 : strlen( value ); return ldap_compare_ext( ld, dn, attr, &bvalue, NULL, NULL, &msgid ) == LDAP_SUCCESS ? msgid : -1; } int ldap_compare_ext_s( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *attr, struct berval *bvalue, LDAPControl **sctrl, LDAPControl **cctrl ) { int rc; int msgid; LDAPMessage *res; rc = ldap_compare_ext( ld, dn, attr, bvalue, sctrl, cctrl, &msgid ); if ( rc != LDAP_SUCCESS ) return( rc ); if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, &res ) == -1 || !res ) return( ld->ld_errno ); return( ldap_result2error( ld, res, 1 ) ); } int ldap_compare_s( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *attr, LDAP_CONST char *value ) { struct berval bvalue; assert( value != NULL ); bvalue.bv_val = (char *) value; bvalue.bv_len = (value == NULL) ? 0 : strlen( value ); return ldap_compare_ext_s( ld, dn, attr, &bvalue, NULL, NULL ); } openldap-2.5.11+dfsg/libraries/libldap/messages.c0000644000175000017500000000241314172327167020375 0ustar ryanryan/* messages.c */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" LDAPMessage * ldap_first_message( LDAP *ld, LDAPMessage *chain ) { assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( chain != NULL ); return chain; } LDAPMessage * ldap_next_message( LDAP *ld, LDAPMessage *msg ) { assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( msg != NULL ); return msg->lm_chain; } int ldap_count_messages( LDAP *ld, LDAPMessage *chain ) { int i; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); for ( i = 0; chain != NULL; chain = chain->lm_chain ) { i++; } return( i ); } BerElement* ldap_get_message_ber( LDAPMessage *ld ) { return ld->lm_ber; } openldap-2.5.11+dfsg/libraries/libldap/cancel.c0000644000175000017500000000337214172327167020020 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This program was originally developed by Kurt D. Zeilenga for inclusion * in OpenLDAP Software. */ /* * LDAPv3 Cancel Operation Request */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" #include "ldap_log.h" int ldap_cancel( LDAP *ld, int cancelid, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp ) { BerElement *cancelidber = NULL; struct berval cancelidvalp = { 0, NULL }; int rc; cancelidber = ber_alloc_t( LBER_USE_DER ); ber_printf( cancelidber, "{i}", cancelid ); ber_flatten2( cancelidber, &cancelidvalp, 0 ); rc = ldap_extended_operation( ld, LDAP_EXOP_CANCEL, &cancelidvalp, sctrls, cctrls, msgidp ); ber_free( cancelidber, 1 ); return rc; } int ldap_cancel_s( LDAP *ld, int cancelid, LDAPControl **sctrls, LDAPControl **cctrls ) { BerElement *cancelidber = NULL; struct berval cancelidvalp = { 0, NULL }; int rc; cancelidber = ber_alloc_t( LBER_USE_DER ); ber_printf( cancelidber, "{i}", cancelid ); ber_flatten2( cancelidber, &cancelidvalp, 0 ); rc = ldap_extended_operation_s( ld, LDAP_EXOP_CANCEL, &cancelidvalp, sctrls, cctrls, NULL, NULL ); ber_free( cancelidber, 1 ); return rc; } openldap-2.5.11+dfsg/libraries/libldap/thr_debug.c0000644000175000017500000011006614172327167020535 0ustar ryanryan/* thr_debug.c - wrapper around the chosen thread wrapper, for debugging. */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2005-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* * This package provides several types of thread operation debugging: * * - Check the results of operations on threads, mutexes, condition * variables and read/write locks. Also check some thread pool * operations, but not those for which failure can happen in normal * slapd operation. * * - Wrap those types except threads and pools in structs with state * information, and check that on all operations: * * + Check that the resources are initialized and are only used at * their original address (i.e. not realloced or copied). * * + Check the owner (thread ID) on mutex operations. * * + Optionally allocate a reference to a byte of dummy memory. * This lets malloc debuggers see some incorrect use as memory * leaks, access to freed memory, etc. * * - Print an error message and by default abort() upon errors. * * - Print a count of leaked thread resources after cleanup. * * Compile-time (./configure) setup: Macros defined in CPPFLAGS. * * LDAP_THREAD_DEBUG or LDAP_THREAD_DEBUG=2 * Enables debugging, but value & 2 turns off type wrapping. * * LDAP_UINTPTR_T=integer type to hold pointers, preferably unsigned. * Used by dummy memory option "scramble". Default = unsigned long. * * LDAP_DEBUG_THREAD_NONE = initializer for a "no thread" thread ID. * * In addition, you may need to set up an implementation-specific way * to enable whatever error checking your thread library provides. * Currently only implemented for Posix threads (pthreads), where * you may need to define LDAP_INT_THREAD_MUTEXATTR. The default * is PTHREAD_MUTEX_ERRORCHECK, or PTHREAD_MUTEX_ERRORCHECK_NP for * Linux threads. See pthread_mutexattr_settype(3). * * Run-time configuration: * * Memory debugging tools: * Tools that report uninitialized memory accesses should disable * such warnings about the function debug_already_initialized(). * Alternatively, include "noreinit" (below) in $LDAP_THREAD_DEBUG. * * Environment variable $LDAP_THREAD_DEBUG: * The variable may contain a comma- or space-separated option list. * Options: * off - Disable this package. (It still slows things down). * tracethreads - Report create/join/exit/kill of threads. * noabort - Do not abort() on errors. * noerror - Do not report errors. Implies noabort. * nocount - Do not report counts of unreleased resources. * nosync - Disable tests that use synchronization and thus * clearly affect thread scheduling: * Implies nocount, and cancels threadID if that is set. * Note that if you turn on tracethreads or malloc * debugging, these also use library calls which may * affect thread scheduling (fprintf and malloc). * The following options do not apply if type wrapping is disabled: * nomem - Do not check memory operations. * Implies noreinit,noalloc. * noreinit - Do not catch reinitialization of existing resources. * (That test accesses uninitialized memory). * threadID - Trace thread IDs. Currently mostly useless. * Malloc debugging -- allocate dummy memory for initialized * resources, so malloc debuggers will report them as memory leaks: * noalloc - Default. Do not allocate dummy memory. * alloc - Store a pointer to dummy memory. However, leak * detectors might not catch unreleased resources in * global variables. * scramble - Store bitwise complement of dummy memory pointer. * That never escapes memory leak detectors - * but detection while the program is running will * report active resources as leaks. Do not * use this if a garbage collector is in use:-) * adjptr - Point to end of dummy memory. * Purify reports these as "potential leaks" (PLK). * I have not checked other malloc debuggers. */ #include "portable.h" #if defined( LDAP_THREAD_DEBUG ) #include #include #include #include #include "ldap_pvt_thread.h" /* Get the thread interface */ #define LDAP_THREAD_IMPLEMENTATION #define LDAP_THREAD_DEBUG_IMPLEMENTATION #define LDAP_THREAD_RDWR_IMPLEMENTATION #define LDAP_THREAD_POOL_IMPLEMENTATION #include "ldap_thr_debug.h" /* Get the underlying implementation */ #ifndef LDAP_THREAD_DEBUG_WRAP #undef LDAP_THREAD_DEBUG_THREAD_ID #elif !defined LDAP_THREAD_DEBUG_THREAD_ID #define LDAP_THREAD_DEBUG_THREAD_ID 1 #endif /* Use native malloc - the OpenLDAP wrappers may defeat malloc debuggers */ #undef malloc #undef calloc #undef realloc #undef free /* Options from environment variable $LDAP_THREAD_DEBUG */ enum { Count_no = 0, Count_yes, Count_reported, Count_reported_more }; static int count = Count_yes; #ifdef LDAP_THREAD_DEBUG_WRAP enum { Wrap_noalloc, Wrap_alloc, Wrap_scramble, Wrap_adjptr }; static int wraptype = Wrap_noalloc, wrap_offset, unwrap_offset; static int nomem, noreinit; #endif #if LDAP_THREAD_DEBUG_THREAD_ID +0 static int threadID; #else enum { threadID = 0 }; #endif static int nodebug, noabort, noerror, nosync, tracethreads; static int wrap_threads; static int options_done; /* ldap_pvt_thread_initialize() called, ldap_pvt_thread_destroy() not called */ static int threading_enabled; /* Resource counts */ enum { Idx_unexited_thread, Idx_unjoined_thread, Idx_locked_mutex, Idx_mutex, Idx_cond, Idx_rdwr, Idx_tpool, Idx_max }; static int resource_counts[Idx_max]; static const char *const resource_names[] = { "unexited threads", "unjoined threads", "locked mutexes", "mutexes", "conds", "rdwrs", "thread pools" }; static ldap_int_thread_mutex_t resource_mutexes[Idx_max]; /* Hide pointers from malloc debuggers. */ #define SCRAMBLE(ptr) (~(LDAP_UINTPTR_T) (ptr)) #define UNSCRAMBLE_usagep(num) ((ldap_debug_usage_info_t *) ~(num)) #define UNSCRAMBLE_dummyp(num) ((unsigned char *) ~(num)) #define WARN(var, msg) (warn (__FILE__, __LINE__, (msg), #var, (var))) #define WARN_IF(rc, msg) {if (rc) warn (__FILE__, __LINE__, (msg), #rc, (rc));} #define ERROR(var, msg) { \ if (!noerror) { \ errmsg(__FILE__, __LINE__, (msg), #var, (var)); \ if( !noabort ) abort(); \ } \ } #define ERROR_IF(rc, msg) { \ if (!noerror) { \ int rc_ = (rc); \ if (rc_) { \ errmsg(__FILE__, __LINE__, (msg), #rc, rc_); \ if( !noabort ) abort(); \ } \ } \ } #ifdef LDAP_THREAD_DEBUG_WRAP #define MEMERROR_IF(rc, msg, mem_act) { \ if (!noerror) { \ int rc_ = (rc); \ if (rc_) { \ errmsg(__FILE__, __LINE__, (msg), #rc, rc_); \ if( wraptype != Wrap_noalloc ) { mem_act; } \ if( !noabort ) abort(); \ } \ } \ } #endif /* LDAP_THREAD_DEBUG_WRAP */ #if 0 static void warn( const char *file, int line, const char *msg, const char *var, int val ) { fprintf( stderr, (strpbrk( var, "!=" ) ? "%s:%d: %s warning: %s\n" : "%s:%d: %s warning: %s is %d\n"), file, line, msg, var, val ); } #endif static void errmsg( const char *file, int line, const char *msg, const char *var, int val ) { fprintf( stderr, (strpbrk( var, "!=" ) ? "%s:%d: %s error: %s\n" : "%s:%d: %s error: %s is %d\n"), file, line, msg, var, val ); } static void count_resource_leaks( void ) { int i, j; char errbuf[200]; if( count == Count_yes ) { count = Count_reported; #if 0 /* Could break if there are still threads after atexit */ for( i = j = 0; i < Idx_max; i++ ) j |= ldap_int_thread_mutex_destroy( &resource_mutexes[i] ); WARN_IF( j, "ldap_debug_thread_destroy:mutexes" ); #endif for( i = j = 0; i < Idx_max; i++ ) if( resource_counts[i] ) j += sprintf( errbuf + j, ", %d %s", resource_counts[i], resource_names[i] ); if( j ) fprintf( stderr, "== thr_debug: Leaked%s. ==\n", errbuf + 1 ); } } static void get_options( void ) { static const struct option_info_s { const char *name; int *var, val; } option_info[] = { { "off", &nodebug, 1 }, { "noabort", &noabort, 1 }, { "noerror", &noerror, 1 }, { "nocount", &count, Count_no }, { "nosync", &nosync, 1 }, #if LDAP_THREAD_DEBUG_THREAD_ID +0 { "threadID", &threadID, 1 }, #endif #ifdef LDAP_THREAD_DEBUG_WRAP { "nomem", &nomem, 1 }, { "noreinit", &noreinit, 1 }, { "noalloc", &wraptype, Wrap_noalloc }, { "alloc", &wraptype, Wrap_alloc }, { "adjptr", &wraptype, Wrap_adjptr }, { "scramble", &wraptype, Wrap_scramble }, #endif { "tracethreads", &tracethreads, 1 }, { NULL, NULL, 0 } }; const char *s = getenv( "LDAP_THREAD_DEBUG" ); if( s != NULL ) { while( *(s += strspn( s, ", \t\r\n" )) != '\0' ) { size_t optlen = strcspn( s, ", \t\r\n" ); const struct option_info_s *oi = option_info; while( oi->name && (strncasecmp( oi->name, s, optlen ) || oi->name[optlen]) ) oi++; if( oi->name ) *oi->var = oi->val; else fprintf( stderr, "== thr_debug: Unknown $%s option '%.*s' ==\n", "LDAP_THREAD_DEBUG", (int) optlen, s ); s += optlen; } } if( nodebug ) { tracethreads = 0; nosync = noerror = 1; } if( nosync ) count = Count_no; if( noerror ) noabort = 1; #if LDAP_THREAD_DEBUG_THREAD_ID +0 if( nosync ) threadID = 0; #endif #ifdef LDAP_THREAD_DEBUG_WRAP if( noerror ) nomem = 1; if( !nomem ) { static const ldap_debug_usage_info_t usage; if( sizeof(LDAP_UINTPTR_T) < sizeof(unsigned char *) || sizeof(LDAP_UINTPTR_T) < sizeof(ldap_debug_usage_info_t *) || UNSCRAMBLE_usagep( SCRAMBLE( &usage ) ) != &usage || UNSCRAMBLE_dummyp( SCRAMBLE( (unsigned char *) 0 ) ) ) { fputs( "== thr_debug: Memory checks unsupported, " "adding nomem to $LDAP_THREAD_DEBUG ==\n", stderr ); nomem = 1; } } if( nomem ) { noreinit = 1; wraptype = Wrap_noalloc; } unwrap_offset = -(wrap_offset = (wraptype == Wrap_adjptr)); #endif wrap_threads = (tracethreads || threadID || count); options_done = 1; } #ifndef LDAP_THREAD_DEBUG_WRAP #define WRAPPED(ptr) (ptr) #define GET_OWNER(ptr) 0 #define SET_OWNER(ptr, thread) ((void) 0) #define RESET_OWNER(ptr) ((void) 0) #define ASSERT_OWNER(ptr, msg) ((void) 0) #define ASSERT_NO_OWNER(ptr, msg) ((void) 0) #define init_usage(ptr, msg) ((void) 0) #define check_usage(ptr, msg) ((void) 0) #define destroy_usage(ptr) ((void) 0) #else /* LDAP_THREAD_DEBUG_WRAP */ /* Specialize this if the initializer is not appropriate. */ /* The ASSERT_NO_OWNER() definition may also need an override. */ #ifndef LDAP_DEBUG_THREAD_NONE #define LDAP_DEBUG_THREAD_NONE { -1 } /* "no thread" ldap_int_thread_t value */ #endif static const ldap_int_thread_t ldap_debug_thread_none = LDAP_DEBUG_THREAD_NONE; #define THREAD_MUTEX_OWNER(mutex) \ ldap_int_thread_equal( (mutex)->owner, ldap_int_thread_self() ) void ldap_debug_thread_assert_mutex_owner( const char *file, int line, const char *msg, ldap_pvt_thread_mutex_t *mutex ) { if( !(noerror || THREAD_MUTEX_OWNER( mutex )) ) { errmsg( file, line, msg, "ASSERT_MUTEX_OWNER", 0 ); if( !noabort ) abort(); } } #define WRAPPED(ptr) (&(ptr)->wrapped) #define GET_OWNER(ptr) ((ptr)->owner) #define SET_OWNER(ptr, thread) ((ptr)->owner = (thread)) #define RESET_OWNER(ptr) ((ptr)->owner = ldap_debug_thread_none) #define ASSERT_OWNER(ptr, msg) ERROR_IF( !THREAD_MUTEX_OWNER( ptr ), msg ) #ifndef ASSERT_NO_OWNER #define ASSERT_NO_OWNER(ptr, msg) ERROR_IF( \ !ldap_int_thread_equal( (ptr)->owner, ldap_debug_thread_none ), msg ) #endif /* Try to provoke memory access error (for malloc debuggers) */ #define PEEK(mem) {if (-*(volatile const unsigned char *)(mem)) debug_noop();} static void debug_noop( void ); static int debug_already_initialized( const ldap_debug_usage_info_t *usage ); /* Name used for clearer error message */ #define IS_COPY_OR_MOVED(usage) ((usage)->self != SCRAMBLE( usage )) #define DUMMY_ADDR(usage) \ (wraptype == Wrap_scramble \ ? UNSCRAMBLE_dummyp( (usage)->mem.num ) \ : (usage)->mem.ptr + unwrap_offset) /* Mark resource as initialized */ static void init_usage( ldap_debug_usage_info_t *usage, const char *msg ) { if( !options_done ) get_options(); if( !nomem ) { if( !noreinit ) { MEMERROR_IF( debug_already_initialized( usage ), msg, { /* Provoke malloc debuggers */ unsigned char *dummy = DUMMY_ADDR( usage ); PEEK( dummy ); free( dummy ); free( dummy ); } ); } if( wraptype != Wrap_noalloc ) { unsigned char *dummy = malloc( 1 ); assert( dummy != NULL ); if( wraptype == Wrap_scramble ) { usage->mem.num = SCRAMBLE( dummy ); /* Verify that ptr<->integer casts work on this host */ assert( UNSCRAMBLE_dummyp( usage->mem.num ) == dummy ); } else { usage->mem.ptr = dummy + wrap_offset; } } } else { /* Unused, but set for readability in debugger */ usage->mem.ptr = NULL; } usage->self = SCRAMBLE( usage ); /* If nomem, only for debugger */ usage->magic = ldap_debug_magic; usage->state = ldap_debug_state_inited; } /* Check that resource is initialized and not copied/realloced */ static void check_usage( const ldap_debug_usage_info_t *usage, const char *msg ) { enum { Is_destroyed = 1 }; /* Name used for clearer error message */ if( usage->magic != ldap_debug_magic ) { ERROR( usage->magic, msg ); return; } switch( usage->state ) { case ldap_debug_state_destroyed: MEMERROR_IF( Is_destroyed, msg, { PEEK( DUMMY_ADDR( usage ) ); } ); break; default: ERROR( usage->state, msg ); break; case ldap_debug_state_inited: if( !nomem ) { MEMERROR_IF( IS_COPY_OR_MOVED( usage ), msg, { PEEK( DUMMY_ADDR( usage ) ); PEEK( UNSCRAMBLE_usagep( usage->self ) ); } ); } break; } } /* Mark resource as destroyed. */ /* Does not check for errors, call check_usage()/init_usage() first. */ static void destroy_usage( ldap_debug_usage_info_t *usage ) { if( usage->state == ldap_debug_state_inited ) { if( wraptype != Wrap_noalloc ) { free( DUMMY_ADDR( usage ) ); /* Do not reset the DUMMY_ADDR, leave it for malloc debuggers * in case the resource is used after it is freed. */ } usage->state = ldap_debug_state_destroyed; } } /* Define these after they are used, so they are hopefully not inlined */ static void debug_noop( void ) { } /* * Valid programs access uninitialized memory here unless "noreinit". * * Returns true if the resource is initialized and not copied/realloced. */ LDAP_GCCATTR((noinline)) static int debug_already_initialized( const ldap_debug_usage_info_t *usage ) { /* * 'ret' keeps the Valgrind warning "Conditional jump or move * depends on uninitialised value(s)" _inside_ this function. */ volatile int ret = 0; if( usage->state == ldap_debug_state_inited ) if( !IS_COPY_OR_MOVED( usage ) ) if( usage->magic == ldap_debug_magic ) ret = 1; return ret; } #endif /* LDAP_THREAD_DEBUG_WRAP */ #if !(LDAP_THREAD_DEBUG_THREAD_ID +0) typedef void ldap_debug_thread_t; #define init_thread_info() {} #define with_thread_info_lock(statements) { statements; } #define thread_info_detached(t) 0 #define add_thread_info(msg, thr, det) ((void) 0) #define remove_thread_info(tinfo, msg) ((void) 0) #define get_thread_info(thread, msg) NULL #else /* LDAP_THREAD_DEBUG_THREAD_ID */ /* * Thread ID tracking. Currently achieves little. * Should be either expanded or deleted. */ /* * Array of threads. Used instead of making ldap_pvt_thread_t a wrapper * around ldap_int_thread_t, which would slow down ldap_pvt_thread_self(). */ typedef struct { ldap_pvt_thread_t wrapped; ldap_debug_usage_info_t usage; int detached; int idx; } ldap_debug_thread_t; static ldap_debug_thread_t **thread_info; static unsigned int thread_info_size, thread_info_used; static ldap_int_thread_mutex_t thread_info_mutex; #define init_thread_info() { \ if( threadID ) { \ int mutex_init_rc = ldap_int_thread_mutex_init( &thread_info_mutex ); \ assert( mutex_init_rc == 0 ); \ } \ } #define with_thread_info_lock(statements) { \ int rc_wtl_ = ldap_int_thread_mutex_lock( &thread_info_mutex ); \ assert( rc_wtl_ == 0 ); \ { statements; } \ rc_wtl_ = ldap_int_thread_mutex_unlock( &thread_info_mutex ); \ assert( rc_wtl_ == 0 ); \ } #define thread_info_detached(t) ((t)->detached) static void add_thread_info( const char *msg, const ldap_pvt_thread_t *thread, int detached ) { ldap_debug_thread_t *t; if( thread_info_used >= thread_info_size ) { unsigned int more = thread_info_size + 8; unsigned int new_size = thread_info_size + more; t = calloc( more, sizeof(ldap_debug_thread_t) ); assert( t != NULL ); thread_info = realloc( thread_info, new_size * sizeof(*thread_info) ); assert( thread_info != NULL ); do { t->idx = thread_info_size; thread_info[thread_info_size++] = t++; } while( thread_info_size < new_size ); } t = thread_info[thread_info_used]; init_usage( &t->usage, msg ); t->wrapped = *thread; t->detached = detached; thread_info_used++; } static void remove_thread_info( ldap_debug_thread_t *t, const char *msg ) { ldap_debug_thread_t *last; int idx; check_usage( &t->usage, msg ); destroy_usage( &t->usage ); idx = t->idx; assert( thread_info[idx] == t ); last = thread_info[--thread_info_used]; assert( last->idx == thread_info_used ); (thread_info[idx] = last)->idx = idx; (thread_info[thread_info_used] = t )->idx = thread_info_used; } static ldap_debug_thread_t * get_thread_info( ldap_pvt_thread_t thread, const char *msg ) { unsigned int i; ldap_debug_thread_t *t; for( i = 0; i < thread_info_used; i++ ) { if( ldap_pvt_thread_equal( thread, thread_info[i]->wrapped ) ) break; } ERROR_IF( i == thread_info_used, msg ); t = thread_info[i]; check_usage( &t->usage, msg ); return t; } #endif /* LDAP_THREAD_DEBUG_THREAD_ID */ static char * thread_name( char *buf, int bufsize, ldap_pvt_thread_t thread ) { int i; --bufsize; if( bufsize > 2*sizeof(thread) ) bufsize = 2*sizeof(thread); for( i = 0; i < bufsize; i += 2 ) snprintf( buf+i, 3, "%02x", ((unsigned char *)&thread)[i/2] ); return buf; } /* Add (+/-1) to resource count unless "nocount". */ static void adjust_count( int which, int adjust ) { int rc; switch( count ) { case Count_no: break; case Count_yes: rc = ldap_int_thread_mutex_lock( &resource_mutexes[which] ); assert( rc == 0 ); resource_counts[which] += adjust; rc = ldap_int_thread_mutex_unlock( &resource_mutexes[which] ); assert( rc == 0 ); break; case Count_reported: fputs( "== thr_debug: More thread activity after exit ==\n", stderr ); count = Count_reported_more; /* FALL THROUGH */ case Count_reported_more: /* Not used, but result might be inspected with debugger */ /* (Hopefully threading is disabled by now...) */ resource_counts[which] += adjust; break; } } /* Wrappers for LDAP_THREAD_IMPLEMENTATION: */ /* Used instead of ldap_int_thread_initialize by ldap_pvt_thread_initialize */ int ldap_debug_thread_initialize( void ) { int i, rc, rc2; if( !options_done ) get_options(); ERROR_IF( threading_enabled, "ldap_debug_thread_initialize" ); threading_enabled = 1; rc = ldap_int_thread_initialize(); if( rc ) { ERROR( rc, "ldap_debug_thread_initialize:threads" ); threading_enabled = 0; } else { init_thread_info(); if( count != Count_no ) { for( i = rc2 = 0; i < Idx_max; i++ ) rc2 |= ldap_int_thread_mutex_init( &resource_mutexes[i] ); assert( rc2 == 0 ); /* FIXME: Only for static libldap as in init.c? If so, why? */ atexit( count_resource_leaks ); } } return rc; } /* Used instead of ldap_int_thread_destroy by ldap_pvt_thread_destroy */ int ldap_debug_thread_destroy( void ) { int rc; ERROR_IF( !threading_enabled, "ldap_debug_thread_destroy" ); /* sleep(1) -- need to wait for thread pool to finish? */ rc = ldap_int_thread_destroy(); if( rc ) { ERROR( rc, "ldap_debug_thread_destroy:threads" ); } else { threading_enabled = 0; } return rc; } int ldap_pvt_thread_set_concurrency( int n ) { int rc; ERROR_IF( !threading_enabled, "ldap_pvt_thread_set_concurrency" ); rc = ldap_int_thread_set_concurrency( n ); ERROR_IF( rc, "ldap_pvt_thread_set_concurrency" ); return rc; } int ldap_pvt_thread_get_concurrency( void ) { int rc; ERROR_IF( !threading_enabled, "ldap_pvt_thread_get_concurrency" ); rc = ldap_int_thread_get_concurrency(); ERROR_IF( rc, "ldap_pvt_thread_get_concurrency" ); return rc; } unsigned int ldap_pvt_thread_sleep( unsigned int interval ) { int rc; ERROR_IF( !threading_enabled, "ldap_pvt_thread_sleep" ); rc = ldap_int_thread_sleep( interval ); ERROR_IF( rc, "ldap_pvt_thread_sleep" ); return 0; } static void thread_exiting( const char *how, const char *msg ) { ldap_pvt_thread_t thread; #if 0 /* Detached threads may exit after ldap_debug_thread_destroy(). */ ERROR_IF( !threading_enabled, msg ); #endif thread = ldap_pvt_thread_self(); if( tracethreads ) { char buf[40]; fprintf( stderr, "== thr_debug: %s thread %s ==\n", how, thread_name( buf, sizeof(buf), thread ) ); } if( threadID ) { with_thread_info_lock({ ldap_debug_thread_t *t = get_thread_info( thread, msg ); if( thread_info_detached( t ) ) remove_thread_info( t, msg ); }); } adjust_count( Idx_unexited_thread, -1 ); } void ldap_pvt_thread_exit( void *retval ) { thread_exiting( "Exiting", "ldap_pvt_thread_exit" ); ldap_int_thread_exit( retval ); } typedef struct { void *(*start_routine)( void * ); void *arg; } ldap_debug_thread_call_t; static void * ldap_debug_thread_wrapper( void *arg ) { void *ret; ldap_debug_thread_call_t call = *(ldap_debug_thread_call_t *)arg; free( arg ); ret = call.start_routine( call.arg ); thread_exiting( "Returning from", "ldap_debug_thread_wrapper" ); return ret; } int ldap_pvt_thread_create( ldap_pvt_thread_t *thread, int detach, void *(*start_routine)( void * ), void *arg ) { int rc; if( !options_done ) get_options(); ERROR_IF( !threading_enabled, "ldap_pvt_thread_create" ); if( wrap_threads ) { ldap_debug_thread_call_t *call = malloc( sizeof( ldap_debug_thread_call_t ) ); assert( call != NULL ); call->start_routine = start_routine; call->arg = arg; start_routine = ldap_debug_thread_wrapper; arg = call; } if( threadID ) { with_thread_info_lock({ rc = ldap_int_thread_create( thread, detach, start_routine, arg ); if( rc == 0 ) add_thread_info( "ldap_pvt_thread_create", thread, detach ); }); } else { rc = ldap_int_thread_create( thread, detach, start_routine, arg ); } if( rc ) { ERROR( rc, "ldap_pvt_thread_create" ); if( wrap_threads ) free( arg ); } else { if( tracethreads ) { char buf[40], buf2[40]; fprintf( stderr, "== thr_debug: Created thread %s%s from thread %s ==\n", thread_name( buf, sizeof(buf), *thread ), detach ? " (detached)" : "", thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) ); } adjust_count( Idx_unexited_thread, +1 ); if( !detach ) adjust_count( Idx_unjoined_thread, +1 ); } return rc; } int ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return ) { int rc; ldap_debug_thread_t *t = NULL; ERROR_IF( !threading_enabled, "ldap_pvt_thread_join" ); if( tracethreads ) { char buf[40], buf2[40]; fprintf( stderr, "== thr_debug: Joining thread %s in thread %s ==\n", thread_name( buf, sizeof(buf), thread ), thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) ); } if( threadID ) with_thread_info_lock( { t = get_thread_info( thread, "ldap_pvt_thread_join" ); ERROR_IF( thread_info_detached( t ), "ldap_pvt_thread_join" ); } ); rc = ldap_int_thread_join( thread, thread_return ); if( rc ) { ERROR( rc, "ldap_pvt_thread_join" ); } else { if( threadID ) with_thread_info_lock( remove_thread_info( t, "ldap_pvt_thread_join" ) ); adjust_count( Idx_unjoined_thread, -1 ); } return rc; } int ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo ) { int rc; ERROR_IF( !threading_enabled, "ldap_pvt_thread_kill" ); if( tracethreads ) { char buf[40], buf2[40]; fprintf( stderr, "== thr_debug: Killing thread %s (sig %i) from thread %s ==\n", thread_name( buf, sizeof(buf), thread ), signo, thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) ); } rc = ldap_int_thread_kill( thread, signo ); ERROR_IF( rc, "ldap_pvt_thread_kill" ); return rc; } int ldap_pvt_thread_yield( void ) { int rc; ERROR_IF( !threading_enabled, "ldap_pvt_thread_yield" ); rc = ldap_int_thread_yield(); ERROR_IF( rc, "ldap_pvt_thread_yield" ); return rc; } ldap_pvt_thread_t ldap_pvt_thread_self( void ) { #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */ ERROR_IF( !threading_enabled, "ldap_pvt_thread_self" ); #endif return ldap_int_thread_self(); } int ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond ) { int rc; init_usage( &cond->usage, "ldap_pvt_thread_cond_init" ); rc = ldap_int_thread_cond_init( WRAPPED( cond ) ); if( rc ) { ERROR( rc, "ldap_pvt_thread_cond_init" ); destroy_usage( &cond->usage ); } else { adjust_count( Idx_cond, +1 ); } return rc; } int ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cond ) { int rc; check_usage( &cond->usage, "ldap_pvt_thread_cond_destroy" ); rc = ldap_int_thread_cond_destroy( WRAPPED( cond ) ); if( rc ) { ERROR( rc, "ldap_pvt_thread_cond_destroy" ); } else { destroy_usage( &cond->usage ); adjust_count( Idx_cond, -1 ); } return rc; } int ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond ) { int rc; check_usage( &cond->usage, "ldap_pvt_thread_cond_signal" ); rc = ldap_int_thread_cond_signal( WRAPPED( cond ) ); ERROR_IF( rc, "ldap_pvt_thread_cond_signal" ); return rc; } int ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cond ) { int rc; check_usage( &cond->usage, "ldap_pvt_thread_cond_broadcast" ); rc = ldap_int_thread_cond_broadcast( WRAPPED( cond ) ); ERROR_IF( rc, "ldap_pvt_thread_cond_broadcast" ); return rc; } int ldap_pvt_thread_cond_wait( ldap_pvt_thread_cond_t *cond, ldap_pvt_thread_mutex_t *mutex ) { int rc; ldap_int_thread_t owner; check_usage( &cond->usage, "ldap_pvt_thread_cond_wait:cond" ); check_usage( &mutex->usage, "ldap_pvt_thread_cond_wait:mutex" ); adjust_count( Idx_locked_mutex, -1 ); owner = GET_OWNER( mutex ); ASSERT_OWNER( mutex, "ldap_pvt_thread_cond_wait" ); RESET_OWNER( mutex ); rc = ldap_int_thread_cond_wait( WRAPPED( cond ), WRAPPED( mutex ) ); ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_cond_wait" ); SET_OWNER( mutex, rc ? owner : ldap_int_thread_self() ); adjust_count( Idx_locked_mutex, +1 ); ERROR_IF( rc, "ldap_pvt_thread_cond_wait" ); return rc; } int ldap_pvt_thread_mutex_recursive_init( ldap_pvt_thread_mutex_t *mutex ) { int rc; init_usage( &mutex->usage, "ldap_pvt_thread_mutex_recursive_init" ); rc = ldap_int_thread_mutex_recursive_init( WRAPPED( mutex ) ); if( rc ) { ERROR( rc, "ldap_pvt_thread_mutex_recursive_init" ); destroy_usage( &mutex->usage ); } else { RESET_OWNER( mutex ); adjust_count( Idx_mutex, +1 ); } return rc; } int ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex ) { int rc; init_usage( &mutex->usage, "ldap_pvt_thread_mutex_init" ); rc = ldap_int_thread_mutex_init( WRAPPED( mutex ) ); if( rc ) { ERROR( rc, "ldap_pvt_thread_mutex_init" ); destroy_usage( &mutex->usage ); } else { RESET_OWNER( mutex ); adjust_count( Idx_mutex, +1 ); } return rc; } int ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex ) { int rc; check_usage( &mutex->usage, "ldap_pvt_thread_mutex_destroy" ); ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_destroy" ); rc = ldap_int_thread_mutex_destroy( WRAPPED( mutex ) ); if( rc ) { ERROR( rc, "ldap_pvt_thread_mutex_destroy" ); } else { destroy_usage( &mutex->usage ); RESET_OWNER( mutex ); adjust_count( Idx_mutex, -1 ); } return rc; } int ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex ) { int rc; check_usage( &mutex->usage, "ldap_pvt_thread_mutex_lock" ); rc = ldap_int_thread_mutex_lock( WRAPPED( mutex ) ); if( rc ) { ERROR_IF( rc, "ldap_pvt_thread_mutex_lock" ); } else { ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_lock" ); SET_OWNER( mutex, ldap_int_thread_self() ); adjust_count( Idx_locked_mutex, +1 ); } return rc; } int ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mutex ) { int rc; check_usage( &mutex->usage, "ldap_pvt_thread_mutex_trylock" ); rc = ldap_int_thread_mutex_trylock( WRAPPED( mutex ) ); if( rc == 0 ) { ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_trylock" ); SET_OWNER( mutex, ldap_int_thread_self() ); adjust_count( Idx_locked_mutex, +1 ); } return rc; } int ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex ) { int rc; check_usage( &mutex->usage, "ldap_pvt_thread_mutex_unlock" ); ASSERT_OWNER( mutex, "ldap_pvt_thread_mutex_unlock" ); RESET_OWNER( mutex ); /* Breaks if this thread did not own the mutex */ rc = ldap_int_thread_mutex_unlock( WRAPPED( mutex ) ); if( rc ) { ERROR_IF( rc, "ldap_pvt_thread_mutex_unlock" ); } else { adjust_count( Idx_locked_mutex, -1 ); } return rc; } /* Wrappers for LDAP_THREAD_RDWR_IMPLEMENTATION: */ int ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rwlock ) { int rc; init_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_init" ); rc = ldap_int_thread_rdwr_init( WRAPPED( rwlock ) ); if( rc ) { ERROR( rc, "ldap_pvt_thread_rdwr_init" ); destroy_usage( &rwlock->usage ); } else { adjust_count( Idx_rdwr, +1 ); } return rc; } int ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rwlock ) { int rc; check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_destroy" ); rc = ldap_int_thread_rdwr_destroy( WRAPPED( rwlock ) ); if( rc ) { ERROR( rc, "ldap_pvt_thread_rdwr_destroy" ); } else { destroy_usage( &rwlock->usage ); adjust_count( Idx_rdwr, -1 ); } return rc; } int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock ) { int rc; check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rlock" ); rc = ldap_int_thread_rdwr_rlock( WRAPPED( rwlock ) ); ERROR_IF( rc, "ldap_pvt_thread_rdwr_rlock" ); return rc; } int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock ) { check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rtrylock" ); return ldap_int_thread_rdwr_rtrylock( WRAPPED( rwlock ) ); } int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock ) { int rc; check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_runlock" ); rc = ldap_int_thread_rdwr_runlock( WRAPPED( rwlock ) ); ERROR_IF( rc, "ldap_pvt_thread_rdwr_runlock" ); return rc; } int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock ) { int rc; check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wlock" ); rc = ldap_int_thread_rdwr_wlock( WRAPPED( rwlock ) ); ERROR_IF( rc, "ldap_pvt_thread_rdwr_wlock" ); return rc; } int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock ) { check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wtrylock" ); return ldap_int_thread_rdwr_wtrylock( WRAPPED( rwlock ) ); } int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock ) { int rc; check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wunlock" ); rc = ldap_int_thread_rdwr_wunlock( WRAPPED( rwlock ) ); ERROR_IF( rc, "ldap_pvt_thread_rdwr_wunlock" ); return rc; } #if defined(LDAP_RDWR_DEBUG) && !defined(LDAP_THREAD_HAVE_RDWR) int ldap_pvt_thread_rdwr_readers( ldap_pvt_thread_rdwr_t *rwlock ) { check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_readers" ); return ldap_int_thread_rdwr_readers( WRAPPED( rwlock ) ); } int ldap_pvt_thread_rdwr_writers( ldap_pvt_thread_rdwr_t *rwlock ) { check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_writers" ); return ldap_int_thread_rdwr_writers( WRAPPED( rwlock ) ); } int ldap_pvt_thread_rdwr_active( ldap_pvt_thread_rdwr_t *rwlock ) { check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_active" ); return ldap_int_thread_rdwr_active( WRAPPED( rwlock ) ); } #endif /* LDAP_RDWR_DEBUG && !LDAP_THREAD_HAVE_RDWR */ /* Some wrappers for LDAP_THREAD_POOL_IMPLEMENTATION: */ #ifdef LDAP_THREAD_POOL_IMPLEMENTATION int ldap_pvt_thread_pool_init( ldap_pvt_thread_pool_t *tpool, int max_threads, int max_pending ) { int rc; if( !options_done ) get_options(); ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_init" ); rc = ldap_int_thread_pool_init( tpool, max_threads, max_pending ); if( rc ) { ERROR( rc, "ldap_pvt_thread_pool_init" ); } else { adjust_count( Idx_tpool, +1 ); } return rc; } int ldap_pvt_thread_pool_submit( ldap_pvt_thread_pool_t *tpool, ldap_pvt_thread_start_t *start_routine, void *arg ) { int rc, has_pool; ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_submit" ); has_pool = (tpool && *tpool); rc = ldap_int_thread_pool_submit( tpool, start_routine, arg ); if( has_pool ) ERROR_IF( rc, "ldap_pvt_thread_pool_submit" ); return rc; } int ldap_pvt_thread_pool_maxthreads( ldap_pvt_thread_pool_t *tpool, int max_threads ) { ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_maxthreads" ); return ldap_int_thread_pool_maxthreads( tpool, max_threads ); } int ldap_pvt_thread_pool_backload( ldap_pvt_thread_pool_t *tpool ) { ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_backload" ); return ldap_int_thread_pool_backload( tpool ); } int ldap_pvt_thread_pool_destroy( ldap_pvt_thread_pool_t *tpool, int run_pending ) { int rc, has_pool; ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_destroy" ); has_pool = (tpool && *tpool); rc = ldap_int_thread_pool_destroy( tpool, run_pending ); if( has_pool ) { if( rc ) { ERROR( rc, "ldap_pvt_thread_pool_destroy" ); } else { adjust_count( Idx_tpool, -1 ); } } return rc; } int ldap_pvt_thread_pool_close( ldap_pvt_thread_pool_t *tpool, int run_pending ) { int rc, has_pool; ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_close" ); has_pool = (tpool && *tpool); rc = ldap_int_thread_pool_close( tpool, run_pending ); if( has_pool && rc ) { ERROR( rc, "ldap_pvt_thread_pool_close" ); } return rc; } int ldap_pvt_thread_pool_free( ldap_pvt_thread_pool_t *tpool ) { int rc, has_pool; ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_free" ); has_pool = (tpool && *tpool); rc = ldap_int_thread_pool_free( tpool ); if( has_pool ) { if( rc ) { ERROR( rc, "ldap_pvt_thread_pool_free" ); } else { adjust_count( Idx_tpool, -1 ); } } return rc; } int ldap_pvt_thread_pool_pause( ldap_pvt_thread_pool_t *tpool ) { ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_pause" ); return ldap_int_thread_pool_pause( tpool ); } int ldap_pvt_thread_pool_resume( ldap_pvt_thread_pool_t *tpool ) { ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_resume" ); return ldap_int_thread_pool_resume( tpool ); } int ldap_pvt_thread_pool_getkey( void *xctx, void *key, void **data, ldap_pvt_thread_pool_keyfree_t **kfree ) { #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */ ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_getkey" ); #endif return ldap_int_thread_pool_getkey( xctx, key, data, kfree ); } int ldap_pvt_thread_pool_setkey( void *xctx, void *key, void *data, ldap_pvt_thread_pool_keyfree_t *kfree, void **olddatap, ldap_pvt_thread_pool_keyfree_t **oldkfreep ) { int rc; ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_setkey" ); rc = ldap_int_thread_pool_setkey( xctx, key, data, kfree, olddatap, oldkfreep ); ERROR_IF( rc, "ldap_pvt_thread_pool_setkey" ); return rc; } void ldap_pvt_thread_pool_purgekey( void *key ) { ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_purgekey" ); ldap_int_thread_pool_purgekey( key ); } void * ldap_pvt_thread_pool_context( void ) { #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */ ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context" ); #endif return ldap_int_thread_pool_context(); } void ldap_pvt_thread_pool_context_reset( void *vctx ) { ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context_reset" ); ldap_int_thread_pool_context_reset( vctx ); } #endif /* LDAP_THREAD_POOL_IMPLEMENTATION */ #endif /* LDAP_THREAD_DEBUG */ openldap-2.5.11+dfsg/libraries/libldap/tls2.c0000644000175000017500000011721214172327167017456 0ustar ryanryan/* tls.c - Handle tls/ssl. */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: restructured by Howard Chu. */ #include "portable.h" #include "ldap_config.h" #include #include #include #include #include #include #include #include #include #include #include "ldap-int.h" #ifdef HAVE_TLS #include "ldap-tls.h" static tls_impl *tls_imp = &ldap_int_tls_impl; #define HAS_TLS( sb ) ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, \ (void *)tls_imp->ti_sbio ) #endif /* HAVE_TLS */ /* RFC2459 minimum required set of supported attribute types * in a certificate DN */ typedef struct oid_name { struct berval oid; struct berval name; } oid_name; static oid_name oids[] = { { BER_BVC("2.5.4.3"), BER_BVC("cn") }, { BER_BVC("2.5.4.4"), BER_BVC("sn") }, { BER_BVC("2.5.4.6"), BER_BVC("c") }, { BER_BVC("2.5.4.7"), BER_BVC("l") }, { BER_BVC("2.5.4.8"), BER_BVC("st") }, { BER_BVC("2.5.4.10"), BER_BVC("o") }, { BER_BVC("2.5.4.11"), BER_BVC("ou") }, { BER_BVC("2.5.4.12"), BER_BVC("title") }, { BER_BVC("2.5.4.41"), BER_BVC("name") }, { BER_BVC("2.5.4.42"), BER_BVC("givenName") }, { BER_BVC("2.5.4.43"), BER_BVC("initials") }, { BER_BVC("2.5.4.44"), BER_BVC("generationQualifier") }, { BER_BVC("2.5.4.46"), BER_BVC("dnQualifier") }, { BER_BVC("1.2.840.113549.1.9.1"), BER_BVC("email") }, { BER_BVC("0.9.2342.19200300.100.1.25"), BER_BVC("dc") }, { BER_BVNULL, BER_BVNULL } }; #ifdef HAVE_TLS LDAP_F(int) ldap_pvt_tls_check_hostname LDAP_P(( LDAP *ld, void *s, const char *name_in )); LDAP_F(int) ldap_pvt_tls_get_peercert LDAP_P(( void *s, struct berval *der )); void ldap_pvt_tls_ctx_free ( void *c ) { if ( !c ) return; tls_imp->ti_ctx_free( c ); } static void tls_ctx_ref( tls_ctx *ctx ) { if ( !ctx ) return; tls_imp->ti_ctx_ref( ctx ); } #ifdef LDAP_R_COMPILE /* * an extra mutex for the default ctx. */ static ldap_pvt_thread_mutex_t tls_def_ctx_mutex; #endif void ldap_int_tls_destroy( struct ldapoptions *lo ) { if ( lo->ldo_tls_ctx ) { ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx ); lo->ldo_tls_ctx = NULL; } if ( lo->ldo_tls_certfile ) { LDAP_FREE( lo->ldo_tls_certfile ); lo->ldo_tls_certfile = NULL; } if ( lo->ldo_tls_keyfile ) { LDAP_FREE( lo->ldo_tls_keyfile ); lo->ldo_tls_keyfile = NULL; } if ( lo->ldo_tls_dhfile ) { LDAP_FREE( lo->ldo_tls_dhfile ); lo->ldo_tls_dhfile = NULL; } if ( lo->ldo_tls_ecname ) { LDAP_FREE( lo->ldo_tls_ecname ); lo->ldo_tls_ecname = NULL; } if ( lo->ldo_tls_cacertfile ) { LDAP_FREE( lo->ldo_tls_cacertfile ); lo->ldo_tls_cacertfile = NULL; } if ( lo->ldo_tls_cacertdir ) { LDAP_FREE( lo->ldo_tls_cacertdir ); lo->ldo_tls_cacertdir = NULL; } if ( lo->ldo_tls_ciphersuite ) { LDAP_FREE( lo->ldo_tls_ciphersuite ); lo->ldo_tls_ciphersuite = NULL; } if ( lo->ldo_tls_crlfile ) { LDAP_FREE( lo->ldo_tls_crlfile ); lo->ldo_tls_crlfile = NULL; } /* tls_pin_hashalg and tls_pin share the same buffer */ if ( lo->ldo_tls_pin_hashalg ) { LDAP_FREE( lo->ldo_tls_pin_hashalg ); lo->ldo_tls_pin_hashalg = NULL; } else { LDAP_FREE( lo->ldo_tls_pin.bv_val ); } BER_BVZERO( &lo->ldo_tls_pin ); } /* * Tear down the TLS subsystem. Should only be called once. */ void ldap_pvt_tls_destroy( void ) { struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT(); ldap_int_tls_destroy( lo ); tls_imp->ti_tls_destroy(); } /* * Initialize a particular TLS implementation. * Called once per implementation. */ static int tls_init(tls_impl *impl, int do_threads ) { static int tls_initialized = 0; if ( !tls_initialized++ ) { #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_init( &tls_def_ctx_mutex ); #endif } if ( impl->ti_inited++ ) return 0; if ( do_threads ) { #ifdef LDAP_R_COMPILE impl->ti_thr_init(); #endif } return impl->ti_tls_init(); } /* * Initialize TLS subsystem. Called once per implementation. */ int ldap_pvt_tls_init( int do_threads ) { return tls_init( tls_imp, do_threads ); } /* * initialize a new TLS context */ static int ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server ) { int rc = 0; tls_impl *ti = tls_imp; struct ldaptls lts = lo->ldo_tls_info; if ( lo->ldo_tls_ctx ) return 0; tls_init( ti, 0 ); if ( is_server && !lts.lt_certfile && !lts.lt_keyfile && !lts.lt_cacertfile && !lts.lt_cacertdir && !lts.lt_cacert.bv_val && !lts.lt_cert.bv_val && !lts.lt_key.bv_val ) { /* minimum configuration not provided */ return LDAP_NOT_SUPPORTED; } #ifdef HAVE_EBCDIC /* This ASCII/EBCDIC handling is a real pain! */ if ( lts.lt_ciphersuite ) { lts.lt_ciphersuite = LDAP_STRDUP( lts.lt_ciphersuite ); __atoe( lts.lt_ciphersuite ); } if ( lts.lt_cacertfile ) { lts.lt_cacertfile = LDAP_STRDUP( lts.lt_cacertfile ); __atoe( lts.lt_cacertfile ); } if ( lts.lt_certfile ) { lts.lt_certfile = LDAP_STRDUP( lts.lt_certfile ); __atoe( lts.lt_certfile ); } if ( lts.lt_keyfile ) { lts.lt_keyfile = LDAP_STRDUP( lts.lt_keyfile ); __atoe( lts.lt_keyfile ); } if ( lts.lt_crlfile ) { lts.lt_crlfile = LDAP_STRDUP( lts.lt_crlfile ); __atoe( lts.lt_crlfile ); } if ( lts.lt_cacertdir ) { lts.lt_cacertdir = LDAP_STRDUP( lts.lt_cacertdir ); __atoe( lts.lt_cacertdir ); } if ( lts.lt_dhfile ) { lts.lt_dhfile = LDAP_STRDUP( lts.lt_dhfile ); __atoe( lts.lt_dhfile ); } if ( lts.lt_ecname ) { lts.lt_ecname = LDAP_STRDUP( lts.lt_ecname ); __atoe( lts.lt_ecname ); } #endif lo->ldo_tls_ctx = ti->ti_ctx_new( lo ); if ( lo->ldo_tls_ctx == NULL ) { Debug0( LDAP_DEBUG_ANY, "TLS: could not allocate default ctx.\n" ); rc = -1; goto error_exit; } rc = ti->ti_ctx_init( lo, <s, is_server ); error_exit: if ( rc < 0 && lo->ldo_tls_ctx != NULL ) { ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx ); lo->ldo_tls_ctx = NULL; } #ifdef HAVE_EBCDIC LDAP_FREE( lts.lt_ciphersuite ); LDAP_FREE( lts.lt_cacertfile ); LDAP_FREE( lts.lt_certfile ); LDAP_FREE( lts.lt_keyfile ); LDAP_FREE( lts.lt_crlfile ); LDAP_FREE( lts.lt_cacertdir ); LDAP_FREE( lts.lt_dhfile ); LDAP_FREE( lts.lt_ecname ); #endif return rc; } /* * initialize the default context */ int ldap_pvt_tls_init_def_ctx( int is_server ) { struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT(); int rc; LDAP_MUTEX_LOCK( &tls_def_ctx_mutex ); rc = ldap_int_tls_init_ctx( lo, is_server ); LDAP_MUTEX_UNLOCK( &tls_def_ctx_mutex ); return rc; } static tls_session * alloc_handle( void *ctx_arg, int is_server ) { tls_ctx *ctx; tls_session *ssl; if ( ctx_arg ) { ctx = ctx_arg; } else { struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT(); if ( ldap_pvt_tls_init_def_ctx( is_server ) < 0 ) return NULL; ctx = lo->ldo_tls_ctx; } ssl = tls_imp->ti_session_new( ctx, is_server ); if ( ssl == NULL ) { Debug0( LDAP_DEBUG_ANY,"TLS: can't create ssl handle.\n" ); return NULL; } return ssl; } static int update_flags( Sockbuf *sb, tls_session * ssl, int rc ) { sb->sb_trans_needs_read = 0; sb->sb_trans_needs_write = 0; return tls_imp->ti_session_upflags( sb, ssl, rc ); } /* * Call this to do a TLS connect on a sockbuf. ctx_arg can be * a SSL_CTX * or NULL, in which case the default ctx is used. * * Return value: * * 0 - Success. Connection is ready for communication. * <0 - Error. Can't create a TLS stream. * >0 - Partial success. * Do a select (using information from lber_pvt_sb_needs_{read,write} * and call again. */ static int ldap_int_tls_connect( LDAP *ld, LDAPConn *conn, const char *host ) { Sockbuf *sb = conn->lconn_sb; int err; tls_session *ssl = NULL; const char *sni = host; if ( HAS_TLS( sb )) { ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl ); } else { struct ldapoptions *lo; tls_ctx *ctx; ctx = ld->ld_options.ldo_tls_ctx; ssl = alloc_handle( ctx, 0 ); if ( ssl == NULL ) return -1; #ifdef LDAP_DEBUG ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_TRANSPORT, (void *)"tls_" ); #endif ber_sockbuf_add_io( sb, tls_imp->ti_sbio, LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl ); lo = LDAP_INT_GLOBAL_OPT(); if( ctx == NULL ) { ctx = lo->ldo_tls_ctx; ld->ld_options.ldo_tls_ctx = ctx; tls_ctx_ref( ctx ); } if ( ld->ld_options.ldo_tls_connect_cb ) ld->ld_options.ldo_tls_connect_cb( ld, ssl, ctx, ld->ld_options.ldo_tls_connect_arg ); if ( lo && lo->ldo_tls_connect_cb && lo->ldo_tls_connect_cb != ld->ld_options.ldo_tls_connect_cb ) lo->ldo_tls_connect_cb( ld, ssl, ctx, lo->ldo_tls_connect_arg ); } /* pass hostname for SNI, but only if it's an actual name * and not a numeric address */ { int numeric = 1; unsigned char *c; for ( c = (unsigned char *)sni; *c; c++ ) { if ( *c == ':' ) /* IPv6 address */ break; if ( *c == '.' ) continue; if ( !isdigit( *c )) { numeric = 0; break; } } if ( numeric ) sni = NULL; } err = tls_imp->ti_session_connect( ld, ssl, sni ); #ifdef HAVE_WINSOCK errno = WSAGetLastError(); #endif if ( err == 0 ) { err = ldap_pvt_tls_check_hostname( ld, ssl, host ); } if ( err < 0 ) { char buf[256], *msg; if ( update_flags( sb, ssl, err )) { return 1; } msg = tls_imp->ti_session_errmsg( ssl, err, buf, sizeof(buf) ); if ( msg ) { if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } ld->ld_error = LDAP_STRDUP( msg ); #ifdef HAVE_EBCDIC if ( ld->ld_error ) __etoa(ld->ld_error); #endif } Debug1( LDAP_DEBUG_ANY,"TLS: can't connect: %s.\n", ld->ld_error ? ld->ld_error : "" ); ber_sockbuf_remove_io( sb, tls_imp->ti_sbio, LBER_SBIOD_LEVEL_TRANSPORT ); #ifdef LDAP_DEBUG ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_TRANSPORT ); #endif return -1; } return 0; } int ldap_pvt_tls_connect( LDAP *ld, Sockbuf *sb, const char *host ) { LDAPConn conn = { .lconn_sb = sb }; return ldap_int_tls_connect( ld, &conn, host ); } /* * Call this to do a TLS accept on a sockbuf. * Everything else is the same as with tls_connect. */ int ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg ) { int err; tls_session *ssl = NULL; if ( HAS_TLS( sb )) { ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl ); } else { ssl = alloc_handle( ctx_arg, 1 ); if ( ssl == NULL ) return -1; #ifdef LDAP_DEBUG ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_TRANSPORT, (void *)"tls_" ); #endif ber_sockbuf_add_io( sb, tls_imp->ti_sbio, LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl ); } err = tls_imp->ti_session_accept( ssl ); #ifdef HAVE_WINSOCK errno = WSAGetLastError(); #endif if ( err < 0 ) { if ( update_flags( sb, ssl, err )) return 1; if ( DebugTest( LDAP_DEBUG_ANY ) ) { char buf[256], *msg; msg = tls_imp->ti_session_errmsg( ssl, err, buf, sizeof(buf) ); Debug1( LDAP_DEBUG_ANY,"TLS: can't accept: %s.\n", msg ? msg : "(unknown)" ); } ber_sockbuf_remove_io( sb, tls_imp->ti_sbio, LBER_SBIOD_LEVEL_TRANSPORT ); #ifdef LDAP_DEBUG ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_TRANSPORT ); #endif return -1; } return 0; } int ldap_pvt_tls_inplace ( Sockbuf *sb ) { return HAS_TLS( sb ) ? 1 : 0; } int ldap_tls_inplace( LDAP *ld ) { Sockbuf *sb = NULL; if ( ld->ld_defconn && ld->ld_defconn->lconn_sb ) { sb = ld->ld_defconn->lconn_sb; } else if ( ld->ld_sb ) { sb = ld->ld_sb; } else { return 0; } return ldap_pvt_tls_inplace( sb ); } int ldap_pvt_tls_get_peer_dn( void *s, struct berval *dn, LDAPDN_rewrite_dummy *func, unsigned flags ) { tls_session *session = s; struct berval bvdn; int rc; rc = tls_imp->ti_session_peer_dn( session, &bvdn ); if ( rc ) return rc; rc = ldap_X509dn2bv( &bvdn, dn, (LDAPDN_rewrite_func *)func, flags); return rc; } int ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in ) { tls_session *session = s; if (ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER && ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_ALLOW) { ld->ld_errno = tls_imp->ti_session_chkhost( ld, session, name_in ); if (ld->ld_errno != LDAP_SUCCESS) { return ld->ld_errno; } } /* * If instructed to do pinning, do it now */ if ( !BER_BVISNULL( &ld->ld_options.ldo_tls_pin ) ) { ld->ld_errno = tls_imp->ti_session_pinning( ld, s, ld->ld_options.ldo_tls_pin_hashalg, &ld->ld_options.ldo_tls_pin ); if (ld->ld_errno != LDAP_SUCCESS) { return ld->ld_errno; } } return LDAP_SUCCESS; } int ldap_pvt_tls_config( LDAP *ld, int option, const char *arg ) { int i; switch( option ) { case LDAP_OPT_X_TLS_CACERTFILE: case LDAP_OPT_X_TLS_CACERTDIR: case LDAP_OPT_X_TLS_CERTFILE: case LDAP_OPT_X_TLS_KEYFILE: case LDAP_OPT_X_TLS_RANDOM_FILE: case LDAP_OPT_X_TLS_CIPHER_SUITE: case LDAP_OPT_X_TLS_DHFILE: case LDAP_OPT_X_TLS_PEERKEY_HASH: case LDAP_OPT_X_TLS_ECNAME: case LDAP_OPT_X_TLS_CRLFILE: /* GnuTLS only */ return ldap_pvt_tls_set_option( ld, option, (void *) arg ); case LDAP_OPT_X_TLS_REQUIRE_CERT: case LDAP_OPT_X_TLS_REQUIRE_SAN: case LDAP_OPT_X_TLS: i = -1; if ( strcasecmp( arg, "never" ) == 0 ) { i = LDAP_OPT_X_TLS_NEVER ; } else if ( strcasecmp( arg, "demand" ) == 0 ) { i = LDAP_OPT_X_TLS_DEMAND ; } else if ( strcasecmp( arg, "allow" ) == 0 ) { i = LDAP_OPT_X_TLS_ALLOW ; } else if ( strcasecmp( arg, "try" ) == 0 ) { i = LDAP_OPT_X_TLS_TRY ; } else if ( ( strcasecmp( arg, "hard" ) == 0 ) || ( strcasecmp( arg, "on" ) == 0 ) || ( strcasecmp( arg, "yes" ) == 0) || ( strcasecmp( arg, "true" ) == 0 ) ) { i = LDAP_OPT_X_TLS_HARD ; } if (i >= 0) { return ldap_pvt_tls_set_option( ld, option, &i ); } return -1; case LDAP_OPT_X_TLS_PROTOCOL_MAX: case LDAP_OPT_X_TLS_PROTOCOL_MIN: { char *next; long l; l = strtol( arg, &next, 10 ); if ( l < 0 || l > 0xff || next == arg || ( *next != '\0' && *next != '.' ) ) return -1; i = l << 8; if (*next == '.') { arg = next + 1; l = strtol( arg, &next, 10 ); if ( l < 0 || l > 0xff || next == arg || *next != '\0' ) return -1; i += l; } return ldap_pvt_tls_set_option( ld, option, &i ); } #ifdef HAVE_OPENSSL case LDAP_OPT_X_TLS_CRLCHECK: /* OpenSSL only */ i = -1; if ( strcasecmp( arg, "none" ) == 0 ) { i = LDAP_OPT_X_TLS_CRL_NONE ; } else if ( strcasecmp( arg, "peer" ) == 0 ) { i = LDAP_OPT_X_TLS_CRL_PEER ; } else if ( strcasecmp( arg, "all" ) == 0 ) { i = LDAP_OPT_X_TLS_CRL_ALL ; } if (i >= 0) { return ldap_pvt_tls_set_option( ld, option, &i ); } return -1; #endif } return -1; } int ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg ) { struct ldapoptions *lo; if( option == LDAP_OPT_X_TLS_PACKAGE ) { *(char **)arg = LDAP_STRDUP( tls_imp->ti_name ); return 0; } if( ld != NULL ) { assert( LDAP_VALID( ld ) ); if( !LDAP_VALID( ld ) ) { return LDAP_OPT_ERROR; } lo = &ld->ld_options; } else { /* Get pointer to global option structure */ lo = LDAP_INT_GLOBAL_OPT(); if ( lo == NULL ) { return LDAP_NO_MEMORY; } } switch( option ) { case LDAP_OPT_X_TLS: *(int *)arg = lo->ldo_tls_mode; break; case LDAP_OPT_X_TLS_CTX: *(void **)arg = lo->ldo_tls_ctx; if ( lo->ldo_tls_ctx ) { tls_ctx_ref( lo->ldo_tls_ctx ); } break; case LDAP_OPT_X_TLS_CACERTFILE: *(char **)arg = lo->ldo_tls_cacertfile ? LDAP_STRDUP( lo->ldo_tls_cacertfile ) : NULL; break; case LDAP_OPT_X_TLS_CACERTDIR: *(char **)arg = lo->ldo_tls_cacertdir ? LDAP_STRDUP( lo->ldo_tls_cacertdir ) : NULL; break; case LDAP_OPT_X_TLS_CERTFILE: *(char **)arg = lo->ldo_tls_certfile ? LDAP_STRDUP( lo->ldo_tls_certfile ) : NULL; break; case LDAP_OPT_X_TLS_KEYFILE: *(char **)arg = lo->ldo_tls_keyfile ? LDAP_STRDUP( lo->ldo_tls_keyfile ) : NULL; break; case LDAP_OPT_X_TLS_DHFILE: *(char **)arg = lo->ldo_tls_dhfile ? LDAP_STRDUP( lo->ldo_tls_dhfile ) : NULL; break; case LDAP_OPT_X_TLS_ECNAME: *(char **)arg = lo->ldo_tls_ecname ? LDAP_STRDUP( lo->ldo_tls_ecname ) : NULL; break; case LDAP_OPT_X_TLS_CRLFILE: /* GnuTLS only */ *(char **)arg = lo->ldo_tls_crlfile ? LDAP_STRDUP( lo->ldo_tls_crlfile ) : NULL; break; case LDAP_OPT_X_TLS_REQUIRE_CERT: *(int *)arg = lo->ldo_tls_require_cert; break; case LDAP_OPT_X_TLS_REQUIRE_SAN: *(int *)arg = lo->ldo_tls_require_san; break; #ifdef HAVE_OPENSSL case LDAP_OPT_X_TLS_CRLCHECK: /* OpenSSL only */ *(int *)arg = lo->ldo_tls_crlcheck; break; #endif case LDAP_OPT_X_TLS_CIPHER_SUITE: *(char **)arg = lo->ldo_tls_ciphersuite ? LDAP_STRDUP( lo->ldo_tls_ciphersuite ) : NULL; break; case LDAP_OPT_X_TLS_PROTOCOL_MIN: *(int *)arg = lo->ldo_tls_protocol_min; break; case LDAP_OPT_X_TLS_PROTOCOL_MAX: *(int *)arg = lo->ldo_tls_protocol_max; break; case LDAP_OPT_X_TLS_RANDOM_FILE: *(char **)arg = lo->ldo_tls_randfile ? LDAP_STRDUP( lo->ldo_tls_randfile ) : NULL; break; case LDAP_OPT_X_TLS_SSL_CTX: { void *retval = 0; if ( ld != NULL ) { LDAPConn *conn = ld->ld_defconn; if ( conn != NULL ) { Sockbuf *sb = conn->lconn_sb; retval = ldap_pvt_tls_sb_ctx( sb ); } } *(void **)arg = retval; break; } case LDAP_OPT_X_TLS_CONNECT_CB: *(LDAP_TLS_CONNECT_CB **)arg = lo->ldo_tls_connect_cb; break; case LDAP_OPT_X_TLS_CONNECT_ARG: *(void **)arg = lo->ldo_tls_connect_arg; break; case LDAP_OPT_X_TLS_VERSION: { void *sess = NULL; const char *retval = NULL; if ( ld != NULL ) { LDAPConn *conn = ld->ld_defconn; if ( conn != NULL ) { Sockbuf *sb = conn->lconn_sb; sess = ldap_pvt_tls_sb_ctx( sb ); if ( sess != NULL ) retval = ldap_pvt_tls_get_version( sess ); } } *(char **)arg = retval ? LDAP_STRDUP( retval ) : NULL; break; } case LDAP_OPT_X_TLS_CIPHER: { void *sess = NULL; const char *retval = NULL; if ( ld != NULL ) { LDAPConn *conn = ld->ld_defconn; if ( conn != NULL ) { Sockbuf *sb = conn->lconn_sb; sess = ldap_pvt_tls_sb_ctx( sb ); if ( sess != NULL ) retval = ldap_pvt_tls_get_cipher( sess ); } } *(char **)arg = retval ? LDAP_STRDUP( retval ) : NULL; break; } case LDAP_OPT_X_TLS_PEERCERT: { void *sess = NULL; struct berval *bv = arg; bv->bv_len = 0; bv->bv_val = NULL; if ( ld != NULL ) { LDAPConn *conn = ld->ld_defconn; if ( conn != NULL ) { Sockbuf *sb = conn->lconn_sb; sess = ldap_pvt_tls_sb_ctx( sb ); if ( sess != NULL ) return ldap_pvt_tls_get_peercert( sess, bv ); } } break; } case LDAP_OPT_X_TLS_CACERT: { struct berval *bv = arg; if ( lo->ldo_tls_cacert.bv_val ) { ber_dupbv( bv, &lo->ldo_tls_cacert ); } else { BER_BVZERO( bv ); } break; } case LDAP_OPT_X_TLS_CERT: { struct berval *bv = arg; if ( lo->ldo_tls_cert.bv_val ) { ber_dupbv( bv, &lo->ldo_tls_cert ); } else { BER_BVZERO( bv ); } break; } case LDAP_OPT_X_TLS_KEY: { struct berval *bv = arg; if ( lo->ldo_tls_key.bv_val ) { ber_dupbv( bv, &lo->ldo_tls_key ); } else { BER_BVZERO( bv ); } break; } default: return -1; } return 0; } int ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg ) { struct ldapoptions *lo; if( ld != NULL ) { assert( LDAP_VALID( ld ) ); if( !LDAP_VALID( ld ) ) { return LDAP_OPT_ERROR; } lo = &ld->ld_options; } else { /* Get pointer to global option structure */ lo = LDAP_INT_GLOBAL_OPT(); if ( lo == NULL ) { return LDAP_NO_MEMORY; } } switch( option ) { case LDAP_OPT_X_TLS: if ( !arg ) return -1; switch( *(int *) arg ) { case LDAP_OPT_X_TLS_NEVER: case LDAP_OPT_X_TLS_DEMAND: case LDAP_OPT_X_TLS_ALLOW: case LDAP_OPT_X_TLS_TRY: case LDAP_OPT_X_TLS_HARD: if (lo != NULL) { lo->ldo_tls_mode = *(int *)arg; } return 0; } return -1; case LDAP_OPT_X_TLS_CTX: if ( lo->ldo_tls_ctx ) ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx ); lo->ldo_tls_ctx = arg; tls_ctx_ref( lo->ldo_tls_ctx ); return 0; case LDAP_OPT_X_TLS_CONNECT_CB: lo->ldo_tls_connect_cb = (LDAP_TLS_CONNECT_CB *)arg; return 0; case LDAP_OPT_X_TLS_CONNECT_ARG: lo->ldo_tls_connect_arg = arg; return 0; case LDAP_OPT_X_TLS_CACERTFILE: if ( lo->ldo_tls_cacertfile ) LDAP_FREE( lo->ldo_tls_cacertfile ); lo->ldo_tls_cacertfile = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL; return 0; case LDAP_OPT_X_TLS_CACERTDIR: if ( lo->ldo_tls_cacertdir ) LDAP_FREE( lo->ldo_tls_cacertdir ); lo->ldo_tls_cacertdir = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL; return 0; case LDAP_OPT_X_TLS_CERTFILE: if ( lo->ldo_tls_certfile ) LDAP_FREE( lo->ldo_tls_certfile ); lo->ldo_tls_certfile = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL; return 0; case LDAP_OPT_X_TLS_KEYFILE: if ( lo->ldo_tls_keyfile ) LDAP_FREE( lo->ldo_tls_keyfile ); lo->ldo_tls_keyfile = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL; return 0; case LDAP_OPT_X_TLS_DHFILE: if ( lo->ldo_tls_dhfile ) LDAP_FREE( lo->ldo_tls_dhfile ); lo->ldo_tls_dhfile = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL; return 0; case LDAP_OPT_X_TLS_ECNAME: if ( lo->ldo_tls_ecname ) LDAP_FREE( lo->ldo_tls_ecname ); lo->ldo_tls_ecname = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL; return 0; case LDAP_OPT_X_TLS_CRLFILE: /* GnuTLS only */ if ( lo->ldo_tls_crlfile ) LDAP_FREE( lo->ldo_tls_crlfile ); lo->ldo_tls_crlfile = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL; return 0; case LDAP_OPT_X_TLS_REQUIRE_CERT: if ( !arg ) return -1; switch( *(int *) arg ) { case LDAP_OPT_X_TLS_NEVER: case LDAP_OPT_X_TLS_DEMAND: case LDAP_OPT_X_TLS_ALLOW: case LDAP_OPT_X_TLS_TRY: case LDAP_OPT_X_TLS_HARD: lo->ldo_tls_require_cert = * (int *) arg; return 0; } return -1; case LDAP_OPT_X_TLS_REQUIRE_SAN: if ( !arg ) return -1; switch( *(int *) arg ) { case LDAP_OPT_X_TLS_NEVER: case LDAP_OPT_X_TLS_DEMAND: case LDAP_OPT_X_TLS_ALLOW: case LDAP_OPT_X_TLS_TRY: case LDAP_OPT_X_TLS_HARD: lo->ldo_tls_require_san = * (int *) arg; return 0; } return -1; #ifdef HAVE_OPENSSL case LDAP_OPT_X_TLS_CRLCHECK: /* OpenSSL only */ if ( !arg ) return -1; switch( *(int *) arg ) { case LDAP_OPT_X_TLS_CRL_NONE: case LDAP_OPT_X_TLS_CRL_PEER: case LDAP_OPT_X_TLS_CRL_ALL: lo->ldo_tls_crlcheck = * (int *) arg; return 0; } return -1; #endif case LDAP_OPT_X_TLS_CIPHER_SUITE: if ( lo->ldo_tls_ciphersuite ) LDAP_FREE( lo->ldo_tls_ciphersuite ); lo->ldo_tls_ciphersuite = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL; return 0; case LDAP_OPT_X_TLS_PROTOCOL_MIN: if ( !arg ) return -1; lo->ldo_tls_protocol_min = *(int *)arg; return 0; case LDAP_OPT_X_TLS_PROTOCOL_MAX: if ( !arg ) return -1; lo->ldo_tls_protocol_max = *(int *)arg; return 0; case LDAP_OPT_X_TLS_RANDOM_FILE: if ( ld != NULL ) return -1; if ( lo->ldo_tls_randfile ) LDAP_FREE (lo->ldo_tls_randfile ); lo->ldo_tls_randfile = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL; break; case LDAP_OPT_X_TLS_NEWCTX: if ( !arg ) return -1; if ( lo->ldo_tls_ctx ) ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx ); lo->ldo_tls_ctx = NULL; return ldap_int_tls_init_ctx( lo, *(int *)arg ); case LDAP_OPT_X_TLS_CACERT: if ( lo->ldo_tls_cacert.bv_val ) LDAP_FREE( lo->ldo_tls_cacert.bv_val ); if ( arg ) { lo->ldo_tls_cacert.bv_len = ((struct berval *)arg)->bv_len; lo->ldo_tls_cacert.bv_val = LDAP_MALLOC( lo->ldo_tls_cacert.bv_len ); if ( !lo->ldo_tls_cacert.bv_val ) return -1; AC_MEMCPY( lo->ldo_tls_cacert.bv_val, ((struct berval *)arg)->bv_val, lo->ldo_tls_cacert.bv_len ); } else { BER_BVZERO( &lo->ldo_tls_cacert ); } break; case LDAP_OPT_X_TLS_CERT: if ( lo->ldo_tls_cert.bv_val ) LDAP_FREE( lo->ldo_tls_cert.bv_val ); if ( arg ) { lo->ldo_tls_cert.bv_len = ((struct berval *)arg)->bv_len; lo->ldo_tls_cert.bv_val = LDAP_MALLOC( lo->ldo_tls_cert.bv_len ); if ( !lo->ldo_tls_cert.bv_val ) return -1; AC_MEMCPY( lo->ldo_tls_cert.bv_val, ((struct berval *)arg)->bv_val, lo->ldo_tls_cert.bv_len ); } else { BER_BVZERO( &lo->ldo_tls_cert ); } break; case LDAP_OPT_X_TLS_KEY: if ( lo->ldo_tls_key.bv_val ) LDAP_FREE( lo->ldo_tls_key.bv_val ); if ( arg ) { lo->ldo_tls_key.bv_len = ((struct berval *)arg)->bv_len; lo->ldo_tls_key.bv_val = LDAP_MALLOC( lo->ldo_tls_key.bv_len ); if ( !lo->ldo_tls_key.bv_val ) return -1; AC_MEMCPY( lo->ldo_tls_key.bv_val, ((struct berval *)arg)->bv_val, lo->ldo_tls_key.bv_len ); } else { BER_BVZERO( &lo->ldo_tls_key ); } break; case LDAP_OPT_X_TLS_PEERKEY_HASH: { /* arg = "[hashalg:]pubkey_hash" */ struct berval bv; char *p, *pin = arg; int rc = LDAP_SUCCESS; if ( !tls_imp->ti_session_pinning ) return -1; if ( !pin || !*pin ) { if ( lo->ldo_tls_pin_hashalg ) { LDAP_FREE( lo->ldo_tls_pin_hashalg ); } else if ( lo->ldo_tls_pin.bv_val ) { LDAP_FREE( lo->ldo_tls_pin.bv_val ); } lo->ldo_tls_pin_hashalg = NULL; BER_BVZERO( &lo->ldo_tls_pin ); return rc; } pin = LDAP_STRDUP( pin ); p = strchr( pin, ':' ); /* pubkey (its hash) goes in bv, alg in p */ if ( p ) { *p = '\0'; bv.bv_val = p+1; p = pin; } else { bv.bv_val = pin; } bv.bv_len = strlen(bv.bv_val); if ( ldap_int_decode_b64_inplace( &bv ) ) { LDAP_FREE( pin ); return -1; } if ( ld != NULL ) { LDAPConn *conn = ld->ld_defconn; if ( conn != NULL ) { Sockbuf *sb = conn->lconn_sb; void *sess = ldap_pvt_tls_sb_ctx( sb ); if ( sess != NULL ) { rc = tls_imp->ti_session_pinning( ld, sess, p, &bv ); } } } if ( rc == LDAP_SUCCESS ) { if ( lo->ldo_tls_pin_hashalg ) { LDAP_FREE( lo->ldo_tls_pin_hashalg ); } else if ( lo->ldo_tls_pin.bv_val ) { LDAP_FREE( lo->ldo_tls_pin.bv_val ); } lo->ldo_tls_pin_hashalg = p; lo->ldo_tls_pin = bv; } else { LDAP_FREE( pin ); } return rc; } default: return -1; } return 0; } int ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv ) { Sockbuf *sb; char *host; void *ssl; int ret, async; struct timeval start_time_tv, tv, tv0; ber_socket_t sd = AC_SOCKET_ERROR; if ( !conn ) return LDAP_PARAM_ERROR; sb = conn->lconn_sb; if( srv ) { host = srv->lud_host; } else { host = conn->lconn_server->lud_host; } /* avoid NULL host */ if( host == NULL ) { host = "localhost"; } (void) tls_init( tls_imp, 0 ); /* * Use non-blocking io during SSL Handshake when a timeout is configured */ async = LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_CONNECT_ASYNC ); if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) { if ( !async ) { /* if async, this has already been set */ ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_NONBLOCK, (void*)1 ); } ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); tv = ld->ld_options.ldo_tm_net; tv0 = tv; #ifdef HAVE_GETTIMEOFDAY gettimeofday( &start_time_tv, NULL ); #else /* ! HAVE_GETTIMEOFDAY */ time( &start_time_tv.tv_sec ); start_time_tv.tv_usec = 0; #endif /* ! HAVE_GETTIMEOFDAY */ } ld->ld_errno = LDAP_SUCCESS; ret = ldap_int_tls_connect( ld, conn, host ); /* this mainly only happens for non-blocking io * but can also happen when the handshake is too * big for a single network message. */ while ( ret > 0 ) { if ( async ) { struct timeval curr_time_tv, delta_tv; int wr=0; if ( sb->sb_trans_needs_read ) { wr=0; } else if ( sb->sb_trans_needs_write ) { wr=1; } Debug1( LDAP_DEBUG_TRACE, "ldap_int_tls_start: ldap_int_tls_connect needs %s\n", wr ? "write": "read" ); /* This is mostly copied from result.c:wait4msg(), should * probably be moved into a separate function */ #ifdef HAVE_GETTIMEOFDAY gettimeofday( &curr_time_tv, NULL ); #else /* ! HAVE_GETTIMEOFDAY */ time( &curr_time_tv.tv_sec ); curr_time_tv.tv_usec = 0; #endif /* ! HAVE_GETTIMEOFDAY */ /* delta = curr - start */ delta_tv.tv_sec = curr_time_tv.tv_sec - start_time_tv.tv_sec; delta_tv.tv_usec = curr_time_tv.tv_usec - start_time_tv.tv_usec; if ( delta_tv.tv_usec < 0 ) { delta_tv.tv_sec--; delta_tv.tv_usec += 1000000; } /* tv0 < delta ? */ if ( ( tv0.tv_sec < delta_tv.tv_sec ) || ( ( tv0.tv_sec == delta_tv.tv_sec ) && ( tv0.tv_usec < delta_tv.tv_usec ) ) ) { ret = -1; ld->ld_errno = LDAP_TIMEOUT; break; } /* timeout -= delta_time */ tv0.tv_sec -= delta_tv.tv_sec; tv0.tv_usec -= delta_tv.tv_usec; if ( tv0.tv_usec < 0 ) { tv0.tv_sec--; tv0.tv_usec += 1000000; } start_time_tv.tv_sec = curr_time_tv.tv_sec; start_time_tv.tv_usec = curr_time_tv.tv_usec; tv = tv0; Debug3( LDAP_DEBUG_TRACE, "ldap_int_tls_start: ld %p %ld s %ld us to go\n", (void *)ld, (long) tv.tv_sec, (long) tv.tv_usec ); ret = ldap_int_poll( ld, sd, &tv, wr); if ( ret < 0 ) { ld->ld_errno = LDAP_TIMEOUT; break; } } ret = ldap_int_tls_connect( ld, conn, host ); } if ( ret < 0 ) { if ( ld->ld_errno == LDAP_SUCCESS ) ld->ld_errno = LDAP_CONNECT_ERROR; return (ld->ld_errno); } return LDAP_SUCCESS; } void * ldap_pvt_tls_sb_ctx( Sockbuf *sb ) { void *p = NULL; ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&p ); return p; } int ldap_pvt_tls_get_strength( void *s ) { tls_session *session = s; return tls_imp->ti_session_strength( session ); } int ldap_pvt_tls_get_my_dn( void *s, struct berval *dn, LDAPDN_rewrite_dummy *func, unsigned flags ) { tls_session *session = s; struct berval der_dn; int rc; rc = tls_imp->ti_session_my_dn( session, &der_dn ); if ( rc == LDAP_SUCCESS ) rc = ldap_X509dn2bv(&der_dn, dn, (LDAPDN_rewrite_func *)func, flags ); return rc; } int ldap_pvt_tls_get_unique( void *s, struct berval *buf, int is_server ) { tls_session *session = s; return tls_imp->ti_session_unique( session, buf, is_server ); } int ldap_pvt_tls_get_endpoint( void *s, struct berval *buf, int is_server ) { tls_session *session = s; return tls_imp->ti_session_endpoint( session, buf, is_server ); } const char * ldap_pvt_tls_get_version( void *s ) { tls_session *session = s; return tls_imp->ti_session_version( session ); } const char * ldap_pvt_tls_get_cipher( void *s ) { tls_session *session = s; return tls_imp->ti_session_cipher( session ); } int ldap_pvt_tls_get_peercert( void *s, struct berval *der ) { tls_session *session = s; return tls_imp->ti_session_peercert( session, der ); } #endif /* HAVE_TLS */ int ldap_start_tls( LDAP *ld, LDAPControl **serverctrls, LDAPControl **clientctrls, int *msgidp ) { return ldap_extended_operation( ld, LDAP_EXOP_START_TLS, NULL, serverctrls, clientctrls, msgidp ); } int ldap_install_tls( LDAP *ld ) { #ifndef HAVE_TLS return LDAP_NOT_SUPPORTED; #else if ( ldap_tls_inplace( ld ) ) { return LDAP_LOCAL_ERROR; } return ldap_int_tls_start( ld, ld->ld_defconn, NULL ); #endif } int ldap_start_tls_s ( LDAP *ld, LDAPControl **serverctrls, LDAPControl **clientctrls ) { #ifndef HAVE_TLS return LDAP_NOT_SUPPORTED; #else int rc; char *rspoid = NULL; struct berval *rspdata = NULL; /* XXYYZ: this initiates operation only on default connection! */ if ( ldap_tls_inplace( ld ) ) { return LDAP_LOCAL_ERROR; } rc = ldap_extended_operation_s( ld, LDAP_EXOP_START_TLS, NULL, serverctrls, clientctrls, &rspoid, &rspdata ); if ( rspoid != NULL ) { LDAP_FREE(rspoid); } if ( rspdata != NULL ) { ber_bvfree( rspdata ); } if ( rc == LDAP_SUCCESS ) { rc = ldap_int_tls_start( ld, ld->ld_defconn, NULL ); } return rc; #endif } /* These tags probably all belong in lber.h, but they're * not normally encountered when processing LDAP, so maybe * they belong somewhere else instead. */ #define LBER_TAG_OID ((ber_tag_t) 0x06UL) /* Tags for string types used in a DirectoryString. * * Note that IA5string is not one of the defined choices for * DirectoryString in X.520, but it gets used for email AVAs. */ #define LBER_TAG_UTF8 ((ber_tag_t) 0x0cUL) #define LBER_TAG_PRINTABLE ((ber_tag_t) 0x13UL) #define LBER_TAG_TELETEX ((ber_tag_t) 0x14UL) #define LBER_TAG_IA5 ((ber_tag_t) 0x16UL) #define LBER_TAG_UNIVERSAL ((ber_tag_t) 0x1cUL) #define LBER_TAG_BMP ((ber_tag_t) 0x1eUL) static oid_name * find_oid( struct berval *oid ) { int i; for ( i=0; !BER_BVISNULL( &oids[i].oid ); i++ ) { if ( oids[i].oid.bv_len != oid->bv_len ) continue; if ( !strcmp( oids[i].oid.bv_val, oid->bv_val )) return &oids[i]; } return NULL; } /* Converts BER Bitstring value to LDAP BitString value (RFC4517) * * berValue : IN * rfc4517Value: OUT * * berValue and ldapValue should not be NULL */ #define BITS_PER_BYTE 8 #define SQUOTE_LENGTH 1 #define B_CHAR_LENGTH 1 #define STR_OVERHEAD (2*SQUOTE_LENGTH + B_CHAR_LENGTH) static int der_to_ldap_BitString (struct berval *berValue, struct berval *ldapValue) { ber_len_t bitPadding=0; ber_len_t bits, maxBits; char *tmpStr; unsigned char byte; ber_len_t bitLength; ber_len_t valLen; unsigned char* valPtr; ldapValue->bv_len=0; ldapValue->bv_val=NULL; /* Gets padding and points to binary data */ valLen=berValue->bv_len; valPtr=(unsigned char*)berValue->bv_val; if (valLen) { bitPadding=(ber_len_t)(valPtr[0]); valLen--; valPtr++; } /* If Block is non DER encoding fixes to DER encoding */ if (bitPadding >= BITS_PER_BYTE) { if (valLen*BITS_PER_BYTE > bitPadding ) { valLen-=(bitPadding/BITS_PER_BYTE); bitPadding%=BITS_PER_BYTE; } else { valLen=0; bitPadding=0; } } /* Just in case bad encoding */ if (valLen*BITS_PER_BYTE < bitPadding ) { bitPadding=0; valLen=0; } /* Gets buffer to hold RFC4517 Bit String format */ bitLength=valLen*BITS_PER_BYTE-bitPadding; tmpStr=LDAP_MALLOC(bitLength + STR_OVERHEAD + 1); if (!tmpStr) return LDAP_NO_MEMORY; ldapValue->bv_val=tmpStr; ldapValue->bv_len=bitLength + STR_OVERHEAD; /* Formatting in '*binary-digit'B format */ maxBits=BITS_PER_BYTE; *tmpStr++ ='\''; while(valLen) { byte=*valPtr; if (valLen==1) maxBits-=bitPadding; for (bits=0; bitsbv_len = 0; bv->bv_val = NULL; navas = 0; nrdns = 0; /* A DN is a SEQUENCE of RDNs. An RDN is a SET of AVAs. * An AVA is a SEQUENCE of attr and value. * Count the number of AVAs and RDNs */ ber_init2( ber, in, LBER_USE_DER ); tag = ber_peek_tag( ber, &len ); if ( tag != LBER_SEQUENCE ) return LDAP_DECODING_ERROR; for ( tag = ber_first_element( ber, &len, &dn_end ); tag == LBER_SET; tag = ber_next_element( ber, &len, dn_end )) { nrdns++; for ( tag = ber_first_element( ber, &len, &rdn_end ); tag == LBER_SEQUENCE; tag = ber_next_element( ber, &len, rdn_end )) { if ( rdn_end > dn_end ) return LDAP_DECODING_ERROR; tag = ber_skip_tag( ber, &len ); ber_skip_data( ber, len ); navas++; } } /* Rewind and prepare to extract */ ber_rewind( ber ); tag = ber_first_element( ber, &len, &dn_end ); if ( tag != LBER_SET ) return LDAP_DECODING_ERROR; /* Allocate the DN/RDN/AVA stuff as a single block */ dnsize = sizeof(LDAPRDN) * (nrdns+1); dnsize += sizeof(LDAPAVA *) * (navas+nrdns); dnsize += sizeof(LDAPAVA) * navas; if (dnsize > sizeof(ptrs)) { newDN = (LDAPDN)LDAP_MALLOC( dnsize ); if ( newDN == NULL ) return LDAP_NO_MEMORY; } else { newDN = (LDAPDN)(char *)ptrs; } newDN[nrdns] = NULL; newRDN = (LDAPRDN)(newDN + nrdns+1); newAVA = (LDAPAVA *)(newRDN + navas + nrdns); baseAVA = newAVA; for ( i = nrdns - 1; i >= 0; i-- ) { newDN[i] = newRDN; for ( tag = ber_first_element( ber, &len, &rdn_end ); tag == LBER_SEQUENCE; tag = ber_next_element( ber, &len, rdn_end )) { *newRDN++ = newAVA; tag = ber_skip_tag( ber, &len ); tag = ber_get_stringbv( ber, &Oid, LBER_BV_NOTERM ); if ( tag != LBER_TAG_OID ) { rc = LDAP_DECODING_ERROR; goto nomem; } oid2.bv_val = oidptr; oid2.bv_len = oidrem; if ( ber_decode_oid( &Oid, &oid2 ) < 0 ) { rc = LDAP_DECODING_ERROR; goto nomem; } oidname = find_oid( &oid2 ); if ( !oidname ) { newAVA->la_attr = oid2; oidptr += oid2.bv_len + 1; oidrem -= oid2.bv_len + 1; /* Running out of OID buffer space? */ if (oidrem < 128) { if ( oidsize == 0 ) { oidsize = sizeof(oids) * 2; oidrem = oidsize; oidbuf = LDAP_MALLOC( oidsize ); if ( oidbuf == NULL ) goto nomem; oidptr = oidbuf; } else { char *old = oidbuf; oidbuf = LDAP_REALLOC( oidbuf, oidsize*2 ); if ( oidbuf == NULL ) goto nomem; /* Buffer moved! Fix AVA pointers */ if ( old != oidbuf ) { LDAPAVA *a; long dif = oidbuf - old; for (a=baseAVA; a<=newAVA; a++){ if (a->la_attr.bv_val >= old && a->la_attr.bv_val <= (old + oidsize)) a->la_attr.bv_val += dif; } } oidptr = oidbuf + oidsize - oidrem; oidrem += oidsize; oidsize *= 2; } } } else { if ( func ) { newAVA->la_attr = oidname->oid; } else { newAVA->la_attr = oidname->name; } } newAVA->la_private = NULL; newAVA->la_flags = LDAP_AVA_STRING; tag = ber_get_stringbv( ber, &Val, LBER_BV_NOTERM ); switch(tag) { case LBER_TAG_UNIVERSAL: /* This uses 32-bit ISO 10646-1 */ csize = 4; goto to_utf8; case LBER_TAG_BMP: /* This uses 16-bit ISO 10646-1 */ csize = 2; goto to_utf8; case LBER_TAG_TELETEX: /* This uses 8-bit, assume ISO 8859-1 */ csize = 1; to_utf8: rc = ldap_ucs_to_utf8s( &Val, csize, &newAVA->la_value ); newAVA->la_flags |= LDAP_AVA_NONPRINTABLE; allocd: newAVA->la_flags |= LDAP_AVA_FREE_VALUE; if (rc != LDAP_SUCCESS) goto nomem; break; case LBER_TAG_UTF8: newAVA->la_flags |= LDAP_AVA_NONPRINTABLE; /* This is already in UTF-8 encoding */ case LBER_TAG_IA5: case LBER_TAG_PRINTABLE: /* These are always 7-bit strings */ newAVA->la_value = Val; break; case LBER_BITSTRING: /* X.690 bitString value converted to RFC4517 Bit String */ rc = der_to_ldap_BitString( &Val, &newAVA->la_value ); goto allocd; case LBER_DEFAULT: /* decode error */ rc = LDAP_DECODING_ERROR; goto nomem; default: /* Not a string type at all */ newAVA->la_flags = 0; newAVA->la_value = Val; break; } newAVA++; } *newRDN++ = NULL; tag = ber_next_element( ber, &len, dn_end ); } if ( func ) { rc = func( newDN, flags, NULL ); if ( rc != LDAP_SUCCESS ) goto nomem; } rc = ldap_dn2bv_x( newDN, bv, LDAP_DN_FORMAT_LDAPV3, NULL ); nomem: for (;baseAVA < newAVA; baseAVA++) { if (baseAVA->la_flags & LDAP_AVA_FREE_ATTR) LDAP_FREE( baseAVA->la_attr.bv_val ); if (baseAVA->la_flags & LDAP_AVA_FREE_VALUE) LDAP_FREE( baseAVA->la_value.bv_val ); } if ( oidsize != 0 ) LDAP_FREE( oidbuf ); if ( newDN != (LDAPDN)(char *) ptrs ) LDAP_FREE( newDN ); return rc; } openldap-2.5.11+dfsg/libraries/libldap/avl.c0000644000175000017500000003721114172327167017354 0ustar ryanryan/* avl.c - routines to implement an avl tree */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1993 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ /* ACKNOWLEDGEMENTS: * This work was originally developed by the University of Michigan * (as part of U-MICH LDAP). Additional significant contributors * include: * Howard Y. Chu * Hallvard B. Furuseth * Kurt D. Zeilenga */ #include "portable.h" #include #include #include #ifdef CSRIMALLOC #define ber_memalloc malloc #define ber_memrealloc realloc #define ber_memfree free #else #include "lber.h" #endif #define AVL_INTERNAL #include "ldap_avl.h" /* Maximum tree depth this host's address space could support */ #define MAX_TREE_DEPTH (sizeof(void *) * CHAR_BIT) static const int avl_bfs[] = {LH, RH}; /* * ldap_avl_insert -- insert a node containing data data into the avl tree * with root root. fcmp is a function to call to compare the data portion * of two nodes. it should take two arguments and return <, >, or == 0, * depending on whether its first argument is <, >, or == its second * argument (like strcmp, e.g.). fdup is a function to call when a duplicate * node is inserted. it should return 0, or -1 and its return value * will be the return value from ldap_avl_insert in the case of a duplicate node. * the function will be called with the original node's data as its first * argument and with the incoming duplicate node's data as its second * argument. this could be used, for example, to keep a count with each * node. * * NOTE: this routine may malloc memory */ int ldap_avl_insert( Avlnode ** root, void *data, AVL_CMP fcmp, AVL_DUP fdup ) { Avlnode *t, *p, *s, *q, *r; int a, cmp, ncmp; if ( *root == NULL ) { if (( r = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) { return( -1 ); } r->avl_link[0] = r->avl_link[1] = NULL; r->avl_data = data; r->avl_bits[0] = r->avl_bits[1] = AVL_CHILD; r->avl_bf = EH; *root = r; return( 0 ); } t = NULL; s = p = *root; /* find insertion point */ while (1) { cmp = fcmp( data, p->avl_data ); if ( cmp == 0 ) return (*fdup)( p->avl_data, data ); cmp = (cmp > 0); q = p->avl_link[cmp]; if (q == NULL) { /* insert */ if (( q = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) { return( -1 ); } q->avl_link[0] = q->avl_link[1] = NULL; q->avl_data = data; q->avl_bits[0] = q->avl_bits[1] = AVL_CHILD; q->avl_bf = EH; p->avl_link[cmp] = q; break; } else if ( q->avl_bf ) { t = p; s = q; } p = q; } /* adjust balance factors */ cmp = fcmp( data, s->avl_data ) > 0; r = p = s->avl_link[cmp]; a = avl_bfs[cmp]; while ( p != q ) { cmp = fcmp( data, p->avl_data ) > 0; p->avl_bf = avl_bfs[cmp]; p = p->avl_link[cmp]; } /* checks and balances */ if ( s->avl_bf == EH ) { s->avl_bf = a; return 0; } else if ( s->avl_bf == -a ) { s->avl_bf = EH; return 0; } else if ( s->avl_bf == a ) { cmp = (a > 0); ncmp = !cmp; if ( r->avl_bf == a ) { /* single rotation */ p = r; s->avl_link[cmp] = r->avl_link[ncmp]; r->avl_link[ncmp] = s; s->avl_bf = 0; r->avl_bf = 0; } else if ( r->avl_bf == -a ) { /* double rotation */ p = r->avl_link[ncmp]; r->avl_link[ncmp] = p->avl_link[cmp]; p->avl_link[cmp] = r; s->avl_link[cmp] = p->avl_link[ncmp]; p->avl_link[ncmp] = s; if ( p->avl_bf == a ) { s->avl_bf = -a; r->avl_bf = 0; } else if ( p->avl_bf == -a ) { s->avl_bf = 0; r->avl_bf = a; } else { s->avl_bf = 0; r->avl_bf = 0; } p->avl_bf = 0; } /* Update parent */ if ( t == NULL ) *root = p; else if ( s == t->avl_right ) t->avl_right = p; else t->avl_left = p; } return 0; } void* ldap_avl_delete( Avlnode **root, void* data, AVL_CMP fcmp ) { Avlnode *p, *q, *r, *top; int side, side_bf, shorter, nside; /* parent stack */ Avlnode *pptr[MAX_TREE_DEPTH]; unsigned char pdir[MAX_TREE_DEPTH]; int depth = 0; if ( *root == NULL ) return NULL; p = *root; while (1) { side = fcmp( data, p->avl_data ); if ( !side ) break; side = ( side > 0 ); pdir[depth] = side; pptr[depth++] = p; p = p->avl_link[side]; if ( p == NULL ) return p; } data = p->avl_data; /* If this node has two children, swap so we are deleting a node with * at most one child. */ if ( p->avl_link[0] && p->avl_link[1] ) { /* find the immediate predecessor */ q = p->avl_link[0]; side = depth; pdir[depth++] = 0; while (q->avl_link[1]) { pdir[depth] = 1; pptr[depth++] = q; q = q->avl_link[1]; } /* swap links */ r = p->avl_link[0]; p->avl_link[0] = q->avl_link[0]; q->avl_link[0] = r; q->avl_link[1] = p->avl_link[1]; p->avl_link[1] = NULL; q->avl_bf = p->avl_bf; /* fix stack positions: old parent of p points to q */ pptr[side] = q; if ( side ) { r = pptr[side-1]; r->avl_link[pdir[side-1]] = q; } else { *root = q; } /* new parent of p points to p */ if ( depth-side > 1 ) { r = pptr[depth-1]; r->avl_link[1] = p; } else { q->avl_link[0] = p; } } /* now

has at most one child, get it */ q = p->avl_link[0] ? p->avl_link[0] : p->avl_link[1]; ber_memfree( p ); if ( !depth ) { *root = q; return data; } /* set the child into p's parent */ depth--; p = pptr[depth]; side = pdir[depth]; p->avl_link[side] = q; top = NULL; shorter = 1; while ( shorter ) { p = pptr[depth]; side = pdir[depth]; nside = !side; side_bf = avl_bfs[side]; /* case 1: height unchanged */ if ( p->avl_bf == EH ) { /* Tree is now heavier on opposite side */ p->avl_bf = avl_bfs[nside]; shorter = 0; } else if ( p->avl_bf == side_bf ) { /* case 2: taller subtree shortened, height reduced */ p->avl_bf = EH; } else { /* case 3: shorter subtree shortened */ if ( depth ) top = pptr[depth-1]; /* p->parent; */ else top = NULL; /* set to the taller of the two subtrees of

*/ q = p->avl_link[nside]; if ( q->avl_bf == EH ) { /* case 3a: height unchanged, single rotate */ p->avl_link[nside] = q->avl_link[side]; q->avl_link[side] = p; shorter = 0; q->avl_bf = side_bf; p->avl_bf = (- side_bf); } else if ( q->avl_bf == p->avl_bf ) { /* case 3b: height reduced, single rotate */ p->avl_link[nside] = q->avl_link[side]; q->avl_link[side] = p; shorter = 1; q->avl_bf = EH; p->avl_bf = EH; } else { /* case 3c: height reduced, balance factors opposite */ r = q->avl_link[side]; q->avl_link[side] = r->avl_link[nside]; r->avl_link[nside] = q; p->avl_link[nside] = r->avl_link[side]; r->avl_link[side] = p; if ( r->avl_bf == side_bf ) { q->avl_bf = (- side_bf); p->avl_bf = EH; } else if ( r->avl_bf == (- side_bf)) { q->avl_bf = EH; p->avl_bf = side_bf; } else { q->avl_bf = EH; p->avl_bf = EH; } r->avl_bf = EH; q = r; } /* a rotation has caused (or in case 3c) to become * the root. let

's former parent know this. */ if ( top == NULL ) { *root = q; } else if (top->avl_link[0] == p) { top->avl_link[0] = q; } else { top->avl_link[1] = q; } /* end case 3 */ p = q; } if ( !depth ) break; depth--; } /* end while(shorter) */ return data; } static int avl_inapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag ) { if ( root == 0 ) return( AVL_NOMORE ); if ( root->avl_left != 0 ) if ( avl_inapply( root->avl_left, fn, arg, stopflag ) == stopflag ) return( stopflag ); if ( (*fn)( root->avl_data, arg ) == stopflag ) return( stopflag ); if ( root->avl_right == 0 ) return( AVL_NOMORE ); else return( avl_inapply( root->avl_right, fn, arg, stopflag ) ); } static int avl_postapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag ) { if ( root == 0 ) return( AVL_NOMORE ); if ( root->avl_left != 0 ) if ( avl_postapply( root->avl_left, fn, arg, stopflag ) == stopflag ) return( stopflag ); if ( root->avl_right != 0 ) if ( avl_postapply( root->avl_right, fn, arg, stopflag ) == stopflag ) return( stopflag ); return( (*fn)( root->avl_data, arg ) ); } static int avl_preapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag ) { if ( root == 0 ) return( AVL_NOMORE ); if ( (*fn)( root->avl_data, arg ) == stopflag ) return( stopflag ); if ( root->avl_left != 0 ) if ( avl_preapply( root->avl_left, fn, arg, stopflag ) == stopflag ) return( stopflag ); if ( root->avl_right == 0 ) return( AVL_NOMORE ); else return( avl_preapply( root->avl_right, fn, arg, stopflag ) ); } /* * ldap_avl_apply -- avl tree root is traversed, function fn is called with * arguments arg and the data portion of each node. if fn returns stopflag, * the traversal is cut short, otherwise it continues. Do not use -6 as * a stopflag, as this is what is used to indicate the traversal ran out * of nodes. */ int ldap_avl_apply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag, int type ) { switch ( type ) { case AVL_INORDER: return( avl_inapply( root, fn, arg, stopflag ) ); case AVL_PREORDER: return( avl_preapply( root, fn, arg, stopflag ) ); case AVL_POSTORDER: return( avl_postapply( root, fn, arg, stopflag ) ); default: fprintf( stderr, "Invalid traversal type %d\n", type ); return( -1 ); } /* NOTREACHED */ } /* * ldap_avl_prefixapply - traverse avl tree root, applying function fprefix * to any nodes that match. fcmp is called with data as its first arg * and the current node's data as its second arg. it should return * 0 if they match, < 0 if data is less, and > 0 if data is greater. * the idea is to efficiently find all nodes that are prefixes of * some key... Like ldap_avl_apply, this routine also takes a stopflag * and will return prematurely if fmatch returns this value. Otherwise, * AVL_NOMORE is returned. */ int ldap_avl_prefixapply( Avlnode *root, void* data, AVL_CMP fmatch, void* marg, AVL_CMP fcmp, void* carg, int stopflag ) { int cmp; if ( root == 0 ) return( AVL_NOMORE ); cmp = (*fcmp)( data, root->avl_data /* , carg */); if ( cmp == 0 ) { if ( (*fmatch)( root->avl_data, marg ) == stopflag ) return( stopflag ); if ( root->avl_left != 0 ) if ( ldap_avl_prefixapply( root->avl_left, data, fmatch, marg, fcmp, carg, stopflag ) == stopflag ) return( stopflag ); if ( root->avl_right != 0 ) return( ldap_avl_prefixapply( root->avl_right, data, fmatch, marg, fcmp, carg, stopflag ) ); else return( AVL_NOMORE ); } else if ( cmp < 0 ) { if ( root->avl_left != 0 ) return( ldap_avl_prefixapply( root->avl_left, data, fmatch, marg, fcmp, carg, stopflag ) ); } else { if ( root->avl_right != 0 ) return( ldap_avl_prefixapply( root->avl_right, data, fmatch, marg, fcmp, carg, stopflag ) ); } return( AVL_NOMORE ); } /* * ldap_avl_free -- traverse avltree root, freeing the memory it is using. * the dfree() is called to free the data portion of each node. The * number of items actually freed is returned. */ int ldap_avl_free( Avlnode *root, AVL_FREE dfree ) { int nleft, nright; if ( root == 0 ) return( 0 ); nleft = nright = 0; if ( root->avl_left != 0 ) nleft = ldap_avl_free( root->avl_left, dfree ); if ( root->avl_right != 0 ) nright = ldap_avl_free( root->avl_right, dfree ); if ( dfree ) (*dfree)( root->avl_data ); ber_memfree( root ); return( nleft + nright + 1 ); } /* * ldap_avl_find -- search avltree root for a node with data data. the function * cmp is used to compare things. it is called with data as its first arg * and the current node data as its second. it should return 0 if they match, * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2. */ Avlnode * ldap_avl_find2( Avlnode *root, const void *data, AVL_CMP fcmp ) { int cmp; while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) { cmp = cmp > 0; root = root->avl_link[cmp]; } return root; } void* ldap_avl_find( Avlnode *root, const void* data, AVL_CMP fcmp ) { int cmp; while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) { cmp = cmp > 0; root = root->avl_link[cmp]; } return( root ? root->avl_data : 0 ); } /* * ldap_avl_find_lin -- search avltree root linearly for a node with data data. * the function cmp is used to compare things. it is called with data as its * first arg and the current node data as its second. it should return 0 if * they match, non-zero otherwise. */ void* ldap_avl_find_lin( Avlnode *root, const void* data, AVL_CMP fcmp ) { void* res; if ( root == 0 ) return( NULL ); if ( (*fcmp)( data, root->avl_data ) == 0 ) return( root->avl_data ); if ( root->avl_left != 0 ) if ( (res = ldap_avl_find_lin( root->avl_left, data, fcmp )) != NULL ) return( res ); if ( root->avl_right == 0 ) return( NULL ); else return( ldap_avl_find_lin( root->avl_right, data, fcmp ) ); } /* NON-REENTRANT INTERFACE */ static void* *avl_list; static int avl_maxlist; static int ldap_avl_nextlist; #define AVL_GRABSIZE 100 /* ARGSUSED */ static int avl_buildlist( void* data, void* arg ) { static int slots; if ( avl_list == (void* *) 0 ) { avl_list = (void* *) ber_memalloc(AVL_GRABSIZE * sizeof(void*)); slots = AVL_GRABSIZE; avl_maxlist = 0; } else if ( avl_maxlist == slots ) { slots += AVL_GRABSIZE; avl_list = (void* *) ber_memrealloc( (char *) avl_list, (unsigned) slots * sizeof(void*)); } avl_list[ avl_maxlist++ ] = data; return( 0 ); } /* * ldap_avl_getfirst() and ldap_avl_getnext() are provided as alternate tree * traversal methods, to be used when a single function cannot be * provided to be called with every node in the tree. ldap_avl_getfirst() * traverses the tree and builds a linear list of all the nodes, * returning the first node. ldap_avl_getnext() returns the next thing * on the list built by ldap_avl_getfirst(). This means that ldap_avl_getfirst() * can take a while, and that the tree should not be messed with while * being traversed in this way, and that multiple traversals (even of * different trees) cannot be active at once. */ void* ldap_avl_getfirst( Avlnode *root ) { if ( avl_list ) { ber_memfree( (char *) avl_list); avl_list = (void* *) 0; } avl_maxlist = 0; ldap_avl_nextlist = 0; if ( root == 0 ) return( 0 ); (void) ldap_avl_apply( root, avl_buildlist, (void*) 0, -1, AVL_INORDER ); return( avl_list[ ldap_avl_nextlist++ ] ); } void* ldap_avl_getnext( void ) { if ( avl_list == 0 ) return( 0 ); if ( ldap_avl_nextlist == avl_maxlist ) { ber_memfree( (void*) avl_list); avl_list = (void* *) 0; return( 0 ); } return( avl_list[ ldap_avl_nextlist++ ] ); } /* end non-reentrant code */ int ldap_avl_dup_error( void* left, void* right ) { return( -1 ); } int ldap_avl_dup_ok( void* left, void* right ) { return( 0 ); } openldap-2.5.11+dfsg/libraries/libldap/print.c0000644000175000017500000000222314172327167017721 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" /* * ldap log */ static int ldap_log_check( LDAP *ld, int loglvl ) { int errlvl; if(ld == NULL) { errlvl = ldap_debug; } else { errlvl = ld->ld_debug; } return errlvl & loglvl ? 1 : 0; } int ldap_log_printf( LDAP *ld, int loglvl, const char *fmt, ... ) { char buf[ 1024 ]; va_list ap; if ( !ldap_log_check( ld, loglvl )) { return 0; } va_start( ap, fmt ); buf[sizeof(buf) - 1] = '\0'; vsnprintf( buf, sizeof(buf)-1, fmt, ap ); va_end(ap); (*ber_pvt_log_print)( buf ); return 1; } openldap-2.5.11+dfsg/libraries/libldap/threads.c0000644000175000017500000000431214172327167020220 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" #ifdef LDAP_R_COMPILE #include "ldap_pvt_thread.h" /* Get the thread interface */ #include "ldap_thr_debug.h" /* May redirect thread initialize/destroy calls */ /* * Common LDAP thread routines * see thr_*.c for implementation specific routines * see rdwr.c for generic reader/writer lock implementation * see tpool.c for generic thread pool implementation */ int ldap_pvt_thread_initialize( void ) { int rc; static int init = 0; ldap_pvt_thread_t tid; /* we only get one shot at this */ if( init++ ) return -1; rc = ldap_int_thread_initialize(); if( rc ) return rc; #ifndef LDAP_THREAD_HAVE_TPOOL rc = ldap_int_thread_pool_startup(); if( rc ) return rc; #endif /* kludge to pull symbol definitions in */ tid = ldap_pvt_thread_self(); return 0; } int ldap_pvt_thread_destroy( void ) { #ifndef LDAP_THREAD_HAVE_TPOOL (void) ldap_int_thread_pool_shutdown(); #endif return ldap_int_thread_destroy(); } /* * Default implementations of some LDAP thread routines */ #define LDAP_THREAD_IMPLEMENTATION #include "ldap_thr_debug.h" /* May rename the symbols defined below */ #ifndef LDAP_THREAD_HAVE_GETCONCURRENCY int ldap_pvt_thread_get_concurrency ( void ) { return 1; } #endif #ifndef LDAP_THREAD_HAVE_SETCONCURRENCY int ldap_pvt_thread_set_concurrency ( int concurrency ) { return 1; } #endif #ifndef LDAP_THREAD_HAVE_SLEEP /* * Here we assume we have fully preemptive threads and that sleep() * does the right thing. */ unsigned int ldap_pvt_thread_sleep( unsigned int interval ) { sleep( interval ); return 0; } #endif #endif /* LDAP_R_COMPILE */ openldap-2.5.11+dfsg/libraries/libldap/testavl.c0000644000175000017500000000737614172327167020265 0ustar ryanryan/* testavl.c - Test Tim Howes AVL code */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1993 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ /* ACKNOWLEDGEMENTS: * This work was originally developed by the University of Michigan * (as part of U-MICH LDAP). */ #include "portable.h" #include #include #include #define AVL_INTERNAL #define AVL_NONREENTRANT #include "ldap_avl.h" static void ravl_print LDAP_P(( Avlnode *root, int depth )); static void myprint LDAP_P(( Avlnode *root )); static int avl_strcmp LDAP_P(( const void *s, const void *t )); int main( int argc, char **argv ) { Avlnode *tree = NULL; char command[ 10 ]; char name[ 80 ]; char *p; printf( "> " ); while ( fgets( command, sizeof( command ), stdin ) != NULL ) { switch( *command ) { case 'n': /* new tree */ ( void ) ldap_avl_free( tree, free ); tree = NULL; break; case 'p': /* print */ ( void ) myprint( tree ); break; case 't': /* traverse with first, next */ #ifdef AVL_NONREENTRANT printf( "***\n" ); for ( p = (char * ) ldap_avl_getfirst( tree ); p != NULL; p = (char *) ldap_avl_getnext()) printf( "%s\n", p ); printf( "***\n" ); #else printf( "*** reentrant interface not implemented ***" ); #endif break; case 'f': /* find */ printf( "data? " ); if ( fgets( name, sizeof( name ), stdin ) == NULL ) exit( EXIT_SUCCESS ); name[ strlen( name ) - 1 ] = '\0'; if ( (p = (char *) ldap_avl_find( tree, name, avl_strcmp )) == NULL ) printf( "Not found.\n\n" ); else printf( "%s\n\n", p ); break; case 'i': /* insert */ printf( "data? " ); if ( fgets( name, sizeof( name ), stdin ) == NULL ) exit( EXIT_SUCCESS ); name[ strlen( name ) - 1 ] = '\0'; if ( ldap_avl_insert( &tree, strdup( name ), avl_strcmp, ldap_avl_dup_error ) != 0 ) printf( "\nNot inserted!\n" ); break; case 'd': /* delete */ printf( "data? " ); if ( fgets( name, sizeof( name ), stdin ) == NULL ) exit( EXIT_SUCCESS ); name[ strlen( name ) - 1 ] = '\0'; if ( ldap_avl_delete( &tree, name, avl_strcmp ) == NULL ) printf( "\nNot found!\n" ); break; case 'q': /* quit */ exit( EXIT_SUCCESS ); break; case '\n': break; default: printf("Commands: insert, delete, print, new, quit\n"); } printf( "> " ); } return( 0 ); } static void ravl_print( Avlnode *root, int depth ) { int i; if ( root == 0 ) return; ravl_print( root->avl_right, depth+1 ); for ( i = 0; i < depth; i++ ) printf( " " ); printf( "%s %d\n", (char *) root->avl_data, root->avl_bf ); ravl_print( root->avl_left, depth+1 ); } static void myprint( Avlnode *root ) { printf( "********\n" ); if ( root == 0 ) printf( "\tNULL\n" ); else ravl_print( root, 0 ); printf( "********\n" ); } static int avl_strcmp( const void *s, const void *t ) { return strcmp( s, t ); } openldap-2.5.11+dfsg/libraries/libldap/error.c0000644000175000017500000002566114172327167017731 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" void ldap_int_error_init( void ) { } char * ldap_err2string( int err ) { char *m; Debug0( LDAP_DEBUG_TRACE, "ldap_err2string\n" ); switch ( err ) { # define C(code, message) case code: m = message; break /* LDAPv3 (RFC 4511) codes */ C(LDAP_SUCCESS, N_("Success")); C(LDAP_OPERATIONS_ERROR, N_("Operations error")); C(LDAP_PROTOCOL_ERROR, N_("Protocol error")); C(LDAP_TIMELIMIT_EXCEEDED, N_("Time limit exceeded")); C(LDAP_SIZELIMIT_EXCEEDED, N_("Size limit exceeded")); C(LDAP_COMPARE_FALSE, N_("Compare False")); C(LDAP_COMPARE_TRUE, N_("Compare True")); C(LDAP_STRONG_AUTH_NOT_SUPPORTED,N_("Authentication method not supported")); C(LDAP_STRONG_AUTH_REQUIRED, N_("Strong(er) authentication required")); C(LDAP_REFERRAL, N_("Referral")); C(LDAP_ADMINLIMIT_EXCEEDED, N_("Administrative limit exceeded")); C(LDAP_UNAVAILABLE_CRITICAL_EXTENSION, N_("Critical extension is unavailable")); C(LDAP_CONFIDENTIALITY_REQUIRED,N_("Confidentiality required")); C(LDAP_SASL_BIND_IN_PROGRESS, N_("SASL bind in progress")); C(LDAP_NO_SUCH_ATTRIBUTE, N_("No such attribute")); C(LDAP_UNDEFINED_TYPE, N_("Undefined attribute type")); C(LDAP_INAPPROPRIATE_MATCHING, N_("Inappropriate matching")); C(LDAP_CONSTRAINT_VIOLATION, N_("Constraint violation")); C(LDAP_TYPE_OR_VALUE_EXISTS, N_("Type or value exists")); C(LDAP_INVALID_SYNTAX, N_("Invalid syntax")); C(LDAP_NO_SUCH_OBJECT, N_("No such object")); C(LDAP_ALIAS_PROBLEM, N_("Alias problem")); C(LDAP_INVALID_DN_SYNTAX, N_("Invalid DN syntax")); C(LDAP_ALIAS_DEREF_PROBLEM, N_("Alias dereferencing problem")); C(LDAP_INAPPROPRIATE_AUTH, N_("Inappropriate authentication")); C(LDAP_INVALID_CREDENTIALS, N_("Invalid credentials")); C(LDAP_INSUFFICIENT_ACCESS, N_("Insufficient access")); C(LDAP_BUSY, N_("Server is busy")); C(LDAP_UNAVAILABLE, N_("Server is unavailable")); C(LDAP_UNWILLING_TO_PERFORM, N_("Server is unwilling to perform")); C(LDAP_LOOP_DETECT, N_("Loop detected")); C(LDAP_NAMING_VIOLATION, N_("Naming violation")); C(LDAP_OBJECT_CLASS_VIOLATION, N_("Object class violation")); C(LDAP_NOT_ALLOWED_ON_NONLEAF, N_("Operation not allowed on non-leaf")); C(LDAP_NOT_ALLOWED_ON_RDN, N_("Operation not allowed on RDN")); C(LDAP_ALREADY_EXISTS, N_("Already exists")); C(LDAP_NO_OBJECT_CLASS_MODS, N_("Cannot modify object class")); C(LDAP_AFFECTS_MULTIPLE_DSAS, N_("Operation affects multiple DSAs")); /* Virtual List View draft */ C(LDAP_VLV_ERROR, N_("Virtual List View error")); C(LDAP_OTHER, N_("Other (e.g., implementation specific) error")); /* LDAPv2 (RFC 1777) codes */ C(LDAP_PARTIAL_RESULTS, N_("Partial results and referral received")); C(LDAP_IS_LEAF, N_("Entry is a leaf")); /* Connection-less LDAP (CLDAP - RFC 1798) code */ C(LDAP_RESULTS_TOO_LARGE, N_("Results too large")); /* Cancel Operation (RFC 3909) codes */ C(LDAP_CANCELLED, N_("Cancelled")); C(LDAP_NO_SUCH_OPERATION, N_("No Operation to Cancel")); C(LDAP_TOO_LATE, N_("Too Late to Cancel")); C(LDAP_CANNOT_CANCEL, N_("Cannot Cancel")); /* Assert Control (RFC 4528 and old internet-draft) codes */ C(LDAP_ASSERTION_FAILED, N_("Assertion Failed")); C(LDAP_X_ASSERTION_FAILED, N_("Assertion Failed (X)")); /* Proxied Authorization Control (RFC 4370 and I-D) codes */ C(LDAP_PROXIED_AUTHORIZATION_DENIED, N_("Proxied Authorization Denied")); C(LDAP_X_PROXY_AUTHZ_FAILURE, N_("Proxy Authorization Failure (X)")); /* Content Sync Operation (RFC 4533 and I-D) codes */ C(LDAP_SYNC_REFRESH_REQUIRED, N_("Content Sync Refresh Required")); C(LDAP_X_SYNC_REFRESH_REQUIRED, N_("Content Sync Refresh Required (X)")); /* No-Op Control (draft-zeilenga-ldap-noop) code */ C(LDAP_X_NO_OPERATION, N_("No Operation (X)")); /* Client Update Protocol (RFC 3928) codes */ C(LDAP_CUP_RESOURCES_EXHAUSTED, N_("LCUP Resources Exhausted")); C(LDAP_CUP_SECURITY_VIOLATION, N_("LCUP Security Violation")); C(LDAP_CUP_INVALID_DATA, N_("LCUP Invalid Data")); C(LDAP_CUP_UNSUPPORTED_SCHEME, N_("LCUP Unsupported Scheme")); C(LDAP_CUP_RELOAD_REQUIRED, N_("LCUP Reload Required")); C(LDAP_TXN_SPECIFY_OKAY, N_("TXN specify okay")); C(LDAP_TXN_ID_INVALID, N_("TXN ID is invalid")); /* API codes - renumbered since draft-ietf-ldapext-ldap-c-api */ C(LDAP_SERVER_DOWN, N_("Can't contact LDAP server")); C(LDAP_LOCAL_ERROR, N_("Local error")); C(LDAP_ENCODING_ERROR, N_("Encoding error")); C(LDAP_DECODING_ERROR, N_("Decoding error")); C(LDAP_TIMEOUT, N_("Timed out")); C(LDAP_AUTH_UNKNOWN, N_("Unknown authentication method")); C(LDAP_FILTER_ERROR, N_("Bad search filter")); C(LDAP_USER_CANCELLED, N_("User cancelled operation")); C(LDAP_PARAM_ERROR, N_("Bad parameter to an ldap routine")); C(LDAP_NO_MEMORY, N_("Out of memory")); C(LDAP_CONNECT_ERROR, N_("Connect error")); C(LDAP_NOT_SUPPORTED, N_("Not Supported")); C(LDAP_CONTROL_NOT_FOUND, N_("Control not found")); C(LDAP_NO_RESULTS_RETURNED, N_("No results returned")); C(LDAP_MORE_RESULTS_TO_RETURN, N_("More results to return")); C(LDAP_CLIENT_LOOP, N_("Client Loop")); C(LDAP_REFERRAL_LIMIT_EXCEEDED, N_("Referral Limit Exceeded")); C(LDAP_X_CONNECTING, N_("Connecting (X)")); # undef C default: m = (LDAP_API_ERROR(err) ? N_("Unknown API error") : LDAP_E_ERROR(err) ? N_("Unknown (extension) error") : LDAP_X_ERROR(err) ? N_("Unknown (private extension) error") : N_("Unknown error")); break; } return _(m); } /* deprecated */ void ldap_perror( LDAP *ld, LDAP_CONST char *str ) { int i; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( str != NULL ); fprintf( stderr, "%s: %s (%d)\n", str ? str : "ldap_perror", ldap_err2string( ld->ld_errno ), ld->ld_errno ); if ( ld->ld_matched != NULL && ld->ld_matched[0] != '\0' ) { fprintf( stderr, _("\tmatched DN: %s\n"), ld->ld_matched ); } if ( ld->ld_error != NULL && ld->ld_error[0] != '\0' ) { fprintf( stderr, _("\tadditional info: %s\n"), ld->ld_error ); } if ( ld->ld_referrals != NULL && ld->ld_referrals[0] != NULL) { fprintf( stderr, _("\treferrals:\n") ); for (i=0; ld->ld_referrals[i]; i++) { fprintf( stderr, _("\t\t%s\n"), ld->ld_referrals[i] ); } } fflush( stderr ); } /* deprecated */ int ldap_result2error( LDAP *ld, LDAPMessage *r, int freeit ) { int rc, err; rc = ldap_parse_result( ld, r, &err, NULL, NULL, NULL, NULL, freeit ); return err != LDAP_SUCCESS ? err : rc; } /* * Parse LDAPResult Messages: * * LDAPResult ::= SEQUENCE { * resultCode ENUMERATED, * matchedDN LDAPDN, * errorMessage LDAPString, * referral [3] Referral OPTIONAL } * * including Bind results: * * BindResponse ::= [APPLICATION 1] SEQUENCE { * COMPONENTS OF LDAPResult, * serverSaslCreds [7] OCTET STRING OPTIONAL } * * and ExtendedOp results: * * ExtendedResponse ::= [APPLICATION 24] SEQUENCE { * COMPONENTS OF LDAPResult, * responseName [10] LDAPOID OPTIONAL, * response [11] OCTET STRING OPTIONAL } * */ int ldap_parse_result( LDAP *ld, LDAPMessage *r, int *errcodep, char **matcheddnp, char **errmsgp, char ***referralsp, LDAPControl ***serverctrls, int freeit ) { LDAPMessage *lm; ber_int_t errcode = LDAP_SUCCESS; ber_tag_t tag; BerElement *ber; Debug0( LDAP_DEBUG_TRACE, "ldap_parse_result\n" ); assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( r != NULL ); if(errcodep != NULL) *errcodep = LDAP_SUCCESS; if(matcheddnp != NULL) *matcheddnp = NULL; if(errmsgp != NULL) *errmsgp = NULL; if(referralsp != NULL) *referralsp = NULL; if(serverctrls != NULL) *serverctrls = NULL; LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); /* Find the result, last msg in chain... */ lm = r->lm_chain_tail; /* FIXME: either this is not possible (assert?) * or it should be handled */ if ( lm != NULL ) { switch ( lm->lm_msgtype ) { case LDAP_RES_SEARCH_ENTRY: case LDAP_RES_SEARCH_REFERENCE: case LDAP_RES_INTERMEDIATE: lm = NULL; break; default: break; } } if( lm == NULL ) { errcode = ld->ld_errno = LDAP_NO_RESULTS_RETURNED; LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); goto done; } if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); ld->ld_error = NULL; } if ( ld->ld_matched ) { LDAP_FREE( ld->ld_matched ); ld->ld_matched = NULL; } if ( ld->ld_referrals ) { LDAP_VFREE( ld->ld_referrals ); ld->ld_referrals = NULL; } /* parse results */ ber = ber_dup( lm->lm_ber ); if ( ld->ld_version < LDAP_VERSION2 ) { tag = ber_scanf( ber, "{iA}", &ld->ld_errno, &ld->ld_error ); } else { ber_len_t len; tag = ber_scanf( ber, "{iAA" /*}*/, &ld->ld_errno, &ld->ld_matched, &ld->ld_error ); if( tag != LBER_ERROR ) { /* peek for referrals */ if( ber_peek_tag(ber, &len) == LDAP_TAG_REFERRAL ) { tag = ber_scanf( ber, "v", &ld->ld_referrals ); } } /* need to clean out misc items */ if( tag != LBER_ERROR ) { if( lm->lm_msgtype == LDAP_RES_BIND ) { /* look for sasl result credentials */ if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SASL_RES_CREDS ) { /* skip 'em */ tag = ber_scanf( ber, "x" ); } } else if( lm->lm_msgtype == LDAP_RES_EXTENDED ) { /* look for exop result oid or value */ if ( ber_peek_tag( ber, &len ) == LDAP_TAG_EXOP_RES_OID ) { /* skip 'em */ tag = ber_scanf( ber, "x" ); } if ( tag != LBER_ERROR && ber_peek_tag( ber, &len ) == LDAP_TAG_EXOP_RES_VALUE ) { /* skip 'em */ tag = ber_scanf( ber, "x" ); } } } if( tag != LBER_ERROR ) { int rc = ldap_pvt_get_controls( ber, serverctrls ); if( rc != LDAP_SUCCESS ) { tag = LBER_ERROR; } } if( tag != LBER_ERROR ) { tag = ber_scanf( ber, /*{*/"}" ); } } if ( tag == LBER_ERROR ) { ld->ld_errno = errcode = LDAP_DECODING_ERROR; } if( ber != NULL ) { ber_free( ber, 0 ); } /* return */ if( errcodep != NULL ) { *errcodep = ld->ld_errno; } if ( errcode == LDAP_SUCCESS ) { if( matcheddnp != NULL ) { if ( ld->ld_matched ) { *matcheddnp = LDAP_STRDUP( ld->ld_matched ); } } if( errmsgp != NULL ) { if ( ld->ld_error ) { *errmsgp = LDAP_STRDUP( ld->ld_error ); } } if( referralsp != NULL) { *referralsp = ldap_value_dup( ld->ld_referrals ); } } LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); done: if ( freeit ) { ldap_msgfree( r ); } return errcode; } openldap-2.5.11+dfsg/libraries/libldap/utf-8.c0000644000175000017500000003032314172327167017532 0ustar ryanryan/* utf-8.c -- Basic UTF-8 routines */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Basic UTF-8 routines * * These routines are "dumb". Though they understand UTF-8, * they don't grok Unicode. That is, they can push bits, * but don't have a clue what the bits represent. That's * good enough for use with the LDAP Client SDK. * * These routines are not optimized. */ #include "portable.h" #include #include #include #include #include #include "ldap_utf8.h" #include "ldap-int.h" #include "ldap_defaults.h" /* * return the number of bytes required to hold the * NULL-terminated UTF-8 string NOT INCLUDING the * termination. */ ber_len_t ldap_utf8_bytes( const char * p ) { ber_len_t bytes; for( bytes=0; p[bytes]; bytes++ ) { /* EMPTY */ ; } return bytes; } ber_len_t ldap_utf8_chars( const char * p ) { /* could be optimized and could check for invalid sequences */ ber_len_t chars=0; for( ; *p ; LDAP_UTF8_INCR(p) ) { chars++; } return chars; } /* return offset to next character */ int ldap_utf8_offset( const char * p ) { return LDAP_UTF8_NEXT(p) - p; } /* * Returns length indicated by first byte. */ const char ldap_utf8_lentab[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0 }; int ldap_utf8_charlen( const char * p ) { if (!(*p & 0x80)) return 1; return ldap_utf8_lentab[*(const unsigned char *)p ^ 0x80]; } /* * Make sure the UTF-8 char used the shortest possible encoding * returns charlen if valid, 0 if not. * * Here are the valid UTF-8 encodings, taken from RFC 2279 page 4. * The table is slightly modified from that of the RFC. * * UCS-4 range (hex) UTF-8 sequence (binary) * 0000 0000-0000 007F 0....... * 0000 0080-0000 07FF 110++++. 10...... * 0000 0800-0000 FFFF 1110++++ 10+..... 10...... * 0001 0000-001F FFFF 11110+++ 10++.... 10...... 10...... * 0020 0000-03FF FFFF 111110++ 10+++... 10...... 10...... 10...... * 0400 0000-7FFF FFFF 1111110+ 10++++.. 10...... 10...... 10...... 10...... * * The '.' bits are "don't cares". When validating a UTF-8 sequence, * at least one of the '+' bits must be set, otherwise the character * should have been encoded in fewer octets. Note that in the two-octet * case, only the first octet needs to be validated, and this is done * in the ldap_utf8_lentab[] above. */ /* mask of required bits in second octet */ #undef c #define c const char c ldap_utf8_mintab[] = { (c)0x20, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x30, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x38, (c)0x80, (c)0x80, (c)0x80, (c)0x3c, (c)0x80, (c)0x00, (c)0x00 }; #undef c int ldap_utf8_charlen2( const char * p ) { int i = LDAP_UTF8_CHARLEN( p ); if ( i > 2 ) { if ( !( ldap_utf8_mintab[*p & 0x1f] & p[1] ) ) i = 0; } return i; } /* conv UTF-8 to UCS-4, useful for comparisons */ ldap_ucs4_t ldap_x_utf8_to_ucs4( const char * p ) { const unsigned char *c = (const unsigned char *) p; ldap_ucs4_t ch; int len, i; static unsigned char mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; len = LDAP_UTF8_CHARLEN2(p, len); if( len == 0 ) return LDAP_UCS4_INVALID; ch = c[0] & mask[len]; for(i=1; i < len; i++) { if ((c[i] & 0xc0) != 0x80) { return LDAP_UCS4_INVALID; } ch <<= 6; ch |= c[i] & 0x3f; } return ch; } /* conv UCS-4 to UTF-8, not used */ int ldap_x_ucs4_to_utf8( ldap_ucs4_t c, char *buf ) { int len=0; unsigned char* p = (unsigned char *) buf; /* not a valid Unicode character */ if ( c < 0 ) return 0; /* Just return length, don't convert */ if(buf == NULL) { if( c < 0x80 ) return 1; else if( c < 0x800 ) return 2; else if( c < 0x10000 ) return 3; else if( c < 0x200000 ) return 4; else if( c < 0x4000000 ) return 5; else return 6; } if( c < 0x80 ) { p[len++] = c; } else if( c < 0x800 ) { p[len++] = 0xc0 | ( c >> 6 ); p[len++] = 0x80 | ( c & 0x3f ); } else if( c < 0x10000 ) { p[len++] = 0xe0 | ( c >> 12 ); p[len++] = 0x80 | ( (c >> 6) & 0x3f ); p[len++] = 0x80 | ( c & 0x3f ); } else if( c < 0x200000 ) { p[len++] = 0xf0 | ( c >> 18 ); p[len++] = 0x80 | ( (c >> 12) & 0x3f ); p[len++] = 0x80 | ( (c >> 6) & 0x3f ); p[len++] = 0x80 | ( c & 0x3f ); } else if( c < 0x4000000 ) { p[len++] = 0xf8 | ( c >> 24 ); p[len++] = 0x80 | ( (c >> 18) & 0x3f ); p[len++] = 0x80 | ( (c >> 12) & 0x3f ); p[len++] = 0x80 | ( (c >> 6) & 0x3f ); p[len++] = 0x80 | ( c & 0x3f ); } else /* if( c < 0x80000000 ) */ { p[len++] = 0xfc | ( c >> 30 ); p[len++] = 0x80 | ( (c >> 24) & 0x3f ); p[len++] = 0x80 | ( (c >> 18) & 0x3f ); p[len++] = 0x80 | ( (c >> 12) & 0x3f ); p[len++] = 0x80 | ( (c >> 6) & 0x3f ); p[len++] = 0x80 | ( c & 0x3f ); } return len; } #define LDAP_UCS_UTF8LEN(c) \ c < 0 ? 0 : (c < 0x80 ? 1 : (c < 0x800 ? 2 : (c < 0x10000 ? 3 : \ (c < 0x200000 ? 4 : (c < 0x4000000 ? 5 : 6))))) /* Convert a string to UTF-8 format. The input string is expected to * have characters of 1, 2, or 4 octets (in network byte order) * corresponding to the ASN.1 T61STRING, BMPSTRING, and UNIVERSALSTRING * types respectively. (Here T61STRING just means that there is one * octet per character and characters may use the high bit of the octet. * The characters are assumed to use ISO mappings, no provision is made * for converting from T.61 coding rules to Unicode.) */ int ldap_ucs_to_utf8s( struct berval *ucs, int csize, struct berval *utf8s ) { unsigned char *in, *end; char *ptr; ldap_ucs4_t u; int i, l = 0; utf8s->bv_val = NULL; utf8s->bv_len = 0; in = (unsigned char *)ucs->bv_val; /* Make sure we stop at an even multiple of csize */ end = in + ( ucs->bv_len & ~(csize-1) ); for (; in < end; ) { u = *in++; if (csize > 1) { u <<= 8; u |= *in++; } if (csize > 2) { u <<= 8; u |= *in++; u <<= 8; u |= *in++; } i = LDAP_UCS_UTF8LEN(u); if (i == 0) return LDAP_INVALID_SYNTAX; l += i; } utf8s->bv_val = LDAP_MALLOC( l+1 ); if (utf8s->bv_val == NULL) return LDAP_NO_MEMORY; utf8s->bv_len = l; ptr = utf8s->bv_val; for (in = (unsigned char *)ucs->bv_val; in < end; ) { u = *in++; if (csize > 1) { u <<= 8; u |= *in++; } if (csize > 2) { u <<= 8; u |= *in++; u <<= 8; u |= *in++; } ptr += ldap_x_ucs4_to_utf8(u, ptr); } *ptr = '\0'; return LDAP_SUCCESS; } /* * Advance to the next UTF-8 character * * Ignores length of multibyte character, instead rely on * continuation markers to find start of next character. * This allows for "resyncing" of when invalid characters * are provided provided the start of the next character * is appears within the 6 bytes examined. */ char* ldap_utf8_next( const char * p ) { int i; const unsigned char *u = (const unsigned char *) p; if( LDAP_UTF8_ISASCII(u) ) { return (char *) &p[1]; } for( i=1; i<6; i++ ) { if ( ( u[i] & 0xc0 ) != 0x80 ) { return (char *) &p[i]; } } return (char *) &p[i]; } /* * Advance to the previous UTF-8 character * * Ignores length of multibyte character, instead rely on * continuation markers to find start of next character. * This allows for "resyncing" of when invalid characters * are provided provided the start of the next character * is appears within the 6 bytes examined. */ char* ldap_utf8_prev( const char * p ) { int i; const unsigned char *u = (const unsigned char *) p; for( i=-1; i>-6 ; i-- ) { if ( ( u[i] & 0xc0 ) != 0x80 ) { return (char *) &p[i]; } } return (char *) &p[i]; } /* * Copy one UTF-8 character from src to dst returning * number of bytes copied. * * Ignores length of multibyte character, instead rely on * continuation markers to find start of next character. * This allows for "resyncing" of when invalid characters * are provided provided the start of the next character * is appears within the 6 bytes examined. */ int ldap_utf8_copy( char* dst, const char *src ) { int i; const unsigned char *u = (const unsigned char *) src; dst[0] = src[0]; if( LDAP_UTF8_ISASCII(u) ) { return 1; } for( i=1; i<6; i++ ) { if ( ( u[i] & 0xc0 ) != 0x80 ) { return i; } dst[i] = src[i]; } return i; } #ifndef UTF8_ALPHA_CTYPE /* * UTF-8 ctype routines * Only deals with characters < 0x80 (ie: US-ASCII) */ int ldap_utf8_isascii( const char * p ) { unsigned c = * (const unsigned char *) p; return LDAP_ASCII(c); } int ldap_utf8_isdigit( const char * p ) { unsigned c = * (const unsigned char *) p; if(!LDAP_ASCII(c)) return 0; return LDAP_DIGIT( c ); } int ldap_utf8_isxdigit( const char * p ) { unsigned c = * (const unsigned char *) p; if(!LDAP_ASCII(c)) return 0; return LDAP_HEX(c); } int ldap_utf8_isspace( const char * p ) { unsigned c = * (const unsigned char *) p; if(!LDAP_ASCII(c)) return 0; switch(c) { case ' ': case '\t': case '\n': case '\r': case '\v': case '\f': return 1; } return 0; } /* * These are not needed by the C SDK and are * not "good enough" for general use. */ int ldap_utf8_isalpha( const char * p ) { unsigned c = * (const unsigned char *) p; if(!LDAP_ASCII(c)) return 0; return LDAP_ALPHA(c); } int ldap_utf8_isalnum( const char * p ) { unsigned c = * (const unsigned char *) p; if(!LDAP_ASCII(c)) return 0; return LDAP_ALNUM(c); } int ldap_utf8_islower( const char * p ) { unsigned c = * (const unsigned char *) p; if(!LDAP_ASCII(c)) return 0; return LDAP_LOWER(c); } int ldap_utf8_isupper( const char * p ) { unsigned c = * (const unsigned char *) p; if(!LDAP_ASCII(c)) return 0; return LDAP_UPPER(c); } #endif /* * UTF-8 string routines */ /* like strchr() */ char * (ldap_utf8_strchr)( const char *str, const char *chr ) { for( ; *str != '\0'; LDAP_UTF8_INCR(str) ) { if( ldap_x_utf8_to_ucs4( str ) == ldap_x_utf8_to_ucs4( chr ) ) { return (char *) str; } } return NULL; } /* like strcspn() but returns number of bytes, not characters */ ber_len_t (ldap_utf8_strcspn)( const char *str, const char *set ) { const char *cstr; const char *cset; for( cstr = str; *cstr != '\0'; LDAP_UTF8_INCR(cstr) ) { for( cset = set; *cset != '\0'; LDAP_UTF8_INCR(cset) ) { if( ldap_x_utf8_to_ucs4( cstr ) == ldap_x_utf8_to_ucs4( cset ) ) { return cstr - str; } } } return cstr - str; } /* like strspn() but returns number of bytes, not characters */ ber_len_t (ldap_utf8_strspn)( const char *str, const char *set ) { const char *cstr; const char *cset; for( cstr = str; *cstr != '\0'; LDAP_UTF8_INCR(cstr) ) { for( cset = set; ; LDAP_UTF8_INCR(cset) ) { if( *cset == '\0' ) { return cstr - str; } if( ldap_x_utf8_to_ucs4( cstr ) == ldap_x_utf8_to_ucs4( cset ) ) { break; } } } return cstr - str; } /* like strpbrk(), replaces strchr() as well */ char *(ldap_utf8_strpbrk)( const char *str, const char *set ) { for( ; *str != '\0'; LDAP_UTF8_INCR(str) ) { const char *cset; for( cset = set; *cset != '\0'; LDAP_UTF8_INCR(cset) ) { if( ldap_x_utf8_to_ucs4( str ) == ldap_x_utf8_to_ucs4( cset ) ) { return (char *) str; } } } return NULL; } /* like strtok_r(), not strtok() */ char *(ldap_utf8_strtok)(char *str, const char *sep, char **last) { char *begin; char *end; if( last == NULL ) return NULL; begin = str ? str : *last; begin += ldap_utf8_strspn( begin, sep ); if( *begin == '\0' ) { *last = NULL; return NULL; } end = &begin[ ldap_utf8_strcspn( begin, sep ) ]; if( *end != '\0' ) { char *next = LDAP_UTF8_NEXT( end ); *end = '\0'; end = next; } *last = end; return begin; } openldap-2.5.11+dfsg/libraries/libldap/search.c0000644000175000017500000002745514172327167020050 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ #include "portable.h" #include #include #include #include #include #include "ldap-int.h" #include "ldap_log.h" /* * ldap_search_ext - initiate an ldap search operation. * * Parameters: * * ld LDAP descriptor * base DN of the base object * scope the search scope - one of * LDAP_SCOPE_BASE (baseObject), * LDAP_SCOPE_ONELEVEL (oneLevel), * LDAP_SCOPE_SUBTREE (subtree), or * LDAP_SCOPE_SUBORDINATE (children) -- OpenLDAP extension * filter a string containing the search filter * (e.g., "(|(cn=bob)(sn=bob))") * attrs list of attribute types to return for matches * attrsonly 1 => attributes only 0 => attributes and values * * Example: * char *attrs[] = { "mail", "title", 0 }; * ldap_search_ext( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob", * attrs, attrsonly, sctrls, ctrls, timeout, sizelimit, * &msgid ); */ int ldap_search_ext( LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter, char **attrs, int attrsonly, LDAPControl **sctrls, LDAPControl **cctrls, struct timeval *timeout, int sizelimit, int *msgidp ) { return ldap_pvt_search( ld, base, scope, filter, attrs, attrsonly, sctrls, cctrls, timeout, sizelimit, -1, msgidp ); } int ldap_pvt_search( LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter, char **attrs, int attrsonly, LDAPControl **sctrls, LDAPControl **cctrls, struct timeval *timeout, int sizelimit, int deref, int *msgidp ) { int rc; BerElement *ber; int timelimit; ber_int_t id; Debug0( LDAP_DEBUG_TRACE, "ldap_search_ext\n" ); assert( ld != NULL ); assert( LDAP_VALID( ld ) ); /* check client controls */ rc = ldap_int_client_controls( ld, cctrls ); if( rc != LDAP_SUCCESS ) return rc; /* * if timeout is provided, both tv_sec and tv_usec must * not be zero */ if( timeout != NULL ) { if( timeout->tv_sec == 0 && timeout->tv_usec == 0 ) { return LDAP_PARAM_ERROR; } /* timelimit must be non-zero if timeout is provided */ timelimit = timeout->tv_sec != 0 ? timeout->tv_sec : 1; } else { /* no timeout, no timelimit */ timelimit = -1; } ber = ldap_build_search_req( ld, base, scope, filter, attrs, attrsonly, sctrls, cctrls, timelimit, sizelimit, deref, &id ); if ( ber == NULL ) { return ld->ld_errno; } /* send the message */ *msgidp = ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id ); if( *msgidp < 0 ) return ld->ld_errno; return LDAP_SUCCESS; } int ldap_search_ext_s( LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter, char **attrs, int attrsonly, LDAPControl **sctrls, LDAPControl **cctrls, struct timeval *timeout, int sizelimit, LDAPMessage **res ) { return ldap_pvt_search_s( ld, base, scope, filter, attrs, attrsonly, sctrls, cctrls, timeout, sizelimit, -1, res ); } int ldap_pvt_search_s( LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter, char **attrs, int attrsonly, LDAPControl **sctrls, LDAPControl **cctrls, struct timeval *timeout, int sizelimit, int deref, LDAPMessage **res ) { int rc; int msgid; *res = NULL; rc = ldap_pvt_search( ld, base, scope, filter, attrs, attrsonly, sctrls, cctrls, timeout, sizelimit, deref, &msgid ); if ( rc != LDAP_SUCCESS ) { return( rc ); } rc = ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ); if( rc <= 0 ) { /* error(-1) or timeout(0) */ if ( ld->ld_errno == LDAP_TIMEOUT ) { /* cleanup request */ (void) ldap_abandon( ld, msgid ); ld->ld_errno = LDAP_TIMEOUT; } return( ld->ld_errno ); } if( rc == LDAP_RES_SEARCH_REFERENCE || rc == LDAP_RES_INTERMEDIATE ) { return( ld->ld_errno ); } return( ldap_result2error( ld, *res, 0 ) ); } /* * ldap_search - initiate an ldap search operation. * * Parameters: * * ld LDAP descriptor * base DN of the base object * scope the search scope - one of * LDAP_SCOPE_BASE (baseObject), * LDAP_SCOPE_ONELEVEL (oneLevel), * LDAP_SCOPE_SUBTREE (subtree), or * LDAP_SCOPE_SUBORDINATE (children) -- OpenLDAP extension * filter a string containing the search filter * (e.g., "(|(cn=bob)(sn=bob))") * attrs list of attribute types to return for matches * attrsonly 1 => attributes only 0 => attributes and values * * Example: * char *attrs[] = { "mail", "title", 0 }; * msgid = ldap_search( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob", * attrs, attrsonly ); */ int ldap_search( LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter, char **attrs, int attrsonly ) { BerElement *ber; ber_int_t id; Debug0( LDAP_DEBUG_TRACE, "ldap_search\n" ); assert( ld != NULL ); assert( LDAP_VALID( ld ) ); ber = ldap_build_search_req( ld, base, scope, filter, attrs, attrsonly, NULL, NULL, -1, -1, -1, &id ); if ( ber == NULL ) { return( -1 ); } /* send the message */ return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id )); } BerElement * ldap_build_search_req( LDAP *ld, LDAP_CONST char *base, ber_int_t scope, LDAP_CONST char *filter, char **attrs, ber_int_t attrsonly, LDAPControl **sctrls, LDAPControl **cctrls, ber_int_t timelimit, ber_int_t sizelimit, ber_int_t deref, ber_int_t *idp) { BerElement *ber; int err; /* * Create the search request. It looks like this: * SearchRequest := [APPLICATION 3] SEQUENCE { * baseObject DistinguishedName, * scope ENUMERATED { * baseObject (0), * singleLevel (1), * wholeSubtree (2) * }, * derefAliases ENUMERATED { * neverDerefaliases (0), * derefInSearching (1), * derefFindingBaseObj (2), * alwaysDerefAliases (3) * }, * sizelimit INTEGER (0 .. 65535), * timelimit INTEGER (0 .. 65535), * attrsOnly BOOLEAN, * filter Filter, * attributes SEQUENCE OF AttributeType * } * wrapped in an ldap message. */ /* create a message to send */ if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { return( NULL ); } if ( base == NULL ) { /* no base provided, use session default base */ base = ld->ld_options.ldo_defbase; if ( base == NULL ) { /* no session default base, use top */ base = ""; } } LDAP_NEXT_MSGID( ld, *idp ); #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP(ld) ) { struct sockaddr_storage sa = {0}; /* dummy, filled with ldo_peer in request.c */ err = ber_write( ber, (char *) &sa, sizeof( sa ), 0 ); } if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) { char *dn = ld->ld_options.ldo_cldapdn; if (!dn) dn = ""; err = ber_printf( ber, "{ist{seeiib", *idp, dn, LDAP_REQ_SEARCH, base, (ber_int_t) scope, (deref < 0) ? ld->ld_deref : deref, (sizelimit < 0) ? ld->ld_sizelimit : sizelimit, (timelimit < 0) ? ld->ld_timelimit : timelimit, attrsonly ); } else #endif { err = ber_printf( ber, "{it{seeiib", *idp, LDAP_REQ_SEARCH, base, (ber_int_t) scope, (deref < 0) ? ld->ld_deref : deref, (sizelimit < 0) ? ld->ld_sizelimit : sizelimit, (timelimit < 0) ? ld->ld_timelimit : timelimit, attrsonly ); } if ( err == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } if( filter == NULL ) { filter = "(objectclass=*)"; } err = ldap_pvt_put_filter( ber, filter ); if ( err == -1 ) { ld->ld_errno = LDAP_FILTER_ERROR; ber_free( ber, 1 ); return( NULL ); } #ifdef LDAP_DEBUG if ( ldap_debug & LDAP_DEBUG_ARGS ) { char buf[ BUFSIZ ], *ptr = " *"; if ( attrs != NULL ) { int i, len, rest = sizeof( buf ); for ( i = 0; attrs[ i ] != NULL && rest > 0; i++ ) { ptr = &buf[ sizeof( buf ) - rest ]; len = snprintf( ptr, rest, " %s", attrs[ i ] ); rest -= (len >= 0 ? len : (int) sizeof( buf )); } if ( rest <= 0 ) { AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ], "...(truncated)", STRLENOF( "...(truncated)" ) + 1 ); } ptr = buf; } Debug1( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", ptr ); } #endif /* LDAP_DEBUG */ if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } /* Put Server Controls */ if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return( NULL ); } if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } return( ber ); } int ldap_search_st( LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter, char **attrs, int attrsonly, struct timeval *timeout, LDAPMessage **res ) { int msgid; *res = NULL; if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly )) == -1 ) return( ld->ld_errno ); if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 || !*res ) return( ld->ld_errno ); if ( ld->ld_errno == LDAP_TIMEOUT ) { (void) ldap_abandon( ld, msgid ); ld->ld_errno = LDAP_TIMEOUT; return( ld->ld_errno ); } return( ldap_result2error( ld, *res, 0 ) ); } int ldap_search_s( LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter, char **attrs, int attrsonly, LDAPMessage **res ) { int msgid; *res = NULL; if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly )) == -1 ) return( ld->ld_errno ); if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 || !*res ) return( ld->ld_errno ); return( ldap_result2error( ld, *res, 0 ) ); } static char escape[128] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; #define NEEDFLTESCAPE(c) ((c) & 0x80 || escape[ (unsigned)(c) ]) /* * compute the length of the escaped value */ ber_len_t ldap_bv2escaped_filter_value_len( struct berval *in ) { ber_len_t i, l; assert( in != NULL ); if ( in->bv_len == 0 ) { return 0; } for( l = 0, i = 0; i < in->bv_len; l++, i++ ) { char c = in->bv_val[ i ]; if ( NEEDFLTESCAPE( c ) ) { l += 2; } } return l; } int ldap_bv2escaped_filter_value( struct berval *in, struct berval *out ) { return ldap_bv2escaped_filter_value_x( in, out, 0, NULL ); } int ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx ) { ber_len_t i, l; assert( in != NULL ); assert( out != NULL ); BER_BVZERO( out ); if ( in->bv_len == 0 ) { return 0; } /* assume we'll escape everything */ l = ldap_bv2escaped_filter_value_len( in ); if ( l == in->bv_len ) { if ( inplace ) { *out = *in; } else { ber_dupbv( out, in ); } return 0; } out->bv_val = LDAP_MALLOCX( l + 1, ctx ); if ( out->bv_val == NULL ) { return -1; } for ( i = 0; i < in->bv_len; i++ ) { char c = in->bv_val[ i ]; if ( NEEDFLTESCAPE( c ) ) { assert( out->bv_len < l - 2 ); out->bv_val[out->bv_len++] = '\\'; out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)]; out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c]; } else { assert( out->bv_len < l ); out->bv_val[out->bv_len++] = c; } } out->bv_val[out->bv_len] = '\0'; return 0; } openldap-2.5.11+dfsg/libraries/libldap/apitest.c0000644000175000017500000001466214172327167020250 0ustar ryanryan/* apitest.c -- OpenLDAP API Test Program */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * Portions Copyright 1998-2003 Kurt D. Zeilenga. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This program was originally developed by Kurt D. Zeilenga for inclusion in * OpenLDAP Software. */ #include "portable.h" #include #include #include int main(int argc, char **argv) { LDAPAPIInfo api; int ival; char *sval; printf("Compile time API Information\n"); #ifdef LDAP_API_INFO_VERSION api.ldapai_info_version = LDAP_API_INFO_VERSION; printf(" API Info version: %d\n", (int) api.ldapai_info_version); #else api.ldapai_info_version = 1; printf(" API Info version: unknown\n"); #endif #ifdef LDAP_FEATURE_INFO_VERSION printf(" Feature Info version: %d\n", (int) LDAP_FEATURE_INFO_VERSION); #else printf(" Feature Info version: unknown\n"); api.ldapai_info_version = 1; #endif #ifdef LDAP_API_VERSION printf(" API version: %d\n", (int) LDAP_API_VERSION); #else printf(" API version: unknown\n"); #endif #ifdef LDAP_VERSION printf(" Protocol Version: %d\n", (int) LDAP_VERSION); #else printf(" Protocol Version: unknown\n"); #endif #ifdef LDAP_VERSION_MIN printf(" Protocol Min: %d\n", (int) LDAP_VERSION_MIN); #else printf(" Protocol Min: unknown\n"); #endif #ifdef LDAP_VERSION_MAX printf(" Protocol Max: %d\n", (int) LDAP_VERSION_MAX); #else printf(" Protocol Max: unknown\n"); #endif #ifdef LDAP_VENDOR_NAME printf(" Vendor Name: %s\n", LDAP_VENDOR_NAME); #else printf(" Vendor Name: unknown\n"); #endif #ifdef LDAP_VENDOR_VERSION printf(" Vendor Version: %d\n", (int) LDAP_VENDOR_VERSION); #else printf(" Vendor Version: unknown\n"); #endif if(ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) != LDAP_SUCCESS) { fprintf(stderr, "%s: ldap_get_option(API_INFO) failed\n", argv[0]); return EXIT_FAILURE; } printf("\nExecution time API Information\n"); printf(" API Info version: %d\n", api.ldapai_info_version); if (api.ldapai_info_version != LDAP_API_INFO_VERSION) { printf(" API INFO version mismatch: got %d, expected %d\n", api.ldapai_info_version, LDAP_API_INFO_VERSION); return EXIT_FAILURE; } printf(" API Version: %d\n", api.ldapai_api_version); printf(" Protocol Max: %d\n", api.ldapai_protocol_version); if(api.ldapai_extensions == NULL) { printf(" Extensions: none\n"); } else { int i; for(i=0; api.ldapai_extensions[i] != NULL; i++) /* empty */; printf(" Extensions: %d\n", i); for(i=0; api.ldapai_extensions[i] != NULL; i++) { #ifdef LDAP_OPT_API_FEATURE_INFO LDAPAPIFeatureInfo fi; fi.ldapaif_info_version = LDAP_FEATURE_INFO_VERSION; fi.ldapaif_name = api.ldapai_extensions[i]; fi.ldapaif_version = 0; if( ldap_get_option(NULL, LDAP_OPT_API_FEATURE_INFO, &fi) == LDAP_SUCCESS ) { if(fi.ldapaif_info_version != LDAP_FEATURE_INFO_VERSION) { printf(" %s feature info mismatch: got %d, expected %d\n", api.ldapai_extensions[i], LDAP_FEATURE_INFO_VERSION, fi.ldapaif_info_version); } else { printf(" %s: version %d\n", fi.ldapaif_name, fi.ldapaif_version); } } else { printf(" %s (NO FEATURE INFO)\n", api.ldapai_extensions[i]); } #else printf(" %s\n", api.ldapai_extensions[i]); #endif ldap_memfree(api.ldapai_extensions[i]); } ldap_memfree(api.ldapai_extensions); } printf(" Vendor Name: %s\n", api.ldapai_vendor_name); ldap_memfree(api.ldapai_vendor_name); printf(" Vendor Version: %d\n", api.ldapai_vendor_version); printf("\nExecution time Default Options\n"); if(ldap_get_option(NULL, LDAP_OPT_DEREF, &ival) != LDAP_SUCCESS) { fprintf(stderr, "%s: ldap_get_option(api) failed\n", argv[0]); return EXIT_FAILURE; } printf(" DEREF: %d\n", ival); if(ldap_get_option(NULL, LDAP_OPT_SIZELIMIT, &ival) != LDAP_SUCCESS) { fprintf(stderr, "%s: ldap_get_option(sizelimit) failed\n", argv[0]); return EXIT_FAILURE; } printf(" SIZELIMIT: %d\n", ival); if(ldap_get_option(NULL, LDAP_OPT_TIMELIMIT, &ival) != LDAP_SUCCESS) { fprintf(stderr, "%s: ldap_get_option(timelimit) failed\n", argv[0]); return EXIT_FAILURE; } printf(" TIMELIMIT: %d\n", ival); if(ldap_get_option(NULL, LDAP_OPT_REFERRALS, &ival) != LDAP_SUCCESS) { fprintf(stderr, "%s: ldap_get_option(referrals) failed\n", argv[0]); return EXIT_FAILURE; } printf(" REFERRALS: %s\n", ival ? "on" : "off"); if(ldap_get_option(NULL, LDAP_OPT_RESTART, &ival) != LDAP_SUCCESS) { fprintf(stderr, "%s: ldap_get_option(restart) failed\n", argv[0]); return EXIT_FAILURE; } printf(" RESTART: %s\n", ival ? "on" : "off"); if(ldap_get_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ival) != LDAP_SUCCESS) { fprintf(stderr, "%s: ldap_get_option(protocol version) failed\n", argv[0]); return EXIT_FAILURE; } printf(" PROTOCOL VERSION: %d\n", ival); if(ldap_get_option(NULL, LDAP_OPT_HOST_NAME, &sval) != LDAP_SUCCESS) { fprintf(stderr, "%s: ldap_get_option(host name) failed\n", argv[0]); return EXIT_FAILURE; } if( sval != NULL ) { printf(" HOST NAME: %s\n", sval); ldap_memfree(sval); } else { puts(" HOST NAME: "); } #if 0 /* API tests */ { /* bindless unbind */ LDAP *ld; int rc; ld = ldap_init( "localhost", 389 ); if( ld == NULL ) { perror("ldap_init"); return EXIT_FAILURE; } rc = ldap_unbind( ld ); if( rc != LDAP_SUCCESS ) { perror("ldap_unbind"); return EXIT_FAILURE; } } { /* bindless unbind */ LDAP *ld; int rc; ld = ldap_init( "localhost", 389 ); if( ld == NULL ) { perror("ldap_init"); return EXIT_FAILURE; } rc = ldap_abandon_ext( ld, 0, NULL, NULL ); if( rc != LDAP_SERVER_DOWN ) { ldap_perror( ld, "ldap_abandon"); return EXIT_FAILURE; } rc = ldap_unbind( ld ); if( rc != LDAP_SUCCESS ) { perror("ldap_unbind"); return EXIT_FAILURE; } } #endif return EXIT_SUCCESS; } openldap-2.5.11+dfsg/libraries/libldap/dds.c0000644000175000017500000000575714172327167017356 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2005-2022 The OpenLDAP Foundation. * Portions Copyright 2005-2006 SysNet s.n.c. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This work was developed by Pierangelo Masarati for inclusion * in OpenLDAP Software */ #include "portable.h" #include #include #include #include #include "ldap-int.h" int ldap_parse_refresh( LDAP *ld, LDAPMessage *res, ber_int_t *newttl ) { int rc; struct berval *retdata = NULL; ber_tag_t tag; BerElement *ber; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( res != NULL ); assert( newttl != NULL ); *newttl = 0; rc = ldap_parse_extended_result( ld, res, NULL, &retdata, 0 ); if ( rc != LDAP_SUCCESS ) { return rc; } if ( ld->ld_errno != LDAP_SUCCESS ) { return ld->ld_errno; } if ( retdata == NULL ) { rc = ld->ld_errno = LDAP_DECODING_ERROR; return rc; } ber = ber_init( retdata ); if ( ber == NULL ) { rc = ld->ld_errno = LDAP_NO_MEMORY; goto done; } /* check the tag */ tag = ber_scanf( ber, "{i}", newttl ); ber_free( ber, 1 ); if ( tag != LDAP_TAG_EXOP_REFRESH_RES_TTL ) { *newttl = 0; rc = ld->ld_errno = LDAP_DECODING_ERROR; } done:; if ( retdata ) { ber_bvfree( retdata ); } return rc; } int ldap_refresh( LDAP *ld, struct berval *dn, ber_int_t ttl, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp ) { struct berval bv = { 0, NULL }; BerElement *ber = NULL; int rc; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( dn != NULL ); assert( msgidp != NULL ); *msgidp = -1; ber = ber_alloc_t( LBER_USE_DER ); if ( ber == NULL ) { ld->ld_errno = LDAP_NO_MEMORY; return ld->ld_errno; } ber_printf( ber, "{tOtiN}", LDAP_TAG_EXOP_REFRESH_REQ_DN, dn, LDAP_TAG_EXOP_REFRESH_REQ_TTL, ttl ); rc = ber_flatten2( ber, &bv, 0 ); if ( rc < 0 ) { rc = ld->ld_errno = LDAP_ENCODING_ERROR; goto done; } rc = ldap_extended_operation( ld, LDAP_EXOP_REFRESH, &bv, sctrls, cctrls, msgidp ); done:; ber_free( ber, 1 ); return rc; } int ldap_refresh_s( LDAP *ld, struct berval *dn, ber_int_t ttl, ber_int_t *newttl, LDAPControl **sctrls, LDAPControl **cctrls ) { int rc; int msgid; LDAPMessage *res; rc = ldap_refresh( ld, dn, ttl, sctrls, cctrls, &msgid ); if ( rc != LDAP_SUCCESS ) return rc; rc = ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *)NULL, &res ); if( rc == -1 || !res ) return ld->ld_errno; rc = ldap_parse_refresh( ld, res, newttl ); if( rc != LDAP_SUCCESS ) { ldap_msgfree( res ); return rc; } return ldap_result2error( ld, res, 1 ); } openldap-2.5.11+dfsg/libraries/libldap/string.c0000644000175000017500000000525414172327167020102 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* * Locale-specific 1-byte character versions * See utf-8.c for UTF-8 versions */ #include "portable.h" #include #include #include #include #include "ldap-int.h" #if defined ( HAVE_STRSPN ) #define int_strspn strspn #else static int int_strspn( const char *str, const char *delim ) { int pos; const char *p=delim; for( pos=0; (*str) ; pos++,str++) { if (*str!=*p) { for( p=delim; (*p) ; p++ ) { if (*str==*p) { break; } } } if (*p=='\0') { return pos; } } return pos; } #endif #if defined( HAVE_STRPBRK ) #define int_strpbrk strpbrk #else static char *(int_strpbrk)( const char *str, const char *accept ) { const char *p; for( ; (*str) ; str++ ) { for( p=accept; (*p) ; p++) { if (*str==*p) { return str; } } } return NULL; } #endif char *(ldap_pvt_strtok)( char *str, const char *delim, char **pos ) { char *p; if (pos==NULL) { return NULL; } if (str==NULL) { if (*pos==NULL) { return NULL; } str=*pos; } /* skip any initial delimiters */ str += int_strspn( str, delim ); if (*str == '\0') { return NULL; } p = int_strpbrk( str, delim ); if (p==NULL) { *pos = NULL; } else { *p ='\0'; *pos = p+1; } return str; } char * ldap_pvt_str2upper( char *str ) { char *s; /* to upper */ if ( str ) { for ( s = str; *s; s++ ) { *s = TOUPPER( (unsigned char) *s ); } } return( str ); } struct berval * ldap_pvt_str2upperbv( char *str, struct berval *bv ) { char *s = NULL; assert( bv != NULL ); /* to upper */ if ( str ) { for ( s = str; *s; s++ ) { *s = TOUPPER( (unsigned char) *s ); } } bv->bv_val = str; bv->bv_len = (ber_len_t)(s - str); return( bv ); } char * ldap_pvt_str2lower( char *str ) { char *s; /* to lower */ if ( str ) { for ( s = str; *s; s++ ) { *s = TOLOWER( (unsigned char) *s ); } } return( str ); } struct berval * ldap_pvt_str2lowerbv( char *str, struct berval *bv ) { char *s = NULL; assert( bv != NULL ); /* to lower */ if ( str ) { for ( s = str; *s; s++ ) { *s = TOLOWER( (unsigned char) *s ); } } bv->bv_val = str; bv->bv_len = (ber_len_t)(s - str); return( bv ); } openldap-2.5.11+dfsg/libraries/libldap/fetch.c0000644000175000017500000000553214172327167017664 0ustar ryanryan/* fetch.c - routines for fetching data at URLs */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1999-2022 The OpenLDAP Foundation. * Portions Copyright 1999-2003 Kurt D. Zeilenga. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* This work was initially developed by Kurt D. Zeilenga for * inclusion in OpenLDAP Software. */ #include "portable.h" #include #include #include #include #include #ifdef HAVE_FETCH #include #endif #include "lber_pvt.h" #include "ldap_pvt.h" #include "ldap_config.h" #include "ldif.h" FILE * ldif_open_url( LDAP_CONST char *urlstr ) { FILE *url; if( strncasecmp( "file:", urlstr, sizeof("file:")-1 ) == 0 ) { char *p; urlstr += sizeof("file:")-1; /* we don't check for LDAP_DIRSEP since URLs should contain '/' */ if ( urlstr[0] == '/' && urlstr[1] == '/' ) { urlstr += 2; /* path must be absolute if authority is present * technically, file://hostname/path is also legal but we don't * accept a non-empty hostname */ if ( urlstr[0] != '/' ) { #ifdef _WIN32 /* An absolute path in improper file://C:/foo/bar format */ if ( urlstr[1] != ':' ) #endif return NULL; } #ifdef _WIN32 /* An absolute path in proper file:///C:/foo/bar format */ if ( urlstr[2] == ':' ) urlstr++; #endif } p = ber_strdup( urlstr ); /* But we should convert to LDAP_DIRSEP before use */ if ( LDAP_DIRSEP[0] != '/' ) { char *s = p; while (( s = strchr( s, '/' ))) *s++ = LDAP_DIRSEP[0]; } ldap_pvt_hex_unescape( p ); url = fopen( p, "rb" ); ber_memfree( p ); } else { #ifdef HAVE_FETCH url = fetchGetURL( (char*) urlstr, "" ); #else url = NULL; #endif } return url; } int ldif_fetch_url( LDAP_CONST char *urlstr, char **valuep, ber_len_t *vlenp ) { FILE *url; char buffer[1024]; char *p = NULL; size_t total; size_t bytes; *valuep = NULL; *vlenp = 0; url = ldif_open_url( urlstr ); if( url == NULL ) { return -1; } total = 0; while( (bytes = fread( buffer, 1, sizeof(buffer), url )) != 0 ) { char *newp = ber_memrealloc( p, total + bytes + 1 ); if( newp == NULL ) { ber_memfree( p ); fclose( url ); return -1; } p = newp; AC_MEMCPY( &p[total], buffer, bytes ); total += bytes; } fclose( url ); if( total == 0 ) { char *newp = ber_memrealloc( p, 1 ); if( newp == NULL ) { ber_memfree( p ); return -1; } p = newp; } p[total] = '\0'; *valuep = p; *vlenp = total; return 0; } openldap-2.5.11+dfsg/libraries/libldap/ppolicy.c0000644000175000017500000001650214172327167020251 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2004-2022 The OpenLDAP Foundation. * Portions Copyright 2004 Hewlett-Packard Company. * Portions Copyright 2004 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This work was developed by Howard Chu for inclusion in * OpenLDAP Software, based on prior work by Neil Dunbar (HP). * This work was sponsored by the Hewlett-Packard Company. */ #include "portable.h" #include #include #include #include #include "ldap-int.h" #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST /* IMPLICIT TAGS, all context-specific */ #define PPOLICY_WARNING 0xa0L /* constructed + 0 */ #define PPOLICY_ERROR 0x81L /* primitive + 1 */ #define PPOLICY_EXPIRE 0x80L /* primitive + 0 */ #define PPOLICY_GRACE 0x81L /* primitive + 1 */ /*--- ldap_create_passwordpolicy_control Create and encode the Password Policy Request ld (IN) An LDAP session handle, as obtained from a call to ldap_init(). ctrlp (OUT) A result parameter that will be assigned the address of an LDAPControl structure that contains the passwordPolicyRequest control created by this function. The memory occupied by the LDAPControl structure SHOULD be freed when it is no longer in use by calling ldap_control_free(). There is no control value for a password policy request ---*/ int ldap_create_passwordpolicy_control( LDAP *ld, LDAPControl **ctrlp ) { assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( ctrlp != NULL ); ld->ld_errno = ldap_control_create( LDAP_CONTROL_PASSWORDPOLICYREQUEST, 0, NULL, 0, ctrlp ); return ld->ld_errno; } /*--- ldap_parse_passwordpolicy_control Decode the passwordPolicyResponse control and return information. ld (IN) An LDAP session handle. ctrl (IN) The address of an LDAPControl structure, either obtained by running through the list of response controls or by a call to ldap_control_find(). exptimep (OUT) This result parameter is filled in with the number of seconds before the password will expire, if expiration is imminent (imminency defined by the password policy). If expiration is not imminent, the value is set to -1. gracep (OUT) This result parameter is filled in with the number of grace logins after the password has expired, before no further login attempts will be allowed. errorcodep (OUT) This result parameter is filled in with the error code of the password operation If no error was detected, this error is set to PP_noError. Ber encoding PasswordPolicyResponseValue ::= SEQUENCE { warning [0] CHOICE { timeBeforeExpiration [0] INTEGER (0 .. maxInt), graceLoginsRemaining [1] INTEGER (0 .. maxInt) } OPTIONAL error [1] ENUMERATED { passwordExpired (0), accountLocked (1), changeAfterReset (2), passwordModNotAllowed (3), mustSupplyOldPassword (4), invalidPasswordSyntax (5), passwordTooShort (6), passwordTooYoung (7), passwordInHistory (8) } OPTIONAL } ---*/ int ldap_parse_passwordpolicy_control( LDAP *ld, LDAPControl *ctrl, ber_int_t *expirep, ber_int_t *gracep, LDAPPasswordPolicyError *errorp ) { BerElement *ber; int exp = -1, grace = -1; ber_tag_t tag; ber_len_t berLen; char *last; int err = PP_noError; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( ctrl != NULL ); if ( !ctrl->ldctl_value.bv_val ) { ld->ld_errno = LDAP_DECODING_ERROR; return(ld->ld_errno); } /* Create a BerElement from the berval returned in the control. */ ber = ber_init(&ctrl->ldctl_value); if (ber == NULL) { ld->ld_errno = LDAP_NO_MEMORY; return(ld->ld_errno); } tag = ber_peek_tag( ber, &berLen ); if (tag != LBER_SEQUENCE) goto exit; for( tag = ber_first_element( ber, &berLen, &last ); tag != LBER_DEFAULT; tag = ber_next_element( ber, &berLen, last ) ) { switch (tag) { case PPOLICY_WARNING: ber_skip_tag(ber, &berLen ); tag = ber_peek_tag( ber, &berLen ); switch( tag ) { case PPOLICY_EXPIRE: if (ber_get_int( ber, &exp ) == LBER_DEFAULT) goto exit; break; case PPOLICY_GRACE: if (ber_get_int( ber, &grace ) == LBER_DEFAULT) goto exit; break; default: goto exit; } break; case PPOLICY_ERROR: if (ber_get_enum( ber, &err ) == LBER_DEFAULT) goto exit; break; default: goto exit; } } ber_free(ber, 1); /* Return data to the caller for items that were requested. */ if (expirep) *expirep = exp; if (gracep) *gracep = grace; if (errorp) *errorp = err; ld->ld_errno = LDAP_SUCCESS; return(ld->ld_errno); exit: ber_free(ber, 1); ld->ld_errno = LDAP_DECODING_ERROR; return(ld->ld_errno); } const char * ldap_passwordpolicy_err2txt( LDAPPasswordPolicyError err ) { switch(err) { case PP_passwordExpired: return "Password expired"; case PP_accountLocked: return "Account locked"; case PP_changeAfterReset: return "Password must be changed"; case PP_passwordModNotAllowed: return "Policy prevents password modification"; case PP_mustSupplyOldPassword: return "Policy requires old password in order to change password"; case PP_insufficientPasswordQuality: return "Password fails quality checks"; case PP_passwordTooShort: return "Password is too short for policy"; case PP_passwordTooYoung: return "Password has been changed too recently"; case PP_passwordInHistory: return "New password is in list of old passwords"; case PP_passwordTooLong: return "Password is too long for policy"; case PP_noError: return "No error"; default: return "Unknown error code"; } } #endif /* LDAP_CONTROL_PASSWORDPOLICYREQUEST */ #ifdef LDAP_CONTROL_X_PASSWORD_EXPIRING int ldap_parse_password_expiring_control( LDAP *ld, LDAPControl *ctrl, long *secondsp ) { long seconds = 0; char buf[sizeof("-2147483648")]; char *next; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( ctrl != NULL ); if ( BER_BVISEMPTY( &ctrl->ldctl_value ) || ctrl->ldctl_value.bv_len >= sizeof(buf) ) { ld->ld_errno = LDAP_DECODING_ERROR; return(ld->ld_errno); } memcpy( buf, ctrl->ldctl_value.bv_val, ctrl->ldctl_value.bv_len ); buf[ctrl->ldctl_value.bv_len] = '\0'; seconds = strtol( buf, &next, 10 ); if ( next == buf || next[0] != '\0' ) goto exit; if ( secondsp != NULL ) { *secondsp = seconds; } ld->ld_errno = LDAP_SUCCESS; return(ld->ld_errno); exit: ld->ld_errno = LDAP_DECODING_ERROR; return(ld->ld_errno); } #endif /* LDAP_CONTROL_X_PASSWORD_EXPIRING */ openldap-2.5.11+dfsg/libraries/libldap/whoami.c0000644000175000017500000000404114172327167020051 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This program was originally developed by Kurt D. Zeilenga for inclusion in * OpenLDAP Software. */ #include "portable.h" #include #include #include #include #include "ldap-int.h" /* * LDAP Who Am I? (Extended) Operation */ int ldap_parse_whoami( LDAP *ld, LDAPMessage *res, struct berval **authzid ) { int rc; char *retoid = NULL; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( res != NULL ); assert( authzid != NULL ); *authzid = NULL; rc = ldap_parse_extended_result( ld, res, &retoid, authzid, 0 ); if( rc != LDAP_SUCCESS ) { ldap_perror( ld, "ldap_parse_whoami" ); return rc; } ber_memfree( retoid ); return rc; } int ldap_whoami( LDAP *ld, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp ) { int rc; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( msgidp != NULL ); rc = ldap_extended_operation( ld, LDAP_EXOP_WHO_AM_I, NULL, sctrls, cctrls, msgidp ); return rc; } int ldap_whoami_s( LDAP *ld, struct berval **authzid, LDAPControl **sctrls, LDAPControl **cctrls ) { int rc; int msgid; LDAPMessage *res; rc = ldap_whoami( ld, sctrls, cctrls, &msgid ); if ( rc != LDAP_SUCCESS ) return rc; if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, &res ) == -1 || !res ) { return ld->ld_errno; } rc = ldap_parse_whoami( ld, res, authzid ); if( rc != LDAP_SUCCESS ) { ldap_msgfree( res ); return rc; } return( ldap_result2error( ld, res, 1 ) ); } openldap-2.5.11+dfsg/libraries/libldap/delete.c0000644000175000017500000000676714172327167020050 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1990 Regents of the University of Michigan. * All rights reserved. */ #include "portable.h" #include #include #include #include #include "ldap-int.h" /* * A delete request looks like this: * DelRequest ::= DistinguishedName, */ BerElement * ldap_build_delete_req( LDAP *ld, LDAP_CONST char *dn, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp ) { BerElement *ber; int rc; /* create a message to send */ if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { return( NULL ); } LDAP_NEXT_MSGID( ld, *msgidp ); rc = ber_printf( ber, "{its", /* '}' */ *msgidp, LDAP_REQ_DELETE, dn ); if ( rc == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } /* Put Server Controls */ if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { ber_free( ber, 1 ); return( NULL ); } if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { ld->ld_errno = LDAP_ENCODING_ERROR; ber_free( ber, 1 ); return( NULL ); } return( ber ); } /* * ldap_delete_ext - initiate an ldap extended delete operation. Parameters: * * ld LDAP descriptor * dn DN of the object to delete * sctrls Server Controls * cctrls Client Controls * msgidp Message Id Pointer * * Example: * rc = ldap_delete( ld, dn, sctrls, cctrls, msgidp ); */ int ldap_delete_ext( LDAP *ld, LDAP_CONST char* dn, LDAPControl **sctrls, LDAPControl **cctrls, int *msgidp ) { int rc; BerElement *ber; ber_int_t id; Debug0( LDAP_DEBUG_TRACE, "ldap_delete_ext\n" ); assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( dn != NULL ); assert( msgidp != NULL ); /* check client controls */ rc = ldap_int_client_controls( ld, cctrls ); if( rc != LDAP_SUCCESS ) return rc; ber = ldap_build_delete_req( ld, dn, sctrls, cctrls, &id ); if( !ber ) return ld->ld_errno; /* send the message */ *msgidp = ldap_send_initial_request( ld, LDAP_REQ_DELETE, dn, ber, id ); if(*msgidp < 0) return ld->ld_errno; return LDAP_SUCCESS; } int ldap_delete_ext_s( LDAP *ld, LDAP_CONST char *dn, LDAPControl **sctrls, LDAPControl **cctrls ) { int msgid; int rc; LDAPMessage *res; rc = ldap_delete_ext( ld, dn, sctrls, cctrls, &msgid ); if( rc != LDAP_SUCCESS ) return( ld->ld_errno ); if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, &res ) == -1 || !res ) return( ld->ld_errno ); return( ldap_result2error( ld, res, 1 ) ); } /* * ldap_delete - initiate an ldap (and X.500) delete operation. Parameters: * * ld LDAP descriptor * dn DN of the object to delete * * Example: * msgid = ldap_delete( ld, dn ); */ int ldap_delete( LDAP *ld, LDAP_CONST char *dn ) { int msgid; /* * A delete request looks like this: * DelRequest ::= DistinguishedName, */ Debug0( LDAP_DEBUG_TRACE, "ldap_delete\n" ); return ldap_delete_ext( ld, dn, NULL, NULL, &msgid ) == LDAP_SUCCESS ? msgid : -1 ; } int ldap_delete_s( LDAP *ld, LDAP_CONST char *dn ) { return ldap_delete_ext_s( ld, dn, NULL, NULL ); } openldap-2.5.11+dfsg/libraries/liblunicode/0000755000175000017500000000000014172327167017304 5ustar ryanryanopenldap-2.5.11+dfsg/libraries/liblunicode/ucdata/0000755000175000017500000000000014172327167020545 5ustar ryanryanopenldap-2.5.11+dfsg/libraries/liblunicode/ucdata/ucpgba.h0000644000175000017500000001356214172327167022166 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Copyright 1999 Computing Research Labs, New Mexico State University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* $Id: ucpgba.h,v 1.4 1999/11/19 15:24:30 mleisher Exp $ */ #ifndef _h_ucpgba #define _h_ucpgba #include "portable.h" LDAP_BEGIN_DECL /*************************************************************************** * * Macros and types. * ***************************************************************************/ /* * These are the direction values that can appear in render runs and render * strings. */ #define UCPGBA_LTR 0 #define UCPGBA_RTL 1 /* * These are the flags for cursor motion. */ #define UCPGBA_CURSOR_VISUAL 0 #define UCPGBA_CURSOR_LOGICAL 1 /* * This structure is used to contain runs of text in a particular direction. */ typedef struct _ucrun_t { struct _ucrun_t *visual_prev; /* Pointer to the previous visual run. */ struct _ucrun_t *visual_next; /* Pointer to the next visual run. */ struct _ucrun_t *logical_prev; /* Pointer to the previous logical run. */ struct _ucrun_t *logical_next; /* Pointer to the next logical run. */ int direction; /* Direction of the run. */ long cursor; /* Position of "cursor" in the string. */ unsigned long *chars; /* List of characters for the run. */ unsigned long *positions; /* List of original positions in source. */ unsigned long *source; /* The source string. */ unsigned long start; /* Beginning offset in the source string. */ unsigned long end; /* Ending offset in the source string. */ } ucrun_t; /* * This represents a string of runs rendered up to a point that is not * platform specific. */ typedef struct _ucstring_t { int direction; /* Overall direction of the string. */ int cursor_motion; /* Logical or visual cursor motion flag. */ ucrun_t *cursor; /* The run containing the "cursor." */ ucrun_t *logical_first; /* First run in the logical order. */ ucrun_t *logical_last; /* Last run in the logical order. */ ucrun_t *visual_first; /* First run in the visual order. */ ucrun_t *visual_last; /* Last run in the visual order. */ unsigned long *source; /* The source string. */ unsigned long start; /* The beginning offset in the source. */ unsigned long end; /* The ending offset in the source. */ } ucstring_t; /*************************************************************************** * * API * ***************************************************************************/ /* * This creates and reorders the specified substring using the * "Pretty Good Bidi Algorithm." A default direction is provided for cases * of a string containing no strong direction characters and the default * cursor motion should be provided. */ LDAP_LUNICODE_F (ucstring_t *) ucstring_create LDAP_P((unsigned long *source, unsigned long start, unsigned long end, int default_direction, int cursor_motion)); /* * This releases the string. */ LDAP_LUNICODE_F (void) ucstring_free LDAP_P((ucstring_t *string)); /* * This changes the cursor motion flag for the string. */ LDAP_LUNICODE_F (int) ucstring_set_cursor_motion LDAP_P((ucstring_t *string, int cursor_motion)); /* * This function will move the cursor to the right depending on the * type of cursor motion that was specified for the string. * * A 0 is returned if no cursor motion is performed, otherwise a * 1 is returned. */ LDAP_LUNICODE_F (int) ucstring_cursor_right LDAP_P((ucstring_t *string, int count)); /* * This function will move the cursor to the left depending on the * type of cursor motion that was specified for the string. * * A 0 is returned if no cursor motion is performed, otherwise a * 1 is returned. */ LDAP_LUNICODE_F (int) ucstring_cursor_left LDAP_P((ucstring_t *string, int count)); /* * This routine retrieves the direction of the run containing the cursor * and the actual position in the original text string. */ LDAP_LUNICODE_F (void) ucstring_cursor_info LDAP_P((ucstring_t *string, int *direction, unsigned long *position)); LDAP_END_DECL #endif /* _h_ucpgba */ openldap-2.5.11+dfsg/libraries/liblunicode/ucdata/ucdata.man0000644000175000017500000002774314172327167022520 0ustar ryanryan.\" .\" $Id: ucdata.man,v 1.5 2001/01/02 18:46:20 mleisher Exp $ .\" .TH ucdata 3 "03 January 2001" .SH NAME ucdata \- package for providing Unicode/ISO10646 character information .SH SYNOPSIS #include .sp void ucdata_load(char * paths, int masks) .sp void ucdata_unload(int masks) .sp void ucdata_reload(char * paths, int masks) .sp int ucdecomp(unsigned long code, unsigned long *num, unsigned long **decomp) .sp int uccanondecomp(const unsigned long *in, int inlen, unsigned long **out, int *outlen) .sp int ucdecomp_hangul(unsigned long code, unsigned long *num, unsigned long decomp[]) .sp int uccomp(unsigned long ch1, unsigned long ch2, unsigned long *comp) .sp int uccomp_hangul(unsigned long *str, int len) .sp int uccanoncomp(unsigned long *str, int len) .nf struct ucnumber { int numerator; int denominator; }; .sp int ucnumber_lookup(unsigned long code, struct ucnumber *num) .sp int ucdigit_lookup(unsigned long code, int *digit) .sp struct ucnumber ucgetnumber(unsigned long code) .sp int ucgetdigit(unsigned long code) .sp unsigned long uctoupper(unsigned long code) .sp unsigned long uctolower(unsigned long code) .sp unsigned long uctotitle(unsigned long code) .sp int ucisalpha(unsigned long code) .sp int ucisalnum(unsigned long code) .sp int ucisdigit(unsigned long code) .sp int uciscntrl(unsigned long code) .sp int ucisspace(unsigned long code) .sp int ucisblank(unsigned long code) .sp int ucispunct(unsigned long code) .sp int ucisgraph(unsigned long code) .sp int ucisprint(unsigned long code) .sp int ucisxdigit(unsigned long code) .sp int ucisupper(unsigned long code) .sp int ucislower(unsigned long code) .sp int ucistitle(unsigned long code) .sp int ucisisocntrl(unsigned long code) .sp int ucisfmtcntrl(unsigned long code) .sp int ucissymbol(unsigned long code) .sp int ucisnumber(unsigned long code) .sp int ucisnonspacing(unsigned long code) .sp int ucisopenpunct(unsigned long code) .sp int ucisclosepunct(unsigned long code) .sp int ucisinitialpunct(unsigned long code) .sp int ucisfinalpunct(unsigned long code) .sp int uciscomposite(unsigned long code) .sp int ucisquote(unsigned long code) .sp int ucissymmetric(unsigned long code) .sp int ucismirroring(unsigned long code) .sp int ucisnonbreaking(unsigned long code) .sp int ucisrtl(unsigned long code) .sp int ucisltr(unsigned long code) .sp int ucisstrong(unsigned long code) .sp int ucisweak(unsigned long code) .sp int ucisneutral(unsigned long code) .sp int ucisseparator(unsigned long code) .sp int ucislsep(unsigned long code) .sp int ucispsep(unsigned long code) .sp int ucismark(unsigned long code) .sp int ucisnsmark(unsigned long code) .sp int ucisspmark(unsigned long code) .sp int ucismodif(unsigned long code) .sp int ucismodifsymbol(unsigned long code) .sp int ucisletnum(unsigned long code) .sp int ucisconnect(unsigned long code) .sp int ucisdash(unsigned long code) .sp int ucismath(unsigned long code) .sp int uciscurrency(unsigned long code) .sp int ucisenclosing(unsigned long code) .sp int ucisprivate(unsigned long code) .sp int ucissurrogate(unsigned long code) .sp int ucisidentstart(unsigned long code) .sp int ucisidentpart(unsigned long code) .sp int ucisdefined(unsigned long code) .sp int ucisundefined(unsigned long code) .sp int ucishan(unsigned long code) .sp int ucishangul(unsigned long code) .SH DESCRIPTION .TP 4 .BR Macros .br UCDATA_CASE .br UCDATA_CTYPE .br UCDATA_DECOMP .br UCDATA_CMBCL .br UCDATA_NUM .br UCDATA_ALL .br .TP 4 .BR ucdata_load() This function initializes the UCData library by locating the data files in one of the colon-separated directories in the `paths' parameter. The data files to be loaded are specified in the `masks' parameter as a bitwise combination of the macros listed above. .sp This should be called before using any of the other functions. .TP 4 .BR ucdata_unload() This function unloads the data tables specified in the `masks' parameter. .sp This function should be called when the application is done using the UCData package. .TP 4 .BR ucdata_reload() This function reloads the data files from one of the colon-separated directories in the `paths' parameter. The data files to be reloaded are specified in the `masks' parameter as a bitwise combination of the macros listed above. .TP 4 .BR ucdecomp() This function determines if a character has a decomposition and returns the decomposition information if it exists. .sp If a zero is returned, there is no decomposition. If a non-zero is returned, then the `num' and `decomp' variables are filled in with the appropriate values. .sp Example call: .sp .nf unsigned long i, num, *decomp; if (ucdecomp(0x1d5, &num, &decomp) != 0) { for (i = 0; i < num; i++) printf("0x%08lX,", decomp[i]); putchar('\n'); } .TP 4 .BR uccanondecomp() This function will decompose a string, insuring the characters are in canonical order for comparison. .sp If a decomposed string is returned, the caller is responsible for deallocating the string. .sp If a -1 is returned, memory allocation failed. If a zero is returned, no decomposition was done. Any other value means a decomposition string was created and the values returned in the `out' and `outlen' parameters. .TP 4 .BR ucdecomp_hangul() This function determines if a Hangul syllable has a decomposition and returns the decomposition information. .sp An array of at least size 3 should be passed to the function for the decomposition of the syllable. .sp If a zero is returned, the character is not a Hangul syllable. If a non-zero is returned, the `num' field will be 2 or 3 and the syllable will be decomposed into the `decomp' array arithmetically. .sp Example call: .sp .nf unsigned long i, num, decomp[3]; if (ucdecomp_hangul(0xb1ba, &num, &decomp) != 0) { for (i = 0; i < num; i++) printf("0x%08lX,", decomp[i]); putchar('\n'); } .TP 4 .BR uccomp() This function determines if a pair of characters have a composition, and returns that composition if one exists. .sp A zero is returned is no composition exists for the character pair. Any other value indicates the `comp' field holds the character code representing the composition of the two character codes. .TP 4 .BR uccomp_hangul() This composes the Hangul Jamo in-place in the string. .sp The returned value is the new length of the string. .TP 4 .BR uccanoncomp() This function does a full composition in-place in the string, including the Hangul composition. .sp The returned value is the new length of the string. .TP 4 .BR ucnumber_lookup() This function determines if the code is a number and fills in the `num' field with the numerator and denominator. If the code happens to be a single digit, the numerator and denominator fields will be the same. .sp If the function returns 0, the code is not a number. Any other return value means the code is a number. .TP 4 .BR ucdigit_lookup() This function determines if the code is a digit and fills in the `digit' field with the digit value. .sp If the function returns 0, the code is not a number. Any other return value means the code is a number. .TP 4 .BR ucgetnumber() This is a compatibility function with John Cowan's "uctype" package. It uses ucnumber_lookup(). .TP 4 .BR ucgetdigit() This is a compatibility function with John Cowan's "uctype" package. It uses ucdigit_lookup(). .TP 4 .BR uctoupper() This function returns the code unchanged if it is already upper case or has no upper case equivalent. Otherwise the upper case equivalent is returned. .TP 4 .BR uctolower() This function returns the code unchanged if it is already lower case or has no lower case equivalent. Otherwise the lower case equivalent is returned. .TP 4 .BR uctotitle() This function returns the code unchanged if it is already title case or has no title case equivalent. Otherwise the title case equivalent is returned. .TP 4 .BR ucisalpha() Test if \fIcode\fR is an alpha character. .TP 4 .BR ucisalnum() Test if \fIcode\fR is an alpha or digit character. .TP 4 .BR ucisdigit() Test if \fIcode\fR is a digit character. .TP 4 .BR uciscntrl() Test if \fIcode\fR is a control character. .TP 4 .BR ucisspace() Test if \fIcode\fR is a space character. .TP 4 .BR ucisblank() Test if \fIcode\fR is a blank character. .TP 4 .BR ucispunct() Test if \fIcode\fR is a punctuation character. .TP 4 .BR ucisgraph() Test if \fIcode\fR is a graphical (visible) character. .TP 4 .BR ucisprint() Test if \fIcode\fR is a printable character. .TP 4 .BR ucisxdigit() Test if \fIcode\fR is a hexadecimal digit character. .TP 4 .BR ucisupper() Test if \fIcode\fR is an upper case character. .TP 4 .BR ucislower() Test if \fIcode\fR is a lower case character. .TP 4 .BR ucistitle() Test if \fIcode\fR is a title case character. .TP 4 .BR ucisisocntrl() Is the character a C0 control character (< 32)? .TP 4 .BR ucisfmtcntrl() Is the character a format control character? .TP 4 .BR ucissymbol() Is the character a symbol? .TP 4 .BR ucisnumber() Is the character a number or digit? .TP 4 .BR ucisnonspacing() Is the character non-spacing? .TP 4 .BR ucisopenpunct() Is the character an open/left punctuation (i.e. '[') .TP 4 .BR ucisclosepunct() Is the character an close/right punctuation (i.e. ']') .TP 4 .BR ucisinitialpunct() Is the character an initial punctuation (i.e. U+2018 LEFT SINGLE QUOTATION MARK) .TP 4 .BR ucisfinalpunct() Is the character a final punctuation (i.e. U+2019 RIGHT SINGLE QUOTATION MARK) .TP 4 .BR uciscomposite() Can the character be decomposed into a set of other characters? .TP 4 .BR ucisquote() Is the character one of the many quotation marks? .TP 4 .BR ucissymmetric() Is the character one that has an opposite form (i.e. <>) .TP 4 .BR ucismirroring() Is the character mirroring (superset of symmetric)? .TP 4 .BR ucisnonbreaking() Is the character non-breaking (i.e. non-breaking space)? .TP 4 .BR ucisrtl() Does the character have strong right-to-left directionality (i.e. Arabic letters)? .TP 4 .BR ucisltr() Does the character have strong left-to-right directionality (i.e. Latin letters)? .TP 4 .BR ucisstrong() Does the character have strong directionality? .TP 4 .BR ucisweak() Does the character have weak directionality (i.e. numbers)? .TP 4 .BR ucisneutral() Does the character have neutral directionality (i.e. whitespace)? .TP 4 .BR ucisseparator() Is the character a block or segment separator? .TP 4 .BR ucislsep() Is the character a line separator? .TP 4 .BR ucispsep() Is the character a paragraph separator? .TP 4 .BR ucismark() Is the character a mark of some kind? .TP 4 .BR ucisnsmark() Is the character a non-spacing mark? .TP 4 .BR ucisspmark() Is the character a spacing mark? .TP 4 .BR ucismodif() Is the character a modifier letter? .TP 4 .BR ucismodifsymbol() Is the character a modifier symbol? .TP 4 .BR ucisletnum() Is the character a number represented by a letter? .TP 4 .BR ucisconnect() Is the character connecting punctuation? .TP 4 .BR ucisdash() Is the character dash punctuation? .TP 4 .BR ucismath() Is the character a math character? .TP 4 .BR uciscurrency() Is the character a currency character? .TP 4 .BR ucisenclosing() Is the character enclosing (i.e. enclosing box)? .TP 4 .BR ucisprivate() Is the character from the Private Use Area? .TP 4 .BR ucissurrogate() Is the character one of the surrogate codes? .TP 4 .BR ucisidentstart() Is the character a legal initial character of an identifier? .TP 4 .BR ucisidentpart() Is the character a legal identifier character? .TP 4 .BR ucisdefined() Is the character defined (appeared in one of the data files)? .TP 4 .BR ucisundefined() Is the character not defined (non-Unicode)? .TP 4 .BR ucishan() Is the character a Han ideograph? .TP 4 .BR ucishangul() Is the character a pre-composed Hangul syllable? .SH "SEE ALSO" ctype(3) .SH ACKNOWLEDGMENTS These are people who have helped with patches or alerted me about problems. .sp John Cowan .br Bob Verbrugge .br Christophe Pierret .br Kent Johnson .br Valeriy E. Ushakov .br Stig Venaas .SH AUTHOR Mark Leisher .br Computing Research Lab .br New Mexico State University .br Email: mleisher@crl.nmsu.edu openldap-2.5.11+dfsg/libraries/liblunicode/ucdata/api.txt0000644000175000017500000002723314172327167022066 0ustar ryanryan# # $Id: api.txt,v 1.3 2001/01/02 18:46:20 mleisher Exp $ # The MUTT UCData API ------------------- #### NOTE: This library has been customized for use with OpenLDAP. The character data tables are hardcoded into the library and the load/unload/reload functions are no-ops. Also, the MUTT API claimed to be compatible with John Cowan's library but its ucnumber behavior was broken. This has been fixed in the OpenLDAP release. By default, the implementation specific properties in MUTTUCData.txt are not incorporated into the OpenLDAP build. You can supply them to ucgendat and recreate uctable.h if you need them. -- hyc@openldap.org #### ----------------------------------------------------------------------------- Macros that combine to select data tables for ucdata_load(), ucdata_unload(), and ucdata_reload(). #define UCDATA_CASE 0x01 #define UCDATA_CTYPE 0x02 #define UCDATA_DECOMP 0x04 #define UCDATA_CMBCL 0x08 #define UCDATA_NUM 0x10 #define UCDATA_COMP 0x20 #define UCATA_ALL (UCDATA_CASE|UCDATA_CTYPE|UCDATA_DECOMP|\ UCDATA_CMBCL|UCDATA_NUM|UCDATA_COMP) ----------------------------------------------------------------------------- void ucdata_load(char *paths, int masks) This function initializes the UCData library by locating the data files in one of the colon-separated directories in the `paths' parameter. The data files to be loaded are specified in the `masks' parameter as a bitwise combination of the macros listed above. This should be called before using any of the other functions. NOTE: the ucdata_setup(char *paths) function is now a macro that expands into this function at compile time. ----------------------------------------------------------------------------- void ucdata_unload(int masks) This function unloads the data tables specified in the `masks' parameter. This function should be called when the application is done using the UCData package. NOTE: the ucdata_cleanup() function is now a macro that expands into this function at compile time. ----------------------------------------------------------------------------- void ucdata_reload(char *paths, int masks) This function reloads the data files from one of the colon-separated directories in the `paths' parameter. The data files to be reloaded are specified in the `masks' parameter as a bitwise combination of the macros listed above. If the data files have already been loaded, they are unloaded before the data files are loaded again. ----------------------------------------------------------------------------- int ucdecomp(unsigned long code, unsigned long *num, unsigned long **decomp) This function determines if a character has a decomposition and returns the decomposition information if it exists. If a zero is returned, there is no decomposition. If a non-zero is returned, then the `num' and `decomp' variables are filled in with the appropriate values. Example call: unsigned long i, num, *decomp; if (ucdecomp(0x1d5, &num, &decomp) != 0) { for (i = 0; i < num; i++) printf("0x%08lX,", decomp[i]); putchar('\n'); } int uccanondecomp(const unsigned long *in, int inlen, unsigned long **out, int *outlen) This function decomposes an input string and does canonical reordering of the characters at the same time. If a -1 is returned, memory allocation was not successful. If a zero is returned, no decomposition occurred. Any other value means the output string contains the fully decomposed string in canonical order. If the "outlen" parameter comes back with a value > 0, then the string returned in the "out" parameter needs to be deallocated by the caller. ----------------------------------------------------------------------------- int ucdecomp_hangul(unsigned long code, unsigned long *num, unsigned long decomp[]) This function determines if a Hangul syllable has a decomposition and returns the decomposition information. An array of at least size 3 should be passed to the function for the decomposition of the syllable. If a zero is returned, the character is not a Hangul syllable. If a non-zero is returned, the `num' field will be 2 or 3 and the syllable will be decomposed into the `decomp' array arithmetically. Example call: unsigned long i, num, decomp[3]; if (ucdecomp_hangul(0xb1ba, &num, &decomp) != 0) { for (i = 0; i < num; i++) printf("0x%08lX,", decomp[i]); putchar('\n'); } ----------------------------------------------------------------------------- int uccomp(unsigned long ch1, unsigned long ch2, unsigned long *comp) This function takes a pair of characters and determines if they combine to form another character. If a zero is returned, no composition is formed by the character pair. Any other value indicates the "comp" parameter has a value. int uccomp_hangul(unsigned long *str, int len) This function composes the Hangul Jamo in the string. The composition is done in-place. The return value provides the new length of the string. This will be smaller than "len" if compositions occurred. int uccanoncomp(unsigned long *str, int len) This function does a canonical composition of characters in the string. The return value is the new length of the string. ----------------------------------------------------------------------------- struct ucnumber { int numerator; int denominator; }; int ucnumber_lookup(unsigned long code, struct ucnumber *num) This function determines if the code is a number and fills in the `num' field with the numerator and denominator. If the code happens to be a single digit, the denominator field will be 1. #### The original code would set numerator = denominator for regular digits. However, the Readme also claimed to be compatible with John Cowan's uctype library, but this behavior is both nonsensical and incompatible with the Cowan library. As such, it has been fixed here as described above. -- hyc@openldap.org #### If the function returns 0, the code is not a number. Any other return value means the code is a number. int ucdigit_lookup(unsigned long code, int *digit) This function determines if the code is a digit and fills in the `digit' field with the digit value. If the function returns 0, the code is not a number. Any other return value means the code is a number. struct ucnumber ucgetnumber(unsigned long code) This is a compatibility function with John Cowan's "uctype" package. It uses ucnumber_lookup(). int ucgetdigit(unsigned long code) This is a compatibility function with John Cowan's "uctype" package. It uses ucdigit_lookup(). ----------------------------------------------------------------------------- unsigned long uctoupper(unsigned long code) This function returns the code unchanged if it is already upper case or has no upper case equivalent. Otherwise the upper case equivalent is returned. ----------------------------------------------------------------------------- unsigned long uctolower(unsigned long code) This function returns the code unchanged if it is already lower case or has no lower case equivalent. Otherwise the lower case equivalent is returned. ----------------------------------------------------------------------------- unsigned long uctotitle(unsigned long code) This function returns the code unchanged if it is already title case or has no title case equivalent. Otherwise the title case equivalent is returned. ----------------------------------------------------------------------------- int ucisalpha(unsigned long code) int ucisalnum(unsigned long code) int ucisdigit(unsigned long code) int uciscntrl(unsigned long code) int ucisspace(unsigned long code) int ucisblank(unsigned long code) int ucispunct(unsigned long code) int ucisgraph(unsigned long code) int ucisprint(unsigned long code) int ucisxdigit(unsigned long code) int ucisupper(unsigned long code) int ucislower(unsigned long code) int ucistitle(unsigned long code) These functions (actually macros) determine if a character has these properties. These behave in a fashion very similar to the venerable ctype package. ----------------------------------------------------------------------------- int ucisisocntrl(unsigned long code) Is the character a C0 control character (< 32) ? int ucisfmtcntrl(unsigned long code) Is the character a format control character? int ucissymbol(unsigned long code) Is the character a symbol? int ucisnumber(unsigned long code) Is the character a number or digit? int ucisnonspacing(unsigned long code) Is the character non-spacing? int ucisopenpunct(unsigned long code) Is the character an open/left punctuation (i.e. '[') int ucisclosepunct(unsigned long code) Is the character an close/right punctuation (i.e. ']') int ucisinitialpunct(unsigned long code) Is the character an initial punctuation (i.e. U+2018 LEFT SINGLE QUOTATION MARK) int ucisfinalpunct(unsigned long code) Is the character a final punctuation (i.e. U+2019 RIGHT SINGLE QUOTATION MARK) int uciscomposite(unsigned long code) Can the character be decomposed into a set of other characters? int ucisquote(unsigned long code) Is the character one of the many quotation marks? int ucissymmetric(unsigned long code) Is the character one that has an opposite form (i.e. <>) int ucismirroring(unsigned long code) Is the character mirroring (superset of symmetric)? int ucisnonbreaking(unsigned long code) Is the character non-breaking (i.e. non-breaking space)? int ucisrtl(unsigned long code) Does the character have strong right-to-left directionality (i.e. Arabic letters)? int ucisltr(unsigned long code) Does the character have strong left-to-right directionality (i.e. Latin letters)? int ucisstrong(unsigned long code) Does the character have strong directionality? int ucisweak(unsigned long code) Does the character have weak directionality (i.e. numbers)? int ucisneutral(unsigned long code) Does the character have neutral directionality (i.e. whitespace)? int ucisseparator(unsigned long code) Is the character a block or segment separator? int ucislsep(unsigned long code) Is the character a line separator? int ucispsep(unsigned long code) Is the character a paragraph separator? int ucismark(unsigned long code) Is the character a mark of some kind? int ucisnsmark(unsigned long code) Is the character a non-spacing mark? int ucisspmark(unsigned long code) Is the character a spacing mark? int ucismodif(unsigned long code) Is the character a modifier letter? int ucismodifsymbol(unsigned long code) Is the character a modifier symbol? int ucisletnum(unsigned long code) Is the character a number represented by a letter? int ucisconnect(unsigned long code) Is the character connecting punctuation? int ucisdash(unsigned long code) Is the character dash punctuation? int ucismath(unsigned long code) Is the character a math character? int uciscurrency(unsigned long code) Is the character a currency character? int ucisenclosing(unsigned long code) Is the character enclosing (i.e. enclosing box)? int ucisprivate(unsigned long code) Is the character from the Private Use Area? int ucissurrogate(unsigned long code) Is the character one of the surrogate codes? int ucisdefined(unsigned long code) Is the character defined (appeared in one of the data files)? int ucisundefined(unsigned long code) Is the character not defined (non-Unicode)? int ucishan(unsigned long code) Is the character a Han ideograph? int ucishangul(unsigned long code) Is the character a pre-composed Hangul syllable? openldap-2.5.11+dfsg/libraries/liblunicode/ucdata/uctable.h0000644000175000017500000175012414172333437022344 0ustar ryanryanstatic const ac_uint4 _ucprop_size = 50; static const ac_uint2 _ucprop_offsets[] = { 0x0000, 0x00d0, 0x0138, 0x0140, 0x016a, 0x0176, 0x019e, 0x01ac, 0x01ae, 0x01b0, 0x01b4, 0x01cc, 0x01ce, 0xffff, 0x01d4, 0x051a, 0x0862, 0x0876, 0x089e, 0x0a32, 0x0a40, 0x0a58, 0x0ad8, 0x0b54, 0x0be0, 0x0c54, 0x0c6a, 0x0c96, 0x0d66, 0x0fee, 0x100a, 0x1020, 0x1024, 0x1054, 0x1058, 0x106e, 0x1078, 0x107e, 0x108e, 0x1240, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x13e8, 0x16e4, 0x16ee, 0x16f6, 0x1720, 0x0000 }; static const ac_uint4 _ucprop_ranges[] = { 0x00000300, 0x0000034f, 0x00000360, 0x0000036f, 0x00000483, 0x00000486, 0x00000591, 0x000005a1, 0x000005a3, 0x000005b9, 0x000005bb, 0x000005bd, 0x000005bf, 0x000005bf, 0x000005c1, 0x000005c2, 0x000005c4, 0x000005c4, 0x0000064b, 0x00000655, 0x00000670, 0x00000670, 0x000006d6, 0x000006dc, 0x000006df, 0x000006e4, 0x000006e7, 0x000006e8, 0x000006ea, 0x000006ed, 0x00000711, 0x00000711, 0x00000730, 0x0000074a, 0x000007a6, 0x000007b0, 0x00000901, 0x00000902, 0x0000093c, 0x0000093c, 0x00000941, 0x00000948, 0x0000094d, 0x0000094d, 0x00000951, 0x00000954, 0x00000962, 0x00000963, 0x00000981, 0x00000981, 0x000009bc, 0x000009bc, 0x000009c1, 0x000009c4, 0x000009cd, 0x000009cd, 0x000009e2, 0x000009e3, 0x00000a02, 0x00000a02, 0x00000a3c, 0x00000a3c, 0x00000a41, 0x00000a42, 0x00000a47, 0x00000a48, 0x00000a4b, 0x00000a4d, 0x00000a70, 0x00000a71, 0x00000a81, 0x00000a82, 0x00000abc, 0x00000abc, 0x00000ac1, 0x00000ac5, 0x00000ac7, 0x00000ac8, 0x00000acd, 0x00000acd, 0x00000b01, 0x00000b01, 0x00000b3c, 0x00000b3c, 0x00000b3f, 0x00000b3f, 0x00000b41, 0x00000b43, 0x00000b4d, 0x00000b4d, 0x00000b56, 0x00000b56, 0x00000b82, 0x00000b82, 0x00000bc0, 0x00000bc0, 0x00000bcd, 0x00000bcd, 0x00000c3e, 0x00000c40, 0x00000c46, 0x00000c48, 0x00000c4a, 0x00000c4d, 0x00000c55, 0x00000c56, 0x00000cbf, 0x00000cbf, 0x00000cc6, 0x00000cc6, 0x00000ccc, 0x00000ccd, 0x00000d41, 0x00000d43, 0x00000d4d, 0x00000d4d, 0x00000dca, 0x00000dca, 0x00000dd2, 0x00000dd4, 0x00000dd6, 0x00000dd6, 0x00000e31, 0x00000e31, 0x00000e34, 0x00000e3a, 0x00000e47, 0x00000e4e, 0x00000eb1, 0x00000eb1, 0x00000eb4, 0x00000eb9, 0x00000ebb, 0x00000ebc, 0x00000ec8, 0x00000ecd, 0x00000f18, 0x00000f19, 0x00000f35, 0x00000f35, 0x00000f37, 0x00000f37, 0x00000f39, 0x00000f39, 0x00000f71, 0x00000f7e, 0x00000f80, 0x00000f84, 0x00000f86, 0x00000f87, 0x00000f90, 0x00000f97, 0x00000f99, 0x00000fbc, 0x00000fc6, 0x00000fc6, 0x0000102d, 0x00001030, 0x00001032, 0x00001032, 0x00001036, 0x00001037, 0x00001039, 0x00001039, 0x00001058, 0x00001059, 0x00001712, 0x00001714, 0x00001732, 0x00001734, 0x00001752, 0x00001753, 0x00001772, 0x00001773, 0x000017b7, 0x000017bd, 0x000017c6, 0x000017c6, 0x000017c9, 0x000017d3, 0x0000180b, 0x0000180d, 0x000018a9, 0x000018a9, 0x000020d0, 0x000020dc, 0x000020e1, 0x000020e1, 0x000020e5, 0x000020ea, 0x0000302a, 0x0000302f, 0x00003099, 0x0000309a, 0x0000fb1e, 0x0000fb1e, 0x0000fe00, 0x0000fe0f, 0x0000fe20, 0x0000fe23, 0x0001d167, 0x0001d169, 0x0001d17b, 0x0001d182, 0x0001d185, 0x0001d18b, 0x0001d1aa, 0x0001d1ad, 0x00000903, 0x00000903, 0x0000093e, 0x00000940, 0x00000949, 0x0000094c, 0x00000982, 0x00000983, 0x000009be, 0x000009c0, 0x000009c7, 0x000009c8, 0x000009cb, 0x000009cc, 0x000009d7, 0x000009d7, 0x00000a3e, 0x00000a40, 0x00000a83, 0x00000a83, 0x00000abe, 0x00000ac0, 0x00000ac9, 0x00000ac9, 0x00000acb, 0x00000acc, 0x00000b02, 0x00000b03, 0x00000b3e, 0x00000b3e, 0x00000b40, 0x00000b40, 0x00000b47, 0x00000b48, 0x00000b4b, 0x00000b4c, 0x00000b57, 0x00000b57, 0x00000bbe, 0x00000bbf, 0x00000bc1, 0x00000bc2, 0x00000bc6, 0x00000bc8, 0x00000bca, 0x00000bcc, 0x00000bd7, 0x00000bd7, 0x00000c01, 0x00000c03, 0x00000c41, 0x00000c44, 0x00000c82, 0x00000c83, 0x00000cbe, 0x00000cbe, 0x00000cc0, 0x00000cc4, 0x00000cc7, 0x00000cc8, 0x00000cca, 0x00000ccb, 0x00000cd5, 0x00000cd6, 0x00000d02, 0x00000d03, 0x00000d3e, 0x00000d40, 0x00000d46, 0x00000d48, 0x00000d4a, 0x00000d4c, 0x00000d57, 0x00000d57, 0x00000d82, 0x00000d83, 0x00000dcf, 0x00000dd1, 0x00000dd8, 0x00000ddf, 0x00000df2, 0x00000df3, 0x00000f3e, 0x00000f3f, 0x00000f7f, 0x00000f7f, 0x0000102c, 0x0000102c, 0x00001031, 0x00001031, 0x00001038, 0x00001038, 0x00001056, 0x00001057, 0x000017b4, 0x000017b6, 0x000017be, 0x000017c5, 0x000017c7, 0x000017c8, 0x0001d165, 0x0001d166, 0x0001d16d, 0x0001d172, 0x00000488, 0x00000489, 0x000006de, 0x000006de, 0x000020dd, 0x000020e0, 0x000020e2, 0x000020e4, 0x00000030, 0x00000039, 0x00000660, 0x00000669, 0x000006f0, 0x000006f9, 0x00000966, 0x0000096f, 0x000009e6, 0x000009ef, 0x00000a66, 0x00000a6f, 0x00000ae6, 0x00000aef, 0x00000b66, 0x00000b6f, 0x00000be7, 0x00000bef, 0x00000c66, 0x00000c6f, 0x00000ce6, 0x00000cef, 0x00000d66, 0x00000d6f, 0x00000e50, 0x00000e59, 0x00000ed0, 0x00000ed9, 0x00000f20, 0x00000f29, 0x00001040, 0x00001049, 0x00001369, 0x00001371, 0x000017e0, 0x000017e9, 0x00001810, 0x00001819, 0x0000ff10, 0x0000ff19, 0x0001d7ce, 0x0001d7ff, 0x000016ee, 0x000016f0, 0x00002160, 0x00002183, 0x00003007, 0x00003007, 0x00003021, 0x00003029, 0x00003038, 0x0000303a, 0x0001034a, 0x0001034a, 0x000000b2, 0x000000b3, 0x000000b9, 0x000000b9, 0x000000bc, 0x000000be, 0x000009f4, 0x000009f9, 0x00000bf0, 0x00000bf2, 0x00000f2a, 0x00000f33, 0x00001372, 0x0000137c, 0x00002070, 0x00002070, 0x00002074, 0x00002079, 0x00002080, 0x00002089, 0x00002153, 0x0000215f, 0x00002460, 0x0000249b, 0x000024ea, 0x000024fe, 0x00002776, 0x00002793, 0x00003192, 0x00003195, 0x00003220, 0x00003229, 0x00003251, 0x0000325f, 0x00003280, 0x00003289, 0x000032b1, 0x000032bf, 0x00010320, 0x00010323, 0x00000020, 0x00000020, 0x000000a0, 0x000000a0, 0x00001680, 0x00001680, 0x00002000, 0x0000200b, 0x0000202f, 0x0000202f, 0x0000205f, 0x0000205f, 0x00003000, 0x00003000, 0x00002028, 0x00002028, 0x00002029, 0x00002029, 0x00000000, 0x0000001f, 0x0000007f, 0x0000009f, 0x000006dd, 0x000006dd, 0x0000070f, 0x0000070f, 0x0000180e, 0x0000180e, 0x0000200c, 0x0000200f, 0x0000202a, 0x0000202e, 0x00002060, 0x00002063, 0x0000206a, 0x0000206f, 0x0000feff, 0x0000feff, 0x0000fff9, 0x0000fffb, 0x0001d173, 0x0001d17a, 0x000e0001, 0x000e0001, 0x000e0020, 0x000e007f, 0x00010000, 0x0010ffff, 0x0000e000, 0x0000f8ff, 0x000f0000, 0x000ffffd, 0x00100000, 0x0010fffd, 0x00000041, 0x0000005a, 0x000000c0, 0x000000d6, 0x000000d8, 0x000000de, 0x00000100, 0x00000100, 0x00000102, 0x00000102, 0x00000104, 0x00000104, 0x00000106, 0x00000106, 0x00000108, 0x00000108, 0x0000010a, 0x0000010a, 0x0000010c, 0x0000010c, 0x0000010e, 0x0000010e, 0x00000110, 0x00000110, 0x00000112, 0x00000112, 0x00000114, 0x00000114, 0x00000116, 0x00000116, 0x00000118, 0x00000118, 0x0000011a, 0x0000011a, 0x0000011c, 0x0000011c, 0x0000011e, 0x0000011e, 0x00000120, 0x00000120, 0x00000122, 0x00000122, 0x00000124, 0x00000124, 0x00000126, 0x00000126, 0x00000128, 0x00000128, 0x0000012a, 0x0000012a, 0x0000012c, 0x0000012c, 0x0000012e, 0x0000012e, 0x00000130, 0x00000130, 0x00000132, 0x00000132, 0x00000134, 0x00000134, 0x00000136, 0x00000136, 0x00000139, 0x00000139, 0x0000013b, 0x0000013b, 0x0000013d, 0x0000013d, 0x0000013f, 0x0000013f, 0x00000141, 0x00000141, 0x00000143, 0x00000143, 0x00000145, 0x00000145, 0x00000147, 0x00000147, 0x0000014a, 0x0000014a, 0x0000014c, 0x0000014c, 0x0000014e, 0x0000014e, 0x00000150, 0x00000150, 0x00000152, 0x00000152, 0x00000154, 0x00000154, 0x00000156, 0x00000156, 0x00000158, 0x00000158, 0x0000015a, 0x0000015a, 0x0000015c, 0x0000015c, 0x0000015e, 0x0000015e, 0x00000160, 0x00000160, 0x00000162, 0x00000162, 0x00000164, 0x00000164, 0x00000166, 0x00000166, 0x00000168, 0x00000168, 0x0000016a, 0x0000016a, 0x0000016c, 0x0000016c, 0x0000016e, 0x0000016e, 0x00000170, 0x00000170, 0x00000172, 0x00000172, 0x00000174, 0x00000174, 0x00000176, 0x00000176, 0x00000178, 0x00000179, 0x0000017b, 0x0000017b, 0x0000017d, 0x0000017d, 0x00000181, 0x00000182, 0x00000184, 0x00000184, 0x00000186, 0x00000187, 0x00000189, 0x0000018b, 0x0000018e, 0x00000191, 0x00000193, 0x00000194, 0x00000196, 0x00000198, 0x0000019c, 0x0000019d, 0x0000019f, 0x000001a0, 0x000001a2, 0x000001a2, 0x000001a4, 0x000001a4, 0x000001a6, 0x000001a7, 0x000001a9, 0x000001a9, 0x000001ac, 0x000001ac, 0x000001ae, 0x000001af, 0x000001b1, 0x000001b3, 0x000001b5, 0x000001b5, 0x000001b7, 0x000001b8, 0x000001bc, 0x000001bc, 0x000001c4, 0x000001c4, 0x000001c7, 0x000001c7, 0x000001ca, 0x000001ca, 0x000001cd, 0x000001cd, 0x000001cf, 0x000001cf, 0x000001d1, 0x000001d1, 0x000001d3, 0x000001d3, 0x000001d5, 0x000001d5, 0x000001d7, 0x000001d7, 0x000001d9, 0x000001d9, 0x000001db, 0x000001db, 0x000001de, 0x000001de, 0x000001e0, 0x000001e0, 0x000001e2, 0x000001e2, 0x000001e4, 0x000001e4, 0x000001e6, 0x000001e6, 0x000001e8, 0x000001e8, 0x000001ea, 0x000001ea, 0x000001ec, 0x000001ec, 0x000001ee, 0x000001ee, 0x000001f1, 0x000001f1, 0x000001f4, 0x000001f4, 0x000001f6, 0x000001f8, 0x000001fa, 0x000001fa, 0x000001fc, 0x000001fc, 0x000001fe, 0x000001fe, 0x00000200, 0x00000200, 0x00000202, 0x00000202, 0x00000204, 0x00000204, 0x00000206, 0x00000206, 0x00000208, 0x00000208, 0x0000020a, 0x0000020a, 0x0000020c, 0x0000020c, 0x0000020e, 0x0000020e, 0x00000210, 0x00000210, 0x00000212, 0x00000212, 0x00000214, 0x00000214, 0x00000216, 0x00000216, 0x00000218, 0x00000218, 0x0000021a, 0x0000021a, 0x0000021c, 0x0000021c, 0x0000021e, 0x0000021e, 0x00000220, 0x00000220, 0x00000222, 0x00000222, 0x00000224, 0x00000224, 0x00000226, 0x00000226, 0x00000228, 0x00000228, 0x0000022a, 0x0000022a, 0x0000022c, 0x0000022c, 0x0000022e, 0x0000022e, 0x00000230, 0x00000230, 0x00000232, 0x00000232, 0x00000386, 0x00000386, 0x00000388, 0x0000038a, 0x0000038c, 0x0000038c, 0x0000038e, 0x0000038f, 0x00000391, 0x000003a1, 0x000003a3, 0x000003ab, 0x000003d2, 0x000003d4, 0x000003d8, 0x000003d8, 0x000003da, 0x000003da, 0x000003dc, 0x000003dc, 0x000003de, 0x000003de, 0x000003e0, 0x000003e0, 0x000003e2, 0x000003e2, 0x000003e4, 0x000003e4, 0x000003e6, 0x000003e6, 0x000003e8, 0x000003e8, 0x000003ea, 0x000003ea, 0x000003ec, 0x000003ec, 0x000003ee, 0x000003ee, 0x000003f4, 0x000003f4, 0x00000400, 0x0000042f, 0x00000460, 0x00000460, 0x00000462, 0x00000462, 0x00000464, 0x00000464, 0x00000466, 0x00000466, 0x00000468, 0x00000468, 0x0000046a, 0x0000046a, 0x0000046c, 0x0000046c, 0x0000046e, 0x0000046e, 0x00000470, 0x00000470, 0x00000472, 0x00000472, 0x00000474, 0x00000474, 0x00000476, 0x00000476, 0x00000478, 0x00000478, 0x0000047a, 0x0000047a, 0x0000047c, 0x0000047c, 0x0000047e, 0x0000047e, 0x00000480, 0x00000480, 0x0000048a, 0x0000048a, 0x0000048c, 0x0000048c, 0x0000048e, 0x0000048e, 0x00000490, 0x00000490, 0x00000492, 0x00000492, 0x00000494, 0x00000494, 0x00000496, 0x00000496, 0x00000498, 0x00000498, 0x0000049a, 0x0000049a, 0x0000049c, 0x0000049c, 0x0000049e, 0x0000049e, 0x000004a0, 0x000004a0, 0x000004a2, 0x000004a2, 0x000004a4, 0x000004a4, 0x000004a6, 0x000004a6, 0x000004a8, 0x000004a8, 0x000004aa, 0x000004aa, 0x000004ac, 0x000004ac, 0x000004ae, 0x000004ae, 0x000004b0, 0x000004b0, 0x000004b2, 0x000004b2, 0x000004b4, 0x000004b4, 0x000004b6, 0x000004b6, 0x000004b8, 0x000004b8, 0x000004ba, 0x000004ba, 0x000004bc, 0x000004bc, 0x000004be, 0x000004be, 0x000004c0, 0x000004c1, 0x000004c3, 0x000004c3, 0x000004c5, 0x000004c5, 0x000004c7, 0x000004c7, 0x000004c9, 0x000004c9, 0x000004cb, 0x000004cb, 0x000004cd, 0x000004cd, 0x000004d0, 0x000004d0, 0x000004d2, 0x000004d2, 0x000004d4, 0x000004d4, 0x000004d6, 0x000004d6, 0x000004d8, 0x000004d8, 0x000004da, 0x000004da, 0x000004dc, 0x000004dc, 0x000004de, 0x000004de, 0x000004e0, 0x000004e0, 0x000004e2, 0x000004e2, 0x000004e4, 0x000004e4, 0x000004e6, 0x000004e6, 0x000004e8, 0x000004e8, 0x000004ea, 0x000004ea, 0x000004ec, 0x000004ec, 0x000004ee, 0x000004ee, 0x000004f0, 0x000004f0, 0x000004f2, 0x000004f2, 0x000004f4, 0x000004f4, 0x000004f8, 0x000004f8, 0x00000500, 0x00000500, 0x00000502, 0x00000502, 0x00000504, 0x00000504, 0x00000506, 0x00000506, 0x00000508, 0x00000508, 0x0000050a, 0x0000050a, 0x0000050c, 0x0000050c, 0x0000050e, 0x0000050e, 0x00000531, 0x00000556, 0x000010a0, 0x000010c5, 0x00001e00, 0x00001e00, 0x00001e02, 0x00001e02, 0x00001e04, 0x00001e04, 0x00001e06, 0x00001e06, 0x00001e08, 0x00001e08, 0x00001e0a, 0x00001e0a, 0x00001e0c, 0x00001e0c, 0x00001e0e, 0x00001e0e, 0x00001e10, 0x00001e10, 0x00001e12, 0x00001e12, 0x00001e14, 0x00001e14, 0x00001e16, 0x00001e16, 0x00001e18, 0x00001e18, 0x00001e1a, 0x00001e1a, 0x00001e1c, 0x00001e1c, 0x00001e1e, 0x00001e1e, 0x00001e20, 0x00001e20, 0x00001e22, 0x00001e22, 0x00001e24, 0x00001e24, 0x00001e26, 0x00001e26, 0x00001e28, 0x00001e28, 0x00001e2a, 0x00001e2a, 0x00001e2c, 0x00001e2c, 0x00001e2e, 0x00001e2e, 0x00001e30, 0x00001e30, 0x00001e32, 0x00001e32, 0x00001e34, 0x00001e34, 0x00001e36, 0x00001e36, 0x00001e38, 0x00001e38, 0x00001e3a, 0x00001e3a, 0x00001e3c, 0x00001e3c, 0x00001e3e, 0x00001e3e, 0x00001e40, 0x00001e40, 0x00001e42, 0x00001e42, 0x00001e44, 0x00001e44, 0x00001e46, 0x00001e46, 0x00001e48, 0x00001e48, 0x00001e4a, 0x00001e4a, 0x00001e4c, 0x00001e4c, 0x00001e4e, 0x00001e4e, 0x00001e50, 0x00001e50, 0x00001e52, 0x00001e52, 0x00001e54, 0x00001e54, 0x00001e56, 0x00001e56, 0x00001e58, 0x00001e58, 0x00001e5a, 0x00001e5a, 0x00001e5c, 0x00001e5c, 0x00001e5e, 0x00001e5e, 0x00001e60, 0x00001e60, 0x00001e62, 0x00001e62, 0x00001e64, 0x00001e64, 0x00001e66, 0x00001e66, 0x00001e68, 0x00001e68, 0x00001e6a, 0x00001e6a, 0x00001e6c, 0x00001e6c, 0x00001e6e, 0x00001e6e, 0x00001e70, 0x00001e70, 0x00001e72, 0x00001e72, 0x00001e74, 0x00001e74, 0x00001e76, 0x00001e76, 0x00001e78, 0x00001e78, 0x00001e7a, 0x00001e7a, 0x00001e7c, 0x00001e7c, 0x00001e7e, 0x00001e7e, 0x00001e80, 0x00001e80, 0x00001e82, 0x00001e82, 0x00001e84, 0x00001e84, 0x00001e86, 0x00001e86, 0x00001e88, 0x00001e88, 0x00001e8a, 0x00001e8a, 0x00001e8c, 0x00001e8c, 0x00001e8e, 0x00001e8e, 0x00001e90, 0x00001e90, 0x00001e92, 0x00001e92, 0x00001e94, 0x00001e94, 0x00001ea0, 0x00001ea0, 0x00001ea2, 0x00001ea2, 0x00001ea4, 0x00001ea4, 0x00001ea6, 0x00001ea6, 0x00001ea8, 0x00001ea8, 0x00001eaa, 0x00001eaa, 0x00001eac, 0x00001eac, 0x00001eae, 0x00001eae, 0x00001eb0, 0x00001eb0, 0x00001eb2, 0x00001eb2, 0x00001eb4, 0x00001eb4, 0x00001eb6, 0x00001eb6, 0x00001eb8, 0x00001eb8, 0x00001eba, 0x00001eba, 0x00001ebc, 0x00001ebc, 0x00001ebe, 0x00001ebe, 0x00001ec0, 0x00001ec0, 0x00001ec2, 0x00001ec2, 0x00001ec4, 0x00001ec4, 0x00001ec6, 0x00001ec6, 0x00001ec8, 0x00001ec8, 0x00001eca, 0x00001eca, 0x00001ecc, 0x00001ecc, 0x00001ece, 0x00001ece, 0x00001ed0, 0x00001ed0, 0x00001ed2, 0x00001ed2, 0x00001ed4, 0x00001ed4, 0x00001ed6, 0x00001ed6, 0x00001ed8, 0x00001ed8, 0x00001eda, 0x00001eda, 0x00001edc, 0x00001edc, 0x00001ede, 0x00001ede, 0x00001ee0, 0x00001ee0, 0x00001ee2, 0x00001ee2, 0x00001ee4, 0x00001ee4, 0x00001ee6, 0x00001ee6, 0x00001ee8, 0x00001ee8, 0x00001eea, 0x00001eea, 0x00001eec, 0x00001eec, 0x00001eee, 0x00001eee, 0x00001ef0, 0x00001ef0, 0x00001ef2, 0x00001ef2, 0x00001ef4, 0x00001ef4, 0x00001ef6, 0x00001ef6, 0x00001ef8, 0x00001ef8, 0x00001f08, 0x00001f0f, 0x00001f18, 0x00001f1d, 0x00001f28, 0x00001f2f, 0x00001f38, 0x00001f3f, 0x00001f48, 0x00001f4d, 0x00001f59, 0x00001f59, 0x00001f5b, 0x00001f5b, 0x00001f5d, 0x00001f5d, 0x00001f5f, 0x00001f5f, 0x00001f68, 0x00001f6f, 0x00001fb8, 0x00001fbb, 0x00001fc8, 0x00001fcb, 0x00001fd8, 0x00001fdb, 0x00001fe8, 0x00001fec, 0x00001ff8, 0x00001ffb, 0x00002102, 0x00002102, 0x00002107, 0x00002107, 0x0000210b, 0x0000210d, 0x00002110, 0x00002112, 0x00002115, 0x00002115, 0x00002119, 0x0000211d, 0x00002124, 0x00002124, 0x00002126, 0x00002126, 0x00002128, 0x00002128, 0x0000212a, 0x0000212d, 0x00002130, 0x00002131, 0x00002133, 0x00002133, 0x0000213e, 0x0000213f, 0x00002145, 0x00002145, 0x0000ff21, 0x0000ff3a, 0x00010400, 0x00010425, 0x0001d400, 0x0001d419, 0x0001d434, 0x0001d44d, 0x0001d468, 0x0001d481, 0x0001d49c, 0x0001d49c, 0x0001d49e, 0x0001d49f, 0x0001d4a2, 0x0001d4a2, 0x0001d4a5, 0x0001d4a6, 0x0001d4a9, 0x0001d4ac, 0x0001d4ae, 0x0001d4b5, 0x0001d4d0, 0x0001d4e9, 0x0001d504, 0x0001d505, 0x0001d507, 0x0001d50a, 0x0001d50d, 0x0001d514, 0x0001d516, 0x0001d51c, 0x0001d538, 0x0001d539, 0x0001d53b, 0x0001d53e, 0x0001d540, 0x0001d544, 0x0001d546, 0x0001d546, 0x0001d54a, 0x0001d550, 0x0001d56c, 0x0001d585, 0x0001d5a0, 0x0001d5b9, 0x0001d5d4, 0x0001d5ed, 0x0001d608, 0x0001d621, 0x0001d63c, 0x0001d655, 0x0001d670, 0x0001d689, 0x0001d6a8, 0x0001d6c0, 0x0001d6e2, 0x0001d6fa, 0x0001d71c, 0x0001d734, 0x0001d756, 0x0001d76e, 0x0001d790, 0x0001d7a8, 0x00000061, 0x0000007a, 0x000000aa, 0x000000aa, 0x000000b5, 0x000000b5, 0x000000ba, 0x000000ba, 0x000000df, 0x000000f6, 0x000000f8, 0x000000ff, 0x00000101, 0x00000101, 0x00000103, 0x00000103, 0x00000105, 0x00000105, 0x00000107, 0x00000107, 0x00000109, 0x00000109, 0x0000010b, 0x0000010b, 0x0000010d, 0x0000010d, 0x0000010f, 0x0000010f, 0x00000111, 0x00000111, 0x00000113, 0x00000113, 0x00000115, 0x00000115, 0x00000117, 0x00000117, 0x00000119, 0x00000119, 0x0000011b, 0x0000011b, 0x0000011d, 0x0000011d, 0x0000011f, 0x0000011f, 0x00000121, 0x00000121, 0x00000123, 0x00000123, 0x00000125, 0x00000125, 0x00000127, 0x00000127, 0x00000129, 0x00000129, 0x0000012b, 0x0000012b, 0x0000012d, 0x0000012d, 0x0000012f, 0x0000012f, 0x00000131, 0x00000131, 0x00000133, 0x00000133, 0x00000135, 0x00000135, 0x00000137, 0x00000138, 0x0000013a, 0x0000013a, 0x0000013c, 0x0000013c, 0x0000013e, 0x0000013e, 0x00000140, 0x00000140, 0x00000142, 0x00000142, 0x00000144, 0x00000144, 0x00000146, 0x00000146, 0x00000148, 0x00000149, 0x0000014b, 0x0000014b, 0x0000014d, 0x0000014d, 0x0000014f, 0x0000014f, 0x00000151, 0x00000151, 0x00000153, 0x00000153, 0x00000155, 0x00000155, 0x00000157, 0x00000157, 0x00000159, 0x00000159, 0x0000015b, 0x0000015b, 0x0000015d, 0x0000015d, 0x0000015f, 0x0000015f, 0x00000161, 0x00000161, 0x00000163, 0x00000163, 0x00000165, 0x00000165, 0x00000167, 0x00000167, 0x00000169, 0x00000169, 0x0000016b, 0x0000016b, 0x0000016d, 0x0000016d, 0x0000016f, 0x0000016f, 0x00000171, 0x00000171, 0x00000173, 0x00000173, 0x00000175, 0x00000175, 0x00000177, 0x00000177, 0x0000017a, 0x0000017a, 0x0000017c, 0x0000017c, 0x0000017e, 0x00000180, 0x00000183, 0x00000183, 0x00000185, 0x00000185, 0x00000188, 0x00000188, 0x0000018c, 0x0000018d, 0x00000192, 0x00000192, 0x00000195, 0x00000195, 0x00000199, 0x0000019b, 0x0000019e, 0x0000019e, 0x000001a1, 0x000001a1, 0x000001a3, 0x000001a3, 0x000001a5, 0x000001a5, 0x000001a8, 0x000001a8, 0x000001aa, 0x000001ab, 0x000001ad, 0x000001ad, 0x000001b0, 0x000001b0, 0x000001b4, 0x000001b4, 0x000001b6, 0x000001b6, 0x000001b9, 0x000001ba, 0x000001bd, 0x000001bf, 0x000001c6, 0x000001c6, 0x000001c9, 0x000001c9, 0x000001cc, 0x000001cc, 0x000001ce, 0x000001ce, 0x000001d0, 0x000001d0, 0x000001d2, 0x000001d2, 0x000001d4, 0x000001d4, 0x000001d6, 0x000001d6, 0x000001d8, 0x000001d8, 0x000001da, 0x000001da, 0x000001dc, 0x000001dd, 0x000001df, 0x000001df, 0x000001e1, 0x000001e1, 0x000001e3, 0x000001e3, 0x000001e5, 0x000001e5, 0x000001e7, 0x000001e7, 0x000001e9, 0x000001e9, 0x000001eb, 0x000001eb, 0x000001ed, 0x000001ed, 0x000001ef, 0x000001f0, 0x000001f3, 0x000001f3, 0x000001f5, 0x000001f5, 0x000001f9, 0x000001f9, 0x000001fb, 0x000001fb, 0x000001fd, 0x000001fd, 0x000001ff, 0x000001ff, 0x00000201, 0x00000201, 0x00000203, 0x00000203, 0x00000205, 0x00000205, 0x00000207, 0x00000207, 0x00000209, 0x00000209, 0x0000020b, 0x0000020b, 0x0000020d, 0x0000020d, 0x0000020f, 0x0000020f, 0x00000211, 0x00000211, 0x00000213, 0x00000213, 0x00000215, 0x00000215, 0x00000217, 0x00000217, 0x00000219, 0x00000219, 0x0000021b, 0x0000021b, 0x0000021d, 0x0000021d, 0x0000021f, 0x0000021f, 0x00000223, 0x00000223, 0x00000225, 0x00000225, 0x00000227, 0x00000227, 0x00000229, 0x00000229, 0x0000022b, 0x0000022b, 0x0000022d, 0x0000022d, 0x0000022f, 0x0000022f, 0x00000231, 0x00000231, 0x00000233, 0x00000233, 0x00000250, 0x000002ad, 0x00000390, 0x00000390, 0x000003ac, 0x000003ce, 0x000003d0, 0x000003d1, 0x000003d5, 0x000003d7, 0x000003d9, 0x000003d9, 0x000003db, 0x000003db, 0x000003dd, 0x000003dd, 0x000003df, 0x000003df, 0x000003e1, 0x000003e1, 0x000003e3, 0x000003e3, 0x000003e5, 0x000003e5, 0x000003e7, 0x000003e7, 0x000003e9, 0x000003e9, 0x000003eb, 0x000003eb, 0x000003ed, 0x000003ed, 0x000003ef, 0x000003f3, 0x000003f5, 0x000003f5, 0x00000430, 0x0000045f, 0x00000461, 0x00000461, 0x00000463, 0x00000463, 0x00000465, 0x00000465, 0x00000467, 0x00000467, 0x00000469, 0x00000469, 0x0000046b, 0x0000046b, 0x0000046d, 0x0000046d, 0x0000046f, 0x0000046f, 0x00000471, 0x00000471, 0x00000473, 0x00000473, 0x00000475, 0x00000475, 0x00000477, 0x00000477, 0x00000479, 0x00000479, 0x0000047b, 0x0000047b, 0x0000047d, 0x0000047d, 0x0000047f, 0x0000047f, 0x00000481, 0x00000481, 0x0000048b, 0x0000048b, 0x0000048d, 0x0000048d, 0x0000048f, 0x0000048f, 0x00000491, 0x00000491, 0x00000493, 0x00000493, 0x00000495, 0x00000495, 0x00000497, 0x00000497, 0x00000499, 0x00000499, 0x0000049b, 0x0000049b, 0x0000049d, 0x0000049d, 0x0000049f, 0x0000049f, 0x000004a1, 0x000004a1, 0x000004a3, 0x000004a3, 0x000004a5, 0x000004a5, 0x000004a7, 0x000004a7, 0x000004a9, 0x000004a9, 0x000004ab, 0x000004ab, 0x000004ad, 0x000004ad, 0x000004af, 0x000004af, 0x000004b1, 0x000004b1, 0x000004b3, 0x000004b3, 0x000004b5, 0x000004b5, 0x000004b7, 0x000004b7, 0x000004b9, 0x000004b9, 0x000004bb, 0x000004bb, 0x000004bd, 0x000004bd, 0x000004bf, 0x000004bf, 0x000004c2, 0x000004c2, 0x000004c4, 0x000004c4, 0x000004c6, 0x000004c6, 0x000004c8, 0x000004c8, 0x000004ca, 0x000004ca, 0x000004cc, 0x000004cc, 0x000004ce, 0x000004ce, 0x000004d1, 0x000004d1, 0x000004d3, 0x000004d3, 0x000004d5, 0x000004d5, 0x000004d7, 0x000004d7, 0x000004d9, 0x000004d9, 0x000004db, 0x000004db, 0x000004dd, 0x000004dd, 0x000004df, 0x000004df, 0x000004e1, 0x000004e1, 0x000004e3, 0x000004e3, 0x000004e5, 0x000004e5, 0x000004e7, 0x000004e7, 0x000004e9, 0x000004e9, 0x000004eb, 0x000004eb, 0x000004ed, 0x000004ed, 0x000004ef, 0x000004ef, 0x000004f1, 0x000004f1, 0x000004f3, 0x000004f3, 0x000004f5, 0x000004f5, 0x000004f9, 0x000004f9, 0x00000501, 0x00000501, 0x00000503, 0x00000503, 0x00000505, 0x00000505, 0x00000507, 0x00000507, 0x00000509, 0x00000509, 0x0000050b, 0x0000050b, 0x0000050d, 0x0000050d, 0x0000050f, 0x0000050f, 0x00000561, 0x00000587, 0x00001e01, 0x00001e01, 0x00001e03, 0x00001e03, 0x00001e05, 0x00001e05, 0x00001e07, 0x00001e07, 0x00001e09, 0x00001e09, 0x00001e0b, 0x00001e0b, 0x00001e0d, 0x00001e0d, 0x00001e0f, 0x00001e0f, 0x00001e11, 0x00001e11, 0x00001e13, 0x00001e13, 0x00001e15, 0x00001e15, 0x00001e17, 0x00001e17, 0x00001e19, 0x00001e19, 0x00001e1b, 0x00001e1b, 0x00001e1d, 0x00001e1d, 0x00001e1f, 0x00001e1f, 0x00001e21, 0x00001e21, 0x00001e23, 0x00001e23, 0x00001e25, 0x00001e25, 0x00001e27, 0x00001e27, 0x00001e29, 0x00001e29, 0x00001e2b, 0x00001e2b, 0x00001e2d, 0x00001e2d, 0x00001e2f, 0x00001e2f, 0x00001e31, 0x00001e31, 0x00001e33, 0x00001e33, 0x00001e35, 0x00001e35, 0x00001e37, 0x00001e37, 0x00001e39, 0x00001e39, 0x00001e3b, 0x00001e3b, 0x00001e3d, 0x00001e3d, 0x00001e3f, 0x00001e3f, 0x00001e41, 0x00001e41, 0x00001e43, 0x00001e43, 0x00001e45, 0x00001e45, 0x00001e47, 0x00001e47, 0x00001e49, 0x00001e49, 0x00001e4b, 0x00001e4b, 0x00001e4d, 0x00001e4d, 0x00001e4f, 0x00001e4f, 0x00001e51, 0x00001e51, 0x00001e53, 0x00001e53, 0x00001e55, 0x00001e55, 0x00001e57, 0x00001e57, 0x00001e59, 0x00001e59, 0x00001e5b, 0x00001e5b, 0x00001e5d, 0x00001e5d, 0x00001e5f, 0x00001e5f, 0x00001e61, 0x00001e61, 0x00001e63, 0x00001e63, 0x00001e65, 0x00001e65, 0x00001e67, 0x00001e67, 0x00001e69, 0x00001e69, 0x00001e6b, 0x00001e6b, 0x00001e6d, 0x00001e6d, 0x00001e6f, 0x00001e6f, 0x00001e71, 0x00001e71, 0x00001e73, 0x00001e73, 0x00001e75, 0x00001e75, 0x00001e77, 0x00001e77, 0x00001e79, 0x00001e79, 0x00001e7b, 0x00001e7b, 0x00001e7d, 0x00001e7d, 0x00001e7f, 0x00001e7f, 0x00001e81, 0x00001e81, 0x00001e83, 0x00001e83, 0x00001e85, 0x00001e85, 0x00001e87, 0x00001e87, 0x00001e89, 0x00001e89, 0x00001e8b, 0x00001e8b, 0x00001e8d, 0x00001e8d, 0x00001e8f, 0x00001e8f, 0x00001e91, 0x00001e91, 0x00001e93, 0x00001e93, 0x00001e95, 0x00001e9b, 0x00001ea1, 0x00001ea1, 0x00001ea3, 0x00001ea3, 0x00001ea5, 0x00001ea5, 0x00001ea7, 0x00001ea7, 0x00001ea9, 0x00001ea9, 0x00001eab, 0x00001eab, 0x00001ead, 0x00001ead, 0x00001eaf, 0x00001eaf, 0x00001eb1, 0x00001eb1, 0x00001eb3, 0x00001eb3, 0x00001eb5, 0x00001eb5, 0x00001eb7, 0x00001eb7, 0x00001eb9, 0x00001eb9, 0x00001ebb, 0x00001ebb, 0x00001ebd, 0x00001ebd, 0x00001ebf, 0x00001ebf, 0x00001ec1, 0x00001ec1, 0x00001ec3, 0x00001ec3, 0x00001ec5, 0x00001ec5, 0x00001ec7, 0x00001ec7, 0x00001ec9, 0x00001ec9, 0x00001ecb, 0x00001ecb, 0x00001ecd, 0x00001ecd, 0x00001ecf, 0x00001ecf, 0x00001ed1, 0x00001ed1, 0x00001ed3, 0x00001ed3, 0x00001ed5, 0x00001ed5, 0x00001ed7, 0x00001ed7, 0x00001ed9, 0x00001ed9, 0x00001edb, 0x00001edb, 0x00001edd, 0x00001edd, 0x00001edf, 0x00001edf, 0x00001ee1, 0x00001ee1, 0x00001ee3, 0x00001ee3, 0x00001ee5, 0x00001ee5, 0x00001ee7, 0x00001ee7, 0x00001ee9, 0x00001ee9, 0x00001eeb, 0x00001eeb, 0x00001eed, 0x00001eed, 0x00001eef, 0x00001eef, 0x00001ef1, 0x00001ef1, 0x00001ef3, 0x00001ef3, 0x00001ef5, 0x00001ef5, 0x00001ef7, 0x00001ef7, 0x00001ef9, 0x00001ef9, 0x00001f00, 0x00001f07, 0x00001f10, 0x00001f15, 0x00001f20, 0x00001f27, 0x00001f30, 0x00001f37, 0x00001f40, 0x00001f45, 0x00001f50, 0x00001f57, 0x00001f60, 0x00001f67, 0x00001f70, 0x00001f7d, 0x00001f80, 0x00001f87, 0x00001f90, 0x00001f97, 0x00001fa0, 0x00001fa7, 0x00001fb0, 0x00001fb4, 0x00001fb6, 0x00001fb7, 0x00001fbe, 0x00001fbe, 0x00001fc2, 0x00001fc4, 0x00001fc6, 0x00001fc7, 0x00001fd0, 0x00001fd3, 0x00001fd6, 0x00001fd7, 0x00001fe0, 0x00001fe7, 0x00001ff2, 0x00001ff4, 0x00001ff6, 0x00001ff7, 0x00002071, 0x00002071, 0x0000207f, 0x0000207f, 0x0000210a, 0x0000210a, 0x0000210e, 0x0000210f, 0x00002113, 0x00002113, 0x0000212f, 0x0000212f, 0x00002134, 0x00002134, 0x00002139, 0x00002139, 0x0000213d, 0x0000213d, 0x00002146, 0x00002149, 0x0000fb00, 0x0000fb06, 0x0000fb13, 0x0000fb17, 0x0000ff41, 0x0000ff5a, 0x00010428, 0x0001044d, 0x0001d41a, 0x0001d433, 0x0001d44e, 0x0001d454, 0x0001d456, 0x0001d467, 0x0001d482, 0x0001d49b, 0x0001d4b6, 0x0001d4b9, 0x0001d4bb, 0x0001d4bb, 0x0001d4bd, 0x0001d4c0, 0x0001d4c2, 0x0001d4c3, 0x0001d4c5, 0x0001d4cf, 0x0001d4ea, 0x0001d503, 0x0001d51e, 0x0001d537, 0x0001d552, 0x0001d56b, 0x0001d586, 0x0001d59f, 0x0001d5ba, 0x0001d5d3, 0x0001d5ee, 0x0001d607, 0x0001d622, 0x0001d63b, 0x0001d656, 0x0001d66f, 0x0001d68a, 0x0001d6a3, 0x0001d6c2, 0x0001d6da, 0x0001d6dc, 0x0001d6e1, 0x0001d6fc, 0x0001d714, 0x0001d716, 0x0001d71b, 0x0001d736, 0x0001d74e, 0x0001d750, 0x0001d755, 0x0001d770, 0x0001d788, 0x0001d78a, 0x0001d78f, 0x0001d7aa, 0x0001d7c2, 0x0001d7c4, 0x0001d7c9, 0x000001c5, 0x000001c5, 0x000001c8, 0x000001c8, 0x000001cb, 0x000001cb, 0x000001f2, 0x000001f2, 0x00001f88, 0x00001f8f, 0x00001f98, 0x00001f9f, 0x00001fa8, 0x00001faf, 0x00001fbc, 0x00001fbc, 0x00001fcc, 0x00001fcc, 0x00001ffc, 0x00001ffc, 0x000002b0, 0x000002b8, 0x000002bb, 0x000002c1, 0x000002d0, 0x000002d1, 0x000002e0, 0x000002e4, 0x000002ee, 0x000002ee, 0x0000037a, 0x0000037a, 0x00000559, 0x00000559, 0x00000640, 0x00000640, 0x000006e5, 0x000006e6, 0x00000e46, 0x00000e46, 0x00000ec6, 0x00000ec6, 0x000017d7, 0x000017d7, 0x00001843, 0x00001843, 0x00003005, 0x00003005, 0x00003031, 0x00003035, 0x0000303b, 0x0000303b, 0x0000309d, 0x0000309e, 0x000030fc, 0x000030fe, 0x0000ff70, 0x0000ff70, 0x0000ff9e, 0x0000ff9f, 0x000001bb, 0x000001bb, 0x000001c0, 0x000001c3, 0x000005d0, 0x000005ea, 0x000005f0, 0x000005f2, 0x00000621, 0x0000063a, 0x00000641, 0x0000064a, 0x0000066e, 0x0000066f, 0x00000671, 0x000006d3, 0x000006d5, 0x000006d5, 0x000006fa, 0x000006fc, 0x00000710, 0x00000710, 0x00000712, 0x0000072c, 0x00000780, 0x000007a5, 0x000007b1, 0x000007b1, 0x00000905, 0x00000939, 0x0000093d, 0x0000093d, 0x00000950, 0x00000950, 0x00000958, 0x00000961, 0x00000985, 0x0000098c, 0x0000098f, 0x00000990, 0x00000993, 0x000009a8, 0x000009aa, 0x000009b0, 0x000009b2, 0x000009b2, 0x000009b6, 0x000009b9, 0x000009dc, 0x000009dd, 0x000009df, 0x000009e1, 0x000009f0, 0x000009f1, 0x00000a05, 0x00000a0a, 0x00000a0f, 0x00000a10, 0x00000a13, 0x00000a28, 0x00000a2a, 0x00000a30, 0x00000a32, 0x00000a33, 0x00000a35, 0x00000a36, 0x00000a38, 0x00000a39, 0x00000a59, 0x00000a5c, 0x00000a5e, 0x00000a5e, 0x00000a72, 0x00000a74, 0x00000a85, 0x00000a8b, 0x00000a8d, 0x00000a8d, 0x00000a8f, 0x00000a91, 0x00000a93, 0x00000aa8, 0x00000aaa, 0x00000ab0, 0x00000ab2, 0x00000ab3, 0x00000ab5, 0x00000ab9, 0x00000abd, 0x00000abd, 0x00000ad0, 0x00000ad0, 0x00000ae0, 0x00000ae0, 0x00000b05, 0x00000b0c, 0x00000b0f, 0x00000b10, 0x00000b13, 0x00000b28, 0x00000b2a, 0x00000b30, 0x00000b32, 0x00000b33, 0x00000b36, 0x00000b39, 0x00000b3d, 0x00000b3d, 0x00000b5c, 0x00000b5d, 0x00000b5f, 0x00000b61, 0x00000b83, 0x00000b83, 0x00000b85, 0x00000b8a, 0x00000b8e, 0x00000b90, 0x00000b92, 0x00000b95, 0x00000b99, 0x00000b9a, 0x00000b9c, 0x00000b9c, 0x00000b9e, 0x00000b9f, 0x00000ba3, 0x00000ba4, 0x00000ba8, 0x00000baa, 0x00000bae, 0x00000bb5, 0x00000bb7, 0x00000bb9, 0x00000c05, 0x00000c0c, 0x00000c0e, 0x00000c10, 0x00000c12, 0x00000c28, 0x00000c2a, 0x00000c33, 0x00000c35, 0x00000c39, 0x00000c60, 0x00000c61, 0x00000c85, 0x00000c8c, 0x00000c8e, 0x00000c90, 0x00000c92, 0x00000ca8, 0x00000caa, 0x00000cb3, 0x00000cb5, 0x00000cb9, 0x00000cde, 0x00000cde, 0x00000ce0, 0x00000ce1, 0x00000d05, 0x00000d0c, 0x00000d0e, 0x00000d10, 0x00000d12, 0x00000d28, 0x00000d2a, 0x00000d39, 0x00000d60, 0x00000d61, 0x00000d85, 0x00000d96, 0x00000d9a, 0x00000db1, 0x00000db3, 0x00000dbb, 0x00000dbd, 0x00000dbd, 0x00000dc0, 0x00000dc6, 0x00000e01, 0x00000e30, 0x00000e32, 0x00000e33, 0x00000e40, 0x00000e45, 0x00000e81, 0x00000e82, 0x00000e84, 0x00000e84, 0x00000e87, 0x00000e88, 0x00000e8a, 0x00000e8a, 0x00000e8d, 0x00000e8d, 0x00000e94, 0x00000e97, 0x00000e99, 0x00000e9f, 0x00000ea1, 0x00000ea3, 0x00000ea5, 0x00000ea5, 0x00000ea7, 0x00000ea7, 0x00000eaa, 0x00000eab, 0x00000ead, 0x00000eb0, 0x00000eb2, 0x00000eb3, 0x00000ebd, 0x00000ebd, 0x00000ec0, 0x00000ec4, 0x00000edc, 0x00000edd, 0x00000f00, 0x00000f00, 0x00000f40, 0x00000f47, 0x00000f49, 0x00000f6a, 0x00000f88, 0x00000f8b, 0x00001000, 0x00001021, 0x00001023, 0x00001027, 0x00001029, 0x0000102a, 0x00001050, 0x00001055, 0x000010d0, 0x000010f8, 0x00001100, 0x00001159, 0x0000115f, 0x000011a2, 0x000011a8, 0x000011f9, 0x00001200, 0x00001206, 0x00001208, 0x00001246, 0x00001248, 0x00001248, 0x0000124a, 0x0000124d, 0x00001250, 0x00001256, 0x00001258, 0x00001258, 0x0000125a, 0x0000125d, 0x00001260, 0x00001286, 0x00001288, 0x00001288, 0x0000128a, 0x0000128d, 0x00001290, 0x000012ae, 0x000012b0, 0x000012b0, 0x000012b2, 0x000012b5, 0x000012b8, 0x000012be, 0x000012c0, 0x000012c0, 0x000012c2, 0x000012c5, 0x000012c8, 0x000012ce, 0x000012d0, 0x000012d6, 0x000012d8, 0x000012ee, 0x000012f0, 0x0000130e, 0x00001310, 0x00001310, 0x00001312, 0x00001315, 0x00001318, 0x0000131e, 0x00001320, 0x00001346, 0x00001348, 0x0000135a, 0x000013a0, 0x000013f4, 0x00001401, 0x0000166c, 0x0000166f, 0x00001676, 0x00001681, 0x0000169a, 0x000016a0, 0x000016ea, 0x00001700, 0x0000170c, 0x0000170e, 0x00001711, 0x00001720, 0x00001731, 0x00001740, 0x00001751, 0x00001760, 0x0000176c, 0x0000176e, 0x00001770, 0x00001780, 0x000017b3, 0x000017dc, 0x000017dc, 0x00001820, 0x00001842, 0x00001844, 0x00001877, 0x00001880, 0x000018a8, 0x00002135, 0x00002138, 0x00003006, 0x00003006, 0x0000303c, 0x0000303c, 0x00003041, 0x00003096, 0x0000309f, 0x0000309f, 0x000030a1, 0x000030fa, 0x000030ff, 0x000030ff, 0x00003105, 0x0000312c, 0x00003131, 0x0000318e, 0x000031a0, 0x000031b7, 0x000031f0, 0x000031ff, 0x00003400, 0x00004db5, 0x00004e00, 0x0000a48c, 0x0000ac00, 0x0000d7a3, 0x0000f900, 0x0000faff, 0x0000fb1d, 0x0000fb1d, 0x0000fb1f, 0x0000fb28, 0x0000fb2a, 0x0000fb36, 0x0000fb38, 0x0000fb3c, 0x0000fb3e, 0x0000fb3e, 0x0000fb40, 0x0000fb41, 0x0000fb43, 0x0000fb44, 0x0000fb46, 0x0000fbb1, 0x0000fbd3, 0x0000fd3d, 0x0000fd50, 0x0000fd8f, 0x0000fd92, 0x0000fdc7, 0x0000fdf0, 0x0000fdfb, 0x0000fe70, 0x0000fe74, 0x0000fe76, 0x0000fefc, 0x0000ff66, 0x0000ff6f, 0x0000ff71, 0x0000ff9d, 0x0000ffa0, 0x0000ffbe, 0x0000ffc2, 0x0000ffc7, 0x0000ffca, 0x0000ffcf, 0x0000ffd2, 0x0000ffd7, 0x0000ffda, 0x0000ffdc, 0x00010300, 0x0001031e, 0x00010330, 0x00010349, 0x00020000, 0x0002a6d6, 0x0002f800, 0x0002fa1d, 0x0000005f, 0x0000005f, 0x0000203f, 0x00002040, 0x000030fb, 0x000030fb, 0x0000fe33, 0x0000fe34, 0x0000fe4d, 0x0000fe4f, 0x0000ff3f, 0x0000ff3f, 0x0000ff65, 0x0000ff65, 0x0000002d, 0x0000002d, 0x000000ad, 0x000000ad, 0x0000058a, 0x0000058a, 0x00001806, 0x00001806, 0x00002010, 0x00002015, 0x0000301c, 0x0000301c, 0x00003030, 0x00003030, 0x000030a0, 0x000030a0, 0x0000fe31, 0x0000fe32, 0x0000fe58, 0x0000fe58, 0x0000fe63, 0x0000fe63, 0x0000ff0d, 0x0000ff0d, 0x00000028, 0x00000028, 0x0000005b, 0x0000005b, 0x0000007b, 0x0000007b, 0x00000f3a, 0x00000f3a, 0x00000f3c, 0x00000f3c, 0x0000169b, 0x0000169b, 0x0000201a, 0x0000201a, 0x0000201e, 0x0000201e, 0x00002045, 0x00002045, 0x0000207d, 0x0000207d, 0x0000208d, 0x0000208d, 0x00002329, 0x00002329, 0x000023b4, 0x000023b4, 0x00002768, 0x00002768, 0x0000276a, 0x0000276a, 0x0000276c, 0x0000276c, 0x0000276e, 0x0000276e, 0x00002770, 0x00002770, 0x00002772, 0x00002772, 0x00002774, 0x00002774, 0x000027e6, 0x000027e6, 0x000027e8, 0x000027e8, 0x000027ea, 0x000027ea, 0x00002983, 0x00002983, 0x00002985, 0x00002985, 0x00002987, 0x00002987, 0x00002989, 0x00002989, 0x0000298b, 0x0000298b, 0x0000298d, 0x0000298d, 0x0000298f, 0x0000298f, 0x00002991, 0x00002991, 0x00002993, 0x00002993, 0x00002995, 0x00002995, 0x00002997, 0x00002997, 0x000029d8, 0x000029d8, 0x000029da, 0x000029da, 0x000029fc, 0x000029fc, 0x00003008, 0x00003008, 0x0000300a, 0x0000300a, 0x0000300c, 0x0000300c, 0x0000300e, 0x0000300e, 0x00003010, 0x00003010, 0x00003014, 0x00003014, 0x00003016, 0x00003016, 0x00003018, 0x00003018, 0x0000301a, 0x0000301a, 0x0000301d, 0x0000301d, 0x0000fd3e, 0x0000fd3e, 0x0000fe35, 0x0000fe35, 0x0000fe37, 0x0000fe37, 0x0000fe39, 0x0000fe39, 0x0000fe3b, 0x0000fe3b, 0x0000fe3d, 0x0000fe3d, 0x0000fe3f, 0x0000fe3f, 0x0000fe41, 0x0000fe41, 0x0000fe43, 0x0000fe43, 0x0000fe59, 0x0000fe59, 0x0000fe5b, 0x0000fe5b, 0x0000fe5d, 0x0000fe5d, 0x0000ff08, 0x0000ff08, 0x0000ff3b, 0x0000ff3b, 0x0000ff5b, 0x0000ff5b, 0x0000ff5f, 0x0000ff5f, 0x0000ff62, 0x0000ff62, 0x00000029, 0x00000029, 0x0000005d, 0x0000005d, 0x0000007d, 0x0000007d, 0x00000f3b, 0x00000f3b, 0x00000f3d, 0x00000f3d, 0x0000169c, 0x0000169c, 0x00002046, 0x00002046, 0x0000207e, 0x0000207e, 0x0000208e, 0x0000208e, 0x0000232a, 0x0000232a, 0x000023b5, 0x000023b5, 0x00002769, 0x00002769, 0x0000276b, 0x0000276b, 0x0000276d, 0x0000276d, 0x0000276f, 0x0000276f, 0x00002771, 0x00002771, 0x00002773, 0x00002773, 0x00002775, 0x00002775, 0x000027e7, 0x000027e7, 0x000027e9, 0x000027e9, 0x000027eb, 0x000027eb, 0x00002984, 0x00002984, 0x00002986, 0x00002986, 0x00002988, 0x00002988, 0x0000298a, 0x0000298a, 0x0000298c, 0x0000298c, 0x0000298e, 0x0000298e, 0x00002990, 0x00002990, 0x00002992, 0x00002992, 0x00002994, 0x00002994, 0x00002996, 0x00002996, 0x00002998, 0x00002998, 0x000029d9, 0x000029d9, 0x000029db, 0x000029db, 0x000029fd, 0x000029fd, 0x00003009, 0x00003009, 0x0000300b, 0x0000300b, 0x0000300d, 0x0000300d, 0x0000300f, 0x0000300f, 0x00003011, 0x00003011, 0x00003015, 0x00003015, 0x00003017, 0x00003017, 0x00003019, 0x00003019, 0x0000301b, 0x0000301b, 0x0000301e, 0x0000301f, 0x0000fd3f, 0x0000fd3f, 0x0000fe36, 0x0000fe36, 0x0000fe38, 0x0000fe38, 0x0000fe3a, 0x0000fe3a, 0x0000fe3c, 0x0000fe3c, 0x0000fe3e, 0x0000fe3e, 0x0000fe40, 0x0000fe40, 0x0000fe42, 0x0000fe42, 0x0000fe44, 0x0000fe44, 0x0000fe5a, 0x0000fe5a, 0x0000fe5c, 0x0000fe5c, 0x0000fe5e, 0x0000fe5e, 0x0000ff09, 0x0000ff09, 0x0000ff3d, 0x0000ff3d, 0x0000ff5d, 0x0000ff5d, 0x0000ff60, 0x0000ff60, 0x0000ff63, 0x0000ff63, 0x00000021, 0x00000023, 0x00000025, 0x00000027, 0x0000002a, 0x0000002a, 0x0000002c, 0x0000002c, 0x0000002e, 0x0000002f, 0x0000003a, 0x0000003b, 0x0000003f, 0x00000040, 0x0000005c, 0x0000005c, 0x000000a1, 0x000000a1, 0x000000b7, 0x000000b7, 0x000000bf, 0x000000bf, 0x0000037e, 0x0000037e, 0x00000387, 0x00000387, 0x0000055a, 0x0000055f, 0x00000589, 0x00000589, 0x000005be, 0x000005be, 0x000005c0, 0x000005c0, 0x000005c3, 0x000005c3, 0x000005f3, 0x000005f4, 0x0000060c, 0x0000060c, 0x0000061b, 0x0000061b, 0x0000061f, 0x0000061f, 0x0000066a, 0x0000066d, 0x000006d4, 0x000006d4, 0x00000700, 0x0000070d, 0x00000964, 0x00000965, 0x00000970, 0x00000970, 0x00000df4, 0x00000df4, 0x00000e4f, 0x00000e4f, 0x00000e5a, 0x00000e5b, 0x00000f04, 0x00000f12, 0x00000f85, 0x00000f85, 0x0000104a, 0x0000104f, 0x000010fb, 0x000010fb, 0x00001361, 0x00001368, 0x0000166d, 0x0000166e, 0x000016eb, 0x000016ed, 0x00001735, 0x00001736, 0x000017d4, 0x000017d6, 0x000017d8, 0x000017da, 0x00001800, 0x00001805, 0x00001807, 0x0000180a, 0x00002016, 0x00002017, 0x00002020, 0x00002027, 0x00002030, 0x00002038, 0x0000203b, 0x0000203e, 0x00002041, 0x00002043, 0x00002047, 0x00002051, 0x00002057, 0x00002057, 0x000023b6, 0x000023b6, 0x00003001, 0x00003003, 0x0000303d, 0x0000303d, 0x0000fe30, 0x0000fe30, 0x0000fe45, 0x0000fe46, 0x0000fe49, 0x0000fe4c, 0x0000fe50, 0x0000fe52, 0x0000fe54, 0x0000fe57, 0x0000fe5f, 0x0000fe61, 0x0000fe68, 0x0000fe68, 0x0000fe6a, 0x0000fe6b, 0x0000ff01, 0x0000ff03, 0x0000ff05, 0x0000ff07, 0x0000ff0a, 0x0000ff0a, 0x0000ff0c, 0x0000ff0c, 0x0000ff0e, 0x0000ff0f, 0x0000ff1a, 0x0000ff1b, 0x0000ff1f, 0x0000ff20, 0x0000ff3c, 0x0000ff3c, 0x0000ff61, 0x0000ff61, 0x0000ff64, 0x0000ff64, 0x0000002b, 0x0000002b, 0x0000003c, 0x0000003e, 0x0000007c, 0x0000007c, 0x0000007e, 0x0000007e, 0x000000ac, 0x000000ac, 0x000000b1, 0x000000b1, 0x000000d7, 0x000000d7, 0x000000f7, 0x000000f7, 0x000003f6, 0x000003f6, 0x00002044, 0x00002044, 0x00002052, 0x00002052, 0x0000207a, 0x0000207c, 0x0000208a, 0x0000208c, 0x00002140, 0x00002144, 0x0000214b, 0x0000214b, 0x00002190, 0x00002194, 0x0000219a, 0x0000219b, 0x000021a0, 0x000021a0, 0x000021a3, 0x000021a3, 0x000021a6, 0x000021a6, 0x000021ae, 0x000021ae, 0x000021ce, 0x000021cf, 0x000021d2, 0x000021d2, 0x000021d4, 0x000021d4, 0x000021f4, 0x000022ff, 0x00002308, 0x0000230b, 0x00002320, 0x00002321, 0x0000237c, 0x0000237c, 0x0000239b, 0x000023b3, 0x000025b7, 0x000025b7, 0x000025c1, 0x000025c1, 0x000025f8, 0x000025ff, 0x0000266f, 0x0000266f, 0x000027d0, 0x000027e5, 0x000027f0, 0x000027ff, 0x00002900, 0x00002982, 0x00002999, 0x000029d7, 0x000029dc, 0x000029fb, 0x000029fe, 0x00002aff, 0x0000fb29, 0x0000fb29, 0x0000fe62, 0x0000fe62, 0x0000fe64, 0x0000fe66, 0x0000ff0b, 0x0000ff0b, 0x0000ff1c, 0x0000ff1e, 0x0000ff5c, 0x0000ff5c, 0x0000ff5e, 0x0000ff5e, 0x0000ffe2, 0x0000ffe2, 0x0000ffe9, 0x0000ffec, 0x0001d6c1, 0x0001d6c1, 0x0001d6db, 0x0001d6db, 0x0001d6fb, 0x0001d6fb, 0x0001d715, 0x0001d715, 0x0001d735, 0x0001d735, 0x0001d74f, 0x0001d74f, 0x0001d76f, 0x0001d76f, 0x0001d789, 0x0001d789, 0x0001d7a9, 0x0001d7a9, 0x0001d7c3, 0x0001d7c3, 0x00000024, 0x00000024, 0x000000a2, 0x000000a5, 0x000009f2, 0x000009f3, 0x00000e3f, 0x00000e3f, 0x000017db, 0x000017db, 0x000020a0, 0x000020b1, 0x0000fdfc, 0x0000fdfc, 0x0000fe69, 0x0000fe69, 0x0000ff04, 0x0000ff04, 0x0000ffe0, 0x0000ffe1, 0x0000ffe5, 0x0000ffe6, 0x0000005e, 0x0000005e, 0x00000060, 0x00000060, 0x000000a8, 0x000000a8, 0x000000af, 0x000000af, 0x000000b4, 0x000000b4, 0x000000b8, 0x000000b8, 0x000002b9, 0x000002ba, 0x000002c2, 0x000002cf, 0x000002d2, 0x000002df, 0x000002e5, 0x000002ed, 0x00000374, 0x00000375, 0x00000384, 0x00000385, 0x00001fbd, 0x00001fbd, 0x00001fbf, 0x00001fc1, 0x00001fcd, 0x00001fcf, 0x00001fdd, 0x00001fdf, 0x00001fed, 0x00001fef, 0x00001ffd, 0x00001ffe, 0x0000309b, 0x0000309c, 0x0000ff3e, 0x0000ff3e, 0x0000ff40, 0x0000ff40, 0x0000ffe3, 0x0000ffe3, 0x000000a6, 0x000000a7, 0x000000a9, 0x000000a9, 0x000000ae, 0x000000ae, 0x000000b0, 0x000000b0, 0x000000b6, 0x000000b6, 0x00000482, 0x00000482, 0x000006e9, 0x000006e9, 0x000006fd, 0x000006fe, 0x000009fa, 0x000009fa, 0x00000b70, 0x00000b70, 0x00000f01, 0x00000f03, 0x00000f13, 0x00000f17, 0x00000f1a, 0x00000f1f, 0x00000f34, 0x00000f34, 0x00000f36, 0x00000f36, 0x00000f38, 0x00000f38, 0x00000fbe, 0x00000fc5, 0x00000fc7, 0x00000fcc, 0x00000fcf, 0x00000fcf, 0x00002100, 0x00002101, 0x00002103, 0x00002106, 0x00002108, 0x00002109, 0x00002114, 0x00002114, 0x00002116, 0x00002118, 0x0000211e, 0x00002123, 0x00002125, 0x00002125, 0x00002127, 0x00002127, 0x00002129, 0x00002129, 0x0000212e, 0x0000212e, 0x00002132, 0x00002132, 0x0000213a, 0x0000213a, 0x0000214a, 0x0000214a, 0x00002195, 0x00002199, 0x0000219c, 0x0000219f, 0x000021a1, 0x000021a2, 0x000021a4, 0x000021a5, 0x000021a7, 0x000021ad, 0x000021af, 0x000021cd, 0x000021d0, 0x000021d1, 0x000021d3, 0x000021d3, 0x000021d5, 0x000021f3, 0x00002300, 0x00002307, 0x0000230c, 0x0000231f, 0x00002322, 0x00002328, 0x0000232b, 0x0000237b, 0x0000237d, 0x0000239a, 0x000023b7, 0x000023ce, 0x00002400, 0x00002426, 0x00002440, 0x0000244a, 0x0000249c, 0x000024e9, 0x00002500, 0x000025b6, 0x000025b8, 0x000025c0, 0x000025c2, 0x000025f7, 0x00002600, 0x00002613, 0x00002616, 0x00002617, 0x00002619, 0x0000266e, 0x00002670, 0x0000267d, 0x00002680, 0x00002689, 0x00002701, 0x00002704, 0x00002706, 0x00002709, 0x0000270c, 0x00002727, 0x00002729, 0x0000274b, 0x0000274d, 0x0000274d, 0x0000274f, 0x00002752, 0x00002756, 0x00002756, 0x00002758, 0x0000275e, 0x00002761, 0x00002767, 0x00002794, 0x00002794, 0x00002798, 0x000027af, 0x000027b1, 0x000027be, 0x00002800, 0x000028ff, 0x00002e80, 0x00002e99, 0x00002e9b, 0x00002ef3, 0x00002f00, 0x00002fd5, 0x00002ff0, 0x00002ffb, 0x00003004, 0x00003004, 0x00003012, 0x00003013, 0x00003020, 0x00003020, 0x00003036, 0x00003037, 0x0000303e, 0x0000303f, 0x00003190, 0x00003191, 0x00003196, 0x0000319f, 0x00003200, 0x0000321c, 0x0000322a, 0x00003243, 0x00003260, 0x0000327b, 0x0000327f, 0x0000327f, 0x0000328a, 0x000032b0, 0x000032c0, 0x000032cb, 0x000032d0, 0x000032fe, 0x00003300, 0x00003376, 0x0000337b, 0x000033dd, 0x000033e0, 0x000033fe, 0x0000a490, 0x0000a4c6, 0x0000ffe4, 0x0000ffe4, 0x0000ffe8, 0x0000ffe8, 0x0000ffed, 0x0000ffee, 0x0000fffc, 0x0000fffd, 0x0001d000, 0x0001d0f5, 0x0001d100, 0x0001d126, 0x0001d12a, 0x0001d164, 0x0001d16a, 0x0001d16c, 0x0001d183, 0x0001d184, 0x0001d18c, 0x0001d1a9, 0x0001d1ae, 0x0001d1dd, 0x00000041, 0x0000005a, 0x00000061, 0x0000007a, 0x000000aa, 0x000000aa, 0x000000b5, 0x000000b5, 0x000000ba, 0x000000ba, 0x000000c0, 0x000000d6, 0x000000d8, 0x000000f6, 0x000000f8, 0x00000220, 0x00000222, 0x00000233, 0x00000250, 0x000002ad, 0x000002b0, 0x000002b8, 0x000002bb, 0x000002c1, 0x000002d0, 0x000002d1, 0x000002e0, 0x000002e4, 0x000002ee, 0x000002ee, 0x0000037a, 0x0000037a, 0x00000386, 0x00000386, 0x00000388, 0x0000038a, 0x0000038c, 0x0000038c, 0x0000038e, 0x000003a1, 0x000003a3, 0x000003ce, 0x000003d0, 0x000003f5, 0x00000400, 0x00000482, 0x0000048a, 0x000004ce, 0x000004d0, 0x000004f5, 0x000004f8, 0x000004f9, 0x00000500, 0x0000050f, 0x00000531, 0x00000556, 0x00000559, 0x0000055f, 0x00000561, 0x00000587, 0x00000589, 0x00000589, 0x00000903, 0x00000903, 0x00000905, 0x00000939, 0x0000093d, 0x00000940, 0x00000949, 0x0000094c, 0x00000950, 0x00000950, 0x00000958, 0x00000961, 0x00000964, 0x00000970, 0x00000982, 0x00000983, 0x00000985, 0x0000098c, 0x0000098f, 0x00000990, 0x00000993, 0x000009a8, 0x000009aa, 0x000009b0, 0x000009b2, 0x000009b2, 0x000009b6, 0x000009b9, 0x000009be, 0x000009c0, 0x000009c7, 0x000009c8, 0x000009cb, 0x000009cc, 0x000009d7, 0x000009d7, 0x000009dc, 0x000009dd, 0x000009df, 0x000009e1, 0x000009e6, 0x000009f1, 0x000009f4, 0x000009fa, 0x00000a05, 0x00000a0a, 0x00000a0f, 0x00000a10, 0x00000a13, 0x00000a28, 0x00000a2a, 0x00000a30, 0x00000a32, 0x00000a33, 0x00000a35, 0x00000a36, 0x00000a38, 0x00000a39, 0x00000a3e, 0x00000a40, 0x00000a59, 0x00000a5c, 0x00000a5e, 0x00000a5e, 0x00000a66, 0x00000a6f, 0x00000a72, 0x00000a74, 0x00000a83, 0x00000a83, 0x00000a85, 0x00000a8b, 0x00000a8d, 0x00000a8d, 0x00000a8f, 0x00000a91, 0x00000a93, 0x00000aa8, 0x00000aaa, 0x00000ab0, 0x00000ab2, 0x00000ab3, 0x00000ab5, 0x00000ab9, 0x00000abd, 0x00000ac0, 0x00000ac9, 0x00000ac9, 0x00000acb, 0x00000acc, 0x00000ad0, 0x00000ad0, 0x00000ae0, 0x00000ae0, 0x00000ae6, 0x00000aef, 0x00000b02, 0x00000b03, 0x00000b05, 0x00000b0c, 0x00000b0f, 0x00000b10, 0x00000b13, 0x00000b28, 0x00000b2a, 0x00000b30, 0x00000b32, 0x00000b33, 0x00000b36, 0x00000b39, 0x00000b3d, 0x00000b3e, 0x00000b40, 0x00000b40, 0x00000b47, 0x00000b48, 0x00000b4b, 0x00000b4c, 0x00000b57, 0x00000b57, 0x00000b5c, 0x00000b5d, 0x00000b5f, 0x00000b61, 0x00000b66, 0x00000b70, 0x00000b83, 0x00000b83, 0x00000b85, 0x00000b8a, 0x00000b8e, 0x00000b90, 0x00000b92, 0x00000b95, 0x00000b99, 0x00000b9a, 0x00000b9c, 0x00000b9c, 0x00000b9e, 0x00000b9f, 0x00000ba3, 0x00000ba4, 0x00000ba8, 0x00000baa, 0x00000bae, 0x00000bb5, 0x00000bb7, 0x00000bb9, 0x00000bbe, 0x00000bbf, 0x00000bc1, 0x00000bc2, 0x00000bc6, 0x00000bc8, 0x00000bca, 0x00000bcc, 0x00000bd7, 0x00000bd7, 0x00000be7, 0x00000bf2, 0x00000c01, 0x00000c03, 0x00000c05, 0x00000c0c, 0x00000c0e, 0x00000c10, 0x00000c12, 0x00000c28, 0x00000c2a, 0x00000c33, 0x00000c35, 0x00000c39, 0x00000c41, 0x00000c44, 0x00000c60, 0x00000c61, 0x00000c66, 0x00000c6f, 0x00000c82, 0x00000c83, 0x00000c85, 0x00000c8c, 0x00000c8e, 0x00000c90, 0x00000c92, 0x00000ca8, 0x00000caa, 0x00000cb3, 0x00000cb5, 0x00000cb9, 0x00000cbe, 0x00000cbe, 0x00000cc0, 0x00000cc4, 0x00000cc7, 0x00000cc8, 0x00000cca, 0x00000ccb, 0x00000cd5, 0x00000cd6, 0x00000cde, 0x00000cde, 0x00000ce0, 0x00000ce1, 0x00000ce6, 0x00000cef, 0x00000d02, 0x00000d03, 0x00000d05, 0x00000d0c, 0x00000d0e, 0x00000d10, 0x00000d12, 0x00000d28, 0x00000d2a, 0x00000d39, 0x00000d3e, 0x00000d40, 0x00000d46, 0x00000d48, 0x00000d4a, 0x00000d4c, 0x00000d57, 0x00000d57, 0x00000d60, 0x00000d61, 0x00000d66, 0x00000d6f, 0x00000d82, 0x00000d83, 0x00000d85, 0x00000d96, 0x00000d9a, 0x00000db1, 0x00000db3, 0x00000dbb, 0x00000dbd, 0x00000dbd, 0x00000dc0, 0x00000dc6, 0x00000dcf, 0x00000dd1, 0x00000dd8, 0x00000ddf, 0x00000df2, 0x00000df4, 0x00000e01, 0x00000e30, 0x00000e32, 0x00000e33, 0x00000e40, 0x00000e46, 0x00000e4f, 0x00000e5b, 0x00000e81, 0x00000e82, 0x00000e84, 0x00000e84, 0x00000e87, 0x00000e88, 0x00000e8a, 0x00000e8a, 0x00000e8d, 0x00000e8d, 0x00000e94, 0x00000e97, 0x00000e99, 0x00000e9f, 0x00000ea1, 0x00000ea3, 0x00000ea5, 0x00000ea5, 0x00000ea7, 0x00000ea7, 0x00000eaa, 0x00000eab, 0x00000ead, 0x00000eb0, 0x00000eb2, 0x00000eb3, 0x00000ebd, 0x00000ebd, 0x00000ec0, 0x00000ec4, 0x00000ec6, 0x00000ec6, 0x00000ed0, 0x00000ed9, 0x00000edc, 0x00000edd, 0x00000f00, 0x00000f17, 0x00000f1a, 0x00000f34, 0x00000f36, 0x00000f36, 0x00000f38, 0x00000f38, 0x00000f3e, 0x00000f47, 0x00000f49, 0x00000f6a, 0x00000f7f, 0x00000f7f, 0x00000f85, 0x00000f85, 0x00000f88, 0x00000f8b, 0x00000fbe, 0x00000fc5, 0x00000fc7, 0x00000fcc, 0x00000fcf, 0x00000fcf, 0x00001000, 0x00001021, 0x00001023, 0x00001027, 0x00001029, 0x0000102a, 0x0000102c, 0x0000102c, 0x00001031, 0x00001031, 0x00001038, 0x00001038, 0x00001040, 0x00001057, 0x000010a0, 0x000010c5, 0x000010d0, 0x000010f8, 0x000010fb, 0x000010fb, 0x00001100, 0x00001159, 0x0000115f, 0x000011a2, 0x000011a8, 0x000011f9, 0x00001200, 0x00001206, 0x00001208, 0x00001246, 0x00001248, 0x00001248, 0x0000124a, 0x0000124d, 0x00001250, 0x00001256, 0x00001258, 0x00001258, 0x0000125a, 0x0000125d, 0x00001260, 0x00001286, 0x00001288, 0x00001288, 0x0000128a, 0x0000128d, 0x00001290, 0x000012ae, 0x000012b0, 0x000012b0, 0x000012b2, 0x000012b5, 0x000012b8, 0x000012be, 0x000012c0, 0x000012c0, 0x000012c2, 0x000012c5, 0x000012c8, 0x000012ce, 0x000012d0, 0x000012d6, 0x000012d8, 0x000012ee, 0x000012f0, 0x0000130e, 0x00001310, 0x00001310, 0x00001312, 0x00001315, 0x00001318, 0x0000131e, 0x00001320, 0x00001346, 0x00001348, 0x0000135a, 0x00001361, 0x0000137c, 0x000013a0, 0x000013f4, 0x00001401, 0x00001676, 0x00001681, 0x0000169a, 0x000016a0, 0x000016f0, 0x00001700, 0x0000170c, 0x0000170e, 0x00001711, 0x00001720, 0x00001731, 0x00001735, 0x00001736, 0x00001740, 0x00001751, 0x00001760, 0x0000176c, 0x0000176e, 0x00001770, 0x00001780, 0x000017b6, 0x000017be, 0x000017c5, 0x000017c7, 0x000017c8, 0x000017d4, 0x000017da, 0x000017dc, 0x000017dc, 0x000017e0, 0x000017e9, 0x00001810, 0x00001819, 0x00001820, 0x00001877, 0x00001880, 0x000018a8, 0x00001e00, 0x00001e9b, 0x00001ea0, 0x00001ef9, 0x00001f00, 0x00001f15, 0x00001f18, 0x00001f1d, 0x00001f20, 0x00001f45, 0x00001f48, 0x00001f4d, 0x00001f50, 0x00001f57, 0x00001f59, 0x00001f59, 0x00001f5b, 0x00001f5b, 0x00001f5d, 0x00001f5d, 0x00001f5f, 0x00001f7d, 0x00001f80, 0x00001fb4, 0x00001fb6, 0x00001fbc, 0x00001fbe, 0x00001fbe, 0x00001fc2, 0x00001fc4, 0x00001fc6, 0x00001fcc, 0x00001fd0, 0x00001fd3, 0x00001fd6, 0x00001fdb, 0x00001fe0, 0x00001fec, 0x00001ff2, 0x00001ff4, 0x00001ff6, 0x00001ffc, 0x0000200e, 0x0000200e, 0x00002071, 0x00002071, 0x0000207f, 0x0000207f, 0x00002102, 0x00002102, 0x00002107, 0x00002107, 0x0000210a, 0x00002113, 0x00002115, 0x00002115, 0x00002119, 0x0000211d, 0x00002124, 0x00002124, 0x00002126, 0x00002126, 0x00002128, 0x00002128, 0x0000212a, 0x0000212d, 0x0000212f, 0x00002131, 0x00002133, 0x00002139, 0x0000213d, 0x0000213f, 0x00002145, 0x00002149, 0x00002160, 0x00002183, 0x00002336, 0x0000237a, 0x00002395, 0x00002395, 0x0000249c, 0x000024e9, 0x00003005, 0x00003007, 0x00003021, 0x00003029, 0x00003031, 0x00003035, 0x00003038, 0x0000303c, 0x00003041, 0x00003096, 0x0000309d, 0x0000309f, 0x000030a1, 0x000030fa, 0x000030fc, 0x000030ff, 0x00003105, 0x0000312c, 0x00003131, 0x0000318e, 0x00003190, 0x000031b7, 0x000031f0, 0x0000321c, 0x00003220, 0x00003243, 0x00003260, 0x0000327b, 0x0000327f, 0x000032b0, 0x000032c0, 0x000032cb, 0x000032d0, 0x000032fe, 0x00003300, 0x00003376, 0x0000337b, 0x000033dd, 0x000033e0, 0x000033fe, 0x00003400, 0x00004db5, 0x00004e00, 0x0000a48c, 0x0000ac00, 0x0000d7a3, 0x0000e000, 0x0000fb06, 0x0000fb13, 0x0000fb17, 0x0000ff21, 0x0000ff3a, 0x0000ff41, 0x0000ff5a, 0x0000ff66, 0x0000ffbe, 0x0000ffc2, 0x0000ffc7, 0x0000ffca, 0x0000ffcf, 0x0000ffd2, 0x0000ffd7, 0x0000ffda, 0x0000ffdc, 0x00010000, 0x0002a6d6, 0x0002f800, 0x0002fa1d, 0x000f0000, 0x000ffffd, 0x00100000, 0x0010fffd, 0x000005be, 0x000005be, 0x000005c0, 0x000005c0, 0x000005c3, 0x000005c3, 0x000005d0, 0x000005ea, 0x000005f0, 0x000005f4, 0x0000200f, 0x0000200f, 0x0000fb1d, 0x0000fb1d, 0x0000fb1f, 0x0000fb28, 0x0000fb2a, 0x0000fb36, 0x0000fb38, 0x0000fb3c, 0x0000fb3e, 0x0000fb3e, 0x0000fb40, 0x0000fb41, 0x0000fb43, 0x0000fb44, 0x0000fb46, 0x0000fb4f, 0x00000030, 0x00000039, 0x000000b2, 0x000000b3, 0x000000b9, 0x000000b9, 0x000006f0, 0x000006f9, 0x00002070, 0x00002070, 0x00002074, 0x00002079, 0x00002080, 0x00002089, 0x00002460, 0x0000249b, 0x000024ea, 0x000024ea, 0x0000ff10, 0x0000ff19, 0x0001d7ce, 0x0001d7ff, 0x0000002f, 0x0000002f, 0x0000ff0f, 0x0000ff0f, 0x00000023, 0x00000025, 0x0000002b, 0x0000002b, 0x0000002d, 0x0000002d, 0x000000a2, 0x000000a5, 0x000000b0, 0x000000b1, 0x0000066a, 0x0000066a, 0x000009f2, 0x000009f3, 0x00000e3f, 0x00000e3f, 0x000017db, 0x000017db, 0x00002030, 0x00002034, 0x0000207a, 0x0000207b, 0x0000208a, 0x0000208b, 0x000020a0, 0x000020b1, 0x0000212e, 0x0000212e, 0x00002212, 0x00002213, 0x0000fb29, 0x0000fb29, 0x0000fe5f, 0x0000fe5f, 0x0000fe62, 0x0000fe63, 0x0000fe69, 0x0000fe6a, 0x0000ff03, 0x0000ff05, 0x0000ff0b, 0x0000ff0b, 0x0000ff0d, 0x0000ff0d, 0x0000ffe0, 0x0000ffe1, 0x0000ffe5, 0x0000ffe6, 0x00000660, 0x00000669, 0x0000066b, 0x0000066c, 0x0000002c, 0x0000002c, 0x0000002e, 0x0000002e, 0x0000003a, 0x0000003a, 0x000000a0, 0x000000a0, 0x0000060c, 0x0000060c, 0x0000fe50, 0x0000fe50, 0x0000fe52, 0x0000fe52, 0x0000fe55, 0x0000fe55, 0x0000ff0c, 0x0000ff0c, 0x0000ff0e, 0x0000ff0e, 0x0000ff1a, 0x0000ff1a, 0x0000000a, 0x0000000a, 0x0000000d, 0x0000000d, 0x0000001c, 0x0000001e, 0x00000085, 0x00000085, 0x00002029, 0x00002029, 0x00000009, 0x00000009, 0x0000000b, 0x0000000b, 0x0000001f, 0x0000001f, 0x0000000c, 0x0000000c, 0x00000020, 0x00000020, 0x00001680, 0x00001680, 0x00002000, 0x0000200a, 0x00002028, 0x00002028, 0x0000202f, 0x0000202f, 0x0000205f, 0x0000205f, 0x00003000, 0x00003000, 0x00000000, 0x00000008, 0x0000000e, 0x0000001b, 0x00000021, 0x00000022, 0x00000026, 0x0000002a, 0x0000003b, 0x00000040, 0x0000005b, 0x00000060, 0x0000007b, 0x00000084, 0x00000086, 0x0000009f, 0x000000a1, 0x000000a1, 0x000000a6, 0x000000a9, 0x000000ab, 0x000000af, 0x000000b4, 0x000000b4, 0x000000b6, 0x000000b8, 0x000000bb, 0x000000bf, 0x000000d7, 0x000000d7, 0x000000f7, 0x000000f7, 0x000002b9, 0x000002ba, 0x000002c2, 0x000002cf, 0x000002d2, 0x000002df, 0x000002e5, 0x000002ed, 0x00000300, 0x0000034f, 0x00000360, 0x0000036f, 0x00000374, 0x00000375, 0x0000037e, 0x0000037e, 0x00000384, 0x00000385, 0x00000387, 0x00000387, 0x000003f6, 0x000003f6, 0x00000483, 0x00000486, 0x00000488, 0x00000489, 0x0000058a, 0x0000058a, 0x00000591, 0x000005a1, 0x000005a3, 0x000005b9, 0x000005bb, 0x000005bd, 0x000005bf, 0x000005bf, 0x000005c1, 0x000005c2, 0x000005c4, 0x000005c4, 0x0000064b, 0x00000655, 0x00000670, 0x00000670, 0x000006d6, 0x000006dc, 0x000006de, 0x000006e4, 0x000006e7, 0x000006ed, 0x0000070f, 0x0000070f, 0x00000711, 0x00000711, 0x00000730, 0x0000074a, 0x000007a6, 0x000007b0, 0x00000901, 0x00000902, 0x0000093c, 0x0000093c, 0x00000941, 0x00000948, 0x0000094d, 0x0000094d, 0x00000951, 0x00000954, 0x00000962, 0x00000963, 0x00000981, 0x00000981, 0x000009bc, 0x000009bc, 0x000009c1, 0x000009c4, 0x000009cd, 0x000009cd, 0x000009e2, 0x000009e3, 0x00000a02, 0x00000a02, 0x00000a3c, 0x00000a3c, 0x00000a41, 0x00000a42, 0x00000a47, 0x00000a48, 0x00000a4b, 0x00000a4d, 0x00000a70, 0x00000a71, 0x00000a81, 0x00000a82, 0x00000abc, 0x00000abc, 0x00000ac1, 0x00000ac5, 0x00000ac7, 0x00000ac8, 0x00000acd, 0x00000acd, 0x00000b01, 0x00000b01, 0x00000b3c, 0x00000b3c, 0x00000b3f, 0x00000b3f, 0x00000b41, 0x00000b43, 0x00000b4d, 0x00000b4d, 0x00000b56, 0x00000b56, 0x00000b82, 0x00000b82, 0x00000bc0, 0x00000bc0, 0x00000bcd, 0x00000bcd, 0x00000c3e, 0x00000c40, 0x00000c46, 0x00000c48, 0x00000c4a, 0x00000c4d, 0x00000c55, 0x00000c56, 0x00000cbf, 0x00000cbf, 0x00000cc6, 0x00000cc6, 0x00000ccc, 0x00000ccd, 0x00000d41, 0x00000d43, 0x00000d4d, 0x00000d4d, 0x00000dca, 0x00000dca, 0x00000dd2, 0x00000dd4, 0x00000dd6, 0x00000dd6, 0x00000e31, 0x00000e31, 0x00000e34, 0x00000e3a, 0x00000e47, 0x00000e4e, 0x00000eb1, 0x00000eb1, 0x00000eb4, 0x00000eb9, 0x00000ebb, 0x00000ebc, 0x00000ec8, 0x00000ecd, 0x00000f18, 0x00000f19, 0x00000f35, 0x00000f35, 0x00000f37, 0x00000f37, 0x00000f39, 0x00000f3d, 0x00000f71, 0x00000f7e, 0x00000f80, 0x00000f84, 0x00000f86, 0x00000f87, 0x00000f90, 0x00000f97, 0x00000f99, 0x00000fbc, 0x00000fc6, 0x00000fc6, 0x0000102d, 0x00001030, 0x00001032, 0x00001032, 0x00001036, 0x00001037, 0x00001039, 0x00001039, 0x00001058, 0x00001059, 0x0000169b, 0x0000169c, 0x00001712, 0x00001714, 0x00001732, 0x00001734, 0x00001752, 0x00001753, 0x00001772, 0x00001773, 0x000017b7, 0x000017bd, 0x000017c6, 0x000017c6, 0x000017c9, 0x000017d3, 0x00001800, 0x0000180e, 0x000018a9, 0x000018a9, 0x00001fbd, 0x00001fbd, 0x00001fbf, 0x00001fc1, 0x00001fcd, 0x00001fcf, 0x00001fdd, 0x00001fdf, 0x00001fed, 0x00001fef, 0x00001ffd, 0x00001ffe, 0x0000200b, 0x0000200d, 0x00002010, 0x00002027, 0x0000202a, 0x0000202e, 0x00002035, 0x00002052, 0x00002057, 0x00002057, 0x00002060, 0x00002063, 0x0000206a, 0x0000206f, 0x0000207c, 0x0000207e, 0x0000208c, 0x0000208e, 0x000020d0, 0x000020ea, 0x00002100, 0x00002101, 0x00002103, 0x00002106, 0x00002108, 0x00002109, 0x00002114, 0x00002114, 0x00002116, 0x00002118, 0x0000211e, 0x00002123, 0x00002125, 0x00002125, 0x00002127, 0x00002127, 0x00002129, 0x00002129, 0x00002132, 0x00002132, 0x0000213a, 0x0000213a, 0x00002140, 0x00002144, 0x0000214a, 0x0000214b, 0x00002153, 0x0000215f, 0x00002190, 0x00002211, 0x00002214, 0x00002335, 0x0000237b, 0x00002394, 0x00002396, 0x000023ce, 0x00002400, 0x00002426, 0x00002440, 0x0000244a, 0x000024eb, 0x000024fe, 0x00002500, 0x00002613, 0x00002616, 0x00002617, 0x00002619, 0x0000267d, 0x00002680, 0x00002689, 0x00002701, 0x00002704, 0x00002706, 0x00002709, 0x0000270c, 0x00002727, 0x00002729, 0x0000274b, 0x0000274d, 0x0000274d, 0x0000274f, 0x00002752, 0x00002756, 0x00002756, 0x00002758, 0x0000275e, 0x00002761, 0x00002794, 0x00002798, 0x000027af, 0x000027b1, 0x000027be, 0x000027d0, 0x000027eb, 0x000027f0, 0x00002aff, 0x00002e80, 0x00002e99, 0x00002e9b, 0x00002ef3, 0x00002f00, 0x00002fd5, 0x00002ff0, 0x00002ffb, 0x00003001, 0x00003004, 0x00003008, 0x00003020, 0x0000302a, 0x00003030, 0x00003036, 0x00003037, 0x0000303d, 0x0000303f, 0x00003099, 0x0000309c, 0x000030a0, 0x000030a0, 0x000030fb, 0x000030fb, 0x00003251, 0x0000325f, 0x000032b1, 0x000032bf, 0x0000a490, 0x0000a4c6, 0x0000fb1e, 0x0000fb1e, 0x0000fd3e, 0x0000fd3f, 0x0000fe00, 0x0000fe0f, 0x0000fe20, 0x0000fe23, 0x0000fe30, 0x0000fe46, 0x0000fe49, 0x0000fe4f, 0x0000fe51, 0x0000fe51, 0x0000fe54, 0x0000fe54, 0x0000fe56, 0x0000fe5e, 0x0000fe60, 0x0000fe61, 0x0000fe64, 0x0000fe66, 0x0000fe68, 0x0000fe68, 0x0000fe6b, 0x0000fe6b, 0x0000feff, 0x0000feff, 0x0000ff01, 0x0000ff02, 0x0000ff06, 0x0000ff0a, 0x0000ff1b, 0x0000ff20, 0x0000ff3b, 0x0000ff40, 0x0000ff5b, 0x0000ff65, 0x0000ffe2, 0x0000ffe4, 0x0000ffe8, 0x0000ffee, 0x0000fff9, 0x0000fffd, 0x0001d167, 0x0001d169, 0x0001d173, 0x0001d182, 0x0001d185, 0x0001d18b, 0x0001d1aa, 0x0001d1ad, 0x000e0001, 0x000e0001, 0x000e0020, 0x000e007f, 0x000000c0, 0x000000c5, 0x000000c7, 0x000000cf, 0x000000d1, 0x000000d6, 0x000000d9, 0x000000dd, 0x000000e0, 0x000000e5, 0x000000e7, 0x000000ef, 0x000000f1, 0x000000f6, 0x000000f9, 0x000000fd, 0x000000ff, 0x0000010f, 0x00000112, 0x00000125, 0x00000128, 0x00000130, 0x00000134, 0x00000137, 0x00000139, 0x0000013e, 0x00000143, 0x00000148, 0x0000014c, 0x00000151, 0x00000154, 0x00000165, 0x00000168, 0x0000017e, 0x000001a0, 0x000001a1, 0x000001af, 0x000001b0, 0x000001cd, 0x000001dc, 0x000001de, 0x000001e3, 0x000001e6, 0x000001f0, 0x000001f4, 0x000001f5, 0x000001f8, 0x0000021b, 0x0000021e, 0x0000021f, 0x00000226, 0x00000233, 0x00000340, 0x00000341, 0x00000343, 0x00000344, 0x00000374, 0x00000374, 0x0000037e, 0x0000037e, 0x00000385, 0x0000038a, 0x0000038c, 0x0000038c, 0x0000038e, 0x00000390, 0x000003aa, 0x000003b0, 0x000003ca, 0x000003ce, 0x000003d3, 0x000003d4, 0x00000400, 0x00000401, 0x00000403, 0x00000403, 0x00000407, 0x00000407, 0x0000040c, 0x0000040e, 0x00000419, 0x00000419, 0x00000439, 0x00000439, 0x00000450, 0x00000451, 0x00000453, 0x00000453, 0x00000457, 0x00000457, 0x0000045c, 0x0000045e, 0x00000476, 0x00000477, 0x000004c1, 0x000004c2, 0x000004d0, 0x000004d3, 0x000004d6, 0x000004d7, 0x000004da, 0x000004df, 0x000004e2, 0x000004e7, 0x000004ea, 0x000004f5, 0x000004f8, 0x000004f9, 0x00000622, 0x00000626, 0x000006c0, 0x000006c0, 0x000006c2, 0x000006c2, 0x000006d3, 0x000006d3, 0x00000929, 0x00000929, 0x00000931, 0x00000931, 0x00000934, 0x00000934, 0x00000958, 0x0000095f, 0x000009cb, 0x000009cc, 0x000009dc, 0x000009dd, 0x000009df, 0x000009df, 0x00000a33, 0x00000a33, 0x00000a36, 0x00000a36, 0x00000a59, 0x00000a5b, 0x00000a5e, 0x00000a5e, 0x00000b48, 0x00000b48, 0x00000b4b, 0x00000b4c, 0x00000b5c, 0x00000b5d, 0x00000b94, 0x00000b94, 0x00000bca, 0x00000bcc, 0x00000c48, 0x00000c48, 0x00000cc0, 0x00000cc0, 0x00000cc7, 0x00000cc8, 0x00000cca, 0x00000ccb, 0x00000d4a, 0x00000d4c, 0x00000dda, 0x00000dda, 0x00000ddc, 0x00000dde, 0x00000f43, 0x00000f43, 0x00000f4d, 0x00000f4d, 0x00000f52, 0x00000f52, 0x00000f57, 0x00000f57, 0x00000f5c, 0x00000f5c, 0x00000f69, 0x00000f69, 0x00000f73, 0x00000f73, 0x00000f75, 0x00000f76, 0x00000f78, 0x00000f78, 0x00000f81, 0x00000f81, 0x00000f93, 0x00000f93, 0x00000f9d, 0x00000f9d, 0x00000fa2, 0x00000fa2, 0x00000fa7, 0x00000fa7, 0x00000fac, 0x00000fac, 0x00000fb9, 0x00000fb9, 0x00001026, 0x00001026, 0x00001e00, 0x00001e99, 0x00001e9b, 0x00001e9b, 0x00001ea0, 0x00001ef9, 0x00001f00, 0x00001f15, 0x00001f18, 0x00001f1d, 0x00001f20, 0x00001f45, 0x00001f48, 0x00001f4d, 0x00001f50, 0x00001f57, 0x00001f59, 0x00001f59, 0x00001f5b, 0x00001f5b, 0x00001f5d, 0x00001f5d, 0x00001f5f, 0x00001f7d, 0x00001f80, 0x00001fb4, 0x00001fb6, 0x00001fbc, 0x00001fbe, 0x00001fbe, 0x00001fc1, 0x00001fc4, 0x00001fc6, 0x00001fd3, 0x00001fd6, 0x00001fdb, 0x00001fdd, 0x00001fef, 0x00001ff2, 0x00001ff4, 0x00001ff6, 0x00001ffd, 0x00002000, 0x00002001, 0x00002126, 0x00002126, 0x0000212a, 0x0000212b, 0x0000219a, 0x0000219b, 0x000021ae, 0x000021ae, 0x000021cd, 0x000021cf, 0x00002204, 0x00002204, 0x00002209, 0x00002209, 0x0000220c, 0x0000220c, 0x00002224, 0x00002224, 0x00002226, 0x00002226, 0x00002241, 0x00002241, 0x00002244, 0x00002244, 0x00002247, 0x00002247, 0x00002249, 0x00002249, 0x00002260, 0x00002260, 0x00002262, 0x00002262, 0x0000226d, 0x00002271, 0x00002274, 0x00002275, 0x00002278, 0x00002279, 0x00002280, 0x00002281, 0x00002284, 0x00002285, 0x00002288, 0x00002289, 0x000022ac, 0x000022af, 0x000022e0, 0x000022e3, 0x000022ea, 0x000022ed, 0x00002329, 0x0000232a, 0x00002adc, 0x00002adc, 0x0000304c, 0x0000304c, 0x0000304e, 0x0000304e, 0x00003050, 0x00003050, 0x00003052, 0x00003052, 0x00003054, 0x00003054, 0x00003056, 0x00003056, 0x00003058, 0x00003058, 0x0000305a, 0x0000305a, 0x0000305c, 0x0000305c, 0x0000305e, 0x0000305e, 0x00003060, 0x00003060, 0x00003062, 0x00003062, 0x00003065, 0x00003065, 0x00003067, 0x00003067, 0x00003069, 0x00003069, 0x00003070, 0x00003071, 0x00003073, 0x00003074, 0x00003076, 0x00003077, 0x00003079, 0x0000307a, 0x0000307c, 0x0000307d, 0x00003094, 0x00003094, 0x0000309e, 0x0000309e, 0x000030ac, 0x000030ac, 0x000030ae, 0x000030ae, 0x000030b0, 0x000030b0, 0x000030b2, 0x000030b2, 0x000030b4, 0x000030b4, 0x000030b6, 0x000030b6, 0x000030b8, 0x000030b8, 0x000030ba, 0x000030ba, 0x000030bc, 0x000030bc, 0x000030be, 0x000030be, 0x000030c0, 0x000030c0, 0x000030c2, 0x000030c2, 0x000030c5, 0x000030c5, 0x000030c7, 0x000030c7, 0x000030c9, 0x000030c9, 0x000030d0, 0x000030d1, 0x000030d3, 0x000030d4, 0x000030d6, 0x000030d7, 0x000030d9, 0x000030da, 0x000030dc, 0x000030dd, 0x000030f4, 0x000030f4, 0x000030f7, 0x000030fa, 0x000030fe, 0x000030fe, 0x0000f902, 0x0000fa0d, 0x0000fa10, 0x0000fa10, 0x0000fa12, 0x0000fa12, 0x0000fa15, 0x0000fa1e, 0x0000fa20, 0x0000fa20, 0x0000fa22, 0x0000fa22, 0x0000fa25, 0x0000fa26, 0x0000fa2a, 0x0000fa2d, 0x0000fa30, 0x0000fa6a, 0x0000fb1d, 0x0000fb1d, 0x0000fb1f, 0x0000fb1f, 0x0000fb2a, 0x0000fb36, 0x0000fb38, 0x0000fb3c, 0x0000fb3e, 0x0000fb3e, 0x0000fb40, 0x0000fb41, 0x0000fb43, 0x0000fb44, 0x0000fb46, 0x0000fb4e, 0x0001d15e, 0x0001d164, 0x0001d1bb, 0x0001d1c0, 0x0002f800, 0x0002fa1d, 0x00000000, 0x00000220, 0x00000222, 0x00000233, 0x00000250, 0x000002ad, 0x000002b0, 0x000002ee, 0x00000300, 0x0000034f, 0x00000360, 0x0000036f, 0x00000374, 0x00000375, 0x0000037a, 0x0000037a, 0x0000037e, 0x0000037e, 0x00000384, 0x0000038a, 0x0000038c, 0x0000038c, 0x0000038e, 0x000003a1, 0x000003a3, 0x000003ce, 0x000003d0, 0x000003f6, 0x00000400, 0x00000486, 0x00000488, 0x000004ce, 0x000004d0, 0x000004f5, 0x000004f8, 0x000004f9, 0x00000500, 0x0000050f, 0x00000531, 0x00000556, 0x00000559, 0x0000055f, 0x00000561, 0x00000587, 0x00000589, 0x0000058a, 0x00000591, 0x000005a1, 0x000005a3, 0x000005b9, 0x000005bb, 0x000005c4, 0x000005d0, 0x000005ea, 0x000005f0, 0x000005f4, 0x0000060c, 0x0000060c, 0x0000061b, 0x0000061b, 0x0000061f, 0x0000061f, 0x00000621, 0x0000063a, 0x00000640, 0x00000655, 0x00000660, 0x000006ed, 0x000006f0, 0x000006fe, 0x00000700, 0x0000070d, 0x0000070f, 0x0000072c, 0x00000730, 0x0000074a, 0x00000780, 0x000007b1, 0x00000901, 0x00000903, 0x00000905, 0x00000939, 0x0000093c, 0x0000094d, 0x00000950, 0x00000954, 0x00000958, 0x00000970, 0x00000981, 0x00000983, 0x00000985, 0x0000098c, 0x0000098f, 0x00000990, 0x00000993, 0x000009a8, 0x000009aa, 0x000009b0, 0x000009b2, 0x000009b2, 0x000009b6, 0x000009b9, 0x000009bc, 0x000009bc, 0x000009be, 0x000009c4, 0x000009c7, 0x000009c8, 0x000009cb, 0x000009cd, 0x000009d7, 0x000009d7, 0x000009dc, 0x000009dd, 0x000009df, 0x000009e3, 0x000009e6, 0x000009fa, 0x00000a02, 0x00000a02, 0x00000a05, 0x00000a0a, 0x00000a0f, 0x00000a10, 0x00000a13, 0x00000a28, 0x00000a2a, 0x00000a30, 0x00000a32, 0x00000a33, 0x00000a35, 0x00000a36, 0x00000a38, 0x00000a39, 0x00000a3c, 0x00000a3c, 0x00000a3e, 0x00000a42, 0x00000a47, 0x00000a48, 0x00000a4b, 0x00000a4d, 0x00000a59, 0x00000a5c, 0x00000a5e, 0x00000a5e, 0x00000a66, 0x00000a74, 0x00000a81, 0x00000a83, 0x00000a85, 0x00000a8b, 0x00000a8d, 0x00000a8d, 0x00000a8f, 0x00000a91, 0x00000a93, 0x00000aa8, 0x00000aaa, 0x00000ab0, 0x00000ab2, 0x00000ab3, 0x00000ab5, 0x00000ab9, 0x00000abc, 0x00000ac5, 0x00000ac7, 0x00000ac9, 0x00000acb, 0x00000acd, 0x00000ad0, 0x00000ad0, 0x00000ae0, 0x00000ae0, 0x00000ae6, 0x00000aef, 0x00000b01, 0x00000b03, 0x00000b05, 0x00000b0c, 0x00000b0f, 0x00000b10, 0x00000b13, 0x00000b28, 0x00000b2a, 0x00000b30, 0x00000b32, 0x00000b33, 0x00000b36, 0x00000b39, 0x00000b3c, 0x00000b43, 0x00000b47, 0x00000b48, 0x00000b4b, 0x00000b4d, 0x00000b56, 0x00000b57, 0x00000b5c, 0x00000b5d, 0x00000b5f, 0x00000b61, 0x00000b66, 0x00000b70, 0x00000b82, 0x00000b83, 0x00000b85, 0x00000b8a, 0x00000b8e, 0x00000b90, 0x00000b92, 0x00000b95, 0x00000b99, 0x00000b9a, 0x00000b9c, 0x00000b9c, 0x00000b9e, 0x00000b9f, 0x00000ba3, 0x00000ba4, 0x00000ba8, 0x00000baa, 0x00000bae, 0x00000bb5, 0x00000bb7, 0x00000bb9, 0x00000bbe, 0x00000bc2, 0x00000bc6, 0x00000bc8, 0x00000bca, 0x00000bcd, 0x00000bd7, 0x00000bd7, 0x00000be7, 0x00000bf2, 0x00000c01, 0x00000c03, 0x00000c05, 0x00000c0c, 0x00000c0e, 0x00000c10, 0x00000c12, 0x00000c28, 0x00000c2a, 0x00000c33, 0x00000c35, 0x00000c39, 0x00000c3e, 0x00000c44, 0x00000c46, 0x00000c48, 0x00000c4a, 0x00000c4d, 0x00000c55, 0x00000c56, 0x00000c60, 0x00000c61, 0x00000c66, 0x00000c6f, 0x00000c82, 0x00000c83, 0x00000c85, 0x00000c8c, 0x00000c8e, 0x00000c90, 0x00000c92, 0x00000ca8, 0x00000caa, 0x00000cb3, 0x00000cb5, 0x00000cb9, 0x00000cbe, 0x00000cc4, 0x00000cc6, 0x00000cc8, 0x00000cca, 0x00000ccd, 0x00000cd5, 0x00000cd6, 0x00000cde, 0x00000cde, 0x00000ce0, 0x00000ce1, 0x00000ce6, 0x00000cef, 0x00000d02, 0x00000d03, 0x00000d05, 0x00000d0c, 0x00000d0e, 0x00000d10, 0x00000d12, 0x00000d28, 0x00000d2a, 0x00000d39, 0x00000d3e, 0x00000d43, 0x00000d46, 0x00000d48, 0x00000d4a, 0x00000d4d, 0x00000d57, 0x00000d57, 0x00000d60, 0x00000d61, 0x00000d66, 0x00000d6f, 0x00000d82, 0x00000d83, 0x00000d85, 0x00000d96, 0x00000d9a, 0x00000db1, 0x00000db3, 0x00000dbb, 0x00000dbd, 0x00000dbd, 0x00000dc0, 0x00000dc6, 0x00000dca, 0x00000dca, 0x00000dcf, 0x00000dd4, 0x00000dd6, 0x00000dd6, 0x00000dd8, 0x00000ddf, 0x00000df2, 0x00000df4, 0x00000e01, 0x00000e3a, 0x00000e3f, 0x00000e5b, 0x00000e81, 0x00000e82, 0x00000e84, 0x00000e84, 0x00000e87, 0x00000e88, 0x00000e8a, 0x00000e8a, 0x00000e8d, 0x00000e8d, 0x00000e94, 0x00000e97, 0x00000e99, 0x00000e9f, 0x00000ea1, 0x00000ea3, 0x00000ea5, 0x00000ea5, 0x00000ea7, 0x00000ea7, 0x00000eaa, 0x00000eab, 0x00000ead, 0x00000eb9, 0x00000ebb, 0x00000ebd, 0x00000ec0, 0x00000ec4, 0x00000ec6, 0x00000ec6, 0x00000ec8, 0x00000ecd, 0x00000ed0, 0x00000ed9, 0x00000edc, 0x00000edd, 0x00000f00, 0x00000f47, 0x00000f49, 0x00000f6a, 0x00000f71, 0x00000f8b, 0x00000f90, 0x00000f97, 0x00000f99, 0x00000fbc, 0x00000fbe, 0x00000fcc, 0x00000fcf, 0x00000fcf, 0x00001000, 0x00001021, 0x00001023, 0x00001027, 0x00001029, 0x0000102a, 0x0000102c, 0x00001032, 0x00001036, 0x00001039, 0x00001040, 0x00001059, 0x000010a0, 0x000010c5, 0x000010d0, 0x000010f8, 0x000010fb, 0x000010fb, 0x00001100, 0x00001159, 0x0000115f, 0x000011a2, 0x000011a8, 0x000011f9, 0x00001200, 0x00001206, 0x00001208, 0x00001246, 0x00001248, 0x00001248, 0x0000124a, 0x0000124d, 0x00001250, 0x00001256, 0x00001258, 0x00001258, 0x0000125a, 0x0000125d, 0x00001260, 0x00001286, 0x00001288, 0x00001288, 0x0000128a, 0x0000128d, 0x00001290, 0x000012ae, 0x000012b0, 0x000012b0, 0x000012b2, 0x000012b5, 0x000012b8, 0x000012be, 0x000012c0, 0x000012c0, 0x000012c2, 0x000012c5, 0x000012c8, 0x000012ce, 0x000012d0, 0x000012d6, 0x000012d8, 0x000012ee, 0x000012f0, 0x0000130e, 0x00001310, 0x00001310, 0x00001312, 0x00001315, 0x00001318, 0x0000131e, 0x00001320, 0x00001346, 0x00001348, 0x0000135a, 0x00001361, 0x0000137c, 0x000013a0, 0x000013f4, 0x00001401, 0x00001676, 0x00001680, 0x0000169c, 0x000016a0, 0x000016f0, 0x00001700, 0x0000170c, 0x0000170e, 0x00001714, 0x00001720, 0x00001736, 0x00001740, 0x00001753, 0x00001760, 0x0000176c, 0x0000176e, 0x00001770, 0x00001772, 0x00001773, 0x00001780, 0x000017dc, 0x000017e0, 0x000017e9, 0x00001800, 0x0000180e, 0x00001810, 0x00001819, 0x00001820, 0x00001877, 0x00001880, 0x000018a9, 0x00001e00, 0x00001e9b, 0x00001ea0, 0x00001ef9, 0x00001f00, 0x00001f15, 0x00001f18, 0x00001f1d, 0x00001f20, 0x00001f45, 0x00001f48, 0x00001f4d, 0x00001f50, 0x00001f57, 0x00001f59, 0x00001f59, 0x00001f5b, 0x00001f5b, 0x00001f5d, 0x00001f5d, 0x00001f5f, 0x00001f7d, 0x00001f80, 0x00001fb4, 0x00001fb6, 0x00001fc4, 0x00001fc6, 0x00001fd3, 0x00001fd6, 0x00001fdb, 0x00001fdd, 0x00001fef, 0x00001ff2, 0x00001ff4, 0x00001ff6, 0x00001ffe, 0x00002000, 0x00002052, 0x00002057, 0x00002057, 0x0000205f, 0x00002063, 0x0000206a, 0x00002071, 0x00002074, 0x0000208e, 0x000020a0, 0x000020b1, 0x000020d0, 0x000020ea, 0x00002100, 0x0000213a, 0x0000213d, 0x0000214b, 0x00002153, 0x00002183, 0x00002190, 0x000023ce, 0x00002400, 0x00002426, 0x00002440, 0x0000244a, 0x00002460, 0x000024fe, 0x00002500, 0x00002613, 0x00002616, 0x00002617, 0x00002619, 0x0000267d, 0x00002680, 0x00002689, 0x00002701, 0x00002704, 0x00002706, 0x00002709, 0x0000270c, 0x00002727, 0x00002729, 0x0000274b, 0x0000274d, 0x0000274d, 0x0000274f, 0x00002752, 0x00002756, 0x00002756, 0x00002758, 0x0000275e, 0x00002761, 0x00002794, 0x00002798, 0x000027af, 0x000027b1, 0x000027be, 0x000027d0, 0x000027eb, 0x000027f0, 0x00002aff, 0x00002e80, 0x00002e99, 0x00002e9b, 0x00002ef3, 0x00002f00, 0x00002fd5, 0x00002ff0, 0x00002ffb, 0x00003000, 0x0000303f, 0x00003041, 0x00003096, 0x00003099, 0x000030ff, 0x00003105, 0x0000312c, 0x00003131, 0x0000318e, 0x00003190, 0x000031b7, 0x000031f0, 0x0000321c, 0x00003220, 0x00003243, 0x00003251, 0x0000327b, 0x0000327f, 0x000032cb, 0x000032d0, 0x000032fe, 0x00003300, 0x00003376, 0x0000337b, 0x000033dd, 0x000033e0, 0x000033fe, 0x00003400, 0x00004db5, 0x00004e00, 0x00009fa5, 0x0000a000, 0x0000a48c, 0x0000a490, 0x0000a4c6, 0x0000ac00, 0x0000d7a3, 0x0000f900, 0x0000fb06, 0x0000fb13, 0x0000fb17, 0x0000fb1d, 0x0000fb36, 0x0000fb38, 0x0000fb3c, 0x0000fb3e, 0x0000fb3e, 0x0000fb40, 0x0000fb41, 0x0000fb43, 0x0000fb44, 0x0000fb46, 0x0000fbb1, 0x0000fbd3, 0x0000fd3f, 0x0000fd50, 0x0000fd8f, 0x0000fd92, 0x0000fdc7, 0x0000fdf0, 0x0000fdfc, 0x0000fe00, 0x0000fe0f, 0x0000fe20, 0x0000fe23, 0x0000fe30, 0x0000fe46, 0x0000fe49, 0x0000fe52, 0x0000fe54, 0x0000fe66, 0x0000fe68, 0x0000fe6b, 0x0000fe70, 0x0000fe74, 0x0000fe76, 0x0000fefc, 0x0000feff, 0x0000feff, 0x0000ff01, 0x0000ffbe, 0x0000ffc2, 0x0000ffc7, 0x0000ffca, 0x0000ffcf, 0x0000ffd2, 0x0000ffd7, 0x0000ffda, 0x0000ffdc, 0x0000ffe0, 0x0000ffe6, 0x0000ffe8, 0x0000ffee, 0x0000fff9, 0x0000fffd, 0x00010300, 0x0001031e, 0x00010320, 0x00010323, 0x00010330, 0x0001034a, 0x00010400, 0x00010425, 0x00010428, 0x0001044d, 0x0001d000, 0x0001d0f5, 0x0001d100, 0x0001d126, 0x0001d12a, 0x0001d1dd, 0x0001d400, 0x0001d454, 0x0001d456, 0x0001d49c, 0x0001d49e, 0x0001d49f, 0x0001d4a2, 0x0001d4a2, 0x0001d4a5, 0x0001d4a6, 0x0001d4a9, 0x0001d4ac, 0x0001d4ae, 0x0001d4b9, 0x0001d4bb, 0x0001d4bb, 0x0001d4bd, 0x0001d4c0, 0x0001d4c2, 0x0001d4c3, 0x0001d4c5, 0x0001d505, 0x0001d507, 0x0001d50a, 0x0001d50d, 0x0001d514, 0x0001d516, 0x0001d51c, 0x0001d51e, 0x0001d539, 0x0001d53b, 0x0001d53e, 0x0001d540, 0x0001d544, 0x0001d546, 0x0001d546, 0x0001d54a, 0x0001d550, 0x0001d552, 0x0001d6a3, 0x0001d6a8, 0x0001d7c9, 0x0001d7ce, 0x0001d7ff, 0x00020000, 0x0002a6d6, 0x0002f800, 0x0002fa1d, 0x000e0001, 0x000e0001, 0x000e0020, 0x000e007f, 0x000000ab, 0x000000ab, 0x00002018, 0x00002018, 0x0000201b, 0x0000201c, 0x0000201f, 0x0000201f, 0x00002039, 0x00002039, 0x000000bb, 0x000000bb, 0x00002019, 0x00002019, 0x0000201d, 0x0000201d, 0x0000203a, 0x0000203a, 0x0000061b, 0x0000061b, 0x0000061f, 0x0000061f, 0x00000621, 0x0000063a, 0x00000640, 0x0000064a, 0x0000066d, 0x0000066f, 0x00000671, 0x000006d5, 0x000006dd, 0x000006dd, 0x000006e5, 0x000006e6, 0x000006fa, 0x000006fe, 0x00000700, 0x0000070d, 0x00000710, 0x00000710, 0x00000712, 0x0000072c, 0x00000780, 0x000007a5, 0x000007b1, 0x000007b1, 0x0000fb50, 0x0000fbb1, 0x0000fbd3, 0x0000fd3d, 0x0000fd50, 0x0000fd8f, 0x0000fd92, 0x0000fdc7, 0x0000fdf0, 0x0000fdfc, 0x0000fe70, 0x0000fe74, 0x0000fe76, 0x0000fefc }; static const ac_uint4 _uccase_size = 1504; static const ac_uint2 _uccase_len[2] = {718, 755}; static const ac_uint4 _uccase_map[] = { 0x00000041, 0x00000061, 0x00000041, 0x00000042, 0x00000062, 0x00000042, 0x00000043, 0x00000063, 0x00000043, 0x00000044, 0x00000064, 0x00000044, 0x00000045, 0x00000065, 0x00000045, 0x00000046, 0x00000066, 0x00000046, 0x00000047, 0x00000067, 0x00000047, 0x00000048, 0x00000068, 0x00000048, 0x00000049, 0x00000069, 0x00000049, 0x0000004a, 0x0000006a, 0x0000004a, 0x0000004b, 0x0000006b, 0x0000004b, 0x0000004c, 0x0000006c, 0x0000004c, 0x0000004d, 0x0000006d, 0x0000004d, 0x0000004e, 0x0000006e, 0x0000004e, 0x0000004f, 0x0000006f, 0x0000004f, 0x00000050, 0x00000070, 0x00000050, 0x00000051, 0x00000071, 0x00000051, 0x00000052, 0x00000072, 0x00000052, 0x00000053, 0x00000073, 0x00000053, 0x00000054, 0x00000074, 0x00000054, 0x00000055, 0x00000075, 0x00000055, 0x00000056, 0x00000076, 0x00000056, 0x00000057, 0x00000077, 0x00000057, 0x00000058, 0x00000078, 0x00000058, 0x00000059, 0x00000079, 0x00000059, 0x0000005a, 0x0000007a, 0x0000005a, 0x000000c0, 0x000000e0, 0x000000c0, 0x000000c1, 0x000000e1, 0x000000c1, 0x000000c2, 0x000000e2, 0x000000c2, 0x000000c3, 0x000000e3, 0x000000c3, 0x000000c4, 0x000000e4, 0x000000c4, 0x000000c5, 0x000000e5, 0x000000c5, 0x000000c6, 0x000000e6, 0x000000c6, 0x000000c7, 0x000000e7, 0x000000c7, 0x000000c8, 0x000000e8, 0x000000c8, 0x000000c9, 0x000000e9, 0x000000c9, 0x000000ca, 0x000000ea, 0x000000ca, 0x000000cb, 0x000000eb, 0x000000cb, 0x000000cc, 0x000000ec, 0x000000cc, 0x000000cd, 0x000000ed, 0x000000cd, 0x000000ce, 0x000000ee, 0x000000ce, 0x000000cf, 0x000000ef, 0x000000cf, 0x000000d0, 0x000000f0, 0x000000d0, 0x000000d1, 0x000000f1, 0x000000d1, 0x000000d2, 0x000000f2, 0x000000d2, 0x000000d3, 0x000000f3, 0x000000d3, 0x000000d4, 0x000000f4, 0x000000d4, 0x000000d5, 0x000000f5, 0x000000d5, 0x000000d6, 0x000000f6, 0x000000d6, 0x000000d8, 0x000000f8, 0x000000d8, 0x000000d9, 0x000000f9, 0x000000d9, 0x000000da, 0x000000fa, 0x000000da, 0x000000db, 0x000000fb, 0x000000db, 0x000000dc, 0x000000fc, 0x000000dc, 0x000000dd, 0x000000fd, 0x000000dd, 0x000000de, 0x000000fe, 0x000000de, 0x00000100, 0x00000101, 0x00000100, 0x00000102, 0x00000103, 0x00000102, 0x00000104, 0x00000105, 0x00000104, 0x00000106, 0x00000107, 0x00000106, 0x00000108, 0x00000109, 0x00000108, 0x0000010a, 0x0000010b, 0x0000010a, 0x0000010c, 0x0000010d, 0x0000010c, 0x0000010e, 0x0000010f, 0x0000010e, 0x00000110, 0x00000111, 0x00000110, 0x00000112, 0x00000113, 0x00000112, 0x00000114, 0x00000115, 0x00000114, 0x00000116, 0x00000117, 0x00000116, 0x00000118, 0x00000119, 0x00000118, 0x0000011a, 0x0000011b, 0x0000011a, 0x0000011c, 0x0000011d, 0x0000011c, 0x0000011e, 0x0000011f, 0x0000011e, 0x00000120, 0x00000121, 0x00000120, 0x00000122, 0x00000123, 0x00000122, 0x00000124, 0x00000125, 0x00000124, 0x00000126, 0x00000127, 0x00000126, 0x00000128, 0x00000129, 0x00000128, 0x0000012a, 0x0000012b, 0x0000012a, 0x0000012c, 0x0000012d, 0x0000012c, 0x0000012e, 0x0000012f, 0x0000012e, 0x00000130, 0x00000069, 0x00000130, 0x00000132, 0x00000133, 0x00000132, 0x00000134, 0x00000135, 0x00000134, 0x00000136, 0x00000137, 0x00000136, 0x00000139, 0x0000013a, 0x00000139, 0x0000013b, 0x0000013c, 0x0000013b, 0x0000013d, 0x0000013e, 0x0000013d, 0x0000013f, 0x00000140, 0x0000013f, 0x00000141, 0x00000142, 0x00000141, 0x00000143, 0x00000144, 0x00000143, 0x00000145, 0x00000146, 0x00000145, 0x00000147, 0x00000148, 0x00000147, 0x0000014a, 0x0000014b, 0x0000014a, 0x0000014c, 0x0000014d, 0x0000014c, 0x0000014e, 0x0000014f, 0x0000014e, 0x00000150, 0x00000151, 0x00000150, 0x00000152, 0x00000153, 0x00000152, 0x00000154, 0x00000155, 0x00000154, 0x00000156, 0x00000157, 0x00000156, 0x00000158, 0x00000159, 0x00000158, 0x0000015a, 0x0000015b, 0x0000015a, 0x0000015c, 0x0000015d, 0x0000015c, 0x0000015e, 0x0000015f, 0x0000015e, 0x00000160, 0x00000161, 0x00000160, 0x00000162, 0x00000163, 0x00000162, 0x00000164, 0x00000165, 0x00000164, 0x00000166, 0x00000167, 0x00000166, 0x00000168, 0x00000169, 0x00000168, 0x0000016a, 0x0000016b, 0x0000016a, 0x0000016c, 0x0000016d, 0x0000016c, 0x0000016e, 0x0000016f, 0x0000016e, 0x00000170, 0x00000171, 0x00000170, 0x00000172, 0x00000173, 0x00000172, 0x00000174, 0x00000175, 0x00000174, 0x00000176, 0x00000177, 0x00000176, 0x00000178, 0x000000ff, 0x00000178, 0x00000179, 0x0000017a, 0x00000179, 0x0000017b, 0x0000017c, 0x0000017b, 0x0000017d, 0x0000017e, 0x0000017d, 0x00000181, 0x00000253, 0x00000181, 0x00000182, 0x00000183, 0x00000182, 0x00000184, 0x00000185, 0x00000184, 0x00000186, 0x00000254, 0x00000186, 0x00000187, 0x00000188, 0x00000187, 0x00000189, 0x00000256, 0x00000189, 0x0000018a, 0x00000257, 0x0000018a, 0x0000018b, 0x0000018c, 0x0000018b, 0x0000018e, 0x000001dd, 0x0000018e, 0x0000018f, 0x00000259, 0x0000018f, 0x00000190, 0x0000025b, 0x00000190, 0x00000191, 0x00000192, 0x00000191, 0x00000193, 0x00000260, 0x00000193, 0x00000194, 0x00000263, 0x00000194, 0x00000196, 0x00000269, 0x00000196, 0x00000197, 0x00000268, 0x00000197, 0x00000198, 0x00000199, 0x00000198, 0x0000019c, 0x0000026f, 0x0000019c, 0x0000019d, 0x00000272, 0x0000019d, 0x0000019f, 0x00000275, 0x0000019f, 0x000001a0, 0x000001a1, 0x000001a0, 0x000001a2, 0x000001a3, 0x000001a2, 0x000001a4, 0x000001a5, 0x000001a4, 0x000001a6, 0x00000280, 0x000001a6, 0x000001a7, 0x000001a8, 0x000001a7, 0x000001a9, 0x00000283, 0x000001a9, 0x000001ac, 0x000001ad, 0x000001ac, 0x000001ae, 0x00000288, 0x000001ae, 0x000001af, 0x000001b0, 0x000001af, 0x000001b1, 0x0000028a, 0x000001b1, 0x000001b2, 0x0000028b, 0x000001b2, 0x000001b3, 0x000001b4, 0x000001b3, 0x000001b5, 0x000001b6, 0x000001b5, 0x000001b7, 0x00000292, 0x000001b7, 0x000001b8, 0x000001b9, 0x000001b8, 0x000001bc, 0x000001bd, 0x000001bc, 0x000001c4, 0x000001c6, 0x000001c5, 0x000001c7, 0x000001c9, 0x000001c8, 0x000001ca, 0x000001cc, 0x000001cb, 0x000001cd, 0x000001ce, 0x000001cd, 0x000001cf, 0x000001d0, 0x000001cf, 0x000001d1, 0x000001d2, 0x000001d1, 0x000001d3, 0x000001d4, 0x000001d3, 0x000001d5, 0x000001d6, 0x000001d5, 0x000001d7, 0x000001d8, 0x000001d7, 0x000001d9, 0x000001da, 0x000001d9, 0x000001db, 0x000001dc, 0x000001db, 0x000001de, 0x000001df, 0x000001de, 0x000001e0, 0x000001e1, 0x000001e0, 0x000001e2, 0x000001e3, 0x000001e2, 0x000001e4, 0x000001e5, 0x000001e4, 0x000001e6, 0x000001e7, 0x000001e6, 0x000001e8, 0x000001e9, 0x000001e8, 0x000001ea, 0x000001eb, 0x000001ea, 0x000001ec, 0x000001ed, 0x000001ec, 0x000001ee, 0x000001ef, 0x000001ee, 0x000001f1, 0x000001f3, 0x000001f2, 0x000001f4, 0x000001f5, 0x000001f4, 0x000001f6, 0x00000195, 0x000001f6, 0x000001f7, 0x000001bf, 0x000001f7, 0x000001f8, 0x000001f9, 0x000001f8, 0x000001fa, 0x000001fb, 0x000001fa, 0x000001fc, 0x000001fd, 0x000001fc, 0x000001fe, 0x000001ff, 0x000001fe, 0x00000200, 0x00000201, 0x00000200, 0x00000202, 0x00000203, 0x00000202, 0x00000204, 0x00000205, 0x00000204, 0x00000206, 0x00000207, 0x00000206, 0x00000208, 0x00000209, 0x00000208, 0x0000020a, 0x0000020b, 0x0000020a, 0x0000020c, 0x0000020d, 0x0000020c, 0x0000020e, 0x0000020f, 0x0000020e, 0x00000210, 0x00000211, 0x00000210, 0x00000212, 0x00000213, 0x00000212, 0x00000214, 0x00000215, 0x00000214, 0x00000216, 0x00000217, 0x00000216, 0x00000218, 0x00000219, 0x00000218, 0x0000021a, 0x0000021b, 0x0000021a, 0x0000021c, 0x0000021d, 0x0000021c, 0x0000021e, 0x0000021f, 0x0000021e, 0x00000220, 0x0000019e, 0x00000220, 0x00000222, 0x00000223, 0x00000222, 0x00000224, 0x00000225, 0x00000224, 0x00000226, 0x00000227, 0x00000226, 0x00000228, 0x00000229, 0x00000228, 0x0000022a, 0x0000022b, 0x0000022a, 0x0000022c, 0x0000022d, 0x0000022c, 0x0000022e, 0x0000022f, 0x0000022e, 0x00000230, 0x00000231, 0x00000230, 0x00000232, 0x00000233, 0x00000232, 0x00000386, 0x000003ac, 0x00000386, 0x00000388, 0x000003ad, 0x00000388, 0x00000389, 0x000003ae, 0x00000389, 0x0000038a, 0x000003af, 0x0000038a, 0x0000038c, 0x000003cc, 0x0000038c, 0x0000038e, 0x000003cd, 0x0000038e, 0x0000038f, 0x000003ce, 0x0000038f, 0x00000391, 0x000003b1, 0x00000391, 0x00000392, 0x000003b2, 0x00000392, 0x00000393, 0x000003b3, 0x00000393, 0x00000394, 0x000003b4, 0x00000394, 0x00000395, 0x000003b5, 0x00000395, 0x00000396, 0x000003b6, 0x00000396, 0x00000397, 0x000003b7, 0x00000397, 0x00000398, 0x000003b8, 0x00000398, 0x00000399, 0x000003b9, 0x00000399, 0x0000039a, 0x000003ba, 0x0000039a, 0x0000039b, 0x000003bb, 0x0000039b, 0x0000039c, 0x000003bc, 0x0000039c, 0x0000039d, 0x000003bd, 0x0000039d, 0x0000039e, 0x000003be, 0x0000039e, 0x0000039f, 0x000003bf, 0x0000039f, 0x000003a0, 0x000003c0, 0x000003a0, 0x000003a1, 0x000003c1, 0x000003a1, 0x000003a3, 0x000003c3, 0x000003a3, 0x000003a4, 0x000003c4, 0x000003a4, 0x000003a5, 0x000003c5, 0x000003a5, 0x000003a6, 0x000003c6, 0x000003a6, 0x000003a7, 0x000003c7, 0x000003a7, 0x000003a8, 0x000003c8, 0x000003a8, 0x000003a9, 0x000003c9, 0x000003a9, 0x000003aa, 0x000003ca, 0x000003aa, 0x000003ab, 0x000003cb, 0x000003ab, 0x000003d8, 0x000003d9, 0x000003d8, 0x000003da, 0x000003db, 0x000003da, 0x000003dc, 0x000003dd, 0x000003dc, 0x000003de, 0x000003df, 0x000003de, 0x000003e0, 0x000003e1, 0x000003e0, 0x000003e2, 0x000003e3, 0x000003e2, 0x000003e4, 0x000003e5, 0x000003e4, 0x000003e6, 0x000003e7, 0x000003e6, 0x000003e8, 0x000003e9, 0x000003e8, 0x000003ea, 0x000003eb, 0x000003ea, 0x000003ec, 0x000003ed, 0x000003ec, 0x000003ee, 0x000003ef, 0x000003ee, 0x000003f4, 0x000003b8, 0x000003f4, 0x00000400, 0x00000450, 0x00000400, 0x00000401, 0x00000451, 0x00000401, 0x00000402, 0x00000452, 0x00000402, 0x00000403, 0x00000453, 0x00000403, 0x00000404, 0x00000454, 0x00000404, 0x00000405, 0x00000455, 0x00000405, 0x00000406, 0x00000456, 0x00000406, 0x00000407, 0x00000457, 0x00000407, 0x00000408, 0x00000458, 0x00000408, 0x00000409, 0x00000459, 0x00000409, 0x0000040a, 0x0000045a, 0x0000040a, 0x0000040b, 0x0000045b, 0x0000040b, 0x0000040c, 0x0000045c, 0x0000040c, 0x0000040d, 0x0000045d, 0x0000040d, 0x0000040e, 0x0000045e, 0x0000040e, 0x0000040f, 0x0000045f, 0x0000040f, 0x00000410, 0x00000430, 0x00000410, 0x00000411, 0x00000431, 0x00000411, 0x00000412, 0x00000432, 0x00000412, 0x00000413, 0x00000433, 0x00000413, 0x00000414, 0x00000434, 0x00000414, 0x00000415, 0x00000435, 0x00000415, 0x00000416, 0x00000436, 0x00000416, 0x00000417, 0x00000437, 0x00000417, 0x00000418, 0x00000438, 0x00000418, 0x00000419, 0x00000439, 0x00000419, 0x0000041a, 0x0000043a, 0x0000041a, 0x0000041b, 0x0000043b, 0x0000041b, 0x0000041c, 0x0000043c, 0x0000041c, 0x0000041d, 0x0000043d, 0x0000041d, 0x0000041e, 0x0000043e, 0x0000041e, 0x0000041f, 0x0000043f, 0x0000041f, 0x00000420, 0x00000440, 0x00000420, 0x00000421, 0x00000441, 0x00000421, 0x00000422, 0x00000442, 0x00000422, 0x00000423, 0x00000443, 0x00000423, 0x00000424, 0x00000444, 0x00000424, 0x00000425, 0x00000445, 0x00000425, 0x00000426, 0x00000446, 0x00000426, 0x00000427, 0x00000447, 0x00000427, 0x00000428, 0x00000448, 0x00000428, 0x00000429, 0x00000449, 0x00000429, 0x0000042a, 0x0000044a, 0x0000042a, 0x0000042b, 0x0000044b, 0x0000042b, 0x0000042c, 0x0000044c, 0x0000042c, 0x0000042d, 0x0000044d, 0x0000042d, 0x0000042e, 0x0000044e, 0x0000042e, 0x0000042f, 0x0000044f, 0x0000042f, 0x00000460, 0x00000461, 0x00000460, 0x00000462, 0x00000463, 0x00000462, 0x00000464, 0x00000465, 0x00000464, 0x00000466, 0x00000467, 0x00000466, 0x00000468, 0x00000469, 0x00000468, 0x0000046a, 0x0000046b, 0x0000046a, 0x0000046c, 0x0000046d, 0x0000046c, 0x0000046e, 0x0000046f, 0x0000046e, 0x00000470, 0x00000471, 0x00000470, 0x00000472, 0x00000473, 0x00000472, 0x00000474, 0x00000475, 0x00000474, 0x00000476, 0x00000477, 0x00000476, 0x00000478, 0x00000479, 0x00000478, 0x0000047a, 0x0000047b, 0x0000047a, 0x0000047c, 0x0000047d, 0x0000047c, 0x0000047e, 0x0000047f, 0x0000047e, 0x00000480, 0x00000481, 0x00000480, 0x0000048a, 0x0000048b, 0x0000048a, 0x0000048c, 0x0000048d, 0x0000048c, 0x0000048e, 0x0000048f, 0x0000048e, 0x00000490, 0x00000491, 0x00000490, 0x00000492, 0x00000493, 0x00000492, 0x00000494, 0x00000495, 0x00000494, 0x00000496, 0x00000497, 0x00000496, 0x00000498, 0x00000499, 0x00000498, 0x0000049a, 0x0000049b, 0x0000049a, 0x0000049c, 0x0000049d, 0x0000049c, 0x0000049e, 0x0000049f, 0x0000049e, 0x000004a0, 0x000004a1, 0x000004a0, 0x000004a2, 0x000004a3, 0x000004a2, 0x000004a4, 0x000004a5, 0x000004a4, 0x000004a6, 0x000004a7, 0x000004a6, 0x000004a8, 0x000004a9, 0x000004a8, 0x000004aa, 0x000004ab, 0x000004aa, 0x000004ac, 0x000004ad, 0x000004ac, 0x000004ae, 0x000004af, 0x000004ae, 0x000004b0, 0x000004b1, 0x000004b0, 0x000004b2, 0x000004b3, 0x000004b2, 0x000004b4, 0x000004b5, 0x000004b4, 0x000004b6, 0x000004b7, 0x000004b6, 0x000004b8, 0x000004b9, 0x000004b8, 0x000004ba, 0x000004bb, 0x000004ba, 0x000004bc, 0x000004bd, 0x000004bc, 0x000004be, 0x000004bf, 0x000004be, 0x000004c1, 0x000004c2, 0x000004c1, 0x000004c3, 0x000004c4, 0x000004c3, 0x000004c5, 0x000004c6, 0x000004c5, 0x000004c7, 0x000004c8, 0x000004c7, 0x000004c9, 0x000004ca, 0x000004c9, 0x000004cb, 0x000004cc, 0x000004cb, 0x000004cd, 0x000004ce, 0x000004cd, 0x000004d0, 0x000004d1, 0x000004d0, 0x000004d2, 0x000004d3, 0x000004d2, 0x000004d4, 0x000004d5, 0x000004d4, 0x000004d6, 0x000004d7, 0x000004d6, 0x000004d8, 0x000004d9, 0x000004d8, 0x000004da, 0x000004db, 0x000004da, 0x000004dc, 0x000004dd, 0x000004dc, 0x000004de, 0x000004df, 0x000004de, 0x000004e0, 0x000004e1, 0x000004e0, 0x000004e2, 0x000004e3, 0x000004e2, 0x000004e4, 0x000004e5, 0x000004e4, 0x000004e6, 0x000004e7, 0x000004e6, 0x000004e8, 0x000004e9, 0x000004e8, 0x000004ea, 0x000004eb, 0x000004ea, 0x000004ec, 0x000004ed, 0x000004ec, 0x000004ee, 0x000004ef, 0x000004ee, 0x000004f0, 0x000004f1, 0x000004f0, 0x000004f2, 0x000004f3, 0x000004f2, 0x000004f4, 0x000004f5, 0x000004f4, 0x000004f8, 0x000004f9, 0x000004f8, 0x00000500, 0x00000501, 0x00000500, 0x00000502, 0x00000503, 0x00000502, 0x00000504, 0x00000505, 0x00000504, 0x00000506, 0x00000507, 0x00000506, 0x00000508, 0x00000509, 0x00000508, 0x0000050a, 0x0000050b, 0x0000050a, 0x0000050c, 0x0000050d, 0x0000050c, 0x0000050e, 0x0000050f, 0x0000050e, 0x00000531, 0x00000561, 0x00000531, 0x00000532, 0x00000562, 0x00000532, 0x00000533, 0x00000563, 0x00000533, 0x00000534, 0x00000564, 0x00000534, 0x00000535, 0x00000565, 0x00000535, 0x00000536, 0x00000566, 0x00000536, 0x00000537, 0x00000567, 0x00000537, 0x00000538, 0x00000568, 0x00000538, 0x00000539, 0x00000569, 0x00000539, 0x0000053a, 0x0000056a, 0x0000053a, 0x0000053b, 0x0000056b, 0x0000053b, 0x0000053c, 0x0000056c, 0x0000053c, 0x0000053d, 0x0000056d, 0x0000053d, 0x0000053e, 0x0000056e, 0x0000053e, 0x0000053f, 0x0000056f, 0x0000053f, 0x00000540, 0x00000570, 0x00000540, 0x00000541, 0x00000571, 0x00000541, 0x00000542, 0x00000572, 0x00000542, 0x00000543, 0x00000573, 0x00000543, 0x00000544, 0x00000574, 0x00000544, 0x00000545, 0x00000575, 0x00000545, 0x00000546, 0x00000576, 0x00000546, 0x00000547, 0x00000577, 0x00000547, 0x00000548, 0x00000578, 0x00000548, 0x00000549, 0x00000579, 0x00000549, 0x0000054a, 0x0000057a, 0x0000054a, 0x0000054b, 0x0000057b, 0x0000054b, 0x0000054c, 0x0000057c, 0x0000054c, 0x0000054d, 0x0000057d, 0x0000054d, 0x0000054e, 0x0000057e, 0x0000054e, 0x0000054f, 0x0000057f, 0x0000054f, 0x00000550, 0x00000580, 0x00000550, 0x00000551, 0x00000581, 0x00000551, 0x00000552, 0x00000582, 0x00000552, 0x00000553, 0x00000583, 0x00000553, 0x00000554, 0x00000584, 0x00000554, 0x00000555, 0x00000585, 0x00000555, 0x00000556, 0x00000586, 0x00000556, 0x00001e00, 0x00001e01, 0x00001e00, 0x00001e02, 0x00001e03, 0x00001e02, 0x00001e04, 0x00001e05, 0x00001e04, 0x00001e06, 0x00001e07, 0x00001e06, 0x00001e08, 0x00001e09, 0x00001e08, 0x00001e0a, 0x00001e0b, 0x00001e0a, 0x00001e0c, 0x00001e0d, 0x00001e0c, 0x00001e0e, 0x00001e0f, 0x00001e0e, 0x00001e10, 0x00001e11, 0x00001e10, 0x00001e12, 0x00001e13, 0x00001e12, 0x00001e14, 0x00001e15, 0x00001e14, 0x00001e16, 0x00001e17, 0x00001e16, 0x00001e18, 0x00001e19, 0x00001e18, 0x00001e1a, 0x00001e1b, 0x00001e1a, 0x00001e1c, 0x00001e1d, 0x00001e1c, 0x00001e1e, 0x00001e1f, 0x00001e1e, 0x00001e20, 0x00001e21, 0x00001e20, 0x00001e22, 0x00001e23, 0x00001e22, 0x00001e24, 0x00001e25, 0x00001e24, 0x00001e26, 0x00001e27, 0x00001e26, 0x00001e28, 0x00001e29, 0x00001e28, 0x00001e2a, 0x00001e2b, 0x00001e2a, 0x00001e2c, 0x00001e2d, 0x00001e2c, 0x00001e2e, 0x00001e2f, 0x00001e2e, 0x00001e30, 0x00001e31, 0x00001e30, 0x00001e32, 0x00001e33, 0x00001e32, 0x00001e34, 0x00001e35, 0x00001e34, 0x00001e36, 0x00001e37, 0x00001e36, 0x00001e38, 0x00001e39, 0x00001e38, 0x00001e3a, 0x00001e3b, 0x00001e3a, 0x00001e3c, 0x00001e3d, 0x00001e3c, 0x00001e3e, 0x00001e3f, 0x00001e3e, 0x00001e40, 0x00001e41, 0x00001e40, 0x00001e42, 0x00001e43, 0x00001e42, 0x00001e44, 0x00001e45, 0x00001e44, 0x00001e46, 0x00001e47, 0x00001e46, 0x00001e48, 0x00001e49, 0x00001e48, 0x00001e4a, 0x00001e4b, 0x00001e4a, 0x00001e4c, 0x00001e4d, 0x00001e4c, 0x00001e4e, 0x00001e4f, 0x00001e4e, 0x00001e50, 0x00001e51, 0x00001e50, 0x00001e52, 0x00001e53, 0x00001e52, 0x00001e54, 0x00001e55, 0x00001e54, 0x00001e56, 0x00001e57, 0x00001e56, 0x00001e58, 0x00001e59, 0x00001e58, 0x00001e5a, 0x00001e5b, 0x00001e5a, 0x00001e5c, 0x00001e5d, 0x00001e5c, 0x00001e5e, 0x00001e5f, 0x00001e5e, 0x00001e60, 0x00001e61, 0x00001e60, 0x00001e62, 0x00001e63, 0x00001e62, 0x00001e64, 0x00001e65, 0x00001e64, 0x00001e66, 0x00001e67, 0x00001e66, 0x00001e68, 0x00001e69, 0x00001e68, 0x00001e6a, 0x00001e6b, 0x00001e6a, 0x00001e6c, 0x00001e6d, 0x00001e6c, 0x00001e6e, 0x00001e6f, 0x00001e6e, 0x00001e70, 0x00001e71, 0x00001e70, 0x00001e72, 0x00001e73, 0x00001e72, 0x00001e74, 0x00001e75, 0x00001e74, 0x00001e76, 0x00001e77, 0x00001e76, 0x00001e78, 0x00001e79, 0x00001e78, 0x00001e7a, 0x00001e7b, 0x00001e7a, 0x00001e7c, 0x00001e7d, 0x00001e7c, 0x00001e7e, 0x00001e7f, 0x00001e7e, 0x00001e80, 0x00001e81, 0x00001e80, 0x00001e82, 0x00001e83, 0x00001e82, 0x00001e84, 0x00001e85, 0x00001e84, 0x00001e86, 0x00001e87, 0x00001e86, 0x00001e88, 0x00001e89, 0x00001e88, 0x00001e8a, 0x00001e8b, 0x00001e8a, 0x00001e8c, 0x00001e8d, 0x00001e8c, 0x00001e8e, 0x00001e8f, 0x00001e8e, 0x00001e90, 0x00001e91, 0x00001e90, 0x00001e92, 0x00001e93, 0x00001e92, 0x00001e94, 0x00001e95, 0x00001e94, 0x00001ea0, 0x00001ea1, 0x00001ea0, 0x00001ea2, 0x00001ea3, 0x00001ea2, 0x00001ea4, 0x00001ea5, 0x00001ea4, 0x00001ea6, 0x00001ea7, 0x00001ea6, 0x00001ea8, 0x00001ea9, 0x00001ea8, 0x00001eaa, 0x00001eab, 0x00001eaa, 0x00001eac, 0x00001ead, 0x00001eac, 0x00001eae, 0x00001eaf, 0x00001eae, 0x00001eb0, 0x00001eb1, 0x00001eb0, 0x00001eb2, 0x00001eb3, 0x00001eb2, 0x00001eb4, 0x00001eb5, 0x00001eb4, 0x00001eb6, 0x00001eb7, 0x00001eb6, 0x00001eb8, 0x00001eb9, 0x00001eb8, 0x00001eba, 0x00001ebb, 0x00001eba, 0x00001ebc, 0x00001ebd, 0x00001ebc, 0x00001ebe, 0x00001ebf, 0x00001ebe, 0x00001ec0, 0x00001ec1, 0x00001ec0, 0x00001ec2, 0x00001ec3, 0x00001ec2, 0x00001ec4, 0x00001ec5, 0x00001ec4, 0x00001ec6, 0x00001ec7, 0x00001ec6, 0x00001ec8, 0x00001ec9, 0x00001ec8, 0x00001eca, 0x00001ecb, 0x00001eca, 0x00001ecc, 0x00001ecd, 0x00001ecc, 0x00001ece, 0x00001ecf, 0x00001ece, 0x00001ed0, 0x00001ed1, 0x00001ed0, 0x00001ed2, 0x00001ed3, 0x00001ed2, 0x00001ed4, 0x00001ed5, 0x00001ed4, 0x00001ed6, 0x00001ed7, 0x00001ed6, 0x00001ed8, 0x00001ed9, 0x00001ed8, 0x00001eda, 0x00001edb, 0x00001eda, 0x00001edc, 0x00001edd, 0x00001edc, 0x00001ede, 0x00001edf, 0x00001ede, 0x00001ee0, 0x00001ee1, 0x00001ee0, 0x00001ee2, 0x00001ee3, 0x00001ee2, 0x00001ee4, 0x00001ee5, 0x00001ee4, 0x00001ee6, 0x00001ee7, 0x00001ee6, 0x00001ee8, 0x00001ee9, 0x00001ee8, 0x00001eea, 0x00001eeb, 0x00001eea, 0x00001eec, 0x00001eed, 0x00001eec, 0x00001eee, 0x00001eef, 0x00001eee, 0x00001ef0, 0x00001ef1, 0x00001ef0, 0x00001ef2, 0x00001ef3, 0x00001ef2, 0x00001ef4, 0x00001ef5, 0x00001ef4, 0x00001ef6, 0x00001ef7, 0x00001ef6, 0x00001ef8, 0x00001ef9, 0x00001ef8, 0x00001f08, 0x00001f00, 0x00001f08, 0x00001f09, 0x00001f01, 0x00001f09, 0x00001f0a, 0x00001f02, 0x00001f0a, 0x00001f0b, 0x00001f03, 0x00001f0b, 0x00001f0c, 0x00001f04, 0x00001f0c, 0x00001f0d, 0x00001f05, 0x00001f0d, 0x00001f0e, 0x00001f06, 0x00001f0e, 0x00001f0f, 0x00001f07, 0x00001f0f, 0x00001f18, 0x00001f10, 0x00001f18, 0x00001f19, 0x00001f11, 0x00001f19, 0x00001f1a, 0x00001f12, 0x00001f1a, 0x00001f1b, 0x00001f13, 0x00001f1b, 0x00001f1c, 0x00001f14, 0x00001f1c, 0x00001f1d, 0x00001f15, 0x00001f1d, 0x00001f28, 0x00001f20, 0x00001f28, 0x00001f29, 0x00001f21, 0x00001f29, 0x00001f2a, 0x00001f22, 0x00001f2a, 0x00001f2b, 0x00001f23, 0x00001f2b, 0x00001f2c, 0x00001f24, 0x00001f2c, 0x00001f2d, 0x00001f25, 0x00001f2d, 0x00001f2e, 0x00001f26, 0x00001f2e, 0x00001f2f, 0x00001f27, 0x00001f2f, 0x00001f38, 0x00001f30, 0x00001f38, 0x00001f39, 0x00001f31, 0x00001f39, 0x00001f3a, 0x00001f32, 0x00001f3a, 0x00001f3b, 0x00001f33, 0x00001f3b, 0x00001f3c, 0x00001f34, 0x00001f3c, 0x00001f3d, 0x00001f35, 0x00001f3d, 0x00001f3e, 0x00001f36, 0x00001f3e, 0x00001f3f, 0x00001f37, 0x00001f3f, 0x00001f48, 0x00001f40, 0x00001f48, 0x00001f49, 0x00001f41, 0x00001f49, 0x00001f4a, 0x00001f42, 0x00001f4a, 0x00001f4b, 0x00001f43, 0x00001f4b, 0x00001f4c, 0x00001f44, 0x00001f4c, 0x00001f4d, 0x00001f45, 0x00001f4d, 0x00001f59, 0x00001f51, 0x00001f59, 0x00001f5b, 0x00001f53, 0x00001f5b, 0x00001f5d, 0x00001f55, 0x00001f5d, 0x00001f5f, 0x00001f57, 0x00001f5f, 0x00001f68, 0x00001f60, 0x00001f68, 0x00001f69, 0x00001f61, 0x00001f69, 0x00001f6a, 0x00001f62, 0x00001f6a, 0x00001f6b, 0x00001f63, 0x00001f6b, 0x00001f6c, 0x00001f64, 0x00001f6c, 0x00001f6d, 0x00001f65, 0x00001f6d, 0x00001f6e, 0x00001f66, 0x00001f6e, 0x00001f6f, 0x00001f67, 0x00001f6f, 0x00001fb8, 0x00001fb0, 0x00001fb8, 0x00001fb9, 0x00001fb1, 0x00001fb9, 0x00001fba, 0x00001f70, 0x00001fba, 0x00001fbb, 0x00001f71, 0x00001fbb, 0x00001fc8, 0x00001f72, 0x00001fc8, 0x00001fc9, 0x00001f73, 0x00001fc9, 0x00001fca, 0x00001f74, 0x00001fca, 0x00001fcb, 0x00001f75, 0x00001fcb, 0x00001fd8, 0x00001fd0, 0x00001fd8, 0x00001fd9, 0x00001fd1, 0x00001fd9, 0x00001fda, 0x00001f76, 0x00001fda, 0x00001fdb, 0x00001f77, 0x00001fdb, 0x00001fe8, 0x00001fe0, 0x00001fe8, 0x00001fe9, 0x00001fe1, 0x00001fe9, 0x00001fea, 0x00001f7a, 0x00001fea, 0x00001feb, 0x00001f7b, 0x00001feb, 0x00001fec, 0x00001fe5, 0x00001fec, 0x00001ff8, 0x00001f78, 0x00001ff8, 0x00001ff9, 0x00001f79, 0x00001ff9, 0x00001ffa, 0x00001f7c, 0x00001ffa, 0x00001ffb, 0x00001f7d, 0x00001ffb, 0x00002126, 0x000003c9, 0x00002126, 0x0000212a, 0x0000006b, 0x0000212a, 0x0000212b, 0x000000e5, 0x0000212b, 0x00002160, 0x00002170, 0x00002160, 0x00002161, 0x00002171, 0x00002161, 0x00002162, 0x00002172, 0x00002162, 0x00002163, 0x00002173, 0x00002163, 0x00002164, 0x00002174, 0x00002164, 0x00002165, 0x00002175, 0x00002165, 0x00002166, 0x00002176, 0x00002166, 0x00002167, 0x00002177, 0x00002167, 0x00002168, 0x00002178, 0x00002168, 0x00002169, 0x00002179, 0x00002169, 0x0000216a, 0x0000217a, 0x0000216a, 0x0000216b, 0x0000217b, 0x0000216b, 0x0000216c, 0x0000217c, 0x0000216c, 0x0000216d, 0x0000217d, 0x0000216d, 0x0000216e, 0x0000217e, 0x0000216e, 0x0000216f, 0x0000217f, 0x0000216f, 0x000024b6, 0x000024d0, 0x000024b6, 0x000024b7, 0x000024d1, 0x000024b7, 0x000024b8, 0x000024d2, 0x000024b8, 0x000024b9, 0x000024d3, 0x000024b9, 0x000024ba, 0x000024d4, 0x000024ba, 0x000024bb, 0x000024d5, 0x000024bb, 0x000024bc, 0x000024d6, 0x000024bc, 0x000024bd, 0x000024d7, 0x000024bd, 0x000024be, 0x000024d8, 0x000024be, 0x000024bf, 0x000024d9, 0x000024bf, 0x000024c0, 0x000024da, 0x000024c0, 0x000024c1, 0x000024db, 0x000024c1, 0x000024c2, 0x000024dc, 0x000024c2, 0x000024c3, 0x000024dd, 0x000024c3, 0x000024c4, 0x000024de, 0x000024c4, 0x000024c5, 0x000024df, 0x000024c5, 0x000024c6, 0x000024e0, 0x000024c6, 0x000024c7, 0x000024e1, 0x000024c7, 0x000024c8, 0x000024e2, 0x000024c8, 0x000024c9, 0x000024e3, 0x000024c9, 0x000024ca, 0x000024e4, 0x000024ca, 0x000024cb, 0x000024e5, 0x000024cb, 0x000024cc, 0x000024e6, 0x000024cc, 0x000024cd, 0x000024e7, 0x000024cd, 0x000024ce, 0x000024e8, 0x000024ce, 0x000024cf, 0x000024e9, 0x000024cf, 0x0000ff21, 0x0000ff41, 0x0000ff21, 0x0000ff22, 0x0000ff42, 0x0000ff22, 0x0000ff23, 0x0000ff43, 0x0000ff23, 0x0000ff24, 0x0000ff44, 0x0000ff24, 0x0000ff25, 0x0000ff45, 0x0000ff25, 0x0000ff26, 0x0000ff46, 0x0000ff26, 0x0000ff27, 0x0000ff47, 0x0000ff27, 0x0000ff28, 0x0000ff48, 0x0000ff28, 0x0000ff29, 0x0000ff49, 0x0000ff29, 0x0000ff2a, 0x0000ff4a, 0x0000ff2a, 0x0000ff2b, 0x0000ff4b, 0x0000ff2b, 0x0000ff2c, 0x0000ff4c, 0x0000ff2c, 0x0000ff2d, 0x0000ff4d, 0x0000ff2d, 0x0000ff2e, 0x0000ff4e, 0x0000ff2e, 0x0000ff2f, 0x0000ff4f, 0x0000ff2f, 0x0000ff30, 0x0000ff50, 0x0000ff30, 0x0000ff31, 0x0000ff51, 0x0000ff31, 0x0000ff32, 0x0000ff52, 0x0000ff32, 0x0000ff33, 0x0000ff53, 0x0000ff33, 0x0000ff34, 0x0000ff54, 0x0000ff34, 0x0000ff35, 0x0000ff55, 0x0000ff35, 0x0000ff36, 0x0000ff56, 0x0000ff36, 0x0000ff37, 0x0000ff57, 0x0000ff37, 0x0000ff38, 0x0000ff58, 0x0000ff38, 0x0000ff39, 0x0000ff59, 0x0000ff39, 0x0000ff3a, 0x0000ff5a, 0x0000ff3a, 0x00010400, 0x00010428, 0x00010400, 0x00010401, 0x00010429, 0x00010401, 0x00010402, 0x0001042a, 0x00010402, 0x00010403, 0x0001042b, 0x00010403, 0x00010404, 0x0001042c, 0x00010404, 0x00010405, 0x0001042d, 0x00010405, 0x00010406, 0x0001042e, 0x00010406, 0x00010407, 0x0001042f, 0x00010407, 0x00010408, 0x00010430, 0x00010408, 0x00010409, 0x00010431, 0x00010409, 0x0001040a, 0x00010432, 0x0001040a, 0x0001040b, 0x00010433, 0x0001040b, 0x0001040c, 0x00010434, 0x0001040c, 0x0001040d, 0x00010435, 0x0001040d, 0x0001040e, 0x00010436, 0x0001040e, 0x0001040f, 0x00010437, 0x0001040f, 0x00010410, 0x00010438, 0x00010410, 0x00010411, 0x00010439, 0x00010411, 0x00010412, 0x0001043a, 0x00010412, 0x00010413, 0x0001043b, 0x00010413, 0x00010414, 0x0001043c, 0x00010414, 0x00010415, 0x0001043d, 0x00010415, 0x00010416, 0x0001043e, 0x00010416, 0x00010417, 0x0001043f, 0x00010417, 0x00010418, 0x00010440, 0x00010418, 0x00010419, 0x00010441, 0x00010419, 0x0001041a, 0x00010442, 0x0001041a, 0x0001041b, 0x00010443, 0x0001041b, 0x0001041c, 0x00010444, 0x0001041c, 0x0001041d, 0x00010445, 0x0001041d, 0x0001041e, 0x00010446, 0x0001041e, 0x0001041f, 0x00010447, 0x0001041f, 0x00010420, 0x00010448, 0x00010420, 0x00010421, 0x00010449, 0x00010421, 0x00010422, 0x0001044a, 0x00010422, 0x00010423, 0x0001044b, 0x00010423, 0x00010424, 0x0001044c, 0x00010424, 0x00010425, 0x0001044d, 0x00010425, 0x00000061, 0x00000041, 0x00000041, 0x00000062, 0x00000042, 0x00000042, 0x00000063, 0x00000043, 0x00000043, 0x00000064, 0x00000044, 0x00000044, 0x00000065, 0x00000045, 0x00000045, 0x00000066, 0x00000046, 0x00000046, 0x00000067, 0x00000047, 0x00000047, 0x00000068, 0x00000048, 0x00000048, 0x00000069, 0x00000049, 0x00000049, 0x0000006a, 0x0000004a, 0x0000004a, 0x0000006b, 0x0000004b, 0x0000004b, 0x0000006c, 0x0000004c, 0x0000004c, 0x0000006d, 0x0000004d, 0x0000004d, 0x0000006e, 0x0000004e, 0x0000004e, 0x0000006f, 0x0000004f, 0x0000004f, 0x00000070, 0x00000050, 0x00000050, 0x00000071, 0x00000051, 0x00000051, 0x00000072, 0x00000052, 0x00000052, 0x00000073, 0x00000053, 0x00000053, 0x00000074, 0x00000054, 0x00000054, 0x00000075, 0x00000055, 0x00000055, 0x00000076, 0x00000056, 0x00000056, 0x00000077, 0x00000057, 0x00000057, 0x00000078, 0x00000058, 0x00000058, 0x00000079, 0x00000059, 0x00000059, 0x0000007a, 0x0000005a, 0x0000005a, 0x000000b5, 0x0000039c, 0x0000039c, 0x000000e0, 0x000000c0, 0x000000c0, 0x000000e1, 0x000000c1, 0x000000c1, 0x000000e2, 0x000000c2, 0x000000c2, 0x000000e3, 0x000000c3, 0x000000c3, 0x000000e4, 0x000000c4, 0x000000c4, 0x000000e5, 0x000000c5, 0x000000c5, 0x000000e6, 0x000000c6, 0x000000c6, 0x000000e7, 0x000000c7, 0x000000c7, 0x000000e8, 0x000000c8, 0x000000c8, 0x000000e9, 0x000000c9, 0x000000c9, 0x000000ea, 0x000000ca, 0x000000ca, 0x000000eb, 0x000000cb, 0x000000cb, 0x000000ec, 0x000000cc, 0x000000cc, 0x000000ed, 0x000000cd, 0x000000cd, 0x000000ee, 0x000000ce, 0x000000ce, 0x000000ef, 0x000000cf, 0x000000cf, 0x000000f0, 0x000000d0, 0x000000d0, 0x000000f1, 0x000000d1, 0x000000d1, 0x000000f2, 0x000000d2, 0x000000d2, 0x000000f3, 0x000000d3, 0x000000d3, 0x000000f4, 0x000000d4, 0x000000d4, 0x000000f5, 0x000000d5, 0x000000d5, 0x000000f6, 0x000000d6, 0x000000d6, 0x000000f8, 0x000000d8, 0x000000d8, 0x000000f9, 0x000000d9, 0x000000d9, 0x000000fa, 0x000000da, 0x000000da, 0x000000fb, 0x000000db, 0x000000db, 0x000000fc, 0x000000dc, 0x000000dc, 0x000000fd, 0x000000dd, 0x000000dd, 0x000000fe, 0x000000de, 0x000000de, 0x000000ff, 0x00000178, 0x00000178, 0x00000101, 0x00000100, 0x00000100, 0x00000103, 0x00000102, 0x00000102, 0x00000105, 0x00000104, 0x00000104, 0x00000107, 0x00000106, 0x00000106, 0x00000109, 0x00000108, 0x00000108, 0x0000010b, 0x0000010a, 0x0000010a, 0x0000010d, 0x0000010c, 0x0000010c, 0x0000010f, 0x0000010e, 0x0000010e, 0x00000111, 0x00000110, 0x00000110, 0x00000113, 0x00000112, 0x00000112, 0x00000115, 0x00000114, 0x00000114, 0x00000117, 0x00000116, 0x00000116, 0x00000119, 0x00000118, 0x00000118, 0x0000011b, 0x0000011a, 0x0000011a, 0x0000011d, 0x0000011c, 0x0000011c, 0x0000011f, 0x0000011e, 0x0000011e, 0x00000121, 0x00000120, 0x00000120, 0x00000123, 0x00000122, 0x00000122, 0x00000125, 0x00000124, 0x00000124, 0x00000127, 0x00000126, 0x00000126, 0x00000129, 0x00000128, 0x00000128, 0x0000012b, 0x0000012a, 0x0000012a, 0x0000012d, 0x0000012c, 0x0000012c, 0x0000012f, 0x0000012e, 0x0000012e, 0x00000131, 0x00000049, 0x00000049, 0x00000133, 0x00000132, 0x00000132, 0x00000135, 0x00000134, 0x00000134, 0x00000137, 0x00000136, 0x00000136, 0x0000013a, 0x00000139, 0x00000139, 0x0000013c, 0x0000013b, 0x0000013b, 0x0000013e, 0x0000013d, 0x0000013d, 0x00000140, 0x0000013f, 0x0000013f, 0x00000142, 0x00000141, 0x00000141, 0x00000144, 0x00000143, 0x00000143, 0x00000146, 0x00000145, 0x00000145, 0x00000148, 0x00000147, 0x00000147, 0x0000014b, 0x0000014a, 0x0000014a, 0x0000014d, 0x0000014c, 0x0000014c, 0x0000014f, 0x0000014e, 0x0000014e, 0x00000151, 0x00000150, 0x00000150, 0x00000153, 0x00000152, 0x00000152, 0x00000155, 0x00000154, 0x00000154, 0x00000157, 0x00000156, 0x00000156, 0x00000159, 0x00000158, 0x00000158, 0x0000015b, 0x0000015a, 0x0000015a, 0x0000015d, 0x0000015c, 0x0000015c, 0x0000015f, 0x0000015e, 0x0000015e, 0x00000161, 0x00000160, 0x00000160, 0x00000163, 0x00000162, 0x00000162, 0x00000165, 0x00000164, 0x00000164, 0x00000167, 0x00000166, 0x00000166, 0x00000169, 0x00000168, 0x00000168, 0x0000016b, 0x0000016a, 0x0000016a, 0x0000016d, 0x0000016c, 0x0000016c, 0x0000016f, 0x0000016e, 0x0000016e, 0x00000171, 0x00000170, 0x00000170, 0x00000173, 0x00000172, 0x00000172, 0x00000175, 0x00000174, 0x00000174, 0x00000177, 0x00000176, 0x00000176, 0x0000017a, 0x00000179, 0x00000179, 0x0000017c, 0x0000017b, 0x0000017b, 0x0000017e, 0x0000017d, 0x0000017d, 0x0000017f, 0x00000053, 0x00000053, 0x00000183, 0x00000182, 0x00000182, 0x00000185, 0x00000184, 0x00000184, 0x00000188, 0x00000187, 0x00000187, 0x0000018c, 0x0000018b, 0x0000018b, 0x00000192, 0x00000191, 0x00000191, 0x00000195, 0x000001f6, 0x000001f6, 0x00000199, 0x00000198, 0x00000198, 0x0000019e, 0x00000220, 0x00000220, 0x000001a1, 0x000001a0, 0x000001a0, 0x000001a3, 0x000001a2, 0x000001a2, 0x000001a5, 0x000001a4, 0x000001a4, 0x000001a8, 0x000001a7, 0x000001a7, 0x000001ad, 0x000001ac, 0x000001ac, 0x000001b0, 0x000001af, 0x000001af, 0x000001b4, 0x000001b3, 0x000001b3, 0x000001b6, 0x000001b5, 0x000001b5, 0x000001b9, 0x000001b8, 0x000001b8, 0x000001bd, 0x000001bc, 0x000001bc, 0x000001bf, 0x000001f7, 0x000001f7, 0x000001c6, 0x000001c4, 0x000001c5, 0x000001c9, 0x000001c7, 0x000001c8, 0x000001cc, 0x000001ca, 0x000001cb, 0x000001ce, 0x000001cd, 0x000001cd, 0x000001d0, 0x000001cf, 0x000001cf, 0x000001d2, 0x000001d1, 0x000001d1, 0x000001d4, 0x000001d3, 0x000001d3, 0x000001d6, 0x000001d5, 0x000001d5, 0x000001d8, 0x000001d7, 0x000001d7, 0x000001da, 0x000001d9, 0x000001d9, 0x000001dc, 0x000001db, 0x000001db, 0x000001dd, 0x0000018e, 0x0000018e, 0x000001df, 0x000001de, 0x000001de, 0x000001e1, 0x000001e0, 0x000001e0, 0x000001e3, 0x000001e2, 0x000001e2, 0x000001e5, 0x000001e4, 0x000001e4, 0x000001e7, 0x000001e6, 0x000001e6, 0x000001e9, 0x000001e8, 0x000001e8, 0x000001eb, 0x000001ea, 0x000001ea, 0x000001ed, 0x000001ec, 0x000001ec, 0x000001ef, 0x000001ee, 0x000001ee, 0x000001f3, 0x000001f1, 0x000001f2, 0x000001f5, 0x000001f4, 0x000001f4, 0x000001f9, 0x000001f8, 0x000001f8, 0x000001fb, 0x000001fa, 0x000001fa, 0x000001fd, 0x000001fc, 0x000001fc, 0x000001ff, 0x000001fe, 0x000001fe, 0x00000201, 0x00000200, 0x00000200, 0x00000203, 0x00000202, 0x00000202, 0x00000205, 0x00000204, 0x00000204, 0x00000207, 0x00000206, 0x00000206, 0x00000209, 0x00000208, 0x00000208, 0x0000020b, 0x0000020a, 0x0000020a, 0x0000020d, 0x0000020c, 0x0000020c, 0x0000020f, 0x0000020e, 0x0000020e, 0x00000211, 0x00000210, 0x00000210, 0x00000213, 0x00000212, 0x00000212, 0x00000215, 0x00000214, 0x00000214, 0x00000217, 0x00000216, 0x00000216, 0x00000219, 0x00000218, 0x00000218, 0x0000021b, 0x0000021a, 0x0000021a, 0x0000021d, 0x0000021c, 0x0000021c, 0x0000021f, 0x0000021e, 0x0000021e, 0x00000223, 0x00000222, 0x00000222, 0x00000225, 0x00000224, 0x00000224, 0x00000227, 0x00000226, 0x00000226, 0x00000229, 0x00000228, 0x00000228, 0x0000022b, 0x0000022a, 0x0000022a, 0x0000022d, 0x0000022c, 0x0000022c, 0x0000022f, 0x0000022e, 0x0000022e, 0x00000231, 0x00000230, 0x00000230, 0x00000233, 0x00000232, 0x00000232, 0x00000253, 0x00000181, 0x00000181, 0x00000254, 0x00000186, 0x00000186, 0x00000256, 0x00000189, 0x00000189, 0x00000257, 0x0000018a, 0x0000018a, 0x00000259, 0x0000018f, 0x0000018f, 0x0000025b, 0x00000190, 0x00000190, 0x00000260, 0x00000193, 0x00000193, 0x00000263, 0x00000194, 0x00000194, 0x00000268, 0x00000197, 0x00000197, 0x00000269, 0x00000196, 0x00000196, 0x0000026f, 0x0000019c, 0x0000019c, 0x00000272, 0x0000019d, 0x0000019d, 0x00000275, 0x0000019f, 0x0000019f, 0x00000280, 0x000001a6, 0x000001a6, 0x00000283, 0x000001a9, 0x000001a9, 0x00000288, 0x000001ae, 0x000001ae, 0x0000028a, 0x000001b1, 0x000001b1, 0x0000028b, 0x000001b2, 0x000001b2, 0x00000292, 0x000001b7, 0x000001b7, 0x00000345, 0x00000399, 0x00000399, 0x000003ac, 0x00000386, 0x00000386, 0x000003ad, 0x00000388, 0x00000388, 0x000003ae, 0x00000389, 0x00000389, 0x000003af, 0x0000038a, 0x0000038a, 0x000003b1, 0x00000391, 0x00000391, 0x000003b2, 0x00000392, 0x00000392, 0x000003b3, 0x00000393, 0x00000393, 0x000003b4, 0x00000394, 0x00000394, 0x000003b5, 0x00000395, 0x00000395, 0x000003b6, 0x00000396, 0x00000396, 0x000003b7, 0x00000397, 0x00000397, 0x000003b8, 0x00000398, 0x00000398, 0x000003b9, 0x00000399, 0x00000399, 0x000003ba, 0x0000039a, 0x0000039a, 0x000003bb, 0x0000039b, 0x0000039b, 0x000003bc, 0x0000039c, 0x0000039c, 0x000003bd, 0x0000039d, 0x0000039d, 0x000003be, 0x0000039e, 0x0000039e, 0x000003bf, 0x0000039f, 0x0000039f, 0x000003c0, 0x000003a0, 0x000003a0, 0x000003c1, 0x000003a1, 0x000003a1, 0x000003c2, 0x000003a3, 0x000003a3, 0x000003c3, 0x000003a3, 0x000003a3, 0x000003c4, 0x000003a4, 0x000003a4, 0x000003c5, 0x000003a5, 0x000003a5, 0x000003c6, 0x000003a6, 0x000003a6, 0x000003c7, 0x000003a7, 0x000003a7, 0x000003c8, 0x000003a8, 0x000003a8, 0x000003c9, 0x000003a9, 0x000003a9, 0x000003ca, 0x000003aa, 0x000003aa, 0x000003cb, 0x000003ab, 0x000003ab, 0x000003cc, 0x0000038c, 0x0000038c, 0x000003cd, 0x0000038e, 0x0000038e, 0x000003ce, 0x0000038f, 0x0000038f, 0x000003d0, 0x00000392, 0x00000392, 0x000003d1, 0x00000398, 0x00000398, 0x000003d5, 0x000003a6, 0x000003a6, 0x000003d6, 0x000003a0, 0x000003a0, 0x000003d9, 0x000003d8, 0x000003d8, 0x000003db, 0x000003da, 0x000003da, 0x000003dd, 0x000003dc, 0x000003dc, 0x000003df, 0x000003de, 0x000003de, 0x000003e1, 0x000003e0, 0x000003e0, 0x000003e3, 0x000003e2, 0x000003e2, 0x000003e5, 0x000003e4, 0x000003e4, 0x000003e7, 0x000003e6, 0x000003e6, 0x000003e9, 0x000003e8, 0x000003e8, 0x000003eb, 0x000003ea, 0x000003ea, 0x000003ed, 0x000003ec, 0x000003ec, 0x000003ef, 0x000003ee, 0x000003ee, 0x000003f0, 0x0000039a, 0x0000039a, 0x000003f1, 0x000003a1, 0x000003a1, 0x000003f2, 0x000003a3, 0x000003a3, 0x000003f5, 0x00000395, 0x00000395, 0x00000430, 0x00000410, 0x00000410, 0x00000431, 0x00000411, 0x00000411, 0x00000432, 0x00000412, 0x00000412, 0x00000433, 0x00000413, 0x00000413, 0x00000434, 0x00000414, 0x00000414, 0x00000435, 0x00000415, 0x00000415, 0x00000436, 0x00000416, 0x00000416, 0x00000437, 0x00000417, 0x00000417, 0x00000438, 0x00000418, 0x00000418, 0x00000439, 0x00000419, 0x00000419, 0x0000043a, 0x0000041a, 0x0000041a, 0x0000043b, 0x0000041b, 0x0000041b, 0x0000043c, 0x0000041c, 0x0000041c, 0x0000043d, 0x0000041d, 0x0000041d, 0x0000043e, 0x0000041e, 0x0000041e, 0x0000043f, 0x0000041f, 0x0000041f, 0x00000440, 0x00000420, 0x00000420, 0x00000441, 0x00000421, 0x00000421, 0x00000442, 0x00000422, 0x00000422, 0x00000443, 0x00000423, 0x00000423, 0x00000444, 0x00000424, 0x00000424, 0x00000445, 0x00000425, 0x00000425, 0x00000446, 0x00000426, 0x00000426, 0x00000447, 0x00000427, 0x00000427, 0x00000448, 0x00000428, 0x00000428, 0x00000449, 0x00000429, 0x00000429, 0x0000044a, 0x0000042a, 0x0000042a, 0x0000044b, 0x0000042b, 0x0000042b, 0x0000044c, 0x0000042c, 0x0000042c, 0x0000044d, 0x0000042d, 0x0000042d, 0x0000044e, 0x0000042e, 0x0000042e, 0x0000044f, 0x0000042f, 0x0000042f, 0x00000450, 0x00000400, 0x00000400, 0x00000451, 0x00000401, 0x00000401, 0x00000452, 0x00000402, 0x00000402, 0x00000453, 0x00000403, 0x00000403, 0x00000454, 0x00000404, 0x00000404, 0x00000455, 0x00000405, 0x00000405, 0x00000456, 0x00000406, 0x00000406, 0x00000457, 0x00000407, 0x00000407, 0x00000458, 0x00000408, 0x00000408, 0x00000459, 0x00000409, 0x00000409, 0x0000045a, 0x0000040a, 0x0000040a, 0x0000045b, 0x0000040b, 0x0000040b, 0x0000045c, 0x0000040c, 0x0000040c, 0x0000045d, 0x0000040d, 0x0000040d, 0x0000045e, 0x0000040e, 0x0000040e, 0x0000045f, 0x0000040f, 0x0000040f, 0x00000461, 0x00000460, 0x00000460, 0x00000463, 0x00000462, 0x00000462, 0x00000465, 0x00000464, 0x00000464, 0x00000467, 0x00000466, 0x00000466, 0x00000469, 0x00000468, 0x00000468, 0x0000046b, 0x0000046a, 0x0000046a, 0x0000046d, 0x0000046c, 0x0000046c, 0x0000046f, 0x0000046e, 0x0000046e, 0x00000471, 0x00000470, 0x00000470, 0x00000473, 0x00000472, 0x00000472, 0x00000475, 0x00000474, 0x00000474, 0x00000477, 0x00000476, 0x00000476, 0x00000479, 0x00000478, 0x00000478, 0x0000047b, 0x0000047a, 0x0000047a, 0x0000047d, 0x0000047c, 0x0000047c, 0x0000047f, 0x0000047e, 0x0000047e, 0x00000481, 0x00000480, 0x00000480, 0x0000048b, 0x0000048a, 0x0000048a, 0x0000048d, 0x0000048c, 0x0000048c, 0x0000048f, 0x0000048e, 0x0000048e, 0x00000491, 0x00000490, 0x00000490, 0x00000493, 0x00000492, 0x00000492, 0x00000495, 0x00000494, 0x00000494, 0x00000497, 0x00000496, 0x00000496, 0x00000499, 0x00000498, 0x00000498, 0x0000049b, 0x0000049a, 0x0000049a, 0x0000049d, 0x0000049c, 0x0000049c, 0x0000049f, 0x0000049e, 0x0000049e, 0x000004a1, 0x000004a0, 0x000004a0, 0x000004a3, 0x000004a2, 0x000004a2, 0x000004a5, 0x000004a4, 0x000004a4, 0x000004a7, 0x000004a6, 0x000004a6, 0x000004a9, 0x000004a8, 0x000004a8, 0x000004ab, 0x000004aa, 0x000004aa, 0x000004ad, 0x000004ac, 0x000004ac, 0x000004af, 0x000004ae, 0x000004ae, 0x000004b1, 0x000004b0, 0x000004b0, 0x000004b3, 0x000004b2, 0x000004b2, 0x000004b5, 0x000004b4, 0x000004b4, 0x000004b7, 0x000004b6, 0x000004b6, 0x000004b9, 0x000004b8, 0x000004b8, 0x000004bb, 0x000004ba, 0x000004ba, 0x000004bd, 0x000004bc, 0x000004bc, 0x000004bf, 0x000004be, 0x000004be, 0x000004c2, 0x000004c1, 0x000004c1, 0x000004c4, 0x000004c3, 0x000004c3, 0x000004c6, 0x000004c5, 0x000004c5, 0x000004c8, 0x000004c7, 0x000004c7, 0x000004ca, 0x000004c9, 0x000004c9, 0x000004cc, 0x000004cb, 0x000004cb, 0x000004ce, 0x000004cd, 0x000004cd, 0x000004d1, 0x000004d0, 0x000004d0, 0x000004d3, 0x000004d2, 0x000004d2, 0x000004d5, 0x000004d4, 0x000004d4, 0x000004d7, 0x000004d6, 0x000004d6, 0x000004d9, 0x000004d8, 0x000004d8, 0x000004db, 0x000004da, 0x000004da, 0x000004dd, 0x000004dc, 0x000004dc, 0x000004df, 0x000004de, 0x000004de, 0x000004e1, 0x000004e0, 0x000004e0, 0x000004e3, 0x000004e2, 0x000004e2, 0x000004e5, 0x000004e4, 0x000004e4, 0x000004e7, 0x000004e6, 0x000004e6, 0x000004e9, 0x000004e8, 0x000004e8, 0x000004eb, 0x000004ea, 0x000004ea, 0x000004ed, 0x000004ec, 0x000004ec, 0x000004ef, 0x000004ee, 0x000004ee, 0x000004f1, 0x000004f0, 0x000004f0, 0x000004f3, 0x000004f2, 0x000004f2, 0x000004f5, 0x000004f4, 0x000004f4, 0x000004f9, 0x000004f8, 0x000004f8, 0x00000501, 0x00000500, 0x00000500, 0x00000503, 0x00000502, 0x00000502, 0x00000505, 0x00000504, 0x00000504, 0x00000507, 0x00000506, 0x00000506, 0x00000509, 0x00000508, 0x00000508, 0x0000050b, 0x0000050a, 0x0000050a, 0x0000050d, 0x0000050c, 0x0000050c, 0x0000050f, 0x0000050e, 0x0000050e, 0x00000561, 0x00000531, 0x00000531, 0x00000562, 0x00000532, 0x00000532, 0x00000563, 0x00000533, 0x00000533, 0x00000564, 0x00000534, 0x00000534, 0x00000565, 0x00000535, 0x00000535, 0x00000566, 0x00000536, 0x00000536, 0x00000567, 0x00000537, 0x00000537, 0x00000568, 0x00000538, 0x00000538, 0x00000569, 0x00000539, 0x00000539, 0x0000056a, 0x0000053a, 0x0000053a, 0x0000056b, 0x0000053b, 0x0000053b, 0x0000056c, 0x0000053c, 0x0000053c, 0x0000056d, 0x0000053d, 0x0000053d, 0x0000056e, 0x0000053e, 0x0000053e, 0x0000056f, 0x0000053f, 0x0000053f, 0x00000570, 0x00000540, 0x00000540, 0x00000571, 0x00000541, 0x00000541, 0x00000572, 0x00000542, 0x00000542, 0x00000573, 0x00000543, 0x00000543, 0x00000574, 0x00000544, 0x00000544, 0x00000575, 0x00000545, 0x00000545, 0x00000576, 0x00000546, 0x00000546, 0x00000577, 0x00000547, 0x00000547, 0x00000578, 0x00000548, 0x00000548, 0x00000579, 0x00000549, 0x00000549, 0x0000057a, 0x0000054a, 0x0000054a, 0x0000057b, 0x0000054b, 0x0000054b, 0x0000057c, 0x0000054c, 0x0000054c, 0x0000057d, 0x0000054d, 0x0000054d, 0x0000057e, 0x0000054e, 0x0000054e, 0x0000057f, 0x0000054f, 0x0000054f, 0x00000580, 0x00000550, 0x00000550, 0x00000581, 0x00000551, 0x00000551, 0x00000582, 0x00000552, 0x00000552, 0x00000583, 0x00000553, 0x00000553, 0x00000584, 0x00000554, 0x00000554, 0x00000585, 0x00000555, 0x00000555, 0x00000586, 0x00000556, 0x00000556, 0x00001e01, 0x00001e00, 0x00001e00, 0x00001e03, 0x00001e02, 0x00001e02, 0x00001e05, 0x00001e04, 0x00001e04, 0x00001e07, 0x00001e06, 0x00001e06, 0x00001e09, 0x00001e08, 0x00001e08, 0x00001e0b, 0x00001e0a, 0x00001e0a, 0x00001e0d, 0x00001e0c, 0x00001e0c, 0x00001e0f, 0x00001e0e, 0x00001e0e, 0x00001e11, 0x00001e10, 0x00001e10, 0x00001e13, 0x00001e12, 0x00001e12, 0x00001e15, 0x00001e14, 0x00001e14, 0x00001e17, 0x00001e16, 0x00001e16, 0x00001e19, 0x00001e18, 0x00001e18, 0x00001e1b, 0x00001e1a, 0x00001e1a, 0x00001e1d, 0x00001e1c, 0x00001e1c, 0x00001e1f, 0x00001e1e, 0x00001e1e, 0x00001e21, 0x00001e20, 0x00001e20, 0x00001e23, 0x00001e22, 0x00001e22, 0x00001e25, 0x00001e24, 0x00001e24, 0x00001e27, 0x00001e26, 0x00001e26, 0x00001e29, 0x00001e28, 0x00001e28, 0x00001e2b, 0x00001e2a, 0x00001e2a, 0x00001e2d, 0x00001e2c, 0x00001e2c, 0x00001e2f, 0x00001e2e, 0x00001e2e, 0x00001e31, 0x00001e30, 0x00001e30, 0x00001e33, 0x00001e32, 0x00001e32, 0x00001e35, 0x00001e34, 0x00001e34, 0x00001e37, 0x00001e36, 0x00001e36, 0x00001e39, 0x00001e38, 0x00001e38, 0x00001e3b, 0x00001e3a, 0x00001e3a, 0x00001e3d, 0x00001e3c, 0x00001e3c, 0x00001e3f, 0x00001e3e, 0x00001e3e, 0x00001e41, 0x00001e40, 0x00001e40, 0x00001e43, 0x00001e42, 0x00001e42, 0x00001e45, 0x00001e44, 0x00001e44, 0x00001e47, 0x00001e46, 0x00001e46, 0x00001e49, 0x00001e48, 0x00001e48, 0x00001e4b, 0x00001e4a, 0x00001e4a, 0x00001e4d, 0x00001e4c, 0x00001e4c, 0x00001e4f, 0x00001e4e, 0x00001e4e, 0x00001e51, 0x00001e50, 0x00001e50, 0x00001e53, 0x00001e52, 0x00001e52, 0x00001e55, 0x00001e54, 0x00001e54, 0x00001e57, 0x00001e56, 0x00001e56, 0x00001e59, 0x00001e58, 0x00001e58, 0x00001e5b, 0x00001e5a, 0x00001e5a, 0x00001e5d, 0x00001e5c, 0x00001e5c, 0x00001e5f, 0x00001e5e, 0x00001e5e, 0x00001e61, 0x00001e60, 0x00001e60, 0x00001e63, 0x00001e62, 0x00001e62, 0x00001e65, 0x00001e64, 0x00001e64, 0x00001e67, 0x00001e66, 0x00001e66, 0x00001e69, 0x00001e68, 0x00001e68, 0x00001e6b, 0x00001e6a, 0x00001e6a, 0x00001e6d, 0x00001e6c, 0x00001e6c, 0x00001e6f, 0x00001e6e, 0x00001e6e, 0x00001e71, 0x00001e70, 0x00001e70, 0x00001e73, 0x00001e72, 0x00001e72, 0x00001e75, 0x00001e74, 0x00001e74, 0x00001e77, 0x00001e76, 0x00001e76, 0x00001e79, 0x00001e78, 0x00001e78, 0x00001e7b, 0x00001e7a, 0x00001e7a, 0x00001e7d, 0x00001e7c, 0x00001e7c, 0x00001e7f, 0x00001e7e, 0x00001e7e, 0x00001e81, 0x00001e80, 0x00001e80, 0x00001e83, 0x00001e82, 0x00001e82, 0x00001e85, 0x00001e84, 0x00001e84, 0x00001e87, 0x00001e86, 0x00001e86, 0x00001e89, 0x00001e88, 0x00001e88, 0x00001e8b, 0x00001e8a, 0x00001e8a, 0x00001e8d, 0x00001e8c, 0x00001e8c, 0x00001e8f, 0x00001e8e, 0x00001e8e, 0x00001e91, 0x00001e90, 0x00001e90, 0x00001e93, 0x00001e92, 0x00001e92, 0x00001e95, 0x00001e94, 0x00001e94, 0x00001e9b, 0x00001e60, 0x00001e60, 0x00001ea1, 0x00001ea0, 0x00001ea0, 0x00001ea3, 0x00001ea2, 0x00001ea2, 0x00001ea5, 0x00001ea4, 0x00001ea4, 0x00001ea7, 0x00001ea6, 0x00001ea6, 0x00001ea9, 0x00001ea8, 0x00001ea8, 0x00001eab, 0x00001eaa, 0x00001eaa, 0x00001ead, 0x00001eac, 0x00001eac, 0x00001eaf, 0x00001eae, 0x00001eae, 0x00001eb1, 0x00001eb0, 0x00001eb0, 0x00001eb3, 0x00001eb2, 0x00001eb2, 0x00001eb5, 0x00001eb4, 0x00001eb4, 0x00001eb7, 0x00001eb6, 0x00001eb6, 0x00001eb9, 0x00001eb8, 0x00001eb8, 0x00001ebb, 0x00001eba, 0x00001eba, 0x00001ebd, 0x00001ebc, 0x00001ebc, 0x00001ebf, 0x00001ebe, 0x00001ebe, 0x00001ec1, 0x00001ec0, 0x00001ec0, 0x00001ec3, 0x00001ec2, 0x00001ec2, 0x00001ec5, 0x00001ec4, 0x00001ec4, 0x00001ec7, 0x00001ec6, 0x00001ec6, 0x00001ec9, 0x00001ec8, 0x00001ec8, 0x00001ecb, 0x00001eca, 0x00001eca, 0x00001ecd, 0x00001ecc, 0x00001ecc, 0x00001ecf, 0x00001ece, 0x00001ece, 0x00001ed1, 0x00001ed0, 0x00001ed0, 0x00001ed3, 0x00001ed2, 0x00001ed2, 0x00001ed5, 0x00001ed4, 0x00001ed4, 0x00001ed7, 0x00001ed6, 0x00001ed6, 0x00001ed9, 0x00001ed8, 0x00001ed8, 0x00001edb, 0x00001eda, 0x00001eda, 0x00001edd, 0x00001edc, 0x00001edc, 0x00001edf, 0x00001ede, 0x00001ede, 0x00001ee1, 0x00001ee0, 0x00001ee0, 0x00001ee3, 0x00001ee2, 0x00001ee2, 0x00001ee5, 0x00001ee4, 0x00001ee4, 0x00001ee7, 0x00001ee6, 0x00001ee6, 0x00001ee9, 0x00001ee8, 0x00001ee8, 0x00001eeb, 0x00001eea, 0x00001eea, 0x00001eed, 0x00001eec, 0x00001eec, 0x00001eef, 0x00001eee, 0x00001eee, 0x00001ef1, 0x00001ef0, 0x00001ef0, 0x00001ef3, 0x00001ef2, 0x00001ef2, 0x00001ef5, 0x00001ef4, 0x00001ef4, 0x00001ef7, 0x00001ef6, 0x00001ef6, 0x00001ef9, 0x00001ef8, 0x00001ef8, 0x00001f00, 0x00001f08, 0x00001f08, 0x00001f01, 0x00001f09, 0x00001f09, 0x00001f02, 0x00001f0a, 0x00001f0a, 0x00001f03, 0x00001f0b, 0x00001f0b, 0x00001f04, 0x00001f0c, 0x00001f0c, 0x00001f05, 0x00001f0d, 0x00001f0d, 0x00001f06, 0x00001f0e, 0x00001f0e, 0x00001f07, 0x00001f0f, 0x00001f0f, 0x00001f10, 0x00001f18, 0x00001f18, 0x00001f11, 0x00001f19, 0x00001f19, 0x00001f12, 0x00001f1a, 0x00001f1a, 0x00001f13, 0x00001f1b, 0x00001f1b, 0x00001f14, 0x00001f1c, 0x00001f1c, 0x00001f15, 0x00001f1d, 0x00001f1d, 0x00001f20, 0x00001f28, 0x00001f28, 0x00001f21, 0x00001f29, 0x00001f29, 0x00001f22, 0x00001f2a, 0x00001f2a, 0x00001f23, 0x00001f2b, 0x00001f2b, 0x00001f24, 0x00001f2c, 0x00001f2c, 0x00001f25, 0x00001f2d, 0x00001f2d, 0x00001f26, 0x00001f2e, 0x00001f2e, 0x00001f27, 0x00001f2f, 0x00001f2f, 0x00001f30, 0x00001f38, 0x00001f38, 0x00001f31, 0x00001f39, 0x00001f39, 0x00001f32, 0x00001f3a, 0x00001f3a, 0x00001f33, 0x00001f3b, 0x00001f3b, 0x00001f34, 0x00001f3c, 0x00001f3c, 0x00001f35, 0x00001f3d, 0x00001f3d, 0x00001f36, 0x00001f3e, 0x00001f3e, 0x00001f37, 0x00001f3f, 0x00001f3f, 0x00001f40, 0x00001f48, 0x00001f48, 0x00001f41, 0x00001f49, 0x00001f49, 0x00001f42, 0x00001f4a, 0x00001f4a, 0x00001f43, 0x00001f4b, 0x00001f4b, 0x00001f44, 0x00001f4c, 0x00001f4c, 0x00001f45, 0x00001f4d, 0x00001f4d, 0x00001f51, 0x00001f59, 0x00001f59, 0x00001f53, 0x00001f5b, 0x00001f5b, 0x00001f55, 0x00001f5d, 0x00001f5d, 0x00001f57, 0x00001f5f, 0x00001f5f, 0x00001f60, 0x00001f68, 0x00001f68, 0x00001f61, 0x00001f69, 0x00001f69, 0x00001f62, 0x00001f6a, 0x00001f6a, 0x00001f63, 0x00001f6b, 0x00001f6b, 0x00001f64, 0x00001f6c, 0x00001f6c, 0x00001f65, 0x00001f6d, 0x00001f6d, 0x00001f66, 0x00001f6e, 0x00001f6e, 0x00001f67, 0x00001f6f, 0x00001f6f, 0x00001f70, 0x00001fba, 0x00001fba, 0x00001f71, 0x00001fbb, 0x00001fbb, 0x00001f72, 0x00001fc8, 0x00001fc8, 0x00001f73, 0x00001fc9, 0x00001fc9, 0x00001f74, 0x00001fca, 0x00001fca, 0x00001f75, 0x00001fcb, 0x00001fcb, 0x00001f76, 0x00001fda, 0x00001fda, 0x00001f77, 0x00001fdb, 0x00001fdb, 0x00001f78, 0x00001ff8, 0x00001ff8, 0x00001f79, 0x00001ff9, 0x00001ff9, 0x00001f7a, 0x00001fea, 0x00001fea, 0x00001f7b, 0x00001feb, 0x00001feb, 0x00001f7c, 0x00001ffa, 0x00001ffa, 0x00001f7d, 0x00001ffb, 0x00001ffb, 0x00001f80, 0x00001f88, 0x00001f88, 0x00001f81, 0x00001f89, 0x00001f89, 0x00001f82, 0x00001f8a, 0x00001f8a, 0x00001f83, 0x00001f8b, 0x00001f8b, 0x00001f84, 0x00001f8c, 0x00001f8c, 0x00001f85, 0x00001f8d, 0x00001f8d, 0x00001f86, 0x00001f8e, 0x00001f8e, 0x00001f87, 0x00001f8f, 0x00001f8f, 0x00001f90, 0x00001f98, 0x00001f98, 0x00001f91, 0x00001f99, 0x00001f99, 0x00001f92, 0x00001f9a, 0x00001f9a, 0x00001f93, 0x00001f9b, 0x00001f9b, 0x00001f94, 0x00001f9c, 0x00001f9c, 0x00001f95, 0x00001f9d, 0x00001f9d, 0x00001f96, 0x00001f9e, 0x00001f9e, 0x00001f97, 0x00001f9f, 0x00001f9f, 0x00001fa0, 0x00001fa8, 0x00001fa8, 0x00001fa1, 0x00001fa9, 0x00001fa9, 0x00001fa2, 0x00001faa, 0x00001faa, 0x00001fa3, 0x00001fab, 0x00001fab, 0x00001fa4, 0x00001fac, 0x00001fac, 0x00001fa5, 0x00001fad, 0x00001fad, 0x00001fa6, 0x00001fae, 0x00001fae, 0x00001fa7, 0x00001faf, 0x00001faf, 0x00001fb0, 0x00001fb8, 0x00001fb8, 0x00001fb1, 0x00001fb9, 0x00001fb9, 0x00001fb3, 0x00001fbc, 0x00001fbc, 0x00001fbe, 0x00000399, 0x00000399, 0x00001fc3, 0x00001fcc, 0x00001fcc, 0x00001fd0, 0x00001fd8, 0x00001fd8, 0x00001fd1, 0x00001fd9, 0x00001fd9, 0x00001fe0, 0x00001fe8, 0x00001fe8, 0x00001fe1, 0x00001fe9, 0x00001fe9, 0x00001fe5, 0x00001fec, 0x00001fec, 0x00001ff3, 0x00001ffc, 0x00001ffc, 0x00002170, 0x00002160, 0x00002160, 0x00002171, 0x00002161, 0x00002161, 0x00002172, 0x00002162, 0x00002162, 0x00002173, 0x00002163, 0x00002163, 0x00002174, 0x00002164, 0x00002164, 0x00002175, 0x00002165, 0x00002165, 0x00002176, 0x00002166, 0x00002166, 0x00002177, 0x00002167, 0x00002167, 0x00002178, 0x00002168, 0x00002168, 0x00002179, 0x00002169, 0x00002169, 0x0000217a, 0x0000216a, 0x0000216a, 0x0000217b, 0x0000216b, 0x0000216b, 0x0000217c, 0x0000216c, 0x0000216c, 0x0000217d, 0x0000216d, 0x0000216d, 0x0000217e, 0x0000216e, 0x0000216e, 0x0000217f, 0x0000216f, 0x0000216f, 0x000024d0, 0x000024b6, 0x000024b6, 0x000024d1, 0x000024b7, 0x000024b7, 0x000024d2, 0x000024b8, 0x000024b8, 0x000024d3, 0x000024b9, 0x000024b9, 0x000024d4, 0x000024ba, 0x000024ba, 0x000024d5, 0x000024bb, 0x000024bb, 0x000024d6, 0x000024bc, 0x000024bc, 0x000024d7, 0x000024bd, 0x000024bd, 0x000024d8, 0x000024be, 0x000024be, 0x000024d9, 0x000024bf, 0x000024bf, 0x000024da, 0x000024c0, 0x000024c0, 0x000024db, 0x000024c1, 0x000024c1, 0x000024dc, 0x000024c2, 0x000024c2, 0x000024dd, 0x000024c3, 0x000024c3, 0x000024de, 0x000024c4, 0x000024c4, 0x000024df, 0x000024c5, 0x000024c5, 0x000024e0, 0x000024c6, 0x000024c6, 0x000024e1, 0x000024c7, 0x000024c7, 0x000024e2, 0x000024c8, 0x000024c8, 0x000024e3, 0x000024c9, 0x000024c9, 0x000024e4, 0x000024ca, 0x000024ca, 0x000024e5, 0x000024cb, 0x000024cb, 0x000024e6, 0x000024cc, 0x000024cc, 0x000024e7, 0x000024cd, 0x000024cd, 0x000024e8, 0x000024ce, 0x000024ce, 0x000024e9, 0x000024cf, 0x000024cf, 0x0000ff41, 0x0000ff21, 0x0000ff21, 0x0000ff42, 0x0000ff22, 0x0000ff22, 0x0000ff43, 0x0000ff23, 0x0000ff23, 0x0000ff44, 0x0000ff24, 0x0000ff24, 0x0000ff45, 0x0000ff25, 0x0000ff25, 0x0000ff46, 0x0000ff26, 0x0000ff26, 0x0000ff47, 0x0000ff27, 0x0000ff27, 0x0000ff48, 0x0000ff28, 0x0000ff28, 0x0000ff49, 0x0000ff29, 0x0000ff29, 0x0000ff4a, 0x0000ff2a, 0x0000ff2a, 0x0000ff4b, 0x0000ff2b, 0x0000ff2b, 0x0000ff4c, 0x0000ff2c, 0x0000ff2c, 0x0000ff4d, 0x0000ff2d, 0x0000ff2d, 0x0000ff4e, 0x0000ff2e, 0x0000ff2e, 0x0000ff4f, 0x0000ff2f, 0x0000ff2f, 0x0000ff50, 0x0000ff30, 0x0000ff30, 0x0000ff51, 0x0000ff31, 0x0000ff31, 0x0000ff52, 0x0000ff32, 0x0000ff32, 0x0000ff53, 0x0000ff33, 0x0000ff33, 0x0000ff54, 0x0000ff34, 0x0000ff34, 0x0000ff55, 0x0000ff35, 0x0000ff35, 0x0000ff56, 0x0000ff36, 0x0000ff36, 0x0000ff57, 0x0000ff37, 0x0000ff37, 0x0000ff58, 0x0000ff38, 0x0000ff38, 0x0000ff59, 0x0000ff39, 0x0000ff39, 0x0000ff5a, 0x0000ff3a, 0x0000ff3a, 0x00010428, 0x00010400, 0x00010400, 0x00010429, 0x00010401, 0x00010401, 0x0001042a, 0x00010402, 0x00010402, 0x0001042b, 0x00010403, 0x00010403, 0x0001042c, 0x00010404, 0x00010404, 0x0001042d, 0x00010405, 0x00010405, 0x0001042e, 0x00010406, 0x00010406, 0x0001042f, 0x00010407, 0x00010407, 0x00010430, 0x00010408, 0x00010408, 0x00010431, 0x00010409, 0x00010409, 0x00010432, 0x0001040a, 0x0001040a, 0x00010433, 0x0001040b, 0x0001040b, 0x00010434, 0x0001040c, 0x0001040c, 0x00010435, 0x0001040d, 0x0001040d, 0x00010436, 0x0001040e, 0x0001040e, 0x00010437, 0x0001040f, 0x0001040f, 0x00010438, 0x00010410, 0x00010410, 0x00010439, 0x00010411, 0x00010411, 0x0001043a, 0x00010412, 0x00010412, 0x0001043b, 0x00010413, 0x00010413, 0x0001043c, 0x00010414, 0x00010414, 0x0001043d, 0x00010415, 0x00010415, 0x0001043e, 0x00010416, 0x00010416, 0x0001043f, 0x00010417, 0x00010417, 0x00010440, 0x00010418, 0x00010418, 0x00010441, 0x00010419, 0x00010419, 0x00010442, 0x0001041a, 0x0001041a, 0x00010443, 0x0001041b, 0x0001041b, 0x00010444, 0x0001041c, 0x0001041c, 0x00010445, 0x0001041d, 0x0001041d, 0x00010446, 0x0001041e, 0x0001041e, 0x00010447, 0x0001041f, 0x0001041f, 0x00010448, 0x00010420, 0x00010420, 0x00010449, 0x00010421, 0x00010421, 0x0001044a, 0x00010422, 0x00010422, 0x0001044b, 0x00010423, 0x00010423, 0x0001044c, 0x00010424, 0x00010424, 0x0001044d, 0x00010425, 0x00010425, 0x000001c5, 0x000001c4, 0x000001c6, 0x000001c8, 0x000001c7, 0x000001c9, 0x000001cb, 0x000001ca, 0x000001cc, 0x000001f2, 0x000001f1, 0x000001f3, 0x00001f88, 0x00001f88, 0x00001f80, 0x00001f89, 0x00001f89, 0x00001f81, 0x00001f8a, 0x00001f8a, 0x00001f82, 0x00001f8b, 0x00001f8b, 0x00001f83, 0x00001f8c, 0x00001f8c, 0x00001f84, 0x00001f8d, 0x00001f8d, 0x00001f85, 0x00001f8e, 0x00001f8e, 0x00001f86, 0x00001f8f, 0x00001f8f, 0x00001f87, 0x00001f98, 0x00001f98, 0x00001f90, 0x00001f99, 0x00001f99, 0x00001f91, 0x00001f9a, 0x00001f9a, 0x00001f92, 0x00001f9b, 0x00001f9b, 0x00001f93, 0x00001f9c, 0x00001f9c, 0x00001f94, 0x00001f9d, 0x00001f9d, 0x00001f95, 0x00001f9e, 0x00001f9e, 0x00001f96, 0x00001f9f, 0x00001f9f, 0x00001f97, 0x00001fa8, 0x00001fa8, 0x00001fa0, 0x00001fa9, 0x00001fa9, 0x00001fa1, 0x00001faa, 0x00001faa, 0x00001fa2, 0x00001fab, 0x00001fab, 0x00001fa3, 0x00001fac, 0x00001fac, 0x00001fa4, 0x00001fad, 0x00001fad, 0x00001fa5, 0x00001fae, 0x00001fae, 0x00001fa6, 0x00001faf, 0x00001faf, 0x00001fa7, 0x00001fbc, 0x00001fbc, 0x00001fb3, 0x00001fcc, 0x00001fcc, 0x00001fc3, 0x00001ffc, 0x00001ffc, 0x00001ff3 }; static const ac_uint4 _uccomp_size = 3684; static const ac_uint4 _uccomp_data[] = { 0x0000226e, 0x00000002, 0x0000003c, 0x00000338, 0x00002260, 0x00000002, 0x0000003d, 0x00000338, 0x0000226f, 0x00000002, 0x0000003e, 0x00000338, 0x000000c0, 0x00000002, 0x00000041, 0x00000300, 0x000000c1, 0x00000002, 0x00000041, 0x00000301, 0x000000c2, 0x00000002, 0x00000041, 0x00000302, 0x000000c3, 0x00000002, 0x00000041, 0x00000303, 0x00000100, 0x00000002, 0x00000041, 0x00000304, 0x00000102, 0x00000002, 0x00000041, 0x00000306, 0x00000226, 0x00000002, 0x00000041, 0x00000307, 0x000000c4, 0x00000002, 0x00000041, 0x00000308, 0x00001ea2, 0x00000002, 0x00000041, 0x00000309, 0x000000c5, 0x00000002, 0x00000041, 0x0000030a, 0x000001cd, 0x00000002, 0x00000041, 0x0000030c, 0x00000200, 0x00000002, 0x00000041, 0x0000030f, 0x00000202, 0x00000002, 0x00000041, 0x00000311, 0x00001ea0, 0x00000002, 0x00000041, 0x00000323, 0x00001e00, 0x00000002, 0x00000041, 0x00000325, 0x00000104, 0x00000002, 0x00000041, 0x00000328, 0x00001e02, 0x00000002, 0x00000042, 0x00000307, 0x00001e04, 0x00000002, 0x00000042, 0x00000323, 0x00001e06, 0x00000002, 0x00000042, 0x00000331, 0x00000106, 0x00000002, 0x00000043, 0x00000301, 0x00000108, 0x00000002, 0x00000043, 0x00000302, 0x0000010a, 0x00000002, 0x00000043, 0x00000307, 0x0000010c, 0x00000002, 0x00000043, 0x0000030c, 0x000000c7, 0x00000002, 0x00000043, 0x00000327, 0x00001e0a, 0x00000002, 0x00000044, 0x00000307, 0x0000010e, 0x00000002, 0x00000044, 0x0000030c, 0x00001e0c, 0x00000002, 0x00000044, 0x00000323, 0x00001e10, 0x00000002, 0x00000044, 0x00000327, 0x00001e12, 0x00000002, 0x00000044, 0x0000032d, 0x00001e0e, 0x00000002, 0x00000044, 0x00000331, 0x000000c8, 0x00000002, 0x00000045, 0x00000300, 0x000000c9, 0x00000002, 0x00000045, 0x00000301, 0x000000ca, 0x00000002, 0x00000045, 0x00000302, 0x00001ebc, 0x00000002, 0x00000045, 0x00000303, 0x00000112, 0x00000002, 0x00000045, 0x00000304, 0x00000114, 0x00000002, 0x00000045, 0x00000306, 0x00000116, 0x00000002, 0x00000045, 0x00000307, 0x000000cb, 0x00000002, 0x00000045, 0x00000308, 0x00001eba, 0x00000002, 0x00000045, 0x00000309, 0x0000011a, 0x00000002, 0x00000045, 0x0000030c, 0x00000204, 0x00000002, 0x00000045, 0x0000030f, 0x00000206, 0x00000002, 0x00000045, 0x00000311, 0x00001eb8, 0x00000002, 0x00000045, 0x00000323, 0x00000228, 0x00000002, 0x00000045, 0x00000327, 0x00000118, 0x00000002, 0x00000045, 0x00000328, 0x00001e18, 0x00000002, 0x00000045, 0x0000032d, 0x00001e1a, 0x00000002, 0x00000045, 0x00000330, 0x00001e1e, 0x00000002, 0x00000046, 0x00000307, 0x000001f4, 0x00000002, 0x00000047, 0x00000301, 0x0000011c, 0x00000002, 0x00000047, 0x00000302, 0x00001e20, 0x00000002, 0x00000047, 0x00000304, 0x0000011e, 0x00000002, 0x00000047, 0x00000306, 0x00000120, 0x00000002, 0x00000047, 0x00000307, 0x000001e6, 0x00000002, 0x00000047, 0x0000030c, 0x00000122, 0x00000002, 0x00000047, 0x00000327, 0x00000124, 0x00000002, 0x00000048, 0x00000302, 0x00001e22, 0x00000002, 0x00000048, 0x00000307, 0x00001e26, 0x00000002, 0x00000048, 0x00000308, 0x0000021e, 0x00000002, 0x00000048, 0x0000030c, 0x00001e24, 0x00000002, 0x00000048, 0x00000323, 0x00001e28, 0x00000002, 0x00000048, 0x00000327, 0x00001e2a, 0x00000002, 0x00000048, 0x0000032e, 0x000000cc, 0x00000002, 0x00000049, 0x00000300, 0x000000cd, 0x00000002, 0x00000049, 0x00000301, 0x000000ce, 0x00000002, 0x00000049, 0x00000302, 0x00000128, 0x00000002, 0x00000049, 0x00000303, 0x0000012a, 0x00000002, 0x00000049, 0x00000304, 0x0000012c, 0x00000002, 0x00000049, 0x00000306, 0x00000130, 0x00000002, 0x00000049, 0x00000307, 0x000000cf, 0x00000002, 0x00000049, 0x00000308, 0x00001ec8, 0x00000002, 0x00000049, 0x00000309, 0x000001cf, 0x00000002, 0x00000049, 0x0000030c, 0x00000208, 0x00000002, 0x00000049, 0x0000030f, 0x0000020a, 0x00000002, 0x00000049, 0x00000311, 0x00001eca, 0x00000002, 0x00000049, 0x00000323, 0x0000012e, 0x00000002, 0x00000049, 0x00000328, 0x00001e2c, 0x00000002, 0x00000049, 0x00000330, 0x00000134, 0x00000002, 0x0000004a, 0x00000302, 0x00001e30, 0x00000002, 0x0000004b, 0x00000301, 0x000001e8, 0x00000002, 0x0000004b, 0x0000030c, 0x00001e32, 0x00000002, 0x0000004b, 0x00000323, 0x00000136, 0x00000002, 0x0000004b, 0x00000327, 0x00001e34, 0x00000002, 0x0000004b, 0x00000331, 0x00000139, 0x00000002, 0x0000004c, 0x00000301, 0x0000013d, 0x00000002, 0x0000004c, 0x0000030c, 0x00001e36, 0x00000002, 0x0000004c, 0x00000323, 0x0000013b, 0x00000002, 0x0000004c, 0x00000327, 0x00001e3c, 0x00000002, 0x0000004c, 0x0000032d, 0x00001e3a, 0x00000002, 0x0000004c, 0x00000331, 0x00001e3e, 0x00000002, 0x0000004d, 0x00000301, 0x00001e40, 0x00000002, 0x0000004d, 0x00000307, 0x00001e42, 0x00000002, 0x0000004d, 0x00000323, 0x000001f8, 0x00000002, 0x0000004e, 0x00000300, 0x00000143, 0x00000002, 0x0000004e, 0x00000301, 0x000000d1, 0x00000002, 0x0000004e, 0x00000303, 0x00001e44, 0x00000002, 0x0000004e, 0x00000307, 0x00000147, 0x00000002, 0x0000004e, 0x0000030c, 0x00001e46, 0x00000002, 0x0000004e, 0x00000323, 0x00000145, 0x00000002, 0x0000004e, 0x00000327, 0x00001e4a, 0x00000002, 0x0000004e, 0x0000032d, 0x00001e48, 0x00000002, 0x0000004e, 0x00000331, 0x000000d2, 0x00000002, 0x0000004f, 0x00000300, 0x000000d3, 0x00000002, 0x0000004f, 0x00000301, 0x000000d4, 0x00000002, 0x0000004f, 0x00000302, 0x000000d5, 0x00000002, 0x0000004f, 0x00000303, 0x0000014c, 0x00000002, 0x0000004f, 0x00000304, 0x0000014e, 0x00000002, 0x0000004f, 0x00000306, 0x0000022e, 0x00000002, 0x0000004f, 0x00000307, 0x000000d6, 0x00000002, 0x0000004f, 0x00000308, 0x00001ece, 0x00000002, 0x0000004f, 0x00000309, 0x00000150, 0x00000002, 0x0000004f, 0x0000030b, 0x000001d1, 0x00000002, 0x0000004f, 0x0000030c, 0x0000020c, 0x00000002, 0x0000004f, 0x0000030f, 0x0000020e, 0x00000002, 0x0000004f, 0x00000311, 0x000001a0, 0x00000002, 0x0000004f, 0x0000031b, 0x00001ecc, 0x00000002, 0x0000004f, 0x00000323, 0x000001ea, 0x00000002, 0x0000004f, 0x00000328, 0x00001e54, 0x00000002, 0x00000050, 0x00000301, 0x00001e56, 0x00000002, 0x00000050, 0x00000307, 0x00000154, 0x00000002, 0x00000052, 0x00000301, 0x00001e58, 0x00000002, 0x00000052, 0x00000307, 0x00000158, 0x00000002, 0x00000052, 0x0000030c, 0x00000210, 0x00000002, 0x00000052, 0x0000030f, 0x00000212, 0x00000002, 0x00000052, 0x00000311, 0x00001e5a, 0x00000002, 0x00000052, 0x00000323, 0x00000156, 0x00000002, 0x00000052, 0x00000327, 0x00001e5e, 0x00000002, 0x00000052, 0x00000331, 0x0000015a, 0x00000002, 0x00000053, 0x00000301, 0x0000015c, 0x00000002, 0x00000053, 0x00000302, 0x00001e60, 0x00000002, 0x00000053, 0x00000307, 0x00000160, 0x00000002, 0x00000053, 0x0000030c, 0x00001e62, 0x00000002, 0x00000053, 0x00000323, 0x00000218, 0x00000002, 0x00000053, 0x00000326, 0x0000015e, 0x00000002, 0x00000053, 0x00000327, 0x00001e6a, 0x00000002, 0x00000054, 0x00000307, 0x00000164, 0x00000002, 0x00000054, 0x0000030c, 0x00001e6c, 0x00000002, 0x00000054, 0x00000323, 0x0000021a, 0x00000002, 0x00000054, 0x00000326, 0x00000162, 0x00000002, 0x00000054, 0x00000327, 0x00001e70, 0x00000002, 0x00000054, 0x0000032d, 0x00001e6e, 0x00000002, 0x00000054, 0x00000331, 0x000000d9, 0x00000002, 0x00000055, 0x00000300, 0x000000da, 0x00000002, 0x00000055, 0x00000301, 0x000000db, 0x00000002, 0x00000055, 0x00000302, 0x00000168, 0x00000002, 0x00000055, 0x00000303, 0x0000016a, 0x00000002, 0x00000055, 0x00000304, 0x0000016c, 0x00000002, 0x00000055, 0x00000306, 0x000000dc, 0x00000002, 0x00000055, 0x00000308, 0x00001ee6, 0x00000002, 0x00000055, 0x00000309, 0x0000016e, 0x00000002, 0x00000055, 0x0000030a, 0x00000170, 0x00000002, 0x00000055, 0x0000030b, 0x000001d3, 0x00000002, 0x00000055, 0x0000030c, 0x00000214, 0x00000002, 0x00000055, 0x0000030f, 0x00000216, 0x00000002, 0x00000055, 0x00000311, 0x000001af, 0x00000002, 0x00000055, 0x0000031b, 0x00001ee4, 0x00000002, 0x00000055, 0x00000323, 0x00001e72, 0x00000002, 0x00000055, 0x00000324, 0x00000172, 0x00000002, 0x00000055, 0x00000328, 0x00001e76, 0x00000002, 0x00000055, 0x0000032d, 0x00001e74, 0x00000002, 0x00000055, 0x00000330, 0x00001e7c, 0x00000002, 0x00000056, 0x00000303, 0x00001e7e, 0x00000002, 0x00000056, 0x00000323, 0x00001e80, 0x00000002, 0x00000057, 0x00000300, 0x00001e82, 0x00000002, 0x00000057, 0x00000301, 0x00000174, 0x00000002, 0x00000057, 0x00000302, 0x00001e86, 0x00000002, 0x00000057, 0x00000307, 0x00001e84, 0x00000002, 0x00000057, 0x00000308, 0x00001e88, 0x00000002, 0x00000057, 0x00000323, 0x00001e8a, 0x00000002, 0x00000058, 0x00000307, 0x00001e8c, 0x00000002, 0x00000058, 0x00000308, 0x00001ef2, 0x00000002, 0x00000059, 0x00000300, 0x000000dd, 0x00000002, 0x00000059, 0x00000301, 0x00000176, 0x00000002, 0x00000059, 0x00000302, 0x00001ef8, 0x00000002, 0x00000059, 0x00000303, 0x00000232, 0x00000002, 0x00000059, 0x00000304, 0x00001e8e, 0x00000002, 0x00000059, 0x00000307, 0x00000178, 0x00000002, 0x00000059, 0x00000308, 0x00001ef6, 0x00000002, 0x00000059, 0x00000309, 0x00001ef4, 0x00000002, 0x00000059, 0x00000323, 0x00000179, 0x00000002, 0x0000005a, 0x00000301, 0x00001e90, 0x00000002, 0x0000005a, 0x00000302, 0x0000017b, 0x00000002, 0x0000005a, 0x00000307, 0x0000017d, 0x00000002, 0x0000005a, 0x0000030c, 0x00001e92, 0x00000002, 0x0000005a, 0x00000323, 0x00001e94, 0x00000002, 0x0000005a, 0x00000331, 0x000000e0, 0x00000002, 0x00000061, 0x00000300, 0x000000e1, 0x00000002, 0x00000061, 0x00000301, 0x000000e2, 0x00000002, 0x00000061, 0x00000302, 0x000000e3, 0x00000002, 0x00000061, 0x00000303, 0x00000101, 0x00000002, 0x00000061, 0x00000304, 0x00000103, 0x00000002, 0x00000061, 0x00000306, 0x00000227, 0x00000002, 0x00000061, 0x00000307, 0x000000e4, 0x00000002, 0x00000061, 0x00000308, 0x00001ea3, 0x00000002, 0x00000061, 0x00000309, 0x000000e5, 0x00000002, 0x00000061, 0x0000030a, 0x000001ce, 0x00000002, 0x00000061, 0x0000030c, 0x00000201, 0x00000002, 0x00000061, 0x0000030f, 0x00000203, 0x00000002, 0x00000061, 0x00000311, 0x00001ea1, 0x00000002, 0x00000061, 0x00000323, 0x00001e01, 0x00000002, 0x00000061, 0x00000325, 0x00000105, 0x00000002, 0x00000061, 0x00000328, 0x00001e03, 0x00000002, 0x00000062, 0x00000307, 0x00001e05, 0x00000002, 0x00000062, 0x00000323, 0x00001e07, 0x00000002, 0x00000062, 0x00000331, 0x00000107, 0x00000002, 0x00000063, 0x00000301, 0x00000109, 0x00000002, 0x00000063, 0x00000302, 0x0000010b, 0x00000002, 0x00000063, 0x00000307, 0x0000010d, 0x00000002, 0x00000063, 0x0000030c, 0x000000e7, 0x00000002, 0x00000063, 0x00000327, 0x00001e0b, 0x00000002, 0x00000064, 0x00000307, 0x0000010f, 0x00000002, 0x00000064, 0x0000030c, 0x00001e0d, 0x00000002, 0x00000064, 0x00000323, 0x00001e11, 0x00000002, 0x00000064, 0x00000327, 0x00001e13, 0x00000002, 0x00000064, 0x0000032d, 0x00001e0f, 0x00000002, 0x00000064, 0x00000331, 0x000000e8, 0x00000002, 0x00000065, 0x00000300, 0x000000e9, 0x00000002, 0x00000065, 0x00000301, 0x000000ea, 0x00000002, 0x00000065, 0x00000302, 0x00001ebd, 0x00000002, 0x00000065, 0x00000303, 0x00000113, 0x00000002, 0x00000065, 0x00000304, 0x00000115, 0x00000002, 0x00000065, 0x00000306, 0x00000117, 0x00000002, 0x00000065, 0x00000307, 0x000000eb, 0x00000002, 0x00000065, 0x00000308, 0x00001ebb, 0x00000002, 0x00000065, 0x00000309, 0x0000011b, 0x00000002, 0x00000065, 0x0000030c, 0x00000205, 0x00000002, 0x00000065, 0x0000030f, 0x00000207, 0x00000002, 0x00000065, 0x00000311, 0x00001eb9, 0x00000002, 0x00000065, 0x00000323, 0x00000229, 0x00000002, 0x00000065, 0x00000327, 0x00000119, 0x00000002, 0x00000065, 0x00000328, 0x00001e19, 0x00000002, 0x00000065, 0x0000032d, 0x00001e1b, 0x00000002, 0x00000065, 0x00000330, 0x00001e1f, 0x00000002, 0x00000066, 0x00000307, 0x000001f5, 0x00000002, 0x00000067, 0x00000301, 0x0000011d, 0x00000002, 0x00000067, 0x00000302, 0x00001e21, 0x00000002, 0x00000067, 0x00000304, 0x0000011f, 0x00000002, 0x00000067, 0x00000306, 0x00000121, 0x00000002, 0x00000067, 0x00000307, 0x000001e7, 0x00000002, 0x00000067, 0x0000030c, 0x00000123, 0x00000002, 0x00000067, 0x00000327, 0x00000125, 0x00000002, 0x00000068, 0x00000302, 0x00001e23, 0x00000002, 0x00000068, 0x00000307, 0x00001e27, 0x00000002, 0x00000068, 0x00000308, 0x0000021f, 0x00000002, 0x00000068, 0x0000030c, 0x00001e25, 0x00000002, 0x00000068, 0x00000323, 0x00001e29, 0x00000002, 0x00000068, 0x00000327, 0x00001e2b, 0x00000002, 0x00000068, 0x0000032e, 0x00001e96, 0x00000002, 0x00000068, 0x00000331, 0x000000ec, 0x00000002, 0x00000069, 0x00000300, 0x000000ed, 0x00000002, 0x00000069, 0x00000301, 0x000000ee, 0x00000002, 0x00000069, 0x00000302, 0x00000129, 0x00000002, 0x00000069, 0x00000303, 0x0000012b, 0x00000002, 0x00000069, 0x00000304, 0x0000012d, 0x00000002, 0x00000069, 0x00000306, 0x000000ef, 0x00000002, 0x00000069, 0x00000308, 0x00001ec9, 0x00000002, 0x00000069, 0x00000309, 0x000001d0, 0x00000002, 0x00000069, 0x0000030c, 0x00000209, 0x00000002, 0x00000069, 0x0000030f, 0x0000020b, 0x00000002, 0x00000069, 0x00000311, 0x00001ecb, 0x00000002, 0x00000069, 0x00000323, 0x0000012f, 0x00000002, 0x00000069, 0x00000328, 0x00001e2d, 0x00000002, 0x00000069, 0x00000330, 0x00000135, 0x00000002, 0x0000006a, 0x00000302, 0x000001f0, 0x00000002, 0x0000006a, 0x0000030c, 0x00001e31, 0x00000002, 0x0000006b, 0x00000301, 0x000001e9, 0x00000002, 0x0000006b, 0x0000030c, 0x00001e33, 0x00000002, 0x0000006b, 0x00000323, 0x00000137, 0x00000002, 0x0000006b, 0x00000327, 0x00001e35, 0x00000002, 0x0000006b, 0x00000331, 0x0000013a, 0x00000002, 0x0000006c, 0x00000301, 0x0000013e, 0x00000002, 0x0000006c, 0x0000030c, 0x00001e37, 0x00000002, 0x0000006c, 0x00000323, 0x0000013c, 0x00000002, 0x0000006c, 0x00000327, 0x00001e3d, 0x00000002, 0x0000006c, 0x0000032d, 0x00001e3b, 0x00000002, 0x0000006c, 0x00000331, 0x00001e3f, 0x00000002, 0x0000006d, 0x00000301, 0x00001e41, 0x00000002, 0x0000006d, 0x00000307, 0x00001e43, 0x00000002, 0x0000006d, 0x00000323, 0x000001f9, 0x00000002, 0x0000006e, 0x00000300, 0x00000144, 0x00000002, 0x0000006e, 0x00000301, 0x000000f1, 0x00000002, 0x0000006e, 0x00000303, 0x00001e45, 0x00000002, 0x0000006e, 0x00000307, 0x00000148, 0x00000002, 0x0000006e, 0x0000030c, 0x00001e47, 0x00000002, 0x0000006e, 0x00000323, 0x00000146, 0x00000002, 0x0000006e, 0x00000327, 0x00001e4b, 0x00000002, 0x0000006e, 0x0000032d, 0x00001e49, 0x00000002, 0x0000006e, 0x00000331, 0x000000f2, 0x00000002, 0x0000006f, 0x00000300, 0x000000f3, 0x00000002, 0x0000006f, 0x00000301, 0x000000f4, 0x00000002, 0x0000006f, 0x00000302, 0x000000f5, 0x00000002, 0x0000006f, 0x00000303, 0x0000014d, 0x00000002, 0x0000006f, 0x00000304, 0x0000014f, 0x00000002, 0x0000006f, 0x00000306, 0x0000022f, 0x00000002, 0x0000006f, 0x00000307, 0x000000f6, 0x00000002, 0x0000006f, 0x00000308, 0x00001ecf, 0x00000002, 0x0000006f, 0x00000309, 0x00000151, 0x00000002, 0x0000006f, 0x0000030b, 0x000001d2, 0x00000002, 0x0000006f, 0x0000030c, 0x0000020d, 0x00000002, 0x0000006f, 0x0000030f, 0x0000020f, 0x00000002, 0x0000006f, 0x00000311, 0x000001a1, 0x00000002, 0x0000006f, 0x0000031b, 0x00001ecd, 0x00000002, 0x0000006f, 0x00000323, 0x000001eb, 0x00000002, 0x0000006f, 0x00000328, 0x00001e55, 0x00000002, 0x00000070, 0x00000301, 0x00001e57, 0x00000002, 0x00000070, 0x00000307, 0x00000155, 0x00000002, 0x00000072, 0x00000301, 0x00001e59, 0x00000002, 0x00000072, 0x00000307, 0x00000159, 0x00000002, 0x00000072, 0x0000030c, 0x00000211, 0x00000002, 0x00000072, 0x0000030f, 0x00000213, 0x00000002, 0x00000072, 0x00000311, 0x00001e5b, 0x00000002, 0x00000072, 0x00000323, 0x00000157, 0x00000002, 0x00000072, 0x00000327, 0x00001e5f, 0x00000002, 0x00000072, 0x00000331, 0x0000015b, 0x00000002, 0x00000073, 0x00000301, 0x0000015d, 0x00000002, 0x00000073, 0x00000302, 0x00001e61, 0x00000002, 0x00000073, 0x00000307, 0x00000161, 0x00000002, 0x00000073, 0x0000030c, 0x00001e63, 0x00000002, 0x00000073, 0x00000323, 0x00000219, 0x00000002, 0x00000073, 0x00000326, 0x0000015f, 0x00000002, 0x00000073, 0x00000327, 0x00001e6b, 0x00000002, 0x00000074, 0x00000307, 0x00001e97, 0x00000002, 0x00000074, 0x00000308, 0x00000165, 0x00000002, 0x00000074, 0x0000030c, 0x00001e6d, 0x00000002, 0x00000074, 0x00000323, 0x0000021b, 0x00000002, 0x00000074, 0x00000326, 0x00000163, 0x00000002, 0x00000074, 0x00000327, 0x00001e71, 0x00000002, 0x00000074, 0x0000032d, 0x00001e6f, 0x00000002, 0x00000074, 0x00000331, 0x000000f9, 0x00000002, 0x00000075, 0x00000300, 0x000000fa, 0x00000002, 0x00000075, 0x00000301, 0x000000fb, 0x00000002, 0x00000075, 0x00000302, 0x00000169, 0x00000002, 0x00000075, 0x00000303, 0x0000016b, 0x00000002, 0x00000075, 0x00000304, 0x0000016d, 0x00000002, 0x00000075, 0x00000306, 0x000000fc, 0x00000002, 0x00000075, 0x00000308, 0x00001ee7, 0x00000002, 0x00000075, 0x00000309, 0x0000016f, 0x00000002, 0x00000075, 0x0000030a, 0x00000171, 0x00000002, 0x00000075, 0x0000030b, 0x000001d4, 0x00000002, 0x00000075, 0x0000030c, 0x00000215, 0x00000002, 0x00000075, 0x0000030f, 0x00000217, 0x00000002, 0x00000075, 0x00000311, 0x000001b0, 0x00000002, 0x00000075, 0x0000031b, 0x00001ee5, 0x00000002, 0x00000075, 0x00000323, 0x00001e73, 0x00000002, 0x00000075, 0x00000324, 0x00000173, 0x00000002, 0x00000075, 0x00000328, 0x00001e77, 0x00000002, 0x00000075, 0x0000032d, 0x00001e75, 0x00000002, 0x00000075, 0x00000330, 0x00001e7d, 0x00000002, 0x00000076, 0x00000303, 0x00001e7f, 0x00000002, 0x00000076, 0x00000323, 0x00001e81, 0x00000002, 0x00000077, 0x00000300, 0x00001e83, 0x00000002, 0x00000077, 0x00000301, 0x00000175, 0x00000002, 0x00000077, 0x00000302, 0x00001e87, 0x00000002, 0x00000077, 0x00000307, 0x00001e85, 0x00000002, 0x00000077, 0x00000308, 0x00001e98, 0x00000002, 0x00000077, 0x0000030a, 0x00001e89, 0x00000002, 0x00000077, 0x00000323, 0x00001e8b, 0x00000002, 0x00000078, 0x00000307, 0x00001e8d, 0x00000002, 0x00000078, 0x00000308, 0x00001ef3, 0x00000002, 0x00000079, 0x00000300, 0x000000fd, 0x00000002, 0x00000079, 0x00000301, 0x00000177, 0x00000002, 0x00000079, 0x00000302, 0x00001ef9, 0x00000002, 0x00000079, 0x00000303, 0x00000233, 0x00000002, 0x00000079, 0x00000304, 0x00001e8f, 0x00000002, 0x00000079, 0x00000307, 0x000000ff, 0x00000002, 0x00000079, 0x00000308, 0x00001ef7, 0x00000002, 0x00000079, 0x00000309, 0x00001e99, 0x00000002, 0x00000079, 0x0000030a, 0x00001ef5, 0x00000002, 0x00000079, 0x00000323, 0x0000017a, 0x00000002, 0x0000007a, 0x00000301, 0x00001e91, 0x00000002, 0x0000007a, 0x00000302, 0x0000017c, 0x00000002, 0x0000007a, 0x00000307, 0x0000017e, 0x00000002, 0x0000007a, 0x0000030c, 0x00001e93, 0x00000002, 0x0000007a, 0x00000323, 0x00001e95, 0x00000002, 0x0000007a, 0x00000331, 0x00001fed, 0x00000002, 0x000000a8, 0x00000300, 0x00000385, 0x00000002, 0x000000a8, 0x00000301, 0x00001fc1, 0x00000002, 0x000000a8, 0x00000342, 0x00001ea6, 0x00000002, 0x000000c2, 0x00000300, 0x00001ea4, 0x00000002, 0x000000c2, 0x00000301, 0x00001eaa, 0x00000002, 0x000000c2, 0x00000303, 0x00001ea8, 0x00000002, 0x000000c2, 0x00000309, 0x000001de, 0x00000002, 0x000000c4, 0x00000304, 0x000001fa, 0x00000002, 0x000000c5, 0x00000301, 0x000001fc, 0x00000002, 0x000000c6, 0x00000301, 0x000001e2, 0x00000002, 0x000000c6, 0x00000304, 0x00001e08, 0x00000002, 0x000000c7, 0x00000301, 0x00001ec0, 0x00000002, 0x000000ca, 0x00000300, 0x00001ebe, 0x00000002, 0x000000ca, 0x00000301, 0x00001ec4, 0x00000002, 0x000000ca, 0x00000303, 0x00001ec2, 0x00000002, 0x000000ca, 0x00000309, 0x00001e2e, 0x00000002, 0x000000cf, 0x00000301, 0x00001ed2, 0x00000002, 0x000000d4, 0x00000300, 0x00001ed0, 0x00000002, 0x000000d4, 0x00000301, 0x00001ed6, 0x00000002, 0x000000d4, 0x00000303, 0x00001ed4, 0x00000002, 0x000000d4, 0x00000309, 0x00001e4c, 0x00000002, 0x000000d5, 0x00000301, 0x0000022c, 0x00000002, 0x000000d5, 0x00000304, 0x00001e4e, 0x00000002, 0x000000d5, 0x00000308, 0x0000022a, 0x00000002, 0x000000d6, 0x00000304, 0x000001fe, 0x00000002, 0x000000d8, 0x00000301, 0x000001db, 0x00000002, 0x000000dc, 0x00000300, 0x000001d7, 0x00000002, 0x000000dc, 0x00000301, 0x000001d5, 0x00000002, 0x000000dc, 0x00000304, 0x000001d9, 0x00000002, 0x000000dc, 0x0000030c, 0x00001ea7, 0x00000002, 0x000000e2, 0x00000300, 0x00001ea5, 0x00000002, 0x000000e2, 0x00000301, 0x00001eab, 0x00000002, 0x000000e2, 0x00000303, 0x00001ea9, 0x00000002, 0x000000e2, 0x00000309, 0x000001df, 0x00000002, 0x000000e4, 0x00000304, 0x000001fb, 0x00000002, 0x000000e5, 0x00000301, 0x000001fd, 0x00000002, 0x000000e6, 0x00000301, 0x000001e3, 0x00000002, 0x000000e6, 0x00000304, 0x00001e09, 0x00000002, 0x000000e7, 0x00000301, 0x00001ec1, 0x00000002, 0x000000ea, 0x00000300, 0x00001ebf, 0x00000002, 0x000000ea, 0x00000301, 0x00001ec5, 0x00000002, 0x000000ea, 0x00000303, 0x00001ec3, 0x00000002, 0x000000ea, 0x00000309, 0x00001e2f, 0x00000002, 0x000000ef, 0x00000301, 0x00001ed3, 0x00000002, 0x000000f4, 0x00000300, 0x00001ed1, 0x00000002, 0x000000f4, 0x00000301, 0x00001ed7, 0x00000002, 0x000000f4, 0x00000303, 0x00001ed5, 0x00000002, 0x000000f4, 0x00000309, 0x00001e4d, 0x00000002, 0x000000f5, 0x00000301, 0x0000022d, 0x00000002, 0x000000f5, 0x00000304, 0x00001e4f, 0x00000002, 0x000000f5, 0x00000308, 0x0000022b, 0x00000002, 0x000000f6, 0x00000304, 0x000001ff, 0x00000002, 0x000000f8, 0x00000301, 0x000001dc, 0x00000002, 0x000000fc, 0x00000300, 0x000001d8, 0x00000002, 0x000000fc, 0x00000301, 0x000001d6, 0x00000002, 0x000000fc, 0x00000304, 0x000001da, 0x00000002, 0x000000fc, 0x0000030c, 0x00001eb0, 0x00000002, 0x00000102, 0x00000300, 0x00001eae, 0x00000002, 0x00000102, 0x00000301, 0x00001eb4, 0x00000002, 0x00000102, 0x00000303, 0x00001eb2, 0x00000002, 0x00000102, 0x00000309, 0x00001eb1, 0x00000002, 0x00000103, 0x00000300, 0x00001eaf, 0x00000002, 0x00000103, 0x00000301, 0x00001eb5, 0x00000002, 0x00000103, 0x00000303, 0x00001eb3, 0x00000002, 0x00000103, 0x00000309, 0x00001e14, 0x00000002, 0x00000112, 0x00000300, 0x00001e16, 0x00000002, 0x00000112, 0x00000301, 0x00001e15, 0x00000002, 0x00000113, 0x00000300, 0x00001e17, 0x00000002, 0x00000113, 0x00000301, 0x00001e50, 0x00000002, 0x0000014c, 0x00000300, 0x00001e52, 0x00000002, 0x0000014c, 0x00000301, 0x00001e51, 0x00000002, 0x0000014d, 0x00000300, 0x00001e53, 0x00000002, 0x0000014d, 0x00000301, 0x00001e64, 0x00000002, 0x0000015a, 0x00000307, 0x00001e65, 0x00000002, 0x0000015b, 0x00000307, 0x00001e66, 0x00000002, 0x00000160, 0x00000307, 0x00001e67, 0x00000002, 0x00000161, 0x00000307, 0x00001e78, 0x00000002, 0x00000168, 0x00000301, 0x00001e79, 0x00000002, 0x00000169, 0x00000301, 0x00001e7a, 0x00000002, 0x0000016a, 0x00000308, 0x00001e7b, 0x00000002, 0x0000016b, 0x00000308, 0x00001e9b, 0x00000002, 0x0000017f, 0x00000307, 0x00001edc, 0x00000002, 0x000001a0, 0x00000300, 0x00001eda, 0x00000002, 0x000001a0, 0x00000301, 0x00001ee0, 0x00000002, 0x000001a0, 0x00000303, 0x00001ede, 0x00000002, 0x000001a0, 0x00000309, 0x00001ee2, 0x00000002, 0x000001a0, 0x00000323, 0x00001edd, 0x00000002, 0x000001a1, 0x00000300, 0x00001edb, 0x00000002, 0x000001a1, 0x00000301, 0x00001ee1, 0x00000002, 0x000001a1, 0x00000303, 0x00001edf, 0x00000002, 0x000001a1, 0x00000309, 0x00001ee3, 0x00000002, 0x000001a1, 0x00000323, 0x00001eea, 0x00000002, 0x000001af, 0x00000300, 0x00001ee8, 0x00000002, 0x000001af, 0x00000301, 0x00001eee, 0x00000002, 0x000001af, 0x00000303, 0x00001eec, 0x00000002, 0x000001af, 0x00000309, 0x00001ef0, 0x00000002, 0x000001af, 0x00000323, 0x00001eeb, 0x00000002, 0x000001b0, 0x00000300, 0x00001ee9, 0x00000002, 0x000001b0, 0x00000301, 0x00001eef, 0x00000002, 0x000001b0, 0x00000303, 0x00001eed, 0x00000002, 0x000001b0, 0x00000309, 0x00001ef1, 0x00000002, 0x000001b0, 0x00000323, 0x000001ee, 0x00000002, 0x000001b7, 0x0000030c, 0x000001ec, 0x00000002, 0x000001ea, 0x00000304, 0x000001ed, 0x00000002, 0x000001eb, 0x00000304, 0x000001e0, 0x00000002, 0x00000226, 0x00000304, 0x000001e1, 0x00000002, 0x00000227, 0x00000304, 0x00001e1c, 0x00000002, 0x00000228, 0x00000306, 0x00001e1d, 0x00000002, 0x00000229, 0x00000306, 0x00000230, 0x00000002, 0x0000022e, 0x00000304, 0x00000231, 0x00000002, 0x0000022f, 0x00000304, 0x000001ef, 0x00000002, 0x00000292, 0x0000030c, 0x00000344, 0x00000002, 0x00000308, 0x00000301, 0x00001fba, 0x00000002, 0x00000391, 0x00000300, 0x00000386, 0x00000002, 0x00000391, 0x00000301, 0x00001fb9, 0x00000002, 0x00000391, 0x00000304, 0x00001fb8, 0x00000002, 0x00000391, 0x00000306, 0x00001f08, 0x00000002, 0x00000391, 0x00000313, 0x00001f09, 0x00000002, 0x00000391, 0x00000314, 0x00001fbc, 0x00000002, 0x00000391, 0x00000345, 0x00001fc8, 0x00000002, 0x00000395, 0x00000300, 0x00000388, 0x00000002, 0x00000395, 0x00000301, 0x00001f18, 0x00000002, 0x00000395, 0x00000313, 0x00001f19, 0x00000002, 0x00000395, 0x00000314, 0x00001fca, 0x00000002, 0x00000397, 0x00000300, 0x00000389, 0x00000002, 0x00000397, 0x00000301, 0x00001f28, 0x00000002, 0x00000397, 0x00000313, 0x00001f29, 0x00000002, 0x00000397, 0x00000314, 0x00001fcc, 0x00000002, 0x00000397, 0x00000345, 0x00001fda, 0x00000002, 0x00000399, 0x00000300, 0x0000038a, 0x00000002, 0x00000399, 0x00000301, 0x00001fd9, 0x00000002, 0x00000399, 0x00000304, 0x00001fd8, 0x00000002, 0x00000399, 0x00000306, 0x000003aa, 0x00000002, 0x00000399, 0x00000308, 0x00001f38, 0x00000002, 0x00000399, 0x00000313, 0x00001f39, 0x00000002, 0x00000399, 0x00000314, 0x00001ff8, 0x00000002, 0x0000039f, 0x00000300, 0x0000038c, 0x00000002, 0x0000039f, 0x00000301, 0x00001f48, 0x00000002, 0x0000039f, 0x00000313, 0x00001f49, 0x00000002, 0x0000039f, 0x00000314, 0x00001fec, 0x00000002, 0x000003a1, 0x00000314, 0x00001fea, 0x00000002, 0x000003a5, 0x00000300, 0x0000038e, 0x00000002, 0x000003a5, 0x00000301, 0x00001fe9, 0x00000002, 0x000003a5, 0x00000304, 0x00001fe8, 0x00000002, 0x000003a5, 0x00000306, 0x000003ab, 0x00000002, 0x000003a5, 0x00000308, 0x00001f59, 0x00000002, 0x000003a5, 0x00000314, 0x00001ffa, 0x00000002, 0x000003a9, 0x00000300, 0x0000038f, 0x00000002, 0x000003a9, 0x00000301, 0x00001f68, 0x00000002, 0x000003a9, 0x00000313, 0x00001f69, 0x00000002, 0x000003a9, 0x00000314, 0x00001ffc, 0x00000002, 0x000003a9, 0x00000345, 0x00001fb4, 0x00000002, 0x000003ac, 0x00000345, 0x00001fc4, 0x00000002, 0x000003ae, 0x00000345, 0x00001f70, 0x00000002, 0x000003b1, 0x00000300, 0x000003ac, 0x00000002, 0x000003b1, 0x00000301, 0x00001fb1, 0x00000002, 0x000003b1, 0x00000304, 0x00001fb0, 0x00000002, 0x000003b1, 0x00000306, 0x00001f00, 0x00000002, 0x000003b1, 0x00000313, 0x00001f01, 0x00000002, 0x000003b1, 0x00000314, 0x00001fb6, 0x00000002, 0x000003b1, 0x00000342, 0x00001fb3, 0x00000002, 0x000003b1, 0x00000345, 0x00001f72, 0x00000002, 0x000003b5, 0x00000300, 0x000003ad, 0x00000002, 0x000003b5, 0x00000301, 0x00001f10, 0x00000002, 0x000003b5, 0x00000313, 0x00001f11, 0x00000002, 0x000003b5, 0x00000314, 0x00001f74, 0x00000002, 0x000003b7, 0x00000300, 0x000003ae, 0x00000002, 0x000003b7, 0x00000301, 0x00001f20, 0x00000002, 0x000003b7, 0x00000313, 0x00001f21, 0x00000002, 0x000003b7, 0x00000314, 0x00001fc6, 0x00000002, 0x000003b7, 0x00000342, 0x00001fc3, 0x00000002, 0x000003b7, 0x00000345, 0x00001f76, 0x00000002, 0x000003b9, 0x00000300, 0x000003af, 0x00000002, 0x000003b9, 0x00000301, 0x00001fd1, 0x00000002, 0x000003b9, 0x00000304, 0x00001fd0, 0x00000002, 0x000003b9, 0x00000306, 0x000003ca, 0x00000002, 0x000003b9, 0x00000308, 0x00001f30, 0x00000002, 0x000003b9, 0x00000313, 0x00001f31, 0x00000002, 0x000003b9, 0x00000314, 0x00001fd6, 0x00000002, 0x000003b9, 0x00000342, 0x00001f78, 0x00000002, 0x000003bf, 0x00000300, 0x000003cc, 0x00000002, 0x000003bf, 0x00000301, 0x00001f40, 0x00000002, 0x000003bf, 0x00000313, 0x00001f41, 0x00000002, 0x000003bf, 0x00000314, 0x00001fe4, 0x00000002, 0x000003c1, 0x00000313, 0x00001fe5, 0x00000002, 0x000003c1, 0x00000314, 0x00001f7a, 0x00000002, 0x000003c5, 0x00000300, 0x000003cd, 0x00000002, 0x000003c5, 0x00000301, 0x00001fe1, 0x00000002, 0x000003c5, 0x00000304, 0x00001fe0, 0x00000002, 0x000003c5, 0x00000306, 0x000003cb, 0x00000002, 0x000003c5, 0x00000308, 0x00001f50, 0x00000002, 0x000003c5, 0x00000313, 0x00001f51, 0x00000002, 0x000003c5, 0x00000314, 0x00001fe6, 0x00000002, 0x000003c5, 0x00000342, 0x00001f7c, 0x00000002, 0x000003c9, 0x00000300, 0x000003ce, 0x00000002, 0x000003c9, 0x00000301, 0x00001f60, 0x00000002, 0x000003c9, 0x00000313, 0x00001f61, 0x00000002, 0x000003c9, 0x00000314, 0x00001ff6, 0x00000002, 0x000003c9, 0x00000342, 0x00001ff3, 0x00000002, 0x000003c9, 0x00000345, 0x00001fd2, 0x00000002, 0x000003ca, 0x00000300, 0x00000390, 0x00000002, 0x000003ca, 0x00000301, 0x00001fd7, 0x00000002, 0x000003ca, 0x00000342, 0x00001fe2, 0x00000002, 0x000003cb, 0x00000300, 0x000003b0, 0x00000002, 0x000003cb, 0x00000301, 0x00001fe7, 0x00000002, 0x000003cb, 0x00000342, 0x00001ff4, 0x00000002, 0x000003ce, 0x00000345, 0x000003d3, 0x00000002, 0x000003d2, 0x00000301, 0x000003d4, 0x00000002, 0x000003d2, 0x00000308, 0x00000407, 0x00000002, 0x00000406, 0x00000308, 0x000004d0, 0x00000002, 0x00000410, 0x00000306, 0x000004d2, 0x00000002, 0x00000410, 0x00000308, 0x00000403, 0x00000002, 0x00000413, 0x00000301, 0x00000400, 0x00000002, 0x00000415, 0x00000300, 0x000004d6, 0x00000002, 0x00000415, 0x00000306, 0x00000401, 0x00000002, 0x00000415, 0x00000308, 0x000004c1, 0x00000002, 0x00000416, 0x00000306, 0x000004dc, 0x00000002, 0x00000416, 0x00000308, 0x000004de, 0x00000002, 0x00000417, 0x00000308, 0x0000040d, 0x00000002, 0x00000418, 0x00000300, 0x000004e2, 0x00000002, 0x00000418, 0x00000304, 0x00000419, 0x00000002, 0x00000418, 0x00000306, 0x000004e4, 0x00000002, 0x00000418, 0x00000308, 0x0000040c, 0x00000002, 0x0000041a, 0x00000301, 0x000004e6, 0x00000002, 0x0000041e, 0x00000308, 0x000004ee, 0x00000002, 0x00000423, 0x00000304, 0x0000040e, 0x00000002, 0x00000423, 0x00000306, 0x000004f0, 0x00000002, 0x00000423, 0x00000308, 0x000004f2, 0x00000002, 0x00000423, 0x0000030b, 0x000004f4, 0x00000002, 0x00000427, 0x00000308, 0x000004f8, 0x00000002, 0x0000042b, 0x00000308, 0x000004ec, 0x00000002, 0x0000042d, 0x00000308, 0x000004d1, 0x00000002, 0x00000430, 0x00000306, 0x000004d3, 0x00000002, 0x00000430, 0x00000308, 0x00000453, 0x00000002, 0x00000433, 0x00000301, 0x00000450, 0x00000002, 0x00000435, 0x00000300, 0x000004d7, 0x00000002, 0x00000435, 0x00000306, 0x00000451, 0x00000002, 0x00000435, 0x00000308, 0x000004c2, 0x00000002, 0x00000436, 0x00000306, 0x000004dd, 0x00000002, 0x00000436, 0x00000308, 0x000004df, 0x00000002, 0x00000437, 0x00000308, 0x0000045d, 0x00000002, 0x00000438, 0x00000300, 0x000004e3, 0x00000002, 0x00000438, 0x00000304, 0x00000439, 0x00000002, 0x00000438, 0x00000306, 0x000004e5, 0x00000002, 0x00000438, 0x00000308, 0x0000045c, 0x00000002, 0x0000043a, 0x00000301, 0x000004e7, 0x00000002, 0x0000043e, 0x00000308, 0x000004ef, 0x00000002, 0x00000443, 0x00000304, 0x0000045e, 0x00000002, 0x00000443, 0x00000306, 0x000004f1, 0x00000002, 0x00000443, 0x00000308, 0x000004f3, 0x00000002, 0x00000443, 0x0000030b, 0x000004f5, 0x00000002, 0x00000447, 0x00000308, 0x000004f9, 0x00000002, 0x0000044b, 0x00000308, 0x000004ed, 0x00000002, 0x0000044d, 0x00000308, 0x00000457, 0x00000002, 0x00000456, 0x00000308, 0x00000476, 0x00000002, 0x00000474, 0x0000030f, 0x00000477, 0x00000002, 0x00000475, 0x0000030f, 0x000004da, 0x00000002, 0x000004d8, 0x00000308, 0x000004db, 0x00000002, 0x000004d9, 0x00000308, 0x000004ea, 0x00000002, 0x000004e8, 0x00000308, 0x000004eb, 0x00000002, 0x000004e9, 0x00000308, 0x00000622, 0x00000002, 0x00000627, 0x00000653, 0x00000623, 0x00000002, 0x00000627, 0x00000654, 0x00000625, 0x00000002, 0x00000627, 0x00000655, 0x00000624, 0x00000002, 0x00000648, 0x00000654, 0x00000626, 0x00000002, 0x0000064a, 0x00000654, 0x000006c2, 0x00000002, 0x000006c1, 0x00000654, 0x000006d3, 0x00000002, 0x000006d2, 0x00000654, 0x000006c0, 0x00000002, 0x000006d5, 0x00000654, 0x00000929, 0x00000002, 0x00000928, 0x0000093c, 0x00000931, 0x00000002, 0x00000930, 0x0000093c, 0x00000934, 0x00000002, 0x00000933, 0x0000093c, 0x000009cb, 0x00000002, 0x000009c7, 0x000009be, 0x000009cc, 0x00000002, 0x000009c7, 0x000009d7, 0x00000b4b, 0x00000002, 0x00000b47, 0x00000b3e, 0x00000b48, 0x00000002, 0x00000b47, 0x00000b56, 0x00000b4c, 0x00000002, 0x00000b47, 0x00000b57, 0x00000b94, 0x00000002, 0x00000b92, 0x00000bd7, 0x00000bca, 0x00000002, 0x00000bc6, 0x00000bbe, 0x00000bcc, 0x00000002, 0x00000bc6, 0x00000bd7, 0x00000bcb, 0x00000002, 0x00000bc7, 0x00000bbe, 0x00000c48, 0x00000002, 0x00000c46, 0x00000c56, 0x00000cc0, 0x00000002, 0x00000cbf, 0x00000cd5, 0x00000cca, 0x00000002, 0x00000cc6, 0x00000cc2, 0x00000cc7, 0x00000002, 0x00000cc6, 0x00000cd5, 0x00000cc8, 0x00000002, 0x00000cc6, 0x00000cd6, 0x00000ccb, 0x00000002, 0x00000cca, 0x00000cd5, 0x00000d4a, 0x00000002, 0x00000d46, 0x00000d3e, 0x00000d4c, 0x00000002, 0x00000d46, 0x00000d57, 0x00000d4b, 0x00000002, 0x00000d47, 0x00000d3e, 0x00000dda, 0x00000002, 0x00000dd9, 0x00000dca, 0x00000ddc, 0x00000002, 0x00000dd9, 0x00000dcf, 0x00000dde, 0x00000002, 0x00000dd9, 0x00000ddf, 0x00000ddd, 0x00000002, 0x00000ddc, 0x00000dca, 0x00000f73, 0x00000002, 0x00000f71, 0x00000f72, 0x00000f75, 0x00000002, 0x00000f71, 0x00000f74, 0x00000f81, 0x00000002, 0x00000f71, 0x00000f80, 0x00001026, 0x00000002, 0x00001025, 0x0000102e, 0x00001e38, 0x00000002, 0x00001e36, 0x00000304, 0x00001e39, 0x00000002, 0x00001e37, 0x00000304, 0x00001e5c, 0x00000002, 0x00001e5a, 0x00000304, 0x00001e5d, 0x00000002, 0x00001e5b, 0x00000304, 0x00001e68, 0x00000002, 0x00001e62, 0x00000307, 0x00001e69, 0x00000002, 0x00001e63, 0x00000307, 0x00001eac, 0x00000002, 0x00001ea0, 0x00000302, 0x00001eb6, 0x00000002, 0x00001ea0, 0x00000306, 0x00001ead, 0x00000002, 0x00001ea1, 0x00000302, 0x00001eb7, 0x00000002, 0x00001ea1, 0x00000306, 0x00001ec6, 0x00000002, 0x00001eb8, 0x00000302, 0x00001ec7, 0x00000002, 0x00001eb9, 0x00000302, 0x00001ed8, 0x00000002, 0x00001ecc, 0x00000302, 0x00001ed9, 0x00000002, 0x00001ecd, 0x00000302, 0x00001f02, 0x00000002, 0x00001f00, 0x00000300, 0x00001f04, 0x00000002, 0x00001f00, 0x00000301, 0x00001f06, 0x00000002, 0x00001f00, 0x00000342, 0x00001f80, 0x00000002, 0x00001f00, 0x00000345, 0x00001f03, 0x00000002, 0x00001f01, 0x00000300, 0x00001f05, 0x00000002, 0x00001f01, 0x00000301, 0x00001f07, 0x00000002, 0x00001f01, 0x00000342, 0x00001f81, 0x00000002, 0x00001f01, 0x00000345, 0x00001f82, 0x00000002, 0x00001f02, 0x00000345, 0x00001f83, 0x00000002, 0x00001f03, 0x00000345, 0x00001f84, 0x00000002, 0x00001f04, 0x00000345, 0x00001f85, 0x00000002, 0x00001f05, 0x00000345, 0x00001f86, 0x00000002, 0x00001f06, 0x00000345, 0x00001f87, 0x00000002, 0x00001f07, 0x00000345, 0x00001f0a, 0x00000002, 0x00001f08, 0x00000300, 0x00001f0c, 0x00000002, 0x00001f08, 0x00000301, 0x00001f0e, 0x00000002, 0x00001f08, 0x00000342, 0x00001f88, 0x00000002, 0x00001f08, 0x00000345, 0x00001f0b, 0x00000002, 0x00001f09, 0x00000300, 0x00001f0d, 0x00000002, 0x00001f09, 0x00000301, 0x00001f0f, 0x00000002, 0x00001f09, 0x00000342, 0x00001f89, 0x00000002, 0x00001f09, 0x00000345, 0x00001f8a, 0x00000002, 0x00001f0a, 0x00000345, 0x00001f8b, 0x00000002, 0x00001f0b, 0x00000345, 0x00001f8c, 0x00000002, 0x00001f0c, 0x00000345, 0x00001f8d, 0x00000002, 0x00001f0d, 0x00000345, 0x00001f8e, 0x00000002, 0x00001f0e, 0x00000345, 0x00001f8f, 0x00000002, 0x00001f0f, 0x00000345, 0x00001f12, 0x00000002, 0x00001f10, 0x00000300, 0x00001f14, 0x00000002, 0x00001f10, 0x00000301, 0x00001f13, 0x00000002, 0x00001f11, 0x00000300, 0x00001f15, 0x00000002, 0x00001f11, 0x00000301, 0x00001f1a, 0x00000002, 0x00001f18, 0x00000300, 0x00001f1c, 0x00000002, 0x00001f18, 0x00000301, 0x00001f1b, 0x00000002, 0x00001f19, 0x00000300, 0x00001f1d, 0x00000002, 0x00001f19, 0x00000301, 0x00001f22, 0x00000002, 0x00001f20, 0x00000300, 0x00001f24, 0x00000002, 0x00001f20, 0x00000301, 0x00001f26, 0x00000002, 0x00001f20, 0x00000342, 0x00001f90, 0x00000002, 0x00001f20, 0x00000345, 0x00001f23, 0x00000002, 0x00001f21, 0x00000300, 0x00001f25, 0x00000002, 0x00001f21, 0x00000301, 0x00001f27, 0x00000002, 0x00001f21, 0x00000342, 0x00001f91, 0x00000002, 0x00001f21, 0x00000345, 0x00001f92, 0x00000002, 0x00001f22, 0x00000345, 0x00001f93, 0x00000002, 0x00001f23, 0x00000345, 0x00001f94, 0x00000002, 0x00001f24, 0x00000345, 0x00001f95, 0x00000002, 0x00001f25, 0x00000345, 0x00001f96, 0x00000002, 0x00001f26, 0x00000345, 0x00001f97, 0x00000002, 0x00001f27, 0x00000345, 0x00001f2a, 0x00000002, 0x00001f28, 0x00000300, 0x00001f2c, 0x00000002, 0x00001f28, 0x00000301, 0x00001f2e, 0x00000002, 0x00001f28, 0x00000342, 0x00001f98, 0x00000002, 0x00001f28, 0x00000345, 0x00001f2b, 0x00000002, 0x00001f29, 0x00000300, 0x00001f2d, 0x00000002, 0x00001f29, 0x00000301, 0x00001f2f, 0x00000002, 0x00001f29, 0x00000342, 0x00001f99, 0x00000002, 0x00001f29, 0x00000345, 0x00001f9a, 0x00000002, 0x00001f2a, 0x00000345, 0x00001f9b, 0x00000002, 0x00001f2b, 0x00000345, 0x00001f9c, 0x00000002, 0x00001f2c, 0x00000345, 0x00001f9d, 0x00000002, 0x00001f2d, 0x00000345, 0x00001f9e, 0x00000002, 0x00001f2e, 0x00000345, 0x00001f9f, 0x00000002, 0x00001f2f, 0x00000345, 0x00001f32, 0x00000002, 0x00001f30, 0x00000300, 0x00001f34, 0x00000002, 0x00001f30, 0x00000301, 0x00001f36, 0x00000002, 0x00001f30, 0x00000342, 0x00001f33, 0x00000002, 0x00001f31, 0x00000300, 0x00001f35, 0x00000002, 0x00001f31, 0x00000301, 0x00001f37, 0x00000002, 0x00001f31, 0x00000342, 0x00001f3a, 0x00000002, 0x00001f38, 0x00000300, 0x00001f3c, 0x00000002, 0x00001f38, 0x00000301, 0x00001f3e, 0x00000002, 0x00001f38, 0x00000342, 0x00001f3b, 0x00000002, 0x00001f39, 0x00000300, 0x00001f3d, 0x00000002, 0x00001f39, 0x00000301, 0x00001f3f, 0x00000002, 0x00001f39, 0x00000342, 0x00001f42, 0x00000002, 0x00001f40, 0x00000300, 0x00001f44, 0x00000002, 0x00001f40, 0x00000301, 0x00001f43, 0x00000002, 0x00001f41, 0x00000300, 0x00001f45, 0x00000002, 0x00001f41, 0x00000301, 0x00001f4a, 0x00000002, 0x00001f48, 0x00000300, 0x00001f4c, 0x00000002, 0x00001f48, 0x00000301, 0x00001f4b, 0x00000002, 0x00001f49, 0x00000300, 0x00001f4d, 0x00000002, 0x00001f49, 0x00000301, 0x00001f52, 0x00000002, 0x00001f50, 0x00000300, 0x00001f54, 0x00000002, 0x00001f50, 0x00000301, 0x00001f56, 0x00000002, 0x00001f50, 0x00000342, 0x00001f53, 0x00000002, 0x00001f51, 0x00000300, 0x00001f55, 0x00000002, 0x00001f51, 0x00000301, 0x00001f57, 0x00000002, 0x00001f51, 0x00000342, 0x00001f5b, 0x00000002, 0x00001f59, 0x00000300, 0x00001f5d, 0x00000002, 0x00001f59, 0x00000301, 0x00001f5f, 0x00000002, 0x00001f59, 0x00000342, 0x00001f62, 0x00000002, 0x00001f60, 0x00000300, 0x00001f64, 0x00000002, 0x00001f60, 0x00000301, 0x00001f66, 0x00000002, 0x00001f60, 0x00000342, 0x00001fa0, 0x00000002, 0x00001f60, 0x00000345, 0x00001f63, 0x00000002, 0x00001f61, 0x00000300, 0x00001f65, 0x00000002, 0x00001f61, 0x00000301, 0x00001f67, 0x00000002, 0x00001f61, 0x00000342, 0x00001fa1, 0x00000002, 0x00001f61, 0x00000345, 0x00001fa2, 0x00000002, 0x00001f62, 0x00000345, 0x00001fa3, 0x00000002, 0x00001f63, 0x00000345, 0x00001fa4, 0x00000002, 0x00001f64, 0x00000345, 0x00001fa5, 0x00000002, 0x00001f65, 0x00000345, 0x00001fa6, 0x00000002, 0x00001f66, 0x00000345, 0x00001fa7, 0x00000002, 0x00001f67, 0x00000345, 0x00001f6a, 0x00000002, 0x00001f68, 0x00000300, 0x00001f6c, 0x00000002, 0x00001f68, 0x00000301, 0x00001f6e, 0x00000002, 0x00001f68, 0x00000342, 0x00001fa8, 0x00000002, 0x00001f68, 0x00000345, 0x00001f6b, 0x00000002, 0x00001f69, 0x00000300, 0x00001f6d, 0x00000002, 0x00001f69, 0x00000301, 0x00001f6f, 0x00000002, 0x00001f69, 0x00000342, 0x00001fa9, 0x00000002, 0x00001f69, 0x00000345, 0x00001faa, 0x00000002, 0x00001f6a, 0x00000345, 0x00001fab, 0x00000002, 0x00001f6b, 0x00000345, 0x00001fac, 0x00000002, 0x00001f6c, 0x00000345, 0x00001fad, 0x00000002, 0x00001f6d, 0x00000345, 0x00001fae, 0x00000002, 0x00001f6e, 0x00000345, 0x00001faf, 0x00000002, 0x00001f6f, 0x00000345, 0x00001fb2, 0x00000002, 0x00001f70, 0x00000345, 0x00001fc2, 0x00000002, 0x00001f74, 0x00000345, 0x00001ff2, 0x00000002, 0x00001f7c, 0x00000345, 0x00001fb7, 0x00000002, 0x00001fb6, 0x00000345, 0x00001fcd, 0x00000002, 0x00001fbf, 0x00000300, 0x00001fce, 0x00000002, 0x00001fbf, 0x00000301, 0x00001fcf, 0x00000002, 0x00001fbf, 0x00000342, 0x00001fc7, 0x00000002, 0x00001fc6, 0x00000345, 0x00001ff7, 0x00000002, 0x00001ff6, 0x00000345, 0x00001fdd, 0x00000002, 0x00001ffe, 0x00000300, 0x00001fde, 0x00000002, 0x00001ffe, 0x00000301, 0x00001fdf, 0x00000002, 0x00001ffe, 0x00000342, 0x0000219a, 0x00000002, 0x00002190, 0x00000338, 0x0000219b, 0x00000002, 0x00002192, 0x00000338, 0x000021ae, 0x00000002, 0x00002194, 0x00000338, 0x000021cd, 0x00000002, 0x000021d0, 0x00000338, 0x000021cf, 0x00000002, 0x000021d2, 0x00000338, 0x000021ce, 0x00000002, 0x000021d4, 0x00000338, 0x00002204, 0x00000002, 0x00002203, 0x00000338, 0x00002209, 0x00000002, 0x00002208, 0x00000338, 0x0000220c, 0x00000002, 0x0000220b, 0x00000338, 0x00002224, 0x00000002, 0x00002223, 0x00000338, 0x00002226, 0x00000002, 0x00002225, 0x00000338, 0x00002241, 0x00000002, 0x0000223c, 0x00000338, 0x00002244, 0x00000002, 0x00002243, 0x00000338, 0x00002247, 0x00000002, 0x00002245, 0x00000338, 0x00002249, 0x00000002, 0x00002248, 0x00000338, 0x0000226d, 0x00000002, 0x0000224d, 0x00000338, 0x00002262, 0x00000002, 0x00002261, 0x00000338, 0x00002270, 0x00000002, 0x00002264, 0x00000338, 0x00002271, 0x00000002, 0x00002265, 0x00000338, 0x00002274, 0x00000002, 0x00002272, 0x00000338, 0x00002275, 0x00000002, 0x00002273, 0x00000338, 0x00002278, 0x00000002, 0x00002276, 0x00000338, 0x00002279, 0x00000002, 0x00002277, 0x00000338, 0x00002280, 0x00000002, 0x0000227a, 0x00000338, 0x00002281, 0x00000002, 0x0000227b, 0x00000338, 0x000022e0, 0x00000002, 0x0000227c, 0x00000338, 0x000022e1, 0x00000002, 0x0000227d, 0x00000338, 0x00002284, 0x00000002, 0x00002282, 0x00000338, 0x00002285, 0x00000002, 0x00002283, 0x00000338, 0x00002288, 0x00000002, 0x00002286, 0x00000338, 0x00002289, 0x00000002, 0x00002287, 0x00000338, 0x000022e2, 0x00000002, 0x00002291, 0x00000338, 0x000022e3, 0x00000002, 0x00002292, 0x00000338, 0x000022ac, 0x00000002, 0x000022a2, 0x00000338, 0x000022ad, 0x00000002, 0x000022a8, 0x00000338, 0x000022ae, 0x00000002, 0x000022a9, 0x00000338, 0x000022af, 0x00000002, 0x000022ab, 0x00000338, 0x000022ea, 0x00000002, 0x000022b2, 0x00000338, 0x000022eb, 0x00000002, 0x000022b3, 0x00000338, 0x000022ec, 0x00000002, 0x000022b4, 0x00000338, 0x000022ed, 0x00000002, 0x000022b5, 0x00000338, 0x00003094, 0x00000002, 0x00003046, 0x00003099, 0x0000304c, 0x00000002, 0x0000304b, 0x00003099, 0x0000304e, 0x00000002, 0x0000304d, 0x00003099, 0x00003050, 0x00000002, 0x0000304f, 0x00003099, 0x00003052, 0x00000002, 0x00003051, 0x00003099, 0x00003054, 0x00000002, 0x00003053, 0x00003099, 0x00003056, 0x00000002, 0x00003055, 0x00003099, 0x00003058, 0x00000002, 0x00003057, 0x00003099, 0x0000305a, 0x00000002, 0x00003059, 0x00003099, 0x0000305c, 0x00000002, 0x0000305b, 0x00003099, 0x0000305e, 0x00000002, 0x0000305d, 0x00003099, 0x00003060, 0x00000002, 0x0000305f, 0x00003099, 0x00003062, 0x00000002, 0x00003061, 0x00003099, 0x00003065, 0x00000002, 0x00003064, 0x00003099, 0x00003067, 0x00000002, 0x00003066, 0x00003099, 0x00003069, 0x00000002, 0x00003068, 0x00003099, 0x00003070, 0x00000002, 0x0000306f, 0x00003099, 0x00003071, 0x00000002, 0x0000306f, 0x0000309a, 0x00003073, 0x00000002, 0x00003072, 0x00003099, 0x00003074, 0x00000002, 0x00003072, 0x0000309a, 0x00003076, 0x00000002, 0x00003075, 0x00003099, 0x00003077, 0x00000002, 0x00003075, 0x0000309a, 0x00003079, 0x00000002, 0x00003078, 0x00003099, 0x0000307a, 0x00000002, 0x00003078, 0x0000309a, 0x0000307c, 0x00000002, 0x0000307b, 0x00003099, 0x0000307d, 0x00000002, 0x0000307b, 0x0000309a, 0x0000309e, 0x00000002, 0x0000309d, 0x00003099, 0x000030f4, 0x00000002, 0x000030a6, 0x00003099, 0x000030ac, 0x00000002, 0x000030ab, 0x00003099, 0x000030ae, 0x00000002, 0x000030ad, 0x00003099, 0x000030b0, 0x00000002, 0x000030af, 0x00003099, 0x000030b2, 0x00000002, 0x000030b1, 0x00003099, 0x000030b4, 0x00000002, 0x000030b3, 0x00003099, 0x000030b6, 0x00000002, 0x000030b5, 0x00003099, 0x000030b8, 0x00000002, 0x000030b7, 0x00003099, 0x000030ba, 0x00000002, 0x000030b9, 0x00003099, 0x000030bc, 0x00000002, 0x000030bb, 0x00003099, 0x000030be, 0x00000002, 0x000030bd, 0x00003099, 0x000030c0, 0x00000002, 0x000030bf, 0x00003099, 0x000030c2, 0x00000002, 0x000030c1, 0x00003099, 0x000030c5, 0x00000002, 0x000030c4, 0x00003099, 0x000030c7, 0x00000002, 0x000030c6, 0x00003099, 0x000030c9, 0x00000002, 0x000030c8, 0x00003099, 0x000030d0, 0x00000002, 0x000030cf, 0x00003099, 0x000030d1, 0x00000002, 0x000030cf, 0x0000309a, 0x000030d3, 0x00000002, 0x000030d2, 0x00003099, 0x000030d4, 0x00000002, 0x000030d2, 0x0000309a, 0x000030d6, 0x00000002, 0x000030d5, 0x00003099, 0x000030d7, 0x00000002, 0x000030d5, 0x0000309a, 0x000030d9, 0x00000002, 0x000030d8, 0x00003099, 0x000030da, 0x00000002, 0x000030d8, 0x0000309a, 0x000030dc, 0x00000002, 0x000030db, 0x00003099, 0x000030dd, 0x00000002, 0x000030db, 0x0000309a, 0x000030f7, 0x00000002, 0x000030ef, 0x00003099, 0x000030f8, 0x00000002, 0x000030f0, 0x00003099, 0x000030f9, 0x00000002, 0x000030f1, 0x00003099, 0x000030fa, 0x00000002, 0x000030f2, 0x00003099, 0x000030fe, 0x00000002, 0x000030fd, 0x00003099 }; static const ac_uint4 _ucdcmp_size = 3848; static const ac_uint4 _ucdcmp_nodes[] = { 0x000000c0, 0x00000000, 0x000000c1, 0x00000002, 0x000000c2, 0x00000004, 0x000000c3, 0x00000006, 0x000000c4, 0x00000008, 0x000000c5, 0x0000000a, 0x000000c7, 0x0000000c, 0x000000c8, 0x0000000e, 0x000000c9, 0x00000010, 0x000000ca, 0x00000012, 0x000000cb, 0x00000014, 0x000000cc, 0x00000016, 0x000000cd, 0x00000018, 0x000000ce, 0x0000001a, 0x000000cf, 0x0000001c, 0x000000d1, 0x0000001e, 0x000000d2, 0x00000020, 0x000000d3, 0x00000022, 0x000000d4, 0x00000024, 0x000000d5, 0x00000026, 0x000000d6, 0x00000028, 0x000000d9, 0x0000002a, 0x000000da, 0x0000002c, 0x000000db, 0x0000002e, 0x000000dc, 0x00000030, 0x000000dd, 0x00000032, 0x000000e0, 0x00000034, 0x000000e1, 0x00000036, 0x000000e2, 0x00000038, 0x000000e3, 0x0000003a, 0x000000e4, 0x0000003c, 0x000000e5, 0x0000003e, 0x000000e7, 0x00000040, 0x000000e8, 0x00000042, 0x000000e9, 0x00000044, 0x000000ea, 0x00000046, 0x000000eb, 0x00000048, 0x000000ec, 0x0000004a, 0x000000ed, 0x0000004c, 0x000000ee, 0x0000004e, 0x000000ef, 0x00000050, 0x000000f1, 0x00000052, 0x000000f2, 0x00000054, 0x000000f3, 0x00000056, 0x000000f4, 0x00000058, 0x000000f5, 0x0000005a, 0x000000f6, 0x0000005c, 0x000000f9, 0x0000005e, 0x000000fa, 0x00000060, 0x000000fb, 0x00000062, 0x000000fc, 0x00000064, 0x000000fd, 0x00000066, 0x000000ff, 0x00000068, 0x00000100, 0x0000006a, 0x00000101, 0x0000006c, 0x00000102, 0x0000006e, 0x00000103, 0x00000070, 0x00000104, 0x00000072, 0x00000105, 0x00000074, 0x00000106, 0x00000076, 0x00000107, 0x00000078, 0x00000108, 0x0000007a, 0x00000109, 0x0000007c, 0x0000010a, 0x0000007e, 0x0000010b, 0x00000080, 0x0000010c, 0x00000082, 0x0000010d, 0x00000084, 0x0000010e, 0x00000086, 0x0000010f, 0x00000088, 0x00000112, 0x0000008a, 0x00000113, 0x0000008c, 0x00000114, 0x0000008e, 0x00000115, 0x00000090, 0x00000116, 0x00000092, 0x00000117, 0x00000094, 0x00000118, 0x00000096, 0x00000119, 0x00000098, 0x0000011a, 0x0000009a, 0x0000011b, 0x0000009c, 0x0000011c, 0x0000009e, 0x0000011d, 0x000000a0, 0x0000011e, 0x000000a2, 0x0000011f, 0x000000a4, 0x00000120, 0x000000a6, 0x00000121, 0x000000a8, 0x00000122, 0x000000aa, 0x00000123, 0x000000ac, 0x00000124, 0x000000ae, 0x00000125, 0x000000b0, 0x00000128, 0x000000b2, 0x00000129, 0x000000b4, 0x0000012a, 0x000000b6, 0x0000012b, 0x000000b8, 0x0000012c, 0x000000ba, 0x0000012d, 0x000000bc, 0x0000012e, 0x000000be, 0x0000012f, 0x000000c0, 0x00000130, 0x000000c2, 0x00000134, 0x000000c4, 0x00000135, 0x000000c6, 0x00000136, 0x000000c8, 0x00000137, 0x000000ca, 0x00000139, 0x000000cc, 0x0000013a, 0x000000ce, 0x0000013b, 0x000000d0, 0x0000013c, 0x000000d2, 0x0000013d, 0x000000d4, 0x0000013e, 0x000000d6, 0x00000143, 0x000000d8, 0x00000144, 0x000000da, 0x00000145, 0x000000dc, 0x00000146, 0x000000de, 0x00000147, 0x000000e0, 0x00000148, 0x000000e2, 0x0000014c, 0x000000e4, 0x0000014d, 0x000000e6, 0x0000014e, 0x000000e8, 0x0000014f, 0x000000ea, 0x00000150, 0x000000ec, 0x00000151, 0x000000ee, 0x00000154, 0x000000f0, 0x00000155, 0x000000f2, 0x00000156, 0x000000f4, 0x00000157, 0x000000f6, 0x00000158, 0x000000f8, 0x00000159, 0x000000fa, 0x0000015a, 0x000000fc, 0x0000015b, 0x000000fe, 0x0000015c, 0x00000100, 0x0000015d, 0x00000102, 0x0000015e, 0x00000104, 0x0000015f, 0x00000106, 0x00000160, 0x00000108, 0x00000161, 0x0000010a, 0x00000162, 0x0000010c, 0x00000163, 0x0000010e, 0x00000164, 0x00000110, 0x00000165, 0x00000112, 0x00000168, 0x00000114, 0x00000169, 0x00000116, 0x0000016a, 0x00000118, 0x0000016b, 0x0000011a, 0x0000016c, 0x0000011c, 0x0000016d, 0x0000011e, 0x0000016e, 0x00000120, 0x0000016f, 0x00000122, 0x00000170, 0x00000124, 0x00000171, 0x00000126, 0x00000172, 0x00000128, 0x00000173, 0x0000012a, 0x00000174, 0x0000012c, 0x00000175, 0x0000012e, 0x00000176, 0x00000130, 0x00000177, 0x00000132, 0x00000178, 0x00000134, 0x00000179, 0x00000136, 0x0000017a, 0x00000138, 0x0000017b, 0x0000013a, 0x0000017c, 0x0000013c, 0x0000017d, 0x0000013e, 0x0000017e, 0x00000140, 0x000001a0, 0x00000142, 0x000001a1, 0x00000144, 0x000001af, 0x00000146, 0x000001b0, 0x00000148, 0x000001cd, 0x0000014a, 0x000001ce, 0x0000014c, 0x000001cf, 0x0000014e, 0x000001d0, 0x00000150, 0x000001d1, 0x00000152, 0x000001d2, 0x00000154, 0x000001d3, 0x00000156, 0x000001d4, 0x00000158, 0x000001d5, 0x0000015a, 0x000001d6, 0x0000015d, 0x000001d7, 0x00000160, 0x000001d8, 0x00000163, 0x000001d9, 0x00000166, 0x000001da, 0x00000169, 0x000001db, 0x0000016c, 0x000001dc, 0x0000016f, 0x000001de, 0x00000172, 0x000001df, 0x00000175, 0x000001e0, 0x00000178, 0x000001e1, 0x0000017b, 0x000001e2, 0x0000017e, 0x000001e3, 0x00000180, 0x000001e6, 0x00000182, 0x000001e7, 0x00000184, 0x000001e8, 0x00000186, 0x000001e9, 0x00000188, 0x000001ea, 0x0000018a, 0x000001eb, 0x0000018c, 0x000001ec, 0x0000018e, 0x000001ed, 0x00000191, 0x000001ee, 0x00000194, 0x000001ef, 0x00000196, 0x000001f0, 0x00000198, 0x000001f4, 0x0000019a, 0x000001f5, 0x0000019c, 0x000001f8, 0x0000019e, 0x000001f9, 0x000001a0, 0x000001fa, 0x000001a2, 0x000001fb, 0x000001a5, 0x000001fc, 0x000001a8, 0x000001fd, 0x000001aa, 0x000001fe, 0x000001ac, 0x000001ff, 0x000001ae, 0x00000200, 0x000001b0, 0x00000201, 0x000001b2, 0x00000202, 0x000001b4, 0x00000203, 0x000001b6, 0x00000204, 0x000001b8, 0x00000205, 0x000001ba, 0x00000206, 0x000001bc, 0x00000207, 0x000001be, 0x00000208, 0x000001c0, 0x00000209, 0x000001c2, 0x0000020a, 0x000001c4, 0x0000020b, 0x000001c6, 0x0000020c, 0x000001c8, 0x0000020d, 0x000001ca, 0x0000020e, 0x000001cc, 0x0000020f, 0x000001ce, 0x00000210, 0x000001d0, 0x00000211, 0x000001d2, 0x00000212, 0x000001d4, 0x00000213, 0x000001d6, 0x00000214, 0x000001d8, 0x00000215, 0x000001da, 0x00000216, 0x000001dc, 0x00000217, 0x000001de, 0x00000218, 0x000001e0, 0x00000219, 0x000001e2, 0x0000021a, 0x000001e4, 0x0000021b, 0x000001e6, 0x0000021e, 0x000001e8, 0x0000021f, 0x000001ea, 0x00000226, 0x000001ec, 0x00000227, 0x000001ee, 0x00000228, 0x000001f0, 0x00000229, 0x000001f2, 0x0000022a, 0x000001f4, 0x0000022b, 0x000001f7, 0x0000022c, 0x000001fa, 0x0000022d, 0x000001fd, 0x0000022e, 0x00000200, 0x0000022f, 0x00000202, 0x00000230, 0x00000204, 0x00000231, 0x00000207, 0x00000232, 0x0000020a, 0x00000233, 0x0000020c, 0x00000340, 0x0000020e, 0x00000341, 0x0000020f, 0x00000343, 0x00000210, 0x00000344, 0x00000211, 0x00000374, 0x00000213, 0x0000037e, 0x00000214, 0x00000385, 0x00000215, 0x00000386, 0x00000217, 0x00000387, 0x00000219, 0x00000388, 0x0000021a, 0x00000389, 0x0000021c, 0x0000038a, 0x0000021e, 0x0000038c, 0x00000220, 0x0000038e, 0x00000222, 0x0000038f, 0x00000224, 0x00000390, 0x00000226, 0x000003aa, 0x00000229, 0x000003ab, 0x0000022b, 0x000003ac, 0x0000022d, 0x000003ad, 0x0000022f, 0x000003ae, 0x00000231, 0x000003af, 0x00000233, 0x000003b0, 0x00000235, 0x000003ca, 0x00000238, 0x000003cb, 0x0000023a, 0x000003cc, 0x0000023c, 0x000003cd, 0x0000023e, 0x000003ce, 0x00000240, 0x000003d3, 0x00000242, 0x000003d4, 0x00000244, 0x00000400, 0x00000246, 0x00000401, 0x00000248, 0x00000403, 0x0000024a, 0x00000407, 0x0000024c, 0x0000040c, 0x0000024e, 0x0000040d, 0x00000250, 0x0000040e, 0x00000252, 0x00000419, 0x00000254, 0x00000439, 0x00000256, 0x00000450, 0x00000258, 0x00000451, 0x0000025a, 0x00000453, 0x0000025c, 0x00000457, 0x0000025e, 0x0000045c, 0x00000260, 0x0000045d, 0x00000262, 0x0000045e, 0x00000264, 0x00000476, 0x00000266, 0x00000477, 0x00000268, 0x000004c1, 0x0000026a, 0x000004c2, 0x0000026c, 0x000004d0, 0x0000026e, 0x000004d1, 0x00000270, 0x000004d2, 0x00000272, 0x000004d3, 0x00000274, 0x000004d6, 0x00000276, 0x000004d7, 0x00000278, 0x000004da, 0x0000027a, 0x000004db, 0x0000027c, 0x000004dc, 0x0000027e, 0x000004dd, 0x00000280, 0x000004de, 0x00000282, 0x000004df, 0x00000284, 0x000004e2, 0x00000286, 0x000004e3, 0x00000288, 0x000004e4, 0x0000028a, 0x000004e5, 0x0000028c, 0x000004e6, 0x0000028e, 0x000004e7, 0x00000290, 0x000004ea, 0x00000292, 0x000004eb, 0x00000294, 0x000004ec, 0x00000296, 0x000004ed, 0x00000298, 0x000004ee, 0x0000029a, 0x000004ef, 0x0000029c, 0x000004f0, 0x0000029e, 0x000004f1, 0x000002a0, 0x000004f2, 0x000002a2, 0x000004f3, 0x000002a4, 0x000004f4, 0x000002a6, 0x000004f5, 0x000002a8, 0x000004f8, 0x000002aa, 0x000004f9, 0x000002ac, 0x00000622, 0x000002ae, 0x00000623, 0x000002b0, 0x00000624, 0x000002b2, 0x00000625, 0x000002b4, 0x00000626, 0x000002b6, 0x000006c0, 0x000002b8, 0x000006c2, 0x000002ba, 0x000006d3, 0x000002bc, 0x00000929, 0x000002be, 0x00000931, 0x000002c0, 0x00000934, 0x000002c2, 0x00000958, 0x000002c4, 0x00000959, 0x000002c6, 0x0000095a, 0x000002c8, 0x0000095b, 0x000002ca, 0x0000095c, 0x000002cc, 0x0000095d, 0x000002ce, 0x0000095e, 0x000002d0, 0x0000095f, 0x000002d2, 0x000009cb, 0x000002d4, 0x000009cc, 0x000002d6, 0x000009dc, 0x000002d8, 0x000009dd, 0x000002da, 0x000009df, 0x000002dc, 0x00000a33, 0x000002de, 0x00000a36, 0x000002e0, 0x00000a59, 0x000002e2, 0x00000a5a, 0x000002e4, 0x00000a5b, 0x000002e6, 0x00000a5e, 0x000002e8, 0x00000b48, 0x000002ea, 0x00000b4b, 0x000002ec, 0x00000b4c, 0x000002ee, 0x00000b5c, 0x000002f0, 0x00000b5d, 0x000002f2, 0x00000b94, 0x000002f4, 0x00000bca, 0x000002f6, 0x00000bcb, 0x000002f8, 0x00000bcc, 0x000002fa, 0x00000c48, 0x000002fc, 0x00000cc0, 0x000002fe, 0x00000cc7, 0x00000300, 0x00000cc8, 0x00000302, 0x00000cca, 0x00000304, 0x00000ccb, 0x00000306, 0x00000d4a, 0x00000309, 0x00000d4b, 0x0000030b, 0x00000d4c, 0x0000030d, 0x00000dda, 0x0000030f, 0x00000ddc, 0x00000311, 0x00000ddd, 0x00000313, 0x00000dde, 0x00000316, 0x00000f43, 0x00000318, 0x00000f4d, 0x0000031a, 0x00000f52, 0x0000031c, 0x00000f57, 0x0000031e, 0x00000f5c, 0x00000320, 0x00000f69, 0x00000322, 0x00000f73, 0x00000324, 0x00000f75, 0x00000326, 0x00000f76, 0x00000328, 0x00000f78, 0x0000032a, 0x00000f81, 0x0000032c, 0x00000f93, 0x0000032e, 0x00000f9d, 0x00000330, 0x00000fa2, 0x00000332, 0x00000fa7, 0x00000334, 0x00000fac, 0x00000336, 0x00000fb9, 0x00000338, 0x00001026, 0x0000033a, 0x00001e00, 0x0000033c, 0x00001e01, 0x0000033e, 0x00001e02, 0x00000340, 0x00001e03, 0x00000342, 0x00001e04, 0x00000344, 0x00001e05, 0x00000346, 0x00001e06, 0x00000348, 0x00001e07, 0x0000034a, 0x00001e08, 0x0000034c, 0x00001e09, 0x0000034f, 0x00001e0a, 0x00000352, 0x00001e0b, 0x00000354, 0x00001e0c, 0x00000356, 0x00001e0d, 0x00000358, 0x00001e0e, 0x0000035a, 0x00001e0f, 0x0000035c, 0x00001e10, 0x0000035e, 0x00001e11, 0x00000360, 0x00001e12, 0x00000362, 0x00001e13, 0x00000364, 0x00001e14, 0x00000366, 0x00001e15, 0x00000369, 0x00001e16, 0x0000036c, 0x00001e17, 0x0000036f, 0x00001e18, 0x00000372, 0x00001e19, 0x00000374, 0x00001e1a, 0x00000376, 0x00001e1b, 0x00000378, 0x00001e1c, 0x0000037a, 0x00001e1d, 0x0000037d, 0x00001e1e, 0x00000380, 0x00001e1f, 0x00000382, 0x00001e20, 0x00000384, 0x00001e21, 0x00000386, 0x00001e22, 0x00000388, 0x00001e23, 0x0000038a, 0x00001e24, 0x0000038c, 0x00001e25, 0x0000038e, 0x00001e26, 0x00000390, 0x00001e27, 0x00000392, 0x00001e28, 0x00000394, 0x00001e29, 0x00000396, 0x00001e2a, 0x00000398, 0x00001e2b, 0x0000039a, 0x00001e2c, 0x0000039c, 0x00001e2d, 0x0000039e, 0x00001e2e, 0x000003a0, 0x00001e2f, 0x000003a3, 0x00001e30, 0x000003a6, 0x00001e31, 0x000003a8, 0x00001e32, 0x000003aa, 0x00001e33, 0x000003ac, 0x00001e34, 0x000003ae, 0x00001e35, 0x000003b0, 0x00001e36, 0x000003b2, 0x00001e37, 0x000003b4, 0x00001e38, 0x000003b6, 0x00001e39, 0x000003b9, 0x00001e3a, 0x000003bc, 0x00001e3b, 0x000003be, 0x00001e3c, 0x000003c0, 0x00001e3d, 0x000003c2, 0x00001e3e, 0x000003c4, 0x00001e3f, 0x000003c6, 0x00001e40, 0x000003c8, 0x00001e41, 0x000003ca, 0x00001e42, 0x000003cc, 0x00001e43, 0x000003ce, 0x00001e44, 0x000003d0, 0x00001e45, 0x000003d2, 0x00001e46, 0x000003d4, 0x00001e47, 0x000003d6, 0x00001e48, 0x000003d8, 0x00001e49, 0x000003da, 0x00001e4a, 0x000003dc, 0x00001e4b, 0x000003de, 0x00001e4c, 0x000003e0, 0x00001e4d, 0x000003e3, 0x00001e4e, 0x000003e6, 0x00001e4f, 0x000003e9, 0x00001e50, 0x000003ec, 0x00001e51, 0x000003ef, 0x00001e52, 0x000003f2, 0x00001e53, 0x000003f5, 0x00001e54, 0x000003f8, 0x00001e55, 0x000003fa, 0x00001e56, 0x000003fc, 0x00001e57, 0x000003fe, 0x00001e58, 0x00000400, 0x00001e59, 0x00000402, 0x00001e5a, 0x00000404, 0x00001e5b, 0x00000406, 0x00001e5c, 0x00000408, 0x00001e5d, 0x0000040b, 0x00001e5e, 0x0000040e, 0x00001e5f, 0x00000410, 0x00001e60, 0x00000412, 0x00001e61, 0x00000414, 0x00001e62, 0x00000416, 0x00001e63, 0x00000418, 0x00001e64, 0x0000041a, 0x00001e65, 0x0000041d, 0x00001e66, 0x00000420, 0x00001e67, 0x00000423, 0x00001e68, 0x00000426, 0x00001e69, 0x00000429, 0x00001e6a, 0x0000042c, 0x00001e6b, 0x0000042e, 0x00001e6c, 0x00000430, 0x00001e6d, 0x00000432, 0x00001e6e, 0x00000434, 0x00001e6f, 0x00000436, 0x00001e70, 0x00000438, 0x00001e71, 0x0000043a, 0x00001e72, 0x0000043c, 0x00001e73, 0x0000043e, 0x00001e74, 0x00000440, 0x00001e75, 0x00000442, 0x00001e76, 0x00000444, 0x00001e77, 0x00000446, 0x00001e78, 0x00000448, 0x00001e79, 0x0000044b, 0x00001e7a, 0x0000044e, 0x00001e7b, 0x00000451, 0x00001e7c, 0x00000454, 0x00001e7d, 0x00000456, 0x00001e7e, 0x00000458, 0x00001e7f, 0x0000045a, 0x00001e80, 0x0000045c, 0x00001e81, 0x0000045e, 0x00001e82, 0x00000460, 0x00001e83, 0x00000462, 0x00001e84, 0x00000464, 0x00001e85, 0x00000466, 0x00001e86, 0x00000468, 0x00001e87, 0x0000046a, 0x00001e88, 0x0000046c, 0x00001e89, 0x0000046e, 0x00001e8a, 0x00000470, 0x00001e8b, 0x00000472, 0x00001e8c, 0x00000474, 0x00001e8d, 0x00000476, 0x00001e8e, 0x00000478, 0x00001e8f, 0x0000047a, 0x00001e90, 0x0000047c, 0x00001e91, 0x0000047e, 0x00001e92, 0x00000480, 0x00001e93, 0x00000482, 0x00001e94, 0x00000484, 0x00001e95, 0x00000486, 0x00001e96, 0x00000488, 0x00001e97, 0x0000048a, 0x00001e98, 0x0000048c, 0x00001e99, 0x0000048e, 0x00001e9b, 0x00000490, 0x00001ea0, 0x00000492, 0x00001ea1, 0x00000494, 0x00001ea2, 0x00000496, 0x00001ea3, 0x00000498, 0x00001ea4, 0x0000049a, 0x00001ea5, 0x0000049d, 0x00001ea6, 0x000004a0, 0x00001ea7, 0x000004a3, 0x00001ea8, 0x000004a6, 0x00001ea9, 0x000004a9, 0x00001eaa, 0x000004ac, 0x00001eab, 0x000004af, 0x00001eac, 0x000004b2, 0x00001ead, 0x000004b5, 0x00001eae, 0x000004b8, 0x00001eaf, 0x000004bb, 0x00001eb0, 0x000004be, 0x00001eb1, 0x000004c1, 0x00001eb2, 0x000004c4, 0x00001eb3, 0x000004c7, 0x00001eb4, 0x000004ca, 0x00001eb5, 0x000004cd, 0x00001eb6, 0x000004d0, 0x00001eb7, 0x000004d3, 0x00001eb8, 0x000004d6, 0x00001eb9, 0x000004d8, 0x00001eba, 0x000004da, 0x00001ebb, 0x000004dc, 0x00001ebc, 0x000004de, 0x00001ebd, 0x000004e0, 0x00001ebe, 0x000004e2, 0x00001ebf, 0x000004e5, 0x00001ec0, 0x000004e8, 0x00001ec1, 0x000004eb, 0x00001ec2, 0x000004ee, 0x00001ec3, 0x000004f1, 0x00001ec4, 0x000004f4, 0x00001ec5, 0x000004f7, 0x00001ec6, 0x000004fa, 0x00001ec7, 0x000004fd, 0x00001ec8, 0x00000500, 0x00001ec9, 0x00000502, 0x00001eca, 0x00000504, 0x00001ecb, 0x00000506, 0x00001ecc, 0x00000508, 0x00001ecd, 0x0000050a, 0x00001ece, 0x0000050c, 0x00001ecf, 0x0000050e, 0x00001ed0, 0x00000510, 0x00001ed1, 0x00000513, 0x00001ed2, 0x00000516, 0x00001ed3, 0x00000519, 0x00001ed4, 0x0000051c, 0x00001ed5, 0x0000051f, 0x00001ed6, 0x00000522, 0x00001ed7, 0x00000525, 0x00001ed8, 0x00000528, 0x00001ed9, 0x0000052b, 0x00001eda, 0x0000052e, 0x00001edb, 0x00000531, 0x00001edc, 0x00000534, 0x00001edd, 0x00000537, 0x00001ede, 0x0000053a, 0x00001edf, 0x0000053d, 0x00001ee0, 0x00000540, 0x00001ee1, 0x00000543, 0x00001ee2, 0x00000546, 0x00001ee3, 0x00000549, 0x00001ee4, 0x0000054c, 0x00001ee5, 0x0000054e, 0x00001ee6, 0x00000550, 0x00001ee7, 0x00000552, 0x00001ee8, 0x00000554, 0x00001ee9, 0x00000557, 0x00001eea, 0x0000055a, 0x00001eeb, 0x0000055d, 0x00001eec, 0x00000560, 0x00001eed, 0x00000563, 0x00001eee, 0x00000566, 0x00001eef, 0x00000569, 0x00001ef0, 0x0000056c, 0x00001ef1, 0x0000056f, 0x00001ef2, 0x00000572, 0x00001ef3, 0x00000574, 0x00001ef4, 0x00000576, 0x00001ef5, 0x00000578, 0x00001ef6, 0x0000057a, 0x00001ef7, 0x0000057c, 0x00001ef8, 0x0000057e, 0x00001ef9, 0x00000580, 0x00001f00, 0x00000582, 0x00001f01, 0x00000584, 0x00001f02, 0x00000586, 0x00001f03, 0x00000589, 0x00001f04, 0x0000058c, 0x00001f05, 0x0000058f, 0x00001f06, 0x00000592, 0x00001f07, 0x00000595, 0x00001f08, 0x00000598, 0x00001f09, 0x0000059a, 0x00001f0a, 0x0000059c, 0x00001f0b, 0x0000059f, 0x00001f0c, 0x000005a2, 0x00001f0d, 0x000005a5, 0x00001f0e, 0x000005a8, 0x00001f0f, 0x000005ab, 0x00001f10, 0x000005ae, 0x00001f11, 0x000005b0, 0x00001f12, 0x000005b2, 0x00001f13, 0x000005b5, 0x00001f14, 0x000005b8, 0x00001f15, 0x000005bb, 0x00001f18, 0x000005be, 0x00001f19, 0x000005c0, 0x00001f1a, 0x000005c2, 0x00001f1b, 0x000005c5, 0x00001f1c, 0x000005c8, 0x00001f1d, 0x000005cb, 0x00001f20, 0x000005ce, 0x00001f21, 0x000005d0, 0x00001f22, 0x000005d2, 0x00001f23, 0x000005d5, 0x00001f24, 0x000005d8, 0x00001f25, 0x000005db, 0x00001f26, 0x000005de, 0x00001f27, 0x000005e1, 0x00001f28, 0x000005e4, 0x00001f29, 0x000005e6, 0x00001f2a, 0x000005e8, 0x00001f2b, 0x000005eb, 0x00001f2c, 0x000005ee, 0x00001f2d, 0x000005f1, 0x00001f2e, 0x000005f4, 0x00001f2f, 0x000005f7, 0x00001f30, 0x000005fa, 0x00001f31, 0x000005fc, 0x00001f32, 0x000005fe, 0x00001f33, 0x00000601, 0x00001f34, 0x00000604, 0x00001f35, 0x00000607, 0x00001f36, 0x0000060a, 0x00001f37, 0x0000060d, 0x00001f38, 0x00000610, 0x00001f39, 0x00000612, 0x00001f3a, 0x00000614, 0x00001f3b, 0x00000617, 0x00001f3c, 0x0000061a, 0x00001f3d, 0x0000061d, 0x00001f3e, 0x00000620, 0x00001f3f, 0x00000623, 0x00001f40, 0x00000626, 0x00001f41, 0x00000628, 0x00001f42, 0x0000062a, 0x00001f43, 0x0000062d, 0x00001f44, 0x00000630, 0x00001f45, 0x00000633, 0x00001f48, 0x00000636, 0x00001f49, 0x00000638, 0x00001f4a, 0x0000063a, 0x00001f4b, 0x0000063d, 0x00001f4c, 0x00000640, 0x00001f4d, 0x00000643, 0x00001f50, 0x00000646, 0x00001f51, 0x00000648, 0x00001f52, 0x0000064a, 0x00001f53, 0x0000064d, 0x00001f54, 0x00000650, 0x00001f55, 0x00000653, 0x00001f56, 0x00000656, 0x00001f57, 0x00000659, 0x00001f59, 0x0000065c, 0x00001f5b, 0x0000065e, 0x00001f5d, 0x00000661, 0x00001f5f, 0x00000664, 0x00001f60, 0x00000667, 0x00001f61, 0x00000669, 0x00001f62, 0x0000066b, 0x00001f63, 0x0000066e, 0x00001f64, 0x00000671, 0x00001f65, 0x00000674, 0x00001f66, 0x00000677, 0x00001f67, 0x0000067a, 0x00001f68, 0x0000067d, 0x00001f69, 0x0000067f, 0x00001f6a, 0x00000681, 0x00001f6b, 0x00000684, 0x00001f6c, 0x00000687, 0x00001f6d, 0x0000068a, 0x00001f6e, 0x0000068d, 0x00001f6f, 0x00000690, 0x00001f70, 0x00000693, 0x00001f71, 0x00000695, 0x00001f72, 0x00000697, 0x00001f73, 0x00000699, 0x00001f74, 0x0000069b, 0x00001f75, 0x0000069d, 0x00001f76, 0x0000069f, 0x00001f77, 0x000006a1, 0x00001f78, 0x000006a3, 0x00001f79, 0x000006a5, 0x00001f7a, 0x000006a7, 0x00001f7b, 0x000006a9, 0x00001f7c, 0x000006ab, 0x00001f7d, 0x000006ad, 0x00001f80, 0x000006af, 0x00001f81, 0x000006b2, 0x00001f82, 0x000006b5, 0x00001f83, 0x000006b9, 0x00001f84, 0x000006bd, 0x00001f85, 0x000006c1, 0x00001f86, 0x000006c5, 0x00001f87, 0x000006c9, 0x00001f88, 0x000006cd, 0x00001f89, 0x000006d0, 0x00001f8a, 0x000006d3, 0x00001f8b, 0x000006d7, 0x00001f8c, 0x000006db, 0x00001f8d, 0x000006df, 0x00001f8e, 0x000006e3, 0x00001f8f, 0x000006e7, 0x00001f90, 0x000006eb, 0x00001f91, 0x000006ee, 0x00001f92, 0x000006f1, 0x00001f93, 0x000006f5, 0x00001f94, 0x000006f9, 0x00001f95, 0x000006fd, 0x00001f96, 0x00000701, 0x00001f97, 0x00000705, 0x00001f98, 0x00000709, 0x00001f99, 0x0000070c, 0x00001f9a, 0x0000070f, 0x00001f9b, 0x00000713, 0x00001f9c, 0x00000717, 0x00001f9d, 0x0000071b, 0x00001f9e, 0x0000071f, 0x00001f9f, 0x00000723, 0x00001fa0, 0x00000727, 0x00001fa1, 0x0000072a, 0x00001fa2, 0x0000072d, 0x00001fa3, 0x00000731, 0x00001fa4, 0x00000735, 0x00001fa5, 0x00000739, 0x00001fa6, 0x0000073d, 0x00001fa7, 0x00000741, 0x00001fa8, 0x00000745, 0x00001fa9, 0x00000748, 0x00001faa, 0x0000074b, 0x00001fab, 0x0000074f, 0x00001fac, 0x00000753, 0x00001fad, 0x00000757, 0x00001fae, 0x0000075b, 0x00001faf, 0x0000075f, 0x00001fb0, 0x00000763, 0x00001fb1, 0x00000765, 0x00001fb2, 0x00000767, 0x00001fb3, 0x0000076a, 0x00001fb4, 0x0000076c, 0x00001fb6, 0x0000076f, 0x00001fb7, 0x00000771, 0x00001fb8, 0x00000774, 0x00001fb9, 0x00000776, 0x00001fba, 0x00000778, 0x00001fbb, 0x0000077a, 0x00001fbc, 0x0000077c, 0x00001fbe, 0x0000077e, 0x00001fc1, 0x0000077f, 0x00001fc2, 0x00000781, 0x00001fc3, 0x00000784, 0x00001fc4, 0x00000786, 0x00001fc6, 0x00000789, 0x00001fc7, 0x0000078b, 0x00001fc8, 0x0000078e, 0x00001fc9, 0x00000790, 0x00001fca, 0x00000792, 0x00001fcb, 0x00000794, 0x00001fcc, 0x00000796, 0x00001fcd, 0x00000798, 0x00001fce, 0x0000079a, 0x00001fcf, 0x0000079c, 0x00001fd0, 0x0000079e, 0x00001fd1, 0x000007a0, 0x00001fd2, 0x000007a2, 0x00001fd3, 0x000007a5, 0x00001fd6, 0x000007a8, 0x00001fd7, 0x000007aa, 0x00001fd8, 0x000007ad, 0x00001fd9, 0x000007af, 0x00001fda, 0x000007b1, 0x00001fdb, 0x000007b3, 0x00001fdd, 0x000007b5, 0x00001fde, 0x000007b7, 0x00001fdf, 0x000007b9, 0x00001fe0, 0x000007bb, 0x00001fe1, 0x000007bd, 0x00001fe2, 0x000007bf, 0x00001fe3, 0x000007c2, 0x00001fe4, 0x000007c5, 0x00001fe5, 0x000007c7, 0x00001fe6, 0x000007c9, 0x00001fe7, 0x000007cb, 0x00001fe8, 0x000007ce, 0x00001fe9, 0x000007d0, 0x00001fea, 0x000007d2, 0x00001feb, 0x000007d4, 0x00001fec, 0x000007d6, 0x00001fed, 0x000007d8, 0x00001fee, 0x000007da, 0x00001fef, 0x000007dc, 0x00001ff2, 0x000007dd, 0x00001ff3, 0x000007e0, 0x00001ff4, 0x000007e2, 0x00001ff6, 0x000007e5, 0x00001ff7, 0x000007e7, 0x00001ff8, 0x000007ea, 0x00001ff9, 0x000007ec, 0x00001ffa, 0x000007ee, 0x00001ffb, 0x000007f0, 0x00001ffc, 0x000007f2, 0x00001ffd, 0x000007f4, 0x00002000, 0x000007f5, 0x00002001, 0x000007f6, 0x00002126, 0x000007f7, 0x0000212a, 0x000007f8, 0x0000212b, 0x000007f9, 0x0000219a, 0x000007fb, 0x0000219b, 0x000007fd, 0x000021ae, 0x000007ff, 0x000021cd, 0x00000801, 0x000021ce, 0x00000803, 0x000021cf, 0x00000805, 0x00002204, 0x00000807, 0x00002209, 0x00000809, 0x0000220c, 0x0000080b, 0x00002224, 0x0000080d, 0x00002226, 0x0000080f, 0x00002241, 0x00000811, 0x00002244, 0x00000813, 0x00002247, 0x00000815, 0x00002249, 0x00000817, 0x00002260, 0x00000819, 0x00002262, 0x0000081b, 0x0000226d, 0x0000081d, 0x0000226e, 0x0000081f, 0x0000226f, 0x00000821, 0x00002270, 0x00000823, 0x00002271, 0x00000825, 0x00002274, 0x00000827, 0x00002275, 0x00000829, 0x00002278, 0x0000082b, 0x00002279, 0x0000082d, 0x00002280, 0x0000082f, 0x00002281, 0x00000831, 0x00002284, 0x00000833, 0x00002285, 0x00000835, 0x00002288, 0x00000837, 0x00002289, 0x00000839, 0x000022ac, 0x0000083b, 0x000022ad, 0x0000083d, 0x000022ae, 0x0000083f, 0x000022af, 0x00000841, 0x000022e0, 0x00000843, 0x000022e1, 0x00000845, 0x000022e2, 0x00000847, 0x000022e3, 0x00000849, 0x000022ea, 0x0000084b, 0x000022eb, 0x0000084d, 0x000022ec, 0x0000084f, 0x000022ed, 0x00000851, 0x00002329, 0x00000853, 0x0000232a, 0x00000854, 0x00002adc, 0x00000855, 0x0000304c, 0x00000857, 0x0000304e, 0x00000859, 0x00003050, 0x0000085b, 0x00003052, 0x0000085d, 0x00003054, 0x0000085f, 0x00003056, 0x00000861, 0x00003058, 0x00000863, 0x0000305a, 0x00000865, 0x0000305c, 0x00000867, 0x0000305e, 0x00000869, 0x00003060, 0x0000086b, 0x00003062, 0x0000086d, 0x00003065, 0x0000086f, 0x00003067, 0x00000871, 0x00003069, 0x00000873, 0x00003070, 0x00000875, 0x00003071, 0x00000877, 0x00003073, 0x00000879, 0x00003074, 0x0000087b, 0x00003076, 0x0000087d, 0x00003077, 0x0000087f, 0x00003079, 0x00000881, 0x0000307a, 0x00000883, 0x0000307c, 0x00000885, 0x0000307d, 0x00000887, 0x00003094, 0x00000889, 0x0000309e, 0x0000088b, 0x000030ac, 0x0000088d, 0x000030ae, 0x0000088f, 0x000030b0, 0x00000891, 0x000030b2, 0x00000893, 0x000030b4, 0x00000895, 0x000030b6, 0x00000897, 0x000030b8, 0x00000899, 0x000030ba, 0x0000089b, 0x000030bc, 0x0000089d, 0x000030be, 0x0000089f, 0x000030c0, 0x000008a1, 0x000030c2, 0x000008a3, 0x000030c5, 0x000008a5, 0x000030c7, 0x000008a7, 0x000030c9, 0x000008a9, 0x000030d0, 0x000008ab, 0x000030d1, 0x000008ad, 0x000030d3, 0x000008af, 0x000030d4, 0x000008b1, 0x000030d6, 0x000008b3, 0x000030d7, 0x000008b5, 0x000030d9, 0x000008b7, 0x000030da, 0x000008b9, 0x000030dc, 0x000008bb, 0x000030dd, 0x000008bd, 0x000030f4, 0x000008bf, 0x000030f7, 0x000008c1, 0x000030f8, 0x000008c3, 0x000030f9, 0x000008c5, 0x000030fa, 0x000008c7, 0x000030fe, 0x000008c9, 0x0000f902, 0x000008cb, 0x0000f903, 0x000008cc, 0x0000f904, 0x000008cd, 0x0000f905, 0x000008ce, 0x0000f906, 0x000008cf, 0x0000f907, 0x000008d0, 0x0000f908, 0x000008d1, 0x0000f909, 0x000008d2, 0x0000f90a, 0x000008d3, 0x0000f90b, 0x000008d4, 0x0000f90c, 0x000008d5, 0x0000f90d, 0x000008d6, 0x0000f90e, 0x000008d7, 0x0000f90f, 0x000008d8, 0x0000f910, 0x000008d9, 0x0000f911, 0x000008da, 0x0000f912, 0x000008db, 0x0000f913, 0x000008dc, 0x0000f914, 0x000008dd, 0x0000f915, 0x000008de, 0x0000f916, 0x000008df, 0x0000f917, 0x000008e0, 0x0000f918, 0x000008e1, 0x0000f919, 0x000008e2, 0x0000f91a, 0x000008e3, 0x0000f91b, 0x000008e4, 0x0000f91c, 0x000008e5, 0x0000f91d, 0x000008e6, 0x0000f91e, 0x000008e7, 0x0000f91f, 0x000008e8, 0x0000f920, 0x000008e9, 0x0000f921, 0x000008ea, 0x0000f922, 0x000008eb, 0x0000f923, 0x000008ec, 0x0000f924, 0x000008ed, 0x0000f925, 0x000008ee, 0x0000f926, 0x000008ef, 0x0000f927, 0x000008f0, 0x0000f928, 0x000008f1, 0x0000f929, 0x000008f2, 0x0000f92a, 0x000008f3, 0x0000f92b, 0x000008f4, 0x0000f92c, 0x000008f5, 0x0000f92d, 0x000008f6, 0x0000f92e, 0x000008f7, 0x0000f92f, 0x000008f8, 0x0000f930, 0x000008f9, 0x0000f931, 0x000008fa, 0x0000f932, 0x000008fb, 0x0000f933, 0x000008fc, 0x0000f934, 0x000008fd, 0x0000f935, 0x000008fe, 0x0000f936, 0x000008ff, 0x0000f937, 0x00000900, 0x0000f938, 0x00000901, 0x0000f939, 0x00000902, 0x0000f93a, 0x00000903, 0x0000f93b, 0x00000904, 0x0000f93c, 0x00000905, 0x0000f93d, 0x00000906, 0x0000f93e, 0x00000907, 0x0000f93f, 0x00000908, 0x0000f940, 0x00000909, 0x0000f941, 0x0000090a, 0x0000f942, 0x0000090b, 0x0000f943, 0x0000090c, 0x0000f944, 0x0000090d, 0x0000f945, 0x0000090e, 0x0000f946, 0x0000090f, 0x0000f947, 0x00000910, 0x0000f948, 0x00000911, 0x0000f949, 0x00000912, 0x0000f94a, 0x00000913, 0x0000f94b, 0x00000914, 0x0000f94c, 0x00000915, 0x0000f94d, 0x00000916, 0x0000f94e, 0x00000917, 0x0000f94f, 0x00000918, 0x0000f950, 0x00000919, 0x0000f951, 0x0000091a, 0x0000f952, 0x0000091b, 0x0000f953, 0x0000091c, 0x0000f954, 0x0000091d, 0x0000f955, 0x0000091e, 0x0000f956, 0x0000091f, 0x0000f957, 0x00000920, 0x0000f958, 0x00000921, 0x0000f959, 0x00000922, 0x0000f95a, 0x00000923, 0x0000f95b, 0x00000924, 0x0000f95c, 0x00000925, 0x0000f95d, 0x00000926, 0x0000f95e, 0x00000927, 0x0000f95f, 0x00000928, 0x0000f960, 0x00000929, 0x0000f961, 0x0000092a, 0x0000f962, 0x0000092b, 0x0000f963, 0x0000092c, 0x0000f964, 0x0000092d, 0x0000f965, 0x0000092e, 0x0000f966, 0x0000092f, 0x0000f967, 0x00000930, 0x0000f968, 0x00000931, 0x0000f969, 0x00000932, 0x0000f96a, 0x00000933, 0x0000f96b, 0x00000934, 0x0000f96c, 0x00000935, 0x0000f96d, 0x00000936, 0x0000f96e, 0x00000937, 0x0000f96f, 0x00000938, 0x0000f970, 0x00000939, 0x0000f971, 0x0000093a, 0x0000f972, 0x0000093b, 0x0000f973, 0x0000093c, 0x0000f974, 0x0000093d, 0x0000f975, 0x0000093e, 0x0000f976, 0x0000093f, 0x0000f977, 0x00000940, 0x0000f978, 0x00000941, 0x0000f979, 0x00000942, 0x0000f97a, 0x00000943, 0x0000f97b, 0x00000944, 0x0000f97c, 0x00000945, 0x0000f97d, 0x00000946, 0x0000f97e, 0x00000947, 0x0000f97f, 0x00000948, 0x0000f980, 0x00000949, 0x0000f981, 0x0000094a, 0x0000f982, 0x0000094b, 0x0000f983, 0x0000094c, 0x0000f984, 0x0000094d, 0x0000f985, 0x0000094e, 0x0000f986, 0x0000094f, 0x0000f987, 0x00000950, 0x0000f988, 0x00000951, 0x0000f989, 0x00000952, 0x0000f98a, 0x00000953, 0x0000f98b, 0x00000954, 0x0000f98c, 0x00000955, 0x0000f98d, 0x00000956, 0x0000f98e, 0x00000957, 0x0000f98f, 0x00000958, 0x0000f990, 0x00000959, 0x0000f991, 0x0000095a, 0x0000f992, 0x0000095b, 0x0000f993, 0x0000095c, 0x0000f994, 0x0000095d, 0x0000f995, 0x0000095e, 0x0000f996, 0x0000095f, 0x0000f997, 0x00000960, 0x0000f998, 0x00000961, 0x0000f999, 0x00000962, 0x0000f99a, 0x00000963, 0x0000f99b, 0x00000964, 0x0000f99c, 0x00000965, 0x0000f99d, 0x00000966, 0x0000f99e, 0x00000967, 0x0000f99f, 0x00000968, 0x0000f9a0, 0x00000969, 0x0000f9a1, 0x0000096a, 0x0000f9a2, 0x0000096b, 0x0000f9a3, 0x0000096c, 0x0000f9a4, 0x0000096d, 0x0000f9a5, 0x0000096e, 0x0000f9a6, 0x0000096f, 0x0000f9a7, 0x00000970, 0x0000f9a8, 0x00000971, 0x0000f9a9, 0x00000972, 0x0000f9aa, 0x00000973, 0x0000f9ab, 0x00000974, 0x0000f9ac, 0x00000975, 0x0000f9ad, 0x00000976, 0x0000f9ae, 0x00000977, 0x0000f9af, 0x00000978, 0x0000f9b0, 0x00000979, 0x0000f9b1, 0x0000097a, 0x0000f9b2, 0x0000097b, 0x0000f9b3, 0x0000097c, 0x0000f9b4, 0x0000097d, 0x0000f9b5, 0x0000097e, 0x0000f9b6, 0x0000097f, 0x0000f9b7, 0x00000980, 0x0000f9b8, 0x00000981, 0x0000f9b9, 0x00000982, 0x0000f9ba, 0x00000983, 0x0000f9bb, 0x00000984, 0x0000f9bc, 0x00000985, 0x0000f9bd, 0x00000986, 0x0000f9be, 0x00000987, 0x0000f9bf, 0x00000988, 0x0000f9c0, 0x00000989, 0x0000f9c1, 0x0000098a, 0x0000f9c2, 0x0000098b, 0x0000f9c3, 0x0000098c, 0x0000f9c4, 0x0000098d, 0x0000f9c5, 0x0000098e, 0x0000f9c6, 0x0000098f, 0x0000f9c7, 0x00000990, 0x0000f9c8, 0x00000991, 0x0000f9c9, 0x00000992, 0x0000f9ca, 0x00000993, 0x0000f9cb, 0x00000994, 0x0000f9cc, 0x00000995, 0x0000f9cd, 0x00000996, 0x0000f9ce, 0x00000997, 0x0000f9cf, 0x00000998, 0x0000f9d0, 0x00000999, 0x0000f9d1, 0x0000099a, 0x0000f9d2, 0x0000099b, 0x0000f9d3, 0x0000099c, 0x0000f9d4, 0x0000099d, 0x0000f9d5, 0x0000099e, 0x0000f9d6, 0x0000099f, 0x0000f9d7, 0x000009a0, 0x0000f9d8, 0x000009a1, 0x0000f9d9, 0x000009a2, 0x0000f9da, 0x000009a3, 0x0000f9db, 0x000009a4, 0x0000f9dc, 0x000009a5, 0x0000f9dd, 0x000009a6, 0x0000f9de, 0x000009a7, 0x0000f9df, 0x000009a8, 0x0000f9e0, 0x000009a9, 0x0000f9e1, 0x000009aa, 0x0000f9e2, 0x000009ab, 0x0000f9e3, 0x000009ac, 0x0000f9e4, 0x000009ad, 0x0000f9e5, 0x000009ae, 0x0000f9e6, 0x000009af, 0x0000f9e7, 0x000009b0, 0x0000f9e8, 0x000009b1, 0x0000f9e9, 0x000009b2, 0x0000f9ea, 0x000009b3, 0x0000f9eb, 0x000009b4, 0x0000f9ec, 0x000009b5, 0x0000f9ed, 0x000009b6, 0x0000f9ee, 0x000009b7, 0x0000f9ef, 0x000009b8, 0x0000f9f0, 0x000009b9, 0x0000f9f1, 0x000009ba, 0x0000f9f2, 0x000009bb, 0x0000f9f3, 0x000009bc, 0x0000f9f4, 0x000009bd, 0x0000f9f5, 0x000009be, 0x0000f9f6, 0x000009bf, 0x0000f9f7, 0x000009c0, 0x0000f9f8, 0x000009c1, 0x0000f9f9, 0x000009c2, 0x0000f9fa, 0x000009c3, 0x0000f9fb, 0x000009c4, 0x0000f9fc, 0x000009c5, 0x0000f9fd, 0x000009c6, 0x0000f9fe, 0x000009c7, 0x0000f9ff, 0x000009c8, 0x0000fa00, 0x000009c9, 0x0000fa01, 0x000009ca, 0x0000fa02, 0x000009cb, 0x0000fa03, 0x000009cc, 0x0000fa04, 0x000009cd, 0x0000fa05, 0x000009ce, 0x0000fa06, 0x000009cf, 0x0000fa07, 0x000009d0, 0x0000fa08, 0x000009d1, 0x0000fa09, 0x000009d2, 0x0000fa0a, 0x000009d3, 0x0000fa0b, 0x000009d4, 0x0000fa0c, 0x000009d5, 0x0000fa0d, 0x000009d6, 0x0000fa10, 0x000009d7, 0x0000fa12, 0x000009d8, 0x0000fa15, 0x000009d9, 0x0000fa16, 0x000009da, 0x0000fa17, 0x000009db, 0x0000fa18, 0x000009dc, 0x0000fa19, 0x000009dd, 0x0000fa1a, 0x000009de, 0x0000fa1b, 0x000009df, 0x0000fa1c, 0x000009e0, 0x0000fa1d, 0x000009e1, 0x0000fa1e, 0x000009e2, 0x0000fa20, 0x000009e3, 0x0000fa22, 0x000009e4, 0x0000fa25, 0x000009e5, 0x0000fa26, 0x000009e6, 0x0000fa2a, 0x000009e7, 0x0000fa2b, 0x000009e8, 0x0000fa2c, 0x000009e9, 0x0000fa2d, 0x000009ea, 0x0000fa30, 0x000009eb, 0x0000fa31, 0x000009ec, 0x0000fa32, 0x000009ed, 0x0000fa33, 0x000009ee, 0x0000fa34, 0x000009ef, 0x0000fa35, 0x000009f0, 0x0000fa36, 0x000009f1, 0x0000fa37, 0x000009f2, 0x0000fa38, 0x000009f3, 0x0000fa39, 0x000009f4, 0x0000fa3a, 0x000009f5, 0x0000fa3b, 0x000009f6, 0x0000fa3c, 0x000009f7, 0x0000fa3d, 0x000009f8, 0x0000fa3e, 0x000009f9, 0x0000fa3f, 0x000009fa, 0x0000fa40, 0x000009fb, 0x0000fa41, 0x000009fc, 0x0000fa42, 0x000009fd, 0x0000fa43, 0x000009fe, 0x0000fa44, 0x000009ff, 0x0000fa45, 0x00000a00, 0x0000fa46, 0x00000a01, 0x0000fa47, 0x00000a02, 0x0000fa48, 0x00000a03, 0x0000fa49, 0x00000a04, 0x0000fa4a, 0x00000a05, 0x0000fa4b, 0x00000a06, 0x0000fa4c, 0x00000a07, 0x0000fa4d, 0x00000a08, 0x0000fa4e, 0x00000a09, 0x0000fa4f, 0x00000a0a, 0x0000fa50, 0x00000a0b, 0x0000fa51, 0x00000a0c, 0x0000fa52, 0x00000a0d, 0x0000fa53, 0x00000a0e, 0x0000fa54, 0x00000a0f, 0x0000fa55, 0x00000a10, 0x0000fa56, 0x00000a11, 0x0000fa57, 0x00000a12, 0x0000fa58, 0x00000a13, 0x0000fa59, 0x00000a14, 0x0000fa5a, 0x00000a15, 0x0000fa5b, 0x00000a16, 0x0000fa5c, 0x00000a17, 0x0000fa5d, 0x00000a18, 0x0000fa5e, 0x00000a19, 0x0000fa5f, 0x00000a1a, 0x0000fa60, 0x00000a1b, 0x0000fa61, 0x00000a1c, 0x0000fa62, 0x00000a1d, 0x0000fa63, 0x00000a1e, 0x0000fa64, 0x00000a1f, 0x0000fa65, 0x00000a20, 0x0000fa66, 0x00000a21, 0x0000fa67, 0x00000a22, 0x0000fa68, 0x00000a23, 0x0000fa69, 0x00000a24, 0x0000fa6a, 0x00000a25, 0x0000fb1d, 0x00000a26, 0x0000fb1f, 0x00000a28, 0x0000fb2a, 0x00000a2a, 0x0000fb2b, 0x00000a2c, 0x0000fb2c, 0x00000a2e, 0x0000fb2d, 0x00000a31, 0x0000fb2e, 0x00000a34, 0x0000fb2f, 0x00000a36, 0x0000fb30, 0x00000a38, 0x0000fb31, 0x00000a3a, 0x0000fb32, 0x00000a3c, 0x0000fb33, 0x00000a3e, 0x0000fb34, 0x00000a40, 0x0000fb35, 0x00000a42, 0x0000fb36, 0x00000a44, 0x0000fb38, 0x00000a46, 0x0000fb39, 0x00000a48, 0x0000fb3a, 0x00000a4a, 0x0000fb3b, 0x00000a4c, 0x0000fb3c, 0x00000a4e, 0x0000fb3e, 0x00000a50, 0x0000fb40, 0x00000a52, 0x0000fb41, 0x00000a54, 0x0000fb43, 0x00000a56, 0x0000fb44, 0x00000a58, 0x0000fb46, 0x00000a5a, 0x0000fb47, 0x00000a5c, 0x0000fb48, 0x00000a5e, 0x0000fb49, 0x00000a60, 0x0000fb4a, 0x00000a62, 0x0000fb4b, 0x00000a64, 0x0000fb4c, 0x00000a66, 0x0000fb4d, 0x00000a68, 0x0000fb4e, 0x00000a6a, 0x0001d15e, 0x00000a6c, 0x0001d15f, 0x00000a6e, 0x0001d160, 0x00000a70, 0x0001d161, 0x00000a73, 0x0001d162, 0x00000a76, 0x0001d163, 0x00000a79, 0x0001d164, 0x00000a7c, 0x0001d1bb, 0x00000a7f, 0x0001d1bc, 0x00000a81, 0x0001d1bd, 0x00000a83, 0x0001d1be, 0x00000a86, 0x0001d1bf, 0x00000a89, 0x0001d1c0, 0x00000a8c, 0x0002f800, 0x00000a8f, 0x0002f801, 0x00000a90, 0x0002f802, 0x00000a91, 0x0002f803, 0x00000a92, 0x0002f804, 0x00000a93, 0x0002f805, 0x00000a94, 0x0002f806, 0x00000a95, 0x0002f807, 0x00000a96, 0x0002f808, 0x00000a97, 0x0002f809, 0x00000a98, 0x0002f80a, 0x00000a99, 0x0002f80b, 0x00000a9a, 0x0002f80c, 0x00000a9b, 0x0002f80d, 0x00000a9c, 0x0002f80e, 0x00000a9d, 0x0002f80f, 0x00000a9e, 0x0002f810, 0x00000a9f, 0x0002f811, 0x00000aa0, 0x0002f812, 0x00000aa1, 0x0002f813, 0x00000aa2, 0x0002f814, 0x00000aa3, 0x0002f815, 0x00000aa4, 0x0002f816, 0x00000aa5, 0x0002f817, 0x00000aa6, 0x0002f818, 0x00000aa7, 0x0002f819, 0x00000aa8, 0x0002f81a, 0x00000aa9, 0x0002f81b, 0x00000aaa, 0x0002f81c, 0x00000aab, 0x0002f81d, 0x00000aac, 0x0002f81e, 0x00000aad, 0x0002f81f, 0x00000aae, 0x0002f820, 0x00000aaf, 0x0002f821, 0x00000ab0, 0x0002f822, 0x00000ab1, 0x0002f823, 0x00000ab2, 0x0002f824, 0x00000ab3, 0x0002f825, 0x00000ab4, 0x0002f826, 0x00000ab5, 0x0002f827, 0x00000ab6, 0x0002f828, 0x00000ab7, 0x0002f829, 0x00000ab8, 0x0002f82a, 0x00000ab9, 0x0002f82b, 0x00000aba, 0x0002f82c, 0x00000abb, 0x0002f82d, 0x00000abc, 0x0002f82e, 0x00000abd, 0x0002f82f, 0x00000abe, 0x0002f830, 0x00000abf, 0x0002f831, 0x00000ac0, 0x0002f832, 0x00000ac1, 0x0002f833, 0x00000ac2, 0x0002f834, 0x00000ac3, 0x0002f835, 0x00000ac4, 0x0002f836, 0x00000ac5, 0x0002f837, 0x00000ac6, 0x0002f838, 0x00000ac7, 0x0002f839, 0x00000ac8, 0x0002f83a, 0x00000ac9, 0x0002f83b, 0x00000aca, 0x0002f83c, 0x00000acb, 0x0002f83d, 0x00000acc, 0x0002f83e, 0x00000acd, 0x0002f83f, 0x00000ace, 0x0002f840, 0x00000acf, 0x0002f841, 0x00000ad0, 0x0002f842, 0x00000ad1, 0x0002f843, 0x00000ad2, 0x0002f844, 0x00000ad3, 0x0002f845, 0x00000ad4, 0x0002f846, 0x00000ad5, 0x0002f847, 0x00000ad6, 0x0002f848, 0x00000ad7, 0x0002f849, 0x00000ad8, 0x0002f84a, 0x00000ad9, 0x0002f84b, 0x00000ada, 0x0002f84c, 0x00000adb, 0x0002f84d, 0x00000adc, 0x0002f84e, 0x00000add, 0x0002f84f, 0x00000ade, 0x0002f850, 0x00000adf, 0x0002f851, 0x00000ae0, 0x0002f852, 0x00000ae1, 0x0002f853, 0x00000ae2, 0x0002f854, 0x00000ae3, 0x0002f855, 0x00000ae4, 0x0002f856, 0x00000ae5, 0x0002f857, 0x00000ae6, 0x0002f858, 0x00000ae7, 0x0002f859, 0x00000ae8, 0x0002f85a, 0x00000ae9, 0x0002f85b, 0x00000aea, 0x0002f85c, 0x00000aeb, 0x0002f85d, 0x00000aec, 0x0002f85e, 0x00000aed, 0x0002f85f, 0x00000aee, 0x0002f860, 0x00000aef, 0x0002f861, 0x00000af0, 0x0002f862, 0x00000af1, 0x0002f863, 0x00000af2, 0x0002f864, 0x00000af3, 0x0002f865, 0x00000af4, 0x0002f866, 0x00000af5, 0x0002f867, 0x00000af6, 0x0002f868, 0x00000af7, 0x0002f869, 0x00000af8, 0x0002f86a, 0x00000af9, 0x0002f86b, 0x00000afa, 0x0002f86c, 0x00000afb, 0x0002f86d, 0x00000afc, 0x0002f86e, 0x00000afd, 0x0002f86f, 0x00000afe, 0x0002f870, 0x00000aff, 0x0002f871, 0x00000b00, 0x0002f872, 0x00000b01, 0x0002f873, 0x00000b02, 0x0002f874, 0x00000b03, 0x0002f875, 0x00000b04, 0x0002f876, 0x00000b05, 0x0002f877, 0x00000b06, 0x0002f878, 0x00000b07, 0x0002f879, 0x00000b08, 0x0002f87a, 0x00000b09, 0x0002f87b, 0x00000b0a, 0x0002f87c, 0x00000b0b, 0x0002f87d, 0x00000b0c, 0x0002f87e, 0x00000b0d, 0x0002f87f, 0x00000b0e, 0x0002f880, 0x00000b0f, 0x0002f881, 0x00000b10, 0x0002f882, 0x00000b11, 0x0002f883, 0x00000b12, 0x0002f884, 0x00000b13, 0x0002f885, 0x00000b14, 0x0002f886, 0x00000b15, 0x0002f887, 0x00000b16, 0x0002f888, 0x00000b17, 0x0002f889, 0x00000b18, 0x0002f88a, 0x00000b19, 0x0002f88b, 0x00000b1a, 0x0002f88c, 0x00000b1b, 0x0002f88d, 0x00000b1c, 0x0002f88e, 0x00000b1d, 0x0002f88f, 0x00000b1e, 0x0002f890, 0x00000b1f, 0x0002f891, 0x00000b20, 0x0002f892, 0x00000b21, 0x0002f893, 0x00000b22, 0x0002f894, 0x00000b23, 0x0002f895, 0x00000b24, 0x0002f896, 0x00000b25, 0x0002f897, 0x00000b26, 0x0002f898, 0x00000b27, 0x0002f899, 0x00000b28, 0x0002f89a, 0x00000b29, 0x0002f89b, 0x00000b2a, 0x0002f89c, 0x00000b2b, 0x0002f89d, 0x00000b2c, 0x0002f89e, 0x00000b2d, 0x0002f89f, 0x00000b2e, 0x0002f8a0, 0x00000b2f, 0x0002f8a1, 0x00000b30, 0x0002f8a2, 0x00000b31, 0x0002f8a3, 0x00000b32, 0x0002f8a4, 0x00000b33, 0x0002f8a5, 0x00000b34, 0x0002f8a6, 0x00000b35, 0x0002f8a7, 0x00000b36, 0x0002f8a8, 0x00000b37, 0x0002f8a9, 0x00000b38, 0x0002f8aa, 0x00000b39, 0x0002f8ab, 0x00000b3a, 0x0002f8ac, 0x00000b3b, 0x0002f8ad, 0x00000b3c, 0x0002f8ae, 0x00000b3d, 0x0002f8af, 0x00000b3e, 0x0002f8b0, 0x00000b3f, 0x0002f8b1, 0x00000b40, 0x0002f8b2, 0x00000b41, 0x0002f8b3, 0x00000b42, 0x0002f8b4, 0x00000b43, 0x0002f8b5, 0x00000b44, 0x0002f8b6, 0x00000b45, 0x0002f8b7, 0x00000b46, 0x0002f8b8, 0x00000b47, 0x0002f8b9, 0x00000b48, 0x0002f8ba, 0x00000b49, 0x0002f8bb, 0x00000b4a, 0x0002f8bc, 0x00000b4b, 0x0002f8bd, 0x00000b4c, 0x0002f8be, 0x00000b4d, 0x0002f8bf, 0x00000b4e, 0x0002f8c0, 0x00000b4f, 0x0002f8c1, 0x00000b50, 0x0002f8c2, 0x00000b51, 0x0002f8c3, 0x00000b52, 0x0002f8c4, 0x00000b53, 0x0002f8c5, 0x00000b54, 0x0002f8c6, 0x00000b55, 0x0002f8c7, 0x00000b56, 0x0002f8c8, 0x00000b57, 0x0002f8c9, 0x00000b58, 0x0002f8ca, 0x00000b59, 0x0002f8cb, 0x00000b5a, 0x0002f8cc, 0x00000b5b, 0x0002f8cd, 0x00000b5c, 0x0002f8ce, 0x00000b5d, 0x0002f8cf, 0x00000b5e, 0x0002f8d0, 0x00000b5f, 0x0002f8d1, 0x00000b60, 0x0002f8d2, 0x00000b61, 0x0002f8d3, 0x00000b62, 0x0002f8d4, 0x00000b63, 0x0002f8d5, 0x00000b64, 0x0002f8d6, 0x00000b65, 0x0002f8d7, 0x00000b66, 0x0002f8d8, 0x00000b67, 0x0002f8d9, 0x00000b68, 0x0002f8da, 0x00000b69, 0x0002f8db, 0x00000b6a, 0x0002f8dc, 0x00000b6b, 0x0002f8dd, 0x00000b6c, 0x0002f8de, 0x00000b6d, 0x0002f8df, 0x00000b6e, 0x0002f8e0, 0x00000b6f, 0x0002f8e1, 0x00000b70, 0x0002f8e2, 0x00000b71, 0x0002f8e3, 0x00000b72, 0x0002f8e4, 0x00000b73, 0x0002f8e5, 0x00000b74, 0x0002f8e6, 0x00000b75, 0x0002f8e7, 0x00000b76, 0x0002f8e8, 0x00000b77, 0x0002f8e9, 0x00000b78, 0x0002f8ea, 0x00000b79, 0x0002f8eb, 0x00000b7a, 0x0002f8ec, 0x00000b7b, 0x0002f8ed, 0x00000b7c, 0x0002f8ee, 0x00000b7d, 0x0002f8ef, 0x00000b7e, 0x0002f8f0, 0x00000b7f, 0x0002f8f1, 0x00000b80, 0x0002f8f2, 0x00000b81, 0x0002f8f3, 0x00000b82, 0x0002f8f4, 0x00000b83, 0x0002f8f5, 0x00000b84, 0x0002f8f6, 0x00000b85, 0x0002f8f7, 0x00000b86, 0x0002f8f8, 0x00000b87, 0x0002f8f9, 0x00000b88, 0x0002f8fa, 0x00000b89, 0x0002f8fb, 0x00000b8a, 0x0002f8fc, 0x00000b8b, 0x0002f8fd, 0x00000b8c, 0x0002f8fe, 0x00000b8d, 0x0002f8ff, 0x00000b8e, 0x0002f900, 0x00000b8f, 0x0002f901, 0x00000b90, 0x0002f902, 0x00000b91, 0x0002f903, 0x00000b92, 0x0002f904, 0x00000b93, 0x0002f905, 0x00000b94, 0x0002f906, 0x00000b95, 0x0002f907, 0x00000b96, 0x0002f908, 0x00000b97, 0x0002f909, 0x00000b98, 0x0002f90a, 0x00000b99, 0x0002f90b, 0x00000b9a, 0x0002f90c, 0x00000b9b, 0x0002f90d, 0x00000b9c, 0x0002f90e, 0x00000b9d, 0x0002f90f, 0x00000b9e, 0x0002f910, 0x00000b9f, 0x0002f911, 0x00000ba0, 0x0002f912, 0x00000ba1, 0x0002f913, 0x00000ba2, 0x0002f914, 0x00000ba3, 0x0002f915, 0x00000ba4, 0x0002f916, 0x00000ba5, 0x0002f917, 0x00000ba6, 0x0002f918, 0x00000ba7, 0x0002f919, 0x00000ba8, 0x0002f91a, 0x00000ba9, 0x0002f91b, 0x00000baa, 0x0002f91c, 0x00000bab, 0x0002f91d, 0x00000bac, 0x0002f91e, 0x00000bad, 0x0002f91f, 0x00000bae, 0x0002f920, 0x00000baf, 0x0002f921, 0x00000bb0, 0x0002f922, 0x00000bb1, 0x0002f923, 0x00000bb2, 0x0002f924, 0x00000bb3, 0x0002f925, 0x00000bb4, 0x0002f926, 0x00000bb5, 0x0002f927, 0x00000bb6, 0x0002f928, 0x00000bb7, 0x0002f929, 0x00000bb8, 0x0002f92a, 0x00000bb9, 0x0002f92b, 0x00000bba, 0x0002f92c, 0x00000bbb, 0x0002f92d, 0x00000bbc, 0x0002f92e, 0x00000bbd, 0x0002f92f, 0x00000bbe, 0x0002f930, 0x00000bbf, 0x0002f931, 0x00000bc0, 0x0002f932, 0x00000bc1, 0x0002f933, 0x00000bc2, 0x0002f934, 0x00000bc3, 0x0002f935, 0x00000bc4, 0x0002f936, 0x00000bc5, 0x0002f937, 0x00000bc6, 0x0002f938, 0x00000bc7, 0x0002f939, 0x00000bc8, 0x0002f93a, 0x00000bc9, 0x0002f93b, 0x00000bca, 0x0002f93c, 0x00000bcb, 0x0002f93d, 0x00000bcc, 0x0002f93e, 0x00000bcd, 0x0002f93f, 0x00000bce, 0x0002f940, 0x00000bcf, 0x0002f941, 0x00000bd0, 0x0002f942, 0x00000bd1, 0x0002f943, 0x00000bd2, 0x0002f944, 0x00000bd3, 0x0002f945, 0x00000bd4, 0x0002f946, 0x00000bd5, 0x0002f947, 0x00000bd6, 0x0002f948, 0x00000bd7, 0x0002f949, 0x00000bd8, 0x0002f94a, 0x00000bd9, 0x0002f94b, 0x00000bda, 0x0002f94c, 0x00000bdb, 0x0002f94d, 0x00000bdc, 0x0002f94e, 0x00000bdd, 0x0002f94f, 0x00000bde, 0x0002f950, 0x00000bdf, 0x0002f951, 0x00000be0, 0x0002f952, 0x00000be1, 0x0002f953, 0x00000be2, 0x0002f954, 0x00000be3, 0x0002f955, 0x00000be4, 0x0002f956, 0x00000be5, 0x0002f957, 0x00000be6, 0x0002f958, 0x00000be7, 0x0002f959, 0x00000be8, 0x0002f95a, 0x00000be9, 0x0002f95b, 0x00000bea, 0x0002f95c, 0x00000beb, 0x0002f95d, 0x00000bec, 0x0002f95e, 0x00000bed, 0x0002f95f, 0x00000bee, 0x0002f960, 0x00000bef, 0x0002f961, 0x00000bf0, 0x0002f962, 0x00000bf1, 0x0002f963, 0x00000bf2, 0x0002f964, 0x00000bf3, 0x0002f965, 0x00000bf4, 0x0002f966, 0x00000bf5, 0x0002f967, 0x00000bf6, 0x0002f968, 0x00000bf7, 0x0002f969, 0x00000bf8, 0x0002f96a, 0x00000bf9, 0x0002f96b, 0x00000bfa, 0x0002f96c, 0x00000bfb, 0x0002f96d, 0x00000bfc, 0x0002f96e, 0x00000bfd, 0x0002f96f, 0x00000bfe, 0x0002f970, 0x00000bff, 0x0002f971, 0x00000c00, 0x0002f972, 0x00000c01, 0x0002f973, 0x00000c02, 0x0002f974, 0x00000c03, 0x0002f975, 0x00000c04, 0x0002f976, 0x00000c05, 0x0002f977, 0x00000c06, 0x0002f978, 0x00000c07, 0x0002f979, 0x00000c08, 0x0002f97a, 0x00000c09, 0x0002f97b, 0x00000c0a, 0x0002f97c, 0x00000c0b, 0x0002f97d, 0x00000c0c, 0x0002f97e, 0x00000c0d, 0x0002f97f, 0x00000c0e, 0x0002f980, 0x00000c0f, 0x0002f981, 0x00000c10, 0x0002f982, 0x00000c11, 0x0002f983, 0x00000c12, 0x0002f984, 0x00000c13, 0x0002f985, 0x00000c14, 0x0002f986, 0x00000c15, 0x0002f987, 0x00000c16, 0x0002f988, 0x00000c17, 0x0002f989, 0x00000c18, 0x0002f98a, 0x00000c19, 0x0002f98b, 0x00000c1a, 0x0002f98c, 0x00000c1b, 0x0002f98d, 0x00000c1c, 0x0002f98e, 0x00000c1d, 0x0002f98f, 0x00000c1e, 0x0002f990, 0x00000c1f, 0x0002f991, 0x00000c20, 0x0002f992, 0x00000c21, 0x0002f993, 0x00000c22, 0x0002f994, 0x00000c23, 0x0002f995, 0x00000c24, 0x0002f996, 0x00000c25, 0x0002f997, 0x00000c26, 0x0002f998, 0x00000c27, 0x0002f999, 0x00000c28, 0x0002f99a, 0x00000c29, 0x0002f99b, 0x00000c2a, 0x0002f99c, 0x00000c2b, 0x0002f99d, 0x00000c2c, 0x0002f99e, 0x00000c2d, 0x0002f99f, 0x00000c2e, 0x0002f9a0, 0x00000c2f, 0x0002f9a1, 0x00000c30, 0x0002f9a2, 0x00000c31, 0x0002f9a3, 0x00000c32, 0x0002f9a4, 0x00000c33, 0x0002f9a5, 0x00000c34, 0x0002f9a6, 0x00000c35, 0x0002f9a7, 0x00000c36, 0x0002f9a8, 0x00000c37, 0x0002f9a9, 0x00000c38, 0x0002f9aa, 0x00000c39, 0x0002f9ab, 0x00000c3a, 0x0002f9ac, 0x00000c3b, 0x0002f9ad, 0x00000c3c, 0x0002f9ae, 0x00000c3d, 0x0002f9af, 0x00000c3e, 0x0002f9b0, 0x00000c3f, 0x0002f9b1, 0x00000c40, 0x0002f9b2, 0x00000c41, 0x0002f9b3, 0x00000c42, 0x0002f9b4, 0x00000c43, 0x0002f9b5, 0x00000c44, 0x0002f9b6, 0x00000c45, 0x0002f9b7, 0x00000c46, 0x0002f9b8, 0x00000c47, 0x0002f9b9, 0x00000c48, 0x0002f9ba, 0x00000c49, 0x0002f9bb, 0x00000c4a, 0x0002f9bc, 0x00000c4b, 0x0002f9bd, 0x00000c4c, 0x0002f9be, 0x00000c4d, 0x0002f9bf, 0x00000c4e, 0x0002f9c0, 0x00000c4f, 0x0002f9c1, 0x00000c50, 0x0002f9c2, 0x00000c51, 0x0002f9c3, 0x00000c52, 0x0002f9c4, 0x00000c53, 0x0002f9c5, 0x00000c54, 0x0002f9c6, 0x00000c55, 0x0002f9c7, 0x00000c56, 0x0002f9c8, 0x00000c57, 0x0002f9c9, 0x00000c58, 0x0002f9ca, 0x00000c59, 0x0002f9cb, 0x00000c5a, 0x0002f9cc, 0x00000c5b, 0x0002f9cd, 0x00000c5c, 0x0002f9ce, 0x00000c5d, 0x0002f9cf, 0x00000c5e, 0x0002f9d0, 0x00000c5f, 0x0002f9d1, 0x00000c60, 0x0002f9d2, 0x00000c61, 0x0002f9d3, 0x00000c62, 0x0002f9d4, 0x00000c63, 0x0002f9d5, 0x00000c64, 0x0002f9d6, 0x00000c65, 0x0002f9d7, 0x00000c66, 0x0002f9d8, 0x00000c67, 0x0002f9d9, 0x00000c68, 0x0002f9da, 0x00000c69, 0x0002f9db, 0x00000c6a, 0x0002f9dc, 0x00000c6b, 0x0002f9dd, 0x00000c6c, 0x0002f9de, 0x00000c6d, 0x0002f9df, 0x00000c6e, 0x0002f9e0, 0x00000c6f, 0x0002f9e1, 0x00000c70, 0x0002f9e2, 0x00000c71, 0x0002f9e3, 0x00000c72, 0x0002f9e4, 0x00000c73, 0x0002f9e5, 0x00000c74, 0x0002f9e6, 0x00000c75, 0x0002f9e7, 0x00000c76, 0x0002f9e8, 0x00000c77, 0x0002f9e9, 0x00000c78, 0x0002f9ea, 0x00000c79, 0x0002f9eb, 0x00000c7a, 0x0002f9ec, 0x00000c7b, 0x0002f9ed, 0x00000c7c, 0x0002f9ee, 0x00000c7d, 0x0002f9ef, 0x00000c7e, 0x0002f9f0, 0x00000c7f, 0x0002f9f1, 0x00000c80, 0x0002f9f2, 0x00000c81, 0x0002f9f3, 0x00000c82, 0x0002f9f4, 0x00000c83, 0x0002f9f5, 0x00000c84, 0x0002f9f6, 0x00000c85, 0x0002f9f7, 0x00000c86, 0x0002f9f8, 0x00000c87, 0x0002f9f9, 0x00000c88, 0x0002f9fa, 0x00000c89, 0x0002f9fb, 0x00000c8a, 0x0002f9fc, 0x00000c8b, 0x0002f9fd, 0x00000c8c, 0x0002f9fe, 0x00000c8d, 0x0002f9ff, 0x00000c8e, 0x0002fa00, 0x00000c8f, 0x0002fa01, 0x00000c90, 0x0002fa02, 0x00000c91, 0x0002fa03, 0x00000c92, 0x0002fa04, 0x00000c93, 0x0002fa05, 0x00000c94, 0x0002fa06, 0x00000c95, 0x0002fa07, 0x00000c96, 0x0002fa08, 0x00000c97, 0x0002fa09, 0x00000c98, 0x0002fa0a, 0x00000c99, 0x0002fa0b, 0x00000c9a, 0x0002fa0c, 0x00000c9b, 0x0002fa0d, 0x00000c9c, 0x0002fa0e, 0x00000c9d, 0x0002fa0f, 0x00000c9e, 0x0002fa10, 0x00000c9f, 0x0002fa11, 0x00000ca0, 0x0002fa12, 0x00000ca1, 0x0002fa13, 0x00000ca2, 0x0002fa14, 0x00000ca3, 0x0002fa15, 0x00000ca4, 0x0002fa16, 0x00000ca5, 0x0002fa17, 0x00000ca6, 0x0002fa18, 0x00000ca7, 0x0002fa19, 0x00000ca8, 0x0002fa1a, 0x00000ca9, 0x0002fa1b, 0x00000caa, 0x0002fa1c, 0x00000cab, 0x0002fa1d, 0x00000cac, 0x00000cad }; static const ac_uint4 _ucdcmp_decomp[] = { 0x00000041, 0x00000300, 0x00000041, 0x00000301, 0x00000041, 0x00000302, 0x00000041, 0x00000303, 0x00000041, 0x00000308, 0x00000041, 0x0000030a, 0x00000043, 0x00000327, 0x00000045, 0x00000300, 0x00000045, 0x00000301, 0x00000045, 0x00000302, 0x00000045, 0x00000308, 0x00000049, 0x00000300, 0x00000049, 0x00000301, 0x00000049, 0x00000302, 0x00000049, 0x00000308, 0x0000004e, 0x00000303, 0x0000004f, 0x00000300, 0x0000004f, 0x00000301, 0x0000004f, 0x00000302, 0x0000004f, 0x00000303, 0x0000004f, 0x00000308, 0x00000055, 0x00000300, 0x00000055, 0x00000301, 0x00000055, 0x00000302, 0x00000055, 0x00000308, 0x00000059, 0x00000301, 0x00000061, 0x00000300, 0x00000061, 0x00000301, 0x00000061, 0x00000302, 0x00000061, 0x00000303, 0x00000061, 0x00000308, 0x00000061, 0x0000030a, 0x00000063, 0x00000327, 0x00000065, 0x00000300, 0x00000065, 0x00000301, 0x00000065, 0x00000302, 0x00000065, 0x00000308, 0x00000069, 0x00000300, 0x00000069, 0x00000301, 0x00000069, 0x00000302, 0x00000069, 0x00000308, 0x0000006e, 0x00000303, 0x0000006f, 0x00000300, 0x0000006f, 0x00000301, 0x0000006f, 0x00000302, 0x0000006f, 0x00000303, 0x0000006f, 0x00000308, 0x00000075, 0x00000300, 0x00000075, 0x00000301, 0x00000075, 0x00000302, 0x00000075, 0x00000308, 0x00000079, 0x00000301, 0x00000079, 0x00000308, 0x00000041, 0x00000304, 0x00000061, 0x00000304, 0x00000041, 0x00000306, 0x00000061, 0x00000306, 0x00000041, 0x00000328, 0x00000061, 0x00000328, 0x00000043, 0x00000301, 0x00000063, 0x00000301, 0x00000043, 0x00000302, 0x00000063, 0x00000302, 0x00000043, 0x00000307, 0x00000063, 0x00000307, 0x00000043, 0x0000030c, 0x00000063, 0x0000030c, 0x00000044, 0x0000030c, 0x00000064, 0x0000030c, 0x00000045, 0x00000304, 0x00000065, 0x00000304, 0x00000045, 0x00000306, 0x00000065, 0x00000306, 0x00000045, 0x00000307, 0x00000065, 0x00000307, 0x00000045, 0x00000328, 0x00000065, 0x00000328, 0x00000045, 0x0000030c, 0x00000065, 0x0000030c, 0x00000047, 0x00000302, 0x00000067, 0x00000302, 0x00000047, 0x00000306, 0x00000067, 0x00000306, 0x00000047, 0x00000307, 0x00000067, 0x00000307, 0x00000047, 0x00000327, 0x00000067, 0x00000327, 0x00000048, 0x00000302, 0x00000068, 0x00000302, 0x00000049, 0x00000303, 0x00000069, 0x00000303, 0x00000049, 0x00000304, 0x00000069, 0x00000304, 0x00000049, 0x00000306, 0x00000069, 0x00000306, 0x00000049, 0x00000328, 0x00000069, 0x00000328, 0x00000049, 0x00000307, 0x0000004a, 0x00000302, 0x0000006a, 0x00000302, 0x0000004b, 0x00000327, 0x0000006b, 0x00000327, 0x0000004c, 0x00000301, 0x0000006c, 0x00000301, 0x0000004c, 0x00000327, 0x0000006c, 0x00000327, 0x0000004c, 0x0000030c, 0x0000006c, 0x0000030c, 0x0000004e, 0x00000301, 0x0000006e, 0x00000301, 0x0000004e, 0x00000327, 0x0000006e, 0x00000327, 0x0000004e, 0x0000030c, 0x0000006e, 0x0000030c, 0x0000004f, 0x00000304, 0x0000006f, 0x00000304, 0x0000004f, 0x00000306, 0x0000006f, 0x00000306, 0x0000004f, 0x0000030b, 0x0000006f, 0x0000030b, 0x00000052, 0x00000301, 0x00000072, 0x00000301, 0x00000052, 0x00000327, 0x00000072, 0x00000327, 0x00000052, 0x0000030c, 0x00000072, 0x0000030c, 0x00000053, 0x00000301, 0x00000073, 0x00000301, 0x00000053, 0x00000302, 0x00000073, 0x00000302, 0x00000053, 0x00000327, 0x00000073, 0x00000327, 0x00000053, 0x0000030c, 0x00000073, 0x0000030c, 0x00000054, 0x00000327, 0x00000074, 0x00000327, 0x00000054, 0x0000030c, 0x00000074, 0x0000030c, 0x00000055, 0x00000303, 0x00000075, 0x00000303, 0x00000055, 0x00000304, 0x00000075, 0x00000304, 0x00000055, 0x00000306, 0x00000075, 0x00000306, 0x00000055, 0x0000030a, 0x00000075, 0x0000030a, 0x00000055, 0x0000030b, 0x00000075, 0x0000030b, 0x00000055, 0x00000328, 0x00000075, 0x00000328, 0x00000057, 0x00000302, 0x00000077, 0x00000302, 0x00000059, 0x00000302, 0x00000079, 0x00000302, 0x00000059, 0x00000308, 0x0000005a, 0x00000301, 0x0000007a, 0x00000301, 0x0000005a, 0x00000307, 0x0000007a, 0x00000307, 0x0000005a, 0x0000030c, 0x0000007a, 0x0000030c, 0x0000004f, 0x0000031b, 0x0000006f, 0x0000031b, 0x00000055, 0x0000031b, 0x00000075, 0x0000031b, 0x00000041, 0x0000030c, 0x00000061, 0x0000030c, 0x00000049, 0x0000030c, 0x00000069, 0x0000030c, 0x0000004f, 0x0000030c, 0x0000006f, 0x0000030c, 0x00000055, 0x0000030c, 0x00000075, 0x0000030c, 0x00000055, 0x00000308, 0x00000304, 0x00000075, 0x00000308, 0x00000304, 0x00000055, 0x00000308, 0x00000301, 0x00000075, 0x00000308, 0x00000301, 0x00000055, 0x00000308, 0x0000030c, 0x00000075, 0x00000308, 0x0000030c, 0x00000055, 0x00000308, 0x00000300, 0x00000075, 0x00000308, 0x00000300, 0x00000041, 0x00000308, 0x00000304, 0x00000061, 0x00000308, 0x00000304, 0x00000041, 0x00000307, 0x00000304, 0x00000061, 0x00000307, 0x00000304, 0x000000c6, 0x00000304, 0x000000e6, 0x00000304, 0x00000047, 0x0000030c, 0x00000067, 0x0000030c, 0x0000004b, 0x0000030c, 0x0000006b, 0x0000030c, 0x0000004f, 0x00000328, 0x0000006f, 0x00000328, 0x0000004f, 0x00000328, 0x00000304, 0x0000006f, 0x00000328, 0x00000304, 0x000001b7, 0x0000030c, 0x00000292, 0x0000030c, 0x0000006a, 0x0000030c, 0x00000047, 0x00000301, 0x00000067, 0x00000301, 0x0000004e, 0x00000300, 0x0000006e, 0x00000300, 0x00000041, 0x0000030a, 0x00000301, 0x00000061, 0x0000030a, 0x00000301, 0x000000c6, 0x00000301, 0x000000e6, 0x00000301, 0x000000d8, 0x00000301, 0x000000f8, 0x00000301, 0x00000041, 0x0000030f, 0x00000061, 0x0000030f, 0x00000041, 0x00000311, 0x00000061, 0x00000311, 0x00000045, 0x0000030f, 0x00000065, 0x0000030f, 0x00000045, 0x00000311, 0x00000065, 0x00000311, 0x00000049, 0x0000030f, 0x00000069, 0x0000030f, 0x00000049, 0x00000311, 0x00000069, 0x00000311, 0x0000004f, 0x0000030f, 0x0000006f, 0x0000030f, 0x0000004f, 0x00000311, 0x0000006f, 0x00000311, 0x00000052, 0x0000030f, 0x00000072, 0x0000030f, 0x00000052, 0x00000311, 0x00000072, 0x00000311, 0x00000055, 0x0000030f, 0x00000075, 0x0000030f, 0x00000055, 0x00000311, 0x00000075, 0x00000311, 0x00000053, 0x00000326, 0x00000073, 0x00000326, 0x00000054, 0x00000326, 0x00000074, 0x00000326, 0x00000048, 0x0000030c, 0x00000068, 0x0000030c, 0x00000041, 0x00000307, 0x00000061, 0x00000307, 0x00000045, 0x00000327, 0x00000065, 0x00000327, 0x0000004f, 0x00000308, 0x00000304, 0x0000006f, 0x00000308, 0x00000304, 0x0000004f, 0x00000303, 0x00000304, 0x0000006f, 0x00000303, 0x00000304, 0x0000004f, 0x00000307, 0x0000006f, 0x00000307, 0x0000004f, 0x00000307, 0x00000304, 0x0000006f, 0x00000307, 0x00000304, 0x00000059, 0x00000304, 0x00000079, 0x00000304, 0x00000300, 0x00000301, 0x00000313, 0x00000308, 0x00000301, 0x000002b9, 0x0000003b, 0x000000a8, 0x00000301, 0x00000391, 0x00000301, 0x000000b7, 0x00000395, 0x00000301, 0x00000397, 0x00000301, 0x00000399, 0x00000301, 0x0000039f, 0x00000301, 0x000003a5, 0x00000301, 0x000003a9, 0x00000301, 0x000003b9, 0x00000308, 0x00000301, 0x00000399, 0x00000308, 0x000003a5, 0x00000308, 0x000003b1, 0x00000301, 0x000003b5, 0x00000301, 0x000003b7, 0x00000301, 0x000003b9, 0x00000301, 0x000003c5, 0x00000308, 0x00000301, 0x000003b9, 0x00000308, 0x000003c5, 0x00000308, 0x000003bf, 0x00000301, 0x000003c5, 0x00000301, 0x000003c9, 0x00000301, 0x000003d2, 0x00000301, 0x000003d2, 0x00000308, 0x00000415, 0x00000300, 0x00000415, 0x00000308, 0x00000413, 0x00000301, 0x00000406, 0x00000308, 0x0000041a, 0x00000301, 0x00000418, 0x00000300, 0x00000423, 0x00000306, 0x00000418, 0x00000306, 0x00000438, 0x00000306, 0x00000435, 0x00000300, 0x00000435, 0x00000308, 0x00000433, 0x00000301, 0x00000456, 0x00000308, 0x0000043a, 0x00000301, 0x00000438, 0x00000300, 0x00000443, 0x00000306, 0x00000474, 0x0000030f, 0x00000475, 0x0000030f, 0x00000416, 0x00000306, 0x00000436, 0x00000306, 0x00000410, 0x00000306, 0x00000430, 0x00000306, 0x00000410, 0x00000308, 0x00000430, 0x00000308, 0x00000415, 0x00000306, 0x00000435, 0x00000306, 0x000004d8, 0x00000308, 0x000004d9, 0x00000308, 0x00000416, 0x00000308, 0x00000436, 0x00000308, 0x00000417, 0x00000308, 0x00000437, 0x00000308, 0x00000418, 0x00000304, 0x00000438, 0x00000304, 0x00000418, 0x00000308, 0x00000438, 0x00000308, 0x0000041e, 0x00000308, 0x0000043e, 0x00000308, 0x000004e8, 0x00000308, 0x000004e9, 0x00000308, 0x0000042d, 0x00000308, 0x0000044d, 0x00000308, 0x00000423, 0x00000304, 0x00000443, 0x00000304, 0x00000423, 0x00000308, 0x00000443, 0x00000308, 0x00000423, 0x0000030b, 0x00000443, 0x0000030b, 0x00000427, 0x00000308, 0x00000447, 0x00000308, 0x0000042b, 0x00000308, 0x0000044b, 0x00000308, 0x00000627, 0x00000653, 0x00000627, 0x00000654, 0x00000648, 0x00000654, 0x00000627, 0x00000655, 0x0000064a, 0x00000654, 0x000006d5, 0x00000654, 0x000006c1, 0x00000654, 0x000006d2, 0x00000654, 0x00000928, 0x0000093c, 0x00000930, 0x0000093c, 0x00000933, 0x0000093c, 0x00000915, 0x0000093c, 0x00000916, 0x0000093c, 0x00000917, 0x0000093c, 0x0000091c, 0x0000093c, 0x00000921, 0x0000093c, 0x00000922, 0x0000093c, 0x0000092b, 0x0000093c, 0x0000092f, 0x0000093c, 0x000009c7, 0x000009be, 0x000009c7, 0x000009d7, 0x000009a1, 0x000009bc, 0x000009a2, 0x000009bc, 0x000009af, 0x000009bc, 0x00000a32, 0x00000a3c, 0x00000a38, 0x00000a3c, 0x00000a16, 0x00000a3c, 0x00000a17, 0x00000a3c, 0x00000a1c, 0x00000a3c, 0x00000a2b, 0x00000a3c, 0x00000b47, 0x00000b56, 0x00000b47, 0x00000b3e, 0x00000b47, 0x00000b57, 0x00000b21, 0x00000b3c, 0x00000b22, 0x00000b3c, 0x00000b92, 0x00000bd7, 0x00000bc6, 0x00000bbe, 0x00000bc7, 0x00000bbe, 0x00000bc6, 0x00000bd7, 0x00000c46, 0x00000c56, 0x00000cbf, 0x00000cd5, 0x00000cc6, 0x00000cd5, 0x00000cc6, 0x00000cd6, 0x00000cc6, 0x00000cc2, 0x00000cc6, 0x00000cc2, 0x00000cd5, 0x00000d46, 0x00000d3e, 0x00000d47, 0x00000d3e, 0x00000d46, 0x00000d57, 0x00000dd9, 0x00000dca, 0x00000dd9, 0x00000dcf, 0x00000dd9, 0x00000dcf, 0x00000dca, 0x00000dd9, 0x00000ddf, 0x00000f42, 0x00000fb7, 0x00000f4c, 0x00000fb7, 0x00000f51, 0x00000fb7, 0x00000f56, 0x00000fb7, 0x00000f5b, 0x00000fb7, 0x00000f40, 0x00000fb5, 0x00000f71, 0x00000f72, 0x00000f71, 0x00000f74, 0x00000fb2, 0x00000f80, 0x00000fb3, 0x00000f80, 0x00000f71, 0x00000f80, 0x00000f92, 0x00000fb7, 0x00000f9c, 0x00000fb7, 0x00000fa1, 0x00000fb7, 0x00000fa6, 0x00000fb7, 0x00000fab, 0x00000fb7, 0x00000f90, 0x00000fb5, 0x00001025, 0x0000102e, 0x00000041, 0x00000325, 0x00000061, 0x00000325, 0x00000042, 0x00000307, 0x00000062, 0x00000307, 0x00000042, 0x00000323, 0x00000062, 0x00000323, 0x00000042, 0x00000331, 0x00000062, 0x00000331, 0x00000043, 0x00000327, 0x00000301, 0x00000063, 0x00000327, 0x00000301, 0x00000044, 0x00000307, 0x00000064, 0x00000307, 0x00000044, 0x00000323, 0x00000064, 0x00000323, 0x00000044, 0x00000331, 0x00000064, 0x00000331, 0x00000044, 0x00000327, 0x00000064, 0x00000327, 0x00000044, 0x0000032d, 0x00000064, 0x0000032d, 0x00000045, 0x00000304, 0x00000300, 0x00000065, 0x00000304, 0x00000300, 0x00000045, 0x00000304, 0x00000301, 0x00000065, 0x00000304, 0x00000301, 0x00000045, 0x0000032d, 0x00000065, 0x0000032d, 0x00000045, 0x00000330, 0x00000065, 0x00000330, 0x00000045, 0x00000327, 0x00000306, 0x00000065, 0x00000327, 0x00000306, 0x00000046, 0x00000307, 0x00000066, 0x00000307, 0x00000047, 0x00000304, 0x00000067, 0x00000304, 0x00000048, 0x00000307, 0x00000068, 0x00000307, 0x00000048, 0x00000323, 0x00000068, 0x00000323, 0x00000048, 0x00000308, 0x00000068, 0x00000308, 0x00000048, 0x00000327, 0x00000068, 0x00000327, 0x00000048, 0x0000032e, 0x00000068, 0x0000032e, 0x00000049, 0x00000330, 0x00000069, 0x00000330, 0x00000049, 0x00000308, 0x00000301, 0x00000069, 0x00000308, 0x00000301, 0x0000004b, 0x00000301, 0x0000006b, 0x00000301, 0x0000004b, 0x00000323, 0x0000006b, 0x00000323, 0x0000004b, 0x00000331, 0x0000006b, 0x00000331, 0x0000004c, 0x00000323, 0x0000006c, 0x00000323, 0x0000004c, 0x00000323, 0x00000304, 0x0000006c, 0x00000323, 0x00000304, 0x0000004c, 0x00000331, 0x0000006c, 0x00000331, 0x0000004c, 0x0000032d, 0x0000006c, 0x0000032d, 0x0000004d, 0x00000301, 0x0000006d, 0x00000301, 0x0000004d, 0x00000307, 0x0000006d, 0x00000307, 0x0000004d, 0x00000323, 0x0000006d, 0x00000323, 0x0000004e, 0x00000307, 0x0000006e, 0x00000307, 0x0000004e, 0x00000323, 0x0000006e, 0x00000323, 0x0000004e, 0x00000331, 0x0000006e, 0x00000331, 0x0000004e, 0x0000032d, 0x0000006e, 0x0000032d, 0x0000004f, 0x00000303, 0x00000301, 0x0000006f, 0x00000303, 0x00000301, 0x0000004f, 0x00000303, 0x00000308, 0x0000006f, 0x00000303, 0x00000308, 0x0000004f, 0x00000304, 0x00000300, 0x0000006f, 0x00000304, 0x00000300, 0x0000004f, 0x00000304, 0x00000301, 0x0000006f, 0x00000304, 0x00000301, 0x00000050, 0x00000301, 0x00000070, 0x00000301, 0x00000050, 0x00000307, 0x00000070, 0x00000307, 0x00000052, 0x00000307, 0x00000072, 0x00000307, 0x00000052, 0x00000323, 0x00000072, 0x00000323, 0x00000052, 0x00000323, 0x00000304, 0x00000072, 0x00000323, 0x00000304, 0x00000052, 0x00000331, 0x00000072, 0x00000331, 0x00000053, 0x00000307, 0x00000073, 0x00000307, 0x00000053, 0x00000323, 0x00000073, 0x00000323, 0x00000053, 0x00000301, 0x00000307, 0x00000073, 0x00000301, 0x00000307, 0x00000053, 0x0000030c, 0x00000307, 0x00000073, 0x0000030c, 0x00000307, 0x00000053, 0x00000323, 0x00000307, 0x00000073, 0x00000323, 0x00000307, 0x00000054, 0x00000307, 0x00000074, 0x00000307, 0x00000054, 0x00000323, 0x00000074, 0x00000323, 0x00000054, 0x00000331, 0x00000074, 0x00000331, 0x00000054, 0x0000032d, 0x00000074, 0x0000032d, 0x00000055, 0x00000324, 0x00000075, 0x00000324, 0x00000055, 0x00000330, 0x00000075, 0x00000330, 0x00000055, 0x0000032d, 0x00000075, 0x0000032d, 0x00000055, 0x00000303, 0x00000301, 0x00000075, 0x00000303, 0x00000301, 0x00000055, 0x00000304, 0x00000308, 0x00000075, 0x00000304, 0x00000308, 0x00000056, 0x00000303, 0x00000076, 0x00000303, 0x00000056, 0x00000323, 0x00000076, 0x00000323, 0x00000057, 0x00000300, 0x00000077, 0x00000300, 0x00000057, 0x00000301, 0x00000077, 0x00000301, 0x00000057, 0x00000308, 0x00000077, 0x00000308, 0x00000057, 0x00000307, 0x00000077, 0x00000307, 0x00000057, 0x00000323, 0x00000077, 0x00000323, 0x00000058, 0x00000307, 0x00000078, 0x00000307, 0x00000058, 0x00000308, 0x00000078, 0x00000308, 0x00000059, 0x00000307, 0x00000079, 0x00000307, 0x0000005a, 0x00000302, 0x0000007a, 0x00000302, 0x0000005a, 0x00000323, 0x0000007a, 0x00000323, 0x0000005a, 0x00000331, 0x0000007a, 0x00000331, 0x00000068, 0x00000331, 0x00000074, 0x00000308, 0x00000077, 0x0000030a, 0x00000079, 0x0000030a, 0x0000017f, 0x00000307, 0x00000041, 0x00000323, 0x00000061, 0x00000323, 0x00000041, 0x00000309, 0x00000061, 0x00000309, 0x00000041, 0x00000302, 0x00000301, 0x00000061, 0x00000302, 0x00000301, 0x00000041, 0x00000302, 0x00000300, 0x00000061, 0x00000302, 0x00000300, 0x00000041, 0x00000302, 0x00000309, 0x00000061, 0x00000302, 0x00000309, 0x00000041, 0x00000302, 0x00000303, 0x00000061, 0x00000302, 0x00000303, 0x00000041, 0x00000323, 0x00000302, 0x00000061, 0x00000323, 0x00000302, 0x00000041, 0x00000306, 0x00000301, 0x00000061, 0x00000306, 0x00000301, 0x00000041, 0x00000306, 0x00000300, 0x00000061, 0x00000306, 0x00000300, 0x00000041, 0x00000306, 0x00000309, 0x00000061, 0x00000306, 0x00000309, 0x00000041, 0x00000306, 0x00000303, 0x00000061, 0x00000306, 0x00000303, 0x00000041, 0x00000323, 0x00000306, 0x00000061, 0x00000323, 0x00000306, 0x00000045, 0x00000323, 0x00000065, 0x00000323, 0x00000045, 0x00000309, 0x00000065, 0x00000309, 0x00000045, 0x00000303, 0x00000065, 0x00000303, 0x00000045, 0x00000302, 0x00000301, 0x00000065, 0x00000302, 0x00000301, 0x00000045, 0x00000302, 0x00000300, 0x00000065, 0x00000302, 0x00000300, 0x00000045, 0x00000302, 0x00000309, 0x00000065, 0x00000302, 0x00000309, 0x00000045, 0x00000302, 0x00000303, 0x00000065, 0x00000302, 0x00000303, 0x00000045, 0x00000323, 0x00000302, 0x00000065, 0x00000323, 0x00000302, 0x00000049, 0x00000309, 0x00000069, 0x00000309, 0x00000049, 0x00000323, 0x00000069, 0x00000323, 0x0000004f, 0x00000323, 0x0000006f, 0x00000323, 0x0000004f, 0x00000309, 0x0000006f, 0x00000309, 0x0000004f, 0x00000302, 0x00000301, 0x0000006f, 0x00000302, 0x00000301, 0x0000004f, 0x00000302, 0x00000300, 0x0000006f, 0x00000302, 0x00000300, 0x0000004f, 0x00000302, 0x00000309, 0x0000006f, 0x00000302, 0x00000309, 0x0000004f, 0x00000302, 0x00000303, 0x0000006f, 0x00000302, 0x00000303, 0x0000004f, 0x00000323, 0x00000302, 0x0000006f, 0x00000323, 0x00000302, 0x0000004f, 0x0000031b, 0x00000301, 0x0000006f, 0x0000031b, 0x00000301, 0x0000004f, 0x0000031b, 0x00000300, 0x0000006f, 0x0000031b, 0x00000300, 0x0000004f, 0x0000031b, 0x00000309, 0x0000006f, 0x0000031b, 0x00000309, 0x0000004f, 0x0000031b, 0x00000303, 0x0000006f, 0x0000031b, 0x00000303, 0x0000004f, 0x0000031b, 0x00000323, 0x0000006f, 0x0000031b, 0x00000323, 0x00000055, 0x00000323, 0x00000075, 0x00000323, 0x00000055, 0x00000309, 0x00000075, 0x00000309, 0x00000055, 0x0000031b, 0x00000301, 0x00000075, 0x0000031b, 0x00000301, 0x00000055, 0x0000031b, 0x00000300, 0x00000075, 0x0000031b, 0x00000300, 0x00000055, 0x0000031b, 0x00000309, 0x00000075, 0x0000031b, 0x00000309, 0x00000055, 0x0000031b, 0x00000303, 0x00000075, 0x0000031b, 0x00000303, 0x00000055, 0x0000031b, 0x00000323, 0x00000075, 0x0000031b, 0x00000323, 0x00000059, 0x00000300, 0x00000079, 0x00000300, 0x00000059, 0x00000323, 0x00000079, 0x00000323, 0x00000059, 0x00000309, 0x00000079, 0x00000309, 0x00000059, 0x00000303, 0x00000079, 0x00000303, 0x000003b1, 0x00000313, 0x000003b1, 0x00000314, 0x000003b1, 0x00000313, 0x00000300, 0x000003b1, 0x00000314, 0x00000300, 0x000003b1, 0x00000313, 0x00000301, 0x000003b1, 0x00000314, 0x00000301, 0x000003b1, 0x00000313, 0x00000342, 0x000003b1, 0x00000314, 0x00000342, 0x00000391, 0x00000313, 0x00000391, 0x00000314, 0x00000391, 0x00000313, 0x00000300, 0x00000391, 0x00000314, 0x00000300, 0x00000391, 0x00000313, 0x00000301, 0x00000391, 0x00000314, 0x00000301, 0x00000391, 0x00000313, 0x00000342, 0x00000391, 0x00000314, 0x00000342, 0x000003b5, 0x00000313, 0x000003b5, 0x00000314, 0x000003b5, 0x00000313, 0x00000300, 0x000003b5, 0x00000314, 0x00000300, 0x000003b5, 0x00000313, 0x00000301, 0x000003b5, 0x00000314, 0x00000301, 0x00000395, 0x00000313, 0x00000395, 0x00000314, 0x00000395, 0x00000313, 0x00000300, 0x00000395, 0x00000314, 0x00000300, 0x00000395, 0x00000313, 0x00000301, 0x00000395, 0x00000314, 0x00000301, 0x000003b7, 0x00000313, 0x000003b7, 0x00000314, 0x000003b7, 0x00000313, 0x00000300, 0x000003b7, 0x00000314, 0x00000300, 0x000003b7, 0x00000313, 0x00000301, 0x000003b7, 0x00000314, 0x00000301, 0x000003b7, 0x00000313, 0x00000342, 0x000003b7, 0x00000314, 0x00000342, 0x00000397, 0x00000313, 0x00000397, 0x00000314, 0x00000397, 0x00000313, 0x00000300, 0x00000397, 0x00000314, 0x00000300, 0x00000397, 0x00000313, 0x00000301, 0x00000397, 0x00000314, 0x00000301, 0x00000397, 0x00000313, 0x00000342, 0x00000397, 0x00000314, 0x00000342, 0x000003b9, 0x00000313, 0x000003b9, 0x00000314, 0x000003b9, 0x00000313, 0x00000300, 0x000003b9, 0x00000314, 0x00000300, 0x000003b9, 0x00000313, 0x00000301, 0x000003b9, 0x00000314, 0x00000301, 0x000003b9, 0x00000313, 0x00000342, 0x000003b9, 0x00000314, 0x00000342, 0x00000399, 0x00000313, 0x00000399, 0x00000314, 0x00000399, 0x00000313, 0x00000300, 0x00000399, 0x00000314, 0x00000300, 0x00000399, 0x00000313, 0x00000301, 0x00000399, 0x00000314, 0x00000301, 0x00000399, 0x00000313, 0x00000342, 0x00000399, 0x00000314, 0x00000342, 0x000003bf, 0x00000313, 0x000003bf, 0x00000314, 0x000003bf, 0x00000313, 0x00000300, 0x000003bf, 0x00000314, 0x00000300, 0x000003bf, 0x00000313, 0x00000301, 0x000003bf, 0x00000314, 0x00000301, 0x0000039f, 0x00000313, 0x0000039f, 0x00000314, 0x0000039f, 0x00000313, 0x00000300, 0x0000039f, 0x00000314, 0x00000300, 0x0000039f, 0x00000313, 0x00000301, 0x0000039f, 0x00000314, 0x00000301, 0x000003c5, 0x00000313, 0x000003c5, 0x00000314, 0x000003c5, 0x00000313, 0x00000300, 0x000003c5, 0x00000314, 0x00000300, 0x000003c5, 0x00000313, 0x00000301, 0x000003c5, 0x00000314, 0x00000301, 0x000003c5, 0x00000313, 0x00000342, 0x000003c5, 0x00000314, 0x00000342, 0x000003a5, 0x00000314, 0x000003a5, 0x00000314, 0x00000300, 0x000003a5, 0x00000314, 0x00000301, 0x000003a5, 0x00000314, 0x00000342, 0x000003c9, 0x00000313, 0x000003c9, 0x00000314, 0x000003c9, 0x00000313, 0x00000300, 0x000003c9, 0x00000314, 0x00000300, 0x000003c9, 0x00000313, 0x00000301, 0x000003c9, 0x00000314, 0x00000301, 0x000003c9, 0x00000313, 0x00000342, 0x000003c9, 0x00000314, 0x00000342, 0x000003a9, 0x00000313, 0x000003a9, 0x00000314, 0x000003a9, 0x00000313, 0x00000300, 0x000003a9, 0x00000314, 0x00000300, 0x000003a9, 0x00000313, 0x00000301, 0x000003a9, 0x00000314, 0x00000301, 0x000003a9, 0x00000313, 0x00000342, 0x000003a9, 0x00000314, 0x00000342, 0x000003b1, 0x00000300, 0x000003b1, 0x00000301, 0x000003b5, 0x00000300, 0x000003b5, 0x00000301, 0x000003b7, 0x00000300, 0x000003b7, 0x00000301, 0x000003b9, 0x00000300, 0x000003b9, 0x00000301, 0x000003bf, 0x00000300, 0x000003bf, 0x00000301, 0x000003c5, 0x00000300, 0x000003c5, 0x00000301, 0x000003c9, 0x00000300, 0x000003c9, 0x00000301, 0x000003b1, 0x00000313, 0x00000345, 0x000003b1, 0x00000314, 0x00000345, 0x000003b1, 0x00000313, 0x00000300, 0x00000345, 0x000003b1, 0x00000314, 0x00000300, 0x00000345, 0x000003b1, 0x00000313, 0x00000301, 0x00000345, 0x000003b1, 0x00000314, 0x00000301, 0x00000345, 0x000003b1, 0x00000313, 0x00000342, 0x00000345, 0x000003b1, 0x00000314, 0x00000342, 0x00000345, 0x00000391, 0x00000313, 0x00000345, 0x00000391, 0x00000314, 0x00000345, 0x00000391, 0x00000313, 0x00000300, 0x00000345, 0x00000391, 0x00000314, 0x00000300, 0x00000345, 0x00000391, 0x00000313, 0x00000301, 0x00000345, 0x00000391, 0x00000314, 0x00000301, 0x00000345, 0x00000391, 0x00000313, 0x00000342, 0x00000345, 0x00000391, 0x00000314, 0x00000342, 0x00000345, 0x000003b7, 0x00000313, 0x00000345, 0x000003b7, 0x00000314, 0x00000345, 0x000003b7, 0x00000313, 0x00000300, 0x00000345, 0x000003b7, 0x00000314, 0x00000300, 0x00000345, 0x000003b7, 0x00000313, 0x00000301, 0x00000345, 0x000003b7, 0x00000314, 0x00000301, 0x00000345, 0x000003b7, 0x00000313, 0x00000342, 0x00000345, 0x000003b7, 0x00000314, 0x00000342, 0x00000345, 0x00000397, 0x00000313, 0x00000345, 0x00000397, 0x00000314, 0x00000345, 0x00000397, 0x00000313, 0x00000300, 0x00000345, 0x00000397, 0x00000314, 0x00000300, 0x00000345, 0x00000397, 0x00000313, 0x00000301, 0x00000345, 0x00000397, 0x00000314, 0x00000301, 0x00000345, 0x00000397, 0x00000313, 0x00000342, 0x00000345, 0x00000397, 0x00000314, 0x00000342, 0x00000345, 0x000003c9, 0x00000313, 0x00000345, 0x000003c9, 0x00000314, 0x00000345, 0x000003c9, 0x00000313, 0x00000300, 0x00000345, 0x000003c9, 0x00000314, 0x00000300, 0x00000345, 0x000003c9, 0x00000313, 0x00000301, 0x00000345, 0x000003c9, 0x00000314, 0x00000301, 0x00000345, 0x000003c9, 0x00000313, 0x00000342, 0x00000345, 0x000003c9, 0x00000314, 0x00000342, 0x00000345, 0x000003a9, 0x00000313, 0x00000345, 0x000003a9, 0x00000314, 0x00000345, 0x000003a9, 0x00000313, 0x00000300, 0x00000345, 0x000003a9, 0x00000314, 0x00000300, 0x00000345, 0x000003a9, 0x00000313, 0x00000301, 0x00000345, 0x000003a9, 0x00000314, 0x00000301, 0x00000345, 0x000003a9, 0x00000313, 0x00000342, 0x00000345, 0x000003a9, 0x00000314, 0x00000342, 0x00000345, 0x000003b1, 0x00000306, 0x000003b1, 0x00000304, 0x000003b1, 0x00000300, 0x00000345, 0x000003b1, 0x00000345, 0x000003b1, 0x00000301, 0x00000345, 0x000003b1, 0x00000342, 0x000003b1, 0x00000342, 0x00000345, 0x00000391, 0x00000306, 0x00000391, 0x00000304, 0x00000391, 0x00000300, 0x00000391, 0x00000301, 0x00000391, 0x00000345, 0x000003b9, 0x000000a8, 0x00000342, 0x000003b7, 0x00000300, 0x00000345, 0x000003b7, 0x00000345, 0x000003b7, 0x00000301, 0x00000345, 0x000003b7, 0x00000342, 0x000003b7, 0x00000342, 0x00000345, 0x00000395, 0x00000300, 0x00000395, 0x00000301, 0x00000397, 0x00000300, 0x00000397, 0x00000301, 0x00000397, 0x00000345, 0x00001fbf, 0x00000300, 0x00001fbf, 0x00000301, 0x00001fbf, 0x00000342, 0x000003b9, 0x00000306, 0x000003b9, 0x00000304, 0x000003b9, 0x00000308, 0x00000300, 0x000003b9, 0x00000308, 0x00000301, 0x000003b9, 0x00000342, 0x000003b9, 0x00000308, 0x00000342, 0x00000399, 0x00000306, 0x00000399, 0x00000304, 0x00000399, 0x00000300, 0x00000399, 0x00000301, 0x00001ffe, 0x00000300, 0x00001ffe, 0x00000301, 0x00001ffe, 0x00000342, 0x000003c5, 0x00000306, 0x000003c5, 0x00000304, 0x000003c5, 0x00000308, 0x00000300, 0x000003c5, 0x00000308, 0x00000301, 0x000003c1, 0x00000313, 0x000003c1, 0x00000314, 0x000003c5, 0x00000342, 0x000003c5, 0x00000308, 0x00000342, 0x000003a5, 0x00000306, 0x000003a5, 0x00000304, 0x000003a5, 0x00000300, 0x000003a5, 0x00000301, 0x000003a1, 0x00000314, 0x000000a8, 0x00000300, 0x000000a8, 0x00000301, 0x00000060, 0x000003c9, 0x00000300, 0x00000345, 0x000003c9, 0x00000345, 0x000003c9, 0x00000301, 0x00000345, 0x000003c9, 0x00000342, 0x000003c9, 0x00000342, 0x00000345, 0x0000039f, 0x00000300, 0x0000039f, 0x00000301, 0x000003a9, 0x00000300, 0x000003a9, 0x00000301, 0x000003a9, 0x00000345, 0x000000b4, 0x00002002, 0x00002003, 0x000003a9, 0x0000004b, 0x00000041, 0x0000030a, 0x00002190, 0x00000338, 0x00002192, 0x00000338, 0x00002194, 0x00000338, 0x000021d0, 0x00000338, 0x000021d4, 0x00000338, 0x000021d2, 0x00000338, 0x00002203, 0x00000338, 0x00002208, 0x00000338, 0x0000220b, 0x00000338, 0x00002223, 0x00000338, 0x00002225, 0x00000338, 0x0000223c, 0x00000338, 0x00002243, 0x00000338, 0x00002245, 0x00000338, 0x00002248, 0x00000338, 0x0000003d, 0x00000338, 0x00002261, 0x00000338, 0x0000224d, 0x00000338, 0x0000003c, 0x00000338, 0x0000003e, 0x00000338, 0x00002264, 0x00000338, 0x00002265, 0x00000338, 0x00002272, 0x00000338, 0x00002273, 0x00000338, 0x00002276, 0x00000338, 0x00002277, 0x00000338, 0x0000227a, 0x00000338, 0x0000227b, 0x00000338, 0x00002282, 0x00000338, 0x00002283, 0x00000338, 0x00002286, 0x00000338, 0x00002287, 0x00000338, 0x000022a2, 0x00000338, 0x000022a8, 0x00000338, 0x000022a9, 0x00000338, 0x000022ab, 0x00000338, 0x0000227c, 0x00000338, 0x0000227d, 0x00000338, 0x00002291, 0x00000338, 0x00002292, 0x00000338, 0x000022b2, 0x00000338, 0x000022b3, 0x00000338, 0x000022b4, 0x00000338, 0x000022b5, 0x00000338, 0x00003008, 0x00003009, 0x00002add, 0x00000338, 0x0000304b, 0x00003099, 0x0000304d, 0x00003099, 0x0000304f, 0x00003099, 0x00003051, 0x00003099, 0x00003053, 0x00003099, 0x00003055, 0x00003099, 0x00003057, 0x00003099, 0x00003059, 0x00003099, 0x0000305b, 0x00003099, 0x0000305d, 0x00003099, 0x0000305f, 0x00003099, 0x00003061, 0x00003099, 0x00003064, 0x00003099, 0x00003066, 0x00003099, 0x00003068, 0x00003099, 0x0000306f, 0x00003099, 0x0000306f, 0x0000309a, 0x00003072, 0x00003099, 0x00003072, 0x0000309a, 0x00003075, 0x00003099, 0x00003075, 0x0000309a, 0x00003078, 0x00003099, 0x00003078, 0x0000309a, 0x0000307b, 0x00003099, 0x0000307b, 0x0000309a, 0x00003046, 0x00003099, 0x0000309d, 0x00003099, 0x000030ab, 0x00003099, 0x000030ad, 0x00003099, 0x000030af, 0x00003099, 0x000030b1, 0x00003099, 0x000030b3, 0x00003099, 0x000030b5, 0x00003099, 0x000030b7, 0x00003099, 0x000030b9, 0x00003099, 0x000030bb, 0x00003099, 0x000030bd, 0x00003099, 0x000030bf, 0x00003099, 0x000030c1, 0x00003099, 0x000030c4, 0x00003099, 0x000030c6, 0x00003099, 0x000030c8, 0x00003099, 0x000030cf, 0x00003099, 0x000030cf, 0x0000309a, 0x000030d2, 0x00003099, 0x000030d2, 0x0000309a, 0x000030d5, 0x00003099, 0x000030d5, 0x0000309a, 0x000030d8, 0x00003099, 0x000030d8, 0x0000309a, 0x000030db, 0x00003099, 0x000030db, 0x0000309a, 0x000030a6, 0x00003099, 0x000030ef, 0x00003099, 0x000030f0, 0x00003099, 0x000030f1, 0x00003099, 0x000030f2, 0x00003099, 0x000030fd, 0x00003099, 0x00008eca, 0x00008cc8, 0x00006ed1, 0x00004e32, 0x000053e5, 0x00009f9c, 0x00009f9c, 0x00005951, 0x000091d1, 0x00005587, 0x00005948, 0x000061f6, 0x00007669, 0x00007f85, 0x0000863f, 0x000087ba, 0x000088f8, 0x0000908f, 0x00006a02, 0x00006d1b, 0x000070d9, 0x000073de, 0x0000843d, 0x0000916a, 0x000099f1, 0x00004e82, 0x00005375, 0x00006b04, 0x0000721b, 0x0000862d, 0x00009e1e, 0x00005d50, 0x00006feb, 0x000085cd, 0x00008964, 0x000062c9, 0x000081d8, 0x0000881f, 0x00005eca, 0x00006717, 0x00006d6a, 0x000072fc, 0x000090ce, 0x00004f86, 0x000051b7, 0x000052de, 0x000064c4, 0x00006ad3, 0x00007210, 0x000076e7, 0x00008001, 0x00008606, 0x0000865c, 0x00008def, 0x00009732, 0x00009b6f, 0x00009dfa, 0x0000788c, 0x0000797f, 0x00007da0, 0x000083c9, 0x00009304, 0x00009e7f, 0x00008ad6, 0x000058df, 0x00005f04, 0x00007c60, 0x0000807e, 0x00007262, 0x000078ca, 0x00008cc2, 0x000096f7, 0x000058d8, 0x00005c62, 0x00006a13, 0x00006dda, 0x00006f0f, 0x00007d2f, 0x00007e37, 0x0000964b, 0x000052d2, 0x0000808b, 0x000051dc, 0x000051cc, 0x00007a1c, 0x00007dbe, 0x000083f1, 0x00009675, 0x00008b80, 0x000062cf, 0x00006a02, 0x00008afe, 0x00004e39, 0x00005be7, 0x00006012, 0x00007387, 0x00007570, 0x00005317, 0x000078fb, 0x00004fbf, 0x00005fa9, 0x00004e0d, 0x00006ccc, 0x00006578, 0x00007d22, 0x000053c3, 0x0000585e, 0x00007701, 0x00008449, 0x00008aaa, 0x00006bba, 0x00008fb0, 0x00006c88, 0x000062fe, 0x000082e5, 0x000063a0, 0x00007565, 0x00004eae, 0x00005169, 0x000051c9, 0x00006881, 0x00007ce7, 0x0000826f, 0x00008ad2, 0x000091cf, 0x000052f5, 0x00005442, 0x00005973, 0x00005eec, 0x000065c5, 0x00006ffe, 0x0000792a, 0x000095ad, 0x00009a6a, 0x00009e97, 0x00009ece, 0x0000529b, 0x000066c6, 0x00006b77, 0x00008f62, 0x00005e74, 0x00006190, 0x00006200, 0x0000649a, 0x00006f23, 0x00007149, 0x00007489, 0x000079ca, 0x00007df4, 0x0000806f, 0x00008f26, 0x000084ee, 0x00009023, 0x0000934a, 0x00005217, 0x000052a3, 0x000054bd, 0x000070c8, 0x000088c2, 0x00008aaa, 0x00005ec9, 0x00005ff5, 0x0000637b, 0x00006bae, 0x00007c3e, 0x00007375, 0x00004ee4, 0x000056f9, 0x00005be7, 0x00005dba, 0x0000601c, 0x000073b2, 0x00007469, 0x00007f9a, 0x00008046, 0x00009234, 0x000096f6, 0x00009748, 0x00009818, 0x00004f8b, 0x000079ae, 0x000091b4, 0x000096b8, 0x000060e1, 0x00004e86, 0x000050da, 0x00005bee, 0x00005c3f, 0x00006599, 0x00006a02, 0x000071ce, 0x00007642, 0x000084fc, 0x0000907c, 0x00009f8d, 0x00006688, 0x0000962e, 0x00005289, 0x0000677b, 0x000067f3, 0x00006d41, 0x00006e9c, 0x00007409, 0x00007559, 0x0000786b, 0x00007d10, 0x0000985e, 0x0000516d, 0x0000622e, 0x00009678, 0x0000502b, 0x00005d19, 0x00006dea, 0x00008f2a, 0x00005f8b, 0x00006144, 0x00006817, 0x00007387, 0x00009686, 0x00005229, 0x0000540f, 0x00005c65, 0x00006613, 0x0000674e, 0x000068a8, 0x00006ce5, 0x00007406, 0x000075e2, 0x00007f79, 0x000088cf, 0x000088e1, 0x000091cc, 0x000096e2, 0x0000533f, 0x00006eba, 0x0000541d, 0x000071d0, 0x00007498, 0x000085fa, 0x000096a3, 0x00009c57, 0x00009e9f, 0x00006797, 0x00006dcb, 0x000081e8, 0x00007acb, 0x00007b20, 0x00007c92, 0x000072c0, 0x00007099, 0x00008b58, 0x00004ec0, 0x00008336, 0x0000523a, 0x00005207, 0x00005ea6, 0x000062d3, 0x00007cd6, 0x00005b85, 0x00006d1e, 0x000066b4, 0x00008f3b, 0x0000884c, 0x0000964d, 0x0000898b, 0x00005ed3, 0x00005140, 0x000055c0, 0x0000585a, 0x00006674, 0x000051de, 0x0000732a, 0x000076ca, 0x0000793c, 0x0000795e, 0x00007965, 0x0000798f, 0x00009756, 0x00007cbe, 0x00007fbd, 0x00008612, 0x00008af8, 0x00009038, 0x000090fd, 0x000098ef, 0x000098fc, 0x00009928, 0x00009db4, 0x00004fae, 0x000050e7, 0x0000514d, 0x000052c9, 0x000052e4, 0x00005351, 0x0000559d, 0x00005606, 0x00005668, 0x00005840, 0x000058a8, 0x00005c64, 0x00005c6e, 0x00006094, 0x00006168, 0x0000618e, 0x000061f2, 0x0000654f, 0x000065e2, 0x00006691, 0x00006885, 0x00006d77, 0x00006e1a, 0x00006f22, 0x0000716e, 0x0000722b, 0x00007422, 0x00007891, 0x0000793e, 0x00007949, 0x00007948, 0x00007950, 0x00007956, 0x0000795d, 0x0000798d, 0x0000798e, 0x00007a40, 0x00007a81, 0x00007bc0, 0x00007df4, 0x00007e09, 0x00007e41, 0x00007f72, 0x00008005, 0x000081ed, 0x00008279, 0x00008279, 0x00008457, 0x00008910, 0x00008996, 0x00008b01, 0x00008b39, 0x00008cd3, 0x00008d08, 0x00008fb6, 0x00009038, 0x000096e3, 0x000097ff, 0x0000983b, 0x000005d9, 0x000005b4, 0x000005f2, 0x000005b7, 0x000005e9, 0x000005c1, 0x000005e9, 0x000005c2, 0x000005e9, 0x000005bc, 0x000005c1, 0x000005e9, 0x000005bc, 0x000005c2, 0x000005d0, 0x000005b7, 0x000005d0, 0x000005b8, 0x000005d0, 0x000005bc, 0x000005d1, 0x000005bc, 0x000005d2, 0x000005bc, 0x000005d3, 0x000005bc, 0x000005d4, 0x000005bc, 0x000005d5, 0x000005bc, 0x000005d6, 0x000005bc, 0x000005d8, 0x000005bc, 0x000005d9, 0x000005bc, 0x000005da, 0x000005bc, 0x000005db, 0x000005bc, 0x000005dc, 0x000005bc, 0x000005de, 0x000005bc, 0x000005e0, 0x000005bc, 0x000005e1, 0x000005bc, 0x000005e3, 0x000005bc, 0x000005e4, 0x000005bc, 0x000005e6, 0x000005bc, 0x000005e7, 0x000005bc, 0x000005e8, 0x000005bc, 0x000005e9, 0x000005bc, 0x000005ea, 0x000005bc, 0x000005d5, 0x000005b9, 0x000005d1, 0x000005bf, 0x000005db, 0x000005bf, 0x000005e4, 0x000005bf, 0x0001d157, 0x0001d165, 0x0001d158, 0x0001d165, 0x0001d158, 0x0001d165, 0x0001d16e, 0x0001d158, 0x0001d165, 0x0001d16f, 0x0001d158, 0x0001d165, 0x0001d170, 0x0001d158, 0x0001d165, 0x0001d171, 0x0001d158, 0x0001d165, 0x0001d172, 0x0001d1b9, 0x0001d165, 0x0001d1ba, 0x0001d165, 0x0001d1b9, 0x0001d165, 0x0001d16e, 0x0001d1ba, 0x0001d165, 0x0001d16e, 0x0001d1b9, 0x0001d165, 0x0001d16f, 0x0001d1ba, 0x0001d165, 0x0001d16f, 0x00004e3d, 0x00004e38, 0x00004e41, 0x00020122, 0x00004f60, 0x00004fae, 0x00004fbb, 0x00005002, 0x0000507a, 0x00005099, 0x000050e7, 0x000050cf, 0x0000349e, 0x0002063a, 0x0000514d, 0x00005154, 0x00005164, 0x00005177, 0x0002051c, 0x000034b9, 0x00005167, 0x0000518d, 0x0002054b, 0x00005197, 0x000051a4, 0x00004ecc, 0x000051ac, 0x000051b5, 0x000291df, 0x000051f5, 0x00005203, 0x000034df, 0x0000523b, 0x00005246, 0x00005272, 0x00005277, 0x00003515, 0x000052c7, 0x000052c9, 0x000052e4, 0x000052fa, 0x00005305, 0x00005306, 0x00005317, 0x00005349, 0x00005351, 0x0000535a, 0x00005373, 0x0000537d, 0x0000537f, 0x0000537f, 0x0000537f, 0x00020a2c, 0x00007070, 0x000053ca, 0x000053df, 0x00020b63, 0x000053eb, 0x000053f1, 0x00005406, 0x0000549e, 0x00005438, 0x00005448, 0x00005468, 0x000054a2, 0x000054f6, 0x00005510, 0x00005553, 0x00005563, 0x00005584, 0x00005584, 0x00005599, 0x000055ab, 0x000055b3, 0x000055c2, 0x00005716, 0x00005606, 0x00005717, 0x00005651, 0x00005674, 0x00005207, 0x000058ee, 0x000057ce, 0x000057f4, 0x0000580d, 0x0000578b, 0x00005832, 0x00005831, 0x000058ac, 0x000214e4, 0x000058f2, 0x000058f7, 0x00005906, 0x0000591a, 0x00005922, 0x00005962, 0x000216a8, 0x000216ea, 0x000059ec, 0x00005a1b, 0x00005a27, 0x000059d8, 0x00005a66, 0x000036ee, 0x0002136a, 0x00005b08, 0x00005b3e, 0x00005b3e, 0x000219c8, 0x00005bc3, 0x00005bd8, 0x00005be7, 0x00005bf3, 0x00021b18, 0x00005bff, 0x00005c06, 0x00005f33, 0x00005c22, 0x00003781, 0x00005c60, 0x00005c6e, 0x00005cc0, 0x00005c8d, 0x00021de4, 0x00005d43, 0x00021de6, 0x00005d6e, 0x00005d6b, 0x00005d7c, 0x00005de1, 0x00005de2, 0x0000382f, 0x00005dfd, 0x00005e28, 0x00005e3d, 0x00005e69, 0x00003862, 0x00022183, 0x0000387c, 0x00005eb0, 0x00005eb3, 0x00005eb6, 0x00005eca, 0x0002a392, 0x00005efe, 0x00022331, 0x00022331, 0x00008201, 0x00005f22, 0x00005f22, 0x000038c7, 0x000232b8, 0x000261da, 0x00005f62, 0x00005f6b, 0x000038e3, 0x00005f9a, 0x00005fcd, 0x00005fd7, 0x00005ff9, 0x00006081, 0x0000393a, 0x0000391c, 0x00006094, 0x000226d4, 0x000060c7, 0x00006148, 0x0000614c, 0x0000614e, 0x0000614c, 0x0000617a, 0x0000618e, 0x000061b2, 0x000061a4, 0x000061af, 0x000061de, 0x000061f2, 0x000061f6, 0x00006210, 0x0000621b, 0x0000625d, 0x000062b1, 0x000062d4, 0x00006350, 0x00022b0c, 0x0000633d, 0x000062fc, 0x00006368, 0x00006383, 0x000063e4, 0x00022bf1, 0x00006422, 0x000063c5, 0x000063a9, 0x00003a2e, 0x00006469, 0x0000647e, 0x0000649d, 0x00006477, 0x00003a6c, 0x0000654f, 0x0000656c, 0x0002300a, 0x000065e3, 0x000066f8, 0x00006649, 0x00003b19, 0x00006691, 0x00003b08, 0x00003ae4, 0x00005192, 0x00005195, 0x00006700, 0x0000669c, 0x000080ad, 0x000043d9, 0x00006717, 0x0000671b, 0x00006721, 0x0000675e, 0x00006753, 0x000233c3, 0x00003b49, 0x000067fa, 0x00006785, 0x00006852, 0x00006885, 0x0002346d, 0x0000688e, 0x0000681f, 0x00006914, 0x00003b9d, 0x00006942, 0x000069a3, 0x000069ea, 0x00006aa8, 0x000236a3, 0x00006adb, 0x00003c18, 0x00006b21, 0x000238a7, 0x00006b54, 0x00003c4e, 0x00006b72, 0x00006b9f, 0x00006bba, 0x00006bbb, 0x00023a8d, 0x00021d0b, 0x00023afa, 0x00006c4e, 0x00023cbc, 0x00006cbf, 0x00006ccd, 0x00006c67, 0x00006d16, 0x00006d3e, 0x00006d77, 0x00006d41, 0x00006d69, 0x00006d78, 0x00006d85, 0x00023d1e, 0x00006d34, 0x00006e2f, 0x00006e6e, 0x00003d33, 0x00006ecb, 0x00006ec7, 0x00023ed1, 0x00006df9, 0x00006f6e, 0x00023f5e, 0x00023f8e, 0x00006fc6, 0x00007039, 0x0000701e, 0x0000701b, 0x00003d96, 0x0000704a, 0x0000707d, 0x00007077, 0x000070ad, 0x00020525, 0x00007145, 0x00024263, 0x0000719c, 0x000043ab, 0x00007228, 0x00007235, 0x00007250, 0x00024608, 0x00007280, 0x00007295, 0x00024735, 0x00024814, 0x0000737a, 0x0000738b, 0x00003eac, 0x000073a5, 0x00003eb8, 0x00003eb8, 0x00007447, 0x0000745c, 0x00007471, 0x00007485, 0x000074ca, 0x00003f1b, 0x00007524, 0x00024c36, 0x0000753e, 0x00024c92, 0x00007570, 0x0002219f, 0x00007610, 0x00024fa1, 0x00024fb8, 0x00025044, 0x00003ffc, 0x00004008, 0x000076f4, 0x000250f3, 0x000250f2, 0x00025119, 0x00025133, 0x0000771e, 0x0000771f, 0x0000771f, 0x0000774a, 0x00004039, 0x0000778b, 0x00004046, 0x00004096, 0x0002541d, 0x0000784e, 0x0000788c, 0x000078cc, 0x000040e3, 0x00025626, 0x00007956, 0x0002569a, 0x000256c5, 0x0000798f, 0x000079eb, 0x0000412f, 0x00007a40, 0x00007a4a, 0x00007a4f, 0x0002597c, 0x00025aa7, 0x00025aa7, 0x00007aae, 0x00004202, 0x00025bab, 0x00007bc6, 0x00007bc9, 0x00004227, 0x00025c80, 0x00007cd2, 0x000042a0, 0x00007ce8, 0x00007ce3, 0x00007d00, 0x00025f86, 0x00007d63, 0x00004301, 0x00007dc7, 0x00007e02, 0x00007e45, 0x00004334, 0x00026228, 0x00026247, 0x00004359, 0x000262d9, 0x00007f7a, 0x0002633e, 0x00007f95, 0x00007ffa, 0x00008005, 0x000264da, 0x00026523, 0x00008060, 0x000265a8, 0x00008070, 0x0002335f, 0x000043d5, 0x000080b2, 0x00008103, 0x0000440b, 0x0000813e, 0x00005ab5, 0x000267a7, 0x000267b5, 0x00023393, 0x0002339c, 0x00008201, 0x00008204, 0x00008f9e, 0x0000446b, 0x00008291, 0x0000828b, 0x0000829d, 0x000052b3, 0x000082b1, 0x000082b3, 0x000082bd, 0x000082e6, 0x00026b3c, 0x000082e5, 0x0000831d, 0x00008363, 0x000083ad, 0x00008323, 0x000083bd, 0x000083e7, 0x00008457, 0x00008353, 0x000083ca, 0x000083cc, 0x000083dc, 0x00026c36, 0x00026d6b, 0x00026cd5, 0x0000452b, 0x000084f1, 0x000084f3, 0x00008516, 0x000273ca, 0x00008564, 0x00026f2c, 0x0000455d, 0x00004561, 0x00026fb1, 0x000270d2, 0x0000456b, 0x00008650, 0x0000865c, 0x00008667, 0x00008669, 0x000086a9, 0x00008688, 0x0000870e, 0x000086e2, 0x00008779, 0x00008728, 0x0000876b, 0x00008786, 0x00004d57, 0x000087e1, 0x00008801, 0x000045f9, 0x00008860, 0x00008863, 0x00027667, 0x000088d7, 0x000088de, 0x00004635, 0x000088fa, 0x000034bb, 0x000278ae, 0x00027966, 0x000046be, 0x000046c7, 0x00008aa0, 0x00008aed, 0x00008b8a, 0x00008c55, 0x00027ca8, 0x00008cab, 0x00008cc1, 0x00008d1b, 0x00008d77, 0x00027f2f, 0x00020804, 0x00008dcb, 0x00008dbc, 0x00008df0, 0x000208de, 0x00008ed4, 0x00008f38, 0x000285d2, 0x000285ed, 0x00009094, 0x000090f1, 0x00009111, 0x0002872e, 0x0000911b, 0x00009238, 0x000092d7, 0x000092d8, 0x0000927c, 0x000093f9, 0x00009415, 0x00028bfa, 0x0000958b, 0x00004995, 0x000095b7, 0x00028d77, 0x000049e6, 0x000096c3, 0x00005db2, 0x00009723, 0x00029145, 0x0002921a, 0x00004a6e, 0x00004a76, 0x000097e0, 0x0002940a, 0x00004ab2, 0x00029496, 0x0000980b, 0x0000980b, 0x00009829, 0x000295b6, 0x000098e2, 0x00004b33, 0x00009929, 0x000099a7, 0x000099c2, 0x000099fe, 0x00004bce, 0x00029b30, 0x00009b12, 0x00009c40, 0x00009cfd, 0x00004cce, 0x00004ced, 0x00009d67, 0x0002a0ce, 0x00004cf8, 0x0002a105, 0x0002a20e, 0x0002a291, 0x00009ebb, 0x00004d56, 0x00009ef9, 0x00009efe, 0x00009f05, 0x00009f0f, 0x00009f16, 0x00009f3b, 0x0002a600 }; static const ac_uint4 _uckdcmp_size = 10282; static const ac_uint4 _uckdcmp_nodes[] = { 0x000000a0, 0x00000000, 0x000000a8, 0x00000001, 0x000000aa, 0x00000003, 0x000000af, 0x00000004, 0x000000b2, 0x00000006, 0x000000b3, 0x00000007, 0x000000b4, 0x00000008, 0x000000b5, 0x0000000a, 0x000000b8, 0x0000000b, 0x000000b9, 0x0000000d, 0x000000ba, 0x0000000e, 0x000000bc, 0x0000000f, 0x000000bd, 0x00000012, 0x000000be, 0x00000015, 0x000000c0, 0x00000018, 0x000000c1, 0x0000001a, 0x000000c2, 0x0000001c, 0x000000c3, 0x0000001e, 0x000000c4, 0x00000020, 0x000000c5, 0x00000022, 0x000000c7, 0x00000024, 0x000000c8, 0x00000026, 0x000000c9, 0x00000028, 0x000000ca, 0x0000002a, 0x000000cb, 0x0000002c, 0x000000cc, 0x0000002e, 0x000000cd, 0x00000030, 0x000000ce, 0x00000032, 0x000000cf, 0x00000034, 0x000000d1, 0x00000036, 0x000000d2, 0x00000038, 0x000000d3, 0x0000003a, 0x000000d4, 0x0000003c, 0x000000d5, 0x0000003e, 0x000000d6, 0x00000040, 0x000000d9, 0x00000042, 0x000000da, 0x00000044, 0x000000db, 0x00000046, 0x000000dc, 0x00000048, 0x000000dd, 0x0000004a, 0x000000e0, 0x0000004c, 0x000000e1, 0x0000004e, 0x000000e2, 0x00000050, 0x000000e3, 0x00000052, 0x000000e4, 0x00000054, 0x000000e5, 0x00000056, 0x000000e7, 0x00000058, 0x000000e8, 0x0000005a, 0x000000e9, 0x0000005c, 0x000000ea, 0x0000005e, 0x000000eb, 0x00000060, 0x000000ec, 0x00000062, 0x000000ed, 0x00000064, 0x000000ee, 0x00000066, 0x000000ef, 0x00000068, 0x000000f1, 0x0000006a, 0x000000f2, 0x0000006c, 0x000000f3, 0x0000006e, 0x000000f4, 0x00000070, 0x000000f5, 0x00000072, 0x000000f6, 0x00000074, 0x000000f9, 0x00000076, 0x000000fa, 0x00000078, 0x000000fb, 0x0000007a, 0x000000fc, 0x0000007c, 0x000000fd, 0x0000007e, 0x000000ff, 0x00000080, 0x00000100, 0x00000082, 0x00000101, 0x00000084, 0x00000102, 0x00000086, 0x00000103, 0x00000088, 0x00000104, 0x0000008a, 0x00000105, 0x0000008c, 0x00000106, 0x0000008e, 0x00000107, 0x00000090, 0x00000108, 0x00000092, 0x00000109, 0x00000094, 0x0000010a, 0x00000096, 0x0000010b, 0x00000098, 0x0000010c, 0x0000009a, 0x0000010d, 0x0000009c, 0x0000010e, 0x0000009e, 0x0000010f, 0x000000a0, 0x00000112, 0x000000a2, 0x00000113, 0x000000a4, 0x00000114, 0x000000a6, 0x00000115, 0x000000a8, 0x00000116, 0x000000aa, 0x00000117, 0x000000ac, 0x00000118, 0x000000ae, 0x00000119, 0x000000b0, 0x0000011a, 0x000000b2, 0x0000011b, 0x000000b4, 0x0000011c, 0x000000b6, 0x0000011d, 0x000000b8, 0x0000011e, 0x000000ba, 0x0000011f, 0x000000bc, 0x00000120, 0x000000be, 0x00000121, 0x000000c0, 0x00000122, 0x000000c2, 0x00000123, 0x000000c4, 0x00000124, 0x000000c6, 0x00000125, 0x000000c8, 0x00000128, 0x000000ca, 0x00000129, 0x000000cc, 0x0000012a, 0x000000ce, 0x0000012b, 0x000000d0, 0x0000012c, 0x000000d2, 0x0000012d, 0x000000d4, 0x0000012e, 0x000000d6, 0x0000012f, 0x000000d8, 0x00000130, 0x000000da, 0x00000132, 0x000000dc, 0x00000133, 0x000000de, 0x00000134, 0x000000e0, 0x00000135, 0x000000e2, 0x00000136, 0x000000e4, 0x00000137, 0x000000e6, 0x00000139, 0x000000e8, 0x0000013a, 0x000000ea, 0x0000013b, 0x000000ec, 0x0000013c, 0x000000ee, 0x0000013d, 0x000000f0, 0x0000013e, 0x000000f2, 0x0000013f, 0x000000f4, 0x00000140, 0x000000f6, 0x00000143, 0x000000f8, 0x00000144, 0x000000fa, 0x00000145, 0x000000fc, 0x00000146, 0x000000fe, 0x00000147, 0x00000100, 0x00000148, 0x00000102, 0x00000149, 0x00000104, 0x0000014c, 0x00000106, 0x0000014d, 0x00000108, 0x0000014e, 0x0000010a, 0x0000014f, 0x0000010c, 0x00000150, 0x0000010e, 0x00000151, 0x00000110, 0x00000154, 0x00000112, 0x00000155, 0x00000114, 0x00000156, 0x00000116, 0x00000157, 0x00000118, 0x00000158, 0x0000011a, 0x00000159, 0x0000011c, 0x0000015a, 0x0000011e, 0x0000015b, 0x00000120, 0x0000015c, 0x00000122, 0x0000015d, 0x00000124, 0x0000015e, 0x00000126, 0x0000015f, 0x00000128, 0x00000160, 0x0000012a, 0x00000161, 0x0000012c, 0x00000162, 0x0000012e, 0x00000163, 0x00000130, 0x00000164, 0x00000132, 0x00000165, 0x00000134, 0x00000168, 0x00000136, 0x00000169, 0x00000138, 0x0000016a, 0x0000013a, 0x0000016b, 0x0000013c, 0x0000016c, 0x0000013e, 0x0000016d, 0x00000140, 0x0000016e, 0x00000142, 0x0000016f, 0x00000144, 0x00000170, 0x00000146, 0x00000171, 0x00000148, 0x00000172, 0x0000014a, 0x00000173, 0x0000014c, 0x00000174, 0x0000014e, 0x00000175, 0x00000150, 0x00000176, 0x00000152, 0x00000177, 0x00000154, 0x00000178, 0x00000156, 0x00000179, 0x00000158, 0x0000017a, 0x0000015a, 0x0000017b, 0x0000015c, 0x0000017c, 0x0000015e, 0x0000017d, 0x00000160, 0x0000017e, 0x00000162, 0x0000017f, 0x00000164, 0x000001a0, 0x00000165, 0x000001a1, 0x00000167, 0x000001af, 0x00000169, 0x000001b0, 0x0000016b, 0x000001c4, 0x0000016d, 0x000001c5, 0x00000170, 0x000001c6, 0x00000173, 0x000001c7, 0x00000176, 0x000001c8, 0x00000178, 0x000001c9, 0x0000017a, 0x000001ca, 0x0000017c, 0x000001cb, 0x0000017e, 0x000001cc, 0x00000180, 0x000001cd, 0x00000182, 0x000001ce, 0x00000184, 0x000001cf, 0x00000186, 0x000001d0, 0x00000188, 0x000001d1, 0x0000018a, 0x000001d2, 0x0000018c, 0x000001d3, 0x0000018e, 0x000001d4, 0x00000190, 0x000001d5, 0x00000192, 0x000001d6, 0x00000195, 0x000001d7, 0x00000198, 0x000001d8, 0x0000019b, 0x000001d9, 0x0000019e, 0x000001da, 0x000001a1, 0x000001db, 0x000001a4, 0x000001dc, 0x000001a7, 0x000001de, 0x000001aa, 0x000001df, 0x000001ad, 0x000001e0, 0x000001b0, 0x000001e1, 0x000001b3, 0x000001e2, 0x000001b6, 0x000001e3, 0x000001b8, 0x000001e6, 0x000001ba, 0x000001e7, 0x000001bc, 0x000001e8, 0x000001be, 0x000001e9, 0x000001c0, 0x000001ea, 0x000001c2, 0x000001eb, 0x000001c4, 0x000001ec, 0x000001c6, 0x000001ed, 0x000001c9, 0x000001ee, 0x000001cc, 0x000001ef, 0x000001ce, 0x000001f0, 0x000001d0, 0x000001f1, 0x000001d2, 0x000001f2, 0x000001d4, 0x000001f3, 0x000001d6, 0x000001f4, 0x000001d8, 0x000001f5, 0x000001da, 0x000001f8, 0x000001dc, 0x000001f9, 0x000001de, 0x000001fa, 0x000001e0, 0x000001fb, 0x000001e3, 0x000001fc, 0x000001e6, 0x000001fd, 0x000001e8, 0x000001fe, 0x000001ea, 0x000001ff, 0x000001ec, 0x00000200, 0x000001ee, 0x00000201, 0x000001f0, 0x00000202, 0x000001f2, 0x00000203, 0x000001f4, 0x00000204, 0x000001f6, 0x00000205, 0x000001f8, 0x00000206, 0x000001fa, 0x00000207, 0x000001fc, 0x00000208, 0x000001fe, 0x00000209, 0x00000200, 0x0000020a, 0x00000202, 0x0000020b, 0x00000204, 0x0000020c, 0x00000206, 0x0000020d, 0x00000208, 0x0000020e, 0x0000020a, 0x0000020f, 0x0000020c, 0x00000210, 0x0000020e, 0x00000211, 0x00000210, 0x00000212, 0x00000212, 0x00000213, 0x00000214, 0x00000214, 0x00000216, 0x00000215, 0x00000218, 0x00000216, 0x0000021a, 0x00000217, 0x0000021c, 0x00000218, 0x0000021e, 0x00000219, 0x00000220, 0x0000021a, 0x00000222, 0x0000021b, 0x00000224, 0x0000021e, 0x00000226, 0x0000021f, 0x00000228, 0x00000226, 0x0000022a, 0x00000227, 0x0000022c, 0x00000228, 0x0000022e, 0x00000229, 0x00000230, 0x0000022a, 0x00000232, 0x0000022b, 0x00000235, 0x0000022c, 0x00000238, 0x0000022d, 0x0000023b, 0x0000022e, 0x0000023e, 0x0000022f, 0x00000240, 0x00000230, 0x00000242, 0x00000231, 0x00000245, 0x00000232, 0x00000248, 0x00000233, 0x0000024a, 0x000002b0, 0x0000024c, 0x000002b1, 0x0000024d, 0x000002b2, 0x0000024e, 0x000002b3, 0x0000024f, 0x000002b4, 0x00000250, 0x000002b5, 0x00000251, 0x000002b6, 0x00000252, 0x000002b7, 0x00000253, 0x000002b8, 0x00000254, 0x000002d8, 0x00000255, 0x000002d9, 0x00000257, 0x000002da, 0x00000259, 0x000002db, 0x0000025b, 0x000002dc, 0x0000025d, 0x000002dd, 0x0000025f, 0x000002e0, 0x00000261, 0x000002e1, 0x00000262, 0x000002e2, 0x00000263, 0x000002e3, 0x00000264, 0x000002e4, 0x00000265, 0x00000340, 0x00000266, 0x00000341, 0x00000267, 0x00000343, 0x00000268, 0x00000344, 0x00000269, 0x00000374, 0x0000026b, 0x0000037a, 0x0000026c, 0x0000037e, 0x0000026e, 0x00000384, 0x0000026f, 0x00000385, 0x00000271, 0x00000386, 0x00000274, 0x00000387, 0x00000276, 0x00000388, 0x00000277, 0x00000389, 0x00000279, 0x0000038a, 0x0000027b, 0x0000038c, 0x0000027d, 0x0000038e, 0x0000027f, 0x0000038f, 0x00000281, 0x00000390, 0x00000283, 0x000003aa, 0x00000286, 0x000003ab, 0x00000288, 0x000003ac, 0x0000028a, 0x000003ad, 0x0000028c, 0x000003ae, 0x0000028e, 0x000003af, 0x00000290, 0x000003b0, 0x00000292, 0x000003ca, 0x00000295, 0x000003cb, 0x00000297, 0x000003cc, 0x00000299, 0x000003cd, 0x0000029b, 0x000003ce, 0x0000029d, 0x000003d0, 0x0000029f, 0x000003d1, 0x000002a0, 0x000003d2, 0x000002a1, 0x000003d3, 0x000002a2, 0x000003d4, 0x000002a4, 0x000003d5, 0x000002a6, 0x000003d6, 0x000002a7, 0x000003f0, 0x000002a8, 0x000003f1, 0x000002a9, 0x000003f2, 0x000002aa, 0x000003f4, 0x000002ab, 0x000003f5, 0x000002ac, 0x00000400, 0x000002ad, 0x00000401, 0x000002af, 0x00000403, 0x000002b1, 0x00000407, 0x000002b3, 0x0000040c, 0x000002b5, 0x0000040d, 0x000002b7, 0x0000040e, 0x000002b9, 0x00000419, 0x000002bb, 0x00000439, 0x000002bd, 0x00000450, 0x000002bf, 0x00000451, 0x000002c1, 0x00000453, 0x000002c3, 0x00000457, 0x000002c5, 0x0000045c, 0x000002c7, 0x0000045d, 0x000002c9, 0x0000045e, 0x000002cb, 0x00000476, 0x000002cd, 0x00000477, 0x000002cf, 0x000004c1, 0x000002d1, 0x000004c2, 0x000002d3, 0x000004d0, 0x000002d5, 0x000004d1, 0x000002d7, 0x000004d2, 0x000002d9, 0x000004d3, 0x000002db, 0x000004d6, 0x000002dd, 0x000004d7, 0x000002df, 0x000004da, 0x000002e1, 0x000004db, 0x000002e3, 0x000004dc, 0x000002e5, 0x000004dd, 0x000002e7, 0x000004de, 0x000002e9, 0x000004df, 0x000002eb, 0x000004e2, 0x000002ed, 0x000004e3, 0x000002ef, 0x000004e4, 0x000002f1, 0x000004e5, 0x000002f3, 0x000004e6, 0x000002f5, 0x000004e7, 0x000002f7, 0x000004ea, 0x000002f9, 0x000004eb, 0x000002fb, 0x000004ec, 0x000002fd, 0x000004ed, 0x000002ff, 0x000004ee, 0x00000301, 0x000004ef, 0x00000303, 0x000004f0, 0x00000305, 0x000004f1, 0x00000307, 0x000004f2, 0x00000309, 0x000004f3, 0x0000030b, 0x000004f4, 0x0000030d, 0x000004f5, 0x0000030f, 0x000004f8, 0x00000311, 0x000004f9, 0x00000313, 0x00000587, 0x00000315, 0x00000622, 0x00000317, 0x00000623, 0x00000319, 0x00000624, 0x0000031b, 0x00000625, 0x0000031d, 0x00000626, 0x0000031f, 0x00000675, 0x00000321, 0x00000676, 0x00000323, 0x00000677, 0x00000325, 0x00000678, 0x00000327, 0x000006c0, 0x00000329, 0x000006c2, 0x0000032b, 0x000006d3, 0x0000032d, 0x00000929, 0x0000032f, 0x00000931, 0x00000331, 0x00000934, 0x00000333, 0x00000958, 0x00000335, 0x00000959, 0x00000337, 0x0000095a, 0x00000339, 0x0000095b, 0x0000033b, 0x0000095c, 0x0000033d, 0x0000095d, 0x0000033f, 0x0000095e, 0x00000341, 0x0000095f, 0x00000343, 0x000009cb, 0x00000345, 0x000009cc, 0x00000347, 0x000009dc, 0x00000349, 0x000009dd, 0x0000034b, 0x000009df, 0x0000034d, 0x00000a33, 0x0000034f, 0x00000a36, 0x00000351, 0x00000a59, 0x00000353, 0x00000a5a, 0x00000355, 0x00000a5b, 0x00000357, 0x00000a5e, 0x00000359, 0x00000b48, 0x0000035b, 0x00000b4b, 0x0000035d, 0x00000b4c, 0x0000035f, 0x00000b5c, 0x00000361, 0x00000b5d, 0x00000363, 0x00000b94, 0x00000365, 0x00000bca, 0x00000367, 0x00000bcb, 0x00000369, 0x00000bcc, 0x0000036b, 0x00000c48, 0x0000036d, 0x00000cc0, 0x0000036f, 0x00000cc7, 0x00000371, 0x00000cc8, 0x00000373, 0x00000cca, 0x00000375, 0x00000ccb, 0x00000377, 0x00000d4a, 0x0000037a, 0x00000d4b, 0x0000037c, 0x00000d4c, 0x0000037e, 0x00000dda, 0x00000380, 0x00000ddc, 0x00000382, 0x00000ddd, 0x00000384, 0x00000dde, 0x00000387, 0x00000e33, 0x00000389, 0x00000eb3, 0x0000038b, 0x00000edc, 0x0000038d, 0x00000edd, 0x0000038f, 0x00000f0c, 0x00000391, 0x00000f43, 0x00000392, 0x00000f4d, 0x00000394, 0x00000f52, 0x00000396, 0x00000f57, 0x00000398, 0x00000f5c, 0x0000039a, 0x00000f69, 0x0000039c, 0x00000f73, 0x0000039e, 0x00000f75, 0x000003a0, 0x00000f76, 0x000003a2, 0x00000f77, 0x000003a4, 0x00000f78, 0x000003a7, 0x00000f79, 0x000003a9, 0x00000f81, 0x000003ac, 0x00000f93, 0x000003ae, 0x00000f9d, 0x000003b0, 0x00000fa2, 0x000003b2, 0x00000fa7, 0x000003b4, 0x00000fac, 0x000003b6, 0x00000fb9, 0x000003b8, 0x00001026, 0x000003ba, 0x00001e00, 0x000003bc, 0x00001e01, 0x000003be, 0x00001e02, 0x000003c0, 0x00001e03, 0x000003c2, 0x00001e04, 0x000003c4, 0x00001e05, 0x000003c6, 0x00001e06, 0x000003c8, 0x00001e07, 0x000003ca, 0x00001e08, 0x000003cc, 0x00001e09, 0x000003cf, 0x00001e0a, 0x000003d2, 0x00001e0b, 0x000003d4, 0x00001e0c, 0x000003d6, 0x00001e0d, 0x000003d8, 0x00001e0e, 0x000003da, 0x00001e0f, 0x000003dc, 0x00001e10, 0x000003de, 0x00001e11, 0x000003e0, 0x00001e12, 0x000003e2, 0x00001e13, 0x000003e4, 0x00001e14, 0x000003e6, 0x00001e15, 0x000003e9, 0x00001e16, 0x000003ec, 0x00001e17, 0x000003ef, 0x00001e18, 0x000003f2, 0x00001e19, 0x000003f4, 0x00001e1a, 0x000003f6, 0x00001e1b, 0x000003f8, 0x00001e1c, 0x000003fa, 0x00001e1d, 0x000003fd, 0x00001e1e, 0x00000400, 0x00001e1f, 0x00000402, 0x00001e20, 0x00000404, 0x00001e21, 0x00000406, 0x00001e22, 0x00000408, 0x00001e23, 0x0000040a, 0x00001e24, 0x0000040c, 0x00001e25, 0x0000040e, 0x00001e26, 0x00000410, 0x00001e27, 0x00000412, 0x00001e28, 0x00000414, 0x00001e29, 0x00000416, 0x00001e2a, 0x00000418, 0x00001e2b, 0x0000041a, 0x00001e2c, 0x0000041c, 0x00001e2d, 0x0000041e, 0x00001e2e, 0x00000420, 0x00001e2f, 0x00000423, 0x00001e30, 0x00000426, 0x00001e31, 0x00000428, 0x00001e32, 0x0000042a, 0x00001e33, 0x0000042c, 0x00001e34, 0x0000042e, 0x00001e35, 0x00000430, 0x00001e36, 0x00000432, 0x00001e37, 0x00000434, 0x00001e38, 0x00000436, 0x00001e39, 0x00000439, 0x00001e3a, 0x0000043c, 0x00001e3b, 0x0000043e, 0x00001e3c, 0x00000440, 0x00001e3d, 0x00000442, 0x00001e3e, 0x00000444, 0x00001e3f, 0x00000446, 0x00001e40, 0x00000448, 0x00001e41, 0x0000044a, 0x00001e42, 0x0000044c, 0x00001e43, 0x0000044e, 0x00001e44, 0x00000450, 0x00001e45, 0x00000452, 0x00001e46, 0x00000454, 0x00001e47, 0x00000456, 0x00001e48, 0x00000458, 0x00001e49, 0x0000045a, 0x00001e4a, 0x0000045c, 0x00001e4b, 0x0000045e, 0x00001e4c, 0x00000460, 0x00001e4d, 0x00000463, 0x00001e4e, 0x00000466, 0x00001e4f, 0x00000469, 0x00001e50, 0x0000046c, 0x00001e51, 0x0000046f, 0x00001e52, 0x00000472, 0x00001e53, 0x00000475, 0x00001e54, 0x00000478, 0x00001e55, 0x0000047a, 0x00001e56, 0x0000047c, 0x00001e57, 0x0000047e, 0x00001e58, 0x00000480, 0x00001e59, 0x00000482, 0x00001e5a, 0x00000484, 0x00001e5b, 0x00000486, 0x00001e5c, 0x00000488, 0x00001e5d, 0x0000048b, 0x00001e5e, 0x0000048e, 0x00001e5f, 0x00000490, 0x00001e60, 0x00000492, 0x00001e61, 0x00000494, 0x00001e62, 0x00000496, 0x00001e63, 0x00000498, 0x00001e64, 0x0000049a, 0x00001e65, 0x0000049d, 0x00001e66, 0x000004a0, 0x00001e67, 0x000004a3, 0x00001e68, 0x000004a6, 0x00001e69, 0x000004a9, 0x00001e6a, 0x000004ac, 0x00001e6b, 0x000004ae, 0x00001e6c, 0x000004b0, 0x00001e6d, 0x000004b2, 0x00001e6e, 0x000004b4, 0x00001e6f, 0x000004b6, 0x00001e70, 0x000004b8, 0x00001e71, 0x000004ba, 0x00001e72, 0x000004bc, 0x00001e73, 0x000004be, 0x00001e74, 0x000004c0, 0x00001e75, 0x000004c2, 0x00001e76, 0x000004c4, 0x00001e77, 0x000004c6, 0x00001e78, 0x000004c8, 0x00001e79, 0x000004cb, 0x00001e7a, 0x000004ce, 0x00001e7b, 0x000004d1, 0x00001e7c, 0x000004d4, 0x00001e7d, 0x000004d6, 0x00001e7e, 0x000004d8, 0x00001e7f, 0x000004da, 0x00001e80, 0x000004dc, 0x00001e81, 0x000004de, 0x00001e82, 0x000004e0, 0x00001e83, 0x000004e2, 0x00001e84, 0x000004e4, 0x00001e85, 0x000004e6, 0x00001e86, 0x000004e8, 0x00001e87, 0x000004ea, 0x00001e88, 0x000004ec, 0x00001e89, 0x000004ee, 0x00001e8a, 0x000004f0, 0x00001e8b, 0x000004f2, 0x00001e8c, 0x000004f4, 0x00001e8d, 0x000004f6, 0x00001e8e, 0x000004f8, 0x00001e8f, 0x000004fa, 0x00001e90, 0x000004fc, 0x00001e91, 0x000004fe, 0x00001e92, 0x00000500, 0x00001e93, 0x00000502, 0x00001e94, 0x00000504, 0x00001e95, 0x00000506, 0x00001e96, 0x00000508, 0x00001e97, 0x0000050a, 0x00001e98, 0x0000050c, 0x00001e99, 0x0000050e, 0x00001e9a, 0x00000510, 0x00001e9b, 0x00000512, 0x00001ea0, 0x00000514, 0x00001ea1, 0x00000516, 0x00001ea2, 0x00000518, 0x00001ea3, 0x0000051a, 0x00001ea4, 0x0000051c, 0x00001ea5, 0x0000051f, 0x00001ea6, 0x00000522, 0x00001ea7, 0x00000525, 0x00001ea8, 0x00000528, 0x00001ea9, 0x0000052b, 0x00001eaa, 0x0000052e, 0x00001eab, 0x00000531, 0x00001eac, 0x00000534, 0x00001ead, 0x00000537, 0x00001eae, 0x0000053a, 0x00001eaf, 0x0000053d, 0x00001eb0, 0x00000540, 0x00001eb1, 0x00000543, 0x00001eb2, 0x00000546, 0x00001eb3, 0x00000549, 0x00001eb4, 0x0000054c, 0x00001eb5, 0x0000054f, 0x00001eb6, 0x00000552, 0x00001eb7, 0x00000555, 0x00001eb8, 0x00000558, 0x00001eb9, 0x0000055a, 0x00001eba, 0x0000055c, 0x00001ebb, 0x0000055e, 0x00001ebc, 0x00000560, 0x00001ebd, 0x00000562, 0x00001ebe, 0x00000564, 0x00001ebf, 0x00000567, 0x00001ec0, 0x0000056a, 0x00001ec1, 0x0000056d, 0x00001ec2, 0x00000570, 0x00001ec3, 0x00000573, 0x00001ec4, 0x00000576, 0x00001ec5, 0x00000579, 0x00001ec6, 0x0000057c, 0x00001ec7, 0x0000057f, 0x00001ec8, 0x00000582, 0x00001ec9, 0x00000584, 0x00001eca, 0x00000586, 0x00001ecb, 0x00000588, 0x00001ecc, 0x0000058a, 0x00001ecd, 0x0000058c, 0x00001ece, 0x0000058e, 0x00001ecf, 0x00000590, 0x00001ed0, 0x00000592, 0x00001ed1, 0x00000595, 0x00001ed2, 0x00000598, 0x00001ed3, 0x0000059b, 0x00001ed4, 0x0000059e, 0x00001ed5, 0x000005a1, 0x00001ed6, 0x000005a4, 0x00001ed7, 0x000005a7, 0x00001ed8, 0x000005aa, 0x00001ed9, 0x000005ad, 0x00001eda, 0x000005b0, 0x00001edb, 0x000005b3, 0x00001edc, 0x000005b6, 0x00001edd, 0x000005b9, 0x00001ede, 0x000005bc, 0x00001edf, 0x000005bf, 0x00001ee0, 0x000005c2, 0x00001ee1, 0x000005c5, 0x00001ee2, 0x000005c8, 0x00001ee3, 0x000005cb, 0x00001ee4, 0x000005ce, 0x00001ee5, 0x000005d0, 0x00001ee6, 0x000005d2, 0x00001ee7, 0x000005d4, 0x00001ee8, 0x000005d6, 0x00001ee9, 0x000005d9, 0x00001eea, 0x000005dc, 0x00001eeb, 0x000005df, 0x00001eec, 0x000005e2, 0x00001eed, 0x000005e5, 0x00001eee, 0x000005e8, 0x00001eef, 0x000005eb, 0x00001ef0, 0x000005ee, 0x00001ef1, 0x000005f1, 0x00001ef2, 0x000005f4, 0x00001ef3, 0x000005f6, 0x00001ef4, 0x000005f8, 0x00001ef5, 0x000005fa, 0x00001ef6, 0x000005fc, 0x00001ef7, 0x000005fe, 0x00001ef8, 0x00000600, 0x00001ef9, 0x00000602, 0x00001f00, 0x00000604, 0x00001f01, 0x00000606, 0x00001f02, 0x00000608, 0x00001f03, 0x0000060b, 0x00001f04, 0x0000060e, 0x00001f05, 0x00000611, 0x00001f06, 0x00000614, 0x00001f07, 0x00000617, 0x00001f08, 0x0000061a, 0x00001f09, 0x0000061c, 0x00001f0a, 0x0000061e, 0x00001f0b, 0x00000621, 0x00001f0c, 0x00000624, 0x00001f0d, 0x00000627, 0x00001f0e, 0x0000062a, 0x00001f0f, 0x0000062d, 0x00001f10, 0x00000630, 0x00001f11, 0x00000632, 0x00001f12, 0x00000634, 0x00001f13, 0x00000637, 0x00001f14, 0x0000063a, 0x00001f15, 0x0000063d, 0x00001f18, 0x00000640, 0x00001f19, 0x00000642, 0x00001f1a, 0x00000644, 0x00001f1b, 0x00000647, 0x00001f1c, 0x0000064a, 0x00001f1d, 0x0000064d, 0x00001f20, 0x00000650, 0x00001f21, 0x00000652, 0x00001f22, 0x00000654, 0x00001f23, 0x00000657, 0x00001f24, 0x0000065a, 0x00001f25, 0x0000065d, 0x00001f26, 0x00000660, 0x00001f27, 0x00000663, 0x00001f28, 0x00000666, 0x00001f29, 0x00000668, 0x00001f2a, 0x0000066a, 0x00001f2b, 0x0000066d, 0x00001f2c, 0x00000670, 0x00001f2d, 0x00000673, 0x00001f2e, 0x00000676, 0x00001f2f, 0x00000679, 0x00001f30, 0x0000067c, 0x00001f31, 0x0000067e, 0x00001f32, 0x00000680, 0x00001f33, 0x00000683, 0x00001f34, 0x00000686, 0x00001f35, 0x00000689, 0x00001f36, 0x0000068c, 0x00001f37, 0x0000068f, 0x00001f38, 0x00000692, 0x00001f39, 0x00000694, 0x00001f3a, 0x00000696, 0x00001f3b, 0x00000699, 0x00001f3c, 0x0000069c, 0x00001f3d, 0x0000069f, 0x00001f3e, 0x000006a2, 0x00001f3f, 0x000006a5, 0x00001f40, 0x000006a8, 0x00001f41, 0x000006aa, 0x00001f42, 0x000006ac, 0x00001f43, 0x000006af, 0x00001f44, 0x000006b2, 0x00001f45, 0x000006b5, 0x00001f48, 0x000006b8, 0x00001f49, 0x000006ba, 0x00001f4a, 0x000006bc, 0x00001f4b, 0x000006bf, 0x00001f4c, 0x000006c2, 0x00001f4d, 0x000006c5, 0x00001f50, 0x000006c8, 0x00001f51, 0x000006ca, 0x00001f52, 0x000006cc, 0x00001f53, 0x000006cf, 0x00001f54, 0x000006d2, 0x00001f55, 0x000006d5, 0x00001f56, 0x000006d8, 0x00001f57, 0x000006db, 0x00001f59, 0x000006de, 0x00001f5b, 0x000006e0, 0x00001f5d, 0x000006e3, 0x00001f5f, 0x000006e6, 0x00001f60, 0x000006e9, 0x00001f61, 0x000006eb, 0x00001f62, 0x000006ed, 0x00001f63, 0x000006f0, 0x00001f64, 0x000006f3, 0x00001f65, 0x000006f6, 0x00001f66, 0x000006f9, 0x00001f67, 0x000006fc, 0x00001f68, 0x000006ff, 0x00001f69, 0x00000701, 0x00001f6a, 0x00000703, 0x00001f6b, 0x00000706, 0x00001f6c, 0x00000709, 0x00001f6d, 0x0000070c, 0x00001f6e, 0x0000070f, 0x00001f6f, 0x00000712, 0x00001f70, 0x00000715, 0x00001f71, 0x00000717, 0x00001f72, 0x00000719, 0x00001f73, 0x0000071b, 0x00001f74, 0x0000071d, 0x00001f75, 0x0000071f, 0x00001f76, 0x00000721, 0x00001f77, 0x00000723, 0x00001f78, 0x00000725, 0x00001f79, 0x00000727, 0x00001f7a, 0x00000729, 0x00001f7b, 0x0000072b, 0x00001f7c, 0x0000072d, 0x00001f7d, 0x0000072f, 0x00001f80, 0x00000731, 0x00001f81, 0x00000734, 0x00001f82, 0x00000737, 0x00001f83, 0x0000073b, 0x00001f84, 0x0000073f, 0x00001f85, 0x00000743, 0x00001f86, 0x00000747, 0x00001f87, 0x0000074b, 0x00001f88, 0x0000074f, 0x00001f89, 0x00000752, 0x00001f8a, 0x00000755, 0x00001f8b, 0x00000759, 0x00001f8c, 0x0000075d, 0x00001f8d, 0x00000761, 0x00001f8e, 0x00000765, 0x00001f8f, 0x00000769, 0x00001f90, 0x0000076d, 0x00001f91, 0x00000770, 0x00001f92, 0x00000773, 0x00001f93, 0x00000777, 0x00001f94, 0x0000077b, 0x00001f95, 0x0000077f, 0x00001f96, 0x00000783, 0x00001f97, 0x00000787, 0x00001f98, 0x0000078b, 0x00001f99, 0x0000078e, 0x00001f9a, 0x00000791, 0x00001f9b, 0x00000795, 0x00001f9c, 0x00000799, 0x00001f9d, 0x0000079d, 0x00001f9e, 0x000007a1, 0x00001f9f, 0x000007a5, 0x00001fa0, 0x000007a9, 0x00001fa1, 0x000007ac, 0x00001fa2, 0x000007af, 0x00001fa3, 0x000007b3, 0x00001fa4, 0x000007b7, 0x00001fa5, 0x000007bb, 0x00001fa6, 0x000007bf, 0x00001fa7, 0x000007c3, 0x00001fa8, 0x000007c7, 0x00001fa9, 0x000007ca, 0x00001faa, 0x000007cd, 0x00001fab, 0x000007d1, 0x00001fac, 0x000007d5, 0x00001fad, 0x000007d9, 0x00001fae, 0x000007dd, 0x00001faf, 0x000007e1, 0x00001fb0, 0x000007e5, 0x00001fb1, 0x000007e7, 0x00001fb2, 0x000007e9, 0x00001fb3, 0x000007ec, 0x00001fb4, 0x000007ee, 0x00001fb6, 0x000007f1, 0x00001fb7, 0x000007f3, 0x00001fb8, 0x000007f6, 0x00001fb9, 0x000007f8, 0x00001fba, 0x000007fa, 0x00001fbb, 0x000007fc, 0x00001fbc, 0x000007fe, 0x00001fbd, 0x00000800, 0x00001fbe, 0x00000802, 0x00001fbf, 0x00000803, 0x00001fc0, 0x00000805, 0x00001fc1, 0x00000807, 0x00001fc2, 0x0000080a, 0x00001fc3, 0x0000080d, 0x00001fc4, 0x0000080f, 0x00001fc6, 0x00000812, 0x00001fc7, 0x00000814, 0x00001fc8, 0x00000817, 0x00001fc9, 0x00000819, 0x00001fca, 0x0000081b, 0x00001fcb, 0x0000081d, 0x00001fcc, 0x0000081f, 0x00001fcd, 0x00000821, 0x00001fce, 0x00000824, 0x00001fcf, 0x00000827, 0x00001fd0, 0x0000082a, 0x00001fd1, 0x0000082c, 0x00001fd2, 0x0000082e, 0x00001fd3, 0x00000831, 0x00001fd6, 0x00000834, 0x00001fd7, 0x00000836, 0x00001fd8, 0x00000839, 0x00001fd9, 0x0000083b, 0x00001fda, 0x0000083d, 0x00001fdb, 0x0000083f, 0x00001fdd, 0x00000841, 0x00001fde, 0x00000844, 0x00001fdf, 0x00000847, 0x00001fe0, 0x0000084a, 0x00001fe1, 0x0000084c, 0x00001fe2, 0x0000084e, 0x00001fe3, 0x00000851, 0x00001fe4, 0x00000854, 0x00001fe5, 0x00000856, 0x00001fe6, 0x00000858, 0x00001fe7, 0x0000085a, 0x00001fe8, 0x0000085d, 0x00001fe9, 0x0000085f, 0x00001fea, 0x00000861, 0x00001feb, 0x00000863, 0x00001fec, 0x00000865, 0x00001fed, 0x00000867, 0x00001fee, 0x0000086a, 0x00001fef, 0x0000086d, 0x00001ff2, 0x0000086e, 0x00001ff3, 0x00000871, 0x00001ff4, 0x00000873, 0x00001ff6, 0x00000876, 0x00001ff7, 0x00000878, 0x00001ff8, 0x0000087b, 0x00001ff9, 0x0000087d, 0x00001ffa, 0x0000087f, 0x00001ffb, 0x00000881, 0x00001ffc, 0x00000883, 0x00001ffd, 0x00000885, 0x00001ffe, 0x00000887, 0x00002000, 0x00000889, 0x00002001, 0x0000088a, 0x00002002, 0x0000088b, 0x00002003, 0x0000088c, 0x00002004, 0x0000088d, 0x00002005, 0x0000088e, 0x00002006, 0x0000088f, 0x00002007, 0x00000890, 0x00002008, 0x00000891, 0x00002009, 0x00000892, 0x0000200a, 0x00000893, 0x00002011, 0x00000894, 0x00002017, 0x00000895, 0x00002024, 0x00000897, 0x00002025, 0x00000898, 0x00002026, 0x0000089a, 0x0000202f, 0x0000089d, 0x00002033, 0x0000089e, 0x00002034, 0x000008a0, 0x00002036, 0x000008a3, 0x00002037, 0x000008a5, 0x0000203c, 0x000008a8, 0x0000203e, 0x000008aa, 0x00002047, 0x000008ac, 0x00002048, 0x000008ae, 0x00002049, 0x000008b0, 0x00002057, 0x000008b2, 0x0000205f, 0x000008b6, 0x00002070, 0x000008b7, 0x00002071, 0x000008b8, 0x00002074, 0x000008b9, 0x00002075, 0x000008ba, 0x00002076, 0x000008bb, 0x00002077, 0x000008bc, 0x00002078, 0x000008bd, 0x00002079, 0x000008be, 0x0000207a, 0x000008bf, 0x0000207b, 0x000008c0, 0x0000207c, 0x000008c1, 0x0000207d, 0x000008c2, 0x0000207e, 0x000008c3, 0x0000207f, 0x000008c4, 0x00002080, 0x000008c5, 0x00002081, 0x000008c6, 0x00002082, 0x000008c7, 0x00002083, 0x000008c8, 0x00002084, 0x000008c9, 0x00002085, 0x000008ca, 0x00002086, 0x000008cb, 0x00002087, 0x000008cc, 0x00002088, 0x000008cd, 0x00002089, 0x000008ce, 0x0000208a, 0x000008cf, 0x0000208b, 0x000008d0, 0x0000208c, 0x000008d1, 0x0000208d, 0x000008d2, 0x0000208e, 0x000008d3, 0x000020a8, 0x000008d4, 0x00002100, 0x000008d6, 0x00002101, 0x000008d9, 0x00002102, 0x000008dc, 0x00002103, 0x000008dd, 0x00002105, 0x000008df, 0x00002106, 0x000008e2, 0x00002107, 0x000008e5, 0x00002109, 0x000008e6, 0x0000210a, 0x000008e8, 0x0000210b, 0x000008e9, 0x0000210c, 0x000008ea, 0x0000210d, 0x000008eb, 0x0000210e, 0x000008ec, 0x0000210f, 0x000008ed, 0x00002110, 0x000008ee, 0x00002111, 0x000008ef, 0x00002112, 0x000008f0, 0x00002113, 0x000008f1, 0x00002115, 0x000008f2, 0x00002116, 0x000008f3, 0x00002119, 0x000008f5, 0x0000211a, 0x000008f6, 0x0000211b, 0x000008f7, 0x0000211c, 0x000008f8, 0x0000211d, 0x000008f9, 0x00002120, 0x000008fa, 0x00002121, 0x000008fc, 0x00002122, 0x000008ff, 0x00002124, 0x00000901, 0x00002126, 0x00000902, 0x00002128, 0x00000903, 0x0000212a, 0x00000904, 0x0000212b, 0x00000905, 0x0000212c, 0x00000907, 0x0000212d, 0x00000908, 0x0000212f, 0x00000909, 0x00002130, 0x0000090a, 0x00002131, 0x0000090b, 0x00002133, 0x0000090c, 0x00002134, 0x0000090d, 0x00002135, 0x0000090e, 0x00002136, 0x0000090f, 0x00002137, 0x00000910, 0x00002138, 0x00000911, 0x00002139, 0x00000912, 0x0000213d, 0x00000913, 0x0000213e, 0x00000914, 0x0000213f, 0x00000915, 0x00002140, 0x00000916, 0x00002145, 0x00000917, 0x00002146, 0x00000918, 0x00002147, 0x00000919, 0x00002148, 0x0000091a, 0x00002149, 0x0000091b, 0x00002153, 0x0000091c, 0x00002154, 0x0000091f, 0x00002155, 0x00000922, 0x00002156, 0x00000925, 0x00002157, 0x00000928, 0x00002158, 0x0000092b, 0x00002159, 0x0000092e, 0x0000215a, 0x00000931, 0x0000215b, 0x00000934, 0x0000215c, 0x00000937, 0x0000215d, 0x0000093a, 0x0000215e, 0x0000093d, 0x0000215f, 0x00000940, 0x00002160, 0x00000942, 0x00002161, 0x00000943, 0x00002162, 0x00000945, 0x00002163, 0x00000948, 0x00002164, 0x0000094a, 0x00002165, 0x0000094b, 0x00002166, 0x0000094d, 0x00002167, 0x00000950, 0x00002168, 0x00000954, 0x00002169, 0x00000956, 0x0000216a, 0x00000957, 0x0000216b, 0x00000959, 0x0000216c, 0x0000095c, 0x0000216d, 0x0000095d, 0x0000216e, 0x0000095e, 0x0000216f, 0x0000095f, 0x00002170, 0x00000960, 0x00002171, 0x00000961, 0x00002172, 0x00000963, 0x00002173, 0x00000966, 0x00002174, 0x00000968, 0x00002175, 0x00000969, 0x00002176, 0x0000096b, 0x00002177, 0x0000096e, 0x00002178, 0x00000972, 0x00002179, 0x00000974, 0x0000217a, 0x00000975, 0x0000217b, 0x00000977, 0x0000217c, 0x0000097a, 0x0000217d, 0x0000097b, 0x0000217e, 0x0000097c, 0x0000217f, 0x0000097d, 0x0000219a, 0x0000097e, 0x0000219b, 0x00000980, 0x000021ae, 0x00000982, 0x000021cd, 0x00000984, 0x000021ce, 0x00000986, 0x000021cf, 0x00000988, 0x00002204, 0x0000098a, 0x00002209, 0x0000098c, 0x0000220c, 0x0000098e, 0x00002224, 0x00000990, 0x00002226, 0x00000992, 0x0000222c, 0x00000994, 0x0000222d, 0x00000996, 0x0000222f, 0x00000999, 0x00002230, 0x0000099b, 0x00002241, 0x0000099e, 0x00002244, 0x000009a0, 0x00002247, 0x000009a2, 0x00002249, 0x000009a4, 0x00002260, 0x000009a6, 0x00002262, 0x000009a8, 0x0000226d, 0x000009aa, 0x0000226e, 0x000009ac, 0x0000226f, 0x000009ae, 0x00002270, 0x000009b0, 0x00002271, 0x000009b2, 0x00002274, 0x000009b4, 0x00002275, 0x000009b6, 0x00002278, 0x000009b8, 0x00002279, 0x000009ba, 0x00002280, 0x000009bc, 0x00002281, 0x000009be, 0x00002284, 0x000009c0, 0x00002285, 0x000009c2, 0x00002288, 0x000009c4, 0x00002289, 0x000009c6, 0x000022ac, 0x000009c8, 0x000022ad, 0x000009ca, 0x000022ae, 0x000009cc, 0x000022af, 0x000009ce, 0x000022e0, 0x000009d0, 0x000022e1, 0x000009d2, 0x000022e2, 0x000009d4, 0x000022e3, 0x000009d6, 0x000022ea, 0x000009d8, 0x000022eb, 0x000009da, 0x000022ec, 0x000009dc, 0x000022ed, 0x000009de, 0x00002329, 0x000009e0, 0x0000232a, 0x000009e1, 0x00002460, 0x000009e2, 0x00002461, 0x000009e3, 0x00002462, 0x000009e4, 0x00002463, 0x000009e5, 0x00002464, 0x000009e6, 0x00002465, 0x000009e7, 0x00002466, 0x000009e8, 0x00002467, 0x000009e9, 0x00002468, 0x000009ea, 0x00002469, 0x000009eb, 0x0000246a, 0x000009ed, 0x0000246b, 0x000009ef, 0x0000246c, 0x000009f1, 0x0000246d, 0x000009f3, 0x0000246e, 0x000009f5, 0x0000246f, 0x000009f7, 0x00002470, 0x000009f9, 0x00002471, 0x000009fb, 0x00002472, 0x000009fd, 0x00002473, 0x000009ff, 0x00002474, 0x00000a01, 0x00002475, 0x00000a04, 0x00002476, 0x00000a07, 0x00002477, 0x00000a0a, 0x00002478, 0x00000a0d, 0x00002479, 0x00000a10, 0x0000247a, 0x00000a13, 0x0000247b, 0x00000a16, 0x0000247c, 0x00000a19, 0x0000247d, 0x00000a1c, 0x0000247e, 0x00000a20, 0x0000247f, 0x00000a24, 0x00002480, 0x00000a28, 0x00002481, 0x00000a2c, 0x00002482, 0x00000a30, 0x00002483, 0x00000a34, 0x00002484, 0x00000a38, 0x00002485, 0x00000a3c, 0x00002486, 0x00000a40, 0x00002487, 0x00000a44, 0x00002488, 0x00000a48, 0x00002489, 0x00000a4a, 0x0000248a, 0x00000a4c, 0x0000248b, 0x00000a4e, 0x0000248c, 0x00000a50, 0x0000248d, 0x00000a52, 0x0000248e, 0x00000a54, 0x0000248f, 0x00000a56, 0x00002490, 0x00000a58, 0x00002491, 0x00000a5a, 0x00002492, 0x00000a5d, 0x00002493, 0x00000a60, 0x00002494, 0x00000a63, 0x00002495, 0x00000a66, 0x00002496, 0x00000a69, 0x00002497, 0x00000a6c, 0x00002498, 0x00000a6f, 0x00002499, 0x00000a72, 0x0000249a, 0x00000a75, 0x0000249b, 0x00000a78, 0x0000249c, 0x00000a7b, 0x0000249d, 0x00000a7e, 0x0000249e, 0x00000a81, 0x0000249f, 0x00000a84, 0x000024a0, 0x00000a87, 0x000024a1, 0x00000a8a, 0x000024a2, 0x00000a8d, 0x000024a3, 0x00000a90, 0x000024a4, 0x00000a93, 0x000024a5, 0x00000a96, 0x000024a6, 0x00000a99, 0x000024a7, 0x00000a9c, 0x000024a8, 0x00000a9f, 0x000024a9, 0x00000aa2, 0x000024aa, 0x00000aa5, 0x000024ab, 0x00000aa8, 0x000024ac, 0x00000aab, 0x000024ad, 0x00000aae, 0x000024ae, 0x00000ab1, 0x000024af, 0x00000ab4, 0x000024b0, 0x00000ab7, 0x000024b1, 0x00000aba, 0x000024b2, 0x00000abd, 0x000024b3, 0x00000ac0, 0x000024b4, 0x00000ac3, 0x000024b5, 0x00000ac6, 0x000024b6, 0x00000ac9, 0x000024b7, 0x00000aca, 0x000024b8, 0x00000acb, 0x000024b9, 0x00000acc, 0x000024ba, 0x00000acd, 0x000024bb, 0x00000ace, 0x000024bc, 0x00000acf, 0x000024bd, 0x00000ad0, 0x000024be, 0x00000ad1, 0x000024bf, 0x00000ad2, 0x000024c0, 0x00000ad3, 0x000024c1, 0x00000ad4, 0x000024c2, 0x00000ad5, 0x000024c3, 0x00000ad6, 0x000024c4, 0x00000ad7, 0x000024c5, 0x00000ad8, 0x000024c6, 0x00000ad9, 0x000024c7, 0x00000ada, 0x000024c8, 0x00000adb, 0x000024c9, 0x00000adc, 0x000024ca, 0x00000add, 0x000024cb, 0x00000ade, 0x000024cc, 0x00000adf, 0x000024cd, 0x00000ae0, 0x000024ce, 0x00000ae1, 0x000024cf, 0x00000ae2, 0x000024d0, 0x00000ae3, 0x000024d1, 0x00000ae4, 0x000024d2, 0x00000ae5, 0x000024d3, 0x00000ae6, 0x000024d4, 0x00000ae7, 0x000024d5, 0x00000ae8, 0x000024d6, 0x00000ae9, 0x000024d7, 0x00000aea, 0x000024d8, 0x00000aeb, 0x000024d9, 0x00000aec, 0x000024da, 0x00000aed, 0x000024db, 0x00000aee, 0x000024dc, 0x00000aef, 0x000024dd, 0x00000af0, 0x000024de, 0x00000af1, 0x000024df, 0x00000af2, 0x000024e0, 0x00000af3, 0x000024e1, 0x00000af4, 0x000024e2, 0x00000af5, 0x000024e3, 0x00000af6, 0x000024e4, 0x00000af7, 0x000024e5, 0x00000af8, 0x000024e6, 0x00000af9, 0x000024e7, 0x00000afa, 0x000024e8, 0x00000afb, 0x000024e9, 0x00000afc, 0x000024ea, 0x00000afd, 0x00002a0c, 0x00000afe, 0x00002a74, 0x00000b02, 0x00002a75, 0x00000b05, 0x00002a76, 0x00000b07, 0x00002adc, 0x00000b0a, 0x00002e9f, 0x00000b0c, 0x00002ef3, 0x00000b0d, 0x00002f00, 0x00000b0e, 0x00002f01, 0x00000b0f, 0x00002f02, 0x00000b10, 0x00002f03, 0x00000b11, 0x00002f04, 0x00000b12, 0x00002f05, 0x00000b13, 0x00002f06, 0x00000b14, 0x00002f07, 0x00000b15, 0x00002f08, 0x00000b16, 0x00002f09, 0x00000b17, 0x00002f0a, 0x00000b18, 0x00002f0b, 0x00000b19, 0x00002f0c, 0x00000b1a, 0x00002f0d, 0x00000b1b, 0x00002f0e, 0x00000b1c, 0x00002f0f, 0x00000b1d, 0x00002f10, 0x00000b1e, 0x00002f11, 0x00000b1f, 0x00002f12, 0x00000b20, 0x00002f13, 0x00000b21, 0x00002f14, 0x00000b22, 0x00002f15, 0x00000b23, 0x00002f16, 0x00000b24, 0x00002f17, 0x00000b25, 0x00002f18, 0x00000b26, 0x00002f19, 0x00000b27, 0x00002f1a, 0x00000b28, 0x00002f1b, 0x00000b29, 0x00002f1c, 0x00000b2a, 0x00002f1d, 0x00000b2b, 0x00002f1e, 0x00000b2c, 0x00002f1f, 0x00000b2d, 0x00002f20, 0x00000b2e, 0x00002f21, 0x00000b2f, 0x00002f22, 0x00000b30, 0x00002f23, 0x00000b31, 0x00002f24, 0x00000b32, 0x00002f25, 0x00000b33, 0x00002f26, 0x00000b34, 0x00002f27, 0x00000b35, 0x00002f28, 0x00000b36, 0x00002f29, 0x00000b37, 0x00002f2a, 0x00000b38, 0x00002f2b, 0x00000b39, 0x00002f2c, 0x00000b3a, 0x00002f2d, 0x00000b3b, 0x00002f2e, 0x00000b3c, 0x00002f2f, 0x00000b3d, 0x00002f30, 0x00000b3e, 0x00002f31, 0x00000b3f, 0x00002f32, 0x00000b40, 0x00002f33, 0x00000b41, 0x00002f34, 0x00000b42, 0x00002f35, 0x00000b43, 0x00002f36, 0x00000b44, 0x00002f37, 0x00000b45, 0x00002f38, 0x00000b46, 0x00002f39, 0x00000b47, 0x00002f3a, 0x00000b48, 0x00002f3b, 0x00000b49, 0x00002f3c, 0x00000b4a, 0x00002f3d, 0x00000b4b, 0x00002f3e, 0x00000b4c, 0x00002f3f, 0x00000b4d, 0x00002f40, 0x00000b4e, 0x00002f41, 0x00000b4f, 0x00002f42, 0x00000b50, 0x00002f43, 0x00000b51, 0x00002f44, 0x00000b52, 0x00002f45, 0x00000b53, 0x00002f46, 0x00000b54, 0x00002f47, 0x00000b55, 0x00002f48, 0x00000b56, 0x00002f49, 0x00000b57, 0x00002f4a, 0x00000b58, 0x00002f4b, 0x00000b59, 0x00002f4c, 0x00000b5a, 0x00002f4d, 0x00000b5b, 0x00002f4e, 0x00000b5c, 0x00002f4f, 0x00000b5d, 0x00002f50, 0x00000b5e, 0x00002f51, 0x00000b5f, 0x00002f52, 0x00000b60, 0x00002f53, 0x00000b61, 0x00002f54, 0x00000b62, 0x00002f55, 0x00000b63, 0x00002f56, 0x00000b64, 0x00002f57, 0x00000b65, 0x00002f58, 0x00000b66, 0x00002f59, 0x00000b67, 0x00002f5a, 0x00000b68, 0x00002f5b, 0x00000b69, 0x00002f5c, 0x00000b6a, 0x00002f5d, 0x00000b6b, 0x00002f5e, 0x00000b6c, 0x00002f5f, 0x00000b6d, 0x00002f60, 0x00000b6e, 0x00002f61, 0x00000b6f, 0x00002f62, 0x00000b70, 0x00002f63, 0x00000b71, 0x00002f64, 0x00000b72, 0x00002f65, 0x00000b73, 0x00002f66, 0x00000b74, 0x00002f67, 0x00000b75, 0x00002f68, 0x00000b76, 0x00002f69, 0x00000b77, 0x00002f6a, 0x00000b78, 0x00002f6b, 0x00000b79, 0x00002f6c, 0x00000b7a, 0x00002f6d, 0x00000b7b, 0x00002f6e, 0x00000b7c, 0x00002f6f, 0x00000b7d, 0x00002f70, 0x00000b7e, 0x00002f71, 0x00000b7f, 0x00002f72, 0x00000b80, 0x00002f73, 0x00000b81, 0x00002f74, 0x00000b82, 0x00002f75, 0x00000b83, 0x00002f76, 0x00000b84, 0x00002f77, 0x00000b85, 0x00002f78, 0x00000b86, 0x00002f79, 0x00000b87, 0x00002f7a, 0x00000b88, 0x00002f7b, 0x00000b89, 0x00002f7c, 0x00000b8a, 0x00002f7d, 0x00000b8b, 0x00002f7e, 0x00000b8c, 0x00002f7f, 0x00000b8d, 0x00002f80, 0x00000b8e, 0x00002f81, 0x00000b8f, 0x00002f82, 0x00000b90, 0x00002f83, 0x00000b91, 0x00002f84, 0x00000b92, 0x00002f85, 0x00000b93, 0x00002f86, 0x00000b94, 0x00002f87, 0x00000b95, 0x00002f88, 0x00000b96, 0x00002f89, 0x00000b97, 0x00002f8a, 0x00000b98, 0x00002f8b, 0x00000b99, 0x00002f8c, 0x00000b9a, 0x00002f8d, 0x00000b9b, 0x00002f8e, 0x00000b9c, 0x00002f8f, 0x00000b9d, 0x00002f90, 0x00000b9e, 0x00002f91, 0x00000b9f, 0x00002f92, 0x00000ba0, 0x00002f93, 0x00000ba1, 0x00002f94, 0x00000ba2, 0x00002f95, 0x00000ba3, 0x00002f96, 0x00000ba4, 0x00002f97, 0x00000ba5, 0x00002f98, 0x00000ba6, 0x00002f99, 0x00000ba7, 0x00002f9a, 0x00000ba8, 0x00002f9b, 0x00000ba9, 0x00002f9c, 0x00000baa, 0x00002f9d, 0x00000bab, 0x00002f9e, 0x00000bac, 0x00002f9f, 0x00000bad, 0x00002fa0, 0x00000bae, 0x00002fa1, 0x00000baf, 0x00002fa2, 0x00000bb0, 0x00002fa3, 0x00000bb1, 0x00002fa4, 0x00000bb2, 0x00002fa5, 0x00000bb3, 0x00002fa6, 0x00000bb4, 0x00002fa7, 0x00000bb5, 0x00002fa8, 0x00000bb6, 0x00002fa9, 0x00000bb7, 0x00002faa, 0x00000bb8, 0x00002fab, 0x00000bb9, 0x00002fac, 0x00000bba, 0x00002fad, 0x00000bbb, 0x00002fae, 0x00000bbc, 0x00002faf, 0x00000bbd, 0x00002fb0, 0x00000bbe, 0x00002fb1, 0x00000bbf, 0x00002fb2, 0x00000bc0, 0x00002fb3, 0x00000bc1, 0x00002fb4, 0x00000bc2, 0x00002fb5, 0x00000bc3, 0x00002fb6, 0x00000bc4, 0x00002fb7, 0x00000bc5, 0x00002fb8, 0x00000bc6, 0x00002fb9, 0x00000bc7, 0x00002fba, 0x00000bc8, 0x00002fbb, 0x00000bc9, 0x00002fbc, 0x00000bca, 0x00002fbd, 0x00000bcb, 0x00002fbe, 0x00000bcc, 0x00002fbf, 0x00000bcd, 0x00002fc0, 0x00000bce, 0x00002fc1, 0x00000bcf, 0x00002fc2, 0x00000bd0, 0x00002fc3, 0x00000bd1, 0x00002fc4, 0x00000bd2, 0x00002fc5, 0x00000bd3, 0x00002fc6, 0x00000bd4, 0x00002fc7, 0x00000bd5, 0x00002fc8, 0x00000bd6, 0x00002fc9, 0x00000bd7, 0x00002fca, 0x00000bd8, 0x00002fcb, 0x00000bd9, 0x00002fcc, 0x00000bda, 0x00002fcd, 0x00000bdb, 0x00002fce, 0x00000bdc, 0x00002fcf, 0x00000bdd, 0x00002fd0, 0x00000bde, 0x00002fd1, 0x00000bdf, 0x00002fd2, 0x00000be0, 0x00002fd3, 0x00000be1, 0x00002fd4, 0x00000be2, 0x00002fd5, 0x00000be3, 0x00003000, 0x00000be4, 0x00003036, 0x00000be5, 0x00003038, 0x00000be6, 0x00003039, 0x00000be7, 0x0000303a, 0x00000be8, 0x0000304c, 0x00000be9, 0x0000304e, 0x00000beb, 0x00003050, 0x00000bed, 0x00003052, 0x00000bef, 0x00003054, 0x00000bf1, 0x00003056, 0x00000bf3, 0x00003058, 0x00000bf5, 0x0000305a, 0x00000bf7, 0x0000305c, 0x00000bf9, 0x0000305e, 0x00000bfb, 0x00003060, 0x00000bfd, 0x00003062, 0x00000bff, 0x00003065, 0x00000c01, 0x00003067, 0x00000c03, 0x00003069, 0x00000c05, 0x00003070, 0x00000c07, 0x00003071, 0x00000c09, 0x00003073, 0x00000c0b, 0x00003074, 0x00000c0d, 0x00003076, 0x00000c0f, 0x00003077, 0x00000c11, 0x00003079, 0x00000c13, 0x0000307a, 0x00000c15, 0x0000307c, 0x00000c17, 0x0000307d, 0x00000c19, 0x00003094, 0x00000c1b, 0x0000309b, 0x00000c1d, 0x0000309c, 0x00000c1f, 0x0000309e, 0x00000c21, 0x0000309f, 0x00000c23, 0x000030ac, 0x00000c25, 0x000030ae, 0x00000c27, 0x000030b0, 0x00000c29, 0x000030b2, 0x00000c2b, 0x000030b4, 0x00000c2d, 0x000030b6, 0x00000c2f, 0x000030b8, 0x00000c31, 0x000030ba, 0x00000c33, 0x000030bc, 0x00000c35, 0x000030be, 0x00000c37, 0x000030c0, 0x00000c39, 0x000030c2, 0x00000c3b, 0x000030c5, 0x00000c3d, 0x000030c7, 0x00000c3f, 0x000030c9, 0x00000c41, 0x000030d0, 0x00000c43, 0x000030d1, 0x00000c45, 0x000030d3, 0x00000c47, 0x000030d4, 0x00000c49, 0x000030d6, 0x00000c4b, 0x000030d7, 0x00000c4d, 0x000030d9, 0x00000c4f, 0x000030da, 0x00000c51, 0x000030dc, 0x00000c53, 0x000030dd, 0x00000c55, 0x000030f4, 0x00000c57, 0x000030f7, 0x00000c59, 0x000030f8, 0x00000c5b, 0x000030f9, 0x00000c5d, 0x000030fa, 0x00000c5f, 0x000030fe, 0x00000c61, 0x000030ff, 0x00000c63, 0x00003131, 0x00000c65, 0x00003132, 0x00000c66, 0x00003133, 0x00000c67, 0x00003134, 0x00000c68, 0x00003135, 0x00000c69, 0x00003136, 0x00000c6a, 0x00003137, 0x00000c6b, 0x00003138, 0x00000c6c, 0x00003139, 0x00000c6d, 0x0000313a, 0x00000c6e, 0x0000313b, 0x00000c6f, 0x0000313c, 0x00000c70, 0x0000313d, 0x00000c71, 0x0000313e, 0x00000c72, 0x0000313f, 0x00000c73, 0x00003140, 0x00000c74, 0x00003141, 0x00000c75, 0x00003142, 0x00000c76, 0x00003143, 0x00000c77, 0x00003144, 0x00000c78, 0x00003145, 0x00000c79, 0x00003146, 0x00000c7a, 0x00003147, 0x00000c7b, 0x00003148, 0x00000c7c, 0x00003149, 0x00000c7d, 0x0000314a, 0x00000c7e, 0x0000314b, 0x00000c7f, 0x0000314c, 0x00000c80, 0x0000314d, 0x00000c81, 0x0000314e, 0x00000c82, 0x0000314f, 0x00000c83, 0x00003150, 0x00000c84, 0x00003151, 0x00000c85, 0x00003152, 0x00000c86, 0x00003153, 0x00000c87, 0x00003154, 0x00000c88, 0x00003155, 0x00000c89, 0x00003156, 0x00000c8a, 0x00003157, 0x00000c8b, 0x00003158, 0x00000c8c, 0x00003159, 0x00000c8d, 0x0000315a, 0x00000c8e, 0x0000315b, 0x00000c8f, 0x0000315c, 0x00000c90, 0x0000315d, 0x00000c91, 0x0000315e, 0x00000c92, 0x0000315f, 0x00000c93, 0x00003160, 0x00000c94, 0x00003161, 0x00000c95, 0x00003162, 0x00000c96, 0x00003163, 0x00000c97, 0x00003164, 0x00000c98, 0x00003165, 0x00000c99, 0x00003166, 0x00000c9a, 0x00003167, 0x00000c9b, 0x00003168, 0x00000c9c, 0x00003169, 0x00000c9d, 0x0000316a, 0x00000c9e, 0x0000316b, 0x00000c9f, 0x0000316c, 0x00000ca0, 0x0000316d, 0x00000ca1, 0x0000316e, 0x00000ca2, 0x0000316f, 0x00000ca3, 0x00003170, 0x00000ca4, 0x00003171, 0x00000ca5, 0x00003172, 0x00000ca6, 0x00003173, 0x00000ca7, 0x00003174, 0x00000ca8, 0x00003175, 0x00000ca9, 0x00003176, 0x00000caa, 0x00003177, 0x00000cab, 0x00003178, 0x00000cac, 0x00003179, 0x00000cad, 0x0000317a, 0x00000cae, 0x0000317b, 0x00000caf, 0x0000317c, 0x00000cb0, 0x0000317d, 0x00000cb1, 0x0000317e, 0x00000cb2, 0x0000317f, 0x00000cb3, 0x00003180, 0x00000cb4, 0x00003181, 0x00000cb5, 0x00003182, 0x00000cb6, 0x00003183, 0x00000cb7, 0x00003184, 0x00000cb8, 0x00003185, 0x00000cb9, 0x00003186, 0x00000cba, 0x00003187, 0x00000cbb, 0x00003188, 0x00000cbc, 0x00003189, 0x00000cbd, 0x0000318a, 0x00000cbe, 0x0000318b, 0x00000cbf, 0x0000318c, 0x00000cc0, 0x0000318d, 0x00000cc1, 0x0000318e, 0x00000cc2, 0x00003192, 0x00000cc3, 0x00003193, 0x00000cc4, 0x00003194, 0x00000cc5, 0x00003195, 0x00000cc6, 0x00003196, 0x00000cc7, 0x00003197, 0x00000cc8, 0x00003198, 0x00000cc9, 0x00003199, 0x00000cca, 0x0000319a, 0x00000ccb, 0x0000319b, 0x00000ccc, 0x0000319c, 0x00000ccd, 0x0000319d, 0x00000cce, 0x0000319e, 0x00000ccf, 0x0000319f, 0x00000cd0, 0x00003200, 0x00000cd1, 0x00003201, 0x00000cd4, 0x00003202, 0x00000cd7, 0x00003203, 0x00000cda, 0x00003204, 0x00000cdd, 0x00003205, 0x00000ce0, 0x00003206, 0x00000ce3, 0x00003207, 0x00000ce6, 0x00003208, 0x00000ce9, 0x00003209, 0x00000cec, 0x0000320a, 0x00000cef, 0x0000320b, 0x00000cf2, 0x0000320c, 0x00000cf5, 0x0000320d, 0x00000cf8, 0x0000320e, 0x00000cfb, 0x0000320f, 0x00000cff, 0x00003210, 0x00000d03, 0x00003211, 0x00000d07, 0x00003212, 0x00000d0b, 0x00003213, 0x00000d0f, 0x00003214, 0x00000d13, 0x00003215, 0x00000d17, 0x00003216, 0x00000d1b, 0x00003217, 0x00000d1f, 0x00003218, 0x00000d23, 0x00003219, 0x00000d27, 0x0000321a, 0x00000d2b, 0x0000321b, 0x00000d2f, 0x0000321c, 0x00000d33, 0x00003220, 0x00000d37, 0x00003221, 0x00000d3a, 0x00003222, 0x00000d3d, 0x00003223, 0x00000d40, 0x00003224, 0x00000d43, 0x00003225, 0x00000d46, 0x00003226, 0x00000d49, 0x00003227, 0x00000d4c, 0x00003228, 0x00000d4f, 0x00003229, 0x00000d52, 0x0000322a, 0x00000d55, 0x0000322b, 0x00000d58, 0x0000322c, 0x00000d5b, 0x0000322d, 0x00000d5e, 0x0000322e, 0x00000d61, 0x0000322f, 0x00000d64, 0x00003230, 0x00000d67, 0x00003231, 0x00000d6a, 0x00003232, 0x00000d6d, 0x00003233, 0x00000d70, 0x00003234, 0x00000d73, 0x00003235, 0x00000d76, 0x00003236, 0x00000d79, 0x00003237, 0x00000d7c, 0x00003238, 0x00000d7f, 0x00003239, 0x00000d82, 0x0000323a, 0x00000d85, 0x0000323b, 0x00000d88, 0x0000323c, 0x00000d8b, 0x0000323d, 0x00000d8e, 0x0000323e, 0x00000d91, 0x0000323f, 0x00000d94, 0x00003240, 0x00000d97, 0x00003241, 0x00000d9a, 0x00003242, 0x00000d9d, 0x00003243, 0x00000da0, 0x00003251, 0x00000da3, 0x00003252, 0x00000da5, 0x00003253, 0x00000da7, 0x00003254, 0x00000da9, 0x00003255, 0x00000dab, 0x00003256, 0x00000dad, 0x00003257, 0x00000daf, 0x00003258, 0x00000db1, 0x00003259, 0x00000db3, 0x0000325a, 0x00000db5, 0x0000325b, 0x00000db7, 0x0000325c, 0x00000db9, 0x0000325d, 0x00000dbb, 0x0000325e, 0x00000dbd, 0x0000325f, 0x00000dbf, 0x00003260, 0x00000dc1, 0x00003261, 0x00000dc2, 0x00003262, 0x00000dc3, 0x00003263, 0x00000dc4, 0x00003264, 0x00000dc5, 0x00003265, 0x00000dc6, 0x00003266, 0x00000dc7, 0x00003267, 0x00000dc8, 0x00003268, 0x00000dc9, 0x00003269, 0x00000dca, 0x0000326a, 0x00000dcb, 0x0000326b, 0x00000dcc, 0x0000326c, 0x00000dcd, 0x0000326d, 0x00000dce, 0x0000326e, 0x00000dcf, 0x0000326f, 0x00000dd1, 0x00003270, 0x00000dd3, 0x00003271, 0x00000dd5, 0x00003272, 0x00000dd7, 0x00003273, 0x00000dd9, 0x00003274, 0x00000ddb, 0x00003275, 0x00000ddd, 0x00003276, 0x00000ddf, 0x00003277, 0x00000de1, 0x00003278, 0x00000de3, 0x00003279, 0x00000de5, 0x0000327a, 0x00000de7, 0x0000327b, 0x00000de9, 0x00003280, 0x00000deb, 0x00003281, 0x00000dec, 0x00003282, 0x00000ded, 0x00003283, 0x00000dee, 0x00003284, 0x00000def, 0x00003285, 0x00000df0, 0x00003286, 0x00000df1, 0x00003287, 0x00000df2, 0x00003288, 0x00000df3, 0x00003289, 0x00000df4, 0x0000328a, 0x00000df5, 0x0000328b, 0x00000df6, 0x0000328c, 0x00000df7, 0x0000328d, 0x00000df8, 0x0000328e, 0x00000df9, 0x0000328f, 0x00000dfa, 0x00003290, 0x00000dfb, 0x00003291, 0x00000dfc, 0x00003292, 0x00000dfd, 0x00003293, 0x00000dfe, 0x00003294, 0x00000dff, 0x00003295, 0x00000e00, 0x00003296, 0x00000e01, 0x00003297, 0x00000e02, 0x00003298, 0x00000e03, 0x00003299, 0x00000e04, 0x0000329a, 0x00000e05, 0x0000329b, 0x00000e06, 0x0000329c, 0x00000e07, 0x0000329d, 0x00000e08, 0x0000329e, 0x00000e09, 0x0000329f, 0x00000e0a, 0x000032a0, 0x00000e0b, 0x000032a1, 0x00000e0c, 0x000032a2, 0x00000e0d, 0x000032a3, 0x00000e0e, 0x000032a4, 0x00000e0f, 0x000032a5, 0x00000e10, 0x000032a6, 0x00000e11, 0x000032a7, 0x00000e12, 0x000032a8, 0x00000e13, 0x000032a9, 0x00000e14, 0x000032aa, 0x00000e15, 0x000032ab, 0x00000e16, 0x000032ac, 0x00000e17, 0x000032ad, 0x00000e18, 0x000032ae, 0x00000e19, 0x000032af, 0x00000e1a, 0x000032b0, 0x00000e1b, 0x000032b1, 0x00000e1c, 0x000032b2, 0x00000e1e, 0x000032b3, 0x00000e20, 0x000032b4, 0x00000e22, 0x000032b5, 0x00000e24, 0x000032b6, 0x00000e26, 0x000032b7, 0x00000e28, 0x000032b8, 0x00000e2a, 0x000032b9, 0x00000e2c, 0x000032ba, 0x00000e2e, 0x000032bb, 0x00000e30, 0x000032bc, 0x00000e32, 0x000032bd, 0x00000e34, 0x000032be, 0x00000e36, 0x000032bf, 0x00000e38, 0x000032c0, 0x00000e3a, 0x000032c1, 0x00000e3c, 0x000032c2, 0x00000e3e, 0x000032c3, 0x00000e40, 0x000032c4, 0x00000e42, 0x000032c5, 0x00000e44, 0x000032c6, 0x00000e46, 0x000032c7, 0x00000e48, 0x000032c8, 0x00000e4a, 0x000032c9, 0x00000e4c, 0x000032ca, 0x00000e4f, 0x000032cb, 0x00000e52, 0x000032d0, 0x00000e55, 0x000032d1, 0x00000e56, 0x000032d2, 0x00000e57, 0x000032d3, 0x00000e58, 0x000032d4, 0x00000e59, 0x000032d5, 0x00000e5a, 0x000032d6, 0x00000e5b, 0x000032d7, 0x00000e5c, 0x000032d8, 0x00000e5d, 0x000032d9, 0x00000e5e, 0x000032da, 0x00000e5f, 0x000032db, 0x00000e60, 0x000032dc, 0x00000e61, 0x000032dd, 0x00000e62, 0x000032de, 0x00000e63, 0x000032df, 0x00000e64, 0x000032e0, 0x00000e65, 0x000032e1, 0x00000e66, 0x000032e2, 0x00000e67, 0x000032e3, 0x00000e68, 0x000032e4, 0x00000e69, 0x000032e5, 0x00000e6a, 0x000032e6, 0x00000e6b, 0x000032e7, 0x00000e6c, 0x000032e8, 0x00000e6d, 0x000032e9, 0x00000e6e, 0x000032ea, 0x00000e6f, 0x000032eb, 0x00000e70, 0x000032ec, 0x00000e71, 0x000032ed, 0x00000e72, 0x000032ee, 0x00000e73, 0x000032ef, 0x00000e74, 0x000032f0, 0x00000e75, 0x000032f1, 0x00000e76, 0x000032f2, 0x00000e77, 0x000032f3, 0x00000e78, 0x000032f4, 0x00000e79, 0x000032f5, 0x00000e7a, 0x000032f6, 0x00000e7b, 0x000032f7, 0x00000e7c, 0x000032f8, 0x00000e7d, 0x000032f9, 0x00000e7e, 0x000032fa, 0x00000e7f, 0x000032fb, 0x00000e80, 0x000032fc, 0x00000e81, 0x000032fd, 0x00000e82, 0x000032fe, 0x00000e83, 0x00003300, 0x00000e84, 0x00003301, 0x00000e89, 0x00003302, 0x00000e8d, 0x00003303, 0x00000e92, 0x00003304, 0x00000e95, 0x00003305, 0x00000e9a, 0x00003306, 0x00000e9d, 0x00003307, 0x00000ea0, 0x00003308, 0x00000ea6, 0x00003309, 0x00000eaa, 0x0000330a, 0x00000ead, 0x0000330b, 0x00000eb0, 0x0000330c, 0x00000eb3, 0x0000330d, 0x00000eb7, 0x0000330e, 0x00000ebb, 0x0000330f, 0x00000ebf, 0x00003310, 0x00000ec3, 0x00003311, 0x00000ec7, 0x00003312, 0x00000ecb, 0x00003313, 0x00000ecf, 0x00003314, 0x00000ed5, 0x00003315, 0x00000ed7, 0x00003316, 0x00000edd, 0x00003317, 0x00000ee3, 0x00003318, 0x00000ee8, 0x00003319, 0x00000eec, 0x0000331a, 0x00000ef2, 0x0000331b, 0x00000ef8, 0x0000331c, 0x00000efc, 0x0000331d, 0x00000eff, 0x0000331e, 0x00000f02, 0x0000331f, 0x00000f06, 0x00003320, 0x00000f0a, 0x00003321, 0x00000f0f, 0x00003322, 0x00000f14, 0x00003323, 0x00000f17, 0x00003324, 0x00000f1a, 0x00003325, 0x00000f1e, 0x00003326, 0x00000f21, 0x00003327, 0x00000f24, 0x00003328, 0x00000f26, 0x00003329, 0x00000f28, 0x0000332a, 0x00000f2b, 0x0000332b, 0x00000f2e, 0x0000332c, 0x00000f34, 0x0000332d, 0x00000f38, 0x0000332e, 0x00000f3d, 0x0000332f, 0x00000f43, 0x00003330, 0x00000f47, 0x00003331, 0x00000f4a, 0x00003332, 0x00000f4d, 0x00003333, 0x00000f53, 0x00003334, 0x00000f57, 0x00003335, 0x00000f5d, 0x00003336, 0x00000f60, 0x00003337, 0x00000f65, 0x00003338, 0x00000f68, 0x00003339, 0x00000f6c, 0x0000333a, 0x00000f6f, 0x0000333b, 0x00000f73, 0x0000333c, 0x00000f78, 0x0000333d, 0x00000f7c, 0x0000333e, 0x00000f81, 0x0000333f, 0x00000f85, 0x00003340, 0x00000f87, 0x00003341, 0x00000f8c, 0x00003342, 0x00000f8f, 0x00003343, 0x00000f92, 0x00003344, 0x00000f96, 0x00003345, 0x00000f99, 0x00003346, 0x00000f9c, 0x00003347, 0x00000f9f, 0x00003348, 0x00000fa4, 0x00003349, 0x00000fa8, 0x0000334a, 0x00000faa, 0x0000334b, 0x00000fb0, 0x0000334c, 0x00000fb3, 0x0000334d, 0x00000fb8, 0x0000334e, 0x00000fbc, 0x0000334f, 0x00000fc0, 0x00003350, 0x00000fc3, 0x00003351, 0x00000fc6, 0x00003352, 0x00000fca, 0x00003353, 0x00000fcc, 0x00003354, 0x00000fd0, 0x00003355, 0x00000fd5, 0x00003356, 0x00000fd7, 0x00003357, 0x00000fdd, 0x00003358, 0x00000fe0, 0x00003359, 0x00000fe2, 0x0000335a, 0x00000fe4, 0x0000335b, 0x00000fe6, 0x0000335c, 0x00000fe8, 0x0000335d, 0x00000fea, 0x0000335e, 0x00000fec, 0x0000335f, 0x00000fee, 0x00003360, 0x00000ff0, 0x00003361, 0x00000ff2, 0x00003362, 0x00000ff4, 0x00003363, 0x00000ff7, 0x00003364, 0x00000ffa, 0x00003365, 0x00000ffd, 0x00003366, 0x00001000, 0x00003367, 0x00001003, 0x00003368, 0x00001006, 0x00003369, 0x00001009, 0x0000336a, 0x0000100c, 0x0000336b, 0x0000100f, 0x0000336c, 0x00001012, 0x0000336d, 0x00001015, 0x0000336e, 0x00001018, 0x0000336f, 0x0000101b, 0x00003370, 0x0000101e, 0x00003371, 0x00001021, 0x00003372, 0x00001024, 0x00003373, 0x00001026, 0x00003374, 0x00001028, 0x00003375, 0x0000102b, 0x00003376, 0x0000102d, 0x0000337b, 0x0000102f, 0x0000337c, 0x00001031, 0x0000337d, 0x00001033, 0x0000337e, 0x00001035, 0x0000337f, 0x00001037, 0x00003380, 0x0000103b, 0x00003381, 0x0000103d, 0x00003382, 0x0000103f, 0x00003383, 0x00001041, 0x00003384, 0x00001043, 0x00003385, 0x00001045, 0x00003386, 0x00001047, 0x00003387, 0x00001049, 0x00003388, 0x0000104b, 0x00003389, 0x0000104e, 0x0000338a, 0x00001052, 0x0000338b, 0x00001054, 0x0000338c, 0x00001056, 0x0000338d, 0x00001058, 0x0000338e, 0x0000105a, 0x0000338f, 0x0000105c, 0x00003390, 0x0000105e, 0x00003391, 0x00001060, 0x00003392, 0x00001063, 0x00003393, 0x00001066, 0x00003394, 0x00001069, 0x00003395, 0x0000106c, 0x00003396, 0x0000106e, 0x00003397, 0x00001070, 0x00003398, 0x00001072, 0x00003399, 0x00001074, 0x0000339a, 0x00001076, 0x0000339b, 0x00001078, 0x0000339c, 0x0000107a, 0x0000339d, 0x0000107c, 0x0000339e, 0x0000107e, 0x0000339f, 0x00001080, 0x000033a0, 0x00001083, 0x000033a1, 0x00001086, 0x000033a2, 0x00001088, 0x000033a3, 0x0000108b, 0x000033a4, 0x0000108e, 0x000033a5, 0x00001091, 0x000033a6, 0x00001093, 0x000033a7, 0x00001096, 0x000033a8, 0x00001099, 0x000033a9, 0x0000109d, 0x000033aa, 0x0000109f, 0x000033ab, 0x000010a2, 0x000033ac, 0x000010a5, 0x000033ad, 0x000010a8, 0x000033ae, 0x000010ab, 0x000033af, 0x000010b0, 0x000033b0, 0x000010b6, 0x000033b1, 0x000010b8, 0x000033b2, 0x000010ba, 0x000033b3, 0x000010bc, 0x000033b4, 0x000010be, 0x000033b5, 0x000010c0, 0x000033b6, 0x000010c2, 0x000033b7, 0x000010c4, 0x000033b8, 0x000010c6, 0x000033b9, 0x000010c8, 0x000033ba, 0x000010ca, 0x000033bb, 0x000010cc, 0x000033bc, 0x000010ce, 0x000033bd, 0x000010d0, 0x000033be, 0x000010d2, 0x000033bf, 0x000010d4, 0x000033c0, 0x000010d6, 0x000033c1, 0x000010d8, 0x000033c2, 0x000010da, 0x000033c3, 0x000010de, 0x000033c4, 0x000010e0, 0x000033c5, 0x000010e2, 0x000033c6, 0x000010e4, 0x000033c7, 0x000010e8, 0x000033c8, 0x000010eb, 0x000033c9, 0x000010ed, 0x000033ca, 0x000010ef, 0x000033cb, 0x000010f1, 0x000033cc, 0x000010f3, 0x000033cd, 0x000010f5, 0x000033ce, 0x000010f7, 0x000033cf, 0x000010f9, 0x000033d0, 0x000010fb, 0x000033d1, 0x000010fd, 0x000033d2, 0x000010ff, 0x000033d3, 0x00001102, 0x000033d4, 0x00001104, 0x000033d5, 0x00001106, 0x000033d6, 0x00001109, 0x000033d7, 0x0000110c, 0x000033d8, 0x0000110e, 0x000033d9, 0x00001112, 0x000033da, 0x00001115, 0x000033db, 0x00001117, 0x000033dc, 0x00001119, 0x000033dd, 0x0000111b, 0x000033e0, 0x0000111d, 0x000033e1, 0x0000111f, 0x000033e2, 0x00001121, 0x000033e3, 0x00001123, 0x000033e4, 0x00001125, 0x000033e5, 0x00001127, 0x000033e6, 0x00001129, 0x000033e7, 0x0000112b, 0x000033e8, 0x0000112d, 0x000033e9, 0x0000112f, 0x000033ea, 0x00001132, 0x000033eb, 0x00001135, 0x000033ec, 0x00001138, 0x000033ed, 0x0000113b, 0x000033ee, 0x0000113e, 0x000033ef, 0x00001141, 0x000033f0, 0x00001144, 0x000033f1, 0x00001147, 0x000033f2, 0x0000114a, 0x000033f3, 0x0000114d, 0x000033f4, 0x00001150, 0x000033f5, 0x00001153, 0x000033f6, 0x00001156, 0x000033f7, 0x00001159, 0x000033f8, 0x0000115c, 0x000033f9, 0x0000115f, 0x000033fa, 0x00001162, 0x000033fb, 0x00001165, 0x000033fc, 0x00001168, 0x000033fd, 0x0000116b, 0x000033fe, 0x0000116e, 0x0000f902, 0x00001171, 0x0000f903, 0x00001172, 0x0000f904, 0x00001173, 0x0000f905, 0x00001174, 0x0000f906, 0x00001175, 0x0000f907, 0x00001176, 0x0000f908, 0x00001177, 0x0000f909, 0x00001178, 0x0000f90a, 0x00001179, 0x0000f90b, 0x0000117a, 0x0000f90c, 0x0000117b, 0x0000f90d, 0x0000117c, 0x0000f90e, 0x0000117d, 0x0000f90f, 0x0000117e, 0x0000f910, 0x0000117f, 0x0000f911, 0x00001180, 0x0000f912, 0x00001181, 0x0000f913, 0x00001182, 0x0000f914, 0x00001183, 0x0000f915, 0x00001184, 0x0000f916, 0x00001185, 0x0000f917, 0x00001186, 0x0000f918, 0x00001187, 0x0000f919, 0x00001188, 0x0000f91a, 0x00001189, 0x0000f91b, 0x0000118a, 0x0000f91c, 0x0000118b, 0x0000f91d, 0x0000118c, 0x0000f91e, 0x0000118d, 0x0000f91f, 0x0000118e, 0x0000f920, 0x0000118f, 0x0000f921, 0x00001190, 0x0000f922, 0x00001191, 0x0000f923, 0x00001192, 0x0000f924, 0x00001193, 0x0000f925, 0x00001194, 0x0000f926, 0x00001195, 0x0000f927, 0x00001196, 0x0000f928, 0x00001197, 0x0000f929, 0x00001198, 0x0000f92a, 0x00001199, 0x0000f92b, 0x0000119a, 0x0000f92c, 0x0000119b, 0x0000f92d, 0x0000119c, 0x0000f92e, 0x0000119d, 0x0000f92f, 0x0000119e, 0x0000f930, 0x0000119f, 0x0000f931, 0x000011a0, 0x0000f932, 0x000011a1, 0x0000f933, 0x000011a2, 0x0000f934, 0x000011a3, 0x0000f935, 0x000011a4, 0x0000f936, 0x000011a5, 0x0000f937, 0x000011a6, 0x0000f938, 0x000011a7, 0x0000f939, 0x000011a8, 0x0000f93a, 0x000011a9, 0x0000f93b, 0x000011aa, 0x0000f93c, 0x000011ab, 0x0000f93d, 0x000011ac, 0x0000f93e, 0x000011ad, 0x0000f93f, 0x000011ae, 0x0000f940, 0x000011af, 0x0000f941, 0x000011b0, 0x0000f942, 0x000011b1, 0x0000f943, 0x000011b2, 0x0000f944, 0x000011b3, 0x0000f945, 0x000011b4, 0x0000f946, 0x000011b5, 0x0000f947, 0x000011b6, 0x0000f948, 0x000011b7, 0x0000f949, 0x000011b8, 0x0000f94a, 0x000011b9, 0x0000f94b, 0x000011ba, 0x0000f94c, 0x000011bb, 0x0000f94d, 0x000011bc, 0x0000f94e, 0x000011bd, 0x0000f94f, 0x000011be, 0x0000f950, 0x000011bf, 0x0000f951, 0x000011c0, 0x0000f952, 0x000011c1, 0x0000f953, 0x000011c2, 0x0000f954, 0x000011c3, 0x0000f955, 0x000011c4, 0x0000f956, 0x000011c5, 0x0000f957, 0x000011c6, 0x0000f958, 0x000011c7, 0x0000f959, 0x000011c8, 0x0000f95a, 0x000011c9, 0x0000f95b, 0x000011ca, 0x0000f95c, 0x000011cb, 0x0000f95d, 0x000011cc, 0x0000f95e, 0x000011cd, 0x0000f95f, 0x000011ce, 0x0000f960, 0x000011cf, 0x0000f961, 0x000011d0, 0x0000f962, 0x000011d1, 0x0000f963, 0x000011d2, 0x0000f964, 0x000011d3, 0x0000f965, 0x000011d4, 0x0000f966, 0x000011d5, 0x0000f967, 0x000011d6, 0x0000f968, 0x000011d7, 0x0000f969, 0x000011d8, 0x0000f96a, 0x000011d9, 0x0000f96b, 0x000011da, 0x0000f96c, 0x000011db, 0x0000f96d, 0x000011dc, 0x0000f96e, 0x000011dd, 0x0000f96f, 0x000011de, 0x0000f970, 0x000011df, 0x0000f971, 0x000011e0, 0x0000f972, 0x000011e1, 0x0000f973, 0x000011e2, 0x0000f974, 0x000011e3, 0x0000f975, 0x000011e4, 0x0000f976, 0x000011e5, 0x0000f977, 0x000011e6, 0x0000f978, 0x000011e7, 0x0000f979, 0x000011e8, 0x0000f97a, 0x000011e9, 0x0000f97b, 0x000011ea, 0x0000f97c, 0x000011eb, 0x0000f97d, 0x000011ec, 0x0000f97e, 0x000011ed, 0x0000f97f, 0x000011ee, 0x0000f980, 0x000011ef, 0x0000f981, 0x000011f0, 0x0000f982, 0x000011f1, 0x0000f983, 0x000011f2, 0x0000f984, 0x000011f3, 0x0000f985, 0x000011f4, 0x0000f986, 0x000011f5, 0x0000f987, 0x000011f6, 0x0000f988, 0x000011f7, 0x0000f989, 0x000011f8, 0x0000f98a, 0x000011f9, 0x0000f98b, 0x000011fa, 0x0000f98c, 0x000011fb, 0x0000f98d, 0x000011fc, 0x0000f98e, 0x000011fd, 0x0000f98f, 0x000011fe, 0x0000f990, 0x000011ff, 0x0000f991, 0x00001200, 0x0000f992, 0x00001201, 0x0000f993, 0x00001202, 0x0000f994, 0x00001203, 0x0000f995, 0x00001204, 0x0000f996, 0x00001205, 0x0000f997, 0x00001206, 0x0000f998, 0x00001207, 0x0000f999, 0x00001208, 0x0000f99a, 0x00001209, 0x0000f99b, 0x0000120a, 0x0000f99c, 0x0000120b, 0x0000f99d, 0x0000120c, 0x0000f99e, 0x0000120d, 0x0000f99f, 0x0000120e, 0x0000f9a0, 0x0000120f, 0x0000f9a1, 0x00001210, 0x0000f9a2, 0x00001211, 0x0000f9a3, 0x00001212, 0x0000f9a4, 0x00001213, 0x0000f9a5, 0x00001214, 0x0000f9a6, 0x00001215, 0x0000f9a7, 0x00001216, 0x0000f9a8, 0x00001217, 0x0000f9a9, 0x00001218, 0x0000f9aa, 0x00001219, 0x0000f9ab, 0x0000121a, 0x0000f9ac, 0x0000121b, 0x0000f9ad, 0x0000121c, 0x0000f9ae, 0x0000121d, 0x0000f9af, 0x0000121e, 0x0000f9b0, 0x0000121f, 0x0000f9b1, 0x00001220, 0x0000f9b2, 0x00001221, 0x0000f9b3, 0x00001222, 0x0000f9b4, 0x00001223, 0x0000f9b5, 0x00001224, 0x0000f9b6, 0x00001225, 0x0000f9b7, 0x00001226, 0x0000f9b8, 0x00001227, 0x0000f9b9, 0x00001228, 0x0000f9ba, 0x00001229, 0x0000f9bb, 0x0000122a, 0x0000f9bc, 0x0000122b, 0x0000f9bd, 0x0000122c, 0x0000f9be, 0x0000122d, 0x0000f9bf, 0x0000122e, 0x0000f9c0, 0x0000122f, 0x0000f9c1, 0x00001230, 0x0000f9c2, 0x00001231, 0x0000f9c3, 0x00001232, 0x0000f9c4, 0x00001233, 0x0000f9c5, 0x00001234, 0x0000f9c6, 0x00001235, 0x0000f9c7, 0x00001236, 0x0000f9c8, 0x00001237, 0x0000f9c9, 0x00001238, 0x0000f9ca, 0x00001239, 0x0000f9cb, 0x0000123a, 0x0000f9cc, 0x0000123b, 0x0000f9cd, 0x0000123c, 0x0000f9ce, 0x0000123d, 0x0000f9cf, 0x0000123e, 0x0000f9d0, 0x0000123f, 0x0000f9d1, 0x00001240, 0x0000f9d2, 0x00001241, 0x0000f9d3, 0x00001242, 0x0000f9d4, 0x00001243, 0x0000f9d5, 0x00001244, 0x0000f9d6, 0x00001245, 0x0000f9d7, 0x00001246, 0x0000f9d8, 0x00001247, 0x0000f9d9, 0x00001248, 0x0000f9da, 0x00001249, 0x0000f9db, 0x0000124a, 0x0000f9dc, 0x0000124b, 0x0000f9dd, 0x0000124c, 0x0000f9de, 0x0000124d, 0x0000f9df, 0x0000124e, 0x0000f9e0, 0x0000124f, 0x0000f9e1, 0x00001250, 0x0000f9e2, 0x00001251, 0x0000f9e3, 0x00001252, 0x0000f9e4, 0x00001253, 0x0000f9e5, 0x00001254, 0x0000f9e6, 0x00001255, 0x0000f9e7, 0x00001256, 0x0000f9e8, 0x00001257, 0x0000f9e9, 0x00001258, 0x0000f9ea, 0x00001259, 0x0000f9eb, 0x0000125a, 0x0000f9ec, 0x0000125b, 0x0000f9ed, 0x0000125c, 0x0000f9ee, 0x0000125d, 0x0000f9ef, 0x0000125e, 0x0000f9f0, 0x0000125f, 0x0000f9f1, 0x00001260, 0x0000f9f2, 0x00001261, 0x0000f9f3, 0x00001262, 0x0000f9f4, 0x00001263, 0x0000f9f5, 0x00001264, 0x0000f9f6, 0x00001265, 0x0000f9f7, 0x00001266, 0x0000f9f8, 0x00001267, 0x0000f9f9, 0x00001268, 0x0000f9fa, 0x00001269, 0x0000f9fb, 0x0000126a, 0x0000f9fc, 0x0000126b, 0x0000f9fd, 0x0000126c, 0x0000f9fe, 0x0000126d, 0x0000f9ff, 0x0000126e, 0x0000fa00, 0x0000126f, 0x0000fa01, 0x00001270, 0x0000fa02, 0x00001271, 0x0000fa03, 0x00001272, 0x0000fa04, 0x00001273, 0x0000fa05, 0x00001274, 0x0000fa06, 0x00001275, 0x0000fa07, 0x00001276, 0x0000fa08, 0x00001277, 0x0000fa09, 0x00001278, 0x0000fa0a, 0x00001279, 0x0000fa0b, 0x0000127a, 0x0000fa0c, 0x0000127b, 0x0000fa0d, 0x0000127c, 0x0000fa10, 0x0000127d, 0x0000fa12, 0x0000127e, 0x0000fa15, 0x0000127f, 0x0000fa16, 0x00001280, 0x0000fa17, 0x00001281, 0x0000fa18, 0x00001282, 0x0000fa19, 0x00001283, 0x0000fa1a, 0x00001284, 0x0000fa1b, 0x00001285, 0x0000fa1c, 0x00001286, 0x0000fa1d, 0x00001287, 0x0000fa1e, 0x00001288, 0x0000fa20, 0x00001289, 0x0000fa22, 0x0000128a, 0x0000fa25, 0x0000128b, 0x0000fa26, 0x0000128c, 0x0000fa2a, 0x0000128d, 0x0000fa2b, 0x0000128e, 0x0000fa2c, 0x0000128f, 0x0000fa2d, 0x00001290, 0x0000fa30, 0x00001291, 0x0000fa31, 0x00001292, 0x0000fa32, 0x00001293, 0x0000fa33, 0x00001294, 0x0000fa34, 0x00001295, 0x0000fa35, 0x00001296, 0x0000fa36, 0x00001297, 0x0000fa37, 0x00001298, 0x0000fa38, 0x00001299, 0x0000fa39, 0x0000129a, 0x0000fa3a, 0x0000129b, 0x0000fa3b, 0x0000129c, 0x0000fa3c, 0x0000129d, 0x0000fa3d, 0x0000129e, 0x0000fa3e, 0x0000129f, 0x0000fa3f, 0x000012a0, 0x0000fa40, 0x000012a1, 0x0000fa41, 0x000012a2, 0x0000fa42, 0x000012a3, 0x0000fa43, 0x000012a4, 0x0000fa44, 0x000012a5, 0x0000fa45, 0x000012a6, 0x0000fa46, 0x000012a7, 0x0000fa47, 0x000012a8, 0x0000fa48, 0x000012a9, 0x0000fa49, 0x000012aa, 0x0000fa4a, 0x000012ab, 0x0000fa4b, 0x000012ac, 0x0000fa4c, 0x000012ad, 0x0000fa4d, 0x000012ae, 0x0000fa4e, 0x000012af, 0x0000fa4f, 0x000012b0, 0x0000fa50, 0x000012b1, 0x0000fa51, 0x000012b2, 0x0000fa52, 0x000012b3, 0x0000fa53, 0x000012b4, 0x0000fa54, 0x000012b5, 0x0000fa55, 0x000012b6, 0x0000fa56, 0x000012b7, 0x0000fa57, 0x000012b8, 0x0000fa58, 0x000012b9, 0x0000fa59, 0x000012ba, 0x0000fa5a, 0x000012bb, 0x0000fa5b, 0x000012bc, 0x0000fa5c, 0x000012bd, 0x0000fa5d, 0x000012be, 0x0000fa5e, 0x000012bf, 0x0000fa5f, 0x000012c0, 0x0000fa60, 0x000012c1, 0x0000fa61, 0x000012c2, 0x0000fa62, 0x000012c3, 0x0000fa63, 0x000012c4, 0x0000fa64, 0x000012c5, 0x0000fa65, 0x000012c6, 0x0000fa66, 0x000012c7, 0x0000fa67, 0x000012c8, 0x0000fa68, 0x000012c9, 0x0000fa69, 0x000012ca, 0x0000fa6a, 0x000012cb, 0x0000fb00, 0x000012cc, 0x0000fb01, 0x000012ce, 0x0000fb02, 0x000012d0, 0x0000fb03, 0x000012d2, 0x0000fb04, 0x000012d5, 0x0000fb05, 0x000012d8, 0x0000fb06, 0x000012da, 0x0000fb13, 0x000012dc, 0x0000fb14, 0x000012de, 0x0000fb15, 0x000012e0, 0x0000fb16, 0x000012e2, 0x0000fb17, 0x000012e4, 0x0000fb1d, 0x000012e6, 0x0000fb1f, 0x000012e8, 0x0000fb20, 0x000012ea, 0x0000fb21, 0x000012eb, 0x0000fb22, 0x000012ec, 0x0000fb23, 0x000012ed, 0x0000fb24, 0x000012ee, 0x0000fb25, 0x000012ef, 0x0000fb26, 0x000012f0, 0x0000fb27, 0x000012f1, 0x0000fb28, 0x000012f2, 0x0000fb29, 0x000012f3, 0x0000fb2a, 0x000012f4, 0x0000fb2b, 0x000012f6, 0x0000fb2c, 0x000012f8, 0x0000fb2d, 0x000012fb, 0x0000fb2e, 0x000012fe, 0x0000fb2f, 0x00001300, 0x0000fb30, 0x00001302, 0x0000fb31, 0x00001304, 0x0000fb32, 0x00001306, 0x0000fb33, 0x00001308, 0x0000fb34, 0x0000130a, 0x0000fb35, 0x0000130c, 0x0000fb36, 0x0000130e, 0x0000fb38, 0x00001310, 0x0000fb39, 0x00001312, 0x0000fb3a, 0x00001314, 0x0000fb3b, 0x00001316, 0x0000fb3c, 0x00001318, 0x0000fb3e, 0x0000131a, 0x0000fb40, 0x0000131c, 0x0000fb41, 0x0000131e, 0x0000fb43, 0x00001320, 0x0000fb44, 0x00001322, 0x0000fb46, 0x00001324, 0x0000fb47, 0x00001326, 0x0000fb48, 0x00001328, 0x0000fb49, 0x0000132a, 0x0000fb4a, 0x0000132c, 0x0000fb4b, 0x0000132e, 0x0000fb4c, 0x00001330, 0x0000fb4d, 0x00001332, 0x0000fb4e, 0x00001334, 0x0000fb4f, 0x00001336, 0x0000fb50, 0x00001338, 0x0000fb51, 0x00001339, 0x0000fb52, 0x0000133a, 0x0000fb53, 0x0000133b, 0x0000fb54, 0x0000133c, 0x0000fb55, 0x0000133d, 0x0000fb56, 0x0000133e, 0x0000fb57, 0x0000133f, 0x0000fb58, 0x00001340, 0x0000fb59, 0x00001341, 0x0000fb5a, 0x00001342, 0x0000fb5b, 0x00001343, 0x0000fb5c, 0x00001344, 0x0000fb5d, 0x00001345, 0x0000fb5e, 0x00001346, 0x0000fb5f, 0x00001347, 0x0000fb60, 0x00001348, 0x0000fb61, 0x00001349, 0x0000fb62, 0x0000134a, 0x0000fb63, 0x0000134b, 0x0000fb64, 0x0000134c, 0x0000fb65, 0x0000134d, 0x0000fb66, 0x0000134e, 0x0000fb67, 0x0000134f, 0x0000fb68, 0x00001350, 0x0000fb69, 0x00001351, 0x0000fb6a, 0x00001352, 0x0000fb6b, 0x00001353, 0x0000fb6c, 0x00001354, 0x0000fb6d, 0x00001355, 0x0000fb6e, 0x00001356, 0x0000fb6f, 0x00001357, 0x0000fb70, 0x00001358, 0x0000fb71, 0x00001359, 0x0000fb72, 0x0000135a, 0x0000fb73, 0x0000135b, 0x0000fb74, 0x0000135c, 0x0000fb75, 0x0000135d, 0x0000fb76, 0x0000135e, 0x0000fb77, 0x0000135f, 0x0000fb78, 0x00001360, 0x0000fb79, 0x00001361, 0x0000fb7a, 0x00001362, 0x0000fb7b, 0x00001363, 0x0000fb7c, 0x00001364, 0x0000fb7d, 0x00001365, 0x0000fb7e, 0x00001366, 0x0000fb7f, 0x00001367, 0x0000fb80, 0x00001368, 0x0000fb81, 0x00001369, 0x0000fb82, 0x0000136a, 0x0000fb83, 0x0000136b, 0x0000fb84, 0x0000136c, 0x0000fb85, 0x0000136d, 0x0000fb86, 0x0000136e, 0x0000fb87, 0x0000136f, 0x0000fb88, 0x00001370, 0x0000fb89, 0x00001371, 0x0000fb8a, 0x00001372, 0x0000fb8b, 0x00001373, 0x0000fb8c, 0x00001374, 0x0000fb8d, 0x00001375, 0x0000fb8e, 0x00001376, 0x0000fb8f, 0x00001377, 0x0000fb90, 0x00001378, 0x0000fb91, 0x00001379, 0x0000fb92, 0x0000137a, 0x0000fb93, 0x0000137b, 0x0000fb94, 0x0000137c, 0x0000fb95, 0x0000137d, 0x0000fb96, 0x0000137e, 0x0000fb97, 0x0000137f, 0x0000fb98, 0x00001380, 0x0000fb99, 0x00001381, 0x0000fb9a, 0x00001382, 0x0000fb9b, 0x00001383, 0x0000fb9c, 0x00001384, 0x0000fb9d, 0x00001385, 0x0000fb9e, 0x00001386, 0x0000fb9f, 0x00001387, 0x0000fba0, 0x00001388, 0x0000fba1, 0x00001389, 0x0000fba2, 0x0000138a, 0x0000fba3, 0x0000138b, 0x0000fba4, 0x0000138c, 0x0000fba5, 0x0000138e, 0x0000fba6, 0x00001390, 0x0000fba7, 0x00001391, 0x0000fba8, 0x00001392, 0x0000fba9, 0x00001393, 0x0000fbaa, 0x00001394, 0x0000fbab, 0x00001395, 0x0000fbac, 0x00001396, 0x0000fbad, 0x00001397, 0x0000fbae, 0x00001398, 0x0000fbaf, 0x00001399, 0x0000fbb0, 0x0000139a, 0x0000fbb1, 0x0000139c, 0x0000fbd3, 0x0000139e, 0x0000fbd4, 0x0000139f, 0x0000fbd5, 0x000013a0, 0x0000fbd6, 0x000013a1, 0x0000fbd7, 0x000013a2, 0x0000fbd8, 0x000013a3, 0x0000fbd9, 0x000013a4, 0x0000fbda, 0x000013a5, 0x0000fbdb, 0x000013a6, 0x0000fbdc, 0x000013a7, 0x0000fbdd, 0x000013a8, 0x0000fbde, 0x000013aa, 0x0000fbdf, 0x000013ab, 0x0000fbe0, 0x000013ac, 0x0000fbe1, 0x000013ad, 0x0000fbe2, 0x000013ae, 0x0000fbe3, 0x000013af, 0x0000fbe4, 0x000013b0, 0x0000fbe5, 0x000013b1, 0x0000fbe6, 0x000013b2, 0x0000fbe7, 0x000013b3, 0x0000fbe8, 0x000013b4, 0x0000fbe9, 0x000013b5, 0x0000fbea, 0x000013b6, 0x0000fbeb, 0x000013b9, 0x0000fbec, 0x000013bc, 0x0000fbed, 0x000013bf, 0x0000fbee, 0x000013c2, 0x0000fbef, 0x000013c5, 0x0000fbf0, 0x000013c8, 0x0000fbf1, 0x000013cb, 0x0000fbf2, 0x000013ce, 0x0000fbf3, 0x000013d1, 0x0000fbf4, 0x000013d4, 0x0000fbf5, 0x000013d7, 0x0000fbf6, 0x000013da, 0x0000fbf7, 0x000013dd, 0x0000fbf8, 0x000013e0, 0x0000fbf9, 0x000013e3, 0x0000fbfa, 0x000013e6, 0x0000fbfb, 0x000013e9, 0x0000fbfc, 0x000013ec, 0x0000fbfd, 0x000013ed, 0x0000fbfe, 0x000013ee, 0x0000fbff, 0x000013ef, 0x0000fc00, 0x000013f0, 0x0000fc01, 0x000013f3, 0x0000fc02, 0x000013f6, 0x0000fc03, 0x000013f9, 0x0000fc04, 0x000013fc, 0x0000fc05, 0x000013ff, 0x0000fc06, 0x00001401, 0x0000fc07, 0x00001403, 0x0000fc08, 0x00001405, 0x0000fc09, 0x00001407, 0x0000fc0a, 0x00001409, 0x0000fc0b, 0x0000140b, 0x0000fc0c, 0x0000140d, 0x0000fc0d, 0x0000140f, 0x0000fc0e, 0x00001411, 0x0000fc0f, 0x00001413, 0x0000fc10, 0x00001415, 0x0000fc11, 0x00001417, 0x0000fc12, 0x00001419, 0x0000fc13, 0x0000141b, 0x0000fc14, 0x0000141d, 0x0000fc15, 0x0000141f, 0x0000fc16, 0x00001421, 0x0000fc17, 0x00001423, 0x0000fc18, 0x00001425, 0x0000fc19, 0x00001427, 0x0000fc1a, 0x00001429, 0x0000fc1b, 0x0000142b, 0x0000fc1c, 0x0000142d, 0x0000fc1d, 0x0000142f, 0x0000fc1e, 0x00001431, 0x0000fc1f, 0x00001433, 0x0000fc20, 0x00001435, 0x0000fc21, 0x00001437, 0x0000fc22, 0x00001439, 0x0000fc23, 0x0000143b, 0x0000fc24, 0x0000143d, 0x0000fc25, 0x0000143f, 0x0000fc26, 0x00001441, 0x0000fc27, 0x00001443, 0x0000fc28, 0x00001445, 0x0000fc29, 0x00001447, 0x0000fc2a, 0x00001449, 0x0000fc2b, 0x0000144b, 0x0000fc2c, 0x0000144d, 0x0000fc2d, 0x0000144f, 0x0000fc2e, 0x00001451, 0x0000fc2f, 0x00001453, 0x0000fc30, 0x00001455, 0x0000fc31, 0x00001457, 0x0000fc32, 0x00001459, 0x0000fc33, 0x0000145b, 0x0000fc34, 0x0000145d, 0x0000fc35, 0x0000145f, 0x0000fc36, 0x00001461, 0x0000fc37, 0x00001463, 0x0000fc38, 0x00001465, 0x0000fc39, 0x00001467, 0x0000fc3a, 0x00001469, 0x0000fc3b, 0x0000146b, 0x0000fc3c, 0x0000146d, 0x0000fc3d, 0x0000146f, 0x0000fc3e, 0x00001471, 0x0000fc3f, 0x00001473, 0x0000fc40, 0x00001475, 0x0000fc41, 0x00001477, 0x0000fc42, 0x00001479, 0x0000fc43, 0x0000147b, 0x0000fc44, 0x0000147d, 0x0000fc45, 0x0000147f, 0x0000fc46, 0x00001481, 0x0000fc47, 0x00001483, 0x0000fc48, 0x00001485, 0x0000fc49, 0x00001487, 0x0000fc4a, 0x00001489, 0x0000fc4b, 0x0000148b, 0x0000fc4c, 0x0000148d, 0x0000fc4d, 0x0000148f, 0x0000fc4e, 0x00001491, 0x0000fc4f, 0x00001493, 0x0000fc50, 0x00001495, 0x0000fc51, 0x00001497, 0x0000fc52, 0x00001499, 0x0000fc53, 0x0000149b, 0x0000fc54, 0x0000149d, 0x0000fc55, 0x0000149f, 0x0000fc56, 0x000014a1, 0x0000fc57, 0x000014a3, 0x0000fc58, 0x000014a5, 0x0000fc59, 0x000014a7, 0x0000fc5a, 0x000014a9, 0x0000fc5b, 0x000014ab, 0x0000fc5c, 0x000014ad, 0x0000fc5d, 0x000014af, 0x0000fc5e, 0x000014b1, 0x0000fc5f, 0x000014b4, 0x0000fc60, 0x000014b7, 0x0000fc61, 0x000014ba, 0x0000fc62, 0x000014bd, 0x0000fc63, 0x000014c0, 0x0000fc64, 0x000014c3, 0x0000fc65, 0x000014c6, 0x0000fc66, 0x000014c9, 0x0000fc67, 0x000014cc, 0x0000fc68, 0x000014cf, 0x0000fc69, 0x000014d2, 0x0000fc6a, 0x000014d5, 0x0000fc6b, 0x000014d7, 0x0000fc6c, 0x000014d9, 0x0000fc6d, 0x000014db, 0x0000fc6e, 0x000014dd, 0x0000fc6f, 0x000014df, 0x0000fc70, 0x000014e1, 0x0000fc71, 0x000014e3, 0x0000fc72, 0x000014e5, 0x0000fc73, 0x000014e7, 0x0000fc74, 0x000014e9, 0x0000fc75, 0x000014eb, 0x0000fc76, 0x000014ed, 0x0000fc77, 0x000014ef, 0x0000fc78, 0x000014f1, 0x0000fc79, 0x000014f3, 0x0000fc7a, 0x000014f5, 0x0000fc7b, 0x000014f7, 0x0000fc7c, 0x000014f9, 0x0000fc7d, 0x000014fb, 0x0000fc7e, 0x000014fd, 0x0000fc7f, 0x000014ff, 0x0000fc80, 0x00001501, 0x0000fc81, 0x00001503, 0x0000fc82, 0x00001505, 0x0000fc83, 0x00001507, 0x0000fc84, 0x00001509, 0x0000fc85, 0x0000150b, 0x0000fc86, 0x0000150d, 0x0000fc87, 0x0000150f, 0x0000fc88, 0x00001511, 0x0000fc89, 0x00001513, 0x0000fc8a, 0x00001515, 0x0000fc8b, 0x00001517, 0x0000fc8c, 0x00001519, 0x0000fc8d, 0x0000151b, 0x0000fc8e, 0x0000151d, 0x0000fc8f, 0x0000151f, 0x0000fc90, 0x00001521, 0x0000fc91, 0x00001523, 0x0000fc92, 0x00001525, 0x0000fc93, 0x00001527, 0x0000fc94, 0x00001529, 0x0000fc95, 0x0000152b, 0x0000fc96, 0x0000152d, 0x0000fc97, 0x0000152f, 0x0000fc98, 0x00001532, 0x0000fc99, 0x00001535, 0x0000fc9a, 0x00001538, 0x0000fc9b, 0x0000153b, 0x0000fc9c, 0x0000153e, 0x0000fc9d, 0x00001540, 0x0000fc9e, 0x00001542, 0x0000fc9f, 0x00001544, 0x0000fca0, 0x00001546, 0x0000fca1, 0x00001548, 0x0000fca2, 0x0000154a, 0x0000fca3, 0x0000154c, 0x0000fca4, 0x0000154e, 0x0000fca5, 0x00001550, 0x0000fca6, 0x00001552, 0x0000fca7, 0x00001554, 0x0000fca8, 0x00001556, 0x0000fca9, 0x00001558, 0x0000fcaa, 0x0000155a, 0x0000fcab, 0x0000155c, 0x0000fcac, 0x0000155e, 0x0000fcad, 0x00001560, 0x0000fcae, 0x00001562, 0x0000fcaf, 0x00001564, 0x0000fcb0, 0x00001566, 0x0000fcb1, 0x00001568, 0x0000fcb2, 0x0000156a, 0x0000fcb3, 0x0000156c, 0x0000fcb4, 0x0000156e, 0x0000fcb5, 0x00001570, 0x0000fcb6, 0x00001572, 0x0000fcb7, 0x00001574, 0x0000fcb8, 0x00001576, 0x0000fcb9, 0x00001578, 0x0000fcba, 0x0000157a, 0x0000fcbb, 0x0000157c, 0x0000fcbc, 0x0000157e, 0x0000fcbd, 0x00001580, 0x0000fcbe, 0x00001582, 0x0000fcbf, 0x00001584, 0x0000fcc0, 0x00001586, 0x0000fcc1, 0x00001588, 0x0000fcc2, 0x0000158a, 0x0000fcc3, 0x0000158c, 0x0000fcc4, 0x0000158e, 0x0000fcc5, 0x00001590, 0x0000fcc6, 0x00001592, 0x0000fcc7, 0x00001594, 0x0000fcc8, 0x00001596, 0x0000fcc9, 0x00001598, 0x0000fcca, 0x0000159a, 0x0000fccb, 0x0000159c, 0x0000fccc, 0x0000159e, 0x0000fccd, 0x000015a0, 0x0000fcce, 0x000015a2, 0x0000fccf, 0x000015a4, 0x0000fcd0, 0x000015a6, 0x0000fcd1, 0x000015a8, 0x0000fcd2, 0x000015aa, 0x0000fcd3, 0x000015ac, 0x0000fcd4, 0x000015ae, 0x0000fcd5, 0x000015b0, 0x0000fcd6, 0x000015b2, 0x0000fcd7, 0x000015b4, 0x0000fcd8, 0x000015b6, 0x0000fcd9, 0x000015b8, 0x0000fcda, 0x000015ba, 0x0000fcdb, 0x000015bc, 0x0000fcdc, 0x000015be, 0x0000fcdd, 0x000015c0, 0x0000fcde, 0x000015c2, 0x0000fcdf, 0x000015c4, 0x0000fce0, 0x000015c7, 0x0000fce1, 0x000015ca, 0x0000fce2, 0x000015cc, 0x0000fce3, 0x000015ce, 0x0000fce4, 0x000015d0, 0x0000fce5, 0x000015d2, 0x0000fce6, 0x000015d4, 0x0000fce7, 0x000015d6, 0x0000fce8, 0x000015d8, 0x0000fce9, 0x000015da, 0x0000fcea, 0x000015dc, 0x0000fceb, 0x000015de, 0x0000fcec, 0x000015e0, 0x0000fced, 0x000015e2, 0x0000fcee, 0x000015e4, 0x0000fcef, 0x000015e6, 0x0000fcf0, 0x000015e8, 0x0000fcf1, 0x000015ea, 0x0000fcf2, 0x000015ec, 0x0000fcf3, 0x000015ef, 0x0000fcf4, 0x000015f2, 0x0000fcf5, 0x000015f5, 0x0000fcf6, 0x000015f7, 0x0000fcf7, 0x000015f9, 0x0000fcf8, 0x000015fb, 0x0000fcf9, 0x000015fd, 0x0000fcfa, 0x000015ff, 0x0000fcfb, 0x00001601, 0x0000fcfc, 0x00001603, 0x0000fcfd, 0x00001605, 0x0000fcfe, 0x00001607, 0x0000fcff, 0x00001609, 0x0000fd00, 0x0000160b, 0x0000fd01, 0x0000160d, 0x0000fd02, 0x0000160f, 0x0000fd03, 0x00001611, 0x0000fd04, 0x00001613, 0x0000fd05, 0x00001615, 0x0000fd06, 0x00001617, 0x0000fd07, 0x00001619, 0x0000fd08, 0x0000161b, 0x0000fd09, 0x0000161d, 0x0000fd0a, 0x0000161f, 0x0000fd0b, 0x00001621, 0x0000fd0c, 0x00001623, 0x0000fd0d, 0x00001625, 0x0000fd0e, 0x00001627, 0x0000fd0f, 0x00001629, 0x0000fd10, 0x0000162b, 0x0000fd11, 0x0000162d, 0x0000fd12, 0x0000162f, 0x0000fd13, 0x00001631, 0x0000fd14, 0x00001633, 0x0000fd15, 0x00001635, 0x0000fd16, 0x00001637, 0x0000fd17, 0x00001639, 0x0000fd18, 0x0000163b, 0x0000fd19, 0x0000163d, 0x0000fd1a, 0x0000163f, 0x0000fd1b, 0x00001641, 0x0000fd1c, 0x00001643, 0x0000fd1d, 0x00001645, 0x0000fd1e, 0x00001647, 0x0000fd1f, 0x00001649, 0x0000fd20, 0x0000164b, 0x0000fd21, 0x0000164d, 0x0000fd22, 0x0000164f, 0x0000fd23, 0x00001651, 0x0000fd24, 0x00001653, 0x0000fd25, 0x00001655, 0x0000fd26, 0x00001657, 0x0000fd27, 0x00001659, 0x0000fd28, 0x0000165b, 0x0000fd29, 0x0000165d, 0x0000fd2a, 0x0000165f, 0x0000fd2b, 0x00001661, 0x0000fd2c, 0x00001663, 0x0000fd2d, 0x00001665, 0x0000fd2e, 0x00001667, 0x0000fd2f, 0x00001669, 0x0000fd30, 0x0000166b, 0x0000fd31, 0x0000166d, 0x0000fd32, 0x0000166f, 0x0000fd33, 0x00001671, 0x0000fd34, 0x00001673, 0x0000fd35, 0x00001675, 0x0000fd36, 0x00001677, 0x0000fd37, 0x00001679, 0x0000fd38, 0x0000167b, 0x0000fd39, 0x0000167d, 0x0000fd3a, 0x0000167f, 0x0000fd3b, 0x00001681, 0x0000fd3c, 0x00001683, 0x0000fd3d, 0x00001685, 0x0000fd50, 0x00001687, 0x0000fd51, 0x0000168a, 0x0000fd52, 0x0000168d, 0x0000fd53, 0x00001690, 0x0000fd54, 0x00001693, 0x0000fd55, 0x00001696, 0x0000fd56, 0x00001699, 0x0000fd57, 0x0000169c, 0x0000fd58, 0x0000169f, 0x0000fd59, 0x000016a2, 0x0000fd5a, 0x000016a5, 0x0000fd5b, 0x000016a8, 0x0000fd5c, 0x000016ab, 0x0000fd5d, 0x000016ae, 0x0000fd5e, 0x000016b1, 0x0000fd5f, 0x000016b4, 0x0000fd60, 0x000016b7, 0x0000fd61, 0x000016ba, 0x0000fd62, 0x000016bd, 0x0000fd63, 0x000016c0, 0x0000fd64, 0x000016c3, 0x0000fd65, 0x000016c6, 0x0000fd66, 0x000016c9, 0x0000fd67, 0x000016cc, 0x0000fd68, 0x000016cf, 0x0000fd69, 0x000016d2, 0x0000fd6a, 0x000016d5, 0x0000fd6b, 0x000016d8, 0x0000fd6c, 0x000016db, 0x0000fd6d, 0x000016de, 0x0000fd6e, 0x000016e1, 0x0000fd6f, 0x000016e4, 0x0000fd70, 0x000016e7, 0x0000fd71, 0x000016ea, 0x0000fd72, 0x000016ed, 0x0000fd73, 0x000016f0, 0x0000fd74, 0x000016f3, 0x0000fd75, 0x000016f6, 0x0000fd76, 0x000016f9, 0x0000fd77, 0x000016fc, 0x0000fd78, 0x000016ff, 0x0000fd79, 0x00001702, 0x0000fd7a, 0x00001705, 0x0000fd7b, 0x00001708, 0x0000fd7c, 0x0000170b, 0x0000fd7d, 0x0000170e, 0x0000fd7e, 0x00001711, 0x0000fd7f, 0x00001714, 0x0000fd80, 0x00001717, 0x0000fd81, 0x0000171a, 0x0000fd82, 0x0000171d, 0x0000fd83, 0x00001720, 0x0000fd84, 0x00001723, 0x0000fd85, 0x00001726, 0x0000fd86, 0x00001729, 0x0000fd87, 0x0000172c, 0x0000fd88, 0x0000172f, 0x0000fd89, 0x00001732, 0x0000fd8a, 0x00001735, 0x0000fd8b, 0x00001738, 0x0000fd8c, 0x0000173b, 0x0000fd8d, 0x0000173e, 0x0000fd8e, 0x00001741, 0x0000fd8f, 0x00001744, 0x0000fd92, 0x00001747, 0x0000fd93, 0x0000174a, 0x0000fd94, 0x0000174d, 0x0000fd95, 0x00001750, 0x0000fd96, 0x00001753, 0x0000fd97, 0x00001756, 0x0000fd98, 0x00001759, 0x0000fd99, 0x0000175c, 0x0000fd9a, 0x0000175f, 0x0000fd9b, 0x00001762, 0x0000fd9c, 0x00001765, 0x0000fd9d, 0x00001768, 0x0000fd9e, 0x0000176b, 0x0000fd9f, 0x0000176e, 0x0000fda0, 0x00001771, 0x0000fda1, 0x00001774, 0x0000fda2, 0x00001777, 0x0000fda3, 0x0000177a, 0x0000fda4, 0x0000177d, 0x0000fda5, 0x00001780, 0x0000fda6, 0x00001783, 0x0000fda7, 0x00001786, 0x0000fda8, 0x00001789, 0x0000fda9, 0x0000178c, 0x0000fdaa, 0x0000178f, 0x0000fdab, 0x00001792, 0x0000fdac, 0x00001795, 0x0000fdad, 0x00001798, 0x0000fdae, 0x0000179b, 0x0000fdaf, 0x0000179e, 0x0000fdb0, 0x000017a1, 0x0000fdb1, 0x000017a4, 0x0000fdb2, 0x000017a7, 0x0000fdb3, 0x000017aa, 0x0000fdb4, 0x000017ad, 0x0000fdb5, 0x000017b0, 0x0000fdb6, 0x000017b3, 0x0000fdb7, 0x000017b6, 0x0000fdb8, 0x000017b9, 0x0000fdb9, 0x000017bc, 0x0000fdba, 0x000017bf, 0x0000fdbb, 0x000017c2, 0x0000fdbc, 0x000017c5, 0x0000fdbd, 0x000017c8, 0x0000fdbe, 0x000017cb, 0x0000fdbf, 0x000017ce, 0x0000fdc0, 0x000017d1, 0x0000fdc1, 0x000017d4, 0x0000fdc2, 0x000017d7, 0x0000fdc3, 0x000017da, 0x0000fdc4, 0x000017dd, 0x0000fdc5, 0x000017e0, 0x0000fdc6, 0x000017e3, 0x0000fdc7, 0x000017e6, 0x0000fdf0, 0x000017e9, 0x0000fdf1, 0x000017ec, 0x0000fdf2, 0x000017ef, 0x0000fdf3, 0x000017f3, 0x0000fdf4, 0x000017f7, 0x0000fdf5, 0x000017fb, 0x0000fdf6, 0x000017ff, 0x0000fdf7, 0x00001803, 0x0000fdf8, 0x00001807, 0x0000fdf9, 0x0000180b, 0x0000fdfa, 0x0000180e, 0x0000fdfb, 0x00001820, 0x0000fdfc, 0x00001828, 0x0000fe30, 0x0000182c, 0x0000fe31, 0x0000182e, 0x0000fe32, 0x0000182f, 0x0000fe33, 0x00001830, 0x0000fe34, 0x00001831, 0x0000fe35, 0x00001832, 0x0000fe36, 0x00001833, 0x0000fe37, 0x00001834, 0x0000fe38, 0x00001835, 0x0000fe39, 0x00001836, 0x0000fe3a, 0x00001837, 0x0000fe3b, 0x00001838, 0x0000fe3c, 0x00001839, 0x0000fe3d, 0x0000183a, 0x0000fe3e, 0x0000183b, 0x0000fe3f, 0x0000183c, 0x0000fe40, 0x0000183d, 0x0000fe41, 0x0000183e, 0x0000fe42, 0x0000183f, 0x0000fe43, 0x00001840, 0x0000fe44, 0x00001841, 0x0000fe49, 0x00001842, 0x0000fe4a, 0x00001844, 0x0000fe4b, 0x00001846, 0x0000fe4c, 0x00001848, 0x0000fe4d, 0x0000184a, 0x0000fe4e, 0x0000184b, 0x0000fe4f, 0x0000184c, 0x0000fe50, 0x0000184d, 0x0000fe51, 0x0000184e, 0x0000fe52, 0x0000184f, 0x0000fe54, 0x00001850, 0x0000fe55, 0x00001851, 0x0000fe56, 0x00001852, 0x0000fe57, 0x00001853, 0x0000fe58, 0x00001854, 0x0000fe59, 0x00001855, 0x0000fe5a, 0x00001856, 0x0000fe5b, 0x00001857, 0x0000fe5c, 0x00001858, 0x0000fe5d, 0x00001859, 0x0000fe5e, 0x0000185a, 0x0000fe5f, 0x0000185b, 0x0000fe60, 0x0000185c, 0x0000fe61, 0x0000185d, 0x0000fe62, 0x0000185e, 0x0000fe63, 0x0000185f, 0x0000fe64, 0x00001860, 0x0000fe65, 0x00001861, 0x0000fe66, 0x00001862, 0x0000fe68, 0x00001863, 0x0000fe69, 0x00001864, 0x0000fe6a, 0x00001865, 0x0000fe6b, 0x00001866, 0x0000fe70, 0x00001867, 0x0000fe71, 0x00001869, 0x0000fe72, 0x0000186b, 0x0000fe74, 0x0000186d, 0x0000fe76, 0x0000186f, 0x0000fe77, 0x00001871, 0x0000fe78, 0x00001873, 0x0000fe79, 0x00001875, 0x0000fe7a, 0x00001877, 0x0000fe7b, 0x00001879, 0x0000fe7c, 0x0000187b, 0x0000fe7d, 0x0000187d, 0x0000fe7e, 0x0000187f, 0x0000fe7f, 0x00001881, 0x0000fe80, 0x00001883, 0x0000fe81, 0x00001884, 0x0000fe82, 0x00001886, 0x0000fe83, 0x00001888, 0x0000fe84, 0x0000188a, 0x0000fe85, 0x0000188c, 0x0000fe86, 0x0000188e, 0x0000fe87, 0x00001890, 0x0000fe88, 0x00001892, 0x0000fe89, 0x00001894, 0x0000fe8a, 0x00001896, 0x0000fe8b, 0x00001898, 0x0000fe8c, 0x0000189a, 0x0000fe8d, 0x0000189c, 0x0000fe8e, 0x0000189d, 0x0000fe8f, 0x0000189e, 0x0000fe90, 0x0000189f, 0x0000fe91, 0x000018a0, 0x0000fe92, 0x000018a1, 0x0000fe93, 0x000018a2, 0x0000fe94, 0x000018a3, 0x0000fe95, 0x000018a4, 0x0000fe96, 0x000018a5, 0x0000fe97, 0x000018a6, 0x0000fe98, 0x000018a7, 0x0000fe99, 0x000018a8, 0x0000fe9a, 0x000018a9, 0x0000fe9b, 0x000018aa, 0x0000fe9c, 0x000018ab, 0x0000fe9d, 0x000018ac, 0x0000fe9e, 0x000018ad, 0x0000fe9f, 0x000018ae, 0x0000fea0, 0x000018af, 0x0000fea1, 0x000018b0, 0x0000fea2, 0x000018b1, 0x0000fea3, 0x000018b2, 0x0000fea4, 0x000018b3, 0x0000fea5, 0x000018b4, 0x0000fea6, 0x000018b5, 0x0000fea7, 0x000018b6, 0x0000fea8, 0x000018b7, 0x0000fea9, 0x000018b8, 0x0000feaa, 0x000018b9, 0x0000feab, 0x000018ba, 0x0000feac, 0x000018bb, 0x0000fead, 0x000018bc, 0x0000feae, 0x000018bd, 0x0000feaf, 0x000018be, 0x0000feb0, 0x000018bf, 0x0000feb1, 0x000018c0, 0x0000feb2, 0x000018c1, 0x0000feb3, 0x000018c2, 0x0000feb4, 0x000018c3, 0x0000feb5, 0x000018c4, 0x0000feb6, 0x000018c5, 0x0000feb7, 0x000018c6, 0x0000feb8, 0x000018c7, 0x0000feb9, 0x000018c8, 0x0000feba, 0x000018c9, 0x0000febb, 0x000018ca, 0x0000febc, 0x000018cb, 0x0000febd, 0x000018cc, 0x0000febe, 0x000018cd, 0x0000febf, 0x000018ce, 0x0000fec0, 0x000018cf, 0x0000fec1, 0x000018d0, 0x0000fec2, 0x000018d1, 0x0000fec3, 0x000018d2, 0x0000fec4, 0x000018d3, 0x0000fec5, 0x000018d4, 0x0000fec6, 0x000018d5, 0x0000fec7, 0x000018d6, 0x0000fec8, 0x000018d7, 0x0000fec9, 0x000018d8, 0x0000feca, 0x000018d9, 0x0000fecb, 0x000018da, 0x0000fecc, 0x000018db, 0x0000fecd, 0x000018dc, 0x0000fece, 0x000018dd, 0x0000fecf, 0x000018de, 0x0000fed0, 0x000018df, 0x0000fed1, 0x000018e0, 0x0000fed2, 0x000018e1, 0x0000fed3, 0x000018e2, 0x0000fed4, 0x000018e3, 0x0000fed5, 0x000018e4, 0x0000fed6, 0x000018e5, 0x0000fed7, 0x000018e6, 0x0000fed8, 0x000018e7, 0x0000fed9, 0x000018e8, 0x0000feda, 0x000018e9, 0x0000fedb, 0x000018ea, 0x0000fedc, 0x000018eb, 0x0000fedd, 0x000018ec, 0x0000fede, 0x000018ed, 0x0000fedf, 0x000018ee, 0x0000fee0, 0x000018ef, 0x0000fee1, 0x000018f0, 0x0000fee2, 0x000018f1, 0x0000fee3, 0x000018f2, 0x0000fee4, 0x000018f3, 0x0000fee5, 0x000018f4, 0x0000fee6, 0x000018f5, 0x0000fee7, 0x000018f6, 0x0000fee8, 0x000018f7, 0x0000fee9, 0x000018f8, 0x0000feea, 0x000018f9, 0x0000feeb, 0x000018fa, 0x0000feec, 0x000018fb, 0x0000feed, 0x000018fc, 0x0000feee, 0x000018fd, 0x0000feef, 0x000018fe, 0x0000fef0, 0x000018ff, 0x0000fef1, 0x00001900, 0x0000fef2, 0x00001901, 0x0000fef3, 0x00001902, 0x0000fef4, 0x00001903, 0x0000fef5, 0x00001904, 0x0000fef6, 0x00001907, 0x0000fef7, 0x0000190a, 0x0000fef8, 0x0000190d, 0x0000fef9, 0x00001910, 0x0000fefa, 0x00001913, 0x0000fefb, 0x00001916, 0x0000fefc, 0x00001918, 0x0000ff01, 0x0000191a, 0x0000ff02, 0x0000191b, 0x0000ff03, 0x0000191c, 0x0000ff04, 0x0000191d, 0x0000ff05, 0x0000191e, 0x0000ff06, 0x0000191f, 0x0000ff07, 0x00001920, 0x0000ff08, 0x00001921, 0x0000ff09, 0x00001922, 0x0000ff0a, 0x00001923, 0x0000ff0b, 0x00001924, 0x0000ff0c, 0x00001925, 0x0000ff0d, 0x00001926, 0x0000ff0e, 0x00001927, 0x0000ff0f, 0x00001928, 0x0000ff10, 0x00001929, 0x0000ff11, 0x0000192a, 0x0000ff12, 0x0000192b, 0x0000ff13, 0x0000192c, 0x0000ff14, 0x0000192d, 0x0000ff15, 0x0000192e, 0x0000ff16, 0x0000192f, 0x0000ff17, 0x00001930, 0x0000ff18, 0x00001931, 0x0000ff19, 0x00001932, 0x0000ff1a, 0x00001933, 0x0000ff1b, 0x00001934, 0x0000ff1c, 0x00001935, 0x0000ff1d, 0x00001936, 0x0000ff1e, 0x00001937, 0x0000ff1f, 0x00001938, 0x0000ff20, 0x00001939, 0x0000ff21, 0x0000193a, 0x0000ff22, 0x0000193b, 0x0000ff23, 0x0000193c, 0x0000ff24, 0x0000193d, 0x0000ff25, 0x0000193e, 0x0000ff26, 0x0000193f, 0x0000ff27, 0x00001940, 0x0000ff28, 0x00001941, 0x0000ff29, 0x00001942, 0x0000ff2a, 0x00001943, 0x0000ff2b, 0x00001944, 0x0000ff2c, 0x00001945, 0x0000ff2d, 0x00001946, 0x0000ff2e, 0x00001947, 0x0000ff2f, 0x00001948, 0x0000ff30, 0x00001949, 0x0000ff31, 0x0000194a, 0x0000ff32, 0x0000194b, 0x0000ff33, 0x0000194c, 0x0000ff34, 0x0000194d, 0x0000ff35, 0x0000194e, 0x0000ff36, 0x0000194f, 0x0000ff37, 0x00001950, 0x0000ff38, 0x00001951, 0x0000ff39, 0x00001952, 0x0000ff3a, 0x00001953, 0x0000ff3b, 0x00001954, 0x0000ff3c, 0x00001955, 0x0000ff3d, 0x00001956, 0x0000ff3e, 0x00001957, 0x0000ff3f, 0x00001958, 0x0000ff40, 0x00001959, 0x0000ff41, 0x0000195a, 0x0000ff42, 0x0000195b, 0x0000ff43, 0x0000195c, 0x0000ff44, 0x0000195d, 0x0000ff45, 0x0000195e, 0x0000ff46, 0x0000195f, 0x0000ff47, 0x00001960, 0x0000ff48, 0x00001961, 0x0000ff49, 0x00001962, 0x0000ff4a, 0x00001963, 0x0000ff4b, 0x00001964, 0x0000ff4c, 0x00001965, 0x0000ff4d, 0x00001966, 0x0000ff4e, 0x00001967, 0x0000ff4f, 0x00001968, 0x0000ff50, 0x00001969, 0x0000ff51, 0x0000196a, 0x0000ff52, 0x0000196b, 0x0000ff53, 0x0000196c, 0x0000ff54, 0x0000196d, 0x0000ff55, 0x0000196e, 0x0000ff56, 0x0000196f, 0x0000ff57, 0x00001970, 0x0000ff58, 0x00001971, 0x0000ff59, 0x00001972, 0x0000ff5a, 0x00001973, 0x0000ff5b, 0x00001974, 0x0000ff5c, 0x00001975, 0x0000ff5d, 0x00001976, 0x0000ff5e, 0x00001977, 0x0000ff5f, 0x00001978, 0x0000ff60, 0x00001979, 0x0000ff61, 0x0000197a, 0x0000ff62, 0x0000197b, 0x0000ff63, 0x0000197c, 0x0000ff64, 0x0000197d, 0x0000ff65, 0x0000197e, 0x0000ff66, 0x0000197f, 0x0000ff67, 0x00001980, 0x0000ff68, 0x00001981, 0x0000ff69, 0x00001982, 0x0000ff6a, 0x00001983, 0x0000ff6b, 0x00001984, 0x0000ff6c, 0x00001985, 0x0000ff6d, 0x00001986, 0x0000ff6e, 0x00001987, 0x0000ff6f, 0x00001988, 0x0000ff70, 0x00001989, 0x0000ff71, 0x0000198a, 0x0000ff72, 0x0000198b, 0x0000ff73, 0x0000198c, 0x0000ff74, 0x0000198d, 0x0000ff75, 0x0000198e, 0x0000ff76, 0x0000198f, 0x0000ff77, 0x00001990, 0x0000ff78, 0x00001991, 0x0000ff79, 0x00001992, 0x0000ff7a, 0x00001993, 0x0000ff7b, 0x00001994, 0x0000ff7c, 0x00001995, 0x0000ff7d, 0x00001996, 0x0000ff7e, 0x00001997, 0x0000ff7f, 0x00001998, 0x0000ff80, 0x00001999, 0x0000ff81, 0x0000199a, 0x0000ff82, 0x0000199b, 0x0000ff83, 0x0000199c, 0x0000ff84, 0x0000199d, 0x0000ff85, 0x0000199e, 0x0000ff86, 0x0000199f, 0x0000ff87, 0x000019a0, 0x0000ff88, 0x000019a1, 0x0000ff89, 0x000019a2, 0x0000ff8a, 0x000019a3, 0x0000ff8b, 0x000019a4, 0x0000ff8c, 0x000019a5, 0x0000ff8d, 0x000019a6, 0x0000ff8e, 0x000019a7, 0x0000ff8f, 0x000019a8, 0x0000ff90, 0x000019a9, 0x0000ff91, 0x000019aa, 0x0000ff92, 0x000019ab, 0x0000ff93, 0x000019ac, 0x0000ff94, 0x000019ad, 0x0000ff95, 0x000019ae, 0x0000ff96, 0x000019af, 0x0000ff97, 0x000019b0, 0x0000ff98, 0x000019b1, 0x0000ff99, 0x000019b2, 0x0000ff9a, 0x000019b3, 0x0000ff9b, 0x000019b4, 0x0000ff9c, 0x000019b5, 0x0000ff9d, 0x000019b6, 0x0000ff9e, 0x000019b7, 0x0000ff9f, 0x000019b8, 0x0000ffa0, 0x000019b9, 0x0000ffa1, 0x000019ba, 0x0000ffa2, 0x000019bb, 0x0000ffa3, 0x000019bc, 0x0000ffa4, 0x000019bd, 0x0000ffa5, 0x000019be, 0x0000ffa6, 0x000019bf, 0x0000ffa7, 0x000019c0, 0x0000ffa8, 0x000019c1, 0x0000ffa9, 0x000019c2, 0x0000ffaa, 0x000019c3, 0x0000ffab, 0x000019c4, 0x0000ffac, 0x000019c5, 0x0000ffad, 0x000019c6, 0x0000ffae, 0x000019c7, 0x0000ffaf, 0x000019c8, 0x0000ffb0, 0x000019c9, 0x0000ffb1, 0x000019ca, 0x0000ffb2, 0x000019cb, 0x0000ffb3, 0x000019cc, 0x0000ffb4, 0x000019cd, 0x0000ffb5, 0x000019ce, 0x0000ffb6, 0x000019cf, 0x0000ffb7, 0x000019d0, 0x0000ffb8, 0x000019d1, 0x0000ffb9, 0x000019d2, 0x0000ffba, 0x000019d3, 0x0000ffbb, 0x000019d4, 0x0000ffbc, 0x000019d5, 0x0000ffbd, 0x000019d6, 0x0000ffbe, 0x000019d7, 0x0000ffc2, 0x000019d8, 0x0000ffc3, 0x000019d9, 0x0000ffc4, 0x000019da, 0x0000ffc5, 0x000019db, 0x0000ffc6, 0x000019dc, 0x0000ffc7, 0x000019dd, 0x0000ffca, 0x000019de, 0x0000ffcb, 0x000019df, 0x0000ffcc, 0x000019e0, 0x0000ffcd, 0x000019e1, 0x0000ffce, 0x000019e2, 0x0000ffcf, 0x000019e3, 0x0000ffd2, 0x000019e4, 0x0000ffd3, 0x000019e5, 0x0000ffd4, 0x000019e6, 0x0000ffd5, 0x000019e7, 0x0000ffd6, 0x000019e8, 0x0000ffd7, 0x000019e9, 0x0000ffda, 0x000019ea, 0x0000ffdb, 0x000019eb, 0x0000ffdc, 0x000019ec, 0x0000ffe0, 0x000019ed, 0x0000ffe1, 0x000019ee, 0x0000ffe2, 0x000019ef, 0x0000ffe3, 0x000019f0, 0x0000ffe4, 0x000019f2, 0x0000ffe5, 0x000019f3, 0x0000ffe6, 0x000019f4, 0x0000ffe8, 0x000019f5, 0x0000ffe9, 0x000019f6, 0x0000ffea, 0x000019f7, 0x0000ffeb, 0x000019f8, 0x0000ffec, 0x000019f9, 0x0000ffed, 0x000019fa, 0x0000ffee, 0x000019fb, 0x0001d15e, 0x000019fc, 0x0001d15f, 0x000019fe, 0x0001d160, 0x00001a00, 0x0001d161, 0x00001a03, 0x0001d162, 0x00001a06, 0x0001d163, 0x00001a09, 0x0001d164, 0x00001a0c, 0x0001d1bb, 0x00001a0f, 0x0001d1bc, 0x00001a11, 0x0001d1bd, 0x00001a13, 0x0001d1be, 0x00001a16, 0x0001d1bf, 0x00001a19, 0x0001d1c0, 0x00001a1c, 0x0001d400, 0x00001a1f, 0x0001d401, 0x00001a20, 0x0001d402, 0x00001a21, 0x0001d403, 0x00001a22, 0x0001d404, 0x00001a23, 0x0001d405, 0x00001a24, 0x0001d406, 0x00001a25, 0x0001d407, 0x00001a26, 0x0001d408, 0x00001a27, 0x0001d409, 0x00001a28, 0x0001d40a, 0x00001a29, 0x0001d40b, 0x00001a2a, 0x0001d40c, 0x00001a2b, 0x0001d40d, 0x00001a2c, 0x0001d40e, 0x00001a2d, 0x0001d40f, 0x00001a2e, 0x0001d410, 0x00001a2f, 0x0001d411, 0x00001a30, 0x0001d412, 0x00001a31, 0x0001d413, 0x00001a32, 0x0001d414, 0x00001a33, 0x0001d415, 0x00001a34, 0x0001d416, 0x00001a35, 0x0001d417, 0x00001a36, 0x0001d418, 0x00001a37, 0x0001d419, 0x00001a38, 0x0001d41a, 0x00001a39, 0x0001d41b, 0x00001a3a, 0x0001d41c, 0x00001a3b, 0x0001d41d, 0x00001a3c, 0x0001d41e, 0x00001a3d, 0x0001d41f, 0x00001a3e, 0x0001d420, 0x00001a3f, 0x0001d421, 0x00001a40, 0x0001d422, 0x00001a41, 0x0001d423, 0x00001a42, 0x0001d424, 0x00001a43, 0x0001d425, 0x00001a44, 0x0001d426, 0x00001a45, 0x0001d427, 0x00001a46, 0x0001d428, 0x00001a47, 0x0001d429, 0x00001a48, 0x0001d42a, 0x00001a49, 0x0001d42b, 0x00001a4a, 0x0001d42c, 0x00001a4b, 0x0001d42d, 0x00001a4c, 0x0001d42e, 0x00001a4d, 0x0001d42f, 0x00001a4e, 0x0001d430, 0x00001a4f, 0x0001d431, 0x00001a50, 0x0001d432, 0x00001a51, 0x0001d433, 0x00001a52, 0x0001d434, 0x00001a53, 0x0001d435, 0x00001a54, 0x0001d436, 0x00001a55, 0x0001d437, 0x00001a56, 0x0001d438, 0x00001a57, 0x0001d439, 0x00001a58, 0x0001d43a, 0x00001a59, 0x0001d43b, 0x00001a5a, 0x0001d43c, 0x00001a5b, 0x0001d43d, 0x00001a5c, 0x0001d43e, 0x00001a5d, 0x0001d43f, 0x00001a5e, 0x0001d440, 0x00001a5f, 0x0001d441, 0x00001a60, 0x0001d442, 0x00001a61, 0x0001d443, 0x00001a62, 0x0001d444, 0x00001a63, 0x0001d445, 0x00001a64, 0x0001d446, 0x00001a65, 0x0001d447, 0x00001a66, 0x0001d448, 0x00001a67, 0x0001d449, 0x00001a68, 0x0001d44a, 0x00001a69, 0x0001d44b, 0x00001a6a, 0x0001d44c, 0x00001a6b, 0x0001d44d, 0x00001a6c, 0x0001d44e, 0x00001a6d, 0x0001d44f, 0x00001a6e, 0x0001d450, 0x00001a6f, 0x0001d451, 0x00001a70, 0x0001d452, 0x00001a71, 0x0001d453, 0x00001a72, 0x0001d454, 0x00001a73, 0x0001d456, 0x00001a74, 0x0001d457, 0x00001a75, 0x0001d458, 0x00001a76, 0x0001d459, 0x00001a77, 0x0001d45a, 0x00001a78, 0x0001d45b, 0x00001a79, 0x0001d45c, 0x00001a7a, 0x0001d45d, 0x00001a7b, 0x0001d45e, 0x00001a7c, 0x0001d45f, 0x00001a7d, 0x0001d460, 0x00001a7e, 0x0001d461, 0x00001a7f, 0x0001d462, 0x00001a80, 0x0001d463, 0x00001a81, 0x0001d464, 0x00001a82, 0x0001d465, 0x00001a83, 0x0001d466, 0x00001a84, 0x0001d467, 0x00001a85, 0x0001d468, 0x00001a86, 0x0001d469, 0x00001a87, 0x0001d46a, 0x00001a88, 0x0001d46b, 0x00001a89, 0x0001d46c, 0x00001a8a, 0x0001d46d, 0x00001a8b, 0x0001d46e, 0x00001a8c, 0x0001d46f, 0x00001a8d, 0x0001d470, 0x00001a8e, 0x0001d471, 0x00001a8f, 0x0001d472, 0x00001a90, 0x0001d473, 0x00001a91, 0x0001d474, 0x00001a92, 0x0001d475, 0x00001a93, 0x0001d476, 0x00001a94, 0x0001d477, 0x00001a95, 0x0001d478, 0x00001a96, 0x0001d479, 0x00001a97, 0x0001d47a, 0x00001a98, 0x0001d47b, 0x00001a99, 0x0001d47c, 0x00001a9a, 0x0001d47d, 0x00001a9b, 0x0001d47e, 0x00001a9c, 0x0001d47f, 0x00001a9d, 0x0001d480, 0x00001a9e, 0x0001d481, 0x00001a9f, 0x0001d482, 0x00001aa0, 0x0001d483, 0x00001aa1, 0x0001d484, 0x00001aa2, 0x0001d485, 0x00001aa3, 0x0001d486, 0x00001aa4, 0x0001d487, 0x00001aa5, 0x0001d488, 0x00001aa6, 0x0001d489, 0x00001aa7, 0x0001d48a, 0x00001aa8, 0x0001d48b, 0x00001aa9, 0x0001d48c, 0x00001aaa, 0x0001d48d, 0x00001aab, 0x0001d48e, 0x00001aac, 0x0001d48f, 0x00001aad, 0x0001d490, 0x00001aae, 0x0001d491, 0x00001aaf, 0x0001d492, 0x00001ab0, 0x0001d493, 0x00001ab1, 0x0001d494, 0x00001ab2, 0x0001d495, 0x00001ab3, 0x0001d496, 0x00001ab4, 0x0001d497, 0x00001ab5, 0x0001d498, 0x00001ab6, 0x0001d499, 0x00001ab7, 0x0001d49a, 0x00001ab8, 0x0001d49b, 0x00001ab9, 0x0001d49c, 0x00001aba, 0x0001d49e, 0x00001abb, 0x0001d49f, 0x00001abc, 0x0001d4a2, 0x00001abd, 0x0001d4a5, 0x00001abe, 0x0001d4a6, 0x00001abf, 0x0001d4a9, 0x00001ac0, 0x0001d4aa, 0x00001ac1, 0x0001d4ab, 0x00001ac2, 0x0001d4ac, 0x00001ac3, 0x0001d4ae, 0x00001ac4, 0x0001d4af, 0x00001ac5, 0x0001d4b0, 0x00001ac6, 0x0001d4b1, 0x00001ac7, 0x0001d4b2, 0x00001ac8, 0x0001d4b3, 0x00001ac9, 0x0001d4b4, 0x00001aca, 0x0001d4b5, 0x00001acb, 0x0001d4b6, 0x00001acc, 0x0001d4b7, 0x00001acd, 0x0001d4b8, 0x00001ace, 0x0001d4b9, 0x00001acf, 0x0001d4bb, 0x00001ad0, 0x0001d4bd, 0x00001ad1, 0x0001d4be, 0x00001ad2, 0x0001d4bf, 0x00001ad3, 0x0001d4c0, 0x00001ad4, 0x0001d4c2, 0x00001ad5, 0x0001d4c3, 0x00001ad6, 0x0001d4c5, 0x00001ad7, 0x0001d4c6, 0x00001ad8, 0x0001d4c7, 0x00001ad9, 0x0001d4c8, 0x00001ada, 0x0001d4c9, 0x00001adb, 0x0001d4ca, 0x00001adc, 0x0001d4cb, 0x00001add, 0x0001d4cc, 0x00001ade, 0x0001d4cd, 0x00001adf, 0x0001d4ce, 0x00001ae0, 0x0001d4cf, 0x00001ae1, 0x0001d4d0, 0x00001ae2, 0x0001d4d1, 0x00001ae3, 0x0001d4d2, 0x00001ae4, 0x0001d4d3, 0x00001ae5, 0x0001d4d4, 0x00001ae6, 0x0001d4d5, 0x00001ae7, 0x0001d4d6, 0x00001ae8, 0x0001d4d7, 0x00001ae9, 0x0001d4d8, 0x00001aea, 0x0001d4d9, 0x00001aeb, 0x0001d4da, 0x00001aec, 0x0001d4db, 0x00001aed, 0x0001d4dc, 0x00001aee, 0x0001d4dd, 0x00001aef, 0x0001d4de, 0x00001af0, 0x0001d4df, 0x00001af1, 0x0001d4e0, 0x00001af2, 0x0001d4e1, 0x00001af3, 0x0001d4e2, 0x00001af4, 0x0001d4e3, 0x00001af5, 0x0001d4e4, 0x00001af6, 0x0001d4e5, 0x00001af7, 0x0001d4e6, 0x00001af8, 0x0001d4e7, 0x00001af9, 0x0001d4e8, 0x00001afa, 0x0001d4e9, 0x00001afb, 0x0001d4ea, 0x00001afc, 0x0001d4eb, 0x00001afd, 0x0001d4ec, 0x00001afe, 0x0001d4ed, 0x00001aff, 0x0001d4ee, 0x00001b00, 0x0001d4ef, 0x00001b01, 0x0001d4f0, 0x00001b02, 0x0001d4f1, 0x00001b03, 0x0001d4f2, 0x00001b04, 0x0001d4f3, 0x00001b05, 0x0001d4f4, 0x00001b06, 0x0001d4f5, 0x00001b07, 0x0001d4f6, 0x00001b08, 0x0001d4f7, 0x00001b09, 0x0001d4f8, 0x00001b0a, 0x0001d4f9, 0x00001b0b, 0x0001d4fa, 0x00001b0c, 0x0001d4fb, 0x00001b0d, 0x0001d4fc, 0x00001b0e, 0x0001d4fd, 0x00001b0f, 0x0001d4fe, 0x00001b10, 0x0001d4ff, 0x00001b11, 0x0001d500, 0x00001b12, 0x0001d501, 0x00001b13, 0x0001d502, 0x00001b14, 0x0001d503, 0x00001b15, 0x0001d504, 0x00001b16, 0x0001d505, 0x00001b17, 0x0001d507, 0x00001b18, 0x0001d508, 0x00001b19, 0x0001d509, 0x00001b1a, 0x0001d50a, 0x00001b1b, 0x0001d50d, 0x00001b1c, 0x0001d50e, 0x00001b1d, 0x0001d50f, 0x00001b1e, 0x0001d510, 0x00001b1f, 0x0001d511, 0x00001b20, 0x0001d512, 0x00001b21, 0x0001d513, 0x00001b22, 0x0001d514, 0x00001b23, 0x0001d516, 0x00001b24, 0x0001d517, 0x00001b25, 0x0001d518, 0x00001b26, 0x0001d519, 0x00001b27, 0x0001d51a, 0x00001b28, 0x0001d51b, 0x00001b29, 0x0001d51c, 0x00001b2a, 0x0001d51e, 0x00001b2b, 0x0001d51f, 0x00001b2c, 0x0001d520, 0x00001b2d, 0x0001d521, 0x00001b2e, 0x0001d522, 0x00001b2f, 0x0001d523, 0x00001b30, 0x0001d524, 0x00001b31, 0x0001d525, 0x00001b32, 0x0001d526, 0x00001b33, 0x0001d527, 0x00001b34, 0x0001d528, 0x00001b35, 0x0001d529, 0x00001b36, 0x0001d52a, 0x00001b37, 0x0001d52b, 0x00001b38, 0x0001d52c, 0x00001b39, 0x0001d52d, 0x00001b3a, 0x0001d52e, 0x00001b3b, 0x0001d52f, 0x00001b3c, 0x0001d530, 0x00001b3d, 0x0001d531, 0x00001b3e, 0x0001d532, 0x00001b3f, 0x0001d533, 0x00001b40, 0x0001d534, 0x00001b41, 0x0001d535, 0x00001b42, 0x0001d536, 0x00001b43, 0x0001d537, 0x00001b44, 0x0001d538, 0x00001b45, 0x0001d539, 0x00001b46, 0x0001d53b, 0x00001b47, 0x0001d53c, 0x00001b48, 0x0001d53d, 0x00001b49, 0x0001d53e, 0x00001b4a, 0x0001d540, 0x00001b4b, 0x0001d541, 0x00001b4c, 0x0001d542, 0x00001b4d, 0x0001d543, 0x00001b4e, 0x0001d544, 0x00001b4f, 0x0001d546, 0x00001b50, 0x0001d54a, 0x00001b51, 0x0001d54b, 0x00001b52, 0x0001d54c, 0x00001b53, 0x0001d54d, 0x00001b54, 0x0001d54e, 0x00001b55, 0x0001d54f, 0x00001b56, 0x0001d550, 0x00001b57, 0x0001d552, 0x00001b58, 0x0001d553, 0x00001b59, 0x0001d554, 0x00001b5a, 0x0001d555, 0x00001b5b, 0x0001d556, 0x00001b5c, 0x0001d557, 0x00001b5d, 0x0001d558, 0x00001b5e, 0x0001d559, 0x00001b5f, 0x0001d55a, 0x00001b60, 0x0001d55b, 0x00001b61, 0x0001d55c, 0x00001b62, 0x0001d55d, 0x00001b63, 0x0001d55e, 0x00001b64, 0x0001d55f, 0x00001b65, 0x0001d560, 0x00001b66, 0x0001d561, 0x00001b67, 0x0001d562, 0x00001b68, 0x0001d563, 0x00001b69, 0x0001d564, 0x00001b6a, 0x0001d565, 0x00001b6b, 0x0001d566, 0x00001b6c, 0x0001d567, 0x00001b6d, 0x0001d568, 0x00001b6e, 0x0001d569, 0x00001b6f, 0x0001d56a, 0x00001b70, 0x0001d56b, 0x00001b71, 0x0001d56c, 0x00001b72, 0x0001d56d, 0x00001b73, 0x0001d56e, 0x00001b74, 0x0001d56f, 0x00001b75, 0x0001d570, 0x00001b76, 0x0001d571, 0x00001b77, 0x0001d572, 0x00001b78, 0x0001d573, 0x00001b79, 0x0001d574, 0x00001b7a, 0x0001d575, 0x00001b7b, 0x0001d576, 0x00001b7c, 0x0001d577, 0x00001b7d, 0x0001d578, 0x00001b7e, 0x0001d579, 0x00001b7f, 0x0001d57a, 0x00001b80, 0x0001d57b, 0x00001b81, 0x0001d57c, 0x00001b82, 0x0001d57d, 0x00001b83, 0x0001d57e, 0x00001b84, 0x0001d57f, 0x00001b85, 0x0001d580, 0x00001b86, 0x0001d581, 0x00001b87, 0x0001d582, 0x00001b88, 0x0001d583, 0x00001b89, 0x0001d584, 0x00001b8a, 0x0001d585, 0x00001b8b, 0x0001d586, 0x00001b8c, 0x0001d587, 0x00001b8d, 0x0001d588, 0x00001b8e, 0x0001d589, 0x00001b8f, 0x0001d58a, 0x00001b90, 0x0001d58b, 0x00001b91, 0x0001d58c, 0x00001b92, 0x0001d58d, 0x00001b93, 0x0001d58e, 0x00001b94, 0x0001d58f, 0x00001b95, 0x0001d590, 0x00001b96, 0x0001d591, 0x00001b97, 0x0001d592, 0x00001b98, 0x0001d593, 0x00001b99, 0x0001d594, 0x00001b9a, 0x0001d595, 0x00001b9b, 0x0001d596, 0x00001b9c, 0x0001d597, 0x00001b9d, 0x0001d598, 0x00001b9e, 0x0001d599, 0x00001b9f, 0x0001d59a, 0x00001ba0, 0x0001d59b, 0x00001ba1, 0x0001d59c, 0x00001ba2, 0x0001d59d, 0x00001ba3, 0x0001d59e, 0x00001ba4, 0x0001d59f, 0x00001ba5, 0x0001d5a0, 0x00001ba6, 0x0001d5a1, 0x00001ba7, 0x0001d5a2, 0x00001ba8, 0x0001d5a3, 0x00001ba9, 0x0001d5a4, 0x00001baa, 0x0001d5a5, 0x00001bab, 0x0001d5a6, 0x00001bac, 0x0001d5a7, 0x00001bad, 0x0001d5a8, 0x00001bae, 0x0001d5a9, 0x00001baf, 0x0001d5aa, 0x00001bb0, 0x0001d5ab, 0x00001bb1, 0x0001d5ac, 0x00001bb2, 0x0001d5ad, 0x00001bb3, 0x0001d5ae, 0x00001bb4, 0x0001d5af, 0x00001bb5, 0x0001d5b0, 0x00001bb6, 0x0001d5b1, 0x00001bb7, 0x0001d5b2, 0x00001bb8, 0x0001d5b3, 0x00001bb9, 0x0001d5b4, 0x00001bba, 0x0001d5b5, 0x00001bbb, 0x0001d5b6, 0x00001bbc, 0x0001d5b7, 0x00001bbd, 0x0001d5b8, 0x00001bbe, 0x0001d5b9, 0x00001bbf, 0x0001d5ba, 0x00001bc0, 0x0001d5bb, 0x00001bc1, 0x0001d5bc, 0x00001bc2, 0x0001d5bd, 0x00001bc3, 0x0001d5be, 0x00001bc4, 0x0001d5bf, 0x00001bc5, 0x0001d5c0, 0x00001bc6, 0x0001d5c1, 0x00001bc7, 0x0001d5c2, 0x00001bc8, 0x0001d5c3, 0x00001bc9, 0x0001d5c4, 0x00001bca, 0x0001d5c5, 0x00001bcb, 0x0001d5c6, 0x00001bcc, 0x0001d5c7, 0x00001bcd, 0x0001d5c8, 0x00001bce, 0x0001d5c9, 0x00001bcf, 0x0001d5ca, 0x00001bd0, 0x0001d5cb, 0x00001bd1, 0x0001d5cc, 0x00001bd2, 0x0001d5cd, 0x00001bd3, 0x0001d5ce, 0x00001bd4, 0x0001d5cf, 0x00001bd5, 0x0001d5d0, 0x00001bd6, 0x0001d5d1, 0x00001bd7, 0x0001d5d2, 0x00001bd8, 0x0001d5d3, 0x00001bd9, 0x0001d5d4, 0x00001bda, 0x0001d5d5, 0x00001bdb, 0x0001d5d6, 0x00001bdc, 0x0001d5d7, 0x00001bdd, 0x0001d5d8, 0x00001bde, 0x0001d5d9, 0x00001bdf, 0x0001d5da, 0x00001be0, 0x0001d5db, 0x00001be1, 0x0001d5dc, 0x00001be2, 0x0001d5dd, 0x00001be3, 0x0001d5de, 0x00001be4, 0x0001d5df, 0x00001be5, 0x0001d5e0, 0x00001be6, 0x0001d5e1, 0x00001be7, 0x0001d5e2, 0x00001be8, 0x0001d5e3, 0x00001be9, 0x0001d5e4, 0x00001bea, 0x0001d5e5, 0x00001beb, 0x0001d5e6, 0x00001bec, 0x0001d5e7, 0x00001bed, 0x0001d5e8, 0x00001bee, 0x0001d5e9, 0x00001bef, 0x0001d5ea, 0x00001bf0, 0x0001d5eb, 0x00001bf1, 0x0001d5ec, 0x00001bf2, 0x0001d5ed, 0x00001bf3, 0x0001d5ee, 0x00001bf4, 0x0001d5ef, 0x00001bf5, 0x0001d5f0, 0x00001bf6, 0x0001d5f1, 0x00001bf7, 0x0001d5f2, 0x00001bf8, 0x0001d5f3, 0x00001bf9, 0x0001d5f4, 0x00001bfa, 0x0001d5f5, 0x00001bfb, 0x0001d5f6, 0x00001bfc, 0x0001d5f7, 0x00001bfd, 0x0001d5f8, 0x00001bfe, 0x0001d5f9, 0x00001bff, 0x0001d5fa, 0x00001c00, 0x0001d5fb, 0x00001c01, 0x0001d5fc, 0x00001c02, 0x0001d5fd, 0x00001c03, 0x0001d5fe, 0x00001c04, 0x0001d5ff, 0x00001c05, 0x0001d600, 0x00001c06, 0x0001d601, 0x00001c07, 0x0001d602, 0x00001c08, 0x0001d603, 0x00001c09, 0x0001d604, 0x00001c0a, 0x0001d605, 0x00001c0b, 0x0001d606, 0x00001c0c, 0x0001d607, 0x00001c0d, 0x0001d608, 0x00001c0e, 0x0001d609, 0x00001c0f, 0x0001d60a, 0x00001c10, 0x0001d60b, 0x00001c11, 0x0001d60c, 0x00001c12, 0x0001d60d, 0x00001c13, 0x0001d60e, 0x00001c14, 0x0001d60f, 0x00001c15, 0x0001d610, 0x00001c16, 0x0001d611, 0x00001c17, 0x0001d612, 0x00001c18, 0x0001d613, 0x00001c19, 0x0001d614, 0x00001c1a, 0x0001d615, 0x00001c1b, 0x0001d616, 0x00001c1c, 0x0001d617, 0x00001c1d, 0x0001d618, 0x00001c1e, 0x0001d619, 0x00001c1f, 0x0001d61a, 0x00001c20, 0x0001d61b, 0x00001c21, 0x0001d61c, 0x00001c22, 0x0001d61d, 0x00001c23, 0x0001d61e, 0x00001c24, 0x0001d61f, 0x00001c25, 0x0001d620, 0x00001c26, 0x0001d621, 0x00001c27, 0x0001d622, 0x00001c28, 0x0001d623, 0x00001c29, 0x0001d624, 0x00001c2a, 0x0001d625, 0x00001c2b, 0x0001d626, 0x00001c2c, 0x0001d627, 0x00001c2d, 0x0001d628, 0x00001c2e, 0x0001d629, 0x00001c2f, 0x0001d62a, 0x00001c30, 0x0001d62b, 0x00001c31, 0x0001d62c, 0x00001c32, 0x0001d62d, 0x00001c33, 0x0001d62e, 0x00001c34, 0x0001d62f, 0x00001c35, 0x0001d630, 0x00001c36, 0x0001d631, 0x00001c37, 0x0001d632, 0x00001c38, 0x0001d633, 0x00001c39, 0x0001d634, 0x00001c3a, 0x0001d635, 0x00001c3b, 0x0001d636, 0x00001c3c, 0x0001d637, 0x00001c3d, 0x0001d638, 0x00001c3e, 0x0001d639, 0x00001c3f, 0x0001d63a, 0x00001c40, 0x0001d63b, 0x00001c41, 0x0001d63c, 0x00001c42, 0x0001d63d, 0x00001c43, 0x0001d63e, 0x00001c44, 0x0001d63f, 0x00001c45, 0x0001d640, 0x00001c46, 0x0001d641, 0x00001c47, 0x0001d642, 0x00001c48, 0x0001d643, 0x00001c49, 0x0001d644, 0x00001c4a, 0x0001d645, 0x00001c4b, 0x0001d646, 0x00001c4c, 0x0001d647, 0x00001c4d, 0x0001d648, 0x00001c4e, 0x0001d649, 0x00001c4f, 0x0001d64a, 0x00001c50, 0x0001d64b, 0x00001c51, 0x0001d64c, 0x00001c52, 0x0001d64d, 0x00001c53, 0x0001d64e, 0x00001c54, 0x0001d64f, 0x00001c55, 0x0001d650, 0x00001c56, 0x0001d651, 0x00001c57, 0x0001d652, 0x00001c58, 0x0001d653, 0x00001c59, 0x0001d654, 0x00001c5a, 0x0001d655, 0x00001c5b, 0x0001d656, 0x00001c5c, 0x0001d657, 0x00001c5d, 0x0001d658, 0x00001c5e, 0x0001d659, 0x00001c5f, 0x0001d65a, 0x00001c60, 0x0001d65b, 0x00001c61, 0x0001d65c, 0x00001c62, 0x0001d65d, 0x00001c63, 0x0001d65e, 0x00001c64, 0x0001d65f, 0x00001c65, 0x0001d660, 0x00001c66, 0x0001d661, 0x00001c67, 0x0001d662, 0x00001c68, 0x0001d663, 0x00001c69, 0x0001d664, 0x00001c6a, 0x0001d665, 0x00001c6b, 0x0001d666, 0x00001c6c, 0x0001d667, 0x00001c6d, 0x0001d668, 0x00001c6e, 0x0001d669, 0x00001c6f, 0x0001d66a, 0x00001c70, 0x0001d66b, 0x00001c71, 0x0001d66c, 0x00001c72, 0x0001d66d, 0x00001c73, 0x0001d66e, 0x00001c74, 0x0001d66f, 0x00001c75, 0x0001d670, 0x00001c76, 0x0001d671, 0x00001c77, 0x0001d672, 0x00001c78, 0x0001d673, 0x00001c79, 0x0001d674, 0x00001c7a, 0x0001d675, 0x00001c7b, 0x0001d676, 0x00001c7c, 0x0001d677, 0x00001c7d, 0x0001d678, 0x00001c7e, 0x0001d679, 0x00001c7f, 0x0001d67a, 0x00001c80, 0x0001d67b, 0x00001c81, 0x0001d67c, 0x00001c82, 0x0001d67d, 0x00001c83, 0x0001d67e, 0x00001c84, 0x0001d67f, 0x00001c85, 0x0001d680, 0x00001c86, 0x0001d681, 0x00001c87, 0x0001d682, 0x00001c88, 0x0001d683, 0x00001c89, 0x0001d684, 0x00001c8a, 0x0001d685, 0x00001c8b, 0x0001d686, 0x00001c8c, 0x0001d687, 0x00001c8d, 0x0001d688, 0x00001c8e, 0x0001d689, 0x00001c8f, 0x0001d68a, 0x00001c90, 0x0001d68b, 0x00001c91, 0x0001d68c, 0x00001c92, 0x0001d68d, 0x00001c93, 0x0001d68e, 0x00001c94, 0x0001d68f, 0x00001c95, 0x0001d690, 0x00001c96, 0x0001d691, 0x00001c97, 0x0001d692, 0x00001c98, 0x0001d693, 0x00001c99, 0x0001d694, 0x00001c9a, 0x0001d695, 0x00001c9b, 0x0001d696, 0x00001c9c, 0x0001d697, 0x00001c9d, 0x0001d698, 0x00001c9e, 0x0001d699, 0x00001c9f, 0x0001d69a, 0x00001ca0, 0x0001d69b, 0x00001ca1, 0x0001d69c, 0x00001ca2, 0x0001d69d, 0x00001ca3, 0x0001d69e, 0x00001ca4, 0x0001d69f, 0x00001ca5, 0x0001d6a0, 0x00001ca6, 0x0001d6a1, 0x00001ca7, 0x0001d6a2, 0x00001ca8, 0x0001d6a3, 0x00001ca9, 0x0001d6a8, 0x00001caa, 0x0001d6a9, 0x00001cab, 0x0001d6aa, 0x00001cac, 0x0001d6ab, 0x00001cad, 0x0001d6ac, 0x00001cae, 0x0001d6ad, 0x00001caf, 0x0001d6ae, 0x00001cb0, 0x0001d6af, 0x00001cb1, 0x0001d6b0, 0x00001cb2, 0x0001d6b1, 0x00001cb3, 0x0001d6b2, 0x00001cb4, 0x0001d6b3, 0x00001cb5, 0x0001d6b4, 0x00001cb6, 0x0001d6b5, 0x00001cb7, 0x0001d6b6, 0x00001cb8, 0x0001d6b7, 0x00001cb9, 0x0001d6b8, 0x00001cba, 0x0001d6b9, 0x00001cbb, 0x0001d6ba, 0x00001cbc, 0x0001d6bb, 0x00001cbd, 0x0001d6bc, 0x00001cbe, 0x0001d6bd, 0x00001cbf, 0x0001d6be, 0x00001cc0, 0x0001d6bf, 0x00001cc1, 0x0001d6c0, 0x00001cc2, 0x0001d6c1, 0x00001cc3, 0x0001d6c2, 0x00001cc4, 0x0001d6c3, 0x00001cc5, 0x0001d6c4, 0x00001cc6, 0x0001d6c5, 0x00001cc7, 0x0001d6c6, 0x00001cc8, 0x0001d6c7, 0x00001cc9, 0x0001d6c8, 0x00001cca, 0x0001d6c9, 0x00001ccb, 0x0001d6ca, 0x00001ccc, 0x0001d6cb, 0x00001ccd, 0x0001d6cc, 0x00001cce, 0x0001d6cd, 0x00001ccf, 0x0001d6ce, 0x00001cd0, 0x0001d6cf, 0x00001cd1, 0x0001d6d0, 0x00001cd2, 0x0001d6d1, 0x00001cd3, 0x0001d6d2, 0x00001cd4, 0x0001d6d3, 0x00001cd5, 0x0001d6d4, 0x00001cd6, 0x0001d6d5, 0x00001cd7, 0x0001d6d6, 0x00001cd8, 0x0001d6d7, 0x00001cd9, 0x0001d6d8, 0x00001cda, 0x0001d6d9, 0x00001cdb, 0x0001d6da, 0x00001cdc, 0x0001d6db, 0x00001cdd, 0x0001d6dc, 0x00001cde, 0x0001d6dd, 0x00001cdf, 0x0001d6de, 0x00001ce0, 0x0001d6df, 0x00001ce1, 0x0001d6e0, 0x00001ce2, 0x0001d6e1, 0x00001ce3, 0x0001d6e2, 0x00001ce4, 0x0001d6e3, 0x00001ce5, 0x0001d6e4, 0x00001ce6, 0x0001d6e5, 0x00001ce7, 0x0001d6e6, 0x00001ce8, 0x0001d6e7, 0x00001ce9, 0x0001d6e8, 0x00001cea, 0x0001d6e9, 0x00001ceb, 0x0001d6ea, 0x00001cec, 0x0001d6eb, 0x00001ced, 0x0001d6ec, 0x00001cee, 0x0001d6ed, 0x00001cef, 0x0001d6ee, 0x00001cf0, 0x0001d6ef, 0x00001cf1, 0x0001d6f0, 0x00001cf2, 0x0001d6f1, 0x00001cf3, 0x0001d6f2, 0x00001cf4, 0x0001d6f3, 0x00001cf5, 0x0001d6f4, 0x00001cf6, 0x0001d6f5, 0x00001cf7, 0x0001d6f6, 0x00001cf8, 0x0001d6f7, 0x00001cf9, 0x0001d6f8, 0x00001cfa, 0x0001d6f9, 0x00001cfb, 0x0001d6fa, 0x00001cfc, 0x0001d6fb, 0x00001cfd, 0x0001d6fc, 0x00001cfe, 0x0001d6fd, 0x00001cff, 0x0001d6fe, 0x00001d00, 0x0001d6ff, 0x00001d01, 0x0001d700, 0x00001d02, 0x0001d701, 0x00001d03, 0x0001d702, 0x00001d04, 0x0001d703, 0x00001d05, 0x0001d704, 0x00001d06, 0x0001d705, 0x00001d07, 0x0001d706, 0x00001d08, 0x0001d707, 0x00001d09, 0x0001d708, 0x00001d0a, 0x0001d709, 0x00001d0b, 0x0001d70a, 0x00001d0c, 0x0001d70b, 0x00001d0d, 0x0001d70c, 0x00001d0e, 0x0001d70d, 0x00001d0f, 0x0001d70e, 0x00001d10, 0x0001d70f, 0x00001d11, 0x0001d710, 0x00001d12, 0x0001d711, 0x00001d13, 0x0001d712, 0x00001d14, 0x0001d713, 0x00001d15, 0x0001d714, 0x00001d16, 0x0001d715, 0x00001d17, 0x0001d716, 0x00001d18, 0x0001d717, 0x00001d19, 0x0001d718, 0x00001d1a, 0x0001d719, 0x00001d1b, 0x0001d71a, 0x00001d1c, 0x0001d71b, 0x00001d1d, 0x0001d71c, 0x00001d1e, 0x0001d71d, 0x00001d1f, 0x0001d71e, 0x00001d20, 0x0001d71f, 0x00001d21, 0x0001d720, 0x00001d22, 0x0001d721, 0x00001d23, 0x0001d722, 0x00001d24, 0x0001d723, 0x00001d25, 0x0001d724, 0x00001d26, 0x0001d725, 0x00001d27, 0x0001d726, 0x00001d28, 0x0001d727, 0x00001d29, 0x0001d728, 0x00001d2a, 0x0001d729, 0x00001d2b, 0x0001d72a, 0x00001d2c, 0x0001d72b, 0x00001d2d, 0x0001d72c, 0x00001d2e, 0x0001d72d, 0x00001d2f, 0x0001d72e, 0x00001d30, 0x0001d72f, 0x00001d31, 0x0001d730, 0x00001d32, 0x0001d731, 0x00001d33, 0x0001d732, 0x00001d34, 0x0001d733, 0x00001d35, 0x0001d734, 0x00001d36, 0x0001d735, 0x00001d37, 0x0001d736, 0x00001d38, 0x0001d737, 0x00001d39, 0x0001d738, 0x00001d3a, 0x0001d739, 0x00001d3b, 0x0001d73a, 0x00001d3c, 0x0001d73b, 0x00001d3d, 0x0001d73c, 0x00001d3e, 0x0001d73d, 0x00001d3f, 0x0001d73e, 0x00001d40, 0x0001d73f, 0x00001d41, 0x0001d740, 0x00001d42, 0x0001d741, 0x00001d43, 0x0001d742, 0x00001d44, 0x0001d743, 0x00001d45, 0x0001d744, 0x00001d46, 0x0001d745, 0x00001d47, 0x0001d746, 0x00001d48, 0x0001d747, 0x00001d49, 0x0001d748, 0x00001d4a, 0x0001d749, 0x00001d4b, 0x0001d74a, 0x00001d4c, 0x0001d74b, 0x00001d4d, 0x0001d74c, 0x00001d4e, 0x0001d74d, 0x00001d4f, 0x0001d74e, 0x00001d50, 0x0001d74f, 0x00001d51, 0x0001d750, 0x00001d52, 0x0001d751, 0x00001d53, 0x0001d752, 0x00001d54, 0x0001d753, 0x00001d55, 0x0001d754, 0x00001d56, 0x0001d755, 0x00001d57, 0x0001d756, 0x00001d58, 0x0001d757, 0x00001d59, 0x0001d758, 0x00001d5a, 0x0001d759, 0x00001d5b, 0x0001d75a, 0x00001d5c, 0x0001d75b, 0x00001d5d, 0x0001d75c, 0x00001d5e, 0x0001d75d, 0x00001d5f, 0x0001d75e, 0x00001d60, 0x0001d75f, 0x00001d61, 0x0001d760, 0x00001d62, 0x0001d761, 0x00001d63, 0x0001d762, 0x00001d64, 0x0001d763, 0x00001d65, 0x0001d764, 0x00001d66, 0x0001d765, 0x00001d67, 0x0001d766, 0x00001d68, 0x0001d767, 0x00001d69, 0x0001d768, 0x00001d6a, 0x0001d769, 0x00001d6b, 0x0001d76a, 0x00001d6c, 0x0001d76b, 0x00001d6d, 0x0001d76c, 0x00001d6e, 0x0001d76d, 0x00001d6f, 0x0001d76e, 0x00001d70, 0x0001d76f, 0x00001d71, 0x0001d770, 0x00001d72, 0x0001d771, 0x00001d73, 0x0001d772, 0x00001d74, 0x0001d773, 0x00001d75, 0x0001d774, 0x00001d76, 0x0001d775, 0x00001d77, 0x0001d776, 0x00001d78, 0x0001d777, 0x00001d79, 0x0001d778, 0x00001d7a, 0x0001d779, 0x00001d7b, 0x0001d77a, 0x00001d7c, 0x0001d77b, 0x00001d7d, 0x0001d77c, 0x00001d7e, 0x0001d77d, 0x00001d7f, 0x0001d77e, 0x00001d80, 0x0001d77f, 0x00001d81, 0x0001d780, 0x00001d82, 0x0001d781, 0x00001d83, 0x0001d782, 0x00001d84, 0x0001d783, 0x00001d85, 0x0001d784, 0x00001d86, 0x0001d785, 0x00001d87, 0x0001d786, 0x00001d88, 0x0001d787, 0x00001d89, 0x0001d788, 0x00001d8a, 0x0001d789, 0x00001d8b, 0x0001d78a, 0x00001d8c, 0x0001d78b, 0x00001d8d, 0x0001d78c, 0x00001d8e, 0x0001d78d, 0x00001d8f, 0x0001d78e, 0x00001d90, 0x0001d78f, 0x00001d91, 0x0001d790, 0x00001d92, 0x0001d791, 0x00001d93, 0x0001d792, 0x00001d94, 0x0001d793, 0x00001d95, 0x0001d794, 0x00001d96, 0x0001d795, 0x00001d97, 0x0001d796, 0x00001d98, 0x0001d797, 0x00001d99, 0x0001d798, 0x00001d9a, 0x0001d799, 0x00001d9b, 0x0001d79a, 0x00001d9c, 0x0001d79b, 0x00001d9d, 0x0001d79c, 0x00001d9e, 0x0001d79d, 0x00001d9f, 0x0001d79e, 0x00001da0, 0x0001d79f, 0x00001da1, 0x0001d7a0, 0x00001da2, 0x0001d7a1, 0x00001da3, 0x0001d7a2, 0x00001da4, 0x0001d7a3, 0x00001da5, 0x0001d7a4, 0x00001da6, 0x0001d7a5, 0x00001da7, 0x0001d7a6, 0x00001da8, 0x0001d7a7, 0x00001da9, 0x0001d7a8, 0x00001daa, 0x0001d7a9, 0x00001dab, 0x0001d7aa, 0x00001dac, 0x0001d7ab, 0x00001dad, 0x0001d7ac, 0x00001dae, 0x0001d7ad, 0x00001daf, 0x0001d7ae, 0x00001db0, 0x0001d7af, 0x00001db1, 0x0001d7b0, 0x00001db2, 0x0001d7b1, 0x00001db3, 0x0001d7b2, 0x00001db4, 0x0001d7b3, 0x00001db5, 0x0001d7b4, 0x00001db6, 0x0001d7b5, 0x00001db7, 0x0001d7b6, 0x00001db8, 0x0001d7b7, 0x00001db9, 0x0001d7b8, 0x00001dba, 0x0001d7b9, 0x00001dbb, 0x0001d7ba, 0x00001dbc, 0x0001d7bb, 0x00001dbd, 0x0001d7bc, 0x00001dbe, 0x0001d7bd, 0x00001dbf, 0x0001d7be, 0x00001dc0, 0x0001d7bf, 0x00001dc1, 0x0001d7c0, 0x00001dc2, 0x0001d7c1, 0x00001dc3, 0x0001d7c2, 0x00001dc4, 0x0001d7c3, 0x00001dc5, 0x0001d7c4, 0x00001dc6, 0x0001d7c5, 0x00001dc7, 0x0001d7c6, 0x00001dc8, 0x0001d7c7, 0x00001dc9, 0x0001d7c8, 0x00001dca, 0x0001d7c9, 0x00001dcb, 0x0001d7ce, 0x00001dcc, 0x0001d7cf, 0x00001dcd, 0x0001d7d0, 0x00001dce, 0x0001d7d1, 0x00001dcf, 0x0001d7d2, 0x00001dd0, 0x0001d7d3, 0x00001dd1, 0x0001d7d4, 0x00001dd2, 0x0001d7d5, 0x00001dd3, 0x0001d7d6, 0x00001dd4, 0x0001d7d7, 0x00001dd5, 0x0001d7d8, 0x00001dd6, 0x0001d7d9, 0x00001dd7, 0x0001d7da, 0x00001dd8, 0x0001d7db, 0x00001dd9, 0x0001d7dc, 0x00001dda, 0x0001d7dd, 0x00001ddb, 0x0001d7de, 0x00001ddc, 0x0001d7df, 0x00001ddd, 0x0001d7e0, 0x00001dde, 0x0001d7e1, 0x00001ddf, 0x0001d7e2, 0x00001de0, 0x0001d7e3, 0x00001de1, 0x0001d7e4, 0x00001de2, 0x0001d7e5, 0x00001de3, 0x0001d7e6, 0x00001de4, 0x0001d7e7, 0x00001de5, 0x0001d7e8, 0x00001de6, 0x0001d7e9, 0x00001de7, 0x0001d7ea, 0x00001de8, 0x0001d7eb, 0x00001de9, 0x0001d7ec, 0x00001dea, 0x0001d7ed, 0x00001deb, 0x0001d7ee, 0x00001dec, 0x0001d7ef, 0x00001ded, 0x0001d7f0, 0x00001dee, 0x0001d7f1, 0x00001def, 0x0001d7f2, 0x00001df0, 0x0001d7f3, 0x00001df1, 0x0001d7f4, 0x00001df2, 0x0001d7f5, 0x00001df3, 0x0001d7f6, 0x00001df4, 0x0001d7f7, 0x00001df5, 0x0001d7f8, 0x00001df6, 0x0001d7f9, 0x00001df7, 0x0001d7fa, 0x00001df8, 0x0001d7fb, 0x00001df9, 0x0001d7fc, 0x00001dfa, 0x0001d7fd, 0x00001dfb, 0x0001d7fe, 0x00001dfc, 0x0001d7ff, 0x00001dfd, 0x0002f800, 0x00001dfe, 0x0002f801, 0x00001dff, 0x0002f802, 0x00001e00, 0x0002f803, 0x00001e01, 0x0002f804, 0x00001e02, 0x0002f805, 0x00001e03, 0x0002f806, 0x00001e04, 0x0002f807, 0x00001e05, 0x0002f808, 0x00001e06, 0x0002f809, 0x00001e07, 0x0002f80a, 0x00001e08, 0x0002f80b, 0x00001e09, 0x0002f80c, 0x00001e0a, 0x0002f80d, 0x00001e0b, 0x0002f80e, 0x00001e0c, 0x0002f80f, 0x00001e0d, 0x0002f810, 0x00001e0e, 0x0002f811, 0x00001e0f, 0x0002f812, 0x00001e10, 0x0002f813, 0x00001e11, 0x0002f814, 0x00001e12, 0x0002f815, 0x00001e13, 0x0002f816, 0x00001e14, 0x0002f817, 0x00001e15, 0x0002f818, 0x00001e16, 0x0002f819, 0x00001e17, 0x0002f81a, 0x00001e18, 0x0002f81b, 0x00001e19, 0x0002f81c, 0x00001e1a, 0x0002f81d, 0x00001e1b, 0x0002f81e, 0x00001e1c, 0x0002f81f, 0x00001e1d, 0x0002f820, 0x00001e1e, 0x0002f821, 0x00001e1f, 0x0002f822, 0x00001e20, 0x0002f823, 0x00001e21, 0x0002f824, 0x00001e22, 0x0002f825, 0x00001e23, 0x0002f826, 0x00001e24, 0x0002f827, 0x00001e25, 0x0002f828, 0x00001e26, 0x0002f829, 0x00001e27, 0x0002f82a, 0x00001e28, 0x0002f82b, 0x00001e29, 0x0002f82c, 0x00001e2a, 0x0002f82d, 0x00001e2b, 0x0002f82e, 0x00001e2c, 0x0002f82f, 0x00001e2d, 0x0002f830, 0x00001e2e, 0x0002f831, 0x00001e2f, 0x0002f832, 0x00001e30, 0x0002f833, 0x00001e31, 0x0002f834, 0x00001e32, 0x0002f835, 0x00001e33, 0x0002f836, 0x00001e34, 0x0002f837, 0x00001e35, 0x0002f838, 0x00001e36, 0x0002f839, 0x00001e37, 0x0002f83a, 0x00001e38, 0x0002f83b, 0x00001e39, 0x0002f83c, 0x00001e3a, 0x0002f83d, 0x00001e3b, 0x0002f83e, 0x00001e3c, 0x0002f83f, 0x00001e3d, 0x0002f840, 0x00001e3e, 0x0002f841, 0x00001e3f, 0x0002f842, 0x00001e40, 0x0002f843, 0x00001e41, 0x0002f844, 0x00001e42, 0x0002f845, 0x00001e43, 0x0002f846, 0x00001e44, 0x0002f847, 0x00001e45, 0x0002f848, 0x00001e46, 0x0002f849, 0x00001e47, 0x0002f84a, 0x00001e48, 0x0002f84b, 0x00001e49, 0x0002f84c, 0x00001e4a, 0x0002f84d, 0x00001e4b, 0x0002f84e, 0x00001e4c, 0x0002f84f, 0x00001e4d, 0x0002f850, 0x00001e4e, 0x0002f851, 0x00001e4f, 0x0002f852, 0x00001e50, 0x0002f853, 0x00001e51, 0x0002f854, 0x00001e52, 0x0002f855, 0x00001e53, 0x0002f856, 0x00001e54, 0x0002f857, 0x00001e55, 0x0002f858, 0x00001e56, 0x0002f859, 0x00001e57, 0x0002f85a, 0x00001e58, 0x0002f85b, 0x00001e59, 0x0002f85c, 0x00001e5a, 0x0002f85d, 0x00001e5b, 0x0002f85e, 0x00001e5c, 0x0002f85f, 0x00001e5d, 0x0002f860, 0x00001e5e, 0x0002f861, 0x00001e5f, 0x0002f862, 0x00001e60, 0x0002f863, 0x00001e61, 0x0002f864, 0x00001e62, 0x0002f865, 0x00001e63, 0x0002f866, 0x00001e64, 0x0002f867, 0x00001e65, 0x0002f868, 0x00001e66, 0x0002f869, 0x00001e67, 0x0002f86a, 0x00001e68, 0x0002f86b, 0x00001e69, 0x0002f86c, 0x00001e6a, 0x0002f86d, 0x00001e6b, 0x0002f86e, 0x00001e6c, 0x0002f86f, 0x00001e6d, 0x0002f870, 0x00001e6e, 0x0002f871, 0x00001e6f, 0x0002f872, 0x00001e70, 0x0002f873, 0x00001e71, 0x0002f874, 0x00001e72, 0x0002f875, 0x00001e73, 0x0002f876, 0x00001e74, 0x0002f877, 0x00001e75, 0x0002f878, 0x00001e76, 0x0002f879, 0x00001e77, 0x0002f87a, 0x00001e78, 0x0002f87b, 0x00001e79, 0x0002f87c, 0x00001e7a, 0x0002f87d, 0x00001e7b, 0x0002f87e, 0x00001e7c, 0x0002f87f, 0x00001e7d, 0x0002f880, 0x00001e7e, 0x0002f881, 0x00001e7f, 0x0002f882, 0x00001e80, 0x0002f883, 0x00001e81, 0x0002f884, 0x00001e82, 0x0002f885, 0x00001e83, 0x0002f886, 0x00001e84, 0x0002f887, 0x00001e85, 0x0002f888, 0x00001e86, 0x0002f889, 0x00001e87, 0x0002f88a, 0x00001e88, 0x0002f88b, 0x00001e89, 0x0002f88c, 0x00001e8a, 0x0002f88d, 0x00001e8b, 0x0002f88e, 0x00001e8c, 0x0002f88f, 0x00001e8d, 0x0002f890, 0x00001e8e, 0x0002f891, 0x00001e8f, 0x0002f892, 0x00001e90, 0x0002f893, 0x00001e91, 0x0002f894, 0x00001e92, 0x0002f895, 0x00001e93, 0x0002f896, 0x00001e94, 0x0002f897, 0x00001e95, 0x0002f898, 0x00001e96, 0x0002f899, 0x00001e97, 0x0002f89a, 0x00001e98, 0x0002f89b, 0x00001e99, 0x0002f89c, 0x00001e9a, 0x0002f89d, 0x00001e9b, 0x0002f89e, 0x00001e9c, 0x0002f89f, 0x00001e9d, 0x0002f8a0, 0x00001e9e, 0x0002f8a1, 0x00001e9f, 0x0002f8a2, 0x00001ea0, 0x0002f8a3, 0x00001ea1, 0x0002f8a4, 0x00001ea2, 0x0002f8a5, 0x00001ea3, 0x0002f8a6, 0x00001ea4, 0x0002f8a7, 0x00001ea5, 0x0002f8a8, 0x00001ea6, 0x0002f8a9, 0x00001ea7, 0x0002f8aa, 0x00001ea8, 0x0002f8ab, 0x00001ea9, 0x0002f8ac, 0x00001eaa, 0x0002f8ad, 0x00001eab, 0x0002f8ae, 0x00001eac, 0x0002f8af, 0x00001ead, 0x0002f8b0, 0x00001eae, 0x0002f8b1, 0x00001eaf, 0x0002f8b2, 0x00001eb0, 0x0002f8b3, 0x00001eb1, 0x0002f8b4, 0x00001eb2, 0x0002f8b5, 0x00001eb3, 0x0002f8b6, 0x00001eb4, 0x0002f8b7, 0x00001eb5, 0x0002f8b8, 0x00001eb6, 0x0002f8b9, 0x00001eb7, 0x0002f8ba, 0x00001eb8, 0x0002f8bb, 0x00001eb9, 0x0002f8bc, 0x00001eba, 0x0002f8bd, 0x00001ebb, 0x0002f8be, 0x00001ebc, 0x0002f8bf, 0x00001ebd, 0x0002f8c0, 0x00001ebe, 0x0002f8c1, 0x00001ebf, 0x0002f8c2, 0x00001ec0, 0x0002f8c3, 0x00001ec1, 0x0002f8c4, 0x00001ec2, 0x0002f8c5, 0x00001ec3, 0x0002f8c6, 0x00001ec4, 0x0002f8c7, 0x00001ec5, 0x0002f8c8, 0x00001ec6, 0x0002f8c9, 0x00001ec7, 0x0002f8ca, 0x00001ec8, 0x0002f8cb, 0x00001ec9, 0x0002f8cc, 0x00001eca, 0x0002f8cd, 0x00001ecb, 0x0002f8ce, 0x00001ecc, 0x0002f8cf, 0x00001ecd, 0x0002f8d0, 0x00001ece, 0x0002f8d1, 0x00001ecf, 0x0002f8d2, 0x00001ed0, 0x0002f8d3, 0x00001ed1, 0x0002f8d4, 0x00001ed2, 0x0002f8d5, 0x00001ed3, 0x0002f8d6, 0x00001ed4, 0x0002f8d7, 0x00001ed5, 0x0002f8d8, 0x00001ed6, 0x0002f8d9, 0x00001ed7, 0x0002f8da, 0x00001ed8, 0x0002f8db, 0x00001ed9, 0x0002f8dc, 0x00001eda, 0x0002f8dd, 0x00001edb, 0x0002f8de, 0x00001edc, 0x0002f8df, 0x00001edd, 0x0002f8e0, 0x00001ede, 0x0002f8e1, 0x00001edf, 0x0002f8e2, 0x00001ee0, 0x0002f8e3, 0x00001ee1, 0x0002f8e4, 0x00001ee2, 0x0002f8e5, 0x00001ee3, 0x0002f8e6, 0x00001ee4, 0x0002f8e7, 0x00001ee5, 0x0002f8e8, 0x00001ee6, 0x0002f8e9, 0x00001ee7, 0x0002f8ea, 0x00001ee8, 0x0002f8eb, 0x00001ee9, 0x0002f8ec, 0x00001eea, 0x0002f8ed, 0x00001eeb, 0x0002f8ee, 0x00001eec, 0x0002f8ef, 0x00001eed, 0x0002f8f0, 0x00001eee, 0x0002f8f1, 0x00001eef, 0x0002f8f2, 0x00001ef0, 0x0002f8f3, 0x00001ef1, 0x0002f8f4, 0x00001ef2, 0x0002f8f5, 0x00001ef3, 0x0002f8f6, 0x00001ef4, 0x0002f8f7, 0x00001ef5, 0x0002f8f8, 0x00001ef6, 0x0002f8f9, 0x00001ef7, 0x0002f8fa, 0x00001ef8, 0x0002f8fb, 0x00001ef9, 0x0002f8fc, 0x00001efa, 0x0002f8fd, 0x00001efb, 0x0002f8fe, 0x00001efc, 0x0002f8ff, 0x00001efd, 0x0002f900, 0x00001efe, 0x0002f901, 0x00001eff, 0x0002f902, 0x00001f00, 0x0002f903, 0x00001f01, 0x0002f904, 0x00001f02, 0x0002f905, 0x00001f03, 0x0002f906, 0x00001f04, 0x0002f907, 0x00001f05, 0x0002f908, 0x00001f06, 0x0002f909, 0x00001f07, 0x0002f90a, 0x00001f08, 0x0002f90b, 0x00001f09, 0x0002f90c, 0x00001f0a, 0x0002f90d, 0x00001f0b, 0x0002f90e, 0x00001f0c, 0x0002f90f, 0x00001f0d, 0x0002f910, 0x00001f0e, 0x0002f911, 0x00001f0f, 0x0002f912, 0x00001f10, 0x0002f913, 0x00001f11, 0x0002f914, 0x00001f12, 0x0002f915, 0x00001f13, 0x0002f916, 0x00001f14, 0x0002f917, 0x00001f15, 0x0002f918, 0x00001f16, 0x0002f919, 0x00001f17, 0x0002f91a, 0x00001f18, 0x0002f91b, 0x00001f19, 0x0002f91c, 0x00001f1a, 0x0002f91d, 0x00001f1b, 0x0002f91e, 0x00001f1c, 0x0002f91f, 0x00001f1d, 0x0002f920, 0x00001f1e, 0x0002f921, 0x00001f1f, 0x0002f922, 0x00001f20, 0x0002f923, 0x00001f21, 0x0002f924, 0x00001f22, 0x0002f925, 0x00001f23, 0x0002f926, 0x00001f24, 0x0002f927, 0x00001f25, 0x0002f928, 0x00001f26, 0x0002f929, 0x00001f27, 0x0002f92a, 0x00001f28, 0x0002f92b, 0x00001f29, 0x0002f92c, 0x00001f2a, 0x0002f92d, 0x00001f2b, 0x0002f92e, 0x00001f2c, 0x0002f92f, 0x00001f2d, 0x0002f930, 0x00001f2e, 0x0002f931, 0x00001f2f, 0x0002f932, 0x00001f30, 0x0002f933, 0x00001f31, 0x0002f934, 0x00001f32, 0x0002f935, 0x00001f33, 0x0002f936, 0x00001f34, 0x0002f937, 0x00001f35, 0x0002f938, 0x00001f36, 0x0002f939, 0x00001f37, 0x0002f93a, 0x00001f38, 0x0002f93b, 0x00001f39, 0x0002f93c, 0x00001f3a, 0x0002f93d, 0x00001f3b, 0x0002f93e, 0x00001f3c, 0x0002f93f, 0x00001f3d, 0x0002f940, 0x00001f3e, 0x0002f941, 0x00001f3f, 0x0002f942, 0x00001f40, 0x0002f943, 0x00001f41, 0x0002f944, 0x00001f42, 0x0002f945, 0x00001f43, 0x0002f946, 0x00001f44, 0x0002f947, 0x00001f45, 0x0002f948, 0x00001f46, 0x0002f949, 0x00001f47, 0x0002f94a, 0x00001f48, 0x0002f94b, 0x00001f49, 0x0002f94c, 0x00001f4a, 0x0002f94d, 0x00001f4b, 0x0002f94e, 0x00001f4c, 0x0002f94f, 0x00001f4d, 0x0002f950, 0x00001f4e, 0x0002f951, 0x00001f4f, 0x0002f952, 0x00001f50, 0x0002f953, 0x00001f51, 0x0002f954, 0x00001f52, 0x0002f955, 0x00001f53, 0x0002f956, 0x00001f54, 0x0002f957, 0x00001f55, 0x0002f958, 0x00001f56, 0x0002f959, 0x00001f57, 0x0002f95a, 0x00001f58, 0x0002f95b, 0x00001f59, 0x0002f95c, 0x00001f5a, 0x0002f95d, 0x00001f5b, 0x0002f95e, 0x00001f5c, 0x0002f95f, 0x00001f5d, 0x0002f960, 0x00001f5e, 0x0002f961, 0x00001f5f, 0x0002f962, 0x00001f60, 0x0002f963, 0x00001f61, 0x0002f964, 0x00001f62, 0x0002f965, 0x00001f63, 0x0002f966, 0x00001f64, 0x0002f967, 0x00001f65, 0x0002f968, 0x00001f66, 0x0002f969, 0x00001f67, 0x0002f96a, 0x00001f68, 0x0002f96b, 0x00001f69, 0x0002f96c, 0x00001f6a, 0x0002f96d, 0x00001f6b, 0x0002f96e, 0x00001f6c, 0x0002f96f, 0x00001f6d, 0x0002f970, 0x00001f6e, 0x0002f971, 0x00001f6f, 0x0002f972, 0x00001f70, 0x0002f973, 0x00001f71, 0x0002f974, 0x00001f72, 0x0002f975, 0x00001f73, 0x0002f976, 0x00001f74, 0x0002f977, 0x00001f75, 0x0002f978, 0x00001f76, 0x0002f979, 0x00001f77, 0x0002f97a, 0x00001f78, 0x0002f97b, 0x00001f79, 0x0002f97c, 0x00001f7a, 0x0002f97d, 0x00001f7b, 0x0002f97e, 0x00001f7c, 0x0002f97f, 0x00001f7d, 0x0002f980, 0x00001f7e, 0x0002f981, 0x00001f7f, 0x0002f982, 0x00001f80, 0x0002f983, 0x00001f81, 0x0002f984, 0x00001f82, 0x0002f985, 0x00001f83, 0x0002f986, 0x00001f84, 0x0002f987, 0x00001f85, 0x0002f988, 0x00001f86, 0x0002f989, 0x00001f87, 0x0002f98a, 0x00001f88, 0x0002f98b, 0x00001f89, 0x0002f98c, 0x00001f8a, 0x0002f98d, 0x00001f8b, 0x0002f98e, 0x00001f8c, 0x0002f98f, 0x00001f8d, 0x0002f990, 0x00001f8e, 0x0002f991, 0x00001f8f, 0x0002f992, 0x00001f90, 0x0002f993, 0x00001f91, 0x0002f994, 0x00001f92, 0x0002f995, 0x00001f93, 0x0002f996, 0x00001f94, 0x0002f997, 0x00001f95, 0x0002f998, 0x00001f96, 0x0002f999, 0x00001f97, 0x0002f99a, 0x00001f98, 0x0002f99b, 0x00001f99, 0x0002f99c, 0x00001f9a, 0x0002f99d, 0x00001f9b, 0x0002f99e, 0x00001f9c, 0x0002f99f, 0x00001f9d, 0x0002f9a0, 0x00001f9e, 0x0002f9a1, 0x00001f9f, 0x0002f9a2, 0x00001fa0, 0x0002f9a3, 0x00001fa1, 0x0002f9a4, 0x00001fa2, 0x0002f9a5, 0x00001fa3, 0x0002f9a6, 0x00001fa4, 0x0002f9a7, 0x00001fa5, 0x0002f9a8, 0x00001fa6, 0x0002f9a9, 0x00001fa7, 0x0002f9aa, 0x00001fa8, 0x0002f9ab, 0x00001fa9, 0x0002f9ac, 0x00001faa, 0x0002f9ad, 0x00001fab, 0x0002f9ae, 0x00001fac, 0x0002f9af, 0x00001fad, 0x0002f9b0, 0x00001fae, 0x0002f9b1, 0x00001faf, 0x0002f9b2, 0x00001fb0, 0x0002f9b3, 0x00001fb1, 0x0002f9b4, 0x00001fb2, 0x0002f9b5, 0x00001fb3, 0x0002f9b6, 0x00001fb4, 0x0002f9b7, 0x00001fb5, 0x0002f9b8, 0x00001fb6, 0x0002f9b9, 0x00001fb7, 0x0002f9ba, 0x00001fb8, 0x0002f9bb, 0x00001fb9, 0x0002f9bc, 0x00001fba, 0x0002f9bd, 0x00001fbb, 0x0002f9be, 0x00001fbc, 0x0002f9bf, 0x00001fbd, 0x0002f9c0, 0x00001fbe, 0x0002f9c1, 0x00001fbf, 0x0002f9c2, 0x00001fc0, 0x0002f9c3, 0x00001fc1, 0x0002f9c4, 0x00001fc2, 0x0002f9c5, 0x00001fc3, 0x0002f9c6, 0x00001fc4, 0x0002f9c7, 0x00001fc5, 0x0002f9c8, 0x00001fc6, 0x0002f9c9, 0x00001fc7, 0x0002f9ca, 0x00001fc8, 0x0002f9cb, 0x00001fc9, 0x0002f9cc, 0x00001fca, 0x0002f9cd, 0x00001fcb, 0x0002f9ce, 0x00001fcc, 0x0002f9cf, 0x00001fcd, 0x0002f9d0, 0x00001fce, 0x0002f9d1, 0x00001fcf, 0x0002f9d2, 0x00001fd0, 0x0002f9d3, 0x00001fd1, 0x0002f9d4, 0x00001fd2, 0x0002f9d5, 0x00001fd3, 0x0002f9d6, 0x00001fd4, 0x0002f9d7, 0x00001fd5, 0x0002f9d8, 0x00001fd6, 0x0002f9d9, 0x00001fd7, 0x0002f9da, 0x00001fd8, 0x0002f9db, 0x00001fd9, 0x0002f9dc, 0x00001fda, 0x0002f9dd, 0x00001fdb, 0x0002f9de, 0x00001fdc, 0x0002f9df, 0x00001fdd, 0x0002f9e0, 0x00001fde, 0x0002f9e1, 0x00001fdf, 0x0002f9e2, 0x00001fe0, 0x0002f9e3, 0x00001fe1, 0x0002f9e4, 0x00001fe2, 0x0002f9e5, 0x00001fe3, 0x0002f9e6, 0x00001fe4, 0x0002f9e7, 0x00001fe5, 0x0002f9e8, 0x00001fe6, 0x0002f9e9, 0x00001fe7, 0x0002f9ea, 0x00001fe8, 0x0002f9eb, 0x00001fe9, 0x0002f9ec, 0x00001fea, 0x0002f9ed, 0x00001feb, 0x0002f9ee, 0x00001fec, 0x0002f9ef, 0x00001fed, 0x0002f9f0, 0x00001fee, 0x0002f9f1, 0x00001fef, 0x0002f9f2, 0x00001ff0, 0x0002f9f3, 0x00001ff1, 0x0002f9f4, 0x00001ff2, 0x0002f9f5, 0x00001ff3, 0x0002f9f6, 0x00001ff4, 0x0002f9f7, 0x00001ff5, 0x0002f9f8, 0x00001ff6, 0x0002f9f9, 0x00001ff7, 0x0002f9fa, 0x00001ff8, 0x0002f9fb, 0x00001ff9, 0x0002f9fc, 0x00001ffa, 0x0002f9fd, 0x00001ffb, 0x0002f9fe, 0x00001ffc, 0x0002f9ff, 0x00001ffd, 0x0002fa00, 0x00001ffe, 0x0002fa01, 0x00001fff, 0x0002fa02, 0x00002000, 0x0002fa03, 0x00002001, 0x0002fa04, 0x00002002, 0x0002fa05, 0x00002003, 0x0002fa06, 0x00002004, 0x0002fa07, 0x00002005, 0x0002fa08, 0x00002006, 0x0002fa09, 0x00002007, 0x0002fa0a, 0x00002008, 0x0002fa0b, 0x00002009, 0x0002fa0c, 0x0000200a, 0x0002fa0d, 0x0000200b, 0x0002fa0e, 0x0000200c, 0x0002fa0f, 0x0000200d, 0x0002fa10, 0x0000200e, 0x0002fa11, 0x0000200f, 0x0002fa12, 0x00002010, 0x0002fa13, 0x00002011, 0x0002fa14, 0x00002012, 0x0002fa15, 0x00002013, 0x0002fa16, 0x00002014, 0x0002fa17, 0x00002015, 0x0002fa18, 0x00002016, 0x0002fa19, 0x00002017, 0x0002fa1a, 0x00002018, 0x0002fa1b, 0x00002019, 0x0002fa1c, 0x0000201a, 0x0002fa1d, 0x0000201b, 0x0000201c }; static const ac_uint4 _uckdcmp_decomp[] = { 0x00000020, 0x00000020, 0x00000308, 0x00000061, 0x00000020, 0x00000304, 0x00000032, 0x00000033, 0x00000020, 0x00000301, 0x000003bc, 0x00000020, 0x00000327, 0x00000031, 0x0000006f, 0x00000031, 0x00002044, 0x00000034, 0x00000031, 0x00002044, 0x00000032, 0x00000033, 0x00002044, 0x00000034, 0x00000041, 0x00000300, 0x00000041, 0x00000301, 0x00000041, 0x00000302, 0x00000041, 0x00000303, 0x00000041, 0x00000308, 0x00000041, 0x0000030a, 0x00000043, 0x00000327, 0x00000045, 0x00000300, 0x00000045, 0x00000301, 0x00000045, 0x00000302, 0x00000045, 0x00000308, 0x00000049, 0x00000300, 0x00000049, 0x00000301, 0x00000049, 0x00000302, 0x00000049, 0x00000308, 0x0000004e, 0x00000303, 0x0000004f, 0x00000300, 0x0000004f, 0x00000301, 0x0000004f, 0x00000302, 0x0000004f, 0x00000303, 0x0000004f, 0x00000308, 0x00000055, 0x00000300, 0x00000055, 0x00000301, 0x00000055, 0x00000302, 0x00000055, 0x00000308, 0x00000059, 0x00000301, 0x00000061, 0x00000300, 0x00000061, 0x00000301, 0x00000061, 0x00000302, 0x00000061, 0x00000303, 0x00000061, 0x00000308, 0x00000061, 0x0000030a, 0x00000063, 0x00000327, 0x00000065, 0x00000300, 0x00000065, 0x00000301, 0x00000065, 0x00000302, 0x00000065, 0x00000308, 0x00000069, 0x00000300, 0x00000069, 0x00000301, 0x00000069, 0x00000302, 0x00000069, 0x00000308, 0x0000006e, 0x00000303, 0x0000006f, 0x00000300, 0x0000006f, 0x00000301, 0x0000006f, 0x00000302, 0x0000006f, 0x00000303, 0x0000006f, 0x00000308, 0x00000075, 0x00000300, 0x00000075, 0x00000301, 0x00000075, 0x00000302, 0x00000075, 0x00000308, 0x00000079, 0x00000301, 0x00000079, 0x00000308, 0x00000041, 0x00000304, 0x00000061, 0x00000304, 0x00000041, 0x00000306, 0x00000061, 0x00000306, 0x00000041, 0x00000328, 0x00000061, 0x00000328, 0x00000043, 0x00000301, 0x00000063, 0x00000301, 0x00000043, 0x00000302, 0x00000063, 0x00000302, 0x00000043, 0x00000307, 0x00000063, 0x00000307, 0x00000043, 0x0000030c, 0x00000063, 0x0000030c, 0x00000044, 0x0000030c, 0x00000064, 0x0000030c, 0x00000045, 0x00000304, 0x00000065, 0x00000304, 0x00000045, 0x00000306, 0x00000065, 0x00000306, 0x00000045, 0x00000307, 0x00000065, 0x00000307, 0x00000045, 0x00000328, 0x00000065, 0x00000328, 0x00000045, 0x0000030c, 0x00000065, 0x0000030c, 0x00000047, 0x00000302, 0x00000067, 0x00000302, 0x00000047, 0x00000306, 0x00000067, 0x00000306, 0x00000047, 0x00000307, 0x00000067, 0x00000307, 0x00000047, 0x00000327, 0x00000067, 0x00000327, 0x00000048, 0x00000302, 0x00000068, 0x00000302, 0x00000049, 0x00000303, 0x00000069, 0x00000303, 0x00000049, 0x00000304, 0x00000069, 0x00000304, 0x00000049, 0x00000306, 0x00000069, 0x00000306, 0x00000049, 0x00000328, 0x00000069, 0x00000328, 0x00000049, 0x00000307, 0x00000049, 0x0000004a, 0x00000069, 0x0000006a, 0x0000004a, 0x00000302, 0x0000006a, 0x00000302, 0x0000004b, 0x00000327, 0x0000006b, 0x00000327, 0x0000004c, 0x00000301, 0x0000006c, 0x00000301, 0x0000004c, 0x00000327, 0x0000006c, 0x00000327, 0x0000004c, 0x0000030c, 0x0000006c, 0x0000030c, 0x0000004c, 0x000000b7, 0x0000006c, 0x000000b7, 0x0000004e, 0x00000301, 0x0000006e, 0x00000301, 0x0000004e, 0x00000327, 0x0000006e, 0x00000327, 0x0000004e, 0x0000030c, 0x0000006e, 0x0000030c, 0x000002bc, 0x0000006e, 0x0000004f, 0x00000304, 0x0000006f, 0x00000304, 0x0000004f, 0x00000306, 0x0000006f, 0x00000306, 0x0000004f, 0x0000030b, 0x0000006f, 0x0000030b, 0x00000052, 0x00000301, 0x00000072, 0x00000301, 0x00000052, 0x00000327, 0x00000072, 0x00000327, 0x00000052, 0x0000030c, 0x00000072, 0x0000030c, 0x00000053, 0x00000301, 0x00000073, 0x00000301, 0x00000053, 0x00000302, 0x00000073, 0x00000302, 0x00000053, 0x00000327, 0x00000073, 0x00000327, 0x00000053, 0x0000030c, 0x00000073, 0x0000030c, 0x00000054, 0x00000327, 0x00000074, 0x00000327, 0x00000054, 0x0000030c, 0x00000074, 0x0000030c, 0x00000055, 0x00000303, 0x00000075, 0x00000303, 0x00000055, 0x00000304, 0x00000075, 0x00000304, 0x00000055, 0x00000306, 0x00000075, 0x00000306, 0x00000055, 0x0000030a, 0x00000075, 0x0000030a, 0x00000055, 0x0000030b, 0x00000075, 0x0000030b, 0x00000055, 0x00000328, 0x00000075, 0x00000328, 0x00000057, 0x00000302, 0x00000077, 0x00000302, 0x00000059, 0x00000302, 0x00000079, 0x00000302, 0x00000059, 0x00000308, 0x0000005a, 0x00000301, 0x0000007a, 0x00000301, 0x0000005a, 0x00000307, 0x0000007a, 0x00000307, 0x0000005a, 0x0000030c, 0x0000007a, 0x0000030c, 0x00000073, 0x0000004f, 0x0000031b, 0x0000006f, 0x0000031b, 0x00000055, 0x0000031b, 0x00000075, 0x0000031b, 0x00000044, 0x0000005a, 0x0000030c, 0x00000044, 0x0000007a, 0x0000030c, 0x00000064, 0x0000007a, 0x0000030c, 0x0000004c, 0x0000004a, 0x0000004c, 0x0000006a, 0x0000006c, 0x0000006a, 0x0000004e, 0x0000004a, 0x0000004e, 0x0000006a, 0x0000006e, 0x0000006a, 0x00000041, 0x0000030c, 0x00000061, 0x0000030c, 0x00000049, 0x0000030c, 0x00000069, 0x0000030c, 0x0000004f, 0x0000030c, 0x0000006f, 0x0000030c, 0x00000055, 0x0000030c, 0x00000075, 0x0000030c, 0x00000055, 0x00000308, 0x00000304, 0x00000075, 0x00000308, 0x00000304, 0x00000055, 0x00000308, 0x00000301, 0x00000075, 0x00000308, 0x00000301, 0x00000055, 0x00000308, 0x0000030c, 0x00000075, 0x00000308, 0x0000030c, 0x00000055, 0x00000308, 0x00000300, 0x00000075, 0x00000308, 0x00000300, 0x00000041, 0x00000308, 0x00000304, 0x00000061, 0x00000308, 0x00000304, 0x00000041, 0x00000307, 0x00000304, 0x00000061, 0x00000307, 0x00000304, 0x000000c6, 0x00000304, 0x000000e6, 0x00000304, 0x00000047, 0x0000030c, 0x00000067, 0x0000030c, 0x0000004b, 0x0000030c, 0x0000006b, 0x0000030c, 0x0000004f, 0x00000328, 0x0000006f, 0x00000328, 0x0000004f, 0x00000328, 0x00000304, 0x0000006f, 0x00000328, 0x00000304, 0x000001b7, 0x0000030c, 0x00000292, 0x0000030c, 0x0000006a, 0x0000030c, 0x00000044, 0x0000005a, 0x00000044, 0x0000007a, 0x00000064, 0x0000007a, 0x00000047, 0x00000301, 0x00000067, 0x00000301, 0x0000004e, 0x00000300, 0x0000006e, 0x00000300, 0x00000041, 0x0000030a, 0x00000301, 0x00000061, 0x0000030a, 0x00000301, 0x000000c6, 0x00000301, 0x000000e6, 0x00000301, 0x000000d8, 0x00000301, 0x000000f8, 0x00000301, 0x00000041, 0x0000030f, 0x00000061, 0x0000030f, 0x00000041, 0x00000311, 0x00000061, 0x00000311, 0x00000045, 0x0000030f, 0x00000065, 0x0000030f, 0x00000045, 0x00000311, 0x00000065, 0x00000311, 0x00000049, 0x0000030f, 0x00000069, 0x0000030f, 0x00000049, 0x00000311, 0x00000069, 0x00000311, 0x0000004f, 0x0000030f, 0x0000006f, 0x0000030f, 0x0000004f, 0x00000311, 0x0000006f, 0x00000311, 0x00000052, 0x0000030f, 0x00000072, 0x0000030f, 0x00000052, 0x00000311, 0x00000072, 0x00000311, 0x00000055, 0x0000030f, 0x00000075, 0x0000030f, 0x00000055, 0x00000311, 0x00000075, 0x00000311, 0x00000053, 0x00000326, 0x00000073, 0x00000326, 0x00000054, 0x00000326, 0x00000074, 0x00000326, 0x00000048, 0x0000030c, 0x00000068, 0x0000030c, 0x00000041, 0x00000307, 0x00000061, 0x00000307, 0x00000045, 0x00000327, 0x00000065, 0x00000327, 0x0000004f, 0x00000308, 0x00000304, 0x0000006f, 0x00000308, 0x00000304, 0x0000004f, 0x00000303, 0x00000304, 0x0000006f, 0x00000303, 0x00000304, 0x0000004f, 0x00000307, 0x0000006f, 0x00000307, 0x0000004f, 0x00000307, 0x00000304, 0x0000006f, 0x00000307, 0x00000304, 0x00000059, 0x00000304, 0x00000079, 0x00000304, 0x00000068, 0x00000266, 0x0000006a, 0x00000072, 0x00000279, 0x0000027b, 0x00000281, 0x00000077, 0x00000079, 0x00000020, 0x00000306, 0x00000020, 0x00000307, 0x00000020, 0x0000030a, 0x00000020, 0x00000328, 0x00000020, 0x00000303, 0x00000020, 0x0000030b, 0x00000263, 0x0000006c, 0x00000073, 0x00000078, 0x00000295, 0x00000300, 0x00000301, 0x00000313, 0x00000308, 0x00000301, 0x000002b9, 0x00000020, 0x00000345, 0x0000003b, 0x00000020, 0x00000301, 0x00000020, 0x00000308, 0x00000301, 0x00000391, 0x00000301, 0x000000b7, 0x00000395, 0x00000301, 0x00000397, 0x00000301, 0x00000399, 0x00000301, 0x0000039f, 0x00000301, 0x000003a5, 0x00000301, 0x000003a9, 0x00000301, 0x000003b9, 0x00000308, 0x00000301, 0x00000399, 0x00000308, 0x000003a5, 0x00000308, 0x000003b1, 0x00000301, 0x000003b5, 0x00000301, 0x000003b7, 0x00000301, 0x000003b9, 0x00000301, 0x000003c5, 0x00000308, 0x00000301, 0x000003b9, 0x00000308, 0x000003c5, 0x00000308, 0x000003bf, 0x00000301, 0x000003c5, 0x00000301, 0x000003c9, 0x00000301, 0x000003b2, 0x000003b8, 0x000003a5, 0x000003a5, 0x00000301, 0x000003a5, 0x00000308, 0x000003c6, 0x000003c0, 0x000003ba, 0x000003c1, 0x000003c2, 0x00000398, 0x000003b5, 0x00000415, 0x00000300, 0x00000415, 0x00000308, 0x00000413, 0x00000301, 0x00000406, 0x00000308, 0x0000041a, 0x00000301, 0x00000418, 0x00000300, 0x00000423, 0x00000306, 0x00000418, 0x00000306, 0x00000438, 0x00000306, 0x00000435, 0x00000300, 0x00000435, 0x00000308, 0x00000433, 0x00000301, 0x00000456, 0x00000308, 0x0000043a, 0x00000301, 0x00000438, 0x00000300, 0x00000443, 0x00000306, 0x00000474, 0x0000030f, 0x00000475, 0x0000030f, 0x00000416, 0x00000306, 0x00000436, 0x00000306, 0x00000410, 0x00000306, 0x00000430, 0x00000306, 0x00000410, 0x00000308, 0x00000430, 0x00000308, 0x00000415, 0x00000306, 0x00000435, 0x00000306, 0x000004d8, 0x00000308, 0x000004d9, 0x00000308, 0x00000416, 0x00000308, 0x00000436, 0x00000308, 0x00000417, 0x00000308, 0x00000437, 0x00000308, 0x00000418, 0x00000304, 0x00000438, 0x00000304, 0x00000418, 0x00000308, 0x00000438, 0x00000308, 0x0000041e, 0x00000308, 0x0000043e, 0x00000308, 0x000004e8, 0x00000308, 0x000004e9, 0x00000308, 0x0000042d, 0x00000308, 0x0000044d, 0x00000308, 0x00000423, 0x00000304, 0x00000443, 0x00000304, 0x00000423, 0x00000308, 0x00000443, 0x00000308, 0x00000423, 0x0000030b, 0x00000443, 0x0000030b, 0x00000427, 0x00000308, 0x00000447, 0x00000308, 0x0000042b, 0x00000308, 0x0000044b, 0x00000308, 0x00000565, 0x00000582, 0x00000627, 0x00000653, 0x00000627, 0x00000654, 0x00000648, 0x00000654, 0x00000627, 0x00000655, 0x0000064a, 0x00000654, 0x00000627, 0x00000674, 0x00000648, 0x00000674, 0x000006c7, 0x00000674, 0x0000064a, 0x00000674, 0x000006d5, 0x00000654, 0x000006c1, 0x00000654, 0x000006d2, 0x00000654, 0x00000928, 0x0000093c, 0x00000930, 0x0000093c, 0x00000933, 0x0000093c, 0x00000915, 0x0000093c, 0x00000916, 0x0000093c, 0x00000917, 0x0000093c, 0x0000091c, 0x0000093c, 0x00000921, 0x0000093c, 0x00000922, 0x0000093c, 0x0000092b, 0x0000093c, 0x0000092f, 0x0000093c, 0x000009c7, 0x000009be, 0x000009c7, 0x000009d7, 0x000009a1, 0x000009bc, 0x000009a2, 0x000009bc, 0x000009af, 0x000009bc, 0x00000a32, 0x00000a3c, 0x00000a38, 0x00000a3c, 0x00000a16, 0x00000a3c, 0x00000a17, 0x00000a3c, 0x00000a1c, 0x00000a3c, 0x00000a2b, 0x00000a3c, 0x00000b47, 0x00000b56, 0x00000b47, 0x00000b3e, 0x00000b47, 0x00000b57, 0x00000b21, 0x00000b3c, 0x00000b22, 0x00000b3c, 0x00000b92, 0x00000bd7, 0x00000bc6, 0x00000bbe, 0x00000bc7, 0x00000bbe, 0x00000bc6, 0x00000bd7, 0x00000c46, 0x00000c56, 0x00000cbf, 0x00000cd5, 0x00000cc6, 0x00000cd5, 0x00000cc6, 0x00000cd6, 0x00000cc6, 0x00000cc2, 0x00000cc6, 0x00000cc2, 0x00000cd5, 0x00000d46, 0x00000d3e, 0x00000d47, 0x00000d3e, 0x00000d46, 0x00000d57, 0x00000dd9, 0x00000dca, 0x00000dd9, 0x00000dcf, 0x00000dd9, 0x00000dcf, 0x00000dca, 0x00000dd9, 0x00000ddf, 0x00000e4d, 0x00000e32, 0x00000ecd, 0x00000eb2, 0x00000eab, 0x00000e99, 0x00000eab, 0x00000ea1, 0x00000f0b, 0x00000f42, 0x00000fb7, 0x00000f4c, 0x00000fb7, 0x00000f51, 0x00000fb7, 0x00000f56, 0x00000fb7, 0x00000f5b, 0x00000fb7, 0x00000f40, 0x00000fb5, 0x00000f71, 0x00000f72, 0x00000f71, 0x00000f74, 0x00000fb2, 0x00000f80, 0x00000fb2, 0x00000f71, 0x00000f80, 0x00000fb3, 0x00000f80, 0x00000fb3, 0x00000f71, 0x00000f80, 0x00000f71, 0x00000f80, 0x00000f92, 0x00000fb7, 0x00000f9c, 0x00000fb7, 0x00000fa1, 0x00000fb7, 0x00000fa6, 0x00000fb7, 0x00000fab, 0x00000fb7, 0x00000f90, 0x00000fb5, 0x00001025, 0x0000102e, 0x00000041, 0x00000325, 0x00000061, 0x00000325, 0x00000042, 0x00000307, 0x00000062, 0x00000307, 0x00000042, 0x00000323, 0x00000062, 0x00000323, 0x00000042, 0x00000331, 0x00000062, 0x00000331, 0x00000043, 0x00000327, 0x00000301, 0x00000063, 0x00000327, 0x00000301, 0x00000044, 0x00000307, 0x00000064, 0x00000307, 0x00000044, 0x00000323, 0x00000064, 0x00000323, 0x00000044, 0x00000331, 0x00000064, 0x00000331, 0x00000044, 0x00000327, 0x00000064, 0x00000327, 0x00000044, 0x0000032d, 0x00000064, 0x0000032d, 0x00000045, 0x00000304, 0x00000300, 0x00000065, 0x00000304, 0x00000300, 0x00000045, 0x00000304, 0x00000301, 0x00000065, 0x00000304, 0x00000301, 0x00000045, 0x0000032d, 0x00000065, 0x0000032d, 0x00000045, 0x00000330, 0x00000065, 0x00000330, 0x00000045, 0x00000327, 0x00000306, 0x00000065, 0x00000327, 0x00000306, 0x00000046, 0x00000307, 0x00000066, 0x00000307, 0x00000047, 0x00000304, 0x00000067, 0x00000304, 0x00000048, 0x00000307, 0x00000068, 0x00000307, 0x00000048, 0x00000323, 0x00000068, 0x00000323, 0x00000048, 0x00000308, 0x00000068, 0x00000308, 0x00000048, 0x00000327, 0x00000068, 0x00000327, 0x00000048, 0x0000032e, 0x00000068, 0x0000032e, 0x00000049, 0x00000330, 0x00000069, 0x00000330, 0x00000049, 0x00000308, 0x00000301, 0x00000069, 0x00000308, 0x00000301, 0x0000004b, 0x00000301, 0x0000006b, 0x00000301, 0x0000004b, 0x00000323, 0x0000006b, 0x00000323, 0x0000004b, 0x00000331, 0x0000006b, 0x00000331, 0x0000004c, 0x00000323, 0x0000006c, 0x00000323, 0x0000004c, 0x00000323, 0x00000304, 0x0000006c, 0x00000323, 0x00000304, 0x0000004c, 0x00000331, 0x0000006c, 0x00000331, 0x0000004c, 0x0000032d, 0x0000006c, 0x0000032d, 0x0000004d, 0x00000301, 0x0000006d, 0x00000301, 0x0000004d, 0x00000307, 0x0000006d, 0x00000307, 0x0000004d, 0x00000323, 0x0000006d, 0x00000323, 0x0000004e, 0x00000307, 0x0000006e, 0x00000307, 0x0000004e, 0x00000323, 0x0000006e, 0x00000323, 0x0000004e, 0x00000331, 0x0000006e, 0x00000331, 0x0000004e, 0x0000032d, 0x0000006e, 0x0000032d, 0x0000004f, 0x00000303, 0x00000301, 0x0000006f, 0x00000303, 0x00000301, 0x0000004f, 0x00000303, 0x00000308, 0x0000006f, 0x00000303, 0x00000308, 0x0000004f, 0x00000304, 0x00000300, 0x0000006f, 0x00000304, 0x00000300, 0x0000004f, 0x00000304, 0x00000301, 0x0000006f, 0x00000304, 0x00000301, 0x00000050, 0x00000301, 0x00000070, 0x00000301, 0x00000050, 0x00000307, 0x00000070, 0x00000307, 0x00000052, 0x00000307, 0x00000072, 0x00000307, 0x00000052, 0x00000323, 0x00000072, 0x00000323, 0x00000052, 0x00000323, 0x00000304, 0x00000072, 0x00000323, 0x00000304, 0x00000052, 0x00000331, 0x00000072, 0x00000331, 0x00000053, 0x00000307, 0x00000073, 0x00000307, 0x00000053, 0x00000323, 0x00000073, 0x00000323, 0x00000053, 0x00000301, 0x00000307, 0x00000073, 0x00000301, 0x00000307, 0x00000053, 0x0000030c, 0x00000307, 0x00000073, 0x0000030c, 0x00000307, 0x00000053, 0x00000323, 0x00000307, 0x00000073, 0x00000323, 0x00000307, 0x00000054, 0x00000307, 0x00000074, 0x00000307, 0x00000054, 0x00000323, 0x00000074, 0x00000323, 0x00000054, 0x00000331, 0x00000074, 0x00000331, 0x00000054, 0x0000032d, 0x00000074, 0x0000032d, 0x00000055, 0x00000324, 0x00000075, 0x00000324, 0x00000055, 0x00000330, 0x00000075, 0x00000330, 0x00000055, 0x0000032d, 0x00000075, 0x0000032d, 0x00000055, 0x00000303, 0x00000301, 0x00000075, 0x00000303, 0x00000301, 0x00000055, 0x00000304, 0x00000308, 0x00000075, 0x00000304, 0x00000308, 0x00000056, 0x00000303, 0x00000076, 0x00000303, 0x00000056, 0x00000323, 0x00000076, 0x00000323, 0x00000057, 0x00000300, 0x00000077, 0x00000300, 0x00000057, 0x00000301, 0x00000077, 0x00000301, 0x00000057, 0x00000308, 0x00000077, 0x00000308, 0x00000057, 0x00000307, 0x00000077, 0x00000307, 0x00000057, 0x00000323, 0x00000077, 0x00000323, 0x00000058, 0x00000307, 0x00000078, 0x00000307, 0x00000058, 0x00000308, 0x00000078, 0x00000308, 0x00000059, 0x00000307, 0x00000079, 0x00000307, 0x0000005a, 0x00000302, 0x0000007a, 0x00000302, 0x0000005a, 0x00000323, 0x0000007a, 0x00000323, 0x0000005a, 0x00000331, 0x0000007a, 0x00000331, 0x00000068, 0x00000331, 0x00000074, 0x00000308, 0x00000077, 0x0000030a, 0x00000079, 0x0000030a, 0x00000061, 0x000002be, 0x00000073, 0x00000307, 0x00000041, 0x00000323, 0x00000061, 0x00000323, 0x00000041, 0x00000309, 0x00000061, 0x00000309, 0x00000041, 0x00000302, 0x00000301, 0x00000061, 0x00000302, 0x00000301, 0x00000041, 0x00000302, 0x00000300, 0x00000061, 0x00000302, 0x00000300, 0x00000041, 0x00000302, 0x00000309, 0x00000061, 0x00000302, 0x00000309, 0x00000041, 0x00000302, 0x00000303, 0x00000061, 0x00000302, 0x00000303, 0x00000041, 0x00000323, 0x00000302, 0x00000061, 0x00000323, 0x00000302, 0x00000041, 0x00000306, 0x00000301, 0x00000061, 0x00000306, 0x00000301, 0x00000041, 0x00000306, 0x00000300, 0x00000061, 0x00000306, 0x00000300, 0x00000041, 0x00000306, 0x00000309, 0x00000061, 0x00000306, 0x00000309, 0x00000041, 0x00000306, 0x00000303, 0x00000061, 0x00000306, 0x00000303, 0x00000041, 0x00000323, 0x00000306, 0x00000061, 0x00000323, 0x00000306, 0x00000045, 0x00000323, 0x00000065, 0x00000323, 0x00000045, 0x00000309, 0x00000065, 0x00000309, 0x00000045, 0x00000303, 0x00000065, 0x00000303, 0x00000045, 0x00000302, 0x00000301, 0x00000065, 0x00000302, 0x00000301, 0x00000045, 0x00000302, 0x00000300, 0x00000065, 0x00000302, 0x00000300, 0x00000045, 0x00000302, 0x00000309, 0x00000065, 0x00000302, 0x00000309, 0x00000045, 0x00000302, 0x00000303, 0x00000065, 0x00000302, 0x00000303, 0x00000045, 0x00000323, 0x00000302, 0x00000065, 0x00000323, 0x00000302, 0x00000049, 0x00000309, 0x00000069, 0x00000309, 0x00000049, 0x00000323, 0x00000069, 0x00000323, 0x0000004f, 0x00000323, 0x0000006f, 0x00000323, 0x0000004f, 0x00000309, 0x0000006f, 0x00000309, 0x0000004f, 0x00000302, 0x00000301, 0x0000006f, 0x00000302, 0x00000301, 0x0000004f, 0x00000302, 0x00000300, 0x0000006f, 0x00000302, 0x00000300, 0x0000004f, 0x00000302, 0x00000309, 0x0000006f, 0x00000302, 0x00000309, 0x0000004f, 0x00000302, 0x00000303, 0x0000006f, 0x00000302, 0x00000303, 0x0000004f, 0x00000323, 0x00000302, 0x0000006f, 0x00000323, 0x00000302, 0x0000004f, 0x0000031b, 0x00000301, 0x0000006f, 0x0000031b, 0x00000301, 0x0000004f, 0x0000031b, 0x00000300, 0x0000006f, 0x0000031b, 0x00000300, 0x0000004f, 0x0000031b, 0x00000309, 0x0000006f, 0x0000031b, 0x00000309, 0x0000004f, 0x0000031b, 0x00000303, 0x0000006f, 0x0000031b, 0x00000303, 0x0000004f, 0x0000031b, 0x00000323, 0x0000006f, 0x0000031b, 0x00000323, 0x00000055, 0x00000323, 0x00000075, 0x00000323, 0x00000055, 0x00000309, 0x00000075, 0x00000309, 0x00000055, 0x0000031b, 0x00000301, 0x00000075, 0x0000031b, 0x00000301, 0x00000055, 0x0000031b, 0x00000300, 0x00000075, 0x0000031b, 0x00000300, 0x00000055, 0x0000031b, 0x00000309, 0x00000075, 0x0000031b, 0x00000309, 0x00000055, 0x0000031b, 0x00000303, 0x00000075, 0x0000031b, 0x00000303, 0x00000055, 0x0000031b, 0x00000323, 0x00000075, 0x0000031b, 0x00000323, 0x00000059, 0x00000300, 0x00000079, 0x00000300, 0x00000059, 0x00000323, 0x00000079, 0x00000323, 0x00000059, 0x00000309, 0x00000079, 0x00000309, 0x00000059, 0x00000303, 0x00000079, 0x00000303, 0x000003b1, 0x00000313, 0x000003b1, 0x00000314, 0x000003b1, 0x00000313, 0x00000300, 0x000003b1, 0x00000314, 0x00000300, 0x000003b1, 0x00000313, 0x00000301, 0x000003b1, 0x00000314, 0x00000301, 0x000003b1, 0x00000313, 0x00000342, 0x000003b1, 0x00000314, 0x00000342, 0x00000391, 0x00000313, 0x00000391, 0x00000314, 0x00000391, 0x00000313, 0x00000300, 0x00000391, 0x00000314, 0x00000300, 0x00000391, 0x00000313, 0x00000301, 0x00000391, 0x00000314, 0x00000301, 0x00000391, 0x00000313, 0x00000342, 0x00000391, 0x00000314, 0x00000342, 0x000003b5, 0x00000313, 0x000003b5, 0x00000314, 0x000003b5, 0x00000313, 0x00000300, 0x000003b5, 0x00000314, 0x00000300, 0x000003b5, 0x00000313, 0x00000301, 0x000003b5, 0x00000314, 0x00000301, 0x00000395, 0x00000313, 0x00000395, 0x00000314, 0x00000395, 0x00000313, 0x00000300, 0x00000395, 0x00000314, 0x00000300, 0x00000395, 0x00000313, 0x00000301, 0x00000395, 0x00000314, 0x00000301, 0x000003b7, 0x00000313, 0x000003b7, 0x00000314, 0x000003b7, 0x00000313, 0x00000300, 0x000003b7, 0x00000314, 0x00000300, 0x000003b7, 0x00000313, 0x00000301, 0x000003b7, 0x00000314, 0x00000301, 0x000003b7, 0x00000313, 0x00000342, 0x000003b7, 0x00000314, 0x00000342, 0x00000397, 0x00000313, 0x00000397, 0x00000314, 0x00000397, 0x00000313, 0x00000300, 0x00000397, 0x00000314, 0x00000300, 0x00000397, 0x00000313, 0x00000301, 0x00000397, 0x00000314, 0x00000301, 0x00000397, 0x00000313, 0x00000342, 0x00000397, 0x00000314, 0x00000342, 0x000003b9, 0x00000313, 0x000003b9, 0x00000314, 0x000003b9, 0x00000313, 0x00000300, 0x000003b9, 0x00000314, 0x00000300, 0x000003b9, 0x00000313, 0x00000301, 0x000003b9, 0x00000314, 0x00000301, 0x000003b9, 0x00000313, 0x00000342, 0x000003b9, 0x00000314, 0x00000342, 0x00000399, 0x00000313, 0x00000399, 0x00000314, 0x00000399, 0x00000313, 0x00000300, 0x00000399, 0x00000314, 0x00000300, 0x00000399, 0x00000313, 0x00000301, 0x00000399, 0x00000314, 0x00000301, 0x00000399, 0x00000313, 0x00000342, 0x00000399, 0x00000314, 0x00000342, 0x000003bf, 0x00000313, 0x000003bf, 0x00000314, 0x000003bf, 0x00000313, 0x00000300, 0x000003bf, 0x00000314, 0x00000300, 0x000003bf, 0x00000313, 0x00000301, 0x000003bf, 0x00000314, 0x00000301, 0x0000039f, 0x00000313, 0x0000039f, 0x00000314, 0x0000039f, 0x00000313, 0x00000300, 0x0000039f, 0x00000314, 0x00000300, 0x0000039f, 0x00000313, 0x00000301, 0x0000039f, 0x00000314, 0x00000301, 0x000003c5, 0x00000313, 0x000003c5, 0x00000314, 0x000003c5, 0x00000313, 0x00000300, 0x000003c5, 0x00000314, 0x00000300, 0x000003c5, 0x00000313, 0x00000301, 0x000003c5, 0x00000314, 0x00000301, 0x000003c5, 0x00000313, 0x00000342, 0x000003c5, 0x00000314, 0x00000342, 0x000003a5, 0x00000314, 0x000003a5, 0x00000314, 0x00000300, 0x000003a5, 0x00000314, 0x00000301, 0x000003a5, 0x00000314, 0x00000342, 0x000003c9, 0x00000313, 0x000003c9, 0x00000314, 0x000003c9, 0x00000313, 0x00000300, 0x000003c9, 0x00000314, 0x00000300, 0x000003c9, 0x00000313, 0x00000301, 0x000003c9, 0x00000314, 0x00000301, 0x000003c9, 0x00000313, 0x00000342, 0x000003c9, 0x00000314, 0x00000342, 0x000003a9, 0x00000313, 0x000003a9, 0x00000314, 0x000003a9, 0x00000313, 0x00000300, 0x000003a9, 0x00000314, 0x00000300, 0x000003a9, 0x00000313, 0x00000301, 0x000003a9, 0x00000314, 0x00000301, 0x000003a9, 0x00000313, 0x00000342, 0x000003a9, 0x00000314, 0x00000342, 0x000003b1, 0x00000300, 0x000003b1, 0x00000301, 0x000003b5, 0x00000300, 0x000003b5, 0x00000301, 0x000003b7, 0x00000300, 0x000003b7, 0x00000301, 0x000003b9, 0x00000300, 0x000003b9, 0x00000301, 0x000003bf, 0x00000300, 0x000003bf, 0x00000301, 0x000003c5, 0x00000300, 0x000003c5, 0x00000301, 0x000003c9, 0x00000300, 0x000003c9, 0x00000301, 0x000003b1, 0x00000313, 0x00000345, 0x000003b1, 0x00000314, 0x00000345, 0x000003b1, 0x00000313, 0x00000300, 0x00000345, 0x000003b1, 0x00000314, 0x00000300, 0x00000345, 0x000003b1, 0x00000313, 0x00000301, 0x00000345, 0x000003b1, 0x00000314, 0x00000301, 0x00000345, 0x000003b1, 0x00000313, 0x00000342, 0x00000345, 0x000003b1, 0x00000314, 0x00000342, 0x00000345, 0x00000391, 0x00000313, 0x00000345, 0x00000391, 0x00000314, 0x00000345, 0x00000391, 0x00000313, 0x00000300, 0x00000345, 0x00000391, 0x00000314, 0x00000300, 0x00000345, 0x00000391, 0x00000313, 0x00000301, 0x00000345, 0x00000391, 0x00000314, 0x00000301, 0x00000345, 0x00000391, 0x00000313, 0x00000342, 0x00000345, 0x00000391, 0x00000314, 0x00000342, 0x00000345, 0x000003b7, 0x00000313, 0x00000345, 0x000003b7, 0x00000314, 0x00000345, 0x000003b7, 0x00000313, 0x00000300, 0x00000345, 0x000003b7, 0x00000314, 0x00000300, 0x00000345, 0x000003b7, 0x00000313, 0x00000301, 0x00000345, 0x000003b7, 0x00000314, 0x00000301, 0x00000345, 0x000003b7, 0x00000313, 0x00000342, 0x00000345, 0x000003b7, 0x00000314, 0x00000342, 0x00000345, 0x00000397, 0x00000313, 0x00000345, 0x00000397, 0x00000314, 0x00000345, 0x00000397, 0x00000313, 0x00000300, 0x00000345, 0x00000397, 0x00000314, 0x00000300, 0x00000345, 0x00000397, 0x00000313, 0x00000301, 0x00000345, 0x00000397, 0x00000314, 0x00000301, 0x00000345, 0x00000397, 0x00000313, 0x00000342, 0x00000345, 0x00000397, 0x00000314, 0x00000342, 0x00000345, 0x000003c9, 0x00000313, 0x00000345, 0x000003c9, 0x00000314, 0x00000345, 0x000003c9, 0x00000313, 0x00000300, 0x00000345, 0x000003c9, 0x00000314, 0x00000300, 0x00000345, 0x000003c9, 0x00000313, 0x00000301, 0x00000345, 0x000003c9, 0x00000314, 0x00000301, 0x00000345, 0x000003c9, 0x00000313, 0x00000342, 0x00000345, 0x000003c9, 0x00000314, 0x00000342, 0x00000345, 0x000003a9, 0x00000313, 0x00000345, 0x000003a9, 0x00000314, 0x00000345, 0x000003a9, 0x00000313, 0x00000300, 0x00000345, 0x000003a9, 0x00000314, 0x00000300, 0x00000345, 0x000003a9, 0x00000313, 0x00000301, 0x00000345, 0x000003a9, 0x00000314, 0x00000301, 0x00000345, 0x000003a9, 0x00000313, 0x00000342, 0x00000345, 0x000003a9, 0x00000314, 0x00000342, 0x00000345, 0x000003b1, 0x00000306, 0x000003b1, 0x00000304, 0x000003b1, 0x00000300, 0x00000345, 0x000003b1, 0x00000345, 0x000003b1, 0x00000301, 0x00000345, 0x000003b1, 0x00000342, 0x000003b1, 0x00000342, 0x00000345, 0x00000391, 0x00000306, 0x00000391, 0x00000304, 0x00000391, 0x00000300, 0x00000391, 0x00000301, 0x00000391, 0x00000345, 0x00000020, 0x00000313, 0x000003b9, 0x00000020, 0x00000313, 0x00000020, 0x00000342, 0x00000020, 0x00000308, 0x00000342, 0x000003b7, 0x00000300, 0x00000345, 0x000003b7, 0x00000345, 0x000003b7, 0x00000301, 0x00000345, 0x000003b7, 0x00000342, 0x000003b7, 0x00000342, 0x00000345, 0x00000395, 0x00000300, 0x00000395, 0x00000301, 0x00000397, 0x00000300, 0x00000397, 0x00000301, 0x00000397, 0x00000345, 0x00000020, 0x00000313, 0x00000300, 0x00000020, 0x00000313, 0x00000301, 0x00000020, 0x00000313, 0x00000342, 0x000003b9, 0x00000306, 0x000003b9, 0x00000304, 0x000003b9, 0x00000308, 0x00000300, 0x000003b9, 0x00000308, 0x00000301, 0x000003b9, 0x00000342, 0x000003b9, 0x00000308, 0x00000342, 0x00000399, 0x00000306, 0x00000399, 0x00000304, 0x00000399, 0x00000300, 0x00000399, 0x00000301, 0x00000020, 0x00000314, 0x00000300, 0x00000020, 0x00000314, 0x00000301, 0x00000020, 0x00000314, 0x00000342, 0x000003c5, 0x00000306, 0x000003c5, 0x00000304, 0x000003c5, 0x00000308, 0x00000300, 0x000003c5, 0x00000308, 0x00000301, 0x000003c1, 0x00000313, 0x000003c1, 0x00000314, 0x000003c5, 0x00000342, 0x000003c5, 0x00000308, 0x00000342, 0x000003a5, 0x00000306, 0x000003a5, 0x00000304, 0x000003a5, 0x00000300, 0x000003a5, 0x00000301, 0x000003a1, 0x00000314, 0x00000020, 0x00000308, 0x00000300, 0x00000020, 0x00000308, 0x00000301, 0x00000060, 0x000003c9, 0x00000300, 0x00000345, 0x000003c9, 0x00000345, 0x000003c9, 0x00000301, 0x00000345, 0x000003c9, 0x00000342, 0x000003c9, 0x00000342, 0x00000345, 0x0000039f, 0x00000300, 0x0000039f, 0x00000301, 0x000003a9, 0x00000300, 0x000003a9, 0x00000301, 0x000003a9, 0x00000345, 0x00000020, 0x00000301, 0x00000020, 0x00000314, 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00002010, 0x00000020, 0x00000333, 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e, 0x00000020, 0x00002032, 0x00002032, 0x00002032, 0x00002032, 0x00002032, 0x00002035, 0x00002035, 0x00002035, 0x00002035, 0x00002035, 0x00000021, 0x00000021, 0x00000020, 0x00000305, 0x0000003f, 0x0000003f, 0x0000003f, 0x00000021, 0x00000021, 0x0000003f, 0x00002032, 0x00002032, 0x00002032, 0x00002032, 0x00000020, 0x00000030, 0x00000069, 0x00000034, 0x00000035, 0x00000036, 0x00000037, 0x00000038, 0x00000039, 0x0000002b, 0x00002212, 0x0000003d, 0x00000028, 0x00000029, 0x0000006e, 0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x00000034, 0x00000035, 0x00000036, 0x00000037, 0x00000038, 0x00000039, 0x0000002b, 0x00002212, 0x0000003d, 0x00000028, 0x00000029, 0x00000052, 0x00000073, 0x00000061, 0x0000002f, 0x00000063, 0x00000061, 0x0000002f, 0x00000073, 0x00000043, 0x000000b0, 0x00000043, 0x00000063, 0x0000002f, 0x0000006f, 0x00000063, 0x0000002f, 0x00000075, 0x00000190, 0x000000b0, 0x00000046, 0x00000067, 0x00000048, 0x00000048, 0x00000048, 0x00000068, 0x00000127, 0x00000049, 0x00000049, 0x0000004c, 0x0000006c, 0x0000004e, 0x0000004e, 0x0000006f, 0x00000050, 0x00000051, 0x00000052, 0x00000052, 0x00000052, 0x00000053, 0x0000004d, 0x00000054, 0x00000045, 0x0000004c, 0x00000054, 0x0000004d, 0x0000005a, 0x000003a9, 0x0000005a, 0x0000004b, 0x00000041, 0x0000030a, 0x00000042, 0x00000043, 0x00000065, 0x00000045, 0x00000046, 0x0000004d, 0x0000006f, 0x000005d0, 0x000005d1, 0x000005d2, 0x000005d3, 0x00000069, 0x000003b3, 0x00000393, 0x000003a0, 0x00002211, 0x00000044, 0x00000064, 0x00000065, 0x00000069, 0x0000006a, 0x00000031, 0x00002044, 0x00000033, 0x00000032, 0x00002044, 0x00000033, 0x00000031, 0x00002044, 0x00000035, 0x00000032, 0x00002044, 0x00000035, 0x00000033, 0x00002044, 0x00000035, 0x00000034, 0x00002044, 0x00000035, 0x00000031, 0x00002044, 0x00000036, 0x00000035, 0x00002044, 0x00000036, 0x00000031, 0x00002044, 0x00000038, 0x00000033, 0x00002044, 0x00000038, 0x00000035, 0x00002044, 0x00000038, 0x00000037, 0x00002044, 0x00000038, 0x00000031, 0x00002044, 0x00000049, 0x00000049, 0x00000049, 0x00000049, 0x00000049, 0x00000049, 0x00000049, 0x00000056, 0x00000056, 0x00000056, 0x00000049, 0x00000056, 0x00000049, 0x00000049, 0x00000056, 0x00000049, 0x00000049, 0x00000049, 0x00000049, 0x00000058, 0x00000058, 0x00000058, 0x00000049, 0x00000058, 0x00000049, 0x00000049, 0x0000004c, 0x00000043, 0x00000044, 0x0000004d, 0x00000069, 0x00000069, 0x00000069, 0x00000069, 0x00000069, 0x00000069, 0x00000069, 0x00000076, 0x00000076, 0x00000076, 0x00000069, 0x00000076, 0x00000069, 0x00000069, 0x00000076, 0x00000069, 0x00000069, 0x00000069, 0x00000069, 0x00000078, 0x00000078, 0x00000078, 0x00000069, 0x00000078, 0x00000069, 0x00000069, 0x0000006c, 0x00000063, 0x00000064, 0x0000006d, 0x00002190, 0x00000338, 0x00002192, 0x00000338, 0x00002194, 0x00000338, 0x000021d0, 0x00000338, 0x000021d4, 0x00000338, 0x000021d2, 0x00000338, 0x00002203, 0x00000338, 0x00002208, 0x00000338, 0x0000220b, 0x00000338, 0x00002223, 0x00000338, 0x00002225, 0x00000338, 0x0000222b, 0x0000222b, 0x0000222b, 0x0000222b, 0x0000222b, 0x0000222e, 0x0000222e, 0x0000222e, 0x0000222e, 0x0000222e, 0x0000223c, 0x00000338, 0x00002243, 0x00000338, 0x00002245, 0x00000338, 0x00002248, 0x00000338, 0x0000003d, 0x00000338, 0x00002261, 0x00000338, 0x0000224d, 0x00000338, 0x0000003c, 0x00000338, 0x0000003e, 0x00000338, 0x00002264, 0x00000338, 0x00002265, 0x00000338, 0x00002272, 0x00000338, 0x00002273, 0x00000338, 0x00002276, 0x00000338, 0x00002277, 0x00000338, 0x0000227a, 0x00000338, 0x0000227b, 0x00000338, 0x00002282, 0x00000338, 0x00002283, 0x00000338, 0x00002286, 0x00000338, 0x00002287, 0x00000338, 0x000022a2, 0x00000338, 0x000022a8, 0x00000338, 0x000022a9, 0x00000338, 0x000022ab, 0x00000338, 0x0000227c, 0x00000338, 0x0000227d, 0x00000338, 0x00002291, 0x00000338, 0x00002292, 0x00000338, 0x000022b2, 0x00000338, 0x000022b3, 0x00000338, 0x000022b4, 0x00000338, 0x000022b5, 0x00000338, 0x00003008, 0x00003009, 0x00000031, 0x00000032, 0x00000033, 0x00000034, 0x00000035, 0x00000036, 0x00000037, 0x00000038, 0x00000039, 0x00000031, 0x00000030, 0x00000031, 0x00000031, 0x00000031, 0x00000032, 0x00000031, 0x00000033, 0x00000031, 0x00000034, 0x00000031, 0x00000035, 0x00000031, 0x00000036, 0x00000031, 0x00000037, 0x00000031, 0x00000038, 0x00000031, 0x00000039, 0x00000032, 0x00000030, 0x00000028, 0x00000031, 0x00000029, 0x00000028, 0x00000032, 0x00000029, 0x00000028, 0x00000033, 0x00000029, 0x00000028, 0x00000034, 0x00000029, 0x00000028, 0x00000035, 0x00000029, 0x00000028, 0x00000036, 0x00000029, 0x00000028, 0x00000037, 0x00000029, 0x00000028, 0x00000038, 0x00000029, 0x00000028, 0x00000039, 0x00000029, 0x00000028, 0x00000031, 0x00000030, 0x00000029, 0x00000028, 0x00000031, 0x00000031, 0x00000029, 0x00000028, 0x00000031, 0x00000032, 0x00000029, 0x00000028, 0x00000031, 0x00000033, 0x00000029, 0x00000028, 0x00000031, 0x00000034, 0x00000029, 0x00000028, 0x00000031, 0x00000035, 0x00000029, 0x00000028, 0x00000031, 0x00000036, 0x00000029, 0x00000028, 0x00000031, 0x00000037, 0x00000029, 0x00000028, 0x00000031, 0x00000038, 0x00000029, 0x00000028, 0x00000031, 0x00000039, 0x00000029, 0x00000028, 0x00000032, 0x00000030, 0x00000029, 0x00000031, 0x0000002e, 0x00000032, 0x0000002e, 0x00000033, 0x0000002e, 0x00000034, 0x0000002e, 0x00000035, 0x0000002e, 0x00000036, 0x0000002e, 0x00000037, 0x0000002e, 0x00000038, 0x0000002e, 0x00000039, 0x0000002e, 0x00000031, 0x00000030, 0x0000002e, 0x00000031, 0x00000031, 0x0000002e, 0x00000031, 0x00000032, 0x0000002e, 0x00000031, 0x00000033, 0x0000002e, 0x00000031, 0x00000034, 0x0000002e, 0x00000031, 0x00000035, 0x0000002e, 0x00000031, 0x00000036, 0x0000002e, 0x00000031, 0x00000037, 0x0000002e, 0x00000031, 0x00000038, 0x0000002e, 0x00000031, 0x00000039, 0x0000002e, 0x00000032, 0x00000030, 0x0000002e, 0x00000028, 0x00000061, 0x00000029, 0x00000028, 0x00000062, 0x00000029, 0x00000028, 0x00000063, 0x00000029, 0x00000028, 0x00000064, 0x00000029, 0x00000028, 0x00000065, 0x00000029, 0x00000028, 0x00000066, 0x00000029, 0x00000028, 0x00000067, 0x00000029, 0x00000028, 0x00000068, 0x00000029, 0x00000028, 0x00000069, 0x00000029, 0x00000028, 0x0000006a, 0x00000029, 0x00000028, 0x0000006b, 0x00000029, 0x00000028, 0x0000006c, 0x00000029, 0x00000028, 0x0000006d, 0x00000029, 0x00000028, 0x0000006e, 0x00000029, 0x00000028, 0x0000006f, 0x00000029, 0x00000028, 0x00000070, 0x00000029, 0x00000028, 0x00000071, 0x00000029, 0x00000028, 0x00000072, 0x00000029, 0x00000028, 0x00000073, 0x00000029, 0x00000028, 0x00000074, 0x00000029, 0x00000028, 0x00000075, 0x00000029, 0x00000028, 0x00000076, 0x00000029, 0x00000028, 0x00000077, 0x00000029, 0x00000028, 0x00000078, 0x00000029, 0x00000028, 0x00000079, 0x00000029, 0x00000028, 0x0000007a, 0x00000029, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 0x00000048, 0x00000049, 0x0000004a, 0x0000004b, 0x0000004c, 0x0000004d, 0x0000004e, 0x0000004f, 0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 0x00000058, 0x00000059, 0x0000005a, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x00000069, 0x0000006a, 0x0000006b, 0x0000006c, 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 0x00000078, 0x00000079, 0x0000007a, 0x00000030, 0x0000222b, 0x0000222b, 0x0000222b, 0x0000222b, 0x0000003a, 0x0000003a, 0x0000003d, 0x0000003d, 0x0000003d, 0x0000003d, 0x0000003d, 0x0000003d, 0x00002add, 0x00000338, 0x00006bcd, 0x00009f9f, 0x00004e00, 0x00004e28, 0x00004e36, 0x00004e3f, 0x00004e59, 0x00004e85, 0x00004e8c, 0x00004ea0, 0x00004eba, 0x0000513f, 0x00005165, 0x0000516b, 0x00005182, 0x00005196, 0x000051ab, 0x000051e0, 0x000051f5, 0x00005200, 0x0000529b, 0x000052f9, 0x00005315, 0x0000531a, 0x00005338, 0x00005341, 0x0000535c, 0x00005369, 0x00005382, 0x000053b6, 0x000053c8, 0x000053e3, 0x000056d7, 0x0000571f, 0x000058eb, 0x00005902, 0x0000590a, 0x00005915, 0x00005927, 0x00005973, 0x00005b50, 0x00005b80, 0x00005bf8, 0x00005c0f, 0x00005c22, 0x00005c38, 0x00005c6e, 0x00005c71, 0x00005ddb, 0x00005de5, 0x00005df1, 0x00005dfe, 0x00005e72, 0x00005e7a, 0x00005e7f, 0x00005ef4, 0x00005efe, 0x00005f0b, 0x00005f13, 0x00005f50, 0x00005f61, 0x00005f73, 0x00005fc3, 0x00006208, 0x00006236, 0x0000624b, 0x0000652f, 0x00006534, 0x00006587, 0x00006597, 0x000065a4, 0x000065b9, 0x000065e0, 0x000065e5, 0x000066f0, 0x00006708, 0x00006728, 0x00006b20, 0x00006b62, 0x00006b79, 0x00006bb3, 0x00006bcb, 0x00006bd4, 0x00006bdb, 0x00006c0f, 0x00006c14, 0x00006c34, 0x0000706b, 0x0000722a, 0x00007236, 0x0000723b, 0x0000723f, 0x00007247, 0x00007259, 0x0000725b, 0x000072ac, 0x00007384, 0x00007389, 0x000074dc, 0x000074e6, 0x00007518, 0x0000751f, 0x00007528, 0x00007530, 0x0000758b, 0x00007592, 0x00007676, 0x0000767d, 0x000076ae, 0x000076bf, 0x000076ee, 0x000077db, 0x000077e2, 0x000077f3, 0x0000793a, 0x000079b8, 0x000079be, 0x00007a74, 0x00007acb, 0x00007af9, 0x00007c73, 0x00007cf8, 0x00007f36, 0x00007f51, 0x00007f8a, 0x00007fbd, 0x00008001, 0x0000800c, 0x00008012, 0x00008033, 0x0000807f, 0x00008089, 0x000081e3, 0x000081ea, 0x000081f3, 0x000081fc, 0x0000820c, 0x0000821b, 0x0000821f, 0x0000826e, 0x00008272, 0x00008278, 0x0000864d, 0x0000866b, 0x00008840, 0x0000884c, 0x00008863, 0x0000897e, 0x0000898b, 0x000089d2, 0x00008a00, 0x00008c37, 0x00008c46, 0x00008c55, 0x00008c78, 0x00008c9d, 0x00008d64, 0x00008d70, 0x00008db3, 0x00008eab, 0x00008eca, 0x00008f9b, 0x00008fb0, 0x00008fb5, 0x00009091, 0x00009149, 0x000091c6, 0x000091cc, 0x000091d1, 0x00009577, 0x00009580, 0x0000961c, 0x000096b6, 0x000096b9, 0x000096e8, 0x00009751, 0x0000975e, 0x00009762, 0x00009769, 0x000097cb, 0x000097ed, 0x000097f3, 0x00009801, 0x000098a8, 0x000098db, 0x000098df, 0x00009996, 0x00009999, 0x000099ac, 0x00009aa8, 0x00009ad8, 0x00009adf, 0x00009b25, 0x00009b2f, 0x00009b32, 0x00009b3c, 0x00009b5a, 0x00009ce5, 0x00009e75, 0x00009e7f, 0x00009ea5, 0x00009ebb, 0x00009ec3, 0x00009ecd, 0x00009ed1, 0x00009ef9, 0x00009efd, 0x00009f0e, 0x00009f13, 0x00009f20, 0x00009f3b, 0x00009f4a, 0x00009f52, 0x00009f8d, 0x00009f9c, 0x00009fa0, 0x00000020, 0x00003012, 0x00005341, 0x00005344, 0x00005345, 0x0000304b, 0x00003099, 0x0000304d, 0x00003099, 0x0000304f, 0x00003099, 0x00003051, 0x00003099, 0x00003053, 0x00003099, 0x00003055, 0x00003099, 0x00003057, 0x00003099, 0x00003059, 0x00003099, 0x0000305b, 0x00003099, 0x0000305d, 0x00003099, 0x0000305f, 0x00003099, 0x00003061, 0x00003099, 0x00003064, 0x00003099, 0x00003066, 0x00003099, 0x00003068, 0x00003099, 0x0000306f, 0x00003099, 0x0000306f, 0x0000309a, 0x00003072, 0x00003099, 0x00003072, 0x0000309a, 0x00003075, 0x00003099, 0x00003075, 0x0000309a, 0x00003078, 0x00003099, 0x00003078, 0x0000309a, 0x0000307b, 0x00003099, 0x0000307b, 0x0000309a, 0x00003046, 0x00003099, 0x00000020, 0x00003099, 0x00000020, 0x0000309a, 0x0000309d, 0x00003099, 0x00003088, 0x0000308a, 0x000030ab, 0x00003099, 0x000030ad, 0x00003099, 0x000030af, 0x00003099, 0x000030b1, 0x00003099, 0x000030b3, 0x00003099, 0x000030b5, 0x00003099, 0x000030b7, 0x00003099, 0x000030b9, 0x00003099, 0x000030bb, 0x00003099, 0x000030bd, 0x00003099, 0x000030bf, 0x00003099, 0x000030c1, 0x00003099, 0x000030c4, 0x00003099, 0x000030c6, 0x00003099, 0x000030c8, 0x00003099, 0x000030cf, 0x00003099, 0x000030cf, 0x0000309a, 0x000030d2, 0x00003099, 0x000030d2, 0x0000309a, 0x000030d5, 0x00003099, 0x000030d5, 0x0000309a, 0x000030d8, 0x00003099, 0x000030d8, 0x0000309a, 0x000030db, 0x00003099, 0x000030db, 0x0000309a, 0x000030a6, 0x00003099, 0x000030ef, 0x00003099, 0x000030f0, 0x00003099, 0x000030f1, 0x00003099, 0x000030f2, 0x00003099, 0x000030fd, 0x00003099, 0x000030b3, 0x000030c8, 0x00001100, 0x00001101, 0x000011aa, 0x00001102, 0x000011ac, 0x000011ad, 0x00001103, 0x00001104, 0x00001105, 0x000011b0, 0x000011b1, 0x000011b2, 0x000011b3, 0x000011b4, 0x000011b5, 0x0000111a, 0x00001106, 0x00001107, 0x00001108, 0x00001121, 0x00001109, 0x0000110a, 0x0000110b, 0x0000110c, 0x0000110d, 0x0000110e, 0x0000110f, 0x00001110, 0x00001111, 0x00001112, 0x00001161, 0x00001162, 0x00001163, 0x00001164, 0x00001165, 0x00001166, 0x00001167, 0x00001168, 0x00001169, 0x0000116a, 0x0000116b, 0x0000116c, 0x0000116d, 0x0000116e, 0x0000116f, 0x00001170, 0x00001171, 0x00001172, 0x00001173, 0x00001174, 0x00001175, 0x00001160, 0x00001114, 0x00001115, 0x000011c7, 0x000011c8, 0x000011cc, 0x000011ce, 0x000011d3, 0x000011d7, 0x000011d9, 0x0000111c, 0x000011dd, 0x000011df, 0x0000111d, 0x0000111e, 0x00001120, 0x00001122, 0x00001123, 0x00001127, 0x00001129, 0x0000112b, 0x0000112c, 0x0000112d, 0x0000112e, 0x0000112f, 0x00001132, 0x00001136, 0x00001140, 0x00001147, 0x0000114c, 0x000011f1, 0x000011f2, 0x00001157, 0x00001158, 0x00001159, 0x00001184, 0x00001185, 0x00001188, 0x00001191, 0x00001192, 0x00001194, 0x0000119e, 0x000011a1, 0x00004e00, 0x00004e8c, 0x00004e09, 0x000056db, 0x00004e0a, 0x00004e2d, 0x00004e0b, 0x00007532, 0x00004e59, 0x00004e19, 0x00004e01, 0x00005929, 0x00005730, 0x00004eba, 0x00000028, 0x00001100, 0x00000029, 0x00000028, 0x00001102, 0x00000029, 0x00000028, 0x00001103, 0x00000029, 0x00000028, 0x00001105, 0x00000029, 0x00000028, 0x00001106, 0x00000029, 0x00000028, 0x00001107, 0x00000029, 0x00000028, 0x00001109, 0x00000029, 0x00000028, 0x0000110b, 0x00000029, 0x00000028, 0x0000110c, 0x00000029, 0x00000028, 0x0000110e, 0x00000029, 0x00000028, 0x0000110f, 0x00000029, 0x00000028, 0x00001110, 0x00000029, 0x00000028, 0x00001111, 0x00000029, 0x00000028, 0x00001112, 0x00000029, 0x00000028, 0x00001100, 0x00001161, 0x00000029, 0x00000028, 0x00001102, 0x00001161, 0x00000029, 0x00000028, 0x00001103, 0x00001161, 0x00000029, 0x00000028, 0x00001105, 0x00001161, 0x00000029, 0x00000028, 0x00001106, 0x00001161, 0x00000029, 0x00000028, 0x00001107, 0x00001161, 0x00000029, 0x00000028, 0x00001109, 0x00001161, 0x00000029, 0x00000028, 0x0000110b, 0x00001161, 0x00000029, 0x00000028, 0x0000110c, 0x00001161, 0x00000029, 0x00000028, 0x0000110e, 0x00001161, 0x00000029, 0x00000028, 0x0000110f, 0x00001161, 0x00000029, 0x00000028, 0x00001110, 0x00001161, 0x00000029, 0x00000028, 0x00001111, 0x00001161, 0x00000029, 0x00000028, 0x00001112, 0x00001161, 0x00000029, 0x00000028, 0x0000110c, 0x0000116e, 0x00000029, 0x00000028, 0x00004e00, 0x00000029, 0x00000028, 0x00004e8c, 0x00000029, 0x00000028, 0x00004e09, 0x00000029, 0x00000028, 0x000056db, 0x00000029, 0x00000028, 0x00004e94, 0x00000029, 0x00000028, 0x0000516d, 0x00000029, 0x00000028, 0x00004e03, 0x00000029, 0x00000028, 0x0000516b, 0x00000029, 0x00000028, 0x00004e5d, 0x00000029, 0x00000028, 0x00005341, 0x00000029, 0x00000028, 0x00006708, 0x00000029, 0x00000028, 0x0000706b, 0x00000029, 0x00000028, 0x00006c34, 0x00000029, 0x00000028, 0x00006728, 0x00000029, 0x00000028, 0x000091d1, 0x00000029, 0x00000028, 0x0000571f, 0x00000029, 0x00000028, 0x000065e5, 0x00000029, 0x00000028, 0x0000682a, 0x00000029, 0x00000028, 0x00006709, 0x00000029, 0x00000028, 0x0000793e, 0x00000029, 0x00000028, 0x0000540d, 0x00000029, 0x00000028, 0x00007279, 0x00000029, 0x00000028, 0x00008ca1, 0x00000029, 0x00000028, 0x0000795d, 0x00000029, 0x00000028, 0x000052b4, 0x00000029, 0x00000028, 0x00004ee3, 0x00000029, 0x00000028, 0x0000547c, 0x00000029, 0x00000028, 0x00005b66, 0x00000029, 0x00000028, 0x000076e3, 0x00000029, 0x00000028, 0x00004f01, 0x00000029, 0x00000028, 0x00008cc7, 0x00000029, 0x00000028, 0x00005354, 0x00000029, 0x00000028, 0x0000796d, 0x00000029, 0x00000028, 0x00004f11, 0x00000029, 0x00000028, 0x000081ea, 0x00000029, 0x00000028, 0x000081f3, 0x00000029, 0x00000032, 0x00000031, 0x00000032, 0x00000032, 0x00000032, 0x00000033, 0x00000032, 0x00000034, 0x00000032, 0x00000035, 0x00000032, 0x00000036, 0x00000032, 0x00000037, 0x00000032, 0x00000038, 0x00000032, 0x00000039, 0x00000033, 0x00000030, 0x00000033, 0x00000031, 0x00000033, 0x00000032, 0x00000033, 0x00000033, 0x00000033, 0x00000034, 0x00000033, 0x00000035, 0x00001100, 0x00001102, 0x00001103, 0x00001105, 0x00001106, 0x00001107, 0x00001109, 0x0000110b, 0x0000110c, 0x0000110e, 0x0000110f, 0x00001110, 0x00001111, 0x00001112, 0x00001100, 0x00001161, 0x00001102, 0x00001161, 0x00001103, 0x00001161, 0x00001105, 0x00001161, 0x00001106, 0x00001161, 0x00001107, 0x00001161, 0x00001109, 0x00001161, 0x0000110b, 0x00001161, 0x0000110c, 0x00001161, 0x0000110e, 0x00001161, 0x0000110f, 0x00001161, 0x00001110, 0x00001161, 0x00001111, 0x00001161, 0x00001112, 0x00001161, 0x00004e00, 0x00004e8c, 0x00004e09, 0x000056db, 0x00004e94, 0x0000516d, 0x00004e03, 0x0000516b, 0x00004e5d, 0x00005341, 0x00006708, 0x0000706b, 0x00006c34, 0x00006728, 0x000091d1, 0x0000571f, 0x000065e5, 0x0000682a, 0x00006709, 0x0000793e, 0x0000540d, 0x00007279, 0x00008ca1, 0x0000795d, 0x000052b4, 0x000079d8, 0x00007537, 0x00005973, 0x00009069, 0x0000512a, 0x00005370, 0x00006ce8, 0x00009805, 0x00004f11, 0x00005199, 0x00006b63, 0x00004e0a, 0x00004e2d, 0x00004e0b, 0x00005de6, 0x000053f3, 0x0000533b, 0x00005b97, 0x00005b66, 0x000076e3, 0x00004f01, 0x00008cc7, 0x00005354, 0x0000591c, 0x00000033, 0x00000036, 0x00000033, 0x00000037, 0x00000033, 0x00000038, 0x00000033, 0x00000039, 0x00000034, 0x00000030, 0x00000034, 0x00000031, 0x00000034, 0x00000032, 0x00000034, 0x00000033, 0x00000034, 0x00000034, 0x00000034, 0x00000035, 0x00000034, 0x00000036, 0x00000034, 0x00000037, 0x00000034, 0x00000038, 0x00000034, 0x00000039, 0x00000035, 0x00000030, 0x00000031, 0x00006708, 0x00000032, 0x00006708, 0x00000033, 0x00006708, 0x00000034, 0x00006708, 0x00000035, 0x00006708, 0x00000036, 0x00006708, 0x00000037, 0x00006708, 0x00000038, 0x00006708, 0x00000039, 0x00006708, 0x00000031, 0x00000030, 0x00006708, 0x00000031, 0x00000031, 0x00006708, 0x00000031, 0x00000032, 0x00006708, 0x000030a2, 0x000030a4, 0x000030a6, 0x000030a8, 0x000030aa, 0x000030ab, 0x000030ad, 0x000030af, 0x000030b1, 0x000030b3, 0x000030b5, 0x000030b7, 0x000030b9, 0x000030bb, 0x000030bd, 0x000030bf, 0x000030c1, 0x000030c4, 0x000030c6, 0x000030c8, 0x000030ca, 0x000030cb, 0x000030cc, 0x000030cd, 0x000030ce, 0x000030cf, 0x000030d2, 0x000030d5, 0x000030d8, 0x000030db, 0x000030de, 0x000030df, 0x000030e0, 0x000030e1, 0x000030e2, 0x000030e4, 0x000030e6, 0x000030e8, 0x000030e9, 0x000030ea, 0x000030eb, 0x000030ec, 0x000030ed, 0x000030ef, 0x000030f0, 0x000030f1, 0x000030f2, 0x000030a2, 0x000030cf, 0x0000309a, 0x000030fc, 0x000030c8, 0x000030a2, 0x000030eb, 0x000030d5, 0x000030a1, 0x000030a2, 0x000030f3, 0x000030d8, 0x0000309a, 0x000030a2, 0x000030a2, 0x000030fc, 0x000030eb, 0x000030a4, 0x000030cb, 0x000030f3, 0x000030af, 0x00003099, 0x000030a4, 0x000030f3, 0x000030c1, 0x000030a6, 0x000030a9, 0x000030f3, 0x000030a8, 0x000030b9, 0x000030af, 0x000030fc, 0x000030c8, 0x00003099, 0x000030a8, 0x000030fc, 0x000030ab, 0x000030fc, 0x000030aa, 0x000030f3, 0x000030b9, 0x000030aa, 0x000030fc, 0x000030e0, 0x000030ab, 0x000030a4, 0x000030ea, 0x000030ab, 0x000030e9, 0x000030c3, 0x000030c8, 0x000030ab, 0x000030ed, 0x000030ea, 0x000030fc, 0x000030ab, 0x00003099, 0x000030ed, 0x000030f3, 0x000030ab, 0x00003099, 0x000030f3, 0x000030de, 0x000030ad, 0x00003099, 0x000030ab, 0x00003099, 0x000030ad, 0x00003099, 0x000030cb, 0x000030fc, 0x000030ad, 0x000030e5, 0x000030ea, 0x000030fc, 0x000030ad, 0x00003099, 0x000030eb, 0x000030bf, 0x00003099, 0x000030fc, 0x000030ad, 0x000030ed, 0x000030ad, 0x000030ed, 0x000030af, 0x00003099, 0x000030e9, 0x000030e0, 0x000030ad, 0x000030ed, 0x000030e1, 0x000030fc, 0x000030c8, 0x000030eb, 0x000030ad, 0x000030ed, 0x000030ef, 0x000030c3, 0x000030c8, 0x000030af, 0x00003099, 0x000030e9, 0x000030e0, 0x000030af, 0x00003099, 0x000030e9, 0x000030e0, 0x000030c8, 0x000030f3, 0x000030af, 0x000030eb, 0x000030bb, 0x00003099, 0x000030a4, 0x000030ed, 0x000030af, 0x000030ed, 0x000030fc, 0x000030cd, 0x000030b1, 0x000030fc, 0x000030b9, 0x000030b3, 0x000030eb, 0x000030ca, 0x000030b3, 0x000030fc, 0x000030db, 0x0000309a, 0x000030b5, 0x000030a4, 0x000030af, 0x000030eb, 0x000030b5, 0x000030f3, 0x000030c1, 0x000030fc, 0x000030e0, 0x000030b7, 0x000030ea, 0x000030f3, 0x000030af, 0x00003099, 0x000030bb, 0x000030f3, 0x000030c1, 0x000030bb, 0x000030f3, 0x000030c8, 0x000030bf, 0x00003099, 0x000030fc, 0x000030b9, 0x000030c6, 0x00003099, 0x000030b7, 0x000030c8, 0x00003099, 0x000030eb, 0x000030c8, 0x000030f3, 0x000030ca, 0x000030ce, 0x000030ce, 0x000030c3, 0x000030c8, 0x000030cf, 0x000030a4, 0x000030c4, 0x000030cf, 0x0000309a, 0x000030fc, 0x000030bb, 0x000030f3, 0x000030c8, 0x000030cf, 0x0000309a, 0x000030fc, 0x000030c4, 0x000030cf, 0x00003099, 0x000030fc, 0x000030ec, 0x000030eb, 0x000030d2, 0x0000309a, 0x000030a2, 0x000030b9, 0x000030c8, 0x000030eb, 0x000030d2, 0x0000309a, 0x000030af, 0x000030eb, 0x000030d2, 0x0000309a, 0x000030b3, 0x000030d2, 0x00003099, 0x000030eb, 0x000030d5, 0x000030a1, 0x000030e9, 0x000030c3, 0x000030c8, 0x00003099, 0x000030d5, 0x000030a3, 0x000030fc, 0x000030c8, 0x000030d5, 0x00003099, 0x000030c3, 0x000030b7, 0x000030a7, 0x000030eb, 0x000030d5, 0x000030e9, 0x000030f3, 0x000030d8, 0x000030af, 0x000030bf, 0x000030fc, 0x000030eb, 0x000030d8, 0x0000309a, 0x000030bd, 0x000030d8, 0x0000309a, 0x000030cb, 0x000030d2, 0x000030d8, 0x000030eb, 0x000030c4, 0x000030d8, 0x0000309a, 0x000030f3, 0x000030b9, 0x000030d8, 0x0000309a, 0x000030fc, 0x000030b7, 0x00003099, 0x000030d8, 0x00003099, 0x000030fc, 0x000030bf, 0x000030db, 0x0000309a, 0x000030a4, 0x000030f3, 0x000030c8, 0x000030db, 0x00003099, 0x000030eb, 0x000030c8, 0x000030db, 0x000030f3, 0x000030db, 0x0000309a, 0x000030f3, 0x000030c8, 0x00003099, 0x000030db, 0x000030fc, 0x000030eb, 0x000030db, 0x000030fc, 0x000030f3, 0x000030de, 0x000030a4, 0x000030af, 0x000030ed, 0x000030de, 0x000030a4, 0x000030eb, 0x000030de, 0x000030c3, 0x000030cf, 0x000030de, 0x000030eb, 0x000030af, 0x000030de, 0x000030f3, 0x000030b7, 0x000030e7, 0x000030f3, 0x000030df, 0x000030af, 0x000030ed, 0x000030f3, 0x000030df, 0x000030ea, 0x000030df, 0x000030ea, 0x000030cf, 0x00003099, 0x000030fc, 0x000030eb, 0x000030e1, 0x000030ab, 0x00003099, 0x000030e1, 0x000030ab, 0x00003099, 0x000030c8, 0x000030f3, 0x000030e1, 0x000030fc, 0x000030c8, 0x000030eb, 0x000030e4, 0x000030fc, 0x000030c8, 0x00003099, 0x000030e4, 0x000030fc, 0x000030eb, 0x000030e6, 0x000030a2, 0x000030f3, 0x000030ea, 0x000030c3, 0x000030c8, 0x000030eb, 0x000030ea, 0x000030e9, 0x000030eb, 0x000030d2, 0x0000309a, 0x000030fc, 0x000030eb, 0x000030fc, 0x000030d5, 0x00003099, 0x000030eb, 0x000030ec, 0x000030e0, 0x000030ec, 0x000030f3, 0x000030c8, 0x000030b1, 0x00003099, 0x000030f3, 0x000030ef, 0x000030c3, 0x000030c8, 0x00000030, 0x000070b9, 0x00000031, 0x000070b9, 0x00000032, 0x000070b9, 0x00000033, 0x000070b9, 0x00000034, 0x000070b9, 0x00000035, 0x000070b9, 0x00000036, 0x000070b9, 0x00000037, 0x000070b9, 0x00000038, 0x000070b9, 0x00000039, 0x000070b9, 0x00000031, 0x00000030, 0x000070b9, 0x00000031, 0x00000031, 0x000070b9, 0x00000031, 0x00000032, 0x000070b9, 0x00000031, 0x00000033, 0x000070b9, 0x00000031, 0x00000034, 0x000070b9, 0x00000031, 0x00000035, 0x000070b9, 0x00000031, 0x00000036, 0x000070b9, 0x00000031, 0x00000037, 0x000070b9, 0x00000031, 0x00000038, 0x000070b9, 0x00000031, 0x00000039, 0x000070b9, 0x00000032, 0x00000030, 0x000070b9, 0x00000032, 0x00000031, 0x000070b9, 0x00000032, 0x00000032, 0x000070b9, 0x00000032, 0x00000033, 0x000070b9, 0x00000032, 0x00000034, 0x000070b9, 0x00000068, 0x00000050, 0x00000061, 0x00000064, 0x00000061, 0x00000041, 0x00000055, 0x00000062, 0x00000061, 0x00000072, 0x0000006f, 0x00000056, 0x00000070, 0x00000063, 0x00005e73, 0x00006210, 0x0000662d, 0x0000548c, 0x00005927, 0x00006b63, 0x0000660e, 0x00006cbb, 0x0000682a, 0x00005f0f, 0x00004f1a, 0x0000793e, 0x00000070, 0x00000041, 0x0000006e, 0x00000041, 0x000003bc, 0x00000041, 0x0000006d, 0x00000041, 0x0000006b, 0x00000041, 0x0000004b, 0x00000042, 0x0000004d, 0x00000042, 0x00000047, 0x00000042, 0x00000063, 0x00000061, 0x0000006c, 0x0000006b, 0x00000063, 0x00000061, 0x0000006c, 0x00000070, 0x00000046, 0x0000006e, 0x00000046, 0x000003bc, 0x00000046, 0x000003bc, 0x00000067, 0x0000006d, 0x00000067, 0x0000006b, 0x00000067, 0x00000048, 0x0000007a, 0x0000006b, 0x00000048, 0x0000007a, 0x0000004d, 0x00000048, 0x0000007a, 0x00000047, 0x00000048, 0x0000007a, 0x00000054, 0x00000048, 0x0000007a, 0x000003bc, 0x0000006c, 0x0000006d, 0x0000006c, 0x00000064, 0x0000006c, 0x0000006b, 0x0000006c, 0x00000066, 0x0000006d, 0x0000006e, 0x0000006d, 0x000003bc, 0x0000006d, 0x0000006d, 0x0000006d, 0x00000063, 0x0000006d, 0x0000006b, 0x0000006d, 0x0000006d, 0x0000006d, 0x00000032, 0x00000063, 0x0000006d, 0x00000032, 0x0000006d, 0x00000032, 0x0000006b, 0x0000006d, 0x00000032, 0x0000006d, 0x0000006d, 0x00000033, 0x00000063, 0x0000006d, 0x00000033, 0x0000006d, 0x00000033, 0x0000006b, 0x0000006d, 0x00000033, 0x0000006d, 0x00002215, 0x00000073, 0x0000006d, 0x00002215, 0x00000073, 0x00000032, 0x00000050, 0x00000061, 0x0000006b, 0x00000050, 0x00000061, 0x0000004d, 0x00000050, 0x00000061, 0x00000047, 0x00000050, 0x00000061, 0x00000072, 0x00000061, 0x00000064, 0x00000072, 0x00000061, 0x00000064, 0x00002215, 0x00000073, 0x00000072, 0x00000061, 0x00000064, 0x00002215, 0x00000073, 0x00000032, 0x00000070, 0x00000073, 0x0000006e, 0x00000073, 0x000003bc, 0x00000073, 0x0000006d, 0x00000073, 0x00000070, 0x00000056, 0x0000006e, 0x00000056, 0x000003bc, 0x00000056, 0x0000006d, 0x00000056, 0x0000006b, 0x00000056, 0x0000004d, 0x00000056, 0x00000070, 0x00000057, 0x0000006e, 0x00000057, 0x000003bc, 0x00000057, 0x0000006d, 0x00000057, 0x0000006b, 0x00000057, 0x0000004d, 0x00000057, 0x0000006b, 0x000003a9, 0x0000004d, 0x000003a9, 0x00000061, 0x0000002e, 0x0000006d, 0x0000002e, 0x00000042, 0x00000071, 0x00000063, 0x00000063, 0x00000063, 0x00000064, 0x00000043, 0x00002215, 0x0000006b, 0x00000067, 0x00000043, 0x0000006f, 0x0000002e, 0x00000064, 0x00000042, 0x00000047, 0x00000079, 0x00000068, 0x00000061, 0x00000048, 0x00000050, 0x00000069, 0x0000006e, 0x0000004b, 0x0000004b, 0x0000004b, 0x0000004d, 0x0000006b, 0x00000074, 0x0000006c, 0x0000006d, 0x0000006c, 0x0000006e, 0x0000006c, 0x0000006f, 0x00000067, 0x0000006c, 0x00000078, 0x0000006d, 0x00000062, 0x0000006d, 0x00000069, 0x0000006c, 0x0000006d, 0x0000006f, 0x0000006c, 0x00000050, 0x00000048, 0x00000070, 0x0000002e, 0x0000006d, 0x0000002e, 0x00000050, 0x00000050, 0x0000004d, 0x00000050, 0x00000052, 0x00000073, 0x00000072, 0x00000053, 0x00000076, 0x00000057, 0x00000062, 0x00000031, 0x000065e5, 0x00000032, 0x000065e5, 0x00000033, 0x000065e5, 0x00000034, 0x000065e5, 0x00000035, 0x000065e5, 0x00000036, 0x000065e5, 0x00000037, 0x000065e5, 0x00000038, 0x000065e5, 0x00000039, 0x000065e5, 0x00000031, 0x00000030, 0x000065e5, 0x00000031, 0x00000031, 0x000065e5, 0x00000031, 0x00000032, 0x000065e5, 0x00000031, 0x00000033, 0x000065e5, 0x00000031, 0x00000034, 0x000065e5, 0x00000031, 0x00000035, 0x000065e5, 0x00000031, 0x00000036, 0x000065e5, 0x00000031, 0x00000037, 0x000065e5, 0x00000031, 0x00000038, 0x000065e5, 0x00000031, 0x00000039, 0x000065e5, 0x00000032, 0x00000030, 0x000065e5, 0x00000032, 0x00000031, 0x000065e5, 0x00000032, 0x00000032, 0x000065e5, 0x00000032, 0x00000033, 0x000065e5, 0x00000032, 0x00000034, 0x000065e5, 0x00000032, 0x00000035, 0x000065e5, 0x00000032, 0x00000036, 0x000065e5, 0x00000032, 0x00000037, 0x000065e5, 0x00000032, 0x00000038, 0x000065e5, 0x00000032, 0x00000039, 0x000065e5, 0x00000033, 0x00000030, 0x000065e5, 0x00000033, 0x00000031, 0x000065e5, 0x00008eca, 0x00008cc8, 0x00006ed1, 0x00004e32, 0x000053e5, 0x00009f9c, 0x00009f9c, 0x00005951, 0x000091d1, 0x00005587, 0x00005948, 0x000061f6, 0x00007669, 0x00007f85, 0x0000863f, 0x000087ba, 0x000088f8, 0x0000908f, 0x00006a02, 0x00006d1b, 0x000070d9, 0x000073de, 0x0000843d, 0x0000916a, 0x000099f1, 0x00004e82, 0x00005375, 0x00006b04, 0x0000721b, 0x0000862d, 0x00009e1e, 0x00005d50, 0x00006feb, 0x000085cd, 0x00008964, 0x000062c9, 0x000081d8, 0x0000881f, 0x00005eca, 0x00006717, 0x00006d6a, 0x000072fc, 0x000090ce, 0x00004f86, 0x000051b7, 0x000052de, 0x000064c4, 0x00006ad3, 0x00007210, 0x000076e7, 0x00008001, 0x00008606, 0x0000865c, 0x00008def, 0x00009732, 0x00009b6f, 0x00009dfa, 0x0000788c, 0x0000797f, 0x00007da0, 0x000083c9, 0x00009304, 0x00009e7f, 0x00008ad6, 0x000058df, 0x00005f04, 0x00007c60, 0x0000807e, 0x00007262, 0x000078ca, 0x00008cc2, 0x000096f7, 0x000058d8, 0x00005c62, 0x00006a13, 0x00006dda, 0x00006f0f, 0x00007d2f, 0x00007e37, 0x0000964b, 0x000052d2, 0x0000808b, 0x000051dc, 0x000051cc, 0x00007a1c, 0x00007dbe, 0x000083f1, 0x00009675, 0x00008b80, 0x000062cf, 0x00006a02, 0x00008afe, 0x00004e39, 0x00005be7, 0x00006012, 0x00007387, 0x00007570, 0x00005317, 0x000078fb, 0x00004fbf, 0x00005fa9, 0x00004e0d, 0x00006ccc, 0x00006578, 0x00007d22, 0x000053c3, 0x0000585e, 0x00007701, 0x00008449, 0x00008aaa, 0x00006bba, 0x00008fb0, 0x00006c88, 0x000062fe, 0x000082e5, 0x000063a0, 0x00007565, 0x00004eae, 0x00005169, 0x000051c9, 0x00006881, 0x00007ce7, 0x0000826f, 0x00008ad2, 0x000091cf, 0x000052f5, 0x00005442, 0x00005973, 0x00005eec, 0x000065c5, 0x00006ffe, 0x0000792a, 0x000095ad, 0x00009a6a, 0x00009e97, 0x00009ece, 0x0000529b, 0x000066c6, 0x00006b77, 0x00008f62, 0x00005e74, 0x00006190, 0x00006200, 0x0000649a, 0x00006f23, 0x00007149, 0x00007489, 0x000079ca, 0x00007df4, 0x0000806f, 0x00008f26, 0x000084ee, 0x00009023, 0x0000934a, 0x00005217, 0x000052a3, 0x000054bd, 0x000070c8, 0x000088c2, 0x00008aaa, 0x00005ec9, 0x00005ff5, 0x0000637b, 0x00006bae, 0x00007c3e, 0x00007375, 0x00004ee4, 0x000056f9, 0x00005be7, 0x00005dba, 0x0000601c, 0x000073b2, 0x00007469, 0x00007f9a, 0x00008046, 0x00009234, 0x000096f6, 0x00009748, 0x00009818, 0x00004f8b, 0x000079ae, 0x000091b4, 0x000096b8, 0x000060e1, 0x00004e86, 0x000050da, 0x00005bee, 0x00005c3f, 0x00006599, 0x00006a02, 0x000071ce, 0x00007642, 0x000084fc, 0x0000907c, 0x00009f8d, 0x00006688, 0x0000962e, 0x00005289, 0x0000677b, 0x000067f3, 0x00006d41, 0x00006e9c, 0x00007409, 0x00007559, 0x0000786b, 0x00007d10, 0x0000985e, 0x0000516d, 0x0000622e, 0x00009678, 0x0000502b, 0x00005d19, 0x00006dea, 0x00008f2a, 0x00005f8b, 0x00006144, 0x00006817, 0x00007387, 0x00009686, 0x00005229, 0x0000540f, 0x00005c65, 0x00006613, 0x0000674e, 0x000068a8, 0x00006ce5, 0x00007406, 0x000075e2, 0x00007f79, 0x000088cf, 0x000088e1, 0x000091cc, 0x000096e2, 0x0000533f, 0x00006eba, 0x0000541d, 0x000071d0, 0x00007498, 0x000085fa, 0x000096a3, 0x00009c57, 0x00009e9f, 0x00006797, 0x00006dcb, 0x000081e8, 0x00007acb, 0x00007b20, 0x00007c92, 0x000072c0, 0x00007099, 0x00008b58, 0x00004ec0, 0x00008336, 0x0000523a, 0x00005207, 0x00005ea6, 0x000062d3, 0x00007cd6, 0x00005b85, 0x00006d1e, 0x000066b4, 0x00008f3b, 0x0000884c, 0x0000964d, 0x0000898b, 0x00005ed3, 0x00005140, 0x000055c0, 0x0000585a, 0x00006674, 0x000051de, 0x0000732a, 0x000076ca, 0x0000793c, 0x0000795e, 0x00007965, 0x0000798f, 0x00009756, 0x00007cbe, 0x00007fbd, 0x00008612, 0x00008af8, 0x00009038, 0x000090fd, 0x000098ef, 0x000098fc, 0x00009928, 0x00009db4, 0x00004fae, 0x000050e7, 0x0000514d, 0x000052c9, 0x000052e4, 0x00005351, 0x0000559d, 0x00005606, 0x00005668, 0x00005840, 0x000058a8, 0x00005c64, 0x00005c6e, 0x00006094, 0x00006168, 0x0000618e, 0x000061f2, 0x0000654f, 0x000065e2, 0x00006691, 0x00006885, 0x00006d77, 0x00006e1a, 0x00006f22, 0x0000716e, 0x0000722b, 0x00007422, 0x00007891, 0x0000793e, 0x00007949, 0x00007948, 0x00007950, 0x00007956, 0x0000795d, 0x0000798d, 0x0000798e, 0x00007a40, 0x00007a81, 0x00007bc0, 0x00007df4, 0x00007e09, 0x00007e41, 0x00007f72, 0x00008005, 0x000081ed, 0x00008279, 0x00008279, 0x00008457, 0x00008910, 0x00008996, 0x00008b01, 0x00008b39, 0x00008cd3, 0x00008d08, 0x00008fb6, 0x00009038, 0x000096e3, 0x000097ff, 0x0000983b, 0x00000066, 0x00000066, 0x00000066, 0x00000069, 0x00000066, 0x0000006c, 0x00000066, 0x00000066, 0x00000069, 0x00000066, 0x00000066, 0x0000006c, 0x00000073, 0x00000074, 0x00000073, 0x00000074, 0x00000574, 0x00000576, 0x00000574, 0x00000565, 0x00000574, 0x0000056b, 0x0000057e, 0x00000576, 0x00000574, 0x0000056d, 0x000005d9, 0x000005b4, 0x000005f2, 0x000005b7, 0x000005e2, 0x000005d0, 0x000005d3, 0x000005d4, 0x000005db, 0x000005dc, 0x000005dd, 0x000005e8, 0x000005ea, 0x0000002b, 0x000005e9, 0x000005c1, 0x000005e9, 0x000005c2, 0x000005e9, 0x000005bc, 0x000005c1, 0x000005e9, 0x000005bc, 0x000005c2, 0x000005d0, 0x000005b7, 0x000005d0, 0x000005b8, 0x000005d0, 0x000005bc, 0x000005d1, 0x000005bc, 0x000005d2, 0x000005bc, 0x000005d3, 0x000005bc, 0x000005d4, 0x000005bc, 0x000005d5, 0x000005bc, 0x000005d6, 0x000005bc, 0x000005d8, 0x000005bc, 0x000005d9, 0x000005bc, 0x000005da, 0x000005bc, 0x000005db, 0x000005bc, 0x000005dc, 0x000005bc, 0x000005de, 0x000005bc, 0x000005e0, 0x000005bc, 0x000005e1, 0x000005bc, 0x000005e3, 0x000005bc, 0x000005e4, 0x000005bc, 0x000005e6, 0x000005bc, 0x000005e7, 0x000005bc, 0x000005e8, 0x000005bc, 0x000005e9, 0x000005bc, 0x000005ea, 0x000005bc, 0x000005d5, 0x000005b9, 0x000005d1, 0x000005bf, 0x000005db, 0x000005bf, 0x000005e4, 0x000005bf, 0x000005d0, 0x000005dc, 0x00000671, 0x00000671, 0x0000067b, 0x0000067b, 0x0000067b, 0x0000067b, 0x0000067e, 0x0000067e, 0x0000067e, 0x0000067e, 0x00000680, 0x00000680, 0x00000680, 0x00000680, 0x0000067a, 0x0000067a, 0x0000067a, 0x0000067a, 0x0000067f, 0x0000067f, 0x0000067f, 0x0000067f, 0x00000679, 0x00000679, 0x00000679, 0x00000679, 0x000006a4, 0x000006a4, 0x000006a4, 0x000006a4, 0x000006a6, 0x000006a6, 0x000006a6, 0x000006a6, 0x00000684, 0x00000684, 0x00000684, 0x00000684, 0x00000683, 0x00000683, 0x00000683, 0x00000683, 0x00000686, 0x00000686, 0x00000686, 0x00000686, 0x00000687, 0x00000687, 0x00000687, 0x00000687, 0x0000068d, 0x0000068d, 0x0000068c, 0x0000068c, 0x0000068e, 0x0000068e, 0x00000688, 0x00000688, 0x00000698, 0x00000698, 0x00000691, 0x00000691, 0x000006a9, 0x000006a9, 0x000006a9, 0x000006a9, 0x000006af, 0x000006af, 0x000006af, 0x000006af, 0x000006b3, 0x000006b3, 0x000006b3, 0x000006b3, 0x000006b1, 0x000006b1, 0x000006b1, 0x000006b1, 0x000006ba, 0x000006ba, 0x000006bb, 0x000006bb, 0x000006bb, 0x000006bb, 0x000006d5, 0x00000654, 0x000006d5, 0x00000654, 0x000006c1, 0x000006c1, 0x000006c1, 0x000006c1, 0x000006be, 0x000006be, 0x000006be, 0x000006be, 0x000006d2, 0x000006d2, 0x000006d2, 0x00000654, 0x000006d2, 0x00000654, 0x000006ad, 0x000006ad, 0x000006ad, 0x000006ad, 0x000006c7, 0x000006c7, 0x000006c6, 0x000006c6, 0x000006c8, 0x000006c8, 0x000006c7, 0x00000674, 0x000006cb, 0x000006cb, 0x000006c5, 0x000006c5, 0x000006c9, 0x000006c9, 0x000006d0, 0x000006d0, 0x000006d0, 0x000006d0, 0x00000649, 0x00000649, 0x0000064a, 0x00000654, 0x00000627, 0x0000064a, 0x00000654, 0x00000627, 0x0000064a, 0x00000654, 0x000006d5, 0x0000064a, 0x00000654, 0x000006d5, 0x0000064a, 0x00000654, 0x00000648, 0x0000064a, 0x00000654, 0x00000648, 0x0000064a, 0x00000654, 0x000006c7, 0x0000064a, 0x00000654, 0x000006c7, 0x0000064a, 0x00000654, 0x000006c6, 0x0000064a, 0x00000654, 0x000006c6, 0x0000064a, 0x00000654, 0x000006c8, 0x0000064a, 0x00000654, 0x000006c8, 0x0000064a, 0x00000654, 0x000006d0, 0x0000064a, 0x00000654, 0x000006d0, 0x0000064a, 0x00000654, 0x000006d0, 0x0000064a, 0x00000654, 0x00000649, 0x0000064a, 0x00000654, 0x00000649, 0x0000064a, 0x00000654, 0x00000649, 0x000006cc, 0x000006cc, 0x000006cc, 0x000006cc, 0x0000064a, 0x00000654, 0x0000062c, 0x0000064a, 0x00000654, 0x0000062d, 0x0000064a, 0x00000654, 0x00000645, 0x0000064a, 0x00000654, 0x00000649, 0x0000064a, 0x00000654, 0x0000064a, 0x00000628, 0x0000062c, 0x00000628, 0x0000062d, 0x00000628, 0x0000062e, 0x00000628, 0x00000645, 0x00000628, 0x00000649, 0x00000628, 0x0000064a, 0x0000062a, 0x0000062c, 0x0000062a, 0x0000062d, 0x0000062a, 0x0000062e, 0x0000062a, 0x00000645, 0x0000062a, 0x00000649, 0x0000062a, 0x0000064a, 0x0000062b, 0x0000062c, 0x0000062b, 0x00000645, 0x0000062b, 0x00000649, 0x0000062b, 0x0000064a, 0x0000062c, 0x0000062d, 0x0000062c, 0x00000645, 0x0000062d, 0x0000062c, 0x0000062d, 0x00000645, 0x0000062e, 0x0000062c, 0x0000062e, 0x0000062d, 0x0000062e, 0x00000645, 0x00000633, 0x0000062c, 0x00000633, 0x0000062d, 0x00000633, 0x0000062e, 0x00000633, 0x00000645, 0x00000635, 0x0000062d, 0x00000635, 0x00000645, 0x00000636, 0x0000062c, 0x00000636, 0x0000062d, 0x00000636, 0x0000062e, 0x00000636, 0x00000645, 0x00000637, 0x0000062d, 0x00000637, 0x00000645, 0x00000638, 0x00000645, 0x00000639, 0x0000062c, 0x00000639, 0x00000645, 0x0000063a, 0x0000062c, 0x0000063a, 0x00000645, 0x00000641, 0x0000062c, 0x00000641, 0x0000062d, 0x00000641, 0x0000062e, 0x00000641, 0x00000645, 0x00000641, 0x00000649, 0x00000641, 0x0000064a, 0x00000642, 0x0000062d, 0x00000642, 0x00000645, 0x00000642, 0x00000649, 0x00000642, 0x0000064a, 0x00000643, 0x00000627, 0x00000643, 0x0000062c, 0x00000643, 0x0000062d, 0x00000643, 0x0000062e, 0x00000643, 0x00000644, 0x00000643, 0x00000645, 0x00000643, 0x00000649, 0x00000643, 0x0000064a, 0x00000644, 0x0000062c, 0x00000644, 0x0000062d, 0x00000644, 0x0000062e, 0x00000644, 0x00000645, 0x00000644, 0x00000649, 0x00000644, 0x0000064a, 0x00000645, 0x0000062c, 0x00000645, 0x0000062d, 0x00000645, 0x0000062e, 0x00000645, 0x00000645, 0x00000645, 0x00000649, 0x00000645, 0x0000064a, 0x00000646, 0x0000062c, 0x00000646, 0x0000062d, 0x00000646, 0x0000062e, 0x00000646, 0x00000645, 0x00000646, 0x00000649, 0x00000646, 0x0000064a, 0x00000647, 0x0000062c, 0x00000647, 0x00000645, 0x00000647, 0x00000649, 0x00000647, 0x0000064a, 0x0000064a, 0x0000062c, 0x0000064a, 0x0000062d, 0x0000064a, 0x0000062e, 0x0000064a, 0x00000645, 0x0000064a, 0x00000649, 0x0000064a, 0x0000064a, 0x00000630, 0x00000670, 0x00000631, 0x00000670, 0x00000649, 0x00000670, 0x00000020, 0x0000064c, 0x00000651, 0x00000020, 0x0000064d, 0x00000651, 0x00000020, 0x0000064e, 0x00000651, 0x00000020, 0x0000064f, 0x00000651, 0x00000020, 0x00000650, 0x00000651, 0x00000020, 0x00000651, 0x00000670, 0x0000064a, 0x00000654, 0x00000631, 0x0000064a, 0x00000654, 0x00000632, 0x0000064a, 0x00000654, 0x00000645, 0x0000064a, 0x00000654, 0x00000646, 0x0000064a, 0x00000654, 0x00000649, 0x0000064a, 0x00000654, 0x0000064a, 0x00000628, 0x00000631, 0x00000628, 0x00000632, 0x00000628, 0x00000645, 0x00000628, 0x00000646, 0x00000628, 0x00000649, 0x00000628, 0x0000064a, 0x0000062a, 0x00000631, 0x0000062a, 0x00000632, 0x0000062a, 0x00000645, 0x0000062a, 0x00000646, 0x0000062a, 0x00000649, 0x0000062a, 0x0000064a, 0x0000062b, 0x00000631, 0x0000062b, 0x00000632, 0x0000062b, 0x00000645, 0x0000062b, 0x00000646, 0x0000062b, 0x00000649, 0x0000062b, 0x0000064a, 0x00000641, 0x00000649, 0x00000641, 0x0000064a, 0x00000642, 0x00000649, 0x00000642, 0x0000064a, 0x00000643, 0x00000627, 0x00000643, 0x00000644, 0x00000643, 0x00000645, 0x00000643, 0x00000649, 0x00000643, 0x0000064a, 0x00000644, 0x00000645, 0x00000644, 0x00000649, 0x00000644, 0x0000064a, 0x00000645, 0x00000627, 0x00000645, 0x00000645, 0x00000646, 0x00000631, 0x00000646, 0x00000632, 0x00000646, 0x00000645, 0x00000646, 0x00000646, 0x00000646, 0x00000649, 0x00000646, 0x0000064a, 0x00000649, 0x00000670, 0x0000064a, 0x00000631, 0x0000064a, 0x00000632, 0x0000064a, 0x00000645, 0x0000064a, 0x00000646, 0x0000064a, 0x00000649, 0x0000064a, 0x0000064a, 0x0000064a, 0x00000654, 0x0000062c, 0x0000064a, 0x00000654, 0x0000062d, 0x0000064a, 0x00000654, 0x0000062e, 0x0000064a, 0x00000654, 0x00000645, 0x0000064a, 0x00000654, 0x00000647, 0x00000628, 0x0000062c, 0x00000628, 0x0000062d, 0x00000628, 0x0000062e, 0x00000628, 0x00000645, 0x00000628, 0x00000647, 0x0000062a, 0x0000062c, 0x0000062a, 0x0000062d, 0x0000062a, 0x0000062e, 0x0000062a, 0x00000645, 0x0000062a, 0x00000647, 0x0000062b, 0x00000645, 0x0000062c, 0x0000062d, 0x0000062c, 0x00000645, 0x0000062d, 0x0000062c, 0x0000062d, 0x00000645, 0x0000062e, 0x0000062c, 0x0000062e, 0x00000645, 0x00000633, 0x0000062c, 0x00000633, 0x0000062d, 0x00000633, 0x0000062e, 0x00000633, 0x00000645, 0x00000635, 0x0000062d, 0x00000635, 0x0000062e, 0x00000635, 0x00000645, 0x00000636, 0x0000062c, 0x00000636, 0x0000062d, 0x00000636, 0x0000062e, 0x00000636, 0x00000645, 0x00000637, 0x0000062d, 0x00000638, 0x00000645, 0x00000639, 0x0000062c, 0x00000639, 0x00000645, 0x0000063a, 0x0000062c, 0x0000063a, 0x00000645, 0x00000641, 0x0000062c, 0x00000641, 0x0000062d, 0x00000641, 0x0000062e, 0x00000641, 0x00000645, 0x00000642, 0x0000062d, 0x00000642, 0x00000645, 0x00000643, 0x0000062c, 0x00000643, 0x0000062d, 0x00000643, 0x0000062e, 0x00000643, 0x00000644, 0x00000643, 0x00000645, 0x00000644, 0x0000062c, 0x00000644, 0x0000062d, 0x00000644, 0x0000062e, 0x00000644, 0x00000645, 0x00000644, 0x00000647, 0x00000645, 0x0000062c, 0x00000645, 0x0000062d, 0x00000645, 0x0000062e, 0x00000645, 0x00000645, 0x00000646, 0x0000062c, 0x00000646, 0x0000062d, 0x00000646, 0x0000062e, 0x00000646, 0x00000645, 0x00000646, 0x00000647, 0x00000647, 0x0000062c, 0x00000647, 0x00000645, 0x00000647, 0x00000670, 0x0000064a, 0x0000062c, 0x0000064a, 0x0000062d, 0x0000064a, 0x0000062e, 0x0000064a, 0x00000645, 0x0000064a, 0x00000647, 0x0000064a, 0x00000654, 0x00000645, 0x0000064a, 0x00000654, 0x00000647, 0x00000628, 0x00000645, 0x00000628, 0x00000647, 0x0000062a, 0x00000645, 0x0000062a, 0x00000647, 0x0000062b, 0x00000645, 0x0000062b, 0x00000647, 0x00000633, 0x00000645, 0x00000633, 0x00000647, 0x00000634, 0x00000645, 0x00000634, 0x00000647, 0x00000643, 0x00000644, 0x00000643, 0x00000645, 0x00000644, 0x00000645, 0x00000646, 0x00000645, 0x00000646, 0x00000647, 0x0000064a, 0x00000645, 0x0000064a, 0x00000647, 0x00000640, 0x0000064e, 0x00000651, 0x00000640, 0x0000064f, 0x00000651, 0x00000640, 0x00000650, 0x00000651, 0x00000637, 0x00000649, 0x00000637, 0x0000064a, 0x00000639, 0x00000649, 0x00000639, 0x0000064a, 0x0000063a, 0x00000649, 0x0000063a, 0x0000064a, 0x00000633, 0x00000649, 0x00000633, 0x0000064a, 0x00000634, 0x00000649, 0x00000634, 0x0000064a, 0x0000062d, 0x00000649, 0x0000062d, 0x0000064a, 0x0000062c, 0x00000649, 0x0000062c, 0x0000064a, 0x0000062e, 0x00000649, 0x0000062e, 0x0000064a, 0x00000635, 0x00000649, 0x00000635, 0x0000064a, 0x00000636, 0x00000649, 0x00000636, 0x0000064a, 0x00000634, 0x0000062c, 0x00000634, 0x0000062d, 0x00000634, 0x0000062e, 0x00000634, 0x00000645, 0x00000634, 0x00000631, 0x00000633, 0x00000631, 0x00000635, 0x00000631, 0x00000636, 0x00000631, 0x00000637, 0x00000649, 0x00000637, 0x0000064a, 0x00000639, 0x00000649, 0x00000639, 0x0000064a, 0x0000063a, 0x00000649, 0x0000063a, 0x0000064a, 0x00000633, 0x00000649, 0x00000633, 0x0000064a, 0x00000634, 0x00000649, 0x00000634, 0x0000064a, 0x0000062d, 0x00000649, 0x0000062d, 0x0000064a, 0x0000062c, 0x00000649, 0x0000062c, 0x0000064a, 0x0000062e, 0x00000649, 0x0000062e, 0x0000064a, 0x00000635, 0x00000649, 0x00000635, 0x0000064a, 0x00000636, 0x00000649, 0x00000636, 0x0000064a, 0x00000634, 0x0000062c, 0x00000634, 0x0000062d, 0x00000634, 0x0000062e, 0x00000634, 0x00000645, 0x00000634, 0x00000631, 0x00000633, 0x00000631, 0x00000635, 0x00000631, 0x00000636, 0x00000631, 0x00000634, 0x0000062c, 0x00000634, 0x0000062d, 0x00000634, 0x0000062e, 0x00000634, 0x00000645, 0x00000633, 0x00000647, 0x00000634, 0x00000647, 0x00000637, 0x00000645, 0x00000633, 0x0000062c, 0x00000633, 0x0000062d, 0x00000633, 0x0000062e, 0x00000634, 0x0000062c, 0x00000634, 0x0000062d, 0x00000634, 0x0000062e, 0x00000637, 0x00000645, 0x00000638, 0x00000645, 0x00000627, 0x0000064b, 0x00000627, 0x0000064b, 0x0000062a, 0x0000062c, 0x00000645, 0x0000062a, 0x0000062d, 0x0000062c, 0x0000062a, 0x0000062d, 0x0000062c, 0x0000062a, 0x0000062d, 0x00000645, 0x0000062a, 0x0000062e, 0x00000645, 0x0000062a, 0x00000645, 0x0000062c, 0x0000062a, 0x00000645, 0x0000062d, 0x0000062a, 0x00000645, 0x0000062e, 0x0000062c, 0x00000645, 0x0000062d, 0x0000062c, 0x00000645, 0x0000062d, 0x0000062d, 0x00000645, 0x0000064a, 0x0000062d, 0x00000645, 0x00000649, 0x00000633, 0x0000062d, 0x0000062c, 0x00000633, 0x0000062c, 0x0000062d, 0x00000633, 0x0000062c, 0x00000649, 0x00000633, 0x00000645, 0x0000062d, 0x00000633, 0x00000645, 0x0000062d, 0x00000633, 0x00000645, 0x0000062c, 0x00000633, 0x00000645, 0x00000645, 0x00000633, 0x00000645, 0x00000645, 0x00000635, 0x0000062d, 0x0000062d, 0x00000635, 0x0000062d, 0x0000062d, 0x00000635, 0x00000645, 0x00000645, 0x00000634, 0x0000062d, 0x00000645, 0x00000634, 0x0000062d, 0x00000645, 0x00000634, 0x0000062c, 0x0000064a, 0x00000634, 0x00000645, 0x0000062e, 0x00000634, 0x00000645, 0x0000062e, 0x00000634, 0x00000645, 0x00000645, 0x00000634, 0x00000645, 0x00000645, 0x00000636, 0x0000062d, 0x00000649, 0x00000636, 0x0000062e, 0x00000645, 0x00000636, 0x0000062e, 0x00000645, 0x00000637, 0x00000645, 0x0000062d, 0x00000637, 0x00000645, 0x0000062d, 0x00000637, 0x00000645, 0x00000645, 0x00000637, 0x00000645, 0x0000064a, 0x00000639, 0x0000062c, 0x00000645, 0x00000639, 0x00000645, 0x00000645, 0x00000639, 0x00000645, 0x00000645, 0x00000639, 0x00000645, 0x00000649, 0x0000063a, 0x00000645, 0x00000645, 0x0000063a, 0x00000645, 0x0000064a, 0x0000063a, 0x00000645, 0x00000649, 0x00000641, 0x0000062e, 0x00000645, 0x00000641, 0x0000062e, 0x00000645, 0x00000642, 0x00000645, 0x0000062d, 0x00000642, 0x00000645, 0x00000645, 0x00000644, 0x0000062d, 0x00000645, 0x00000644, 0x0000062d, 0x0000064a, 0x00000644, 0x0000062d, 0x00000649, 0x00000644, 0x0000062c, 0x0000062c, 0x00000644, 0x0000062c, 0x0000062c, 0x00000644, 0x0000062e, 0x00000645, 0x00000644, 0x0000062e, 0x00000645, 0x00000644, 0x00000645, 0x0000062d, 0x00000644, 0x00000645, 0x0000062d, 0x00000645, 0x0000062d, 0x0000062c, 0x00000645, 0x0000062d, 0x00000645, 0x00000645, 0x0000062d, 0x0000064a, 0x00000645, 0x0000062c, 0x0000062d, 0x00000645, 0x0000062c, 0x00000645, 0x00000645, 0x0000062e, 0x0000062c, 0x00000645, 0x0000062e, 0x00000645, 0x00000645, 0x0000062c, 0x0000062e, 0x00000647, 0x00000645, 0x0000062c, 0x00000647, 0x00000645, 0x00000645, 0x00000646, 0x0000062d, 0x00000645, 0x00000646, 0x0000062d, 0x00000649, 0x00000646, 0x0000062c, 0x00000645, 0x00000646, 0x0000062c, 0x00000645, 0x00000646, 0x0000062c, 0x00000649, 0x00000646, 0x00000645, 0x0000064a, 0x00000646, 0x00000645, 0x00000649, 0x0000064a, 0x00000645, 0x00000645, 0x0000064a, 0x00000645, 0x00000645, 0x00000628, 0x0000062e, 0x0000064a, 0x0000062a, 0x0000062c, 0x0000064a, 0x0000062a, 0x0000062c, 0x00000649, 0x0000062a, 0x0000062e, 0x0000064a, 0x0000062a, 0x0000062e, 0x00000649, 0x0000062a, 0x00000645, 0x0000064a, 0x0000062a, 0x00000645, 0x00000649, 0x0000062c, 0x00000645, 0x0000064a, 0x0000062c, 0x0000062d, 0x00000649, 0x0000062c, 0x00000645, 0x00000649, 0x00000633, 0x0000062e, 0x00000649, 0x00000635, 0x0000062d, 0x0000064a, 0x00000634, 0x0000062d, 0x0000064a, 0x00000636, 0x0000062d, 0x0000064a, 0x00000644, 0x0000062c, 0x0000064a, 0x00000644, 0x00000645, 0x0000064a, 0x0000064a, 0x0000062d, 0x0000064a, 0x0000064a, 0x0000062c, 0x0000064a, 0x0000064a, 0x00000645, 0x0000064a, 0x00000645, 0x00000645, 0x0000064a, 0x00000642, 0x00000645, 0x0000064a, 0x00000646, 0x0000062d, 0x0000064a, 0x00000642, 0x00000645, 0x0000062d, 0x00000644, 0x0000062d, 0x00000645, 0x00000639, 0x00000645, 0x0000064a, 0x00000643, 0x00000645, 0x0000064a, 0x00000646, 0x0000062c, 0x0000062d, 0x00000645, 0x0000062e, 0x0000064a, 0x00000644, 0x0000062c, 0x00000645, 0x00000643, 0x00000645, 0x00000645, 0x00000644, 0x0000062c, 0x00000645, 0x00000646, 0x0000062c, 0x0000062d, 0x0000062c, 0x0000062d, 0x0000064a, 0x0000062d, 0x0000062c, 0x0000064a, 0x00000645, 0x0000062c, 0x0000064a, 0x00000641, 0x00000645, 0x0000064a, 0x00000628, 0x0000062d, 0x0000064a, 0x00000643, 0x00000645, 0x00000645, 0x00000639, 0x0000062c, 0x00000645, 0x00000635, 0x00000645, 0x00000645, 0x00000633, 0x0000062e, 0x0000064a, 0x00000646, 0x0000062c, 0x0000064a, 0x00000635, 0x00000644, 0x000006d2, 0x00000642, 0x00000644, 0x000006d2, 0x00000627, 0x00000644, 0x00000644, 0x00000647, 0x00000627, 0x00000643, 0x00000628, 0x00000631, 0x00000645, 0x0000062d, 0x00000645, 0x0000062f, 0x00000635, 0x00000644, 0x00000639, 0x00000645, 0x00000631, 0x00000633, 0x00000648, 0x00000644, 0x00000639, 0x00000644, 0x0000064a, 0x00000647, 0x00000648, 0x00000633, 0x00000644, 0x00000645, 0x00000635, 0x00000644, 0x00000649, 0x00000635, 0x00000644, 0x00000649, 0x00000020, 0x00000627, 0x00000644, 0x00000644, 0x00000647, 0x00000020, 0x00000639, 0x00000644, 0x0000064a, 0x00000647, 0x00000020, 0x00000648, 0x00000633, 0x00000644, 0x00000645, 0x0000062c, 0x00000644, 0x00000020, 0x0000062c, 0x00000644, 0x00000627, 0x00000644, 0x00000647, 0x00000631, 0x000006cc, 0x00000627, 0x00000644, 0x0000002e, 0x0000002e, 0x00002014, 0x00002013, 0x0000005f, 0x0000005f, 0x00000028, 0x00000029, 0x0000007b, 0x0000007d, 0x00003014, 0x00003015, 0x00003010, 0x00003011, 0x0000300a, 0x0000300b, 0x00003008, 0x00003009, 0x0000300c, 0x0000300d, 0x0000300e, 0x0000300f, 0x00000020, 0x00000305, 0x00000020, 0x00000305, 0x00000020, 0x00000305, 0x00000020, 0x00000305, 0x0000005f, 0x0000005f, 0x0000005f, 0x0000002c, 0x00003001, 0x0000002e, 0x0000003b, 0x0000003a, 0x0000003f, 0x00000021, 0x00002014, 0x00000028, 0x00000029, 0x0000007b, 0x0000007d, 0x00003014, 0x00003015, 0x00000023, 0x00000026, 0x0000002a, 0x0000002b, 0x0000002d, 0x0000003c, 0x0000003e, 0x0000003d, 0x0000005c, 0x00000024, 0x00000025, 0x00000040, 0x00000020, 0x0000064b, 0x00000640, 0x0000064b, 0x00000020, 0x0000064c, 0x00000020, 0x0000064d, 0x00000020, 0x0000064e, 0x00000640, 0x0000064e, 0x00000020, 0x0000064f, 0x00000640, 0x0000064f, 0x00000020, 0x00000650, 0x00000640, 0x00000650, 0x00000020, 0x00000651, 0x00000640, 0x00000651, 0x00000020, 0x00000652, 0x00000640, 0x00000652, 0x00000621, 0x00000627, 0x00000653, 0x00000627, 0x00000653, 0x00000627, 0x00000654, 0x00000627, 0x00000654, 0x00000648, 0x00000654, 0x00000648, 0x00000654, 0x00000627, 0x00000655, 0x00000627, 0x00000655, 0x0000064a, 0x00000654, 0x0000064a, 0x00000654, 0x0000064a, 0x00000654, 0x0000064a, 0x00000654, 0x00000627, 0x00000627, 0x00000628, 0x00000628, 0x00000628, 0x00000628, 0x00000629, 0x00000629, 0x0000062a, 0x0000062a, 0x0000062a, 0x0000062a, 0x0000062b, 0x0000062b, 0x0000062b, 0x0000062b, 0x0000062c, 0x0000062c, 0x0000062c, 0x0000062c, 0x0000062d, 0x0000062d, 0x0000062d, 0x0000062d, 0x0000062e, 0x0000062e, 0x0000062e, 0x0000062e, 0x0000062f, 0x0000062f, 0x00000630, 0x00000630, 0x00000631, 0x00000631, 0x00000632, 0x00000632, 0x00000633, 0x00000633, 0x00000633, 0x00000633, 0x00000634, 0x00000634, 0x00000634, 0x00000634, 0x00000635, 0x00000635, 0x00000635, 0x00000635, 0x00000636, 0x00000636, 0x00000636, 0x00000636, 0x00000637, 0x00000637, 0x00000637, 0x00000637, 0x00000638, 0x00000638, 0x00000638, 0x00000638, 0x00000639, 0x00000639, 0x00000639, 0x00000639, 0x0000063a, 0x0000063a, 0x0000063a, 0x0000063a, 0x00000641, 0x00000641, 0x00000641, 0x00000641, 0x00000642, 0x00000642, 0x00000642, 0x00000642, 0x00000643, 0x00000643, 0x00000643, 0x00000643, 0x00000644, 0x00000644, 0x00000644, 0x00000644, 0x00000645, 0x00000645, 0x00000645, 0x00000645, 0x00000646, 0x00000646, 0x00000646, 0x00000646, 0x00000647, 0x00000647, 0x00000647, 0x00000647, 0x00000648, 0x00000648, 0x00000649, 0x00000649, 0x0000064a, 0x0000064a, 0x0000064a, 0x0000064a, 0x00000644, 0x00000627, 0x00000653, 0x00000644, 0x00000627, 0x00000653, 0x00000644, 0x00000627, 0x00000654, 0x00000644, 0x00000627, 0x00000654, 0x00000644, 0x00000627, 0x00000655, 0x00000644, 0x00000627, 0x00000655, 0x00000644, 0x00000627, 0x00000644, 0x00000627, 0x00000021, 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x00000026, 0x00000027, 0x00000028, 0x00000029, 0x0000002a, 0x0000002b, 0x0000002c, 0x0000002d, 0x0000002e, 0x0000002f, 0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x00000034, 0x00000035, 0x00000036, 0x00000037, 0x00000038, 0x00000039, 0x0000003a, 0x0000003b, 0x0000003c, 0x0000003d, 0x0000003e, 0x0000003f, 0x00000040, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 0x00000048, 0x00000049, 0x0000004a, 0x0000004b, 0x0000004c, 0x0000004d, 0x0000004e, 0x0000004f, 0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 0x00000058, 0x00000059, 0x0000005a, 0x0000005b, 0x0000005c, 0x0000005d, 0x0000005e, 0x0000005f, 0x00000060, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x00000069, 0x0000006a, 0x0000006b, 0x0000006c, 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 0x00000078, 0x00000079, 0x0000007a, 0x0000007b, 0x0000007c, 0x0000007d, 0x0000007e, 0x00002985, 0x00002986, 0x00003002, 0x0000300c, 0x0000300d, 0x00003001, 0x000030fb, 0x000030f2, 0x000030a1, 0x000030a3, 0x000030a5, 0x000030a7, 0x000030a9, 0x000030e3, 0x000030e5, 0x000030e7, 0x000030c3, 0x000030fc, 0x000030a2, 0x000030a4, 0x000030a6, 0x000030a8, 0x000030aa, 0x000030ab, 0x000030ad, 0x000030af, 0x000030b1, 0x000030b3, 0x000030b5, 0x000030b7, 0x000030b9, 0x000030bb, 0x000030bd, 0x000030bf, 0x000030c1, 0x000030c4, 0x000030c6, 0x000030c8, 0x000030ca, 0x000030cb, 0x000030cc, 0x000030cd, 0x000030ce, 0x000030cf, 0x000030d2, 0x000030d5, 0x000030d8, 0x000030db, 0x000030de, 0x000030df, 0x000030e0, 0x000030e1, 0x000030e2, 0x000030e4, 0x000030e6, 0x000030e8, 0x000030e9, 0x000030ea, 0x000030eb, 0x000030ec, 0x000030ed, 0x000030ef, 0x000030f3, 0x00003099, 0x0000309a, 0x00001160, 0x00001100, 0x00001101, 0x000011aa, 0x00001102, 0x000011ac, 0x000011ad, 0x00001103, 0x00001104, 0x00001105, 0x000011b0, 0x000011b1, 0x000011b2, 0x000011b3, 0x000011b4, 0x000011b5, 0x0000111a, 0x00001106, 0x00001107, 0x00001108, 0x00001121, 0x00001109, 0x0000110a, 0x0000110b, 0x0000110c, 0x0000110d, 0x0000110e, 0x0000110f, 0x00001110, 0x00001111, 0x00001112, 0x00001161, 0x00001162, 0x00001163, 0x00001164, 0x00001165, 0x00001166, 0x00001167, 0x00001168, 0x00001169, 0x0000116a, 0x0000116b, 0x0000116c, 0x0000116d, 0x0000116e, 0x0000116f, 0x00001170, 0x00001171, 0x00001172, 0x00001173, 0x00001174, 0x00001175, 0x000000a2, 0x000000a3, 0x000000ac, 0x00000020, 0x00000304, 0x000000a6, 0x000000a5, 0x000020a9, 0x00002502, 0x00002190, 0x00002191, 0x00002192, 0x00002193, 0x000025a0, 0x000025cb, 0x0001d157, 0x0001d165, 0x0001d158, 0x0001d165, 0x0001d158, 0x0001d165, 0x0001d16e, 0x0001d158, 0x0001d165, 0x0001d16f, 0x0001d158, 0x0001d165, 0x0001d170, 0x0001d158, 0x0001d165, 0x0001d171, 0x0001d158, 0x0001d165, 0x0001d172, 0x0001d1b9, 0x0001d165, 0x0001d1ba, 0x0001d165, 0x0001d1b9, 0x0001d165, 0x0001d16e, 0x0001d1ba, 0x0001d165, 0x0001d16e, 0x0001d1b9, 0x0001d165, 0x0001d16f, 0x0001d1ba, 0x0001d165, 0x0001d16f, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 0x00000048, 0x00000049, 0x0000004a, 0x0000004b, 0x0000004c, 0x0000004d, 0x0000004e, 0x0000004f, 0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 0x00000058, 0x00000059, 0x0000005a, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x00000069, 0x0000006a, 0x0000006b, 0x0000006c, 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 0x00000078, 0x00000079, 0x0000007a, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 0x00000048, 0x00000049, 0x0000004a, 0x0000004b, 0x0000004c, 0x0000004d, 0x0000004e, 0x0000004f, 0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 0x00000058, 0x00000059, 0x0000005a, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 0x00000069, 0x0000006a, 0x0000006b, 0x0000006c, 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 0x00000078, 0x00000079, 0x0000007a, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 0x00000048, 0x00000049, 0x0000004a, 0x0000004b, 0x0000004c, 0x0000004d, 0x0000004e, 0x0000004f, 0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 0x00000058, 0x00000059, 0x0000005a, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x00000069, 0x0000006a, 0x0000006b, 0x0000006c, 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 0x00000078, 0x00000079, 0x0000007a, 0x00000041, 0x00000043, 0x00000044, 0x00000047, 0x0000004a, 0x0000004b, 0x0000004e, 0x0000004f, 0x00000050, 0x00000051, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 0x00000058, 0x00000059, 0x0000005a, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000066, 0x00000068, 0x00000069, 0x0000006a, 0x0000006b, 0x0000006d, 0x0000006e, 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 0x00000078, 0x00000079, 0x0000007a, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 0x00000048, 0x00000049, 0x0000004a, 0x0000004b, 0x0000004c, 0x0000004d, 0x0000004e, 0x0000004f, 0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 0x00000058, 0x00000059, 0x0000005a, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x00000069, 0x0000006a, 0x0000006b, 0x0000006c, 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 0x00000078, 0x00000079, 0x0000007a, 0x00000041, 0x00000042, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 0x0000004a, 0x0000004b, 0x0000004c, 0x0000004d, 0x0000004e, 0x0000004f, 0x00000050, 0x00000051, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 0x00000058, 0x00000059, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x00000069, 0x0000006a, 0x0000006b, 0x0000006c, 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 0x00000078, 0x00000079, 0x0000007a, 0x00000041, 0x00000042, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 0x00000049, 0x0000004a, 0x0000004b, 0x0000004c, 0x0000004d, 0x0000004f, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 0x00000058, 0x00000059, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x00000069, 0x0000006a, 0x0000006b, 0x0000006c, 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 0x00000078, 0x00000079, 0x0000007a, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 0x00000048, 0x00000049, 0x0000004a, 0x0000004b, 0x0000004c, 0x0000004d, 0x0000004e, 0x0000004f, 0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 0x00000058, 0x00000059, 0x0000005a, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x00000069, 0x0000006a, 0x0000006b, 0x0000006c, 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 0x00000078, 0x00000079, 0x0000007a, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 0x00000048, 0x00000049, 0x0000004a, 0x0000004b, 0x0000004c, 0x0000004d, 0x0000004e, 0x0000004f, 0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 0x00000058, 0x00000059, 0x0000005a, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x00000069, 0x0000006a, 0x0000006b, 0x0000006c, 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 0x00000078, 0x00000079, 0x0000007a, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 0x00000048, 0x00000049, 0x0000004a, 0x0000004b, 0x0000004c, 0x0000004d, 0x0000004e, 0x0000004f, 0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 0x00000058, 0x00000059, 0x0000005a, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x00000069, 0x0000006a, 0x0000006b, 0x0000006c, 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 0x00000078, 0x00000079, 0x0000007a, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 0x00000048, 0x00000049, 0x0000004a, 0x0000004b, 0x0000004c, 0x0000004d, 0x0000004e, 0x0000004f, 0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 0x00000058, 0x00000059, 0x0000005a, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x00000069, 0x0000006a, 0x0000006b, 0x0000006c, 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 0x00000078, 0x00000079, 0x0000007a, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 0x00000048, 0x00000049, 0x0000004a, 0x0000004b, 0x0000004c, 0x0000004d, 0x0000004e, 0x0000004f, 0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 0x00000058, 0x00000059, 0x0000005a, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x00000069, 0x0000006a, 0x0000006b, 0x0000006c, 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 0x00000078, 0x00000079, 0x0000007a, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 0x00000048, 0x00000049, 0x0000004a, 0x0000004b, 0x0000004c, 0x0000004d, 0x0000004e, 0x0000004f, 0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 0x00000058, 0x00000059, 0x0000005a, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x00000069, 0x0000006a, 0x0000006b, 0x0000006c, 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 0x00000078, 0x00000079, 0x0000007a, 0x00000391, 0x00000392, 0x00000393, 0x00000394, 0x00000395, 0x00000396, 0x00000397, 0x00000398, 0x00000399, 0x0000039a, 0x0000039b, 0x0000039c, 0x0000039d, 0x0000039e, 0x0000039f, 0x000003a0, 0x000003a1, 0x00000398, 0x000003a3, 0x000003a4, 0x000003a5, 0x000003a6, 0x000003a7, 0x000003a8, 0x000003a9, 0x00002207, 0x000003b1, 0x000003b2, 0x000003b3, 0x000003b4, 0x000003b5, 0x000003b6, 0x000003b7, 0x000003b8, 0x000003b9, 0x000003ba, 0x000003bb, 0x000003bc, 0x000003bd, 0x000003be, 0x000003bf, 0x000003c0, 0x000003c1, 0x000003c2, 0x000003c3, 0x000003c4, 0x000003c5, 0x000003c6, 0x000003c7, 0x000003c8, 0x000003c9, 0x00002202, 0x000003b5, 0x000003b8, 0x000003ba, 0x000003c6, 0x000003c1, 0x000003c0, 0x00000391, 0x00000392, 0x00000393, 0x00000394, 0x00000395, 0x00000396, 0x00000397, 0x00000398, 0x00000399, 0x0000039a, 0x0000039b, 0x0000039c, 0x0000039d, 0x0000039e, 0x0000039f, 0x000003a0, 0x000003a1, 0x00000398, 0x000003a3, 0x000003a4, 0x000003a5, 0x000003a6, 0x000003a7, 0x000003a8, 0x000003a9, 0x00002207, 0x000003b1, 0x000003b2, 0x000003b3, 0x000003b4, 0x000003b5, 0x000003b6, 0x000003b7, 0x000003b8, 0x000003b9, 0x000003ba, 0x000003bb, 0x000003bc, 0x000003bd, 0x000003be, 0x000003bf, 0x000003c0, 0x000003c1, 0x000003c2, 0x000003c3, 0x000003c4, 0x000003c5, 0x000003c6, 0x000003c7, 0x000003c8, 0x000003c9, 0x00002202, 0x000003b5, 0x000003b8, 0x000003ba, 0x000003c6, 0x000003c1, 0x000003c0, 0x00000391, 0x00000392, 0x00000393, 0x00000394, 0x00000395, 0x00000396, 0x00000397, 0x00000398, 0x00000399, 0x0000039a, 0x0000039b, 0x0000039c, 0x0000039d, 0x0000039e, 0x0000039f, 0x000003a0, 0x000003a1, 0x00000398, 0x000003a3, 0x000003a4, 0x000003a5, 0x000003a6, 0x000003a7, 0x000003a8, 0x000003a9, 0x00002207, 0x000003b1, 0x000003b2, 0x000003b3, 0x000003b4, 0x000003b5, 0x000003b6, 0x000003b7, 0x000003b8, 0x000003b9, 0x000003ba, 0x000003bb, 0x000003bc, 0x000003bd, 0x000003be, 0x000003bf, 0x000003c0, 0x000003c1, 0x000003c2, 0x000003c3, 0x000003c4, 0x000003c5, 0x000003c6, 0x000003c7, 0x000003c8, 0x000003c9, 0x00002202, 0x000003b5, 0x000003b8, 0x000003ba, 0x000003c6, 0x000003c1, 0x000003c0, 0x00000391, 0x00000392, 0x00000393, 0x00000394, 0x00000395, 0x00000396, 0x00000397, 0x00000398, 0x00000399, 0x0000039a, 0x0000039b, 0x0000039c, 0x0000039d, 0x0000039e, 0x0000039f, 0x000003a0, 0x000003a1, 0x00000398, 0x000003a3, 0x000003a4, 0x000003a5, 0x000003a6, 0x000003a7, 0x000003a8, 0x000003a9, 0x00002207, 0x000003b1, 0x000003b2, 0x000003b3, 0x000003b4, 0x000003b5, 0x000003b6, 0x000003b7, 0x000003b8, 0x000003b9, 0x000003ba, 0x000003bb, 0x000003bc, 0x000003bd, 0x000003be, 0x000003bf, 0x000003c0, 0x000003c1, 0x000003c2, 0x000003c3, 0x000003c4, 0x000003c5, 0x000003c6, 0x000003c7, 0x000003c8, 0x000003c9, 0x00002202, 0x000003b5, 0x000003b8, 0x000003ba, 0x000003c6, 0x000003c1, 0x000003c0, 0x00000391, 0x00000392, 0x00000393, 0x00000394, 0x00000395, 0x00000396, 0x00000397, 0x00000398, 0x00000399, 0x0000039a, 0x0000039b, 0x0000039c, 0x0000039d, 0x0000039e, 0x0000039f, 0x000003a0, 0x000003a1, 0x00000398, 0x000003a3, 0x000003a4, 0x000003a5, 0x000003a6, 0x000003a7, 0x000003a8, 0x000003a9, 0x00002207, 0x000003b1, 0x000003b2, 0x000003b3, 0x000003b4, 0x000003b5, 0x000003b6, 0x000003b7, 0x000003b8, 0x000003b9, 0x000003ba, 0x000003bb, 0x000003bc, 0x000003bd, 0x000003be, 0x000003bf, 0x000003c0, 0x000003c1, 0x000003c2, 0x000003c3, 0x000003c4, 0x000003c5, 0x000003c6, 0x000003c7, 0x000003c8, 0x000003c9, 0x00002202, 0x000003b5, 0x000003b8, 0x000003ba, 0x000003c6, 0x000003c1, 0x000003c0, 0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x00000034, 0x00000035, 0x00000036, 0x00000037, 0x00000038, 0x00000039, 0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x00000034, 0x00000035, 0x00000036, 0x00000037, 0x00000038, 0x00000039, 0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x00000034, 0x00000035, 0x00000036, 0x00000037, 0x00000038, 0x00000039, 0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x00000034, 0x00000035, 0x00000036, 0x00000037, 0x00000038, 0x00000039, 0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x00000034, 0x00000035, 0x00000036, 0x00000037, 0x00000038, 0x00000039, 0x00004e3d, 0x00004e38, 0x00004e41, 0x00020122, 0x00004f60, 0x00004fae, 0x00004fbb, 0x00005002, 0x0000507a, 0x00005099, 0x000050e7, 0x000050cf, 0x0000349e, 0x0002063a, 0x0000514d, 0x00005154, 0x00005164, 0x00005177, 0x0002051c, 0x000034b9, 0x00005167, 0x0000518d, 0x0002054b, 0x00005197, 0x000051a4, 0x00004ecc, 0x000051ac, 0x000051b5, 0x000291df, 0x000051f5, 0x00005203, 0x000034df, 0x0000523b, 0x00005246, 0x00005272, 0x00005277, 0x00003515, 0x000052c7, 0x000052c9, 0x000052e4, 0x000052fa, 0x00005305, 0x00005306, 0x00005317, 0x00005349, 0x00005351, 0x0000535a, 0x00005373, 0x0000537d, 0x0000537f, 0x0000537f, 0x0000537f, 0x00020a2c, 0x00007070, 0x000053ca, 0x000053df, 0x00020b63, 0x000053eb, 0x000053f1, 0x00005406, 0x0000549e, 0x00005438, 0x00005448, 0x00005468, 0x000054a2, 0x000054f6, 0x00005510, 0x00005553, 0x00005563, 0x00005584, 0x00005584, 0x00005599, 0x000055ab, 0x000055b3, 0x000055c2, 0x00005716, 0x00005606, 0x00005717, 0x00005651, 0x00005674, 0x00005207, 0x000058ee, 0x000057ce, 0x000057f4, 0x0000580d, 0x0000578b, 0x00005832, 0x00005831, 0x000058ac, 0x000214e4, 0x000058f2, 0x000058f7, 0x00005906, 0x0000591a, 0x00005922, 0x00005962, 0x000216a8, 0x000216ea, 0x000059ec, 0x00005a1b, 0x00005a27, 0x000059d8, 0x00005a66, 0x000036ee, 0x0002136a, 0x00005b08, 0x00005b3e, 0x00005b3e, 0x000219c8, 0x00005bc3, 0x00005bd8, 0x00005be7, 0x00005bf3, 0x00021b18, 0x00005bff, 0x00005c06, 0x00005f33, 0x00005c22, 0x00003781, 0x00005c60, 0x00005c6e, 0x00005cc0, 0x00005c8d, 0x00021de4, 0x00005d43, 0x00021de6, 0x00005d6e, 0x00005d6b, 0x00005d7c, 0x00005de1, 0x00005de2, 0x0000382f, 0x00005dfd, 0x00005e28, 0x00005e3d, 0x00005e69, 0x00003862, 0x00022183, 0x0000387c, 0x00005eb0, 0x00005eb3, 0x00005eb6, 0x00005eca, 0x0002a392, 0x00005efe, 0x00022331, 0x00022331, 0x00008201, 0x00005f22, 0x00005f22, 0x000038c7, 0x000232b8, 0x000261da, 0x00005f62, 0x00005f6b, 0x000038e3, 0x00005f9a, 0x00005fcd, 0x00005fd7, 0x00005ff9, 0x00006081, 0x0000393a, 0x0000391c, 0x00006094, 0x000226d4, 0x000060c7, 0x00006148, 0x0000614c, 0x0000614e, 0x0000614c, 0x0000617a, 0x0000618e, 0x000061b2, 0x000061a4, 0x000061af, 0x000061de, 0x000061f2, 0x000061f6, 0x00006210, 0x0000621b, 0x0000625d, 0x000062b1, 0x000062d4, 0x00006350, 0x00022b0c, 0x0000633d, 0x000062fc, 0x00006368, 0x00006383, 0x000063e4, 0x00022bf1, 0x00006422, 0x000063c5, 0x000063a9, 0x00003a2e, 0x00006469, 0x0000647e, 0x0000649d, 0x00006477, 0x00003a6c, 0x0000654f, 0x0000656c, 0x0002300a, 0x000065e3, 0x000066f8, 0x00006649, 0x00003b19, 0x00006691, 0x00003b08, 0x00003ae4, 0x00005192, 0x00005195, 0x00006700, 0x0000669c, 0x000080ad, 0x000043d9, 0x00006717, 0x0000671b, 0x00006721, 0x0000675e, 0x00006753, 0x000233c3, 0x00003b49, 0x000067fa, 0x00006785, 0x00006852, 0x00006885, 0x0002346d, 0x0000688e, 0x0000681f, 0x00006914, 0x00003b9d, 0x00006942, 0x000069a3, 0x000069ea, 0x00006aa8, 0x000236a3, 0x00006adb, 0x00003c18, 0x00006b21, 0x000238a7, 0x00006b54, 0x00003c4e, 0x00006b72, 0x00006b9f, 0x00006bba, 0x00006bbb, 0x00023a8d, 0x00021d0b, 0x00023afa, 0x00006c4e, 0x00023cbc, 0x00006cbf, 0x00006ccd, 0x00006c67, 0x00006d16, 0x00006d3e, 0x00006d77, 0x00006d41, 0x00006d69, 0x00006d78, 0x00006d85, 0x00023d1e, 0x00006d34, 0x00006e2f, 0x00006e6e, 0x00003d33, 0x00006ecb, 0x00006ec7, 0x00023ed1, 0x00006df9, 0x00006f6e, 0x00023f5e, 0x00023f8e, 0x00006fc6, 0x00007039, 0x0000701e, 0x0000701b, 0x00003d96, 0x0000704a, 0x0000707d, 0x00007077, 0x000070ad, 0x00020525, 0x00007145, 0x00024263, 0x0000719c, 0x000043ab, 0x00007228, 0x00007235, 0x00007250, 0x00024608, 0x00007280, 0x00007295, 0x00024735, 0x00024814, 0x0000737a, 0x0000738b, 0x00003eac, 0x000073a5, 0x00003eb8, 0x00003eb8, 0x00007447, 0x0000745c, 0x00007471, 0x00007485, 0x000074ca, 0x00003f1b, 0x00007524, 0x00024c36, 0x0000753e, 0x00024c92, 0x00007570, 0x0002219f, 0x00007610, 0x00024fa1, 0x00024fb8, 0x00025044, 0x00003ffc, 0x00004008, 0x000076f4, 0x000250f3, 0x000250f2, 0x00025119, 0x00025133, 0x0000771e, 0x0000771f, 0x0000771f, 0x0000774a, 0x00004039, 0x0000778b, 0x00004046, 0x00004096, 0x0002541d, 0x0000784e, 0x0000788c, 0x000078cc, 0x000040e3, 0x00025626, 0x00007956, 0x0002569a, 0x000256c5, 0x0000798f, 0x000079eb, 0x0000412f, 0x00007a40, 0x00007a4a, 0x00007a4f, 0x0002597c, 0x00025aa7, 0x00025aa7, 0x00007aae, 0x00004202, 0x00025bab, 0x00007bc6, 0x00007bc9, 0x00004227, 0x00025c80, 0x00007cd2, 0x000042a0, 0x00007ce8, 0x00007ce3, 0x00007d00, 0x00025f86, 0x00007d63, 0x00004301, 0x00007dc7, 0x00007e02, 0x00007e45, 0x00004334, 0x00026228, 0x00026247, 0x00004359, 0x000262d9, 0x00007f7a, 0x0002633e, 0x00007f95, 0x00007ffa, 0x00008005, 0x000264da, 0x00026523, 0x00008060, 0x000265a8, 0x00008070, 0x0002335f, 0x000043d5, 0x000080b2, 0x00008103, 0x0000440b, 0x0000813e, 0x00005ab5, 0x000267a7, 0x000267b5, 0x00023393, 0x0002339c, 0x00008201, 0x00008204, 0x00008f9e, 0x0000446b, 0x00008291, 0x0000828b, 0x0000829d, 0x000052b3, 0x000082b1, 0x000082b3, 0x000082bd, 0x000082e6, 0x00026b3c, 0x000082e5, 0x0000831d, 0x00008363, 0x000083ad, 0x00008323, 0x000083bd, 0x000083e7, 0x00008457, 0x00008353, 0x000083ca, 0x000083cc, 0x000083dc, 0x00026c36, 0x00026d6b, 0x00026cd5, 0x0000452b, 0x000084f1, 0x000084f3, 0x00008516, 0x000273ca, 0x00008564, 0x00026f2c, 0x0000455d, 0x00004561, 0x00026fb1, 0x000270d2, 0x0000456b, 0x00008650, 0x0000865c, 0x00008667, 0x00008669, 0x000086a9, 0x00008688, 0x0000870e, 0x000086e2, 0x00008779, 0x00008728, 0x0000876b, 0x00008786, 0x00004d57, 0x000087e1, 0x00008801, 0x000045f9, 0x00008860, 0x00008863, 0x00027667, 0x000088d7, 0x000088de, 0x00004635, 0x000088fa, 0x000034bb, 0x000278ae, 0x00027966, 0x000046be, 0x000046c7, 0x00008aa0, 0x00008aed, 0x00008b8a, 0x00008c55, 0x00027ca8, 0x00008cab, 0x00008cc1, 0x00008d1b, 0x00008d77, 0x00027f2f, 0x00020804, 0x00008dcb, 0x00008dbc, 0x00008df0, 0x000208de, 0x00008ed4, 0x00008f38, 0x000285d2, 0x000285ed, 0x00009094, 0x000090f1, 0x00009111, 0x0002872e, 0x0000911b, 0x00009238, 0x000092d7, 0x000092d8, 0x0000927c, 0x000093f9, 0x00009415, 0x00028bfa, 0x0000958b, 0x00004995, 0x000095b7, 0x00028d77, 0x000049e6, 0x000096c3, 0x00005db2, 0x00009723, 0x00029145, 0x0002921a, 0x00004a6e, 0x00004a76, 0x000097e0, 0x0002940a, 0x00004ab2, 0x00029496, 0x0000980b, 0x0000980b, 0x00009829, 0x000295b6, 0x000098e2, 0x00004b33, 0x00009929, 0x000099a7, 0x000099c2, 0x000099fe, 0x00004bce, 0x00029b30, 0x00009b12, 0x00009c40, 0x00009cfd, 0x00004cce, 0x00004ced, 0x00009d67, 0x0002a0ce, 0x00004cf8, 0x0002a105, 0x0002a20e, 0x0002a291, 0x00009ebb, 0x00004d56, 0x00009ef9, 0x00009efe, 0x00009f05, 0x00009f0f, 0x00009f16, 0x00009f3b, 0x0002a600 }; static const ac_uint4 _uccmcl_size = 489; static const ac_uint4 _uccmcl_nodes[] = { 0x00000300, 0x00000314, 0x000000e6, 0x00000315, 0x00000315, 0x000000e8, 0x00000316, 0x00000319, 0x000000dc, 0x0000031a, 0x0000031a, 0x000000e8, 0x0000031b, 0x0000031b, 0x000000d8, 0x0000031c, 0x00000320, 0x000000dc, 0x00000321, 0x00000322, 0x000000ca, 0x00000323, 0x00000326, 0x000000dc, 0x00000327, 0x00000328, 0x000000ca, 0x00000329, 0x00000333, 0x000000dc, 0x00000334, 0x00000338, 0x00000001, 0x00000339, 0x0000033c, 0x000000dc, 0x0000033d, 0x00000344, 0x000000e6, 0x00000345, 0x00000345, 0x000000f0, 0x00000346, 0x00000346, 0x000000e6, 0x00000347, 0x00000349, 0x000000dc, 0x0000034a, 0x0000034c, 0x000000e6, 0x0000034d, 0x0000034e, 0x000000dc, 0x00000360, 0x00000361, 0x000000ea, 0x00000362, 0x00000362, 0x000000e9, 0x00000363, 0x0000036f, 0x000000e6, 0x00000483, 0x00000486, 0x000000e6, 0x00000591, 0x00000591, 0x000000dc, 0x00000592, 0x00000595, 0x000000e6, 0x00000596, 0x00000596, 0x000000dc, 0x00000597, 0x00000599, 0x000000e6, 0x0000059a, 0x0000059a, 0x000000de, 0x0000059b, 0x0000059b, 0x000000dc, 0x0000059c, 0x000005a1, 0x000000e6, 0x000005a3, 0x000005a7, 0x000000dc, 0x000005a8, 0x000005a9, 0x000000e6, 0x000005aa, 0x000005aa, 0x000000dc, 0x000005ab, 0x000005ac, 0x000000e6, 0x000005ad, 0x000005ad, 0x000000de, 0x000005ae, 0x000005ae, 0x000000e4, 0x000005af, 0x000005af, 0x000000e6, 0x000005b0, 0x000005b0, 0x0000000a, 0x000005b1, 0x000005b1, 0x0000000b, 0x000005b2, 0x000005b2, 0x0000000c, 0x000005b3, 0x000005b3, 0x0000000d, 0x000005b4, 0x000005b4, 0x0000000e, 0x000005b5, 0x000005b5, 0x0000000f, 0x000005b6, 0x000005b6, 0x00000010, 0x000005b7, 0x000005b7, 0x00000011, 0x000005b8, 0x000005b8, 0x00000012, 0x000005b9, 0x000005b9, 0x00000013, 0x000005bb, 0x000005bb, 0x00000014, 0x000005bc, 0x000005bc, 0x00000015, 0x000005bd, 0x000005bd, 0x00000016, 0x000005bf, 0x000005bf, 0x00000017, 0x000005c1, 0x000005c1, 0x00000018, 0x000005c2, 0x000005c2, 0x00000019, 0x000005c4, 0x000005c4, 0x000000e6, 0x0000064b, 0x0000064b, 0x0000001b, 0x0000064c, 0x0000064c, 0x0000001c, 0x0000064d, 0x0000064d, 0x0000001d, 0x0000064e, 0x0000064e, 0x0000001e, 0x0000064f, 0x0000064f, 0x0000001f, 0x00000650, 0x00000650, 0x00000020, 0x00000651, 0x00000651, 0x00000021, 0x00000652, 0x00000652, 0x00000022, 0x00000653, 0x00000654, 0x000000e6, 0x00000655, 0x00000655, 0x000000dc, 0x00000670, 0x00000670, 0x00000023, 0x000006d6, 0x000006dc, 0x000000e6, 0x000006df, 0x000006e2, 0x000000e6, 0x000006e3, 0x000006e3, 0x000000dc, 0x000006e4, 0x000006e4, 0x000000e6, 0x000006e7, 0x000006e8, 0x000000e6, 0x000006ea, 0x000006ea, 0x000000dc, 0x000006eb, 0x000006ec, 0x000000e6, 0x000006ed, 0x000006ed, 0x000000dc, 0x00000711, 0x00000711, 0x00000024, 0x00000730, 0x00000730, 0x000000e6, 0x00000731, 0x00000731, 0x000000dc, 0x00000732, 0x00000733, 0x000000e6, 0x00000734, 0x00000734, 0x000000dc, 0x00000735, 0x00000736, 0x000000e6, 0x00000737, 0x00000739, 0x000000dc, 0x0000073a, 0x0000073a, 0x000000e6, 0x0000073b, 0x0000073c, 0x000000dc, 0x0000073d, 0x0000073d, 0x000000e6, 0x0000073e, 0x0000073e, 0x000000dc, 0x0000073f, 0x00000741, 0x000000e6, 0x00000742, 0x00000742, 0x000000dc, 0x00000743, 0x00000743, 0x000000e6, 0x00000744, 0x00000744, 0x000000dc, 0x00000745, 0x00000745, 0x000000e6, 0x00000746, 0x00000746, 0x000000dc, 0x00000747, 0x00000747, 0x000000e6, 0x00000748, 0x00000748, 0x000000dc, 0x00000749, 0x0000074a, 0x000000e6, 0x0000093c, 0x0000093c, 0x00000007, 0x0000094d, 0x0000094d, 0x00000009, 0x00000951, 0x00000951, 0x000000e6, 0x00000952, 0x00000952, 0x000000dc, 0x00000953, 0x00000954, 0x000000e6, 0x000009bc, 0x000009bc, 0x00000007, 0x000009cd, 0x000009cd, 0x00000009, 0x00000a3c, 0x00000a3c, 0x00000007, 0x00000a4d, 0x00000a4d, 0x00000009, 0x00000abc, 0x00000abc, 0x00000007, 0x00000acd, 0x00000acd, 0x00000009, 0x00000b3c, 0x00000b3c, 0x00000007, 0x00000b4d, 0x00000b4d, 0x00000009, 0x00000bcd, 0x00000bcd, 0x00000009, 0x00000c4d, 0x00000c4d, 0x00000009, 0x00000c55, 0x00000c55, 0x00000054, 0x00000c56, 0x00000c56, 0x0000005b, 0x00000ccd, 0x00000ccd, 0x00000009, 0x00000d4d, 0x00000d4d, 0x00000009, 0x00000dca, 0x00000dca, 0x00000009, 0x00000e38, 0x00000e39, 0x00000067, 0x00000e3a, 0x00000e3a, 0x00000009, 0x00000e48, 0x00000e4b, 0x0000006b, 0x00000eb8, 0x00000eb9, 0x00000076, 0x00000ec8, 0x00000ecb, 0x0000007a, 0x00000f18, 0x00000f19, 0x000000dc, 0x00000f35, 0x00000f35, 0x000000dc, 0x00000f37, 0x00000f37, 0x000000dc, 0x00000f39, 0x00000f39, 0x000000d8, 0x00000f71, 0x00000f71, 0x00000081, 0x00000f72, 0x00000f72, 0x00000082, 0x00000f74, 0x00000f74, 0x00000084, 0x00000f7a, 0x00000f7d, 0x00000082, 0x00000f80, 0x00000f80, 0x00000082, 0x00000f82, 0x00000f83, 0x000000e6, 0x00000f84, 0x00000f84, 0x00000009, 0x00000f86, 0x00000f87, 0x000000e6, 0x00000fc6, 0x00000fc6, 0x000000dc, 0x00001037, 0x00001037, 0x00000007, 0x00001039, 0x00001039, 0x00000009, 0x00001714, 0x00001714, 0x00000009, 0x00001734, 0x00001734, 0x00000009, 0x000017d2, 0x000017d2, 0x00000009, 0x000018a9, 0x000018a9, 0x000000e4, 0x000020d0, 0x000020d1, 0x000000e6, 0x000020d2, 0x000020d3, 0x00000001, 0x000020d4, 0x000020d7, 0x000000e6, 0x000020d8, 0x000020da, 0x00000001, 0x000020db, 0x000020dc, 0x000000e6, 0x000020e1, 0x000020e1, 0x000000e6, 0x000020e5, 0x000020e6, 0x00000001, 0x000020e7, 0x000020e7, 0x000000e6, 0x000020e8, 0x000020e8, 0x000000dc, 0x000020e9, 0x000020e9, 0x000000e6, 0x000020ea, 0x000020ea, 0x00000001, 0x0000302a, 0x0000302a, 0x000000da, 0x0000302b, 0x0000302b, 0x000000e4, 0x0000302c, 0x0000302c, 0x000000e8, 0x0000302d, 0x0000302d, 0x000000de, 0x0000302e, 0x0000302f, 0x000000e0, 0x00003099, 0x0000309a, 0x00000008, 0x0000fb1e, 0x0000fb1e, 0x0000001a, 0x0000fe20, 0x0000fe23, 0x000000e6, 0x0001d165, 0x0001d166, 0x000000d8, 0x0001d167, 0x0001d169, 0x00000001, 0x0001d16d, 0x0001d16d, 0x000000e2, 0x0001d16e, 0x0001d172, 0x000000d8, 0x0001d17b, 0x0001d182, 0x000000dc, 0x0001d185, 0x0001d189, 0x000000e6, 0x0001d18a, 0x0001d18b, 0x000000dc, 0x0001d1aa, 0x0001d1ad, 0x000000e6 }; static const ac_uint4 _ucnum_size = 1066; static const ac_uint4 _ucnum_nodes[] = { 0x00000030, 0x00000000, 0x00000031, 0x00000002, 0x00000032, 0x00000004, 0x00000033, 0x00000006, 0x00000034, 0x00000008, 0x00000035, 0x0000000a, 0x00000036, 0x0000000c, 0x00000037, 0x0000000e, 0x00000038, 0x00000010, 0x00000039, 0x00000012, 0x000000b2, 0x00000004, 0x000000b3, 0x00000006, 0x000000b9, 0x00000002, 0x000000bc, 0x00000014, 0x000000bd, 0x00000016, 0x000000be, 0x00000018, 0x00000660, 0x00000000, 0x00000661, 0x00000002, 0x00000662, 0x00000004, 0x00000663, 0x00000006, 0x00000664, 0x00000008, 0x00000665, 0x0000000a, 0x00000666, 0x0000000c, 0x00000667, 0x0000000e, 0x00000668, 0x00000010, 0x00000669, 0x00000012, 0x000006f0, 0x00000000, 0x000006f1, 0x00000002, 0x000006f2, 0x00000004, 0x000006f3, 0x00000006, 0x000006f4, 0x00000008, 0x000006f5, 0x0000000a, 0x000006f6, 0x0000000c, 0x000006f7, 0x0000000e, 0x000006f8, 0x00000010, 0x000006f9, 0x00000012, 0x00000966, 0x00000000, 0x00000967, 0x00000002, 0x00000968, 0x00000004, 0x00000969, 0x00000006, 0x0000096a, 0x00000008, 0x0000096b, 0x0000000a, 0x0000096c, 0x0000000c, 0x0000096d, 0x0000000e, 0x0000096e, 0x00000010, 0x0000096f, 0x00000012, 0x000009e6, 0x00000000, 0x000009e7, 0x00000002, 0x000009e8, 0x00000004, 0x000009e9, 0x00000006, 0x000009ea, 0x00000008, 0x000009eb, 0x0000000a, 0x000009ec, 0x0000000c, 0x000009ed, 0x0000000e, 0x000009ee, 0x00000010, 0x000009ef, 0x00000012, 0x000009f4, 0x00000002, 0x000009f5, 0x00000004, 0x000009f6, 0x00000006, 0x000009f7, 0x00000008, 0x000009f9, 0x0000001a, 0x00000a66, 0x00000000, 0x00000a67, 0x00000002, 0x00000a68, 0x00000004, 0x00000a69, 0x00000006, 0x00000a6a, 0x00000008, 0x00000a6b, 0x0000000a, 0x00000a6c, 0x0000000c, 0x00000a6d, 0x0000000e, 0x00000a6e, 0x00000010, 0x00000a6f, 0x00000012, 0x00000ae6, 0x00000000, 0x00000ae7, 0x00000002, 0x00000ae8, 0x00000004, 0x00000ae9, 0x00000006, 0x00000aea, 0x00000008, 0x00000aeb, 0x0000000a, 0x00000aec, 0x0000000c, 0x00000aed, 0x0000000e, 0x00000aee, 0x00000010, 0x00000aef, 0x00000012, 0x00000b66, 0x00000000, 0x00000b67, 0x00000002, 0x00000b68, 0x00000004, 0x00000b69, 0x00000006, 0x00000b6a, 0x00000008, 0x00000b6b, 0x0000000a, 0x00000b6c, 0x0000000c, 0x00000b6d, 0x0000000e, 0x00000b6e, 0x00000010, 0x00000b6f, 0x00000012, 0x00000be7, 0x00000002, 0x00000be8, 0x00000004, 0x00000be9, 0x00000006, 0x00000bea, 0x00000008, 0x00000beb, 0x0000000a, 0x00000bec, 0x0000000c, 0x00000bed, 0x0000000e, 0x00000bee, 0x00000010, 0x00000bef, 0x00000012, 0x00000bf0, 0x0000001c, 0x00000bf1, 0x0000001e, 0x00000bf2, 0x00000020, 0x00000c66, 0x00000000, 0x00000c67, 0x00000002, 0x00000c68, 0x00000004, 0x00000c69, 0x00000006, 0x00000c6a, 0x00000008, 0x00000c6b, 0x0000000a, 0x00000c6c, 0x0000000c, 0x00000c6d, 0x0000000e, 0x00000c6e, 0x00000010, 0x00000c6f, 0x00000012, 0x00000ce6, 0x00000000, 0x00000ce7, 0x00000002, 0x00000ce8, 0x00000004, 0x00000ce9, 0x00000006, 0x00000cea, 0x00000008, 0x00000ceb, 0x0000000a, 0x00000cec, 0x0000000c, 0x00000ced, 0x0000000e, 0x00000cee, 0x00000010, 0x00000cef, 0x00000012, 0x00000d66, 0x00000000, 0x00000d67, 0x00000002, 0x00000d68, 0x00000004, 0x00000d69, 0x00000006, 0x00000d6a, 0x00000008, 0x00000d6b, 0x0000000a, 0x00000d6c, 0x0000000c, 0x00000d6d, 0x0000000e, 0x00000d6e, 0x00000010, 0x00000d6f, 0x00000012, 0x00000e50, 0x00000000, 0x00000e51, 0x00000002, 0x00000e52, 0x00000004, 0x00000e53, 0x00000006, 0x00000e54, 0x00000008, 0x00000e55, 0x0000000a, 0x00000e56, 0x0000000c, 0x00000e57, 0x0000000e, 0x00000e58, 0x00000010, 0x00000e59, 0x00000012, 0x00000ed0, 0x00000000, 0x00000ed1, 0x00000002, 0x00000ed2, 0x00000004, 0x00000ed3, 0x00000006, 0x00000ed4, 0x00000008, 0x00000ed5, 0x0000000a, 0x00000ed6, 0x0000000c, 0x00000ed7, 0x0000000e, 0x00000ed8, 0x00000010, 0x00000ed9, 0x00000012, 0x00000f20, 0x00000000, 0x00000f21, 0x00000002, 0x00000f22, 0x00000004, 0x00000f23, 0x00000006, 0x00000f24, 0x00000008, 0x00000f25, 0x0000000a, 0x00000f26, 0x0000000c, 0x00000f27, 0x0000000e, 0x00000f28, 0x00000010, 0x00000f29, 0x00000012, 0x00000f2a, 0x00000016, 0x00000f2b, 0x00000022, 0x00000f2c, 0x00000024, 0x00000f2d, 0x00000026, 0x00000f2e, 0x00000028, 0x00000f2f, 0x0000002a, 0x00000f30, 0x0000002c, 0x00000f31, 0x0000002e, 0x00000f32, 0x00000030, 0x00000f33, 0x00000032, 0x00001040, 0x00000000, 0x00001041, 0x00000002, 0x00001042, 0x00000004, 0x00001043, 0x00000006, 0x00001044, 0x00000008, 0x00001045, 0x0000000a, 0x00001046, 0x0000000c, 0x00001047, 0x0000000e, 0x00001048, 0x00000010, 0x00001049, 0x00000012, 0x00001369, 0x00000002, 0x0000136a, 0x00000004, 0x0000136b, 0x00000006, 0x0000136c, 0x00000008, 0x0000136d, 0x0000000a, 0x0000136e, 0x0000000c, 0x0000136f, 0x0000000e, 0x00001370, 0x00000010, 0x00001371, 0x00000012, 0x00001372, 0x0000001c, 0x00001373, 0x00000034, 0x00001374, 0x00000036, 0x00001375, 0x00000038, 0x00001376, 0x0000003a, 0x00001377, 0x0000003c, 0x00001378, 0x0000003e, 0x00001379, 0x00000040, 0x0000137a, 0x00000042, 0x0000137b, 0x0000001e, 0x0000137c, 0x00000044, 0x000016ee, 0x00000046, 0x000016ef, 0x00000048, 0x000016f0, 0x0000004a, 0x000017e0, 0x00000000, 0x000017e1, 0x00000002, 0x000017e2, 0x00000004, 0x000017e3, 0x00000006, 0x000017e4, 0x00000008, 0x000017e5, 0x0000000a, 0x000017e6, 0x0000000c, 0x000017e7, 0x0000000e, 0x000017e8, 0x00000010, 0x000017e9, 0x00000012, 0x00001810, 0x00000000, 0x00001811, 0x00000002, 0x00001812, 0x00000004, 0x00001813, 0x00000006, 0x00001814, 0x00000008, 0x00001815, 0x0000000a, 0x00001816, 0x0000000c, 0x00001817, 0x0000000e, 0x00001818, 0x00000010, 0x00001819, 0x00000012, 0x00002070, 0x00000000, 0x00002074, 0x00000008, 0x00002075, 0x0000000a, 0x00002076, 0x0000000c, 0x00002077, 0x0000000e, 0x00002078, 0x00000010, 0x00002079, 0x00000012, 0x00002080, 0x00000000, 0x00002081, 0x00000002, 0x00002082, 0x00000004, 0x00002083, 0x00000006, 0x00002084, 0x00000008, 0x00002085, 0x0000000a, 0x00002086, 0x0000000c, 0x00002087, 0x0000000e, 0x00002088, 0x00000010, 0x00002089, 0x00000012, 0x00002153, 0x0000004c, 0x00002154, 0x0000004e, 0x00002155, 0x00000050, 0x00002156, 0x00000052, 0x00002157, 0x00000054, 0x00002158, 0x00000056, 0x00002159, 0x00000058, 0x0000215a, 0x0000005a, 0x0000215b, 0x0000005c, 0x0000215c, 0x0000005e, 0x0000215d, 0x00000060, 0x0000215e, 0x00000062, 0x0000215f, 0x00000002, 0x00002160, 0x00000002, 0x00002161, 0x00000004, 0x00002162, 0x00000006, 0x00002163, 0x00000008, 0x00002164, 0x0000000a, 0x00002165, 0x0000000c, 0x00002166, 0x0000000e, 0x00002167, 0x00000010, 0x00002168, 0x00000012, 0x00002169, 0x0000001c, 0x0000216a, 0x00000064, 0x0000216b, 0x00000066, 0x0000216c, 0x0000003a, 0x0000216d, 0x0000001e, 0x0000216e, 0x00000068, 0x0000216f, 0x00000020, 0x00002170, 0x00000002, 0x00002171, 0x00000004, 0x00002172, 0x00000006, 0x00002173, 0x00000008, 0x00002174, 0x0000000a, 0x00002175, 0x0000000c, 0x00002176, 0x0000000e, 0x00002177, 0x00000010, 0x00002178, 0x00000012, 0x00002179, 0x0000001c, 0x0000217a, 0x00000064, 0x0000217b, 0x00000066, 0x0000217c, 0x0000003a, 0x0000217d, 0x0000001e, 0x0000217e, 0x00000068, 0x0000217f, 0x00000020, 0x00002180, 0x00000020, 0x00002181, 0x0000006a, 0x00002182, 0x00000044, 0x00002460, 0x00000002, 0x00002461, 0x00000004, 0x00002462, 0x00000006, 0x00002463, 0x00000008, 0x00002464, 0x0000000a, 0x00002465, 0x0000000c, 0x00002466, 0x0000000e, 0x00002467, 0x00000010, 0x00002468, 0x00000012, 0x00002469, 0x0000001c, 0x0000246a, 0x00000064, 0x0000246b, 0x00000066, 0x0000246c, 0x0000006c, 0x0000246d, 0x0000006e, 0x0000246e, 0x00000070, 0x0000246f, 0x0000001a, 0x00002470, 0x00000046, 0x00002471, 0x00000048, 0x00002472, 0x0000004a, 0x00002473, 0x00000034, 0x00002474, 0x00000002, 0x00002475, 0x00000004, 0x00002476, 0x00000006, 0x00002477, 0x00000008, 0x00002478, 0x0000000a, 0x00002479, 0x0000000c, 0x0000247a, 0x0000000e, 0x0000247b, 0x00000010, 0x0000247c, 0x00000012, 0x0000247d, 0x0000001c, 0x0000247e, 0x00000064, 0x0000247f, 0x00000066, 0x00002480, 0x0000006c, 0x00002481, 0x0000006e, 0x00002482, 0x00000070, 0x00002483, 0x0000001a, 0x00002484, 0x00000046, 0x00002485, 0x00000048, 0x00002486, 0x0000004a, 0x00002487, 0x00000034, 0x00002488, 0x00000002, 0x00002489, 0x00000004, 0x0000248a, 0x00000006, 0x0000248b, 0x00000008, 0x0000248c, 0x0000000a, 0x0000248d, 0x0000000c, 0x0000248e, 0x0000000e, 0x0000248f, 0x00000010, 0x00002490, 0x00000012, 0x00002491, 0x0000001c, 0x00002492, 0x00000064, 0x00002493, 0x00000066, 0x00002494, 0x0000006c, 0x00002495, 0x0000006e, 0x00002496, 0x00000070, 0x00002497, 0x0000001a, 0x00002498, 0x00000046, 0x00002499, 0x00000048, 0x0000249a, 0x0000004a, 0x0000249b, 0x00000034, 0x000024ea, 0x00000000, 0x000024eb, 0x00000064, 0x000024ec, 0x00000066, 0x000024ed, 0x0000006c, 0x000024ee, 0x0000006e, 0x000024ef, 0x00000070, 0x000024f0, 0x0000001a, 0x000024f1, 0x00000046, 0x000024f2, 0x00000048, 0x000024f3, 0x0000004a, 0x000024f4, 0x00000034, 0x000024f5, 0x00000002, 0x000024f6, 0x00000004, 0x000024f7, 0x00000006, 0x000024f8, 0x00000008, 0x000024f9, 0x0000000a, 0x000024fa, 0x0000000c, 0x000024fb, 0x0000000e, 0x000024fc, 0x00000010, 0x000024fd, 0x00000012, 0x000024fe, 0x0000001c, 0x00002776, 0x00000002, 0x00002777, 0x00000004, 0x00002778, 0x00000006, 0x00002779, 0x00000008, 0x0000277a, 0x0000000a, 0x0000277b, 0x0000000c, 0x0000277c, 0x0000000e, 0x0000277d, 0x00000010, 0x0000277e, 0x00000012, 0x0000277f, 0x0000001c, 0x00002780, 0x00000002, 0x00002781, 0x00000004, 0x00002782, 0x00000006, 0x00002783, 0x00000008, 0x00002784, 0x0000000a, 0x00002785, 0x0000000c, 0x00002786, 0x0000000e, 0x00002787, 0x00000010, 0x00002788, 0x00000012, 0x00002789, 0x0000001c, 0x0000278a, 0x00000002, 0x0000278b, 0x00000004, 0x0000278c, 0x00000006, 0x0000278d, 0x00000008, 0x0000278e, 0x0000000a, 0x0000278f, 0x0000000c, 0x00002790, 0x0000000e, 0x00002791, 0x00000010, 0x00002792, 0x00000012, 0x00002793, 0x0000001c, 0x00003007, 0x00000000, 0x00003021, 0x00000002, 0x00003022, 0x00000004, 0x00003023, 0x00000006, 0x00003024, 0x00000008, 0x00003025, 0x0000000a, 0x00003026, 0x0000000c, 0x00003027, 0x0000000e, 0x00003028, 0x00000010, 0x00003029, 0x00000012, 0x00003038, 0x0000001c, 0x00003039, 0x00000034, 0x0000303a, 0x00000036, 0x00003192, 0x00000002, 0x00003193, 0x00000004, 0x00003194, 0x00000006, 0x00003195, 0x00000008, 0x00003220, 0x00000002, 0x00003221, 0x00000004, 0x00003222, 0x00000006, 0x00003223, 0x00000008, 0x00003224, 0x0000000a, 0x00003225, 0x0000000c, 0x00003226, 0x0000000e, 0x00003227, 0x00000010, 0x00003228, 0x00000012, 0x00003229, 0x0000001c, 0x00003251, 0x00000072, 0x00003252, 0x00000074, 0x00003253, 0x00000076, 0x00003254, 0x00000078, 0x00003255, 0x0000007a, 0x00003256, 0x0000007c, 0x00003257, 0x0000007e, 0x00003258, 0x00000080, 0x00003259, 0x00000082, 0x0000325a, 0x00000036, 0x0000325b, 0x00000084, 0x0000325c, 0x00000086, 0x0000325d, 0x00000088, 0x0000325e, 0x0000008a, 0x0000325f, 0x0000008c, 0x00003280, 0x00000002, 0x00003281, 0x00000004, 0x00003282, 0x00000006, 0x00003283, 0x00000008, 0x00003284, 0x0000000a, 0x00003285, 0x0000000c, 0x00003286, 0x0000000e, 0x00003287, 0x00000010, 0x00003288, 0x00000012, 0x00003289, 0x0000001c, 0x000032b1, 0x0000008e, 0x000032b2, 0x00000090, 0x000032b3, 0x00000092, 0x000032b4, 0x00000094, 0x000032b5, 0x00000038, 0x000032b6, 0x00000096, 0x000032b7, 0x00000098, 0x000032b8, 0x0000009a, 0x000032b9, 0x0000009c, 0x000032ba, 0x0000009e, 0x000032bb, 0x000000a0, 0x000032bc, 0x000000a2, 0x000032bd, 0x000000a4, 0x000032be, 0x000000a6, 0x000032bf, 0x0000003a, 0x0000ff10, 0x00000000, 0x0000ff11, 0x00000002, 0x0000ff12, 0x00000004, 0x0000ff13, 0x00000006, 0x0000ff14, 0x00000008, 0x0000ff15, 0x0000000a, 0x0000ff16, 0x0000000c, 0x0000ff17, 0x0000000e, 0x0000ff18, 0x00000010, 0x0000ff19, 0x00000012, 0x00010320, 0x00000002, 0x00010321, 0x0000000a, 0x00010322, 0x0000001c, 0x00010323, 0x0000003a, 0x0001d7ce, 0x00000000, 0x0001d7cf, 0x00000002, 0x0001d7d0, 0x00000004, 0x0001d7d1, 0x00000006, 0x0001d7d2, 0x00000008, 0x0001d7d3, 0x0000000a, 0x0001d7d4, 0x0000000c, 0x0001d7d5, 0x0000000e, 0x0001d7d6, 0x00000010, 0x0001d7d7, 0x00000012, 0x0001d7d8, 0x00000000, 0x0001d7d9, 0x00000002, 0x0001d7da, 0x00000004, 0x0001d7db, 0x00000006, 0x0001d7dc, 0x00000008, 0x0001d7dd, 0x0000000a, 0x0001d7de, 0x0000000c, 0x0001d7df, 0x0000000e, 0x0001d7e0, 0x00000010, 0x0001d7e1, 0x00000012, 0x0001d7e2, 0x00000000, 0x0001d7e3, 0x00000002, 0x0001d7e4, 0x00000004, 0x0001d7e5, 0x00000006, 0x0001d7e6, 0x00000008, 0x0001d7e7, 0x0000000a, 0x0001d7e8, 0x0000000c, 0x0001d7e9, 0x0000000e, 0x0001d7ea, 0x00000010, 0x0001d7eb, 0x00000012, 0x0001d7ec, 0x00000000, 0x0001d7ed, 0x00000002, 0x0001d7ee, 0x00000004, 0x0001d7ef, 0x00000006, 0x0001d7f0, 0x00000008, 0x0001d7f1, 0x0000000a, 0x0001d7f2, 0x0000000c, 0x0001d7f3, 0x0000000e, 0x0001d7f4, 0x00000010, 0x0001d7f5, 0x00000012, 0x0001d7f6, 0x00000000, 0x0001d7f7, 0x00000002, 0x0001d7f8, 0x00000004, 0x0001d7f9, 0x00000006, 0x0001d7fa, 0x00000008, 0x0001d7fb, 0x0000000a, 0x0001d7fc, 0x0000000c, 0x0001d7fd, 0x0000000e, 0x0001d7fe, 0x00000010, 0x0001d7ff, 0x00000012 }; static const short _ucnum_vals[] = { 0x0000, 0x0001, 0x0001, 0x0001, 0x0002, 0x0001, 0x0003, 0x0001, 0x0004, 0x0001, 0x0005, 0x0001, 0x0006, 0x0001, 0x0007, 0x0001, 0x0008, 0x0001, 0x0009, 0x0001, 0x0001, 0x0004, 0x0001, 0x0002, 0x0003, 0x0004, 0x0010, 0x0001, 0x000a, 0x0001, 0x0064, 0x0001, 0x03e8, 0x0001, 0x0003, 0x0002, 0x0005, 0x0002, 0x0007, 0x0002, 0x0009, 0x0002, 0x000b, 0x0002, 0x000d, 0x0002, 0x000f, 0x0002, 0x0011, 0x0002, -1, 0x0002, 0x0014, 0x0001, 0x001e, 0x0001, 0x0028, 0x0001, 0x0032, 0x0001, 0x003c, 0x0001, 0x0046, 0x0001, 0x0050, 0x0001, 0x005a, 0x0001, 0x2710, 0x0001, 0x0011, 0x0001, 0x0012, 0x0001, 0x0013, 0x0001, 0x0001, 0x0003, 0x0002, 0x0003, 0x0001, 0x0005, 0x0002, 0x0005, 0x0003, 0x0005, 0x0004, 0x0005, 0x0001, 0x0006, 0x0005, 0x0006, 0x0001, 0x0008, 0x0003, 0x0008, 0x0005, 0x0008, 0x0007, 0x0008, 0x000b, 0x0001, 0x000c, 0x0001, 0x01f4, 0x0001, 0x1388, 0x0001, 0x000d, 0x0001, 0x000e, 0x0001, 0x000f, 0x0001, 0x0015, 0x0001, 0x0016, 0x0001, 0x0017, 0x0001, 0x0018, 0x0001, 0x0019, 0x0001, 0x001a, 0x0001, 0x001b, 0x0001, 0x001c, 0x0001, 0x001d, 0x0001, 0x001f, 0x0001, 0x0020, 0x0001, 0x0021, 0x0001, 0x0022, 0x0001, 0x0023, 0x0001, 0x0024, 0x0001, 0x0025, 0x0001, 0x0026, 0x0001, 0x0027, 0x0001, 0x0029, 0x0001, 0x002a, 0x0001, 0x002b, 0x0001, 0x002c, 0x0001, 0x002d, 0x0001, 0x002e, 0x0001, 0x002f, 0x0001, 0x0030, 0x0001, 0x0031, 0x0001 }; openldap-2.5.11+dfsg/libraries/liblunicode/ucdata/format.txt0000644000175000017500000002232714172327167022604 0ustar ryanryan# # $Id: format.txt,v 1.2 2001/01/02 18:46:20 mleisher Exp $ # CHARACTER DATA ============== This package generates some data files that contain character properties useful for text processing. CHARACTER PROPERTIES ==================== The first data file is called "ctype.dat" and contains a compressed form of the character properties found in the Unicode Character Database (UCDB). Additional properties can be specified in limited UCDB format in another file to avoid modifying the original UCDB. The following is a property name and code table to be used with the character data: NAME CODE DESCRIPTION --------------------- Mn 0 Mark, Non-Spacing Mc 1 Mark, Spacing Combining Me 2 Mark, Enclosing Nd 3 Number, Decimal Digit Nl 4 Number, Letter No 5 Number, Other Zs 6 Separator, Space Zl 7 Separator, Line Zp 8 Separator, Paragraph Cc 9 Other, Control Cf 10 Other, Format Cs 11 Other, Surrogate Co 12 Other, Private Use Cn 13 Other, Not Assigned Lu 14 Letter, Uppercase Ll 15 Letter, Lowercase Lt 16 Letter, Titlecase Lm 17 Letter, Modifier Lo 18 Letter, Other Pc 19 Punctuation, Connector Pd 20 Punctuation, Dash Ps 21 Punctuation, Open Pe 22 Punctuation, Close Po 23 Punctuation, Other Sm 24 Symbol, Math Sc 25 Symbol, Currency Sk 26 Symbol, Modifier So 27 Symbol, Other L 28 Left-To-Right R 29 Right-To-Left EN 30 European Number ES 31 European Number Separator ET 32 European Number Terminator AN 33 Arabic Number CS 34 Common Number Separator B 35 Block Separator S 36 Segment Separator WS 37 Whitespace ON 38 Other Neutrals Pi 47 Punctuation, Initial Pf 48 Punctuation, Final # # Implementation specific properties. # Cm 39 Composite Nb 40 Non-Breaking Sy 41 Symmetric (characters which are part of open/close pairs) Hd 42 Hex Digit Qm 43 Quote Mark Mr 44 Mirroring Ss 45 Space, Other (controls viewed as spaces in ctype isspace()) Cp 46 Defined character The actual binary data is formatted as follows: Assumptions: unsigned short is at least 16-bits in size and unsigned long is at least 32-bits in size. unsigned short ByteOrderMark unsigned short OffsetArraySize unsigned long Bytes unsigned short Offsets[OffsetArraySize + 1] unsigned long Ranges[N], N = value of Offsets[OffsetArraySize] The Bytes field provides the total byte count used for the Offsets[] and Ranges[] arrays. The Offsets[] array is aligned on a 4-byte boundary and there is always one extra node on the end to hold the final index of the Ranges[] array. The Ranges[] array contains pairs of 4-byte values representing a range of Unicode characters. The pairs are arranged in increasing order by the first character code in the range. Determining if a particular character is in the property list requires a simple binary search to determine if a character is in any of the ranges for the property. If the ByteOrderMark is equal to 0xFFFE, then the data was generated on a machine with a different endian order and the values must be byte-swapped. To swap a 16-bit value: c = (c >> 8) | ((c & 0xff) << 8) To swap a 32-bit value: c = ((c & 0xff) << 24) | (((c >> 8) & 0xff) << 16) | (((c >> 16) & 0xff) << 8) | (c >> 24) CASE MAPPINGS ============= The next data file is called "case.dat" and contains three case mapping tables in the following order: upper, lower, and title case. Each table is in increasing order by character code and each mapping contains 3 unsigned longs which represent the possible mappings. The format for the binary form of these tables is: unsigned short ByteOrderMark unsigned short NumMappingNodes, count of all mapping nodes unsigned short CaseTableSizes[2], upper and lower mapping node counts unsigned long CaseTables[NumMappingNodes] The starting indexes of the case tables are calculated as following: UpperIndex = 0; LowerIndex = CaseTableSizes[0] * 3; TitleIndex = LowerIndex + CaseTableSizes[1] * 3; The order of the fields for the three tables are: Upper case ---------- unsigned long upper; unsigned long lower; unsigned long title; Lower case ---------- unsigned long lower; unsigned long upper; unsigned long title; Title case ---------- unsigned long title; unsigned long upper; unsigned long lower; If the ByteOrderMark is equal to 0xFFFE, endian swapping is required in the same way as described in the CHARACTER PROPERTIES section. Because the tables are in increasing order by character code, locating a mapping requires a simple binary search on one of the 3 codes that make up each node. It is important to note that there can only be 65536 mapping nodes which divided into 3 portions allows 21845 nodes for each case mapping table. The distribution of mappings may be more or less than 21845 per table, but only 65536 are allowed. COMPOSITIONS ============ This data file is called "comp.dat" and contains data that tracks character pairs that have a single Unicode value representing the combination of the two characters. The format for the binary form of this table is: unsigned short ByteOrderMark unsigned short NumCompositionNodes, count of composition nodes unsigned long Bytes, total number of bytes used for composition nodes unsigned long CompositionNodes[NumCompositionNodes * 4] If the ByteOrderMark is equal to 0xFFFE, endian swapping is required in the same way as described in the CHARACTER PROPERTIES section. The CompositionNodes[] array consists of groups of 4 unsigned longs. The first of these is the character code representing the combination of two other character codes, the second records the number of character codes that make up the composition (not currently used), and the last two are the pair of character codes whose combination is represented by the character code in the first field. DECOMPOSITIONS ============== The next data file is called "decomp.dat" and contains the decomposition data for all characters with decompositions containing more than one character and are *not* compatibility decompositions. Compatibility decompositions are signaled in the UCDB format by the use of the tag in the decomposition field. Each list of character codes represents a full decomposition of a composite character. The nodes are arranged in increasing order by character code. The format for the binary form of this table is: unsigned short ByteOrderMark unsigned short NumDecompNodes, count of all decomposition nodes unsigned long Bytes unsigned long DecompNodes[(NumDecompNodes * 2) + 1] unsigned long Decomp[N], N = sum of all counts in DecompNodes[] If the ByteOrderMark is equal to 0xFFFE, endian swapping is required in the same way as described in the CHARACTER PROPERTIES section. The DecompNodes[] array consists of pairs of unsigned longs, the first of which is the character code and the second is the initial index of the list of character codes representing the decomposition. Locating the decomposition of a composite character requires a binary search for a character code in the DecompNodes[] array and using its index to locate the start of the decomposition. The length of the decomposition list is the index in the following element in DecompNode[] minus the current index. COMBINING CLASSES ================= The fourth data file is called "cmbcl.dat" and contains the characters with non-zero combining classes. The format for the binary form of this table is: unsigned short ByteOrderMark unsigned short NumCCLNodes unsigned long Bytes unsigned long CCLNodes[NumCCLNodes * 3] If the ByteOrderMark is equal to 0xFFFE, endian swapping is required in the same way as described in the CHARACTER PROPERTIES section. The CCLNodes[] array consists of groups of three unsigned longs. The first and second are the beginning and ending of a range and the third is the combining class of that range. If a character is not found in this table, then the combining class is assumed to be 0. It is important to note that only 65536 distinct ranges plus combining class can be specified because the NumCCLNodes is usually a 16-bit number. NUMBER TABLE ============ The final data file is called "num.dat" and contains the characters that have a numeric value associated with them. The format for the binary form of the table is: unsigned short ByteOrderMark unsigned short NumNumberNodes unsigned long Bytes unsigned long NumberNodes[NumNumberNodes] unsigned short ValueNodes[(Bytes - (NumNumberNodes * sizeof(unsigned long))) / sizeof(short)] If the ByteOrderMark is equal to 0xFFFE, endian swapping is required in the same way as described in the CHARACTER PROPERTIES section. The NumberNodes array contains pairs of values, the first of which is the character code and the second an index into the ValueNodes array. The ValueNodes array contains pairs of integers which represent the numerator and denominator of the numeric value of the character. If the character happens to map to an integer, both the values in ValueNodes will be the same. openldap-2.5.11+dfsg/libraries/liblunicode/ucdata/README0000644000175000017500000002477614172327167021445 0ustar ryanryan# # $Id: README,v 1.33 2001/01/02 18:46:19 mleisher Exp $ # MUTT UCData Package 2.5 ----------------------- This is a package that supports ctype-like operations for Unicode UCS-2 text (and surrogates), case mapping, decomposition lookup, and provides a bidirectional reordering algorithm. To use it, you will need to get the latest "UnicodeData-*.txt" (or later) file from the Unicode Web or FTP site. The character information portion of the package consists of three parts: 1. A program called "ucgendat" which generates five data files from the UnicodeData-*.txt file. The files are: A. case.dat - the case mappings. B. ctype.dat - the character property tables. C. comp.dat - the character composition pairs. D. decomp.dat - the character decompositions. E. cmbcl.dat - the non-zero combining classes. F. num.dat - the codes representing numbers. 2. The "ucdata.[ch]" files which implement the functions needed to check to see if a character matches groups of properties, to map between upper, lower, and title case, to look up the decomposition of a character, look up the combining class of a character, and get the number value of a character. 3. The UCData.java class which provides the same API (with minor changes for the numbers) and loads the same binary data files as the C code. A short reference to the functions available is in the "api.txt" file. Techie Details ============== The "ucgendat" program parses files from the command line which are all in the Unicode Character Database (UCDB) format. An additional properties file, "MUTTUCData.txt", provides some extra properties for some characters. The program looks for the two character properties fields (2 and 4), the combining class field (3), the decomposition field (5), the numeric value field (8), and the case mapping fields (12, 13, and 14). The decompositions are recursively expanded before being written out. The decomposition table contains all the canonical decompositions. This means all decompositions that do not have tags such as "" or "". The data is almost all stored as unsigned longs (32-bits assumed) and the routines that load the data take care of endian swaps when necessary. This also means that supplementary characters (>= 0x10000) can be placed in the data files the "ucgendat" program parses. The data is written as external files and broken into six parts so it can be selectively updated at runtime if necessary. The data files currently generated from the "ucgendat" program total about 56K in size all together. The format of the binary data files is documented in the "format.txt" file. ========================================================================== The "Pretty Good Bidi Algorithm" -------------------------------- This routine provides an alternative to the Unicode Bidi algorithm. The difference is that this version of the PGBA does not handle the explicit directional codes (LRE, RLE, LRO, RLO, PDF). It should now produce the same results as the Unicode BiDi algorithm for implicit reordering. Included are functions for doing cursor motion in both logical and visual order. This implementation is provided to demonstrate an effective alternate method for implicit reordering. To make this useful for an application, it probably needs some changes to the memory allocation and deallocation, as well as data structure additions for rendering. Mark Leisher 19 November 1999 ----------------------------------------------------------------------------- CHANGES ======= Version 2.5 ----------- 1. Changed the number lookup to set the denominator to 1 in cases of digits. This restores functional compatibility with John Cowan's UCType package. 2. Added support for the AL property. 3. Modified load and reload functions to return error codes. Version 2.4 ----------- 1. Improved some bidi algorithm documentation in the code. 2. Fixed a code mixup that produced a non-working version. Version 2.3 ----------- 1. Fixed a misspelling in the ucpgba.h header file. 2. Fixed a bug which caused trailing weak non-digit sequences to be left out of the reordered string in the bidi algorithm. 3. Fixed a problem with weak sequences containing non-spacing marks in the bidi algorithm. 4. Fixed a problem with text runs of the opposite direction of the string surrounding a weak + neutral text run appearing in the wrong order in the bidi algorithm. 5. Added a default overall direction parameter to the reordering function for cases of strings with no strong directional characters in the bidi algorithm. 6. The bidi API documentation was improved. 7. Added a man page for the bidi API. Version 2.2 ----------- 1. Fixed a problem with the bidi algorithm locating directional section boundaries. 2. Fixed a problem with the bidi algorithm starting the reordering correctly. 3. Fixed a problem with the bidi algorithm determining end boundaries for LTR segments. 4. Fixed a problem with the bidi algorithm reordering weak (digits and number separators) segments. 5. Added automatic switching of symmetrically paired characters when reversing RTL segments. 6. Added a missing symmetric character to the extra character properties in MUTTUCData.txt. 7. Added support for doing logical and visual cursor traversal. Version 2.1 ----------- 1. Updated the ucgendat program to handle the Unicode 3.0 character database properties. The AL and BM bidi properties gets marked as strong RTL and Other Neutral, the NSM, LRE, RLE, PDF, LRO, and RLO controls all get marked as Other Neutral. 2. Fixed some problems with testing against signed values in the UCData.java code and some minor cleanup. 3. Added the "Pretty Good Bidi Algorithm." Version 2.0 ----------- 1. Removed the old Java stuff for a new class that loads directly from the same data files as the C code does. 2. Fixed a problem with choosing the correct field when mapping case. 3. Adjust some search routines to start their search in the correct position. 4. Moved the copyright year to 1999. Version 1.9 ----------- 1. Fixed a problem with an incorrect amount of storage being allocated for the combining class nodes. 2. Fixed an invalid initialization in the number code. 3. Changed the Java template file formatting a bit. 4. Added tables and function for getting decompositions in the Java class. Version 1.8 ----------- 1. Fixed a problem with adding certain ranges. 2. Added two more macros for testing for identifiers. 3. Tested with the UnicodeData-2.1.5.txt file. Version 1.7 ----------- 1. Fixed a problem with looking up decompositions in "ucgendat." Version 1.6 ----------- 1. Added two new properties introduced with UnicodeData-2.1.4.txt. 2. Changed the "ucgendat.c" program a little to automatically align the property data on a 4-byte boundary when new properties are added. 3. Changed the "ucgendat.c" programs to only generate canonical decompositions. 4. Added two new macros ucisinitialpunct() and ucisfinalpunct() to check for initial and final punctuation characters. 5. Minor additions and changes to the documentation. Version 1.5 ----------- 1. Changed all file open calls to include binary mode with "b" for DOS/WIN platforms. 2. Wrapped the unistd.h include so it won't be included when compiled under Win32. 3. Fixed a bad range check for hex digits in ucgendat.c. 4. Fixed a bad endian swap for combining classes. 5. Added code to make a number table and associated lookup functions. Functions added are ucnumber(), ucdigit(), and ucgetnumber(). The last function is to maintain compatibility with John Cowan's "uctype" package. Version 1.4 ----------- 1. Fixed a bug with adding a range. 2. Fixed a bug with inserting a range in order. 3. Fixed incorrectly specified ucisdefined() and ucisundefined() macros. 4. Added the missing unload for the combining class data. 5. Fixed a bad macro placement in ucisweak(). Version 1.3 ----------- 1. Bug with case mapping calculations fixed. 2. Bug with empty character property entries fixed. 3. Bug with incorrect type in the combining class lookup fixed. 4. Some corrections done to api.txt. 5. Bug in certain character property lookups fixed. 6. Added a character property table that records the defined characters. 7. Replaced ucisunknown() with ucisdefined() and ucisundefined(). Version 1.2 ----------- 1. Added code to ucgendat to generate a combining class table. 2. Fixed an endian problem with the byte count of decompositions. 3. Fixed some minor problems in the "format.txt" file. 4. Removed some bogus "Ss" values from MUTTUCData.txt file. 5. Added API function to get combining class. 6. Changed the open mode to "rb" so binary data files will be opened correctly on DOS/WIN as well as other platforms. 7. Added the "api.txt" file. Version 1.1 ----------- 1. Added ucisxdigit() which I overlooked. 2. Added UC_LT to the ucisalpha() macro which I overlooked. 3. Change uciscntrl() to include UC_CF. 4. Added ucisocntrl() and ucfntcntrl() macros. 5. Added a ucisblank() which I overlooked. 6. Added missing properties to ucissymbol() and ucisnumber(). 7. Added ucisgraph() and ucisprint(). 8. Changed the "Mr" property to "Sy" to mark this subset of mirroring characters as symmetric to avoid trampling the Unicode/ISO10646 sense of mirroring. 9. Added another property called "Ss" which includes control characters traditionally seen as spaces in the isspace() macro. 10. Added a bunch of macros to be API compatible with John Cowan's package. ACKNOWLEDGEMENTS ================ Thanks go to John Cowan for pointing out lots of missing things and giving me stuff, particularly a bunch of new macros. Thanks go to Bob Verbrugge for pointing out various bugs. Thanks go to Christophe Pierret for pointing out that file modes need to have "b" for DOS/WIN machines, pointing out unistd.h is not a Win 32 header, and pointing out a problem with ucisalnum(). Thanks go to Kent Johnson for finding a bug that caused incomplete decompositions to be generated by the "ucgendat" program. Thanks go to Valeriy E. Ushakov for spotting an allocation error and an initialization error. Thanks go to Stig Venaas for providing a patch to support return types on load and reload, and for major updates to handle canonical composition and decomposition. openldap-2.5.11+dfsg/libraries/liblunicode/ucdata/ucpgba.c0000644000175000017500000005570114172327167022162 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Copyright 2001 Computing Research Labs, New Mexico State University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* $Id: ucpgba.c,v 1.5 2001/01/02 18:46:20 mleisher Exp $ */ #include "portable.h" #include #include #include "ucdata.h" #include "ucpgba.h" /* * These macros are used while reordering of RTL runs of text for the * special case of non-spacing characters being in runs of weakly * directional text. They check for weak and non-spacing, and digits and * non-spacing. */ #define ISWEAKSPECIAL(cc) ucisprop(cc, UC_EN|UC_ES|UC_MN, UC_ET|UC_AN|UC_CS) #define ISDIGITSPECIAL(cc) ucisprop(cc, UC_ND|UC_MN, 0) /* * These macros are used while breaking a string into runs of text in * different directions. Descriptions: * * ISLTR_LTR - Test for members of an LTR run in an LTR context. This looks * for characters with ltr, non-spacing, weak, and neutral * properties. * * ISRTL_RTL - Test for members of an RTL run in an RTL context. This looks * for characters with rtl, non-spacing, weak, and neutral * properties. * * ISRTL_NEUTRAL - Test for RTL or neutral characters. * * ISWEAK_NEUTRAL - Test for weak or neutral characters. */ #define ISLTR_LTR(cc) ucisprop(cc, UC_L|UC_MN|UC_EN|UC_ES,\ UC_ET|UC_CS|UC_B|UC_S|UC_WS|UC_ON) #define ISRTL_RTL(cc) ucisprop(cc, UC_R|UC_MN|UC_EN|UC_ES,\ UC_ET|UC_AN|UC_CS|UC_B|UC_S|UC_WS|UC_ON) #define ISRTL_NEUTRAL(cc) ucisprop(cc, UC_R, UC_B|UC_S|UC_WS|UC_ON) #define ISWEAK_NEUTRAL(cc) ucisprop(cc, UC_EN|UC_ES, \ UC_B|UC_S|UC_WS|UC_ON|UC_ET|UC_AN|UC_CS) /* * This table is temporarily hard-coded here until it can be constructed * automatically somehow. */ static unsigned long _symmetric_pairs[] = { 0x0028, 0x0029, 0x0029, 0x0028, 0x003C, 0x003E, 0x003E, 0x003C, 0x005B, 0x005D, 0x005D, 0x005B, 0x007B, 0x007D, 0x007D, 0x007B, 0x2045, 0x2046, 0x2046, 0x2045, 0x207D, 0x207E, 0x207E, 0x207D, 0x208D, 0x208E, 0x208E, 0x208D, 0x3008, 0x3009, 0x3009, 0x3008, 0x300A, 0x300B, 0x300B, 0x300A, 0x300C, 0x300D, 0x300D, 0x300C, 0x300E, 0x300F, 0x300F, 0x300E, 0x3010, 0x3011, 0x3011, 0x3010, 0x3014, 0x3015, 0x3015, 0x3014, 0x3016, 0x3017, 0x3017, 0x3016, 0x3018, 0x3019, 0x3019, 0x3018, 0x301A, 0x301B, 0x301B, 0x301A, 0xFD3E, 0xFD3F, 0xFD3F, 0xFD3E, 0xFE59, 0xFE5A, 0xFE5A, 0xFE59, 0xFE5B, 0xFE5C, 0xFE5C, 0xFE5B, 0xFE5D, 0xFE5E, 0xFE5E, 0xFE5D, 0xFF08, 0xFF09, 0xFF09, 0xFF08, 0xFF3B, 0xFF3D, 0xFF3D, 0xFF3B, 0xFF5B, 0xFF5D, 0xFF5D, 0xFF5B, 0xFF62, 0xFF63, 0xFF63, 0xFF62, }; static int _symmetric_pairs_size = sizeof(_symmetric_pairs)/sizeof(_symmetric_pairs[0]); /* * This routine looks up the other form of a symmetric pair. */ static unsigned long _ucsymmetric_pair(unsigned long c) { int i; for (i = 0; i < _symmetric_pairs_size; i += 2) { if (_symmetric_pairs[i] == c) return _symmetric_pairs[i+1]; } return c; } /* * This routine creates a new run, copies the text into it, links it into the * logical text order chain and returns it to the caller to be linked into * the visual text order chain. */ static ucrun_t * _add_run(ucstring_t *str, unsigned long *src, unsigned long start, unsigned long end, int direction) { long i, t; ucrun_t *run; run = (ucrun_t *) malloc(sizeof(ucrun_t)); run->visual_next = run->visual_prev = 0; run->direction = direction; run->cursor = ~0; run->chars = (unsigned long *) malloc(sizeof(unsigned long) * ((end - start) << 1)); run->positions = run->chars + (end - start); run->source = src; run->start = start; run->end = end; if (direction == UCPGBA_RTL) { /* * Copy the source text into the run in reverse order and select * replacements for the pairwise punctuation and the <> characters. */ for (i = 0, t = end - 1; start < end; start++, t--, i++) { run->positions[i] = t; if (ucissymmetric(src[t]) || src[t] == '<' || src[t] == '>') run->chars[i] = _ucsymmetric_pair(src[t]); else run->chars[i] = src[t]; } } else { /* * Copy the source text into the run directly. */ for (i = start; i < end; i++) { run->positions[i - start] = i; run->chars[i - start] = src[i]; } } /* * Add the run to the logical list for cursor traversal. */ if (str->logical_first == 0) str->logical_first = str->logical_last = run; else { run->logical_prev = str->logical_last; str->logical_last->logical_next = run; str->logical_last = run; } return run; } static void _ucadd_rtl_segment(ucstring_t *str, unsigned long *source, unsigned long start, unsigned long end) { unsigned long s, e; ucrun_t *run, *lrun; /* * This is used to splice runs into strings with overall LTR direction. * The `lrun' variable will never be NULL because at least one LTR run was * added before this RTL run. */ lrun = str->visual_last; for (e = s = start; s < end;) { for (; e < end && ISRTL_NEUTRAL(source[e]); e++) ; if (e > s) { run = _add_run(str, source, s, e, UCPGBA_RTL); /* * Add the run to the visual list for cursor traversal. */ if (str->visual_first != 0) { if (str->direction == UCPGBA_LTR) { run->visual_prev = lrun; run->visual_next = lrun->visual_next; if (lrun->visual_next != 0) lrun->visual_next->visual_prev = run; lrun->visual_next = run; if (lrun == str->visual_last) str->visual_last = run; } else { run->visual_next = str->visual_first; str->visual_first->visual_prev = run; str->visual_first = run; } } else str->visual_first = str->visual_last = run; } /* * Handle digits in a special way. This makes sure the weakly * directional characters appear on the expected sides of a number * depending on whether that number is Arabic or not. */ for (s = e; e < end && ISWEAKSPECIAL(source[e]); e++) { if (!ISDIGITSPECIAL(source[e]) && (e + 1 == end || !ISDIGITSPECIAL(source[e + 1]))) break; } if (e > s) { run = _add_run(str, source, s, e, UCPGBA_LTR); /* * Add the run to the visual list for cursor traversal. */ if (str->visual_first != 0) { if (str->direction == UCPGBA_LTR) { run->visual_prev = lrun; run->visual_next = lrun->visual_next; if (lrun->visual_next != 0) lrun->visual_next->visual_prev = run; lrun->visual_next = run; if (lrun == str->visual_last) str->visual_last = run; } else { run->visual_next = str->visual_first; str->visual_first->visual_prev = run; str->visual_first = run; } } else str->visual_first = str->visual_last = run; } /* * Collect all weak non-digit sequences for an RTL segment. These * will appear as part of the next RTL segment or will be added as * an RTL segment by themselves. */ for (s = e; e < end && ucisweak(source[e]) && !ucisdigit(source[e]); e++) ; } /* * Capture any weak non-digit sequences that occur at the end of the RTL * run. */ if (e > s) { run = _add_run(str, source, s, e, UCPGBA_RTL); /* * Add the run to the visual list for cursor traversal. */ if (str->visual_first != 0) { if (str->direction == UCPGBA_LTR) { run->visual_prev = lrun; run->visual_next = lrun->visual_next; if (lrun->visual_next != 0) lrun->visual_next->visual_prev = run; lrun->visual_next = run; if (lrun == str->visual_last) str->visual_last = run; } else { run->visual_next = str->visual_first; str->visual_first->visual_prev = run; str->visual_first = run; } } else str->visual_first = str->visual_last = run; } } static void _ucadd_ltr_segment(ucstring_t *str, unsigned long *source, unsigned long start, unsigned long end) { ucrun_t *run; run = _add_run(str, source, start, end, UCPGBA_LTR); /* * Add the run to the visual list for cursor traversal. */ if (str->visual_first != 0) { if (str->direction == UCPGBA_LTR) { run->visual_prev = str->visual_last; str->visual_last->visual_next = run; str->visual_last = run; } else { run->visual_next = str->visual_first; str->visual_first->visual_prev = run; str->visual_first = run; } } else str->visual_first = str->visual_last = run; } ucstring_t * ucstring_create(unsigned long *source, unsigned long start, unsigned long end, int default_direction, int cursor_motion) { int rtl_first; unsigned long s, e, ld; ucstring_t *str; str = (ucstring_t *) malloc(sizeof(ucstring_t)); /* * Set the initial values. */ str->cursor_motion = cursor_motion; str->logical_first = str->logical_last = 0; str->visual_first = str->visual_last = str->cursor = 0; str->source = source; str->start = start; str->end = end; /* * If the length of the string is 0, then just return it at this point. */ if (start == end) return str; /* * This flag indicates whether the collection loop for RTL is called * before the LTR loop the first time. */ rtl_first = 0; /* * Look for the first character in the string that has strong * directionality. */ for (s = start; s < end && !ucisstrong(source[s]); s++) ; if (s == end) /* * If the string contains no characters with strong directionality, use * the default direction. */ str->direction = default_direction; else str->direction = ucisrtl(source[s]) ? UCPGBA_RTL : UCPGBA_LTR; if (str->direction == UCPGBA_RTL) /* * Set the flag that causes the RTL collection loop to run first. */ rtl_first = 1; /* * This loop now separates the string into runs based on directionality. */ for (s = e = 0; s < end; s = e) { if (!rtl_first) { /* * Determine the next run of LTR text. */ ld = s; while (e < end && ISLTR_LTR(source[e])) { if (ucisdigit(source[e]) && !(0x660 <= source[e] && source[e] <= 0x669)) ld = e; e++; } if (str->direction != UCPGBA_LTR) { while (e > ld && ISWEAK_NEUTRAL(source[e - 1])) e--; } /* * Add the LTR segment to the string. */ if (e > s) _ucadd_ltr_segment(str, source, s, e); } /* * Determine the next run of RTL text. */ ld = s = e; while (e < end && ISRTL_RTL(source[e])) { if (ucisdigit(source[e]) && !(0x660 <= source[e] && source[e] <= 0x669)) ld = e; e++; } if (str->direction != UCPGBA_RTL) { while (e > ld && ISWEAK_NEUTRAL(source[e - 1])) e--; } /* * Add the RTL segment to the string. */ if (e > s) _ucadd_rtl_segment(str, source, s, e); /* * Clear the flag that allowed the RTL collection loop to run first * for strings with overall RTL directionality. */ rtl_first = 0; } /* * Set up the initial cursor run. */ str->cursor = str->logical_first; if (str != 0) str->cursor->cursor = (str->cursor->direction == UCPGBA_RTL) ? str->cursor->end - str->cursor->start : 0; return str; } void ucstring_free(ucstring_t *s) { ucrun_t *l, *r; if (s == 0) return; for (l = 0, r = s->visual_first; r != 0; r = r->visual_next) { if (r->end > r->start) free((char *) r->chars); if (l) free((char *) l); l = r; } if (l) free((char *) l); free((char *) s); } int ucstring_set_cursor_motion(ucstring_t *str, int cursor_motion) { int n; if (str == 0) return -1; n = str->cursor_motion; str->cursor_motion = cursor_motion; return n; } static int _ucstring_visual_cursor_right(ucstring_t *str, int count) { int cnt = count; unsigned long size; ucrun_t *cursor; if (str == 0) return 0; cursor = str->cursor; while (cnt > 0) { size = cursor->end - cursor->start; if ((cursor->direction == UCPGBA_RTL && cursor->cursor + 1 == size) || cursor->cursor + 1 > size) { /* * If the next run is NULL, then the cursor is already on the * far right end already. */ if (cursor->visual_next == 0) /* * If movement occurred, then report it. */ return (cnt != count); /* * Move to the next run. */ str->cursor = cursor = cursor->visual_next; cursor->cursor = (cursor->direction == UCPGBA_RTL) ? -1 : 0; size = cursor->end - cursor->start; } else cursor->cursor++; cnt--; } return 1; } static int _ucstring_logical_cursor_right(ucstring_t *str, int count) { int cnt = count; unsigned long size; ucrun_t *cursor; if (str == 0) return 0; cursor = str->cursor; while (cnt > 0) { size = cursor->end - cursor->start; if (str->direction == UCPGBA_RTL) { if (cursor->direction == UCPGBA_RTL) { if (cursor->cursor + 1 == size) { if (cursor == str->logical_first) /* * Already at the beginning of the string. */ return (cnt != count); str->cursor = cursor = cursor->logical_prev; size = cursor->end - cursor->start; cursor->cursor = (cursor->direction == UCPGBA_LTR) ? size : 0; } else cursor->cursor++; } else { if (cursor->cursor == 0) { if (cursor == str->logical_first) /* * At the beginning of the string already. */ return (cnt != count); str->cursor = cursor = cursor->logical_prev; size = cursor->end - cursor->start; cursor->cursor = (cursor->direction == UCPGBA_LTR) ? size : 0; } else cursor->cursor--; } } else { if (cursor->direction == UCPGBA_RTL) { if (cursor->cursor == 0) { if (cursor == str->logical_last) /* * Already at the end of the string. */ return (cnt != count); str->cursor = cursor = cursor->logical_next; size = cursor->end - cursor->start; cursor->cursor = (cursor->direction == UCPGBA_LTR) ? 0 : size - 1; } else cursor->cursor--; } else { if (cursor->cursor + 1 > size) { if (cursor == str->logical_last) /* * Already at the end of the string. */ return (cnt != count); str->cursor = cursor = cursor->logical_next; cursor->cursor = (cursor->direction == UCPGBA_LTR) ? 0 : size - 1; } else cursor->cursor++; } } cnt--; } return 1; } int ucstring_cursor_right(ucstring_t *str, int count) { if (str == 0) return 0; return (str->cursor_motion == UCPGBA_CURSOR_VISUAL) ? _ucstring_visual_cursor_right(str, count) : _ucstring_logical_cursor_right(str, count); } static int _ucstring_visual_cursor_left(ucstring_t *str, int count) { int cnt = count; unsigned long size; ucrun_t *cursor; if (str == 0) return 0; cursor = str->cursor; while (cnt > 0) { size = cursor->end - cursor->start; if ((cursor->direction == UCPGBA_LTR && cursor->cursor == 0) || cursor->cursor - 1 < -1) { /* * If the preceding run is NULL, then the cursor is already on the * far left end already. */ if (cursor->visual_prev == 0) /* * If movement occurred, then report it. */ return (cnt != count); /* * Move to the previous run. */ str->cursor = cursor = cursor->visual_prev; size = cursor->end - cursor->start; cursor->cursor = (cursor->direction == UCPGBA_RTL) ? size : size - 1; } else cursor->cursor--; cnt--; } return 1; } static int _ucstring_logical_cursor_left(ucstring_t *str, int count) { int cnt = count; unsigned long size; ucrun_t *cursor; if (str == 0) return 0; cursor = str->cursor; while (cnt > 0) { size = cursor->end - cursor->start; if (str->direction == UCPGBA_RTL) { if (cursor->direction == UCPGBA_RTL) { if (cursor->cursor == -1) { if (cursor == str->logical_last) /* * Already at the end of the string. */ return (cnt != count); str->cursor = cursor = cursor->logical_next; size = cursor->end - cursor->start; cursor->cursor = (cursor->direction == UCPGBA_LTR) ? 0 : size - 1; } else cursor->cursor--; } else { if (cursor->cursor + 1 > size) { if (cursor == str->logical_last) /* * At the end of the string already. */ return (cnt != count); str->cursor = cursor = cursor->logical_next; size = cursor->end - cursor->start; cursor->cursor = (cursor->direction == UCPGBA_LTR) ? 0 : size - 1; } else cursor->cursor++; } } else { if (cursor->direction == UCPGBA_RTL) { if (cursor->cursor + 1 == size) { if (cursor == str->logical_first) /* * Already at the beginning of the string. */ return (cnt != count); str->cursor = cursor = cursor->logical_prev; size = cursor->end - cursor->start; cursor->cursor = (cursor->direction == UCPGBA_LTR) ? size : 0; } else cursor->cursor++; } else { if (cursor->cursor == 0) { if (cursor == str->logical_first) /* * Already at the beginning of the string. */ return (cnt != count); str->cursor = cursor = cursor->logical_prev; cursor->cursor = (cursor->direction == UCPGBA_LTR) ? size : 0; } else cursor->cursor--; } } cnt--; } return 1; } int ucstring_cursor_left(ucstring_t *str, int count) { if (str == 0) return 0; return (str->cursor_motion == UCPGBA_CURSOR_VISUAL) ? _ucstring_visual_cursor_left(str, count) : _ucstring_logical_cursor_left(str, count); } void ucstring_cursor_info(ucstring_t *str, int *direction, unsigned long *position) { long c; unsigned long size; ucrun_t *cursor; if (str == 0 || direction == 0 || position == 0) return; cursor = str->cursor; *direction = cursor->direction; c = cursor->cursor; size = cursor->end - cursor->start; if (c == size) *position = (cursor->direction == UCPGBA_RTL) ? cursor->start : cursor->positions[c - 1]; else if (c == -1) *position = (cursor->direction == UCPGBA_RTL) ? cursor->end : cursor->start; else *position = cursor->positions[c]; } openldap-2.5.11+dfsg/libraries/liblunicode/ucdata/MUTTUCData.txt0000644000175000017500000002346614172327167023134 0ustar ryanryan# # $Id: MUTTUCData.txt,v 1.3 1999/10/29 00:04:35 mleisher Exp $ # # Copyright 1999 Computing Research Labs, New Mexico State University # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT # OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR # THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # # Implementation specific character properties. # # # Space, other. # 0009;;Ss;;;;;;;;;;;; 000A;;Ss;;;;;;;;;;;; 000B;;Ss;;;;;;;;;;;; 000C;;Ss;;;;;;;;;;;; 000D;;Ss;;;;;;;;;;;; # # Non-breaking. # 00A0;;Nb;;;;;;;;;;;; 2007;;Nb;;;;;;;;;;;; 2011;;Nb;;;;;;;;;;;; FEFF;;Nb;;;;;;;;;;;; # # Symmetric. # 0028;;Sy;;;;;;;;;;;; 0029;;Sy;;;;;;;;;;;; 005B;;Sy;;;;;;;;;;;; 005D;;Sy;;;;;;;;;;;; 007B;;Sy;;;;;;;;;;;; 007D;;Sy;;;;;;;;;;;; 00AB;;Sy;;;;;;;;;;;; 00BB;;Sy;;;;;;;;;;;; 0F3A;;Sy;;;;;;;;;;;; 0F3B;;Sy;;;;;;;;;;;; 0F3C;;Sy;;;;;;;;;;;; 0F3D;;Sy;;;;;;;;;;;; 0F3E;;Sy;;;;;;;;;;;; 0F3F;;Sy;;;;;;;;;;;; 2018;;Sy;;;;;;;;;;;; 2019;;Sy;;;;;;;;;;;; 201A;;Sy;;;;;;;;;;;; 201B;;Sy;;;;;;;;;;;; 201C;;Sy;;;;;;;;;;;; 201D;;Sy;;;;;;;;;;;; 201E;;Sy;;;;;;;;;;;; 201F;;Sy;;;;;;;;;;;; 2039;;Sy;;;;;;;;;;;; 203A;;Sy;;;;;;;;;;;; 2045;;Sy;;;;;;;;;;;; 2046;;Sy;;;;;;;;;;;; 207D;;Sy;;;;;;;;;;;; 207E;;Sy;;;;;;;;;;;; 208D;;Sy;;;;;;;;;;;; 208E;;Sy;;;;;;;;;;;; 2329;;Sy;;;;;;;;;;;; 232A;;Sy;;;;;;;;;;;; 3008;;Sy;;;;;;;;;;;; 3009;;Sy;;;;;;;;;;;; 300A;;Sy;;;;;;;;;;;; 300B;;Sy;;;;;;;;;;;; 300C;;Sy;;;;;;;;;;;; 300D;;Sy;;;;;;;;;;;; 300E;;Sy;;;;;;;;;;;; 300F;;Sy;;;;;;;;;;;; 3010;;Sy;;;;;;;;;;;; 3011;;Sy;;;;;;;;;;;; 3014;;Sy;;;;;;;;;;;; 3015;;Sy;;;;;;;;;;;; 3016;;Sy;;;;;;;;;;;; 3017;;Sy;;;;;;;;;;;; 3018;;Sy;;;;;;;;;;;; 3019;;Sy;;;;;;;;;;;; 301A;;Sy;;;;;;;;;;;; 301B;;Sy;;;;;;;;;;;; 301D;;Sy;;;;;;;;;;;; 301E;;Sy;;;;;;;;;;;; 301F;;Sy;;;;;;;;;;;; FD3E;;Sy;;;;;;;;;;;; FD3F;;Sy;;;;;;;;;;;; FE35;;Sy;;;;;;;;;;;; FE36;;Sy;;;;;;;;;;;; FE37;;Sy;;;;;;;;;;;; FE38;;Sy;;;;;;;;;;;; FE39;;Sy;;;;;;;;;;;; FE3A;;Sy;;;;;;;;;;;; FE3B;;Sy;;;;;;;;;;;; FE3C;;Sy;;;;;;;;;;;; FE3D;;Sy;;;;;;;;;;;; FE3E;;Sy;;;;;;;;;;;; FE3F;;Sy;;;;;;;;;;;; FE40;;Sy;;;;;;;;;;;; FE41;;Sy;;;;;;;;;;;; FE42;;Sy;;;;;;;;;;;; FE43;;Sy;;;;;;;;;;;; FE44;;Sy;;;;;;;;;;;; FE59;;Sy;;;;;;;;;;;; FE5A;;Sy;;;;;;;;;;;; FE5B;;Sy;;;;;;;;;;;; FE5C;;Sy;;;;;;;;;;;; FE5D;;Sy;;;;;;;;;;;; FE5E;;Sy;;;;;;;;;;;; FF08;;Sy;;;;;;;;;;;; FF09;;Sy;;;;;;;;;;;; FF3B;;Sy;;;;;;;;;;;; FF3D;;Sy;;;;;;;;;;;; FF5B;;Sy;;;;;;;;;;;; FF5D;;Sy;;;;;;;;;;;; FF62;;Sy;;;;;;;;;;;; FF63;;Sy;;;;;;;;;;;; # # Hex digit. # 0030;;Hd;;;;;;;;;;;; 0031;;Hd;;;;;;;;;;;; 0032;;Hd;;;;;;;;;;;; 0033;;Hd;;;;;;;;;;;; 0034;;Hd;;;;;;;;;;;; 0035;;Hd;;;;;;;;;;;; 0036;;Hd;;;;;;;;;;;; 0037;;Hd;;;;;;;;;;;; 0038;;Hd;;;;;;;;;;;; 0039;;Hd;;;;;;;;;;;; 0041;;Hd;;;;;;;;;;;; 0042;;Hd;;;;;;;;;;;; 0043;;Hd;;;;;;;;;;;; 0044;;Hd;;;;;;;;;;;; 0045;;Hd;;;;;;;;;;;; 0046;;Hd;;;;;;;;;;;; 0061;;Hd;;;;;;;;;;;; 0062;;Hd;;;;;;;;;;;; 0063;;Hd;;;;;;;;;;;; 0064;;Hd;;;;;;;;;;;; 0065;;Hd;;;;;;;;;;;; 0066;;Hd;;;;;;;;;;;; FF10;;Hd;;;;;;;;;;;; FF11;;Hd;;;;;;;;;;;; FF12;;Hd;;;;;;;;;;;; FF13;;Hd;;;;;;;;;;;; FF14;;Hd;;;;;;;;;;;; FF15;;Hd;;;;;;;;;;;; FF16;;Hd;;;;;;;;;;;; FF17;;Hd;;;;;;;;;;;; FF18;;Hd;;;;;;;;;;;; FF19;;Hd;;;;;;;;;;;; FF21;;Hd;;;;;;;;;;;; FF22;;Hd;;;;;;;;;;;; FF23;;Hd;;;;;;;;;;;; FF24;;Hd;;;;;;;;;;;; FF25;;Hd;;;;;;;;;;;; FF26;;Hd;;;;;;;;;;;; FF41;;Hd;;;;;;;;;;;; FF42;;Hd;;;;;;;;;;;; FF43;;Hd;;;;;;;;;;;; FF44;;Hd;;;;;;;;;;;; FF45;;Hd;;;;;;;;;;;; FF46;;Hd;;;;;;;;;;;; # # Quote marks. # 0022;;Qm;;;;;;;;;;;; 0027;;Qm;;;;;;;;;;;; 00AB;;Qm;;;;;;;;;;;; 00BB;;Qm;;;;;;;;;;;; 2018;;Qm;;;;;;;;;;;; 2019;;Qm;;;;;;;;;;;; 201A;;Qm;;;;;;;;;;;; 201B;;Qm;;;;;;;;;;;; 201C;;Qm;;;;;;;;;;;; 201D;;Qm;;;;;;;;;;;; 201E;;Qm;;;;;;;;;;;; 201F;;Qm;;;;;;;;;;;; 2039;;Qm;;;;;;;;;;;; 203A;;Qm;;;;;;;;;;;; 300C;;Qm;;;;;;;;;;;; 300D;;Qm;;;;;;;;;;;; 300E;;Qm;;;;;;;;;;;; 300F;;Qm;;;;;;;;;;;; 301D;;Qm;;;;;;;;;;;; 301E;;Qm;;;;;;;;;;;; 301F;;Qm;;;;;;;;;;;; FE41;;Qm;;;;;;;;;;;; FE42;;Qm;;;;;;;;;;;; FE43;;Qm;;;;;;;;;;;; FE44;;Qm;;;;;;;;;;;; FF02;;Qm;;;;;;;;;;;; FF07;;Qm;;;;;;;;;;;; FF62;;Qm;;;;;;;;;;;; FF63;;Qm;;;;;;;;;;;; # # Special Devanagari forms # E900;DEVANAGARI KSHA LIGATURE;Lo;0;L;0915 094D 0937;;;;N;;;;; E901;DEVANAGARI GNYA LIGATURE;Lo;0;L;091C 094D 091E;;;;N;;;;; E902;DEVANAGARI TTA LIGATURE;Lo;0;L;0924 094D 0924;;;;N;;;;; E903;DEVANAGARI TRA LIGATURE;Lo;0;L;0924 094D 0930;;;;N;;;;; E904;DEVANAGARI SHCHA LIGATURE;Lo;0;L;0936 094D 091B;;;;N;;;;; E905;DEVANAGARI SHRA LIGATURE;Lo;0;L;0936 094D 0930;;;;N;;;;; E906;DEVANAGARI SHVA LIGATURE;Lo;0;L;0936 094D 0935;;;;N;;;;; E907;DEVANAGARI KRA LIGATURE;Lo;0;L;;;;;N;;;;; E908;DEVANAGARI JRA LIGATURE;Lo;0;L;;;;;N;;;;; E909;DEVANAGARI ZRA LIGATURE;Lo;0;L;;;;;N;;;;; E90A;DEVANAGARI PHRA LIGATURE;Lo;0;L;;;;;N;;;;; E90B;DEVANAGARI FRA LIGATURE;Lo;0;L;;;;;N;;;;; E90C;DEVANAGARI PRA LIGATURE;Lo;0;L;;;;;N;;;;; E90D;DEVANAGARI SRA LIGATURE;Lo;0;L;;;;;N;;;;; E90E;DEVANAGARI RU LIGATURE;Lo;0;L;;;;;N;;;;; E90F;DEVANAGARI RUU LIGATURE;Lo;0;L;;;;;N;;;;; E915;DEVANAGARI HALF LETTER KA;Lo;0;L;;;;;N;;;;; E916;DEVANAGARI HALF LETTER KHA;Lo;0;L;;;;;N;;;;; E917;DEVANAGARI HALF LETTER GA;Lo;0;L;;;;;N;;;;; E918;DEVANAGARI HALF LETTER GHA;Lo;0;L;;;;;N;;;;; E919;DEVANAGARI HALF LETTER NGA;Lo;0;L;;;;;N;;;;; E91A;DEVANAGARI HALF LETTER CA;Lo;0;L;;;;;N;;;;; E91B;DEVANAGARI HALF LETTER CHA;Lo;0;L;;;;;N;;;;; E91C;DEVANAGARI HALF LETTER JA;Lo;0;L;;;;;N;;;;; E91D;DEVANAGARI HALF LETTER JHA;Lo;0;L;;;;;N;;;;; E91E;DEVANAGARI HALF LETTER NYA;Lo;0;L;;;;;N;;;;; E91F;DEVANAGARI HALF LETTER TTA;Lo;0;L;;;;;N;;;;; E920;DEVANAGARI HALF LETTER TTHA;Lo;0;L;;;;;N;;;;; E921;DEVANAGARI HALF LETTER DDA;Lo;0;L;;;;;N;;;;; E922;DEVANAGARI HALF LETTER DDHA;Lo;0;L;;;;;N;;;;; E923;DEVANAGARI HALF LETTER NNA;Lo;0;L;;;;;N;;;;; E924;DEVANAGARI HALF LETTER TA;Lo;0;L;;;;;N;;;;; E925;DEVANAGARI HALF LETTER THA;Lo;0;L;;;;;N;;;;; E926;DEVANAGARI HALF LETTER DA;Lo;0;L;;;;;N;;;;; E927;DEVANAGARI HALF LETTER DHA;Lo;0;L;;;;;N;;;;; E928;DEVANAGARI HALF LETTER NA;Lo;0;L;;;;;N;;;;; E929;DEVANAGARI HALF LETTER NNNA;Lo;0;L;0928 093C;;;;N;;;;; E92A;DEVANAGARI HALF LETTER PA;Lo;0;L;;;;;N;;;;; E92B;DEVANAGARI HALF LETTER PHA;Lo;0;L;;;;;N;;;;; E92C;DEVANAGARI HALF LETTER BA;Lo;0;L;;;;;N;;;;; E92D;DEVANAGARI HALF LETTER BHA;Lo;0;L;;;;;N;;;;; E92E;DEVANAGARI HALF LETTER MA;Lo;0;L;;;;;N;;;;; E92F;DEVANAGARI HALF LETTER YA;Lo;0;L;;;;;N;;;;; E930;DEVANAGARI HALF LETTER RA;Lo;0;L;;;;;N;;;;; E931;DEVANAGARI HALF LETTER RRA;Lo;0;L;0930 093C;;;;N;;;;; E932;DEVANAGARI HALF LETTER LA;Lo;0;L;;;;;N;;;;; E933;DEVANAGARI HALF LETTER LLA;Lo;0;L;;;;;N;;;;; E934;DEVANAGARI HALF LETTER LLLA;Lo;0;L;0933 093C;;;;N;;;;; E935;DEVANAGARI HALF LETTER VA;Lo;0;L;;;;;N;;;;; E936;DEVANAGARI HALF LETTER SHA;Lo;0;L;;;;;N;;;;; E937;DEVANAGARI HALF LETTER SSA;Lo;0;L;;;;;N;;;;; E938;DEVANAGARI HALF LETTER SA;Lo;0;L;;;;;N;;;;; E939;DEVANAGARI HALF LETTER HA;Lo;0;L;;;;;N;;;;; E940;DEVANAGARI KKA LIGATURE;Lo;0;L;0915 094D 0915;;;;N;;;;; E941;DEVANAGARI KTA LIGATURE;Lo;0;L;0915 094D 0924;;;;N;;;;; E942;DEVANAGARI NGKA LIGATURE;Lo;0;L;0919 094D 0915;;;;N;;;;; E943;DEVANAGARI NGKHA LIGATURE;Lo;0;L;0919 094D 0916;;;;N;;;;; E944;DEVANAGARI NGGA LIGATURE;Lo;0;L;0919 094D 0917;;;;N;;;;; E945;DEVANAGARI NGGHA LIGATURE;Lo;0;L;0919 094D 0918;;;;N;;;;; E946;DEVANAGARI NYJA LIGATURE;Lo;0;L;091E 094D 091C;;;;N;;;;; E947;DEVANAGARI DGHA LIGATURE;Lo;0;L;0926 094D 0918;;;;N;;;;; E948;DEVANAGARI DDA LIGATURE;Lo;0;L;0926 094D 0926;;;;N;;;;; E949;DEVANAGARI DDHA LIGATURE;Lo;0;L;0926 094D 0927;;;;N;;;;; E94A;DEVANAGARI DBA LIGATURE;Lo;0;L;0926 094D 092C;;;;N;;;;; E94B;DEVANAGARI DBHA LIGATURE;Lo;0;L;0926 094D 092D;;;;N;;;;; E94C;DEVANAGARI DMA LIGATURE;Lo;0;L;0926 094D 092E;;;;N;;;;; E94D;DEVANAGARI DYA LIGATURE;Lo;0;L;0926 094D 092F;;;;N;;;;; E94E;DEVANAGARI DVA LIGATURE;Lo;0;L;0926 094D 0935;;;;N;;;;; E94F;DEVANAGARI TT-TTA LIGATURE;Lo;0;L;091F 094D 091F;;;;N;;;;; E950;DEVANAGARI TT-TTHA LIGATURE;Lo;0;L;091F 094D 0920;;;;N;;;;; E951;DEVANAGARI TTH-TTHA LIGATURE;Lo;0;L;0920 094D 0920;;;;N;;;;; E952;DEVANAGARI DD-GA LIGATURE;Lo;0;L;0921 094D 0917;;;;N;;;;; E953;DEVANAGARI DD-DDA LIGATURE;Lo;0;L;0921 094D 0921;;;;N;;;;; E954;DEVANAGARI DD-DDHA LIGATURE;Lo;0;L;0921 094D 0922;;;;N;;;;; E955;DEVANAGARI NNA LIGATURE;Lo;0;L;0928 094D 0928;;;;N;;;;; E956;DEVANAGARI HMA LIGATURE;Lo;0;L;0939 094D 092E;;;;N;;;;; E957;DEVANAGARI HYA LIGATURE;Lo;0;L;0939 094D 092F;;;;N;;;;; E958;DEVANAGARI HLA LIGATURE;Lo;0;L;0939 094D 0932;;;;N;;;;; E959;DEVANAGARI HVA LIGATURE;Lo;0;L;0939 094D 0935;;;;N;;;;; E95A;DEVANAGARI STRA LIGATURE;Lo;0;L;0938 094D 0924 094D 0930;;;;N;;;;; E970;DEVANAGARI HALF KSHA LIGATURE;Lo;0;L;0915 094D 0937;;;;N;;;;; E971;DEVANAGARI HALF GNYA LIGATURE;Lo;0;L;091C 094D 091E;;;;N;;;;; E972;DEVANAGARI HALF TTA LIGATURE;Lo;0;L;0924 094D 0924;;;;N;;;;; E973;DEVANAGARI HALF TRA LIGATURE;Lo;0;L;0924 094D 0930;;;;N;;;;; E974;DEVANAGARI HALF SHCHA LIGATURE;Lo;0;L;0936 094D 091B;;;;N;;;;; E975;DEVANAGARI HALF SHRA LIGATURE;Lo;0;L;0936 094D 0930;;;;N;;;;; E976;DEVANAGARI HALF SHVA LIGATURE;Lo;0;L;0936 094D 0935;;;;N;;;;; E97B;DEVANAGARI SIGN RRA-REPHA;Mn;36;L;;;;;N;;;;; E97C;DEVANAGARI HAR LIGATURE;Lo;0;L;0939 0943;;;;N;;;;; E97D;DEVANAGARI SIGN EYELASH RA;Lo;0;L;;;;;N;;;;; E97E;DEVANAGARI SIGN REPHA;Mn;36;L;;;;;N;;;;; E97F;DEVANAGARI SIGN SUBJOINED RA;Mn;36;L;;;;;N;;;;; openldap-2.5.11+dfsg/libraries/liblunicode/ucdata/ucdata.c0000644000175000017500000010713314172327167022157 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Copyright 2001 Computing Research Labs, New Mexico State University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* $Id: ucdata.c,v 1.4 2001/01/02 18:46:20 mleisher Exp $" */ #include "portable.h" #include "ldap_config.h" #include #include #include #include #include #include "lber_pvt.h" #include "ucdata.h" #ifndef HARDCODE_DATA #define HARDCODE_DATA 1 #endif #if HARDCODE_DATA #include "uctable.h" #endif /************************************************************************** * * Miscellaneous types, data, and support functions. * **************************************************************************/ typedef struct { ac_uint2 bom; ac_uint2 cnt; union { ac_uint4 bytes; ac_uint2 len[2]; } size; } _ucheader_t; /* * A simple array of 32-bit masks for lookup. */ static ac_uint4 masks32[32] = { 0x00000001UL, 0x00000002UL, 0x00000004UL, 0x00000008UL, 0x00000010UL, 0x00000020UL, 0x00000040UL, 0x00000080UL, 0x00000100UL, 0x00000200UL, 0x00000400UL, 0x00000800UL, 0x00001000UL, 0x00002000UL, 0x00004000UL, 0x00008000UL, 0x00010000UL, 0x00020000UL, 0x00040000UL, 0x00080000UL, 0x00100000UL, 0x00200000UL, 0x00400000UL, 0x00800000UL, 0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, 0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL }; #define endian_short(cc) (((cc) >> 8) | (((cc) & 0xff) << 8)) #define endian_long(cc) ((((cc) & 0xff) << 24)|((((cc) >> 8) & 0xff) << 16)|\ ((((cc) >> 16) & 0xff) << 8)|((cc) >> 24)) #if !HARDCODE_DATA static FILE * _ucopenfile(char *paths, char *filename, char *mode) { FILE *f; char *fp, *dp, *pp, path[BUFSIZ]; if (filename == 0 || *filename == 0) return 0; dp = paths; while (dp && *dp) { pp = path; while (*dp && *dp != ':') *pp++ = *dp++; *pp++ = *LDAP_DIRSEP; fp = filename; while (*fp) *pp++ = *fp++; *pp = 0; if ((f = fopen(path, mode)) != 0) return f; if (*dp == ':') dp++; } return 0; } #endif /************************************************************************** * * Support for the character properties. * **************************************************************************/ #if !HARDCODE_DATA static ac_uint4 _ucprop_size; static ac_uint2 *_ucprop_offsets; static ac_uint4 *_ucprop_ranges; /* * Return -1 on error, 0 if okay */ static int _ucprop_load(char *paths, int reload) { FILE *in; ac_uint4 size, i; _ucheader_t hdr; if (_ucprop_size > 0) { if (!reload) /* * The character properties have already been loaded. */ return 0; /* * Unload the current character property data in preparation for * loading a new copy. Only the first array has to be deallocated * because all the memory for the arrays is allocated as a single * block. */ free((char *) _ucprop_offsets); _ucprop_size = 0; } if ((in = _ucopenfile(paths, "ctype.dat", "rb")) == 0) return -1; /* * Load the header. */ fread((char *) &hdr, sizeof(_ucheader_t), 1, in); if (hdr.bom == 0xfffe) { hdr.cnt = endian_short(hdr.cnt); hdr.size.bytes = endian_long(hdr.size.bytes); } if ((_ucprop_size = hdr.cnt) == 0) { fclose(in); return -1; } /* * Allocate all the storage needed for the lookup table. */ _ucprop_offsets = (ac_uint2 *) malloc(hdr.size.bytes); /* * Calculate the offset into the storage for the ranges. The offsets * array is on a 4-byte boundary and one larger than the value provided in * the header count field. This means the offset to the ranges must be * calculated after aligning the count to a 4-byte boundary. */ if ((size = ((hdr.cnt + 1) * sizeof(ac_uint2))) & 3) size += 4 - (size & 3); size >>= 1; _ucprop_ranges = (ac_uint4 *) (_ucprop_offsets + size); /* * Load the offset array. */ fread((char *) _ucprop_offsets, sizeof(ac_uint2), size, in); /* * Do an endian swap if necessary. Don't forget there is an extra node on * the end with the final index. */ if (hdr.bom == 0xfffe) { for (i = 0; i <= _ucprop_size; i++) _ucprop_offsets[i] = endian_short(_ucprop_offsets[i]); } /* * Load the ranges. The number of elements is in the last array position * of the offsets. */ fread((char *) _ucprop_ranges, sizeof(ac_uint4), _ucprop_offsets[_ucprop_size], in); fclose(in); /* * Do an endian swap if necessary. */ if (hdr.bom == 0xfffe) { for (i = 0; i < _ucprop_offsets[_ucprop_size]; i++) _ucprop_ranges[i] = endian_long(_ucprop_ranges[i]); } return 0; } static void _ucprop_unload(void) { if (_ucprop_size == 0) return; /* * Only need to free the offsets because the memory is allocated as a * single block. */ free((char *) _ucprop_offsets); _ucprop_size = 0; } #endif static int _ucprop_lookup(ac_uint4 code, ac_uint4 n) { long l, r, m; if (_ucprop_size == 0) return 0; /* * There is an extra node on the end of the offsets to allow this routine * to work right. If the index is 0xffff, then there are no nodes for the * property. */ if ((l = _ucprop_offsets[n]) == 0xffff) return 0; /* * Locate the next offset that is not 0xffff. The sentinel at the end of * the array is the max index value. */ for (m = 1; n + m < _ucprop_size && _ucprop_offsets[n + m] == 0xffff; m++) ; r = _ucprop_offsets[n + m] - 1; while (l <= r) { /* * Determine a "mid" point and adjust to make sure the mid point is at * the beginning of a range pair. */ m = (l + r) >> 1; m -= (m & 1); if (code > _ucprop_ranges[m + 1]) l = m + 2; else if (code < _ucprop_ranges[m]) r = m - 2; else if (code >= _ucprop_ranges[m] && code <= _ucprop_ranges[m + 1]) return 1; } return 0; } int ucisprop(ac_uint4 code, ac_uint4 mask1, ac_uint4 mask2) { ac_uint4 i; if (mask1 == 0 && mask2 == 0) return 0; for (i = 0; mask1 && i < 32; i++) { if ((mask1 & masks32[i]) && _ucprop_lookup(code, i)) return 1; } for (i = 32; mask2 && i < _ucprop_size; i++) { if ((mask2 & masks32[i & 31]) && _ucprop_lookup(code, i)) return 1; } return 0; } /************************************************************************** * * Support for case mapping. * **************************************************************************/ #if !HARDCODE_DATA /* These record the number of slots in the map. * There are 3 words per slot. */ static ac_uint4 _uccase_size; static ac_uint2 _uccase_len[2]; static ac_uint4 *_uccase_map; /* * Return -1 on error, 0 if okay */ static int _uccase_load(char *paths, int reload) { FILE *in; ac_uint4 i; _ucheader_t hdr; if (_uccase_size > 0) { if (!reload) /* * The case mappings have already been loaded. */ return 0; free((char *) _uccase_map); _uccase_size = 0; } if ((in = _ucopenfile(paths, "case.dat", "rb")) == 0) return -1; /* * Load the header. */ fread((char *) &hdr, sizeof(_ucheader_t), 1, in); if (hdr.bom == 0xfffe) { hdr.cnt = endian_short(hdr.cnt); hdr.size.len[0] = endian_short(hdr.size.len[0]); hdr.size.len[1] = endian_short(hdr.size.len[1]); } /* * Set the node count and lengths of the upper and lower case mapping * tables. */ _uccase_size = hdr.cnt; _uccase_len[0] = hdr.size.len[0]; _uccase_len[1] = hdr.size.len[1]; _uccase_map = (ac_uint4 *) malloc(_uccase_size * 3 * sizeof(ac_uint4)); /* * Load the case mapping table. */ fread((char *) _uccase_map, sizeof(ac_uint4), _uccase_size * 3, in); /* * Do an endian swap if necessary. */ if (hdr.bom == 0xfffe) { for (i = 0; i < _uccase_size * 3; i++) _uccase_map[i] = endian_long(_uccase_map[i]); } fclose(in); return 0; } static void _uccase_unload(void) { if (_uccase_size == 0) return; free((char *) _uccase_map); _uccase_size = 0; } #endif static ac_uint4 _uccase_lookup(ac_uint4 code, long l, long r, int field) { long m; const ac_uint4 *tmp; /* * Do the binary search. */ while (l <= r) { /* * Determine a "mid" point and adjust to make sure the mid point is at * the beginning of a case mapping triple. */ m = (l + r) >> 1; tmp = &_uccase_map[m*3]; if (code > *tmp) l = m + 1; else if (code < *tmp) r = m - 1; else if (code == *tmp) return tmp[field]; } return code; } ac_uint4 uctoupper(ac_uint4 code) { int field; long l, r; if (ucisupper(code)) return code; if (ucislower(code)) { /* * The character is lower case. */ field = 2; l = _uccase_len[0]; r = (l + _uccase_len[1]) - 1; } else { /* * The character is title case. */ field = 1; l = _uccase_len[0] + _uccase_len[1]; r = _uccase_size - 1; } return _uccase_lookup(code, l, r, field); } ac_uint4 uctolower(ac_uint4 code) { int field; long l, r; if (ucislower(code)) return code; if (ucisupper(code)) { /* * The character is upper case. */ field = 1; l = 0; r = _uccase_len[0] - 1; } else { /* * The character is title case. */ field = 2; l = _uccase_len[0] + _uccase_len[1]; r = _uccase_size - 1; } return _uccase_lookup(code, l, r, field); } ac_uint4 uctotitle(ac_uint4 code) { int field; long l, r; if (ucistitle(code)) return code; /* * The offset will always be the same for converting to title case. */ field = 2; if (ucisupper(code)) { /* * The character is upper case. */ l = 0; r = _uccase_len[0] - 1; } else { /* * The character is lower case. */ l = _uccase_len[0]; r = (l + _uccase_len[1]) - 1; } return _uccase_lookup(code, l, r, field); } /************************************************************************** * * Support for compositions. * **************************************************************************/ #if !HARDCODE_DATA static ac_uint4 _uccomp_size; static ac_uint4 *_uccomp_data; /* * Return -1 on error, 0 if okay */ static int _uccomp_load(char *paths, int reload) { FILE *in; ac_uint4 size, i; _ucheader_t hdr; if (_uccomp_size > 0) { if (!reload) /* * The compositions have already been loaded. */ return 0; free((char *) _uccomp_data); _uccomp_size = 0; } if ((in = _ucopenfile(paths, "comp.dat", "rb")) == 0) return -1; /* * Load the header. */ fread((char *) &hdr, sizeof(_ucheader_t), 1, in); if (hdr.bom == 0xfffe) { hdr.cnt = endian_short(hdr.cnt); hdr.size.bytes = endian_long(hdr.size.bytes); } _uccomp_size = hdr.cnt; _uccomp_data = (ac_uint4 *) malloc(hdr.size.bytes); /* * Read the composition data in. */ size = hdr.size.bytes / sizeof(ac_uint4); fread((char *) _uccomp_data, sizeof(ac_uint4), size, in); /* * Do an endian swap if necessary. */ if (hdr.bom == 0xfffe) { for (i = 0; i < size; i++) _uccomp_data[i] = endian_long(_uccomp_data[i]); } /* * Assume that the data is ordered on count, so that all compositions * of length 2 come first. Only handling length 2 for now. */ for (i = 1; i < size; i += 4) if (_uccomp_data[i] != 2) break; _uccomp_size = i - 1; fclose(in); return 0; } static void _uccomp_unload(void) { if (_uccomp_size == 0) return; free((char *) _uccomp_data); _uccomp_size = 0; } #endif int uccomp(ac_uint4 node1, ac_uint4 node2, ac_uint4 *comp) { int l, r, m; l = 0; r = _uccomp_size - 1; while (l <= r) { m = ((r + l) >> 1); m -= m & 3; if (node1 > _uccomp_data[m+2]) l = m + 4; else if (node1 < _uccomp_data[m+2]) r = m - 4; else if (node2 > _uccomp_data[m+3]) l = m + 4; else if (node2 < _uccomp_data[m+3]) r = m - 4; else { *comp = _uccomp_data[m]; return 1; } } return 0; } int uccomp_hangul(ac_uint4 *str, int len) { const int SBase = 0xAC00, LBase = 0x1100, VBase = 0x1161, TBase = 0x11A7, LCount = 19, VCount = 21, TCount = 28, NCount = VCount * TCount, /* 588 */ SCount = LCount * NCount; /* 11172 */ int i, rlen; ac_uint4 ch, last, lindex, sindex; last = str[0]; rlen = 1; for ( i = 1; i < len; i++ ) { ch = str[i]; /* check if two current characters are L and V */ lindex = last - LBase; if (lindex < (ac_uint4) LCount) { ac_uint4 vindex = ch - VBase; if (vindex < (ac_uint4) VCount) { /* make syllable of form LV */ last = SBase + (lindex * VCount + vindex) * TCount; str[rlen-1] = last; /* reset last */ continue; } } /* check if two current characters are LV and T */ sindex = last - SBase; if (sindex < (ac_uint4) SCount && (sindex % TCount) == 0) { ac_uint4 tindex = ch - TBase; if (tindex <= (ac_uint4) TCount) { /* make syllable of form LVT */ last += tindex; str[rlen-1] = last; /* reset last */ continue; } } /* if neither case was true, just add the character */ last = ch; str[rlen] = ch; rlen++; } return rlen; } int uccanoncomp(ac_uint4 *str, int len) { int i, stpos, copos; ac_uint4 cl, prevcl, st, ch, co; st = str[0]; stpos = 0; copos = 1; prevcl = uccombining_class(st) == 0 ? 0 : 256; for (i = 1; i < len; i++) { ch = str[i]; cl = uccombining_class(ch); if (uccomp(st, ch, &co) && (prevcl < cl || prevcl == 0)) st = str[stpos] = co; else { if (cl == 0) { stpos = copos; st = ch; } prevcl = cl; str[copos++] = ch; } } return uccomp_hangul(str, copos); } /************************************************************************** * * Support for decompositions. * **************************************************************************/ #if !HARDCODE_DATA static ac_uint4 _ucdcmp_size; static ac_uint4 *_ucdcmp_nodes; static ac_uint4 *_ucdcmp_decomp; static ac_uint4 _uckdcmp_size; static ac_uint4 *_uckdcmp_nodes; static ac_uint4 *_uckdcmp_decomp; /* * Return -1 on error, 0 if okay */ static int _ucdcmp_load(char *paths, int reload) { FILE *in; ac_uint4 size, i; _ucheader_t hdr; if (_ucdcmp_size > 0) { if (!reload) /* * The decompositions have already been loaded. */ return 0; free((char *) _ucdcmp_nodes); _ucdcmp_size = 0; } if ((in = _ucopenfile(paths, "decomp.dat", "rb")) == 0) return -1; /* * Load the header. */ fread((char *) &hdr, sizeof(_ucheader_t), 1, in); if (hdr.bom == 0xfffe) { hdr.cnt = endian_short(hdr.cnt); hdr.size.bytes = endian_long(hdr.size.bytes); } _ucdcmp_size = hdr.cnt << 1; _ucdcmp_nodes = (ac_uint4 *) malloc(hdr.size.bytes); _ucdcmp_decomp = _ucdcmp_nodes + (_ucdcmp_size + 1); /* * Read the decomposition data in. */ size = hdr.size.bytes / sizeof(ac_uint4); fread((char *) _ucdcmp_nodes, sizeof(ac_uint4), size, in); /* * Do an endian swap if necessary. */ if (hdr.bom == 0xfffe) { for (i = 0; i < size; i++) _ucdcmp_nodes[i] = endian_long(_ucdcmp_nodes[i]); } fclose(in); return 0; } /* * Return -1 on error, 0 if okay */ static int _uckdcmp_load(char *paths, int reload) { FILE *in; ac_uint4 size, i; _ucheader_t hdr; if (_uckdcmp_size > 0) { if (!reload) /* * The decompositions have already been loaded. */ return 0; free((char *) _uckdcmp_nodes); _uckdcmp_size = 0; } if ((in = _ucopenfile(paths, "kdecomp.dat", "rb")) == 0) return -1; /* * Load the header. */ fread((char *) &hdr, sizeof(_ucheader_t), 1, in); if (hdr.bom == 0xfffe) { hdr.cnt = endian_short(hdr.cnt); hdr.size.bytes = endian_long(hdr.size.bytes); } _uckdcmp_size = hdr.cnt << 1; _uckdcmp_nodes = (ac_uint4 *) malloc(hdr.size.bytes); _uckdcmp_decomp = _uckdcmp_nodes + (_uckdcmp_size + 1); /* * Read the decomposition data in. */ size = hdr.size.bytes / sizeof(ac_uint4); fread((char *) _uckdcmp_nodes, sizeof(ac_uint4), size, in); /* * Do an endian swap if necessary. */ if (hdr.bom == 0xfffe) { for (i = 0; i < size; i++) _uckdcmp_nodes[i] = endian_long(_uckdcmp_nodes[i]); } fclose(in); return 0; } static void _ucdcmp_unload(void) { if (_ucdcmp_size == 0) return; /* * Only need to free the offsets because the memory is allocated as a * single block. */ free((char *) _ucdcmp_nodes); _ucdcmp_size = 0; } static void _uckdcmp_unload(void) { if (_uckdcmp_size == 0) return; /* * Only need to free the offsets because the memory is allocated as a * single block. */ free((char *) _uckdcmp_nodes); _uckdcmp_size = 0; } #endif int ucdecomp(ac_uint4 code, ac_uint4 *num, ac_uint4 **decomp) { long l, r, m; if (code < _ucdcmp_nodes[0]) { return 0; } l = 0; r = _ucdcmp_nodes[_ucdcmp_size] - 1; while (l <= r) { /* * Determine a "mid" point and adjust to make sure the mid point is at * the beginning of a code+offset pair. */ m = (l + r) >> 1; m -= (m & 1); if (code > _ucdcmp_nodes[m]) l = m + 2; else if (code < _ucdcmp_nodes[m]) r = m - 2; else if (code == _ucdcmp_nodes[m]) { *num = _ucdcmp_nodes[m + 3] - _ucdcmp_nodes[m + 1]; *decomp = (ac_uint4*)&_ucdcmp_decomp[_ucdcmp_nodes[m + 1]]; return 1; } } return 0; } int uckdecomp(ac_uint4 code, ac_uint4 *num, ac_uint4 **decomp) { long l, r, m; if (code < _uckdcmp_nodes[0]) { return 0; } l = 0; r = _uckdcmp_nodes[_uckdcmp_size] - 1; while (l <= r) { /* * Determine a "mid" point and adjust to make sure the mid point is at * the beginning of a code+offset pair. */ m = (l + r) >> 1; m -= (m & 1); if (code > _uckdcmp_nodes[m]) l = m + 2; else if (code < _uckdcmp_nodes[m]) r = m - 2; else if (code == _uckdcmp_nodes[m]) { *num = _uckdcmp_nodes[m + 3] - _uckdcmp_nodes[m + 1]; *decomp = (ac_uint4*)&_uckdcmp_decomp[_uckdcmp_nodes[m + 1]]; return 1; } } return 0; } int ucdecomp_hangul(ac_uint4 code, ac_uint4 *num, ac_uint4 decomp[]) { if (!ucishangul(code)) return 0; code -= 0xac00; decomp[0] = 0x1100 + (ac_uint4) (code / 588); decomp[1] = 0x1161 + (ac_uint4) ((code % 588) / 28); decomp[2] = 0x11a7 + (ac_uint4) (code % 28); *num = (decomp[2] != 0x11a7) ? 3 : 2; return 1; } /* mode == 0 for canonical, mode == 1 for compatibility */ static int uccanoncompatdecomp(const ac_uint4 *in, int inlen, ac_uint4 **out, int *outlen, short mode, void *ctx) { int l, size; unsigned i, j, k; ac_uint4 num, class, *decomp, hangdecomp[3]; size = inlen * 2; *out = (ac_uint4 *) ber_memalloc_x(size * sizeof(**out), ctx); if (*out == NULL) return *outlen = -1; i = 0; for (j = 0; j < (unsigned) inlen; j++) { if (mode ? uckdecomp(in[j], &num, &decomp) : ucdecomp(in[j], &num, &decomp)) { if ( size - i < num) { size = inlen + i - j + num - 1; *out = (ac_uint4 *) ber_memrealloc_x(*out, size * sizeof(**out), ctx ); if (*out == NULL) return *outlen = -1; } for (k = 0; k < num; k++) { class = uccombining_class(decomp[k]); if (class == 0) { (*out)[i] = decomp[k]; } else { for (l = i; l > 0; l--) if (class >= uccombining_class((*out)[l-1])) break; AC_MEMCPY(*out + l + 1, *out + l, (i - l) * sizeof(**out)); (*out)[l] = decomp[k]; } i++; } } else if (ucdecomp_hangul(in[j], &num, hangdecomp)) { if (size - i < num) { size = inlen + i - j + num - 1; *out = (ac_uint4 *) ber_memrealloc_x(*out, size * sizeof(**out), ctx); if (*out == NULL) return *outlen = -1; } for (k = 0; k < num; k++) { (*out)[i] = hangdecomp[k]; i++; } } else { if (size - i < 1) { size = inlen + i - j; *out = (ac_uint4 *) ber_memrealloc_x(*out, size * sizeof(**out), ctx); if (*out == NULL) return *outlen = -1; } class = uccombining_class(in[j]); if (class == 0) { (*out)[i] = in[j]; } else { for (l = i; l > 0; l--) if (class >= uccombining_class((*out)[l-1])) break; AC_MEMCPY(*out + l + 1, *out + l, (i - l) * sizeof(**out)); (*out)[l] = in[j]; } i++; } } return *outlen = i; } int uccanondecomp(const ac_uint4 *in, int inlen, ac_uint4 **out, int *outlen, void *ctx) { return uccanoncompatdecomp(in, inlen, out, outlen, 0, ctx); } int uccompatdecomp(const ac_uint4 *in, int inlen, ac_uint4 **out, int *outlen, void *ctx) { return uccanoncompatdecomp(in, inlen, out, outlen, 1, ctx); } /************************************************************************** * * Support for combining classes. * **************************************************************************/ #if !HARDCODE_DATA static ac_uint4 _uccmcl_size; static ac_uint4 *_uccmcl_nodes; /* * Return -1 on error, 0 if okay */ static int _uccmcl_load(char *paths, int reload) { FILE *in; ac_uint4 i; _ucheader_t hdr; if (_uccmcl_size > 0) { if (!reload) /* * The combining classes have already been loaded. */ return 0; free((char *) _uccmcl_nodes); _uccmcl_size = 0; } if ((in = _ucopenfile(paths, "cmbcl.dat", "rb")) == 0) return -1; /* * Load the header. */ fread((char *) &hdr, sizeof(_ucheader_t), 1, in); if (hdr.bom == 0xfffe) { hdr.cnt = endian_short(hdr.cnt); hdr.size.bytes = endian_long(hdr.size.bytes); } _uccmcl_size = hdr.cnt * 3; _uccmcl_nodes = (ac_uint4 *) malloc(hdr.size.bytes); /* * Read the combining classes in. */ fread((char *) _uccmcl_nodes, sizeof(ac_uint4), _uccmcl_size, in); /* * Do an endian swap if necessary. */ if (hdr.bom == 0xfffe) { for (i = 0; i < _uccmcl_size; i++) _uccmcl_nodes[i] = endian_long(_uccmcl_nodes[i]); } fclose(in); return 0; } static void _uccmcl_unload(void) { if (_uccmcl_size == 0) return; free((char *) _uccmcl_nodes); _uccmcl_size = 0; } #endif ac_uint4 uccombining_class(ac_uint4 code) { long l, r, m; l = 0; r = _uccmcl_size - 1; while (l <= r) { m = (l + r) >> 1; m -= (m % 3); if (code > _uccmcl_nodes[m + 1]) l = m + 3; else if (code < _uccmcl_nodes[m]) r = m - 3; else if (code >= _uccmcl_nodes[m] && code <= _uccmcl_nodes[m + 1]) return _uccmcl_nodes[m + 2]; } return 0; } /************************************************************************** * * Support for numeric values. * **************************************************************************/ #if !HARDCODE_DATA static ac_uint4 *_ucnum_nodes; static ac_uint4 _ucnum_size; static short *_ucnum_vals; /* * Return -1 on error, 0 if okay */ static int _ucnumb_load(char *paths, int reload) { FILE *in; ac_uint4 size, i; _ucheader_t hdr; if (_ucnum_size > 0) { if (!reload) /* * The numbers have already been loaded. */ return 0; free((char *) _ucnum_nodes); _ucnum_size = 0; } if ((in = _ucopenfile(paths, "num.dat", "rb")) == 0) return -1; /* * Load the header. */ fread((char *) &hdr, sizeof(_ucheader_t), 1, in); if (hdr.bom == 0xfffe) { hdr.cnt = endian_short(hdr.cnt); hdr.size.bytes = endian_long(hdr.size.bytes); } _ucnum_size = hdr.cnt; _ucnum_nodes = (ac_uint4 *) malloc(hdr.size.bytes); _ucnum_vals = (short *) (_ucnum_nodes + _ucnum_size); /* * Read the combining classes in. */ fread((char *) _ucnum_nodes, sizeof(unsigned char), hdr.size.bytes, in); /* * Do an endian swap if necessary. */ if (hdr.bom == 0xfffe) { for (i = 0; i < _ucnum_size; i++) _ucnum_nodes[i] = endian_long(_ucnum_nodes[i]); /* * Determine the number of values that have to be adjusted. */ size = (hdr.size.bytes - (_ucnum_size * (sizeof(ac_uint4) << 1))) / sizeof(short); for (i = 0; i < size; i++) _ucnum_vals[i] = endian_short(_ucnum_vals[i]); } fclose(in); return 0; } static void _ucnumb_unload(void) { if (_ucnum_size == 0) return; free((char *) _ucnum_nodes); _ucnum_size = 0; } #endif int ucnumber_lookup(ac_uint4 code, struct ucnumber *num) { long l, r, m; short *vp; l = 0; r = _ucnum_size - 1; while (l <= r) { /* * Determine a "mid" point and adjust to make sure the mid point is at * the beginning of a code+offset pair. */ m = (l + r) >> 1; m -= (m & 1); if (code > _ucnum_nodes[m]) l = m + 2; else if (code < _ucnum_nodes[m]) r = m - 2; else { vp = (short *)_ucnum_vals + _ucnum_nodes[m + 1]; num->numerator = (int) *vp++; num->denominator = (int) *vp; return 1; } } return 0; } int ucdigit_lookup(ac_uint4 code, int *digit) { long l, r, m; short *vp; l = 0; r = _ucnum_size - 1; while (l <= r) { /* * Determine a "mid" point and adjust to make sure the mid point is at * the beginning of a code+offset pair. */ m = (l + r) >> 1; m -= (m & 1); if (code > _ucnum_nodes[m]) l = m + 2; else if (code < _ucnum_nodes[m]) r = m - 2; else { vp = (short *)_ucnum_vals + _ucnum_nodes[m + 1]; if (*vp == *(vp + 1)) { *digit = *vp; return 1; } return 0; } } return 0; } struct ucnumber ucgetnumber(ac_uint4 code) { struct ucnumber num; /* * Initialize with some arbitrary value, because the caller simply cannot * tell for sure if the code is a number without calling the ucisnumber() * macro before calling this function. */ num.numerator = num.denominator = -111; (void) ucnumber_lookup(code, &num); return num; } int ucgetdigit(ac_uint4 code) { int dig; /* * Initialize with some arbitrary value, because the caller simply cannot * tell for sure if the code is a number without calling the ucisdigit() * macro before calling this function. */ dig = -111; (void) ucdigit_lookup(code, &dig); return dig; } /************************************************************************** * * Setup and cleanup routines. * **************************************************************************/ #if HARDCODE_DATA int ucdata_load(char *paths, int masks) { return 0; } void ucdata_unload(int masks) { } int ucdata_reload(char *paths, int masks) { return 0; } #else /* * Return 0 if okay, negative on error */ int ucdata_load(char *paths, int masks) { int error = 0; if (masks & UCDATA_CTYPE) error |= _ucprop_load(paths, 0) < 0 ? UCDATA_CTYPE : 0; if (masks & UCDATA_CASE) error |= _uccase_load(paths, 0) < 0 ? UCDATA_CASE : 0; if (masks & UCDATA_DECOMP) error |= _ucdcmp_load(paths, 0) < 0 ? UCDATA_DECOMP : 0; if (masks & UCDATA_CMBCL) error |= _uccmcl_load(paths, 0) < 0 ? UCDATA_CMBCL : 0; if (masks & UCDATA_NUM) error |= _ucnumb_load(paths, 0) < 0 ? UCDATA_NUM : 0; if (masks & UCDATA_COMP) error |= _uccomp_load(paths, 0) < 0 ? UCDATA_COMP : 0; if (masks & UCDATA_KDECOMP) error |= _uckdcmp_load(paths, 0) < 0 ? UCDATA_KDECOMP : 0; return -error; } void ucdata_unload(int masks) { if (masks & UCDATA_CTYPE) _ucprop_unload(); if (masks & UCDATA_CASE) _uccase_unload(); if (masks & UCDATA_DECOMP) _ucdcmp_unload(); if (masks & UCDATA_CMBCL) _uccmcl_unload(); if (masks & UCDATA_NUM) _ucnumb_unload(); if (masks & UCDATA_COMP) _uccomp_unload(); if (masks & UCDATA_KDECOMP) _uckdcmp_unload(); } /* * Return 0 if okay, negative on error */ int ucdata_reload(char *paths, int masks) { int error = 0; if (masks & UCDATA_CTYPE) error |= _ucprop_load(paths, 1) < 0 ? UCDATA_CTYPE : 0; if (masks & UCDATA_CASE) error |= _uccase_load(paths, 1) < 0 ? UCDATA_CASE : 0; if (masks & UCDATA_DECOMP) error |= _ucdcmp_load(paths, 1) < 0 ? UCDATA_DECOMP : 0; if (masks & UCDATA_CMBCL) error |= _uccmcl_load(paths, 1) < 0 ? UCDATA_CMBCL : 0; if (masks & UCDATA_NUM) error |= _ucnumb_load(paths, 1) < 0 ? UCDATA_NUM : 0; if (masks & UCDATA_COMP) error |= _uccomp_load(paths, 1) < 0 ? UCDATA_COMP : 0; if (masks & UCDATA_KDECOMP) error |= _uckdcmp_load(paths, 1) < 0 ? UCDATA_KDECOMP : 0; return -error; } #endif #ifdef TEST void main(void) { int dig; ac_uint4 i, lo, *dec; struct ucnumber num; /* ucdata_setup("."); */ if (ucisweak(0x30)) printf("WEAK\n"); else printf("NOT WEAK\n"); printf("LOWER 0x%04lX\n", uctolower(0xff3a)); printf("UPPER 0x%04lX\n", uctoupper(0xff5a)); if (ucisalpha(0x1d5)) printf("ALPHA\n"); else printf("NOT ALPHA\n"); if (ucisupper(0x1d5)) { printf("UPPER\n"); lo = uctolower(0x1d5); printf("0x%04lx\n", lo); lo = uctotitle(0x1d5); printf("0x%04lx\n", lo); } else printf("NOT UPPER\n"); if (ucistitle(0x1d5)) printf("TITLE\n"); else printf("NOT TITLE\n"); if (uciscomposite(0x1d5)) printf("COMPOSITE\n"); else printf("NOT COMPOSITE\n"); if (ucdecomp(0x1d5, &lo, &dec)) { for (i = 0; i < lo; i++) printf("0x%04lx ", dec[i]); putchar('\n'); } if ((lo = uccombining_class(0x41)) != 0) printf("0x41 CCL %ld\n", lo); if (ucisxdigit(0xfeff)) printf("0xFEFF HEX DIGIT\n"); else printf("0xFEFF NOT HEX DIGIT\n"); if (ucisdefined(0x10000)) printf("0x10000 DEFINED\n"); else printf("0x10000 NOT DEFINED\n"); if (ucnumber_lookup(0x30, &num)) { if (num.denominator != 1) printf("UCNUMBER: 0x30 = %d/%d\n", num.numerator, num.denominator); else printf("UCNUMBER: 0x30 = %d\n", num.numerator); } else printf("UCNUMBER: 0x30 NOT A NUMBER\n"); if (ucnumber_lookup(0xbc, &num)) { if (num.denominator != 1) printf("UCNUMBER: 0xbc = %d/%d\n", num.numerator, num.denominator); else printf("UCNUMBER: 0xbc = %d\n", num.numerator); } else printf("UCNUMBER: 0xbc NOT A NUMBER\n"); if (ucnumber_lookup(0xff19, &num)) { if (num.denominator != 1) printf("UCNUMBER: 0xff19 = %d/%d\n", num.numerator, num.denominator); else printf("UCNUMBER: 0xff19 = %d\n", num.numerator); } else printf("UCNUMBER: 0xff19 NOT A NUMBER\n"); if (ucnumber_lookup(0x4e00, &num)) { if (num.denominator != 1) printf("UCNUMBER: 0x4e00 = %d/%d\n", num.numerator, num.denominator); else printf("UCNUMBER: 0x4e00 = %d\n", num.numerator); } else printf("UCNUMBER: 0x4e00 NOT A NUMBER\n"); if (ucdigit_lookup(0x06f9, &dig)) printf("UCDIGIT: 0x6f9 = %d\n", dig); else printf("UCDIGIT: 0x6f9 NOT A NUMBER\n"); dig = ucgetdigit(0x0969); printf("UCGETDIGIT: 0x969 = %d\n", dig); num = ucgetnumber(0x30); if (num.denominator != 1) printf("UCGETNUMBER: 0x30 = %d/%d\n", num.numerator, num.denominator); else printf("UCGETNUMBER: 0x30 = %d\n", num.numerator); num = ucgetnumber(0xbc); if (num.denominator != 1) printf("UCGETNUMBER: 0xbc = %d/%d\n", num.numerator, num.denominator); else printf("UCGETNUMBER: 0xbc = %d\n", num.numerator); num = ucgetnumber(0xff19); if (num.denominator != 1) printf("UCGETNUMBER: 0xff19 = %d/%d\n", num.numerator, num.denominator); else printf("UCGETNUMBER: 0xff19 = %d\n", num.numerator); /* ucdata_cleanup(); */ exit(0); } #endif /* TEST */ openldap-2.5.11+dfsg/libraries/liblunicode/ucdata/ucgendat.c0000644000175000017500000014116314172327167022511 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Copyright 2001 Computing Research Labs, New Mexico State University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* $Id: ucgendat.c,v 1.4 2001/01/02 18:46:20 mleisher Exp $" */ #include "portable.h" #include "ldap_config.h" #include #include #include #include #include #include #include #ifndef HARDCODE_DATA #define HARDCODE_DATA 1 #endif #undef ishdigit #define ishdigit(cc) (((cc) >= '0' && (cc) <= '9') ||\ ((cc) >= 'A' && (cc) <= 'F') ||\ ((cc) >= 'a' && (cc) <= 'f')) /* * A header written to the output file with the byte-order-mark and the number * of property nodes. */ static ac_uint2 hdr[2] = {0xfeff, 0}; #define NUMPROPS 50 #define NEEDPROPS (NUMPROPS + (4 - (NUMPROPS & 3))) typedef struct { char *name; int len; } _prop_t; /* * List of properties expected to be found in the Unicode Character Database * including some implementation specific properties. * * The implementation specific properties are: * Cm = Composed (can be decomposed) * Nb = Non-breaking * Sy = Symmetric (has left and right forms) * Hd = Hex digit * Qm = Quote marks * Mr = Mirroring * Ss = Space, other * Cp = Defined character */ static _prop_t props[NUMPROPS] = { {"Mn", 2}, {"Mc", 2}, {"Me", 2}, {"Nd", 2}, {"Nl", 2}, {"No", 2}, {"Zs", 2}, {"Zl", 2}, {"Zp", 2}, {"Cc", 2}, {"Cf", 2}, {"Cs", 2}, {"Co", 2}, {"Cn", 2}, {"Lu", 2}, {"Ll", 2}, {"Lt", 2}, {"Lm", 2}, {"Lo", 2}, {"Pc", 2}, {"Pd", 2}, {"Ps", 2}, {"Pe", 2}, {"Po", 2}, {"Sm", 2}, {"Sc", 2}, {"Sk", 2}, {"So", 2}, {"L", 1}, {"R", 1}, {"EN", 2}, {"ES", 2}, {"ET", 2}, {"AN", 2}, {"CS", 2}, {"B", 1}, {"S", 1}, {"WS", 2}, {"ON", 2}, {"Cm", 2}, {"Nb", 2}, {"Sy", 2}, {"Hd", 2}, {"Qm", 2}, {"Mr", 2}, {"Ss", 2}, {"Cp", 2}, {"Pi", 2}, {"Pf", 2}, {"AL", 2} }; typedef struct { ac_uint4 *ranges; ac_uint2 used; ac_uint2 size; } _ranges_t; static _ranges_t proptbl[NUMPROPS]; /* * Make sure this array is sized to be on a 4-byte boundary at compile time. */ static ac_uint2 propcnt[NEEDPROPS]; /* * Array used to collect a decomposition before adding it to the decomposition * table. */ static ac_uint4 dectmp[64]; static ac_uint4 dectmp_size; typedef struct { ac_uint4 code; ac_uint2 size; ac_uint2 used; ac_uint4 *decomp; } _decomp_t; /* * List of decomposition. Created and expanded in order as the characters are * encountered. First list contains canonical mappings, second also includes * compatibility mappings. */ static _decomp_t *decomps; static ac_uint4 decomps_used; static ac_uint4 decomps_size; static _decomp_t *kdecomps; static ac_uint4 kdecomps_used; static ac_uint4 kdecomps_size; /* * Composition exclusion table stuff. */ #define COMPEX_SET(c) (compexs[(c) >> 5] |= (1 << ((c) & 31))) #define COMPEX_TEST(c) (compexs[(c) >> 5] & (1 << ((c) & 31))) static ac_uint4 compexs[8192]; /* * Struct for holding a composition pair, and array of composition pairs */ typedef struct { ac_uint4 comp; ac_uint4 count; ac_uint4 code1; ac_uint4 code2; } _comp_t; static _comp_t *comps; static ac_uint4 comps_used; /* * Types and lists for handling lists of case mappings. */ typedef struct { ac_uint4 key; ac_uint4 other1; ac_uint4 other2; } _case_t; static _case_t *upper; static _case_t *lower; static _case_t *title; static ac_uint4 upper_used; static ac_uint4 upper_size; static ac_uint4 lower_used; static ac_uint4 lower_size; static ac_uint4 title_used; static ac_uint4 title_size; /* * Array used to collect case mappings before adding them to a list. */ static ac_uint4 cases[3]; /* * An array to hold ranges for combining classes. */ static ac_uint4 *ccl; static ac_uint4 ccl_used; static ac_uint4 ccl_size; /* * Structures for handling numbers. */ typedef struct { ac_uint4 code; ac_uint4 idx; } _codeidx_t; typedef struct { short numerator; short denominator; } _num_t; /* * Arrays to hold the mapping of codes to numbers. */ static _codeidx_t *ncodes; static ac_uint4 ncodes_used; static ac_uint4 ncodes_size; static _num_t *nums; static ac_uint4 nums_used; static ac_uint4 nums_size; /* * Array for holding numbers. */ static _num_t *nums; static ac_uint4 nums_used; static ac_uint4 nums_size; static void add_range(ac_uint4 start, ac_uint4 end, char *p1, char *p2) { int i, j, k, len; _ranges_t *rlp; char *name; for (k = 0; k < 2; k++) { if (k == 0) { name = p1; len = 2; } else { if (p2 == 0) break; name = p2; len = 1; } for (i = 0; i < NUMPROPS; i++) { if (props[i].len == len && memcmp(props[i].name, name, len) == 0) break; } if (i == NUMPROPS) continue; rlp = &proptbl[i]; /* * Resize the range list if necessary. */ if (rlp->used == rlp->size) { if (rlp->size == 0) rlp->ranges = (ac_uint4 *) malloc(sizeof(ac_uint4) << 3); else rlp->ranges = (ac_uint4 *) realloc((char *) rlp->ranges, sizeof(ac_uint4) * (rlp->size + 8)); rlp->size += 8; } /* * If this is the first code for this property list, just add it * and return. */ if (rlp->used == 0) { rlp->ranges[0] = start; rlp->ranges[1] = end; rlp->used += 2; continue; } /* * Optimize the case of adding the range to the end. */ j = rlp->used - 1; if (start > rlp->ranges[j]) { j = rlp->used; rlp->ranges[j++] = start; rlp->ranges[j++] = end; rlp->used = j; continue; } /* * Need to locate the insertion point. */ for (i = 0; i < rlp->used && start > rlp->ranges[i + 1] + 1; i += 2) ; /* * If the start value lies in the current range, then simply set the * new end point of the range to the end value passed as a parameter. */ if (rlp->ranges[i] <= start && start <= rlp->ranges[i + 1] + 1) { rlp->ranges[i + 1] = end; return; } /* * Shift following values up by two. */ for (j = rlp->used; j > i; j -= 2) { rlp->ranges[j] = rlp->ranges[j - 2]; rlp->ranges[j + 1] = rlp->ranges[j - 1]; } /* * Add the new range at the insertion point. */ rlp->ranges[i] = start; rlp->ranges[i + 1] = end; rlp->used += 2; } } static void ordered_range_insert(ac_uint4 c, char *name, int len) { int i, j; ac_uint4 s, e; _ranges_t *rlp; if (len == 0) return; /* * Deal with directionality codes introduced in Unicode 3.0. */ if ((len == 2 && memcmp(name, "BN", 2) == 0) || (len == 3 && (memcmp(name, "NSM", 3) == 0 || memcmp(name, "PDF", 3) == 0 || memcmp(name, "LRE", 3) == 0 || memcmp(name, "LRO", 3) == 0 || memcmp(name, "RLE", 3) == 0 || memcmp(name, "RLO", 3) == 0))) { /* * Mark all of these as Other Neutral to preserve compatibility with * older versions. */ len = 2; name = "ON"; } for (i = 0; i < NUMPROPS; i++) { if (props[i].len == len && memcmp(props[i].name, name, len) == 0) break; } if (i == NUMPROPS) return; /* * Have a match, so insert the code in order. */ rlp = &proptbl[i]; /* * Resize the range list if necessary. */ if (rlp->used == rlp->size) { if (rlp->size == 0) rlp->ranges = (ac_uint4 *) malloc(sizeof(ac_uint4) << 3); else rlp->ranges = (ac_uint4 *) realloc((char *) rlp->ranges, sizeof(ac_uint4) * (rlp->size + 8)); rlp->size += 8; } /* * If this is the first code for this property list, just add it * and return. */ if (rlp->used == 0) { rlp->ranges[0] = rlp->ranges[1] = c; rlp->used += 2; return; } /* * Optimize the cases of extending the last range and adding new ranges to * the end. */ j = rlp->used - 1; e = rlp->ranges[j]; s = rlp->ranges[j - 1]; if (c == e + 1) { /* * Extend the last range. */ rlp->ranges[j] = c; return; } if (c > e + 1) { /* * Start another range on the end. */ j = rlp->used; rlp->ranges[j] = rlp->ranges[j + 1] = c; rlp->used += 2; return; } if (c >= s) /* * The code is a duplicate of a code in the last range, so just return. */ return; /* * The code should be inserted somewhere before the last range in the * list. Locate the insertion point. */ for (i = 0; i < rlp->used && c > rlp->ranges[i + 1] + 1; i += 2) ; s = rlp->ranges[i]; e = rlp->ranges[i + 1]; if (c == e + 1) /* * Simply extend the current range. */ rlp->ranges[i + 1] = c; else if (c < s) { /* * Add a new entry before the current location. Shift all entries * before the current one up by one to make room. */ for (j = rlp->used; j > i; j -= 2) { rlp->ranges[j] = rlp->ranges[j - 2]; rlp->ranges[j + 1] = rlp->ranges[j - 1]; } rlp->ranges[i] = rlp->ranges[i + 1] = c; rlp->used += 2; } } static void add_decomp(ac_uint4 code, short compat) { ac_uint4 i, j, size; _decomp_t **pdecomps; ac_uint4 *pdecomps_used; ac_uint4 *pdecomps_size; if (compat) { pdecomps = &kdecomps; pdecomps_used = &kdecomps_used; pdecomps_size = &kdecomps_size; } else { pdecomps = &decomps; pdecomps_used = &decomps_used; pdecomps_size = &decomps_size; } /* * Add the code to the composite property. */ if (!compat) { ordered_range_insert(code, "Cm", 2); } /* * Locate the insertion point for the code. */ for (i = 0; i < *pdecomps_used && code > (*pdecomps)[i].code; i++) ; /* * Allocate space for a new decomposition. */ if (*pdecomps_used == *pdecomps_size) { if (*pdecomps_size == 0) *pdecomps = (_decomp_t *) malloc(sizeof(_decomp_t) << 3); else *pdecomps = (_decomp_t *) realloc((char *) *pdecomps, sizeof(_decomp_t) * (*pdecomps_size + 8)); (void) memset((char *) (*pdecomps + *pdecomps_size), '\0', sizeof(_decomp_t) << 3); *pdecomps_size += 8; } if (i < *pdecomps_used && code != (*pdecomps)[i].code) { /* * Shift the decomps up by one if the codes don't match. */ for (j = *pdecomps_used; j > i; j--) (void) AC_MEMCPY((char *) &(*pdecomps)[j], (char *) &(*pdecomps)[j - 1], sizeof(_decomp_t)); } /* * Insert or replace a decomposition. */ size = dectmp_size + (4 - (dectmp_size & 3)); if ((*pdecomps)[i].size < size) { if ((*pdecomps)[i].size == 0) (*pdecomps)[i].decomp = (ac_uint4 *) malloc(sizeof(ac_uint4) * size); else (*pdecomps)[i].decomp = (ac_uint4 *) realloc((char *) (*pdecomps)[i].decomp, sizeof(ac_uint4) * size); (*pdecomps)[i].size = size; } if ((*pdecomps)[i].code != code) (*pdecomps_used)++; (*pdecomps)[i].code = code; (*pdecomps)[i].used = dectmp_size; (void) AC_MEMCPY((char *) (*pdecomps)[i].decomp, (char *) dectmp, sizeof(ac_uint4) * dectmp_size); /* * NOTICE: This needs changing later so it is more general than simply * pairs. This calculation is done here to simplify allocation elsewhere. */ if (!compat && dectmp_size == 2) comps_used++; } static void add_title(ac_uint4 code) { ac_uint4 i, j; /* * Always map the code to itself. */ cases[2] = code; /* * If the upper case character is not present, then make it the same as * the title case. */ if (cases[0] == 0) cases[0] = code; if (title_used == title_size) { if (title_size == 0) title = (_case_t *) malloc(sizeof(_case_t) << 3); else title = (_case_t *) realloc((char *) title, sizeof(_case_t) * (title_size + 8)); title_size += 8; } /* * Locate the insertion point. */ for (i = 0; i < title_used && code > title[i].key; i++) ; if (i < title_used) { /* * Shift the array up by one. */ for (j = title_used; j > i; j--) (void) AC_MEMCPY((char *) &title[j], (char *) &title[j - 1], sizeof(_case_t)); } title[i].key = cases[2]; /* Title */ title[i].other1 = cases[0]; /* Upper */ title[i].other2 = cases[1]; /* Lower */ title_used++; } static void add_upper(ac_uint4 code) { ac_uint4 i, j; /* * Always map the code to itself. */ cases[0] = code; /* * If the title case character is not present, then make it the same as * the upper case. */ if (cases[2] == 0) cases[2] = code; if (upper_used == upper_size) { if (upper_size == 0) upper = (_case_t *) malloc(sizeof(_case_t) << 3); else upper = (_case_t *) realloc((char *) upper, sizeof(_case_t) * (upper_size + 8)); upper_size += 8; } /* * Locate the insertion point. */ for (i = 0; i < upper_used && code > upper[i].key; i++) ; if (i < upper_used) { /* * Shift the array up by one. */ for (j = upper_used; j > i; j--) (void) AC_MEMCPY((char *) &upper[j], (char *) &upper[j - 1], sizeof(_case_t)); } upper[i].key = cases[0]; /* Upper */ upper[i].other1 = cases[1]; /* Lower */ upper[i].other2 = cases[2]; /* Title */ upper_used++; } static void add_lower(ac_uint4 code) { ac_uint4 i, j; /* * Always map the code to itself. */ cases[1] = code; /* * If the title case character is empty, then make it the same as the * upper case. */ if (cases[2] == 0) cases[2] = cases[0]; if (lower_used == lower_size) { if (lower_size == 0) lower = (_case_t *) malloc(sizeof(_case_t) << 3); else lower = (_case_t *) realloc((char *) lower, sizeof(_case_t) * (lower_size + 8)); lower_size += 8; } /* * Locate the insertion point. */ for (i = 0; i < lower_used && code > lower[i].key; i++) ; if (i < lower_used) { /* * Shift the array up by one. */ for (j = lower_used; j > i; j--) (void) AC_MEMCPY((char *) &lower[j], (char *) &lower[j - 1], sizeof(_case_t)); } lower[i].key = cases[1]; /* Lower */ lower[i].other1 = cases[0]; /* Upper */ lower[i].other2 = cases[2]; /* Title */ lower_used++; } static void ordered_ccl_insert(ac_uint4 c, ac_uint4 ccl_code) { ac_uint4 i, j; if (ccl_used == ccl_size) { if (ccl_size == 0) ccl = (ac_uint4 *) malloc(sizeof(ac_uint4) * 24); else ccl = (ac_uint4 *) realloc((char *) ccl, sizeof(ac_uint4) * (ccl_size + 24)); ccl_size += 24; } /* * Optimize adding the first item. */ if (ccl_used == 0) { ccl[0] = ccl[1] = c; ccl[2] = ccl_code; ccl_used += 3; return; } /* * Handle the special case of extending the range on the end. This * requires that the combining class codes are the same. */ if (ccl_code == ccl[ccl_used - 1] && c == ccl[ccl_used - 2] + 1) { ccl[ccl_used - 2] = c; return; } /* * Handle the special case of adding another range on the end. */ if (c > ccl[ccl_used - 2] + 1 || (c == ccl[ccl_used - 2] + 1 && ccl_code != ccl[ccl_used - 1])) { ccl[ccl_used++] = c; ccl[ccl_used++] = c; ccl[ccl_used++] = ccl_code; return; } /* * Locate either the insertion point or range for the code. */ for (i = 0; i < ccl_used && c > ccl[i + 1] + 1; i += 3) ; if (ccl_code == ccl[i + 2] && c == ccl[i + 1] + 1) { /* * Extend an existing range. */ ccl[i + 1] = c; return; } else if (c < ccl[i]) { /* * Start a new range before the current location. */ for (j = ccl_used; j > i; j -= 3) { ccl[j] = ccl[j - 3]; ccl[j - 1] = ccl[j - 4]; ccl[j - 2] = ccl[j - 5]; } ccl[i] = ccl[i + 1] = c; ccl[i + 2] = ccl_code; } } /* * Adds a number if it does not already exist and returns an index value * multiplied by 2. */ static ac_uint4 make_number(short num, short denom) { ac_uint4 n; /* * Determine if the number already exists. */ for (n = 0; n < nums_used; n++) { if (nums[n].numerator == num && nums[n].denominator == denom) return n << 1; } if (nums_used == nums_size) { if (nums_size == 0) nums = (_num_t *) malloc(sizeof(_num_t) << 3); else nums = (_num_t *) realloc((char *) nums, sizeof(_num_t) * (nums_size + 8)); nums_size += 8; } n = nums_used++; nums[n].numerator = num; nums[n].denominator = denom; return n << 1; } static void add_number(ac_uint4 code, short num, short denom) { ac_uint4 i, j; /* * Insert the code in order. */ for (i = 0; i < ncodes_used && code > ncodes[i].code; i++) ; /* * Handle the case of the codes matching and simply replace the number * that was there before. */ if (i < ncodes_used && code == ncodes[i].code) { ncodes[i].idx = make_number(num, denom); return; } /* * Resize the array if necessary. */ if (ncodes_used == ncodes_size) { if (ncodes_size == 0) ncodes = (_codeidx_t *) malloc(sizeof(_codeidx_t) << 3); else ncodes = (_codeidx_t *) realloc((char *) ncodes, sizeof(_codeidx_t) * (ncodes_size + 8)); ncodes_size += 8; } /* * Shift things around to insert the code if necessary. */ if (i < ncodes_used) { for (j = ncodes_used; j > i; j--) { ncodes[j].code = ncodes[j - 1].code; ncodes[j].idx = ncodes[j - 1].idx; } } ncodes[i].code = code; ncodes[i].idx = make_number(num, denom); ncodes_used++; } /* * This routine assumes that the line is a valid Unicode Character Database * entry. */ static void read_cdata(FILE *in) { ac_uint4 i, lineno, skip, code, ccl_code; short wnum, neg, number[2], compat; char line[512], *s, *e, *first_prop; lineno = skip = 0; while (fgets(line, sizeof(line), in)) { if( (s=strchr(line, '\n')) ) *s = '\0'; lineno++; /* * Skip blank lines and lines that start with a '#'. */ if (line[0] == 0 || line[0] == '#') continue; /* * If lines need to be skipped, do it here. */ if (skip) { skip--; continue; } /* * Collect the code. The code can be up to 6 hex digits in length to * allow surrogates to be specified. */ for (s = line, i = code = 0; *s != ';' && i < 6; i++, s++) { code <<= 4; if (*s >= '0' && *s <= '9') code += *s - '0'; else if (*s >= 'A' && *s <= 'F') code += (*s - 'A') + 10; else if (*s >= 'a' && *s <= 'f') code += (*s - 'a') + 10; } /* * Handle the following special cases: * 1. 4E00-9FA5 CJK Ideographs. * 2. AC00-D7A3 Hangul Syllables. * 3. D800-DFFF Surrogates. * 4. E000-F8FF Private Use Area. * 5. F900-FA2D Han compatibility. * ...Plus additional ranges in newer Unicode versions... */ switch (code) { case 0x3400: /* CJK Ideograph Extension A */ add_range(0x3400, 0x4db5, "Lo", "L"); add_range(0x3400, 0x4db5, "Cp", 0); skip = 1; break; case 0x4e00: /* * The Han ideographs. */ add_range(0x4e00, 0x9fff, "Lo", "L"); /* * Add the characters to the defined category. */ add_range(0x4e00, 0x9fa5, "Cp", 0); skip = 1; break; case 0xac00: /* * The Hangul syllables. */ add_range(0xac00, 0xd7a3, "Lo", "L"); /* * Add the characters to the defined category. */ add_range(0xac00, 0xd7a3, "Cp", 0); skip = 1; break; case 0xd800: /* * Make a range of all surrogates and assume some default * properties. */ add_range(0x010000, 0x10ffff, "Cs", "L"); skip = 5; break; case 0xe000: /* * The Private Use area. Add with a default set of properties. */ add_range(0xe000, 0xf8ff, "Co", "L"); skip = 1; break; case 0xf900: /* * The CJK compatibility area. */ add_range(0xf900, 0xfaff, "Lo", "L"); /* * Add the characters to the defined category. */ add_range(0xf900, 0xfaff, "Cp", 0); skip = 1; break; case 0x20000: /* CJK Ideograph Extension B */ add_range(0x20000, 0x2a6d6, "Lo", "L"); add_range(0x20000, 0x2a6d6, "Cp", 0); skip = 1; break; case 0xf0000: /* Plane 15 private use */ add_range(0xf0000, 0xffffd, "Co", "L"); skip = 1; break; case 0x100000: /* Plane 16 private use */ add_range(0x100000, 0x10fffd, "Co", "L"); skip = 1; break; } if (skip) continue; /* * Add the code to the defined category. */ ordered_range_insert(code, "Cp", 2); /* * Locate the first character property field. */ for (i = 0; *s != 0 && i < 2; s++) { if (*s == ';') i++; } for (e = s; *e && *e != ';'; e++) ; first_prop = s; ordered_range_insert(code, s, e - s); /* * Locate the combining class code. */ for (s = e; *s != 0 && i < 3; s++) { if (*s == ';') i++; } /* * Convert the combining class code from decimal. */ for (ccl_code = 0, e = s; *e && *e != ';'; e++) ccl_code = (ccl_code * 10) + (*e - '0'); /* * Add the code if it not 0. */ if (ccl_code != 0) ordered_ccl_insert(code, ccl_code); /* * Locate the second character property field. */ for (s = e; *s != 0 && i < 4; s++) { if (*s == ';') i++; } for (e = s; *e && *e != ';'; e++) ; ordered_range_insert(code, s, e - s); /* * Check for a decomposition. */ s = ++e; if (*s != ';') { compat = *s == '<'; if (compat) { /* * Skip compatibility formatting tag. */ while (*s++ != '>'); } /* * Collect the codes of the decomposition. */ for (dectmp_size = 0; *s != ';'; ) { /* * Skip all leading non-hex digits. */ while (!ishdigit(*s)) s++; for (dectmp[dectmp_size] = 0; ishdigit(*s); s++) { dectmp[dectmp_size] <<= 4; if (*s >= '0' && *s <= '9') dectmp[dectmp_size] += *s - '0'; else if (*s >= 'A' && *s <= 'F') dectmp[dectmp_size] += (*s - 'A') + 10; else if (*s >= 'a' && *s <= 'f') dectmp[dectmp_size] += (*s - 'a') + 10; } dectmp_size++; } /* * If there are any codes in the temporary decomposition array, * then add the character with its decomposition. */ if (dectmp_size > 0) { if (!compat) { add_decomp(code, 0); } add_decomp(code, 1); } } /* * Skip to the number field. */ for (i = 0; i < 3 && *s; s++) { if (*s == ';') i++; } /* * Scan the number in. */ number[0] = number[1] = 0; for (e = s, neg = wnum = 0; *e && *e != ';'; e++) { if (*e == '-') { neg = 1; continue; } if (*e == '/') { /* * Move the the denominator of the fraction. */ if (neg) number[wnum] *= -1; neg = 0; e++; wnum++; } number[wnum] = (number[wnum] * 10) + (*e - '0'); } if (e > s) { /* * Adjust the denominator in case of integers and add the number. */ if (wnum == 0) number[1] = 1; add_number(code, number[0], number[1]); } /* * Skip to the start of the possible case mappings. */ for (s = e, i = 0; i < 4 && *s; s++) { if (*s == ';') i++; } /* * Collect the case mappings. */ cases[0] = cases[1] = cases[2] = 0; for (i = 0; i < 3; i++) { while (ishdigit(*s)) { cases[i] <<= 4; if (*s >= '0' && *s <= '9') cases[i] += *s - '0'; else if (*s >= 'A' && *s <= 'F') cases[i] += (*s - 'A') + 10; else if (*s >= 'a' && *s <= 'f') cases[i] += (*s - 'a') + 10; s++; } if (*s == ';') s++; } if (!strncmp(first_prop,"Lt",2) && (cases[0] || cases[1])) /* * Add the upper and lower mappings for a title case character. */ add_title(code); else if (cases[1]) /* * Add the lower and title case mappings for the upper case * character. */ add_upper(code); else if (cases[0]) /* * Add the upper and title case mappings for the lower case * character. */ add_lower(code); } } static _decomp_t * find_decomp(ac_uint4 code, short compat) { long l, r, m; _decomp_t *decs; l = 0; r = (compat ? kdecomps_used : decomps_used) - 1; decs = compat ? kdecomps : decomps; while (l <= r) { m = (l + r) >> 1; if (code > decs[m].code) l = m + 1; else if (code < decs[m].code) r = m - 1; else return &decs[m]; } return 0; } static void decomp_it(_decomp_t *d, short compat) { ac_uint4 i; _decomp_t *dp; for (i = 0; i < d->used; i++) { if ((dp = find_decomp(d->decomp[i], compat)) != 0) decomp_it(dp, compat); else dectmp[dectmp_size++] = d->decomp[i]; } } /* * Expand all decompositions by recursively decomposing each character * in the decomposition. */ static void expand_decomp(void) { ac_uint4 i; for (i = 0; i < decomps_used; i++) { dectmp_size = 0; decomp_it(&decomps[i], 0); if (dectmp_size > 0) add_decomp(decomps[i].code, 0); } for (i = 0; i < kdecomps_used; i++) { dectmp_size = 0; decomp_it(&kdecomps[i], 1); if (dectmp_size > 0) add_decomp(kdecomps[i].code, 1); } } static int cmpcomps(const void *v_comp1, const void *v_comp2) { const _comp_t *comp1 = v_comp1, *comp2 = v_comp2; long diff = comp1->code1 - comp2->code1; if (!diff) diff = comp1->code2 - comp2->code2; return (int) diff; } /* * Load composition exclusion data */ static void read_compexdata(FILE *in) { ac_uint2 i; ac_uint4 code; char line[512], *s; (void) memset((char *) compexs, 0, sizeof(compexs)); while (fgets(line, sizeof(line), in)) { if( (s=strchr(line, '\n')) ) *s = '\0'; /* * Skip blank lines and lines that start with a '#'. */ if (line[0] == 0 || line[0] == '#') continue; /* * Collect the code. Assume max 6 digits */ for (s = line, i = code = 0; *s != '#' && i < 6; i++, s++) { if (isspace((unsigned char)*s)) break; code <<= 4; if (*s >= '0' && *s <= '9') code += *s - '0'; else if (*s >= 'A' && *s <= 'F') code += (*s - 'A') + 10; else if (*s >= 'a' && *s <= 'f') code += (*s - 'a') + 10; } COMPEX_SET(code); } } /* * Creates array of compositions from decomposition array */ static void create_comps(void) { ac_uint4 i, cu; comps = (_comp_t *) malloc(comps_used * sizeof(_comp_t)); for (i = cu = 0; i < decomps_used; i++) { if (decomps[i].used != 2 || COMPEX_TEST(decomps[i].code)) continue; comps[cu].comp = decomps[i].code; comps[cu].count = 2; comps[cu].code1 = decomps[i].decomp[0]; comps[cu].code2 = decomps[i].decomp[1]; cu++; } comps_used = cu; qsort(comps, comps_used, sizeof(_comp_t), cmpcomps); } #if HARDCODE_DATA static void write_case(FILE *out, _case_t *tab, int num, int first) { int i; for (i=0; i 0) { for (j=0; j 0) fwrite((char *) proptbl[i].ranges, sizeof(ac_uint4), proptbl[i].used, out); } fclose(out); #endif /***************************************************************** * * Generate the case mapping data. * *****************************************************************/ #if HARDCODE_DATA fprintf(out, PREF "ac_uint4 _uccase_size = %ld;\n\n", (long) (upper_used + lower_used + title_used)); fprintf(out, PREF "ac_uint2 _uccase_len[2] = {%ld, %ld};\n\n", (long) upper_used, (long) lower_used); fprintf(out, PREF "ac_uint4 _uccase_map[] = {"); if (upper_used > 0) /* * Write the upper case table. */ write_case(out, upper, upper_used, 1); if (lower_used > 0) /* * Write the lower case table. */ write_case(out, lower, lower_used, !upper_used); if (title_used > 0) /* * Write the title case table. */ write_case(out, title, title_used, !(upper_used||lower_used)); if (!(upper_used || lower_used || title_used)) fprintf(out, "\t0"); fprintf(out, "\n};\n\n"); #else /* * Open the case.dat file. */ snprintf(path, sizeof path, "%s" LDAP_DIRSEP "case.dat", opath); if ((out = fopen(path, "wb")) == 0) return; /* * Write the case mapping tables. */ hdr[1] = upper_used + lower_used + title_used; casecnt[0] = upper_used; casecnt[1] = lower_used; /* * Write the header. */ fwrite((char *) hdr, sizeof(ac_uint2), 2, out); /* * Write the upper and lower case table sizes. */ fwrite((char *) casecnt, sizeof(ac_uint2), 2, out); if (upper_used > 0) /* * Write the upper case table. */ fwrite((char *) upper, sizeof(_case_t), upper_used, out); if (lower_used > 0) /* * Write the lower case table. */ fwrite((char *) lower, sizeof(_case_t), lower_used, out); if (title_used > 0) /* * Write the title case table. */ fwrite((char *) title, sizeof(_case_t), title_used, out); fclose(out); #endif /***************************************************************** * * Generate the composition data. * *****************************************************************/ /* * Create compositions from decomposition data */ create_comps(); #if HARDCODE_DATA fprintf(out, PREF "ac_uint4 _uccomp_size = %ld;\n\n", comps_used * 4L); fprintf(out, PREF "ac_uint4 _uccomp_data[] = {"); /* * Now, if comps exist, write them out. */ if (comps_used > 0) { for (i=0; i 0) fwrite((char *) comps, sizeof(_comp_t), comps_used, out); fclose(out); #endif /***************************************************************** * * Generate the decomposition data. * *****************************************************************/ /* * Fully expand all decompositions before generating the output file. */ expand_decomp(); #if HARDCODE_DATA fprintf(out, PREF "ac_uint4 _ucdcmp_size = %ld;\n\n", decomps_used * 2L); fprintf(out, PREF "ac_uint4 _ucdcmp_nodes[] = {"); if (decomps_used) { /* * Write the list of decomp nodes. */ for (i = idx = 0; i < decomps_used; i++) { fprintf(out, "\n\t0x%08lx, 0x%08lx,", (unsigned long) decomps[i].code, (unsigned long) idx); idx += decomps[i].used; } /* * Write the sentinel index as the last decomp node. */ fprintf(out, "\n\t0x%08lx\n};\n\n", (unsigned long) idx); fprintf(out, PREF "ac_uint4 _ucdcmp_decomp[] = {"); /* * Write the decompositions themselves. */ k = 0; for (i = 0; i < decomps_used; i++) for (j=0; j 0) { /* * Write the combining class ranges out. */ for (i = 0; i 0) /* * Write the combining class ranges out. */ fwrite((char *) ccl, sizeof(ac_uint4), ccl_used, out); fclose(out); #endif /***************************************************************** * * Generate the number data. * *****************************************************************/ #if HARDCODE_DATA fprintf(out, PREF "ac_uint4 _ucnum_size = %lu;\n\n", (unsigned long)ncodes_used<<1); fprintf(out, PREF "ac_uint4 _ucnum_nodes[] = {"); /* * Now, if number mappings exist, write them out. */ if (ncodes_used > 0) { for (i = 0; i 0) { fwrite((char *) ncodes, sizeof(_codeidx_t), ncodes_used, out); fwrite((char *) nums, sizeof(_num_t), nums_used, out); } #endif fclose(out); } static void usage(char *prog) { fprintf(stderr, "Usage: %s [-o output-directory|-x composition-exclusions]", prog); fprintf(stderr, " datafile1 datafile2 ...\n\n"); fprintf(stderr, "-o output-directory\n\t\tWrite the output files to a different"); fprintf(stderr, " directory (default: .).\n"); fprintf(stderr, "-x composition-exclusion\n\t\tFile of composition codes"); fprintf(stderr, " that should be excluded.\n"); exit(1); } int main(int argc, char *argv[]) { FILE *in; char *prog, *opath; prog = lutil_progname( "ucgendat", argc, argv ); opath = 0; in = stdin; argc--; argv++; while (argc > 0) { if (argv[0][0] == '-') { switch (argv[0][1]) { case 'o': argc--; argv++; opath = argv[0]; break; case 'x': argc--; argv++; if ((in = fopen(argv[0], "r")) == 0) fprintf(stderr, "%s: unable to open composition exclusion file %s\n", prog, argv[0]); else { read_compexdata(in); fclose(in); in = 0; } break; default: usage(prog); } } else { if (in != stdin && in != NULL) fclose(in); if ((in = fopen(argv[0], "r")) == 0) fprintf(stderr, "%s: unable to open ctype file %s\n", prog, argv[0]); else { read_cdata(in); fclose(in); in = 0; } } argc--; argv++; } if (opath == 0) opath = "."; write_cdata(opath); return 0; } openldap-2.5.11+dfsg/libraries/liblunicode/ucdata/ucdata.h0000644000175000017500000003323014172327167022160 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Copyright 2001 Computing Research Labs, New Mexico State University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* $Id: ucdata.h,v 1.6 2001/01/02 18:46:20 mleisher Exp $ */ #ifndef _h_ucdata #define _h_ucdata LDAP_BEGIN_DECL #define UCDATA_VERSION "2.4" /************************************************************************** * * Masks and macros for character properties. * **************************************************************************/ /* * Values that can appear in the `mask1' parameter of the ucisprop() * function. */ #define UC_MN 0x00000001 /* Mark, Non-Spacing */ #define UC_MC 0x00000002 /* Mark, Spacing Combining */ #define UC_ME 0x00000004 /* Mark, Enclosing */ #define UC_ND 0x00000008 /* Number, Decimal Digit */ #define UC_NL 0x00000010 /* Number, Letter */ #define UC_NO 0x00000020 /* Number, Other */ #define UC_ZS 0x00000040 /* Separator, Space */ #define UC_ZL 0x00000080 /* Separator, Line */ #define UC_ZP 0x00000100 /* Separator, Paragraph */ #define UC_CC 0x00000200 /* Other, Control */ #define UC_CF 0x00000400 /* Other, Format */ #define UC_OS 0x00000800 /* Other, Surrogate */ #define UC_CO 0x00001000 /* Other, Private Use */ #define UC_CN 0x00002000 /* Other, Not Assigned */ #define UC_LU 0x00004000 /* Letter, Uppercase */ #define UC_LL 0x00008000 /* Letter, Lowercase */ #define UC_LT 0x00010000 /* Letter, Titlecase */ #define UC_LM 0x00020000 /* Letter, Modifier */ #define UC_LO 0x00040000 /* Letter, Other */ #define UC_PC 0x00080000 /* Punctuation, Connector */ #define UC_PD 0x00100000 /* Punctuation, Dash */ #define UC_PS 0x00200000 /* Punctuation, Open */ #define UC_PE 0x00400000 /* Punctuation, Close */ #define UC_PO 0x00800000 /* Punctuation, Other */ #define UC_SM 0x01000000 /* Symbol, Math */ #define UC_SC 0x02000000 /* Symbol, Currency */ #define UC_SK 0x04000000 /* Symbol, Modifier */ #define UC_SO 0x08000000 /* Symbol, Other */ #define UC_L 0x10000000 /* Left-To-Right */ #define UC_R 0x20000000 /* Right-To-Left */ #define UC_EN 0x40000000 /* European Number */ #define UC_ES 0x80000000 /* European Number Separator */ /* * Values that can appear in the `mask2' parameter of the ucisprop() * function. */ #define UC_ET 0x00000001 /* European Number Terminator */ #define UC_AN 0x00000002 /* Arabic Number */ #define UC_CS 0x00000004 /* Common Number Separator */ #define UC_B 0x00000008 /* Block Separator */ #define UC_S 0x00000010 /* Segment Separator */ #define UC_WS 0x00000020 /* Whitespace */ #define UC_ON 0x00000040 /* Other Neutrals */ /* * Implementation specific character properties. */ #define UC_CM 0x00000080 /* Composite */ #define UC_NB 0x00000100 /* Non-Breaking */ #define UC_SY 0x00000200 /* Symmetric */ #define UC_HD 0x00000400 /* Hex Digit */ #define UC_QM 0x00000800 /* Quote Mark */ #define UC_MR 0x00001000 /* Mirroring */ #define UC_SS 0x00002000 /* Space, other */ #define UC_CP 0x00004000 /* Defined */ /* * Added for UnicodeData-2.1.3. */ #define UC_PI 0x00008000 /* Punctuation, Initial */ #define UC_PF 0x00010000 /* Punctuation, Final */ /* * This is the primary function for testing to see if a character has some set * of properties. The macros that test for various character properties all * call this function with some set of masks. */ LDAP_LUNICODE_F (int) ucisprop LDAP_P((ac_uint4 code, ac_uint4 mask1, ac_uint4 mask2)); #define ucisalpha(cc) ucisprop(cc, UC_LU|UC_LL|UC_LM|UC_LO|UC_LT, 0) #define ucisdigit(cc) ucisprop(cc, UC_ND, 0) #define ucisalnum(cc) ucisprop(cc, UC_LU|UC_LL|UC_LM|UC_LO|UC_LT|UC_ND, 0) #define uciscntrl(cc) ucisprop(cc, UC_CC|UC_CF, 0) #define ucisspace(cc) ucisprop(cc, UC_ZS|UC_SS, 0) #define ucisblank(cc) ucisprop(cc, UC_ZS, 0) #define ucispunct(cc) ucisprop(cc, UC_PD|UC_PS|UC_PE|UC_PO, UC_PI|UC_PF) #define ucisgraph(cc) ucisprop(cc, UC_MN|UC_MC|UC_ME|UC_ND|UC_NL|UC_NO|\ UC_LU|UC_LL|UC_LT|UC_LM|UC_LO|UC_PC|UC_PD|\ UC_PS|UC_PE|UC_PO|UC_SM|UC_SM|UC_SC|UC_SK|\ UC_SO, UC_PI|UC_PF) #define ucisprint(cc) ucisprop(cc, UC_MN|UC_MC|UC_ME|UC_ND|UC_NL|UC_NO|\ UC_LU|UC_LL|UC_LT|UC_LM|UC_LO|UC_PC|UC_PD|\ UC_PS|UC_PE|UC_PO|UC_SM|UC_SM|UC_SC|UC_SK|\ UC_SO|UC_ZS, UC_PI|UC_PF) #define ucisupper(cc) ucisprop(cc, UC_LU, 0) #define ucislower(cc) ucisprop(cc, UC_LL, 0) #define ucistitle(cc) ucisprop(cc, UC_LT, 0) #define ucisxdigit(cc) ucisprop(cc, 0, UC_HD) #define ucisisocntrl(cc) ucisprop(cc, UC_CC, 0) #define ucisfmtcntrl(cc) ucisprop(cc, UC_CF, 0) #define ucissymbol(cc) ucisprop(cc, UC_SM|UC_SC|UC_SO|UC_SK, 0) #define ucisnumber(cc) ucisprop(cc, UC_ND|UC_NO|UC_NL, 0) #define ucisnonspacing(cc) ucisprop(cc, UC_MN, 0) #define ucisopenpunct(cc) ucisprop(cc, UC_PS, 0) #define ucisclosepunct(cc) ucisprop(cc, UC_PE, 0) #define ucisinitialpunct(cc) ucisprop(cc, 0, UC_PI) #define ucisfinalpunct(cc) ucisprop(cc, 0, UC_PF) #define uciscomposite(cc) ucisprop(cc, 0, UC_CM) #define ucishex(cc) ucisprop(cc, 0, UC_HD) #define ucisquote(cc) ucisprop(cc, 0, UC_QM) #define ucissymmetric(cc) ucisprop(cc, 0, UC_SY) #define ucismirroring(cc) ucisprop(cc, 0, UC_MR) #define ucisnonbreaking(cc) ucisprop(cc, 0, UC_NB) /* * Directionality macros. */ #define ucisrtl(cc) ucisprop(cc, UC_R, 0) #define ucisltr(cc) ucisprop(cc, UC_L, 0) #define ucisstrong(cc) ucisprop(cc, UC_L|UC_R, 0) #define ucisweak(cc) ucisprop(cc, UC_EN|UC_ES, UC_ET|UC_AN|UC_CS) #define ucisneutral(cc) ucisprop(cc, 0, UC_B|UC_S|UC_WS|UC_ON) #define ucisseparator(cc) ucisprop(cc, 0, UC_B|UC_S) /* * Other macros inspired by John Cowan. */ #define ucismark(cc) ucisprop(cc, UC_MN|UC_MC|UC_ME, 0) #define ucismodif(cc) ucisprop(cc, UC_LM, 0) #define ucisletnum(cc) ucisprop(cc, UC_NL, 0) #define ucisconnect(cc) ucisprop(cc, UC_PC, 0) #define ucisdash(cc) ucisprop(cc, UC_PD, 0) #define ucismath(cc) ucisprop(cc, UC_SM, 0) #define uciscurrency(cc) ucisprop(cc, UC_SC, 0) #define ucismodifsymbol(cc) ucisprop(cc, UC_SK, 0) #define ucisnsmark(cc) ucisprop(cc, UC_MN, 0) #define ucisspmark(cc) ucisprop(cc, UC_MC, 0) #define ucisenclosing(cc) ucisprop(cc, UC_ME, 0) #define ucisprivate(cc) ucisprop(cc, UC_CO, 0) #define ucissurrogate(cc) ucisprop(cc, UC_OS, 0) #define ucislsep(cc) ucisprop(cc, UC_ZL, 0) #define ucispsep(cc) ucisprop(cc, UC_ZP, 0) #define ucisidentstart(cc) ucisprop(cc, UC_LU|UC_LL|UC_LT|UC_LO|UC_NL, 0) #define ucisidentpart(cc) ucisprop(cc, UC_LU|UC_LL|UC_LT|UC_LO|UC_NL|\ UC_MN|UC_MC|UC_ND|UC_PC|UC_CF, 0) #define ucisdefined(cc) ucisprop(cc, 0, UC_CP) #define ucisundefined(cc) !ucisprop(cc, 0, UC_CP) /* * Other miscellaneous character property macros. */ #define ucishan(cc) (((cc) >= 0x4e00 && (cc) <= 0x9fff) ||\ ((cc) >= 0xf900 && (cc) <= 0xfaff)) #define ucishangul(cc) ((cc) >= 0xac00 && (cc) <= 0xd7ff) /************************************************************************** * * Functions for case conversion. * **************************************************************************/ LDAP_LUNICODE_F (ac_uint4) uctoupper LDAP_P((ac_uint4 code)); LDAP_LUNICODE_F (ac_uint4) uctolower LDAP_P((ac_uint4 code)); LDAP_LUNICODE_F (ac_uint4) uctotitle LDAP_P((ac_uint4 code)); /************************************************************************** * * Functions for getting compositions. * **************************************************************************/ /* * This routine determines if there exists a composition of node1 and node2. * If it returns 0, there is no composition. Any other value indicates a * composition was returned in comp. */ LDAP_LUNICODE_F (int) uccomp LDAP_P((ac_uint4 node1, ac_uint4 node2, ac_uint4 *comp)); /* * Does Hangul composition on the string str with length len, and returns * the length of the composed string. */ LDAP_LUNICODE_F (int) uccomp_hangul LDAP_P((ac_uint4 *str, int len)); /* * Does canonical composition on the string str with length len, and returns * the length of the composed string. */ LDAP_LUNICODE_F (int) uccanoncomp LDAP_P((ac_uint4 *str, int len)); /************************************************************************** * * Functions for getting decompositions. * **************************************************************************/ /* * This routine determines if the code has a decomposition. If it returns 0, * there is no decomposition. Any other value indicates a decomposition was * returned. */ LDAP_LUNICODE_F (int) ucdecomp LDAP_P((ac_uint4 code, ac_uint4 *num, ac_uint4 **decomp)); /* * Equivalent to ucdecomp() except that it includes compatibility * decompositions. */ LDAP_LUNICODE_F (int) uckdecomp LDAP_P((ac_uint4 code, ac_uint4 *num, ac_uint4 **decomp)); /* * If the code is a Hangul syllable, this routine decomposes it into the array * passed. The array size should be at least 3. */ LDAP_LUNICODE_F (int) ucdecomp_hangul LDAP_P((ac_uint4 code, ac_uint4 *num, ac_uint4 decomp[])); /* * This routine does canonical decomposition of the string in of length * inlen, and returns the decomposed string in out with length outlen. * The memory for out is allocated by this routine. It returns the length * of the decomposed string if okay, and -1 on error. */ LDAP_LUNICODE_F (int) uccanondecomp LDAP_P((const ac_uint4 *in, int inlen, ac_uint4 **out, int *outlen, void *ctx)); /* * Equivalent to uccanondecomp() except that it includes compatibility * decompositions. */ LDAP_LUNICODE_F (int) uccompatdecomp LDAP_P((const ac_uint4 *in, int inlen, ac_uint4 **out, int *outlen, void *ctx)); /************************************************************************** * * Functions for getting combining classes. * **************************************************************************/ /* * This will return the combining class for a character to be used with the * Canonical Ordering algorithm. */ LDAP_LUNICODE_F (ac_uint4) uccombining_class LDAP_P((ac_uint4 code)); /************************************************************************** * * Functions for getting numbers and digits. * **************************************************************************/ struct ucnumber { int numerator; int denominator; }; LDAP_LUNICODE_F (int) ucnumber_lookup LDAP_P((ac_uint4 code, struct ucnumber *num)); LDAP_LUNICODE_F (int) ucdigit_lookup LDAP_P((ac_uint4 code, int *digit)); /* * For compatibility with John Cowan's "uctype" package. */ LDAP_LUNICODE_F (struct ucnumber) ucgetnumber LDAP_P((ac_uint4 code)); LDAP_LUNICODE_F (int) ucgetdigit LDAP_P((ac_uint4 code)); /************************************************************************** * * Functions library initialization and cleanup. * **************************************************************************/ /* * Macros for specifying the data tables to be loaded, unloaded, or reloaded * by the ucdata_load(), ucdata_unload(), and ucdata_reload() routines. */ #define UCDATA_CASE 0x01 #define UCDATA_CTYPE 0x02 #define UCDATA_DECOMP 0x04 #define UCDATA_CMBCL 0x08 #define UCDATA_NUM 0x10 #define UCDATA_COMP 0x20 #define UCDATA_KDECOMP 0x40 #define UCDATA_ALL (UCDATA_CASE|UCDATA_CTYPE|UCDATA_DECOMP|\ UCDATA_CMBCL|UCDATA_NUM|UCDATA_COMP|UCDATA_KDECOMP) /* * Functions to load, unload, and reload specific data files. */ LDAP_LUNICODE_F (int) ucdata_load LDAP_P((char *paths, int mask)); LDAP_LUNICODE_F (void) ucdata_unload LDAP_P((int mask)); LDAP_LUNICODE_F (int) ucdata_reload LDAP_P((char *paths, int mask)); #ifdef UCDATA_DEPRECATED /* * Deprecated functions, now just compatibility macros. */ #define ucdata_setup(p) ucdata_load(p, UCDATA_ALL) #define ucdata_cleanup() ucdata_unload(UCDATA_ALL) #endif LDAP_END_DECL #endif /* _h_ucdata */ openldap-2.5.11+dfsg/libraries/liblunicode/ucdata/ucpgba.man0000644000175000017500000000516614172327167022513 0ustar ryanryan.\" .\" $Id: ucpgba.man,v 1.1 1999/11/19 16:08:34 mleisher Exp $ .\" .TH ucpgba 3 "19 November 1999" .SH NAME ucpgba \- functions for doing bidirectional reordering of Unicode text and logical and visual cursor motion .SH SYNOPSIS .nf #include #include ucstring_t *ucstring_create(unsigned long *source, unsigned long start, unsigned long end, int default_direction, int cursor_motion) .sp void ucstring_free(ucstring_t *string) .sp int ucstring_set_cursor_motion(ucstring_t *string, int cursor_motion) .sp int ucstring_cursor_right(ucstring_t *string, int count) .sp int ucstring_cursor_left(ucstring_t *string, int count) .sp void ucstring_cursor_info(ucstring_t *string, int *direction, unsigned long *position) .SH DESCRIPTION .TP 4 .BR Macros UCPGBA_LTR .br UCPGBA_RTL .br UCPGBA_CURSOR_VISUAL .br UCPGBA_CURSOR_LOGICAL .TP 4 .BR ucstring_create() This function will create a reordered string by using the implicit directionality of the characters in the specified substring. .sp The `default_direction' parameter should be one of UCPGBA_LTR or UCPGBA_RTL and is used only in cases where a string contains no characters with strong directionality. .sp The `cursor_motion' parameter should be one of UCPGBA_CURSOR_VISUAL or UCPGBA_CURSOR_LOGICAL, and is used to specify the initial cursor motion behavior. This behavior can be switched at any time using ustring_set_cursor_motion(). .TP 4 .BR ucstring_free() This function will deallocate the memory used by the string, including the string itself. .TP 4 .BR ucstring_cursor_info() This function will return the text position of the internal cursor and the directionality of the text at that position. The position returned is the original text position of the character. .TP 4 .BR ucstring_set_cursor_motion() This function will change the cursor motion type and return the previous cursor motion type. .TP 4 .BR ucstring_cursor_right() This function will move the internal cursor to the right according to the type of cursor motion set for the string. .sp If no cursor motion is performed, it returns 0. Otherwise it will return a 1. .TP 4 .BR ucstring_cursor_left() This function will move the internal cursor to the left according to the type of cursor motion set for the string. .sp If no cursor motion is performed, it returns 0. Otherwise it will return a 1. .SH "SEE ALSO" ucdata(3) .SH ACKNOWLEDGMENTS These are people who have helped with patches or alerted me about problems. .SH AUTHOR Mark Leisher .br Computing Research Lab .br New Mexico State University .br Email: mleisher@crl.nmsu.edu openldap-2.5.11+dfsg/libraries/liblunicode/ucdata/bidiapi.txt0000644000175000017500000000612714172327167022715 0ustar ryanryan# # $Id: bidiapi.txt,v 1.2 1999/11/19 15:24:29 mleisher Exp $ # "Pretty Good Bidi Algorithm" API The PGBA (Pretty Good Bidi Algorithm) is an effective alternative to the Unicode BiDi algorithm. It currently provides only implicit reordering and does not yet support explicit reordering codes that the Unicode BiDi algorithm supports. In addition to reordering, the PGBA includes cursor movement support for both visual and logical navigation. ----------------------------------------------------------------------------- #define UCPGBA_LTR 0 #define UCPGBA_RTL 1 These macros appear in the `direction' field of the data structures. #define UCPGBA_CURSOR_VISUAL 0 #define UCPGBA_CURSOR_LOGICAL 1 These macros are used to set the cursor movement for each reordered string. ----------------------------------------------------------------------------- ucstring_t *ucstring_create(unsigned long *source, unsigned long start, unsigned long end, int default_direction, int cursor_motion) This function will create a reordered string by using the implicit directionality of the characters in the specified substring. The `default_direction' parameter should be one of UCPGBA_LTR or UCPGBA_RTL and is used only in cases where a string contains no characters with strong directionality. The `cursor_motion' parameter should be one of UCPGBA_CURSOR_VISUAL or UCPGBA_CURSOR_LOGICAL, and is used to specify the initial cursor motion behavior. This behavior can be switched at any time using ustring_set_cursor_motion(). ----------------------------------------------------------------------------- void ucstring_free(ucstring_t *string) This function will deallocate the memory used by the string, including the string itself. ----------------------------------------------------------------------------- void ucstring_cursor_info(ustring_t *string, int *direction, unsigned long *position) This function will return the text position of the internal cursor and the directionality of the text at that position. The position returned is the original text position of the character. ----------------------------------------------------------------------------- int ucstring_set_cursor_motion(ucstring_t *string, int cursor_motion) This function will change the cursor motion type and return the previous cursor motion type. ----------------------------------------------------------------------------- int ucstring_cursor_right(ucstring_t *string, int count) This function will move the internal cursor to the right according to the type of cursor motion set for the string. If no cursor motion is performed, it returns 0. Otherwise it will return a 1. ----------------------------------------------------------------------------- int ucstring_cursor_left(ucstring_t *string, int count) This function will move the internal cursor to the left according to the type of cursor motion set for the string. If no cursor motion is performed, it returns 0. Otherwise it will return a 1. openldap-2.5.11+dfsg/libraries/liblunicode/utbm/0000755000175000017500000000000014172327167020253 5ustar ryanryanopenldap-2.5.11+dfsg/libraries/liblunicode/utbm/utbmstub.c0000644000175000017500000000547414172327167022276 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Copyright 1997, 1998, 1999 Computing Research Labs, * New Mexico State University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* $Id: utbmstub.c,v 1.1 1999/09/21 15:45:18 mleisher Exp $ */ #include "utbm.h" /* * This should be redefined to use the `isspace' function available in the * Unicode support on the platform where this is being used. */ #define _platform_isspace(x) 0 /* * Return non-zero for any character that should be considered the equivalent * of a space character. Return zero otherwise. */ int _utbm_isspace(ucs4_t c, int compress) { if (compress) return (c == 0x09 || c == 0x0a || c == 0x0d || c == 0x2028 || c == 0x2029 || _platform_isspace(c)) ? 1 : 0; return _platform_isspace(c); } /* * Return non-zero if the character is a control character, or zero otherwise. */ int _utbm_iscntrl(ucs4_t c) { return 0; } /* * Return non-zero if the character is a non-spacing character, or zero * otherwise. */ int _utbm_nonspacing(ucs4_t c) { return 0; } /* * Convert a character to lower case. */ ucs4_t _utbm_tolower(ucs4_t c) { return c; } /* * Convert a character to upper case. */ ucs4_t _utbm_toupper(ucs4_t c) { return c; } /* * Convert a character to title case. */ ucs4_t _utbm_totitle(ucs4_t c) { return c; } openldap-2.5.11+dfsg/libraries/liblunicode/utbm/utbm.c0000644000175000017500000003167514172327167021402 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Copyright 1997, 1998, 1999 Computing Research Labs, * New Mexico State University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* $Id: utbm.c,v 1.1 1999/09/21 15:45:17 mleisher Exp $ */ /* * Assumptions: * 1. Case conversions of UTF-16 characters must also be UTF-16 characters. * 2. Case conversions are all one-to-one. * 3. Text and pattern have already been normalized in some fashion. */ #include #include #include #include "utbm.h" /* * Single pattern character. */ typedef struct { ucs4_t lc; ucs4_t uc; ucs4_t tc; } _utbm_char_t; typedef struct { _utbm_char_t *ch; unsigned long skip; } _utbm_skip_t; typedef struct _utbm_pattern_t { unsigned long flags; _utbm_char_t *pat; unsigned long pat_used; unsigned long pat_size; unsigned long patlen; _utbm_skip_t *skip; unsigned long skip_used; unsigned long skip_size; unsigned long md4; } _utbm_pattern_t; /************************************************************************* * * Support functions. * *************************************************************************/ /* * Routine to look up the skip value for a character. */ static unsigned long _utbm_skip(utbm_pattern_t p, ucs2_t *start, ucs2_t *end) { unsigned long i; ucs4_t c1, c2; _utbm_skip_t *sp; if (start >= end) return 0; c1 = *start; c2 = (start + 1 < end) ? *(start + 1) : ~0; if (0xd800 <= c1 && c1 <= 0xdbff && 0xdc00 <= c2 && c2 <= 0xdfff) c1 = 0x10000 + (((c1 & 0x03ff) << 10) | (c2 & 0x03ff)); for (i = 0, sp = p->skip; i < p->skip_used; i++, sp++) { if (!((c1 ^ sp->ch->uc) & (c1 ^ sp->ch->lc) & (c1 ^ sp->ch->tc))) { return ((unsigned long) (end - start) < sp->skip) ? end - start : sp->skip; } } return p->patlen; } static int _utbm_match(utbm_pattern_t pat, ucs2_t *text, ucs2_t *start, ucs2_t *end, unsigned long *match_start, unsigned long *match_end) { int check_space; ucs4_t c1, c2; unsigned long count; _utbm_char_t *cp; /* * Set the potential match endpoint first. */ *match_end = (start - text) + 1; c1 = *start; c2 = (start + 1 < end) ? *(start + 1) : ~0; if (0xd800 <= c1 && c1 <= 0xdbff && 0xdc00 <= c2 && c2 <= 0xdfff) { c1 = 0x10000 + (((c1 & 0x03ff) << 10) | (c2 & 0x03ff)); /* * Adjust the match end point to occur after the UTF-16 character. */ *match_end = *match_end + 1; } if (pat->pat_used == 1) { *match_start = start - text; return 1; } /* * Compare backward. */ cp = pat->pat + (pat->pat_used - 1); for (count = pat->patlen; start > text && count > 0;) { /* * Ignore non-spacing characters if indicated. */ if (pat->flags & UTBM_IGNORE_NONSPACING) { while (start > text && _utbm_nonspacing(c1)) { c2 = *--start; c1 = (start - 1 > text) ? *(start - 1) : ~0; if (0xdc00 <= c2 && c2 <= 0xdfff && 0xd800 <= c1 && c1 <= 0xdbff) { c1 = 0x10000 + (((c1 & 0x03ff) << 10) | (c2 & 0x03ff)); start--; } else c1 = c2; } } /* * Handle space compression if indicated. */ if (pat->flags & UTBM_SPACE_COMPRESS) { check_space = 0; while (start > text && (_utbm_isspace(c1, 1) || _utbm_iscntrl(c1))) { check_space = _utbm_isspace(c1, 1); c2 = *--start; c1 = (start - 1 > text) ? *(start - 1) : ~0; if (0xdc00 <= c2 && c2 <= 0xdfff && 0xd800 <= c1 && c1 <= 0xdbff) { c1 = 0x10000 + (((c1 & 0x03ff) << 10) | (c2 & 0x03ff)); start--; } else c1 = c2; } /* * Handle things if space compression was indicated and one or * more member characters were found. */ if (check_space) { if (cp->uc != ' ') return 0; cp--; count--; } } /* * Handle the normal comparison cases. */ if (count > 0 && ((c1 ^ cp->uc) & (c1 ^ cp->lc) & (c1 ^ cp->tc))) return 0; count -= (c1 >= 0x10000) ? 2 : 1; if (count > 0) { cp--; /* * Get the next preceding character. */ if (start > text) { c2 = *--start; c1 = (start - 1 > text) ? *(start - 1) : ~0; if (0xdc00 <= c2 && c2 <= 0xdfff && 0xd800 <= c1 && c1 <= 0xdbff) { c1 = 0x10000 + (((c1 & 0x03ff) << 10) | (c2 & 0x03ff)); start--; } else c1 = c2; } } } /* * Set the match start position. */ *match_start = start - text; return 1; } /************************************************************************* * * API. * *************************************************************************/ utbm_pattern_t utbm_create_pattern(void) { utbm_pattern_t p; p = (utbm_pattern_t) malloc(sizeof(_utbm_pattern_t)); (void) memset((char *) p, '\0', sizeof(_utbm_pattern_t)); return p; } void utbm_free_pattern(utbm_pattern_t pattern) { if (pattern == 0) return; if (pattern->pat_size > 0) free((char *) pattern->pat); if (pattern->skip_size > 0) free((char *) pattern->skip); free((char *) pattern); } void utbm_compile(ucs2_t *pat, unsigned long patlen, unsigned long flags, utbm_pattern_t p) { int have_space; unsigned long i, j, k, slen; _utbm_char_t *cp; _utbm_skip_t *sp; ucs4_t c1, c2, sentinel; if (p == 0 || pat == 0 || *pat == 0 || patlen == 0) return; /* * Reset the pattern buffer. */ p->patlen = p->pat_used = p->skip_used = 0; /* * Set the flags. */ p->flags = flags; /* * Initialize the extra skip flag. */ p->md4 = 1; /* * Allocate more storage if necessary. */ if (patlen > p->pat_size) { if (p->pat_size == 0) { p->pat = (_utbm_char_t *) malloc(sizeof(_utbm_char_t) * patlen); p->skip = (_utbm_skip_t *) malloc(sizeof(_utbm_skip_t) * patlen); } else { p->pat = (_utbm_char_t *) realloc((char *) p->pat, sizeof(_utbm_char_t) * patlen); p->skip = (_utbm_skip_t *) realloc((char *) p->skip, sizeof(_utbm_skip_t) * patlen); } p->pat_size = p->skip_size = patlen; } /* * Preprocess the pattern to remove controls (if specified) and determine * case. */ for (have_space = 0, cp = p->pat, i = 0; i < patlen; i++) { c1 = pat[i]; c2 = (i + 1 < patlen) ? pat[i + 1] : ~0; if (0xd800 <= c1 && c1 <= 0xdbff && 0xdc00 <= c2 && c2 <= 0xdfff) c1 = 0x10000 + (((c1 & 0x03ff) << 10) | (c2 & 0x03ff)); /* * Make sure the `have_space' flag is turned off if the character * is not an appropriate one. */ if (!_utbm_isspace(c1, flags & UTBM_SPACE_COMPRESS)) have_space = 0; /* * If non-spacing characters should be ignored, do it here. */ if ((flags & UTBM_IGNORE_NONSPACING) && _utbm_nonspacing(c1)) continue; /* * Check if spaces and controls need to be compressed. */ if (flags & UTBM_SPACE_COMPRESS) { if (_utbm_isspace(c1, 1)) { if (!have_space) { /* * Add a space and set the flag. */ cp->uc = cp->lc = cp->tc = ' '; cp++; /* * Increase the real pattern length. */ p->patlen++; sentinel = ' '; have_space = 1; } continue; } /* * Ignore all control characters. */ if (_utbm_iscntrl(c1)) continue; } /* * Add the character. */ if (flags & UTBM_CASEFOLD) { cp->uc = _utbm_toupper(c1); cp->lc = _utbm_tolower(c1); cp->tc = _utbm_totitle(c1); } else cp->uc = cp->lc = cp->tc = c1; /* * Set the sentinel character. */ sentinel = cp->uc; /* * Move to the next character. */ cp++; /* * Increase the real pattern length appropriately. */ p->patlen += (c1 >= 0x10000) ? 2 : 1; /* * Increment the loop index for UTF-16 characters. */ i += (c1 >= 0x10000) ? 1 : 0; } /* * Set the number of characters actually used. */ p->pat_used = cp - p->pat; /* * Go through and construct the skip array and determine the actual length * of the pattern in UCS2 terms. */ slen = p->patlen - 1; cp = p->pat; for (i = k = 0; i < p->pat_used; i++, cp++) { /* * Locate the character in the skip array. */ for (sp = p->skip, j = 0; j < p->skip_used && sp->ch->uc != cp->uc; j++, sp++) ; /* * If the character is not found, set the new skip element and * increase the number of skip elements. */ if (j == p->skip_used) { sp->ch = cp; p->skip_used++; } /* * Set the updated skip value. If the character is UTF-16 and is * not the last one in the pattern, add one to its skip value. */ sp->skip = slen - k; if (cp->uc >= 0x10000 && k + 2 < slen) sp->skip++; /* * Set the new extra skip for the sentinel character. */ if (((cp->uc >= 0x10000 && k + 2 <= slen) || k + 1 <= slen) && cp->uc == sentinel) p->md4 = slen - k; /* * Increase the actual index. */ k += (cp->uc >= 0x10000) ? 2 : 1; } } int utbm_exec(utbm_pattern_t pat, ucs2_t *text, unsigned long textlen, unsigned long *match_start, unsigned long *match_end) { unsigned long k; ucs2_t *start, *end; if (pat == 0 || pat->pat_used == 0 || text == 0 || textlen == 0 || textlen < pat->patlen) return 0; start = text + pat->patlen; end = text + textlen; /* * Adjust the start point if it points to a low surrogate. */ if (0xdc00 <= *start && *start <= 0xdfff && 0xd800 <= *(start - 1) && *(start - 1) <= 0xdbff) start--; while (start < end) { while ((k = _utbm_skip(pat, start, end))) { start += k; if (start < end && 0xdc00 <= *start && *start <= 0xdfff && 0xd800 <= *(start - 1) && *(start - 1) <= 0xdbff) start--; } if (start < end && _utbm_match(pat, text, start, end, match_start, match_end)) return 1; start += pat->md4; if (start < end && 0xdc00 <= *start && *start <= 0xdfff && 0xd800 <= *(start - 1) && *(start - 1) <= 0xdbff) start--; } return 0; } openldap-2.5.11+dfsg/libraries/liblunicode/utbm/README0000644000175000017500000001002014172327167021124 0ustar ryanryan# # $Id: README,v 1.1 1999/09/21 15:45:17 mleisher Exp $ # # Copyright 1997, 1998, 1999 Computing Research Labs, # New Mexico State University # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT # OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR # THE USE OR OTHER DEALINGS IN THE SOFTWARE. # Unicode and Boyer-Moore Searching Version 0.2 UTBM (Unicode Tuned Boyer-Moore) is a simple package that provides tuned Boyer-Moore searches on Unicode UCS2 text (handles high and low surrogates). --------------------------------------------------------------------------- Assumptions: o Search pattern and text already normalized in some fashion. o Upper, lower, and title case conversions are one-to-one. o For conversions between upper, lower, and title case, UCS2 characters always convert to other UCS2 characters, and UTF-16 characters always convert to other UTF-16 characters. Flags: UTBM provides three processing flags: o UTBM_CASEFOLD - search in a case-insensitive manner. o UTBM_IGNORE_NONSPACING - ignore non-spacing characters in the pattern and the text. o UTBM_SPACE_COMPRESS - view as a *single space*, sequential groups of U+2028, U+2029, '\n', '\r', '\t', and any character identified as a space by the Unicode support on the platform. This flag also causes all characters identified as control by the Unicode support on the platform to be ignored (except for '\n', '\r', and '\t'). --------------------------------------------------------------------------- Before using UTBM ----------------- Before UTBM is used, some functions need to be created. The "utbmstub.c" file contains stubs that need to be rewritten so they work with the Unicode support on the platform on which this package is being used. Using UTBM ---------- Sample pseudo-code fragment. utbm_pattern_t pat; ucs2_t *pattern, *text; unsigned long patternlen, textlen; unsigned long flags, match_start, match_end; /* * Allocate the dynamic storage needed for a search pattern. */ pat = utbm_create_pattern(); /* * Set the search flags desired. */ flags = UTBM_CASEFOLD|UTBM_IGNORE_NONSPACING; /* * Compile the search pattern. */ utbm_compile(pattern, patternlen, flags, pat); /* * Find the first occurrence of the search pattern in the text. */ if (utbm_exec(pat, text, textlen, &match_start, &match_end)) printf("MATCH: %ld %ld\n", match_start, match_end); /* * Free the dynamic storage used for the search pattern. */ ure_free_pattern(pat); --------------------------------------------------------------------------- Mark Leisher 2 May 1997 =========================================================================== CHANGES ------- Version: 0.2 Date : 21 September 1999 ========================== 1. Added copyright stuff and put in CVS. openldap-2.5.11+dfsg/libraries/liblunicode/utbm/utbm.h0000644000175000017500000000715614172327167021404 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Copyright 1997, 1998, 1999 Computing Research Labs, * New Mexico State University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* $Id: utbm.h,v 1.1 1999/09/21 15:45:18 mleisher Exp $ */ #ifndef _h_utbm #define _h_utbm #include "portable.h" LDAP_BEGIN_DECL /************************************************************************* * * Types. * *************************************************************************/ /* * Fundamental character types. */ typedef unsigned long ucs4_t; typedef unsigned short ucs2_t; /* * An opaque type used for the search pattern. */ typedef struct _utbm_pattern_t *utbm_pattern_t; /************************************************************************* * * Flags. * *************************************************************************/ #define UTBM_CASEFOLD 0x01 #define UTBM_IGNORE_NONSPACING 0x02 #define UTBM_SPACE_COMPRESS 0x04 /************************************************************************* * * API. * *************************************************************************/ LDAP_LUNICODE_F (utbm_pattern_t) utbm_create_pattern LDAP_P((void)); LDAP_LUNICODE_F (void) utbm_free_pattern LDAP_P((utbm_pattern_t pattern)); LDAP_LUNICODE_F (void) utbm_compile LDAP_P((ucs2_t *pat, unsigned long patlen, unsigned long flags, utbm_pattern_t pattern)); LDAP_LUNICODE_F (int) utbm_exec LDAP_P((utbm_pattern_t pat, ucs2_t *text, unsigned long textlen, unsigned long *match_start, unsigned long *match_end)); /************************************************************************* * * Prototypes for the stub functions needed. * *************************************************************************/ LDAP_LUNICODE_F (int) _utbm_isspace LDAP_P((ucs4_t c, int compress)); LDAP_LUNICODE_F (int) _utbm_iscntrl LDAP_P((ucs4_t c)); LDAP_LUNICODE_F (int) _utbm_nonspacing LDAP_P((ucs4_t c)); LDAP_LUNICODE_F (ucs4_t) _utbm_tolower LDAP_P((ucs4_t c)); LDAP_LUNICODE_F (ucs4_t) _utbm_toupper LDAP_P((ucs4_t c)); LDAP_LUNICODE_F (ucs4_t) _utbm_totitle LDAP_P((ucs4_t c)); LDAP_END_DECL #endif #endif /* _h_utbm */ openldap-2.5.11+dfsg/libraries/liblunicode/UCD-Terms0000644000175000017500000000244014172327167020732 0ustar ryanryanUCD Terms of Use (http://www.unicode.org/Public/UNIDATA/UCD.html) Disclaimer The Unicode Character Database is provided as is by Unicode, Inc. No claims are made as to fitness for any particular purpose. No warranties of any kind are expressed or implied. The recipient agrees to determine applicability of information provided. If this file has been purchased on magnetic or optical media from Unicode, Inc., the sole remedy for any claim will be exchange of defective media within 90 days of receipt. This disclaimer is applicable for all other data files accompanying the Unicode Character Database, some of which have been compiled by the Unicode Consortium, and some of which have been supplied by other sources. Limitations on Rights to Redistribute This Data Recipient is granted the right to make copies in any form for internal distribution and to freely use the information supplied in the creation of products supporting the Unicode (TM) Standard. The files in the Unicode Character Database can be redistributed to third parties or other organizations (whether for profit or not) as long as this notice and the disclaimer notice are retained. Information can be extracted from these files and used in documentation or programs, as long as there is an accompanying notice indicating the source. openldap-2.5.11+dfsg/libraries/liblunicode/UnicodeData.txt0000644000175000017500000314257514172327167022246 0ustar ryanryan0000;;Cc;0;BN;;;;;N;NULL;;;; 0001;;Cc;0;BN;;;;;N;START OF HEADING;;;; 0002;;Cc;0;BN;;;;;N;START OF TEXT;;;; 0003;;Cc;0;BN;;;;;N;END OF TEXT;;;; 0004;;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; 0005;;Cc;0;BN;;;;;N;ENQUIRY;;;; 0006;;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; 0007;;Cc;0;BN;;;;;N;BELL;;;; 0008;;Cc;0;BN;;;;;N;BACKSPACE;;;; 0009;;Cc;0;S;;;;;N;CHARACTER TABULATION;;;; 000A;;Cc;0;B;;;;;N;LINE FEED (LF);;;; 000B;;Cc;0;S;;;;;N;LINE TABULATION;;;; 000C;;Cc;0;WS;;;;;N;FORM FEED (FF);;;; 000D;;Cc;0;B;;;;;N;CARRIAGE RETURN (CR);;;; 000E;;Cc;0;BN;;;;;N;SHIFT OUT;;;; 000F;;Cc;0;BN;;;;;N;SHIFT IN;;;; 0010;;Cc;0;BN;;;;;N;DATA LINK ESCAPE;;;; 0011;;Cc;0;BN;;;;;N;DEVICE CONTROL ONE;;;; 0012;;Cc;0;BN;;;;;N;DEVICE CONTROL TWO;;;; 0013;;Cc;0;BN;;;;;N;DEVICE CONTROL THREE;;;; 0014;;Cc;0;BN;;;;;N;DEVICE CONTROL FOUR;;;; 0015;;Cc;0;BN;;;;;N;NEGATIVE ACKNOWLEDGE;;;; 0016;;Cc;0;BN;;;;;N;SYNCHRONOUS IDLE;;;; 0017;;Cc;0;BN;;;;;N;END OF TRANSMISSION BLOCK;;;; 0018;;Cc;0;BN;;;;;N;CANCEL;;;; 0019;;Cc;0;BN;;;;;N;END OF MEDIUM;;;; 001A;;Cc;0;BN;;;;;N;SUBSTITUTE;;;; 001B;;Cc;0;BN;;;;;N;ESCAPE;;;; 001C;;Cc;0;B;;;;;N;INFORMATION SEPARATOR FOUR;;;; 001D;;Cc;0;B;;;;;N;INFORMATION SEPARATOR THREE;;;; 001E;;Cc;0;B;;;;;N;INFORMATION SEPARATOR TWO;;;; 001F;;Cc;0;S;;;;;N;INFORMATION SEPARATOR ONE;;;; 0020;SPACE;Zs;0;WS;;;;;N;;;;; 0021;EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; 0022;QUOTATION MARK;Po;0;ON;;;;;N;;;;; 0023;NUMBER SIGN;Po;0;ET;;;;;N;;;;; 0024;DOLLAR SIGN;Sc;0;ET;;;;;N;;;;; 0025;PERCENT SIGN;Po;0;ET;;;;;N;;;;; 0026;AMPERSAND;Po;0;ON;;;;;N;;;;; 0027;APOSTROPHE;Po;0;ON;;;;;N;APOSTROPHE-QUOTE;;;; 0028;LEFT PARENTHESIS;Ps;0;ON;;;;;Y;OPENING PARENTHESIS;;;; 0029;RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;CLOSING PARENTHESIS;;;; 002A;ASTERISK;Po;0;ON;;;;;N;;;;; 002B;PLUS SIGN;Sm;0;ET;;;;;N;;;;; 002C;COMMA;Po;0;CS;;;;;N;;;;; 002D;HYPHEN-MINUS;Pd;0;ET;;;;;N;;;;; 002E;FULL STOP;Po;0;CS;;;;;N;PERIOD;;;; 002F;SOLIDUS;Po;0;ES;;;;;N;SLASH;;;; 0030;DIGIT ZERO;Nd;0;EN;;0;0;0;N;;;;; 0031;DIGIT ONE;Nd;0;EN;;1;1;1;N;;;;; 0032;DIGIT TWO;Nd;0;EN;;2;2;2;N;;;;; 0033;DIGIT THREE;Nd;0;EN;;3;3;3;N;;;;; 0034;DIGIT FOUR;Nd;0;EN;;4;4;4;N;;;;; 0035;DIGIT FIVE;Nd;0;EN;;5;5;5;N;;;;; 0036;DIGIT SIX;Nd;0;EN;;6;6;6;N;;;;; 0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;; 0038;DIGIT EIGHT;Nd;0;EN;;8;8;8;N;;;;; 0039;DIGIT NINE;Nd;0;EN;;9;9;9;N;;;;; 003A;COLON;Po;0;CS;;;;;N;;;;; 003B;SEMICOLON;Po;0;ON;;;;;N;;;;; 003C;LESS-THAN SIGN;Sm;0;ON;;;;;Y;;;;; 003D;EQUALS SIGN;Sm;0;ON;;;;;N;;;;; 003E;GREATER-THAN SIGN;Sm;0;ON;;;;;Y;;;;; 003F;QUESTION MARK;Po;0;ON;;;;;N;;;;; 0040;COMMERCIAL AT;Po;0;ON;;;;;N;;;;; 0041;LATIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0061; 0042;LATIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;0062; 0043;LATIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;0063; 0044;LATIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;0064; 0045;LATIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;0065; 0046;LATIN CAPITAL LETTER F;Lu;0;L;;;;;N;;;;0066; 0047;LATIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;0067; 0048;LATIN CAPITAL LETTER H;Lu;0;L;;;;;N;;;;0068; 0049;LATIN CAPITAL LETTER I;Lu;0;L;;;;;N;;;;0069; 004A;LATIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;006A; 004B;LATIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;006B; 004C;LATIN CAPITAL LETTER L;Lu;0;L;;;;;N;;;;006C; 004D;LATIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;006D; 004E;LATIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;006E; 004F;LATIN CAPITAL LETTER O;Lu;0;L;;;;;N;;;;006F; 0050;LATIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;0070; 0051;LATIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;0071; 0052;LATIN CAPITAL LETTER R;Lu;0;L;;;;;N;;;;0072; 0053;LATIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;0073; 0054;LATIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;0074; 0055;LATIN CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0075; 0056;LATIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;0076; 0057;LATIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;0077; 0058;LATIN CAPITAL LETTER X;Lu;0;L;;;;;N;;;;0078; 0059;LATIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;0079; 005A;LATIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;007A; 005B;LEFT SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING SQUARE BRACKET;;;; 005C;REVERSE SOLIDUS;Po;0;ON;;;;;N;BACKSLASH;;;; 005D;RIGHT SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING SQUARE BRACKET;;;; 005E;CIRCUMFLEX ACCENT;Sk;0;ON;;;;;N;SPACING CIRCUMFLEX;;;; 005F;LOW LINE;Pc;0;ON;;;;;N;SPACING UNDERSCORE;;;; 0060;GRAVE ACCENT;Sk;0;ON;;;;;N;SPACING GRAVE;;;; 0061;LATIN SMALL LETTER A;Ll;0;L;;;;;N;;;0041;;0041 0062;LATIN SMALL LETTER B;Ll;0;L;;;;;N;;;0042;;0042 0063;LATIN SMALL LETTER C;Ll;0;L;;;;;N;;;0043;;0043 0064;LATIN SMALL LETTER D;Ll;0;L;;;;;N;;;0044;;0044 0065;LATIN SMALL LETTER E;Ll;0;L;;;;;N;;;0045;;0045 0066;LATIN SMALL LETTER F;Ll;0;L;;;;;N;;;0046;;0046 0067;LATIN SMALL LETTER G;Ll;0;L;;;;;N;;;0047;;0047 0068;LATIN SMALL LETTER H;Ll;0;L;;;;;N;;;0048;;0048 0069;LATIN SMALL LETTER I;Ll;0;L;;;;;N;;;0049;;0049 006A;LATIN SMALL LETTER J;Ll;0;L;;;;;N;;;004A;;004A 006B;LATIN SMALL LETTER K;Ll;0;L;;;;;N;;;004B;;004B 006C;LATIN SMALL LETTER L;Ll;0;L;;;;;N;;;004C;;004C 006D;LATIN SMALL LETTER M;Ll;0;L;;;;;N;;;004D;;004D 006E;LATIN SMALL LETTER N;Ll;0;L;;;;;N;;;004E;;004E 006F;LATIN SMALL LETTER O;Ll;0;L;;;;;N;;;004F;;004F 0070;LATIN SMALL LETTER P;Ll;0;L;;;;;N;;;0050;;0050 0071;LATIN SMALL LETTER Q;Ll;0;L;;;;;N;;;0051;;0051 0072;LATIN SMALL LETTER R;Ll;0;L;;;;;N;;;0052;;0052 0073;LATIN SMALL LETTER S;Ll;0;L;;;;;N;;;0053;;0053 0074;LATIN SMALL LETTER T;Ll;0;L;;;;;N;;;0054;;0054 0075;LATIN SMALL LETTER U;Ll;0;L;;;;;N;;;0055;;0055 0076;LATIN SMALL LETTER V;Ll;0;L;;;;;N;;;0056;;0056 0077;LATIN SMALL LETTER W;Ll;0;L;;;;;N;;;0057;;0057 0078;LATIN SMALL LETTER X;Ll;0;L;;;;;N;;;0058;;0058 0079;LATIN SMALL LETTER Y;Ll;0;L;;;;;N;;;0059;;0059 007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A 007B;LEFT CURLY BRACKET;Ps;0;ON;;;;;Y;OPENING CURLY BRACKET;;;; 007C;VERTICAL LINE;Sm;0;ON;;;;;N;VERTICAL BAR;;;; 007D;RIGHT CURLY BRACKET;Pe;0;ON;;;;;Y;CLOSING CURLY BRACKET;;;; 007E;TILDE;Sm;0;ON;;;;;N;;;;; 007F;;Cc;0;BN;;;;;N;DELETE;;;; 0080;;Cc;0;BN;;;;;N;;;;; 0081;;Cc;0;BN;;;;;N;;;;; 0082;;Cc;0;BN;;;;;N;BREAK PERMITTED HERE;;;; 0083;;Cc;0;BN;;;;;N;NO BREAK HERE;;;; 0084;;Cc;0;BN;;;;;N;;;;; 0085;;Cc;0;B;;;;;N;NEXT LINE (NEL);;;; 0086;;Cc;0;BN;;;;;N;START OF SELECTED AREA;;;; 0087;;Cc;0;BN;;;;;N;END OF SELECTED AREA;;;; 0088;;Cc;0;BN;;;;;N;CHARACTER TABULATION SET;;;; 0089;;Cc;0;BN;;;;;N;CHARACTER TABULATION WITH JUSTIFICATION;;;; 008A;;Cc;0;BN;;;;;N;LINE TABULATION SET;;;; 008B;;Cc;0;BN;;;;;N;PARTIAL LINE FORWARD;;;; 008C;;Cc;0;BN;;;;;N;PARTIAL LINE BACKWARD;;;; 008D;;Cc;0;BN;;;;;N;REVERSE LINE FEED;;;; 008E;;Cc;0;BN;;;;;N;SINGLE SHIFT TWO;;;; 008F;;Cc;0;BN;;;;;N;SINGLE SHIFT THREE;;;; 0090;;Cc;0;BN;;;;;N;DEVICE CONTROL STRING;;;; 0091;;Cc;0;BN;;;;;N;PRIVATE USE ONE;;;; 0092;;Cc;0;BN;;;;;N;PRIVATE USE TWO;;;; 0093;;Cc;0;BN;;;;;N;SET TRANSMIT STATE;;;; 0094;;Cc;0;BN;;;;;N;CANCEL CHARACTER;;;; 0095;;Cc;0;BN;;;;;N;MESSAGE WAITING;;;; 0096;;Cc;0;BN;;;;;N;START OF GUARDED AREA;;;; 0097;;Cc;0;BN;;;;;N;END OF GUARDED AREA;;;; 0098;;Cc;0;BN;;;;;N;START OF STRING;;;; 0099;;Cc;0;BN;;;;;N;;;;; 009A;;Cc;0;BN;;;;;N;SINGLE CHARACTER INTRODUCER;;;; 009B;;Cc;0;BN;;;;;N;CONTROL SEQUENCE INTRODUCER;;;; 009C;;Cc;0;BN;;;;;N;STRING TERMINATOR;;;; 009D;;Cc;0;BN;;;;;N;OPERATING SYSTEM COMMAND;;;; 009E;;Cc;0;BN;;;;;N;PRIVACY MESSAGE;;;; 009F;;Cc;0;BN;;;;;N;APPLICATION PROGRAM COMMAND;;;; 00A0;NO-BREAK SPACE;Zs;0;CS; 0020;;;;N;NON-BREAKING SPACE;;;; 00A1;INVERTED EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; 00A2;CENT SIGN;Sc;0;ET;;;;;N;;;;; 00A3;POUND SIGN;Sc;0;ET;;;;;N;;;;; 00A4;CURRENCY SIGN;Sc;0;ET;;;;;N;;;;; 00A5;YEN SIGN;Sc;0;ET;;;;;N;;;;; 00A6;BROKEN BAR;So;0;ON;;;;;N;BROKEN VERTICAL BAR;;;; 00A7;SECTION SIGN;So;0;ON;;;;;N;;;;; 00A8;DIAERESIS;Sk;0;ON; 0020 0308;;;;N;SPACING DIAERESIS;;;; 00A9;COPYRIGHT SIGN;So;0;ON;;;;;N;;;;; 00AA;FEMININE ORDINAL INDICATOR;Ll;0;L; 0061;;;;N;;;;; 00AB;LEFT-POINTING DOUBLE ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING GUILLEMET;*;;; 00AC;NOT SIGN;Sm;0;ON;;;;;N;;;;; 00AD;SOFT HYPHEN;Pd;0;ON;;;;;N;;;;; 00AE;REGISTERED SIGN;So;0;ON;;;;;N;REGISTERED TRADE MARK SIGN;;;; 00AF;MACRON;Sk;0;ON; 0020 0304;;;;N;SPACING MACRON;;;; 00B0;DEGREE SIGN;So;0;ET;;;;;N;;;;; 00B1;PLUS-MINUS SIGN;Sm;0;ET;;;;;N;PLUS-OR-MINUS SIGN;;;; 00B2;SUPERSCRIPT TWO;No;0;EN; 0032;2;2;2;N;SUPERSCRIPT DIGIT TWO;;;; 00B3;SUPERSCRIPT THREE;No;0;EN; 0033;3;3;3;N;SUPERSCRIPT DIGIT THREE;;;; 00B4;ACUTE ACCENT;Sk;0;ON; 0020 0301;;;;N;SPACING ACUTE;;;; 00B5;MICRO SIGN;Ll;0;L; 03BC;;;;N;;;039C;;039C 00B6;PILCROW SIGN;So;0;ON;;;;;N;PARAGRAPH SIGN;;;; 00B7;MIDDLE DOT;Po;0;ON;;;;;N;;;;; 00B8;CEDILLA;Sk;0;ON; 0020 0327;;;;N;SPACING CEDILLA;;;; 00B9;SUPERSCRIPT ONE;No;0;EN; 0031;1;1;1;N;SUPERSCRIPT DIGIT ONE;;;; 00BA;MASCULINE ORDINAL INDICATOR;Ll;0;L; 006F;;;;N;;;;; 00BB;RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING GUILLEMET;*;;; 00BC;VULGAR FRACTION ONE QUARTER;No;0;ON; 0031 2044 0034;;;1/4;N;FRACTION ONE QUARTER;;;; 00BD;VULGAR FRACTION ONE HALF;No;0;ON; 0031 2044 0032;;;1/2;N;FRACTION ONE HALF;;;; 00BE;VULGAR FRACTION THREE QUARTERS;No;0;ON; 0033 2044 0034;;;3/4;N;FRACTION THREE QUARTERS;;;; 00BF;INVERTED QUESTION MARK;Po;0;ON;;;;;N;;;;; 00C0;LATIN CAPITAL LETTER A WITH GRAVE;Lu;0;L;0041 0300;;;;N;LATIN CAPITAL LETTER A GRAVE;;;00E0; 00C1;LATIN CAPITAL LETTER A WITH ACUTE;Lu;0;L;0041 0301;;;;N;LATIN CAPITAL LETTER A ACUTE;;;00E1; 00C2;LATIN CAPITAL LETTER A WITH CIRCUMFLEX;Lu;0;L;0041 0302;;;;N;LATIN CAPITAL LETTER A CIRCUMFLEX;;;00E2; 00C3;LATIN CAPITAL LETTER A WITH TILDE;Lu;0;L;0041 0303;;;;N;LATIN CAPITAL LETTER A TILDE;;;00E3; 00C4;LATIN CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0041 0308;;;;N;LATIN CAPITAL LETTER A DIAERESIS;;;00E4; 00C5;LATIN CAPITAL LETTER A WITH RING ABOVE;Lu;0;L;0041 030A;;;;N;LATIN CAPITAL LETTER A RING;;;00E5; 00C6;LATIN CAPITAL LETTER AE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER A E;ash *;;00E6; 00C7;LATIN CAPITAL LETTER C WITH CEDILLA;Lu;0;L;0043 0327;;;;N;LATIN CAPITAL LETTER C CEDILLA;;;00E7; 00C8;LATIN CAPITAL LETTER E WITH GRAVE;Lu;0;L;0045 0300;;;;N;LATIN CAPITAL LETTER E GRAVE;;;00E8; 00C9;LATIN CAPITAL LETTER E WITH ACUTE;Lu;0;L;0045 0301;;;;N;LATIN CAPITAL LETTER E ACUTE;;;00E9; 00CA;LATIN CAPITAL LETTER E WITH CIRCUMFLEX;Lu;0;L;0045 0302;;;;N;LATIN CAPITAL LETTER E CIRCUMFLEX;;;00EA; 00CB;LATIN CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;0045 0308;;;;N;LATIN CAPITAL LETTER E DIAERESIS;;;00EB; 00CC;LATIN CAPITAL LETTER I WITH GRAVE;Lu;0;L;0049 0300;;;;N;LATIN CAPITAL LETTER I GRAVE;;;00EC; 00CD;LATIN CAPITAL LETTER I WITH ACUTE;Lu;0;L;0049 0301;;;;N;LATIN CAPITAL LETTER I ACUTE;;;00ED; 00CE;LATIN CAPITAL LETTER I WITH CIRCUMFLEX;Lu;0;L;0049 0302;;;;N;LATIN CAPITAL LETTER I CIRCUMFLEX;;;00EE; 00CF;LATIN CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0049 0308;;;;N;LATIN CAPITAL LETTER I DIAERESIS;;;00EF; 00D0;LATIN CAPITAL LETTER ETH;Lu;0;L;;;;;N;;Icelandic;;00F0; 00D1;LATIN CAPITAL LETTER N WITH TILDE;Lu;0;L;004E 0303;;;;N;LATIN CAPITAL LETTER N TILDE;;;00F1; 00D2;LATIN CAPITAL LETTER O WITH GRAVE;Lu;0;L;004F 0300;;;;N;LATIN CAPITAL LETTER O GRAVE;;;00F2; 00D3;LATIN CAPITAL LETTER O WITH ACUTE;Lu;0;L;004F 0301;;;;N;LATIN CAPITAL LETTER O ACUTE;;;00F3; 00D4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX;Lu;0;L;004F 0302;;;;N;LATIN CAPITAL LETTER O CIRCUMFLEX;;;00F4; 00D5;LATIN CAPITAL LETTER O WITH TILDE;Lu;0;L;004F 0303;;;;N;LATIN CAPITAL LETTER O TILDE;;;00F5; 00D6;LATIN CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;004F 0308;;;;N;LATIN CAPITAL LETTER O DIAERESIS;;;00F6; 00D7;MULTIPLICATION SIGN;Sm;0;ON;;;;;N;;;;; 00D8;LATIN CAPITAL LETTER O WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O SLASH;;;00F8; 00D9;LATIN CAPITAL LETTER U WITH GRAVE;Lu;0;L;0055 0300;;;;N;LATIN CAPITAL LETTER U GRAVE;;;00F9; 00DA;LATIN CAPITAL LETTER U WITH ACUTE;Lu;0;L;0055 0301;;;;N;LATIN CAPITAL LETTER U ACUTE;;;00FA; 00DB;LATIN CAPITAL LETTER U WITH CIRCUMFLEX;Lu;0;L;0055 0302;;;;N;LATIN CAPITAL LETTER U CIRCUMFLEX;;;00FB; 00DC;LATIN CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0055 0308;;;;N;LATIN CAPITAL LETTER U DIAERESIS;;;00FC; 00DD;LATIN CAPITAL LETTER Y WITH ACUTE;Lu;0;L;0059 0301;;;;N;LATIN CAPITAL LETTER Y ACUTE;;;00FD; 00DE;LATIN CAPITAL LETTER THORN;Lu;0;L;;;;;N;;Icelandic;;00FE; 00DF;LATIN SMALL LETTER SHARP S;Ll;0;L;;;;;N;;German;;; 00E0;LATIN SMALL LETTER A WITH GRAVE;Ll;0;L;0061 0300;;;;N;LATIN SMALL LETTER A GRAVE;;00C0;;00C0 00E1;LATIN SMALL LETTER A WITH ACUTE;Ll;0;L;0061 0301;;;;N;LATIN SMALL LETTER A ACUTE;;00C1;;00C1 00E2;LATIN SMALL LETTER A WITH CIRCUMFLEX;Ll;0;L;0061 0302;;;;N;LATIN SMALL LETTER A CIRCUMFLEX;;00C2;;00C2 00E3;LATIN SMALL LETTER A WITH TILDE;Ll;0;L;0061 0303;;;;N;LATIN SMALL LETTER A TILDE;;00C3;;00C3 00E4;LATIN SMALL LETTER A WITH DIAERESIS;Ll;0;L;0061 0308;;;;N;LATIN SMALL LETTER A DIAERESIS;;00C4;;00C4 00E5;LATIN SMALL LETTER A WITH RING ABOVE;Ll;0;L;0061 030A;;;;N;LATIN SMALL LETTER A RING;;00C5;;00C5 00E6;LATIN SMALL LETTER AE;Ll;0;L;;;;;N;LATIN SMALL LETTER A E;ash *;00C6;;00C6 00E7;LATIN SMALL LETTER C WITH CEDILLA;Ll;0;L;0063 0327;;;;N;LATIN SMALL LETTER C CEDILLA;;00C7;;00C7 00E8;LATIN SMALL LETTER E WITH GRAVE;Ll;0;L;0065 0300;;;;N;LATIN SMALL LETTER E GRAVE;;00C8;;00C8 00E9;LATIN SMALL LETTER E WITH ACUTE;Ll;0;L;0065 0301;;;;N;LATIN SMALL LETTER E ACUTE;;00C9;;00C9 00EA;LATIN SMALL LETTER E WITH CIRCUMFLEX;Ll;0;L;0065 0302;;;;N;LATIN SMALL LETTER E CIRCUMFLEX;;00CA;;00CA 00EB;LATIN SMALL LETTER E WITH DIAERESIS;Ll;0;L;0065 0308;;;;N;LATIN SMALL LETTER E DIAERESIS;;00CB;;00CB 00EC;LATIN SMALL LETTER I WITH GRAVE;Ll;0;L;0069 0300;;;;N;LATIN SMALL LETTER I GRAVE;;00CC;;00CC 00ED;LATIN SMALL LETTER I WITH ACUTE;Ll;0;L;0069 0301;;;;N;LATIN SMALL LETTER I ACUTE;;00CD;;00CD 00EE;LATIN SMALL LETTER I WITH CIRCUMFLEX;Ll;0;L;0069 0302;;;;N;LATIN SMALL LETTER I CIRCUMFLEX;;00CE;;00CE 00EF;LATIN SMALL LETTER I WITH DIAERESIS;Ll;0;L;0069 0308;;;;N;LATIN SMALL LETTER I DIAERESIS;;00CF;;00CF 00F0;LATIN SMALL LETTER ETH;Ll;0;L;;;;;N;;Icelandic;00D0;;00D0 00F1;LATIN SMALL LETTER N WITH TILDE;Ll;0;L;006E 0303;;;;N;LATIN SMALL LETTER N TILDE;;00D1;;00D1 00F2;LATIN SMALL LETTER O WITH GRAVE;Ll;0;L;006F 0300;;;;N;LATIN SMALL LETTER O GRAVE;;00D2;;00D2 00F3;LATIN SMALL LETTER O WITH ACUTE;Ll;0;L;006F 0301;;;;N;LATIN SMALL LETTER O ACUTE;;00D3;;00D3 00F4;LATIN SMALL LETTER O WITH CIRCUMFLEX;Ll;0;L;006F 0302;;;;N;LATIN SMALL LETTER O CIRCUMFLEX;;00D4;;00D4 00F5;LATIN SMALL LETTER O WITH TILDE;Ll;0;L;006F 0303;;;;N;LATIN SMALL LETTER O TILDE;;00D5;;00D5 00F6;LATIN SMALL LETTER O WITH DIAERESIS;Ll;0;L;006F 0308;;;;N;LATIN SMALL LETTER O DIAERESIS;;00D6;;00D6 00F7;DIVISION SIGN;Sm;0;ON;;;;;N;;;;; 00F8;LATIN SMALL LETTER O WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER O SLASH;;00D8;;00D8 00F9;LATIN SMALL LETTER U WITH GRAVE;Ll;0;L;0075 0300;;;;N;LATIN SMALL LETTER U GRAVE;;00D9;;00D9 00FA;LATIN SMALL LETTER U WITH ACUTE;Ll;0;L;0075 0301;;;;N;LATIN SMALL LETTER U ACUTE;;00DA;;00DA 00FB;LATIN SMALL LETTER U WITH CIRCUMFLEX;Ll;0;L;0075 0302;;;;N;LATIN SMALL LETTER U CIRCUMFLEX;;00DB;;00DB 00FC;LATIN SMALL LETTER U WITH DIAERESIS;Ll;0;L;0075 0308;;;;N;LATIN SMALL LETTER U DIAERESIS;;00DC;;00DC 00FD;LATIN SMALL LETTER Y WITH ACUTE;Ll;0;L;0079 0301;;;;N;LATIN SMALL LETTER Y ACUTE;;00DD;;00DD 00FE;LATIN SMALL LETTER THORN;Ll;0;L;;;;;N;;Icelandic;00DE;;00DE 00FF;LATIN SMALL LETTER Y WITH DIAERESIS;Ll;0;L;0079 0308;;;;N;LATIN SMALL LETTER Y DIAERESIS;;0178;;0178 0100;LATIN CAPITAL LETTER A WITH MACRON;Lu;0;L;0041 0304;;;;N;LATIN CAPITAL LETTER A MACRON;;;0101; 0101;LATIN SMALL LETTER A WITH MACRON;Ll;0;L;0061 0304;;;;N;LATIN SMALL LETTER A MACRON;;0100;;0100 0102;LATIN CAPITAL LETTER A WITH BREVE;Lu;0;L;0041 0306;;;;N;LATIN CAPITAL LETTER A BREVE;;;0103; 0103;LATIN SMALL LETTER A WITH BREVE;Ll;0;L;0061 0306;;;;N;LATIN SMALL LETTER A BREVE;;0102;;0102 0104;LATIN CAPITAL LETTER A WITH OGONEK;Lu;0;L;0041 0328;;;;N;LATIN CAPITAL LETTER A OGONEK;;;0105; 0105;LATIN SMALL LETTER A WITH OGONEK;Ll;0;L;0061 0328;;;;N;LATIN SMALL LETTER A OGONEK;;0104;;0104 0106;LATIN CAPITAL LETTER C WITH ACUTE;Lu;0;L;0043 0301;;;;N;LATIN CAPITAL LETTER C ACUTE;;;0107; 0107;LATIN SMALL LETTER C WITH ACUTE;Ll;0;L;0063 0301;;;;N;LATIN SMALL LETTER C ACUTE;;0106;;0106 0108;LATIN CAPITAL LETTER C WITH CIRCUMFLEX;Lu;0;L;0043 0302;;;;N;LATIN CAPITAL LETTER C CIRCUMFLEX;;;0109; 0109;LATIN SMALL LETTER C WITH CIRCUMFLEX;Ll;0;L;0063 0302;;;;N;LATIN SMALL LETTER C CIRCUMFLEX;;0108;;0108 010A;LATIN CAPITAL LETTER C WITH DOT ABOVE;Lu;0;L;0043 0307;;;;N;LATIN CAPITAL LETTER C DOT;;;010B; 010B;LATIN SMALL LETTER C WITH DOT ABOVE;Ll;0;L;0063 0307;;;;N;LATIN SMALL LETTER C DOT;;010A;;010A 010C;LATIN CAPITAL LETTER C WITH CARON;Lu;0;L;0043 030C;;;;N;LATIN CAPITAL LETTER C HACEK;;;010D; 010D;LATIN SMALL LETTER C WITH CARON;Ll;0;L;0063 030C;;;;N;LATIN SMALL LETTER C HACEK;;010C;;010C 010E;LATIN CAPITAL LETTER D WITH CARON;Lu;0;L;0044 030C;;;;N;LATIN CAPITAL LETTER D HACEK;;;010F; 010F;LATIN SMALL LETTER D WITH CARON;Ll;0;L;0064 030C;;;;N;LATIN SMALL LETTER D HACEK;;010E;;010E 0110;LATIN CAPITAL LETTER D WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D BAR;;;0111; 0111;LATIN SMALL LETTER D WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER D BAR;;0110;;0110 0112;LATIN CAPITAL LETTER E WITH MACRON;Lu;0;L;0045 0304;;;;N;LATIN CAPITAL LETTER E MACRON;;;0113; 0113;LATIN SMALL LETTER E WITH MACRON;Ll;0;L;0065 0304;;;;N;LATIN SMALL LETTER E MACRON;;0112;;0112 0114;LATIN CAPITAL LETTER E WITH BREVE;Lu;0;L;0045 0306;;;;N;LATIN CAPITAL LETTER E BREVE;;;0115; 0115;LATIN SMALL LETTER E WITH BREVE;Ll;0;L;0065 0306;;;;N;LATIN SMALL LETTER E BREVE;;0114;;0114 0116;LATIN CAPITAL LETTER E WITH DOT ABOVE;Lu;0;L;0045 0307;;;;N;LATIN CAPITAL LETTER E DOT;;;0117; 0117;LATIN SMALL LETTER E WITH DOT ABOVE;Ll;0;L;0065 0307;;;;N;LATIN SMALL LETTER E DOT;;0116;;0116 0118;LATIN CAPITAL LETTER E WITH OGONEK;Lu;0;L;0045 0328;;;;N;LATIN CAPITAL LETTER E OGONEK;;;0119; 0119;LATIN SMALL LETTER E WITH OGONEK;Ll;0;L;0065 0328;;;;N;LATIN SMALL LETTER E OGONEK;;0118;;0118 011A;LATIN CAPITAL LETTER E WITH CARON;Lu;0;L;0045 030C;;;;N;LATIN CAPITAL LETTER E HACEK;;;011B; 011B;LATIN SMALL LETTER E WITH CARON;Ll;0;L;0065 030C;;;;N;LATIN SMALL LETTER E HACEK;;011A;;011A 011C;LATIN CAPITAL LETTER G WITH CIRCUMFLEX;Lu;0;L;0047 0302;;;;N;LATIN CAPITAL LETTER G CIRCUMFLEX;;;011D; 011D;LATIN SMALL LETTER G WITH CIRCUMFLEX;Ll;0;L;0067 0302;;;;N;LATIN SMALL LETTER G CIRCUMFLEX;;011C;;011C 011E;LATIN CAPITAL LETTER G WITH BREVE;Lu;0;L;0047 0306;;;;N;LATIN CAPITAL LETTER G BREVE;;;011F; 011F;LATIN SMALL LETTER G WITH BREVE;Ll;0;L;0067 0306;;;;N;LATIN SMALL LETTER G BREVE;;011E;;011E 0120;LATIN CAPITAL LETTER G WITH DOT ABOVE;Lu;0;L;0047 0307;;;;N;LATIN CAPITAL LETTER G DOT;;;0121; 0121;LATIN SMALL LETTER G WITH DOT ABOVE;Ll;0;L;0067 0307;;;;N;LATIN SMALL LETTER G DOT;;0120;;0120 0122;LATIN CAPITAL LETTER G WITH CEDILLA;Lu;0;L;0047 0327;;;;N;LATIN CAPITAL LETTER G CEDILLA;;;0123; 0123;LATIN SMALL LETTER G WITH CEDILLA;Ll;0;L;0067 0327;;;;N;LATIN SMALL LETTER G CEDILLA;;0122;;0122 0124;LATIN CAPITAL LETTER H WITH CIRCUMFLEX;Lu;0;L;0048 0302;;;;N;LATIN CAPITAL LETTER H CIRCUMFLEX;;;0125; 0125;LATIN SMALL LETTER H WITH CIRCUMFLEX;Ll;0;L;0068 0302;;;;N;LATIN SMALL LETTER H CIRCUMFLEX;;0124;;0124 0126;LATIN CAPITAL LETTER H WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER H BAR;;;0127; 0127;LATIN SMALL LETTER H WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER H BAR;;0126;;0126 0128;LATIN CAPITAL LETTER I WITH TILDE;Lu;0;L;0049 0303;;;;N;LATIN CAPITAL LETTER I TILDE;;;0129; 0129;LATIN SMALL LETTER I WITH TILDE;Ll;0;L;0069 0303;;;;N;LATIN SMALL LETTER I TILDE;;0128;;0128 012A;LATIN CAPITAL LETTER I WITH MACRON;Lu;0;L;0049 0304;;;;N;LATIN CAPITAL LETTER I MACRON;;;012B; 012B;LATIN SMALL LETTER I WITH MACRON;Ll;0;L;0069 0304;;;;N;LATIN SMALL LETTER I MACRON;;012A;;012A 012C;LATIN CAPITAL LETTER I WITH BREVE;Lu;0;L;0049 0306;;;;N;LATIN CAPITAL LETTER I BREVE;;;012D; 012D;LATIN SMALL LETTER I WITH BREVE;Ll;0;L;0069 0306;;;;N;LATIN SMALL LETTER I BREVE;;012C;;012C 012E;LATIN CAPITAL LETTER I WITH OGONEK;Lu;0;L;0049 0328;;;;N;LATIN CAPITAL LETTER I OGONEK;;;012F; 012F;LATIN SMALL LETTER I WITH OGONEK;Ll;0;L;0069 0328;;;;N;LATIN SMALL LETTER I OGONEK;;012E;;012E 0130;LATIN CAPITAL LETTER I WITH DOT ABOVE;Lu;0;L;0049 0307;;;;N;LATIN CAPITAL LETTER I DOT;;;0069; 0131;LATIN SMALL LETTER DOTLESS I;Ll;0;L;;;;;N;;;0049;;0049 0132;LATIN CAPITAL LIGATURE IJ;Lu;0;L; 0049 004A;;;;N;LATIN CAPITAL LETTER I J;;;0133; 0133;LATIN SMALL LIGATURE IJ;Ll;0;L; 0069 006A;;;;N;LATIN SMALL LETTER I J;;0132;;0132 0134;LATIN CAPITAL LETTER J WITH CIRCUMFLEX;Lu;0;L;004A 0302;;;;N;LATIN CAPITAL LETTER J CIRCUMFLEX;;;0135; 0135;LATIN SMALL LETTER J WITH CIRCUMFLEX;Ll;0;L;006A 0302;;;;N;LATIN SMALL LETTER J CIRCUMFLEX;;0134;;0134 0136;LATIN CAPITAL LETTER K WITH CEDILLA;Lu;0;L;004B 0327;;;;N;LATIN CAPITAL LETTER K CEDILLA;;;0137; 0137;LATIN SMALL LETTER K WITH CEDILLA;Ll;0;L;006B 0327;;;;N;LATIN SMALL LETTER K CEDILLA;;0136;;0136 0138;LATIN SMALL LETTER KRA;Ll;0;L;;;;;N;;Greenlandic;;; 0139;LATIN CAPITAL LETTER L WITH ACUTE;Lu;0;L;004C 0301;;;;N;LATIN CAPITAL LETTER L ACUTE;;;013A; 013A;LATIN SMALL LETTER L WITH ACUTE;Ll;0;L;006C 0301;;;;N;LATIN SMALL LETTER L ACUTE;;0139;;0139 013B;LATIN CAPITAL LETTER L WITH CEDILLA;Lu;0;L;004C 0327;;;;N;LATIN CAPITAL LETTER L CEDILLA;;;013C; 013C;LATIN SMALL LETTER L WITH CEDILLA;Ll;0;L;006C 0327;;;;N;LATIN SMALL LETTER L CEDILLA;;013B;;013B 013D;LATIN CAPITAL LETTER L WITH CARON;Lu;0;L;004C 030C;;;;N;LATIN CAPITAL LETTER L HACEK;;;013E; 013E;LATIN SMALL LETTER L WITH CARON;Ll;0;L;006C 030C;;;;N;LATIN SMALL LETTER L HACEK;;013D;;013D 013F;LATIN CAPITAL LETTER L WITH MIDDLE DOT;Lu;0;L; 004C 00B7;;;;N;;;;0140; 0140;LATIN SMALL LETTER L WITH MIDDLE DOT;Ll;0;L; 006C 00B7;;;;N;;;013F;;013F 0141;LATIN CAPITAL LETTER L WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER L SLASH;;;0142; 0142;LATIN SMALL LETTER L WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER L SLASH;;0141;;0141 0143;LATIN CAPITAL LETTER N WITH ACUTE;Lu;0;L;004E 0301;;;;N;LATIN CAPITAL LETTER N ACUTE;;;0144; 0144;LATIN SMALL LETTER N WITH ACUTE;Ll;0;L;006E 0301;;;;N;LATIN SMALL LETTER N ACUTE;;0143;;0143 0145;LATIN CAPITAL LETTER N WITH CEDILLA;Lu;0;L;004E 0327;;;;N;LATIN CAPITAL LETTER N CEDILLA;;;0146; 0146;LATIN SMALL LETTER N WITH CEDILLA;Ll;0;L;006E 0327;;;;N;LATIN SMALL LETTER N CEDILLA;;0145;;0145 0147;LATIN CAPITAL LETTER N WITH CARON;Lu;0;L;004E 030C;;;;N;LATIN CAPITAL LETTER N HACEK;;;0148; 0148;LATIN SMALL LETTER N WITH CARON;Ll;0;L;006E 030C;;;;N;LATIN SMALL LETTER N HACEK;;0147;;0147 0149;LATIN SMALL LETTER N PRECEDED BY APOSTROPHE;Ll;0;L; 02BC 006E;;;;N;LATIN SMALL LETTER APOSTROPHE N;;;; 014A;LATIN CAPITAL LETTER ENG;Lu;0;L;;;;;N;;Sami;;014B; 014B;LATIN SMALL LETTER ENG;Ll;0;L;;;;;N;;Sami;014A;;014A 014C;LATIN CAPITAL LETTER O WITH MACRON;Lu;0;L;004F 0304;;;;N;LATIN CAPITAL LETTER O MACRON;;;014D; 014D;LATIN SMALL LETTER O WITH MACRON;Ll;0;L;006F 0304;;;;N;LATIN SMALL LETTER O MACRON;;014C;;014C 014E;LATIN CAPITAL LETTER O WITH BREVE;Lu;0;L;004F 0306;;;;N;LATIN CAPITAL LETTER O BREVE;;;014F; 014F;LATIN SMALL LETTER O WITH BREVE;Ll;0;L;006F 0306;;;;N;LATIN SMALL LETTER O BREVE;;014E;;014E 0150;LATIN CAPITAL LETTER O WITH DOUBLE ACUTE;Lu;0;L;004F 030B;;;;N;LATIN CAPITAL LETTER O DOUBLE ACUTE;;;0151; 0151;LATIN SMALL LETTER O WITH DOUBLE ACUTE;Ll;0;L;006F 030B;;;;N;LATIN SMALL LETTER O DOUBLE ACUTE;;0150;;0150 0152;LATIN CAPITAL LIGATURE OE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O E;;;0153; 0153;LATIN SMALL LIGATURE OE;Ll;0;L;;;;;N;LATIN SMALL LETTER O E;;0152;;0152 0154;LATIN CAPITAL LETTER R WITH ACUTE;Lu;0;L;0052 0301;;;;N;LATIN CAPITAL LETTER R ACUTE;;;0155; 0155;LATIN SMALL LETTER R WITH ACUTE;Ll;0;L;0072 0301;;;;N;LATIN SMALL LETTER R ACUTE;;0154;;0154 0156;LATIN CAPITAL LETTER R WITH CEDILLA;Lu;0;L;0052 0327;;;;N;LATIN CAPITAL LETTER R CEDILLA;;;0157; 0157;LATIN SMALL LETTER R WITH CEDILLA;Ll;0;L;0072 0327;;;;N;LATIN SMALL LETTER R CEDILLA;;0156;;0156 0158;LATIN CAPITAL LETTER R WITH CARON;Lu;0;L;0052 030C;;;;N;LATIN CAPITAL LETTER R HACEK;;;0159; 0159;LATIN SMALL LETTER R WITH CARON;Ll;0;L;0072 030C;;;;N;LATIN SMALL LETTER R HACEK;;0158;;0158 015A;LATIN CAPITAL LETTER S WITH ACUTE;Lu;0;L;0053 0301;;;;N;LATIN CAPITAL LETTER S ACUTE;;;015B; 015B;LATIN SMALL LETTER S WITH ACUTE;Ll;0;L;0073 0301;;;;N;LATIN SMALL LETTER S ACUTE;;015A;;015A 015C;LATIN CAPITAL LETTER S WITH CIRCUMFLEX;Lu;0;L;0053 0302;;;;N;LATIN CAPITAL LETTER S CIRCUMFLEX;;;015D; 015D;LATIN SMALL LETTER S WITH CIRCUMFLEX;Ll;0;L;0073 0302;;;;N;LATIN SMALL LETTER S CIRCUMFLEX;;015C;;015C 015E;LATIN CAPITAL LETTER S WITH CEDILLA;Lu;0;L;0053 0327;;;;N;LATIN CAPITAL LETTER S CEDILLA;*;;015F; 015F;LATIN SMALL LETTER S WITH CEDILLA;Ll;0;L;0073 0327;;;;N;LATIN SMALL LETTER S CEDILLA;*;015E;;015E 0160;LATIN CAPITAL LETTER S WITH CARON;Lu;0;L;0053 030C;;;;N;LATIN CAPITAL LETTER S HACEK;;;0161; 0161;LATIN SMALL LETTER S WITH CARON;Ll;0;L;0073 030C;;;;N;LATIN SMALL LETTER S HACEK;;0160;;0160 0162;LATIN CAPITAL LETTER T WITH CEDILLA;Lu;0;L;0054 0327;;;;N;LATIN CAPITAL LETTER T CEDILLA;*;;0163; 0163;LATIN SMALL LETTER T WITH CEDILLA;Ll;0;L;0074 0327;;;;N;LATIN SMALL LETTER T CEDILLA;*;0162;;0162 0164;LATIN CAPITAL LETTER T WITH CARON;Lu;0;L;0054 030C;;;;N;LATIN CAPITAL LETTER T HACEK;;;0165; 0165;LATIN SMALL LETTER T WITH CARON;Ll;0;L;0074 030C;;;;N;LATIN SMALL LETTER T HACEK;;0164;;0164 0166;LATIN CAPITAL LETTER T WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T BAR;;;0167; 0167;LATIN SMALL LETTER T WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER T BAR;;0166;;0166 0168;LATIN CAPITAL LETTER U WITH TILDE;Lu;0;L;0055 0303;;;;N;LATIN CAPITAL LETTER U TILDE;;;0169; 0169;LATIN SMALL LETTER U WITH TILDE;Ll;0;L;0075 0303;;;;N;LATIN SMALL LETTER U TILDE;;0168;;0168 016A;LATIN CAPITAL LETTER U WITH MACRON;Lu;0;L;0055 0304;;;;N;LATIN CAPITAL LETTER U MACRON;;;016B; 016B;LATIN SMALL LETTER U WITH MACRON;Ll;0;L;0075 0304;;;;N;LATIN SMALL LETTER U MACRON;;016A;;016A 016C;LATIN CAPITAL LETTER U WITH BREVE;Lu;0;L;0055 0306;;;;N;LATIN CAPITAL LETTER U BREVE;;;016D; 016D;LATIN SMALL LETTER U WITH BREVE;Ll;0;L;0075 0306;;;;N;LATIN SMALL LETTER U BREVE;;016C;;016C 016E;LATIN CAPITAL LETTER U WITH RING ABOVE;Lu;0;L;0055 030A;;;;N;LATIN CAPITAL LETTER U RING;;;016F; 016F;LATIN SMALL LETTER U WITH RING ABOVE;Ll;0;L;0075 030A;;;;N;LATIN SMALL LETTER U RING;;016E;;016E 0170;LATIN CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0055 030B;;;;N;LATIN CAPITAL LETTER U DOUBLE ACUTE;;;0171; 0171;LATIN SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0075 030B;;;;N;LATIN SMALL LETTER U DOUBLE ACUTE;;0170;;0170 0172;LATIN CAPITAL LETTER U WITH OGONEK;Lu;0;L;0055 0328;;;;N;LATIN CAPITAL LETTER U OGONEK;;;0173; 0173;LATIN SMALL LETTER U WITH OGONEK;Ll;0;L;0075 0328;;;;N;LATIN SMALL LETTER U OGONEK;;0172;;0172 0174;LATIN CAPITAL LETTER W WITH CIRCUMFLEX;Lu;0;L;0057 0302;;;;N;LATIN CAPITAL LETTER W CIRCUMFLEX;;;0175; 0175;LATIN SMALL LETTER W WITH CIRCUMFLEX;Ll;0;L;0077 0302;;;;N;LATIN SMALL LETTER W CIRCUMFLEX;;0174;;0174 0176;LATIN CAPITAL LETTER Y WITH CIRCUMFLEX;Lu;0;L;0059 0302;;;;N;LATIN CAPITAL LETTER Y CIRCUMFLEX;;;0177; 0177;LATIN SMALL LETTER Y WITH CIRCUMFLEX;Ll;0;L;0079 0302;;;;N;LATIN SMALL LETTER Y CIRCUMFLEX;;0176;;0176 0178;LATIN CAPITAL LETTER Y WITH DIAERESIS;Lu;0;L;0059 0308;;;;N;LATIN CAPITAL LETTER Y DIAERESIS;;;00FF; 0179;LATIN CAPITAL LETTER Z WITH ACUTE;Lu;0;L;005A 0301;;;;N;LATIN CAPITAL LETTER Z ACUTE;;;017A; 017A;LATIN SMALL LETTER Z WITH ACUTE;Ll;0;L;007A 0301;;;;N;LATIN SMALL LETTER Z ACUTE;;0179;;0179 017B;LATIN CAPITAL LETTER Z WITH DOT ABOVE;Lu;0;L;005A 0307;;;;N;LATIN CAPITAL LETTER Z DOT;;;017C; 017C;LATIN SMALL LETTER Z WITH DOT ABOVE;Ll;0;L;007A 0307;;;;N;LATIN SMALL LETTER Z DOT;;017B;;017B 017D;LATIN CAPITAL LETTER Z WITH CARON;Lu;0;L;005A 030C;;;;N;LATIN CAPITAL LETTER Z HACEK;;;017E; 017E;LATIN SMALL LETTER Z WITH CARON;Ll;0;L;007A 030C;;;;N;LATIN SMALL LETTER Z HACEK;;017D;;017D 017F;LATIN SMALL LETTER LONG S;Ll;0;L; 0073;;;;N;;;0053;;0053 0180;LATIN SMALL LETTER B WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER B BAR;;;; 0181;LATIN CAPITAL LETTER B WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B HOOK;;;0253; 0182;LATIN CAPITAL LETTER B WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B TOPBAR;;;0183; 0183;LATIN SMALL LETTER B WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER B TOPBAR;;0182;;0182 0184;LATIN CAPITAL LETTER TONE SIX;Lu;0;L;;;;;N;;;;0185; 0185;LATIN SMALL LETTER TONE SIX;Ll;0;L;;;;;N;;;0184;;0184 0186;LATIN CAPITAL LETTER OPEN O;Lu;0;L;;;;;N;;;;0254; 0187;LATIN CAPITAL LETTER C WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER C HOOK;;;0188; 0188;LATIN SMALL LETTER C WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER C HOOK;;0187;;0187 0189;LATIN CAPITAL LETTER AFRICAN D;Lu;0;L;;;;;N;;*;;0256; 018A;LATIN CAPITAL LETTER D WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D HOOK;;;0257; 018B;LATIN CAPITAL LETTER D WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D TOPBAR;;;018C; 018C;LATIN SMALL LETTER D WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER D TOPBAR;;018B;;018B 018D;LATIN SMALL LETTER TURNED DELTA;Ll;0;L;;;;;N;;;;; 018E;LATIN CAPITAL LETTER REVERSED E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER TURNED E;;;01DD; 018F;LATIN CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;0259; 0190;LATIN CAPITAL LETTER OPEN E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER EPSILON;;;025B; 0191;LATIN CAPITAL LETTER F WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER F HOOK;;;0192; 0192;LATIN SMALL LETTER F WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT F;;0191;;0191 0193;LATIN CAPITAL LETTER G WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G HOOK;;;0260; 0194;LATIN CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;0263; 0195;LATIN SMALL LETTER HV;Ll;0;L;;;;;N;LATIN SMALL LETTER H V;hwair;01F6;;01F6 0196;LATIN CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;0269; 0197;LATIN CAPITAL LETTER I WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED I;;;0268; 0198;LATIN CAPITAL LETTER K WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER K HOOK;;;0199; 0199;LATIN SMALL LETTER K WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER K HOOK;;0198;;0198 019A;LATIN SMALL LETTER L WITH BAR;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED L;;;; 019B;LATIN SMALL LETTER LAMBDA WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED LAMBDA;;;; 019C;LATIN CAPITAL LETTER TURNED M;Lu;0;L;;;;;N;;;;026F; 019D;LATIN CAPITAL LETTER N WITH LEFT HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER N HOOK;;;0272; 019E;LATIN SMALL LETTER N WITH LONG RIGHT LEG;Ll;0;L;;;;;N;;;0220;;0220 019F;LATIN CAPITAL LETTER O WITH MIDDLE TILDE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED O;*;;0275; 01A0;LATIN CAPITAL LETTER O WITH HORN;Lu;0;L;004F 031B;;;;N;LATIN CAPITAL LETTER O HORN;;;01A1; 01A1;LATIN SMALL LETTER O WITH HORN;Ll;0;L;006F 031B;;;;N;LATIN SMALL LETTER O HORN;;01A0;;01A0 01A2;LATIN CAPITAL LETTER OI;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O I;gha;;01A3; 01A3;LATIN SMALL LETTER OI;Ll;0;L;;;;;N;LATIN SMALL LETTER O I;gha;01A2;;01A2 01A4;LATIN CAPITAL LETTER P WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER P HOOK;;;01A5; 01A5;LATIN SMALL LETTER P WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER P HOOK;;01A4;;01A4 01A6;LATIN LETTER YR;Lu;0;L;;;;;N;LATIN LETTER Y R;*;;0280; 01A7;LATIN CAPITAL LETTER TONE TWO;Lu;0;L;;;;;N;;;;01A8; 01A8;LATIN SMALL LETTER TONE TWO;Ll;0;L;;;;;N;;;01A7;;01A7 01A9;LATIN CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;0283; 01AA;LATIN LETTER REVERSED ESH LOOP;Ll;0;L;;;;;N;;;;; 01AB;LATIN SMALL LETTER T WITH PALATAL HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T PALATAL HOOK;;;; 01AC;LATIN CAPITAL LETTER T WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T HOOK;;;01AD; 01AD;LATIN SMALL LETTER T WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T HOOK;;01AC;;01AC 01AE;LATIN CAPITAL LETTER T WITH RETROFLEX HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T RETROFLEX HOOK;;;0288; 01AF;LATIN CAPITAL LETTER U WITH HORN;Lu;0;L;0055 031B;;;;N;LATIN CAPITAL LETTER U HORN;;;01B0; 01B0;LATIN SMALL LETTER U WITH HORN;Ll;0;L;0075 031B;;;;N;LATIN SMALL LETTER U HORN;;01AF;;01AF 01B1;LATIN CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;028A; 01B2;LATIN CAPITAL LETTER V WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER SCRIPT V;;;028B; 01B3;LATIN CAPITAL LETTER Y WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Y HOOK;;;01B4; 01B4;LATIN SMALL LETTER Y WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Y HOOK;;01B3;;01B3 01B5;LATIN CAPITAL LETTER Z WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Z BAR;;;01B6; 01B6;LATIN SMALL LETTER Z WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER Z BAR;;01B5;;01B5 01B7;LATIN CAPITAL LETTER EZH;Lu;0;L;;;;;N;LATIN CAPITAL LETTER YOGH;;;0292; 01B8;LATIN CAPITAL LETTER EZH REVERSED;Lu;0;L;;;;;N;LATIN CAPITAL LETTER REVERSED YOGH;;;01B9; 01B9;LATIN SMALL LETTER EZH REVERSED;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED YOGH;;01B8;;01B8 01BA;LATIN SMALL LETTER EZH WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH WITH TAIL;;;; 01BB;LATIN LETTER TWO WITH STROKE;Lo;0;L;;;;;N;LATIN LETTER TWO BAR;;;; 01BC;LATIN CAPITAL LETTER TONE FIVE;Lu;0;L;;;;;N;;;;01BD; 01BD;LATIN SMALL LETTER TONE FIVE;Ll;0;L;;;;;N;;;01BC;;01BC 01BE;LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER INVERTED GLOTTAL STOP BAR;;;; 01BF;LATIN LETTER WYNN;Ll;0;L;;;;;N;;;01F7;;01F7 01C0;LATIN LETTER DENTAL CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE;;;; 01C1;LATIN LETTER LATERAL CLICK;Lo;0;L;;;;;N;LATIN LETTER DOUBLE PIPE;;;; 01C2;LATIN LETTER ALVEOLAR CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE DOUBLE BAR;;;; 01C3;LATIN LETTER RETROFLEX CLICK;Lo;0;L;;;;;N;LATIN LETTER EXCLAMATION MARK;;;; 01C4;LATIN CAPITAL LETTER DZ WITH CARON;Lu;0;L; 0044 017D;;;;N;LATIN CAPITAL LETTER D Z HACEK;;;01C6;01C5 01C5;LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON;Lt;0;L; 0044 017E;;;;N;LATIN LETTER CAPITAL D SMALL Z HACEK;;01C4;01C6; 01C6;LATIN SMALL LETTER DZ WITH CARON;Ll;0;L; 0064 017E;;;;N;LATIN SMALL LETTER D Z HACEK;;01C4;;01C5 01C7;LATIN CAPITAL LETTER LJ;Lu;0;L; 004C 004A;;;;N;LATIN CAPITAL LETTER L J;;;01C9;01C8 01C8;LATIN CAPITAL LETTER L WITH SMALL LETTER J;Lt;0;L; 004C 006A;;;;N;LATIN LETTER CAPITAL L SMALL J;;01C7;01C9; 01C9;LATIN SMALL LETTER LJ;Ll;0;L; 006C 006A;;;;N;LATIN SMALL LETTER L J;;01C7;;01C8 01CA;LATIN CAPITAL LETTER NJ;Lu;0;L; 004E 004A;;;;N;LATIN CAPITAL LETTER N J;;;01CC;01CB 01CB;LATIN CAPITAL LETTER N WITH SMALL LETTER J;Lt;0;L; 004E 006A;;;;N;LATIN LETTER CAPITAL N SMALL J;;01CA;01CC; 01CC;LATIN SMALL LETTER NJ;Ll;0;L; 006E 006A;;;;N;LATIN SMALL LETTER N J;;01CA;;01CB 01CD;LATIN CAPITAL LETTER A WITH CARON;Lu;0;L;0041 030C;;;;N;LATIN CAPITAL LETTER A HACEK;;;01CE; 01CE;LATIN SMALL LETTER A WITH CARON;Ll;0;L;0061 030C;;;;N;LATIN SMALL LETTER A HACEK;;01CD;;01CD 01CF;LATIN CAPITAL LETTER I WITH CARON;Lu;0;L;0049 030C;;;;N;LATIN CAPITAL LETTER I HACEK;;;01D0; 01D0;LATIN SMALL LETTER I WITH CARON;Ll;0;L;0069 030C;;;;N;LATIN SMALL LETTER I HACEK;;01CF;;01CF 01D1;LATIN CAPITAL LETTER O WITH CARON;Lu;0;L;004F 030C;;;;N;LATIN CAPITAL LETTER O HACEK;;;01D2; 01D2;LATIN SMALL LETTER O WITH CARON;Ll;0;L;006F 030C;;;;N;LATIN SMALL LETTER O HACEK;;01D1;;01D1 01D3;LATIN CAPITAL LETTER U WITH CARON;Lu;0;L;0055 030C;;;;N;LATIN CAPITAL LETTER U HACEK;;;01D4; 01D4;LATIN SMALL LETTER U WITH CARON;Ll;0;L;0075 030C;;;;N;LATIN SMALL LETTER U HACEK;;01D3;;01D3 01D5;LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON;Lu;0;L;00DC 0304;;;;N;LATIN CAPITAL LETTER U DIAERESIS MACRON;;;01D6; 01D6;LATIN SMALL LETTER U WITH DIAERESIS AND MACRON;Ll;0;L;00FC 0304;;;;N;LATIN SMALL LETTER U DIAERESIS MACRON;;01D5;;01D5 01D7;LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE;Lu;0;L;00DC 0301;;;;N;LATIN CAPITAL LETTER U DIAERESIS ACUTE;;;01D8; 01D8;LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE;Ll;0;L;00FC 0301;;;;N;LATIN SMALL LETTER U DIAERESIS ACUTE;;01D7;;01D7 01D9;LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON;Lu;0;L;00DC 030C;;;;N;LATIN CAPITAL LETTER U DIAERESIS HACEK;;;01DA; 01DA;LATIN SMALL LETTER U WITH DIAERESIS AND CARON;Ll;0;L;00FC 030C;;;;N;LATIN SMALL LETTER U DIAERESIS HACEK;;01D9;;01D9 01DB;LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE;Lu;0;L;00DC 0300;;;;N;LATIN CAPITAL LETTER U DIAERESIS GRAVE;;;01DC; 01DC;LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE;Ll;0;L;00FC 0300;;;;N;LATIN SMALL LETTER U DIAERESIS GRAVE;;01DB;;01DB 01DD;LATIN SMALL LETTER TURNED E;Ll;0;L;;;;;N;;;018E;;018E 01DE;LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON;Lu;0;L;00C4 0304;;;;N;LATIN CAPITAL LETTER A DIAERESIS MACRON;;;01DF; 01DF;LATIN SMALL LETTER A WITH DIAERESIS AND MACRON;Ll;0;L;00E4 0304;;;;N;LATIN SMALL LETTER A DIAERESIS MACRON;;01DE;;01DE 01E0;LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON;Lu;0;L;0226 0304;;;;N;LATIN CAPITAL LETTER A DOT MACRON;;;01E1; 01E1;LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON;Ll;0;L;0227 0304;;;;N;LATIN SMALL LETTER A DOT MACRON;;01E0;;01E0 01E2;LATIN CAPITAL LETTER AE WITH MACRON;Lu;0;L;00C6 0304;;;;N;LATIN CAPITAL LETTER A E MACRON;ash *;;01E3; 01E3;LATIN SMALL LETTER AE WITH MACRON;Ll;0;L;00E6 0304;;;;N;LATIN SMALL LETTER A E MACRON;ash *;01E2;;01E2 01E4;LATIN CAPITAL LETTER G WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G BAR;;;01E5; 01E5;LATIN SMALL LETTER G WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER G BAR;;01E4;;01E4 01E6;LATIN CAPITAL LETTER G WITH CARON;Lu;0;L;0047 030C;;;;N;LATIN CAPITAL LETTER G HACEK;;;01E7; 01E7;LATIN SMALL LETTER G WITH CARON;Ll;0;L;0067 030C;;;;N;LATIN SMALL LETTER G HACEK;;01E6;;01E6 01E8;LATIN CAPITAL LETTER K WITH CARON;Lu;0;L;004B 030C;;;;N;LATIN CAPITAL LETTER K HACEK;;;01E9; 01E9;LATIN SMALL LETTER K WITH CARON;Ll;0;L;006B 030C;;;;N;LATIN SMALL LETTER K HACEK;;01E8;;01E8 01EA;LATIN CAPITAL LETTER O WITH OGONEK;Lu;0;L;004F 0328;;;;N;LATIN CAPITAL LETTER O OGONEK;;;01EB; 01EB;LATIN SMALL LETTER O WITH OGONEK;Ll;0;L;006F 0328;;;;N;LATIN SMALL LETTER O OGONEK;;01EA;;01EA 01EC;LATIN CAPITAL LETTER O WITH OGONEK AND MACRON;Lu;0;L;01EA 0304;;;;N;LATIN CAPITAL LETTER O OGONEK MACRON;;;01ED; 01ED;LATIN SMALL LETTER O WITH OGONEK AND MACRON;Ll;0;L;01EB 0304;;;;N;LATIN SMALL LETTER O OGONEK MACRON;;01EC;;01EC 01EE;LATIN CAPITAL LETTER EZH WITH CARON;Lu;0;L;01B7 030C;;;;N;LATIN CAPITAL LETTER YOGH HACEK;;;01EF; 01EF;LATIN SMALL LETTER EZH WITH CARON;Ll;0;L;0292 030C;;;;N;LATIN SMALL LETTER YOGH HACEK;;01EE;;01EE 01F0;LATIN SMALL LETTER J WITH CARON;Ll;0;L;006A 030C;;;;N;LATIN SMALL LETTER J HACEK;;;; 01F1;LATIN CAPITAL LETTER DZ;Lu;0;L; 0044 005A;;;;N;;;;01F3;01F2 01F2;LATIN CAPITAL LETTER D WITH SMALL LETTER Z;Lt;0;L; 0044 007A;;;;N;;;01F1;01F3; 01F3;LATIN SMALL LETTER DZ;Ll;0;L; 0064 007A;;;;N;;;01F1;;01F2 01F4;LATIN CAPITAL LETTER G WITH ACUTE;Lu;0;L;0047 0301;;;;N;;;;01F5; 01F5;LATIN SMALL LETTER G WITH ACUTE;Ll;0;L;0067 0301;;;;N;;;01F4;;01F4 01F6;LATIN CAPITAL LETTER HWAIR;Lu;0;L;;;;;N;;;;0195; 01F7;LATIN CAPITAL LETTER WYNN;Lu;0;L;;;;;N;;;;01BF; 01F8;LATIN CAPITAL LETTER N WITH GRAVE;Lu;0;L;004E 0300;;;;N;;;;01F9; 01F9;LATIN SMALL LETTER N WITH GRAVE;Ll;0;L;006E 0300;;;;N;;;01F8;;01F8 01FA;LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE;Lu;0;L;00C5 0301;;;;N;;;;01FB; 01FB;LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE;Ll;0;L;00E5 0301;;;;N;;;01FA;;01FA 01FC;LATIN CAPITAL LETTER AE WITH ACUTE;Lu;0;L;00C6 0301;;;;N;;ash *;;01FD; 01FD;LATIN SMALL LETTER AE WITH ACUTE;Ll;0;L;00E6 0301;;;;N;;ash *;01FC;;01FC 01FE;LATIN CAPITAL LETTER O WITH STROKE AND ACUTE;Lu;0;L;00D8 0301;;;;N;;;;01FF; 01FF;LATIN SMALL LETTER O WITH STROKE AND ACUTE;Ll;0;L;00F8 0301;;;;N;;;01FE;;01FE 0200;LATIN CAPITAL LETTER A WITH DOUBLE GRAVE;Lu;0;L;0041 030F;;;;N;;;;0201; 0201;LATIN SMALL LETTER A WITH DOUBLE GRAVE;Ll;0;L;0061 030F;;;;N;;;0200;;0200 0202;LATIN CAPITAL LETTER A WITH INVERTED BREVE;Lu;0;L;0041 0311;;;;N;;;;0203; 0203;LATIN SMALL LETTER A WITH INVERTED BREVE;Ll;0;L;0061 0311;;;;N;;;0202;;0202 0204;LATIN CAPITAL LETTER E WITH DOUBLE GRAVE;Lu;0;L;0045 030F;;;;N;;;;0205; 0205;LATIN SMALL LETTER E WITH DOUBLE GRAVE;Ll;0;L;0065 030F;;;;N;;;0204;;0204 0206;LATIN CAPITAL LETTER E WITH INVERTED BREVE;Lu;0;L;0045 0311;;;;N;;;;0207; 0207;LATIN SMALL LETTER E WITH INVERTED BREVE;Ll;0;L;0065 0311;;;;N;;;0206;;0206 0208;LATIN CAPITAL LETTER I WITH DOUBLE GRAVE;Lu;0;L;0049 030F;;;;N;;;;0209; 0209;LATIN SMALL LETTER I WITH DOUBLE GRAVE;Ll;0;L;0069 030F;;;;N;;;0208;;0208 020A;LATIN CAPITAL LETTER I WITH INVERTED BREVE;Lu;0;L;0049 0311;;;;N;;;;020B; 020B;LATIN SMALL LETTER I WITH INVERTED BREVE;Ll;0;L;0069 0311;;;;N;;;020A;;020A 020C;LATIN CAPITAL LETTER O WITH DOUBLE GRAVE;Lu;0;L;004F 030F;;;;N;;;;020D; 020D;LATIN SMALL LETTER O WITH DOUBLE GRAVE;Ll;0;L;006F 030F;;;;N;;;020C;;020C 020E;LATIN CAPITAL LETTER O WITH INVERTED BREVE;Lu;0;L;004F 0311;;;;N;;;;020F; 020F;LATIN SMALL LETTER O WITH INVERTED BREVE;Ll;0;L;006F 0311;;;;N;;;020E;;020E 0210;LATIN CAPITAL LETTER R WITH DOUBLE GRAVE;Lu;0;L;0052 030F;;;;N;;;;0211; 0211;LATIN SMALL LETTER R WITH DOUBLE GRAVE;Ll;0;L;0072 030F;;;;N;;;0210;;0210 0212;LATIN CAPITAL LETTER R WITH INVERTED BREVE;Lu;0;L;0052 0311;;;;N;;;;0213; 0213;LATIN SMALL LETTER R WITH INVERTED BREVE;Ll;0;L;0072 0311;;;;N;;;0212;;0212 0214;LATIN CAPITAL LETTER U WITH DOUBLE GRAVE;Lu;0;L;0055 030F;;;;N;;;;0215; 0215;LATIN SMALL LETTER U WITH DOUBLE GRAVE;Ll;0;L;0075 030F;;;;N;;;0214;;0214 0216;LATIN CAPITAL LETTER U WITH INVERTED BREVE;Lu;0;L;0055 0311;;;;N;;;;0217; 0217;LATIN SMALL LETTER U WITH INVERTED BREVE;Ll;0;L;0075 0311;;;;N;;;0216;;0216 0218;LATIN CAPITAL LETTER S WITH COMMA BELOW;Lu;0;L;0053 0326;;;;N;;*;;0219; 0219;LATIN SMALL LETTER S WITH COMMA BELOW;Ll;0;L;0073 0326;;;;N;;*;0218;;0218 021A;LATIN CAPITAL LETTER T WITH COMMA BELOW;Lu;0;L;0054 0326;;;;N;;*;;021B; 021B;LATIN SMALL LETTER T WITH COMMA BELOW;Ll;0;L;0074 0326;;;;N;;*;021A;;021A 021C;LATIN CAPITAL LETTER YOGH;Lu;0;L;;;;;N;;;;021D; 021D;LATIN SMALL LETTER YOGH;Ll;0;L;;;;;N;;;021C;;021C 021E;LATIN CAPITAL LETTER H WITH CARON;Lu;0;L;0048 030C;;;;N;;;;021F; 021F;LATIN SMALL LETTER H WITH CARON;Ll;0;L;0068 030C;;;;N;;;021E;;021E 0220;LATIN CAPITAL LETTER N WITH LONG RIGHT LEG;Lu;0;L;;;;;N;;;;019E; 0222;LATIN CAPITAL LETTER OU;Lu;0;L;;;;;N;;;;0223; 0223;LATIN SMALL LETTER OU;Ll;0;L;;;;;N;;;0222;;0222 0224;LATIN CAPITAL LETTER Z WITH HOOK;Lu;0;L;;;;;N;;;;0225; 0225;LATIN SMALL LETTER Z WITH HOOK;Ll;0;L;;;;;N;;;0224;;0224 0226;LATIN CAPITAL LETTER A WITH DOT ABOVE;Lu;0;L;0041 0307;;;;N;;;;0227; 0227;LATIN SMALL LETTER A WITH DOT ABOVE;Ll;0;L;0061 0307;;;;N;;;0226;;0226 0228;LATIN CAPITAL LETTER E WITH CEDILLA;Lu;0;L;0045 0327;;;;N;;;;0229; 0229;LATIN SMALL LETTER E WITH CEDILLA;Ll;0;L;0065 0327;;;;N;;;0228;;0228 022A;LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON;Lu;0;L;00D6 0304;;;;N;;;;022B; 022B;LATIN SMALL LETTER O WITH DIAERESIS AND MACRON;Ll;0;L;00F6 0304;;;;N;;;022A;;022A 022C;LATIN CAPITAL LETTER O WITH TILDE AND MACRON;Lu;0;L;00D5 0304;;;;N;;;;022D; 022D;LATIN SMALL LETTER O WITH TILDE AND MACRON;Ll;0;L;00F5 0304;;;;N;;;022C;;022C 022E;LATIN CAPITAL LETTER O WITH DOT ABOVE;Lu;0;L;004F 0307;;;;N;;;;022F; 022F;LATIN SMALL LETTER O WITH DOT ABOVE;Ll;0;L;006F 0307;;;;N;;;022E;;022E 0230;LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON;Lu;0;L;022E 0304;;;;N;;;;0231; 0231;LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON;Ll;0;L;022F 0304;;;;N;;;0230;;0230 0232;LATIN CAPITAL LETTER Y WITH MACRON;Lu;0;L;0059 0304;;;;N;;;;0233; 0233;LATIN SMALL LETTER Y WITH MACRON;Ll;0;L;0079 0304;;;;N;;;0232;;0232 0250;LATIN SMALL LETTER TURNED A;Ll;0;L;;;;;N;;;;; 0251;LATIN SMALL LETTER ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT A;;;; 0252;LATIN SMALL LETTER TURNED ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED SCRIPT A;;;; 0253;LATIN SMALL LETTER B WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER B HOOK;;0181;;0181 0254;LATIN SMALL LETTER OPEN O;Ll;0;L;;;;;N;;;0186;;0186 0255;LATIN SMALL LETTER C WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER C CURL;;;; 0256;LATIN SMALL LETTER D WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER D RETROFLEX HOOK;;0189;;0189 0257;LATIN SMALL LETTER D WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER D HOOK;;018A;;018A 0258;LATIN SMALL LETTER REVERSED E;Ll;0;L;;;;;N;;;;; 0259;LATIN SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;018F;;018F 025A;LATIN SMALL LETTER SCHWA WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCHWA HOOK;;;; 025B;LATIN SMALL LETTER OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER EPSILON;;0190;;0190 025C;LATIN SMALL LETTER REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON;;;; 025D;LATIN SMALL LETTER REVERSED OPEN E WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON HOOK;;;; 025E;LATIN SMALL LETTER CLOSED REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED REVERSED EPSILON;;;; 025F;LATIN SMALL LETTER DOTLESS J WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR;;;; 0260;LATIN SMALL LETTER G WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER G HOOK;;0193;;0193 0261;LATIN SMALL LETTER SCRIPT G;Ll;0;L;;;;;N;;;;; 0262;LATIN LETTER SMALL CAPITAL G;Ll;0;L;;;;;N;;;;; 0263;LATIN SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0194;;0194 0264;LATIN SMALL LETTER RAMS HORN;Ll;0;L;;;;;N;LATIN SMALL LETTER BABY GAMMA;;;; 0265;LATIN SMALL LETTER TURNED H;Ll;0;L;;;;;N;;;;; 0266;LATIN SMALL LETTER H WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER H HOOK;;;; 0267;LATIN SMALL LETTER HENG WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER HENG HOOK;;;; 0268;LATIN SMALL LETTER I WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED I;;0197;;0197 0269;LATIN SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0196;;0196 026A;LATIN LETTER SMALL CAPITAL I;Ll;0;L;;;;;N;;;;; 026B;LATIN SMALL LETTER L WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; 026C;LATIN SMALL LETTER L WITH BELT;Ll;0;L;;;;;N;LATIN SMALL LETTER L BELT;;;; 026D;LATIN SMALL LETTER L WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER L RETROFLEX HOOK;;;; 026E;LATIN SMALL LETTER LEZH;Ll;0;L;;;;;N;LATIN SMALL LETTER L YOGH;;;; 026F;LATIN SMALL LETTER TURNED M;Ll;0;L;;;;;N;;;019C;;019C 0270;LATIN SMALL LETTER TURNED M WITH LONG LEG;Ll;0;L;;;;;N;;;;; 0271;LATIN SMALL LETTER M WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER M HOOK;;;; 0272;LATIN SMALL LETTER N WITH LEFT HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N HOOK;;019D;;019D 0273;LATIN SMALL LETTER N WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N RETROFLEX HOOK;;;; 0274;LATIN LETTER SMALL CAPITAL N;Ll;0;L;;;;;N;;;;; 0275;LATIN SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;019F;;019F 0276;LATIN LETTER SMALL CAPITAL OE;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL O E;;;; 0277;LATIN SMALL LETTER CLOSED OMEGA;Ll;0;L;;;;;N;;;;; 0278;LATIN SMALL LETTER PHI;Ll;0;L;;;;;N;;;;; 0279;LATIN SMALL LETTER TURNED R;Ll;0;L;;;;;N;;;;; 027A;LATIN SMALL LETTER TURNED R WITH LONG LEG;Ll;0;L;;;;;N;;;;; 027B;LATIN SMALL LETTER TURNED R WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED R HOOK;;;; 027C;LATIN SMALL LETTER R WITH LONG LEG;Ll;0;L;;;;;N;;;;; 027D;LATIN SMALL LETTER R WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER R HOOK;;;; 027E;LATIN SMALL LETTER R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER FISHHOOK R;;;; 027F;LATIN SMALL LETTER REVERSED R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED FISHHOOK R;;;; 0280;LATIN LETTER SMALL CAPITAL R;Ll;0;L;;;;;N;;*;01A6;;01A6 0281;LATIN LETTER SMALL CAPITAL INVERTED R;Ll;0;L;;;;;N;;;;; 0282;LATIN SMALL LETTER S WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER S HOOK;;;; 0283;LATIN SMALL LETTER ESH;Ll;0;L;;;;;N;;;01A9;;01A9 0284;LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR HOOK;;;; 0285;LATIN SMALL LETTER SQUAT REVERSED ESH;Ll;0;L;;;;;N;;;;; 0286;LATIN SMALL LETTER ESH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER ESH CURL;;;; 0287;LATIN SMALL LETTER TURNED T;Ll;0;L;;;;;N;;;;; 0288;LATIN SMALL LETTER T WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T RETROFLEX HOOK;;01AE;;01AE 0289;LATIN SMALL LETTER U BAR;Ll;0;L;;;;;N;;;;; 028A;LATIN SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;01B1;;01B1 028B;LATIN SMALL LETTER V WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT V;;01B2;;01B2 028C;LATIN SMALL LETTER TURNED V;Ll;0;L;;;;;N;;;;; 028D;LATIN SMALL LETTER TURNED W;Ll;0;L;;;;;N;;;;; 028E;LATIN SMALL LETTER TURNED Y;Ll;0;L;;;;;N;;;;; 028F;LATIN LETTER SMALL CAPITAL Y;Ll;0;L;;;;;N;;;;; 0290;LATIN SMALL LETTER Z WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Z RETROFLEX HOOK;;;; 0291;LATIN SMALL LETTER Z WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER Z CURL;;;; 0292;LATIN SMALL LETTER EZH;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH;;01B7;;01B7 0293;LATIN SMALL LETTER EZH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH CURL;;;; 0294;LATIN LETTER GLOTTAL STOP;Ll;0;L;;;;;N;;;;; 0295;LATIN LETTER PHARYNGEAL VOICED FRICATIVE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP;;;; 0296;LATIN LETTER INVERTED GLOTTAL STOP;Ll;0;L;;;;;N;;;;; 0297;LATIN LETTER STRETCHED C;Ll;0;L;;;;;N;;;;; 0298;LATIN LETTER BILABIAL CLICK;Ll;0;L;;;;;N;LATIN LETTER BULLSEYE;;;; 0299;LATIN LETTER SMALL CAPITAL B;Ll;0;L;;;;;N;;;;; 029A;LATIN SMALL LETTER CLOSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED EPSILON;;;; 029B;LATIN LETTER SMALL CAPITAL G WITH HOOK;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL G HOOK;;;; 029C;LATIN LETTER SMALL CAPITAL H;Ll;0;L;;;;;N;;;;; 029D;LATIN SMALL LETTER J WITH CROSSED-TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER CROSSED-TAIL J;;;; 029E;LATIN SMALL LETTER TURNED K;Ll;0;L;;;;;N;;;;; 029F;LATIN LETTER SMALL CAPITAL L;Ll;0;L;;;;;N;;;;; 02A0;LATIN SMALL LETTER Q WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Q HOOK;;;; 02A1;LATIN LETTER GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER GLOTTAL STOP BAR;;;; 02A2;LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP BAR;;;; 02A3;LATIN SMALL LETTER DZ DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z;;;; 02A4;LATIN SMALL LETTER DEZH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D YOGH;;;; 02A5;LATIN SMALL LETTER DZ DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z CURL;;;; 02A6;LATIN SMALL LETTER TS DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T S;;;; 02A7;LATIN SMALL LETTER TESH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T ESH;;;; 02A8;LATIN SMALL LETTER TC DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER T C CURL;;;; 02A9;LATIN SMALL LETTER FENG DIGRAPH;Ll;0;L;;;;;N;;;;; 02AA;LATIN SMALL LETTER LS DIGRAPH;Ll;0;L;;;;;N;;;;; 02AB;LATIN SMALL LETTER LZ DIGRAPH;Ll;0;L;;;;;N;;;;; 02AC;LATIN LETTER BILABIAL PERCUSSIVE;Ll;0;L;;;;;N;;;;; 02AD;LATIN LETTER BIDENTAL PERCUSSIVE;Ll;0;L;;;;;N;;;;; 02B0;MODIFIER LETTER SMALL H;Lm;0;L; 0068;;;;N;;;;; 02B1;MODIFIER LETTER SMALL H WITH HOOK;Lm;0;L; 0266;;;;N;MODIFIER LETTER SMALL H HOOK;;;; 02B2;MODIFIER LETTER SMALL J;Lm;0;L; 006A;;;;N;;;;; 02B3;MODIFIER LETTER SMALL R;Lm;0;L; 0072;;;;N;;;;; 02B4;MODIFIER LETTER SMALL TURNED R;Lm;0;L; 0279;;;;N;;;;; 02B5;MODIFIER LETTER SMALL TURNED R WITH HOOK;Lm;0;L; 027B;;;;N;MODIFIER LETTER SMALL TURNED R HOOK;;;; 02B6;MODIFIER LETTER SMALL CAPITAL INVERTED R;Lm;0;L; 0281;;;;N;;;;; 02B7;MODIFIER LETTER SMALL W;Lm;0;L; 0077;;;;N;;;;; 02B8;MODIFIER LETTER SMALL Y;Lm;0;L; 0079;;;;N;;;;; 02B9;MODIFIER LETTER PRIME;Sk;0;ON;;;;;N;;;;; 02BA;MODIFIER LETTER DOUBLE PRIME;Sk;0;ON;;;;;N;;;;; 02BB;MODIFIER LETTER TURNED COMMA;Lm;0;L;;;;;N;;;;; 02BC;MODIFIER LETTER APOSTROPHE;Lm;0;L;;;;;N;;;;; 02BD;MODIFIER LETTER REVERSED COMMA;Lm;0;L;;;;;N;;;;; 02BE;MODIFIER LETTER RIGHT HALF RING;Lm;0;L;;;;;N;;;;; 02BF;MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;; 02C0;MODIFIER LETTER GLOTTAL STOP;Lm;0;L;;;;;N;;;;; 02C1;MODIFIER LETTER REVERSED GLOTTAL STOP;Lm;0;L;;;;;N;;;;; 02C2;MODIFIER LETTER LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;; 02C3;MODIFIER LETTER RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;; 02C4;MODIFIER LETTER UP ARROWHEAD;Sk;0;ON;;;;;N;;;;; 02C5;MODIFIER LETTER DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;; 02C6;MODIFIER LETTER CIRCUMFLEX ACCENT;Sk;0;ON;;;;;N;MODIFIER LETTER CIRCUMFLEX;;;; 02C7;CARON;Sk;0;ON;;;;;N;MODIFIER LETTER HACEK;Mandarin Chinese third tone;;; 02C8;MODIFIER LETTER VERTICAL LINE;Sk;0;ON;;;;;N;;;;; 02C9;MODIFIER LETTER MACRON;Sk;0;ON;;;;;N;;Mandarin Chinese first tone;;; 02CA;MODIFIER LETTER ACUTE ACCENT;Sk;0;ON;;;;;N;MODIFIER LETTER ACUTE;Mandarin Chinese second tone;;; 02CB;MODIFIER LETTER GRAVE ACCENT;Sk;0;ON;;;;;N;MODIFIER LETTER GRAVE;Mandarin Chinese fourth tone;;; 02CC;MODIFIER LETTER LOW VERTICAL LINE;Sk;0;ON;;;;;N;;;;; 02CD;MODIFIER LETTER LOW MACRON;Sk;0;ON;;;;;N;;;;; 02CE;MODIFIER LETTER LOW GRAVE ACCENT;Sk;0;ON;;;;;N;MODIFIER LETTER LOW GRAVE;;;; 02CF;MODIFIER LETTER LOW ACUTE ACCENT;Sk;0;ON;;;;;N;MODIFIER LETTER LOW ACUTE;;;; 02D0;MODIFIER LETTER TRIANGULAR COLON;Lm;0;L;;;;;N;;;;; 02D1;MODIFIER LETTER HALF TRIANGULAR COLON;Lm;0;L;;;;;N;;;;; 02D2;MODIFIER LETTER CENTRED RIGHT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED RIGHT HALF RING;;;; 02D3;MODIFIER LETTER CENTRED LEFT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED LEFT HALF RING;;;; 02D4;MODIFIER LETTER UP TACK;Sk;0;ON;;;;;N;;;;; 02D5;MODIFIER LETTER DOWN TACK;Sk;0;ON;;;;;N;;;;; 02D6;MODIFIER LETTER PLUS SIGN;Sk;0;ON;;;;;N;;;;; 02D7;MODIFIER LETTER MINUS SIGN;Sk;0;ON;;;;;N;;;;; 02D8;BREVE;Sk;0;ON; 0020 0306;;;;N;SPACING BREVE;;;; 02D9;DOT ABOVE;Sk;0;ON; 0020 0307;;;;N;SPACING DOT ABOVE;Mandarin Chinese light tone;;; 02DA;RING ABOVE;Sk;0;ON; 0020 030A;;;;N;SPACING RING ABOVE;;;; 02DB;OGONEK;Sk;0;ON; 0020 0328;;;;N;SPACING OGONEK;;;; 02DC;SMALL TILDE;Sk;0;ON; 0020 0303;;;;N;SPACING TILDE;;;; 02DD;DOUBLE ACUTE ACCENT;Sk;0;ON; 0020 030B;;;;N;SPACING DOUBLE ACUTE;;;; 02DE;MODIFIER LETTER RHOTIC HOOK;Sk;0;ON;;;;;N;;;;; 02DF;MODIFIER LETTER CROSS ACCENT;Sk;0;ON;;;;;N;;;;; 02E0;MODIFIER LETTER SMALL GAMMA;Lm;0;L; 0263;;;;N;;;;; 02E1;MODIFIER LETTER SMALL L;Lm;0;L; 006C;;;;N;;;;; 02E2;MODIFIER LETTER SMALL S;Lm;0;L; 0073;;;;N;;;;; 02E3;MODIFIER LETTER SMALL X;Lm;0;L; 0078;;;;N;;;;; 02E4;MODIFIER LETTER SMALL REVERSED GLOTTAL STOP;Lm;0;L; 0295;;;;N;;;;; 02E5;MODIFIER LETTER EXTRA-HIGH TONE BAR;Sk;0;ON;;;;;N;;;;; 02E6;MODIFIER LETTER HIGH TONE BAR;Sk;0;ON;;;;;N;;;;; 02E7;MODIFIER LETTER MID TONE BAR;Sk;0;ON;;;;;N;;;;; 02E8;MODIFIER LETTER LOW TONE BAR;Sk;0;ON;;;;;N;;;;; 02E9;MODIFIER LETTER EXTRA-LOW TONE BAR;Sk;0;ON;;;;;N;;;;; 02EA;MODIFIER LETTER YIN DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;; 02EB;MODIFIER LETTER YANG DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;; 02EC;MODIFIER LETTER VOICING;Sk;0;ON;;;;;N;;;;; 02ED;MODIFIER LETTER UNASPIRATED;Sk;0;ON;;;;;N;;;;; 02EE;MODIFIER LETTER DOUBLE APOSTROPHE;Lm;0;L;;;;;N;;;;; 0300;COMBINING GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING GRAVE;Varia;;; 0301;COMBINING ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING ACUTE;Oxia, Tonos;;; 0302;COMBINING CIRCUMFLEX ACCENT;Mn;230;NSM;;;;;N;NON-SPACING CIRCUMFLEX;;;; 0303;COMBINING TILDE;Mn;230;NSM;;;;;N;NON-SPACING TILDE;;;; 0304;COMBINING MACRON;Mn;230;NSM;;;;;N;NON-SPACING MACRON;;;; 0305;COMBINING OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING OVERSCORE;;;; 0306;COMBINING BREVE;Mn;230;NSM;;;;;N;NON-SPACING BREVE;Vrachy;;; 0307;COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOT ABOVE;;;; 0308;COMBINING DIAERESIS;Mn;230;NSM;;;;;N;NON-SPACING DIAERESIS;Dialytika;;; 0309;COMBINING HOOK ABOVE;Mn;230;NSM;;;;;N;NON-SPACING HOOK ABOVE;;;; 030A;COMBINING RING ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RING ABOVE;;;; 030B;COMBINING DOUBLE ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE ACUTE;;;; 030C;COMBINING CARON;Mn;230;NSM;;;;;N;NON-SPACING HACEK;;;; 030D;COMBINING VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL LINE ABOVE;;;; 030E;COMBINING DOUBLE VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE VERTICAL LINE ABOVE;;;; 030F;COMBINING DOUBLE GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE GRAVE;;;; 0310;COMBINING CANDRABINDU;Mn;230;NSM;;;;;N;NON-SPACING CANDRABINDU;;;; 0311;COMBINING INVERTED BREVE;Mn;230;NSM;;;;;N;NON-SPACING INVERTED BREVE;;;; 0312;COMBINING TURNED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING TURNED COMMA ABOVE;;;; 0313;COMBINING COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING COMMA ABOVE;Psili;;; 0314;COMBINING REVERSED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING REVERSED COMMA ABOVE;Dasia;;; 0315;COMBINING COMMA ABOVE RIGHT;Mn;232;NSM;;;;;N;NON-SPACING COMMA ABOVE RIGHT;;;; 0316;COMBINING GRAVE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING GRAVE BELOW;;;; 0317;COMBINING ACUTE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING ACUTE BELOW;;;; 0318;COMBINING LEFT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT TACK BELOW;;;; 0319;COMBINING RIGHT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT TACK BELOW;;;; 031A;COMBINING LEFT ANGLE ABOVE;Mn;232;NSM;;;;;N;NON-SPACING LEFT ANGLE ABOVE;;;; 031B;COMBINING HORN;Mn;216;NSM;;;;;N;NON-SPACING HORN;;;; 031C;COMBINING LEFT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT HALF RING BELOW;;;; 031D;COMBINING UP TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING UP TACK BELOW;;;; 031E;COMBINING DOWN TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOWN TACK BELOW;;;; 031F;COMBINING PLUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING PLUS SIGN BELOW;;;; 0320;COMBINING MINUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING MINUS SIGN BELOW;;;; 0321;COMBINING PALATALIZED HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING PALATALIZED HOOK BELOW;;;; 0322;COMBINING RETROFLEX HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING RETROFLEX HOOK BELOW;;;; 0323;COMBINING DOT BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOT BELOW;;;; 0324;COMBINING DIAERESIS BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE DOT BELOW;;;; 0325;COMBINING RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RING BELOW;;;; 0326;COMBINING COMMA BELOW;Mn;220;NSM;;;;;N;NON-SPACING COMMA BELOW;;;; 0327;COMBINING CEDILLA;Mn;202;NSM;;;;;N;NON-SPACING CEDILLA;;;; 0328;COMBINING OGONEK;Mn;202;NSM;;;;;N;NON-SPACING OGONEK;;;; 0329;COMBINING VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;NON-SPACING VERTICAL LINE BELOW;;;; 032A;COMBINING BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BRIDGE BELOW;;;; 032B;COMBINING INVERTED DOUBLE ARCH BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED DOUBLE ARCH BELOW;;;; 032C;COMBINING CARON BELOW;Mn;220;NSM;;;;;N;NON-SPACING HACEK BELOW;;;; 032D;COMBINING CIRCUMFLEX ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING CIRCUMFLEX BELOW;;;; 032E;COMBINING BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BREVE BELOW;;;; 032F;COMBINING INVERTED BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BREVE BELOW;;;; 0330;COMBINING TILDE BELOW;Mn;220;NSM;;;;;N;NON-SPACING TILDE BELOW;;;; 0331;COMBINING MACRON BELOW;Mn;220;NSM;;;;;N;NON-SPACING MACRON BELOW;;;; 0332;COMBINING LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING UNDERSCORE;;;; 0333;COMBINING DOUBLE LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE UNDERSCORE;;;; 0334;COMBINING TILDE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING TILDE OVERLAY;;;; 0335;COMBINING SHORT STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT BAR OVERLAY;;;; 0336;COMBINING LONG STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG BAR OVERLAY;;;; 0337;COMBINING SHORT SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT SLASH OVERLAY;;;; 0338;COMBINING LONG SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG SLASH OVERLAY;;;; 0339;COMBINING RIGHT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT HALF RING BELOW;;;; 033A;COMBINING INVERTED BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BRIDGE BELOW;;;; 033B;COMBINING SQUARE BELOW;Mn;220;NSM;;;;;N;NON-SPACING SQUARE BELOW;;;; 033C;COMBINING SEAGULL BELOW;Mn;220;NSM;;;;;N;NON-SPACING SEAGULL BELOW;;;; 033D;COMBINING X ABOVE;Mn;230;NSM;;;;;N;NON-SPACING X ABOVE;;;; 033E;COMBINING VERTICAL TILDE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL TILDE;;;; 033F;COMBINING DOUBLE OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE OVERSCORE;;;; 0340;COMBINING GRAVE TONE MARK;Mn;230;NSM;0300;;;;N;NON-SPACING GRAVE TONE MARK;Vietnamese;;; 0341;COMBINING ACUTE TONE MARK;Mn;230;NSM;0301;;;;N;NON-SPACING ACUTE TONE MARK;Vietnamese;;; 0342;COMBINING GREEK PERISPOMENI;Mn;230;NSM;;;;;N;;;;; 0343;COMBINING GREEK KORONIS;Mn;230;NSM;0313;;;;N;;;;; 0344;COMBINING GREEK DIALYTIKA TONOS;Mn;230;NSM;0308 0301;;;;N;GREEK NON-SPACING DIAERESIS TONOS;;;; 0345;COMBINING GREEK YPOGEGRAMMENI;Mn;240;NSM;;;;;N;GREEK NON-SPACING IOTA BELOW;;0399;;0399 0346;COMBINING BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;; 0347;COMBINING EQUALS SIGN BELOW;Mn;220;NSM;;;;;N;;;;; 0348;COMBINING DOUBLE VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;;;;; 0349;COMBINING LEFT ANGLE BELOW;Mn;220;NSM;;;;;N;;;;; 034A;COMBINING NOT TILDE ABOVE;Mn;230;NSM;;;;;N;;;;; 034B;COMBINING HOMOTHETIC ABOVE;Mn;230;NSM;;;;;N;;;;; 034C;COMBINING ALMOST EQUAL TO ABOVE;Mn;230;NSM;;;;;N;;;;; 034D;COMBINING LEFT RIGHT ARROW BELOW;Mn;220;NSM;;;;;N;;;;; 034E;COMBINING UPWARDS ARROW BELOW;Mn;220;NSM;;;;;N;;;;; 034F;COMBINING GRAPHEME JOINER;Mn;0;NSM;;;;;N;;;;; 0360;COMBINING DOUBLE TILDE;Mn;234;NSM;;;;;N;;;;; 0361;COMBINING DOUBLE INVERTED BREVE;Mn;234;NSM;;;;;N;;;;; 0362;COMBINING DOUBLE RIGHTWARDS ARROW BELOW;Mn;233;NSM;;;;;N;;;;; 0363;COMBINING LATIN SMALL LETTER A;Mn;230;NSM;;;;;N;;;;; 0364;COMBINING LATIN SMALL LETTER E;Mn;230;NSM;;;;;N;;;;; 0365;COMBINING LATIN SMALL LETTER I;Mn;230;NSM;;;;;N;;;;; 0366;COMBINING LATIN SMALL LETTER O;Mn;230;NSM;;;;;N;;;;; 0367;COMBINING LATIN SMALL LETTER U;Mn;230;NSM;;;;;N;;;;; 0368;COMBINING LATIN SMALL LETTER C;Mn;230;NSM;;;;;N;;;;; 0369;COMBINING LATIN SMALL LETTER D;Mn;230;NSM;;;;;N;;;;; 036A;COMBINING LATIN SMALL LETTER H;Mn;230;NSM;;;;;N;;;;; 036B;COMBINING LATIN SMALL LETTER M;Mn;230;NSM;;;;;N;;;;; 036C;COMBINING LATIN SMALL LETTER R;Mn;230;NSM;;;;;N;;;;; 036D;COMBINING LATIN SMALL LETTER T;Mn;230;NSM;;;;;N;;;;; 036E;COMBINING LATIN SMALL LETTER V;Mn;230;NSM;;;;;N;;;;; 036F;COMBINING LATIN SMALL LETTER X;Mn;230;NSM;;;;;N;;;;; 0374;GREEK NUMERAL SIGN;Sk;0;ON;02B9;;;;N;GREEK UPPER NUMERAL SIGN;Dexia keraia;;; 0375;GREEK LOWER NUMERAL SIGN;Sk;0;ON;;;;;N;;Aristeri keraia;;; 037A;GREEK YPOGEGRAMMENI;Lm;0;L; 0020 0345;;;;N;GREEK SPACING IOTA BELOW;;;; 037E;GREEK QUESTION MARK;Po;0;ON;003B;;;;N;;Erotimatiko;;; 0384;GREEK TONOS;Sk;0;ON; 0020 0301;;;;N;GREEK SPACING TONOS;;;; 0385;GREEK DIALYTIKA TONOS;Sk;0;ON;00A8 0301;;;;N;GREEK SPACING DIAERESIS TONOS;;;; 0386;GREEK CAPITAL LETTER ALPHA WITH TONOS;Lu;0;L;0391 0301;;;;N;GREEK CAPITAL LETTER ALPHA TONOS;;;03AC; 0387;GREEK ANO TELEIA;Po;0;ON;00B7;;;;N;;;;; 0388;GREEK CAPITAL LETTER EPSILON WITH TONOS;Lu;0;L;0395 0301;;;;N;GREEK CAPITAL LETTER EPSILON TONOS;;;03AD; 0389;GREEK CAPITAL LETTER ETA WITH TONOS;Lu;0;L;0397 0301;;;;N;GREEK CAPITAL LETTER ETA TONOS;;;03AE; 038A;GREEK CAPITAL LETTER IOTA WITH TONOS;Lu;0;L;0399 0301;;;;N;GREEK CAPITAL LETTER IOTA TONOS;;;03AF; 038C;GREEK CAPITAL LETTER OMICRON WITH TONOS;Lu;0;L;039F 0301;;;;N;GREEK CAPITAL LETTER OMICRON TONOS;;;03CC; 038E;GREEK CAPITAL LETTER UPSILON WITH TONOS;Lu;0;L;03A5 0301;;;;N;GREEK CAPITAL LETTER UPSILON TONOS;;;03CD; 038F;GREEK CAPITAL LETTER OMEGA WITH TONOS;Lu;0;L;03A9 0301;;;;N;GREEK CAPITAL LETTER OMEGA TONOS;;;03CE; 0390;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS;Ll;0;L;03CA 0301;;;;N;GREEK SMALL LETTER IOTA DIAERESIS TONOS;;;; 0391;GREEK CAPITAL LETTER ALPHA;Lu;0;L;;;;;N;;;;03B1; 0392;GREEK CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;03B2; 0393;GREEK CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;03B3; 0394;GREEK CAPITAL LETTER DELTA;Lu;0;L;;;;;N;;;;03B4; 0395;GREEK CAPITAL LETTER EPSILON;Lu;0;L;;;;;N;;;;03B5; 0396;GREEK CAPITAL LETTER ZETA;Lu;0;L;;;;;N;;;;03B6; 0397;GREEK CAPITAL LETTER ETA;Lu;0;L;;;;;N;;;;03B7; 0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8; 0399;GREEK CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;03B9; 039A;GREEK CAPITAL LETTER KAPPA;Lu;0;L;;;;;N;;;;03BA; 039B;GREEK CAPITAL LETTER LAMDA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER LAMBDA;;;03BB; 039C;GREEK CAPITAL LETTER MU;Lu;0;L;;;;;N;;;;03BC; 039D;GREEK CAPITAL LETTER NU;Lu;0;L;;;;;N;;;;03BD; 039E;GREEK CAPITAL LETTER XI;Lu;0;L;;;;;N;;;;03BE; 039F;GREEK CAPITAL LETTER OMICRON;Lu;0;L;;;;;N;;;;03BF; 03A0;GREEK CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;03C0; 03A1;GREEK CAPITAL LETTER RHO;Lu;0;L;;;;;N;;;;03C1; 03A3;GREEK CAPITAL LETTER SIGMA;Lu;0;L;;;;;N;;;;03C3; 03A4;GREEK CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;03C4; 03A5;GREEK CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;03C5; 03A6;GREEK CAPITAL LETTER PHI;Lu;0;L;;;;;N;;;;03C6; 03A7;GREEK CAPITAL LETTER CHI;Lu;0;L;;;;;N;;;;03C7; 03A8;GREEK CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;03C8; 03A9;GREEK CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;03C9; 03AA;GREEK CAPITAL LETTER IOTA WITH DIALYTIKA;Lu;0;L;0399 0308;;;;N;GREEK CAPITAL LETTER IOTA DIAERESIS;;;03CA; 03AB;GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA;Lu;0;L;03A5 0308;;;;N;GREEK CAPITAL LETTER UPSILON DIAERESIS;;;03CB; 03AC;GREEK SMALL LETTER ALPHA WITH TONOS;Ll;0;L;03B1 0301;;;;N;GREEK SMALL LETTER ALPHA TONOS;;0386;;0386 03AD;GREEK SMALL LETTER EPSILON WITH TONOS;Ll;0;L;03B5 0301;;;;N;GREEK SMALL LETTER EPSILON TONOS;;0388;;0388 03AE;GREEK SMALL LETTER ETA WITH TONOS;Ll;0;L;03B7 0301;;;;N;GREEK SMALL LETTER ETA TONOS;;0389;;0389 03AF;GREEK SMALL LETTER IOTA WITH TONOS;Ll;0;L;03B9 0301;;;;N;GREEK SMALL LETTER IOTA TONOS;;038A;;038A 03B0;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS;Ll;0;L;03CB 0301;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS TONOS;;;; 03B1;GREEK SMALL LETTER ALPHA;Ll;0;L;;;;;N;;;0391;;0391 03B2;GREEK SMALL LETTER BETA;Ll;0;L;;;;;N;;;0392;;0392 03B3;GREEK SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0393;;0393 03B4;GREEK SMALL LETTER DELTA;Ll;0;L;;;;;N;;;0394;;0394 03B5;GREEK SMALL LETTER EPSILON;Ll;0;L;;;;;N;;;0395;;0395 03B6;GREEK SMALL LETTER ZETA;Ll;0;L;;;;;N;;;0396;;0396 03B7;GREEK SMALL LETTER ETA;Ll;0;L;;;;;N;;;0397;;0397 03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398 03B9;GREEK SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0399;;0399 03BA;GREEK SMALL LETTER KAPPA;Ll;0;L;;;;;N;;;039A;;039A 03BB;GREEK SMALL LETTER LAMDA;Ll;0;L;;;;;N;GREEK SMALL LETTER LAMBDA;;039B;;039B 03BC;GREEK SMALL LETTER MU;Ll;0;L;;;;;N;;;039C;;039C 03BD;GREEK SMALL LETTER NU;Ll;0;L;;;;;N;;;039D;;039D 03BE;GREEK SMALL LETTER XI;Ll;0;L;;;;;N;;;039E;;039E 03BF;GREEK SMALL LETTER OMICRON;Ll;0;L;;;;;N;;;039F;;039F 03C0;GREEK SMALL LETTER PI;Ll;0;L;;;;;N;;;03A0;;03A0 03C1;GREEK SMALL LETTER RHO;Ll;0;L;;;;;N;;;03A1;;03A1 03C2;GREEK SMALL LETTER FINAL SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3 03C3;GREEK SMALL LETTER SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3 03C4;GREEK SMALL LETTER TAU;Ll;0;L;;;;;N;;;03A4;;03A4 03C5;GREEK SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;03A5;;03A5 03C6;GREEK SMALL LETTER PHI;Ll;0;L;;;;;N;;;03A6;;03A6 03C7;GREEK SMALL LETTER CHI;Ll;0;L;;;;;N;;;03A7;;03A7 03C8;GREEK SMALL LETTER PSI;Ll;0;L;;;;;N;;;03A8;;03A8 03C9;GREEK SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;03A9;;03A9 03CA;GREEK SMALL LETTER IOTA WITH DIALYTIKA;Ll;0;L;03B9 0308;;;;N;GREEK SMALL LETTER IOTA DIAERESIS;;03AA;;03AA 03CB;GREEK SMALL LETTER UPSILON WITH DIALYTIKA;Ll;0;L;03C5 0308;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS;;03AB;;03AB 03CC;GREEK SMALL LETTER OMICRON WITH TONOS;Ll;0;L;03BF 0301;;;;N;GREEK SMALL LETTER OMICRON TONOS;;038C;;038C 03CD;GREEK SMALL LETTER UPSILON WITH TONOS;Ll;0;L;03C5 0301;;;;N;GREEK SMALL LETTER UPSILON TONOS;;038E;;038E 03CE;GREEK SMALL LETTER OMEGA WITH TONOS;Ll;0;L;03C9 0301;;;;N;GREEK SMALL LETTER OMEGA TONOS;;038F;;038F 03D0;GREEK BETA SYMBOL;Ll;0;L; 03B2;;;;N;GREEK SMALL LETTER CURLED BETA;;0392;;0392 03D1;GREEK THETA SYMBOL;Ll;0;L; 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398 03D2;GREEK UPSILON WITH HOOK SYMBOL;Lu;0;L; 03A5;;;;N;GREEK CAPITAL LETTER UPSILON HOOK;;;; 03D3;GREEK UPSILON WITH ACUTE AND HOOK SYMBOL;Lu;0;L;03D2 0301;;;;N;GREEK CAPITAL LETTER UPSILON HOOK TONOS;;;; 03D4;GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL;Lu;0;L;03D2 0308;;;;N;GREEK CAPITAL LETTER UPSILON HOOK DIAERESIS;;;; 03D5;GREEK PHI SYMBOL;Ll;0;L; 03C6;;;;N;GREEK SMALL LETTER SCRIPT PHI;;03A6;;03A6 03D6;GREEK PI SYMBOL;Ll;0;L; 03C0;;;;N;GREEK SMALL LETTER OMEGA PI;;03A0;;03A0 03D7;GREEK KAI SYMBOL;Ll;0;L;;;;;N;;;;; 03D8;GREEK LETTER ARCHAIC KOPPA;Lu;0;L;;;;;N;;*;;03D9; 03D9;GREEK SMALL LETTER ARCHAIC KOPPA;Ll;0;L;;;;;N;;*;03D8;;03D8 03DA;GREEK LETTER STIGMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER STIGMA;;;03DB; 03DB;GREEK SMALL LETTER STIGMA;Ll;0;L;;;;;N;;;03DA;;03DA 03DC;GREEK LETTER DIGAMMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DIGAMMA;;;03DD; 03DD;GREEK SMALL LETTER DIGAMMA;Ll;0;L;;;;;N;;;03DC;;03DC 03DE;GREEK LETTER KOPPA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KOPPA;;;03DF; 03DF;GREEK SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;03DE;;03DE 03E0;GREEK LETTER SAMPI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SAMPI;;;03E1; 03E1;GREEK SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;03E0;;03E0 03E2;COPTIC CAPITAL LETTER SHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHEI;;;03E3; 03E3;COPTIC SMALL LETTER SHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER SHEI;;03E2;;03E2 03E4;COPTIC CAPITAL LETTER FEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER FEI;;;03E5; 03E5;COPTIC SMALL LETTER FEI;Ll;0;L;;;;;N;GREEK SMALL LETTER FEI;;03E4;;03E4 03E6;COPTIC CAPITAL LETTER KHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KHEI;;;03E7; 03E7;COPTIC SMALL LETTER KHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER KHEI;;03E6;;03E6 03E8;COPTIC CAPITAL LETTER HORI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER HORI;;;03E9; 03E9;COPTIC SMALL LETTER HORI;Ll;0;L;;;;;N;GREEK SMALL LETTER HORI;;03E8;;03E8 03EA;COPTIC CAPITAL LETTER GANGIA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER GANGIA;;;03EB; 03EB;COPTIC SMALL LETTER GANGIA;Ll;0;L;;;;;N;GREEK SMALL LETTER GANGIA;;03EA;;03EA 03EC;COPTIC CAPITAL LETTER SHIMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHIMA;;;03ED; 03ED;COPTIC SMALL LETTER SHIMA;Ll;0;L;;;;;N;GREEK SMALL LETTER SHIMA;;03EC;;03EC 03EE;COPTIC CAPITAL LETTER DEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DEI;;;03EF; 03EF;COPTIC SMALL LETTER DEI;Ll;0;L;;;;;N;GREEK SMALL LETTER DEI;;03EE;;03EE 03F0;GREEK KAPPA SYMBOL;Ll;0;L; 03BA;;;;N;GREEK SMALL LETTER SCRIPT KAPPA;;039A;;039A 03F1;GREEK RHO SYMBOL;Ll;0;L; 03C1;;;;N;GREEK SMALL LETTER TAILED RHO;;03A1;;03A1 03F2;GREEK LUNATE SIGMA SYMBOL;Ll;0;L; 03C2;;;;N;GREEK SMALL LETTER LUNATE SIGMA;;03A3;;03A3 03F3;GREEK LETTER YOT;Ll;0;L;;;;;N;;;;; 03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L; 0398;;;;N;;;;03B8; 03F5;GREEK LUNATE EPSILON SYMBOL;Ll;0;L; 03B5;;;;N;;;0395;;0395 03F6;GREEK REVERSED LUNATE EPSILON SYMBOL;Sm;0;ON;;;;;N;;;;; 0400;CYRILLIC CAPITAL LETTER IE WITH GRAVE;Lu;0;L;0415 0300;;;;N;;;;0450; 0401;CYRILLIC CAPITAL LETTER IO;Lu;0;L;0415 0308;;;;N;;;;0451; 0402;CYRILLIC CAPITAL LETTER DJE;Lu;0;L;;;;;N;;Serbocroatian;;0452; 0403;CYRILLIC CAPITAL LETTER GJE;Lu;0;L;0413 0301;;;;N;;;;0453; 0404;CYRILLIC CAPITAL LETTER UKRAINIAN IE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER E;;;0454; 0405;CYRILLIC CAPITAL LETTER DZE;Lu;0;L;;;;;N;;;;0455; 0406;CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER I;;;0456; 0407;CYRILLIC CAPITAL LETTER YI;Lu;0;L;0406 0308;;;;N;;Ukrainian;;0457; 0408;CYRILLIC CAPITAL LETTER JE;Lu;0;L;;;;;N;;;;0458; 0409;CYRILLIC CAPITAL LETTER LJE;Lu;0;L;;;;;N;;;;0459; 040A;CYRILLIC CAPITAL LETTER NJE;Lu;0;L;;;;;N;;;;045A; 040B;CYRILLIC CAPITAL LETTER TSHE;Lu;0;L;;;;;N;;Serbocroatian;;045B; 040C;CYRILLIC CAPITAL LETTER KJE;Lu;0;L;041A 0301;;;;N;;;;045C; 040D;CYRILLIC CAPITAL LETTER I WITH GRAVE;Lu;0;L;0418 0300;;;;N;;;;045D; 040E;CYRILLIC CAPITAL LETTER SHORT U;Lu;0;L;0423 0306;;;;N;;Byelorussian;;045E; 040F;CYRILLIC CAPITAL LETTER DZHE;Lu;0;L;;;;;N;;;;045F; 0410;CYRILLIC CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0430; 0411;CYRILLIC CAPITAL LETTER BE;Lu;0;L;;;;;N;;;;0431; 0412;CYRILLIC CAPITAL LETTER VE;Lu;0;L;;;;;N;;;;0432; 0413;CYRILLIC CAPITAL LETTER GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE;;;0433; 0414;CYRILLIC CAPITAL LETTER DE;Lu;0;L;;;;;N;;;;0434; 0415;CYRILLIC CAPITAL LETTER IE;Lu;0;L;;;;;N;;;;0435; 0416;CYRILLIC CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;0436; 0417;CYRILLIC CAPITAL LETTER ZE;Lu;0;L;;;;;N;;;;0437; 0418;CYRILLIC CAPITAL LETTER I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER II;;;0438; 0419;CYRILLIC CAPITAL LETTER SHORT I;Lu;0;L;0418 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT II;;;0439; 041A;CYRILLIC CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;043A; 041B;CYRILLIC CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;043B; 041C;CYRILLIC CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;043C; 041D;CYRILLIC CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;043D; 041E;CYRILLIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;043E; 041F;CYRILLIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;043F; 0420;CYRILLIC CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;0440; 0421;CYRILLIC CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;0441; 0422;CYRILLIC CAPITAL LETTER TE;Lu;0;L;;;;;N;;;;0442; 0423;CYRILLIC CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0443; 0424;CYRILLIC CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;0444; 0425;CYRILLIC CAPITAL LETTER HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA;;;0445; 0426;CYRILLIC CAPITAL LETTER TSE;Lu;0;L;;;;;N;;;;0446; 0427;CYRILLIC CAPITAL LETTER CHE;Lu;0;L;;;;;N;;;;0447; 0428;CYRILLIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0448; 0429;CYRILLIC CAPITAL LETTER SHCHA;Lu;0;L;;;;;N;;;;0449; 042A;CYRILLIC CAPITAL LETTER HARD SIGN;Lu;0;L;;;;;N;;;;044A; 042B;CYRILLIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER YERI;;;044B; 042C;CYRILLIC CAPITAL LETTER SOFT SIGN;Lu;0;L;;;;;N;;;;044C; 042D;CYRILLIC CAPITAL LETTER E;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED E;;;044D; 042E;CYRILLIC CAPITAL LETTER YU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IU;;;044E; 042F;CYRILLIC CAPITAL LETTER YA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IA;;;044F; 0430;CYRILLIC SMALL LETTER A;Ll;0;L;;;;;N;;;0410;;0410 0431;CYRILLIC SMALL LETTER BE;Ll;0;L;;;;;N;;;0411;;0411 0432;CYRILLIC SMALL LETTER VE;Ll;0;L;;;;;N;;;0412;;0412 0433;CYRILLIC SMALL LETTER GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE;;0413;;0413 0434;CYRILLIC SMALL LETTER DE;Ll;0;L;;;;;N;;;0414;;0414 0435;CYRILLIC SMALL LETTER IE;Ll;0;L;;;;;N;;;0415;;0415 0436;CYRILLIC SMALL LETTER ZHE;Ll;0;L;;;;;N;;;0416;;0416 0437;CYRILLIC SMALL LETTER ZE;Ll;0;L;;;;;N;;;0417;;0417 0438;CYRILLIC SMALL LETTER I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER II;;0418;;0418 0439;CYRILLIC SMALL LETTER SHORT I;Ll;0;L;0438 0306;;;;N;CYRILLIC SMALL LETTER SHORT II;;0419;;0419 043A;CYRILLIC SMALL LETTER KA;Ll;0;L;;;;;N;;;041A;;041A 043B;CYRILLIC SMALL LETTER EL;Ll;0;L;;;;;N;;;041B;;041B 043C;CYRILLIC SMALL LETTER EM;Ll;0;L;;;;;N;;;041C;;041C 043D;CYRILLIC SMALL LETTER EN;Ll;0;L;;;;;N;;;041D;;041D 043E;CYRILLIC SMALL LETTER O;Ll;0;L;;;;;N;;;041E;;041E 043F;CYRILLIC SMALL LETTER PE;Ll;0;L;;;;;N;;;041F;;041F 0440;CYRILLIC SMALL LETTER ER;Ll;0;L;;;;;N;;;0420;;0420 0441;CYRILLIC SMALL LETTER ES;Ll;0;L;;;;;N;;;0421;;0421 0442;CYRILLIC SMALL LETTER TE;Ll;0;L;;;;;N;;;0422;;0422 0443;CYRILLIC SMALL LETTER U;Ll;0;L;;;;;N;;;0423;;0423 0444;CYRILLIC SMALL LETTER EF;Ll;0;L;;;;;N;;;0424;;0424 0445;CYRILLIC SMALL LETTER HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA;;0425;;0425 0446;CYRILLIC SMALL LETTER TSE;Ll;0;L;;;;;N;;;0426;;0426 0447;CYRILLIC SMALL LETTER CHE;Ll;0;L;;;;;N;;;0427;;0427 0448;CYRILLIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;0428;;0428 0449;CYRILLIC SMALL LETTER SHCHA;Ll;0;L;;;;;N;;;0429;;0429 044A;CYRILLIC SMALL LETTER HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A 044B;CYRILLIC SMALL LETTER YERU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER YERI;;042B;;042B 044C;CYRILLIC SMALL LETTER SOFT SIGN;Ll;0;L;;;;;N;;;042C;;042C 044D;CYRILLIC SMALL LETTER E;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED E;;042D;;042D 044E;CYRILLIC SMALL LETTER YU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IU;;042E;;042E 044F;CYRILLIC SMALL LETTER YA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IA;;042F;;042F 0450;CYRILLIC SMALL LETTER IE WITH GRAVE;Ll;0;L;0435 0300;;;;N;;;0400;;0400 0451;CYRILLIC SMALL LETTER IO;Ll;0;L;0435 0308;;;;N;;;0401;;0401 0452;CYRILLIC SMALL LETTER DJE;Ll;0;L;;;;;N;;Serbocroatian;0402;;0402 0453;CYRILLIC SMALL LETTER GJE;Ll;0;L;0433 0301;;;;N;;;0403;;0403 0454;CYRILLIC SMALL LETTER UKRAINIAN IE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER E;;0404;;0404 0455;CYRILLIC SMALL LETTER DZE;Ll;0;L;;;;;N;;;0405;;0405 0456;CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER I;;0406;;0406 0457;CYRILLIC SMALL LETTER YI;Ll;0;L;0456 0308;;;;N;;Ukrainian;0407;;0407 0458;CYRILLIC SMALL LETTER JE;Ll;0;L;;;;;N;;;0408;;0408 0459;CYRILLIC SMALL LETTER LJE;Ll;0;L;;;;;N;;;0409;;0409 045A;CYRILLIC SMALL LETTER NJE;Ll;0;L;;;;;N;;;040A;;040A 045B;CYRILLIC SMALL LETTER TSHE;Ll;0;L;;;;;N;;Serbocroatian;040B;;040B 045C;CYRILLIC SMALL LETTER KJE;Ll;0;L;043A 0301;;;;N;;;040C;;040C 045D;CYRILLIC SMALL LETTER I WITH GRAVE;Ll;0;L;0438 0300;;;;N;;;040D;;040D 045E;CYRILLIC SMALL LETTER SHORT U;Ll;0;L;0443 0306;;;;N;;Byelorussian;040E;;040E 045F;CYRILLIC SMALL LETTER DZHE;Ll;0;L;;;;;N;;;040F;;040F 0460;CYRILLIC CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;0461; 0461;CYRILLIC SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;0460;;0460 0462;CYRILLIC CAPITAL LETTER YAT;Lu;0;L;;;;;N;;;;0463; 0463;CYRILLIC SMALL LETTER YAT;Ll;0;L;;;;;N;;;0462;;0462 0464;CYRILLIC CAPITAL LETTER IOTIFIED E;Lu;0;L;;;;;N;;;;0465; 0465;CYRILLIC SMALL LETTER IOTIFIED E;Ll;0;L;;;;;N;;;0464;;0464 0466;CYRILLIC CAPITAL LETTER LITTLE YUS;Lu;0;L;;;;;N;;;;0467; 0467;CYRILLIC SMALL LETTER LITTLE YUS;Ll;0;L;;;;;N;;;0466;;0466 0468;CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS;Lu;0;L;;;;;N;;;;0469; 0469;CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS;Ll;0;L;;;;;N;;;0468;;0468 046A;CYRILLIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;046B; 046B;CYRILLIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;046A;;046A 046C;CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS;Lu;0;L;;;;;N;;;;046D; 046D;CYRILLIC SMALL LETTER IOTIFIED BIG YUS;Ll;0;L;;;;;N;;;046C;;046C 046E;CYRILLIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;046F; 046F;CYRILLIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;046E;;046E 0470;CYRILLIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;0471; 0471;CYRILLIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;0470;;0470 0472;CYRILLIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;0473; 0473;CYRILLIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;0472;;0472 0474;CYRILLIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;0475; 0475;CYRILLIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;0474;;0474 0476;CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Lu;0;L;0474 030F;;;;N;CYRILLIC CAPITAL LETTER IZHITSA DOUBLE GRAVE;;;0477; 0477;CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Ll;0;L;0475 030F;;;;N;CYRILLIC SMALL LETTER IZHITSA DOUBLE GRAVE;;0476;;0476 0478;CYRILLIC CAPITAL LETTER UK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER UK DIGRAPH;;;0479; 0479;CYRILLIC SMALL LETTER UK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER UK DIGRAPH;;0478;;0478 047A;CYRILLIC CAPITAL LETTER ROUND OMEGA;Lu;0;L;;;;;N;;;;047B; 047B;CYRILLIC SMALL LETTER ROUND OMEGA;Ll;0;L;;;;;N;;;047A;;047A 047C;CYRILLIC CAPITAL LETTER OMEGA WITH TITLO;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER OMEGA TITLO;;;047D; 047D;CYRILLIC SMALL LETTER OMEGA WITH TITLO;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER OMEGA TITLO;;047C;;047C 047E;CYRILLIC CAPITAL LETTER OT;Lu;0;L;;;;;N;;;;047F; 047F;CYRILLIC SMALL LETTER OT;Ll;0;L;;;;;N;;;047E;;047E 0480;CYRILLIC CAPITAL LETTER KOPPA;Lu;0;L;;;;;N;;;;0481; 0481;CYRILLIC SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;0480;;0480 0482;CYRILLIC THOUSANDS SIGN;So;0;L;;;;;N;;;;; 0483;COMBINING CYRILLIC TITLO;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING TITLO;;;; 0484;COMBINING CYRILLIC PALATALIZATION;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PALATALIZATION;;;; 0485;COMBINING CYRILLIC DASIA PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING DASIA PNEUMATA;;;; 0486;COMBINING CYRILLIC PSILI PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PSILI PNEUMATA;;;; 0488;COMBINING CYRILLIC HUNDRED THOUSANDS SIGN;Me;0;NSM;;;;;N;;;;; 0489;COMBINING CYRILLIC MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; 048A;CYRILLIC CAPITAL LETTER SHORT I WITH TAIL;Lu;0;L;;;;;N;;;;048B; 048B;CYRILLIC SMALL LETTER SHORT I WITH TAIL;Ll;0;L;;;;;N;;;048A;;048A 048C;CYRILLIC CAPITAL LETTER SEMISOFT SIGN;Lu;0;L;;;;;N;;;;048D; 048D;CYRILLIC SMALL LETTER SEMISOFT SIGN;Ll;0;L;;;;;N;;;048C;;048C 048E;CYRILLIC CAPITAL LETTER ER WITH TICK;Lu;0;L;;;;;N;;;;048F; 048F;CYRILLIC SMALL LETTER ER WITH TICK;Ll;0;L;;;;;N;;;048E;;048E 0490;CYRILLIC CAPITAL LETTER GHE WITH UPTURN;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE WITH UPTURN;;;0491; 0491;CYRILLIC SMALL LETTER GHE WITH UPTURN;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE WITH UPTURN;;0490;;0490 0492;CYRILLIC CAPITAL LETTER GHE WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE BAR;;;0493; 0493;CYRILLIC SMALL LETTER GHE WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE BAR;;0492;;0492 0494;CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE HOOK;;;0495; 0495;CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE HOOK;;0494;;0494 0496;CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZHE WITH RIGHT DESCENDER;;;0497; 0497;CYRILLIC SMALL LETTER ZHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZHE WITH RIGHT DESCENDER;;0496;;0496 0498;CYRILLIC CAPITAL LETTER ZE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZE CEDILLA;;;0499; 0499;CYRILLIC SMALL LETTER ZE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZE CEDILLA;;0498;;0498 049A;CYRILLIC CAPITAL LETTER KA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA WITH RIGHT DESCENDER;;;049B; 049B;CYRILLIC SMALL LETTER KA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA WITH RIGHT DESCENDER;;049A;;049A 049C;CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA VERTICAL BAR;;;049D; 049D;CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA VERTICAL BAR;;049C;;049C 049E;CYRILLIC CAPITAL LETTER KA WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA BAR;;;049F; 049F;CYRILLIC SMALL LETTER KA WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA BAR;;049E;;049E 04A0;CYRILLIC CAPITAL LETTER BASHKIR KA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED GE KA;;;04A1; 04A1;CYRILLIC SMALL LETTER BASHKIR KA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED GE KA;;04A0;;04A0 04A2;CYRILLIC CAPITAL LETTER EN WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN WITH RIGHT DESCENDER;;;04A3; 04A3;CYRILLIC SMALL LETTER EN WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN WITH RIGHT DESCENDER;;04A2;;04A2 04A4;CYRILLIC CAPITAL LIGATURE EN GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN GE;;;04A5; 04A5;CYRILLIC SMALL LIGATURE EN GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN GE;;04A4;;04A4 04A6;CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER PE HOOK;Abkhasian;;04A7; 04A7;CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER PE HOOK;Abkhasian;04A6;;04A6 04A8;CYRILLIC CAPITAL LETTER ABKHASIAN HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER O HOOK;;;04A9; 04A9;CYRILLIC SMALL LETTER ABKHASIAN HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER O HOOK;;04A8;;04A8 04AA;CYRILLIC CAPITAL LETTER ES WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ES CEDILLA;;;04AB; 04AB;CYRILLIC SMALL LETTER ES WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ES CEDILLA;;04AA;;04AA 04AC;CYRILLIC CAPITAL LETTER TE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE WITH RIGHT DESCENDER;;;04AD; 04AD;CYRILLIC SMALL LETTER TE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE WITH RIGHT DESCENDER;;04AC;;04AC 04AE;CYRILLIC CAPITAL LETTER STRAIGHT U;Lu;0;L;;;;;N;;;;04AF; 04AF;CYRILLIC SMALL LETTER STRAIGHT U;Ll;0;L;;;;;N;;;04AE;;04AE 04B0;CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER STRAIGHT U BAR;;;04B1; 04B1;CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER STRAIGHT U BAR;;04B0;;04B0 04B2;CYRILLIC CAPITAL LETTER HA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA WITH RIGHT DESCENDER;;;04B3; 04B3;CYRILLIC SMALL LETTER HA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA WITH RIGHT DESCENDER;;04B2;;04B2 04B4;CYRILLIC CAPITAL LIGATURE TE TSE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE TSE;Abkhasian;;04B5; 04B5;CYRILLIC SMALL LIGATURE TE TSE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE TSE;Abkhasian;04B4;;04B4 04B6;CYRILLIC CAPITAL LETTER CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH RIGHT DESCENDER;;;04B7; 04B7;CYRILLIC SMALL LETTER CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH RIGHT DESCENDER;;04B6;;04B6 04B8;CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE VERTICAL BAR;;;04B9; 04B9;CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE VERTICAL BAR;;04B8;;04B8 04BA;CYRILLIC CAPITAL LETTER SHHA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER H;;;04BB; 04BB;CYRILLIC SMALL LETTER SHHA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER H;;04BA;;04BA 04BC;CYRILLIC CAPITAL LETTER ABKHASIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK;;;04BD; 04BD;CYRILLIC SMALL LETTER ABKHASIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK;;04BC;;04BC 04BE;CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK OGONEK;;;04BF; 04BF;CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK OGONEK;;04BE;;04BE 04C0;CYRILLIC LETTER PALOCHKA;Lu;0;L;;;;;N;CYRILLIC LETTER I;;;; 04C1;CYRILLIC CAPITAL LETTER ZHE WITH BREVE;Lu;0;L;0416 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT ZHE;;;04C2; 04C2;CYRILLIC SMALL LETTER ZHE WITH BREVE;Ll;0;L;0436 0306;;;;N;CYRILLIC SMALL LETTER SHORT ZHE;;04C1;;04C1 04C3;CYRILLIC CAPITAL LETTER KA WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA HOOK;;;04C4; 04C4;CYRILLIC SMALL LETTER KA WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA HOOK;;04C3;;04C3 04C5;CYRILLIC CAPITAL LETTER EL WITH TAIL;Lu;0;L;;;;;N;;;;04C6; 04C6;CYRILLIC SMALL LETTER EL WITH TAIL;Ll;0;L;;;;;N;;;04C5;;04C5 04C7;CYRILLIC CAPITAL LETTER EN WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN HOOK;;;04C8; 04C8;CYRILLIC SMALL LETTER EN WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN HOOK;;04C7;;04C7 04C9;CYRILLIC CAPITAL LETTER EN WITH TAIL;Lu;0;L;;;;;N;;;;04CA; 04CA;CYRILLIC SMALL LETTER EN WITH TAIL;Ll;0;L;;;;;N;;;04C9;;04C9 04CB;CYRILLIC CAPITAL LETTER KHAKASSIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH LEFT DESCENDER;;;04CC; 04CC;CYRILLIC SMALL LETTER KHAKASSIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH LEFT DESCENDER;;04CB;;04CB 04CD;CYRILLIC CAPITAL LETTER EM WITH TAIL;Lu;0;L;;;;;N;;;;04CE; 04CE;CYRILLIC SMALL LETTER EM WITH TAIL;Ll;0;L;;;;;N;;;04CD;;04CD 04D0;CYRILLIC CAPITAL LETTER A WITH BREVE;Lu;0;L;0410 0306;;;;N;;;;04D1; 04D1;CYRILLIC SMALL LETTER A WITH BREVE;Ll;0;L;0430 0306;;;;N;;;04D0;;04D0 04D2;CYRILLIC CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0410 0308;;;;N;;;;04D3; 04D3;CYRILLIC SMALL LETTER A WITH DIAERESIS;Ll;0;L;0430 0308;;;;N;;;04D2;;04D2 04D4;CYRILLIC CAPITAL LIGATURE A IE;Lu;0;L;;;;;N;;;;04D5; 04D5;CYRILLIC SMALL LIGATURE A IE;Ll;0;L;;;;;N;;;04D4;;04D4 04D6;CYRILLIC CAPITAL LETTER IE WITH BREVE;Lu;0;L;0415 0306;;;;N;;;;04D7; 04D7;CYRILLIC SMALL LETTER IE WITH BREVE;Ll;0;L;0435 0306;;;;N;;;04D6;;04D6 04D8;CYRILLIC CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;04D9; 04D9;CYRILLIC SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;04D8;;04D8 04DA;CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS;Lu;0;L;04D8 0308;;;;N;;;;04DB; 04DB;CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS;Ll;0;L;04D9 0308;;;;N;;;04DA;;04DA 04DC;CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS;Lu;0;L;0416 0308;;;;N;;;;04DD; 04DD;CYRILLIC SMALL LETTER ZHE WITH DIAERESIS;Ll;0;L;0436 0308;;;;N;;;04DC;;04DC 04DE;CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS;Lu;0;L;0417 0308;;;;N;;;;04DF; 04DF;CYRILLIC SMALL LETTER ZE WITH DIAERESIS;Ll;0;L;0437 0308;;;;N;;;04DE;;04DE 04E0;CYRILLIC CAPITAL LETTER ABKHASIAN DZE;Lu;0;L;;;;;N;;;;04E1; 04E1;CYRILLIC SMALL LETTER ABKHASIAN DZE;Ll;0;L;;;;;N;;;04E0;;04E0 04E2;CYRILLIC CAPITAL LETTER I WITH MACRON;Lu;0;L;0418 0304;;;;N;;;;04E3; 04E3;CYRILLIC SMALL LETTER I WITH MACRON;Ll;0;L;0438 0304;;;;N;;;04E2;;04E2 04E4;CYRILLIC CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0418 0308;;;;N;;;;04E5; 04E5;CYRILLIC SMALL LETTER I WITH DIAERESIS;Ll;0;L;0438 0308;;;;N;;;04E4;;04E4 04E6;CYRILLIC CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;041E 0308;;;;N;;;;04E7; 04E7;CYRILLIC SMALL LETTER O WITH DIAERESIS;Ll;0;L;043E 0308;;;;N;;;04E6;;04E6 04E8;CYRILLIC CAPITAL LETTER BARRED O;Lu;0;L;;;;;N;;;;04E9; 04E9;CYRILLIC SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;04E8;;04E8 04EA;CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS;Lu;0;L;04E8 0308;;;;N;;;;04EB; 04EB;CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS;Ll;0;L;04E9 0308;;;;N;;;04EA;;04EA 04EC;CYRILLIC CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;042D 0308;;;;N;;;;04ED; 04ED;CYRILLIC SMALL LETTER E WITH DIAERESIS;Ll;0;L;044D 0308;;;;N;;;04EC;;04EC 04EE;CYRILLIC CAPITAL LETTER U WITH MACRON;Lu;0;L;0423 0304;;;;N;;;;04EF; 04EF;CYRILLIC SMALL LETTER U WITH MACRON;Ll;0;L;0443 0304;;;;N;;;04EE;;04EE 04F0;CYRILLIC CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0423 0308;;;;N;;;;04F1; 04F1;CYRILLIC SMALL LETTER U WITH DIAERESIS;Ll;0;L;0443 0308;;;;N;;;04F0;;04F0 04F2;CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0423 030B;;;;N;;;;04F3; 04F3;CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0443 030B;;;;N;;;04F2;;04F2 04F4;CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS;Lu;0;L;0427 0308;;;;N;;;;04F5; 04F5;CYRILLIC SMALL LETTER CHE WITH DIAERESIS;Ll;0;L;0447 0308;;;;N;;;04F4;;04F4 04F8;CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS;Lu;0;L;042B 0308;;;;N;;;;04F9; 04F9;CYRILLIC SMALL LETTER YERU WITH DIAERESIS;Ll;0;L;044B 0308;;;;N;;;04F8;;04F8 0500;CYRILLIC CAPITAL LETTER KOMI DE;Lu;0;L;;;;;N;;;;0501; 0501;CYRILLIC SMALL LETTER KOMI DE;Ll;0;L;;;;;N;;;0500;;0500 0502;CYRILLIC CAPITAL LETTER KOMI DJE;Lu;0;L;;;;;N;;;;0503; 0503;CYRILLIC SMALL LETTER KOMI DJE;Ll;0;L;;;;;N;;;0502;;0502 0504;CYRILLIC CAPITAL LETTER KOMI ZJE;Lu;0;L;;;;;N;;;;0505; 0505;CYRILLIC SMALL LETTER KOMI ZJE;Ll;0;L;;;;;N;;;0504;;0504 0506;CYRILLIC CAPITAL LETTER KOMI DZJE;Lu;0;L;;;;;N;;;;0507; 0507;CYRILLIC SMALL LETTER KOMI DZJE;Ll;0;L;;;;;N;;;0506;;0506 0508;CYRILLIC CAPITAL LETTER KOMI LJE;Lu;0;L;;;;;N;;;;0509; 0509;CYRILLIC SMALL LETTER KOMI LJE;Ll;0;L;;;;;N;;;0508;;0508 050A;CYRILLIC CAPITAL LETTER KOMI NJE;Lu;0;L;;;;;N;;;;050B; 050B;CYRILLIC SMALL LETTER KOMI NJE;Ll;0;L;;;;;N;;;050A;;050A 050C;CYRILLIC CAPITAL LETTER KOMI SJE;Lu;0;L;;;;;N;;;;050D; 050D;CYRILLIC SMALL LETTER KOMI SJE;Ll;0;L;;;;;N;;;050C;;050C 050E;CYRILLIC CAPITAL LETTER KOMI TJE;Lu;0;L;;;;;N;;;;050F; 050F;CYRILLIC SMALL LETTER KOMI TJE;Ll;0;L;;;;;N;;;050E;;050E 0531;ARMENIAN CAPITAL LETTER AYB;Lu;0;L;;;;;N;;;;0561; 0532;ARMENIAN CAPITAL LETTER BEN;Lu;0;L;;;;;N;;;;0562; 0533;ARMENIAN CAPITAL LETTER GIM;Lu;0;L;;;;;N;;;;0563; 0534;ARMENIAN CAPITAL LETTER DA;Lu;0;L;;;;;N;;;;0564; 0535;ARMENIAN CAPITAL LETTER ECH;Lu;0;L;;;;;N;;;;0565; 0536;ARMENIAN CAPITAL LETTER ZA;Lu;0;L;;;;;N;;;;0566; 0537;ARMENIAN CAPITAL LETTER EH;Lu;0;L;;;;;N;;;;0567; 0538;ARMENIAN CAPITAL LETTER ET;Lu;0;L;;;;;N;;;;0568; 0539;ARMENIAN CAPITAL LETTER TO;Lu;0;L;;;;;N;;;;0569; 053A;ARMENIAN CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;056A; 053B;ARMENIAN CAPITAL LETTER INI;Lu;0;L;;;;;N;;;;056B; 053C;ARMENIAN CAPITAL LETTER LIWN;Lu;0;L;;;;;N;;;;056C; 053D;ARMENIAN CAPITAL LETTER XEH;Lu;0;L;;;;;N;;;;056D; 053E;ARMENIAN CAPITAL LETTER CA;Lu;0;L;;;;;N;;;;056E; 053F;ARMENIAN CAPITAL LETTER KEN;Lu;0;L;;;;;N;;;;056F; 0540;ARMENIAN CAPITAL LETTER HO;Lu;0;L;;;;;N;;;;0570; 0541;ARMENIAN CAPITAL LETTER JA;Lu;0;L;;;;;N;;;;0571; 0542;ARMENIAN CAPITAL LETTER GHAD;Lu;0;L;;;;;N;ARMENIAN CAPITAL LETTER LAD;;;0572; 0543;ARMENIAN CAPITAL LETTER CHEH;Lu;0;L;;;;;N;;;;0573; 0544;ARMENIAN CAPITAL LETTER MEN;Lu;0;L;;;;;N;;;;0574; 0545;ARMENIAN CAPITAL LETTER YI;Lu;0;L;;;;;N;;;;0575; 0546;ARMENIAN CAPITAL LETTER NOW;Lu;0;L;;;;;N;;;;0576; 0547;ARMENIAN CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0577; 0548;ARMENIAN CAPITAL LETTER VO;Lu;0;L;;;;;N;;;;0578; 0549;ARMENIAN CAPITAL LETTER CHA;Lu;0;L;;;;;N;;;;0579; 054A;ARMENIAN CAPITAL LETTER PEH;Lu;0;L;;;;;N;;;;057A; 054B;ARMENIAN CAPITAL LETTER JHEH;Lu;0;L;;;;;N;;;;057B; 054C;ARMENIAN CAPITAL LETTER RA;Lu;0;L;;;;;N;;;;057C; 054D;ARMENIAN CAPITAL LETTER SEH;Lu;0;L;;;;;N;;;;057D; 054E;ARMENIAN CAPITAL LETTER VEW;Lu;0;L;;;;;N;;;;057E; 054F;ARMENIAN CAPITAL LETTER TIWN;Lu;0;L;;;;;N;;;;057F; 0550;ARMENIAN CAPITAL LETTER REH;Lu;0;L;;;;;N;;;;0580; 0551;ARMENIAN CAPITAL LETTER CO;Lu;0;L;;;;;N;;;;0581; 0552;ARMENIAN CAPITAL LETTER YIWN;Lu;0;L;;;;;N;;;;0582; 0553;ARMENIAN CAPITAL LETTER PIWR;Lu;0;L;;;;;N;;;;0583; 0554;ARMENIAN CAPITAL LETTER KEH;Lu;0;L;;;;;N;;;;0584; 0555;ARMENIAN CAPITAL LETTER OH;Lu;0;L;;;;;N;;;;0585; 0556;ARMENIAN CAPITAL LETTER FEH;Lu;0;L;;;;;N;;;;0586; 0559;ARMENIAN MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;; 055A;ARMENIAN APOSTROPHE;Po;0;L;;;;;N;ARMENIAN MODIFIER LETTER RIGHT HALF RING;;;; 055B;ARMENIAN EMPHASIS MARK;Po;0;L;;;;;N;;;;; 055C;ARMENIAN EXCLAMATION MARK;Po;0;L;;;;;N;;;;; 055D;ARMENIAN COMMA;Po;0;L;;;;;N;;;;; 055E;ARMENIAN QUESTION MARK;Po;0;L;;;;;N;;;;; 055F;ARMENIAN ABBREVIATION MARK;Po;0;L;;;;;N;;;;; 0561;ARMENIAN SMALL LETTER AYB;Ll;0;L;;;;;N;;;0531;;0531 0562;ARMENIAN SMALL LETTER BEN;Ll;0;L;;;;;N;;;0532;;0532 0563;ARMENIAN SMALL LETTER GIM;Ll;0;L;;;;;N;;;0533;;0533 0564;ARMENIAN SMALL LETTER DA;Ll;0;L;;;;;N;;;0534;;0534 0565;ARMENIAN SMALL LETTER ECH;Ll;0;L;;;;;N;;;0535;;0535 0566;ARMENIAN SMALL LETTER ZA;Ll;0;L;;;;;N;;;0536;;0536 0567;ARMENIAN SMALL LETTER EH;Ll;0;L;;;;;N;;;0537;;0537 0568;ARMENIAN SMALL LETTER ET;Ll;0;L;;;;;N;;;0538;;0538 0569;ARMENIAN SMALL LETTER TO;Ll;0;L;;;;;N;;;0539;;0539 056A;ARMENIAN SMALL LETTER ZHE;Ll;0;L;;;;;N;;;053A;;053A 056B;ARMENIAN SMALL LETTER INI;Ll;0;L;;;;;N;;;053B;;053B 056C;ARMENIAN SMALL LETTER LIWN;Ll;0;L;;;;;N;;;053C;;053C 056D;ARMENIAN SMALL LETTER XEH;Ll;0;L;;;;;N;;;053D;;053D 056E;ARMENIAN SMALL LETTER CA;Ll;0;L;;;;;N;;;053E;;053E 056F;ARMENIAN SMALL LETTER KEN;Ll;0;L;;;;;N;;;053F;;053F 0570;ARMENIAN SMALL LETTER HO;Ll;0;L;;;;;N;;;0540;;0540 0571;ARMENIAN SMALL LETTER JA;Ll;0;L;;;;;N;;;0541;;0541 0572;ARMENIAN SMALL LETTER GHAD;Ll;0;L;;;;;N;ARMENIAN SMALL LETTER LAD;;0542;;0542 0573;ARMENIAN SMALL LETTER CHEH;Ll;0;L;;;;;N;;;0543;;0543 0574;ARMENIAN SMALL LETTER MEN;Ll;0;L;;;;;N;;;0544;;0544 0575;ARMENIAN SMALL LETTER YI;Ll;0;L;;;;;N;;;0545;;0545 0576;ARMENIAN SMALL LETTER NOW;Ll;0;L;;;;;N;;;0546;;0546 0577;ARMENIAN SMALL LETTER SHA;Ll;0;L;;;;;N;;;0547;;0547 0578;ARMENIAN SMALL LETTER VO;Ll;0;L;;;;;N;;;0548;;0548 0579;ARMENIAN SMALL LETTER CHA;Ll;0;L;;;;;N;;;0549;;0549 057A;ARMENIAN SMALL LETTER PEH;Ll;0;L;;;;;N;;;054A;;054A 057B;ARMENIAN SMALL LETTER JHEH;Ll;0;L;;;;;N;;;054B;;054B 057C;ARMENIAN SMALL LETTER RA;Ll;0;L;;;;;N;;;054C;;054C 057D;ARMENIAN SMALL LETTER SEH;Ll;0;L;;;;;N;;;054D;;054D 057E;ARMENIAN SMALL LETTER VEW;Ll;0;L;;;;;N;;;054E;;054E 057F;ARMENIAN SMALL LETTER TIWN;Ll;0;L;;;;;N;;;054F;;054F 0580;ARMENIAN SMALL LETTER REH;Ll;0;L;;;;;N;;;0550;;0550 0581;ARMENIAN SMALL LETTER CO;Ll;0;L;;;;;N;;;0551;;0551 0582;ARMENIAN SMALL LETTER YIWN;Ll;0;L;;;;;N;;;0552;;0552 0583;ARMENIAN SMALL LETTER PIWR;Ll;0;L;;;;;N;;;0553;;0553 0584;ARMENIAN SMALL LETTER KEH;Ll;0;L;;;;;N;;;0554;;0554 0585;ARMENIAN SMALL LETTER OH;Ll;0;L;;;;;N;;;0555;;0555 0586;ARMENIAN SMALL LETTER FEH;Ll;0;L;;;;;N;;;0556;;0556 0587;ARMENIAN SMALL LIGATURE ECH YIWN;Ll;0;L; 0565 0582;;;;N;;;;; 0589;ARMENIAN FULL STOP;Po;0;L;;;;;N;ARMENIAN PERIOD;;;; 058A;ARMENIAN HYPHEN;Pd;0;ON;;;;;N;;;;; 0591;HEBREW ACCENT ETNAHTA;Mn;220;NSM;;;;;N;;;;; 0592;HEBREW ACCENT SEGOL;Mn;230;NSM;;;;;N;;;;; 0593;HEBREW ACCENT SHALSHELET;Mn;230;NSM;;;;;N;;;;; 0594;HEBREW ACCENT ZAQEF QATAN;Mn;230;NSM;;;;;N;;;;; 0595;HEBREW ACCENT ZAQEF GADOL;Mn;230;NSM;;;;;N;;;;; 0596;HEBREW ACCENT TIPEHA;Mn;220;NSM;;;;;N;;*;;; 0597;HEBREW ACCENT REVIA;Mn;230;NSM;;;;;N;;;;; 0598;HEBREW ACCENT ZARQA;Mn;230;NSM;;;;;N;;*;;; 0599;HEBREW ACCENT PASHTA;Mn;230;NSM;;;;;N;;;;; 059A;HEBREW ACCENT YETIV;Mn;222;NSM;;;;;N;;;;; 059B;HEBREW ACCENT TEVIR;Mn;220;NSM;;;;;N;;;;; 059C;HEBREW ACCENT GERESH;Mn;230;NSM;;;;;N;;;;; 059D;HEBREW ACCENT GERESH MUQDAM;Mn;230;NSM;;;;;N;;;;; 059E;HEBREW ACCENT GERSHAYIM;Mn;230;NSM;;;;;N;;;;; 059F;HEBREW ACCENT QARNEY PARA;Mn;230;NSM;;;;;N;;;;; 05A0;HEBREW ACCENT TELISHA GEDOLA;Mn;230;NSM;;;;;N;;;;; 05A1;HEBREW ACCENT PAZER;Mn;230;NSM;;;;;N;;;;; 05A3;HEBREW ACCENT MUNAH;Mn;220;NSM;;;;;N;;;;; 05A4;HEBREW ACCENT MAHAPAKH;Mn;220;NSM;;;;;N;;;;; 05A5;HEBREW ACCENT MERKHA;Mn;220;NSM;;;;;N;;*;;; 05A6;HEBREW ACCENT MERKHA KEFULA;Mn;220;NSM;;;;;N;;;;; 05A7;HEBREW ACCENT DARGA;Mn;220;NSM;;;;;N;;;;; 05A8;HEBREW ACCENT QADMA;Mn;230;NSM;;;;;N;;*;;; 05A9;HEBREW ACCENT TELISHA QETANA;Mn;230;NSM;;;;;N;;;;; 05AA;HEBREW ACCENT YERAH BEN YOMO;Mn;220;NSM;;;;;N;;*;;; 05AB;HEBREW ACCENT OLE;Mn;230;NSM;;;;;N;;;;; 05AC;HEBREW ACCENT ILUY;Mn;230;NSM;;;;;N;;;;; 05AD;HEBREW ACCENT DEHI;Mn;222;NSM;;;;;N;;;;; 05AE;HEBREW ACCENT ZINOR;Mn;228;NSM;;;;;N;;;;; 05AF;HEBREW MARK MASORA CIRCLE;Mn;230;NSM;;;;;N;;;;; 05B0;HEBREW POINT SHEVA;Mn;10;NSM;;;;;N;;;;; 05B1;HEBREW POINT HATAF SEGOL;Mn;11;NSM;;;;;N;;;;; 05B2;HEBREW POINT HATAF PATAH;Mn;12;NSM;;;;;N;;;;; 05B3;HEBREW POINT HATAF QAMATS;Mn;13;NSM;;;;;N;;;;; 05B4;HEBREW POINT HIRIQ;Mn;14;NSM;;;;;N;;;;; 05B5;HEBREW POINT TSERE;Mn;15;NSM;;;;;N;;;;; 05B6;HEBREW POINT SEGOL;Mn;16;NSM;;;;;N;;;;; 05B7;HEBREW POINT PATAH;Mn;17;NSM;;;;;N;;;;; 05B8;HEBREW POINT QAMATS;Mn;18;NSM;;;;;N;;;;; 05B9;HEBREW POINT HOLAM;Mn;19;NSM;;;;;N;;;;; 05BB;HEBREW POINT QUBUTS;Mn;20;NSM;;;;;N;;;;; 05BC;HEBREW POINT DAGESH OR MAPIQ;Mn;21;NSM;;;;;N;HEBREW POINT DAGESH;or shuruq;;; 05BD;HEBREW POINT METEG;Mn;22;NSM;;;;;N;;*;;; 05BE;HEBREW PUNCTUATION MAQAF;Po;0;R;;;;;N;;;;; 05BF;HEBREW POINT RAFE;Mn;23;NSM;;;;;N;;;;; 05C0;HEBREW PUNCTUATION PASEQ;Po;0;R;;;;;N;HEBREW POINT PASEQ;*;;; 05C1;HEBREW POINT SHIN DOT;Mn;24;NSM;;;;;N;;;;; 05C2;HEBREW POINT SIN DOT;Mn;25;NSM;;;;;N;;;;; 05C3;HEBREW PUNCTUATION SOF PASUQ;Po;0;R;;;;;N;;*;;; 05C4;HEBREW MARK UPPER DOT;Mn;230;NSM;;;;;N;;;;; 05D0;HEBREW LETTER ALEF;Lo;0;R;;;;;N;;;;; 05D1;HEBREW LETTER BET;Lo;0;R;;;;;N;;;;; 05D2;HEBREW LETTER GIMEL;Lo;0;R;;;;;N;;;;; 05D3;HEBREW LETTER DALET;Lo;0;R;;;;;N;;;;; 05D4;HEBREW LETTER HE;Lo;0;R;;;;;N;;;;; 05D5;HEBREW LETTER VAV;Lo;0;R;;;;;N;;;;; 05D6;HEBREW LETTER ZAYIN;Lo;0;R;;;;;N;;;;; 05D7;HEBREW LETTER HET;Lo;0;R;;;;;N;;;;; 05D8;HEBREW LETTER TET;Lo;0;R;;;;;N;;;;; 05D9;HEBREW LETTER YOD;Lo;0;R;;;;;N;;;;; 05DA;HEBREW LETTER FINAL KAF;Lo;0;R;;;;;N;;;;; 05DB;HEBREW LETTER KAF;Lo;0;R;;;;;N;;;;; 05DC;HEBREW LETTER LAMED;Lo;0;R;;;;;N;;;;; 05DD;HEBREW LETTER FINAL MEM;Lo;0;R;;;;;N;;;;; 05DE;HEBREW LETTER MEM;Lo;0;R;;;;;N;;;;; 05DF;HEBREW LETTER FINAL NUN;Lo;0;R;;;;;N;;;;; 05E0;HEBREW LETTER NUN;Lo;0;R;;;;;N;;;;; 05E1;HEBREW LETTER SAMEKH;Lo;0;R;;;;;N;;;;; 05E2;HEBREW LETTER AYIN;Lo;0;R;;;;;N;;;;; 05E3;HEBREW LETTER FINAL PE;Lo;0;R;;;;;N;;;;; 05E4;HEBREW LETTER PE;Lo;0;R;;;;;N;;;;; 05E5;HEBREW LETTER FINAL TSADI;Lo;0;R;;;;;N;;;;; 05E6;HEBREW LETTER TSADI;Lo;0;R;;;;;N;;;;; 05E7;HEBREW LETTER QOF;Lo;0;R;;;;;N;;;;; 05E8;HEBREW LETTER RESH;Lo;0;R;;;;;N;;;;; 05E9;HEBREW LETTER SHIN;Lo;0;R;;;;;N;;;;; 05EA;HEBREW LETTER TAV;Lo;0;R;;;;;N;;;;; 05F0;HEBREW LIGATURE YIDDISH DOUBLE VAV;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE VAV;;;; 05F1;HEBREW LIGATURE YIDDISH VAV YOD;Lo;0;R;;;;;N;HEBREW LETTER VAV YOD;;;; 05F2;HEBREW LIGATURE YIDDISH DOUBLE YOD;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE YOD;;;; 05F3;HEBREW PUNCTUATION GERESH;Po;0;R;;;;;N;;;;; 05F4;HEBREW PUNCTUATION GERSHAYIM;Po;0;R;;;;;N;;;;; 060C;ARABIC COMMA;Po;0;CS;;;;;N;;;;; 061B;ARABIC SEMICOLON;Po;0;AL;;;;;N;;;;; 061F;ARABIC QUESTION MARK;Po;0;AL;;;;;N;;;;; 0621;ARABIC LETTER HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH;;;; 0622;ARABIC LETTER ALEF WITH MADDA ABOVE;Lo;0;AL;0627 0653;;;;N;ARABIC LETTER MADDAH ON ALEF;;;; 0623;ARABIC LETTER ALEF WITH HAMZA ABOVE;Lo;0;AL;0627 0654;;;;N;ARABIC LETTER HAMZAH ON ALEF;;;; 0624;ARABIC LETTER WAW WITH HAMZA ABOVE;Lo;0;AL;0648 0654;;;;N;ARABIC LETTER HAMZAH ON WAW;;;; 0625;ARABIC LETTER ALEF WITH HAMZA BELOW;Lo;0;AL;0627 0655;;;;N;ARABIC LETTER HAMZAH UNDER ALEF;;;; 0626;ARABIC LETTER YEH WITH HAMZA ABOVE;Lo;0;AL;064A 0654;;;;N;ARABIC LETTER HAMZAH ON YA;;;; 0627;ARABIC LETTER ALEF;Lo;0;AL;;;;;N;;;;; 0628;ARABIC LETTER BEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA;;;; 0629;ARABIC LETTER TEH MARBUTA;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH;;;; 062A;ARABIC LETTER TEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA;;;; 062B;ARABIC LETTER THEH;Lo;0;AL;;;;;N;ARABIC LETTER THAA;;;; 062C;ARABIC LETTER JEEM;Lo;0;AL;;;;;N;;;;; 062D;ARABIC LETTER HAH;Lo;0;AL;;;;;N;ARABIC LETTER HAA;;;; 062E;ARABIC LETTER KHAH;Lo;0;AL;;;;;N;ARABIC LETTER KHAA;;;; 062F;ARABIC LETTER DAL;Lo;0;AL;;;;;N;;;;; 0630;ARABIC LETTER THAL;Lo;0;AL;;;;;N;;;;; 0631;ARABIC LETTER REH;Lo;0;AL;;;;;N;ARABIC LETTER RA;;;; 0632;ARABIC LETTER ZAIN;Lo;0;AL;;;;;N;;;;; 0633;ARABIC LETTER SEEN;Lo;0;AL;;;;;N;;;;; 0634;ARABIC LETTER SHEEN;Lo;0;AL;;;;;N;;;;; 0635;ARABIC LETTER SAD;Lo;0;AL;;;;;N;;;;; 0636;ARABIC LETTER DAD;Lo;0;AL;;;;;N;;;;; 0637;ARABIC LETTER TAH;Lo;0;AL;;;;;N;;;;; 0638;ARABIC LETTER ZAH;Lo;0;AL;;;;;N;ARABIC LETTER DHAH;;;; 0639;ARABIC LETTER AIN;Lo;0;AL;;;;;N;;;;; 063A;ARABIC LETTER GHAIN;Lo;0;AL;;;;;N;;;;; 0640;ARABIC TATWEEL;Lm;0;AL;;;;;N;;;;; 0641;ARABIC LETTER FEH;Lo;0;AL;;;;;N;ARABIC LETTER FA;;;; 0642;ARABIC LETTER QAF;Lo;0;AL;;;;;N;;;;; 0643;ARABIC LETTER KAF;Lo;0;AL;;;;;N;ARABIC LETTER CAF;;;; 0644;ARABIC LETTER LAM;Lo;0;AL;;;;;N;;;;; 0645;ARABIC LETTER MEEM;Lo;0;AL;;;;;N;;;;; 0646;ARABIC LETTER NOON;Lo;0;AL;;;;;N;;;;; 0647;ARABIC LETTER HEH;Lo;0;AL;;;;;N;ARABIC LETTER HA;;;; 0648;ARABIC LETTER WAW;Lo;0;AL;;;;;N;;;;; 0649;ARABIC LETTER ALEF MAKSURA;Lo;0;AL;;;;;N;ARABIC LETTER ALEF MAQSURAH;;;; 064A;ARABIC LETTER YEH;Lo;0;AL;;;;;N;ARABIC LETTER YA;;;; 064B;ARABIC FATHATAN;Mn;27;NSM;;;;;N;;;;; 064C;ARABIC DAMMATAN;Mn;28;NSM;;;;;N;;;;; 064D;ARABIC KASRATAN;Mn;29;NSM;;;;;N;;;;; 064E;ARABIC FATHA;Mn;30;NSM;;;;;N;ARABIC FATHAH;;;; 064F;ARABIC DAMMA;Mn;31;NSM;;;;;N;ARABIC DAMMAH;;;; 0650;ARABIC KASRA;Mn;32;NSM;;;;;N;ARABIC KASRAH;;;; 0651;ARABIC SHADDA;Mn;33;NSM;;;;;N;ARABIC SHADDAH;;;; 0652;ARABIC SUKUN;Mn;34;NSM;;;;;N;;;;; 0653;ARABIC MADDAH ABOVE;Mn;230;NSM;;;;;N;;;;; 0654;ARABIC HAMZA ABOVE;Mn;230;NSM;;;;;N;;;;; 0655;ARABIC HAMZA BELOW;Mn;220;NSM;;;;;N;;;;; 0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;; 0661;ARABIC-INDIC DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;; 0662;ARABIC-INDIC DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;; 0663;ARABIC-INDIC DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;; 0664;ARABIC-INDIC DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;; 0665;ARABIC-INDIC DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;; 0666;ARABIC-INDIC DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;; 0667;ARABIC-INDIC DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;; 0668;ARABIC-INDIC DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;; 0669;ARABIC-INDIC DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;; 066A;ARABIC PERCENT SIGN;Po;0;ET;;;;;N;;;;; 066B;ARABIC DECIMAL SEPARATOR;Po;0;AN;;;;;N;;;;; 066C;ARABIC THOUSANDS SEPARATOR;Po;0;AN;;;;;N;;;;; 066D;ARABIC FIVE POINTED STAR;Po;0;AL;;;;;N;;;;; 066E;ARABIC LETTER DOTLESS BEH;Lo;0;AL;;;;;N;;;;; 066F;ARABIC LETTER DOTLESS QAF;Lo;0;AL;;;;;N;;;;; 0670;ARABIC LETTER SUPERSCRIPT ALEF;Mn;35;NSM;;;;;N;ARABIC ALEF ABOVE;;;; 0671;ARABIC LETTER ALEF WASLA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAT WASL ON ALEF;;;; 0672;ARABIC LETTER ALEF WITH WAVY HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH ON ALEF;;;; 0673;ARABIC LETTER ALEF WITH WAVY HAMZA BELOW;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH UNDER ALEF;;;; 0674;ARABIC LETTER HIGH HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HIGH HAMZAH;;;; 0675;ARABIC LETTER HIGH HAMZA ALEF;Lo;0;AL; 0627 0674;;;;N;ARABIC LETTER HIGH HAMZAH ALEF;;;; 0676;ARABIC LETTER HIGH HAMZA WAW;Lo;0;AL; 0648 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW;;;; 0677;ARABIC LETTER U WITH HAMZA ABOVE;Lo;0;AL; 06C7 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW WITH DAMMAH;;;; 0678;ARABIC LETTER HIGH HAMZA YEH;Lo;0;AL; 064A 0674;;;;N;ARABIC LETTER HIGH HAMZAH YA;;;; 0679;ARABIC LETTER TTEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH SMALL TAH;;;; 067A;ARABIC LETTER TTEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH TWO DOTS VERTICAL ABOVE;;;; 067B;ARABIC LETTER BEEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH TWO DOTS VERTICAL BELOW;;;; 067C;ARABIC LETTER TEH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH RING;;;; 067D;ARABIC LETTER TEH WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS ABOVE DOWNWARD;;;; 067E;ARABIC LETTER PEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS BELOW;;;; 067F;ARABIC LETTER TEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH FOUR DOTS ABOVE;;;; 0680;ARABIC LETTER BEHEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH FOUR DOTS BELOW;;;; 0681;ARABIC LETTER HAH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH ON HAA;;;; 0682;ARABIC LETTER HAH WITH TWO DOTS VERTICAL ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH TWO DOTS VERTICAL ABOVE;;;; 0683;ARABIC LETTER NYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS;;;; 0684;ARABIC LETTER DYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS VERTICAL;;;; 0685;ARABIC LETTER HAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH THREE DOTS ABOVE;;;; 0686;ARABIC LETTER TCHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE THREE DOTS DOWNWARD;;;; 0687;ARABIC LETTER TCHEHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE FOUR DOTS;;;; 0688;ARABIC LETTER DDAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH SMALL TAH;;;; 0689;ARABIC LETTER DAL WITH RING;Lo;0;AL;;;;;N;;;;; 068A;ARABIC LETTER DAL WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; 068B;ARABIC LETTER DAL WITH DOT BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;; 068C;ARABIC LETTER DAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS ABOVE;;;; 068D;ARABIC LETTER DDAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS BELOW;;;; 068E;ARABIC LETTER DUL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE;;;; 068F;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARD;;;; 0690;ARABIC LETTER DAL WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;; 0691;ARABIC LETTER RREH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL TAH;;;; 0692;ARABIC LETTER REH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V;;;; 0693;ARABIC LETTER REH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH RING;;;; 0694;ARABIC LETTER REH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW;;;; 0695;ARABIC LETTER REH WITH SMALL V BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V BELOW;;;; 0696;ARABIC LETTER REH WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW AND DOT ABOVE;;;; 0697;ARABIC LETTER REH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH TWO DOTS ABOVE;;;; 0698;ARABIC LETTER JEH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH THREE DOTS ABOVE;;;; 0699;ARABIC LETTER REH WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH FOUR DOTS ABOVE;;;; 069A;ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; 069B;ARABIC LETTER SEEN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; 069C;ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; 069D;ARABIC LETTER SAD WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; 069E;ARABIC LETTER SAD WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; 069F;ARABIC LETTER TAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; 06A0;ARABIC LETTER AIN WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; 06A1;ARABIC LETTER DOTLESS FEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS FA;;;; 06A2;ARABIC LETTER FEH WITH DOT MOVED BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT MOVED BELOW;;;; 06A3;ARABIC LETTER FEH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT BELOW;;;; 06A4;ARABIC LETTER VEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS ABOVE;;;; 06A5;ARABIC LETTER FEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS BELOW;;;; 06A6;ARABIC LETTER PEHEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH FOUR DOTS ABOVE;;;; 06A7;ARABIC LETTER QAF WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; 06A8;ARABIC LETTER QAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; 06A9;ARABIC LETTER KEHEH;Lo;0;AL;;;;;N;ARABIC LETTER OPEN CAF;;;; 06AA;ARABIC LETTER SWASH KAF;Lo;0;AL;;;;;N;ARABIC LETTER SWASH CAF;;;; 06AB;ARABIC LETTER KAF WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH RING;;;; 06AC;ARABIC LETTER KAF WITH DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH DOT ABOVE;;;; 06AD;ARABIC LETTER NG;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS ABOVE;;;; 06AE;ARABIC LETTER KAF WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS BELOW;;;; 06AF;ARABIC LETTER GAF;Lo;0;AL;;;;;N;;*;;; 06B0;ARABIC LETTER GAF WITH RING;Lo;0;AL;;;;;N;;;;; 06B1;ARABIC LETTER NGOEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS ABOVE;;;; 06B2;ARABIC LETTER GAF WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; 06B3;ARABIC LETTER GUEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS VERTICAL BELOW;;;; 06B4;ARABIC LETTER GAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; 06B5;ARABIC LETTER LAM WITH SMALL V;Lo;0;AL;;;;;N;;;;; 06B6;ARABIC LETTER LAM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; 06B7;ARABIC LETTER LAM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; 06B8;ARABIC LETTER LAM WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; 06B9;ARABIC LETTER NOON WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; 06BA;ARABIC LETTER NOON GHUNNA;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON;;;; 06BB;ARABIC LETTER RNOON;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON WITH SMALL TAH;;;; 06BC;ARABIC LETTER NOON WITH RING;Lo;0;AL;;;;;N;;;;; 06BD;ARABIC LETTER NOON WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; 06BE;ARABIC LETTER HEH DOACHASHMEE;Lo;0;AL;;;;;N;ARABIC LETTER KNOTTED HA;;;; 06BF;ARABIC LETTER TCHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; 06C0;ARABIC LETTER HEH WITH YEH ABOVE;Lo;0;AL;06D5 0654;;;;N;ARABIC LETTER HAMZAH ON HA;;;; 06C1;ARABIC LETTER HEH GOAL;Lo;0;AL;;;;;N;ARABIC LETTER HA GOAL;;;; 06C2;ARABIC LETTER HEH GOAL WITH HAMZA ABOVE;Lo;0;AL;06C1 0654;;;;N;ARABIC LETTER HAMZAH ON HA GOAL;;;; 06C3;ARABIC LETTER TEH MARBUTA GOAL;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH GOAL;;;; 06C4;ARABIC LETTER WAW WITH RING;Lo;0;AL;;;;;N;;;;; 06C5;ARABIC LETTER KIRGHIZ OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH BAR;;;; 06C6;ARABIC LETTER OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH SMALL V;;;; 06C7;ARABIC LETTER U;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH DAMMAH;;;; 06C8;ARABIC LETTER YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH ALEF ABOVE;;;; 06C9;ARABIC LETTER KIRGHIZ YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH INVERTED SMALL V;;;; 06CA;ARABIC LETTER WAW WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; 06CB;ARABIC LETTER VE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH THREE DOTS ABOVE;;;; 06CC;ARABIC LETTER FARSI YEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS YA;;;; 06CD;ARABIC LETTER YEH WITH TAIL;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TAIL;;;; 06CE;ARABIC LETTER YEH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH SMALL V;;;; 06CF;ARABIC LETTER WAW WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; 06D0;ARABIC LETTER E;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TWO DOTS VERTICAL BELOW;*;;; 06D1;ARABIC LETTER YEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH THREE DOTS BELOW;;;; 06D2;ARABIC LETTER YEH BARREE;Lo;0;AL;;;;;N;ARABIC LETTER YA BARREE;;;; 06D3;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE;Lo;0;AL;06D2 0654;;;;N;ARABIC LETTER HAMZAH ON YA BARREE;;;; 06D4;ARABIC FULL STOP;Po;0;AL;;;;;N;ARABIC PERIOD;;;; 06D5;ARABIC LETTER AE;Lo;0;AL;;;;;N;;;;; 06D6;ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;; 06D7;ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;; 06D8;ARABIC SMALL HIGH MEEM INITIAL FORM;Mn;230;NSM;;;;;N;;;;; 06D9;ARABIC SMALL HIGH LAM ALEF;Mn;230;NSM;;;;;N;;;;; 06DA;ARABIC SMALL HIGH JEEM;Mn;230;NSM;;;;;N;;;;; 06DB;ARABIC SMALL HIGH THREE DOTS;Mn;230;NSM;;;;;N;;;;; 06DC;ARABIC SMALL HIGH SEEN;Mn;230;NSM;;;;;N;;;;; 06DD;ARABIC END OF AYAH;Cf;0;AL;;;;;N;;;;; 06DE;ARABIC START OF RUB EL HIZB;Me;0;NSM;;;;;N;;;;; 06DF;ARABIC SMALL HIGH ROUNDED ZERO;Mn;230;NSM;;;;;N;;;;; 06E0;ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO;Mn;230;NSM;;;;;N;;;;; 06E1;ARABIC SMALL HIGH DOTLESS HEAD OF KHAH;Mn;230;NSM;;;;;N;;;;; 06E2;ARABIC SMALL HIGH MEEM ISOLATED FORM;Mn;230;NSM;;;;;N;;;;; 06E3;ARABIC SMALL LOW SEEN;Mn;220;NSM;;;;;N;;;;; 06E4;ARABIC SMALL HIGH MADDA;Mn;230;NSM;;;;;N;;;;; 06E5;ARABIC SMALL WAW;Lm;0;AL;;;;;N;;;;; 06E6;ARABIC SMALL YEH;Lm;0;AL;;;;;N;;;;; 06E7;ARABIC SMALL HIGH YEH;Mn;230;NSM;;;;;N;;;;; 06E8;ARABIC SMALL HIGH NOON;Mn;230;NSM;;;;;N;;;;; 06E9;ARABIC PLACE OF SAJDAH;So;0;ON;;;;;N;;;;; 06EA;ARABIC EMPTY CENTRE LOW STOP;Mn;220;NSM;;;;;N;;;;; 06EB;ARABIC EMPTY CENTRE HIGH STOP;Mn;230;NSM;;;;;N;;;;; 06EC;ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE;Mn;230;NSM;;;;;N;;;;; 06ED;ARABIC SMALL LOW MEEM;Mn;220;NSM;;;;;N;;;;; 06F0;EXTENDED ARABIC-INDIC DIGIT ZERO;Nd;0;EN;;0;0;0;N;EASTERN ARABIC-INDIC DIGIT ZERO;;;; 06F1;EXTENDED ARABIC-INDIC DIGIT ONE;Nd;0;EN;;1;1;1;N;EASTERN ARABIC-INDIC DIGIT ONE;;;; 06F2;EXTENDED ARABIC-INDIC DIGIT TWO;Nd;0;EN;;2;2;2;N;EASTERN ARABIC-INDIC DIGIT TWO;;;; 06F3;EXTENDED ARABIC-INDIC DIGIT THREE;Nd;0;EN;;3;3;3;N;EASTERN ARABIC-INDIC DIGIT THREE;;;; 06F4;EXTENDED ARABIC-INDIC DIGIT FOUR;Nd;0;EN;;4;4;4;N;EASTERN ARABIC-INDIC DIGIT FOUR;;;; 06F5;EXTENDED ARABIC-INDIC DIGIT FIVE;Nd;0;EN;;5;5;5;N;EASTERN ARABIC-INDIC DIGIT FIVE;;;; 06F6;EXTENDED ARABIC-INDIC DIGIT SIX;Nd;0;EN;;6;6;6;N;EASTERN ARABIC-INDIC DIGIT SIX;;;; 06F7;EXTENDED ARABIC-INDIC DIGIT SEVEN;Nd;0;EN;;7;7;7;N;EASTERN ARABIC-INDIC DIGIT SEVEN;;;; 06F8;EXTENDED ARABIC-INDIC DIGIT EIGHT;Nd;0;EN;;8;8;8;N;EASTERN ARABIC-INDIC DIGIT EIGHT;;;; 06F9;EXTENDED ARABIC-INDIC DIGIT NINE;Nd;0;EN;;9;9;9;N;EASTERN ARABIC-INDIC DIGIT NINE;;;; 06FA;ARABIC LETTER SHEEN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; 06FB;ARABIC LETTER DAD WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; 06FC;ARABIC LETTER GHAIN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; 06FD;ARABIC SIGN SINDHI AMPERSAND;So;0;AL;;;;;N;;;;; 06FE;ARABIC SIGN SINDHI POSTPOSITION MEN;So;0;AL;;;;;N;;;;; 0700;SYRIAC END OF PARAGRAPH;Po;0;AL;;;;;N;;;;; 0701;SYRIAC SUPRALINEAR FULL STOP;Po;0;AL;;;;;N;;;;; 0702;SYRIAC SUBLINEAR FULL STOP;Po;0;AL;;;;;N;;;;; 0703;SYRIAC SUPRALINEAR COLON;Po;0;AL;;;;;N;;;;; 0704;SYRIAC SUBLINEAR COLON;Po;0;AL;;;;;N;;;;; 0705;SYRIAC HORIZONTAL COLON;Po;0;AL;;;;;N;;;;; 0706;SYRIAC COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;; 0707;SYRIAC COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;; 0708;SYRIAC SUPRALINEAR COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;; 0709;SYRIAC SUBLINEAR COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;; 070A;SYRIAC CONTRACTION;Po;0;AL;;;;;N;;;;; 070B;SYRIAC HARKLEAN OBELUS;Po;0;AL;;;;;N;;;;; 070C;SYRIAC HARKLEAN METOBELUS;Po;0;AL;;;;;N;;;;; 070D;SYRIAC HARKLEAN ASTERISCUS;Po;0;AL;;;;;N;;;;; 070F;SYRIAC ABBREVIATION MARK;Cf;0;BN;;;;;N;;;;; 0710;SYRIAC LETTER ALAPH;Lo;0;AL;;;;;N;;;;; 0711;SYRIAC LETTER SUPERSCRIPT ALAPH;Mn;36;NSM;;;;;N;;;;; 0712;SYRIAC LETTER BETH;Lo;0;AL;;;;;N;;;;; 0713;SYRIAC LETTER GAMAL;Lo;0;AL;;;;;N;;;;; 0714;SYRIAC LETTER GAMAL GARSHUNI;Lo;0;AL;;;;;N;;;;; 0715;SYRIAC LETTER DALATH;Lo;0;AL;;;;;N;;;;; 0716;SYRIAC LETTER DOTLESS DALATH RISH;Lo;0;AL;;;;;N;;;;; 0717;SYRIAC LETTER HE;Lo;0;AL;;;;;N;;;;; 0718;SYRIAC LETTER WAW;Lo;0;AL;;;;;N;;;;; 0719;SYRIAC LETTER ZAIN;Lo;0;AL;;;;;N;;;;; 071A;SYRIAC LETTER HETH;Lo;0;AL;;;;;N;;;;; 071B;SYRIAC LETTER TETH;Lo;0;AL;;;;;N;;;;; 071C;SYRIAC LETTER TETH GARSHUNI;Lo;0;AL;;;;;N;;;;; 071D;SYRIAC LETTER YUDH;Lo;0;AL;;;;;N;;;;; 071E;SYRIAC LETTER YUDH HE;Lo;0;AL;;;;;N;;;;; 071F;SYRIAC LETTER KAPH;Lo;0;AL;;;;;N;;;;; 0720;SYRIAC LETTER LAMADH;Lo;0;AL;;;;;N;;;;; 0721;SYRIAC LETTER MIM;Lo;0;AL;;;;;N;;;;; 0722;SYRIAC LETTER NUN;Lo;0;AL;;;;;N;;;;; 0723;SYRIAC LETTER SEMKATH;Lo;0;AL;;;;;N;;;;; 0724;SYRIAC LETTER FINAL SEMKATH;Lo;0;AL;;;;;N;;;;; 0725;SYRIAC LETTER E;Lo;0;AL;;;;;N;;;;; 0726;SYRIAC LETTER PE;Lo;0;AL;;;;;N;;;;; 0727;SYRIAC LETTER REVERSED PE;Lo;0;AL;;;;;N;;;;; 0728;SYRIAC LETTER SADHE;Lo;0;AL;;;;;N;;;;; 0729;SYRIAC LETTER QAPH;Lo;0;AL;;;;;N;;;;; 072A;SYRIAC LETTER RISH;Lo;0;AL;;;;;N;;;;; 072B;SYRIAC LETTER SHIN;Lo;0;AL;;;;;N;;;;; 072C;SYRIAC LETTER TAW;Lo;0;AL;;;;;N;;;;; 0730;SYRIAC PTHAHA ABOVE;Mn;230;NSM;;;;;N;;;;; 0731;SYRIAC PTHAHA BELOW;Mn;220;NSM;;;;;N;;;;; 0732;SYRIAC PTHAHA DOTTED;Mn;230;NSM;;;;;N;;;;; 0733;SYRIAC ZQAPHA ABOVE;Mn;230;NSM;;;;;N;;;;; 0734;SYRIAC ZQAPHA BELOW;Mn;220;NSM;;;;;N;;;;; 0735;SYRIAC ZQAPHA DOTTED;Mn;230;NSM;;;;;N;;;;; 0736;SYRIAC RBASA ABOVE;Mn;230;NSM;;;;;N;;;;; 0737;SYRIAC RBASA BELOW;Mn;220;NSM;;;;;N;;;;; 0738;SYRIAC DOTTED ZLAMA HORIZONTAL;Mn;220;NSM;;;;;N;;;;; 0739;SYRIAC DOTTED ZLAMA ANGULAR;Mn;220;NSM;;;;;N;;;;; 073A;SYRIAC HBASA ABOVE;Mn;230;NSM;;;;;N;;;;; 073B;SYRIAC HBASA BELOW;Mn;220;NSM;;;;;N;;;;; 073C;SYRIAC HBASA-ESASA DOTTED;Mn;220;NSM;;;;;N;;;;; 073D;SYRIAC ESASA ABOVE;Mn;230;NSM;;;;;N;;;;; 073E;SYRIAC ESASA BELOW;Mn;220;NSM;;;;;N;;;;; 073F;SYRIAC RWAHA;Mn;230;NSM;;;;;N;;;;; 0740;SYRIAC FEMININE DOT;Mn;230;NSM;;;;;N;;;;; 0741;SYRIAC QUSHSHAYA;Mn;230;NSM;;;;;N;;;;; 0742;SYRIAC RUKKAKHA;Mn;220;NSM;;;;;N;;;;; 0743;SYRIAC TWO VERTICAL DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; 0744;SYRIAC TWO VERTICAL DOTS BELOW;Mn;220;NSM;;;;;N;;;;; 0745;SYRIAC THREE DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; 0746;SYRIAC THREE DOTS BELOW;Mn;220;NSM;;;;;N;;;;; 0747;SYRIAC OBLIQUE LINE ABOVE;Mn;230;NSM;;;;;N;;;;; 0748;SYRIAC OBLIQUE LINE BELOW;Mn;220;NSM;;;;;N;;;;; 0749;SYRIAC MUSIC;Mn;230;NSM;;;;;N;;;;; 074A;SYRIAC BARREKH;Mn;230;NSM;;;;;N;;;;; 0780;THAANA LETTER HAA;Lo;0;AL;;;;;N;;;;; 0781;THAANA LETTER SHAVIYANI;Lo;0;AL;;;;;N;;;;; 0782;THAANA LETTER NOONU;Lo;0;AL;;;;;N;;;;; 0783;THAANA LETTER RAA;Lo;0;AL;;;;;N;;;;; 0784;THAANA LETTER BAA;Lo;0;AL;;;;;N;;;;; 0785;THAANA LETTER LHAVIYANI;Lo;0;AL;;;;;N;;;;; 0786;THAANA LETTER KAAFU;Lo;0;AL;;;;;N;;;;; 0787;THAANA LETTER ALIFU;Lo;0;AL;;;;;N;;;;; 0788;THAANA LETTER VAAVU;Lo;0;AL;;;;;N;;;;; 0789;THAANA LETTER MEEMU;Lo;0;AL;;;;;N;;;;; 078A;THAANA LETTER FAAFU;Lo;0;AL;;;;;N;;;;; 078B;THAANA LETTER DHAALU;Lo;0;AL;;;;;N;;;;; 078C;THAANA LETTER THAA;Lo;0;AL;;;;;N;;;;; 078D;THAANA LETTER LAAMU;Lo;0;AL;;;;;N;;;;; 078E;THAANA LETTER GAAFU;Lo;0;AL;;;;;N;;;;; 078F;THAANA LETTER GNAVIYANI;Lo;0;AL;;;;;N;;;;; 0790;THAANA LETTER SEENU;Lo;0;AL;;;;;N;;;;; 0791;THAANA LETTER DAVIYANI;Lo;0;AL;;;;;N;;;;; 0792;THAANA LETTER ZAVIYANI;Lo;0;AL;;;;;N;;;;; 0793;THAANA LETTER TAVIYANI;Lo;0;AL;;;;;N;;;;; 0794;THAANA LETTER YAA;Lo;0;AL;;;;;N;;;;; 0795;THAANA LETTER PAVIYANI;Lo;0;AL;;;;;N;;;;; 0796;THAANA LETTER JAVIYANI;Lo;0;AL;;;;;N;;;;; 0797;THAANA LETTER CHAVIYANI;Lo;0;AL;;;;;N;;;;; 0798;THAANA LETTER TTAA;Lo;0;AL;;;;;N;;;;; 0799;THAANA LETTER HHAA;Lo;0;AL;;;;;N;;;;; 079A;THAANA LETTER KHAA;Lo;0;AL;;;;;N;;;;; 079B;THAANA LETTER THAALU;Lo;0;AL;;;;;N;;;;; 079C;THAANA LETTER ZAA;Lo;0;AL;;;;;N;;;;; 079D;THAANA LETTER SHEENU;Lo;0;AL;;;;;N;;;;; 079E;THAANA LETTER SAADHU;Lo;0;AL;;;;;N;;;;; 079F;THAANA LETTER DAADHU;Lo;0;AL;;;;;N;;;;; 07A0;THAANA LETTER TO;Lo;0;AL;;;;;N;;;;; 07A1;THAANA LETTER ZO;Lo;0;AL;;;;;N;;;;; 07A2;THAANA LETTER AINU;Lo;0;AL;;;;;N;;;;; 07A3;THAANA LETTER GHAINU;Lo;0;AL;;;;;N;;;;; 07A4;THAANA LETTER QAAFU;Lo;0;AL;;;;;N;;;;; 07A5;THAANA LETTER WAAVU;Lo;0;AL;;;;;N;;;;; 07A6;THAANA ABAFILI;Mn;0;NSM;;;;;N;;;;; 07A7;THAANA AABAAFILI;Mn;0;NSM;;;;;N;;;;; 07A8;THAANA IBIFILI;Mn;0;NSM;;;;;N;;;;; 07A9;THAANA EEBEEFILI;Mn;0;NSM;;;;;N;;;;; 07AA;THAANA UBUFILI;Mn;0;NSM;;;;;N;;;;; 07AB;THAANA OOBOOFILI;Mn;0;NSM;;;;;N;;;;; 07AC;THAANA EBEFILI;Mn;0;NSM;;;;;N;;;;; 07AD;THAANA EYBEYFILI;Mn;0;NSM;;;;;N;;;;; 07AE;THAANA OBOFILI;Mn;0;NSM;;;;;N;;;;; 07AF;THAANA OABOAFILI;Mn;0;NSM;;;;;N;;;;; 07B0;THAANA SUKUN;Mn;0;NSM;;;;;N;;;;; 07B1;THAANA LETTER NAA;Lo;0;AL;;;;;N;;;;; 0901;DEVANAGARI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0902;DEVANAGARI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; 0903;DEVANAGARI SIGN VISARGA;Mc;0;L;;;;;N;;;;; 0905;DEVANAGARI LETTER A;Lo;0;L;;;;;N;;;;; 0906;DEVANAGARI LETTER AA;Lo;0;L;;;;;N;;;;; 0907;DEVANAGARI LETTER I;Lo;0;L;;;;;N;;;;; 0908;DEVANAGARI LETTER II;Lo;0;L;;;;;N;;;;; 0909;DEVANAGARI LETTER U;Lo;0;L;;;;;N;;;;; 090A;DEVANAGARI LETTER UU;Lo;0;L;;;;;N;;;;; 090B;DEVANAGARI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; 090C;DEVANAGARI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; 090D;DEVANAGARI LETTER CANDRA E;Lo;0;L;;;;;N;;;;; 090E;DEVANAGARI LETTER SHORT E;Lo;0;L;;;;;N;;;;; 090F;DEVANAGARI LETTER E;Lo;0;L;;;;;N;;;;; 0910;DEVANAGARI LETTER AI;Lo;0;L;;;;;N;;;;; 0911;DEVANAGARI LETTER CANDRA O;Lo;0;L;;;;;N;;;;; 0912;DEVANAGARI LETTER SHORT O;Lo;0;L;;;;;N;;;;; 0913;DEVANAGARI LETTER O;Lo;0;L;;;;;N;;;;; 0914;DEVANAGARI LETTER AU;Lo;0;L;;;;;N;;;;; 0915;DEVANAGARI LETTER KA;Lo;0;L;;;;;N;;;;; 0916;DEVANAGARI LETTER KHA;Lo;0;L;;;;;N;;;;; 0917;DEVANAGARI LETTER GA;Lo;0;L;;;;;N;;;;; 0918;DEVANAGARI LETTER GHA;Lo;0;L;;;;;N;;;;; 0919;DEVANAGARI LETTER NGA;Lo;0;L;;;;;N;;;;; 091A;DEVANAGARI LETTER CA;Lo;0;L;;;;;N;;;;; 091B;DEVANAGARI LETTER CHA;Lo;0;L;;;;;N;;;;; 091C;DEVANAGARI LETTER JA;Lo;0;L;;;;;N;;;;; 091D;DEVANAGARI LETTER JHA;Lo;0;L;;;;;N;;;;; 091E;DEVANAGARI LETTER NYA;Lo;0;L;;;;;N;;;;; 091F;DEVANAGARI LETTER TTA;Lo;0;L;;;;;N;;;;; 0920;DEVANAGARI LETTER TTHA;Lo;0;L;;;;;N;;;;; 0921;DEVANAGARI LETTER DDA;Lo;0;L;;;;;N;;;;; 0922;DEVANAGARI LETTER DDHA;Lo;0;L;;;;;N;;;;; 0923;DEVANAGARI LETTER NNA;Lo;0;L;;;;;N;;;;; 0924;DEVANAGARI LETTER TA;Lo;0;L;;;;;N;;;;; 0925;DEVANAGARI LETTER THA;Lo;0;L;;;;;N;;;;; 0926;DEVANAGARI LETTER DA;Lo;0;L;;;;;N;;;;; 0927;DEVANAGARI LETTER DHA;Lo;0;L;;;;;N;;;;; 0928;DEVANAGARI LETTER NA;Lo;0;L;;;;;N;;;;; 0929;DEVANAGARI LETTER NNNA;Lo;0;L;0928 093C;;;;N;;;;; 092A;DEVANAGARI LETTER PA;Lo;0;L;;;;;N;;;;; 092B;DEVANAGARI LETTER PHA;Lo;0;L;;;;;N;;;;; 092C;DEVANAGARI LETTER BA;Lo;0;L;;;;;N;;;;; 092D;DEVANAGARI LETTER BHA;Lo;0;L;;;;;N;;;;; 092E;DEVANAGARI LETTER MA;Lo;0;L;;;;;N;;;;; 092F;DEVANAGARI LETTER YA;Lo;0;L;;;;;N;;;;; 0930;DEVANAGARI LETTER RA;Lo;0;L;;;;;N;;;;; 0931;DEVANAGARI LETTER RRA;Lo;0;L;0930 093C;;;;N;;;;; 0932;DEVANAGARI LETTER LA;Lo;0;L;;;;;N;;;;; 0933;DEVANAGARI LETTER LLA;Lo;0;L;;;;;N;;;;; 0934;DEVANAGARI LETTER LLLA;Lo;0;L;0933 093C;;;;N;;;;; 0935;DEVANAGARI LETTER VA;Lo;0;L;;;;;N;;;;; 0936;DEVANAGARI LETTER SHA;Lo;0;L;;;;;N;;;;; 0937;DEVANAGARI LETTER SSA;Lo;0;L;;;;;N;;;;; 0938;DEVANAGARI LETTER SA;Lo;0;L;;;;;N;;;;; 0939;DEVANAGARI LETTER HA;Lo;0;L;;;;;N;;;;; 093C;DEVANAGARI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; 093D;DEVANAGARI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; 093E;DEVANAGARI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; 093F;DEVANAGARI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; 0940;DEVANAGARI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; 0941;DEVANAGARI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; 0942;DEVANAGARI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; 0943;DEVANAGARI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; 0944;DEVANAGARI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; 0945;DEVANAGARI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;; 0946;DEVANAGARI VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;; 0947;DEVANAGARI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; 0948;DEVANAGARI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; 0949;DEVANAGARI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;; 094A;DEVANAGARI VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;; 094B;DEVANAGARI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; 094C;DEVANAGARI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; 094D;DEVANAGARI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 0950;DEVANAGARI OM;Lo;0;L;;;;;N;;;;; 0951;DEVANAGARI STRESS SIGN UDATTA;Mn;230;NSM;;;;;N;;;;; 0952;DEVANAGARI STRESS SIGN ANUDATTA;Mn;220;NSM;;;;;N;;;;; 0953;DEVANAGARI GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;; 0954;DEVANAGARI ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;; 0958;DEVANAGARI LETTER QA;Lo;0;L;0915 093C;;;;N;;;;; 0959;DEVANAGARI LETTER KHHA;Lo;0;L;0916 093C;;;;N;;;;; 095A;DEVANAGARI LETTER GHHA;Lo;0;L;0917 093C;;;;N;;;;; 095B;DEVANAGARI LETTER ZA;Lo;0;L;091C 093C;;;;N;;;;; 095C;DEVANAGARI LETTER DDDHA;Lo;0;L;0921 093C;;;;N;;;;; 095D;DEVANAGARI LETTER RHA;Lo;0;L;0922 093C;;;;N;;;;; 095E;DEVANAGARI LETTER FA;Lo;0;L;092B 093C;;;;N;;;;; 095F;DEVANAGARI LETTER YYA;Lo;0;L;092F 093C;;;;N;;;;; 0960;DEVANAGARI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0961;DEVANAGARI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; 0962;DEVANAGARI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; 0963;DEVANAGARI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; 0964;DEVANAGARI DANDA;Po;0;L;;;;;N;;;;; 0965;DEVANAGARI DOUBLE DANDA;Po;0;L;;;;;N;;;;; 0966;DEVANAGARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0967;DEVANAGARI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0968;DEVANAGARI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 0969;DEVANAGARI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; 096A;DEVANAGARI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; 096B;DEVANAGARI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; 096C;DEVANAGARI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; 096D;DEVANAGARI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 096E;DEVANAGARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 096F;DEVANAGARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0970;DEVANAGARI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; 0981;BENGALI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0982;BENGALI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0983;BENGALI SIGN VISARGA;Mc;0;L;;;;;N;;;;; 0985;BENGALI LETTER A;Lo;0;L;;;;;N;;;;; 0986;BENGALI LETTER AA;Lo;0;L;;;;;N;;;;; 0987;BENGALI LETTER I;Lo;0;L;;;;;N;;;;; 0988;BENGALI LETTER II;Lo;0;L;;;;;N;;;;; 0989;BENGALI LETTER U;Lo;0;L;;;;;N;;;;; 098A;BENGALI LETTER UU;Lo;0;L;;;;;N;;;;; 098B;BENGALI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; 098C;BENGALI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; 098F;BENGALI LETTER E;Lo;0;L;;;;;N;;;;; 0990;BENGALI LETTER AI;Lo;0;L;;;;;N;;;;; 0993;BENGALI LETTER O;Lo;0;L;;;;;N;;;;; 0994;BENGALI LETTER AU;Lo;0;L;;;;;N;;;;; 0995;BENGALI LETTER KA;Lo;0;L;;;;;N;;;;; 0996;BENGALI LETTER KHA;Lo;0;L;;;;;N;;;;; 0997;BENGALI LETTER GA;Lo;0;L;;;;;N;;;;; 0998;BENGALI LETTER GHA;Lo;0;L;;;;;N;;;;; 0999;BENGALI LETTER NGA;Lo;0;L;;;;;N;;;;; 099A;BENGALI LETTER CA;Lo;0;L;;;;;N;;;;; 099B;BENGALI LETTER CHA;Lo;0;L;;;;;N;;;;; 099C;BENGALI LETTER JA;Lo;0;L;;;;;N;;;;; 099D;BENGALI LETTER JHA;Lo;0;L;;;;;N;;;;; 099E;BENGALI LETTER NYA;Lo;0;L;;;;;N;;;;; 099F;BENGALI LETTER TTA;Lo;0;L;;;;;N;;;;; 09A0;BENGALI LETTER TTHA;Lo;0;L;;;;;N;;;;; 09A1;BENGALI LETTER DDA;Lo;0;L;;;;;N;;;;; 09A2;BENGALI LETTER DDHA;Lo;0;L;;;;;N;;;;; 09A3;BENGALI LETTER NNA;Lo;0;L;;;;;N;;;;; 09A4;BENGALI LETTER TA;Lo;0;L;;;;;N;;;;; 09A5;BENGALI LETTER THA;Lo;0;L;;;;;N;;;;; 09A6;BENGALI LETTER DA;Lo;0;L;;;;;N;;;;; 09A7;BENGALI LETTER DHA;Lo;0;L;;;;;N;;;;; 09A8;BENGALI LETTER NA;Lo;0;L;;;;;N;;;;; 09AA;BENGALI LETTER PA;Lo;0;L;;;;;N;;;;; 09AB;BENGALI LETTER PHA;Lo;0;L;;;;;N;;;;; 09AC;BENGALI LETTER BA;Lo;0;L;;;;;N;;;;; 09AD;BENGALI LETTER BHA;Lo;0;L;;;;;N;;;;; 09AE;BENGALI LETTER MA;Lo;0;L;;;;;N;;;;; 09AF;BENGALI LETTER YA;Lo;0;L;;;;;N;;;;; 09B0;BENGALI LETTER RA;Lo;0;L;;;;;N;;;;; 09B2;BENGALI LETTER LA;Lo;0;L;;;;;N;;;;; 09B6;BENGALI LETTER SHA;Lo;0;L;;;;;N;;;;; 09B7;BENGALI LETTER SSA;Lo;0;L;;;;;N;;;;; 09B8;BENGALI LETTER SA;Lo;0;L;;;;;N;;;;; 09B9;BENGALI LETTER HA;Lo;0;L;;;;;N;;;;; 09BC;BENGALI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; 09BE;BENGALI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; 09BF;BENGALI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; 09C0;BENGALI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; 09C1;BENGALI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; 09C2;BENGALI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; 09C3;BENGALI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; 09C4;BENGALI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; 09C7;BENGALI VOWEL SIGN E;Mc;0;L;;;;;N;;;;; 09C8;BENGALI VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; 09CB;BENGALI VOWEL SIGN O;Mc;0;L;09C7 09BE;;;;N;;;;; 09CC;BENGALI VOWEL SIGN AU;Mc;0;L;09C7 09D7;;;;N;;;;; 09CD;BENGALI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 09D7;BENGALI AU LENGTH MARK;Mc;0;L;;;;;N;;;;; 09DC;BENGALI LETTER RRA;Lo;0;L;09A1 09BC;;;;N;;;;; 09DD;BENGALI LETTER RHA;Lo;0;L;09A2 09BC;;;;N;;;;; 09DF;BENGALI LETTER YYA;Lo;0;L;09AF 09BC;;;;N;;;;; 09E0;BENGALI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 09E1;BENGALI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; 09E2;BENGALI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; 09E3;BENGALI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; 09E6;BENGALI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 09E7;BENGALI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 09E8;BENGALI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 09E9;BENGALI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; 09EA;BENGALI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; 09EB;BENGALI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; 09EC;BENGALI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; 09ED;BENGALI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 09EE;BENGALI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 09EF;BENGALI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 09F0;BENGALI LETTER RA WITH MIDDLE DIAGONAL;Lo;0;L;;;;;N;;Assamese;;; 09F1;BENGALI LETTER RA WITH LOWER DIAGONAL;Lo;0;L;;;;;N;BENGALI LETTER VA WITH LOWER DIAGONAL;Assamese;;; 09F2;BENGALI RUPEE MARK;Sc;0;ET;;;;;N;;;;; 09F3;BENGALI RUPEE SIGN;Sc;0;ET;;;;;N;;;;; 09F4;BENGALI CURRENCY NUMERATOR ONE;No;0;L;;;;1;N;;;;; 09F5;BENGALI CURRENCY NUMERATOR TWO;No;0;L;;;;2;N;;;;; 09F6;BENGALI CURRENCY NUMERATOR THREE;No;0;L;;;;3;N;;;;; 09F7;BENGALI CURRENCY NUMERATOR FOUR;No;0;L;;;;4;N;;;;; 09F8;BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR;No;0;L;;;;;N;;;;; 09F9;BENGALI CURRENCY DENOMINATOR SIXTEEN;No;0;L;;;;16;N;;;;; 09FA;BENGALI ISSHAR;So;0;L;;;;;N;;;;; 0A02;GURMUKHI SIGN BINDI;Mn;0;NSM;;;;;N;;;;; 0A05;GURMUKHI LETTER A;Lo;0;L;;;;;N;;;;; 0A06;GURMUKHI LETTER AA;Lo;0;L;;;;;N;;;;; 0A07;GURMUKHI LETTER I;Lo;0;L;;;;;N;;;;; 0A08;GURMUKHI LETTER II;Lo;0;L;;;;;N;;;;; 0A09;GURMUKHI LETTER U;Lo;0;L;;;;;N;;;;; 0A0A;GURMUKHI LETTER UU;Lo;0;L;;;;;N;;;;; 0A0F;GURMUKHI LETTER EE;Lo;0;L;;;;;N;;;;; 0A10;GURMUKHI LETTER AI;Lo;0;L;;;;;N;;;;; 0A13;GURMUKHI LETTER OO;Lo;0;L;;;;;N;;;;; 0A14;GURMUKHI LETTER AU;Lo;0;L;;;;;N;;;;; 0A15;GURMUKHI LETTER KA;Lo;0;L;;;;;N;;;;; 0A16;GURMUKHI LETTER KHA;Lo;0;L;;;;;N;;;;; 0A17;GURMUKHI LETTER GA;Lo;0;L;;;;;N;;;;; 0A18;GURMUKHI LETTER GHA;Lo;0;L;;;;;N;;;;; 0A19;GURMUKHI LETTER NGA;Lo;0;L;;;;;N;;;;; 0A1A;GURMUKHI LETTER CA;Lo;0;L;;;;;N;;;;; 0A1B;GURMUKHI LETTER CHA;Lo;0;L;;;;;N;;;;; 0A1C;GURMUKHI LETTER JA;Lo;0;L;;;;;N;;;;; 0A1D;GURMUKHI LETTER JHA;Lo;0;L;;;;;N;;;;; 0A1E;GURMUKHI LETTER NYA;Lo;0;L;;;;;N;;;;; 0A1F;GURMUKHI LETTER TTA;Lo;0;L;;;;;N;;;;; 0A20;GURMUKHI LETTER TTHA;Lo;0;L;;;;;N;;;;; 0A21;GURMUKHI LETTER DDA;Lo;0;L;;;;;N;;;;; 0A22;GURMUKHI LETTER DDHA;Lo;0;L;;;;;N;;;;; 0A23;GURMUKHI LETTER NNA;Lo;0;L;;;;;N;;;;; 0A24;GURMUKHI LETTER TA;Lo;0;L;;;;;N;;;;; 0A25;GURMUKHI LETTER THA;Lo;0;L;;;;;N;;;;; 0A26;GURMUKHI LETTER DA;Lo;0;L;;;;;N;;;;; 0A27;GURMUKHI LETTER DHA;Lo;0;L;;;;;N;;;;; 0A28;GURMUKHI LETTER NA;Lo;0;L;;;;;N;;;;; 0A2A;GURMUKHI LETTER PA;Lo;0;L;;;;;N;;;;; 0A2B;GURMUKHI LETTER PHA;Lo;0;L;;;;;N;;;;; 0A2C;GURMUKHI LETTER BA;Lo;0;L;;;;;N;;;;; 0A2D;GURMUKHI LETTER BHA;Lo;0;L;;;;;N;;;;; 0A2E;GURMUKHI LETTER MA;Lo;0;L;;;;;N;;;;; 0A2F;GURMUKHI LETTER YA;Lo;0;L;;;;;N;;;;; 0A30;GURMUKHI LETTER RA;Lo;0;L;;;;;N;;;;; 0A32;GURMUKHI LETTER LA;Lo;0;L;;;;;N;;;;; 0A33;GURMUKHI LETTER LLA;Lo;0;L;0A32 0A3C;;;;N;;;;; 0A35;GURMUKHI LETTER VA;Lo;0;L;;;;;N;;;;; 0A36;GURMUKHI LETTER SHA;Lo;0;L;0A38 0A3C;;;;N;;;;; 0A38;GURMUKHI LETTER SA;Lo;0;L;;;;;N;;;;; 0A39;GURMUKHI LETTER HA;Lo;0;L;;;;;N;;;;; 0A3C;GURMUKHI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; 0A3E;GURMUKHI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; 0A3F;GURMUKHI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; 0A40;GURMUKHI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; 0A41;GURMUKHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; 0A42;GURMUKHI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; 0A47;GURMUKHI VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;; 0A48;GURMUKHI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; 0A4B;GURMUKHI VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;; 0A4C;GURMUKHI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; 0A4D;GURMUKHI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 0A59;GURMUKHI LETTER KHHA;Lo;0;L;0A16 0A3C;;;;N;;;;; 0A5A;GURMUKHI LETTER GHHA;Lo;0;L;0A17 0A3C;;;;N;;;;; 0A5B;GURMUKHI LETTER ZA;Lo;0;L;0A1C 0A3C;;;;N;;;;; 0A5C;GURMUKHI LETTER RRA;Lo;0;L;;;;;N;;;;; 0A5E;GURMUKHI LETTER FA;Lo;0;L;0A2B 0A3C;;;;N;;;;; 0A66;GURMUKHI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0A67;GURMUKHI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0A68;GURMUKHI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 0A69;GURMUKHI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; 0A6A;GURMUKHI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; 0A6B;GURMUKHI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; 0A6C;GURMUKHI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; 0A6D;GURMUKHI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 0A6E;GURMUKHI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 0A6F;GURMUKHI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0A70;GURMUKHI TIPPI;Mn;0;NSM;;;;;N;;;;; 0A71;GURMUKHI ADDAK;Mn;0;NSM;;;;;N;;;;; 0A72;GURMUKHI IRI;Lo;0;L;;;;;N;;;;; 0A73;GURMUKHI URA;Lo;0;L;;;;;N;;;;; 0A74;GURMUKHI EK ONKAR;Lo;0;L;;;;;N;;;;; 0A81;GUJARATI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0A82;GUJARATI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; 0A83;GUJARATI SIGN VISARGA;Mc;0;L;;;;;N;;;;; 0A85;GUJARATI LETTER A;Lo;0;L;;;;;N;;;;; 0A86;GUJARATI LETTER AA;Lo;0;L;;;;;N;;;;; 0A87;GUJARATI LETTER I;Lo;0;L;;;;;N;;;;; 0A88;GUJARATI LETTER II;Lo;0;L;;;;;N;;;;; 0A89;GUJARATI LETTER U;Lo;0;L;;;;;N;;;;; 0A8A;GUJARATI LETTER UU;Lo;0;L;;;;;N;;;;; 0A8B;GUJARATI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; 0A8D;GUJARATI VOWEL CANDRA E;Lo;0;L;;;;;N;;;;; 0A8F;GUJARATI LETTER E;Lo;0;L;;;;;N;;;;; 0A90;GUJARATI LETTER AI;Lo;0;L;;;;;N;;;;; 0A91;GUJARATI VOWEL CANDRA O;Lo;0;L;;;;;N;;;;; 0A93;GUJARATI LETTER O;Lo;0;L;;;;;N;;;;; 0A94;GUJARATI LETTER AU;Lo;0;L;;;;;N;;;;; 0A95;GUJARATI LETTER KA;Lo;0;L;;;;;N;;;;; 0A96;GUJARATI LETTER KHA;Lo;0;L;;;;;N;;;;; 0A97;GUJARATI LETTER GA;Lo;0;L;;;;;N;;;;; 0A98;GUJARATI LETTER GHA;Lo;0;L;;;;;N;;;;; 0A99;GUJARATI LETTER NGA;Lo;0;L;;;;;N;;;;; 0A9A;GUJARATI LETTER CA;Lo;0;L;;;;;N;;;;; 0A9B;GUJARATI LETTER CHA;Lo;0;L;;;;;N;;;;; 0A9C;GUJARATI LETTER JA;Lo;0;L;;;;;N;;;;; 0A9D;GUJARATI LETTER JHA;Lo;0;L;;;;;N;;;;; 0A9E;GUJARATI LETTER NYA;Lo;0;L;;;;;N;;;;; 0A9F;GUJARATI LETTER TTA;Lo;0;L;;;;;N;;;;; 0AA0;GUJARATI LETTER TTHA;Lo;0;L;;;;;N;;;;; 0AA1;GUJARATI LETTER DDA;Lo;0;L;;;;;N;;;;; 0AA2;GUJARATI LETTER DDHA;Lo;0;L;;;;;N;;;;; 0AA3;GUJARATI LETTER NNA;Lo;0;L;;;;;N;;;;; 0AA4;GUJARATI LETTER TA;Lo;0;L;;;;;N;;;;; 0AA5;GUJARATI LETTER THA;Lo;0;L;;;;;N;;;;; 0AA6;GUJARATI LETTER DA;Lo;0;L;;;;;N;;;;; 0AA7;GUJARATI LETTER DHA;Lo;0;L;;;;;N;;;;; 0AA8;GUJARATI LETTER NA;Lo;0;L;;;;;N;;;;; 0AAA;GUJARATI LETTER PA;Lo;0;L;;;;;N;;;;; 0AAB;GUJARATI LETTER PHA;Lo;0;L;;;;;N;;;;; 0AAC;GUJARATI LETTER BA;Lo;0;L;;;;;N;;;;; 0AAD;GUJARATI LETTER BHA;Lo;0;L;;;;;N;;;;; 0AAE;GUJARATI LETTER MA;Lo;0;L;;;;;N;;;;; 0AAF;GUJARATI LETTER YA;Lo;0;L;;;;;N;;;;; 0AB0;GUJARATI LETTER RA;Lo;0;L;;;;;N;;;;; 0AB2;GUJARATI LETTER LA;Lo;0;L;;;;;N;;;;; 0AB3;GUJARATI LETTER LLA;Lo;0;L;;;;;N;;;;; 0AB5;GUJARATI LETTER VA;Lo;0;L;;;;;N;;;;; 0AB6;GUJARATI LETTER SHA;Lo;0;L;;;;;N;;;;; 0AB7;GUJARATI LETTER SSA;Lo;0;L;;;;;N;;;;; 0AB8;GUJARATI LETTER SA;Lo;0;L;;;;;N;;;;; 0AB9;GUJARATI LETTER HA;Lo;0;L;;;;;N;;;;; 0ABC;GUJARATI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; 0ABD;GUJARATI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; 0ABE;GUJARATI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; 0ABF;GUJARATI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; 0AC0;GUJARATI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; 0AC1;GUJARATI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; 0AC2;GUJARATI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; 0AC3;GUJARATI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; 0AC4;GUJARATI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; 0AC5;GUJARATI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;; 0AC7;GUJARATI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; 0AC8;GUJARATI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; 0AC9;GUJARATI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;; 0ACB;GUJARATI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; 0ACC;GUJARATI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; 0ACD;GUJARATI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 0AD0;GUJARATI OM;Lo;0;L;;;;;N;;;;; 0AE0;GUJARATI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0AE6;GUJARATI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0AE7;GUJARATI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0AE8;GUJARATI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 0AE9;GUJARATI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; 0AEA;GUJARATI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; 0AEB;GUJARATI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; 0AEC;GUJARATI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; 0AED;GUJARATI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 0AEE;GUJARATI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 0AEF;GUJARATI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0B01;ORIYA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0B02;ORIYA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0B03;ORIYA SIGN VISARGA;Mc;0;L;;;;;N;;;;; 0B05;ORIYA LETTER A;Lo;0;L;;;;;N;;;;; 0B06;ORIYA LETTER AA;Lo;0;L;;;;;N;;;;; 0B07;ORIYA LETTER I;Lo;0;L;;;;;N;;;;; 0B08;ORIYA LETTER II;Lo;0;L;;;;;N;;;;; 0B09;ORIYA LETTER U;Lo;0;L;;;;;N;;;;; 0B0A;ORIYA LETTER UU;Lo;0;L;;;;;N;;;;; 0B0B;ORIYA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; 0B0C;ORIYA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; 0B0F;ORIYA LETTER E;Lo;0;L;;;;;N;;;;; 0B10;ORIYA LETTER AI;Lo;0;L;;;;;N;;;;; 0B13;ORIYA LETTER O;Lo;0;L;;;;;N;;;;; 0B14;ORIYA LETTER AU;Lo;0;L;;;;;N;;;;; 0B15;ORIYA LETTER KA;Lo;0;L;;;;;N;;;;; 0B16;ORIYA LETTER KHA;Lo;0;L;;;;;N;;;;; 0B17;ORIYA LETTER GA;Lo;0;L;;;;;N;;;;; 0B18;ORIYA LETTER GHA;Lo;0;L;;;;;N;;;;; 0B19;ORIYA LETTER NGA;Lo;0;L;;;;;N;;;;; 0B1A;ORIYA LETTER CA;Lo;0;L;;;;;N;;;;; 0B1B;ORIYA LETTER CHA;Lo;0;L;;;;;N;;;;; 0B1C;ORIYA LETTER JA;Lo;0;L;;;;;N;;;;; 0B1D;ORIYA LETTER JHA;Lo;0;L;;;;;N;;;;; 0B1E;ORIYA LETTER NYA;Lo;0;L;;;;;N;;;;; 0B1F;ORIYA LETTER TTA;Lo;0;L;;;;;N;;;;; 0B20;ORIYA LETTER TTHA;Lo;0;L;;;;;N;;;;; 0B21;ORIYA LETTER DDA;Lo;0;L;;;;;N;;;;; 0B22;ORIYA LETTER DDHA;Lo;0;L;;;;;N;;;;; 0B23;ORIYA LETTER NNA;Lo;0;L;;;;;N;;;;; 0B24;ORIYA LETTER TA;Lo;0;L;;;;;N;;;;; 0B25;ORIYA LETTER THA;Lo;0;L;;;;;N;;;;; 0B26;ORIYA LETTER DA;Lo;0;L;;;;;N;;;;; 0B27;ORIYA LETTER DHA;Lo;0;L;;;;;N;;;;; 0B28;ORIYA LETTER NA;Lo;0;L;;;;;N;;;;; 0B2A;ORIYA LETTER PA;Lo;0;L;;;;;N;;;;; 0B2B;ORIYA LETTER PHA;Lo;0;L;;;;;N;;;;; 0B2C;ORIYA LETTER BA;Lo;0;L;;;;;N;;;;; 0B2D;ORIYA LETTER BHA;Lo;0;L;;;;;N;;;;; 0B2E;ORIYA LETTER MA;Lo;0;L;;;;;N;;;;; 0B2F;ORIYA LETTER YA;Lo;0;L;;;;;N;;;;; 0B30;ORIYA LETTER RA;Lo;0;L;;;;;N;;;;; 0B32;ORIYA LETTER LA;Lo;0;L;;;;;N;;;;; 0B33;ORIYA LETTER LLA;Lo;0;L;;;;;N;;;;; 0B36;ORIYA LETTER SHA;Lo;0;L;;;;;N;;;;; 0B37;ORIYA LETTER SSA;Lo;0;L;;;;;N;;;;; 0B38;ORIYA LETTER SA;Lo;0;L;;;;;N;;;;; 0B39;ORIYA LETTER HA;Lo;0;L;;;;;N;;;;; 0B3C;ORIYA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; 0B3D;ORIYA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; 0B3E;ORIYA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; 0B3F;ORIYA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 0B40;ORIYA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; 0B41;ORIYA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; 0B42;ORIYA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; 0B43;ORIYA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; 0B47;ORIYA VOWEL SIGN E;Mc;0;L;;;;;N;;;;; 0B48;ORIYA VOWEL SIGN AI;Mc;0;L;0B47 0B56;;;;N;;;;; 0B4B;ORIYA VOWEL SIGN O;Mc;0;L;0B47 0B3E;;;;N;;;;; 0B4C;ORIYA VOWEL SIGN AU;Mc;0;L;0B47 0B57;;;;N;;;;; 0B4D;ORIYA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 0B56;ORIYA AI LENGTH MARK;Mn;0;NSM;;;;;N;;;;; 0B57;ORIYA AU LENGTH MARK;Mc;0;L;;;;;N;;;;; 0B5C;ORIYA LETTER RRA;Lo;0;L;0B21 0B3C;;;;N;;;;; 0B5D;ORIYA LETTER RHA;Lo;0;L;0B22 0B3C;;;;N;;;;; 0B5F;ORIYA LETTER YYA;Lo;0;L;;;;;N;;;;; 0B60;ORIYA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0B61;ORIYA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; 0B66;ORIYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0B67;ORIYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0B68;ORIYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 0B69;ORIYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; 0B6A;ORIYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; 0B6B;ORIYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; 0B6C;ORIYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; 0B6D;ORIYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 0B6E;ORIYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 0B6F;ORIYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0B70;ORIYA ISSHAR;So;0;L;;;;;N;;;;; 0B82;TAMIL SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; 0B83;TAMIL SIGN VISARGA;Lo;0;L;;;;;N;;;;; 0B85;TAMIL LETTER A;Lo;0;L;;;;;N;;;;; 0B86;TAMIL LETTER AA;Lo;0;L;;;;;N;;;;; 0B87;TAMIL LETTER I;Lo;0;L;;;;;N;;;;; 0B88;TAMIL LETTER II;Lo;0;L;;;;;N;;;;; 0B89;TAMIL LETTER U;Lo;0;L;;;;;N;;;;; 0B8A;TAMIL LETTER UU;Lo;0;L;;;;;N;;;;; 0B8E;TAMIL LETTER E;Lo;0;L;;;;;N;;;;; 0B8F;TAMIL LETTER EE;Lo;0;L;;;;;N;;;;; 0B90;TAMIL LETTER AI;Lo;0;L;;;;;N;;;;; 0B92;TAMIL LETTER O;Lo;0;L;;;;;N;;;;; 0B93;TAMIL LETTER OO;Lo;0;L;;;;;N;;;;; 0B94;TAMIL LETTER AU;Lo;0;L;0B92 0BD7;;;;N;;;;; 0B95;TAMIL LETTER KA;Lo;0;L;;;;;N;;;;; 0B99;TAMIL LETTER NGA;Lo;0;L;;;;;N;;;;; 0B9A;TAMIL LETTER CA;Lo;0;L;;;;;N;;;;; 0B9C;TAMIL LETTER JA;Lo;0;L;;;;;N;;;;; 0B9E;TAMIL LETTER NYA;Lo;0;L;;;;;N;;;;; 0B9F;TAMIL LETTER TTA;Lo;0;L;;;;;N;;;;; 0BA3;TAMIL LETTER NNA;Lo;0;L;;;;;N;;;;; 0BA4;TAMIL LETTER TA;Lo;0;L;;;;;N;;;;; 0BA8;TAMIL LETTER NA;Lo;0;L;;;;;N;;;;; 0BA9;TAMIL LETTER NNNA;Lo;0;L;;;;;N;;;;; 0BAA;TAMIL LETTER PA;Lo;0;L;;;;;N;;;;; 0BAE;TAMIL LETTER MA;Lo;0;L;;;;;N;;;;; 0BAF;TAMIL LETTER YA;Lo;0;L;;;;;N;;;;; 0BB0;TAMIL LETTER RA;Lo;0;L;;;;;N;;;;; 0BB1;TAMIL LETTER RRA;Lo;0;L;;;;;N;;;;; 0BB2;TAMIL LETTER LA;Lo;0;L;;;;;N;;;;; 0BB3;TAMIL LETTER LLA;Lo;0;L;;;;;N;;;;; 0BB4;TAMIL LETTER LLLA;Lo;0;L;;;;;N;;;;; 0BB5;TAMIL LETTER VA;Lo;0;L;;;;;N;;;;; 0BB7;TAMIL LETTER SSA;Lo;0;L;;;;;N;;;;; 0BB8;TAMIL LETTER SA;Lo;0;L;;;;;N;;;;; 0BB9;TAMIL LETTER HA;Lo;0;L;;;;;N;;;;; 0BBE;TAMIL VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; 0BBF;TAMIL VOWEL SIGN I;Mc;0;L;;;;;N;;;;; 0BC0;TAMIL VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; 0BC1;TAMIL VOWEL SIGN U;Mc;0;L;;;;;N;;;;; 0BC2;TAMIL VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; 0BC6;TAMIL VOWEL SIGN E;Mc;0;L;;;;;N;;;;; 0BC7;TAMIL VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; 0BC8;TAMIL VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; 0BCA;TAMIL VOWEL SIGN O;Mc;0;L;0BC6 0BBE;;;;N;;;;; 0BCB;TAMIL VOWEL SIGN OO;Mc;0;L;0BC7 0BBE;;;;N;;;;; 0BCC;TAMIL VOWEL SIGN AU;Mc;0;L;0BC6 0BD7;;;;N;;;;; 0BCD;TAMIL SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 0BD7;TAMIL AU LENGTH MARK;Mc;0;L;;;;;N;;;;; 0BE7;TAMIL DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0BE8;TAMIL DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 0BE9;TAMIL DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; 0BEA;TAMIL DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; 0BEB;TAMIL DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; 0BEC;TAMIL DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; 0BED;TAMIL DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 0BEE;TAMIL DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 0BEF;TAMIL DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0BF0;TAMIL NUMBER TEN;No;0;L;;;;10;N;;;;; 0BF1;TAMIL NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;; 0BF2;TAMIL NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;; 0C01;TELUGU SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;; 0C02;TELUGU SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0C03;TELUGU SIGN VISARGA;Mc;0;L;;;;;N;;;;; 0C05;TELUGU LETTER A;Lo;0;L;;;;;N;;;;; 0C06;TELUGU LETTER AA;Lo;0;L;;;;;N;;;;; 0C07;TELUGU LETTER I;Lo;0;L;;;;;N;;;;; 0C08;TELUGU LETTER II;Lo;0;L;;;;;N;;;;; 0C09;TELUGU LETTER U;Lo;0;L;;;;;N;;;;; 0C0A;TELUGU LETTER UU;Lo;0;L;;;;;N;;;;; 0C0B;TELUGU LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; 0C0C;TELUGU LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; 0C0E;TELUGU LETTER E;Lo;0;L;;;;;N;;;;; 0C0F;TELUGU LETTER EE;Lo;0;L;;;;;N;;;;; 0C10;TELUGU LETTER AI;Lo;0;L;;;;;N;;;;; 0C12;TELUGU LETTER O;Lo;0;L;;;;;N;;;;; 0C13;TELUGU LETTER OO;Lo;0;L;;;;;N;;;;; 0C14;TELUGU LETTER AU;Lo;0;L;;;;;N;;;;; 0C15;TELUGU LETTER KA;Lo;0;L;;;;;N;;;;; 0C16;TELUGU LETTER KHA;Lo;0;L;;;;;N;;;;; 0C17;TELUGU LETTER GA;Lo;0;L;;;;;N;;;;; 0C18;TELUGU LETTER GHA;Lo;0;L;;;;;N;;;;; 0C19;TELUGU LETTER NGA;Lo;0;L;;;;;N;;;;; 0C1A;TELUGU LETTER CA;Lo;0;L;;;;;N;;;;; 0C1B;TELUGU LETTER CHA;Lo;0;L;;;;;N;;;;; 0C1C;TELUGU LETTER JA;Lo;0;L;;;;;N;;;;; 0C1D;TELUGU LETTER JHA;Lo;0;L;;;;;N;;;;; 0C1E;TELUGU LETTER NYA;Lo;0;L;;;;;N;;;;; 0C1F;TELUGU LETTER TTA;Lo;0;L;;;;;N;;;;; 0C20;TELUGU LETTER TTHA;Lo;0;L;;;;;N;;;;; 0C21;TELUGU LETTER DDA;Lo;0;L;;;;;N;;;;; 0C22;TELUGU LETTER DDHA;Lo;0;L;;;;;N;;;;; 0C23;TELUGU LETTER NNA;Lo;0;L;;;;;N;;;;; 0C24;TELUGU LETTER TA;Lo;0;L;;;;;N;;;;; 0C25;TELUGU LETTER THA;Lo;0;L;;;;;N;;;;; 0C26;TELUGU LETTER DA;Lo;0;L;;;;;N;;;;; 0C27;TELUGU LETTER DHA;Lo;0;L;;;;;N;;;;; 0C28;TELUGU LETTER NA;Lo;0;L;;;;;N;;;;; 0C2A;TELUGU LETTER PA;Lo;0;L;;;;;N;;;;; 0C2B;TELUGU LETTER PHA;Lo;0;L;;;;;N;;;;; 0C2C;TELUGU LETTER BA;Lo;0;L;;;;;N;;;;; 0C2D;TELUGU LETTER BHA;Lo;0;L;;;;;N;;;;; 0C2E;TELUGU LETTER MA;Lo;0;L;;;;;N;;;;; 0C2F;TELUGU LETTER YA;Lo;0;L;;;;;N;;;;; 0C30;TELUGU LETTER RA;Lo;0;L;;;;;N;;;;; 0C31;TELUGU LETTER RRA;Lo;0;L;;;;;N;;;;; 0C32;TELUGU LETTER LA;Lo;0;L;;;;;N;;;;; 0C33;TELUGU LETTER LLA;Lo;0;L;;;;;N;;;;; 0C35;TELUGU LETTER VA;Lo;0;L;;;;;N;;;;; 0C36;TELUGU LETTER SHA;Lo;0;L;;;;;N;;;;; 0C37;TELUGU LETTER SSA;Lo;0;L;;;;;N;;;;; 0C38;TELUGU LETTER SA;Lo;0;L;;;;;N;;;;; 0C39;TELUGU LETTER HA;Lo;0;L;;;;;N;;;;; 0C3E;TELUGU VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; 0C3F;TELUGU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 0C40;TELUGU VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; 0C41;TELUGU VOWEL SIGN U;Mc;0;L;;;;;N;;;;; 0C42;TELUGU VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; 0C43;TELUGU VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; 0C44;TELUGU VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; 0C46;TELUGU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; 0C47;TELUGU VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;; 0C48;TELUGU VOWEL SIGN AI;Mn;0;NSM;0C46 0C56;;;;N;;;;; 0C4A;TELUGU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; 0C4B;TELUGU VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;; 0C4C;TELUGU VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; 0C4D;TELUGU SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 0C55;TELUGU LENGTH MARK;Mn;84;NSM;;;;;N;;;;; 0C56;TELUGU AI LENGTH MARK;Mn;91;NSM;;;;;N;;;;; 0C60;TELUGU LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0C61;TELUGU LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; 0C66;TELUGU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0C67;TELUGU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0C68;TELUGU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 0C69;TELUGU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; 0C6A;TELUGU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; 0C6B;TELUGU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; 0C6C;TELUGU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; 0C6D;TELUGU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 0C6E;TELUGU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 0C6F;TELUGU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;; 0C85;KANNADA LETTER A;Lo;0;L;;;;;N;;;;; 0C86;KANNADA LETTER AA;Lo;0;L;;;;;N;;;;; 0C87;KANNADA LETTER I;Lo;0;L;;;;;N;;;;; 0C88;KANNADA LETTER II;Lo;0;L;;;;;N;;;;; 0C89;KANNADA LETTER U;Lo;0;L;;;;;N;;;;; 0C8A;KANNADA LETTER UU;Lo;0;L;;;;;N;;;;; 0C8B;KANNADA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; 0C8C;KANNADA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; 0C8E;KANNADA LETTER E;Lo;0;L;;;;;N;;;;; 0C8F;KANNADA LETTER EE;Lo;0;L;;;;;N;;;;; 0C90;KANNADA LETTER AI;Lo;0;L;;;;;N;;;;; 0C92;KANNADA LETTER O;Lo;0;L;;;;;N;;;;; 0C93;KANNADA LETTER OO;Lo;0;L;;;;;N;;;;; 0C94;KANNADA LETTER AU;Lo;0;L;;;;;N;;;;; 0C95;KANNADA LETTER KA;Lo;0;L;;;;;N;;;;; 0C96;KANNADA LETTER KHA;Lo;0;L;;;;;N;;;;; 0C97;KANNADA LETTER GA;Lo;0;L;;;;;N;;;;; 0C98;KANNADA LETTER GHA;Lo;0;L;;;;;N;;;;; 0C99;KANNADA LETTER NGA;Lo;0;L;;;;;N;;;;; 0C9A;KANNADA LETTER CA;Lo;0;L;;;;;N;;;;; 0C9B;KANNADA LETTER CHA;Lo;0;L;;;;;N;;;;; 0C9C;KANNADA LETTER JA;Lo;0;L;;;;;N;;;;; 0C9D;KANNADA LETTER JHA;Lo;0;L;;;;;N;;;;; 0C9E;KANNADA LETTER NYA;Lo;0;L;;;;;N;;;;; 0C9F;KANNADA LETTER TTA;Lo;0;L;;;;;N;;;;; 0CA0;KANNADA LETTER TTHA;Lo;0;L;;;;;N;;;;; 0CA1;KANNADA LETTER DDA;Lo;0;L;;;;;N;;;;; 0CA2;KANNADA LETTER DDHA;Lo;0;L;;;;;N;;;;; 0CA3;KANNADA LETTER NNA;Lo;0;L;;;;;N;;;;; 0CA4;KANNADA LETTER TA;Lo;0;L;;;;;N;;;;; 0CA5;KANNADA LETTER THA;Lo;0;L;;;;;N;;;;; 0CA6;KANNADA LETTER DA;Lo;0;L;;;;;N;;;;; 0CA7;KANNADA LETTER DHA;Lo;0;L;;;;;N;;;;; 0CA8;KANNADA LETTER NA;Lo;0;L;;;;;N;;;;; 0CAA;KANNADA LETTER PA;Lo;0;L;;;;;N;;;;; 0CAB;KANNADA LETTER PHA;Lo;0;L;;;;;N;;;;; 0CAC;KANNADA LETTER BA;Lo;0;L;;;;;N;;;;; 0CAD;KANNADA LETTER BHA;Lo;0;L;;;;;N;;;;; 0CAE;KANNADA LETTER MA;Lo;0;L;;;;;N;;;;; 0CAF;KANNADA LETTER YA;Lo;0;L;;;;;N;;;;; 0CB0;KANNADA LETTER RA;Lo;0;L;;;;;N;;;;; 0CB1;KANNADA LETTER RRA;Lo;0;L;;;;;N;;;;; 0CB2;KANNADA LETTER LA;Lo;0;L;;;;;N;;;;; 0CB3;KANNADA LETTER LLA;Lo;0;L;;;;;N;;;;; 0CB5;KANNADA LETTER VA;Lo;0;L;;;;;N;;;;; 0CB6;KANNADA LETTER SHA;Lo;0;L;;;;;N;;;;; 0CB7;KANNADA LETTER SSA;Lo;0;L;;;;;N;;;;; 0CB8;KANNADA LETTER SA;Lo;0;L;;;;;N;;;;; 0CB9;KANNADA LETTER HA;Lo;0;L;;;;;N;;;;; 0CBE;KANNADA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; 0CBF;KANNADA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 0CC0;KANNADA VOWEL SIGN II;Mc;0;L;0CBF 0CD5;;;;N;;;;; 0CC1;KANNADA VOWEL SIGN U;Mc;0;L;;;;;N;;;;; 0CC2;KANNADA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; 0CC3;KANNADA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; 0CC4;KANNADA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; 0CC6;KANNADA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; 0CC7;KANNADA VOWEL SIGN EE;Mc;0;L;0CC6 0CD5;;;;N;;;;; 0CC8;KANNADA VOWEL SIGN AI;Mc;0;L;0CC6 0CD6;;;;N;;;;; 0CCA;KANNADA VOWEL SIGN O;Mc;0;L;0CC6 0CC2;;;;N;;;;; 0CCB;KANNADA VOWEL SIGN OO;Mc;0;L;0CCA 0CD5;;;;N;;;;; 0CCC;KANNADA VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; 0CCD;KANNADA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 0CD5;KANNADA LENGTH MARK;Mc;0;L;;;;;N;;;;; 0CD6;KANNADA AI LENGTH MARK;Mc;0;L;;;;;N;;;;; 0CDE;KANNADA LETTER FA;Lo;0;L;;;;;N;;;;; 0CE0;KANNADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0CE1;KANNADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; 0CE6;KANNADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0CE7;KANNADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0CE8;KANNADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 0CE9;KANNADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; 0CEA;KANNADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; 0CEB;KANNADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; 0CEC;KANNADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; 0CED;KANNADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 0CEE;KANNADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0D03;MALAYALAM SIGN VISARGA;Mc;0;L;;;;;N;;;;; 0D05;MALAYALAM LETTER A;Lo;0;L;;;;;N;;;;; 0D06;MALAYALAM LETTER AA;Lo;0;L;;;;;N;;;;; 0D07;MALAYALAM LETTER I;Lo;0;L;;;;;N;;;;; 0D08;MALAYALAM LETTER II;Lo;0;L;;;;;N;;;;; 0D09;MALAYALAM LETTER U;Lo;0;L;;;;;N;;;;; 0D0A;MALAYALAM LETTER UU;Lo;0;L;;;;;N;;;;; 0D0B;MALAYALAM LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; 0D0C;MALAYALAM LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; 0D0E;MALAYALAM LETTER E;Lo;0;L;;;;;N;;;;; 0D0F;MALAYALAM LETTER EE;Lo;0;L;;;;;N;;;;; 0D10;MALAYALAM LETTER AI;Lo;0;L;;;;;N;;;;; 0D12;MALAYALAM LETTER O;Lo;0;L;;;;;N;;;;; 0D13;MALAYALAM LETTER OO;Lo;0;L;;;;;N;;;;; 0D14;MALAYALAM LETTER AU;Lo;0;L;;;;;N;;;;; 0D15;MALAYALAM LETTER KA;Lo;0;L;;;;;N;;;;; 0D16;MALAYALAM LETTER KHA;Lo;0;L;;;;;N;;;;; 0D17;MALAYALAM LETTER GA;Lo;0;L;;;;;N;;;;; 0D18;MALAYALAM LETTER GHA;Lo;0;L;;;;;N;;;;; 0D19;MALAYALAM LETTER NGA;Lo;0;L;;;;;N;;;;; 0D1A;MALAYALAM LETTER CA;Lo;0;L;;;;;N;;;;; 0D1B;MALAYALAM LETTER CHA;Lo;0;L;;;;;N;;;;; 0D1C;MALAYALAM LETTER JA;Lo;0;L;;;;;N;;;;; 0D1D;MALAYALAM LETTER JHA;Lo;0;L;;;;;N;;;;; 0D1E;MALAYALAM LETTER NYA;Lo;0;L;;;;;N;;;;; 0D1F;MALAYALAM LETTER TTA;Lo;0;L;;;;;N;;;;; 0D20;MALAYALAM LETTER TTHA;Lo;0;L;;;;;N;;;;; 0D21;MALAYALAM LETTER DDA;Lo;0;L;;;;;N;;;;; 0D22;MALAYALAM LETTER DDHA;Lo;0;L;;;;;N;;;;; 0D23;MALAYALAM LETTER NNA;Lo;0;L;;;;;N;;;;; 0D24;MALAYALAM LETTER TA;Lo;0;L;;;;;N;;;;; 0D25;MALAYALAM LETTER THA;Lo;0;L;;;;;N;;;;; 0D26;MALAYALAM LETTER DA;Lo;0;L;;;;;N;;;;; 0D27;MALAYALAM LETTER DHA;Lo;0;L;;;;;N;;;;; 0D28;MALAYALAM LETTER NA;Lo;0;L;;;;;N;;;;; 0D2A;MALAYALAM LETTER PA;Lo;0;L;;;;;N;;;;; 0D2B;MALAYALAM LETTER PHA;Lo;0;L;;;;;N;;;;; 0D2C;MALAYALAM LETTER BA;Lo;0;L;;;;;N;;;;; 0D2D;MALAYALAM LETTER BHA;Lo;0;L;;;;;N;;;;; 0D2E;MALAYALAM LETTER MA;Lo;0;L;;;;;N;;;;; 0D2F;MALAYALAM LETTER YA;Lo;0;L;;;;;N;;;;; 0D30;MALAYALAM LETTER RA;Lo;0;L;;;;;N;;;;; 0D31;MALAYALAM LETTER RRA;Lo;0;L;;;;;N;;;;; 0D32;MALAYALAM LETTER LA;Lo;0;L;;;;;N;;;;; 0D33;MALAYALAM LETTER LLA;Lo;0;L;;;;;N;;;;; 0D34;MALAYALAM LETTER LLLA;Lo;0;L;;;;;N;;;;; 0D35;MALAYALAM LETTER VA;Lo;0;L;;;;;N;;;;; 0D36;MALAYALAM LETTER SHA;Lo;0;L;;;;;N;;;;; 0D37;MALAYALAM LETTER SSA;Lo;0;L;;;;;N;;;;; 0D38;MALAYALAM LETTER SA;Lo;0;L;;;;;N;;;;; 0D39;MALAYALAM LETTER HA;Lo;0;L;;;;;N;;;;; 0D3E;MALAYALAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; 0D3F;MALAYALAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;; 0D40;MALAYALAM VOWEL SIGN II;Mc;0;L;;;;;N;;;;; 0D41;MALAYALAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; 0D42;MALAYALAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; 0D43;MALAYALAM VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; 0D46;MALAYALAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;; 0D47;MALAYALAM VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; 0D48;MALAYALAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; 0D4A;MALAYALAM VOWEL SIGN O;Mc;0;L;0D46 0D3E;;;;N;;;;; 0D4B;MALAYALAM VOWEL SIGN OO;Mc;0;L;0D47 0D3E;;;;N;;;;; 0D4C;MALAYALAM VOWEL SIGN AU;Mc;0;L;0D46 0D57;;;;N;;;;; 0D4D;MALAYALAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 0D57;MALAYALAM AU LENGTH MARK;Mc;0;L;;;;;N;;;;; 0D60;MALAYALAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0D61;MALAYALAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; 0D66;MALAYALAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0D67;MALAYALAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0D68;MALAYALAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 0D69;MALAYALAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; 0D6A;MALAYALAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; 0D6B;MALAYALAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; 0D6C;MALAYALAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; 0D6D;MALAYALAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 0D6E;MALAYALAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 0D6F;MALAYALAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0D82;SINHALA SIGN ANUSVARAYA;Mc;0;L;;;;;N;;;;; 0D83;SINHALA SIGN VISARGAYA;Mc;0;L;;;;;N;;;;; 0D85;SINHALA LETTER AYANNA;Lo;0;L;;;;;N;;;;; 0D86;SINHALA LETTER AAYANNA;Lo;0;L;;;;;N;;;;; 0D87;SINHALA LETTER AEYANNA;Lo;0;L;;;;;N;;;;; 0D88;SINHALA LETTER AEEYANNA;Lo;0;L;;;;;N;;;;; 0D89;SINHALA LETTER IYANNA;Lo;0;L;;;;;N;;;;; 0D8A;SINHALA LETTER IIYANNA;Lo;0;L;;;;;N;;;;; 0D8B;SINHALA LETTER UYANNA;Lo;0;L;;;;;N;;;;; 0D8C;SINHALA LETTER UUYANNA;Lo;0;L;;;;;N;;;;; 0D8D;SINHALA LETTER IRUYANNA;Lo;0;L;;;;;N;;;;; 0D8E;SINHALA LETTER IRUUYANNA;Lo;0;L;;;;;N;;;;; 0D8F;SINHALA LETTER ILUYANNA;Lo;0;L;;;;;N;;;;; 0D90;SINHALA LETTER ILUUYANNA;Lo;0;L;;;;;N;;;;; 0D91;SINHALA LETTER EYANNA;Lo;0;L;;;;;N;;;;; 0D92;SINHALA LETTER EEYANNA;Lo;0;L;;;;;N;;;;; 0D93;SINHALA LETTER AIYANNA;Lo;0;L;;;;;N;;;;; 0D94;SINHALA LETTER OYANNA;Lo;0;L;;;;;N;;;;; 0D95;SINHALA LETTER OOYANNA;Lo;0;L;;;;;N;;;;; 0D96;SINHALA LETTER AUYANNA;Lo;0;L;;;;;N;;;;; 0D9A;SINHALA LETTER ALPAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;; 0D9B;SINHALA LETTER MAHAAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;; 0D9C;SINHALA LETTER ALPAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;; 0D9D;SINHALA LETTER MAHAAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;; 0D9E;SINHALA LETTER KANTAJA NAASIKYAYA;Lo;0;L;;;;;N;;;;; 0D9F;SINHALA LETTER SANYAKA GAYANNA;Lo;0;L;;;;;N;;;;; 0DA0;SINHALA LETTER ALPAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;; 0DA1;SINHALA LETTER MAHAAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;; 0DA2;SINHALA LETTER ALPAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;; 0DA3;SINHALA LETTER MAHAAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;; 0DA4;SINHALA LETTER TAALUJA NAASIKYAYA;Lo;0;L;;;;;N;;;;; 0DA5;SINHALA LETTER TAALUJA SANYOOGA NAAKSIKYAYA;Lo;0;L;;;;;N;;;;; 0DA6;SINHALA LETTER SANYAKA JAYANNA;Lo;0;L;;;;;N;;;;; 0DA7;SINHALA LETTER ALPAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;; 0DA8;SINHALA LETTER MAHAAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;; 0DA9;SINHALA LETTER ALPAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;; 0DAA;SINHALA LETTER MAHAAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;; 0DAB;SINHALA LETTER MUURDHAJA NAYANNA;Lo;0;L;;;;;N;;;;; 0DAC;SINHALA LETTER SANYAKA DDAYANNA;Lo;0;L;;;;;N;;;;; 0DAD;SINHALA LETTER ALPAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;; 0DAE;SINHALA LETTER MAHAAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;; 0DAF;SINHALA LETTER ALPAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;; 0DB0;SINHALA LETTER MAHAAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;; 0DB1;SINHALA LETTER DANTAJA NAYANNA;Lo;0;L;;;;;N;;;;; 0DB3;SINHALA LETTER SANYAKA DAYANNA;Lo;0;L;;;;;N;;;;; 0DB4;SINHALA LETTER ALPAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;; 0DB5;SINHALA LETTER MAHAAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;; 0DB6;SINHALA LETTER ALPAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;; 0DB7;SINHALA LETTER MAHAAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;; 0DB8;SINHALA LETTER MAYANNA;Lo;0;L;;;;;N;;;;; 0DB9;SINHALA LETTER AMBA BAYANNA;Lo;0;L;;;;;N;;;;; 0DBA;SINHALA LETTER YAYANNA;Lo;0;L;;;;;N;;;;; 0DBB;SINHALA LETTER RAYANNA;Lo;0;L;;;;;N;;;;; 0DBD;SINHALA LETTER DANTAJA LAYANNA;Lo;0;L;;;;;N;;;;; 0DC0;SINHALA LETTER VAYANNA;Lo;0;L;;;;;N;;;;; 0DC1;SINHALA LETTER TAALUJA SAYANNA;Lo;0;L;;;;;N;;;;; 0DC2;SINHALA LETTER MUURDHAJA SAYANNA;Lo;0;L;;;;;N;;;;; 0DC3;SINHALA LETTER DANTAJA SAYANNA;Lo;0;L;;;;;N;;;;; 0DC4;SINHALA LETTER HAYANNA;Lo;0;L;;;;;N;;;;; 0DC5;SINHALA LETTER MUURDHAJA LAYANNA;Lo;0;L;;;;;N;;;;; 0DC6;SINHALA LETTER FAYANNA;Lo;0;L;;;;;N;;;;; 0DCA;SINHALA SIGN AL-LAKUNA;Mn;9;NSM;;;;;N;;;;; 0DCF;SINHALA VOWEL SIGN AELA-PILLA;Mc;0;L;;;;;N;;;;; 0DD0;SINHALA VOWEL SIGN KETTI AEDA-PILLA;Mc;0;L;;;;;N;;;;; 0DD1;SINHALA VOWEL SIGN DIGA AEDA-PILLA;Mc;0;L;;;;;N;;;;; 0DD2;SINHALA VOWEL SIGN KETTI IS-PILLA;Mn;0;NSM;;;;;N;;;;; 0DD3;SINHALA VOWEL SIGN DIGA IS-PILLA;Mn;0;NSM;;;;;N;;;;; 0DD4;SINHALA VOWEL SIGN KETTI PAA-PILLA;Mn;0;NSM;;;;;N;;;;; 0DD6;SINHALA VOWEL SIGN DIGA PAA-PILLA;Mn;0;NSM;;;;;N;;;;; 0DD8;SINHALA VOWEL SIGN GAETTA-PILLA;Mc;0;L;;;;;N;;;;; 0DD9;SINHALA VOWEL SIGN KOMBUVA;Mc;0;L;;;;;N;;;;; 0DDA;SINHALA VOWEL SIGN DIGA KOMBUVA;Mc;0;L;0DD9 0DCA;;;;N;;;;; 0DDB;SINHALA VOWEL SIGN KOMBU DEKA;Mc;0;L;;;;;N;;;;; 0DDC;SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA;Mc;0;L;0DD9 0DCF;;;;N;;;;; 0DDD;SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA;Mc;0;L;0DDC 0DCA;;;;N;;;;; 0DDE;SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA;Mc;0;L;0DD9 0DDF;;;;N;;;;; 0DDF;SINHALA VOWEL SIGN GAYANUKITTA;Mc;0;L;;;;;N;;;;; 0DF2;SINHALA VOWEL SIGN DIGA GAETTA-PILLA;Mc;0;L;;;;;N;;;;; 0DF3;SINHALA VOWEL SIGN DIGA GAYANUKITTA;Mc;0;L;;;;;N;;;;; 0DF4;SINHALA PUNCTUATION KUNDDALIYA;Po;0;L;;;;;N;;;;; 0E01;THAI CHARACTER KO KAI;Lo;0;L;;;;;N;THAI LETTER KO KAI;;;; 0E02;THAI CHARACTER KHO KHAI;Lo;0;L;;;;;N;THAI LETTER KHO KHAI;;;; 0E03;THAI CHARACTER KHO KHUAT;Lo;0;L;;;;;N;THAI LETTER KHO KHUAT;;;; 0E04;THAI CHARACTER KHO KHWAI;Lo;0;L;;;;;N;THAI LETTER KHO KHWAI;;;; 0E05;THAI CHARACTER KHO KHON;Lo;0;L;;;;;N;THAI LETTER KHO KHON;;;; 0E06;THAI CHARACTER KHO RAKHANG;Lo;0;L;;;;;N;THAI LETTER KHO RAKHANG;;;; 0E07;THAI CHARACTER NGO NGU;Lo;0;L;;;;;N;THAI LETTER NGO NGU;;;; 0E08;THAI CHARACTER CHO CHAN;Lo;0;L;;;;;N;THAI LETTER CHO CHAN;;;; 0E09;THAI CHARACTER CHO CHING;Lo;0;L;;;;;N;THAI LETTER CHO CHING;;;; 0E0A;THAI CHARACTER CHO CHANG;Lo;0;L;;;;;N;THAI LETTER CHO CHANG;;;; 0E0B;THAI CHARACTER SO SO;Lo;0;L;;;;;N;THAI LETTER SO SO;;;; 0E0C;THAI CHARACTER CHO CHOE;Lo;0;L;;;;;N;THAI LETTER CHO CHOE;;;; 0E0D;THAI CHARACTER YO YING;Lo;0;L;;;;;N;THAI LETTER YO YING;;;; 0E0E;THAI CHARACTER DO CHADA;Lo;0;L;;;;;N;THAI LETTER DO CHADA;;;; 0E0F;THAI CHARACTER TO PATAK;Lo;0;L;;;;;N;THAI LETTER TO PATAK;;;; 0E10;THAI CHARACTER THO THAN;Lo;0;L;;;;;N;THAI LETTER THO THAN;;;; 0E11;THAI CHARACTER THO NANGMONTHO;Lo;0;L;;;;;N;THAI LETTER THO NANGMONTHO;;;; 0E12;THAI CHARACTER THO PHUTHAO;Lo;0;L;;;;;N;THAI LETTER THO PHUTHAO;;;; 0E13;THAI CHARACTER NO NEN;Lo;0;L;;;;;N;THAI LETTER NO NEN;;;; 0E14;THAI CHARACTER DO DEK;Lo;0;L;;;;;N;THAI LETTER DO DEK;;;; 0E15;THAI CHARACTER TO TAO;Lo;0;L;;;;;N;THAI LETTER TO TAO;;;; 0E16;THAI CHARACTER THO THUNG;Lo;0;L;;;;;N;THAI LETTER THO THUNG;;;; 0E17;THAI CHARACTER THO THAHAN;Lo;0;L;;;;;N;THAI LETTER THO THAHAN;;;; 0E18;THAI CHARACTER THO THONG;Lo;0;L;;;;;N;THAI LETTER THO THONG;;;; 0E19;THAI CHARACTER NO NU;Lo;0;L;;;;;N;THAI LETTER NO NU;;;; 0E1A;THAI CHARACTER BO BAIMAI;Lo;0;L;;;;;N;THAI LETTER BO BAIMAI;;;; 0E1B;THAI CHARACTER PO PLA;Lo;0;L;;;;;N;THAI LETTER PO PLA;;;; 0E1C;THAI CHARACTER PHO PHUNG;Lo;0;L;;;;;N;THAI LETTER PHO PHUNG;;;; 0E1D;THAI CHARACTER FO FA;Lo;0;L;;;;;N;THAI LETTER FO FA;;;; 0E1E;THAI CHARACTER PHO PHAN;Lo;0;L;;;;;N;THAI LETTER PHO PHAN;;;; 0E1F;THAI CHARACTER FO FAN;Lo;0;L;;;;;N;THAI LETTER FO FAN;;;; 0E20;THAI CHARACTER PHO SAMPHAO;Lo;0;L;;;;;N;THAI LETTER PHO SAMPHAO;;;; 0E21;THAI CHARACTER MO MA;Lo;0;L;;;;;N;THAI LETTER MO MA;;;; 0E22;THAI CHARACTER YO YAK;Lo;0;L;;;;;N;THAI LETTER YO YAK;;;; 0E23;THAI CHARACTER RO RUA;Lo;0;L;;;;;N;THAI LETTER RO RUA;;;; 0E24;THAI CHARACTER RU;Lo;0;L;;;;;N;THAI LETTER RU;;;; 0E25;THAI CHARACTER LO LING;Lo;0;L;;;;;N;THAI LETTER LO LING;;;; 0E26;THAI CHARACTER LU;Lo;0;L;;;;;N;THAI LETTER LU;;;; 0E27;THAI CHARACTER WO WAEN;Lo;0;L;;;;;N;THAI LETTER WO WAEN;;;; 0E28;THAI CHARACTER SO SALA;Lo;0;L;;;;;N;THAI LETTER SO SALA;;;; 0E29;THAI CHARACTER SO RUSI;Lo;0;L;;;;;N;THAI LETTER SO RUSI;;;; 0E2A;THAI CHARACTER SO SUA;Lo;0;L;;;;;N;THAI LETTER SO SUA;;;; 0E2B;THAI CHARACTER HO HIP;Lo;0;L;;;;;N;THAI LETTER HO HIP;;;; 0E2C;THAI CHARACTER LO CHULA;Lo;0;L;;;;;N;THAI LETTER LO CHULA;;;; 0E2D;THAI CHARACTER O ANG;Lo;0;L;;;;;N;THAI LETTER O ANG;;;; 0E2E;THAI CHARACTER HO NOKHUK;Lo;0;L;;;;;N;THAI LETTER HO NOK HUK;;;; 0E2F;THAI CHARACTER PAIYANNOI;Lo;0;L;;;;;N;THAI PAI YAN NOI;paiyan noi;;; 0E30;THAI CHARACTER SARA A;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA A;;;; 0E31;THAI CHARACTER MAI HAN-AKAT;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI HAN-AKAT;;;; 0E32;THAI CHARACTER SARA AA;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AA;;;; 0E33;THAI CHARACTER SARA AM;Lo;0;L; 0E4D 0E32;;;;N;THAI VOWEL SIGN SARA AM;;;; 0E34;THAI CHARACTER SARA I;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA I;;;; 0E35;THAI CHARACTER SARA II;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA II;;;; 0E36;THAI CHARACTER SARA UE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UE;;;; 0E37;THAI CHARACTER SARA UEE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UEE;sara uue;;; 0E38;THAI CHARACTER SARA U;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA U;;;; 0E39;THAI CHARACTER SARA UU;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA UU;;;; 0E3A;THAI CHARACTER PHINTHU;Mn;9;NSM;;;;;N;THAI VOWEL SIGN PHINTHU;;;; 0E3F;THAI CURRENCY SYMBOL BAHT;Sc;0;ET;;;;;N;THAI BAHT SIGN;;;; 0E40;THAI CHARACTER SARA E;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA E;;;; 0E41;THAI CHARACTER SARA AE;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AE;;;; 0E42;THAI CHARACTER SARA O;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA O;;;; 0E43;THAI CHARACTER SARA AI MAIMUAN;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MUAN;sara ai mai muan;;; 0E44;THAI CHARACTER SARA AI MAIMALAI;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MALAI;sara ai mai malai;;; 0E45;THAI CHARACTER LAKKHANGYAO;Lo;0;L;;;;;N;THAI LAK KHANG YAO;lakkhang yao;;; 0E46;THAI CHARACTER MAIYAMOK;Lm;0;L;;;;;N;THAI MAI YAMOK;mai yamok;;; 0E47;THAI CHARACTER MAITAIKHU;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI TAI KHU;mai taikhu;;; 0E48;THAI CHARACTER MAI EK;Mn;107;NSM;;;;;N;THAI TONE MAI EK;;;; 0E49;THAI CHARACTER MAI THO;Mn;107;NSM;;;;;N;THAI TONE MAI THO;;;; 0E4A;THAI CHARACTER MAI TRI;Mn;107;NSM;;;;;N;THAI TONE MAI TRI;;;; 0E4B;THAI CHARACTER MAI CHATTAWA;Mn;107;NSM;;;;;N;THAI TONE MAI CHATTAWA;;;; 0E4C;THAI CHARACTER THANTHAKHAT;Mn;0;NSM;;;;;N;THAI THANTHAKHAT;;;; 0E4D;THAI CHARACTER NIKHAHIT;Mn;0;NSM;;;;;N;THAI NIKKHAHIT;nikkhahit;;; 0E4E;THAI CHARACTER YAMAKKAN;Mn;0;NSM;;;;;N;THAI YAMAKKAN;;;; 0E4F;THAI CHARACTER FONGMAN;Po;0;L;;;;;N;THAI FONGMAN;;;; 0E50;THAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0E51;THAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0E52;THAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 0E53;THAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; 0E54;THAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; 0E55;THAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; 0E56;THAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; 0E57;THAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 0E58;THAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 0E59;THAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0E5A;THAI CHARACTER ANGKHANKHU;Po;0;L;;;;;N;THAI ANGKHANKHU;;;; 0E5B;THAI CHARACTER KHOMUT;Po;0;L;;;;;N;THAI KHOMUT;;;; 0E81;LAO LETTER KO;Lo;0;L;;;;;N;;;;; 0E82;LAO LETTER KHO SUNG;Lo;0;L;;;;;N;;;;; 0E84;LAO LETTER KHO TAM;Lo;0;L;;;;;N;;;;; 0E87;LAO LETTER NGO;Lo;0;L;;;;;N;;;;; 0E88;LAO LETTER CO;Lo;0;L;;;;;N;;;;; 0E8A;LAO LETTER SO TAM;Lo;0;L;;;;;N;;;;; 0E8D;LAO LETTER NYO;Lo;0;L;;;;;N;;;;; 0E94;LAO LETTER DO;Lo;0;L;;;;;N;;;;; 0E95;LAO LETTER TO;Lo;0;L;;;;;N;;;;; 0E96;LAO LETTER THO SUNG;Lo;0;L;;;;;N;;;;; 0E97;LAO LETTER THO TAM;Lo;0;L;;;;;N;;;;; 0E99;LAO LETTER NO;Lo;0;L;;;;;N;;;;; 0E9A;LAO LETTER BO;Lo;0;L;;;;;N;;;;; 0E9B;LAO LETTER PO;Lo;0;L;;;;;N;;;;; 0E9C;LAO LETTER PHO SUNG;Lo;0;L;;;;;N;;;;; 0E9D;LAO LETTER FO TAM;Lo;0;L;;;;;N;;;;; 0E9E;LAO LETTER PHO TAM;Lo;0;L;;;;;N;;;;; 0E9F;LAO LETTER FO SUNG;Lo;0;L;;;;;N;;;;; 0EA1;LAO LETTER MO;Lo;0;L;;;;;N;;;;; 0EA2;LAO LETTER YO;Lo;0;L;;;;;N;;;;; 0EA3;LAO LETTER LO LING;Lo;0;L;;;;;N;;;;; 0EA5;LAO LETTER LO LOOT;Lo;0;L;;;;;N;;;;; 0EA7;LAO LETTER WO;Lo;0;L;;;;;N;;;;; 0EAA;LAO LETTER SO SUNG;Lo;0;L;;;;;N;;;;; 0EAB;LAO LETTER HO SUNG;Lo;0;L;;;;;N;;;;; 0EAD;LAO LETTER O;Lo;0;L;;;;;N;;;;; 0EAE;LAO LETTER HO TAM;Lo;0;L;;;;;N;;;;; 0EAF;LAO ELLIPSIS;Lo;0;L;;;;;N;;;;; 0EB0;LAO VOWEL SIGN A;Lo;0;L;;;;;N;;;;; 0EB1;LAO VOWEL SIGN MAI KAN;Mn;0;NSM;;;;;N;;;;; 0EB2;LAO VOWEL SIGN AA;Lo;0;L;;;;;N;;;;; 0EB3;LAO VOWEL SIGN AM;Lo;0;L; 0ECD 0EB2;;;;N;;;;; 0EB4;LAO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 0EB5;LAO VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; 0EB6;LAO VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;; 0EB7;LAO VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;; 0EB8;LAO VOWEL SIGN U;Mn;118;NSM;;;;;N;;;;; 0EB9;LAO VOWEL SIGN UU;Mn;118;NSM;;;;;N;;;;; 0EBB;LAO VOWEL SIGN MAI KON;Mn;0;NSM;;;;;N;;;;; 0EBC;LAO SEMIVOWEL SIGN LO;Mn;0;NSM;;;;;N;;;;; 0EBD;LAO SEMIVOWEL SIGN NYO;Lo;0;L;;;;;N;;;;; 0EC0;LAO VOWEL SIGN E;Lo;0;L;;;;;N;;;;; 0EC1;LAO VOWEL SIGN EI;Lo;0;L;;;;;N;;;;; 0EC2;LAO VOWEL SIGN O;Lo;0;L;;;;;N;;;;; 0EC3;LAO VOWEL SIGN AY;Lo;0;L;;;;;N;;;;; 0EC4;LAO VOWEL SIGN AI;Lo;0;L;;;;;N;;;;; 0EC6;LAO KO LA;Lm;0;L;;;;;N;;;;; 0EC8;LAO TONE MAI EK;Mn;122;NSM;;;;;N;;;;; 0EC9;LAO TONE MAI THO;Mn;122;NSM;;;;;N;;;;; 0ECA;LAO TONE MAI TI;Mn;122;NSM;;;;;N;;;;; 0ECB;LAO TONE MAI CATAWA;Mn;122;NSM;;;;;N;;;;; 0ECC;LAO CANCELLATION MARK;Mn;0;NSM;;;;;N;;;;; 0ECD;LAO NIGGAHITA;Mn;0;NSM;;;;;N;;;;; 0ED0;LAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0ED1;LAO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0ED2;LAO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 0ED3;LAO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; 0ED4;LAO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; 0ED5;LAO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; 0ED6;LAO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; 0ED7;LAO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 0ED8;LAO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 0ED9;LAO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0EDC;LAO HO NO;Lo;0;L; 0EAB 0E99;;;;N;;;;; 0EDD;LAO HO MO;Lo;0;L; 0EAB 0EA1;;;;N;;;;; 0F00;TIBETAN SYLLABLE OM;Lo;0;L;;;;;N;;;;; 0F01;TIBETAN MARK GTER YIG MGO TRUNCATED A;So;0;L;;;;;N;;ter yik go a thung;;; 0F02;TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA;So;0;L;;;;;N;;ter yik go wum nam chey ma;;; 0F03;TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA;So;0;L;;;;;N;;ter yik go wum ter tsek ma;;; 0F04;TIBETAN MARK INITIAL YIG MGO MDUN MA;Po;0;L;;;;;N;TIBETAN SINGLE ORNAMENT;yik go dun ma;;; 0F05;TIBETAN MARK CLOSING YIG MGO SGAB MA;Po;0;L;;;;;N;;yik go kab ma;;; 0F06;TIBETAN MARK CARET YIG MGO PHUR SHAD MA;Po;0;L;;;;;N;;yik go pur shey ma;;; 0F07;TIBETAN MARK YIG MGO TSHEG SHAD MA;Po;0;L;;;;;N;;yik go tsek shey ma;;; 0F08;TIBETAN MARK SBRUL SHAD;Po;0;L;;;;;N;TIBETAN RGYANSHAD;drul shey;;; 0F09;TIBETAN MARK BSKUR YIG MGO;Po;0;L;;;;;N;;kur yik go;;; 0F0A;TIBETAN MARK BKA- SHOG YIG MGO;Po;0;L;;;;;N;;ka sho yik go;;; 0F0B;TIBETAN MARK INTERSYLLABIC TSHEG;Po;0;L;;;;;N;TIBETAN TSEG;tsek;;; 0F0C;TIBETAN MARK DELIMITER TSHEG BSTAR;Po;0;L; 0F0B;;;;N;;tsek tar;;; 0F0D;TIBETAN MARK SHAD;Po;0;L;;;;;N;TIBETAN SHAD;shey;;; 0F0E;TIBETAN MARK NYIS SHAD;Po;0;L;;;;;N;TIBETAN DOUBLE SHAD;nyi shey;;; 0F0F;TIBETAN MARK TSHEG SHAD;Po;0;L;;;;;N;;tsek shey;;; 0F10;TIBETAN MARK NYIS TSHEG SHAD;Po;0;L;;;;;N;;nyi tsek shey;;; 0F11;TIBETAN MARK RIN CHEN SPUNGS SHAD;Po;0;L;;;;;N;TIBETAN RINCHANPHUNGSHAD;rinchen pung shey;;; 0F12;TIBETAN MARK RGYA GRAM SHAD;Po;0;L;;;;;N;;gya tram shey;;; 0F13;TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN;So;0;L;;;;;N;;dzu ta me long chen;;; 0F14;TIBETAN MARK GTER TSHEG;So;0;L;;;;;N;TIBETAN COMMA;ter tsek;;; 0F15;TIBETAN LOGOTYPE SIGN CHAD RTAGS;So;0;L;;;;;N;;che ta;;; 0F16;TIBETAN LOGOTYPE SIGN LHAG RTAGS;So;0;L;;;;;N;;hlak ta;;; 0F17;TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS;So;0;L;;;;;N;;trachen char ta;;; 0F18;TIBETAN ASTROLOGICAL SIGN -KHYUD PA;Mn;220;NSM;;;;;N;;kyu pa;;; 0F19;TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS;Mn;220;NSM;;;;;N;;dong tsu;;; 0F1A;TIBETAN SIGN RDEL DKAR GCIG;So;0;L;;;;;N;;deka chig;;; 0F1B;TIBETAN SIGN RDEL DKAR GNYIS;So;0;L;;;;;N;;deka nyi;;; 0F1C;TIBETAN SIGN RDEL DKAR GSUM;So;0;L;;;;;N;;deka sum;;; 0F1D;TIBETAN SIGN RDEL NAG GCIG;So;0;L;;;;;N;;dena chig;;; 0F1E;TIBETAN SIGN RDEL NAG GNYIS;So;0;L;;;;;N;;dena nyi;;; 0F1F;TIBETAN SIGN RDEL DKAR RDEL NAG;So;0;L;;;;;N;;deka dena;;; 0F20;TIBETAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0F21;TIBETAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0F22;TIBETAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 0F23;TIBETAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; 0F24;TIBETAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; 0F25;TIBETAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; 0F26;TIBETAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; 0F27;TIBETAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 0F28;TIBETAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 0F29;TIBETAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0F2A;TIBETAN DIGIT HALF ONE;No;0;L;;;;1/2;N;;;;; 0F2B;TIBETAN DIGIT HALF TWO;No;0;L;;;;3/2;N;;;;; 0F2C;TIBETAN DIGIT HALF THREE;No;0;L;;;;5/2;N;;;;; 0F2D;TIBETAN DIGIT HALF FOUR;No;0;L;;;;7/2;N;;;;; 0F2E;TIBETAN DIGIT HALF FIVE;No;0;L;;;;9/2;N;;;;; 0F2F;TIBETAN DIGIT HALF SIX;No;0;L;;;;11/2;N;;;;; 0F30;TIBETAN DIGIT HALF SEVEN;No;0;L;;;;13/2;N;;;;; 0F31;TIBETAN DIGIT HALF EIGHT;No;0;L;;;;15/2;N;;;;; 0F32;TIBETAN DIGIT HALF NINE;No;0;L;;;;17/2;N;;;;; 0F33;TIBETAN DIGIT HALF ZERO;No;0;L;;;;-1/2;N;;;;; 0F34;TIBETAN MARK BSDUS RTAGS;So;0;L;;;;;N;;du ta;;; 0F35;TIBETAN MARK NGAS BZUNG NYI ZLA;Mn;220;NSM;;;;;N;TIBETAN HONORIFIC UNDER RING;nge zung nyi da;;; 0F36;TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN;So;0;L;;;;;N;;dzu ta shi mig chen;;; 0F37;TIBETAN MARK NGAS BZUNG SGOR RTAGS;Mn;220;NSM;;;;;N;TIBETAN UNDER RING;nge zung gor ta;;; 0F38;TIBETAN MARK CHE MGO;So;0;L;;;;;N;;che go;;; 0F39;TIBETAN MARK TSA -PHRU;Mn;216;NSM;;;;;N;TIBETAN LENITION MARK;tsa tru;;; 0F3A;TIBETAN MARK GUG RTAGS GYON;Ps;0;ON;;;;;N;;gug ta yun;;; 0F3B;TIBETAN MARK GUG RTAGS GYAS;Pe;0;ON;;;;;N;;gug ta ye;;; 0F3C;TIBETAN MARK ANG KHANG GYON;Ps;0;ON;;;;;N;TIBETAN LEFT BRACE;ang kang yun;;; 0F3D;TIBETAN MARK ANG KHANG GYAS;Pe;0;ON;;;;;N;TIBETAN RIGHT BRACE;ang kang ye;;; 0F3E;TIBETAN SIGN YAR TSHES;Mc;0;L;;;;;N;;yar tse;;; 0F3F;TIBETAN SIGN MAR TSHES;Mc;0;L;;;;;N;;mar tse;;; 0F40;TIBETAN LETTER KA;Lo;0;L;;;;;N;;;;; 0F41;TIBETAN LETTER KHA;Lo;0;L;;;;;N;;;;; 0F42;TIBETAN LETTER GA;Lo;0;L;;;;;N;;;;; 0F43;TIBETAN LETTER GHA;Lo;0;L;0F42 0FB7;;;;N;;;;; 0F44;TIBETAN LETTER NGA;Lo;0;L;;;;;N;;;;; 0F45;TIBETAN LETTER CA;Lo;0;L;;;;;N;;;;; 0F46;TIBETAN LETTER CHA;Lo;0;L;;;;;N;;;;; 0F47;TIBETAN LETTER JA;Lo;0;L;;;;;N;;;;; 0F49;TIBETAN LETTER NYA;Lo;0;L;;;;;N;;;;; 0F4A;TIBETAN LETTER TTA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED TA;;;; 0F4B;TIBETAN LETTER TTHA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED THA;;;; 0F4C;TIBETAN LETTER DDA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED DA;;;; 0F4D;TIBETAN LETTER DDHA;Lo;0;L;0F4C 0FB7;;;;N;;;;; 0F4E;TIBETAN LETTER NNA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED NA;;;; 0F4F;TIBETAN LETTER TA;Lo;0;L;;;;;N;;;;; 0F50;TIBETAN LETTER THA;Lo;0;L;;;;;N;;;;; 0F51;TIBETAN LETTER DA;Lo;0;L;;;;;N;;;;; 0F52;TIBETAN LETTER DHA;Lo;0;L;0F51 0FB7;;;;N;;;;; 0F53;TIBETAN LETTER NA;Lo;0;L;;;;;N;;;;; 0F54;TIBETAN LETTER PA;Lo;0;L;;;;;N;;;;; 0F55;TIBETAN LETTER PHA;Lo;0;L;;;;;N;;;;; 0F56;TIBETAN LETTER BA;Lo;0;L;;;;;N;;;;; 0F57;TIBETAN LETTER BHA;Lo;0;L;0F56 0FB7;;;;N;;;;; 0F58;TIBETAN LETTER MA;Lo;0;L;;;;;N;;;;; 0F59;TIBETAN LETTER TSA;Lo;0;L;;;;;N;;;;; 0F5A;TIBETAN LETTER TSHA;Lo;0;L;;;;;N;;;;; 0F5B;TIBETAN LETTER DZA;Lo;0;L;;;;;N;;;;; 0F5C;TIBETAN LETTER DZHA;Lo;0;L;0F5B 0FB7;;;;N;;;;; 0F5D;TIBETAN LETTER WA;Lo;0;L;;;;;N;;;;; 0F5E;TIBETAN LETTER ZHA;Lo;0;L;;;;;N;;;;; 0F5F;TIBETAN LETTER ZA;Lo;0;L;;;;;N;;;;; 0F60;TIBETAN LETTER -A;Lo;0;L;;;;;N;TIBETAN LETTER AA;;;; 0F61;TIBETAN LETTER YA;Lo;0;L;;;;;N;;;;; 0F62;TIBETAN LETTER RA;Lo;0;L;;;;;N;;*;;; 0F63;TIBETAN LETTER LA;Lo;0;L;;;;;N;;;;; 0F64;TIBETAN LETTER SHA;Lo;0;L;;;;;N;;;;; 0F65;TIBETAN LETTER SSA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED SHA;;;; 0F66;TIBETAN LETTER SA;Lo;0;L;;;;;N;;;;; 0F67;TIBETAN LETTER HA;Lo;0;L;;;;;N;;;;; 0F68;TIBETAN LETTER A;Lo;0;L;;;;;N;;;;; 0F69;TIBETAN LETTER KSSA;Lo;0;L;0F40 0FB5;;;;N;;;;; 0F6A;TIBETAN LETTER FIXED-FORM RA;Lo;0;L;;;;;N;;*;;; 0F71;TIBETAN VOWEL SIGN AA;Mn;129;NSM;;;;;N;;;;; 0F72;TIBETAN VOWEL SIGN I;Mn;130;NSM;;;;;N;;;;; 0F73;TIBETAN VOWEL SIGN II;Mn;0;NSM;0F71 0F72;;;;N;;;;; 0F74;TIBETAN VOWEL SIGN U;Mn;132;NSM;;;;;N;;;;; 0F75;TIBETAN VOWEL SIGN UU;Mn;0;NSM;0F71 0F74;;;;N;;;;; 0F76;TIBETAN VOWEL SIGN VOCALIC R;Mn;0;NSM;0FB2 0F80;;;;N;;;;; 0F77;TIBETAN VOWEL SIGN VOCALIC RR;Mn;0;NSM; 0FB2 0F81;;;;N;;;;; 0F78;TIBETAN VOWEL SIGN VOCALIC L;Mn;0;NSM;0FB3 0F80;;;;N;;;;; 0F79;TIBETAN VOWEL SIGN VOCALIC LL;Mn;0;NSM; 0FB3 0F81;;;;N;;;;; 0F7A;TIBETAN VOWEL SIGN E;Mn;130;NSM;;;;;N;;;;; 0F7B;TIBETAN VOWEL SIGN EE;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AI;;;; 0F7C;TIBETAN VOWEL SIGN O;Mn;130;NSM;;;;;N;;;;; 0F7D;TIBETAN VOWEL SIGN OO;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AU;;;; 0F7E;TIBETAN SIGN RJES SU NGA RO;Mn;0;NSM;;;;;N;TIBETAN ANUSVARA;je su nga ro;;; 0F7F;TIBETAN SIGN RNAM BCAD;Mc;0;L;;;;;N;TIBETAN VISARGA;nam chey;;; 0F80;TIBETAN VOWEL SIGN REVERSED I;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN SHORT I;;;; 0F81;TIBETAN VOWEL SIGN REVERSED II;Mn;0;NSM;0F71 0F80;;;;N;;;;; 0F82;TIBETAN SIGN NYI ZLA NAA DA;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU WITH ORNAMENT;nyi da na da;;; 0F83;TIBETAN SIGN SNA LDAN;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU;nan de;;; 0F84;TIBETAN MARK HALANTA;Mn;9;NSM;;;;;N;TIBETAN VIRAMA;;;; 0F85;TIBETAN MARK PALUTA;Po;0;L;;;;;N;TIBETAN CHUCHENYIGE;;;; 0F86;TIBETAN SIGN LCI RTAGS;Mn;230;NSM;;;;;N;;ji ta;;; 0F87;TIBETAN SIGN YANG RTAGS;Mn;230;NSM;;;;;N;;yang ta;;; 0F88;TIBETAN SIGN LCE TSA CAN;Lo;0;L;;;;;N;;che tsa chen;;; 0F89;TIBETAN SIGN MCHU CAN;Lo;0;L;;;;;N;;chu chen;;; 0F8A;TIBETAN SIGN GRU CAN RGYINGS;Lo;0;L;;;;;N;;tru chen ging;;; 0F8B;TIBETAN SIGN GRU MED RGYINGS;Lo;0;L;;;;;N;;tru me ging;;; 0F90;TIBETAN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;; 0F91;TIBETAN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;; 0F92;TIBETAN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;; 0F93;TIBETAN SUBJOINED LETTER GHA;Mn;0;NSM;0F92 0FB7;;;;N;;;;; 0F94;TIBETAN SUBJOINED LETTER NGA;Mn;0;NSM;;;;;N;;;;; 0F95;TIBETAN SUBJOINED LETTER CA;Mn;0;NSM;;;;;N;;;;; 0F96;TIBETAN SUBJOINED LETTER CHA;Mn;0;NSM;;;;;N;;;;; 0F97;TIBETAN SUBJOINED LETTER JA;Mn;0;NSM;;;;;N;;;;; 0F99;TIBETAN SUBJOINED LETTER NYA;Mn;0;NSM;;;;;N;;;;; 0F9A;TIBETAN SUBJOINED LETTER TTA;Mn;0;NSM;;;;;N;;;;; 0F9B;TIBETAN SUBJOINED LETTER TTHA;Mn;0;NSM;;;;;N;;;;; 0F9C;TIBETAN SUBJOINED LETTER DDA;Mn;0;NSM;;;;;N;;;;; 0F9D;TIBETAN SUBJOINED LETTER DDHA;Mn;0;NSM;0F9C 0FB7;;;;N;;;;; 0F9E;TIBETAN SUBJOINED LETTER NNA;Mn;0;NSM;;;;;N;;;;; 0F9F;TIBETAN SUBJOINED LETTER TA;Mn;0;NSM;;;;;N;;;;; 0FA0;TIBETAN SUBJOINED LETTER THA;Mn;0;NSM;;;;;N;;;;; 0FA1;TIBETAN SUBJOINED LETTER DA;Mn;0;NSM;;;;;N;;;;; 0FA2;TIBETAN SUBJOINED LETTER DHA;Mn;0;NSM;0FA1 0FB7;;;;N;;;;; 0FA3;TIBETAN SUBJOINED LETTER NA;Mn;0;NSM;;;;;N;;;;; 0FA4;TIBETAN SUBJOINED LETTER PA;Mn;0;NSM;;;;;N;;;;; 0FA5;TIBETAN SUBJOINED LETTER PHA;Mn;0;NSM;;;;;N;;;;; 0FA6;TIBETAN SUBJOINED LETTER BA;Mn;0;NSM;;;;;N;;;;; 0FA7;TIBETAN SUBJOINED LETTER BHA;Mn;0;NSM;0FA6 0FB7;;;;N;;;;; 0FA8;TIBETAN SUBJOINED LETTER MA;Mn;0;NSM;;;;;N;;;;; 0FA9;TIBETAN SUBJOINED LETTER TSA;Mn;0;NSM;;;;;N;;;;; 0FAA;TIBETAN SUBJOINED LETTER TSHA;Mn;0;NSM;;;;;N;;;;; 0FAB;TIBETAN SUBJOINED LETTER DZA;Mn;0;NSM;;;;;N;;;;; 0FAC;TIBETAN SUBJOINED LETTER DZHA;Mn;0;NSM;0FAB 0FB7;;;;N;;;;; 0FAD;TIBETAN SUBJOINED LETTER WA;Mn;0;NSM;;;;;N;;*;;; 0FAE;TIBETAN SUBJOINED LETTER ZHA;Mn;0;NSM;;;;;N;;;;; 0FAF;TIBETAN SUBJOINED LETTER ZA;Mn;0;NSM;;;;;N;;;;; 0FB0;TIBETAN SUBJOINED LETTER -A;Mn;0;NSM;;;;;N;;;;; 0FB1;TIBETAN SUBJOINED LETTER YA;Mn;0;NSM;;;;;N;;*;;; 0FB2;TIBETAN SUBJOINED LETTER RA;Mn;0;NSM;;;;;N;;*;;; 0FB3;TIBETAN SUBJOINED LETTER LA;Mn;0;NSM;;;;;N;;;;; 0FB4;TIBETAN SUBJOINED LETTER SHA;Mn;0;NSM;;;;;N;;;;; 0FB5;TIBETAN SUBJOINED LETTER SSA;Mn;0;NSM;;;;;N;;;;; 0FB6;TIBETAN SUBJOINED LETTER SA;Mn;0;NSM;;;;;N;;;;; 0FB7;TIBETAN SUBJOINED LETTER HA;Mn;0;NSM;;;;;N;;;;; 0FB8;TIBETAN SUBJOINED LETTER A;Mn;0;NSM;;;;;N;;;;; 0FB9;TIBETAN SUBJOINED LETTER KSSA;Mn;0;NSM;0F90 0FB5;;;;N;;;;; 0FBA;TIBETAN SUBJOINED LETTER FIXED-FORM WA;Mn;0;NSM;;;;;N;;*;;; 0FBB;TIBETAN SUBJOINED LETTER FIXED-FORM YA;Mn;0;NSM;;;;;N;;*;;; 0FBC;TIBETAN SUBJOINED LETTER FIXED-FORM RA;Mn;0;NSM;;;;;N;;*;;; 0FBE;TIBETAN KU RU KHA;So;0;L;;;;;N;;kuruka;;; 0FBF;TIBETAN KU RU KHA BZHI MIG CAN;So;0;L;;;;;N;;kuruka shi mik chen;;; 0FC0;TIBETAN CANTILLATION SIGN HEAVY BEAT;So;0;L;;;;;N;;;;; 0FC1;TIBETAN CANTILLATION SIGN LIGHT BEAT;So;0;L;;;;;N;;;;; 0FC2;TIBETAN CANTILLATION SIGN CANG TE-U;So;0;L;;;;;N;;chang tyu;;; 0FC3;TIBETAN CANTILLATION SIGN SBUB -CHAL;So;0;L;;;;;N;;bub chey;;; 0FC4;TIBETAN SYMBOL DRIL BU;So;0;L;;;;;N;;drilbu;;; 0FC5;TIBETAN SYMBOL RDO RJE;So;0;L;;;;;N;;dorje;;; 0FC6;TIBETAN SYMBOL PADMA GDAN;Mn;220;NSM;;;;;N;;pema den;;; 0FC7;TIBETAN SYMBOL RDO RJE RGYA GRAM;So;0;L;;;;;N;;dorje gya dram;;; 0FC8;TIBETAN SYMBOL PHUR PA;So;0;L;;;;;N;;phurba;;; 0FC9;TIBETAN SYMBOL NOR BU;So;0;L;;;;;N;;norbu;;; 0FCA;TIBETAN SYMBOL NOR BU NYIS -KHYIL;So;0;L;;;;;N;;norbu nyi khyi;;; 0FCB;TIBETAN SYMBOL NOR BU GSUM -KHYIL;So;0;L;;;;;N;;norbu sum khyi;;; 0FCC;TIBETAN SYMBOL NOR BU BZHI -KHYIL;So;0;L;;;;;N;;norbu shi khyi;;; 0FCF;TIBETAN SIGN RDEL NAG GSUM;So;0;L;;;;;N;;dena sum;;; 1000;MYANMAR LETTER KA;Lo;0;L;;;;;N;;;;; 1001;MYANMAR LETTER KHA;Lo;0;L;;;;;N;;;;; 1002;MYANMAR LETTER GA;Lo;0;L;;;;;N;;;;; 1003;MYANMAR LETTER GHA;Lo;0;L;;;;;N;;;;; 1004;MYANMAR LETTER NGA;Lo;0;L;;;;;N;;;;; 1005;MYANMAR LETTER CA;Lo;0;L;;;;;N;;;;; 1006;MYANMAR LETTER CHA;Lo;0;L;;;;;N;;;;; 1007;MYANMAR LETTER JA;Lo;0;L;;;;;N;;;;; 1008;MYANMAR LETTER JHA;Lo;0;L;;;;;N;;;;; 1009;MYANMAR LETTER NYA;Lo;0;L;;;;;N;;;;; 100A;MYANMAR LETTER NNYA;Lo;0;L;;;;;N;;;;; 100B;MYANMAR LETTER TTA;Lo;0;L;;;;;N;;;;; 100C;MYANMAR LETTER TTHA;Lo;0;L;;;;;N;;;;; 100D;MYANMAR LETTER DDA;Lo;0;L;;;;;N;;;;; 100E;MYANMAR LETTER DDHA;Lo;0;L;;;;;N;;;;; 100F;MYANMAR LETTER NNA;Lo;0;L;;;;;N;;;;; 1010;MYANMAR LETTER TA;Lo;0;L;;;;;N;;;;; 1011;MYANMAR LETTER THA;Lo;0;L;;;;;N;;;;; 1012;MYANMAR LETTER DA;Lo;0;L;;;;;N;;;;; 1013;MYANMAR LETTER DHA;Lo;0;L;;;;;N;;;;; 1014;MYANMAR LETTER NA;Lo;0;L;;;;;N;;;;; 1015;MYANMAR LETTER PA;Lo;0;L;;;;;N;;;;; 1016;MYANMAR LETTER PHA;Lo;0;L;;;;;N;;;;; 1017;MYANMAR LETTER BA;Lo;0;L;;;;;N;;;;; 1018;MYANMAR LETTER BHA;Lo;0;L;;;;;N;;;;; 1019;MYANMAR LETTER MA;Lo;0;L;;;;;N;;;;; 101A;MYANMAR LETTER YA;Lo;0;L;;;;;N;;;;; 101B;MYANMAR LETTER RA;Lo;0;L;;;;;N;;;;; 101C;MYANMAR LETTER LA;Lo;0;L;;;;;N;;;;; 101D;MYANMAR LETTER WA;Lo;0;L;;;;;N;;;;; 101E;MYANMAR LETTER SA;Lo;0;L;;;;;N;;;;; 101F;MYANMAR LETTER HA;Lo;0;L;;;;;N;;;;; 1020;MYANMAR LETTER LLA;Lo;0;L;;;;;N;;;;; 1021;MYANMAR LETTER A;Lo;0;L;;;;;N;;;;; 1023;MYANMAR LETTER I;Lo;0;L;;;;;N;;;;; 1024;MYANMAR LETTER II;Lo;0;L;;;;;N;;;;; 1025;MYANMAR LETTER U;Lo;0;L;;;;;N;;;;; 1026;MYANMAR LETTER UU;Lo;0;L;1025 102E;;;;N;;;;; 1027;MYANMAR LETTER E;Lo;0;L;;;;;N;;;;; 1029;MYANMAR LETTER O;Lo;0;L;;;;;N;;;;; 102A;MYANMAR LETTER AU;Lo;0;L;;;;;N;;;;; 102C;MYANMAR VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; 102D;MYANMAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 102E;MYANMAR VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; 102F;MYANMAR VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; 1030;MYANMAR VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; 1031;MYANMAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;; 1032;MYANMAR VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; 1036;MYANMAR SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; 1037;MYANMAR SIGN DOT BELOW;Mn;7;NSM;;;;;N;;;;; 1038;MYANMAR SIGN VISARGA;Mc;0;L;;;;;N;;;;; 1039;MYANMAR SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 1040;MYANMAR DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 1041;MYANMAR DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 1042;MYANMAR DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 1043;MYANMAR DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; 1044;MYANMAR DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; 1045;MYANMAR DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; 1046;MYANMAR DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; 1047;MYANMAR DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 1048;MYANMAR DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 1049;MYANMAR DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 104A;MYANMAR SIGN LITTLE SECTION;Po;0;L;;;;;N;;;;; 104B;MYANMAR SIGN SECTION;Po;0;L;;;;;N;;;;; 104C;MYANMAR SYMBOL LOCATIVE;Po;0;L;;;;;N;;;;; 104D;MYANMAR SYMBOL COMPLETED;Po;0;L;;;;;N;;;;; 104E;MYANMAR SYMBOL AFOREMENTIONED;Po;0;L;;;;;N;;;;; 104F;MYANMAR SYMBOL GENITIVE;Po;0;L;;;;;N;;;;; 1050;MYANMAR LETTER SHA;Lo;0;L;;;;;N;;;;; 1051;MYANMAR LETTER SSA;Lo;0;L;;;;;N;;;;; 1052;MYANMAR LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; 1053;MYANMAR LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 1054;MYANMAR LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; 1055;MYANMAR LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; 1056;MYANMAR VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; 1057;MYANMAR VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; 1058;MYANMAR VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; 1059;MYANMAR VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; 10A0;GEORGIAN CAPITAL LETTER AN;Lu;0;L;;;;;N;;Khutsuri;;; 10A1;GEORGIAN CAPITAL LETTER BAN;Lu;0;L;;;;;N;;Khutsuri;;; 10A2;GEORGIAN CAPITAL LETTER GAN;Lu;0;L;;;;;N;;Khutsuri;;; 10A3;GEORGIAN CAPITAL LETTER DON;Lu;0;L;;;;;N;;Khutsuri;;; 10A4;GEORGIAN CAPITAL LETTER EN;Lu;0;L;;;;;N;;Khutsuri;;; 10A5;GEORGIAN CAPITAL LETTER VIN;Lu;0;L;;;;;N;;Khutsuri;;; 10A6;GEORGIAN CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;Khutsuri;;; 10A7;GEORGIAN CAPITAL LETTER TAN;Lu;0;L;;;;;N;;Khutsuri;;; 10A8;GEORGIAN CAPITAL LETTER IN;Lu;0;L;;;;;N;;Khutsuri;;; 10A9;GEORGIAN CAPITAL LETTER KAN;Lu;0;L;;;;;N;;Khutsuri;;; 10AA;GEORGIAN CAPITAL LETTER LAS;Lu;0;L;;;;;N;;Khutsuri;;; 10AB;GEORGIAN CAPITAL LETTER MAN;Lu;0;L;;;;;N;;Khutsuri;;; 10AC;GEORGIAN CAPITAL LETTER NAR;Lu;0;L;;;;;N;;Khutsuri;;; 10AD;GEORGIAN CAPITAL LETTER ON;Lu;0;L;;;;;N;;Khutsuri;;; 10AE;GEORGIAN CAPITAL LETTER PAR;Lu;0;L;;;;;N;;Khutsuri;;; 10AF;GEORGIAN CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;Khutsuri;;; 10B0;GEORGIAN CAPITAL LETTER RAE;Lu;0;L;;;;;N;;Khutsuri;;; 10B1;GEORGIAN CAPITAL LETTER SAN;Lu;0;L;;;;;N;;Khutsuri;;; 10B2;GEORGIAN CAPITAL LETTER TAR;Lu;0;L;;;;;N;;Khutsuri;;; 10B3;GEORGIAN CAPITAL LETTER UN;Lu;0;L;;;;;N;;Khutsuri;;; 10B4;GEORGIAN CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;Khutsuri;;; 10B5;GEORGIAN CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;Khutsuri;;; 10B6;GEORGIAN CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;Khutsuri;;; 10B7;GEORGIAN CAPITAL LETTER QAR;Lu;0;L;;;;;N;;Khutsuri;;; 10B8;GEORGIAN CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;Khutsuri;;; 10B9;GEORGIAN CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;Khutsuri;;; 10BA;GEORGIAN CAPITAL LETTER CAN;Lu;0;L;;;;;N;;Khutsuri;;; 10BB;GEORGIAN CAPITAL LETTER JIL;Lu;0;L;;;;;N;;Khutsuri;;; 10BC;GEORGIAN CAPITAL LETTER CIL;Lu;0;L;;;;;N;;Khutsuri;;; 10BD;GEORGIAN CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;Khutsuri;;; 10BE;GEORGIAN CAPITAL LETTER XAN;Lu;0;L;;;;;N;;Khutsuri;;; 10BF;GEORGIAN CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;Khutsuri;;; 10C0;GEORGIAN CAPITAL LETTER HAE;Lu;0;L;;;;;N;;Khutsuri;;; 10C1;GEORGIAN CAPITAL LETTER HE;Lu;0;L;;;;;N;;Khutsuri;;; 10C2;GEORGIAN CAPITAL LETTER HIE;Lu;0;L;;;;;N;;Khutsuri;;; 10C3;GEORGIAN CAPITAL LETTER WE;Lu;0;L;;;;;N;;Khutsuri;;; 10C4;GEORGIAN CAPITAL LETTER HAR;Lu;0;L;;;;;N;;Khutsuri;;; 10C5;GEORGIAN CAPITAL LETTER HOE;Lu;0;L;;;;;N;;Khutsuri;;; 10D0;GEORGIAN LETTER AN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;;; 10D1;GEORGIAN LETTER BAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;;; 10D2;GEORGIAN LETTER GAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;;; 10D3;GEORGIAN LETTER DON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER DON;;;; 10D4;GEORGIAN LETTER EN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER EN;;;; 10D5;GEORGIAN LETTER VIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER VIN;;;; 10D6;GEORGIAN LETTER ZEN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZEN;;;; 10D7;GEORGIAN LETTER TAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAN;;;; 10D8;GEORGIAN LETTER IN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER IN;;;; 10D9;GEORGIAN LETTER KAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KAN;;;; 10DA;GEORGIAN LETTER LAS;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER LAS;;;; 10DB;GEORGIAN LETTER MAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER MAN;;;; 10DC;GEORGIAN LETTER NAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER NAR;;;; 10DD;GEORGIAN LETTER ON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ON;;;; 10DE;GEORGIAN LETTER PAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PAR;;;; 10DF;GEORGIAN LETTER ZHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZHAR;;;; 10E0;GEORGIAN LETTER RAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER RAE;;;; 10E1;GEORGIAN LETTER SAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SAN;;;; 10E2;GEORGIAN LETTER TAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAR;;;; 10E3;GEORGIAN LETTER UN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER UN;;;; 10E4;GEORGIAN LETTER PHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PHAR;;;; 10E5;GEORGIAN LETTER KHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KHAR;;;; 10E6;GEORGIAN LETTER GHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GHAN;;;; 10E7;GEORGIAN LETTER QAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER QAR;;;; 10E8;GEORGIAN LETTER SHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SHIN;;;; 10E9;GEORGIAN LETTER CHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHIN;;;; 10EA;GEORGIAN LETTER CAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CAN;;;; 10EB;GEORGIAN LETTER JIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JIL;;;; 10EC;GEORGIAN LETTER CIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CIL;;;; 10ED;GEORGIAN LETTER CHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHAR;;;; 10EE;GEORGIAN LETTER XAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER XAN;;;; 10EF;GEORGIAN LETTER JHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JHAN;;;; 10F0;GEORGIAN LETTER HAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAE;;;; 10F1;GEORGIAN LETTER HE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HE;;;; 10F2;GEORGIAN LETTER HIE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HIE;;;; 10F3;GEORGIAN LETTER WE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER WE;;;; 10F4;GEORGIAN LETTER HAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAR;;;; 10F5;GEORGIAN LETTER HOE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HOE;;;; 10F6;GEORGIAN LETTER FI;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;;; 10F7;GEORGIAN LETTER YN;Lo;0;L;;;;;N;;;;; 10F8;GEORGIAN LETTER ELIFI;Lo;0;L;;;;;N;;;;; 10FB;GEORGIAN PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;; 1100;HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;g *;;; 1101;HANGUL CHOSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;gg *;;; 1102;HANGUL CHOSEONG NIEUN;Lo;0;L;;;;;N;;n *;;; 1103;HANGUL CHOSEONG TIKEUT;Lo;0;L;;;;;N;;d *;;; 1104;HANGUL CHOSEONG SSANGTIKEUT;Lo;0;L;;;;;N;;dd *;;; 1105;HANGUL CHOSEONG RIEUL;Lo;0;L;;;;;N;;r *;;; 1106;HANGUL CHOSEONG MIEUM;Lo;0;L;;;;;N;;m *;;; 1107;HANGUL CHOSEONG PIEUP;Lo;0;L;;;;;N;;b *;;; 1108;HANGUL CHOSEONG SSANGPIEUP;Lo;0;L;;;;;N;;bb *;;; 1109;HANGUL CHOSEONG SIOS;Lo;0;L;;;;;N;;s *;;; 110A;HANGUL CHOSEONG SSANGSIOS;Lo;0;L;;;;;N;;ss *;;; 110B;HANGUL CHOSEONG IEUNG;Lo;0;L;;;;;N;;;;; 110C;HANGUL CHOSEONG CIEUC;Lo;0;L;;;;;N;;j *;;; 110D;HANGUL CHOSEONG SSANGCIEUC;Lo;0;L;;;;;N;;jj *;;; 110E;HANGUL CHOSEONG CHIEUCH;Lo;0;L;;;;;N;;c *;;; 110F;HANGUL CHOSEONG KHIEUKH;Lo;0;L;;;;;N;;k *;;; 1110;HANGUL CHOSEONG THIEUTH;Lo;0;L;;;;;N;;t *;;; 1111;HANGUL CHOSEONG PHIEUPH;Lo;0;L;;;;;N;;p *;;; 1112;HANGUL CHOSEONG HIEUH;Lo;0;L;;;;;N;;h *;;; 1113;HANGUL CHOSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;; 1114;HANGUL CHOSEONG SSANGNIEUN;Lo;0;L;;;;;N;;;;; 1115;HANGUL CHOSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;; 1116;HANGUL CHOSEONG NIEUN-PIEUP;Lo;0;L;;;;;N;;;;; 1117;HANGUL CHOSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;; 1118;HANGUL CHOSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;; 1119;HANGUL CHOSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;; 111A;HANGUL CHOSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;;;; 111B;HANGUL CHOSEONG KAPYEOUNRIEUL;Lo;0;L;;;;;N;;;;; 111C;HANGUL CHOSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;; 111D;HANGUL CHOSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;; 111E;HANGUL CHOSEONG PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;; 111F;HANGUL CHOSEONG PIEUP-NIEUN;Lo;0;L;;;;;N;;;;; 1120;HANGUL CHOSEONG PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;; 1121;HANGUL CHOSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;;;; 1122;HANGUL CHOSEONG PIEUP-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; 1123;HANGUL CHOSEONG PIEUP-SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; 1124;HANGUL CHOSEONG PIEUP-SIOS-PIEUP;Lo;0;L;;;;;N;;;;; 1125;HANGUL CHOSEONG PIEUP-SSANGSIOS;Lo;0;L;;;;;N;;;;; 1126;HANGUL CHOSEONG PIEUP-SIOS-CIEUC;Lo;0;L;;;;;N;;;;; 1127;HANGUL CHOSEONG PIEUP-CIEUC;Lo;0;L;;;;;N;;;;; 1128;HANGUL CHOSEONG PIEUP-CHIEUCH;Lo;0;L;;;;;N;;;;; 1129;HANGUL CHOSEONG PIEUP-THIEUTH;Lo;0;L;;;;;N;;;;; 112A;HANGUL CHOSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;; 112B;HANGUL CHOSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; 112C;HANGUL CHOSEONG KAPYEOUNSSANGPIEUP;Lo;0;L;;;;;N;;;;; 112D;HANGUL CHOSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; 112E;HANGUL CHOSEONG SIOS-NIEUN;Lo;0;L;;;;;N;;;;; 112F;HANGUL CHOSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; 1130;HANGUL CHOSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;; 1131;HANGUL CHOSEONG SIOS-MIEUM;Lo;0;L;;;;;N;;;;; 1132;HANGUL CHOSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;; 1133;HANGUL CHOSEONG SIOS-PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;; 1134;HANGUL CHOSEONG SIOS-SSANGSIOS;Lo;0;L;;;;;N;;;;; 1135;HANGUL CHOSEONG SIOS-IEUNG;Lo;0;L;;;;;N;;;;; 1136;HANGUL CHOSEONG SIOS-CIEUC;Lo;0;L;;;;;N;;;;; 1137;HANGUL CHOSEONG SIOS-CHIEUCH;Lo;0;L;;;;;N;;;;; 1138;HANGUL CHOSEONG SIOS-KHIEUKH;Lo;0;L;;;;;N;;;;; 1139;HANGUL CHOSEONG SIOS-THIEUTH;Lo;0;L;;;;;N;;;;; 113A;HANGUL CHOSEONG SIOS-PHIEUPH;Lo;0;L;;;;;N;;;;; 113B;HANGUL CHOSEONG SIOS-HIEUH;Lo;0;L;;;;;N;;;;; 113C;HANGUL CHOSEONG CHITUEUMSIOS;Lo;0;L;;;;;N;;;;; 113D;HANGUL CHOSEONG CHITUEUMSSANGSIOS;Lo;0;L;;;;;N;;;;; 113E;HANGUL CHOSEONG CEONGCHIEUMSIOS;Lo;0;L;;;;;N;;;;; 113F;HANGUL CHOSEONG CEONGCHIEUMSSANGSIOS;Lo;0;L;;;;;N;;;;; 1140;HANGUL CHOSEONG PANSIOS;Lo;0;L;;;;;N;;;;; 1141;HANGUL CHOSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;; 1142;HANGUL CHOSEONG IEUNG-TIKEUT;Lo;0;L;;;;;N;;;;; 1143;HANGUL CHOSEONG IEUNG-MIEUM;Lo;0;L;;;;;N;;;;; 1144;HANGUL CHOSEONG IEUNG-PIEUP;Lo;0;L;;;;;N;;;;; 1145;HANGUL CHOSEONG IEUNG-SIOS;Lo;0;L;;;;;N;;;;; 1146;HANGUL CHOSEONG IEUNG-PANSIOS;Lo;0;L;;;;;N;;;;; 1147;HANGUL CHOSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;; 1148;HANGUL CHOSEONG IEUNG-CIEUC;Lo;0;L;;;;;N;;;;; 1149;HANGUL CHOSEONG IEUNG-CHIEUCH;Lo;0;L;;;;;N;;;;; 114A;HANGUL CHOSEONG IEUNG-THIEUTH;Lo;0;L;;;;;N;;;;; 114B;HANGUL CHOSEONG IEUNG-PHIEUPH;Lo;0;L;;;;;N;;;;; 114C;HANGUL CHOSEONG YESIEUNG;Lo;0;L;;;;;N;;;;; 114D;HANGUL CHOSEONG CIEUC-IEUNG;Lo;0;L;;;;;N;;;;; 114E;HANGUL CHOSEONG CHITUEUMCIEUC;Lo;0;L;;;;;N;;;;; 114F;HANGUL CHOSEONG CHITUEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;; 1150;HANGUL CHOSEONG CEONGCHIEUMCIEUC;Lo;0;L;;;;;N;;;;; 1151;HANGUL CHOSEONG CEONGCHIEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;; 1152;HANGUL CHOSEONG CHIEUCH-KHIEUKH;Lo;0;L;;;;;N;;;;; 1153;HANGUL CHOSEONG CHIEUCH-HIEUH;Lo;0;L;;;;;N;;;;; 1154;HANGUL CHOSEONG CHITUEUMCHIEUCH;Lo;0;L;;;;;N;;;;; 1155;HANGUL CHOSEONG CEONGCHIEUMCHIEUCH;Lo;0;L;;;;;N;;;;; 1156;HANGUL CHOSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;; 1157;HANGUL CHOSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;; 1158;HANGUL CHOSEONG SSANGHIEUH;Lo;0;L;;;;;N;;;;; 1159;HANGUL CHOSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;; 115F;HANGUL CHOSEONG FILLER;Lo;0;L;;;;;N;;;;; 1160;HANGUL JUNGSEONG FILLER;Lo;0;L;;;;;N;;;;; 1161;HANGUL JUNGSEONG A;Lo;0;L;;;;;N;;;;; 1162;HANGUL JUNGSEONG AE;Lo;0;L;;;;;N;;;;; 1163;HANGUL JUNGSEONG YA;Lo;0;L;;;;;N;;;;; 1164;HANGUL JUNGSEONG YAE;Lo;0;L;;;;;N;;;;; 1165;HANGUL JUNGSEONG EO;Lo;0;L;;;;;N;;;;; 1166;HANGUL JUNGSEONG E;Lo;0;L;;;;;N;;;;; 1167;HANGUL JUNGSEONG YEO;Lo;0;L;;;;;N;;;;; 1168;HANGUL JUNGSEONG YE;Lo;0;L;;;;;N;;;;; 1169;HANGUL JUNGSEONG O;Lo;0;L;;;;;N;;;;; 116A;HANGUL JUNGSEONG WA;Lo;0;L;;;;;N;;;;; 116B;HANGUL JUNGSEONG WAE;Lo;0;L;;;;;N;;;;; 116C;HANGUL JUNGSEONG OE;Lo;0;L;;;;;N;;;;; 116D;HANGUL JUNGSEONG YO;Lo;0;L;;;;;N;;;;; 116E;HANGUL JUNGSEONG U;Lo;0;L;;;;;N;;;;; 116F;HANGUL JUNGSEONG WEO;Lo;0;L;;;;;N;;;;; 1170;HANGUL JUNGSEONG WE;Lo;0;L;;;;;N;;;;; 1171;HANGUL JUNGSEONG WI;Lo;0;L;;;;;N;;;;; 1172;HANGUL JUNGSEONG YU;Lo;0;L;;;;;N;;;;; 1173;HANGUL JUNGSEONG EU;Lo;0;L;;;;;N;;;;; 1174;HANGUL JUNGSEONG YI;Lo;0;L;;;;;N;;;;; 1175;HANGUL JUNGSEONG I;Lo;0;L;;;;;N;;;;; 1176;HANGUL JUNGSEONG A-O;Lo;0;L;;;;;N;;;;; 1177;HANGUL JUNGSEONG A-U;Lo;0;L;;;;;N;;;;; 1178;HANGUL JUNGSEONG YA-O;Lo;0;L;;;;;N;;;;; 1179;HANGUL JUNGSEONG YA-YO;Lo;0;L;;;;;N;;;;; 117A;HANGUL JUNGSEONG EO-O;Lo;0;L;;;;;N;;;;; 117B;HANGUL JUNGSEONG EO-U;Lo;0;L;;;;;N;;;;; 117C;HANGUL JUNGSEONG EO-EU;Lo;0;L;;;;;N;;;;; 117D;HANGUL JUNGSEONG YEO-O;Lo;0;L;;;;;N;;;;; 117E;HANGUL JUNGSEONG YEO-U;Lo;0;L;;;;;N;;;;; 117F;HANGUL JUNGSEONG O-EO;Lo;0;L;;;;;N;;;;; 1180;HANGUL JUNGSEONG O-E;Lo;0;L;;;;;N;;;;; 1181;HANGUL JUNGSEONG O-YE;Lo;0;L;;;;;N;;;;; 1182;HANGUL JUNGSEONG O-O;Lo;0;L;;;;;N;;;;; 1183;HANGUL JUNGSEONG O-U;Lo;0;L;;;;;N;;;;; 1184;HANGUL JUNGSEONG YO-YA;Lo;0;L;;;;;N;;;;; 1185;HANGUL JUNGSEONG YO-YAE;Lo;0;L;;;;;N;;;;; 1186;HANGUL JUNGSEONG YO-YEO;Lo;0;L;;;;;N;;;;; 1187;HANGUL JUNGSEONG YO-O;Lo;0;L;;;;;N;;;;; 1188;HANGUL JUNGSEONG YO-I;Lo;0;L;;;;;N;;;;; 1189;HANGUL JUNGSEONG U-A;Lo;0;L;;;;;N;;;;; 118A;HANGUL JUNGSEONG U-AE;Lo;0;L;;;;;N;;;;; 118B;HANGUL JUNGSEONG U-EO-EU;Lo;0;L;;;;;N;;;;; 118C;HANGUL JUNGSEONG U-YE;Lo;0;L;;;;;N;;;;; 118D;HANGUL JUNGSEONG U-U;Lo;0;L;;;;;N;;;;; 118E;HANGUL JUNGSEONG YU-A;Lo;0;L;;;;;N;;;;; 118F;HANGUL JUNGSEONG YU-EO;Lo;0;L;;;;;N;;;;; 1190;HANGUL JUNGSEONG YU-E;Lo;0;L;;;;;N;;;;; 1191;HANGUL JUNGSEONG YU-YEO;Lo;0;L;;;;;N;;;;; 1192;HANGUL JUNGSEONG YU-YE;Lo;0;L;;;;;N;;;;; 1193;HANGUL JUNGSEONG YU-U;Lo;0;L;;;;;N;;;;; 1194;HANGUL JUNGSEONG YU-I;Lo;0;L;;;;;N;;;;; 1195;HANGUL JUNGSEONG EU-U;Lo;0;L;;;;;N;;;;; 1196;HANGUL JUNGSEONG EU-EU;Lo;0;L;;;;;N;;;;; 1197;HANGUL JUNGSEONG YI-U;Lo;0;L;;;;;N;;;;; 1198;HANGUL JUNGSEONG I-A;Lo;0;L;;;;;N;;;;; 1199;HANGUL JUNGSEONG I-YA;Lo;0;L;;;;;N;;;;; 119A;HANGUL JUNGSEONG I-O;Lo;0;L;;;;;N;;;;; 119B;HANGUL JUNGSEONG I-U;Lo;0;L;;;;;N;;;;; 119C;HANGUL JUNGSEONG I-EU;Lo;0;L;;;;;N;;;;; 119D;HANGUL JUNGSEONG I-ARAEA;Lo;0;L;;;;;N;;;;; 119E;HANGUL JUNGSEONG ARAEA;Lo;0;L;;;;;N;;;;; 119F;HANGUL JUNGSEONG ARAEA-EO;Lo;0;L;;;;;N;;;;; 11A0;HANGUL JUNGSEONG ARAEA-U;Lo;0;L;;;;;N;;;;; 11A1;HANGUL JUNGSEONG ARAEA-I;Lo;0;L;;;;;N;;;;; 11A2;HANGUL JUNGSEONG SSANGARAEA;Lo;0;L;;;;;N;;;;; 11A8;HANGUL JONGSEONG KIYEOK;Lo;0;L;;;;;N;;g *;;; 11A9;HANGUL JONGSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;gg *;;; 11AA;HANGUL JONGSEONG KIYEOK-SIOS;Lo;0;L;;;;;N;;gs *;;; 11AB;HANGUL JONGSEONG NIEUN;Lo;0;L;;;;;N;;n *;;; 11AC;HANGUL JONGSEONG NIEUN-CIEUC;Lo;0;L;;;;;N;;nj *;;; 11AD;HANGUL JONGSEONG NIEUN-HIEUH;Lo;0;L;;;;;N;;nh *;;; 11AE;HANGUL JONGSEONG TIKEUT;Lo;0;L;;;;;N;;d *;;; 11AF;HANGUL JONGSEONG RIEUL;Lo;0;L;;;;;N;;l *;;; 11B0;HANGUL JONGSEONG RIEUL-KIYEOK;Lo;0;L;;;;;N;;lg *;;; 11B1;HANGUL JONGSEONG RIEUL-MIEUM;Lo;0;L;;;;;N;;lm *;;; 11B2;HANGUL JONGSEONG RIEUL-PIEUP;Lo;0;L;;;;;N;;lb *;;; 11B3;HANGUL JONGSEONG RIEUL-SIOS;Lo;0;L;;;;;N;;ls *;;; 11B4;HANGUL JONGSEONG RIEUL-THIEUTH;Lo;0;L;;;;;N;;lt *;;; 11B5;HANGUL JONGSEONG RIEUL-PHIEUPH;Lo;0;L;;;;;N;;lp *;;; 11B6;HANGUL JONGSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;lh *;;; 11B7;HANGUL JONGSEONG MIEUM;Lo;0;L;;;;;N;;m *;;; 11B8;HANGUL JONGSEONG PIEUP;Lo;0;L;;;;;N;;b *;;; 11B9;HANGUL JONGSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;bs *;;; 11BA;HANGUL JONGSEONG SIOS;Lo;0;L;;;;;N;;s *;;; 11BB;HANGUL JONGSEONG SSANGSIOS;Lo;0;L;;;;;N;;ss *;;; 11BC;HANGUL JONGSEONG IEUNG;Lo;0;L;;;;;N;;ng *;;; 11BD;HANGUL JONGSEONG CIEUC;Lo;0;L;;;;;N;;j *;;; 11BE;HANGUL JONGSEONG CHIEUCH;Lo;0;L;;;;;N;;c *;;; 11BF;HANGUL JONGSEONG KHIEUKH;Lo;0;L;;;;;N;;k *;;; 11C0;HANGUL JONGSEONG THIEUTH;Lo;0;L;;;;;N;;t *;;; 11C1;HANGUL JONGSEONG PHIEUPH;Lo;0;L;;;;;N;;p *;;; 11C2;HANGUL JONGSEONG HIEUH;Lo;0;L;;;;;N;;h *;;; 11C3;HANGUL JONGSEONG KIYEOK-RIEUL;Lo;0;L;;;;;N;;;;; 11C4;HANGUL JONGSEONG KIYEOK-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; 11C5;HANGUL JONGSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;; 11C6;HANGUL JONGSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;; 11C7;HANGUL JONGSEONG NIEUN-SIOS;Lo;0;L;;;;;N;;;;; 11C8;HANGUL JONGSEONG NIEUN-PANSIOS;Lo;0;L;;;;;N;;;;; 11C9;HANGUL JONGSEONG NIEUN-THIEUTH;Lo;0;L;;;;;N;;;;; 11CA;HANGUL JONGSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;; 11CB;HANGUL JONGSEONG TIKEUT-RIEUL;Lo;0;L;;;;;N;;;;; 11CC;HANGUL JONGSEONG RIEUL-KIYEOK-SIOS;Lo;0;L;;;;;N;;;;; 11CD;HANGUL JONGSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;; 11CE;HANGUL JONGSEONG RIEUL-TIKEUT;Lo;0;L;;;;;N;;;;; 11CF;HANGUL JONGSEONG RIEUL-TIKEUT-HIEUH;Lo;0;L;;;;;N;;;;; 11D0;HANGUL JONGSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;; 11D1;HANGUL JONGSEONG RIEUL-MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;; 11D2;HANGUL JONGSEONG RIEUL-MIEUM-SIOS;Lo;0;L;;;;;N;;;;; 11D3;HANGUL JONGSEONG RIEUL-PIEUP-SIOS;Lo;0;L;;;;;N;;;;; 11D4;HANGUL JONGSEONG RIEUL-PIEUP-HIEUH;Lo;0;L;;;;;N;;;;; 11D5;HANGUL JONGSEONG RIEUL-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; 11D6;HANGUL JONGSEONG RIEUL-SSANGSIOS;Lo;0;L;;;;;N;;;;; 11D7;HANGUL JONGSEONG RIEUL-PANSIOS;Lo;0;L;;;;;N;;;;; 11D8;HANGUL JONGSEONG RIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;; 11D9;HANGUL JONGSEONG RIEUL-YEORINHIEUH;Lo;0;L;;;;;N;;;;; 11DA;HANGUL JONGSEONG MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;; 11DB;HANGUL JONGSEONG MIEUM-RIEUL;Lo;0;L;;;;;N;;;;; 11DC;HANGUL JONGSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;; 11DD;HANGUL JONGSEONG MIEUM-SIOS;Lo;0;L;;;;;N;;;;; 11DE;HANGUL JONGSEONG MIEUM-SSANGSIOS;Lo;0;L;;;;;N;;;;; 11DF;HANGUL JONGSEONG MIEUM-PANSIOS;Lo;0;L;;;;;N;;;;; 11E0;HANGUL JONGSEONG MIEUM-CHIEUCH;Lo;0;L;;;;;N;;;;; 11E1;HANGUL JONGSEONG MIEUM-HIEUH;Lo;0;L;;;;;N;;;;; 11E2;HANGUL JONGSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;; 11E3;HANGUL JONGSEONG PIEUP-RIEUL;Lo;0;L;;;;;N;;;;; 11E4;HANGUL JONGSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;; 11E5;HANGUL JONGSEONG PIEUP-HIEUH;Lo;0;L;;;;;N;;;;; 11E6;HANGUL JONGSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; 11E7;HANGUL JONGSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; 11E8;HANGUL JONGSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; 11E9;HANGUL JONGSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;; 11EA;HANGUL JONGSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;; 11EB;HANGUL JONGSEONG PANSIOS;Lo;0;L;;;;;N;;;;; 11EC;HANGUL JONGSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;; 11ED;HANGUL JONGSEONG IEUNG-SSANGKIYEOK;Lo;0;L;;;;;N;;;;; 11EE;HANGUL JONGSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;; 11EF;HANGUL JONGSEONG IEUNG-KHIEUKH;Lo;0;L;;;;;N;;;;; 11F0;HANGUL JONGSEONG YESIEUNG;Lo;0;L;;;;;N;;;;; 11F1;HANGUL JONGSEONG YESIEUNG-SIOS;Lo;0;L;;;;;N;;;;; 11F2;HANGUL JONGSEONG YESIEUNG-PANSIOS;Lo;0;L;;;;;N;;;;; 11F3;HANGUL JONGSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;; 11F4;HANGUL JONGSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;; 11F5;HANGUL JONGSEONG HIEUH-NIEUN;Lo;0;L;;;;;N;;;;; 11F6;HANGUL JONGSEONG HIEUH-RIEUL;Lo;0;L;;;;;N;;;;; 11F7;HANGUL JONGSEONG HIEUH-MIEUM;Lo;0;L;;;;;N;;;;; 11F8;HANGUL JONGSEONG HIEUH-PIEUP;Lo;0;L;;;;;N;;;;; 11F9;HANGUL JONGSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;; 1200;ETHIOPIC SYLLABLE HA;Lo;0;L;;;;;N;;;;; 1201;ETHIOPIC SYLLABLE HU;Lo;0;L;;;;;N;;;;; 1202;ETHIOPIC SYLLABLE HI;Lo;0;L;;;;;N;;;;; 1203;ETHIOPIC SYLLABLE HAA;Lo;0;L;;;;;N;;;;; 1204;ETHIOPIC SYLLABLE HEE;Lo;0;L;;;;;N;;;;; 1205;ETHIOPIC SYLLABLE HE;Lo;0;L;;;;;N;;;;; 1206;ETHIOPIC SYLLABLE HO;Lo;0;L;;;;;N;;;;; 1208;ETHIOPIC SYLLABLE LA;Lo;0;L;;;;;N;;;;; 1209;ETHIOPIC SYLLABLE LU;Lo;0;L;;;;;N;;;;; 120A;ETHIOPIC SYLLABLE LI;Lo;0;L;;;;;N;;;;; 120B;ETHIOPIC SYLLABLE LAA;Lo;0;L;;;;;N;;;;; 120C;ETHIOPIC SYLLABLE LEE;Lo;0;L;;;;;N;;;;; 120D;ETHIOPIC SYLLABLE LE;Lo;0;L;;;;;N;;;;; 120E;ETHIOPIC SYLLABLE LO;Lo;0;L;;;;;N;;;;; 120F;ETHIOPIC SYLLABLE LWA;Lo;0;L;;;;;N;;;;; 1210;ETHIOPIC SYLLABLE HHA;Lo;0;L;;;;;N;;;;; 1211;ETHIOPIC SYLLABLE HHU;Lo;0;L;;;;;N;;;;; 1212;ETHIOPIC SYLLABLE HHI;Lo;0;L;;;;;N;;;;; 1213;ETHIOPIC SYLLABLE HHAA;Lo;0;L;;;;;N;;;;; 1214;ETHIOPIC SYLLABLE HHEE;Lo;0;L;;;;;N;;;;; 1215;ETHIOPIC SYLLABLE HHE;Lo;0;L;;;;;N;;;;; 1216;ETHIOPIC SYLLABLE HHO;Lo;0;L;;;;;N;;;;; 1217;ETHIOPIC SYLLABLE HHWA;Lo;0;L;;;;;N;;;;; 1218;ETHIOPIC SYLLABLE MA;Lo;0;L;;;;;N;;;;; 1219;ETHIOPIC SYLLABLE MU;Lo;0;L;;;;;N;;;;; 121A;ETHIOPIC SYLLABLE MI;Lo;0;L;;;;;N;;;;; 121B;ETHIOPIC SYLLABLE MAA;Lo;0;L;;;;;N;;;;; 121C;ETHIOPIC SYLLABLE MEE;Lo;0;L;;;;;N;;;;; 121D;ETHIOPIC SYLLABLE ME;Lo;0;L;;;;;N;;;;; 121E;ETHIOPIC SYLLABLE MO;Lo;0;L;;;;;N;;;;; 121F;ETHIOPIC SYLLABLE MWA;Lo;0;L;;;;;N;;;;; 1220;ETHIOPIC SYLLABLE SZA;Lo;0;L;;;;;N;;;;; 1221;ETHIOPIC SYLLABLE SZU;Lo;0;L;;;;;N;;;;; 1222;ETHIOPIC SYLLABLE SZI;Lo;0;L;;;;;N;;;;; 1223;ETHIOPIC SYLLABLE SZAA;Lo;0;L;;;;;N;;;;; 1224;ETHIOPIC SYLLABLE SZEE;Lo;0;L;;;;;N;;;;; 1225;ETHIOPIC SYLLABLE SZE;Lo;0;L;;;;;N;;;;; 1226;ETHIOPIC SYLLABLE SZO;Lo;0;L;;;;;N;;;;; 1227;ETHIOPIC SYLLABLE SZWA;Lo;0;L;;;;;N;;;;; 1228;ETHIOPIC SYLLABLE RA;Lo;0;L;;;;;N;;;;; 1229;ETHIOPIC SYLLABLE RU;Lo;0;L;;;;;N;;;;; 122A;ETHIOPIC SYLLABLE RI;Lo;0;L;;;;;N;;;;; 122B;ETHIOPIC SYLLABLE RAA;Lo;0;L;;;;;N;;;;; 122C;ETHIOPIC SYLLABLE REE;Lo;0;L;;;;;N;;;;; 122D;ETHIOPIC SYLLABLE RE;Lo;0;L;;;;;N;;;;; 122E;ETHIOPIC SYLLABLE RO;Lo;0;L;;;;;N;;;;; 122F;ETHIOPIC SYLLABLE RWA;Lo;0;L;;;;;N;;;;; 1230;ETHIOPIC SYLLABLE SA;Lo;0;L;;;;;N;;;;; 1231;ETHIOPIC SYLLABLE SU;Lo;0;L;;;;;N;;;;; 1232;ETHIOPIC SYLLABLE SI;Lo;0;L;;;;;N;;;;; 1233;ETHIOPIC SYLLABLE SAA;Lo;0;L;;;;;N;;;;; 1234;ETHIOPIC SYLLABLE SEE;Lo;0;L;;;;;N;;;;; 1235;ETHIOPIC SYLLABLE SE;Lo;0;L;;;;;N;;;;; 1236;ETHIOPIC SYLLABLE SO;Lo;0;L;;;;;N;;;;; 1237;ETHIOPIC SYLLABLE SWA;Lo;0;L;;;;;N;;;;; 1238;ETHIOPIC SYLLABLE SHA;Lo;0;L;;;;;N;;;;; 1239;ETHIOPIC SYLLABLE SHU;Lo;0;L;;;;;N;;;;; 123A;ETHIOPIC SYLLABLE SHI;Lo;0;L;;;;;N;;;;; 123B;ETHIOPIC SYLLABLE SHAA;Lo;0;L;;;;;N;;;;; 123C;ETHIOPIC SYLLABLE SHEE;Lo;0;L;;;;;N;;;;; 123D;ETHIOPIC SYLLABLE SHE;Lo;0;L;;;;;N;;;;; 123E;ETHIOPIC SYLLABLE SHO;Lo;0;L;;;;;N;;;;; 123F;ETHIOPIC SYLLABLE SHWA;Lo;0;L;;;;;N;;;;; 1240;ETHIOPIC SYLLABLE QA;Lo;0;L;;;;;N;;;;; 1241;ETHIOPIC SYLLABLE QU;Lo;0;L;;;;;N;;;;; 1242;ETHIOPIC SYLLABLE QI;Lo;0;L;;;;;N;;;;; 1243;ETHIOPIC SYLLABLE QAA;Lo;0;L;;;;;N;;;;; 1244;ETHIOPIC SYLLABLE QEE;Lo;0;L;;;;;N;;;;; 1245;ETHIOPIC SYLLABLE QE;Lo;0;L;;;;;N;;;;; 1246;ETHIOPIC SYLLABLE QO;Lo;0;L;;;;;N;;;;; 1248;ETHIOPIC SYLLABLE QWA;Lo;0;L;;;;;N;;;;; 124A;ETHIOPIC SYLLABLE QWI;Lo;0;L;;;;;N;;;;; 124B;ETHIOPIC SYLLABLE QWAA;Lo;0;L;;;;;N;;;;; 124C;ETHIOPIC SYLLABLE QWEE;Lo;0;L;;;;;N;;;;; 124D;ETHIOPIC SYLLABLE QWE;Lo;0;L;;;;;N;;;;; 1250;ETHIOPIC SYLLABLE QHA;Lo;0;L;;;;;N;;;;; 1251;ETHIOPIC SYLLABLE QHU;Lo;0;L;;;;;N;;;;; 1252;ETHIOPIC SYLLABLE QHI;Lo;0;L;;;;;N;;;;; 1253;ETHIOPIC SYLLABLE QHAA;Lo;0;L;;;;;N;;;;; 1254;ETHIOPIC SYLLABLE QHEE;Lo;0;L;;;;;N;;;;; 1255;ETHIOPIC SYLLABLE QHE;Lo;0;L;;;;;N;;;;; 1256;ETHIOPIC SYLLABLE QHO;Lo;0;L;;;;;N;;;;; 1258;ETHIOPIC SYLLABLE QHWA;Lo;0;L;;;;;N;;;;; 125A;ETHIOPIC SYLLABLE QHWI;Lo;0;L;;;;;N;;;;; 125B;ETHIOPIC SYLLABLE QHWAA;Lo;0;L;;;;;N;;;;; 125C;ETHIOPIC SYLLABLE QHWEE;Lo;0;L;;;;;N;;;;; 125D;ETHIOPIC SYLLABLE QHWE;Lo;0;L;;;;;N;;;;; 1260;ETHIOPIC SYLLABLE BA;Lo;0;L;;;;;N;;;;; 1261;ETHIOPIC SYLLABLE BU;Lo;0;L;;;;;N;;;;; 1262;ETHIOPIC SYLLABLE BI;Lo;0;L;;;;;N;;;;; 1263;ETHIOPIC SYLLABLE BAA;Lo;0;L;;;;;N;;;;; 1264;ETHIOPIC SYLLABLE BEE;Lo;0;L;;;;;N;;;;; 1265;ETHIOPIC SYLLABLE BE;Lo;0;L;;;;;N;;;;; 1266;ETHIOPIC SYLLABLE BO;Lo;0;L;;;;;N;;;;; 1267;ETHIOPIC SYLLABLE BWA;Lo;0;L;;;;;N;;;;; 1268;ETHIOPIC SYLLABLE VA;Lo;0;L;;;;;N;;;;; 1269;ETHIOPIC SYLLABLE VU;Lo;0;L;;;;;N;;;;; 126A;ETHIOPIC SYLLABLE VI;Lo;0;L;;;;;N;;;;; 126B;ETHIOPIC SYLLABLE VAA;Lo;0;L;;;;;N;;;;; 126C;ETHIOPIC SYLLABLE VEE;Lo;0;L;;;;;N;;;;; 126D;ETHIOPIC SYLLABLE VE;Lo;0;L;;;;;N;;;;; 126E;ETHIOPIC SYLLABLE VO;Lo;0;L;;;;;N;;;;; 126F;ETHIOPIC SYLLABLE VWA;Lo;0;L;;;;;N;;;;; 1270;ETHIOPIC SYLLABLE TA;Lo;0;L;;;;;N;;;;; 1271;ETHIOPIC SYLLABLE TU;Lo;0;L;;;;;N;;;;; 1272;ETHIOPIC SYLLABLE TI;Lo;0;L;;;;;N;;;;; 1273;ETHIOPIC SYLLABLE TAA;Lo;0;L;;;;;N;;;;; 1274;ETHIOPIC SYLLABLE TEE;Lo;0;L;;;;;N;;;;; 1275;ETHIOPIC SYLLABLE TE;Lo;0;L;;;;;N;;;;; 1276;ETHIOPIC SYLLABLE TO;Lo;0;L;;;;;N;;;;; 1277;ETHIOPIC SYLLABLE TWA;Lo;0;L;;;;;N;;;;; 1278;ETHIOPIC SYLLABLE CA;Lo;0;L;;;;;N;;;;; 1279;ETHIOPIC SYLLABLE CU;Lo;0;L;;;;;N;;;;; 127A;ETHIOPIC SYLLABLE CI;Lo;0;L;;;;;N;;;;; 127B;ETHIOPIC SYLLABLE CAA;Lo;0;L;;;;;N;;;;; 127C;ETHIOPIC SYLLABLE CEE;Lo;0;L;;;;;N;;;;; 127D;ETHIOPIC SYLLABLE CE;Lo;0;L;;;;;N;;;;; 127E;ETHIOPIC SYLLABLE CO;Lo;0;L;;;;;N;;;;; 127F;ETHIOPIC SYLLABLE CWA;Lo;0;L;;;;;N;;;;; 1280;ETHIOPIC SYLLABLE XA;Lo;0;L;;;;;N;;;;; 1281;ETHIOPIC SYLLABLE XU;Lo;0;L;;;;;N;;;;; 1282;ETHIOPIC SYLLABLE XI;Lo;0;L;;;;;N;;;;; 1283;ETHIOPIC SYLLABLE XAA;Lo;0;L;;;;;N;;;;; 1284;ETHIOPIC SYLLABLE XEE;Lo;0;L;;;;;N;;;;; 1285;ETHIOPIC SYLLABLE XE;Lo;0;L;;;;;N;;;;; 1286;ETHIOPIC SYLLABLE XO;Lo;0;L;;;;;N;;;;; 1288;ETHIOPIC SYLLABLE XWA;Lo;0;L;;;;;N;;;;; 128A;ETHIOPIC SYLLABLE XWI;Lo;0;L;;;;;N;;;;; 128B;ETHIOPIC SYLLABLE XWAA;Lo;0;L;;;;;N;;;;; 128C;ETHIOPIC SYLLABLE XWEE;Lo;0;L;;;;;N;;;;; 128D;ETHIOPIC SYLLABLE XWE;Lo;0;L;;;;;N;;;;; 1290;ETHIOPIC SYLLABLE NA;Lo;0;L;;;;;N;;;;; 1291;ETHIOPIC SYLLABLE NU;Lo;0;L;;;;;N;;;;; 1292;ETHIOPIC SYLLABLE NI;Lo;0;L;;;;;N;;;;; 1293;ETHIOPIC SYLLABLE NAA;Lo;0;L;;;;;N;;;;; 1294;ETHIOPIC SYLLABLE NEE;Lo;0;L;;;;;N;;;;; 1295;ETHIOPIC SYLLABLE NE;Lo;0;L;;;;;N;;;;; 1296;ETHIOPIC SYLLABLE NO;Lo;0;L;;;;;N;;;;; 1297;ETHIOPIC SYLLABLE NWA;Lo;0;L;;;;;N;;;;; 1298;ETHIOPIC SYLLABLE NYA;Lo;0;L;;;;;N;;;;; 1299;ETHIOPIC SYLLABLE NYU;Lo;0;L;;;;;N;;;;; 129A;ETHIOPIC SYLLABLE NYI;Lo;0;L;;;;;N;;;;; 129B;ETHIOPIC SYLLABLE NYAA;Lo;0;L;;;;;N;;;;; 129C;ETHIOPIC SYLLABLE NYEE;Lo;0;L;;;;;N;;;;; 129D;ETHIOPIC SYLLABLE NYE;Lo;0;L;;;;;N;;;;; 129E;ETHIOPIC SYLLABLE NYO;Lo;0;L;;;;;N;;;;; 129F;ETHIOPIC SYLLABLE NYWA;Lo;0;L;;;;;N;;;;; 12A0;ETHIOPIC SYLLABLE GLOTTAL A;Lo;0;L;;;;;N;;;;; 12A1;ETHIOPIC SYLLABLE GLOTTAL U;Lo;0;L;;;;;N;;;;; 12A2;ETHIOPIC SYLLABLE GLOTTAL I;Lo;0;L;;;;;N;;;;; 12A3;ETHIOPIC SYLLABLE GLOTTAL AA;Lo;0;L;;;;;N;;;;; 12A4;ETHIOPIC SYLLABLE GLOTTAL EE;Lo;0;L;;;;;N;;;;; 12A5;ETHIOPIC SYLLABLE GLOTTAL E;Lo;0;L;;;;;N;;;;; 12A6;ETHIOPIC SYLLABLE GLOTTAL O;Lo;0;L;;;;;N;;;;; 12A7;ETHIOPIC SYLLABLE GLOTTAL WA;Lo;0;L;;;;;N;;;;; 12A8;ETHIOPIC SYLLABLE KA;Lo;0;L;;;;;N;;;;; 12A9;ETHIOPIC SYLLABLE KU;Lo;0;L;;;;;N;;;;; 12AA;ETHIOPIC SYLLABLE KI;Lo;0;L;;;;;N;;;;; 12AB;ETHIOPIC SYLLABLE KAA;Lo;0;L;;;;;N;;;;; 12AC;ETHIOPIC SYLLABLE KEE;Lo;0;L;;;;;N;;;;; 12AD;ETHIOPIC SYLLABLE KE;Lo;0;L;;;;;N;;;;; 12AE;ETHIOPIC SYLLABLE KO;Lo;0;L;;;;;N;;;;; 12B0;ETHIOPIC SYLLABLE KWA;Lo;0;L;;;;;N;;;;; 12B2;ETHIOPIC SYLLABLE KWI;Lo;0;L;;;;;N;;;;; 12B3;ETHIOPIC SYLLABLE KWAA;Lo;0;L;;;;;N;;;;; 12B4;ETHIOPIC SYLLABLE KWEE;Lo;0;L;;;;;N;;;;; 12B5;ETHIOPIC SYLLABLE KWE;Lo;0;L;;;;;N;;;;; 12B8;ETHIOPIC SYLLABLE KXA;Lo;0;L;;;;;N;;;;; 12B9;ETHIOPIC SYLLABLE KXU;Lo;0;L;;;;;N;;;;; 12BA;ETHIOPIC SYLLABLE KXI;Lo;0;L;;;;;N;;;;; 12BB;ETHIOPIC SYLLABLE KXAA;Lo;0;L;;;;;N;;;;; 12BC;ETHIOPIC SYLLABLE KXEE;Lo;0;L;;;;;N;;;;; 12BD;ETHIOPIC SYLLABLE KXE;Lo;0;L;;;;;N;;;;; 12BE;ETHIOPIC SYLLABLE KXO;Lo;0;L;;;;;N;;;;; 12C0;ETHIOPIC SYLLABLE KXWA;Lo;0;L;;;;;N;;;;; 12C2;ETHIOPIC SYLLABLE KXWI;Lo;0;L;;;;;N;;;;; 12C3;ETHIOPIC SYLLABLE KXWAA;Lo;0;L;;;;;N;;;;; 12C4;ETHIOPIC SYLLABLE KXWEE;Lo;0;L;;;;;N;;;;; 12C5;ETHIOPIC SYLLABLE KXWE;Lo;0;L;;;;;N;;;;; 12C8;ETHIOPIC SYLLABLE WA;Lo;0;L;;;;;N;;;;; 12C9;ETHIOPIC SYLLABLE WU;Lo;0;L;;;;;N;;;;; 12CA;ETHIOPIC SYLLABLE WI;Lo;0;L;;;;;N;;;;; 12CB;ETHIOPIC SYLLABLE WAA;Lo;0;L;;;;;N;;;;; 12CC;ETHIOPIC SYLLABLE WEE;Lo;0;L;;;;;N;;;;; 12CD;ETHIOPIC SYLLABLE WE;Lo;0;L;;;;;N;;;;; 12CE;ETHIOPIC SYLLABLE WO;Lo;0;L;;;;;N;;;;; 12D0;ETHIOPIC SYLLABLE PHARYNGEAL A;Lo;0;L;;;;;N;;;;; 12D1;ETHIOPIC SYLLABLE PHARYNGEAL U;Lo;0;L;;;;;N;;;;; 12D2;ETHIOPIC SYLLABLE PHARYNGEAL I;Lo;0;L;;;;;N;;;;; 12D3;ETHIOPIC SYLLABLE PHARYNGEAL AA;Lo;0;L;;;;;N;;;;; 12D4;ETHIOPIC SYLLABLE PHARYNGEAL EE;Lo;0;L;;;;;N;;;;; 12D5;ETHIOPIC SYLLABLE PHARYNGEAL E;Lo;0;L;;;;;N;;;;; 12D6;ETHIOPIC SYLLABLE PHARYNGEAL O;Lo;0;L;;;;;N;;;;; 12D8;ETHIOPIC SYLLABLE ZA;Lo;0;L;;;;;N;;;;; 12D9;ETHIOPIC SYLLABLE ZU;Lo;0;L;;;;;N;;;;; 12DA;ETHIOPIC SYLLABLE ZI;Lo;0;L;;;;;N;;;;; 12DB;ETHIOPIC SYLLABLE ZAA;Lo;0;L;;;;;N;;;;; 12DC;ETHIOPIC SYLLABLE ZEE;Lo;0;L;;;;;N;;;;; 12DD;ETHIOPIC SYLLABLE ZE;Lo;0;L;;;;;N;;;;; 12DE;ETHIOPIC SYLLABLE ZO;Lo;0;L;;;;;N;;;;; 12DF;ETHIOPIC SYLLABLE ZWA;Lo;0;L;;;;;N;;;;; 12E0;ETHIOPIC SYLLABLE ZHA;Lo;0;L;;;;;N;;;;; 12E1;ETHIOPIC SYLLABLE ZHU;Lo;0;L;;;;;N;;;;; 12E2;ETHIOPIC SYLLABLE ZHI;Lo;0;L;;;;;N;;;;; 12E3;ETHIOPIC SYLLABLE ZHAA;Lo;0;L;;;;;N;;;;; 12E4;ETHIOPIC SYLLABLE ZHEE;Lo;0;L;;;;;N;;;;; 12E5;ETHIOPIC SYLLABLE ZHE;Lo;0;L;;;;;N;;;;; 12E6;ETHIOPIC SYLLABLE ZHO;Lo;0;L;;;;;N;;;;; 12E7;ETHIOPIC SYLLABLE ZHWA;Lo;0;L;;;;;N;;;;; 12E8;ETHIOPIC SYLLABLE YA;Lo;0;L;;;;;N;;;;; 12E9;ETHIOPIC SYLLABLE YU;Lo;0;L;;;;;N;;;;; 12EA;ETHIOPIC SYLLABLE YI;Lo;0;L;;;;;N;;;;; 12EB;ETHIOPIC SYLLABLE YAA;Lo;0;L;;;;;N;;;;; 12EC;ETHIOPIC SYLLABLE YEE;Lo;0;L;;;;;N;;;;; 12ED;ETHIOPIC SYLLABLE YE;Lo;0;L;;;;;N;;;;; 12EE;ETHIOPIC SYLLABLE YO;Lo;0;L;;;;;N;;;;; 12F0;ETHIOPIC SYLLABLE DA;Lo;0;L;;;;;N;;;;; 12F1;ETHIOPIC SYLLABLE DU;Lo;0;L;;;;;N;;;;; 12F2;ETHIOPIC SYLLABLE DI;Lo;0;L;;;;;N;;;;; 12F3;ETHIOPIC SYLLABLE DAA;Lo;0;L;;;;;N;;;;; 12F4;ETHIOPIC SYLLABLE DEE;Lo;0;L;;;;;N;;;;; 12F5;ETHIOPIC SYLLABLE DE;Lo;0;L;;;;;N;;;;; 12F6;ETHIOPIC SYLLABLE DO;Lo;0;L;;;;;N;;;;; 12F7;ETHIOPIC SYLLABLE DWA;Lo;0;L;;;;;N;;;;; 12F8;ETHIOPIC SYLLABLE DDA;Lo;0;L;;;;;N;;;;; 12F9;ETHIOPIC SYLLABLE DDU;Lo;0;L;;;;;N;;;;; 12FA;ETHIOPIC SYLLABLE DDI;Lo;0;L;;;;;N;;;;; 12FB;ETHIOPIC SYLLABLE DDAA;Lo;0;L;;;;;N;;;;; 12FC;ETHIOPIC SYLLABLE DDEE;Lo;0;L;;;;;N;;;;; 12FD;ETHIOPIC SYLLABLE DDE;Lo;0;L;;;;;N;;;;; 12FE;ETHIOPIC SYLLABLE DDO;Lo;0;L;;;;;N;;;;; 12FF;ETHIOPIC SYLLABLE DDWA;Lo;0;L;;;;;N;;;;; 1300;ETHIOPIC SYLLABLE JA;Lo;0;L;;;;;N;;;;; 1301;ETHIOPIC SYLLABLE JU;Lo;0;L;;;;;N;;;;; 1302;ETHIOPIC SYLLABLE JI;Lo;0;L;;;;;N;;;;; 1303;ETHIOPIC SYLLABLE JAA;Lo;0;L;;;;;N;;;;; 1304;ETHIOPIC SYLLABLE JEE;Lo;0;L;;;;;N;;;;; 1305;ETHIOPIC SYLLABLE JE;Lo;0;L;;;;;N;;;;; 1306;ETHIOPIC SYLLABLE JO;Lo;0;L;;;;;N;;;;; 1307;ETHIOPIC SYLLABLE JWA;Lo;0;L;;;;;N;;;;; 1308;ETHIOPIC SYLLABLE GA;Lo;0;L;;;;;N;;;;; 1309;ETHIOPIC SYLLABLE GU;Lo;0;L;;;;;N;;;;; 130A;ETHIOPIC SYLLABLE GI;Lo;0;L;;;;;N;;;;; 130B;ETHIOPIC SYLLABLE GAA;Lo;0;L;;;;;N;;;;; 130C;ETHIOPIC SYLLABLE GEE;Lo;0;L;;;;;N;;;;; 130D;ETHIOPIC SYLLABLE GE;Lo;0;L;;;;;N;;;;; 130E;ETHIOPIC SYLLABLE GO;Lo;0;L;;;;;N;;;;; 1310;ETHIOPIC SYLLABLE GWA;Lo;0;L;;;;;N;;;;; 1312;ETHIOPIC SYLLABLE GWI;Lo;0;L;;;;;N;;;;; 1313;ETHIOPIC SYLLABLE GWAA;Lo;0;L;;;;;N;;;;; 1314;ETHIOPIC SYLLABLE GWEE;Lo;0;L;;;;;N;;;;; 1315;ETHIOPIC SYLLABLE GWE;Lo;0;L;;;;;N;;;;; 1318;ETHIOPIC SYLLABLE GGA;Lo;0;L;;;;;N;;;;; 1319;ETHIOPIC SYLLABLE GGU;Lo;0;L;;;;;N;;;;; 131A;ETHIOPIC SYLLABLE GGI;Lo;0;L;;;;;N;;;;; 131B;ETHIOPIC SYLLABLE GGAA;Lo;0;L;;;;;N;;;;; 131C;ETHIOPIC SYLLABLE GGEE;Lo;0;L;;;;;N;;;;; 131D;ETHIOPIC SYLLABLE GGE;Lo;0;L;;;;;N;;;;; 131E;ETHIOPIC SYLLABLE GGO;Lo;0;L;;;;;N;;;;; 1320;ETHIOPIC SYLLABLE THA;Lo;0;L;;;;;N;;;;; 1321;ETHIOPIC SYLLABLE THU;Lo;0;L;;;;;N;;;;; 1322;ETHIOPIC SYLLABLE THI;Lo;0;L;;;;;N;;;;; 1323;ETHIOPIC SYLLABLE THAA;Lo;0;L;;;;;N;;;;; 1324;ETHIOPIC SYLLABLE THEE;Lo;0;L;;;;;N;;;;; 1325;ETHIOPIC SYLLABLE THE;Lo;0;L;;;;;N;;;;; 1326;ETHIOPIC SYLLABLE THO;Lo;0;L;;;;;N;;;;; 1327;ETHIOPIC SYLLABLE THWA;Lo;0;L;;;;;N;;;;; 1328;ETHIOPIC SYLLABLE CHA;Lo;0;L;;;;;N;;;;; 1329;ETHIOPIC SYLLABLE CHU;Lo;0;L;;;;;N;;;;; 132A;ETHIOPIC SYLLABLE CHI;Lo;0;L;;;;;N;;;;; 132B;ETHIOPIC SYLLABLE CHAA;Lo;0;L;;;;;N;;;;; 132C;ETHIOPIC SYLLABLE CHEE;Lo;0;L;;;;;N;;;;; 132D;ETHIOPIC SYLLABLE CHE;Lo;0;L;;;;;N;;;;; 132E;ETHIOPIC SYLLABLE CHO;Lo;0;L;;;;;N;;;;; 132F;ETHIOPIC SYLLABLE CHWA;Lo;0;L;;;;;N;;;;; 1330;ETHIOPIC SYLLABLE PHA;Lo;0;L;;;;;N;;;;; 1331;ETHIOPIC SYLLABLE PHU;Lo;0;L;;;;;N;;;;; 1332;ETHIOPIC SYLLABLE PHI;Lo;0;L;;;;;N;;;;; 1333;ETHIOPIC SYLLABLE PHAA;Lo;0;L;;;;;N;;;;; 1334;ETHIOPIC SYLLABLE PHEE;Lo;0;L;;;;;N;;;;; 1335;ETHIOPIC SYLLABLE PHE;Lo;0;L;;;;;N;;;;; 1336;ETHIOPIC SYLLABLE PHO;Lo;0;L;;;;;N;;;;; 1337;ETHIOPIC SYLLABLE PHWA;Lo;0;L;;;;;N;;;;; 1338;ETHIOPIC SYLLABLE TSA;Lo;0;L;;;;;N;;;;; 1339;ETHIOPIC SYLLABLE TSU;Lo;0;L;;;;;N;;;;; 133A;ETHIOPIC SYLLABLE TSI;Lo;0;L;;;;;N;;;;; 133B;ETHIOPIC SYLLABLE TSAA;Lo;0;L;;;;;N;;;;; 133C;ETHIOPIC SYLLABLE TSEE;Lo;0;L;;;;;N;;;;; 133D;ETHIOPIC SYLLABLE TSE;Lo;0;L;;;;;N;;;;; 133E;ETHIOPIC SYLLABLE TSO;Lo;0;L;;;;;N;;;;; 133F;ETHIOPIC SYLLABLE TSWA;Lo;0;L;;;;;N;;;;; 1340;ETHIOPIC SYLLABLE TZA;Lo;0;L;;;;;N;;;;; 1341;ETHIOPIC SYLLABLE TZU;Lo;0;L;;;;;N;;;;; 1342;ETHIOPIC SYLLABLE TZI;Lo;0;L;;;;;N;;;;; 1343;ETHIOPIC SYLLABLE TZAA;Lo;0;L;;;;;N;;;;; 1344;ETHIOPIC SYLLABLE TZEE;Lo;0;L;;;;;N;;;;; 1345;ETHIOPIC SYLLABLE TZE;Lo;0;L;;;;;N;;;;; 1346;ETHIOPIC SYLLABLE TZO;Lo;0;L;;;;;N;;;;; 1348;ETHIOPIC SYLLABLE FA;Lo;0;L;;;;;N;;;;; 1349;ETHIOPIC SYLLABLE FU;Lo;0;L;;;;;N;;;;; 134A;ETHIOPIC SYLLABLE FI;Lo;0;L;;;;;N;;;;; 134B;ETHIOPIC SYLLABLE FAA;Lo;0;L;;;;;N;;;;; 134C;ETHIOPIC SYLLABLE FEE;Lo;0;L;;;;;N;;;;; 134D;ETHIOPIC SYLLABLE FE;Lo;0;L;;;;;N;;;;; 134E;ETHIOPIC SYLLABLE FO;Lo;0;L;;;;;N;;;;; 134F;ETHIOPIC SYLLABLE FWA;Lo;0;L;;;;;N;;;;; 1350;ETHIOPIC SYLLABLE PA;Lo;0;L;;;;;N;;;;; 1351;ETHIOPIC SYLLABLE PU;Lo;0;L;;;;;N;;;;; 1352;ETHIOPIC SYLLABLE PI;Lo;0;L;;;;;N;;;;; 1353;ETHIOPIC SYLLABLE PAA;Lo;0;L;;;;;N;;;;; 1354;ETHIOPIC SYLLABLE PEE;Lo;0;L;;;;;N;;;;; 1355;ETHIOPIC SYLLABLE PE;Lo;0;L;;;;;N;;;;; 1356;ETHIOPIC SYLLABLE PO;Lo;0;L;;;;;N;;;;; 1357;ETHIOPIC SYLLABLE PWA;Lo;0;L;;;;;N;;;;; 1358;ETHIOPIC SYLLABLE RYA;Lo;0;L;;;;;N;;;;; 1359;ETHIOPIC SYLLABLE MYA;Lo;0;L;;;;;N;;;;; 135A;ETHIOPIC SYLLABLE FYA;Lo;0;L;;;;;N;;;;; 1361;ETHIOPIC WORDSPACE;Po;0;L;;;;;N;;;;; 1362;ETHIOPIC FULL STOP;Po;0;L;;;;;N;;;;; 1363;ETHIOPIC COMMA;Po;0;L;;;;;N;;;;; 1364;ETHIOPIC SEMICOLON;Po;0;L;;;;;N;;;;; 1365;ETHIOPIC COLON;Po;0;L;;;;;N;;;;; 1366;ETHIOPIC PREFACE COLON;Po;0;L;;;;;N;;;;; 1367;ETHIOPIC QUESTION MARK;Po;0;L;;;;;N;;;;; 1368;ETHIOPIC PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;; 1369;ETHIOPIC DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 136A;ETHIOPIC DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 136B;ETHIOPIC DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; 136C;ETHIOPIC DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; 136D;ETHIOPIC DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; 136E;ETHIOPIC DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; 136F;ETHIOPIC DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 1370;ETHIOPIC DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 1371;ETHIOPIC DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 1372;ETHIOPIC NUMBER TEN;No;0;L;;;;10;N;;;;; 1373;ETHIOPIC NUMBER TWENTY;No;0;L;;;;20;N;;;;; 1374;ETHIOPIC NUMBER THIRTY;No;0;L;;;;30;N;;;;; 1375;ETHIOPIC NUMBER FORTY;No;0;L;;;;40;N;;;;; 1376;ETHIOPIC NUMBER FIFTY;No;0;L;;;;50;N;;;;; 1377;ETHIOPIC NUMBER SIXTY;No;0;L;;;;60;N;;;;; 1378;ETHIOPIC NUMBER SEVENTY;No;0;L;;;;70;N;;;;; 1379;ETHIOPIC NUMBER EIGHTY;No;0;L;;;;80;N;;;;; 137A;ETHIOPIC NUMBER NINETY;No;0;L;;;;90;N;;;;; 137B;ETHIOPIC NUMBER HUNDRED;No;0;L;;;;100;N;;;;; 137C;ETHIOPIC NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;; 13A0;CHEROKEE LETTER A;Lo;0;L;;;;;N;;;;; 13A1;CHEROKEE LETTER E;Lo;0;L;;;;;N;;;;; 13A2;CHEROKEE LETTER I;Lo;0;L;;;;;N;;;;; 13A3;CHEROKEE LETTER O;Lo;0;L;;;;;N;;;;; 13A4;CHEROKEE LETTER U;Lo;0;L;;;;;N;;;;; 13A5;CHEROKEE LETTER V;Lo;0;L;;;;;N;;;;; 13A6;CHEROKEE LETTER GA;Lo;0;L;;;;;N;;;;; 13A7;CHEROKEE LETTER KA;Lo;0;L;;;;;N;;;;; 13A8;CHEROKEE LETTER GE;Lo;0;L;;;;;N;;;;; 13A9;CHEROKEE LETTER GI;Lo;0;L;;;;;N;;;;; 13AA;CHEROKEE LETTER GO;Lo;0;L;;;;;N;;;;; 13AB;CHEROKEE LETTER GU;Lo;0;L;;;;;N;;;;; 13AC;CHEROKEE LETTER GV;Lo;0;L;;;;;N;;;;; 13AD;CHEROKEE LETTER HA;Lo;0;L;;;;;N;;;;; 13AE;CHEROKEE LETTER HE;Lo;0;L;;;;;N;;;;; 13AF;CHEROKEE LETTER HI;Lo;0;L;;;;;N;;;;; 13B0;CHEROKEE LETTER HO;Lo;0;L;;;;;N;;;;; 13B1;CHEROKEE LETTER HU;Lo;0;L;;;;;N;;;;; 13B2;CHEROKEE LETTER HV;Lo;0;L;;;;;N;;;;; 13B3;CHEROKEE LETTER LA;Lo;0;L;;;;;N;;;;; 13B4;CHEROKEE LETTER LE;Lo;0;L;;;;;N;;;;; 13B5;CHEROKEE LETTER LI;Lo;0;L;;;;;N;;;;; 13B6;CHEROKEE LETTER LO;Lo;0;L;;;;;N;;;;; 13B7;CHEROKEE LETTER LU;Lo;0;L;;;;;N;;;;; 13B8;CHEROKEE LETTER LV;Lo;0;L;;;;;N;;;;; 13B9;CHEROKEE LETTER MA;Lo;0;L;;;;;N;;;;; 13BA;CHEROKEE LETTER ME;Lo;0;L;;;;;N;;;;; 13BB;CHEROKEE LETTER MI;Lo;0;L;;;;;N;;;;; 13BC;CHEROKEE LETTER MO;Lo;0;L;;;;;N;;;;; 13BD;CHEROKEE LETTER MU;Lo;0;L;;;;;N;;;;; 13BE;CHEROKEE LETTER NA;Lo;0;L;;;;;N;;;;; 13BF;CHEROKEE LETTER HNA;Lo;0;L;;;;;N;;;;; 13C0;CHEROKEE LETTER NAH;Lo;0;L;;;;;N;;;;; 13C1;CHEROKEE LETTER NE;Lo;0;L;;;;;N;;;;; 13C2;CHEROKEE LETTER NI;Lo;0;L;;;;;N;;;;; 13C3;CHEROKEE LETTER NO;Lo;0;L;;;;;N;;;;; 13C4;CHEROKEE LETTER NU;Lo;0;L;;;;;N;;;;; 13C5;CHEROKEE LETTER NV;Lo;0;L;;;;;N;;;;; 13C6;CHEROKEE LETTER QUA;Lo;0;L;;;;;N;;;;; 13C7;CHEROKEE LETTER QUE;Lo;0;L;;;;;N;;;;; 13C8;CHEROKEE LETTER QUI;Lo;0;L;;;;;N;;;;; 13C9;CHEROKEE LETTER QUO;Lo;0;L;;;;;N;;;;; 13CA;CHEROKEE LETTER QUU;Lo;0;L;;;;;N;;;;; 13CB;CHEROKEE LETTER QUV;Lo;0;L;;;;;N;;;;; 13CC;CHEROKEE LETTER SA;Lo;0;L;;;;;N;;;;; 13CD;CHEROKEE LETTER S;Lo;0;L;;;;;N;;;;; 13CE;CHEROKEE LETTER SE;Lo;0;L;;;;;N;;;;; 13CF;CHEROKEE LETTER SI;Lo;0;L;;;;;N;;;;; 13D0;CHEROKEE LETTER SO;Lo;0;L;;;;;N;;;;; 13D1;CHEROKEE LETTER SU;Lo;0;L;;;;;N;;;;; 13D2;CHEROKEE LETTER SV;Lo;0;L;;;;;N;;;;; 13D3;CHEROKEE LETTER DA;Lo;0;L;;;;;N;;;;; 13D4;CHEROKEE LETTER TA;Lo;0;L;;;;;N;;;;; 13D5;CHEROKEE LETTER DE;Lo;0;L;;;;;N;;;;; 13D6;CHEROKEE LETTER TE;Lo;0;L;;;;;N;;;;; 13D7;CHEROKEE LETTER DI;Lo;0;L;;;;;N;;;;; 13D8;CHEROKEE LETTER TI;Lo;0;L;;;;;N;;;;; 13D9;CHEROKEE LETTER DO;Lo;0;L;;;;;N;;;;; 13DA;CHEROKEE LETTER DU;Lo;0;L;;;;;N;;;;; 13DB;CHEROKEE LETTER DV;Lo;0;L;;;;;N;;;;; 13DC;CHEROKEE LETTER DLA;Lo;0;L;;;;;N;;;;; 13DD;CHEROKEE LETTER TLA;Lo;0;L;;;;;N;;;;; 13DE;CHEROKEE LETTER TLE;Lo;0;L;;;;;N;;;;; 13DF;CHEROKEE LETTER TLI;Lo;0;L;;;;;N;;;;; 13E0;CHEROKEE LETTER TLO;Lo;0;L;;;;;N;;;;; 13E1;CHEROKEE LETTER TLU;Lo;0;L;;;;;N;;;;; 13E2;CHEROKEE LETTER TLV;Lo;0;L;;;;;N;;;;; 13E3;CHEROKEE LETTER TSA;Lo;0;L;;;;;N;;;;; 13E4;CHEROKEE LETTER TSE;Lo;0;L;;;;;N;;;;; 13E5;CHEROKEE LETTER TSI;Lo;0;L;;;;;N;;;;; 13E6;CHEROKEE LETTER TSO;Lo;0;L;;;;;N;;;;; 13E7;CHEROKEE LETTER TSU;Lo;0;L;;;;;N;;;;; 13E8;CHEROKEE LETTER TSV;Lo;0;L;;;;;N;;;;; 13E9;CHEROKEE LETTER WA;Lo;0;L;;;;;N;;;;; 13EA;CHEROKEE LETTER WE;Lo;0;L;;;;;N;;;;; 13EB;CHEROKEE LETTER WI;Lo;0;L;;;;;N;;;;; 13EC;CHEROKEE LETTER WO;Lo;0;L;;;;;N;;;;; 13ED;CHEROKEE LETTER WU;Lo;0;L;;;;;N;;;;; 13EE;CHEROKEE LETTER WV;Lo;0;L;;;;;N;;;;; 13EF;CHEROKEE LETTER YA;Lo;0;L;;;;;N;;;;; 13F0;CHEROKEE LETTER YE;Lo;0;L;;;;;N;;;;; 13F1;CHEROKEE LETTER YI;Lo;0;L;;;;;N;;;;; 13F2;CHEROKEE LETTER YO;Lo;0;L;;;;;N;;;;; 13F3;CHEROKEE LETTER YU;Lo;0;L;;;;;N;;;;; 13F4;CHEROKEE LETTER YV;Lo;0;L;;;;;N;;;;; 1401;CANADIAN SYLLABICS E;Lo;0;L;;;;;N;;;;; 1402;CANADIAN SYLLABICS AAI;Lo;0;L;;;;;N;;;;; 1403;CANADIAN SYLLABICS I;Lo;0;L;;;;;N;;;;; 1404;CANADIAN SYLLABICS II;Lo;0;L;;;;;N;;;;; 1405;CANADIAN SYLLABICS O;Lo;0;L;;;;;N;;;;; 1406;CANADIAN SYLLABICS OO;Lo;0;L;;;;;N;;;;; 1407;CANADIAN SYLLABICS Y-CREE OO;Lo;0;L;;;;;N;;;;; 1408;CANADIAN SYLLABICS CARRIER EE;Lo;0;L;;;;;N;;;;; 1409;CANADIAN SYLLABICS CARRIER I;Lo;0;L;;;;;N;;;;; 140A;CANADIAN SYLLABICS A;Lo;0;L;;;;;N;;;;; 140B;CANADIAN SYLLABICS AA;Lo;0;L;;;;;N;;;;; 140C;CANADIAN SYLLABICS WE;Lo;0;L;;;;;N;;;;; 140D;CANADIAN SYLLABICS WEST-CREE WE;Lo;0;L;;;;;N;;;;; 140E;CANADIAN SYLLABICS WI;Lo;0;L;;;;;N;;;;; 140F;CANADIAN SYLLABICS WEST-CREE WI;Lo;0;L;;;;;N;;;;; 1410;CANADIAN SYLLABICS WII;Lo;0;L;;;;;N;;;;; 1411;CANADIAN SYLLABICS WEST-CREE WII;Lo;0;L;;;;;N;;;;; 1412;CANADIAN SYLLABICS WO;Lo;0;L;;;;;N;;;;; 1413;CANADIAN SYLLABICS WEST-CREE WO;Lo;0;L;;;;;N;;;;; 1414;CANADIAN SYLLABICS WOO;Lo;0;L;;;;;N;;;;; 1415;CANADIAN SYLLABICS WEST-CREE WOO;Lo;0;L;;;;;N;;;;; 1416;CANADIAN SYLLABICS NASKAPI WOO;Lo;0;L;;;;;N;;;;; 1417;CANADIAN SYLLABICS WA;Lo;0;L;;;;;N;;;;; 1418;CANADIAN SYLLABICS WEST-CREE WA;Lo;0;L;;;;;N;;;;; 1419;CANADIAN SYLLABICS WAA;Lo;0;L;;;;;N;;;;; 141A;CANADIAN SYLLABICS WEST-CREE WAA;Lo;0;L;;;;;N;;;;; 141B;CANADIAN SYLLABICS NASKAPI WAA;Lo;0;L;;;;;N;;;;; 141C;CANADIAN SYLLABICS AI;Lo;0;L;;;;;N;;;;; 141D;CANADIAN SYLLABICS Y-CREE W;Lo;0;L;;;;;N;;;;; 141E;CANADIAN SYLLABICS GLOTTAL STOP;Lo;0;L;;;;;N;;;;; 141F;CANADIAN SYLLABICS FINAL ACUTE;Lo;0;L;;;;;N;;;;; 1420;CANADIAN SYLLABICS FINAL GRAVE;Lo;0;L;;;;;N;;;;; 1421;CANADIAN SYLLABICS FINAL BOTTOM HALF RING;Lo;0;L;;;;;N;;;;; 1422;CANADIAN SYLLABICS FINAL TOP HALF RING;Lo;0;L;;;;;N;;;;; 1423;CANADIAN SYLLABICS FINAL RIGHT HALF RING;Lo;0;L;;;;;N;;;;; 1424;CANADIAN SYLLABICS FINAL RING;Lo;0;L;;;;;N;;;;; 1425;CANADIAN SYLLABICS FINAL DOUBLE ACUTE;Lo;0;L;;;;;N;;;;; 1426;CANADIAN SYLLABICS FINAL DOUBLE SHORT VERTICAL STROKES;Lo;0;L;;;;;N;;;;; 1427;CANADIAN SYLLABICS FINAL MIDDLE DOT;Lo;0;L;;;;;N;;;;; 1428;CANADIAN SYLLABICS FINAL SHORT HORIZONTAL STROKE;Lo;0;L;;;;;N;;;;; 1429;CANADIAN SYLLABICS FINAL PLUS;Lo;0;L;;;;;N;;;;; 142A;CANADIAN SYLLABICS FINAL DOWN TACK;Lo;0;L;;;;;N;;;;; 142B;CANADIAN SYLLABICS EN;Lo;0;L;;;;;N;;;;; 142C;CANADIAN SYLLABICS IN;Lo;0;L;;;;;N;;;;; 142D;CANADIAN SYLLABICS ON;Lo;0;L;;;;;N;;;;; 142E;CANADIAN SYLLABICS AN;Lo;0;L;;;;;N;;;;; 142F;CANADIAN SYLLABICS PE;Lo;0;L;;;;;N;;;;; 1430;CANADIAN SYLLABICS PAAI;Lo;0;L;;;;;N;;;;; 1431;CANADIAN SYLLABICS PI;Lo;0;L;;;;;N;;;;; 1432;CANADIAN SYLLABICS PII;Lo;0;L;;;;;N;;;;; 1433;CANADIAN SYLLABICS PO;Lo;0;L;;;;;N;;;;; 1434;CANADIAN SYLLABICS POO;Lo;0;L;;;;;N;;;;; 1435;CANADIAN SYLLABICS Y-CREE POO;Lo;0;L;;;;;N;;;;; 1436;CANADIAN SYLLABICS CARRIER HEE;Lo;0;L;;;;;N;;;;; 1437;CANADIAN SYLLABICS CARRIER HI;Lo;0;L;;;;;N;;;;; 1438;CANADIAN SYLLABICS PA;Lo;0;L;;;;;N;;;;; 1439;CANADIAN SYLLABICS PAA;Lo;0;L;;;;;N;;;;; 143A;CANADIAN SYLLABICS PWE;Lo;0;L;;;;;N;;;;; 143B;CANADIAN SYLLABICS WEST-CREE PWE;Lo;0;L;;;;;N;;;;; 143C;CANADIAN SYLLABICS PWI;Lo;0;L;;;;;N;;;;; 143D;CANADIAN SYLLABICS WEST-CREE PWI;Lo;0;L;;;;;N;;;;; 143E;CANADIAN SYLLABICS PWII;Lo;0;L;;;;;N;;;;; 143F;CANADIAN SYLLABICS WEST-CREE PWII;Lo;0;L;;;;;N;;;;; 1440;CANADIAN SYLLABICS PWO;Lo;0;L;;;;;N;;;;; 1441;CANADIAN SYLLABICS WEST-CREE PWO;Lo;0;L;;;;;N;;;;; 1442;CANADIAN SYLLABICS PWOO;Lo;0;L;;;;;N;;;;; 1443;CANADIAN SYLLABICS WEST-CREE PWOO;Lo;0;L;;;;;N;;;;; 1444;CANADIAN SYLLABICS PWA;Lo;0;L;;;;;N;;;;; 1445;CANADIAN SYLLABICS WEST-CREE PWA;Lo;0;L;;;;;N;;;;; 1446;CANADIAN SYLLABICS PWAA;Lo;0;L;;;;;N;;;;; 1447;CANADIAN SYLLABICS WEST-CREE PWAA;Lo;0;L;;;;;N;;;;; 1448;CANADIAN SYLLABICS Y-CREE PWAA;Lo;0;L;;;;;N;;;;; 1449;CANADIAN SYLLABICS P;Lo;0;L;;;;;N;;;;; 144A;CANADIAN SYLLABICS WEST-CREE P;Lo;0;L;;;;;N;;;;; 144B;CANADIAN SYLLABICS CARRIER H;Lo;0;L;;;;;N;;;;; 144C;CANADIAN SYLLABICS TE;Lo;0;L;;;;;N;;;;; 144D;CANADIAN SYLLABICS TAAI;Lo;0;L;;;;;N;;;;; 144E;CANADIAN SYLLABICS TI;Lo;0;L;;;;;N;;;;; 144F;CANADIAN SYLLABICS TII;Lo;0;L;;;;;N;;;;; 1450;CANADIAN SYLLABICS TO;Lo;0;L;;;;;N;;;;; 1451;CANADIAN SYLLABICS TOO;Lo;0;L;;;;;N;;;;; 1452;CANADIAN SYLLABICS Y-CREE TOO;Lo;0;L;;;;;N;;;;; 1453;CANADIAN SYLLABICS CARRIER DEE;Lo;0;L;;;;;N;;;;; 1454;CANADIAN SYLLABICS CARRIER DI;Lo;0;L;;;;;N;;;;; 1455;CANADIAN SYLLABICS TA;Lo;0;L;;;;;N;;;;; 1456;CANADIAN SYLLABICS TAA;Lo;0;L;;;;;N;;;;; 1457;CANADIAN SYLLABICS TWE;Lo;0;L;;;;;N;;;;; 1458;CANADIAN SYLLABICS WEST-CREE TWE;Lo;0;L;;;;;N;;;;; 1459;CANADIAN SYLLABICS TWI;Lo;0;L;;;;;N;;;;; 145A;CANADIAN SYLLABICS WEST-CREE TWI;Lo;0;L;;;;;N;;;;; 145B;CANADIAN SYLLABICS TWII;Lo;0;L;;;;;N;;;;; 145C;CANADIAN SYLLABICS WEST-CREE TWII;Lo;0;L;;;;;N;;;;; 145D;CANADIAN SYLLABICS TWO;Lo;0;L;;;;;N;;;;; 145E;CANADIAN SYLLABICS WEST-CREE TWO;Lo;0;L;;;;;N;;;;; 145F;CANADIAN SYLLABICS TWOO;Lo;0;L;;;;;N;;;;; 1460;CANADIAN SYLLABICS WEST-CREE TWOO;Lo;0;L;;;;;N;;;;; 1461;CANADIAN SYLLABICS TWA;Lo;0;L;;;;;N;;;;; 1462;CANADIAN SYLLABICS WEST-CREE TWA;Lo;0;L;;;;;N;;;;; 1463;CANADIAN SYLLABICS TWAA;Lo;0;L;;;;;N;;;;; 1464;CANADIAN SYLLABICS WEST-CREE TWAA;Lo;0;L;;;;;N;;;;; 1465;CANADIAN SYLLABICS NASKAPI TWAA;Lo;0;L;;;;;N;;;;; 1466;CANADIAN SYLLABICS T;Lo;0;L;;;;;N;;;;; 1467;CANADIAN SYLLABICS TTE;Lo;0;L;;;;;N;;;;; 1468;CANADIAN SYLLABICS TTI;Lo;0;L;;;;;N;;;;; 1469;CANADIAN SYLLABICS TTO;Lo;0;L;;;;;N;;;;; 146A;CANADIAN SYLLABICS TTA;Lo;0;L;;;;;N;;;;; 146B;CANADIAN SYLLABICS KE;Lo;0;L;;;;;N;;;;; 146C;CANADIAN SYLLABICS KAAI;Lo;0;L;;;;;N;;;;; 146D;CANADIAN SYLLABICS KI;Lo;0;L;;;;;N;;;;; 146E;CANADIAN SYLLABICS KII;Lo;0;L;;;;;N;;;;; 146F;CANADIAN SYLLABICS KO;Lo;0;L;;;;;N;;;;; 1470;CANADIAN SYLLABICS KOO;Lo;0;L;;;;;N;;;;; 1471;CANADIAN SYLLABICS Y-CREE KOO;Lo;0;L;;;;;N;;;;; 1472;CANADIAN SYLLABICS KA;Lo;0;L;;;;;N;;;;; 1473;CANADIAN SYLLABICS KAA;Lo;0;L;;;;;N;;;;; 1474;CANADIAN SYLLABICS KWE;Lo;0;L;;;;;N;;;;; 1475;CANADIAN SYLLABICS WEST-CREE KWE;Lo;0;L;;;;;N;;;;; 1476;CANADIAN SYLLABICS KWI;Lo;0;L;;;;;N;;;;; 1477;CANADIAN SYLLABICS WEST-CREE KWI;Lo;0;L;;;;;N;;;;; 1478;CANADIAN SYLLABICS KWII;Lo;0;L;;;;;N;;;;; 1479;CANADIAN SYLLABICS WEST-CREE KWII;Lo;0;L;;;;;N;;;;; 147A;CANADIAN SYLLABICS KWO;Lo;0;L;;;;;N;;;;; 147B;CANADIAN SYLLABICS WEST-CREE KWO;Lo;0;L;;;;;N;;;;; 147C;CANADIAN SYLLABICS KWOO;Lo;0;L;;;;;N;;;;; 147D;CANADIAN SYLLABICS WEST-CREE KWOO;Lo;0;L;;;;;N;;;;; 147E;CANADIAN SYLLABICS KWA;Lo;0;L;;;;;N;;;;; 147F;CANADIAN SYLLABICS WEST-CREE KWA;Lo;0;L;;;;;N;;;;; 1480;CANADIAN SYLLABICS KWAA;Lo;0;L;;;;;N;;;;; 1481;CANADIAN SYLLABICS WEST-CREE KWAA;Lo;0;L;;;;;N;;;;; 1482;CANADIAN SYLLABICS NASKAPI KWAA;Lo;0;L;;;;;N;;;;; 1483;CANADIAN SYLLABICS K;Lo;0;L;;;;;N;;;;; 1484;CANADIAN SYLLABICS KW;Lo;0;L;;;;;N;;;;; 1485;CANADIAN SYLLABICS SOUTH-SLAVEY KEH;Lo;0;L;;;;;N;;;;; 1486;CANADIAN SYLLABICS SOUTH-SLAVEY KIH;Lo;0;L;;;;;N;;;;; 1487;CANADIAN SYLLABICS SOUTH-SLAVEY KOH;Lo;0;L;;;;;N;;;;; 1488;CANADIAN SYLLABICS SOUTH-SLAVEY KAH;Lo;0;L;;;;;N;;;;; 1489;CANADIAN SYLLABICS CE;Lo;0;L;;;;;N;;;;; 148A;CANADIAN SYLLABICS CAAI;Lo;0;L;;;;;N;;;;; 148B;CANADIAN SYLLABICS CI;Lo;0;L;;;;;N;;;;; 148C;CANADIAN SYLLABICS CII;Lo;0;L;;;;;N;;;;; 148D;CANADIAN SYLLABICS CO;Lo;0;L;;;;;N;;;;; 148E;CANADIAN SYLLABICS COO;Lo;0;L;;;;;N;;;;; 148F;CANADIAN SYLLABICS Y-CREE COO;Lo;0;L;;;;;N;;;;; 1490;CANADIAN SYLLABICS CA;Lo;0;L;;;;;N;;;;; 1491;CANADIAN SYLLABICS CAA;Lo;0;L;;;;;N;;;;; 1492;CANADIAN SYLLABICS CWE;Lo;0;L;;;;;N;;;;; 1493;CANADIAN SYLLABICS WEST-CREE CWE;Lo;0;L;;;;;N;;;;; 1494;CANADIAN SYLLABICS CWI;Lo;0;L;;;;;N;;;;; 1495;CANADIAN SYLLABICS WEST-CREE CWI;Lo;0;L;;;;;N;;;;; 1496;CANADIAN SYLLABICS CWII;Lo;0;L;;;;;N;;;;; 1497;CANADIAN SYLLABICS WEST-CREE CWII;Lo;0;L;;;;;N;;;;; 1498;CANADIAN SYLLABICS CWO;Lo;0;L;;;;;N;;;;; 1499;CANADIAN SYLLABICS WEST-CREE CWO;Lo;0;L;;;;;N;;;;; 149A;CANADIAN SYLLABICS CWOO;Lo;0;L;;;;;N;;;;; 149B;CANADIAN SYLLABICS WEST-CREE CWOO;Lo;0;L;;;;;N;;;;; 149C;CANADIAN SYLLABICS CWA;Lo;0;L;;;;;N;;;;; 149D;CANADIAN SYLLABICS WEST-CREE CWA;Lo;0;L;;;;;N;;;;; 149E;CANADIAN SYLLABICS CWAA;Lo;0;L;;;;;N;;;;; 149F;CANADIAN SYLLABICS WEST-CREE CWAA;Lo;0;L;;;;;N;;;;; 14A0;CANADIAN SYLLABICS NASKAPI CWAA;Lo;0;L;;;;;N;;;;; 14A1;CANADIAN SYLLABICS C;Lo;0;L;;;;;N;;;;; 14A2;CANADIAN SYLLABICS SAYISI TH;Lo;0;L;;;;;N;;;;; 14A3;CANADIAN SYLLABICS ME;Lo;0;L;;;;;N;;;;; 14A4;CANADIAN SYLLABICS MAAI;Lo;0;L;;;;;N;;;;; 14A5;CANADIAN SYLLABICS MI;Lo;0;L;;;;;N;;;;; 14A6;CANADIAN SYLLABICS MII;Lo;0;L;;;;;N;;;;; 14A7;CANADIAN SYLLABICS MO;Lo;0;L;;;;;N;;;;; 14A8;CANADIAN SYLLABICS MOO;Lo;0;L;;;;;N;;;;; 14A9;CANADIAN SYLLABICS Y-CREE MOO;Lo;0;L;;;;;N;;;;; 14AA;CANADIAN SYLLABICS MA;Lo;0;L;;;;;N;;;;; 14AB;CANADIAN SYLLABICS MAA;Lo;0;L;;;;;N;;;;; 14AC;CANADIAN SYLLABICS MWE;Lo;0;L;;;;;N;;;;; 14AD;CANADIAN SYLLABICS WEST-CREE MWE;Lo;0;L;;;;;N;;;;; 14AE;CANADIAN SYLLABICS MWI;Lo;0;L;;;;;N;;;;; 14AF;CANADIAN SYLLABICS WEST-CREE MWI;Lo;0;L;;;;;N;;;;; 14B0;CANADIAN SYLLABICS MWII;Lo;0;L;;;;;N;;;;; 14B1;CANADIAN SYLLABICS WEST-CREE MWII;Lo;0;L;;;;;N;;;;; 14B2;CANADIAN SYLLABICS MWO;Lo;0;L;;;;;N;;;;; 14B3;CANADIAN SYLLABICS WEST-CREE MWO;Lo;0;L;;;;;N;;;;; 14B4;CANADIAN SYLLABICS MWOO;Lo;0;L;;;;;N;;;;; 14B5;CANADIAN SYLLABICS WEST-CREE MWOO;Lo;0;L;;;;;N;;;;; 14B6;CANADIAN SYLLABICS MWA;Lo;0;L;;;;;N;;;;; 14B7;CANADIAN SYLLABICS WEST-CREE MWA;Lo;0;L;;;;;N;;;;; 14B8;CANADIAN SYLLABICS MWAA;Lo;0;L;;;;;N;;;;; 14B9;CANADIAN SYLLABICS WEST-CREE MWAA;Lo;0;L;;;;;N;;;;; 14BA;CANADIAN SYLLABICS NASKAPI MWAA;Lo;0;L;;;;;N;;;;; 14BB;CANADIAN SYLLABICS M;Lo;0;L;;;;;N;;;;; 14BC;CANADIAN SYLLABICS WEST-CREE M;Lo;0;L;;;;;N;;;;; 14BD;CANADIAN SYLLABICS MH;Lo;0;L;;;;;N;;;;; 14BE;CANADIAN SYLLABICS ATHAPASCAN M;Lo;0;L;;;;;N;;;;; 14BF;CANADIAN SYLLABICS SAYISI M;Lo;0;L;;;;;N;;;;; 14C0;CANADIAN SYLLABICS NE;Lo;0;L;;;;;N;;;;; 14C1;CANADIAN SYLLABICS NAAI;Lo;0;L;;;;;N;;;;; 14C2;CANADIAN SYLLABICS NI;Lo;0;L;;;;;N;;;;; 14C3;CANADIAN SYLLABICS NII;Lo;0;L;;;;;N;;;;; 14C4;CANADIAN SYLLABICS NO;Lo;0;L;;;;;N;;;;; 14C5;CANADIAN SYLLABICS NOO;Lo;0;L;;;;;N;;;;; 14C6;CANADIAN SYLLABICS Y-CREE NOO;Lo;0;L;;;;;N;;;;; 14C7;CANADIAN SYLLABICS NA;Lo;0;L;;;;;N;;;;; 14C8;CANADIAN SYLLABICS NAA;Lo;0;L;;;;;N;;;;; 14C9;CANADIAN SYLLABICS NWE;Lo;0;L;;;;;N;;;;; 14CA;CANADIAN SYLLABICS WEST-CREE NWE;Lo;0;L;;;;;N;;;;; 14CB;CANADIAN SYLLABICS NWA;Lo;0;L;;;;;N;;;;; 14CC;CANADIAN SYLLABICS WEST-CREE NWA;Lo;0;L;;;;;N;;;;; 14CD;CANADIAN SYLLABICS NWAA;Lo;0;L;;;;;N;;;;; 14CE;CANADIAN SYLLABICS WEST-CREE NWAA;Lo;0;L;;;;;N;;;;; 14CF;CANADIAN SYLLABICS NASKAPI NWAA;Lo;0;L;;;;;N;;;;; 14D0;CANADIAN SYLLABICS N;Lo;0;L;;;;;N;;;;; 14D1;CANADIAN SYLLABICS CARRIER NG;Lo;0;L;;;;;N;;;;; 14D2;CANADIAN SYLLABICS NH;Lo;0;L;;;;;N;;;;; 14D3;CANADIAN SYLLABICS LE;Lo;0;L;;;;;N;;;;; 14D4;CANADIAN SYLLABICS LAAI;Lo;0;L;;;;;N;;;;; 14D5;CANADIAN SYLLABICS LI;Lo;0;L;;;;;N;;;;; 14D6;CANADIAN SYLLABICS LII;Lo;0;L;;;;;N;;;;; 14D7;CANADIAN SYLLABICS LO;Lo;0;L;;;;;N;;;;; 14D8;CANADIAN SYLLABICS LOO;Lo;0;L;;;;;N;;;;; 14D9;CANADIAN SYLLABICS Y-CREE LOO;Lo;0;L;;;;;N;;;;; 14DA;CANADIAN SYLLABICS LA;Lo;0;L;;;;;N;;;;; 14DB;CANADIAN SYLLABICS LAA;Lo;0;L;;;;;N;;;;; 14DC;CANADIAN SYLLABICS LWE;Lo;0;L;;;;;N;;;;; 14DD;CANADIAN SYLLABICS WEST-CREE LWE;Lo;0;L;;;;;N;;;;; 14DE;CANADIAN SYLLABICS LWI;Lo;0;L;;;;;N;;;;; 14DF;CANADIAN SYLLABICS WEST-CREE LWI;Lo;0;L;;;;;N;;;;; 14E0;CANADIAN SYLLABICS LWII;Lo;0;L;;;;;N;;;;; 14E1;CANADIAN SYLLABICS WEST-CREE LWII;Lo;0;L;;;;;N;;;;; 14E2;CANADIAN SYLLABICS LWO;Lo;0;L;;;;;N;;;;; 14E3;CANADIAN SYLLABICS WEST-CREE LWO;Lo;0;L;;;;;N;;;;; 14E4;CANADIAN SYLLABICS LWOO;Lo;0;L;;;;;N;;;;; 14E5;CANADIAN SYLLABICS WEST-CREE LWOO;Lo;0;L;;;;;N;;;;; 14E6;CANADIAN SYLLABICS LWA;Lo;0;L;;;;;N;;;;; 14E7;CANADIAN SYLLABICS WEST-CREE LWA;Lo;0;L;;;;;N;;;;; 14E8;CANADIAN SYLLABICS LWAA;Lo;0;L;;;;;N;;;;; 14E9;CANADIAN SYLLABICS WEST-CREE LWAA;Lo;0;L;;;;;N;;;;; 14EA;CANADIAN SYLLABICS L;Lo;0;L;;;;;N;;;;; 14EB;CANADIAN SYLLABICS WEST-CREE L;Lo;0;L;;;;;N;;;;; 14EC;CANADIAN SYLLABICS MEDIAL L;Lo;0;L;;;;;N;;;;; 14ED;CANADIAN SYLLABICS SE;Lo;0;L;;;;;N;;;;; 14EE;CANADIAN SYLLABICS SAAI;Lo;0;L;;;;;N;;;;; 14EF;CANADIAN SYLLABICS SI;Lo;0;L;;;;;N;;;;; 14F0;CANADIAN SYLLABICS SII;Lo;0;L;;;;;N;;;;; 14F1;CANADIAN SYLLABICS SO;Lo;0;L;;;;;N;;;;; 14F2;CANADIAN SYLLABICS SOO;Lo;0;L;;;;;N;;;;; 14F3;CANADIAN SYLLABICS Y-CREE SOO;Lo;0;L;;;;;N;;;;; 14F4;CANADIAN SYLLABICS SA;Lo;0;L;;;;;N;;;;; 14F5;CANADIAN SYLLABICS SAA;Lo;0;L;;;;;N;;;;; 14F6;CANADIAN SYLLABICS SWE;Lo;0;L;;;;;N;;;;; 14F7;CANADIAN SYLLABICS WEST-CREE SWE;Lo;0;L;;;;;N;;;;; 14F8;CANADIAN SYLLABICS SWI;Lo;0;L;;;;;N;;;;; 14F9;CANADIAN SYLLABICS WEST-CREE SWI;Lo;0;L;;;;;N;;;;; 14FA;CANADIAN SYLLABICS SWII;Lo;0;L;;;;;N;;;;; 14FB;CANADIAN SYLLABICS WEST-CREE SWII;Lo;0;L;;;;;N;;;;; 14FC;CANADIAN SYLLABICS SWO;Lo;0;L;;;;;N;;;;; 14FD;CANADIAN SYLLABICS WEST-CREE SWO;Lo;0;L;;;;;N;;;;; 14FE;CANADIAN SYLLABICS SWOO;Lo;0;L;;;;;N;;;;; 14FF;CANADIAN SYLLABICS WEST-CREE SWOO;Lo;0;L;;;;;N;;;;; 1500;CANADIAN SYLLABICS SWA;Lo;0;L;;;;;N;;;;; 1501;CANADIAN SYLLABICS WEST-CREE SWA;Lo;0;L;;;;;N;;;;; 1502;CANADIAN SYLLABICS SWAA;Lo;0;L;;;;;N;;;;; 1503;CANADIAN SYLLABICS WEST-CREE SWAA;Lo;0;L;;;;;N;;;;; 1504;CANADIAN SYLLABICS NASKAPI SWAA;Lo;0;L;;;;;N;;;;; 1505;CANADIAN SYLLABICS S;Lo;0;L;;;;;N;;;;; 1506;CANADIAN SYLLABICS ATHAPASCAN S;Lo;0;L;;;;;N;;;;; 1507;CANADIAN SYLLABICS SW;Lo;0;L;;;;;N;;;;; 1508;CANADIAN SYLLABICS BLACKFOOT S;Lo;0;L;;;;;N;;;;; 1509;CANADIAN SYLLABICS MOOSE-CREE SK;Lo;0;L;;;;;N;;;;; 150A;CANADIAN SYLLABICS NASKAPI SKW;Lo;0;L;;;;;N;;;;; 150B;CANADIAN SYLLABICS NASKAPI S-W;Lo;0;L;;;;;N;;;;; 150C;CANADIAN SYLLABICS NASKAPI SPWA;Lo;0;L;;;;;N;;;;; 150D;CANADIAN SYLLABICS NASKAPI STWA;Lo;0;L;;;;;N;;;;; 150E;CANADIAN SYLLABICS NASKAPI SKWA;Lo;0;L;;;;;N;;;;; 150F;CANADIAN SYLLABICS NASKAPI SCWA;Lo;0;L;;;;;N;;;;; 1510;CANADIAN SYLLABICS SHE;Lo;0;L;;;;;N;;;;; 1511;CANADIAN SYLLABICS SHI;Lo;0;L;;;;;N;;;;; 1512;CANADIAN SYLLABICS SHII;Lo;0;L;;;;;N;;;;; 1513;CANADIAN SYLLABICS SHO;Lo;0;L;;;;;N;;;;; 1514;CANADIAN SYLLABICS SHOO;Lo;0;L;;;;;N;;;;; 1515;CANADIAN SYLLABICS SHA;Lo;0;L;;;;;N;;;;; 1516;CANADIAN SYLLABICS SHAA;Lo;0;L;;;;;N;;;;; 1517;CANADIAN SYLLABICS SHWE;Lo;0;L;;;;;N;;;;; 1518;CANADIAN SYLLABICS WEST-CREE SHWE;Lo;0;L;;;;;N;;;;; 1519;CANADIAN SYLLABICS SHWI;Lo;0;L;;;;;N;;;;; 151A;CANADIAN SYLLABICS WEST-CREE SHWI;Lo;0;L;;;;;N;;;;; 151B;CANADIAN SYLLABICS SHWII;Lo;0;L;;;;;N;;;;; 151C;CANADIAN SYLLABICS WEST-CREE SHWII;Lo;0;L;;;;;N;;;;; 151D;CANADIAN SYLLABICS SHWO;Lo;0;L;;;;;N;;;;; 151E;CANADIAN SYLLABICS WEST-CREE SHWO;Lo;0;L;;;;;N;;;;; 151F;CANADIAN SYLLABICS SHWOO;Lo;0;L;;;;;N;;;;; 1520;CANADIAN SYLLABICS WEST-CREE SHWOO;Lo;0;L;;;;;N;;;;; 1521;CANADIAN SYLLABICS SHWA;Lo;0;L;;;;;N;;;;; 1522;CANADIAN SYLLABICS WEST-CREE SHWA;Lo;0;L;;;;;N;;;;; 1523;CANADIAN SYLLABICS SHWAA;Lo;0;L;;;;;N;;;;; 1524;CANADIAN SYLLABICS WEST-CREE SHWAA;Lo;0;L;;;;;N;;;;; 1525;CANADIAN SYLLABICS SH;Lo;0;L;;;;;N;;;;; 1526;CANADIAN SYLLABICS YE;Lo;0;L;;;;;N;;;;; 1527;CANADIAN SYLLABICS YAAI;Lo;0;L;;;;;N;;;;; 1528;CANADIAN SYLLABICS YI;Lo;0;L;;;;;N;;;;; 1529;CANADIAN SYLLABICS YII;Lo;0;L;;;;;N;;;;; 152A;CANADIAN SYLLABICS YO;Lo;0;L;;;;;N;;;;; 152B;CANADIAN SYLLABICS YOO;Lo;0;L;;;;;N;;;;; 152C;CANADIAN SYLLABICS Y-CREE YOO;Lo;0;L;;;;;N;;;;; 152D;CANADIAN SYLLABICS YA;Lo;0;L;;;;;N;;;;; 152E;CANADIAN SYLLABICS YAA;Lo;0;L;;;;;N;;;;; 152F;CANADIAN SYLLABICS YWE;Lo;0;L;;;;;N;;;;; 1530;CANADIAN SYLLABICS WEST-CREE YWE;Lo;0;L;;;;;N;;;;; 1531;CANADIAN SYLLABICS YWI;Lo;0;L;;;;;N;;;;; 1532;CANADIAN SYLLABICS WEST-CREE YWI;Lo;0;L;;;;;N;;;;; 1533;CANADIAN SYLLABICS YWII;Lo;0;L;;;;;N;;;;; 1534;CANADIAN SYLLABICS WEST-CREE YWII;Lo;0;L;;;;;N;;;;; 1535;CANADIAN SYLLABICS YWO;Lo;0;L;;;;;N;;;;; 1536;CANADIAN SYLLABICS WEST-CREE YWO;Lo;0;L;;;;;N;;;;; 1537;CANADIAN SYLLABICS YWOO;Lo;0;L;;;;;N;;;;; 1538;CANADIAN SYLLABICS WEST-CREE YWOO;Lo;0;L;;;;;N;;;;; 1539;CANADIAN SYLLABICS YWA;Lo;0;L;;;;;N;;;;; 153A;CANADIAN SYLLABICS WEST-CREE YWA;Lo;0;L;;;;;N;;;;; 153B;CANADIAN SYLLABICS YWAA;Lo;0;L;;;;;N;;;;; 153C;CANADIAN SYLLABICS WEST-CREE YWAA;Lo;0;L;;;;;N;;;;; 153D;CANADIAN SYLLABICS NASKAPI YWAA;Lo;0;L;;;;;N;;;;; 153E;CANADIAN SYLLABICS Y;Lo;0;L;;;;;N;;;;; 153F;CANADIAN SYLLABICS BIBLE-CREE Y;Lo;0;L;;;;;N;;;;; 1540;CANADIAN SYLLABICS WEST-CREE Y;Lo;0;L;;;;;N;;;;; 1541;CANADIAN SYLLABICS SAYISI YI;Lo;0;L;;;;;N;;;;; 1542;CANADIAN SYLLABICS RE;Lo;0;L;;;;;N;;;;; 1543;CANADIAN SYLLABICS R-CREE RE;Lo;0;L;;;;;N;;;;; 1544;CANADIAN SYLLABICS WEST-CREE LE;Lo;0;L;;;;;N;;;;; 1545;CANADIAN SYLLABICS RAAI;Lo;0;L;;;;;N;;;;; 1546;CANADIAN SYLLABICS RI;Lo;0;L;;;;;N;;;;; 1547;CANADIAN SYLLABICS RII;Lo;0;L;;;;;N;;;;; 1548;CANADIAN SYLLABICS RO;Lo;0;L;;;;;N;;;;; 1549;CANADIAN SYLLABICS ROO;Lo;0;L;;;;;N;;;;; 154A;CANADIAN SYLLABICS WEST-CREE LO;Lo;0;L;;;;;N;;;;; 154B;CANADIAN SYLLABICS RA;Lo;0;L;;;;;N;;;;; 154C;CANADIAN SYLLABICS RAA;Lo;0;L;;;;;N;;;;; 154D;CANADIAN SYLLABICS WEST-CREE LA;Lo;0;L;;;;;N;;;;; 154E;CANADIAN SYLLABICS RWAA;Lo;0;L;;;;;N;;;;; 154F;CANADIAN SYLLABICS WEST-CREE RWAA;Lo;0;L;;;;;N;;;;; 1550;CANADIAN SYLLABICS R;Lo;0;L;;;;;N;;;;; 1551;CANADIAN SYLLABICS WEST-CREE R;Lo;0;L;;;;;N;;;;; 1552;CANADIAN SYLLABICS MEDIAL R;Lo;0;L;;;;;N;;;;; 1553;CANADIAN SYLLABICS FE;Lo;0;L;;;;;N;;;;; 1554;CANADIAN SYLLABICS FAAI;Lo;0;L;;;;;N;;;;; 1555;CANADIAN SYLLABICS FI;Lo;0;L;;;;;N;;;;; 1556;CANADIAN SYLLABICS FII;Lo;0;L;;;;;N;;;;; 1557;CANADIAN SYLLABICS FO;Lo;0;L;;;;;N;;;;; 1558;CANADIAN SYLLABICS FOO;Lo;0;L;;;;;N;;;;; 1559;CANADIAN SYLLABICS FA;Lo;0;L;;;;;N;;;;; 155A;CANADIAN SYLLABICS FAA;Lo;0;L;;;;;N;;;;; 155B;CANADIAN SYLLABICS FWAA;Lo;0;L;;;;;N;;;;; 155C;CANADIAN SYLLABICS WEST-CREE FWAA;Lo;0;L;;;;;N;;;;; 155D;CANADIAN SYLLABICS F;Lo;0;L;;;;;N;;;;; 155E;CANADIAN SYLLABICS THE;Lo;0;L;;;;;N;;;;; 155F;CANADIAN SYLLABICS N-CREE THE;Lo;0;L;;;;;N;;;;; 1560;CANADIAN SYLLABICS THI;Lo;0;L;;;;;N;;;;; 1561;CANADIAN SYLLABICS N-CREE THI;Lo;0;L;;;;;N;;;;; 1562;CANADIAN SYLLABICS THII;Lo;0;L;;;;;N;;;;; 1563;CANADIAN SYLLABICS N-CREE THII;Lo;0;L;;;;;N;;;;; 1564;CANADIAN SYLLABICS THO;Lo;0;L;;;;;N;;;;; 1565;CANADIAN SYLLABICS THOO;Lo;0;L;;;;;N;;;;; 1566;CANADIAN SYLLABICS THA;Lo;0;L;;;;;N;;;;; 1567;CANADIAN SYLLABICS THAA;Lo;0;L;;;;;N;;;;; 1568;CANADIAN SYLLABICS THWAA;Lo;0;L;;;;;N;;;;; 1569;CANADIAN SYLLABICS WEST-CREE THWAA;Lo;0;L;;;;;N;;;;; 156A;CANADIAN SYLLABICS TH;Lo;0;L;;;;;N;;;;; 156B;CANADIAN SYLLABICS TTHE;Lo;0;L;;;;;N;;;;; 156C;CANADIAN SYLLABICS TTHI;Lo;0;L;;;;;N;;;;; 156D;CANADIAN SYLLABICS TTHO;Lo;0;L;;;;;N;;;;; 156E;CANADIAN SYLLABICS TTHA;Lo;0;L;;;;;N;;;;; 156F;CANADIAN SYLLABICS TTH;Lo;0;L;;;;;N;;;;; 1570;CANADIAN SYLLABICS TYE;Lo;0;L;;;;;N;;;;; 1571;CANADIAN SYLLABICS TYI;Lo;0;L;;;;;N;;;;; 1572;CANADIAN SYLLABICS TYO;Lo;0;L;;;;;N;;;;; 1573;CANADIAN SYLLABICS TYA;Lo;0;L;;;;;N;;;;; 1574;CANADIAN SYLLABICS NUNAVIK HE;Lo;0;L;;;;;N;;;;; 1575;CANADIAN SYLLABICS NUNAVIK HI;Lo;0;L;;;;;N;;;;; 1576;CANADIAN SYLLABICS NUNAVIK HII;Lo;0;L;;;;;N;;;;; 1577;CANADIAN SYLLABICS NUNAVIK HO;Lo;0;L;;;;;N;;;;; 1578;CANADIAN SYLLABICS NUNAVIK HOO;Lo;0;L;;;;;N;;;;; 1579;CANADIAN SYLLABICS NUNAVIK HA;Lo;0;L;;;;;N;;;;; 157A;CANADIAN SYLLABICS NUNAVIK HAA;Lo;0;L;;;;;N;;;;; 157B;CANADIAN SYLLABICS NUNAVIK H;Lo;0;L;;;;;N;;;;; 157C;CANADIAN SYLLABICS NUNAVUT H;Lo;0;L;;;;;N;;;;; 157D;CANADIAN SYLLABICS HK;Lo;0;L;;;;;N;;;;; 157E;CANADIAN SYLLABICS QAAI;Lo;0;L;;;;;N;;;;; 157F;CANADIAN SYLLABICS QI;Lo;0;L;;;;;N;;;;; 1580;CANADIAN SYLLABICS QII;Lo;0;L;;;;;N;;;;; 1581;CANADIAN SYLLABICS QO;Lo;0;L;;;;;N;;;;; 1582;CANADIAN SYLLABICS QOO;Lo;0;L;;;;;N;;;;; 1583;CANADIAN SYLLABICS QA;Lo;0;L;;;;;N;;;;; 1584;CANADIAN SYLLABICS QAA;Lo;0;L;;;;;N;;;;; 1585;CANADIAN SYLLABICS Q;Lo;0;L;;;;;N;;;;; 1586;CANADIAN SYLLABICS TLHE;Lo;0;L;;;;;N;;;;; 1587;CANADIAN SYLLABICS TLHI;Lo;0;L;;;;;N;;;;; 1588;CANADIAN SYLLABICS TLHO;Lo;0;L;;;;;N;;;;; 1589;CANADIAN SYLLABICS TLHA;Lo;0;L;;;;;N;;;;; 158A;CANADIAN SYLLABICS WEST-CREE RE;Lo;0;L;;;;;N;;;;; 158B;CANADIAN SYLLABICS WEST-CREE RI;Lo;0;L;;;;;N;;;;; 158C;CANADIAN SYLLABICS WEST-CREE RO;Lo;0;L;;;;;N;;;;; 158D;CANADIAN SYLLABICS WEST-CREE RA;Lo;0;L;;;;;N;;;;; 158E;CANADIAN SYLLABICS NGAAI;Lo;0;L;;;;;N;;;;; 158F;CANADIAN SYLLABICS NGI;Lo;0;L;;;;;N;;;;; 1590;CANADIAN SYLLABICS NGII;Lo;0;L;;;;;N;;;;; 1591;CANADIAN SYLLABICS NGO;Lo;0;L;;;;;N;;;;; 1592;CANADIAN SYLLABICS NGOO;Lo;0;L;;;;;N;;;;; 1593;CANADIAN SYLLABICS NGA;Lo;0;L;;;;;N;;;;; 1594;CANADIAN SYLLABICS NGAA;Lo;0;L;;;;;N;;;;; 1595;CANADIAN SYLLABICS NG;Lo;0;L;;;;;N;;;;; 1596;CANADIAN SYLLABICS NNG;Lo;0;L;;;;;N;;;;; 1597;CANADIAN SYLLABICS SAYISI SHE;Lo;0;L;;;;;N;;;;; 1598;CANADIAN SYLLABICS SAYISI SHI;Lo;0;L;;;;;N;;;;; 1599;CANADIAN SYLLABICS SAYISI SHO;Lo;0;L;;;;;N;;;;; 159A;CANADIAN SYLLABICS SAYISI SHA;Lo;0;L;;;;;N;;;;; 159B;CANADIAN SYLLABICS WOODS-CREE THE;Lo;0;L;;;;;N;;;;; 159C;CANADIAN SYLLABICS WOODS-CREE THI;Lo;0;L;;;;;N;;;;; 159D;CANADIAN SYLLABICS WOODS-CREE THO;Lo;0;L;;;;;N;;;;; 159E;CANADIAN SYLLABICS WOODS-CREE THA;Lo;0;L;;;;;N;;;;; 159F;CANADIAN SYLLABICS WOODS-CREE TH;Lo;0;L;;;;;N;;;;; 15A0;CANADIAN SYLLABICS LHI;Lo;0;L;;;;;N;;;;; 15A1;CANADIAN SYLLABICS LHII;Lo;0;L;;;;;N;;;;; 15A2;CANADIAN SYLLABICS LHO;Lo;0;L;;;;;N;;;;; 15A3;CANADIAN SYLLABICS LHOO;Lo;0;L;;;;;N;;;;; 15A4;CANADIAN SYLLABICS LHA;Lo;0;L;;;;;N;;;;; 15A5;CANADIAN SYLLABICS LHAA;Lo;0;L;;;;;N;;;;; 15A6;CANADIAN SYLLABICS LH;Lo;0;L;;;;;N;;;;; 15A7;CANADIAN SYLLABICS TH-CREE THE;Lo;0;L;;;;;N;;;;; 15A8;CANADIAN SYLLABICS TH-CREE THI;Lo;0;L;;;;;N;;;;; 15A9;CANADIAN SYLLABICS TH-CREE THII;Lo;0;L;;;;;N;;;;; 15AA;CANADIAN SYLLABICS TH-CREE THO;Lo;0;L;;;;;N;;;;; 15AB;CANADIAN SYLLABICS TH-CREE THOO;Lo;0;L;;;;;N;;;;; 15AC;CANADIAN SYLLABICS TH-CREE THA;Lo;0;L;;;;;N;;;;; 15AD;CANADIAN SYLLABICS TH-CREE THAA;Lo;0;L;;;;;N;;;;; 15AE;CANADIAN SYLLABICS TH-CREE TH;Lo;0;L;;;;;N;;;;; 15AF;CANADIAN SYLLABICS AIVILIK B;Lo;0;L;;;;;N;;;;; 15B0;CANADIAN SYLLABICS BLACKFOOT E;Lo;0;L;;;;;N;;;;; 15B1;CANADIAN SYLLABICS BLACKFOOT I;Lo;0;L;;;;;N;;;;; 15B2;CANADIAN SYLLABICS BLACKFOOT O;Lo;0;L;;;;;N;;;;; 15B3;CANADIAN SYLLABICS BLACKFOOT A;Lo;0;L;;;;;N;;;;; 15B4;CANADIAN SYLLABICS BLACKFOOT WE;Lo;0;L;;;;;N;;;;; 15B5;CANADIAN SYLLABICS BLACKFOOT WI;Lo;0;L;;;;;N;;;;; 15B6;CANADIAN SYLLABICS BLACKFOOT WO;Lo;0;L;;;;;N;;;;; 15B7;CANADIAN SYLLABICS BLACKFOOT WA;Lo;0;L;;;;;N;;;;; 15B8;CANADIAN SYLLABICS BLACKFOOT NE;Lo;0;L;;;;;N;;;;; 15B9;CANADIAN SYLLABICS BLACKFOOT NI;Lo;0;L;;;;;N;;;;; 15BA;CANADIAN SYLLABICS BLACKFOOT NO;Lo;0;L;;;;;N;;;;; 15BB;CANADIAN SYLLABICS BLACKFOOT NA;Lo;0;L;;;;;N;;;;; 15BC;CANADIAN SYLLABICS BLACKFOOT KE;Lo;0;L;;;;;N;;;;; 15BD;CANADIAN SYLLABICS BLACKFOOT KI;Lo;0;L;;;;;N;;;;; 15BE;CANADIAN SYLLABICS BLACKFOOT KO;Lo;0;L;;;;;N;;;;; 15BF;CANADIAN SYLLABICS BLACKFOOT KA;Lo;0;L;;;;;N;;;;; 15C0;CANADIAN SYLLABICS SAYISI HE;Lo;0;L;;;;;N;;;;; 15C1;CANADIAN SYLLABICS SAYISI HI;Lo;0;L;;;;;N;;;;; 15C2;CANADIAN SYLLABICS SAYISI HO;Lo;0;L;;;;;N;;;;; 15C3;CANADIAN SYLLABICS SAYISI HA;Lo;0;L;;;;;N;;;;; 15C4;CANADIAN SYLLABICS CARRIER GHU;Lo;0;L;;;;;N;;;;; 15C5;CANADIAN SYLLABICS CARRIER GHO;Lo;0;L;;;;;N;;;;; 15C6;CANADIAN SYLLABICS CARRIER GHE;Lo;0;L;;;;;N;;;;; 15C7;CANADIAN SYLLABICS CARRIER GHEE;Lo;0;L;;;;;N;;;;; 15C8;CANADIAN SYLLABICS CARRIER GHI;Lo;0;L;;;;;N;;;;; 15C9;CANADIAN SYLLABICS CARRIER GHA;Lo;0;L;;;;;N;;;;; 15CA;CANADIAN SYLLABICS CARRIER RU;Lo;0;L;;;;;N;;;;; 15CB;CANADIAN SYLLABICS CARRIER RO;Lo;0;L;;;;;N;;;;; 15CC;CANADIAN SYLLABICS CARRIER RE;Lo;0;L;;;;;N;;;;; 15CD;CANADIAN SYLLABICS CARRIER REE;Lo;0;L;;;;;N;;;;; 15CE;CANADIAN SYLLABICS CARRIER RI;Lo;0;L;;;;;N;;;;; 15CF;CANADIAN SYLLABICS CARRIER RA;Lo;0;L;;;;;N;;;;; 15D0;CANADIAN SYLLABICS CARRIER WU;Lo;0;L;;;;;N;;;;; 15D1;CANADIAN SYLLABICS CARRIER WO;Lo;0;L;;;;;N;;;;; 15D2;CANADIAN SYLLABICS CARRIER WE;Lo;0;L;;;;;N;;;;; 15D3;CANADIAN SYLLABICS CARRIER WEE;Lo;0;L;;;;;N;;;;; 15D4;CANADIAN SYLLABICS CARRIER WI;Lo;0;L;;;;;N;;;;; 15D5;CANADIAN SYLLABICS CARRIER WA;Lo;0;L;;;;;N;;;;; 15D6;CANADIAN SYLLABICS CARRIER HWU;Lo;0;L;;;;;N;;;;; 15D7;CANADIAN SYLLABICS CARRIER HWO;Lo;0;L;;;;;N;;;;; 15D8;CANADIAN SYLLABICS CARRIER HWE;Lo;0;L;;;;;N;;;;; 15D9;CANADIAN SYLLABICS CARRIER HWEE;Lo;0;L;;;;;N;;;;; 15DA;CANADIAN SYLLABICS CARRIER HWI;Lo;0;L;;;;;N;;;;; 15DB;CANADIAN SYLLABICS CARRIER HWA;Lo;0;L;;;;;N;;;;; 15DC;CANADIAN SYLLABICS CARRIER THU;Lo;0;L;;;;;N;;;;; 15DD;CANADIAN SYLLABICS CARRIER THO;Lo;0;L;;;;;N;;;;; 15DE;CANADIAN SYLLABICS CARRIER THE;Lo;0;L;;;;;N;;;;; 15DF;CANADIAN SYLLABICS CARRIER THEE;Lo;0;L;;;;;N;;;;; 15E0;CANADIAN SYLLABICS CARRIER THI;Lo;0;L;;;;;N;;;;; 15E1;CANADIAN SYLLABICS CARRIER THA;Lo;0;L;;;;;N;;;;; 15E2;CANADIAN SYLLABICS CARRIER TTU;Lo;0;L;;;;;N;;;;; 15E3;CANADIAN SYLLABICS CARRIER TTO;Lo;0;L;;;;;N;;;;; 15E4;CANADIAN SYLLABICS CARRIER TTE;Lo;0;L;;;;;N;;;;; 15E5;CANADIAN SYLLABICS CARRIER TTEE;Lo;0;L;;;;;N;;;;; 15E6;CANADIAN SYLLABICS CARRIER TTI;Lo;0;L;;;;;N;;;;; 15E7;CANADIAN SYLLABICS CARRIER TTA;Lo;0;L;;;;;N;;;;; 15E8;CANADIAN SYLLABICS CARRIER PU;Lo;0;L;;;;;N;;;;; 15E9;CANADIAN SYLLABICS CARRIER PO;Lo;0;L;;;;;N;;;;; 15EA;CANADIAN SYLLABICS CARRIER PE;Lo;0;L;;;;;N;;;;; 15EB;CANADIAN SYLLABICS CARRIER PEE;Lo;0;L;;;;;N;;;;; 15EC;CANADIAN SYLLABICS CARRIER PI;Lo;0;L;;;;;N;;;;; 15ED;CANADIAN SYLLABICS CARRIER PA;Lo;0;L;;;;;N;;;;; 15EE;CANADIAN SYLLABICS CARRIER P;Lo;0;L;;;;;N;;;;; 15EF;CANADIAN SYLLABICS CARRIER GU;Lo;0;L;;;;;N;;;;; 15F0;CANADIAN SYLLABICS CARRIER GO;Lo;0;L;;;;;N;;;;; 15F1;CANADIAN SYLLABICS CARRIER GE;Lo;0;L;;;;;N;;;;; 15F2;CANADIAN SYLLABICS CARRIER GEE;Lo;0;L;;;;;N;;;;; 15F3;CANADIAN SYLLABICS CARRIER GI;Lo;0;L;;;;;N;;;;; 15F4;CANADIAN SYLLABICS CARRIER GA;Lo;0;L;;;;;N;;;;; 15F5;CANADIAN SYLLABICS CARRIER KHU;Lo;0;L;;;;;N;;;;; 15F6;CANADIAN SYLLABICS CARRIER KHO;Lo;0;L;;;;;N;;;;; 15F7;CANADIAN SYLLABICS CARRIER KHE;Lo;0;L;;;;;N;;;;; 15F8;CANADIAN SYLLABICS CARRIER KHEE;Lo;0;L;;;;;N;;;;; 15F9;CANADIAN SYLLABICS CARRIER KHI;Lo;0;L;;;;;N;;;;; 15FA;CANADIAN SYLLABICS CARRIER KHA;Lo;0;L;;;;;N;;;;; 15FB;CANADIAN SYLLABICS CARRIER KKU;Lo;0;L;;;;;N;;;;; 15FC;CANADIAN SYLLABICS CARRIER KKO;Lo;0;L;;;;;N;;;;; 15FD;CANADIAN SYLLABICS CARRIER KKE;Lo;0;L;;;;;N;;;;; 15FE;CANADIAN SYLLABICS CARRIER KKEE;Lo;0;L;;;;;N;;;;; 15FF;CANADIAN SYLLABICS CARRIER KKI;Lo;0;L;;;;;N;;;;; 1600;CANADIAN SYLLABICS CARRIER KKA;Lo;0;L;;;;;N;;;;; 1601;CANADIAN SYLLABICS CARRIER KK;Lo;0;L;;;;;N;;;;; 1602;CANADIAN SYLLABICS CARRIER NU;Lo;0;L;;;;;N;;;;; 1603;CANADIAN SYLLABICS CARRIER NO;Lo;0;L;;;;;N;;;;; 1604;CANADIAN SYLLABICS CARRIER NE;Lo;0;L;;;;;N;;;;; 1605;CANADIAN SYLLABICS CARRIER NEE;Lo;0;L;;;;;N;;;;; 1606;CANADIAN SYLLABICS CARRIER NI;Lo;0;L;;;;;N;;;;; 1607;CANADIAN SYLLABICS CARRIER NA;Lo;0;L;;;;;N;;;;; 1608;CANADIAN SYLLABICS CARRIER MU;Lo;0;L;;;;;N;;;;; 1609;CANADIAN SYLLABICS CARRIER MO;Lo;0;L;;;;;N;;;;; 160A;CANADIAN SYLLABICS CARRIER ME;Lo;0;L;;;;;N;;;;; 160B;CANADIAN SYLLABICS CARRIER MEE;Lo;0;L;;;;;N;;;;; 160C;CANADIAN SYLLABICS CARRIER MI;Lo;0;L;;;;;N;;;;; 160D;CANADIAN SYLLABICS CARRIER MA;Lo;0;L;;;;;N;;;;; 160E;CANADIAN SYLLABICS CARRIER YU;Lo;0;L;;;;;N;;;;; 160F;CANADIAN SYLLABICS CARRIER YO;Lo;0;L;;;;;N;;;;; 1610;CANADIAN SYLLABICS CARRIER YE;Lo;0;L;;;;;N;;;;; 1611;CANADIAN SYLLABICS CARRIER YEE;Lo;0;L;;;;;N;;;;; 1612;CANADIAN SYLLABICS CARRIER YI;Lo;0;L;;;;;N;;;;; 1613;CANADIAN SYLLABICS CARRIER YA;Lo;0;L;;;;;N;;;;; 1614;CANADIAN SYLLABICS CARRIER JU;Lo;0;L;;;;;N;;;;; 1615;CANADIAN SYLLABICS SAYISI JU;Lo;0;L;;;;;N;;;;; 1616;CANADIAN SYLLABICS CARRIER JO;Lo;0;L;;;;;N;;;;; 1617;CANADIAN SYLLABICS CARRIER JE;Lo;0;L;;;;;N;;;;; 1618;CANADIAN SYLLABICS CARRIER JEE;Lo;0;L;;;;;N;;;;; 1619;CANADIAN SYLLABICS CARRIER JI;Lo;0;L;;;;;N;;;;; 161A;CANADIAN SYLLABICS SAYISI JI;Lo;0;L;;;;;N;;;;; 161B;CANADIAN SYLLABICS CARRIER JA;Lo;0;L;;;;;N;;;;; 161C;CANADIAN SYLLABICS CARRIER JJU;Lo;0;L;;;;;N;;;;; 161D;CANADIAN SYLLABICS CARRIER JJO;Lo;0;L;;;;;N;;;;; 161E;CANADIAN SYLLABICS CARRIER JJE;Lo;0;L;;;;;N;;;;; 161F;CANADIAN SYLLABICS CARRIER JJEE;Lo;0;L;;;;;N;;;;; 1620;CANADIAN SYLLABICS CARRIER JJI;Lo;0;L;;;;;N;;;;; 1621;CANADIAN SYLLABICS CARRIER JJA;Lo;0;L;;;;;N;;;;; 1622;CANADIAN SYLLABICS CARRIER LU;Lo;0;L;;;;;N;;;;; 1623;CANADIAN SYLLABICS CARRIER LO;Lo;0;L;;;;;N;;;;; 1624;CANADIAN SYLLABICS CARRIER LE;Lo;0;L;;;;;N;;;;; 1625;CANADIAN SYLLABICS CARRIER LEE;Lo;0;L;;;;;N;;;;; 1626;CANADIAN SYLLABICS CARRIER LI;Lo;0;L;;;;;N;;;;; 1627;CANADIAN SYLLABICS CARRIER LA;Lo;0;L;;;;;N;;;;; 1628;CANADIAN SYLLABICS CARRIER DLU;Lo;0;L;;;;;N;;;;; 1629;CANADIAN SYLLABICS CARRIER DLO;Lo;0;L;;;;;N;;;;; 162A;CANADIAN SYLLABICS CARRIER DLE;Lo;0;L;;;;;N;;;;; 162B;CANADIAN SYLLABICS CARRIER DLEE;Lo;0;L;;;;;N;;;;; 162C;CANADIAN SYLLABICS CARRIER DLI;Lo;0;L;;;;;N;;;;; 162D;CANADIAN SYLLABICS CARRIER DLA;Lo;0;L;;;;;N;;;;; 162E;CANADIAN SYLLABICS CARRIER LHU;Lo;0;L;;;;;N;;;;; 162F;CANADIAN SYLLABICS CARRIER LHO;Lo;0;L;;;;;N;;;;; 1630;CANADIAN SYLLABICS CARRIER LHE;Lo;0;L;;;;;N;;;;; 1631;CANADIAN SYLLABICS CARRIER LHEE;Lo;0;L;;;;;N;;;;; 1632;CANADIAN SYLLABICS CARRIER LHI;Lo;0;L;;;;;N;;;;; 1633;CANADIAN SYLLABICS CARRIER LHA;Lo;0;L;;;;;N;;;;; 1634;CANADIAN SYLLABICS CARRIER TLHU;Lo;0;L;;;;;N;;;;; 1635;CANADIAN SYLLABICS CARRIER TLHO;Lo;0;L;;;;;N;;;;; 1636;CANADIAN SYLLABICS CARRIER TLHE;Lo;0;L;;;;;N;;;;; 1637;CANADIAN SYLLABICS CARRIER TLHEE;Lo;0;L;;;;;N;;;;; 1638;CANADIAN SYLLABICS CARRIER TLHI;Lo;0;L;;;;;N;;;;; 1639;CANADIAN SYLLABICS CARRIER TLHA;Lo;0;L;;;;;N;;;;; 163A;CANADIAN SYLLABICS CARRIER TLU;Lo;0;L;;;;;N;;;;; 163B;CANADIAN SYLLABICS CARRIER TLO;Lo;0;L;;;;;N;;;;; 163C;CANADIAN SYLLABICS CARRIER TLE;Lo;0;L;;;;;N;;;;; 163D;CANADIAN SYLLABICS CARRIER TLEE;Lo;0;L;;;;;N;;;;; 163E;CANADIAN SYLLABICS CARRIER TLI;Lo;0;L;;;;;N;;;;; 163F;CANADIAN SYLLABICS CARRIER TLA;Lo;0;L;;;;;N;;;;; 1640;CANADIAN SYLLABICS CARRIER ZU;Lo;0;L;;;;;N;;;;; 1641;CANADIAN SYLLABICS CARRIER ZO;Lo;0;L;;;;;N;;;;; 1642;CANADIAN SYLLABICS CARRIER ZE;Lo;0;L;;;;;N;;;;; 1643;CANADIAN SYLLABICS CARRIER ZEE;Lo;0;L;;;;;N;;;;; 1644;CANADIAN SYLLABICS CARRIER ZI;Lo;0;L;;;;;N;;;;; 1645;CANADIAN SYLLABICS CARRIER ZA;Lo;0;L;;;;;N;;;;; 1646;CANADIAN SYLLABICS CARRIER Z;Lo;0;L;;;;;N;;;;; 1647;CANADIAN SYLLABICS CARRIER INITIAL Z;Lo;0;L;;;;;N;;;;; 1648;CANADIAN SYLLABICS CARRIER DZU;Lo;0;L;;;;;N;;;;; 1649;CANADIAN SYLLABICS CARRIER DZO;Lo;0;L;;;;;N;;;;; 164A;CANADIAN SYLLABICS CARRIER DZE;Lo;0;L;;;;;N;;;;; 164B;CANADIAN SYLLABICS CARRIER DZEE;Lo;0;L;;;;;N;;;;; 164C;CANADIAN SYLLABICS CARRIER DZI;Lo;0;L;;;;;N;;;;; 164D;CANADIAN SYLLABICS CARRIER DZA;Lo;0;L;;;;;N;;;;; 164E;CANADIAN SYLLABICS CARRIER SU;Lo;0;L;;;;;N;;;;; 164F;CANADIAN SYLLABICS CARRIER SO;Lo;0;L;;;;;N;;;;; 1650;CANADIAN SYLLABICS CARRIER SE;Lo;0;L;;;;;N;;;;; 1651;CANADIAN SYLLABICS CARRIER SEE;Lo;0;L;;;;;N;;;;; 1652;CANADIAN SYLLABICS CARRIER SI;Lo;0;L;;;;;N;;;;; 1653;CANADIAN SYLLABICS CARRIER SA;Lo;0;L;;;;;N;;;;; 1654;CANADIAN SYLLABICS CARRIER SHU;Lo;0;L;;;;;N;;;;; 1655;CANADIAN SYLLABICS CARRIER SHO;Lo;0;L;;;;;N;;;;; 1656;CANADIAN SYLLABICS CARRIER SHE;Lo;0;L;;;;;N;;;;; 1657;CANADIAN SYLLABICS CARRIER SHEE;Lo;0;L;;;;;N;;;;; 1658;CANADIAN SYLLABICS CARRIER SHI;Lo;0;L;;;;;N;;;;; 1659;CANADIAN SYLLABICS CARRIER SHA;Lo;0;L;;;;;N;;;;; 165A;CANADIAN SYLLABICS CARRIER SH;Lo;0;L;;;;;N;;;;; 165B;CANADIAN SYLLABICS CARRIER TSU;Lo;0;L;;;;;N;;;;; 165C;CANADIAN SYLLABICS CARRIER TSO;Lo;0;L;;;;;N;;;;; 165D;CANADIAN SYLLABICS CARRIER TSE;Lo;0;L;;;;;N;;;;; 165E;CANADIAN SYLLABICS CARRIER TSEE;Lo;0;L;;;;;N;;;;; 165F;CANADIAN SYLLABICS CARRIER TSI;Lo;0;L;;;;;N;;;;; 1660;CANADIAN SYLLABICS CARRIER TSA;Lo;0;L;;;;;N;;;;; 1661;CANADIAN SYLLABICS CARRIER CHU;Lo;0;L;;;;;N;;;;; 1662;CANADIAN SYLLABICS CARRIER CHO;Lo;0;L;;;;;N;;;;; 1663;CANADIAN SYLLABICS CARRIER CHE;Lo;0;L;;;;;N;;;;; 1664;CANADIAN SYLLABICS CARRIER CHEE;Lo;0;L;;;;;N;;;;; 1665;CANADIAN SYLLABICS CARRIER CHI;Lo;0;L;;;;;N;;;;; 1666;CANADIAN SYLLABICS CARRIER CHA;Lo;0;L;;;;;N;;;;; 1667;CANADIAN SYLLABICS CARRIER TTSU;Lo;0;L;;;;;N;;;;; 1668;CANADIAN SYLLABICS CARRIER TTSO;Lo;0;L;;;;;N;;;;; 1669;CANADIAN SYLLABICS CARRIER TTSE;Lo;0;L;;;;;N;;;;; 166A;CANADIAN SYLLABICS CARRIER TTSEE;Lo;0;L;;;;;N;;;;; 166B;CANADIAN SYLLABICS CARRIER TTSI;Lo;0;L;;;;;N;;;;; 166C;CANADIAN SYLLABICS CARRIER TTSA;Lo;0;L;;;;;N;;;;; 166D;CANADIAN SYLLABICS CHI SIGN;Po;0;L;;;;;N;;;;; 166E;CANADIAN SYLLABICS FULL STOP;Po;0;L;;;;;N;;;;; 166F;CANADIAN SYLLABICS QAI;Lo;0;L;;;;;N;;;;; 1670;CANADIAN SYLLABICS NGAI;Lo;0;L;;;;;N;;;;; 1671;CANADIAN SYLLABICS NNGI;Lo;0;L;;;;;N;;;;; 1672;CANADIAN SYLLABICS NNGII;Lo;0;L;;;;;N;;;;; 1673;CANADIAN SYLLABICS NNGO;Lo;0;L;;;;;N;;;;; 1674;CANADIAN SYLLABICS NNGOO;Lo;0;L;;;;;N;;;;; 1675;CANADIAN SYLLABICS NNGA;Lo;0;L;;;;;N;;;;; 1676;CANADIAN SYLLABICS NNGAA;Lo;0;L;;;;;N;;;;; 1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;; 1681;OGHAM LETTER BEITH;Lo;0;L;;;;;N;;;;; 1682;OGHAM LETTER LUIS;Lo;0;L;;;;;N;;;;; 1683;OGHAM LETTER FEARN;Lo;0;L;;;;;N;;;;; 1684;OGHAM LETTER SAIL;Lo;0;L;;;;;N;;;;; 1685;OGHAM LETTER NION;Lo;0;L;;;;;N;;;;; 1686;OGHAM LETTER UATH;Lo;0;L;;;;;N;;;;; 1687;OGHAM LETTER DAIR;Lo;0;L;;;;;N;;;;; 1688;OGHAM LETTER TINNE;Lo;0;L;;;;;N;;;;; 1689;OGHAM LETTER COLL;Lo;0;L;;;;;N;;;;; 168A;OGHAM LETTER CEIRT;Lo;0;L;;;;;N;;;;; 168B;OGHAM LETTER MUIN;Lo;0;L;;;;;N;;;;; 168C;OGHAM LETTER GORT;Lo;0;L;;;;;N;;;;; 168D;OGHAM LETTER NGEADAL;Lo;0;L;;;;;N;;;;; 168E;OGHAM LETTER STRAIF;Lo;0;L;;;;;N;;;;; 168F;OGHAM LETTER RUIS;Lo;0;L;;;;;N;;;;; 1690;OGHAM LETTER AILM;Lo;0;L;;;;;N;;;;; 1691;OGHAM LETTER ONN;Lo;0;L;;;;;N;;;;; 1692;OGHAM LETTER UR;Lo;0;L;;;;;N;;;;; 1693;OGHAM LETTER EADHADH;Lo;0;L;;;;;N;;;;; 1694;OGHAM LETTER IODHADH;Lo;0;L;;;;;N;;;;; 1695;OGHAM LETTER EABHADH;Lo;0;L;;;;;N;;;;; 1696;OGHAM LETTER OR;Lo;0;L;;;;;N;;;;; 1697;OGHAM LETTER UILLEANN;Lo;0;L;;;;;N;;;;; 1698;OGHAM LETTER IFIN;Lo;0;L;;;;;N;;;;; 1699;OGHAM LETTER EAMHANCHOLL;Lo;0;L;;;;;N;;;;; 169A;OGHAM LETTER PEITH;Lo;0;L;;;;;N;;;;; 169B;OGHAM FEATHER MARK;Ps;0;ON;;;;;N;;;;; 169C;OGHAM REVERSED FEATHER MARK;Pe;0;ON;;;;;N;;;;; 16A0;RUNIC LETTER FEHU FEOH FE F;Lo;0;L;;;;;N;;;;; 16A1;RUNIC LETTER V;Lo;0;L;;;;;N;;;;; 16A2;RUNIC LETTER URUZ UR U;Lo;0;L;;;;;N;;;;; 16A3;RUNIC LETTER YR;Lo;0;L;;;;;N;;;;; 16A4;RUNIC LETTER Y;Lo;0;L;;;;;N;;;;; 16A5;RUNIC LETTER W;Lo;0;L;;;;;N;;;;; 16A6;RUNIC LETTER THURISAZ THURS THORN;Lo;0;L;;;;;N;;;;; 16A7;RUNIC LETTER ETH;Lo;0;L;;;;;N;;;;; 16A8;RUNIC LETTER ANSUZ A;Lo;0;L;;;;;N;;;;; 16A9;RUNIC LETTER OS O;Lo;0;L;;;;;N;;;;; 16AA;RUNIC LETTER AC A;Lo;0;L;;;;;N;;;;; 16AB;RUNIC LETTER AESC;Lo;0;L;;;;;N;;;;; 16AC;RUNIC LETTER LONG-BRANCH-OSS O;Lo;0;L;;;;;N;;;;; 16AD;RUNIC LETTER SHORT-TWIG-OSS O;Lo;0;L;;;;;N;;;;; 16AE;RUNIC LETTER O;Lo;0;L;;;;;N;;;;; 16AF;RUNIC LETTER OE;Lo;0;L;;;;;N;;;;; 16B0;RUNIC LETTER ON;Lo;0;L;;;;;N;;;;; 16B1;RUNIC LETTER RAIDO RAD REID R;Lo;0;L;;;;;N;;;;; 16B2;RUNIC LETTER KAUNA;Lo;0;L;;;;;N;;;;; 16B3;RUNIC LETTER CEN;Lo;0;L;;;;;N;;;;; 16B4;RUNIC LETTER KAUN K;Lo;0;L;;;;;N;;;;; 16B5;RUNIC LETTER G;Lo;0;L;;;;;N;;;;; 16B6;RUNIC LETTER ENG;Lo;0;L;;;;;N;;;;; 16B7;RUNIC LETTER GEBO GYFU G;Lo;0;L;;;;;N;;;;; 16B8;RUNIC LETTER GAR;Lo;0;L;;;;;N;;;;; 16B9;RUNIC LETTER WUNJO WYNN W;Lo;0;L;;;;;N;;;;; 16BA;RUNIC LETTER HAGLAZ H;Lo;0;L;;;;;N;;;;; 16BB;RUNIC LETTER HAEGL H;Lo;0;L;;;;;N;;;;; 16BC;RUNIC LETTER LONG-BRANCH-HAGALL H;Lo;0;L;;;;;N;;;;; 16BD;RUNIC LETTER SHORT-TWIG-HAGALL H;Lo;0;L;;;;;N;;;;; 16BE;RUNIC LETTER NAUDIZ NYD NAUD N;Lo;0;L;;;;;N;;;;; 16BF;RUNIC LETTER SHORT-TWIG-NAUD N;Lo;0;L;;;;;N;;;;; 16C0;RUNIC LETTER DOTTED-N;Lo;0;L;;;;;N;;;;; 16C1;RUNIC LETTER ISAZ IS ISS I;Lo;0;L;;;;;N;;;;; 16C2;RUNIC LETTER E;Lo;0;L;;;;;N;;;;; 16C3;RUNIC LETTER JERAN J;Lo;0;L;;;;;N;;;;; 16C4;RUNIC LETTER GER;Lo;0;L;;;;;N;;;;; 16C5;RUNIC LETTER LONG-BRANCH-AR AE;Lo;0;L;;;;;N;;;;; 16C6;RUNIC LETTER SHORT-TWIG-AR A;Lo;0;L;;;;;N;;;;; 16C7;RUNIC LETTER IWAZ EOH;Lo;0;L;;;;;N;;;;; 16C8;RUNIC LETTER PERTHO PEORTH P;Lo;0;L;;;;;N;;;;; 16C9;RUNIC LETTER ALGIZ EOLHX;Lo;0;L;;;;;N;;;;; 16CA;RUNIC LETTER SOWILO S;Lo;0;L;;;;;N;;;;; 16CB;RUNIC LETTER SIGEL LONG-BRANCH-SOL S;Lo;0;L;;;;;N;;;;; 16CC;RUNIC LETTER SHORT-TWIG-SOL S;Lo;0;L;;;;;N;;;;; 16CD;RUNIC LETTER C;Lo;0;L;;;;;N;;;;; 16CE;RUNIC LETTER Z;Lo;0;L;;;;;N;;;;; 16CF;RUNIC LETTER TIWAZ TIR TYR T;Lo;0;L;;;;;N;;;;; 16D0;RUNIC LETTER SHORT-TWIG-TYR T;Lo;0;L;;;;;N;;;;; 16D1;RUNIC LETTER D;Lo;0;L;;;;;N;;;;; 16D2;RUNIC LETTER BERKANAN BEORC BJARKAN B;Lo;0;L;;;;;N;;;;; 16D3;RUNIC LETTER SHORT-TWIG-BJARKAN B;Lo;0;L;;;;;N;;;;; 16D4;RUNIC LETTER DOTTED-P;Lo;0;L;;;;;N;;;;; 16D5;RUNIC LETTER OPEN-P;Lo;0;L;;;;;N;;;;; 16D6;RUNIC LETTER EHWAZ EH E;Lo;0;L;;;;;N;;;;; 16D7;RUNIC LETTER MANNAZ MAN M;Lo;0;L;;;;;N;;;;; 16D8;RUNIC LETTER LONG-BRANCH-MADR M;Lo;0;L;;;;;N;;;;; 16D9;RUNIC LETTER SHORT-TWIG-MADR M;Lo;0;L;;;;;N;;;;; 16DA;RUNIC LETTER LAUKAZ LAGU LOGR L;Lo;0;L;;;;;N;;;;; 16DB;RUNIC LETTER DOTTED-L;Lo;0;L;;;;;N;;;;; 16DC;RUNIC LETTER INGWAZ;Lo;0;L;;;;;N;;;;; 16DD;RUNIC LETTER ING;Lo;0;L;;;;;N;;;;; 16DE;RUNIC LETTER DAGAZ DAEG D;Lo;0;L;;;;;N;;;;; 16DF;RUNIC LETTER OTHALAN ETHEL O;Lo;0;L;;;;;N;;;;; 16E0;RUNIC LETTER EAR;Lo;0;L;;;;;N;;;;; 16E1;RUNIC LETTER IOR;Lo;0;L;;;;;N;;;;; 16E2;RUNIC LETTER CWEORTH;Lo;0;L;;;;;N;;;;; 16E3;RUNIC LETTER CALC;Lo;0;L;;;;;N;;;;; 16E4;RUNIC LETTER CEALC;Lo;0;L;;;;;N;;;;; 16E5;RUNIC LETTER STAN;Lo;0;L;;;;;N;;;;; 16E6;RUNIC LETTER LONG-BRANCH-YR;Lo;0;L;;;;;N;;;;; 16E7;RUNIC LETTER SHORT-TWIG-YR;Lo;0;L;;;;;N;;;;; 16E8;RUNIC LETTER ICELANDIC-YR;Lo;0;L;;;;;N;;;;; 16E9;RUNIC LETTER Q;Lo;0;L;;;;;N;;;;; 16EA;RUNIC LETTER X;Lo;0;L;;;;;N;;;;; 16EB;RUNIC SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;; 16EC;RUNIC MULTIPLE PUNCTUATION;Po;0;L;;;;;N;;;;; 16ED;RUNIC CROSS PUNCTUATION;Po;0;L;;;;;N;;;;; 16EE;RUNIC ARLAUG SYMBOL;Nl;0;L;;;;17;N;;golden number 17;;; 16EF;RUNIC TVIMADUR SYMBOL;Nl;0;L;;;;18;N;;golden number 18;;; 16F0;RUNIC BELGTHOR SYMBOL;Nl;0;L;;;;19;N;;golden number 19;;; 1700;TAGALOG LETTER A;Lo;0;L;;;;;N;;;;; 1701;TAGALOG LETTER I;Lo;0;L;;;;;N;;;;; 1702;TAGALOG LETTER U;Lo;0;L;;;;;N;;;;; 1703;TAGALOG LETTER KA;Lo;0;L;;;;;N;;;;; 1704;TAGALOG LETTER GA;Lo;0;L;;;;;N;;;;; 1705;TAGALOG LETTER NGA;Lo;0;L;;;;;N;;;;; 1706;TAGALOG LETTER TA;Lo;0;L;;;;;N;;;;; 1707;TAGALOG LETTER DA;Lo;0;L;;;;;N;;;;; 1708;TAGALOG LETTER NA;Lo;0;L;;;;;N;;;;; 1709;TAGALOG LETTER PA;Lo;0;L;;;;;N;;;;; 170A;TAGALOG LETTER BA;Lo;0;L;;;;;N;;;;; 170B;TAGALOG LETTER MA;Lo;0;L;;;;;N;;;;; 170C;TAGALOG LETTER YA;Lo;0;L;;;;;N;;;;; 170E;TAGALOG LETTER LA;Lo;0;L;;;;;N;;;;; 170F;TAGALOG LETTER WA;Lo;0;L;;;;;N;;;;; 1710;TAGALOG LETTER SA;Lo;0;L;;;;;N;;;;; 1711;TAGALOG LETTER HA;Lo;0;L;;;;;N;;;;; 1712;TAGALOG VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 1713;TAGALOG VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; 1714;TAGALOG SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 1720;HANUNOO LETTER A;Lo;0;L;;;;;N;;;;; 1721;HANUNOO LETTER I;Lo;0;L;;;;;N;;;;; 1722;HANUNOO LETTER U;Lo;0;L;;;;;N;;;;; 1723;HANUNOO LETTER KA;Lo;0;L;;;;;N;;;;; 1724;HANUNOO LETTER GA;Lo;0;L;;;;;N;;;;; 1725;HANUNOO LETTER NGA;Lo;0;L;;;;;N;;;;; 1726;HANUNOO LETTER TA;Lo;0;L;;;;;N;;;;; 1727;HANUNOO LETTER DA;Lo;0;L;;;;;N;;;;; 1728;HANUNOO LETTER NA;Lo;0;L;;;;;N;;;;; 1729;HANUNOO LETTER PA;Lo;0;L;;;;;N;;;;; 172A;HANUNOO LETTER BA;Lo;0;L;;;;;N;;;;; 172B;HANUNOO LETTER MA;Lo;0;L;;;;;N;;;;; 172C;HANUNOO LETTER YA;Lo;0;L;;;;;N;;;;; 172D;HANUNOO LETTER RA;Lo;0;L;;;;;N;;;;; 172E;HANUNOO LETTER LA;Lo;0;L;;;;;N;;;;; 172F;HANUNOO LETTER WA;Lo;0;L;;;;;N;;;;; 1730;HANUNOO LETTER SA;Lo;0;L;;;;;N;;;;; 1731;HANUNOO LETTER HA;Lo;0;L;;;;;N;;;;; 1732;HANUNOO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 1733;HANUNOO VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; 1734;HANUNOO SIGN PAMUDPOD;Mn;9;NSM;;;;;N;;;;; 1735;PHILIPPINE SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;; 1736;PHILIPPINE DOUBLE PUNCTUATION;Po;0;L;;;;;N;;;;; 1740;BUHID LETTER A;Lo;0;L;;;;;N;;;;; 1741;BUHID LETTER I;Lo;0;L;;;;;N;;;;; 1742;BUHID LETTER U;Lo;0;L;;;;;N;;;;; 1743;BUHID LETTER KA;Lo;0;L;;;;;N;;;;; 1744;BUHID LETTER GA;Lo;0;L;;;;;N;;;;; 1745;BUHID LETTER NGA;Lo;0;L;;;;;N;;;;; 1746;BUHID LETTER TA;Lo;0;L;;;;;N;;;;; 1747;BUHID LETTER DA;Lo;0;L;;;;;N;;;;; 1748;BUHID LETTER NA;Lo;0;L;;;;;N;;;;; 1749;BUHID LETTER PA;Lo;0;L;;;;;N;;;;; 174A;BUHID LETTER BA;Lo;0;L;;;;;N;;;;; 174B;BUHID LETTER MA;Lo;0;L;;;;;N;;;;; 174C;BUHID LETTER YA;Lo;0;L;;;;;N;;;;; 174D;BUHID LETTER RA;Lo;0;L;;;;;N;;;;; 174E;BUHID LETTER LA;Lo;0;L;;;;;N;;;;; 174F;BUHID LETTER WA;Lo;0;L;;;;;N;;;;; 1750;BUHID LETTER SA;Lo;0;L;;;;;N;;;;; 1751;BUHID LETTER HA;Lo;0;L;;;;;N;;;;; 1752;BUHID VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 1753;BUHID VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; 1760;TAGBANWA LETTER A;Lo;0;L;;;;;N;;;;; 1761;TAGBANWA LETTER I;Lo;0;L;;;;;N;;;;; 1762;TAGBANWA LETTER U;Lo;0;L;;;;;N;;;;; 1763;TAGBANWA LETTER KA;Lo;0;L;;;;;N;;;;; 1764;TAGBANWA LETTER GA;Lo;0;L;;;;;N;;;;; 1765;TAGBANWA LETTER NGA;Lo;0;L;;;;;N;;;;; 1766;TAGBANWA LETTER TA;Lo;0;L;;;;;N;;;;; 1767;TAGBANWA LETTER DA;Lo;0;L;;;;;N;;;;; 1768;TAGBANWA LETTER NA;Lo;0;L;;;;;N;;;;; 1769;TAGBANWA LETTER PA;Lo;0;L;;;;;N;;;;; 176A;TAGBANWA LETTER BA;Lo;0;L;;;;;N;;;;; 176B;TAGBANWA LETTER MA;Lo;0;L;;;;;N;;;;; 176C;TAGBANWA LETTER YA;Lo;0;L;;;;;N;;;;; 176E;TAGBANWA LETTER LA;Lo;0;L;;;;;N;;;;; 176F;TAGBANWA LETTER WA;Lo;0;L;;;;;N;;;;; 1770;TAGBANWA LETTER SA;Lo;0;L;;;;;N;;;;; 1772;TAGBANWA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 1773;TAGBANWA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; 1780;KHMER LETTER KA;Lo;0;L;;;;;N;;;;; 1781;KHMER LETTER KHA;Lo;0;L;;;;;N;;;;; 1782;KHMER LETTER KO;Lo;0;L;;;;;N;;;;; 1783;KHMER LETTER KHO;Lo;0;L;;;;;N;;;;; 1784;KHMER LETTER NGO;Lo;0;L;;;;;N;;;;; 1785;KHMER LETTER CA;Lo;0;L;;;;;N;;;;; 1786;KHMER LETTER CHA;Lo;0;L;;;;;N;;;;; 1787;KHMER LETTER CO;Lo;0;L;;;;;N;;;;; 1788;KHMER LETTER CHO;Lo;0;L;;;;;N;;;;; 1789;KHMER LETTER NYO;Lo;0;L;;;;;N;;;;; 178A;KHMER LETTER DA;Lo;0;L;;;;;N;;;;; 178B;KHMER LETTER TTHA;Lo;0;L;;;;;N;;;;; 178C;KHMER LETTER DO;Lo;0;L;;;;;N;;;;; 178D;KHMER LETTER TTHO;Lo;0;L;;;;;N;;;;; 178E;KHMER LETTER NNO;Lo;0;L;;;;;N;;;;; 178F;KHMER LETTER TA;Lo;0;L;;;;;N;;;;; 1790;KHMER LETTER THA;Lo;0;L;;;;;N;;;;; 1791;KHMER LETTER TO;Lo;0;L;;;;;N;;;;; 1792;KHMER LETTER THO;Lo;0;L;;;;;N;;;;; 1793;KHMER LETTER NO;Lo;0;L;;;;;N;;;;; 1794;KHMER LETTER BA;Lo;0;L;;;;;N;;;;; 1795;KHMER LETTER PHA;Lo;0;L;;;;;N;;;;; 1796;KHMER LETTER PO;Lo;0;L;;;;;N;;;;; 1797;KHMER LETTER PHO;Lo;0;L;;;;;N;;;;; 1798;KHMER LETTER MO;Lo;0;L;;;;;N;;;;; 1799;KHMER LETTER YO;Lo;0;L;;;;;N;;;;; 179A;KHMER LETTER RO;Lo;0;L;;;;;N;;;;; 179B;KHMER LETTER LO;Lo;0;L;;;;;N;;;;; 179C;KHMER LETTER VO;Lo;0;L;;;;;N;;;;; 179D;KHMER LETTER SHA;Lo;0;L;;;;;N;;;;; 179E;KHMER LETTER SSO;Lo;0;L;;;;;N;;;;; 179F;KHMER LETTER SA;Lo;0;L;;;;;N;;;;; 17A0;KHMER LETTER HA;Lo;0;L;;;;;N;;;;; 17A1;KHMER LETTER LA;Lo;0;L;;;;;N;;;;; 17A2;KHMER LETTER QA;Lo;0;L;;;;;N;;;;; 17A3;KHMER INDEPENDENT VOWEL QAQ;Lo;0;L;;;;;N;;;;; 17A4;KHMER INDEPENDENT VOWEL QAA;Lo;0;L;;;;;N;;;;; 17A5;KHMER INDEPENDENT VOWEL QI;Lo;0;L;;;;;N;;;;; 17A6;KHMER INDEPENDENT VOWEL QII;Lo;0;L;;;;;N;;;;; 17A7;KHMER INDEPENDENT VOWEL QU;Lo;0;L;;;;;N;;;;; 17A8;KHMER INDEPENDENT VOWEL QUK;Lo;0;L;;;;;N;;;;; 17A9;KHMER INDEPENDENT VOWEL QUU;Lo;0;L;;;;;N;;;;; 17AA;KHMER INDEPENDENT VOWEL QUUV;Lo;0;L;;;;;N;;;;; 17AB;KHMER INDEPENDENT VOWEL RY;Lo;0;L;;;;;N;;;;; 17AC;KHMER INDEPENDENT VOWEL RYY;Lo;0;L;;;;;N;;;;; 17AD;KHMER INDEPENDENT VOWEL LY;Lo;0;L;;;;;N;;;;; 17AE;KHMER INDEPENDENT VOWEL LYY;Lo;0;L;;;;;N;;;;; 17AF;KHMER INDEPENDENT VOWEL QE;Lo;0;L;;;;;N;;;;; 17B0;KHMER INDEPENDENT VOWEL QAI;Lo;0;L;;;;;N;;;;; 17B1;KHMER INDEPENDENT VOWEL QOO TYPE ONE;Lo;0;L;;;;;N;;;;; 17B2;KHMER INDEPENDENT VOWEL QOO TYPE TWO;Lo;0;L;;;;;N;;;;; 17B3;KHMER INDEPENDENT VOWEL QAU;Lo;0;L;;;;;N;;;;; 17B4;KHMER VOWEL INHERENT AQ;Mc;0;L;;;;;N;;;;; 17B5;KHMER VOWEL INHERENT AA;Mc;0;L;;;;;N;;;;; 17B6;KHMER VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; 17B7;KHMER VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 17B8;KHMER VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; 17B9;KHMER VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;; 17BA;KHMER VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;; 17BB;KHMER VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; 17BC;KHMER VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; 17BD;KHMER VOWEL SIGN UA;Mn;0;NSM;;;;;N;;;;; 17BE;KHMER VOWEL SIGN OE;Mc;0;L;;;;;N;;;;; 17BF;KHMER VOWEL SIGN YA;Mc;0;L;;;;;N;;;;; 17C0;KHMER VOWEL SIGN IE;Mc;0;L;;;;;N;;;;; 17C1;KHMER VOWEL SIGN E;Mc;0;L;;;;;N;;;;; 17C2;KHMER VOWEL SIGN AE;Mc;0;L;;;;;N;;;;; 17C3;KHMER VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; 17C4;KHMER VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; 17C5;KHMER VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; 17C6;KHMER SIGN NIKAHIT;Mn;0;NSM;;;;;N;;;;; 17C7;KHMER SIGN REAHMUK;Mc;0;L;;;;;N;;;;; 17C8;KHMER SIGN YUUKALEAPINTU;Mc;0;L;;;;;N;;;;; 17C9;KHMER SIGN MUUSIKATOAN;Mn;0;NSM;;;;;N;;;;; 17CA;KHMER SIGN TRIISAP;Mn;0;NSM;;;;;N;;;;; 17CB;KHMER SIGN BANTOC;Mn;0;NSM;;;;;N;;;;; 17CC;KHMER SIGN ROBAT;Mn;0;NSM;;;;;N;;;;; 17CD;KHMER SIGN TOANDAKHIAT;Mn;0;NSM;;;;;N;;;;; 17CE;KHMER SIGN KAKABAT;Mn;0;NSM;;;;;N;;;;; 17CF;KHMER SIGN AHSDA;Mn;0;NSM;;;;;N;;;;; 17D0;KHMER SIGN SAMYOK SANNYA;Mn;0;NSM;;;;;N;;;;; 17D1;KHMER SIGN VIRIAM;Mn;0;NSM;;;;;N;;;;; 17D2;KHMER SIGN COENG;Mn;9;NSM;;;;;N;;;;; 17D3;KHMER SIGN BATHAMASAT;Mn;0;NSM;;;;;N;;;;; 17D4;KHMER SIGN KHAN;Po;0;L;;;;;N;;;;; 17D5;KHMER SIGN BARIYOOSAN;Po;0;L;;;;;N;;;;; 17D6;KHMER SIGN CAMNUC PII KUUH;Po;0;L;;;;;N;;;;; 17D7;KHMER SIGN LEK TOO;Lm;0;L;;;;;N;;;;; 17D8;KHMER SIGN BEYYAL;Po;0;L;;;;;N;;;;; 17D9;KHMER SIGN PHNAEK MUAN;Po;0;L;;;;;N;;;;; 17DA;KHMER SIGN KOOMUUT;Po;0;L;;;;;N;;;;; 17DB;KHMER CURRENCY SYMBOL RIEL;Sc;0;ET;;;;;N;;;;; 17DC;KHMER SIGN AVAKRAHASANYA;Lo;0;L;;;;;N;;;;; 17E0;KHMER DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 17E1;KHMER DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 17E2;KHMER DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 17E3;KHMER DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; 17E4;KHMER DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; 17E5;KHMER DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; 17E6;KHMER DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; 17E7;KHMER DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 17E8;KHMER DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 17E9;KHMER DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 1800;MONGOLIAN BIRGA;Po;0;ON;;;;;N;;;;; 1801;MONGOLIAN ELLIPSIS;Po;0;ON;;;;;N;;;;; 1802;MONGOLIAN COMMA;Po;0;ON;;;;;N;;;;; 1803;MONGOLIAN FULL STOP;Po;0;ON;;;;;N;;;;; 1804;MONGOLIAN COLON;Po;0;ON;;;;;N;;;;; 1805;MONGOLIAN FOUR DOTS;Po;0;ON;;;;;N;;;;; 1806;MONGOLIAN TODO SOFT HYPHEN;Pd;0;ON;;;;;N;;;;; 1807;MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER;Po;0;ON;;;;;N;;;;; 1808;MONGOLIAN MANCHU COMMA;Po;0;ON;;;;;N;;;;; 1809;MONGOLIAN MANCHU FULL STOP;Po;0;ON;;;;;N;;;;; 180A;MONGOLIAN NIRUGU;Po;0;ON;;;;;N;;;;; 180B;MONGOLIAN FREE VARIATION SELECTOR ONE;Mn;0;NSM;;;;;N;;;;; 180C;MONGOLIAN FREE VARIATION SELECTOR TWO;Mn;0;NSM;;;;;N;;;;; 180D;MONGOLIAN FREE VARIATION SELECTOR THREE;Mn;0;NSM;;;;;N;;;;; 180E;MONGOLIAN VOWEL SEPARATOR;Cf;0;BN;;;;;N;;;;; 1810;MONGOLIAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 1811;MONGOLIAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 1812;MONGOLIAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; 1813;MONGOLIAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; 1814;MONGOLIAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; 1815;MONGOLIAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; 1816;MONGOLIAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; 1817;MONGOLIAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 1818;MONGOLIAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 1819;MONGOLIAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 1820;MONGOLIAN LETTER A;Lo;0;L;;;;;N;;;;; 1821;MONGOLIAN LETTER E;Lo;0;L;;;;;N;;;;; 1822;MONGOLIAN LETTER I;Lo;0;L;;;;;N;;;;; 1823;MONGOLIAN LETTER O;Lo;0;L;;;;;N;;;;; 1824;MONGOLIAN LETTER U;Lo;0;L;;;;;N;;;;; 1825;MONGOLIAN LETTER OE;Lo;0;L;;;;;N;;;;; 1826;MONGOLIAN LETTER UE;Lo;0;L;;;;;N;;;;; 1827;MONGOLIAN LETTER EE;Lo;0;L;;;;;N;;;;; 1828;MONGOLIAN LETTER NA;Lo;0;L;;;;;N;;;;; 1829;MONGOLIAN LETTER ANG;Lo;0;L;;;;;N;;;;; 182A;MONGOLIAN LETTER BA;Lo;0;L;;;;;N;;;;; 182B;MONGOLIAN LETTER PA;Lo;0;L;;;;;N;;;;; 182C;MONGOLIAN LETTER QA;Lo;0;L;;;;;N;;;;; 182D;MONGOLIAN LETTER GA;Lo;0;L;;;;;N;;;;; 182E;MONGOLIAN LETTER MA;Lo;0;L;;;;;N;;;;; 182F;MONGOLIAN LETTER LA;Lo;0;L;;;;;N;;;;; 1830;MONGOLIAN LETTER SA;Lo;0;L;;;;;N;;;;; 1831;MONGOLIAN LETTER SHA;Lo;0;L;;;;;N;;;;; 1832;MONGOLIAN LETTER TA;Lo;0;L;;;;;N;;;;; 1833;MONGOLIAN LETTER DA;Lo;0;L;;;;;N;;;;; 1834;MONGOLIAN LETTER CHA;Lo;0;L;;;;;N;;;;; 1835;MONGOLIAN LETTER JA;Lo;0;L;;;;;N;;;;; 1836;MONGOLIAN LETTER YA;Lo;0;L;;;;;N;;;;; 1837;MONGOLIAN LETTER RA;Lo;0;L;;;;;N;;;;; 1838;MONGOLIAN LETTER WA;Lo;0;L;;;;;N;;;;; 1839;MONGOLIAN LETTER FA;Lo;0;L;;;;;N;;;;; 183A;MONGOLIAN LETTER KA;Lo;0;L;;;;;N;;;;; 183B;MONGOLIAN LETTER KHA;Lo;0;L;;;;;N;;;;; 183C;MONGOLIAN LETTER TSA;Lo;0;L;;;;;N;;;;; 183D;MONGOLIAN LETTER ZA;Lo;0;L;;;;;N;;;;; 183E;MONGOLIAN LETTER HAA;Lo;0;L;;;;;N;;;;; 183F;MONGOLIAN LETTER ZRA;Lo;0;L;;;;;N;;;;; 1840;MONGOLIAN LETTER LHA;Lo;0;L;;;;;N;;;;; 1841;MONGOLIAN LETTER ZHI;Lo;0;L;;;;;N;;;;; 1842;MONGOLIAN LETTER CHI;Lo;0;L;;;;;N;;;;; 1843;MONGOLIAN LETTER TODO LONG VOWEL SIGN;Lm;0;L;;;;;N;;;;; 1844;MONGOLIAN LETTER TODO E;Lo;0;L;;;;;N;;;;; 1845;MONGOLIAN LETTER TODO I;Lo;0;L;;;;;N;;;;; 1846;MONGOLIAN LETTER TODO O;Lo;0;L;;;;;N;;;;; 1847;MONGOLIAN LETTER TODO U;Lo;0;L;;;;;N;;;;; 1848;MONGOLIAN LETTER TODO OE;Lo;0;L;;;;;N;;;;; 1849;MONGOLIAN LETTER TODO UE;Lo;0;L;;;;;N;;;;; 184A;MONGOLIAN LETTER TODO ANG;Lo;0;L;;;;;N;;;;; 184B;MONGOLIAN LETTER TODO BA;Lo;0;L;;;;;N;;;;; 184C;MONGOLIAN LETTER TODO PA;Lo;0;L;;;;;N;;;;; 184D;MONGOLIAN LETTER TODO QA;Lo;0;L;;;;;N;;;;; 184E;MONGOLIAN LETTER TODO GA;Lo;0;L;;;;;N;;;;; 184F;MONGOLIAN LETTER TODO MA;Lo;0;L;;;;;N;;;;; 1850;MONGOLIAN LETTER TODO TA;Lo;0;L;;;;;N;;;;; 1851;MONGOLIAN LETTER TODO DA;Lo;0;L;;;;;N;;;;; 1852;MONGOLIAN LETTER TODO CHA;Lo;0;L;;;;;N;;;;; 1853;MONGOLIAN LETTER TODO JA;Lo;0;L;;;;;N;;;;; 1854;MONGOLIAN LETTER TODO TSA;Lo;0;L;;;;;N;;;;; 1855;MONGOLIAN LETTER TODO YA;Lo;0;L;;;;;N;;;;; 1856;MONGOLIAN LETTER TODO WA;Lo;0;L;;;;;N;;;;; 1857;MONGOLIAN LETTER TODO KA;Lo;0;L;;;;;N;;;;; 1858;MONGOLIAN LETTER TODO GAA;Lo;0;L;;;;;N;;;;; 1859;MONGOLIAN LETTER TODO HAA;Lo;0;L;;;;;N;;;;; 185A;MONGOLIAN LETTER TODO JIA;Lo;0;L;;;;;N;;;;; 185B;MONGOLIAN LETTER TODO NIA;Lo;0;L;;;;;N;;;;; 185C;MONGOLIAN LETTER TODO DZA;Lo;0;L;;;;;N;;;;; 185D;MONGOLIAN LETTER SIBE E;Lo;0;L;;;;;N;;;;; 185E;MONGOLIAN LETTER SIBE I;Lo;0;L;;;;;N;;;;; 185F;MONGOLIAN LETTER SIBE IY;Lo;0;L;;;;;N;;;;; 1860;MONGOLIAN LETTER SIBE UE;Lo;0;L;;;;;N;;;;; 1861;MONGOLIAN LETTER SIBE U;Lo;0;L;;;;;N;;;;; 1862;MONGOLIAN LETTER SIBE ANG;Lo;0;L;;;;;N;;;;; 1863;MONGOLIAN LETTER SIBE KA;Lo;0;L;;;;;N;;;;; 1864;MONGOLIAN LETTER SIBE GA;Lo;0;L;;;;;N;;;;; 1865;MONGOLIAN LETTER SIBE HA;Lo;0;L;;;;;N;;;;; 1866;MONGOLIAN LETTER SIBE PA;Lo;0;L;;;;;N;;;;; 1867;MONGOLIAN LETTER SIBE SHA;Lo;0;L;;;;;N;;;;; 1868;MONGOLIAN LETTER SIBE TA;Lo;0;L;;;;;N;;;;; 1869;MONGOLIAN LETTER SIBE DA;Lo;0;L;;;;;N;;;;; 186A;MONGOLIAN LETTER SIBE JA;Lo;0;L;;;;;N;;;;; 186B;MONGOLIAN LETTER SIBE FA;Lo;0;L;;;;;N;;;;; 186C;MONGOLIAN LETTER SIBE GAA;Lo;0;L;;;;;N;;;;; 186D;MONGOLIAN LETTER SIBE HAA;Lo;0;L;;;;;N;;;;; 186E;MONGOLIAN LETTER SIBE TSA;Lo;0;L;;;;;N;;;;; 186F;MONGOLIAN LETTER SIBE ZA;Lo;0;L;;;;;N;;;;; 1870;MONGOLIAN LETTER SIBE RAA;Lo;0;L;;;;;N;;;;; 1871;MONGOLIAN LETTER SIBE CHA;Lo;0;L;;;;;N;;;;; 1872;MONGOLIAN LETTER SIBE ZHA;Lo;0;L;;;;;N;;;;; 1873;MONGOLIAN LETTER MANCHU I;Lo;0;L;;;;;N;;;;; 1874;MONGOLIAN LETTER MANCHU KA;Lo;0;L;;;;;N;;;;; 1875;MONGOLIAN LETTER MANCHU RA;Lo;0;L;;;;;N;;;;; 1876;MONGOLIAN LETTER MANCHU FA;Lo;0;L;;;;;N;;;;; 1877;MONGOLIAN LETTER MANCHU ZHA;Lo;0;L;;;;;N;;;;; 1880;MONGOLIAN LETTER ALI GALI ANUSVARA ONE;Lo;0;L;;;;;N;;;;; 1881;MONGOLIAN LETTER ALI GALI VISARGA ONE;Lo;0;L;;;;;N;;;;; 1882;MONGOLIAN LETTER ALI GALI DAMARU;Lo;0;L;;;;;N;;;;; 1883;MONGOLIAN LETTER ALI GALI UBADAMA;Lo;0;L;;;;;N;;;;; 1884;MONGOLIAN LETTER ALI GALI INVERTED UBADAMA;Lo;0;L;;;;;N;;;;; 1885;MONGOLIAN LETTER ALI GALI BALUDA;Lo;0;L;;;;;N;;;;; 1886;MONGOLIAN LETTER ALI GALI THREE BALUDA;Lo;0;L;;;;;N;;;;; 1887;MONGOLIAN LETTER ALI GALI A;Lo;0;L;;;;;N;;;;; 1888;MONGOLIAN LETTER ALI GALI I;Lo;0;L;;;;;N;;;;; 1889;MONGOLIAN LETTER ALI GALI KA;Lo;0;L;;;;;N;;;;; 188A;MONGOLIAN LETTER ALI GALI NGA;Lo;0;L;;;;;N;;;;; 188B;MONGOLIAN LETTER ALI GALI CA;Lo;0;L;;;;;N;;;;; 188C;MONGOLIAN LETTER ALI GALI TTA;Lo;0;L;;;;;N;;;;; 188D;MONGOLIAN LETTER ALI GALI TTHA;Lo;0;L;;;;;N;;;;; 188E;MONGOLIAN LETTER ALI GALI DDA;Lo;0;L;;;;;N;;;;; 188F;MONGOLIAN LETTER ALI GALI NNA;Lo;0;L;;;;;N;;;;; 1890;MONGOLIAN LETTER ALI GALI TA;Lo;0;L;;;;;N;;;;; 1891;MONGOLIAN LETTER ALI GALI DA;Lo;0;L;;;;;N;;;;; 1892;MONGOLIAN LETTER ALI GALI PA;Lo;0;L;;;;;N;;;;; 1893;MONGOLIAN LETTER ALI GALI PHA;Lo;0;L;;;;;N;;;;; 1894;MONGOLIAN LETTER ALI GALI SSA;Lo;0;L;;;;;N;;;;; 1895;MONGOLIAN LETTER ALI GALI ZHA;Lo;0;L;;;;;N;;;;; 1896;MONGOLIAN LETTER ALI GALI ZA;Lo;0;L;;;;;N;;;;; 1897;MONGOLIAN LETTER ALI GALI AH;Lo;0;L;;;;;N;;;;; 1898;MONGOLIAN LETTER TODO ALI GALI TA;Lo;0;L;;;;;N;;;;; 1899;MONGOLIAN LETTER TODO ALI GALI ZHA;Lo;0;L;;;;;N;;;;; 189A;MONGOLIAN LETTER MANCHU ALI GALI GHA;Lo;0;L;;;;;N;;;;; 189B;MONGOLIAN LETTER MANCHU ALI GALI NGA;Lo;0;L;;;;;N;;;;; 189C;MONGOLIAN LETTER MANCHU ALI GALI CA;Lo;0;L;;;;;N;;;;; 189D;MONGOLIAN LETTER MANCHU ALI GALI JHA;Lo;0;L;;;;;N;;;;; 189E;MONGOLIAN LETTER MANCHU ALI GALI TTA;Lo;0;L;;;;;N;;;;; 189F;MONGOLIAN LETTER MANCHU ALI GALI DDHA;Lo;0;L;;;;;N;;;;; 18A0;MONGOLIAN LETTER MANCHU ALI GALI TA;Lo;0;L;;;;;N;;;;; 18A1;MONGOLIAN LETTER MANCHU ALI GALI DHA;Lo;0;L;;;;;N;;;;; 18A2;MONGOLIAN LETTER MANCHU ALI GALI SSA;Lo;0;L;;;;;N;;;;; 18A3;MONGOLIAN LETTER MANCHU ALI GALI CYA;Lo;0;L;;;;;N;;;;; 18A4;MONGOLIAN LETTER MANCHU ALI GALI ZHA;Lo;0;L;;;;;N;;;;; 18A5;MONGOLIAN LETTER MANCHU ALI GALI ZA;Lo;0;L;;;;;N;;;;; 18A6;MONGOLIAN LETTER ALI GALI HALF U;Lo;0;L;;;;;N;;;;; 18A7;MONGOLIAN LETTER ALI GALI HALF YA;Lo;0;L;;;;;N;;;;; 18A8;MONGOLIAN LETTER MANCHU ALI GALI BHA;Lo;0;L;;;;;N;;;;; 18A9;MONGOLIAN LETTER ALI GALI DAGALGA;Mn;228;NSM;;;;;N;;;;; 1E00;LATIN CAPITAL LETTER A WITH RING BELOW;Lu;0;L;0041 0325;;;;N;;;;1E01; 1E01;LATIN SMALL LETTER A WITH RING BELOW;Ll;0;L;0061 0325;;;;N;;;1E00;;1E00 1E02;LATIN CAPITAL LETTER B WITH DOT ABOVE;Lu;0;L;0042 0307;;;;N;;;;1E03; 1E03;LATIN SMALL LETTER B WITH DOT ABOVE;Ll;0;L;0062 0307;;;;N;;;1E02;;1E02 1E04;LATIN CAPITAL LETTER B WITH DOT BELOW;Lu;0;L;0042 0323;;;;N;;;;1E05; 1E05;LATIN SMALL LETTER B WITH DOT BELOW;Ll;0;L;0062 0323;;;;N;;;1E04;;1E04 1E06;LATIN CAPITAL LETTER B WITH LINE BELOW;Lu;0;L;0042 0331;;;;N;;;;1E07; 1E07;LATIN SMALL LETTER B WITH LINE BELOW;Ll;0;L;0062 0331;;;;N;;;1E06;;1E06 1E08;LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE;Lu;0;L;00C7 0301;;;;N;;;;1E09; 1E09;LATIN SMALL LETTER C WITH CEDILLA AND ACUTE;Ll;0;L;00E7 0301;;;;N;;;1E08;;1E08 1E0A;LATIN CAPITAL LETTER D WITH DOT ABOVE;Lu;0;L;0044 0307;;;;N;;;;1E0B; 1E0B;LATIN SMALL LETTER D WITH DOT ABOVE;Ll;0;L;0064 0307;;;;N;;;1E0A;;1E0A 1E0C;LATIN CAPITAL LETTER D WITH DOT BELOW;Lu;0;L;0044 0323;;;;N;;;;1E0D; 1E0D;LATIN SMALL LETTER D WITH DOT BELOW;Ll;0;L;0064 0323;;;;N;;;1E0C;;1E0C 1E0E;LATIN CAPITAL LETTER D WITH LINE BELOW;Lu;0;L;0044 0331;;;;N;;;;1E0F; 1E0F;LATIN SMALL LETTER D WITH LINE BELOW;Ll;0;L;0064 0331;;;;N;;;1E0E;;1E0E 1E10;LATIN CAPITAL LETTER D WITH CEDILLA;Lu;0;L;0044 0327;;;;N;;;;1E11; 1E11;LATIN SMALL LETTER D WITH CEDILLA;Ll;0;L;0064 0327;;;;N;;;1E10;;1E10 1E12;LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW;Lu;0;L;0044 032D;;;;N;;;;1E13; 1E13;LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW;Ll;0;L;0064 032D;;;;N;;;1E12;;1E12 1E14;LATIN CAPITAL LETTER E WITH MACRON AND GRAVE;Lu;0;L;0112 0300;;;;N;;;;1E15; 1E15;LATIN SMALL LETTER E WITH MACRON AND GRAVE;Ll;0;L;0113 0300;;;;N;;;1E14;;1E14 1E16;LATIN CAPITAL LETTER E WITH MACRON AND ACUTE;Lu;0;L;0112 0301;;;;N;;;;1E17; 1E17;LATIN SMALL LETTER E WITH MACRON AND ACUTE;Ll;0;L;0113 0301;;;;N;;;1E16;;1E16 1E18;LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW;Lu;0;L;0045 032D;;;;N;;;;1E19; 1E19;LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW;Ll;0;L;0065 032D;;;;N;;;1E18;;1E18 1E1A;LATIN CAPITAL LETTER E WITH TILDE BELOW;Lu;0;L;0045 0330;;;;N;;;;1E1B; 1E1B;LATIN SMALL LETTER E WITH TILDE BELOW;Ll;0;L;0065 0330;;;;N;;;1E1A;;1E1A 1E1C;LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE;Lu;0;L;0228 0306;;;;N;;;;1E1D; 1E1D;LATIN SMALL LETTER E WITH CEDILLA AND BREVE;Ll;0;L;0229 0306;;;;N;;;1E1C;;1E1C 1E1E;LATIN CAPITAL LETTER F WITH DOT ABOVE;Lu;0;L;0046 0307;;;;N;;;;1E1F; 1E1F;LATIN SMALL LETTER F WITH DOT ABOVE;Ll;0;L;0066 0307;;;;N;;;1E1E;;1E1E 1E20;LATIN CAPITAL LETTER G WITH MACRON;Lu;0;L;0047 0304;;;;N;;;;1E21; 1E21;LATIN SMALL LETTER G WITH MACRON;Ll;0;L;0067 0304;;;;N;;;1E20;;1E20 1E22;LATIN CAPITAL LETTER H WITH DOT ABOVE;Lu;0;L;0048 0307;;;;N;;;;1E23; 1E23;LATIN SMALL LETTER H WITH DOT ABOVE;Ll;0;L;0068 0307;;;;N;;;1E22;;1E22 1E24;LATIN CAPITAL LETTER H WITH DOT BELOW;Lu;0;L;0048 0323;;;;N;;;;1E25; 1E25;LATIN SMALL LETTER H WITH DOT BELOW;Ll;0;L;0068 0323;;;;N;;;1E24;;1E24 1E26;LATIN CAPITAL LETTER H WITH DIAERESIS;Lu;0;L;0048 0308;;;;N;;;;1E27; 1E27;LATIN SMALL LETTER H WITH DIAERESIS;Ll;0;L;0068 0308;;;;N;;;1E26;;1E26 1E28;LATIN CAPITAL LETTER H WITH CEDILLA;Lu;0;L;0048 0327;;;;N;;;;1E29; 1E29;LATIN SMALL LETTER H WITH CEDILLA;Ll;0;L;0068 0327;;;;N;;;1E28;;1E28 1E2A;LATIN CAPITAL LETTER H WITH BREVE BELOW;Lu;0;L;0048 032E;;;;N;;;;1E2B; 1E2B;LATIN SMALL LETTER H WITH BREVE BELOW;Ll;0;L;0068 032E;;;;N;;;1E2A;;1E2A 1E2C;LATIN CAPITAL LETTER I WITH TILDE BELOW;Lu;0;L;0049 0330;;;;N;;;;1E2D; 1E2D;LATIN SMALL LETTER I WITH TILDE BELOW;Ll;0;L;0069 0330;;;;N;;;1E2C;;1E2C 1E2E;LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE;Lu;0;L;00CF 0301;;;;N;;;;1E2F; 1E2F;LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE;Ll;0;L;00EF 0301;;;;N;;;1E2E;;1E2E 1E30;LATIN CAPITAL LETTER K WITH ACUTE;Lu;0;L;004B 0301;;;;N;;;;1E31; 1E31;LATIN SMALL LETTER K WITH ACUTE;Ll;0;L;006B 0301;;;;N;;;1E30;;1E30 1E32;LATIN CAPITAL LETTER K WITH DOT BELOW;Lu;0;L;004B 0323;;;;N;;;;1E33; 1E33;LATIN SMALL LETTER K WITH DOT BELOW;Ll;0;L;006B 0323;;;;N;;;1E32;;1E32 1E34;LATIN CAPITAL LETTER K WITH LINE BELOW;Lu;0;L;004B 0331;;;;N;;;;1E35; 1E35;LATIN SMALL LETTER K WITH LINE BELOW;Ll;0;L;006B 0331;;;;N;;;1E34;;1E34 1E36;LATIN CAPITAL LETTER L WITH DOT BELOW;Lu;0;L;004C 0323;;;;N;;;;1E37; 1E37;LATIN SMALL LETTER L WITH DOT BELOW;Ll;0;L;006C 0323;;;;N;;;1E36;;1E36 1E38;LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON;Lu;0;L;1E36 0304;;;;N;;;;1E39; 1E39;LATIN SMALL LETTER L WITH DOT BELOW AND MACRON;Ll;0;L;1E37 0304;;;;N;;;1E38;;1E38 1E3A;LATIN CAPITAL LETTER L WITH LINE BELOW;Lu;0;L;004C 0331;;;;N;;;;1E3B; 1E3B;LATIN SMALL LETTER L WITH LINE BELOW;Ll;0;L;006C 0331;;;;N;;;1E3A;;1E3A 1E3C;LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW;Lu;0;L;004C 032D;;;;N;;;;1E3D; 1E3D;LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW;Ll;0;L;006C 032D;;;;N;;;1E3C;;1E3C 1E3E;LATIN CAPITAL LETTER M WITH ACUTE;Lu;0;L;004D 0301;;;;N;;;;1E3F; 1E3F;LATIN SMALL LETTER M WITH ACUTE;Ll;0;L;006D 0301;;;;N;;;1E3E;;1E3E 1E40;LATIN CAPITAL LETTER M WITH DOT ABOVE;Lu;0;L;004D 0307;;;;N;;;;1E41; 1E41;LATIN SMALL LETTER M WITH DOT ABOVE;Ll;0;L;006D 0307;;;;N;;;1E40;;1E40 1E42;LATIN CAPITAL LETTER M WITH DOT BELOW;Lu;0;L;004D 0323;;;;N;;;;1E43; 1E43;LATIN SMALL LETTER M WITH DOT BELOW;Ll;0;L;006D 0323;;;;N;;;1E42;;1E42 1E44;LATIN CAPITAL LETTER N WITH DOT ABOVE;Lu;0;L;004E 0307;;;;N;;;;1E45; 1E45;LATIN SMALL LETTER N WITH DOT ABOVE;Ll;0;L;006E 0307;;;;N;;;1E44;;1E44 1E46;LATIN CAPITAL LETTER N WITH DOT BELOW;Lu;0;L;004E 0323;;;;N;;;;1E47; 1E47;LATIN SMALL LETTER N WITH DOT BELOW;Ll;0;L;006E 0323;;;;N;;;1E46;;1E46 1E48;LATIN CAPITAL LETTER N WITH LINE BELOW;Lu;0;L;004E 0331;;;;N;;;;1E49; 1E49;LATIN SMALL LETTER N WITH LINE BELOW;Ll;0;L;006E 0331;;;;N;;;1E48;;1E48 1E4A;LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW;Lu;0;L;004E 032D;;;;N;;;;1E4B; 1E4B;LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW;Ll;0;L;006E 032D;;;;N;;;1E4A;;1E4A 1E4C;LATIN CAPITAL LETTER O WITH TILDE AND ACUTE;Lu;0;L;00D5 0301;;;;N;;;;1E4D; 1E4D;LATIN SMALL LETTER O WITH TILDE AND ACUTE;Ll;0;L;00F5 0301;;;;N;;;1E4C;;1E4C 1E4E;LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS;Lu;0;L;00D5 0308;;;;N;;;;1E4F; 1E4F;LATIN SMALL LETTER O WITH TILDE AND DIAERESIS;Ll;0;L;00F5 0308;;;;N;;;1E4E;;1E4E 1E50;LATIN CAPITAL LETTER O WITH MACRON AND GRAVE;Lu;0;L;014C 0300;;;;N;;;;1E51; 1E51;LATIN SMALL LETTER O WITH MACRON AND GRAVE;Ll;0;L;014D 0300;;;;N;;;1E50;;1E50 1E52;LATIN CAPITAL LETTER O WITH MACRON AND ACUTE;Lu;0;L;014C 0301;;;;N;;;;1E53; 1E53;LATIN SMALL LETTER O WITH MACRON AND ACUTE;Ll;0;L;014D 0301;;;;N;;;1E52;;1E52 1E54;LATIN CAPITAL LETTER P WITH ACUTE;Lu;0;L;0050 0301;;;;N;;;;1E55; 1E55;LATIN SMALL LETTER P WITH ACUTE;Ll;0;L;0070 0301;;;;N;;;1E54;;1E54 1E56;LATIN CAPITAL LETTER P WITH DOT ABOVE;Lu;0;L;0050 0307;;;;N;;;;1E57; 1E57;LATIN SMALL LETTER P WITH DOT ABOVE;Ll;0;L;0070 0307;;;;N;;;1E56;;1E56 1E58;LATIN CAPITAL LETTER R WITH DOT ABOVE;Lu;0;L;0052 0307;;;;N;;;;1E59; 1E59;LATIN SMALL LETTER R WITH DOT ABOVE;Ll;0;L;0072 0307;;;;N;;;1E58;;1E58 1E5A;LATIN CAPITAL LETTER R WITH DOT BELOW;Lu;0;L;0052 0323;;;;N;;;;1E5B; 1E5B;LATIN SMALL LETTER R WITH DOT BELOW;Ll;0;L;0072 0323;;;;N;;;1E5A;;1E5A 1E5C;LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON;Lu;0;L;1E5A 0304;;;;N;;;;1E5D; 1E5D;LATIN SMALL LETTER R WITH DOT BELOW AND MACRON;Ll;0;L;1E5B 0304;;;;N;;;1E5C;;1E5C 1E5E;LATIN CAPITAL LETTER R WITH LINE BELOW;Lu;0;L;0052 0331;;;;N;;;;1E5F; 1E5F;LATIN SMALL LETTER R WITH LINE BELOW;Ll;0;L;0072 0331;;;;N;;;1E5E;;1E5E 1E60;LATIN CAPITAL LETTER S WITH DOT ABOVE;Lu;0;L;0053 0307;;;;N;;;;1E61; 1E61;LATIN SMALL LETTER S WITH DOT ABOVE;Ll;0;L;0073 0307;;;;N;;;1E60;;1E60 1E62;LATIN CAPITAL LETTER S WITH DOT BELOW;Lu;0;L;0053 0323;;;;N;;;;1E63; 1E63;LATIN SMALL LETTER S WITH DOT BELOW;Ll;0;L;0073 0323;;;;N;;;1E62;;1E62 1E64;LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE;Lu;0;L;015A 0307;;;;N;;;;1E65; 1E65;LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE;Ll;0;L;015B 0307;;;;N;;;1E64;;1E64 1E66;LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE;Lu;0;L;0160 0307;;;;N;;;;1E67; 1E67;LATIN SMALL LETTER S WITH CARON AND DOT ABOVE;Ll;0;L;0161 0307;;;;N;;;1E66;;1E66 1E68;LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE;Lu;0;L;1E62 0307;;;;N;;;;1E69; 1E69;LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE;Ll;0;L;1E63 0307;;;;N;;;1E68;;1E68 1E6A;LATIN CAPITAL LETTER T WITH DOT ABOVE;Lu;0;L;0054 0307;;;;N;;;;1E6B; 1E6B;LATIN SMALL LETTER T WITH DOT ABOVE;Ll;0;L;0074 0307;;;;N;;;1E6A;;1E6A 1E6C;LATIN CAPITAL LETTER T WITH DOT BELOW;Lu;0;L;0054 0323;;;;N;;;;1E6D; 1E6D;LATIN SMALL LETTER T WITH DOT BELOW;Ll;0;L;0074 0323;;;;N;;;1E6C;;1E6C 1E6E;LATIN CAPITAL LETTER T WITH LINE BELOW;Lu;0;L;0054 0331;;;;N;;;;1E6F; 1E6F;LATIN SMALL LETTER T WITH LINE BELOW;Ll;0;L;0074 0331;;;;N;;;1E6E;;1E6E 1E70;LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW;Lu;0;L;0054 032D;;;;N;;;;1E71; 1E71;LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW;Ll;0;L;0074 032D;;;;N;;;1E70;;1E70 1E72;LATIN CAPITAL LETTER U WITH DIAERESIS BELOW;Lu;0;L;0055 0324;;;;N;;;;1E73; 1E73;LATIN SMALL LETTER U WITH DIAERESIS BELOW;Ll;0;L;0075 0324;;;;N;;;1E72;;1E72 1E74;LATIN CAPITAL LETTER U WITH TILDE BELOW;Lu;0;L;0055 0330;;;;N;;;;1E75; 1E75;LATIN SMALL LETTER U WITH TILDE BELOW;Ll;0;L;0075 0330;;;;N;;;1E74;;1E74 1E76;LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW;Lu;0;L;0055 032D;;;;N;;;;1E77; 1E77;LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW;Ll;0;L;0075 032D;;;;N;;;1E76;;1E76 1E78;LATIN CAPITAL LETTER U WITH TILDE AND ACUTE;Lu;0;L;0168 0301;;;;N;;;;1E79; 1E79;LATIN SMALL LETTER U WITH TILDE AND ACUTE;Ll;0;L;0169 0301;;;;N;;;1E78;;1E78 1E7A;LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS;Lu;0;L;016A 0308;;;;N;;;;1E7B; 1E7B;LATIN SMALL LETTER U WITH MACRON AND DIAERESIS;Ll;0;L;016B 0308;;;;N;;;1E7A;;1E7A 1E7C;LATIN CAPITAL LETTER V WITH TILDE;Lu;0;L;0056 0303;;;;N;;;;1E7D; 1E7D;LATIN SMALL LETTER V WITH TILDE;Ll;0;L;0076 0303;;;;N;;;1E7C;;1E7C 1E7E;LATIN CAPITAL LETTER V WITH DOT BELOW;Lu;0;L;0056 0323;;;;N;;;;1E7F; 1E7F;LATIN SMALL LETTER V WITH DOT BELOW;Ll;0;L;0076 0323;;;;N;;;1E7E;;1E7E 1E80;LATIN CAPITAL LETTER W WITH GRAVE;Lu;0;L;0057 0300;;;;N;;;;1E81; 1E81;LATIN SMALL LETTER W WITH GRAVE;Ll;0;L;0077 0300;;;;N;;;1E80;;1E80 1E82;LATIN CAPITAL LETTER W WITH ACUTE;Lu;0;L;0057 0301;;;;N;;;;1E83; 1E83;LATIN SMALL LETTER W WITH ACUTE;Ll;0;L;0077 0301;;;;N;;;1E82;;1E82 1E84;LATIN CAPITAL LETTER W WITH DIAERESIS;Lu;0;L;0057 0308;;;;N;;;;1E85; 1E85;LATIN SMALL LETTER W WITH DIAERESIS;Ll;0;L;0077 0308;;;;N;;;1E84;;1E84 1E86;LATIN CAPITAL LETTER W WITH DOT ABOVE;Lu;0;L;0057 0307;;;;N;;;;1E87; 1E87;LATIN SMALL LETTER W WITH DOT ABOVE;Ll;0;L;0077 0307;;;;N;;;1E86;;1E86 1E88;LATIN CAPITAL LETTER W WITH DOT BELOW;Lu;0;L;0057 0323;;;;N;;;;1E89; 1E89;LATIN SMALL LETTER W WITH DOT BELOW;Ll;0;L;0077 0323;;;;N;;;1E88;;1E88 1E8A;LATIN CAPITAL LETTER X WITH DOT ABOVE;Lu;0;L;0058 0307;;;;N;;;;1E8B; 1E8B;LATIN SMALL LETTER X WITH DOT ABOVE;Ll;0;L;0078 0307;;;;N;;;1E8A;;1E8A 1E8C;LATIN CAPITAL LETTER X WITH DIAERESIS;Lu;0;L;0058 0308;;;;N;;;;1E8D; 1E8D;LATIN SMALL LETTER X WITH DIAERESIS;Ll;0;L;0078 0308;;;;N;;;1E8C;;1E8C 1E8E;LATIN CAPITAL LETTER Y WITH DOT ABOVE;Lu;0;L;0059 0307;;;;N;;;;1E8F; 1E8F;LATIN SMALL LETTER Y WITH DOT ABOVE;Ll;0;L;0079 0307;;;;N;;;1E8E;;1E8E 1E90;LATIN CAPITAL LETTER Z WITH CIRCUMFLEX;Lu;0;L;005A 0302;;;;N;;;;1E91; 1E91;LATIN SMALL LETTER Z WITH CIRCUMFLEX;Ll;0;L;007A 0302;;;;N;;;1E90;;1E90 1E92;LATIN CAPITAL LETTER Z WITH DOT BELOW;Lu;0;L;005A 0323;;;;N;;;;1E93; 1E93;LATIN SMALL LETTER Z WITH DOT BELOW;Ll;0;L;007A 0323;;;;N;;;1E92;;1E92 1E94;LATIN CAPITAL LETTER Z WITH LINE BELOW;Lu;0;L;005A 0331;;;;N;;;;1E95; 1E95;LATIN SMALL LETTER Z WITH LINE BELOW;Ll;0;L;007A 0331;;;;N;;;1E94;;1E94 1E96;LATIN SMALL LETTER H WITH LINE BELOW;Ll;0;L;0068 0331;;;;N;;;;; 1E97;LATIN SMALL LETTER T WITH DIAERESIS;Ll;0;L;0074 0308;;;;N;;;;; 1E98;LATIN SMALL LETTER W WITH RING ABOVE;Ll;0;L;0077 030A;;;;N;;;;; 1E99;LATIN SMALL LETTER Y WITH RING ABOVE;Ll;0;L;0079 030A;;;;N;;;;; 1E9A;LATIN SMALL LETTER A WITH RIGHT HALF RING;Ll;0;L; 0061 02BE;;;;N;;;;; 1E9B;LATIN SMALL LETTER LONG S WITH DOT ABOVE;Ll;0;L;017F 0307;;;;N;;;1E60;;1E60 1EA0;LATIN CAPITAL LETTER A WITH DOT BELOW;Lu;0;L;0041 0323;;;;N;;;;1EA1; 1EA1;LATIN SMALL LETTER A WITH DOT BELOW;Ll;0;L;0061 0323;;;;N;;;1EA0;;1EA0 1EA2;LATIN CAPITAL LETTER A WITH HOOK ABOVE;Lu;0;L;0041 0309;;;;N;;;;1EA3; 1EA3;LATIN SMALL LETTER A WITH HOOK ABOVE;Ll;0;L;0061 0309;;;;N;;;1EA2;;1EA2 1EA4;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00C2 0301;;;;N;;;;1EA5; 1EA5;LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00E2 0301;;;;N;;;1EA4;;1EA4 1EA6;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00C2 0300;;;;N;;;;1EA7; 1EA7;LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00E2 0300;;;;N;;;1EA6;;1EA6 1EA8;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00C2 0309;;;;N;;;;1EA9; 1EA9;LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00E2 0309;;;;N;;;1EA8;;1EA8 1EAA;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE;Lu;0;L;00C2 0303;;;;N;;;;1EAB; 1EAB;LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE;Ll;0;L;00E2 0303;;;;N;;;1EAA;;1EAA 1EAC;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EA0 0302;;;;N;;;;1EAD; 1EAD;LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EA1 0302;;;;N;;;1EAC;;1EAC 1EAE;LATIN CAPITAL LETTER A WITH BREVE AND ACUTE;Lu;0;L;0102 0301;;;;N;;;;1EAF; 1EAF;LATIN SMALL LETTER A WITH BREVE AND ACUTE;Ll;0;L;0103 0301;;;;N;;;1EAE;;1EAE 1EB0;LATIN CAPITAL LETTER A WITH BREVE AND GRAVE;Lu;0;L;0102 0300;;;;N;;;;1EB1; 1EB1;LATIN SMALL LETTER A WITH BREVE AND GRAVE;Ll;0;L;0103 0300;;;;N;;;1EB0;;1EB0 1EB2;LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE;Lu;0;L;0102 0309;;;;N;;;;1EB3; 1EB3;LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE;Ll;0;L;0103 0309;;;;N;;;1EB2;;1EB2 1EB4;LATIN CAPITAL LETTER A WITH BREVE AND TILDE;Lu;0;L;0102 0303;;;;N;;;;1EB5; 1EB5;LATIN SMALL LETTER A WITH BREVE AND TILDE;Ll;0;L;0103 0303;;;;N;;;1EB4;;1EB4 1EB6;LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW;Lu;0;L;1EA0 0306;;;;N;;;;1EB7; 1EB7;LATIN SMALL LETTER A WITH BREVE AND DOT BELOW;Ll;0;L;1EA1 0306;;;;N;;;1EB6;;1EB6 1EB8;LATIN CAPITAL LETTER E WITH DOT BELOW;Lu;0;L;0045 0323;;;;N;;;;1EB9; 1EB9;LATIN SMALL LETTER E WITH DOT BELOW;Ll;0;L;0065 0323;;;;N;;;1EB8;;1EB8 1EBA;LATIN CAPITAL LETTER E WITH HOOK ABOVE;Lu;0;L;0045 0309;;;;N;;;;1EBB; 1EBB;LATIN SMALL LETTER E WITH HOOK ABOVE;Ll;0;L;0065 0309;;;;N;;;1EBA;;1EBA 1EBC;LATIN CAPITAL LETTER E WITH TILDE;Lu;0;L;0045 0303;;;;N;;;;1EBD; 1EBD;LATIN SMALL LETTER E WITH TILDE;Ll;0;L;0065 0303;;;;N;;;1EBC;;1EBC 1EBE;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00CA 0301;;;;N;;;;1EBF; 1EBF;LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00EA 0301;;;;N;;;1EBE;;1EBE 1EC0;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00CA 0300;;;;N;;;;1EC1; 1EC1;LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00EA 0300;;;;N;;;1EC0;;1EC0 1EC2;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00CA 0309;;;;N;;;;1EC3; 1EC3;LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00EA 0309;;;;N;;;1EC2;;1EC2 1EC4;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE;Lu;0;L;00CA 0303;;;;N;;;;1EC5; 1EC5;LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE;Ll;0;L;00EA 0303;;;;N;;;1EC4;;1EC4 1EC6;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EB8 0302;;;;N;;;;1EC7; 1EC7;LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EB9 0302;;;;N;;;1EC6;;1EC6 1EC8;LATIN CAPITAL LETTER I WITH HOOK ABOVE;Lu;0;L;0049 0309;;;;N;;;;1EC9; 1EC9;LATIN SMALL LETTER I WITH HOOK ABOVE;Ll;0;L;0069 0309;;;;N;;;1EC8;;1EC8 1ECA;LATIN CAPITAL LETTER I WITH DOT BELOW;Lu;0;L;0049 0323;;;;N;;;;1ECB; 1ECB;LATIN SMALL LETTER I WITH DOT BELOW;Ll;0;L;0069 0323;;;;N;;;1ECA;;1ECA 1ECC;LATIN CAPITAL LETTER O WITH DOT BELOW;Lu;0;L;004F 0323;;;;N;;;;1ECD; 1ECD;LATIN SMALL LETTER O WITH DOT BELOW;Ll;0;L;006F 0323;;;;N;;;1ECC;;1ECC 1ECE;LATIN CAPITAL LETTER O WITH HOOK ABOVE;Lu;0;L;004F 0309;;;;N;;;;1ECF; 1ECF;LATIN SMALL LETTER O WITH HOOK ABOVE;Ll;0;L;006F 0309;;;;N;;;1ECE;;1ECE 1ED0;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00D4 0301;;;;N;;;;1ED1; 1ED1;LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00F4 0301;;;;N;;;1ED0;;1ED0 1ED2;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00D4 0300;;;;N;;;;1ED3; 1ED3;LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00F4 0300;;;;N;;;1ED2;;1ED2 1ED4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00D4 0309;;;;N;;;;1ED5; 1ED5;LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00F4 0309;;;;N;;;1ED4;;1ED4 1ED6;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE;Lu;0;L;00D4 0303;;;;N;;;;1ED7; 1ED7;LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE;Ll;0;L;00F4 0303;;;;N;;;1ED6;;1ED6 1ED8;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1ECC 0302;;;;N;;;;1ED9; 1ED9;LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1ECD 0302;;;;N;;;1ED8;;1ED8 1EDA;LATIN CAPITAL LETTER O WITH HORN AND ACUTE;Lu;0;L;01A0 0301;;;;N;;;;1EDB; 1EDB;LATIN SMALL LETTER O WITH HORN AND ACUTE;Ll;0;L;01A1 0301;;;;N;;;1EDA;;1EDA 1EDC;LATIN CAPITAL LETTER O WITH HORN AND GRAVE;Lu;0;L;01A0 0300;;;;N;;;;1EDD; 1EDD;LATIN SMALL LETTER O WITH HORN AND GRAVE;Ll;0;L;01A1 0300;;;;N;;;1EDC;;1EDC 1EDE;LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE;Lu;0;L;01A0 0309;;;;N;;;;1EDF; 1EDF;LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE;Ll;0;L;01A1 0309;;;;N;;;1EDE;;1EDE 1EE0;LATIN CAPITAL LETTER O WITH HORN AND TILDE;Lu;0;L;01A0 0303;;;;N;;;;1EE1; 1EE1;LATIN SMALL LETTER O WITH HORN AND TILDE;Ll;0;L;01A1 0303;;;;N;;;1EE0;;1EE0 1EE2;LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW;Lu;0;L;01A0 0323;;;;N;;;;1EE3; 1EE3;LATIN SMALL LETTER O WITH HORN AND DOT BELOW;Ll;0;L;01A1 0323;;;;N;;;1EE2;;1EE2 1EE4;LATIN CAPITAL LETTER U WITH DOT BELOW;Lu;0;L;0055 0323;;;;N;;;;1EE5; 1EE5;LATIN SMALL LETTER U WITH DOT BELOW;Ll;0;L;0075 0323;;;;N;;;1EE4;;1EE4 1EE6;LATIN CAPITAL LETTER U WITH HOOK ABOVE;Lu;0;L;0055 0309;;;;N;;;;1EE7; 1EE7;LATIN SMALL LETTER U WITH HOOK ABOVE;Ll;0;L;0075 0309;;;;N;;;1EE6;;1EE6 1EE8;LATIN CAPITAL LETTER U WITH HORN AND ACUTE;Lu;0;L;01AF 0301;;;;N;;;;1EE9; 1EE9;LATIN SMALL LETTER U WITH HORN AND ACUTE;Ll;0;L;01B0 0301;;;;N;;;1EE8;;1EE8 1EEA;LATIN CAPITAL LETTER U WITH HORN AND GRAVE;Lu;0;L;01AF 0300;;;;N;;;;1EEB; 1EEB;LATIN SMALL LETTER U WITH HORN AND GRAVE;Ll;0;L;01B0 0300;;;;N;;;1EEA;;1EEA 1EEC;LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE;Lu;0;L;01AF 0309;;;;N;;;;1EED; 1EED;LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE;Ll;0;L;01B0 0309;;;;N;;;1EEC;;1EEC 1EEE;LATIN CAPITAL LETTER U WITH HORN AND TILDE;Lu;0;L;01AF 0303;;;;N;;;;1EEF; 1EEF;LATIN SMALL LETTER U WITH HORN AND TILDE;Ll;0;L;01B0 0303;;;;N;;;1EEE;;1EEE 1EF0;LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW;Lu;0;L;01AF 0323;;;;N;;;;1EF1; 1EF1;LATIN SMALL LETTER U WITH HORN AND DOT BELOW;Ll;0;L;01B0 0323;;;;N;;;1EF0;;1EF0 1EF2;LATIN CAPITAL LETTER Y WITH GRAVE;Lu;0;L;0059 0300;;;;N;;;;1EF3; 1EF3;LATIN SMALL LETTER Y WITH GRAVE;Ll;0;L;0079 0300;;;;N;;;1EF2;;1EF2 1EF4;LATIN CAPITAL LETTER Y WITH DOT BELOW;Lu;0;L;0059 0323;;;;N;;;;1EF5; 1EF5;LATIN SMALL LETTER Y WITH DOT BELOW;Ll;0;L;0079 0323;;;;N;;;1EF4;;1EF4 1EF6;LATIN CAPITAL LETTER Y WITH HOOK ABOVE;Lu;0;L;0059 0309;;;;N;;;;1EF7; 1EF7;LATIN SMALL LETTER Y WITH HOOK ABOVE;Ll;0;L;0079 0309;;;;N;;;1EF6;;1EF6 1EF8;LATIN CAPITAL LETTER Y WITH TILDE;Lu;0;L;0059 0303;;;;N;;;;1EF9; 1EF9;LATIN SMALL LETTER Y WITH TILDE;Ll;0;L;0079 0303;;;;N;;;1EF8;;1EF8 1F00;GREEK SMALL LETTER ALPHA WITH PSILI;Ll;0;L;03B1 0313;;;;N;;;1F08;;1F08 1F01;GREEK SMALL LETTER ALPHA WITH DASIA;Ll;0;L;03B1 0314;;;;N;;;1F09;;1F09 1F02;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA;Ll;0;L;1F00 0300;;;;N;;;1F0A;;1F0A 1F03;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA;Ll;0;L;1F01 0300;;;;N;;;1F0B;;1F0B 1F04;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA;Ll;0;L;1F00 0301;;;;N;;;1F0C;;1F0C 1F05;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA;Ll;0;L;1F01 0301;;;;N;;;1F0D;;1F0D 1F06;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI;Ll;0;L;1F00 0342;;;;N;;;1F0E;;1F0E 1F07;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI;Ll;0;L;1F01 0342;;;;N;;;1F0F;;1F0F 1F08;GREEK CAPITAL LETTER ALPHA WITH PSILI;Lu;0;L;0391 0313;;;;N;;;;1F00; 1F09;GREEK CAPITAL LETTER ALPHA WITH DASIA;Lu;0;L;0391 0314;;;;N;;;;1F01; 1F0A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA;Lu;0;L;1F08 0300;;;;N;;;;1F02; 1F0B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA;Lu;0;L;1F09 0300;;;;N;;;;1F03; 1F0C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA;Lu;0;L;1F08 0301;;;;N;;;;1F04; 1F0D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA;Lu;0;L;1F09 0301;;;;N;;;;1F05; 1F0E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI;Lu;0;L;1F08 0342;;;;N;;;;1F06; 1F0F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI;Lu;0;L;1F09 0342;;;;N;;;;1F07; 1F10;GREEK SMALL LETTER EPSILON WITH PSILI;Ll;0;L;03B5 0313;;;;N;;;1F18;;1F18 1F11;GREEK SMALL LETTER EPSILON WITH DASIA;Ll;0;L;03B5 0314;;;;N;;;1F19;;1F19 1F12;GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA;Ll;0;L;1F10 0300;;;;N;;;1F1A;;1F1A 1F13;GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA;Ll;0;L;1F11 0300;;;;N;;;1F1B;;1F1B 1F14;GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA;Ll;0;L;1F10 0301;;;;N;;;1F1C;;1F1C 1F15;GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA;Ll;0;L;1F11 0301;;;;N;;;1F1D;;1F1D 1F18;GREEK CAPITAL LETTER EPSILON WITH PSILI;Lu;0;L;0395 0313;;;;N;;;;1F10; 1F19;GREEK CAPITAL LETTER EPSILON WITH DASIA;Lu;0;L;0395 0314;;;;N;;;;1F11; 1F1A;GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA;Lu;0;L;1F18 0300;;;;N;;;;1F12; 1F1B;GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA;Lu;0;L;1F19 0300;;;;N;;;;1F13; 1F1C;GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA;Lu;0;L;1F18 0301;;;;N;;;;1F14; 1F1D;GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA;Lu;0;L;1F19 0301;;;;N;;;;1F15; 1F20;GREEK SMALL LETTER ETA WITH PSILI;Ll;0;L;03B7 0313;;;;N;;;1F28;;1F28 1F21;GREEK SMALL LETTER ETA WITH DASIA;Ll;0;L;03B7 0314;;;;N;;;1F29;;1F29 1F22;GREEK SMALL LETTER ETA WITH PSILI AND VARIA;Ll;0;L;1F20 0300;;;;N;;;1F2A;;1F2A 1F23;GREEK SMALL LETTER ETA WITH DASIA AND VARIA;Ll;0;L;1F21 0300;;;;N;;;1F2B;;1F2B 1F24;GREEK SMALL LETTER ETA WITH PSILI AND OXIA;Ll;0;L;1F20 0301;;;;N;;;1F2C;;1F2C 1F25;GREEK SMALL LETTER ETA WITH DASIA AND OXIA;Ll;0;L;1F21 0301;;;;N;;;1F2D;;1F2D 1F26;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI;Ll;0;L;1F20 0342;;;;N;;;1F2E;;1F2E 1F27;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI;Ll;0;L;1F21 0342;;;;N;;;1F2F;;1F2F 1F28;GREEK CAPITAL LETTER ETA WITH PSILI;Lu;0;L;0397 0313;;;;N;;;;1F20; 1F29;GREEK CAPITAL LETTER ETA WITH DASIA;Lu;0;L;0397 0314;;;;N;;;;1F21; 1F2A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA;Lu;0;L;1F28 0300;;;;N;;;;1F22; 1F2B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA;Lu;0;L;1F29 0300;;;;N;;;;1F23; 1F2C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA;Lu;0;L;1F28 0301;;;;N;;;;1F24; 1F2D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA;Lu;0;L;1F29 0301;;;;N;;;;1F25; 1F2E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI;Lu;0;L;1F28 0342;;;;N;;;;1F26; 1F2F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI;Lu;0;L;1F29 0342;;;;N;;;;1F27; 1F30;GREEK SMALL LETTER IOTA WITH PSILI;Ll;0;L;03B9 0313;;;;N;;;1F38;;1F38 1F31;GREEK SMALL LETTER IOTA WITH DASIA;Ll;0;L;03B9 0314;;;;N;;;1F39;;1F39 1F32;GREEK SMALL LETTER IOTA WITH PSILI AND VARIA;Ll;0;L;1F30 0300;;;;N;;;1F3A;;1F3A 1F33;GREEK SMALL LETTER IOTA WITH DASIA AND VARIA;Ll;0;L;1F31 0300;;;;N;;;1F3B;;1F3B 1F34;GREEK SMALL LETTER IOTA WITH PSILI AND OXIA;Ll;0;L;1F30 0301;;;;N;;;1F3C;;1F3C 1F35;GREEK SMALL LETTER IOTA WITH DASIA AND OXIA;Ll;0;L;1F31 0301;;;;N;;;1F3D;;1F3D 1F36;GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI;Ll;0;L;1F30 0342;;;;N;;;1F3E;;1F3E 1F37;GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI;Ll;0;L;1F31 0342;;;;N;;;1F3F;;1F3F 1F38;GREEK CAPITAL LETTER IOTA WITH PSILI;Lu;0;L;0399 0313;;;;N;;;;1F30; 1F39;GREEK CAPITAL LETTER IOTA WITH DASIA;Lu;0;L;0399 0314;;;;N;;;;1F31; 1F3A;GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA;Lu;0;L;1F38 0300;;;;N;;;;1F32; 1F3B;GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA;Lu;0;L;1F39 0300;;;;N;;;;1F33; 1F3C;GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA;Lu;0;L;1F38 0301;;;;N;;;;1F34; 1F3D;GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA;Lu;0;L;1F39 0301;;;;N;;;;1F35; 1F3E;GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI;Lu;0;L;1F38 0342;;;;N;;;;1F36; 1F3F;GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI;Lu;0;L;1F39 0342;;;;N;;;;1F37; 1F40;GREEK SMALL LETTER OMICRON WITH PSILI;Ll;0;L;03BF 0313;;;;N;;;1F48;;1F48 1F41;GREEK SMALL LETTER OMICRON WITH DASIA;Ll;0;L;03BF 0314;;;;N;;;1F49;;1F49 1F42;GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA;Ll;0;L;1F40 0300;;;;N;;;1F4A;;1F4A 1F43;GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA;Ll;0;L;1F41 0300;;;;N;;;1F4B;;1F4B 1F44;GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA;Ll;0;L;1F40 0301;;;;N;;;1F4C;;1F4C 1F45;GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA;Ll;0;L;1F41 0301;;;;N;;;1F4D;;1F4D 1F48;GREEK CAPITAL LETTER OMICRON WITH PSILI;Lu;0;L;039F 0313;;;;N;;;;1F40; 1F49;GREEK CAPITAL LETTER OMICRON WITH DASIA;Lu;0;L;039F 0314;;;;N;;;;1F41; 1F4A;GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA;Lu;0;L;1F48 0300;;;;N;;;;1F42; 1F4B;GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA;Lu;0;L;1F49 0300;;;;N;;;;1F43; 1F4C;GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA;Lu;0;L;1F48 0301;;;;N;;;;1F44; 1F4D;GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA;Lu;0;L;1F49 0301;;;;N;;;;1F45; 1F50;GREEK SMALL LETTER UPSILON WITH PSILI;Ll;0;L;03C5 0313;;;;N;;;;; 1F51;GREEK SMALL LETTER UPSILON WITH DASIA;Ll;0;L;03C5 0314;;;;N;;;1F59;;1F59 1F52;GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA;Ll;0;L;1F50 0300;;;;N;;;;; 1F53;GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA;Ll;0;L;1F51 0300;;;;N;;;1F5B;;1F5B 1F54;GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA;Ll;0;L;1F50 0301;;;;N;;;;; 1F55;GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA;Ll;0;L;1F51 0301;;;;N;;;1F5D;;1F5D 1F56;GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI;Ll;0;L;1F50 0342;;;;N;;;;; 1F57;GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI;Ll;0;L;1F51 0342;;;;N;;;1F5F;;1F5F 1F59;GREEK CAPITAL LETTER UPSILON WITH DASIA;Lu;0;L;03A5 0314;;;;N;;;;1F51; 1F5B;GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA;Lu;0;L;1F59 0300;;;;N;;;;1F53; 1F5D;GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA;Lu;0;L;1F59 0301;;;;N;;;;1F55; 1F5F;GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI;Lu;0;L;1F59 0342;;;;N;;;;1F57; 1F60;GREEK SMALL LETTER OMEGA WITH PSILI;Ll;0;L;03C9 0313;;;;N;;;1F68;;1F68 1F61;GREEK SMALL LETTER OMEGA WITH DASIA;Ll;0;L;03C9 0314;;;;N;;;1F69;;1F69 1F62;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA;Ll;0;L;1F60 0300;;;;N;;;1F6A;;1F6A 1F63;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA;Ll;0;L;1F61 0300;;;;N;;;1F6B;;1F6B 1F64;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA;Ll;0;L;1F60 0301;;;;N;;;1F6C;;1F6C 1F65;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA;Ll;0;L;1F61 0301;;;;N;;;1F6D;;1F6D 1F66;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI;Ll;0;L;1F60 0342;;;;N;;;1F6E;;1F6E 1F67;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI;Ll;0;L;1F61 0342;;;;N;;;1F6F;;1F6F 1F68;GREEK CAPITAL LETTER OMEGA WITH PSILI;Lu;0;L;03A9 0313;;;;N;;;;1F60; 1F69;GREEK CAPITAL LETTER OMEGA WITH DASIA;Lu;0;L;03A9 0314;;;;N;;;;1F61; 1F6A;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA;Lu;0;L;1F68 0300;;;;N;;;;1F62; 1F6B;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA;Lu;0;L;1F69 0300;;;;N;;;;1F63; 1F6C;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA;Lu;0;L;1F68 0301;;;;N;;;;1F64; 1F6D;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA;Lu;0;L;1F69 0301;;;;N;;;;1F65; 1F6E;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI;Lu;0;L;1F68 0342;;;;N;;;;1F66; 1F6F;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI;Lu;0;L;1F69 0342;;;;N;;;;1F67; 1F70;GREEK SMALL LETTER ALPHA WITH VARIA;Ll;0;L;03B1 0300;;;;N;;;1FBA;;1FBA 1F71;GREEK SMALL LETTER ALPHA WITH OXIA;Ll;0;L;03AC;;;;N;;;1FBB;;1FBB 1F72;GREEK SMALL LETTER EPSILON WITH VARIA;Ll;0;L;03B5 0300;;;;N;;;1FC8;;1FC8 1F73;GREEK SMALL LETTER EPSILON WITH OXIA;Ll;0;L;03AD;;;;N;;;1FC9;;1FC9 1F74;GREEK SMALL LETTER ETA WITH VARIA;Ll;0;L;03B7 0300;;;;N;;;1FCA;;1FCA 1F75;GREEK SMALL LETTER ETA WITH OXIA;Ll;0;L;03AE;;;;N;;;1FCB;;1FCB 1F76;GREEK SMALL LETTER IOTA WITH VARIA;Ll;0;L;03B9 0300;;;;N;;;1FDA;;1FDA 1F77;GREEK SMALL LETTER IOTA WITH OXIA;Ll;0;L;03AF;;;;N;;;1FDB;;1FDB 1F78;GREEK SMALL LETTER OMICRON WITH VARIA;Ll;0;L;03BF 0300;;;;N;;;1FF8;;1FF8 1F79;GREEK SMALL LETTER OMICRON WITH OXIA;Ll;0;L;03CC;;;;N;;;1FF9;;1FF9 1F7A;GREEK SMALL LETTER UPSILON WITH VARIA;Ll;0;L;03C5 0300;;;;N;;;1FEA;;1FEA 1F7B;GREEK SMALL LETTER UPSILON WITH OXIA;Ll;0;L;03CD;;;;N;;;1FEB;;1FEB 1F7C;GREEK SMALL LETTER OMEGA WITH VARIA;Ll;0;L;03C9 0300;;;;N;;;1FFA;;1FFA 1F7D;GREEK SMALL LETTER OMEGA WITH OXIA;Ll;0;L;03CE;;;;N;;;1FFB;;1FFB 1F80;GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F00 0345;;;;N;;;1F88;;1F88 1F81;GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F01 0345;;;;N;;;1F89;;1F89 1F82;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F02 0345;;;;N;;;1F8A;;1F8A 1F83;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F03 0345;;;;N;;;1F8B;;1F8B 1F84;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F04 0345;;;;N;;;1F8C;;1F8C 1F85;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F05 0345;;;;N;;;1F8D;;1F8D 1F86;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F06 0345;;;;N;;;1F8E;;1F8E 1F87;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F07 0345;;;;N;;;1F8F;;1F8F 1F88;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F08 0345;;;;N;;;;1F80; 1F89;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F09 0345;;;;N;;;;1F81; 1F8A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0A 0345;;;;N;;;;1F82; 1F8B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0B 0345;;;;N;;;;1F83; 1F8C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0C 0345;;;;N;;;;1F84; 1F8D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0D 0345;;;;N;;;;1F85; 1F8E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0E 0345;;;;N;;;;1F86; 1F8F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0F 0345;;;;N;;;;1F87; 1F90;GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F20 0345;;;;N;;;1F98;;1F98 1F91;GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F21 0345;;;;N;;;1F99;;1F99 1F92;GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F22 0345;;;;N;;;1F9A;;1F9A 1F93;GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F23 0345;;;;N;;;1F9B;;1F9B 1F94;GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F24 0345;;;;N;;;1F9C;;1F9C 1F95;GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F25 0345;;;;N;;;1F9D;;1F9D 1F96;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F26 0345;;;;N;;;1F9E;;1F9E 1F97;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F27 0345;;;;N;;;1F9F;;1F9F 1F98;GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F28 0345;;;;N;;;;1F90; 1F99;GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F29 0345;;;;N;;;;1F91; 1F9A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2A 0345;;;;N;;;;1F92; 1F9B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2B 0345;;;;N;;;;1F93; 1F9C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2C 0345;;;;N;;;;1F94; 1F9D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2D 0345;;;;N;;;;1F95; 1F9E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2E 0345;;;;N;;;;1F96; 1F9F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2F 0345;;;;N;;;;1F97; 1FA0;GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F60 0345;;;;N;;;1FA8;;1FA8 1FA1;GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F61 0345;;;;N;;;1FA9;;1FA9 1FA2;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F62 0345;;;;N;;;1FAA;;1FAA 1FA3;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F63 0345;;;;N;;;1FAB;;1FAB 1FA4;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F64 0345;;;;N;;;1FAC;;1FAC 1FA5;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F65 0345;;;;N;;;1FAD;;1FAD 1FA6;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F66 0345;;;;N;;;1FAE;;1FAE 1FA7;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F67 0345;;;;N;;;1FAF;;1FAF 1FA8;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F68 0345;;;;N;;;;1FA0; 1FA9;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F69 0345;;;;N;;;;1FA1; 1FAA;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6A 0345;;;;N;;;;1FA2; 1FAB;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6B 0345;;;;N;;;;1FA3; 1FAC;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6C 0345;;;;N;;;;1FA4; 1FAD;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6D 0345;;;;N;;;;1FA5; 1FAE;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6E 0345;;;;N;;;;1FA6; 1FAF;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6F 0345;;;;N;;;;1FA7; 1FB0;GREEK SMALL LETTER ALPHA WITH VRACHY;Ll;0;L;03B1 0306;;;;N;;;1FB8;;1FB8 1FB1;GREEK SMALL LETTER ALPHA WITH MACRON;Ll;0;L;03B1 0304;;;;N;;;1FB9;;1FB9 1FB2;GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F70 0345;;;;N;;;;; 1FB3;GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI;Ll;0;L;03B1 0345;;;;N;;;1FBC;;1FBC 1FB4;GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AC 0345;;;;N;;;;; 1FB6;GREEK SMALL LETTER ALPHA WITH PERISPOMENI;Ll;0;L;03B1 0342;;;;N;;;;; 1FB7;GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FB6 0345;;;;N;;;;; 1FB8;GREEK CAPITAL LETTER ALPHA WITH VRACHY;Lu;0;L;0391 0306;;;;N;;;;1FB0; 1FB9;GREEK CAPITAL LETTER ALPHA WITH MACRON;Lu;0;L;0391 0304;;;;N;;;;1FB1; 1FBA;GREEK CAPITAL LETTER ALPHA WITH VARIA;Lu;0;L;0391 0300;;;;N;;;;1F70; 1FBB;GREEK CAPITAL LETTER ALPHA WITH OXIA;Lu;0;L;0386;;;;N;;;;1F71; 1FBC;GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI;Lt;0;L;0391 0345;;;;N;;;;1FB3; 1FBD;GREEK KORONIS;Sk;0;ON; 0020 0313;;;;N;;;;; 1FBE;GREEK PROSGEGRAMMENI;Ll;0;L;03B9;;;;N;;;0399;;0399 1FBF;GREEK PSILI;Sk;0;ON; 0020 0313;;;;N;;;;; 1FC0;GREEK PERISPOMENI;Sk;0;ON; 0020 0342;;;;N;;;;; 1FC1;GREEK DIALYTIKA AND PERISPOMENI;Sk;0;ON;00A8 0342;;;;N;;;;; 1FC2;GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F74 0345;;;;N;;;;; 1FC3;GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI;Ll;0;L;03B7 0345;;;;N;;;1FCC;;1FCC 1FC4;GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AE 0345;;;;N;;;;; 1FC6;GREEK SMALL LETTER ETA WITH PERISPOMENI;Ll;0;L;03B7 0342;;;;N;;;;; 1FC7;GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FC6 0345;;;;N;;;;; 1FC8;GREEK CAPITAL LETTER EPSILON WITH VARIA;Lu;0;L;0395 0300;;;;N;;;;1F72; 1FC9;GREEK CAPITAL LETTER EPSILON WITH OXIA;Lu;0;L;0388;;;;N;;;;1F73; 1FCA;GREEK CAPITAL LETTER ETA WITH VARIA;Lu;0;L;0397 0300;;;;N;;;;1F74; 1FCB;GREEK CAPITAL LETTER ETA WITH OXIA;Lu;0;L;0389;;;;N;;;;1F75; 1FCC;GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI;Lt;0;L;0397 0345;;;;N;;;;1FC3; 1FCD;GREEK PSILI AND VARIA;Sk;0;ON;1FBF 0300;;;;N;;;;; 1FCE;GREEK PSILI AND OXIA;Sk;0;ON;1FBF 0301;;;;N;;;;; 1FCF;GREEK PSILI AND PERISPOMENI;Sk;0;ON;1FBF 0342;;;;N;;;;; 1FD0;GREEK SMALL LETTER IOTA WITH VRACHY;Ll;0;L;03B9 0306;;;;N;;;1FD8;;1FD8 1FD1;GREEK SMALL LETTER IOTA WITH MACRON;Ll;0;L;03B9 0304;;;;N;;;1FD9;;1FD9 1FD2;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA;Ll;0;L;03CA 0300;;;;N;;;;; 1FD3;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA;Ll;0;L;0390;;;;N;;;;; 1FD6;GREEK SMALL LETTER IOTA WITH PERISPOMENI;Ll;0;L;03B9 0342;;;;N;;;;; 1FD7;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CA 0342;;;;N;;;;; 1FD8;GREEK CAPITAL LETTER IOTA WITH VRACHY;Lu;0;L;0399 0306;;;;N;;;;1FD0; 1FD9;GREEK CAPITAL LETTER IOTA WITH MACRON;Lu;0;L;0399 0304;;;;N;;;;1FD1; 1FDA;GREEK CAPITAL LETTER IOTA WITH VARIA;Lu;0;L;0399 0300;;;;N;;;;1F76; 1FDB;GREEK CAPITAL LETTER IOTA WITH OXIA;Lu;0;L;038A;;;;N;;;;1F77; 1FDD;GREEK DASIA AND VARIA;Sk;0;ON;1FFE 0300;;;;N;;;;; 1FDE;GREEK DASIA AND OXIA;Sk;0;ON;1FFE 0301;;;;N;;;;; 1FDF;GREEK DASIA AND PERISPOMENI;Sk;0;ON;1FFE 0342;;;;N;;;;; 1FE0;GREEK SMALL LETTER UPSILON WITH VRACHY;Ll;0;L;03C5 0306;;;;N;;;1FE8;;1FE8 1FE1;GREEK SMALL LETTER UPSILON WITH MACRON;Ll;0;L;03C5 0304;;;;N;;;1FE9;;1FE9 1FE2;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA;Ll;0;L;03CB 0300;;;;N;;;;; 1FE3;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA;Ll;0;L;03B0;;;;N;;;;; 1FE4;GREEK SMALL LETTER RHO WITH PSILI;Ll;0;L;03C1 0313;;;;N;;;;; 1FE5;GREEK SMALL LETTER RHO WITH DASIA;Ll;0;L;03C1 0314;;;;N;;;1FEC;;1FEC 1FE6;GREEK SMALL LETTER UPSILON WITH PERISPOMENI;Ll;0;L;03C5 0342;;;;N;;;;; 1FE7;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CB 0342;;;;N;;;;; 1FE8;GREEK CAPITAL LETTER UPSILON WITH VRACHY;Lu;0;L;03A5 0306;;;;N;;;;1FE0; 1FE9;GREEK CAPITAL LETTER UPSILON WITH MACRON;Lu;0;L;03A5 0304;;;;N;;;;1FE1; 1FEA;GREEK CAPITAL LETTER UPSILON WITH VARIA;Lu;0;L;03A5 0300;;;;N;;;;1F7A; 1FEB;GREEK CAPITAL LETTER UPSILON WITH OXIA;Lu;0;L;038E;;;;N;;;;1F7B; 1FEC;GREEK CAPITAL LETTER RHO WITH DASIA;Lu;0;L;03A1 0314;;;;N;;;;1FE5; 1FED;GREEK DIALYTIKA AND VARIA;Sk;0;ON;00A8 0300;;;;N;;;;; 1FEE;GREEK DIALYTIKA AND OXIA;Sk;0;ON;0385;;;;N;;;;; 1FEF;GREEK VARIA;Sk;0;ON;0060;;;;N;;;;; 1FF2;GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F7C 0345;;;;N;;;;; 1FF3;GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI;Ll;0;L;03C9 0345;;;;N;;;1FFC;;1FFC 1FF4;GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03CE 0345;;;;N;;;;; 1FF6;GREEK SMALL LETTER OMEGA WITH PERISPOMENI;Ll;0;L;03C9 0342;;;;N;;;;; 1FF7;GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FF6 0345;;;;N;;;;; 1FF8;GREEK CAPITAL LETTER OMICRON WITH VARIA;Lu;0;L;039F 0300;;;;N;;;;1F78; 1FF9;GREEK CAPITAL LETTER OMICRON WITH OXIA;Lu;0;L;038C;;;;N;;;;1F79; 1FFA;GREEK CAPITAL LETTER OMEGA WITH VARIA;Lu;0;L;03A9 0300;;;;N;;;;1F7C; 1FFB;GREEK CAPITAL LETTER OMEGA WITH OXIA;Lu;0;L;038F;;;;N;;;;1F7D; 1FFC;GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI;Lt;0;L;03A9 0345;;;;N;;;;1FF3; 1FFD;GREEK OXIA;Sk;0;ON;00B4;;;;N;;;;; 1FFE;GREEK DASIA;Sk;0;ON; 0020 0314;;;;N;;;;; 2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;; 2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;; 2002;EN SPACE;Zs;0;WS; 0020;;;;N;;;;; 2003;EM SPACE;Zs;0;WS; 0020;;;;N;;;;; 2004;THREE-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; 2005;FOUR-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; 2006;SIX-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; 2007;FIGURE SPACE;Zs;0;WS; 0020;;;;N;;;;; 2008;PUNCTUATION SPACE;Zs;0;WS; 0020;;;;N;;;;; 2009;THIN SPACE;Zs;0;WS; 0020;;;;N;;;;; 200A;HAIR SPACE;Zs;0;WS; 0020;;;;N;;;;; 200B;ZERO WIDTH SPACE;Zs;0;BN;;;;;N;;;;; 200C;ZERO WIDTH NON-JOINER;Cf;0;BN;;;;;N;;;;; 200D;ZERO WIDTH JOINER;Cf;0;BN;;;;;N;;;;; 200E;LEFT-TO-RIGHT MARK;Cf;0;L;;;;;N;;;;; 200F;RIGHT-TO-LEFT MARK;Cf;0;R;;;;;N;;;;; 2010;HYPHEN;Pd;0;ON;;;;;N;;;;; 2011;NON-BREAKING HYPHEN;Pd;0;ON; 2010;;;;N;;;;; 2012;FIGURE DASH;Pd;0;ON;;;;;N;;;;; 2013;EN DASH;Pd;0;ON;;;;;N;;;;; 2014;EM DASH;Pd;0;ON;;;;;N;;;;; 2015;HORIZONTAL BAR;Pd;0;ON;;;;;N;QUOTATION DASH;;;; 2016;DOUBLE VERTICAL LINE;Po;0;ON;;;;;N;DOUBLE VERTICAL BAR;;;; 2017;DOUBLE LOW LINE;Po;0;ON; 0020 0333;;;;N;SPACING DOUBLE UNDERSCORE;;;; 2018;LEFT SINGLE QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE TURNED COMMA QUOTATION MARK;;;; 2019;RIGHT SINGLE QUOTATION MARK;Pf;0;ON;;;;;N;SINGLE COMMA QUOTATION MARK;;;; 201A;SINGLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW SINGLE COMMA QUOTATION MARK;;;; 201B;SINGLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE REVERSED COMMA QUOTATION MARK;;;; 201C;LEFT DOUBLE QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE TURNED COMMA QUOTATION MARK;;;; 201D;RIGHT DOUBLE QUOTATION MARK;Pf;0;ON;;;;;N;DOUBLE COMMA QUOTATION MARK;;;; 201E;DOUBLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW DOUBLE COMMA QUOTATION MARK;;;; 201F;DOUBLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE REVERSED COMMA QUOTATION MARK;;;; 2020;DAGGER;Po;0;ON;;;;;N;;;;; 2021;DOUBLE DAGGER;Po;0;ON;;;;;N;;;;; 2022;BULLET;Po;0;ON;;;;;N;;;;; 2023;TRIANGULAR BULLET;Po;0;ON;;;;;N;;;;; 2024;ONE DOT LEADER;Po;0;ON; 002E;;;;N;;;;; 2025;TWO DOT LEADER;Po;0;ON; 002E 002E;;;;N;;;;; 2026;HORIZONTAL ELLIPSIS;Po;0;ON; 002E 002E 002E;;;;N;;;;; 2027;HYPHENATION POINT;Po;0;ON;;;;;N;;;;; 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; 202A;LEFT-TO-RIGHT EMBEDDING;Cf;0;LRE;;;;;N;;;;; 202B;RIGHT-TO-LEFT EMBEDDING;Cf;0;RLE;;;;;N;;;;; 202C;POP DIRECTIONAL FORMATTING;Cf;0;PDF;;;;;N;;;;; 202D;LEFT-TO-RIGHT OVERRIDE;Cf;0;LRO;;;;;N;;;;; 202E;RIGHT-TO-LEFT OVERRIDE;Cf;0;RLO;;;;;N;;;;; 202F;NARROW NO-BREAK SPACE;Zs;0;WS; 0020;;;;N;;;;; 2030;PER MILLE SIGN;Po;0;ET;;;;;N;;;;; 2031;PER TEN THOUSAND SIGN;Po;0;ET;;;;;N;;;;; 2032;PRIME;Po;0;ET;;;;;N;;;;; 2033;DOUBLE PRIME;Po;0;ET; 2032 2032;;;;N;;;;; 2034;TRIPLE PRIME;Po;0;ET; 2032 2032 2032;;;;N;;;;; 2035;REVERSED PRIME;Po;0;ON;;;;;N;;;;; 2036;REVERSED DOUBLE PRIME;Po;0;ON; 2035 2035;;;;N;;;;; 2037;REVERSED TRIPLE PRIME;Po;0;ON; 2035 2035 2035;;;;N;;;;; 2038;CARET;Po;0;ON;;;;;N;;;;; 2039;SINGLE LEFT-POINTING ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING SINGLE GUILLEMET;;;; 203A;SINGLE RIGHT-POINTING ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING SINGLE GUILLEMET;;;; 203B;REFERENCE MARK;Po;0;ON;;;;;N;;;;; 203C;DOUBLE EXCLAMATION MARK;Po;0;ON; 0021 0021;;;;N;;;;; 203D;INTERROBANG;Po;0;ON;;;;;N;;;;; 203E;OVERLINE;Po;0;ON; 0020 0305;;;;N;SPACING OVERSCORE;;;; 203F;UNDERTIE;Pc;0;ON;;;;;N;;Enotikon;;; 2040;CHARACTER TIE;Pc;0;ON;;;;;N;;;;; 2041;CARET INSERTION POINT;Po;0;ON;;;;;N;;;;; 2042;ASTERISM;Po;0;ON;;;;;N;;;;; 2043;HYPHEN BULLET;Po;0;ON;;;;;N;;;;; 2044;FRACTION SLASH;Sm;0;ON;;;;;N;;;;; 2045;LEFT SQUARE BRACKET WITH QUILL;Ps;0;ON;;;;;Y;;;;; 2046;RIGHT SQUARE BRACKET WITH QUILL;Pe;0;ON;;;;;Y;;;;; 2047;DOUBLE QUESTION MARK;Po;0;ON; 003F 003F;;;;N;;;;; 2048;QUESTION EXCLAMATION MARK;Po;0;ON; 003F 0021;;;;N;;;;; 2049;EXCLAMATION QUESTION MARK;Po;0;ON; 0021 003F;;;;N;;;;; 204A;TIRONIAN SIGN ET;Po;0;ON;;;;;N;;;;; 204B;REVERSED PILCROW SIGN;Po;0;ON;;;;;N;;;;; 204C;BLACK LEFTWARDS BULLET;Po;0;ON;;;;;N;;;;; 204D;BLACK RIGHTWARDS BULLET;Po;0;ON;;;;;N;;;;; 204E;LOW ASTERISK;Po;0;ON;;;;;N;;;;; 204F;REVERSED SEMICOLON;Po;0;ON;;;;;N;;;;; 2050;CLOSE UP;Po;0;ON;;;;;N;;;;; 2051;TWO ASTERISKS ALIGNED VERTICALLY;Po;0;ON;;;;;N;;;;; 2052;COMMERCIAL MINUS SIGN;Sm;0;ON;;;;;N;;;;; 2057;QUADRUPLE PRIME;Po;0;ON; 2032 2032 2032 2032;;;;N;;;;; 205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS; 0020;;;;N;;;;; 2060;WORD JOINER;Cf;0;BN;;;;;N;;;;; 2061;FUNCTION APPLICATION;Cf;0;BN;;;;;N;;;;; 2062;INVISIBLE TIMES;Cf;0;BN;;;;;N;;;;; 2063;INVISIBLE SEPARATOR;Cf;0;BN;;;;;N;;;;; 206A;INHIBIT SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;; 206B;ACTIVATE SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;; 206C;INHIBIT ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;; 206D;ACTIVATE ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;; 206E;NATIONAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;; 206F;NOMINAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;; 2070;SUPERSCRIPT ZERO;No;0;EN; 0030;0;0;0;N;SUPERSCRIPT DIGIT ZERO;;;; 2071;SUPERSCRIPT LATIN SMALL LETTER I;Ll;0;L; 0069;;;;N;;;;; 2074;SUPERSCRIPT FOUR;No;0;EN; 0034;4;4;4;N;SUPERSCRIPT DIGIT FOUR;;;; 2075;SUPERSCRIPT FIVE;No;0;EN; 0035;5;5;5;N;SUPERSCRIPT DIGIT FIVE;;;; 2076;SUPERSCRIPT SIX;No;0;EN; 0036;6;6;6;N;SUPERSCRIPT DIGIT SIX;;;; 2077;SUPERSCRIPT SEVEN;No;0;EN; 0037;7;7;7;N;SUPERSCRIPT DIGIT SEVEN;;;; 2078;SUPERSCRIPT EIGHT;No;0;EN; 0038;8;8;8;N;SUPERSCRIPT DIGIT EIGHT;;;; 2079;SUPERSCRIPT NINE;No;0;EN; 0039;9;9;9;N;SUPERSCRIPT DIGIT NINE;;;; 207A;SUPERSCRIPT PLUS SIGN;Sm;0;ET; 002B;;;;N;;;;; 207B;SUPERSCRIPT MINUS;Sm;0;ET; 2212;;;;N;SUPERSCRIPT HYPHEN-MINUS;;;; 207C;SUPERSCRIPT EQUALS SIGN;Sm;0;ON; 003D;;;;N;;;;; 207D;SUPERSCRIPT LEFT PARENTHESIS;Ps;0;ON; 0028;;;;Y;SUPERSCRIPT OPENING PARENTHESIS;;;; 207E;SUPERSCRIPT RIGHT PARENTHESIS;Pe;0;ON; 0029;;;;Y;SUPERSCRIPT CLOSING PARENTHESIS;;;; 207F;SUPERSCRIPT LATIN SMALL LETTER N;Ll;0;L; 006E;;;;N;;;;; 2080;SUBSCRIPT ZERO;No;0;EN; 0030;0;0;0;N;SUBSCRIPT DIGIT ZERO;;;; 2081;SUBSCRIPT ONE;No;0;EN; 0031;1;1;1;N;SUBSCRIPT DIGIT ONE;;;; 2082;SUBSCRIPT TWO;No;0;EN; 0032;2;2;2;N;SUBSCRIPT DIGIT TWO;;;; 2083;SUBSCRIPT THREE;No;0;EN; 0033;3;3;3;N;SUBSCRIPT DIGIT THREE;;;; 2084;SUBSCRIPT FOUR;No;0;EN; 0034;4;4;4;N;SUBSCRIPT DIGIT FOUR;;;; 2085;SUBSCRIPT FIVE;No;0;EN; 0035;5;5;5;N;SUBSCRIPT DIGIT FIVE;;;; 2086;SUBSCRIPT SIX;No;0;EN; 0036;6;6;6;N;SUBSCRIPT DIGIT SIX;;;; 2087;SUBSCRIPT SEVEN;No;0;EN; 0037;7;7;7;N;SUBSCRIPT DIGIT SEVEN;;;; 2088;SUBSCRIPT EIGHT;No;0;EN; 0038;8;8;8;N;SUBSCRIPT DIGIT EIGHT;;;; 2089;SUBSCRIPT NINE;No;0;EN; 0039;9;9;9;N;SUBSCRIPT DIGIT NINE;;;; 208A;SUBSCRIPT PLUS SIGN;Sm;0;ET; 002B;;;;N;;;;; 208B;SUBSCRIPT MINUS;Sm;0;ET; 2212;;;;N;SUBSCRIPT HYPHEN-MINUS;;;; 208C;SUBSCRIPT EQUALS SIGN;Sm;0;ON; 003D;;;;N;;;;; 208D;SUBSCRIPT LEFT PARENTHESIS;Ps;0;ON; 0028;;;;Y;SUBSCRIPT OPENING PARENTHESIS;;;; 208E;SUBSCRIPT RIGHT PARENTHESIS;Pe;0;ON; 0029;;;;Y;SUBSCRIPT CLOSING PARENTHESIS;;;; 20A0;EURO-CURRENCY SIGN;Sc;0;ET;;;;;N;;;;; 20A1;COLON SIGN;Sc;0;ET;;;;;N;;;;; 20A2;CRUZEIRO SIGN;Sc;0;ET;;;;;N;;;;; 20A3;FRENCH FRANC SIGN;Sc;0;ET;;;;;N;;;;; 20A4;LIRA SIGN;Sc;0;ET;;;;;N;;;;; 20A5;MILL SIGN;Sc;0;ET;;;;;N;;;;; 20A6;NAIRA SIGN;Sc;0;ET;;;;;N;;;;; 20A7;PESETA SIGN;Sc;0;ET;;;;;N;;;;; 20A8;RUPEE SIGN;Sc;0;ET; 0052 0073;;;;N;;;;; 20A9;WON SIGN;Sc;0;ET;;;;;N;;;;; 20AA;NEW SHEQEL SIGN;Sc;0;ET;;;;;N;;;;; 20AB;DONG SIGN;Sc;0;ET;;;;;N;;;;; 20AC;EURO SIGN;Sc;0;ET;;;;;N;;;;; 20AD;KIP SIGN;Sc;0;ET;;;;;N;;;;; 20AE;TUGRIK SIGN;Sc;0;ET;;;;;N;;;;; 20AF;DRACHMA SIGN;Sc;0;ET;;;;;N;;;;; 20B0;GERMAN PENNY SIGN;Sc;0;ET;;;;;N;;;;; 20B1;PESO SIGN;Sc;0;ET;;;;;N;;;;; 20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;; 20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;; 20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;; 20D3;COMBINING SHORT VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT VERTICAL BAR OVERLAY;;;; 20D4;COMBINING ANTICLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING ANTICLOCKWISE ARROW ABOVE;;;; 20D5;COMBINING CLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING CLOCKWISE ARROW ABOVE;;;; 20D6;COMBINING LEFT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT ARROW ABOVE;;;; 20D7;COMBINING RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT ARROW ABOVE;;;; 20D8;COMBINING RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING RING OVERLAY;;;; 20D9;COMBINING CLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING CLOCKWISE RING OVERLAY;;;; 20DA;COMBINING ANTICLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING ANTICLOCKWISE RING OVERLAY;;;; 20DB;COMBINING THREE DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING THREE DOTS ABOVE;;;; 20DC;COMBINING FOUR DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING FOUR DOTS ABOVE;;;; 20DD;COMBINING ENCLOSING CIRCLE;Me;0;NSM;;;;;N;ENCLOSING CIRCLE;;;; 20DE;COMBINING ENCLOSING SQUARE;Me;0;NSM;;;;;N;ENCLOSING SQUARE;;;; 20DF;COMBINING ENCLOSING DIAMOND;Me;0;NSM;;;;;N;ENCLOSING DIAMOND;;;; 20E0;COMBINING ENCLOSING CIRCLE BACKSLASH;Me;0;NSM;;;;;N;ENCLOSING CIRCLE SLASH;;;; 20E1;COMBINING LEFT RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT RIGHT ARROW ABOVE;;;; 20E2;COMBINING ENCLOSING SCREEN;Me;0;NSM;;;;;N;;;;; 20E3;COMBINING ENCLOSING KEYCAP;Me;0;NSM;;;;;N;;;;; 20E4;COMBINING ENCLOSING UPWARD POINTING TRIANGLE;Me;0;NSM;;;;;N;;;;; 20E5;COMBINING REVERSE SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;;;;; 20E6;COMBINING DOUBLE VERTICAL STROKE OVERLAY;Mn;1;NSM;;;;;N;;;;; 20E7;COMBINING ANNUITY SYMBOL;Mn;230;NSM;;;;;N;;;;; 20E8;COMBINING TRIPLE UNDERDOT;Mn;220;NSM;;;;;N;;;;; 20E9;COMBINING WIDE BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;; 20EA;COMBINING LEFTWARDS ARROW OVERLAY;Mn;1;NSM;;;;;N;;;;; 2100;ACCOUNT OF;So;0;ON; 0061 002F 0063;;;;N;;;;; 2101;ADDRESSED TO THE SUBJECT;So;0;ON; 0061 002F 0073;;;;N;;;;; 2102;DOUBLE-STRUCK CAPITAL C;Lu;0;L; 0043;;;;N;DOUBLE-STRUCK C;;;; 2103;DEGREE CELSIUS;So;0;ON; 00B0 0043;;;;N;DEGREES CENTIGRADE;;;; 2104;CENTRE LINE SYMBOL;So;0;ON;;;;;N;C L SYMBOL;;;; 2105;CARE OF;So;0;ON; 0063 002F 006F;;;;N;;;;; 2106;CADA UNA;So;0;ON; 0063 002F 0075;;;;N;;;;; 2107;EULER CONSTANT;Lu;0;L; 0190;;;;N;EULERS;;;; 2108;SCRUPLE;So;0;ON;;;;;N;;;;; 2109;DEGREE FAHRENHEIT;So;0;ON; 00B0 0046;;;;N;DEGREES FAHRENHEIT;;;; 210A;SCRIPT SMALL G;Ll;0;L; 0067;;;;N;;;;; 210B;SCRIPT CAPITAL H;Lu;0;L; 0048;;;;N;SCRIPT H;;;; 210C;BLACK-LETTER CAPITAL H;Lu;0;L; 0048;;;;N;BLACK-LETTER H;;;; 210D;DOUBLE-STRUCK CAPITAL H;Lu;0;L; 0048;;;;N;DOUBLE-STRUCK H;;;; 210E;PLANCK CONSTANT;Ll;0;L; 0068;;;;N;;;;; 210F;PLANCK CONSTANT OVER TWO PI;Ll;0;L; 0127;;;;N;PLANCK CONSTANT OVER 2 PI;;;; 2110;SCRIPT CAPITAL I;Lu;0;L; 0049;;;;N;SCRIPT I;;;; 2111;BLACK-LETTER CAPITAL I;Lu;0;L; 0049;;;;N;BLACK-LETTER I;;;; 2112;SCRIPT CAPITAL L;Lu;0;L; 004C;;;;N;SCRIPT L;;;; 2113;SCRIPT SMALL L;Ll;0;L; 006C;;;;N;;;;; 2114;L B BAR SYMBOL;So;0;ON;;;;;N;;;;; 2115;DOUBLE-STRUCK CAPITAL N;Lu;0;L; 004E;;;;N;DOUBLE-STRUCK N;;;; 2116;NUMERO SIGN;So;0;ON; 004E 006F;;;;N;NUMERO;;;; 2117;SOUND RECORDING COPYRIGHT;So;0;ON;;;;;N;;;;; 2118;SCRIPT CAPITAL P;So;0;ON;;;;;N;SCRIPT P;;;; 2119;DOUBLE-STRUCK CAPITAL P;Lu;0;L; 0050;;;;N;DOUBLE-STRUCK P;;;; 211A;DOUBLE-STRUCK CAPITAL Q;Lu;0;L; 0051;;;;N;DOUBLE-STRUCK Q;;;; 211B;SCRIPT CAPITAL R;Lu;0;L; 0052;;;;N;SCRIPT R;;;; 211C;BLACK-LETTER CAPITAL R;Lu;0;L; 0052;;;;N;BLACK-LETTER R;;;; 211D;DOUBLE-STRUCK CAPITAL R;Lu;0;L; 0052;;;;N;DOUBLE-STRUCK R;;;; 211E;PRESCRIPTION TAKE;So;0;ON;;;;;N;;;;; 211F;RESPONSE;So;0;ON;;;;;N;;;;; 2120;SERVICE MARK;So;0;ON; 0053 004D;;;;N;;;;; 2121;TELEPHONE SIGN;So;0;ON; 0054 0045 004C;;;;N;T E L SYMBOL;;;; 2122;TRADE MARK SIGN;So;0;ON; 0054 004D;;;;N;TRADEMARK;;;; 2123;VERSICLE;So;0;ON;;;;;N;;;;; 2124;DOUBLE-STRUCK CAPITAL Z;Lu;0;L; 005A;;;;N;DOUBLE-STRUCK Z;;;; 2125;OUNCE SIGN;So;0;ON;;;;;N;OUNCE;;;; 2126;OHM SIGN;Lu;0;L;03A9;;;;N;OHM;;;03C9; 2127;INVERTED OHM SIGN;So;0;ON;;;;;N;MHO;;;; 2128;BLACK-LETTER CAPITAL Z;Lu;0;L; 005A;;;;N;BLACK-LETTER Z;;;; 2129;TURNED GREEK SMALL LETTER IOTA;So;0;ON;;;;;N;;;;; 212A;KELVIN SIGN;Lu;0;L;004B;;;;N;DEGREES KELVIN;;;006B; 212B;ANGSTROM SIGN;Lu;0;L;00C5;;;;N;ANGSTROM UNIT;;;00E5; 212C;SCRIPT CAPITAL B;Lu;0;L; 0042;;;;N;SCRIPT B;;;; 212D;BLACK-LETTER CAPITAL C;Lu;0;L; 0043;;;;N;BLACK-LETTER C;;;; 212E;ESTIMATED SYMBOL;So;0;ET;;;;;N;;;;; 212F;SCRIPT SMALL E;Ll;0;L; 0065;;;;N;;;;; 2130;SCRIPT CAPITAL E;Lu;0;L; 0045;;;;N;SCRIPT E;;;; 2131;SCRIPT CAPITAL F;Lu;0;L; 0046;;;;N;SCRIPT F;;;; 2132;TURNED CAPITAL F;So;0;ON;;;;;N;TURNED F;;;; 2133;SCRIPT CAPITAL M;Lu;0;L; 004D;;;;N;SCRIPT M;;;; 2134;SCRIPT SMALL O;Ll;0;L; 006F;;;;N;;;;; 2135;ALEF SYMBOL;Lo;0;L; 05D0;;;;N;FIRST TRANSFINITE CARDINAL;;;; 2136;BET SYMBOL;Lo;0;L; 05D1;;;;N;SECOND TRANSFINITE CARDINAL;;;; 2137;GIMEL SYMBOL;Lo;0;L; 05D2;;;;N;THIRD TRANSFINITE CARDINAL;;;; 2138;DALET SYMBOL;Lo;0;L; 05D3;;;;N;FOURTH TRANSFINITE CARDINAL;;;; 2139;INFORMATION SOURCE;Ll;0;L; 0069;;;;N;;;;; 213A;ROTATED CAPITAL Q;So;0;ON;;;;;N;;;;; 213D;DOUBLE-STRUCK SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; 213E;DOUBLE-STRUCK CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; 213F;DOUBLE-STRUCK CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; 2140;DOUBLE-STRUCK N-ARY SUMMATION;Sm;0;ON; 2211;;;;Y;;;;; 2141;TURNED SANS-SERIF CAPITAL G;Sm;0;ON;;;;;N;;;;; 2142;TURNED SANS-SERIF CAPITAL L;Sm;0;ON;;;;;N;;;;; 2143;REVERSED SANS-SERIF CAPITAL L;Sm;0;ON;;;;;N;;;;; 2144;TURNED SANS-SERIF CAPITAL Y;Sm;0;ON;;;;;N;;;;; 2145;DOUBLE-STRUCK ITALIC CAPITAL D;Lu;0;L; 0044;;;;N;;;;; 2146;DOUBLE-STRUCK ITALIC SMALL D;Ll;0;L; 0064;;;;N;;;;; 2147;DOUBLE-STRUCK ITALIC SMALL E;Ll;0;L; 0065;;;;N;;;;; 2148;DOUBLE-STRUCK ITALIC SMALL I;Ll;0;L; 0069;;;;N;;;;; 2149;DOUBLE-STRUCK ITALIC SMALL J;Ll;0;L; 006A;;;;N;;;;; 214A;PROPERTY LINE;So;0;ON;;;;;N;;;;; 214B;TURNED AMPERSAND;Sm;0;ON;;;;;N;;;;; 2153;VULGAR FRACTION ONE THIRD;No;0;ON; 0031 2044 0033;;;1/3;N;FRACTION ONE THIRD;;;; 2154;VULGAR FRACTION TWO THIRDS;No;0;ON; 0032 2044 0033;;;2/3;N;FRACTION TWO THIRDS;;;; 2155;VULGAR FRACTION ONE FIFTH;No;0;ON; 0031 2044 0035;;;1/5;N;FRACTION ONE FIFTH;;;; 2156;VULGAR FRACTION TWO FIFTHS;No;0;ON; 0032 2044 0035;;;2/5;N;FRACTION TWO FIFTHS;;;; 2157;VULGAR FRACTION THREE FIFTHS;No;0;ON; 0033 2044 0035;;;3/5;N;FRACTION THREE FIFTHS;;;; 2158;VULGAR FRACTION FOUR FIFTHS;No;0;ON; 0034 2044 0035;;;4/5;N;FRACTION FOUR FIFTHS;;;; 2159;VULGAR FRACTION ONE SIXTH;No;0;ON; 0031 2044 0036;;;1/6;N;FRACTION ONE SIXTH;;;; 215A;VULGAR FRACTION FIVE SIXTHS;No;0;ON; 0035 2044 0036;;;5/6;N;FRACTION FIVE SIXTHS;;;; 215B;VULGAR FRACTION ONE EIGHTH;No;0;ON; 0031 2044 0038;;;1/8;N;FRACTION ONE EIGHTH;;;; 215C;VULGAR FRACTION THREE EIGHTHS;No;0;ON; 0033 2044 0038;;;3/8;N;FRACTION THREE EIGHTHS;;;; 215D;VULGAR FRACTION FIVE EIGHTHS;No;0;ON; 0035 2044 0038;;;5/8;N;FRACTION FIVE EIGHTHS;;;; 215E;VULGAR FRACTION SEVEN EIGHTHS;No;0;ON; 0037 2044 0038;;;7/8;N;FRACTION SEVEN EIGHTHS;;;; 215F;FRACTION NUMERATOR ONE;No;0;ON; 0031 2044;;;1;N;;;;; 2160;ROMAN NUMERAL ONE;Nl;0;L; 0049;;;1;N;;;;2170; 2161;ROMAN NUMERAL TWO;Nl;0;L; 0049 0049;;;2;N;;;;2171; 2162;ROMAN NUMERAL THREE;Nl;0;L; 0049 0049 0049;;;3;N;;;;2172; 2163;ROMAN NUMERAL FOUR;Nl;0;L; 0049 0056;;;4;N;;;;2173; 2164;ROMAN NUMERAL FIVE;Nl;0;L; 0056;;;5;N;;;;2174; 2165;ROMAN NUMERAL SIX;Nl;0;L; 0056 0049;;;6;N;;;;2175; 2166;ROMAN NUMERAL SEVEN;Nl;0;L; 0056 0049 0049;;;7;N;;;;2176; 2167;ROMAN NUMERAL EIGHT;Nl;0;L; 0056 0049 0049 0049;;;8;N;;;;2177; 2168;ROMAN NUMERAL NINE;Nl;0;L; 0049 0058;;;9;N;;;;2178; 2169;ROMAN NUMERAL TEN;Nl;0;L; 0058;;;10;N;;;;2179; 216A;ROMAN NUMERAL ELEVEN;Nl;0;L; 0058 0049;;;11;N;;;;217A; 216B;ROMAN NUMERAL TWELVE;Nl;0;L; 0058 0049 0049;;;12;N;;;;217B; 216C;ROMAN NUMERAL FIFTY;Nl;0;L; 004C;;;50;N;;;;217C; 216D;ROMAN NUMERAL ONE HUNDRED;Nl;0;L; 0043;;;100;N;;;;217D; 216E;ROMAN NUMERAL FIVE HUNDRED;Nl;0;L; 0044;;;500;N;;;;217E; 216F;ROMAN NUMERAL ONE THOUSAND;Nl;0;L; 004D;;;1000;N;;;;217F; 2170;SMALL ROMAN NUMERAL ONE;Nl;0;L; 0069;;;1;N;;;2160;;2160 2171;SMALL ROMAN NUMERAL TWO;Nl;0;L; 0069 0069;;;2;N;;;2161;;2161 2172;SMALL ROMAN NUMERAL THREE;Nl;0;L; 0069 0069 0069;;;3;N;;;2162;;2162 2173;SMALL ROMAN NUMERAL FOUR;Nl;0;L; 0069 0076;;;4;N;;;2163;;2163 2174;SMALL ROMAN NUMERAL FIVE;Nl;0;L; 0076;;;5;N;;;2164;;2164 2175;SMALL ROMAN NUMERAL SIX;Nl;0;L; 0076 0069;;;6;N;;;2165;;2165 2176;SMALL ROMAN NUMERAL SEVEN;Nl;0;L; 0076 0069 0069;;;7;N;;;2166;;2166 2177;SMALL ROMAN NUMERAL EIGHT;Nl;0;L; 0076 0069 0069 0069;;;8;N;;;2167;;2167 2178;SMALL ROMAN NUMERAL NINE;Nl;0;L; 0069 0078;;;9;N;;;2168;;2168 2179;SMALL ROMAN NUMERAL TEN;Nl;0;L; 0078;;;10;N;;;2169;;2169 217A;SMALL ROMAN NUMERAL ELEVEN;Nl;0;L; 0078 0069;;;11;N;;;216A;;216A 217B;SMALL ROMAN NUMERAL TWELVE;Nl;0;L; 0078 0069 0069;;;12;N;;;216B;;216B 217C;SMALL ROMAN NUMERAL FIFTY;Nl;0;L; 006C;;;50;N;;;216C;;216C 217D;SMALL ROMAN NUMERAL ONE HUNDRED;Nl;0;L; 0063;;;100;N;;;216D;;216D 217E;SMALL ROMAN NUMERAL FIVE HUNDRED;Nl;0;L; 0064;;;500;N;;;216E;;216E 217F;SMALL ROMAN NUMERAL ONE THOUSAND;Nl;0;L; 006D;;;1000;N;;;216F;;216F 2180;ROMAN NUMERAL ONE THOUSAND C D;Nl;0;L;;;;1000;N;;;;; 2181;ROMAN NUMERAL FIVE THOUSAND;Nl;0;L;;;;5000;N;;;;; 2182;ROMAN NUMERAL TEN THOUSAND;Nl;0;L;;;;10000;N;;;;; 2183;ROMAN NUMERAL REVERSED ONE HUNDRED;Nl;0;L;;;;;N;;;;; 2190;LEFTWARDS ARROW;Sm;0;ON;;;;;N;LEFT ARROW;;;; 2191;UPWARDS ARROW;Sm;0;ON;;;;;N;UP ARROW;;;; 2192;RIGHTWARDS ARROW;Sm;0;ON;;;;;N;RIGHT ARROW;;;; 2193;DOWNWARDS ARROW;Sm;0;ON;;;;;N;DOWN ARROW;;;; 2194;LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;; 2195;UP DOWN ARROW;So;0;ON;;;;;N;;;;; 2196;NORTH WEST ARROW;So;0;ON;;;;;N;UPPER LEFT ARROW;;;; 2197;NORTH EAST ARROW;So;0;ON;;;;;N;UPPER RIGHT ARROW;;;; 2198;SOUTH EAST ARROW;So;0;ON;;;;;N;LOWER RIGHT ARROW;;;; 2199;SOUTH WEST ARROW;So;0;ON;;;;;N;LOWER LEFT ARROW;;;; 219A;LEFTWARDS ARROW WITH STROKE;Sm;0;ON;2190 0338;;;;N;LEFT ARROW WITH STROKE;;;; 219B;RIGHTWARDS ARROW WITH STROKE;Sm;0;ON;2192 0338;;;;N;RIGHT ARROW WITH STROKE;;;; 219C;LEFTWARDS WAVE ARROW;So;0;ON;;;;;N;LEFT WAVE ARROW;;;; 219D;RIGHTWARDS WAVE ARROW;So;0;ON;;;;;N;RIGHT WAVE ARROW;;;; 219E;LEFTWARDS TWO HEADED ARROW;So;0;ON;;;;;N;LEFT TWO HEADED ARROW;;;; 219F;UPWARDS TWO HEADED ARROW;So;0;ON;;;;;N;UP TWO HEADED ARROW;;;; 21A0;RIGHTWARDS TWO HEADED ARROW;Sm;0;ON;;;;;N;RIGHT TWO HEADED ARROW;;;; 21A1;DOWNWARDS TWO HEADED ARROW;So;0;ON;;;;;N;DOWN TWO HEADED ARROW;;;; 21A2;LEFTWARDS ARROW WITH TAIL;So;0;ON;;;;;N;LEFT ARROW WITH TAIL;;;; 21A3;RIGHTWARDS ARROW WITH TAIL;Sm;0;ON;;;;;N;RIGHT ARROW WITH TAIL;;;; 21A4;LEFTWARDS ARROW FROM BAR;So;0;ON;;;;;N;LEFT ARROW FROM BAR;;;; 21A5;UPWARDS ARROW FROM BAR;So;0;ON;;;;;N;UP ARROW FROM BAR;;;; 21A6;RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;RIGHT ARROW FROM BAR;;;; 21A7;DOWNWARDS ARROW FROM BAR;So;0;ON;;;;;N;DOWN ARROW FROM BAR;;;; 21A8;UP DOWN ARROW WITH BASE;So;0;ON;;;;;N;;;;; 21A9;LEFTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;LEFT ARROW WITH HOOK;;;; 21AA;RIGHTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;RIGHT ARROW WITH HOOK;;;; 21AB;LEFTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;LEFT ARROW WITH LOOP;;;; 21AC;RIGHTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;RIGHT ARROW WITH LOOP;;;; 21AD;LEFT RIGHT WAVE ARROW;So;0;ON;;;;;N;;;;; 21AE;LEFT RIGHT ARROW WITH STROKE;Sm;0;ON;2194 0338;;;;N;;;;; 21AF;DOWNWARDS ZIGZAG ARROW;So;0;ON;;;;;N;DOWN ZIGZAG ARROW;;;; 21B0;UPWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP LEFT;;;; 21B1;UPWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP RIGHT;;;; 21B2;DOWNWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP LEFT;;;; 21B3;DOWNWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP RIGHT;;;; 21B4;RIGHTWARDS ARROW WITH CORNER DOWNWARDS;So;0;ON;;;;;N;RIGHT ARROW WITH CORNER DOWN;;;; 21B5;DOWNWARDS ARROW WITH CORNER LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH CORNER LEFT;;;; 21B6;ANTICLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;; 21B7;CLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;; 21B8;NORTH WEST ARROW TO LONG BAR;So;0;ON;;;;;N;UPPER LEFT ARROW TO LONG BAR;;;; 21B9;LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR OVER RIGHT ARROW TO BAR;;;; 21BA;ANTICLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;; 21BB;CLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;; 21BC;LEFTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB UP;;;; 21BD;LEFTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB DOWN;;;; 21BE;UPWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB RIGHT;;;; 21BF;UPWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB LEFT;;;; 21C0;RIGHTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB UP;;;; 21C1;RIGHTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB DOWN;;;; 21C2;DOWNWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB RIGHT;;;; 21C3;DOWNWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB LEFT;;;; 21C4;RIGHTWARDS ARROW OVER LEFTWARDS ARROW;So;0;ON;;;;;N;RIGHT ARROW OVER LEFT ARROW;;;; 21C5;UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW;So;0;ON;;;;;N;UP ARROW LEFT OF DOWN ARROW;;;; 21C6;LEFTWARDS ARROW OVER RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT ARROW OVER RIGHT ARROW;;;; 21C7;LEFTWARDS PAIRED ARROWS;So;0;ON;;;;;N;LEFT PAIRED ARROWS;;;; 21C8;UPWARDS PAIRED ARROWS;So;0;ON;;;;;N;UP PAIRED ARROWS;;;; 21C9;RIGHTWARDS PAIRED ARROWS;So;0;ON;;;;;N;RIGHT PAIRED ARROWS;;;; 21CA;DOWNWARDS PAIRED ARROWS;So;0;ON;;;;;N;DOWN PAIRED ARROWS;;;; 21CB;LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON;So;0;ON;;;;;N;LEFT HARPOON OVER RIGHT HARPOON;;;; 21CC;RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON;So;0;ON;;;;;N;RIGHT HARPOON OVER LEFT HARPOON;;;; 21CD;LEFTWARDS DOUBLE ARROW WITH STROKE;So;0;ON;21D0 0338;;;;N;LEFT DOUBLE ARROW WITH STROKE;;;; 21CE;LEFT RIGHT DOUBLE ARROW WITH STROKE;Sm;0;ON;21D4 0338;;;;N;;;;; 21CF;RIGHTWARDS DOUBLE ARROW WITH STROKE;Sm;0;ON;21D2 0338;;;;N;RIGHT DOUBLE ARROW WITH STROKE;;;; 21D0;LEFTWARDS DOUBLE ARROW;So;0;ON;;;;;N;LEFT DOUBLE ARROW;;;; 21D1;UPWARDS DOUBLE ARROW;So;0;ON;;;;;N;UP DOUBLE ARROW;;;; 21D2;RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;RIGHT DOUBLE ARROW;;;; 21D3;DOWNWARDS DOUBLE ARROW;So;0;ON;;;;;N;DOWN DOUBLE ARROW;;;; 21D4;LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; 21D5;UP DOWN DOUBLE ARROW;So;0;ON;;;;;N;;;;; 21D6;NORTH WEST DOUBLE ARROW;So;0;ON;;;;;N;UPPER LEFT DOUBLE ARROW;;;; 21D7;NORTH EAST DOUBLE ARROW;So;0;ON;;;;;N;UPPER RIGHT DOUBLE ARROW;;;; 21D8;SOUTH EAST DOUBLE ARROW;So;0;ON;;;;;N;LOWER RIGHT DOUBLE ARROW;;;; 21D9;SOUTH WEST DOUBLE ARROW;So;0;ON;;;;;N;LOWER LEFT DOUBLE ARROW;;;; 21DA;LEFTWARDS TRIPLE ARROW;So;0;ON;;;;;N;LEFT TRIPLE ARROW;;;; 21DB;RIGHTWARDS TRIPLE ARROW;So;0;ON;;;;;N;RIGHT TRIPLE ARROW;;;; 21DC;LEFTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;LEFT SQUIGGLE ARROW;;;; 21DD;RIGHTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;RIGHT SQUIGGLE ARROW;;;; 21DE;UPWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;UP ARROW WITH DOUBLE STROKE;;;; 21DF;DOWNWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;DOWN ARROW WITH DOUBLE STROKE;;;; 21E0;LEFTWARDS DASHED ARROW;So;0;ON;;;;;N;LEFT DASHED ARROW;;;; 21E1;UPWARDS DASHED ARROW;So;0;ON;;;;;N;UP DASHED ARROW;;;; 21E2;RIGHTWARDS DASHED ARROW;So;0;ON;;;;;N;RIGHT DASHED ARROW;;;; 21E3;DOWNWARDS DASHED ARROW;So;0;ON;;;;;N;DOWN DASHED ARROW;;;; 21E4;LEFTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR;;;; 21E5;RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;RIGHT ARROW TO BAR;;;; 21E6;LEFTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE LEFT ARROW;;;; 21E7;UPWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE UP ARROW;;;; 21E8;RIGHTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE RIGHT ARROW;;;; 21E9;DOWNWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE DOWN ARROW;;;; 21EA;UPWARDS WHITE ARROW FROM BAR;So;0;ON;;;;;N;WHITE UP ARROW FROM BAR;;;; 21EB;UPWARDS WHITE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;; 21EC;UPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;; 21ED;UPWARDS WHITE ARROW ON PEDESTAL WITH VERTICAL BAR;So;0;ON;;;;;N;;;;; 21EE;UPWARDS WHITE DOUBLE ARROW;So;0;ON;;;;;N;;;;; 21EF;UPWARDS WHITE DOUBLE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;; 21F0;RIGHTWARDS WHITE ARROW FROM WALL;So;0;ON;;;;;N;;;;; 21F1;NORTH WEST ARROW TO CORNER;So;0;ON;;;;;N;;;;; 21F2;SOUTH EAST ARROW TO CORNER;So;0;ON;;;;;N;;;;; 21F3;UP DOWN WHITE ARROW;So;0;ON;;;;;N;;;;; 21F4;RIGHT ARROW WITH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; 21F5;DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW;Sm;0;ON;;;;;N;;;;; 21F6;THREE RIGHTWARDS ARROWS;Sm;0;ON;;;;;N;;;;; 21F7;LEFTWARDS ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 21F8;RIGHTWARDS ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 21F9;LEFT RIGHT ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 21FA;LEFTWARDS ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 21FB;RIGHTWARDS ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 21FC;LEFT RIGHT ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 21FD;LEFTWARDS OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;; 21FE;RIGHTWARDS OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;; 21FF;LEFT RIGHT OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;; 2200;FOR ALL;Sm;0;ON;;;;;N;;;;; 2201;COMPLEMENT;Sm;0;ON;;;;;Y;;;;; 2202;PARTIAL DIFFERENTIAL;Sm;0;ON;;;;;Y;;;;; 2203;THERE EXISTS;Sm;0;ON;;;;;Y;;;;; 2204;THERE DOES NOT EXIST;Sm;0;ON;2203 0338;;;;Y;;;;; 2205;EMPTY SET;Sm;0;ON;;;;;N;;;;; 2206;INCREMENT;Sm;0;ON;;;;;N;;;;; 2207;NABLA;Sm;0;ON;;;;;N;;;;; 2208;ELEMENT OF;Sm;0;ON;;;;;Y;;;;; 2209;NOT AN ELEMENT OF;Sm;0;ON;2208 0338;;;;Y;;;;; 220A;SMALL ELEMENT OF;Sm;0;ON;;;;;Y;;;;; 220B;CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;; 220C;DOES NOT CONTAIN AS MEMBER;Sm;0;ON;220B 0338;;;;Y;;;;; 220D;SMALL CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;; 220E;END OF PROOF;Sm;0;ON;;;;;N;;;;; 220F;N-ARY PRODUCT;Sm;0;ON;;;;;N;;;;; 2210;N-ARY COPRODUCT;Sm;0;ON;;;;;N;;;;; 2211;N-ARY SUMMATION;Sm;0;ON;;;;;Y;;;;; 2212;MINUS SIGN;Sm;0;ET;;;;;N;;;;; 2213;MINUS-OR-PLUS SIGN;Sm;0;ET;;;;;N;;;;; 2214;DOT PLUS;Sm;0;ON;;;;;N;;;;; 2215;DIVISION SLASH;Sm;0;ON;;;;;Y;;;;; 2216;SET MINUS;Sm;0;ON;;;;;Y;;;;; 2217;ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;; 2218;RING OPERATOR;Sm;0;ON;;;;;N;;;;; 2219;BULLET OPERATOR;Sm;0;ON;;;;;N;;;;; 221A;SQUARE ROOT;Sm;0;ON;;;;;Y;;;;; 221B;CUBE ROOT;Sm;0;ON;;;;;Y;;;;; 221C;FOURTH ROOT;Sm;0;ON;;;;;Y;;;;; 221D;PROPORTIONAL TO;Sm;0;ON;;;;;Y;;;;; 221E;INFINITY;Sm;0;ON;;;;;N;;;;; 221F;RIGHT ANGLE;Sm;0;ON;;;;;Y;;;;; 2220;ANGLE;Sm;0;ON;;;;;Y;;;;; 2221;MEASURED ANGLE;Sm;0;ON;;;;;Y;;;;; 2222;SPHERICAL ANGLE;Sm;0;ON;;;;;Y;;;;; 2223;DIVIDES;Sm;0;ON;;;;;N;;;;; 2224;DOES NOT DIVIDE;Sm;0;ON;2223 0338;;;;Y;;;;; 2225;PARALLEL TO;Sm;0;ON;;;;;N;;;;; 2226;NOT PARALLEL TO;Sm;0;ON;2225 0338;;;;Y;;;;; 2227;LOGICAL AND;Sm;0;ON;;;;;N;;;;; 2228;LOGICAL OR;Sm;0;ON;;;;;N;;;;; 2229;INTERSECTION;Sm;0;ON;;;;;N;;;;; 222A;UNION;Sm;0;ON;;;;;N;;;;; 222B;INTEGRAL;Sm;0;ON;;;;;Y;;;;; 222C;DOUBLE INTEGRAL;Sm;0;ON; 222B 222B;;;;Y;;;;; 222D;TRIPLE INTEGRAL;Sm;0;ON; 222B 222B 222B;;;;Y;;;;; 222E;CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;; 222F;SURFACE INTEGRAL;Sm;0;ON; 222E 222E;;;;Y;;;;; 2230;VOLUME INTEGRAL;Sm;0;ON; 222E 222E 222E;;;;Y;;;;; 2231;CLOCKWISE INTEGRAL;Sm;0;ON;;;;;Y;;;;; 2232;CLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;; 2233;ANTICLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;; 2234;THEREFORE;Sm;0;ON;;;;;N;;;;; 2235;BECAUSE;Sm;0;ON;;;;;N;;;;; 2236;RATIO;Sm;0;ON;;;;;N;;;;; 2237;PROPORTION;Sm;0;ON;;;;;N;;;;; 2238;DOT MINUS;Sm;0;ON;;;;;N;;;;; 2239;EXCESS;Sm;0;ON;;;;;Y;;;;; 223A;GEOMETRIC PROPORTION;Sm;0;ON;;;;;N;;;;; 223B;HOMOTHETIC;Sm;0;ON;;;;;Y;;;;; 223C;TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; 223D;REVERSED TILDE;Sm;0;ON;;;;;Y;;lazy S;;; 223E;INVERTED LAZY S;Sm;0;ON;;;;;Y;;;;; 223F;SINE WAVE;Sm;0;ON;;;;;Y;;;;; 2240;WREATH PRODUCT;Sm;0;ON;;;;;Y;;;;; 2241;NOT TILDE;Sm;0;ON;223C 0338;;;;Y;;;;; 2242;MINUS TILDE;Sm;0;ON;;;;;Y;;;;; 2243;ASYMPTOTICALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2244;NOT ASYMPTOTICALLY EQUAL TO;Sm;0;ON;2243 0338;;;;Y;;;;; 2245;APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2246;APPROXIMATELY BUT NOT ACTUALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2247;NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO;Sm;0;ON;2245 0338;;;;Y;;;;; 2248;ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2249;NOT ALMOST EQUAL TO;Sm;0;ON;2248 0338;;;;Y;;;;; 224A;ALMOST EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; 224B;TRIPLE TILDE;Sm;0;ON;;;;;Y;;;;; 224C;ALL EQUAL TO;Sm;0;ON;;;;;Y;;;;; 224D;EQUIVALENT TO;Sm;0;ON;;;;;N;;;;; 224E;GEOMETRICALLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;; 224F;DIFFERENCE BETWEEN;Sm;0;ON;;;;;N;;;;; 2250;APPROACHES THE LIMIT;Sm;0;ON;;;;;N;;;;; 2251;GEOMETRICALLY EQUAL TO;Sm;0;ON;;;;;N;;;;; 2252;APPROXIMATELY EQUAL TO OR THE IMAGE OF;Sm;0;ON;;;;;Y;;;;; 2253;IMAGE OF OR APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2254;COLON EQUALS;Sm;0;ON;;;;;Y;COLON EQUAL;;;; 2255;EQUALS COLON;Sm;0;ON;;;;;Y;EQUAL COLON;;;; 2256;RING IN EQUAL TO;Sm;0;ON;;;;;N;;;;; 2257;RING EQUAL TO;Sm;0;ON;;;;;N;;;;; 2258;CORRESPONDS TO;Sm;0;ON;;;;;N;;;;; 2259;ESTIMATES;Sm;0;ON;;;;;N;;;;; 225A;EQUIANGULAR TO;Sm;0;ON;;;;;N;;;;; 225B;STAR EQUALS;Sm;0;ON;;;;;N;;;;; 225C;DELTA EQUAL TO;Sm;0;ON;;;;;N;;;;; 225D;EQUAL TO BY DEFINITION;Sm;0;ON;;;;;N;;;;; 225E;MEASURED BY;Sm;0;ON;;;;;N;;;;; 225F;QUESTIONED EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2260;NOT EQUAL TO;Sm;0;ON;003D 0338;;;;Y;;;;; 2261;IDENTICAL TO;Sm;0;ON;;;;;N;;;;; 2262;NOT IDENTICAL TO;Sm;0;ON;2261 0338;;;;Y;;;;; 2263;STRICTLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;; 2264;LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUAL TO;;;; 2265;GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUAL TO;;;; 2266;LESS-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OVER EQUAL TO;;;; 2267;GREATER-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OVER EQUAL TO;;;; 2268;LESS-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUAL TO;;;; 2269;GREATER-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUAL TO;;;; 226A;MUCH LESS-THAN;Sm;0;ON;;;;;Y;MUCH LESS THAN;;;; 226B;MUCH GREATER-THAN;Sm;0;ON;;;;;Y;MUCH GREATER THAN;;;; 226C;BETWEEN;Sm;0;ON;;;;;N;;;;; 226D;NOT EQUIVALENT TO;Sm;0;ON;224D 0338;;;;N;;;;; 226E;NOT LESS-THAN;Sm;0;ON;003C 0338;;;;Y;NOT LESS THAN;;;; 226F;NOT GREATER-THAN;Sm;0;ON;003E 0338;;;;Y;NOT GREATER THAN;;;; 2270;NEITHER LESS-THAN NOR EQUAL TO;Sm;0;ON;2264 0338;;;;Y;NEITHER LESS THAN NOR EQUAL TO;;;; 2271;NEITHER GREATER-THAN NOR EQUAL TO;Sm;0;ON;2265 0338;;;;Y;NEITHER GREATER THAN NOR EQUAL TO;;;; 2272;LESS-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUIVALENT TO;;;; 2273;GREATER-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUIVALENT TO;;;; 2274;NEITHER LESS-THAN NOR EQUIVALENT TO;Sm;0;ON;2272 0338;;;;Y;NEITHER LESS THAN NOR EQUIVALENT TO;;;; 2275;NEITHER GREATER-THAN NOR EQUIVALENT TO;Sm;0;ON;2273 0338;;;;Y;NEITHER GREATER THAN NOR EQUIVALENT TO;;;; 2276;LESS-THAN OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN OR GREATER THAN;;;; 2277;GREATER-THAN OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN OR LESS THAN;;;; 2278;NEITHER LESS-THAN NOR GREATER-THAN;Sm;0;ON;2276 0338;;;;Y;NEITHER LESS THAN NOR GREATER THAN;;;; 2279;NEITHER GREATER-THAN NOR LESS-THAN;Sm;0;ON;2277 0338;;;;Y;NEITHER GREATER THAN NOR LESS THAN;;;; 227A;PRECEDES;Sm;0;ON;;;;;Y;;;;; 227B;SUCCEEDS;Sm;0;ON;;;;;Y;;;;; 227C;PRECEDES OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; 227D;SUCCEEDS OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; 227E;PRECEDES OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; 227F;SUCCEEDS OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; 2280;DOES NOT PRECEDE;Sm;0;ON;227A 0338;;;;Y;;;;; 2281;DOES NOT SUCCEED;Sm;0;ON;227B 0338;;;;Y;;;;; 2282;SUBSET OF;Sm;0;ON;;;;;Y;;;;; 2283;SUPERSET OF;Sm;0;ON;;;;;Y;;;;; 2284;NOT A SUBSET OF;Sm;0;ON;2282 0338;;;;Y;;;;; 2285;NOT A SUPERSET OF;Sm;0;ON;2283 0338;;;;Y;;;;; 2286;SUBSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2287;SUPERSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2288;NEITHER A SUBSET OF NOR EQUAL TO;Sm;0;ON;2286 0338;;;;Y;;;;; 2289;NEITHER A SUPERSET OF NOR EQUAL TO;Sm;0;ON;2287 0338;;;;Y;;;;; 228A;SUBSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUBSET OF OR NOT EQUAL TO;;;; 228B;SUPERSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUPERSET OF OR NOT EQUAL TO;;;; 228C;MULTISET;Sm;0;ON;;;;;Y;;;;; 228D;MULTISET MULTIPLICATION;Sm;0;ON;;;;;N;;;;; 228E;MULTISET UNION;Sm;0;ON;;;;;N;;;;; 228F;SQUARE IMAGE OF;Sm;0;ON;;;;;Y;;;;; 2290;SQUARE ORIGINAL OF;Sm;0;ON;;;;;Y;;;;; 2291;SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2292;SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2293;SQUARE CAP;Sm;0;ON;;;;;N;;;;; 2294;SQUARE CUP;Sm;0;ON;;;;;N;;;;; 2295;CIRCLED PLUS;Sm;0;ON;;;;;N;;;;; 2296;CIRCLED MINUS;Sm;0;ON;;;;;N;;;;; 2297;CIRCLED TIMES;Sm;0;ON;;;;;N;;;;; 2298;CIRCLED DIVISION SLASH;Sm;0;ON;;;;;Y;;;;; 2299;CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;; 229A;CIRCLED RING OPERATOR;Sm;0;ON;;;;;N;;;;; 229B;CIRCLED ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;; 229C;CIRCLED EQUALS;Sm;0;ON;;;;;N;;;;; 229D;CIRCLED DASH;Sm;0;ON;;;;;N;;;;; 229E;SQUARED PLUS;Sm;0;ON;;;;;N;;;;; 229F;SQUARED MINUS;Sm;0;ON;;;;;N;;;;; 22A0;SQUARED TIMES;Sm;0;ON;;;;;N;;;;; 22A1;SQUARED DOT OPERATOR;Sm;0;ON;;;;;N;;;;; 22A2;RIGHT TACK;Sm;0;ON;;;;;Y;;;;; 22A3;LEFT TACK;Sm;0;ON;;;;;Y;;;;; 22A4;DOWN TACK;Sm;0;ON;;;;;N;;;;; 22A5;UP TACK;Sm;0;ON;;;;;N;;;;; 22A6;ASSERTION;Sm;0;ON;;;;;Y;;;;; 22A7;MODELS;Sm;0;ON;;;;;Y;;;;; 22A8;TRUE;Sm;0;ON;;;;;Y;;;;; 22A9;FORCES;Sm;0;ON;;;;;Y;;;;; 22AA;TRIPLE VERTICAL BAR RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;; 22AB;DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;; 22AC;DOES NOT PROVE;Sm;0;ON;22A2 0338;;;;Y;;;;; 22AD;NOT TRUE;Sm;0;ON;22A8 0338;;;;Y;;;;; 22AE;DOES NOT FORCE;Sm;0;ON;22A9 0338;;;;Y;;;;; 22AF;NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;22AB 0338;;;;Y;;;;; 22B0;PRECEDES UNDER RELATION;Sm;0;ON;;;;;Y;;;;; 22B1;SUCCEEDS UNDER RELATION;Sm;0;ON;;;;;Y;;;;; 22B2;NORMAL SUBGROUP OF;Sm;0;ON;;;;;Y;;;;; 22B3;CONTAINS AS NORMAL SUBGROUP;Sm;0;ON;;;;;Y;;;;; 22B4;NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; 22B5;CONTAINS AS NORMAL SUBGROUP OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; 22B6;ORIGINAL OF;Sm;0;ON;;;;;Y;;;;; 22B7;IMAGE OF;Sm;0;ON;;;;;Y;;;;; 22B8;MULTIMAP;Sm;0;ON;;;;;Y;;;;; 22B9;HERMITIAN CONJUGATE MATRIX;Sm;0;ON;;;;;N;;;;; 22BA;INTERCALATE;Sm;0;ON;;;;;N;;;;; 22BB;XOR;Sm;0;ON;;;;;N;;;;; 22BC;NAND;Sm;0;ON;;;;;N;;;;; 22BD;NOR;Sm;0;ON;;;;;N;;;;; 22BE;RIGHT ANGLE WITH ARC;Sm;0;ON;;;;;Y;;;;; 22BF;RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;; 22C0;N-ARY LOGICAL AND;Sm;0;ON;;;;;N;;;;; 22C1;N-ARY LOGICAL OR;Sm;0;ON;;;;;N;;;;; 22C2;N-ARY INTERSECTION;Sm;0;ON;;;;;N;;;;; 22C3;N-ARY UNION;Sm;0;ON;;;;;N;;;;; 22C4;DIAMOND OPERATOR;Sm;0;ON;;;;;N;;;;; 22C5;DOT OPERATOR;Sm;0;ON;;;;;N;;;;; 22C6;STAR OPERATOR;Sm;0;ON;;;;;N;;;;; 22C7;DIVISION TIMES;Sm;0;ON;;;;;N;;;;; 22C8;BOWTIE;Sm;0;ON;;;;;N;;;;; 22C9;LEFT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; 22CA;RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; 22CB;LEFT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; 22CC;RIGHT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; 22CD;REVERSED TILDE EQUALS;Sm;0;ON;;;;;Y;;;;; 22CE;CURLY LOGICAL OR;Sm;0;ON;;;;;N;;;;; 22CF;CURLY LOGICAL AND;Sm;0;ON;;;;;N;;;;; 22D0;DOUBLE SUBSET;Sm;0;ON;;;;;Y;;;;; 22D1;DOUBLE SUPERSET;Sm;0;ON;;;;;Y;;;;; 22D2;DOUBLE INTERSECTION;Sm;0;ON;;;;;N;;;;; 22D3;DOUBLE UNION;Sm;0;ON;;;;;N;;;;; 22D4;PITCHFORK;Sm;0;ON;;;;;N;;;;; 22D5;EQUAL AND PARALLEL TO;Sm;0;ON;;;;;N;;;;; 22D6;LESS-THAN WITH DOT;Sm;0;ON;;;;;Y;LESS THAN WITH DOT;;;; 22D7;GREATER-THAN WITH DOT;Sm;0;ON;;;;;Y;GREATER THAN WITH DOT;;;; 22D8;VERY MUCH LESS-THAN;Sm;0;ON;;;;;Y;VERY MUCH LESS THAN;;;; 22D9;VERY MUCH GREATER-THAN;Sm;0;ON;;;;;Y;VERY MUCH GREATER THAN;;;; 22DA;LESS-THAN EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN EQUAL TO OR GREATER THAN;;;; 22DB;GREATER-THAN EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN EQUAL TO OR LESS THAN;;;; 22DC;EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR LESS THAN;;;; 22DD;EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR GREATER THAN;;;; 22DE;EQUAL TO OR PRECEDES;Sm;0;ON;;;;;Y;;;;; 22DF;EQUAL TO OR SUCCEEDS;Sm;0;ON;;;;;Y;;;;; 22E0;DOES NOT PRECEDE OR EQUAL;Sm;0;ON;227C 0338;;;;Y;;;;; 22E1;DOES NOT SUCCEED OR EQUAL;Sm;0;ON;227D 0338;;;;Y;;;;; 22E2;NOT SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;2291 0338;;;;Y;;;;; 22E3;NOT SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;2292 0338;;;;Y;;;;; 22E4;SQUARE IMAGE OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; 22E5;SQUARE ORIGINAL OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; 22E6;LESS-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUIVALENT TO;;;; 22E7;GREATER-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUIVALENT TO;;;; 22E8;PRECEDES BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; 22E9;SUCCEEDS BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; 22EA;NOT NORMAL SUBGROUP OF;Sm;0;ON;22B2 0338;;;;Y;;;;; 22EB;DOES NOT CONTAIN AS NORMAL SUBGROUP;Sm;0;ON;22B3 0338;;;;Y;;;;; 22EC;NOT NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;22B4 0338;;;;Y;;;;; 22ED;DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL;Sm;0;ON;22B5 0338;;;;Y;;;;; 22EE;VERTICAL ELLIPSIS;Sm;0;ON;;;;;N;;;;; 22EF;MIDLINE HORIZONTAL ELLIPSIS;Sm;0;ON;;;;;N;;;;; 22F0;UP RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;; 22F1;DOWN RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;; 22F2;ELEMENT OF WITH LONG HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; 22F3;ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; 22F4;SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; 22F5;ELEMENT OF WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; 22F6;ELEMENT OF WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; 22F7;SMALL ELEMENT OF WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; 22F8;ELEMENT OF WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; 22F9;ELEMENT OF WITH TWO HORIZONTAL STROKES;Sm;0;ON;;;;;Y;;;;; 22FA;CONTAINS WITH LONG HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; 22FB;CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; 22FC;SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; 22FD;CONTAINS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; 22FE;SMALL CONTAINS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; 22FF;Z NOTATION BAG MEMBERSHIP;Sm;0;ON;;;;;Y;;;;; 2300;DIAMETER SIGN;So;0;ON;;;;;N;;;;; 2301;ELECTRIC ARROW;So;0;ON;;;;;N;;;;; 2302;HOUSE;So;0;ON;;;;;N;;;;; 2303;UP ARROWHEAD;So;0;ON;;;;;N;;;;; 2304;DOWN ARROWHEAD;So;0;ON;;;;;N;;;;; 2305;PROJECTIVE;So;0;ON;;;;;N;;;;; 2306;PERSPECTIVE;So;0;ON;;;;;N;;;;; 2307;WAVY LINE;So;0;ON;;;;;N;;;;; 2308;LEFT CEILING;Sm;0;ON;;;;;Y;;;;; 2309;RIGHT CEILING;Sm;0;ON;;;;;Y;;;;; 230A;LEFT FLOOR;Sm;0;ON;;;;;Y;;;;; 230B;RIGHT FLOOR;Sm;0;ON;;;;;Y;;;;; 230C;BOTTOM RIGHT CROP;So;0;ON;;;;;N;;;;; 230D;BOTTOM LEFT CROP;So;0;ON;;;;;N;;;;; 230E;TOP RIGHT CROP;So;0;ON;;;;;N;;;;; 230F;TOP LEFT CROP;So;0;ON;;;;;N;;;;; 2310;REVERSED NOT SIGN;So;0;ON;;;;;N;;;;; 2311;SQUARE LOZENGE;So;0;ON;;;;;N;;;;; 2312;ARC;So;0;ON;;;;;N;;;;; 2313;SEGMENT;So;0;ON;;;;;N;;;;; 2314;SECTOR;So;0;ON;;;;;N;;;;; 2315;TELEPHONE RECORDER;So;0;ON;;;;;N;;;;; 2316;POSITION INDICATOR;So;0;ON;;;;;N;;;;; 2317;VIEWDATA SQUARE;So;0;ON;;;;;N;;;;; 2318;PLACE OF INTEREST SIGN;So;0;ON;;;;;N;COMMAND KEY;;;; 2319;TURNED NOT SIGN;So;0;ON;;;;;N;;;;; 231A;WATCH;So;0;ON;;;;;N;;;;; 231B;HOURGLASS;So;0;ON;;;;;N;;;;; 231C;TOP LEFT CORNER;So;0;ON;;;;;N;;;;; 231D;TOP RIGHT CORNER;So;0;ON;;;;;N;;;;; 231E;BOTTOM LEFT CORNER;So;0;ON;;;;;N;;;;; 231F;BOTTOM RIGHT CORNER;So;0;ON;;;;;N;;;;; 2320;TOP HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;; 2321;BOTTOM HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;; 2322;FROWN;So;0;ON;;;;;N;;;;; 2323;SMILE;So;0;ON;;;;;N;;;;; 2324;UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS;So;0;ON;;;;;N;ENTER KEY;;;; 2325;OPTION KEY;So;0;ON;;;;;N;;;;; 2326;ERASE TO THE RIGHT;So;0;ON;;;;;N;DELETE TO THE RIGHT KEY;;;; 2327;X IN A RECTANGLE BOX;So;0;ON;;;;;N;CLEAR KEY;;;; 2328;KEYBOARD;So;0;ON;;;;;N;;;;; 2329;LEFT-POINTING ANGLE BRACKET;Ps;0;ON;3008;;;;Y;BRA;;;; 232A;RIGHT-POINTING ANGLE BRACKET;Pe;0;ON;3009;;;;Y;KET;;;; 232B;ERASE TO THE LEFT;So;0;ON;;;;;N;DELETE TO THE LEFT KEY;;;; 232C;BENZENE RING;So;0;ON;;;;;N;;;;; 232D;CYLINDRICITY;So;0;ON;;;;;N;;;;; 232E;ALL AROUND-PROFILE;So;0;ON;;;;;N;;;;; 232F;SYMMETRY;So;0;ON;;;;;N;;;;; 2330;TOTAL RUNOUT;So;0;ON;;;;;N;;;;; 2331;DIMENSION ORIGIN;So;0;ON;;;;;N;;;;; 2332;CONICAL TAPER;So;0;ON;;;;;N;;;;; 2333;SLOPE;So;0;ON;;;;;N;;;;; 2334;COUNTERBORE;So;0;ON;;;;;N;;;;; 2335;COUNTERSINK;So;0;ON;;;;;N;;;;; 2336;APL FUNCTIONAL SYMBOL I-BEAM;So;0;L;;;;;N;;;;; 2337;APL FUNCTIONAL SYMBOL SQUISH QUAD;So;0;L;;;;;N;;;;; 2338;APL FUNCTIONAL SYMBOL QUAD EQUAL;So;0;L;;;;;N;;;;; 2339;APL FUNCTIONAL SYMBOL QUAD DIVIDE;So;0;L;;;;;N;;;;; 233A;APL FUNCTIONAL SYMBOL QUAD DIAMOND;So;0;L;;;;;N;;;;; 233B;APL FUNCTIONAL SYMBOL QUAD JOT;So;0;L;;;;;N;;;;; 233C;APL FUNCTIONAL SYMBOL QUAD CIRCLE;So;0;L;;;;;N;;;;; 233D;APL FUNCTIONAL SYMBOL CIRCLE STILE;So;0;L;;;;;N;;;;; 233E;APL FUNCTIONAL SYMBOL CIRCLE JOT;So;0;L;;;;;N;;;;; 233F;APL FUNCTIONAL SYMBOL SLASH BAR;So;0;L;;;;;N;;;;; 2340;APL FUNCTIONAL SYMBOL BACKSLASH BAR;So;0;L;;;;;N;;;;; 2341;APL FUNCTIONAL SYMBOL QUAD SLASH;So;0;L;;;;;N;;;;; 2342;APL FUNCTIONAL SYMBOL QUAD BACKSLASH;So;0;L;;;;;N;;;;; 2343;APL FUNCTIONAL SYMBOL QUAD LESS-THAN;So;0;L;;;;;N;;;;; 2344;APL FUNCTIONAL SYMBOL QUAD GREATER-THAN;So;0;L;;;;;N;;;;; 2345;APL FUNCTIONAL SYMBOL LEFTWARDS VANE;So;0;L;;;;;N;;;;; 2346;APL FUNCTIONAL SYMBOL RIGHTWARDS VANE;So;0;L;;;;;N;;;;; 2347;APL FUNCTIONAL SYMBOL QUAD LEFTWARDS ARROW;So;0;L;;;;;N;;;;; 2348;APL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROW;So;0;L;;;;;N;;;;; 2349;APL FUNCTIONAL SYMBOL CIRCLE BACKSLASH;So;0;L;;;;;N;;;;; 234A;APL FUNCTIONAL SYMBOL DOWN TACK UNDERBAR;So;0;L;;;;;N;;*;;; 234B;APL FUNCTIONAL SYMBOL DELTA STILE;So;0;L;;;;;N;;;;; 234C;APL FUNCTIONAL SYMBOL QUAD DOWN CARET;So;0;L;;;;;N;;;;; 234D;APL FUNCTIONAL SYMBOL QUAD DELTA;So;0;L;;;;;N;;;;; 234E;APL FUNCTIONAL SYMBOL DOWN TACK JOT;So;0;L;;;;;N;;*;;; 234F;APL FUNCTIONAL SYMBOL UPWARDS VANE;So;0;L;;;;;N;;;;; 2350;APL FUNCTIONAL SYMBOL QUAD UPWARDS ARROW;So;0;L;;;;;N;;;;; 2351;APL FUNCTIONAL SYMBOL UP TACK OVERBAR;So;0;L;;;;;N;;*;;; 2352;APL FUNCTIONAL SYMBOL DEL STILE;So;0;L;;;;;N;;;;; 2353;APL FUNCTIONAL SYMBOL QUAD UP CARET;So;0;L;;;;;N;;;;; 2354;APL FUNCTIONAL SYMBOL QUAD DEL;So;0;L;;;;;N;;;;; 2355;APL FUNCTIONAL SYMBOL UP TACK JOT;So;0;L;;;;;N;;*;;; 2356;APL FUNCTIONAL SYMBOL DOWNWARDS VANE;So;0;L;;;;;N;;;;; 2357;APL FUNCTIONAL SYMBOL QUAD DOWNWARDS ARROW;So;0;L;;;;;N;;;;; 2358;APL FUNCTIONAL SYMBOL QUOTE UNDERBAR;So;0;L;;;;;N;;;;; 2359;APL FUNCTIONAL SYMBOL DELTA UNDERBAR;So;0;L;;;;;N;;;;; 235A;APL FUNCTIONAL SYMBOL DIAMOND UNDERBAR;So;0;L;;;;;N;;;;; 235B;APL FUNCTIONAL SYMBOL JOT UNDERBAR;So;0;L;;;;;N;;;;; 235C;APL FUNCTIONAL SYMBOL CIRCLE UNDERBAR;So;0;L;;;;;N;;;;; 235D;APL FUNCTIONAL SYMBOL UP SHOE JOT;So;0;L;;;;;N;;;;; 235E;APL FUNCTIONAL SYMBOL QUOTE QUAD;So;0;L;;;;;N;;;;; 235F;APL FUNCTIONAL SYMBOL CIRCLE STAR;So;0;L;;;;;N;;;;; 2360;APL FUNCTIONAL SYMBOL QUAD COLON;So;0;L;;;;;N;;;;; 2361;APL FUNCTIONAL SYMBOL UP TACK DIAERESIS;So;0;L;;;;;N;;*;;; 2362;APL FUNCTIONAL SYMBOL DEL DIAERESIS;So;0;L;;;;;N;;;;; 2363;APL FUNCTIONAL SYMBOL STAR DIAERESIS;So;0;L;;;;;N;;;;; 2364;APL FUNCTIONAL SYMBOL JOT DIAERESIS;So;0;L;;;;;N;;;;; 2365;APL FUNCTIONAL SYMBOL CIRCLE DIAERESIS;So;0;L;;;;;N;;;;; 2366;APL FUNCTIONAL SYMBOL DOWN SHOE STILE;So;0;L;;;;;N;;;;; 2367;APL FUNCTIONAL SYMBOL LEFT SHOE STILE;So;0;L;;;;;N;;;;; 2368;APL FUNCTIONAL SYMBOL TILDE DIAERESIS;So;0;L;;;;;N;;;;; 2369;APL FUNCTIONAL SYMBOL GREATER-THAN DIAERESIS;So;0;L;;;;;N;;;;; 236A;APL FUNCTIONAL SYMBOL COMMA BAR;So;0;L;;;;;N;;;;; 236B;APL FUNCTIONAL SYMBOL DEL TILDE;So;0;L;;;;;N;;;;; 236C;APL FUNCTIONAL SYMBOL ZILDE;So;0;L;;;;;N;;;;; 236D;APL FUNCTIONAL SYMBOL STILE TILDE;So;0;L;;;;;N;;;;; 236E;APL FUNCTIONAL SYMBOL SEMICOLON UNDERBAR;So;0;L;;;;;N;;;;; 236F;APL FUNCTIONAL SYMBOL QUAD NOT EQUAL;So;0;L;;;;;N;;;;; 2370;APL FUNCTIONAL SYMBOL QUAD QUESTION;So;0;L;;;;;N;;;;; 2371;APL FUNCTIONAL SYMBOL DOWN CARET TILDE;So;0;L;;;;;N;;;;; 2372;APL FUNCTIONAL SYMBOL UP CARET TILDE;So;0;L;;;;;N;;;;; 2373;APL FUNCTIONAL SYMBOL IOTA;So;0;L;;;;;N;;;;; 2374;APL FUNCTIONAL SYMBOL RHO;So;0;L;;;;;N;;;;; 2375;APL FUNCTIONAL SYMBOL OMEGA;So;0;L;;;;;N;;;;; 2376;APL FUNCTIONAL SYMBOL ALPHA UNDERBAR;So;0;L;;;;;N;;;;; 2377;APL FUNCTIONAL SYMBOL EPSILON UNDERBAR;So;0;L;;;;;N;;;;; 2378;APL FUNCTIONAL SYMBOL IOTA UNDERBAR;So;0;L;;;;;N;;;;; 2379;APL FUNCTIONAL SYMBOL OMEGA UNDERBAR;So;0;L;;;;;N;;;;; 237A;APL FUNCTIONAL SYMBOL ALPHA;So;0;L;;;;;N;;;;; 237B;NOT CHECK MARK;So;0;ON;;;;;N;;;;; 237C;RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW;Sm;0;ON;;;;;N;;;;; 237D;SHOULDERED OPEN BOX;So;0;ON;;;;;N;;;;; 237E;BELL SYMBOL;So;0;ON;;;;;N;;;;; 237F;VERTICAL LINE WITH MIDDLE DOT;So;0;ON;;;;;N;;;;; 2380;INSERTION SYMBOL;So;0;ON;;;;;N;;;;; 2381;CONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;; 2382;DISCONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;; 2383;EMPHASIS SYMBOL;So;0;ON;;;;;N;;;;; 2384;COMPOSITION SYMBOL;So;0;ON;;;;;N;;;;; 2385;WHITE SQUARE WITH CENTRE VERTICAL LINE;So;0;ON;;;;;N;;;;; 2386;ENTER SYMBOL;So;0;ON;;;;;N;;;;; 2387;ALTERNATIVE KEY SYMBOL;So;0;ON;;;;;N;;;;; 2388;HELM SYMBOL;So;0;ON;;;;;N;;;;; 2389;CIRCLED HORIZONTAL BAR WITH NOTCH;So;0;ON;;;;;N;;pause;;; 238A;CIRCLED TRIANGLE DOWN;So;0;ON;;;;;N;;break;;; 238B;BROKEN CIRCLE WITH NORTHWEST ARROW;So;0;ON;;;;;N;;escape;;; 238C;UNDO SYMBOL;So;0;ON;;;;;N;;;;; 238D;MONOSTABLE SYMBOL;So;0;ON;;;;;N;;;;; 238E;HYSTERESIS SYMBOL;So;0;ON;;;;;N;;;;; 238F;OPEN-CIRCUIT-OUTPUT H-TYPE SYMBOL;So;0;ON;;;;;N;;;;; 2390;OPEN-CIRCUIT-OUTPUT L-TYPE SYMBOL;So;0;ON;;;;;N;;;;; 2391;PASSIVE-PULL-DOWN-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;; 2392;PASSIVE-PULL-UP-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;; 2393;DIRECT CURRENT SYMBOL FORM TWO;So;0;ON;;;;;N;;;;; 2394;SOFTWARE-FUNCTION SYMBOL;So;0;ON;;;;;N;;;;; 2395;APL FUNCTIONAL SYMBOL QUAD;So;0;L;;;;;N;;;;; 2396;DECIMAL SEPARATOR KEY SYMBOL;So;0;ON;;;;;N;;;;; 2397;PREVIOUS PAGE;So;0;ON;;;;;N;;;;; 2398;NEXT PAGE;So;0;ON;;;;;N;;;;; 2399;PRINT SCREEN SYMBOL;So;0;ON;;;;;N;;;;; 239A;CLEAR SCREEN SYMBOL;So;0;ON;;;;;N;;;;; 239B;LEFT PARENTHESIS UPPER HOOK;Sm;0;ON;;;;;N;;;;; 239C;LEFT PARENTHESIS EXTENSION;Sm;0;ON;;;;;N;;;;; 239D;LEFT PARENTHESIS LOWER HOOK;Sm;0;ON;;;;;N;;;;; 239E;RIGHT PARENTHESIS UPPER HOOK;Sm;0;ON;;;;;N;;;;; 239F;RIGHT PARENTHESIS EXTENSION;Sm;0;ON;;;;;N;;;;; 23A0;RIGHT PARENTHESIS LOWER HOOK;Sm;0;ON;;;;;N;;;;; 23A1;LEFT SQUARE BRACKET UPPER CORNER;Sm;0;ON;;;;;N;;;;; 23A2;LEFT SQUARE BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;; 23A3;LEFT SQUARE BRACKET LOWER CORNER;Sm;0;ON;;;;;N;;;;; 23A4;RIGHT SQUARE BRACKET UPPER CORNER;Sm;0;ON;;;;;N;;;;; 23A5;RIGHT SQUARE BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;; 23A6;RIGHT SQUARE BRACKET LOWER CORNER;Sm;0;ON;;;;;N;;;;; 23A7;LEFT CURLY BRACKET UPPER HOOK;Sm;0;ON;;;;;N;;;;; 23A8;LEFT CURLY BRACKET MIDDLE PIECE;Sm;0;ON;;;;;N;;;;; 23A9;LEFT CURLY BRACKET LOWER HOOK;Sm;0;ON;;;;;N;;;;; 23AA;CURLY BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;; 23AB;RIGHT CURLY BRACKET UPPER HOOK;Sm;0;ON;;;;;N;;;;; 23AC;RIGHT CURLY BRACKET MIDDLE PIECE;Sm;0;ON;;;;;N;;;;; 23AD;RIGHT CURLY BRACKET LOWER HOOK;Sm;0;ON;;;;;N;;;;; 23AE;INTEGRAL EXTENSION;Sm;0;ON;;;;;N;;;;; 23AF;HORIZONTAL LINE EXTENSION;Sm;0;ON;;;;;N;;;;; 23B0;UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;; 23B1;UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;; 23B2;SUMMATION TOP;Sm;0;ON;;;;;N;;;;; 23B3;SUMMATION BOTTOM;Sm;0;ON;;;;;N;;;;; 23B4;TOP SQUARE BRACKET;Ps;0;ON;;;;;N;;;;; 23B5;BOTTOM SQUARE BRACKET;Pe;0;ON;;;;;N;;;;; 23B6;BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET;Po;0;ON;;;;;N;;;;; 23B7;RADICAL SYMBOL BOTTOM;So;0;ON;;;;;N;;;;; 23B8;LEFT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;; 23B9;RIGHT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;; 23BA;HORIZONTAL SCAN LINE-1;So;0;ON;;;;;N;;;;; 23BB;HORIZONTAL SCAN LINE-3;So;0;ON;;;;;N;;;;; 23BC;HORIZONTAL SCAN LINE-7;So;0;ON;;;;;N;;;;; 23BD;HORIZONTAL SCAN LINE-9;So;0;ON;;;;;N;;;;; 23BE;DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT;So;0;ON;;;;;N;;;;; 23BF;DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT;So;0;ON;;;;;N;;;;; 23C0;DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE;So;0;ON;;;;;N;;;;; 23C1;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE;So;0;ON;;;;;N;;;;; 23C2;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE;So;0;ON;;;;;N;;;;; 23C3;DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE;So;0;ON;;;;;N;;;;; 23C4;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE;So;0;ON;;;;;N;;;;; 23C5;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE;So;0;ON;;;;;N;;;;; 23C6;DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE;So;0;ON;;;;;N;;;;; 23C7;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE;So;0;ON;;;;;N;;;;; 23C8;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE;So;0;ON;;;;;N;;;;; 23C9;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;;;;; 23CA;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;;;;; 23CB;DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT;So;0;ON;;;;;N;;;;; 23CC;DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT;So;0;ON;;;;;N;;;;; 23CD;SQUARE FOOT;So;0;ON;;;;;N;;;;; 23CE;RETURN SYMBOL;So;0;ON;;;;;N;;;;; 2400;SYMBOL FOR NULL;So;0;ON;;;;;N;GRAPHIC FOR NULL;;;; 2401;SYMBOL FOR START OF HEADING;So;0;ON;;;;;N;GRAPHIC FOR START OF HEADING;;;; 2402;SYMBOL FOR START OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR START OF TEXT;;;; 2403;SYMBOL FOR END OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR END OF TEXT;;;; 2404;SYMBOL FOR END OF TRANSMISSION;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION;;;; 2405;SYMBOL FOR ENQUIRY;So;0;ON;;;;;N;GRAPHIC FOR ENQUIRY;;;; 2406;SYMBOL FOR ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR ACKNOWLEDGE;;;; 2407;SYMBOL FOR BELL;So;0;ON;;;;;N;GRAPHIC FOR BELL;;;; 2408;SYMBOL FOR BACKSPACE;So;0;ON;;;;;N;GRAPHIC FOR BACKSPACE;;;; 2409;SYMBOL FOR HORIZONTAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR HORIZONTAL TABULATION;;;; 240A;SYMBOL FOR LINE FEED;So;0;ON;;;;;N;GRAPHIC FOR LINE FEED;;;; 240B;SYMBOL FOR VERTICAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR VERTICAL TABULATION;;;; 240C;SYMBOL FOR FORM FEED;So;0;ON;;;;;N;GRAPHIC FOR FORM FEED;;;; 240D;SYMBOL FOR CARRIAGE RETURN;So;0;ON;;;;;N;GRAPHIC FOR CARRIAGE RETURN;;;; 240E;SYMBOL FOR SHIFT OUT;So;0;ON;;;;;N;GRAPHIC FOR SHIFT OUT;;;; 240F;SYMBOL FOR SHIFT IN;So;0;ON;;;;;N;GRAPHIC FOR SHIFT IN;;;; 2410;SYMBOL FOR DATA LINK ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR DATA LINK ESCAPE;;;; 2411;SYMBOL FOR DEVICE CONTROL ONE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL ONE;;;; 2412;SYMBOL FOR DEVICE CONTROL TWO;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL TWO;;;; 2413;SYMBOL FOR DEVICE CONTROL THREE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL THREE;;;; 2414;SYMBOL FOR DEVICE CONTROL FOUR;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL FOUR;;;; 2415;SYMBOL FOR NEGATIVE ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR NEGATIVE ACKNOWLEDGE;;;; 2416;SYMBOL FOR SYNCHRONOUS IDLE;So;0;ON;;;;;N;GRAPHIC FOR SYNCHRONOUS IDLE;;;; 2417;SYMBOL FOR END OF TRANSMISSION BLOCK;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION BLOCK;;;; 2418;SYMBOL FOR CANCEL;So;0;ON;;;;;N;GRAPHIC FOR CANCEL;;;; 2419;SYMBOL FOR END OF MEDIUM;So;0;ON;;;;;N;GRAPHIC FOR END OF MEDIUM;;;; 241A;SYMBOL FOR SUBSTITUTE;So;0;ON;;;;;N;GRAPHIC FOR SUBSTITUTE;;;; 241B;SYMBOL FOR ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR ESCAPE;;;; 241C;SYMBOL FOR FILE SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR FILE SEPARATOR;;;; 241D;SYMBOL FOR GROUP SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR GROUP SEPARATOR;;;; 241E;SYMBOL FOR RECORD SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR RECORD SEPARATOR;;;; 241F;SYMBOL FOR UNIT SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR UNIT SEPARATOR;;;; 2420;SYMBOL FOR SPACE;So;0;ON;;;;;N;GRAPHIC FOR SPACE;;;; 2421;SYMBOL FOR DELETE;So;0;ON;;;;;N;GRAPHIC FOR DELETE;;;; 2422;BLANK SYMBOL;So;0;ON;;;;;N;BLANK;;;; 2423;OPEN BOX;So;0;ON;;;;;N;;;;; 2424;SYMBOL FOR NEWLINE;So;0;ON;;;;;N;GRAPHIC FOR NEWLINE;;;; 2425;SYMBOL FOR DELETE FORM TWO;So;0;ON;;;;;N;;;;; 2426;SYMBOL FOR SUBSTITUTE FORM TWO;So;0;ON;;;;;N;;;;; 2440;OCR HOOK;So;0;ON;;;;;N;;;;; 2441;OCR CHAIR;So;0;ON;;;;;N;;;;; 2442;OCR FORK;So;0;ON;;;;;N;;;;; 2443;OCR INVERTED FORK;So;0;ON;;;;;N;;;;; 2444;OCR BELT BUCKLE;So;0;ON;;;;;N;;;;; 2445;OCR BOW TIE;So;0;ON;;;;;N;;;;; 2446;OCR BRANCH BANK IDENTIFICATION;So;0;ON;;;;;N;;;;; 2447;OCR AMOUNT OF CHECK;So;0;ON;;;;;N;;;;; 2448;OCR DASH;So;0;ON;;;;;N;;;;; 2449;OCR CUSTOMER ACCOUNT NUMBER;So;0;ON;;;;;N;;;;; 244A;OCR DOUBLE BACKSLASH;So;0;ON;;;;;N;;;;; 2460;CIRCLED DIGIT ONE;No;0;EN; 0031;;1;1;N;;;;; 2461;CIRCLED DIGIT TWO;No;0;EN; 0032;;2;2;N;;;;; 2462;CIRCLED DIGIT THREE;No;0;EN; 0033;;3;3;N;;;;; 2463;CIRCLED DIGIT FOUR;No;0;EN; 0034;;4;4;N;;;;; 2464;CIRCLED DIGIT FIVE;No;0;EN; 0035;;5;5;N;;;;; 2465;CIRCLED DIGIT SIX;No;0;EN; 0036;;6;6;N;;;;; 2466;CIRCLED DIGIT SEVEN;No;0;EN; 0037;;7;7;N;;;;; 2467;CIRCLED DIGIT EIGHT;No;0;EN; 0038;;8;8;N;;;;; 2468;CIRCLED DIGIT NINE;No;0;EN; 0039;;9;9;N;;;;; 2469;CIRCLED NUMBER TEN;No;0;EN; 0031 0030;;;10;N;;;;; 246A;CIRCLED NUMBER ELEVEN;No;0;EN; 0031 0031;;;11;N;;;;; 246B;CIRCLED NUMBER TWELVE;No;0;EN; 0031 0032;;;12;N;;;;; 246C;CIRCLED NUMBER THIRTEEN;No;0;EN; 0031 0033;;;13;N;;;;; 246D;CIRCLED NUMBER FOURTEEN;No;0;EN; 0031 0034;;;14;N;;;;; 246E;CIRCLED NUMBER FIFTEEN;No;0;EN; 0031 0035;;;15;N;;;;; 246F;CIRCLED NUMBER SIXTEEN;No;0;EN; 0031 0036;;;16;N;;;;; 2470;CIRCLED NUMBER SEVENTEEN;No;0;EN; 0031 0037;;;17;N;;;;; 2471;CIRCLED NUMBER EIGHTEEN;No;0;EN; 0031 0038;;;18;N;;;;; 2472;CIRCLED NUMBER NINETEEN;No;0;EN; 0031 0039;;;19;N;;;;; 2473;CIRCLED NUMBER TWENTY;No;0;EN; 0032 0030;;;20;N;;;;; 2474;PARENTHESIZED DIGIT ONE;No;0;EN; 0028 0031 0029;;1;1;N;;;;; 2475;PARENTHESIZED DIGIT TWO;No;0;EN; 0028 0032 0029;;2;2;N;;;;; 2476;PARENTHESIZED DIGIT THREE;No;0;EN; 0028 0033 0029;;3;3;N;;;;; 2477;PARENTHESIZED DIGIT FOUR;No;0;EN; 0028 0034 0029;;4;4;N;;;;; 2478;PARENTHESIZED DIGIT FIVE;No;0;EN; 0028 0035 0029;;5;5;N;;;;; 2479;PARENTHESIZED DIGIT SIX;No;0;EN; 0028 0036 0029;;6;6;N;;;;; 247A;PARENTHESIZED DIGIT SEVEN;No;0;EN; 0028 0037 0029;;7;7;N;;;;; 247B;PARENTHESIZED DIGIT EIGHT;No;0;EN; 0028 0038 0029;;8;8;N;;;;; 247C;PARENTHESIZED DIGIT NINE;No;0;EN; 0028 0039 0029;;9;9;N;;;;; 247D;PARENTHESIZED NUMBER TEN;No;0;EN; 0028 0031 0030 0029;;;10;N;;;;; 247E;PARENTHESIZED NUMBER ELEVEN;No;0;EN; 0028 0031 0031 0029;;;11;N;;;;; 247F;PARENTHESIZED NUMBER TWELVE;No;0;EN; 0028 0031 0032 0029;;;12;N;;;;; 2480;PARENTHESIZED NUMBER THIRTEEN;No;0;EN; 0028 0031 0033 0029;;;13;N;;;;; 2481;PARENTHESIZED NUMBER FOURTEEN;No;0;EN; 0028 0031 0034 0029;;;14;N;;;;; 2482;PARENTHESIZED NUMBER FIFTEEN;No;0;EN; 0028 0031 0035 0029;;;15;N;;;;; 2483;PARENTHESIZED NUMBER SIXTEEN;No;0;EN; 0028 0031 0036 0029;;;16;N;;;;; 2484;PARENTHESIZED NUMBER SEVENTEEN;No;0;EN; 0028 0031 0037 0029;;;17;N;;;;; 2485;PARENTHESIZED NUMBER EIGHTEEN;No;0;EN; 0028 0031 0038 0029;;;18;N;;;;; 2486;PARENTHESIZED NUMBER NINETEEN;No;0;EN; 0028 0031 0039 0029;;;19;N;;;;; 2487;PARENTHESIZED NUMBER TWENTY;No;0;EN; 0028 0032 0030 0029;;;20;N;;;;; 2488;DIGIT ONE FULL STOP;No;0;EN; 0031 002E;;1;1;N;DIGIT ONE PERIOD;;;; 2489;DIGIT TWO FULL STOP;No;0;EN; 0032 002E;;2;2;N;DIGIT TWO PERIOD;;;; 248A;DIGIT THREE FULL STOP;No;0;EN; 0033 002E;;3;3;N;DIGIT THREE PERIOD;;;; 248B;DIGIT FOUR FULL STOP;No;0;EN; 0034 002E;;4;4;N;DIGIT FOUR PERIOD;;;; 248C;DIGIT FIVE FULL STOP;No;0;EN; 0035 002E;;5;5;N;DIGIT FIVE PERIOD;;;; 248D;DIGIT SIX FULL STOP;No;0;EN; 0036 002E;;6;6;N;DIGIT SIX PERIOD;;;; 248E;DIGIT SEVEN FULL STOP;No;0;EN; 0037 002E;;7;7;N;DIGIT SEVEN PERIOD;;;; 248F;DIGIT EIGHT FULL STOP;No;0;EN; 0038 002E;;8;8;N;DIGIT EIGHT PERIOD;;;; 2490;DIGIT NINE FULL STOP;No;0;EN; 0039 002E;;9;9;N;DIGIT NINE PERIOD;;;; 2491;NUMBER TEN FULL STOP;No;0;EN; 0031 0030 002E;;;10;N;NUMBER TEN PERIOD;;;; 2492;NUMBER ELEVEN FULL STOP;No;0;EN; 0031 0031 002E;;;11;N;NUMBER ELEVEN PERIOD;;;; 2493;NUMBER TWELVE FULL STOP;No;0;EN; 0031 0032 002E;;;12;N;NUMBER TWELVE PERIOD;;;; 2494;NUMBER THIRTEEN FULL STOP;No;0;EN; 0031 0033 002E;;;13;N;NUMBER THIRTEEN PERIOD;;;; 2495;NUMBER FOURTEEN FULL STOP;No;0;EN; 0031 0034 002E;;;14;N;NUMBER FOURTEEN PERIOD;;;; 2496;NUMBER FIFTEEN FULL STOP;No;0;EN; 0031 0035 002E;;;15;N;NUMBER FIFTEEN PERIOD;;;; 2497;NUMBER SIXTEEN FULL STOP;No;0;EN; 0031 0036 002E;;;16;N;NUMBER SIXTEEN PERIOD;;;; 2498;NUMBER SEVENTEEN FULL STOP;No;0;EN; 0031 0037 002E;;;17;N;NUMBER SEVENTEEN PERIOD;;;; 2499;NUMBER EIGHTEEN FULL STOP;No;0;EN; 0031 0038 002E;;;18;N;NUMBER EIGHTEEN PERIOD;;;; 249A;NUMBER NINETEEN FULL STOP;No;0;EN; 0031 0039 002E;;;19;N;NUMBER NINETEEN PERIOD;;;; 249B;NUMBER TWENTY FULL STOP;No;0;EN; 0032 0030 002E;;;20;N;NUMBER TWENTY PERIOD;;;; 249C;PARENTHESIZED LATIN SMALL LETTER A;So;0;L; 0028 0061 0029;;;;N;;;;; 249D;PARENTHESIZED LATIN SMALL LETTER B;So;0;L; 0028 0062 0029;;;;N;;;;; 249E;PARENTHESIZED LATIN SMALL LETTER C;So;0;L; 0028 0063 0029;;;;N;;;;; 249F;PARENTHESIZED LATIN SMALL LETTER D;So;0;L; 0028 0064 0029;;;;N;;;;; 24A0;PARENTHESIZED LATIN SMALL LETTER E;So;0;L; 0028 0065 0029;;;;N;;;;; 24A1;PARENTHESIZED LATIN SMALL LETTER F;So;0;L; 0028 0066 0029;;;;N;;;;; 24A2;PARENTHESIZED LATIN SMALL LETTER G;So;0;L; 0028 0067 0029;;;;N;;;;; 24A3;PARENTHESIZED LATIN SMALL LETTER H;So;0;L; 0028 0068 0029;;;;N;;;;; 24A4;PARENTHESIZED LATIN SMALL LETTER I;So;0;L; 0028 0069 0029;;;;N;;;;; 24A5;PARENTHESIZED LATIN SMALL LETTER J;So;0;L; 0028 006A 0029;;;;N;;;;; 24A6;PARENTHESIZED LATIN SMALL LETTER K;So;0;L; 0028 006B 0029;;;;N;;;;; 24A7;PARENTHESIZED LATIN SMALL LETTER L;So;0;L; 0028 006C 0029;;;;N;;;;; 24A8;PARENTHESIZED LATIN SMALL LETTER M;So;0;L; 0028 006D 0029;;;;N;;;;; 24A9;PARENTHESIZED LATIN SMALL LETTER N;So;0;L; 0028 006E 0029;;;;N;;;;; 24AA;PARENTHESIZED LATIN SMALL LETTER O;So;0;L; 0028 006F 0029;;;;N;;;;; 24AB;PARENTHESIZED LATIN SMALL LETTER P;So;0;L; 0028 0070 0029;;;;N;;;;; 24AC;PARENTHESIZED LATIN SMALL LETTER Q;So;0;L; 0028 0071 0029;;;;N;;;;; 24AD;PARENTHESIZED LATIN SMALL LETTER R;So;0;L; 0028 0072 0029;;;;N;;;;; 24AE;PARENTHESIZED LATIN SMALL LETTER S;So;0;L; 0028 0073 0029;;;;N;;;;; 24AF;PARENTHESIZED LATIN SMALL LETTER T;So;0;L; 0028 0074 0029;;;;N;;;;; 24B0;PARENTHESIZED LATIN SMALL LETTER U;So;0;L; 0028 0075 0029;;;;N;;;;; 24B1;PARENTHESIZED LATIN SMALL LETTER V;So;0;L; 0028 0076 0029;;;;N;;;;; 24B2;PARENTHESIZED LATIN SMALL LETTER W;So;0;L; 0028 0077 0029;;;;N;;;;; 24B3;PARENTHESIZED LATIN SMALL LETTER X;So;0;L; 0028 0078 0029;;;;N;;;;; 24B4;PARENTHESIZED LATIN SMALL LETTER Y;So;0;L; 0028 0079 0029;;;;N;;;;; 24B5;PARENTHESIZED LATIN SMALL LETTER Z;So;0;L; 0028 007A 0029;;;;N;;;;; 24B6;CIRCLED LATIN CAPITAL LETTER A;So;0;L; 0041;;;;N;;;;24D0; 24B7;CIRCLED LATIN CAPITAL LETTER B;So;0;L; 0042;;;;N;;;;24D1; 24B8;CIRCLED LATIN CAPITAL LETTER C;So;0;L; 0043;;;;N;;;;24D2; 24B9;CIRCLED LATIN CAPITAL LETTER D;So;0;L; 0044;;;;N;;;;24D3; 24BA;CIRCLED LATIN CAPITAL LETTER E;So;0;L; 0045;;;;N;;;;24D4; 24BB;CIRCLED LATIN CAPITAL LETTER F;So;0;L; 0046;;;;N;;;;24D5; 24BC;CIRCLED LATIN CAPITAL LETTER G;So;0;L; 0047;;;;N;;;;24D6; 24BD;CIRCLED LATIN CAPITAL LETTER H;So;0;L; 0048;;;;N;;;;24D7; 24BE;CIRCLED LATIN CAPITAL LETTER I;So;0;L; 0049;;;;N;;;;24D8; 24BF;CIRCLED LATIN CAPITAL LETTER J;So;0;L; 004A;;;;N;;;;24D9; 24C0;CIRCLED LATIN CAPITAL LETTER K;So;0;L; 004B;;;;N;;;;24DA; 24C1;CIRCLED LATIN CAPITAL LETTER L;So;0;L; 004C;;;;N;;;;24DB; 24C2;CIRCLED LATIN CAPITAL LETTER M;So;0;L; 004D;;;;N;;;;24DC; 24C3;CIRCLED LATIN CAPITAL LETTER N;So;0;L; 004E;;;;N;;;;24DD; 24C4;CIRCLED LATIN CAPITAL LETTER O;So;0;L; 004F;;;;N;;;;24DE; 24C5;CIRCLED LATIN CAPITAL LETTER P;So;0;L; 0050;;;;N;;;;24DF; 24C6;CIRCLED LATIN CAPITAL LETTER Q;So;0;L; 0051;;;;N;;;;24E0; 24C7;CIRCLED LATIN CAPITAL LETTER R;So;0;L; 0052;;;;N;;;;24E1; 24C8;CIRCLED LATIN CAPITAL LETTER S;So;0;L; 0053;;;;N;;;;24E2; 24C9;CIRCLED LATIN CAPITAL LETTER T;So;0;L; 0054;;;;N;;;;24E3; 24CA;CIRCLED LATIN CAPITAL LETTER U;So;0;L; 0055;;;;N;;;;24E4; 24CB;CIRCLED LATIN CAPITAL LETTER V;So;0;L; 0056;;;;N;;;;24E5; 24CC;CIRCLED LATIN CAPITAL LETTER W;So;0;L; 0057;;;;N;;;;24E6; 24CD;CIRCLED LATIN CAPITAL LETTER X;So;0;L; 0058;;;;N;;;;24E7; 24CE;CIRCLED LATIN CAPITAL LETTER Y;So;0;L; 0059;;;;N;;;;24E8; 24CF;CIRCLED LATIN CAPITAL LETTER Z;So;0;L; 005A;;;;N;;;;24E9; 24D0;CIRCLED LATIN SMALL LETTER A;So;0;L; 0061;;;;N;;;24B6;;24B6 24D1;CIRCLED LATIN SMALL LETTER B;So;0;L; 0062;;;;N;;;24B7;;24B7 24D2;CIRCLED LATIN SMALL LETTER C;So;0;L; 0063;;;;N;;;24B8;;24B8 24D3;CIRCLED LATIN SMALL LETTER D;So;0;L; 0064;;;;N;;;24B9;;24B9 24D4;CIRCLED LATIN SMALL LETTER E;So;0;L; 0065;;;;N;;;24BA;;24BA 24D5;CIRCLED LATIN SMALL LETTER F;So;0;L; 0066;;;;N;;;24BB;;24BB 24D6;CIRCLED LATIN SMALL LETTER G;So;0;L; 0067;;;;N;;;24BC;;24BC 24D7;CIRCLED LATIN SMALL LETTER H;So;0;L; 0068;;;;N;;;24BD;;24BD 24D8;CIRCLED LATIN SMALL LETTER I;So;0;L; 0069;;;;N;;;24BE;;24BE 24D9;CIRCLED LATIN SMALL LETTER J;So;0;L; 006A;;;;N;;;24BF;;24BF 24DA;CIRCLED LATIN SMALL LETTER K;So;0;L; 006B;;;;N;;;24C0;;24C0 24DB;CIRCLED LATIN SMALL LETTER L;So;0;L; 006C;;;;N;;;24C1;;24C1 24DC;CIRCLED LATIN SMALL LETTER M;So;0;L; 006D;;;;N;;;24C2;;24C2 24DD;CIRCLED LATIN SMALL LETTER N;So;0;L; 006E;;;;N;;;24C3;;24C3 24DE;CIRCLED LATIN SMALL LETTER O;So;0;L; 006F;;;;N;;;24C4;;24C4 24DF;CIRCLED LATIN SMALL LETTER P;So;0;L; 0070;;;;N;;;24C5;;24C5 24E0;CIRCLED LATIN SMALL LETTER Q;So;0;L; 0071;;;;N;;;24C6;;24C6 24E1;CIRCLED LATIN SMALL LETTER R;So;0;L; 0072;;;;N;;;24C7;;24C7 24E2;CIRCLED LATIN SMALL LETTER S;So;0;L; 0073;;;;N;;;24C8;;24C8 24E3;CIRCLED LATIN SMALL LETTER T;So;0;L; 0074;;;;N;;;24C9;;24C9 24E4;CIRCLED LATIN SMALL LETTER U;So;0;L; 0075;;;;N;;;24CA;;24CA 24E5;CIRCLED LATIN SMALL LETTER V;So;0;L; 0076;;;;N;;;24CB;;24CB 24E6;CIRCLED LATIN SMALL LETTER W;So;0;L; 0077;;;;N;;;24CC;;24CC 24E7;CIRCLED LATIN SMALL LETTER X;So;0;L; 0078;;;;N;;;24CD;;24CD 24E8;CIRCLED LATIN SMALL LETTER Y;So;0;L; 0079;;;;N;;;24CE;;24CE 24E9;CIRCLED LATIN SMALL LETTER Z;So;0;L; 007A;;;;N;;;24CF;;24CF 24EA;CIRCLED DIGIT ZERO;No;0;EN; 0030;;0;0;N;;;;; 24EB;NEGATIVE CIRCLED NUMBER ELEVEN;No;0;ON;;;;11;N;;;;; 24EC;NEGATIVE CIRCLED NUMBER TWELVE;No;0;ON;;;;12;N;;;;; 24ED;NEGATIVE CIRCLED NUMBER THIRTEEN;No;0;ON;;;;13;N;;;;; 24EE;NEGATIVE CIRCLED NUMBER FOURTEEN;No;0;ON;;;;14;N;;;;; 24EF;NEGATIVE CIRCLED NUMBER FIFTEEN;No;0;ON;;;;15;N;;;;; 24F0;NEGATIVE CIRCLED NUMBER SIXTEEN;No;0;ON;;;;16;N;;;;; 24F1;NEGATIVE CIRCLED NUMBER SEVENTEEN;No;0;ON;;;;17;N;;;;; 24F2;NEGATIVE CIRCLED NUMBER EIGHTEEN;No;0;ON;;;;18;N;;;;; 24F3;NEGATIVE CIRCLED NUMBER NINETEEN;No;0;ON;;;;19;N;;;;; 24F4;NEGATIVE CIRCLED NUMBER TWENTY;No;0;ON;;;;20;N;;;;; 24F5;DOUBLE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;;;;; 24F6;DOUBLE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;;;;; 24F7;DOUBLE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;;;;; 24F8;DOUBLE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;;;;; 24F9;DOUBLE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;;;;; 24FA;DOUBLE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;;;;; 24FB;DOUBLE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;;;;; 24FC;DOUBLE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;;;;; 24FD;DOUBLE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;;;;; 24FE;DOUBLE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;;;;; 2500;BOX DRAWINGS LIGHT HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT HORIZONTAL;;;; 2501;BOX DRAWINGS HEAVY HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY HORIZONTAL;;;; 2502;BOX DRAWINGS LIGHT VERTICAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL;;;; 2503;BOX DRAWINGS HEAVY VERTICAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL;;;; 2504;BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH HORIZONTAL;;;; 2505;BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH HORIZONTAL;;;; 2506;BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH VERTICAL;;;; 2507;BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH VERTICAL;;;; 2508;BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH HORIZONTAL;;;; 2509;BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH HORIZONTAL;;;; 250A;BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH VERTICAL;;;; 250B;BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH VERTICAL;;;; 250C;BOX DRAWINGS LIGHT DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND RIGHT;;;; 250D;BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT HEAVY;;;; 250E;BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT LIGHT;;;; 250F;BOX DRAWINGS HEAVY DOWN AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND RIGHT;;;; 2510;BOX DRAWINGS LIGHT DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND LEFT;;;; 2511;BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT HEAVY;;;; 2512;BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT LIGHT;;;; 2513;BOX DRAWINGS HEAVY DOWN AND LEFT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND LEFT;;;; 2514;BOX DRAWINGS LIGHT UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT UP AND RIGHT;;;; 2515;BOX DRAWINGS UP LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT HEAVY;;;; 2516;BOX DRAWINGS UP HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT LIGHT;;;; 2517;BOX DRAWINGS HEAVY UP AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY UP AND RIGHT;;;; 2518;BOX DRAWINGS LIGHT UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT UP AND LEFT;;;; 2519;BOX DRAWINGS UP LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT HEAVY;;;; 251A;BOX DRAWINGS UP HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT LIGHT;;;; 251B;BOX DRAWINGS HEAVY UP AND LEFT;So;0;ON;;;;;N;FORMS HEAVY UP AND LEFT;;;; 251C;BOX DRAWINGS LIGHT VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND RIGHT;;;; 251D;BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND RIGHT HEAVY;;;; 251E;BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT DOWN LIGHT;;;; 251F;BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT UP LIGHT;;;; 2520;BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND RIGHT LIGHT;;;; 2521;BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT UP HEAVY;;;; 2522;BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT DOWN HEAVY;;;; 2523;BOX DRAWINGS HEAVY VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND RIGHT;;;; 2524;BOX DRAWINGS LIGHT VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND LEFT;;;; 2525;BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND LEFT HEAVY;;;; 2526;BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT DOWN LIGHT;;;; 2527;BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT UP LIGHT;;;; 2528;BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND LEFT LIGHT;;;; 2529;BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT UP HEAVY;;;; 252A;BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT DOWN HEAVY;;;; 252B;BOX DRAWINGS HEAVY VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND LEFT;;;; 252C;BOX DRAWINGS LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOWN AND HORIZONTAL;;;; 252D;BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT DOWN LIGHT;;;; 252E;BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT DOWN LIGHT;;;; 252F;BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND HORIZONTAL HEAVY;;;; 2530;BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND HORIZONTAL LIGHT;;;; 2531;BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT DOWN HEAVY;;;; 2532;BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT DOWN HEAVY;;;; 2533;BOX DRAWINGS HEAVY DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOWN AND HORIZONTAL;;;; 2534;BOX DRAWINGS LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT UP AND HORIZONTAL;;;; 2535;BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT UP LIGHT;;;; 2536;BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT UP LIGHT;;;; 2537;BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND HORIZONTAL HEAVY;;;; 2538;BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND HORIZONTAL LIGHT;;;; 2539;BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT UP HEAVY;;;; 253A;BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT UP HEAVY;;;; 253B;BOX DRAWINGS HEAVY UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY UP AND HORIZONTAL;;;; 253C;BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND HORIZONTAL;;;; 253D;BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT VERTICAL LIGHT;;;; 253E;BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT VERTICAL LIGHT;;;; 253F;BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND HORIZONTAL HEAVY;;;; 2540;BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND DOWN HORIZONTAL LIGHT;;;; 2541;BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND UP HORIZONTAL LIGHT;;;; 2542;BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND HORIZONTAL LIGHT;;;; 2543;BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT UP HEAVY AND RIGHT DOWN LIGHT;;;; 2544;BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT UP HEAVY AND LEFT DOWN LIGHT;;;; 2545;BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT DOWN HEAVY AND RIGHT UP LIGHT;;;; 2546;BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT DOWN HEAVY AND LEFT UP LIGHT;;;; 2547;BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND UP HORIZONTAL HEAVY;;;; 2548;BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND DOWN HORIZONTAL HEAVY;;;; 2549;BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT VERTICAL HEAVY;;;; 254A;BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT VERTICAL HEAVY;;;; 254B;BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND HORIZONTAL;;;; 254C;BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH HORIZONTAL;;;; 254D;BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH HORIZONTAL;;;; 254E;BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH VERTICAL;;;; 254F;BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH VERTICAL;;;; 2550;BOX DRAWINGS DOUBLE HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE HORIZONTAL;;;; 2551;BOX DRAWINGS DOUBLE VERTICAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL;;;; 2552;BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND RIGHT DOUBLE;;;; 2553;BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND RIGHT SINGLE;;;; 2554;BOX DRAWINGS DOUBLE DOWN AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND RIGHT;;;; 2555;BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND LEFT DOUBLE;;;; 2556;BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND LEFT SINGLE;;;; 2557;BOX DRAWINGS DOUBLE DOWN AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND LEFT;;;; 2558;BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND RIGHT DOUBLE;;;; 2559;BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND RIGHT SINGLE;;;; 255A;BOX DRAWINGS DOUBLE UP AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE UP AND RIGHT;;;; 255B;BOX DRAWINGS UP SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND LEFT DOUBLE;;;; 255C;BOX DRAWINGS UP DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND LEFT SINGLE;;;; 255D;BOX DRAWINGS DOUBLE UP AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE UP AND LEFT;;;; 255E;BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND RIGHT DOUBLE;;;; 255F;BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND RIGHT SINGLE;;;; 2560;BOX DRAWINGS DOUBLE VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND RIGHT;;;; 2561;BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND LEFT DOUBLE;;;; 2562;BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND LEFT SINGLE;;;; 2563;BOX DRAWINGS DOUBLE VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND LEFT;;;; 2564;BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND HORIZONTAL DOUBLE;;;; 2565;BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND HORIZONTAL SINGLE;;;; 2566;BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND HORIZONTAL;;;; 2567;BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND HORIZONTAL DOUBLE;;;; 2568;BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND HORIZONTAL SINGLE;;;; 2569;BOX DRAWINGS DOUBLE UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE UP AND HORIZONTAL;;;; 256A;BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND HORIZONTAL DOUBLE;;;; 256B;BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND HORIZONTAL SINGLE;;;; 256C;BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND HORIZONTAL;;;; 256D;BOX DRAWINGS LIGHT ARC DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND RIGHT;;;; 256E;BOX DRAWINGS LIGHT ARC DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND LEFT;;;; 256F;BOX DRAWINGS LIGHT ARC UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND LEFT;;;; 2570;BOX DRAWINGS LIGHT ARC UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND RIGHT;;;; 2571;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;;;; 2572;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;;;; 2573;BOX DRAWINGS LIGHT DIAGONAL CROSS;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL CROSS;;;; 2574;BOX DRAWINGS LIGHT LEFT;So;0;ON;;;;;N;FORMS LIGHT LEFT;;;; 2575;BOX DRAWINGS LIGHT UP;So;0;ON;;;;;N;FORMS LIGHT UP;;;; 2576;BOX DRAWINGS LIGHT RIGHT;So;0;ON;;;;;N;FORMS LIGHT RIGHT;;;; 2577;BOX DRAWINGS LIGHT DOWN;So;0;ON;;;;;N;FORMS LIGHT DOWN;;;; 2578;BOX DRAWINGS HEAVY LEFT;So;0;ON;;;;;N;FORMS HEAVY LEFT;;;; 2579;BOX DRAWINGS HEAVY UP;So;0;ON;;;;;N;FORMS HEAVY UP;;;; 257A;BOX DRAWINGS HEAVY RIGHT;So;0;ON;;;;;N;FORMS HEAVY RIGHT;;;; 257B;BOX DRAWINGS HEAVY DOWN;So;0;ON;;;;;N;FORMS HEAVY DOWN;;;; 257C;BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT;So;0;ON;;;;;N;FORMS LIGHT LEFT AND HEAVY RIGHT;;;; 257D;BOX DRAWINGS LIGHT UP AND HEAVY DOWN;So;0;ON;;;;;N;FORMS LIGHT UP AND HEAVY DOWN;;;; 257E;BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT;So;0;ON;;;;;N;FORMS HEAVY LEFT AND LIGHT RIGHT;;;; 257F;BOX DRAWINGS HEAVY UP AND LIGHT DOWN;So;0;ON;;;;;N;FORMS HEAVY UP AND LIGHT DOWN;;;; 2580;UPPER HALF BLOCK;So;0;ON;;;;;N;;;;; 2581;LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; 2582;LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; 2583;LOWER THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; 2584;LOWER HALF BLOCK;So;0;ON;;;;;N;;;;; 2585;LOWER FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; 2586;LOWER THREE QUARTERS BLOCK;So;0;ON;;;;;N;LOWER THREE QUARTER BLOCK;;;; 2587;LOWER SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; 2588;FULL BLOCK;So;0;ON;;;;;N;;;;; 2589;LEFT SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; 258A;LEFT THREE QUARTERS BLOCK;So;0;ON;;;;;N;LEFT THREE QUARTER BLOCK;;;; 258B;LEFT FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; 258C;LEFT HALF BLOCK;So;0;ON;;;;;N;;;;; 258D;LEFT THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; 258E;LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; 258F;LEFT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; 2590;RIGHT HALF BLOCK;So;0;ON;;;;;N;;;;; 2591;LIGHT SHADE;So;0;ON;;;;;N;;;;; 2592;MEDIUM SHADE;So;0;ON;;;;;N;;;;; 2593;DARK SHADE;So;0;ON;;;;;N;;;;; 2594;UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; 2595;RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; 2596;QUADRANT LOWER LEFT;So;0;ON;;;;;N;;;;; 2597;QUADRANT LOWER RIGHT;So;0;ON;;;;;N;;;;; 2598;QUADRANT UPPER LEFT;So;0;ON;;;;;N;;;;; 2599;QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; 259A;QUADRANT UPPER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; 259B;QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT;So;0;ON;;;;;N;;;;; 259C;QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; 259D;QUADRANT UPPER RIGHT;So;0;ON;;;;;N;;;;; 259E;QUADRANT UPPER RIGHT AND LOWER LEFT;So;0;ON;;;;;N;;;;; 259F;QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; 25A0;BLACK SQUARE;So;0;ON;;;;;N;;;;; 25A1;WHITE SQUARE;So;0;ON;;;;;N;;;;; 25A2;WHITE SQUARE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;; 25A3;WHITE SQUARE CONTAINING BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;; 25A4;SQUARE WITH HORIZONTAL FILL;So;0;ON;;;;;N;;;;; 25A5;SQUARE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;; 25A6;SQUARE WITH ORTHOGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;; 25A7;SQUARE WITH UPPER LEFT TO LOWER RIGHT FILL;So;0;ON;;;;;N;;;;; 25A8;SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL;So;0;ON;;;;;N;;;;; 25A9;SQUARE WITH DIAGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;; 25AA;BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;; 25AB;WHITE SMALL SQUARE;So;0;ON;;;;;N;;;;; 25AC;BLACK RECTANGLE;So;0;ON;;;;;N;;;;; 25AD;WHITE RECTANGLE;So;0;ON;;;;;N;;;;; 25AE;BLACK VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;; 25AF;WHITE VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;; 25B0;BLACK PARALLELOGRAM;So;0;ON;;;;;N;;;;; 25B1;WHITE PARALLELOGRAM;So;0;ON;;;;;N;;;;; 25B2;BLACK UP-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING TRIANGLE;;;; 25B3;WHITE UP-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE;;;; 25B4;BLACK UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING SMALL TRIANGLE;;;; 25B5;WHITE UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING SMALL TRIANGLE;;;; 25B6;BLACK RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING TRIANGLE;;;; 25B7;WHITE RIGHT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE RIGHT POINTING TRIANGLE;;;; 25B8;BLACK RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING SMALL TRIANGLE;;;; 25B9;WHITE RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE RIGHT POINTING SMALL TRIANGLE;;;; 25BA;BLACK RIGHT-POINTING POINTER;So;0;ON;;;;;N;BLACK RIGHT POINTING POINTER;;;; 25BB;WHITE RIGHT-POINTING POINTER;So;0;ON;;;;;N;WHITE RIGHT POINTING POINTER;;;; 25BC;BLACK DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING TRIANGLE;;;; 25BD;WHITE DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING TRIANGLE;;;; 25BE;BLACK DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING SMALL TRIANGLE;;;; 25BF;WHITE DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING SMALL TRIANGLE;;;; 25C0;BLACK LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING TRIANGLE;;;; 25C1;WHITE LEFT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE LEFT POINTING TRIANGLE;;;; 25C2;BLACK LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING SMALL TRIANGLE;;;; 25C3;WHITE LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE LEFT POINTING SMALL TRIANGLE;;;; 25C4;BLACK LEFT-POINTING POINTER;So;0;ON;;;;;N;BLACK LEFT POINTING POINTER;;;; 25C5;WHITE LEFT-POINTING POINTER;So;0;ON;;;;;N;WHITE LEFT POINTING POINTER;;;; 25C6;BLACK DIAMOND;So;0;ON;;;;;N;;;;; 25C7;WHITE DIAMOND;So;0;ON;;;;;N;;;;; 25C8;WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND;So;0;ON;;;;;N;;;;; 25C9;FISHEYE;So;0;ON;;;;;N;;;;; 25CA;LOZENGE;So;0;ON;;;;;N;;;;; 25CB;WHITE CIRCLE;So;0;ON;;;;;N;;;;; 25CC;DOTTED CIRCLE;So;0;ON;;;;;N;;;;; 25CD;CIRCLE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;; 25CE;BULLSEYE;So;0;ON;;;;;N;;;;; 25CF;BLACK CIRCLE;So;0;ON;;;;;N;;;;; 25D0;CIRCLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;; 25D1;CIRCLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;; 25D2;CIRCLE WITH LOWER HALF BLACK;So;0;ON;;;;;N;;;;; 25D3;CIRCLE WITH UPPER HALF BLACK;So;0;ON;;;;;N;;;;; 25D4;CIRCLE WITH UPPER RIGHT QUADRANT BLACK;So;0;ON;;;;;N;;;;; 25D5;CIRCLE WITH ALL BUT UPPER LEFT QUADRANT BLACK;So;0;ON;;;;;N;;;;; 25D6;LEFT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; 25D7;RIGHT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; 25D8;INVERSE BULLET;So;0;ON;;;;;N;;;;; 25D9;INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;; 25DA;UPPER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;; 25DB;LOWER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;; 25DC;UPPER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; 25DD;UPPER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; 25DE;LOWER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; 25DF;LOWER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; 25E0;UPPER HALF CIRCLE;So;0;ON;;;;;N;;;;; 25E1;LOWER HALF CIRCLE;So;0;ON;;;;;N;;;;; 25E2;BLACK LOWER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; 25E3;BLACK LOWER LEFT TRIANGLE;So;0;ON;;;;;N;;;;; 25E4;BLACK UPPER LEFT TRIANGLE;So;0;ON;;;;;N;;;;; 25E5;BLACK UPPER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; 25E6;WHITE BULLET;So;0;ON;;;;;N;;;;; 25E7;SQUARE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;; 25E8;SQUARE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;; 25E9;SQUARE WITH UPPER LEFT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;; 25EA;SQUARE WITH LOWER RIGHT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;; 25EB;WHITE SQUARE WITH VERTICAL BISECTING LINE;So;0;ON;;;;;N;;;;; 25EC;WHITE UP-POINTING TRIANGLE WITH DOT;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE WITH DOT;;;; 25ED;UP-POINTING TRIANGLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH LEFT HALF BLACK;;;; 25EE;UP-POINTING TRIANGLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH RIGHT HALF BLACK;;;; 25EF;LARGE CIRCLE;So;0;ON;;;;;N;;;;; 25F0;WHITE SQUARE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;; 25F1;WHITE SQUARE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;; 25F2;WHITE SQUARE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; 25F3;WHITE SQUARE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; 25F4;WHITE CIRCLE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;; 25F5;WHITE CIRCLE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;; 25F6;WHITE CIRCLE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; 25F7;WHITE CIRCLE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; 25F8;UPPER LEFT TRIANGLE;Sm;0;ON;;;;;N;;;;; 25F9;UPPER RIGHT TRIANGLE;Sm;0;ON;;;;;N;;;;; 25FA;LOWER LEFT TRIANGLE;Sm;0;ON;;;;;N;;;;; 25FB;WHITE MEDIUM SQUARE;Sm;0;ON;;;;;N;;;;; 25FC;BLACK MEDIUM SQUARE;Sm;0;ON;;;;;N;;;;; 25FD;WHITE MEDIUM SMALL SQUARE;Sm;0;ON;;;;;N;;;;; 25FE;BLACK MEDIUM SMALL SQUARE;Sm;0;ON;;;;;N;;;;; 25FF;LOWER RIGHT TRIANGLE;Sm;0;ON;;;;;N;;;;; 2600;BLACK SUN WITH RAYS;So;0;ON;;;;;N;;;;; 2601;CLOUD;So;0;ON;;;;;N;;;;; 2602;UMBRELLA;So;0;ON;;;;;N;;;;; 2603;SNOWMAN;So;0;ON;;;;;N;;;;; 2604;COMET;So;0;ON;;;;;N;;;;; 2605;BLACK STAR;So;0;ON;;;;;N;;;;; 2606;WHITE STAR;So;0;ON;;;;;N;;;;; 2607;LIGHTNING;So;0;ON;;;;;N;;;;; 2608;THUNDERSTORM;So;0;ON;;;;;N;;;;; 2609;SUN;So;0;ON;;;;;N;;;;; 260A;ASCENDING NODE;So;0;ON;;;;;N;;;;; 260B;DESCENDING NODE;So;0;ON;;;;;N;;;;; 260C;CONJUNCTION;So;0;ON;;;;;N;;;;; 260D;OPPOSITION;So;0;ON;;;;;N;;;;; 260E;BLACK TELEPHONE;So;0;ON;;;;;N;;;;; 260F;WHITE TELEPHONE;So;0;ON;;;;;N;;;;; 2610;BALLOT BOX;So;0;ON;;;;;N;;;;; 2611;BALLOT BOX WITH CHECK;So;0;ON;;;;;N;;;;; 2612;BALLOT BOX WITH X;So;0;ON;;;;;N;;;;; 2613;SALTIRE;So;0;ON;;;;;N;;;;; 2616;WHITE SHOGI PIECE;So;0;ON;;;;;N;;;;; 2617;BLACK SHOGI PIECE;So;0;ON;;;;;N;;;;; 2619;REVERSED ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;; 261A;BLACK LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; 261B;BLACK RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; 261C;WHITE LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; 261D;WHITE UP POINTING INDEX;So;0;ON;;;;;N;;;;; 261E;WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; 261F;WHITE DOWN POINTING INDEX;So;0;ON;;;;;N;;;;; 2620;SKULL AND CROSSBONES;So;0;ON;;;;;N;;;;; 2621;CAUTION SIGN;So;0;ON;;;;;N;;;;; 2622;RADIOACTIVE SIGN;So;0;ON;;;;;N;;;;; 2623;BIOHAZARD SIGN;So;0;ON;;;;;N;;;;; 2624;CADUCEUS;So;0;ON;;;;;N;;;;; 2625;ANKH;So;0;ON;;;;;N;;;;; 2626;ORTHODOX CROSS;So;0;ON;;;;;N;;;;; 2627;CHI RHO;So;0;ON;;;;;N;;;;; 2628;CROSS OF LORRAINE;So;0;ON;;;;;N;;;;; 2629;CROSS OF JERUSALEM;So;0;ON;;;;;N;;;;; 262A;STAR AND CRESCENT;So;0;ON;;;;;N;;;;; 262B;FARSI SYMBOL;So;0;ON;;;;;N;SYMBOL OF IRAN;;;; 262C;ADI SHAKTI;So;0;ON;;;;;N;;;;; 262D;HAMMER AND SICKLE;So;0;ON;;;;;N;;;;; 262E;PEACE SYMBOL;So;0;ON;;;;;N;;;;; 262F;YIN YANG;So;0;ON;;;;;N;;;;; 2630;TRIGRAM FOR HEAVEN;So;0;ON;;;;;N;;;;; 2631;TRIGRAM FOR LAKE;So;0;ON;;;;;N;;;;; 2632;TRIGRAM FOR FIRE;So;0;ON;;;;;N;;;;; 2633;TRIGRAM FOR THUNDER;So;0;ON;;;;;N;;;;; 2634;TRIGRAM FOR WIND;So;0;ON;;;;;N;;;;; 2635;TRIGRAM FOR WATER;So;0;ON;;;;;N;;;;; 2636;TRIGRAM FOR MOUNTAIN;So;0;ON;;;;;N;;;;; 2637;TRIGRAM FOR EARTH;So;0;ON;;;;;N;;;;; 2638;WHEEL OF DHARMA;So;0;ON;;;;;N;;;;; 2639;WHITE FROWNING FACE;So;0;ON;;;;;N;;;;; 263A;WHITE SMILING FACE;So;0;ON;;;;;N;;;;; 263B;BLACK SMILING FACE;So;0;ON;;;;;N;;;;; 263C;WHITE SUN WITH RAYS;So;0;ON;;;;;N;;;;; 263D;FIRST QUARTER MOON;So;0;ON;;;;;N;;;;; 263E;LAST QUARTER MOON;So;0;ON;;;;;N;;;;; 263F;MERCURY;So;0;ON;;;;;N;;;;; 2640;FEMALE SIGN;So;0;ON;;;;;N;;;;; 2641;EARTH;So;0;ON;;;;;N;;;;; 2642;MALE SIGN;So;0;ON;;;;;N;;;;; 2643;JUPITER;So;0;ON;;;;;N;;;;; 2644;SATURN;So;0;ON;;;;;N;;;;; 2645;URANUS;So;0;ON;;;;;N;;;;; 2646;NEPTUNE;So;0;ON;;;;;N;;;;; 2647;PLUTO;So;0;ON;;;;;N;;;;; 2648;ARIES;So;0;ON;;;;;N;;;;; 2649;TAURUS;So;0;ON;;;;;N;;;;; 264A;GEMINI;So;0;ON;;;;;N;;;;; 264B;CANCER;So;0;ON;;;;;N;;;;; 264C;LEO;So;0;ON;;;;;N;;;;; 264D;VIRGO;So;0;ON;;;;;N;;;;; 264E;LIBRA;So;0;ON;;;;;N;;;;; 264F;SCORPIUS;So;0;ON;;;;;N;;;;; 2650;SAGITTARIUS;So;0;ON;;;;;N;;;;; 2651;CAPRICORN;So;0;ON;;;;;N;;;;; 2652;AQUARIUS;So;0;ON;;;;;N;;;;; 2653;PISCES;So;0;ON;;;;;N;;;;; 2654;WHITE CHESS KING;So;0;ON;;;;;N;;;;; 2655;WHITE CHESS QUEEN;So;0;ON;;;;;N;;;;; 2656;WHITE CHESS ROOK;So;0;ON;;;;;N;;;;; 2657;WHITE CHESS BISHOP;So;0;ON;;;;;N;;;;; 2658;WHITE CHESS KNIGHT;So;0;ON;;;;;N;;;;; 2659;WHITE CHESS PAWN;So;0;ON;;;;;N;;;;; 265A;BLACK CHESS KING;So;0;ON;;;;;N;;;;; 265B;BLACK CHESS QUEEN;So;0;ON;;;;;N;;;;; 265C;BLACK CHESS ROOK;So;0;ON;;;;;N;;;;; 265D;BLACK CHESS BISHOP;So;0;ON;;;;;N;;;;; 265E;BLACK CHESS KNIGHT;So;0;ON;;;;;N;;;;; 265F;BLACK CHESS PAWN;So;0;ON;;;;;N;;;;; 2660;BLACK SPADE SUIT;So;0;ON;;;;;N;;;;; 2661;WHITE HEART SUIT;So;0;ON;;;;;N;;;;; 2662;WHITE DIAMOND SUIT;So;0;ON;;;;;N;;;;; 2663;BLACK CLUB SUIT;So;0;ON;;;;;N;;;;; 2664;WHITE SPADE SUIT;So;0;ON;;;;;N;;;;; 2665;BLACK HEART SUIT;So;0;ON;;;;;N;;;;; 2666;BLACK DIAMOND SUIT;So;0;ON;;;;;N;;;;; 2667;WHITE CLUB SUIT;So;0;ON;;;;;N;;;;; 2668;HOT SPRINGS;So;0;ON;;;;;N;;;;; 2669;QUARTER NOTE;So;0;ON;;;;;N;;;;; 266A;EIGHTH NOTE;So;0;ON;;;;;N;;;;; 266B;BEAMED EIGHTH NOTES;So;0;ON;;;;;N;BARRED EIGHTH NOTES;;;; 266C;BEAMED SIXTEENTH NOTES;So;0;ON;;;;;N;BARRED SIXTEENTH NOTES;;;; 266D;MUSIC FLAT SIGN;So;0;ON;;;;;N;FLAT;;;; 266E;MUSIC NATURAL SIGN;So;0;ON;;;;;N;NATURAL;;;; 266F;MUSIC SHARP SIGN;Sm;0;ON;;;;;N;SHARP;;;; 2670;WEST SYRIAC CROSS;So;0;ON;;;;;N;;;;; 2671;EAST SYRIAC CROSS;So;0;ON;;;;;N;;;;; 2672;UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;; 2673;RECYCLING SYMBOL FOR TYPE-1 PLASTICS;So;0;ON;;;;;N;;pete;;; 2674;RECYCLING SYMBOL FOR TYPE-2 PLASTICS;So;0;ON;;;;;N;;hdpe;;; 2675;RECYCLING SYMBOL FOR TYPE-3 PLASTICS;So;0;ON;;;;;N;;pvc;;; 2676;RECYCLING SYMBOL FOR TYPE-4 PLASTICS;So;0;ON;;;;;N;;ldpe;;; 2677;RECYCLING SYMBOL FOR TYPE-5 PLASTICS;So;0;ON;;;;;N;;pp;;; 2678;RECYCLING SYMBOL FOR TYPE-6 PLASTICS;So;0;ON;;;;;N;;ps;;; 2679;RECYCLING SYMBOL FOR TYPE-7 PLASTICS;So;0;ON;;;;;N;;other;;; 267A;RECYCLING SYMBOL FOR GENERIC MATERIALS;So;0;ON;;;;;N;;;;; 267B;BLACK UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;; 267C;RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;; 267D;PARTIALLY-RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;; 2680;DIE FACE-1;So;0;ON;;;;;N;;;;; 2681;DIE FACE-2;So;0;ON;;;;;N;;;;; 2682;DIE FACE-3;So;0;ON;;;;;N;;;;; 2683;DIE FACE-4;So;0;ON;;;;;N;;;;; 2684;DIE FACE-5;So;0;ON;;;;;N;;;;; 2685;DIE FACE-6;So;0;ON;;;;;N;;;;; 2686;WHITE CIRCLE WITH DOT RIGHT;So;0;ON;;;;;N;;;;; 2687;WHITE CIRCLE WITH TWO DOTS;So;0;ON;;;;;N;;;;; 2688;BLACK CIRCLE WITH WHITE DOT RIGHT;So;0;ON;;;;;N;;;;; 2689;BLACK CIRCLE WITH TWO WHITE DOTS;So;0;ON;;;;;N;;;;; 2701;UPPER BLADE SCISSORS;So;0;ON;;;;;N;;;;; 2702;BLACK SCISSORS;So;0;ON;;;;;N;;;;; 2703;LOWER BLADE SCISSORS;So;0;ON;;;;;N;;;;; 2704;WHITE SCISSORS;So;0;ON;;;;;N;;;;; 2706;TELEPHONE LOCATION SIGN;So;0;ON;;;;;N;;;;; 2707;TAPE DRIVE;So;0;ON;;;;;N;;;;; 2708;AIRPLANE;So;0;ON;;;;;N;;;;; 2709;ENVELOPE;So;0;ON;;;;;N;;;;; 270C;VICTORY HAND;So;0;ON;;;;;N;;;;; 270D;WRITING HAND;So;0;ON;;;;;N;;;;; 270E;LOWER RIGHT PENCIL;So;0;ON;;;;;N;;;;; 270F;PENCIL;So;0;ON;;;;;N;;;;; 2710;UPPER RIGHT PENCIL;So;0;ON;;;;;N;;;;; 2711;WHITE NIB;So;0;ON;;;;;N;;;;; 2712;BLACK NIB;So;0;ON;;;;;N;;;;; 2713;CHECK MARK;So;0;ON;;;;;N;;;;; 2714;HEAVY CHECK MARK;So;0;ON;;;;;N;;;;; 2715;MULTIPLICATION X;So;0;ON;;;;;N;;;;; 2716;HEAVY MULTIPLICATION X;So;0;ON;;;;;N;;;;; 2717;BALLOT X;So;0;ON;;;;;N;;;;; 2718;HEAVY BALLOT X;So;0;ON;;;;;N;;;;; 2719;OUTLINED GREEK CROSS;So;0;ON;;;;;N;;;;; 271A;HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;; 271B;OPEN CENTRE CROSS;So;0;ON;;;;;N;OPEN CENTER CROSS;;;; 271C;HEAVY OPEN CENTRE CROSS;So;0;ON;;;;;N;HEAVY OPEN CENTER CROSS;;;; 271D;LATIN CROSS;So;0;ON;;;;;N;;;;; 271E;SHADOWED WHITE LATIN CROSS;So;0;ON;;;;;N;;;;; 271F;OUTLINED LATIN CROSS;So;0;ON;;;;;N;;;;; 2720;MALTESE CROSS;So;0;ON;;;;;N;;;;; 2721;STAR OF DAVID;So;0;ON;;;;;N;;;;; 2722;FOUR TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; 2723;FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; 2724;HEAVY FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; 2725;FOUR CLUB-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; 2726;BLACK FOUR POINTED STAR;So;0;ON;;;;;N;;;;; 2727;WHITE FOUR POINTED STAR;So;0;ON;;;;;N;;;;; 2729;STRESS OUTLINED WHITE STAR;So;0;ON;;;;;N;;;;; 272A;CIRCLED WHITE STAR;So;0;ON;;;;;N;;;;; 272B;OPEN CENTRE BLACK STAR;So;0;ON;;;;;N;OPEN CENTER BLACK STAR;;;; 272C;BLACK CENTRE WHITE STAR;So;0;ON;;;;;N;BLACK CENTER WHITE STAR;;;; 272D;OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;; 272E;HEAVY OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;; 272F;PINWHEEL STAR;So;0;ON;;;;;N;;;;; 2730;SHADOWED WHITE STAR;So;0;ON;;;;;N;;;;; 2731;HEAVY ASTERISK;So;0;ON;;;;;N;;;;; 2732;OPEN CENTRE ASTERISK;So;0;ON;;;;;N;OPEN CENTER ASTERISK;;;; 2733;EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; 2734;EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;; 2735;EIGHT POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; 2736;SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;; 2737;EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;; 2738;HEAVY EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;; 2739;TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; 273A;SIXTEEN POINTED ASTERISK;So;0;ON;;;;;N;;;;; 273B;TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; 273C;OPEN CENTRE TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;OPEN CENTER TEARDROP-SPOKED ASTERISK;;;; 273D;HEAVY TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; 273E;SIX PETALLED BLACK AND WHITE FLORETTE;So;0;ON;;;;;N;;;;; 273F;BLACK FLORETTE;So;0;ON;;;;;N;;;;; 2740;WHITE FLORETTE;So;0;ON;;;;;N;;;;; 2741;EIGHT PETALLED OUTLINED BLACK FLORETTE;So;0;ON;;;;;N;;;;; 2742;CIRCLED OPEN CENTRE EIGHT POINTED STAR;So;0;ON;;;;;N;CIRCLED OPEN CENTER EIGHT POINTED STAR;;;; 2743;HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK;So;0;ON;;;;;N;;;;; 2744;SNOWFLAKE;So;0;ON;;;;;N;;;;; 2745;TIGHT TRIFOLIATE SNOWFLAKE;So;0;ON;;;;;N;;;;; 2746;HEAVY CHEVRON SNOWFLAKE;So;0;ON;;;;;N;;;;; 2747;SPARKLE;So;0;ON;;;;;N;;;;; 2748;HEAVY SPARKLE;So;0;ON;;;;;N;;;;; 2749;BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; 274A;EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;; 274B;HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;; 274D;SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;; 274F;LOWER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; 2750;UPPER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; 2751;LOWER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; 2752;UPPER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; 2756;BLACK DIAMOND MINUS WHITE X;So;0;ON;;;;;N;;;;; 2758;LIGHT VERTICAL BAR;So;0;ON;;;;;N;;;;; 2759;MEDIUM VERTICAL BAR;So;0;ON;;;;;N;;;;; 275A;HEAVY VERTICAL BAR;So;0;ON;;;;;N;;;;; 275B;HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; 275C;HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; 275D;HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; 275E;HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; 2761;CURVED STEM PARAGRAPH SIGN ORNAMENT;So;0;ON;;;;;N;;;;; 2762;HEAVY EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; 2763;HEAVY HEART EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; 2764;HEAVY BLACK HEART;So;0;ON;;;;;N;;;;; 2765;ROTATED HEAVY BLACK HEART BULLET;So;0;ON;;;;;N;;;;; 2766;FLORAL HEART;So;0;ON;;;;;N;;;;; 2767;ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;; 2768;MEDIUM LEFT PARENTHESIS ORNAMENT;Ps;0;ON;;;;;Y;;;;; 2769;MEDIUM RIGHT PARENTHESIS ORNAMENT;Pe;0;ON;;;;;Y;;;;; 276A;MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT;Ps;0;ON;;;;;Y;;;;; 276B;MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT;Pe;0;ON;;;;;Y;;;;; 276C;MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;; 276D;MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;; 276E;HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT;Ps;0;ON;;;;;Y;;;;; 276F;HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT;Pe;0;ON;;;;;Y;;;;; 2770;HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;; 2771;HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;; 2772;LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;; 2773;LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;; 2774;MEDIUM LEFT CURLY BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;; 2775;MEDIUM RIGHT CURLY BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;; 2776;DINGBAT NEGATIVE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED DIGIT ONE;;;; 2777;DINGBAT NEGATIVE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED DIGIT TWO;;;; 2778;DINGBAT NEGATIVE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED DIGIT THREE;;;; 2779;DINGBAT NEGATIVE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED DIGIT FOUR;;;; 277A;DINGBAT NEGATIVE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED DIGIT FIVE;;;; 277B;DINGBAT NEGATIVE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED DIGIT SIX;;;; 277C;DINGBAT NEGATIVE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED DIGIT SEVEN;;;; 277D;DINGBAT NEGATIVE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED DIGIT EIGHT;;;; 277E;DINGBAT NEGATIVE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED DIGIT NINE;;;; 277F;DINGBAT NEGATIVE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED NUMBER TEN;;;; 2780;DINGBAT CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;CIRCLED SANS-SERIF DIGIT ONE;;;; 2781;DINGBAT CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;CIRCLED SANS-SERIF DIGIT TWO;;;; 2782;DINGBAT CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;CIRCLED SANS-SERIF DIGIT THREE;;;; 2783;DINGBAT CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;CIRCLED SANS-SERIF DIGIT FOUR;;;; 2784;DINGBAT CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;CIRCLED SANS-SERIF DIGIT FIVE;;;; 2785;DINGBAT CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;CIRCLED SANS-SERIF DIGIT SIX;;;; 2786;DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;CIRCLED SANS-SERIF DIGIT SEVEN;;;; 2787;DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;CIRCLED SANS-SERIF DIGIT EIGHT;;;; 2788;DINGBAT CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;CIRCLED SANS-SERIF DIGIT NINE;;;; 2789;DINGBAT CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;CIRCLED SANS-SERIF NUMBER TEN;;;; 278A;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED SANS-SERIF DIGIT ONE;;;; 278B;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED SANS-SERIF DIGIT TWO;;;; 278C;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED SANS-SERIF DIGIT THREE;;;; 278D;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED SANS-SERIF DIGIT FOUR;;;; 278E;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED SANS-SERIF DIGIT FIVE;;;; 278F;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED SANS-SERIF DIGIT SIX;;;; 2790;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED SANS-SERIF DIGIT SEVEN;;;; 2791;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED SANS-SERIF DIGIT EIGHT;;;; 2792;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED SANS-SERIF DIGIT NINE;;;; 2793;DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED SANS-SERIF NUMBER TEN;;;; 2794;HEAVY WIDE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WIDE-HEADED RIGHT ARROW;;;; 2798;HEAVY SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT ARROW;;;; 2799;HEAVY RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY RIGHT ARROW;;;; 279A;HEAVY NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT ARROW;;;; 279B;DRAFTING POINT RIGHTWARDS ARROW;So;0;ON;;;;;N;DRAFTING POINT RIGHT ARROW;;;; 279C;HEAVY ROUND-TIPPED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY ROUND-TIPPED RIGHT ARROW;;;; 279D;TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;TRIANGLE-HEADED RIGHT ARROW;;;; 279E;HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TRIANGLE-HEADED RIGHT ARROW;;;; 279F;DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;DASHED TRIANGLE-HEADED RIGHT ARROW;;;; 27A0;HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY DASHED TRIANGLE-HEADED RIGHT ARROW;;;; 27A1;BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK RIGHT ARROW;;;; 27A2;THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D TOP-LIGHTED RIGHT ARROWHEAD;;;; 27A3;THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D BOTTOM-LIGHTED RIGHT ARROWHEAD;;;; 27A4;BLACK RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;BLACK RIGHT ARROWHEAD;;;; 27A5;HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED DOWN AND RIGHT ARROW;;;; 27A6;HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED UP AND RIGHT ARROW;;;; 27A7;SQUAT BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;SQUAT BLACK RIGHT ARROW;;;; 27A8;HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY CONCAVE-POINTED BLACK RIGHT ARROW;;;; 27A9;RIGHT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;RIGHT-SHADED WHITE RIGHT ARROW;;;; 27AA;LEFT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT-SHADED WHITE RIGHT ARROW;;;; 27AB;BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;BACK-TILTED SHADOWED WHITE RIGHT ARROW;;;; 27AC;FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;FRONT-TILTED SHADOWED WHITE RIGHT ARROW;;;; 27AD;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; 27AE;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; 27AF;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; 27B1;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; 27B2;CIRCLED HEAVY WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;CIRCLED HEAVY WHITE RIGHT ARROW;;;; 27B3;WHITE-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;WHITE-FEATHERED RIGHT ARROW;;;; 27B4;BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED LOWER RIGHT ARROW;;;; 27B5;BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK-FEATHERED RIGHT ARROW;;;; 27B6;BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED UPPER RIGHT ARROW;;;; 27B7;HEAVY BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED LOWER RIGHT ARROW;;;; 27B8;HEAVY BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED RIGHT ARROW;;;; 27B9;HEAVY BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED UPPER RIGHT ARROW;;;; 27BA;TEARDROP-BARBED RIGHTWARDS ARROW;So;0;ON;;;;;N;TEARDROP-BARBED RIGHT ARROW;;;; 27BB;HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TEARDROP-SHANKED RIGHT ARROW;;;; 27BC;WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;WEDGE-TAILED RIGHT ARROW;;;; 27BD;HEAVY WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WEDGE-TAILED RIGHT ARROW;;;; 27BE;OPEN-OUTLINED RIGHTWARDS ARROW;So;0;ON;;;;;N;OPEN-OUTLINED RIGHT ARROW;;;; 27D0;WHITE DIAMOND WITH CENTRED DOT;Sm;0;ON;;;;;N;;;;; 27D1;AND WITH DOT;Sm;0;ON;;;;;N;;;;; 27D2;ELEMENT OF OPENING UPWARDS;Sm;0;ON;;;;;N;;;;; 27D3;LOWER RIGHT CORNER WITH DOT;Sm;0;ON;;;;;Y;;;;; 27D4;UPPER LEFT CORNER WITH DOT;Sm;0;ON;;;;;Y;;;;; 27D5;LEFT OUTER JOIN;Sm;0;ON;;;;;Y;;;;; 27D6;RIGHT OUTER JOIN;Sm;0;ON;;;;;Y;;;;; 27D7;FULL OUTER JOIN;Sm;0;ON;;;;;N;;;;; 27D8;LARGE UP TACK;Sm;0;ON;;;;;N;;;;; 27D9;LARGE DOWN TACK;Sm;0;ON;;;;;N;;;;; 27DA;LEFT AND RIGHT DOUBLE TURNSTILE;Sm;0;ON;;;;;N;;;;; 27DB;LEFT AND RIGHT TACK;Sm;0;ON;;;;;N;;;;; 27DC;LEFT MULTIMAP;Sm;0;ON;;;;;Y;;;;; 27DD;LONG RIGHT TACK;Sm;0;ON;;;;;Y;;;;; 27DE;LONG LEFT TACK;Sm;0;ON;;;;;Y;;;;; 27DF;UP TACK WITH CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;; 27E0;LOZENGE DIVIDED BY HORIZONTAL RULE;Sm;0;ON;;;;;N;;;;; 27E1;WHITE CONCAVE-SIDED DIAMOND;Sm;0;ON;;;;;N;;;;; 27E2;WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK;Sm;0;ON;;;;;Y;;;;; 27E3;WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK;Sm;0;ON;;;;;Y;;;;; 27E4;WHITE SQUARE WITH LEFTWARDS TICK;Sm;0;ON;;;;;Y;;;;; 27E5;WHITE SQUARE WITH RIGHTWARDS TICK;Sm;0;ON;;;;;Y;;;;; 27E6;MATHEMATICAL LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;;;;; 27E7;MATHEMATICAL RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;;;;; 27E8;MATHEMATICAL LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;; 27E9;MATHEMATICAL RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;; 27EA;MATHEMATICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;; 27EB;MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;; 27F0;UPWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;; 27F1;DOWNWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;; 27F2;ANTICLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; 27F3;CLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; 27F4;RIGHT ARROW WITH CIRCLED PLUS;Sm;0;ON;;;;;N;;;;; 27F5;LONG LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; 27F6;LONG RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; 27F7;LONG LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;; 27F8;LONG LEFTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; 27F9;LONG RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; 27FA;LONG LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; 27FB;LONG LEFTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; 27FC;LONG RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; 27FD;LONG LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; 27FE;LONG RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; 27FF;LONG RIGHTWARDS SQUIGGLE ARROW;Sm;0;ON;;;;;N;;;;; 2800;BRAILLE PATTERN BLANK;So;0;ON;;;;;N;;;;; 2801;BRAILLE PATTERN DOTS-1;So;0;ON;;;;;N;;;;; 2802;BRAILLE PATTERN DOTS-2;So;0;ON;;;;;N;;;;; 2803;BRAILLE PATTERN DOTS-12;So;0;ON;;;;;N;;;;; 2804;BRAILLE PATTERN DOTS-3;So;0;ON;;;;;N;;;;; 2805;BRAILLE PATTERN DOTS-13;So;0;ON;;;;;N;;;;; 2806;BRAILLE PATTERN DOTS-23;So;0;ON;;;;;N;;;;; 2807;BRAILLE PATTERN DOTS-123;So;0;ON;;;;;N;;;;; 2808;BRAILLE PATTERN DOTS-4;So;0;ON;;;;;N;;;;; 2809;BRAILLE PATTERN DOTS-14;So;0;ON;;;;;N;;;;; 280A;BRAILLE PATTERN DOTS-24;So;0;ON;;;;;N;;;;; 280B;BRAILLE PATTERN DOTS-124;So;0;ON;;;;;N;;;;; 280C;BRAILLE PATTERN DOTS-34;So;0;ON;;;;;N;;;;; 280D;BRAILLE PATTERN DOTS-134;So;0;ON;;;;;N;;;;; 280E;BRAILLE PATTERN DOTS-234;So;0;ON;;;;;N;;;;; 280F;BRAILLE PATTERN DOTS-1234;So;0;ON;;;;;N;;;;; 2810;BRAILLE PATTERN DOTS-5;So;0;ON;;;;;N;;;;; 2811;BRAILLE PATTERN DOTS-15;So;0;ON;;;;;N;;;;; 2812;BRAILLE PATTERN DOTS-25;So;0;ON;;;;;N;;;;; 2813;BRAILLE PATTERN DOTS-125;So;0;ON;;;;;N;;;;; 2814;BRAILLE PATTERN DOTS-35;So;0;ON;;;;;N;;;;; 2815;BRAILLE PATTERN DOTS-135;So;0;ON;;;;;N;;;;; 2816;BRAILLE PATTERN DOTS-235;So;0;ON;;;;;N;;;;; 2817;BRAILLE PATTERN DOTS-1235;So;0;ON;;;;;N;;;;; 2818;BRAILLE PATTERN DOTS-45;So;0;ON;;;;;N;;;;; 2819;BRAILLE PATTERN DOTS-145;So;0;ON;;;;;N;;;;; 281A;BRAILLE PATTERN DOTS-245;So;0;ON;;;;;N;;;;; 281B;BRAILLE PATTERN DOTS-1245;So;0;ON;;;;;N;;;;; 281C;BRAILLE PATTERN DOTS-345;So;0;ON;;;;;N;;;;; 281D;BRAILLE PATTERN DOTS-1345;So;0;ON;;;;;N;;;;; 281E;BRAILLE PATTERN DOTS-2345;So;0;ON;;;;;N;;;;; 281F;BRAILLE PATTERN DOTS-12345;So;0;ON;;;;;N;;;;; 2820;BRAILLE PATTERN DOTS-6;So;0;ON;;;;;N;;;;; 2821;BRAILLE PATTERN DOTS-16;So;0;ON;;;;;N;;;;; 2822;BRAILLE PATTERN DOTS-26;So;0;ON;;;;;N;;;;; 2823;BRAILLE PATTERN DOTS-126;So;0;ON;;;;;N;;;;; 2824;BRAILLE PATTERN DOTS-36;So;0;ON;;;;;N;;;;; 2825;BRAILLE PATTERN DOTS-136;So;0;ON;;;;;N;;;;; 2826;BRAILLE PATTERN DOTS-236;So;0;ON;;;;;N;;;;; 2827;BRAILLE PATTERN DOTS-1236;So;0;ON;;;;;N;;;;; 2828;BRAILLE PATTERN DOTS-46;So;0;ON;;;;;N;;;;; 2829;BRAILLE PATTERN DOTS-146;So;0;ON;;;;;N;;;;; 282A;BRAILLE PATTERN DOTS-246;So;0;ON;;;;;N;;;;; 282B;BRAILLE PATTERN DOTS-1246;So;0;ON;;;;;N;;;;; 282C;BRAILLE PATTERN DOTS-346;So;0;ON;;;;;N;;;;; 282D;BRAILLE PATTERN DOTS-1346;So;0;ON;;;;;N;;;;; 282E;BRAILLE PATTERN DOTS-2346;So;0;ON;;;;;N;;;;; 282F;BRAILLE PATTERN DOTS-12346;So;0;ON;;;;;N;;;;; 2830;BRAILLE PATTERN DOTS-56;So;0;ON;;;;;N;;;;; 2831;BRAILLE PATTERN DOTS-156;So;0;ON;;;;;N;;;;; 2832;BRAILLE PATTERN DOTS-256;So;0;ON;;;;;N;;;;; 2833;BRAILLE PATTERN DOTS-1256;So;0;ON;;;;;N;;;;; 2834;BRAILLE PATTERN DOTS-356;So;0;ON;;;;;N;;;;; 2835;BRAILLE PATTERN DOTS-1356;So;0;ON;;;;;N;;;;; 2836;BRAILLE PATTERN DOTS-2356;So;0;ON;;;;;N;;;;; 2837;BRAILLE PATTERN DOTS-12356;So;0;ON;;;;;N;;;;; 2838;BRAILLE PATTERN DOTS-456;So;0;ON;;;;;N;;;;; 2839;BRAILLE PATTERN DOTS-1456;So;0;ON;;;;;N;;;;; 283A;BRAILLE PATTERN DOTS-2456;So;0;ON;;;;;N;;;;; 283B;BRAILLE PATTERN DOTS-12456;So;0;ON;;;;;N;;;;; 283C;BRAILLE PATTERN DOTS-3456;So;0;ON;;;;;N;;;;; 283D;BRAILLE PATTERN DOTS-13456;So;0;ON;;;;;N;;;;; 283E;BRAILLE PATTERN DOTS-23456;So;0;ON;;;;;N;;;;; 283F;BRAILLE PATTERN DOTS-123456;So;0;ON;;;;;N;;;;; 2840;BRAILLE PATTERN DOTS-7;So;0;ON;;;;;N;;;;; 2841;BRAILLE PATTERN DOTS-17;So;0;ON;;;;;N;;;;; 2842;BRAILLE PATTERN DOTS-27;So;0;ON;;;;;N;;;;; 2843;BRAILLE PATTERN DOTS-127;So;0;ON;;;;;N;;;;; 2844;BRAILLE PATTERN DOTS-37;So;0;ON;;;;;N;;;;; 2845;BRAILLE PATTERN DOTS-137;So;0;ON;;;;;N;;;;; 2846;BRAILLE PATTERN DOTS-237;So;0;ON;;;;;N;;;;; 2847;BRAILLE PATTERN DOTS-1237;So;0;ON;;;;;N;;;;; 2848;BRAILLE PATTERN DOTS-47;So;0;ON;;;;;N;;;;; 2849;BRAILLE PATTERN DOTS-147;So;0;ON;;;;;N;;;;; 284A;BRAILLE PATTERN DOTS-247;So;0;ON;;;;;N;;;;; 284B;BRAILLE PATTERN DOTS-1247;So;0;ON;;;;;N;;;;; 284C;BRAILLE PATTERN DOTS-347;So;0;ON;;;;;N;;;;; 284D;BRAILLE PATTERN DOTS-1347;So;0;ON;;;;;N;;;;; 284E;BRAILLE PATTERN DOTS-2347;So;0;ON;;;;;N;;;;; 284F;BRAILLE PATTERN DOTS-12347;So;0;ON;;;;;N;;;;; 2850;BRAILLE PATTERN DOTS-57;So;0;ON;;;;;N;;;;; 2851;BRAILLE PATTERN DOTS-157;So;0;ON;;;;;N;;;;; 2852;BRAILLE PATTERN DOTS-257;So;0;ON;;;;;N;;;;; 2853;BRAILLE PATTERN DOTS-1257;So;0;ON;;;;;N;;;;; 2854;BRAILLE PATTERN DOTS-357;So;0;ON;;;;;N;;;;; 2855;BRAILLE PATTERN DOTS-1357;So;0;ON;;;;;N;;;;; 2856;BRAILLE PATTERN DOTS-2357;So;0;ON;;;;;N;;;;; 2857;BRAILLE PATTERN DOTS-12357;So;0;ON;;;;;N;;;;; 2858;BRAILLE PATTERN DOTS-457;So;0;ON;;;;;N;;;;; 2859;BRAILLE PATTERN DOTS-1457;So;0;ON;;;;;N;;;;; 285A;BRAILLE PATTERN DOTS-2457;So;0;ON;;;;;N;;;;; 285B;BRAILLE PATTERN DOTS-12457;So;0;ON;;;;;N;;;;; 285C;BRAILLE PATTERN DOTS-3457;So;0;ON;;;;;N;;;;; 285D;BRAILLE PATTERN DOTS-13457;So;0;ON;;;;;N;;;;; 285E;BRAILLE PATTERN DOTS-23457;So;0;ON;;;;;N;;;;; 285F;BRAILLE PATTERN DOTS-123457;So;0;ON;;;;;N;;;;; 2860;BRAILLE PATTERN DOTS-67;So;0;ON;;;;;N;;;;; 2861;BRAILLE PATTERN DOTS-167;So;0;ON;;;;;N;;;;; 2862;BRAILLE PATTERN DOTS-267;So;0;ON;;;;;N;;;;; 2863;BRAILLE PATTERN DOTS-1267;So;0;ON;;;;;N;;;;; 2864;BRAILLE PATTERN DOTS-367;So;0;ON;;;;;N;;;;; 2865;BRAILLE PATTERN DOTS-1367;So;0;ON;;;;;N;;;;; 2866;BRAILLE PATTERN DOTS-2367;So;0;ON;;;;;N;;;;; 2867;BRAILLE PATTERN DOTS-12367;So;0;ON;;;;;N;;;;; 2868;BRAILLE PATTERN DOTS-467;So;0;ON;;;;;N;;;;; 2869;BRAILLE PATTERN DOTS-1467;So;0;ON;;;;;N;;;;; 286A;BRAILLE PATTERN DOTS-2467;So;0;ON;;;;;N;;;;; 286B;BRAILLE PATTERN DOTS-12467;So;0;ON;;;;;N;;;;; 286C;BRAILLE PATTERN DOTS-3467;So;0;ON;;;;;N;;;;; 286D;BRAILLE PATTERN DOTS-13467;So;0;ON;;;;;N;;;;; 286E;BRAILLE PATTERN DOTS-23467;So;0;ON;;;;;N;;;;; 286F;BRAILLE PATTERN DOTS-123467;So;0;ON;;;;;N;;;;; 2870;BRAILLE PATTERN DOTS-567;So;0;ON;;;;;N;;;;; 2871;BRAILLE PATTERN DOTS-1567;So;0;ON;;;;;N;;;;; 2872;BRAILLE PATTERN DOTS-2567;So;0;ON;;;;;N;;;;; 2873;BRAILLE PATTERN DOTS-12567;So;0;ON;;;;;N;;;;; 2874;BRAILLE PATTERN DOTS-3567;So;0;ON;;;;;N;;;;; 2875;BRAILLE PATTERN DOTS-13567;So;0;ON;;;;;N;;;;; 2876;BRAILLE PATTERN DOTS-23567;So;0;ON;;;;;N;;;;; 2877;BRAILLE PATTERN DOTS-123567;So;0;ON;;;;;N;;;;; 2878;BRAILLE PATTERN DOTS-4567;So;0;ON;;;;;N;;;;; 2879;BRAILLE PATTERN DOTS-14567;So;0;ON;;;;;N;;;;; 287A;BRAILLE PATTERN DOTS-24567;So;0;ON;;;;;N;;;;; 287B;BRAILLE PATTERN DOTS-124567;So;0;ON;;;;;N;;;;; 287C;BRAILLE PATTERN DOTS-34567;So;0;ON;;;;;N;;;;; 287D;BRAILLE PATTERN DOTS-134567;So;0;ON;;;;;N;;;;; 287E;BRAILLE PATTERN DOTS-234567;So;0;ON;;;;;N;;;;; 287F;BRAILLE PATTERN DOTS-1234567;So;0;ON;;;;;N;;;;; 2880;BRAILLE PATTERN DOTS-8;So;0;ON;;;;;N;;;;; 2881;BRAILLE PATTERN DOTS-18;So;0;ON;;;;;N;;;;; 2882;BRAILLE PATTERN DOTS-28;So;0;ON;;;;;N;;;;; 2883;BRAILLE PATTERN DOTS-128;So;0;ON;;;;;N;;;;; 2884;BRAILLE PATTERN DOTS-38;So;0;ON;;;;;N;;;;; 2885;BRAILLE PATTERN DOTS-138;So;0;ON;;;;;N;;;;; 2886;BRAILLE PATTERN DOTS-238;So;0;ON;;;;;N;;;;; 2887;BRAILLE PATTERN DOTS-1238;So;0;ON;;;;;N;;;;; 2888;BRAILLE PATTERN DOTS-48;So;0;ON;;;;;N;;;;; 2889;BRAILLE PATTERN DOTS-148;So;0;ON;;;;;N;;;;; 288A;BRAILLE PATTERN DOTS-248;So;0;ON;;;;;N;;;;; 288B;BRAILLE PATTERN DOTS-1248;So;0;ON;;;;;N;;;;; 288C;BRAILLE PATTERN DOTS-348;So;0;ON;;;;;N;;;;; 288D;BRAILLE PATTERN DOTS-1348;So;0;ON;;;;;N;;;;; 288E;BRAILLE PATTERN DOTS-2348;So;0;ON;;;;;N;;;;; 288F;BRAILLE PATTERN DOTS-12348;So;0;ON;;;;;N;;;;; 2890;BRAILLE PATTERN DOTS-58;So;0;ON;;;;;N;;;;; 2891;BRAILLE PATTERN DOTS-158;So;0;ON;;;;;N;;;;; 2892;BRAILLE PATTERN DOTS-258;So;0;ON;;;;;N;;;;; 2893;BRAILLE PATTERN DOTS-1258;So;0;ON;;;;;N;;;;; 2894;BRAILLE PATTERN DOTS-358;So;0;ON;;;;;N;;;;; 2895;BRAILLE PATTERN DOTS-1358;So;0;ON;;;;;N;;;;; 2896;BRAILLE PATTERN DOTS-2358;So;0;ON;;;;;N;;;;; 2897;BRAILLE PATTERN DOTS-12358;So;0;ON;;;;;N;;;;; 2898;BRAILLE PATTERN DOTS-458;So;0;ON;;;;;N;;;;; 2899;BRAILLE PATTERN DOTS-1458;So;0;ON;;;;;N;;;;; 289A;BRAILLE PATTERN DOTS-2458;So;0;ON;;;;;N;;;;; 289B;BRAILLE PATTERN DOTS-12458;So;0;ON;;;;;N;;;;; 289C;BRAILLE PATTERN DOTS-3458;So;0;ON;;;;;N;;;;; 289D;BRAILLE PATTERN DOTS-13458;So;0;ON;;;;;N;;;;; 289E;BRAILLE PATTERN DOTS-23458;So;0;ON;;;;;N;;;;; 289F;BRAILLE PATTERN DOTS-123458;So;0;ON;;;;;N;;;;; 28A0;BRAILLE PATTERN DOTS-68;So;0;ON;;;;;N;;;;; 28A1;BRAILLE PATTERN DOTS-168;So;0;ON;;;;;N;;;;; 28A2;BRAILLE PATTERN DOTS-268;So;0;ON;;;;;N;;;;; 28A3;BRAILLE PATTERN DOTS-1268;So;0;ON;;;;;N;;;;; 28A4;BRAILLE PATTERN DOTS-368;So;0;ON;;;;;N;;;;; 28A5;BRAILLE PATTERN DOTS-1368;So;0;ON;;;;;N;;;;; 28A6;BRAILLE PATTERN DOTS-2368;So;0;ON;;;;;N;;;;; 28A7;BRAILLE PATTERN DOTS-12368;So;0;ON;;;;;N;;;;; 28A8;BRAILLE PATTERN DOTS-468;So;0;ON;;;;;N;;;;; 28A9;BRAILLE PATTERN DOTS-1468;So;0;ON;;;;;N;;;;; 28AA;BRAILLE PATTERN DOTS-2468;So;0;ON;;;;;N;;;;; 28AB;BRAILLE PATTERN DOTS-12468;So;0;ON;;;;;N;;;;; 28AC;BRAILLE PATTERN DOTS-3468;So;0;ON;;;;;N;;;;; 28AD;BRAILLE PATTERN DOTS-13468;So;0;ON;;;;;N;;;;; 28AE;BRAILLE PATTERN DOTS-23468;So;0;ON;;;;;N;;;;; 28AF;BRAILLE PATTERN DOTS-123468;So;0;ON;;;;;N;;;;; 28B0;BRAILLE PATTERN DOTS-568;So;0;ON;;;;;N;;;;; 28B1;BRAILLE PATTERN DOTS-1568;So;0;ON;;;;;N;;;;; 28B2;BRAILLE PATTERN DOTS-2568;So;0;ON;;;;;N;;;;; 28B3;BRAILLE PATTERN DOTS-12568;So;0;ON;;;;;N;;;;; 28B4;BRAILLE PATTERN DOTS-3568;So;0;ON;;;;;N;;;;; 28B5;BRAILLE PATTERN DOTS-13568;So;0;ON;;;;;N;;;;; 28B6;BRAILLE PATTERN DOTS-23568;So;0;ON;;;;;N;;;;; 28B7;BRAILLE PATTERN DOTS-123568;So;0;ON;;;;;N;;;;; 28B8;BRAILLE PATTERN DOTS-4568;So;0;ON;;;;;N;;;;; 28B9;BRAILLE PATTERN DOTS-14568;So;0;ON;;;;;N;;;;; 28BA;BRAILLE PATTERN DOTS-24568;So;0;ON;;;;;N;;;;; 28BB;BRAILLE PATTERN DOTS-124568;So;0;ON;;;;;N;;;;; 28BC;BRAILLE PATTERN DOTS-34568;So;0;ON;;;;;N;;;;; 28BD;BRAILLE PATTERN DOTS-134568;So;0;ON;;;;;N;;;;; 28BE;BRAILLE PATTERN DOTS-234568;So;0;ON;;;;;N;;;;; 28BF;BRAILLE PATTERN DOTS-1234568;So;0;ON;;;;;N;;;;; 28C0;BRAILLE PATTERN DOTS-78;So;0;ON;;;;;N;;;;; 28C1;BRAILLE PATTERN DOTS-178;So;0;ON;;;;;N;;;;; 28C2;BRAILLE PATTERN DOTS-278;So;0;ON;;;;;N;;;;; 28C3;BRAILLE PATTERN DOTS-1278;So;0;ON;;;;;N;;;;; 28C4;BRAILLE PATTERN DOTS-378;So;0;ON;;;;;N;;;;; 28C5;BRAILLE PATTERN DOTS-1378;So;0;ON;;;;;N;;;;; 28C6;BRAILLE PATTERN DOTS-2378;So;0;ON;;;;;N;;;;; 28C7;BRAILLE PATTERN DOTS-12378;So;0;ON;;;;;N;;;;; 28C8;BRAILLE PATTERN DOTS-478;So;0;ON;;;;;N;;;;; 28C9;BRAILLE PATTERN DOTS-1478;So;0;ON;;;;;N;;;;; 28CA;BRAILLE PATTERN DOTS-2478;So;0;ON;;;;;N;;;;; 28CB;BRAILLE PATTERN DOTS-12478;So;0;ON;;;;;N;;;;; 28CC;BRAILLE PATTERN DOTS-3478;So;0;ON;;;;;N;;;;; 28CD;BRAILLE PATTERN DOTS-13478;So;0;ON;;;;;N;;;;; 28CE;BRAILLE PATTERN DOTS-23478;So;0;ON;;;;;N;;;;; 28CF;BRAILLE PATTERN DOTS-123478;So;0;ON;;;;;N;;;;; 28D0;BRAILLE PATTERN DOTS-578;So;0;ON;;;;;N;;;;; 28D1;BRAILLE PATTERN DOTS-1578;So;0;ON;;;;;N;;;;; 28D2;BRAILLE PATTERN DOTS-2578;So;0;ON;;;;;N;;;;; 28D3;BRAILLE PATTERN DOTS-12578;So;0;ON;;;;;N;;;;; 28D4;BRAILLE PATTERN DOTS-3578;So;0;ON;;;;;N;;;;; 28D5;BRAILLE PATTERN DOTS-13578;So;0;ON;;;;;N;;;;; 28D6;BRAILLE PATTERN DOTS-23578;So;0;ON;;;;;N;;;;; 28D7;BRAILLE PATTERN DOTS-123578;So;0;ON;;;;;N;;;;; 28D8;BRAILLE PATTERN DOTS-4578;So;0;ON;;;;;N;;;;; 28D9;BRAILLE PATTERN DOTS-14578;So;0;ON;;;;;N;;;;; 28DA;BRAILLE PATTERN DOTS-24578;So;0;ON;;;;;N;;;;; 28DB;BRAILLE PATTERN DOTS-124578;So;0;ON;;;;;N;;;;; 28DC;BRAILLE PATTERN DOTS-34578;So;0;ON;;;;;N;;;;; 28DD;BRAILLE PATTERN DOTS-134578;So;0;ON;;;;;N;;;;; 28DE;BRAILLE PATTERN DOTS-234578;So;0;ON;;;;;N;;;;; 28DF;BRAILLE PATTERN DOTS-1234578;So;0;ON;;;;;N;;;;; 28E0;BRAILLE PATTERN DOTS-678;So;0;ON;;;;;N;;;;; 28E1;BRAILLE PATTERN DOTS-1678;So;0;ON;;;;;N;;;;; 28E2;BRAILLE PATTERN DOTS-2678;So;0;ON;;;;;N;;;;; 28E3;BRAILLE PATTERN DOTS-12678;So;0;ON;;;;;N;;;;; 28E4;BRAILLE PATTERN DOTS-3678;So;0;ON;;;;;N;;;;; 28E5;BRAILLE PATTERN DOTS-13678;So;0;ON;;;;;N;;;;; 28E6;BRAILLE PATTERN DOTS-23678;So;0;ON;;;;;N;;;;; 28E7;BRAILLE PATTERN DOTS-123678;So;0;ON;;;;;N;;;;; 28E8;BRAILLE PATTERN DOTS-4678;So;0;ON;;;;;N;;;;; 28E9;BRAILLE PATTERN DOTS-14678;So;0;ON;;;;;N;;;;; 28EA;BRAILLE PATTERN DOTS-24678;So;0;ON;;;;;N;;;;; 28EB;BRAILLE PATTERN DOTS-124678;So;0;ON;;;;;N;;;;; 28EC;BRAILLE PATTERN DOTS-34678;So;0;ON;;;;;N;;;;; 28ED;BRAILLE PATTERN DOTS-134678;So;0;ON;;;;;N;;;;; 28EE;BRAILLE PATTERN DOTS-234678;So;0;ON;;;;;N;;;;; 28EF;BRAILLE PATTERN DOTS-1234678;So;0;ON;;;;;N;;;;; 28F0;BRAILLE PATTERN DOTS-5678;So;0;ON;;;;;N;;;;; 28F1;BRAILLE PATTERN DOTS-15678;So;0;ON;;;;;N;;;;; 28F2;BRAILLE PATTERN DOTS-25678;So;0;ON;;;;;N;;;;; 28F3;BRAILLE PATTERN DOTS-125678;So;0;ON;;;;;N;;;;; 28F4;BRAILLE PATTERN DOTS-35678;So;0;ON;;;;;N;;;;; 28F5;BRAILLE PATTERN DOTS-135678;So;0;ON;;;;;N;;;;; 28F6;BRAILLE PATTERN DOTS-235678;So;0;ON;;;;;N;;;;; 28F7;BRAILLE PATTERN DOTS-1235678;So;0;ON;;;;;N;;;;; 28F8;BRAILLE PATTERN DOTS-45678;So;0;ON;;;;;N;;;;; 28F9;BRAILLE PATTERN DOTS-145678;So;0;ON;;;;;N;;;;; 28FA;BRAILLE PATTERN DOTS-245678;So;0;ON;;;;;N;;;;; 28FB;BRAILLE PATTERN DOTS-1245678;So;0;ON;;;;;N;;;;; 28FC;BRAILLE PATTERN DOTS-345678;So;0;ON;;;;;N;;;;; 28FD;BRAILLE PATTERN DOTS-1345678;So;0;ON;;;;;N;;;;; 28FE;BRAILLE PATTERN DOTS-2345678;So;0;ON;;;;;N;;;;; 28FF;BRAILLE PATTERN DOTS-12345678;So;0;ON;;;;;N;;;;; 2900;RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 2901;RIGHTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 2902;LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 2903;RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 2904;LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 2905;RIGHTWARDS TWO-HEADED ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; 2906;LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; 2907;RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; 2908;DOWNWARDS ARROW WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; 2909;UPWARDS ARROW WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; 290A;UPWARDS TRIPLE ARROW;Sm;0;ON;;;;;N;;;;; 290B;DOWNWARDS TRIPLE ARROW;Sm;0;ON;;;;;N;;;;; 290C;LEFTWARDS DOUBLE DASH ARROW;Sm;0;ON;;;;;N;;;;; 290D;RIGHTWARDS DOUBLE DASH ARROW;Sm;0;ON;;;;;N;;;;; 290E;LEFTWARDS TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;; 290F;RIGHTWARDS TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;; 2910;RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;; 2911;RIGHTWARDS ARROW WITH DOTTED STEM;Sm;0;ON;;;;;N;;;;; 2912;UPWARDS ARROW TO BAR;Sm;0;ON;;;;;N;;;;; 2913;DOWNWARDS ARROW TO BAR;Sm;0;ON;;;;;N;;;;; 2914;RIGHTWARDS ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 2915;RIGHTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 2916;RIGHTWARDS TWO-HEADED ARROW WITH TAIL;Sm;0;ON;;;;;N;;;;; 2917;RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 2918;RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 2919;LEFTWARDS ARROW-TAIL;Sm;0;ON;;;;;N;;;;; 291A;RIGHTWARDS ARROW-TAIL;Sm;0;ON;;;;;N;;;;; 291B;LEFTWARDS DOUBLE ARROW-TAIL;Sm;0;ON;;;;;N;;;;; 291C;RIGHTWARDS DOUBLE ARROW-TAIL;Sm;0;ON;;;;;N;;;;; 291D;LEFTWARDS ARROW TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; 291E;RIGHTWARDS ARROW TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; 291F;LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; 2920;RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; 2921;NORTH WEST AND SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;; 2922;NORTH EAST AND SOUTH WEST ARROW;Sm;0;ON;;;;;N;;;;; 2923;NORTH WEST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;; 2924;NORTH EAST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;; 2925;SOUTH EAST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;; 2926;SOUTH WEST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;; 2927;NORTH WEST ARROW AND NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;; 2928;NORTH EAST ARROW AND SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;; 2929;SOUTH EAST ARROW AND SOUTH WEST ARROW;Sm;0;ON;;;;;N;;;;; 292A;SOUTH WEST ARROW AND NORTH WEST ARROW;Sm;0;ON;;;;;N;;;;; 292B;RISING DIAGONAL CROSSING FALLING DIAGONAL;Sm;0;ON;;;;;N;;;;; 292C;FALLING DIAGONAL CROSSING RISING DIAGONAL;Sm;0;ON;;;;;N;;;;; 292D;SOUTH EAST ARROW CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;; 292E;NORTH EAST ARROW CROSSING SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;; 292F;FALLING DIAGONAL CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;; 2930;RISING DIAGONAL CROSSING SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;; 2931;NORTH EAST ARROW CROSSING NORTH WEST ARROW;Sm;0;ON;;;;;N;;;;; 2932;NORTH WEST ARROW CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;; 2933;WAVE ARROW POINTING DIRECTLY RIGHT;Sm;0;ON;;;;;N;;;;; 2934;ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS;Sm;0;ON;;;;;N;;;;; 2935;ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS;Sm;0;ON;;;;;N;;;;; 2936;ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS;Sm;0;ON;;;;;N;;;;; 2937;ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS;Sm;0;ON;;;;;N;;;;; 2938;RIGHT-SIDE ARC CLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; 2939;LEFT-SIDE ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; 293A;TOP ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; 293B;BOTTOM ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; 293C;TOP ARC CLOCKWISE ARROW WITH MINUS;Sm;0;ON;;;;;N;;;;; 293D;TOP ARC ANTICLOCKWISE ARROW WITH PLUS;Sm;0;ON;;;;;N;;;;; 293E;LOWER RIGHT SEMICIRCULAR CLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; 293F;LOWER LEFT SEMICIRCULAR ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; 2940;ANTICLOCKWISE CLOSED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; 2941;CLOCKWISE CLOSED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; 2942;RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; 2943;LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; 2944;SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; 2945;RIGHTWARDS ARROW WITH PLUS BELOW;Sm;0;ON;;;;;N;;;;; 2946;LEFTWARDS ARROW WITH PLUS BELOW;Sm;0;ON;;;;;N;;;;; 2947;RIGHTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;; 2948;LEFT RIGHT ARROW THROUGH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; 2949;UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; 294A;LEFT BARB UP RIGHT BARB DOWN HARPOON;Sm;0;ON;;;;;N;;;;; 294B;LEFT BARB DOWN RIGHT BARB UP HARPOON;Sm;0;ON;;;;;N;;;;; 294C;UP BARB RIGHT DOWN BARB LEFT HARPOON;Sm;0;ON;;;;;N;;;;; 294D;UP BARB LEFT DOWN BARB RIGHT HARPOON;Sm;0;ON;;;;;N;;;;; 294E;LEFT BARB UP RIGHT BARB UP HARPOON;Sm;0;ON;;;;;N;;;;; 294F;UP BARB RIGHT DOWN BARB RIGHT HARPOON;Sm;0;ON;;;;;N;;;;; 2950;LEFT BARB DOWN RIGHT BARB DOWN HARPOON;Sm;0;ON;;;;;N;;;;; 2951;UP BARB LEFT DOWN BARB LEFT HARPOON;Sm;0;ON;;;;;N;;;;; 2952;LEFTWARDS HARPOON WITH BARB UP TO BAR;Sm;0;ON;;;;;N;;;;; 2953;RIGHTWARDS HARPOON WITH BARB UP TO BAR;Sm;0;ON;;;;;N;;;;; 2954;UPWARDS HARPOON WITH BARB RIGHT TO BAR;Sm;0;ON;;;;;N;;;;; 2955;DOWNWARDS HARPOON WITH BARB RIGHT TO BAR;Sm;0;ON;;;;;N;;;;; 2956;LEFTWARDS HARPOON WITH BARB DOWN TO BAR;Sm;0;ON;;;;;N;;;;; 2957;RIGHTWARDS HARPOON WITH BARB DOWN TO BAR;Sm;0;ON;;;;;N;;;;; 2958;UPWARDS HARPOON WITH BARB LEFT TO BAR;Sm;0;ON;;;;;N;;;;; 2959;DOWNWARDS HARPOON WITH BARB LEFT TO BAR;Sm;0;ON;;;;;N;;;;; 295A;LEFTWARDS HARPOON WITH BARB UP FROM BAR;Sm;0;ON;;;;;N;;;;; 295B;RIGHTWARDS HARPOON WITH BARB UP FROM BAR;Sm;0;ON;;;;;N;;;;; 295C;UPWARDS HARPOON WITH BARB RIGHT FROM BAR;Sm;0;ON;;;;;N;;;;; 295D;DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR;Sm;0;ON;;;;;N;;;;; 295E;LEFTWARDS HARPOON WITH BARB DOWN FROM BAR;Sm;0;ON;;;;;N;;;;; 295F;RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR;Sm;0;ON;;;;;N;;;;; 2960;UPWARDS HARPOON WITH BARB LEFT FROM BAR;Sm;0;ON;;;;;N;;;;; 2961;DOWNWARDS HARPOON WITH BARB LEFT FROM BAR;Sm;0;ON;;;;;N;;;;; 2962;LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;; 2963;UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;; 2964;RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;; 2965;DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;; 2966;LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP;Sm;0;ON;;;;;N;;;;; 2967;LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;; 2968;RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP;Sm;0;ON;;;;;N;;;;; 2969;RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;; 296A;LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH;Sm;0;ON;;;;;N;;;;; 296B;LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH;Sm;0;ON;;;;;N;;;;; 296C;RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH;Sm;0;ON;;;;;N;;;;; 296D;RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH;Sm;0;ON;;;;;N;;;;; 296E;UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;; 296F;DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;; 2970;RIGHT DOUBLE ARROW WITH ROUNDED HEAD;Sm;0;ON;;;;;N;;;;; 2971;EQUALS SIGN ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; 2972;TILDE OPERATOR ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; 2973;LEFTWARDS ARROW ABOVE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;; 2974;RIGHTWARDS ARROW ABOVE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;; 2975;RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;; 2976;LESS-THAN ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; 2977;LEFTWARDS ARROW THROUGH LESS-THAN;Sm;0;ON;;;;;N;;;;; 2978;GREATER-THAN ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; 2979;SUBSET ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; 297A;LEFTWARDS ARROW THROUGH SUBSET;Sm;0;ON;;;;;N;;;;; 297B;SUPERSET ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; 297C;LEFT FISH TAIL;Sm;0;ON;;;;;N;;;;; 297D;RIGHT FISH TAIL;Sm;0;ON;;;;;N;;;;; 297E;UP FISH TAIL;Sm;0;ON;;;;;N;;;;; 297F;DOWN FISH TAIL;Sm;0;ON;;;;;N;;;;; 2980;TRIPLE VERTICAL BAR DELIMITER;Sm;0;ON;;;;;N;;;;; 2981;Z NOTATION SPOT;Sm;0;ON;;;;;N;;;;; 2982;Z NOTATION TYPE COLON;Sm;0;ON;;;;;N;;;;; 2983;LEFT WHITE CURLY BRACKET;Ps;0;ON;;;;;Y;;;;; 2984;RIGHT WHITE CURLY BRACKET;Pe;0;ON;;;;;Y;;;;; 2985;LEFT WHITE PARENTHESIS;Ps;0;ON;;;;;Y;;;;; 2986;RIGHT WHITE PARENTHESIS;Pe;0;ON;;;;;Y;;;;; 2987;Z NOTATION LEFT IMAGE BRACKET;Ps;0;ON;;;;;Y;;;;; 2988;Z NOTATION RIGHT IMAGE BRACKET;Pe;0;ON;;;;;Y;;;;; 2989;Z NOTATION LEFT BINDING BRACKET;Ps;0;ON;;;;;Y;;;;; 298A;Z NOTATION RIGHT BINDING BRACKET;Pe;0;ON;;;;;Y;;;;; 298B;LEFT SQUARE BRACKET WITH UNDERBAR;Ps;0;ON;;;;;Y;;;;; 298C;RIGHT SQUARE BRACKET WITH UNDERBAR;Pe;0;ON;;;;;Y;;;;; 298D;LEFT SQUARE BRACKET WITH TICK IN TOP CORNER;Ps;0;ON;;;;;Y;;;;; 298E;RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Pe;0;ON;;;;;Y;;;;; 298F;LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Ps;0;ON;;;;;Y;;;;; 2990;RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER;Pe;0;ON;;;;;Y;;;;; 2991;LEFT ANGLE BRACKET WITH DOT;Ps;0;ON;;;;;Y;;;;; 2992;RIGHT ANGLE BRACKET WITH DOT;Pe;0;ON;;;;;Y;;;;; 2993;LEFT ARC LESS-THAN BRACKET;Ps;0;ON;;;;;Y;;;;; 2994;RIGHT ARC GREATER-THAN BRACKET;Pe;0;ON;;;;;Y;;;;; 2995;DOUBLE LEFT ARC GREATER-THAN BRACKET;Ps;0;ON;;;;;Y;;;;; 2996;DOUBLE RIGHT ARC LESS-THAN BRACKET;Pe;0;ON;;;;;Y;;;;; 2997;LEFT BLACK TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;;;;; 2998;RIGHT BLACK TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;;;;; 2999;DOTTED FENCE;Sm;0;ON;;;;;N;;;;; 299A;VERTICAL ZIGZAG LINE;Sm;0;ON;;;;;N;;;;; 299B;MEASURED ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;; 299C;RIGHT ANGLE VARIANT WITH SQUARE;Sm;0;ON;;;;;Y;;;;; 299D;MEASURED RIGHT ANGLE WITH DOT;Sm;0;ON;;;;;Y;;;;; 299E;ANGLE WITH S INSIDE;Sm;0;ON;;;;;Y;;;;; 299F;ACUTE ANGLE;Sm;0;ON;;;;;Y;;;;; 29A0;SPHERICAL ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;; 29A1;SPHERICAL ANGLE OPENING UP;Sm;0;ON;;;;;Y;;;;; 29A2;TURNED ANGLE;Sm;0;ON;;;;;Y;;;;; 29A3;REVERSED ANGLE;Sm;0;ON;;;;;Y;;;;; 29A4;ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; 29A5;REVERSED ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; 29A6;OBLIQUE ANGLE OPENING UP;Sm;0;ON;;;;;Y;;;;; 29A7;OBLIQUE ANGLE OPENING DOWN;Sm;0;ON;;;;;Y;;;;; 29A8;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT;Sm;0;ON;;;;;Y;;;;; 29A9;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT;Sm;0;ON;;;;;Y;;;;; 29AA;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT;Sm;0;ON;;;;;Y;;;;; 29AB;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT;Sm;0;ON;;;;;Y;;;;; 29AC;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP;Sm;0;ON;;;;;Y;;;;; 29AD;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP;Sm;0;ON;;;;;Y;;;;; 29AE;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN;Sm;0;ON;;;;;Y;;;;; 29AF;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN;Sm;0;ON;;;;;Y;;;;; 29B0;REVERSED EMPTY SET;Sm;0;ON;;;;;N;;;;; 29B1;EMPTY SET WITH OVERBAR;Sm;0;ON;;;;;N;;;;; 29B2;EMPTY SET WITH SMALL CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;; 29B3;EMPTY SET WITH RIGHT ARROW ABOVE;Sm;0;ON;;;;;N;;;;; 29B4;EMPTY SET WITH LEFT ARROW ABOVE;Sm;0;ON;;;;;N;;;;; 29B5;CIRCLE WITH HORIZONTAL BAR;Sm;0;ON;;;;;N;;;;; 29B6;CIRCLED VERTICAL BAR;Sm;0;ON;;;;;N;;;;; 29B7;CIRCLED PARALLEL;Sm;0;ON;;;;;N;;;;; 29B8;CIRCLED REVERSE SOLIDUS;Sm;0;ON;;;;;Y;;;;; 29B9;CIRCLED PERPENDICULAR;Sm;0;ON;;;;;N;;;;; 29BA;CIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTICAL BAR;Sm;0;ON;;;;;N;;;;; 29BB;CIRCLE WITH SUPERIMPOSED X;Sm;0;ON;;;;;N;;;;; 29BC;CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN;Sm;0;ON;;;;;N;;;;; 29BD;UP ARROW THROUGH CIRCLE;Sm;0;ON;;;;;N;;;;; 29BE;CIRCLED WHITE BULLET;Sm;0;ON;;;;;N;;;;; 29BF;CIRCLED BULLET;Sm;0;ON;;;;;N;;;;; 29C0;CIRCLED LESS-THAN;Sm;0;ON;;;;;Y;;;;; 29C1;CIRCLED GREATER-THAN;Sm;0;ON;;;;;Y;;;;; 29C2;CIRCLE WITH SMALL CIRCLE TO THE RIGHT;Sm;0;ON;;;;;Y;;;;; 29C3;CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT;Sm;0;ON;;;;;Y;;;;; 29C4;SQUARED RISING DIAGONAL SLASH;Sm;0;ON;;;;;Y;;;;; 29C5;SQUARED FALLING DIAGONAL SLASH;Sm;0;ON;;;;;Y;;;;; 29C6;SQUARED ASTERISK;Sm;0;ON;;;;;N;;;;; 29C7;SQUARED SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; 29C8;SQUARED SQUARE;Sm;0;ON;;;;;N;;;;; 29C9;TWO JOINED SQUARES;Sm;0;ON;;;;;Y;;;;; 29CA;TRIANGLE WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; 29CB;TRIANGLE WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; 29CC;S IN TRIANGLE;Sm;0;ON;;;;;N;;;;; 29CD;TRIANGLE WITH SERIFS AT BOTTOM;Sm;0;ON;;;;;N;;;;; 29CE;RIGHT TRIANGLE ABOVE LEFT TRIANGLE;Sm;0;ON;;;;;Y;;;;; 29CF;LEFT TRIANGLE BESIDE VERTICAL BAR;Sm;0;ON;;;;;Y;;;;; 29D0;VERTICAL BAR BESIDE RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;; 29D1;BOWTIE WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;; 29D2;BOWTIE WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;; 29D3;BLACK BOWTIE;Sm;0;ON;;;;;N;;;;; 29D4;TIMES WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;; 29D5;TIMES WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;; 29D6;WHITE HOURGLASS;Sm;0;ON;;;;;N;;;;; 29D7;BLACK HOURGLASS;Sm;0;ON;;;;;N;;;;; 29D8;LEFT WIGGLY FENCE;Ps;0;ON;;;;;Y;;;;; 29D9;RIGHT WIGGLY FENCE;Pe;0;ON;;;;;Y;;;;; 29DA;LEFT DOUBLE WIGGLY FENCE;Ps;0;ON;;;;;Y;;;;; 29DB;RIGHT DOUBLE WIGGLY FENCE;Pe;0;ON;;;;;Y;;;;; 29DC;INCOMPLETE INFINITY;Sm;0;ON;;;;;Y;;;;; 29DD;TIE OVER INFINITY;Sm;0;ON;;;;;N;;;;; 29DE;INFINITY NEGATED WITH VERTICAL BAR;Sm;0;ON;;;;;N;;;;; 29DF;DOUBLE-ENDED MULTIMAP;Sm;0;ON;;;;;N;;;;; 29E0;SQUARE WITH CONTOURED OUTLINE;Sm;0;ON;;;;;N;;;;; 29E1;INCREASES AS;Sm;0;ON;;;;;Y;;;;; 29E2;SHUFFLE PRODUCT;Sm;0;ON;;;;;N;;;;; 29E3;EQUALS SIGN AND SLANTED PARALLEL;Sm;0;ON;;;;;Y;;;;; 29E4;EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE;Sm;0;ON;;;;;Y;;;;; 29E5;IDENTICAL TO AND SLANTED PARALLEL;Sm;0;ON;;;;;Y;;;;; 29E6;GLEICH STARK;Sm;0;ON;;;;;N;;;;; 29E7;THERMODYNAMIC;Sm;0;ON;;;;;N;;;;; 29E8;DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;; 29E9;DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;; 29EA;BLACK DIAMOND WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;; 29EB;BLACK LOZENGE;Sm;0;ON;;;;;N;;;;; 29EC;WHITE CIRCLE WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;; 29ED;BLACK CIRCLE WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;; 29EE;ERROR-BARRED WHITE SQUARE;Sm;0;ON;;;;;N;;;;; 29EF;ERROR-BARRED BLACK SQUARE;Sm;0;ON;;;;;N;;;;; 29F0;ERROR-BARRED WHITE DIAMOND;Sm;0;ON;;;;;N;;;;; 29F1;ERROR-BARRED BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; 29F2;ERROR-BARRED WHITE CIRCLE;Sm;0;ON;;;;;N;;;;; 29F3;ERROR-BARRED BLACK CIRCLE;Sm;0;ON;;;;;N;;;;; 29F4;RULE-DELAYED;Sm;0;ON;;;;;Y;;;;; 29F5;REVERSE SOLIDUS OPERATOR;Sm;0;ON;;;;;Y;;;;; 29F6;SOLIDUS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; 29F7;REVERSE SOLIDUS WITH HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; 29F8;BIG SOLIDUS;Sm;0;ON;;;;;Y;;;;; 29F9;BIG REVERSE SOLIDUS;Sm;0;ON;;;;;Y;;;;; 29FA;DOUBLE PLUS;Sm;0;ON;;;;;N;;;;; 29FB;TRIPLE PLUS;Sm;0;ON;;;;;N;;;;; 29FC;LEFT-POINTING CURVED ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;; 29FD;RIGHT-POINTING CURVED ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;; 29FE;TINY;Sm;0;ON;;;;;N;;;;; 29FF;MINY;Sm;0;ON;;;;;N;;;;; 2A00;N-ARY CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;; 2A01;N-ARY CIRCLED PLUS OPERATOR;Sm;0;ON;;;;;N;;;;; 2A02;N-ARY CIRCLED TIMES OPERATOR;Sm;0;ON;;;;;N;;;;; 2A03;N-ARY UNION OPERATOR WITH DOT;Sm;0;ON;;;;;N;;;;; 2A04;N-ARY UNION OPERATOR WITH PLUS;Sm;0;ON;;;;;N;;;;; 2A05;N-ARY SQUARE INTERSECTION OPERATOR;Sm;0;ON;;;;;N;;;;; 2A06;N-ARY SQUARE UNION OPERATOR;Sm;0;ON;;;;;N;;;;; 2A07;TWO LOGICAL AND OPERATOR;Sm;0;ON;;;;;N;;;;; 2A08;TWO LOGICAL OR OPERATOR;Sm;0;ON;;;;;N;;;;; 2A09;N-ARY TIMES OPERATOR;Sm;0;ON;;;;;N;;;;; 2A0A;MODULO TWO SUM;Sm;0;ON;;;;;Y;;;;; 2A0B;SUMMATION WITH INTEGRAL;Sm;0;ON;;;;;Y;;;;; 2A0C;QUADRUPLE INTEGRAL OPERATOR;Sm;0;ON; 222B 222B 222B 222B;;;;Y;;;;; 2A0D;FINITE PART INTEGRAL;Sm;0;ON;;;;;Y;;;;; 2A0E;INTEGRAL WITH DOUBLE STROKE;Sm;0;ON;;;;;Y;;;;; 2A0F;INTEGRAL AVERAGE WITH SLASH;Sm;0;ON;;;;;Y;;;;; 2A10;CIRCULATION FUNCTION;Sm;0;ON;;;;;Y;;;;; 2A11;ANTICLOCKWISE INTEGRATION;Sm;0;ON;;;;;Y;;;;; 2A12;LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE;Sm;0;ON;;;;;Y;;;;; 2A13;LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE;Sm;0;ON;;;;;Y;;;;; 2A14;LINE INTEGRATION NOT INCLUDING THE POLE;Sm;0;ON;;;;;Y;;;;; 2A15;INTEGRAL AROUND A POINT OPERATOR;Sm;0;ON;;;;;Y;;;;; 2A16;QUATERNION INTEGRAL OPERATOR;Sm;0;ON;;;;;Y;;;;; 2A17;INTEGRAL WITH LEFTWARDS ARROW WITH HOOK;Sm;0;ON;;;;;Y;;;;; 2A18;INTEGRAL WITH TIMES SIGN;Sm;0;ON;;;;;Y;;;;; 2A19;INTEGRAL WITH INTERSECTION;Sm;0;ON;;;;;Y;;;;; 2A1A;INTEGRAL WITH UNION;Sm;0;ON;;;;;Y;;;;; 2A1B;INTEGRAL WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; 2A1C;INTEGRAL WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; 2A1D;JOIN;Sm;0;ON;;;;;N;;;;; 2A1E;LARGE LEFT TRIANGLE OPERATOR;Sm;0;ON;;;;;Y;;;;; 2A1F;Z NOTATION SCHEMA COMPOSITION;Sm;0;ON;;;;;Y;;;;; 2A20;Z NOTATION SCHEMA PIPING;Sm;0;ON;;;;;Y;;;;; 2A21;Z NOTATION SCHEMA PROJECTION;Sm;0;ON;;;;;Y;;;;; 2A22;PLUS SIGN WITH SMALL CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;; 2A23;PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE;Sm;0;ON;;;;;N;;;;; 2A24;PLUS SIGN WITH TILDE ABOVE;Sm;0;ON;;;;;Y;;;;; 2A25;PLUS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;; 2A26;PLUS SIGN WITH TILDE BELOW;Sm;0;ON;;;;;Y;;;;; 2A27;PLUS SIGN WITH SUBSCRIPT TWO;Sm;0;ON;;;;;N;;;;; 2A28;PLUS SIGN WITH BLACK TRIANGLE;Sm;0;ON;;;;;N;;;;; 2A29;MINUS SIGN WITH COMMA ABOVE;Sm;0;ON;;;;;Y;;;;; 2A2A;MINUS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;; 2A2B;MINUS SIGN WITH FALLING DOTS;Sm;0;ON;;;;;Y;;;;; 2A2C;MINUS SIGN WITH RISING DOTS;Sm;0;ON;;;;;Y;;;;; 2A2D;PLUS SIGN IN LEFT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;; 2A2E;PLUS SIGN IN RIGHT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;; 2A2F;VECTOR OR CROSS PRODUCT;Sm;0;ON;;;;;N;;;;; 2A30;MULTIPLICATION SIGN WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; 2A31;MULTIPLICATION SIGN WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; 2A32;SEMIDIRECT PRODUCT WITH BOTTOM CLOSED;Sm;0;ON;;;;;N;;;;; 2A33;SMASH PRODUCT;Sm;0;ON;;;;;N;;;;; 2A34;MULTIPLICATION SIGN IN LEFT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;; 2A35;MULTIPLICATION SIGN IN RIGHT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;; 2A36;CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT;Sm;0;ON;;;;;N;;;;; 2A37;MULTIPLICATION SIGN IN DOUBLE CIRCLE;Sm;0;ON;;;;;N;;;;; 2A38;CIRCLED DIVISION SIGN;Sm;0;ON;;;;;N;;;;; 2A39;PLUS SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;; 2A3A;MINUS SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;; 2A3B;MULTIPLICATION SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;; 2A3C;INTERIOR PRODUCT;Sm;0;ON;;;;;Y;;;;; 2A3D;RIGHTHAND INTERIOR PRODUCT;Sm;0;ON;;;;;Y;;;;; 2A3E;Z NOTATION RELATIONAL COMPOSITION;Sm;0;ON;;;;;Y;;;;; 2A3F;AMALGAMATION OR COPRODUCT;Sm;0;ON;;;;;N;;;;; 2A40;INTERSECTION WITH DOT;Sm;0;ON;;;;;N;;;;; 2A41;UNION WITH MINUS SIGN;Sm;0;ON;;;;;N;;;;; 2A42;UNION WITH OVERBAR;Sm;0;ON;;;;;N;;;;; 2A43;INTERSECTION WITH OVERBAR;Sm;0;ON;;;;;N;;;;; 2A44;INTERSECTION WITH LOGICAL AND;Sm;0;ON;;;;;N;;;;; 2A45;UNION WITH LOGICAL OR;Sm;0;ON;;;;;N;;;;; 2A46;UNION ABOVE INTERSECTION;Sm;0;ON;;;;;N;;;;; 2A47;INTERSECTION ABOVE UNION;Sm;0;ON;;;;;N;;;;; 2A48;UNION ABOVE BAR ABOVE INTERSECTION;Sm;0;ON;;;;;N;;;;; 2A49;INTERSECTION ABOVE BAR ABOVE UNION;Sm;0;ON;;;;;N;;;;; 2A4A;UNION BESIDE AND JOINED WITH UNION;Sm;0;ON;;;;;N;;;;; 2A4B;INTERSECTION BESIDE AND JOINED WITH INTERSECTION;Sm;0;ON;;;;;N;;;;; 2A4C;CLOSED UNION WITH SERIFS;Sm;0;ON;;;;;N;;;;; 2A4D;CLOSED INTERSECTION WITH SERIFS;Sm;0;ON;;;;;N;;;;; 2A4E;DOUBLE SQUARE INTERSECTION;Sm;0;ON;;;;;N;;;;; 2A4F;DOUBLE SQUARE UNION;Sm;0;ON;;;;;N;;;;; 2A50;CLOSED UNION WITH SERIFS AND SMASH PRODUCT;Sm;0;ON;;;;;N;;;;; 2A51;LOGICAL AND WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; 2A52;LOGICAL OR WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; 2A53;DOUBLE LOGICAL AND;Sm;0;ON;;;;;N;;;;; 2A54;DOUBLE LOGICAL OR;Sm;0;ON;;;;;N;;;;; 2A55;TWO INTERSECTING LOGICAL AND;Sm;0;ON;;;;;N;;;;; 2A56;TWO INTERSECTING LOGICAL OR;Sm;0;ON;;;;;N;;;;; 2A57;SLOPING LARGE OR;Sm;0;ON;;;;;Y;;;;; 2A58;SLOPING LARGE AND;Sm;0;ON;;;;;Y;;;;; 2A59;LOGICAL OR OVERLAPPING LOGICAL AND;Sm;0;ON;;;;;N;;;;; 2A5A;LOGICAL AND WITH MIDDLE STEM;Sm;0;ON;;;;;N;;;;; 2A5B;LOGICAL OR WITH MIDDLE STEM;Sm;0;ON;;;;;N;;;;; 2A5C;LOGICAL AND WITH HORIZONTAL DASH;Sm;0;ON;;;;;N;;;;; 2A5D;LOGICAL OR WITH HORIZONTAL DASH;Sm;0;ON;;;;;N;;;;; 2A5E;LOGICAL AND WITH DOUBLE OVERBAR;Sm;0;ON;;;;;N;;;;; 2A5F;LOGICAL AND WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; 2A60;LOGICAL AND WITH DOUBLE UNDERBAR;Sm;0;ON;;;;;N;;;;; 2A61;SMALL VEE WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; 2A62;LOGICAL OR WITH DOUBLE OVERBAR;Sm;0;ON;;;;;N;;;;; 2A63;LOGICAL OR WITH DOUBLE UNDERBAR;Sm;0;ON;;;;;N;;;;; 2A64;Z NOTATION DOMAIN ANTIRESTRICTION;Sm;0;ON;;;;;Y;;;;; 2A65;Z NOTATION RANGE ANTIRESTRICTION;Sm;0;ON;;;;;Y;;;;; 2A66;EQUALS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;; 2A67;IDENTICAL WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; 2A68;TRIPLE HORIZONTAL BAR WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 2A69;TRIPLE HORIZONTAL BAR WITH TRIPLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; 2A6A;TILDE OPERATOR WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; 2A6B;TILDE OPERATOR WITH RISING DOTS;Sm;0;ON;;;;;Y;;;;; 2A6C;SIMILAR MINUS SIMILAR;Sm;0;ON;;;;;Y;;;;; 2A6D;CONGRUENT WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; 2A6E;EQUALS WITH ASTERISK;Sm;0;ON;;;;;N;;;;; 2A6F;ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT;Sm;0;ON;;;;;Y;;;;; 2A70;APPROXIMATELY EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2A71;EQUALS SIGN ABOVE PLUS SIGN;Sm;0;ON;;;;;N;;;;; 2A72;PLUS SIGN ABOVE EQUALS SIGN;Sm;0;ON;;;;;N;;;;; 2A73;EQUALS SIGN ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; 2A74;DOUBLE COLON EQUAL;Sm;0;ON; 003A 003A 003D;;;;Y;;;;; 2A75;TWO CONSECUTIVE EQUALS SIGNS;Sm;0;ON; 003D 003D;;;;N;;;;; 2A76;THREE CONSECUTIVE EQUALS SIGNS;Sm;0;ON; 003D 003D 003D;;;;N;;;;; 2A77;EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW;Sm;0;ON;;;;;N;;;;; 2A78;EQUIVALENT WITH FOUR DOTS ABOVE;Sm;0;ON;;;;;N;;;;; 2A79;LESS-THAN WITH CIRCLE INSIDE;Sm;0;ON;;;;;Y;;;;; 2A7A;GREATER-THAN WITH CIRCLE INSIDE;Sm;0;ON;;;;;Y;;;;; 2A7B;LESS-THAN WITH QUESTION MARK ABOVE;Sm;0;ON;;;;;Y;;;;; 2A7C;GREATER-THAN WITH QUESTION MARK ABOVE;Sm;0;ON;;;;;Y;;;;; 2A7D;LESS-THAN OR SLANTED EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2A7E;GREATER-THAN OR SLANTED EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2A7F;LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;; 2A80;GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;; 2A81;LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; 2A82;GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; 2A83;LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT;Sm;0;ON;;;;;Y;;;;; 2A84;GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT;Sm;0;ON;;;;;Y;;;;; 2A85;LESS-THAN OR APPROXIMATE;Sm;0;ON;;;;;Y;;;;; 2A86;GREATER-THAN OR APPROXIMATE;Sm;0;ON;;;;;Y;;;;; 2A87;LESS-THAN AND SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2A88;GREATER-THAN AND SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2A89;LESS-THAN AND NOT APPROXIMATE;Sm;0;ON;;;;;Y;;;;; 2A8A;GREATER-THAN AND NOT APPROXIMATE;Sm;0;ON;;;;;Y;;;;; 2A8B;LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN;Sm;0;ON;;;;;Y;;;;; 2A8C;GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN;Sm;0;ON;;;;;Y;;;;; 2A8D;LESS-THAN ABOVE SIMILAR OR EQUAL;Sm;0;ON;;;;;Y;;;;; 2A8E;GREATER-THAN ABOVE SIMILAR OR EQUAL;Sm;0;ON;;;;;Y;;;;; 2A8F;LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN;Sm;0;ON;;;;;Y;;;;; 2A90;GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN;Sm;0;ON;;;;;Y;;;;; 2A91;LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL;Sm;0;ON;;;;;Y;;;;; 2A92;GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL;Sm;0;ON;;;;;Y;;;;; 2A93;LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;; 2A94;GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;; 2A95;SLANTED EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;; 2A96;SLANTED EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;; 2A97;SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;; 2A98;SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;; 2A99;DOUBLE-LINE EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;; 2A9A;DOUBLE-LINE EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;; 2A9B;DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;; 2A9C;DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;; 2A9D;SIMILAR OR LESS-THAN;Sm;0;ON;;;;;Y;;;;; 2A9E;SIMILAR OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;; 2A9F;SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; 2AA0;SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; 2AA1;DOUBLE NESTED LESS-THAN;Sm;0;ON;;;;;Y;;;;; 2AA2;DOUBLE NESTED GREATER-THAN;Sm;0;ON;;;;;Y;;;;; 2AA3;DOUBLE NESTED LESS-THAN WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; 2AA4;GREATER-THAN OVERLAPPING LESS-THAN;Sm;0;ON;;;;;N;;;;; 2AA5;GREATER-THAN BESIDE LESS-THAN;Sm;0;ON;;;;;N;;;;; 2AA6;LESS-THAN CLOSED BY CURVE;Sm;0;ON;;;;;Y;;;;; 2AA7;GREATER-THAN CLOSED BY CURVE;Sm;0;ON;;;;;Y;;;;; 2AA8;LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;; 2AA9;GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;; 2AAA;SMALLER THAN;Sm;0;ON;;;;;Y;;;;; 2AAB;LARGER THAN;Sm;0;ON;;;;;Y;;;;; 2AAC;SMALLER THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2AAD;LARGER THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2AAE;EQUALS SIGN WITH BUMPY ABOVE;Sm;0;ON;;;;;N;;;;; 2AAF;PRECEDES ABOVE SINGLE-LINE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; 2AB0;SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; 2AB1;PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2AB2;SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2AB3;PRECEDES ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; 2AB4;SUCCEEDS ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; 2AB5;PRECEDES ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2AB6;SUCCEEDS ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2AB7;PRECEDES ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2AB8;SUCCEEDS ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2AB9;PRECEDES ABOVE NOT ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2ABA;SUCCEEDS ABOVE NOT ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2ABB;DOUBLE PRECEDES;Sm;0;ON;;;;;Y;;;;; 2ABC;DOUBLE SUCCEEDS;Sm;0;ON;;;;;Y;;;;; 2ABD;SUBSET WITH DOT;Sm;0;ON;;;;;Y;;;;; 2ABE;SUPERSET WITH DOT;Sm;0;ON;;;;;Y;;;;; 2ABF;SUBSET WITH PLUS SIGN BELOW;Sm;0;ON;;;;;Y;;;;; 2AC0;SUPERSET WITH PLUS SIGN BELOW;Sm;0;ON;;;;;Y;;;;; 2AC1;SUBSET WITH MULTIPLICATION SIGN BELOW;Sm;0;ON;;;;;Y;;;;; 2AC2;SUPERSET WITH MULTIPLICATION SIGN BELOW;Sm;0;ON;;;;;Y;;;;; 2AC3;SUBSET OF OR EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; 2AC4;SUPERSET OF OR EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; 2AC5;SUBSET OF ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; 2AC6;SUPERSET OF ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; 2AC7;SUBSET OF ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; 2AC8;SUPERSET OF ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; 2AC9;SUBSET OF ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2ACA;SUPERSET OF ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2ACB;SUBSET OF ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2ACC;SUPERSET OF ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2ACD;SQUARE LEFT OPEN BOX OPERATOR;Sm;0;ON;;;;;Y;;;;; 2ACE;SQUARE RIGHT OPEN BOX OPERATOR;Sm;0;ON;;;;;Y;;;;; 2ACF;CLOSED SUBSET;Sm;0;ON;;;;;Y;;;;; 2AD0;CLOSED SUPERSET;Sm;0;ON;;;;;Y;;;;; 2AD1;CLOSED SUBSET OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2AD2;CLOSED SUPERSET OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2AD3;SUBSET ABOVE SUPERSET;Sm;0;ON;;;;;Y;;;;; 2AD4;SUPERSET ABOVE SUBSET;Sm;0;ON;;;;;Y;;;;; 2AD5;SUBSET ABOVE SUBSET;Sm;0;ON;;;;;Y;;;;; 2AD6;SUPERSET ABOVE SUPERSET;Sm;0;ON;;;;;Y;;;;; 2AD7;SUPERSET BESIDE SUBSET;Sm;0;ON;;;;;N;;;;; 2AD8;SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET;Sm;0;ON;;;;;N;;;;; 2AD9;ELEMENT OF OPENING DOWNWARDS;Sm;0;ON;;;;;N;;;;; 2ADA;PITCHFORK WITH TEE TOP;Sm;0;ON;;;;;N;;;;; 2ADB;TRANSVERSAL INTERSECTION;Sm;0;ON;;;;;N;;;;; 2ADC;FORKING;Sm;0;ON;2ADD 0338;;;;Y;;not independent;;; 2ADD;NONFORKING;Sm;0;ON;;;;;N;;independent;;; 2ADE;SHORT LEFT TACK;Sm;0;ON;;;;;Y;;;;; 2ADF;SHORT DOWN TACK;Sm;0;ON;;;;;N;;;;; 2AE0;SHORT UP TACK;Sm;0;ON;;;;;N;;;;; 2AE1;PERPENDICULAR WITH S;Sm;0;ON;;;;;N;;;;; 2AE2;VERTICAL BAR TRIPLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;; 2AE3;DOUBLE VERTICAL BAR LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;; 2AE4;VERTICAL BAR DOUBLE LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;; 2AE5;DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;; 2AE6;LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL;Sm;0;ON;;;;;Y;;;;; 2AE7;SHORT DOWN TACK WITH OVERBAR;Sm;0;ON;;;;;N;;;;; 2AE8;SHORT UP TACK WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; 2AE9;SHORT UP TACK ABOVE SHORT DOWN TACK;Sm;0;ON;;;;;N;;;;; 2AEA;DOUBLE DOWN TACK;Sm;0;ON;;;;;N;;;;; 2AEB;DOUBLE UP TACK;Sm;0;ON;;;;;N;;;;; 2AEC;DOUBLE STROKE NOT SIGN;Sm;0;ON;;;;;Y;;;;; 2AED;REVERSED DOUBLE STROKE NOT SIGN;Sm;0;ON;;;;;Y;;;;; 2AEE;DOES NOT DIVIDE WITH REVERSED NEGATION SLASH;Sm;0;ON;;;;;Y;;;;; 2AEF;VERTICAL LINE WITH CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;; 2AF0;VERTICAL LINE WITH CIRCLE BELOW;Sm;0;ON;;;;;N;;;;; 2AF1;DOWN TACK WITH CIRCLE BELOW;Sm;0;ON;;;;;N;;;;; 2AF2;PARALLEL WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; 2AF3;PARALLEL WITH TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; 2AF4;TRIPLE VERTICAL BAR BINARY RELATION;Sm;0;ON;;;;;N;;;;; 2AF5;TRIPLE VERTICAL BAR WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; 2AF6;TRIPLE COLON OPERATOR;Sm;0;ON;;;;;N;;;;; 2AF7;TRIPLE NESTED LESS-THAN;Sm;0;ON;;;;;Y;;;;; 2AF8;TRIPLE NESTED GREATER-THAN;Sm;0;ON;;;;;Y;;;;; 2AF9;DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2AFA;DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; 2AFB;TRIPLE SOLIDUS BINARY RELATION;Sm;0;ON;;;;;Y;;;;; 2AFC;LARGE TRIPLE VERTICAL BAR OPERATOR;Sm;0;ON;;;;;N;;;;; 2AFD;DOUBLE SOLIDUS OPERATOR;Sm;0;ON;;;;;Y;;;;; 2AFE;WHITE VERTICAL BAR;Sm;0;ON;;;;;N;;;;; 2AFF;N-ARY WHITE VERTICAL BAR;Sm;0;ON;;;;;N;;;;; 2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;; 2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;; 2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;; 2E83;CJK RADICAL SECOND TWO;So;0;ON;;;;;N;;;;; 2E84;CJK RADICAL SECOND THREE;So;0;ON;;;;;N;;;;; 2E85;CJK RADICAL PERSON;So;0;ON;;;;;N;;;;; 2E86;CJK RADICAL BOX;So;0;ON;;;;;N;;;;; 2E87;CJK RADICAL TABLE;So;0;ON;;;;;N;;;;; 2E88;CJK RADICAL KNIFE ONE;So;0;ON;;;;;N;;;;; 2E89;CJK RADICAL KNIFE TWO;So;0;ON;;;;;N;;;;; 2E8A;CJK RADICAL DIVINATION;So;0;ON;;;;;N;;;;; 2E8B;CJK RADICAL SEAL;So;0;ON;;;;;N;;;;; 2E8C;CJK RADICAL SMALL ONE;So;0;ON;;;;;N;;;;; 2E8D;CJK RADICAL SMALL TWO;So;0;ON;;;;;N;;;;; 2E8E;CJK RADICAL LAME ONE;So;0;ON;;;;;N;;;;; 2E8F;CJK RADICAL LAME TWO;So;0;ON;;;;;N;;;;; 2E90;CJK RADICAL LAME THREE;So;0;ON;;;;;N;;;;; 2E91;CJK RADICAL LAME FOUR;So;0;ON;;;;;N;;;;; 2E92;CJK RADICAL SNAKE;So;0;ON;;;;;N;;;;; 2E93;CJK RADICAL THREAD;So;0;ON;;;;;N;;;;; 2E94;CJK RADICAL SNOUT ONE;So;0;ON;;;;;N;;;;; 2E95;CJK RADICAL SNOUT TWO;So;0;ON;;;;;N;;;;; 2E96;CJK RADICAL HEART ONE;So;0;ON;;;;;N;;;;; 2E97;CJK RADICAL HEART TWO;So;0;ON;;;;;N;;;;; 2E98;CJK RADICAL HAND;So;0;ON;;;;;N;;;;; 2E99;CJK RADICAL RAP;So;0;ON;;;;;N;;;;; 2E9B;CJK RADICAL CHOKE;So;0;ON;;;;;N;;;;; 2E9C;CJK RADICAL SUN;So;0;ON;;;;;N;;;;; 2E9D;CJK RADICAL MOON;So;0;ON;;;;;N;;;;; 2E9E;CJK RADICAL DEATH;So;0;ON;;;;;N;;;;; 2E9F;CJK RADICAL MOTHER;So;0;ON; 6BCD;;;;N;;;;; 2EA0;CJK RADICAL CIVILIAN;So;0;ON;;;;;N;;;;; 2EA1;CJK RADICAL WATER ONE;So;0;ON;;;;;N;;;;; 2EA2;CJK RADICAL WATER TWO;So;0;ON;;;;;N;;;;; 2EA3;CJK RADICAL FIRE;So;0;ON;;;;;N;;;;; 2EA4;CJK RADICAL PAW ONE;So;0;ON;;;;;N;;;;; 2EA5;CJK RADICAL PAW TWO;So;0;ON;;;;;N;;;;; 2EA6;CJK RADICAL SIMPLIFIED HALF TREE TRUNK;So;0;ON;;;;;N;;;;; 2EA7;CJK RADICAL COW;So;0;ON;;;;;N;;;;; 2EA8;CJK RADICAL DOG;So;0;ON;;;;;N;;;;; 2EA9;CJK RADICAL JADE;So;0;ON;;;;;N;;;;; 2EAA;CJK RADICAL BOLT OF CLOTH;So;0;ON;;;;;N;;;;; 2EAB;CJK RADICAL EYE;So;0;ON;;;;;N;;;;; 2EAC;CJK RADICAL SPIRIT ONE;So;0;ON;;;;;N;;;;; 2EAD;CJK RADICAL SPIRIT TWO;So;0;ON;;;;;N;;;;; 2EAE;CJK RADICAL BAMBOO;So;0;ON;;;;;N;;;;; 2EAF;CJK RADICAL SILK;So;0;ON;;;;;N;;;;; 2EB0;CJK RADICAL C-SIMPLIFIED SILK;So;0;ON;;;;;N;;;;; 2EB1;CJK RADICAL NET ONE;So;0;ON;;;;;N;;;;; 2EB2;CJK RADICAL NET TWO;So;0;ON;;;;;N;;;;; 2EB3;CJK RADICAL NET THREE;So;0;ON;;;;;N;;;;; 2EB4;CJK RADICAL NET FOUR;So;0;ON;;;;;N;;;;; 2EB5;CJK RADICAL MESH;So;0;ON;;;;;N;;;;; 2EB6;CJK RADICAL SHEEP;So;0;ON;;;;;N;;;;; 2EB7;CJK RADICAL RAM;So;0;ON;;;;;N;;;;; 2EB8;CJK RADICAL EWE;So;0;ON;;;;;N;;;;; 2EB9;CJK RADICAL OLD;So;0;ON;;;;;N;;;;; 2EBA;CJK RADICAL BRUSH ONE;So;0;ON;;;;;N;;;;; 2EBB;CJK RADICAL BRUSH TWO;So;0;ON;;;;;N;;;;; 2EBC;CJK RADICAL MEAT;So;0;ON;;;;;N;;;;; 2EBD;CJK RADICAL MORTAR;So;0;ON;;;;;N;;;;; 2EBE;CJK RADICAL GRASS ONE;So;0;ON;;;;;N;;;;; 2EBF;CJK RADICAL GRASS TWO;So;0;ON;;;;;N;;;;; 2EC0;CJK RADICAL GRASS THREE;So;0;ON;;;;;N;;;;; 2EC1;CJK RADICAL TIGER;So;0;ON;;;;;N;;;;; 2EC2;CJK RADICAL CLOTHES;So;0;ON;;;;;N;;;;; 2EC3;CJK RADICAL WEST ONE;So;0;ON;;;;;N;;;;; 2EC4;CJK RADICAL WEST TWO;So;0;ON;;;;;N;;;;; 2EC5;CJK RADICAL C-SIMPLIFIED SEE;So;0;ON;;;;;N;;;;; 2EC6;CJK RADICAL SIMPLIFIED HORN;So;0;ON;;;;;N;;;;; 2EC7;CJK RADICAL HORN;So;0;ON;;;;;N;;;;; 2EC8;CJK RADICAL C-SIMPLIFIED SPEECH;So;0;ON;;;;;N;;;;; 2EC9;CJK RADICAL C-SIMPLIFIED SHELL;So;0;ON;;;;;N;;;;; 2ECA;CJK RADICAL FOOT;So;0;ON;;;;;N;;;;; 2ECB;CJK RADICAL C-SIMPLIFIED CART;So;0;ON;;;;;N;;;;; 2ECC;CJK RADICAL SIMPLIFIED WALK;So;0;ON;;;;;N;;;;; 2ECD;CJK RADICAL WALK ONE;So;0;ON;;;;;N;;;;; 2ECE;CJK RADICAL WALK TWO;So;0;ON;;;;;N;;;;; 2ECF;CJK RADICAL CITY;So;0;ON;;;;;N;;;;; 2ED0;CJK RADICAL C-SIMPLIFIED GOLD;So;0;ON;;;;;N;;;;; 2ED1;CJK RADICAL LONG ONE;So;0;ON;;;;;N;;;;; 2ED2;CJK RADICAL LONG TWO;So;0;ON;;;;;N;;;;; 2ED3;CJK RADICAL C-SIMPLIFIED LONG;So;0;ON;;;;;N;;;;; 2ED4;CJK RADICAL C-SIMPLIFIED GATE;So;0;ON;;;;;N;;;;; 2ED5;CJK RADICAL MOUND ONE;So;0;ON;;;;;N;;;;; 2ED6;CJK RADICAL MOUND TWO;So;0;ON;;;;;N;;;;; 2ED7;CJK RADICAL RAIN;So;0;ON;;;;;N;;;;; 2ED8;CJK RADICAL BLUE;So;0;ON;;;;;N;;;;; 2ED9;CJK RADICAL C-SIMPLIFIED TANNED LEATHER;So;0;ON;;;;;N;;;;; 2EDA;CJK RADICAL C-SIMPLIFIED LEAF;So;0;ON;;;;;N;;;;; 2EDB;CJK RADICAL C-SIMPLIFIED WIND;So;0;ON;;;;;N;;;;; 2EDC;CJK RADICAL C-SIMPLIFIED FLY;So;0;ON;;;;;N;;;;; 2EDD;CJK RADICAL EAT ONE;So;0;ON;;;;;N;;;;; 2EDE;CJK RADICAL EAT TWO;So;0;ON;;;;;N;;;;; 2EDF;CJK RADICAL EAT THREE;So;0;ON;;;;;N;;;;; 2EE0;CJK RADICAL C-SIMPLIFIED EAT;So;0;ON;;;;;N;;;;; 2EE1;CJK RADICAL HEAD;So;0;ON;;;;;N;;;;; 2EE2;CJK RADICAL C-SIMPLIFIED HORSE;So;0;ON;;;;;N;;;;; 2EE3;CJK RADICAL BONE;So;0;ON;;;;;N;;;;; 2EE4;CJK RADICAL GHOST;So;0;ON;;;;;N;;;;; 2EE5;CJK RADICAL C-SIMPLIFIED FISH;So;0;ON;;;;;N;;;;; 2EE6;CJK RADICAL C-SIMPLIFIED BIRD;So;0;ON;;;;;N;;;;; 2EE7;CJK RADICAL C-SIMPLIFIED SALT;So;0;ON;;;;;N;;;;; 2EE8;CJK RADICAL SIMPLIFIED WHEAT;So;0;ON;;;;;N;;;;; 2EE9;CJK RADICAL SIMPLIFIED YELLOW;So;0;ON;;;;;N;;;;; 2EEA;CJK RADICAL C-SIMPLIFIED FROG;So;0;ON;;;;;N;;;;; 2EEB;CJK RADICAL J-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;; 2EEC;CJK RADICAL C-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;; 2EED;CJK RADICAL J-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;; 2EEE;CJK RADICAL C-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;; 2EEF;CJK RADICAL J-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;; 2EF0;CJK RADICAL C-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;; 2EF1;CJK RADICAL TURTLE;So;0;ON;;;;;N;;;;; 2EF2;CJK RADICAL J-SIMPLIFIED TURTLE;So;0;ON;;;;;N;;;;; 2EF3;CJK RADICAL C-SIMPLIFIED TURTLE;So;0;ON; 9F9F;;;;N;;;;; 2F00;KANGXI RADICAL ONE;So;0;ON; 4E00;;;;N;;;;; 2F01;KANGXI RADICAL LINE;So;0;ON; 4E28;;;;N;;;;; 2F02;KANGXI RADICAL DOT;So;0;ON; 4E36;;;;N;;;;; 2F03;KANGXI RADICAL SLASH;So;0;ON; 4E3F;;;;N;;;;; 2F04;KANGXI RADICAL SECOND;So;0;ON; 4E59;;;;N;;;;; 2F05;KANGXI RADICAL HOOK;So;0;ON; 4E85;;;;N;;;;; 2F06;KANGXI RADICAL TWO;So;0;ON; 4E8C;;;;N;;;;; 2F07;KANGXI RADICAL LID;So;0;ON; 4EA0;;;;N;;;;; 2F08;KANGXI RADICAL MAN;So;0;ON; 4EBA;;;;N;;;;; 2F09;KANGXI RADICAL LEGS;So;0;ON; 513F;;;;N;;;;; 2F0A;KANGXI RADICAL ENTER;So;0;ON; 5165;;;;N;;;;; 2F0B;KANGXI RADICAL EIGHT;So;0;ON; 516B;;;;N;;;;; 2F0C;KANGXI RADICAL DOWN BOX;So;0;ON; 5182;;;;N;;;;; 2F0D;KANGXI RADICAL COVER;So;0;ON; 5196;;;;N;;;;; 2F0E;KANGXI RADICAL ICE;So;0;ON; 51AB;;;;N;;;;; 2F0F;KANGXI RADICAL TABLE;So;0;ON; 51E0;;;;N;;;;; 2F10;KANGXI RADICAL OPEN BOX;So;0;ON; 51F5;;;;N;;;;; 2F11;KANGXI RADICAL KNIFE;So;0;ON; 5200;;;;N;;;;; 2F12;KANGXI RADICAL POWER;So;0;ON; 529B;;;;N;;;;; 2F13;KANGXI RADICAL WRAP;So;0;ON; 52F9;;;;N;;;;; 2F14;KANGXI RADICAL SPOON;So;0;ON; 5315;;;;N;;;;; 2F15;KANGXI RADICAL RIGHT OPEN BOX;So;0;ON; 531A;;;;N;;;;; 2F16;KANGXI RADICAL HIDING ENCLOSURE;So;0;ON; 5338;;;;N;;;;; 2F17;KANGXI RADICAL TEN;So;0;ON; 5341;;;;N;;;;; 2F18;KANGXI RADICAL DIVINATION;So;0;ON; 535C;;;;N;;;;; 2F19;KANGXI RADICAL SEAL;So;0;ON; 5369;;;;N;;;;; 2F1A;KANGXI RADICAL CLIFF;So;0;ON; 5382;;;;N;;;;; 2F1B;KANGXI RADICAL PRIVATE;So;0;ON; 53B6;;;;N;;;;; 2F1C;KANGXI RADICAL AGAIN;So;0;ON; 53C8;;;;N;;;;; 2F1D;KANGXI RADICAL MOUTH;So;0;ON; 53E3;;;;N;;;;; 2F1E;KANGXI RADICAL ENCLOSURE;So;0;ON; 56D7;;;;N;;;;; 2F1F;KANGXI RADICAL EARTH;So;0;ON; 571F;;;;N;;;;; 2F20;KANGXI RADICAL SCHOLAR;So;0;ON; 58EB;;;;N;;;;; 2F21;KANGXI RADICAL GO;So;0;ON; 5902;;;;N;;;;; 2F22;KANGXI RADICAL GO SLOWLY;So;0;ON; 590A;;;;N;;;;; 2F23;KANGXI RADICAL EVENING;So;0;ON; 5915;;;;N;;;;; 2F24;KANGXI RADICAL BIG;So;0;ON; 5927;;;;N;;;;; 2F25;KANGXI RADICAL WOMAN;So;0;ON; 5973;;;;N;;;;; 2F26;KANGXI RADICAL CHILD;So;0;ON; 5B50;;;;N;;;;; 2F27;KANGXI RADICAL ROOF;So;0;ON; 5B80;;;;N;;;;; 2F28;KANGXI RADICAL INCH;So;0;ON; 5BF8;;;;N;;;;; 2F29;KANGXI RADICAL SMALL;So;0;ON; 5C0F;;;;N;;;;; 2F2A;KANGXI RADICAL LAME;So;0;ON; 5C22;;;;N;;;;; 2F2B;KANGXI RADICAL CORPSE;So;0;ON; 5C38;;;;N;;;;; 2F2C;KANGXI RADICAL SPROUT;So;0;ON; 5C6E;;;;N;;;;; 2F2D;KANGXI RADICAL MOUNTAIN;So;0;ON; 5C71;;;;N;;;;; 2F2E;KANGXI RADICAL RIVER;So;0;ON; 5DDB;;;;N;;;;; 2F2F;KANGXI RADICAL WORK;So;0;ON; 5DE5;;;;N;;;;; 2F30;KANGXI RADICAL ONESELF;So;0;ON; 5DF1;;;;N;;;;; 2F31;KANGXI RADICAL TURBAN;So;0;ON; 5DFE;;;;N;;;;; 2F32;KANGXI RADICAL DRY;So;0;ON; 5E72;;;;N;;;;; 2F33;KANGXI RADICAL SHORT THREAD;So;0;ON; 5E7A;;;;N;;;;; 2F34;KANGXI RADICAL DOTTED CLIFF;So;0;ON; 5E7F;;;;N;;;;; 2F35;KANGXI RADICAL LONG STRIDE;So;0;ON; 5EF4;;;;N;;;;; 2F36;KANGXI RADICAL TWO HANDS;So;0;ON; 5EFE;;;;N;;;;; 2F37;KANGXI RADICAL SHOOT;So;0;ON; 5F0B;;;;N;;;;; 2F38;KANGXI RADICAL BOW;So;0;ON; 5F13;;;;N;;;;; 2F39;KANGXI RADICAL SNOUT;So;0;ON; 5F50;;;;N;;;;; 2F3A;KANGXI RADICAL BRISTLE;So;0;ON; 5F61;;;;N;;;;; 2F3B;KANGXI RADICAL STEP;So;0;ON; 5F73;;;;N;;;;; 2F3C;KANGXI RADICAL HEART;So;0;ON; 5FC3;;;;N;;;;; 2F3D;KANGXI RADICAL HALBERD;So;0;ON; 6208;;;;N;;;;; 2F3E;KANGXI RADICAL DOOR;So;0;ON; 6236;;;;N;;;;; 2F3F;KANGXI RADICAL HAND;So;0;ON; 624B;;;;N;;;;; 2F40;KANGXI RADICAL BRANCH;So;0;ON; 652F;;;;N;;;;; 2F41;KANGXI RADICAL RAP;So;0;ON; 6534;;;;N;;;;; 2F42;KANGXI RADICAL SCRIPT;So;0;ON; 6587;;;;N;;;;; 2F43;KANGXI RADICAL DIPPER;So;0;ON; 6597;;;;N;;;;; 2F44;KANGXI RADICAL AXE;So;0;ON; 65A4;;;;N;;;;; 2F45;KANGXI RADICAL SQUARE;So;0;ON; 65B9;;;;N;;;;; 2F46;KANGXI RADICAL NOT;So;0;ON; 65E0;;;;N;;;;; 2F47;KANGXI RADICAL SUN;So;0;ON; 65E5;;;;N;;;;; 2F48;KANGXI RADICAL SAY;So;0;ON; 66F0;;;;N;;;;; 2F49;KANGXI RADICAL MOON;So;0;ON; 6708;;;;N;;;;; 2F4A;KANGXI RADICAL TREE;So;0;ON; 6728;;;;N;;;;; 2F4B;KANGXI RADICAL LACK;So;0;ON; 6B20;;;;N;;;;; 2F4C;KANGXI RADICAL STOP;So;0;ON; 6B62;;;;N;;;;; 2F4D;KANGXI RADICAL DEATH;So;0;ON; 6B79;;;;N;;;;; 2F4E;KANGXI RADICAL WEAPON;So;0;ON; 6BB3;;;;N;;;;; 2F4F;KANGXI RADICAL DO NOT;So;0;ON; 6BCB;;;;N;;;;; 2F50;KANGXI RADICAL COMPARE;So;0;ON; 6BD4;;;;N;;;;; 2F51;KANGXI RADICAL FUR;So;0;ON; 6BDB;;;;N;;;;; 2F52;KANGXI RADICAL CLAN;So;0;ON; 6C0F;;;;N;;;;; 2F53;KANGXI RADICAL STEAM;So;0;ON; 6C14;;;;N;;;;; 2F54;KANGXI RADICAL WATER;So;0;ON; 6C34;;;;N;;;;; 2F55;KANGXI RADICAL FIRE;So;0;ON; 706B;;;;N;;;;; 2F56;KANGXI RADICAL CLAW;So;0;ON; 722A;;;;N;;;;; 2F57;KANGXI RADICAL FATHER;So;0;ON; 7236;;;;N;;;;; 2F58;KANGXI RADICAL DOUBLE X;So;0;ON; 723B;;;;N;;;;; 2F59;KANGXI RADICAL HALF TREE TRUNK;So;0;ON; 723F;;;;N;;;;; 2F5A;KANGXI RADICAL SLICE;So;0;ON; 7247;;;;N;;;;; 2F5B;KANGXI RADICAL FANG;So;0;ON; 7259;;;;N;;;;; 2F5C;KANGXI RADICAL COW;So;0;ON; 725B;;;;N;;;;; 2F5D;KANGXI RADICAL DOG;So;0;ON; 72AC;;;;N;;;;; 2F5E;KANGXI RADICAL PROFOUND;So;0;ON; 7384;;;;N;;;;; 2F5F;KANGXI RADICAL JADE;So;0;ON; 7389;;;;N;;;;; 2F60;KANGXI RADICAL MELON;So;0;ON; 74DC;;;;N;;;;; 2F61;KANGXI RADICAL TILE;So;0;ON; 74E6;;;;N;;;;; 2F62;KANGXI RADICAL SWEET;So;0;ON; 7518;;;;N;;;;; 2F63;KANGXI RADICAL LIFE;So;0;ON; 751F;;;;N;;;;; 2F64;KANGXI RADICAL USE;So;0;ON; 7528;;;;N;;;;; 2F65;KANGXI RADICAL FIELD;So;0;ON; 7530;;;;N;;;;; 2F66;KANGXI RADICAL BOLT OF CLOTH;So;0;ON; 758B;;;;N;;;;; 2F67;KANGXI RADICAL SICKNESS;So;0;ON; 7592;;;;N;;;;; 2F68;KANGXI RADICAL DOTTED TENT;So;0;ON; 7676;;;;N;;;;; 2F69;KANGXI RADICAL WHITE;So;0;ON; 767D;;;;N;;;;; 2F6A;KANGXI RADICAL SKIN;So;0;ON; 76AE;;;;N;;;;; 2F6B;KANGXI RADICAL DISH;So;0;ON; 76BF;;;;N;;;;; 2F6C;KANGXI RADICAL EYE;So;0;ON; 76EE;;;;N;;;;; 2F6D;KANGXI RADICAL SPEAR;So;0;ON; 77DB;;;;N;;;;; 2F6E;KANGXI RADICAL ARROW;So;0;ON; 77E2;;;;N;;;;; 2F6F;KANGXI RADICAL STONE;So;0;ON; 77F3;;;;N;;;;; 2F70;KANGXI RADICAL SPIRIT;So;0;ON; 793A;;;;N;;;;; 2F71;KANGXI RADICAL TRACK;So;0;ON; 79B8;;;;N;;;;; 2F72;KANGXI RADICAL GRAIN;So;0;ON; 79BE;;;;N;;;;; 2F73;KANGXI RADICAL CAVE;So;0;ON; 7A74;;;;N;;;;; 2F74;KANGXI RADICAL STAND;So;0;ON; 7ACB;;;;N;;;;; 2F75;KANGXI RADICAL BAMBOO;So;0;ON; 7AF9;;;;N;;;;; 2F76;KANGXI RADICAL RICE;So;0;ON; 7C73;;;;N;;;;; 2F77;KANGXI RADICAL SILK;So;0;ON; 7CF8;;;;N;;;;; 2F78;KANGXI RADICAL JAR;So;0;ON; 7F36;;;;N;;;;; 2F79;KANGXI RADICAL NET;So;0;ON; 7F51;;;;N;;;;; 2F7A;KANGXI RADICAL SHEEP;So;0;ON; 7F8A;;;;N;;;;; 2F7B;KANGXI RADICAL FEATHER;So;0;ON; 7FBD;;;;N;;;;; 2F7C;KANGXI RADICAL OLD;So;0;ON; 8001;;;;N;;;;; 2F7D;KANGXI RADICAL AND;So;0;ON; 800C;;;;N;;;;; 2F7E;KANGXI RADICAL PLOW;So;0;ON; 8012;;;;N;;;;; 2F7F;KANGXI RADICAL EAR;So;0;ON; 8033;;;;N;;;;; 2F80;KANGXI RADICAL BRUSH;So;0;ON; 807F;;;;N;;;;; 2F81;KANGXI RADICAL MEAT;So;0;ON; 8089;;;;N;;;;; 2F82;KANGXI RADICAL MINISTER;So;0;ON; 81E3;;;;N;;;;; 2F83;KANGXI RADICAL SELF;So;0;ON; 81EA;;;;N;;;;; 2F84;KANGXI RADICAL ARRIVE;So;0;ON; 81F3;;;;N;;;;; 2F85;KANGXI RADICAL MORTAR;So;0;ON; 81FC;;;;N;;;;; 2F86;KANGXI RADICAL TONGUE;So;0;ON; 820C;;;;N;;;;; 2F87;KANGXI RADICAL OPPOSE;So;0;ON; 821B;;;;N;;;;; 2F88;KANGXI RADICAL BOAT;So;0;ON; 821F;;;;N;;;;; 2F89;KANGXI RADICAL STOPPING;So;0;ON; 826E;;;;N;;;;; 2F8A;KANGXI RADICAL COLOR;So;0;ON; 8272;;;;N;;;;; 2F8B;KANGXI RADICAL GRASS;So;0;ON; 8278;;;;N;;;;; 2F8C;KANGXI RADICAL TIGER;So;0;ON; 864D;;;;N;;;;; 2F8D;KANGXI RADICAL INSECT;So;0;ON; 866B;;;;N;;;;; 2F8E;KANGXI RADICAL BLOOD;So;0;ON; 8840;;;;N;;;;; 2F8F;KANGXI RADICAL WALK ENCLOSURE;So;0;ON; 884C;;;;N;;;;; 2F90;KANGXI RADICAL CLOTHES;So;0;ON; 8863;;;;N;;;;; 2F91;KANGXI RADICAL WEST;So;0;ON; 897E;;;;N;;;;; 2F92;KANGXI RADICAL SEE;So;0;ON; 898B;;;;N;;;;; 2F93;KANGXI RADICAL HORN;So;0;ON; 89D2;;;;N;;;;; 2F94;KANGXI RADICAL SPEECH;So;0;ON; 8A00;;;;N;;;;; 2F95;KANGXI RADICAL VALLEY;So;0;ON; 8C37;;;;N;;;;; 2F96;KANGXI RADICAL BEAN;So;0;ON; 8C46;;;;N;;;;; 2F97;KANGXI RADICAL PIG;So;0;ON; 8C55;;;;N;;;;; 2F98;KANGXI RADICAL BADGER;So;0;ON; 8C78;;;;N;;;;; 2F99;KANGXI RADICAL SHELL;So;0;ON; 8C9D;;;;N;;;;; 2F9A;KANGXI RADICAL RED;So;0;ON; 8D64;;;;N;;;;; 2F9B;KANGXI RADICAL RUN;So;0;ON; 8D70;;;;N;;;;; 2F9C;KANGXI RADICAL FOOT;So;0;ON; 8DB3;;;;N;;;;; 2F9D;KANGXI RADICAL BODY;So;0;ON; 8EAB;;;;N;;;;; 2F9E;KANGXI RADICAL CART;So;0;ON; 8ECA;;;;N;;;;; 2F9F;KANGXI RADICAL BITTER;So;0;ON; 8F9B;;;;N;;;;; 2FA0;KANGXI RADICAL MORNING;So;0;ON; 8FB0;;;;N;;;;; 2FA1;KANGXI RADICAL WALK;So;0;ON; 8FB5;;;;N;;;;; 2FA2;KANGXI RADICAL CITY;So;0;ON; 9091;;;;N;;;;; 2FA3;KANGXI RADICAL WINE;So;0;ON; 9149;;;;N;;;;; 2FA4;KANGXI RADICAL DISTINGUISH;So;0;ON; 91C6;;;;N;;;;; 2FA5;KANGXI RADICAL VILLAGE;So;0;ON; 91CC;;;;N;;;;; 2FA6;KANGXI RADICAL GOLD;So;0;ON; 91D1;;;;N;;;;; 2FA7;KANGXI RADICAL LONG;So;0;ON; 9577;;;;N;;;;; 2FA8;KANGXI RADICAL GATE;So;0;ON; 9580;;;;N;;;;; 2FA9;KANGXI RADICAL MOUND;So;0;ON; 961C;;;;N;;;;; 2FAA;KANGXI RADICAL SLAVE;So;0;ON; 96B6;;;;N;;;;; 2FAB;KANGXI RADICAL SHORT TAILED BIRD;So;0;ON; 96B9;;;;N;;;;; 2FAC;KANGXI RADICAL RAIN;So;0;ON; 96E8;;;;N;;;;; 2FAD;KANGXI RADICAL BLUE;So;0;ON; 9751;;;;N;;;;; 2FAE;KANGXI RADICAL WRONG;So;0;ON; 975E;;;;N;;;;; 2FAF;KANGXI RADICAL FACE;So;0;ON; 9762;;;;N;;;;; 2FB0;KANGXI RADICAL LEATHER;So;0;ON; 9769;;;;N;;;;; 2FB1;KANGXI RADICAL TANNED LEATHER;So;0;ON; 97CB;;;;N;;;;; 2FB2;KANGXI RADICAL LEEK;So;0;ON; 97ED;;;;N;;;;; 2FB3;KANGXI RADICAL SOUND;So;0;ON; 97F3;;;;N;;;;; 2FB4;KANGXI RADICAL LEAF;So;0;ON; 9801;;;;N;;;;; 2FB5;KANGXI RADICAL WIND;So;0;ON; 98A8;;;;N;;;;; 2FB6;KANGXI RADICAL FLY;So;0;ON; 98DB;;;;N;;;;; 2FB7;KANGXI RADICAL EAT;So;0;ON; 98DF;;;;N;;;;; 2FB8;KANGXI RADICAL HEAD;So;0;ON; 9996;;;;N;;;;; 2FB9;KANGXI RADICAL FRAGRANT;So;0;ON; 9999;;;;N;;;;; 2FBA;KANGXI RADICAL HORSE;So;0;ON; 99AC;;;;N;;;;; 2FBB;KANGXI RADICAL BONE;So;0;ON; 9AA8;;;;N;;;;; 2FBC;KANGXI RADICAL TALL;So;0;ON; 9AD8;;;;N;;;;; 2FBD;KANGXI RADICAL HAIR;So;0;ON; 9ADF;;;;N;;;;; 2FBE;KANGXI RADICAL FIGHT;So;0;ON; 9B25;;;;N;;;;; 2FBF;KANGXI RADICAL SACRIFICIAL WINE;So;0;ON; 9B2F;;;;N;;;;; 2FC0;KANGXI RADICAL CAULDRON;So;0;ON; 9B32;;;;N;;;;; 2FC1;KANGXI RADICAL GHOST;So;0;ON; 9B3C;;;;N;;;;; 2FC2;KANGXI RADICAL FISH;So;0;ON; 9B5A;;;;N;;;;; 2FC3;KANGXI RADICAL BIRD;So;0;ON; 9CE5;;;;N;;;;; 2FC4;KANGXI RADICAL SALT;So;0;ON; 9E75;;;;N;;;;; 2FC5;KANGXI RADICAL DEER;So;0;ON; 9E7F;;;;N;;;;; 2FC6;KANGXI RADICAL WHEAT;So;0;ON; 9EA5;;;;N;;;;; 2FC7;KANGXI RADICAL HEMP;So;0;ON; 9EBB;;;;N;;;;; 2FC8;KANGXI RADICAL YELLOW;So;0;ON; 9EC3;;;;N;;;;; 2FC9;KANGXI RADICAL MILLET;So;0;ON; 9ECD;;;;N;;;;; 2FCA;KANGXI RADICAL BLACK;So;0;ON; 9ED1;;;;N;;;;; 2FCB;KANGXI RADICAL EMBROIDERY;So;0;ON; 9EF9;;;;N;;;;; 2FCC;KANGXI RADICAL FROG;So;0;ON; 9EFD;;;;N;;;;; 2FCD;KANGXI RADICAL TRIPOD;So;0;ON; 9F0E;;;;N;;;;; 2FCE;KANGXI RADICAL DRUM;So;0;ON; 9F13;;;;N;;;;; 2FCF;KANGXI RADICAL RAT;So;0;ON; 9F20;;;;N;;;;; 2FD0;KANGXI RADICAL NOSE;So;0;ON; 9F3B;;;;N;;;;; 2FD1;KANGXI RADICAL EVEN;So;0;ON; 9F4A;;;;N;;;;; 2FD2;KANGXI RADICAL TOOTH;So;0;ON; 9F52;;;;N;;;;; 2FD3;KANGXI RADICAL DRAGON;So;0;ON; 9F8D;;;;N;;;;; 2FD4;KANGXI RADICAL TURTLE;So;0;ON; 9F9C;;;;N;;;;; 2FD5;KANGXI RADICAL FLUTE;So;0;ON; 9FA0;;;;N;;;;; 2FF0;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT;So;0;ON;;;;;N;;;;; 2FF1;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO BELOW;So;0;ON;;;;;N;;;;; 2FF2;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO MIDDLE AND RIGHT;So;0;ON;;;;;N;;;;; 2FF3;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND BELOW;So;0;ON;;;;;N;;;;; 2FF4;IDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUND;So;0;ON;;;;;N;;;;; 2FF5;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM ABOVE;So;0;ON;;;;;N;;;;; 2FF6;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM BELOW;So;0;ON;;;;;N;;;;; 2FF7;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LEFT;So;0;ON;;;;;N;;;;; 2FF8;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER LEFT;So;0;ON;;;;;N;;;;; 2FF9;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER RIGHT;So;0;ON;;;;;N;;;;; 2FFA;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER LEFT;So;0;ON;;;;;N;;;;; 2FFB;IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID;So;0;ON;;;;;N;;;;; 3000;IDEOGRAPHIC SPACE;Zs;0;WS; 0020;;;;N;;;;; 3001;IDEOGRAPHIC COMMA;Po;0;ON;;;;;N;;;;; 3002;IDEOGRAPHIC FULL STOP;Po;0;ON;;;;;N;IDEOGRAPHIC PERIOD;;;; 3003;DITTO MARK;Po;0;ON;;;;;N;;;;; 3004;JAPANESE INDUSTRIAL STANDARD SYMBOL;So;0;ON;;;;;N;;;;; 3005;IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;; 3006;IDEOGRAPHIC CLOSING MARK;Lo;0;L;;;;;N;;;;; 3007;IDEOGRAPHIC NUMBER ZERO;Nl;0;L;;;;0;N;;;;; 3008;LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING ANGLE BRACKET;;;; 3009;RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING ANGLE BRACKET;;;; 300A;LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING DOUBLE ANGLE BRACKET;;;; 300B;RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING DOUBLE ANGLE BRACKET;;;; 300C;LEFT CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING CORNER BRACKET;;;; 300D;RIGHT CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING CORNER BRACKET;;;; 300E;LEFT WHITE CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE CORNER BRACKET;;;; 300F;RIGHT WHITE CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE CORNER BRACKET;;;; 3010;LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING BLACK LENTICULAR BRACKET;;;; 3011;RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING BLACK LENTICULAR BRACKET;;;; 3012;POSTAL MARK;So;0;ON;;;;;N;;;;; 3013;GETA MARK;So;0;ON;;;;;N;;;;; 3014;LEFT TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING TORTOISE SHELL BRACKET;;;; 3015;RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING TORTOISE SHELL BRACKET;;;; 3016;LEFT WHITE LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE LENTICULAR BRACKET;;;; 3017;RIGHT WHITE LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE LENTICULAR BRACKET;;;; 3018;LEFT WHITE TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE TORTOISE SHELL BRACKET;;;; 3019;RIGHT WHITE TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE TORTOISE SHELL BRACKET;;;; 301A;LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE SQUARE BRACKET;;;; 301B;RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE SQUARE BRACKET;;;; 301C;WAVE DASH;Pd;0;ON;;;;;N;;;;; 301D;REVERSED DOUBLE PRIME QUOTATION MARK;Ps;0;ON;;;;;N;;;;; 301E;DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;; 301F;LOW DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;; 3020;POSTAL MARK FACE;So;0;ON;;;;;N;;;;; 3021;HANGZHOU NUMERAL ONE;Nl;0;L;;;;1;N;;;;; 3022;HANGZHOU NUMERAL TWO;Nl;0;L;;;;2;N;;;;; 3023;HANGZHOU NUMERAL THREE;Nl;0;L;;;;3;N;;;;; 3024;HANGZHOU NUMERAL FOUR;Nl;0;L;;;;4;N;;;;; 3025;HANGZHOU NUMERAL FIVE;Nl;0;L;;;;5;N;;;;; 3026;HANGZHOU NUMERAL SIX;Nl;0;L;;;;6;N;;;;; 3027;HANGZHOU NUMERAL SEVEN;Nl;0;L;;;;7;N;;;;; 3028;HANGZHOU NUMERAL EIGHT;Nl;0;L;;;;8;N;;;;; 3029;HANGZHOU NUMERAL NINE;Nl;0;L;;;;9;N;;;;; 302A;IDEOGRAPHIC LEVEL TONE MARK;Mn;218;NSM;;;;;N;;;;; 302B;IDEOGRAPHIC RISING TONE MARK;Mn;228;NSM;;;;;N;;;;; 302C;IDEOGRAPHIC DEPARTING TONE MARK;Mn;232;NSM;;;;;N;;;;; 302D;IDEOGRAPHIC ENTERING TONE MARK;Mn;222;NSM;;;;;N;;;;; 302E;HANGUL SINGLE DOT TONE MARK;Mn;224;NSM;;;;;N;;;;; 302F;HANGUL DOUBLE DOT TONE MARK;Mn;224;NSM;;;;;N;;;;; 3030;WAVY DASH;Pd;0;ON;;;;;N;;;;; 3031;VERTICAL KANA REPEAT MARK;Lm;0;L;;;;;N;;;;; 3032;VERTICAL KANA REPEAT WITH VOICED SOUND MARK;Lm;0;L;;;;;N;;;;; 3033;VERTICAL KANA REPEAT MARK UPPER HALF;Lm;0;L;;;;;N;;;;; 3034;VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF;Lm;0;L;;;;;N;;;;; 3035;VERTICAL KANA REPEAT MARK LOWER HALF;Lm;0;L;;;;;N;;;;; 3036;CIRCLED POSTAL MARK;So;0;ON; 3012;;;;N;;;;; 3037;IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL;So;0;ON;;;;;N;;;;; 3038;HANGZHOU NUMERAL TEN;Nl;0;L; 5341;;;10;N;;;;; 3039;HANGZHOU NUMERAL TWENTY;Nl;0;L; 5344;;;20;N;;;;; 303A;HANGZHOU NUMERAL THIRTY;Nl;0;L; 5345;;;30;N;;;;; 303B;VERTICAL IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;; 303C;MASU MARK;Lo;0;L;;;;;N;;;;; 303D;PART ALTERNATION MARK;Po;0;ON;;;;;N;;;;; 303E;IDEOGRAPHIC VARIATION INDICATOR;So;0;ON;;;;;N;;;;; 303F;IDEOGRAPHIC HALF FILL SPACE;So;0;ON;;;;;N;;;;; 3041;HIRAGANA LETTER SMALL A;Lo;0;L;;;;;N;;;;; 3042;HIRAGANA LETTER A;Lo;0;L;;;;;N;;;;; 3043;HIRAGANA LETTER SMALL I;Lo;0;L;;;;;N;;;;; 3044;HIRAGANA LETTER I;Lo;0;L;;;;;N;;;;; 3045;HIRAGANA LETTER SMALL U;Lo;0;L;;;;;N;;;;; 3046;HIRAGANA LETTER U;Lo;0;L;;;;;N;;;;; 3047;HIRAGANA LETTER SMALL E;Lo;0;L;;;;;N;;;;; 3048;HIRAGANA LETTER E;Lo;0;L;;;;;N;;;;; 3049;HIRAGANA LETTER SMALL O;Lo;0;L;;;;;N;;;;; 304A;HIRAGANA LETTER O;Lo;0;L;;;;;N;;;;; 304B;HIRAGANA LETTER KA;Lo;0;L;;;;;N;;;;; 304C;HIRAGANA LETTER GA;Lo;0;L;304B 3099;;;;N;;;;; 304D;HIRAGANA LETTER KI;Lo;0;L;;;;;N;;;;; 304E;HIRAGANA LETTER GI;Lo;0;L;304D 3099;;;;N;;;;; 304F;HIRAGANA LETTER KU;Lo;0;L;;;;;N;;;;; 3050;HIRAGANA LETTER GU;Lo;0;L;304F 3099;;;;N;;;;; 3051;HIRAGANA LETTER KE;Lo;0;L;;;;;N;;;;; 3052;HIRAGANA LETTER GE;Lo;0;L;3051 3099;;;;N;;;;; 3053;HIRAGANA LETTER KO;Lo;0;L;;;;;N;;;;; 3054;HIRAGANA LETTER GO;Lo;0;L;3053 3099;;;;N;;;;; 3055;HIRAGANA LETTER SA;Lo;0;L;;;;;N;;;;; 3056;HIRAGANA LETTER ZA;Lo;0;L;3055 3099;;;;N;;;;; 3057;HIRAGANA LETTER SI;Lo;0;L;;;;;N;;;;; 3058;HIRAGANA LETTER ZI;Lo;0;L;3057 3099;;;;N;;;;; 3059;HIRAGANA LETTER SU;Lo;0;L;;;;;N;;;;; 305A;HIRAGANA LETTER ZU;Lo;0;L;3059 3099;;;;N;;;;; 305B;HIRAGANA LETTER SE;Lo;0;L;;;;;N;;;;; 305C;HIRAGANA LETTER ZE;Lo;0;L;305B 3099;;;;N;;;;; 305D;HIRAGANA LETTER SO;Lo;0;L;;;;;N;;;;; 305E;HIRAGANA LETTER ZO;Lo;0;L;305D 3099;;;;N;;;;; 305F;HIRAGANA LETTER TA;Lo;0;L;;;;;N;;;;; 3060;HIRAGANA LETTER DA;Lo;0;L;305F 3099;;;;N;;;;; 3061;HIRAGANA LETTER TI;Lo;0;L;;;;;N;;;;; 3062;HIRAGANA LETTER DI;Lo;0;L;3061 3099;;;;N;;;;; 3063;HIRAGANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;; 3064;HIRAGANA LETTER TU;Lo;0;L;;;;;N;;;;; 3065;HIRAGANA LETTER DU;Lo;0;L;3064 3099;;;;N;;;;; 3066;HIRAGANA LETTER TE;Lo;0;L;;;;;N;;;;; 3067;HIRAGANA LETTER DE;Lo;0;L;3066 3099;;;;N;;;;; 3068;HIRAGANA LETTER TO;Lo;0;L;;;;;N;;;;; 3069;HIRAGANA LETTER DO;Lo;0;L;3068 3099;;;;N;;;;; 306A;HIRAGANA LETTER NA;Lo;0;L;;;;;N;;;;; 306B;HIRAGANA LETTER NI;Lo;0;L;;;;;N;;;;; 306C;HIRAGANA LETTER NU;Lo;0;L;;;;;N;;;;; 306D;HIRAGANA LETTER NE;Lo;0;L;;;;;N;;;;; 306E;HIRAGANA LETTER NO;Lo;0;L;;;;;N;;;;; 306F;HIRAGANA LETTER HA;Lo;0;L;;;;;N;;;;; 3070;HIRAGANA LETTER BA;Lo;0;L;306F 3099;;;;N;;;;; 3071;HIRAGANA LETTER PA;Lo;0;L;306F 309A;;;;N;;;;; 3072;HIRAGANA LETTER HI;Lo;0;L;;;;;N;;;;; 3073;HIRAGANA LETTER BI;Lo;0;L;3072 3099;;;;N;;;;; 3074;HIRAGANA LETTER PI;Lo;0;L;3072 309A;;;;N;;;;; 3075;HIRAGANA LETTER HU;Lo;0;L;;;;;N;;;;; 3076;HIRAGANA LETTER BU;Lo;0;L;3075 3099;;;;N;;;;; 3077;HIRAGANA LETTER PU;Lo;0;L;3075 309A;;;;N;;;;; 3078;HIRAGANA LETTER HE;Lo;0;L;;;;;N;;;;; 3079;HIRAGANA LETTER BE;Lo;0;L;3078 3099;;;;N;;;;; 307A;HIRAGANA LETTER PE;Lo;0;L;3078 309A;;;;N;;;;; 307B;HIRAGANA LETTER HO;Lo;0;L;;;;;N;;;;; 307C;HIRAGANA LETTER BO;Lo;0;L;307B 3099;;;;N;;;;; 307D;HIRAGANA LETTER PO;Lo;0;L;307B 309A;;;;N;;;;; 307E;HIRAGANA LETTER MA;Lo;0;L;;;;;N;;;;; 307F;HIRAGANA LETTER MI;Lo;0;L;;;;;N;;;;; 3080;HIRAGANA LETTER MU;Lo;0;L;;;;;N;;;;; 3081;HIRAGANA LETTER ME;Lo;0;L;;;;;N;;;;; 3082;HIRAGANA LETTER MO;Lo;0;L;;;;;N;;;;; 3083;HIRAGANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;; 3084;HIRAGANA LETTER YA;Lo;0;L;;;;;N;;;;; 3085;HIRAGANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;; 3086;HIRAGANA LETTER YU;Lo;0;L;;;;;N;;;;; 3087;HIRAGANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;; 3088;HIRAGANA LETTER YO;Lo;0;L;;;;;N;;;;; 3089;HIRAGANA LETTER RA;Lo;0;L;;;;;N;;;;; 308A;HIRAGANA LETTER RI;Lo;0;L;;;;;N;;;;; 308B;HIRAGANA LETTER RU;Lo;0;L;;;;;N;;;;; 308C;HIRAGANA LETTER RE;Lo;0;L;;;;;N;;;;; 308D;HIRAGANA LETTER RO;Lo;0;L;;;;;N;;;;; 308E;HIRAGANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;; 308F;HIRAGANA LETTER WA;Lo;0;L;;;;;N;;;;; 3090;HIRAGANA LETTER WI;Lo;0;L;;;;;N;;;;; 3091;HIRAGANA LETTER WE;Lo;0;L;;;;;N;;;;; 3092;HIRAGANA LETTER WO;Lo;0;L;;;;;N;;;;; 3093;HIRAGANA LETTER N;Lo;0;L;;;;;N;;;;; 3094;HIRAGANA LETTER VU;Lo;0;L;3046 3099;;;;N;;;;; 3095;HIRAGANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;; 3096;HIRAGANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;; 3099;COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA VOICED SOUND MARK;;;; 309A;COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;;;; 309B;KATAKANA-HIRAGANA VOICED SOUND MARK;Sk;0;ON; 0020 3099;;;;N;;;;; 309C;KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Sk;0;ON; 0020 309A;;;;N;;;;; 309D;HIRAGANA ITERATION MARK;Lm;0;L;;;;;N;;;;; 309E;HIRAGANA VOICED ITERATION MARK;Lm;0;L;309D 3099;;;;N;;;;; 309F;HIRAGANA DIGRAPH YORI;Lo;0;L; 3088 308A;;;;N;;;;; 30A0;KATAKANA-HIRAGANA DOUBLE HYPHEN;Pd;0;ON;;;;;N;;;;; 30A1;KATAKANA LETTER SMALL A;Lo;0;L;;;;;N;;;;; 30A2;KATAKANA LETTER A;Lo;0;L;;;;;N;;;;; 30A3;KATAKANA LETTER SMALL I;Lo;0;L;;;;;N;;;;; 30A4;KATAKANA LETTER I;Lo;0;L;;;;;N;;;;; 30A5;KATAKANA LETTER SMALL U;Lo;0;L;;;;;N;;;;; 30A6;KATAKANA LETTER U;Lo;0;L;;;;;N;;;;; 30A7;KATAKANA LETTER SMALL E;Lo;0;L;;;;;N;;;;; 30A8;KATAKANA LETTER E;Lo;0;L;;;;;N;;;;; 30A9;KATAKANA LETTER SMALL O;Lo;0;L;;;;;N;;;;; 30AA;KATAKANA LETTER O;Lo;0;L;;;;;N;;;;; 30AB;KATAKANA LETTER KA;Lo;0;L;;;;;N;;;;; 30AC;KATAKANA LETTER GA;Lo;0;L;30AB 3099;;;;N;;;;; 30AD;KATAKANA LETTER KI;Lo;0;L;;;;;N;;;;; 30AE;KATAKANA LETTER GI;Lo;0;L;30AD 3099;;;;N;;;;; 30AF;KATAKANA LETTER KU;Lo;0;L;;;;;N;;;;; 30B0;KATAKANA LETTER GU;Lo;0;L;30AF 3099;;;;N;;;;; 30B1;KATAKANA LETTER KE;Lo;0;L;;;;;N;;;;; 30B2;KATAKANA LETTER GE;Lo;0;L;30B1 3099;;;;N;;;;; 30B3;KATAKANA LETTER KO;Lo;0;L;;;;;N;;;;; 30B4;KATAKANA LETTER GO;Lo;0;L;30B3 3099;;;;N;;;;; 30B5;KATAKANA LETTER SA;Lo;0;L;;;;;N;;;;; 30B6;KATAKANA LETTER ZA;Lo;0;L;30B5 3099;;;;N;;;;; 30B7;KATAKANA LETTER SI;Lo;0;L;;;;;N;;;;; 30B8;KATAKANA LETTER ZI;Lo;0;L;30B7 3099;;;;N;;;;; 30B9;KATAKANA LETTER SU;Lo;0;L;;;;;N;;;;; 30BA;KATAKANA LETTER ZU;Lo;0;L;30B9 3099;;;;N;;;;; 30BB;KATAKANA LETTER SE;Lo;0;L;;;;;N;;;;; 30BC;KATAKANA LETTER ZE;Lo;0;L;30BB 3099;;;;N;;;;; 30BD;KATAKANA LETTER SO;Lo;0;L;;;;;N;;;;; 30BE;KATAKANA LETTER ZO;Lo;0;L;30BD 3099;;;;N;;;;; 30BF;KATAKANA LETTER TA;Lo;0;L;;;;;N;;;;; 30C0;KATAKANA LETTER DA;Lo;0;L;30BF 3099;;;;N;;;;; 30C1;KATAKANA LETTER TI;Lo;0;L;;;;;N;;;;; 30C2;KATAKANA LETTER DI;Lo;0;L;30C1 3099;;;;N;;;;; 30C3;KATAKANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;; 30C4;KATAKANA LETTER TU;Lo;0;L;;;;;N;;;;; 30C5;KATAKANA LETTER DU;Lo;0;L;30C4 3099;;;;N;;;;; 30C6;KATAKANA LETTER TE;Lo;0;L;;;;;N;;;;; 30C7;KATAKANA LETTER DE;Lo;0;L;30C6 3099;;;;N;;;;; 30C8;KATAKANA LETTER TO;Lo;0;L;;;;;N;;;;; 30C9;KATAKANA LETTER DO;Lo;0;L;30C8 3099;;;;N;;;;; 30CA;KATAKANA LETTER NA;Lo;0;L;;;;;N;;;;; 30CB;KATAKANA LETTER NI;Lo;0;L;;;;;N;;;;; 30CC;KATAKANA LETTER NU;Lo;0;L;;;;;N;;;;; 30CD;KATAKANA LETTER NE;Lo;0;L;;;;;N;;;;; 30CE;KATAKANA LETTER NO;Lo;0;L;;;;;N;;;;; 30CF;KATAKANA LETTER HA;Lo;0;L;;;;;N;;;;; 30D0;KATAKANA LETTER BA;Lo;0;L;30CF 3099;;;;N;;;;; 30D1;KATAKANA LETTER PA;Lo;0;L;30CF 309A;;;;N;;;;; 30D2;KATAKANA LETTER HI;Lo;0;L;;;;;N;;;;; 30D3;KATAKANA LETTER BI;Lo;0;L;30D2 3099;;;;N;;;;; 30D4;KATAKANA LETTER PI;Lo;0;L;30D2 309A;;;;N;;;;; 30D5;KATAKANA LETTER HU;Lo;0;L;;;;;N;;;;; 30D6;KATAKANA LETTER BU;Lo;0;L;30D5 3099;;;;N;;;;; 30D7;KATAKANA LETTER PU;Lo;0;L;30D5 309A;;;;N;;;;; 30D8;KATAKANA LETTER HE;Lo;0;L;;;;;N;;;;; 30D9;KATAKANA LETTER BE;Lo;0;L;30D8 3099;;;;N;;;;; 30DA;KATAKANA LETTER PE;Lo;0;L;30D8 309A;;;;N;;;;; 30DB;KATAKANA LETTER HO;Lo;0;L;;;;;N;;;;; 30DC;KATAKANA LETTER BO;Lo;0;L;30DB 3099;;;;N;;;;; 30DD;KATAKANA LETTER PO;Lo;0;L;30DB 309A;;;;N;;;;; 30DE;KATAKANA LETTER MA;Lo;0;L;;;;;N;;;;; 30DF;KATAKANA LETTER MI;Lo;0;L;;;;;N;;;;; 30E0;KATAKANA LETTER MU;Lo;0;L;;;;;N;;;;; 30E1;KATAKANA LETTER ME;Lo;0;L;;;;;N;;;;; 30E2;KATAKANA LETTER MO;Lo;0;L;;;;;N;;;;; 30E3;KATAKANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;; 30E4;KATAKANA LETTER YA;Lo;0;L;;;;;N;;;;; 30E5;KATAKANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;; 30E6;KATAKANA LETTER YU;Lo;0;L;;;;;N;;;;; 30E7;KATAKANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;; 30E8;KATAKANA LETTER YO;Lo;0;L;;;;;N;;;;; 30E9;KATAKANA LETTER RA;Lo;0;L;;;;;N;;;;; 30EA;KATAKANA LETTER RI;Lo;0;L;;;;;N;;;;; 30EB;KATAKANA LETTER RU;Lo;0;L;;;;;N;;;;; 30EC;KATAKANA LETTER RE;Lo;0;L;;;;;N;;;;; 30ED;KATAKANA LETTER RO;Lo;0;L;;;;;N;;;;; 30EE;KATAKANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;; 30EF;KATAKANA LETTER WA;Lo;0;L;;;;;N;;;;; 30F0;KATAKANA LETTER WI;Lo;0;L;;;;;N;;;;; 30F1;KATAKANA LETTER WE;Lo;0;L;;;;;N;;;;; 30F2;KATAKANA LETTER WO;Lo;0;L;;;;;N;;;;; 30F3;KATAKANA LETTER N;Lo;0;L;;;;;N;;;;; 30F4;KATAKANA LETTER VU;Lo;0;L;30A6 3099;;;;N;;;;; 30F5;KATAKANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;; 30F6;KATAKANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;; 30F7;KATAKANA LETTER VA;Lo;0;L;30EF 3099;;;;N;;;;; 30F8;KATAKANA LETTER VI;Lo;0;L;30F0 3099;;;;N;;;;; 30F9;KATAKANA LETTER VE;Lo;0;L;30F1 3099;;;;N;;;;; 30FA;KATAKANA LETTER VO;Lo;0;L;30F2 3099;;;;N;;;;; 30FB;KATAKANA MIDDLE DOT;Pc;0;ON;;;;;N;;;;; 30FC;KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;;;;;N;;;;; 30FD;KATAKANA ITERATION MARK;Lm;0;L;;;;;N;;;;; 30FE;KATAKANA VOICED ITERATION MARK;Lm;0;L;30FD 3099;;;;N;;;;; 30FF;KATAKANA DIGRAPH KOTO;Lo;0;L; 30B3 30C8;;;;N;;;;; 3105;BOPOMOFO LETTER B;Lo;0;L;;;;;N;;;;; 3106;BOPOMOFO LETTER P;Lo;0;L;;;;;N;;;;; 3107;BOPOMOFO LETTER M;Lo;0;L;;;;;N;;;;; 3108;BOPOMOFO LETTER F;Lo;0;L;;;;;N;;;;; 3109;BOPOMOFO LETTER D;Lo;0;L;;;;;N;;;;; 310A;BOPOMOFO LETTER T;Lo;0;L;;;;;N;;;;; 310B;BOPOMOFO LETTER N;Lo;0;L;;;;;N;;;;; 310C;BOPOMOFO LETTER L;Lo;0;L;;;;;N;;;;; 310D;BOPOMOFO LETTER G;Lo;0;L;;;;;N;;;;; 310E;BOPOMOFO LETTER K;Lo;0;L;;;;;N;;;;; 310F;BOPOMOFO LETTER H;Lo;0;L;;;;;N;;;;; 3110;BOPOMOFO LETTER J;Lo;0;L;;;;;N;;;;; 3111;BOPOMOFO LETTER Q;Lo;0;L;;;;;N;;;;; 3112;BOPOMOFO LETTER X;Lo;0;L;;;;;N;;;;; 3113;BOPOMOFO LETTER ZH;Lo;0;L;;;;;N;;;;; 3114;BOPOMOFO LETTER CH;Lo;0;L;;;;;N;;;;; 3115;BOPOMOFO LETTER SH;Lo;0;L;;;;;N;;;;; 3116;BOPOMOFO LETTER R;Lo;0;L;;;;;N;;;;; 3117;BOPOMOFO LETTER Z;Lo;0;L;;;;;N;;;;; 3118;BOPOMOFO LETTER C;Lo;0;L;;;;;N;;;;; 3119;BOPOMOFO LETTER S;Lo;0;L;;;;;N;;;;; 311A;BOPOMOFO LETTER A;Lo;0;L;;;;;N;;;;; 311B;BOPOMOFO LETTER O;Lo;0;L;;;;;N;;;;; 311C;BOPOMOFO LETTER E;Lo;0;L;;;;;N;;;;; 311D;BOPOMOFO LETTER EH;Lo;0;L;;;;;N;;;;; 311E;BOPOMOFO LETTER AI;Lo;0;L;;;;;N;;;;; 311F;BOPOMOFO LETTER EI;Lo;0;L;;;;;N;;;;; 3120;BOPOMOFO LETTER AU;Lo;0;L;;;;;N;;;;; 3121;BOPOMOFO LETTER OU;Lo;0;L;;;;;N;;;;; 3122;BOPOMOFO LETTER AN;Lo;0;L;;;;;N;;;;; 3123;BOPOMOFO LETTER EN;Lo;0;L;;;;;N;;;;; 3124;BOPOMOFO LETTER ANG;Lo;0;L;;;;;N;;;;; 3125;BOPOMOFO LETTER ENG;Lo;0;L;;;;;N;;;;; 3126;BOPOMOFO LETTER ER;Lo;0;L;;;;;N;;;;; 3127;BOPOMOFO LETTER I;Lo;0;L;;;;;N;;;;; 3128;BOPOMOFO LETTER U;Lo;0;L;;;;;N;;;;; 3129;BOPOMOFO LETTER IU;Lo;0;L;;;;;N;;;;; 312A;BOPOMOFO LETTER V;Lo;0;L;;;;;N;;;;; 312B;BOPOMOFO LETTER NG;Lo;0;L;;;;;N;;;;; 312C;BOPOMOFO LETTER GN;Lo;0;L;;;;;N;;;;; 3131;HANGUL LETTER KIYEOK;Lo;0;L; 1100;;;;N;HANGUL LETTER GIYEOG;;;; 3132;HANGUL LETTER SSANGKIYEOK;Lo;0;L; 1101;;;;N;HANGUL LETTER SSANG GIYEOG;;;; 3133;HANGUL LETTER KIYEOK-SIOS;Lo;0;L; 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;; 3134;HANGUL LETTER NIEUN;Lo;0;L; 1102;;;;N;;;;; 3135;HANGUL LETTER NIEUN-CIEUC;Lo;0;L; 11AC;;;;N;HANGUL LETTER NIEUN JIEUJ;;;; 3136;HANGUL LETTER NIEUN-HIEUH;Lo;0;L; 11AD;;;;N;HANGUL LETTER NIEUN HIEUH;;;; 3137;HANGUL LETTER TIKEUT;Lo;0;L; 1103;;;;N;HANGUL LETTER DIGEUD;;;; 3138;HANGUL LETTER SSANGTIKEUT;Lo;0;L; 1104;;;;N;HANGUL LETTER SSANG DIGEUD;;;; 3139;HANGUL LETTER RIEUL;Lo;0;L; 1105;;;;N;HANGUL LETTER LIEUL;;;; 313A;HANGUL LETTER RIEUL-KIYEOK;Lo;0;L; 11B0;;;;N;HANGUL LETTER LIEUL GIYEOG;;;; 313B;HANGUL LETTER RIEUL-MIEUM;Lo;0;L; 11B1;;;;N;HANGUL LETTER LIEUL MIEUM;;;; 313C;HANGUL LETTER RIEUL-PIEUP;Lo;0;L; 11B2;;;;N;HANGUL LETTER LIEUL BIEUB;;;; 313D;HANGUL LETTER RIEUL-SIOS;Lo;0;L; 11B3;;;;N;HANGUL LETTER LIEUL SIOS;;;; 313E;HANGUL LETTER RIEUL-THIEUTH;Lo;0;L; 11B4;;;;N;HANGUL LETTER LIEUL TIEUT;;;; 313F;HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L; 11B5;;;;N;HANGUL LETTER LIEUL PIEUP;;;; 3140;HANGUL LETTER RIEUL-HIEUH;Lo;0;L; 111A;;;;N;HANGUL LETTER LIEUL HIEUH;;;; 3141;HANGUL LETTER MIEUM;Lo;0;L; 1106;;;;N;;;;; 3142;HANGUL LETTER PIEUP;Lo;0;L; 1107;;;;N;HANGUL LETTER BIEUB;;;; 3143;HANGUL LETTER SSANGPIEUP;Lo;0;L; 1108;;;;N;HANGUL LETTER SSANG BIEUB;;;; 3144;HANGUL LETTER PIEUP-SIOS;Lo;0;L; 1121;;;;N;HANGUL LETTER BIEUB SIOS;;;; 3145;HANGUL LETTER SIOS;Lo;0;L; 1109;;;;N;;;;; 3146;HANGUL LETTER SSANGSIOS;Lo;0;L; 110A;;;;N;HANGUL LETTER SSANG SIOS;;;; 3147;HANGUL LETTER IEUNG;Lo;0;L; 110B;;;;N;;;;; 3148;HANGUL LETTER CIEUC;Lo;0;L; 110C;;;;N;HANGUL LETTER JIEUJ;;;; 3149;HANGUL LETTER SSANGCIEUC;Lo;0;L; 110D;;;;N;HANGUL LETTER SSANG JIEUJ;;;; 314A;HANGUL LETTER CHIEUCH;Lo;0;L; 110E;;;;N;HANGUL LETTER CIEUC;;;; 314B;HANGUL LETTER KHIEUKH;Lo;0;L; 110F;;;;N;HANGUL LETTER KIYEOK;;;; 314C;HANGUL LETTER THIEUTH;Lo;0;L; 1110;;;;N;HANGUL LETTER TIEUT;;;; 314D;HANGUL LETTER PHIEUPH;Lo;0;L; 1111;;;;N;HANGUL LETTER PIEUP;;;; 314E;HANGUL LETTER HIEUH;Lo;0;L; 1112;;;;N;;;;; 314F;HANGUL LETTER A;Lo;0;L; 1161;;;;N;;;;; 3150;HANGUL LETTER AE;Lo;0;L; 1162;;;;N;;;;; 3151;HANGUL LETTER YA;Lo;0;L; 1163;;;;N;;;;; 3152;HANGUL LETTER YAE;Lo;0;L; 1164;;;;N;;;;; 3153;HANGUL LETTER EO;Lo;0;L; 1165;;;;N;;;;; 3154;HANGUL LETTER E;Lo;0;L; 1166;;;;N;;;;; 3155;HANGUL LETTER YEO;Lo;0;L; 1167;;;;N;;;;; 3156;HANGUL LETTER YE;Lo;0;L; 1168;;;;N;;;;; 3157;HANGUL LETTER O;Lo;0;L; 1169;;;;N;;;;; 3158;HANGUL LETTER WA;Lo;0;L; 116A;;;;N;;;;; 3159;HANGUL LETTER WAE;Lo;0;L; 116B;;;;N;;;;; 315A;HANGUL LETTER OE;Lo;0;L; 116C;;;;N;;;;; 315B;HANGUL LETTER YO;Lo;0;L; 116D;;;;N;;;;; 315C;HANGUL LETTER U;Lo;0;L; 116E;;;;N;;;;; 315D;HANGUL LETTER WEO;Lo;0;L; 116F;;;;N;;;;; 315E;HANGUL LETTER WE;Lo;0;L; 1170;;;;N;;;;; 315F;HANGUL LETTER WI;Lo;0;L; 1171;;;;N;;;;; 3160;HANGUL LETTER YU;Lo;0;L; 1172;;;;N;;;;; 3161;HANGUL LETTER EU;Lo;0;L; 1173;;;;N;;;;; 3162;HANGUL LETTER YI;Lo;0;L; 1174;;;;N;;;;; 3163;HANGUL LETTER I;Lo;0;L; 1175;;;;N;;;;; 3164;HANGUL FILLER;Lo;0;L; 1160;;;;N;HANGUL CAE OM;;;; 3165;HANGUL LETTER SSANGNIEUN;Lo;0;L; 1114;;;;N;HANGUL LETTER SSANG NIEUN;;;; 3166;HANGUL LETTER NIEUN-TIKEUT;Lo;0;L; 1115;;;;N;HANGUL LETTER NIEUN DIGEUD;;;; 3167;HANGUL LETTER NIEUN-SIOS;Lo;0;L; 11C7;;;;N;HANGUL LETTER NIEUN SIOS;;;; 3168;HANGUL LETTER NIEUN-PANSIOS;Lo;0;L; 11C8;;;;N;HANGUL LETTER NIEUN BAN CHI EUM;;;; 3169;HANGUL LETTER RIEUL-KIYEOK-SIOS;Lo;0;L; 11CC;;;;N;HANGUL LETTER LIEUL GIYEOG SIOS;;;; 316A;HANGUL LETTER RIEUL-TIKEUT;Lo;0;L; 11CE;;;;N;HANGUL LETTER LIEUL DIGEUD;;;; 316B;HANGUL LETTER RIEUL-PIEUP-SIOS;Lo;0;L; 11D3;;;;N;HANGUL LETTER LIEUL BIEUB SIOS;;;; 316C;HANGUL LETTER RIEUL-PANSIOS;Lo;0;L; 11D7;;;;N;HANGUL LETTER LIEUL BAN CHI EUM;;;; 316D;HANGUL LETTER RIEUL-YEORINHIEUH;Lo;0;L; 11D9;;;;N;HANGUL LETTER LIEUL YEOLIN HIEUH;;;; 316E;HANGUL LETTER MIEUM-PIEUP;Lo;0;L; 111C;;;;N;HANGUL LETTER MIEUM BIEUB;;;; 316F;HANGUL LETTER MIEUM-SIOS;Lo;0;L; 11DD;;;;N;HANGUL LETTER MIEUM SIOS;;;; 3170;HANGUL LETTER MIEUM-PANSIOS;Lo;0;L; 11DF;;;;N;HANGUL LETTER BIEUB BAN CHI EUM;;;; 3171;HANGUL LETTER KAPYEOUNMIEUM;Lo;0;L; 111D;;;;N;HANGUL LETTER MIEUM SUN GYEONG EUM;;;; 3172;HANGUL LETTER PIEUP-KIYEOK;Lo;0;L; 111E;;;;N;HANGUL LETTER BIEUB GIYEOG;;;; 3173;HANGUL LETTER PIEUP-TIKEUT;Lo;0;L; 1120;;;;N;HANGUL LETTER BIEUB DIGEUD;;;; 3174;HANGUL LETTER PIEUP-SIOS-KIYEOK;Lo;0;L; 1122;;;;N;HANGUL LETTER BIEUB SIOS GIYEOG;;;; 3175;HANGUL LETTER PIEUP-SIOS-TIKEUT;Lo;0;L; 1123;;;;N;HANGUL LETTER BIEUB SIOS DIGEUD;;;; 3176;HANGUL LETTER PIEUP-CIEUC;Lo;0;L; 1127;;;;N;HANGUL LETTER BIEUB JIEUJ;;;; 3177;HANGUL LETTER PIEUP-THIEUTH;Lo;0;L; 1129;;;;N;HANGUL LETTER BIEUB TIEUT;;;; 3178;HANGUL LETTER KAPYEOUNPIEUP;Lo;0;L; 112B;;;;N;HANGUL LETTER BIEUB SUN GYEONG EUM;;;; 3179;HANGUL LETTER KAPYEOUNSSANGPIEUP;Lo;0;L; 112C;;;;N;HANGUL LETTER SSANG BIEUB SUN GYEONG EUM;;;; 317A;HANGUL LETTER SIOS-KIYEOK;Lo;0;L; 112D;;;;N;HANGUL LETTER SIOS GIYEOG;;;; 317B;HANGUL LETTER SIOS-NIEUN;Lo;0;L; 112E;;;;N;HANGUL LETTER SIOS NIEUN;;;; 317C;HANGUL LETTER SIOS-TIKEUT;Lo;0;L; 112F;;;;N;HANGUL LETTER SIOS DIGEUD;;;; 317D;HANGUL LETTER SIOS-PIEUP;Lo;0;L; 1132;;;;N;HANGUL LETTER SIOS BIEUB;;;; 317E;HANGUL LETTER SIOS-CIEUC;Lo;0;L; 1136;;;;N;HANGUL LETTER SIOS JIEUJ;;;; 317F;HANGUL LETTER PANSIOS;Lo;0;L; 1140;;;;N;HANGUL LETTER BAN CHI EUM;;;; 3180;HANGUL LETTER SSANGIEUNG;Lo;0;L; 1147;;;;N;HANGUL LETTER SSANG IEUNG;;;; 3181;HANGUL LETTER YESIEUNG;Lo;0;L; 114C;;;;N;HANGUL LETTER NGIEUNG;;;; 3182;HANGUL LETTER YESIEUNG-SIOS;Lo;0;L; 11F1;;;;N;HANGUL LETTER NGIEUNG SIOS;;;; 3183;HANGUL LETTER YESIEUNG-PANSIOS;Lo;0;L; 11F2;;;;N;HANGUL LETTER NGIEUNG BAN CHI EUM;;;; 3184;HANGUL LETTER KAPYEOUNPHIEUPH;Lo;0;L; 1157;;;;N;HANGUL LETTER PIEUP SUN GYEONG EUM;;;; 3185;HANGUL LETTER SSANGHIEUH;Lo;0;L; 1158;;;;N;HANGUL LETTER SSANG HIEUH;;;; 3186;HANGUL LETTER YEORINHIEUH;Lo;0;L; 1159;;;;N;HANGUL LETTER YEOLIN HIEUH;;;; 3187;HANGUL LETTER YO-YA;Lo;0;L; 1184;;;;N;HANGUL LETTER YOYA;;;; 3188;HANGUL LETTER YO-YAE;Lo;0;L; 1185;;;;N;HANGUL LETTER YOYAE;;;; 3189;HANGUL LETTER YO-I;Lo;0;L; 1188;;;;N;HANGUL LETTER YOI;;;; 318A;HANGUL LETTER YU-YEO;Lo;0;L; 1191;;;;N;HANGUL LETTER YUYEO;;;; 318B;HANGUL LETTER YU-YE;Lo;0;L; 1192;;;;N;HANGUL LETTER YUYE;;;; 318C;HANGUL LETTER YU-I;Lo;0;L; 1194;;;;N;HANGUL LETTER YUI;;;; 318D;HANGUL LETTER ARAEA;Lo;0;L; 119E;;;;N;HANGUL LETTER ALAE A;;;; 318E;HANGUL LETTER ARAEAE;Lo;0;L; 11A1;;;;N;HANGUL LETTER ALAE AE;;;; 3190;IDEOGRAPHIC ANNOTATION LINKING MARK;So;0;L;;;;;N;KANBUN TATETEN;Kanbun Tateten;;; 3191;IDEOGRAPHIC ANNOTATION REVERSE MARK;So;0;L;;;;;N;KAERITEN RE;Kaeriten;;; 3192;IDEOGRAPHIC ANNOTATION ONE MARK;No;0;L; 4E00;;;1;N;KAERITEN ITI;Kaeriten;;; 3193;IDEOGRAPHIC ANNOTATION TWO MARK;No;0;L; 4E8C;;;2;N;KAERITEN NI;Kaeriten;;; 3194;IDEOGRAPHIC ANNOTATION THREE MARK;No;0;L; 4E09;;;3;N;KAERITEN SAN;Kaeriten;;; 3195;IDEOGRAPHIC ANNOTATION FOUR MARK;No;0;L; 56DB;;;4;N;KAERITEN SI;Kaeriten;;; 3196;IDEOGRAPHIC ANNOTATION TOP MARK;So;0;L; 4E0A;;;;N;KAERITEN ZYOU;Kaeriten;;; 3197;IDEOGRAPHIC ANNOTATION MIDDLE MARK;So;0;L; 4E2D;;;;N;KAERITEN TYUU;Kaeriten;;; 3198;IDEOGRAPHIC ANNOTATION BOTTOM MARK;So;0;L; 4E0B;;;;N;KAERITEN GE;Kaeriten;;; 3199;IDEOGRAPHIC ANNOTATION FIRST MARK;So;0;L; 7532;;;;N;KAERITEN KOU;Kaeriten;;; 319A;IDEOGRAPHIC ANNOTATION SECOND MARK;So;0;L; 4E59;;;;N;KAERITEN OTU;Kaeriten;;; 319B;IDEOGRAPHIC ANNOTATION THIRD MARK;So;0;L; 4E19;;;;N;KAERITEN HEI;Kaeriten;;; 319C;IDEOGRAPHIC ANNOTATION FOURTH MARK;So;0;L; 4E01;;;;N;KAERITEN TEI;Kaeriten;;; 319D;IDEOGRAPHIC ANNOTATION HEAVEN MARK;So;0;L; 5929;;;;N;KAERITEN TEN;Kaeriten;;; 319E;IDEOGRAPHIC ANNOTATION EARTH MARK;So;0;L; 5730;;;;N;KAERITEN TI;Kaeriten;;; 319F;IDEOGRAPHIC ANNOTATION MAN MARK;So;0;L; 4EBA;;;;N;KAERITEN ZIN;Kaeriten;;; 31A0;BOPOMOFO LETTER BU;Lo;0;L;;;;;N;;;;; 31A1;BOPOMOFO LETTER ZI;Lo;0;L;;;;;N;;;;; 31A2;BOPOMOFO LETTER JI;Lo;0;L;;;;;N;;;;; 31A3;BOPOMOFO LETTER GU;Lo;0;L;;;;;N;;;;; 31A4;BOPOMOFO LETTER EE;Lo;0;L;;;;;N;;;;; 31A5;BOPOMOFO LETTER ENN;Lo;0;L;;;;;N;;;;; 31A6;BOPOMOFO LETTER OO;Lo;0;L;;;;;N;;;;; 31A7;BOPOMOFO LETTER ONN;Lo;0;L;;;;;N;;;;; 31A8;BOPOMOFO LETTER IR;Lo;0;L;;;;;N;;;;; 31A9;BOPOMOFO LETTER ANN;Lo;0;L;;;;;N;;;;; 31AA;BOPOMOFO LETTER INN;Lo;0;L;;;;;N;;;;; 31AB;BOPOMOFO LETTER UNN;Lo;0;L;;;;;N;;;;; 31AC;BOPOMOFO LETTER IM;Lo;0;L;;;;;N;;;;; 31AD;BOPOMOFO LETTER NGG;Lo;0;L;;;;;N;;;;; 31AE;BOPOMOFO LETTER AINN;Lo;0;L;;;;;N;;;;; 31AF;BOPOMOFO LETTER AUNN;Lo;0;L;;;;;N;;;;; 31B0;BOPOMOFO LETTER AM;Lo;0;L;;;;;N;;;;; 31B1;BOPOMOFO LETTER OM;Lo;0;L;;;;;N;;;;; 31B2;BOPOMOFO LETTER ONG;Lo;0;L;;;;;N;;;;; 31B3;BOPOMOFO LETTER INNN;Lo;0;L;;;;;N;;;;; 31B4;BOPOMOFO FINAL LETTER P;Lo;0;L;;;;;N;;;;; 31B5;BOPOMOFO FINAL LETTER T;Lo;0;L;;;;;N;;;;; 31B6;BOPOMOFO FINAL LETTER K;Lo;0;L;;;;;N;;;;; 31B7;BOPOMOFO FINAL LETTER H;Lo;0;L;;;;;N;;;;; 31F0;KATAKANA LETTER SMALL KU;Lo;0;L;;;;;N;;;;; 31F1;KATAKANA LETTER SMALL SI;Lo;0;L;;;;;N;;;;; 31F2;KATAKANA LETTER SMALL SU;Lo;0;L;;;;;N;;;;; 31F3;KATAKANA LETTER SMALL TO;Lo;0;L;;;;;N;;;;; 31F4;KATAKANA LETTER SMALL NU;Lo;0;L;;;;;N;;;;; 31F5;KATAKANA LETTER SMALL HA;Lo;0;L;;;;;N;;;;; 31F6;KATAKANA LETTER SMALL HI;Lo;0;L;;;;;N;;;;; 31F7;KATAKANA LETTER SMALL HU;Lo;0;L;;;;;N;;;;; 31F8;KATAKANA LETTER SMALL HE;Lo;0;L;;;;;N;;;;; 31F9;KATAKANA LETTER SMALL HO;Lo;0;L;;;;;N;;;;; 31FA;KATAKANA LETTER SMALL MU;Lo;0;L;;;;;N;;;;; 31FB;KATAKANA LETTER SMALL RA;Lo;0;L;;;;;N;;;;; 31FC;KATAKANA LETTER SMALL RI;Lo;0;L;;;;;N;;;;; 31FD;KATAKANA LETTER SMALL RU;Lo;0;L;;;;;N;;;;; 31FE;KATAKANA LETTER SMALL RE;Lo;0;L;;;;;N;;;;; 31FF;KATAKANA LETTER SMALL RO;Lo;0;L;;;;;N;;;;; 3200;PARENTHESIZED HANGUL KIYEOK;So;0;L; 0028 1100 0029;;;;N;PARENTHESIZED HANGUL GIYEOG;;;; 3201;PARENTHESIZED HANGUL NIEUN;So;0;L; 0028 1102 0029;;;;N;;;;; 3202;PARENTHESIZED HANGUL TIKEUT;So;0;L; 0028 1103 0029;;;;N;PARENTHESIZED HANGUL DIGEUD;;;; 3203;PARENTHESIZED HANGUL RIEUL;So;0;L; 0028 1105 0029;;;;N;PARENTHESIZED HANGUL LIEUL;;;; 3204;PARENTHESIZED HANGUL MIEUM;So;0;L; 0028 1106 0029;;;;N;;;;; 3205;PARENTHESIZED HANGUL PIEUP;So;0;L; 0028 1107 0029;;;;N;PARENTHESIZED HANGUL BIEUB;;;; 3206;PARENTHESIZED HANGUL SIOS;So;0;L; 0028 1109 0029;;;;N;;;;; 3207;PARENTHESIZED HANGUL IEUNG;So;0;L; 0028 110B 0029;;;;N;;;;; 3208;PARENTHESIZED HANGUL CIEUC;So;0;L; 0028 110C 0029;;;;N;PARENTHESIZED HANGUL JIEUJ;;;; 3209;PARENTHESIZED HANGUL CHIEUCH;So;0;L; 0028 110E 0029;;;;N;PARENTHESIZED HANGUL CIEUC;;;; 320A;PARENTHESIZED HANGUL KHIEUKH;So;0;L; 0028 110F 0029;;;;N;PARENTHESIZED HANGUL KIYEOK;;;; 320B;PARENTHESIZED HANGUL THIEUTH;So;0;L; 0028 1110 0029;;;;N;PARENTHESIZED HANGUL TIEUT;;;; 320C;PARENTHESIZED HANGUL PHIEUPH;So;0;L; 0028 1111 0029;;;;N;PARENTHESIZED HANGUL PIEUP;;;; 320D;PARENTHESIZED HANGUL HIEUH;So;0;L; 0028 1112 0029;;;;N;;;;; 320E;PARENTHESIZED HANGUL KIYEOK A;So;0;L; 0028 1100 1161 0029;;;;N;PARENTHESIZED HANGUL GA;;;; 320F;PARENTHESIZED HANGUL NIEUN A;So;0;L; 0028 1102 1161 0029;;;;N;PARENTHESIZED HANGUL NA;;;; 3210;PARENTHESIZED HANGUL TIKEUT A;So;0;L; 0028 1103 1161 0029;;;;N;PARENTHESIZED HANGUL DA;;;; 3211;PARENTHESIZED HANGUL RIEUL A;So;0;L; 0028 1105 1161 0029;;;;N;PARENTHESIZED HANGUL LA;;;; 3212;PARENTHESIZED HANGUL MIEUM A;So;0;L; 0028 1106 1161 0029;;;;N;PARENTHESIZED HANGUL MA;;;; 3213;PARENTHESIZED HANGUL PIEUP A;So;0;L; 0028 1107 1161 0029;;;;N;PARENTHESIZED HANGUL BA;;;; 3214;PARENTHESIZED HANGUL SIOS A;So;0;L; 0028 1109 1161 0029;;;;N;PARENTHESIZED HANGUL SA;;;; 3215;PARENTHESIZED HANGUL IEUNG A;So;0;L; 0028 110B 1161 0029;;;;N;PARENTHESIZED HANGUL A;;;; 3216;PARENTHESIZED HANGUL CIEUC A;So;0;L; 0028 110C 1161 0029;;;;N;PARENTHESIZED HANGUL JA;;;; 3217;PARENTHESIZED HANGUL CHIEUCH A;So;0;L; 0028 110E 1161 0029;;;;N;PARENTHESIZED HANGUL CA;;;; 3218;PARENTHESIZED HANGUL KHIEUKH A;So;0;L; 0028 110F 1161 0029;;;;N;PARENTHESIZED HANGUL KA;;;; 3219;PARENTHESIZED HANGUL THIEUTH A;So;0;L; 0028 1110 1161 0029;;;;N;PARENTHESIZED HANGUL TA;;;; 321A;PARENTHESIZED HANGUL PHIEUPH A;So;0;L; 0028 1111 1161 0029;;;;N;PARENTHESIZED HANGUL PA;;;; 321B;PARENTHESIZED HANGUL HIEUH A;So;0;L; 0028 1112 1161 0029;;;;N;PARENTHESIZED HANGUL HA;;;; 321C;PARENTHESIZED HANGUL CIEUC U;So;0;L; 0028 110C 116E 0029;;;;N;PARENTHESIZED HANGUL JU;;;; 3220;PARENTHESIZED IDEOGRAPH ONE;No;0;L; 0028 4E00 0029;;;1;N;;;;; 3221;PARENTHESIZED IDEOGRAPH TWO;No;0;L; 0028 4E8C 0029;;;2;N;;;;; 3222;PARENTHESIZED IDEOGRAPH THREE;No;0;L; 0028 4E09 0029;;;3;N;;;;; 3223;PARENTHESIZED IDEOGRAPH FOUR;No;0;L; 0028 56DB 0029;;;4;N;;;;; 3224;PARENTHESIZED IDEOGRAPH FIVE;No;0;L; 0028 4E94 0029;;;5;N;;;;; 3225;PARENTHESIZED IDEOGRAPH SIX;No;0;L; 0028 516D 0029;;;6;N;;;;; 3226;PARENTHESIZED IDEOGRAPH SEVEN;No;0;L; 0028 4E03 0029;;;7;N;;;;; 3227;PARENTHESIZED IDEOGRAPH EIGHT;No;0;L; 0028 516B 0029;;;8;N;;;;; 3228;PARENTHESIZED IDEOGRAPH NINE;No;0;L; 0028 4E5D 0029;;;9;N;;;;; 3229;PARENTHESIZED IDEOGRAPH TEN;No;0;L; 0028 5341 0029;;;10;N;;;;; 322A;PARENTHESIZED IDEOGRAPH MOON;So;0;L; 0028 6708 0029;;;;N;;;;; 322B;PARENTHESIZED IDEOGRAPH FIRE;So;0;L; 0028 706B 0029;;;;N;;;;; 322C;PARENTHESIZED IDEOGRAPH WATER;So;0;L; 0028 6C34 0029;;;;N;;;;; 322D;PARENTHESIZED IDEOGRAPH WOOD;So;0;L; 0028 6728 0029;;;;N;;;;; 322E;PARENTHESIZED IDEOGRAPH METAL;So;0;L; 0028 91D1 0029;;;;N;;;;; 322F;PARENTHESIZED IDEOGRAPH EARTH;So;0;L; 0028 571F 0029;;;;N;;;;; 3230;PARENTHESIZED IDEOGRAPH SUN;So;0;L; 0028 65E5 0029;;;;N;;;;; 3231;PARENTHESIZED IDEOGRAPH STOCK;So;0;L; 0028 682A 0029;;;;N;;;;; 3232;PARENTHESIZED IDEOGRAPH HAVE;So;0;L; 0028 6709 0029;;;;N;;;;; 3233;PARENTHESIZED IDEOGRAPH SOCIETY;So;0;L; 0028 793E 0029;;;;N;;;;; 3234;PARENTHESIZED IDEOGRAPH NAME;So;0;L; 0028 540D 0029;;;;N;;;;; 3235;PARENTHESIZED IDEOGRAPH SPECIAL;So;0;L; 0028 7279 0029;;;;N;;;;; 3236;PARENTHESIZED IDEOGRAPH FINANCIAL;So;0;L; 0028 8CA1 0029;;;;N;;;;; 3237;PARENTHESIZED IDEOGRAPH CONGRATULATION;So;0;L; 0028 795D 0029;;;;N;;;;; 3238;PARENTHESIZED IDEOGRAPH LABOR;So;0;L; 0028 52B4 0029;;;;N;;;;; 3239;PARENTHESIZED IDEOGRAPH REPRESENT;So;0;L; 0028 4EE3 0029;;;;N;;;;; 323A;PARENTHESIZED IDEOGRAPH CALL;So;0;L; 0028 547C 0029;;;;N;;;;; 323B;PARENTHESIZED IDEOGRAPH STUDY;So;0;L; 0028 5B66 0029;;;;N;;;;; 323C;PARENTHESIZED IDEOGRAPH SUPERVISE;So;0;L; 0028 76E3 0029;;;;N;;;;; 323D;PARENTHESIZED IDEOGRAPH ENTERPRISE;So;0;L; 0028 4F01 0029;;;;N;;;;; 323E;PARENTHESIZED IDEOGRAPH RESOURCE;So;0;L; 0028 8CC7 0029;;;;N;;;;; 323F;PARENTHESIZED IDEOGRAPH ALLIANCE;So;0;L; 0028 5354 0029;;;;N;;;;; 3240;PARENTHESIZED IDEOGRAPH FESTIVAL;So;0;L; 0028 796D 0029;;;;N;;;;; 3241;PARENTHESIZED IDEOGRAPH REST;So;0;L; 0028 4F11 0029;;;;N;;;;; 3242;PARENTHESIZED IDEOGRAPH SELF;So;0;L; 0028 81EA 0029;;;;N;;;;; 3243;PARENTHESIZED IDEOGRAPH REACH;So;0;L; 0028 81F3 0029;;;;N;;;;; 3251;CIRCLED NUMBER TWENTY ONE;No;0;ON; 0032 0031;;;21;N;;;;; 3252;CIRCLED NUMBER TWENTY TWO;No;0;ON; 0032 0032;;;22;N;;;;; 3253;CIRCLED NUMBER TWENTY THREE;No;0;ON; 0032 0033;;;23;N;;;;; 3254;CIRCLED NUMBER TWENTY FOUR;No;0;ON; 0032 0034;;;24;N;;;;; 3255;CIRCLED NUMBER TWENTY FIVE;No;0;ON; 0032 0035;;;25;N;;;;; 3256;CIRCLED NUMBER TWENTY SIX;No;0;ON; 0032 0036;;;26;N;;;;; 3257;CIRCLED NUMBER TWENTY SEVEN;No;0;ON; 0032 0037;;;27;N;;;;; 3258;CIRCLED NUMBER TWENTY EIGHT;No;0;ON; 0032 0038;;;28;N;;;;; 3259;CIRCLED NUMBER TWENTY NINE;No;0;ON; 0032 0039;;;29;N;;;;; 325A;CIRCLED NUMBER THIRTY;No;0;ON; 0033 0030;;;30;N;;;;; 325B;CIRCLED NUMBER THIRTY ONE;No;0;ON; 0033 0031;;;31;N;;;;; 325C;CIRCLED NUMBER THIRTY TWO;No;0;ON; 0033 0032;;;32;N;;;;; 325D;CIRCLED NUMBER THIRTY THREE;No;0;ON; 0033 0033;;;33;N;;;;; 325E;CIRCLED NUMBER THIRTY FOUR;No;0;ON; 0033 0034;;;34;N;;;;; 325F;CIRCLED NUMBER THIRTY FIVE;No;0;ON; 0033 0035;;;35;N;;;;; 3260;CIRCLED HANGUL KIYEOK;So;0;L; 1100;;;;N;CIRCLED HANGUL GIYEOG;;;; 3261;CIRCLED HANGUL NIEUN;So;0;L; 1102;;;;N;;;;; 3262;CIRCLED HANGUL TIKEUT;So;0;L; 1103;;;;N;CIRCLED HANGUL DIGEUD;;;; 3263;CIRCLED HANGUL RIEUL;So;0;L; 1105;;;;N;CIRCLED HANGUL LIEUL;;;; 3264;CIRCLED HANGUL MIEUM;So;0;L; 1106;;;;N;;;;; 3265;CIRCLED HANGUL PIEUP;So;0;L; 1107;;;;N;CIRCLED HANGUL BIEUB;;;; 3266;CIRCLED HANGUL SIOS;So;0;L; 1109;;;;N;;;;; 3267;CIRCLED HANGUL IEUNG;So;0;L; 110B;;;;N;;;;; 3268;CIRCLED HANGUL CIEUC;So;0;L; 110C;;;;N;CIRCLED HANGUL JIEUJ;;;; 3269;CIRCLED HANGUL CHIEUCH;So;0;L; 110E;;;;N;CIRCLED HANGUL CIEUC;;;; 326A;CIRCLED HANGUL KHIEUKH;So;0;L; 110F;;;;N;CIRCLED HANGUL KIYEOK;;;; 326B;CIRCLED HANGUL THIEUTH;So;0;L; 1110;;;;N;CIRCLED HANGUL TIEUT;;;; 326C;CIRCLED HANGUL PHIEUPH;So;0;L; 1111;;;;N;CIRCLED HANGUL PIEUP;;;; 326D;CIRCLED HANGUL HIEUH;So;0;L; 1112;;;;N;;;;; 326E;CIRCLED HANGUL KIYEOK A;So;0;L; 1100 1161;;;;N;CIRCLED HANGUL GA;;;; 326F;CIRCLED HANGUL NIEUN A;So;0;L; 1102 1161;;;;N;CIRCLED HANGUL NA;;;; 3270;CIRCLED HANGUL TIKEUT A;So;0;L; 1103 1161;;;;N;CIRCLED HANGUL DA;;;; 3271;CIRCLED HANGUL RIEUL A;So;0;L; 1105 1161;;;;N;CIRCLED HANGUL LA;;;; 3272;CIRCLED HANGUL MIEUM A;So;0;L; 1106 1161;;;;N;CIRCLED HANGUL MA;;;; 3273;CIRCLED HANGUL PIEUP A;So;0;L; 1107 1161;;;;N;CIRCLED HANGUL BA;;;; 3274;CIRCLED HANGUL SIOS A;So;0;L; 1109 1161;;;;N;CIRCLED HANGUL SA;;;; 3275;CIRCLED HANGUL IEUNG A;So;0;L; 110B 1161;;;;N;CIRCLED HANGUL A;;;; 3276;CIRCLED HANGUL CIEUC A;So;0;L; 110C 1161;;;;N;CIRCLED HANGUL JA;;;; 3277;CIRCLED HANGUL CHIEUCH A;So;0;L; 110E 1161;;;;N;CIRCLED HANGUL CA;;;; 3278;CIRCLED HANGUL KHIEUKH A;So;0;L; 110F 1161;;;;N;CIRCLED HANGUL KA;;;; 3279;CIRCLED HANGUL THIEUTH A;So;0;L; 1110 1161;;;;N;CIRCLED HANGUL TA;;;; 327A;CIRCLED HANGUL PHIEUPH A;So;0;L; 1111 1161;;;;N;CIRCLED HANGUL PA;;;; 327B;CIRCLED HANGUL HIEUH A;So;0;L; 1112 1161;;;;N;CIRCLED HANGUL HA;;;; 327F;KOREAN STANDARD SYMBOL;So;0;L;;;;;N;;;;; 3280;CIRCLED IDEOGRAPH ONE;No;0;L; 4E00;;;1;N;;;;; 3281;CIRCLED IDEOGRAPH TWO;No;0;L; 4E8C;;;2;N;;;;; 3282;CIRCLED IDEOGRAPH THREE;No;0;L; 4E09;;;3;N;;;;; 3283;CIRCLED IDEOGRAPH FOUR;No;0;L; 56DB;;;4;N;;;;; 3284;CIRCLED IDEOGRAPH FIVE;No;0;L; 4E94;;;5;N;;;;; 3285;CIRCLED IDEOGRAPH SIX;No;0;L; 516D;;;6;N;;;;; 3286;CIRCLED IDEOGRAPH SEVEN;No;0;L; 4E03;;;7;N;;;;; 3287;CIRCLED IDEOGRAPH EIGHT;No;0;L; 516B;;;8;N;;;;; 3288;CIRCLED IDEOGRAPH NINE;No;0;L; 4E5D;;;9;N;;;;; 3289;CIRCLED IDEOGRAPH TEN;No;0;L; 5341;;;10;N;;;;; 328A;CIRCLED IDEOGRAPH MOON;So;0;L; 6708;;;;N;;;;; 328B;CIRCLED IDEOGRAPH FIRE;So;0;L; 706B;;;;N;;;;; 328C;CIRCLED IDEOGRAPH WATER;So;0;L; 6C34;;;;N;;;;; 328D;CIRCLED IDEOGRAPH WOOD;So;0;L; 6728;;;;N;;;;; 328E;CIRCLED IDEOGRAPH METAL;So;0;L; 91D1;;;;N;;;;; 328F;CIRCLED IDEOGRAPH EARTH;So;0;L; 571F;;;;N;;;;; 3290;CIRCLED IDEOGRAPH SUN;So;0;L; 65E5;;;;N;;;;; 3291;CIRCLED IDEOGRAPH STOCK;So;0;L; 682A;;;;N;;;;; 3292;CIRCLED IDEOGRAPH HAVE;So;0;L; 6709;;;;N;;;;; 3293;CIRCLED IDEOGRAPH SOCIETY;So;0;L; 793E;;;;N;;;;; 3294;CIRCLED IDEOGRAPH NAME;So;0;L; 540D;;;;N;;;;; 3295;CIRCLED IDEOGRAPH SPECIAL;So;0;L; 7279;;;;N;;;;; 3296;CIRCLED IDEOGRAPH FINANCIAL;So;0;L; 8CA1;;;;N;;;;; 3297;CIRCLED IDEOGRAPH CONGRATULATION;So;0;L; 795D;;;;N;;;;; 3298;CIRCLED IDEOGRAPH LABOR;So;0;L; 52B4;;;;N;;;;; 3299;CIRCLED IDEOGRAPH SECRET;So;0;L; 79D8;;;;N;;;;; 329A;CIRCLED IDEOGRAPH MALE;So;0;L; 7537;;;;N;;;;; 329B;CIRCLED IDEOGRAPH FEMALE;So;0;L; 5973;;;;N;;;;; 329C;CIRCLED IDEOGRAPH SUITABLE;So;0;L; 9069;;;;N;;;;; 329D;CIRCLED IDEOGRAPH EXCELLENT;So;0;L; 512A;;;;N;;;;; 329E;CIRCLED IDEOGRAPH PRINT;So;0;L; 5370;;;;N;;;;; 329F;CIRCLED IDEOGRAPH ATTENTION;So;0;L; 6CE8;;;;N;;;;; 32A0;CIRCLED IDEOGRAPH ITEM;So;0;L; 9805;;;;N;;;;; 32A1;CIRCLED IDEOGRAPH REST;So;0;L; 4F11;;;;N;;;;; 32A2;CIRCLED IDEOGRAPH COPY;So;0;L; 5199;;;;N;;;;; 32A3;CIRCLED IDEOGRAPH CORRECT;So;0;L; 6B63;;;;N;;;;; 32A4;CIRCLED IDEOGRAPH HIGH;So;0;L; 4E0A;;;;N;;;;; 32A5;CIRCLED IDEOGRAPH CENTRE;So;0;L; 4E2D;;;;N;CIRCLED IDEOGRAPH CENTER;;;; 32A6;CIRCLED IDEOGRAPH LOW;So;0;L; 4E0B;;;;N;;;;; 32A7;CIRCLED IDEOGRAPH LEFT;So;0;L; 5DE6;;;;N;;;;; 32A8;CIRCLED IDEOGRAPH RIGHT;So;0;L; 53F3;;;;N;;;;; 32A9;CIRCLED IDEOGRAPH MEDICINE;So;0;L; 533B;;;;N;;;;; 32AA;CIRCLED IDEOGRAPH RELIGION;So;0;L; 5B97;;;;N;;;;; 32AB;CIRCLED IDEOGRAPH STUDY;So;0;L; 5B66;;;;N;;;;; 32AC;CIRCLED IDEOGRAPH SUPERVISE;So;0;L; 76E3;;;;N;;;;; 32AD;CIRCLED IDEOGRAPH ENTERPRISE;So;0;L; 4F01;;;;N;;;;; 32AE;CIRCLED IDEOGRAPH RESOURCE;So;0;L; 8CC7;;;;N;;;;; 32AF;CIRCLED IDEOGRAPH ALLIANCE;So;0;L; 5354;;;;N;;;;; 32B0;CIRCLED IDEOGRAPH NIGHT;So;0;L; 591C;;;;N;;;;; 32B1;CIRCLED NUMBER THIRTY SIX;No;0;ON; 0033 0036;;;36;N;;;;; 32B2;CIRCLED NUMBER THIRTY SEVEN;No;0;ON; 0033 0037;;;37;N;;;;; 32B3;CIRCLED NUMBER THIRTY EIGHT;No;0;ON; 0033 0038;;;38;N;;;;; 32B4;CIRCLED NUMBER THIRTY NINE;No;0;ON; 0033 0039;;;39;N;;;;; 32B5;CIRCLED NUMBER FORTY;No;0;ON; 0034 0030;;;40;N;;;;; 32B6;CIRCLED NUMBER FORTY ONE;No;0;ON; 0034 0031;;;41;N;;;;; 32B7;CIRCLED NUMBER FORTY TWO;No;0;ON; 0034 0032;;;42;N;;;;; 32B8;CIRCLED NUMBER FORTY THREE;No;0;ON; 0034 0033;;;43;N;;;;; 32B9;CIRCLED NUMBER FORTY FOUR;No;0;ON; 0034 0034;;;44;N;;;;; 32BA;CIRCLED NUMBER FORTY FIVE;No;0;ON; 0034 0035;;;45;N;;;;; 32BB;CIRCLED NUMBER FORTY SIX;No;0;ON; 0034 0036;;;46;N;;;;; 32BC;CIRCLED NUMBER FORTY SEVEN;No;0;ON; 0034 0037;;;47;N;;;;; 32BD;CIRCLED NUMBER FORTY EIGHT;No;0;ON; 0034 0038;;;48;N;;;;; 32BE;CIRCLED NUMBER FORTY NINE;No;0;ON; 0034 0039;;;49;N;;;;; 32BF;CIRCLED NUMBER FIFTY;No;0;ON; 0035 0030;;;50;N;;;;; 32C0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY;So;0;L; 0031 6708;;;;N;;;;; 32C1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY;So;0;L; 0032 6708;;;;N;;;;; 32C2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH;So;0;L; 0033 6708;;;;N;;;;; 32C3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL;So;0;L; 0034 6708;;;;N;;;;; 32C4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY;So;0;L; 0035 6708;;;;N;;;;; 32C5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE;So;0;L; 0036 6708;;;;N;;;;; 32C6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY;So;0;L; 0037 6708;;;;N;;;;; 32C7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST;So;0;L; 0038 6708;;;;N;;;;; 32C8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER;So;0;L; 0039 6708;;;;N;;;;; 32C9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER;So;0;L; 0031 0030 6708;;;;N;;;;; 32CA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER;So;0;L; 0031 0031 6708;;;;N;;;;; 32CB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER;So;0;L; 0031 0032 6708;;;;N;;;;; 32D0;CIRCLED KATAKANA A;So;0;L; 30A2;;;;N;;;;; 32D1;CIRCLED KATAKANA I;So;0;L; 30A4;;;;N;;;;; 32D2;CIRCLED KATAKANA U;So;0;L; 30A6;;;;N;;;;; 32D3;CIRCLED KATAKANA E;So;0;L; 30A8;;;;N;;;;; 32D4;CIRCLED KATAKANA O;So;0;L; 30AA;;;;N;;;;; 32D5;CIRCLED KATAKANA KA;So;0;L; 30AB;;;;N;;;;; 32D6;CIRCLED KATAKANA KI;So;0;L; 30AD;;;;N;;;;; 32D7;CIRCLED KATAKANA KU;So;0;L; 30AF;;;;N;;;;; 32D8;CIRCLED KATAKANA KE;So;0;L; 30B1;;;;N;;;;; 32D9;CIRCLED KATAKANA KO;So;0;L; 30B3;;;;N;;;;; 32DA;CIRCLED KATAKANA SA;So;0;L; 30B5;;;;N;;;;; 32DB;CIRCLED KATAKANA SI;So;0;L; 30B7;;;;N;;;;; 32DC;CIRCLED KATAKANA SU;So;0;L; 30B9;;;;N;;;;; 32DD;CIRCLED KATAKANA SE;So;0;L; 30BB;;;;N;;;;; 32DE;CIRCLED KATAKANA SO;So;0;L; 30BD;;;;N;;;;; 32DF;CIRCLED KATAKANA TA;So;0;L; 30BF;;;;N;;;;; 32E0;CIRCLED KATAKANA TI;So;0;L; 30C1;;;;N;;;;; 32E1;CIRCLED KATAKANA TU;So;0;L; 30C4;;;;N;;;;; 32E2;CIRCLED KATAKANA TE;So;0;L; 30C6;;;;N;;;;; 32E3;CIRCLED KATAKANA TO;So;0;L; 30C8;;;;N;;;;; 32E4;CIRCLED KATAKANA NA;So;0;L; 30CA;;;;N;;;;; 32E5;CIRCLED KATAKANA NI;So;0;L; 30CB;;;;N;;;;; 32E6;CIRCLED KATAKANA NU;So;0;L; 30CC;;;;N;;;;; 32E7;CIRCLED KATAKANA NE;So;0;L; 30CD;;;;N;;;;; 32E8;CIRCLED KATAKANA NO;So;0;L; 30CE;;;;N;;;;; 32E9;CIRCLED KATAKANA HA;So;0;L; 30CF;;;;N;;;;; 32EA;CIRCLED KATAKANA HI;So;0;L; 30D2;;;;N;;;;; 32EB;CIRCLED KATAKANA HU;So;0;L; 30D5;;;;N;;;;; 32EC;CIRCLED KATAKANA HE;So;0;L; 30D8;;;;N;;;;; 32ED;CIRCLED KATAKANA HO;So;0;L; 30DB;;;;N;;;;; 32EE;CIRCLED KATAKANA MA;So;0;L; 30DE;;;;N;;;;; 32EF;CIRCLED KATAKANA MI;So;0;L; 30DF;;;;N;;;;; 32F0;CIRCLED KATAKANA MU;So;0;L; 30E0;;;;N;;;;; 32F1;CIRCLED KATAKANA ME;So;0;L; 30E1;;;;N;;;;; 32F2;CIRCLED KATAKANA MO;So;0;L; 30E2;;;;N;;;;; 32F3;CIRCLED KATAKANA YA;So;0;L; 30E4;;;;N;;;;; 32F4;CIRCLED KATAKANA YU;So;0;L; 30E6;;;;N;;;;; 32F5;CIRCLED KATAKANA YO;So;0;L; 30E8;;;;N;;;;; 32F6;CIRCLED KATAKANA RA;So;0;L; 30E9;;;;N;;;;; 32F7;CIRCLED KATAKANA RI;So;0;L; 30EA;;;;N;;;;; 32F8;CIRCLED KATAKANA RU;So;0;L; 30EB;;;;N;;;;; 32F9;CIRCLED KATAKANA RE;So;0;L; 30EC;;;;N;;;;; 32FA;CIRCLED KATAKANA RO;So;0;L; 30ED;;;;N;;;;; 32FB;CIRCLED KATAKANA WA;So;0;L; 30EF;;;;N;;;;; 32FC;CIRCLED KATAKANA WI;So;0;L; 30F0;;;;N;;;;; 32FD;CIRCLED KATAKANA WE;So;0;L; 30F1;;;;N;;;;; 32FE;CIRCLED KATAKANA WO;So;0;L; 30F2;;;;N;;;;; 3300;SQUARE APAATO;So;0;L; 30A2 30D1 30FC 30C8;;;;N;SQUARED APAATO;;;; 3301;SQUARE ARUHUA;So;0;L; 30A2 30EB 30D5 30A1;;;;N;SQUARED ARUHUA;;;; 3302;SQUARE ANPEA;So;0;L; 30A2 30F3 30DA 30A2;;;;N;SQUARED ANPEA;;;; 3303;SQUARE AARU;So;0;L; 30A2 30FC 30EB;;;;N;SQUARED AARU;;;; 3304;SQUARE ININGU;So;0;L; 30A4 30CB 30F3 30B0;;;;N;SQUARED ININGU;;;; 3305;SQUARE INTI;So;0;L; 30A4 30F3 30C1;;;;N;SQUARED INTI;;;; 3306;SQUARE UON;So;0;L; 30A6 30A9 30F3;;;;N;SQUARED UON;;;; 3307;SQUARE ESUKUUDO;So;0;L; 30A8 30B9 30AF 30FC 30C9;;;;N;SQUARED ESUKUUDO;;;; 3308;SQUARE EEKAA;So;0;L; 30A8 30FC 30AB 30FC;;;;N;SQUARED EEKAA;;;; 3309;SQUARE ONSU;So;0;L; 30AA 30F3 30B9;;;;N;SQUARED ONSU;;;; 330A;SQUARE OOMU;So;0;L; 30AA 30FC 30E0;;;;N;SQUARED OOMU;;;; 330B;SQUARE KAIRI;So;0;L; 30AB 30A4 30EA;;;;N;SQUARED KAIRI;;;; 330C;SQUARE KARATTO;So;0;L; 30AB 30E9 30C3 30C8;;;;N;SQUARED KARATTO;;;; 330D;SQUARE KARORII;So;0;L; 30AB 30ED 30EA 30FC;;;;N;SQUARED KARORII;;;; 330E;SQUARE GARON;So;0;L; 30AC 30ED 30F3;;;;N;SQUARED GARON;;;; 330F;SQUARE GANMA;So;0;L; 30AC 30F3 30DE;;;;N;SQUARED GANMA;;;; 3310;SQUARE GIGA;So;0;L; 30AE 30AC;;;;N;SQUARED GIGA;;;; 3311;SQUARE GINII;So;0;L; 30AE 30CB 30FC;;;;N;SQUARED GINII;;;; 3312;SQUARE KYURII;So;0;L; 30AD 30E5 30EA 30FC;;;;N;SQUARED KYURII;;;; 3313;SQUARE GIRUDAA;So;0;L; 30AE 30EB 30C0 30FC;;;;N;SQUARED GIRUDAA;;;; 3314;SQUARE KIRO;So;0;L; 30AD 30ED;;;;N;SQUARED KIRO;;;; 3315;SQUARE KIROGURAMU;So;0;L; 30AD 30ED 30B0 30E9 30E0;;;;N;SQUARED KIROGURAMU;;;; 3316;SQUARE KIROMEETORU;So;0;L; 30AD 30ED 30E1 30FC 30C8 30EB;;;;N;SQUARED KIROMEETORU;;;; 3317;SQUARE KIROWATTO;So;0;L; 30AD 30ED 30EF 30C3 30C8;;;;N;SQUARED KIROWATTO;;;; 3318;SQUARE GURAMU;So;0;L; 30B0 30E9 30E0;;;;N;SQUARED GURAMU;;;; 3319;SQUARE GURAMUTON;So;0;L; 30B0 30E9 30E0 30C8 30F3;;;;N;SQUARED GURAMUTON;;;; 331A;SQUARE KURUZEIRO;So;0;L; 30AF 30EB 30BC 30A4 30ED;;;;N;SQUARED KURUZEIRO;;;; 331B;SQUARE KUROONE;So;0;L; 30AF 30ED 30FC 30CD;;;;N;SQUARED KUROONE;;;; 331C;SQUARE KEESU;So;0;L; 30B1 30FC 30B9;;;;N;SQUARED KEESU;;;; 331D;SQUARE KORUNA;So;0;L; 30B3 30EB 30CA;;;;N;SQUARED KORUNA;;;; 331E;SQUARE KOOPO;So;0;L; 30B3 30FC 30DD;;;;N;SQUARED KOOPO;;;; 331F;SQUARE SAIKURU;So;0;L; 30B5 30A4 30AF 30EB;;;;N;SQUARED SAIKURU;;;; 3320;SQUARE SANTIIMU;So;0;L; 30B5 30F3 30C1 30FC 30E0;;;;N;SQUARED SANTIIMU;;;; 3321;SQUARE SIRINGU;So;0;L; 30B7 30EA 30F3 30B0;;;;N;SQUARED SIRINGU;;;; 3322;SQUARE SENTI;So;0;L; 30BB 30F3 30C1;;;;N;SQUARED SENTI;;;; 3323;SQUARE SENTO;So;0;L; 30BB 30F3 30C8;;;;N;SQUARED SENTO;;;; 3324;SQUARE DAASU;So;0;L; 30C0 30FC 30B9;;;;N;SQUARED DAASU;;;; 3325;SQUARE DESI;So;0;L; 30C7 30B7;;;;N;SQUARED DESI;;;; 3326;SQUARE DORU;So;0;L; 30C9 30EB;;;;N;SQUARED DORU;;;; 3327;SQUARE TON;So;0;L; 30C8 30F3;;;;N;SQUARED TON;;;; 3328;SQUARE NANO;So;0;L; 30CA 30CE;;;;N;SQUARED NANO;;;; 3329;SQUARE NOTTO;So;0;L; 30CE 30C3 30C8;;;;N;SQUARED NOTTO;;;; 332A;SQUARE HAITU;So;0;L; 30CF 30A4 30C4;;;;N;SQUARED HAITU;;;; 332B;SQUARE PAASENTO;So;0;L; 30D1 30FC 30BB 30F3 30C8;;;;N;SQUARED PAASENTO;;;; 332C;SQUARE PAATU;So;0;L; 30D1 30FC 30C4;;;;N;SQUARED PAATU;;;; 332D;SQUARE BAARERU;So;0;L; 30D0 30FC 30EC 30EB;;;;N;SQUARED BAARERU;;;; 332E;SQUARE PIASUTORU;So;0;L; 30D4 30A2 30B9 30C8 30EB;;;;N;SQUARED PIASUTORU;;;; 332F;SQUARE PIKURU;So;0;L; 30D4 30AF 30EB;;;;N;SQUARED PIKURU;;;; 3330;SQUARE PIKO;So;0;L; 30D4 30B3;;;;N;SQUARED PIKO;;;; 3331;SQUARE BIRU;So;0;L; 30D3 30EB;;;;N;SQUARED BIRU;;;; 3332;SQUARE HUARADDO;So;0;L; 30D5 30A1 30E9 30C3 30C9;;;;N;SQUARED HUARADDO;;;; 3333;SQUARE HUIITO;So;0;L; 30D5 30A3 30FC 30C8;;;;N;SQUARED HUIITO;;;; 3334;SQUARE BUSSYERU;So;0;L; 30D6 30C3 30B7 30A7 30EB;;;;N;SQUARED BUSSYERU;;;; 3335;SQUARE HURAN;So;0;L; 30D5 30E9 30F3;;;;N;SQUARED HURAN;;;; 3336;SQUARE HEKUTAARU;So;0;L; 30D8 30AF 30BF 30FC 30EB;;;;N;SQUARED HEKUTAARU;;;; 3337;SQUARE PESO;So;0;L; 30DA 30BD;;;;N;SQUARED PESO;;;; 3338;SQUARE PENIHI;So;0;L; 30DA 30CB 30D2;;;;N;SQUARED PENIHI;;;; 3339;SQUARE HERUTU;So;0;L; 30D8 30EB 30C4;;;;N;SQUARED HERUTU;;;; 333A;SQUARE PENSU;So;0;L; 30DA 30F3 30B9;;;;N;SQUARED PENSU;;;; 333B;SQUARE PEEZI;So;0;L; 30DA 30FC 30B8;;;;N;SQUARED PEEZI;;;; 333C;SQUARE BEETA;So;0;L; 30D9 30FC 30BF;;;;N;SQUARED BEETA;;;; 333D;SQUARE POINTO;So;0;L; 30DD 30A4 30F3 30C8;;;;N;SQUARED POINTO;;;; 333E;SQUARE BORUTO;So;0;L; 30DC 30EB 30C8;;;;N;SQUARED BORUTO;;;; 333F;SQUARE HON;So;0;L; 30DB 30F3;;;;N;SQUARED HON;;;; 3340;SQUARE PONDO;So;0;L; 30DD 30F3 30C9;;;;N;SQUARED PONDO;;;; 3341;SQUARE HOORU;So;0;L; 30DB 30FC 30EB;;;;N;SQUARED HOORU;;;; 3342;SQUARE HOON;So;0;L; 30DB 30FC 30F3;;;;N;SQUARED HOON;;;; 3343;SQUARE MAIKURO;So;0;L; 30DE 30A4 30AF 30ED;;;;N;SQUARED MAIKURO;;;; 3344;SQUARE MAIRU;So;0;L; 30DE 30A4 30EB;;;;N;SQUARED MAIRU;;;; 3345;SQUARE MAHHA;So;0;L; 30DE 30C3 30CF;;;;N;SQUARED MAHHA;;;; 3346;SQUARE MARUKU;So;0;L; 30DE 30EB 30AF;;;;N;SQUARED MARUKU;;;; 3347;SQUARE MANSYON;So;0;L; 30DE 30F3 30B7 30E7 30F3;;;;N;SQUARED MANSYON;;;; 3348;SQUARE MIKURON;So;0;L; 30DF 30AF 30ED 30F3;;;;N;SQUARED MIKURON;;;; 3349;SQUARE MIRI;So;0;L; 30DF 30EA;;;;N;SQUARED MIRI;;;; 334A;SQUARE MIRIBAARU;So;0;L; 30DF 30EA 30D0 30FC 30EB;;;;N;SQUARED MIRIBAARU;;;; 334B;SQUARE MEGA;So;0;L; 30E1 30AC;;;;N;SQUARED MEGA;;;; 334C;SQUARE MEGATON;So;0;L; 30E1 30AC 30C8 30F3;;;;N;SQUARED MEGATON;;;; 334D;SQUARE MEETORU;So;0;L; 30E1 30FC 30C8 30EB;;;;N;SQUARED MEETORU;;;; 334E;SQUARE YAADO;So;0;L; 30E4 30FC 30C9;;;;N;SQUARED YAADO;;;; 334F;SQUARE YAARU;So;0;L; 30E4 30FC 30EB;;;;N;SQUARED YAARU;;;; 3350;SQUARE YUAN;So;0;L; 30E6 30A2 30F3;;;;N;SQUARED YUAN;;;; 3351;SQUARE RITTORU;So;0;L; 30EA 30C3 30C8 30EB;;;;N;SQUARED RITTORU;;;; 3352;SQUARE RIRA;So;0;L; 30EA 30E9;;;;N;SQUARED RIRA;;;; 3353;SQUARE RUPII;So;0;L; 30EB 30D4 30FC;;;;N;SQUARED RUPII;;;; 3354;SQUARE RUUBURU;So;0;L; 30EB 30FC 30D6 30EB;;;;N;SQUARED RUUBURU;;;; 3355;SQUARE REMU;So;0;L; 30EC 30E0;;;;N;SQUARED REMU;;;; 3356;SQUARE RENTOGEN;So;0;L; 30EC 30F3 30C8 30B2 30F3;;;;N;SQUARED RENTOGEN;;;; 3357;SQUARE WATTO;So;0;L; 30EF 30C3 30C8;;;;N;SQUARED WATTO;;;; 3358;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO;So;0;L; 0030 70B9;;;;N;;;;; 3359;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE;So;0;L; 0031 70B9;;;;N;;;;; 335A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO;So;0;L; 0032 70B9;;;;N;;;;; 335B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE;So;0;L; 0033 70B9;;;;N;;;;; 335C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR;So;0;L; 0034 70B9;;;;N;;;;; 335D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE;So;0;L; 0035 70B9;;;;N;;;;; 335E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX;So;0;L; 0036 70B9;;;;N;;;;; 335F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN;So;0;L; 0037 70B9;;;;N;;;;; 3360;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT;So;0;L; 0038 70B9;;;;N;;;;; 3361;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE;So;0;L; 0039 70B9;;;;N;;;;; 3362;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN;So;0;L; 0031 0030 70B9;;;;N;;;;; 3363;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN;So;0;L; 0031 0031 70B9;;;;N;;;;; 3364;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE;So;0;L; 0031 0032 70B9;;;;N;;;;; 3365;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN;So;0;L; 0031 0033 70B9;;;;N;;;;; 3366;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN;So;0;L; 0031 0034 70B9;;;;N;;;;; 3367;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN;So;0;L; 0031 0035 70B9;;;;N;;;;; 3368;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN;So;0;L; 0031 0036 70B9;;;;N;;;;; 3369;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN;So;0;L; 0031 0037 70B9;;;;N;;;;; 336A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN;So;0;L; 0031 0038 70B9;;;;N;;;;; 336B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN;So;0;L; 0031 0039 70B9;;;;N;;;;; 336C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY;So;0;L; 0032 0030 70B9;;;;N;;;;; 336D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE;So;0;L; 0032 0031 70B9;;;;N;;;;; 336E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO;So;0;L; 0032 0032 70B9;;;;N;;;;; 336F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE;So;0;L; 0032 0033 70B9;;;;N;;;;; 3370;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR;So;0;L; 0032 0034 70B9;;;;N;;;;; 3371;SQUARE HPA;So;0;L; 0068 0050 0061;;;;N;;;;; 3372;SQUARE DA;So;0;L; 0064 0061;;;;N;;;;; 3373;SQUARE AU;So;0;L; 0041 0055;;;;N;;;;; 3374;SQUARE BAR;So;0;L; 0062 0061 0072;;;;N;;;;; 3375;SQUARE OV;So;0;L; 006F 0056;;;;N;;;;; 3376;SQUARE PC;So;0;L; 0070 0063;;;;N;;;;; 337B;SQUARE ERA NAME HEISEI;So;0;L; 5E73 6210;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME HEISEI;;;; 337C;SQUARE ERA NAME SYOUWA;So;0;L; 662D 548C;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME SYOUWA;;;; 337D;SQUARE ERA NAME TAISYOU;So;0;L; 5927 6B63;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME TAISYOU;;;; 337E;SQUARE ERA NAME MEIZI;So;0;L; 660E 6CBB;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME MEIZI;;;; 337F;SQUARE CORPORATION;So;0;L; 682A 5F0F 4F1A 793E;;;;N;SQUARED FOUR IDEOGRAPHS CORPORATION;;;; 3380;SQUARE PA AMPS;So;0;L; 0070 0041;;;;N;SQUARED PA AMPS;;;; 3381;SQUARE NA;So;0;L; 006E 0041;;;;N;SQUARED NA;;;; 3382;SQUARE MU A;So;0;L; 03BC 0041;;;;N;SQUARED MU A;;;; 3383;SQUARE MA;So;0;L; 006D 0041;;;;N;SQUARED MA;;;; 3384;SQUARE KA;So;0;L; 006B 0041;;;;N;SQUARED KA;;;; 3385;SQUARE KB;So;0;L; 004B 0042;;;;N;SQUARED KB;;;; 3386;SQUARE MB;So;0;L; 004D 0042;;;;N;SQUARED MB;;;; 3387;SQUARE GB;So;0;L; 0047 0042;;;;N;SQUARED GB;;;; 3388;SQUARE CAL;So;0;L; 0063 0061 006C;;;;N;SQUARED CAL;;;; 3389;SQUARE KCAL;So;0;L; 006B 0063 0061 006C;;;;N;SQUARED KCAL;;;; 338A;SQUARE PF;So;0;L; 0070 0046;;;;N;SQUARED PF;;;; 338B;SQUARE NF;So;0;L; 006E 0046;;;;N;SQUARED NF;;;; 338C;SQUARE MU F;So;0;L; 03BC 0046;;;;N;SQUARED MU F;;;; 338D;SQUARE MU G;So;0;L; 03BC 0067;;;;N;SQUARED MU G;;;; 338E;SQUARE MG;So;0;L; 006D 0067;;;;N;SQUARED MG;;;; 338F;SQUARE KG;So;0;L; 006B 0067;;;;N;SQUARED KG;;;; 3390;SQUARE HZ;So;0;L; 0048 007A;;;;N;SQUARED HZ;;;; 3391;SQUARE KHZ;So;0;L; 006B 0048 007A;;;;N;SQUARED KHZ;;;; 3392;SQUARE MHZ;So;0;L; 004D 0048 007A;;;;N;SQUARED MHZ;;;; 3393;SQUARE GHZ;So;0;L; 0047 0048 007A;;;;N;SQUARED GHZ;;;; 3394;SQUARE THZ;So;0;L; 0054 0048 007A;;;;N;SQUARED THZ;;;; 3395;SQUARE MU L;So;0;L; 03BC 2113;;;;N;SQUARED MU L;;;; 3396;SQUARE ML;So;0;L; 006D 2113;;;;N;SQUARED ML;;;; 3397;SQUARE DL;So;0;L; 0064 2113;;;;N;SQUARED DL;;;; 3398;SQUARE KL;So;0;L; 006B 2113;;;;N;SQUARED KL;;;; 3399;SQUARE FM;So;0;L; 0066 006D;;;;N;SQUARED FM;;;; 339A;SQUARE NM;So;0;L; 006E 006D;;;;N;SQUARED NM;;;; 339B;SQUARE MU M;So;0;L; 03BC 006D;;;;N;SQUARED MU M;;;; 339C;SQUARE MM;So;0;L; 006D 006D;;;;N;SQUARED MM;;;; 339D;SQUARE CM;So;0;L; 0063 006D;;;;N;SQUARED CM;;;; 339E;SQUARE KM;So;0;L; 006B 006D;;;;N;SQUARED KM;;;; 339F;SQUARE MM SQUARED;So;0;L; 006D 006D 00B2;;;;N;SQUARED MM SQUARED;;;; 33A0;SQUARE CM SQUARED;So;0;L; 0063 006D 00B2;;;;N;SQUARED CM SQUARED;;;; 33A1;SQUARE M SQUARED;So;0;L; 006D 00B2;;;;N;SQUARED M SQUARED;;;; 33A2;SQUARE KM SQUARED;So;0;L; 006B 006D 00B2;;;;N;SQUARED KM SQUARED;;;; 33A3;SQUARE MM CUBED;So;0;L; 006D 006D 00B3;;;;N;SQUARED MM CUBED;;;; 33A4;SQUARE CM CUBED;So;0;L; 0063 006D 00B3;;;;N;SQUARED CM CUBED;;;; 33A5;SQUARE M CUBED;So;0;L; 006D 00B3;;;;N;SQUARED M CUBED;;;; 33A6;SQUARE KM CUBED;So;0;L; 006B 006D 00B3;;;;N;SQUARED KM CUBED;;;; 33A7;SQUARE M OVER S;So;0;L; 006D 2215 0073;;;;N;SQUARED M OVER S;;;; 33A8;SQUARE M OVER S SQUARED;So;0;L; 006D 2215 0073 00B2;;;;N;SQUARED M OVER S SQUARED;;;; 33A9;SQUARE PA;So;0;L; 0050 0061;;;;N;SQUARED PA;;;; 33AA;SQUARE KPA;So;0;L; 006B 0050 0061;;;;N;SQUARED KPA;;;; 33AB;SQUARE MPA;So;0;L; 004D 0050 0061;;;;N;SQUARED MPA;;;; 33AC;SQUARE GPA;So;0;L; 0047 0050 0061;;;;N;SQUARED GPA;;;; 33AD;SQUARE RAD;So;0;L; 0072 0061 0064;;;;N;SQUARED RAD;;;; 33AE;SQUARE RAD OVER S;So;0;L; 0072 0061 0064 2215 0073;;;;N;SQUARED RAD OVER S;;;; 33AF;SQUARE RAD OVER S SQUARED;So;0;L; 0072 0061 0064 2215 0073 00B2;;;;N;SQUARED RAD OVER S SQUARED;;;; 33B0;SQUARE PS;So;0;L; 0070 0073;;;;N;SQUARED PS;;;; 33B1;SQUARE NS;So;0;L; 006E 0073;;;;N;SQUARED NS;;;; 33B2;SQUARE MU S;So;0;L; 03BC 0073;;;;N;SQUARED MU S;;;; 33B3;SQUARE MS;So;0;L; 006D 0073;;;;N;SQUARED MS;;;; 33B4;SQUARE PV;So;0;L; 0070 0056;;;;N;SQUARED PV;;;; 33B5;SQUARE NV;So;0;L; 006E 0056;;;;N;SQUARED NV;;;; 33B6;SQUARE MU V;So;0;L; 03BC 0056;;;;N;SQUARED MU V;;;; 33B7;SQUARE MV;So;0;L; 006D 0056;;;;N;SQUARED MV;;;; 33B8;SQUARE KV;So;0;L; 006B 0056;;;;N;SQUARED KV;;;; 33B9;SQUARE MV MEGA;So;0;L; 004D 0056;;;;N;SQUARED MV MEGA;;;; 33BA;SQUARE PW;So;0;L; 0070 0057;;;;N;SQUARED PW;;;; 33BB;SQUARE NW;So;0;L; 006E 0057;;;;N;SQUARED NW;;;; 33BC;SQUARE MU W;So;0;L; 03BC 0057;;;;N;SQUARED MU W;;;; 33BD;SQUARE MW;So;0;L; 006D 0057;;;;N;SQUARED MW;;;; 33BE;SQUARE KW;So;0;L; 006B 0057;;;;N;SQUARED KW;;;; 33BF;SQUARE MW MEGA;So;0;L; 004D 0057;;;;N;SQUARED MW MEGA;;;; 33C0;SQUARE K OHM;So;0;L; 006B 03A9;;;;N;SQUARED K OHM;;;; 33C1;SQUARE M OHM;So;0;L; 004D 03A9;;;;N;SQUARED M OHM;;;; 33C2;SQUARE AM;So;0;L; 0061 002E 006D 002E;;;;N;SQUARED AM;;;; 33C3;SQUARE BQ;So;0;L; 0042 0071;;;;N;SQUARED BQ;;;; 33C4;SQUARE CC;So;0;L; 0063 0063;;;;N;SQUARED CC;;;; 33C5;SQUARE CD;So;0;L; 0063 0064;;;;N;SQUARED CD;;;; 33C6;SQUARE C OVER KG;So;0;L; 0043 2215 006B 0067;;;;N;SQUARED C OVER KG;;;; 33C7;SQUARE CO;So;0;L; 0043 006F 002E;;;;N;SQUARED CO;;;; 33C8;SQUARE DB;So;0;L; 0064 0042;;;;N;SQUARED DB;;;; 33C9;SQUARE GY;So;0;L; 0047 0079;;;;N;SQUARED GY;;;; 33CA;SQUARE HA;So;0;L; 0068 0061;;;;N;SQUARED HA;;;; 33CB;SQUARE HP;So;0;L; 0048 0050;;;;N;SQUARED HP;;;; 33CC;SQUARE IN;So;0;L; 0069 006E;;;;N;SQUARED IN;;;; 33CD;SQUARE KK;So;0;L; 004B 004B;;;;N;SQUARED KK;;;; 33CE;SQUARE KM CAPITAL;So;0;L; 004B 004D;;;;N;SQUARED KM CAPITAL;;;; 33CF;SQUARE KT;So;0;L; 006B 0074;;;;N;SQUARED KT;;;; 33D0;SQUARE LM;So;0;L; 006C 006D;;;;N;SQUARED LM;;;; 33D1;SQUARE LN;So;0;L; 006C 006E;;;;N;SQUARED LN;;;; 33D2;SQUARE LOG;So;0;L; 006C 006F 0067;;;;N;SQUARED LOG;;;; 33D3;SQUARE LX;So;0;L; 006C 0078;;;;N;SQUARED LX;;;; 33D4;SQUARE MB SMALL;So;0;L; 006D 0062;;;;N;SQUARED MB SMALL;;;; 33D5;SQUARE MIL;So;0;L; 006D 0069 006C;;;;N;SQUARED MIL;;;; 33D6;SQUARE MOL;So;0;L; 006D 006F 006C;;;;N;SQUARED MOL;;;; 33D7;SQUARE PH;So;0;L; 0050 0048;;;;N;SQUARED PH;;;; 33D8;SQUARE PM;So;0;L; 0070 002E 006D 002E;;;;N;SQUARED PM;;;; 33D9;SQUARE PPM;So;0;L; 0050 0050 004D;;;;N;SQUARED PPM;;;; 33DA;SQUARE PR;So;0;L; 0050 0052;;;;N;SQUARED PR;;;; 33DB;SQUARE SR;So;0;L; 0073 0072;;;;N;SQUARED SR;;;; 33DC;SQUARE SV;So;0;L; 0053 0076;;;;N;SQUARED SV;;;; 33DD;SQUARE WB;So;0;L; 0057 0062;;;;N;SQUARED WB;;;; 33E0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE;So;0;L; 0031 65E5;;;;N;;;;; 33E1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO;So;0;L; 0032 65E5;;;;N;;;;; 33E2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE;So;0;L; 0033 65E5;;;;N;;;;; 33E3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR;So;0;L; 0034 65E5;;;;N;;;;; 33E4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE;So;0;L; 0035 65E5;;;;N;;;;; 33E5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX;So;0;L; 0036 65E5;;;;N;;;;; 33E6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN;So;0;L; 0037 65E5;;;;N;;;;; 33E7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT;So;0;L; 0038 65E5;;;;N;;;;; 33E8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE;So;0;L; 0039 65E5;;;;N;;;;; 33E9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN;So;0;L; 0031 0030 65E5;;;;N;;;;; 33EA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN;So;0;L; 0031 0031 65E5;;;;N;;;;; 33EB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE;So;0;L; 0031 0032 65E5;;;;N;;;;; 33EC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN;So;0;L; 0031 0033 65E5;;;;N;;;;; 33ED;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN;So;0;L; 0031 0034 65E5;;;;N;;;;; 33EE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN;So;0;L; 0031 0035 65E5;;;;N;;;;; 33EF;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN;So;0;L; 0031 0036 65E5;;;;N;;;;; 33F0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN;So;0;L; 0031 0037 65E5;;;;N;;;;; 33F1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN;So;0;L; 0031 0038 65E5;;;;N;;;;; 33F2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN;So;0;L; 0031 0039 65E5;;;;N;;;;; 33F3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY;So;0;L; 0032 0030 65E5;;;;N;;;;; 33F4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE;So;0;L; 0032 0031 65E5;;;;N;;;;; 33F5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO;So;0;L; 0032 0032 65E5;;;;N;;;;; 33F6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE;So;0;L; 0032 0033 65E5;;;;N;;;;; 33F7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR;So;0;L; 0032 0034 65E5;;;;N;;;;; 33F8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE;So;0;L; 0032 0035 65E5;;;;N;;;;; 33F9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX;So;0;L; 0032 0036 65E5;;;;N;;;;; 33FA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN;So;0;L; 0032 0037 65E5;;;;N;;;;; 33FB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT;So;0;L; 0032 0038 65E5;;;;N;;;;; 33FC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE;So;0;L; 0032 0039 65E5;;;;N;;;;; 33FD;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY;So;0;L; 0033 0030 65E5;;;;N;;;;; 33FE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE;So;0;L; 0033 0031 65E5;;;;N;;;;; 3400;;Lo;0;L;;;;;N;;;;; 4DB5;;Lo;0;L;;;;;N;;;;; 4E00;;Lo;0;L;;;;;N;;;;; 9FA5;;Lo;0;L;;;;;N;;;;; A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;; A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;; A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;; A003;YI SYLLABLE IP;Lo;0;L;;;;;N;;;;; A004;YI SYLLABLE IET;Lo;0;L;;;;;N;;;;; A005;YI SYLLABLE IEX;Lo;0;L;;;;;N;;;;; A006;YI SYLLABLE IE;Lo;0;L;;;;;N;;;;; A007;YI SYLLABLE IEP;Lo;0;L;;;;;N;;;;; A008;YI SYLLABLE AT;Lo;0;L;;;;;N;;;;; A009;YI SYLLABLE AX;Lo;0;L;;;;;N;;;;; A00A;YI SYLLABLE A;Lo;0;L;;;;;N;;;;; A00B;YI SYLLABLE AP;Lo;0;L;;;;;N;;;;; A00C;YI SYLLABLE UOX;Lo;0;L;;;;;N;;;;; A00D;YI SYLLABLE UO;Lo;0;L;;;;;N;;;;; A00E;YI SYLLABLE UOP;Lo;0;L;;;;;N;;;;; A00F;YI SYLLABLE OT;Lo;0;L;;;;;N;;;;; A010;YI SYLLABLE OX;Lo;0;L;;;;;N;;;;; A011;YI SYLLABLE O;Lo;0;L;;;;;N;;;;; A012;YI SYLLABLE OP;Lo;0;L;;;;;N;;;;; A013;YI SYLLABLE EX;Lo;0;L;;;;;N;;;;; A014;YI SYLLABLE E;Lo;0;L;;;;;N;;;;; A015;YI SYLLABLE WU;Lo;0;L;;;;;N;;;;; A016;YI SYLLABLE BIT;Lo;0;L;;;;;N;;;;; A017;YI SYLLABLE BIX;Lo;0;L;;;;;N;;;;; A018;YI SYLLABLE BI;Lo;0;L;;;;;N;;;;; A019;YI SYLLABLE BIP;Lo;0;L;;;;;N;;;;; A01A;YI SYLLABLE BIET;Lo;0;L;;;;;N;;;;; A01B;YI SYLLABLE BIEX;Lo;0;L;;;;;N;;;;; A01C;YI SYLLABLE BIE;Lo;0;L;;;;;N;;;;; A01D;YI SYLLABLE BIEP;Lo;0;L;;;;;N;;;;; A01E;YI SYLLABLE BAT;Lo;0;L;;;;;N;;;;; A01F;YI SYLLABLE BAX;Lo;0;L;;;;;N;;;;; A020;YI SYLLABLE BA;Lo;0;L;;;;;N;;;;; A021;YI SYLLABLE BAP;Lo;0;L;;;;;N;;;;; A022;YI SYLLABLE BUOX;Lo;0;L;;;;;N;;;;; A023;YI SYLLABLE BUO;Lo;0;L;;;;;N;;;;; A024;YI SYLLABLE BUOP;Lo;0;L;;;;;N;;;;; A025;YI SYLLABLE BOT;Lo;0;L;;;;;N;;;;; A026;YI SYLLABLE BOX;Lo;0;L;;;;;N;;;;; A027;YI SYLLABLE BO;Lo;0;L;;;;;N;;;;; A028;YI SYLLABLE BOP;Lo;0;L;;;;;N;;;;; A029;YI SYLLABLE BEX;Lo;0;L;;;;;N;;;;; A02A;YI SYLLABLE BE;Lo;0;L;;;;;N;;;;; A02B;YI SYLLABLE BEP;Lo;0;L;;;;;N;;;;; A02C;YI SYLLABLE BUT;Lo;0;L;;;;;N;;;;; A02D;YI SYLLABLE BUX;Lo;0;L;;;;;N;;;;; A02E;YI SYLLABLE BU;Lo;0;L;;;;;N;;;;; A02F;YI SYLLABLE BUP;Lo;0;L;;;;;N;;;;; A030;YI SYLLABLE BURX;Lo;0;L;;;;;N;;;;; A031;YI SYLLABLE BUR;Lo;0;L;;;;;N;;;;; A032;YI SYLLABLE BYT;Lo;0;L;;;;;N;;;;; A033;YI SYLLABLE BYX;Lo;0;L;;;;;N;;;;; A034;YI SYLLABLE BY;Lo;0;L;;;;;N;;;;; A035;YI SYLLABLE BYP;Lo;0;L;;;;;N;;;;; A036;YI SYLLABLE BYRX;Lo;0;L;;;;;N;;;;; A037;YI SYLLABLE BYR;Lo;0;L;;;;;N;;;;; A038;YI SYLLABLE PIT;Lo;0;L;;;;;N;;;;; A039;YI SYLLABLE PIX;Lo;0;L;;;;;N;;;;; A03A;YI SYLLABLE PI;Lo;0;L;;;;;N;;;;; A03B;YI SYLLABLE PIP;Lo;0;L;;;;;N;;;;; A03C;YI SYLLABLE PIEX;Lo;0;L;;;;;N;;;;; A03D;YI SYLLABLE PIE;Lo;0;L;;;;;N;;;;; A03E;YI SYLLABLE PIEP;Lo;0;L;;;;;N;;;;; A03F;YI SYLLABLE PAT;Lo;0;L;;;;;N;;;;; A040;YI SYLLABLE PAX;Lo;0;L;;;;;N;;;;; A041;YI SYLLABLE PA;Lo;0;L;;;;;N;;;;; A042;YI SYLLABLE PAP;Lo;0;L;;;;;N;;;;; A043;YI SYLLABLE PUOX;Lo;0;L;;;;;N;;;;; A044;YI SYLLABLE PUO;Lo;0;L;;;;;N;;;;; A045;YI SYLLABLE PUOP;Lo;0;L;;;;;N;;;;; A046;YI SYLLABLE POT;Lo;0;L;;;;;N;;;;; A047;YI SYLLABLE POX;Lo;0;L;;;;;N;;;;; A048;YI SYLLABLE PO;Lo;0;L;;;;;N;;;;; A049;YI SYLLABLE POP;Lo;0;L;;;;;N;;;;; A04A;YI SYLLABLE PUT;Lo;0;L;;;;;N;;;;; A04B;YI SYLLABLE PUX;Lo;0;L;;;;;N;;;;; A04C;YI SYLLABLE PU;Lo;0;L;;;;;N;;;;; A04D;YI SYLLABLE PUP;Lo;0;L;;;;;N;;;;; A04E;YI SYLLABLE PURX;Lo;0;L;;;;;N;;;;; A04F;YI SYLLABLE PUR;Lo;0;L;;;;;N;;;;; A050;YI SYLLABLE PYT;Lo;0;L;;;;;N;;;;; A051;YI SYLLABLE PYX;Lo;0;L;;;;;N;;;;; A052;YI SYLLABLE PY;Lo;0;L;;;;;N;;;;; A053;YI SYLLABLE PYP;Lo;0;L;;;;;N;;;;; A054;YI SYLLABLE PYRX;Lo;0;L;;;;;N;;;;; A055;YI SYLLABLE PYR;Lo;0;L;;;;;N;;;;; A056;YI SYLLABLE BBIT;Lo;0;L;;;;;N;;;;; A057;YI SYLLABLE BBIX;Lo;0;L;;;;;N;;;;; A058;YI SYLLABLE BBI;Lo;0;L;;;;;N;;;;; A059;YI SYLLABLE BBIP;Lo;0;L;;;;;N;;;;; A05A;YI SYLLABLE BBIET;Lo;0;L;;;;;N;;;;; A05B;YI SYLLABLE BBIEX;Lo;0;L;;;;;N;;;;; A05C;YI SYLLABLE BBIE;Lo;0;L;;;;;N;;;;; A05D;YI SYLLABLE BBIEP;Lo;0;L;;;;;N;;;;; A05E;YI SYLLABLE BBAT;Lo;0;L;;;;;N;;;;; A05F;YI SYLLABLE BBAX;Lo;0;L;;;;;N;;;;; A060;YI SYLLABLE BBA;Lo;0;L;;;;;N;;;;; A061;YI SYLLABLE BBAP;Lo;0;L;;;;;N;;;;; A062;YI SYLLABLE BBUOX;Lo;0;L;;;;;N;;;;; A063;YI SYLLABLE BBUO;Lo;0;L;;;;;N;;;;; A064;YI SYLLABLE BBUOP;Lo;0;L;;;;;N;;;;; A065;YI SYLLABLE BBOT;Lo;0;L;;;;;N;;;;; A066;YI SYLLABLE BBOX;Lo;0;L;;;;;N;;;;; A067;YI SYLLABLE BBO;Lo;0;L;;;;;N;;;;; A068;YI SYLLABLE BBOP;Lo;0;L;;;;;N;;;;; A069;YI SYLLABLE BBEX;Lo;0;L;;;;;N;;;;; A06A;YI SYLLABLE BBE;Lo;0;L;;;;;N;;;;; A06B;YI SYLLABLE BBEP;Lo;0;L;;;;;N;;;;; A06C;YI SYLLABLE BBUT;Lo;0;L;;;;;N;;;;; A06D;YI SYLLABLE BBUX;Lo;0;L;;;;;N;;;;; A06E;YI SYLLABLE BBU;Lo;0;L;;;;;N;;;;; A06F;YI SYLLABLE BBUP;Lo;0;L;;;;;N;;;;; A070;YI SYLLABLE BBURX;Lo;0;L;;;;;N;;;;; A071;YI SYLLABLE BBUR;Lo;0;L;;;;;N;;;;; A072;YI SYLLABLE BBYT;Lo;0;L;;;;;N;;;;; A073;YI SYLLABLE BBYX;Lo;0;L;;;;;N;;;;; A074;YI SYLLABLE BBY;Lo;0;L;;;;;N;;;;; A075;YI SYLLABLE BBYP;Lo;0;L;;;;;N;;;;; A076;YI SYLLABLE NBIT;Lo;0;L;;;;;N;;;;; A077;YI SYLLABLE NBIX;Lo;0;L;;;;;N;;;;; A078;YI SYLLABLE NBI;Lo;0;L;;;;;N;;;;; A079;YI SYLLABLE NBIP;Lo;0;L;;;;;N;;;;; A07A;YI SYLLABLE NBIEX;Lo;0;L;;;;;N;;;;; A07B;YI SYLLABLE NBIE;Lo;0;L;;;;;N;;;;; A07C;YI SYLLABLE NBIEP;Lo;0;L;;;;;N;;;;; A07D;YI SYLLABLE NBAT;Lo;0;L;;;;;N;;;;; A07E;YI SYLLABLE NBAX;Lo;0;L;;;;;N;;;;; A07F;YI SYLLABLE NBA;Lo;0;L;;;;;N;;;;; A080;YI SYLLABLE NBAP;Lo;0;L;;;;;N;;;;; A081;YI SYLLABLE NBOT;Lo;0;L;;;;;N;;;;; A082;YI SYLLABLE NBOX;Lo;0;L;;;;;N;;;;; A083;YI SYLLABLE NBO;Lo;0;L;;;;;N;;;;; A084;YI SYLLABLE NBOP;Lo;0;L;;;;;N;;;;; A085;YI SYLLABLE NBUT;Lo;0;L;;;;;N;;;;; A086;YI SYLLABLE NBUX;Lo;0;L;;;;;N;;;;; A087;YI SYLLABLE NBU;Lo;0;L;;;;;N;;;;; A088;YI SYLLABLE NBUP;Lo;0;L;;;;;N;;;;; A089;YI SYLLABLE NBURX;Lo;0;L;;;;;N;;;;; A08A;YI SYLLABLE NBUR;Lo;0;L;;;;;N;;;;; A08B;YI SYLLABLE NBYT;Lo;0;L;;;;;N;;;;; A08C;YI SYLLABLE NBYX;Lo;0;L;;;;;N;;;;; A08D;YI SYLLABLE NBY;Lo;0;L;;;;;N;;;;; A08E;YI SYLLABLE NBYP;Lo;0;L;;;;;N;;;;; A08F;YI SYLLABLE NBYRX;Lo;0;L;;;;;N;;;;; A090;YI SYLLABLE NBYR;Lo;0;L;;;;;N;;;;; A091;YI SYLLABLE HMIT;Lo;0;L;;;;;N;;;;; A092;YI SYLLABLE HMIX;Lo;0;L;;;;;N;;;;; A093;YI SYLLABLE HMI;Lo;0;L;;;;;N;;;;; A094;YI SYLLABLE HMIP;Lo;0;L;;;;;N;;;;; A095;YI SYLLABLE HMIEX;Lo;0;L;;;;;N;;;;; A096;YI SYLLABLE HMIE;Lo;0;L;;;;;N;;;;; A097;YI SYLLABLE HMIEP;Lo;0;L;;;;;N;;;;; A098;YI SYLLABLE HMAT;Lo;0;L;;;;;N;;;;; A099;YI SYLLABLE HMAX;Lo;0;L;;;;;N;;;;; A09A;YI SYLLABLE HMA;Lo;0;L;;;;;N;;;;; A09B;YI SYLLABLE HMAP;Lo;0;L;;;;;N;;;;; A09C;YI SYLLABLE HMUOX;Lo;0;L;;;;;N;;;;; A09D;YI SYLLABLE HMUO;Lo;0;L;;;;;N;;;;; A09E;YI SYLLABLE HMUOP;Lo;0;L;;;;;N;;;;; A09F;YI SYLLABLE HMOT;Lo;0;L;;;;;N;;;;; A0A0;YI SYLLABLE HMOX;Lo;0;L;;;;;N;;;;; A0A1;YI SYLLABLE HMO;Lo;0;L;;;;;N;;;;; A0A2;YI SYLLABLE HMOP;Lo;0;L;;;;;N;;;;; A0A3;YI SYLLABLE HMUT;Lo;0;L;;;;;N;;;;; A0A4;YI SYLLABLE HMUX;Lo;0;L;;;;;N;;;;; A0A5;YI SYLLABLE HMU;Lo;0;L;;;;;N;;;;; A0A6;YI SYLLABLE HMUP;Lo;0;L;;;;;N;;;;; A0A7;YI SYLLABLE HMURX;Lo;0;L;;;;;N;;;;; A0A8;YI SYLLABLE HMUR;Lo;0;L;;;;;N;;;;; A0A9;YI SYLLABLE HMYX;Lo;0;L;;;;;N;;;;; A0AA;YI SYLLABLE HMY;Lo;0;L;;;;;N;;;;; A0AB;YI SYLLABLE HMYP;Lo;0;L;;;;;N;;;;; A0AC;YI SYLLABLE HMYRX;Lo;0;L;;;;;N;;;;; A0AD;YI SYLLABLE HMYR;Lo;0;L;;;;;N;;;;; A0AE;YI SYLLABLE MIT;Lo;0;L;;;;;N;;;;; A0AF;YI SYLLABLE MIX;Lo;0;L;;;;;N;;;;; A0B0;YI SYLLABLE MI;Lo;0;L;;;;;N;;;;; A0B1;YI SYLLABLE MIP;Lo;0;L;;;;;N;;;;; A0B2;YI SYLLABLE MIEX;Lo;0;L;;;;;N;;;;; A0B3;YI SYLLABLE MIE;Lo;0;L;;;;;N;;;;; A0B4;YI SYLLABLE MIEP;Lo;0;L;;;;;N;;;;; A0B5;YI SYLLABLE MAT;Lo;0;L;;;;;N;;;;; A0B6;YI SYLLABLE MAX;Lo;0;L;;;;;N;;;;; A0B7;YI SYLLABLE MA;Lo;0;L;;;;;N;;;;; A0B8;YI SYLLABLE MAP;Lo;0;L;;;;;N;;;;; A0B9;YI SYLLABLE MUOT;Lo;0;L;;;;;N;;;;; A0BA;YI SYLLABLE MUOX;Lo;0;L;;;;;N;;;;; A0BB;YI SYLLABLE MUO;Lo;0;L;;;;;N;;;;; A0BC;YI SYLLABLE MUOP;Lo;0;L;;;;;N;;;;; A0BD;YI SYLLABLE MOT;Lo;0;L;;;;;N;;;;; A0BE;YI SYLLABLE MOX;Lo;0;L;;;;;N;;;;; A0BF;YI SYLLABLE MO;Lo;0;L;;;;;N;;;;; A0C0;YI SYLLABLE MOP;Lo;0;L;;;;;N;;;;; A0C1;YI SYLLABLE MEX;Lo;0;L;;;;;N;;;;; A0C2;YI SYLLABLE ME;Lo;0;L;;;;;N;;;;; A0C3;YI SYLLABLE MUT;Lo;0;L;;;;;N;;;;; A0C4;YI SYLLABLE MUX;Lo;0;L;;;;;N;;;;; A0C5;YI SYLLABLE MU;Lo;0;L;;;;;N;;;;; A0C6;YI SYLLABLE MUP;Lo;0;L;;;;;N;;;;; A0C7;YI SYLLABLE MURX;Lo;0;L;;;;;N;;;;; A0C8;YI SYLLABLE MUR;Lo;0;L;;;;;N;;;;; A0C9;YI SYLLABLE MYT;Lo;0;L;;;;;N;;;;; A0CA;YI SYLLABLE MYX;Lo;0;L;;;;;N;;;;; A0CB;YI SYLLABLE MY;Lo;0;L;;;;;N;;;;; A0CC;YI SYLLABLE MYP;Lo;0;L;;;;;N;;;;; A0CD;YI SYLLABLE FIT;Lo;0;L;;;;;N;;;;; A0CE;YI SYLLABLE FIX;Lo;0;L;;;;;N;;;;; A0CF;YI SYLLABLE FI;Lo;0;L;;;;;N;;;;; A0D0;YI SYLLABLE FIP;Lo;0;L;;;;;N;;;;; A0D1;YI SYLLABLE FAT;Lo;0;L;;;;;N;;;;; A0D2;YI SYLLABLE FAX;Lo;0;L;;;;;N;;;;; A0D3;YI SYLLABLE FA;Lo;0;L;;;;;N;;;;; A0D4;YI SYLLABLE FAP;Lo;0;L;;;;;N;;;;; A0D5;YI SYLLABLE FOX;Lo;0;L;;;;;N;;;;; A0D6;YI SYLLABLE FO;Lo;0;L;;;;;N;;;;; A0D7;YI SYLLABLE FOP;Lo;0;L;;;;;N;;;;; A0D8;YI SYLLABLE FUT;Lo;0;L;;;;;N;;;;; A0D9;YI SYLLABLE FUX;Lo;0;L;;;;;N;;;;; A0DA;YI SYLLABLE FU;Lo;0;L;;;;;N;;;;; A0DB;YI SYLLABLE FUP;Lo;0;L;;;;;N;;;;; A0DC;YI SYLLABLE FURX;Lo;0;L;;;;;N;;;;; A0DD;YI SYLLABLE FUR;Lo;0;L;;;;;N;;;;; A0DE;YI SYLLABLE FYT;Lo;0;L;;;;;N;;;;; A0DF;YI SYLLABLE FYX;Lo;0;L;;;;;N;;;;; A0E0;YI SYLLABLE FY;Lo;0;L;;;;;N;;;;; A0E1;YI SYLLABLE FYP;Lo;0;L;;;;;N;;;;; A0E2;YI SYLLABLE VIT;Lo;0;L;;;;;N;;;;; A0E3;YI SYLLABLE VIX;Lo;0;L;;;;;N;;;;; A0E4;YI SYLLABLE VI;Lo;0;L;;;;;N;;;;; A0E5;YI SYLLABLE VIP;Lo;0;L;;;;;N;;;;; A0E6;YI SYLLABLE VIET;Lo;0;L;;;;;N;;;;; A0E7;YI SYLLABLE VIEX;Lo;0;L;;;;;N;;;;; A0E8;YI SYLLABLE VIE;Lo;0;L;;;;;N;;;;; A0E9;YI SYLLABLE VIEP;Lo;0;L;;;;;N;;;;; A0EA;YI SYLLABLE VAT;Lo;0;L;;;;;N;;;;; A0EB;YI SYLLABLE VAX;Lo;0;L;;;;;N;;;;; A0EC;YI SYLLABLE VA;Lo;0;L;;;;;N;;;;; A0ED;YI SYLLABLE VAP;Lo;0;L;;;;;N;;;;; A0EE;YI SYLLABLE VOT;Lo;0;L;;;;;N;;;;; A0EF;YI SYLLABLE VOX;Lo;0;L;;;;;N;;;;; A0F0;YI SYLLABLE VO;Lo;0;L;;;;;N;;;;; A0F1;YI SYLLABLE VOP;Lo;0;L;;;;;N;;;;; A0F2;YI SYLLABLE VEX;Lo;0;L;;;;;N;;;;; A0F3;YI SYLLABLE VEP;Lo;0;L;;;;;N;;;;; A0F4;YI SYLLABLE VUT;Lo;0;L;;;;;N;;;;; A0F5;YI SYLLABLE VUX;Lo;0;L;;;;;N;;;;; A0F6;YI SYLLABLE VU;Lo;0;L;;;;;N;;;;; A0F7;YI SYLLABLE VUP;Lo;0;L;;;;;N;;;;; A0F8;YI SYLLABLE VURX;Lo;0;L;;;;;N;;;;; A0F9;YI SYLLABLE VUR;Lo;0;L;;;;;N;;;;; A0FA;YI SYLLABLE VYT;Lo;0;L;;;;;N;;;;; A0FB;YI SYLLABLE VYX;Lo;0;L;;;;;N;;;;; A0FC;YI SYLLABLE VY;Lo;0;L;;;;;N;;;;; A0FD;YI SYLLABLE VYP;Lo;0;L;;;;;N;;;;; A0FE;YI SYLLABLE VYRX;Lo;0;L;;;;;N;;;;; A0FF;YI SYLLABLE VYR;Lo;0;L;;;;;N;;;;; A100;YI SYLLABLE DIT;Lo;0;L;;;;;N;;;;; A101;YI SYLLABLE DIX;Lo;0;L;;;;;N;;;;; A102;YI SYLLABLE DI;Lo;0;L;;;;;N;;;;; A103;YI SYLLABLE DIP;Lo;0;L;;;;;N;;;;; A104;YI SYLLABLE DIEX;Lo;0;L;;;;;N;;;;; A105;YI SYLLABLE DIE;Lo;0;L;;;;;N;;;;; A106;YI SYLLABLE DIEP;Lo;0;L;;;;;N;;;;; A107;YI SYLLABLE DAT;Lo;0;L;;;;;N;;;;; A108;YI SYLLABLE DAX;Lo;0;L;;;;;N;;;;; A109;YI SYLLABLE DA;Lo;0;L;;;;;N;;;;; A10A;YI SYLLABLE DAP;Lo;0;L;;;;;N;;;;; A10B;YI SYLLABLE DUOX;Lo;0;L;;;;;N;;;;; A10C;YI SYLLABLE DUO;Lo;0;L;;;;;N;;;;; A10D;YI SYLLABLE DOT;Lo;0;L;;;;;N;;;;; A10E;YI SYLLABLE DOX;Lo;0;L;;;;;N;;;;; A10F;YI SYLLABLE DO;Lo;0;L;;;;;N;;;;; A110;YI SYLLABLE DOP;Lo;0;L;;;;;N;;;;; A111;YI SYLLABLE DEX;Lo;0;L;;;;;N;;;;; A112;YI SYLLABLE DE;Lo;0;L;;;;;N;;;;; A113;YI SYLLABLE DEP;Lo;0;L;;;;;N;;;;; A114;YI SYLLABLE DUT;Lo;0;L;;;;;N;;;;; A115;YI SYLLABLE DUX;Lo;0;L;;;;;N;;;;; A116;YI SYLLABLE DU;Lo;0;L;;;;;N;;;;; A117;YI SYLLABLE DUP;Lo;0;L;;;;;N;;;;; A118;YI SYLLABLE DURX;Lo;0;L;;;;;N;;;;; A119;YI SYLLABLE DUR;Lo;0;L;;;;;N;;;;; A11A;YI SYLLABLE TIT;Lo;0;L;;;;;N;;;;; A11B;YI SYLLABLE TIX;Lo;0;L;;;;;N;;;;; A11C;YI SYLLABLE TI;Lo;0;L;;;;;N;;;;; A11D;YI SYLLABLE TIP;Lo;0;L;;;;;N;;;;; A11E;YI SYLLABLE TIEX;Lo;0;L;;;;;N;;;;; A11F;YI SYLLABLE TIE;Lo;0;L;;;;;N;;;;; A120;YI SYLLABLE TIEP;Lo;0;L;;;;;N;;;;; A121;YI SYLLABLE TAT;Lo;0;L;;;;;N;;;;; A122;YI SYLLABLE TAX;Lo;0;L;;;;;N;;;;; A123;YI SYLLABLE TA;Lo;0;L;;;;;N;;;;; A124;YI SYLLABLE TAP;Lo;0;L;;;;;N;;;;; A125;YI SYLLABLE TUOT;Lo;0;L;;;;;N;;;;; A126;YI SYLLABLE TUOX;Lo;0;L;;;;;N;;;;; A127;YI SYLLABLE TUO;Lo;0;L;;;;;N;;;;; A128;YI SYLLABLE TUOP;Lo;0;L;;;;;N;;;;; A129;YI SYLLABLE TOT;Lo;0;L;;;;;N;;;;; A12A;YI SYLLABLE TOX;Lo;0;L;;;;;N;;;;; A12B;YI SYLLABLE TO;Lo;0;L;;;;;N;;;;; A12C;YI SYLLABLE TOP;Lo;0;L;;;;;N;;;;; A12D;YI SYLLABLE TEX;Lo;0;L;;;;;N;;;;; A12E;YI SYLLABLE TE;Lo;0;L;;;;;N;;;;; A12F;YI SYLLABLE TEP;Lo;0;L;;;;;N;;;;; A130;YI SYLLABLE TUT;Lo;0;L;;;;;N;;;;; A131;YI SYLLABLE TUX;Lo;0;L;;;;;N;;;;; A132;YI SYLLABLE TU;Lo;0;L;;;;;N;;;;; A133;YI SYLLABLE TUP;Lo;0;L;;;;;N;;;;; A134;YI SYLLABLE TURX;Lo;0;L;;;;;N;;;;; A135;YI SYLLABLE TUR;Lo;0;L;;;;;N;;;;; A136;YI SYLLABLE DDIT;Lo;0;L;;;;;N;;;;; A137;YI SYLLABLE DDIX;Lo;0;L;;;;;N;;;;; A138;YI SYLLABLE DDI;Lo;0;L;;;;;N;;;;; A139;YI SYLLABLE DDIP;Lo;0;L;;;;;N;;;;; A13A;YI SYLLABLE DDIEX;Lo;0;L;;;;;N;;;;; A13B;YI SYLLABLE DDIE;Lo;0;L;;;;;N;;;;; A13C;YI SYLLABLE DDIEP;Lo;0;L;;;;;N;;;;; A13D;YI SYLLABLE DDAT;Lo;0;L;;;;;N;;;;; A13E;YI SYLLABLE DDAX;Lo;0;L;;;;;N;;;;; A13F;YI SYLLABLE DDA;Lo;0;L;;;;;N;;;;; A140;YI SYLLABLE DDAP;Lo;0;L;;;;;N;;;;; A141;YI SYLLABLE DDUOX;Lo;0;L;;;;;N;;;;; A142;YI SYLLABLE DDUO;Lo;0;L;;;;;N;;;;; A143;YI SYLLABLE DDUOP;Lo;0;L;;;;;N;;;;; A144;YI SYLLABLE DDOT;Lo;0;L;;;;;N;;;;; A145;YI SYLLABLE DDOX;Lo;0;L;;;;;N;;;;; A146;YI SYLLABLE DDO;Lo;0;L;;;;;N;;;;; A147;YI SYLLABLE DDOP;Lo;0;L;;;;;N;;;;; A148;YI SYLLABLE DDEX;Lo;0;L;;;;;N;;;;; A149;YI SYLLABLE DDE;Lo;0;L;;;;;N;;;;; A14A;YI SYLLABLE DDEP;Lo;0;L;;;;;N;;;;; A14B;YI SYLLABLE DDUT;Lo;0;L;;;;;N;;;;; A14C;YI SYLLABLE DDUX;Lo;0;L;;;;;N;;;;; A14D;YI SYLLABLE DDU;Lo;0;L;;;;;N;;;;; A14E;YI SYLLABLE DDUP;Lo;0;L;;;;;N;;;;; A14F;YI SYLLABLE DDURX;Lo;0;L;;;;;N;;;;; A150;YI SYLLABLE DDUR;Lo;0;L;;;;;N;;;;; A151;YI SYLLABLE NDIT;Lo;0;L;;;;;N;;;;; A152;YI SYLLABLE NDIX;Lo;0;L;;;;;N;;;;; A153;YI SYLLABLE NDI;Lo;0;L;;;;;N;;;;; A154;YI SYLLABLE NDIP;Lo;0;L;;;;;N;;;;; A155;YI SYLLABLE NDIEX;Lo;0;L;;;;;N;;;;; A156;YI SYLLABLE NDIE;Lo;0;L;;;;;N;;;;; A157;YI SYLLABLE NDAT;Lo;0;L;;;;;N;;;;; A158;YI SYLLABLE NDAX;Lo;0;L;;;;;N;;;;; A159;YI SYLLABLE NDA;Lo;0;L;;;;;N;;;;; A15A;YI SYLLABLE NDAP;Lo;0;L;;;;;N;;;;; A15B;YI SYLLABLE NDOT;Lo;0;L;;;;;N;;;;; A15C;YI SYLLABLE NDOX;Lo;0;L;;;;;N;;;;; A15D;YI SYLLABLE NDO;Lo;0;L;;;;;N;;;;; A15E;YI SYLLABLE NDOP;Lo;0;L;;;;;N;;;;; A15F;YI SYLLABLE NDEX;Lo;0;L;;;;;N;;;;; A160;YI SYLLABLE NDE;Lo;0;L;;;;;N;;;;; A161;YI SYLLABLE NDEP;Lo;0;L;;;;;N;;;;; A162;YI SYLLABLE NDUT;Lo;0;L;;;;;N;;;;; A163;YI SYLLABLE NDUX;Lo;0;L;;;;;N;;;;; A164;YI SYLLABLE NDU;Lo;0;L;;;;;N;;;;; A165;YI SYLLABLE NDUP;Lo;0;L;;;;;N;;;;; A166;YI SYLLABLE NDURX;Lo;0;L;;;;;N;;;;; A167;YI SYLLABLE NDUR;Lo;0;L;;;;;N;;;;; A168;YI SYLLABLE HNIT;Lo;0;L;;;;;N;;;;; A169;YI SYLLABLE HNIX;Lo;0;L;;;;;N;;;;; A16A;YI SYLLABLE HNI;Lo;0;L;;;;;N;;;;; A16B;YI SYLLABLE HNIP;Lo;0;L;;;;;N;;;;; A16C;YI SYLLABLE HNIET;Lo;0;L;;;;;N;;;;; A16D;YI SYLLABLE HNIEX;Lo;0;L;;;;;N;;;;; A16E;YI SYLLABLE HNIE;Lo;0;L;;;;;N;;;;; A16F;YI SYLLABLE HNIEP;Lo;0;L;;;;;N;;;;; A170;YI SYLLABLE HNAT;Lo;0;L;;;;;N;;;;; A171;YI SYLLABLE HNAX;Lo;0;L;;;;;N;;;;; A172;YI SYLLABLE HNA;Lo;0;L;;;;;N;;;;; A173;YI SYLLABLE HNAP;Lo;0;L;;;;;N;;;;; A174;YI SYLLABLE HNUOX;Lo;0;L;;;;;N;;;;; A175;YI SYLLABLE HNUO;Lo;0;L;;;;;N;;;;; A176;YI SYLLABLE HNOT;Lo;0;L;;;;;N;;;;; A177;YI SYLLABLE HNOX;Lo;0;L;;;;;N;;;;; A178;YI SYLLABLE HNOP;Lo;0;L;;;;;N;;;;; A179;YI SYLLABLE HNEX;Lo;0;L;;;;;N;;;;; A17A;YI SYLLABLE HNE;Lo;0;L;;;;;N;;;;; A17B;YI SYLLABLE HNEP;Lo;0;L;;;;;N;;;;; A17C;YI SYLLABLE HNUT;Lo;0;L;;;;;N;;;;; A17D;YI SYLLABLE NIT;Lo;0;L;;;;;N;;;;; A17E;YI SYLLABLE NIX;Lo;0;L;;;;;N;;;;; A17F;YI SYLLABLE NI;Lo;0;L;;;;;N;;;;; A180;YI SYLLABLE NIP;Lo;0;L;;;;;N;;;;; A181;YI SYLLABLE NIEX;Lo;0;L;;;;;N;;;;; A182;YI SYLLABLE NIE;Lo;0;L;;;;;N;;;;; A183;YI SYLLABLE NIEP;Lo;0;L;;;;;N;;;;; A184;YI SYLLABLE NAX;Lo;0;L;;;;;N;;;;; A185;YI SYLLABLE NA;Lo;0;L;;;;;N;;;;; A186;YI SYLLABLE NAP;Lo;0;L;;;;;N;;;;; A187;YI SYLLABLE NUOX;Lo;0;L;;;;;N;;;;; A188;YI SYLLABLE NUO;Lo;0;L;;;;;N;;;;; A189;YI SYLLABLE NUOP;Lo;0;L;;;;;N;;;;; A18A;YI SYLLABLE NOT;Lo;0;L;;;;;N;;;;; A18B;YI SYLLABLE NOX;Lo;0;L;;;;;N;;;;; A18C;YI SYLLABLE NO;Lo;0;L;;;;;N;;;;; A18D;YI SYLLABLE NOP;Lo;0;L;;;;;N;;;;; A18E;YI SYLLABLE NEX;Lo;0;L;;;;;N;;;;; A18F;YI SYLLABLE NE;Lo;0;L;;;;;N;;;;; A190;YI SYLLABLE NEP;Lo;0;L;;;;;N;;;;; A191;YI SYLLABLE NUT;Lo;0;L;;;;;N;;;;; A192;YI SYLLABLE NUX;Lo;0;L;;;;;N;;;;; A193;YI SYLLABLE NU;Lo;0;L;;;;;N;;;;; A194;YI SYLLABLE NUP;Lo;0;L;;;;;N;;;;; A195;YI SYLLABLE NURX;Lo;0;L;;;;;N;;;;; A196;YI SYLLABLE NUR;Lo;0;L;;;;;N;;;;; A197;YI SYLLABLE HLIT;Lo;0;L;;;;;N;;;;; A198;YI SYLLABLE HLIX;Lo;0;L;;;;;N;;;;; A199;YI SYLLABLE HLI;Lo;0;L;;;;;N;;;;; A19A;YI SYLLABLE HLIP;Lo;0;L;;;;;N;;;;; A19B;YI SYLLABLE HLIEX;Lo;0;L;;;;;N;;;;; A19C;YI SYLLABLE HLIE;Lo;0;L;;;;;N;;;;; A19D;YI SYLLABLE HLIEP;Lo;0;L;;;;;N;;;;; A19E;YI SYLLABLE HLAT;Lo;0;L;;;;;N;;;;; A19F;YI SYLLABLE HLAX;Lo;0;L;;;;;N;;;;; A1A0;YI SYLLABLE HLA;Lo;0;L;;;;;N;;;;; A1A1;YI SYLLABLE HLAP;Lo;0;L;;;;;N;;;;; A1A2;YI SYLLABLE HLUOX;Lo;0;L;;;;;N;;;;; A1A3;YI SYLLABLE HLUO;Lo;0;L;;;;;N;;;;; A1A4;YI SYLLABLE HLUOP;Lo;0;L;;;;;N;;;;; A1A5;YI SYLLABLE HLOX;Lo;0;L;;;;;N;;;;; A1A6;YI SYLLABLE HLO;Lo;0;L;;;;;N;;;;; A1A7;YI SYLLABLE HLOP;Lo;0;L;;;;;N;;;;; A1A8;YI SYLLABLE HLEX;Lo;0;L;;;;;N;;;;; A1A9;YI SYLLABLE HLE;Lo;0;L;;;;;N;;;;; A1AA;YI SYLLABLE HLEP;Lo;0;L;;;;;N;;;;; A1AB;YI SYLLABLE HLUT;Lo;0;L;;;;;N;;;;; A1AC;YI SYLLABLE HLUX;Lo;0;L;;;;;N;;;;; A1AD;YI SYLLABLE HLU;Lo;0;L;;;;;N;;;;; A1AE;YI SYLLABLE HLUP;Lo;0;L;;;;;N;;;;; A1AF;YI SYLLABLE HLURX;Lo;0;L;;;;;N;;;;; A1B0;YI SYLLABLE HLUR;Lo;0;L;;;;;N;;;;; A1B1;YI SYLLABLE HLYT;Lo;0;L;;;;;N;;;;; A1B2;YI SYLLABLE HLYX;Lo;0;L;;;;;N;;;;; A1B3;YI SYLLABLE HLY;Lo;0;L;;;;;N;;;;; A1B4;YI SYLLABLE HLYP;Lo;0;L;;;;;N;;;;; A1B5;YI SYLLABLE HLYRX;Lo;0;L;;;;;N;;;;; A1B6;YI SYLLABLE HLYR;Lo;0;L;;;;;N;;;;; A1B7;YI SYLLABLE LIT;Lo;0;L;;;;;N;;;;; A1B8;YI SYLLABLE LIX;Lo;0;L;;;;;N;;;;; A1B9;YI SYLLABLE LI;Lo;0;L;;;;;N;;;;; A1BA;YI SYLLABLE LIP;Lo;0;L;;;;;N;;;;; A1BB;YI SYLLABLE LIET;Lo;0;L;;;;;N;;;;; A1BC;YI SYLLABLE LIEX;Lo;0;L;;;;;N;;;;; A1BD;YI SYLLABLE LIE;Lo;0;L;;;;;N;;;;; A1BE;YI SYLLABLE LIEP;Lo;0;L;;;;;N;;;;; A1BF;YI SYLLABLE LAT;Lo;0;L;;;;;N;;;;; A1C0;YI SYLLABLE LAX;Lo;0;L;;;;;N;;;;; A1C1;YI SYLLABLE LA;Lo;0;L;;;;;N;;;;; A1C2;YI SYLLABLE LAP;Lo;0;L;;;;;N;;;;; A1C3;YI SYLLABLE LUOT;Lo;0;L;;;;;N;;;;; A1C4;YI SYLLABLE LUOX;Lo;0;L;;;;;N;;;;; A1C5;YI SYLLABLE LUO;Lo;0;L;;;;;N;;;;; A1C6;YI SYLLABLE LUOP;Lo;0;L;;;;;N;;;;; A1C7;YI SYLLABLE LOT;Lo;0;L;;;;;N;;;;; A1C8;YI SYLLABLE LOX;Lo;0;L;;;;;N;;;;; A1C9;YI SYLLABLE LO;Lo;0;L;;;;;N;;;;; A1CA;YI SYLLABLE LOP;Lo;0;L;;;;;N;;;;; A1CB;YI SYLLABLE LEX;Lo;0;L;;;;;N;;;;; A1CC;YI SYLLABLE LE;Lo;0;L;;;;;N;;;;; A1CD;YI SYLLABLE LEP;Lo;0;L;;;;;N;;;;; A1CE;YI SYLLABLE LUT;Lo;0;L;;;;;N;;;;; A1CF;YI SYLLABLE LUX;Lo;0;L;;;;;N;;;;; A1D0;YI SYLLABLE LU;Lo;0;L;;;;;N;;;;; A1D1;YI SYLLABLE LUP;Lo;0;L;;;;;N;;;;; A1D2;YI SYLLABLE LURX;Lo;0;L;;;;;N;;;;; A1D3;YI SYLLABLE LUR;Lo;0;L;;;;;N;;;;; A1D4;YI SYLLABLE LYT;Lo;0;L;;;;;N;;;;; A1D5;YI SYLLABLE LYX;Lo;0;L;;;;;N;;;;; A1D6;YI SYLLABLE LY;Lo;0;L;;;;;N;;;;; A1D7;YI SYLLABLE LYP;Lo;0;L;;;;;N;;;;; A1D8;YI SYLLABLE LYRX;Lo;0;L;;;;;N;;;;; A1D9;YI SYLLABLE LYR;Lo;0;L;;;;;N;;;;; A1DA;YI SYLLABLE GIT;Lo;0;L;;;;;N;;;;; A1DB;YI SYLLABLE GIX;Lo;0;L;;;;;N;;;;; A1DC;YI SYLLABLE GI;Lo;0;L;;;;;N;;;;; A1DD;YI SYLLABLE GIP;Lo;0;L;;;;;N;;;;; A1DE;YI SYLLABLE GIET;Lo;0;L;;;;;N;;;;; A1DF;YI SYLLABLE GIEX;Lo;0;L;;;;;N;;;;; A1E0;YI SYLLABLE GIE;Lo;0;L;;;;;N;;;;; A1E1;YI SYLLABLE GIEP;Lo;0;L;;;;;N;;;;; A1E2;YI SYLLABLE GAT;Lo;0;L;;;;;N;;;;; A1E3;YI SYLLABLE GAX;Lo;0;L;;;;;N;;;;; A1E4;YI SYLLABLE GA;Lo;0;L;;;;;N;;;;; A1E5;YI SYLLABLE GAP;Lo;0;L;;;;;N;;;;; A1E6;YI SYLLABLE GUOT;Lo;0;L;;;;;N;;;;; A1E7;YI SYLLABLE GUOX;Lo;0;L;;;;;N;;;;; A1E8;YI SYLLABLE GUO;Lo;0;L;;;;;N;;;;; A1E9;YI SYLLABLE GUOP;Lo;0;L;;;;;N;;;;; A1EA;YI SYLLABLE GOT;Lo;0;L;;;;;N;;;;; A1EB;YI SYLLABLE GOX;Lo;0;L;;;;;N;;;;; A1EC;YI SYLLABLE GO;Lo;0;L;;;;;N;;;;; A1ED;YI SYLLABLE GOP;Lo;0;L;;;;;N;;;;; A1EE;YI SYLLABLE GET;Lo;0;L;;;;;N;;;;; A1EF;YI SYLLABLE GEX;Lo;0;L;;;;;N;;;;; A1F0;YI SYLLABLE GE;Lo;0;L;;;;;N;;;;; A1F1;YI SYLLABLE GEP;Lo;0;L;;;;;N;;;;; A1F2;YI SYLLABLE GUT;Lo;0;L;;;;;N;;;;; A1F3;YI SYLLABLE GUX;Lo;0;L;;;;;N;;;;; A1F4;YI SYLLABLE GU;Lo;0;L;;;;;N;;;;; A1F5;YI SYLLABLE GUP;Lo;0;L;;;;;N;;;;; A1F6;YI SYLLABLE GURX;Lo;0;L;;;;;N;;;;; A1F7;YI SYLLABLE GUR;Lo;0;L;;;;;N;;;;; A1F8;YI SYLLABLE KIT;Lo;0;L;;;;;N;;;;; A1F9;YI SYLLABLE KIX;Lo;0;L;;;;;N;;;;; A1FA;YI SYLLABLE KI;Lo;0;L;;;;;N;;;;; A1FB;YI SYLLABLE KIP;Lo;0;L;;;;;N;;;;; A1FC;YI SYLLABLE KIEX;Lo;0;L;;;;;N;;;;; A1FD;YI SYLLABLE KIE;Lo;0;L;;;;;N;;;;; A1FE;YI SYLLABLE KIEP;Lo;0;L;;;;;N;;;;; A1FF;YI SYLLABLE KAT;Lo;0;L;;;;;N;;;;; A200;YI SYLLABLE KAX;Lo;0;L;;;;;N;;;;; A201;YI SYLLABLE KA;Lo;0;L;;;;;N;;;;; A202;YI SYLLABLE KAP;Lo;0;L;;;;;N;;;;; A203;YI SYLLABLE KUOX;Lo;0;L;;;;;N;;;;; A204;YI SYLLABLE KUO;Lo;0;L;;;;;N;;;;; A205;YI SYLLABLE KUOP;Lo;0;L;;;;;N;;;;; A206;YI SYLLABLE KOT;Lo;0;L;;;;;N;;;;; A207;YI SYLLABLE KOX;Lo;0;L;;;;;N;;;;; A208;YI SYLLABLE KO;Lo;0;L;;;;;N;;;;; A209;YI SYLLABLE KOP;Lo;0;L;;;;;N;;;;; A20A;YI SYLLABLE KET;Lo;0;L;;;;;N;;;;; A20B;YI SYLLABLE KEX;Lo;0;L;;;;;N;;;;; A20C;YI SYLLABLE KE;Lo;0;L;;;;;N;;;;; A20D;YI SYLLABLE KEP;Lo;0;L;;;;;N;;;;; A20E;YI SYLLABLE KUT;Lo;0;L;;;;;N;;;;; A20F;YI SYLLABLE KUX;Lo;0;L;;;;;N;;;;; A210;YI SYLLABLE KU;Lo;0;L;;;;;N;;;;; A211;YI SYLLABLE KUP;Lo;0;L;;;;;N;;;;; A212;YI SYLLABLE KURX;Lo;0;L;;;;;N;;;;; A213;YI SYLLABLE KUR;Lo;0;L;;;;;N;;;;; A214;YI SYLLABLE GGIT;Lo;0;L;;;;;N;;;;; A215;YI SYLLABLE GGIX;Lo;0;L;;;;;N;;;;; A216;YI SYLLABLE GGI;Lo;0;L;;;;;N;;;;; A217;YI SYLLABLE GGIEX;Lo;0;L;;;;;N;;;;; A218;YI SYLLABLE GGIE;Lo;0;L;;;;;N;;;;; A219;YI SYLLABLE GGIEP;Lo;0;L;;;;;N;;;;; A21A;YI SYLLABLE GGAT;Lo;0;L;;;;;N;;;;; A21B;YI SYLLABLE GGAX;Lo;0;L;;;;;N;;;;; A21C;YI SYLLABLE GGA;Lo;0;L;;;;;N;;;;; A21D;YI SYLLABLE GGAP;Lo;0;L;;;;;N;;;;; A21E;YI SYLLABLE GGUOT;Lo;0;L;;;;;N;;;;; A21F;YI SYLLABLE GGUOX;Lo;0;L;;;;;N;;;;; A220;YI SYLLABLE GGUO;Lo;0;L;;;;;N;;;;; A221;YI SYLLABLE GGUOP;Lo;0;L;;;;;N;;;;; A222;YI SYLLABLE GGOT;Lo;0;L;;;;;N;;;;; A223;YI SYLLABLE GGOX;Lo;0;L;;;;;N;;;;; A224;YI SYLLABLE GGO;Lo;0;L;;;;;N;;;;; A225;YI SYLLABLE GGOP;Lo;0;L;;;;;N;;;;; A226;YI SYLLABLE GGET;Lo;0;L;;;;;N;;;;; A227;YI SYLLABLE GGEX;Lo;0;L;;;;;N;;;;; A228;YI SYLLABLE GGE;Lo;0;L;;;;;N;;;;; A229;YI SYLLABLE GGEP;Lo;0;L;;;;;N;;;;; A22A;YI SYLLABLE GGUT;Lo;0;L;;;;;N;;;;; A22B;YI SYLLABLE GGUX;Lo;0;L;;;;;N;;;;; A22C;YI SYLLABLE GGU;Lo;0;L;;;;;N;;;;; A22D;YI SYLLABLE GGUP;Lo;0;L;;;;;N;;;;; A22E;YI SYLLABLE GGURX;Lo;0;L;;;;;N;;;;; A22F;YI SYLLABLE GGUR;Lo;0;L;;;;;N;;;;; A230;YI SYLLABLE MGIEX;Lo;0;L;;;;;N;;;;; A231;YI SYLLABLE MGIE;Lo;0;L;;;;;N;;;;; A232;YI SYLLABLE MGAT;Lo;0;L;;;;;N;;;;; A233;YI SYLLABLE MGAX;Lo;0;L;;;;;N;;;;; A234;YI SYLLABLE MGA;Lo;0;L;;;;;N;;;;; A235;YI SYLLABLE MGAP;Lo;0;L;;;;;N;;;;; A236;YI SYLLABLE MGUOX;Lo;0;L;;;;;N;;;;; A237;YI SYLLABLE MGUO;Lo;0;L;;;;;N;;;;; A238;YI SYLLABLE MGUOP;Lo;0;L;;;;;N;;;;; A239;YI SYLLABLE MGOT;Lo;0;L;;;;;N;;;;; A23A;YI SYLLABLE MGOX;Lo;0;L;;;;;N;;;;; A23B;YI SYLLABLE MGO;Lo;0;L;;;;;N;;;;; A23C;YI SYLLABLE MGOP;Lo;0;L;;;;;N;;;;; A23D;YI SYLLABLE MGEX;Lo;0;L;;;;;N;;;;; A23E;YI SYLLABLE MGE;Lo;0;L;;;;;N;;;;; A23F;YI SYLLABLE MGEP;Lo;0;L;;;;;N;;;;; A240;YI SYLLABLE MGUT;Lo;0;L;;;;;N;;;;; A241;YI SYLLABLE MGUX;Lo;0;L;;;;;N;;;;; A242;YI SYLLABLE MGU;Lo;0;L;;;;;N;;;;; A243;YI SYLLABLE MGUP;Lo;0;L;;;;;N;;;;; A244;YI SYLLABLE MGURX;Lo;0;L;;;;;N;;;;; A245;YI SYLLABLE MGUR;Lo;0;L;;;;;N;;;;; A246;YI SYLLABLE HXIT;Lo;0;L;;;;;N;;;;; A247;YI SYLLABLE HXIX;Lo;0;L;;;;;N;;;;; A248;YI SYLLABLE HXI;Lo;0;L;;;;;N;;;;; A249;YI SYLLABLE HXIP;Lo;0;L;;;;;N;;;;; A24A;YI SYLLABLE HXIET;Lo;0;L;;;;;N;;;;; A24B;YI SYLLABLE HXIEX;Lo;0;L;;;;;N;;;;; A24C;YI SYLLABLE HXIE;Lo;0;L;;;;;N;;;;; A24D;YI SYLLABLE HXIEP;Lo;0;L;;;;;N;;;;; A24E;YI SYLLABLE HXAT;Lo;0;L;;;;;N;;;;; A24F;YI SYLLABLE HXAX;Lo;0;L;;;;;N;;;;; A250;YI SYLLABLE HXA;Lo;0;L;;;;;N;;;;; A251;YI SYLLABLE HXAP;Lo;0;L;;;;;N;;;;; A252;YI SYLLABLE HXUOT;Lo;0;L;;;;;N;;;;; A253;YI SYLLABLE HXUOX;Lo;0;L;;;;;N;;;;; A254;YI SYLLABLE HXUO;Lo;0;L;;;;;N;;;;; A255;YI SYLLABLE HXUOP;Lo;0;L;;;;;N;;;;; A256;YI SYLLABLE HXOT;Lo;0;L;;;;;N;;;;; A257;YI SYLLABLE HXOX;Lo;0;L;;;;;N;;;;; A258;YI SYLLABLE HXO;Lo;0;L;;;;;N;;;;; A259;YI SYLLABLE HXOP;Lo;0;L;;;;;N;;;;; A25A;YI SYLLABLE HXEX;Lo;0;L;;;;;N;;;;; A25B;YI SYLLABLE HXE;Lo;0;L;;;;;N;;;;; A25C;YI SYLLABLE HXEP;Lo;0;L;;;;;N;;;;; A25D;YI SYLLABLE NGIEX;Lo;0;L;;;;;N;;;;; A25E;YI SYLLABLE NGIE;Lo;0;L;;;;;N;;;;; A25F;YI SYLLABLE NGIEP;Lo;0;L;;;;;N;;;;; A260;YI SYLLABLE NGAT;Lo;0;L;;;;;N;;;;; A261;YI SYLLABLE NGAX;Lo;0;L;;;;;N;;;;; A262;YI SYLLABLE NGA;Lo;0;L;;;;;N;;;;; A263;YI SYLLABLE NGAP;Lo;0;L;;;;;N;;;;; A264;YI SYLLABLE NGUOT;Lo;0;L;;;;;N;;;;; A265;YI SYLLABLE NGUOX;Lo;0;L;;;;;N;;;;; A266;YI SYLLABLE NGUO;Lo;0;L;;;;;N;;;;; A267;YI SYLLABLE NGOT;Lo;0;L;;;;;N;;;;; A268;YI SYLLABLE NGOX;Lo;0;L;;;;;N;;;;; A269;YI SYLLABLE NGO;Lo;0;L;;;;;N;;;;; A26A;YI SYLLABLE NGOP;Lo;0;L;;;;;N;;;;; A26B;YI SYLLABLE NGEX;Lo;0;L;;;;;N;;;;; A26C;YI SYLLABLE NGE;Lo;0;L;;;;;N;;;;; A26D;YI SYLLABLE NGEP;Lo;0;L;;;;;N;;;;; A26E;YI SYLLABLE HIT;Lo;0;L;;;;;N;;;;; A26F;YI SYLLABLE HIEX;Lo;0;L;;;;;N;;;;; A270;YI SYLLABLE HIE;Lo;0;L;;;;;N;;;;; A271;YI SYLLABLE HAT;Lo;0;L;;;;;N;;;;; A272;YI SYLLABLE HAX;Lo;0;L;;;;;N;;;;; A273;YI SYLLABLE HA;Lo;0;L;;;;;N;;;;; A274;YI SYLLABLE HAP;Lo;0;L;;;;;N;;;;; A275;YI SYLLABLE HUOT;Lo;0;L;;;;;N;;;;; A276;YI SYLLABLE HUOX;Lo;0;L;;;;;N;;;;; A277;YI SYLLABLE HUO;Lo;0;L;;;;;N;;;;; A278;YI SYLLABLE HUOP;Lo;0;L;;;;;N;;;;; A279;YI SYLLABLE HOT;Lo;0;L;;;;;N;;;;; A27A;YI SYLLABLE HOX;Lo;0;L;;;;;N;;;;; A27B;YI SYLLABLE HO;Lo;0;L;;;;;N;;;;; A27C;YI SYLLABLE HOP;Lo;0;L;;;;;N;;;;; A27D;YI SYLLABLE HEX;Lo;0;L;;;;;N;;;;; A27E;YI SYLLABLE HE;Lo;0;L;;;;;N;;;;; A27F;YI SYLLABLE HEP;Lo;0;L;;;;;N;;;;; A280;YI SYLLABLE WAT;Lo;0;L;;;;;N;;;;; A281;YI SYLLABLE WAX;Lo;0;L;;;;;N;;;;; A282;YI SYLLABLE WA;Lo;0;L;;;;;N;;;;; A283;YI SYLLABLE WAP;Lo;0;L;;;;;N;;;;; A284;YI SYLLABLE WUOX;Lo;0;L;;;;;N;;;;; A285;YI SYLLABLE WUO;Lo;0;L;;;;;N;;;;; A286;YI SYLLABLE WUOP;Lo;0;L;;;;;N;;;;; A287;YI SYLLABLE WOX;Lo;0;L;;;;;N;;;;; A288;YI SYLLABLE WO;Lo;0;L;;;;;N;;;;; A289;YI SYLLABLE WOP;Lo;0;L;;;;;N;;;;; A28A;YI SYLLABLE WEX;Lo;0;L;;;;;N;;;;; A28B;YI SYLLABLE WE;Lo;0;L;;;;;N;;;;; A28C;YI SYLLABLE WEP;Lo;0;L;;;;;N;;;;; A28D;YI SYLLABLE ZIT;Lo;0;L;;;;;N;;;;; A28E;YI SYLLABLE ZIX;Lo;0;L;;;;;N;;;;; A28F;YI SYLLABLE ZI;Lo;0;L;;;;;N;;;;; A290;YI SYLLABLE ZIP;Lo;0;L;;;;;N;;;;; A291;YI SYLLABLE ZIEX;Lo;0;L;;;;;N;;;;; A292;YI SYLLABLE ZIE;Lo;0;L;;;;;N;;;;; A293;YI SYLLABLE ZIEP;Lo;0;L;;;;;N;;;;; A294;YI SYLLABLE ZAT;Lo;0;L;;;;;N;;;;; A295;YI SYLLABLE ZAX;Lo;0;L;;;;;N;;;;; A296;YI SYLLABLE ZA;Lo;0;L;;;;;N;;;;; A297;YI SYLLABLE ZAP;Lo;0;L;;;;;N;;;;; A298;YI SYLLABLE ZUOX;Lo;0;L;;;;;N;;;;; A299;YI SYLLABLE ZUO;Lo;0;L;;;;;N;;;;; A29A;YI SYLLABLE ZUOP;Lo;0;L;;;;;N;;;;; A29B;YI SYLLABLE ZOT;Lo;0;L;;;;;N;;;;; A29C;YI SYLLABLE ZOX;Lo;0;L;;;;;N;;;;; A29D;YI SYLLABLE ZO;Lo;0;L;;;;;N;;;;; A29E;YI SYLLABLE ZOP;Lo;0;L;;;;;N;;;;; A29F;YI SYLLABLE ZEX;Lo;0;L;;;;;N;;;;; A2A0;YI SYLLABLE ZE;Lo;0;L;;;;;N;;;;; A2A1;YI SYLLABLE ZEP;Lo;0;L;;;;;N;;;;; A2A2;YI SYLLABLE ZUT;Lo;0;L;;;;;N;;;;; A2A3;YI SYLLABLE ZUX;Lo;0;L;;;;;N;;;;; A2A4;YI SYLLABLE ZU;Lo;0;L;;;;;N;;;;; A2A5;YI SYLLABLE ZUP;Lo;0;L;;;;;N;;;;; A2A6;YI SYLLABLE ZURX;Lo;0;L;;;;;N;;;;; A2A7;YI SYLLABLE ZUR;Lo;0;L;;;;;N;;;;; A2A8;YI SYLLABLE ZYT;Lo;0;L;;;;;N;;;;; A2A9;YI SYLLABLE ZYX;Lo;0;L;;;;;N;;;;; A2AA;YI SYLLABLE ZY;Lo;0;L;;;;;N;;;;; A2AB;YI SYLLABLE ZYP;Lo;0;L;;;;;N;;;;; A2AC;YI SYLLABLE ZYRX;Lo;0;L;;;;;N;;;;; A2AD;YI SYLLABLE ZYR;Lo;0;L;;;;;N;;;;; A2AE;YI SYLLABLE CIT;Lo;0;L;;;;;N;;;;; A2AF;YI SYLLABLE CIX;Lo;0;L;;;;;N;;;;; A2B0;YI SYLLABLE CI;Lo;0;L;;;;;N;;;;; A2B1;YI SYLLABLE CIP;Lo;0;L;;;;;N;;;;; A2B2;YI SYLLABLE CIET;Lo;0;L;;;;;N;;;;; A2B3;YI SYLLABLE CIEX;Lo;0;L;;;;;N;;;;; A2B4;YI SYLLABLE CIE;Lo;0;L;;;;;N;;;;; A2B5;YI SYLLABLE CIEP;Lo;0;L;;;;;N;;;;; A2B6;YI SYLLABLE CAT;Lo;0;L;;;;;N;;;;; A2B7;YI SYLLABLE CAX;Lo;0;L;;;;;N;;;;; A2B8;YI SYLLABLE CA;Lo;0;L;;;;;N;;;;; A2B9;YI SYLLABLE CAP;Lo;0;L;;;;;N;;;;; A2BA;YI SYLLABLE CUOX;Lo;0;L;;;;;N;;;;; A2BB;YI SYLLABLE CUO;Lo;0;L;;;;;N;;;;; A2BC;YI SYLLABLE CUOP;Lo;0;L;;;;;N;;;;; A2BD;YI SYLLABLE COT;Lo;0;L;;;;;N;;;;; A2BE;YI SYLLABLE COX;Lo;0;L;;;;;N;;;;; A2BF;YI SYLLABLE CO;Lo;0;L;;;;;N;;;;; A2C0;YI SYLLABLE COP;Lo;0;L;;;;;N;;;;; A2C1;YI SYLLABLE CEX;Lo;0;L;;;;;N;;;;; A2C2;YI SYLLABLE CE;Lo;0;L;;;;;N;;;;; A2C3;YI SYLLABLE CEP;Lo;0;L;;;;;N;;;;; A2C4;YI SYLLABLE CUT;Lo;0;L;;;;;N;;;;; A2C5;YI SYLLABLE CUX;Lo;0;L;;;;;N;;;;; A2C6;YI SYLLABLE CU;Lo;0;L;;;;;N;;;;; A2C7;YI SYLLABLE CUP;Lo;0;L;;;;;N;;;;; A2C8;YI SYLLABLE CURX;Lo;0;L;;;;;N;;;;; A2C9;YI SYLLABLE CUR;Lo;0;L;;;;;N;;;;; A2CA;YI SYLLABLE CYT;Lo;0;L;;;;;N;;;;; A2CB;YI SYLLABLE CYX;Lo;0;L;;;;;N;;;;; A2CC;YI SYLLABLE CY;Lo;0;L;;;;;N;;;;; A2CD;YI SYLLABLE CYP;Lo;0;L;;;;;N;;;;; A2CE;YI SYLLABLE CYRX;Lo;0;L;;;;;N;;;;; A2CF;YI SYLLABLE CYR;Lo;0;L;;;;;N;;;;; A2D0;YI SYLLABLE ZZIT;Lo;0;L;;;;;N;;;;; A2D1;YI SYLLABLE ZZIX;Lo;0;L;;;;;N;;;;; A2D2;YI SYLLABLE ZZI;Lo;0;L;;;;;N;;;;; A2D3;YI SYLLABLE ZZIP;Lo;0;L;;;;;N;;;;; A2D4;YI SYLLABLE ZZIET;Lo;0;L;;;;;N;;;;; A2D5;YI SYLLABLE ZZIEX;Lo;0;L;;;;;N;;;;; A2D6;YI SYLLABLE ZZIE;Lo;0;L;;;;;N;;;;; A2D7;YI SYLLABLE ZZIEP;Lo;0;L;;;;;N;;;;; A2D8;YI SYLLABLE ZZAT;Lo;0;L;;;;;N;;;;; A2D9;YI SYLLABLE ZZAX;Lo;0;L;;;;;N;;;;; A2DA;YI SYLLABLE ZZA;Lo;0;L;;;;;N;;;;; A2DB;YI SYLLABLE ZZAP;Lo;0;L;;;;;N;;;;; A2DC;YI SYLLABLE ZZOX;Lo;0;L;;;;;N;;;;; A2DD;YI SYLLABLE ZZO;Lo;0;L;;;;;N;;;;; A2DE;YI SYLLABLE ZZOP;Lo;0;L;;;;;N;;;;; A2DF;YI SYLLABLE ZZEX;Lo;0;L;;;;;N;;;;; A2E0;YI SYLLABLE ZZE;Lo;0;L;;;;;N;;;;; A2E1;YI SYLLABLE ZZEP;Lo;0;L;;;;;N;;;;; A2E2;YI SYLLABLE ZZUX;Lo;0;L;;;;;N;;;;; A2E3;YI SYLLABLE ZZU;Lo;0;L;;;;;N;;;;; A2E4;YI SYLLABLE ZZUP;Lo;0;L;;;;;N;;;;; A2E5;YI SYLLABLE ZZURX;Lo;0;L;;;;;N;;;;; A2E6;YI SYLLABLE ZZUR;Lo;0;L;;;;;N;;;;; A2E7;YI SYLLABLE ZZYT;Lo;0;L;;;;;N;;;;; A2E8;YI SYLLABLE ZZYX;Lo;0;L;;;;;N;;;;; A2E9;YI SYLLABLE ZZY;Lo;0;L;;;;;N;;;;; A2EA;YI SYLLABLE ZZYP;Lo;0;L;;;;;N;;;;; A2EB;YI SYLLABLE ZZYRX;Lo;0;L;;;;;N;;;;; A2EC;YI SYLLABLE ZZYR;Lo;0;L;;;;;N;;;;; A2ED;YI SYLLABLE NZIT;Lo;0;L;;;;;N;;;;; A2EE;YI SYLLABLE NZIX;Lo;0;L;;;;;N;;;;; A2EF;YI SYLLABLE NZI;Lo;0;L;;;;;N;;;;; A2F0;YI SYLLABLE NZIP;Lo;0;L;;;;;N;;;;; A2F1;YI SYLLABLE NZIEX;Lo;0;L;;;;;N;;;;; A2F2;YI SYLLABLE NZIE;Lo;0;L;;;;;N;;;;; A2F3;YI SYLLABLE NZIEP;Lo;0;L;;;;;N;;;;; A2F4;YI SYLLABLE NZAT;Lo;0;L;;;;;N;;;;; A2F5;YI SYLLABLE NZAX;Lo;0;L;;;;;N;;;;; A2F6;YI SYLLABLE NZA;Lo;0;L;;;;;N;;;;; A2F7;YI SYLLABLE NZAP;Lo;0;L;;;;;N;;;;; A2F8;YI SYLLABLE NZUOX;Lo;0;L;;;;;N;;;;; A2F9;YI SYLLABLE NZUO;Lo;0;L;;;;;N;;;;; A2FA;YI SYLLABLE NZOX;Lo;0;L;;;;;N;;;;; A2FB;YI SYLLABLE NZOP;Lo;0;L;;;;;N;;;;; A2FC;YI SYLLABLE NZEX;Lo;0;L;;;;;N;;;;; A2FD;YI SYLLABLE NZE;Lo;0;L;;;;;N;;;;; A2FE;YI SYLLABLE NZUX;Lo;0;L;;;;;N;;;;; A2FF;YI SYLLABLE NZU;Lo;0;L;;;;;N;;;;; A300;YI SYLLABLE NZUP;Lo;0;L;;;;;N;;;;; A301;YI SYLLABLE NZURX;Lo;0;L;;;;;N;;;;; A302;YI SYLLABLE NZUR;Lo;0;L;;;;;N;;;;; A303;YI SYLLABLE NZYT;Lo;0;L;;;;;N;;;;; A304;YI SYLLABLE NZYX;Lo;0;L;;;;;N;;;;; A305;YI SYLLABLE NZY;Lo;0;L;;;;;N;;;;; A306;YI SYLLABLE NZYP;Lo;0;L;;;;;N;;;;; A307;YI SYLLABLE NZYRX;Lo;0;L;;;;;N;;;;; A308;YI SYLLABLE NZYR;Lo;0;L;;;;;N;;;;; A309;YI SYLLABLE SIT;Lo;0;L;;;;;N;;;;; A30A;YI SYLLABLE SIX;Lo;0;L;;;;;N;;;;; A30B;YI SYLLABLE SI;Lo;0;L;;;;;N;;;;; A30C;YI SYLLABLE SIP;Lo;0;L;;;;;N;;;;; A30D;YI SYLLABLE SIEX;Lo;0;L;;;;;N;;;;; A30E;YI SYLLABLE SIE;Lo;0;L;;;;;N;;;;; A30F;YI SYLLABLE SIEP;Lo;0;L;;;;;N;;;;; A310;YI SYLLABLE SAT;Lo;0;L;;;;;N;;;;; A311;YI SYLLABLE SAX;Lo;0;L;;;;;N;;;;; A312;YI SYLLABLE SA;Lo;0;L;;;;;N;;;;; A313;YI SYLLABLE SAP;Lo;0;L;;;;;N;;;;; A314;YI SYLLABLE SUOX;Lo;0;L;;;;;N;;;;; A315;YI SYLLABLE SUO;Lo;0;L;;;;;N;;;;; A316;YI SYLLABLE SUOP;Lo;0;L;;;;;N;;;;; A317;YI SYLLABLE SOT;Lo;0;L;;;;;N;;;;; A318;YI SYLLABLE SOX;Lo;0;L;;;;;N;;;;; A319;YI SYLLABLE SO;Lo;0;L;;;;;N;;;;; A31A;YI SYLLABLE SOP;Lo;0;L;;;;;N;;;;; A31B;YI SYLLABLE SEX;Lo;0;L;;;;;N;;;;; A31C;YI SYLLABLE SE;Lo;0;L;;;;;N;;;;; A31D;YI SYLLABLE SEP;Lo;0;L;;;;;N;;;;; A31E;YI SYLLABLE SUT;Lo;0;L;;;;;N;;;;; A31F;YI SYLLABLE SUX;Lo;0;L;;;;;N;;;;; A320;YI SYLLABLE SU;Lo;0;L;;;;;N;;;;; A321;YI SYLLABLE SUP;Lo;0;L;;;;;N;;;;; A322;YI SYLLABLE SURX;Lo;0;L;;;;;N;;;;; A323;YI SYLLABLE SUR;Lo;0;L;;;;;N;;;;; A324;YI SYLLABLE SYT;Lo;0;L;;;;;N;;;;; A325;YI SYLLABLE SYX;Lo;0;L;;;;;N;;;;; A326;YI SYLLABLE SY;Lo;0;L;;;;;N;;;;; A327;YI SYLLABLE SYP;Lo;0;L;;;;;N;;;;; A328;YI SYLLABLE SYRX;Lo;0;L;;;;;N;;;;; A329;YI SYLLABLE SYR;Lo;0;L;;;;;N;;;;; A32A;YI SYLLABLE SSIT;Lo;0;L;;;;;N;;;;; A32B;YI SYLLABLE SSIX;Lo;0;L;;;;;N;;;;; A32C;YI SYLLABLE SSI;Lo;0;L;;;;;N;;;;; A32D;YI SYLLABLE SSIP;Lo;0;L;;;;;N;;;;; A32E;YI SYLLABLE SSIEX;Lo;0;L;;;;;N;;;;; A32F;YI SYLLABLE SSIE;Lo;0;L;;;;;N;;;;; A330;YI SYLLABLE SSIEP;Lo;0;L;;;;;N;;;;; A331;YI SYLLABLE SSAT;Lo;0;L;;;;;N;;;;; A332;YI SYLLABLE SSAX;Lo;0;L;;;;;N;;;;; A333;YI SYLLABLE SSA;Lo;0;L;;;;;N;;;;; A334;YI SYLLABLE SSAP;Lo;0;L;;;;;N;;;;; A335;YI SYLLABLE SSOT;Lo;0;L;;;;;N;;;;; A336;YI SYLLABLE SSOX;Lo;0;L;;;;;N;;;;; A337;YI SYLLABLE SSO;Lo;0;L;;;;;N;;;;; A338;YI SYLLABLE SSOP;Lo;0;L;;;;;N;;;;; A339;YI SYLLABLE SSEX;Lo;0;L;;;;;N;;;;; A33A;YI SYLLABLE SSE;Lo;0;L;;;;;N;;;;; A33B;YI SYLLABLE SSEP;Lo;0;L;;;;;N;;;;; A33C;YI SYLLABLE SSUT;Lo;0;L;;;;;N;;;;; A33D;YI SYLLABLE SSUX;Lo;0;L;;;;;N;;;;; A33E;YI SYLLABLE SSU;Lo;0;L;;;;;N;;;;; A33F;YI SYLLABLE SSUP;Lo;0;L;;;;;N;;;;; A340;YI SYLLABLE SSYT;Lo;0;L;;;;;N;;;;; A341;YI SYLLABLE SSYX;Lo;0;L;;;;;N;;;;; A342;YI SYLLABLE SSY;Lo;0;L;;;;;N;;;;; A343;YI SYLLABLE SSYP;Lo;0;L;;;;;N;;;;; A344;YI SYLLABLE SSYRX;Lo;0;L;;;;;N;;;;; A345;YI SYLLABLE SSYR;Lo;0;L;;;;;N;;;;; A346;YI SYLLABLE ZHAT;Lo;0;L;;;;;N;;;;; A347;YI SYLLABLE ZHAX;Lo;0;L;;;;;N;;;;; A348;YI SYLLABLE ZHA;Lo;0;L;;;;;N;;;;; A349;YI SYLLABLE ZHAP;Lo;0;L;;;;;N;;;;; A34A;YI SYLLABLE ZHUOX;Lo;0;L;;;;;N;;;;; A34B;YI SYLLABLE ZHUO;Lo;0;L;;;;;N;;;;; A34C;YI SYLLABLE ZHUOP;Lo;0;L;;;;;N;;;;; A34D;YI SYLLABLE ZHOT;Lo;0;L;;;;;N;;;;; A34E;YI SYLLABLE ZHOX;Lo;0;L;;;;;N;;;;; A34F;YI SYLLABLE ZHO;Lo;0;L;;;;;N;;;;; A350;YI SYLLABLE ZHOP;Lo;0;L;;;;;N;;;;; A351;YI SYLLABLE ZHET;Lo;0;L;;;;;N;;;;; A352;YI SYLLABLE ZHEX;Lo;0;L;;;;;N;;;;; A353;YI SYLLABLE ZHE;Lo;0;L;;;;;N;;;;; A354;YI SYLLABLE ZHEP;Lo;0;L;;;;;N;;;;; A355;YI SYLLABLE ZHUT;Lo;0;L;;;;;N;;;;; A356;YI SYLLABLE ZHUX;Lo;0;L;;;;;N;;;;; A357;YI SYLLABLE ZHU;Lo;0;L;;;;;N;;;;; A358;YI SYLLABLE ZHUP;Lo;0;L;;;;;N;;;;; A359;YI SYLLABLE ZHURX;Lo;0;L;;;;;N;;;;; A35A;YI SYLLABLE ZHUR;Lo;0;L;;;;;N;;;;; A35B;YI SYLLABLE ZHYT;Lo;0;L;;;;;N;;;;; A35C;YI SYLLABLE ZHYX;Lo;0;L;;;;;N;;;;; A35D;YI SYLLABLE ZHY;Lo;0;L;;;;;N;;;;; A35E;YI SYLLABLE ZHYP;Lo;0;L;;;;;N;;;;; A35F;YI SYLLABLE ZHYRX;Lo;0;L;;;;;N;;;;; A360;YI SYLLABLE ZHYR;Lo;0;L;;;;;N;;;;; A361;YI SYLLABLE CHAT;Lo;0;L;;;;;N;;;;; A362;YI SYLLABLE CHAX;Lo;0;L;;;;;N;;;;; A363;YI SYLLABLE CHA;Lo;0;L;;;;;N;;;;; A364;YI SYLLABLE CHAP;Lo;0;L;;;;;N;;;;; A365;YI SYLLABLE CHUOT;Lo;0;L;;;;;N;;;;; A366;YI SYLLABLE CHUOX;Lo;0;L;;;;;N;;;;; A367;YI SYLLABLE CHUO;Lo;0;L;;;;;N;;;;; A368;YI SYLLABLE CHUOP;Lo;0;L;;;;;N;;;;; A369;YI SYLLABLE CHOT;Lo;0;L;;;;;N;;;;; A36A;YI SYLLABLE CHOX;Lo;0;L;;;;;N;;;;; A36B;YI SYLLABLE CHO;Lo;0;L;;;;;N;;;;; A36C;YI SYLLABLE CHOP;Lo;0;L;;;;;N;;;;; A36D;YI SYLLABLE CHET;Lo;0;L;;;;;N;;;;; A36E;YI SYLLABLE CHEX;Lo;0;L;;;;;N;;;;; A36F;YI SYLLABLE CHE;Lo;0;L;;;;;N;;;;; A370;YI SYLLABLE CHEP;Lo;0;L;;;;;N;;;;; A371;YI SYLLABLE CHUX;Lo;0;L;;;;;N;;;;; A372;YI SYLLABLE CHU;Lo;0;L;;;;;N;;;;; A373;YI SYLLABLE CHUP;Lo;0;L;;;;;N;;;;; A374;YI SYLLABLE CHURX;Lo;0;L;;;;;N;;;;; A375;YI SYLLABLE CHUR;Lo;0;L;;;;;N;;;;; A376;YI SYLLABLE CHYT;Lo;0;L;;;;;N;;;;; A377;YI SYLLABLE CHYX;Lo;0;L;;;;;N;;;;; A378;YI SYLLABLE CHY;Lo;0;L;;;;;N;;;;; A379;YI SYLLABLE CHYP;Lo;0;L;;;;;N;;;;; A37A;YI SYLLABLE CHYRX;Lo;0;L;;;;;N;;;;; A37B;YI SYLLABLE CHYR;Lo;0;L;;;;;N;;;;; A37C;YI SYLLABLE RRAX;Lo;0;L;;;;;N;;;;; A37D;YI SYLLABLE RRA;Lo;0;L;;;;;N;;;;; A37E;YI SYLLABLE RRUOX;Lo;0;L;;;;;N;;;;; A37F;YI SYLLABLE RRUO;Lo;0;L;;;;;N;;;;; A380;YI SYLLABLE RROT;Lo;0;L;;;;;N;;;;; A381;YI SYLLABLE RROX;Lo;0;L;;;;;N;;;;; A382;YI SYLLABLE RRO;Lo;0;L;;;;;N;;;;; A383;YI SYLLABLE RROP;Lo;0;L;;;;;N;;;;; A384;YI SYLLABLE RRET;Lo;0;L;;;;;N;;;;; A385;YI SYLLABLE RREX;Lo;0;L;;;;;N;;;;; A386;YI SYLLABLE RRE;Lo;0;L;;;;;N;;;;; A387;YI SYLLABLE RREP;Lo;0;L;;;;;N;;;;; A388;YI SYLLABLE RRUT;Lo;0;L;;;;;N;;;;; A389;YI SYLLABLE RRUX;Lo;0;L;;;;;N;;;;; A38A;YI SYLLABLE RRU;Lo;0;L;;;;;N;;;;; A38B;YI SYLLABLE RRUP;Lo;0;L;;;;;N;;;;; A38C;YI SYLLABLE RRURX;Lo;0;L;;;;;N;;;;; A38D;YI SYLLABLE RRUR;Lo;0;L;;;;;N;;;;; A38E;YI SYLLABLE RRYT;Lo;0;L;;;;;N;;;;; A38F;YI SYLLABLE RRYX;Lo;0;L;;;;;N;;;;; A390;YI SYLLABLE RRY;Lo;0;L;;;;;N;;;;; A391;YI SYLLABLE RRYP;Lo;0;L;;;;;N;;;;; A392;YI SYLLABLE RRYRX;Lo;0;L;;;;;N;;;;; A393;YI SYLLABLE RRYR;Lo;0;L;;;;;N;;;;; A394;YI SYLLABLE NRAT;Lo;0;L;;;;;N;;;;; A395;YI SYLLABLE NRAX;Lo;0;L;;;;;N;;;;; A396;YI SYLLABLE NRA;Lo;0;L;;;;;N;;;;; A397;YI SYLLABLE NRAP;Lo;0;L;;;;;N;;;;; A398;YI SYLLABLE NROX;Lo;0;L;;;;;N;;;;; A399;YI SYLLABLE NRO;Lo;0;L;;;;;N;;;;; A39A;YI SYLLABLE NROP;Lo;0;L;;;;;N;;;;; A39B;YI SYLLABLE NRET;Lo;0;L;;;;;N;;;;; A39C;YI SYLLABLE NREX;Lo;0;L;;;;;N;;;;; A39D;YI SYLLABLE NRE;Lo;0;L;;;;;N;;;;; A39E;YI SYLLABLE NREP;Lo;0;L;;;;;N;;;;; A39F;YI SYLLABLE NRUT;Lo;0;L;;;;;N;;;;; A3A0;YI SYLLABLE NRUX;Lo;0;L;;;;;N;;;;; A3A1;YI SYLLABLE NRU;Lo;0;L;;;;;N;;;;; A3A2;YI SYLLABLE NRUP;Lo;0;L;;;;;N;;;;; A3A3;YI SYLLABLE NRURX;Lo;0;L;;;;;N;;;;; A3A4;YI SYLLABLE NRUR;Lo;0;L;;;;;N;;;;; A3A5;YI SYLLABLE NRYT;Lo;0;L;;;;;N;;;;; A3A6;YI SYLLABLE NRYX;Lo;0;L;;;;;N;;;;; A3A7;YI SYLLABLE NRY;Lo;0;L;;;;;N;;;;; A3A8;YI SYLLABLE NRYP;Lo;0;L;;;;;N;;;;; A3A9;YI SYLLABLE NRYRX;Lo;0;L;;;;;N;;;;; A3AA;YI SYLLABLE NRYR;Lo;0;L;;;;;N;;;;; A3AB;YI SYLLABLE SHAT;Lo;0;L;;;;;N;;;;; A3AC;YI SYLLABLE SHAX;Lo;0;L;;;;;N;;;;; A3AD;YI SYLLABLE SHA;Lo;0;L;;;;;N;;;;; A3AE;YI SYLLABLE SHAP;Lo;0;L;;;;;N;;;;; A3AF;YI SYLLABLE SHUOX;Lo;0;L;;;;;N;;;;; A3B0;YI SYLLABLE SHUO;Lo;0;L;;;;;N;;;;; A3B1;YI SYLLABLE SHUOP;Lo;0;L;;;;;N;;;;; A3B2;YI SYLLABLE SHOT;Lo;0;L;;;;;N;;;;; A3B3;YI SYLLABLE SHOX;Lo;0;L;;;;;N;;;;; A3B4;YI SYLLABLE SHO;Lo;0;L;;;;;N;;;;; A3B5;YI SYLLABLE SHOP;Lo;0;L;;;;;N;;;;; A3B6;YI SYLLABLE SHET;Lo;0;L;;;;;N;;;;; A3B7;YI SYLLABLE SHEX;Lo;0;L;;;;;N;;;;; A3B8;YI SYLLABLE SHE;Lo;0;L;;;;;N;;;;; A3B9;YI SYLLABLE SHEP;Lo;0;L;;;;;N;;;;; A3BA;YI SYLLABLE SHUT;Lo;0;L;;;;;N;;;;; A3BB;YI SYLLABLE SHUX;Lo;0;L;;;;;N;;;;; A3BC;YI SYLLABLE SHU;Lo;0;L;;;;;N;;;;; A3BD;YI SYLLABLE SHUP;Lo;0;L;;;;;N;;;;; A3BE;YI SYLLABLE SHURX;Lo;0;L;;;;;N;;;;; A3BF;YI SYLLABLE SHUR;Lo;0;L;;;;;N;;;;; A3C0;YI SYLLABLE SHYT;Lo;0;L;;;;;N;;;;; A3C1;YI SYLLABLE SHYX;Lo;0;L;;;;;N;;;;; A3C2;YI SYLLABLE SHY;Lo;0;L;;;;;N;;;;; A3C3;YI SYLLABLE SHYP;Lo;0;L;;;;;N;;;;; A3C4;YI SYLLABLE SHYRX;Lo;0;L;;;;;N;;;;; A3C5;YI SYLLABLE SHYR;Lo;0;L;;;;;N;;;;; A3C6;YI SYLLABLE RAT;Lo;0;L;;;;;N;;;;; A3C7;YI SYLLABLE RAX;Lo;0;L;;;;;N;;;;; A3C8;YI SYLLABLE RA;Lo;0;L;;;;;N;;;;; A3C9;YI SYLLABLE RAP;Lo;0;L;;;;;N;;;;; A3CA;YI SYLLABLE RUOX;Lo;0;L;;;;;N;;;;; A3CB;YI SYLLABLE RUO;Lo;0;L;;;;;N;;;;; A3CC;YI SYLLABLE RUOP;Lo;0;L;;;;;N;;;;; A3CD;YI SYLLABLE ROT;Lo;0;L;;;;;N;;;;; A3CE;YI SYLLABLE ROX;Lo;0;L;;;;;N;;;;; A3CF;YI SYLLABLE RO;Lo;0;L;;;;;N;;;;; A3D0;YI SYLLABLE ROP;Lo;0;L;;;;;N;;;;; A3D1;YI SYLLABLE REX;Lo;0;L;;;;;N;;;;; A3D2;YI SYLLABLE RE;Lo;0;L;;;;;N;;;;; A3D3;YI SYLLABLE REP;Lo;0;L;;;;;N;;;;; A3D4;YI SYLLABLE RUT;Lo;0;L;;;;;N;;;;; A3D5;YI SYLLABLE RUX;Lo;0;L;;;;;N;;;;; A3D6;YI SYLLABLE RU;Lo;0;L;;;;;N;;;;; A3D7;YI SYLLABLE RUP;Lo;0;L;;;;;N;;;;; A3D8;YI SYLLABLE RURX;Lo;0;L;;;;;N;;;;; A3D9;YI SYLLABLE RUR;Lo;0;L;;;;;N;;;;; A3DA;YI SYLLABLE RYT;Lo;0;L;;;;;N;;;;; A3DB;YI SYLLABLE RYX;Lo;0;L;;;;;N;;;;; A3DC;YI SYLLABLE RY;Lo;0;L;;;;;N;;;;; A3DD;YI SYLLABLE RYP;Lo;0;L;;;;;N;;;;; A3DE;YI SYLLABLE RYRX;Lo;0;L;;;;;N;;;;; A3DF;YI SYLLABLE RYR;Lo;0;L;;;;;N;;;;; A3E0;YI SYLLABLE JIT;Lo;0;L;;;;;N;;;;; A3E1;YI SYLLABLE JIX;Lo;0;L;;;;;N;;;;; A3E2;YI SYLLABLE JI;Lo;0;L;;;;;N;;;;; A3E3;YI SYLLABLE JIP;Lo;0;L;;;;;N;;;;; A3E4;YI SYLLABLE JIET;Lo;0;L;;;;;N;;;;; A3E5;YI SYLLABLE JIEX;Lo;0;L;;;;;N;;;;; A3E6;YI SYLLABLE JIE;Lo;0;L;;;;;N;;;;; A3E7;YI SYLLABLE JIEP;Lo;0;L;;;;;N;;;;; A3E8;YI SYLLABLE JUOT;Lo;0;L;;;;;N;;;;; A3E9;YI SYLLABLE JUOX;Lo;0;L;;;;;N;;;;; A3EA;YI SYLLABLE JUO;Lo;0;L;;;;;N;;;;; A3EB;YI SYLLABLE JUOP;Lo;0;L;;;;;N;;;;; A3EC;YI SYLLABLE JOT;Lo;0;L;;;;;N;;;;; A3ED;YI SYLLABLE JOX;Lo;0;L;;;;;N;;;;; A3EE;YI SYLLABLE JO;Lo;0;L;;;;;N;;;;; A3EF;YI SYLLABLE JOP;Lo;0;L;;;;;N;;;;; A3F0;YI SYLLABLE JUT;Lo;0;L;;;;;N;;;;; A3F1;YI SYLLABLE JUX;Lo;0;L;;;;;N;;;;; A3F2;YI SYLLABLE JU;Lo;0;L;;;;;N;;;;; A3F3;YI SYLLABLE JUP;Lo;0;L;;;;;N;;;;; A3F4;YI SYLLABLE JURX;Lo;0;L;;;;;N;;;;; A3F5;YI SYLLABLE JUR;Lo;0;L;;;;;N;;;;; A3F6;YI SYLLABLE JYT;Lo;0;L;;;;;N;;;;; A3F7;YI SYLLABLE JYX;Lo;0;L;;;;;N;;;;; A3F8;YI SYLLABLE JY;Lo;0;L;;;;;N;;;;; A3F9;YI SYLLABLE JYP;Lo;0;L;;;;;N;;;;; A3FA;YI SYLLABLE JYRX;Lo;0;L;;;;;N;;;;; A3FB;YI SYLLABLE JYR;Lo;0;L;;;;;N;;;;; A3FC;YI SYLLABLE QIT;Lo;0;L;;;;;N;;;;; A3FD;YI SYLLABLE QIX;Lo;0;L;;;;;N;;;;; A3FE;YI SYLLABLE QI;Lo;0;L;;;;;N;;;;; A3FF;YI SYLLABLE QIP;Lo;0;L;;;;;N;;;;; A400;YI SYLLABLE QIET;Lo;0;L;;;;;N;;;;; A401;YI SYLLABLE QIEX;Lo;0;L;;;;;N;;;;; A402;YI SYLLABLE QIE;Lo;0;L;;;;;N;;;;; A403;YI SYLLABLE QIEP;Lo;0;L;;;;;N;;;;; A404;YI SYLLABLE QUOT;Lo;0;L;;;;;N;;;;; A405;YI SYLLABLE QUOX;Lo;0;L;;;;;N;;;;; A406;YI SYLLABLE QUO;Lo;0;L;;;;;N;;;;; A407;YI SYLLABLE QUOP;Lo;0;L;;;;;N;;;;; A408;YI SYLLABLE QOT;Lo;0;L;;;;;N;;;;; A409;YI SYLLABLE QOX;Lo;0;L;;;;;N;;;;; A40A;YI SYLLABLE QO;Lo;0;L;;;;;N;;;;; A40B;YI SYLLABLE QOP;Lo;0;L;;;;;N;;;;; A40C;YI SYLLABLE QUT;Lo;0;L;;;;;N;;;;; A40D;YI SYLLABLE QUX;Lo;0;L;;;;;N;;;;; A40E;YI SYLLABLE QU;Lo;0;L;;;;;N;;;;; A40F;YI SYLLABLE QUP;Lo;0;L;;;;;N;;;;; A410;YI SYLLABLE QURX;Lo;0;L;;;;;N;;;;; A411;YI SYLLABLE QUR;Lo;0;L;;;;;N;;;;; A412;YI SYLLABLE QYT;Lo;0;L;;;;;N;;;;; A413;YI SYLLABLE QYX;Lo;0;L;;;;;N;;;;; A414;YI SYLLABLE QY;Lo;0;L;;;;;N;;;;; A415;YI SYLLABLE QYP;Lo;0;L;;;;;N;;;;; A416;YI SYLLABLE QYRX;Lo;0;L;;;;;N;;;;; A417;YI SYLLABLE QYR;Lo;0;L;;;;;N;;;;; A418;YI SYLLABLE JJIT;Lo;0;L;;;;;N;;;;; A419;YI SYLLABLE JJIX;Lo;0;L;;;;;N;;;;; A41A;YI SYLLABLE JJI;Lo;0;L;;;;;N;;;;; A41B;YI SYLLABLE JJIP;Lo;0;L;;;;;N;;;;; A41C;YI SYLLABLE JJIET;Lo;0;L;;;;;N;;;;; A41D;YI SYLLABLE JJIEX;Lo;0;L;;;;;N;;;;; A41E;YI SYLLABLE JJIE;Lo;0;L;;;;;N;;;;; A41F;YI SYLLABLE JJIEP;Lo;0;L;;;;;N;;;;; A420;YI SYLLABLE JJUOX;Lo;0;L;;;;;N;;;;; A421;YI SYLLABLE JJUO;Lo;0;L;;;;;N;;;;; A422;YI SYLLABLE JJUOP;Lo;0;L;;;;;N;;;;; A423;YI SYLLABLE JJOT;Lo;0;L;;;;;N;;;;; A424;YI SYLLABLE JJOX;Lo;0;L;;;;;N;;;;; A425;YI SYLLABLE JJO;Lo;0;L;;;;;N;;;;; A426;YI SYLLABLE JJOP;Lo;0;L;;;;;N;;;;; A427;YI SYLLABLE JJUT;Lo;0;L;;;;;N;;;;; A428;YI SYLLABLE JJUX;Lo;0;L;;;;;N;;;;; A429;YI SYLLABLE JJU;Lo;0;L;;;;;N;;;;; A42A;YI SYLLABLE JJUP;Lo;0;L;;;;;N;;;;; A42B;YI SYLLABLE JJURX;Lo;0;L;;;;;N;;;;; A42C;YI SYLLABLE JJUR;Lo;0;L;;;;;N;;;;; A42D;YI SYLLABLE JJYT;Lo;0;L;;;;;N;;;;; A42E;YI SYLLABLE JJYX;Lo;0;L;;;;;N;;;;; A42F;YI SYLLABLE JJY;Lo;0;L;;;;;N;;;;; A430;YI SYLLABLE JJYP;Lo;0;L;;;;;N;;;;; A431;YI SYLLABLE NJIT;Lo;0;L;;;;;N;;;;; A432;YI SYLLABLE NJIX;Lo;0;L;;;;;N;;;;; A433;YI SYLLABLE NJI;Lo;0;L;;;;;N;;;;; A434;YI SYLLABLE NJIP;Lo;0;L;;;;;N;;;;; A435;YI SYLLABLE NJIET;Lo;0;L;;;;;N;;;;; A436;YI SYLLABLE NJIEX;Lo;0;L;;;;;N;;;;; A437;YI SYLLABLE NJIE;Lo;0;L;;;;;N;;;;; A438;YI SYLLABLE NJIEP;Lo;0;L;;;;;N;;;;; A439;YI SYLLABLE NJUOX;Lo;0;L;;;;;N;;;;; A43A;YI SYLLABLE NJUO;Lo;0;L;;;;;N;;;;; A43B;YI SYLLABLE NJOT;Lo;0;L;;;;;N;;;;; A43C;YI SYLLABLE NJOX;Lo;0;L;;;;;N;;;;; A43D;YI SYLLABLE NJO;Lo;0;L;;;;;N;;;;; A43E;YI SYLLABLE NJOP;Lo;0;L;;;;;N;;;;; A43F;YI SYLLABLE NJUX;Lo;0;L;;;;;N;;;;; A440;YI SYLLABLE NJU;Lo;0;L;;;;;N;;;;; A441;YI SYLLABLE NJUP;Lo;0;L;;;;;N;;;;; A442;YI SYLLABLE NJURX;Lo;0;L;;;;;N;;;;; A443;YI SYLLABLE NJUR;Lo;0;L;;;;;N;;;;; A444;YI SYLLABLE NJYT;Lo;0;L;;;;;N;;;;; A445;YI SYLLABLE NJYX;Lo;0;L;;;;;N;;;;; A446;YI SYLLABLE NJY;Lo;0;L;;;;;N;;;;; A447;YI SYLLABLE NJYP;Lo;0;L;;;;;N;;;;; A448;YI SYLLABLE NJYRX;Lo;0;L;;;;;N;;;;; A449;YI SYLLABLE NJYR;Lo;0;L;;;;;N;;;;; A44A;YI SYLLABLE NYIT;Lo;0;L;;;;;N;;;;; A44B;YI SYLLABLE NYIX;Lo;0;L;;;;;N;;;;; A44C;YI SYLLABLE NYI;Lo;0;L;;;;;N;;;;; A44D;YI SYLLABLE NYIP;Lo;0;L;;;;;N;;;;; A44E;YI SYLLABLE NYIET;Lo;0;L;;;;;N;;;;; A44F;YI SYLLABLE NYIEX;Lo;0;L;;;;;N;;;;; A450;YI SYLLABLE NYIE;Lo;0;L;;;;;N;;;;; A451;YI SYLLABLE NYIEP;Lo;0;L;;;;;N;;;;; A452;YI SYLLABLE NYUOX;Lo;0;L;;;;;N;;;;; A453;YI SYLLABLE NYUO;Lo;0;L;;;;;N;;;;; A454;YI SYLLABLE NYUOP;Lo;0;L;;;;;N;;;;; A455;YI SYLLABLE NYOT;Lo;0;L;;;;;N;;;;; A456;YI SYLLABLE NYOX;Lo;0;L;;;;;N;;;;; A457;YI SYLLABLE NYO;Lo;0;L;;;;;N;;;;; A458;YI SYLLABLE NYOP;Lo;0;L;;;;;N;;;;; A459;YI SYLLABLE NYUT;Lo;0;L;;;;;N;;;;; A45A;YI SYLLABLE NYUX;Lo;0;L;;;;;N;;;;; A45B;YI SYLLABLE NYU;Lo;0;L;;;;;N;;;;; A45C;YI SYLLABLE NYUP;Lo;0;L;;;;;N;;;;; A45D;YI SYLLABLE XIT;Lo;0;L;;;;;N;;;;; A45E;YI SYLLABLE XIX;Lo;0;L;;;;;N;;;;; A45F;YI SYLLABLE XI;Lo;0;L;;;;;N;;;;; A460;YI SYLLABLE XIP;Lo;0;L;;;;;N;;;;; A461;YI SYLLABLE XIET;Lo;0;L;;;;;N;;;;; A462;YI SYLLABLE XIEX;Lo;0;L;;;;;N;;;;; A463;YI SYLLABLE XIE;Lo;0;L;;;;;N;;;;; A464;YI SYLLABLE XIEP;Lo;0;L;;;;;N;;;;; A465;YI SYLLABLE XUOX;Lo;0;L;;;;;N;;;;; A466;YI SYLLABLE XUO;Lo;0;L;;;;;N;;;;; A467;YI SYLLABLE XOT;Lo;0;L;;;;;N;;;;; A468;YI SYLLABLE XOX;Lo;0;L;;;;;N;;;;; A469;YI SYLLABLE XO;Lo;0;L;;;;;N;;;;; A46A;YI SYLLABLE XOP;Lo;0;L;;;;;N;;;;; A46B;YI SYLLABLE XYT;Lo;0;L;;;;;N;;;;; A46C;YI SYLLABLE XYX;Lo;0;L;;;;;N;;;;; A46D;YI SYLLABLE XY;Lo;0;L;;;;;N;;;;; A46E;YI SYLLABLE XYP;Lo;0;L;;;;;N;;;;; A46F;YI SYLLABLE XYRX;Lo;0;L;;;;;N;;;;; A470;YI SYLLABLE XYR;Lo;0;L;;;;;N;;;;; A471;YI SYLLABLE YIT;Lo;0;L;;;;;N;;;;; A472;YI SYLLABLE YIX;Lo;0;L;;;;;N;;;;; A473;YI SYLLABLE YI;Lo;0;L;;;;;N;;;;; A474;YI SYLLABLE YIP;Lo;0;L;;;;;N;;;;; A475;YI SYLLABLE YIET;Lo;0;L;;;;;N;;;;; A476;YI SYLLABLE YIEX;Lo;0;L;;;;;N;;;;; A477;YI SYLLABLE YIE;Lo;0;L;;;;;N;;;;; A478;YI SYLLABLE YIEP;Lo;0;L;;;;;N;;;;; A479;YI SYLLABLE YUOT;Lo;0;L;;;;;N;;;;; A47A;YI SYLLABLE YUOX;Lo;0;L;;;;;N;;;;; A47B;YI SYLLABLE YUO;Lo;0;L;;;;;N;;;;; A47C;YI SYLLABLE YUOP;Lo;0;L;;;;;N;;;;; A47D;YI SYLLABLE YOT;Lo;0;L;;;;;N;;;;; A47E;YI SYLLABLE YOX;Lo;0;L;;;;;N;;;;; A47F;YI SYLLABLE YO;Lo;0;L;;;;;N;;;;; A480;YI SYLLABLE YOP;Lo;0;L;;;;;N;;;;; A481;YI SYLLABLE YUT;Lo;0;L;;;;;N;;;;; A482;YI SYLLABLE YUX;Lo;0;L;;;;;N;;;;; A483;YI SYLLABLE YU;Lo;0;L;;;;;N;;;;; A484;YI SYLLABLE YUP;Lo;0;L;;;;;N;;;;; A485;YI SYLLABLE YURX;Lo;0;L;;;;;N;;;;; A486;YI SYLLABLE YUR;Lo;0;L;;;;;N;;;;; A487;YI SYLLABLE YYT;Lo;0;L;;;;;N;;;;; A488;YI SYLLABLE YYX;Lo;0;L;;;;;N;;;;; A489;YI SYLLABLE YY;Lo;0;L;;;;;N;;;;; A48A;YI SYLLABLE YYP;Lo;0;L;;;;;N;;;;; A48B;YI SYLLABLE YYRX;Lo;0;L;;;;;N;;;;; A48C;YI SYLLABLE YYR;Lo;0;L;;;;;N;;;;; A490;YI RADICAL QOT;So;0;ON;;;;;N;;;;; A491;YI RADICAL LI;So;0;ON;;;;;N;;;;; A492;YI RADICAL KIT;So;0;ON;;;;;N;;;;; A493;YI RADICAL NYIP;So;0;ON;;;;;N;;;;; A494;YI RADICAL CYP;So;0;ON;;;;;N;;;;; A495;YI RADICAL SSI;So;0;ON;;;;;N;;;;; A496;YI RADICAL GGOP;So;0;ON;;;;;N;;;;; A497;YI RADICAL GEP;So;0;ON;;;;;N;;;;; A498;YI RADICAL MI;So;0;ON;;;;;N;;;;; A499;YI RADICAL HXIT;So;0;ON;;;;;N;;;;; A49A;YI RADICAL LYR;So;0;ON;;;;;N;;;;; A49B;YI RADICAL BBUT;So;0;ON;;;;;N;;;;; A49C;YI RADICAL MOP;So;0;ON;;;;;N;;;;; A49D;YI RADICAL YO;So;0;ON;;;;;N;;;;; A49E;YI RADICAL PUT;So;0;ON;;;;;N;;;;; A49F;YI RADICAL HXUO;So;0;ON;;;;;N;;;;; A4A0;YI RADICAL TAT;So;0;ON;;;;;N;;;;; A4A1;YI RADICAL GA;So;0;ON;;;;;N;;;;; A4A2;YI RADICAL ZUP;So;0;ON;;;;;N;;;;; A4A3;YI RADICAL CYT;So;0;ON;;;;;N;;;;; A4A4;YI RADICAL DDUR;So;0;ON;;;;;N;;;;; A4A5;YI RADICAL BUR;So;0;ON;;;;;N;;;;; A4A6;YI RADICAL GGUO;So;0;ON;;;;;N;;;;; A4A7;YI RADICAL NYOP;So;0;ON;;;;;N;;;;; A4A8;YI RADICAL TU;So;0;ON;;;;;N;;;;; A4A9;YI RADICAL OP;So;0;ON;;;;;N;;;;; A4AA;YI RADICAL JJUT;So;0;ON;;;;;N;;;;; A4AB;YI RADICAL ZOT;So;0;ON;;;;;N;;;;; A4AC;YI RADICAL PYT;So;0;ON;;;;;N;;;;; A4AD;YI RADICAL HMO;So;0;ON;;;;;N;;;;; A4AE;YI RADICAL YIT;So;0;ON;;;;;N;;;;; A4AF;YI RADICAL VUR;So;0;ON;;;;;N;;;;; A4B0;YI RADICAL SHY;So;0;ON;;;;;N;;;;; A4B1;YI RADICAL VEP;So;0;ON;;;;;N;;;;; A4B2;YI RADICAL ZA;So;0;ON;;;;;N;;;;; A4B3;YI RADICAL JO;So;0;ON;;;;;N;;;;; A4B4;YI RADICAL NZUP;So;0;ON;;;;;N;;;;; A4B5;YI RADICAL JJY;So;0;ON;;;;;N;;;;; A4B6;YI RADICAL GOT;So;0;ON;;;;;N;;;;; A4B7;YI RADICAL JJIE;So;0;ON;;;;;N;;;;; A4B8;YI RADICAL WO;So;0;ON;;;;;N;;;;; A4B9;YI RADICAL DU;So;0;ON;;;;;N;;;;; A4BA;YI RADICAL SHUR;So;0;ON;;;;;N;;;;; A4BB;YI RADICAL LIE;So;0;ON;;;;;N;;;;; A4BC;YI RADICAL CY;So;0;ON;;;;;N;;;;; A4BD;YI RADICAL CUOP;So;0;ON;;;;;N;;;;; A4BE;YI RADICAL CIP;So;0;ON;;;;;N;;;;; A4BF;YI RADICAL HXOP;So;0;ON;;;;;N;;;;; A4C0;YI RADICAL SHAT;So;0;ON;;;;;N;;;;; A4C1;YI RADICAL ZUR;So;0;ON;;;;;N;;;;; A4C2;YI RADICAL SHOP;So;0;ON;;;;;N;;;;; A4C3;YI RADICAL CHE;So;0;ON;;;;;N;;;;; A4C4;YI RADICAL ZZIET;So;0;ON;;;;;N;;;;; A4C5;YI RADICAL NBIE;So;0;ON;;;;;N;;;;; A4C6;YI RADICAL KE;So;0;ON;;;;;N;;;;; AC00;;Lo;0;L;;;;;N;;;;; D7A3;;Lo;0;L;;;;;N;;;;; D800;;Cs;0;L;;;;;N;;;;; DB7F;;Cs;0;L;;;;;N;;;;; DB80;;Cs;0;L;;;;;N;;;;; DBFF;;Cs;0;L;;;;;N;;;;; DC00;;Cs;0;L;;;;;N;;;;; DFFF;;Cs;0;L;;;;;N;;;;; E000;;Co;0;L;;;;;N;;;;; F8FF;;Co;0;L;;;;;N;;;;; F900;CJK COMPATIBILITY IDEOGRAPH-F900;Lo;0;L;8C48;;;;N;;;;; F901;CJK COMPATIBILITY IDEOGRAPH-F901;Lo;0;L;66F4;;;;N;;;;; F902;CJK COMPATIBILITY IDEOGRAPH-F902;Lo;0;L;8ECA;;;;N;;;;; F903;CJK COMPATIBILITY IDEOGRAPH-F903;Lo;0;L;8CC8;;;;N;;;;; F904;CJK COMPATIBILITY IDEOGRAPH-F904;Lo;0;L;6ED1;;;;N;;;;; F905;CJK COMPATIBILITY IDEOGRAPH-F905;Lo;0;L;4E32;;;;N;;;;; F906;CJK COMPATIBILITY IDEOGRAPH-F906;Lo;0;L;53E5;;;;N;;;;; F907;CJK COMPATIBILITY IDEOGRAPH-F907;Lo;0;L;9F9C;;;;N;;;;; F908;CJK COMPATIBILITY IDEOGRAPH-F908;Lo;0;L;9F9C;;;;N;;;;; F909;CJK COMPATIBILITY IDEOGRAPH-F909;Lo;0;L;5951;;;;N;;;;; F90A;CJK COMPATIBILITY IDEOGRAPH-F90A;Lo;0;L;91D1;;;;N;;;;; F90B;CJK COMPATIBILITY IDEOGRAPH-F90B;Lo;0;L;5587;;;;N;;;;; F90C;CJK COMPATIBILITY IDEOGRAPH-F90C;Lo;0;L;5948;;;;N;;;;; F90D;CJK COMPATIBILITY IDEOGRAPH-F90D;Lo;0;L;61F6;;;;N;;;;; F90E;CJK COMPATIBILITY IDEOGRAPH-F90E;Lo;0;L;7669;;;;N;;;;; F90F;CJK COMPATIBILITY IDEOGRAPH-F90F;Lo;0;L;7F85;;;;N;;;;; F910;CJK COMPATIBILITY IDEOGRAPH-F910;Lo;0;L;863F;;;;N;;;;; F911;CJK COMPATIBILITY IDEOGRAPH-F911;Lo;0;L;87BA;;;;N;;;;; F912;CJK COMPATIBILITY IDEOGRAPH-F912;Lo;0;L;88F8;;;;N;;;;; F913;CJK COMPATIBILITY IDEOGRAPH-F913;Lo;0;L;908F;;;;N;;;;; F914;CJK COMPATIBILITY IDEOGRAPH-F914;Lo;0;L;6A02;;;;N;;;;; F915;CJK COMPATIBILITY IDEOGRAPH-F915;Lo;0;L;6D1B;;;;N;;;;; F916;CJK COMPATIBILITY IDEOGRAPH-F916;Lo;0;L;70D9;;;;N;;;;; F917;CJK COMPATIBILITY IDEOGRAPH-F917;Lo;0;L;73DE;;;;N;;;;; F918;CJK COMPATIBILITY IDEOGRAPH-F918;Lo;0;L;843D;;;;N;;;;; F919;CJK COMPATIBILITY IDEOGRAPH-F919;Lo;0;L;916A;;;;N;;;;; F91A;CJK COMPATIBILITY IDEOGRAPH-F91A;Lo;0;L;99F1;;;;N;;;;; F91B;CJK COMPATIBILITY IDEOGRAPH-F91B;Lo;0;L;4E82;;;;N;;;;; F91C;CJK COMPATIBILITY IDEOGRAPH-F91C;Lo;0;L;5375;;;;N;;;;; F91D;CJK COMPATIBILITY IDEOGRAPH-F91D;Lo;0;L;6B04;;;;N;;;;; F91E;CJK COMPATIBILITY IDEOGRAPH-F91E;Lo;0;L;721B;;;;N;;;;; F91F;CJK COMPATIBILITY IDEOGRAPH-F91F;Lo;0;L;862D;;;;N;;;;; F920;CJK COMPATIBILITY IDEOGRAPH-F920;Lo;0;L;9E1E;;;;N;;;;; F921;CJK COMPATIBILITY IDEOGRAPH-F921;Lo;0;L;5D50;;;;N;;;;; F922;CJK COMPATIBILITY IDEOGRAPH-F922;Lo;0;L;6FEB;;;;N;;;;; F923;CJK COMPATIBILITY IDEOGRAPH-F923;Lo;0;L;85CD;;;;N;;;;; F924;CJK COMPATIBILITY IDEOGRAPH-F924;Lo;0;L;8964;;;;N;;;;; F925;CJK COMPATIBILITY IDEOGRAPH-F925;Lo;0;L;62C9;;;;N;;;;; F926;CJK COMPATIBILITY IDEOGRAPH-F926;Lo;0;L;81D8;;;;N;;;;; F927;CJK COMPATIBILITY IDEOGRAPH-F927;Lo;0;L;881F;;;;N;;;;; F928;CJK COMPATIBILITY IDEOGRAPH-F928;Lo;0;L;5ECA;;;;N;;;;; F929;CJK COMPATIBILITY IDEOGRAPH-F929;Lo;0;L;6717;;;;N;;;;; F92A;CJK COMPATIBILITY IDEOGRAPH-F92A;Lo;0;L;6D6A;;;;N;;;;; F92B;CJK COMPATIBILITY IDEOGRAPH-F92B;Lo;0;L;72FC;;;;N;;;;; F92C;CJK COMPATIBILITY IDEOGRAPH-F92C;Lo;0;L;90CE;;;;N;;;;; F92D;CJK COMPATIBILITY IDEOGRAPH-F92D;Lo;0;L;4F86;;;;N;;;;; F92E;CJK COMPATIBILITY IDEOGRAPH-F92E;Lo;0;L;51B7;;;;N;;;;; F92F;CJK COMPATIBILITY IDEOGRAPH-F92F;Lo;0;L;52DE;;;;N;;;;; F930;CJK COMPATIBILITY IDEOGRAPH-F930;Lo;0;L;64C4;;;;N;;;;; F931;CJK COMPATIBILITY IDEOGRAPH-F931;Lo;0;L;6AD3;;;;N;;;;; F932;CJK COMPATIBILITY IDEOGRAPH-F932;Lo;0;L;7210;;;;N;;;;; F933;CJK COMPATIBILITY IDEOGRAPH-F933;Lo;0;L;76E7;;;;N;;;;; F934;CJK COMPATIBILITY IDEOGRAPH-F934;Lo;0;L;8001;;;;N;;;;; F935;CJK COMPATIBILITY IDEOGRAPH-F935;Lo;0;L;8606;;;;N;;;;; F936;CJK COMPATIBILITY IDEOGRAPH-F936;Lo;0;L;865C;;;;N;;;;; F937;CJK COMPATIBILITY IDEOGRAPH-F937;Lo;0;L;8DEF;;;;N;;;;; F938;CJK COMPATIBILITY IDEOGRAPH-F938;Lo;0;L;9732;;;;N;;;;; F939;CJK COMPATIBILITY IDEOGRAPH-F939;Lo;0;L;9B6F;;;;N;;;;; F93A;CJK COMPATIBILITY IDEOGRAPH-F93A;Lo;0;L;9DFA;;;;N;;;;; F93B;CJK COMPATIBILITY IDEOGRAPH-F93B;Lo;0;L;788C;;;;N;;;;; F93C;CJK COMPATIBILITY IDEOGRAPH-F93C;Lo;0;L;797F;;;;N;;;;; F93D;CJK COMPATIBILITY IDEOGRAPH-F93D;Lo;0;L;7DA0;;;;N;;;;; F93E;CJK COMPATIBILITY IDEOGRAPH-F93E;Lo;0;L;83C9;;;;N;;;;; F93F;CJK COMPATIBILITY IDEOGRAPH-F93F;Lo;0;L;9304;;;;N;;;;; F940;CJK COMPATIBILITY IDEOGRAPH-F940;Lo;0;L;9E7F;;;;N;;;;; F941;CJK COMPATIBILITY IDEOGRAPH-F941;Lo;0;L;8AD6;;;;N;;;;; F942;CJK COMPATIBILITY IDEOGRAPH-F942;Lo;0;L;58DF;;;;N;;;;; F943;CJK COMPATIBILITY IDEOGRAPH-F943;Lo;0;L;5F04;;;;N;;;;; F944;CJK COMPATIBILITY IDEOGRAPH-F944;Lo;0;L;7C60;;;;N;;;;; F945;CJK COMPATIBILITY IDEOGRAPH-F945;Lo;0;L;807E;;;;N;;;;; F946;CJK COMPATIBILITY IDEOGRAPH-F946;Lo;0;L;7262;;;;N;;;;; F947;CJK COMPATIBILITY IDEOGRAPH-F947;Lo;0;L;78CA;;;;N;;;;; F948;CJK COMPATIBILITY IDEOGRAPH-F948;Lo;0;L;8CC2;;;;N;;;;; F949;CJK COMPATIBILITY IDEOGRAPH-F949;Lo;0;L;96F7;;;;N;;;;; F94A;CJK COMPATIBILITY IDEOGRAPH-F94A;Lo;0;L;58D8;;;;N;;;;; F94B;CJK COMPATIBILITY IDEOGRAPH-F94B;Lo;0;L;5C62;;;;N;;;;; F94C;CJK COMPATIBILITY IDEOGRAPH-F94C;Lo;0;L;6A13;;;;N;;;;; F94D;CJK COMPATIBILITY IDEOGRAPH-F94D;Lo;0;L;6DDA;;;;N;;;;; F94E;CJK COMPATIBILITY IDEOGRAPH-F94E;Lo;0;L;6F0F;;;;N;;;;; F94F;CJK COMPATIBILITY IDEOGRAPH-F94F;Lo;0;L;7D2F;;;;N;;;;; F950;CJK COMPATIBILITY IDEOGRAPH-F950;Lo;0;L;7E37;;;;N;;;;; F951;CJK COMPATIBILITY IDEOGRAPH-F951;Lo;0;L;964B;;;;N;;;;; F952;CJK COMPATIBILITY IDEOGRAPH-F952;Lo;0;L;52D2;;;;N;;;;; F953;CJK COMPATIBILITY IDEOGRAPH-F953;Lo;0;L;808B;;;;N;;;;; F954;CJK COMPATIBILITY IDEOGRAPH-F954;Lo;0;L;51DC;;;;N;;;;; F955;CJK COMPATIBILITY IDEOGRAPH-F955;Lo;0;L;51CC;;;;N;;;;; F956;CJK COMPATIBILITY IDEOGRAPH-F956;Lo;0;L;7A1C;;;;N;;;;; F957;CJK COMPATIBILITY IDEOGRAPH-F957;Lo;0;L;7DBE;;;;N;;;;; F958;CJK COMPATIBILITY IDEOGRAPH-F958;Lo;0;L;83F1;;;;N;;;;; F959;CJK COMPATIBILITY IDEOGRAPH-F959;Lo;0;L;9675;;;;N;;;;; F95A;CJK COMPATIBILITY IDEOGRAPH-F95A;Lo;0;L;8B80;;;;N;;;;; F95B;CJK COMPATIBILITY IDEOGRAPH-F95B;Lo;0;L;62CF;;;;N;;;;; F95C;CJK COMPATIBILITY IDEOGRAPH-F95C;Lo;0;L;6A02;;;;N;;;;; F95D;CJK COMPATIBILITY IDEOGRAPH-F95D;Lo;0;L;8AFE;;;;N;;;;; F95E;CJK COMPATIBILITY IDEOGRAPH-F95E;Lo;0;L;4E39;;;;N;;;;; F95F;CJK COMPATIBILITY IDEOGRAPH-F95F;Lo;0;L;5BE7;;;;N;;;;; F960;CJK COMPATIBILITY IDEOGRAPH-F960;Lo;0;L;6012;;;;N;;;;; F961;CJK COMPATIBILITY IDEOGRAPH-F961;Lo;0;L;7387;;;;N;;;;; F962;CJK COMPATIBILITY IDEOGRAPH-F962;Lo;0;L;7570;;;;N;;;;; F963;CJK COMPATIBILITY IDEOGRAPH-F963;Lo;0;L;5317;;;;N;;;;; F964;CJK COMPATIBILITY IDEOGRAPH-F964;Lo;0;L;78FB;;;;N;;;;; F965;CJK COMPATIBILITY IDEOGRAPH-F965;Lo;0;L;4FBF;;;;N;;;;; F966;CJK COMPATIBILITY IDEOGRAPH-F966;Lo;0;L;5FA9;;;;N;;;;; F967;CJK COMPATIBILITY IDEOGRAPH-F967;Lo;0;L;4E0D;;;;N;;;;; F968;CJK COMPATIBILITY IDEOGRAPH-F968;Lo;0;L;6CCC;;;;N;;;;; F969;CJK COMPATIBILITY IDEOGRAPH-F969;Lo;0;L;6578;;;;N;;;;; F96A;CJK COMPATIBILITY IDEOGRAPH-F96A;Lo;0;L;7D22;;;;N;;;;; F96B;CJK COMPATIBILITY IDEOGRAPH-F96B;Lo;0;L;53C3;;;;N;;;;; F96C;CJK COMPATIBILITY IDEOGRAPH-F96C;Lo;0;L;585E;;;;N;;;;; F96D;CJK COMPATIBILITY IDEOGRAPH-F96D;Lo;0;L;7701;;;;N;;;;; F96E;CJK COMPATIBILITY IDEOGRAPH-F96E;Lo;0;L;8449;;;;N;;;;; F96F;CJK COMPATIBILITY IDEOGRAPH-F96F;Lo;0;L;8AAA;;;;N;;;;; F970;CJK COMPATIBILITY IDEOGRAPH-F970;Lo;0;L;6BBA;;;;N;;;;; F971;CJK COMPATIBILITY IDEOGRAPH-F971;Lo;0;L;8FB0;;;;N;;;;; F972;CJK COMPATIBILITY IDEOGRAPH-F972;Lo;0;L;6C88;;;;N;;;;; F973;CJK COMPATIBILITY IDEOGRAPH-F973;Lo;0;L;62FE;;;;N;;;;; F974;CJK COMPATIBILITY IDEOGRAPH-F974;Lo;0;L;82E5;;;;N;;;;; F975;CJK COMPATIBILITY IDEOGRAPH-F975;Lo;0;L;63A0;;;;N;;;;; F976;CJK COMPATIBILITY IDEOGRAPH-F976;Lo;0;L;7565;;;;N;;;;; F977;CJK COMPATIBILITY IDEOGRAPH-F977;Lo;0;L;4EAE;;;;N;;;;; F978;CJK COMPATIBILITY IDEOGRAPH-F978;Lo;0;L;5169;;;;N;;;;; F979;CJK COMPATIBILITY IDEOGRAPH-F979;Lo;0;L;51C9;;;;N;;;;; F97A;CJK COMPATIBILITY IDEOGRAPH-F97A;Lo;0;L;6881;;;;N;;;;; F97B;CJK COMPATIBILITY IDEOGRAPH-F97B;Lo;0;L;7CE7;;;;N;;;;; F97C;CJK COMPATIBILITY IDEOGRAPH-F97C;Lo;0;L;826F;;;;N;;;;; F97D;CJK COMPATIBILITY IDEOGRAPH-F97D;Lo;0;L;8AD2;;;;N;;;;; F97E;CJK COMPATIBILITY IDEOGRAPH-F97E;Lo;0;L;91CF;;;;N;;;;; F97F;CJK COMPATIBILITY IDEOGRAPH-F97F;Lo;0;L;52F5;;;;N;;;;; F980;CJK COMPATIBILITY IDEOGRAPH-F980;Lo;0;L;5442;;;;N;;;;; F981;CJK COMPATIBILITY IDEOGRAPH-F981;Lo;0;L;5973;;;;N;;;;; F982;CJK COMPATIBILITY IDEOGRAPH-F982;Lo;0;L;5EEC;;;;N;;;;; F983;CJK COMPATIBILITY IDEOGRAPH-F983;Lo;0;L;65C5;;;;N;;;;; F984;CJK COMPATIBILITY IDEOGRAPH-F984;Lo;0;L;6FFE;;;;N;;;;; F985;CJK COMPATIBILITY IDEOGRAPH-F985;Lo;0;L;792A;;;;N;;;;; F986;CJK COMPATIBILITY IDEOGRAPH-F986;Lo;0;L;95AD;;;;N;;;;; F987;CJK COMPATIBILITY IDEOGRAPH-F987;Lo;0;L;9A6A;;;;N;;;;; F988;CJK COMPATIBILITY IDEOGRAPH-F988;Lo;0;L;9E97;;;;N;;;;; F989;CJK COMPATIBILITY IDEOGRAPH-F989;Lo;0;L;9ECE;;;;N;;;;; F98A;CJK COMPATIBILITY IDEOGRAPH-F98A;Lo;0;L;529B;;;;N;;;;; F98B;CJK COMPATIBILITY IDEOGRAPH-F98B;Lo;0;L;66C6;;;;N;;;;; F98C;CJK COMPATIBILITY IDEOGRAPH-F98C;Lo;0;L;6B77;;;;N;;;;; F98D;CJK COMPATIBILITY IDEOGRAPH-F98D;Lo;0;L;8F62;;;;N;;;;; F98E;CJK COMPATIBILITY IDEOGRAPH-F98E;Lo;0;L;5E74;;;;N;;;;; F98F;CJK COMPATIBILITY IDEOGRAPH-F98F;Lo;0;L;6190;;;;N;;;;; F990;CJK COMPATIBILITY IDEOGRAPH-F990;Lo;0;L;6200;;;;N;;;;; F991;CJK COMPATIBILITY IDEOGRAPH-F991;Lo;0;L;649A;;;;N;;;;; F992;CJK COMPATIBILITY IDEOGRAPH-F992;Lo;0;L;6F23;;;;N;;;;; F993;CJK COMPATIBILITY IDEOGRAPH-F993;Lo;0;L;7149;;;;N;;;;; F994;CJK COMPATIBILITY IDEOGRAPH-F994;Lo;0;L;7489;;;;N;;;;; F995;CJK COMPATIBILITY IDEOGRAPH-F995;Lo;0;L;79CA;;;;N;;;;; F996;CJK COMPATIBILITY IDEOGRAPH-F996;Lo;0;L;7DF4;;;;N;;;;; F997;CJK COMPATIBILITY IDEOGRAPH-F997;Lo;0;L;806F;;;;N;;;;; F998;CJK COMPATIBILITY IDEOGRAPH-F998;Lo;0;L;8F26;;;;N;;;;; F999;CJK COMPATIBILITY IDEOGRAPH-F999;Lo;0;L;84EE;;;;N;;;;; F99A;CJK COMPATIBILITY IDEOGRAPH-F99A;Lo;0;L;9023;;;;N;;;;; F99B;CJK COMPATIBILITY IDEOGRAPH-F99B;Lo;0;L;934A;;;;N;;;;; F99C;CJK COMPATIBILITY IDEOGRAPH-F99C;Lo;0;L;5217;;;;N;;;;; F99D;CJK COMPATIBILITY IDEOGRAPH-F99D;Lo;0;L;52A3;;;;N;;;;; F99E;CJK COMPATIBILITY IDEOGRAPH-F99E;Lo;0;L;54BD;;;;N;;;;; F99F;CJK COMPATIBILITY IDEOGRAPH-F99F;Lo;0;L;70C8;;;;N;;;;; F9A0;CJK COMPATIBILITY IDEOGRAPH-F9A0;Lo;0;L;88C2;;;;N;;;;; F9A1;CJK COMPATIBILITY IDEOGRAPH-F9A1;Lo;0;L;8AAA;;;;N;;;;; F9A2;CJK COMPATIBILITY IDEOGRAPH-F9A2;Lo;0;L;5EC9;;;;N;;;;; F9A3;CJK COMPATIBILITY IDEOGRAPH-F9A3;Lo;0;L;5FF5;;;;N;;;;; F9A4;CJK COMPATIBILITY IDEOGRAPH-F9A4;Lo;0;L;637B;;;;N;;;;; F9A5;CJK COMPATIBILITY IDEOGRAPH-F9A5;Lo;0;L;6BAE;;;;N;;;;; F9A6;CJK COMPATIBILITY IDEOGRAPH-F9A6;Lo;0;L;7C3E;;;;N;;;;; F9A7;CJK COMPATIBILITY IDEOGRAPH-F9A7;Lo;0;L;7375;;;;N;;;;; F9A8;CJK COMPATIBILITY IDEOGRAPH-F9A8;Lo;0;L;4EE4;;;;N;;;;; F9A9;CJK COMPATIBILITY IDEOGRAPH-F9A9;Lo;0;L;56F9;;;;N;;;;; F9AA;CJK COMPATIBILITY IDEOGRAPH-F9AA;Lo;0;L;5BE7;;;;N;;;;; F9AB;CJK COMPATIBILITY IDEOGRAPH-F9AB;Lo;0;L;5DBA;;;;N;;;;; F9AC;CJK COMPATIBILITY IDEOGRAPH-F9AC;Lo;0;L;601C;;;;N;;;;; F9AD;CJK COMPATIBILITY IDEOGRAPH-F9AD;Lo;0;L;73B2;;;;N;;;;; F9AE;CJK COMPATIBILITY IDEOGRAPH-F9AE;Lo;0;L;7469;;;;N;;;;; F9AF;CJK COMPATIBILITY IDEOGRAPH-F9AF;Lo;0;L;7F9A;;;;N;;;;; F9B0;CJK COMPATIBILITY IDEOGRAPH-F9B0;Lo;0;L;8046;;;;N;;;;; F9B1;CJK COMPATIBILITY IDEOGRAPH-F9B1;Lo;0;L;9234;;;;N;;;;; F9B2;CJK COMPATIBILITY IDEOGRAPH-F9B2;Lo;0;L;96F6;;;;N;;;;; F9B3;CJK COMPATIBILITY IDEOGRAPH-F9B3;Lo;0;L;9748;;;;N;;;;; F9B4;CJK COMPATIBILITY IDEOGRAPH-F9B4;Lo;0;L;9818;;;;N;;;;; F9B5;CJK COMPATIBILITY IDEOGRAPH-F9B5;Lo;0;L;4F8B;;;;N;;;;; F9B6;CJK COMPATIBILITY IDEOGRAPH-F9B6;Lo;0;L;79AE;;;;N;;;;; F9B7;CJK COMPATIBILITY IDEOGRAPH-F9B7;Lo;0;L;91B4;;;;N;;;;; F9B8;CJK COMPATIBILITY IDEOGRAPH-F9B8;Lo;0;L;96B8;;;;N;;;;; F9B9;CJK COMPATIBILITY IDEOGRAPH-F9B9;Lo;0;L;60E1;;;;N;;;;; F9BA;CJK COMPATIBILITY IDEOGRAPH-F9BA;Lo;0;L;4E86;;;;N;;;;; F9BB;CJK COMPATIBILITY IDEOGRAPH-F9BB;Lo;0;L;50DA;;;;N;;;;; F9BC;CJK COMPATIBILITY IDEOGRAPH-F9BC;Lo;0;L;5BEE;;;;N;;;;; F9BD;CJK COMPATIBILITY IDEOGRAPH-F9BD;Lo;0;L;5C3F;;;;N;;;;; F9BE;CJK COMPATIBILITY IDEOGRAPH-F9BE;Lo;0;L;6599;;;;N;;;;; F9BF;CJK COMPATIBILITY IDEOGRAPH-F9BF;Lo;0;L;6A02;;;;N;;;;; F9C0;CJK COMPATIBILITY IDEOGRAPH-F9C0;Lo;0;L;71CE;;;;N;;;;; F9C1;CJK COMPATIBILITY IDEOGRAPH-F9C1;Lo;0;L;7642;;;;N;;;;; F9C2;CJK COMPATIBILITY IDEOGRAPH-F9C2;Lo;0;L;84FC;;;;N;;;;; F9C3;CJK COMPATIBILITY IDEOGRAPH-F9C3;Lo;0;L;907C;;;;N;;;;; F9C4;CJK COMPATIBILITY IDEOGRAPH-F9C4;Lo;0;L;9F8D;;;;N;;;;; F9C5;CJK COMPATIBILITY IDEOGRAPH-F9C5;Lo;0;L;6688;;;;N;;;;; F9C6;CJK COMPATIBILITY IDEOGRAPH-F9C6;Lo;0;L;962E;;;;N;;;;; F9C7;CJK COMPATIBILITY IDEOGRAPH-F9C7;Lo;0;L;5289;;;;N;;;;; F9C8;CJK COMPATIBILITY IDEOGRAPH-F9C8;Lo;0;L;677B;;;;N;;;;; F9C9;CJK COMPATIBILITY IDEOGRAPH-F9C9;Lo;0;L;67F3;;;;N;;;;; F9CA;CJK COMPATIBILITY IDEOGRAPH-F9CA;Lo;0;L;6D41;;;;N;;;;; F9CB;CJK COMPATIBILITY IDEOGRAPH-F9CB;Lo;0;L;6E9C;;;;N;;;;; F9CC;CJK COMPATIBILITY IDEOGRAPH-F9CC;Lo;0;L;7409;;;;N;;;;; F9CD;CJK COMPATIBILITY IDEOGRAPH-F9CD;Lo;0;L;7559;;;;N;;;;; F9CE;CJK COMPATIBILITY IDEOGRAPH-F9CE;Lo;0;L;786B;;;;N;;;;; F9CF;CJK COMPATIBILITY IDEOGRAPH-F9CF;Lo;0;L;7D10;;;;N;;;;; F9D0;CJK COMPATIBILITY IDEOGRAPH-F9D0;Lo;0;L;985E;;;;N;;;;; F9D1;CJK COMPATIBILITY IDEOGRAPH-F9D1;Lo;0;L;516D;;;;N;;;;; F9D2;CJK COMPATIBILITY IDEOGRAPH-F9D2;Lo;0;L;622E;;;;N;;;;; F9D3;CJK COMPATIBILITY IDEOGRAPH-F9D3;Lo;0;L;9678;;;;N;;;;; F9D4;CJK COMPATIBILITY IDEOGRAPH-F9D4;Lo;0;L;502B;;;;N;;;;; F9D5;CJK COMPATIBILITY IDEOGRAPH-F9D5;Lo;0;L;5D19;;;;N;;;;; F9D6;CJK COMPATIBILITY IDEOGRAPH-F9D6;Lo;0;L;6DEA;;;;N;;;;; F9D7;CJK COMPATIBILITY IDEOGRAPH-F9D7;Lo;0;L;8F2A;;;;N;;;;; F9D8;CJK COMPATIBILITY IDEOGRAPH-F9D8;Lo;0;L;5F8B;;;;N;;;;; F9D9;CJK COMPATIBILITY IDEOGRAPH-F9D9;Lo;0;L;6144;;;;N;;;;; F9DA;CJK COMPATIBILITY IDEOGRAPH-F9DA;Lo;0;L;6817;;;;N;;;;; F9DB;CJK COMPATIBILITY IDEOGRAPH-F9DB;Lo;0;L;7387;;;;N;;;;; F9DC;CJK COMPATIBILITY IDEOGRAPH-F9DC;Lo;0;L;9686;;;;N;;;;; F9DD;CJK COMPATIBILITY IDEOGRAPH-F9DD;Lo;0;L;5229;;;;N;;;;; F9DE;CJK COMPATIBILITY IDEOGRAPH-F9DE;Lo;0;L;540F;;;;N;;;;; F9DF;CJK COMPATIBILITY IDEOGRAPH-F9DF;Lo;0;L;5C65;;;;N;;;;; F9E0;CJK COMPATIBILITY IDEOGRAPH-F9E0;Lo;0;L;6613;;;;N;;;;; F9E1;CJK COMPATIBILITY IDEOGRAPH-F9E1;Lo;0;L;674E;;;;N;;;;; F9E2;CJK COMPATIBILITY IDEOGRAPH-F9E2;Lo;0;L;68A8;;;;N;;;;; F9E3;CJK COMPATIBILITY IDEOGRAPH-F9E3;Lo;0;L;6CE5;;;;N;;;;; F9E4;CJK COMPATIBILITY IDEOGRAPH-F9E4;Lo;0;L;7406;;;;N;;;;; F9E5;CJK COMPATIBILITY IDEOGRAPH-F9E5;Lo;0;L;75E2;;;;N;;;;; F9E6;CJK COMPATIBILITY IDEOGRAPH-F9E6;Lo;0;L;7F79;;;;N;;;;; F9E7;CJK COMPATIBILITY IDEOGRAPH-F9E7;Lo;0;L;88CF;;;;N;;;;; F9E8;CJK COMPATIBILITY IDEOGRAPH-F9E8;Lo;0;L;88E1;;;;N;;;;; F9E9;CJK COMPATIBILITY IDEOGRAPH-F9E9;Lo;0;L;91CC;;;;N;;;;; F9EA;CJK COMPATIBILITY IDEOGRAPH-F9EA;Lo;0;L;96E2;;;;N;;;;; F9EB;CJK COMPATIBILITY IDEOGRAPH-F9EB;Lo;0;L;533F;;;;N;;;;; F9EC;CJK COMPATIBILITY IDEOGRAPH-F9EC;Lo;0;L;6EBA;;;;N;;;;; F9ED;CJK COMPATIBILITY IDEOGRAPH-F9ED;Lo;0;L;541D;;;;N;;;;; F9EE;CJK COMPATIBILITY IDEOGRAPH-F9EE;Lo;0;L;71D0;;;;N;;;;; F9EF;CJK COMPATIBILITY IDEOGRAPH-F9EF;Lo;0;L;7498;;;;N;;;;; F9F0;CJK COMPATIBILITY IDEOGRAPH-F9F0;Lo;0;L;85FA;;;;N;;;;; F9F1;CJK COMPATIBILITY IDEOGRAPH-F9F1;Lo;0;L;96A3;;;;N;;;;; F9F2;CJK COMPATIBILITY IDEOGRAPH-F9F2;Lo;0;L;9C57;;;;N;;;;; F9F3;CJK COMPATIBILITY IDEOGRAPH-F9F3;Lo;0;L;9E9F;;;;N;;;;; F9F4;CJK COMPATIBILITY IDEOGRAPH-F9F4;Lo;0;L;6797;;;;N;;;;; F9F5;CJK COMPATIBILITY IDEOGRAPH-F9F5;Lo;0;L;6DCB;;;;N;;;;; F9F6;CJK COMPATIBILITY IDEOGRAPH-F9F6;Lo;0;L;81E8;;;;N;;;;; F9F7;CJK COMPATIBILITY IDEOGRAPH-F9F7;Lo;0;L;7ACB;;;;N;;;;; F9F8;CJK COMPATIBILITY IDEOGRAPH-F9F8;Lo;0;L;7B20;;;;N;;;;; F9F9;CJK COMPATIBILITY IDEOGRAPH-F9F9;Lo;0;L;7C92;;;;N;;;;; F9FA;CJK COMPATIBILITY IDEOGRAPH-F9FA;Lo;0;L;72C0;;;;N;;;;; F9FB;CJK COMPATIBILITY IDEOGRAPH-F9FB;Lo;0;L;7099;;;;N;;;;; F9FC;CJK COMPATIBILITY IDEOGRAPH-F9FC;Lo;0;L;8B58;;;;N;;;;; F9FD;CJK COMPATIBILITY IDEOGRAPH-F9FD;Lo;0;L;4EC0;;;;N;;;;; F9FE;CJK COMPATIBILITY IDEOGRAPH-F9FE;Lo;0;L;8336;;;;N;;;;; F9FF;CJK COMPATIBILITY IDEOGRAPH-F9FF;Lo;0;L;523A;;;;N;;;;; FA00;CJK COMPATIBILITY IDEOGRAPH-FA00;Lo;0;L;5207;;;;N;;;;; FA01;CJK COMPATIBILITY IDEOGRAPH-FA01;Lo;0;L;5EA6;;;;N;;;;; FA02;CJK COMPATIBILITY IDEOGRAPH-FA02;Lo;0;L;62D3;;;;N;;;;; FA03;CJK COMPATIBILITY IDEOGRAPH-FA03;Lo;0;L;7CD6;;;;N;;;;; FA04;CJK COMPATIBILITY IDEOGRAPH-FA04;Lo;0;L;5B85;;;;N;;;;; FA05;CJK COMPATIBILITY IDEOGRAPH-FA05;Lo;0;L;6D1E;;;;N;;;;; FA06;CJK COMPATIBILITY IDEOGRAPH-FA06;Lo;0;L;66B4;;;;N;;;;; FA07;CJK COMPATIBILITY IDEOGRAPH-FA07;Lo;0;L;8F3B;;;;N;;;;; FA08;CJK COMPATIBILITY IDEOGRAPH-FA08;Lo;0;L;884C;;;;N;;;;; FA09;CJK COMPATIBILITY IDEOGRAPH-FA09;Lo;0;L;964D;;;;N;;;;; FA0A;CJK COMPATIBILITY IDEOGRAPH-FA0A;Lo;0;L;898B;;;;N;;;;; FA0B;CJK COMPATIBILITY IDEOGRAPH-FA0B;Lo;0;L;5ED3;;;;N;;;;; FA0C;CJK COMPATIBILITY IDEOGRAPH-FA0C;Lo;0;L;5140;;;;N;;;;; FA0D;CJK COMPATIBILITY IDEOGRAPH-FA0D;Lo;0;L;55C0;;;;N;;;;; FA0E;CJK COMPATIBILITY IDEOGRAPH-FA0E;Lo;0;L;;;;;N;;;;; FA0F;CJK COMPATIBILITY IDEOGRAPH-FA0F;Lo;0;L;;;;;N;;;;; FA10;CJK COMPATIBILITY IDEOGRAPH-FA10;Lo;0;L;585A;;;;N;;;;; FA11;CJK COMPATIBILITY IDEOGRAPH-FA11;Lo;0;L;;;;;N;;;;; FA12;CJK COMPATIBILITY IDEOGRAPH-FA12;Lo;0;L;6674;;;;N;;;;; FA13;CJK COMPATIBILITY IDEOGRAPH-FA13;Lo;0;L;;;;;N;;;;; FA14;CJK COMPATIBILITY IDEOGRAPH-FA14;Lo;0;L;;;;;N;;;;; FA15;CJK COMPATIBILITY IDEOGRAPH-FA15;Lo;0;L;51DE;;;;N;;;;; FA16;CJK COMPATIBILITY IDEOGRAPH-FA16;Lo;0;L;732A;;;;N;;;;; FA17;CJK COMPATIBILITY IDEOGRAPH-FA17;Lo;0;L;76CA;;;;N;;;;; FA18;CJK COMPATIBILITY IDEOGRAPH-FA18;Lo;0;L;793C;;;;N;;;;; FA19;CJK COMPATIBILITY IDEOGRAPH-FA19;Lo;0;L;795E;;;;N;;;;; FA1A;CJK COMPATIBILITY IDEOGRAPH-FA1A;Lo;0;L;7965;;;;N;;;;; FA1B;CJK COMPATIBILITY IDEOGRAPH-FA1B;Lo;0;L;798F;;;;N;;;;; FA1C;CJK COMPATIBILITY IDEOGRAPH-FA1C;Lo;0;L;9756;;;;N;;;;; FA1D;CJK COMPATIBILITY IDEOGRAPH-FA1D;Lo;0;L;7CBE;;;;N;;;;; FA1E;CJK COMPATIBILITY IDEOGRAPH-FA1E;Lo;0;L;7FBD;;;;N;;;;; FA1F;CJK COMPATIBILITY IDEOGRAPH-FA1F;Lo;0;L;;;;;N;;*;;; FA20;CJK COMPATIBILITY IDEOGRAPH-FA20;Lo;0;L;8612;;;;N;;;;; FA21;CJK COMPATIBILITY IDEOGRAPH-FA21;Lo;0;L;;;;;N;;;;; FA22;CJK COMPATIBILITY IDEOGRAPH-FA22;Lo;0;L;8AF8;;;;N;;;;; FA23;CJK COMPATIBILITY IDEOGRAPH-FA23;Lo;0;L;;;;;N;;*;;; FA24;CJK COMPATIBILITY IDEOGRAPH-FA24;Lo;0;L;;;;;N;;;;; FA25;CJK COMPATIBILITY IDEOGRAPH-FA25;Lo;0;L;9038;;;;N;;;;; FA26;CJK COMPATIBILITY IDEOGRAPH-FA26;Lo;0;L;90FD;;;;N;;;;; FA27;CJK COMPATIBILITY IDEOGRAPH-FA27;Lo;0;L;;;;;N;;;;; FA28;CJK COMPATIBILITY IDEOGRAPH-FA28;Lo;0;L;;;;;N;;;;; FA29;CJK COMPATIBILITY IDEOGRAPH-FA29;Lo;0;L;;;;;N;;;;; FA2A;CJK COMPATIBILITY IDEOGRAPH-FA2A;Lo;0;L;98EF;;;;N;;;;; FA2B;CJK COMPATIBILITY IDEOGRAPH-FA2B;Lo;0;L;98FC;;;;N;;;;; FA2C;CJK COMPATIBILITY IDEOGRAPH-FA2C;Lo;0;L;9928;;;;N;;;;; FA2D;CJK COMPATIBILITY IDEOGRAPH-FA2D;Lo;0;L;9DB4;;;;N;;;;; FA30;CJK COMPATIBILITY IDEOGRAPH-FA30;Lo;0;L;4FAE;;;;N;;;;; FA31;CJK COMPATIBILITY IDEOGRAPH-FA31;Lo;0;L;50E7;;;;N;;;;; FA32;CJK COMPATIBILITY IDEOGRAPH-FA32;Lo;0;L;514D;;;;N;;;;; FA33;CJK COMPATIBILITY IDEOGRAPH-FA33;Lo;0;L;52C9;;;;N;;;;; FA34;CJK COMPATIBILITY IDEOGRAPH-FA34;Lo;0;L;52E4;;;;N;;;;; FA35;CJK COMPATIBILITY IDEOGRAPH-FA35;Lo;0;L;5351;;;;N;;;;; FA36;CJK COMPATIBILITY IDEOGRAPH-FA36;Lo;0;L;559D;;;;N;;;;; FA37;CJK COMPATIBILITY IDEOGRAPH-FA37;Lo;0;L;5606;;;;N;;;;; FA38;CJK COMPATIBILITY IDEOGRAPH-FA38;Lo;0;L;5668;;;;N;;;;; FA39;CJK COMPATIBILITY IDEOGRAPH-FA39;Lo;0;L;5840;;;;N;;;;; FA3A;CJK COMPATIBILITY IDEOGRAPH-FA3A;Lo;0;L;58A8;;;;N;;;;; FA3B;CJK COMPATIBILITY IDEOGRAPH-FA3B;Lo;0;L;5C64;;;;N;;;;; FA3C;CJK COMPATIBILITY IDEOGRAPH-FA3C;Lo;0;L;5C6E;;;;N;;;;; FA3D;CJK COMPATIBILITY IDEOGRAPH-FA3D;Lo;0;L;6094;;;;N;;;;; FA3E;CJK COMPATIBILITY IDEOGRAPH-FA3E;Lo;0;L;6168;;;;N;;;;; FA3F;CJK COMPATIBILITY IDEOGRAPH-FA3F;Lo;0;L;618E;;;;N;;;;; FA40;CJK COMPATIBILITY IDEOGRAPH-FA40;Lo;0;L;61F2;;;;N;;;;; FA41;CJK COMPATIBILITY IDEOGRAPH-FA41;Lo;0;L;654F;;;;N;;;;; FA42;CJK COMPATIBILITY IDEOGRAPH-FA42;Lo;0;L;65E2;;;;N;;;;; FA43;CJK COMPATIBILITY IDEOGRAPH-FA43;Lo;0;L;6691;;;;N;;;;; FA44;CJK COMPATIBILITY IDEOGRAPH-FA44;Lo;0;L;6885;;;;N;;;;; FA45;CJK COMPATIBILITY IDEOGRAPH-FA45;Lo;0;L;6D77;;;;N;;;;; FA46;CJK COMPATIBILITY IDEOGRAPH-FA46;Lo;0;L;6E1A;;;;N;;;;; FA47;CJK COMPATIBILITY IDEOGRAPH-FA47;Lo;0;L;6F22;;;;N;;;;; FA48;CJK COMPATIBILITY IDEOGRAPH-FA48;Lo;0;L;716E;;;;N;;;;; FA49;CJK COMPATIBILITY IDEOGRAPH-FA49;Lo;0;L;722B;;;;N;;;;; FA4A;CJK COMPATIBILITY IDEOGRAPH-FA4A;Lo;0;L;7422;;;;N;;;;; FA4B;CJK COMPATIBILITY IDEOGRAPH-FA4B;Lo;0;L;7891;;;;N;;;;; FA4C;CJK COMPATIBILITY IDEOGRAPH-FA4C;Lo;0;L;793E;;;;N;;;;; FA4D;CJK COMPATIBILITY IDEOGRAPH-FA4D;Lo;0;L;7949;;;;N;;;;; FA4E;CJK COMPATIBILITY IDEOGRAPH-FA4E;Lo;0;L;7948;;;;N;;;;; FA4F;CJK COMPATIBILITY IDEOGRAPH-FA4F;Lo;0;L;7950;;;;N;;;;; FA50;CJK COMPATIBILITY IDEOGRAPH-FA50;Lo;0;L;7956;;;;N;;;;; FA51;CJK COMPATIBILITY IDEOGRAPH-FA51;Lo;0;L;795D;;;;N;;;;; FA52;CJK COMPATIBILITY IDEOGRAPH-FA52;Lo;0;L;798D;;;;N;;;;; FA53;CJK COMPATIBILITY IDEOGRAPH-FA53;Lo;0;L;798E;;;;N;;;;; FA54;CJK COMPATIBILITY IDEOGRAPH-FA54;Lo;0;L;7A40;;;;N;;;;; FA55;CJK COMPATIBILITY IDEOGRAPH-FA55;Lo;0;L;7A81;;;;N;;;;; FA56;CJK COMPATIBILITY IDEOGRAPH-FA56;Lo;0;L;7BC0;;;;N;;;;; FA57;CJK COMPATIBILITY IDEOGRAPH-FA57;Lo;0;L;7DF4;;;;N;;;;; FA58;CJK COMPATIBILITY IDEOGRAPH-FA58;Lo;0;L;7E09;;;;N;;;;; FA59;CJK COMPATIBILITY IDEOGRAPH-FA59;Lo;0;L;7E41;;;;N;;;;; FA5A;CJK COMPATIBILITY IDEOGRAPH-FA5A;Lo;0;L;7F72;;;;N;;;;; FA5B;CJK COMPATIBILITY IDEOGRAPH-FA5B;Lo;0;L;8005;;;;N;;;;; FA5C;CJK COMPATIBILITY IDEOGRAPH-FA5C;Lo;0;L;81ED;;;;N;;;;; FA5D;CJK COMPATIBILITY IDEOGRAPH-FA5D;Lo;0;L;8279;;;;N;;;;; FA5E;CJK COMPATIBILITY IDEOGRAPH-FA5E;Lo;0;L;8279;;;;N;;;;; FA5F;CJK COMPATIBILITY IDEOGRAPH-FA5F;Lo;0;L;8457;;;;N;;;;; FA60;CJK COMPATIBILITY IDEOGRAPH-FA60;Lo;0;L;8910;;;;N;;;;; FA61;CJK COMPATIBILITY IDEOGRAPH-FA61;Lo;0;L;8996;;;;N;;;;; FA62;CJK COMPATIBILITY IDEOGRAPH-FA62;Lo;0;L;8B01;;;;N;;;;; FA63;CJK COMPATIBILITY IDEOGRAPH-FA63;Lo;0;L;8B39;;;;N;;;;; FA64;CJK COMPATIBILITY IDEOGRAPH-FA64;Lo;0;L;8CD3;;;;N;;;;; FA65;CJK COMPATIBILITY IDEOGRAPH-FA65;Lo;0;L;8D08;;;;N;;;;; FA66;CJK COMPATIBILITY IDEOGRAPH-FA66;Lo;0;L;8FB6;;;;N;;;;; FA67;CJK COMPATIBILITY IDEOGRAPH-FA67;Lo;0;L;9038;;;;N;;;;; FA68;CJK COMPATIBILITY IDEOGRAPH-FA68;Lo;0;L;96E3;;;;N;;;;; FA69;CJK COMPATIBILITY IDEOGRAPH-FA69;Lo;0;L;97FF;;;;N;;;;; FA6A;CJK COMPATIBILITY IDEOGRAPH-FA6A;Lo;0;L;983B;;;;N;;;;; FB00;LATIN SMALL LIGATURE FF;Ll;0;L; 0066 0066;;;;N;;;;; FB01;LATIN SMALL LIGATURE FI;Ll;0;L; 0066 0069;;;;N;;;;; FB02;LATIN SMALL LIGATURE FL;Ll;0;L; 0066 006C;;;;N;;;;; FB03;LATIN SMALL LIGATURE FFI;Ll;0;L; 0066 0066 0069;;;;N;;;;; FB04;LATIN SMALL LIGATURE FFL;Ll;0;L; 0066 0066 006C;;;;N;;;;; FB05;LATIN SMALL LIGATURE LONG S T;Ll;0;L; 017F 0074;;;;N;;;;; FB06;LATIN SMALL LIGATURE ST;Ll;0;L; 0073 0074;;;;N;;;;; FB13;ARMENIAN SMALL LIGATURE MEN NOW;Ll;0;L; 0574 0576;;;;N;;;;; FB14;ARMENIAN SMALL LIGATURE MEN ECH;Ll;0;L; 0574 0565;;;;N;;;;; FB15;ARMENIAN SMALL LIGATURE MEN INI;Ll;0;L; 0574 056B;;;;N;;;;; FB16;ARMENIAN SMALL LIGATURE VEW NOW;Ll;0;L; 057E 0576;;;;N;;;;; FB17;ARMENIAN SMALL LIGATURE MEN XEH;Ll;0;L; 0574 056D;;;;N;;;;; FB1D;HEBREW LETTER YOD WITH HIRIQ;Lo;0;R;05D9 05B4;;;;N;;;;; FB1E;HEBREW POINT JUDEO-SPANISH VARIKA;Mn;26;NSM;;;;;N;HEBREW POINT VARIKA;;;; FB1F;HEBREW LIGATURE YIDDISH YOD YOD PATAH;Lo;0;R;05F2 05B7;;;;N;;;;; FB20;HEBREW LETTER ALTERNATIVE AYIN;Lo;0;R; 05E2;;;;N;;;;; FB21;HEBREW LETTER WIDE ALEF;Lo;0;R; 05D0;;;;N;;;;; FB22;HEBREW LETTER WIDE DALET;Lo;0;R; 05D3;;;;N;;;;; FB23;HEBREW LETTER WIDE HE;Lo;0;R; 05D4;;;;N;;;;; FB24;HEBREW LETTER WIDE KAF;Lo;0;R; 05DB;;;;N;;;;; FB25;HEBREW LETTER WIDE LAMED;Lo;0;R; 05DC;;;;N;;;;; FB26;HEBREW LETTER WIDE FINAL MEM;Lo;0;R; 05DD;;;;N;;;;; FB27;HEBREW LETTER WIDE RESH;Lo;0;R; 05E8;;;;N;;;;; FB28;HEBREW LETTER WIDE TAV;Lo;0;R; 05EA;;;;N;;;;; FB29;HEBREW LETTER ALTERNATIVE PLUS SIGN;Sm;0;ET; 002B;;;;N;;;;; FB2A;HEBREW LETTER SHIN WITH SHIN DOT;Lo;0;R;05E9 05C1;;;;N;;;;; FB2B;HEBREW LETTER SHIN WITH SIN DOT;Lo;0;R;05E9 05C2;;;;N;;;;; FB2C;HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT;Lo;0;R;FB49 05C1;;;;N;;;;; FB2D;HEBREW LETTER SHIN WITH DAGESH AND SIN DOT;Lo;0;R;FB49 05C2;;;;N;;;;; FB2E;HEBREW LETTER ALEF WITH PATAH;Lo;0;R;05D0 05B7;;;;N;;;;; FB2F;HEBREW LETTER ALEF WITH QAMATS;Lo;0;R;05D0 05B8;;;;N;;;;; FB30;HEBREW LETTER ALEF WITH MAPIQ;Lo;0;R;05D0 05BC;;;;N;;;;; FB31;HEBREW LETTER BET WITH DAGESH;Lo;0;R;05D1 05BC;;;;N;;;;; FB32;HEBREW LETTER GIMEL WITH DAGESH;Lo;0;R;05D2 05BC;;;;N;;;;; FB33;HEBREW LETTER DALET WITH DAGESH;Lo;0;R;05D3 05BC;;;;N;;;;; FB34;HEBREW LETTER HE WITH MAPIQ;Lo;0;R;05D4 05BC;;;;N;;;;; FB35;HEBREW LETTER VAV WITH DAGESH;Lo;0;R;05D5 05BC;;;;N;;;;; FB36;HEBREW LETTER ZAYIN WITH DAGESH;Lo;0;R;05D6 05BC;;;;N;;;;; FB38;HEBREW LETTER TET WITH DAGESH;Lo;0;R;05D8 05BC;;;;N;;;;; FB39;HEBREW LETTER YOD WITH DAGESH;Lo;0;R;05D9 05BC;;;;N;;;;; FB3A;HEBREW LETTER FINAL KAF WITH DAGESH;Lo;0;R;05DA 05BC;;;;N;;;;; FB3B;HEBREW LETTER KAF WITH DAGESH;Lo;0;R;05DB 05BC;;;;N;;;;; FB3C;HEBREW LETTER LAMED WITH DAGESH;Lo;0;R;05DC 05BC;;;;N;;;;; FB3E;HEBREW LETTER MEM WITH DAGESH;Lo;0;R;05DE 05BC;;;;N;;;;; FB40;HEBREW LETTER NUN WITH DAGESH;Lo;0;R;05E0 05BC;;;;N;;;;; FB41;HEBREW LETTER SAMEKH WITH DAGESH;Lo;0;R;05E1 05BC;;;;N;;;;; FB43;HEBREW LETTER FINAL PE WITH DAGESH;Lo;0;R;05E3 05BC;;;;N;;;;; FB44;HEBREW LETTER PE WITH DAGESH;Lo;0;R;05E4 05BC;;;;N;;;;; FB46;HEBREW LETTER TSADI WITH DAGESH;Lo;0;R;05E6 05BC;;;;N;;;;; FB47;HEBREW LETTER QOF WITH DAGESH;Lo;0;R;05E7 05BC;;;;N;;;;; FB48;HEBREW LETTER RESH WITH DAGESH;Lo;0;R;05E8 05BC;;;;N;;;;; FB49;HEBREW LETTER SHIN WITH DAGESH;Lo;0;R;05E9 05BC;;;;N;;;;; FB4A;HEBREW LETTER TAV WITH DAGESH;Lo;0;R;05EA 05BC;;;;N;;;;; FB4B;HEBREW LETTER VAV WITH HOLAM;Lo;0;R;05D5 05B9;;;;N;;;;; FB4C;HEBREW LETTER BET WITH RAFE;Lo;0;R;05D1 05BF;;;;N;;;;; FB4D;HEBREW LETTER KAF WITH RAFE;Lo;0;R;05DB 05BF;;;;N;;;;; FB4E;HEBREW LETTER PE WITH RAFE;Lo;0;R;05E4 05BF;;;;N;;;;; FB4F;HEBREW LIGATURE ALEF LAMED;Lo;0;R; 05D0 05DC;;;;N;;;;; FB50;ARABIC LETTER ALEF WASLA ISOLATED FORM;Lo;0;AL; 0671;;;;N;;;;; FB51;ARABIC LETTER ALEF WASLA FINAL FORM;Lo;0;AL; 0671;;;;N;;;;; FB52;ARABIC LETTER BEEH ISOLATED FORM;Lo;0;AL; 067B;;;;N;;;;; FB53;ARABIC LETTER BEEH FINAL FORM;Lo;0;AL; 067B;;;;N;;;;; FB54;ARABIC LETTER BEEH INITIAL FORM;Lo;0;AL; 067B;;;;N;;;;; FB55;ARABIC LETTER BEEH MEDIAL FORM;Lo;0;AL; 067B;;;;N;;;;; FB56;ARABIC LETTER PEH ISOLATED FORM;Lo;0;AL; 067E;;;;N;;;;; FB57;ARABIC LETTER PEH FINAL FORM;Lo;0;AL; 067E;;;;N;;;;; FB58;ARABIC LETTER PEH INITIAL FORM;Lo;0;AL; 067E;;;;N;;;;; FB59;ARABIC LETTER PEH MEDIAL FORM;Lo;0;AL; 067E;;;;N;;;;; FB5A;ARABIC LETTER BEHEH ISOLATED FORM;Lo;0;AL; 0680;;;;N;;;;; FB5B;ARABIC LETTER BEHEH FINAL FORM;Lo;0;AL; 0680;;;;N;;;;; FB5C;ARABIC LETTER BEHEH INITIAL FORM;Lo;0;AL; 0680;;;;N;;;;; FB5D;ARABIC LETTER BEHEH MEDIAL FORM;Lo;0;AL; 0680;;;;N;;;;; FB5E;ARABIC LETTER TTEHEH ISOLATED FORM;Lo;0;AL; 067A;;;;N;;;;; FB5F;ARABIC LETTER TTEHEH FINAL FORM;Lo;0;AL; 067A;;;;N;;;;; FB60;ARABIC LETTER TTEHEH INITIAL FORM;Lo;0;AL; 067A;;;;N;;;;; FB61;ARABIC LETTER TTEHEH MEDIAL FORM;Lo;0;AL; 067A;;;;N;;;;; FB62;ARABIC LETTER TEHEH ISOLATED FORM;Lo;0;AL; 067F;;;;N;;;;; FB63;ARABIC LETTER TEHEH FINAL FORM;Lo;0;AL; 067F;;;;N;;;;; FB64;ARABIC LETTER TEHEH INITIAL FORM;Lo;0;AL; 067F;;;;N;;;;; FB65;ARABIC LETTER TEHEH MEDIAL FORM;Lo;0;AL; 067F;;;;N;;;;; FB66;ARABIC LETTER TTEH ISOLATED FORM;Lo;0;AL; 0679;;;;N;;;;; FB67;ARABIC LETTER TTEH FINAL FORM;Lo;0;AL; 0679;;;;N;;;;; FB68;ARABIC LETTER TTEH INITIAL FORM;Lo;0;AL; 0679;;;;N;;;;; FB69;ARABIC LETTER TTEH MEDIAL FORM;Lo;0;AL; 0679;;;;N;;;;; FB6A;ARABIC LETTER VEH ISOLATED FORM;Lo;0;AL; 06A4;;;;N;;;;; FB6B;ARABIC LETTER VEH FINAL FORM;Lo;0;AL; 06A4;;;;N;;;;; FB6C;ARABIC LETTER VEH INITIAL FORM;Lo;0;AL; 06A4;;;;N;;;;; FB6D;ARABIC LETTER VEH MEDIAL FORM;Lo;0;AL; 06A4;;;;N;;;;; FB6E;ARABIC LETTER PEHEH ISOLATED FORM;Lo;0;AL; 06A6;;;;N;;;;; FB6F;ARABIC LETTER PEHEH FINAL FORM;Lo;0;AL; 06A6;;;;N;;;;; FB70;ARABIC LETTER PEHEH INITIAL FORM;Lo;0;AL; 06A6;;;;N;;;;; FB71;ARABIC LETTER PEHEH MEDIAL FORM;Lo;0;AL; 06A6;;;;N;;;;; FB72;ARABIC LETTER DYEH ISOLATED FORM;Lo;0;AL; 0684;;;;N;;;;; FB73;ARABIC LETTER DYEH FINAL FORM;Lo;0;AL; 0684;;;;N;;;;; FB74;ARABIC LETTER DYEH INITIAL FORM;Lo;0;AL; 0684;;;;N;;;;; FB75;ARABIC LETTER DYEH MEDIAL FORM;Lo;0;AL; 0684;;;;N;;;;; FB76;ARABIC LETTER NYEH ISOLATED FORM;Lo;0;AL; 0683;;;;N;;;;; FB77;ARABIC LETTER NYEH FINAL FORM;Lo;0;AL; 0683;;;;N;;;;; FB78;ARABIC LETTER NYEH INITIAL FORM;Lo;0;AL; 0683;;;;N;;;;; FB79;ARABIC LETTER NYEH MEDIAL FORM;Lo;0;AL; 0683;;;;N;;;;; FB7A;ARABIC LETTER TCHEH ISOLATED FORM;Lo;0;AL; 0686;;;;N;;;;; FB7B;ARABIC LETTER TCHEH FINAL FORM;Lo;0;AL; 0686;;;;N;;;;; FB7C;ARABIC LETTER TCHEH INITIAL FORM;Lo;0;AL; 0686;;;;N;;;;; FB7D;ARABIC LETTER TCHEH MEDIAL FORM;Lo;0;AL; 0686;;;;N;;;;; FB7E;ARABIC LETTER TCHEHEH ISOLATED FORM;Lo;0;AL; 0687;;;;N;;;;; FB7F;ARABIC LETTER TCHEHEH FINAL FORM;Lo;0;AL; 0687;;;;N;;;;; FB80;ARABIC LETTER TCHEHEH INITIAL FORM;Lo;0;AL; 0687;;;;N;;;;; FB81;ARABIC LETTER TCHEHEH MEDIAL FORM;Lo;0;AL; 0687;;;;N;;;;; FB82;ARABIC LETTER DDAHAL ISOLATED FORM;Lo;0;AL; 068D;;;;N;;;;; FB83;ARABIC LETTER DDAHAL FINAL FORM;Lo;0;AL; 068D;;;;N;;;;; FB84;ARABIC LETTER DAHAL ISOLATED FORM;Lo;0;AL; 068C;;;;N;;;;; FB85;ARABIC LETTER DAHAL FINAL FORM;Lo;0;AL; 068C;;;;N;;;;; FB86;ARABIC LETTER DUL ISOLATED FORM;Lo;0;AL; 068E;;;;N;;;;; FB87;ARABIC LETTER DUL FINAL FORM;Lo;0;AL; 068E;;;;N;;;;; FB88;ARABIC LETTER DDAL ISOLATED FORM;Lo;0;AL; 0688;;;;N;;;;; FB89;ARABIC LETTER DDAL FINAL FORM;Lo;0;AL; 0688;;;;N;;;;; FB8A;ARABIC LETTER JEH ISOLATED FORM;Lo;0;AL; 0698;;;;N;;;;; FB8B;ARABIC LETTER JEH FINAL FORM;Lo;0;AL; 0698;;;;N;;;;; FB8C;ARABIC LETTER RREH ISOLATED FORM;Lo;0;AL; 0691;;;;N;;;;; FB8D;ARABIC LETTER RREH FINAL FORM;Lo;0;AL; 0691;;;;N;;;;; FB8E;ARABIC LETTER KEHEH ISOLATED FORM;Lo;0;AL; 06A9;;;;N;;;;; FB8F;ARABIC LETTER KEHEH FINAL FORM;Lo;0;AL; 06A9;;;;N;;;;; FB90;ARABIC LETTER KEHEH INITIAL FORM;Lo;0;AL; 06A9;;;;N;;;;; FB91;ARABIC LETTER KEHEH MEDIAL FORM;Lo;0;AL; 06A9;;;;N;;;;; FB92;ARABIC LETTER GAF ISOLATED FORM;Lo;0;AL; 06AF;;;;N;;;;; FB93;ARABIC LETTER GAF FINAL FORM;Lo;0;AL; 06AF;;;;N;;;;; FB94;ARABIC LETTER GAF INITIAL FORM;Lo;0;AL; 06AF;;;;N;;;;; FB95;ARABIC LETTER GAF MEDIAL FORM;Lo;0;AL; 06AF;;;;N;;;;; FB96;ARABIC LETTER GUEH ISOLATED FORM;Lo;0;AL; 06B3;;;;N;;;;; FB97;ARABIC LETTER GUEH FINAL FORM;Lo;0;AL; 06B3;;;;N;;;;; FB98;ARABIC LETTER GUEH INITIAL FORM;Lo;0;AL; 06B3;;;;N;;;;; FB99;ARABIC LETTER GUEH MEDIAL FORM;Lo;0;AL; 06B3;;;;N;;;;; FB9A;ARABIC LETTER NGOEH ISOLATED FORM;Lo;0;AL; 06B1;;;;N;;;;; FB9B;ARABIC LETTER NGOEH FINAL FORM;Lo;0;AL; 06B1;;;;N;;;;; FB9C;ARABIC LETTER NGOEH INITIAL FORM;Lo;0;AL; 06B1;;;;N;;;;; FB9D;ARABIC LETTER NGOEH MEDIAL FORM;Lo;0;AL; 06B1;;;;N;;;;; FB9E;ARABIC LETTER NOON GHUNNA ISOLATED FORM;Lo;0;AL; 06BA;;;;N;;;;; FB9F;ARABIC LETTER NOON GHUNNA FINAL FORM;Lo;0;AL; 06BA;;;;N;;;;; FBA0;ARABIC LETTER RNOON ISOLATED FORM;Lo;0;AL; 06BB;;;;N;;;;; FBA1;ARABIC LETTER RNOON FINAL FORM;Lo;0;AL; 06BB;;;;N;;;;; FBA2;ARABIC LETTER RNOON INITIAL FORM;Lo;0;AL; 06BB;;;;N;;;;; FBA3;ARABIC LETTER RNOON MEDIAL FORM;Lo;0;AL; 06BB;;;;N;;;;; FBA4;ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM;Lo;0;AL; 06C0;;;;N;;;;; FBA5;ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM;Lo;0;AL; 06C0;;;;N;;;;; FBA6;ARABIC LETTER HEH GOAL ISOLATED FORM;Lo;0;AL; 06C1;;;;N;;;;; FBA7;ARABIC LETTER HEH GOAL FINAL FORM;Lo;0;AL; 06C1;;;;N;;;;; FBA8;ARABIC LETTER HEH GOAL INITIAL FORM;Lo;0;AL; 06C1;;;;N;;;;; FBA9;ARABIC LETTER HEH GOAL MEDIAL FORM;Lo;0;AL; 06C1;;;;N;;;;; FBAA;ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM;Lo;0;AL; 06BE;;;;N;;;;; FBAB;ARABIC LETTER HEH DOACHASHMEE FINAL FORM;Lo;0;AL; 06BE;;;;N;;;;; FBAC;ARABIC LETTER HEH DOACHASHMEE INITIAL FORM;Lo;0;AL; 06BE;;;;N;;;;; FBAD;ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM;Lo;0;AL; 06BE;;;;N;;;;; FBAE;ARABIC LETTER YEH BARREE ISOLATED FORM;Lo;0;AL; 06D2;;;;N;;;;; FBAF;ARABIC LETTER YEH BARREE FINAL FORM;Lo;0;AL; 06D2;;;;N;;;;; FBB0;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 06D3;;;;N;;;;; FBB1;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM;Lo;0;AL; 06D3;;;;N;;;;; FBD3;ARABIC LETTER NG ISOLATED FORM;Lo;0;AL; 06AD;;;;N;;;;; FBD4;ARABIC LETTER NG FINAL FORM;Lo;0;AL; 06AD;;;;N;;;;; FBD5;ARABIC LETTER NG INITIAL FORM;Lo;0;AL; 06AD;;;;N;;;;; FBD6;ARABIC LETTER NG MEDIAL FORM;Lo;0;AL; 06AD;;;;N;;;;; FBD7;ARABIC LETTER U ISOLATED FORM;Lo;0;AL; 06C7;;;;N;;;;; FBD8;ARABIC LETTER U FINAL FORM;Lo;0;AL; 06C7;;;;N;;;;; FBD9;ARABIC LETTER OE ISOLATED FORM;Lo;0;AL; 06C6;;;;N;;;;; FBDA;ARABIC LETTER OE FINAL FORM;Lo;0;AL; 06C6;;;;N;;;;; FBDB;ARABIC LETTER YU ISOLATED FORM;Lo;0;AL; 06C8;;;;N;;;;; FBDC;ARABIC LETTER YU FINAL FORM;Lo;0;AL; 06C8;;;;N;;;;; FBDD;ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 0677;;;;N;;;;; FBDE;ARABIC LETTER VE ISOLATED FORM;Lo;0;AL; 06CB;;;;N;;;;; FBDF;ARABIC LETTER VE FINAL FORM;Lo;0;AL; 06CB;;;;N;;;;; FBE0;ARABIC LETTER KIRGHIZ OE ISOLATED FORM;Lo;0;AL; 06C5;;;;N;;;;; FBE1;ARABIC LETTER KIRGHIZ OE FINAL FORM;Lo;0;AL; 06C5;;;;N;;;;; FBE2;ARABIC LETTER KIRGHIZ YU ISOLATED FORM;Lo;0;AL; 06C9;;;;N;;;;; FBE3;ARABIC LETTER KIRGHIZ YU FINAL FORM;Lo;0;AL; 06C9;;;;N;;;;; FBE4;ARABIC LETTER E ISOLATED FORM;Lo;0;AL; 06D0;;;;N;;;;; FBE5;ARABIC LETTER E FINAL FORM;Lo;0;AL; 06D0;;;;N;;;;; FBE6;ARABIC LETTER E INITIAL FORM;Lo;0;AL; 06D0;;;;N;;;;; FBE7;ARABIC LETTER E MEDIAL FORM;Lo;0;AL; 06D0;;;;N;;;;; FBE8;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM;Lo;0;AL; 0649;;;;N;;;;; FBE9;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM;Lo;0;AL; 0649;;;;N;;;;; FBEA;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM;Lo;0;AL; 0626 0627;;;;N;;;;; FBEB;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM;Lo;0;AL; 0626 0627;;;;N;;;;; FBEC;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM;Lo;0;AL; 0626 06D5;;;;N;;;;; FBED;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM;Lo;0;AL; 0626 06D5;;;;N;;;;; FBEE;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM;Lo;0;AL; 0626 0648;;;;N;;;;; FBEF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM;Lo;0;AL; 0626 0648;;;;N;;;;; FBF0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM;Lo;0;AL; 0626 06C7;;;;N;;;;; FBF1;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM;Lo;0;AL; 0626 06C7;;;;N;;;;; FBF2;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM;Lo;0;AL; 0626 06C6;;;;N;;;;; FBF3;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM;Lo;0;AL; 0626 06C6;;;;N;;;;; FBF4;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM;Lo;0;AL; 0626 06C8;;;;N;;;;; FBF5;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM;Lo;0;AL; 0626 06C8;;;;N;;;;; FBF6;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM;Lo;0;AL; 0626 06D0;;;;N;;;;; FBF7;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORM;Lo;0;AL; 0626 06D0;;;;N;;;;; FBF8;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM;Lo;0;AL; 0626 06D0;;;;N;;;;; FBF9;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0626 0649;;;;N;;;;; FBFA;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0626 0649;;;;N;;;;; FBFB;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM;Lo;0;AL; 0626 0649;;;;N;;;;; FBFC;ARABIC LETTER FARSI YEH ISOLATED FORM;Lo;0;AL; 06CC;;;;N;;;;; FBFD;ARABIC LETTER FARSI YEH FINAL FORM;Lo;0;AL; 06CC;;;;N;;;;; FBFE;ARABIC LETTER FARSI YEH INITIAL FORM;Lo;0;AL; 06CC;;;;N;;;;; FBFF;ARABIC LETTER FARSI YEH MEDIAL FORM;Lo;0;AL; 06CC;;;;N;;;;; FC00;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM;Lo;0;AL; 0626 062C;;;;N;;;;; FC01;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM;Lo;0;AL; 0626 062D;;;;N;;;;; FC02;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM;Lo;0;AL; 0626 0645;;;;N;;;;; FC03;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0626 0649;;;;N;;;;; FC04;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM;Lo;0;AL; 0626 064A;;;;N;;;;; FC05;ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM;Lo;0;AL; 0628 062C;;;;N;;;;; FC06;ARABIC LIGATURE BEH WITH HAH ISOLATED FORM;Lo;0;AL; 0628 062D;;;;N;;;;; FC07;ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM;Lo;0;AL; 0628 062E;;;;N;;;;; FC08;ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM;Lo;0;AL; 0628 0645;;;;N;;;;; FC09;ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0628 0649;;;;N;;;;; FC0A;ARABIC LIGATURE BEH WITH YEH ISOLATED FORM;Lo;0;AL; 0628 064A;;;;N;;;;; FC0B;ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM;Lo;0;AL; 062A 062C;;;;N;;;;; FC0C;ARABIC LIGATURE TEH WITH HAH ISOLATED FORM;Lo;0;AL; 062A 062D;;;;N;;;;; FC0D;ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM;Lo;0;AL; 062A 062E;;;;N;;;;; FC0E;ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM;Lo;0;AL; 062A 0645;;;;N;;;;; FC0F;ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 062A 0649;;;;N;;;;; FC10;ARABIC LIGATURE TEH WITH YEH ISOLATED FORM;Lo;0;AL; 062A 064A;;;;N;;;;; FC11;ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM;Lo;0;AL; 062B 062C;;;;N;;;;; FC12;ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM;Lo;0;AL; 062B 0645;;;;N;;;;; FC13;ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 062B 0649;;;;N;;;;; FC14;ARABIC LIGATURE THEH WITH YEH ISOLATED FORM;Lo;0;AL; 062B 064A;;;;N;;;;; FC15;ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM;Lo;0;AL; 062C 062D;;;;N;;;;; FC16;ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM;Lo;0;AL; 062C 0645;;;;N;;;;; FC17;ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM;Lo;0;AL; 062D 062C;;;;N;;;;; FC18;ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM;Lo;0;AL; 062D 0645;;;;N;;;;; FC19;ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM;Lo;0;AL; 062E 062C;;;;N;;;;; FC1A;ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM;Lo;0;AL; 062E 062D;;;;N;;;;; FC1B;ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM;Lo;0;AL; 062E 0645;;;;N;;;;; FC1C;ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM;Lo;0;AL; 0633 062C;;;;N;;;;; FC1D;ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM;Lo;0;AL; 0633 062D;;;;N;;;;; FC1E;ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM;Lo;0;AL; 0633 062E;;;;N;;;;; FC1F;ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM;Lo;0;AL; 0633 0645;;;;N;;;;; FC20;ARABIC LIGATURE SAD WITH HAH ISOLATED FORM;Lo;0;AL; 0635 062D;;;;N;;;;; FC21;ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM;Lo;0;AL; 0635 0645;;;;N;;;;; FC22;ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM;Lo;0;AL; 0636 062C;;;;N;;;;; FC23;ARABIC LIGATURE DAD WITH HAH ISOLATED FORM;Lo;0;AL; 0636 062D;;;;N;;;;; FC24;ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM;Lo;0;AL; 0636 062E;;;;N;;;;; FC25;ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM;Lo;0;AL; 0636 0645;;;;N;;;;; FC26;ARABIC LIGATURE TAH WITH HAH ISOLATED FORM;Lo;0;AL; 0637 062D;;;;N;;;;; FC27;ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM;Lo;0;AL; 0637 0645;;;;N;;;;; FC28;ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM;Lo;0;AL; 0638 0645;;;;N;;;;; FC29;ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM;Lo;0;AL; 0639 062C;;;;N;;;;; FC2A;ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM;Lo;0;AL; 0639 0645;;;;N;;;;; FC2B;ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM;Lo;0;AL; 063A 062C;;;;N;;;;; FC2C;ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM;Lo;0;AL; 063A 0645;;;;N;;;;; FC2D;ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM;Lo;0;AL; 0641 062C;;;;N;;;;; FC2E;ARABIC LIGATURE FEH WITH HAH ISOLATED FORM;Lo;0;AL; 0641 062D;;;;N;;;;; FC2F;ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM;Lo;0;AL; 0641 062E;;;;N;;;;; FC30;ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM;Lo;0;AL; 0641 0645;;;;N;;;;; FC31;ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0641 0649;;;;N;;;;; FC32;ARABIC LIGATURE FEH WITH YEH ISOLATED FORM;Lo;0;AL; 0641 064A;;;;N;;;;; FC33;ARABIC LIGATURE QAF WITH HAH ISOLATED FORM;Lo;0;AL; 0642 062D;;;;N;;;;; FC34;ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM;Lo;0;AL; 0642 0645;;;;N;;;;; FC35;ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0642 0649;;;;N;;;;; FC36;ARABIC LIGATURE QAF WITH YEH ISOLATED FORM;Lo;0;AL; 0642 064A;;;;N;;;;; FC37;ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM;Lo;0;AL; 0643 0627;;;;N;;;;; FC38;ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM;Lo;0;AL; 0643 062C;;;;N;;;;; FC39;ARABIC LIGATURE KAF WITH HAH ISOLATED FORM;Lo;0;AL; 0643 062D;;;;N;;;;; FC3A;ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM;Lo;0;AL; 0643 062E;;;;N;;;;; FC3B;ARABIC LIGATURE KAF WITH LAM ISOLATED FORM;Lo;0;AL; 0643 0644;;;;N;;;;; FC3C;ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM;Lo;0;AL; 0643 0645;;;;N;;;;; FC3D;ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0643 0649;;;;N;;;;; FC3E;ARABIC LIGATURE KAF WITH YEH ISOLATED FORM;Lo;0;AL; 0643 064A;;;;N;;;;; FC3F;ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM;Lo;0;AL; 0644 062C;;;;N;;;;; FC40;ARABIC LIGATURE LAM WITH HAH ISOLATED FORM;Lo;0;AL; 0644 062D;;;;N;;;;; FC41;ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM;Lo;0;AL; 0644 062E;;;;N;;;;; FC42;ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM;Lo;0;AL; 0644 0645;;;;N;;;;; FC43;ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0644 0649;;;;N;;;;; FC44;ARABIC LIGATURE LAM WITH YEH ISOLATED FORM;Lo;0;AL; 0644 064A;;;;N;;;;; FC45;ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM;Lo;0;AL; 0645 062C;;;;N;;;;; FC46;ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM;Lo;0;AL; 0645 062D;;;;N;;;;; FC47;ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM;Lo;0;AL; 0645 062E;;;;N;;;;; FC48;ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM;Lo;0;AL; 0645 0645;;;;N;;;;; FC49;ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0645 0649;;;;N;;;;; FC4A;ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM;Lo;0;AL; 0645 064A;;;;N;;;;; FC4B;ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM;Lo;0;AL; 0646 062C;;;;N;;;;; FC4C;ARABIC LIGATURE NOON WITH HAH ISOLATED FORM;Lo;0;AL; 0646 062D;;;;N;;;;; FC4D;ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM;Lo;0;AL; 0646 062E;;;;N;;;;; FC4E;ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM;Lo;0;AL; 0646 0645;;;;N;;;;; FC4F;ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0646 0649;;;;N;;;;; FC50;ARABIC LIGATURE NOON WITH YEH ISOLATED FORM;Lo;0;AL; 0646 064A;;;;N;;;;; FC51;ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM;Lo;0;AL; 0647 062C;;;;N;;;;; FC52;ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM;Lo;0;AL; 0647 0645;;;;N;;;;; FC53;ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0647 0649;;;;N;;;;; FC54;ARABIC LIGATURE HEH WITH YEH ISOLATED FORM;Lo;0;AL; 0647 064A;;;;N;;;;; FC55;ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM;Lo;0;AL; 064A 062C;;;;N;;;;; FC56;ARABIC LIGATURE YEH WITH HAH ISOLATED FORM;Lo;0;AL; 064A 062D;;;;N;;;;; FC57;ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM;Lo;0;AL; 064A 062E;;;;N;;;;; FC58;ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM;Lo;0;AL; 064A 0645;;;;N;;;;; FC59;ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 064A 0649;;;;N;;;;; FC5A;ARABIC LIGATURE YEH WITH YEH ISOLATED FORM;Lo;0;AL; 064A 064A;;;;N;;;;; FC5B;ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL; 0630 0670;;;;N;;;;; FC5C;ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL; 0631 0670;;;;N;;;;; FC5D;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL; 0649 0670;;;;N;;;;; FC5E;ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM;Lo;0;AL; 0020 064C 0651;;;;N;;;;; FC5F;ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM;Lo;0;AL; 0020 064D 0651;;;;N;;;;; FC60;ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM;Lo;0;AL; 0020 064E 0651;;;;N;;;;; FC61;ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM;Lo;0;AL; 0020 064F 0651;;;;N;;;;; FC62;ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM;Lo;0;AL; 0020 0650 0651;;;;N;;;;; FC63;ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL; 0020 0651 0670;;;;N;;;;; FC64;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM;Lo;0;AL; 0626 0631;;;;N;;;;; FC65;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM;Lo;0;AL; 0626 0632;;;;N;;;;; FC66;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM;Lo;0;AL; 0626 0645;;;;N;;;;; FC67;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM;Lo;0;AL; 0626 0646;;;;N;;;;; FC68;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0626 0649;;;;N;;;;; FC69;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM;Lo;0;AL; 0626 064A;;;;N;;;;; FC6A;ARABIC LIGATURE BEH WITH REH FINAL FORM;Lo;0;AL; 0628 0631;;;;N;;;;; FC6B;ARABIC LIGATURE BEH WITH ZAIN FINAL FORM;Lo;0;AL; 0628 0632;;;;N;;;;; FC6C;ARABIC LIGATURE BEH WITH MEEM FINAL FORM;Lo;0;AL; 0628 0645;;;;N;;;;; FC6D;ARABIC LIGATURE BEH WITH NOON FINAL FORM;Lo;0;AL; 0628 0646;;;;N;;;;; FC6E;ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0628 0649;;;;N;;;;; FC6F;ARABIC LIGATURE BEH WITH YEH FINAL FORM;Lo;0;AL; 0628 064A;;;;N;;;;; FC70;ARABIC LIGATURE TEH WITH REH FINAL FORM;Lo;0;AL; 062A 0631;;;;N;;;;; FC71;ARABIC LIGATURE TEH WITH ZAIN FINAL FORM;Lo;0;AL; 062A 0632;;;;N;;;;; FC72;ARABIC LIGATURE TEH WITH MEEM FINAL FORM;Lo;0;AL; 062A 0645;;;;N;;;;; FC73;ARABIC LIGATURE TEH WITH NOON FINAL FORM;Lo;0;AL; 062A 0646;;;;N;;;;; FC74;ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062A 0649;;;;N;;;;; FC75;ARABIC LIGATURE TEH WITH YEH FINAL FORM;Lo;0;AL; 062A 064A;;;;N;;;;; FC76;ARABIC LIGATURE THEH WITH REH FINAL FORM;Lo;0;AL; 062B 0631;;;;N;;;;; FC77;ARABIC LIGATURE THEH WITH ZAIN FINAL FORM;Lo;0;AL; 062B 0632;;;;N;;;;; FC78;ARABIC LIGATURE THEH WITH MEEM FINAL FORM;Lo;0;AL; 062B 0645;;;;N;;;;; FC79;ARABIC LIGATURE THEH WITH NOON FINAL FORM;Lo;0;AL; 062B 0646;;;;N;;;;; FC7A;ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062B 0649;;;;N;;;;; FC7B;ARABIC LIGATURE THEH WITH YEH FINAL FORM;Lo;0;AL; 062B 064A;;;;N;;;;; FC7C;ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0641 0649;;;;N;;;;; FC7D;ARABIC LIGATURE FEH WITH YEH FINAL FORM;Lo;0;AL; 0641 064A;;;;N;;;;; FC7E;ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0642 0649;;;;N;;;;; FC7F;ARABIC LIGATURE QAF WITH YEH FINAL FORM;Lo;0;AL; 0642 064A;;;;N;;;;; FC80;ARABIC LIGATURE KAF WITH ALEF FINAL FORM;Lo;0;AL; 0643 0627;;;;N;;;;; FC81;ARABIC LIGATURE KAF WITH LAM FINAL FORM;Lo;0;AL; 0643 0644;;;;N;;;;; FC82;ARABIC LIGATURE KAF WITH MEEM FINAL FORM;Lo;0;AL; 0643 0645;;;;N;;;;; FC83;ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0643 0649;;;;N;;;;; FC84;ARABIC LIGATURE KAF WITH YEH FINAL FORM;Lo;0;AL; 0643 064A;;;;N;;;;; FC85;ARABIC LIGATURE LAM WITH MEEM FINAL FORM;Lo;0;AL; 0644 0645;;;;N;;;;; FC86;ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0644 0649;;;;N;;;;; FC87;ARABIC LIGATURE LAM WITH YEH FINAL FORM;Lo;0;AL; 0644 064A;;;;N;;;;; FC88;ARABIC LIGATURE MEEM WITH ALEF FINAL FORM;Lo;0;AL; 0645 0627;;;;N;;;;; FC89;ARABIC LIGATURE MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0645 0645;;;;N;;;;; FC8A;ARABIC LIGATURE NOON WITH REH FINAL FORM;Lo;0;AL; 0646 0631;;;;N;;;;; FC8B;ARABIC LIGATURE NOON WITH ZAIN FINAL FORM;Lo;0;AL; 0646 0632;;;;N;;;;; FC8C;ARABIC LIGATURE NOON WITH MEEM FINAL FORM;Lo;0;AL; 0646 0645;;;;N;;;;; FC8D;ARABIC LIGATURE NOON WITH NOON FINAL FORM;Lo;0;AL; 0646 0646;;;;N;;;;; FC8E;ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0646 0649;;;;N;;;;; FC8F;ARABIC LIGATURE NOON WITH YEH FINAL FORM;Lo;0;AL; 0646 064A;;;;N;;;;; FC90;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM;Lo;0;AL; 0649 0670;;;;N;;;;; FC91;ARABIC LIGATURE YEH WITH REH FINAL FORM;Lo;0;AL; 064A 0631;;;;N;;;;; FC92;ARABIC LIGATURE YEH WITH ZAIN FINAL FORM;Lo;0;AL; 064A 0632;;;;N;;;;; FC93;ARABIC LIGATURE YEH WITH MEEM FINAL FORM;Lo;0;AL; 064A 0645;;;;N;;;;; FC94;ARABIC LIGATURE YEH WITH NOON FINAL FORM;Lo;0;AL; 064A 0646;;;;N;;;;; FC95;ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 064A 0649;;;;N;;;;; FC96;ARABIC LIGATURE YEH WITH YEH FINAL FORM;Lo;0;AL; 064A 064A;;;;N;;;;; FC97;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM;Lo;0;AL; 0626 062C;;;;N;;;;; FC98;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM;Lo;0;AL; 0626 062D;;;;N;;;;; FC99;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM;Lo;0;AL; 0626 062E;;;;N;;;;; FC9A;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM;Lo;0;AL; 0626 0645;;;;N;;;;; FC9B;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM;Lo;0;AL; 0626 0647;;;;N;;;;; FC9C;ARABIC LIGATURE BEH WITH JEEM INITIAL FORM;Lo;0;AL; 0628 062C;;;;N;;;;; FC9D;ARABIC LIGATURE BEH WITH HAH INITIAL FORM;Lo;0;AL; 0628 062D;;;;N;;;;; FC9E;ARABIC LIGATURE BEH WITH KHAH INITIAL FORM;Lo;0;AL; 0628 062E;;;;N;;;;; FC9F;ARABIC LIGATURE BEH WITH MEEM INITIAL FORM;Lo;0;AL; 0628 0645;;;;N;;;;; FCA0;ARABIC LIGATURE BEH WITH HEH INITIAL FORM;Lo;0;AL; 0628 0647;;;;N;;;;; FCA1;ARABIC LIGATURE TEH WITH JEEM INITIAL FORM;Lo;0;AL; 062A 062C;;;;N;;;;; FCA2;ARABIC LIGATURE TEH WITH HAH INITIAL FORM;Lo;0;AL; 062A 062D;;;;N;;;;; FCA3;ARABIC LIGATURE TEH WITH KHAH INITIAL FORM;Lo;0;AL; 062A 062E;;;;N;;;;; FCA4;ARABIC LIGATURE TEH WITH MEEM INITIAL FORM;Lo;0;AL; 062A 0645;;;;N;;;;; FCA5;ARABIC LIGATURE TEH WITH HEH INITIAL FORM;Lo;0;AL; 062A 0647;;;;N;;;;; FCA6;ARABIC LIGATURE THEH WITH MEEM INITIAL FORM;Lo;0;AL; 062B 0645;;;;N;;;;; FCA7;ARABIC LIGATURE JEEM WITH HAH INITIAL FORM;Lo;0;AL; 062C 062D;;;;N;;;;; FCA8;ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 062C 0645;;;;N;;;;; FCA9;ARABIC LIGATURE HAH WITH JEEM INITIAL FORM;Lo;0;AL; 062D 062C;;;;N;;;;; FCAA;ARABIC LIGATURE HAH WITH MEEM INITIAL FORM;Lo;0;AL; 062D 0645;;;;N;;;;; FCAB;ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM;Lo;0;AL; 062E 062C;;;;N;;;;; FCAC;ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 062E 0645;;;;N;;;;; FCAD;ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM;Lo;0;AL; 0633 062C;;;;N;;;;; FCAE;ARABIC LIGATURE SEEN WITH HAH INITIAL FORM;Lo;0;AL; 0633 062D;;;;N;;;;; FCAF;ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM;Lo;0;AL; 0633 062E;;;;N;;;;; FCB0;ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM;Lo;0;AL; 0633 0645;;;;N;;;;; FCB1;ARABIC LIGATURE SAD WITH HAH INITIAL FORM;Lo;0;AL; 0635 062D;;;;N;;;;; FCB2;ARABIC LIGATURE SAD WITH KHAH INITIAL FORM;Lo;0;AL; 0635 062E;;;;N;;;;; FCB3;ARABIC LIGATURE SAD WITH MEEM INITIAL FORM;Lo;0;AL; 0635 0645;;;;N;;;;; FCB4;ARABIC LIGATURE DAD WITH JEEM INITIAL FORM;Lo;0;AL; 0636 062C;;;;N;;;;; FCB5;ARABIC LIGATURE DAD WITH HAH INITIAL FORM;Lo;0;AL; 0636 062D;;;;N;;;;; FCB6;ARABIC LIGATURE DAD WITH KHAH INITIAL FORM;Lo;0;AL; 0636 062E;;;;N;;;;; FCB7;ARABIC LIGATURE DAD WITH MEEM INITIAL FORM;Lo;0;AL; 0636 0645;;;;N;;;;; FCB8;ARABIC LIGATURE TAH WITH HAH INITIAL FORM;Lo;0;AL; 0637 062D;;;;N;;;;; FCB9;ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM;Lo;0;AL; 0638 0645;;;;N;;;;; FCBA;ARABIC LIGATURE AIN WITH JEEM INITIAL FORM;Lo;0;AL; 0639 062C;;;;N;;;;; FCBB;ARABIC LIGATURE AIN WITH MEEM INITIAL FORM;Lo;0;AL; 0639 0645;;;;N;;;;; FCBC;ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM;Lo;0;AL; 063A 062C;;;;N;;;;; FCBD;ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM;Lo;0;AL; 063A 0645;;;;N;;;;; FCBE;ARABIC LIGATURE FEH WITH JEEM INITIAL FORM;Lo;0;AL; 0641 062C;;;;N;;;;; FCBF;ARABIC LIGATURE FEH WITH HAH INITIAL FORM;Lo;0;AL; 0641 062D;;;;N;;;;; FCC0;ARABIC LIGATURE FEH WITH KHAH INITIAL FORM;Lo;0;AL; 0641 062E;;;;N;;;;; FCC1;ARABIC LIGATURE FEH WITH MEEM INITIAL FORM;Lo;0;AL; 0641 0645;;;;N;;;;; FCC2;ARABIC LIGATURE QAF WITH HAH INITIAL FORM;Lo;0;AL; 0642 062D;;;;N;;;;; FCC3;ARABIC LIGATURE QAF WITH MEEM INITIAL FORM;Lo;0;AL; 0642 0645;;;;N;;;;; FCC4;ARABIC LIGATURE KAF WITH JEEM INITIAL FORM;Lo;0;AL; 0643 062C;;;;N;;;;; FCC5;ARABIC LIGATURE KAF WITH HAH INITIAL FORM;Lo;0;AL; 0643 062D;;;;N;;;;; FCC6;ARABIC LIGATURE KAF WITH KHAH INITIAL FORM;Lo;0;AL; 0643 062E;;;;N;;;;; FCC7;ARABIC LIGATURE KAF WITH LAM INITIAL FORM;Lo;0;AL; 0643 0644;;;;N;;;;; FCC8;ARABIC LIGATURE KAF WITH MEEM INITIAL FORM;Lo;0;AL; 0643 0645;;;;N;;;;; FCC9;ARABIC LIGATURE LAM WITH JEEM INITIAL FORM;Lo;0;AL; 0644 062C;;;;N;;;;; FCCA;ARABIC LIGATURE LAM WITH HAH INITIAL FORM;Lo;0;AL; 0644 062D;;;;N;;;;; FCCB;ARABIC LIGATURE LAM WITH KHAH INITIAL FORM;Lo;0;AL; 0644 062E;;;;N;;;;; FCCC;ARABIC LIGATURE LAM WITH MEEM INITIAL FORM;Lo;0;AL; 0644 0645;;;;N;;;;; FCCD;ARABIC LIGATURE LAM WITH HEH INITIAL FORM;Lo;0;AL; 0644 0647;;;;N;;;;; FCCE;ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM;Lo;0;AL; 0645 062C;;;;N;;;;; FCCF;ARABIC LIGATURE MEEM WITH HAH INITIAL FORM;Lo;0;AL; 0645 062D;;;;N;;;;; FCD0;ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM;Lo;0;AL; 0645 062E;;;;N;;;;; FCD1;ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0645 0645;;;;N;;;;; FCD2;ARABIC LIGATURE NOON WITH JEEM INITIAL FORM;Lo;0;AL; 0646 062C;;;;N;;;;; FCD3;ARABIC LIGATURE NOON WITH HAH INITIAL FORM;Lo;0;AL; 0646 062D;;;;N;;;;; FCD4;ARABIC LIGATURE NOON WITH KHAH INITIAL FORM;Lo;0;AL; 0646 062E;;;;N;;;;; FCD5;ARABIC LIGATURE NOON WITH MEEM INITIAL FORM;Lo;0;AL; 0646 0645;;;;N;;;;; FCD6;ARABIC LIGATURE NOON WITH HEH INITIAL FORM;Lo;0;AL; 0646 0647;;;;N;;;;; FCD7;ARABIC LIGATURE HEH WITH JEEM INITIAL FORM;Lo;0;AL; 0647 062C;;;;N;;;;; FCD8;ARABIC LIGATURE HEH WITH MEEM INITIAL FORM;Lo;0;AL; 0647 0645;;;;N;;;;; FCD9;ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM;Lo;0;AL; 0647 0670;;;;N;;;;; FCDA;ARABIC LIGATURE YEH WITH JEEM INITIAL FORM;Lo;0;AL; 064A 062C;;;;N;;;;; FCDB;ARABIC LIGATURE YEH WITH HAH INITIAL FORM;Lo;0;AL; 064A 062D;;;;N;;;;; FCDC;ARABIC LIGATURE YEH WITH KHAH INITIAL FORM;Lo;0;AL; 064A 062E;;;;N;;;;; FCDD;ARABIC LIGATURE YEH WITH MEEM INITIAL FORM;Lo;0;AL; 064A 0645;;;;N;;;;; FCDE;ARABIC LIGATURE YEH WITH HEH INITIAL FORM;Lo;0;AL; 064A 0647;;;;N;;;;; FCDF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM;Lo;0;AL; 0626 0645;;;;N;;;;; FCE0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM;Lo;0;AL; 0626 0647;;;;N;;;;; FCE1;ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM;Lo;0;AL; 0628 0645;;;;N;;;;; FCE2;ARABIC LIGATURE BEH WITH HEH MEDIAL FORM;Lo;0;AL; 0628 0647;;;;N;;;;; FCE3;ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM;Lo;0;AL; 062A 0645;;;;N;;;;; FCE4;ARABIC LIGATURE TEH WITH HEH MEDIAL FORM;Lo;0;AL; 062A 0647;;;;N;;;;; FCE5;ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM;Lo;0;AL; 062B 0645;;;;N;;;;; FCE6;ARABIC LIGATURE THEH WITH HEH MEDIAL FORM;Lo;0;AL; 062B 0647;;;;N;;;;; FCE7;ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM;Lo;0;AL; 0633 0645;;;;N;;;;; FCE8;ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM;Lo;0;AL; 0633 0647;;;;N;;;;; FCE9;ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM;Lo;0;AL; 0634 0645;;;;N;;;;; FCEA;ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM;Lo;0;AL; 0634 0647;;;;N;;;;; FCEB;ARABIC LIGATURE KAF WITH LAM MEDIAL FORM;Lo;0;AL; 0643 0644;;;;N;;;;; FCEC;ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM;Lo;0;AL; 0643 0645;;;;N;;;;; FCED;ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM;Lo;0;AL; 0644 0645;;;;N;;;;; FCEE;ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM;Lo;0;AL; 0646 0645;;;;N;;;;; FCEF;ARABIC LIGATURE NOON WITH HEH MEDIAL FORM;Lo;0;AL; 0646 0647;;;;N;;;;; FCF0;ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM;Lo;0;AL; 064A 0645;;;;N;;;;; FCF1;ARABIC LIGATURE YEH WITH HEH MEDIAL FORM;Lo;0;AL; 064A 0647;;;;N;;;;; FCF2;ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM;Lo;0;AL; 0640 064E 0651;;;;N;;;;; FCF3;ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM;Lo;0;AL; 0640 064F 0651;;;;N;;;;; FCF4;ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM;Lo;0;AL; 0640 0650 0651;;;;N;;;;; FCF5;ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0637 0649;;;;N;;;;; FCF6;ARABIC LIGATURE TAH WITH YEH ISOLATED FORM;Lo;0;AL; 0637 064A;;;;N;;;;; FCF7;ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0639 0649;;;;N;;;;; FCF8;ARABIC LIGATURE AIN WITH YEH ISOLATED FORM;Lo;0;AL; 0639 064A;;;;N;;;;; FCF9;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 063A 0649;;;;N;;;;; FCFA;ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM;Lo;0;AL; 063A 064A;;;;N;;;;; FCFB;ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0633 0649;;;;N;;;;; FCFC;ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM;Lo;0;AL; 0633 064A;;;;N;;;;; FCFD;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0634 0649;;;;N;;;;; FCFE;ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM;Lo;0;AL; 0634 064A;;;;N;;;;; FCFF;ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 062D 0649;;;;N;;;;; FD00;ARABIC LIGATURE HAH WITH YEH ISOLATED FORM;Lo;0;AL; 062D 064A;;;;N;;;;; FD01;ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 062C 0649;;;;N;;;;; FD02;ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM;Lo;0;AL; 062C 064A;;;;N;;;;; FD03;ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 062E 0649;;;;N;;;;; FD04;ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM;Lo;0;AL; 062E 064A;;;;N;;;;; FD05;ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0635 0649;;;;N;;;;; FD06;ARABIC LIGATURE SAD WITH YEH ISOLATED FORM;Lo;0;AL; 0635 064A;;;;N;;;;; FD07;ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0636 0649;;;;N;;;;; FD08;ARABIC LIGATURE DAD WITH YEH ISOLATED FORM;Lo;0;AL; 0636 064A;;;;N;;;;; FD09;ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM;Lo;0;AL; 0634 062C;;;;N;;;;; FD0A;ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM;Lo;0;AL; 0634 062D;;;;N;;;;; FD0B;ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM;Lo;0;AL; 0634 062E;;;;N;;;;; FD0C;ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM;Lo;0;AL; 0634 0645;;;;N;;;;; FD0D;ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM;Lo;0;AL; 0634 0631;;;;N;;;;; FD0E;ARABIC LIGATURE SEEN WITH REH ISOLATED FORM;Lo;0;AL; 0633 0631;;;;N;;;;; FD0F;ARABIC LIGATURE SAD WITH REH ISOLATED FORM;Lo;0;AL; 0635 0631;;;;N;;;;; FD10;ARABIC LIGATURE DAD WITH REH ISOLATED FORM;Lo;0;AL; 0636 0631;;;;N;;;;; FD11;ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0637 0649;;;;N;;;;; FD12;ARABIC LIGATURE TAH WITH YEH FINAL FORM;Lo;0;AL; 0637 064A;;;;N;;;;; FD13;ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0639 0649;;;;N;;;;; FD14;ARABIC LIGATURE AIN WITH YEH FINAL FORM;Lo;0;AL; 0639 064A;;;;N;;;;; FD15;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 063A 0649;;;;N;;;;; FD16;ARABIC LIGATURE GHAIN WITH YEH FINAL FORM;Lo;0;AL; 063A 064A;;;;N;;;;; FD17;ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0633 0649;;;;N;;;;; FD18;ARABIC LIGATURE SEEN WITH YEH FINAL FORM;Lo;0;AL; 0633 064A;;;;N;;;;; FD19;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0634 0649;;;;N;;;;; FD1A;ARABIC LIGATURE SHEEN WITH YEH FINAL FORM;Lo;0;AL; 0634 064A;;;;N;;;;; FD1B;ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062D 0649;;;;N;;;;; FD1C;ARABIC LIGATURE HAH WITH YEH FINAL FORM;Lo;0;AL; 062D 064A;;;;N;;;;; FD1D;ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062C 0649;;;;N;;;;; FD1E;ARABIC LIGATURE JEEM WITH YEH FINAL FORM;Lo;0;AL; 062C 064A;;;;N;;;;; FD1F;ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062E 0649;;;;N;;;;; FD20;ARABIC LIGATURE KHAH WITH YEH FINAL FORM;Lo;0;AL; 062E 064A;;;;N;;;;; FD21;ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0635 0649;;;;N;;;;; FD22;ARABIC LIGATURE SAD WITH YEH FINAL FORM;Lo;0;AL; 0635 064A;;;;N;;;;; FD23;ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0636 0649;;;;N;;;;; FD24;ARABIC LIGATURE DAD WITH YEH FINAL FORM;Lo;0;AL; 0636 064A;;;;N;;;;; FD25;ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM;Lo;0;AL; 0634 062C;;;;N;;;;; FD26;ARABIC LIGATURE SHEEN WITH HAH FINAL FORM;Lo;0;AL; 0634 062D;;;;N;;;;; FD27;ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM;Lo;0;AL; 0634 062E;;;;N;;;;; FD28;ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM;Lo;0;AL; 0634 0645;;;;N;;;;; FD29;ARABIC LIGATURE SHEEN WITH REH FINAL FORM;Lo;0;AL; 0634 0631;;;;N;;;;; FD2A;ARABIC LIGATURE SEEN WITH REH FINAL FORM;Lo;0;AL; 0633 0631;;;;N;;;;; FD2B;ARABIC LIGATURE SAD WITH REH FINAL FORM;Lo;0;AL; 0635 0631;;;;N;;;;; FD2C;ARABIC LIGATURE DAD WITH REH FINAL FORM;Lo;0;AL; 0636 0631;;;;N;;;;; FD2D;ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM;Lo;0;AL; 0634 062C;;;;N;;;;; FD2E;ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM;Lo;0;AL; 0634 062D;;;;N;;;;; FD2F;ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM;Lo;0;AL; 0634 062E;;;;N;;;;; FD30;ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM;Lo;0;AL; 0634 0645;;;;N;;;;; FD31;ARABIC LIGATURE SEEN WITH HEH INITIAL FORM;Lo;0;AL; 0633 0647;;;;N;;;;; FD32;ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM;Lo;0;AL; 0634 0647;;;;N;;;;; FD33;ARABIC LIGATURE TAH WITH MEEM INITIAL FORM;Lo;0;AL; 0637 0645;;;;N;;;;; FD34;ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM;Lo;0;AL; 0633 062C;;;;N;;;;; FD35;ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM;Lo;0;AL; 0633 062D;;;;N;;;;; FD36;ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM;Lo;0;AL; 0633 062E;;;;N;;;;; FD37;ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM;Lo;0;AL; 0634 062C;;;;N;;;;; FD38;ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM;Lo;0;AL; 0634 062D;;;;N;;;;; FD39;ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM;Lo;0;AL; 0634 062E;;;;N;;;;; FD3A;ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM;Lo;0;AL; 0637 0645;;;;N;;;;; FD3B;ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM;Lo;0;AL; 0638 0645;;;;N;;;;; FD3C;ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM;Lo;0;AL; 0627 064B;;;;N;;;;; FD3D;ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM;Lo;0;AL; 0627 064B;;;;N;;;;; FD3E;ORNATE LEFT PARENTHESIS;Ps;0;ON;;;;;N;;;;; FD3F;ORNATE RIGHT PARENTHESIS;Pe;0;ON;;;;;N;;;;; FD50;ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 062A 062C 0645;;;;N;;;;; FD51;ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM;Lo;0;AL; 062A 062D 062C;;;;N;;;;; FD52;ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL; 062A 062D 062C;;;;N;;;;; FD53;ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL; 062A 062D 0645;;;;N;;;;; FD54;ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 062A 062E 0645;;;;N;;;;; FD55;ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL; 062A 0645 062C;;;;N;;;;; FD56;ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 062A 0645 062D;;;;N;;;;; FD57;ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL; 062A 0645 062E;;;;N;;;;; FD58;ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL; 062C 0645 062D;;;;N;;;;; FD59;ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 062C 0645 062D;;;;N;;;;; FD5A;ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 062D 0645 064A;;;;N;;;;; FD5B;ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062D 0645 0649;;;;N;;;;; FD5C;ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL; 0633 062D 062C;;;;N;;;;; FD5D;ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL; 0633 062C 062D;;;;N;;;;; FD5E;ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0633 062C 0649;;;;N;;;;; FD5F;ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM;Lo;0;AL; 0633 0645 062D;;;;N;;;;; FD60;ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 0633 0645 062D;;;;N;;;;; FD61;ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL; 0633 0645 062C;;;;N;;;;; FD62;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0633 0645 0645;;;;N;;;;; FD63;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0633 0645 0645;;;;N;;;;; FD64;ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM;Lo;0;AL; 0635 062D 062D;;;;N;;;;; FD65;ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM;Lo;0;AL; 0635 062D 062D;;;;N;;;;; FD66;ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0635 0645 0645;;;;N;;;;; FD67;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM;Lo;0;AL; 0634 062D 0645;;;;N;;;;; FD68;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL; 0634 062D 0645;;;;N;;;;; FD69;ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 0634 062C 064A;;;;N;;;;; FD6A;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM;Lo;0;AL; 0634 0645 062E;;;;N;;;;; FD6B;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL; 0634 0645 062E;;;;N;;;;; FD6C;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0634 0645 0645;;;;N;;;;; FD6D;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0634 0645 0645;;;;N;;;;; FD6E;ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0636 062D 0649;;;;N;;;;; FD6F;ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL; 0636 062E 0645;;;;N;;;;; FD70;ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 0636 062E 0645;;;;N;;;;; FD71;ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM;Lo;0;AL; 0637 0645 062D;;;;N;;;;; FD72;ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 0637 0645 062D;;;;N;;;;; FD73;ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0637 0645 0645;;;;N;;;;; FD74;ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0637 0645 064A;;;;N;;;;; FD75;ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL; 0639 062C 0645;;;;N;;;;; FD76;ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0639 0645 0645;;;;N;;;;; FD77;ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0639 0645 0645;;;;N;;;;; FD78;ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0639 0645 0649;;;;N;;;;; FD79;ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 063A 0645 0645;;;;N;;;;; FD7A;ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 063A 0645 064A;;;;N;;;;; FD7B;ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 063A 0645 0649;;;;N;;;;; FD7C;ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL; 0641 062E 0645;;;;N;;;;; FD7D;ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 0641 062E 0645;;;;N;;;;; FD7E;ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM;Lo;0;AL; 0642 0645 062D;;;;N;;;;; FD7F;ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0642 0645 0645;;;;N;;;;; FD80;ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM;Lo;0;AL; 0644 062D 0645;;;;N;;;;; FD81;ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0644 062D 064A;;;;N;;;;; FD82;ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0644 062D 0649;;;;N;;;;; FD83;ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM;Lo;0;AL; 0644 062C 062C;;;;N;;;;; FD84;ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM;Lo;0;AL; 0644 062C 062C;;;;N;;;;; FD85;ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL; 0644 062E 0645;;;;N;;;;; FD86;ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 0644 062E 0645;;;;N;;;;; FD87;ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL; 0644 0645 062D;;;;N;;;;; FD88;ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 0644 0645 062D;;;;N;;;;; FD89;ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL; 0645 062D 062C;;;;N;;;;; FD8A;ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL; 0645 062D 0645;;;;N;;;;; FD8B;ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0645 062D 064A;;;;N;;;;; FD8C;ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL; 0645 062C 062D;;;;N;;;;; FD8D;ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0645 062C 0645;;;;N;;;;; FD8E;ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM;Lo;0;AL; 0645 062E 062C;;;;N;;;;; FD8F;ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 0645 062E 0645;;;;N;;;;; FD92;ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM;Lo;0;AL; 0645 062C 062E;;;;N;;;;; FD93;ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL; 0647 0645 062C;;;;N;;;;; FD94;ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0647 0645 0645;;;;N;;;;; FD95;ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL; 0646 062D 0645;;;;N;;;;; FD96;ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0646 062D 0649;;;;N;;;;; FD97;ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL; 0646 062C 0645;;;;N;;;;; FD98;ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0646 062C 0645;;;;N;;;;; FD99;ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0646 062C 0649;;;;N;;;;; FD9A;ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0646 0645 064A;;;;N;;;;; FD9B;ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0646 0645 0649;;;;N;;;;; FD9C;ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 064A 0645 0645;;;;N;;;;; FD9D;ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 064A 0645 0645;;;;N;;;;; FD9E;ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL; 0628 062E 064A;;;;N;;;;; FD9F;ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 062A 062C 064A;;;;N;;;;; FDA0;ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062A 062C 0649;;;;N;;;;; FDA1;ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL; 062A 062E 064A;;;;N;;;;; FDA2;ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062A 062E 0649;;;;N;;;;; FDA3;ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 062A 0645 064A;;;;N;;;;; FDA4;ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062A 0645 0649;;;;N;;;;; FDA5;ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 062C 0645 064A;;;;N;;;;; FDA6;ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062C 062D 0649;;;;N;;;;; FDA7;ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062C 0645 0649;;;;N;;;;; FDA8;ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0633 062E 0649;;;;N;;;;; FDA9;ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0635 062D 064A;;;;N;;;;; FDAA;ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0634 062D 064A;;;;N;;;;; FDAB;ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0636 062D 064A;;;;N;;;;; FDAC;ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 0644 062C 064A;;;;N;;;;; FDAD;ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0644 0645 064A;;;;N;;;;; FDAE;ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 064A 062D 064A;;;;N;;;;; FDAF;ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 064A 062C 064A;;;;N;;;;; FDB0;ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 064A 0645 064A;;;;N;;;;; FDB1;ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0645 0645 064A;;;;N;;;;; FDB2;ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0642 0645 064A;;;;N;;;;; FDB3;ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0646 062D 064A;;;;N;;;;; FDB4;ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 0642 0645 062D;;;;N;;;;; FDB5;ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL; 0644 062D 0645;;;;N;;;;; FDB6;ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0639 0645 064A;;;;N;;;;; FDB7;ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0643 0645 064A;;;;N;;;;; FDB8;ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL; 0646 062C 062D;;;;N;;;;; FDB9;ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM;Lo;0;AL; 0645 062E 064A;;;;N;;;;; FDBA;ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0644 062C 0645;;;;N;;;;; FDBB;ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0643 0645 0645;;;;N;;;;; FDBC;ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL; 0644 062C 0645;;;;N;;;;; FDBD;ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM;Lo;0;AL; 0646 062C 062D;;;;N;;;;; FDBE;ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 062C 062D 064A;;;;N;;;;; FDBF;ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 062D 062C 064A;;;;N;;;;; FDC0;ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 0645 062C 064A;;;;N;;;;; FDC1;ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0641 0645 064A;;;;N;;;;; FDC2;ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0628 062D 064A;;;;N;;;;; FDC3;ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0643 0645 0645;;;;N;;;;; FDC4;ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0639 062C 0645;;;;N;;;;; FDC5;ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0635 0645 0645;;;;N;;;;; FDC6;ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM;Lo;0;AL; 0633 062E 064A;;;;N;;;;; FDC7;ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 0646 062C 064A;;;;N;;;;; FDF0;ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL; 0635 0644 06D2;;;;N;;;;; FDF1;ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL; 0642 0644 06D2;;;;N;;;;; FDF2;ARABIC LIGATURE ALLAH ISOLATED FORM;Lo;0;AL; 0627 0644 0644 0647;;;;N;;;;; FDF3;ARABIC LIGATURE AKBAR ISOLATED FORM;Lo;0;AL; 0627 0643 0628 0631;;;;N;;;;; FDF4;ARABIC LIGATURE MOHAMMAD ISOLATED FORM;Lo;0;AL; 0645 062D 0645 062F;;;;N;;;;; FDF5;ARABIC LIGATURE SALAM ISOLATED FORM;Lo;0;AL; 0635 0644 0639 0645;;;;N;;;;; FDF6;ARABIC LIGATURE RASOUL ISOLATED FORM;Lo;0;AL; 0631 0633 0648 0644;;;;N;;;;; FDF7;ARABIC LIGATURE ALAYHE ISOLATED FORM;Lo;0;AL; 0639 0644 064A 0647;;;;N;;;;; FDF8;ARABIC LIGATURE WASALLAM ISOLATED FORM;Lo;0;AL; 0648 0633 0644 0645;;;;N;;;;; FDF9;ARABIC LIGATURE SALLA ISOLATED FORM;Lo;0;AL; 0635 0644 0649;;;;N;;;;; FDFA;ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM;Lo;0;AL; 0635 0644 0649 0020 0627 0644 0644 0647 0020 0639 0644 064A 0647 0020 0648 0633 0644 0645;;;;N;ARABIC LETTER SALLALLAHOU ALAYHE WASALLAM;;;; FDFB;ARABIC LIGATURE JALLAJALALOUHOU;Lo;0;AL; 062C 0644 0020 062C 0644 0627 0644 0647;;;;N;ARABIC LETTER JALLAJALALOUHOU;;;; FDFC;RIAL SIGN;Sc;0;AL; 0631 06CC 0627 0644;;;;N;;;;; FE00;VARIATION SELECTOR-1;Mn;0;NSM;;;;;N;;;;; FE01;VARIATION SELECTOR-2;Mn;0;NSM;;;;;N;;;;; FE02;VARIATION SELECTOR-3;Mn;0;NSM;;;;;N;;;;; FE03;VARIATION SELECTOR-4;Mn;0;NSM;;;;;N;;;;; FE04;VARIATION SELECTOR-5;Mn;0;NSM;;;;;N;;;;; FE05;VARIATION SELECTOR-6;Mn;0;NSM;;;;;N;;;;; FE06;VARIATION SELECTOR-7;Mn;0;NSM;;;;;N;;;;; FE07;VARIATION SELECTOR-8;Mn;0;NSM;;;;;N;;;;; FE08;VARIATION SELECTOR-9;Mn;0;NSM;;;;;N;;;;; FE09;VARIATION SELECTOR-10;Mn;0;NSM;;;;;N;;;;; FE0A;VARIATION SELECTOR-11;Mn;0;NSM;;;;;N;;;;; FE0B;VARIATION SELECTOR-12;Mn;0;NSM;;;;;N;;;;; FE0C;VARIATION SELECTOR-13;Mn;0;NSM;;;;;N;;;;; FE0D;VARIATION SELECTOR-14;Mn;0;NSM;;;;;N;;;;; FE0E;VARIATION SELECTOR-15;Mn;0;NSM;;;;;N;;;;; FE0F;VARIATION SELECTOR-16;Mn;0;NSM;;;;;N;;;;; FE20;COMBINING LIGATURE LEFT HALF;Mn;230;NSM;;;;;N;;;;; FE21;COMBINING LIGATURE RIGHT HALF;Mn;230;NSM;;;;;N;;;;; FE22;COMBINING DOUBLE TILDE LEFT HALF;Mn;230;NSM;;;;;N;;;;; FE23;COMBINING DOUBLE TILDE RIGHT HALF;Mn;230;NSM;;;;;N;;;;; FE30;PRESENTATION FORM FOR VERTICAL TWO DOT LEADER;Po;0;ON; 2025;;;;N;GLYPH FOR VERTICAL TWO DOT LEADER;;;; FE31;PRESENTATION FORM FOR VERTICAL EM DASH;Pd;0;ON; 2014;;;;N;GLYPH FOR VERTICAL EM DASH;;;; FE32;PRESENTATION FORM FOR VERTICAL EN DASH;Pd;0;ON; 2013;;;;N;GLYPH FOR VERTICAL EN DASH;;;; FE33;PRESENTATION FORM FOR VERTICAL LOW LINE;Pc;0;ON; 005F;;;;N;GLYPH FOR VERTICAL SPACING UNDERSCORE;;;; FE34;PRESENTATION FORM FOR VERTICAL WAVY LOW LINE;Pc;0;ON; 005F;;;;N;GLYPH FOR VERTICAL SPACING WAVY UNDERSCORE;;;; FE35;PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS;Ps;0;ON; 0028;;;;N;GLYPH FOR VERTICAL OPENING PARENTHESIS;;;; FE36;PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS;Pe;0;ON; 0029;;;;N;GLYPH FOR VERTICAL CLOSING PARENTHESIS;;;; FE37;PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET;Ps;0;ON; 007B;;;;N;GLYPH FOR VERTICAL OPENING CURLY BRACKET;;;; FE38;PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET;Pe;0;ON; 007D;;;;N;GLYPH FOR VERTICAL CLOSING CURLY BRACKET;;;; FE39;PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET;Ps;0;ON; 3014;;;;N;GLYPH FOR VERTICAL OPENING TORTOISE SHELL BRACKET;;;; FE3A;PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON; 3015;;;;N;GLYPH FOR VERTICAL CLOSING TORTOISE SHELL BRACKET;;;; FE3B;PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET;Ps;0;ON; 3010;;;;N;GLYPH FOR VERTICAL OPENING BLACK LENTICULAR BRACKET;;;; FE3C;PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON; 3011;;;;N;GLYPH FOR VERTICAL CLOSING BLACK LENTICULAR BRACKET;;;; FE3D;PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON; 300A;;;;N;GLYPH FOR VERTICAL OPENING DOUBLE ANGLE BRACKET;;;; FE3E;PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON; 300B;;;;N;GLYPH FOR VERTICAL CLOSING DOUBLE ANGLE BRACKET;;;; FE3F;PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET;Ps;0;ON; 3008;;;;N;GLYPH FOR VERTICAL OPENING ANGLE BRACKET;;;; FE40;PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET;Pe;0;ON; 3009;;;;N;GLYPH FOR VERTICAL CLOSING ANGLE BRACKET;;;; FE41;PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET;Ps;0;ON; 300C;;;;N;GLYPH FOR VERTICAL OPENING CORNER BRACKET;;;; FE42;PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET;Pe;0;ON; 300D;;;;N;GLYPH FOR VERTICAL CLOSING CORNER BRACKET;;;; FE43;PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET;Ps;0;ON; 300E;;;;N;GLYPH FOR VERTICAL OPENING WHITE CORNER BRACKET;;;; FE44;PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET;Pe;0;ON; 300F;;;;N;GLYPH FOR VERTICAL CLOSING WHITE CORNER BRACKET;;;; FE45;SESAME DOT;Po;0;ON;;;;;N;;;;; FE46;WHITE SESAME DOT;Po;0;ON;;;;;N;;;;; FE49;DASHED OVERLINE;Po;0;ON; 203E;;;;N;SPACING DASHED OVERSCORE;;;; FE4A;CENTRELINE OVERLINE;Po;0;ON; 203E;;;;N;SPACING CENTERLINE OVERSCORE;;;; FE4B;WAVY OVERLINE;Po;0;ON; 203E;;;;N;SPACING WAVY OVERSCORE;;;; FE4C;DOUBLE WAVY OVERLINE;Po;0;ON; 203E;;;;N;SPACING DOUBLE WAVY OVERSCORE;;;; FE4D;DASHED LOW LINE;Pc;0;ON; 005F;;;;N;SPACING DASHED UNDERSCORE;;;; FE4E;CENTRELINE LOW LINE;Pc;0;ON; 005F;;;;N;SPACING CENTERLINE UNDERSCORE;;;; FE4F;WAVY LOW LINE;Pc;0;ON; 005F;;;;N;SPACING WAVY UNDERSCORE;;;; FE50;SMALL COMMA;Po;0;CS; 002C;;;;N;;;;; FE51;SMALL IDEOGRAPHIC COMMA;Po;0;ON; 3001;;;;N;;;;; FE52;SMALL FULL STOP;Po;0;CS; 002E;;;;N;SMALL PERIOD;;;; FE54;SMALL SEMICOLON;Po;0;ON; 003B;;;;N;;;;; FE55;SMALL COLON;Po;0;CS; 003A;;;;N;;;;; FE56;SMALL QUESTION MARK;Po;0;ON; 003F;;;;N;;;;; FE57;SMALL EXCLAMATION MARK;Po;0;ON; 0021;;;;N;;;;; FE58;SMALL EM DASH;Pd;0;ON; 2014;;;;N;;;;; FE59;SMALL LEFT PARENTHESIS;Ps;0;ON; 0028;;;;N;SMALL OPENING PARENTHESIS;;;; FE5A;SMALL RIGHT PARENTHESIS;Pe;0;ON; 0029;;;;N;SMALL CLOSING PARENTHESIS;;;; FE5B;SMALL LEFT CURLY BRACKET;Ps;0;ON; 007B;;;;N;SMALL OPENING CURLY BRACKET;;;; FE5C;SMALL RIGHT CURLY BRACKET;Pe;0;ON; 007D;;;;N;SMALL CLOSING CURLY BRACKET;;;; FE5D;SMALL LEFT TORTOISE SHELL BRACKET;Ps;0;ON; 3014;;;;N;SMALL OPENING TORTOISE SHELL BRACKET;;;; FE5E;SMALL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON; 3015;;;;N;SMALL CLOSING TORTOISE SHELL BRACKET;;;; FE5F;SMALL NUMBER SIGN;Po;0;ET; 0023;;;;N;;;;; FE60;SMALL AMPERSAND;Po;0;ON; 0026;;;;N;;;;; FE61;SMALL ASTERISK;Po;0;ON; 002A;;;;N;;;;; FE62;SMALL PLUS SIGN;Sm;0;ET; 002B;;;;N;;;;; FE63;SMALL HYPHEN-MINUS;Pd;0;ET; 002D;;;;N;;;;; FE64;SMALL LESS-THAN SIGN;Sm;0;ON; 003C;;;;N;;;;; FE65;SMALL GREATER-THAN SIGN;Sm;0;ON; 003E;;;;N;;;;; FE66;SMALL EQUALS SIGN;Sm;0;ON; 003D;;;;N;;;;; FE68;SMALL REVERSE SOLIDUS;Po;0;ON; 005C;;;;N;SMALL BACKSLASH;;;; FE69;SMALL DOLLAR SIGN;Sc;0;ET; 0024;;;;N;;;;; FE6A;SMALL PERCENT SIGN;Po;0;ET; 0025;;;;N;;;;; FE6B;SMALL COMMERCIAL AT;Po;0;ON; 0040;;;;N;;;;; FE70;ARABIC FATHATAN ISOLATED FORM;Lo;0;AL; 0020 064B;;;;N;ARABIC SPACING FATHATAN;;;; FE71;ARABIC TATWEEL WITH FATHATAN ABOVE;Lo;0;AL; 0640 064B;;;;N;ARABIC FATHATAN ON TATWEEL;;;; FE72;ARABIC DAMMATAN ISOLATED FORM;Lo;0;AL; 0020 064C;;;;N;ARABIC SPACING DAMMATAN;;;; FE73;ARABIC TAIL FRAGMENT;Lo;0;AL;;;;;N;;;;; FE74;ARABIC KASRATAN ISOLATED FORM;Lo;0;AL; 0020 064D;;;;N;ARABIC SPACING KASRATAN;;;; FE76;ARABIC FATHA ISOLATED FORM;Lo;0;AL; 0020 064E;;;;N;ARABIC SPACING FATHAH;;;; FE77;ARABIC FATHA MEDIAL FORM;Lo;0;AL; 0640 064E;;;;N;ARABIC FATHAH ON TATWEEL;;;; FE78;ARABIC DAMMA ISOLATED FORM;Lo;0;AL; 0020 064F;;;;N;ARABIC SPACING DAMMAH;;;; FE79;ARABIC DAMMA MEDIAL FORM;Lo;0;AL; 0640 064F;;;;N;ARABIC DAMMAH ON TATWEEL;;;; FE7A;ARABIC KASRA ISOLATED FORM;Lo;0;AL; 0020 0650;;;;N;ARABIC SPACING KASRAH;;;; FE7B;ARABIC KASRA MEDIAL FORM;Lo;0;AL; 0640 0650;;;;N;ARABIC KASRAH ON TATWEEL;;;; FE7C;ARABIC SHADDA ISOLATED FORM;Lo;0;AL; 0020 0651;;;;N;ARABIC SPACING SHADDAH;;;; FE7D;ARABIC SHADDA MEDIAL FORM;Lo;0;AL; 0640 0651;;;;N;ARABIC SHADDAH ON TATWEEL;;;; FE7E;ARABIC SUKUN ISOLATED FORM;Lo;0;AL; 0020 0652;;;;N;ARABIC SPACING SUKUN;;;; FE7F;ARABIC SUKUN MEDIAL FORM;Lo;0;AL; 0640 0652;;;;N;ARABIC SUKUN ON TATWEEL;;;; FE80;ARABIC LETTER HAMZA ISOLATED FORM;Lo;0;AL; 0621;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH;;;; FE81;ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL; 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON ALEF;;;; FE82;ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL; 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON ALEF;;;; FE83;ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON ALEF;;;; FE84;ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL; 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON ALEF;;;; FE85;ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 0624;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON WAW;;;; FE86;ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM;Lo;0;AL; 0624;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON WAW;;;; FE87;ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL; 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER ALEF;;;; FE88;ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL; 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER ALEF;;;; FE89;ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 0626;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON YA;;;; FE8A;ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM;Lo;0;AL; 0626;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON YA;;;; FE8B;ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM;Lo;0;AL; 0626;;;;N;GLYPH FOR INITIAL ARABIC HAMZAH ON YA;;;; FE8C;ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM;Lo;0;AL; 0626;;;;N;GLYPH FOR MEDIAL ARABIC HAMZAH ON YA;;;; FE8D;ARABIC LETTER ALEF ISOLATED FORM;Lo;0;AL; 0627;;;;N;GLYPH FOR ISOLATE ARABIC ALEF;;;; FE8E;ARABIC LETTER ALEF FINAL FORM;Lo;0;AL; 0627;;;;N;GLYPH FOR FINAL ARABIC ALEF;;;; FE8F;ARABIC LETTER BEH ISOLATED FORM;Lo;0;AL; 0628;;;;N;GLYPH FOR ISOLATE ARABIC BAA;;;; FE90;ARABIC LETTER BEH FINAL FORM;Lo;0;AL; 0628;;;;N;GLYPH FOR FINAL ARABIC BAA;;;; FE91;ARABIC LETTER BEH INITIAL FORM;Lo;0;AL; 0628;;;;N;GLYPH FOR INITIAL ARABIC BAA;;;; FE92;ARABIC LETTER BEH MEDIAL FORM;Lo;0;AL; 0628;;;;N;GLYPH FOR MEDIAL ARABIC BAA;;;; FE93;ARABIC LETTER TEH MARBUTA ISOLATED FORM;Lo;0;AL; 0629;;;;N;GLYPH FOR ISOLATE ARABIC TAA MARBUTAH;;;; FE94;ARABIC LETTER TEH MARBUTA FINAL FORM;Lo;0;AL; 0629;;;;N;GLYPH FOR FINAL ARABIC TAA MARBUTAH;;;; FE95;ARABIC LETTER TEH ISOLATED FORM;Lo;0;AL; 062A;;;;N;GLYPH FOR ISOLATE ARABIC TAA;;;; FE96;ARABIC LETTER TEH FINAL FORM;Lo;0;AL; 062A;;;;N;GLYPH FOR FINAL ARABIC TAA;;;; FE97;ARABIC LETTER TEH INITIAL FORM;Lo;0;AL; 062A;;;;N;GLYPH FOR INITIAL ARABIC TAA;;;; FE98;ARABIC LETTER TEH MEDIAL FORM;Lo;0;AL; 062A;;;;N;GLYPH FOR MEDIAL ARABIC TAA;;;; FE99;ARABIC LETTER THEH ISOLATED FORM;Lo;0;AL; 062B;;;;N;GLYPH FOR ISOLATE ARABIC THAA;;;; FE9A;ARABIC LETTER THEH FINAL FORM;Lo;0;AL; 062B;;;;N;GLYPH FOR FINAL ARABIC THAA;;;; FE9B;ARABIC LETTER THEH INITIAL FORM;Lo;0;AL; 062B;;;;N;GLYPH FOR INITIAL ARABIC THAA;;;; FE9C;ARABIC LETTER THEH MEDIAL FORM;Lo;0;AL; 062B;;;;N;GLYPH FOR MEDIAL ARABIC THAA;;;; FE9D;ARABIC LETTER JEEM ISOLATED FORM;Lo;0;AL; 062C;;;;N;GLYPH FOR ISOLATE ARABIC JEEM;;;; FE9E;ARABIC LETTER JEEM FINAL FORM;Lo;0;AL; 062C;;;;N;GLYPH FOR FINAL ARABIC JEEM;;;; FE9F;ARABIC LETTER JEEM INITIAL FORM;Lo;0;AL; 062C;;;;N;GLYPH FOR INITIAL ARABIC JEEM;;;; FEA0;ARABIC LETTER JEEM MEDIAL FORM;Lo;0;AL; 062C;;;;N;GLYPH FOR MEDIAL ARABIC JEEM;;;; FEA1;ARABIC LETTER HAH ISOLATED FORM;Lo;0;AL; 062D;;;;N;GLYPH FOR ISOLATE ARABIC HAA;;;; FEA2;ARABIC LETTER HAH FINAL FORM;Lo;0;AL; 062D;;;;N;GLYPH FOR FINAL ARABIC HAA;;;; FEA3;ARABIC LETTER HAH INITIAL FORM;Lo;0;AL; 062D;;;;N;GLYPH FOR INITIAL ARABIC HAA;;;; FEA4;ARABIC LETTER HAH MEDIAL FORM;Lo;0;AL; 062D;;;;N;GLYPH FOR MEDIAL ARABIC HAA;;;; FEA5;ARABIC LETTER KHAH ISOLATED FORM;Lo;0;AL; 062E;;;;N;GLYPH FOR ISOLATE ARABIC KHAA;;;; FEA6;ARABIC LETTER KHAH FINAL FORM;Lo;0;AL; 062E;;;;N;GLYPH FOR FINAL ARABIC KHAA;;;; FEA7;ARABIC LETTER KHAH INITIAL FORM;Lo;0;AL; 062E;;;;N;GLYPH FOR INITIAL ARABIC KHAA;;;; FEA8;ARABIC LETTER KHAH MEDIAL FORM;Lo;0;AL; 062E;;;;N;GLYPH FOR MEDIAL ARABIC KHAA;;;; FEA9;ARABIC LETTER DAL ISOLATED FORM;Lo;0;AL; 062F;;;;N;GLYPH FOR ISOLATE ARABIC DAL;;;; FEAA;ARABIC LETTER DAL FINAL FORM;Lo;0;AL; 062F;;;;N;GLYPH FOR FINAL ARABIC DAL;;;; FEAB;ARABIC LETTER THAL ISOLATED FORM;Lo;0;AL; 0630;;;;N;GLYPH FOR ISOLATE ARABIC THAL;;;; FEAC;ARABIC LETTER THAL FINAL FORM;Lo;0;AL; 0630;;;;N;GLYPH FOR FINAL ARABIC THAL;;;; FEAD;ARABIC LETTER REH ISOLATED FORM;Lo;0;AL; 0631;;;;N;GLYPH FOR ISOLATE ARABIC RA;;;; FEAE;ARABIC LETTER REH FINAL FORM;Lo;0;AL; 0631;;;;N;GLYPH FOR FINAL ARABIC RA;;;; FEAF;ARABIC LETTER ZAIN ISOLATED FORM;Lo;0;AL; 0632;;;;N;GLYPH FOR ISOLATE ARABIC ZAIN;;;; FEB0;ARABIC LETTER ZAIN FINAL FORM;Lo;0;AL; 0632;;;;N;GLYPH FOR FINAL ARABIC ZAIN;;;; FEB1;ARABIC LETTER SEEN ISOLATED FORM;Lo;0;AL; 0633;;;;N;GLYPH FOR ISOLATE ARABIC SEEN;;;; FEB2;ARABIC LETTER SEEN FINAL FORM;Lo;0;AL; 0633;;;;N;GLYPH FOR FINAL ARABIC SEEN;;;; FEB3;ARABIC LETTER SEEN INITIAL FORM;Lo;0;AL; 0633;;;;N;GLYPH FOR INITIAL ARABIC SEEN;;;; FEB4;ARABIC LETTER SEEN MEDIAL FORM;Lo;0;AL; 0633;;;;N;GLYPH FOR MEDIAL ARABIC SEEN;;;; FEB5;ARABIC LETTER SHEEN ISOLATED FORM;Lo;0;AL; 0634;;;;N;GLYPH FOR ISOLATE ARABIC SHEEN;;;; FEB6;ARABIC LETTER SHEEN FINAL FORM;Lo;0;AL; 0634;;;;N;GLYPH FOR FINAL ARABIC SHEEN;;;; FEB7;ARABIC LETTER SHEEN INITIAL FORM;Lo;0;AL; 0634;;;;N;GLYPH FOR INITIAL ARABIC SHEEN;;;; FEB8;ARABIC LETTER SHEEN MEDIAL FORM;Lo;0;AL; 0634;;;;N;GLYPH FOR MEDIAL ARABIC SHEEN;;;; FEB9;ARABIC LETTER SAD ISOLATED FORM;Lo;0;AL; 0635;;;;N;GLYPH FOR ISOLATE ARABIC SAD;;;; FEBA;ARABIC LETTER SAD FINAL FORM;Lo;0;AL; 0635;;;;N;GLYPH FOR FINAL ARABIC SAD;;;; FEBB;ARABIC LETTER SAD INITIAL FORM;Lo;0;AL; 0635;;;;N;GLYPH FOR INITIAL ARABIC SAD;;;; FEBC;ARABIC LETTER SAD MEDIAL FORM;Lo;0;AL; 0635;;;;N;GLYPH FOR MEDIAL ARABIC SAD;;;; FEBD;ARABIC LETTER DAD ISOLATED FORM;Lo;0;AL; 0636;;;;N;GLYPH FOR ISOLATE ARABIC DAD;;;; FEBE;ARABIC LETTER DAD FINAL FORM;Lo;0;AL; 0636;;;;N;GLYPH FOR FINAL ARABIC DAD;;;; FEBF;ARABIC LETTER DAD INITIAL FORM;Lo;0;AL; 0636;;;;N;GLYPH FOR INITIAL ARABIC DAD;;;; FEC0;ARABIC LETTER DAD MEDIAL FORM;Lo;0;AL; 0636;;;;N;GLYPH FOR MEDIAL ARABIC DAD;;;; FEC1;ARABIC LETTER TAH ISOLATED FORM;Lo;0;AL; 0637;;;;N;GLYPH FOR ISOLATE ARABIC TAH;;;; FEC2;ARABIC LETTER TAH FINAL FORM;Lo;0;AL; 0637;;;;N;GLYPH FOR FINAL ARABIC TAH;;;; FEC3;ARABIC LETTER TAH INITIAL FORM;Lo;0;AL; 0637;;;;N;GLYPH FOR INITIAL ARABIC TAH;;;; FEC4;ARABIC LETTER TAH MEDIAL FORM;Lo;0;AL; 0637;;;;N;GLYPH FOR MEDIAL ARABIC TAH;;;; FEC5;ARABIC LETTER ZAH ISOLATED FORM;Lo;0;AL; 0638;;;;N;GLYPH FOR ISOLATE ARABIC DHAH;;;; FEC6;ARABIC LETTER ZAH FINAL FORM;Lo;0;AL; 0638;;;;N;GLYPH FOR FINAL ARABIC DHAH;;;; FEC7;ARABIC LETTER ZAH INITIAL FORM;Lo;0;AL; 0638;;;;N;GLYPH FOR INITIAL ARABIC DHAH;;;; FEC8;ARABIC LETTER ZAH MEDIAL FORM;Lo;0;AL; 0638;;;;N;GLYPH FOR MEDIAL ARABIC DHAH;;;; FEC9;ARABIC LETTER AIN ISOLATED FORM;Lo;0;AL; 0639;;;;N;GLYPH FOR ISOLATE ARABIC AIN;;;; FECA;ARABIC LETTER AIN FINAL FORM;Lo;0;AL; 0639;;;;N;GLYPH FOR FINAL ARABIC AIN;;;; FECB;ARABIC LETTER AIN INITIAL FORM;Lo;0;AL; 0639;;;;N;GLYPH FOR INITIAL ARABIC AIN;;;; FECC;ARABIC LETTER AIN MEDIAL FORM;Lo;0;AL; 0639;;;;N;GLYPH FOR MEDIAL ARABIC AIN;;;; FECD;ARABIC LETTER GHAIN ISOLATED FORM;Lo;0;AL; 063A;;;;N;GLYPH FOR ISOLATE ARABIC GHAIN;;;; FECE;ARABIC LETTER GHAIN FINAL FORM;Lo;0;AL; 063A;;;;N;GLYPH FOR FINAL ARABIC GHAIN;;;; FECF;ARABIC LETTER GHAIN INITIAL FORM;Lo;0;AL; 063A;;;;N;GLYPH FOR INITIAL ARABIC GHAIN;;;; FED0;ARABIC LETTER GHAIN MEDIAL FORM;Lo;0;AL; 063A;;;;N;GLYPH FOR MEDIAL ARABIC GHAIN;;;; FED1;ARABIC LETTER FEH ISOLATED FORM;Lo;0;AL; 0641;;;;N;GLYPH FOR ISOLATE ARABIC FA;;;; FED2;ARABIC LETTER FEH FINAL FORM;Lo;0;AL; 0641;;;;N;GLYPH FOR FINAL ARABIC FA;;;; FED3;ARABIC LETTER FEH INITIAL FORM;Lo;0;AL; 0641;;;;N;GLYPH FOR INITIAL ARABIC FA;;;; FED4;ARABIC LETTER FEH MEDIAL FORM;Lo;0;AL; 0641;;;;N;GLYPH FOR MEDIAL ARABIC FA;;;; FED5;ARABIC LETTER QAF ISOLATED FORM;Lo;0;AL; 0642;;;;N;GLYPH FOR ISOLATE ARABIC QAF;;;; FED6;ARABIC LETTER QAF FINAL FORM;Lo;0;AL; 0642;;;;N;GLYPH FOR FINAL ARABIC QAF;;;; FED7;ARABIC LETTER QAF INITIAL FORM;Lo;0;AL; 0642;;;;N;GLYPH FOR INITIAL ARABIC QAF;;;; FED8;ARABIC LETTER QAF MEDIAL FORM;Lo;0;AL; 0642;;;;N;GLYPH FOR MEDIAL ARABIC QAF;;;; FED9;ARABIC LETTER KAF ISOLATED FORM;Lo;0;AL; 0643;;;;N;GLYPH FOR ISOLATE ARABIC CAF;;;; FEDA;ARABIC LETTER KAF FINAL FORM;Lo;0;AL; 0643;;;;N;GLYPH FOR FINAL ARABIC CAF;;;; FEDB;ARABIC LETTER KAF INITIAL FORM;Lo;0;AL; 0643;;;;N;GLYPH FOR INITIAL ARABIC CAF;;;; FEDC;ARABIC LETTER KAF MEDIAL FORM;Lo;0;AL; 0643;;;;N;GLYPH FOR MEDIAL ARABIC CAF;;;; FEDD;ARABIC LETTER LAM ISOLATED FORM;Lo;0;AL; 0644;;;;N;GLYPH FOR ISOLATE ARABIC LAM;;;; FEDE;ARABIC LETTER LAM FINAL FORM;Lo;0;AL; 0644;;;;N;GLYPH FOR FINAL ARABIC LAM;;;; FEDF;ARABIC LETTER LAM INITIAL FORM;Lo;0;AL; 0644;;;;N;GLYPH FOR INITIAL ARABIC LAM;;;; FEE0;ARABIC LETTER LAM MEDIAL FORM;Lo;0;AL; 0644;;;;N;GLYPH FOR MEDIAL ARABIC LAM;;;; FEE1;ARABIC LETTER MEEM ISOLATED FORM;Lo;0;AL; 0645;;;;N;GLYPH FOR ISOLATE ARABIC MEEM;;;; FEE2;ARABIC LETTER MEEM FINAL FORM;Lo;0;AL; 0645;;;;N;GLYPH FOR FINAL ARABIC MEEM;;;; FEE3;ARABIC LETTER MEEM INITIAL FORM;Lo;0;AL; 0645;;;;N;GLYPH FOR INITIAL ARABIC MEEM;;;; FEE4;ARABIC LETTER MEEM MEDIAL FORM;Lo;0;AL; 0645;;;;N;GLYPH FOR MEDIAL ARABIC MEEM;;;; FEE5;ARABIC LETTER NOON ISOLATED FORM;Lo;0;AL; 0646;;;;N;GLYPH FOR ISOLATE ARABIC NOON;;;; FEE6;ARABIC LETTER NOON FINAL FORM;Lo;0;AL; 0646;;;;N;GLYPH FOR FINAL ARABIC NOON;;;; FEE7;ARABIC LETTER NOON INITIAL FORM;Lo;0;AL; 0646;;;;N;GLYPH FOR INITIAL ARABIC NOON;;;; FEE8;ARABIC LETTER NOON MEDIAL FORM;Lo;0;AL; 0646;;;;N;GLYPH FOR MEDIAL ARABIC NOON;;;; FEE9;ARABIC LETTER HEH ISOLATED FORM;Lo;0;AL; 0647;;;;N;GLYPH FOR ISOLATE ARABIC HA;;;; FEEA;ARABIC LETTER HEH FINAL FORM;Lo;0;AL; 0647;;;;N;GLYPH FOR FINAL ARABIC HA;;;; FEEB;ARABIC LETTER HEH INITIAL FORM;Lo;0;AL; 0647;;;;N;GLYPH FOR INITIAL ARABIC HA;;;; FEEC;ARABIC LETTER HEH MEDIAL FORM;Lo;0;AL; 0647;;;;N;GLYPH FOR MEDIAL ARABIC HA;;;; FEED;ARABIC LETTER WAW ISOLATED FORM;Lo;0;AL; 0648;;;;N;GLYPH FOR ISOLATE ARABIC WAW;;;; FEEE;ARABIC LETTER WAW FINAL FORM;Lo;0;AL; 0648;;;;N;GLYPH FOR FINAL ARABIC WAW;;;; FEEF;ARABIC LETTER ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0649;;;;N;GLYPH FOR ISOLATE ARABIC ALEF MAQSURAH;;;; FEF0;ARABIC LETTER ALEF MAKSURA FINAL FORM;Lo;0;AL; 0649;;;;N;GLYPH FOR FINAL ARABIC ALEF MAQSURAH;;;; FEF1;ARABIC LETTER YEH ISOLATED FORM;Lo;0;AL; 064A;;;;N;GLYPH FOR ISOLATE ARABIC YA;;;; FEF2;ARABIC LETTER YEH FINAL FORM;Lo;0;AL; 064A;;;;N;GLYPH FOR FINAL ARABIC YA;;;; FEF3;ARABIC LETTER YEH INITIAL FORM;Lo;0;AL; 064A;;;;N;GLYPH FOR INITIAL ARABIC YA;;;; FEF4;ARABIC LETTER YEH MEDIAL FORM;Lo;0;AL; 064A;;;;N;GLYPH FOR MEDIAL ARABIC YA;;;; FEF5;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL; 0644 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON LIGATURE LAM ALEF;;;; FEF6;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL; 0644 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON LIGATURE LAM ALEF;;;; FEF7;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 0644 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON LIGATURE LAM ALEF;;;; FEF8;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL; 0644 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON LIGATURE LAM ALEF;;;; FEF9;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL; 0644 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;; FEFA;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL; 0644 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;; FEFB;ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM;Lo;0;AL; 0644 0627;;;;N;GLYPH FOR ISOLATE ARABIC LIGATURE LAM ALEF;;;; FEFC;ARABIC LIGATURE LAM WITH ALEF FINAL FORM;Lo;0;AL; 0644 0627;;;;N;GLYPH FOR FINAL ARABIC LIGATURE LAM ALEF;;;; FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; FF01;FULLWIDTH EXCLAMATION MARK;Po;0;ON; 0021;;;;N;;;;; FF02;FULLWIDTH QUOTATION MARK;Po;0;ON; 0022;;;;N;;;;; FF03;FULLWIDTH NUMBER SIGN;Po;0;ET; 0023;;;;N;;;;; FF04;FULLWIDTH DOLLAR SIGN;Sc;0;ET; 0024;;;;N;;;;; FF05;FULLWIDTH PERCENT SIGN;Po;0;ET; 0025;;;;N;;;;; FF06;FULLWIDTH AMPERSAND;Po;0;ON; 0026;;;;N;;;;; FF07;FULLWIDTH APOSTROPHE;Po;0;ON; 0027;;;;N;;;;; FF08;FULLWIDTH LEFT PARENTHESIS;Ps;0;ON; 0028;;;;Y;FULLWIDTH OPENING PARENTHESIS;;;; FF09;FULLWIDTH RIGHT PARENTHESIS;Pe;0;ON; 0029;;;;Y;FULLWIDTH CLOSING PARENTHESIS;;;; FF0A;FULLWIDTH ASTERISK;Po;0;ON; 002A;;;;N;;;;; FF0B;FULLWIDTH PLUS SIGN;Sm;0;ET; 002B;;;;N;;;;; FF0C;FULLWIDTH COMMA;Po;0;CS; 002C;;;;N;;;;; FF0D;FULLWIDTH HYPHEN-MINUS;Pd;0;ET; 002D;;;;N;;;;; FF0E;FULLWIDTH FULL STOP;Po;0;CS; 002E;;;;N;FULLWIDTH PERIOD;;;; FF0F;FULLWIDTH SOLIDUS;Po;0;ES; 002F;;;;N;FULLWIDTH SLASH;;;; FF10;FULLWIDTH DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; FF11;FULLWIDTH DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; FF12;FULLWIDTH DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; FF13;FULLWIDTH DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; FF14;FULLWIDTH DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; FF15;FULLWIDTH DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; FF16;FULLWIDTH DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; FF17;FULLWIDTH DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; FF18;FULLWIDTH DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; FF19;FULLWIDTH DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; FF1A;FULLWIDTH COLON;Po;0;CS; 003A;;;;N;;;;; FF1B;FULLWIDTH SEMICOLON;Po;0;ON; 003B;;;;N;;;;; FF1C;FULLWIDTH LESS-THAN SIGN;Sm;0;ON; 003C;;;;Y;;;;; FF1D;FULLWIDTH EQUALS SIGN;Sm;0;ON; 003D;;;;N;;;;; FF1E;FULLWIDTH GREATER-THAN SIGN;Sm;0;ON; 003E;;;;Y;;;;; FF1F;FULLWIDTH QUESTION MARK;Po;0;ON; 003F;;;;N;;;;; FF20;FULLWIDTH COMMERCIAL AT;Po;0;ON; 0040;;;;N;;;;; FF21;FULLWIDTH LATIN CAPITAL LETTER A;Lu;0;L; 0041;;;;N;;;;FF41; FF22;FULLWIDTH LATIN CAPITAL LETTER B;Lu;0;L; 0042;;;;N;;;;FF42; FF23;FULLWIDTH LATIN CAPITAL LETTER C;Lu;0;L; 0043;;;;N;;;;FF43; FF24;FULLWIDTH LATIN CAPITAL LETTER D;Lu;0;L; 0044;;;;N;;;;FF44; FF25;FULLWIDTH LATIN CAPITAL LETTER E;Lu;0;L; 0045;;;;N;;;;FF45; FF26;FULLWIDTH LATIN CAPITAL LETTER F;Lu;0;L; 0046;;;;N;;;;FF46; FF27;FULLWIDTH LATIN CAPITAL LETTER G;Lu;0;L; 0047;;;;N;;;;FF47; FF28;FULLWIDTH LATIN CAPITAL LETTER H;Lu;0;L; 0048;;;;N;;;;FF48; FF29;FULLWIDTH LATIN CAPITAL LETTER I;Lu;0;L; 0049;;;;N;;;;FF49; FF2A;FULLWIDTH LATIN CAPITAL LETTER J;Lu;0;L; 004A;;;;N;;;;FF4A; FF2B;FULLWIDTH LATIN CAPITAL LETTER K;Lu;0;L; 004B;;;;N;;;;FF4B; FF2C;FULLWIDTH LATIN CAPITAL LETTER L;Lu;0;L; 004C;;;;N;;;;FF4C; FF2D;FULLWIDTH LATIN CAPITAL LETTER M;Lu;0;L; 004D;;;;N;;;;FF4D; FF2E;FULLWIDTH LATIN CAPITAL LETTER N;Lu;0;L; 004E;;;;N;;;;FF4E; FF2F;FULLWIDTH LATIN CAPITAL LETTER O;Lu;0;L; 004F;;;;N;;;;FF4F; FF30;FULLWIDTH LATIN CAPITAL LETTER P;Lu;0;L; 0050;;;;N;;;;FF50; FF31;FULLWIDTH LATIN CAPITAL LETTER Q;Lu;0;L; 0051;;;;N;;;;FF51; FF32;FULLWIDTH LATIN CAPITAL LETTER R;Lu;0;L; 0052;;;;N;;;;FF52; FF33;FULLWIDTH LATIN CAPITAL LETTER S;Lu;0;L; 0053;;;;N;;;;FF53; FF34;FULLWIDTH LATIN CAPITAL LETTER T;Lu;0;L; 0054;;;;N;;;;FF54; FF35;FULLWIDTH LATIN CAPITAL LETTER U;Lu;0;L; 0055;;;;N;;;;FF55; FF36;FULLWIDTH LATIN CAPITAL LETTER V;Lu;0;L; 0056;;;;N;;;;FF56; FF37;FULLWIDTH LATIN CAPITAL LETTER W;Lu;0;L; 0057;;;;N;;;;FF57; FF38;FULLWIDTH LATIN CAPITAL LETTER X;Lu;0;L; 0058;;;;N;;;;FF58; FF39;FULLWIDTH LATIN CAPITAL LETTER Y;Lu;0;L; 0059;;;;N;;;;FF59; FF3A;FULLWIDTH LATIN CAPITAL LETTER Z;Lu;0;L; 005A;;;;N;;;;FF5A; FF3B;FULLWIDTH LEFT SQUARE BRACKET;Ps;0;ON; 005B;;;;Y;FULLWIDTH OPENING SQUARE BRACKET;;;; FF3C;FULLWIDTH REVERSE SOLIDUS;Po;0;ON; 005C;;;;N;FULLWIDTH BACKSLASH;;;; FF3D;FULLWIDTH RIGHT SQUARE BRACKET;Pe;0;ON; 005D;;;;Y;FULLWIDTH CLOSING SQUARE BRACKET;;;; FF3E;FULLWIDTH CIRCUMFLEX ACCENT;Sk;0;ON; 005E;;;;N;FULLWIDTH SPACING CIRCUMFLEX;;;; FF3F;FULLWIDTH LOW LINE;Pc;0;ON; 005F;;;;N;FULLWIDTH SPACING UNDERSCORE;;;; FF40;FULLWIDTH GRAVE ACCENT;Sk;0;ON; 0060;;;;N;FULLWIDTH SPACING GRAVE;;;; FF41;FULLWIDTH LATIN SMALL LETTER A;Ll;0;L; 0061;;;;N;;;FF21;;FF21 FF42;FULLWIDTH LATIN SMALL LETTER B;Ll;0;L; 0062;;;;N;;;FF22;;FF22 FF43;FULLWIDTH LATIN SMALL LETTER C;Ll;0;L; 0063;;;;N;;;FF23;;FF23 FF44;FULLWIDTH LATIN SMALL LETTER D;Ll;0;L; 0064;;;;N;;;FF24;;FF24 FF45;FULLWIDTH LATIN SMALL LETTER E;Ll;0;L; 0065;;;;N;;;FF25;;FF25 FF46;FULLWIDTH LATIN SMALL LETTER F;Ll;0;L; 0066;;;;N;;;FF26;;FF26 FF47;FULLWIDTH LATIN SMALL LETTER G;Ll;0;L; 0067;;;;N;;;FF27;;FF27 FF48;FULLWIDTH LATIN SMALL LETTER H;Ll;0;L; 0068;;;;N;;;FF28;;FF28 FF49;FULLWIDTH LATIN SMALL LETTER I;Ll;0;L; 0069;;;;N;;;FF29;;FF29 FF4A;FULLWIDTH LATIN SMALL LETTER J;Ll;0;L; 006A;;;;N;;;FF2A;;FF2A FF4B;FULLWIDTH LATIN SMALL LETTER K;Ll;0;L; 006B;;;;N;;;FF2B;;FF2B FF4C;FULLWIDTH LATIN SMALL LETTER L;Ll;0;L; 006C;;;;N;;;FF2C;;FF2C FF4D;FULLWIDTH LATIN SMALL LETTER M;Ll;0;L; 006D;;;;N;;;FF2D;;FF2D FF4E;FULLWIDTH LATIN SMALL LETTER N;Ll;0;L; 006E;;;;N;;;FF2E;;FF2E FF4F;FULLWIDTH LATIN SMALL LETTER O;Ll;0;L; 006F;;;;N;;;FF2F;;FF2F FF50;FULLWIDTH LATIN SMALL LETTER P;Ll;0;L; 0070;;;;N;;;FF30;;FF30 FF51;FULLWIDTH LATIN SMALL LETTER Q;Ll;0;L; 0071;;;;N;;;FF31;;FF31 FF52;FULLWIDTH LATIN SMALL LETTER R;Ll;0;L; 0072;;;;N;;;FF32;;FF32 FF53;FULLWIDTH LATIN SMALL LETTER S;Ll;0;L; 0073;;;;N;;;FF33;;FF33 FF54;FULLWIDTH LATIN SMALL LETTER T;Ll;0;L; 0074;;;;N;;;FF34;;FF34 FF55;FULLWIDTH LATIN SMALL LETTER U;Ll;0;L; 0075;;;;N;;;FF35;;FF35 FF56;FULLWIDTH LATIN SMALL LETTER V;Ll;0;L; 0076;;;;N;;;FF36;;FF36 FF57;FULLWIDTH LATIN SMALL LETTER W;Ll;0;L; 0077;;;;N;;;FF37;;FF37 FF58;FULLWIDTH LATIN SMALL LETTER X;Ll;0;L; 0078;;;;N;;;FF38;;FF38 FF59;FULLWIDTH LATIN SMALL LETTER Y;Ll;0;L; 0079;;;;N;;;FF39;;FF39 FF5A;FULLWIDTH LATIN SMALL LETTER Z;Ll;0;L; 007A;;;;N;;;FF3A;;FF3A FF5B;FULLWIDTH LEFT CURLY BRACKET;Ps;0;ON; 007B;;;;Y;FULLWIDTH OPENING CURLY BRACKET;;;; FF5C;FULLWIDTH VERTICAL LINE;Sm;0;ON; 007C;;;;N;FULLWIDTH VERTICAL BAR;;;; FF5D;FULLWIDTH RIGHT CURLY BRACKET;Pe;0;ON; 007D;;;;Y;FULLWIDTH CLOSING CURLY BRACKET;;;; FF5E;FULLWIDTH TILDE;Sm;0;ON; 007E;;;;N;FULLWIDTH SPACING TILDE;;;; FF5F;FULLWIDTH LEFT WHITE PARENTHESIS;Ps;0;ON; 2985;;;;Y;;*;;; FF60;FULLWIDTH RIGHT WHITE PARENTHESIS;Pe;0;ON; 2986;;;;Y;;*;;; FF61;HALFWIDTH IDEOGRAPHIC FULL STOP;Po;0;ON; 3002;;;;N;HALFWIDTH IDEOGRAPHIC PERIOD;;;; FF62;HALFWIDTH LEFT CORNER BRACKET;Ps;0;ON; 300C;;;;Y;HALFWIDTH OPENING CORNER BRACKET;;;; FF63;HALFWIDTH RIGHT CORNER BRACKET;Pe;0;ON; 300D;;;;Y;HALFWIDTH CLOSING CORNER BRACKET;;;; FF64;HALFWIDTH IDEOGRAPHIC COMMA;Po;0;ON; 3001;;;;N;;;;; FF65;HALFWIDTH KATAKANA MIDDLE DOT;Pc;0;ON; 30FB;;;;N;;;;; FF66;HALFWIDTH KATAKANA LETTER WO;Lo;0;L; 30F2;;;;N;;;;; FF67;HALFWIDTH KATAKANA LETTER SMALL A;Lo;0;L; 30A1;;;;N;;;;; FF68;HALFWIDTH KATAKANA LETTER SMALL I;Lo;0;L; 30A3;;;;N;;;;; FF69;HALFWIDTH KATAKANA LETTER SMALL U;Lo;0;L; 30A5;;;;N;;;;; FF6A;HALFWIDTH KATAKANA LETTER SMALL E;Lo;0;L; 30A7;;;;N;;;;; FF6B;HALFWIDTH KATAKANA LETTER SMALL O;Lo;0;L; 30A9;;;;N;;;;; FF6C;HALFWIDTH KATAKANA LETTER SMALL YA;Lo;0;L; 30E3;;;;N;;;;; FF6D;HALFWIDTH KATAKANA LETTER SMALL YU;Lo;0;L; 30E5;;;;N;;;;; FF6E;HALFWIDTH KATAKANA LETTER SMALL YO;Lo;0;L; 30E7;;;;N;;;;; FF6F;HALFWIDTH KATAKANA LETTER SMALL TU;Lo;0;L; 30C3;;;;N;;;;; FF70;HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L; 30FC;;;;N;;;;; FF71;HALFWIDTH KATAKANA LETTER A;Lo;0;L; 30A2;;;;N;;;;; FF72;HALFWIDTH KATAKANA LETTER I;Lo;0;L; 30A4;;;;N;;;;; FF73;HALFWIDTH KATAKANA LETTER U;Lo;0;L; 30A6;;;;N;;;;; FF74;HALFWIDTH KATAKANA LETTER E;Lo;0;L; 30A8;;;;N;;;;; FF75;HALFWIDTH KATAKANA LETTER O;Lo;0;L; 30AA;;;;N;;;;; FF76;HALFWIDTH KATAKANA LETTER KA;Lo;0;L; 30AB;;;;N;;;;; FF77;HALFWIDTH KATAKANA LETTER KI;Lo;0;L; 30AD;;;;N;;;;; FF78;HALFWIDTH KATAKANA LETTER KU;Lo;0;L; 30AF;;;;N;;;;; FF79;HALFWIDTH KATAKANA LETTER KE;Lo;0;L; 30B1;;;;N;;;;; FF7A;HALFWIDTH KATAKANA LETTER KO;Lo;0;L; 30B3;;;;N;;;;; FF7B;HALFWIDTH KATAKANA LETTER SA;Lo;0;L; 30B5;;;;N;;;;; FF7C;HALFWIDTH KATAKANA LETTER SI;Lo;0;L; 30B7;;;;N;;;;; FF7D;HALFWIDTH KATAKANA LETTER SU;Lo;0;L; 30B9;;;;N;;;;; FF7E;HALFWIDTH KATAKANA LETTER SE;Lo;0;L; 30BB;;;;N;;;;; FF7F;HALFWIDTH KATAKANA LETTER SO;Lo;0;L; 30BD;;;;N;;;;; FF80;HALFWIDTH KATAKANA LETTER TA;Lo;0;L; 30BF;;;;N;;;;; FF81;HALFWIDTH KATAKANA LETTER TI;Lo;0;L; 30C1;;;;N;;;;; FF82;HALFWIDTH KATAKANA LETTER TU;Lo;0;L; 30C4;;;;N;;;;; FF83;HALFWIDTH KATAKANA LETTER TE;Lo;0;L; 30C6;;;;N;;;;; FF84;HALFWIDTH KATAKANA LETTER TO;Lo;0;L; 30C8;;;;N;;;;; FF85;HALFWIDTH KATAKANA LETTER NA;Lo;0;L; 30CA;;;;N;;;;; FF86;HALFWIDTH KATAKANA LETTER NI;Lo;0;L; 30CB;;;;N;;;;; FF87;HALFWIDTH KATAKANA LETTER NU;Lo;0;L; 30CC;;;;N;;;;; FF88;HALFWIDTH KATAKANA LETTER NE;Lo;0;L; 30CD;;;;N;;;;; FF89;HALFWIDTH KATAKANA LETTER NO;Lo;0;L; 30CE;;;;N;;;;; FF8A;HALFWIDTH KATAKANA LETTER HA;Lo;0;L; 30CF;;;;N;;;;; FF8B;HALFWIDTH KATAKANA LETTER HI;Lo;0;L; 30D2;;;;N;;;;; FF8C;HALFWIDTH KATAKANA LETTER HU;Lo;0;L; 30D5;;;;N;;;;; FF8D;HALFWIDTH KATAKANA LETTER HE;Lo;0;L; 30D8;;;;N;;;;; FF8E;HALFWIDTH KATAKANA LETTER HO;Lo;0;L; 30DB;;;;N;;;;; FF8F;HALFWIDTH KATAKANA LETTER MA;Lo;0;L; 30DE;;;;N;;;;; FF90;HALFWIDTH KATAKANA LETTER MI;Lo;0;L; 30DF;;;;N;;;;; FF91;HALFWIDTH KATAKANA LETTER MU;Lo;0;L; 30E0;;;;N;;;;; FF92;HALFWIDTH KATAKANA LETTER ME;Lo;0;L; 30E1;;;;N;;;;; FF93;HALFWIDTH KATAKANA LETTER MO;Lo;0;L; 30E2;;;;N;;;;; FF94;HALFWIDTH KATAKANA LETTER YA;Lo;0;L; 30E4;;;;N;;;;; FF95;HALFWIDTH KATAKANA LETTER YU;Lo;0;L; 30E6;;;;N;;;;; FF96;HALFWIDTH KATAKANA LETTER YO;Lo;0;L; 30E8;;;;N;;;;; FF97;HALFWIDTH KATAKANA LETTER RA;Lo;0;L; 30E9;;;;N;;;;; FF98;HALFWIDTH KATAKANA LETTER RI;Lo;0;L; 30EA;;;;N;;;;; FF99;HALFWIDTH KATAKANA LETTER RU;Lo;0;L; 30EB;;;;N;;;;; FF9A;HALFWIDTH KATAKANA LETTER RE;Lo;0;L; 30EC;;;;N;;;;; FF9B;HALFWIDTH KATAKANA LETTER RO;Lo;0;L; 30ED;;;;N;;;;; FF9C;HALFWIDTH KATAKANA LETTER WA;Lo;0;L; 30EF;;;;N;;;;; FF9D;HALFWIDTH KATAKANA LETTER N;Lo;0;L; 30F3;;;;N;;;;; FF9E;HALFWIDTH KATAKANA VOICED SOUND MARK;Lm;0;L; 3099;;;;N;;halfwidth katakana-hiragana voiced sound mark;;; FF9F;HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK;Lm;0;L; 309A;;;;N;;halfwidth katakana-hiragana semi-voiced sound mark;;; FFA0;HALFWIDTH HANGUL FILLER;Lo;0;L; 3164;;;;N;HALFWIDTH HANGUL CAE OM;;;; FFA1;HALFWIDTH HANGUL LETTER KIYEOK;Lo;0;L; 3131;;;;N;HALFWIDTH HANGUL LETTER GIYEOG;;;; FFA2;HALFWIDTH HANGUL LETTER SSANGKIYEOK;Lo;0;L; 3132;;;;N;HALFWIDTH HANGUL LETTER SSANG GIYEOG;;;; FFA3;HALFWIDTH HANGUL LETTER KIYEOK-SIOS;Lo;0;L; 3133;;;;N;HALFWIDTH HANGUL LETTER GIYEOG SIOS;;;; FFA4;HALFWIDTH HANGUL LETTER NIEUN;Lo;0;L; 3134;;;;N;;;;; FFA5;HALFWIDTH HANGUL LETTER NIEUN-CIEUC;Lo;0;L; 3135;;;;N;HALFWIDTH HANGUL LETTER NIEUN JIEUJ;;;; FFA6;HALFWIDTH HANGUL LETTER NIEUN-HIEUH;Lo;0;L; 3136;;;;N;HALFWIDTH HANGUL LETTER NIEUN HIEUH;;;; FFA7;HALFWIDTH HANGUL LETTER TIKEUT;Lo;0;L; 3137;;;;N;HALFWIDTH HANGUL LETTER DIGEUD;;;; FFA8;HALFWIDTH HANGUL LETTER SSANGTIKEUT;Lo;0;L; 3138;;;;N;HALFWIDTH HANGUL LETTER SSANG DIGEUD;;;; FFA9;HALFWIDTH HANGUL LETTER RIEUL;Lo;0;L; 3139;;;;N;HALFWIDTH HANGUL LETTER LIEUL;;;; FFAA;HALFWIDTH HANGUL LETTER RIEUL-KIYEOK;Lo;0;L; 313A;;;;N;HALFWIDTH HANGUL LETTER LIEUL GIYEOG;;;; FFAB;HALFWIDTH HANGUL LETTER RIEUL-MIEUM;Lo;0;L; 313B;;;;N;HALFWIDTH HANGUL LETTER LIEUL MIEUM;;;; FFAC;HALFWIDTH HANGUL LETTER RIEUL-PIEUP;Lo;0;L; 313C;;;;N;HALFWIDTH HANGUL LETTER LIEUL BIEUB;;;; FFAD;HALFWIDTH HANGUL LETTER RIEUL-SIOS;Lo;0;L; 313D;;;;N;HALFWIDTH HANGUL LETTER LIEUL SIOS;;;; FFAE;HALFWIDTH HANGUL LETTER RIEUL-THIEUTH;Lo;0;L; 313E;;;;N;HALFWIDTH HANGUL LETTER LIEUL TIEUT;;;; FFAF;HALFWIDTH HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L; 313F;;;;N;HALFWIDTH HANGUL LETTER LIEUL PIEUP;;;; FFB0;HALFWIDTH HANGUL LETTER RIEUL-HIEUH;Lo;0;L; 3140;;;;N;HALFWIDTH HANGUL LETTER LIEUL HIEUH;;;; FFB1;HALFWIDTH HANGUL LETTER MIEUM;Lo;0;L; 3141;;;;N;;;;; FFB2;HALFWIDTH HANGUL LETTER PIEUP;Lo;0;L; 3142;;;;N;HALFWIDTH HANGUL LETTER BIEUB;;;; FFB3;HALFWIDTH HANGUL LETTER SSANGPIEUP;Lo;0;L; 3143;;;;N;HALFWIDTH HANGUL LETTER SSANG BIEUB;;;; FFB4;HALFWIDTH HANGUL LETTER PIEUP-SIOS;Lo;0;L; 3144;;;;N;HALFWIDTH HANGUL LETTER BIEUB SIOS;;;; FFB5;HALFWIDTH HANGUL LETTER SIOS;Lo;0;L; 3145;;;;N;;;;; FFB6;HALFWIDTH HANGUL LETTER SSANGSIOS;Lo;0;L; 3146;;;;N;HALFWIDTH HANGUL LETTER SSANG SIOS;;;; FFB7;HALFWIDTH HANGUL LETTER IEUNG;Lo;0;L; 3147;;;;N;;;;; FFB8;HALFWIDTH HANGUL LETTER CIEUC;Lo;0;L; 3148;;;;N;HALFWIDTH HANGUL LETTER JIEUJ;;;; FFB9;HALFWIDTH HANGUL LETTER SSANGCIEUC;Lo;0;L; 3149;;;;N;HALFWIDTH HANGUL LETTER SSANG JIEUJ;;;; FFBA;HALFWIDTH HANGUL LETTER CHIEUCH;Lo;0;L; 314A;;;;N;HALFWIDTH HANGUL LETTER CIEUC;;;; FFBB;HALFWIDTH HANGUL LETTER KHIEUKH;Lo;0;L; 314B;;;;N;HALFWIDTH HANGUL LETTER KIYEOK;;;; FFBC;HALFWIDTH HANGUL LETTER THIEUTH;Lo;0;L; 314C;;;;N;HALFWIDTH HANGUL LETTER TIEUT;;;; FFBD;HALFWIDTH HANGUL LETTER PHIEUPH;Lo;0;L; 314D;;;;N;HALFWIDTH HANGUL LETTER PIEUP;;;; FFBE;HALFWIDTH HANGUL LETTER HIEUH;Lo;0;L; 314E;;;;N;;;;; FFC2;HALFWIDTH HANGUL LETTER A;Lo;0;L; 314F;;;;N;;;;; FFC3;HALFWIDTH HANGUL LETTER AE;Lo;0;L; 3150;;;;N;;;;; FFC4;HALFWIDTH HANGUL LETTER YA;Lo;0;L; 3151;;;;N;;;;; FFC5;HALFWIDTH HANGUL LETTER YAE;Lo;0;L; 3152;;;;N;;;;; FFC6;HALFWIDTH HANGUL LETTER EO;Lo;0;L; 3153;;;;N;;;;; FFC7;HALFWIDTH HANGUL LETTER E;Lo;0;L; 3154;;;;N;;;;; FFCA;HALFWIDTH HANGUL LETTER YEO;Lo;0;L; 3155;;;;N;;;;; FFCB;HALFWIDTH HANGUL LETTER YE;Lo;0;L; 3156;;;;N;;;;; FFCC;HALFWIDTH HANGUL LETTER O;Lo;0;L; 3157;;;;N;;;;; FFCD;HALFWIDTH HANGUL LETTER WA;Lo;0;L; 3158;;;;N;;;;; FFCE;HALFWIDTH HANGUL LETTER WAE;Lo;0;L; 3159;;;;N;;;;; FFCF;HALFWIDTH HANGUL LETTER OE;Lo;0;L; 315A;;;;N;;;;; FFD2;HALFWIDTH HANGUL LETTER YO;Lo;0;L; 315B;;;;N;;;;; FFD3;HALFWIDTH HANGUL LETTER U;Lo;0;L; 315C;;;;N;;;;; FFD4;HALFWIDTH HANGUL LETTER WEO;Lo;0;L; 315D;;;;N;;;;; FFD5;HALFWIDTH HANGUL LETTER WE;Lo;0;L; 315E;;;;N;;;;; FFD6;HALFWIDTH HANGUL LETTER WI;Lo;0;L; 315F;;;;N;;;;; FFD7;HALFWIDTH HANGUL LETTER YU;Lo;0;L; 3160;;;;N;;;;; FFDA;HALFWIDTH HANGUL LETTER EU;Lo;0;L; 3161;;;;N;;;;; FFDB;HALFWIDTH HANGUL LETTER YI;Lo;0;L; 3162;;;;N;;;;; FFDC;HALFWIDTH HANGUL LETTER I;Lo;0;L; 3163;;;;N;;;;; FFE0;FULLWIDTH CENT SIGN;Sc;0;ET; 00A2;;;;N;;;;; FFE1;FULLWIDTH POUND SIGN;Sc;0;ET; 00A3;;;;N;;;;; FFE2;FULLWIDTH NOT SIGN;Sm;0;ON; 00AC;;;;N;;;;; FFE3;FULLWIDTH MACRON;Sk;0;ON; 00AF;;;;N;FULLWIDTH SPACING MACRON;*;;; FFE4;FULLWIDTH BROKEN BAR;So;0;ON; 00A6;;;;N;FULLWIDTH BROKEN VERTICAL BAR;;;; FFE5;FULLWIDTH YEN SIGN;Sc;0;ET; 00A5;;;;N;;;;; FFE6;FULLWIDTH WON SIGN;Sc;0;ET; 20A9;;;;N;;;;; FFE8;HALFWIDTH FORMS LIGHT VERTICAL;So;0;ON; 2502;;;;N;;;;; FFE9;HALFWIDTH LEFTWARDS ARROW;Sm;0;ON; 2190;;;;N;;;;; FFEA;HALFWIDTH UPWARDS ARROW;Sm;0;ON; 2191;;;;N;;;;; FFEB;HALFWIDTH RIGHTWARDS ARROW;Sm;0;ON; 2192;;;;N;;;;; FFEC;HALFWIDTH DOWNWARDS ARROW;Sm;0;ON; 2193;;;;N;;;;; FFED;HALFWIDTH BLACK SQUARE;So;0;ON; 25A0;;;;N;;;;; FFEE;HALFWIDTH WHITE CIRCLE;So;0;ON; 25CB;;;;N;;;;; FFF9;INTERLINEAR ANNOTATION ANCHOR;Cf;0;BN;;;;;N;;;;; FFFA;INTERLINEAR ANNOTATION SEPARATOR;Cf;0;BN;;;;;N;;;;; FFFB;INTERLINEAR ANNOTATION TERMINATOR;Cf;0;BN;;;;;N;;;;; FFFC;OBJECT REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10300;OLD ITALIC LETTER A;Lo;0;L;;;;;N;;;;; 10301;OLD ITALIC LETTER BE;Lo;0;L;;;;;N;;;;; 10302;OLD ITALIC LETTER KE;Lo;0;L;;;;;N;;;;; 10303;OLD ITALIC LETTER DE;Lo;0;L;;;;;N;;;;; 10304;OLD ITALIC LETTER E;Lo;0;L;;;;;N;;;;; 10305;OLD ITALIC LETTER VE;Lo;0;L;;;;;N;;;;; 10306;OLD ITALIC LETTER ZE;Lo;0;L;;;;;N;;;;; 10307;OLD ITALIC LETTER HE;Lo;0;L;;;;;N;;;;; 10308;OLD ITALIC LETTER THE;Lo;0;L;;;;;N;;;;; 10309;OLD ITALIC LETTER I;Lo;0;L;;;;;N;;;;; 1030A;OLD ITALIC LETTER KA;Lo;0;L;;;;;N;;;;; 1030B;OLD ITALIC LETTER EL;Lo;0;L;;;;;N;;;;; 1030C;OLD ITALIC LETTER EM;Lo;0;L;;;;;N;;;;; 1030D;OLD ITALIC LETTER EN;Lo;0;L;;;;;N;;;;; 1030E;OLD ITALIC LETTER ESH;Lo;0;L;;;;;N;;;;; 1030F;OLD ITALIC LETTER O;Lo;0;L;;;;;N;;Faliscan;;; 10310;OLD ITALIC LETTER PE;Lo;0;L;;;;;N;;;;; 10311;OLD ITALIC LETTER SHE;Lo;0;L;;;;;N;;;;; 10312;OLD ITALIC LETTER KU;Lo;0;L;;;;;N;;;;; 10313;OLD ITALIC LETTER ER;Lo;0;L;;;;;N;;;;; 10314;OLD ITALIC LETTER ES;Lo;0;L;;;;;N;;;;; 10315;OLD ITALIC LETTER TE;Lo;0;L;;;;;N;;;;; 10316;OLD ITALIC LETTER U;Lo;0;L;;;;;N;;;;; 10317;OLD ITALIC LETTER EKS;Lo;0;L;;;;;N;;Faliscan;;; 10318;OLD ITALIC LETTER PHE;Lo;0;L;;;;;N;;;;; 10319;OLD ITALIC LETTER KHE;Lo;0;L;;;;;N;;;;; 1031A;OLD ITALIC LETTER EF;Lo;0;L;;;;;N;;;;; 1031B;OLD ITALIC LETTER ERS;Lo;0;L;;;;;N;;Umbrian;;; 1031C;OLD ITALIC LETTER CHE;Lo;0;L;;;;;N;;Umbrian;;; 1031D;OLD ITALIC LETTER II;Lo;0;L;;;;;N;;Oscan;;; 1031E;OLD ITALIC LETTER UU;Lo;0;L;;;;;N;;Oscan;;; 10320;OLD ITALIC NUMERAL ONE;No;0;L;;;;1;N;;;;; 10321;OLD ITALIC NUMERAL FIVE;No;0;L;;;;5;N;;;;; 10322;OLD ITALIC NUMERAL TEN;No;0;L;;;;10;N;;;;; 10323;OLD ITALIC NUMERAL FIFTY;No;0;L;;;;50;N;;;;; 10330;GOTHIC LETTER AHSA;Lo;0;L;;;;;N;;;;; 10331;GOTHIC LETTER BAIRKAN;Lo;0;L;;;;;N;;;;; 10332;GOTHIC LETTER GIBA;Lo;0;L;;;;;N;;;;; 10333;GOTHIC LETTER DAGS;Lo;0;L;;;;;N;;;;; 10334;GOTHIC LETTER AIHVUS;Lo;0;L;;;;;N;;;;; 10335;GOTHIC LETTER QAIRTHRA;Lo;0;L;;;;;N;;;;; 10336;GOTHIC LETTER IUJA;Lo;0;L;;;;;N;;;;; 10337;GOTHIC LETTER HAGL;Lo;0;L;;;;;N;;;;; 10338;GOTHIC LETTER THIUTH;Lo;0;L;;;;;N;;;;; 10339;GOTHIC LETTER EIS;Lo;0;L;;;;;N;;;;; 1033A;GOTHIC LETTER KUSMA;Lo;0;L;;;;;N;;;;; 1033B;GOTHIC LETTER LAGUS;Lo;0;L;;;;;N;;;;; 1033C;GOTHIC LETTER MANNA;Lo;0;L;;;;;N;;;;; 1033D;GOTHIC LETTER NAUTHS;Lo;0;L;;;;;N;;;;; 1033E;GOTHIC LETTER JER;Lo;0;L;;;;;N;;;;; 1033F;GOTHIC LETTER URUS;Lo;0;L;;;;;N;;;;; 10340;GOTHIC LETTER PAIRTHRA;Lo;0;L;;;;;N;;;;; 10341;GOTHIC LETTER NINETY;Lo;0;L;;;;;N;;;;; 10342;GOTHIC LETTER RAIDA;Lo;0;L;;;;;N;;;;; 10343;GOTHIC LETTER SAUIL;Lo;0;L;;;;;N;;;;; 10344;GOTHIC LETTER TEIWS;Lo;0;L;;;;;N;;;;; 10345;GOTHIC LETTER WINJA;Lo;0;L;;;;;N;;;;; 10346;GOTHIC LETTER FAIHU;Lo;0;L;;;;;N;;;;; 10347;GOTHIC LETTER IGGWS;Lo;0;L;;;;;N;;;;; 10348;GOTHIC LETTER HWAIR;Lo;0;L;;;;;N;;;;; 10349;GOTHIC LETTER OTHAL;Lo;0;L;;;;;N;;;;; 1034A;GOTHIC LETTER NINE HUNDRED;Nl;0;L;;;;;N;;;;; 10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428; 10401;DESERET CAPITAL LETTER LONG E;Lu;0;L;;;;;N;;;;10429; 10402;DESERET CAPITAL LETTER LONG A;Lu;0;L;;;;;N;;;;1042A; 10403;DESERET CAPITAL LETTER LONG AH;Lu;0;L;;;;;N;;;;1042B; 10404;DESERET CAPITAL LETTER LONG O;Lu;0;L;;;;;N;;;;1042C; 10405;DESERET CAPITAL LETTER LONG OO;Lu;0;L;;;;;N;;;;1042D; 10406;DESERET CAPITAL LETTER SHORT I;Lu;0;L;;;;;N;;;;1042E; 10407;DESERET CAPITAL LETTER SHORT E;Lu;0;L;;;;;N;;;;1042F; 10408;DESERET CAPITAL LETTER SHORT A;Lu;0;L;;;;;N;;;;10430; 10409;DESERET CAPITAL LETTER SHORT AH;Lu;0;L;;;;;N;;;;10431; 1040A;DESERET CAPITAL LETTER SHORT O;Lu;0;L;;;;;N;;;;10432; 1040B;DESERET CAPITAL LETTER SHORT OO;Lu;0;L;;;;;N;;;;10433; 1040C;DESERET CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;10434; 1040D;DESERET CAPITAL LETTER OW;Lu;0;L;;;;;N;;;;10435; 1040E;DESERET CAPITAL LETTER WU;Lu;0;L;;;;;N;;;;10436; 1040F;DESERET CAPITAL LETTER YEE;Lu;0;L;;;;;N;;;;10437; 10410;DESERET CAPITAL LETTER H;Lu;0;L;;;;;N;;;;10438; 10411;DESERET CAPITAL LETTER PEE;Lu;0;L;;;;;N;;;;10439; 10412;DESERET CAPITAL LETTER BEE;Lu;0;L;;;;;N;;;;1043A; 10413;DESERET CAPITAL LETTER TEE;Lu;0;L;;;;;N;;;;1043B; 10414;DESERET CAPITAL LETTER DEE;Lu;0;L;;;;;N;;;;1043C; 10415;DESERET CAPITAL LETTER CHEE;Lu;0;L;;;;;N;;;;1043D; 10416;DESERET CAPITAL LETTER JEE;Lu;0;L;;;;;N;;;;1043E; 10417;DESERET CAPITAL LETTER KAY;Lu;0;L;;;;;N;;;;1043F; 10418;DESERET CAPITAL LETTER GAY;Lu;0;L;;;;;N;;;;10440; 10419;DESERET CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;10441; 1041A;DESERET CAPITAL LETTER VEE;Lu;0;L;;;;;N;;;;10442; 1041B;DESERET CAPITAL LETTER ETH;Lu;0;L;;;;;N;;;;10443; 1041C;DESERET CAPITAL LETTER THEE;Lu;0;L;;;;;N;;;;10444; 1041D;DESERET CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;10445; 1041E;DESERET CAPITAL LETTER ZEE;Lu;0;L;;;;;N;;;;10446; 1041F;DESERET CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;10447; 10420;DESERET CAPITAL LETTER ZHEE;Lu;0;L;;;;;N;;;;10448; 10421;DESERET CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;10449; 10422;DESERET CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;1044A; 10423;DESERET CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;1044B; 10424;DESERET CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;1044C; 10425;DESERET CAPITAL LETTER ENG;Lu;0;L;;;;;N;;;;1044D; 10428;DESERET SMALL LETTER LONG I;Ll;0;L;;;;;N;;;10400;;10400 10429;DESERET SMALL LETTER LONG E;Ll;0;L;;;;;N;;;10401;;10401 1042A;DESERET SMALL LETTER LONG A;Ll;0;L;;;;;N;;;10402;;10402 1042B;DESERET SMALL LETTER LONG AH;Ll;0;L;;;;;N;;;10403;;10403 1042C;DESERET SMALL LETTER LONG O;Ll;0;L;;;;;N;;;10404;;10404 1042D;DESERET SMALL LETTER LONG OO;Ll;0;L;;;;;N;;;10405;;10405 1042E;DESERET SMALL LETTER SHORT I;Ll;0;L;;;;;N;;;10406;;10406 1042F;DESERET SMALL LETTER SHORT E;Ll;0;L;;;;;N;;;10407;;10407 10430;DESERET SMALL LETTER SHORT A;Ll;0;L;;;;;N;;;10408;;10408 10431;DESERET SMALL LETTER SHORT AH;Ll;0;L;;;;;N;;;10409;;10409 10432;DESERET SMALL LETTER SHORT O;Ll;0;L;;;;;N;;;1040A;;1040A 10433;DESERET SMALL LETTER SHORT OO;Ll;0;L;;;;;N;;;1040B;;1040B 10434;DESERET SMALL LETTER AY;Ll;0;L;;;;;N;;;1040C;;1040C 10435;DESERET SMALL LETTER OW;Ll;0;L;;;;;N;;;1040D;;1040D 10436;DESERET SMALL LETTER WU;Ll;0;L;;;;;N;;;1040E;;1040E 10437;DESERET SMALL LETTER YEE;Ll;0;L;;;;;N;;;1040F;;1040F 10438;DESERET SMALL LETTER H;Ll;0;L;;;;;N;;;10410;;10410 10439;DESERET SMALL LETTER PEE;Ll;0;L;;;;;N;;;10411;;10411 1043A;DESERET SMALL LETTER BEE;Ll;0;L;;;;;N;;;10412;;10412 1043B;DESERET SMALL LETTER TEE;Ll;0;L;;;;;N;;;10413;;10413 1043C;DESERET SMALL LETTER DEE;Ll;0;L;;;;;N;;;10414;;10414 1043D;DESERET SMALL LETTER CHEE;Ll;0;L;;;;;N;;;10415;;10415 1043E;DESERET SMALL LETTER JEE;Ll;0;L;;;;;N;;;10416;;10416 1043F;DESERET SMALL LETTER KAY;Ll;0;L;;;;;N;;;10417;;10417 10440;DESERET SMALL LETTER GAY;Ll;0;L;;;;;N;;;10418;;10418 10441;DESERET SMALL LETTER EF;Ll;0;L;;;;;N;;;10419;;10419 10442;DESERET SMALL LETTER VEE;Ll;0;L;;;;;N;;;1041A;;1041A 10443;DESERET SMALL LETTER ETH;Ll;0;L;;;;;N;;;1041B;;1041B 10444;DESERET SMALL LETTER THEE;Ll;0;L;;;;;N;;;1041C;;1041C 10445;DESERET SMALL LETTER ES;Ll;0;L;;;;;N;;;1041D;;1041D 10446;DESERET SMALL LETTER ZEE;Ll;0;L;;;;;N;;;1041E;;1041E 10447;DESERET SMALL LETTER ESH;Ll;0;L;;;;;N;;;1041F;;1041F 10448;DESERET SMALL LETTER ZHEE;Ll;0;L;;;;;N;;;10420;;10420 10449;DESERET SMALL LETTER ER;Ll;0;L;;;;;N;;;10421;;10421 1044A;DESERET SMALL LETTER EL;Ll;0;L;;;;;N;;;10422;;10422 1044B;DESERET SMALL LETTER EM;Ll;0;L;;;;;N;;;10423;;10423 1044C;DESERET SMALL LETTER EN;Ll;0;L;;;;;N;;;10424;;10424 1044D;DESERET SMALL LETTER ENG;Ll;0;L;;;;;N;;;10425;;10425 1D000;BYZANTINE MUSICAL SYMBOL PSILI;So;0;L;;;;;N;;;;; 1D001;BYZANTINE MUSICAL SYMBOL DASEIA;So;0;L;;;;;N;;;;; 1D002;BYZANTINE MUSICAL SYMBOL PERISPOMENI;So;0;L;;;;;N;;;;; 1D003;BYZANTINE MUSICAL SYMBOL OXEIA EKFONITIKON;So;0;L;;;;;N;;;;; 1D004;BYZANTINE MUSICAL SYMBOL OXEIA DIPLI;So;0;L;;;;;N;;;;; 1D005;BYZANTINE MUSICAL SYMBOL VAREIA EKFONITIKON;So;0;L;;;;;N;;;;; 1D006;BYZANTINE MUSICAL SYMBOL VAREIA DIPLI;So;0;L;;;;;N;;;;; 1D007;BYZANTINE MUSICAL SYMBOL KATHISTI;So;0;L;;;;;N;;;;; 1D008;BYZANTINE MUSICAL SYMBOL SYRMATIKI;So;0;L;;;;;N;;;;; 1D009;BYZANTINE MUSICAL SYMBOL PARAKLITIKI;So;0;L;;;;;N;;;;; 1D00A;BYZANTINE MUSICAL SYMBOL YPOKRISIS;So;0;L;;;;;N;;;;; 1D00B;BYZANTINE MUSICAL SYMBOL YPOKRISIS DIPLI;So;0;L;;;;;N;;;;; 1D00C;BYZANTINE MUSICAL SYMBOL KREMASTI;So;0;L;;;;;N;;;;; 1D00D;BYZANTINE MUSICAL SYMBOL APESO EKFONITIKON;So;0;L;;;;;N;;;;; 1D00E;BYZANTINE MUSICAL SYMBOL EXO EKFONITIKON;So;0;L;;;;;N;;;;; 1D00F;BYZANTINE MUSICAL SYMBOL TELEIA;So;0;L;;;;;N;;;;; 1D010;BYZANTINE MUSICAL SYMBOL KENTIMATA;So;0;L;;;;;N;;;;; 1D011;BYZANTINE MUSICAL SYMBOL APOSTROFOS;So;0;L;;;;;N;;;;; 1D012;BYZANTINE MUSICAL SYMBOL APOSTROFOS DIPLI;So;0;L;;;;;N;;;;; 1D013;BYZANTINE MUSICAL SYMBOL SYNEVMA;So;0;L;;;;;N;;;;; 1D014;BYZANTINE MUSICAL SYMBOL THITA;So;0;L;;;;;N;;;;; 1D015;BYZANTINE MUSICAL SYMBOL OLIGON ARCHAION;So;0;L;;;;;N;;;;; 1D016;BYZANTINE MUSICAL SYMBOL GORGON ARCHAION;So;0;L;;;;;N;;;;; 1D017;BYZANTINE MUSICAL SYMBOL PSILON;So;0;L;;;;;N;;;;; 1D018;BYZANTINE MUSICAL SYMBOL CHAMILON;So;0;L;;;;;N;;;;; 1D019;BYZANTINE MUSICAL SYMBOL VATHY;So;0;L;;;;;N;;;;; 1D01A;BYZANTINE MUSICAL SYMBOL ISON ARCHAION;So;0;L;;;;;N;;;;; 1D01B;BYZANTINE MUSICAL SYMBOL KENTIMA ARCHAION;So;0;L;;;;;N;;;;; 1D01C;BYZANTINE MUSICAL SYMBOL KENTIMATA ARCHAION;So;0;L;;;;;N;;;;; 1D01D;BYZANTINE MUSICAL SYMBOL SAXIMATA;So;0;L;;;;;N;;;;; 1D01E;BYZANTINE MUSICAL SYMBOL PARICHON;So;0;L;;;;;N;;;;; 1D01F;BYZANTINE MUSICAL SYMBOL STAVROS APODEXIA;So;0;L;;;;;N;;;;; 1D020;BYZANTINE MUSICAL SYMBOL OXEIAI ARCHAION;So;0;L;;;;;N;;;;; 1D021;BYZANTINE MUSICAL SYMBOL VAREIAI ARCHAION;So;0;L;;;;;N;;;;; 1D022;BYZANTINE MUSICAL SYMBOL APODERMA ARCHAION;So;0;L;;;;;N;;;;; 1D023;BYZANTINE MUSICAL SYMBOL APOTHEMA;So;0;L;;;;;N;;;;; 1D024;BYZANTINE MUSICAL SYMBOL KLASMA;So;0;L;;;;;N;;;;; 1D025;BYZANTINE MUSICAL SYMBOL REVMA;So;0;L;;;;;N;;;;; 1D026;BYZANTINE MUSICAL SYMBOL PIASMA ARCHAION;So;0;L;;;;;N;;;;; 1D027;BYZANTINE MUSICAL SYMBOL TINAGMA;So;0;L;;;;;N;;;;; 1D028;BYZANTINE MUSICAL SYMBOL ANATRICHISMA;So;0;L;;;;;N;;;;; 1D029;BYZANTINE MUSICAL SYMBOL SEISMA;So;0;L;;;;;N;;;;; 1D02A;BYZANTINE MUSICAL SYMBOL SYNAGMA ARCHAION;So;0;L;;;;;N;;;;; 1D02B;BYZANTINE MUSICAL SYMBOL SYNAGMA META STAVROU;So;0;L;;;;;N;;;;; 1D02C;BYZANTINE MUSICAL SYMBOL OYRANISMA ARCHAION;So;0;L;;;;;N;;;;; 1D02D;BYZANTINE MUSICAL SYMBOL THEMA;So;0;L;;;;;N;;;;; 1D02E;BYZANTINE MUSICAL SYMBOL LEMOI;So;0;L;;;;;N;;;;; 1D02F;BYZANTINE MUSICAL SYMBOL DYO;So;0;L;;;;;N;;;;; 1D030;BYZANTINE MUSICAL SYMBOL TRIA;So;0;L;;;;;N;;;;; 1D031;BYZANTINE MUSICAL SYMBOL TESSERA;So;0;L;;;;;N;;;;; 1D032;BYZANTINE MUSICAL SYMBOL KRATIMATA;So;0;L;;;;;N;;;;; 1D033;BYZANTINE MUSICAL SYMBOL APESO EXO NEO;So;0;L;;;;;N;;;;; 1D034;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION;So;0;L;;;;;N;;;;; 1D035;BYZANTINE MUSICAL SYMBOL IMIFTHORA;So;0;L;;;;;N;;;;; 1D036;BYZANTINE MUSICAL SYMBOL TROMIKON ARCHAION;So;0;L;;;;;N;;;;; 1D037;BYZANTINE MUSICAL SYMBOL KATAVA TROMIKON;So;0;L;;;;;N;;;;; 1D038;BYZANTINE MUSICAL SYMBOL PELASTON;So;0;L;;;;;N;;;;; 1D039;BYZANTINE MUSICAL SYMBOL PSIFISTON;So;0;L;;;;;N;;;;; 1D03A;BYZANTINE MUSICAL SYMBOL KONTEVMA;So;0;L;;;;;N;;;;; 1D03B;BYZANTINE MUSICAL SYMBOL CHOREVMA ARCHAION;So;0;L;;;;;N;;;;; 1D03C;BYZANTINE MUSICAL SYMBOL RAPISMA;So;0;L;;;;;N;;;;; 1D03D;BYZANTINE MUSICAL SYMBOL PARAKALESMA ARCHAION;So;0;L;;;;;N;;;;; 1D03E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI ARCHAION;So;0;L;;;;;N;;;;; 1D03F;BYZANTINE MUSICAL SYMBOL ICHADIN;So;0;L;;;;;N;;;;; 1D040;BYZANTINE MUSICAL SYMBOL NANA;So;0;L;;;;;N;;;;; 1D041;BYZANTINE MUSICAL SYMBOL PETASMA;So;0;L;;;;;N;;;;; 1D042;BYZANTINE MUSICAL SYMBOL KONTEVMA ALLO;So;0;L;;;;;N;;;;; 1D043;BYZANTINE MUSICAL SYMBOL TROMIKON ALLO;So;0;L;;;;;N;;;;; 1D044;BYZANTINE MUSICAL SYMBOL STRAGGISMATA;So;0;L;;;;;N;;;;; 1D045;BYZANTINE MUSICAL SYMBOL GRONTHISMATA;So;0;L;;;;;N;;;;; 1D046;BYZANTINE MUSICAL SYMBOL ISON NEO;So;0;L;;;;;N;;;;; 1D047;BYZANTINE MUSICAL SYMBOL OLIGON NEO;So;0;L;;;;;N;;;;; 1D048;BYZANTINE MUSICAL SYMBOL OXEIA NEO;So;0;L;;;;;N;;;;; 1D049;BYZANTINE MUSICAL SYMBOL PETASTI;So;0;L;;;;;N;;;;; 1D04A;BYZANTINE MUSICAL SYMBOL KOUFISMA;So;0;L;;;;;N;;;;; 1D04B;BYZANTINE MUSICAL SYMBOL PETASTOKOUFISMA;So;0;L;;;;;N;;;;; 1D04C;BYZANTINE MUSICAL SYMBOL KRATIMOKOUFISMA;So;0;L;;;;;N;;;;; 1D04D;BYZANTINE MUSICAL SYMBOL PELASTON NEO;So;0;L;;;;;N;;;;; 1D04E;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO ANO;So;0;L;;;;;N;;;;; 1D04F;BYZANTINE MUSICAL SYMBOL KENTIMA NEO ANO;So;0;L;;;;;N;;;;; 1D050;BYZANTINE MUSICAL SYMBOL YPSILI;So;0;L;;;;;N;;;;; 1D051;BYZANTINE MUSICAL SYMBOL APOSTROFOS NEO;So;0;L;;;;;N;;;;; 1D052;BYZANTINE MUSICAL SYMBOL APOSTROFOI SYNDESMOS NEO;So;0;L;;;;;N;;;;; 1D053;BYZANTINE MUSICAL SYMBOL YPORROI;So;0;L;;;;;N;;;;; 1D054;BYZANTINE MUSICAL SYMBOL KRATIMOYPORROON;So;0;L;;;;;N;;;;; 1D055;BYZANTINE MUSICAL SYMBOL ELAFRON;So;0;L;;;;;N;;;;; 1D056;BYZANTINE MUSICAL SYMBOL CHAMILI;So;0;L;;;;;N;;;;; 1D057;BYZANTINE MUSICAL SYMBOL MIKRON ISON;So;0;L;;;;;N;;;;; 1D058;BYZANTINE MUSICAL SYMBOL VAREIA NEO;So;0;L;;;;;N;;;;; 1D059;BYZANTINE MUSICAL SYMBOL PIASMA NEO;So;0;L;;;;;N;;;;; 1D05A;BYZANTINE MUSICAL SYMBOL PSIFISTON NEO;So;0;L;;;;;N;;;;; 1D05B;BYZANTINE MUSICAL SYMBOL OMALON;So;0;L;;;;;N;;;;; 1D05C;BYZANTINE MUSICAL SYMBOL ANTIKENOMA;So;0;L;;;;;N;;;;; 1D05D;BYZANTINE MUSICAL SYMBOL LYGISMA;So;0;L;;;;;N;;;;; 1D05E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI NEO;So;0;L;;;;;N;;;;; 1D05F;BYZANTINE MUSICAL SYMBOL PARAKALESMA NEO;So;0;L;;;;;N;;;;; 1D060;BYZANTINE MUSICAL SYMBOL ETERON PARAKALESMA;So;0;L;;;;;N;;;;; 1D061;BYZANTINE MUSICAL SYMBOL KYLISMA;So;0;L;;;;;N;;;;; 1D062;BYZANTINE MUSICAL SYMBOL ANTIKENOKYLISMA;So;0;L;;;;;N;;;;; 1D063;BYZANTINE MUSICAL SYMBOL TROMIKON NEO;So;0;L;;;;;N;;;;; 1D064;BYZANTINE MUSICAL SYMBOL EKSTREPTON;So;0;L;;;;;N;;;;; 1D065;BYZANTINE MUSICAL SYMBOL SYNAGMA NEO;So;0;L;;;;;N;;;;; 1D066;BYZANTINE MUSICAL SYMBOL SYRMA;So;0;L;;;;;N;;;;; 1D067;BYZANTINE MUSICAL SYMBOL CHOREVMA NEO;So;0;L;;;;;N;;;;; 1D068;BYZANTINE MUSICAL SYMBOL EPEGERMA;So;0;L;;;;;N;;;;; 1D069;BYZANTINE MUSICAL SYMBOL SEISMA NEO;So;0;L;;;;;N;;;;; 1D06A;BYZANTINE MUSICAL SYMBOL XIRON KLASMA;So;0;L;;;;;N;;;;; 1D06B;BYZANTINE MUSICAL SYMBOL TROMIKOPSIFISTON;So;0;L;;;;;N;;;;; 1D06C;BYZANTINE MUSICAL SYMBOL PSIFISTOLYGISMA;So;0;L;;;;;N;;;;; 1D06D;BYZANTINE MUSICAL SYMBOL TROMIKOLYGISMA;So;0;L;;;;;N;;;;; 1D06E;BYZANTINE MUSICAL SYMBOL TROMIKOPARAKALESMA;So;0;L;;;;;N;;;;; 1D06F;BYZANTINE MUSICAL SYMBOL PSIFISTOPARAKALESMA;So;0;L;;;;;N;;;;; 1D070;BYZANTINE MUSICAL SYMBOL TROMIKOSYNAGMA;So;0;L;;;;;N;;;;; 1D071;BYZANTINE MUSICAL SYMBOL PSIFISTOSYNAGMA;So;0;L;;;;;N;;;;; 1D072;BYZANTINE MUSICAL SYMBOL GORGOSYNTHETON;So;0;L;;;;;N;;;;; 1D073;BYZANTINE MUSICAL SYMBOL ARGOSYNTHETON;So;0;L;;;;;N;;;;; 1D074;BYZANTINE MUSICAL SYMBOL ETERON ARGOSYNTHETON;So;0;L;;;;;N;;;;; 1D075;BYZANTINE MUSICAL SYMBOL OYRANISMA NEO;So;0;L;;;;;N;;;;; 1D076;BYZANTINE MUSICAL SYMBOL THEMATISMOS ESO;So;0;L;;;;;N;;;;; 1D077;BYZANTINE MUSICAL SYMBOL THEMATISMOS EXO;So;0;L;;;;;N;;;;; 1D078;BYZANTINE MUSICAL SYMBOL THEMA APLOUN;So;0;L;;;;;N;;;;; 1D079;BYZANTINE MUSICAL SYMBOL THES KAI APOTHES;So;0;L;;;;;N;;;;; 1D07A;BYZANTINE MUSICAL SYMBOL KATAVASMA;So;0;L;;;;;N;;;;; 1D07B;BYZANTINE MUSICAL SYMBOL ENDOFONON;So;0;L;;;;;N;;;;; 1D07C;BYZANTINE MUSICAL SYMBOL YFEN KATO;So;0;L;;;;;N;;;;; 1D07D;BYZANTINE MUSICAL SYMBOL YFEN ANO;So;0;L;;;;;N;;;;; 1D07E;BYZANTINE MUSICAL SYMBOL STAVROS;So;0;L;;;;;N;;;;; 1D07F;BYZANTINE MUSICAL SYMBOL KLASMA ANO;So;0;L;;;;;N;;;;; 1D080;BYZANTINE MUSICAL SYMBOL DIPLI ARCHAION;So;0;L;;;;;N;;;;; 1D081;BYZANTINE MUSICAL SYMBOL KRATIMA ARCHAION;So;0;L;;;;;N;;;;; 1D082;BYZANTINE MUSICAL SYMBOL KRATIMA ALLO;So;0;L;;;;;N;;;;; 1D083;BYZANTINE MUSICAL SYMBOL KRATIMA NEO;So;0;L;;;;;N;;;;; 1D084;BYZANTINE MUSICAL SYMBOL APODERMA NEO;So;0;L;;;;;N;;;;; 1D085;BYZANTINE MUSICAL SYMBOL APLI;So;0;L;;;;;N;;;;; 1D086;BYZANTINE MUSICAL SYMBOL DIPLI;So;0;L;;;;;N;;;;; 1D087;BYZANTINE MUSICAL SYMBOL TRIPLI;So;0;L;;;;;N;;;;; 1D088;BYZANTINE MUSICAL SYMBOL TETRAPLI;So;0;L;;;;;N;;;;; 1D089;BYZANTINE MUSICAL SYMBOL KORONIS;So;0;L;;;;;N;;;;; 1D08A;BYZANTINE MUSICAL SYMBOL LEIMMA ENOS CHRONOU;So;0;L;;;;;N;;;;; 1D08B;BYZANTINE MUSICAL SYMBOL LEIMMA DYO CHRONON;So;0;L;;;;;N;;;;; 1D08C;BYZANTINE MUSICAL SYMBOL LEIMMA TRION CHRONON;So;0;L;;;;;N;;;;; 1D08D;BYZANTINE MUSICAL SYMBOL LEIMMA TESSARON CHRONON;So;0;L;;;;;N;;;;; 1D08E;BYZANTINE MUSICAL SYMBOL LEIMMA IMISEOS CHRONOU;So;0;L;;;;;N;;;;; 1D08F;BYZANTINE MUSICAL SYMBOL GORGON NEO ANO;So;0;L;;;;;N;;;;; 1D090;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON ARISTERA;So;0;L;;;;;N;;;;; 1D091;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;; 1D092;BYZANTINE MUSICAL SYMBOL DIGORGON;So;0;L;;;;;N;;;;; 1D093;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA KATO;So;0;L;;;;;N;;;;; 1D094;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA ANO;So;0;L;;;;;N;;;;; 1D095;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;; 1D096;BYZANTINE MUSICAL SYMBOL TRIGORGON;So;0;L;;;;;N;;;;; 1D097;BYZANTINE MUSICAL SYMBOL ARGON;So;0;L;;;;;N;;;;; 1D098;BYZANTINE MUSICAL SYMBOL IMIDIARGON;So;0;L;;;;;N;;;;; 1D099;BYZANTINE MUSICAL SYMBOL DIARGON;So;0;L;;;;;N;;;;; 1D09A;BYZANTINE MUSICAL SYMBOL AGOGI POLI ARGI;So;0;L;;;;;N;;;;; 1D09B;BYZANTINE MUSICAL SYMBOL AGOGI ARGOTERI;So;0;L;;;;;N;;;;; 1D09C;BYZANTINE MUSICAL SYMBOL AGOGI ARGI;So;0;L;;;;;N;;;;; 1D09D;BYZANTINE MUSICAL SYMBOL AGOGI METRIA;So;0;L;;;;;N;;;;; 1D09E;BYZANTINE MUSICAL SYMBOL AGOGI MESI;So;0;L;;;;;N;;;;; 1D09F;BYZANTINE MUSICAL SYMBOL AGOGI GORGI;So;0;L;;;;;N;;;;; 1D0A0;BYZANTINE MUSICAL SYMBOL AGOGI GORGOTERI;So;0;L;;;;;N;;;;; 1D0A1;BYZANTINE MUSICAL SYMBOL AGOGI POLI GORGI;So;0;L;;;;;N;;;;; 1D0A2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOS ICHOS;So;0;L;;;;;N;;;;; 1D0A3;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI PROTOS ICHOS;So;0;L;;;;;N;;;;; 1D0A4;BYZANTINE MUSICAL SYMBOL MARTYRIA DEYTEROS ICHOS;So;0;L;;;;;N;;;;; 1D0A5;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI DEYTEROS ICHOS;So;0;L;;;;;N;;;;; 1D0A6;BYZANTINE MUSICAL SYMBOL MARTYRIA TRITOS ICHOS;So;0;L;;;;;N;;;;; 1D0A7;BYZANTINE MUSICAL SYMBOL MARTYRIA TRIFONIAS;So;0;L;;;;;N;;;;; 1D0A8;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS ICHOS;So;0;L;;;;;N;;;;; 1D0A9;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS LEGETOS ICHOS;So;0;L;;;;;N;;;;; 1D0AA;BYZANTINE MUSICAL SYMBOL MARTYRIA LEGETOS ICHOS;So;0;L;;;;;N;;;;; 1D0AB;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS ICHOS;So;0;L;;;;;N;;;;; 1D0AC;BYZANTINE MUSICAL SYMBOL ISAKIA TELOUS ICHIMATOS;So;0;L;;;;;N;;;;; 1D0AD;BYZANTINE MUSICAL SYMBOL APOSTROFOI TELOUS ICHIMATOS;So;0;L;;;;;N;;;;; 1D0AE;BYZANTINE MUSICAL SYMBOL FANEROSIS TETRAFONIAS;So;0;L;;;;;N;;;;; 1D0AF;BYZANTINE MUSICAL SYMBOL FANEROSIS MONOFONIAS;So;0;L;;;;;N;;;;; 1D0B0;BYZANTINE MUSICAL SYMBOL FANEROSIS DIFONIAS;So;0;L;;;;;N;;;;; 1D0B1;BYZANTINE MUSICAL SYMBOL MARTYRIA VARYS ICHOS;So;0;L;;;;;N;;;;; 1D0B2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOVARYS ICHOS;So;0;L;;;;;N;;;;; 1D0B3;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS TETARTOS ICHOS;So;0;L;;;;;N;;;;; 1D0B4;BYZANTINE MUSICAL SYMBOL GORTHMIKON N APLOUN;So;0;L;;;;;N;;;;; 1D0B5;BYZANTINE MUSICAL SYMBOL GORTHMIKON N DIPLOUN;So;0;L;;;;;N;;;;; 1D0B6;BYZANTINE MUSICAL SYMBOL ENARXIS KAI FTHORA VOU;So;0;L;;;;;N;;;;; 1D0B7;BYZANTINE MUSICAL SYMBOL IMIFONON;So;0;L;;;;;N;;;;; 1D0B8;BYZANTINE MUSICAL SYMBOL IMIFTHORON;So;0;L;;;;;N;;;;; 1D0B9;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION DEYTEROU ICHOU;So;0;L;;;;;N;;;;; 1D0BA;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI PA;So;0;L;;;;;N;;;;; 1D0BB;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NANA;So;0;L;;;;;N;;;;; 1D0BC;BYZANTINE MUSICAL SYMBOL FTHORA NAOS ICHOS;So;0;L;;;;;N;;;;; 1D0BD;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI DI;So;0;L;;;;;N;;;;; 1D0BE;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON DIATONON DI;So;0;L;;;;;N;;;;; 1D0BF;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI KE;So;0;L;;;;;N;;;;; 1D0C0;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI ZO;So;0;L;;;;;N;;;;; 1D0C1;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI KATO;So;0;L;;;;;N;;;;; 1D0C2;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI ANO;So;0;L;;;;;N;;;;; 1D0C3;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA DIFONIAS;So;0;L;;;;;N;;;;; 1D0C4;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA MONOFONIAS;So;0;L;;;;;N;;;;; 1D0C5;BYZANTINE MUSICAL SYMBOL FHTORA SKLIRON CHROMA VASIS;So;0;L;;;;;N;;;;; 1D0C6;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA SYNAFI;So;0;L;;;;;N;;;;; 1D0C7;BYZANTINE MUSICAL SYMBOL FTHORA NENANO;So;0;L;;;;;N;;;;; 1D0C8;BYZANTINE MUSICAL SYMBOL CHROA ZYGOS;So;0;L;;;;;N;;;;; 1D0C9;BYZANTINE MUSICAL SYMBOL CHROA KLITON;So;0;L;;;;;N;;;;; 1D0CA;BYZANTINE MUSICAL SYMBOL CHROA SPATHI;So;0;L;;;;;N;;;;; 1D0CB;BYZANTINE MUSICAL SYMBOL FTHORA I YFESIS TETARTIMORION;So;0;L;;;;;N;;;;; 1D0CC;BYZANTINE MUSICAL SYMBOL FTHORA ENARMONIOS ANTIFONIA;So;0;L;;;;;N;;;;; 1D0CD;BYZANTINE MUSICAL SYMBOL YFESIS TRITIMORION;So;0;L;;;;;N;;;;; 1D0CE;BYZANTINE MUSICAL SYMBOL DIESIS TRITIMORION;So;0;L;;;;;N;;;;; 1D0CF;BYZANTINE MUSICAL SYMBOL DIESIS TETARTIMORION;So;0;L;;;;;N;;;;; 1D0D0;BYZANTINE MUSICAL SYMBOL DIESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;; 1D0D1;BYZANTINE MUSICAL SYMBOL DIESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;; 1D0D2;BYZANTINE MUSICAL SYMBOL DIESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;; 1D0D3;BYZANTINE MUSICAL SYMBOL DIESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;; 1D0D4;BYZANTINE MUSICAL SYMBOL YFESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;; 1D0D5;BYZANTINE MUSICAL SYMBOL YFESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;; 1D0D6;BYZANTINE MUSICAL SYMBOL YFESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;; 1D0D7;BYZANTINE MUSICAL SYMBOL YFESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;; 1D0D8;BYZANTINE MUSICAL SYMBOL GENIKI DIESIS;So;0;L;;;;;N;;;;; 1D0D9;BYZANTINE MUSICAL SYMBOL GENIKI YFESIS;So;0;L;;;;;N;;;;; 1D0DA;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MIKRI;So;0;L;;;;;N;;;;; 1D0DB;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MEGALI;So;0;L;;;;;N;;;;; 1D0DC;BYZANTINE MUSICAL SYMBOL DIASTOLI DIPLI;So;0;L;;;;;N;;;;; 1D0DD;BYZANTINE MUSICAL SYMBOL DIASTOLI THESEOS;So;0;L;;;;;N;;;;; 1D0DE;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS;So;0;L;;;;;N;;;;; 1D0DF;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS DISIMOU;So;0;L;;;;;N;;;;; 1D0E0;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TRISIMOU;So;0;L;;;;;N;;;;; 1D0E1;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TETRASIMOU;So;0;L;;;;;N;;;;; 1D0E2;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS;So;0;L;;;;;N;;;;; 1D0E3;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS DISIMOU;So;0;L;;;;;N;;;;; 1D0E4;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TRISIMOU;So;0;L;;;;;N;;;;; 1D0E5;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TETRASIMOU;So;0;L;;;;;N;;;;; 1D0E6;BYZANTINE MUSICAL SYMBOL DIGRAMMA GG;So;0;L;;;;;N;;;;; 1D0E7;BYZANTINE MUSICAL SYMBOL DIFTOGGOS OU;So;0;L;;;;;N;;;;; 1D0E8;BYZANTINE MUSICAL SYMBOL STIGMA;So;0;L;;;;;N;;;;; 1D0E9;BYZANTINE MUSICAL SYMBOL ARKTIKO PA;So;0;L;;;;;N;;;;; 1D0EA;BYZANTINE MUSICAL SYMBOL ARKTIKO VOU;So;0;L;;;;;N;;;;; 1D0EB;BYZANTINE MUSICAL SYMBOL ARKTIKO GA;So;0;L;;;;;N;;;;; 1D0EC;BYZANTINE MUSICAL SYMBOL ARKTIKO DI;So;0;L;;;;;N;;;;; 1D0ED;BYZANTINE MUSICAL SYMBOL ARKTIKO KE;So;0;L;;;;;N;;;;; 1D0EE;BYZANTINE MUSICAL SYMBOL ARKTIKO ZO;So;0;L;;;;;N;;;;; 1D0EF;BYZANTINE MUSICAL SYMBOL ARKTIKO NI;So;0;L;;;;;N;;;;; 1D0F0;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO MESO;So;0;L;;;;;N;;;;; 1D0F1;BYZANTINE MUSICAL SYMBOL KENTIMA NEO MESO;So;0;L;;;;;N;;;;; 1D0F2;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO KATO;So;0;L;;;;;N;;;;; 1D0F3;BYZANTINE MUSICAL SYMBOL KENTIMA NEO KATO;So;0;L;;;;;N;;;;; 1D0F4;BYZANTINE MUSICAL SYMBOL KLASMA KATO;So;0;L;;;;;N;;;;; 1D0F5;BYZANTINE MUSICAL SYMBOL GORGON NEO KATO;So;0;L;;;;;N;;;;; 1D100;MUSICAL SYMBOL SINGLE BARLINE;So;0;L;;;;;N;;;;; 1D101;MUSICAL SYMBOL DOUBLE BARLINE;So;0;L;;;;;N;;;;; 1D102;MUSICAL SYMBOL FINAL BARLINE;So;0;L;;;;;N;;;;; 1D103;MUSICAL SYMBOL REVERSE FINAL BARLINE;So;0;L;;;;;N;;;;; 1D104;MUSICAL SYMBOL DASHED BARLINE;So;0;L;;;;;N;;;;; 1D105;MUSICAL SYMBOL SHORT BARLINE;So;0;L;;;;;N;;;;; 1D106;MUSICAL SYMBOL LEFT REPEAT SIGN;So;0;L;;;;;N;;;;; 1D107;MUSICAL SYMBOL RIGHT REPEAT SIGN;So;0;L;;;;;N;;;;; 1D108;MUSICAL SYMBOL REPEAT DOTS;So;0;L;;;;;N;;;;; 1D109;MUSICAL SYMBOL DAL SEGNO;So;0;L;;;;;N;;;;; 1D10A;MUSICAL SYMBOL DA CAPO;So;0;L;;;;;N;;;;; 1D10B;MUSICAL SYMBOL SEGNO;So;0;L;;;;;N;;;;; 1D10C;MUSICAL SYMBOL CODA;So;0;L;;;;;N;;;;; 1D10D;MUSICAL SYMBOL REPEATED FIGURE-1;So;0;L;;;;;N;;;;; 1D10E;MUSICAL SYMBOL REPEATED FIGURE-2;So;0;L;;;;;N;;;;; 1D10F;MUSICAL SYMBOL REPEATED FIGURE-3;So;0;L;;;;;N;;;;; 1D110;MUSICAL SYMBOL FERMATA;So;0;L;;;;;N;;;;; 1D111;MUSICAL SYMBOL FERMATA BELOW;So;0;L;;;;;N;;;;; 1D112;MUSICAL SYMBOL BREATH MARK;So;0;L;;;;;N;;;;; 1D113;MUSICAL SYMBOL CAESURA;So;0;L;;;;;N;;;;; 1D114;MUSICAL SYMBOL BRACE;So;0;L;;;;;N;;;;; 1D115;MUSICAL SYMBOL BRACKET;So;0;L;;;;;N;;;;; 1D116;MUSICAL SYMBOL ONE-LINE STAFF;So;0;L;;;;;N;;;;; 1D117;MUSICAL SYMBOL TWO-LINE STAFF;So;0;L;;;;;N;;;;; 1D118;MUSICAL SYMBOL THREE-LINE STAFF;So;0;L;;;;;N;;;;; 1D119;MUSICAL SYMBOL FOUR-LINE STAFF;So;0;L;;;;;N;;;;; 1D11A;MUSICAL SYMBOL FIVE-LINE STAFF;So;0;L;;;;;N;;;;; 1D11B;MUSICAL SYMBOL SIX-LINE STAFF;So;0;L;;;;;N;;;;; 1D11C;MUSICAL SYMBOL SIX-STRING FRETBOARD;So;0;L;;;;;N;;;;; 1D11D;MUSICAL SYMBOL FOUR-STRING FRETBOARD;So;0;L;;;;;N;;;;; 1D11E;MUSICAL SYMBOL G CLEF;So;0;L;;;;;N;;;;; 1D11F;MUSICAL SYMBOL G CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;; 1D120;MUSICAL SYMBOL G CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;; 1D121;MUSICAL SYMBOL C CLEF;So;0;L;;;;;N;;;;; 1D122;MUSICAL SYMBOL F CLEF;So;0;L;;;;;N;;;;; 1D123;MUSICAL SYMBOL F CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;; 1D124;MUSICAL SYMBOL F CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;; 1D125;MUSICAL SYMBOL DRUM CLEF-1;So;0;L;;;;;N;;;;; 1D126;MUSICAL SYMBOL DRUM CLEF-2;So;0;L;;;;;N;;;;; 1D12A;MUSICAL SYMBOL DOUBLE SHARP;So;0;L;;;;;N;;;;; 1D12B;MUSICAL SYMBOL DOUBLE FLAT;So;0;L;;;;;N;;;;; 1D12C;MUSICAL SYMBOL FLAT UP;So;0;L;;;;;N;;;;; 1D12D;MUSICAL SYMBOL FLAT DOWN;So;0;L;;;;;N;;;;; 1D12E;MUSICAL SYMBOL NATURAL UP;So;0;L;;;;;N;;;;; 1D12F;MUSICAL SYMBOL NATURAL DOWN;So;0;L;;;;;N;;;;; 1D130;MUSICAL SYMBOL SHARP UP;So;0;L;;;;;N;;;;; 1D131;MUSICAL SYMBOL SHARP DOWN;So;0;L;;;;;N;;;;; 1D132;MUSICAL SYMBOL QUARTER TONE SHARP;So;0;L;;;;;N;;;;; 1D133;MUSICAL SYMBOL QUARTER TONE FLAT;So;0;L;;;;;N;;;;; 1D134;MUSICAL SYMBOL COMMON TIME;So;0;L;;;;;N;;;;; 1D135;MUSICAL SYMBOL CUT TIME;So;0;L;;;;;N;;;;; 1D136;MUSICAL SYMBOL OTTAVA ALTA;So;0;L;;;;;N;;;;; 1D137;MUSICAL SYMBOL OTTAVA BASSA;So;0;L;;;;;N;;;;; 1D138;MUSICAL SYMBOL QUINDICESIMA ALTA;So;0;L;;;;;N;;;;; 1D139;MUSICAL SYMBOL QUINDICESIMA BASSA;So;0;L;;;;;N;;;;; 1D13A;MUSICAL SYMBOL MULTI REST;So;0;L;;;;;N;;;;; 1D13B;MUSICAL SYMBOL WHOLE REST;So;0;L;;;;;N;;;;; 1D13C;MUSICAL SYMBOL HALF REST;So;0;L;;;;;N;;;;; 1D13D;MUSICAL SYMBOL QUARTER REST;So;0;L;;;;;N;;;;; 1D13E;MUSICAL SYMBOL EIGHTH REST;So;0;L;;;;;N;;;;; 1D13F;MUSICAL SYMBOL SIXTEENTH REST;So;0;L;;;;;N;;;;; 1D140;MUSICAL SYMBOL THIRTY-SECOND REST;So;0;L;;;;;N;;;;; 1D141;MUSICAL SYMBOL SIXTY-FOURTH REST;So;0;L;;;;;N;;;;; 1D142;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH REST;So;0;L;;;;;N;;;;; 1D143;MUSICAL SYMBOL X NOTEHEAD;So;0;L;;;;;N;;;;; 1D144;MUSICAL SYMBOL PLUS NOTEHEAD;So;0;L;;;;;N;;;;; 1D145;MUSICAL SYMBOL CIRCLE X NOTEHEAD;So;0;L;;;;;N;;;;; 1D146;MUSICAL SYMBOL SQUARE NOTEHEAD WHITE;So;0;L;;;;;N;;;;; 1D147;MUSICAL SYMBOL SQUARE NOTEHEAD BLACK;So;0;L;;;;;N;;;;; 1D148;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP WHITE;So;0;L;;;;;N;;;;; 1D149;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP BLACK;So;0;L;;;;;N;;;;; 1D14A;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT WHITE;So;0;L;;;;;N;;;;; 1D14B;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT BLACK;So;0;L;;;;;N;;;;; 1D14C;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT WHITE;So;0;L;;;;;N;;;;; 1D14D;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT BLACK;So;0;L;;;;;N;;;;; 1D14E;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;; 1D14F;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;; 1D150;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT WHITE;So;0;L;;;;;N;;;;; 1D151;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT BLACK;So;0;L;;;;;N;;;;; 1D152;MUSICAL SYMBOL MOON NOTEHEAD WHITE;So;0;L;;;;;N;;;;; 1D153;MUSICAL SYMBOL MOON NOTEHEAD BLACK;So;0;L;;;;;N;;;;; 1D154;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;; 1D155;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;; 1D156;MUSICAL SYMBOL PARENTHESIS NOTEHEAD;So;0;L;;;;;N;;;;; 1D157;MUSICAL SYMBOL VOID NOTEHEAD;So;0;L;;;;;N;;;;; 1D158;MUSICAL SYMBOL NOTEHEAD BLACK;So;0;L;;;;;N;;;;; 1D159;MUSICAL SYMBOL NULL NOTEHEAD;So;0;L;;;;;N;;;;; 1D15A;MUSICAL SYMBOL CLUSTER NOTEHEAD WHITE;So;0;L;;;;;N;;;;; 1D15B;MUSICAL SYMBOL CLUSTER NOTEHEAD BLACK;So;0;L;;;;;N;;;;; 1D15C;MUSICAL SYMBOL BREVE;So;0;L;;;;;N;;;;; 1D15D;MUSICAL SYMBOL WHOLE NOTE;So;0;L;;;;;N;;;;; 1D15E;MUSICAL SYMBOL HALF NOTE;So;0;L;1D157 1D165;;;;N;;;;; 1D15F;MUSICAL SYMBOL QUARTER NOTE;So;0;L;1D158 1D165;;;;N;;;;; 1D160;MUSICAL SYMBOL EIGHTH NOTE;So;0;L;1D15F 1D16E;;;;N;;;;; 1D161;MUSICAL SYMBOL SIXTEENTH NOTE;So;0;L;1D15F 1D16F;;;;N;;;;; 1D162;MUSICAL SYMBOL THIRTY-SECOND NOTE;So;0;L;1D15F 1D170;;;;N;;;;; 1D163;MUSICAL SYMBOL SIXTY-FOURTH NOTE;So;0;L;1D15F 1D171;;;;N;;;;; 1D164;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE;So;0;L;1D15F 1D172;;;;N;;;;; 1D165;MUSICAL SYMBOL COMBINING STEM;Mc;216;L;;;;;N;;;;; 1D166;MUSICAL SYMBOL COMBINING SPRECHGESANG STEM;Mc;216;L;;;;;N;;;;; 1D167;MUSICAL SYMBOL COMBINING TREMOLO-1;Mn;1;NSM;;;;;N;;;;; 1D168;MUSICAL SYMBOL COMBINING TREMOLO-2;Mn;1;NSM;;;;;N;;;;; 1D169;MUSICAL SYMBOL COMBINING TREMOLO-3;Mn;1;NSM;;;;;N;;;;; 1D16A;MUSICAL SYMBOL FINGERED TREMOLO-1;So;0;L;;;;;N;;;;; 1D16B;MUSICAL SYMBOL FINGERED TREMOLO-2;So;0;L;;;;;N;;;;; 1D16C;MUSICAL SYMBOL FINGERED TREMOLO-3;So;0;L;;;;;N;;;;; 1D16D;MUSICAL SYMBOL COMBINING AUGMENTATION DOT;Mc;226;L;;;;;N;;;;; 1D16E;MUSICAL SYMBOL COMBINING FLAG-1;Mc;216;L;;;;;N;;;;; 1D16F;MUSICAL SYMBOL COMBINING FLAG-2;Mc;216;L;;;;;N;;;;; 1D170;MUSICAL SYMBOL COMBINING FLAG-3;Mc;216;L;;;;;N;;;;; 1D171;MUSICAL SYMBOL COMBINING FLAG-4;Mc;216;L;;;;;N;;;;; 1D172;MUSICAL SYMBOL COMBINING FLAG-5;Mc;216;L;;;;;N;;;;; 1D173;MUSICAL SYMBOL BEGIN BEAM;Cf;0;BN;;;;;N;;;;; 1D174;MUSICAL SYMBOL END BEAM;Cf;0;BN;;;;;N;;;;; 1D175;MUSICAL SYMBOL BEGIN TIE;Cf;0;BN;;;;;N;;;;; 1D176;MUSICAL SYMBOL END TIE;Cf;0;BN;;;;;N;;;;; 1D177;MUSICAL SYMBOL BEGIN SLUR;Cf;0;BN;;;;;N;;;;; 1D178;MUSICAL SYMBOL END SLUR;Cf;0;BN;;;;;N;;;;; 1D179;MUSICAL SYMBOL BEGIN PHRASE;Cf;0;BN;;;;;N;;;;; 1D17A;MUSICAL SYMBOL END PHRASE;Cf;0;BN;;;;;N;;;;; 1D17B;MUSICAL SYMBOL COMBINING ACCENT;Mn;220;NSM;;;;;N;;;;; 1D17C;MUSICAL SYMBOL COMBINING STACCATO;Mn;220;NSM;;;;;N;;;;; 1D17D;MUSICAL SYMBOL COMBINING TENUTO;Mn;220;NSM;;;;;N;;;;; 1D17E;MUSICAL SYMBOL COMBINING STACCATISSIMO;Mn;220;NSM;;;;;N;;;;; 1D17F;MUSICAL SYMBOL COMBINING MARCATO;Mn;220;NSM;;;;;N;;;;; 1D180;MUSICAL SYMBOL COMBINING MARCATO-STACCATO;Mn;220;NSM;;;;;N;;;;; 1D181;MUSICAL SYMBOL COMBINING ACCENT-STACCATO;Mn;220;NSM;;;;;N;;;;; 1D182;MUSICAL SYMBOL COMBINING LOURE;Mn;220;NSM;;;;;N;;;;; 1D183;MUSICAL SYMBOL ARPEGGIATO UP;So;0;L;;;;;N;;;;; 1D184;MUSICAL SYMBOL ARPEGGIATO DOWN;So;0;L;;;;;N;;;;; 1D185;MUSICAL SYMBOL COMBINING DOIT;Mn;230;NSM;;;;;N;;;;; 1D186;MUSICAL SYMBOL COMBINING RIP;Mn;230;NSM;;;;;N;;;;; 1D187;MUSICAL SYMBOL COMBINING FLIP;Mn;230;NSM;;;;;N;;;;; 1D188;MUSICAL SYMBOL COMBINING SMEAR;Mn;230;NSM;;;;;N;;;;; 1D189;MUSICAL SYMBOL COMBINING BEND;Mn;230;NSM;;;;;N;;;;; 1D18A;MUSICAL SYMBOL COMBINING DOUBLE TONGUE;Mn;220;NSM;;;;;N;;;;; 1D18B;MUSICAL SYMBOL COMBINING TRIPLE TONGUE;Mn;220;NSM;;;;;N;;;;; 1D18C;MUSICAL SYMBOL RINFORZANDO;So;0;L;;;;;N;;;;; 1D18D;MUSICAL SYMBOL SUBITO;So;0;L;;;;;N;;;;; 1D18E;MUSICAL SYMBOL Z;So;0;L;;;;;N;;;;; 1D18F;MUSICAL SYMBOL PIANO;So;0;L;;;;;N;;;;; 1D190;MUSICAL SYMBOL MEZZO;So;0;L;;;;;N;;;;; 1D191;MUSICAL SYMBOL FORTE;So;0;L;;;;;N;;;;; 1D192;MUSICAL SYMBOL CRESCENDO;So;0;L;;;;;N;;;;; 1D193;MUSICAL SYMBOL DECRESCENDO;So;0;L;;;;;N;;;;; 1D194;MUSICAL SYMBOL GRACE NOTE SLASH;So;0;L;;;;;N;;;;; 1D195;MUSICAL SYMBOL GRACE NOTE NO SLASH;So;0;L;;;;;N;;;;; 1D196;MUSICAL SYMBOL TR;So;0;L;;;;;N;;;;; 1D197;MUSICAL SYMBOL TURN;So;0;L;;;;;N;;;;; 1D198;MUSICAL SYMBOL INVERTED TURN;So;0;L;;;;;N;;;;; 1D199;MUSICAL SYMBOL TURN SLASH;So;0;L;;;;;N;;;;; 1D19A;MUSICAL SYMBOL TURN UP;So;0;L;;;;;N;;;;; 1D19B;MUSICAL SYMBOL ORNAMENT STROKE-1;So;0;L;;;;;N;;;;; 1D19C;MUSICAL SYMBOL ORNAMENT STROKE-2;So;0;L;;;;;N;;;;; 1D19D;MUSICAL SYMBOL ORNAMENT STROKE-3;So;0;L;;;;;N;;;;; 1D19E;MUSICAL SYMBOL ORNAMENT STROKE-4;So;0;L;;;;;N;;;;; 1D19F;MUSICAL SYMBOL ORNAMENT STROKE-5;So;0;L;;;;;N;;;;; 1D1A0;MUSICAL SYMBOL ORNAMENT STROKE-6;So;0;L;;;;;N;;;;; 1D1A1;MUSICAL SYMBOL ORNAMENT STROKE-7;So;0;L;;;;;N;;;;; 1D1A2;MUSICAL SYMBOL ORNAMENT STROKE-8;So;0;L;;;;;N;;;;; 1D1A3;MUSICAL SYMBOL ORNAMENT STROKE-9;So;0;L;;;;;N;;;;; 1D1A4;MUSICAL SYMBOL ORNAMENT STROKE-10;So;0;L;;;;;N;;;;; 1D1A5;MUSICAL SYMBOL ORNAMENT STROKE-11;So;0;L;;;;;N;;;;; 1D1A6;MUSICAL SYMBOL HAUPTSTIMME;So;0;L;;;;;N;;;;; 1D1A7;MUSICAL SYMBOL NEBENSTIMME;So;0;L;;;;;N;;;;; 1D1A8;MUSICAL SYMBOL END OF STIMME;So;0;L;;;;;N;;;;; 1D1A9;MUSICAL SYMBOL DEGREE SLASH;So;0;L;;;;;N;;;;; 1D1AA;MUSICAL SYMBOL COMBINING DOWN BOW;Mn;230;NSM;;;;;N;;;;; 1D1AB;MUSICAL SYMBOL COMBINING UP BOW;Mn;230;NSM;;;;;N;;;;; 1D1AC;MUSICAL SYMBOL COMBINING HARMONIC;Mn;230;NSM;;;;;N;;;;; 1D1AD;MUSICAL SYMBOL COMBINING SNAP PIZZICATO;Mn;230;NSM;;;;;N;;;;; 1D1AE;MUSICAL SYMBOL PEDAL MARK;So;0;L;;;;;N;;;;; 1D1AF;MUSICAL SYMBOL PEDAL UP MARK;So;0;L;;;;;N;;;;; 1D1B0;MUSICAL SYMBOL HALF PEDAL MARK;So;0;L;;;;;N;;;;; 1D1B1;MUSICAL SYMBOL GLISSANDO UP;So;0;L;;;;;N;;;;; 1D1B2;MUSICAL SYMBOL GLISSANDO DOWN;So;0;L;;;;;N;;;;; 1D1B3;MUSICAL SYMBOL WITH FINGERNAILS;So;0;L;;;;;N;;;;; 1D1B4;MUSICAL SYMBOL DAMP;So;0;L;;;;;N;;;;; 1D1B5;MUSICAL SYMBOL DAMP ALL;So;0;L;;;;;N;;;;; 1D1B6;MUSICAL SYMBOL MAXIMA;So;0;L;;;;;N;;;;; 1D1B7;MUSICAL SYMBOL LONGA;So;0;L;;;;;N;;;;; 1D1B8;MUSICAL SYMBOL BREVIS;So;0;L;;;;;N;;;;; 1D1B9;MUSICAL SYMBOL SEMIBREVIS WHITE;So;0;L;;;;;N;;;;; 1D1BA;MUSICAL SYMBOL SEMIBREVIS BLACK;So;0;L;;;;;N;;;;; 1D1BB;MUSICAL SYMBOL MINIMA;So;0;L;1D1B9 1D165;;;;N;;;;; 1D1BC;MUSICAL SYMBOL MINIMA BLACK;So;0;L;1D1BA 1D165;;;;N;;;;; 1D1BD;MUSICAL SYMBOL SEMIMINIMA WHITE;So;0;L;1D1BB 1D16E;;;;N;;;;; 1D1BE;MUSICAL SYMBOL SEMIMINIMA BLACK;So;0;L;1D1BC 1D16E;;;;N;;;;; 1D1BF;MUSICAL SYMBOL FUSA WHITE;So;0;L;1D1BB 1D16F;;;;N;;;;; 1D1C0;MUSICAL SYMBOL FUSA BLACK;So;0;L;1D1BC 1D16F;;;;N;;;;; 1D1C1;MUSICAL SYMBOL LONGA PERFECTA REST;So;0;L;;;;;N;;;;; 1D1C2;MUSICAL SYMBOL LONGA IMPERFECTA REST;So;0;L;;;;;N;;;;; 1D1C3;MUSICAL SYMBOL BREVIS REST;So;0;L;;;;;N;;;;; 1D1C4;MUSICAL SYMBOL SEMIBREVIS REST;So;0;L;;;;;N;;;;; 1D1C5;MUSICAL SYMBOL MINIMA REST;So;0;L;;;;;N;;;;; 1D1C6;MUSICAL SYMBOL SEMIMINIMA REST;So;0;L;;;;;N;;;;; 1D1C7;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;; 1D1C8;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;; 1D1C9;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;; 1D1CA;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;; 1D1CB;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;; 1D1CC;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;; 1D1CD;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-2;So;0;L;;;;;N;;;;; 1D1CE;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-3;So;0;L;;;;;N;;;;; 1D1CF;MUSICAL SYMBOL CROIX;So;0;L;;;;;N;;;;; 1D1D0;MUSICAL SYMBOL GREGORIAN C CLEF;So;0;L;;;;;N;;;;; 1D1D1;MUSICAL SYMBOL GREGORIAN F CLEF;So;0;L;;;;;N;;;;; 1D1D2;MUSICAL SYMBOL SQUARE B;So;0;L;;;;;N;;;;; 1D1D3;MUSICAL SYMBOL VIRGA;So;0;L;;;;;N;;;;; 1D1D4;MUSICAL SYMBOL PODATUS;So;0;L;;;;;N;;;;; 1D1D5;MUSICAL SYMBOL CLIVIS;So;0;L;;;;;N;;;;; 1D1D6;MUSICAL SYMBOL SCANDICUS;So;0;L;;;;;N;;;;; 1D1D7;MUSICAL SYMBOL CLIMACUS;So;0;L;;;;;N;;;;; 1D1D8;MUSICAL SYMBOL TORCULUS;So;0;L;;;;;N;;;;; 1D1D9;MUSICAL SYMBOL PORRECTUS;So;0;L;;;;;N;;;;; 1D1DA;MUSICAL SYMBOL PORRECTUS FLEXUS;So;0;L;;;;;N;;;;; 1D1DB;MUSICAL SYMBOL SCANDICUS FLEXUS;So;0;L;;;;;N;;;;; 1D1DC;MUSICAL SYMBOL TORCULUS RESUPINUS;So;0;L;;;;;N;;;;; 1D1DD;MUSICAL SYMBOL PES SUBPUNCTIS;So;0;L;;;;;N;;;;; 1D400;MATHEMATICAL BOLD CAPITAL A;Lu;0;L; 0041;;;;N;;;;; 1D401;MATHEMATICAL BOLD CAPITAL B;Lu;0;L; 0042;;;;N;;;;; 1D402;MATHEMATICAL BOLD CAPITAL C;Lu;0;L; 0043;;;;N;;;;; 1D403;MATHEMATICAL BOLD CAPITAL D;Lu;0;L; 0044;;;;N;;;;; 1D404;MATHEMATICAL BOLD CAPITAL E;Lu;0;L; 0045;;;;N;;;;; 1D405;MATHEMATICAL BOLD CAPITAL F;Lu;0;L; 0046;;;;N;;;;; 1D406;MATHEMATICAL BOLD CAPITAL G;Lu;0;L; 0047;;;;N;;;;; 1D407;MATHEMATICAL BOLD CAPITAL H;Lu;0;L; 0048;;;;N;;;;; 1D408;MATHEMATICAL BOLD CAPITAL I;Lu;0;L; 0049;;;;N;;;;; 1D409;MATHEMATICAL BOLD CAPITAL J;Lu;0;L; 004A;;;;N;;;;; 1D40A;MATHEMATICAL BOLD CAPITAL K;Lu;0;L; 004B;;;;N;;;;; 1D40B;MATHEMATICAL BOLD CAPITAL L;Lu;0;L; 004C;;;;N;;;;; 1D40C;MATHEMATICAL BOLD CAPITAL M;Lu;0;L; 004D;;;;N;;;;; 1D40D;MATHEMATICAL BOLD CAPITAL N;Lu;0;L; 004E;;;;N;;;;; 1D40E;MATHEMATICAL BOLD CAPITAL O;Lu;0;L; 004F;;;;N;;;;; 1D40F;MATHEMATICAL BOLD CAPITAL P;Lu;0;L; 0050;;;;N;;;;; 1D410;MATHEMATICAL BOLD CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; 1D411;MATHEMATICAL BOLD CAPITAL R;Lu;0;L; 0052;;;;N;;;;; 1D412;MATHEMATICAL BOLD CAPITAL S;Lu;0;L; 0053;;;;N;;;;; 1D413;MATHEMATICAL BOLD CAPITAL T;Lu;0;L; 0054;;;;N;;;;; 1D414;MATHEMATICAL BOLD CAPITAL U;Lu;0;L; 0055;;;;N;;;;; 1D415;MATHEMATICAL BOLD CAPITAL V;Lu;0;L; 0056;;;;N;;;;; 1D416;MATHEMATICAL BOLD CAPITAL W;Lu;0;L; 0057;;;;N;;;;; 1D417;MATHEMATICAL BOLD CAPITAL X;Lu;0;L; 0058;;;;N;;;;; 1D418;MATHEMATICAL BOLD CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; 1D419;MATHEMATICAL BOLD CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; 1D41A;MATHEMATICAL BOLD SMALL A;Ll;0;L; 0061;;;;N;;;;; 1D41B;MATHEMATICAL BOLD SMALL B;Ll;0;L; 0062;;;;N;;;;; 1D41C;MATHEMATICAL BOLD SMALL C;Ll;0;L; 0063;;;;N;;;;; 1D41D;MATHEMATICAL BOLD SMALL D;Ll;0;L; 0064;;;;N;;;;; 1D41E;MATHEMATICAL BOLD SMALL E;Ll;0;L; 0065;;;;N;;;;; 1D41F;MATHEMATICAL BOLD SMALL F;Ll;0;L; 0066;;;;N;;;;; 1D420;MATHEMATICAL BOLD SMALL G;Ll;0;L; 0067;;;;N;;;;; 1D421;MATHEMATICAL BOLD SMALL H;Ll;0;L; 0068;;;;N;;;;; 1D422;MATHEMATICAL BOLD SMALL I;Ll;0;L; 0069;;;;N;;;;; 1D423;MATHEMATICAL BOLD SMALL J;Ll;0;L; 006A;;;;N;;;;; 1D424;MATHEMATICAL BOLD SMALL K;Ll;0;L; 006B;;;;N;;;;; 1D425;MATHEMATICAL BOLD SMALL L;Ll;0;L; 006C;;;;N;;;;; 1D426;MATHEMATICAL BOLD SMALL M;Ll;0;L; 006D;;;;N;;;;; 1D427;MATHEMATICAL BOLD SMALL N;Ll;0;L; 006E;;;;N;;;;; 1D428;MATHEMATICAL BOLD SMALL O;Ll;0;L; 006F;;;;N;;;;; 1D429;MATHEMATICAL BOLD SMALL P;Ll;0;L; 0070;;;;N;;;;; 1D42A;MATHEMATICAL BOLD SMALL Q;Ll;0;L; 0071;;;;N;;;;; 1D42B;MATHEMATICAL BOLD SMALL R;Ll;0;L; 0072;;;;N;;;;; 1D42C;MATHEMATICAL BOLD SMALL S;Ll;0;L; 0073;;;;N;;;;; 1D42D;MATHEMATICAL BOLD SMALL T;Ll;0;L; 0074;;;;N;;;;; 1D42E;MATHEMATICAL BOLD SMALL U;Ll;0;L; 0075;;;;N;;;;; 1D42F;MATHEMATICAL BOLD SMALL V;Ll;0;L; 0076;;;;N;;;;; 1D430;MATHEMATICAL BOLD SMALL W;Ll;0;L; 0077;;;;N;;;;; 1D431;MATHEMATICAL BOLD SMALL X;Ll;0;L; 0078;;;;N;;;;; 1D432;MATHEMATICAL BOLD SMALL Y;Ll;0;L; 0079;;;;N;;;;; 1D433;MATHEMATICAL BOLD SMALL Z;Ll;0;L; 007A;;;;N;;;;; 1D434;MATHEMATICAL ITALIC CAPITAL A;Lu;0;L; 0041;;;;N;;;;; 1D435;MATHEMATICAL ITALIC CAPITAL B;Lu;0;L; 0042;;;;N;;;;; 1D436;MATHEMATICAL ITALIC CAPITAL C;Lu;0;L; 0043;;;;N;;;;; 1D437;MATHEMATICAL ITALIC CAPITAL D;Lu;0;L; 0044;;;;N;;;;; 1D438;MATHEMATICAL ITALIC CAPITAL E;Lu;0;L; 0045;;;;N;;;;; 1D439;MATHEMATICAL ITALIC CAPITAL F;Lu;0;L; 0046;;;;N;;;;; 1D43A;MATHEMATICAL ITALIC CAPITAL G;Lu;0;L; 0047;;;;N;;;;; 1D43B;MATHEMATICAL ITALIC CAPITAL H;Lu;0;L; 0048;;;;N;;;;; 1D43C;MATHEMATICAL ITALIC CAPITAL I;Lu;0;L; 0049;;;;N;;;;; 1D43D;MATHEMATICAL ITALIC CAPITAL J;Lu;0;L; 004A;;;;N;;;;; 1D43E;MATHEMATICAL ITALIC CAPITAL K;Lu;0;L; 004B;;;;N;;;;; 1D43F;MATHEMATICAL ITALIC CAPITAL L;Lu;0;L; 004C;;;;N;;;;; 1D440;MATHEMATICAL ITALIC CAPITAL M;Lu;0;L; 004D;;;;N;;;;; 1D441;MATHEMATICAL ITALIC CAPITAL N;Lu;0;L; 004E;;;;N;;;;; 1D442;MATHEMATICAL ITALIC CAPITAL O;Lu;0;L; 004F;;;;N;;;;; 1D443;MATHEMATICAL ITALIC CAPITAL P;Lu;0;L; 0050;;;;N;;;;; 1D444;MATHEMATICAL ITALIC CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; 1D445;MATHEMATICAL ITALIC CAPITAL R;Lu;0;L; 0052;;;;N;;;;; 1D446;MATHEMATICAL ITALIC CAPITAL S;Lu;0;L; 0053;;;;N;;;;; 1D447;MATHEMATICAL ITALIC CAPITAL T;Lu;0;L; 0054;;;;N;;;;; 1D448;MATHEMATICAL ITALIC CAPITAL U;Lu;0;L; 0055;;;;N;;;;; 1D449;MATHEMATICAL ITALIC CAPITAL V;Lu;0;L; 0056;;;;N;;;;; 1D44A;MATHEMATICAL ITALIC CAPITAL W;Lu;0;L; 0057;;;;N;;;;; 1D44B;MATHEMATICAL ITALIC CAPITAL X;Lu;0;L; 0058;;;;N;;;;; 1D44C;MATHEMATICAL ITALIC CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; 1D44D;MATHEMATICAL ITALIC CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; 1D44E;MATHEMATICAL ITALIC SMALL A;Ll;0;L; 0061;;;;N;;;;; 1D44F;MATHEMATICAL ITALIC SMALL B;Ll;0;L; 0062;;;;N;;;;; 1D450;MATHEMATICAL ITALIC SMALL C;Ll;0;L; 0063;;;;N;;;;; 1D451;MATHEMATICAL ITALIC SMALL D;Ll;0;L; 0064;;;;N;;;;; 1D452;MATHEMATICAL ITALIC SMALL E;Ll;0;L; 0065;;;;N;;;;; 1D453;MATHEMATICAL ITALIC SMALL F;Ll;0;L; 0066;;;;N;;;;; 1D454;MATHEMATICAL ITALIC SMALL G;Ll;0;L; 0067;;;;N;;;;; 1D456;MATHEMATICAL ITALIC SMALL I;Ll;0;L; 0069;;;;N;;;;; 1D457;MATHEMATICAL ITALIC SMALL J;Ll;0;L; 006A;;;;N;;;;; 1D458;MATHEMATICAL ITALIC SMALL K;Ll;0;L; 006B;;;;N;;;;; 1D459;MATHEMATICAL ITALIC SMALL L;Ll;0;L; 006C;;;;N;;;;; 1D45A;MATHEMATICAL ITALIC SMALL M;Ll;0;L; 006D;;;;N;;;;; 1D45B;MATHEMATICAL ITALIC SMALL N;Ll;0;L; 006E;;;;N;;;;; 1D45C;MATHEMATICAL ITALIC SMALL O;Ll;0;L; 006F;;;;N;;;;; 1D45D;MATHEMATICAL ITALIC SMALL P;Ll;0;L; 0070;;;;N;;;;; 1D45E;MATHEMATICAL ITALIC SMALL Q;Ll;0;L; 0071;;;;N;;;;; 1D45F;MATHEMATICAL ITALIC SMALL R;Ll;0;L; 0072;;;;N;;;;; 1D460;MATHEMATICAL ITALIC SMALL S;Ll;0;L; 0073;;;;N;;;;; 1D461;MATHEMATICAL ITALIC SMALL T;Ll;0;L; 0074;;;;N;;;;; 1D462;MATHEMATICAL ITALIC SMALL U;Ll;0;L; 0075;;;;N;;;;; 1D463;MATHEMATICAL ITALIC SMALL V;Ll;0;L; 0076;;;;N;;;;; 1D464;MATHEMATICAL ITALIC SMALL W;Ll;0;L; 0077;;;;N;;;;; 1D465;MATHEMATICAL ITALIC SMALL X;Ll;0;L; 0078;;;;N;;;;; 1D466;MATHEMATICAL ITALIC SMALL Y;Ll;0;L; 0079;;;;N;;;;; 1D467;MATHEMATICAL ITALIC SMALL Z;Ll;0;L; 007A;;;;N;;;;; 1D468;MATHEMATICAL BOLD ITALIC CAPITAL A;Lu;0;L; 0041;;;;N;;;;; 1D469;MATHEMATICAL BOLD ITALIC CAPITAL B;Lu;0;L; 0042;;;;N;;;;; 1D46A;MATHEMATICAL BOLD ITALIC CAPITAL C;Lu;0;L; 0043;;;;N;;;;; 1D46B;MATHEMATICAL BOLD ITALIC CAPITAL D;Lu;0;L; 0044;;;;N;;;;; 1D46C;MATHEMATICAL BOLD ITALIC CAPITAL E;Lu;0;L; 0045;;;;N;;;;; 1D46D;MATHEMATICAL BOLD ITALIC CAPITAL F;Lu;0;L; 0046;;;;N;;;;; 1D46E;MATHEMATICAL BOLD ITALIC CAPITAL G;Lu;0;L; 0047;;;;N;;;;; 1D46F;MATHEMATICAL BOLD ITALIC CAPITAL H;Lu;0;L; 0048;;;;N;;;;; 1D470;MATHEMATICAL BOLD ITALIC CAPITAL I;Lu;0;L; 0049;;;;N;;;;; 1D471;MATHEMATICAL BOLD ITALIC CAPITAL J;Lu;0;L; 004A;;;;N;;;;; 1D472;MATHEMATICAL BOLD ITALIC CAPITAL K;Lu;0;L; 004B;;;;N;;;;; 1D473;MATHEMATICAL BOLD ITALIC CAPITAL L;Lu;0;L; 004C;;;;N;;;;; 1D474;MATHEMATICAL BOLD ITALIC CAPITAL M;Lu;0;L; 004D;;;;N;;;;; 1D475;MATHEMATICAL BOLD ITALIC CAPITAL N;Lu;0;L; 004E;;;;N;;;;; 1D476;MATHEMATICAL BOLD ITALIC CAPITAL O;Lu;0;L; 004F;;;;N;;;;; 1D477;MATHEMATICAL BOLD ITALIC CAPITAL P;Lu;0;L; 0050;;;;N;;;;; 1D478;MATHEMATICAL BOLD ITALIC CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; 1D479;MATHEMATICAL BOLD ITALIC CAPITAL R;Lu;0;L; 0052;;;;N;;;;; 1D47A;MATHEMATICAL BOLD ITALIC CAPITAL S;Lu;0;L; 0053;;;;N;;;;; 1D47B;MATHEMATICAL BOLD ITALIC CAPITAL T;Lu;0;L; 0054;;;;N;;;;; 1D47C;MATHEMATICAL BOLD ITALIC CAPITAL U;Lu;0;L; 0055;;;;N;;;;; 1D47D;MATHEMATICAL BOLD ITALIC CAPITAL V;Lu;0;L; 0056;;;;N;;;;; 1D47E;MATHEMATICAL BOLD ITALIC CAPITAL W;Lu;0;L; 0057;;;;N;;;;; 1D47F;MATHEMATICAL BOLD ITALIC CAPITAL X;Lu;0;L; 0058;;;;N;;;;; 1D480;MATHEMATICAL BOLD ITALIC CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; 1D481;MATHEMATICAL BOLD ITALIC CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; 1D482;MATHEMATICAL BOLD ITALIC SMALL A;Ll;0;L; 0061;;;;N;;;;; 1D483;MATHEMATICAL BOLD ITALIC SMALL B;Ll;0;L; 0062;;;;N;;;;; 1D484;MATHEMATICAL BOLD ITALIC SMALL C;Ll;0;L; 0063;;;;N;;;;; 1D485;MATHEMATICAL BOLD ITALIC SMALL D;Ll;0;L; 0064;;;;N;;;;; 1D486;MATHEMATICAL BOLD ITALIC SMALL E;Ll;0;L; 0065;;;;N;;;;; 1D487;MATHEMATICAL BOLD ITALIC SMALL F;Ll;0;L; 0066;;;;N;;;;; 1D488;MATHEMATICAL BOLD ITALIC SMALL G;Ll;0;L; 0067;;;;N;;;;; 1D489;MATHEMATICAL BOLD ITALIC SMALL H;Ll;0;L; 0068;;;;N;;;;; 1D48A;MATHEMATICAL BOLD ITALIC SMALL I;Ll;0;L; 0069;;;;N;;;;; 1D48B;MATHEMATICAL BOLD ITALIC SMALL J;Ll;0;L; 006A;;;;N;;;;; 1D48C;MATHEMATICAL BOLD ITALIC SMALL K;Ll;0;L; 006B;;;;N;;;;; 1D48D;MATHEMATICAL BOLD ITALIC SMALL L;Ll;0;L; 006C;;;;N;;;;; 1D48E;MATHEMATICAL BOLD ITALIC SMALL M;Ll;0;L; 006D;;;;N;;;;; 1D48F;MATHEMATICAL BOLD ITALIC SMALL N;Ll;0;L; 006E;;;;N;;;;; 1D490;MATHEMATICAL BOLD ITALIC SMALL O;Ll;0;L; 006F;;;;N;;;;; 1D491;MATHEMATICAL BOLD ITALIC SMALL P;Ll;0;L; 0070;;;;N;;;;; 1D492;MATHEMATICAL BOLD ITALIC SMALL Q;Ll;0;L; 0071;;;;N;;;;; 1D493;MATHEMATICAL BOLD ITALIC SMALL R;Ll;0;L; 0072;;;;N;;;;; 1D494;MATHEMATICAL BOLD ITALIC SMALL S;Ll;0;L; 0073;;;;N;;;;; 1D495;MATHEMATICAL BOLD ITALIC SMALL T;Ll;0;L; 0074;;;;N;;;;; 1D496;MATHEMATICAL BOLD ITALIC SMALL U;Ll;0;L; 0075;;;;N;;;;; 1D497;MATHEMATICAL BOLD ITALIC SMALL V;Ll;0;L; 0076;;;;N;;;;; 1D498;MATHEMATICAL BOLD ITALIC SMALL W;Ll;0;L; 0077;;;;N;;;;; 1D499;MATHEMATICAL BOLD ITALIC SMALL X;Ll;0;L; 0078;;;;N;;;;; 1D49A;MATHEMATICAL BOLD ITALIC SMALL Y;Ll;0;L; 0079;;;;N;;;;; 1D49B;MATHEMATICAL BOLD ITALIC SMALL Z;Ll;0;L; 007A;;;;N;;;;; 1D49C;MATHEMATICAL SCRIPT CAPITAL A;Lu;0;L; 0041;;;;N;;;;; 1D49E;MATHEMATICAL SCRIPT CAPITAL C;Lu;0;L; 0043;;;;N;;;;; 1D49F;MATHEMATICAL SCRIPT CAPITAL D;Lu;0;L; 0044;;;;N;;;;; 1D4A2;MATHEMATICAL SCRIPT CAPITAL G;Lu;0;L; 0047;;;;N;;;;; 1D4A5;MATHEMATICAL SCRIPT CAPITAL J;Lu;0;L; 004A;;;;N;;;;; 1D4A6;MATHEMATICAL SCRIPT CAPITAL K;Lu;0;L; 004B;;;;N;;;;; 1D4A9;MATHEMATICAL SCRIPT CAPITAL N;Lu;0;L; 004E;;;;N;;;;; 1D4AA;MATHEMATICAL SCRIPT CAPITAL O;Lu;0;L; 004F;;;;N;;;;; 1D4AB;MATHEMATICAL SCRIPT CAPITAL P;Lu;0;L; 0050;;;;N;;;;; 1D4AC;MATHEMATICAL SCRIPT CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; 1D4AE;MATHEMATICAL SCRIPT CAPITAL S;Lu;0;L; 0053;;;;N;;;;; 1D4AF;MATHEMATICAL SCRIPT CAPITAL T;Lu;0;L; 0054;;;;N;;;;; 1D4B0;MATHEMATICAL SCRIPT CAPITAL U;Lu;0;L; 0055;;;;N;;;;; 1D4B1;MATHEMATICAL SCRIPT CAPITAL V;Lu;0;L; 0056;;;;N;;;;; 1D4B2;MATHEMATICAL SCRIPT CAPITAL W;Lu;0;L; 0057;;;;N;;;;; 1D4B3;MATHEMATICAL SCRIPT CAPITAL X;Lu;0;L; 0058;;;;N;;;;; 1D4B4;MATHEMATICAL SCRIPT CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; 1D4B5;MATHEMATICAL SCRIPT CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; 1D4B6;MATHEMATICAL SCRIPT SMALL A;Ll;0;L; 0061;;;;N;;;;; 1D4B7;MATHEMATICAL SCRIPT SMALL B;Ll;0;L; 0062;;;;N;;;;; 1D4B8;MATHEMATICAL SCRIPT SMALL C;Ll;0;L; 0063;;;;N;;;;; 1D4B9;MATHEMATICAL SCRIPT SMALL D;Ll;0;L; 0064;;;;N;;;;; 1D4BB;MATHEMATICAL SCRIPT SMALL F;Ll;0;L; 0066;;;;N;;;;; 1D4BD;MATHEMATICAL SCRIPT SMALL H;Ll;0;L; 0068;;;;N;;;;; 1D4BE;MATHEMATICAL SCRIPT SMALL I;Ll;0;L; 0069;;;;N;;;;; 1D4BF;MATHEMATICAL SCRIPT SMALL J;Ll;0;L; 006A;;;;N;;;;; 1D4C0;MATHEMATICAL SCRIPT SMALL K;Ll;0;L; 006B;;;;N;;;;; 1D4C2;MATHEMATICAL SCRIPT SMALL M;Ll;0;L; 006D;;;;N;;;;; 1D4C3;MATHEMATICAL SCRIPT SMALL N;Ll;0;L; 006E;;;;N;;;;; 1D4C5;MATHEMATICAL SCRIPT SMALL P;Ll;0;L; 0070;;;;N;;;;; 1D4C6;MATHEMATICAL SCRIPT SMALL Q;Ll;0;L; 0071;;;;N;;;;; 1D4C7;MATHEMATICAL SCRIPT SMALL R;Ll;0;L; 0072;;;;N;;;;; 1D4C8;MATHEMATICAL SCRIPT SMALL S;Ll;0;L; 0073;;;;N;;;;; 1D4C9;MATHEMATICAL SCRIPT SMALL T;Ll;0;L; 0074;;;;N;;;;; 1D4CA;MATHEMATICAL SCRIPT SMALL U;Ll;0;L; 0075;;;;N;;;;; 1D4CB;MATHEMATICAL SCRIPT SMALL V;Ll;0;L; 0076;;;;N;;;;; 1D4CC;MATHEMATICAL SCRIPT SMALL W;Ll;0;L; 0077;;;;N;;;;; 1D4CD;MATHEMATICAL SCRIPT SMALL X;Ll;0;L; 0078;;;;N;;;;; 1D4CE;MATHEMATICAL SCRIPT SMALL Y;Ll;0;L; 0079;;;;N;;;;; 1D4CF;MATHEMATICAL SCRIPT SMALL Z;Ll;0;L; 007A;;;;N;;;;; 1D4D0;MATHEMATICAL BOLD SCRIPT CAPITAL A;Lu;0;L; 0041;;;;N;;;;; 1D4D1;MATHEMATICAL BOLD SCRIPT CAPITAL B;Lu;0;L; 0042;;;;N;;;;; 1D4D2;MATHEMATICAL BOLD SCRIPT CAPITAL C;Lu;0;L; 0043;;;;N;;;;; 1D4D3;MATHEMATICAL BOLD SCRIPT CAPITAL D;Lu;0;L; 0044;;;;N;;;;; 1D4D4;MATHEMATICAL BOLD SCRIPT CAPITAL E;Lu;0;L; 0045;;;;N;;;;; 1D4D5;MATHEMATICAL BOLD SCRIPT CAPITAL F;Lu;0;L; 0046;;;;N;;;;; 1D4D6;MATHEMATICAL BOLD SCRIPT CAPITAL G;Lu;0;L; 0047;;;;N;;;;; 1D4D7;MATHEMATICAL BOLD SCRIPT CAPITAL H;Lu;0;L; 0048;;;;N;;;;; 1D4D8;MATHEMATICAL BOLD SCRIPT CAPITAL I;Lu;0;L; 0049;;;;N;;;;; 1D4D9;MATHEMATICAL BOLD SCRIPT CAPITAL J;Lu;0;L; 004A;;;;N;;;;; 1D4DA;MATHEMATICAL BOLD SCRIPT CAPITAL K;Lu;0;L; 004B;;;;N;;;;; 1D4DB;MATHEMATICAL BOLD SCRIPT CAPITAL L;Lu;0;L; 004C;;;;N;;;;; 1D4DC;MATHEMATICAL BOLD SCRIPT CAPITAL M;Lu;0;L; 004D;;;;N;;;;; 1D4DD;MATHEMATICAL BOLD SCRIPT CAPITAL N;Lu;0;L; 004E;;;;N;;;;; 1D4DE;MATHEMATICAL BOLD SCRIPT CAPITAL O;Lu;0;L; 004F;;;;N;;;;; 1D4DF;MATHEMATICAL BOLD SCRIPT CAPITAL P;Lu;0;L; 0050;;;;N;;;;; 1D4E0;MATHEMATICAL BOLD SCRIPT CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; 1D4E1;MATHEMATICAL BOLD SCRIPT CAPITAL R;Lu;0;L; 0052;;;;N;;;;; 1D4E2;MATHEMATICAL BOLD SCRIPT CAPITAL S;Lu;0;L; 0053;;;;N;;;;; 1D4E3;MATHEMATICAL BOLD SCRIPT CAPITAL T;Lu;0;L; 0054;;;;N;;;;; 1D4E4;MATHEMATICAL BOLD SCRIPT CAPITAL U;Lu;0;L; 0055;;;;N;;;;; 1D4E5;MATHEMATICAL BOLD SCRIPT CAPITAL V;Lu;0;L; 0056;;;;N;;;;; 1D4E6;MATHEMATICAL BOLD SCRIPT CAPITAL W;Lu;0;L; 0057;;;;N;;;;; 1D4E7;MATHEMATICAL BOLD SCRIPT CAPITAL X;Lu;0;L; 0058;;;;N;;;;; 1D4E8;MATHEMATICAL BOLD SCRIPT CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; 1D4E9;MATHEMATICAL BOLD SCRIPT CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; 1D4EA;MATHEMATICAL BOLD SCRIPT SMALL A;Ll;0;L; 0061;;;;N;;;;; 1D4EB;MATHEMATICAL BOLD SCRIPT SMALL B;Ll;0;L; 0062;;;;N;;;;; 1D4EC;MATHEMATICAL BOLD SCRIPT SMALL C;Ll;0;L; 0063;;;;N;;;;; 1D4ED;MATHEMATICAL BOLD SCRIPT SMALL D;Ll;0;L; 0064;;;;N;;;;; 1D4EE;MATHEMATICAL BOLD SCRIPT SMALL E;Ll;0;L; 0065;;;;N;;;;; 1D4EF;MATHEMATICAL BOLD SCRIPT SMALL F;Ll;0;L; 0066;;;;N;;;;; 1D4F0;MATHEMATICAL BOLD SCRIPT SMALL G;Ll;0;L; 0067;;;;N;;;;; 1D4F1;MATHEMATICAL BOLD SCRIPT SMALL H;Ll;0;L; 0068;;;;N;;;;; 1D4F2;MATHEMATICAL BOLD SCRIPT SMALL I;Ll;0;L; 0069;;;;N;;;;; 1D4F3;MATHEMATICAL BOLD SCRIPT SMALL J;Ll;0;L; 006A;;;;N;;;;; 1D4F4;MATHEMATICAL BOLD SCRIPT SMALL K;Ll;0;L; 006B;;;;N;;;;; 1D4F5;MATHEMATICAL BOLD SCRIPT SMALL L;Ll;0;L; 006C;;;;N;;;;; 1D4F6;MATHEMATICAL BOLD SCRIPT SMALL M;Ll;0;L; 006D;;;;N;;;;; 1D4F7;MATHEMATICAL BOLD SCRIPT SMALL N;Ll;0;L; 006E;;;;N;;;;; 1D4F8;MATHEMATICAL BOLD SCRIPT SMALL O;Ll;0;L; 006F;;;;N;;;;; 1D4F9;MATHEMATICAL BOLD SCRIPT SMALL P;Ll;0;L; 0070;;;;N;;;;; 1D4FA;MATHEMATICAL BOLD SCRIPT SMALL Q;Ll;0;L; 0071;;;;N;;;;; 1D4FB;MATHEMATICAL BOLD SCRIPT SMALL R;Ll;0;L; 0072;;;;N;;;;; 1D4FC;MATHEMATICAL BOLD SCRIPT SMALL S;Ll;0;L; 0073;;;;N;;;;; 1D4FD;MATHEMATICAL BOLD SCRIPT SMALL T;Ll;0;L; 0074;;;;N;;;;; 1D4FE;MATHEMATICAL BOLD SCRIPT SMALL U;Ll;0;L; 0075;;;;N;;;;; 1D4FF;MATHEMATICAL BOLD SCRIPT SMALL V;Ll;0;L; 0076;;;;N;;;;; 1D500;MATHEMATICAL BOLD SCRIPT SMALL W;Ll;0;L; 0077;;;;N;;;;; 1D501;MATHEMATICAL BOLD SCRIPT SMALL X;Ll;0;L; 0078;;;;N;;;;; 1D502;MATHEMATICAL BOLD SCRIPT SMALL Y;Ll;0;L; 0079;;;;N;;;;; 1D503;MATHEMATICAL BOLD SCRIPT SMALL Z;Ll;0;L; 007A;;;;N;;;;; 1D504;MATHEMATICAL FRAKTUR CAPITAL A;Lu;0;L; 0041;;;;N;;;;; 1D505;MATHEMATICAL FRAKTUR CAPITAL B;Lu;0;L; 0042;;;;N;;;;; 1D507;MATHEMATICAL FRAKTUR CAPITAL D;Lu;0;L; 0044;;;;N;;;;; 1D508;MATHEMATICAL FRAKTUR CAPITAL E;Lu;0;L; 0045;;;;N;;;;; 1D509;MATHEMATICAL FRAKTUR CAPITAL F;Lu;0;L; 0046;;;;N;;;;; 1D50A;MATHEMATICAL FRAKTUR CAPITAL G;Lu;0;L; 0047;;;;N;;;;; 1D50D;MATHEMATICAL FRAKTUR CAPITAL J;Lu;0;L; 004A;;;;N;;;;; 1D50E;MATHEMATICAL FRAKTUR CAPITAL K;Lu;0;L; 004B;;;;N;;;;; 1D50F;MATHEMATICAL FRAKTUR CAPITAL L;Lu;0;L; 004C;;;;N;;;;; 1D510;MATHEMATICAL FRAKTUR CAPITAL M;Lu;0;L; 004D;;;;N;;;;; 1D511;MATHEMATICAL FRAKTUR CAPITAL N;Lu;0;L; 004E;;;;N;;;;; 1D512;MATHEMATICAL FRAKTUR CAPITAL O;Lu;0;L; 004F;;;;N;;;;; 1D513;MATHEMATICAL FRAKTUR CAPITAL P;Lu;0;L; 0050;;;;N;;;;; 1D514;MATHEMATICAL FRAKTUR CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; 1D516;MATHEMATICAL FRAKTUR CAPITAL S;Lu;0;L; 0053;;;;N;;;;; 1D517;MATHEMATICAL FRAKTUR CAPITAL T;Lu;0;L; 0054;;;;N;;;;; 1D518;MATHEMATICAL FRAKTUR CAPITAL U;Lu;0;L; 0055;;;;N;;;;; 1D519;MATHEMATICAL FRAKTUR CAPITAL V;Lu;0;L; 0056;;;;N;;;;; 1D51A;MATHEMATICAL FRAKTUR CAPITAL W;Lu;0;L; 0057;;;;N;;;;; 1D51B;MATHEMATICAL FRAKTUR CAPITAL X;Lu;0;L; 0058;;;;N;;;;; 1D51C;MATHEMATICAL FRAKTUR CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; 1D51E;MATHEMATICAL FRAKTUR SMALL A;Ll;0;L; 0061;;;;N;;;;; 1D51F;MATHEMATICAL FRAKTUR SMALL B;Ll;0;L; 0062;;;;N;;;;; 1D520;MATHEMATICAL FRAKTUR SMALL C;Ll;0;L; 0063;;;;N;;;;; 1D521;MATHEMATICAL FRAKTUR SMALL D;Ll;0;L; 0064;;;;N;;;;; 1D522;MATHEMATICAL FRAKTUR SMALL E;Ll;0;L; 0065;;;;N;;;;; 1D523;MATHEMATICAL FRAKTUR SMALL F;Ll;0;L; 0066;;;;N;;;;; 1D524;MATHEMATICAL FRAKTUR SMALL G;Ll;0;L; 0067;;;;N;;;;; 1D525;MATHEMATICAL FRAKTUR SMALL H;Ll;0;L; 0068;;;;N;;;;; 1D526;MATHEMATICAL FRAKTUR SMALL I;Ll;0;L; 0069;;;;N;;;;; 1D527;MATHEMATICAL FRAKTUR SMALL J;Ll;0;L; 006A;;;;N;;;;; 1D528;MATHEMATICAL FRAKTUR SMALL K;Ll;0;L; 006B;;;;N;;;;; 1D529;MATHEMATICAL FRAKTUR SMALL L;Ll;0;L; 006C;;;;N;;;;; 1D52A;MATHEMATICAL FRAKTUR SMALL M;Ll;0;L; 006D;;;;N;;;;; 1D52B;MATHEMATICAL FRAKTUR SMALL N;Ll;0;L; 006E;;;;N;;;;; 1D52C;MATHEMATICAL FRAKTUR SMALL O;Ll;0;L; 006F;;;;N;;;;; 1D52D;MATHEMATICAL FRAKTUR SMALL P;Ll;0;L; 0070;;;;N;;;;; 1D52E;MATHEMATICAL FRAKTUR SMALL Q;Ll;0;L; 0071;;;;N;;;;; 1D52F;MATHEMATICAL FRAKTUR SMALL R;Ll;0;L; 0072;;;;N;;;;; 1D530;MATHEMATICAL FRAKTUR SMALL S;Ll;0;L; 0073;;;;N;;;;; 1D531;MATHEMATICAL FRAKTUR SMALL T;Ll;0;L; 0074;;;;N;;;;; 1D532;MATHEMATICAL FRAKTUR SMALL U;Ll;0;L; 0075;;;;N;;;;; 1D533;MATHEMATICAL FRAKTUR SMALL V;Ll;0;L; 0076;;;;N;;;;; 1D534;MATHEMATICAL FRAKTUR SMALL W;Ll;0;L; 0077;;;;N;;;;; 1D535;MATHEMATICAL FRAKTUR SMALL X;Ll;0;L; 0078;;;;N;;;;; 1D536;MATHEMATICAL FRAKTUR SMALL Y;Ll;0;L; 0079;;;;N;;;;; 1D537;MATHEMATICAL FRAKTUR SMALL Z;Ll;0;L; 007A;;;;N;;;;; 1D538;MATHEMATICAL DOUBLE-STRUCK CAPITAL A;Lu;0;L; 0041;;;;N;;;;; 1D539;MATHEMATICAL DOUBLE-STRUCK CAPITAL B;Lu;0;L; 0042;;;;N;;;;; 1D53B;MATHEMATICAL DOUBLE-STRUCK CAPITAL D;Lu;0;L; 0044;;;;N;;;;; 1D53C;MATHEMATICAL DOUBLE-STRUCK CAPITAL E;Lu;0;L; 0045;;;;N;;;;; 1D53D;MATHEMATICAL DOUBLE-STRUCK CAPITAL F;Lu;0;L; 0046;;;;N;;;;; 1D53E;MATHEMATICAL DOUBLE-STRUCK CAPITAL G;Lu;0;L; 0047;;;;N;;;;; 1D540;MATHEMATICAL DOUBLE-STRUCK CAPITAL I;Lu;0;L; 0049;;;;N;;;;; 1D541;MATHEMATICAL DOUBLE-STRUCK CAPITAL J;Lu;0;L; 004A;;;;N;;;;; 1D542;MATHEMATICAL DOUBLE-STRUCK CAPITAL K;Lu;0;L; 004B;;;;N;;;;; 1D543;MATHEMATICAL DOUBLE-STRUCK CAPITAL L;Lu;0;L; 004C;;;;N;;;;; 1D544;MATHEMATICAL DOUBLE-STRUCK CAPITAL M;Lu;0;L; 004D;;;;N;;;;; 1D546;MATHEMATICAL DOUBLE-STRUCK CAPITAL O;Lu;0;L; 004F;;;;N;;;;; 1D54A;MATHEMATICAL DOUBLE-STRUCK CAPITAL S;Lu;0;L; 0053;;;;N;;;;; 1D54B;MATHEMATICAL DOUBLE-STRUCK CAPITAL T;Lu;0;L; 0054;;;;N;;;;; 1D54C;MATHEMATICAL DOUBLE-STRUCK CAPITAL U;Lu;0;L; 0055;;;;N;;;;; 1D54D;MATHEMATICAL DOUBLE-STRUCK CAPITAL V;Lu;0;L; 0056;;;;N;;;;; 1D54E;MATHEMATICAL DOUBLE-STRUCK CAPITAL W;Lu;0;L; 0057;;;;N;;;;; 1D54F;MATHEMATICAL DOUBLE-STRUCK CAPITAL X;Lu;0;L; 0058;;;;N;;;;; 1D550;MATHEMATICAL DOUBLE-STRUCK CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; 1D552;MATHEMATICAL DOUBLE-STRUCK SMALL A;Ll;0;L; 0061;;;;N;;;;; 1D553;MATHEMATICAL DOUBLE-STRUCK SMALL B;Ll;0;L; 0062;;;;N;;;;; 1D554;MATHEMATICAL DOUBLE-STRUCK SMALL C;Ll;0;L; 0063;;;;N;;;;; 1D555;MATHEMATICAL DOUBLE-STRUCK SMALL D;Ll;0;L; 0064;;;;N;;;;; 1D556;MATHEMATICAL DOUBLE-STRUCK SMALL E;Ll;0;L; 0065;;;;N;;;;; 1D557;MATHEMATICAL DOUBLE-STRUCK SMALL F;Ll;0;L; 0066;;;;N;;;;; 1D558;MATHEMATICAL DOUBLE-STRUCK SMALL G;Ll;0;L; 0067;;;;N;;;;; 1D559;MATHEMATICAL DOUBLE-STRUCK SMALL H;Ll;0;L; 0068;;;;N;;;;; 1D55A;MATHEMATICAL DOUBLE-STRUCK SMALL I;Ll;0;L; 0069;;;;N;;;;; 1D55B;MATHEMATICAL DOUBLE-STRUCK SMALL J;Ll;0;L; 006A;;;;N;;;;; 1D55C;MATHEMATICAL DOUBLE-STRUCK SMALL K;Ll;0;L; 006B;;;;N;;;;; 1D55D;MATHEMATICAL DOUBLE-STRUCK SMALL L;Ll;0;L; 006C;;;;N;;;;; 1D55E;MATHEMATICAL DOUBLE-STRUCK SMALL M;Ll;0;L; 006D;;;;N;;;;; 1D55F;MATHEMATICAL DOUBLE-STRUCK SMALL N;Ll;0;L; 006E;;;;N;;;;; 1D560;MATHEMATICAL DOUBLE-STRUCK SMALL O;Ll;0;L; 006F;;;;N;;;;; 1D561;MATHEMATICAL DOUBLE-STRUCK SMALL P;Ll;0;L; 0070;;;;N;;;;; 1D562;MATHEMATICAL DOUBLE-STRUCK SMALL Q;Ll;0;L; 0071;;;;N;;;;; 1D563;MATHEMATICAL DOUBLE-STRUCK SMALL R;Ll;0;L; 0072;;;;N;;;;; 1D564;MATHEMATICAL DOUBLE-STRUCK SMALL S;Ll;0;L; 0073;;;;N;;;;; 1D565;MATHEMATICAL DOUBLE-STRUCK SMALL T;Ll;0;L; 0074;;;;N;;;;; 1D566;MATHEMATICAL DOUBLE-STRUCK SMALL U;Ll;0;L; 0075;;;;N;;;;; 1D567;MATHEMATICAL DOUBLE-STRUCK SMALL V;Ll;0;L; 0076;;;;N;;;;; 1D568;MATHEMATICAL DOUBLE-STRUCK SMALL W;Ll;0;L; 0077;;;;N;;;;; 1D569;MATHEMATICAL DOUBLE-STRUCK SMALL X;Ll;0;L; 0078;;;;N;;;;; 1D56A;MATHEMATICAL DOUBLE-STRUCK SMALL Y;Ll;0;L; 0079;;;;N;;;;; 1D56B;MATHEMATICAL DOUBLE-STRUCK SMALL Z;Ll;0;L; 007A;;;;N;;;;; 1D56C;MATHEMATICAL BOLD FRAKTUR CAPITAL A;Lu;0;L; 0041;;;;N;;;;; 1D56D;MATHEMATICAL BOLD FRAKTUR CAPITAL B;Lu;0;L; 0042;;;;N;;;;; 1D56E;MATHEMATICAL BOLD FRAKTUR CAPITAL C;Lu;0;L; 0043;;;;N;;;;; 1D56F;MATHEMATICAL BOLD FRAKTUR CAPITAL D;Lu;0;L; 0044;;;;N;;;;; 1D570;MATHEMATICAL BOLD FRAKTUR CAPITAL E;Lu;0;L; 0045;;;;N;;;;; 1D571;MATHEMATICAL BOLD FRAKTUR CAPITAL F;Lu;0;L; 0046;;;;N;;;;; 1D572;MATHEMATICAL BOLD FRAKTUR CAPITAL G;Lu;0;L; 0047;;;;N;;;;; 1D573;MATHEMATICAL BOLD FRAKTUR CAPITAL H;Lu;0;L; 0048;;;;N;;;;; 1D574;MATHEMATICAL BOLD FRAKTUR CAPITAL I;Lu;0;L; 0049;;;;N;;;;; 1D575;MATHEMATICAL BOLD FRAKTUR CAPITAL J;Lu;0;L; 004A;;;;N;;;;; 1D576;MATHEMATICAL BOLD FRAKTUR CAPITAL K;Lu;0;L; 004B;;;;N;;;;; 1D577;MATHEMATICAL BOLD FRAKTUR CAPITAL L;Lu;0;L; 004C;;;;N;;;;; 1D578;MATHEMATICAL BOLD FRAKTUR CAPITAL M;Lu;0;L; 004D;;;;N;;;;; 1D579;MATHEMATICAL BOLD FRAKTUR CAPITAL N;Lu;0;L; 004E;;;;N;;;;; 1D57A;MATHEMATICAL BOLD FRAKTUR CAPITAL O;Lu;0;L; 004F;;;;N;;;;; 1D57B;MATHEMATICAL BOLD FRAKTUR CAPITAL P;Lu;0;L; 0050;;;;N;;;;; 1D57C;MATHEMATICAL BOLD FRAKTUR CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; 1D57D;MATHEMATICAL BOLD FRAKTUR CAPITAL R;Lu;0;L; 0052;;;;N;;;;; 1D57E;MATHEMATICAL BOLD FRAKTUR CAPITAL S;Lu;0;L; 0053;;;;N;;;;; 1D57F;MATHEMATICAL BOLD FRAKTUR CAPITAL T;Lu;0;L; 0054;;;;N;;;;; 1D580;MATHEMATICAL BOLD FRAKTUR CAPITAL U;Lu;0;L; 0055;;;;N;;;;; 1D581;MATHEMATICAL BOLD FRAKTUR CAPITAL V;Lu;0;L; 0056;;;;N;;;;; 1D582;MATHEMATICAL BOLD FRAKTUR CAPITAL W;Lu;0;L; 0057;;;;N;;;;; 1D583;MATHEMATICAL BOLD FRAKTUR CAPITAL X;Lu;0;L; 0058;;;;N;;;;; 1D584;MATHEMATICAL BOLD FRAKTUR CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; 1D585;MATHEMATICAL BOLD FRAKTUR CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; 1D586;MATHEMATICAL BOLD FRAKTUR SMALL A;Ll;0;L; 0061;;;;N;;;;; 1D587;MATHEMATICAL BOLD FRAKTUR SMALL B;Ll;0;L; 0062;;;;N;;;;; 1D588;MATHEMATICAL BOLD FRAKTUR SMALL C;Ll;0;L; 0063;;;;N;;;;; 1D589;MATHEMATICAL BOLD FRAKTUR SMALL D;Ll;0;L; 0064;;;;N;;;;; 1D58A;MATHEMATICAL BOLD FRAKTUR SMALL E;Ll;0;L; 0065;;;;N;;;;; 1D58B;MATHEMATICAL BOLD FRAKTUR SMALL F;Ll;0;L; 0066;;;;N;;;;; 1D58C;MATHEMATICAL BOLD FRAKTUR SMALL G;Ll;0;L; 0067;;;;N;;;;; 1D58D;MATHEMATICAL BOLD FRAKTUR SMALL H;Ll;0;L; 0068;;;;N;;;;; 1D58E;MATHEMATICAL BOLD FRAKTUR SMALL I;Ll;0;L; 0069;;;;N;;;;; 1D58F;MATHEMATICAL BOLD FRAKTUR SMALL J;Ll;0;L; 006A;;;;N;;;;; 1D590;MATHEMATICAL BOLD FRAKTUR SMALL K;Ll;0;L; 006B;;;;N;;;;; 1D591;MATHEMATICAL BOLD FRAKTUR SMALL L;Ll;0;L; 006C;;;;N;;;;; 1D592;MATHEMATICAL BOLD FRAKTUR SMALL M;Ll;0;L; 006D;;;;N;;;;; 1D593;MATHEMATICAL BOLD FRAKTUR SMALL N;Ll;0;L; 006E;;;;N;;;;; 1D594;MATHEMATICAL BOLD FRAKTUR SMALL O;Ll;0;L; 006F;;;;N;;;;; 1D595;MATHEMATICAL BOLD FRAKTUR SMALL P;Ll;0;L; 0070;;;;N;;;;; 1D596;MATHEMATICAL BOLD FRAKTUR SMALL Q;Ll;0;L; 0071;;;;N;;;;; 1D597;MATHEMATICAL BOLD FRAKTUR SMALL R;Ll;0;L; 0072;;;;N;;;;; 1D598;MATHEMATICAL BOLD FRAKTUR SMALL S;Ll;0;L; 0073;;;;N;;;;; 1D599;MATHEMATICAL BOLD FRAKTUR SMALL T;Ll;0;L; 0074;;;;N;;;;; 1D59A;MATHEMATICAL BOLD FRAKTUR SMALL U;Ll;0;L; 0075;;;;N;;;;; 1D59B;MATHEMATICAL BOLD FRAKTUR SMALL V;Ll;0;L; 0076;;;;N;;;;; 1D59C;MATHEMATICAL BOLD FRAKTUR SMALL W;Ll;0;L; 0077;;;;N;;;;; 1D59D;MATHEMATICAL BOLD FRAKTUR SMALL X;Ll;0;L; 0078;;;;N;;;;; 1D59E;MATHEMATICAL BOLD FRAKTUR SMALL Y;Ll;0;L; 0079;;;;N;;;;; 1D59F;MATHEMATICAL BOLD FRAKTUR SMALL Z;Ll;0;L; 007A;;;;N;;;;; 1D5A0;MATHEMATICAL SANS-SERIF CAPITAL A;Lu;0;L; 0041;;;;N;;;;; 1D5A1;MATHEMATICAL SANS-SERIF CAPITAL B;Lu;0;L; 0042;;;;N;;;;; 1D5A2;MATHEMATICAL SANS-SERIF CAPITAL C;Lu;0;L; 0043;;;;N;;;;; 1D5A3;MATHEMATICAL SANS-SERIF CAPITAL D;Lu;0;L; 0044;;;;N;;;;; 1D5A4;MATHEMATICAL SANS-SERIF CAPITAL E;Lu;0;L; 0045;;;;N;;;;; 1D5A5;MATHEMATICAL SANS-SERIF CAPITAL F;Lu;0;L; 0046;;;;N;;;;; 1D5A6;MATHEMATICAL SANS-SERIF CAPITAL G;Lu;0;L; 0047;;;;N;;;;; 1D5A7;MATHEMATICAL SANS-SERIF CAPITAL H;Lu;0;L; 0048;;;;N;;;;; 1D5A8;MATHEMATICAL SANS-SERIF CAPITAL I;Lu;0;L; 0049;;;;N;;;;; 1D5A9;MATHEMATICAL SANS-SERIF CAPITAL J;Lu;0;L; 004A;;;;N;;;;; 1D5AA;MATHEMATICAL SANS-SERIF CAPITAL K;Lu;0;L; 004B;;;;N;;;;; 1D5AB;MATHEMATICAL SANS-SERIF CAPITAL L;Lu;0;L; 004C;;;;N;;;;; 1D5AC;MATHEMATICAL SANS-SERIF CAPITAL M;Lu;0;L; 004D;;;;N;;;;; 1D5AD;MATHEMATICAL SANS-SERIF CAPITAL N;Lu;0;L; 004E;;;;N;;;;; 1D5AE;MATHEMATICAL SANS-SERIF CAPITAL O;Lu;0;L; 004F;;;;N;;;;; 1D5AF;MATHEMATICAL SANS-SERIF CAPITAL P;Lu;0;L; 0050;;;;N;;;;; 1D5B0;MATHEMATICAL SANS-SERIF CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; 1D5B1;MATHEMATICAL SANS-SERIF CAPITAL R;Lu;0;L; 0052;;;;N;;;;; 1D5B2;MATHEMATICAL SANS-SERIF CAPITAL S;Lu;0;L; 0053;;;;N;;;;; 1D5B3;MATHEMATICAL SANS-SERIF CAPITAL T;Lu;0;L; 0054;;;;N;;;;; 1D5B4;MATHEMATICAL SANS-SERIF CAPITAL U;Lu;0;L; 0055;;;;N;;;;; 1D5B5;MATHEMATICAL SANS-SERIF CAPITAL V;Lu;0;L; 0056;;;;N;;;;; 1D5B6;MATHEMATICAL SANS-SERIF CAPITAL W;Lu;0;L; 0057;;;;N;;;;; 1D5B7;MATHEMATICAL SANS-SERIF CAPITAL X;Lu;0;L; 0058;;;;N;;;;; 1D5B8;MATHEMATICAL SANS-SERIF CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; 1D5B9;MATHEMATICAL SANS-SERIF CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; 1D5BA;MATHEMATICAL SANS-SERIF SMALL A;Ll;0;L; 0061;;;;N;;;;; 1D5BB;MATHEMATICAL SANS-SERIF SMALL B;Ll;0;L; 0062;;;;N;;;;; 1D5BC;MATHEMATICAL SANS-SERIF SMALL C;Ll;0;L; 0063;;;;N;;;;; 1D5BD;MATHEMATICAL SANS-SERIF SMALL D;Ll;0;L; 0064;;;;N;;;;; 1D5BE;MATHEMATICAL SANS-SERIF SMALL E;Ll;0;L; 0065;;;;N;;;;; 1D5BF;MATHEMATICAL SANS-SERIF SMALL F;Ll;0;L; 0066;;;;N;;;;; 1D5C0;MATHEMATICAL SANS-SERIF SMALL G;Ll;0;L; 0067;;;;N;;;;; 1D5C1;MATHEMATICAL SANS-SERIF SMALL H;Ll;0;L; 0068;;;;N;;;;; 1D5C2;MATHEMATICAL SANS-SERIF SMALL I;Ll;0;L; 0069;;;;N;;;;; 1D5C3;MATHEMATICAL SANS-SERIF SMALL J;Ll;0;L; 006A;;;;N;;;;; 1D5C4;MATHEMATICAL SANS-SERIF SMALL K;Ll;0;L; 006B;;;;N;;;;; 1D5C5;MATHEMATICAL SANS-SERIF SMALL L;Ll;0;L; 006C;;;;N;;;;; 1D5C6;MATHEMATICAL SANS-SERIF SMALL M;Ll;0;L; 006D;;;;N;;;;; 1D5C7;MATHEMATICAL SANS-SERIF SMALL N;Ll;0;L; 006E;;;;N;;;;; 1D5C8;MATHEMATICAL SANS-SERIF SMALL O;Ll;0;L; 006F;;;;N;;;;; 1D5C9;MATHEMATICAL SANS-SERIF SMALL P;Ll;0;L; 0070;;;;N;;;;; 1D5CA;MATHEMATICAL SANS-SERIF SMALL Q;Ll;0;L; 0071;;;;N;;;;; 1D5CB;MATHEMATICAL SANS-SERIF SMALL R;Ll;0;L; 0072;;;;N;;;;; 1D5CC;MATHEMATICAL SANS-SERIF SMALL S;Ll;0;L; 0073;;;;N;;;;; 1D5CD;MATHEMATICAL SANS-SERIF SMALL T;Ll;0;L; 0074;;;;N;;;;; 1D5CE;MATHEMATICAL SANS-SERIF SMALL U;Ll;0;L; 0075;;;;N;;;;; 1D5CF;MATHEMATICAL SANS-SERIF SMALL V;Ll;0;L; 0076;;;;N;;;;; 1D5D0;MATHEMATICAL SANS-SERIF SMALL W;Ll;0;L; 0077;;;;N;;;;; 1D5D1;MATHEMATICAL SANS-SERIF SMALL X;Ll;0;L; 0078;;;;N;;;;; 1D5D2;MATHEMATICAL SANS-SERIF SMALL Y;Ll;0;L; 0079;;;;N;;;;; 1D5D3;MATHEMATICAL SANS-SERIF SMALL Z;Ll;0;L; 007A;;;;N;;;;; 1D5D4;MATHEMATICAL SANS-SERIF BOLD CAPITAL A;Lu;0;L; 0041;;;;N;;;;; 1D5D5;MATHEMATICAL SANS-SERIF BOLD CAPITAL B;Lu;0;L; 0042;;;;N;;;;; 1D5D6;MATHEMATICAL SANS-SERIF BOLD CAPITAL C;Lu;0;L; 0043;;;;N;;;;; 1D5D7;MATHEMATICAL SANS-SERIF BOLD CAPITAL D;Lu;0;L; 0044;;;;N;;;;; 1D5D8;MATHEMATICAL SANS-SERIF BOLD CAPITAL E;Lu;0;L; 0045;;;;N;;;;; 1D5D9;MATHEMATICAL SANS-SERIF BOLD CAPITAL F;Lu;0;L; 0046;;;;N;;;;; 1D5DA;MATHEMATICAL SANS-SERIF BOLD CAPITAL G;Lu;0;L; 0047;;;;N;;;;; 1D5DB;MATHEMATICAL SANS-SERIF BOLD CAPITAL H;Lu;0;L; 0048;;;;N;;;;; 1D5DC;MATHEMATICAL SANS-SERIF BOLD CAPITAL I;Lu;0;L; 0049;;;;N;;;;; 1D5DD;MATHEMATICAL SANS-SERIF BOLD CAPITAL J;Lu;0;L; 004A;;;;N;;;;; 1D5DE;MATHEMATICAL SANS-SERIF BOLD CAPITAL K;Lu;0;L; 004B;;;;N;;;;; 1D5DF;MATHEMATICAL SANS-SERIF BOLD CAPITAL L;Lu;0;L; 004C;;;;N;;;;; 1D5E0;MATHEMATICAL SANS-SERIF BOLD CAPITAL M;Lu;0;L; 004D;;;;N;;;;; 1D5E1;MATHEMATICAL SANS-SERIF BOLD CAPITAL N;Lu;0;L; 004E;;;;N;;;;; 1D5E2;MATHEMATICAL SANS-SERIF BOLD CAPITAL O;Lu;0;L; 004F;;;;N;;;;; 1D5E3;MATHEMATICAL SANS-SERIF BOLD CAPITAL P;Lu;0;L; 0050;;;;N;;;;; 1D5E4;MATHEMATICAL SANS-SERIF BOLD CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; 1D5E5;MATHEMATICAL SANS-SERIF BOLD CAPITAL R;Lu;0;L; 0052;;;;N;;;;; 1D5E6;MATHEMATICAL SANS-SERIF BOLD CAPITAL S;Lu;0;L; 0053;;;;N;;;;; 1D5E7;MATHEMATICAL SANS-SERIF BOLD CAPITAL T;Lu;0;L; 0054;;;;N;;;;; 1D5E8;MATHEMATICAL SANS-SERIF BOLD CAPITAL U;Lu;0;L; 0055;;;;N;;;;; 1D5E9;MATHEMATICAL SANS-SERIF BOLD CAPITAL V;Lu;0;L; 0056;;;;N;;;;; 1D5EA;MATHEMATICAL SANS-SERIF BOLD CAPITAL W;Lu;0;L; 0057;;;;N;;;;; 1D5EB;MATHEMATICAL SANS-SERIF BOLD CAPITAL X;Lu;0;L; 0058;;;;N;;;;; 1D5EC;MATHEMATICAL SANS-SERIF BOLD CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; 1D5ED;MATHEMATICAL SANS-SERIF BOLD CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; 1D5EE;MATHEMATICAL SANS-SERIF BOLD SMALL A;Ll;0;L; 0061;;;;N;;;;; 1D5EF;MATHEMATICAL SANS-SERIF BOLD SMALL B;Ll;0;L; 0062;;;;N;;;;; 1D5F0;MATHEMATICAL SANS-SERIF BOLD SMALL C;Ll;0;L; 0063;;;;N;;;;; 1D5F1;MATHEMATICAL SANS-SERIF BOLD SMALL D;Ll;0;L; 0064;;;;N;;;;; 1D5F2;MATHEMATICAL SANS-SERIF BOLD SMALL E;Ll;0;L; 0065;;;;N;;;;; 1D5F3;MATHEMATICAL SANS-SERIF BOLD SMALL F;Ll;0;L; 0066;;;;N;;;;; 1D5F4;MATHEMATICAL SANS-SERIF BOLD SMALL G;Ll;0;L; 0067;;;;N;;;;; 1D5F5;MATHEMATICAL SANS-SERIF BOLD SMALL H;Ll;0;L; 0068;;;;N;;;;; 1D5F6;MATHEMATICAL SANS-SERIF BOLD SMALL I;Ll;0;L; 0069;;;;N;;;;; 1D5F7;MATHEMATICAL SANS-SERIF BOLD SMALL J;Ll;0;L; 006A;;;;N;;;;; 1D5F8;MATHEMATICAL SANS-SERIF BOLD SMALL K;Ll;0;L; 006B;;;;N;;;;; 1D5F9;MATHEMATICAL SANS-SERIF BOLD SMALL L;Ll;0;L; 006C;;;;N;;;;; 1D5FA;MATHEMATICAL SANS-SERIF BOLD SMALL M;Ll;0;L; 006D;;;;N;;;;; 1D5FB;MATHEMATICAL SANS-SERIF BOLD SMALL N;Ll;0;L; 006E;;;;N;;;;; 1D5FC;MATHEMATICAL SANS-SERIF BOLD SMALL O;Ll;0;L; 006F;;;;N;;;;; 1D5FD;MATHEMATICAL SANS-SERIF BOLD SMALL P;Ll;0;L; 0070;;;;N;;;;; 1D5FE;MATHEMATICAL SANS-SERIF BOLD SMALL Q;Ll;0;L; 0071;;;;N;;;;; 1D5FF;MATHEMATICAL SANS-SERIF BOLD SMALL R;Ll;0;L; 0072;;;;N;;;;; 1D600;MATHEMATICAL SANS-SERIF BOLD SMALL S;Ll;0;L; 0073;;;;N;;;;; 1D601;MATHEMATICAL SANS-SERIF BOLD SMALL T;Ll;0;L; 0074;;;;N;;;;; 1D602;MATHEMATICAL SANS-SERIF BOLD SMALL U;Ll;0;L; 0075;;;;N;;;;; 1D603;MATHEMATICAL SANS-SERIF BOLD SMALL V;Ll;0;L; 0076;;;;N;;;;; 1D604;MATHEMATICAL SANS-SERIF BOLD SMALL W;Ll;0;L; 0077;;;;N;;;;; 1D605;MATHEMATICAL SANS-SERIF BOLD SMALL X;Ll;0;L; 0078;;;;N;;;;; 1D606;MATHEMATICAL SANS-SERIF BOLD SMALL Y;Ll;0;L; 0079;;;;N;;;;; 1D607;MATHEMATICAL SANS-SERIF BOLD SMALL Z;Ll;0;L; 007A;;;;N;;;;; 1D608;MATHEMATICAL SANS-SERIF ITALIC CAPITAL A;Lu;0;L; 0041;;;;N;;;;; 1D609;MATHEMATICAL SANS-SERIF ITALIC CAPITAL B;Lu;0;L; 0042;;;;N;;;;; 1D60A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL C;Lu;0;L; 0043;;;;N;;;;; 1D60B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL D;Lu;0;L; 0044;;;;N;;;;; 1D60C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL E;Lu;0;L; 0045;;;;N;;;;; 1D60D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL F;Lu;0;L; 0046;;;;N;;;;; 1D60E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL G;Lu;0;L; 0047;;;;N;;;;; 1D60F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL H;Lu;0;L; 0048;;;;N;;;;; 1D610;MATHEMATICAL SANS-SERIF ITALIC CAPITAL I;Lu;0;L; 0049;;;;N;;;;; 1D611;MATHEMATICAL SANS-SERIF ITALIC CAPITAL J;Lu;0;L; 004A;;;;N;;;;; 1D612;MATHEMATICAL SANS-SERIF ITALIC CAPITAL K;Lu;0;L; 004B;;;;N;;;;; 1D613;MATHEMATICAL SANS-SERIF ITALIC CAPITAL L;Lu;0;L; 004C;;;;N;;;;; 1D614;MATHEMATICAL SANS-SERIF ITALIC CAPITAL M;Lu;0;L; 004D;;;;N;;;;; 1D615;MATHEMATICAL SANS-SERIF ITALIC CAPITAL N;Lu;0;L; 004E;;;;N;;;;; 1D616;MATHEMATICAL SANS-SERIF ITALIC CAPITAL O;Lu;0;L; 004F;;;;N;;;;; 1D617;MATHEMATICAL SANS-SERIF ITALIC CAPITAL P;Lu;0;L; 0050;;;;N;;;;; 1D618;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; 1D619;MATHEMATICAL SANS-SERIF ITALIC CAPITAL R;Lu;0;L; 0052;;;;N;;;;; 1D61A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL S;Lu;0;L; 0053;;;;N;;;;; 1D61B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL T;Lu;0;L; 0054;;;;N;;;;; 1D61C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL U;Lu;0;L; 0055;;;;N;;;;; 1D61D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL V;Lu;0;L; 0056;;;;N;;;;; 1D61E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL W;Lu;0;L; 0057;;;;N;;;;; 1D61F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL X;Lu;0;L; 0058;;;;N;;;;; 1D620;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; 1D621;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; 1D622;MATHEMATICAL SANS-SERIF ITALIC SMALL A;Ll;0;L; 0061;;;;N;;;;; 1D623;MATHEMATICAL SANS-SERIF ITALIC SMALL B;Ll;0;L; 0062;;;;N;;;;; 1D624;MATHEMATICAL SANS-SERIF ITALIC SMALL C;Ll;0;L; 0063;;;;N;;;;; 1D625;MATHEMATICAL SANS-SERIF ITALIC SMALL D;Ll;0;L; 0064;;;;N;;;;; 1D626;MATHEMATICAL SANS-SERIF ITALIC SMALL E;Ll;0;L; 0065;;;;N;;;;; 1D627;MATHEMATICAL SANS-SERIF ITALIC SMALL F;Ll;0;L; 0066;;;;N;;;;; 1D628;MATHEMATICAL SANS-SERIF ITALIC SMALL G;Ll;0;L; 0067;;;;N;;;;; 1D629;MATHEMATICAL SANS-SERIF ITALIC SMALL H;Ll;0;L; 0068;;;;N;;;;; 1D62A;MATHEMATICAL SANS-SERIF ITALIC SMALL I;Ll;0;L; 0069;;;;N;;;;; 1D62B;MATHEMATICAL SANS-SERIF ITALIC SMALL J;Ll;0;L; 006A;;;;N;;;;; 1D62C;MATHEMATICAL SANS-SERIF ITALIC SMALL K;Ll;0;L; 006B;;;;N;;;;; 1D62D;MATHEMATICAL SANS-SERIF ITALIC SMALL L;Ll;0;L; 006C;;;;N;;;;; 1D62E;MATHEMATICAL SANS-SERIF ITALIC SMALL M;Ll;0;L; 006D;;;;N;;;;; 1D62F;MATHEMATICAL SANS-SERIF ITALIC SMALL N;Ll;0;L; 006E;;;;N;;;;; 1D630;MATHEMATICAL SANS-SERIF ITALIC SMALL O;Ll;0;L; 006F;;;;N;;;;; 1D631;MATHEMATICAL SANS-SERIF ITALIC SMALL P;Ll;0;L; 0070;;;;N;;;;; 1D632;MATHEMATICAL SANS-SERIF ITALIC SMALL Q;Ll;0;L; 0071;;;;N;;;;; 1D633;MATHEMATICAL SANS-SERIF ITALIC SMALL R;Ll;0;L; 0072;;;;N;;;;; 1D634;MATHEMATICAL SANS-SERIF ITALIC SMALL S;Ll;0;L; 0073;;;;N;;;;; 1D635;MATHEMATICAL SANS-SERIF ITALIC SMALL T;Ll;0;L; 0074;;;;N;;;;; 1D636;MATHEMATICAL SANS-SERIF ITALIC SMALL U;Ll;0;L; 0075;;;;N;;;;; 1D637;MATHEMATICAL SANS-SERIF ITALIC SMALL V;Ll;0;L; 0076;;;;N;;;;; 1D638;MATHEMATICAL SANS-SERIF ITALIC SMALL W;Ll;0;L; 0077;;;;N;;;;; 1D639;MATHEMATICAL SANS-SERIF ITALIC SMALL X;Ll;0;L; 0078;;;;N;;;;; 1D63A;MATHEMATICAL SANS-SERIF ITALIC SMALL Y;Ll;0;L; 0079;;;;N;;;;; 1D63B;MATHEMATICAL SANS-SERIF ITALIC SMALL Z;Ll;0;L; 007A;;;;N;;;;; 1D63C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A;Lu;0;L; 0041;;;;N;;;;; 1D63D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B;Lu;0;L; 0042;;;;N;;;;; 1D63E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C;Lu;0;L; 0043;;;;N;;;;; 1D63F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D;Lu;0;L; 0044;;;;N;;;;; 1D640;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E;Lu;0;L; 0045;;;;N;;;;; 1D641;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F;Lu;0;L; 0046;;;;N;;;;; 1D642;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G;Lu;0;L; 0047;;;;N;;;;; 1D643;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H;Lu;0;L; 0048;;;;N;;;;; 1D644;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I;Lu;0;L; 0049;;;;N;;;;; 1D645;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J;Lu;0;L; 004A;;;;N;;;;; 1D646;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K;Lu;0;L; 004B;;;;N;;;;; 1D647;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L;Lu;0;L; 004C;;;;N;;;;; 1D648;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M;Lu;0;L; 004D;;;;N;;;;; 1D649;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N;Lu;0;L; 004E;;;;N;;;;; 1D64A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O;Lu;0;L; 004F;;;;N;;;;; 1D64B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P;Lu;0;L; 0050;;;;N;;;;; 1D64C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; 1D64D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R;Lu;0;L; 0052;;;;N;;;;; 1D64E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S;Lu;0;L; 0053;;;;N;;;;; 1D64F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T;Lu;0;L; 0054;;;;N;;;;; 1D650;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U;Lu;0;L; 0055;;;;N;;;;; 1D651;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V;Lu;0;L; 0056;;;;N;;;;; 1D652;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W;Lu;0;L; 0057;;;;N;;;;; 1D653;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X;Lu;0;L; 0058;;;;N;;;;; 1D654;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; 1D655;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; 1D656;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A;Ll;0;L; 0061;;;;N;;;;; 1D657;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B;Ll;0;L; 0062;;;;N;;;;; 1D658;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C;Ll;0;L; 0063;;;;N;;;;; 1D659;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D;Ll;0;L; 0064;;;;N;;;;; 1D65A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E;Ll;0;L; 0065;;;;N;;;;; 1D65B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F;Ll;0;L; 0066;;;;N;;;;; 1D65C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G;Ll;0;L; 0067;;;;N;;;;; 1D65D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H;Ll;0;L; 0068;;;;N;;;;; 1D65E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I;Ll;0;L; 0069;;;;N;;;;; 1D65F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J;Ll;0;L; 006A;;;;N;;;;; 1D660;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K;Ll;0;L; 006B;;;;N;;;;; 1D661;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L;Ll;0;L; 006C;;;;N;;;;; 1D662;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M;Ll;0;L; 006D;;;;N;;;;; 1D663;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N;Ll;0;L; 006E;;;;N;;;;; 1D664;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O;Ll;0;L; 006F;;;;N;;;;; 1D665;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P;Ll;0;L; 0070;;;;N;;;;; 1D666;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q;Ll;0;L; 0071;;;;N;;;;; 1D667;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R;Ll;0;L; 0072;;;;N;;;;; 1D668;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S;Ll;0;L; 0073;;;;N;;;;; 1D669;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T;Ll;0;L; 0074;;;;N;;;;; 1D66A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U;Ll;0;L; 0075;;;;N;;;;; 1D66B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V;Ll;0;L; 0076;;;;N;;;;; 1D66C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W;Ll;0;L; 0077;;;;N;;;;; 1D66D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X;Ll;0;L; 0078;;;;N;;;;; 1D66E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y;Ll;0;L; 0079;;;;N;;;;; 1D66F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z;Ll;0;L; 007A;;;;N;;;;; 1D670;MATHEMATICAL MONOSPACE CAPITAL A;Lu;0;L; 0041;;;;N;;;;; 1D671;MATHEMATICAL MONOSPACE CAPITAL B;Lu;0;L; 0042;;;;N;;;;; 1D672;MATHEMATICAL MONOSPACE CAPITAL C;Lu;0;L; 0043;;;;N;;;;; 1D673;MATHEMATICAL MONOSPACE CAPITAL D;Lu;0;L; 0044;;;;N;;;;; 1D674;MATHEMATICAL MONOSPACE CAPITAL E;Lu;0;L; 0045;;;;N;;;;; 1D675;MATHEMATICAL MONOSPACE CAPITAL F;Lu;0;L; 0046;;;;N;;;;; 1D676;MATHEMATICAL MONOSPACE CAPITAL G;Lu;0;L; 0047;;;;N;;;;; 1D677;MATHEMATICAL MONOSPACE CAPITAL H;Lu;0;L; 0048;;;;N;;;;; 1D678;MATHEMATICAL MONOSPACE CAPITAL I;Lu;0;L; 0049;;;;N;;;;; 1D679;MATHEMATICAL MONOSPACE CAPITAL J;Lu;0;L; 004A;;;;N;;;;; 1D67A;MATHEMATICAL MONOSPACE CAPITAL K;Lu;0;L; 004B;;;;N;;;;; 1D67B;MATHEMATICAL MONOSPACE CAPITAL L;Lu;0;L; 004C;;;;N;;;;; 1D67C;MATHEMATICAL MONOSPACE CAPITAL M;Lu;0;L; 004D;;;;N;;;;; 1D67D;MATHEMATICAL MONOSPACE CAPITAL N;Lu;0;L; 004E;;;;N;;;;; 1D67E;MATHEMATICAL MONOSPACE CAPITAL O;Lu;0;L; 004F;;;;N;;;;; 1D67F;MATHEMATICAL MONOSPACE CAPITAL P;Lu;0;L; 0050;;;;N;;;;; 1D680;MATHEMATICAL MONOSPACE CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; 1D681;MATHEMATICAL MONOSPACE CAPITAL R;Lu;0;L; 0052;;;;N;;;;; 1D682;MATHEMATICAL MONOSPACE CAPITAL S;Lu;0;L; 0053;;;;N;;;;; 1D683;MATHEMATICAL MONOSPACE CAPITAL T;Lu;0;L; 0054;;;;N;;;;; 1D684;MATHEMATICAL MONOSPACE CAPITAL U;Lu;0;L; 0055;;;;N;;;;; 1D685;MATHEMATICAL MONOSPACE CAPITAL V;Lu;0;L; 0056;;;;N;;;;; 1D686;MATHEMATICAL MONOSPACE CAPITAL W;Lu;0;L; 0057;;;;N;;;;; 1D687;MATHEMATICAL MONOSPACE CAPITAL X;Lu;0;L; 0058;;;;N;;;;; 1D688;MATHEMATICAL MONOSPACE CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; 1D689;MATHEMATICAL MONOSPACE CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; 1D68A;MATHEMATICAL MONOSPACE SMALL A;Ll;0;L; 0061;;;;N;;;;; 1D68B;MATHEMATICAL MONOSPACE SMALL B;Ll;0;L; 0062;;;;N;;;;; 1D68C;MATHEMATICAL MONOSPACE SMALL C;Ll;0;L; 0063;;;;N;;;;; 1D68D;MATHEMATICAL MONOSPACE SMALL D;Ll;0;L; 0064;;;;N;;;;; 1D68E;MATHEMATICAL MONOSPACE SMALL E;Ll;0;L; 0065;;;;N;;;;; 1D68F;MATHEMATICAL MONOSPACE SMALL F;Ll;0;L; 0066;;;;N;;;;; 1D690;MATHEMATICAL MONOSPACE SMALL G;Ll;0;L; 0067;;;;N;;;;; 1D691;MATHEMATICAL MONOSPACE SMALL H;Ll;0;L; 0068;;;;N;;;;; 1D692;MATHEMATICAL MONOSPACE SMALL I;Ll;0;L; 0069;;;;N;;;;; 1D693;MATHEMATICAL MONOSPACE SMALL J;Ll;0;L; 006A;;;;N;;;;; 1D694;MATHEMATICAL MONOSPACE SMALL K;Ll;0;L; 006B;;;;N;;;;; 1D695;MATHEMATICAL MONOSPACE SMALL L;Ll;0;L; 006C;;;;N;;;;; 1D696;MATHEMATICAL MONOSPACE SMALL M;Ll;0;L; 006D;;;;N;;;;; 1D697;MATHEMATICAL MONOSPACE SMALL N;Ll;0;L; 006E;;;;N;;;;; 1D698;MATHEMATICAL MONOSPACE SMALL O;Ll;0;L; 006F;;;;N;;;;; 1D699;MATHEMATICAL MONOSPACE SMALL P;Ll;0;L; 0070;;;;N;;;;; 1D69A;MATHEMATICAL MONOSPACE SMALL Q;Ll;0;L; 0071;;;;N;;;;; 1D69B;MATHEMATICAL MONOSPACE SMALL R;Ll;0;L; 0072;;;;N;;;;; 1D69C;MATHEMATICAL MONOSPACE SMALL S;Ll;0;L; 0073;;;;N;;;;; 1D69D;MATHEMATICAL MONOSPACE SMALL T;Ll;0;L; 0074;;;;N;;;;; 1D69E;MATHEMATICAL MONOSPACE SMALL U;Ll;0;L; 0075;;;;N;;;;; 1D69F;MATHEMATICAL MONOSPACE SMALL V;Ll;0;L; 0076;;;;N;;;;; 1D6A0;MATHEMATICAL MONOSPACE SMALL W;Ll;0;L; 0077;;;;N;;;;; 1D6A1;MATHEMATICAL MONOSPACE SMALL X;Ll;0;L; 0078;;;;N;;;;; 1D6A2;MATHEMATICAL MONOSPACE SMALL Y;Ll;0;L; 0079;;;;N;;;;; 1D6A3;MATHEMATICAL MONOSPACE SMALL Z;Ll;0;L; 007A;;;;N;;;;; 1D6A8;MATHEMATICAL BOLD CAPITAL ALPHA;Lu;0;L; 0391;;;;N;;;;; 1D6A9;MATHEMATICAL BOLD CAPITAL BETA;Lu;0;L; 0392;;;;N;;;;; 1D6AA;MATHEMATICAL BOLD CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; 1D6AB;MATHEMATICAL BOLD CAPITAL DELTA;Lu;0;L; 0394;;;;N;;;;; 1D6AC;MATHEMATICAL BOLD CAPITAL EPSILON;Lu;0;L; 0395;;;;N;;;;; 1D6AD;MATHEMATICAL BOLD CAPITAL ZETA;Lu;0;L; 0396;;;;N;;;;; 1D6AE;MATHEMATICAL BOLD CAPITAL ETA;Lu;0;L; 0397;;;;N;;;;; 1D6AF;MATHEMATICAL BOLD CAPITAL THETA;Lu;0;L; 0398;;;;N;;;;; 1D6B0;MATHEMATICAL BOLD CAPITAL IOTA;Lu;0;L; 0399;;;;N;;;;; 1D6B1;MATHEMATICAL BOLD CAPITAL KAPPA;Lu;0;L; 039A;;;;N;;;;; 1D6B2;MATHEMATICAL BOLD CAPITAL LAMDA;Lu;0;L; 039B;;;;N;;;;; 1D6B3;MATHEMATICAL BOLD CAPITAL MU;Lu;0;L; 039C;;;;N;;;;; 1D6B4;MATHEMATICAL BOLD CAPITAL NU;Lu;0;L; 039D;;;;N;;;;; 1D6B5;MATHEMATICAL BOLD CAPITAL XI;Lu;0;L; 039E;;;;N;;;;; 1D6B6;MATHEMATICAL BOLD CAPITAL OMICRON;Lu;0;L; 039F;;;;N;;;;; 1D6B7;MATHEMATICAL BOLD CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; 1D6B8;MATHEMATICAL BOLD CAPITAL RHO;Lu;0;L; 03A1;;;;N;;;;; 1D6B9;MATHEMATICAL BOLD CAPITAL THETA SYMBOL;Lu;0;L; 03F4;;;;N;;;;; 1D6BA;MATHEMATICAL BOLD CAPITAL SIGMA;Lu;0;L; 03A3;;;;N;;;;; 1D6BB;MATHEMATICAL BOLD CAPITAL TAU;Lu;0;L; 03A4;;;;N;;;;; 1D6BC;MATHEMATICAL BOLD CAPITAL UPSILON;Lu;0;L; 03A5;;;;N;;;;; 1D6BD;MATHEMATICAL BOLD CAPITAL PHI;Lu;0;L; 03A6;;;;N;;;;; 1D6BE;MATHEMATICAL BOLD CAPITAL CHI;Lu;0;L; 03A7;;;;N;;;;; 1D6BF;MATHEMATICAL BOLD CAPITAL PSI;Lu;0;L; 03A8;;;;N;;;;; 1D6C0;MATHEMATICAL BOLD CAPITAL OMEGA;Lu;0;L; 03A9;;;;N;;;;; 1D6C1;MATHEMATICAL BOLD NABLA;Sm;0;L; 2207;;;;N;;;;; 1D6C2;MATHEMATICAL BOLD SMALL ALPHA;Ll;0;L; 03B1;;;;N;;;;; 1D6C3;MATHEMATICAL BOLD SMALL BETA;Ll;0;L; 03B2;;;;N;;;;; 1D6C4;MATHEMATICAL BOLD SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; 1D6C5;MATHEMATICAL BOLD SMALL DELTA;Ll;0;L; 03B4;;;;N;;;;; 1D6C6;MATHEMATICAL BOLD SMALL EPSILON;Ll;0;L; 03B5;;;;N;;;;; 1D6C7;MATHEMATICAL BOLD SMALL ZETA;Ll;0;L; 03B6;;;;N;;;;; 1D6C8;MATHEMATICAL BOLD SMALL ETA;Ll;0;L; 03B7;;;;N;;;;; 1D6C9;MATHEMATICAL BOLD SMALL THETA;Ll;0;L; 03B8;;;;N;;;;; 1D6CA;MATHEMATICAL BOLD SMALL IOTA;Ll;0;L; 03B9;;;;N;;;;; 1D6CB;MATHEMATICAL BOLD SMALL KAPPA;Ll;0;L; 03BA;;;;N;;;;; 1D6CC;MATHEMATICAL BOLD SMALL LAMDA;Ll;0;L; 03BB;;;;N;;;;; 1D6CD;MATHEMATICAL BOLD SMALL MU;Ll;0;L; 03BC;;;;N;;;;; 1D6CE;MATHEMATICAL BOLD SMALL NU;Ll;0;L; 03BD;;;;N;;;;; 1D6CF;MATHEMATICAL BOLD SMALL XI;Ll;0;L; 03BE;;;;N;;;;; 1D6D0;MATHEMATICAL BOLD SMALL OMICRON;Ll;0;L; 03BF;;;;N;;;;; 1D6D1;MATHEMATICAL BOLD SMALL PI;Ll;0;L; 03C0;;;;N;;;;; 1D6D2;MATHEMATICAL BOLD SMALL RHO;Ll;0;L; 03C1;;;;N;;;;; 1D6D3;MATHEMATICAL BOLD SMALL FINAL SIGMA;Ll;0;L; 03C2;;;;N;;;;; 1D6D4;MATHEMATICAL BOLD SMALL SIGMA;Ll;0;L; 03C3;;;;N;;;;; 1D6D5;MATHEMATICAL BOLD SMALL TAU;Ll;0;L; 03C4;;;;N;;;;; 1D6D6;MATHEMATICAL BOLD SMALL UPSILON;Ll;0;L; 03C5;;;;N;;;;; 1D6D7;MATHEMATICAL BOLD SMALL PHI;Ll;0;L; 03C6;;;;N;;;;; 1D6D8;MATHEMATICAL BOLD SMALL CHI;Ll;0;L; 03C7;;;;N;;;;; 1D6D9;MATHEMATICAL BOLD SMALL PSI;Ll;0;L; 03C8;;;;N;;;;; 1D6DA;MATHEMATICAL BOLD SMALL OMEGA;Ll;0;L; 03C9;;;;N;;;;; 1D6DB;MATHEMATICAL BOLD PARTIAL DIFFERENTIAL;Sm;0;L; 2202;;;;N;;;;; 1D6DC;MATHEMATICAL BOLD EPSILON SYMBOL;Ll;0;L; 03F5;;;;N;;;;; 1D6DD;MATHEMATICAL BOLD THETA SYMBOL;Ll;0;L; 03D1;;;;N;;;;; 1D6DE;MATHEMATICAL BOLD KAPPA SYMBOL;Ll;0;L; 03F0;;;;N;;;;; 1D6DF;MATHEMATICAL BOLD PHI SYMBOL;Ll;0;L; 03D5;;;;N;;;;; 1D6E0;MATHEMATICAL BOLD RHO SYMBOL;Ll;0;L; 03F1;;;;N;;;;; 1D6E1;MATHEMATICAL BOLD PI SYMBOL;Ll;0;L; 03D6;;;;N;;;;; 1D6E2;MATHEMATICAL ITALIC CAPITAL ALPHA;Lu;0;L; 0391;;;;N;;;;; 1D6E3;MATHEMATICAL ITALIC CAPITAL BETA;Lu;0;L; 0392;;;;N;;;;; 1D6E4;MATHEMATICAL ITALIC CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; 1D6E5;MATHEMATICAL ITALIC CAPITAL DELTA;Lu;0;L; 0394;;;;N;;;;; 1D6E6;MATHEMATICAL ITALIC CAPITAL EPSILON;Lu;0;L; 0395;;;;N;;;;; 1D6E7;MATHEMATICAL ITALIC CAPITAL ZETA;Lu;0;L; 0396;;;;N;;;;; 1D6E8;MATHEMATICAL ITALIC CAPITAL ETA;Lu;0;L; 0397;;;;N;;;;; 1D6E9;MATHEMATICAL ITALIC CAPITAL THETA;Lu;0;L; 0398;;;;N;;;;; 1D6EA;MATHEMATICAL ITALIC CAPITAL IOTA;Lu;0;L; 0399;;;;N;;;;; 1D6EB;MATHEMATICAL ITALIC CAPITAL KAPPA;Lu;0;L; 039A;;;;N;;;;; 1D6EC;MATHEMATICAL ITALIC CAPITAL LAMDA;Lu;0;L; 039B;;;;N;;;;; 1D6ED;MATHEMATICAL ITALIC CAPITAL MU;Lu;0;L; 039C;;;;N;;;;; 1D6EE;MATHEMATICAL ITALIC CAPITAL NU;Lu;0;L; 039D;;;;N;;;;; 1D6EF;MATHEMATICAL ITALIC CAPITAL XI;Lu;0;L; 039E;;;;N;;;;; 1D6F0;MATHEMATICAL ITALIC CAPITAL OMICRON;Lu;0;L; 039F;;;;N;;;;; 1D6F1;MATHEMATICAL ITALIC CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; 1D6F2;MATHEMATICAL ITALIC CAPITAL RHO;Lu;0;L; 03A1;;;;N;;;;; 1D6F3;MATHEMATICAL ITALIC CAPITAL THETA SYMBOL;Lu;0;L; 03F4;;;;N;;;;; 1D6F4;MATHEMATICAL ITALIC CAPITAL SIGMA;Lu;0;L; 03A3;;;;N;;;;; 1D6F5;MATHEMATICAL ITALIC CAPITAL TAU;Lu;0;L; 03A4;;;;N;;;;; 1D6F6;MATHEMATICAL ITALIC CAPITAL UPSILON;Lu;0;L; 03A5;;;;N;;;;; 1D6F7;MATHEMATICAL ITALIC CAPITAL PHI;Lu;0;L; 03A6;;;;N;;;;; 1D6F8;MATHEMATICAL ITALIC CAPITAL CHI;Lu;0;L; 03A7;;;;N;;;;; 1D6F9;MATHEMATICAL ITALIC CAPITAL PSI;Lu;0;L; 03A8;;;;N;;;;; 1D6FA;MATHEMATICAL ITALIC CAPITAL OMEGA;Lu;0;L; 03A9;;;;N;;;;; 1D6FB;MATHEMATICAL ITALIC NABLA;Sm;0;L; 2207;;;;N;;;;; 1D6FC;MATHEMATICAL ITALIC SMALL ALPHA;Ll;0;L; 03B1;;;;N;;;;; 1D6FD;MATHEMATICAL ITALIC SMALL BETA;Ll;0;L; 03B2;;;;N;;;;; 1D6FE;MATHEMATICAL ITALIC SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; 1D6FF;MATHEMATICAL ITALIC SMALL DELTA;Ll;0;L; 03B4;;;;N;;;;; 1D700;MATHEMATICAL ITALIC SMALL EPSILON;Ll;0;L; 03B5;;;;N;;;;; 1D701;MATHEMATICAL ITALIC SMALL ZETA;Ll;0;L; 03B6;;;;N;;;;; 1D702;MATHEMATICAL ITALIC SMALL ETA;Ll;0;L; 03B7;;;;N;;;;; 1D703;MATHEMATICAL ITALIC SMALL THETA;Ll;0;L; 03B8;;;;N;;;;; 1D704;MATHEMATICAL ITALIC SMALL IOTA;Ll;0;L; 03B9;;;;N;;;;; 1D705;MATHEMATICAL ITALIC SMALL KAPPA;Ll;0;L; 03BA;;;;N;;;;; 1D706;MATHEMATICAL ITALIC SMALL LAMDA;Ll;0;L; 03BB;;;;N;;;;; 1D707;MATHEMATICAL ITALIC SMALL MU;Ll;0;L; 03BC;;;;N;;;;; 1D708;MATHEMATICAL ITALIC SMALL NU;Ll;0;L; 03BD;;;;N;;;;; 1D709;MATHEMATICAL ITALIC SMALL XI;Ll;0;L; 03BE;;;;N;;;;; 1D70A;MATHEMATICAL ITALIC SMALL OMICRON;Ll;0;L; 03BF;;;;N;;;;; 1D70B;MATHEMATICAL ITALIC SMALL PI;Ll;0;L; 03C0;;;;N;;;;; 1D70C;MATHEMATICAL ITALIC SMALL RHO;Ll;0;L; 03C1;;;;N;;;;; 1D70D;MATHEMATICAL ITALIC SMALL FINAL SIGMA;Ll;0;L; 03C2;;;;N;;;;; 1D70E;MATHEMATICAL ITALIC SMALL SIGMA;Ll;0;L; 03C3;;;;N;;;;; 1D70F;MATHEMATICAL ITALIC SMALL TAU;Ll;0;L; 03C4;;;;N;;;;; 1D710;MATHEMATICAL ITALIC SMALL UPSILON;Ll;0;L; 03C5;;;;N;;;;; 1D711;MATHEMATICAL ITALIC SMALL PHI;Ll;0;L; 03C6;;;;N;;;;; 1D712;MATHEMATICAL ITALIC SMALL CHI;Ll;0;L; 03C7;;;;N;;;;; 1D713;MATHEMATICAL ITALIC SMALL PSI;Ll;0;L; 03C8;;;;N;;;;; 1D714;MATHEMATICAL ITALIC SMALL OMEGA;Ll;0;L; 03C9;;;;N;;;;; 1D715;MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL;Sm;0;L; 2202;;;;N;;;;; 1D716;MATHEMATICAL ITALIC EPSILON SYMBOL;Ll;0;L; 03F5;;;;N;;;;; 1D717;MATHEMATICAL ITALIC THETA SYMBOL;Ll;0;L; 03D1;;;;N;;;;; 1D718;MATHEMATICAL ITALIC KAPPA SYMBOL;Ll;0;L; 03F0;;;;N;;;;; 1D719;MATHEMATICAL ITALIC PHI SYMBOL;Ll;0;L; 03D5;;;;N;;;;; 1D71A;MATHEMATICAL ITALIC RHO SYMBOL;Ll;0;L; 03F1;;;;N;;;;; 1D71B;MATHEMATICAL ITALIC PI SYMBOL;Ll;0;L; 03D6;;;;N;;;;; 1D71C;MATHEMATICAL BOLD ITALIC CAPITAL ALPHA;Lu;0;L; 0391;;;;N;;;;; 1D71D;MATHEMATICAL BOLD ITALIC CAPITAL BETA;Lu;0;L; 0392;;;;N;;;;; 1D71E;MATHEMATICAL BOLD ITALIC CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; 1D71F;MATHEMATICAL BOLD ITALIC CAPITAL DELTA;Lu;0;L; 0394;;;;N;;;;; 1D720;MATHEMATICAL BOLD ITALIC CAPITAL EPSILON;Lu;0;L; 0395;;;;N;;;;; 1D721;MATHEMATICAL BOLD ITALIC CAPITAL ZETA;Lu;0;L; 0396;;;;N;;;;; 1D722;MATHEMATICAL BOLD ITALIC CAPITAL ETA;Lu;0;L; 0397;;;;N;;;;; 1D723;MATHEMATICAL BOLD ITALIC CAPITAL THETA;Lu;0;L; 0398;;;;N;;;;; 1D724;MATHEMATICAL BOLD ITALIC CAPITAL IOTA;Lu;0;L; 0399;;;;N;;;;; 1D725;MATHEMATICAL BOLD ITALIC CAPITAL KAPPA;Lu;0;L; 039A;;;;N;;;;; 1D726;MATHEMATICAL BOLD ITALIC CAPITAL LAMDA;Lu;0;L; 039B;;;;N;;;;; 1D727;MATHEMATICAL BOLD ITALIC CAPITAL MU;Lu;0;L; 039C;;;;N;;;;; 1D728;MATHEMATICAL BOLD ITALIC CAPITAL NU;Lu;0;L; 039D;;;;N;;;;; 1D729;MATHEMATICAL BOLD ITALIC CAPITAL XI;Lu;0;L; 039E;;;;N;;;;; 1D72A;MATHEMATICAL BOLD ITALIC CAPITAL OMICRON;Lu;0;L; 039F;;;;N;;;;; 1D72B;MATHEMATICAL BOLD ITALIC CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; 1D72C;MATHEMATICAL BOLD ITALIC CAPITAL RHO;Lu;0;L; 03A1;;;;N;;;;; 1D72D;MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L; 03F4;;;;N;;;;; 1D72E;MATHEMATICAL BOLD ITALIC CAPITAL SIGMA;Lu;0;L; 03A3;;;;N;;;;; 1D72F;MATHEMATICAL BOLD ITALIC CAPITAL TAU;Lu;0;L; 03A4;;;;N;;;;; 1D730;MATHEMATICAL BOLD ITALIC CAPITAL UPSILON;Lu;0;L; 03A5;;;;N;;;;; 1D731;MATHEMATICAL BOLD ITALIC CAPITAL PHI;Lu;0;L; 03A6;;;;N;;;;; 1D732;MATHEMATICAL BOLD ITALIC CAPITAL CHI;Lu;0;L; 03A7;;;;N;;;;; 1D733;MATHEMATICAL BOLD ITALIC CAPITAL PSI;Lu;0;L; 03A8;;;;N;;;;; 1D734;MATHEMATICAL BOLD ITALIC CAPITAL OMEGA;Lu;0;L; 03A9;;;;N;;;;; 1D735;MATHEMATICAL BOLD ITALIC NABLA;Sm;0;L; 2207;;;;N;;;;; 1D736;MATHEMATICAL BOLD ITALIC SMALL ALPHA;Ll;0;L; 03B1;;;;N;;;;; 1D737;MATHEMATICAL BOLD ITALIC SMALL BETA;Ll;0;L; 03B2;;;;N;;;;; 1D738;MATHEMATICAL BOLD ITALIC SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; 1D739;MATHEMATICAL BOLD ITALIC SMALL DELTA;Ll;0;L; 03B4;;;;N;;;;; 1D73A;MATHEMATICAL BOLD ITALIC SMALL EPSILON;Ll;0;L; 03B5;;;;N;;;;; 1D73B;MATHEMATICAL BOLD ITALIC SMALL ZETA;Ll;0;L; 03B6;;;;N;;;;; 1D73C;MATHEMATICAL BOLD ITALIC SMALL ETA;Ll;0;L; 03B7;;;;N;;;;; 1D73D;MATHEMATICAL BOLD ITALIC SMALL THETA;Ll;0;L; 03B8;;;;N;;;;; 1D73E;MATHEMATICAL BOLD ITALIC SMALL IOTA;Ll;0;L; 03B9;;;;N;;;;; 1D73F;MATHEMATICAL BOLD ITALIC SMALL KAPPA;Ll;0;L; 03BA;;;;N;;;;; 1D740;MATHEMATICAL BOLD ITALIC SMALL LAMDA;Ll;0;L; 03BB;;;;N;;;;; 1D741;MATHEMATICAL BOLD ITALIC SMALL MU;Ll;0;L; 03BC;;;;N;;;;; 1D742;MATHEMATICAL BOLD ITALIC SMALL NU;Ll;0;L; 03BD;;;;N;;;;; 1D743;MATHEMATICAL BOLD ITALIC SMALL XI;Ll;0;L; 03BE;;;;N;;;;; 1D744;MATHEMATICAL BOLD ITALIC SMALL OMICRON;Ll;0;L; 03BF;;;;N;;;;; 1D745;MATHEMATICAL BOLD ITALIC SMALL PI;Ll;0;L; 03C0;;;;N;;;;; 1D746;MATHEMATICAL BOLD ITALIC SMALL RHO;Ll;0;L; 03C1;;;;N;;;;; 1D747;MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L; 03C2;;;;N;;;;; 1D748;MATHEMATICAL BOLD ITALIC SMALL SIGMA;Ll;0;L; 03C3;;;;N;;;;; 1D749;MATHEMATICAL BOLD ITALIC SMALL TAU;Ll;0;L; 03C4;;;;N;;;;; 1D74A;MATHEMATICAL BOLD ITALIC SMALL UPSILON;Ll;0;L; 03C5;;;;N;;;;; 1D74B;MATHEMATICAL BOLD ITALIC SMALL PHI;Ll;0;L; 03C6;;;;N;;;;; 1D74C;MATHEMATICAL BOLD ITALIC SMALL CHI;Ll;0;L; 03C7;;;;N;;;;; 1D74D;MATHEMATICAL BOLD ITALIC SMALL PSI;Ll;0;L; 03C8;;;;N;;;;; 1D74E;MATHEMATICAL BOLD ITALIC SMALL OMEGA;Ll;0;L; 03C9;;;;N;;;;; 1D74F;MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;L; 2202;;;;N;;;;; 1D750;MATHEMATICAL BOLD ITALIC EPSILON SYMBOL;Ll;0;L; 03F5;;;;N;;;;; 1D751;MATHEMATICAL BOLD ITALIC THETA SYMBOL;Ll;0;L; 03D1;;;;N;;;;; 1D752;MATHEMATICAL BOLD ITALIC KAPPA SYMBOL;Ll;0;L; 03F0;;;;N;;;;; 1D753;MATHEMATICAL BOLD ITALIC PHI SYMBOL;Ll;0;L; 03D5;;;;N;;;;; 1D754;MATHEMATICAL BOLD ITALIC RHO SYMBOL;Ll;0;L; 03F1;;;;N;;;;; 1D755;MATHEMATICAL BOLD ITALIC PI SYMBOL;Ll;0;L; 03D6;;;;N;;;;; 1D756;MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA;Lu;0;L; 0391;;;;N;;;;; 1D757;MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA;Lu;0;L; 0392;;;;N;;;;; 1D758;MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; 1D759;MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA;Lu;0;L; 0394;;;;N;;;;; 1D75A;MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON;Lu;0;L; 0395;;;;N;;;;; 1D75B;MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA;Lu;0;L; 0396;;;;N;;;;; 1D75C;MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA;Lu;0;L; 0397;;;;N;;;;; 1D75D;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA;Lu;0;L; 0398;;;;N;;;;; 1D75E;MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA;Lu;0;L; 0399;;;;N;;;;; 1D75F;MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA;Lu;0;L; 039A;;;;N;;;;; 1D760;MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA;Lu;0;L; 039B;;;;N;;;;; 1D761;MATHEMATICAL SANS-SERIF BOLD CAPITAL MU;Lu;0;L; 039C;;;;N;;;;; 1D762;MATHEMATICAL SANS-SERIF BOLD CAPITAL NU;Lu;0;L; 039D;;;;N;;;;; 1D763;MATHEMATICAL SANS-SERIF BOLD CAPITAL XI;Lu;0;L; 039E;;;;N;;;;; 1D764;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON;Lu;0;L; 039F;;;;N;;;;; 1D765;MATHEMATICAL SANS-SERIF BOLD CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; 1D766;MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO;Lu;0;L; 03A1;;;;N;;;;; 1D767;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL;Lu;0;L; 03F4;;;;N;;;;; 1D768;MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA;Lu;0;L; 03A3;;;;N;;;;; 1D769;MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU;Lu;0;L; 03A4;;;;N;;;;; 1D76A;MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON;Lu;0;L; 03A5;;;;N;;;;; 1D76B;MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI;Lu;0;L; 03A6;;;;N;;;;; 1D76C;MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI;Lu;0;L; 03A7;;;;N;;;;; 1D76D;MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI;Lu;0;L; 03A8;;;;N;;;;; 1D76E;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA;Lu;0;L; 03A9;;;;N;;;;; 1D76F;MATHEMATICAL SANS-SERIF BOLD NABLA;Sm;0;L; 2207;;;;N;;;;; 1D770;MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA;Ll;0;L; 03B1;;;;N;;;;; 1D771;MATHEMATICAL SANS-SERIF BOLD SMALL BETA;Ll;0;L; 03B2;;;;N;;;;; 1D772;MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; 1D773;MATHEMATICAL SANS-SERIF BOLD SMALL DELTA;Ll;0;L; 03B4;;;;N;;;;; 1D774;MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON;Ll;0;L; 03B5;;;;N;;;;; 1D775;MATHEMATICAL SANS-SERIF BOLD SMALL ZETA;Ll;0;L; 03B6;;;;N;;;;; 1D776;MATHEMATICAL SANS-SERIF BOLD SMALL ETA;Ll;0;L; 03B7;;;;N;;;;; 1D777;MATHEMATICAL SANS-SERIF BOLD SMALL THETA;Ll;0;L; 03B8;;;;N;;;;; 1D778;MATHEMATICAL SANS-SERIF BOLD SMALL IOTA;Ll;0;L; 03B9;;;;N;;;;; 1D779;MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA;Ll;0;L; 03BA;;;;N;;;;; 1D77A;MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA;Ll;0;L; 03BB;;;;N;;;;; 1D77B;MATHEMATICAL SANS-SERIF BOLD SMALL MU;Ll;0;L; 03BC;;;;N;;;;; 1D77C;MATHEMATICAL SANS-SERIF BOLD SMALL NU;Ll;0;L; 03BD;;;;N;;;;; 1D77D;MATHEMATICAL SANS-SERIF BOLD SMALL XI;Ll;0;L; 03BE;;;;N;;;;; 1D77E;MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON;Ll;0;L; 03BF;;;;N;;;;; 1D77F;MATHEMATICAL SANS-SERIF BOLD SMALL PI;Ll;0;L; 03C0;;;;N;;;;; 1D780;MATHEMATICAL SANS-SERIF BOLD SMALL RHO;Ll;0;L; 03C1;;;;N;;;;; 1D781;MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA;Ll;0;L; 03C2;;;;N;;;;; 1D782;MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA;Ll;0;L; 03C3;;;;N;;;;; 1D783;MATHEMATICAL SANS-SERIF BOLD SMALL TAU;Ll;0;L; 03C4;;;;N;;;;; 1D784;MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON;Ll;0;L; 03C5;;;;N;;;;; 1D785;MATHEMATICAL SANS-SERIF BOLD SMALL PHI;Ll;0;L; 03C6;;;;N;;;;; 1D786;MATHEMATICAL SANS-SERIF BOLD SMALL CHI;Ll;0;L; 03C7;;;;N;;;;; 1D787;MATHEMATICAL SANS-SERIF BOLD SMALL PSI;Ll;0;L; 03C8;;;;N;;;;; 1D788;MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA;Ll;0;L; 03C9;;;;N;;;;; 1D789;MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL;Sm;0;L; 2202;;;;N;;;;; 1D78A;MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL;Ll;0;L; 03F5;;;;N;;;;; 1D78B;MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL;Ll;0;L; 03D1;;;;N;;;;; 1D78C;MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL;Ll;0;L; 03F0;;;;N;;;;; 1D78D;MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL;Ll;0;L; 03D5;;;;N;;;;; 1D78E;MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL;Ll;0;L; 03F1;;;;N;;;;; 1D78F;MATHEMATICAL SANS-SERIF BOLD PI SYMBOL;Ll;0;L; 03D6;;;;N;;;;; 1D790;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA;Lu;0;L; 0391;;;;N;;;;; 1D791;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA;Lu;0;L; 0392;;;;N;;;;; 1D792;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; 1D793;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA;Lu;0;L; 0394;;;;N;;;;; 1D794;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON;Lu;0;L; 0395;;;;N;;;;; 1D795;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA;Lu;0;L; 0396;;;;N;;;;; 1D796;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA;Lu;0;L; 0397;;;;N;;;;; 1D797;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA;Lu;0;L; 0398;;;;N;;;;; 1D798;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA;Lu;0;L; 0399;;;;N;;;;; 1D799;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA;Lu;0;L; 039A;;;;N;;;;; 1D79A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA;Lu;0;L; 039B;;;;N;;;;; 1D79B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU;Lu;0;L; 039C;;;;N;;;;; 1D79C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU;Lu;0;L; 039D;;;;N;;;;; 1D79D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI;Lu;0;L; 039E;;;;N;;;;; 1D79E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON;Lu;0;L; 039F;;;;N;;;;; 1D79F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; 1D7A0;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO;Lu;0;L; 03A1;;;;N;;;;; 1D7A1;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L; 03F4;;;;N;;;;; 1D7A2;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA;Lu;0;L; 03A3;;;;N;;;;; 1D7A3;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU;Lu;0;L; 03A4;;;;N;;;;; 1D7A4;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON;Lu;0;L; 03A5;;;;N;;;;; 1D7A5;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI;Lu;0;L; 03A6;;;;N;;;;; 1D7A6;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI;Lu;0;L; 03A7;;;;N;;;;; 1D7A7;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI;Lu;0;L; 03A8;;;;N;;;;; 1D7A8;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA;Lu;0;L; 03A9;;;;N;;;;; 1D7A9;MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA;Sm;0;L; 2207;;;;N;;;;; 1D7AA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA;Ll;0;L; 03B1;;;;N;;;;; 1D7AB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA;Ll;0;L; 03B2;;;;N;;;;; 1D7AC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; 1D7AD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA;Ll;0;L; 03B4;;;;N;;;;; 1D7AE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON;Ll;0;L; 03B5;;;;N;;;;; 1D7AF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA;Ll;0;L; 03B6;;;;N;;;;; 1D7B0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA;Ll;0;L; 03B7;;;;N;;;;; 1D7B1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA;Ll;0;L; 03B8;;;;N;;;;; 1D7B2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA;Ll;0;L; 03B9;;;;N;;;;; 1D7B3;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA;Ll;0;L; 03BA;;;;N;;;;; 1D7B4;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA;Ll;0;L; 03BB;;;;N;;;;; 1D7B5;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU;Ll;0;L; 03BC;;;;N;;;;; 1D7B6;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU;Ll;0;L; 03BD;;;;N;;;;; 1D7B7;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI;Ll;0;L; 03BE;;;;N;;;;; 1D7B8;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON;Ll;0;L; 03BF;;;;N;;;;; 1D7B9;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI;Ll;0;L; 03C0;;;;N;;;;; 1D7BA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO;Ll;0;L; 03C1;;;;N;;;;; 1D7BB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L; 03C2;;;;N;;;;; 1D7BC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA;Ll;0;L; 03C3;;;;N;;;;; 1D7BD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU;Ll;0;L; 03C4;;;;N;;;;; 1D7BE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON;Ll;0;L; 03C5;;;;N;;;;; 1D7BF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI;Ll;0;L; 03C6;;;;N;;;;; 1D7C0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI;Ll;0;L; 03C7;;;;N;;;;; 1D7C1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI;Ll;0;L; 03C8;;;;N;;;;; 1D7C2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA;Ll;0;L; 03C9;;;;N;;;;; 1D7C3;MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;L; 2202;;;;N;;;;; 1D7C4;MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL;Ll;0;L; 03F5;;;;N;;;;; 1D7C5;MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL;Ll;0;L; 03D1;;;;N;;;;; 1D7C6;MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL;Ll;0;L; 03F0;;;;N;;;;; 1D7C7;MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL;Ll;0;L; 03D5;;;;N;;;;; 1D7C8;MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL;Ll;0;L; 03F1;;;;N;;;;; 1D7C9;MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL;Ll;0;L; 03D6;;;;N;;;;; 1D7CE;MATHEMATICAL BOLD DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; 1D7CF;MATHEMATICAL BOLD DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; 1D7D0;MATHEMATICAL BOLD DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; 1D7D1;MATHEMATICAL BOLD DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; 1D7D2;MATHEMATICAL BOLD DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; 1D7D3;MATHEMATICAL BOLD DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; 1D7D4;MATHEMATICAL BOLD DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; 1D7D5;MATHEMATICAL BOLD DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; 1D7D6;MATHEMATICAL BOLD DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; 1D7D7;MATHEMATICAL BOLD DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; 1D7D8;MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; 1D7D9;MATHEMATICAL DOUBLE-STRUCK DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; 1D7DA;MATHEMATICAL DOUBLE-STRUCK DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; 1D7DB;MATHEMATICAL DOUBLE-STRUCK DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; 1D7DC;MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; 1D7DD;MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; 1D7DE;MATHEMATICAL DOUBLE-STRUCK DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; 1D7DF;MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; 1D7E0;MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; 1D7E1;MATHEMATICAL DOUBLE-STRUCK DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; 1D7E2;MATHEMATICAL SANS-SERIF DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; 1D7E3;MATHEMATICAL SANS-SERIF DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; 1D7E4;MATHEMATICAL SANS-SERIF DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; 1D7E5;MATHEMATICAL SANS-SERIF DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; 1D7E6;MATHEMATICAL SANS-SERIF DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; 1D7E7;MATHEMATICAL SANS-SERIF DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; 1D7E8;MATHEMATICAL SANS-SERIF DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; 1D7E9;MATHEMATICAL SANS-SERIF DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; 1D7EA;MATHEMATICAL SANS-SERIF DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; 1D7EB;MATHEMATICAL SANS-SERIF DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; 1D7EC;MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; 1D7ED;MATHEMATICAL SANS-SERIF BOLD DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; 1D7EE;MATHEMATICAL SANS-SERIF BOLD DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; 1D7EF;MATHEMATICAL SANS-SERIF BOLD DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; 1D7F0;MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; 1D7F1;MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; 1D7F2;MATHEMATICAL SANS-SERIF BOLD DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; 1D7F3;MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; 1D7F4;MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; 1D7F5;MATHEMATICAL SANS-SERIF BOLD DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; 1D7F6;MATHEMATICAL MONOSPACE DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; 1D7F7;MATHEMATICAL MONOSPACE DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; 1D7F8;MATHEMATICAL MONOSPACE DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; 1D7F9;MATHEMATICAL MONOSPACE DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; 1D7FA;MATHEMATICAL MONOSPACE DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; 1D7FB;MATHEMATICAL MONOSPACE DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; 1D7FC;MATHEMATICAL MONOSPACE DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; 1D7FD;MATHEMATICAL MONOSPACE DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; 1D7FE;MATHEMATICAL MONOSPACE DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; 1D7FF;MATHEMATICAL MONOSPACE DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; 20000;;Lo;0;L;;;;;N;;;;; 2A6D6;;Lo;0;L;;;;;N;;;;; 2F800;CJK COMPATIBILITY IDEOGRAPH-2F800;Lo;0;L;4E3D;;;;N;;;;; 2F801;CJK COMPATIBILITY IDEOGRAPH-2F801;Lo;0;L;4E38;;;;N;;;;; 2F802;CJK COMPATIBILITY IDEOGRAPH-2F802;Lo;0;L;4E41;;;;N;;;;; 2F803;CJK COMPATIBILITY IDEOGRAPH-2F803;Lo;0;L;20122;;;;N;;;;; 2F804;CJK COMPATIBILITY IDEOGRAPH-2F804;Lo;0;L;4F60;;;;N;;;;; 2F805;CJK COMPATIBILITY IDEOGRAPH-2F805;Lo;0;L;4FAE;;;;N;;;;; 2F806;CJK COMPATIBILITY IDEOGRAPH-2F806;Lo;0;L;4FBB;;;;N;;;;; 2F807;CJK COMPATIBILITY IDEOGRAPH-2F807;Lo;0;L;5002;;;;N;;;;; 2F808;CJK COMPATIBILITY IDEOGRAPH-2F808;Lo;0;L;507A;;;;N;;;;; 2F809;CJK COMPATIBILITY IDEOGRAPH-2F809;Lo;0;L;5099;;;;N;;;;; 2F80A;CJK COMPATIBILITY IDEOGRAPH-2F80A;Lo;0;L;50E7;;;;N;;;;; 2F80B;CJK COMPATIBILITY IDEOGRAPH-2F80B;Lo;0;L;50CF;;;;N;;;;; 2F80C;CJK COMPATIBILITY IDEOGRAPH-2F80C;Lo;0;L;349E;;;;N;;;;; 2F80D;CJK COMPATIBILITY IDEOGRAPH-2F80D;Lo;0;L;2063A;;;;N;;;;; 2F80E;CJK COMPATIBILITY IDEOGRAPH-2F80E;Lo;0;L;514D;;;;N;;;;; 2F80F;CJK COMPATIBILITY IDEOGRAPH-2F80F;Lo;0;L;5154;;;;N;;;;; 2F810;CJK COMPATIBILITY IDEOGRAPH-2F810;Lo;0;L;5164;;;;N;;;;; 2F811;CJK COMPATIBILITY IDEOGRAPH-2F811;Lo;0;L;5177;;;;N;;;;; 2F812;CJK COMPATIBILITY IDEOGRAPH-2F812;Lo;0;L;2051C;;;;N;;;;; 2F813;CJK COMPATIBILITY IDEOGRAPH-2F813;Lo;0;L;34B9;;;;N;;;;; 2F814;CJK COMPATIBILITY IDEOGRAPH-2F814;Lo;0;L;5167;;;;N;;;;; 2F815;CJK COMPATIBILITY IDEOGRAPH-2F815;Lo;0;L;518D;;;;N;;;;; 2F816;CJK COMPATIBILITY IDEOGRAPH-2F816;Lo;0;L;2054B;;;;N;;;;; 2F817;CJK COMPATIBILITY IDEOGRAPH-2F817;Lo;0;L;5197;;;;N;;;;; 2F818;CJK COMPATIBILITY IDEOGRAPH-2F818;Lo;0;L;51A4;;;;N;;;;; 2F819;CJK COMPATIBILITY IDEOGRAPH-2F819;Lo;0;L;4ECC;;;;N;;;;; 2F81A;CJK COMPATIBILITY IDEOGRAPH-2F81A;Lo;0;L;51AC;;;;N;;;;; 2F81B;CJK COMPATIBILITY IDEOGRAPH-2F81B;Lo;0;L;51B5;;;;N;;;;; 2F81C;CJK COMPATIBILITY IDEOGRAPH-2F81C;Lo;0;L;291DF;;;;N;;;;; 2F81D;CJK COMPATIBILITY IDEOGRAPH-2F81D;Lo;0;L;51F5;;;;N;;;;; 2F81E;CJK COMPATIBILITY IDEOGRAPH-2F81E;Lo;0;L;5203;;;;N;;;;; 2F81F;CJK COMPATIBILITY IDEOGRAPH-2F81F;Lo;0;L;34DF;;;;N;;;;; 2F820;CJK COMPATIBILITY IDEOGRAPH-2F820;Lo;0;L;523B;;;;N;;;;; 2F821;CJK COMPATIBILITY IDEOGRAPH-2F821;Lo;0;L;5246;;;;N;;;;; 2F822;CJK COMPATIBILITY IDEOGRAPH-2F822;Lo;0;L;5272;;;;N;;;;; 2F823;CJK COMPATIBILITY IDEOGRAPH-2F823;Lo;0;L;5277;;;;N;;;;; 2F824;CJK COMPATIBILITY IDEOGRAPH-2F824;Lo;0;L;3515;;;;N;;;;; 2F825;CJK COMPATIBILITY IDEOGRAPH-2F825;Lo;0;L;52C7;;;;N;;;;; 2F826;CJK COMPATIBILITY IDEOGRAPH-2F826;Lo;0;L;52C9;;;;N;;;;; 2F827;CJK COMPATIBILITY IDEOGRAPH-2F827;Lo;0;L;52E4;;;;N;;;;; 2F828;CJK COMPATIBILITY IDEOGRAPH-2F828;Lo;0;L;52FA;;;;N;;;;; 2F829;CJK COMPATIBILITY IDEOGRAPH-2F829;Lo;0;L;5305;;;;N;;;;; 2F82A;CJK COMPATIBILITY IDEOGRAPH-2F82A;Lo;0;L;5306;;;;N;;;;; 2F82B;CJK COMPATIBILITY IDEOGRAPH-2F82B;Lo;0;L;5317;;;;N;;;;; 2F82C;CJK COMPATIBILITY IDEOGRAPH-2F82C;Lo;0;L;5349;;;;N;;;;; 2F82D;CJK COMPATIBILITY IDEOGRAPH-2F82D;Lo;0;L;5351;;;;N;;;;; 2F82E;CJK COMPATIBILITY IDEOGRAPH-2F82E;Lo;0;L;535A;;;;N;;;;; 2F82F;CJK COMPATIBILITY IDEOGRAPH-2F82F;Lo;0;L;5373;;;;N;;;;; 2F830;CJK COMPATIBILITY IDEOGRAPH-2F830;Lo;0;L;537D;;;;N;;;;; 2F831;CJK COMPATIBILITY IDEOGRAPH-2F831;Lo;0;L;537F;;;;N;;;;; 2F832;CJK COMPATIBILITY IDEOGRAPH-2F832;Lo;0;L;537F;;;;N;;;;; 2F833;CJK COMPATIBILITY IDEOGRAPH-2F833;Lo;0;L;537F;;;;N;;;;; 2F834;CJK COMPATIBILITY IDEOGRAPH-2F834;Lo;0;L;20A2C;;;;N;;;;; 2F835;CJK COMPATIBILITY IDEOGRAPH-2F835;Lo;0;L;7070;;;;N;;;;; 2F836;CJK COMPATIBILITY IDEOGRAPH-2F836;Lo;0;L;53CA;;;;N;;;;; 2F837;CJK COMPATIBILITY IDEOGRAPH-2F837;Lo;0;L;53DF;;;;N;;;;; 2F838;CJK COMPATIBILITY IDEOGRAPH-2F838;Lo;0;L;20B63;;;;N;;;;; 2F839;CJK COMPATIBILITY IDEOGRAPH-2F839;Lo;0;L;53EB;;;;N;;;;; 2F83A;CJK COMPATIBILITY IDEOGRAPH-2F83A;Lo;0;L;53F1;;;;N;;;;; 2F83B;CJK COMPATIBILITY IDEOGRAPH-2F83B;Lo;0;L;5406;;;;N;;;;; 2F83C;CJK COMPATIBILITY IDEOGRAPH-2F83C;Lo;0;L;549E;;;;N;;;;; 2F83D;CJK COMPATIBILITY IDEOGRAPH-2F83D;Lo;0;L;5438;;;;N;;;;; 2F83E;CJK COMPATIBILITY IDEOGRAPH-2F83E;Lo;0;L;5448;;;;N;;;;; 2F83F;CJK COMPATIBILITY IDEOGRAPH-2F83F;Lo;0;L;5468;;;;N;;;;; 2F840;CJK COMPATIBILITY IDEOGRAPH-2F840;Lo;0;L;54A2;;;;N;;;;; 2F841;CJK COMPATIBILITY IDEOGRAPH-2F841;Lo;0;L;54F6;;;;N;;;;; 2F842;CJK COMPATIBILITY IDEOGRAPH-2F842;Lo;0;L;5510;;;;N;;;;; 2F843;CJK COMPATIBILITY IDEOGRAPH-2F843;Lo;0;L;5553;;;;N;;;;; 2F844;CJK COMPATIBILITY IDEOGRAPH-2F844;Lo;0;L;5563;;;;N;;;;; 2F845;CJK COMPATIBILITY IDEOGRAPH-2F845;Lo;0;L;5584;;;;N;;;;; 2F846;CJK COMPATIBILITY IDEOGRAPH-2F846;Lo;0;L;5584;;;;N;;;;; 2F847;CJK COMPATIBILITY IDEOGRAPH-2F847;Lo;0;L;5599;;;;N;;;;; 2F848;CJK COMPATIBILITY IDEOGRAPH-2F848;Lo;0;L;55AB;;;;N;;;;; 2F849;CJK COMPATIBILITY IDEOGRAPH-2F849;Lo;0;L;55B3;;;;N;;;;; 2F84A;CJK COMPATIBILITY IDEOGRAPH-2F84A;Lo;0;L;55C2;;;;N;;;;; 2F84B;CJK COMPATIBILITY IDEOGRAPH-2F84B;Lo;0;L;5716;;;;N;;;;; 2F84C;CJK COMPATIBILITY IDEOGRAPH-2F84C;Lo;0;L;5606;;;;N;;;;; 2F84D;CJK COMPATIBILITY IDEOGRAPH-2F84D;Lo;0;L;5717;;;;N;;;;; 2F84E;CJK COMPATIBILITY IDEOGRAPH-2F84E;Lo;0;L;5651;;;;N;;;;; 2F84F;CJK COMPATIBILITY IDEOGRAPH-2F84F;Lo;0;L;5674;;;;N;;;;; 2F850;CJK COMPATIBILITY IDEOGRAPH-2F850;Lo;0;L;5207;;;;N;;;;; 2F851;CJK COMPATIBILITY IDEOGRAPH-2F851;Lo;0;L;58EE;;;;N;;;;; 2F852;CJK COMPATIBILITY IDEOGRAPH-2F852;Lo;0;L;57CE;;;;N;;;;; 2F853;CJK COMPATIBILITY IDEOGRAPH-2F853;Lo;0;L;57F4;;;;N;;;;; 2F854;CJK COMPATIBILITY IDEOGRAPH-2F854;Lo;0;L;580D;;;;N;;;;; 2F855;CJK COMPATIBILITY IDEOGRAPH-2F855;Lo;0;L;578B;;;;N;;;;; 2F856;CJK COMPATIBILITY IDEOGRAPH-2F856;Lo;0;L;5832;;;;N;;;;; 2F857;CJK COMPATIBILITY IDEOGRAPH-2F857;Lo;0;L;5831;;;;N;;;;; 2F858;CJK COMPATIBILITY IDEOGRAPH-2F858;Lo;0;L;58AC;;;;N;;;;; 2F859;CJK COMPATIBILITY IDEOGRAPH-2F859;Lo;0;L;214E4;;;;N;;;;; 2F85A;CJK COMPATIBILITY IDEOGRAPH-2F85A;Lo;0;L;58F2;;;;N;;;;; 2F85B;CJK COMPATIBILITY IDEOGRAPH-2F85B;Lo;0;L;58F7;;;;N;;;;; 2F85C;CJK COMPATIBILITY IDEOGRAPH-2F85C;Lo;0;L;5906;;;;N;;;;; 2F85D;CJK COMPATIBILITY IDEOGRAPH-2F85D;Lo;0;L;591A;;;;N;;;;; 2F85E;CJK COMPATIBILITY IDEOGRAPH-2F85E;Lo;0;L;5922;;;;N;;;;; 2F85F;CJK COMPATIBILITY IDEOGRAPH-2F85F;Lo;0;L;5962;;;;N;;;;; 2F860;CJK COMPATIBILITY IDEOGRAPH-2F860;Lo;0;L;216A8;;;;N;;;;; 2F861;CJK COMPATIBILITY IDEOGRAPH-2F861;Lo;0;L;216EA;;;;N;;;;; 2F862;CJK COMPATIBILITY IDEOGRAPH-2F862;Lo;0;L;59EC;;;;N;;;;; 2F863;CJK COMPATIBILITY IDEOGRAPH-2F863;Lo;0;L;5A1B;;;;N;;;;; 2F864;CJK COMPATIBILITY IDEOGRAPH-2F864;Lo;0;L;5A27;;;;N;;;;; 2F865;CJK COMPATIBILITY IDEOGRAPH-2F865;Lo;0;L;59D8;;;;N;;;;; 2F866;CJK COMPATIBILITY IDEOGRAPH-2F866;Lo;0;L;5A66;;;;N;;;;; 2F867;CJK COMPATIBILITY IDEOGRAPH-2F867;Lo;0;L;36EE;;;;N;;;;; 2F868;CJK COMPATIBILITY IDEOGRAPH-2F868;Lo;0;L;2136A;;;;N;;;;; 2F869;CJK COMPATIBILITY IDEOGRAPH-2F869;Lo;0;L;5B08;;;;N;;;;; 2F86A;CJK COMPATIBILITY IDEOGRAPH-2F86A;Lo;0;L;5B3E;;;;N;;;;; 2F86B;CJK COMPATIBILITY IDEOGRAPH-2F86B;Lo;0;L;5B3E;;;;N;;;;; 2F86C;CJK COMPATIBILITY IDEOGRAPH-2F86C;Lo;0;L;219C8;;;;N;;;;; 2F86D;CJK COMPATIBILITY IDEOGRAPH-2F86D;Lo;0;L;5BC3;;;;N;;;;; 2F86E;CJK COMPATIBILITY IDEOGRAPH-2F86E;Lo;0;L;5BD8;;;;N;;;;; 2F86F;CJK COMPATIBILITY IDEOGRAPH-2F86F;Lo;0;L;5BE7;;;;N;;;;; 2F870;CJK COMPATIBILITY IDEOGRAPH-2F870;Lo;0;L;5BF3;;;;N;;;;; 2F871;CJK COMPATIBILITY IDEOGRAPH-2F871;Lo;0;L;21B18;;;;N;;;;; 2F872;CJK COMPATIBILITY IDEOGRAPH-2F872;Lo;0;L;5BFF;;;;N;;;;; 2F873;CJK COMPATIBILITY IDEOGRAPH-2F873;Lo;0;L;5C06;;;;N;;;;; 2F874;CJK COMPATIBILITY IDEOGRAPH-2F874;Lo;0;L;5F33;;;;N;;;;; 2F875;CJK COMPATIBILITY IDEOGRAPH-2F875;Lo;0;L;5C22;;;;N;;;;; 2F876;CJK COMPATIBILITY IDEOGRAPH-2F876;Lo;0;L;3781;;;;N;;;;; 2F877;CJK COMPATIBILITY IDEOGRAPH-2F877;Lo;0;L;5C60;;;;N;;;;; 2F878;CJK COMPATIBILITY IDEOGRAPH-2F878;Lo;0;L;5C6E;;;;N;;;;; 2F879;CJK COMPATIBILITY IDEOGRAPH-2F879;Lo;0;L;5CC0;;;;N;;;;; 2F87A;CJK COMPATIBILITY IDEOGRAPH-2F87A;Lo;0;L;5C8D;;;;N;;;;; 2F87B;CJK COMPATIBILITY IDEOGRAPH-2F87B;Lo;0;L;21DE4;;;;N;;;;; 2F87C;CJK COMPATIBILITY IDEOGRAPH-2F87C;Lo;0;L;5D43;;;;N;;;;; 2F87D;CJK COMPATIBILITY IDEOGRAPH-2F87D;Lo;0;L;21DE6;;;;N;;;;; 2F87E;CJK COMPATIBILITY IDEOGRAPH-2F87E;Lo;0;L;5D6E;;;;N;;;;; 2F87F;CJK COMPATIBILITY IDEOGRAPH-2F87F;Lo;0;L;5D6B;;;;N;;;;; 2F880;CJK COMPATIBILITY IDEOGRAPH-2F880;Lo;0;L;5D7C;;;;N;;;;; 2F881;CJK COMPATIBILITY IDEOGRAPH-2F881;Lo;0;L;5DE1;;;;N;;;;; 2F882;CJK COMPATIBILITY IDEOGRAPH-2F882;Lo;0;L;5DE2;;;;N;;;;; 2F883;CJK COMPATIBILITY IDEOGRAPH-2F883;Lo;0;L;382F;;;;N;;;;; 2F884;CJK COMPATIBILITY IDEOGRAPH-2F884;Lo;0;L;5DFD;;;;N;;;;; 2F885;CJK COMPATIBILITY IDEOGRAPH-2F885;Lo;0;L;5E28;;;;N;;;;; 2F886;CJK COMPATIBILITY IDEOGRAPH-2F886;Lo;0;L;5E3D;;;;N;;;;; 2F887;CJK COMPATIBILITY IDEOGRAPH-2F887;Lo;0;L;5E69;;;;N;;;;; 2F888;CJK COMPATIBILITY IDEOGRAPH-2F888;Lo;0;L;3862;;;;N;;;;; 2F889;CJK COMPATIBILITY IDEOGRAPH-2F889;Lo;0;L;22183;;;;N;;;;; 2F88A;CJK COMPATIBILITY IDEOGRAPH-2F88A;Lo;0;L;387C;;;;N;;;;; 2F88B;CJK COMPATIBILITY IDEOGRAPH-2F88B;Lo;0;L;5EB0;;;;N;;;;; 2F88C;CJK COMPATIBILITY IDEOGRAPH-2F88C;Lo;0;L;5EB3;;;;N;;;;; 2F88D;CJK COMPATIBILITY IDEOGRAPH-2F88D;Lo;0;L;5EB6;;;;N;;;;; 2F88E;CJK COMPATIBILITY IDEOGRAPH-2F88E;Lo;0;L;5ECA;;;;N;;;;; 2F88F;CJK COMPATIBILITY IDEOGRAPH-2F88F;Lo;0;L;2A392;;;;N;;;;; 2F890;CJK COMPATIBILITY IDEOGRAPH-2F890;Lo;0;L;5EFE;;;;N;;;;; 2F891;CJK COMPATIBILITY IDEOGRAPH-2F891;Lo;0;L;22331;;;;N;;;;; 2F892;CJK COMPATIBILITY IDEOGRAPH-2F892;Lo;0;L;22331;;;;N;;;;; 2F893;CJK COMPATIBILITY IDEOGRAPH-2F893;Lo;0;L;8201;;;;N;;;;; 2F894;CJK COMPATIBILITY IDEOGRAPH-2F894;Lo;0;L;5F22;;;;N;;;;; 2F895;CJK COMPATIBILITY IDEOGRAPH-2F895;Lo;0;L;5F22;;;;N;;;;; 2F896;CJK COMPATIBILITY IDEOGRAPH-2F896;Lo;0;L;38C7;;;;N;;;;; 2F897;CJK COMPATIBILITY IDEOGRAPH-2F897;Lo;0;L;232B8;;;;N;;;;; 2F898;CJK COMPATIBILITY IDEOGRAPH-2F898;Lo;0;L;261DA;;;;N;;;;; 2F899;CJK COMPATIBILITY IDEOGRAPH-2F899;Lo;0;L;5F62;;;;N;;;;; 2F89A;CJK COMPATIBILITY IDEOGRAPH-2F89A;Lo;0;L;5F6B;;;;N;;;;; 2F89B;CJK COMPATIBILITY IDEOGRAPH-2F89B;Lo;0;L;38E3;;;;N;;;;; 2F89C;CJK COMPATIBILITY IDEOGRAPH-2F89C;Lo;0;L;5F9A;;;;N;;;;; 2F89D;CJK COMPATIBILITY IDEOGRAPH-2F89D;Lo;0;L;5FCD;;;;N;;;;; 2F89E;CJK COMPATIBILITY IDEOGRAPH-2F89E;Lo;0;L;5FD7;;;;N;;;;; 2F89F;CJK COMPATIBILITY IDEOGRAPH-2F89F;Lo;0;L;5FF9;;;;N;;;;; 2F8A0;CJK COMPATIBILITY IDEOGRAPH-2F8A0;Lo;0;L;6081;;;;N;;;;; 2F8A1;CJK COMPATIBILITY IDEOGRAPH-2F8A1;Lo;0;L;393A;;;;N;;;;; 2F8A2;CJK COMPATIBILITY IDEOGRAPH-2F8A2;Lo;0;L;391C;;;;N;;;;; 2F8A3;CJK COMPATIBILITY IDEOGRAPH-2F8A3;Lo;0;L;6094;;;;N;;;;; 2F8A4;CJK COMPATIBILITY IDEOGRAPH-2F8A4;Lo;0;L;226D4;;;;N;;;;; 2F8A5;CJK COMPATIBILITY IDEOGRAPH-2F8A5;Lo;0;L;60C7;;;;N;;;;; 2F8A6;CJK COMPATIBILITY IDEOGRAPH-2F8A6;Lo;0;L;6148;;;;N;;;;; 2F8A7;CJK COMPATIBILITY IDEOGRAPH-2F8A7;Lo;0;L;614C;;;;N;;;;; 2F8A8;CJK COMPATIBILITY IDEOGRAPH-2F8A8;Lo;0;L;614E;;;;N;;;;; 2F8A9;CJK COMPATIBILITY IDEOGRAPH-2F8A9;Lo;0;L;614C;;;;N;;;;; 2F8AA;CJK COMPATIBILITY IDEOGRAPH-2F8AA;Lo;0;L;617A;;;;N;;;;; 2F8AB;CJK COMPATIBILITY IDEOGRAPH-2F8AB;Lo;0;L;618E;;;;N;;;;; 2F8AC;CJK COMPATIBILITY IDEOGRAPH-2F8AC;Lo;0;L;61B2;;;;N;;;;; 2F8AD;CJK COMPATIBILITY IDEOGRAPH-2F8AD;Lo;0;L;61A4;;;;N;;;;; 2F8AE;CJK COMPATIBILITY IDEOGRAPH-2F8AE;Lo;0;L;61AF;;;;N;;;;; 2F8AF;CJK COMPATIBILITY IDEOGRAPH-2F8AF;Lo;0;L;61DE;;;;N;;;;; 2F8B0;CJK COMPATIBILITY IDEOGRAPH-2F8B0;Lo;0;L;61F2;;;;N;;;;; 2F8B1;CJK COMPATIBILITY IDEOGRAPH-2F8B1;Lo;0;L;61F6;;;;N;;;;; 2F8B2;CJK COMPATIBILITY IDEOGRAPH-2F8B2;Lo;0;L;6210;;;;N;;;;; 2F8B3;CJK COMPATIBILITY IDEOGRAPH-2F8B3;Lo;0;L;621B;;;;N;;;;; 2F8B4;CJK COMPATIBILITY IDEOGRAPH-2F8B4;Lo;0;L;625D;;;;N;;;;; 2F8B5;CJK COMPATIBILITY IDEOGRAPH-2F8B5;Lo;0;L;62B1;;;;N;;;;; 2F8B6;CJK COMPATIBILITY IDEOGRAPH-2F8B6;Lo;0;L;62D4;;;;N;;;;; 2F8B7;CJK COMPATIBILITY IDEOGRAPH-2F8B7;Lo;0;L;6350;;;;N;;;;; 2F8B8;CJK COMPATIBILITY IDEOGRAPH-2F8B8;Lo;0;L;22B0C;;;;N;;;;; 2F8B9;CJK COMPATIBILITY IDEOGRAPH-2F8B9;Lo;0;L;633D;;;;N;;;;; 2F8BA;CJK COMPATIBILITY IDEOGRAPH-2F8BA;Lo;0;L;62FC;;;;N;;;;; 2F8BB;CJK COMPATIBILITY IDEOGRAPH-2F8BB;Lo;0;L;6368;;;;N;;;;; 2F8BC;CJK COMPATIBILITY IDEOGRAPH-2F8BC;Lo;0;L;6383;;;;N;;;;; 2F8BD;CJK COMPATIBILITY IDEOGRAPH-2F8BD;Lo;0;L;63E4;;;;N;;;;; 2F8BE;CJK COMPATIBILITY IDEOGRAPH-2F8BE;Lo;0;L;22BF1;;;;N;;;;; 2F8BF;CJK COMPATIBILITY IDEOGRAPH-2F8BF;Lo;0;L;6422;;;;N;;;;; 2F8C0;CJK COMPATIBILITY IDEOGRAPH-2F8C0;Lo;0;L;63C5;;;;N;;;;; 2F8C1;CJK COMPATIBILITY IDEOGRAPH-2F8C1;Lo;0;L;63A9;;;;N;;;;; 2F8C2;CJK COMPATIBILITY IDEOGRAPH-2F8C2;Lo;0;L;3A2E;;;;N;;;;; 2F8C3;CJK COMPATIBILITY IDEOGRAPH-2F8C3;Lo;0;L;6469;;;;N;;;;; 2F8C4;CJK COMPATIBILITY IDEOGRAPH-2F8C4;Lo;0;L;647E;;;;N;;;;; 2F8C5;CJK COMPATIBILITY IDEOGRAPH-2F8C5;Lo;0;L;649D;;;;N;;;;; 2F8C6;CJK COMPATIBILITY IDEOGRAPH-2F8C6;Lo;0;L;6477;;;;N;;;;; 2F8C7;CJK COMPATIBILITY IDEOGRAPH-2F8C7;Lo;0;L;3A6C;;;;N;;;;; 2F8C8;CJK COMPATIBILITY IDEOGRAPH-2F8C8;Lo;0;L;654F;;;;N;;;;; 2F8C9;CJK COMPATIBILITY IDEOGRAPH-2F8C9;Lo;0;L;656C;;;;N;;;;; 2F8CA;CJK COMPATIBILITY IDEOGRAPH-2F8CA;Lo;0;L;2300A;;;;N;;;;; 2F8CB;CJK COMPATIBILITY IDEOGRAPH-2F8CB;Lo;0;L;65E3;;;;N;;;;; 2F8CC;CJK COMPATIBILITY IDEOGRAPH-2F8CC;Lo;0;L;66F8;;;;N;;;;; 2F8CD;CJK COMPATIBILITY IDEOGRAPH-2F8CD;Lo;0;L;6649;;;;N;;;;; 2F8CE;CJK COMPATIBILITY IDEOGRAPH-2F8CE;Lo;0;L;3B19;;;;N;;;;; 2F8CF;CJK COMPATIBILITY IDEOGRAPH-2F8CF;Lo;0;L;6691;;;;N;;;;; 2F8D0;CJK COMPATIBILITY IDEOGRAPH-2F8D0;Lo;0;L;3B08;;;;N;;;;; 2F8D1;CJK COMPATIBILITY IDEOGRAPH-2F8D1;Lo;0;L;3AE4;;;;N;;;;; 2F8D2;CJK COMPATIBILITY IDEOGRAPH-2F8D2;Lo;0;L;5192;;;;N;;;;; 2F8D3;CJK COMPATIBILITY IDEOGRAPH-2F8D3;Lo;0;L;5195;;;;N;;;;; 2F8D4;CJK COMPATIBILITY IDEOGRAPH-2F8D4;Lo;0;L;6700;;;;N;;;;; 2F8D5;CJK COMPATIBILITY IDEOGRAPH-2F8D5;Lo;0;L;669C;;;;N;;;;; 2F8D6;CJK COMPATIBILITY IDEOGRAPH-2F8D6;Lo;0;L;80AD;;;;N;;;;; 2F8D7;CJK COMPATIBILITY IDEOGRAPH-2F8D7;Lo;0;L;43D9;;;;N;;;;; 2F8D8;CJK COMPATIBILITY IDEOGRAPH-2F8D8;Lo;0;L;6717;;;;N;;;;; 2F8D9;CJK COMPATIBILITY IDEOGRAPH-2F8D9;Lo;0;L;671B;;;;N;;;;; 2F8DA;CJK COMPATIBILITY IDEOGRAPH-2F8DA;Lo;0;L;6721;;;;N;;;;; 2F8DB;CJK COMPATIBILITY IDEOGRAPH-2F8DB;Lo;0;L;675E;;;;N;;;;; 2F8DC;CJK COMPATIBILITY IDEOGRAPH-2F8DC;Lo;0;L;6753;;;;N;;;;; 2F8DD;CJK COMPATIBILITY IDEOGRAPH-2F8DD;Lo;0;L;233C3;;;;N;;;;; 2F8DE;CJK COMPATIBILITY IDEOGRAPH-2F8DE;Lo;0;L;3B49;;;;N;;;;; 2F8DF;CJK COMPATIBILITY IDEOGRAPH-2F8DF;Lo;0;L;67FA;;;;N;;;;; 2F8E0;CJK COMPATIBILITY IDEOGRAPH-2F8E0;Lo;0;L;6785;;;;N;;;;; 2F8E1;CJK COMPATIBILITY IDEOGRAPH-2F8E1;Lo;0;L;6852;;;;N;;;;; 2F8E2;CJK COMPATIBILITY IDEOGRAPH-2F8E2;Lo;0;L;6885;;;;N;;;;; 2F8E3;CJK COMPATIBILITY IDEOGRAPH-2F8E3;Lo;0;L;2346D;;;;N;;;;; 2F8E4;CJK COMPATIBILITY IDEOGRAPH-2F8E4;Lo;0;L;688E;;;;N;;;;; 2F8E5;CJK COMPATIBILITY IDEOGRAPH-2F8E5;Lo;0;L;681F;;;;N;;;;; 2F8E6;CJK COMPATIBILITY IDEOGRAPH-2F8E6;Lo;0;L;6914;;;;N;;;;; 2F8E7;CJK COMPATIBILITY IDEOGRAPH-2F8E7;Lo;0;L;3B9D;;;;N;;;;; 2F8E8;CJK COMPATIBILITY IDEOGRAPH-2F8E8;Lo;0;L;6942;;;;N;;;;; 2F8E9;CJK COMPATIBILITY IDEOGRAPH-2F8E9;Lo;0;L;69A3;;;;N;;;;; 2F8EA;CJK COMPATIBILITY IDEOGRAPH-2F8EA;Lo;0;L;69EA;;;;N;;;;; 2F8EB;CJK COMPATIBILITY IDEOGRAPH-2F8EB;Lo;0;L;6AA8;;;;N;;;;; 2F8EC;CJK COMPATIBILITY IDEOGRAPH-2F8EC;Lo;0;L;236A3;;;;N;;;;; 2F8ED;CJK COMPATIBILITY IDEOGRAPH-2F8ED;Lo;0;L;6ADB;;;;N;;;;; 2F8EE;CJK COMPATIBILITY IDEOGRAPH-2F8EE;Lo;0;L;3C18;;;;N;;;;; 2F8EF;CJK COMPATIBILITY IDEOGRAPH-2F8EF;Lo;0;L;6B21;;;;N;;;;; 2F8F0;CJK COMPATIBILITY IDEOGRAPH-2F8F0;Lo;0;L;238A7;;;;N;;;;; 2F8F1;CJK COMPATIBILITY IDEOGRAPH-2F8F1;Lo;0;L;6B54;;;;N;;;;; 2F8F2;CJK COMPATIBILITY IDEOGRAPH-2F8F2;Lo;0;L;3C4E;;;;N;;;;; 2F8F3;CJK COMPATIBILITY IDEOGRAPH-2F8F3;Lo;0;L;6B72;;;;N;;;;; 2F8F4;CJK COMPATIBILITY IDEOGRAPH-2F8F4;Lo;0;L;6B9F;;;;N;;;;; 2F8F5;CJK COMPATIBILITY IDEOGRAPH-2F8F5;Lo;0;L;6BBA;;;;N;;;;; 2F8F6;CJK COMPATIBILITY IDEOGRAPH-2F8F6;Lo;0;L;6BBB;;;;N;;;;; 2F8F7;CJK COMPATIBILITY IDEOGRAPH-2F8F7;Lo;0;L;23A8D;;;;N;;;;; 2F8F8;CJK COMPATIBILITY IDEOGRAPH-2F8F8;Lo;0;L;21D0B;;;;N;;;;; 2F8F9;CJK COMPATIBILITY IDEOGRAPH-2F8F9;Lo;0;L;23AFA;;;;N;;;;; 2F8FA;CJK COMPATIBILITY IDEOGRAPH-2F8FA;Lo;0;L;6C4E;;;;N;;;;; 2F8FB;CJK COMPATIBILITY IDEOGRAPH-2F8FB;Lo;0;L;23CBC;;;;N;;;;; 2F8FC;CJK COMPATIBILITY IDEOGRAPH-2F8FC;Lo;0;L;6CBF;;;;N;;;;; 2F8FD;CJK COMPATIBILITY IDEOGRAPH-2F8FD;Lo;0;L;6CCD;;;;N;;;;; 2F8FE;CJK COMPATIBILITY IDEOGRAPH-2F8FE;Lo;0;L;6C67;;;;N;;;;; 2F8FF;CJK COMPATIBILITY IDEOGRAPH-2F8FF;Lo;0;L;6D16;;;;N;;;;; 2F900;CJK COMPATIBILITY IDEOGRAPH-2F900;Lo;0;L;6D3E;;;;N;;;;; 2F901;CJK COMPATIBILITY IDEOGRAPH-2F901;Lo;0;L;6D77;;;;N;;;;; 2F902;CJK COMPATIBILITY IDEOGRAPH-2F902;Lo;0;L;6D41;;;;N;;;;; 2F903;CJK COMPATIBILITY IDEOGRAPH-2F903;Lo;0;L;6D69;;;;N;;;;; 2F904;CJK COMPATIBILITY IDEOGRAPH-2F904;Lo;0;L;6D78;;;;N;;;;; 2F905;CJK COMPATIBILITY IDEOGRAPH-2F905;Lo;0;L;6D85;;;;N;;;;; 2F906;CJK COMPATIBILITY IDEOGRAPH-2F906;Lo;0;L;23D1E;;;;N;;;;; 2F907;CJK COMPATIBILITY IDEOGRAPH-2F907;Lo;0;L;6D34;;;;N;;;;; 2F908;CJK COMPATIBILITY IDEOGRAPH-2F908;Lo;0;L;6E2F;;;;N;;;;; 2F909;CJK COMPATIBILITY IDEOGRAPH-2F909;Lo;0;L;6E6E;;;;N;;;;; 2F90A;CJK COMPATIBILITY IDEOGRAPH-2F90A;Lo;0;L;3D33;;;;N;;;;; 2F90B;CJK COMPATIBILITY IDEOGRAPH-2F90B;Lo;0;L;6ECB;;;;N;;;;; 2F90C;CJK COMPATIBILITY IDEOGRAPH-2F90C;Lo;0;L;6EC7;;;;N;;;;; 2F90D;CJK COMPATIBILITY IDEOGRAPH-2F90D;Lo;0;L;23ED1;;;;N;;;;; 2F90E;CJK COMPATIBILITY IDEOGRAPH-2F90E;Lo;0;L;6DF9;;;;N;;;;; 2F90F;CJK COMPATIBILITY IDEOGRAPH-2F90F;Lo;0;L;6F6E;;;;N;;;;; 2F910;CJK COMPATIBILITY IDEOGRAPH-2F910;Lo;0;L;23F5E;;;;N;;;;; 2F911;CJK COMPATIBILITY IDEOGRAPH-2F911;Lo;0;L;23F8E;;;;N;;;;; 2F912;CJK COMPATIBILITY IDEOGRAPH-2F912;Lo;0;L;6FC6;;;;N;;;;; 2F913;CJK COMPATIBILITY IDEOGRAPH-2F913;Lo;0;L;7039;;;;N;;;;; 2F914;CJK COMPATIBILITY IDEOGRAPH-2F914;Lo;0;L;701E;;;;N;;;;; 2F915;CJK COMPATIBILITY IDEOGRAPH-2F915;Lo;0;L;701B;;;;N;;;;; 2F916;CJK COMPATIBILITY IDEOGRAPH-2F916;Lo;0;L;3D96;;;;N;;;;; 2F917;CJK COMPATIBILITY IDEOGRAPH-2F917;Lo;0;L;704A;;;;N;;;;; 2F918;CJK COMPATIBILITY IDEOGRAPH-2F918;Lo;0;L;707D;;;;N;;;;; 2F919;CJK COMPATIBILITY IDEOGRAPH-2F919;Lo;0;L;7077;;;;N;;;;; 2F91A;CJK COMPATIBILITY IDEOGRAPH-2F91A;Lo;0;L;70AD;;;;N;;;;; 2F91B;CJK COMPATIBILITY IDEOGRAPH-2F91B;Lo;0;L;20525;;;;N;;;;; 2F91C;CJK COMPATIBILITY IDEOGRAPH-2F91C;Lo;0;L;7145;;;;N;;;;; 2F91D;CJK COMPATIBILITY IDEOGRAPH-2F91D;Lo;0;L;24263;;;;N;;;;; 2F91E;CJK COMPATIBILITY IDEOGRAPH-2F91E;Lo;0;L;719C;;;;N;;;;; 2F91F;CJK COMPATIBILITY IDEOGRAPH-2F91F;Lo;0;L;43AB;;;;N;;;;; 2F920;CJK COMPATIBILITY IDEOGRAPH-2F920;Lo;0;L;7228;;;;N;;;;; 2F921;CJK COMPATIBILITY IDEOGRAPH-2F921;Lo;0;L;7235;;;;N;;;;; 2F922;CJK COMPATIBILITY IDEOGRAPH-2F922;Lo;0;L;7250;;;;N;;;;; 2F923;CJK COMPATIBILITY IDEOGRAPH-2F923;Lo;0;L;24608;;;;N;;;;; 2F924;CJK COMPATIBILITY IDEOGRAPH-2F924;Lo;0;L;7280;;;;N;;;;; 2F925;CJK COMPATIBILITY IDEOGRAPH-2F925;Lo;0;L;7295;;;;N;;;;; 2F926;CJK COMPATIBILITY IDEOGRAPH-2F926;Lo;0;L;24735;;;;N;;;;; 2F927;CJK COMPATIBILITY IDEOGRAPH-2F927;Lo;0;L;24814;;;;N;;;;; 2F928;CJK COMPATIBILITY IDEOGRAPH-2F928;Lo;0;L;737A;;;;N;;;;; 2F929;CJK COMPATIBILITY IDEOGRAPH-2F929;Lo;0;L;738B;;;;N;;;;; 2F92A;CJK COMPATIBILITY IDEOGRAPH-2F92A;Lo;0;L;3EAC;;;;N;;;;; 2F92B;CJK COMPATIBILITY IDEOGRAPH-2F92B;Lo;0;L;73A5;;;;N;;;;; 2F92C;CJK COMPATIBILITY IDEOGRAPH-2F92C;Lo;0;L;3EB8;;;;N;;;;; 2F92D;CJK COMPATIBILITY IDEOGRAPH-2F92D;Lo;0;L;3EB8;;;;N;;;;; 2F92E;CJK COMPATIBILITY IDEOGRAPH-2F92E;Lo;0;L;7447;;;;N;;;;; 2F92F;CJK COMPATIBILITY IDEOGRAPH-2F92F;Lo;0;L;745C;;;;N;;;;; 2F930;CJK COMPATIBILITY IDEOGRAPH-2F930;Lo;0;L;7471;;;;N;;;;; 2F931;CJK COMPATIBILITY IDEOGRAPH-2F931;Lo;0;L;7485;;;;N;;;;; 2F932;CJK COMPATIBILITY IDEOGRAPH-2F932;Lo;0;L;74CA;;;;N;;;;; 2F933;CJK COMPATIBILITY IDEOGRAPH-2F933;Lo;0;L;3F1B;;;;N;;;;; 2F934;CJK COMPATIBILITY IDEOGRAPH-2F934;Lo;0;L;7524;;;;N;;;;; 2F935;CJK COMPATIBILITY IDEOGRAPH-2F935;Lo;0;L;24C36;;;;N;;;;; 2F936;CJK COMPATIBILITY IDEOGRAPH-2F936;Lo;0;L;753E;;;;N;;;;; 2F937;CJK COMPATIBILITY IDEOGRAPH-2F937;Lo;0;L;24C92;;;;N;;;;; 2F938;CJK COMPATIBILITY IDEOGRAPH-2F938;Lo;0;L;7570;;;;N;;;;; 2F939;CJK COMPATIBILITY IDEOGRAPH-2F939;Lo;0;L;2219F;;;;N;;;;; 2F93A;CJK COMPATIBILITY IDEOGRAPH-2F93A;Lo;0;L;7610;;;;N;;;;; 2F93B;CJK COMPATIBILITY IDEOGRAPH-2F93B;Lo;0;L;24FA1;;;;N;;;;; 2F93C;CJK COMPATIBILITY IDEOGRAPH-2F93C;Lo;0;L;24FB8;;;;N;;;;; 2F93D;CJK COMPATIBILITY IDEOGRAPH-2F93D;Lo;0;L;25044;;;;N;;;;; 2F93E;CJK COMPATIBILITY IDEOGRAPH-2F93E;Lo;0;L;3FFC;;;;N;;;;; 2F93F;CJK COMPATIBILITY IDEOGRAPH-2F93F;Lo;0;L;4008;;;;N;;;;; 2F940;CJK COMPATIBILITY IDEOGRAPH-2F940;Lo;0;L;76F4;;;;N;;;;; 2F941;CJK COMPATIBILITY IDEOGRAPH-2F941;Lo;0;L;250F3;;;;N;;;;; 2F942;CJK COMPATIBILITY IDEOGRAPH-2F942;Lo;0;L;250F2;;;;N;;;;; 2F943;CJK COMPATIBILITY IDEOGRAPH-2F943;Lo;0;L;25119;;;;N;;;;; 2F944;CJK COMPATIBILITY IDEOGRAPH-2F944;Lo;0;L;25133;;;;N;;;;; 2F945;CJK COMPATIBILITY IDEOGRAPH-2F945;Lo;0;L;771E;;;;N;;;;; 2F946;CJK COMPATIBILITY IDEOGRAPH-2F946;Lo;0;L;771F;;;;N;;;;; 2F947;CJK COMPATIBILITY IDEOGRAPH-2F947;Lo;0;L;771F;;;;N;;;;; 2F948;CJK COMPATIBILITY IDEOGRAPH-2F948;Lo;0;L;774A;;;;N;;;;; 2F949;CJK COMPATIBILITY IDEOGRAPH-2F949;Lo;0;L;4039;;;;N;;;;; 2F94A;CJK COMPATIBILITY IDEOGRAPH-2F94A;Lo;0;L;778B;;;;N;;;;; 2F94B;CJK COMPATIBILITY IDEOGRAPH-2F94B;Lo;0;L;4046;;;;N;;;;; 2F94C;CJK COMPATIBILITY IDEOGRAPH-2F94C;Lo;0;L;4096;;;;N;;;;; 2F94D;CJK COMPATIBILITY IDEOGRAPH-2F94D;Lo;0;L;2541D;;;;N;;;;; 2F94E;CJK COMPATIBILITY IDEOGRAPH-2F94E;Lo;0;L;784E;;;;N;;;;; 2F94F;CJK COMPATIBILITY IDEOGRAPH-2F94F;Lo;0;L;788C;;;;N;;;;; 2F950;CJK COMPATIBILITY IDEOGRAPH-2F950;Lo;0;L;78CC;;;;N;;;;; 2F951;CJK COMPATIBILITY IDEOGRAPH-2F951;Lo;0;L;40E3;;;;N;;;;; 2F952;CJK COMPATIBILITY IDEOGRAPH-2F952;Lo;0;L;25626;;;;N;;;;; 2F953;CJK COMPATIBILITY IDEOGRAPH-2F953;Lo;0;L;7956;;;;N;;;;; 2F954;CJK COMPATIBILITY IDEOGRAPH-2F954;Lo;0;L;2569A;;;;N;;;;; 2F955;CJK COMPATIBILITY IDEOGRAPH-2F955;Lo;0;L;256C5;;;;N;;;;; 2F956;CJK COMPATIBILITY IDEOGRAPH-2F956;Lo;0;L;798F;;;;N;;;;; 2F957;CJK COMPATIBILITY IDEOGRAPH-2F957;Lo;0;L;79EB;;;;N;;;;; 2F958;CJK COMPATIBILITY IDEOGRAPH-2F958;Lo;0;L;412F;;;;N;;;;; 2F959;CJK COMPATIBILITY IDEOGRAPH-2F959;Lo;0;L;7A40;;;;N;;;;; 2F95A;CJK COMPATIBILITY IDEOGRAPH-2F95A;Lo;0;L;7A4A;;;;N;;;;; 2F95B;CJK COMPATIBILITY IDEOGRAPH-2F95B;Lo;0;L;7A4F;;;;N;;;;; 2F95C;CJK COMPATIBILITY IDEOGRAPH-2F95C;Lo;0;L;2597C;;;;N;;;;; 2F95D;CJK COMPATIBILITY IDEOGRAPH-2F95D;Lo;0;L;25AA7;;;;N;;;;; 2F95E;CJK COMPATIBILITY IDEOGRAPH-2F95E;Lo;0;L;25AA7;;;;N;;;;; 2F95F;CJK COMPATIBILITY IDEOGRAPH-2F95F;Lo;0;L;7AAE;;;;N;;;;; 2F960;CJK COMPATIBILITY IDEOGRAPH-2F960;Lo;0;L;4202;;;;N;;;;; 2F961;CJK COMPATIBILITY IDEOGRAPH-2F961;Lo;0;L;25BAB;;;;N;;;;; 2F962;CJK COMPATIBILITY IDEOGRAPH-2F962;Lo;0;L;7BC6;;;;N;;;;; 2F963;CJK COMPATIBILITY IDEOGRAPH-2F963;Lo;0;L;7BC9;;;;N;;;;; 2F964;CJK COMPATIBILITY IDEOGRAPH-2F964;Lo;0;L;4227;;;;N;;;;; 2F965;CJK COMPATIBILITY IDEOGRAPH-2F965;Lo;0;L;25C80;;;;N;;;;; 2F966;CJK COMPATIBILITY IDEOGRAPH-2F966;Lo;0;L;7CD2;;;;N;;;;; 2F967;CJK COMPATIBILITY IDEOGRAPH-2F967;Lo;0;L;42A0;;;;N;;;;; 2F968;CJK COMPATIBILITY IDEOGRAPH-2F968;Lo;0;L;7CE8;;;;N;;;;; 2F969;CJK COMPATIBILITY IDEOGRAPH-2F969;Lo;0;L;7CE3;;;;N;;;;; 2F96A;CJK COMPATIBILITY IDEOGRAPH-2F96A;Lo;0;L;7D00;;;;N;;;;; 2F96B;CJK COMPATIBILITY IDEOGRAPH-2F96B;Lo;0;L;25F86;;;;N;;;;; 2F96C;CJK COMPATIBILITY IDEOGRAPH-2F96C;Lo;0;L;7D63;;;;N;;;;; 2F96D;CJK COMPATIBILITY IDEOGRAPH-2F96D;Lo;0;L;4301;;;;N;;;;; 2F96E;CJK COMPATIBILITY IDEOGRAPH-2F96E;Lo;0;L;7DC7;;;;N;;;;; 2F96F;CJK COMPATIBILITY IDEOGRAPH-2F96F;Lo;0;L;7E02;;;;N;;;;; 2F970;CJK COMPATIBILITY IDEOGRAPH-2F970;Lo;0;L;7E45;;;;N;;;;; 2F971;CJK COMPATIBILITY IDEOGRAPH-2F971;Lo;0;L;4334;;;;N;;;;; 2F972;CJK COMPATIBILITY IDEOGRAPH-2F972;Lo;0;L;26228;;;;N;;;;; 2F973;CJK COMPATIBILITY IDEOGRAPH-2F973;Lo;0;L;26247;;;;N;;;;; 2F974;CJK COMPATIBILITY IDEOGRAPH-2F974;Lo;0;L;4359;;;;N;;;;; 2F975;CJK COMPATIBILITY IDEOGRAPH-2F975;Lo;0;L;262D9;;;;N;;;;; 2F976;CJK COMPATIBILITY IDEOGRAPH-2F976;Lo;0;L;7F7A;;;;N;;;;; 2F977;CJK COMPATIBILITY IDEOGRAPH-2F977;Lo;0;L;2633E;;;;N;;;;; 2F978;CJK COMPATIBILITY IDEOGRAPH-2F978;Lo;0;L;7F95;;;;N;;;;; 2F979;CJK COMPATIBILITY IDEOGRAPH-2F979;Lo;0;L;7FFA;;;;N;;;;; 2F97A;CJK COMPATIBILITY IDEOGRAPH-2F97A;Lo;0;L;8005;;;;N;;;;; 2F97B;CJK COMPATIBILITY IDEOGRAPH-2F97B;Lo;0;L;264DA;;;;N;;;;; 2F97C;CJK COMPATIBILITY IDEOGRAPH-2F97C;Lo;0;L;26523;;;;N;;;;; 2F97D;CJK COMPATIBILITY IDEOGRAPH-2F97D;Lo;0;L;8060;;;;N;;;;; 2F97E;CJK COMPATIBILITY IDEOGRAPH-2F97E;Lo;0;L;265A8;;;;N;;;;; 2F97F;CJK COMPATIBILITY IDEOGRAPH-2F97F;Lo;0;L;8070;;;;N;;;;; 2F980;CJK COMPATIBILITY IDEOGRAPH-2F980;Lo;0;L;2335F;;;;N;;;;; 2F981;CJK COMPATIBILITY IDEOGRAPH-2F981;Lo;0;L;43D5;;;;N;;;;; 2F982;CJK COMPATIBILITY IDEOGRAPH-2F982;Lo;0;L;80B2;;;;N;;;;; 2F983;CJK COMPATIBILITY IDEOGRAPH-2F983;Lo;0;L;8103;;;;N;;;;; 2F984;CJK COMPATIBILITY IDEOGRAPH-2F984;Lo;0;L;440B;;;;N;;;;; 2F985;CJK COMPATIBILITY IDEOGRAPH-2F985;Lo;0;L;813E;;;;N;;;;; 2F986;CJK COMPATIBILITY IDEOGRAPH-2F986;Lo;0;L;5AB5;;;;N;;;;; 2F987;CJK COMPATIBILITY IDEOGRAPH-2F987;Lo;0;L;267A7;;;;N;;;;; 2F988;CJK COMPATIBILITY IDEOGRAPH-2F988;Lo;0;L;267B5;;;;N;;;;; 2F989;CJK COMPATIBILITY IDEOGRAPH-2F989;Lo;0;L;23393;;;;N;;;;; 2F98A;CJK COMPATIBILITY IDEOGRAPH-2F98A;Lo;0;L;2339C;;;;N;;;;; 2F98B;CJK COMPATIBILITY IDEOGRAPH-2F98B;Lo;0;L;8201;;;;N;;;;; 2F98C;CJK COMPATIBILITY IDEOGRAPH-2F98C;Lo;0;L;8204;;;;N;;;;; 2F98D;CJK COMPATIBILITY IDEOGRAPH-2F98D;Lo;0;L;8F9E;;;;N;;;;; 2F98E;CJK COMPATIBILITY IDEOGRAPH-2F98E;Lo;0;L;446B;;;;N;;;;; 2F98F;CJK COMPATIBILITY IDEOGRAPH-2F98F;Lo;0;L;8291;;;;N;;;;; 2F990;CJK COMPATIBILITY IDEOGRAPH-2F990;Lo;0;L;828B;;;;N;;;;; 2F991;CJK COMPATIBILITY IDEOGRAPH-2F991;Lo;0;L;829D;;;;N;;;;; 2F992;CJK COMPATIBILITY IDEOGRAPH-2F992;Lo;0;L;52B3;;;;N;;;;; 2F993;CJK COMPATIBILITY IDEOGRAPH-2F993;Lo;0;L;82B1;;;;N;;;;; 2F994;CJK COMPATIBILITY IDEOGRAPH-2F994;Lo;0;L;82B3;;;;N;;;;; 2F995;CJK COMPATIBILITY IDEOGRAPH-2F995;Lo;0;L;82BD;;;;N;;;;; 2F996;CJK COMPATIBILITY IDEOGRAPH-2F996;Lo;0;L;82E6;;;;N;;;;; 2F997;CJK COMPATIBILITY IDEOGRAPH-2F997;Lo;0;L;26B3C;;;;N;;;;; 2F998;CJK COMPATIBILITY IDEOGRAPH-2F998;Lo;0;L;82E5;;;;N;;;;; 2F999;CJK COMPATIBILITY IDEOGRAPH-2F999;Lo;0;L;831D;;;;N;;;;; 2F99A;CJK COMPATIBILITY IDEOGRAPH-2F99A;Lo;0;L;8363;;;;N;;;;; 2F99B;CJK COMPATIBILITY IDEOGRAPH-2F99B;Lo;0;L;83AD;;;;N;;;;; 2F99C;CJK COMPATIBILITY IDEOGRAPH-2F99C;Lo;0;L;8323;;;;N;;;;; 2F99D;CJK COMPATIBILITY IDEOGRAPH-2F99D;Lo;0;L;83BD;;;;N;;;;; 2F99E;CJK COMPATIBILITY IDEOGRAPH-2F99E;Lo;0;L;83E7;;;;N;;;;; 2F99F;CJK COMPATIBILITY IDEOGRAPH-2F99F;Lo;0;L;8457;;;;N;;;;; 2F9A0;CJK COMPATIBILITY IDEOGRAPH-2F9A0;Lo;0;L;8353;;;;N;;;;; 2F9A1;CJK COMPATIBILITY IDEOGRAPH-2F9A1;Lo;0;L;83CA;;;;N;;;;; 2F9A2;CJK COMPATIBILITY IDEOGRAPH-2F9A2;Lo;0;L;83CC;;;;N;;;;; 2F9A3;CJK COMPATIBILITY IDEOGRAPH-2F9A3;Lo;0;L;83DC;;;;N;;;;; 2F9A4;CJK COMPATIBILITY IDEOGRAPH-2F9A4;Lo;0;L;26C36;;;;N;;;;; 2F9A5;CJK COMPATIBILITY IDEOGRAPH-2F9A5;Lo;0;L;26D6B;;;;N;;;;; 2F9A6;CJK COMPATIBILITY IDEOGRAPH-2F9A6;Lo;0;L;26CD5;;;;N;;;;; 2F9A7;CJK COMPATIBILITY IDEOGRAPH-2F9A7;Lo;0;L;452B;;;;N;;;;; 2F9A8;CJK COMPATIBILITY IDEOGRAPH-2F9A8;Lo;0;L;84F1;;;;N;;;;; 2F9A9;CJK COMPATIBILITY IDEOGRAPH-2F9A9;Lo;0;L;84F3;;;;N;;;;; 2F9AA;CJK COMPATIBILITY IDEOGRAPH-2F9AA;Lo;0;L;8516;;;;N;;;;; 2F9AB;CJK COMPATIBILITY IDEOGRAPH-2F9AB;Lo;0;L;273CA;;;;N;;;;; 2F9AC;CJK COMPATIBILITY IDEOGRAPH-2F9AC;Lo;0;L;8564;;;;N;;;;; 2F9AD;CJK COMPATIBILITY IDEOGRAPH-2F9AD;Lo;0;L;26F2C;;;;N;;;;; 2F9AE;CJK COMPATIBILITY IDEOGRAPH-2F9AE;Lo;0;L;455D;;;;N;;;;; 2F9AF;CJK COMPATIBILITY IDEOGRAPH-2F9AF;Lo;0;L;4561;;;;N;;;;; 2F9B0;CJK COMPATIBILITY IDEOGRAPH-2F9B0;Lo;0;L;26FB1;;;;N;;;;; 2F9B1;CJK COMPATIBILITY IDEOGRAPH-2F9B1;Lo;0;L;270D2;;;;N;;;;; 2F9B2;CJK COMPATIBILITY IDEOGRAPH-2F9B2;Lo;0;L;456B;;;;N;;;;; 2F9B3;CJK COMPATIBILITY IDEOGRAPH-2F9B3;Lo;0;L;8650;;;;N;;;;; 2F9B4;CJK COMPATIBILITY IDEOGRAPH-2F9B4;Lo;0;L;865C;;;;N;;;;; 2F9B5;CJK COMPATIBILITY IDEOGRAPH-2F9B5;Lo;0;L;8667;;;;N;;;;; 2F9B6;CJK COMPATIBILITY IDEOGRAPH-2F9B6;Lo;0;L;8669;;;;N;;;;; 2F9B7;CJK COMPATIBILITY IDEOGRAPH-2F9B7;Lo;0;L;86A9;;;;N;;;;; 2F9B8;CJK COMPATIBILITY IDEOGRAPH-2F9B8;Lo;0;L;8688;;;;N;;;;; 2F9B9;CJK COMPATIBILITY IDEOGRAPH-2F9B9;Lo;0;L;870E;;;;N;;;;; 2F9BA;CJK COMPATIBILITY IDEOGRAPH-2F9BA;Lo;0;L;86E2;;;;N;;;;; 2F9BB;CJK COMPATIBILITY IDEOGRAPH-2F9BB;Lo;0;L;8779;;;;N;;;;; 2F9BC;CJK COMPATIBILITY IDEOGRAPH-2F9BC;Lo;0;L;8728;;;;N;;;;; 2F9BD;CJK COMPATIBILITY IDEOGRAPH-2F9BD;Lo;0;L;876B;;;;N;;;;; 2F9BE;CJK COMPATIBILITY IDEOGRAPH-2F9BE;Lo;0;L;8786;;;;N;;;;; 2F9BF;CJK COMPATIBILITY IDEOGRAPH-2F9BF;Lo;0;L;4D57;;;;N;;;;; 2F9C0;CJK COMPATIBILITY IDEOGRAPH-2F9C0;Lo;0;L;87E1;;;;N;;;;; 2F9C1;CJK COMPATIBILITY IDEOGRAPH-2F9C1;Lo;0;L;8801;;;;N;;;;; 2F9C2;CJK COMPATIBILITY IDEOGRAPH-2F9C2;Lo;0;L;45F9;;;;N;;;;; 2F9C3;CJK COMPATIBILITY IDEOGRAPH-2F9C3;Lo;0;L;8860;;;;N;;;;; 2F9C4;CJK COMPATIBILITY IDEOGRAPH-2F9C4;Lo;0;L;8863;;;;N;;;;; 2F9C5;CJK COMPATIBILITY IDEOGRAPH-2F9C5;Lo;0;L;27667;;;;N;;;;; 2F9C6;CJK COMPATIBILITY IDEOGRAPH-2F9C6;Lo;0;L;88D7;;;;N;;;;; 2F9C7;CJK COMPATIBILITY IDEOGRAPH-2F9C7;Lo;0;L;88DE;;;;N;;;;; 2F9C8;CJK COMPATIBILITY IDEOGRAPH-2F9C8;Lo;0;L;4635;;;;N;;;;; 2F9C9;CJK COMPATIBILITY IDEOGRAPH-2F9C9;Lo;0;L;88FA;;;;N;;;;; 2F9CA;CJK COMPATIBILITY IDEOGRAPH-2F9CA;Lo;0;L;34BB;;;;N;;;;; 2F9CB;CJK COMPATIBILITY IDEOGRAPH-2F9CB;Lo;0;L;278AE;;;;N;;;;; 2F9CC;CJK COMPATIBILITY IDEOGRAPH-2F9CC;Lo;0;L;27966;;;;N;;;;; 2F9CD;CJK COMPATIBILITY IDEOGRAPH-2F9CD;Lo;0;L;46BE;;;;N;;;;; 2F9CE;CJK COMPATIBILITY IDEOGRAPH-2F9CE;Lo;0;L;46C7;;;;N;;;;; 2F9CF;CJK COMPATIBILITY IDEOGRAPH-2F9CF;Lo;0;L;8AA0;;;;N;;;;; 2F9D0;CJK COMPATIBILITY IDEOGRAPH-2F9D0;Lo;0;L;8AED;;;;N;;;;; 2F9D1;CJK COMPATIBILITY IDEOGRAPH-2F9D1;Lo;0;L;8B8A;;;;N;;;;; 2F9D2;CJK COMPATIBILITY IDEOGRAPH-2F9D2;Lo;0;L;8C55;;;;N;;;;; 2F9D3;CJK COMPATIBILITY IDEOGRAPH-2F9D3;Lo;0;L;27CA8;;;;N;;;;; 2F9D4;CJK COMPATIBILITY IDEOGRAPH-2F9D4;Lo;0;L;8CAB;;;;N;;;;; 2F9D5;CJK COMPATIBILITY IDEOGRAPH-2F9D5;Lo;0;L;8CC1;;;;N;;;;; 2F9D6;CJK COMPATIBILITY IDEOGRAPH-2F9D6;Lo;0;L;8D1B;;;;N;;;;; 2F9D7;CJK COMPATIBILITY IDEOGRAPH-2F9D7;Lo;0;L;8D77;;;;N;;;;; 2F9D8;CJK COMPATIBILITY IDEOGRAPH-2F9D8;Lo;0;L;27F2F;;;;N;;;;; 2F9D9;CJK COMPATIBILITY IDEOGRAPH-2F9D9;Lo;0;L;20804;;;;N;;;;; 2F9DA;CJK COMPATIBILITY IDEOGRAPH-2F9DA;Lo;0;L;8DCB;;;;N;;;;; 2F9DB;CJK COMPATIBILITY IDEOGRAPH-2F9DB;Lo;0;L;8DBC;;;;N;;;;; 2F9DC;CJK COMPATIBILITY IDEOGRAPH-2F9DC;Lo;0;L;8DF0;;;;N;;;;; 2F9DD;CJK COMPATIBILITY IDEOGRAPH-2F9DD;Lo;0;L;208DE;;;;N;;;;; 2F9DE;CJK COMPATIBILITY IDEOGRAPH-2F9DE;Lo;0;L;8ED4;;;;N;;;;; 2F9DF;CJK COMPATIBILITY IDEOGRAPH-2F9DF;Lo;0;L;8F38;;;;N;;;;; 2F9E0;CJK COMPATIBILITY IDEOGRAPH-2F9E0;Lo;0;L;285D2;;;;N;;;;; 2F9E1;CJK COMPATIBILITY IDEOGRAPH-2F9E1;Lo;0;L;285ED;;;;N;;;;; 2F9E2;CJK COMPATIBILITY IDEOGRAPH-2F9E2;Lo;0;L;9094;;;;N;;;;; 2F9E3;CJK COMPATIBILITY IDEOGRAPH-2F9E3;Lo;0;L;90F1;;;;N;;;;; 2F9E4;CJK COMPATIBILITY IDEOGRAPH-2F9E4;Lo;0;L;9111;;;;N;;;;; 2F9E5;CJK COMPATIBILITY IDEOGRAPH-2F9E5;Lo;0;L;2872E;;;;N;;;;; 2F9E6;CJK COMPATIBILITY IDEOGRAPH-2F9E6;Lo;0;L;911B;;;;N;;;;; 2F9E7;CJK COMPATIBILITY IDEOGRAPH-2F9E7;Lo;0;L;9238;;;;N;;;;; 2F9E8;CJK COMPATIBILITY IDEOGRAPH-2F9E8;Lo;0;L;92D7;;;;N;;;;; 2F9E9;CJK COMPATIBILITY IDEOGRAPH-2F9E9;Lo;0;L;92D8;;;;N;;;;; 2F9EA;CJK COMPATIBILITY IDEOGRAPH-2F9EA;Lo;0;L;927C;;;;N;;;;; 2F9EB;CJK COMPATIBILITY IDEOGRAPH-2F9EB;Lo;0;L;93F9;;;;N;;;;; 2F9EC;CJK COMPATIBILITY IDEOGRAPH-2F9EC;Lo;0;L;9415;;;;N;;;;; 2F9ED;CJK COMPATIBILITY IDEOGRAPH-2F9ED;Lo;0;L;28BFA;;;;N;;;;; 2F9EE;CJK COMPATIBILITY IDEOGRAPH-2F9EE;Lo;0;L;958B;;;;N;;;;; 2F9EF;CJK COMPATIBILITY IDEOGRAPH-2F9EF;Lo;0;L;4995;;;;N;;;;; 2F9F0;CJK COMPATIBILITY IDEOGRAPH-2F9F0;Lo;0;L;95B7;;;;N;;;;; 2F9F1;CJK COMPATIBILITY IDEOGRAPH-2F9F1;Lo;0;L;28D77;;;;N;;;;; 2F9F2;CJK COMPATIBILITY IDEOGRAPH-2F9F2;Lo;0;L;49E6;;;;N;;;;; 2F9F3;CJK COMPATIBILITY IDEOGRAPH-2F9F3;Lo;0;L;96C3;;;;N;;;;; 2F9F4;CJK COMPATIBILITY IDEOGRAPH-2F9F4;Lo;0;L;5DB2;;;;N;;;;; 2F9F5;CJK COMPATIBILITY IDEOGRAPH-2F9F5;Lo;0;L;9723;;;;N;;;;; 2F9F6;CJK COMPATIBILITY IDEOGRAPH-2F9F6;Lo;0;L;29145;;;;N;;;;; 2F9F7;CJK COMPATIBILITY IDEOGRAPH-2F9F7;Lo;0;L;2921A;;;;N;;;;; 2F9F8;CJK COMPATIBILITY IDEOGRAPH-2F9F8;Lo;0;L;4A6E;;;;N;;;;; 2F9F9;CJK COMPATIBILITY IDEOGRAPH-2F9F9;Lo;0;L;4A76;;;;N;;;;; 2F9FA;CJK COMPATIBILITY IDEOGRAPH-2F9FA;Lo;0;L;97E0;;;;N;;;;; 2F9FB;CJK COMPATIBILITY IDEOGRAPH-2F9FB;Lo;0;L;2940A;;;;N;;;;; 2F9FC;CJK COMPATIBILITY IDEOGRAPH-2F9FC;Lo;0;L;4AB2;;;;N;;;;; 2F9FD;CJK COMPATIBILITY IDEOGRAPH-2F9FD;Lo;0;L;29496;;;;N;;;;; 2F9FE;CJK COMPATIBILITY IDEOGRAPH-2F9FE;Lo;0;L;980B;;;;N;;;;; 2F9FF;CJK COMPATIBILITY IDEOGRAPH-2F9FF;Lo;0;L;980B;;;;N;;;;; 2FA00;CJK COMPATIBILITY IDEOGRAPH-2FA00;Lo;0;L;9829;;;;N;;;;; 2FA01;CJK COMPATIBILITY IDEOGRAPH-2FA01;Lo;0;L;295B6;;;;N;;;;; 2FA02;CJK COMPATIBILITY IDEOGRAPH-2FA02;Lo;0;L;98E2;;;;N;;;;; 2FA03;CJK COMPATIBILITY IDEOGRAPH-2FA03;Lo;0;L;4B33;;;;N;;;;; 2FA04;CJK COMPATIBILITY IDEOGRAPH-2FA04;Lo;0;L;9929;;;;N;;;;; 2FA05;CJK COMPATIBILITY IDEOGRAPH-2FA05;Lo;0;L;99A7;;;;N;;;;; 2FA06;CJK COMPATIBILITY IDEOGRAPH-2FA06;Lo;0;L;99C2;;;;N;;;;; 2FA07;CJK COMPATIBILITY IDEOGRAPH-2FA07;Lo;0;L;99FE;;;;N;;;;; 2FA08;CJK COMPATIBILITY IDEOGRAPH-2FA08;Lo;0;L;4BCE;;;;N;;;;; 2FA09;CJK COMPATIBILITY IDEOGRAPH-2FA09;Lo;0;L;29B30;;;;N;;;;; 2FA0A;CJK COMPATIBILITY IDEOGRAPH-2FA0A;Lo;0;L;9B12;;;;N;;;;; 2FA0B;CJK COMPATIBILITY IDEOGRAPH-2FA0B;Lo;0;L;9C40;;;;N;;;;; 2FA0C;CJK COMPATIBILITY IDEOGRAPH-2FA0C;Lo;0;L;9CFD;;;;N;;;;; 2FA0D;CJK COMPATIBILITY IDEOGRAPH-2FA0D;Lo;0;L;4CCE;;;;N;;;;; 2FA0E;CJK COMPATIBILITY IDEOGRAPH-2FA0E;Lo;0;L;4CED;;;;N;;;;; 2FA0F;CJK COMPATIBILITY IDEOGRAPH-2FA0F;Lo;0;L;9D67;;;;N;;;;; 2FA10;CJK COMPATIBILITY IDEOGRAPH-2FA10;Lo;0;L;2A0CE;;;;N;;;;; 2FA11;CJK COMPATIBILITY IDEOGRAPH-2FA11;Lo;0;L;4CF8;;;;N;;;;; 2FA12;CJK COMPATIBILITY IDEOGRAPH-2FA12;Lo;0;L;2A105;;;;N;;;;; 2FA13;CJK COMPATIBILITY IDEOGRAPH-2FA13;Lo;0;L;2A20E;;;;N;;;;; 2FA14;CJK COMPATIBILITY IDEOGRAPH-2FA14;Lo;0;L;2A291;;;;N;;;;; 2FA15;CJK COMPATIBILITY IDEOGRAPH-2FA15;Lo;0;L;9EBB;;;;N;;;;; 2FA16;CJK COMPATIBILITY IDEOGRAPH-2FA16;Lo;0;L;4D56;;;;N;;;;; 2FA17;CJK COMPATIBILITY IDEOGRAPH-2FA17;Lo;0;L;9EF9;;;;N;;;;; 2FA18;CJK COMPATIBILITY IDEOGRAPH-2FA18;Lo;0;L;9EFE;;;;N;;;;; 2FA19;CJK COMPATIBILITY IDEOGRAPH-2FA19;Lo;0;L;9F05;;;;N;;;;; 2FA1A;CJK COMPATIBILITY IDEOGRAPH-2FA1A;Lo;0;L;9F0F;;;;N;;;;; 2FA1B;CJK COMPATIBILITY IDEOGRAPH-2FA1B;Lo;0;L;9F16;;;;N;;;;; 2FA1C;CJK COMPATIBILITY IDEOGRAPH-2FA1C;Lo;0;L;9F3B;;;;N;;;;; 2FA1D;CJK COMPATIBILITY IDEOGRAPH-2FA1D;Lo;0;L;2A600;;;;N;;;;; E0001;LANGUAGE TAG;Cf;0;BN;;;;;N;;;;; E0020;TAG SPACE;Cf;0;BN;;;;;N;;;;; E0021;TAG EXCLAMATION MARK;Cf;0;BN;;;;;N;;;;; E0022;TAG QUOTATION MARK;Cf;0;BN;;;;;N;;;;; E0023;TAG NUMBER SIGN;Cf;0;BN;;;;;N;;;;; E0024;TAG DOLLAR SIGN;Cf;0;BN;;;;;N;;;;; E0025;TAG PERCENT SIGN;Cf;0;BN;;;;;N;;;;; E0026;TAG AMPERSAND;Cf;0;BN;;;;;N;;;;; E0027;TAG APOSTROPHE;Cf;0;BN;;;;;N;;;;; E0028;TAG LEFT PARENTHESIS;Cf;0;BN;;;;;N;;;;; E0029;TAG RIGHT PARENTHESIS;Cf;0;BN;;;;;N;;;;; E002A;TAG ASTERISK;Cf;0;BN;;;;;N;;;;; E002B;TAG PLUS SIGN;Cf;0;BN;;;;;N;;;;; E002C;TAG COMMA;Cf;0;BN;;;;;N;;;;; E002D;TAG HYPHEN-MINUS;Cf;0;BN;;;;;N;;;;; E002E;TAG FULL STOP;Cf;0;BN;;;;;N;;;;; E002F;TAG SOLIDUS;Cf;0;BN;;;;;N;;;;; E0030;TAG DIGIT ZERO;Cf;0;BN;;;;;N;;;;; E0031;TAG DIGIT ONE;Cf;0;BN;;;;;N;;;;; E0032;TAG DIGIT TWO;Cf;0;BN;;;;;N;;;;; E0033;TAG DIGIT THREE;Cf;0;BN;;;;;N;;;;; E0034;TAG DIGIT FOUR;Cf;0;BN;;;;;N;;;;; E0035;TAG DIGIT FIVE;Cf;0;BN;;;;;N;;;;; E0036;TAG DIGIT SIX;Cf;0;BN;;;;;N;;;;; E0037;TAG DIGIT SEVEN;Cf;0;BN;;;;;N;;;;; E0038;TAG DIGIT EIGHT;Cf;0;BN;;;;;N;;;;; E0039;TAG DIGIT NINE;Cf;0;BN;;;;;N;;;;; E003A;TAG COLON;Cf;0;BN;;;;;N;;;;; E003B;TAG SEMICOLON;Cf;0;BN;;;;;N;;;;; E003C;TAG LESS-THAN SIGN;Cf;0;BN;;;;;N;;;;; E003D;TAG EQUALS SIGN;Cf;0;BN;;;;;N;;;;; E003E;TAG GREATER-THAN SIGN;Cf;0;BN;;;;;N;;;;; E003F;TAG QUESTION MARK;Cf;0;BN;;;;;N;;;;; E0040;TAG COMMERCIAL AT;Cf;0;BN;;;;;N;;;;; E0041;TAG LATIN CAPITAL LETTER A;Cf;0;BN;;;;;N;;;;; E0042;TAG LATIN CAPITAL LETTER B;Cf;0;BN;;;;;N;;;;; E0043;TAG LATIN CAPITAL LETTER C;Cf;0;BN;;;;;N;;;;; E0044;TAG LATIN CAPITAL LETTER D;Cf;0;BN;;;;;N;;;;; E0045;TAG LATIN CAPITAL LETTER E;Cf;0;BN;;;;;N;;;;; E0046;TAG LATIN CAPITAL LETTER F;Cf;0;BN;;;;;N;;;;; E0047;TAG LATIN CAPITAL LETTER G;Cf;0;BN;;;;;N;;;;; E0048;TAG LATIN CAPITAL LETTER H;Cf;0;BN;;;;;N;;;;; E0049;TAG LATIN CAPITAL LETTER I;Cf;0;BN;;;;;N;;;;; E004A;TAG LATIN CAPITAL LETTER J;Cf;0;BN;;;;;N;;;;; E004B;TAG LATIN CAPITAL LETTER K;Cf;0;BN;;;;;N;;;;; E004C;TAG LATIN CAPITAL LETTER L;Cf;0;BN;;;;;N;;;;; E004D;TAG LATIN CAPITAL LETTER M;Cf;0;BN;;;;;N;;;;; E004E;TAG LATIN CAPITAL LETTER N;Cf;0;BN;;;;;N;;;;; E004F;TAG LATIN CAPITAL LETTER O;Cf;0;BN;;;;;N;;;;; E0050;TAG LATIN CAPITAL LETTER P;Cf;0;BN;;;;;N;;;;; E0051;TAG LATIN CAPITAL LETTER Q;Cf;0;BN;;;;;N;;;;; E0052;TAG LATIN CAPITAL LETTER R;Cf;0;BN;;;;;N;;;;; E0053;TAG LATIN CAPITAL LETTER S;Cf;0;BN;;;;;N;;;;; E0054;TAG LATIN CAPITAL LETTER T;Cf;0;BN;;;;;N;;;;; E0055;TAG LATIN CAPITAL LETTER U;Cf;0;BN;;;;;N;;;;; E0056;TAG LATIN CAPITAL LETTER V;Cf;0;BN;;;;;N;;;;; E0057;TAG LATIN CAPITAL LETTER W;Cf;0;BN;;;;;N;;;;; E0058;TAG LATIN CAPITAL LETTER X;Cf;0;BN;;;;;N;;;;; E0059;TAG LATIN CAPITAL LETTER Y;Cf;0;BN;;;;;N;;;;; E005A;TAG LATIN CAPITAL LETTER Z;Cf;0;BN;;;;;N;;;;; E005B;TAG LEFT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;; E005C;TAG REVERSE SOLIDUS;Cf;0;BN;;;;;N;;;;; E005D;TAG RIGHT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;; E005E;TAG CIRCUMFLEX ACCENT;Cf;0;BN;;;;;N;;;;; E005F;TAG LOW LINE;Cf;0;BN;;;;;N;;;;; E0060;TAG GRAVE ACCENT;Cf;0;BN;;;;;N;;;;; E0061;TAG LATIN SMALL LETTER A;Cf;0;BN;;;;;N;;;;; E0062;TAG LATIN SMALL LETTER B;Cf;0;BN;;;;;N;;;;; E0063;TAG LATIN SMALL LETTER C;Cf;0;BN;;;;;N;;;;; E0064;TAG LATIN SMALL LETTER D;Cf;0;BN;;;;;N;;;;; E0065;TAG LATIN SMALL LETTER E;Cf;0;BN;;;;;N;;;;; E0066;TAG LATIN SMALL LETTER F;Cf;0;BN;;;;;N;;;;; E0067;TAG LATIN SMALL LETTER G;Cf;0;BN;;;;;N;;;;; E0068;TAG LATIN SMALL LETTER H;Cf;0;BN;;;;;N;;;;; E0069;TAG LATIN SMALL LETTER I;Cf;0;BN;;;;;N;;;;; E006A;TAG LATIN SMALL LETTER J;Cf;0;BN;;;;;N;;;;; E006B;TAG LATIN SMALL LETTER K;Cf;0;BN;;;;;N;;;;; E006C;TAG LATIN SMALL LETTER L;Cf;0;BN;;;;;N;;;;; E006D;TAG LATIN SMALL LETTER M;Cf;0;BN;;;;;N;;;;; E006E;TAG LATIN SMALL LETTER N;Cf;0;BN;;;;;N;;;;; E006F;TAG LATIN SMALL LETTER O;Cf;0;BN;;;;;N;;;;; E0070;TAG LATIN SMALL LETTER P;Cf;0;BN;;;;;N;;;;; E0071;TAG LATIN SMALL LETTER Q;Cf;0;BN;;;;;N;;;;; E0072;TAG LATIN SMALL LETTER R;Cf;0;BN;;;;;N;;;;; E0073;TAG LATIN SMALL LETTER S;Cf;0;BN;;;;;N;;;;; E0074;TAG LATIN SMALL LETTER T;Cf;0;BN;;;;;N;;;;; E0075;TAG LATIN SMALL LETTER U;Cf;0;BN;;;;;N;;;;; E0076;TAG LATIN SMALL LETTER V;Cf;0;BN;;;;;N;;;;; E0077;TAG LATIN SMALL LETTER W;Cf;0;BN;;;;;N;;;;; E0078;TAG LATIN SMALL LETTER X;Cf;0;BN;;;;;N;;;;; E0079;TAG LATIN SMALL LETTER Y;Cf;0;BN;;;;;N;;;;; E007A;TAG LATIN SMALL LETTER Z;Cf;0;BN;;;;;N;;;;; E007B;TAG LEFT CURLY BRACKET;Cf;0;BN;;;;;N;;;;; E007C;TAG VERTICAL LINE;Cf;0;BN;;;;;N;;;;; E007D;TAG RIGHT CURLY BRACKET;Cf;0;BN;;;;;N;;;;; E007E;TAG TILDE;Cf;0;BN;;;;;N;;;;; E007F;CANCEL TAG;Cf;0;BN;;;;;N;;;;; F0000;;Co;0;L;;;;;N;;;;; FFFFD;;Co;0;L;;;;;N;;;;; 100000;;Co;0;L;;;;;N;;;;; 10FFFD;;Co;0;L;;;;;N;;;;; openldap-2.5.11+dfsg/libraries/liblunicode/Makefile.in0000644000175000017500000000262314172327167021354 0ustar ryanryan# Makefile.in for LDAP -llunicode # $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . LIBRARY = liblunicode.a XXDIR = $(srcdir)/ucdata/ XXHEADERS = ucdata.h ure.h uctable.h XXSRCS = ucdata.c ucgendat.c ure.c urestubs.c SRCS = ucstr.c OBJS = ucdata.o ure.o urestubs.o ucstr.o XLIB = $(LIBRARY) XLIBS = $(LDAP_LIBLUTIL_A) $(LDAP_LIBLBER_LA) #PROGRAMS = ucgendat LDAP_INCDIR= ../../include LDAP_LIBDIR= ../../libraries uctable.h: $(XXDIR)/uctable.h $(XXDIR)/uctable.h: $(XXDIR)/ucgendat.c $(srcdir)/UnicodeData.txt $(srcdir)/CompositionExclusions.txt $(MAKE) ucgendat ./ucgendat $(srcdir)/UnicodeData.txt -x $(srcdir)/CompositionExclusions.txt ucgendat: $(XLIBS) ucgendat.o $(LTLINK) -o $@ ucgendat.o $(LIBS) .links : @for i in $(XXSRCS) $(XXHEADERS); do \ $(RM) $$i ; \ ii=`find $(srcdir) -name $$i` ; \ $(LN_S) $$ii . ; \ done touch .links $(XXSRCS) $(XXHEADERS) : .links clean-local: FORCE @$(RM) *.dat .links $(XXHEADERS) ucgendat depend-common: .links openldap-2.5.11+dfsg/libraries/liblunicode/ure/0000755000175000017500000000000014172327167020077 5ustar ryanryanopenldap-2.5.11+dfsg/libraries/liblunicode/ure/ure.c0000644000175000017500000017044114172327167021045 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Copyright 1997, 1998, 1999 Computing Research Labs, * New Mexico State University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* $Id: ure.c,v 1.2 1999/09/21 15:47:43 mleisher Exp $" */ #include "portable.h" #include #include #include #include "ure.h" /* * Flags used internally in the DFA. */ #define _URE_DFA_CASEFOLD 0x01 #define _URE_DFA_BLANKLINE 0x02 static unsigned long cclass_flags[] = { 0, _URE_NONSPACING, _URE_COMBINING, _URE_NUMDIGIT, _URE_NUMOTHER, _URE_SPACESEP, _URE_LINESEP, _URE_PARASEP, _URE_CNTRL, _URE_PUA, _URE_UPPER, _URE_LOWER, _URE_TITLE, _URE_MODIFIER, _URE_OTHERLETTER, _URE_DASHPUNCT, _URE_OPENPUNCT, _URE_CLOSEPUNCT, _URE_OTHERPUNCT, _URE_MATHSYM, _URE_CURRENCYSYM, _URE_OTHERSYM, _URE_LTR, _URE_RTL, _URE_EURONUM, _URE_EURONUMSEP, _URE_EURONUMTERM, _URE_ARABNUM, _URE_COMMONSEP, _URE_BLOCKSEP, _URE_SEGMENTSEP, _URE_WHITESPACE, _URE_OTHERNEUT, }; /* * Symbol types for the DFA. */ #define _URE_ANY_CHAR 1 #define _URE_CHAR 2 #define _URE_CCLASS 3 #define _URE_NCCLASS 4 #define _URE_BOL_ANCHOR 5 #define _URE_EOL_ANCHOR 6 /* * Op codes for converting the NFA to a DFA. */ #define _URE_SYMBOL 10 #define _URE_PAREN 11 #define _URE_QUEST 12 #define _URE_STAR 13 #define _URE_PLUS 14 #define _URE_ONE 15 #define _URE_AND 16 #define _URE_OR 17 #define _URE_NOOP 0xffff #define _URE_REGSTART 0x8000 #define _URE_REGEND 0x4000 /* * Structure used to handle a compacted range of characters. */ typedef struct { ucs4_t min_code; ucs4_t max_code; } _ure_range_t; typedef struct { _ure_range_t *ranges; ucs2_t ranges_used; ucs2_t ranges_size; } _ure_ccl_t; typedef union { ucs4_t chr; _ure_ccl_t ccl; } _ure_sym_t; /* * This is a general element structure used for expressions and stack * elements. */ typedef struct { ucs2_t reg; ucs2_t onstack; ucs2_t type; ucs2_t lhs; ucs2_t rhs; } _ure_elt_t; /* * This is a structure used to track a list or a stack of states. */ typedef struct { ucs2_t *slist; ucs2_t slist_size; ucs2_t slist_used; } _ure_stlist_t; /* * Structure to track the list of unique states for a symbol * during reduction. */ typedef struct { ucs2_t id; ucs2_t type; unsigned long mods; unsigned long props; _ure_sym_t sym; _ure_stlist_t states; } _ure_symtab_t; /* * Structure to hold a single state. */ typedef struct { ucs2_t id; ucs2_t accepting; ucs2_t pad; _ure_stlist_t st; _ure_elt_t *trans; ucs2_t trans_size; ucs2_t trans_used; } _ure_state_t; /* * Structure used for keeping lists of states. */ typedef struct { _ure_state_t *states; ucs2_t states_size; ucs2_t states_used; } _ure_statetable_t; /* * Structure to track pairs of DFA states when equivalent states are * merged. */ typedef struct { ucs2_t l; ucs2_t r; } _ure_equiv_t; /* * Structure used for constructing the NFA and reducing to a minimal DFA. */ typedef struct _ure_buffer_t { int reducing; int error; unsigned long flags; _ure_stlist_t stack; /* * Table of unique symbols encountered. */ _ure_symtab_t *symtab; ucs2_t symtab_size; ucs2_t symtab_used; /* * Tracks the unique expressions generated for the NFA and when the NFA is * reduced. */ _ure_elt_t *expr; ucs2_t expr_used; ucs2_t expr_size; /* * The reduced table of unique groups of NFA states. */ _ure_statetable_t states; /* * Tracks states when equivalent states are merged. */ _ure_equiv_t *equiv; ucs2_t equiv_used; ucs2_t equiv_size; } _ure_buffer_t; typedef struct { ucs2_t symbol; ucs2_t next_state; } _ure_trans_t; typedef struct { ucs2_t accepting; ucs2_t ntrans; _ure_trans_t *trans; } _ure_dstate_t; typedef struct _ure_dfa_t { unsigned long flags; _ure_symtab_t *syms; ucs2_t nsyms; _ure_dstate_t *states; ucs2_t nstates; _ure_trans_t *trans; ucs2_t ntrans; } _ure_dfa_t; /************************************************************************* * * Functions. * *************************************************************************/ static void _ure_memmove(char *dest, char *src, unsigned long bytes) { long i, j; i = (long) bytes; j = i & 7; i = (i + 7) >> 3; /* * Do a memmove using Ye Olde Duff's Device for efficiency. */ if (src < dest) { src += bytes; dest += bytes; switch (j) { case 0: do { *--dest = *--src; case 7: *--dest = *--src; case 6: *--dest = *--src; case 5: *--dest = *--src; case 4: *--dest = *--src; case 3: *--dest = *--src; case 2: *--dest = *--src; case 1: *--dest = *--src; } while (--i > 0); } } else if (src > dest) { switch (j) { case 0: do { *dest++ = *src++; case 7: *dest++ = *src++; case 6: *dest++ = *src++; case 5: *dest++ = *src++; case 4: *dest++ = *src++; case 3: *dest++ = *src++; case 2: *dest++ = *src++; case 1: *dest++ = *src++; } while (--i > 0); } } } static void _ure_push(ucs2_t v, _ure_buffer_t *b) { _ure_stlist_t *s; if (b == 0) return; /* * If the `reducing' parameter is non-zero, check to see if the value * passed is already on the stack. */ if (b->reducing != 0 && b->expr[v].onstack != 0) return; s = &b->stack; if (s->slist_used == s->slist_size) { if (s->slist_size == 0) s->slist = (ucs2_t *) malloc(sizeof(ucs2_t) << 3); else s->slist = (ucs2_t *) realloc((char *) s->slist, sizeof(ucs2_t) * (s->slist_size + 8)); s->slist_size += 8; } s->slist[s->slist_used++] = v; /* * If the `reducing' parameter is non-zero, flag the element as being on * the stack. */ if (b->reducing != 0) b->expr[v].onstack = 1; } static ucs2_t _ure_peek(_ure_buffer_t *b) { if (b == 0 || b->stack.slist_used == 0) return _URE_NOOP; return b->stack.slist[b->stack.slist_used - 1]; } static ucs2_t _ure_pop(_ure_buffer_t *b) { ucs2_t v; if (b == 0 || b->stack.slist_used == 0) return _URE_NOOP; v = b->stack.slist[--b->stack.slist_used]; if (b->reducing) b->expr[v].onstack = 0; return v; } /************************************************************************* * * Start symbol parse functions. * *************************************************************************/ /* * Parse a comma-separated list of integers that represent character * properties. Combine them into a mask that is returned in the `mask' * variable, and return the number of characters consumed. */ static unsigned long _ure_prop_list(ucs2_t *pp, unsigned long limit, unsigned long *mask, _ure_buffer_t *b) { unsigned long n, m; ucs2_t *sp, *ep; sp = pp; ep = sp + limit; for (m = n = 0; b->error == _URE_OK && sp < ep; sp++) { if (*sp == ',') { /* * Encountered a comma, so select the next character property flag * and reset the number. */ m |= cclass_flags[n]; n = 0; } else if (*sp >= '0' && *sp <= '9') /* * Encountered a digit, so start or continue building the cardinal * that represents the character property flag. */ n = (n * 10) + (*sp - '0'); else /* * Encountered something that is not part of the property list. * Indicate that we are done. */ break; /* * If a property number greater than 32 occurs, then there is a * problem. Most likely a missing comma separator. */ if (n > 32) b->error = _URE_INVALID_PROPERTY; } if (b->error == _URE_OK && n != 0) m |= cclass_flags[n]; /* * Set the mask that represents the group of character properties. */ *mask = m; /* * Return the number of characters consumed. */ return sp - pp; } /* * Collect a hex number with 1 to 4 digits and return the number * of characters used. */ static unsigned long _ure_hex(ucs2_t *np, unsigned long limit, ucs4_t *n) { ucs2_t i; ucs2_t *sp, *ep; ucs4_t nn; sp = np; ep = sp + limit; for (nn = 0, i = 0; i < 4 && sp < ep; i++, sp++) { if (*sp >= '0' && *sp <= '9') nn = (nn << 4) + (*sp - '0'); else if (*sp >= 'A' && *sp <= 'F') nn = (nn << 4) + ((*sp - 'A') + 10); else if (*sp >= 'a' && *sp <= 'f') nn = (nn << 4) + ((*sp - 'a') + 10); else /* * Encountered something that is not a hex digit. */ break; } /* * Assign the character code collected and return the number of * characters used. */ *n = nn; return sp - np; } /* * Insert a range into a character class, removing duplicates and ordering * them in increasing range-start order. */ static void _ure_add_range(_ure_ccl_t *ccl, _ure_range_t *r, _ure_buffer_t *b) { ucs2_t i; ucs4_t tmp; _ure_range_t *rp; /* * If the `casefold' flag is set, then make sure both endpoints of the * range are converted to lower case. */ if (b->flags & _URE_DFA_CASEFOLD) { r->min_code = _ure_tolower(r->min_code); r->max_code = _ure_tolower(r->max_code); } /* * Swap the range endpoints if they are not in increasing order. */ if (r->min_code > r->max_code) { tmp = r->min_code; r->min_code = r->max_code; r->max_code = tmp; } for (i = 0, rp = ccl->ranges; i < ccl->ranges_used && r->min_code < rp->min_code; i++, rp++) ; /* * Check for a duplicate. */ if (i < ccl->ranges_used && r->min_code == rp->min_code && r->max_code == rp->max_code) return; if (ccl->ranges_used == ccl->ranges_size) { if (ccl->ranges_size == 0) ccl->ranges = (_ure_range_t *) malloc(sizeof(_ure_range_t) << 3); else ccl->ranges = (_ure_range_t *) realloc((char *) ccl->ranges, sizeof(_ure_range_t) * (ccl->ranges_size + 8)); ccl->ranges_size += 8; } rp = ccl->ranges + ccl->ranges_used; if (i < ccl->ranges_used) _ure_memmove((char *) (rp + 1), (char *) rp, sizeof(_ure_range_t) * (ccl->ranges_used - i)); ccl->ranges_used++; rp->min_code = r->min_code; rp->max_code = r->max_code; } #define _URE_ALPHA_MASK (_URE_UPPER|_URE_LOWER|_URE_OTHERLETTER|\ _URE_MODIFIER|_URE_TITLE|_URE_NONSPACING|_URE_COMBINING) #define _URE_ALNUM_MASK (_URE_ALPHA_MASK|_URE_NUMDIGIT) #define _URE_PUNCT_MASK (_URE_DASHPUNCT|_URE_OPENPUNCT|_URE_CLOSEPUNCT|\ _URE_OTHERPUNCT) #define _URE_GRAPH_MASK (_URE_NUMDIGIT|_URE_NUMOTHER|_URE_ALPHA_MASK|\ _URE_MATHSYM|_URE_CURRENCYSYM|_URE_OTHERSYM) #define _URE_PRINT_MASK (_URE_GRAPH_MASK|_URE_SPACESEP) #define _URE_SPACE_MASK (_URE_SPACESEP|_URE_LINESEP|_URE_PARASEP) typedef void (*_ure_cclsetup_t)( _ure_symtab_t *sym, unsigned long mask, _ure_buffer_t *b ); typedef struct { ucs2_t key; unsigned long len; unsigned long next; _ure_cclsetup_t func; unsigned long mask; } _ure_trie_t; static void _ure_ccl_setup(_ure_symtab_t *sym, unsigned long mask, _ure_buffer_t *b) { sym->props |= mask; } static void _ure_space_setup(_ure_symtab_t *sym, unsigned long mask, _ure_buffer_t *b) { _ure_range_t range; sym->props |= mask; /* * Add the additional characters needed for handling isspace(). */ range.min_code = range.max_code = '\t'; _ure_add_range(&sym->sym.ccl, &range, b); range.min_code = range.max_code = '\r'; _ure_add_range(&sym->sym.ccl, &range, b); range.min_code = range.max_code = '\n'; _ure_add_range(&sym->sym.ccl, &range, b); range.min_code = range.max_code = '\f'; _ure_add_range(&sym->sym.ccl, &range, b); range.min_code = range.max_code = 0xfeff; _ure_add_range(&sym->sym.ccl, &range, b); } static void _ure_xdigit_setup(_ure_symtab_t *sym, unsigned long mask, _ure_buffer_t *b) { _ure_range_t range; /* * Add the additional characters needed for handling isxdigit(). */ range.min_code = '0'; range.max_code = '9'; _ure_add_range(&sym->sym.ccl, &range, b); range.min_code = 'A'; range.max_code = 'F'; _ure_add_range(&sym->sym.ccl, &range, b); range.min_code = 'a'; range.max_code = 'f'; _ure_add_range(&sym->sym.ccl, &range, b); } static _ure_trie_t cclass_trie[] = { {0x003a, 1, 1, 0, 0}, {0x0061, 9, 10, 0, 0}, {0x0063, 8, 19, 0, 0}, {0x0064, 7, 24, 0, 0}, {0x0067, 6, 29, 0, 0}, {0x006c, 5, 34, 0, 0}, {0x0070, 4, 39, 0, 0}, {0x0073, 3, 49, 0, 0}, {0x0075, 2, 54, 0, 0}, {0x0078, 1, 59, 0, 0}, {0x006c, 1, 11, 0, 0}, {0x006e, 2, 13, 0, 0}, {0x0070, 1, 16, 0, 0}, {0x0075, 1, 14, 0, 0}, {0x006d, 1, 15, 0, 0}, {0x003a, 1, 16, _ure_ccl_setup, _URE_ALNUM_MASK}, {0x0068, 1, 17, 0, 0}, {0x0061, 1, 18, 0, 0}, {0x003a, 1, 19, _ure_ccl_setup, _URE_ALPHA_MASK}, {0x006e, 1, 20, 0, 0}, {0x0074, 1, 21, 0, 0}, {0x0072, 1, 22, 0, 0}, {0x006c, 1, 23, 0, 0}, {0x003a, 1, 24, _ure_ccl_setup, _URE_CNTRL}, {0x0069, 1, 25, 0, 0}, {0x0067, 1, 26, 0, 0}, {0x0069, 1, 27, 0, 0}, {0x0074, 1, 28, 0, 0}, {0x003a, 1, 29, _ure_ccl_setup, _URE_NUMDIGIT}, {0x0072, 1, 30, 0, 0}, {0x0061, 1, 31, 0, 0}, {0x0070, 1, 32, 0, 0}, {0x0068, 1, 33, 0, 0}, {0x003a, 1, 34, _ure_ccl_setup, _URE_GRAPH_MASK}, {0x006f, 1, 35, 0, 0}, {0x0077, 1, 36, 0, 0}, {0x0065, 1, 37, 0, 0}, {0x0072, 1, 38, 0, 0}, {0x003a, 1, 39, _ure_ccl_setup, _URE_LOWER}, {0x0072, 2, 41, 0, 0}, {0x0075, 1, 45, 0, 0}, {0x0069, 1, 42, 0, 0}, {0x006e, 1, 43, 0, 0}, {0x0074, 1, 44, 0, 0}, {0x003a, 1, 45, _ure_ccl_setup, _URE_PRINT_MASK}, {0x006e, 1, 46, 0, 0}, {0x0063, 1, 47, 0, 0}, {0x0074, 1, 48, 0, 0}, {0x003a, 1, 49, _ure_ccl_setup, _URE_PUNCT_MASK}, {0x0070, 1, 50, 0, 0}, {0x0061, 1, 51, 0, 0}, {0x0063, 1, 52, 0, 0}, {0x0065, 1, 53, 0, 0}, {0x003a, 1, 54, _ure_space_setup, _URE_SPACE_MASK}, {0x0070, 1, 55, 0, 0}, {0x0070, 1, 56, 0, 0}, {0x0065, 1, 57, 0, 0}, {0x0072, 1, 58, 0, 0}, {0x003a, 1, 59, _ure_ccl_setup, _URE_UPPER}, {0x0064, 1, 60, 0, 0}, {0x0069, 1, 61, 0, 0}, {0x0067, 1, 62, 0, 0}, {0x0069, 1, 63, 0, 0}, {0x0074, 1, 64, 0, 0}, {0x003a, 1, 65, _ure_xdigit_setup, 0}, }; /* * Probe for one of the POSIX colon delimited character classes in the static * trie. */ static unsigned long _ure_posix_ccl(ucs2_t *cp, unsigned long limit, _ure_symtab_t *sym, _ure_buffer_t *b) { int i; unsigned long n; _ure_trie_t *tp; ucs2_t *sp, *ep; /* * If the number of characters left is less than 7, then this cannot be * interpreted as one of the colon delimited classes. */ if (limit < 7) return 0; sp = cp; ep = sp + limit; tp = cclass_trie; for (i = 0; sp < ep && i < 8; i++, sp++) { n = tp->len; for (; n > 0 && tp->key != *sp; tp++, n--) ; if (n == 0) return 0; if (*sp == ':' && (i == 6 || i == 7)) { sp++; break; } if (sp + 1 < ep) tp = cclass_trie + tp->next; } if (tp->func == 0) return 0; (*tp->func)(sym, tp->mask, b); return sp - cp; } /* * Construct a list of ranges and return the number of characters consumed. */ static unsigned long _ure_cclass(ucs2_t *cp, unsigned long limit, _ure_symtab_t *symp, _ure_buffer_t *b) { int range_end; unsigned long n; ucs2_t *sp, *ep; ucs4_t c, last; _ure_ccl_t *cclp; _ure_range_t range; sp = cp; ep = sp + limit; if (*sp == '^') { symp->type = _URE_NCCLASS; sp++; } else symp->type = _URE_CCLASS; for (last = 0, range_end = 0; b->error == _URE_OK && sp < ep && *sp != ']'; ) { c = *sp++; if (c == '\\') { if (sp == ep) { /* * The EOS was encountered when expecting the reverse solidus * to be followed by the character it is escaping. Set an * error code and return the number of characters consumed up * to this point. */ b->error = _URE_UNEXPECTED_EOS; return sp - cp; } c = *sp++; switch (c) { case 'a': c = 0x07; break; case 'b': c = 0x08; break; case 'f': c = 0x0c; break; case 'n': c = 0x0a; break; case 'r': c = 0x0d; break; case 't': c = 0x09; break; case 'v': c = 0x0b; break; case 'p': case 'P': sp += _ure_prop_list(sp, ep - sp, &symp->props, b); /* * Invert the bit mask of the properties if this is a negated * character class or if 'P' is used to specify a list of * character properties that should *not* match in a * character class. */ if (c == 'P') symp->props = ~symp->props; continue; break; case 'x': case 'X': case 'u': case 'U': if (sp < ep && ((*sp >= '0' && *sp <= '9') || (*sp >= 'A' && *sp <= 'F') || (*sp >= 'a' && *sp <= 'f'))) sp += _ure_hex(sp, ep - sp, &c); } } else if (c == ':') { /* * Probe for a POSIX colon delimited character class. */ sp--; if ((n = _ure_posix_ccl(sp, ep - sp, symp, b)) == 0) sp++; else { sp += n; continue; } } cclp = &symp->sym.ccl; /* * Check to see if the current character is a low surrogate that needs * to be combined with a preceding high surrogate. */ if (last != 0) { if (c >= 0xdc00 && c <= 0xdfff) /* * Construct the UTF16 character code. */ c = 0x10000 + (((last & 0x03ff) << 10) | (c & 0x03ff)); else { /* * Add the isolated high surrogate to the range. */ if (range_end == 1) range.max_code = last & 0xffff; else range.min_code = range.max_code = last & 0xffff; _ure_add_range(cclp, &range, b); range_end = 0; } } /* * Clear the last character code. */ last = 0; /* * This slightly awkward code handles the different cases needed to * construct a range. */ if (c >= 0xd800 && c <= 0xdbff) { /* * If the high surrogate is followed by a range indicator, simply * add it as the range start. Otherwise, save it in case the next * character is a low surrogate. */ if (*sp == '-') { sp++; range.min_code = c; range_end = 1; } else last = c; } else if (range_end == 1) { range.max_code = c; _ure_add_range(cclp, &range, b); range_end = 0; } else { range.min_code = range.max_code = c; if (*sp == '-') { sp++; range_end = 1; } else _ure_add_range(cclp, &range, b); } } if (sp < ep && *sp == ']') sp++; else /* * The parse was not terminated by the character class close symbol * (']'), so set an error code. */ b->error = _URE_CCLASS_OPEN; return sp - cp; } /* * Probe for a low surrogate hex code. */ static unsigned long _ure_probe_ls(ucs2_t *ls, unsigned long limit, ucs4_t *c) { ucs4_t i, code; ucs2_t *sp, *ep; for (i = code = 0, sp = ls, ep = sp + limit; i < 4 && sp < ep; sp++) { if (*sp >= '0' && *sp <= '9') code = (code << 4) + (*sp - '0'); else if (*sp >= 'A' && *sp <= 'F') code = (code << 4) + ((*sp - 'A') + 10); else if (*sp >= 'a' && *sp <= 'f') code = (code << 4) + ((*sp - 'a') + 10); else break; } *c = code; return (0xdc00 <= code && code <= 0xdfff) ? sp - ls : 0; } static unsigned long _ure_compile_symbol(ucs2_t *sym, unsigned long limit, _ure_symtab_t *symp, _ure_buffer_t *b) { ucs4_t c; ucs2_t *sp, *ep; sp = sym; ep = sym + limit; if ((c = *sp++) == '\\') { if (sp == ep) { /* * The EOS was encountered when expecting the reverse solidus to * be followed by the character it is escaping. Set an error code * and return the number of characters consumed up to this point. */ b->error = _URE_UNEXPECTED_EOS; return sp - sym; } c = *sp++; switch (c) { case 'p': case 'P': symp->type = (c == 'p') ? _URE_CCLASS : _URE_NCCLASS; sp += _ure_prop_list(sp, ep - sp, &symp->props, b); break; case 'a': symp->type = _URE_CHAR; symp->sym.chr = 0x07; break; case 'b': symp->type = _URE_CHAR; symp->sym.chr = 0x08; break; case 'f': symp->type = _URE_CHAR; symp->sym.chr = 0x0c; break; case 'n': symp->type = _URE_CHAR; symp->sym.chr = 0x0a; break; case 'r': symp->type = _URE_CHAR; symp->sym.chr = 0x0d; break; case 't': symp->type = _URE_CHAR; symp->sym.chr = 0x09; break; case 'v': symp->type = _URE_CHAR; symp->sym.chr = 0x0b; break; case 'x': case 'X': case 'u': case 'U': /* * Collect between 1 and 4 digits representing a UCS2 code. Fall * through to the next case. */ if (sp < ep && ((*sp >= '0' && *sp <= '9') || (*sp >= 'A' && *sp <= 'F') || (*sp >= 'a' && *sp <= 'f'))) sp += _ure_hex(sp, ep - sp, &c); /* FALLTHROUGH */ default: /* * Simply add an escaped character here. */ symp->type = _URE_CHAR; symp->sym.chr = c; } } else if (c == '^' || c == '$') /* * Handle the BOL and EOL anchors. This actually consists simply of * setting a flag that indicates that the user supplied anchor match * function should be called. This needs to be done instead of simply * matching line/paragraph separators because beginning-of-text and * end-of-text tests are needed as well. */ symp->type = (c == '^') ? _URE_BOL_ANCHOR : _URE_EOL_ANCHOR; else if (c == '[') /* * Construct a character class. */ sp += _ure_cclass(sp, ep - sp, symp, b); else if (c == '.') symp->type = _URE_ANY_CHAR; else { symp->type = _URE_CHAR; symp->sym.chr = c; } /* * If the symbol type happens to be a character and is a high surrogate, * then probe forward to see if it is followed by a low surrogate that * needs to be added. */ if (sp < ep && symp->type == _URE_CHAR && 0xd800 <= symp->sym.chr && symp->sym.chr <= 0xdbff) { if (0xdc00 <= *sp && *sp <= 0xdfff) { symp->sym.chr = 0x10000 + (((symp->sym.chr & 0x03ff) << 10) | (*sp & 0x03ff)); sp++; } else if (*sp == '\\' && (*(sp + 1) == 'x' || *(sp + 1) == 'X' || *(sp + 1) == 'u' || *(sp + 1) == 'U')) { sp += _ure_probe_ls(sp + 2, ep - (sp + 2), &c); if (0xdc00 <= c && c <= 0xdfff) { /* * Take into account the \[xu] in front of the hex code. */ sp += 2; symp->sym.chr = 0x10000 + (((symp->sym.chr & 0x03ff) << 10) | (c & 0x03ff)); } } } /* * Last, make sure any _URE_CHAR type symbols are changed to lower case if * the `casefold' flag is set. */ if ((b->flags & _URE_DFA_CASEFOLD) && symp->type == _URE_CHAR) symp->sym.chr = _ure_tolower(symp->sym.chr); /* * If the symbol constructed is anything other than one of the anchors, * make sure the _URE_DFA_BLANKLINE flag is removed. */ if (symp->type != _URE_BOL_ANCHOR && symp->type != _URE_EOL_ANCHOR) b->flags &= ~_URE_DFA_BLANKLINE; /* * Return the number of characters consumed. */ return sp - sym; } static int _ure_sym_neq(_ure_symtab_t *a, _ure_symtab_t *b) { if (a->type != b->type || a->mods != b->mods || a->props != b->props) return 1; if (a->type == _URE_CCLASS || a->type == _URE_NCCLASS) { if (a->sym.ccl.ranges_used != b->sym.ccl.ranges_used) return 1; if (a->sym.ccl.ranges_used > 0 && memcmp((char *) a->sym.ccl.ranges, (char *) b->sym.ccl.ranges, sizeof(_ure_range_t) * a->sym.ccl.ranges_used) != 0) return 1; } else if (a->type == _URE_CHAR && a->sym.chr != b->sym.chr) return 1; return 0; } /* * Construct a symbol, but only keep unique symbols. */ static ucs2_t _ure_make_symbol(ucs2_t *sym, unsigned long limit, unsigned long *consumed, _ure_buffer_t *b) { ucs2_t i; _ure_symtab_t *sp, symbol; /* * Build the next symbol so we can test to see if it is already in the * symbol table. */ (void) memset((char *) &symbol, '\0', sizeof(_ure_symtab_t)); *consumed = _ure_compile_symbol(sym, limit, &symbol, b); /* * Check to see if the symbol exists. */ for (i = 0, sp = b->symtab; i < b->symtab_used && _ure_sym_neq(&symbol, sp); i++, sp++) ; if (i < b->symtab_used) { /* * Free up any ranges used for the symbol. */ if ((symbol.type == _URE_CCLASS || symbol.type == _URE_NCCLASS) && symbol.sym.ccl.ranges_size > 0) free((char *) symbol.sym.ccl.ranges); return b->symtab[i].id; } /* * Need to add the new symbol. */ if (b->symtab_used == b->symtab_size) { if (b->symtab_size == 0) b->symtab = (_ure_symtab_t *) malloc(sizeof(_ure_symtab_t) << 3); else b->symtab = (_ure_symtab_t *) realloc((char *) b->symtab, sizeof(_ure_symtab_t) * (b->symtab_size + 8)); sp = b->symtab + b->symtab_size; (void) memset((char *) sp, '\0', sizeof(_ure_symtab_t) << 3); b->symtab_size += 8; } symbol.id = b->symtab_used++; (void) AC_MEMCPY((char *) &b->symtab[symbol.id], (char *) &symbol, sizeof(_ure_symtab_t)); return symbol.id; } /************************************************************************* * * End symbol parse functions. * *************************************************************************/ static ucs2_t _ure_make_expr(ucs2_t type, ucs2_t lhs, ucs2_t rhs, _ure_buffer_t *b) { ucs2_t i; if (b == 0) return _URE_NOOP; /* * Determine if the expression already exists or not. */ for (i = 0; i < b->expr_used; i++) { if (b->expr[i].type == type && b->expr[i].lhs == lhs && b->expr[i].rhs == rhs) break; } if (i < b->expr_used) return i; /* * Need to add a new expression. */ if (b->expr_used == b->expr_size) { if (b->expr_size == 0) b->expr = (_ure_elt_t *) malloc(sizeof(_ure_elt_t) << 3); else b->expr = (_ure_elt_t *) realloc((char *) b->expr, sizeof(_ure_elt_t) * (b->expr_size + 8)); b->expr_size += 8; } b->expr[b->expr_used].onstack = 0; b->expr[b->expr_used].type = type; b->expr[b->expr_used].lhs = lhs; b->expr[b->expr_used].rhs = rhs; return b->expr_used++; } static unsigned char spmap[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #define _ure_isspecial(cc) ((cc) > 0x20 && (cc) < 0x7f && \ (spmap[(cc) >> 3] & (1 << ((cc) & 7)))) /* * Convert the regular expression into an NFA in a form that will be easy to * reduce to a DFA. The starting state for the reduction will be returned. */ static ucs2_t _ure_re2nfa(ucs2_t *re, unsigned long relen, _ure_buffer_t *b) { ucs2_t c, state, top, sym, *sp, *ep; unsigned long used; state = _URE_NOOP; sp = re; ep = sp + relen; while (b->error == _URE_OK && sp < ep) { c = *sp++; switch (c) { case '(': _ure_push(_URE_PAREN, b); break; case ')': /* * Check for the case of too many close parentheses. */ if (_ure_peek(b) == _URE_NOOP) { b->error = _URE_UNBALANCED_GROUP; break; } while ((top = _ure_peek(b)) == _URE_AND || top == _URE_OR) /* * Make an expression with the AND or OR operator and its right * hand side. */ state = _ure_make_expr(_ure_pop(b), _ure_pop(b), state, b); /* * Remove the _URE_PAREN off the stack. */ (void) _ure_pop(b); break; case '*': state = _ure_make_expr(_URE_STAR, state, _URE_NOOP, b); break; case '+': state = _ure_make_expr(_URE_PLUS, state, _URE_NOOP, b); break; case '?': state = _ure_make_expr(_URE_QUEST, state, _URE_NOOP, b); break; case '|': while ((top = _ure_peek(b)) == _URE_AND || top == _URE_OR) /* * Make an expression with the AND or OR operator and its right * hand side. */ state = _ure_make_expr(_ure_pop(b), _ure_pop(b), state, b); _ure_push(state, b); _ure_push(_URE_OR, b); break; default: sp--; sym = _ure_make_symbol(sp, ep - sp, &used, b); sp += used; state = _ure_make_expr(_URE_SYMBOL, sym, _URE_NOOP, b); break; } if (c != '(' && c != '|' && sp < ep && (!_ure_isspecial(*sp) || *sp == '(')) { _ure_push(state, b); _ure_push(_URE_AND, b); } } while ((top = _ure_peek(b)) == _URE_AND || top == _URE_OR) /* * Make an expression with the AND or OR operator and its right * hand side. */ state = _ure_make_expr(_ure_pop(b), _ure_pop(b), state, b); if (b->stack.slist_used > 0) b->error = _URE_UNBALANCED_GROUP; return (b->error == _URE_OK) ? state : _URE_NOOP; } static void _ure_add_symstate(ucs2_t sym, ucs2_t state, _ure_buffer_t *b) { ucs2_t i, *stp; _ure_symtab_t *sp; /* * Locate the symbol in the symbol table so the state can be added. * If the symbol doesn't exist, then a real problem exists. */ for (i = 0, sp = b->symtab; i < b->symtab_used && sym != sp->id; i++, sp++) ; /* * Now find out if the state exists in the symbol's state list. */ for (i = 0, stp = sp->states.slist; i < sp->states.slist_used && state > *stp; i++, stp++) ; if (i == sp->states.slist_used || state < *stp) { /* * Need to add the state in order. */ if (sp->states.slist_used == sp->states.slist_size) { if (sp->states.slist_size == 0) sp->states.slist = (ucs2_t *) malloc(sizeof(ucs2_t) << 3); else sp->states.slist = (ucs2_t *) realloc((char *) sp->states.slist, sizeof(ucs2_t) * (sp->states.slist_size + 8)); sp->states.slist_size += 8; } if (i < sp->states.slist_used) (void) _ure_memmove((char *) (sp->states.slist + i + 1), (char *) (sp->states.slist + i), sizeof(ucs2_t) * (sp->states.slist_used - i)); sp->states.slist[i] = state; sp->states.slist_used++; } } static ucs2_t _ure_add_state(ucs2_t nstates, ucs2_t *states, _ure_buffer_t *b) { ucs2_t i; _ure_state_t *sp; for (i = 0, sp = b->states.states; i < b->states.states_used; i++, sp++) { if (sp->st.slist_used == nstates && memcmp((char *) states, (char *) sp->st.slist, sizeof(ucs2_t) * nstates) == 0) break; } if (i == b->states.states_used) { /* * Need to add a new DFA state (set of NFA states). */ if (b->states.states_used == b->states.states_size) { if (b->states.states_size == 0) b->states.states = (_ure_state_t *) malloc(sizeof(_ure_state_t) << 3); else b->states.states = (_ure_state_t *) realloc((char *) b->states.states, sizeof(_ure_state_t) * (b->states.states_size + 8)); sp = b->states.states + b->states.states_size; (void) memset((char *) sp, '\0', sizeof(_ure_state_t) << 3); b->states.states_size += 8; } sp = b->states.states + b->states.states_used++; sp->id = i; if (sp->st.slist_used + nstates > sp->st.slist_size) { if (sp->st.slist_size == 0) sp->st.slist = (ucs2_t *) malloc(sizeof(ucs2_t) * (sp->st.slist_used + nstates)); else sp->st.slist = (ucs2_t *) realloc((char *) sp->st.slist, sizeof(ucs2_t) * (sp->st.slist_used + nstates)); sp->st.slist_size = sp->st.slist_used + nstates; } sp->st.slist_used = nstates; (void) AC_MEMCPY((char *) sp->st.slist, (char *) states, sizeof(ucs2_t) * nstates); } /* * Return the ID of the DFA state representing a group of NFA states. */ return i; } static void _ure_reduce(ucs2_t start, _ure_buffer_t *b) { ucs2_t i, j, state, eval, syms, rhs; ucs2_t s1, s2, ns1, ns2; _ure_state_t *sp; _ure_symtab_t *smp; b->reducing = 1; /* * Add the starting state for the reduction. */ _ure_add_state(1, &start, b); /* * Process each set of NFA states that get created. */ for (i = 0; i < b->states.states_used; i++) { sp = b->states.states + i; /* * Push the current states on the stack. */ for (j = 0; j < sp->st.slist_used; j++) _ure_push(sp->st.slist[j], b); /* * Reduce the NFA states. */ for (j = sp->accepting = syms = 0; j < b->stack.slist_used; j++) { state = b->stack.slist[j]; eval = 1; /* * This inner loop is the iterative equivalent of recursively * reducing subexpressions generated as a result of a reduction. */ while (eval) { switch (b->expr[state].type) { case _URE_SYMBOL: ns1 = _ure_make_expr(_URE_ONE, _URE_NOOP, _URE_NOOP, b); _ure_add_symstate(b->expr[state].lhs, ns1, b); syms++; eval = 0; break; case _URE_ONE: sp->accepting = 1; eval = 0; break; case _URE_QUEST: s1 = b->expr[state].lhs; ns1 = _ure_make_expr(_URE_ONE, _URE_NOOP, _URE_NOOP, b); state = _ure_make_expr(_URE_OR, ns1, s1, b); break; case _URE_PLUS: s1 = b->expr[state].lhs; ns1 = _ure_make_expr(_URE_STAR, s1, _URE_NOOP, b); state = _ure_make_expr(_URE_AND, s1, ns1, b); break; case _URE_STAR: s1 = b->expr[state].lhs; ns1 = _ure_make_expr(_URE_ONE, _URE_NOOP, _URE_NOOP, b); ns2 = _ure_make_expr(_URE_PLUS, s1, _URE_NOOP, b); state = _ure_make_expr(_URE_OR, ns1, ns2, b); break; case _URE_OR: s1 = b->expr[state].lhs; s2 = b->expr[state].rhs; _ure_push(s1, b); _ure_push(s2, b); eval = 0; break; case _URE_AND: s1 = b->expr[state].lhs; s2 = b->expr[state].rhs; switch (b->expr[s1].type) { case _URE_SYMBOL: _ure_add_symstate(b->expr[s1].lhs, s2, b); syms++; eval = 0; break; case _URE_ONE: state = s2; break; case _URE_QUEST: ns1 = b->expr[s1].lhs; ns2 = _ure_make_expr(_URE_AND, ns1, s2, b); state = _ure_make_expr(_URE_OR, s2, ns2, b); break; case _URE_PLUS: ns1 = b->expr[s1].lhs; ns2 = _ure_make_expr(_URE_OR, s2, state, b); state = _ure_make_expr(_URE_AND, ns1, ns2, b); break; case _URE_STAR: ns1 = b->expr[s1].lhs; ns2 = _ure_make_expr(_URE_AND, ns1, state, b); state = _ure_make_expr(_URE_OR, s2, ns2, b); break; case _URE_OR: ns1 = b->expr[s1].lhs; ns2 = b->expr[s1].rhs; ns1 = _ure_make_expr(_URE_AND, ns1, s2, b); ns2 = _ure_make_expr(_URE_AND, ns2, s2, b); state = _ure_make_expr(_URE_OR, ns1, ns2, b); break; case _URE_AND: ns1 = b->expr[s1].lhs; ns2 = b->expr[s1].rhs; ns2 = _ure_make_expr(_URE_AND, ns2, s2, b); state = _ure_make_expr(_URE_AND, ns1, ns2, b); break; } } } } /* * Clear the state stack. */ while (_ure_pop(b) != _URE_NOOP) ; /* * Reset the state pointer because the reduction may have moved it * during a reallocation. */ sp = b->states.states + i; /* * Generate the DFA states for the symbols collected during the * current reduction. */ if (sp->trans_used + syms > sp->trans_size) { if (sp->trans_size == 0) sp->trans = (_ure_elt_t *) malloc(sizeof(_ure_elt_t) * (sp->trans_used + syms)); else sp->trans = (_ure_elt_t *) realloc((char *) sp->trans, sizeof(_ure_elt_t) * (sp->trans_used + syms)); sp->trans_size = sp->trans_used + syms; } /* * Go through the symbol table and generate the DFA state transitions * for each symbol that has collected NFA states. */ for (j = syms = 0, smp = b->symtab; j < b->symtab_used; j++, smp++) { sp = b->states.states + i; if (smp->states.slist_used > 0) { sp->trans[syms].lhs = smp->id; rhs = _ure_add_state(smp->states.slist_used, smp->states.slist, b); /* * Reset the state pointer in case the reallocation moves it * in memory. */ sp = b->states.states + i; sp->trans[syms].rhs = rhs; smp->states.slist_used = 0; syms++; } } /* * Set the number of transitions actually used. */ sp->trans_used = syms; } b->reducing = 0; } static void _ure_add_equiv(ucs2_t l, ucs2_t r, _ure_buffer_t *b) { ucs2_t tmp; l = b->states.states[l].id; r = b->states.states[r].id; if (l == r) return; if (l > r) { tmp = l; l = r; r = tmp; } /* * Check to see if the equivalence pair already exists. */ for (tmp = 0; tmp < b->equiv_used && (b->equiv[tmp].l != l || b->equiv[tmp].r != r); tmp++) ; if (tmp < b->equiv_used) return; if (b->equiv_used == b->equiv_size) { if (b->equiv_size == 0) b->equiv = (_ure_equiv_t *) malloc(sizeof(_ure_equiv_t) << 3); else b->equiv = (_ure_equiv_t *) realloc((char *) b->equiv, sizeof(_ure_equiv_t) * (b->equiv_size + 8)); b->equiv_size += 8; } b->equiv[b->equiv_used].l = l; b->equiv[b->equiv_used].r = r; b->equiv_used++; } /* * Merge the DFA states that are equivalent. */ static void _ure_merge_equiv(_ure_buffer_t *b) { ucs2_t i, j, k, eq, done; _ure_state_t *sp1, *sp2, *ls, *rs; for (i = 0; i < b->states.states_used; i++) { sp1 = b->states.states + i; if (sp1->id != i) continue; for (j = 0; j < i; j++) { sp2 = b->states.states + j; if (sp2->id != j) continue; b->equiv_used = 0; _ure_add_equiv(i, j, b); for (eq = 0, done = 0; eq < b->equiv_used; eq++) { ls = b->states.states + b->equiv[eq].l; rs = b->states.states + b->equiv[eq].r; if (ls->accepting != rs->accepting || ls->trans_used != rs->trans_used) { done = 1; break; } for (k = 0; k < ls->trans_used && ls->trans[k].lhs == rs->trans[k].lhs; k++) ; if (k < ls->trans_used) { done = 1; break; } for (k = 0; k < ls->trans_used; k++) _ure_add_equiv(ls->trans[k].rhs, rs->trans[k].rhs, b); } if (done == 0) break; } for (eq = 0; j < i && eq < b->equiv_used; eq++) b->states.states[b->equiv[eq].r].id = b->states.states[b->equiv[eq].l].id; } /* * Renumber the states appropriately. */ for (i = eq = 0, sp1 = b->states.states; i < b->states.states_used; sp1++, i++) sp1->id = (sp1->id == i) ? eq++ : b->states.states[sp1->id].id; } /************************************************************************* * * API. * *************************************************************************/ ure_buffer_t ure_buffer_create(void) { ure_buffer_t b; b = (ure_buffer_t) calloc(1, sizeof(_ure_buffer_t)); return b; } void ure_buffer_free(ure_buffer_t buf) { unsigned long i; if (buf == 0) return; if (buf->stack.slist_size > 0) free((char *) buf->stack.slist); if (buf->expr_size > 0) free((char *) buf->expr); for (i = 0; i < buf->symtab_size; i++) { if (buf->symtab[i].states.slist_size > 0) free((char *) buf->symtab[i].states.slist); } if (buf->symtab_size > 0) free((char *) buf->symtab); for (i = 0; i < buf->states.states_size; i++) { if (buf->states.states[i].trans_size > 0) free((char *) buf->states.states[i].trans); if (buf->states.states[i].st.slist_size > 0) free((char *) buf->states.states[i].st.slist); } if (buf->states.states_size > 0) free((char *) buf->states.states); if (buf->equiv_size > 0) free((char *) buf->equiv); free((char *) buf); } ure_dfa_t ure_compile(ucs2_t *re, unsigned long relen, int casefold, ure_buffer_t buf) { ucs2_t i, j, state; _ure_state_t *sp; _ure_dstate_t *dsp; _ure_trans_t *tp; ure_dfa_t dfa; if (re == 0 || *re == 0 || relen == 0 || buf == 0) return 0; /* * Reset the various fields of the compilation buffer. Default the flags * to indicate the presence of the "^$" pattern. If any other pattern * occurs, then this flag will be removed. This is done to catch this * special pattern and handle it specially when matching. */ buf->flags = _URE_DFA_BLANKLINE | ((casefold) ? _URE_DFA_CASEFOLD : 0); buf->reducing = 0; buf->stack.slist_used = 0; buf->expr_used = 0; for (i = 0; i < buf->symtab_used; i++) buf->symtab[i].states.slist_used = 0; buf->symtab_used = 0; for (i = 0; i < buf->states.states_used; i++) { buf->states.states[i].st.slist_used = 0; buf->states.states[i].trans_used = 0; } buf->states.states_used = 0; /* * Construct the NFA. If this stage returns a 0, then an error occurred or * an empty expression was passed. */ if ((state = _ure_re2nfa(re, relen, buf)) == _URE_NOOP) return 0; /* * Do the expression reduction to get the initial DFA. */ _ure_reduce(state, buf); /* * Merge all the equivalent DFA states. */ _ure_merge_equiv(buf); /* * Construct the minimal DFA. */ dfa = (ure_dfa_t) malloc(sizeof(_ure_dfa_t)); (void) memset((char *) dfa, '\0', sizeof(_ure_dfa_t)); dfa->flags = buf->flags & (_URE_DFA_CASEFOLD|_URE_DFA_BLANKLINE); /* * Free up the NFA state groups and transfer the symbols from the buffer * to the DFA. */ for (i = 0; i < buf->symtab_size; i++) { if (buf->symtab[i].states.slist_size > 0) free((char *) buf->symtab[i].states.slist); } dfa->syms = buf->symtab; dfa->nsyms = buf->symtab_used; buf->symtab_used = buf->symtab_size = 0; /* * Collect the total number of states and transitions needed for the DFA. */ for (i = state = 0, sp = buf->states.states; i < buf->states.states_used; i++, sp++) { if (sp->id == state) { dfa->nstates++; dfa->ntrans += sp->trans_used; state++; } } /* * Allocate enough space for the states and transitions. */ dfa->states = (_ure_dstate_t *) malloc(sizeof(_ure_dstate_t) * dfa->nstates); dfa->trans = (_ure_trans_t *) malloc(sizeof(_ure_trans_t) * dfa->ntrans); /* * Actually transfer the DFA states from the buffer. */ dsp = dfa->states; tp = dfa->trans; for (i = state = 0, sp = buf->states.states; i < buf->states.states_used; i++, sp++) { if (sp->id == state) { dsp->trans = tp; dsp->ntrans = sp->trans_used; dsp->accepting = sp->accepting; /* * Add the transitions for the state. */ for (j = 0; j < dsp->ntrans; j++, tp++) { tp->symbol = sp->trans[j].lhs; tp->next_state = buf->states.states[sp->trans[j].rhs].id; } dsp++; state++; } } return dfa; } void ure_dfa_free(ure_dfa_t dfa) { ucs2_t i; if (dfa == 0) return; for (i = 0; i < dfa->nsyms; i++) { if ((dfa->syms[i].type == _URE_CCLASS || dfa->syms[i].type == _URE_NCCLASS) && dfa->syms[i].sym.ccl.ranges_size > 0) free((char *) dfa->syms[i].sym.ccl.ranges); } if (dfa->nsyms > 0) free((char *) dfa->syms); if (dfa->nstates > 0) free((char *) dfa->states); if (dfa->ntrans > 0) free((char *) dfa->trans); free((char *) dfa); } void ure_write_dfa(ure_dfa_t dfa, FILE *out) { ucs2_t i, j, k, h, l; _ure_dstate_t *sp; _ure_symtab_t *sym; _ure_range_t *rp; if (dfa == 0 || out == 0) return; /* * Write all the different character classes. */ for (i = 0, sym = dfa->syms; i < dfa->nsyms; i++, sym++) { if (sym->type == _URE_CCLASS || sym->type == _URE_NCCLASS) { fprintf(out, "C%hd = ", sym->id); if (sym->sym.ccl.ranges_used > 0) { putc('[', out); if (sym->type == _URE_NCCLASS) putc('^', out); } if (sym->props != 0) { if (sym->type == _URE_NCCLASS) fprintf(out, "\\P"); else fprintf(out, "\\p"); for (k = h = 0; k < 32; k++) { if (sym->props & (1 << k)) { if (h != 0) putc(',', out); fprintf(out, "%d", k + 1); h = 1; } } } /* * Dump the ranges. */ for (k = 0, rp = sym->sym.ccl.ranges; k < sym->sym.ccl.ranges_used; k++, rp++) { /* * Check for UTF16 characters. */ if (0x10000 <= rp->min_code && rp->min_code <= 0x10ffff) { h = (ucs2_t) (((rp->min_code - 0x10000) >> 10) + 0xd800); l = (ucs2_t) (((rp->min_code - 0x10000) & 1023) + 0xdc00); fprintf(out, "\\x%04hX\\x%04hX", h, l); } else fprintf(out, "\\x%04lX", rp->min_code & 0xffff); if (rp->max_code != rp->min_code) { putc('-', out); if (rp->max_code >= 0x10000 && rp->max_code <= 0x10ffff) { h = (ucs2_t) (((rp->max_code - 0x10000) >> 10) + 0xd800); l = (ucs2_t) (((rp->max_code - 0x10000) & 1023) + 0xdc00); fprintf(out, "\\x%04hX\\x%04hX", h, l); } else fprintf(out, "\\x%04lX", rp->max_code & 0xffff); } } if (sym->sym.ccl.ranges_used > 0) putc(']', out); putc('\n', out); } } for (i = 0, sp = dfa->states; i < dfa->nstates; i++, sp++) { fprintf(out, "S%hd = ", i); if (sp->accepting) { fprintf(out, "1 "); if (sp->ntrans) fprintf(out, "| "); } for (j = 0; j < sp->ntrans; j++) { if (j > 0) fprintf(out, "| "); sym = dfa->syms + sp->trans[j].symbol; switch (sym->type) { case _URE_CHAR: if (0x10000 <= sym->sym.chr && sym->sym.chr <= 0x10ffff) { /* * Take care of UTF16 characters. */ h = (ucs2_t) (((sym->sym.chr - 0x10000) >> 10) + 0xd800); l = (ucs2_t) (((sym->sym.chr - 0x10000) & 1023) + 0xdc00); fprintf(out, "\\x%04hX\\x%04hX ", h, l); } else fprintf(out, "\\x%04lX ", sym->sym.chr & 0xffff); break; case _URE_ANY_CHAR: fprintf(out, " "); break; case _URE_BOL_ANCHOR: fprintf(out, " "); break; case _URE_EOL_ANCHOR: fprintf(out, " "); break; case _URE_CCLASS: case _URE_NCCLASS: fprintf(out, "[C%hd] ", sym->id); break; } fprintf(out, "S%hd", sp->trans[j].next_state); if (j + 1 < sp->ntrans) putc(' ', out); } putc('\n', out); } } #define _ure_issep(cc) ((cc) == '\n' || (cc) == '\r' || (cc) == 0x2028 ||\ (cc) == 0x2029) int ure_exec(ure_dfa_t dfa, int flags, ucs2_t *text, unsigned long textlen, unsigned long *match_start, unsigned long *match_end) { int i, j, matched, found, skip; unsigned long ms, me; ucs4_t c; ucs2_t *sp, *ep, *lp; _ure_dstate_t *stp; _ure_symtab_t *sym; _ure_range_t *rp; if (dfa == 0 || text == 0) return 0; /* * Handle the special case of an empty string matching the "^$" pattern. */ if (textlen == 0 && (dfa->flags & _URE_DFA_BLANKLINE)) { *match_start = *match_end = 0; return 1; } sp = text; ep = sp + textlen; ms = me = ~0; stp = dfa->states; for (found = skip = 0; found == 0 && sp < ep; ) { lp = sp; c = *sp++; /* * Check to see if this is a high surrogate that should be * combined with a following low surrogate. */ if (sp < ep && 0xd800 <= c && c <= 0xdbff && 0xdc00 <= *sp && *sp <= 0xdfff) c = 0x10000 + (((c & 0x03ff) << 10) | (*sp++ & 0x03ff)); /* * Determine if the character is non-spacing and should be skipped. */ if (_ure_matches_properties(_URE_NONSPACING, c) && (flags & URE_IGNORE_NONSPACING)) { sp++; continue; } if (dfa->flags & _URE_DFA_CASEFOLD) c = _ure_tolower(c); /* * See if one of the transitions matches. */ for (i = 0, matched = 0; matched == 0 && i < stp->ntrans; i++) { sym = dfa->syms + stp->trans[i].symbol; switch (sym->type) { case _URE_ANY_CHAR: if ((flags & URE_DOT_MATCHES_SEPARATORS) || !_ure_issep(c)) matched = 1; break; case _URE_CHAR: if (c == sym->sym.chr) matched = 1; break; case _URE_BOL_ANCHOR: if (lp == text) { sp = lp; matched = 1; } else if (_ure_issep(c)) { if (c == '\r' && sp < ep && *sp == '\n') sp++; lp = sp; matched = 1; } break; case _URE_EOL_ANCHOR: if (_ure_issep(c)) { /* * Put the pointer back before the separator so the match * end position will be correct. This case will also * cause the `sp' pointer to be advanced over the current * separator once the match end point has been recorded. */ sp = lp; matched = 1; } break; case _URE_CCLASS: case _URE_NCCLASS: if (sym->props != 0) matched = _ure_matches_properties(sym->props, c); for (j = 0, rp = sym->sym.ccl.ranges; j < sym->sym.ccl.ranges_used; j++, rp++) { if (rp->min_code <= c && c <= rp->max_code) matched = 1; } if (sym->type == _URE_NCCLASS) matched = !matched; break; } if (matched) { if (ms == ~0UL) ms = lp - text; else me = sp - text; stp = dfa->states + stp->trans[i].next_state; /* * If the match was an EOL anchor, adjust the pointer past the * separator that caused the match. The correct match * position has been recorded already. */ if (sym->type == _URE_EOL_ANCHOR) { /* * Skip the character that caused the match. */ sp++; /* * Handle the infamous CRLF situation. */ if (sp < ep && c == '\r' && *sp == '\n') sp++; } } } if (matched == 0) { if (stp->accepting == 0) { /* * If the last state was not accepting, then reset * and start over. */ stp = dfa->states; ms = me = ~0; } else /* * The last state was accepting, so terminate the matching * loop to avoid more work. */ found = 1; } else if (sp == ep) { if (!stp->accepting) { /* * This ugly hack is to make sure the end-of-line anchors * match when the source text hits the end. This is only done * if the last subexpression matches. */ for (i = 0; found == 0 && i < stp->ntrans; i++) { sym = dfa->syms + stp->trans[i].symbol; if (sym->type ==_URE_EOL_ANCHOR) { stp = dfa->states + stp->trans[i].next_state; if (stp->accepting) { me = sp - text; found = 1; } else break; } } } else { /* * Make sure any conditions that match all the way to the end * of the string match. */ found = 1; me = sp - text; } } } if (found == 0) ms = me = ~0; *match_start = ms; *match_end = me; return (ms != ~0UL) ? 1 : 0; } openldap-2.5.11+dfsg/libraries/liblunicode/ure/README0000644000175000017500000001406614172327167020766 0ustar ryanryan# # $Id: README,v 1.3 1999/09/21 15:47:43 mleisher Exp $ # # Copyright 1997, 1998, 1999 Computing Research Labs, # New Mexico State University # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT # OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR # THE USE OR OTHER DEALINGS IN THE SOFTWARE. # Unicode and Regular Expressions Version 0.5 This is a simple regular expression package for matching against Unicode text in UCS2 form. The implementation of this URE package is a variation on the RE->DFA algorithm done by Mark Hopkins (markh@csd4.csd.uwm.edu). Mark Hopkins' algorithm had the virtue of being very simple, so it was used as a model. --------------------------------------------------------------------------- Assumptions: o Regular expression and text already normalized. o Conversion to lower case assumes a 1-1 mapping. Definitions: Separator - any one of U+2028, U+2029, '\n', '\r'. Operators: . - match any character. * - match zero or more of the last subexpression. + - match one or more of the last subexpression. ? - match zero or one of the last subexpression. () - subexpression grouping. Notes: o The "." operator normally does not match separators, but a flag is available for the ure_exec() function that will allow this operator to match a separator. Literals and Constants: c - literal UCS2 character. \x.... - hexadecimal number of up to 4 digits. \X.... - hexadecimal number of up to 4 digits. \u.... - hexadecimal number of up to 4 digits. \U.... - hexadecimal number of up to 4 digits. Character classes: [...] - Character class. [^...] - Negated character class. \pN1,N2,...,Nn - Character properties class. \PN1,N2,...,Nn - Negated character properties class. POSIX character classes recognized: :alnum: :alpha: :cntrl: :digit: :graph: :lower: :print: :punct: :space: :upper: :xdigit: Notes: o Character property classes are \p or \P followed by a comma separated list of integers between 1 and 32. These integers are references to the following character properties: N Character Property -------------------------- 1 _URE_NONSPACING 2 _URE_COMBINING 3 _URE_NUMDIGIT 4 _URE_NUMOTHER 5 _URE_SPACESEP 6 _URE_LINESEP 7 _URE_PARASEP 8 _URE_CNTRL 9 _URE_PUA 10 _URE_UPPER 11 _URE_LOWER 12 _URE_TITLE 13 _URE_MODIFIER 14 _URE_OTHERLETTER 15 _URE_DASHPUNCT 16 _URE_OPENPUNCT 17 _URE_CLOSEPUNCT 18 _URE_OTHERPUNCT 19 _URE_MATHSYM 20 _URE_CURRENCYSYM 21 _URE_OTHERSYM 22 _URE_LTR 23 _URE_RTL 24 _URE_EURONUM 25 _URE_EURONUMSEP 26 _URE_EURONUMTERM 27 _URE_ARABNUM 28 _URE_COMMONSEP 29 _URE_BLOCKSEP 30 _URE_SEGMENTSEP 31 _URE_WHITESPACE 32 _URE_OTHERNEUT o Character classes can contain literals, constants, and character property classes. Example: [abc\U10A\p1,3,4] --------------------------------------------------------------------------- Before using URE ---------------- Before URE is used, two functions need to be created. One to check if a character matches a set of URE character properties, and one to convert a character to lower case. Stubs for these function are located in the urestubs.c file. Using URE --------- Sample pseudo-code fragment. ure_buffer_t rebuf; ure_dfa_t dfa; ucs2_t *re, *text; unsigned long relen, textlen; unsigned long match_start, match_end; /* * Allocate the dynamic storage needed to compile regular expressions. */ rebuf = ure_buffer_create(); for each regular expression in a list { re = next regular expression; relen = length(re); /* * Compile the regular expression with the case insensitive flag * turned on. */ dfa = ure_compile(re, relen, 1, rebuf); /* * Look for the first match in some text. The matching will be done * in a case insensitive manner because the expression was compiled * with the case insensitive flag on. */ if (ure_exec(dfa, 0, text, textlen, &match_start, &match_end)) printf("MATCH: %ld %ld\n", match_start, match_end); /* * Look for the first match in some text, ignoring non-spacing * characters. */ if (ure_exec(dfa, URE_IGNORE_NONSPACING, text, textlen, &match_start, &match_end)) printf("MATCH: %ld %ld\n", match_start, match_end); /* * Free the DFA. */ ure_free_dfa(dfa); } /* * Free the dynamic storage used for compiling the expressions. */ ure_free_buffer(rebuf); --------------------------------------------------------------------------- Mark Leisher 29 March 1997 =========================================================================== CHANGES ------- Version: 0.5 Date : 21 September 1999 ========================== 1. Added copyright stuff and put in CVS. openldap-2.5.11+dfsg/libraries/liblunicode/ure/urestubs.c0000644000175000017500000000750714172327167022130 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* * Copyright 1997, 1998, 1999 Computing Research Labs, * New Mexico State University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* $Id: urestubs.c,v 1.2 1999/09/21 15:47:44 mleisher Exp $" */ #include "portable.h" #include #include "ure.h" #ifdef _MSC_VER # include "../ucdata/ucdata.h" #else # include "ucdata.h" #endif /* * This file contains stub routines needed by the URE package to test * character properties and other Unicode implementation specific details. */ /* * This routine should return the lower case equivalent for the character or, * if there is no lower case quivalent, the character itself. */ ucs4_t _ure_tolower(ucs4_t c) { return uctoupper(c); } static struct ucmaskmap { unsigned long mask1; unsigned long mask2; } masks[32] = { { UC_MN, 0 }, /* _URE_NONSPACING */ { UC_MC, 0 }, /* _URE_COMBINING */ { UC_ND, 0 }, /* _URE_NUMDIGIT */ { UC_NL|UC_NO, 0 }, /* _URE_NUMOTHER */ { UC_ZS, 0 }, /* _URE_SPACESEP */ { UC_ZL, 0 }, /* _URE_LINESEP */ { UC_ZP, 0 }, /* _URE_PARASEP */ { UC_CC, 0 }, /* _URE_CNTRL */ { UC_CO, 0 }, /* _URE_PUA */ { UC_LU, 0 }, /* _URE_UPPER */ { UC_LL, 0 }, /* _URE_LOWER */ { UC_LT, 0 }, /* _URE_TITLE */ { UC_LM, 0 }, /* _URE_MODIFIER */ { UC_LO, 0 }, /* _URE_OTHERLETTER */ { UC_PD, 0 }, /* _URE_DASHPUNCT */ { UC_PS, 0 }, /* _URE_OPENPUNCT */ { UC_PC, 0 }, /* _URE_CLOSEPUNCT */ { UC_PO, 0 }, /* _URE_OTHERPUNCT */ { UC_SM, 0 }, /* _URE_MATHSYM */ { UC_SC, 0 }, /* _URE_CURRENCYSYM */ { UC_SO, 0 }, /* _URE_OTHERSYM */ { UC_L, 0 }, /* _URE_LTR */ { UC_R, 0 }, /* _URE_RTL */ { 0, UC_EN }, /* _URE_EURONUM */ { 0, UC_ES }, /* _URE_EURONUMSEP */ { 0, UC_ET }, /* _URE_EURONUMTERM */ { 0, UC_AN }, /* _URE_ARABNUM */ { 0, UC_CS }, /* _URE_COMMONSEP */ { 0, UC_B }, /* _URE_BLOCKSEP */ { 0, UC_S }, /* _URE_SEGMENTSEP */ { 0, UC_WS }, /* _URE_WHITESPACE */ { 0, UC_ON } /* _URE_OTHERNEUT */ }; /* * This routine takes a set of URE character property flags (see ure.h) along * with a character and tests to see if the character has one or more of those * properties. */ int _ure_matches_properties(unsigned long props, ucs4_t c) { int i; unsigned long mask1=0, mask2=0; for( i=0; i<32; i++ ) { if( props & (1 << i) ) { mask1 |= masks[i].mask1; mask2 |= masks[i].mask2; } } return ucisprop( c, mask1, mask2 ); } openldap-2.5.11+dfsg/libraries/liblunicode/ure/ure.h0000644000175000017500000001133314172327167021044 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Copyright 1997, 1998, 1999 Computing Research Labs, * New Mexico State University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* $Id: ure.h,v 1.2 1999/09/21 15:47:44 mleisher Exp $ */ #ifndef _h_ure #define _h_ure #include "portable.h" #include LDAP_BEGIN_DECL /* * Set of character class flags. */ #define _URE_NONSPACING 0x00000001 #define _URE_COMBINING 0x00000002 #define _URE_NUMDIGIT 0x00000004 #define _URE_NUMOTHER 0x00000008 #define _URE_SPACESEP 0x00000010 #define _URE_LINESEP 0x00000020 #define _URE_PARASEP 0x00000040 #define _URE_CNTRL 0x00000080 #define _URE_PUA 0x00000100 #define _URE_UPPER 0x00000200 #define _URE_LOWER 0x00000400 #define _URE_TITLE 0x00000800 #define _URE_MODIFIER 0x00001000 #define _URE_OTHERLETTER 0x00002000 #define _URE_DASHPUNCT 0x00004000 #define _URE_OPENPUNCT 0x00008000 #define _URE_CLOSEPUNCT 0x00010000 #define _URE_OTHERPUNCT 0x00020000 #define _URE_MATHSYM 0x00040000 #define _URE_CURRENCYSYM 0x00080000 #define _URE_OTHERSYM 0x00100000 #define _URE_LTR 0x00200000 #define _URE_RTL 0x00400000 #define _URE_EURONUM 0x00800000 #define _URE_EURONUMSEP 0x01000000 #define _URE_EURONUMTERM 0x02000000 #define _URE_ARABNUM 0x04000000 #define _URE_COMMONSEP 0x08000000 #define _URE_BLOCKSEP 0x10000000 #define _URE_SEGMENTSEP 0x20000000 #define _URE_WHITESPACE 0x40000000 #define _URE_OTHERNEUT 0x80000000 /* * Error codes. */ #define _URE_OK 0 #define _URE_UNEXPECTED_EOS -1 #define _URE_CCLASS_OPEN -2 #define _URE_UNBALANCED_GROUP -3 #define _URE_INVALID_PROPERTY -4 /* * Options that can be combined for searching. */ #define URE_IGNORE_NONSPACING 0x01 #define URE_DOT_MATCHES_SEPARATORS 0x02 typedef unsigned long ucs4_t; typedef unsigned short ucs2_t; /* * Opaque type for memory used when compiling expressions. */ typedef struct _ure_buffer_t *ure_buffer_t; /* * Opaque type for the minimal DFA used when matching. */ typedef struct _ure_dfa_t *ure_dfa_t; /************************************************************************* * * API. * *************************************************************************/ LDAP_LUNICODE_F (ure_buffer_t) ure_buffer_create LDAP_P((void)); LDAP_LUNICODE_F (void) ure_buffer_free LDAP_P((ure_buffer_t buf)); LDAP_LUNICODE_F (ure_dfa_t) ure_compile LDAP_P((ucs2_t *re, unsigned long relen, int casefold, ure_buffer_t buf)); LDAP_LUNICODE_F (void) ure_dfa_free LDAP_P((ure_dfa_t dfa)); LDAP_LUNICODE_F (void) ure_write_dfa LDAP_P((ure_dfa_t dfa, FILE *out)); LDAP_LUNICODE_F (int) ure_exec LDAP_P((ure_dfa_t dfa, int flags, ucs2_t *text, unsigned long textlen, unsigned long *match_start, unsigned long *match_end)); /************************************************************************* * * Prototypes for stub functions used for URE. These need to be rewritten to * use the Unicode support available on the system. * *************************************************************************/ LDAP_LUNICODE_F (ucs4_t) _ure_tolower LDAP_P((ucs4_t c)); LDAP_LUNICODE_F (int) _ure_matches_properties LDAP_P((unsigned long props, ucs4_t c)); LDAP_END_DECL #endif /* _h_ure */ openldap-2.5.11+dfsg/libraries/liblunicode/CompositionExclusions.txt0000644000175000017500000001644114172327167024433 0ustar ryanryan# CompositionExclusions-3.2.0.txt # Date: 2002-03-19,23:30:28 GMT [MD] # # This file lists the characters from the UAX #15 Composition Exclusion Table. # # The format of the comments in this file has been updated since the last version, # CompositionExclusions-3.txt. The only substantive change to this file between that # version and this one is the addition of U+2ADC FORKING. # # For more information, see # http://www.unicode.org/unicode/reports/tr15/#Primary Exclusion List Table # ================================================ # (1) Script Specifics # This list of characters cannot be derived from the UnicodeData file. # ================================================ 0958 # DEVANAGARI LETTER QA 0959 # DEVANAGARI LETTER KHHA 095A # DEVANAGARI LETTER GHHA 095B # DEVANAGARI LETTER ZA 095C # DEVANAGARI LETTER DDDHA 095D # DEVANAGARI LETTER RHA 095E # DEVANAGARI LETTER FA 095F # DEVANAGARI LETTER YYA 09DC # BENGALI LETTER RRA 09DD # BENGALI LETTER RHA 09DF # BENGALI LETTER YYA 0A33 # GURMUKHI LETTER LLA 0A36 # GURMUKHI LETTER SHA 0A59 # GURMUKHI LETTER KHHA 0A5A # GURMUKHI LETTER GHHA 0A5B # GURMUKHI LETTER ZA 0A5E # GURMUKHI LETTER FA 0B5C # ORIYA LETTER RRA 0B5D # ORIYA LETTER RHA 0F43 # TIBETAN LETTER GHA 0F4D # TIBETAN LETTER DDHA 0F52 # TIBETAN LETTER DHA 0F57 # TIBETAN LETTER BHA 0F5C # TIBETAN LETTER DZHA 0F69 # TIBETAN LETTER KSSA 0F76 # TIBETAN VOWEL SIGN VOCALIC R 0F78 # TIBETAN VOWEL SIGN VOCALIC L 0F93 # TIBETAN SUBJOINED LETTER GHA 0F9D # TIBETAN SUBJOINED LETTER DDHA 0FA2 # TIBETAN SUBJOINED LETTER DHA 0FA7 # TIBETAN SUBJOINED LETTER BHA 0FAC # TIBETAN SUBJOINED LETTER DZHA 0FB9 # TIBETAN SUBJOINED LETTER KSSA FB1D # HEBREW LETTER YOD WITH HIRIQ FB1F # HEBREW LIGATURE YIDDISH YOD YOD PATAH FB2A # HEBREW LETTER SHIN WITH SHIN DOT FB2B # HEBREW LETTER SHIN WITH SIN DOT FB2C # HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT FB2D # HEBREW LETTER SHIN WITH DAGESH AND SIN DOT FB2E # HEBREW LETTER ALEF WITH PATAH FB2F # HEBREW LETTER ALEF WITH QAMATS FB30 # HEBREW LETTER ALEF WITH MAPIQ FB31 # HEBREW LETTER BET WITH DAGESH FB32 # HEBREW LETTER GIMEL WITH DAGESH FB33 # HEBREW LETTER DALET WITH DAGESH FB34 # HEBREW LETTER HE WITH MAPIQ FB35 # HEBREW LETTER VAV WITH DAGESH FB36 # HEBREW LETTER ZAYIN WITH DAGESH FB38 # HEBREW LETTER TET WITH DAGESH FB39 # HEBREW LETTER YOD WITH DAGESH FB3A # HEBREW LETTER FINAL KAF WITH DAGESH FB3B # HEBREW LETTER KAF WITH DAGESH FB3C # HEBREW LETTER LAMED WITH DAGESH FB3E # HEBREW LETTER MEM WITH DAGESH FB40 # HEBREW LETTER NUN WITH DAGESH FB41 # HEBREW LETTER SAMEKH WITH DAGESH FB43 # HEBREW LETTER FINAL PE WITH DAGESH FB44 # HEBREW LETTER PE WITH DAGESH FB46 # HEBREW LETTER TSADI WITH DAGESH FB47 # HEBREW LETTER QOF WITH DAGESH FB48 # HEBREW LETTER RESH WITH DAGESH FB49 # HEBREW LETTER SHIN WITH DAGESH FB4A # HEBREW LETTER TAV WITH DAGESH FB4B # HEBREW LETTER VAV WITH HOLAM FB4C # HEBREW LETTER BET WITH RAFE FB4D # HEBREW LETTER KAF WITH RAFE FB4E # HEBREW LETTER PE WITH RAFE # Total code points: 67 # ================================================ # (2) Post Composition Version precomposed characters # These characters cannot be derived solely from the UnicodeData.txt file # in this version of Unicode. # ================================================ 2ADC # FORKING 1D15E # MUSICAL SYMBOL HALF NOTE 1D15F # MUSICAL SYMBOL QUARTER NOTE 1D160 # MUSICAL SYMBOL EIGHTH NOTE 1D161 # MUSICAL SYMBOL SIXTEENTH NOTE 1D162 # MUSICAL SYMBOL THIRTY-SECOND NOTE 1D163 # MUSICAL SYMBOL SIXTY-FOURTH NOTE 1D164 # MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE 1D1BB # MUSICAL SYMBOL MINIMA 1D1BC # MUSICAL SYMBOL MINIMA BLACK 1D1BD # MUSICAL SYMBOL SEMIMINIMA WHITE 1D1BE # MUSICAL SYMBOL SEMIMINIMA BLACK 1D1BF # MUSICAL SYMBOL FUSA WHITE 1D1C0 # MUSICAL SYMBOL FUSA BLACK # Total code points: 14 # ================================================ # (3) Singleton Decompositions # These characters can be derived from the UnicodeData file # by including all characters whose canonical decomposition # consists of a single character. # These characters are simply quoted here for reference. # ================================================ # 0340..0341 [2] COMBINING GRAVE TONE MARK..COMBINING ACUTE TONE MARK # 0343 COMBINING GREEK KORONIS # 0374 GREEK NUMERAL SIGN # 037E GREEK QUESTION MARK # 0387 GREEK ANO TELEIA # 1F71 GREEK SMALL LETTER ALPHA WITH OXIA # 1F73 GREEK SMALL LETTER EPSILON WITH OXIA # 1F75 GREEK SMALL LETTER ETA WITH OXIA # 1F77 GREEK SMALL LETTER IOTA WITH OXIA # 1F79 GREEK SMALL LETTER OMICRON WITH OXIA # 1F7B GREEK SMALL LETTER UPSILON WITH OXIA # 1F7D GREEK SMALL LETTER OMEGA WITH OXIA # 1FBB GREEK CAPITAL LETTER ALPHA WITH OXIA # 1FBE GREEK PROSGEGRAMMENI # 1FC9 GREEK CAPITAL LETTER EPSILON WITH OXIA # 1FCB GREEK CAPITAL LETTER ETA WITH OXIA # 1FD3 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA # 1FDB GREEK CAPITAL LETTER IOTA WITH OXIA # 1FE3 GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA # 1FEB GREEK CAPITAL LETTER UPSILON WITH OXIA # 1FEE..1FEF [2] GREEK DIALYTIKA AND OXIA..GREEK VARIA # 1FF9 GREEK CAPITAL LETTER OMICRON WITH OXIA # 1FFB GREEK CAPITAL LETTER OMEGA WITH OXIA # 1FFD GREEK OXIA # 2000..2001 [2] EN QUAD..EM QUAD # 2126 OHM SIGN # 212A..212B [2] KELVIN SIGN..ANGSTROM SIGN # 2329 LEFT-POINTING ANGLE BRACKET # 232A RIGHT-POINTING ANGLE BRACKET # F900..FA0D [270] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA0D # FA10 CJK COMPATIBILITY IDEOGRAPH-FA10 # FA12 CJK COMPATIBILITY IDEOGRAPH-FA12 # FA15..FA1E [10] CJK COMPATIBILITY IDEOGRAPH-FA15..CJK COMPATIBILITY IDEOGRAPH-FA1E # FA20 CJK COMPATIBILITY IDEOGRAPH-FA20 # FA22 CJK COMPATIBILITY IDEOGRAPH-FA22 # FA25..FA26 [2] CJK COMPATIBILITY IDEOGRAPH-FA25..CJK COMPATIBILITY IDEOGRAPH-FA26 # FA2A..FA2D [4] CJK COMPATIBILITY IDEOGRAPH-FA2A..CJK COMPATIBILITY IDEOGRAPH-FA2D # FA30..FA6A [59] CJK COMPATIBILITY IDEOGRAPH-FA30..CJK COMPATIBILITY IDEOGRAPH-FA6A # 2F800..2FA1D [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D # Total code points: 924 # ================================================ # (4) Non-Starter Decompositions # These characters can be derived from the UnicodeData file # by including all characters whose canonical decomposition consists # of a sequence of characters, the first of which has a non-zero # combining class. # These characters are simply quoted here for reference. # ================================================ # 0344 COMBINING GREEK DIALYTIKA TONOS # 0F73 TIBETAN VOWEL SIGN II # 0F75 TIBETAN VOWEL SIGN UU # 0F81 TIBETAN VOWEL SIGN REVERSED II # Total code points: 4 openldap-2.5.11+dfsg/libraries/liblunicode/ucstr.c0000644000175000017500000002315514172327167020616 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include #include #define malloc(x) ber_memalloc_x(x,ctx) #define realloc(x,y) ber_memrealloc_x(x,y,ctx) #define free(x) ber_memfree_x(x,ctx) int ucstrncmp( const ldap_unicode_t *u1, const ldap_unicode_t *u2, ber_len_t n ) { for(; 0 < n; ++u1, ++u2, --n ) { if( *u1 != *u2 ) { return *u1 < *u2 ? -1 : +1; } if ( *u1 == 0 ) { return 0; } } return 0; } int ucstrncasecmp( const ldap_unicode_t *u1, const ldap_unicode_t *u2, ber_len_t n ) { for(; 0 < n; ++u1, ++u2, --n ) { ldap_unicode_t uu1 = uctolower( *u1 ); ldap_unicode_t uu2 = uctolower( *u2 ); if( uu1 != uu2 ) { return uu1 < uu2 ? -1 : +1; } if ( uu1 == 0 ) { return 0; } } return 0; } ldap_unicode_t * ucstrnchr( const ldap_unicode_t *u, ber_len_t n, ldap_unicode_t c ) { for(; 0 < n; ++u, --n ) { if( *u == c ) { return (ldap_unicode_t *) u; } } return NULL; } ldap_unicode_t * ucstrncasechr( const ldap_unicode_t *u, ber_len_t n, ldap_unicode_t c ) { c = uctolower( c ); for(; 0 < n; ++u, --n ) { if( uctolower( *u ) == c ) { return (ldap_unicode_t *) u; } } return NULL; } void ucstr2upper( ldap_unicode_t *u, ber_len_t n ) { for(; 0 < n; ++u, --n ) { *u = uctoupper( *u ); } } struct berval * UTF8bvnormalize( struct berval *bv, struct berval *newbv, unsigned flags, void *ctx ) { int i, j, len, clen, outpos, ucsoutlen, outsize, last; int didnewbv = 0; char *out, *outtmp, *s; ac_uint4 *ucs, *p, *ucsout; static unsigned char mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; unsigned casefold = flags & LDAP_UTF8_CASEFOLD; unsigned approx = flags & LDAP_UTF8_APPROX; if ( bv == NULL ) { return NULL; } s = bv->bv_val; len = bv->bv_len; if ( len == 0 ) { return ber_dupbv_x( newbv, bv, ctx ); } if ( !newbv ) { newbv = ber_memalloc_x( sizeof(struct berval), ctx ); if ( !newbv ) return NULL; didnewbv = 1; } /* Should first check to see if string is already in proper * normalized form. This is almost as time consuming as * the normalization though. */ /* finish off everything up to character before first non-ascii */ if ( LDAP_UTF8_ISASCII( s ) ) { if ( casefold ) { outsize = len + 7; out = (char *) ber_memalloc_x( outsize, ctx ); if ( out == NULL ) { fail: if ( didnewbv ) ber_memfree_x( newbv, ctx ); return NULL; } outpos = 0; for ( i = 1; (i < len) && LDAP_UTF8_ISASCII(s + i); i++ ) { out[outpos++] = TOLOWER( s[i-1] ); } if ( i == len ) { out[outpos++] = TOLOWER( s[len-1] ); out[outpos] = '\0'; newbv->bv_val = out; newbv->bv_len = outpos; return newbv; } } else { for ( i = 1; (i < len) && LDAP_UTF8_ISASCII(s + i); i++ ) { /* empty */ } if ( i == len ) { return ber_str2bv_x( s, len, 1, newbv, ctx ); } outsize = len + 7; out = (char *) ber_memalloc_x( outsize, ctx ); if ( out == NULL ) { goto fail; } outpos = i - 1; memcpy(out, s, outpos); } } else { outsize = len + 7; out = (char *) ber_memalloc_x( outsize, ctx ); if ( out == NULL ) { goto fail; } outpos = 0; i = 0; } p = ucs = ber_memalloc_x( len * sizeof(*ucs), ctx ); if ( ucs == NULL ) { ber_memfree_x(out, ctx); goto fail; } /* convert character before first non-ascii to ucs-4 */ if ( i > 0 ) { *p = casefold ? TOLOWER( s[i-1] ) : s[i-1]; p++; } /* s[i] is now first non-ascii character */ for (;;) { /* s[i] is non-ascii */ /* convert everything up to next ascii to ucs-4 */ while ( i < len ) { clen = LDAP_UTF8_CHARLEN2( s + i, clen ); if ( clen == 0 ) { ber_memfree_x( ucs, ctx ); ber_memfree_x( out, ctx ); goto fail; } if ( clen == 1 ) { /* ascii */ break; } *p = s[i] & mask[clen]; i++; for( j = 1; j < clen; j++ ) { if ( (s[i] & 0xc0) != 0x80 ) { ber_memfree_x( ucs, ctx ); ber_memfree_x( out, ctx ); goto fail; } *p <<= 6; *p |= s[i] & 0x3f; i++; } if ( casefold ) { *p = uctolower( *p ); } p++; } /* normalize ucs of length p - ucs */ uccompatdecomp( ucs, p - ucs, &ucsout, &ucsoutlen, ctx ); if ( approx ) { for ( j = 0; j < ucsoutlen; j++ ) { if ( ucsout[j] < 0x80 ) { out[outpos++] = ucsout[j]; } } } else { ucsoutlen = uccanoncomp( ucsout, ucsoutlen ); /* convert ucs to utf-8 and store in out */ for ( j = 0; j < ucsoutlen; j++ ) { /* allocate more space if not enough room for 6 bytes and terminator */ if ( outsize - outpos < 7 ) { outsize = ucsoutlen - j + outpos + 6; outtmp = (char *) ber_memrealloc_x( out, outsize, ctx ); if ( outtmp == NULL ) { ber_memfree_x( ucsout, ctx ); ber_memfree_x( ucs, ctx ); ber_memfree_x( out, ctx ); goto fail; } out = outtmp; } outpos += ldap_x_ucs4_to_utf8( ucsout[j], &out[outpos] ); } } ber_memfree_x( ucsout, ctx ); ucsout = NULL; if ( i == len ) { break; } last = i; /* Allocate more space in out if necessary */ if (len - i >= outsize - outpos) { outsize += 1 + ((len - i) - (outsize - outpos)); outtmp = (char *) ber_memrealloc_x(out, outsize, ctx); if (outtmp == NULL) { ber_memfree_x( ucs, ctx ); ber_memfree_x( out, ctx ); goto fail; } out = outtmp; } /* s[i] is ascii */ /* finish off everything up to char before next non-ascii */ for ( i++; (i < len) && LDAP_UTF8_ISASCII(s + i); i++ ) { out[outpos++] = casefold ? TOLOWER( s[i-1] ) : s[i-1]; } if ( i == len ) { out[outpos++] = casefold ? TOLOWER( s[len-1] ) : s[len-1]; break; } /* convert character before next non-ascii to ucs-4 */ *ucs = casefold ? TOLOWER( s[i-1] ) : s[i-1]; p = ucs + 1; } ber_memfree_x( ucs, ctx ); out[outpos] = '\0'; newbv->bv_val = out; newbv->bv_len = outpos; return newbv; } /* compare UTF8-strings, optionally ignore casing */ /* slow, should be optimized */ int UTF8bvnormcmp( struct berval *bv1, struct berval *bv2, unsigned flags, void *ctx ) { int i, l1, l2, len, ulen, res = 0; char *s1, *s2, *done; ac_uint4 *ucs, *ucsout1, *ucsout2; unsigned casefold = flags & LDAP_UTF8_CASEFOLD; unsigned norm1 = flags & LDAP_UTF8_ARG1NFC; unsigned norm2 = flags & LDAP_UTF8_ARG2NFC; if (bv1 == NULL) { return bv2 == NULL ? 0 : -1; } else if (bv2 == NULL) { return 1; } l1 = bv1->bv_len; l2 = bv2->bv_len; len = (l1 < l2) ? l1 : l2; if (len == 0) { return l1 == 0 ? (l2 == 0 ? 0 : -1) : 1; } s1 = bv1->bv_val; s2 = bv2->bv_val; done = s1 + len; while ( (s1 < done) && LDAP_UTF8_ISASCII(s1) && LDAP_UTF8_ISASCII(s2) ) { if (casefold) { char c1 = TOLOWER(*s1); char c2 = TOLOWER(*s2); res = c1 - c2; } else { res = *s1 - *s2; } s1++; s2++; if (res) { /* done unless next character in s1 or s2 is non-ascii */ if (s1 < done) { if (!LDAP_UTF8_ISASCII(s1) || !LDAP_UTF8_ISASCII(s2)) { break; } } else if (((len < l1) && !LDAP_UTF8_ISASCII(s1)) || ((len < l2) && !LDAP_UTF8_ISASCII(s2))) { break; } return res; } } /* We have encountered non-ascii or strings equal up to len */ /* set i to number of iterations */ i = s1 - done + len; /* passed through loop at least once? */ if (i > 0) { if (!res && (s1 == done) && ((len == l1) || LDAP_UTF8_ISASCII(s1)) && ((len == l2) || LDAP_UTF8_ISASCII(s2))) { /* all ascii and equal up to len */ return l1 - l2; } /* rewind one char, and do normalized compare from there */ s1--; s2--; l1 -= i - 1; l2 -= i - 1; } /* Should first check to see if strings are already in * proper normalized form. */ ucs = malloc( ( ( norm1 || l1 > l2 ) ? l1 : l2 ) * sizeof(*ucs) ); if ( ucs == NULL ) { return l1 > l2 ? 1 : -1; /* what to do??? */ } /* * XXYYZ: we convert to ucs4 even though -llunicode * expects ucs2 in an ac_uint4 */ /* convert and normalize 1st string */ for ( i = 0, ulen = 0; i < l1; i += len, ulen++ ) { ucs[ulen] = ldap_x_utf8_to_ucs4( s1 + i ); if ( ucs[ulen] == LDAP_UCS4_INVALID ) { free( ucs ); return -1; /* what to do??? */ } len = LDAP_UTF8_CHARLEN( s1 + i ); } if ( norm1 ) { ucsout1 = ucs; l1 = ulen; ucs = malloc( l2 * sizeof(*ucs) ); if ( ucs == NULL ) { free( ucsout1 ); return l1 > l2 ? 1 : -1; /* what to do??? */ } } else { uccompatdecomp( ucs, ulen, &ucsout1, &l1, ctx ); l1 = uccanoncomp( ucsout1, l1 ); } /* convert and normalize 2nd string */ for ( i = 0, ulen = 0; i < l2; i += len, ulen++ ) { ucs[ulen] = ldap_x_utf8_to_ucs4( s2 + i ); if ( ucs[ulen] == LDAP_UCS4_INVALID ) { free( ucsout1 ); free( ucs ); return 1; /* what to do??? */ } len = LDAP_UTF8_CHARLEN( s2 + i ); } if ( norm2 ) { ucsout2 = ucs; l2 = ulen; } else { uccompatdecomp( ucs, ulen, &ucsout2, &l2, ctx ); l2 = uccanoncomp( ucsout2, l2 ); free( ucs ); } res = casefold ? ucstrncasecmp( ucsout1, ucsout2, l1 < l2 ? l1 : l2 ) : ucstrncmp( ucsout1, ucsout2, l1 < l2 ? l1 : l2 ); free( ucsout1 ); free( ucsout2 ); if ( res != 0 ) { return res; } if ( l1 == l2 ) { return 0; } return l1 > l2 ? 1 : -1; } openldap-2.5.11+dfsg/build/0000755000175000017500000000000014172327167014136 5ustar ryanryanopenldap-2.5.11+dfsg/build/ltmain.sh0000755000175000017500000117077114172327167015777 0ustar ryanryan#! /bin/sh ## DO NOT EDIT - This file generated from ./build-aux/ltmain.in ## by inline-source v2014-01-03.01 # libtool (GNU libtool) 2.4.6 # Provide generalized library-building support services. # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996-2015 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . PROGRAM=libtool PACKAGE=libtool VERSION=2.4.6 package_revision=2.4.6 ## ------ ## ## Usage. ## ## ------ ## # Run './libtool --help' for help with using this script from the # command line. ## ------------------------------- ## ## User overridable command paths. ## ## ------------------------------- ## # After configure completes, it has a better idea of some of the # shell tools we need than the defaults used by the functions shared # with bootstrap, so set those here where they can still be over- # ridden by the user, but otherwise take precedence. : ${AUTOCONF="autoconf"} : ${AUTOMAKE="automake"} ## -------------------------- ## ## Source external libraries. ## ## -------------------------- ## # Much of our low-level functionality needs to be sourced from external # libraries, which are installed to $pkgauxdir. # Set a version string for this script. scriptversion=2015-01-20.17; # UTC # General shell script boiler plate, and helper functions. # Written by Gary V. Vaughan, 2004 # Copyright (C) 2004-2015 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # As a special exception to the GNU General Public License, if you distribute # this file as part of a program or library that is built using GNU Libtool, # you may include this file under the same distribution terms that you use # for the rest of that program. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Please report bugs or propose patches to gary@gnu.org. ## ------ ## ## Usage. ## ## ------ ## # Evaluate this file near the top of your script to gain access to # the functions and variables defined here: # # . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh # # If you need to override any of the default environment variable # settings, do that before evaluating this file. ## -------------------- ## ## Shell normalisation. ## ## -------------------- ## # Some shells need a little help to be as Bourne compatible as possible. # Before doing anything else, make sure all that help has been provided! DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # NLS nuisances: We save the old values in case they are required later. _G_user_locale= _G_safe_locale= for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test set = \"\${$_G_var+set}\"; then save_$_G_var=\$$_G_var $_G_var=C export $_G_var _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\" _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" fi" done # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Make sure IFS has a sensible default sp=' ' nl=' ' IFS="$sp $nl" # There are apparently some retarded systems that use ';' as a PATH separator! if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi ## ------------------------- ## ## Locate command utilities. ## ## ------------------------- ## # func_executable_p FILE # ---------------------- # Check that FILE is an executable regular file. func_executable_p () { test -f "$1" && test -x "$1" } # func_path_progs PROGS_LIST CHECK_FUNC [PATH] # -------------------------------------------- # Search for either a program that responds to --version with output # containing "GNU", or else returned by CHECK_FUNC otherwise, by # trying all the directories in PATH with each of the elements of # PROGS_LIST. # # CHECK_FUNC should accept the path to a candidate program, and # set $func_check_prog_result if it truncates its output less than # $_G_path_prog_max characters. func_path_progs () { _G_progs_list=$1 _G_check_func=$2 _G_PATH=${3-"$PATH"} _G_path_prog_max=0 _G_path_prog_found=false _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:} for _G_dir in $_G_PATH; do IFS=$_G_save_IFS test -z "$_G_dir" && _G_dir=. for _G_prog_name in $_G_progs_list; do for _exeext in '' .EXE; do _G_path_prog=$_G_dir/$_G_prog_name$_exeext func_executable_p "$_G_path_prog" || continue case `"$_G_path_prog" --version 2>&1` in *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;; *) $_G_check_func $_G_path_prog func_path_progs_result=$func_check_prog_result ;; esac $_G_path_prog_found && break 3 done done done IFS=$_G_save_IFS test -z "$func_path_progs_result" && { echo "no acceptable sed could be found in \$PATH" >&2 exit 1 } } # We want to be able to use the functions in this file before configure # has figured out where the best binaries are kept, which means we have # to search for them ourselves - except when the results are already set # where we skip the searches. # Unless the user overrides by setting SED, search the path for either GNU # sed, or the sed that truncates its output the least. test -z "$SED" && { _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for _G_i in 1 2 3 4 5 6 7; do _G_sed_script=$_G_sed_script$nl$_G_sed_script done echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed _G_sed_script= func_check_prog_sed () { _G_path_prog=$1 _G_count=0 printf 0123456789 >conftest.in while : do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo '' >> conftest.nl "$_G_path_prog" -f conftest.sed conftest.out 2>/dev/null || break diff conftest.out conftest.nl >/dev/null 2>&1 || break _G_count=`expr $_G_count + 1` if test "$_G_count" -gt "$_G_path_prog_max"; then # Best one so far, save it but keep looking for a better one func_check_prog_result=$_G_path_prog _G_path_prog_max=$_G_count fi # 10*(2^10) chars as input seems more than enough test 10 -lt "$_G_count" && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out } func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin rm -f conftest.sed SED=$func_path_progs_result } # Unless the user overrides by setting GREP, search the path for either GNU # grep, or the grep that truncates its output the least. test -z "$GREP" && { func_check_prog_grep () { _G_path_prog=$1 _G_count=0 _G_path_prog_max=0 printf 0123456789 >conftest.in while : do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo 'GREP' >> conftest.nl "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' conftest.out 2>/dev/null || break diff conftest.out conftest.nl >/dev/null 2>&1 || break _G_count=`expr $_G_count + 1` if test "$_G_count" -gt "$_G_path_prog_max"; then # Best one so far, save it but keep looking for a better one func_check_prog_result=$_G_path_prog _G_path_prog_max=$_G_count fi # 10*(2^10) chars as input seems more than enough test 10 -lt "$_G_count" && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out } func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin GREP=$func_path_progs_result } ## ------------------------------- ## ## User overridable command paths. ## ## ------------------------------- ## # All uppercase variable names are used for environment variables. These # variables can be overridden by the user before calling a script that # uses them if a suitable command of that name is not already available # in the command search PATH. : ${CP="cp -f"} : ${ECHO="printf %s\n"} : ${EGREP="$GREP -E"} : ${FGREP="$GREP -F"} : ${LN_S="ln -s"} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} ## -------------------- ## ## Useful sed snippets. ## ## -------------------- ## sed_dirname='s|/[^/]*$||' sed_basename='s|^.*/||' # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='s|\([`"$\\]\)|\\\1|g' # Same as above, but do not quote variable references. sed_double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g' # Sed substitution that converts a w32 file name or path # that contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-'\' parameter expansions in output of sed_double_quote_subst that # were '\'-ed in input to the same. If an odd number of '\' preceded a # '$' in input to sed_double_quote_subst, that '$' was protected from # expansion. Since each input '\' is now two '\'s, look for any number # of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'. _G_bs='\\' _G_bs2='\\\\' _G_bs4='\\\\\\\\' _G_dollar='\$' sed_double_backslash="\ s/$_G_bs4/&\\ /g s/^$_G_bs2$_G_dollar/$_G_bs&/ s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g s/\n//g" ## ----------------- ## ## Global variables. ## ## ----------------- ## # Except for the global variables explicitly listed below, the following # functions in the '^func_' namespace, and the '^require_' namespace # variables initialised in the 'Resource management' section, sourcing # this file will not pollute your global namespace with anything # else. There's no portable way to scope variables in Bourne shell # though, so actually running these functions will sometimes place # results into a variable named after the function, and often use # temporary variables in the '^_G_' namespace. If you are careful to # avoid using those namespaces casually in your sourcing script, things # should continue to work as you expect. And, of course, you can freely # overwrite any of the functions or variables defined here before # calling anything to customize them. EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. # Allow overriding, eg assuming that you follow the convention of # putting '$debug_cmd' at the start of all your functions, you can get # bash to show function call trace with: # # debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name debug_cmd=${debug_cmd-":"} exit_cmd=: # By convention, finish your script with: # # exit $exit_status # # so that you can set exit_status to non-zero if you want to indicate # something went wrong during execution without actually bailing out at # the point of failure. exit_status=$EXIT_SUCCESS # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath=$0 # The name of this program. progname=`$ECHO "$progpath" |$SED "$sed_basename"` # Make sure we have an absolute progpath for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=`$ECHO "$progpath" |$SED "$sed_dirname"` progdir=`cd "$progdir" && pwd` progpath=$progdir/$progname ;; *) _G_IFS=$IFS IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS=$_G_IFS test -x "$progdir/$progname" && break done IFS=$_G_IFS test -n "$progdir" || progdir=`pwd` progpath=$progdir/$progname ;; esac ## ----------------- ## ## Standard options. ## ## ----------------- ## # The following options affect the operation of the functions defined # below, and should be set appropriately depending on run-time para- # meters passed on the command line. opt_dry_run=false opt_quiet=false opt_verbose=false # Categories 'all' and 'none' are always available. Append any others # you will pass as the first argument to func_warning from your own # code. warning_categories= # By default, display warnings according to 'opt_warning_types'. Set # 'warning_func' to ':' to elide all warnings, or func_fatal_error to # treat the next displayed warning as a fatal error. warning_func=func_warn_and_continue # Set to 'all' to display all warnings, 'none' to suppress all # warnings, or a space delimited list of some subset of # 'warning_categories' to display only the listed warnings. opt_warning_types=all ## -------------------- ## ## Resource management. ## ## -------------------- ## # This section contains definitions for functions that each ensure a # particular resource (a file, or a non-empty configuration variable for # example) is available, and if appropriate to extract default values # from pertinent package files. Call them using their associated # 'require_*' variable to ensure that they are executed, at most, once. # # It's entirely deliberate that calling these functions can set # variables that don't obey the namespace limitations obeyed by the rest # of this file, in order that that they be as useful as possible to # callers. # require_term_colors # ------------------- # Allow display of bold text on terminals that support it. require_term_colors=func_require_term_colors func_require_term_colors () { $debug_cmd test -t 1 && { # COLORTERM and USE_ANSI_COLORS environment variables take # precedence, because most terminfo databases neglect to describe # whether color sequences are supported. test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"} if test 1 = "$USE_ANSI_COLORS"; then # Standard ANSI escape sequences tc_reset='' tc_bold=''; tc_standout='' tc_red=''; tc_green='' tc_blue=''; tc_cyan='' else # Otherwise trust the terminfo database after all. test -n "`tput sgr0 2>/dev/null`" && { tc_reset=`tput sgr0` test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold` tc_standout=$tc_bold test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso` test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1` test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2` test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4` test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5` } fi } require_term_colors=: } ## ----------------- ## ## Function library. ## ## ----------------- ## # This section contains a variety of useful functions to call in your # scripts. Take note of the portable wrappers for features provided by # some modern shells, which will fall back to slower equivalents on # less featureful shells. # func_append VAR VALUE # --------------------- # Append VALUE onto the existing contents of VAR. # We should try to minimise forks, especially on Windows where they are # unreasonably slow, so skip the feature probes when bash or zsh are # being used: if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then : ${_G_HAVE_ARITH_OP="yes"} : ${_G_HAVE_XSI_OPS="yes"} # The += operator was introduced in bash 3.1 case $BASH_VERSION in [12].* | 3.0 | 3.0*) ;; *) : ${_G_HAVE_PLUSEQ_OP="yes"} ;; esac fi # _G_HAVE_PLUSEQ_OP # Can be empty, in which case the shell is probed, "yes" if += is # useable or anything else if it does not work. test -z "$_G_HAVE_PLUSEQ_OP" \ && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \ && _G_HAVE_PLUSEQ_OP=yes if test yes = "$_G_HAVE_PLUSEQ_OP" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_append () { $debug_cmd eval "$1+=\$2" }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_append () { $debug_cmd eval "$1=\$$1\$2" } fi # func_append_quoted VAR VALUE # ---------------------------- # Quote VALUE and append to the end of shell variable VAR, separated # by a space. if test yes = "$_G_HAVE_PLUSEQ_OP"; then eval 'func_append_quoted () { $debug_cmd func_quote_for_eval "$2" eval "$1+=\\ \$func_quote_for_eval_result" }' else func_append_quoted () { $debug_cmd func_quote_for_eval "$2" eval "$1=\$$1\\ \$func_quote_for_eval_result" } fi # func_append_uniq VAR VALUE # -------------------------- # Append unique VALUE onto the existing contents of VAR, assuming # entries are delimited by the first character of VALUE. For example: # # func_append_uniq options " --another-option option-argument" # # will only append to $options if " --another-option option-argument " # is not already present somewhere in $options already (note spaces at # each end implied by leading space in second argument). func_append_uniq () { $debug_cmd eval _G_current_value='`$ECHO $'$1'`' _G_delim=`expr "$2" : '\(.\)'` case $_G_delim$_G_current_value$_G_delim in *"$2$_G_delim"*) ;; *) func_append "$@" ;; esac } # func_arith TERM... # ------------------ # Set func_arith_result to the result of evaluating TERMs. test -z "$_G_HAVE_ARITH_OP" \ && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \ && _G_HAVE_ARITH_OP=yes if test yes = "$_G_HAVE_ARITH_OP"; then eval 'func_arith () { $debug_cmd func_arith_result=$(( $* )) }' else func_arith () { $debug_cmd func_arith_result=`expr "$@"` } fi # func_basename FILE # ------------------ # Set func_basename_result to FILE with everything up to and including # the last / stripped. if test yes = "$_G_HAVE_XSI_OPS"; then # If this shell supports suffix pattern removal, then use it to avoid # forking. Hide the definitions single quotes in case the shell chokes # on unsupported syntax... _b='func_basename_result=${1##*/}' _d='case $1 in */*) func_dirname_result=${1%/*}$2 ;; * ) func_dirname_result=$3 ;; esac' else # ...otherwise fall back to using sed. _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`' _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"` if test "X$func_dirname_result" = "X$1"; then func_dirname_result=$3 else func_append func_dirname_result "$2" fi' fi eval 'func_basename () { $debug_cmd '"$_b"' }' # func_dirname FILE APPEND NONDIR_REPLACEMENT # ------------------------------------------- # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. eval 'func_dirname () { $debug_cmd '"$_d"' }' # func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT # -------------------------------------------------------- # Perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # For efficiency, we do not delegate to the functions above but instead # duplicate the functionality here. eval 'func_dirname_and_basename () { $debug_cmd '"$_b"' '"$_d"' }' # func_echo ARG... # ---------------- # Echo program name prefixed message. func_echo () { $debug_cmd _G_message=$* func_echo_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_IFS $ECHO "$progname: $_G_line" done IFS=$func_echo_IFS } # func_echo_all ARG... # -------------------- # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_echo_infix_1 INFIX ARG... # ------------------------------ # Echo program name, followed by INFIX on the first line, with any # additional lines not showing INFIX. func_echo_infix_1 () { $debug_cmd $require_term_colors _G_infix=$1; shift _G_indent=$_G_infix _G_prefix="$progname: $_G_infix: " _G_message=$* # Strip color escape sequences before counting printable length for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan" do test -n "$_G_tc" && { _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"` _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"` } done _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes func_echo_infix_1_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_infix_1_IFS $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2 _G_prefix=$_G_indent done IFS=$func_echo_infix_1_IFS } # func_error ARG... # ----------------- # Echo program name prefixed message to standard error. func_error () { $debug_cmd $require_term_colors func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2 } # func_fatal_error ARG... # ----------------------- # Echo program name prefixed message to standard error, and exit. func_fatal_error () { $debug_cmd func_error "$*" exit $EXIT_FAILURE } # func_grep EXPRESSION FILENAME # ----------------------------- # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $debug_cmd $GREP "$1" "$2" >/dev/null 2>&1 } # func_len STRING # --------------- # Set func_len_result to the length of STRING. STRING may not # start with a hyphen. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ && _G_HAVE_XSI_OPS=yes if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_len () { $debug_cmd func_len_result=${#1} }' else func_len () { $debug_cmd func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` } fi # func_mkdir_p DIRECTORY-PATH # --------------------------- # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { $debug_cmd _G_directory_path=$1 _G_dir_list= if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then # Protect directory names starting with '-' case $_G_directory_path in -*) _G_directory_path=./$_G_directory_path ;; esac # While some portion of DIR does not yet exist... while test ! -d "$_G_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. _G_dir_list=$_G_directory_path:$_G_dir_list # If the last portion added has no slash in it, the list is done case $_G_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"` done _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'` func_mkdir_p_IFS=$IFS; IFS=: for _G_dir in $_G_dir_list; do IFS=$func_mkdir_p_IFS # mkdir can fail with a 'File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$_G_dir" 2>/dev/null || : done IFS=$func_mkdir_p_IFS # Bail out if we (or some other process) failed to create a directory. test -d "$_G_directory_path" || \ func_fatal_error "Failed to create '$1'" fi } # func_mktempdir [BASENAME] # ------------------------- # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, BASENAME is the basename for that directory. func_mktempdir () { $debug_cmd _G_template=${TMPDIR-/tmp}/${1-$progname} if test : = "$opt_dry_run"; then # Return a directory name, but don't create it in dry-run mode _G_tmpdir=$_G_template-$$ else # If mktemp works, use that first and foremost _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null` if test ! -d "$_G_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race _G_tmpdir=$_G_template-${RANDOM-0}$$ func_mktempdir_umask=`umask` umask 0077 $MKDIR "$_G_tmpdir" umask $func_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$_G_tmpdir" || \ func_fatal_error "cannot create temporary directory '$_G_tmpdir'" fi $ECHO "$_G_tmpdir" } # func_normal_abspath PATH # ------------------------ # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. func_normal_abspath () { $debug_cmd # These SED scripts presuppose an absolute path with a trailing slash. _G_pathcar='s|^/\([^/]*\).*$|\1|' _G_pathcdr='s|^/[^/]*||' _G_removedotparts=':dotsl s|/\./|/|g t dotsl s|/\.$|/|' _G_collapseslashes='s|/\{1,\}|/|g' _G_finalslash='s|/*$|/|' # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"` while :; do # Processed it all yet? if test / = "$func_normal_abspath_tpath"; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result"; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent" ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_notquiet ARG... # -------------------- # Echo program name prefixed message only when not in quiet mode. func_notquiet () { $debug_cmd $opt_quiet || func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_relative_path SRCDIR DSTDIR # -------------------------------- # Set func_relative_path_result to the relative path from SRCDIR to DSTDIR. func_relative_path () { $debug_cmd func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=$func_dirname_result if test -z "$func_relative_path_tlibdir"; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test -n "$func_stripname_result"; then func_append func_relative_path_result "/$func_stripname_result" fi # Normalisation. If bindir is libdir, return '.' else relative path. if test -n "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result" func_relative_path_result=$func_stripname_result fi test -n "$func_relative_path_result" || func_relative_path_result=. : } # func_quote_for_eval ARG... # -------------------------- # Aesthetically quote ARGs to be evaled later. # This function returns two values: # i) func_quote_for_eval_result # double-quoted, suitable for a subsequent eval # ii) func_quote_for_eval_unquoted_result # has all characters that are still active within double # quotes backslashified. func_quote_for_eval () { $debug_cmd func_quote_for_eval_unquoted_result= func_quote_for_eval_result= while test 0 -lt $#; do case $1 in *[\\\`\"\$]*) _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;; *) _G_unquoted_arg=$1 ;; esac if test -n "$func_quote_for_eval_unquoted_result"; then func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg" else func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg" fi case $_G_unquoted_arg in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and variable expansion # for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") _G_quoted_arg=\"$_G_unquoted_arg\" ;; *) _G_quoted_arg=$_G_unquoted_arg ;; esac if test -n "$func_quote_for_eval_result"; then func_append func_quote_for_eval_result " $_G_quoted_arg" else func_append func_quote_for_eval_result "$_G_quoted_arg" fi shift done } # func_quote_for_expand ARG # ------------------------- # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { $debug_cmd case $1 in *[\\\`\"]*) _G_arg=`$ECHO "$1" | $SED \ -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;; *) _G_arg=$1 ;; esac case $_G_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") _G_arg=\"$_G_arg\" ;; esac func_quote_for_expand_result=$_G_arg } # func_stripname PREFIX SUFFIX NAME # --------------------------------- # strip PREFIX and SUFFIX from NAME, and store in func_stripname_result. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_stripname () { $debug_cmd # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary variable first. func_stripname_result=$3 func_stripname_result=${func_stripname_result#"$1"} func_stripname_result=${func_stripname_result%"$2"} }' else func_stripname () { $debug_cmd case $2 in .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;; *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;; esac } fi # func_show_eval CMD [FAIL_EXP] # ----------------------------- # Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { $debug_cmd _G_cmd=$1 _G_fail_exp=${2-':'} func_quote_for_expand "$_G_cmd" eval "func_notquiet $func_quote_for_expand_result" $opt_dry_run || { eval "$_G_cmd" _G_status=$? if test 0 -ne "$_G_status"; then eval "(exit $_G_status); $_G_fail_exp" fi } } # func_show_eval_locale CMD [FAIL_EXP] # ------------------------------------ # Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { $debug_cmd _G_cmd=$1 _G_fail_exp=${2-':'} $opt_quiet || { func_quote_for_expand "$_G_cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || { eval "$_G_user_locale $_G_cmd" _G_status=$? eval "$_G_safe_locale" if test 0 -ne "$_G_status"; then eval "(exit $_G_status); $_G_fail_exp" fi } } # func_tr_sh # ---------- # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { $debug_cmd case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_verbose ARG... # ------------------- # Echo program name prefixed message in verbose mode only. func_verbose () { $debug_cmd $opt_verbose && func_echo "$*" : } # func_warn_and_continue ARG... # ----------------------------- # Echo program name prefixed warning message to standard error. func_warn_and_continue () { $debug_cmd $require_term_colors func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2 } # func_warning CATEGORY ARG... # ---------------------------- # Echo program name prefixed warning message to standard error. Warning # messages can be filtered according to CATEGORY, where this function # elides messages where CATEGORY is not listed in the global variable # 'opt_warning_types'. func_warning () { $debug_cmd # CATEGORY must be in the warning_categories list! case " $warning_categories " in *" $1 "*) ;; *) func_internal_error "invalid warning category '$1'" ;; esac _G_category=$1 shift case " $opt_warning_types " in *" $_G_category "*) $warning_func ${1+"$@"} ;; esac } # func_sort_ver VER1 VER2 # ----------------------- # 'sort -V' is not generally available. # Note this deviates from the version comparison in automake # in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a # but this should suffice as we won't be specifying old # version formats or redundant trailing .0 in bootstrap.conf. # If we did want full compatibility then we should probably # use m4_version_compare from autoconf. func_sort_ver () { $debug_cmd printf '%s\n%s\n' "$1" "$2" \ | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n } # func_lt_ver PREV CURR # --------------------- # Return true if PREV and CURR are in the correct order according to # func_sort_ver, otherwise false. Use it like this: # # func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..." func_lt_ver () { $debug_cmd test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q` } # Local variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: #! /bin/sh # Set a version string for this script. scriptversion=2014-01-07.03; # UTC # A portable, pluggable option parser for Bourne shell. # Written by Gary V. Vaughan, 2010 # Copyright (C) 2010-2015 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Please report bugs or propose patches to gary@gnu.org. ## ------ ## ## Usage. ## ## ------ ## # This file is a library for parsing options in your shell scripts along # with assorted other useful supporting features that you can make use # of too. # # For the simplest scripts you might need only: # # #!/bin/sh # . relative/path/to/funclib.sh # . relative/path/to/options-parser # scriptversion=1.0 # func_options ${1+"$@"} # eval set dummy "$func_options_result"; shift # ...rest of your script... # # In order for the '--version' option to work, you will need to have a # suitably formatted comment like the one at the top of this file # starting with '# Written by ' and ending with '# warranty; '. # # For '-h' and '--help' to work, you will also need a one line # description of your script's purpose in a comment directly above the # '# Written by ' line, like the one at the top of this file. # # The default options also support '--debug', which will turn on shell # execution tracing (see the comment above debug_cmd below for another # use), and '--verbose' and the func_verbose function to allow your script # to display verbose messages only when your user has specified # '--verbose'. # # After sourcing this file, you can plug processing for additional # options by amending the variables from the 'Configuration' section # below, and following the instructions in the 'Option parsing' # section further down. ## -------------- ## ## Configuration. ## ## -------------- ## # You should override these variables in your script after sourcing this # file so that they reflect the customisations you have added to the # option parser. # The usage line for option parsing errors and the start of '-h' and # '--help' output messages. You can embed shell variables for delayed # expansion at the time the message is displayed, but you will need to # quote other shell meta-characters carefully to prevent them being # expanded when the contents are evaled. usage='$progpath [OPTION]...' # Short help message in response to '-h' and '--help'. Add to this or # override it after sourcing this library to reflect the full set of # options your script accepts. usage_message="\ --debug enable verbose shell tracing -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] -v, --verbose verbosely report processing --version print version information and exit -h, --help print short or long help message and exit " # Additional text appended to 'usage_message' in response to '--help'. long_help_message=" Warning categories include: 'all' show all warnings 'none' turn off all the warnings 'error' warnings are treated as fatal errors" # Help message printed before fatal option parsing errors. fatal_help="Try '\$progname --help' for more information." ## ------------------------- ## ## Hook function management. ## ## ------------------------- ## # This section contains functions for adding, removing, and running hooks # to the main code. A hook is just a named list of of function, that can # be run in order later on. # func_hookable FUNC_NAME # ----------------------- # Declare that FUNC_NAME will run hooks added with # 'func_add_hook FUNC_NAME ...'. func_hookable () { $debug_cmd func_append hookable_fns " $1" } # func_add_hook FUNC_NAME HOOK_FUNC # --------------------------------- # Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must # first have been declared "hookable" by a call to 'func_hookable'. func_add_hook () { $debug_cmd case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not accept hook functions." ;; esac eval func_append ${1}_hooks '" $2"' } # func_remove_hook FUNC_NAME HOOK_FUNC # ------------------------------------ # Remove HOOK_FUNC from the list of functions called by FUNC_NAME. func_remove_hook () { $debug_cmd eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`' } # func_run_hooks FUNC_NAME [ARG]... # --------------------------------- # Run all hook functions registered to FUNC_NAME. # It is assumed that the list of hook functions contains nothing more # than a whitespace-delimited list of legal shell function names, and # no effort is wasted trying to catch shell meta-characters or preserve # whitespace. func_run_hooks () { $debug_cmd case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not support hook funcions.n" ;; esac eval _G_hook_fns=\$$1_hooks; shift for _G_hook in $_G_hook_fns; do eval $_G_hook '"$@"' # store returned options list back into positional # parameters for next 'cmd' execution. eval _G_hook_result=\$${_G_hook}_result eval set dummy "$_G_hook_result"; shift done func_quote_for_eval ${1+"$@"} func_run_hooks_result=$func_quote_for_eval_result } ## --------------- ## ## Option parsing. ## ## --------------- ## # In order to add your own option parsing hooks, you must accept the # full positional parameter list in your hook function, remove any # options that you action, and then pass back the remaining unprocessed # options in '_result', escaped suitably for # 'eval'. Like this: # # my_options_prep () # { # $debug_cmd # # # Extend the existing usage message. # usage_message=$usage_message' # -s, --silent don'\''t print informational messages # ' # # func_quote_for_eval ${1+"$@"} # my_options_prep_result=$func_quote_for_eval_result # } # func_add_hook func_options_prep my_options_prep # # # my_silent_option () # { # $debug_cmd # # # Note that for efficiency, we parse as many options as we can # # recognise in a loop before passing the remainder back to the # # caller on the first unrecognised argument we encounter. # while test $# -gt 0; do # opt=$1; shift # case $opt in # --silent|-s) opt_silent=: ;; # # Separate non-argument short options: # -s*) func_split_short_opt "$_G_opt" # set dummy "$func_split_short_opt_name" \ # "-$func_split_short_opt_arg" ${1+"$@"} # shift # ;; # *) set dummy "$_G_opt" "$*"; shift; break ;; # esac # done # # func_quote_for_eval ${1+"$@"} # my_silent_option_result=$func_quote_for_eval_result # } # func_add_hook func_parse_options my_silent_option # # # my_option_validation () # { # $debug_cmd # # $opt_silent && $opt_verbose && func_fatal_help "\ # '--silent' and '--verbose' options are mutually exclusive." # # func_quote_for_eval ${1+"$@"} # my_option_validation_result=$func_quote_for_eval_result # } # func_add_hook func_validate_options my_option_validation # # You'll alse need to manually amend $usage_message to reflect the extra # options you parse. It's preferable to append if you can, so that # multiple option parsing hooks can be added safely. # func_options [ARG]... # --------------------- # All the functions called inside func_options are hookable. See the # individual implementations for details. func_hookable func_options func_options () { $debug_cmd func_options_prep ${1+"$@"} eval func_parse_options \ ${func_options_prep_result+"$func_options_prep_result"} eval func_validate_options \ ${func_parse_options_result+"$func_parse_options_result"} eval func_run_hooks func_options \ ${func_validate_options_result+"$func_validate_options_result"} # save modified positional parameters for caller func_options_result=$func_run_hooks_result } # func_options_prep [ARG]... # -------------------------- # All initialisations required before starting the option parse loop. # Note that when calling hook functions, we pass through the list of # positional parameters. If a hook function modifies that list, and # needs to propogate that back to rest of this script, then the complete # modified list must be put in 'func_run_hooks_result' before # returning. func_hookable func_options_prep func_options_prep () { $debug_cmd # Option defaults: opt_verbose=false opt_warning_types= func_run_hooks func_options_prep ${1+"$@"} # save modified positional parameters for caller func_options_prep_result=$func_run_hooks_result } # func_parse_options [ARG]... # --------------------------- # The main option parsing loop. func_hookable func_parse_options func_parse_options () { $debug_cmd func_parse_options_result= # this just eases exit handling while test $# -gt 0; do # Defer to hook functions for initial option parsing, so they # get priority in the event of reusing an option name. func_run_hooks func_parse_options ${1+"$@"} # Adjust func_parse_options positional parameters to match eval set dummy "$func_run_hooks_result"; shift # Break out of the loop if we already parsed every option. test $# -gt 0 || break _G_opt=$1 shift case $_G_opt in --debug|-x) debug_cmd='set -x' func_echo "enabling shell trace mode" $debug_cmd ;; --no-warnings|--no-warning|--no-warn) set dummy --warnings none ${1+"$@"} shift ;; --warnings|--warning|-W) test $# = 0 && func_missing_arg $_G_opt && break case " $warning_categories $1" in *" $1 "*) # trailing space prevents matching last $1 above func_append_uniq opt_warning_types " $1" ;; *all) opt_warning_types=$warning_categories ;; *none) opt_warning_types=none warning_func=: ;; *error) opt_warning_types=$warning_categories warning_func=func_fatal_error ;; *) func_fatal_error \ "unsupported warning category: '$1'" ;; esac shift ;; --verbose|-v) opt_verbose=: ;; --version) func_version ;; -\?|-h) func_usage ;; --help) func_help ;; # Separate optargs to long options (plugins may need this): --*=*) func_split_equals "$_G_opt" set dummy "$func_split_equals_lhs" \ "$func_split_equals_rhs" ${1+"$@"} shift ;; # Separate optargs to short options: -W*) func_split_short_opt "$_G_opt" set dummy "$func_split_short_opt_name" \ "$func_split_short_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-v*|-x*) func_split_short_opt "$_G_opt" set dummy "$func_split_short_opt_name" \ "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) break ;; -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; esac done # save modified positional parameters for caller func_quote_for_eval ${1+"$@"} func_parse_options_result=$func_quote_for_eval_result } # func_validate_options [ARG]... # ------------------------------ # Perform any sanity checks on option settings and/or unconsumed # arguments. func_hookable func_validate_options func_validate_options () { $debug_cmd # Display all warnings if -W was not given. test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" func_run_hooks func_validate_options ${1+"$@"} # Bail if the options were screwed! $exit_cmd $EXIT_FAILURE # save modified positional parameters for caller func_validate_options_result=$func_run_hooks_result } ## ----------------- ## ## Helper functions. ## ## ----------------- ## # This section contains the helper functions used by the rest of the # hookable option parser framework in ascii-betical order. # func_fatal_help ARG... # ---------------------- # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { $debug_cmd eval \$ECHO \""Usage: $usage"\" eval \$ECHO \""$fatal_help"\" func_error ${1+"$@"} exit $EXIT_FAILURE } # func_help # --------- # Echo long help message to standard output and exit. func_help () { $debug_cmd func_usage_message $ECHO "$long_help_message" exit 0 } # func_missing_arg ARGNAME # ------------------------ # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $debug_cmd func_error "Missing argument for '$1'." exit_cmd=exit } # func_split_equals STRING # ------------------------ # Set func_split_equals_lhs and func_split_equals_rhs shell variables after # splitting STRING at the '=' sign. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ && _G_HAVE_XSI_OPS=yes if test yes = "$_G_HAVE_XSI_OPS" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_split_equals () { $debug_cmd func_split_equals_lhs=${1%%=*} func_split_equals_rhs=${1#*=} test "x$func_split_equals_lhs" = "x$1" \ && func_split_equals_rhs= }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_split_equals () { $debug_cmd func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` func_split_equals_rhs= test "x$func_split_equals_lhs" = "x$1" \ || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` } fi #func_split_equals # func_split_short_opt SHORTOPT # ----------------------------- # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. if test yes = "$_G_HAVE_XSI_OPS" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_split_short_opt () { $debug_cmd func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"} }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_split_short_opt () { $debug_cmd func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'` func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` } fi #func_split_short_opt # func_usage # ---------- # Echo short help message to standard output and exit. func_usage () { $debug_cmd func_usage_message $ECHO "Run '$progname --help |${PAGER-more}' for full usage" exit 0 } # func_usage_message # ------------------ # Echo short help message to standard output. func_usage_message () { $debug_cmd eval \$ECHO \""Usage: $usage"\" echo $SED -n 's|^# || /^Written by/{ x;p;x } h /^Written by/q' < "$progpath" echo eval \$ECHO \""$usage_message"\" } # func_version # ------------ # Echo version message to standard output and exit. func_version () { $debug_cmd printf '%s\n' "$progname $scriptversion" $SED -n ' /(C)/!b go :more /\./!{ N s|\n# | | b more } :go /^# Written by /,/# warranty; / { s|^# || s|^# *$|| s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| p } /^# Written by / { s|^# || p } /^warranty; /q' < "$progpath" exit $? } # Local variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: # Set a version string. scriptversion='(GNU libtool) 2.4.6' # func_echo ARG... # ---------------- # Libtool also displays the current mode in messages, so override # funclib.sh func_echo with this custom definition. func_echo () { $debug_cmd _G_message=$* func_echo_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_IFS $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line" done IFS=$func_echo_IFS } # func_warning ARG... # ------------------- # Libtool warnings are not categorized, so override funclib.sh # func_warning with this simpler definition. func_warning () { $debug_cmd $warning_func ${1+"$@"} } ## ---------------- ## ## Options parsing. ## ## ---------------- ## # Hook in the functions to make sure our own options are parsed during # the option parsing loop. usage='$progpath [OPTION]... [MODE-ARG]...' # Short help message in response to '-h'. usage_message="Options: --config show all configuration variables --debug enable verbose shell tracing -n, --dry-run display commands without modifying any files --features display basic configuration information and exit --mode=MODE use operation mode MODE --no-warnings equivalent to '-Wnone' --preserve-dup-deps don't remove duplicate dependency libraries --quiet, --silent don't print informational messages --tag=TAG use configuration variables from tag TAG -v, --verbose print more informational messages than default --version print version information -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] -h, --help, --help-all print short, long, or detailed help message " # Additional text appended to 'usage_message' in response to '--help'. func_help () { $debug_cmd func_usage_message $ECHO "$long_help_message MODE must be one of the following: clean remove files from the build directory compile compile a source file into a libtool object execute automatically set library path, then run a program finish complete the installation of libtool libraries install install libraries or executables link create a library or an executable uninstall remove libraries from an installed directory MODE-ARGS vary depending on the MODE. When passed as first option, '--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that. Try '$progname --help --mode=MODE' for a more detailed description of MODE. When reporting a bug, please describe a test case to reproduce it and include the following information: host-triplet: $host shell: $SHELL compiler: $LTCC compiler flags: $LTCFLAGS linker: $LD (gnu? $with_gnu_ld) version: $progname (GNU libtool) 2.4.6 automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` Report bugs to . GNU libtool home page: . General help using GNU software: ." exit 0 } # func_lo2o OBJECT-NAME # --------------------- # Transform OBJECT-NAME from a '.lo' suffix to the platform specific # object suffix. lo2o=s/\\.lo\$/.$objext/ o2lo=s/\\.$objext\$/.lo/ if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_lo2o () { case $1 in *.lo) func_lo2o_result=${1%.lo}.$objext ;; * ) func_lo2o_result=$1 ;; esac }' # func_xform LIBOBJ-OR-SOURCE # --------------------------- # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise) # suffix to a '.lo' libtool-object suffix. eval 'func_xform () { func_xform_result=${1%.*}.lo }' else # ...otherwise fall back to using sed. func_lo2o () { func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"` } func_xform () { func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'` } fi # func_fatal_configuration ARG... # ------------------------------- # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func__fatal_error ${1+"$@"} \ "See the $PACKAGE documentation for more information." \ "Fatal configuration error." } # func_config # ----------- # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # ------------- # Display the features supported by this script. func_features () { echo "host: $host" if test yes = "$build_libtool_libs"; then echo "enable shared libraries" else echo "disable shared libraries" fi if test yes = "$build_old_libs"; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag TAGNAME # ----------------------- # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname=$1 re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf=/$re_begincf/,/$re_endcf/p # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # ------------------------ # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # libtool_options_prep [ARG]... # ----------------------------- # Preparation for options parsed by libtool. libtool_options_prep () { $debug_mode # Option defaults: opt_config=false opt_dlopen= opt_dry_run=false opt_help=false opt_mode= opt_preserve_dup_deps=false opt_quiet=false nonopt= preserve_args= # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Pass back the list of options. func_quote_for_eval ${1+"$@"} libtool_options_prep_result=$func_quote_for_eval_result } func_add_hook func_options_prep libtool_options_prep # libtool_parse_options [ARG]... # --------------------------------- # Provide handling for libtool specific options. libtool_parse_options () { $debug_cmd # Perform our own loop to consume as many options as possible in # each iteration. while test $# -gt 0; do _G_opt=$1 shift case $_G_opt in --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) func_config ;; --dlopen|-dlopen) opt_dlopen="${opt_dlopen+$opt_dlopen }$1" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) func_features ;; --finish) set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $_G_opt && break opt_mode=$1 case $1 in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $_G_opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_quiet=false func_append preserve_args " $_G_opt" ;; --no-warnings|--no-warning|--no-warn) opt_warning=false func_append preserve_args " $_G_opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $_G_opt" ;; --silent|--quiet) opt_quiet=: opt_verbose=false func_append preserve_args " $_G_opt" ;; --tag) test $# = 0 && func_missing_arg $_G_opt && break opt_tag=$1 func_append preserve_args " $_G_opt $1" func_enable_tag "$1" shift ;; --verbose|-v) opt_quiet=false opt_verbose=: func_append preserve_args " $_G_opt" ;; # An option not handled by this hook function: *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; esac done # save modified positional parameters for caller func_quote_for_eval ${1+"$@"} libtool_parse_options_result=$func_quote_for_eval_result } func_add_hook func_parse_options libtool_parse_options # libtool_validate_options [ARG]... # --------------------------------- # Perform any sanity checks on option settings and/or unconsumed # arguments. libtool_validate_options () { # save first non-option argument if test 0 -lt $#; then nonopt=$1 shift fi # preserve --debug test : = "$debug_cmd" || func_append preserve_args " --debug" case $host in # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match test yes != "$build_libtool_libs" \ && test yes != "$build_old_libs" \ && func_fatal_configuration "not configured to build any kind of library" # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test execute != "$opt_mode"; then func_error "unrecognized option '-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help=$help help="Try '$progname --help --mode=$opt_mode' for more information." } # Pass back the unparsed argument list func_quote_for_eval ${1+"$@"} libtool_validate_options_result=$func_quote_for_eval_result } func_add_hook func_validate_options libtool_validate_options # Process options as early as possible so that --help and --version # can return quickly. func_options ${1+"$@"} eval set dummy "$func_options_result"; shift ## ----------- ## ## Main. ## ## ----------- ## magic='%%%MAGIC variable%%%' magic_exe='%%%MAGIC EXE variable%%%' # Global variables. extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # func_generated_by_libtool # True iff stdin has been generated by Libtool. This function is only # a basic sanity check; it will hardly flush out determined imposters. func_generated_by_libtool_p () { $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_p file # True iff FILE is a libtool '.la' library or '.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p } # func_lalib_unsafe_p file # True iff FILE is a libtool '.la' library or '.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if 'file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case $lalib_p_line in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test yes = "$lalib_p" } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { test -f "$1" && $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $debug_cmd save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$sp$nl eval cmd=\"$cmd\" IFS=$save_ifs func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # 'FILE.' does not work on cygwin managed mounts. func_source () { $debug_cmd case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case $lt_sysroot:$1 in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result='='$func_stripname_result ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $debug_cmd if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with '--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=$1 if test yes = "$build_libtool_libs"; then write_lobj=\'$2\' else write_lobj=none fi if test yes = "$build_old_libs"; then write_oldobj=\'$3\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $debug_cmd # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result= if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result"; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $debug_cmd if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $debug_cmd # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $debug_cmd if test -z "$2" && test -n "$1"; then func_error "Could not determine host file name corresponding to" func_error " '$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result=$1 fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $debug_cmd if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " '$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result=$3 fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $debug_cmd case $4 in $1 ) func_to_host_path_result=$3$func_to_host_path_result ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via '$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $debug_cmd $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $debug_cmd case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result=$1 } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result=$func_convert_core_msys_to_w32_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result=$func_convert_core_file_wine_to_w32_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result=$func_cygpath_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result=$func_cygpath_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via '$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $debug_cmd if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd=func_convert_path_$func_stripname_result fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $debug_cmd func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result=$1 } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result=$func_convert_core_msys_to_w32_result func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result=$func_convert_core_path_wine_to_w32_result func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result=$func_cygpath_result func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result=$func_cygpath_result func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_dll_def_p FILE # True iff FILE is a Windows DLL '.def' file. # Keep in sync with _LT_DLL_DEF_P in libtool.m4 func_dll_def_p () { $debug_cmd func_dll_def_p_tmp=`$SED -n \ -e 's/^[ ]*//' \ -e '/^\(;.*\)*$/d' \ -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \ -e q \ "$1"` test DEF = "$func_dll_def_p_tmp" } # func_mode_compile arg... func_mode_compile () { $debug_cmd # Get the compilation command and the source file. base_compile= srcfile=$nonopt # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg=$arg arg_mode=normal ;; target ) libobj=$arg arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify '-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs=$IFS; IFS=, for arg in $args; do IFS=$save_ifs func_append_quoted lastarg "$arg" done IFS=$save_ifs func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg=$srcfile srcfile=$arg ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with '-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj=$func_basename_result } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from '$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test yes = "$build_libtool_libs" \ || func_fatal_configuration "cannot build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_for_eval "$libobj" test "X$libobj" != "X$func_quote_for_eval_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name '$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname=$func_basename_result xdir=$func_dirname_result lobj=$xdir$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test yes = "$build_old_libs"; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test no = "$compiler_c_o"; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext lockfile=$output_obj.lock else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test yes = "$need_locks"; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test warn = "$need_locks"; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test yes = "$build_libtool_libs"; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test no != "$pic_mode"; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test warn = "$need_locks" && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test yes = "$suppress_opt"; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test yes = "$build_old_libs"; then if test yes != "$pic_mode"; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test yes = "$compiler_c_o"; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test warn = "$need_locks" && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test no != "$need_locks"; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test compile = "$opt_mode" && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a '.o' file suitable for static linking -static only build a '.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a 'standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix '.c' with the library object suffix, '.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to '-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the '--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the 'install' or 'cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE '-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE use a list of object files found in FILE to specify objects -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes) -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with '-') are ignored. Every other argument is treated as a filename. Files ending in '.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in '.la', then a libtool library is created, only library objects ('.lo' files) may be specified, and '-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created using 'ar' and 'ranlib', or on Windows using 'lib'. If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode '$opt_mode'" ;; esac echo $ECHO "Try '$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test : = "$opt_help"; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | $SED -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | $SED '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $debug_cmd # The first argument is the command name. cmd=$nonopt test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "'$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "'$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "'$file' was not linked with '-export-dynamic'" continue fi func_dirname "$file" "" "." dir=$func_dirname_result if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir=$func_dirname_result ;; *) func_warning "'-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir=$absdir # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic=$magic # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file=$progdir/$program elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file=$progdir/$program fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if $opt_dry_run; then # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS else if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd=\$cmd$args fi } test execute = "$opt_mode" && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $debug_cmd libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "'$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument '$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and '=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_quiet && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the '-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the '$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the '$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the '$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to '/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test finish = "$opt_mode" && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $debug_cmd # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" func_append install_prog "$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=false stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=: ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test X-m = "X$prev" && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" func_append install_prog " $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the '$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" func_append install_shared_prog " -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=: if $isdir; then destdir=$dest destname= else func_dirname_and_basename "$dest" "" "." destdir=$func_dirname_result destname=$func_basename_result # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "'$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "'$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic=$magic staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "'$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir=$func_dirname_result func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking '$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname=$1 shift srcname=$realname test -n "$relink_command" && srcname=${realname}T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme=$stripme case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme= ;; esac ;; os2*) case $realname in *_dll.a) tstripme= ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try 'ln -sf' first, because the 'ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib=$destdir/$realname func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name=$func_basename_result instname=$dir/${name}i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile=$destdir/$destname else func_basename "$file" destfile=$func_basename_result destfile=$destdir/$destfile fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest=$destfile destfile= ;; *) func_fatal_help "cannot copy a libtool object to '$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test yes = "$build_old_libs"; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile=$destdir/$destname else func_basename "$file" destfile=$func_basename_result destfile=$destdir/$destfile fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext= case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=.exe fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script '$wrapper'" finalize=: for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'` if test -n "$libdir" && test ! -f "$libfile"; then func_warning "'$lib' has not been installed in '$libdir'" finalize=false fi done relink_command= func_source "$wrapper" outputname= if test no = "$fast_install" && test -n "$relink_command"; then $opt_dry_run || { if $finalize; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file=$func_basename_result outputname=$tmpdir/$file # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_quiet || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink '$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file=$outputname else func_warning "cannot relink '$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name=$func_basename_result # Set up the ranlib parameters. oldlib=$destdir/$name func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run '$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test install = "$opt_mode" && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $debug_cmd my_outputname=$1 my_originator=$2 my_pic_p=${3-false} my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms=${my_outputname}S.c else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist=$output_objdir/$my_outputname.nm func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) /* External symbol declarations for the compiler. */\ " if test yes = "$dlself"; then func_verbose "generating symbol list for '$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from '$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols=$output_objdir/$outputname.exp $opt_dry_run || { $RM $export_symbols eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from '$dlprefile'" func_basename "$dlprefile" name=$func_basename_result case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename= if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname"; then func_basename "$dlprefile_dlname" dlprefile_dlbasename=$func_basename_result else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename"; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi func_show_eval '$RM "${nlist}I"' if test -n "$global_symbol_to_import"; then eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[];\ " if test -s "$nlist"I; then echo >> "$output_objdir/$my_dlsyms" "\ static void lt_syminit(void) { LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; for (; symbol->name; ++symbol) {" $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" echo >> "$output_objdir/$my_dlsyms" "\ } }" fi echo >> "$output_objdir/$my_dlsyms" "\ LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = { {\"$my_originator\", (void *) 0}," if test -s "$nlist"I; then echo >> "$output_objdir/$my_dlsyms" "\ {\"@INIT@\", (void *) <_syminit}," fi case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) $my_pic_p && pic_flag_for_symtable=" $pic_flag" ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"' # Transform the symbol file into the correct name. symfileobj=$output_objdir/${my_outputname}S.$objext case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for '$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $debug_cmd func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $debug_cmd func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $debug_cmd win32_libid_type=unknown win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then case $nm_interface in "MS dumpbin") if func_cygming_ms_implib_p "$1" || func_cygming_gnu_implib_p "$1" then win32_nmres=import else win32_nmres= fi ;; *) func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s|.*|import| p q } }'` ;; esac case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $debug_cmd sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $debug_cmd match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive that possess that section. Heuristic: eliminate # all those that have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $debug_cmd if func_cygming_gnu_implib_p "$1"; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1"; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result= fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $debug_cmd f_ex_an_ar_dir=$1; shift f_ex_an_ar_oldlib=$1 if test yes = "$lock_old_archive_extraction"; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test yes = "$lock_old_archive_extraction"; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $debug_cmd my_gentop=$1; shift my_oldlibs=${1+"$@"} my_oldobjs= my_xlib= my_xabs= my_xdir= for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib=$func_basename_result my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir=$my_gentop/$my_xlib_u func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` func_basename "$darwin_archive" darwin_base_archive=$func_basename_result darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches; do func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch" $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive" cd "unfat-$$/$darwin_base_archive-$darwin_arch" func_extract_an_archive "`pwd`" "$darwin_base_archive" cd "$darwin_curdir" $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result=$my_oldobjs } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory where it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ that is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options that match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test yes = "$fast_install"; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else \$ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include #define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) /* declarations of non-ANSI functions */ #if defined __MINGW32__ # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined __CYGWIN__ # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined other_platform || defined ... */ #endif /* portability defines, excluding path handling macros */ #if defined _MSC_VER # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC #elif defined __MINGW32__ # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined __CYGWIN__ # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined other platforms ... */ #endif #if defined PATH_MAX # define LT_PATHMAX PATH_MAX #elif defined MAXPATHLEN # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \ defined __OS2__ # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free (stale); stale = 0; } \ } while (0) #if defined LT_DEBUGWRAPPER static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; size_t tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined HAVE_DOS_BASED_FILE_SYSTEM if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined HAVE_DOS_BASED_FILE_SYSTEM } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = (size_t) (q - p); p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (STREQ (str, pat)) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else size_t len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { size_t orig_value_len = strlen (orig_value); size_t add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ size_t len = strlen (new_value); while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[--len] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $debug_cmd case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_suncc_cstd_abi # !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!! # Several compiler flags select an ABI that is incompatible with the # Cstd library. Avoid specifying it if any are in CXXFLAGS. func_suncc_cstd_abi () { $debug_cmd case " $compile_command " in *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*) suncc_use_cstd_abi=no ;; *) suncc_use_cstd_abi=yes ;; esac } # func_mode_link arg... func_mode_link () { $debug_cmd case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # what system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll that has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= os2dllname= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=false prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module=$wl-single_module func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test yes != "$build_libtool_libs" \ && func_fatal_configuration "cannot build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg=$1 shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir=$arg prev= continue ;; dlfiles|dlprefiles) $preload || { # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=: } case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test no = "$dlself"; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test dlprefiles = "$prev"; then dlself=yes elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test dlfiles = "$prev"; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols=$arg test -f "$arg" \ || func_fatal_error "symbol file '$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex=$arg prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir=$arg prev= continue ;; mllvm) # Clang does not use LLVM to link, so we can simply discard any # '-mllvm $arg' options when doing the link step. prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test none = "$pic_object" && test none = "$non_pic_object"; then func_fatal_error "cannot find name of object for '$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result if test none != "$pic_object"; then # Prepend the subdirectory the object is found in. pic_object=$xdir$pic_object if test dlfiles = "$prev"; then if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test dlprefiles = "$prev"; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg=$pic_object fi # Non-PIC object. if test none != "$non_pic_object"; then # Prepend the subdirectory the object is found in. non_pic_object=$xdir$non_pic_object # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test none = "$pic_object"; then arg=$non_pic_object fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object=$pic_object func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "'$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file '$arg' does not exist" fi arg=$save_arg prev= continue ;; os2dllname) os2dllname=$arg prev= continue ;; precious_regex) precious_files_regex=$arg prev= continue ;; release) release=-$arg prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test rpath = "$prev"; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds=$arg prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg=$arg case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "'-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test X-export-symbols = "X$arg"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between '-L' and '$1'" else func_fatal_error "need path for '-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of '$dir'" dir=$absdir ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test X-lc = "X$arg" || test X-lm = "X$arg"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test X-lc = "X$arg" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) # Do not include libc due to us having libc/libc_r. test X-lc = "X$arg" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test X-lc = "X$arg" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test X-lc = "X$arg" && continue ;; esac elif test X-lc_r = "X$arg"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -mllvm) prev=mllvm continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module=$wl-multi_module continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "'-no-install' is ignored for $host" func_warning "assuming '-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -os2dllname) prev=os2dllname continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs=$IFS; IFS=, for flag in $args; do IFS=$save_ifs func_quote_for_eval "$flag" func_append arg " $func_quote_for_eval_result" func_append compiler_flags " $func_quote_for_eval_result" done IFS=$save_ifs func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs=$IFS; IFS=, for flag in $args; do IFS=$save_ifs func_quote_for_eval "$flag" func_append arg " $wl$func_quote_for_eval_result" func_append compiler_flags " $wl$func_quote_for_eval_result" func_append linker_flags " $func_quote_for_eval_result" done IFS=$save_ifs func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # -fstack-protector* stack protector flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization # -stdlib=* select c++ std lib with clang -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; -Z*) if test os2 = "`expr $host : '.*\(os2\)'`"; then # OS/2 uses -Zxxx to specify OS/2-specific options compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case $arg in -Zlinker | -Zstack) prev=xcompiler ;; esac continue else # Otherwise treat like 'Some other compiler flag' below func_quote_for_eval "$arg" arg=$func_quote_for_eval_result fi ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test none = "$pic_object" && test none = "$non_pic_object"; then func_fatal_error "cannot find name of object for '$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result test none = "$pic_object" || { # Prepend the subdirectory the object is found in. pic_object=$xdir$pic_object if test dlfiles = "$prev"; then if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test dlprefiles = "$prev"; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg=$pic_object } # Non-PIC object. if test none != "$non_pic_object"; then # Prepend the subdirectory the object is found in. non_pic_object=$xdir$non_pic_object # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test none = "$pic_object"; then arg=$non_pic_object fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object=$pic_object func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "'$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test dlfiles = "$prev"; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test dlprefiles = "$prev"; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg=$func_quote_for_eval_result ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the '$prevarg' option requires an argument" if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname=$func_basename_result libobjs_save=$libobjs if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" # Definition is injected by LT_CONFIG during libtool generation. func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH" func_dirname "$output" "/" "" output_objdir=$func_dirname_result$objdir func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test lib = "$linkmode"; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can '-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=false newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test lib,link = "$linkmode,$pass"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs=$tmp_deplibs fi if test lib,link = "$linkmode,$pass" || test prog,scan = "$linkmode,$pass"; then libs=$deplibs deplibs= fi if test prog = "$linkmode"; then case $pass in dlopen) libs=$dlfiles ;; dlpreopen) libs=$dlprefiles ;; link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; esac fi if test lib,dlpreopen = "$linkmode,$pass"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs=$dlprefiles fi if test dlopen = "$pass"; then # Collect dlpreopened libraries save_deplibs=$deplibs deplibs= fi for deplib in $libs; do lib= found=false case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test lib = "$linkmode"; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test lib != "$linkmode" && test prog != "$linkmode"; then func_warning "'-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test lib = "$linkmode"; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib=$searchdir/lib$name$search_ext if test -f "$lib"; then if test .la = "$search_ext"; then found=: else found=false fi break 2 fi done done if $found; then # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test yes = "$allow_libtool_libs_with_static_runtimes"; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll=$l done if test "X$ll" = "X$old_library"; then # only static version available found=false func_dirname "$lib" "" "." ladir=$func_dirname_result lib=$ladir/$old_library if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi else # deplib doesn't seem to be a libtool library if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" fi continue fi ;; # -l *.ltframework) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test lib = "$linkmode"; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test conv = "$pass" && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test conv = "$pass"; then deplibs="$deplib $deplibs" continue fi if test scan = "$pass"; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "'-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test link = "$pass"; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test conv = "$pass"; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=false case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=: fi ;; pass_all) valid_a_lib=: ;; esac if $valid_a_lib; then echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" else echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." fi ;; esac continue ;; prog) if test link != "$pass"; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test conv = "$pass"; then deplibs="$deplib $deplibs" elif test prog = "$linkmode"; then if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=: continue ;; esac # case $deplib $found || test -f "$lib" \ || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'" # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "'$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir=$func_dirname_result dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test lib,link = "$linkmode,$pass" || test prog,scan = "$linkmode,$pass" || { test prog != "$linkmode" && test lib != "$linkmode"; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test conv = "$pass"; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for '$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" elif test prog != "$linkmode" && test lib != "$linkmode"; then func_fatal_error "'$lib' is not a convenience library" fi tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test yes = "$prefer_static_libs" || test built,no = "$prefer_static_libs,$installed"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib=$l done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for '$lib'" fi # This library was specified with -dlopen. if test dlopen = "$pass"; then test -z "$libdir" \ && func_fatal_error "cannot -dlopen a convenience library: '$lib'" if test -z "$dlname" || test yes != "$dlopen_support" || test no = "$build_libtool_libs" then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of '$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir=$ladir fi ;; esac func_basename "$lib" laname=$func_basename_result # Find the relevant object directory and library name. if test yes = "$installed"; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library '$lib' was moved." dir=$ladir absdir=$abs_ladir libdir=$abs_ladir else dir=$lt_sysroot$libdir absdir=$lt_sysroot$libdir fi test yes = "$hardcode_automatic" && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir=$ladir absdir=$abs_ladir # Remove this search path later func_append notinst_path " $abs_ladir" else dir=$ladir/$objdir absdir=$abs_ladir/$objdir # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test dlpreopen = "$pass"; then if test -z "$libdir" && test prog = "$linkmode"; then func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'" fi case $host in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test lib = "$linkmode"; then deplibs="$dir/$old_library $deplibs" elif test prog,link = "$linkmode,$pass"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test prog = "$linkmode" && test link != "$pass"; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=false if test no != "$link_all_deplibs" || test -z "$library_names" || test no = "$build_libtool_libs"; then linkalldeplibs=: fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if $linkalldeplibs; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test prog,link = "$linkmode,$pass"; then if test -n "$library_names" && { { test no = "$prefer_static_libs" || test built,yes = "$prefer_static_libs,$installed"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then # Make sure the rpath contains only unique directories. case $temp_rpath: in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if $alldeplibs && { test pass_all = "$deplibs_check_method" || { test yes = "$build_libtool_libs" && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test built = "$use_static_libs" && test yes = "$installed"; then use_static_libs=no fi if test -n "$library_names" && { test no = "$use_static_libs" || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc* | *os2*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test no = "$installed"; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule= for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule=$dlpremoduletest break fi done if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then echo if test prog = "$linkmode"; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test lib = "$linkmode" && test yes = "$hardcode_into_libs"; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname=$1 shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname=$dlname elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc* | *os2*) func_arith $current - $age major=$func_arith_result versuffix=-$major ;; esac eval soname=\"$soname_spec\" else soname=$realname fi # Make a new name for the extract_expsyms_cmds to use soroot=$soname func_basename "$soroot" soname=$func_basename_result func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from '$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for '$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test prog = "$linkmode" || test relink != "$opt_mode"; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test no = "$hardcode_direct"; then add=$dir/$linklib case $host in *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;; *-*-sysv4*uw2*) add_dir=-L$dir ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir=-L$dir ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we cannot # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library"; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add=$dir/$old_library fi elif test -n "$old_library"; then add=$dir/$old_library fi fi esac elif test no = "$hardcode_minus_L"; then case $host in *-*-sunos*) add_shlibpath=$dir ;; esac add_dir=-L$dir add=-l$name elif test no = "$hardcode_shlibpath_var"; then add_shlibpath=$dir add=-l$name else lib_linked=no fi ;; relink) if test yes = "$hardcode_direct" && test no = "$hardcode_direct_absolute"; then add=$dir/$linklib elif test yes = "$hardcode_minus_L"; then add_dir=-L$absdir # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add=-l$name elif test yes = "$hardcode_shlibpath_var"; then add_shlibpath=$dir add=-l$name else lib_linked=no fi ;; *) lib_linked=no ;; esac if test yes != "$lib_linked"; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test prog = "$linkmode"; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test yes != "$hardcode_direct" && test yes != "$hardcode_minus_L" && test yes = "$hardcode_shlibpath_var"; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test prog = "$linkmode" || test relink = "$opt_mode"; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test yes = "$hardcode_direct" && test no = "$hardcode_direct_absolute"; then add=$libdir/$linklib elif test yes = "$hardcode_minus_L"; then add_dir=-L$libdir add=-l$name elif test yes = "$hardcode_shlibpath_var"; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add=-l$name elif test yes = "$hardcode_automatic"; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib"; then add=$inst_prefix_dir$libdir/$linklib else add=$libdir/$linklib fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir=-L$libdir # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add=-l$name fi if test prog = "$linkmode"; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test prog = "$linkmode"; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test unsupported != "$hardcode_direct"; then test -n "$old_library" && linklib=$old_library compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test yes = "$build_libtool_libs"; then # Not a shared library if test pass_all != "$deplibs_check_method"; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system cannot link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test yes = "$module"; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using 'nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** 'nm' from GNU binutils and a full rebuild may help." fi if test no = "$build_old_libs"; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test lib = "$linkmode"; then if test -n "$dependency_libs" && { test yes != "$hardcode_into_libs" || test yes = "$build_old_libs" || test yes = "$link_static"; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs=$temp_deplibs fi func_append newlib_search_path " $absdir" # Link against this library test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test no != "$link_all_deplibs"; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path=$deplib ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of '$dir'" absdir=$dir fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names"; then for tmp in $deplibrary_names; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl"; then depdepl=$absdir/$objdir/$depdepl darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`$OTOOL64 -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl" func_append linker_flags " -dylib_file $darwin_install_name:$depdepl" path= fi fi ;; *) path=-L$absdir/$objdir ;; esac else eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "'$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "'$deplib' seems to be moved" path=-L$absdir fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test link = "$pass"; then if test prog = "$linkmode"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs=$newdependency_libs if test dlpreopen = "$pass"; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test dlopen != "$pass"; then test conv = "$pass" || { # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= } if test prog,link = "$linkmode,$pass"; then vars="compile_deplibs finalize_deplibs" else vars=deplibs fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Add Sun CC postdeps if required: test CXX = "$tagname" && { case $host_os in linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 func_suncc_cstd_abi if test no != "$suncc_use_cstd_abi"; then func_append postdeps ' -library=Cstd -library=Crun' fi ;; esac ;; solaris*) func_cc_basename "$CC" case $func_cc_basename_result in CC* | sunCC*) func_suncc_cstd_abi if test no != "$suncc_use_cstd_abi"; then func_append postdeps ' -library=Cstd -library=Crun' fi ;; esac ;; esac } # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i= ;; esac if test -n "$i"; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test prog = "$linkmode"; then dlfiles=$newdlfiles fi if test prog = "$linkmode" || test lib = "$linkmode"; then dlprefiles=$newdlprefiles fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then func_warning "'-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "'-l' and '-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "'-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "'-R' is ignored for archives" test -n "$vinfo" && \ func_warning "'-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "'-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "'-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs=$output func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form 'libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test no = "$module" \ && func_fatal_help "libtool library '$output' must begin with 'lib'" if test no != "$need_lib_prefix"; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test pass_all != "$deplibs_check_method"; then func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test no = "$dlself" \ || func_warning "'-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test 1 -lt "$#" \ && func_warning "ignoring multiple '-rpath's for a libtool library" install_libdir=$1 oldlibs= if test -z "$rpath"; then if test yes = "$build_libtool_libs"; then # Building a libtool convenience library. # Some compilers have problems with a '.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "'-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "'-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs=$IFS; IFS=: set dummy $vinfo 0 0 0 shift IFS=$save_ifs test -n "$7" && \ func_fatal_help "too many parameters to '-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major=$1 number_minor=$2 number_revision=$3 # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # that has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|freebsd-elf|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age=$number_minor revision=$number_revision ;; freebsd-aout|qnx|sunos) current=$number_major revision=$number_minor age=0 ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age=$number_minor revision=$number_minor lt_irix_increment=no ;; esac ;; no) current=$1 revision=$2 age=$3 ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT '$current' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION '$revision' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE '$age' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE '$age' is greater than the current interface number '$current'" func_fatal_error "'$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" # On Darwin other compilers case $CC in nagfor*) verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" ;; *) verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; esac ;; freebsd-aout) major=.$current versuffix=.$current.$revision ;; freebsd-elf) func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision ;; irix | nonstopux) if test no = "$lt_irix_increment"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring=$verstring_prefix$major.$revision # Add in all the interfaces that we are compatible with. loop=$revision while test 0 -ne "$loop"; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring=$verstring_prefix$major.$iface:$verstring done # Before this point, $major must not contain '.'. major=.$major versuffix=$major.$revision ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=.$current.$age.$revision verstring=$current.$age.$revision # Add in all the interfaces that we are compatible with. loop=$age while test 0 -ne "$loop"; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring=$verstring:$iface.0 done # Make executables depend on our current version. func_append verstring ":$current.0" ;; qnx) major=.$current versuffix=.$current ;; sco) major=.$current versuffix=.$current ;; sunos) major=.$current versuffix=.$current.$revision ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 file systems. func_arith $current - $age major=$func_arith_result versuffix=-$major ;; *) func_fatal_configuration "unknown library version type '$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring=0.0 ;; esac if test no = "$need_version"; then versuffix= else versuffix=.0.0 fi fi # Remove version info from name if versioning should be avoided if test yes,no = "$avoid_version,$need_version"; then major= versuffix= verstring= fi # Check to see if the archive will have undefined symbols. if test yes = "$allow_undefined"; then if test unsupported = "$allow_undefined_flag"; then if test yes = "$build_old_libs"; then func_warning "undefined symbols not allowed in $host shared libraries; building static only" build_libtool_libs=no else func_fatal_error "can't build $host shared library unless -no-undefined is specified" fi fi else # Don't allow undefined symbols. allow_undefined_flag=$no_undefined_flag fi fi func_generate_dlsyms "$libname" "$libname" : func_append libobjs " $symfileobj" test " " = "$libobjs" && libobjs= if test relink != "$opt_mode"; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*) if test -n "$precious_files_regex"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles=$dlfiles dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles=$dlprefiles dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test yes = "$build_libtool_libs"; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test yes = "$build_libtool_need_lc"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release= versuffix= major= newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib=$potent_lib while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | $SED 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;; *) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib= break 2 fi done done fi if test -n "$a_deplib"; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib"; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test yes = "$allow_libtool_libs_with_static_runtimes"; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib= ;; esac fi if test -n "$a_deplib"; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib=$potent_lib # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib= break 2 fi done done fi if test -n "$a_deplib"; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib"; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs= tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test yes = "$allow_libtool_libs_with_static_runtimes"; then for i in $predeps $postdeps; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test none = "$deplibs_check_method"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test yes = "$droppeddeps"; then if test yes = "$module"; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using 'nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** 'nm' from GNU binutils and a full rebuild may help." fi if test no = "$build_old_libs"; then oldlibs=$output_objdir/$libname.$libext build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test no = "$allow_undefined"; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test no = "$build_old_libs"; then oldlibs=$output_objdir/$libname.$libext build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs=$new_libs # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test yes = "$build_libtool_libs"; then # Remove $wl instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test yes = "$hardcode_into_libs"; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath=$finalize_rpath test relink = "$opt_mode" || rpath=$compile_rpath$rpath for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath=$finalize_shlibpath test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname=$1 shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname=$realname fi if test -z "$dlname"; then dlname=$soname fi lib=$output_objdir/$realname linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols=$output_objdir/$libname.uexp func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile func_dll_def_p "$export_symbols" || { # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols=$export_symbols export_symbols= always_export_symbols=yes } fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for '$libname.la'" export_symbols=$output_objdir/$libname.exp $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs=$IFS; IFS='~' for cmd1 in $cmds; do IFS=$save_ifs # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test yes = "$try_normal_branch" \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=$output_objdir/$output_la.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS=$save_ifs if test -n "$export_symbols_regex" && test : != "$skipped_export"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols=$export_symbols test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test : != "$skipped_export" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for '$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands, which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs=$tmp_deplibs if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test yes = "$compiler_needs_object" && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test relink = "$opt_mode"; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test yes = "$module" && test -n "$module_cmds"; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test : != "$skipped_export" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then output=$output_objdir/$output_la.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then output=$output_objdir/$output_la.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test yes = "$compiler_needs_object"; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-$k.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test -z "$objlist" || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test 1 -eq "$k"; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-$k.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-$k.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi ${skipped_export-false} && { func_verbose "generating symbol list for '$libname.la'" export_symbols=$output_objdir/$libname.exp $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi } test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs=$IFS; IFS='~' for cmd in $concat_cmds; do IFS=$save_ifs $opt_quiet || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test relink = "$opt_mode"; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS=$save_ifs if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi ${skipped_export-false} && { if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols=$export_symbols test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for '$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands, which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi } libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test yes = "$module" && test -n "$module_cmds"; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs=$IFS; IFS='~' for cmd in $cmds; do IFS=$sp$nl eval cmd=\"$cmd\" IFS=$save_ifs $opt_quiet || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test relink = "$opt_mode"; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS=$save_ifs # Restore the uninstalled library and exit if test relink = "$opt_mode"; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test yes = "$module" || test yes = "$export_dynamic"; then # On all known operating systems, these are identical. dlname=$soname fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then func_warning "'-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "'-l' and '-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "'-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "'-R' is ignored for objects" test -n "$vinfo" && \ func_warning "'-version-info' is ignored for objects" test -n "$release" && \ func_warning "'-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object '$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj=$output ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # if reload_cmds runs $LD directly, get rid of -Wl from # whole_archive_flag_spec and hope we can get by with turning comma # into space. case $reload_cmds in *\$LD[\ \$]*) wl= ;; esac if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags else gentop=$output_objdir/${obj}x func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test yes = "$build_libtool_libs" || libobjs=$non_pic_objects # Create the old-style object. reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs output=$obj func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi test yes = "$build_libtool_libs" || { if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS } if test -n "$pic_flag" || test default != "$pic_mode"; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output=$libobj func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "'-version-info' is ignored for programs" test -n "$release" && \ func_warning "'-release' is ignored for programs" $preload \ && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \ && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test CXX = "$tagname"; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " $wl-bind_at_load" func_append finalize_command " $wl-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs=$new_libs func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath=$rpath rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath=$rpath if test -n "$libobjs" && test yes = "$build_old_libs"; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" false # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=: case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=false ;; *cygwin* | *mingw* ) test yes = "$build_libtool_libs" || wrappers_required=false ;; *) if test no = "$need_relink" || test yes != "$build_libtool_libs"; then wrappers_required=false fi ;; esac $wrappers_required || { # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command=$compile_command$compile_rpath # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.$objext"; then func_show_eval '$RM "$output_objdir/${outputname}S.$objext"' fi exit $exit_status } if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test yes = "$no_install"; then # We don't need to create a wrapper script. link_command=$compile_var$compile_command$compile_rpath # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi case $hardcode_action,$fast_install in relink,*) # Fast installation is not supported link_command=$compile_var$compile_command$compile_rpath relink_command=$finalize_var$finalize_command$finalize_rpath func_warning "this platform does not like uninstalled shared libraries" func_warning "'$output' will be relinked during installation" ;; *,yes) link_command=$finalize_var$compile_command$finalize_rpath relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` ;; *,no) link_command=$compile_var$compile_command$compile_rpath relink_command=$finalize_var$finalize_command$finalize_rpath ;; *,needless) link_command=$finalize_var$compile_command$finalize_rpath relink_command= ;; esac # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource=$output_path/$objdir/lt-$output_name.c cwrapper=$output_path/$output_name.exe $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host"; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do case $build_libtool_libs in convenience) oldobjs="$libobjs_save $symfileobj" addlibs=$convenience build_libtool_libs=no ;; module) oldobjs=$libobjs_save addlibs=$old_convenience build_libtool_libs=no ;; *) oldobjs="$old_deplibs $non_pic_objects" $preload && test -f "$symfileobj" \ && func_append oldobjs " $symfileobj" addlibs=$old_convenience ;; esac if test -n "$addlibs"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase=$func_basename_result case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj"; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test -z "$oldobjs"; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test yes = "$build_old_libs" && old_library=$libname.$libext func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test yes = "$hardcode_automatic"; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test yes = "$installed"; then if test -z "$install_libdir"; then break fi output=$output_objdir/${outputname}i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name=$func_basename_result func_resolve_sysroot "$deplib" eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "'$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs=$newdependency_libs newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name=$func_basename_result eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "'$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles=$newdlfiles newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name=$func_basename_result eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "'$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles=$newdlprefiles else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles=$newdlfiles newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles=$newdlprefiles fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test -n "$bindir"; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result/$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that cannot go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test no,yes = "$installed,$need_relink"; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } if test link = "$opt_mode" || test relink = "$opt_mode"; then func_mode_link ${1+"$@"} fi # func_mode_uninstall arg... func_mode_uninstall () { $debug_cmd RM=$nonopt files= rmforce=false exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic=$magic for arg do case $arg in -f) func_append RM " $arg"; rmforce=: ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir=$func_dirname_result if test . = "$dir"; then odir=$objdir else odir=$dir/$objdir fi func_basename "$file" name=$func_basename_result test uninstall = "$opt_mode" && odir=$dir # Remember odir for removal later, being careful to avoid duplicates if test clean = "$opt_mode"; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif $rmforce; then continue fi rmfiles=$file case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case $opt_mode in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test none != "$pic_object"; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test none != "$non_pic_object"; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test clean = "$opt_mode"; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.$objext" if test yes = "$fast_install" && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name"; then func_append rmfiles " $odir/lt-$noexename.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the $objdir's in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then func_mode_uninstall ${1+"$@"} fi test -z "$opt_mode" && { help=$generic_help func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode '$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # where we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: openldap-2.5.11+dfsg/build/ltoptions.m40000644000175000017500000003426214172327167016442 0ustar ryanryan# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 8 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option '$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl 'shared' nor 'disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4], [_LT_WITH_AIX_SONAME([aix])]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the 'shared' and # 'disable-shared' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS=$lt_save_ifs ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the 'static' and # 'disable-static' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS=$lt_save_ifs ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the 'fast-install' # and 'disable-fast-install' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS=$lt_save_ifs ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_AIX_SONAME([DEFAULT]) # ---------------------------------- # implement the --with-aix-soname flag, and support the `aix-soname=aix' # and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT # is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. m4_define([_LT_WITH_AIX_SONAME], [m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[[5-9]]*,yes) AC_MSG_CHECKING([which variant of shared library versioning to provide]) AC_ARG_WITH([aix-soname], [AS_HELP_STRING([--with-aix-soname=aix|svr4|both], [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], [case $withval in aix|svr4|both) ;; *) AC_MSG_ERROR([Unknown argument to --with-aix-soname]) ;; esac lt_cv_with_aix_soname=$with_aix_soname], [AC_CACHE_VAL([lt_cv_with_aix_soname], [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) with_aix_soname=$lt_cv_with_aix_soname]) AC_MSG_RESULT([$with_aix_soname]) if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac _LT_DECL([], [shared_archive_member_spec], [0], [Shared archive member basename, for filename based shared library versioning on AIX])dnl ])# _LT_WITH_AIX_SONAME LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the 'pic-only' and 'no-pic' # LT_INIT options. # MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for lt_pkg in $withval; do IFS=$lt_save_ifs if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS=$lt_save_ifs ;; esac], [pic_mode=m4_default([$1], [default])]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) openldap-2.5.11+dfsg/build/dir.mk0000644000175000017500000000355414172327167015254 0ustar ryanryan# $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . ##--------------------------------------------------------------------------- # # Makes subdirectories # all-common: FORCE @echo "Making all in `$(PWD)`" @for i in $(SUBDIRS) $(ALLDIRS); do \ echo " Entering subdirectory $$i"; \ ( cd $$i && $(MAKE) $(MFLAGS) all ); \ if test $$? != 0 ; then exit 1; fi ; \ echo " "; \ done install-common: FORCE @echo "Making install in `$(PWD)`" @for i in $(SUBDIRS) $(INSTALLDIRS); do \ echo " Entering subdirectory $$i"; \ ( cd $$i && $(MAKE) $(MFLAGS) install ); \ if test $$? != 0 ; then exit 1; fi ; \ echo " "; \ done clean-common: FORCE @echo "Making clean in `$(PWD)`" @for i in $(SUBDIRS) $(CLEANDIRS); do \ echo " Entering subdirectory $$i"; \ ( cd $$i && $(MAKE) $(MFLAGS) clean ); \ if test $$? != 0 ; then exit 1; fi ; \ echo " "; \ done veryclean-common: FORCE @echo "Making veryclean in `$(PWD)`" @for i in $(SUBDIRS) $(CLEANDIRS); do \ echo " Entering subdirectory $$i"; \ ( cd $$i && $(MAKE) $(MFLAGS) veryclean ); \ if test $$? != 0 ; then exit 1; fi ; \ echo " "; \ done depend-common: FORCE @echo "Making depend in `$(PWD)`" @for i in $(SUBDIRS) $(DEPENDDIRS); do \ echo " Entering subdirectory $$i"; \ ( cd $$i && $(MAKE) $(MFLAGS) depend ); \ if test $$? != 0 ; then exit 1; fi ; \ echo " "; \ done Makefile: $(top_srcdir)/build/dir.mk openldap-2.5.11+dfsg/build/LICENSE-2.0.10000644000175000017500000000460214172327167015601 0ustar ryanryanA number of files contained in OpenLDAP Software contain a statement: USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. The following is a verbatim copy of version 2.0.1 of the OpenLDAP Public License referenced in the above statement. The OpenLDAP Public License Version 2.0.1, 21 December 1999 Copyright 1999, The OpenLDAP Foundation, Redwood City, California, USA. All Rights Reserved. Redistribution and use of this software and associated documentation ("Software"), with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain copyright statements and notices. Redistributions must also contain a copy of this document. 2. 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. 3. The name "OpenLDAP" must not be used to endorse or promote products derived from this Software without prior written permission of the OpenLDAP Foundation. For written permission, please contact foundation@openldap.org. 4. Products derived from this Software may not be called "OpenLDAP" nor may "OpenLDAP" appear in their names without prior written permission of the OpenLDAP Foundation. OpenLDAP is a trademark of the OpenLDAP Foundation. 5. Due credit should be given to the OpenLDAP Project (http://www.openldap.org/). THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED 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 OPENLDAP FOUNDATION OR ITS 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. openldap-2.5.11+dfsg/build/version.var0000644000175000017500000000121414172327167016333 0ustar ryanryan#! /bin/sh # $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . ol_package=OpenLDAP ol_major=2 ol_minor=5 ol_patch=11 ol_api_inc=20511 ol_api_current=1 ol_api_revision=6 ol_api_age=1 ol_release_date="2022/01/20" openldap-2.5.11+dfsg/build/shtool0000755000175000017500000014324514172327167015405 0ustar ryanryan#!/bin/sh ## ## GNU shtool -- The GNU Portable Shell Tool ## Copyright (c) 1994-2008 Ralf S. Engelschall ## ## See http://www.gnu.org/software/shtool/ for more information. ## See ftp://ftp.gnu.org/gnu/shtool/ for latest version. ## ## Version: 2.0.8 (18-Jul-2008) ## Contents: 6/19 available modules ## ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ## USA, or contact Ralf S. Engelschall . ## ## NOTICE: Given that you include this file verbatim into your own ## source tree, you are justified in saying that it remains separate ## from your package, and that this way you are simply just using GNU ## shtool. So, in this situation, there is no requirement that your ## package itself is licensed under the GNU General Public License in ## order to take advantage of GNU shtool. ## ## ## Usage: shtool [] [ [] []] ## ## Available commands: ## echo Print string with optional construct expansion ## move Move files with simultaneous substitution ## install Install a program, script or datafile ## mkdir Make one or more directories ## mkln Make link with calculation of relative paths ## subst Apply sed(1) substitution operations ## ## Not available commands (because module was not built-in): ## mdate Pretty-print modification time of a file or dir ## table Pretty-print a field-separated list as a table ## prop Display progress with a running propeller ## mkshadow Make a shadow tree through symbolic links ## fixperm Fix file permissions inside a source tree ## rotate Logfile rotation ## tarball Roll distribution tarballs ## platform Platform Identification Utility ## arx Extended archive command ## slo Separate linker options by library class ## scpp Sharing C Pre-Processor ## version Maintain a version information file ## path Deal with program paths ## # maximum Bourne-Shell compatibility if [ ".$ZSH_VERSION" != . ] && (emulate sh) >/dev/null 2>&1; then # reconfigure zsh(1) emulate sh NULLCMD=: alias -g '${1+"$@"}'='"$@"' elif [ ".$BASH_VERSION" != . ] && (set -o posix) >/dev/null 2>&1; then # reconfigure bash(1) set -o posix fi # maximum independence of NLS nuisances for var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $var=C; export $var) 2>&1`"); then eval $var=C; export $var else unset $var fi done # initial command line handling if [ $# -eq 0 ]; then echo "$0:Error: invalid command line" 1>&2 echo "$0:Hint: run \`$0 -h' for usage" 1>&2 exit 1 fi if [ ".$1" = ".-h" ] || [ ".$1" = ".--help" ]; then echo "This is GNU shtool, version 2.0.8 (18-Jul-2008)" echo 'Copyright (c) 1994-2008 Ralf S. Engelschall ' echo 'Report bugs to ' echo '' echo 'Usage: shtool [] [ [] []]' echo '' echo 'Available global :' echo ' -v, --version display shtool version information' echo ' -h, --help display shtool usage help page (this one)' echo ' -d, --debug display shell trace information' echo ' -r, --recreate recreate this shtool script via shtoolize' echo '' echo 'Available [] []:' echo ' echo [-n|--newline] [-e|--expand] [ ...]' echo ' move [-v|--verbose] [-t|--trace] [-e|--expand] [-p|--preserve]' echo ' ' echo ' install [-v|--verbose] [-t|--trace] [-d|--mkdir] [-c|--copy]' echo ' [-C|--compare-copy] [-s|--strip] [-m|--mode ]' echo ' [-o|--owner ] [-g|--group ] [-e|--exec' echo ' ] [ ...] ' echo ' mkdir [-t|--trace] [-f|--force] [-p|--parents] [-m|--mode' echo ' ] [-o|--owner ] [-g|--group ]

' echo ' [ ...]' echo ' mkln [-t|--trace] [-f|--force] [-s|--symbolic] ' echo ' [ ...] ' echo ' subst [-v|--verbose] [-t|--trace] [-n|--nop] [-w|--warning]' echo ' [-q|--quiet] [-s|--stealth] [-i|--interactive] [-b|--backup' echo ' ] [-e|--exec ] [-f|--file ] []' echo ' [...]' echo '' echo 'Not available (because module was not built-in):' echo ' mdate [-n|--newline] [-z|--zero] [-s|--shorten] [-d|--digits]' echo ' [-f|--field-sep ] [-o|--order ] ' echo ' table [-F|--field-sep ] [-w|--width ] [-c|--columns' echo ' ] [-s|--strip ] ...' echo ' prop [-p|--prefix ]' echo ' mkshadow [-v|--verbose] [-t|--trace] [-a|--all] ' echo ' fixperm [-v|--verbose] [-t|--trace] [ ...]' echo ' rotate [-v|--verbose] [-t|--trace] [-f|--force] [-n|--num-files' echo ' ] [-s|--size ] [-c|--copy] [-r|--remove]' echo ' [-a|--archive-dir ] [-z|--compress [:]]' echo ' [-b|--background] [-d|--delay] [-p|--pad ] [-m|--mode' echo ' ] [-o|--owner ] [-g|--group ] [-M|--migrate' echo ' ] [-P|--prolog ] [-E|--epilog ] [...]' echo ' tarball [-t|--trace] [-v|--verbose] [-o|--output ]' echo ' [-c|--compress ] [-d|--directory ] [-u|--user' echo ' ] [-g|--group ] [-e|--exclude ]' echo ' [ ...]' echo ' platform [-F|--format ] [-S|--sep ] [-C|--conc' echo ' ] [-L|--lower] [-U|--upper] [-v|--verbose]' echo ' [-c|--concise] [-n|--no-newline] [-t|--type ]' echo ' [-V|--version] [-h|--help]' echo ' arx [-t|--trace] [-C|--command ] [' echo ' ...]' echo ' slo [-p|--prefix ] -- -L -l [-L -l' echo ' ...]' echo ' scpp [-v|--verbose] [-p|--preserve] [-f|--filter ]' echo ' [-o|--output ] [-t|--template ] [-M|--mark' echo ' ] [-D|--define ] [-C|--class ]' echo ' [ ...]' echo ' version [-l|--language ] [-n|--name ] [-p|--prefix' echo ' ] [-s|--set ] [-e|--edit] [-i|--increase' echo ' ] [-d|--display ] ' echo ' path [-s|--suppress] [-r|--reverse] [-d|--dirname] [-b|--basename]' echo ' [-m|--magic] [-p|--path ] [ ...]' echo '' exit 0 fi if [ ".$1" = ".-v" ] || [ ".$1" = ".--version" ]; then echo "GNU shtool 2.0.8 (18-Jul-2008)" exit 0 fi if [ ".$1" = ".-r" ] || [ ".$1" = ".--recreate" ]; then shtoolize -oshtool echo move install mkdir mkln subst exit 0 fi if [ ".$1" = ".-d" ] || [ ".$1" = ".--debug" ]; then shift set -x fi name=`echo "$0" | sed -e 's;.*/\([^/]*\)$;\1;' -e 's;-sh$;;' -e 's;\.sh$;;'` case "$name" in echo|move|install|mkdir|mkln|subst ) # implicit tool command selection tool="$name" ;; * ) # explicit tool command selection tool="$1" shift ;; esac arg_spec="" opt_spec="" gen_tmpfile=no ## ## DISPATCH INTO SCRIPT PROLOG ## case $tool in echo ) str_tool="echo" str_usage="[-n|--newline] [-e|--expand] [ ...]" arg_spec="0+" opt_spec="n.e." opt_alias="n:newline,e:expand" opt_n=no opt_e=no ;; move ) str_tool="move" str_usage="[-v|--verbose] [-t|--trace] [-e|--expand] [-p|--preserve] " arg_spec="2=" opt_spec="v.t.e.p." opt_alias="v:verbose,t:trace,e:expand,p:preserve" opt_v=no opt_t=no opt_e=no opt_p=no ;; install ) str_tool="install" str_usage="[-v|--verbose] [-t|--trace] [-d|--mkdir] [-c|--copy] [-C|--compare-copy] [-s|--strip] [-m|--mode ] [-o|--owner ] [-g|--group ] [-e|--exec ] [ ...] " arg_spec="1+" opt_spec="v.t.d.c.C.s.m:o:g:e+" opt_alias="v:verbose,t:trace,d:mkdir,c:copy,C:compare-copy,s:strip,m:mode,o:owner,g:group,e:exec" opt_v=no opt_t=no opt_d=no opt_c=no opt_C=no opt_s=no opt_m="0755" opt_o="" opt_g="" opt_e="" ;; mkdir ) str_tool="mkdir" str_usage="[-t|--trace] [-f|--force] [-p|--parents] [-m|--mode ] [-o|--owner ] [-g|--group ] [ ...]" arg_spec="1+" opt_spec="t.f.p.m:o:g:" opt_alias="t:trace,f:force,p:parents,m:mode,o:owner,g:group" opt_t=no opt_f=no opt_p=no opt_m="" opt_o="" opt_g="" ;; mkln ) str_tool="mkln" str_usage="[-t|--trace] [-f|--force] [-s|--symbolic] [ ...] " arg_spec="2+" opt_spec="t.f.s." opt_alias="t:trace,f:force,s:symbolic" opt_t=no opt_f=no opt_s=no ;; subst ) str_tool="subst" str_usage="[-v|--verbose] [-t|--trace] [-n|--nop] [-w|--warning] [-q|--quiet] [-s|--stealth] [-i|--interactive] [-b|--backup ] [-e|--exec ] [-f|--file ] [] [...]" gen_tmpfile=yes arg_spec="0+" opt_spec="v.t.n.w.q.s.i.b:e+f:" opt_alias="v:verbose,t:trace,n:nop,w:warning,q:quiet,s:stealth,i:interactive,b:backup,e:exec,f:file" opt_v=no opt_t=no opt_n=no opt_w=no opt_q=no opt_s=no opt_i=no opt_b="" opt_e="" opt_f="" ;; -* ) echo "$0:Error: unknown option \`$tool'" 2>&1 echo "$0:Hint: run \`$0 -h' for usage" 2>&1 exit 1 ;; * ) echo "$0:Error: unknown command \`$tool'" 2>&1 echo "$0:Hint: run \`$0 -h' for usage" 2>&1 exit 1 ;; esac ## ## COMMON UTILITY CODE ## # commonly used ASCII values ASC_TAB=" " ASC_NL=" " # determine name of tool if [ ".$tool" != . ]; then # used inside shtool script toolcmd="$0 $tool" toolcmdhelp="shtool $tool" msgprefix="shtool:$tool" else # used as standalone script toolcmd="$0" toolcmdhelp="sh $0" msgprefix="$str_tool" fi # parse argument specification string eval `echo $arg_spec |\ sed -e 's/^\([0-9]*\)\([+=]\)/arg_NUMS=\1; arg_MODE=\2/'` # parse option specification string eval `echo h.$opt_spec |\ sed -e 's/\([a-zA-Z0-9]\)\([.:+]\)/opt_MODE_\1=\2;/g'` # parse option alias string eval `echo h:help,$opt_alias |\ sed -e 's/-/_/g' -e 's/\([a-zA-Z0-9]\):\([^,]*\),*/opt_ALIAS_\2=\1;/g'` # iterate over argument line opt_PREV='' while [ $# -gt 0 ]; do # special option stops processing if [ ".$1" = ".--" ]; then shift break fi # determine option and argument opt_ARG_OK=no if [ ".$opt_PREV" != . ]; then # merge previous seen option with argument opt_OPT="$opt_PREV" opt_ARG="$1" opt_ARG_OK=yes opt_PREV='' else # split argument into option and argument case "$1" in --[a-zA-Z0-9]*=*) eval `echo "x$1" |\ sed -e 's/^x--\([a-zA-Z0-9-]*\)=\(.*\)$/opt_OPT="\1";opt_ARG="\2"/'` opt_STR=`echo $opt_OPT | sed -e 's/-/_/g'` eval "opt_OPT=\${opt_ALIAS_${opt_STR}-${opt_OPT}}" ;; --[a-zA-Z0-9]*) opt_OPT=`echo "x$1" | cut -c4-` opt_STR=`echo $opt_OPT | sed -e 's/-/_/g'` eval "opt_OPT=\${opt_ALIAS_${opt_STR}-${opt_OPT}}" opt_ARG='' ;; -[a-zA-Z0-9]*) eval `echo "x$1" |\ sed -e 's/^x-\([a-zA-Z0-9]\)/opt_OPT="\1";/' \ -e 's/";\(.*\)$/"; opt_ARG="\1"/'` ;; -[a-zA-Z0-9]) opt_OPT=`echo "x$1" | cut -c3-` opt_ARG='' ;; *) break ;; esac fi # eat up option shift # determine whether option needs an argument eval "opt_MODE=\$opt_MODE_${opt_OPT}" if [ ".$opt_ARG" = . ] && [ ".$opt_ARG_OK" != .yes ]; then if [ ".$opt_MODE" = ".:" ] || [ ".$opt_MODE" = ".+" ]; then opt_PREV="$opt_OPT" continue fi fi # process option case $opt_MODE in '.' ) # boolean option eval "opt_${opt_OPT}=yes" ;; ':' ) # option with argument (multiple occurrences override) eval "opt_${opt_OPT}=\"\$opt_ARG\"" ;; '+' ) # option with argument (multiple occurrences append) eval "opt_${opt_OPT}=\"\$opt_${opt_OPT}\${ASC_NL}\$opt_ARG\"" ;; * ) echo "$msgprefix:Error: unknown option: \`$opt_OPT'" 1>&2 echo "$msgprefix:Hint: run \`$toolcmdhelp -h' or \`man shtool' for details" 1>&2 exit 1 ;; esac done if [ ".$opt_PREV" != . ]; then echo "$msgprefix:Error: missing argument to option \`$opt_PREV'" 1>&2 echo "$msgprefix:Hint: run \`$toolcmdhelp -h' or \`man shtool' for details" 1>&2 exit 1 fi # process help option if [ ".$opt_h" = .yes ]; then echo "Usage: $toolcmdhelp $str_usage" exit 0 fi # complain about incorrect number of arguments case $arg_MODE in '=' ) if [ $# -ne $arg_NUMS ]; then echo "$msgprefix:Error: invalid number of arguments (exactly $arg_NUMS expected)" 1>&2 echo "$msgprefix:Hint: run \`$toolcmd -h' or \`man shtool' for details" 1>&2 exit 1 fi ;; '+' ) if [ $# -lt $arg_NUMS ]; then echo "$msgprefix:Error: invalid number of arguments (at least $arg_NUMS expected)" 1>&2 echo "$msgprefix:Hint: run \`$toolcmd -h' or \`man shtool' for details" 1>&2 exit 1 fi ;; esac # establish a temporary file on request if [ ".$gen_tmpfile" = .yes ]; then # create (explicitly) secure temporary directory if [ ".$TMPDIR" != . ]; then tmpdir="$TMPDIR" elif [ ".$TEMPDIR" != . ]; then tmpdir="$TEMPDIR" else tmpdir="/tmp" fi tmpdir="$tmpdir/.shtool.$$" ( umask 077 rm -rf "$tmpdir" >/dev/null 2>&1 || true mkdir "$tmpdir" >/dev/null 2>&1 if [ $? -ne 0 ]; then echo "$msgprefix:Error: failed to create temporary directory \`$tmpdir'" 1>&2 exit 1 fi ) # create (implicitly) secure temporary file tmpfile="$tmpdir/shtool.tmp" touch "$tmpfile" fi # utility function: map string to lower case util_lower () { echo "$1" | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' } # utility function: map string to upper case util_upper () { echo "$1" | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' } # cleanup procedure shtool_exit () { rc="$1" if [ ".$gen_tmpfile" = .yes ]; then rm -rf "$tmpdir" >/dev/null 2>&1 || true fi exit $rc } ## ## DISPATCH INTO SCRIPT BODY ## case $tool in echo ) ## ## echo -- Print string with optional construct expansion ## Copyright (c) 1998-2008 Ralf S. Engelschall ## text="$*" # check for broken escape sequence expansion seo='' bytes=`echo '\1' | wc -c | awk '{ printf("%s", $1); }'` if [ ".$bytes" != .3 ]; then bytes=`echo -E '\1' | wc -c | awk '{ printf("%s", $1); }'` if [ ".$bytes" = .3 ]; then seo='-E' fi fi # check for existing -n option (to suppress newline) minusn='' bytes=`echo -n 123 2>/dev/null | wc -c | awk '{ printf("%s", $1); }'` if [ ".$bytes" = .3 ]; then minusn='-n' fi # determine terminal bold sequence term_bold='' term_norm='' if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[Bb]'`" != . ]; then case $TERM in # for the most important terminal types we directly know the sequences xterm|xterm*|vt220|vt220*) term_bold=`awk 'BEGIN { printf("%c%c%c%c", 27, 91, 49, 109); }' /dev/null` term_norm=`awk 'BEGIN { printf("%c%c%c", 27, 91, 109); }' /dev/null` ;; vt100|vt100*|cygwin) term_bold=`awk 'BEGIN { printf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); }' /dev/null` term_norm=`awk 'BEGIN { printf("%c%c%c%c%c", 27, 91, 109, 0, 0); }' /dev/null` ;; # for all others, we try to use a possibly existing `tput' or `tcout' utility * ) paths=`echo $PATH | sed -e 's/:/ /g'` for tool in tput tcout; do for dir in $paths; do if [ -r "$dir/$tool" ]; then for seq in bold md smso; do # 'smso' is last bold="`$dir/$tool $seq 2>/dev/null`" if [ ".$bold" != . ]; then term_bold="$bold" break fi done if [ ".$term_bold" != . ]; then for seq in sgr0 me rmso init reset; do # 'reset' is last norm="`$dir/$tool $seq 2>/dev/null`" if [ ".$norm" != . ]; then term_norm="$norm" break fi done fi break fi done if [ ".$term_bold" != . ] && [ ".$term_norm" != . ]; then break; fi done ;; esac if [ ".$term_bold" = . ] || [ ".$term_norm" = . ]; then echo "$msgprefix:Warning: unable to determine terminal sequence for bold mode" 1>&2 term_bold='' term_norm='' fi fi # determine user name username='' if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[uUgG]'`" != . ]; then username="`(id -un) 2>/dev/null`" if [ ".$username" = . ]; then str="`(id) 2>/dev/null`" if [ ".`echo $str | grep '^uid[ ]*=[ ]*[0-9]*('`" != . ]; then username=`echo $str | sed -e 's/^uid[ ]*=[ ]*[0-9]*(//' -e 's/).*$//'` fi if [ ".$username" = . ]; then username="$LOGNAME" if [ ".$username" = . ]; then username="$USER" if [ ".$username" = . ]; then username="`(whoami) 2>/dev/null |\ awk '{ printf("%s", $1); }'`" if [ ".$username" = . ]; then username="`(who am i) 2>/dev/null |\ awk '{ printf("%s", $1); }'`" if [ ".$username" = . ]; then username='unknown' fi fi fi fi fi fi fi # determine user id userid='' if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%U'`" != . ]; then userid="`(id -u) 2>/dev/null`" if [ ".$userid" = . ]; then userid="`(id -u ${username}) 2>/dev/null`" if [ ".$userid" = . ]; then str="`(id) 2>/dev/null`" if [ ".`echo $str | grep '^uid[ ]*=[ ]*[0-9]*('`" != . ]; then userid=`echo $str | sed -e 's/^uid[ ]*=[ ]*//' -e 's/(.*$//'` fi if [ ".$userid" = . ]; then userid=`(getent passwd ${username}) 2>/dev/null | \ sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'` if [ ".$userid" = . ]; then userid=`grep "^${username}:" /etc/passwd 2>/dev/null | \ sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'` if [ ".$userid" = . ]; then userid=`(ypmatch "${username}" passwd; nismatch "${username}" passwd) 2>/dev/null | \ sed -e 'q' | sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'` if [ ".$userid" = . ]; then userid=`(nidump passwd . | grep "^${username}:") 2>/dev/null | \ sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'` if [ ".$userid" = . ]; then userid='?' fi fi fi fi fi fi fi fi # determine (primary) group id groupid='' if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[gG]'`" != . ]; then groupid="`(id -g ${username}) 2>/dev/null`" if [ ".$groupid" = . ]; then str="`(id) 2>/dev/null`" if [ ".`echo $str | grep 'gid[ ]*=[ ]*[0-9]*('`" != . ]; then groupid=`echo $str | sed -e 's/^.*gid[ ]*=[ ]*//' -e 's/(.*$//'` fi if [ ".$groupid" = . ]; then groupid=`(getent passwd ${username}) 2>/dev/null | \ sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'` if [ ".$groupid" = . ]; then groupid=`grep "^${username}:" /etc/passwd 2>/dev/null | \ sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'` if [ ".$groupid" = . ]; then groupid=`(ypmatch "${username}" passwd; nismatch "${username}" passwd) 2>/dev/null | \ sed -e 'q' | sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'` if [ ".$groupid" = . ]; then groupid=`(nidump passwd . | grep "^${username}:") 2>/dev/null | \ sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'` if [ ".$groupid" = . ]; then groupid='?' fi fi fi fi fi fi fi # determine (primary) group name groupname='' if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%g'`" != . ]; then groupname="`(id -gn ${username}) 2>/dev/null`" if [ ".$groupname" = . ]; then str="`(id) 2>/dev/null`" if [ ".`echo $str | grep 'gid[ ]*=[ ]*[0-9]*('`" != . ]; then groupname=`echo $str | sed -e 's/^.*gid[ ]*=[ ]*[0-9]*(//' -e 's/).*$//'` fi if [ ".$groupname" = . ]; then groupname=`(getent group) 2>/dev/null | \ grep "^[^:]*:[^:]*:${groupid}:" | \ sed -e 's/:.*$//'` if [ ".$groupname" = . ]; then groupname=`grep "^[^:]*:[^:]*:${groupid}:" /etc/group 2>/dev/null | \ sed -e 's/:.*$//'` if [ ".$groupname" = . ]; then groupname=`(ypcat group; niscat group) 2>/dev/null | \ sed -e 'q' | grep "^[^:]*:[^:]*:${groupid}:" | \ sed -e 's/:.*$//'` if [ ".$groupname" = . ]; then groupname=`(nidump group .) 2>/dev/null | \ grep "^[^:]*:[^:]*:${groupid}:" | \ sed -e 's/:.*$//'` if [ ".$groupname" = . ]; then groupname='?' fi fi fi fi fi fi fi # determine host and domain name hostname='' domainname='' if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%h'`" != . ]; then hostname="`(uname -n) 2>/dev/null |\ awk '{ printf("%s", $1); }'`" if [ ".$hostname" = . ]; then hostname="`(hostname) 2>/dev/null |\ awk '{ printf("%s", $1); }'`" if [ ".$hostname" = . ]; then hostname='unknown' fi fi case $hostname in *.* ) domainname=".`echo $hostname | cut -d. -f2-`" hostname="`echo $hostname | cut -d. -f1`" ;; esac fi if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%d'`" != . ]; then if [ ".$domainname" = . ]; then if [ -f /etc/resolv.conf ]; then domainname="`grep '^[ ]*domain' /etc/resolv.conf | sed -e 'q' |\ sed -e 's/.*domain//' \ -e 's/^[ ]*//' -e 's/^ *//' -e 's/^ *//' \ -e 's/^\.//' -e 's/^/./' |\ awk '{ printf("%s", $1); }'`" if [ ".$domainname" = . ]; then domainname="`grep '^[ ]*search' /etc/resolv.conf | sed -e 'q' |\ sed -e 's/.*search//' \ -e 's/^[ ]*//' -e 's/^ *//' -e 's/^ *//' \ -e 's/ .*//' -e 's/ .*//' \ -e 's/^\.//' -e 's/^/./' |\ awk '{ printf("%s", $1); }'`" fi fi fi fi # determine current time time_day='' time_month='' time_year='' time_monthname='' if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[DMYm]'`" != . ]; then time_day=`date '+%d'` time_month=`date '+%m'` time_year=`date '+%Y' 2>/dev/null` if [ ".$time_year" = . ]; then time_year=`date '+%y'` case $time_year in [5-9][0-9]) time_year="19$time_year" ;; [0-4][0-9]) time_year="20$time_year" ;; esac fi case $time_month in 1|01) time_monthname='Jan' ;; 2|02) time_monthname='Feb' ;; 3|03) time_monthname='Mar' ;; 4|04) time_monthname='Apr' ;; 5|05) time_monthname='May' ;; 6|06) time_monthname='Jun' ;; 7|07) time_monthname='Jul' ;; 8|08) time_monthname='Aug' ;; 9|09) time_monthname='Sep' ;; 10) time_monthname='Oct' ;; 11) time_monthname='Nov' ;; 12) time_monthname='Dec' ;; esac fi # expand special ``%x'' constructs if [ ".$opt_e" = .yes ]; then text=`echo $seo "$text" |\ sed -e "s/%B/${term_bold}/g" \ -e "s/%b/${term_norm}/g" \ -e "s/%u/${username}/g" \ -e "s/%U/${userid}/g" \ -e "s/%g/${groupname}/g" \ -e "s/%G/${groupid}/g" \ -e "s/%h/${hostname}/g" \ -e "s/%d/${domainname}/g" \ -e "s/%D/${time_day}/g" \ -e "s/%M/${time_month}/g" \ -e "s/%Y/${time_year}/g" \ -e "s/%m/${time_monthname}/g" 2>/dev/null` fi # create output if [ .$opt_n = .no ]; then echo $seo "$text" else # the harder part: echo -n is best, because # awk may complain about some \xx sequences. if [ ".$minusn" != . ]; then echo $seo $minusn "$text" else echo dummy | awk '{ printf("%s", TEXT); }' TEXT="$text" fi fi shtool_exit 0 ;; move ) ## ## move -- Move files with simultaneous substitution ## Copyright (c) 1999-2008 Ralf S. Engelschall ## src="$1" dst="$2" # consistency checks if [ ".$src" = . ] || [ ".$dst" = . ]; then echo "$msgprefix:Error: Invalid arguments" 1>&2 shtool_exit 1 fi if [ ".$src" = ".$dst" ]; then echo "$msgprefix:Error: Source and destination files are the same" 1>&2 shtool_exit 1 fi expsrc="$src" if [ ".$opt_e" = .yes ]; then expsrc="`echo $expsrc`" fi if [ ".$opt_e" = .yes ]; then if [ ".`echo "$src" | sed -e 's;^.*\\*.*$;;'`" = ".$src" ]; then echo "$msgprefix:Error: Source doesn't contain wildcard ('*'): $dst" 1>&2 shtool_exit 1 fi if [ ".`echo "$dst" | sed -e 's;^.*%[1-9].*$;;'`" = ".$dst" ]; then echo "$msgprefix:Error: Destination doesn't contain substitution ('%N'): $dst" 1>&2 shtool_exit 1 fi if [ ".$expsrc" = ".$src" ]; then echo "$msgprefix:Error: Sources not found or no asterisk : $src" 1>&2 shtool_exit 1 fi else if [ ! -r "$src" ]; then echo "$msgprefix:Error: Source not found: $src" 1>&2 shtool_exit 1 fi fi # determine substitution patterns if [ ".$opt_e" = .yes ]; then srcpat=`echo "$src" | sed -e 's/\\./\\\\./g' -e 's/;/\\;/g' -e 's;\\*;\\\\(.*\\\\);g'` dstpat=`echo "$dst" | sed -e 's;%\([1-9]\);\\\\\1;g'` fi # iterate over source(s) for onesrc in $expsrc; do if [ .$opt_e = .yes ]; then onedst=`echo $onesrc | sed -e "s;$srcpat;$dstpat;"` else onedst="$dst" fi errorstatus=0 if [ ".$opt_v" = .yes ]; then echo "$onesrc -> $onedst" fi if [ ".$opt_p" = .yes ]; then if [ -r $onedst ]; then if cmp -s $onesrc $onedst; then if [ ".$opt_t" = .yes ]; then echo "rm -f $onesrc" 1>&2 fi rm -f $onesrc || errorstatus=$? else if [ ".$opt_t" = .yes ]; then echo "mv -f $onesrc $onedst" 1>&2 fi mv -f $onesrc $onedst || errorstatus=$? fi else if [ ".$opt_t" = .yes ]; then echo "mv -f $onesrc $onedst" 1>&2 fi mv -f $onesrc $onedst || errorstatus=$? fi else if [ ".$opt_t" = .yes ]; then echo "mv -f $onesrc $onedst" 1>&2 fi mv -f $onesrc $onedst || errorstatus=$? fi if [ $errorstatus -ne 0 ]; then break; fi done shtool_exit $errorstatus ;; install ) ## ## install -- Install a program, script or datafile ## Copyright (c) 1997-2008 Ralf S. Engelschall ## # special case: "shtool install -d [...]" internally # maps to "shtool mkdir -f -p -m 755 [...]" if [ "$opt_d" = yes ]; then cmd="$0 mkdir -f -p -m 755" if [ ".$opt_o" != . ]; then cmd="$cmd -o '$opt_o'" fi if [ ".$opt_g" != . ]; then cmd="$cmd -g '$opt_g'" fi if [ ".$opt_v" = .yes ]; then cmd="$cmd -v" fi if [ ".$opt_t" = .yes ]; then cmd="$cmd -t" fi for dir in "$@"; do eval "$cmd $dir" || shtool_exit $? done shtool_exit 0 fi # determine source(s) and destination argc=$# srcs="" while [ $# -gt 1 ]; do srcs="$srcs $1" shift done dstpath="$1" # type check for destination dstisdir=0 if [ -d $dstpath ]; then dstpath=`echo "$dstpath" | sed -e 's:/$::'` dstisdir=1 fi # consistency check for destination if [ $argc -gt 2 ] && [ $dstisdir = 0 ]; then echo "$msgprefix:Error: multiple sources require destination to be directory" 1>&2 shtool_exit 1 fi # iterate over all source(s) for src in $srcs; do dst=$dstpath # if destination is a directory, append the input filename if [ $dstisdir = 1 ]; then dstfile=`echo "$src" | sed -e 's;.*/\([^/]*\)$;\1;'` dst="$dst/$dstfile" fi # check for correct arguments if [ ".$src" = ".$dst" ]; then echo "$msgprefix:Warning: source and destination are the same - skipped" 1>&2 continue fi if [ -d "$src" ]; then echo "$msgprefix:Warning: source \`$src' is a directory - skipped" 1>&2 continue fi # make a temp file name in the destination directory dsttmp=`echo $dst |\ sed -e 's;[^/]*$;;' -e 's;\(.\)/$;\1;' -e 's;^$;.;' \ -e "s;\$;/#INST@$$#;"` # verbosity if [ ".$opt_v" = .yes ]; then echo "$src -> $dst" 1>&2 fi # copy or move the file name to the temp name # (because we might be not allowed to change the source) if [ ".$opt_C" = .yes ]; then opt_c=yes fi if [ ".$opt_c" = .yes ]; then if [ ".$opt_t" = .yes ]; then echo "cp $src $dsttmp" 1>&2 fi cp "$src" "$dsttmp" || shtool_exit $? else if [ ".$opt_t" = .yes ]; then echo "mv $src $dsttmp" 1>&2 fi mv "$src" "$dsttmp" || shtool_exit $? fi # adjust the target file if [ ".$opt_e" != . ]; then sed='sed' OIFS="$IFS"; IFS="$ASC_NL"; set -- $opt_e; IFS="$OIFS" for e do sed="$sed -e '$e'" done cp "$dsttmp" "$dsttmp.old" chmod u+w $dsttmp eval "$sed <$dsttmp.old >$dsttmp" || shtool_exit $? rm -f $dsttmp.old fi if [ ".$opt_s" = .yes ]; then if [ ".$opt_t" = .yes ]; then echo "strip $dsttmp" 1>&2 fi ${STRIP:-strip} $dsttmp || shtool_exit $? fi if [ ".$opt_o" != . ]; then if [ ".$opt_t" = .yes ]; then echo "chown $opt_o $dsttmp" 1>&2 fi chown $opt_o $dsttmp || shtool_exit $? fi if [ ".$opt_g" != . ]; then if [ ".$opt_t" = .yes ]; then echo "chgrp $opt_g $dsttmp" 1>&2 fi chgrp $opt_g $dsttmp || shtool_exit $? fi if [ ".$opt_m" != ".-" ]; then if [ ".$opt_t" = .yes ]; then echo "chmod $opt_m $dsttmp" 1>&2 fi chmod $opt_m $dsttmp || shtool_exit $? fi # determine whether to do a quick install # (has to be done _after_ the strip was already done) quick=no if [ ".$opt_C" = .yes ]; then if [ -r $dst ]; then if cmp -s "$src" "$dst"; then quick=yes fi fi fi # finally, install the file to the real destination if [ $quick = yes ]; then if [ ".$opt_t" = .yes ]; then echo "rm -f $dsttmp" 1>&2 fi rm -f $dsttmp else if [ ".$opt_t" = .yes ]; then echo "rm -f $dst && mv $dsttmp $dst" 1>&2 fi rm -f $dst && mv $dsttmp $dst fi done shtool_exit 0 ;; mkdir ) ## ## mkdir -- Make one or more directories ## Copyright (c) 1996-2008 Ralf S. Engelschall ## errstatus=0 for p in ${1+"$@"}; do # if the directory already exists... if [ -d "$p" ]; then if [ ".$opt_f" = .no ] && [ ".$opt_p" = .no ]; then echo "$msgprefix:Error: directory already exists: $p" 1>&2 errstatus=1 break else continue fi fi # if the directory has to be created... if [ ".$opt_p" = .no ]; then if [ ".$opt_t" = .yes ]; then echo "mkdir $p" 1>&2 fi mkdir $p || errstatus=$? if [ ".$opt_o" != . ]; then if [ ".$opt_t" = .yes ]; then echo "chown $opt_o $p" 1>&2 fi chown $opt_o $p || errstatus=$? fi if [ ".$opt_g" != . ]; then if [ ".$opt_t" = .yes ]; then echo "chgrp $opt_g $p" 1>&2 fi chgrp $opt_g $p || errstatus=$? fi if [ ".$opt_m" != . ]; then if [ ".$opt_t" = .yes ]; then echo "chmod $opt_m $p" 1>&2 fi chmod $opt_m $p || errstatus=$? fi else # the smart situation set fnord `echo ":$p" |\ sed -e 's/^:\//%/' \ -e 's/^://' \ -e 's/\// /g' \ -e 's/^%/\//'` shift pathcomp='' for d in ${1+"$@"}; do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp="./$pathcomp" ;; esac if [ ! -d "$pathcomp" ]; then if [ ".$opt_t" = .yes ]; then echo "mkdir $pathcomp" 1>&2 fi mkdir $pathcomp || errstatus=$? if [ ".$opt_o" != . ]; then if [ ".$opt_t" = .yes ]; then echo "chown $opt_o $pathcomp" 1>&2 fi chown $opt_o $pathcomp || errstatus=$? fi if [ ".$opt_g" != . ]; then if [ ".$opt_t" = .yes ]; then echo "chgrp $opt_g $pathcomp" 1>&2 fi chgrp $opt_g $pathcomp || errstatus=$? fi if [ ".$opt_m" != . ]; then if [ ".$opt_t" = .yes ]; then echo "chmod $opt_m $pathcomp" 1>&2 fi chmod $opt_m $pathcomp || errstatus=$? fi fi pathcomp="$pathcomp/" done fi done shtool_exit $errstatus ;; mkln ) ## ## mkln -- Make link with calculation of relative paths ## Copyright (c) 1998-2008 Ralf S. Engelschall ## # determine source(s) and destination args=$# srcs="" while [ $# -gt 1 ]; do srcs="$srcs $1" shift done dst="$1" if [ ! -d $dst ]; then if [ $args -gt 2 ]; then echo "$msgprefix:Error: multiple sources not allowed when target isn't a directory" 1>&2 shtool_exit 1 fi fi # determine link options lnopt="" if [ ".$opt_f" = .yes ]; then lnopt="$lnopt -f" fi if [ ".$opt_s" = .yes ]; then lnopt="$lnopt -s" fi # iterate over sources for src in $srcs; do # determine if one of the paths is an absolute path, # because then we _have_ to use an absolute symlink oneisabs=0 srcisabs=0 dstisabs=0 case $src in /* ) oneisabs=1; srcisabs=1 ;; esac case $dst in /* ) oneisabs=1; dstisabs=1 ;; esac # split source and destination into dir and base name if [ -d $src ]; then srcdir=`echo $src | sed -e 's;/*$;;'` srcbase="" else srcdir=`echo $src | sed -e 's;^[^/]*$;;' -e 's;^\(.*/\)[^/]*$;\1;' -e 's;\(.\)/$;\1;'` srcbase=`echo $src | sed -e 's;.*/\([^/]*\)$;\1;'` fi if [ -d $dst ]; then dstdir=`echo $dst | sed -e 's;/*$;;'` dstbase="" else dstdir=`echo $dst | sed -e 's;^[^/]*$;;' -e 's;^\(.*/\)[^/]*$;\1;' -e 's;\(.\)/$;\1;'` dstbase=`echo $dst | sed -e 's;.*/\([^/]*\)$;\1;'` fi # consistency check if [ ".$dstdir" != . ]; then if [ ! -d $dstdir ]; then echo "$msgprefix:Error: destination directory not found: $dstdir" 1>&2 shtool_exit 1 fi fi # make sure the source is reachable from the destination if [ $dstisabs = 1 ]; then if [ $srcisabs = 0 ]; then if [ ".$srcdir" = . ]; then srcdir="`pwd | sed -e 's;/*$;;'`" srcisabs=1 oneisabs=1 elif [ -d $srcdir ]; then srcdir="`cd $srcdir; pwd | sed -e 's;/*$;;'`" srcisabs=1 oneisabs=1 fi fi fi # split away a common prefix prefix="" if [ ".$srcdir" = ".$dstdir" ] && [ ".$srcdir" != . ]; then prefix="$srcdir/" srcdir="" dstdir="" else while [ ".$srcdir" != . ] && [ ".$dstdir" != . ]; do presrc=`echo $srcdir | sed -e 's;^\([^/]*\)/.*;\1;'` predst=`echo $dstdir | sed -e 's;^\([^/]*\)/.*;\1;'` if [ ".$presrc" != ".$predst" ]; then break fi prefix="$prefix$presrc/" srcdir=`echo $srcdir | sed -e 's;^[^/]*/*;;'` dstdir=`echo $dstdir | sed -e 's;^[^/]*/*;;'` done fi # destination prefix is just the common prefix dstpre="$prefix" # determine source prefix which is the reverse directory # step-up corresponding to the destination directory srcpre="" allow_relative_srcpre=no if [ ".$prefix" != . ] && [ ".$prefix" != ./ ]; then allow_relative_srcpre=yes fi if [ $oneisabs = 0 ]; then allow_relative_srcpre=yes fi if [ ".$opt_s" != .yes ]; then allow_relative_srcpre=no fi if [ ".$allow_relative_srcpre" = .yes ]; then pl="$dstdir/" OIFS="$IFS"; IFS='/' for pe in $pl; do [ ".$pe" = . ] && continue [ ".$pe" = .. ] && continue srcpre="../$srcpre" done IFS="$OIFS" else if [ $srcisabs = 1 ]; then srcpre="$prefix" fi fi # determine destination symlink name if [ ".$dstbase" = . ]; then if [ ".$srcbase" != . ]; then dstbase="$srcbase" else dstbase=`echo "$prefix$srcdir" | sed -e 's;/*$;;' -e 's;.*/\([^/]*\)$;\1;'` fi fi # now finalize source and destination directory paths srcdir=`echo $srcdir | sed -e 's;\([^/]\)$;\1/;'` dstdir=`echo $dstdir | sed -e 's;\([^/]\)$;\1/;'` # run the final link command if [ ".$opt_t" = .yes ]; then echo "ln$lnopt $srcpre$srcdir$srcbase $dstpre$dstdir$dstbase" fi eval ln$lnopt $srcpre$srcdir$srcbase $dstpre$dstdir$dstbase done shtool_exit 0 ;; subst ) ## ## subst -- Apply sed(1) substitution operations ## Copyright (c) 2001-2008 Ralf S. Engelschall ## # remember optional list of file(s) files="$*" files_num="$#" # parameter consistency check if [ $# -eq 0 ] && [ ".$opt_b" != . ]; then echo "$msgprefix:Error: option -b cannot be applied to stdin" 1>&2 shtool_exit 1 fi if [ $# -eq 0 ] && [ ".$opt_s" = .yes ]; then echo "$msgprefix:Error: option -s cannot be applied to stdin" 1>&2 shtool_exit 1 fi # build underlying sed(1) command sedcmd='sed' if [ ".$opt_e" != . ]; then OIFS="$IFS"; IFS="$ASC_NL"; set -- $opt_e; IFS="$OIFS" for e do sedcmd="$sedcmd -e '$e'" done elif [ ".$opt_f" != . ]; then if [ ! -f $opt_f ]; then echo "$msgprefix:Error: command file \`$opt_f' not found or not a regular file" 1>&2 shtool_exit 1 fi sedcmd="$sedcmd -f '$opt_f'" else echo "$msgprefix:Error: either -e option(s) or -f option required" 1>&2 shtool_exit 1 fi # determine extension for original file orig=".orig" if [ ".$opt_b" != . ]; then orig="$opt_b" fi # apply sed(1) operation(s) if [ ".$files" != . ]; then # apply operation(s) to files substdone=no for file in $files; do test ".$file" = . && continue if [ ! -f $file ]; then echo "$msgprefix:Warning: file \`$file' not found or not a regular file" 1>&2 continue fi # handle interactive mode if [ ".$opt_i" = .yes ]; then eval "$sedcmd <$file >$file.new" skip=no if cmp $file $file.new >/dev/null 2>&1; then rm -f $file.new skip=yes else (diff -U1 $file $file.new >$tmpfile) 2>/dev/null if [ ".`cat $tmpfile`" = . ]; then (diff -C1 $file $file.new >$tmpfile) 2>/dev/null if [ ".`cat $tmpfile`" = . ]; then echo "$msgprefix:Warning: unable to show difference for file \`$file'" 1>&2 cp /dev/null $tmpfile fi fi rm -f $file.new cat $tmpfile echo dummy | awk '{ printf("%s", TEXT); }' TEXT=">>> Apply [Y/n]: " read input if [ ".$input" != .Y ] &&\ [ ".$input" != .y ] &&\ [ ".$input" != . ]; then skip=yes fi fi if [ ".$skip" = .yes ]; then if [ ".$opt_v" = .yes ]; then echo "file \`$file' -- skipped" 1>&2 fi continue fi fi # apply sed(1) operation(s) if [ ".$opt_v" = .yes ]; then echo "patching \`$file'" 1>&2 fi if [ ".$opt_t" = .yes ]; then echo "\$ cp -p $file $file$orig" echo "\$ chmod u+w $file" echo "\$ $sedcmd <$file$orig >$file" fi if [ ".$opt_n" = .no ]; then cp -p $file $file$orig chmod u+w $file >/dev/null 2>&1 || true eval "$sedcmd <$file$orig >$file" fi # optionally fix timestamp if [ ".$opt_s" = .yes ]; then if [ ".$opt_t" = .yes ]; then echo "\$ touch -r $file$orig $file" fi if [ ".$opt_n" = .no ]; then touch -r $file$orig $file fi fi # optionally check whether any content change actually occurred if [ ".$opt_q" = .no ]; then if cmp $file$orig $file >/dev/null 2>&1; then if [ ".$opt_w" = .yes ]; then echo "$msgprefix:Warning: substitution resulted in no content change on file \"$file\"" 1>&2 fi else substdone=yes fi fi # optionally remove preserved original file if [ ".$opt_b" = . ]; then if [ ".$opt_t" = .yes ]; then echo "\$ rm -f $file$orig" fi if [ ".$opt_n" = .no ]; then rm -f $file$orig fi fi done if [ ".$opt_q" = .no ] && [ ".$opt_w" = .no ]; then if [ ".$substdone" = .no ]; then if [ ".$files_num" = .1 ]; then echo "$msgprefix:Warning: substitution resulted in no content change on file \"$file\"" 1>&2 else echo "$msgprefix:Warning: substitution resulted in no content change on any file" 1>&2 fi fi fi else # apply operation(s) to stdin/stdout if [ ".$opt_v" = .yes ]; then echo "patching " 1>&2 fi if [ ".$opt_t" = .yes ]; then echo "\$ $sedcmd" fi if [ ".$opt_n" = .no ]; then eval "$sedcmd" fi fi shtool_exit 0 ;; esac shtool_exit 0 openldap-2.5.11+dfsg/build/mkvers.bat0000755000175000017500000000161314172327167016141 0ustar ryanryan:: $OpenLDAP$ :: This work is part of OpenLDAP Software . :: :: Copyright 1998-2022 The OpenLDAP Foundation. :: All rights reserved. :: :: Redistribution and use in source and binary forms, with or without :: modification, are permitted only as authorized by the OpenLDAP :: Public License. :: :: A copy of this license is available in the file LICENSE in the :: top-level directory of the distribution or, alternatively, at :: . :: :: Create a version.c file from build/version.h :: :: usage: mkvers.bat , , , copy %1 %2 (echo. ) >> %2 (echo #include "portable.h") >> %2 (echo. ) >> %2 (echo %4 const char __Version[] =) >> %2 (echo "@(#) $" OPENLDAP_PACKAGE ": %3 " OPENLDAP_VERSION) >> %2 (echo " (" __DATE__ " " __TIME__ ") $\n") >> %2 (echo "\t%USERNAME%@%COMPUTERNAME% %CD:\=/%\n";) >> %2 openldap-2.5.11+dfsg/build/ltversion.m40000644000175000017500000000127314172327167016430 0ustar ryanryan# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # @configure_input@ # serial 4179 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.6]) m4_define([LT_PACKAGE_REVISION], [2.4.6]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.6' macro_revision='2.4.6' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) openldap-2.5.11+dfsg/build/config.sub0000755000175000017500000007557114172327167016140 0ustar ryanryan#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2020 Free Software Foundation, Inc. timestamp='2020-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2020 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type # shellcheck disable=SC2162 IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc \ | linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | storm-chaos* | os2-emx* | rtmk-nova*) basic_machine=$field1 os=$maybe_os ;; android-linux) basic_machine=$field1-unknown os=linux-android ;; *) basic_machine=$field1-$field2 os=$field3 ;; esac ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ | unicom* | ibm* | next | hp | isi* | apollo | altos* \ | convergent* | ncr* | news | 32* | 3600* | 3100* \ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ | ultra | tti* | harris | dolphin | highlevel | gould \ | cbm | ns | masscomp | apple | axis | knuth | cray \ | microblaze* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 os= ;; *) basic_machine=$field1 os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc os=bsd ;; a29khif) basic_machine=a29k-amd os=udi ;; adobe68k) basic_machine=m68010-adobe os=scout ;; alliant) basic_machine=fx80-alliant os= ;; altos | altos3068) basic_machine=m68k-altos os= ;; am29k) basic_machine=a29k-none os=bsd ;; amdahl) basic_machine=580-amdahl os=sysv ;; amiga) basic_machine=m68k-unknown os= ;; amigaos | amigados) basic_machine=m68k-unknown os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=sysv4 ;; apollo68) basic_machine=m68k-apollo os=sysv ;; apollo68bsd) basic_machine=m68k-apollo os=bsd ;; aros) basic_machine=i386-pc os=aros ;; aux) basic_machine=m68k-apple os=aux ;; balance) basic_machine=ns32k-sequent os=dynix ;; blackfin) basic_machine=bfin-unknown os=linux ;; cegcc) basic_machine=arm-unknown os=cegcc ;; convex-c1) basic_machine=c1-convex os=bsd ;; convex-c2) basic_machine=c2-convex os=bsd ;; convex-c32) basic_machine=c32-convex os=bsd ;; convex-c34) basic_machine=c34-convex os=bsd ;; convex-c38) basic_machine=c38-convex os=bsd ;; cray) basic_machine=j90-cray os=unicos ;; crds | unos) basic_machine=m68k-crds os= ;; da30) basic_machine=m68k-da30 os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec os= ;; delta88) basic_machine=m88k-motorola os=sysv3 ;; dicos) basic_machine=i686-pc os=dicos ;; djgpp) basic_machine=i586-pc os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=ose ;; gmicro) basic_machine=tron-gmicro os=sysv ;; go32) basic_machine=i386-pc os=go32 ;; h8300hms) basic_machine=h8300-hitachi os=hms ;; h8300xray) basic_machine=h8300-hitachi os=xray ;; h8500hms) basic_machine=h8500-hitachi os=hms ;; harris) basic_machine=m88k-harris os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp os=hpux ;; hp300bsd) basic_machine=m68k-hp os=bsd ;; hppaosf) basic_machine=hppa1.1-hp os=osf ;; hppro) basic_machine=hppa1.1-hp os=proelf ;; i386mach) basic_machine=i386-mach os=mach ;; isi68 | isi) basic_machine=m68k-isi os=sysv ;; m68knommu) basic_machine=m68k-unknown os=linux ;; magnum | m3230) basic_machine=mips-mips os=sysv ;; merlin) basic_machine=ns32k-utek os=sysv ;; mingw64) basic_machine=x86_64-pc os=mingw64 ;; mingw32) basic_machine=i686-pc os=mingw32 ;; mingw32ce) basic_machine=arm-unknown os=mingw32ce ;; monitor) basic_machine=m68k-rom68k os=coff ;; morphos) basic_machine=powerpc-unknown os=morphos ;; moxiebox) basic_machine=moxie-unknown os=moxiebox ;; msdos) basic_machine=i386-pc os=msdos ;; msys) basic_machine=i686-pc os=msys ;; mvs) basic_machine=i370-ibm os=mvs ;; nacl) basic_machine=le32-unknown os=nacl ;; ncr3000) basic_machine=i486-ncr os=sysv4 ;; netbsd386) basic_machine=i386-pc os=netbsd ;; netwinder) basic_machine=armv4l-rebel os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=newsos ;; news1000) basic_machine=m68030-sony os=newsos ;; necv70) basic_machine=v70-nec os=sysv ;; nh3000) basic_machine=m68k-harris os=cxux ;; nh[45]000) basic_machine=m88k-harris os=cxux ;; nindy960) basic_machine=i960-intel os=nindy ;; mon960) basic_machine=i960-intel os=mon960 ;; nonstopux) basic_machine=mips-compaq os=nonstopux ;; os400) basic_machine=powerpc-ibm os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=ose ;; os68k) basic_machine=m68k-none os=os68k ;; paragon) basic_machine=i860-intel os=osf ;; parisc) basic_machine=hppa-unknown os=linux ;; pw32) basic_machine=i586-unknown os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=rdos ;; rdos32) basic_machine=i386-pc os=rdos ;; rom68k) basic_machine=m68k-rom68k os=coff ;; sa29200) basic_machine=a29k-amd os=udi ;; sei) basic_machine=mips-sei os=seiux ;; sequent) basic_machine=i386-sequent os= ;; sps7) basic_machine=m68k-bull os=sysv2 ;; st2000) basic_machine=m68k-tandem os= ;; stratus) basic_machine=i860-stratus os=sysv4 ;; sun2) basic_machine=m68000-sun os= ;; sun2os3) basic_machine=m68000-sun os=sunos3 ;; sun2os4) basic_machine=m68000-sun os=sunos4 ;; sun3) basic_machine=m68k-sun os= ;; sun3os3) basic_machine=m68k-sun os=sunos3 ;; sun3os4) basic_machine=m68k-sun os=sunos4 ;; sun4) basic_machine=sparc-sun os= ;; sun4os3) basic_machine=sparc-sun os=sunos3 ;; sun4os4) basic_machine=sparc-sun os=sunos4 ;; sun4sol2) basic_machine=sparc-sun os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun os= ;; sv1) basic_machine=sv1-cray os=unicos ;; symmetry) basic_machine=i386-sequent os=dynix ;; t3e) basic_machine=alphaev5-cray os=unicos ;; t90) basic_machine=t90-cray os=unicos ;; toad1) basic_machine=pdp10-xkl os=tops20 ;; tpf) basic_machine=s390x-ibm os=tpf ;; udi29k) basic_machine=a29k-amd os=udi ;; ultra3) basic_machine=a29k-nyu os=sym1 ;; v810 | necv810) basic_machine=v810-nec os=none ;; vaxv) basic_machine=vax-dec os=sysv ;; vms) basic_machine=vax-dec os=vms ;; vsta) basic_machine=i386-pc os=vsta ;; vxworks960) basic_machine=i960-wrs os=vxworks ;; vxworks68) basic_machine=m68k-wrs os=vxworks ;; vxworks29k) basic_machine=a29k-wrs os=vxworks ;; xbox) basic_machine=i686-pc os=mingw32 ;; ymp) basic_machine=ymp-cray os=unicos ;; *) basic_machine=$1 os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull os=sysv3 ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi os=${os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray os=${os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $os in irix*) ;; *) os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony os=newsos ;; next | m*-next) cpu=m68k vendor=next case $os in openstep*) ;; nextstep*) ;; ns2*) os=nextstep2 ;; *) os=nextstep3 ;; esac ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde os=${os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x$os != x ] then case $os in # First match some system type aliases that might get confused # with valid system types. # solaris* is a basic system type, with this one exception. auroraux) os=auroraux ;; bluegene*) os=cnk ;; solaris1 | solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; solaris) os=solaris2 ;; unixware*) os=sysv4.2uw ;; gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # es1800 is here to avoid being matched by es* (a different OS) es1800*) os=ose ;; # Some version numbers need modification chorusos*) os=chorusos ;; isc) os=isc2.2 ;; sco6) os=sco5v6 ;; sco5) os=sco3.2v5 ;; sco4) os=sco3.2v4 ;; sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` ;; sco3.2v[4-9]* | sco5v6*) # Don't forget version if it is 3.2v4 or newer. ;; scout) # Don't match below ;; sco*) os=sco3.2v2 ;; psos*) os=psos ;; # Now accept the basic system types. # The portable systems comes first. # Each alternative MUST end in a * to match a version number. # sysv* is not here because it comes later, after sysvr4. gnu* | bsd* | mach* | minix* | genix* | ultrix* | irix* \ | *vms* | esix* | aix* | cnk* | sunos | sunos[34]*\ | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ | sym* | kopensolaris* | plan9* \ | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ | aos* | aros* | cloudabi* | sortix* | twizzler* \ | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \ | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \ | knetbsd* | mirbsd* | netbsd* \ | bitrig* | openbsd* | solidbsd* | libertybsd* | os108* \ | ekkobsd* | kfreebsd* | freebsd* | riscix* | lynxos* \ | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ | udi* | eabi* | lites* | ieee* | go32* | aux* | hcos* \ | chorusrdb* | cegcc* | glidix* \ | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ | midipix* | mingw32* | mingw64* | linux-gnu* | linux-android* \ | linux-newlib* | linux-musl* | linux-uclibc* \ | uxpv* | beos* | mpeix* | udk* | moxiebox* \ | interix* | uwin* | mks* | rhapsody* | darwin* \ | openstep* | oskit* | conix* | pw32* | nonstopux* \ | storm-chaos* | tops10* | tenex* | tops20* | its* \ | os2* | vos* | palmos* | uclinux* | nucleus* \ | morphos* | superux* | rtmk* | windiss* \ | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \ | skyos* | haiku* | rdos* | toppers* | drops* | es* \ | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ | nsk* | powerunix) # Remember, each alternative MUST END IN *, to match a version number. ;; qnx*) case $cpu in x86 | i*86) ;; *) os=nto-$os ;; esac ;; hiux*) os=hiuxwe2 ;; nto-qnx*) ;; nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; sim | xray | os68k* | v88r* \ | windows* | osx | abug | netware* | os9* \ | macos* | mpw* | magic* | mmixware* | mon960* | lnews*) ;; linux-dietlibc) os=linux-dietlibc ;; linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; lynx*178) os=lynxos178 ;; lynx*5) os=lynxos5 ;; lynx*) os=lynxos ;; mac*) os=`echo "$os" | sed -e 's|mac|macos|'` ;; opened*) os=openedition ;; os400*) os=os400 ;; sunos5*) os=`echo "$os" | sed -e 's|sunos5|solaris2|'` ;; sunos6*) os=`echo "$os" | sed -e 's|sunos6|solaris3|'` ;; wince*) os=wince ;; utek*) os=bsd ;; dynix*) os=bsd ;; acis*) os=aos ;; atheos*) os=atheos ;; syllable*) os=syllable ;; 386bsd) os=bsd ;; ctix* | uts*) os=sysv ;; nova*) os=rtmk-nova ;; ns2) os=nextstep2 ;; # Preserve the version number of sinix5. sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; sinix*) os=sysv4 ;; tpf*) os=tpf ;; triton*) os=sysv3 ;; oss*) os=sysv3 ;; svr4*) os=sysv4 ;; svr3) os=sysv3 ;; sysvr4) os=sysv4 ;; # This must come after sysvr4. sysv*) ;; ose*) os=ose ;; *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) os=mint ;; zvmoe) os=zvmoe ;; dicos*) os=dicos ;; pikeos*) # Until real need of OS specific support for # particular features comes up, bare metal # configurations are quite functional. case $cpu in arm*) os=eabi ;; *) os=elf ;; esac ;; nacl*) ;; ios) ;; none) ;; *-eabi) ;; *) echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $cpu-$vendor in score-*) os=elf ;; spu-*) os=elf ;; *-acorn) os=riscix1.2 ;; arm*-rebel) os=linux ;; arm*-semi) os=aout ;; c4x-* | tic4x-*) os=coff ;; c8051-*) os=elf ;; clipper-intergraph) os=clix ;; hexagon-*) os=elf ;; tic54x-*) os=coff ;; tic55x-*) os=coff ;; tic6x-*) os=coff ;; # This must come before the *-dec entry. pdp10-*) os=tops20 ;; pdp11-*) os=none ;; *-dec | vax-*) os=ultrix4.2 ;; m68*-apollo) os=domain ;; i386-sun) os=sunos4.0.2 ;; m68000-sun) os=sunos3 ;; m68*-cisco) os=aout ;; mep-*) os=elf ;; mips*-cisco) os=elf ;; mips*-*) os=elf ;; or32-*) os=coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=sysv3 ;; sparc-* | *-sun) os=sunos4.1.1 ;; pru-*) os=elf ;; *-be) os=beos ;; *-ibm) os=aix ;; *-knuth) os=mmixware ;; *-wec) os=proelf ;; *-winbond) os=proelf ;; *-oki) os=proelf ;; *-hp) os=hpux ;; *-hitachi) os=hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=sysv ;; *-cbm) os=amigaos ;; *-dg) os=dgux ;; *-dolphin) os=sysv3 ;; m68k-ccur) os=rtu ;; m88k-omron*) os=luna ;; *-next) os=nextstep ;; *-sequent) os=ptx ;; *-crds) os=unos ;; *-ns) os=genix ;; i370-*) os=mvs ;; *-gould) os=sysv ;; *-highlevel) os=bsd ;; *-encore) os=bsd ;; *-sgi) os=irix ;; *-siemens) os=sysv4 ;; *-masscomp) os=rtu ;; f30[01]-fujitsu | f700-fujitsu) os=uxpv ;; *-rom68k) os=coff ;; *-*bug) os=coff ;; *-apple) os=macos ;; *-atari*) os=mint ;; *-wrs) os=vxworks ;; *) os=none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $os in riscix*) vendor=acorn ;; sunos*) vendor=sun ;; cnk*|-aix*) vendor=ibm ;; beos*) vendor=be ;; hpux*) vendor=hp ;; mpeix*) vendor=hp ;; hiux*) vendor=hitachi ;; unos*) vendor=crds ;; dgux*) vendor=dg ;; luna*) vendor=omron ;; genix*) vendor=ns ;; clix*) vendor=intergraph ;; mvs* | opened*) vendor=ibm ;; os400*) vendor=ibm ;; ptx*) vendor=sequent ;; tpf*) vendor=ibm ;; vxsim* | vxworks* | windiss*) vendor=wrs ;; aux*) vendor=apple ;; hms*) vendor=hitachi ;; mpw* | macos*) vendor=apple ;; *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) vendor=atari ;; vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor-$os" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: openldap-2.5.11+dfsg/build/openldap.m40000644000175000017500000006115114172327167016206 0ustar ryanryandnl OpenLDAP Autoconf Macros dnl $OpenLDAP$ dnl This work is part of OpenLDAP Software . dnl dnl Copyright 1998-2022 The OpenLDAP Foundation. dnl All rights reserved. dnl dnl Redistribution and use in source and binary forms, with or without dnl modification, are permitted only as authorized by the OpenLDAP dnl Public License. dnl dnl A copy of this license is available in the file LICENSE in the dnl top-level directory of the distribution or, alternatively, at dnl . dnl dnl -------------------------------------------------------------------- dnl Restricted form of AC_ARG_ENABLE that limits user options dnl dnl $1 = option name dnl $2 = help-string dnl $3 = default value (auto). "--" means do not set it by default dnl $4 = allowed values (auto yes no) dnl $5 = overridden default AC_DEFUN([OL_ARG_ENABLE], [# OpenLDAP --enable-$1 pushdef([ol_DefVal],ifelse($3,,auto,$3)) AC_ARG_ENABLE($1,ifelse($4,,[$2],[$2] translit([$4],[ ],[|])) ifelse($3,--,,@<:@ol_DefVal@:>@),[ ol_arg=invalid for ol_val in ifelse($4,,[auto yes no],[$4]) ; do if test "$enableval" = "$ol_val" ; then ol_arg="$ol_val" fi done if test "$ol_arg" = "invalid" ; then AC_MSG_ERROR(bad value $enableval for --enable-$1) fi ol_enable_$1="$ol_arg" ]ifelse($3,--,,[, [ ol_enable_$1=ifelse($5,,ol_DefVal,[${]$5[:-]ol_DefVal[}])]]))dnl dnl AC_MSG_RESULT([OpenLDAP -enable-$1 $ol_enable_$1]) popdef([ol_DefVal]) # end --enable-$1 ])dnl dnl dnl -------------------------------------------------------------------- dnl Restricted form of AC_ARG_WITH that limits user options dnl dnl $1 = option name dnl $2 = help-string dnl $3 = default value (no) dnl $4 = allowed values (yes or no) AC_DEFUN([OL_ARG_WITH], [# OpenLDAP --with-$1 AC_ARG_WITH($1,[$2 @<:@]ifelse($3,,yes,$3)@:>@,[ ol_arg=invalid for ol_val in ifelse($4,,[yes no],[$4]) ; do if test "$withval" = "$ol_val" ; then ol_arg="$ol_val" fi done if test "$ol_arg" = "invalid" ; then AC_MSG_ERROR(bad value $withval for --with-$1) fi ol_with_$1="$ol_arg" ], [ ol_with_$1=ifelse($3,,"no","$3")])dnl dnl AC_MSG_RESULT([OpenLDAP --with-$1 $ol_with_$1]) # end --with-$1 ])dnl dnl ==================================================================== dnl Check for dependency generation flag AC_DEFUN([OL_MKDEPEND], [# test for make depend flag OL_MKDEP= OL_MKDEP_FLAGS= if test -z "${MKDEP}"; then OL_MKDEP="${CC-cc}" if test -z "${MKDEP_FLAGS}"; then AC_CACHE_CHECK([for ${OL_MKDEP} depend flag], ol_cv_mkdep, [ ol_cv_mkdep=no for flag in "-M" "-xM"; do cat > conftest.c </dev/null 2>&1 then if test ! -f conftest."${ac_object}" ; then ol_cv_mkdep=$flag OL_MKDEP_FLAGS="$flag" break fi fi done rm -f conftest* ]) test "$ol_cv_mkdep" = no && OL_MKDEP=":" else cc_cv_mkdep=yes OL_MKDEP_FLAGS="${MKDEP_FLAGS}" fi else cc_cv_mkdep=yes OL_MKDEP="${MKDEP}" OL_MKDEP_FLAGS="${MKDEP_FLAGS}" fi AC_SUBST(OL_MKDEP) AC_SUBST(OL_MKDEP_FLAGS) ]) dnl dnl ==================================================================== dnl Check if system uses EBCDIC instead of ASCII AC_DEFUN([OL_CPP_EBCDIC], [# test for EBCDIC AC_CACHE_CHECK([for EBCDIC],ol_cv_cpp_ebcdic,[ AC_PREPROC_IFELSE([AC_LANG_SOURCE([[ #if !('M' == 0xd4) #include <__ASCII__/generate_error.h> #endif ]])],[ol_cv_cpp_ebcdic=yes],[ol_cv_cpp_ebcdic=no])]) if test $ol_cv_cpp_ebcdic = yes ; then AC_DEFINE(HAVE_EBCDIC,1, [define if system uses EBCDIC instead of ASCII]) fi ]) dnl dnl -------------------------------------------------------------------- dnl Check for MSVC AC_DEFUN([OL_MSVC], [AC_REQUIRE_CPP()dnl AC_CACHE_CHECK([whether we are using MS Visual C++], ol_cv_msvc, [AC_PREPROC_IFELSE([AC_LANG_SOURCE([[ #ifndef _MSC_VER #include <__FOO__/generate_error.h> #endif ]])],[ol_cv_msvc=yes],[ol_cv_msvc=no])])]) dnl -------------------------------------------------------------------- dnl OpenLDAP version of STDC header check w/ EBCDIC support AC_DEFUN([OL_HEADER_STDC], [AC_REQUIRE_CPP()dnl AC_REQUIRE([OL_CPP_EBCDIC])dnl AC_CACHE_CHECK([for ANSI C header files], ol_cv_header_stdc, [AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include #include #include #include ]])],[ol_cv_header_stdc=yes],[ol_cv_header_stdc=no]) if test $ol_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. AC_EGREP_HEADER(memchr, string.h, , ol_cv_header_stdc=no) fi if test $ol_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. AC_EGREP_HEADER(free, stdlib.h, , ol_cv_header_stdc=no) fi if test $ol_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. AC_RUN_IFELSE([AC_LANG_SOURCE([[#include #ifndef HAVE_EBCDIC # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } ]])],[],[ol_cv_header_stdc=no],[:]) fi]) if test $ol_cv_header_stdc = yes; then AC_DEFINE(STDC_HEADERS) fi ac_cv_header_stdc=disable ]) dnl dnl ==================================================================== dnl DNS resolver macros AC_DEFUN([OL_RESOLVER_TRY], [if test $ol_cv_lib_resolver = no ; then AC_CACHE_CHECK([for resolver link (]ifelse($2,,default,$2)[)],[$1], [ ol_RESOLVER_LIB=ifelse($2,,,$2) ol_LIBS=$LIBS LIBS="$ol_RESOLVER_LIB $LIBS" AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #ifdef HAVE_SYS_TYPES_H # include #endif #include #ifdef HAVE_ARPA_NAMESER_H # include #endif #ifdef HAVE_RESOLV_H # include #endif ]], [[{ int len, status; char *request = NULL; unsigned char reply[64*1024]; unsigned char host[64*1024]; unsigned char *p; #ifdef NS_HFIXEDSZ /* Bind 8/9 interface */ len = res_query(request, ns_c_in, ns_t_srv, reply, sizeof(reply)); #else /* Bind 4 interface */ # ifndef T_SRV # define T_SRV 33 # endif len = res_query(request, C_IN, T_SRV, reply, sizeof(reply)); #endif p = reply; #ifdef NS_HFIXEDSZ /* Bind 8/9 interface */ p += NS_HFIXEDSZ; #elif defined(HFIXEDSZ) /* Bind 4 interface w/ HFIXEDSZ */ p += HFIXEDSZ; #else /* Bind 4 interface w/o HFIXEDSZ */ p += sizeof(HEADER); #endif status = dn_expand( reply, reply+len, p, host, sizeof(host)); }]])],[$1=yes],[$1=no]) LIBS="$ol_LIBS" ]) if test $$1 = yes ; then ol_cv_lib_resolver=ifelse($2,,yes,$2) fi fi ]) dnl -------------------------------------------------------------------- dnl Try to locate appropriate library AC_DEFUN([OL_RESOLVER_LINK], [ol_cv_lib_resolver=no OL_RESOLVER_TRY(ol_cv_resolver_none) OL_RESOLVER_TRY(ol_cv_resolver_resolv,[-lresolv]) OL_RESOLVER_TRY(ol_cv_resolver_bind,[-lbind]) ]) dnl dnl ==================================================================== dnl Check POSIX Thread version dnl dnl defines ol_cv_pthread_version to 4, 5, 6, 7, 8, 10, depending on the dnl version of the POSIX.4a Draft that is implemented. dnl 10 == POSIX.4a Final == POSIX.1c-1996 for our purposes. dnl Existence of pthread.h should be tested separately. dnl dnl tests: dnl pthread_detach() was dropped in Draft 8, it is present dnl in every other version dnl PTHREAD_CREATE_UNDETACHED is only in Draft 7, it was called dnl PTHREAD_CREATE_JOINABLE after that dnl pthread_attr_create was renamed to pthread_attr_init in Draft 6. dnl Draft 6-10 has _init, Draft 4-5 has _create. dnl pthread_attr_default was dropped in Draft 6, only 4 and 5 have it dnl PTHREAD_MUTEX_INITIALIZER was introduced in Draft 5. It's not dnl interesting to us because we don't try to statically dnl initialize mutexes. 5-10 has it. dnl dnl Draft 9 and 10 are equivalent for our purposes. dnl AC_DEFUN([OL_POSIX_THREAD_VERSION], [AC_CACHE_CHECK([POSIX thread version],[ol_cv_pthread_version],[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ # include ]], [[ int i = PTHREAD_CREATE_JOINABLE; ]])],[ AC_EGREP_HEADER(pthread_detach,pthread.h, ol_cv_pthread_version=10, ol_cv_pthread_version=8)],[ AC_EGREP_CPP(draft7,[ # include # ifdef PTHREAD_CREATE_UNDETACHED draft7 # endif ], ol_cv_pthread_version=7, [ AC_EGREP_HEADER(pthread_attr_init,pthread.h, ol_cv_pthread_version=6, [ AC_EGREP_CPP(draft5,[ # include #ifdef PTHREAD_MUTEX_INITIALIZER draft5 #endif ], ol_cv_pthread_version=5, ol_cv_pthread_version=4) ]) ]) ]) ]) ])dnl dnl dnl -------------------------------------------------------------------- AC_DEFUN([OL_PTHREAD_TEST_INCLUDES], [[ /* pthread test headers */ #include #if HAVE_PTHREADS < 7 #include #endif #ifndef NULL #define NULL (void*)0 #endif static void *task(p) void *p; { return (void *) (p == NULL); } ]]) AC_DEFUN([OL_PTHREAD_TEST_FUNCTION],[[ /* pthread test function */ #ifndef PTHREAD_CREATE_DETACHED #define PTHREAD_CREATE_DETACHED 1 #endif pthread_t t; int status; int detach = PTHREAD_CREATE_DETACHED; #if HAVE_PTHREADS > 4 /* Final pthreads */ pthread_attr_t attr; status = pthread_attr_init(&attr); if( status ) return status; #if HAVE_PTHREADS < 7 status = pthread_attr_setdetachstate(&attr, &detach); if( status < 0 ) status = errno; #else status = pthread_attr_setdetachstate(&attr, detach); #endif if( status ) return status; status = pthread_create( &t, &attr, task, NULL ); #if HAVE_PTHREADS < 7 if( status < 0 ) status = errno; #endif if( status ) return status; #else /* Draft 4 pthreads */ status = pthread_create( &t, pthread_attr_default, task, NULL ); if( status ) return errno; /* give thread a chance to complete */ /* it should remain joinable and hence detachable */ sleep( 1 ); status = pthread_detach( &t ); if( status ) return errno; #endif #ifdef HAVE_LINUX_THREADS pthread_kill_other_threads_np(); #endif return 0; ]]) AC_DEFUN([OL_PTHREAD_TEST_PROGRAM], [AC_LANG_SOURCE([OL_PTHREAD_TEST_INCLUDES int main(argc, argv) int argc; char **argv; { OL_PTHREAD_TEST_FUNCTION } ])]) dnl -------------------------------------------------------------------- AC_DEFUN([OL_PTHREAD_TRY], [# Pthread try link: $1 ($2) if test "$ol_link_threads" = no ; then # try $1 AC_CACHE_CHECK([for pthread link with $1], [$2], [ # save the flags ol_LIBS="$LIBS" LIBS="$1 $LIBS" AC_RUN_IFELSE([OL_PTHREAD_TEST_PROGRAM], [$2=yes], [$2=no], [AC_LINK_IFELSE([AC_LANG_PROGRAM(OL_PTHREAD_TEST_INCLUDES, OL_PTHREAD_TEST_FUNCTION)], [$2=yes], [$2=no])]) # restore the LIBS LIBS="$ol_LIBS" ]) if test $$2 = yes ; then ol_link_pthreads="$1" ol_link_threads=posix fi fi ]) dnl dnl ==================================================================== dnl Check GNU Pth pthread Header dnl dnl defines ol_cv_header linux_threads to 'yes' or 'no' dnl 'no' implies pthreads.h is not LinuxThreads or pthreads.h dnl doesn't exist. Existence of pthread.h should separately dnl checked. dnl AC_DEFUN([OL_HEADER_GNU_PTH_PTHREAD_H], [ AC_CACHE_CHECK([for GNU Pth pthread.h], [ol_cv_header_gnu_pth_pthread_h], [AC_EGREP_CPP(__gnu_pth__, [#include #ifdef _POSIX_THREAD_IS_GNU_PTH __gnu_pth__; #endif ], [ol_cv_header_gnu_pth_pthread_h=yes], [ol_cv_header_gnu_pth_pthread_h=no]) ]) ])dnl dnl ==================================================================== dnl Check for NT Threads AC_DEFUN([OL_NT_THREADS], [ AC_CHECK_FUNC(_beginthread) if test $ac_cv_func__beginthread = yes ; then AC_DEFINE(HAVE_NT_THREADS,1,[if you have NT Threads]) ol_cv_nt_threads=yes fi ]) dnl ==================================================================== dnl Check LinuxThreads Header dnl dnl defines ol_cv_header linux_threads to 'yes' or 'no' dnl 'no' implies pthreads.h is not LinuxThreads or pthreads.h dnl doesn't exist. Existence of pthread.h should separately dnl checked. dnl AC_DEFUN([OL_HEADER_LINUX_THREADS], [ AC_CACHE_CHECK([for LinuxThreads pthread.h], [ol_cv_header_linux_threads], [AC_EGREP_CPP(pthread_kill_other_threads_np, [#include ], [ol_cv_header_linux_threads=yes], [ol_cv_header_linux_threads=no]) ]) if test $ol_cv_header_linux_threads = yes; then AC_DEFINE(HAVE_LINUX_THREADS,1,[if you have LinuxThreads]) fi ])dnl dnl -------------------------------------------------------------------- dnl Check LinuxThreads Implementation dnl dnl defines ol_cv_sys_linux_threads to 'yes' or 'no' dnl 'no' implies pthreads implementation is not LinuxThreads. dnl AC_DEFUN([OL_SYS_LINUX_THREADS], [ AC_CHECK_FUNCS(pthread_kill_other_threads_np) AC_CACHE_CHECK([for LinuxThreads implementation], [ol_cv_sys_linux_threads], [ol_cv_sys_linux_threads=$ac_cv_func_pthread_kill_other_threads_np]) ])dnl dnl dnl -------------------------------------------------------------------- dnl Check LinuxThreads consistency AC_DEFUN([OL_LINUX_THREADS], [ AC_REQUIRE([OL_HEADER_LINUX_THREADS]) AC_REQUIRE([OL_SYS_LINUX_THREADS]) AC_CACHE_CHECK([for LinuxThreads consistency], [ol_cv_linux_threads], [ if test $ol_cv_header_linux_threads = yes && test $ol_cv_sys_linux_threads = yes; then ol_cv_linux_threads=yes elif test $ol_cv_header_linux_threads = no && test $ol_cv_sys_linux_threads = no; then ol_cv_linux_threads=no else ol_cv_linux_threads=error fi ]) ])dnl dnl dnl ==================================================================== dnl Check for POSIX Regex AC_DEFUN([OL_POSIX_REGEX], [ AC_CACHE_CHECK([for compatible POSIX regex],ol_cv_c_posix_regex,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include static char *pattern, *string; main() { int rc; regex_t re; pattern = "^A"; if(regcomp(&re, pattern, 0)) { return -1; } string = "ALL MATCH"; rc = regexec(&re, string, 0, (void*)0, 0); regfree(&re); return rc; }]])],[ol_cv_c_posix_regex=yes],[ol_cv_c_posix_regex=no],[ol_cv_c_posix_regex=cross])]) ]) dnl dnl ==================================================================== dnl Check if toupper() requires islower() to be called first AC_DEFUN([OL_C_UPPER_LOWER], [AC_CACHE_CHECK([if toupper() requires islower()],ol_cv_c_upper_lower,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include main() { if ('C' == toupper('C')) exit(0); else exit(1); }]])],[ol_cv_c_upper_lower=no],[ol_cv_c_upper_lower=yes],[ol_cv_c_upper_lower=safe])]) if test $ol_cv_c_upper_lower != no ; then AC_DEFINE(C_UPPER_LOWER,1, [define if toupper() requires islower()]) fi ]) dnl dnl ==================================================================== dnl Error string checks dnl dnl Check for declaration of sys_errlist in one of stdio.h and errno.h. dnl Declaration of sys_errlist on BSD4.4 interferes with our declaration. dnl Reported by Keith Bostic. AC_DEFUN([OL_SYS_ERRLIST], [AC_CACHE_CHECK([existence of sys_errlist],ol_cv_have_sys_errlist,[ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[char *c = (char *) *sys_errlist]])],[ol_cv_have_sys_errlist=yes],[ol_cv_have_sys_errlist=no])]) if test $ol_cv_have_sys_errlist = yes ; then AC_DEFINE(HAVE_SYS_ERRLIST,1, [define if you actually have sys_errlist in your libs]) AC_CACHE_CHECK([declaration of sys_errlist],ol_cv_dcl_sys_errlist,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include #include #include #ifdef _WIN32 #include #endif ]], [[char *c = (char *) *sys_errlist]])],[ol_cv_dcl_sys_errlist=yes], [ol_cv_dcl_sys_errlist=no])]) # # It's possible (for near-UNIX clones) that sys_errlist doesn't exist if test $ol_cv_dcl_sys_errlist = no ; then AC_DEFINE(DECL_SYS_ERRLIST,1, [define if sys_errlist is not declared in stdio.h or errno.h]) fi fi ])dnl dnl dnl ==================================================================== dnl glibc supplies a non-standard strerror_r if _GNU_SOURCE is defined. dnl It's actually preferable to the POSIX version, if available. AC_DEFUN([OL_NONPOSIX_STRERROR_R], [AC_CACHE_CHECK([non-posix strerror_r],ol_cv_nonposix_strerror_r,[ AC_EGREP_CPP(strerror_r,[#include ], ol_decl_strerror_r=yes, ol_decl_strerror_r=no)dnl if test $ol_decl_strerror_r = yes ; then AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ /* from autoconf 2.59 */ char buf[100]; char x = *strerror_r (0, buf, sizeof buf); char *p = strerror_r (0, buf, sizeof buf); ]])],[ol_cv_nonposix_strerror_r=yes],[ol_cv_nonposix_strerror_r=no]) else AC_RUN_IFELSE([AC_LANG_SOURCE([[ main() { char buf[100]; buf[0] = 0; strerror_r( 1, buf, sizeof buf ); exit( buf[0] == 0 ); } ]])],[ol_cv_nonposix_strerror_r=yes],[ol_cv_nonposix_strerror_r=no],[ol_cv_nonposix_strerror_r=no]) fi ]) if test $ol_cv_nonposix_strerror_r = yes ; then AC_DEFINE(HAVE_NONPOSIX_STRERROR_R,1, [define if strerror_r returns char* instead of int]) fi ])dnl dnl AC_DEFUN([OL_STRERROR], [AC_CHECK_FUNCS(strerror strerror_r) ol_cv_func_strerror_r=no if test "${ac_cv_func_strerror_r}" = yes ; then OL_NONPOSIX_STRERROR_R elif test "${ac_cv_func_strerror}" = no ; then OL_SYS_ERRLIST fi ])dnl dnl ==================================================================== dnl Early MIPS compilers (used in Ultrix 4.2) don't like dnl "int x; int *volatile a = &x; *a = 0;" dnl -- borrowed from PDKSH AC_DEFUN([OL_C_VOLATILE], [AC_CACHE_CHECK(if compiler understands volatile, ol_cv_c_volatile, [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[int x, y, z;]], [[volatile int a; int * volatile b = x ? &y : &z; /* Older MIPS compilers (eg., in Ultrix 4.2) don't like *b = 0 */ *b = 0;]])],[ol_cv_c_volatile=yes],[ol_cv_c_volatile=no])]) if test $ol_cv_c_volatile = yes; then : else AC_DEFINE(volatile,,[define as empty if volatile is not supported]) fi ])dnl dnl dnl ==================================================================== dnl Look for fetch(3) AC_DEFUN([OL_LIB_FETCH], [ol_LIBS=$LIBS LIBS="-lfetch -lcom_err $LIBS" AC_CACHE_CHECK([fetch(3) library],ol_cv_lib_fetch,[ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #ifdef HAVE_SYS_PARAM_H #include #endif #include #include ]], [[struct url *u = fetchParseURL("file:///"); ]])],[ol_cv_lib_fetch=yes],[ol_cv_lib_fetch=no])]) LIBS=$ol_LIBS if test $ol_cv_lib_fetch != no ; then ol_link_fetch="-lfetch -lcom_err" AC_DEFINE(HAVE_FETCH,1, [define if you actually have FreeBSD fetch(3)]) fi ])dnl dnl dnl ==================================================================== dnl Define inet_aton is available AC_DEFUN([OL_FUNC_INET_ATON], [AC_CACHE_CHECK([for inet_aton()], ol_cv_func_inet_aton, [AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include # ifdef HAVE_SYS_SELECT_H # include # endif # include # ifdef HAVE_ARPA_INET_H # include # endif #endif ]], [[struct in_addr in; int rc = inet_aton( "255.255.255.255", &in );]])],[ol_cv_func_inet_aton=yes],[ol_cv_func_inet_aton=no])]) if test $ol_cv_func_inet_aton != no; then AC_DEFINE(HAVE_INET_ATON, 1, [define to you inet_aton(3) is available]) fi ])dnl dnl dnl ==================================================================== dnl check no of arguments for ctime_r AC_DEFUN([OL_FUNC_CTIME_R_NARGS], [AC_CACHE_CHECK(number of arguments of ctime_r, ol_cv_func_ctime_r_nargs, [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[time_t ti; char *buffer; ctime_r(&ti,buffer,32);]])],[ol_cv_func_ctime_r_nargs3=yes],[ol_cv_func_ctime_r_nargs3=no]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[time_t ti; char *buffer; ctime_r(&ti,buffer);]])],[ol_cv_func_ctime_r_nargs2=yes],[ol_cv_func_ctime_r_nargs2=no]) if test $ol_cv_func_ctime_r_nargs3 = yes && test $ol_cv_func_ctime_r_nargs2 = no ; then ol_cv_func_ctime_r_nargs=3 elif test $ol_cv_func_ctime_r_nargs3 = no && test $ol_cv_func_ctime_r_nargs2 = yes ; then ol_cv_func_ctime_r_nargs=2 else ol_cv_func_ctime_r_nargs=0 fi ]) if test $ol_cv_func_ctime_r_nargs -gt 1 ; then AC_DEFINE_UNQUOTED(CTIME_R_NARGS, $ol_cv_func_ctime_r_nargs, [set to the number of arguments ctime_r() expects]) fi ])dnl dnl dnl -------------------------------------------------------------------- dnl check return type of ctime_r() AC_DEFUN([OL_FUNC_CTIME_R_TYPE], [AC_CACHE_CHECK(return type of ctime_r, ol_cv_func_ctime_r_type, [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[extern int (ctime_r)();]])],[ol_cv_func_ctime_r_type="int"],[ol_cv_func_ctime_r_type="charp"]) ]) if test $ol_cv_func_ctime_r_type = "int" ; then AC_DEFINE(CTIME_R_RETURNS_INT,1, [define if ctime_r() returns int]) fi ])dnl dnl ==================================================================== dnl check no of arguments for gethostbyname_r AC_DEFUN([OL_FUNC_GETHOSTBYNAME_R_NARGS], [AC_CACHE_CHECK(number of arguments of gethostbyname_r, ol_cv_func_gethostbyname_r_nargs, [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #include #include #include #define BUFSIZE (sizeof(struct hostent)+10)]], [[struct hostent hent; char buffer[BUFSIZE]; int bufsize=BUFSIZE;int h_errno; (void)gethostbyname_r("segovia.cs.purdue.edu", &hent, buffer, bufsize, &h_errno);]])],[ol_cv_func_gethostbyname_r_nargs5=yes],[ol_cv_func_gethostbyname_r_nargs5=no]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #include #include #include #define BUFSIZE (sizeof(struct hostent)+10)]], [[struct hostent hent;struct hostent *rhent; char buffer[BUFSIZE]; int bufsize=BUFSIZE;int h_errno; (void)gethostbyname_r("localhost", &hent, buffer, bufsize, &rhent, &h_errno);]])],[ol_cv_func_gethostbyname_r_nargs6=yes],[ol_cv_func_gethostbyname_r_nargs6=no]) if test $ol_cv_func_gethostbyname_r_nargs5 = yes && test $ol_cv_func_gethostbyname_r_nargs6 = no ; then ol_cv_func_gethostbyname_r_nargs=5 elif test $ol_cv_func_gethostbyname_r_nargs5 = no && test $ol_cv_func_gethostbyname_r_nargs6 = yes ; then ol_cv_func_gethostbyname_r_nargs=6 else ol_cv_func_gethostbyname_r_nargs=0 fi ]) if test $ol_cv_func_gethostbyname_r_nargs -gt 1 ; then AC_DEFINE_UNQUOTED(GETHOSTBYNAME_R_NARGS, $ol_cv_func_gethostbyname_r_nargs, [set to the number of arguments gethostbyname_r() expects]) fi ])dnl dnl dnl check no of arguments for gethostbyaddr_r AC_DEFUN([OL_FUNC_GETHOSTBYADDR_R_NARGS], [AC_CACHE_CHECK(number of arguments of gethostbyaddr_r, [ol_cv_func_gethostbyaddr_r_nargs], [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #include #include #include #define BUFSIZE (sizeof(struct hostent)+10)]], [[struct hostent hent; char buffer[BUFSIZE]; struct in_addr add; size_t alen=sizeof(struct in_addr); int bufsize=BUFSIZE;int h_errno; (void)gethostbyaddr_r( (void *)&(add.s_addr), alen, AF_INET, &hent, buffer, bufsize, &h_errno);]])],[ol_cv_func_gethostbyaddr_r_nargs7=yes],[ol_cv_func_gethostbyaddr_r_nargs7=no]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #include #include #include #define BUFSIZE (sizeof(struct hostent)+10)]], [[struct hostent hent; struct hostent *rhent; char buffer[BUFSIZE]; struct in_addr add; size_t alen=sizeof(struct in_addr); int bufsize=BUFSIZE;int h_errno; (void)gethostbyaddr_r( (void *)&(add.s_addr), alen, AF_INET, &hent, buffer, bufsize, &rhent, &h_errno);]])],[ol_cv_func_gethostbyaddr_r_nargs8=yes],[ol_cv_func_gethostbyaddr_r_nargs8=no]) if test $ol_cv_func_gethostbyaddr_r_nargs7 = yes && test $ol_cv_func_gethostbyaddr_r_nargs8 = no ; then ol_cv_func_gethostbyaddr_r_nargs=7 elif test $ol_cv_func_gethostbyaddr_r_nargs7 = no && test $ol_cv_func_gethostbyaddr_r_nargs8 = yes ; then ol_cv_func_gethostbyaddr_r_nargs=8 else ol_cv_func_gethostbyaddr_r_nargs=0 fi ]) if test $ol_cv_func_gethostbyaddr_r_nargs -gt 1 ; then AC_DEFINE_UNQUOTED(GETHOSTBYADDR_R_NARGS, $ol_cv_func_gethostbyaddr_r_nargs, [set to the number of arguments gethostbyaddr_r() expects]) fi ])dnl dnl dnl -------------------------------------------------------------------- dnl Check for Cyrus SASL version compatibility AC_DEFUN([OL_SASL_COMPAT], [AC_CACHE_CHECK([Cyrus SASL library version], [ol_cv_sasl_compat],[ AC_EGREP_CPP(__sasl_compat,[ #ifdef HAVE_SASL_SASL_H #include #else #include #endif /* Require 2.1.15+ */ #if SASL_VERSION_MAJOR == 2 && SASL_VERSION_MINOR > 1 char *__sasl_compat = "2.2+ or better okay (we guess)"; #elif SASL_VERSION_MAJOR == 2 && SASL_VERSION_MINOR == 1 \ && SASL_VERSION_STEP >=15 char *__sasl_compat = "2.1.15+ or better okay"; #endif ], [ol_cv_sasl_compat=yes], [ol_cv_sasl_compat=no])]) ]) openldap-2.5.11+dfsg/build/version.sh0000755000175000017500000000257314172327167016171 0ustar ryanryan#! /bin/sh # $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . DIR=`dirname $0` . $DIR/version.var if test $ol_patch != X ; then ol_version=${ol_major}.${ol_minor}.${ol_patch} ol_api_lib_release=${ol_major}.${ol_minor} ol_type=Release elif test $ol_minor != X ; then ol_version=${ol_major}.${ol_minor}.${ol_patch} ol_api_lib_release=${ol_major}.${ol_minor}.releng ol_type=Engineering else ol_version=${ol_major}.${ol_minor} ol_api_lib_release=${ol_major}.devel ol_type=Devel fi ol_string="${ol_package} ${ol_version}-${ol_type}" ol_api_lib_version="${ol_api_current}:${ol_api_revision}:${ol_api_age}" echo OL_PACKAGE=\"${ol_package}\" echo OL_MAJOR=$ol_major echo OL_MINOR=$ol_minor echo OL_PATCH=$ol_patch echo OL_API_INC=$ol_api_inc echo OL_API_LIB_RELEASE=$ol_api_lib_release echo OL_API_LIB_VERSION=$ol_api_lib_version echo OL_VERSION=$ol_version echo OL_TYPE=$ol_type echo OL_STRING=\"${ol_string}\" echo OL_RELEASE_DATE=\"${ol_release_date}\" openldap-2.5.11+dfsg/build/mkrelease0000755000175000017500000000366614172327167016047 0ustar ryanryan#! /bin/sh # $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . # # Make a release # # # This script MUST NOT add files to the export nor modify # any file in the export, exceptions: # make guide.html # set -e # exit immediately if any errors occur if test $# != 3 ; then echo 'usage: mkrelease REPO RELNAME TAG' exit 1 fi REPO=$1 shift RELNAME=openldap-$1 shift TAG=$1 shift #Linux #SHA="sha1sum" #MD="md5sum" #BSD #SHA="sha1" #MD="md5" #OpenSSL #SHA="openssl sha1" SHA3="openssl sha3-512" #MD="openssl md5" if test -e $RELNAME ; then echo "error: $RELNAME exists" exit 1 fi echo Release: $RELNAME echo Tag: $TAG git archive --format=tar --prefix="${RELNAME}/" --remote="${REPO}" "$TAG" | tar xvf - if test ! -d $RELNAME ; then echo "error: $RELNAME doesn't exists" exit 1 fi if test -e $RELNAME/doc/guide/admin/guide.sdf ; then echo "build guide..." ( cd $RELNAME/doc/guide/admin ; make guide.html ) else echo "No guide" fi if test -e $RELNAME/libraries/liblunicode/ucdata/uctable.h ; then echo "touching uctable.h..." touch $RELNAME/libraries/liblunicode/ucdata/uctable.h fi if test ! -e $RELNAME/build/version.sh ; then echo "No build version" OL_STRING="something" else eval `$RELNAME/build/version.sh` fi echo "Rolling up $OL_STRING ..." tar cf $RELNAME.tar $RELNAME gzip -9 -c $RELNAME.tar > $RELNAME.tgz #${MD} $RELNAME.tgz > $RELNAME.md5 #${SHA} $RELNAME.tgz > $RELNAME.sha1 ${SHA3} $RELNAME.tgz > $RELNAME.sha3-512 rm -f $RELNAME.tar ls -l $RELNAME.* echo "Made $OL_STRING as $RELNAME.tgz" openldap-2.5.11+dfsg/build/README0000644000175000017500000000054514172327167015022 0ustar ryanryanThe OpenLDAP build environment relies on non-standard versions of configuration tools: Autoconf 2.13.1 Automake 1.4a Libtool 1.4.3 The autoconf/automake releases used are available at: ftp://ftp.openldap.org/pub/tools/ The libtool release used is available from: ftp://ftp.gnu.org/ but with ltmain.sh replaced with versions found in this directory. openldap-2.5.11+dfsg/build/version.h0000644000175000017500000000115714172327167016000 0ustar ryanryan/* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ static const char copyright[] = "Copyright 1998-2022 The OpenLDAP Foundation. All rights reserved.\n" "COPYING RESTRICTIONS APPLY.\n"; openldap-2.5.11+dfsg/build/info.mk0000644000175000017500000000122514172327167015422 0ustar ryanryan# $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . ##--------------------------------------------------------------------------- # # Makefile Template for Non-Source Directories # Makefile: $(top_srcdir)/build/info.mk openldap-2.5.11+dfsg/build/ltsugar.m40000644000175000017500000001044014172327167016060 0ustar ryanryan# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59, which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) openldap-2.5.11+dfsg/build/rules.mk0000644000175000017500000000166714172327167015633 0ustar ryanryan# $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . ##--------------------------------------------------------------------------- # # Makefile Template for Programs # all-common: $(PROGRAMS) FORCE clean-common: FORCE $(RM) $(PROGRAMS) $(XPROGRAMS) $(XSRCS) *.o *.lo a.out core *.core \ .libs/* *.exe depend-common: FORCE $(MKDEP) $(DEFS) $(DEFINES) $(SRCS) lint: FORCE $(LINT) $(DEFS) $(DEFINES) $(SRCS) lint5: FORCE $(5LINT) $(DEFS) $(DEFINES) $(SRCS) Makefile: $(top_srcdir)/build/rules.mk openldap-2.5.11+dfsg/build/mod.mk0000644000175000017500000000420314172327167015245 0ustar ryanryan# $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . ##--------------------------------------------------------------------------- # # Makefile Template for Server Modules # LIBRARY = $(LIBBASE).la LIBSTAT = lib$(LIBBASE).a MKDEPFLAG = -l .SUFFIXES: .c .o .lo .c.lo: $(LTCOMPILE_MOD) $< all-no lint-no 5lint-no depend-no install-no: FORCE @echo "run configure with $(BUILD_OPT) to make $(LIBBASE)" all-common: all-$(BUILD_MOD) version.c: Makefile $(RM) $@ $(MKVERSION) $(LIBBASE) > $@ version.lo: version.c $(OBJS) $(LIBRARY): version.lo $(LTLINK_MOD) -module -o $@ $(OBJS) version.lo $(LINK_LIBS) $(LIBSTAT): version.lo $(AR) ruv $@ `echo $(OBJS) | sed 's/\.lo/.o/g'` version.o @$(RANLIB) $@ clean-common: clean-lib FORCE veryclean-common: veryclean-lib FORCE lint-common: lint-$(BUILD_MOD) 5lint-common: 5lint-$(BUILD_MOD) depend-common: depend-$(BUILD_MOD) install-common: install-$(BUILD_MOD) all-local-mod: all-mod: $(LIBRARY) all-local-mod FORCE all-local-lib: all-yes: $(LIBSTAT) all-local-lib FORCE install-mod: $(LIBRARY) @-$(MKDIR) $(DESTDIR)$(moduledir) $(LTINSTALL) $(INSTALLFLAGS) -m 755 $(LIBRARY) $(DESTDIR)$(moduledir) install-local-lib: install-yes: install-local-lib FORCE lint-local-lib: lint-yes lint-mod: lint-local-lib FORCE $(LINT) $(DEFS) $(DEFINES) $(SRCS) 5lint-local-lib: 5lint-yes 5lint-mod: 5lint-local-lib FORCE $(5LINT) $(DEFS) $(DEFINES) $(SRCS) clean-local-lib: clean-lib: clean-local-lib FORCE $(RM) $(LIBRARY) $(LIBSTAT) version.c *.o *.lo a.out core .libs/* depend-local-lib: depend-yes depend-mod: depend-local-lib FORCE $(MKDEP) $(DEFS) $(DEFINES) $(SRCS) veryclean-local-lib: veryclean-lib: clean-lib veryclean-local-lib Makefile: $(top_srcdir)/build/mod.mk openldap-2.5.11+dfsg/build/mkdep0000755000175000017500000001227314172327167015171 0ustar ryanryan#! /bin/sh - # $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . # ## Portions Copyright (c) 1987 Regents of the University of California. ## All rights reserved. ## ## Redistribution and use in source and binary forms are permitted ## provided that the above copyright notice and this paragraph are ## duplicated in all such forms and that any documentation, ## advertising materials, and other materials related to such ## distribution and use acknowledge that the software was developed ## by the University of California, Berkeley. The name of the ## University may not be used to endorse or promote products derived ## from this software without specific prior written permission. ## THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ## IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ## WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. # # @(#)mkdep.sh 5.12 (Berkeley) 6/30/88 # # We now use whatever path is already set by the invoker #PATH=/bin:/usr/bin:/usr/ucb #export PATH set -e # exit immediately if any errors occur MAKE=Makefile # default makefile name is "Makefile" NOSLASH="no" # by default, / dependencies are included SRCDIR="" SED=cat : ${CC=cc} # use cc by default # We generally set these via the command line options : ${MKDEP_CC=$CC} # select default compiler to generate dependencies : ${MKDEP_CFLAGS="-M"} # cc -M usually produces dependencies while : do case "$1" in # the -s flag removes dependencies to files that begin with / -s) NOSLASH=yes; shift ;; # -f allows you to select a makefile name -f) MAKE=$2 shift; shift ;; # -d allows you to select a VPATH directory -d) SRCDIR=$2 shift; shift ;; # -c allows you to override the compiler used to generate dependencies -c) MKDEP_CC=$2 shift; shift ;; # -m allows you to override the compiler flags used to generate # dependencies. -m) MKDEP_CFLAGS=$2 shift; shift ;; # the -p flag produces "program: program.c" style dependencies # so .o's don't get produced -p) SED='sed -e s;\.o;;' shift ;; # the -l flag produces libtool compatible dependencies -l) SED='sed -e s;\.o:;.lo:;' shift ;; # -*) shift ;; *) break ;; esac done if test $# = 0 ; then echo 'usage: mkdep [-p] [-s] [-c cc] [-m flags] [-f makefile] [-d srcdir] [cppflags] file ...' exit 1 fi if test ! -w $MAKE ; then echo "mkdep: no writeable file \"$MAKE\"" exit 1 fi TMP=${TMPDIR-/tmp}/mkdep$$ trap 'rm -f $TMP.sed $TMP ; exit 1' 1 2 3 13 15 cp $MAKE ${MAKE}.bak sed -e '/DO NOT DELETE THIS LINE/,$d' < $MAKE > $TMP cat << _EOF_ >> $TMP # DO NOT DELETE THIS LINE -- mkdep uses it. # DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. _EOF_ # If your compiler doesn't have -M, you may be able to use -E instead. # The preprocessor must generate lines of the form # #.* [0-9]* "dependent file" .* # This script will parse out the "dependent file"s to generate the # dependency list. if test "x$SRCDIR" = "x" ; then files=$* else files= for i in $* ; do if test -f $i ; then files="$files $i" elif test -f $SRCDIR/$i ; then files="$files $SRCDIR/$i" else files="$files $i" fi done MKDEP_CFLAGS="$MKDEP_CFLAGS -I$SRCDIR" fi cat << _EOF_ >> $TMP # # files: $* # command: $MKDEP_CC $MKDEP_CFLAGS $files # _EOF_ case $MKDEP_CFLAGS in # Using regular preprocessor output -E*) FLAGS="" FILES="" for i in $files; do case $i in -*) FLAGS="$FLAGS $i" ;; *) FILES="$FILES $i" ;; esac done for i in $FILES; do $MKDEP_CC $MKDEP_CFLAGS $FLAGS $i | grep '^#.*"' > $TMP.sed awk ' BEGIN { file = "'$i'" n = split(file, parts, "/") filenm = substr(parts[n], 0, length(parts[n])-1) "o" } { dep = split($3, parts, "\"") dep = parts[2] if (dep ~ "^\./.*") dep = substr(dep, 3, length(dep)-2) if (( noslash == "yes") && (dep ~ /^\// )) continue if (deps[dep] == 0) printf "%s: %s\n", filenm, dep deps[dep] = 1 }' noslash="$NOSLASH" $TMP.sed >> $TMP done ;; *) # Using -M or some other specific dependency-generating option $MKDEP_CC $MKDEP_CFLAGS $files | \ sed -e 's; \./; ;g' -e 's/ :/:/' | \ $SED > $TMP.sed # do not pipe to awk. SGI awk wants a filename as argument. # (or '-', but I do not know if all other awks support that.) awk ' $1 ~ /:$/ { filenm=$1 dep=substr($0, length(filenm)+1) } $1 !~ /:$/ { dep=$0 } /.*/ { if ( length(filenm) < 2 ) next if ( filenm ~ /:.*:$/ ) next split(dep, depends, " ") for(d in depends) { dfile = depends[d] if ( length(dfile) < 2 ) continue if ( dfile ~ /:/ ) continue if (( noslash == "yes") && (dfile ~ /^\// )) continue rec = filenm " " dfile print rec } } ' noslash="$NOSLASH" $TMP.sed >> $TMP ;; esac cat << _EOF_ >> $TMP # IF YOU PUT ANYTHING HERE IT WILL GO AWAY _EOF_ # copy to preserve permissions cp $TMP $MAKE rm -f ${MAKE}.bak $TMP.sed $TMP exit 0 openldap-2.5.11+dfsg/build/mkversion0000755000175000017500000000360014172327167016100 0ustar ryanryan#! /bin/sh # Create a version.c file # $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . PACKAGE=OpenLDAP VERSION=unknown SYMBOL=__Version static=static const=const while : do case "$1" in -p) PACKAGE=$2 shift; shift ;; -v) VERSION=$2 shift; shift ;; -c) const= shift ;; -n) SYMBOL=$2 shift; shift ;; -s) static= shift ;; # -*) shift ;; *) break ;; esac done if test $# != 1 ; then echo 'usage: mkversion [-c] [-s] [-p package] [-v version] application' exit 1 fi APPLICATION=$1 # Reproducible builds set SOURCE_DATE_EPOCH, want constant strings if [ -n "${SOURCE_DATE_EPOCH}" ]; then WHOWHERE="openldap" else WHOWHERE="$USER@$(uname -n):$(pwd)" fi cat << __EOF__ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ static const char copyright[] = "Copyright 1998-2022 The OpenLDAP Foundation. All rights reserved.\n" "COPYING RESTRICTIONS APPLY\n"; $static $const char $SYMBOL[] = "@(#) \$$PACKAGE: $APPLICATION $VERSION (" __DATE__ " " __TIME__ ") \$\n" "\t$WHOWHERE\n"; __EOF__ openldap-2.5.11+dfsg/build/lib-static.mk0000644000175000017500000000133214172327167016521 0ustar ryanryan# $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . ##--------------------------------------------------------------------------- # # Makefile Template for Static Libraries # $(LIBRARY): version.o $(AR) ru $@ $(OBJS) version.o @$(RANLIB) $@ Makefile: $(top_srcdir)/build/lib-static.mk openldap-2.5.11+dfsg/build/missing0000755000175000017500000001533014172327167015537 0ustar ryanryan#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2013-10-28.13; # UTC # Copyright (C) 1996-2014 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: openldap-2.5.11+dfsg/build/config.guess0000755000175000017500000013647114172327167016472 0ustar ryanryan#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2020 Free Software Foundation, Inc. timestamp='2020-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # # Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2020 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c89 c99 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD="$driver" break fi done if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac } # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "$UNAME_SYSTEM" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu set_cc_for_build cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" # If ldd exists, use it to detect musl libc. if command -v ldd >/dev/null && \ ldd --version 2>&1 | grep -q ^musl then LIBC=musl fi ;; esac # Note: order is significant - the case branches are not exclusive. case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ "/sbin/$sysctl" 2>/dev/null || \ "/usr/sbin/$sysctl" 2>/dev/null || \ echo unknown)` case "$UNAME_MACHINE_ARCH" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine="${arch}${endian}"-unknown ;; *) machine="$UNAME_MACHINE_ARCH"-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case "$UNAME_MACHINE_ARCH" in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case "$UNAME_MACHINE_ARCH" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "$UNAME_VERSION" in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "$machine-${os}${release}${abi-}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" exit ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" exit ;; *:MidnightBSD:*:*) echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" exit ;; *:ekkoBSD:*:*) echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" exit ;; *:SolidBSD:*:*) echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" exit ;; *:OS108:*:*) echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE" exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:MirBSD:*:*) echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:Sortix:*:*) echo "$UNAME_MACHINE"-unknown-sortix exit ;; *:Twizzler:*:*) echo "$UNAME_MACHINE"-unknown-twizzler exit ;; *:Redox:*:*) echo "$UNAME_MACHINE"-unknown-redox exit ;; mips:OSF1:*.*) echo mips-dec-osf1 exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo "$UNAME_MACHINE"-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo "$UNAME_MACHINE"-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix"$UNAME_RELEASE" exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux"$UNAME_RELEASE" exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`" exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos"$UNAME_RELEASE" exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos"$UNAME_RELEASE" ;; sun4) echo sparc-sun-sunos"$UNAME_RELEASE" ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos"$UNAME_RELEASE" exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint"$UNAME_RELEASE" exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint"$UNAME_RELEASE" exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint"$UNAME_RELEASE" exit ;; m68k:machten:*:*) echo m68k-apple-machten"$UNAME_RELEASE" exit ;; powerpc:machten:*:*) echo powerpc-apple-machten"$UNAME_RELEASE" exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix"$UNAME_RELEASE" exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix"$UNAME_RELEASE" exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix"$UNAME_RELEASE" exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos"$UNAME_RELEASE" exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ] then if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \ [ "$TARGET_BINARY_INTERFACE"x = x ] then echo m88k-dg-dgux"$UNAME_RELEASE" else echo m88k-dg-dguxbcs"$UNAME_RELEASE" fi else echo i586-dg-dgux"$UNAME_RELEASE" fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`" exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/lslpp ] ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi echo "$IBM_ARCH"-ibm-aix"$IBM_REV" exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` case "$UNAME_MACHINE" in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "$sc_cpu_version" in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "$sc_kernel_bits" in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if [ "$HP_ARCH" = "" ]; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ "$HP_ARCH" = hppa2.0w ] then set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi echo "$HP_ARCH"-hp-hpux"$HPUX_REV" exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux"$HPUX_REV" exit ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo "$UNAME_MACHINE"-unknown-osf1mk else echo "$UNAME_MACHINE"-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi"$UNAME_RELEASE" exit ;; *:BSD/OS:*:*) echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" exit ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabi else echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabihf fi exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case "$UNAME_PROCESSOR" in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; i*:CYGWIN*:*) echo "$UNAME_MACHINE"-pc-cygwin exit ;; *:MINGW64*:*) echo "$UNAME_MACHINE"-pc-mingw64 exit ;; *:MINGW*:*) echo "$UNAME_MACHINE"-pc-mingw32 exit ;; *:MSYS*:*) echo "$UNAME_MACHINE"-pc-msys exit ;; i*:PW*:*) echo "$UNAME_MACHINE"-pc-pw32 exit ;; *:Interix*:*) case "$UNAME_MACHINE" in x86) echo i586-pc-interix"$UNAME_RELEASE" exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix"$UNAME_RELEASE" exit ;; IA64) echo ia64-unknown-interix"$UNAME_RELEASE" exit ;; esac ;; i*:UWIN*:*) echo "$UNAME_MACHINE"-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-pc-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; *:GNU:*:*) # the GNU system echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`" exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" exit ;; *:Minix:*:*) echo "$UNAME_MACHINE"-unknown-minix exit ;; aarch64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi else echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf fi fi exit ;; avr32*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; cris:Linux:*:*) echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; crisv32:Linux:*:*) echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; e2k:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; frv:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; hexagon:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:Linux:*:*) echo "$UNAME_MACHINE"-pc-linux-"$LIBC" exit ;; ia64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; k1om:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m32r*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m68*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-"$LIBC" exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; padre:Linux:*:*) echo sparc-unknown-linux-"$LIBC" exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-"$LIBC" exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; *) echo hppa-unknown-linux-"$LIBC" ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-"$LIBC" exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-"$LIBC" exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-"$LIBC" exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-"$LIBC" exit ;; riscv32:Linux:*:* | riscv64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" exit ;; sh64*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sh*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; tile*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; vax:Linux:*:*) echo "$UNAME_MACHINE"-dec-linux-"$LIBC" exit ;; x86_64:Linux:*:*) echo "$UNAME_MACHINE"-pc-linux-"$LIBC" exit ;; xtensa*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo "$UNAME_MACHINE"-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo "$UNAME_MACHINE"-unknown-stop exit ;; i*86:atheos:*:*) echo "$UNAME_MACHINE"-unknown-atheos exit ;; i*86:syllable:*:*) echo "$UNAME_MACHINE"-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos"$UNAME_RELEASE" exit ;; i*86:*DOS:*:*) echo "$UNAME_MACHINE"-pc-msdosdjgpp exit ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" else echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}" exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" else echo "$UNAME_MACHINE"-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos"$UNAME_RELEASE" exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos"$UNAME_RELEASE" exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos"$UNAME_RELEASE" exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos"$UNAME_RELEASE" exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv"$UNAME_RELEASE" exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo "$UNAME_MACHINE"-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo "$UNAME_MACHINE"-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux"$UNAME_RELEASE" exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv"$UNAME_RELEASE" else echo mips-unknown-sysv"$UNAME_RELEASE" fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux"$UNAME_RELEASE" exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux"$UNAME_RELEASE" exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux"$UNAME_RELEASE" exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux"$UNAME_RELEASE" exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux"$UNAME_RELEASE" exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux"$UNAME_RELEASE" exit ;; SX-ACE:SUPER-UX:*:*) echo sxace-nec-superux"$UNAME_RELEASE" exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Rhapsody:*:*) echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-*:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk"$UNAME_RELEASE" exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk"$UNAME_RELEASE" exit ;; NSR-*:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk"$UNAME_RELEASE" exit ;; NSV-*:NONSTOP_KERNEL:*:*) echo nsv-tandem-nsk"$UNAME_RELEASE" exit ;; NSX-*:NONSTOP_KERNEL:*:*) echo nsx-tandem-nsk"$UNAME_RELEASE" exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. # shellcheck disable=SC2154 if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo "$UNAME_MACHINE"-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux"$UNAME_RELEASE" exit ;; *:DragonFly:*:*) echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "$UNAME_MACHINE" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`" exit ;; i*86:rdos:*:*) echo "$UNAME_MACHINE"-pc-rdos exit ;; i*86:AROS:*:*) echo "$UNAME_MACHINE"-pc-aros exit ;; x86_64:VMkernel:*:*) echo "$UNAME_MACHINE"-unknown-esx exit ;; amd64:Isilon\ OneFS:*:*) echo x86_64-unknown-onefs exit ;; *:Unleashed:*:*) echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE" exit ;; esac # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" < #include #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include #if defined(_SIZE_T_) || defined(SIGLOST) #include #endif #endif #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) #include #if defined (BSD) #if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); #else #if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); #else printf ("vax-dec-bsd\n"); exit (0); #endif #endif #else printf ("vax-dec-bsd\n"); exit (0); #endif #else #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 case "$UNAME_MACHINE:$UNAME_SYSTEM" in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: openldap-2.5.11+dfsg/build/top.mk0000644000175000017500000001530414172327167015274 0ustar ryanryan# $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ##--------------------------------------------------------------------------- # # Top-level Makefile template # PACKAGE= @PACKAGE@ VERSION= @VERSION@ RELEASEDATE= @OPENLDAP_RELEASE_DATE@ @SET_MAKE@ SHELL = /bin/sh top_builddir = @top_builddir@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ ldap_subdir = @ldap_subdir@ bindir = @bindir@ datarootdir = @datarootdir@ datadir = @datadir@$(ldap_subdir) includedir = @includedir@ infodir = @infodir@ libdir = @libdir@ libexecdir = @libexecdir@ localstatedir = @localstatedir@ mandir = @mandir@ moduledir = @libexecdir@$(ldap_subdir) sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@$(ldap_subdir) schemadir = $(sysconfdir)/schema systemdsystemunitdir = @systemdsystemunitdir@ PLAT = @PLAT@ EXEEXT = @EXEEXT@ OBJEXT = @OBJEXT@ BUILD_LIBS_DYNAMIC = @BUILD_LIBS_DYNAMIC@ SHTOOL = $(top_srcdir)/build/shtool INSTALL = $(SHTOOL) install -c INSTALL_PROGRAM = $(INSTALL) INSTALL_DATA = $(INSTALL) -m 644 INSTALL_SCRIPT = $(INSTALL) STRIP_OPTS = -s LINT = lint 5LINT = 5lint MKDEP = $(top_srcdir)/build/mkdep $(MKDEPFLAG) \ -d "$(srcdir)" -c "$(MKDEP_CC)" -m "$(MKDEP_CFLAGS)" MKDEP_CC = @OL_MKDEP@ MKDEP_CFLAGS = @OL_MKDEP_FLAGS@ MKVERSION = $(top_srcdir)/build/mkversion -v "$(VERSION)" LIBTOOL = @LIBTOOL@ LIBRELEASE = @OPENLDAP_LIBRELEASE@ LIBVERSION = @OPENLDAP_LIBVERSION@ LTVERSION = -release $(LIBRELEASE) -version-info $(LIBVERSION) # libtool --only flag for libraries: platform specific NT_LTONLY_LIB = # --only-$(BUILD_LIBS_DYNAMIC) LTONLY_LIB = $(@PLAT@_LTONLY_LIB) # libtool --only flag for modules: depends on linkage of module # The BUILD_MOD macro is defined in each backend Makefile.in file LTONLY_yes = --tag=disable-shared LTONLY_mod = --tag=disable-static LTONLY_MOD = $(LTONLY_$(BUILD_MOD)) # platform-specific libtool flags NT_LTFLAGS_LIB = -no-undefined -avoid-version -rpath $(libdir) NT_LTFLAGS_MOD = -no-undefined -avoid-version -rpath $(moduledir) UNIX_LTFLAGS_LIB = $(LTVERSION) -rpath $(libdir) UNIX_LTFLAGS_MOD = $(LTVERSION) -rpath $(moduledir) # libtool flags LTFLAGS = $(@PLAT@_LTFLAGS) LTFLAGS_LIB = $(@PLAT@_LTFLAGS_LIB) LTFLAGS_MOD = $(@PLAT@_LTFLAGS_MOD) # LIB_DEFS defined in liblber and libldap Makefile.in files. # MOD_DEFS defined in backend Makefile.in files. # platform-specific LINK_LIBS defined in various Makefile.in files. # LINK_LIBS referenced in library and module link commands. LINK_LIBS = $(MOD_LIBS) $(@PLAT@_LINK_LIBS) # compiler options for versioned library symbol support OL_VERSIONED_SYMBOLS = @OL_VERSIONED_SYMBOLS@ LTSTATIC = @LTSTATIC@ LTLINK = $(LIBTOOL) --mode=link \ $(CC) $(LTSTATIC) $(LT_CFLAGS) $(LDFLAGS) $(LTFLAGS) LTCOMPILE_LIB = $(LIBTOOL) $(LTONLY_LIB) --mode=compile \ $(CC) $(LT_CFLAGS) $(LT_CPPFLAGS) $(LIB_DEFS) -c LTLINK_LIB = $(LIBTOOL) $(LTONLY_LIB) --mode=link \ $(CC) $(LT_CFLAGS) $(LDFLAGS) $(LTFLAGS_LIB) $(SYMBOL_VERSION_FLAGS) LTCOMPILE_MOD = $(LIBTOOL) $(LTONLY_MOD) --mode=compile \ $(CC) $(LT_CFLAGS) $(LT_CPPFLAGS) $(MOD_DEFS) -c LTLINK_MOD = $(LIBTOOL) $(LTONLY_MOD) --mode=link \ $(CC) $(LT_CFLAGS) $(LDFLAGS) $(LTFLAGS_MOD) LTINSTALL = $(LIBTOOL) --mode=install $(INSTALL) LTFINISH = $(LIBTOOL) --mode=finish # Misc UNIX commands used in build environment AR = @AR@ BASENAME = basename CAT = cat CHMOD = chmod DATE = date ECHO = $(SHTOOL) echo HOSTNAME = $(SHTOOL) echo -e "%h%d" LN = $(SHTOOL) mkln LN_H = $(LN) LN_S = $(LN) -s MAKEINFO = @MAKEINFO@ MKDIR = $(SHTOOL) mkdir -p MV = $(SHTOOL) move PWD = pwd RANLIB = @RANLIB@ RM = rm -f SED = sed SUBST = $(SHTOOL) subst # For manual pages # MANCOMPRESS=@MANCOMPRESS@ # MANCOMPRESSSUFFIX=@MANCOMPRESSSUFFIX@ MANCOMPRESS=$(CAT) MANCOMPRESSSUFFIX= SOELIM=soelim INCLUDEDIR= $(top_srcdir)/include LDAP_INCPATH= -I$(LDAP_INCDIR) -I$(INCLUDEDIR) LDAP_LIBDIR= $(top_builddir)/libraries CLIENT_LIBS = @CLIENT_LIBS@ LUTIL_LIBS = @LUTIL_LIBS@ LTHREAD_LIBS = @LTHREAD_LIBS@ SLAPD_NDB_LIBS = @SLAPD_NDB_LIBS@ WT_LIBS = @WT_LIBS@ LEVENT_LIBS = @LEVENT_LIBS@ LDAP_LIBLBER_LA = $(LDAP_LIBDIR)/liblber/liblber.la LDAP_LIBLDAP_LA = $(LDAP_LIBDIR)/libldap/libldap.la LDAP_LIBREWRITE_A = $(LDAP_LIBDIR)/librewrite/librewrite.a LDAP_LIBLUNICODE_A = $(LDAP_LIBDIR)/liblunicode/liblunicode.a LDAP_LIBLUTIL_A = $(LDAP_LIBDIR)/liblutil/liblutil.a LDAP_L = $(LDAP_LIBLUTIL_A) \ $(LDAP_LIBLDAP_LA) $(LDAP_LIBLBER_LA) SLAPD_L = $(LDAP_LIBLUNICODE_A) $(LDAP_LIBREWRITE_A) \ $(LDAP_LIBLUTIL_A) $(LDAP_LIBLDAP_LA) $(LDAP_LIBLBER_LA) LLOADD_L = $(LDAP_LIBLUTIL_A) $(LDAP_LIBLDAP_LA) \ $(LDAP_LIBLBER_LA) WRAP_LIBS = @WRAP_LIBS@ # AutoConfig generated AC_CC = @CC@ AC_CFLAGS = @CFLAGS@ AC_DEFS = @CPPFLAGS@ # @DEFS@ AC_LDFLAGS = @LDFLAGS@ AC_LIBS = @LIBS@ SASL_LIBS = @SASL_LIBS@ TLS_LIBS = @TLS_LIBS@ AUTH_LIBS = @AUTH_LIBS@ ARGON2_LIBS = @ARGON2_LIBS@ SECURITY_LIBS = $(SASL_LIBS) $(TLS_LIBS) $(AUTH_LIBS) SYSTEMD_LIBS = @SYSTEMD_LIBS@ MODULES_CPPFLAGS = @SLAPD_MODULES_CPPFLAGS@ MODULES_LDFLAGS = @SLAPD_MODULES_LDFLAGS@ MODULES_LIBS = @MODULES_LIBS@ SLAPD_PERL_LDFLAGS = @SLAPD_PERL_LDFLAGS@ SLAPD_SQL_LDFLAGS = @SLAPD_SQL_LDFLAGS@ SLAPD_SQL_INCLUDES = @SLAPD_SQL_INCLUDES@ SLAPD_SQL_LIBS = @SLAPD_SQL_LIBS@ SLAPD_LIBS = @SLAPD_LIBS@ @SLAPD_PERL_LDFLAGS@ @SLAPD_SQL_LDFLAGS@ @SLAPD_SQL_LIBS@ @SLAPD_SLP_LIBS@ @SLAPD_GMP_LIBS@ $(SYSTEMD_LIBS) LLOADD_LIBS = @BALANCER_LIBS@ $(LEVENT_LIBS) # Our Defaults CC = $(AC_CC) DEFS = $(LDAP_INCPATH) $(XINCPATH) $(XDEFS) $(AC_DEFS) $(DEFINES) CFLAGS = $(AC_CFLAGS) $(DEFS) LDFLAGS = $(LDAP_LIBPATH) $(AC_LDFLAGS) $(XLDFLAGS) LIBS = $(XLIBS) $(XXLIBS) $(AC_LIBS) $(XXXLIBS) LT_CFLAGS = $(AC_CFLAGS) LT_CPPFLAGS = $(DEFS) all: all-common all-local FORCE install: install-common install-local FORCE clean: clean-common clean-local FORCE veryclean: veryclean-common veryclean-local FORCE depend: depend-common depend-local FORCE # empty common rules all-common: install-common: clean-common: veryclean-common: clean-common FORCE depend-common: lint-common: lint5-common: # empty local rules all-local: install-local: clean-local: veryclean-local: clean-local FORCE depend-local: lint-local: lint5-local: veryclean: FORCE $(RM) Makefile $(RM) -r .libs Makefile: Makefile.in $(top_srcdir)/build/top.mk pathtest: $(SHTOOL) --version # empty rule for forcing rules FORCE: ##--------------------------------------------------------------------------- openldap-2.5.11+dfsg/build/lib-shared.mk0000644000175000017500000000144614172327167016506 0ustar ryanryan# $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . ##--------------------------------------------------------------------------- # # Makefile Template for Shared Libraries # MKDEPFLAG = -l .SUFFIXES: .c .o .lo .c.lo: $(LTCOMPILE_LIB) $< $(LIBRARY): version.lo $(LTLINK_LIB) -o $@ $(OBJS) version.lo $(LINK_LIBS) Makefile: $(top_srcdir)/build/lib-shared.mk openldap-2.5.11+dfsg/build/lt~obsolete.m40000644000175000017500000001377414172327167016766 0ustar ryanryan# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software # Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) openldap-2.5.11+dfsg/build/lib.mk0000644000175000017500000000255514172327167015244 0ustar ryanryan# $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . ##--------------------------------------------------------------------------- # # Makefile Template for Libraries # all-common: $(LIBRARY) $(PROGRAMS) version.c: Makefile $(RM) $@ $(MKVERSION) $(LIBRARY) > $@ version.o version.lo: version.c $(OBJS) install-common: FORCE lint: lint-local FORCE $(LINT) $(DEFS) $(DEFINES) $(SRCS) lint5: lint5-local FORCE $(5LINT) $(DEFS) $(DEFINES) $(SRCS) # # In the mingw/cygwin environment, the so and dll files must be # deleted separately, instead of using the {.so*,*.dll} construct # that was previously used. It just didn't work. # clean-common: FORCE $(RM) $(LIBRARY) ../$(LIBRARY) $(XLIBRARY) \ $(PROGRAMS) $(XPROGRAMS) $(XSRCS) $(XXSRCS) \ *.o *.lo a.out *.exe *.pc core version.c .libs/* depend-common: FORCE $(MKDEP) $(DEFS) $(DEFINES) $(SRCS) $(XXSRCS) lint-local: FORCE lint5-local: FORCE Makefile: $(top_srcdir)/build/lib.mk openldap-2.5.11+dfsg/build/mkdep.aix0000755000175000017500000000102314172327167015740 0ustar ryanryan#! /bin/sh ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . cc_r -ME $* > /dev/null cat *.u rm *.u openldap-2.5.11+dfsg/build/man.mk0000644000175000017500000000357414172327167015253 0ustar ryanryan# $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . ##--------------------------------------------------------------------------- # # Makefile Template for Manual Pages # MANDIR=$(mandir)/man$(MANSECT) TMP_SUFFIX=tmp all-common: PAGES=`cd $(srcdir); echo *.$(MANSECT)`; \ for page in $$PAGES; do \ $(SED) -e "s%LDVERSION%$(VERSION)%" \ -e 's%ETCDIR%$(sysconfdir)%g' \ -e 's%LOCALSTATEDIR%$(localstatedir)%' \ -e 's%SYSCONFDIR%$(sysconfdir)%' \ -e 's%DATADIR%$(datadir)%' \ -e 's%SBINDIR%$(sbindir)%' \ -e 's%BINDIR%$(bindir)%' \ -e 's%LIBDIR%$(libdir)%' \ -e 's%LIBEXECDIR%$(libexecdir)%' \ -e 's%MODULEDIR%$(moduledir)%' \ -e 's%RELEASEDATE%$(RELEASEDATE)%' \ $(srcdir)/$$page \ | (cd $(srcdir); $(SOELIM) -) > $$page.$(TMP_SUFFIX); \ done install-common: -$(MKDIR) $(DESTDIR)$(MANDIR) PAGES=`cd $(srcdir); echo *.$(MANSECT)`; \ for page in $$PAGES; do \ echo "installing $$page in $(DESTDIR)$(MANDIR)"; \ $(RM) $(DESTDIR)$(MANDIR)/$$page; \ $(INSTALL) $(INSTALLFLAGS) -m 644 $$page.$(TMP_SUFFIX) $(DESTDIR)$(MANDIR)/$$page; \ if test -f "$(srcdir)/$$page.links" ; then \ for link in `$(CAT) $(srcdir)/$$page.links`; do \ echo "installing $$link in $(DESTDIR)$(MANDIR) as link to $$page"; \ $(RM) $(DESTDIR)$(MANDIR)/$$link ; \ $(LN_S) $(DESTDIR)$(MANDIR)/$$page $(DESTDIR)$(MANDIR)/$$link; \ done; \ fi; \ done clean-common: FORCE $(RM) *.tmp all-common Makefile: $(top_srcdir)/build/man.mk openldap-2.5.11+dfsg/build/srv.mk0000644000175000017500000000301214172327167015275 0ustar ryanryan# $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . ##--------------------------------------------------------------------------- # # Makefile Template for Servers # all-common: all-$(BUILD_SRV) all-no lint-no 5lint-no depend-no install-no: @echo "run configure with $(BUILD_OPT) to make $(PROGRAMS)" clean-common: clean-srv FORCE veryclean-common: veryclean-srv FORCE lint-common: lint-$(BUILD_SRV) 5lint-common: 5lint-$(BUILD_SRV) depend-common: depend-$(BUILD_SRV) install-common: install-$(BUILD_SRV) all-local-srv: all-yes: all-local-srv FORCE install-local-srv: install-yes: install-local-srv FORCE lint-local-srv: lint-yes: lint-local-srv FORCE $(LINT) $(DEFS) $(DEFINES) $(SRCS) 5lint-local-srv: 5lint-yes: 5lint-local-srv FORCE $(5LINT) $(DEFS) $(DEFINES) $(SRCS) clean-local-srv: clean-srv: clean-local-srv FORCE $(RM) $(PROGRAMS) $(XPROGRAMS) $(XSRCS) *.o a.out core .libs/* *.exe depend-local-srv: depend-yes: depend-local-srv FORCE $(MKDEP) $(DEFS) $(DEFINES) $(SRCS) veryclean-local-srv: veryclean-srv: clean-srv veryclean-local-srv Makefile: $(top_srcdir)/build/srv.mk openldap-2.5.11+dfsg/build/libtool.m40000644000175000017500000112507314172327167016055 0ustar ryanryan# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 2014 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program or library that is built # using GNU Libtool, you may include this file under the same # distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . ]) # serial 58 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS=$ltmain # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_PREPARE_CC_BASENAME # ----------------------- m4_defun([_LT_PREPARE_CC_BASENAME], [ # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in @S|@*""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } ])# _LT_PREPARE_CC_BASENAME # _LT_CC_BASENAME(CC) # ------------------- # It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME, # but that macro is also expanded into generated libtool script, which # arranges for $SED and $ECHO to be set by different means. m4_defun([_LT_CC_BASENAME], [m4_require([_LT_PREPARE_CC_BASENAME])dnl AC_REQUIRE([_LT_DECL_SED])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl func_cc_basename $1 cc_basename=$func_cc_basename_result ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl m4_require([_LT_CMD_TRUNCATE])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a '.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld=$lt_cv_prog_gnu_ld old_CC=$CC old_CFLAGS=$CFLAGS # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from 'configure', and 'config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # 'config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain=$ac_aux_dir/ltmain.sh ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the 'libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to 'config.status' so that its # declaration there will have the same value as in 'configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags='_LT_TAGS'dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the 'libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into 'config.status', and then the shell code to quote escape them in # for loops in 'config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # '#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test 0 = "$lt_write_fail" && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ '$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test 0 != $[#] do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try '$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try '$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test yes = "$silent" && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi cfgfile=${ofile}T trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # Generated automatically by $as_me ($PACKAGE) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 _LT_COPYING _LT_LIBTOOL_TAGS # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE _LT_PREPARE_MUNGE_PATH_LIST _LT_PREPARE_CC_BASENAME # ### END FUNCTIONS SHARED WITH CONFIGURE _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "$LT_MULTI_MODULE"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS=$save_LDFLAGS ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; 10.[[012]][[,.]]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; then _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' fi if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test yes = "$lt_cv_ld_force_load"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined case $cc_basename in ifort*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" m4_if([$1], [CXX], [ if test yes != "$lt_cv_apple_cc_single_mod"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script that will find a shell with a builtin # printf (that we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case $ECHO in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], [Search for dependent libraries within DIR (or the compiler's sysroot if not specified).])], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([$with_sysroot]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and where our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test no = "$enable_libtool_lock" || enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test yes = "$lt_cv_prog_gnu_ld"; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then emul=elf case `/usr/bin/file conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `/usr/bin/file conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `/usr/bin/file conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD=${LD-ld}_sol2 fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks=$enable_libtool_lock ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test 0 -eq "$ac_status"; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test no = "$lt_cv_ar_at_file"; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in bitrig* | openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test yes = "[$]$2"; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS ]) if test yes = "[$]$2"; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring=ABCD case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test X`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test 17 != "$i" # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n "$lt_cv_sys_max_cmd_len"; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes = "$cross_compiling"; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes != "$enable_dlopen"; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen=load_add_on lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen=dlopen lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[ lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen=shl_load], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen=dlopen], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld]) ]) ]) ]) ]) ]) ;; esac if test no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS=$LDFLAGS wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS=$LIBS LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS LIBS=$save_LIBS ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links=nottested if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test no = "$hard_links"; then AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/", [Define to the sub-directory where libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then # We can hardcode non-existent directories. if test no != "$_LT_TAGVAR(hardcode_direct, $1)" && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" && test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test relink = "$_LT_TAGVAR(hardcode_action, $1)" || test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP"; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_PREPARE_MUNGE_PATH_LIST # --------------------------- # Make sure func_munge_path_list() is defined correctly. m4_defun([_LT_PREPARE_MUNGE_PATH_LIST], [[# func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x@S|@2 in x) ;; *:) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" ;; x:*) eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; *::*) eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" ;; *) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; esac } ]])# _LT_PREPARE_PATH_LIST # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test yes = "$GCC"; then case $host_os in darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; *) lt_sed_strip_eq='s|=/|/|g' ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary... lt_tmp_lt_search_path_spec= lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" elif test -n "$lt_multi_os_dir"; then test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS = " "; FS = "/|\n";} { lt_foo = ""; lt_count = 0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo = "/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=.so postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown AC_ARG_VAR([LT_SYS_LIBRARY_PATH], [User-defined run-time library search path.]) case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='$libname$release$shared_ext$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test ia64 = "$host_cpu"; then # AIX 5 supports IA64 library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line '#! .'. This would cause the generated library to # depend on '.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a[(]lib.so.V[)]' # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='$libname$shared_ext' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' library_names_spec='$libname.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec=$LIB if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' soname_spec='$libname$release$major$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=no sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' if test 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test yes = "$lt_cv_prog_gnu_ld"; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) to the search path. if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test yes = "$with_gnu_ld"; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec; then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' soname_spec='$libname$shared_ext.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=sco need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test yes = "$with_gnu_ld"; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2], [Detected run-time system search path for libraries]) _LT_DECL([], [configure_time_lt_sys_library_path], [2], [Explicit LT_SYS_LIBRARY_PATH set during ./configure time]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program that can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$1"; then lt_cv_path_MAGIC_CMD=$ac_dir/"$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac]) MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program that can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test no = "$withval" || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return, which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD=$ac_prog ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test yes = "$with_gnu_ld"; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD=$ac_dir/$ac_prog # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd], [if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi]) rm -f conftest.i conftest2.i conftest.out]) ])# _LT_PATH_DD # _LT_CMD_TRUNCATE # ---------------- # find command to truncate a binary pipe m4_defun([_LT_CMD_TRUNCATE], [m4_require([_LT_PATH_DD]) AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin], [printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"]) _LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1], [Command to truncate a binary pipe]) ])# _LT_CMD_TRUNCATE # _LT_CHECK_MAGIC_METHOD # ---------------------- # how to check for library dependencies # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_MAGIC_METHOD], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) AC_CACHE_CHECK([how to recognize dependent libraries], lt_cv_deplibs_check_method, [lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # 'unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # that responds to the $file_magic_cmd with a given extended regex. # If you have 'file' or equivalent on your system and you're not sure # whether 'pass_all' will *always* work, you probably want this one. case $host_os in aix[[4-9]]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[[45]]*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM=$NM else lt_nm_to_check=${ac_tool_prefix}nm if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. tmp_nm=$ac_dir/$lt_tmp_nm if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then # Check to see if the nm accepts a BSD-compat flag. # Adding the 'sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS=$lt_save_ifs done : ${lt_cv_path_NM=no} fi]) if test no != "$lt_cv_path_NM"; then NM=$lt_cv_path_NM else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd=$ECHO ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test yes != "$lt_cv_path_mainfest_tool"; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # _LT_DLL_DEF_P([FILE]) # --------------------- # True iff FILE is a Windows DLL '.def' file. # Keep in sync with func_dll_def_p in the libtool script AC_DEFUN([_LT_DLL_DEF_P], [dnl test DEF = "`$SED -n dnl -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl -e q dnl Only consider the first "real" line $1`" dnl ])# _LT_DLL_DEF_P # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw) AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM=-lm) ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test yes = "$GCC"; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test ia64 = "$host_cpu"; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS=conftstm.$ac_objext CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test yes = "$pipe_works"; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1], [Transform the output of nm into a list of symbols to manually relocate]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([nm_interface], [lt_cv_nm_interface], [1], [The name lister interface]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test yes = "$GXX"; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' if test ia64 != "$host_cpu"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64, which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd*) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test yes = "$GCC"; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64, which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms that do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ' (' and ')$', so one must not match beginning or # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', # as well as any symbol that contains 'd'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd* | bitrig*) with_gnu_ld=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test yes = "$with_gnu_ld"; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test yes = "$lt_use_gnu_ld_interface"; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='$wl' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test ia64 != "$host_cpu"; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test linux-dietlibc = "$host_os"; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test no = "$tmp_diet" then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi case $cc_basename in tcc*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' ;; xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GCC"; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' ;; hpux10*) if test yes,no = "$GCC,$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test yes,no = "$GCC,$with_gnu_ld"; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS=$save_LDFLAGS]) if test yes = "$lt_cv_irix_exported_symbol"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' fi else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(ld_shlibs, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; osf3*) if test yes = "$GCC"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test yes = "$GCC"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test yes = "$GCC"; then wlarc='$wl' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='$wl' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. GCC discards it without '$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test yes = "$GCC"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test sequent = "$host_vendor"; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test yes,yes = "$GCC,$enable_shared"; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting $shlibpath_var if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to 'libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC=$CC AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report what library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC=$lt_save_CC ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to 'libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test no != "$CXX" && ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || (test g++ != "$CXX"))); then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_caught_CXX_error"; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test yes = "$GXX"; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test yes = "$GXX"; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test yes = "$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='$wl' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GXX"; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag=$shared_flag' $wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. # The "-G" linker flag allows undefined symbols. _LT_TAGVAR(no_undefined_flag, $1)='-bernotok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ func_to_tool_file "$lt_outputfile"~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require '-G' NOT '-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no _LT_TAGVAR(GCC, $1)=$GXX _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test yes != "$_lt_caught_CXX_error" AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case @S|@2 in .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;; *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case $prev$p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test x-L = "$p" || test x-R = "$p"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test no = "$pre_test_object_deps_done"; then case $prev in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)=$prev$p else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test no = "$pre_test_object_deps_done"; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)=$p else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)=$p else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test no = "$F77"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_disable_F77"; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)=$G77 _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test yes != "$_lt_disable_F77" AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test no = "$FC"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_disable_FC"; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test yes != "$_lt_disable_FC" AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)=$LD _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)=$LD _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code=$lt_simple_compile_test_code # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f "$lt_ac_sed" && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test 10 -lt "$lt_ac_count" && break lt_ac_count=`expr $lt_ac_count + 1` if test "$lt_ac_count" -gt "$lt_ac_max"; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine what file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS openldap-2.5.11+dfsg/Makefile.in0000644000175000017500000000172114172327167015105 0ustar ryanryan# Master Makefile for OpenLDAP # $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . SUBDIRS= include libraries clients servers tests doc CLEANDIRS= INSTALLDIRS= makefiles: FORCE ./config.status # force a make all before make install # only done at the top-level install-common: all FORCE clean-local: FORCE $(RM) config.cache config.log configure.lineno $(RM) -r autom4te.cache veryclean-local: FORCE $(RM) config.status libtool stamp-h stamp-h.in distclean: veryclean FORCE check: test test: FORCE cd tests && $(MAKE) test openldap-2.5.11+dfsg/LICENSE0000644000175000017500000000424614172327167014052 0ustar ryanryanThe OpenLDAP Public License Version 2.8, 17 August 2003 Redistribution and use of this software and associated documentation ("Software"), with or without modification, are permitted provided that the following conditions are met: 1. Redistributions in source form must retain copyright statements and notices, 2. Redistributions in binary form must reproduce applicable copyright statements and notices, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution, and 3. Redistributions must contain a verbatim copy of this document. The OpenLDAP Foundation may revise this license from time to time. Each revision is distinguished by a version number. You may use this Software under terms of this license revision or under the terms of any subsequent revision of the license. THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED 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 OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S) OR OWNER(S) OF THE SOFTWARE 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. The names of the authors and copyright holders must not be used in advertising or otherwise to promote the sale, use or other dealing in this Software without specific, written prior permission. Title to copyright in this Software shall at all times remain with copyright holders. OpenLDAP is a registered trademark of the OpenLDAP Foundation. Copyright 1999-2003 The OpenLDAP Foundation, Redwood City, California, USA. All Rights Reserved. Permission to copy and distribute verbatim copies of this document is granted. openldap-2.5.11+dfsg/servers/0000755000175000017500000000000014172327167014530 5ustar ryanryanopenldap-2.5.11+dfsg/servers/Makefile.in0000644000175000017500000000105014172327167016571 0ustar ryanryan# servers Makefile.in for OpenLDAP # $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . SUBDIRS= slapd lloadd openldap-2.5.11+dfsg/servers/lloadd/0000755000175000017500000000000014172327167015767 5ustar ryanryanopenldap-2.5.11+dfsg/servers/lloadd/design.md0000777000175000017500000000000014172327167025103 2../../doc/devel/lloadd/design.mdustar ryanryanopenldap-2.5.11+dfsg/servers/lloadd/nt_svc.c0000777000175000017500000000000014172327167022402 2../slapd/nt_svc.custar ryanryanopenldap-2.5.11+dfsg/servers/lloadd/upstream.c0000644000175000017500000010142514172327167017776 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include "lload.h" #include "lutil.h" #include "lutil_ldap.h" #ifdef HAVE_CYRUS_SASL static const sasl_callback_t client_callbacks[] = { #ifdef SASL_CB_GETREALM { SASL_CB_GETREALM, NULL, NULL }, #endif { SASL_CB_USER, NULL, NULL }, { SASL_CB_AUTHNAME, NULL, NULL }, { SASL_CB_PASS, NULL, NULL }, { SASL_CB_LIST_END, NULL, NULL } }; #endif /* HAVE_CYRUS_SASL */ static void upstream_unlink( LloadConnection *upstream ); int forward_response( LloadConnection *client, LloadOperation *op, BerElement *ber ) { BerElement *output; BerValue response, controls = BER_BVNULL; ber_int_t msgid; ber_tag_t tag, response_tag; ber_len_t len; CONNECTION_LOCK(client); if ( op->o_client_msgid ) { msgid = op->o_client_msgid; } else { assert( op->o_pin_id ); msgid = op->o_saved_msgid; op->o_saved_msgid = 0; } CONNECTION_UNLOCK(client); response_tag = ber_skip_element( ber, &response ); tag = ber_peek_tag( ber, &len ); if ( tag == LDAP_TAG_CONTROLS ) { ber_skip_element( ber, &controls ); } Debug( LDAP_DEBUG_TRACE, "forward_response: " "%s to client connid=%lu request msgid=%d\n", lload_msgtype2str( response_tag ), op->o_client_connid, msgid ); checked_lock( &client->c_io_mutex ); output = client->c_pendingber; if ( output == NULL && (output = ber_alloc()) == NULL ) { ber_free( ber, 1 ); checked_unlock( &client->c_io_mutex ); return -1; } client->c_pendingber = output; ber_printf( output, "t{titOtO}", LDAP_TAG_MESSAGE, LDAP_TAG_MSGID, msgid, response_tag, &response, LDAP_TAG_CONTROLS, BER_BV_OPTIONAL( &controls ) ); checked_unlock( &client->c_io_mutex ); ber_free( ber, 1 ); connection_write_cb( -1, 0, client ); return 0; } int forward_final_response( LloadConnection *client, LloadOperation *op, BerElement *ber ) { int rc; Debug( LDAP_DEBUG_STATS, "forward_final_response: " "connid=%lu msgid=%d finishing up with a request for " "client connid=%lu\n", op->o_upstream_connid, op->o_upstream_msgid, op->o_client_connid ); rc = forward_response( client, op, ber ); op->o_res = LLOAD_OP_COMPLETED; if ( !op->o_pin_id ) { operation_unlink( op ); } return rc; } static int handle_unsolicited( LloadConnection *c, BerElement *ber ) { CONNECTION_ASSERT_LOCKED(c); if ( c->c_state != LLOAD_C_PREPARING ) { c->c_state = LLOAD_C_CLOSING; } Debug( LDAP_DEBUG_STATS, "handle_unsolicited: " "teardown for upstream connection connid=%lu\n", c->c_connid ); CONNECTION_DESTROY(c); ber_free( ber, 1 ); return -1; } /* * Pull c->c_currentber from the connection and try to look up the operation on * the upstream. * * If it's a notice of disconnection, we won't find it and need to tear down * the connection and tell the clients, if we can't find the operation, ignore * the message (either client already disconnected/abandoned it or the upstream * is pulling our leg). * * Some responses need special handling: * - Bind response * - VC response where the client requested a Bind (both need to update the * client's bind status) * - search entries/referrals and intermediate responses (will not trigger * operation to be removed) * * If the worker pool is overloaded, we might be called directly from * the read callback, at that point, the connection hasn't been muted. * * TODO: when the client already has data pending on write, we should mute the * upstream. * - should record the BerElement on the Op and the Op on the client * * The following hold on entering any of the handlers: * - op->o_upstream_refcnt > 0 * - op->o_upstream->c_refcnt > 0 * - op->o_client->c_refcnt > 0 */ static int handle_one_response( LloadConnection *c ) { BerElement *ber; LloadOperation *op = NULL, needle = { .o_upstream_connid = c->c_connid }; LloadOperationHandler handler = NULL; ber_tag_t tag; ber_len_t len; int rc = LDAP_SUCCESS; ber = c->c_currentber; c->c_currentber = NULL; tag = ber_get_int( ber, &needle.o_upstream_msgid ); if ( tag != LDAP_TAG_MSGID ) { rc = -1; ber_free( ber, 1 ); goto fail; } CONNECTION_LOCK(c); if ( needle.o_upstream_msgid == 0 ) { return handle_unsolicited( c, ber ); } else if ( !( op = ldap_tavl_find( c->c_ops, &needle, operation_upstream_cmp ) ) ) { /* Already abandoned, do nothing */ CONNECTION_UNLOCK(c); ber_free( ber, 1 ); return rc; /* } else if ( op->o_response_pending ) { c->c_pendingop = op; event_del( c->c_read_event ); */ } else { CONNECTION_UNLOCK(c); /* op->o_response_pending = ber; */ tag = ber_peek_tag( ber, &len ); switch ( tag ) { case LDAP_RES_SEARCH_ENTRY: case LDAP_RES_SEARCH_REFERENCE: case LDAP_RES_INTERMEDIATE: handler = forward_response; break; case LDAP_RES_BIND: handler = handle_bind_response; break; case LDAP_RES_EXTENDED: if ( op->o_tag == LDAP_REQ_BIND ) { #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS if ( lload_features & LLOAD_FEATURE_VC ) { handler = handle_vc_bind_response; } else #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */ { handler = handle_whoami_response; } } break; } if ( !handler ) { handler = forward_final_response; } } if ( op ) { op->o_last_response = slap_get_time(); Debug( LDAP_DEBUG_STATS2, "handle_one_response: " "upstream connid=%lu, processing response for " "client connid=%lu, msgid=%d\n", c->c_connid, op->o_client_connid, op->o_client_msgid ); } else { tag = ber_peek_tag( ber, &len ); Debug( LDAP_DEBUG_STATS2, "handle_one_response: " "upstream connid=%lu, %s, msgid=%d not for a pending " "operation\n", c->c_connid, lload_msgtype2str( tag ), needle.o_upstream_msgid ); } if ( handler ) { LloadConnection *client; checked_lock( &op->o_link_mutex ); client = op->o_client; checked_unlock( &op->o_link_mutex ); if ( client && IS_ALIVE( client, c_live ) ) { rc = handler( client, op, ber ); } else { ber_free( ber, 1 ); } } else { assert(0); ber_free( ber, 1 ); } fail: if ( rc ) { Debug( LDAP_DEBUG_STATS, "handle_one_response: " "error on processing a response (%s) on upstream connection " "connid=%ld, tag=%lx\n", lload_msgtype2str( tag ), c->c_connid, tag ); CONNECTION_LOCK_DESTROY(c); } return rc; } #ifdef HAVE_CYRUS_SASL static int sasl_bind_step( LloadConnection *c, BerValue *scred, BerValue *ccred ) { LloadBackend *b = c->c_backend; sasl_conn_t *ctx = c->c_sasl_authctx; sasl_interact_t *prompts = NULL; unsigned credlen; int rc = -1; if ( !ctx ) { const char *mech = NULL; #ifdef HAVE_TLS void *ssl; #endif /* HAVE_TLS */ if ( sasl_client_new( "ldap", b->b_host, NULL, NULL, client_callbacks, 0, &ctx ) != SASL_OK ) { goto done; } c->c_sasl_authctx = ctx; assert( c->c_sasl_defaults == NULL ); c->c_sasl_defaults = lutil_sasl_defaults( NULL, bindconf.sb_saslmech.bv_val, bindconf.sb_realm.bv_val, bindconf.sb_authcId.bv_val, bindconf.sb_cred.bv_val, bindconf.sb_authzId.bv_val ); #ifdef HAVE_TLS /* Check for TLS */ ssl = ldap_pvt_tls_sb_ctx( c->c_sb ); if ( ssl ) { struct berval authid = BER_BVNULL; ber_len_t ssf; ssf = ldap_pvt_tls_get_strength( ssl ); (void)ldap_pvt_tls_get_my_dn( ssl, &authid, NULL, 0 ); sasl_setprop( ctx, SASL_SSF_EXTERNAL, &ssf ); sasl_setprop( ctx, SASL_AUTH_EXTERNAL, authid.bv_val ); ch_free( authid.bv_val ); #ifdef SASL_CHANNEL_BINDING /* 2.1.25+ */ { char cbinding[64]; struct berval cbv = { sizeof(cbinding), cbinding }; if ( ldap_pvt_tls_get_unique( ssl, &cbv, 0 ) ) { sasl_channel_binding_t *cb = ch_malloc( sizeof(*cb) + cbv.bv_len ); void *cb_data; cb->name = "ldap"; cb->critical = 0; cb->len = cbv.bv_len; cb->data = cb_data = cb + 1; memcpy( cb_data, cbv.bv_val, cbv.bv_len ); sasl_setprop( ctx, SASL_CHANNEL_BINDING, cb ); c->c_sasl_cbinding = cb; } } #endif } #endif #if !defined(_WIN32) /* Check for local */ if ( b->b_proto == LDAP_PROTO_IPC ) { char authid[sizeof( "gidNumber=4294967295+uidNumber=4294967295," "cn=peercred,cn=external,cn=auth" )]; int ssf = LDAP_PVT_SASL_LOCAL_SSF; sprintf( authid, "gidNumber=%u+uidNumber=%u," "cn=peercred,cn=external,cn=auth", getegid(), geteuid() ); sasl_setprop( ctx, SASL_SSF_EXTERNAL, &ssf ); sasl_setprop( ctx, SASL_AUTH_EXTERNAL, authid ); } #endif do { rc = sasl_client_start( ctx, bindconf.sb_saslmech.bv_val, &prompts, (const char **)&ccred->bv_val, &credlen, &mech ); if ( rc == SASL_INTERACT ) { if ( lutil_sasl_interact( NULL, LDAP_SASL_QUIET, c->c_sasl_defaults, prompts ) ) { break; } } } while ( rc == SASL_INTERACT ); ber_str2bv( mech, 0, 0, &c->c_sasl_bind_mech ); } else { assert( c->c_sasl_defaults ); do { rc = sasl_client_step( ctx, (scred == NULL) ? NULL : scred->bv_val, (scred == NULL) ? 0 : scred->bv_len, &prompts, (const char **)&ccred->bv_val, &credlen); if ( rc == SASL_INTERACT ) { if ( lutil_sasl_interact( NULL, LDAP_SASL_QUIET, c->c_sasl_defaults, prompts ) ) { break; } } } while ( rc == SASL_INTERACT ); } if ( rc == SASL_OK ) { sasl_ssf_t *ssf; rc = sasl_getprop( ctx, SASL_SSF, (const void **)(char *)&ssf ); if ( rc == SASL_OK && ssf && *ssf ) { Debug( LDAP_DEBUG_CONNS, "sasl_bind_step: " "connid=%lu mech=%s setting up a new SASL security layer\n", c->c_connid, c->c_sasl_bind_mech.bv_val ); ldap_pvt_sasl_install( c->c_sb, ctx ); } } ccred->bv_len = credlen; done: Debug( LDAP_DEBUG_TRACE, "sasl_bind_step: " "connid=%lu next step for SASL bind mech=%s rc=%d\n", c->c_connid, c->c_sasl_bind_mech.bv_val, rc ); return rc; } #endif /* HAVE_CYRUS_SASL */ int upstream_bind_cb( LloadConnection *c ) { BerElement *ber = c->c_currentber; LloadBackend *b = c->c_backend; BerValue matcheddn, message; ber_tag_t tag; ber_int_t msgid, result; c->c_currentber = NULL; if ( ber_scanf( ber, "it", &msgid, &tag ) == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: " "protocol violation from server\n" ); goto fail; } if ( msgid != ( c->c_next_msgid - 1 ) || tag != LDAP_RES_BIND ) { Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: " "unexpected %s from server, msgid=%d\n", lload_msgtype2str( tag ), msgid ); goto fail; } if ( ber_scanf( ber, "{emm" /* "}" */, &result, &matcheddn, &message ) == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: " "response does not conform with a bind response\n" ); goto fail; } switch ( result ) { case LDAP_SUCCESS: #ifdef HAVE_CYRUS_SASL case LDAP_SASL_BIND_IN_PROGRESS: if ( !BER_BVISNULL( &c->c_sasl_bind_mech ) ) { BerValue scred = BER_BVNULL, ccred; ber_len_t len; int rc; if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SASL_RES_CREDS && ber_scanf( ber, "m", &scred ) == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: " "sasl bind response malformed\n" ); goto fail; } rc = sasl_bind_step( c, &scred, &ccred ); if ( rc != SASL_OK && ( rc != SASL_CONTINUE || result == LDAP_SUCCESS ) ) { goto fail; } if ( result == LDAP_SASL_BIND_IN_PROGRESS ) { BerElement *outber; checked_lock( &c->c_io_mutex ); outber = c->c_pendingber; if ( outber == NULL && (outber = ber_alloc()) == NULL ) { checked_unlock( &c->c_io_mutex ); goto fail; } c->c_pendingber = outber; msgid = c->c_next_msgid++; ber_printf( outber, "{it{iOt{OON}N}}", msgid, LDAP_REQ_BIND, LDAP_VERSION3, &bindconf.sb_binddn, LDAP_AUTH_SASL, &c->c_sasl_bind_mech, BER_BV_OPTIONAL( &ccred ) ); checked_unlock( &c->c_io_mutex ); connection_write_cb( -1, 0, c ); if ( rc == SASL_OK ) { BER_BVZERO( &c->c_sasl_bind_mech ); } break; } } if ( result == LDAP_SASL_BIND_IN_PROGRESS ) { goto fail; } #endif /* HAVE_CYRUS_SASL */ CONNECTION_LOCK(c); c->c_pdu_cb = handle_one_response; c->c_state = LLOAD_C_READY; c->c_type = LLOAD_C_OPEN; c->c_read_timeout = NULL; Debug( LDAP_DEBUG_CONNS, "upstream_bind_cb: " "connection connid=%lu for backend server '%s' is ready " "for use\n", c->c_connid, b->b_name.bv_val ); CONNECTION_UNLOCK(c); checked_lock( &b->b_mutex ); LDAP_CIRCLEQ_REMOVE( &b->b_preparing, c, c_next ); b->b_active++; b->b_opening--; b->b_failed = 0; if ( b->b_last_conn ) { LDAP_CIRCLEQ_INSERT_AFTER( &b->b_conns, b->b_last_conn, c, c_next ); } else { LDAP_CIRCLEQ_INSERT_HEAD( &b->b_conns, c, c_next ); } b->b_last_conn = c; backend_retry( b ); checked_unlock( &b->b_mutex ); break; default: Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: " "upstream bind failed, rc=%d, message='%s'\n", result, message.bv_val ); goto fail; } checked_lock( &c->c_io_mutex ); c->c_io_state &= ~LLOAD_C_READ_HANDOVER; checked_unlock( &c->c_io_mutex ); event_add( c->c_read_event, c->c_read_timeout ); ber_free( ber, 1 ); return -1; fail: CONNECTION_LOCK_DESTROY(c); ber_free( ber, 1 ); return -1; } void * upstream_bind( void *ctx, void *arg ) { LloadConnection *c = arg; BerElement *ber; ber_int_t msgid; /* A reference was passed on to us */ assert( IS_ALIVE( c, c_refcnt ) ); if ( !IS_ALIVE( c, c_live ) ) { RELEASE_REF( c, c_refcnt, c->c_destroy ); return NULL; } CONNECTION_LOCK(c); assert( !event_pending( c->c_read_event, EV_READ, NULL ) ); c->c_pdu_cb = upstream_bind_cb; CONNECTION_UNLOCK(c); checked_lock( &c->c_io_mutex ); ber = c->c_pendingber; if ( ber == NULL && (ber = ber_alloc()) == NULL ) { goto fail; } c->c_pendingber = ber; msgid = c->c_next_msgid++; if ( bindconf.sb_method == LDAP_AUTH_SIMPLE ) { /* simple bind */ ber_printf( ber, "{it{iOtON}}", msgid, LDAP_REQ_BIND, LDAP_VERSION3, &bindconf.sb_binddn, LDAP_AUTH_SIMPLE, &bindconf.sb_cred ); #ifdef HAVE_CYRUS_SASL } else { BerValue cred; int rc; rc = sasl_bind_step( c, NULL, &cred ); if ( rc != SASL_OK && rc != SASL_CONTINUE ) { goto fail; } ber_printf( ber, "{it{iOt{OON}N}}", msgid, LDAP_REQ_BIND, LDAP_VERSION3, &bindconf.sb_binddn, LDAP_AUTH_SASL, &c->c_sasl_bind_mech, BER_BV_OPTIONAL( &cred ) ); if ( rc == SASL_OK ) { BER_BVZERO( &c->c_sasl_bind_mech ); } #endif /* HAVE_CYRUS_SASL */ } /* TODO: can we be paused at this point? Then we'd have to move this line * after connection_write_cb */ c->c_io_state &= ~LLOAD_C_READ_HANDOVER; checked_unlock( &c->c_io_mutex ); connection_write_cb( -1, 0, c ); CONNECTION_LOCK(c); c->c_read_timeout = lload_timeout_net; event_add( c->c_read_event, c->c_read_timeout ); CONNECTION_UNLOCK(c); RELEASE_REF( c, c_refcnt, c->c_destroy ); return NULL; fail: checked_unlock( &c->c_io_mutex ); CONNECTION_LOCK_DESTROY(c); RELEASE_REF( c, c_refcnt, c->c_destroy ); return NULL; } /* * The backend is already locked when entering the function. */ static int upstream_finish( LloadConnection *c ) { LloadBackend *b = c->c_backend; int is_bindconn = 0; assert_locked( &b->b_mutex ); CONNECTION_ASSERT_LOCKED(c); assert( c->c_live ); c->c_pdu_cb = handle_one_response; /* Unless we are configured to use the VC exop, consider allocating the * connection into the bind conn pool. Start off by allocating one for * general use, then one for binds, then we start filling up the general * connection pool, finally the bind pool */ if ( #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS !(lload_features & LLOAD_FEATURE_VC) && #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */ b->b_active && b->b_numbindconns ) { if ( !b->b_bindavail ) { is_bindconn = 1; } else if ( b->b_active >= b->b_numconns && b->b_bindavail < b->b_numbindconns ) { is_bindconn = 1; } } if ( is_bindconn ) { LDAP_CIRCLEQ_REMOVE( &b->b_preparing, c, c_next ); c->c_state = LLOAD_C_READY; c->c_type = LLOAD_C_BIND; b->b_bindavail++; b->b_opening--; b->b_failed = 0; if ( b->b_last_bindconn ) { LDAP_CIRCLEQ_INSERT_AFTER( &b->b_bindconns, b->b_last_bindconn, c, c_next ); } else { LDAP_CIRCLEQ_INSERT_HEAD( &b->b_bindconns, c, c_next ); } b->b_last_bindconn = c; } else if ( bindconf.sb_method == LDAP_AUTH_NONE ) { LDAP_CIRCLEQ_REMOVE( &b->b_preparing, c, c_next ); c->c_state = LLOAD_C_READY; c->c_type = LLOAD_C_OPEN; b->b_active++; b->b_opening--; b->b_failed = 0; if ( b->b_last_conn ) { LDAP_CIRCLEQ_INSERT_AFTER( &b->b_conns, b->b_last_conn, c, c_next ); } else { LDAP_CIRCLEQ_INSERT_HEAD( &b->b_conns, c, c_next ); } b->b_last_conn = c; } else { if ( ldap_pvt_thread_pool_submit( &connection_pool, upstream_bind, c ) ) { Debug( LDAP_DEBUG_ANY, "upstream_finish: " "failed to set up a bind callback for connid=%lu\n", c->c_connid ); return -1; } /* keep a reference for upstream_bind */ acquire_ref( &c->c_refcnt ); Debug( LDAP_DEBUG_CONNS, "upstream_finish: " "scheduled a bind callback for connid=%lu\n", c->c_connid ); return LDAP_SUCCESS; } event_add( c->c_read_event, c->c_read_timeout ); Debug( LDAP_DEBUG_CONNS, "upstream_finish: " "%sconnection connid=%lu for backend server '%s' is ready for " "use\n", is_bindconn ? "bind " : "", c->c_connid, b->b_name.bv_val ); backend_retry( b ); return LDAP_SUCCESS; } #ifdef HAVE_TLS static void upstream_tls_handshake_cb( evutil_socket_t s, short what, void *arg ) { LloadConnection *c = arg; LloadBackend *b; epoch_t epoch; int rc = LDAP_SUCCESS; CONNECTION_LOCK(c); if ( what & EV_TIMEOUT ) { Debug( LDAP_DEBUG_CONNS, "upstream_tls_handshake_cb: " "connid=%lu, timeout reached, destroying\n", c->c_connid ); goto fail; } b = c->c_backend; rc = ldap_pvt_tls_connect( lload_tls_backend_ld, c->c_sb, b->b_host ); if ( rc < 0 ) { goto fail; } if ( rc == 0 ) { struct event_base *base = event_get_base( c->c_read_event ); /* * We're finished, replace the callbacks * * This is deadlock-safe, since both share the same base - the one * that's just running us. */ event_del( c->c_read_event ); event_del( c->c_write_event ); c->c_read_timeout = NULL; event_assign( c->c_read_event, base, c->c_fd, EV_READ|EV_PERSIST, connection_read_cb, c ); event_assign( c->c_write_event, base, c->c_fd, EV_WRITE, connection_write_cb, c ); Debug( LDAP_DEBUG_CONNS, "upstream_tls_handshake_cb: " "connid=%lu finished\n", c->c_connid ); c->c_is_tls = LLOAD_TLS_ESTABLISHED; CONNECTION_UNLOCK(c); checked_lock( &b->b_mutex ); CONNECTION_LOCK(c); rc = upstream_finish( c ); checked_unlock( &b->b_mutex ); if ( rc ) { goto fail; } } else if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_WRITE, NULL ) ) { event_add( c->c_write_event, lload_write_timeout ); Debug( LDAP_DEBUG_CONNS, "upstream_tls_handshake_cb: " "connid=%lu need write rc=%d\n", c->c_connid, rc ); } CONNECTION_UNLOCK(c); return; fail: Debug( LDAP_DEBUG_CONNS, "upstream_tls_handshake_cb: " "connid=%lu failed rc=%d\n", c->c_connid, rc ); assert( c->c_ops == NULL ); epoch = epoch_join(); CONNECTION_DESTROY(c); epoch_leave( epoch ); } static int upstream_starttls( LloadConnection *c ) { BerValue matcheddn, message, responseOid, startTLSOid = BER_BVC(LDAP_EXOP_START_TLS); BerElement *ber = c->c_currentber; struct event_base *base; ber_int_t msgid, result; ber_tag_t tag; c->c_currentber = NULL; CONNECTION_LOCK(c); if ( ber_scanf( ber, "it", &msgid, &tag ) == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, "upstream_starttls: " "protocol violation from server\n" ); goto fail; } if ( msgid != ( c->c_next_msgid - 1 ) || tag != LDAP_RES_EXTENDED ) { Debug( LDAP_DEBUG_ANY, "upstream_starttls: " "unexpected %s from server, msgid=%d\n", lload_msgtype2str( tag ), msgid ); goto fail; } if ( ber_scanf( ber, "{emm}", &result, &matcheddn, &message ) == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, "upstream_starttls: " "protocol violation on StartTLS response\n" ); goto fail; } if ( (tag = ber_get_tag( ber )) != LBER_DEFAULT ) { if ( tag != LDAP_TAG_EXOP_RES_OID || ber_scanf( ber, "{m}", &responseOid ) == LBER_DEFAULT ) { Debug( LDAP_DEBUG_ANY, "upstream_starttls: " "protocol violation on StartTLS response\n" ); goto fail; } if ( ber_bvcmp( &responseOid, &startTLSOid ) ) { Debug( LDAP_DEBUG_ANY, "upstream_starttls: " "oid=%s not a StartTLS response\n", responseOid.bv_val ); goto fail; } } if ( result != LDAP_SUCCESS ) { LloadBackend *b = c->c_backend; int rc; Debug( LDAP_DEBUG_STATS, "upstream_starttls: " "server doesn't support StartTLS rc=%d message='%s'%s\n", result, message.bv_val, (c->c_is_tls == LLOAD_STARTTLS_OPTIONAL) ? ", ignored" : "" ); if ( c->c_is_tls != LLOAD_STARTTLS_OPTIONAL ) { goto fail; } c->c_is_tls = LLOAD_CLEARTEXT; CONNECTION_UNLOCK(c); checked_lock( &b->b_mutex ); CONNECTION_LOCK(c); rc = upstream_finish( c ); checked_unlock( &b->b_mutex ); if ( rc ) { goto fail; } ber_free( ber, 1 ); CONNECTION_UNLOCK(c); checked_lock( &c->c_io_mutex ); c->c_io_state &= ~LLOAD_C_READ_HANDOVER; checked_unlock( &c->c_io_mutex ); /* Do not keep handle_pdus running, we have adjusted c_read_event as we * need it. */ return -1; } base = event_get_base( c->c_read_event ); c->c_io_state &= ~LLOAD_C_READ_HANDOVER; event_del( c->c_read_event ); event_del( c->c_write_event ); c->c_read_timeout = lload_timeout_net; event_assign( c->c_read_event, base, c->c_fd, EV_READ|EV_PERSIST, upstream_tls_handshake_cb, c ); event_assign( c->c_write_event, base, c->c_fd, EV_WRITE, upstream_tls_handshake_cb, c ); event_add( c->c_read_event, c->c_read_timeout ); event_add( c->c_write_event, lload_write_timeout ); CONNECTION_UNLOCK(c); ber_free( ber, 1 ); return -1; fail: ber_free( ber, 1 ); CONNECTION_DESTROY(c); return -1; } #endif /* HAVE_TLS */ /* * We must already hold b->b_mutex when called. */ LloadConnection * upstream_init( ber_socket_t s, LloadBackend *b ) { LloadConnection *c; struct event_base *base = lload_get_base( s ); struct event *event; int flags; assert( b != NULL ); flags = (b->b_proto == LDAP_PROTO_IPC) ? CONN_IS_IPC : 0; if ( (c = lload_connection_init( s, b->b_host, flags )) == NULL ) { return NULL; } CONNECTION_LOCK(c); c->c_backend = b; #ifdef HAVE_TLS c->c_is_tls = b->b_tls; #endif c->c_pdu_cb = handle_one_response; LDAP_CIRCLEQ_INSERT_HEAD( &b->b_preparing, c, c_next ); c->c_type = LLOAD_C_PREPARING; { ber_len_t max = sockbuf_max_incoming_upstream; ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max ); } event = event_new( base, s, EV_READ|EV_PERSIST, connection_read_cb, c ); if ( !event ) { Debug( LDAP_DEBUG_ANY, "upstream_init: " "Read event could not be allocated\n" ); goto fail; } c->c_read_event = event; event = event_new( base, s, EV_WRITE, connection_write_cb, c ); if ( !event ) { Debug( LDAP_DEBUG_ANY, "upstream_init: " "Write event could not be allocated\n" ); goto fail; } /* We only add the write event when we have data pending */ c->c_write_event = event; c->c_destroy = upstream_destroy; c->c_unlink = upstream_unlink; #ifdef HAVE_TLS if ( c->c_is_tls == LLOAD_CLEARTEXT ) { #endif /* HAVE_TLS */ if ( upstream_finish( c ) ) { goto fail; } #ifdef HAVE_TLS } else if ( c->c_is_tls == LLOAD_LDAPS ) { event_assign( c->c_read_event, base, s, EV_READ|EV_PERSIST, upstream_tls_handshake_cb, c ); event_add( c->c_read_event, c->c_read_timeout ); event_assign( c->c_write_event, base, s, EV_WRITE, upstream_tls_handshake_cb, c ); event_add( c->c_write_event, lload_write_timeout ); } else if ( c->c_is_tls == LLOAD_STARTTLS || c->c_is_tls == LLOAD_STARTTLS_OPTIONAL ) { BerElement *output; checked_lock( &c->c_io_mutex ); if ( (output = c->c_pendingber = ber_alloc()) == NULL ) { checked_unlock( &c->c_io_mutex ); goto fail; } ber_printf( output, "t{tit{ts}}", LDAP_TAG_MESSAGE, LDAP_TAG_MSGID, c->c_next_msgid++, LDAP_REQ_EXTENDED, LDAP_TAG_EXOP_REQ_OID, LDAP_EXOP_START_TLS ); checked_unlock( &c->c_io_mutex ); c->c_pdu_cb = upstream_starttls; CONNECTION_UNLOCK(c); connection_write_cb( s, 0, c ); CONNECTION_LOCK(c); if ( IS_ALIVE( c, c_live ) ) { event_add( c->c_read_event, c->c_read_timeout ); } } #endif /* HAVE_TLS */ CONNECTION_UNLOCK(c); return c; fail: if ( c->c_write_event ) { event_del( c->c_write_event ); event_free( c->c_write_event ); } if ( c->c_read_event ) { event_del( c->c_read_event ); event_free( c->c_read_event ); } c->c_state = LLOAD_C_INVALID; c->c_live--; c->c_refcnt--; connection_destroy( c ); return NULL; } static void upstream_unlink( LloadConnection *c ) { LloadBackend *b = c->c_backend; struct event *read_event, *write_event; TAvlnode *root; long freed, executing; Debug( LDAP_DEBUG_CONNS, "upstream_unlink: " "removing upstream connid=%lu\n", c->c_connid ); CONNECTION_ASSERT_LOCKED(c); assert( c->c_state != LLOAD_C_INVALID ); assert( c->c_state != LLOAD_C_DYING ); c->c_state = LLOAD_C_DYING; read_event = c->c_read_event; write_event = c->c_write_event; root = c->c_ops; c->c_ops = NULL; executing = c->c_n_ops_executing; c->c_n_ops_executing = 0; CONNECTION_UNLOCK(c); freed = ldap_tavl_free( root, (AVL_FREE)operation_lost_upstream ); assert( freed == executing ); /* * Avoid a deadlock: * event_del will block if the event is currently executing its callback, * that callback might be waiting to lock c->c_mutex */ if ( read_event ) { event_del( read_event ); } if ( write_event ) { event_del( write_event ); } checked_lock( &b->b_mutex ); if ( c->c_type == LLOAD_C_PREPARING ) { LDAP_CIRCLEQ_REMOVE( &b->b_preparing, c, c_next ); b->b_opening--; b->b_failed++; } else if ( c->c_type == LLOAD_C_BIND ) { if ( c == b->b_last_bindconn ) { LloadConnection *prev = LDAP_CIRCLEQ_LOOP_PREV( &b->b_bindconns, c, c_next ); if ( prev == c ) { b->b_last_bindconn = NULL; } else { b->b_last_bindconn = prev; } } LDAP_CIRCLEQ_REMOVE( &b->b_bindconns, c, c_next ); b->b_bindavail--; } else { if ( c == b->b_last_conn ) { LloadConnection *prev = LDAP_CIRCLEQ_LOOP_PREV( &b->b_conns, c, c_next ); if ( prev == c ) { b->b_last_conn = NULL; } else { b->b_last_conn = prev; } } LDAP_CIRCLEQ_REMOVE( &b->b_conns, c, c_next ); b->b_active--; } b->b_n_ops_executing -= executing; backend_retry( b ); checked_unlock( &b->b_mutex ); CONNECTION_LOCK(c); CONNECTION_ASSERT_LOCKED(c); } void upstream_destroy( LloadConnection *c ) { Debug( LDAP_DEBUG_CONNS, "upstream_destroy: " "freeing connection connid=%lu\n", c->c_connid ); CONNECTION_LOCK(c); assert( c->c_state == LLOAD_C_DYING ); c->c_state = LLOAD_C_INVALID; assert( c->c_ops == NULL ); if ( c->c_read_event ) { event_free( c->c_read_event ); c->c_read_event = NULL; } if ( c->c_write_event ) { event_free( c->c_write_event ); c->c_write_event = NULL; } if ( c->c_type != LLOAD_C_BIND ) { BER_BVZERO( &c->c_sasl_bind_mech ); } connection_destroy( c ); } openldap-2.5.11+dfsg/servers/lloadd/monitor.c0000644000175000017500000010307514172327167017630 0ustar ryanryan/* init.c - initialize various things */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ #include "portable.h" #include #include #include #include #include "lload.h" #include "lber_pvt.h" #include "ldap_rq.h" #include "lload-config.h" #include "../slapd/back-monitor/back-monitor.h" #define LLOAD_MONITOR_BALANCER_NAME "Load Balancer" #define LLOAD_MONITOR_BALANCER_RDN \ SLAPD_MONITOR_AT "=" LLOAD_MONITOR_BALANCER_NAME #define LLOAD_MONITOR_BALANCER_DN \ LLOAD_MONITOR_BALANCER_RDN "," SLAPD_MONITOR_BACKEND_DN #define LLOAD_MONITOR_INCOMING_NAME "Incoming Connections" #define LLOAD_MONITOR_INCOMING_RDN \ SLAPD_MONITOR_AT "=" LLOAD_MONITOR_INCOMING_NAME #define LLOAD_MONITOR_INCOMING_DN \ LLOAD_MONITOR_INCOMING_RDN "," LLOAD_MONITOR_BALANCER_DN #define LLOAD_MONITOR_OPERATIONS_NAME "Operations" #define LLOAD_MONITOR_OPERATIONS_RDN \ SLAPD_MONITOR_AT "=" LLOAD_MONITOR_OPERATIONS_NAME #define LLOAD_MONITOR_OPERATIONS_DN \ LLOAD_MONITOR_OPERATIONS_RDN "," LLOAD_MONITOR_BALANCER_DN #define LLOAD_MONITOR_BACKENDS_NAME "Backend Servers" #define LLOAD_MONITOR_BACKENDS_RDN \ SLAPD_MONITOR_AT "=" LLOAD_MONITOR_BACKENDS_NAME #define LLOAD_MONITOR_BACKENDS_DN \ LLOAD_MONITOR_BACKENDS_RDN "," LLOAD_MONITOR_BALANCER_DN struct lload_monitor_ops_t { struct berval rdn; } lload_monitor_op[] = { { BER_BVC("cn=Bind") }, { BER_BVC("cn=Other") }, { BER_BVNULL } }; static ObjectClass *oc_olmBalancer; static ObjectClass *oc_olmBalancerServer; static ObjectClass *oc_olmBalancerConnection; static ObjectClass *oc_olmBalancerOperation; static ObjectClass *oc_monitorContainer; static ObjectClass *oc_monitorCounterObject; static AttributeDescription *ad_olmServerURI; static AttributeDescription *ad_olmReceivedOps; static AttributeDescription *ad_olmForwardedOps; static AttributeDescription *ad_olmRejectedOps; static AttributeDescription *ad_olmCompletedOps; static AttributeDescription *ad_olmFailedOps; static AttributeDescription *ad_olmConnectionType; static AttributeDescription *ad_olmPendingOps; static AttributeDescription *ad_olmPendingConnections; static AttributeDescription *ad_olmActiveConnections; static AttributeDescription *ad_olmIncomingConnections; static AttributeDescription *ad_olmOutgoingConnections; static struct { char *name; char *oid; } s_oid[] = { { "olmBalancerAttributes", "olmModuleAttributes:1" }, { "olmBalancerObjectClasses", "olmModuleObjectClasses:1" }, { NULL } }; static struct { char *desc; AttributeDescription **ad; } s_at[] = { { "( olmBalancerAttributes:1 " "NAME ( 'olmServerURI' ) " "DESC 'URI of a backend server' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 " "EQUALITY caseIgnoreMatch " "NO-USER-MODIFICATION " "USAGE dSAOperation )", &ad_olmServerURI }, { "( olmBalancerAttributes:2 " "NAME ( 'olmReceivedOps' ) " "DESC 'monitor received operations' " "SUP monitorCounter " "NO-USER-MODIFICATION " "USAGE dSAOperation )", &ad_olmReceivedOps }, { "( olmBalancerAttributes:3 " "NAME ( 'olmForwardedOps' ) " "DESC 'monitor forwarded operations' " "SUP monitorCounter " "NO-USER-MODIFICATION " "USAGE dSAOperation )", &ad_olmForwardedOps }, { "( olmBalancerAttributes:4 " "NAME ( 'olmRejectedOps' ) " "DESC 'monitor rejected operations' " "SUP monitorCounter " "NO-USER-MODIFICATION " "USAGE dSAOperation )", &ad_olmRejectedOps }, { "( olmBalancerAttributes:5 " "NAME ( 'olmCompletedOps' ) " "DESC 'monitor completed operations' " "SUP monitorCounter " "NO-USER-MODIFICATION " "USAGE dSAOperation )", &ad_olmCompletedOps }, { "( olmBalancerAttributes:6 " "NAME ( 'olmFailedOps' ) " "DESC 'monitor failed operations' " "SUP monitorCounter " "NO-USER-MODIFICATION " "USAGE dSAOperation )", &ad_olmFailedOps }, { "( olmBalancerAttributes:7 " "NAME ( 'olmPendingOps' ) " "DESC 'monitor number of pending operations' " "EQUALITY integerMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " "NO-USER-MODIFICATION " "USAGE dSAOperation )", &ad_olmPendingOps }, { "( olmBalancerAttributes:8 " "NAME ( 'olmPendingConnections' ) " "DESC 'monitor number of pending connections' " "EQUALITY integerMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " "NO-USER-MODIFICATION " "USAGE dSAOperation )", &ad_olmPendingConnections }, { "( olmBalancerAttributes:9 " "NAME ( 'olmActiveConnections' ) " "DESC 'monitor number of active connections' " "EQUALITY integerMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " "NO-USER-MODIFICATION " "USAGE dSAOperation )", &ad_olmActiveConnections }, { "( olmBalancerAttributes:10 " "NAME ( 'olmConnectionType' ) " "DESC 'Connection type' " "EQUALITY caseIgnoreMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 " "NO-USER-MODIFICATION " "USAGE dSAOperation )", &ad_olmConnectionType }, { "( olmBalancerAttributes:11 " "NAME ( 'olmIncomingConnections' ) " "DESC 'monitor number of incoming connections' " "EQUALITY integerMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " "NO-USER-MODIFICATION " "USAGE dSAOperation )", &ad_olmIncomingConnections }, { "( olmBalancerAttributes:12 " "NAME ( 'olmOutgoingConnections' ) " "DESC 'monitor number of active connections' " "EQUALITY integerMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " "NO-USER-MODIFICATION " "USAGE dSAOperation )", &ad_olmOutgoingConnections }, { NULL } }; static struct { char *name; ObjectClass **oc; } s_moc[] = { { "monitorContainer", &oc_monitorContainer }, { "monitorCounterObject", &oc_monitorCounterObject }, { NULL } }; static struct { char *desc; ObjectClass **oc; } s_oc[] = { { "( olmBalancerObjectClasses:1 " "NAME ( 'olmBalancer' ) " "SUP top STRUCTURAL " "MAY ( " "olmIncomingConnections " "$ olmOutgoingConnections " ") )", &oc_olmBalancer }, { "( olmBalancerObjectClasses:2 " "NAME ( 'olmBalancerServer' ) " "SUP top STRUCTURAL " "MAY ( " "olmServerURI " "$ olmActiveConnections " "$ olmPendingConnections " "$ olmPendingOps" "$ olmReceivedOps " "$ olmCompletedOps " "$ olmFailedOps " ") )", &oc_olmBalancerServer }, { "( olmBalancerObjectClasses:3 " "NAME ( 'olmBalancerOperation' ) " "SUP top STRUCTURAL " "MAY ( " "olmReceivedOps " "$ olmForwardedOps " "$ olmRejectedOps " "$ olmCompletedOps " "$ olmFailedOps " ") )", &oc_olmBalancerOperation }, { "( olmBalancerObjectClasses:4 " "NAME ( 'olmBalancerConnection' ) " "SUP top STRUCTURAL " "MAY ( " "olmConnectionType " "$ olmPendingOps " "$ olmReceivedOps " "$ olmCompletedOps " "$ olmFailedOps " ") )", &oc_olmBalancerConnection }, { NULL } }; static int lload_monitor_subsystem_destroy( BackendDB *be, monitor_subsys_t *ms ) { return LDAP_SUCCESS; } static int lload_monitor_backend_destroy( BackendDB *be, monitor_subsys_t *ms ) { LloadBackend *b = ms->mss_private; monitor_extra_t *mbe; int rc = LDAP_SUCCESS; mbe = (monitor_extra_t *)be->bd_info->bi_extra; if ( b->b_monitor ) { ms->mss_destroy = lload_monitor_subsystem_destroy; assert( b->b_monitor == ms ); b->b_monitor = NULL; rc = mbe->unregister_entry( &ms->mss_ndn ); ber_memfree( ms->mss_dn.bv_val ); ber_memfree( ms->mss_ndn.bv_val ); } return rc; } static void lload_monitor_balancer_dispose( void **priv ) { return; } static int lload_monitor_balancer_free( Entry *e, void **priv ) { return LDAP_SUCCESS; } static int lload_monitor_balancer_update( Operation *op, SlapReply *rs, Entry *e, void *priv ) { Attribute *a; a = attr_find( e->e_attrs, ad_olmIncomingConnections ); assert( a != NULL ); UI2BV( &a->a_vals[0], lload_stats.global_incoming ); a = attr_find( e->e_attrs, ad_olmOutgoingConnections ); assert( a != NULL ); UI2BV( &a->a_vals[0], lload_stats.global_outgoing ); return SLAP_CB_CONTINUE; } static int lload_monitor_ops_update( Operation *op, SlapReply *rs, Entry *e, void *priv ) { Attribute *a; lload_counters_t *counters = (lload_counters_t *)priv; a = attr_find( e->e_attrs, ad_olmReceivedOps ); assert( a != NULL ); UI2BV( &a->a_vals[0], counters->lc_ops_received ); a = attr_find( e->e_attrs, ad_olmForwardedOps ); assert( a != NULL ); UI2BV( &a->a_vals[0], counters->lc_ops_forwarded ); a = attr_find( e->e_attrs, ad_olmRejectedOps ); assert( a != NULL ); UI2BV( &a->a_vals[0], counters->lc_ops_rejected ); a = attr_find( e->e_attrs, ad_olmCompletedOps ); assert( a != NULL ); UI2BV( &a->a_vals[0], counters->lc_ops_completed ); a = attr_find( e->e_attrs, ad_olmFailedOps ); assert( a != NULL ); UI2BV( &a->a_vals[0], counters->lc_ops_failed ); return SLAP_CB_CONTINUE; } static void lload_monitor_ops_dispose( void **priv ) { return; } static int lload_monitor_ops_free( Entry *e, void **priv ) { return LDAP_SUCCESS; } static int lload_monitor_balancer_init( BackendDB *be, monitor_subsys_t *ms ) { monitor_extra_t *mbe; Entry *e; int rc; monitor_callback_t *cb; struct berval value = BER_BVC("0"); assert( be != NULL ); mbe = (monitor_extra_t *)be->bd_info->bi_extra; dnNormalize( 0, NULL, NULL, &ms->mss_dn, &ms->mss_ndn, NULL ); e = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn, &ms->mss_rdn, oc_olmBalancer, NULL, NULL ); if ( e == NULL ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_balancer_init: " "unable to create entry \"%s,%s\"\n", ms->mss_rdn.bv_val, ms->mss_ndn.bv_val ); return -1; } ch_free( ms->mss_ndn.bv_val ); ber_dupbv( &ms->mss_dn, &e->e_name ); ber_dupbv( &ms->mss_ndn, &e->e_nname ); cb = ch_calloc( sizeof(monitor_callback_t), 1 ); cb->mc_update = lload_monitor_balancer_update; cb->mc_free = lload_monitor_balancer_free; cb->mc_dispose = lload_monitor_balancer_dispose; cb->mc_private = NULL; attr_merge_normalize_one( e, ad_olmIncomingConnections, &value, NULL ); attr_merge_normalize_one( e, ad_olmOutgoingConnections, &value, NULL ); rc = mbe->register_entry( e, cb, ms, 0 ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_balancer_init: " "unable to register entry \"%s\" for monitoring\n", e->e_name.bv_val ); goto done; } done: entry_free( e ); return rc; } static int lload_monitor_ops_init( BackendDB *be, monitor_subsys_t *ms ) { monitor_extra_t *mbe; Entry *e, *parent; int rc; int i; struct berval value = BER_BVC("0"); assert( be != NULL ); mbe = (monitor_extra_t *)be->bd_info->bi_extra; dnNormalize( 0, NULL, NULL, &ms->mss_dn, &ms->mss_ndn, NULL ); ms->mss_destroy = lload_monitor_subsystem_destroy; parent = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn, &ms->mss_rdn, oc_monitorContainer, NULL, NULL ); if ( parent == NULL ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_ops_init: " "unable to create entry \"%s,%s\"\n", ms->mss_rdn.bv_val, ms->mss_ndn.bv_val ); return -1; } ch_free( ms->mss_ndn.bv_val ); ber_dupbv( &ms->mss_dn, &parent->e_name ); ber_dupbv( &ms->mss_ndn, &parent->e_nname ); rc = mbe->register_entry( parent, NULL, ms, MONITOR_F_PERSISTENT_CH ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_ops_init: " "unable to register entry \"%s\" for monitoring\n", parent->e_name.bv_val ); goto done; } for ( i = 0; lload_monitor_op[i].rdn.bv_val != NULL; i++ ) { monitor_callback_t *cb; e = mbe->entry_stub( &parent->e_name, &parent->e_nname, &lload_monitor_op[i].rdn, oc_olmBalancerOperation, NULL, NULL ); if ( e == NULL ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_ops_init: " "unable to create entry \"%s,%s\"\n", lload_monitor_op[i].rdn.bv_val, parent->e_nname.bv_val ); return -1; } /* attr_merge_normalize_one( e, ad_olmDbOperations, &value, NULL ); */ /* * We cannot share a single callback between entries. * * monitor_cache_destroy() tries to free all callbacks and it's called * before mss_destroy() so we have no chance of handling it ourselves */ cb = ch_calloc( sizeof(monitor_callback_t), 1 ); cb->mc_update = lload_monitor_ops_update; cb->mc_free = lload_monitor_ops_free; cb->mc_dispose = lload_monitor_ops_dispose; cb->mc_private = &lload_stats.counters[i]; attr_merge_normalize_one( e, ad_olmReceivedOps, &value, NULL ); attr_merge_normalize_one( e, ad_olmForwardedOps, &value, NULL ); attr_merge_normalize_one( e, ad_olmRejectedOps, &value, NULL ); attr_merge_normalize_one( e, ad_olmCompletedOps, &value, NULL ); attr_merge_normalize_one( e, ad_olmFailedOps, &value, NULL ); rc = mbe->register_entry( e, cb, ms, 0 ); entry_free( e ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_ops_init: " "unable to register entry \"%s\" for monitoring\n", e->e_name.bv_val ); ch_free( cb ); break; } } done: entry_free( parent ); return rc; } static int lload_monitor_in_conn_entry( LloadConnection *conn, void *argv ) { Entry *e; monitor_entry_t *mp; struct lload_monitor_conn_arg *arg = argv; monitor_extra_t *mbe = arg->op->o_bd->bd_info->bi_extra; char buf[SLAP_TEXT_BUFLEN]; struct berval bv; bv.bv_val = buf; bv.bv_len = snprintf( bv.bv_val, SLAP_TEXT_BUFLEN, "cn=Connection %lu", conn->c_connid ); e = mbe->entry_stub( &arg->ms->mss_dn, &arg->ms->mss_ndn, &bv, oc_olmBalancerConnection, NULL, NULL ); mp = mbe->entrypriv_create(); e->e_private = mp; mp->mp_info = arg->ms; mp->mp_flags = MONITOR_F_SUB | MONITOR_F_VOLATILE; *arg->ep = e; arg->ep = &mp->mp_next; return 0; } static int lload_monitor_in_conn_create( Operation *op, SlapReply *rs, struct berval *ndn, Entry *e_parent, Entry **ep ) { monitor_entry_t *mp_parent; struct lload_monitor_conn_arg arg = { .op = op, .ep = ep, }; assert( e_parent->e_private != NULL ); mp_parent = e_parent->e_private; arg.ms = (monitor_subsys_t *)mp_parent->mp_info; checked_lock( &clients_mutex ); connections_walk( &clients_mutex, &clients, lload_monitor_in_conn_entry, &arg ); checked_unlock( &clients_mutex ); return 0; } static int lload_monitor_up_conn_entry( LloadConnection *c, void *argv ) { Entry *e; monitor_entry_t *mp; struct lload_monitor_conn_arg *arg = argv; monitor_extra_t *mbe = arg->op->o_bd->bd_info->bi_extra; char buf[SLAP_TEXT_BUFLEN]; struct berval bv_rdn, bv_type = BER_BVNULL, bv_pending = BER_BVNULL, bv_received = BER_BVNULL, bv_completed = BER_BVNULL, bv_failed = BER_BVNULL; bv_rdn.bv_val = buf; bv_rdn.bv_len = snprintf( bv_rdn.bv_val, SLAP_TEXT_BUFLEN, "cn=Connection %lu", c->c_connid ); e = mbe->entry_stub( &arg->ms->mss_dn, &arg->ms->mss_ndn, &bv_rdn, oc_olmBalancerConnection, NULL, NULL ); switch ( c->c_type ) { case LLOAD_C_OPEN: { struct berval bv = BER_BVC("regular"); bv_type = bv; } break; case LLOAD_C_PREPARING: { struct berval bv = BER_BVC("preparing"); bv_type = bv; } break; case LLOAD_C_BIND: { struct berval bv = BER_BVC("bind"); bv_type = bv; } break; case LLOAD_C_PRIVILEGED: { struct berval bv = BER_BVC("privileged"); bv_type = bv; } break; default: { struct berval bv = BER_BVC("unknown"); bv_type = bv; } break; } UI2BV( &bv_pending, (long long unsigned int)c->c_n_ops_executing ); UI2BV( &bv_received, c->c_counters.lc_ops_received ); UI2BV( &bv_completed, c->c_counters.lc_ops_completed ); UI2BV( &bv_failed, c->c_counters.lc_ops_failed ); attr_merge_normalize_one( e, ad_olmConnectionType, &bv_type, NULL ); attr_merge_normalize_one( e, ad_olmPendingOps, &bv_pending, NULL ); attr_merge_normalize_one( e, ad_olmReceivedOps, &bv_received, NULL ); attr_merge_normalize_one( e, ad_olmCompletedOps, &bv_completed, NULL ); attr_merge_normalize_one( e, ad_olmFailedOps, &bv_failed, NULL ); ch_free( bv_pending.bv_val ); ch_free( bv_received.bv_val ); ch_free( bv_completed.bv_val ); ch_free( bv_failed.bv_val ); mp = mbe->entrypriv_create(); e->e_private = mp; mp->mp_info = arg->ms; mp->mp_flags = MONITOR_F_SUB | MONITOR_F_VOLATILE; *arg->ep = e; arg->ep = &mp->mp_next; return 0; } static int lload_monitor_up_conn_create( Operation *op, SlapReply *rs, struct berval *ndn, Entry *e_parent, Entry **ep ) { monitor_entry_t *mp_parent; monitor_subsys_t *ms; LloadBackend *b; struct lload_monitor_conn_arg arg = { .op = op, .ep = ep, }; assert( e_parent->e_private != NULL ); mp_parent = e_parent->e_private; ms = (monitor_subsys_t *)mp_parent->mp_info; b = ms->mss_private; if ( !b ) { return -1; } arg.ms = ms; checked_lock( &b->b_mutex ); connections_walk_last( &b->b_mutex, &b->b_conns, b->b_last_conn, lload_monitor_up_conn_entry, &arg ); connections_walk_last( &b->b_mutex, &b->b_bindconns, b->b_last_bindconn, lload_monitor_up_conn_entry, &arg ); checked_unlock( &b->b_mutex ); return 0; } int lload_monitor_incoming_conn_init( BackendDB *be, monitor_subsys_t *ms ) { monitor_extra_t *mbe; Entry *e; int rc; assert( be != NULL ); mbe = (monitor_extra_t *)be->bd_info->bi_extra; ms->mss_create = lload_monitor_in_conn_create; ms->mss_destroy = lload_monitor_subsystem_destroy; dnNormalize( 0, NULL, NULL, &ms->mss_dn, &ms->mss_ndn, NULL ); e = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn, &ms->mss_rdn, oc_monitorContainer, NULL, NULL ); if ( e == NULL ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_incoming_conn_init: " "unable to create entry \"%s,%s\"\n", ms->mss_rdn.bv_val, ms->mss_ndn.bv_val ); return -1; } ch_free( ms->mss_ndn.bv_val ); ber_dupbv( &ms->mss_dn, &e->e_name ); ber_dupbv( &ms->mss_ndn, &e->e_nname ); rc = mbe->register_entry( e, NULL, ms, MONITOR_F_VOLATILE_CH ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_incoming_conn_init: " "unable to register entry \"%s\" for monitoring\n", e->e_name.bv_val ); goto done; } done: entry_free( e ); return rc; } static int lload_monitor_server_update( Operation *op, SlapReply *rs, Entry *e, void *priv ) { Attribute *a; LloadBackend *b = priv; LloadConnection *c; LloadPendingConnection *pc; ldap_pvt_mp_t active = 0, pending = 0, received = 0, completed = 0, failed = 0; int i; checked_lock( &b->b_mutex ); active = b->b_active + b->b_bindavail; LDAP_CIRCLEQ_FOREACH ( c, &b->b_preparing, c_next ) { pending++; } LDAP_LIST_FOREACH( pc, &b->b_connecting, next ) { pending++; } for ( i = 0; i < LLOAD_STATS_OPS_LAST; i++ ) { received += b->b_counters[i].lc_ops_received; completed += b->b_counters[i].lc_ops_completed; failed += b->b_counters[i].lc_ops_failed; } a = attr_find( e->e_attrs, ad_olmPendingOps ); assert( a != NULL ); UI2BV( &a->a_vals[0], (long long unsigned int)b->b_n_ops_executing ); checked_unlock( &b->b_mutex ); /* Right now, there is no way to retrieve the entry from monitor's * cache to replace URI at the moment it is modified */ a = attr_find( e->e_attrs, ad_olmServerURI ); assert( a != NULL ); ber_bvreplace( &a->a_vals[0], &b->b_uri ); a = attr_find( e->e_attrs, ad_olmActiveConnections ); assert( a != NULL ); UI2BV( &a->a_vals[0], active ); a = attr_find( e->e_attrs, ad_olmPendingConnections ); assert( a != NULL ); UI2BV( &a->a_vals[0], pending ); a = attr_find( e->e_attrs, ad_olmReceivedOps ); assert( a != NULL ); UI2BV( &a->a_vals[0], received ); a = attr_find( e->e_attrs, ad_olmCompletedOps ); assert( a != NULL ); UI2BV( &a->a_vals[0], completed ); a = attr_find( e->e_attrs, ad_olmFailedOps ); assert( a != NULL ); UI2BV( &a->a_vals[0], failed ); return SLAP_CB_CONTINUE; } static int lload_monitor_backend_open( BackendDB *be, monitor_subsys_t *ms ) { Entry *e; struct berval value = BER_BVC("0"); monitor_extra_t *mbe; monitor_callback_t *cb; LloadBackend *b = ms->mss_private; int rc; assert( be != NULL ); mbe = (monitor_extra_t *)be->bd_info->bi_extra; dnNormalize( 0, NULL, NULL, &ms->mss_dn, &ms->mss_ndn, NULL ); e = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn, &ms->mss_rdn, oc_olmBalancerServer, NULL, NULL ); if ( e == NULL ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_backend_open: " "unable to create entry \"%s,%s\"\n", ms->mss_rdn.bv_val, ms->mss_ndn.bv_val ); return -1; } ch_free( ms->mss_ndn.bv_val ); ber_dupbv( &ms->mss_dn, &e->e_name ); ber_dupbv( &ms->mss_ndn, &e->e_nname ); cb = ch_calloc( sizeof(monitor_callback_t), 1 ); cb->mc_update = lload_monitor_server_update; cb->mc_free = NULL; cb->mc_dispose = NULL; cb->mc_private = b; attr_merge_normalize_one( e, ad_olmServerURI, &b->b_uri, NULL ); attr_merge_normalize_one( e, ad_olmActiveConnections, &value, NULL ); attr_merge_normalize_one( e, ad_olmPendingConnections, &value, NULL ); attr_merge_normalize_one( e, ad_olmPendingOps, &value, NULL ); attr_merge_normalize_one( e, ad_olmReceivedOps, &value, NULL ); attr_merge_normalize_one( e, ad_olmCompletedOps, &value, NULL ); attr_merge_normalize_one( e, ad_olmFailedOps, &value, NULL ); rc = mbe->register_entry( e, cb, ms, MONITOR_F_VOLATILE_CH ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_backend_open: " "unable to register entry \"%s\" for monitoring\n", e->e_name.bv_val ); goto done; } b->b_monitor = ms; ms->mss_destroy = lload_monitor_backend_destroy; done: entry_free( e ); return rc; } int lload_monitor_backend_init( BackendInfo *bi, LloadBackend *b ) { monitor_extra_t *mbe; monitor_subsys_t *bk_mss; mbe = (monitor_extra_t *)bi->bi_extra; /* FIXME: With back-monitor as it works now, there is no way to know when * this can be safely freed so we leak it on shutdown */ bk_mss = ch_calloc( 1, sizeof(monitor_subsys_t) ); bk_mss->mss_rdn.bv_len = sizeof("cn=") + b->b_name.bv_len; bk_mss->mss_rdn.bv_val = ch_malloc( bk_mss->mss_rdn.bv_len ); bk_mss->mss_rdn.bv_len = snprintf( bk_mss->mss_rdn.bv_val, bk_mss->mss_rdn.bv_len, "cn=%s", b->b_name.bv_val ); ber_str2bv( LLOAD_MONITOR_BACKENDS_DN, 0, 0, &bk_mss->mss_dn ); bk_mss->mss_name = b->b_name.bv_val; bk_mss->mss_flags = MONITOR_F_VOLATILE_CH; bk_mss->mss_open = lload_monitor_backend_open; bk_mss->mss_create = lload_monitor_up_conn_create; bk_mss->mss_destroy = lload_monitor_subsystem_destroy; bk_mss->mss_update = NULL; bk_mss->mss_private = b; if ( mbe->register_subsys_late( bk_mss ) ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_backend_init: " "failed to register backend %s\n", bk_mss->mss_name ); return -1; } return LDAP_SUCCESS; } int lload_monitor_backends_init( BackendDB *be, monitor_subsys_t *ms ) { monitor_extra_t *mbe; Entry *e; int rc; LloadBackend *b; assert( be != NULL ); mbe = (monitor_extra_t *)be->bd_info->bi_extra; dnNormalize( 0, NULL, NULL, &ms->mss_dn, &ms->mss_ndn, NULL ); e = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn, &ms->mss_rdn, oc_monitorContainer, NULL, NULL ); if ( e == NULL ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_incoming_conn_init: " "unable to create entry \"%s,%s\"\n", ms->mss_rdn.bv_val, ms->mss_ndn.bv_val ); return -1; } ch_free( ms->mss_ndn.bv_val ); ber_dupbv( &ms->mss_dn, &e->e_name ); ber_dupbv( &ms->mss_ndn, &e->e_nname ); rc = mbe->register_entry( e, NULL, ms, MONITOR_F_PERSISTENT_CH ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_backends_init: " "unable to register entry \"%s\" for monitoring\n", e->e_name.bv_val ); goto done; } LDAP_CIRCLEQ_FOREACH ( b, &backend, b_next ) { if ( (rc = lload_monitor_backend_init( be->bd_info, b )) ) { break; } } done: entry_free( e ); return rc; } static int lload_monitor_incoming_count( LloadConnection *conn, void *argv ) { lload_global_stats_t *tmp_stats = argv; tmp_stats->global_incoming++; return 0; } /* * Update all global statistics other than rejected and received, * which are updated in real time */ void * lload_monitor_update_global_stats( void *ctx, void *arg ) { struct re_s *rtask = arg; lload_global_stats_t tmp_stats = {}; LloadBackend *b; int i; Debug( LDAP_DEBUG_TRACE, "lload_monitor_update_global_stats: " "updating stats\n" ); /* count incoming connections */ checked_lock( &clients_mutex ); connections_walk( &clients_mutex, &clients, lload_monitor_incoming_count, &tmp_stats ); checked_unlock( &clients_mutex ); LDAP_CIRCLEQ_FOREACH ( b, &backend, b_next ) { checked_lock( &b->b_mutex ); tmp_stats.global_outgoing += b->b_active + b->b_bindavail; /* merge completed and failed stats */ for ( i = 0; i < LLOAD_STATS_OPS_LAST; i++ ) { tmp_stats.counters[i].lc_ops_completed += b->b_counters[i].lc_ops_completed; tmp_stats.counters[i].lc_ops_failed += b->b_counters[i].lc_ops_failed; } checked_unlock( &b->b_mutex ); } /* update lload_stats */ lload_stats.global_outgoing = tmp_stats.global_outgoing; lload_stats.global_incoming = tmp_stats.global_incoming; for ( i = 0; i < LLOAD_STATS_OPS_LAST; i++ ) { lload_stats.counters[i].lc_ops_completed = tmp_stats.counters[i].lc_ops_completed; lload_stats.counters[i].lc_ops_failed = tmp_stats.counters[i].lc_ops_failed; } /* reschedule */ checked_lock( &slapd_rq.rq_mutex ); ldap_pvt_runqueue_stoptask( &slapd_rq, rtask ); checked_unlock( &slapd_rq.rq_mutex ); return NULL; } static char *lload_subsys_rdn[] = { LLOAD_MONITOR_BALANCER_RDN, LLOAD_MONITOR_INCOMING_RDN, LLOAD_MONITOR_OPERATIONS_RDN, LLOAD_MONITOR_BACKENDS_RDN, NULL }; static struct monitor_subsys_t balancer_subsys[] = { { LLOAD_MONITOR_BALANCER_NAME, BER_BVNULL, BER_BVC(SLAPD_MONITOR_BACKEND_DN), BER_BVNULL, { BER_BVC("Load Balancer information"), BER_BVNULL }, MONITOR_F_PERSISTENT_CH, lload_monitor_balancer_init, lload_monitor_subsystem_destroy, /* destroy */ NULL, /* update */ NULL, /* create */ NULL /* modify */ }, { LLOAD_MONITOR_INCOMING_NAME, BER_BVNULL, BER_BVC(LLOAD_MONITOR_BALANCER_DN), BER_BVNULL, { BER_BVC("Load Balancer incoming connections"), BER_BVNULL }, MONITOR_F_VOLATILE_CH, lload_monitor_incoming_conn_init, lload_monitor_subsystem_destroy, /* destroy */ NULL, /* update */ NULL, /* create */ NULL /* modify */ }, { LLOAD_MONITOR_OPERATIONS_NAME, BER_BVNULL, BER_BVC(LLOAD_MONITOR_BALANCER_DN), BER_BVNULL, { BER_BVC("Load Balancer global operation statistics"), BER_BVNULL }, MONITOR_F_PERSISTENT_CH, lload_monitor_ops_init, lload_monitor_subsystem_destroy, /* destroy */ NULL, /* update */ NULL, /* create */ NULL /* modify */ }, { LLOAD_MONITOR_BACKENDS_NAME, BER_BVNULL, BER_BVC(LLOAD_MONITOR_BALANCER_DN), BER_BVNULL, { BER_BVC("Load Balancer Backends information"), BER_BVNULL }, MONITOR_F_PERSISTENT_CH, lload_monitor_backends_init, lload_monitor_subsystem_destroy, /* destroy */ NULL, /* update */ NULL, /* create */ NULL /* modify */ }, { NULL } }; int lload_monitor_open( void ) { static int lload_monitor_initialized_failure = 1; static int lload_monitor_initialized = 0; BackendInfo *mi; monitor_extra_t *mbe; monitor_subsys_t *mss; ConfigArgs c; char *argv[3], **rdn; int i, rc; /* check if monitor is configured and usable */ mi = backend_info( "monitor" ); if ( !mi || !mi->bi_extra ) { Debug( LDAP_DEBUG_CONFIG, "lload_monitor_open: " "monitor backend not available, monitoring disabled\n" ); return 0; } mbe = mi->bi_extra; /* don't bother if monitor is not configured */ if ( !mbe->is_configured() ) { static int warning = 0; if ( warning++ == 0 ) { Debug( LDAP_DEBUG_CONFIG, "lload_monitor_open: " "monitoring disabled; " "configure monitor database to enable\n" ); } return 0; } if ( lload_monitor_initialized++ ) { return lload_monitor_initialized_failure; } argv[0] = "lload monitor"; c.argv = argv; c.argc = 3; c.fname = argv[0]; for ( i = 0; s_oid[i].name; i++ ) { argv[1] = s_oid[i].name; argv[2] = s_oid[i].oid; if ( parse_oidm( &c, 0, NULL ) != 0 ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_open: " "unable to add objectIdentifier \"%s=%s\"\n", s_oid[i].name, s_oid[i].oid ); return 2; } } for ( i = 0; s_at[i].desc != NULL; i++ ) { rc = register_at( s_at[i].desc, s_at[i].ad, 1 ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_open: " "register_at failed for attributeType (%s)\n", s_at[i].desc ); return 3; } else { (*s_at[i].ad)->ad_type->sat_flags |= SLAP_AT_HIDE; } } for ( i = 0; s_oc[i].desc != NULL; i++ ) { rc = register_oc( s_oc[i].desc, s_oc[i].oc, 1 ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_open: " "register_oc failed for objectClass (%s)\n", s_oc[i].desc ); return 4; } else { (*s_oc[i].oc)->soc_flags |= SLAP_OC_HIDE; } } for ( i = 0; s_moc[i].name != NULL; i++ ) { *s_moc[i].oc = oc_find( s_moc[i].name ); if ( !*s_moc[i].oc ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_open: " "failed to find objectClass (%s)\n", s_moc[i].name ); return 5; } } /* register the subsystems - Servers are registered in backends_init */ for ( mss = balancer_subsys, rdn = lload_subsys_rdn; mss->mss_name; mss++, rdn++ ) { ber_str2bv( *rdn, 0, 1, &mss->mss_rdn ); if ( mbe->register_subsys_late( mss ) ) { Debug( LDAP_DEBUG_ANY, "lload_monitor_open: " "failed to register %s subsystem\n", mss->mss_name ); return -1; } } checked_lock( &slapd_rq.rq_mutex ); ldap_pvt_runqueue_insert( &slapd_rq, 1, lload_monitor_update_global_stats, NULL, "lload_monitor_update_global_stats", "lloadd" ); checked_unlock( &slapd_rq.rq_mutex ); return (lload_monitor_initialized_failure = LDAP_SUCCESS); } openldap-2.5.11+dfsg/servers/lloadd/lload.h0000644000175000017500000003457014172327167017244 0ustar ryanryan/* lload.h - load balancer include file */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ #ifndef _LLOAD_H_ #define _LLOAD_H_ #include "ldap_defaults.h" #include #include #include #include #include #include #include #include #include #include "ldap_avl.h" #include "../servers/slapd/slap.h" #include "../slapd/back-monitor/back-monitor.h" #ifndef ldap_debug #define ldap_debug slap_debug #endif #include "ldap_log.h" #include #include #include "lber_pvt.h" #include "ldap_pvt.h" #include "ldap_pvt_thread.h" #include "ldap_queue.h" #include #ifdef HAVE_CYRUS_SASL #ifdef HAVE_SASL_SASL_H #include #else #include #endif #endif /* HAVE_CYRUS_SASL */ LDAP_BEGIN_DECL #ifdef SERVICE_NAME #undef SERVICE_NAME #endif #define SERVICE_NAME OPENLDAP_PACKAGE "-lloadd" #define LLOAD_SB_MAX_INCOMING_CLIENT ( ( 1 << 24 ) - 1 ) #define LLOAD_SB_MAX_INCOMING_UPSTREAM ( ( 1 << 24 ) - 1 ) #define LLOAD_CONN_MAX_PDUS_PER_CYCLE_DEFAULT 10 #define BER_BV_OPTIONAL( bv ) ( BER_BVISNULL( bv ) ? NULL : ( bv ) ) #include #define checked_lock( mutex ) \ if ( ldap_pvt_thread_mutex_lock( mutex ) != 0 ) assert(0) #define checked_unlock( mutex ) \ if ( ldap_pvt_thread_mutex_unlock( mutex ) != 0 ) assert(0) #ifdef LDAP_THREAD_DEBUG #define assert_locked( mutex ) \ if ( ldap_pvt_thread_mutex_trylock( mutex ) == 0 ) assert(0) #else #define assert_locked( mutex ) ( (void)0 ) #endif typedef struct LloadBackend LloadBackend; typedef struct LloadPendingConnection LloadPendingConnection; typedef struct LloadConnection LloadConnection; typedef struct LloadOperation LloadOperation; typedef struct LloadChange LloadChange; /* end of forward declarations */ typedef LDAP_CIRCLEQ_HEAD(BeSt, LloadBackend) lload_b_head; typedef LDAP_CIRCLEQ_HEAD(ConnSt, LloadConnection) lload_c_head; LDAP_SLAPD_V (lload_b_head) backend; LDAP_SLAPD_V (lload_c_head) clients; LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) backend_mutex; LDAP_SLAPD_V (LloadBackend *) current_backend; LDAP_SLAPD_V (struct slap_bindconf) bindconf; LDAP_SLAPD_V (struct berval) lloadd_identity; /* Used to coordinate server (un)pause, shutdown */ LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) lload_wait_mutex; LDAP_SLAPD_V (ldap_pvt_thread_cond_t) lload_pause_cond; LDAP_SLAPD_V (ldap_pvt_thread_cond_t) lload_wait_cond; typedef int lload_cf_aux_table_parse_x( struct berval *val, void *bc, slap_cf_aux_table *tab0, const char *tabmsg, int unparse ); typedef struct LloadListener LloadListener; enum lc_type { LLOAD_CHANGE_UNDEFINED = 0, LLOAD_CHANGE_MODIFY, LLOAD_CHANGE_ADD, LLOAD_CHANGE_DEL, }; enum lc_object { LLOAD_UNDEFINED = 0, LLOAD_DAEMON, /* LLOAD_BINDCONF, */ LLOAD_BACKEND, }; enum lcf_daemon { LLOAD_DAEMON_MOD_THREADS = 1 << 0, LLOAD_DAEMON_MOD_FEATURES = 1 << 1, LLOAD_DAEMON_MOD_TLS = 1 << 2, LLOAD_DAEMON_MOD_LISTENER_ADD = 1 << 3, LLOAD_DAEMON_MOD_LISTENER_REPLACE = 1 << 4, LLOAD_DAEMON_MOD_BINDCONF = 1 << 5, }; enum lcf_backend { LLOAD_BACKEND_MOD_OTHER = 1 << 0, LLOAD_BACKEND_MOD_CONNS = 1 << 1, }; struct LloadChange { enum lc_type type; enum lc_object object; union { int generic; enum lcf_daemon daemon; enum lcf_backend backend; } flags; void *target; }; typedef enum { #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS LLOAD_FEATURE_VC = 1 << 0, #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */ LLOAD_FEATURE_PROXYAUTHZ = 1 << 1, LLOAD_FEATURE_PAUSE = 1 << 2, } lload_features_t; #define LLOAD_FEATURE_SUPPORTED_MASK ( \ LLOAD_FEATURE_PROXYAUTHZ | \ 0 ) #ifdef BALANCER_MODULE #define LLOAD_TLS_CTX ( lload_use_slap_tls_ctx ? slap_tls_ctx : lload_tls_ctx ) #else #define LLOAD_TLS_CTX ( lload_tls_ctx ) #endif enum lload_tls_type { LLOAD_CLEARTEXT = 0, LLOAD_LDAPS, LLOAD_STARTTLS_OPTIONAL, LLOAD_STARTTLS, LLOAD_TLS_ESTABLISHED, }; struct LloadPendingConnection { LloadBackend *backend; struct event *event; ber_socket_t fd; LDAP_LIST_ENTRY(LloadPendingConnection) next; }; typedef struct lload_counters_t { ldap_pvt_mp_t lc_ops_completed; ldap_pvt_mp_t lc_ops_received; ldap_pvt_mp_t lc_ops_forwarded; ldap_pvt_mp_t lc_ops_rejected; ldap_pvt_mp_t lc_ops_failed; } lload_counters_t; enum { LLOAD_STATS_OPS_BIND = 0, LLOAD_STATS_OPS_OTHER, LLOAD_STATS_OPS_LAST }; typedef struct lload_global_stats_t { ldap_pvt_mp_t global_incoming; ldap_pvt_mp_t global_outgoing; lload_counters_t counters[LLOAD_STATS_OPS_LAST]; } lload_global_stats_t; /* Can hold mutex when locking a linked connection */ struct LloadBackend { ldap_pvt_thread_mutex_t b_mutex; struct berval b_name, b_uri; int b_proto, b_port; enum lload_tls_type b_tls, b_tls_conf; char *b_host; int b_retry_timeout, b_failed; struct event *b_retry_event; struct timeval b_retry_tv; int b_numconns, b_numbindconns; int b_bindavail, b_active, b_opening; lload_c_head b_conns, b_bindconns, b_preparing; LDAP_LIST_HEAD(ConnectingSt, LloadPendingConnection) b_connecting; LloadConnection *b_last_conn, *b_last_bindconn; long b_max_pending, b_max_conn_pending; long b_n_ops_executing; lload_counters_t b_counters[LLOAD_STATS_OPS_LAST]; #ifdef BALANCER_MODULE monitor_subsys_t *b_monitor; #endif /* BALANCER_MODULE */ struct evdns_getaddrinfo_request *b_dns_req; void *b_cookie; LDAP_CIRCLEQ_ENTRY(LloadBackend) b_next; }; typedef int (*LloadOperationHandler)( LloadConnection *client, LloadOperation *op, BerElement *ber ); typedef int (*RequestHandler)( LloadConnection *c, LloadOperation *op ); typedef struct lload_exop_handlers_t { struct berval oid; RequestHandler func; } ExopHandler; typedef int (*CONNECTION_PDU_CB)( LloadConnection *c ); typedef void (*CONNECTION_DESTROY_CB)( LloadConnection *c ); /* connection state (protected by c_mutex) */ enum sc_state { LLOAD_C_INVALID = 0, /* MUST BE ZERO (0) */ LLOAD_C_READY, /* ready */ LLOAD_C_CLOSING, /* closing */ LLOAD_C_ACTIVE, /* exclusive operation (tls setup, ...) in progress */ LLOAD_C_BINDING, /* binding */ LLOAD_C_DYING, /* part-processed dead waiting to be freed, someone * might still be observing it */ }; enum sc_type { LLOAD_C_OPEN = 0, /* regular connection */ LLOAD_C_PREPARING, /* upstream connection not assigned yet */ LLOAD_C_BIND, /* connection used to handle bind client requests if VC not enabled */ LLOAD_C_PRIVILEGED, /* connection can override proxyauthz control */ }; enum sc_io_state { LLOAD_C_OPERATIONAL = 0, /* all is good */ LLOAD_C_READ_HANDOVER = 1 << 0, /* A task to process PDUs is scheduled or * running, do not re-enable c_read_event */ LLOAD_C_READ_PAUSE = 1 << 1, /* We want to pause reading until the client * has sufficiently caught up with what we * sent */ }; /* * represents a connection from an ldap client/to ldap server */ struct LloadConnection { enum sc_state c_state; /* connection state */ enum sc_type c_type; enum sc_io_state c_io_state; ber_socket_t c_fd; /* * LloadConnection reference counting: * - connection has a reference counter in c_refcnt * - also a liveness/validity token is added to c_refcnt during * lload_connection_init, its existence is tracked in c_live and is usually the * only one that prevents it from being destroyed * - anyone who needs to be able to relock the connection after unlocking it has * to use acquire_ref(), they need to make sure a matching * RELEASE_REF( c, c_refcnt, c->c_destroy ); is run eventually * - when a connection is considered dead, use CONNECTION_DESTROY on a locked * connection, it will be made unreachable from normal places and either * scheduled for reclamation when safe to do so or if anyone still holds a * reference, it just gets unlocked and reclaimed after the last ref is * released * - CONNECTION_LOCK_DESTROY is a shorthand for locking and CONNECTION_DESTROY */ ldap_pvt_thread_mutex_t c_mutex; /* protect the connection */ uintptr_t c_refcnt, c_live; CONNECTION_DESTROY_CB c_unlink; CONNECTION_DESTROY_CB c_destroy; CONNECTION_PDU_CB c_pdu_cb; #define CONNECTION_ASSERT_LOCKED(c) assert_locked( &(c)->c_mutex ) #define CONNECTION_LOCK(c) \ do { \ checked_lock( &(c)->c_mutex ); \ } while (0) #define CONNECTION_UNLOCK(c) \ do { \ checked_unlock( &(c)->c_mutex ); \ } while (0) #define CONNECTION_UNLINK_(c) \ do { \ if ( __atomic_exchange_n( &(c)->c_live, 0, __ATOMIC_ACQ_REL ) ) { \ RELEASE_REF( (c), c_refcnt, c->c_destroy ); \ (c)->c_unlink( (c) ); \ } \ } while (0) #define CONNECTION_DESTROY(c) \ do { \ CONNECTION_UNLINK_(c); \ CONNECTION_UNLOCK(c); \ } while (0) #define CONNECTION_LOCK_DESTROY(c) \ do { \ CONNECTION_LOCK(c); \ CONNECTION_DESTROY(c); \ } while (0); Sockbuf *c_sb; /* ber connection stuff */ /* set by connection_init */ unsigned long c_connid; /* unique id of this connection */ struct berval c_peer_name; /* peer name (trans=addr:port) */ time_t c_starttime; /* when the connection was opened */ time_t c_activitytime; /* when the connection was last used */ ber_int_t c_next_msgid; /* msgid of the next message */ /* must not be used while holding either mutex */ struct event *c_read_event, *c_write_event; struct timeval *c_read_timeout; /* can only be changed by binding thread */ struct berval c_sasl_bind_mech; /* mech in progress */ struct berval c_auth; /* authcDN (possibly in progress) */ unsigned long c_pin_id; #ifdef HAVE_CYRUS_SASL sasl_conn_t *c_sasl_authctx; void *c_sasl_defaults; #ifdef SASL_CHANNEL_BINDING /* 2.1.25+ */ sasl_channel_binding_t *c_sasl_cbinding; /* Else cyrus-sasl would happily * leak it on sasl_dispose */ #endif /* SASL_CHANNEL_BINDING */ #endif /* HAVE_CYRUS_SASL */ #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS struct berval c_vc_cookie; #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */ /* Can be held while acquiring c_mutex to inject things into c_ops or * destroy the connection */ ldap_pvt_thread_mutex_t c_io_mutex; /* only one pdu written at a time */ BerElement *c_currentber; /* ber we're attempting to read */ BerElement *c_pendingber; /* ber we're attempting to write */ TAvlnode *c_ops; /* Operations pending on the connection */ #ifdef HAVE_TLS enum lload_tls_type c_is_tls; /* true if this LDAP over raw TLS */ #endif long c_n_ops_executing; /* num of ops currently executing */ long c_n_ops_completed; /* num of ops completed */ lload_counters_t c_counters; /* per connection operation counters */ LloadBackend *c_backend; /* * Protected by the CIRCLEQ mutex: * - Client: clients_mutex * - Upstream: b->b_mutex */ LDAP_CIRCLEQ_ENTRY(LloadConnection) c_next; }; enum op_state { LLOAD_OP_NOT_FREEING = 0, LLOAD_OP_DETACHING_CLIENT = 1 << 1, LLOAD_OP_DETACHING_UPSTREAM = 1 << 0, }; #define LLOAD_OP_DETACHING_MASK \ ( LLOAD_OP_DETACHING_UPSTREAM | LLOAD_OP_DETACHING_CLIENT ) /* operation result for monitoring purposes */ enum op_result { LLOAD_OP_REJECTED, /* operation was not forwarded */ LLOAD_OP_COMPLETED, /* operation sent and response received */ LLOAD_OP_FAILED, /* operation was forwarded, but no response was received */ }; /* * Operation reference tracking: * - o_refcnt is set to 1, never incremented * - operation_unlink sets it to 0 and on transition from 1 clears both * connection links (o_client, o_upstream) */ struct LloadOperation { uintptr_t o_refcnt; LloadConnection *o_client; unsigned long o_client_connid; ber_int_t o_client_msgid; ber_int_t o_saved_msgid; LloadConnection *o_upstream; unsigned long o_upstream_connid; ber_int_t o_upstream_msgid; time_t o_last_response; /* Protects o_client, o_upstream links */ ldap_pvt_thread_mutex_t o_link_mutex; ber_tag_t o_tag; time_t o_start; unsigned long o_pin_id; enum op_result o_res; BerElement *o_ber; BerValue o_request, o_ctrls; }; /* * listener; need to access it from monitor backend */ struct LloadListener { struct berval sl_url; struct berval sl_name; mode_t sl_perms; #ifdef HAVE_TLS int sl_is_tls; #endif int sl_is_proxied; struct event_base *base; struct evconnlistener *listener; int sl_mute; /* Listener is temporarily disabled due to emfile */ int sl_busy; /* Listener is busy (accept thread activated) */ ber_socket_t sl_sd; Sockaddr sl_sa; #define sl_addr sl_sa.sa_in_addr #define LDAP_TCP_BUFFER #ifdef LDAP_TCP_BUFFER int sl_tcp_rmem; /* custom TCP read buffer size */ int sl_tcp_wmem; /* custom TCP write buffer size */ #endif }; typedef int (*CONNCB)( LloadConnection *c, void *arg ); struct lload_monitor_conn_arg { Operation *op; monitor_subsys_t *ms; Entry **ep; }; /* config requires a bi_private with configuration data - dummy for now */ struct lload_conf_info { int dummy; }; LDAP_END_DECL #include "proto-lload.h" #endif /* _LLOAD_H_ */ openldap-2.5.11+dfsg/servers/lloadd/Makefile.in0000644000175000017500000000236514172327167020042 0ustar ryanryan# Makefile.in for Load Balancer # $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . XSRCS = version.c NT_SRCS = nt_svc.c NT_OBJS = nt_svc.o ../../libraries/liblutil/slapdmsg.res SRCS = backend.c bind.c config.c connection.c client.c \ daemon.c epoch.c extended.c init.c operation.c \ upstream.c libevent_support.c \ $(@PLAT@_SRCS) LDAP_INCDIR= ../../include -I$(srcdir) -I$(srcdir)/../slapd LDAP_LIBDIR= ../../libraries # $(LTHREAD_LIBS) must be last! XLIBS = $(LLOADD_L) XXLIBS = $(LLOADD_LIBS) $(SECURITY_LIBS) $(LUTIL_LIBS) XXXLIBS = $(LTHREAD_LIBS) NT_DEPENDS = slapd.exp NT_OBJECTS = slapd.exp symdummy.o $(LLOADD_OBJS) version.o UNIX_DEPENDS = version.o $(LLOADD_L) UNIX_OBJECTS = $(OBJS) version.o LLOADD_DEPENDS = $(@PLAT@_DEPENDS) LLOADD_OBJECTS = $(@PLAT@_OBJECTS) include @BALANCER_INCLUDE@ openldap-2.5.11+dfsg/servers/lloadd/Makefile_server.in0000644000175000017500000000515414172327167021427 0ustar ryanryan# Makefile.in for Load Balancer # $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . PROGRAMS = lloadd XPROGRAMS = slloadd XSRCS = version.c NT_SRCS = ../slapd/nt_svc.c NT_OBJS = ../slapd/nt_svc.o ../../libraries/liblutil/slapdmsg.res SRCS += main.c value.c \ ../slapd/ch_malloc.c ../slapd/proxyp.c ../slapd/sl_malloc.c ../slapd/user.c OBJS = $(patsubst %.c,%.o,$(SRCS)) $(@PLAT@_OBJS) BUILD_OPT = "--enable-balancer" BUILD_SRV = @BUILD_BALANCER@ all-local-srv: $(PROGRAMS) all-cffiles # $(LTHREAD_LIBS) must be last! XLIBS = $(LLOADD_L) XXLIBS = $(LLOADD_LIBS) $(SECURITY_LIBS) $(LUTIL_LIBS) $(SYSTEMD_LIBS) XXXLIBS = $(LTHREAD_LIBS) NT_DEPENDS = slapd.exp NT_OBJECTS = slapd.exp symdummy.o $(LLOADD_OBJS) version.o UNIX_DEPENDS = version.o $(LLOADD_L) UNIX_OBJECTS = $(OBJS) version.o LLOADD_DEPENDS = $(@PLAT@_DEPENDS) LLOADD_OBJECTS = $(@PLAT@_OBJECTS) lloadd: $(LLOADD_DEPENDS) version.o $(LTLINK) -o $@ $(OBJS) version.o $(LIBS) slloadd: version.o $(LTLINK) -static -o $@ $(OBJS) version.o $(LIBS) version.c: Makefile @-$(RM) $@ $(MKVERSION) -s -n Versionstr lloadd > $@ version.o: version.c $(OBJS) $(LLOADD_L) all-cffiles: @if test -n "$(systemdsystemunitdir)"; then \ $(SED) -e "s;%LIBEXECDIR%;$(libexecdir);" \ $(srcdir)/lloadd.service > lloadd.service.tmp ; \ fi touch all-cffiles clean-local-srv: FORCE $(RM) *.tmp all-cffiles install-local-srv: install-lloadd install-conf install-lloadd: FORCE -$(MKDIR) $(DESTDIR)$(libexecdir) @-$(INSTALL) -m 700 -d $(DESTDIR)$(localstatedir)/openldap-lloadd @( \ for prg in $(PROGRAMS); do \ $(LTINSTALL) $(INSTALLFLAGS) $(STRIP_OPTS) -m 755 $$prg$(EXEEXT) \ $(DESTDIR)$(libexecdir); \ done \ ) install-conf: FORCE @-$(MKDIR) $(DESTDIR)$(sysconfdir) if test -n "$(systemdsystemunitdir)" && test ! -f $(DESTDIR)$(systemdsystemunitdir)/lloadd.service; then \ $(MKDIR) $(DESTDIR)$(systemdsystemunitdir); \ echo "installing lloadd.service in $(systemdsystemunitdir)"; \ echo "$(INSTALL) $(INSTALLFLAGS) -m 644 lloadd.service.tmp $(DESTDIR)$(systemdsystemunitdir)/lloadd.service"; \ $(INSTALL) $(INSTALLFLAGS) -m 644 lloadd.service.tmp $(DESTDIR)$(systemdsystemunitdir)/lloadd.service; \ fi openldap-2.5.11+dfsg/servers/lloadd/epoch.c0000644000175000017500000002403114172327167017231 0ustar ryanryan/* epoch.c - epoch based memory reclamation */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2018-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /** @file epoch.c * * Implementation of epoch based memory reclamation, in principle * similar to the algorithm presented in * https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.pdf * * Not completely lock-free at the moment. * * Also the problems with epoch based memory reclamation are still * present - a thread actively observing an epoch getting stuck will * prevent managed objects (in our case connections and operations) * from being freed, potentially running out of memory. */ #include "portable.h" #include "lload.h" #include /* Has to be >= 3 */ #define EPOCH_MASK ( 1 << 2 ) #define EPOCH_PREV(epoch) ( ( (epoch) + EPOCH_MASK - 1 ) % EPOCH_MASK ) #define EPOCH_NEXT(epoch) ( ( (epoch) + 1 ) % EPOCH_MASK ) struct pending_ref { void *object; dispose_cb *dispose; struct pending_ref *next; }; ldap_pvt_thread_rdwr_t epoch_mutex; static epoch_t current_epoch; static uintptr_t epoch_threads[EPOCH_MASK]; static struct pending_ref *references[EPOCH_MASK]; void epoch_init( void ) { epoch_t epoch; current_epoch = 0; for ( epoch = 0; epoch < EPOCH_MASK; epoch++ ) { assert( !epoch_threads[epoch] ); assert( !references[epoch] ); } ldap_pvt_thread_rdwr_init( &epoch_mutex ); } void epoch_shutdown( void ) { epoch_t epoch; struct pending_ref *old, *next; for ( epoch = 0; epoch < EPOCH_MASK; epoch++ ) { assert( !epoch_threads[epoch] ); } /* * Even with the work in epoch_leave(), shutdown code doesn't currently * observe any epoch, so there might still be references left to free. */ epoch = EPOCH_PREV(current_epoch); next = references[epoch]; references[epoch] = NULL; for ( old = next; old; old = next ) { next = old->next; old->dispose( old->object ); ch_free( old ); } epoch = current_epoch; next = references[epoch]; references[epoch] = NULL; for ( old = next; old; old = next ) { next = old->next; old->dispose( old->object ); ch_free( old ); } /* No references should exist anywhere now */ for ( epoch = 0; epoch < EPOCH_MASK; epoch++ ) { assert( !references[epoch] ); } ldap_pvt_thread_rdwr_destroy( &epoch_mutex ); } epoch_t epoch_join( void ) { epoch_t epoch; struct pending_ref *old, *ref = NULL; retry: /* TODO: make this completely lock-free */ ldap_pvt_thread_rdwr_rlock( &epoch_mutex ); epoch = current_epoch; __atomic_add_fetch( &epoch_threads[epoch], 1, __ATOMIC_ACQ_REL ); ldap_pvt_thread_rdwr_runlock( &epoch_mutex ); if ( __atomic_load_n( &epoch_threads[EPOCH_PREV(epoch)], __ATOMIC_ACQUIRE ) ) { return epoch; } __atomic_exchange( &references[EPOCH_PREV(epoch)], &ref, &ref, __ATOMIC_ACQ_REL ); Debug( LDAP_DEBUG_TRACE, "epoch_join: " "advancing epoch to %zu with %s objects to free\n", EPOCH_NEXT(epoch), ref ? "some" : "no" ); ldap_pvt_thread_rdwr_wlock( &epoch_mutex ); current_epoch = EPOCH_NEXT(epoch); ldap_pvt_thread_rdwr_wunlock( &epoch_mutex ); if ( !ref ) { return epoch; } /* * The below is now safe to free outside epochs and we don't want to make * the current epoch last any longer than necessary. * * Looks like there might be fairness issues in massively parallel * environments but they haven't been observed on 32-core machines. */ epoch_leave( epoch ); for ( old = ref; old; old = ref ) { ref = old->next; old->dispose( old->object ); ch_free( old ); } goto retry; } void epoch_leave( epoch_t epoch ) { struct pending_ref *p, *next, *old_refs = NULL, *current_refs = NULL; /* Are there other threads observing our epoch? */ if ( __atomic_sub_fetch( &epoch_threads[epoch], 1, __ATOMIC_ACQ_REL ) ) { return; } /* * Optimisation for the case when we're mostly idle. Otherwise we won't * release resources until another thread comes by and joins the epoch * (twice), and there's no idea how soon (or late) that is going to happen. * * NB. There is no limit to the number of threads executing the following * code in parallel. */ ldap_pvt_thread_rdwr_rlock( &epoch_mutex ); /* * Anything could happen between the subtract and the lock being acquired * above, so check again. But once we hold this lock (and confirm no more * threads still observe either prospective epoch), noone will be able to * finish epoch_join until we've released epoch_mutex since it holds that: * * epoch_threads[EPOCH_PREV(current_epoch)] == 0 * * and that leads epoch_join() to acquire a write lock on &epoch_mutex. */ if ( __atomic_load_n( &epoch_threads[epoch], __ATOMIC_RELAXED ) ) { /* Epoch counter has run full circle */ ldap_pvt_thread_rdwr_runlock( &epoch_mutex ); return; } else if ( epoch == current_epoch ) { if ( __atomic_load_n( &epoch_threads[EPOCH_PREV(epoch)], __ATOMIC_RELAXED ) ) { /* There is another (older) thread still running */ ldap_pvt_thread_rdwr_runlock( &epoch_mutex ); return; } /* We're all alone, it's safe to claim all references and free them. */ __atomic_exchange( &references[EPOCH_PREV(epoch)], &old_refs, &old_refs, __ATOMIC_ACQ_REL ); __atomic_exchange( &references[epoch], ¤t_refs, ¤t_refs, __ATOMIC_ACQ_REL ); } else if ( epoch == EPOCH_PREV(current_epoch) ) { if ( __atomic_load_n( &epoch_threads[EPOCH_NEXT(epoch)], __ATOMIC_RELAXED ) ) { /* There is another (newer) thread still running */ ldap_pvt_thread_rdwr_runlock( &epoch_mutex ); return; } /* We're all alone, it's safe to claim all references and free them. */ __atomic_exchange( &references[epoch], &old_refs, &old_refs, __ATOMIC_ACQ_REL ); __atomic_exchange( &references[EPOCH_NEXT(epoch)], ¤t_refs, ¤t_refs, __ATOMIC_ACQ_REL ); } /* * Else the current_epoch has moved far enough that no references remain to * be freed. */ ldap_pvt_thread_rdwr_runlock( &epoch_mutex ); /* * Trigger a memory-independent read fence to make sure we're reading the * state after all threads actually finished - which might have happened * after we acquired epoch_mutex so ldap_pvt_thread_rdwr_rlock would not * catch everything. * * TODO is to confirm the below: * It might be that the tests and exchanges above only enforce a fence for * the locations affected, so we could still read stale memory for * unrelated locations? At least that's the only explanation I've been able * to establish for repeated crashes that seem to have gone away with this * in place. * * But then that's contrary to the second example in Acquire/Release * section here: * https://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync */ __atomic_thread_fence( __ATOMIC_ACQUIRE ); for ( p = old_refs; p; p = next ) { next = p->next; p->dispose( p->object ); ch_free( p ); } for ( p = current_refs; p; p = next ) { next = p->next; p->dispose( p->object ); ch_free( p ); } } /* * Add the object to the "current global epoch", not the epoch our thread * entered. */ void epoch_append( void *ptr, dispose_cb *cb ) { struct pending_ref *new; epoch_t epoch = __atomic_load_n( ¤t_epoch, __ATOMIC_ACQUIRE ); /* * BTW, the following is not appropriate here: * assert( __atomic_load_n( &epoch_threads[epoch], __ATOMIC_RELAXED ) ); * * We might be a thread lagging behind in the "previous epoch" with no * other threads executing at all. */ new = ch_malloc( sizeof(struct pending_ref) ); new->object = ptr; new->dispose = cb; new->next = __atomic_load_n( &references[epoch], __ATOMIC_ACQUIRE ); while ( !__atomic_compare_exchange( &references[epoch], &new->next, &new, 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED ) ) /* iterate until we succeed */; } int acquire_ref( uintptr_t *refp ) { uintptr_t refcnt, new_refcnt; refcnt = __atomic_load_n( refp, __ATOMIC_ACQUIRE ); /* * If we just incremented the refcnt and checked for zero after, another * thread might falsely believe the object was going to stick around. * * Checking whether the object is still dead at disposal time might not be * able to distinguish it from being freed in a later epoch. */ do { if ( !refcnt ) { return refcnt; } new_refcnt = refcnt + 1; } while ( !__atomic_compare_exchange( refp, &refcnt, &new_refcnt, 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED ) ); assert( new_refcnt == refcnt + 1 ); return refcnt; } int try_release_ref( uintptr_t *refp, void *object, dispose_cb *cb ) { uintptr_t refcnt, new_refcnt; refcnt = __atomic_load_n( refp, __ATOMIC_ACQUIRE ); /* We promise the caller that we won't decrease refcnt below 0 */ do { if ( !refcnt ) { return refcnt; } new_refcnt = refcnt - 1; } while ( !__atomic_compare_exchange( refp, &refcnt, &new_refcnt, 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED ) ); assert( new_refcnt == refcnt - 1 ); if ( !new_refcnt ) { epoch_append( object, cb ); } return refcnt; } openldap-2.5.11+dfsg/servers/lloadd/client.c0000644000175000017500000004254514172327167017423 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include "lutil.h" #include "lload.h" long lload_client_max_pending = 0; lload_c_head clients = LDAP_CIRCLEQ_HEAD_INITIALIZER( clients ); ldap_pvt_thread_mutex_t clients_mutex; static void client_unlink( LloadConnection *upstream ); int request_abandon( LloadConnection *c, LloadOperation *op ) { LloadOperation *request, needle = { .o_client_connid = c->c_connid }; int rc = LDAP_SUCCESS; op->o_res = LLOAD_OP_COMPLETED; if ( ber_decode_int( &op->o_request, &needle.o_client_msgid ) ) { Debug( LDAP_DEBUG_STATS, "request_abandon: " "connid=%lu msgid=%d invalid integer sent in abandon request\n", c->c_connid, op->o_client_msgid ); operation_unlink( op ); CONNECTION_LOCK_DESTROY(c); return -1; } CONNECTION_LOCK(c); request = ldap_tavl_find( c->c_ops, &needle, operation_client_cmp ); if ( !request ) { Debug( LDAP_DEBUG_STATS, "request_abandon: " "connid=%lu msgid=%d requests abandon of an operation " "msgid=%d not being processed anymore\n", c->c_connid, op->o_client_msgid, needle.o_client_msgid ); CONNECTION_UNLOCK(c); goto done; } else if ( request->o_tag == LDAP_REQ_BIND ) { /* RFC 4511 states we must not allow Abandon on Binds */ Debug( LDAP_DEBUG_STATS, "request_abandon: " "connid=%lu msgid=%d requests abandon of a bind operation " "msgid=%d\n", c->c_connid, op->o_client_msgid, needle.o_client_msgid ); CONNECTION_UNLOCK(c); goto done; } Debug( LDAP_DEBUG_STATS, "request_abandon: " "connid=%lu msgid=%d abandoning %s msgid=%d\n", c->c_connid, op->o_client_msgid, lload_msgtype2str( request->o_tag ), needle.o_client_msgid ); if ( c->c_state == LLOAD_C_BINDING ) { assert(0); } CONNECTION_UNLOCK(c); operation_abandon( request ); done: operation_unlink( op ); return rc; } int request_process( LloadConnection *client, LloadOperation *op ) { BerElement *output; LloadConnection *upstream; ber_int_t msgid; int res, rc = LDAP_SUCCESS; upstream = backend_select( op, &res ); if ( !upstream ) { Debug( LDAP_DEBUG_STATS, "request_process: " "connid=%lu, msgid=%d no available connection found\n", op->o_client_connid, op->o_client_msgid ); operation_send_reject( op, res, "no connections available", 1 ); goto fail; } CONNECTION_ASSERT_LOCKED(upstream); assert_locked( &upstream->c_io_mutex ); op->o_upstream = upstream; op->o_upstream_connid = upstream->c_connid; op->o_res = LLOAD_OP_FAILED; /* Was it unlinked in the meantime? No need to send a response since the * client is dead */ if ( !IS_ALIVE( op, o_refcnt ) ) { LloadBackend *b = upstream->c_backend; upstream->c_n_ops_executing--; checked_unlock( &upstream->c_io_mutex ); CONNECTION_UNLOCK(upstream); checked_lock( &b->b_mutex ); b->b_n_ops_executing--; checked_unlock( &b->b_mutex ); assert( !IS_ALIVE( client, c_live ) ); checked_lock( &op->o_link_mutex ); if ( op->o_upstream ) { op->o_upstream = NULL; } checked_unlock( &op->o_link_mutex ); return -1; } output = upstream->c_pendingber; if ( output == NULL && (output = ber_alloc()) == NULL ) { LloadBackend *b = upstream->c_backend; upstream->c_n_ops_executing--; CONNECTION_UNLOCK(upstream); checked_unlock( &upstream->c_io_mutex ); checked_lock( &b->b_mutex ); b->b_n_ops_executing--; operation_update_backend_counters( op, b ); checked_unlock( &b->b_mutex ); Debug( LDAP_DEBUG_ANY, "request_process: " "ber_alloc failed\n" ); rc = -1; goto fail; } upstream->c_pendingber = output; op->o_upstream_msgid = msgid = upstream->c_next_msgid++; rc = ldap_tavl_insert( &upstream->c_ops, op, operation_upstream_cmp, ldap_avl_dup_error ); CONNECTION_UNLOCK(upstream); Debug( LDAP_DEBUG_TRACE, "request_process: " "client connid=%lu added %s msgid=%d to upstream connid=%lu as " "msgid=%d\n", op->o_client_connid, lload_msgtype2str( op->o_tag ), op->o_client_msgid, op->o_upstream_connid, op->o_upstream_msgid ); assert( rc == LDAP_SUCCESS ); lload_stats.counters[LLOAD_STATS_OPS_OTHER].lc_ops_forwarded++; if ( (lload_features & LLOAD_FEATURE_PROXYAUTHZ) && client->c_type != LLOAD_C_PRIVILEGED ) { CONNECTION_LOCK(client); Debug( LDAP_DEBUG_TRACE, "request_process: " "proxying identity %s to upstream\n", client->c_auth.bv_val ); ber_printf( output, "t{titOt{{sbO}" /* "}}" */, LDAP_TAG_MESSAGE, LDAP_TAG_MSGID, msgid, op->o_tag, &op->o_request, LDAP_TAG_CONTROLS, LDAP_CONTROL_PROXY_AUTHZ, 1, &client->c_auth ); CONNECTION_UNLOCK(client); if ( !BER_BVISNULL( &op->o_ctrls ) ) { ber_write( output, op->o_ctrls.bv_val, op->o_ctrls.bv_len, 0 ); } ber_printf( output, /* "{{" */ "}}" ); } else { ber_printf( output, "t{titOtO}", LDAP_TAG_MESSAGE, LDAP_TAG_MSGID, msgid, op->o_tag, &op->o_request, LDAP_TAG_CONTROLS, BER_BV_OPTIONAL( &op->o_ctrls ) ); } checked_unlock( &upstream->c_io_mutex ); connection_write_cb( -1, 0, upstream ); return rc; fail: if ( upstream ) { CONNECTION_LOCK_DESTROY(upstream); operation_send_reject( op, LDAP_OTHER, "internal error", 0 ); } operation_unlink( op ); if ( rc ) { CONNECTION_LOCK_DESTROY(client); } return rc; } int handle_one_request( LloadConnection *c ) { BerElement *ber; LloadOperation *op = NULL; RequestHandler handler = NULL; int over_limit = 0; enum sc_state state; enum sc_io_state io_state; ber = c->c_currentber; c->c_currentber = NULL; CONNECTION_LOCK(c); op = operation_init( c, ber ); if ( !op ) { Debug( LDAP_DEBUG_ANY, "handle_one_request: " "connid=%lu, operation_init failed\n", c->c_connid ); CONNECTION_DESTROY(c); ber_free( ber, 1 ); return -1; } if ( lload_client_max_pending && c->c_n_ops_executing >= lload_client_max_pending ) { over_limit = 1; } /* * Remember the current state so we don't have to lock again, * we're only screening whether we can keep going, e.g. noone can change * state to LLOAD_C_BINDING from under us (would imply a new operation was * received but that's us), but the opposite is possible - a Bind response * could be received and processed in the meantime. */ state = c->c_state; CONNECTION_UNLOCK(c); switch ( op->o_tag ) { case LDAP_REQ_UNBIND: /* There is never a response for this operation */ op->o_res = LLOAD_OP_COMPLETED; operation_unlink( op ); Debug( LDAP_DEBUG_STATS, "handle_one_request: " "received unbind, closing client connid=%lu\n", c->c_connid ); CONNECTION_LOCK_DESTROY(c); return -1; case LDAP_REQ_BIND: handler = request_bind; break; case LDAP_REQ_ABANDON: /* We can't send a response to abandon requests even if a bind is * currently in progress */ return request_abandon( c, op ); case LDAP_REQ_EXTENDED: default: if ( state == LLOAD_C_BINDING ) { operation_send_reject( op, LDAP_PROTOCOL_ERROR, "bind in progress", 0 ); return LDAP_SUCCESS; } if ( over_limit ) { operation_send_reject( op, LDAP_BUSY, "pending operation limit reached on this connection", 0 ); return LDAP_SUCCESS; } checked_lock( &c->c_io_mutex ); io_state = c->c_io_state; checked_unlock( &c->c_io_mutex ); if ( io_state & LLOAD_C_READ_PAUSE ) { operation_send_reject( op, LDAP_BUSY, "writing side backlogged, please keep reading", 0 ); return LDAP_SUCCESS; } if ( op->o_tag == LDAP_REQ_EXTENDED ) { handler = request_extended; } else { handler = request_process; } break; } if ( state == LLOAD_C_CLOSING ) { operation_send_reject( op, LDAP_UNAVAILABLE, "connection is shutting down", 0 ); return LDAP_SUCCESS; } return handler( c, op ); } #ifdef HAVE_TLS /* * The connection has a token assigned to it when the callback is set up. */ void client_tls_handshake_cb( evutil_socket_t s, short what, void *arg ) { LloadConnection *c = arg; epoch_t epoch; int rc = 0; if ( what & EV_TIMEOUT ) { Debug( LDAP_DEBUG_CONNS, "client_tls_handshake_cb: " "connid=%lu, timeout reached, destroying\n", c->c_connid ); goto fail; } /* * In case of StartTLS, make sure we flush the response first. * Also before we try to read anything from the connection, it isn't * permitted to Abandon a StartTLS exop per RFC4511 anyway. */ checked_lock( &c->c_io_mutex ); if ( c->c_pendingber ) { checked_unlock( &c->c_io_mutex ); connection_write_cb( s, what, arg ); if ( !IS_ALIVE( c, c_live ) ) { goto fail; } /* Do we still have data pending? If so, connection_write_cb would * already have arranged the write callback to trigger again */ checked_lock( &c->c_io_mutex ); if ( c->c_pendingber ) { checked_unlock( &c->c_io_mutex ); return; } } rc = ldap_pvt_tls_accept( c->c_sb, LLOAD_TLS_CTX ); checked_unlock( &c->c_io_mutex ); if ( rc < 0 ) { goto fail; } if ( rc == 0 ) { struct event_base *base = event_get_base( c->c_read_event ); /* * We're finished, replace the callbacks * * This is deadlock-safe, since both share the same base - the one * that's just running us. */ CONNECTION_LOCK(c); event_del( c->c_read_event ); event_del( c->c_write_event ); c->c_read_timeout = NULL; event_assign( c->c_read_event, base, c->c_fd, EV_READ|EV_PERSIST, connection_read_cb, c ); if ( IS_ALIVE( c, c_live ) ) { event_add( c->c_read_event, c->c_read_timeout ); } event_assign( c->c_write_event, base, c->c_fd, EV_WRITE, connection_write_cb, c ); Debug( LDAP_DEBUG_CONNS, "client_tls_handshake_cb: " "connid=%lu finished\n", c->c_connid ); c->c_is_tls = LLOAD_TLS_ESTABLISHED; CONNECTION_UNLOCK(c); return; } else if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_WRITE, NULL ) ) { if ( IS_ALIVE( c, c_live ) ) { CONNECTION_LOCK(c); event_add( c->c_write_event, lload_write_timeout ); CONNECTION_UNLOCK(c); } Debug( LDAP_DEBUG_CONNS, "client_tls_handshake_cb: " "connid=%lu need write rc=%d\n", c->c_connid, rc ); } return; fail: Debug( LDAP_DEBUG_CONNS, "client_tls_handshake_cb: " "connid=%lu failed rc=%d\n", c->c_connid, rc ); assert( c->c_ops == NULL ); epoch = epoch_join(); CONNECTION_LOCK_DESTROY(c); epoch_leave( epoch ); } #endif /* HAVE_TLS */ LloadConnection * client_init( ber_socket_t s, const char *peername, struct event_base *base, int flags ) { LloadConnection *c; struct event *event; event_callback_fn read_cb = connection_read_cb, write_cb = connection_write_cb; if ( (c = lload_connection_init( s, peername, flags) ) == NULL ) { return NULL; } { ber_len_t max = sockbuf_max_incoming_client; ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max ); } c->c_state = LLOAD_C_READY; if ( flags & CONN_IS_TLS ) { #ifdef HAVE_TLS int rc; c->c_is_tls = LLOAD_LDAPS; rc = ldap_pvt_tls_accept( c->c_sb, LLOAD_TLS_CTX ); if ( rc < 0 ) { Debug( LDAP_DEBUG_CONNS, "client_init: " "connid=%lu failed initial TLS accept rc=%d\n", c->c_connid, rc ); CONNECTION_LOCK(c); goto fail; } if ( rc ) { c->c_read_timeout = lload_timeout_net; read_cb = write_cb = client_tls_handshake_cb; } #else /* ! HAVE_TLS */ assert(0); #endif /* ! HAVE_TLS */ } event = event_new( base, s, EV_READ|EV_PERSIST, read_cb, c ); if ( !event ) { Debug( LDAP_DEBUG_ANY, "client_init: " "Read event could not be allocated\n" ); CONNECTION_LOCK(c); goto fail; } c->c_read_event = event; event = event_new( base, s, EV_WRITE, write_cb, c ); if ( !event ) { Debug( LDAP_DEBUG_ANY, "client_init: " "Write event could not be allocated\n" ); CONNECTION_LOCK(c); goto fail; } c->c_write_event = event; c->c_destroy = client_destroy; c->c_unlink = client_unlink; c->c_pdu_cb = handle_one_request; CONNECTION_LOCK(c); /* We only register the write event when we have data pending */ event_add( c->c_read_event, c->c_read_timeout ); checked_lock( &clients_mutex ); LDAP_CIRCLEQ_INSERT_TAIL( &clients, c, c_next ); checked_unlock( &clients_mutex ); CONNECTION_UNLOCK(c); return c; fail: if ( c->c_write_event ) { event_free( c->c_write_event ); c->c_write_event = NULL; } if ( c->c_read_event ) { event_free( c->c_read_event ); c->c_read_event = NULL; } c->c_state = LLOAD_C_INVALID; c->c_live--; c->c_refcnt--; connection_destroy( c ); return NULL; } void client_reset( LloadConnection *c ) { TAvlnode *root; long freed = 0, executing; CONNECTION_ASSERT_LOCKED(c); root = c->c_ops; c->c_ops = NULL; executing = c->c_n_ops_executing; c->c_n_ops_executing = 0; if ( !BER_BVISNULL( &c->c_auth ) ) { ch_free( c->c_auth.bv_val ); BER_BVZERO( &c->c_auth ); } if ( !BER_BVISNULL( &c->c_sasl_bind_mech ) ) { ch_free( c->c_sasl_bind_mech.bv_val ); BER_BVZERO( &c->c_sasl_bind_mech ); } CONNECTION_UNLOCK(c); if ( root ) { freed = ldap_tavl_free( root, (AVL_FREE)operation_abandon ); Debug( LDAP_DEBUG_TRACE, "client_reset: " "dropped %ld operations\n", freed ); } assert( freed == executing ); CONNECTION_LOCK(c); CONNECTION_ASSERT_LOCKED(c); } void client_unlink( LloadConnection *c ) { enum sc_state state; struct event *read_event, *write_event; Debug( LDAP_DEBUG_CONNS, "client_unlink: " "removing client connid=%lu\n", c->c_connid ); CONNECTION_ASSERT_LOCKED(c); assert( c->c_state != LLOAD_C_INVALID ); assert( c->c_state != LLOAD_C_DYING ); state = c->c_state; c->c_state = LLOAD_C_DYING; read_event = c->c_read_event; write_event = c->c_write_event; CONNECTION_UNLOCK(c); if ( read_event ) { event_del( read_event ); } if ( write_event ) { event_del( write_event ); } if ( state != LLOAD_C_DYING ) { checked_lock( &clients_mutex ); LDAP_CIRCLEQ_REMOVE( &clients, c, c_next ); checked_unlock( &clients_mutex ); } CONNECTION_LOCK(c); client_reset( c ); CONNECTION_ASSERT_LOCKED(c); } void client_destroy( LloadConnection *c ) { Debug( LDAP_DEBUG_CONNS, "client_destroy: " "destroying client connid=%lu\n", c->c_connid ); CONNECTION_LOCK(c); assert( c->c_state == LLOAD_C_DYING ); c->c_state = LLOAD_C_INVALID; assert( c->c_ops == NULL ); if ( c->c_read_event ) { event_free( c->c_read_event ); c->c_read_event = NULL; } if ( c->c_write_event ) { event_free( c->c_write_event ); c->c_write_event = NULL; } assert( c->c_refcnt == 0 ); connection_destroy( c ); } void clients_destroy( int gentle ) { checked_lock( &clients_mutex ); connections_walk( &clients_mutex, &clients, lload_connection_close, &gentle ); checked_unlock( &clients_mutex ); } openldap-2.5.11+dfsg/servers/lloadd/backend.c0000644000175000017500000005573214172327167017536 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include #include #include "lutil.h" #include "lload.h" static void upstream_connect_cb( evutil_socket_t s, short what, void *arg ) { LloadPendingConnection *conn = arg; LloadBackend *b = conn->backend; int error = 0, rc = -1; epoch_t epoch; checked_lock( &b->b_mutex ); Debug( LDAP_DEBUG_CONNS, "upstream_connect_cb: " "fd=%d connection callback for backend uri='%s'\n", s, b->b_uri.bv_val ); if ( s != conn->fd ) { /* backend_reset has been here first */ goto preempted; } epoch = epoch_join(); if ( what == EV_WRITE ) { socklen_t optlen = sizeof(error); if ( getsockopt( conn->fd, SOL_SOCKET, SO_ERROR, (void *)&error, &optlen ) < 0 ) { goto done; } if ( error == EINTR || error == EINPROGRESS || error == EWOULDBLOCK ) { checked_unlock( &b->b_mutex ); epoch_leave( epoch ); return; } else if ( error ) { goto done; } else if ( upstream_init( s, conn->backend ) == NULL ) { goto done; } rc = LDAP_SUCCESS; } done: epoch_leave( epoch ); LDAP_LIST_REMOVE( conn, next ); if ( rc ) { evutil_closesocket( conn->fd ); b->b_opening--; b->b_failed++; if ( what & EV_TIMEOUT ) { Debug( LDAP_DEBUG_ANY, "upstream_connect_cb: " "fd=%d connection timed out\n", s ); } else { char ebuf[128]; Debug( LDAP_DEBUG_ANY, "upstream_connect_cb: " "fd=%d connection set up failed%s%s\n", s, error ? ": " : "", error ? sock_errstr( error, ebuf, sizeof(ebuf) ) : "" ); } backend_retry( b ); } preempted: checked_unlock( &b->b_mutex ); event_free( conn->event ); ch_free( conn ); } static void upstream_name_cb( int result, struct evutil_addrinfo *res, void *arg ) { LloadBackend *b = arg; ber_socket_t s = AC_SOCKET_INVALID; epoch_t epoch; int rc; if ( result == EVUTIL_EAI_CANCEL ) { Debug( LDAP_DEBUG_ANY, "upstream_name_cb: " "cancelled\n" ); return; } checked_lock( &b->b_mutex ); /* We were already running when backend_reset tried to cancel us, but were * already stuck waiting for the mutex, nothing to do and b_opening has * been decremented as well */ if ( b->b_dns_req == NULL ) { checked_unlock( &b->b_mutex ); return; } b->b_dns_req = NULL; epoch = epoch_join(); if ( result || !res ) { Debug( LDAP_DEBUG_ANY, "upstream_name_cb: " "name resolution failed for backend '%s': %s\n", b->b_uri.bv_val, evutil_gai_strerror( result ) ); goto fail; } /* TODO: if we get failures, try the other addrinfos */ if ( (s = socket( res->ai_family, SOCK_STREAM, 0 )) == AC_SOCKET_INVALID ) { goto fail; } if ( ber_pvt_socket_set_nonblock( s, 1 ) ) { goto fail; } #if defined(SO_KEEPALIVE) || defined(TCP_NODELAY) if ( b->b_proto == LDAP_PROTO_TCP ) { int dummy = 1; #ifdef SO_KEEPALIVE if ( setsockopt( s, SOL_SOCKET, SO_KEEPALIVE, (char *)&dummy, sizeof(dummy) ) == AC_SOCKET_ERROR ) { Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: " "setsockopt(%d, SO_KEEPALIVE) failed (ignored).\n", s ); } if ( bindconf.sb_keepalive.sk_idle > 0 ) { #ifdef TCP_KEEPIDLE if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&bindconf.sb_keepalive.sk_idle, sizeof(bindconf.sb_keepalive.sk_idle) ) == AC_SOCKET_ERROR ) { Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: " "setsockopt(%d, TCP_KEEPIDLE) failed (ignored).\n", s ); } #else Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: " "sockopt TCP_KEEPIDLE not supported on this system.\n" ); #endif /* TCP_KEEPIDLE */ } if ( bindconf.sb_keepalive.sk_probes > 0 ) { #ifdef TCP_KEEPCNT if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPCNT, (void *)&bindconf.sb_keepalive.sk_probes, sizeof(bindconf.sb_keepalive.sk_probes) ) == AC_SOCKET_ERROR ) { Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: " "setsockopt(%d, TCP_KEEPCNT) failed (ignored).\n", s ); } #else Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: " "sockopt TCP_KEEPCNT not supported on this system.\n" ); #endif /* TCP_KEEPCNT */ } if ( bindconf.sb_keepalive.sk_interval > 0 ) { #ifdef TCP_KEEPINTVL if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&bindconf.sb_keepalive.sk_interval, sizeof(bindconf.sb_keepalive.sk_interval) ) == AC_SOCKET_ERROR ) { Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: " "setsockopt(%d, TCP_KEEPINTVL) failed (ignored).\n", s ); } #else Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: " "sockopt TCP_KEEPINTVL not supported on this system.\n" ); #endif /* TCP_KEEPINTVL */ } #endif /* SO_KEEPALIVE */ if ( bindconf.sb_tcp_user_timeout > 0 ) { #ifdef TCP_USER_TIMEOUT if ( setsockopt( s, IPPROTO_TCP, TCP_USER_TIMEOUT, (void *)&bindconf.sb_tcp_user_timeout, sizeof(bindconf.sb_tcp_user_timeout) ) == AC_SOCKET_ERROR ) { Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: " "setsockopt(%d, TCP_USER_TIMEOUT) failed (ignored).\n", s ); } #else Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: " "sockopt TCP_USER_TIMEOUT not supported on this " "system.\n" ); #endif /* TCP_USER_TIMEOUT */ } #ifdef TCP_NODELAY if ( setsockopt( s, IPPROTO_TCP, TCP_NODELAY, (char *)&dummy, sizeof(dummy) ) == AC_SOCKET_ERROR ) { Debug( LDAP_DEBUG_TRACE, "upstream_name_cb: " "setsockopt(%d, TCP_NODELAY) failed (ignored).\n", s ); } #endif /* TCP_NODELAY */ } #endif /* SO_KEEPALIVE || TCP_NODELAY */ if ( res->ai_family == PF_INET ) { struct sockaddr_in *ai = (struct sockaddr_in *)res->ai_addr; ai->sin_port = htons( b->b_port ); rc = connect( s, (struct sockaddr *)ai, res->ai_addrlen ); } else { struct sockaddr_in6 *ai = (struct sockaddr_in6 *)res->ai_addr; ai->sin6_port = htons( b->b_port ); rc = connect( s, (struct sockaddr *)ai, res->ai_addrlen ); } /* Asynchronous connect */ if ( rc ) { LloadPendingConnection *conn; if ( errno != EINPROGRESS && errno != EWOULDBLOCK ) { Debug( LDAP_DEBUG_ANY, "upstream_name_cb: " "failed to connect to server '%s'\n", b->b_uri.bv_val ); evutil_closesocket( s ); goto fail; } conn = ch_calloc( 1, sizeof(LloadPendingConnection) ); LDAP_LIST_ENTRY_INIT( conn, next ); conn->backend = b; conn->fd = s; conn->event = event_new( lload_get_base( s ), s, EV_WRITE|EV_PERSIST, upstream_connect_cb, conn ); if ( !conn->event ) { Debug( LDAP_DEBUG_ANY, "upstream_name_cb: " "failed to acquire an event to finish upstream " "connection setup.\n" ); ch_free( conn ); evutil_closesocket( s ); goto fail; } event_add( conn->event, lload_timeout_net ); LDAP_LIST_INSERT_HEAD( &b->b_connecting, conn, next ); Debug( LDAP_DEBUG_CONNS, "upstream_name_cb: " "connection to backend uri=%s in progress\n", b->b_uri.bv_val ); } else if ( upstream_init( s, b ) == NULL ) { goto fail; } checked_unlock( &b->b_mutex ); evutil_freeaddrinfo( res ); epoch_leave( epoch ); return; fail: if ( s != AC_SOCKET_INVALID ) { evutil_closesocket( s ); } b->b_opening--; b->b_failed++; backend_retry( b ); checked_unlock( &b->b_mutex ); if ( res ) { evutil_freeaddrinfo( res ); } epoch_leave( epoch ); } LloadConnection * backend_select( LloadOperation *op, int *res ) { LloadBackend *b, *first, *next; checked_lock( &backend_mutex ); first = b = current_backend; checked_unlock( &backend_mutex ); *res = LDAP_UNAVAILABLE; if ( !first ) { return NULL; } /* TODO: Two runs, one with trylock, then one actually locked if we don't * find anything? */ do { lload_c_head *head; LloadConnection *c; checked_lock( &b->b_mutex ); next = LDAP_CIRCLEQ_LOOP_NEXT( &backend, b, b_next ); if ( b->b_max_pending && b->b_n_ops_executing >= b->b_max_pending ) { Debug( LDAP_DEBUG_CONNS, "backend_select: " "backend %s too busy\n", b->b_uri.bv_val ); checked_unlock( &b->b_mutex ); b = next; *res = LDAP_BUSY; continue; } if ( op->o_tag == LDAP_REQ_BIND #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS && !(lload_features & LLOAD_FEATURE_VC) #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */ ) { head = &b->b_bindconns; } else { head = &b->b_conns; } if ( !LDAP_CIRCLEQ_EMPTY( head ) ) { *res = LDAP_BUSY; } LDAP_CIRCLEQ_FOREACH ( c, head, c_next ) { checked_lock( &c->c_io_mutex ); CONNECTION_LOCK(c); if ( c->c_state == LLOAD_C_READY && !c->c_pendingber && ( b->b_max_conn_pending == 0 || c->c_n_ops_executing < b->b_max_conn_pending ) ) { Debug( LDAP_DEBUG_CONNS, "backend_select: " "selected connection connid=%lu for client " "connid=%lu msgid=%d\n", c->c_connid, op->o_client_connid, op->o_client_msgid ); /* c_state is DYING if we're about to be unlinked */ assert( IS_ALIVE( c, c_live ) ); /* * Round-robin step: * Rotate the queue to put this connection at the end, same for * the backend. */ LDAP_CIRCLEQ_MAKE_TAIL( head, c, c_next ); checked_lock( &backend_mutex ); current_backend = next; checked_unlock( &backend_mutex ); b->b_n_ops_executing++; if ( op->o_tag == LDAP_REQ_BIND ) { b->b_counters[LLOAD_STATS_OPS_BIND].lc_ops_received++; } else { b->b_counters[LLOAD_STATS_OPS_OTHER].lc_ops_received++; } c->c_n_ops_executing++; c->c_counters.lc_ops_received++; checked_unlock( &b->b_mutex ); *res = LDAP_SUCCESS; CONNECTION_ASSERT_LOCKED(c); assert_locked( &c->c_io_mutex ); return c; } CONNECTION_UNLOCK(c); checked_unlock( &c->c_io_mutex ); } checked_unlock( &b->b_mutex ); b = next; } while ( b != first ); return NULL; } /* * Will schedule a connection attempt if there is a need for it. Need exclusive * access to backend, its b_mutex is not touched here, though. */ void backend_retry( LloadBackend *b ) { int requested; if ( slapd_shutdown ) { Debug( LDAP_DEBUG_CONNS, "backend_retry: " "shutting down\n" ); return; } assert_locked( &b->b_mutex ); requested = b->b_numconns; #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS if ( !(lload_features & LLOAD_FEATURE_VC) ) #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */ { requested += b->b_numbindconns; } if ( b->b_active + b->b_bindavail + b->b_opening >= requested ) { Debug( LDAP_DEBUG_CONNS, "backend_retry: " "no more connections needed for this backend\n" ); assert_locked( &b->b_mutex ); return; } if ( b->b_opening > 0 ) { Debug( LDAP_DEBUG_CONNS, "backend_retry: " "retry in progress already\n" ); assert( b->b_opening == 1 ); assert_locked( &b->b_mutex ); return; } /* We incremented b_opening when we activated the event, so it can't be * pending */ assert( !event_pending( b->b_retry_event, EV_TIMEOUT, NULL ) ); b->b_opening++; if ( b->b_failed > 0 ) { Debug( LDAP_DEBUG_CONNS, "backend_retry: " "scheduling a retry in %d ms\n", b->b_retry_timeout ); event_add( b->b_retry_event, &b->b_retry_tv ); assert_locked( &b->b_mutex ); return; } Debug( LDAP_DEBUG_CONNS, "backend_retry: " "scheduling re-connection straight away\n" ); if ( ldap_pvt_thread_pool_submit2( &connection_pool, backend_connect_task, b, &b->b_cookie ) ) { Debug( LDAP_DEBUG_ANY, "backend_retry: " "failed to submit retry task, scheduling a retry instead\n" ); /* The current implementation of ldap_pvt_thread_pool_submit2 can fail * and still set (an invalid) cookie */ b->b_cookie = NULL; b->b_failed++; event_add( b->b_retry_event, &b->b_retry_tv ); } assert_locked( &b->b_mutex ); } void backend_connect( evutil_socket_t s, short what, void *arg ) { struct evutil_addrinfo hints = {}; LloadBackend *b = arg; struct evdns_getaddrinfo_request *request, *placeholder; char *hostname; epoch_t epoch; checked_lock( &b->b_mutex ); assert( b->b_dns_req == NULL ); if ( b->b_cookie ) { b->b_cookie = NULL; } if ( slapd_shutdown ) { Debug( LDAP_DEBUG_CONNS, "backend_connect: " "doing nothing, shutdown in progress\n" ); b->b_opening--; checked_unlock( &b->b_mutex ); return; } epoch = epoch_join(); Debug( LDAP_DEBUG_CONNS, "backend_connect: " "%sattempting connection to %s\n", (what & EV_TIMEOUT) ? "retry timeout finished, " : "", b->b_host ); #ifdef LDAP_PF_LOCAL if ( b->b_proto == LDAP_PROTO_IPC ) { struct sockaddr_un addr; ber_socket_t s = socket( PF_LOCAL, SOCK_STREAM, 0 ); int rc; if ( s == AC_SOCKET_INVALID ) { goto fail; } rc = ber_pvt_socket_set_nonblock( s, 1 ); if ( rc ) { evutil_closesocket( s ); goto fail; } if ( strlen( b->b_host ) > ( sizeof(addr.sun_path) - 1 ) ) { evutil_closesocket( s ); goto fail; } memset( &addr, '\0', sizeof(addr) ); addr.sun_family = AF_LOCAL; strcpy( addr.sun_path, b->b_host ); rc = connect( s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un) ); /* Asynchronous connect */ if ( rc ) { LloadPendingConnection *conn; if ( errno != EINPROGRESS && errno != EWOULDBLOCK ) { evutil_closesocket( s ); goto fail; } conn = ch_calloc( 1, sizeof(LloadPendingConnection) ); LDAP_LIST_ENTRY_INIT( conn, next ); conn->backend = b; conn->fd = s; conn->event = event_new( lload_get_base( s ), s, EV_WRITE|EV_PERSIST, upstream_connect_cb, conn ); if ( !conn->event ) { Debug( LDAP_DEBUG_ANY, "backend_connect: " "failed to acquire an event to finish upstream " "connection setup.\n" ); ch_free( conn ); evutil_closesocket( s ); goto fail; } event_add( conn->event, lload_timeout_net ); LDAP_LIST_INSERT_HEAD( &b->b_connecting, conn, next ); Debug( LDAP_DEBUG_CONNS, "backend_connect: " "connection to backend uri=%s in progress\n", b->b_uri.bv_val ); } else if ( upstream_init( s, b ) == NULL ) { goto fail; } checked_unlock( &b->b_mutex ); epoch_leave( epoch ); return; } #endif /* LDAP_PF_LOCAL */ hints.ai_family = AF_UNSPEC; hints.ai_flags = EVUTIL_AI_CANONNAME; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hostname = b->b_host; /* * Picking any value on the stack. This is unique to our thread without * having to call ldap_pvt_thread_self. * We might have to revert to using ldap_pvt_thread_self eventually since * this betrays where exactly our stack lies - potentially weakening some * protections like ASLR. */ placeholder = (struct evdns_getaddrinfo_request *)&request; b->b_dns_req = placeholder; checked_unlock( &b->b_mutex ); request = evdns_getaddrinfo( dnsbase, hostname, NULL, &hints, upstream_name_cb, b ); checked_lock( &b->b_mutex ); assert( request || b->b_dns_req != placeholder ); /* Record the request, unless upstream_name_cb or another thread * cleared it. Another thread is usually backend_reset or backend_connect * if upstream_name_cb finished and scheduled another one */ if ( b->b_dns_req == placeholder ) { b->b_dns_req = request; } checked_unlock( &b->b_mutex ); epoch_leave( epoch ); return; fail: b->b_opening--; b->b_failed++; backend_retry( b ); checked_unlock( &b->b_mutex ); epoch_leave( epoch ); } void * backend_connect_task( void *ctx, void *arg ) { backend_connect( -1, 0, arg ); return NULL; } /* * Needs exclusive access to the backend and no other thread is allowed to call * backend_retry while we're handling this. * * If gentle == 0, a full pause must be in effect, else we risk deadlocking on * event_free(). */ void backend_reset( LloadBackend *b, int gentle ) { assert_locked( &b->b_mutex ); if ( b->b_cookie ) { if ( ldap_pvt_thread_pool_retract( b->b_cookie ) ) { b->b_cookie = NULL; b->b_opening--; } else { /* * The task might not be cancelable because it just started * executing. * * Shutdown should be the only time when the thread pool is * in that state. Keep the cookie in to keep an eye on whether * it's finished yet. */ assert( slapd_shutdown ); } } /* Not safe to hold our mutex and call event_del/free if the event's * callback is running, relinquish the mutex while we do so. */ if ( b->b_retry_event && event_pending( b->b_retry_event, EV_TIMEOUT, NULL ) ) { assert( b->b_failed ); checked_unlock( &b->b_mutex ); event_del( b->b_retry_event ); checked_lock( &b->b_mutex ); b->b_opening--; } if ( b->b_dns_req ) { evdns_getaddrinfo_cancel( b->b_dns_req ); b->b_dns_req = NULL; b->b_opening--; } while ( !LDAP_LIST_EMPTY( &b->b_connecting ) ) { LloadPendingConnection *pending = LDAP_LIST_FIRST( &b->b_connecting ); Debug( LDAP_DEBUG_CONNS, "backend_reset: " "destroying socket pending connect() fd=%d\n", pending->fd ); event_active( pending->event, EV_WRITE, 0 ); evutil_closesocket( pending->fd ); pending->fd = -1; LDAP_LIST_REMOVE( pending, next ); if ( !gentle ) { /* None of the event bases are running, we're safe to free the * event right now and potentially free the backend itself */ event_free( pending->event ); ch_free( pending ); } /* else, just let the event dispose of the resources on its own later */ b->b_opening--; } connections_walk( &b->b_mutex, &b->b_preparing, lload_connection_close, &gentle ); assert( LDAP_CIRCLEQ_EMPTY( &b->b_preparing ) ); assert( b->b_opening == ( b->b_cookie ? 1 : 0 ) ); b->b_failed = 0; connections_walk_last( &b->b_mutex, &b->b_bindconns, b->b_last_bindconn, lload_connection_close, &gentle ); assert( gentle || b->b_bindavail == 0 ); connections_walk_last( &b->b_mutex, &b->b_conns, b->b_last_conn, lload_connection_close, &gentle ); assert( gentle || b->b_active == 0 ); assert_locked( &b->b_mutex ); } void lload_backend_destroy( LloadBackend *b ) { LloadBackend *next = LDAP_CIRCLEQ_LOOP_NEXT( &backend, b, b_next ); Debug( LDAP_DEBUG_CONNS, "lload_backend_destroy: " "destroying backend uri='%s', numconns=%d, numbindconns=%d\n", b->b_uri.bv_val, b->b_numconns, b->b_numbindconns ); checked_lock( &b->b_mutex ); b->b_numconns = b->b_numbindconns = 0; backend_reset( b, 0 ); LDAP_CIRCLEQ_REMOVE( &backend, b, b_next ); if ( b == next ) { current_backend = NULL; } else { current_backend = next; } #ifdef BALANCER_MODULE if ( b->b_monitor ) { BackendDB *be; struct berval monitordn = BER_BVC("cn=monitor"); int rc; be = select_backend( &monitordn, 0 ); /* FIXME: implement proper subsys shutdown in back-monitor or make * backend just an entry, not a subsys */ rc = b->b_monitor->mss_destroy( be, b->b_monitor ); assert( rc == LDAP_SUCCESS ); } #endif /* BALANCER_MODULE */ checked_unlock( &b->b_mutex ); ldap_pvt_thread_mutex_destroy( &b->b_mutex ); if ( b->b_retry_event ) { event_del( b->b_retry_event ); event_free( b->b_retry_event ); b->b_retry_event = NULL; } ch_free( b->b_host ); ch_free( b->b_uri.bv_val ); ch_free( b->b_name.bv_val ); ch_free( b ); } void lload_backends_destroy( void ) { while ( !LDAP_CIRCLEQ_EMPTY( &backend ) ) { LloadBackend *b = LDAP_CIRCLEQ_FIRST( &backend ); lload_backend_destroy( b ); } } openldap-2.5.11+dfsg/servers/lloadd/proto-lload.h0000644000175000017500000002207114172327167020376 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ #ifndef PROTO_LLOAD_H #define PROTO_LLOAD_H #include #include "ldap_pvt.h" #include LDAP_BEGIN_DECL /* * backend.c */ LDAP_SLAPD_F (void) backend_connect( evutil_socket_t s, short what, void *arg ); LDAP_SLAPD_F (void *) backend_connect_task( void *ctx, void *arg ); LDAP_SLAPD_F (void) backend_retry( LloadBackend *b ); LDAP_SLAPD_F (LloadConnection *) backend_select( LloadOperation *op, int *res ); LDAP_SLAPD_F (void) backend_reset( LloadBackend *b, int gentle ); LDAP_SLAPD_F (void) lload_backend_destroy( LloadBackend *b ); LDAP_SLAPD_F (void) lload_backends_destroy( void ); /* * bind.c */ LDAP_SLAPD_F (int) request_bind( LloadConnection *c, LloadOperation *op ); LDAP_SLAPD_F (int) handle_bind_response( LloadConnection *client, LloadOperation *op, BerElement *ber ); LDAP_SLAPD_F (int) handle_whoami_response( LloadConnection *client, LloadOperation *op, BerElement *ber ); LDAP_SLAPD_F (int) handle_vc_bind_response( LloadConnection *client, LloadOperation *op, BerElement *ber ); /* * client.c */ LDAP_SLAPD_F (int) request_abandon( LloadConnection *c, LloadOperation *op ); LDAP_SLAPD_F (int) request_process( LloadConnection *c, LloadOperation *op ); LDAP_SLAPD_F (int) handle_one_request( LloadConnection *c ); LDAP_SLAPD_F (void) client_tls_handshake_cb( evutil_socket_t s, short what, void *arg ); LDAP_SLAPD_F (LloadConnection *) client_init( ber_socket_t s, const char *peername, struct event_base *base, int use_tls ); LDAP_SLAPD_F (void) client_reset( LloadConnection *c ); LDAP_SLAPD_F (void) client_destroy( LloadConnection *c ); LDAP_SLAPD_F (void) clients_destroy( int gentle ); LDAP_SLAPD_V (long) lload_client_max_pending; /* * config.c */ LDAP_SLAPD_F (int) lload_read_config( const char *fname, const char *dir ); LDAP_SLAPD_F (void) lload_config_destroy( void ); LDAP_SLAPD_F (int) verb_to_mask( const char *word, slap_verbmasks *v ); LDAP_SLAPD_F (int) lload_tls_get_config( LDAP *ld, int opt, char **val ); LDAP_SLAPD_F (void) lload_bindconf_tls_defaults( slap_bindconf *bc ); LDAP_SLAPD_F (int) lload_backend_parse( const char *word, LloadBackend *b ); LDAP_SLAPD_F (int) lload_bindconf_parse( const char *word, slap_bindconf *bc ); LDAP_SLAPD_F (int) lload_bindconf_unparse( slap_bindconf *bc, struct berval *bv ); LDAP_SLAPD_F (int) lload_bindconf_tls_set( slap_bindconf *bc, LDAP *ld ); LDAP_SLAPD_F (void) lload_bindconf_free( slap_bindconf *bc ); #ifdef BALANCER_MODULE LDAP_SLAPD_F (int) lload_back_init_cf( BackendInfo *bi ); #endif /* * connection.c */ LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) clients_mutex; LDAP_SLAPD_F (void *) handle_pdus( void *ctx, void *arg ); LDAP_SLAPD_F (void) connection_write_cb( evutil_socket_t s, short what, void *arg ); LDAP_SLAPD_F (void) connection_read_cb( evutil_socket_t s, short what, void *arg ); LDAP_SLAPD_F (int) lload_connection_close( LloadConnection *c, void *arg ); LDAP_SLAPD_F (LloadConnection *) lload_connection_init( ber_socket_t s, const char *peername, int use_tls ); LDAP_SLAPD_F (void) connection_destroy( LloadConnection *c ); LDAP_SLAPD_F (void) connections_walk_last( ldap_pvt_thread_mutex_t *cq_mutex, lload_c_head *cq, LloadConnection *cq_last, CONNCB cb, void *arg ); LDAP_SLAPD_F (void) connections_walk( ldap_pvt_thread_mutex_t *cq_mutex, lload_c_head *cq, CONNCB cb, void *arg ); /* * daemon.c */ LDAP_SLAPD_F (int) lload_open_new_listener( const char *urls, LDAPURLDesc *lud ); LDAP_SLAPD_F (int) lloadd_listeners_init( const char *urls ); LDAP_SLAPD_F (int) lloadd_daemon_destroy( void ); LDAP_SLAPD_F (int) lloadd_daemon( struct event_base *daemon_base ); LDAP_SLAPD_F (LloadListener **) lloadd_get_listeners( void ); LDAP_SLAPD_F (void) listeners_reactivate( void ); LDAP_SLAPD_F (struct event_base *) lload_get_base( ber_socket_t s ); LDAP_SLAPD_V (int) lload_daemon_threads; LDAP_SLAPD_V (int) lload_daemon_mask; LDAP_SLAPD_F (void) lload_sig_shutdown( evutil_socket_t sig, short what, void *arg ); LDAP_SLAPD_F (void) lload_pause_server( void ); LDAP_SLAPD_F (void) lload_unpause_server( void ); LDAP_SLAPD_V (struct event_base *) daemon_base; LDAP_SLAPD_V (struct evdns_base *) dnsbase; LDAP_SLAPD_V (volatile sig_atomic_t) slapd_shutdown; LDAP_SLAPD_V (volatile sig_atomic_t) slapd_gentle_shutdown; LDAP_SLAPD_V (int) lloadd_inited; LDAP_SLAPD_V (struct LloadChange) lload_change; LDAP_SLAPD_V (struct event *) lload_timeout_event; LDAP_SLAPD_V (LDAP *) lload_tls_backend_ld; LDAP_SLAPD_V (LDAP *) lload_tls_ld; LDAP_SLAPD_V (void *) lload_tls_ctx; #ifdef BALANCER_MODULE LDAP_SLAPD_V (int) lload_use_slap_tls_ctx; #endif /* BALANCER_MODULE */ /* * extended.c */ LDAP_SLAPD_V (Avlnode *) lload_exop_handlers; LDAP_SLAPD_F (int) exop_handler_cmp( const void *l, const void *r ); LDAP_SLAPD_F (int) request_extended( LloadConnection *c, LloadOperation *op ); LDAP_SLAPD_F (int) lload_exop_init( void ); /* * init.c */ LDAP_SLAPD_F (int) lload_global_init( void ); LDAP_SLAPD_F (int) lload_tls_init( void ); LDAP_SLAPD_F (int) lload_init( int mode, const char *name ); LDAP_SLAPD_F (int) lload_destroy( void ); LDAP_SLAPD_F (void) lload_counters_init( void ); /* * libevent_support.c */ LDAP_SLAPD_F (int) lload_libevent_init( void ); LDAP_SLAPD_F (void) lload_libevent_destroy( void ); #ifdef BALANCER_MODULE /* * monitor.c */ LDAP_SLAPD_F (int) lload_monitor_open( void ); LDAP_SLAPD_F (int) lload_monitor_backend_init( BackendInfo *bi, LloadBackend *b ); #endif /* BALANCER_MODULE */ /* * operation.c */ LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) lload_pin_mutex; LDAP_SLAPD_V (unsigned long) lload_next_pin; LDAP_SLAPD_F (const char *) lload_msgtype2str( ber_tag_t tag ); LDAP_SLAPD_F (int) operation_upstream_cmp( const void *l, const void *r ); LDAP_SLAPD_F (int) operation_client_cmp( const void *l, const void *r ); LDAP_SLAPD_F (LloadOperation *) operation_init( LloadConnection *c, BerElement *ber ); LDAP_SLAPD_F (int) operation_send_abandon( LloadOperation *op, LloadConnection *c ); LDAP_SLAPD_F (void) operation_abandon( LloadOperation *op ); LDAP_SLAPD_F (void) operation_send_reject( LloadOperation *op, int result, const char *msg, int send_anyway ); LDAP_SLAPD_F (int) operation_send_reject_locked( LloadOperation *op, int result, const char *msg, int send_anyway ); LDAP_SLAPD_F (void) operation_lost_upstream( LloadOperation *op ); LDAP_SLAPD_F (void) operation_destroy( LloadOperation *op ); LDAP_SLAPD_F (int) operation_unlink( LloadOperation *op ); LDAP_SLAPD_F (int) operation_unlink_client( LloadOperation *op, LloadConnection *client ); LDAP_SLAPD_F (int) operation_unlink_upstream( LloadOperation *op, LloadConnection *upstream ); LDAP_SLAPD_F (void) operations_timeout( evutil_socket_t s, short what, void *arg ); LDAP_SLAPD_F (void) operation_update_conn_counters( LloadOperation *op, LloadConnection *upstream ); LDAP_SLAPD_F (void) operation_update_backend_counters( LloadOperation *op, LloadBackend *b ); LDAP_SLAPD_F (void) operation_update_global_rejected( LloadOperation *op ); /* * upstream.c */ LDAP_SLAPD_F (int) forward_final_response( LloadConnection *client, LloadOperation *op, BerElement *ber ); LDAP_SLAPD_F (int) forward_response( LloadConnection *client, LloadOperation *op, BerElement *ber ); LDAP_SLAPD_F (void *) upstream_bind( void *ctx, void *arg ); LDAP_SLAPD_F (LloadConnection *) upstream_init( ber_socket_t s, LloadBackend *b ); LDAP_SLAPD_F (void) upstream_destroy( LloadConnection *c ); LDAP_SLAPD_V (ber_len_t) sockbuf_max_incoming_client; LDAP_SLAPD_V (ber_len_t) sockbuf_max_incoming_upstream; LDAP_SLAPD_V (int) lload_conn_max_pdus_per_cycle; LDAP_SLAPD_V (lload_features_t) lload_features; LDAP_SLAPD_V (slap_mask_t) global_allows; LDAP_SLAPD_V (slap_mask_t) global_disallows; LDAP_SLAPD_V (const char) Versionstr[]; LDAP_SLAPD_V (int) global_gentlehup; LDAP_SLAPD_V (int) global_idletimeout; LDAP_SLAPD_V (struct timeval *) lload_timeout_api; LDAP_SLAPD_V (struct timeval *) lload_timeout_net; LDAP_SLAPD_V (struct timeval *) lload_write_timeout; LDAP_SLAPD_V (char *) global_host; LDAP_SLAPD_V (int) lber_debug; LDAP_SLAPD_V (int) ldap_syslog; LDAP_SLAPD_V (lload_global_stats_t) lload_stats; LDAP_SLAPD_V (char *) listeners_list; LDAP_END_DECL #endif /* PROTO_LLOAD_H */ openldap-2.5.11+dfsg/servers/lloadd/operation.c0000644000175000017500000005062114172327167020137 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include "lutil.h" #include "lload.h" ldap_pvt_thread_mutex_t lload_pin_mutex; unsigned long lload_next_pin = 1; ber_tag_t slap_req2res( ber_tag_t tag ) { switch ( tag ) { case LDAP_REQ_ADD: case LDAP_REQ_BIND: case LDAP_REQ_COMPARE: case LDAP_REQ_EXTENDED: case LDAP_REQ_MODIFY: case LDAP_REQ_MODRDN: tag++; break; case LDAP_REQ_DELETE: tag = LDAP_RES_DELETE; break; case LDAP_REQ_ABANDON: case LDAP_REQ_UNBIND: tag = LBER_SEQUENCE; break; case LDAP_REQ_SEARCH: tag = LDAP_RES_SEARCH_RESULT; break; default: tag = LBER_SEQUENCE; } return tag; } const char * lload_msgtype2str( ber_tag_t tag ) { switch ( tag ) { case LDAP_REQ_ABANDON: return "abandon request"; case LDAP_REQ_ADD: return "add request"; case LDAP_REQ_BIND: return "bind request"; case LDAP_REQ_COMPARE: return "compare request"; case LDAP_REQ_DELETE: return "delete request"; case LDAP_REQ_EXTENDED: return "extended request"; case LDAP_REQ_MODIFY: return "modify request"; case LDAP_REQ_RENAME: return "rename request"; case LDAP_REQ_SEARCH: return "search request"; case LDAP_REQ_UNBIND: return "unbind request"; case LDAP_RES_ADD: return "add result"; case LDAP_RES_BIND: return "bind result"; case LDAP_RES_COMPARE: return "compare result"; case LDAP_RES_DELETE: return "delete result"; case LDAP_RES_EXTENDED: return "extended result"; case LDAP_RES_INTERMEDIATE: return "intermediate response"; case LDAP_RES_MODIFY: return "modify result"; case LDAP_RES_RENAME: return "rename result"; case LDAP_RES_SEARCH_ENTRY: return "search-entry response"; case LDAP_RES_SEARCH_REFERENCE: return "search-reference response"; case LDAP_RES_SEARCH_RESULT: return "search result"; } return "unknown message"; } int operation_client_cmp( const void *left, const void *right ) { const LloadOperation *l = left, *r = right; assert( l->o_client_connid == r->o_client_connid ); if ( l->o_client_msgid || r->o_client_msgid ) { return ( l->o_client_msgid < r->o_client_msgid ) ? -1 : ( l->o_client_msgid > r->o_client_msgid ); } else { return ( l->o_pin_id < r->o_pin_id ) ? -1 : ( l->o_pin_id > r->o_pin_id ); } } int operation_upstream_cmp( const void *left, const void *right ) { const LloadOperation *l = left, *r = right; assert( l->o_upstream_connid == r->o_upstream_connid ); if ( l->o_upstream_msgid || r->o_upstream_msgid ) { return ( l->o_upstream_msgid < r->o_upstream_msgid ) ? -1 : ( l->o_upstream_msgid > r->o_upstream_msgid ); } else { return ( l->o_pin_id < r->o_pin_id ) ? -1 : ( l->o_pin_id > r->o_pin_id ); } } /* * Entered holding c_mutex for now. */ LloadOperation * operation_init( LloadConnection *c, BerElement *ber ) { LloadOperation *op; ber_tag_t tag; ber_len_t len; int rc; if ( !IS_ALIVE( c, c_live ) ) { return NULL; } op = ch_calloc( 1, sizeof(LloadOperation) ); op->o_client = c; op->o_client_connid = c->c_connid; op->o_ber = ber; op->o_start = slap_get_time(); ldap_pvt_thread_mutex_init( &op->o_link_mutex ); op->o_refcnt = 1; tag = ber_get_int( ber, &op->o_client_msgid ); if ( tag != LDAP_TAG_MSGID ) { goto fail; } if ( !op->o_client_msgid ) { goto fail; } CONNECTION_ASSERT_LOCKED(c); rc = ldap_tavl_insert( &c->c_ops, op, operation_client_cmp, ldap_avl_dup_error ); if ( rc ) { Debug( LDAP_DEBUG_PACKETS, "operation_init: " "several operations with same msgid=%d in-flight " "from client connid=%lu\n", op->o_client_msgid, op->o_client_connid ); goto fail; } tag = op->o_tag = ber_skip_element( ber, &op->o_request ); switch ( tag ) { case LBER_ERROR: rc = -1; break; } if ( rc ) { ldap_tavl_delete( &c->c_ops, op, operation_client_cmp ); goto fail; } tag = ber_peek_tag( ber, &len ); if ( tag == LDAP_TAG_CONTROLS ) { ber_skip_element( ber, &op->o_ctrls ); } switch ( op->o_tag ) { case LDAP_REQ_BIND: lload_stats.counters[LLOAD_STATS_OPS_BIND].lc_ops_received++; break; default: lload_stats.counters[LLOAD_STATS_OPS_OTHER].lc_ops_received++; break; } Debug( LDAP_DEBUG_STATS, "operation_init: " "received a new operation, %s with msgid=%d for client " "connid=%lu\n", lload_msgtype2str( op->o_tag ), op->o_client_msgid, op->o_client_connid ); c->c_n_ops_executing++; return op; fail: ch_free( op ); return NULL; } void operation_destroy( LloadOperation *op ) { Debug( LDAP_DEBUG_TRACE, "operation_destroy: " "op=%p destroyed operation from client connid=%lu, " "client msgid=%d\n", op, op->o_client_connid, op->o_client_msgid ); assert( op->o_refcnt == 0 ); assert( op->o_client == NULL ); assert( op->o_upstream == NULL ); ber_free( op->o_ber, 1 ); ldap_pvt_thread_mutex_destroy( &op->o_link_mutex ); ch_free( op ); } int operation_unlink( LloadOperation *op ) { LloadConnection *client, *upstream; uintptr_t prev_refcnt; int result = 0; if ( !( prev_refcnt = try_release_ref( &op->o_refcnt, op, (dispose_cb *)operation_destroy ) ) ) { return result; } assert( prev_refcnt == 1 ); Debug( LDAP_DEBUG_TRACE, "operation_unlink: " "unlinking operation between client connid=%lu and upstream " "connid=%lu " "client msgid=%d\n", op->o_client_connid, op->o_upstream_connid, op->o_client_msgid ); checked_lock( &op->o_link_mutex ); client = op->o_client; upstream = op->o_upstream; op->o_client = NULL; op->o_upstream = NULL; checked_unlock( &op->o_link_mutex ); assert( client || upstream ); if ( client ) { result |= operation_unlink_client( op, client ); operation_update_global_rejected( op ); } if ( upstream ) { result |= operation_unlink_upstream( op, upstream ); } return result; } int operation_unlink_client( LloadOperation *op, LloadConnection *client ) { LloadOperation *removed; int result = 0; Debug( LDAP_DEBUG_TRACE, "operation_unlink_client: " "unlinking operation op=%p msgid=%d client connid=%lu\n", op, op->o_client_msgid, op->o_client_connid ); CONNECTION_LOCK(client); if ( (removed = ldap_tavl_delete( &client->c_ops, op, operation_client_cmp )) ) { result = LLOAD_OP_DETACHING_CLIENT; assert( op == removed ); client->c_n_ops_executing--; if ( op->o_tag == LDAP_REQ_BIND && client->c_state == LLOAD_C_BINDING ) { client->c_state = LLOAD_C_READY; if ( !BER_BVISNULL( &client->c_auth ) ) { ber_memfree( client->c_auth.bv_val ); BER_BVZERO( &client->c_auth ); } if ( !BER_BVISNULL( &client->c_sasl_bind_mech ) ) { ber_memfree( client->c_sasl_bind_mech.bv_val ); BER_BVZERO( &client->c_sasl_bind_mech ); } if ( op->o_pin_id ) { client->c_pin_id = 0; } } } if ( client->c_state == LLOAD_C_CLOSING && !client->c_ops ) { CONNECTION_DESTROY(client); } else { CONNECTION_UNLOCK(client); } return result; } int operation_unlink_upstream( LloadOperation *op, LloadConnection *upstream ) { LloadOperation *removed; LloadBackend *b = NULL; int result = 0; Debug( LDAP_DEBUG_TRACE, "operation_unlink_upstream: " "unlinking operation op=%p msgid=%d upstream connid=%lu\n", op, op->o_upstream_msgid, op->o_upstream_connid ); CONNECTION_LOCK(upstream); if ( (removed = ldap_tavl_delete( &upstream->c_ops, op, operation_upstream_cmp )) ) { result |= LLOAD_OP_DETACHING_UPSTREAM; assert( op == removed ); upstream->c_n_ops_executing--; if ( upstream->c_state == LLOAD_C_BINDING ) { assert( op->o_tag == LDAP_REQ_BIND && upstream->c_ops == NULL ); upstream->c_state = LLOAD_C_READY; if ( !BER_BVISNULL( &upstream->c_sasl_bind_mech ) ) { ber_memfree( upstream->c_sasl_bind_mech.bv_val ); BER_BVZERO( &upstream->c_sasl_bind_mech ); } } operation_update_conn_counters( op, upstream ); b = upstream->c_backend; } if ( upstream->c_state == LLOAD_C_CLOSING && !upstream->c_ops ) { CONNECTION_DESTROY(upstream); } else { CONNECTION_UNLOCK(upstream); } if ( b ) { checked_lock( &b->b_mutex ); b->b_n_ops_executing--; operation_update_backend_counters( op, b ); checked_unlock( &b->b_mutex ); } return result; } int operation_send_abandon( LloadOperation *op, LloadConnection *upstream ) { BerElement *ber; int rc = -1; if ( !IS_ALIVE( upstream, c_live ) ) { return rc; } checked_lock( &upstream->c_io_mutex ); ber = upstream->c_pendingber; if ( ber == NULL && (ber = ber_alloc()) == NULL ) { Debug( LDAP_DEBUG_ANY, "operation_send_abandon: " "ber_alloc failed\n" ); goto done; } upstream->c_pendingber = ber; Debug( LDAP_DEBUG_TRACE, "operation_send_abandon: " "abandoning %s msgid=%d on connid=%lu\n", lload_msgtype2str( op->o_tag ), op->o_upstream_msgid, op->o_upstream_connid ); if ( op->o_tag == LDAP_REQ_BIND ) { rc = ber_printf( ber, "t{tit{ist{s}}}", LDAP_TAG_MESSAGE, LDAP_TAG_MSGID, upstream->c_next_msgid++, LDAP_REQ_BIND, LDAP_VERSION3, "", LDAP_AUTH_SASL, "" ); } else { rc = ber_printf( ber, "t{titi}", LDAP_TAG_MESSAGE, LDAP_TAG_MSGID, upstream->c_next_msgid++, LDAP_REQ_ABANDON, op->o_upstream_msgid ); } if ( rc < 0 ) { ber_free( ber, 1 ); upstream->c_pendingber = NULL; goto done; } rc = LDAP_SUCCESS; done: checked_unlock( &upstream->c_io_mutex ); return rc; } /* * Will remove the operation from its upstream and if it was still there, * sends an abandon request. * * Being called from client_reset or request_abandon, the following hold: * - noone else is processing the read part of the client connection (no new * operations come in there - relevant for the c_state checks) * - op->o_client_refcnt > op->o_client_live (and it follows that op->o_client != NULL) */ void operation_abandon( LloadOperation *op ) { LloadConnection *c; checked_lock( &op->o_link_mutex ); c = op->o_upstream; checked_unlock( &op->o_link_mutex ); if ( !c || !IS_ALIVE( c, c_live ) ) { goto done; } /* for now consider all abandoned operations completed, * perhaps add a separate counter later */ op->o_res = LLOAD_OP_COMPLETED; if ( !operation_unlink_upstream( op, c ) ) { /* The operation has already been abandoned or finished */ Debug( LDAP_DEBUG_TRACE, "operation_abandon: " "%s from connid=%lu msgid=%d not present in connid=%lu any " "more\n", lload_msgtype2str( op->o_tag ), op->o_client_connid, op->o_client_msgid, op->o_upstream_connid ); goto done; } if ( operation_send_abandon( op, c ) == LDAP_SUCCESS ) { connection_write_cb( -1, 0, c ); } done: operation_unlink( op ); } void operation_send_reject( LloadOperation *op, int result, const char *msg, int send_anyway ) { LloadConnection *c; BerElement *ber; int found; Debug( LDAP_DEBUG_TRACE, "operation_send_reject: " "rejecting %s from client connid=%lu with message: \"%s\"\n", lload_msgtype2str( op->o_tag ), op->o_client_connid, msg ); checked_lock( &op->o_link_mutex ); c = op->o_client; checked_unlock( &op->o_link_mutex ); if ( !c || !IS_ALIVE( c, c_live ) ) { Debug( LDAP_DEBUG_TRACE, "operation_send_reject: " "not sending msgid=%d, client connid=%lu is dead\n", op->o_client_msgid, op->o_client_connid ); goto done; } found = operation_unlink_client( op, c ); if ( !found && !send_anyway ) { Debug( LDAP_DEBUG_TRACE, "operation_send_reject: " "msgid=%d not scheduled for client connid=%lu anymore, " "not sending\n", op->o_client_msgid, c->c_connid ); goto done; } if ( op->o_client_msgid == 0 ) { assert( op->o_saved_msgid == 0 && op->o_pin_id ); Debug( LDAP_DEBUG_TRACE, "operation_send_reject: " "operation pin=%lu is just a pin, not sending\n", op->o_pin_id ); goto done; } checked_lock( &c->c_io_mutex ); ber = c->c_pendingber; if ( ber == NULL && (ber = ber_alloc()) == NULL ) { checked_unlock( &c->c_io_mutex ); Debug( LDAP_DEBUG_ANY, "operation_send_reject: " "ber_alloc failed, closing connid=%lu\n", c->c_connid ); CONNECTION_LOCK_DESTROY(c); goto done; } c->c_pendingber = ber; ber_printf( ber, "t{tit{ess}}", LDAP_TAG_MESSAGE, LDAP_TAG_MSGID, op->o_client_msgid, slap_req2res( op->o_tag ), result, "", msg ); checked_unlock( &c->c_io_mutex ); connection_write_cb( -1, 0, c ); done: operation_unlink( op ); } /* * Upstream is shutting down, signal the client if necessary, but we have to * call operation_destroy_from_upstream ourselves to detach upstream from the * op. * * Only called from upstream_destroy. */ void operation_lost_upstream( LloadOperation *op ) { operation_send_reject( op, LDAP_OTHER, "connection to the remote server has been severed", 0 ); } int connection_timeout( LloadConnection *upstream, void *arg ) { LloadOperation *op; TAvlnode *ops = NULL, *node, *next; LloadBackend *b = upstream->c_backend; time_t threshold = *(time_t *)arg; int rc, nops = 0; CONNECTION_LOCK(upstream); for ( node = ldap_tavl_end( upstream->c_ops, TAVL_DIR_LEFT ); node && ((LloadOperation *)node->avl_data)->o_start < threshold; /* shortcut */ node = next ) { LloadOperation *found_op; next = ldap_tavl_next( node, TAVL_DIR_RIGHT ); op = node->avl_data; /* Have we received another response since? */ if ( op->o_last_response && op->o_last_response >= threshold ) { continue; } op->o_res = LLOAD_OP_FAILED; found_op = ldap_tavl_delete( &upstream->c_ops, op, operation_upstream_cmp ); assert( op == found_op ); if ( upstream->c_state == LLOAD_C_BINDING ) { assert( op->o_tag == LDAP_REQ_BIND && upstream->c_ops == NULL ); upstream->c_state = LLOAD_C_READY; if ( !BER_BVISNULL( &upstream->c_sasl_bind_mech ) ) { ber_memfree( upstream->c_sasl_bind_mech.bv_val ); BER_BVZERO( &upstream->c_sasl_bind_mech ); } } rc = ldap_tavl_insert( &ops, op, operation_upstream_cmp, ldap_avl_dup_error ); assert( rc == LDAP_SUCCESS ); Debug( LDAP_DEBUG_STATS2, "connection_timeout: " "timing out %s from connid=%lu msgid=%d sent to connid=%lu as " "msgid=%d\n", lload_msgtype2str( op->o_tag ), op->o_client_connid, op->o_client_msgid, op->o_upstream_connid, op->o_upstream_msgid ); nops++; } if ( nops == 0 ) { CONNECTION_UNLOCK(upstream); return LDAP_SUCCESS; } upstream->c_n_ops_executing -= nops; upstream->c_counters.lc_ops_failed += nops; Debug( LDAP_DEBUG_STATS, "connection_timeout: " "timing out %d operations for connid=%lu\n", nops, upstream->c_connid ); CONNECTION_UNLOCK(upstream); checked_lock( &b->b_mutex ); b->b_n_ops_executing -= nops; checked_unlock( &b->b_mutex ); for ( node = ldap_tavl_end( ops, TAVL_DIR_LEFT ); node; node = ldap_tavl_next( node, TAVL_DIR_RIGHT ) ) { op = node->avl_data; operation_send_reject( op, op->o_tag == LDAP_REQ_SEARCH ? LDAP_TIMELIMIT_EXCEEDED : LDAP_ADMINLIMIT_EXCEEDED, "upstream did not respond in time", 0 ); if ( rc == LDAP_SUCCESS ) { rc = operation_send_abandon( op, upstream ); } operation_unlink( op ); } /* TODO: if operation_send_abandon failed, we need to kill the upstream */ if ( rc == LDAP_SUCCESS ) { connection_write_cb( -1, 0, upstream ); } CONNECTION_LOCK(upstream); if ( upstream->c_state == LLOAD_C_CLOSING && !upstream->c_ops ) { CONNECTION_DESTROY(upstream); } else { CONNECTION_UNLOCK(upstream); } /* just dispose of the AVL, most operations should already be gone */ ldap_tavl_free( ops, NULL ); return LDAP_SUCCESS; } void operations_timeout( evutil_socket_t s, short what, void *arg ) { struct event *self = arg; LloadBackend *b; time_t threshold; Debug( LDAP_DEBUG_TRACE, "operations_timeout: " "running timeout task\n" ); if ( !lload_timeout_api ) goto done; threshold = slap_get_time() - lload_timeout_api->tv_sec; LDAP_CIRCLEQ_FOREACH ( b, &backend, b_next ) { epoch_t epoch; checked_lock( &b->b_mutex ); if ( b->b_n_ops_executing == 0 ) { checked_unlock( &b->b_mutex ); continue; } epoch = epoch_join(); Debug( LDAP_DEBUG_TRACE, "operations_timeout: " "timing out binds for backend uri=%s\n", b->b_uri.bv_val ); connections_walk_last( &b->b_mutex, &b->b_bindconns, b->b_last_bindconn, connection_timeout, &threshold ); Debug( LDAP_DEBUG_TRACE, "operations_timeout: " "timing out other operations for backend uri=%s\n", b->b_uri.bv_val ); connections_walk_last( &b->b_mutex, &b->b_conns, b->b_last_conn, connection_timeout, &threshold ); epoch_leave( epoch ); checked_unlock( &b->b_mutex ); } done: Debug( LDAP_DEBUG_TRACE, "operations_timeout: " "timeout task finished\n" ); evtimer_add( self, lload_timeout_api ); } void operation_update_global_rejected( LloadOperation *op ) { if ( op->o_res == LLOAD_OP_REJECTED ) { assert( op->o_upstream_connid == 0 ); switch ( op->o_tag ) { case LDAP_REQ_BIND: lload_stats.counters[LLOAD_STATS_OPS_BIND].lc_ops_rejected++; break; default: lload_stats.counters[LLOAD_STATS_OPS_OTHER].lc_ops_rejected++; break; } } } void operation_update_conn_counters( LloadOperation *op, LloadConnection *upstream ) { if ( op->o_res == LLOAD_OP_COMPLETED ) { upstream->c_counters.lc_ops_completed++; } else { upstream->c_counters.lc_ops_failed++; } } void operation_update_backend_counters( LloadOperation *op, LloadBackend *b ) { int stat_type = op->o_tag == LDAP_REQ_BIND ? LLOAD_STATS_OPS_BIND : LLOAD_STATS_OPS_OTHER; assert( b != NULL ); if ( op->o_res == LLOAD_OP_COMPLETED ) { b->b_counters[stat_type].lc_ops_completed++; } else { b->b_counters[stat_type].lc_ops_failed++; } } openldap-2.5.11+dfsg/servers/lloadd/module_init.c0000644000175000017500000001052214172327167020443 0ustar ryanryan/* module_init.c - module initialization functions */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ #include "portable.h" #include #include #include #include #include "../servers/slapd/slap.h" #include "../servers/slapd/slap-config.h" #include "lload.h" #include "lber_pvt.h" #include "ldap_rq.h" ldap_pvt_thread_t lloadd_main_thread; struct lload_conf_info lload_info; void * lload_start_daemon( void *arg ) { int rc = 0; daemon_base = event_base_new(); if ( !daemon_base ) { Debug( LDAP_DEBUG_ANY, "lload_start_daemon: " "main event base allocation failed\n" ); rc = 1; goto done; } rc = lloadd_daemon( daemon_base ); done: if ( rc != LDAP_SUCCESS ) { assert( lloadd_inited == 0 ); checked_lock( &lload_wait_mutex ); ldap_pvt_thread_cond_signal( &lload_wait_cond ); checked_unlock( &lload_wait_mutex ); } return (void *)(uintptr_t)rc; } static int lload_pause_cb( BackendInfo *bi ) { if ( daemon_base ) { lload_pause_server(); } return 0; } static int lload_unpause_cb( BackendInfo *bi ) { if ( daemon_base ) { lload_unpause_server(); } return 0; } int lload_back_open( BackendInfo *bi ) { int rc = 0; if ( slapMode & SLAP_TOOL_MODE ) { return 0; } /* This will fail if we ever try to instantiate more than one lloadd within * the process */ epoch_init(); if ( lload_tls_init() != 0 ) { return -1; } if ( lload_monitor_open() != 0 ) { return -1; } assert( lloadd_get_listeners() ); checked_lock( &lload_wait_mutex ); rc = ldap_pvt_thread_create( &lloadd_main_thread, 0, lload_start_daemon, NULL ); if ( !rc ) { ldap_pvt_thread_cond_wait( &lload_wait_cond, &lload_wait_mutex ); if ( lloadd_inited != 1 ) { ldap_pvt_thread_join( lloadd_main_thread, (void *)NULL ); rc = -1; } } checked_unlock( &lload_wait_mutex ); return rc; } int lload_back_close( BackendInfo *bi ) { if ( slapMode & SLAP_TOOL_MODE ) { return 0; } assert( lloadd_inited == 1 ); checked_lock( &lload_wait_mutex ); event_base_loopexit( daemon_base, NULL ); ldap_pvt_thread_cond_wait( &lload_wait_cond, &lload_wait_mutex ); checked_unlock( &lload_wait_mutex ); ldap_pvt_thread_join( lloadd_main_thread, (void *)NULL ); return 0; } int lload_back_initialize( BackendInfo *bi ) { bi->bi_flags = SLAP_BFLAG_STANDALONE; bi->bi_open = lload_back_open; bi->bi_config = config_generic_wrapper; bi->bi_pause = lload_pause_cb; bi->bi_unpause = lload_unpause_cb; bi->bi_close = lload_back_close; bi->bi_destroy = 0; bi->bi_db_init = 0; bi->bi_db_config = 0; bi->bi_db_open = 0; bi->bi_db_close = 0; bi->bi_db_destroy = 0; bi->bi_op_bind = 0; bi->bi_op_unbind = 0; bi->bi_op_search = 0; bi->bi_op_compare = 0; bi->bi_op_modify = 0; bi->bi_op_modrdn = 0; bi->bi_op_add = 0; bi->bi_op_delete = 0; bi->bi_op_abandon = 0; bi->bi_extended = 0; bi->bi_chk_referrals = 0; bi->bi_connection_init = 0; bi->bi_connection_destroy = 0; if ( lload_global_init() ) { return -1; } bi->bi_private = &lload_info; return lload_back_init_cf( bi ); } SLAP_BACKEND_INIT_MODULE( lload ) openldap-2.5.11+dfsg/servers/lloadd/lload-config.h0000644000175000017500000000235214172327167020500 0ustar ryanryan/* lload-config.h - configuration abstraction structure */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #ifndef LLOAD_CONFIG_H /* not CONFIG_H because it overlaps with the one from slapd */ #define LLOAD_CONFIG_H #include #include "../slapd/slap-config.h" LDAP_BEGIN_DECL int lload_config_fp_parse_line( ConfigArgs *c ); int lload_config_get_vals( ConfigTable *ct, ConfigArgs *c ); int lload_config_add_vals( ConfigTable *ct, ConfigArgs *c ); void lload_init_config_argv( ConfigArgs *c ); int lload_read_config_file( const char *fname, int depth, ConfigArgs *cf, ConfigTable *cft ); ConfigTable *lload_config_find_keyword( ConfigTable *ct, ConfigArgs *c ); LloadListener *lload_config_check_my_url( const char *url, LDAPURLDesc *lud ); LDAP_END_DECL #endif /* LLOAD_CONFIG_H */ openldap-2.5.11+dfsg/servers/lloadd/Makefile_module.in0000644000175000017500000000232314172327167021401 0ustar ryanryan# Makefile.in for Load Balancer # $OpenLDAP$ ## This work is part of OpenLDAP Software . ## ## Copyright 1998-2022 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted only as authorized by the OpenLDAP ## Public License. ## ## A copy of this license is available in the file LICENSE in the ## top-level directory of the distribution or, alternatively, at ## . XSRCS = version.c NT_SRCS = ../slapd/nt_svc.c NT_OBJS = ../slapd/nt_svc.o ../../libraries/liblutil/slapdmsg.res SRCS += module_init.c monitor.c OBJS = $(patsubst %.c,%.lo,$(SRCS)) $(@PLAT@_OBJS) BUILD_OPT = "--enable-balancer=mod" BUILD_MOD = @BUILD_BALANCER@ LIBBASE=lloadd # $(LTHREAD_LIBS) must be last! XLIBS = $(LLOADD_L) XXLIBS = $(LLOADD_LIBS) $(SECURITY_LIBS) $(LUTIL_LIBS) XXXLIBS = $(LTHREAD_LIBS) NT_DEPENDS = slapd.exp NT_OBJECTS = slapd.exp symdummy.o $(LLOADD_OBJS) version.o UNIX_DEPENDS = version.o $(LLOADD_L) UNIX_OBJECTS = $(OBJS) version.o LLOADD_DEPENDS = $(@PLAT@_DEPENDS) LLOADD_OBJECTS = $(@PLAT@_OBJECTS) LINK_LIBS=$(LLOADD_LIBS) MOD_DEFS = -DSLAPD_IMPORT -DBALANCER_MODULE openldap-2.5.11+dfsg/servers/lloadd/value.c0000644000175000017500000000372214172327167017253 0ustar ryanryan/* value.c - routines for dealing with values */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* * Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ #include "portable.h" #include "lload.h" int value_add_one( BerVarray *vals, struct berval *addval ) { int n; BerVarray v2; if ( *vals == NULL ) { *vals = (BerVarray)SLAP_MALLOC( 2 * sizeof(struct berval) ); if ( *vals == NULL ) { Debug( LDAP_DEBUG_TRACE, "value_add_one: " "SLAP_MALLOC failed.\n" ); return LBER_ERROR_MEMORY; } n = 0; } else { for ( n = 0; !BER_BVISNULL( &(*vals)[n] ); n++ ) { ; /* Empty */ } *vals = (BerVarray)SLAP_REALLOC( (char *)*vals, ( n + 2 ) * sizeof(struct berval) ); if ( *vals == NULL ) { Debug( LDAP_DEBUG_TRACE, "value_add_one: " "SLAP_MALLOC failed.\n" ); return LBER_ERROR_MEMORY; } } v2 = &(*vals)[n]; ber_dupbv( v2, addval ); v2++; BER_BVZERO( v2 ); return LDAP_SUCCESS; } openldap-2.5.11+dfsg/servers/lloadd/init.c0000644000175000017500000001243014172327167017076 0ustar ryanryan/* init.c - initialize various things */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ #include "portable.h" #include #include #include #include #include "lload.h" #include "lber_pvt.h" #include "ldap_rq.h" #ifndef BALANCER_MODULE /* * read-only global variables or variables only written by the listener * thread (after they are initialized) - no need to protect them with a mutex. */ int slap_debug = 0; #ifdef LDAP_DEBUG int ldap_syslog = LDAP_DEBUG_STATS; #else int ldap_syslog; #endif #ifdef LOG_DEBUG int ldap_syslog_level = LOG_DEBUG; #endif /* * global variables that need mutex protection */ ldap_pvt_thread_pool_t connection_pool; int connection_pool_max = SLAP_MAX_WORKER_THREADS; int connection_pool_queues = 1; int slap_tool_thread_max = 1; int slapMode = SLAP_UNDEFINED_MODE; #endif /* !BALANCER_MODULE */ static const char *lload_name = NULL; int lload_global_init( void ) { int rc; if ( lload_libevent_init() ) { return -1; } #ifdef HAVE_TLS if ( ldap_create( &lload_tls_backend_ld ) ) { return -1; } if ( ldap_create( &lload_tls_ld ) ) { return -1; } /* Library defaults to full certificate checking. This is correct when * a client is verifying a server because all servers should have a * valid cert. But few clients have valid certs, so we want our default * to be no checking. The config file can override this as usual. */ rc = LDAP_OPT_X_TLS_NEVER; (void)ldap_pvt_tls_set_option( lload_tls_ld, LDAP_OPT_X_TLS_REQUIRE_CERT, &rc ); #endif ldap_pvt_thread_mutex_init( &lload_wait_mutex ); ldap_pvt_thread_cond_init( &lload_wait_cond ); ldap_pvt_thread_cond_init( &lload_pause_cond ); ldap_pvt_thread_mutex_init( &backend_mutex ); ldap_pvt_thread_mutex_init( &clients_mutex ); ldap_pvt_thread_mutex_init( &lload_pin_mutex ); if ( lload_exop_init() ) { return -1; } return 0; } int lload_tls_init( void ) { #ifdef HAVE_TLS int rc, opt = 1; /* Force new ctx to be created */ rc = ldap_pvt_tls_set_option( lload_tls_ld, LDAP_OPT_X_TLS_NEWCTX, &opt ); if ( rc == 0 ) { /* The ctx's refcount is bumped up here */ ldap_pvt_tls_get_option( lload_tls_ld, LDAP_OPT_X_TLS_CTX, &lload_tls_ctx ); } else if ( rc != LDAP_NOT_SUPPORTED ) { Debug( LDAP_DEBUG_ANY, "lload_global_init: " "TLS init def ctx failed: %d\n", rc ); return -1; } #endif return 0; } int lload_init( int mode, const char *name ) { int rc = LDAP_SUCCESS; assert( mode ); if ( slapMode != SLAP_UNDEFINED_MODE ) { /* Make sure we write something to stderr */ slap_debug |= LDAP_DEBUG_NONE; Debug( LDAP_DEBUG_ANY, "%s init: " "init called twice (old=%d, new=%d)\n", name, slapMode, mode ); return 1; } slapMode = mode; switch ( slapMode & SLAP_MODE ) { case SLAP_SERVER_MODE: Debug( LDAP_DEBUG_TRACE, "%s init: " "initiated server.\n", name ); lload_name = name; ldap_pvt_thread_pool_init_q( &connection_pool, connection_pool_max, 0, connection_pool_queues ); ldap_pvt_thread_mutex_init( &slapd_rq.rq_mutex ); LDAP_STAILQ_INIT( &slapd_rq.task_list ); LDAP_STAILQ_INIT( &slapd_rq.run_list ); rc = lload_global_init(); break; default: slap_debug |= LDAP_DEBUG_NONE; Debug( LDAP_DEBUG_ANY, "%s init: " "undefined mode (%d).\n", name, mode ); rc = 1; break; } return rc; } int lload_destroy( void ) { int rc = LDAP_SUCCESS; Debug( LDAP_DEBUG_TRACE, "%s destroy: " "freeing system resources.\n", lload_name ); ldap_pvt_thread_pool_free( &connection_pool ); switch ( slapMode & SLAP_MODE ) { case SLAP_SERVER_MODE: break; default: Debug( LDAP_DEBUG_ANY, "lload_destroy(): " "undefined mode (%d).\n", slapMode ); rc = 1; break; } ldap_pvt_thread_destroy(); /* should destroy the above mutex */ return rc; } openldap-2.5.11+dfsg/servers/lloadd/connection.c0000644000175000017500000004431514172327167020301 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ #include "portable.h" #include #ifdef HAVE_LIMITS_H #include #endif #include #include #include #include #include #include "lload.h" #include "lutil.h" #include "lutil_ldap.h" static unsigned long conn_nextid = 0; static void lload_connection_assign_nextid( LloadConnection *conn ) { conn->c_connid = __atomic_fetch_add( &conn_nextid, 1, __ATOMIC_RELAXED ); } /* * We start off with the connection muted and c_currentber holding the pdu we * received. * * We run c->c_pdu_cb for each pdu, stopping once we hit an error, have to wait * on reading or after we process lload_conn_max_pdus_per_cycle pdus so as to * maintain fairness and not hog the worker thread forever. * * If we've run out of pdus immediately available from the stream or hit the * budget, we unmute the connection. * * c->c_pdu_cb might return an 'error' and not free the connection. That can * happen when changing the state or when client is blocked on writing and * already has a pdu pending on the same operation, it's their job to make sure * we're woken up again. */ void * handle_pdus( void *ctx, void *arg ) { LloadConnection *c = arg; int pdus_handled = 0; epoch_t epoch; /* A reference was passed on to us */ assert( IS_ALIVE( c, c_refcnt ) ); epoch = epoch_join(); for ( ;; ) { BerElement *ber; ber_tag_t tag; ber_len_t len; if ( c->c_pdu_cb( c ) ) { /* Error/reset, get rid ouf our reference and bail */ goto done; } if ( !IS_ALIVE( c, c_live ) ) { break; } if ( ++pdus_handled >= lload_conn_max_pdus_per_cycle ) { /* Do not read now, re-enable read event instead */ break; } ber = c->c_currentber; if ( ber == NULL && (ber = ber_alloc()) == NULL ) { Debug( LDAP_DEBUG_ANY, "handle_pdus: " "connid=%lu, ber_alloc failed\n", c->c_connid ); CONNECTION_LOCK_DESTROY(c); goto done; } c->c_currentber = ber; checked_lock( &c->c_io_mutex ); if ( (lload_features & LLOAD_FEATURE_PAUSE) && (c->c_io_state & LLOAD_C_READ_PAUSE) ) { goto pause; } tag = ber_get_next( c->c_sb, &len, ber ); checked_unlock( &c->c_io_mutex ); if ( tag != LDAP_TAG_MESSAGE ) { int err = sock_errno(); if ( err != EWOULDBLOCK && err != EAGAIN ) { if ( err || tag == LBER_ERROR ) { char ebuf[128]; Debug( LDAP_DEBUG_ANY, "handle_pdus: " "ber_get_next on fd=%d failed errno=%d (%s)\n", c->c_fd, err, sock_errstr( err, ebuf, sizeof(ebuf) ) ); } else { Debug( LDAP_DEBUG_STATS, "handle_pdus: " "ber_get_next on fd=%d connid=%lu received " "a strange PDU tag=%lx\n", c->c_fd, c->c_connid, tag ); } c->c_currentber = NULL; ber_free( ber, 1 ); CONNECTION_LOCK_DESTROY(c); goto done; } break; } assert( IS_ALIVE( c, c_refcnt ) ); epoch_leave( epoch ); epoch = epoch_join(); assert( IS_ALIVE( c, c_refcnt ) ); } checked_lock( &c->c_io_mutex ); if ( !(lload_features & LLOAD_FEATURE_PAUSE) || !(c->c_io_state & LLOAD_C_READ_PAUSE) ) { event_add( c->c_read_event, c->c_read_timeout ); Debug( LDAP_DEBUG_CONNS, "handle_pdus: " "re-enabled read event on connid=%lu\n", c->c_connid ); } pause: c->c_io_state &= ~LLOAD_C_READ_HANDOVER; checked_unlock( &c->c_io_mutex ); done: RELEASE_REF( c, c_refcnt, c->c_destroy ); epoch_leave( epoch ); return NULL; } /* * Initial read on the connection, if we get an LDAP PDU, submit the * processing of this and successive ones to the work queue. * * If we can't submit it to the queue (overload), process this one and return * to the event loop immediately after. */ void connection_read_cb( evutil_socket_t s, short what, void *arg ) { LloadConnection *c = arg; BerElement *ber; ber_tag_t tag; ber_len_t len; epoch_t epoch; int pause; if ( !IS_ALIVE( c, c_live ) ) { event_del( c->c_read_event ); Debug( LDAP_DEBUG_CONNS, "connection_read_cb: " "suspended read event on a dead connid=%lu\n", c->c_connid ); return; } if ( what & EV_TIMEOUT ) { Debug( LDAP_DEBUG_CONNS, "connection_read_cb: " "connid=%lu, timeout reached, destroying\n", c->c_connid ); /* Make sure the connection stays around for us to unlock it */ epoch = epoch_join(); CONNECTION_LOCK_DESTROY(c); epoch_leave( epoch ); return; } if ( !acquire_ref( &c->c_refcnt ) ) { return; } epoch = epoch_join(); Debug( LDAP_DEBUG_CONNS, "connection_read_cb: " "connection connid=%lu ready to read\n", c->c_connid ); ber = c->c_currentber; if ( ber == NULL && (ber = ber_alloc()) == NULL ) { Debug( LDAP_DEBUG_ANY, "connection_read_cb: " "connid=%lu, ber_alloc failed\n", c->c_connid ); goto out; } c->c_currentber = ber; checked_lock( &c->c_io_mutex ); assert( !(c->c_io_state & LLOAD_C_READ_HANDOVER) ); tag = ber_get_next( c->c_sb, &len, ber ); pause = c->c_io_state & LLOAD_C_READ_PAUSE; checked_unlock( &c->c_io_mutex ); if ( tag != LDAP_TAG_MESSAGE ) { int err = sock_errno(); if ( err != EWOULDBLOCK && err != EAGAIN ) { if ( err || tag == LBER_ERROR ) { char ebuf[128]; Debug( LDAP_DEBUG_STATS, "connection_read_cb: " "ber_get_next on fd=%d failed errno=%d (%s)\n", c->c_fd, err, sock_errstr( err, ebuf, sizeof(ebuf) ) ); } else { Debug( LDAP_DEBUG_STATS, "connection_read_cb: " "ber_get_next on fd=%d connid=%lu received " "a strange PDU tag=%lx\n", c->c_fd, c->c_connid, tag ); } c->c_currentber = NULL; ber_free( ber, 1 ); event_del( c->c_read_event ); Debug( LDAP_DEBUG_CONNS, "connection_read_cb: " "suspended read event on dying connid=%lu\n", c->c_connid ); CONNECTION_LOCK_DESTROY(c); goto out; } if ( !(lload_features & LLOAD_FEATURE_PAUSE) || !pause ) { event_add( c->c_read_event, c->c_read_timeout ); Debug( LDAP_DEBUG_CONNS, "connection_read_cb: " "re-enabled read event on connid=%lu\n", c->c_connid ); } goto out; } checked_lock( &c->c_io_mutex ); c->c_io_state |= LLOAD_C_READ_HANDOVER; checked_unlock( &c->c_io_mutex ); event_del( c->c_read_event ); if ( !lload_conn_max_pdus_per_cycle || ldap_pvt_thread_pool_submit( &connection_pool, handle_pdus, c ) ) { /* If we're overloaded or configured as such, process one and resume in * the next cycle. */ int rc = c->c_pdu_cb( c ); checked_lock( &c->c_io_mutex ); c->c_io_state &= ~LLOAD_C_READ_HANDOVER; if ( rc == LDAP_SUCCESS && ( !(lload_features & LLOAD_FEATURE_PAUSE) || !(c->c_io_state & LLOAD_C_READ_PAUSE) ) ) { event_add( c->c_read_event, c->c_read_timeout ); } checked_unlock( &c->c_io_mutex ); goto out; } Debug( LDAP_DEBUG_CONNS, "connection_read_cb: " "suspended read event on connid=%lu\n", c->c_connid ); /* * We have scheduled a call to handle_pdus to take care of handling this * and further requests, its reference is now owned by that task. */ epoch_leave( epoch ); return; out: RELEASE_REF( c, c_refcnt, c->c_destroy ); epoch_leave( epoch ); } void connection_write_cb( evutil_socket_t s, short what, void *arg ) { LloadConnection *c = arg; epoch_t epoch; Debug( LDAP_DEBUG_CONNS, "connection_write_cb: " "considering writing to%s connid=%lu what=%hd\n", c->c_live ? " live" : " dead", c->c_connid, what ); if ( !IS_ALIVE( c, c_live ) ) { return; } if ( what & EV_TIMEOUT ) { Debug( LDAP_DEBUG_CONNS, "connection_write_cb: " "connid=%lu, timeout reached, destroying\n", c->c_connid ); /* Make sure the connection stays around for us to unlock it */ epoch = epoch_join(); CONNECTION_LOCK_DESTROY(c); epoch_leave( epoch ); return; } /* Before we acquire any locks */ event_del( c->c_write_event ); if ( !acquire_ref( &c->c_refcnt ) ) { return; } /* If what == 0, we have a caller as opposed to being a callback */ if ( what ) { epoch = epoch_join(); } checked_lock( &c->c_io_mutex ); Debug( LDAP_DEBUG_CONNS, "connection_write_cb: " "have something to write to connection connid=%lu\n", c->c_connid ); /* We might have been beaten to flushing the data by another thread */ if ( c->c_pendingber && ber_flush( c->c_sb, c->c_pendingber, 1 ) ) { int err = sock_errno(); if ( err != EWOULDBLOCK && err != EAGAIN ) { char ebuf[128]; checked_unlock( &c->c_io_mutex ); Debug( LDAP_DEBUG_ANY, "connection_write_cb: " "ber_flush on fd=%d failed errno=%d (%s)\n", c->c_fd, err, sock_errstr( err, ebuf, sizeof(ebuf) ) ); CONNECTION_LOCK_DESTROY(c); goto done; } if ( !(c->c_io_state & LLOAD_C_READ_PAUSE) ) { Debug( LDAP_DEBUG_CONNS, "connection_write_cb: " "connection connid=%lu blocked on writing, marking " "paused\n", c->c_connid ); } c->c_io_state |= LLOAD_C_READ_PAUSE; /* TODO: Do not reset write timeout unless we wrote something */ event_add( c->c_write_event, lload_write_timeout ); } else { c->c_pendingber = NULL; if ( c->c_io_state & LLOAD_C_READ_PAUSE ) { c->c_io_state ^= LLOAD_C_READ_PAUSE; Debug( LDAP_DEBUG_CONNS, "connection_write_cb: " "Unpausing connection connid=%lu\n", c->c_connid ); if ( !(c->c_io_state & LLOAD_C_READ_HANDOVER) ) { event_add( c->c_read_event, c->c_read_timeout ); } } } checked_unlock( &c->c_io_mutex ); done: RELEASE_REF( c, c_refcnt, c->c_destroy ); if ( what ) { epoch_leave( epoch ); } } void connection_destroy( LloadConnection *c ) { assert( c ); Debug( LDAP_DEBUG_CONNS, "connection_destroy: " "destroying connection connid=%lu\n", c->c_connid ); CONNECTION_ASSERT_LOCKED(c); assert( c->c_live == 0 ); assert( c->c_refcnt == 0 ); assert( c->c_state == LLOAD_C_INVALID ); ber_sockbuf_free( c->c_sb ); if ( c->c_currentber ) { ber_free( c->c_currentber, 1 ); c->c_currentber = NULL; } if ( c->c_pendingber ) { ber_free( c->c_pendingber, 1 ); c->c_pendingber = NULL; } if ( !BER_BVISNULL( &c->c_sasl_bind_mech ) ) { ber_memfree( c->c_sasl_bind_mech.bv_val ); BER_BVZERO( &c->c_sasl_bind_mech ); } #ifdef HAVE_CYRUS_SASL if ( c->c_sasl_defaults ) { lutil_sasl_freedefs( c->c_sasl_defaults ); c->c_sasl_defaults = NULL; } if ( c->c_sasl_authctx ) { #ifdef SASL_CHANNEL_BINDING /* 2.1.25+ */ if ( c->c_sasl_cbinding ) { ch_free( c->c_sasl_cbinding ); } #endif sasl_dispose( &c->c_sasl_authctx ); } #endif /* HAVE_CYRUS_SASL */ CONNECTION_UNLOCK(c); ldap_pvt_thread_mutex_destroy( &c->c_io_mutex ); ldap_pvt_thread_mutex_destroy( &c->c_mutex ); ch_free( c ); listeners_reactivate(); } /* * Called holding mutex, will walk cq calling cb on all connections whose * c_connid <= cq_last->c_connid that still exist at the time we get to them. */ void connections_walk_last( ldap_pvt_thread_mutex_t *cq_mutex, lload_c_head *cq, LloadConnection *cq_last, CONNCB cb, void *arg ) { LloadConnection *c = cq_last; uintptr_t last_connid; if ( LDAP_CIRCLEQ_EMPTY( cq ) ) { return; } assert_locked( cq_mutex ); last_connid = c->c_connid; c = LDAP_CIRCLEQ_LOOP_NEXT( cq, c, c_next ); while ( !acquire_ref( &c->c_refcnt ) ) { c = LDAP_CIRCLEQ_LOOP_NEXT( cq, c, c_next ); if ( c->c_connid >= last_connid ) { assert_locked( cq_mutex ); return; } } /* * Notes: * - we maintain the connections in the cq CIRCLEQ_ in ascending c_connid * order * - the connection with the highest c_connid is passed in cq_last * - we can only use cq when we hold cq_mutex * - connections might be added to or removed from cq while we're busy * processing connections * - we need a way to detect we've finished looping around cq for some * definition of looping around */ do { int rc; checked_unlock( cq_mutex ); rc = cb( c, arg ); RELEASE_REF( c, c_refcnt, c->c_destroy ); checked_lock( cq_mutex ); if ( rc || LDAP_CIRCLEQ_EMPTY( cq ) ) { break; } do { LloadConnection *old = c; c = LDAP_CIRCLEQ_LOOP_NEXT( cq, c, c_next ); if ( c->c_connid <= old->c_connid || c->c_connid > last_connid ) { assert_locked( cq_mutex ); return; } } while ( !acquire_ref( &c->c_refcnt ) ); } while ( c->c_connid <= last_connid ); assert_locked( cq_mutex ); } void connections_walk( ldap_pvt_thread_mutex_t *cq_mutex, lload_c_head *cq, CONNCB cb, void *arg ) { LloadConnection *cq_last = LDAP_CIRCLEQ_LAST( cq ); return connections_walk_last( cq_mutex, cq, cq_last, cb, arg ); } int lload_connection_close( LloadConnection *c, void *arg ) { int gentle = *(int *)arg; LloadOperation *op; Debug( LDAP_DEBUG_CONNS, "lload_connection_close: " "marking connection connid=%lu closing\n", c->c_connid ); /* We were approached from the connection list */ assert( IS_ALIVE( c, c_refcnt ) ); CONNECTION_LOCK(c); if ( !gentle || !c->c_ops ) { CONNECTION_DESTROY(c); return LDAP_SUCCESS; } /* The first thing we do is make sure we don't get new Operations in */ c->c_state = LLOAD_C_CLOSING; do { TAvlnode *node = ldap_tavl_end( c->c_ops, TAVL_DIR_LEFT ); op = node->avl_data; /* Close operations that would need client action to resolve, * only SASL binds in progress do that right now */ if ( op->o_client_msgid || op->o_upstream_msgid ) { break; } CONNECTION_UNLOCK(c); operation_unlink( op ); CONNECTION_LOCK(c); } while ( c->c_ops ); CONNECTION_UNLOCK(c); return LDAP_SUCCESS; } LloadConnection * lload_connection_init( ber_socket_t s, const char *peername, int flags ) { LloadConnection *c; assert( peername != NULL ); if ( s == AC_SOCKET_INVALID ) { Debug( LDAP_DEBUG_ANY, "lload_connection_init: " "init of socket fd=%ld invalid\n", (long)s ); return NULL; } assert( s >= 0 ); c = ch_calloc( 1, sizeof(LloadConnection) ); c->c_fd = s; c->c_sb = ber_sockbuf_alloc(); ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_FD, &s ); #ifdef LDAP_PF_LOCAL if ( flags & CONN_IS_IPC ) { #ifdef LDAP_DEBUG ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_PROVIDER, (void *)"ipc_" ); #endif ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_fd, LBER_SBIOD_LEVEL_PROVIDER, (void *)&s ); } else #endif /* LDAP_PF_LOCAL */ { #ifdef LDAP_DEBUG ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_PROVIDER, (void *)"tcp_" ); #endif ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_tcp, LBER_SBIOD_LEVEL_PROVIDER, (void *)&s ); } #ifdef LDAP_DEBUG ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug, INT_MAX, (void *)"lload_" ); #endif c->c_next_msgid = 1; c->c_refcnt = c->c_live = 1; c->c_destroy = connection_destroy; LDAP_CIRCLEQ_ENTRY_INIT( c, c_next ); ldap_pvt_thread_mutex_init( &c->c_mutex ); ldap_pvt_thread_mutex_init( &c->c_io_mutex ); lload_connection_assign_nextid( c ); Debug( LDAP_DEBUG_CONNS, "lload_connection_init: " "connection connid=%lu allocated for socket fd=%d peername=%s\n", c->c_connid, s, peername ); c->c_state = LLOAD_C_ACTIVE; return c; } openldap-2.5.11+dfsg/servers/lloadd/config.c0000644000175000017500000033344114172327167017410 0ustar ryanryan/* config.c - configuration file handling routines */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ #include "portable.h" #include #include #include #include #include #include #include #include #include #ifndef S_ISREG #define S_ISREG(m) ( ((m) & _S_IFMT ) == _S_IFREG ) #endif #include "lload.h" #include "lutil.h" #include "lutil_ldap.h" #include "lload-config.h" #ifdef _WIN32 #define LUTIL_ATOULX lutil_atoullx #define Z "I" #else #define LUTIL_ATOULX lutil_atoulx #define Z "z" #endif #define ARGS_STEP 512 /* * defaults for various global variables */ #ifdef BALANCER_MODULE char *listeners_list = NULL; #else /* !BALANCER_MODULE */ slap_mask_t global_allows = 0; slap_mask_t global_disallows = 0; int global_gentlehup = 0; int global_idletimeout = 0; char *global_host = NULL; char *slapd_pid_file = NULL; char *slapd_args_file = NULL; #endif /* !BALANCER_MODULE */ static FILE *logfile; static char *logfileName; static struct timeval timeout_api_tv, timeout_net_tv, timeout_write_tv = { 10, 0 }; lload_features_t lload_features; ber_len_t sockbuf_max_incoming_client = LLOAD_SB_MAX_INCOMING_CLIENT; ber_len_t sockbuf_max_incoming_upstream = LLOAD_SB_MAX_INCOMING_UPSTREAM; int lload_conn_max_pdus_per_cycle = LLOAD_CONN_MAX_PDUS_PER_CYCLE_DEFAULT; struct timeval *lload_timeout_api = NULL; struct timeval *lload_timeout_net = NULL; struct timeval *lload_write_timeout = &timeout_write_tv; static slap_verbmasks tlskey[]; static int fp_getline( FILE *fp, ConfigArgs *c ); static void fp_getline_init( ConfigArgs *c ); static char *strtok_quote( char *line, char *sep, char **quote_ptr, int *inquote ); typedef struct ConfigFile { struct ConfigFile *c_sibs; struct ConfigFile *c_kids; struct berval c_file; BerVarray c_dseFiles; } ConfigFile; static ConfigFile *cfn; static ConfigDriver config_fname; static ConfigDriver config_generic; static ConfigDriver config_backend; static ConfigDriver config_bindconf; #ifdef LDAP_TCP_BUFFER static ConfigDriver config_tcp_buffer; #endif /* LDAP_TCP_BUFFER */ static ConfigDriver config_restrict; static ConfigDriver config_loglevel; static ConfigDriver config_include; static ConfigDriver config_feature; #ifdef HAVE_TLS static ConfigDriver config_tls_option; static ConfigDriver config_tls_config; #endif #ifdef BALANCER_MODULE static ConfigDriver config_share_tls_ctx; static ConfigDriver backend_cf_gen; #endif /* BALANCER_MODULE */ lload_b_head backend = LDAP_CIRCLEQ_HEAD_INITIALIZER(backend); ldap_pvt_thread_mutex_t backend_mutex; LloadBackend *current_backend = NULL; struct slap_bindconf bindconf = {}; struct berval lloadd_identity = BER_BVNULL; enum { CFG_ACL = 1, CFG_BACKEND, CFG_BINDCONF, CFG_LISTEN, CFG_LISTEN_URI, CFG_TLS_RAND, CFG_TLS_CIPHER, CFG_TLS_PROTOCOL_MIN, CFG_TLS_CERT_FILE, CFG_TLS_CERT_KEY, CFG_TLS_CA_PATH, CFG_TLS_CA_FILE, CFG_TLS_DH_FILE, CFG_TLS_VERIFY, CFG_TLS_CRLCHECK, CFG_TLS_CRL_FILE, CFG_TLS_SHARE_CTX, CFG_CONCUR, CFG_THREADS, CFG_LOGFILE, CFG_MIRRORMODE, CFG_IOTHREADS, CFG_MAXBUF_CLIENT, CFG_MAXBUF_UPSTREAM, CFG_FEATURE, CFG_THREADQS, CFG_TLS_ECNAME, CFG_TLS_CACERT, CFG_TLS_CERT, CFG_TLS_KEY, CFG_RESCOUNT, CFG_IOTIMEOUT, CFG_URI, CFG_NUMCONNS, CFG_BINDCONNS, CFG_RETRY, CFG_MAX_PENDING_OPS, CFG_MAX_PENDING_CONNS, CFG_STARTTLS, CFG_CLIENT_PENDING, CFG_LAST }; /* alphabetical ordering */ static ConfigTable config_back_cf_table[] = { /* This attr is read-only */ { "", "", 0, 0, 0, ARG_MAGIC, &config_fname, NULL, NULL, NULL }, { "argsfile", "file", 2, 2, 0, ARG_STRING, &slapd_args_file, NULL, NULL, NULL }, { "concurrency", "level", 2, 2, 0, ARG_UINT|ARG_MAGIC|CFG_CONCUR, &config_generic, NULL, NULL, NULL }, /* conf-file only option */ { "backend-server", "backend options", 2, 0, 0, ARG_MAGIC|CFG_BACKEND, &config_backend, NULL, NULL, NULL }, { "bindconf", "backend credentials", 2, 0, 0, ARG_MAGIC|CFG_BINDCONF, &config_bindconf, "( OLcfgBkAt:13.2 " "NAME 'olcBkLloadBindconf' " "DESC 'Backend credentials' " /* No EQUALITY since this is a compound attribute (and needs * splitting up anyway - which is a TODO) */ "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, { "gentlehup", "on|off", 2, 2, 0, #ifdef SIGHUP ARG_ON_OFF, &global_gentlehup, #else ARG_IGNORED, NULL, #endif NULL, NULL, NULL }, { "idletimeout", "timeout", 2, 2, 0, ARG_UINT, &global_idletimeout, "( OLcfgBkAt:13.3 " "NAME 'olcBkLloadIdleTimeout' " "DESC 'Connection idle timeout' " "EQUALITY integerMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", NULL, NULL }, { "include", "file", 2, 2, 0, ARG_MAGIC, &config_include, NULL, NULL, NULL }, { "io-threads", "count", 2, 0, 0, ARG_UINT|ARG_MAGIC|CFG_IOTHREADS, &config_generic, "( OLcfgBkAt:13.4 " "NAME 'olcBkLloadIOThreads' " "DESC 'I/O thread count' " "EQUALITY integerMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", NULL, NULL }, #ifdef BALANCER_MODULE { "listen", "uri list", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_LISTEN, &config_generic, NULL, NULL, NULL }, { "", "uri", 2, 2, 0, ARG_MAGIC|CFG_LISTEN_URI, &config_generic, "( OLcfgBkAt:13.5 " "NAME 'olcBkLloadListen' " "DESC 'A listener adress' " /* We don't handle adding/removing a value, so no EQUALITY yet */ "SYNTAX OMsDirectoryString )", NULL, NULL }, #endif /* BALANCER_MODULE */ { "logfile", "file", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_LOGFILE, &config_generic, NULL, NULL, NULL }, { "loglevel", "level", 2, 0, 0, ARG_MAGIC, &config_loglevel, NULL, NULL, NULL }, { "pidfile", "file", 2, 2, 0, ARG_STRING, &slapd_pid_file, NULL, NULL, NULL }, { "restrict", "op_list", 2, 0, 0, ARG_MAGIC, &config_restrict, NULL, NULL, NULL }, { "sockbuf_max_incoming_client", "max", 2, 2, 0, ARG_BER_LEN_T|ARG_MAGIC|CFG_MAXBUF_CLIENT, &config_generic, "( OLcfgBkAt:13.6 " "NAME 'olcBkLloadSockbufMaxClient' " "DESC 'The maximum LDAP PDU size accepted coming from clients' " "EQUALITY integerMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", NULL, { .v_ber_t = LLOAD_SB_MAX_INCOMING_CLIENT } }, { "sockbuf_max_incoming_upstream", "max", 2, 2, 0, ARG_BER_LEN_T|ARG_MAGIC|CFG_MAXBUF_UPSTREAM, &config_generic, "( OLcfgBkAt:13.7 " "NAME 'olcBkLloadSockbufMaxUpstream' " "DESC 'The maximum LDAP PDU size accepted coming from upstream' " "EQUALITY integerMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", NULL, { .v_ber_t = LLOAD_SB_MAX_INCOMING_UPSTREAM } }, { "tcp-buffer", "[listener=] [{read|write}=]size", 0, 0, 0, #ifdef LDAP_TCP_BUFFER ARG_MAGIC, &config_tcp_buffer, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.8 " "NAME 'olcBkLloadTcpBuffer' " "DESC 'TCP Buffer size' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, { "threads", "count", 2, 2, 0, ARG_UINT|ARG_MAGIC|CFG_THREADS, &config_generic, NULL, NULL, NULL }, { "threadqueues", "count", 2, 2, 0, ARG_UINT|ARG_MAGIC|CFG_THREADQS, &config_generic, NULL, NULL, NULL }, { "max_pdus_per_cycle", "count", 2, 2, 0, ARG_UINT|ARG_MAGIC|CFG_RESCOUNT, &config_generic, "( OLcfgBkAt:13.9 " "NAME 'olcBkLloadMaxPDUPerCycle' " "DESC 'Maximum number of PDUs to handle in a single cycle' " "EQUALITY integerMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", NULL, NULL }, { "feature", "name", 2, 0, 0, ARG_MAGIC|CFG_FEATURE, &config_feature, "( OLcfgBkAt:13.10 " "NAME 'olcBkLloadFeature' " "DESC 'Lload features enabled' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString )", NULL, NULL }, { "TLSCACertificate", NULL, 2, 2, 0, #ifdef HAVE_TLS CFG_TLS_CACERT|ARG_BINARY|ARG_MAGIC, &config_tls_option, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.11 " "NAME 'olcBkLloadTLSCACertificate' " "DESC 'X.509 certificate, must use ;binary' " "EQUALITY certificateExactMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 " "SINGLE-VALUE )", NULL, NULL }, { "TLSCACertificateFile", NULL, 2, 2, 0, #ifdef HAVE_TLS CFG_TLS_CA_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.12 " "NAME 'olcBkLloadTLSCACertificateFile' " "EQUALITY caseExactMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, { "TLSCACertificatePath", NULL, 2, 2, 0, #ifdef HAVE_TLS CFG_TLS_CA_PATH|ARG_STRING|ARG_MAGIC, &config_tls_option, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.13 " "NAME 'olcBkLloadTLSCACertificatePath' " "EQUALITY caseExactMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, { "TLSCertificate", NULL, 2, 2, 0, #ifdef HAVE_TLS CFG_TLS_CERT|ARG_BINARY|ARG_MAGIC, &config_tls_option, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.14 " "NAME 'olcBkLloadTLSCertificate' " "DESC 'X.509 certificate, must use ;binary' " "EQUALITY certificateExactMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 " "SINGLE-VALUE )", NULL, NULL }, { "TLSCertificateFile", NULL, 2, 2, 0, #ifdef HAVE_TLS CFG_TLS_CERT_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.15 " "NAME 'olcBkLloadTLSCertificateFile' " "EQUALITY caseExactMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, { "TLSCertificateKey", NULL, 2, 2, 0, #ifdef HAVE_TLS CFG_TLS_KEY|ARG_BINARY|ARG_MAGIC, &config_tls_option, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.16 " "NAME 'olcBkLloadTLSCertificateKey' " "DESC 'X.509 privateKey, must use ;binary' " "EQUALITY privateKeyMatch " "SYNTAX 1.2.840.113549.1.8.1.1 " "SINGLE-VALUE )", NULL, NULL }, { "TLSCertificateKeyFile", NULL, 2, 2, 0, #ifdef HAVE_TLS CFG_TLS_CERT_KEY|ARG_STRING|ARG_MAGIC, &config_tls_option, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.17 " "NAME 'olcBkLloadTLSCertificateKeyFile' " "EQUALITY caseExactMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, { "TLSCipherSuite", NULL, 2, 2, 0, #ifdef HAVE_TLS CFG_TLS_CIPHER|ARG_STRING|ARG_MAGIC, &config_tls_option, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.18 " "NAME 'olcBkLloadTLSCipherSuite' " "EQUALITY caseExactMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, { "TLSCRLCheck", NULL, 2, 2, 0, #if defined(HAVE_TLS) && defined(HAVE_OPENSSL) CFG_TLS_CRLCHECK|ARG_STRING|ARG_MAGIC, &config_tls_config, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.19 " "NAME 'olcBkLloadTLSCRLCheck' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, { "TLSCRLFile", NULL, 2, 2, 0, #if defined(HAVE_GNUTLS) CFG_TLS_CRL_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.20 " "NAME 'olcBkLloadTLSCRLFile' " "EQUALITY caseExactMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, { "TLSRandFile", NULL, 2, 2, 0, #ifdef HAVE_TLS CFG_TLS_RAND|ARG_STRING|ARG_MAGIC, &config_tls_option, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.21 " "NAME 'olcBkLloadTLSRandFile' " "EQUALITY caseExactMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, { "TLSVerifyClient", NULL, 2, 2, 0, #ifdef HAVE_TLS CFG_TLS_VERIFY|ARG_STRING|ARG_MAGIC, &config_tls_config, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.22 " "NAME 'olcBkLloadVerifyClient' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, { "TLSDHParamFile", NULL, 2, 2, 0, #ifdef HAVE_TLS CFG_TLS_DH_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.23 " "NAME 'olcBkLloadTLSDHParamFile' " "EQUALITY caseExactMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, { "TLSECName", NULL, 2, 2, 0, #ifdef HAVE_TLS CFG_TLS_ECNAME|ARG_STRING|ARG_MAGIC, &config_tls_option, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.24 " "NAME 'olcBkLloadTLSECName' " "EQUALITY caseExactMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, { "TLSProtocolMin", NULL, 2, 2, 0, #ifdef HAVE_TLS CFG_TLS_PROTOCOL_MIN|ARG_STRING|ARG_MAGIC, &config_tls_config, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.25 " "NAME 'olcBkLloadTLSProtocolMin' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, { "TLSShareSlapdCTX", NULL, 2, 2, 0, #if defined(HAVE_TLS) && defined(BALANCER_MODULE) CFG_TLS_SHARE_CTX|ARG_ON_OFF|ARG_MAGIC, &config_share_tls_ctx, #else ARG_IGNORED, NULL, #endif "( OLcfgBkAt:13.33 " "NAME 'olcBkLloadTLSShareSlapdCTX' " "DESC 'Share slapd TLS context (all other lloadd TLS options cease to take effect)' " "EQUALITY booleanMatch " "SYNTAX OMsBoolean " "SINGLE-VALUE )", NULL, NULL }, { "iotimeout", "ms timeout", 2, 2, 0, ARG_UINT|ARG_MAGIC|CFG_IOTIMEOUT, &config_generic, "( OLcfgBkAt:13.26 " "NAME 'olcBkLloadIOTimeout' " "DESC 'I/O timeout threshold in miliseconds' " "EQUALITY integerMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", NULL, NULL }, { "client_max_pending", NULL, 2, 2, 0, ARG_MAGIC|ARG_UINT|CFG_CLIENT_PENDING, &config_generic, "( OLcfgBkAt:13.35 " "NAME 'olcBkLloadClientMaxPending' " "DESC 'Maximum pending operations per client connection' " "EQUALITY integerMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", NULL, { .v_uint = 0 } }, /* cn=config only options */ #ifdef BALANCER_MODULE { "", "uri", 2, 2, 0, ARG_BERVAL|ARG_MAGIC|CFG_URI, &backend_cf_gen, "( OLcfgBkAt:13.27 " "NAME 'olcBkLloadBackendUri' " "DESC 'URI to contact the server on' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, { "", NULL, 2, 2, 0, ARG_UINT|ARG_MAGIC|CFG_NUMCONNS, &backend_cf_gen, "( OLcfgBkAt:13.28 " "NAME 'olcBkLloadNumconns' " "DESC 'Number of regular connections to maintain' " "EQUALITY integerMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", NULL, NULL }, { "", NULL, 2, 2, 0, ARG_UINT|ARG_MAGIC|CFG_BINDCONNS, &backend_cf_gen, "( OLcfgBkAt:13.29 " "NAME 'olcBkLloadBindconns' " "DESC 'Number of bind connections to maintain' " "EQUALITY integerMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", NULL, NULL }, { "", NULL, 2, 2, 0, ARG_UINT|ARG_MAGIC|CFG_RETRY, &backend_cf_gen, "( OLcfgBkAt:13.30 " "NAME 'olcBkLloadRetry' " "DESC 'Number of seconds to wait before trying to reconnect' " "EQUALITY integerMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", NULL, NULL }, { "", NULL, 2, 2, 0, ARG_UINT|ARG_MAGIC|CFG_MAX_PENDING_OPS, &backend_cf_gen, "( OLcfgBkAt:13.31 " "NAME 'olcBkLloadMaxPendingOps' " "DESC 'Maximum number of pending operations for this backend' " "EQUALITY integerMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", NULL, NULL }, { "", NULL, 2, 2, 0, ARG_UINT|ARG_MAGIC|CFG_MAX_PENDING_CONNS, &backend_cf_gen, "( OLcfgBkAt:13.32 " "NAME 'olcBkLloadMaxPendingConns' " "DESC 'Maximum number of pending operations on each connection' " "EQUALITY integerMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", NULL, NULL }, { "", NULL, 2, 2, 0, ARG_BERVAL|ARG_MAGIC|CFG_STARTTLS, &backend_cf_gen, "( OLcfgBkAt:13.34 " "NAME 'olcBkLloadStartTLS' " "DESC 'Whether StartTLS should be attempted on the connection' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, #endif /* BALANCER_MODULE */ { NULL, NULL, 0, 0, 0, ARG_IGNORED, NULL } }; #ifdef BALANCER_MODULE static ConfigCfAdd lload_cfadd; static ConfigLDAPadd lload_backend_ldadd; #ifdef SLAP_CONFIG_DELETE static ConfigLDAPdel lload_backend_lddel; #endif /* SLAP_CONFIG_DELETE */ static ConfigOCs lloadocs[] = { { "( OLcfgBkOc:13.1 " "NAME 'olcBkLloadConfig' " "DESC 'Lload backend configuration' " "SUP olcBackendConfig " "MUST ( olcBkLloadBindconf " "$ olcBkLloadIOThreads " "$ olcBkLloadListen " "$ olcBkLloadSockbufMaxClient " "$ olcBkLloadSockbufMaxUpstream " "$ olcBkLloadMaxPDUPerCycle " "$ olcBkLloadIOTimeout ) " "MAY ( olcBkLloadFeature " "$ olcBkLloadTcpBuffer " "$ olcBkLloadTLSCACertificateFile " "$ olcBkLloadTLSCACertificatePath " "$ olcBkLloadTLSCertificateFile " "$ olcBkLloadTLSCertificateKeyFile " "$ olcBkLloadTLSCipherSuite " "$ olcBkLloadTLSCRLCheck " "$ olcBkLloadTLSRandFile " "$ olcBkLloadVerifyClient " "$ olcBkLloadTLSDHParamFile " "$ olcBkLloadTLSECName " "$ olcBkLloadTLSProtocolMin " "$ olcBkLloadTLSCRLFile " "$ olcBkLloadTLSShareSlapdCTX " "$ olcBkLloadClientMaxPending " ") )", Cft_Backend, config_back_cf_table, NULL, lload_cfadd, }, { "( OLcfgBkOc:13.2 " "NAME 'olcBkLloadBackendConfig' " "DESC 'Lload backend server configuration' " "SUP olcConfig STRUCTURAL " "MUST ( cn " "$ olcBkLloadBackendUri " "$ olcBkLloadNumconns " "$ olcBkLloadBindconns " "$ olcBkLloadRetry " "$ olcBkLloadMaxPendingOps " "$ olcBkLloadMaxPendingConns ) " "MAY ( olcBkLloadStartTLS " ") )", Cft_Misc, config_back_cf_table, lload_backend_ldadd, NULL, #ifdef SLAP_CONFIG_DELETE lload_backend_lddel, #endif /* SLAP_CONFIG_DELETE */ }, { NULL, 0, NULL } }; #endif /* BALANCER_MODULE */ static int config_generic( ConfigArgs *c ) { enum lcf_daemon flag = 0; int rc = LDAP_SUCCESS; if ( c->op == SLAP_CONFIG_EMIT ) { switch ( c->type ) { case CFG_IOTHREADS: c->value_uint = lload_daemon_threads; break; case CFG_LISTEN_URI: { LloadListener **ll = lloadd_get_listeners(); struct berval bv = BER_BVNULL; for ( ; ll && *ll; ll++ ) { /* The same url could have spawned several consecutive * listeners */ if ( !BER_BVISNULL( &bv ) && !ber_bvcmp( &bv, &(*ll)->sl_url ) ) { continue; } ber_dupbv( &bv, &(*ll)->sl_url ); ber_bvarray_add( &c->rvalue_vals, &bv ); } } break; case CFG_MAXBUF_CLIENT: c->value_uint = sockbuf_max_incoming_client; break; case CFG_MAXBUF_UPSTREAM: c->value_uint = sockbuf_max_incoming_upstream; break; case CFG_RESCOUNT: c->value_uint = lload_conn_max_pdus_per_cycle; break; case CFG_IOTIMEOUT: c->value_uint = 1000 * lload_write_timeout->tv_sec + lload_write_timeout->tv_usec / 1000; break; case CFG_CLIENT_PENDING: c->value_uint = lload_client_max_pending; break; default: rc = 1; break; } return rc; } else if ( c->op == LDAP_MOD_DELETE ) { /* We only need to worry about deletions to multi-value or MAY * attributes that belong to the lloadd module - we don't have any at * the moment */ return rc; } lload_change.type = LLOAD_CHANGE_MODIFY; lload_change.object = LLOAD_DAEMON; switch ( c->type ) { case CFG_CONCUR: ldap_pvt_thread_set_concurrency( c->value_uint ); break; case CFG_LISTEN: if ( lloadd_inited ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "listen directive can only be specified once" ); ch_free( c->value_string ); return 1; } if ( lloadd_listeners_init( c->value_string ) ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "could not open one of the listener sockets: %s", c->value_string ); ch_free( c->value_string ); return 1; } ch_free( c->value_string ); break; case CFG_LISTEN_URI: { LDAPURLDesc *lud; LloadListener *l; if ( ldap_url_parse_ext( c->line, &lud, LDAP_PVT_URL_PARSE_DEF_PORT ) ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "string %s could not be parsed as an LDAP URL", c->line ); goto fail; } /* A sanity check, although it will not catch everything */ if ( ( l = lload_config_check_my_url( c->line, lud ) ) ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "Load Balancer already configured to listen on %s " "(while adding %s)", l->sl_url.bv_val, c->line ); goto fail; } if ( !lloadd_inited ) { if ( lload_open_new_listener( c->line, lud ) ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "could not open a listener for %s", c->line ); goto fail; } } else { snprintf( c->cr_msg, sizeof(c->cr_msg), "listener changes will not take effect until restart: " "%s", c->line ); Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg ); } } break; case CFG_THREADS: if ( c->value_uint < 2 ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "threads=%d smaller than minimum value 2", c->value_uint ); goto fail; } else if ( c->value_uint > 2 * SLAP_MAX_WORKER_THREADS ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "warning, threads=%d larger than twice the default " "(2*%d=%d); YMMV", c->value_uint, SLAP_MAX_WORKER_THREADS, 2 * SLAP_MAX_WORKER_THREADS ); Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg ); } if ( slapMode & SLAP_SERVER_MODE ) ldap_pvt_thread_pool_maxthreads( &connection_pool, c->value_uint ); connection_pool_max = c->value_uint; /* save for reference */ break; case CFG_THREADQS: if ( c->value_uint < 1 ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "threadqueues=%d smaller than minimum value 1", c->value_uint ); goto fail; } if ( slapMode & SLAP_SERVER_MODE ) ldap_pvt_thread_pool_queues( &connection_pool, c->value_uint ); connection_pool_queues = c->value_uint; /* save for reference */ break; case CFG_IOTHREADS: { int mask = 0; /* use a power of two */ while ( c->value_uint > 1 ) { c->value_uint >>= 1; mask <<= 1; mask |= 1; } if ( !lloadd_inited ) { lload_daemon_mask = mask; lload_daemon_threads = mask + 1; flag = LLOAD_DAEMON_MOD_THREADS; } else { snprintf( c->cr_msg, sizeof(c->cr_msg), "io thread changes will not take effect until " "restart" ); Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg ); } } break; case CFG_LOGFILE: { if ( logfileName ) ch_free( logfileName ); logfileName = c->value_string; logfile = fopen( logfileName, "w" ); if ( logfile ) lutil_debug_file( logfile ); } break; case CFG_RESCOUNT: lload_conn_max_pdus_per_cycle = c->value_uint; break; case CFG_IOTIMEOUT: if ( c->value_uint > 0 ) { timeout_write_tv.tv_sec = c->value_uint / 1000; timeout_write_tv.tv_usec = 1000 * ( c->value_uint % 1000 ); lload_write_timeout = &timeout_write_tv; } else { lload_write_timeout = NULL; } break; case CFG_MAXBUF_CLIENT: sockbuf_max_incoming_client = c->value_uint; break; case CFG_MAXBUF_UPSTREAM: sockbuf_max_incoming_upstream = c->value_uint; break; case CFG_CLIENT_PENDING: lload_client_max_pending = c->value_uint; break; default: Debug( LDAP_DEBUG_ANY, "%s: unknown CFG_TYPE %d\n", c->log, c->type ); return 1; } lload_change.flags.daemon |= flag; return 0; fail: if ( lload_change.type == LLOAD_CHANGE_ADD ) { /* Abort the ADD */ lload_change.type = LLOAD_CHANGE_DEL; } Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg ); return 1; } static int lload_backend_finish( ConfigArgs *ca ) { LloadBackend *b = ca->ca_private; if ( ca->reply.err != LDAP_SUCCESS ) { /* Not reached since cleanup is only called on success */ goto fail; } if ( b->b_numconns <= 0 || b->b_numbindconns <= 0 ) { Debug( LDAP_DEBUG_ANY, "lload_backend_finish: " "invalid connection pool configuration\n" ); goto fail; } if ( b->b_retry_timeout < 0 ) { Debug( LDAP_DEBUG_ANY, "lload_backend_finish: " "invalid retry timeout configuration\n" ); goto fail; } b->b_retry_tv.tv_sec = b->b_retry_timeout / 1000; b->b_retry_tv.tv_usec = ( b->b_retry_timeout % 1000 ) * 1000; /* daemon_base is only allocated after initial configuration happens, those * events are allocated on startup, we only deal with online Adds */ if ( !b->b_retry_event && daemon_base ) { struct event *event; assert( CONFIG_ONLINE_ADD( ca ) ); event = evtimer_new( daemon_base, backend_connect, b ); if ( !event ) { Debug( LDAP_DEBUG_ANY, "lload_backend_finish: " "failed to allocate retry event\n" ); goto fail; } b->b_retry_event = event; } return LDAP_SUCCESS; fail: if ( lload_change.type == LLOAD_CHANGE_ADD ) { /* Abort the ADD */ lload_change.type = LLOAD_CHANGE_DEL; } lload_backend_destroy( b ); return -1; } static LloadBackend * backend_alloc( void ) { LloadBackend *b; b = ch_calloc( 1, sizeof(LloadBackend) ); LDAP_CIRCLEQ_INIT( &b->b_conns ); LDAP_CIRCLEQ_INIT( &b->b_bindconns ); LDAP_CIRCLEQ_INIT( &b->b_preparing ); b->b_numconns = 1; b->b_numbindconns = 1; b->b_retry_timeout = 5000; ldap_pvt_thread_mutex_init( &b->b_mutex ); LDAP_CIRCLEQ_INSERT_TAIL( &backend, b, b_next ); return b; } static int backend_config_url( LloadBackend *b, struct berval *uri ) { LDAPURLDesc *lud = NULL; char *host = NULL; int rc, proto, tls = b->b_tls_conf; /* Effect no changes until we've checked everything */ rc = ldap_url_parse_ext( uri->bv_val, &lud, LDAP_PVT_URL_PARSE_DEF_PORT ); if ( rc != LDAP_URL_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "backend_config_url: " "listen URL \"%s\" parse error=%d\n", uri->bv_val, rc ); return -1; } if ( ldap_pvt_url_scheme2tls( lud->lud_scheme ) ) { #ifdef HAVE_TLS /* Specifying ldaps:// overrides starttls= settings */ tls = LLOAD_LDAPS; #else /* ! HAVE_TLS */ Debug( LDAP_DEBUG_ANY, "backend_config_url: " "TLS not supported (%s)\n", uri->bv_val ); rc = -1; goto done; #endif /* ! HAVE_TLS */ } proto = ldap_pvt_url_scheme2proto( lud->lud_scheme ); if ( proto == LDAP_PROTO_IPC ) { #ifdef LDAP_PF_LOCAL if ( lud->lud_host == NULL || lud->lud_host[0] == '\0' ) { host = LDAPI_SOCK; } #else /* ! LDAP_PF_LOCAL */ Debug( LDAP_DEBUG_ANY, "backend_config_url: " "URL scheme not supported: %s", url ); rc = -1; goto done; #endif /* ! LDAP_PF_LOCAL */ } else { if ( lud->lud_host == NULL || lud->lud_host[0] == '\0' ) { Debug( LDAP_DEBUG_ANY, "backend_config_url: " "backend url missing hostname: '%s'\n", uri->bv_val ); rc = -1; goto done; } } if ( !host ) { host = lud->lud_host; } if ( b->b_host ) { ch_free( b->b_host ); } b->b_proto = proto; b->b_tls = tls; b->b_port = lud->lud_port; b->b_host = ch_strdup( host ); done: ldap_free_urldesc( lud ); return rc; } static int config_backend( ConfigArgs *c ) { LloadBackend *b; int i, rc = 0; b = backend_alloc(); for ( i = 1; i < c->argc; i++ ) { if ( lload_backend_parse( c->argv[i], b ) ) { Debug( LDAP_DEBUG_ANY, "config_backend: " "error parsing backend configuration item '%s'\n", c->argv[i] ); return -1; } } if ( BER_BVISNULL( &b->b_uri ) ) { Debug( LDAP_DEBUG_ANY, "config_backend: " "backend address not specified\n" ); rc = -1; goto done; } if ( backend_config_url( b, &b->b_uri ) ) { rc = -1; goto done; } c->ca_private = b; rc = lload_backend_finish( c ); done: if ( rc ) { ch_free( b ); } return rc; } static int config_bindconf( ConfigArgs *c ) { int i; if ( c->op == SLAP_CONFIG_EMIT ) { struct berval bv; lload_bindconf_unparse( &bindconf, &bv ); for ( i = 0; isspace( (unsigned char)bv.bv_val[i] ); i++ ) /* count spaces */; if ( i ) { bv.bv_len -= i; AC_MEMCPY( bv.bv_val, &bv.bv_val[i], bv.bv_len + 1 ); } value_add_one( &c->rvalue_vals, &bv ); ber_memfree( bv.bv_val ); return LDAP_SUCCESS; } else if ( c->op == LDAP_MOD_DELETE ) { /* It's a MUST single-valued attribute, noop for now */ lload_bindconf_free( &bindconf ); return LDAP_SUCCESS; } lload_change.type = LLOAD_CHANGE_MODIFY; lload_change.object = LLOAD_DAEMON; lload_change.flags.daemon |= LLOAD_DAEMON_MOD_BINDCONF; for ( i = 1; i < c->argc; i++ ) { if ( lload_bindconf_parse( c->argv[i], &bindconf ) ) { Debug( LDAP_DEBUG_ANY, "config_bindconf: " "error parsing backend configuration item '%s'\n", c->argv[i] ); return -1; } } if ( bindconf.sb_method == LDAP_AUTH_SASL ) { #ifndef HAVE_CYRUS_SASL Debug( LDAP_DEBUG_ANY, "config_bindconf: " "no sasl support available\n" ); return -1; #endif } if ( !BER_BVISNULL( &bindconf.sb_authzId ) ) { ber_dupbv( &lloadd_identity, &bindconf.sb_authzId ); } else if ( !BER_BVISNULL( &bindconf.sb_authcId ) ) { ber_dupbv( &lloadd_identity, &bindconf.sb_authcId ); } else if ( !BER_BVISNULL( &bindconf.sb_binddn ) ) { char *ptr; lloadd_identity.bv_len = STRLENOF("dn:") + bindconf.sb_binddn.bv_len; lloadd_identity.bv_val = ch_malloc( lloadd_identity.bv_len + 1 ); ptr = lutil_strcopy( lloadd_identity.bv_val, "dn:" ); ptr = lutil_strncopy( ptr, bindconf.sb_binddn.bv_val, bindconf.sb_binddn.bv_len ); *ptr = '\0'; } if ( bindconf.sb_timeout_api ) { timeout_api_tv.tv_sec = bindconf.sb_timeout_api; lload_timeout_api = &timeout_api_tv; if ( lload_timeout_event ) { event_add( lload_timeout_event, lload_timeout_api ); } } else { lload_timeout_api = NULL; if ( lload_timeout_event ) { event_del( lload_timeout_event ); } } if ( bindconf.sb_timeout_net ) { timeout_net_tv.tv_sec = bindconf.sb_timeout_net; lload_timeout_net = &timeout_net_tv; } else { lload_timeout_net = NULL; } #ifdef HAVE_TLS if ( bindconf.sb_tls_do_init ) { lload_bindconf_tls_set( &bindconf, lload_tls_backend_ld ); } #endif /* HAVE_TLS */ return 0; } static int config_fname( ConfigArgs *c ) { return 0; } /* * [listener=] [{read|write}=] */ #ifdef LDAP_TCP_BUFFER static BerVarray tcp_buffer; int tcp_buffer_num; #define SLAP_TCP_RMEM ( 0x1U ) #define SLAP_TCP_WMEM ( 0x2U ) static int tcp_buffer_parse( struct berval *val, int argc, char **argv, int *size, int *rw, LloadListener **l ) { int i, rc = LDAP_SUCCESS; LDAPURLDesc *lud = NULL; char *ptr; if ( val != NULL && argv == NULL ) { char *s = val->bv_val; argv = ldap_str2charray( s, " \t" ); if ( argv == NULL ) { return LDAP_OTHER; } } i = 0; if ( strncasecmp( argv[i], "listener=", STRLENOF("listener=") ) == 0 ) { char *url = argv[i] + STRLENOF("listener="); if ( ldap_url_parse_ext( url, &lud, LDAP_PVT_URL_PARSE_DEF_PORT ) ) { rc = LDAP_INVALID_SYNTAX; goto done; } *l = lload_config_check_my_url( url, lud ); if ( *l == NULL ) { rc = LDAP_NO_SUCH_ATTRIBUTE; goto done; } i++; } ptr = argv[i]; if ( strncasecmp( ptr, "read=", STRLENOF("read=") ) == 0 ) { *rw |= SLAP_TCP_RMEM; ptr += STRLENOF("read="); } else if ( strncasecmp( ptr, "write=", STRLENOF("write=") ) == 0 ) { *rw |= SLAP_TCP_WMEM; ptr += STRLENOF("write="); } else { *rw |= ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ); } /* accept any base */ if ( lutil_atoix( size, ptr, 0 ) ) { rc = LDAP_INVALID_SYNTAX; goto done; } done:; if ( val != NULL && argv != NULL ) { ldap_charray_free( argv ); } if ( lud != NULL ) { ldap_free_urldesc( lud ); } return rc; } #ifdef BALANCER_MODULE static int tcp_buffer_delete_one( struct berval *val ) { int rc = 0; int size = -1, rw = 0; LloadListener *l = NULL; rc = tcp_buffer_parse( val, 0, NULL, &size, &rw, &l ); if ( rc != 0 ) { return rc; } if ( l != NULL ) { int i; LloadListener **ll = lloadd_get_listeners(); for ( i = 0; ll[i] != NULL; i++ ) { if ( ll[i] == l ) break; } if ( ll[i] == NULL ) { return LDAP_NO_SUCH_ATTRIBUTE; } if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = -1; if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = -1; for ( i++; ll[i] != NULL && bvmatch( &l->sl_url, &ll[i]->sl_url ); i++ ) { if ( rw & SLAP_TCP_RMEM ) ll[i]->sl_tcp_rmem = -1; if ( rw & SLAP_TCP_WMEM ) ll[i]->sl_tcp_wmem = -1; } } else { /* NOTE: this affects listeners without a specific setting, * does not reset all listeners. If a listener without * specific settings was assigned a buffer because of * a global setting, it will not be reset. In any case, * buffer changes will only take place at restart. */ if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = -1; if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = -1; } return rc; } static int tcp_buffer_delete( BerVarray vals ) { int i; for ( i = 0; !BER_BVISNULL( &vals[i] ); i++ ) { tcp_buffer_delete_one( &vals[i] ); } return 0; } #endif /* BALANCER_MODULE */ static int tcp_buffer_unparse( int size, int rw, LloadListener *l, struct berval *val ) { char buf[sizeof("2147483648")], *ptr; /* unparse for later use */ val->bv_len = snprintf( buf, sizeof(buf), "%d", size ); if ( l != NULL ) { val->bv_len += STRLENOF( "listener=" " " ) + l->sl_url.bv_len; } if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) { if ( rw & SLAP_TCP_RMEM ) { val->bv_len += STRLENOF("read="); } else if ( rw & SLAP_TCP_WMEM ) { val->bv_len += STRLENOF("write="); } } val->bv_val = SLAP_MALLOC( val->bv_len + 1 ); ptr = val->bv_val; if ( l != NULL ) { ptr = lutil_strcopy( ptr, "listener=" ); ptr = lutil_strncopy( ptr, l->sl_url.bv_val, l->sl_url.bv_len ); *ptr++ = ' '; } if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) { if ( rw & SLAP_TCP_RMEM ) { ptr = lutil_strcopy( ptr, "read=" ); } else if ( rw & SLAP_TCP_WMEM ) { ptr = lutil_strcopy( ptr, "write=" ); } } ptr = lutil_strcopy( ptr, buf ); *ptr = '\0'; assert( val->bv_val + val->bv_len == ptr ); return LDAP_SUCCESS; } static int tcp_buffer_add_one( int argc, char **argv ) { int rc = 0; int size = -1, rw = 0; LloadListener *l = NULL; struct berval val; /* parse */ rc = tcp_buffer_parse( NULL, argc, argv, &size, &rw, &l ); if ( rc != 0 ) { return rc; } /* unparse for later use */ rc = tcp_buffer_unparse( size, rw, l, &val ); if ( rc != LDAP_SUCCESS ) { return rc; } /* use parsed values */ if ( l != NULL ) { int i; LloadListener **ll = lloadd_get_listeners(); for ( i = 0; ll[i] != NULL; i++ ) { if ( ll[i] == l ) break; } if ( ll[i] == NULL ) { return LDAP_NO_SUCH_ATTRIBUTE; } /* buffer only applies to TCP listeners; * we do not do any check here, and delegate them * to setsockopt(2) */ if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = size; if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = size; for ( i++; ll[i] != NULL && bvmatch( &l->sl_url, &ll[i]->sl_url ); i++ ) { if ( rw & SLAP_TCP_RMEM ) ll[i]->sl_tcp_rmem = size; if ( rw & SLAP_TCP_WMEM ) ll[i]->sl_tcp_wmem = size; } } else { /* NOTE: this affects listeners without a specific setting, * does not set all listeners */ if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = size; if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = size; } tcp_buffer = SLAP_REALLOC( tcp_buffer, sizeof(struct berval) * ( tcp_buffer_num + 2 ) ); /* append */ tcp_buffer[tcp_buffer_num] = val; tcp_buffer_num++; BER_BVZERO( &tcp_buffer[tcp_buffer_num] ); return rc; } static int config_tcp_buffer( ConfigArgs *c ) { int rc = LDAP_SUCCESS; #ifdef BALANCER_MODULE if ( c->op == SLAP_CONFIG_EMIT ) { if ( tcp_buffer == NULL || BER_BVISNULL( &tcp_buffer[0] ) ) { return 1; } value_add( &c->rvalue_vals, tcp_buffer ); value_add( &c->rvalue_nvals, tcp_buffer ); return 0; } else if ( c->op == LDAP_MOD_DELETE ) { if ( !c->line ) { tcp_buffer_delete( tcp_buffer ); ber_bvarray_free( tcp_buffer ); tcp_buffer = NULL; tcp_buffer_num = 0; } else { int size = -1, rw = 0; LloadListener *l = NULL; struct berval val = BER_BVNULL; int i; if ( tcp_buffer_num == 0 ) { return 1; } /* parse */ rc = tcp_buffer_parse( NULL, c->argc - 1, &c->argv[1], &size, &rw, &l ); if ( rc != 0 ) { return 1; } /* unparse for later use */ rc = tcp_buffer_unparse( size, rw, l, &val ); if ( rc != LDAP_SUCCESS ) { return 1; } for ( i = 0; !BER_BVISNULL( &tcp_buffer[i] ); i++ ) { if ( bvmatch( &tcp_buffer[i], &val ) ) { break; } } if ( BER_BVISNULL( &tcp_buffer[i] ) ) { /* not found */ rc = 1; goto done; } tcp_buffer_delete_one( &tcp_buffer[i] ); ber_memfree( tcp_buffer[i].bv_val ); for ( ; i < tcp_buffer_num; i++ ) { tcp_buffer[i] = tcp_buffer[i + 1]; } tcp_buffer_num--; done:; if ( !BER_BVISNULL( &val ) ) { SLAP_FREE(val.bv_val); } } return rc; } #endif /* BALANCER_MODULE */ rc = tcp_buffer_add_one( c->argc - 1, &c->argv[1] ); if ( rc ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> unable to add value #%d", c->argv[0], tcp_buffer_num ); Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg ); return 1; } return 0; } #endif /* LDAP_TCP_BUFFER */ static int config_restrict( ConfigArgs *c ) { slap_mask_t restrictops = 0; int i; slap_verbmasks restrictable_ops[] = { { BER_BVC("bind"), SLAP_RESTRICT_OP_BIND }, { BER_BVC("add"), SLAP_RESTRICT_OP_ADD }, { BER_BVC("modify"), SLAP_RESTRICT_OP_MODIFY }, { BER_BVC("rename"), SLAP_RESTRICT_OP_RENAME }, { BER_BVC("modrdn"), 0 }, { BER_BVC("delete"), SLAP_RESTRICT_OP_DELETE }, { BER_BVC("search"), SLAP_RESTRICT_OP_SEARCH }, { BER_BVC("compare"), SLAP_RESTRICT_OP_COMPARE }, { BER_BVC("read"), SLAP_RESTRICT_OP_READS }, { BER_BVC("write"), SLAP_RESTRICT_OP_WRITES }, { BER_BVC("extended"), SLAP_RESTRICT_OP_EXTENDED }, { BER_BVC("extended=" LDAP_EXOP_START_TLS), SLAP_RESTRICT_EXOP_START_TLS }, { BER_BVC("extended=" LDAP_EXOP_MODIFY_PASSWD), SLAP_RESTRICT_EXOP_MODIFY_PASSWD }, { BER_BVC("extended=" LDAP_EXOP_X_WHO_AM_I), SLAP_RESTRICT_EXOP_WHOAMI }, { BER_BVC("extended=" LDAP_EXOP_X_CANCEL), SLAP_RESTRICT_EXOP_CANCEL }, { BER_BVC("all"), SLAP_RESTRICT_OP_ALL }, { BER_BVNULL, 0 } }; i = verbs_to_mask( c->argc, c->argv, restrictable_ops, &restrictops ); if ( i ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> unknown operation", c->argv[0] ); Debug( LDAP_DEBUG_ANY, "%s: %s %s\n", c->log, c->cr_msg, c->argv[i] ); return 1; } if ( restrictops & SLAP_RESTRICT_OP_EXTENDED ) restrictops &= ~SLAP_RESTRICT_EXOP_MASK; return 0; } static slap_verbmasks *loglevel_ops; static int loglevel_init( void ) { slap_verbmasks lo[] = { { BER_BVC("Any"), (slap_mask_t)LDAP_DEBUG_ANY }, { BER_BVC("Trace"), LDAP_DEBUG_TRACE }, { BER_BVC("Packets"), LDAP_DEBUG_PACKETS }, { BER_BVC("Args"), LDAP_DEBUG_ARGS }, { BER_BVC("Conns"), LDAP_DEBUG_CONNS }, { BER_BVC("BER"), LDAP_DEBUG_BER }, { BER_BVC("Filter"), LDAP_DEBUG_FILTER }, { BER_BVC("Config"), LDAP_DEBUG_CONFIG }, { BER_BVC("ACL"), LDAP_DEBUG_ACL }, { BER_BVC("Stats"), LDAP_DEBUG_STATS }, { BER_BVC("Stats2"), LDAP_DEBUG_STATS2 }, { BER_BVC("Shell"), LDAP_DEBUG_SHELL }, { BER_BVC("Parse"), LDAP_DEBUG_PARSE }, { BER_BVC("Sync"), LDAP_DEBUG_SYNC }, { BER_BVC("None"), LDAP_DEBUG_NONE }, { BER_BVNULL, 0 } }; return slap_verbmasks_init( &loglevel_ops, lo ); } static void loglevel_destroy( void ) { if ( loglevel_ops ) { (void)slap_verbmasks_destroy( loglevel_ops ); } loglevel_ops = NULL; } int str2loglevel( const char *s, int *l ) { int i; if ( loglevel_ops == NULL ) { loglevel_init(); } i = verb_to_mask( s, loglevel_ops ); if ( BER_BVISNULL( &loglevel_ops[i].word ) ) { return -1; } *l = loglevel_ops[i].mask; return 0; } int loglevel2bvarray( int l, BerVarray *bva ) { if ( loglevel_ops == NULL ) { loglevel_init(); } if ( l == 0 ) { struct berval bv = BER_BVC("0"); return value_add_one( bva, &bv ); } return mask_to_verbs( loglevel_ops, l, bva ); } int loglevel_print( FILE *out ) { int i; if ( loglevel_ops == NULL ) { loglevel_init(); } fprintf( out, "Installed log subsystems:\n\n" ); for ( i = 0; !BER_BVISNULL( &loglevel_ops[i].word ); i++ ) { unsigned mask = loglevel_ops[i].mask & 0xffffffffUL; fprintf( out, ( mask == ( (slap_mask_t)-1 & 0xffffffffUL ) ? "\t%-30s (-1, 0xffffffff)\n" : "\t%-30s (%u, 0x%x)\n" ), loglevel_ops[i].word.bv_val, mask, mask ); } fprintf( out, "\nNOTE: custom log subsystems may be later installed " "by specific code\n\n" ); return 0; } static int config_syslog; static int config_loglevel( ConfigArgs *c ) { int i; if ( loglevel_ops == NULL ) { loglevel_init(); } if ( c->op == SLAP_CONFIG_EMIT ) { /* Get default or commandline slapd setting */ if ( ldap_syslog && !config_syslog ) config_syslog = ldap_syslog; return loglevel2bvarray( config_syslog, &c->rvalue_vals ); } else if ( c->op == LDAP_MOD_DELETE ) { if ( !c->line ) { config_syslog = 0; } else { i = verb_to_mask( c->line, loglevel_ops ); config_syslog &= ~loglevel_ops[i].mask; } if ( slapMode & SLAP_SERVER_MODE ) { ldap_syslog = config_syslog; } return 0; } for ( i = 1; i < c->argc; i++ ) { int level; if ( isdigit( (unsigned char)c->argv[i][0] ) || c->argv[i][0] == '-' ) { if ( lutil_atoix( &level, c->argv[i], 0 ) != 0 ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> unable to parse level", c->argv[0] ); Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", c->log, c->cr_msg, c->argv[i] ); return 1; } } else { if ( str2loglevel( c->argv[i], &level ) ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> unknown level", c->argv[0] ); Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", c->log, c->cr_msg, c->argv[i] ); return 1; } } /* Explicitly setting a zero clears all the levels */ if ( level ) config_syslog |= level; else config_syslog = 0; } if ( slapMode & SLAP_SERVER_MODE ) { ldap_syslog = config_syslog; } return 0; } static int config_include( ConfigArgs *c ) { int savelineno = c->lineno; int rc; ConfigFile *cf; ConfigFile *cfsave = cfn; ConfigFile *cf2 = NULL; /* Leftover from RE23. No dynamic config for include files */ if ( c->op == SLAP_CONFIG_EMIT || c->op == LDAP_MOD_DELETE ) return 1; cf = ch_calloc( 1, sizeof(ConfigFile) ); if ( cfn->c_kids ) { for ( cf2 = cfn->c_kids; cf2 && cf2->c_sibs; cf2 = cf2->c_sibs ) /* empty */; cf2->c_sibs = cf; } else { cfn->c_kids = cf; } cfn = cf; ber_str2bv( c->argv[1], 0, 1, &cf->c_file ); rc = lload_read_config_file( c->argv[1], c->depth + 1, c, config_back_cf_table ); c->lineno = savelineno - 1; cfn = cfsave; if ( rc ) { if ( cf2 ) cf2->c_sibs = NULL; else cfn->c_kids = NULL; ch_free( cf->c_file.bv_val ); ch_free( cf ); } else { c->ca_private = cf; } return rc; } static int config_feature( ConfigArgs *c ) { slap_verbmasks features[] = { #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS { BER_BVC("vc"), LLOAD_FEATURE_VC }, #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */ { BER_BVC("proxyauthz"), LLOAD_FEATURE_PROXYAUTHZ }, { BER_BVC("read_pause"), LLOAD_FEATURE_PAUSE }, { BER_BVNULL, 0 } }; slap_mask_t mask = 0; int i; if ( c->op == SLAP_CONFIG_EMIT ) { return mask_to_verbs( features, lload_features, &c->rvalue_vals ); } lload_change.type = LLOAD_CHANGE_MODIFY; lload_change.object = LLOAD_DAEMON; lload_change.flags.daemon |= LLOAD_DAEMON_MOD_FEATURES; if ( !lload_change.target ) { lload_change.target = (void *)(uintptr_t)~lload_features; } if ( c->op == LDAP_MOD_DELETE ) { if ( !c->line ) { /* Last value has been deleted */ lload_features = 0; } else { i = verb_to_mask( c->line, features ); lload_features &= ~features[i].mask; } return 0; } i = verbs_to_mask( c->argc, c->argv, features, &mask ); if ( i ) { Debug( LDAP_DEBUG_ANY, "%s: <%s> unknown feature %s\n", c->log, c->argv[0], c->argv[i] ); return 1; } if ( mask & ~LLOAD_FEATURE_SUPPORTED_MASK ) { for ( i = 1; i < c->argc; i++ ) { int j = verb_to_mask( c->argv[i], features ); if ( features[j].mask & ~LLOAD_FEATURE_SUPPORTED_MASK ) { Debug( LDAP_DEBUG_ANY, "%s: <%s> " "experimental feature %s is undocumented, unsupported " "and can change or disappear at any time!\n", c->log, c->argv[0], c->argv[i] ); } } } lload_features |= mask; return 0; } #ifdef HAVE_TLS static int config_tls_cleanup( ConfigArgs *c ) { int rc = 0; if ( lload_tls_ld ) { int opt = 1; ldap_pvt_tls_ctx_free( lload_tls_ctx ); lload_tls_ctx = NULL; /* Force new ctx to be created */ rc = ldap_pvt_tls_set_option( lload_tls_ld, LDAP_OPT_X_TLS_NEWCTX, &opt ); if ( rc == 0 ) { /* The ctx's refcount is bumped up here */ ldap_pvt_tls_get_option( lload_tls_ld, LDAP_OPT_X_TLS_CTX, &lload_tls_ctx ); } else { if ( rc == LDAP_NOT_SUPPORTED ) rc = LDAP_UNWILLING_TO_PERFORM; else rc = LDAP_OTHER; } } return rc; } static int config_tls_option( ConfigArgs *c ) { int flag; int berval = 0; LDAP *ld = lload_tls_ld; switch ( c->type ) { case CFG_TLS_RAND: flag = LDAP_OPT_X_TLS_RANDOM_FILE; ld = NULL; break; case CFG_TLS_CIPHER: flag = LDAP_OPT_X_TLS_CIPHER_SUITE; break; case CFG_TLS_CERT_FILE: flag = LDAP_OPT_X_TLS_CERTFILE; break; case CFG_TLS_CERT_KEY: flag = LDAP_OPT_X_TLS_KEYFILE; break; case CFG_TLS_CA_PATH: flag = LDAP_OPT_X_TLS_CACERTDIR; break; case CFG_TLS_CA_FILE: flag = LDAP_OPT_X_TLS_CACERTFILE; break; case CFG_TLS_DH_FILE: flag = LDAP_OPT_X_TLS_DHFILE; break; case CFG_TLS_ECNAME: flag = LDAP_OPT_X_TLS_ECNAME; break; #ifdef HAVE_GNUTLS case CFG_TLS_CRL_FILE: flag = LDAP_OPT_X_TLS_CRLFILE; break; #endif case CFG_TLS_CACERT: flag = LDAP_OPT_X_TLS_CACERT; berval = 1; break; case CFG_TLS_CERT: flag = LDAP_OPT_X_TLS_CERT; berval = 1; break; case CFG_TLS_KEY: flag = LDAP_OPT_X_TLS_KEY; berval = 1; break; default: Debug( LDAP_DEBUG_ANY, "%s: " "unknown tls_option <0x%x>\n", c->log, c->type ); return 1; } if ( c->op == SLAP_CONFIG_EMIT ) { return ldap_pvt_tls_get_option( ld, flag, berval ? (void *)&c->value_bv : (void *)&c->value_string ); } lload_change.type = LLOAD_CHANGE_MODIFY; lload_change.object = LLOAD_DAEMON; lload_change.flags.daemon |= LLOAD_DAEMON_MOD_TLS; config_push_cleanup( c, config_tls_cleanup ); if ( c->op == LDAP_MOD_DELETE ) { return ldap_pvt_tls_set_option( ld, flag, NULL ); } if ( !berval ) ch_free( c->value_string ); return ldap_pvt_tls_set_option( ld, flag, berval ? (void *)&c->value_bv : (void *)c->argv[1] ); } /* FIXME: this ought to be provided by libldap */ static int config_tls_config( ConfigArgs *c ) { int i, flag; switch ( c->type ) { case CFG_TLS_CRLCHECK: flag = LDAP_OPT_X_TLS_CRLCHECK; break; case CFG_TLS_VERIFY: flag = LDAP_OPT_X_TLS_REQUIRE_CERT; break; case CFG_TLS_PROTOCOL_MIN: flag = LDAP_OPT_X_TLS_PROTOCOL_MIN; break; default: Debug( LDAP_DEBUG_ANY, "%s: " "unknown tls_option <0x%x>\n", c->log, c->type ); return 1; } if ( c->op == SLAP_CONFIG_EMIT ) { return lload_tls_get_config( lload_tls_ld, flag, &c->value_string ); } lload_change.type = LLOAD_CHANGE_MODIFY; lload_change.object = LLOAD_DAEMON; lload_change.flags.daemon |= LLOAD_DAEMON_MOD_TLS; config_push_cleanup( c, config_tls_cleanup ); if ( c->op == LDAP_MOD_DELETE ) { int i = 0; return ldap_pvt_tls_set_option( lload_tls_ld, flag, &i ); } ch_free( c->value_string ); if ( isdigit( (unsigned char)c->argv[1][0] ) && c->type != CFG_TLS_PROTOCOL_MIN ) { if ( lutil_atoi( &i, c->argv[1] ) != 0 ) { Debug( LDAP_DEBUG_ANY, "%s: " "unable to parse %s \"%s\"\n", c->log, c->argv[0], c->argv[1] ); return 1; } return ldap_pvt_tls_set_option( lload_tls_ld, flag, &i ); } else { return ldap_pvt_tls_config( lload_tls_ld, flag, c->argv[1] ); } } #endif #ifdef BALANCER_MODULE static int config_share_tls_ctx( ConfigArgs *c ) { int rc = LDAP_SUCCESS; if ( c->op == SLAP_CONFIG_EMIT ) { c->value_int = lload_use_slap_tls_ctx; return rc; } lload_change.type = LLOAD_CHANGE_MODIFY; lload_change.object = LLOAD_DAEMON; lload_change.flags.daemon |= LLOAD_DAEMON_MOD_TLS; if ( c->op == LDAP_MOD_DELETE ) { lload_use_slap_tls_ctx = 0; return rc; } lload_use_slap_tls_ctx = c->value_int; return rc; } #endif /* BALANCER_MODULE */ void lload_init_config_argv( ConfigArgs *c ) { c->argv = ch_calloc( ARGS_STEP + 1, sizeof(*c->argv) ); c->argv_size = ARGS_STEP + 1; } ConfigTable * lload_config_find_keyword( ConfigTable *Conf, ConfigArgs *c ) { int i; for ( i = 0; Conf[i].name; i++ ) if ( ( Conf[i].length && ( !strncasecmp( c->argv[0], Conf[i].name, Conf[i].length ) ) ) || ( !strcasecmp( c->argv[0], Conf[i].name ) ) ) break; if ( !Conf[i].name ) return NULL; if ( (Conf[i].arg_type & ARGS_TYPES) == ARG_BINARY ) { size_t decode_len = LUTIL_BASE64_DECODE_LEN( c->linelen ); ch_free( c->tline ); c->tline = ch_malloc( decode_len + 1 ); c->linelen = lutil_b64_pton( c->line, c->tline, decode_len ); if ( c->linelen < 0 ) { ch_free( c->tline ); c->tline = NULL; return NULL; } c->line = c->tline; } return Conf + i; } int lload_config_check_vals( ConfigTable *Conf, ConfigArgs *c, int check_only ) { int arg_user, arg_type, arg_syn, iarg; unsigned uiarg; long larg; unsigned long ularg; ber_len_t barg; if ( Conf->arg_type == ARG_IGNORED ) { Debug( LDAP_DEBUG_CONFIG, "%s: keyword <%s> ignored\n", c->log, Conf->name ); return 0; } arg_type = Conf->arg_type & ARGS_TYPES; arg_user = Conf->arg_type & ARGS_USERLAND; arg_syn = Conf->arg_type & ARGS_SYNTAX; if ( Conf->min_args && ( c->argc < Conf->min_args ) ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> missing <%s> argument", c->argv[0], Conf->what ? Conf->what : "" ); Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } if ( Conf->max_args && ( c->argc > Conf->max_args ) ) { char *ignored = " ignored"; snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> extra cruft after <%s>", c->argv[0], Conf->what ); ignored = ""; Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s%s\n", c->log, c->cr_msg, ignored ); return ARG_BAD_CONF; } if ( (arg_syn & ARG_PAREN) && *c->argv[1] != '(' /*')'*/ ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> old format not supported", c->argv[0] ); Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } if ( arg_type && !Conf->arg_item && !(arg_syn & ARG_OFFSET) ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> invalid config_table, arg_item is NULL", c->argv[0] ); Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } c->type = arg_user; memset( &c->values, 0, sizeof(c->values) ); if ( arg_type == ARG_STRING ) { assert( c->argc == 2 ); if ( !check_only ) c->value_string = ch_strdup( c->argv[1] ); } else if ( arg_type == ARG_BERVAL ) { assert( c->argc == 2 ); if ( !check_only ) ber_str2bv( c->argv[1], 0, 1, &c->value_bv ); } else if ( arg_type == ARG_BINARY ) { assert( c->argc == 2 ); if ( !check_only ) { c->value_bv.bv_len = c->linelen; c->value_bv.bv_val = ch_malloc( c->linelen ); AC_MEMCPY( c->value_bv.bv_val, c->line, c->linelen ); } } else { /* all numeric */ int j; iarg = 0; larg = 0; barg = 0; switch ( arg_type ) { case ARG_INT: assert( c->argc == 2 ); if ( lutil_atoix( &iarg, c->argv[1], 0 ) != 0 ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> unable to parse \"%s\" as int", c->argv[0], c->argv[1] ); Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } break; case ARG_UINT: assert( c->argc == 2 ); if ( lutil_atoux( &uiarg, c->argv[1], 0 ) != 0 ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> unable to parse \"%s\" as unsigned int", c->argv[0], c->argv[1] ); Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } break; case ARG_LONG: assert( c->argc == 2 ); if ( lutil_atolx( &larg, c->argv[1], 0 ) != 0 ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> unable to parse \"%s\" as long", c->argv[0], c->argv[1] ); Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } break; case ARG_ULONG: assert( c->argc == 2 ); if ( LUTIL_ATOULX( &ularg, c->argv[1], 0 ) != 0 ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> unable to parse \"%s\" as unsigned long", c->argv[0], c->argv[1] ); Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } break; case ARG_BER_LEN_T: { unsigned long l; assert( c->argc == 2 ); if ( lutil_atoulx( &l, c->argv[1], 0 ) != 0 ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> unable to parse \"%s\" as ber_len_t", c->argv[0], c->argv[1] ); Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } barg = (ber_len_t)l; } break; case ARG_ON_OFF: /* note: this is an explicit exception * to the "need exactly 2 args" rule */ if ( c->argc == 1 ) { iarg = 1; } else if ( !strcasecmp( c->argv[1], "on" ) || !strcasecmp( c->argv[1], "true" ) || !strcasecmp( c->argv[1], "yes" ) ) { iarg = 1; } else if ( !strcasecmp( c->argv[1], "off" ) || !strcasecmp( c->argv[1], "false" ) || !strcasecmp( c->argv[1], "no" ) ) { iarg = 0; } else { snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> invalid value", c->argv[0] ); Debug( LDAP_DEBUG_ANY|LDAP_DEBUG_NONE, "%s: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } break; } j = (arg_type & ARG_NONZERO) ? 1 : 0; if ( iarg < j && larg < j && barg < (unsigned)j ) { larg = larg ? larg : ( barg ? (long)barg : iarg ); snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> invalid value", c->argv[0] ); Debug( LDAP_DEBUG_ANY|LDAP_DEBUG_NONE, "%s: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } switch ( arg_type ) { case ARG_ON_OFF: case ARG_INT: c->value_int = iarg; break; case ARG_UINT: c->value_uint = uiarg; break; case ARG_LONG: c->value_long = larg; break; case ARG_ULONG: c->value_ulong = ularg; break; case ARG_BER_LEN_T: c->value_ber_t = barg; break; } } return 0; } int lload_config_set_vals( ConfigTable *Conf, ConfigArgs *c ) { int rc, arg_type; void *ptr = NULL; arg_type = Conf->arg_type; if ( arg_type & ARG_MAGIC ) { c->cr_msg[0] = '\0'; rc = ( *( (ConfigDriver *)Conf->arg_item ) )( c ); if ( rc ) { if ( !c->cr_msg[0] ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> handler exited with %d", c->argv[0], rc ); Debug( LDAP_DEBUG_CONFIG, "%s: %s!\n", c->log, c->cr_msg ); } return ARG_BAD_CONF; } return 0; } if ( arg_type & ARG_OFFSET ) { { snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> offset is missing base pointer", c->argv[0] ); Debug( LDAP_DEBUG_CONFIG, "%s: %s!\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } ptr = (void *)( (char *)ptr + (long)Conf->arg_item ); } else if ( arg_type & ARGS_TYPES ) { ptr = Conf->arg_item; } if ( arg_type & ARGS_TYPES ) switch ( arg_type & ARGS_TYPES ) { case ARG_ON_OFF: case ARG_INT: *(int *)ptr = c->value_int; break; case ARG_UINT: *(unsigned *)ptr = c->value_uint; break; case ARG_LONG: *(long *)ptr = c->value_long; break; case ARG_ULONG: *(size_t *)ptr = c->value_ulong; break; case ARG_BER_LEN_T: *(ber_len_t *)ptr = c->value_ber_t; break; case ARG_STRING: { char *cc = *(char **)ptr; if ( cc ) { if ( (arg_type & ARG_UNIQUE) && c->op == SLAP_CONFIG_ADD ) { Debug( LDAP_DEBUG_CONFIG, "%s: already set %s!\n", c->log, Conf->name ); return ARG_BAD_CONF; } ch_free( cc ); } *(char **)ptr = c->value_string; break; } case ARG_BERVAL: case ARG_BINARY: *(struct berval *)ptr = c->value_bv; break; } return 0; } int lload_config_add_vals( ConfigTable *Conf, ConfigArgs *c ) { int rc, arg_type; arg_type = Conf->arg_type; if ( arg_type == ARG_IGNORED ) { Debug( LDAP_DEBUG_CONFIG, "%s: keyword <%s> ignored\n", c->log, Conf->name ); return 0; } rc = lload_config_check_vals( Conf, c, 0 ); if ( rc ) return rc; return lload_config_set_vals( Conf, c ); } int lload_read_config_file( const char *fname, int depth, ConfigArgs *cf, ConfigTable *cft ) { FILE *fp; ConfigTable *ct; ConfigArgs *c; int rc; struct stat s; c = ch_calloc( 1, sizeof(ConfigArgs) ); if ( c == NULL ) { return 1; } if ( depth ) { memcpy( c, cf, sizeof(ConfigArgs) ); } else { c->depth = depth; /* XXX */ } c->valx = -1; c->fname = fname; lload_init_config_argv( c ); if ( stat( fname, &s ) != 0 ) { char ebuf[128]; int saved_errno = errno; ldap_syslog = 1; Debug( LDAP_DEBUG_ANY, "could not stat config file \"%s\": %s (%d)\n", fname, AC_STRERROR_R( saved_errno, ebuf, sizeof(ebuf) ), saved_errno ); ch_free( c->argv ); ch_free( c ); return 1; } if ( !S_ISREG(s.st_mode) ) { ldap_syslog = 1; Debug( LDAP_DEBUG_ANY, "regular file expected, got \"%s\"\n", fname ); ch_free( c->argv ); ch_free( c ); return 1; } fp = fopen( fname, "r" ); if ( fp == NULL ) { char ebuf[128]; int saved_errno = errno; ldap_syslog = 1; Debug( LDAP_DEBUG_ANY, "could not open config file \"%s\": %s (%d)\n", fname, AC_STRERROR_R( saved_errno, ebuf, sizeof(ebuf) ), saved_errno ); ch_free( c->argv ); ch_free( c ); return 1; } Debug( LDAP_DEBUG_CONFIG, "reading config file %s\n", fname ); fp_getline_init( c ); c->tline = NULL; while ( fp_getline( fp, c ) ) { /* skip comments and blank lines */ if ( c->line[0] == '#' || c->line[0] == '\0' ) { continue; } snprintf( c->log, sizeof(c->log), "%s: line %d", c->fname, c->lineno ); c->argc = 0; ch_free( c->tline ); if ( lload_config_fp_parse_line( c ) ) { rc = 1; goto done; } if ( c->argc < 1 ) { Debug( LDAP_DEBUG_ANY, "%s: bad config line\n", c->log ); rc = 1; goto done; } c->op = SLAP_CONFIG_ADD; ct = lload_config_find_keyword( cft, c ); if ( ct ) { c->table = Cft_Global; rc = lload_config_add_vals( ct, c ); if ( !rc ) continue; if ( rc & ARGS_USERLAND ) { /* XXX a usertype would be opaque here */ Debug( LDAP_DEBUG_CONFIG, "%s: unknown user type <%s>\n", c->log, c->argv[0] ); rc = 1; goto done; } else if ( rc == ARG_BAD_CONF ) { rc = 1; goto done; } } else { Debug( LDAP_DEBUG_ANY, "%s: unknown directive " "<%s> outside backend info and database definitions\n", c->log, *c->argv ); rc = 1; goto done; } } rc = 0; done: ch_free( c->tline ); fclose( fp ); ch_free( c->argv ); ch_free( c ); return rc; } int lload_read_config( const char *fname, const char *dir ) { if ( !fname ) fname = LLOADD_DEFAULT_CONFIGFILE; cfn = ch_calloc( 1, sizeof(ConfigFile) ); return lload_read_config_file( fname, 0, NULL, config_back_cf_table ); } /* restrictops, allows, disallows, requires, loglevel */ int bverb_to_mask( struct berval *bword, slap_verbmasks *v ) { int i; for ( i = 0; !BER_BVISNULL( &v[i].word ); i++ ) { if ( !ber_bvstrcasecmp( bword, &v[i].word ) ) break; } return i; } int verb_to_mask( const char *word, slap_verbmasks *v ) { struct berval bword; ber_str2bv( word, 0, 0, &bword ); return bverb_to_mask( &bword, v ); } int verbs_to_mask( int argc, char *argv[], slap_verbmasks *v, slap_mask_t *m ) { int i, j; for ( i = 1; i < argc; i++ ) { j = verb_to_mask( argv[i], v ); if ( BER_BVISNULL( &v[j].word ) ) return i; while ( !v[j].mask ) j--; *m |= v[j].mask; } return 0; } /* Mask keywords that represent multiple bits should occur before single * bit keywords in the verbmasks array. */ int mask_to_verbs( slap_verbmasks *v, slap_mask_t m, BerVarray *bva ) { int i, rc = 1; if ( m ) { for ( i = 0; !BER_BVISNULL( &v[i].word ); i++ ) { if ( !v[i].mask ) continue; if ( (m & v[i].mask) == v[i].mask ) { value_add_one( bva, &v[i].word ); rc = 0; m ^= v[i].mask; if ( !m ) break; } } } return rc; } int slap_verbmasks_init( slap_verbmasks **vp, slap_verbmasks *v ) { int i; assert( *vp == NULL ); for ( i = 0; !BER_BVISNULL( &v[i].word ); i++ ) /* EMPTY */; *vp = ch_calloc( i + 1, sizeof(slap_verbmasks) ); for ( i = 0; !BER_BVISNULL( &v[i].word ); i++ ) { ber_dupbv( &(*vp)[i].word, &v[i].word ); *( (slap_mask_t *)&(*vp)[i].mask ) = v[i].mask; } BER_BVZERO( &(*vp)[i].word ); return 0; } int slap_verbmasks_destroy( slap_verbmasks *v ) { int i; assert( v != NULL ); for ( i = 0; !BER_BVISNULL( &v[i].word ); i++ ) { ch_free( v[i].word.bv_val ); } ch_free( v ); return 0; } #ifndef BALANCER_MODULE int config_push_cleanup( ConfigArgs *ca, ConfigDriver *cleanup ) { /* Stub, cleanups only run in online config */ return 0; } #endif /* !BALANCER_MODULE */ static slap_verbmasks tlskey[] = { { BER_BVC("no"), LLOAD_CLEARTEXT }, { BER_BVC("yes"), LLOAD_STARTTLS_OPTIONAL }, { BER_BVC("critical"), LLOAD_STARTTLS }, { BER_BVNULL, 0 } }; static slap_verbmasks crlkeys[] = { { BER_BVC("none"), LDAP_OPT_X_TLS_CRL_NONE }, { BER_BVC("peer"), LDAP_OPT_X_TLS_CRL_PEER }, { BER_BVC("all"), LDAP_OPT_X_TLS_CRL_ALL }, { BER_BVNULL, 0 } }; static slap_verbmasks vfykeys[] = { { BER_BVC("never"), LDAP_OPT_X_TLS_NEVER }, { BER_BVC("allow"), LDAP_OPT_X_TLS_ALLOW }, { BER_BVC("try"), LDAP_OPT_X_TLS_TRY }, { BER_BVC("demand"), LDAP_OPT_X_TLS_DEMAND }, { BER_BVC("hard"), LDAP_OPT_X_TLS_HARD }, { BER_BVC("true"), LDAP_OPT_X_TLS_HARD }, { BER_BVNULL, 0 } }; static slap_verbmasks methkey[] = { { BER_BVC("none"), LDAP_AUTH_NONE }, { BER_BVC("simple"), LDAP_AUTH_SIMPLE }, #ifdef HAVE_CYRUS_SASL { BER_BVC("sasl"), LDAP_AUTH_SASL }, #endif { BER_BVNULL, 0 } }; int lload_keepalive_parse( struct berval *val, void *bc, slap_cf_aux_table *tab0, const char *tabmsg, int unparse ) { if ( unparse ) { slap_keepalive *sk = (slap_keepalive *)bc; int rc = snprintf( val->bv_val, val->bv_len, "%d:%d:%d", sk->sk_idle, sk->sk_probes, sk->sk_interval ); if ( rc < 0 ) { return -1; } if ( (unsigned)rc >= val->bv_len ) { return -1; } val->bv_len = rc; } else { char *s = val->bv_val; char *next; slap_keepalive *sk = (slap_keepalive *)bc; slap_keepalive sk2; if ( s[0] == ':' ) { sk2.sk_idle = 0; s++; } else { sk2.sk_idle = strtol( s, &next, 10 ); if ( next == s || next[0] != ':' ) { return -1; } if ( sk2.sk_idle < 0 ) { return -1; } s = ++next; } if ( s[0] == ':' ) { sk2.sk_probes = 0; s++; } else { sk2.sk_probes = strtol( s, &next, 10 ); if ( next == s || next[0] != ':' ) { return -1; } if ( sk2.sk_probes < 0 ) { return -1; } s = ++next; } if ( *s == '\0' ) { sk2.sk_interval = 0; } else { sk2.sk_interval = strtol( s, &next, 10 ); if ( next == s || next[0] != '\0' ) { return -1; } if ( sk2.sk_interval < 0 ) { return -1; } } *sk = sk2; ber_memfree( val->bv_val ); BER_BVZERO( val ); } return 0; } static slap_cf_aux_table backendkey[] = { { BER_BVC("uri="), offsetof(LloadBackend, b_uri), 'b', 1, NULL }, { BER_BVC("numconns="), offsetof(LloadBackend, b_numconns), 'i', 0, NULL }, { BER_BVC("bindconns="), offsetof(LloadBackend, b_numbindconns), 'i', 0, NULL }, { BER_BVC("retry="), offsetof(LloadBackend, b_retry_timeout), 'i', 0, NULL }, { BER_BVC("max-pending-ops="), offsetof(LloadBackend, b_max_pending), 'i', 0, NULL }, { BER_BVC("conn-max-pending="), offsetof(LloadBackend, b_max_conn_pending), 'i', 0, NULL }, { BER_BVC("starttls="), offsetof(LloadBackend, b_tls_conf), 'i', 0, tlskey }, { BER_BVNULL, 0, 0, 0, NULL } }; static slap_cf_aux_table bindkey[] = { { BER_BVC("bindmethod="), offsetof(slap_bindconf, sb_method), 'i', 0, methkey }, { BER_BVC("timeout="), offsetof(slap_bindconf, sb_timeout_api), 'i', 0, NULL }, { BER_BVC("network-timeout="), offsetof(slap_bindconf, sb_timeout_net), 'i', 0, NULL }, { BER_BVC("binddn="), offsetof(slap_bindconf, sb_binddn), 'b', 1, NULL }, { BER_BVC("credentials="), offsetof(slap_bindconf, sb_cred), 'b', 1, NULL }, { BER_BVC("saslmech="), offsetof(slap_bindconf, sb_saslmech), 'b', 0, NULL }, { BER_BVC("secprops="), offsetof(slap_bindconf, sb_secprops), 's', 0, NULL }, { BER_BVC("realm="), offsetof(slap_bindconf, sb_realm), 'b', 0, NULL }, { BER_BVC("authcID="), offsetof(slap_bindconf, sb_authcId), 'b', 1, NULL }, { BER_BVC("authzID="), offsetof(slap_bindconf, sb_authzId), 'b', 1, NULL }, { BER_BVC("keepalive="), offsetof(slap_bindconf, sb_keepalive), 'x', 0, (slap_verbmasks *)lload_keepalive_parse }, { BER_BVC("tcp-user-timeout="), offsetof(slap_bindconf, sb_tcp_user_timeout), 'u', 0, NULL }, #ifdef HAVE_TLS /* NOTE: replace "12" with the actual index * of the first TLS-related line */ #define aux_TLS (bindkey+12) /* beginning of TLS keywords */ { BER_BVC("tls_cert="), offsetof(slap_bindconf, sb_tls_cert), 's', 1, NULL }, { BER_BVC("tls_key="), offsetof(slap_bindconf, sb_tls_key), 's', 1, NULL }, { BER_BVC("tls_cacert="), offsetof(slap_bindconf, sb_tls_cacert), 's', 1, NULL }, { BER_BVC("tls_cacertdir="), offsetof(slap_bindconf, sb_tls_cacertdir), 's', 1, NULL }, { BER_BVC("tls_reqcert="), offsetof(slap_bindconf, sb_tls_reqcert), 's', 0, NULL }, { BER_BVC("tls_reqsan="), offsetof(slap_bindconf, sb_tls_reqsan), 's', 0, NULL }, { BER_BVC("tls_cipher_suite="), offsetof(slap_bindconf, sb_tls_cipher_suite), 's', 0, NULL }, { BER_BVC("tls_protocol_min="), offsetof(slap_bindconf, sb_tls_protocol_min), 's', 0, NULL }, { BER_BVC("tls_ecname="), offsetof(slap_bindconf, sb_tls_ecname), 's', 0, NULL }, #ifdef HAVE_OPENSSL { BER_BVC("tls_crlcheck="), offsetof(slap_bindconf, sb_tls_crlcheck), 's', 0, NULL }, #endif #endif { BER_BVNULL, 0, 0, 0, NULL } }; /* * 's': char * * 'b': struct berval * 'i': int; if !NULL, compute using ((slap_verbmasks *)aux) * 'u': unsigned * 'I': long * 'U': unsigned long */ int lload_cf_aux_table_parse( const char *word, void *dst, slap_cf_aux_table *tab0, LDAP_CONST char *tabmsg ) { int rc = SLAP_CONF_UNKNOWN; slap_cf_aux_table *tab; for ( tab = tab0; !BER_BVISNULL( &tab->key ); tab++ ) { if ( !strncasecmp( word, tab->key.bv_val, tab->key.bv_len ) ) { char **cptr; int *iptr, j; unsigned *uptr; long *lptr; unsigned long *ulptr; struct berval *bptr; const char *val = word + tab->key.bv_len; switch ( tab->type ) { case 's': cptr = (char **)( (char *)dst + tab->off ); *cptr = ch_strdup( val ); rc = 0; break; case 'b': bptr = (struct berval *)( (char *)dst + tab->off ); assert( tab->aux == NULL ); ber_str2bv( val, 0, 1, bptr ); rc = 0; break; case 'i': iptr = (int *)( (char *)dst + tab->off ); if ( tab->aux != NULL ) { slap_verbmasks *aux = (slap_verbmasks *)tab->aux; assert( aux != NULL ); rc = 1; for ( j = 0; !BER_BVISNULL( &aux[j].word ); j++ ) { if ( !strcasecmp( val, aux[j].word.bv_val ) ) { *iptr = aux[j].mask; rc = 0; break; } } } else { rc = lutil_atoix( iptr, val, 0 ); } break; case 'u': uptr = (unsigned *)( (char *)dst + tab->off ); rc = lutil_atoux( uptr, val, 0 ); break; case 'I': lptr = (long *)( (char *)dst + tab->off ); rc = lutil_atolx( lptr, val, 0 ); break; case 'U': ulptr = (unsigned long *)( (char *)dst + tab->off ); rc = lutil_atoulx( ulptr, val, 0 ); break; case 'x': if ( tab->aux != NULL ) { struct berval value; lload_cf_aux_table_parse_x *func = (lload_cf_aux_table_parse_x *)tab->aux; ber_str2bv( val, 0, 1, &value ); rc = func( &value, (void *)( (char *)dst + tab->off ), tab, tabmsg, 0 ); } else { rc = 1; } break; } if ( rc ) { Debug( LDAP_DEBUG_ANY, "invalid %s value %s\n", tabmsg, word ); } return rc; } } return rc; } int lload_cf_aux_table_unparse( void *src, struct berval *bv, slap_cf_aux_table *tab0 ) { char buf[AC_LINE_MAX], *ptr; slap_cf_aux_table *tab; struct berval tmp; ptr = buf; for ( tab = tab0; !BER_BVISNULL( &tab->key ); tab++ ) { char **cptr; int *iptr, i; unsigned *uptr; long *lptr; unsigned long *ulptr; struct berval *bptr; cptr = (char **)( (char *)src + tab->off ); switch ( tab->type ) { case 'b': bptr = (struct berval *)( (char *)src + tab->off ); cptr = &bptr->bv_val; case 's': if ( *cptr ) { *ptr++ = ' '; ptr = lutil_strcopy( ptr, tab->key.bv_val ); if ( tab->quote ) *ptr++ = '"'; ptr = lutil_strcopy( ptr, *cptr ); if ( tab->quote ) *ptr++ = '"'; } break; case 'i': iptr = (int *)( (char *)src + tab->off ); if ( tab->aux != NULL ) { slap_verbmasks *aux = (slap_verbmasks *)tab->aux; for ( i = 0; !BER_BVISNULL( &aux[i].word ); i++ ) { if ( *iptr == aux[i].mask ) { *ptr++ = ' '; ptr = lutil_strcopy( ptr, tab->key.bv_val ); ptr = lutil_strcopy( ptr, aux[i].word.bv_val ); break; } } } else { *ptr++ = ' '; ptr = lutil_strcopy( ptr, tab->key.bv_val ); ptr += snprintf( ptr, sizeof(buf) - ( ptr - buf ), "%d", *iptr ); } break; case 'u': uptr = (unsigned *)( (char *)src + tab->off ); *ptr++ = ' '; ptr = lutil_strcopy( ptr, tab->key.bv_val ); ptr += snprintf( ptr, sizeof(buf) - ( ptr - buf ), "%u", *uptr ); break; case 'I': lptr = (long *)( (char *)src + tab->off ); *ptr++ = ' '; ptr = lutil_strcopy( ptr, tab->key.bv_val ); ptr += snprintf( ptr, sizeof(buf) - ( ptr - buf ), "%ld", *lptr ); break; case 'U': ulptr = (unsigned long *)( (char *)src + tab->off ); *ptr++ = ' '; ptr = lutil_strcopy( ptr, tab->key.bv_val ); ptr += snprintf( ptr, sizeof(buf) - ( ptr - buf ), "%lu", *ulptr ); break; case 'x': { char *saveptr = ptr; *ptr++ = ' '; ptr = lutil_strcopy( ptr, tab->key.bv_val ); if ( tab->quote ) *ptr++ = '"'; if ( tab->aux != NULL ) { struct berval value; lload_cf_aux_table_parse_x *func = (lload_cf_aux_table_parse_x *)tab->aux; int rc; value.bv_val = ptr; value.bv_len = buf + sizeof(buf) - ptr; rc = func( &value, (void *)( (char *)src + tab->off ), tab, "(unparse)", 1 ); if ( rc == 0 ) { if ( value.bv_len ) { ptr += value.bv_len; } else { ptr = saveptr; break; } } } if ( tab->quote ) *ptr++ = '"'; } break; default: assert(0); } } tmp.bv_val = buf; tmp.bv_len = ptr - buf; ber_dupbv( bv, &tmp ); return 0; } int lload_tls_get_config( LDAP *ld, int opt, char **val ) { #ifdef HAVE_TLS slap_verbmasks *keys; int i, ival; *val = NULL; switch ( opt ) { case LDAP_OPT_X_TLS_CRLCHECK: keys = crlkeys; break; case LDAP_OPT_X_TLS_REQUIRE_CERT: keys = vfykeys; break; case LDAP_OPT_X_TLS_PROTOCOL_MIN: { char buf[8]; ldap_pvt_tls_get_option( ld, opt, &ival ); snprintf( buf, sizeof(buf), "%d.%d", ( ival >> 8 ) & 0xff, ival & 0xff ); *val = ch_strdup( buf ); return 0; } default: return -1; } ldap_pvt_tls_get_option( ld, opt, &ival ); for ( i = 0; !BER_BVISNULL( &keys[i].word ); i++ ) { if ( keys[i].mask == ival ) { *val = ch_strdup( keys[i].word.bv_val ); return 0; } } #endif return -1; } #ifdef HAVE_TLS static struct { const char *key; size_t offset; int opt; } bindtlsopts[] = { { "tls_cert", offsetof(slap_bindconf, sb_tls_cert), LDAP_OPT_X_TLS_CERTFILE }, { "tls_key", offsetof(slap_bindconf, sb_tls_key), LDAP_OPT_X_TLS_KEYFILE }, { "tls_cacert", offsetof(slap_bindconf, sb_tls_cacert), LDAP_OPT_X_TLS_CACERTFILE }, { "tls_cacertdir", offsetof(slap_bindconf, sb_tls_cacertdir), LDAP_OPT_X_TLS_CACERTDIR }, { "tls_cipher_suite", offsetof(slap_bindconf, sb_tls_cipher_suite), LDAP_OPT_X_TLS_CIPHER_SUITE }, { "tls_ecname", offsetof(slap_bindconf, sb_tls_ecname), LDAP_OPT_X_TLS_ECNAME }, { NULL, 0 } }; int lload_bindconf_tls_set( slap_bindconf *bc, LDAP *ld ) { int i, rc, newctx = 0, res = 0; char *ptr = (char *)bc, **word; if ( bc->sb_tls_do_init ) { for ( i = 0; bindtlsopts[i].opt; i++ ) { word = (char **)( ptr + bindtlsopts[i].offset ); if ( *word ) { rc = ldap_set_option( ld, bindtlsopts[i].opt, *word ); if ( rc ) { Debug( LDAP_DEBUG_ANY, "lload_bindconf_tls_set: " "failed to set %s to %s\n", bindtlsopts[i].key, *word ); res = -1; } else newctx = 1; } } if ( bc->sb_tls_reqcert ) { rc = ldap_pvt_tls_config( ld, LDAP_OPT_X_TLS_REQUIRE_CERT, bc->sb_tls_reqcert ); if ( rc ) { Debug( LDAP_DEBUG_ANY, "lload_bindconf_tls_set: " "failed to set tls_reqcert to %s\n", bc->sb_tls_reqcert ); res = -1; } else { newctx = 1; /* retrieve the parsed setting for later use */ ldap_get_option( ld, LDAP_OPT_X_TLS_REQUIRE_CERT, &bc->sb_tls_int_reqcert ); } } if ( bc->sb_tls_reqsan ) { rc = ldap_pvt_tls_config( ld, LDAP_OPT_X_TLS_REQUIRE_SAN, bc->sb_tls_reqsan ); if ( rc ) { Debug( LDAP_DEBUG_ANY, "lload_bindconf_tls_set: " "failed to set tls_reqsan to %s\n", bc->sb_tls_reqsan ); res = -1; } else { newctx = 1; /* retrieve the parsed setting for later use */ ldap_get_option( ld, LDAP_OPT_X_TLS_REQUIRE_SAN, &bc->sb_tls_int_reqsan ); } } if ( bc->sb_tls_protocol_min ) { rc = ldap_pvt_tls_config( ld, LDAP_OPT_X_TLS_PROTOCOL_MIN, bc->sb_tls_protocol_min ); if ( rc ) { Debug( LDAP_DEBUG_ANY, "lload_bindconf_tls_set: " "failed to set tls_protocol_min to %s\n", bc->sb_tls_protocol_min ); res = -1; } else newctx = 1; } #ifdef HAVE_OPENSSL if ( bc->sb_tls_crlcheck ) { rc = ldap_pvt_tls_config( ld, LDAP_OPT_X_TLS_CRLCHECK, bc->sb_tls_crlcheck ); if ( rc ) { Debug( LDAP_DEBUG_ANY, "lload_bindconf_tls_set: " "failed to set tls_crlcheck to %s\n", bc->sb_tls_crlcheck ); res = -1; } else newctx = 1; } #endif if ( !res ) bc->sb_tls_do_init = 0; } if ( newctx ) { int opt = 0; if ( bc->sb_tls_ctx ) { ldap_pvt_tls_ctx_free( bc->sb_tls_ctx ); bc->sb_tls_ctx = NULL; } rc = ldap_set_option( ld, LDAP_OPT_X_TLS_NEWCTX, &opt ); if ( rc ) res = rc; else ldap_get_option( ld, LDAP_OPT_X_TLS_CTX, &bc->sb_tls_ctx ); } else if ( bc->sb_tls_ctx ) { rc = ldap_set_option( ld, LDAP_OPT_X_TLS_CTX, bc->sb_tls_ctx ); if ( rc == LDAP_SUCCESS ) { /* these options aren't actually inside the ctx, so have to be set again */ ldap_set_option( ld, LDAP_OPT_X_TLS_REQUIRE_CERT, &bc->sb_tls_int_reqcert ); ldap_set_option( ld, LDAP_OPT_X_TLS_REQUIRE_SAN, &bc->sb_tls_int_reqsan ); } else res = rc; } return res; } #endif int lload_bindconf_tls_parse( const char *word, slap_bindconf *bc ) { #ifdef HAVE_TLS if ( lload_cf_aux_table_parse( word, bc, aux_TLS, "tls config" ) == 0 ) { bc->sb_tls_do_init = 1; return 0; } #endif return -1; } int lload_backend_parse( const char *word, LloadBackend *b ) { return lload_cf_aux_table_parse( word, b, backendkey, "backend config" ); } int lload_bindconf_parse( const char *word, slap_bindconf *bc ) { #ifdef HAVE_TLS /* Detect TLS config changes explicitly */ if ( lload_bindconf_tls_parse( word, bc ) == 0 ) { return 0; } #endif return lload_cf_aux_table_parse( word, bc, bindkey, "bind config" ); } int lload_bindconf_unparse( slap_bindconf *bc, struct berval *bv ) { return lload_cf_aux_table_unparse( bc, bv, bindkey ); } void lload_bindconf_free( slap_bindconf *bc ) { if ( !BER_BVISNULL( &bc->sb_uri ) ) { ch_free( bc->sb_uri.bv_val ); BER_BVZERO( &bc->sb_uri ); } if ( !BER_BVISNULL( &bc->sb_binddn ) ) { ch_free( bc->sb_binddn.bv_val ); BER_BVZERO( &bc->sb_binddn ); } if ( !BER_BVISNULL( &bc->sb_cred ) ) { ch_free( bc->sb_cred.bv_val ); BER_BVZERO( &bc->sb_cred ); } if ( !BER_BVISNULL( &bc->sb_saslmech ) ) { ch_free( bc->sb_saslmech.bv_val ); BER_BVZERO( &bc->sb_saslmech ); } if ( bc->sb_secprops ) { ch_free( bc->sb_secprops ); bc->sb_secprops = NULL; } if ( !BER_BVISNULL( &bc->sb_realm ) ) { ch_free( bc->sb_realm.bv_val ); BER_BVZERO( &bc->sb_realm ); } if ( !BER_BVISNULL( &bc->sb_authcId ) ) { ch_free( bc->sb_authcId.bv_val ); BER_BVZERO( &bc->sb_authcId ); } if ( !BER_BVISNULL( &bc->sb_authzId ) ) { ch_free( bc->sb_authzId.bv_val ); BER_BVZERO( &bc->sb_authzId ); } #ifdef HAVE_TLS if ( bc->sb_tls_cert ) { ch_free( bc->sb_tls_cert ); bc->sb_tls_cert = NULL; } if ( bc->sb_tls_key ) { ch_free( bc->sb_tls_key ); bc->sb_tls_key = NULL; } if ( bc->sb_tls_cacert ) { ch_free( bc->sb_tls_cacert ); bc->sb_tls_cacert = NULL; } if ( bc->sb_tls_cacertdir ) { ch_free( bc->sb_tls_cacertdir ); bc->sb_tls_cacertdir = NULL; } if ( bc->sb_tls_reqcert ) { ch_free( bc->sb_tls_reqcert ); bc->sb_tls_reqcert = NULL; } if ( bc->sb_tls_cipher_suite ) { ch_free( bc->sb_tls_cipher_suite ); bc->sb_tls_cipher_suite = NULL; } if ( bc->sb_tls_protocol_min ) { ch_free( bc->sb_tls_protocol_min ); bc->sb_tls_protocol_min = NULL; } #ifdef HAVE_OPENSSL_CRL if ( bc->sb_tls_crlcheck ) { ch_free( bc->sb_tls_crlcheck ); bc->sb_tls_crlcheck = NULL; } #endif if ( bc->sb_tls_ctx ) { ldap_pvt_tls_ctx_free( bc->sb_tls_ctx ); bc->sb_tls_ctx = NULL; } #endif } void lload_bindconf_tls_defaults( slap_bindconf *bc ) { #ifdef HAVE_TLS if ( bc->sb_tls_do_init ) { if ( !bc->sb_tls_cacert ) ldap_pvt_tls_get_option( lload_tls_ld, LDAP_OPT_X_TLS_CACERTFILE, &bc->sb_tls_cacert ); if ( !bc->sb_tls_cacertdir ) ldap_pvt_tls_get_option( lload_tls_ld, LDAP_OPT_X_TLS_CACERTDIR, &bc->sb_tls_cacertdir ); if ( !bc->sb_tls_cert ) ldap_pvt_tls_get_option( lload_tls_ld, LDAP_OPT_X_TLS_CERTFILE, &bc->sb_tls_cert ); if ( !bc->sb_tls_key ) ldap_pvt_tls_get_option( lload_tls_ld, LDAP_OPT_X_TLS_KEYFILE, &bc->sb_tls_key ); if ( !bc->sb_tls_cipher_suite ) ldap_pvt_tls_get_option( lload_tls_ld, LDAP_OPT_X_TLS_CIPHER_SUITE, &bc->sb_tls_cipher_suite ); if ( !bc->sb_tls_reqcert ) bc->sb_tls_reqcert = ch_strdup( "demand" ); #ifdef HAVE_OPENSSL_CRL if ( !bc->sb_tls_crlcheck ) lload_tls_get_config( lload_tls_ld, LDAP_OPT_X_TLS_CRLCHECK, &bc->sb_tls_crlcheck ); #endif } #endif } /* -------------------------------------- */ static char * strtok_quote( char *line, char *sep, char **quote_ptr, int *iqp ) { int inquote; char *tmp; static char *next; *quote_ptr = NULL; if ( line != NULL ) { next = line; } while ( *next && strchr( sep, *next ) ) { next++; } if ( *next == '\0' ) { next = NULL; return NULL; } tmp = next; for ( inquote = 0; *next; ) { switch ( *next ) { case '"': if ( inquote ) { inquote = 0; } else { inquote = 1; } AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 ); break; case '\\': if ( next[1] ) AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 ); next++; /* dont parse the escaped character */ break; default: if ( !inquote ) { if ( strchr( sep, *next ) != NULL ) { *quote_ptr = next; *next++ = '\0'; return tmp; } } next++; break; } } *iqp = inquote; return tmp; } static char buf[AC_LINE_MAX]; static char *line; static size_t lmax, lcur; #define CATLINE( buf ) \ do { \ size_t len = strlen( buf ); \ while ( lcur + len + 1 > lmax ) { \ lmax += AC_LINE_MAX; \ line = (char *)ch_realloc( line, lmax ); \ } \ strcpy( line + lcur, buf ); \ lcur += len; \ } while (0) static void fp_getline_init( ConfigArgs *c ) { c->lineno = -1; buf[0] = '\0'; } static int fp_getline( FILE *fp, ConfigArgs *c ) { char *p; lcur = 0; CATLINE( buf ); c->lineno++; /* avoid stack of bufs */ if ( strncasecmp( line, "include", STRLENOF("include") ) == 0 ) { buf[0] = '\0'; c->line = line; return 1; } while ( fgets( buf, sizeof(buf), fp ) ) { p = strchr( buf, '\n' ); if ( p ) { if ( p > buf && p[-1] == '\r' ) { --p; } *p = '\0'; } /* XXX ugly */ c->line = line; if ( line[0] && ( p = line + strlen( line ) - 1 )[0] == '\\' && p[-1] != '\\' ) { p[0] = '\0'; lcur--; } else { if ( !isspace( (unsigned char)buf[0] ) ) { return 1; } buf[0] = ' '; } CATLINE( buf ); c->lineno++; } buf[0] = '\0'; c->line = line; return ( line[0] ? 1 : 0 ); } int lload_config_fp_parse_line( ConfigArgs *c ) { char *token; static char *const hide[] = { "bindconf", NULL }; static char *const raw[] = { NULL }; char *quote_ptr; int i = (int)( sizeof(hide) / sizeof(hide[0]) ) - 1; int inquote = 0; c->tline = ch_strdup( c->line ); c->linelen = strlen( c->line ); token = strtok_quote( c->tline, " \t", "e_ptr, &inquote ); if ( token ) for ( i = 0; hide[i]; i++ ) if ( !strcasecmp( token, hide[i] ) ) break; if ( quote_ptr ) *quote_ptr = ' '; Debug( LDAP_DEBUG_CONFIG, "%s (%s%s)\n", c->log, hide[i] ? hide[i] : c->line, hide[i] ? " ***" : "" ); if ( quote_ptr ) *quote_ptr = '\0'; for ( ;; token = strtok_quote( NULL, " \t", "e_ptr, &inquote ) ) { if ( c->argc >= c->argv_size ) { char **tmp; tmp = ch_realloc( c->argv, ( c->argv_size + ARGS_STEP ) * sizeof(*c->argv) ); if ( !tmp ) { Debug( LDAP_DEBUG_ANY, "%s: out of memory\n", c->log ); return -1; } c->argv = tmp; c->argv_size += ARGS_STEP; } if ( token == NULL ) break; c->argv[c->argc++] = token; } c->argv[c->argc] = NULL; if ( inquote ) { /* these directives parse c->line independently of argv tokenizing */ for ( i = 0; raw[i]; i++ ) if ( !strcasecmp( c->argv[0], raw[i] ) ) return 0; Debug( LDAP_DEBUG_ANY, "%s: unterminated quoted string \"%s\"\n", c->log, c->argv[c->argc - 1] ); return -1; } return 0; } void lload_config_destroy( void ) { free( line ); if ( slapd_args_file ) free( slapd_args_file ); if ( slapd_pid_file ) free( slapd_pid_file ); loglevel_destroy(); } /* See if the given URL (in plain and parsed form) matches * any of the server's listener addresses. Return matching * LloadListener or NULL for no match. */ LloadListener * lload_config_check_my_url( const char *url, LDAPURLDesc *lud ) { LloadListener **l = lloadd_get_listeners(); int i, isMe; /* Try a straight compare with LloadListener strings */ for ( i = 0; l && l[i]; i++ ) { if ( !strcasecmp( url, l[i]->sl_url.bv_val ) ) { return l[i]; } } isMe = 0; /* If hostname is empty, or is localhost, or matches * our hostname, this url refers to this host. * Compare it against listeners and ports. */ if ( !lud->lud_host || !lud->lud_host[0] || !strncasecmp( "localhost", lud->lud_host, STRLENOF("localhost") ) || !strcasecmp( global_host, lud->lud_host ) ) { for ( i = 0; l && l[i]; i++ ) { LDAPURLDesc *lu2; ldap_url_parse_ext( l[i]->sl_url.bv_val, &lu2, LDAP_PVT_URL_PARSE_DEF_PORT ); do { if ( strcasecmp( lud->lud_scheme, lu2->lud_scheme ) ) break; if ( lud->lud_port != lu2->lud_port ) break; /* Listener on ANY address */ if ( !lu2->lud_host || !lu2->lud_host[0] ) { isMe = 1; break; } /* URL on ANY address */ if ( !lud->lud_host || !lud->lud_host[0] ) { isMe = 1; break; } /* Listener has specific host, must * match it */ if ( !strcasecmp( lud->lud_host, lu2->lud_host ) ) { isMe = 1; break; } } while (0); ldap_free_urldesc( lu2 ); if ( isMe ) { return l[i]; } } } return NULL; } #ifdef BALANCER_MODULE static int backend_cf_gen( ConfigArgs *c ) { LloadBackend *b = c->ca_private; enum lcf_backend flag = 0; int rc = LDAP_SUCCESS; assert( b != NULL ); if ( c->op == SLAP_CONFIG_EMIT ) { switch ( c->type ) { case CFG_URI: c->value_bv = b->b_uri; break; case CFG_NUMCONNS: c->value_uint = b->b_numconns; break; case CFG_BINDCONNS: c->value_uint = b->b_numbindconns; break; case CFG_RETRY: c->value_uint = b->b_retry_timeout; break; case CFG_MAX_PENDING_CONNS: c->value_uint = b->b_max_conn_pending; break; case CFG_MAX_PENDING_OPS: c->value_uint = b->b_max_pending; break; case CFG_STARTTLS: enum_to_verb( tlskey, b->b_tls_conf, &c->value_bv ); break; default: rc = 1; break; } return rc; } else if ( c->op == LDAP_MOD_DELETE ) { /* We only need to worry about deletions to multi-value or MAY * attributes */ switch ( c->type ) { case CFG_STARTTLS: b->b_tls_conf = LLOAD_CLEARTEXT; break; default: break; } return rc; } switch ( c->type ) { case CFG_URI: rc = backend_config_url( b, &c->value_bv ); if ( rc ) { backend_config_url( b, &b->b_uri ); goto fail; } if ( !BER_BVISNULL( &b->b_uri ) ) { ch_free( b->b_uri.bv_val ); } b->b_uri = c->value_bv; flag = LLOAD_BACKEND_MOD_OTHER; break; case CFG_NUMCONNS: if ( !c->value_uint ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "invalid connection pool configuration" ); goto fail; } b->b_numconns = c->value_uint; flag = LLOAD_BACKEND_MOD_CONNS; break; case CFG_BINDCONNS: if ( !c->value_uint ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "invalid connection pool configuration" ); goto fail; } b->b_numbindconns = c->value_uint; flag = LLOAD_BACKEND_MOD_CONNS; break; case CFG_RETRY: b->b_retry_timeout = c->value_uint; break; case CFG_MAX_PENDING_CONNS: b->b_max_conn_pending = c->value_uint; break; case CFG_MAX_PENDING_OPS: b->b_max_pending = c->value_uint; break; case CFG_STARTTLS: { int i = bverb_to_mask( &c->value_bv, tlskey ); if ( BER_BVISNULL( &tlskey[i].word ) ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "invalid starttls configuration" ); goto fail; } #ifndef HAVE_TLS if ( tlskey[i].mask == LLOAD_STARTTLS_OPTIONAL ) { Debug( LDAP_DEBUG_ANY, "%s: " "lloadd compiled without TLS but starttls specified, " "it will be ignored\n", c->log ); } else if ( tlskey[i].mask != LLOAD_CLEARTEXT ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "invalid starttls configuration when compiled without " "TLS support" ); goto fail; } #endif /* ! HAVE_TLS */ b->b_tls_conf = tlskey[i].mask; } break; default: rc = 1; break; } /* do not set this if it has already been set by another callback, e.g. * lload_backend_ldadd */ if ( lload_change.type == LLOAD_CHANGE_UNDEFINED ) { lload_change.type = LLOAD_CHANGE_MODIFY; } lload_change.object = LLOAD_BACKEND; lload_change.target = b; lload_change.flags.backend |= flag; config_push_cleanup( c, lload_backend_finish ); return rc; fail: if ( lload_change.type == LLOAD_CHANGE_ADD ) { /* Abort the ADD */ lload_change.type = LLOAD_CHANGE_DEL; } Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg ); return 1; } int lload_back_init_cf( BackendInfo *bi ) { /* Make sure we don't exceed the bits reserved for userland */ config_check_userland( CFG_LAST ); bi->bi_cf_ocs = lloadocs; return config_register_schema( config_back_cf_table, lloadocs ); } static int lload_backend_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca ) { LloadBackend *b; Attribute *a; AttributeDescription *ad = NULL; struct berval bv, type, rdn; const char *text; char *name; Debug( LDAP_DEBUG_TRACE, "lload_backend_ldadd: " "a new backend-server is being added\n" ); if ( p->ce_type != Cft_Backend || !p->ce_bi || p->ce_bi->bi_cf_ocs != lloadocs ) return LDAP_CONSTRAINT_VIOLATION; dnRdn( &e->e_name, &rdn ); type.bv_len = strchr( rdn.bv_val, '=' ) - rdn.bv_val; type.bv_val = rdn.bv_val; /* Find attr */ slap_bv2ad( &type, &ad, &text ); if ( ad != slap_schema.si_ad_cn ) return LDAP_NAMING_VIOLATION; a = attr_find( e->e_attrs, ad ); if ( !a || a->a_numvals != 1 ) return LDAP_NAMING_VIOLATION; bv = a->a_vals[0]; if ( bv.bv_val[0] == '{' && ( name = strchr( bv.bv_val, '}' ) ) ) { name++; bv.bv_len -= name - bv.bv_val; bv.bv_val = name; } b = backend_alloc(); ber_dupbv( &b->b_name, &bv ); ca->bi = p->ce_bi; ca->ca_private = b; config_push_cleanup( ca, lload_backend_finish ); /* ca cleanups are only run in the case of online config but we use it to * save the new config when done with the entry */ ca->lineno = 0; lload_change.type = LLOAD_CHANGE_ADD; lload_change.object = LLOAD_BACKEND; lload_change.target = b; return LDAP_SUCCESS; } #ifdef SLAP_CONFIG_DELETE static int lload_backend_lddel( CfEntryInfo *ce, Operation *op ) { LloadBackend *b = ce->ce_private; lload_change.type = LLOAD_CHANGE_DEL; lload_change.object = LLOAD_BACKEND; lload_change.target = b; return LDAP_SUCCESS; } #endif /* SLAP_CONFIG_DELETE */ static int lload_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *c ) { struct berval bv; LloadBackend *b; int i = 0; bv.bv_val = c->cr_msg; LDAP_CIRCLEQ_FOREACH ( b, &backend, b_next ) { char buf[STRLENOF( "server 4294967295" ) + 1] = { 0 }; bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), "cn=" SLAP_X_ORDERED_FMT "server %d", i, i + 1 ); snprintf( buf, sizeof(buf), "server %d", i + 1 ); ber_str2bv( buf, 0, 1, &b->b_name ); c->ca_private = b; c->valx = i; config_build_entry( op, rs, p->e_private, c, &bv, &lloadocs[1], NULL ); i++; } return LDAP_SUCCESS; } #endif /* BALANCER_MODULE */ openldap-2.5.11+dfsg/servers/lloadd/lloadd.service0000644000175000017500000000053414172327167020612 0ustar ryanryan[Unit] Description=LDAP Load Balancer Daemon After=syslog.target network-online.target Documentation=man:lloadd.conf [Service] Type=notify Environment="LLOADD_URLS=ldap:/// ldapi:///" "LLOADD_OPTIONS=" EnvironmentFile=/etc/sysconfig/lloadd ExecStart=%LIBEXECDIR%/lloadd -d 0 -h ${LLOADD_URLS} $LLOADD_OPTIONS [Install] WantedBy=multi-user.target openldap-2.5.11+dfsg/servers/lloadd/extended.c0000644000175000017500000001327214172327167017740 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include "lutil.h" #include "lload.h" Avlnode *lload_exop_handlers = NULL; #ifdef HAVE_TLS void *lload_tls_ctx; LDAP *lload_tls_ld, *lload_tls_backend_ld; #ifdef BALANCER_MODULE int lload_use_slap_tls_ctx = 0; #endif #endif /* HAVE_TLS */ int handle_starttls( LloadConnection *c, LloadOperation *op ) { struct event_base *base = event_get_base( c->c_read_event ); LloadOperation *found; BerElement *output; char *msg = NULL; int rc = LDAP_SUCCESS; CONNECTION_LOCK(c); found = ldap_tavl_delete( &c->c_ops, op, operation_client_cmp ); assert( op == found ); c->c_n_ops_executing--; #ifdef HAVE_TLS if ( c->c_is_tls == LLOAD_TLS_ESTABLISHED ) { rc = LDAP_OPERATIONS_ERROR; msg = "TLS layer already in effect"; } else if ( c->c_state == LLOAD_C_BINDING ) { rc = LDAP_OPERATIONS_ERROR; msg = "bind in progress"; } else if ( c->c_ops ) { rc = LDAP_OPERATIONS_ERROR; msg = "cannot start TLS when operations are outstanding"; } else if ( !LLOAD_TLS_CTX ) { rc = LDAP_UNAVAILABLE; msg = "Could not initialize TLS"; } #else /* ! HAVE_TLS */ rc = LDAP_UNAVAILABLE; msg = "Could not initialize TLS"; #endif /* ! HAVE_TLS */ CONNECTION_UNLOCK(c); Debug( LDAP_DEBUG_STATS, "handle_starttls: " "handling StartTLS exop connid=%lu rc=%d msg=%s\n", c->c_connid, rc, msg ); if ( rc ) { /* We've already removed the operation from the queue */ operation_send_reject( op, rc, msg, 1 ); return LDAP_SUCCESS; } #ifdef HAVE_TLS event_del( c->c_read_event ); event_del( c->c_write_event ); /* * At this point, we are the only thread handling the connection: * - there are no upstream operations * - the I/O callbacks have been successfully removed * * This means we can safely reconfigure both I/O events now. */ checked_lock( &c->c_io_mutex ); output = c->c_pendingber; if ( output == NULL && (output = ber_alloc()) == NULL ) { checked_unlock( &c->c_io_mutex ); operation_unlink( op ); CONNECTION_LOCK_DESTROY(c); return -1; } c->c_pendingber = output; ber_printf( output, "t{tit{ess}}", LDAP_TAG_MESSAGE, LDAP_TAG_MSGID, op->o_client_msgid, LDAP_RES_EXTENDED, LDAP_SUCCESS, "", "" ); c->c_io_state &= ~LLOAD_C_READ_HANDOVER; checked_unlock( &c->c_io_mutex ); CONNECTION_LOCK(c); c->c_read_timeout = lload_timeout_net; event_assign( c->c_read_event, base, c->c_fd, EV_READ|EV_PERSIST, client_tls_handshake_cb, c ); event_add( c->c_read_event, c->c_read_timeout ); event_assign( c->c_write_event, base, c->c_fd, EV_WRITE, client_tls_handshake_cb, c ); /* We already have something to write */ event_add( c->c_write_event, lload_write_timeout ); op->o_res = LLOAD_OP_COMPLETED; CONNECTION_UNLOCK(c); operation_unlink( op ); return -1; #endif /* HAVE_TLS */ } int request_extended( LloadConnection *c, LloadOperation *op ) { ExopHandler *handler, needle = {}; BerElement *copy; struct berval bv; ber_tag_t tag; if ( (copy = ber_alloc()) == NULL ) { operation_send_reject( op, LDAP_OTHER, "internal error", 0 ); CONNECTION_LOCK_DESTROY(c); return -1; } ber_init2( copy, &op->o_request, 0 ); tag = ber_skip_element( copy, &bv ); if ( tag != LDAP_TAG_EXOP_REQ_OID ) { Debug( LDAP_DEBUG_STATS, "request_extended: " "no OID present in extended request\n" ); operation_send_reject( op, LDAP_PROTOCOL_ERROR, "decoding error", 0 ); CONNECTION_LOCK_DESTROY(c); return -1; } needle.oid = bv; handler = ldap_avl_find( lload_exop_handlers, &needle, exop_handler_cmp ); if ( handler ) { Debug( LDAP_DEBUG_TRACE, "request_extended: " "handling exop OID %.*s internally\n", (int)bv.bv_len, bv.bv_val ); ber_free( copy, 0 ); return handler->func( c, op ); } ber_free( copy, 0 ); return request_process( c, op ); } ExopHandler lload_exops[] = { { BER_BVC(LDAP_EXOP_START_TLS), handle_starttls }, { BER_BVNULL } }; int exop_handler_cmp( const void *left, const void *right ) { const struct lload_exop_handlers_t *l = left, *r = right; return ber_bvcmp( &l->oid, &r->oid ); } int lload_register_exop_handlers( struct lload_exop_handlers_t *handler ) { for ( ; !BER_BVISNULL( &handler->oid ); handler++ ) { Debug( LDAP_DEBUG_TRACE, "lload_register_exop_handlers: " "registering handler for exop oid=%s\n", handler->oid.bv_val ); if ( ldap_avl_insert( &lload_exop_handlers, handler, exop_handler_cmp, ldap_avl_dup_error ) ) { Debug( LDAP_DEBUG_ANY, "lload_register_exop_handlers: " "failed to register handler for exop oid=%s\n", handler->oid.bv_val ); return -1; } } return LDAP_SUCCESS; } int lload_exop_init( void ) { if ( lload_register_exop_handlers( lload_exops ) ) { return -1; } return LDAP_SUCCESS; } openldap-2.5.11+dfsg/servers/lloadd/bind.c0000644000175000017500000010005414172327167017047 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include #include #include "lutil.h" #include "lload.h" struct berval mech_external = BER_BVC("EXTERNAL"); int bind_mech_external( LloadConnection *client, LloadOperation *op, struct berval *credentials ) { BerValue binddn; void *ssl; char *ptr, *message = ""; int result = LDAP_SUCCESS; CONNECTION_ASSERT_LOCKED(client); client->c_state = LLOAD_C_READY; client->c_type = LLOAD_C_OPEN; op->o_res = LLOAD_OP_COMPLETED; /* * We only support implicit assertion. * * Although RFC 4513 says the credentials field must be missing, RFC 4422 * doesn't and libsasl2 will pass a zero-length string to send. We have to * allow that. */ if ( !BER_BVISEMPTY( credentials ) ) { result = LDAP_UNWILLING_TO_PERFORM; message = "proxy authorization is not supported"; goto done; } #ifdef HAVE_TLS ssl = ldap_pvt_tls_sb_ctx( client->c_sb ); if ( !ssl || ldap_pvt_tls_get_peer_dn( ssl, &binddn, NULL, 0 ) ) { result = LDAP_INVALID_CREDENTIALS; message = "no externally negotiated identity"; goto done; } client->c_auth.bv_len = binddn.bv_len + STRLENOF("dn:"); client->c_auth.bv_val = ch_malloc( client->c_auth.bv_len + 1 ); ptr = lutil_strcopy( client->c_auth.bv_val, "dn:" ); ptr = lutil_strncopy( ptr, binddn.bv_val, binddn.bv_len ); *ptr = '\0'; ber_memfree( binddn.bv_val ); if ( !ber_bvstrcasecmp( &client->c_auth, &lloadd_identity ) ) { client->c_type = LLOAD_C_PRIVILEGED; } #else /* ! HAVE_TLS */ result = LDAP_AUTH_METHOD_NOT_SUPPORTED; message = "requested SASL mechanism not supported"; #endif /* ! HAVE_TLS */ done: CONNECTION_UNLOCK(client); operation_send_reject( op, result, message, 1 ); return LDAP_SUCCESS; } static int client_bind( LloadOperation *op, LloadConnection *upstream, struct berval *binddn, ber_tag_t tag, struct berval *auth ) { ber_printf( upstream->c_pendingber, "t{titOtO}", LDAP_TAG_MESSAGE, LDAP_TAG_MSGID, op->o_upstream_msgid, LDAP_REQ_BIND, &op->o_request, LDAP_TAG_CONTROLS, BER_BV_OPTIONAL( &op->o_ctrls ) ); return 0; } #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS static int client_bind_as_vc( LloadOperation *op, LloadConnection *upstream, struct berval *binddn, ber_tag_t tag, struct berval *auth ) { CONNECTION_LOCK(upstream); ber_printf( upstream->c_pendingber, "t{tit{tst{{tOOtOtO}}}}", LDAP_TAG_MESSAGE, LDAP_TAG_MSGID, op->o_upstream_msgid, LDAP_REQ_EXTENDED, LDAP_TAG_EXOP_REQ_OID, LDAP_EXOP_VERIFY_CREDENTIALS, LDAP_TAG_EXOP_REQ_VALUE, LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE, BER_BV_OPTIONAL( &upstream->c_vc_cookie ), &binddn, tag, &auth, LDAP_TAG_EXOP_VERIFY_CREDENTIALS_CONTROLS, BER_BV_OPTIONAL( &op->o_ctrls ) ); CONNECTION_UNLOCK(upstream); return 0; } #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */ /* * The client connection can be in the following states: * 1) there are between zero and many non-bind operations pending * client->c_state == LLOAD_C_READY && client->c_pin_id == 0 * 2) there is one bind operation pending (waiting on an upstream response) * a) It is a simple bind * b) It is a SASL bind * 3) there is one SASL bind in progress (received a LDAP_SASL_BIND_IN_PROGRESS * response) * * In cases 2 and 3, client->c_state == LLOAD_C_BINDING, a SASL bind is in * progress/pending if c_sasl_bind_mech is set. * * In the first case, client_reset abandons all operations on the respective * upstreams, case 2a has client_reset send an anonymous bind to upstream to * terminate the bind. In cases 2b and 3, c_pin_id is set and we retrieve the * op. The rest is the same for both. * * If c_pin_id is unset, we request an upstream connection assigned, otherwise, * we try to reuse the pinned upstream. In the case of no upstream, we reject * the request. A SASL bind request means we acquire a new pin_id if we don't * have one already. * * We have to reset c_auth (which holds the current or pending identity) and * make sure we set it up eventually: * - In the case of a simple bind, we already know the final identity being * requested so we set it up immediately * - In SASL binds, for mechanisms we implement ourselves (EXTERNAL), we set it * up at some point * - Otherwise, we have to ask the upstream what it thinks as the bind * succeeds, we send an LDAP "Who Am I?" exop, this is one of the few * requests we send on our own. If we implement the mechanism, we provide the * identity (EXTERNAL uses the client certificate DN) * * At the end of the request processing, if nothing goes wrong, we're in state * 2b (with c_pin_id set to the op's o_pin_id), or state 2a (we could reset * c_pin_id/o_pin_id if we wanted but we don't always do that at the moment). * If something does go wrong, we're either tearing down the client or we * reject the request and switch to state 1 (clearing c_pin_id). * * As usual, we have to make any changes to the target connection before we've * sent the PDU over it - while we are in charge of the read side and nothing * happens there without our ceding control, the other read side could wake up * at any time and preempt us. * * On a response (in handle_bind_response): * - to a simple bind, clear c_auth on a failure otherwise keep it while we * just reset the client to state 1 * - failure response to a SASL bind - reset client to state 1 * - LDAP_SASL_BIND_IN_PROGRESS - clear o_*_msgid from the op (have to * remove+reinsert it from the respective c_ops!), we need it since it is the * vessel maintaining the pin between client and upstream * - all of the above forward the response immediately * - LDAP_SUCCESS for a SASL bind - we send a "Who Am I?" request to retrieve * the client's DN, only on receiving the response do we finalise the * exchange by forwarding the successful bind response * * We can't do the same for VC Exop since the exchange is finished at the end * and we need a change to the VC Exop spec to have the server (optionally?) * respond with the final authzid (saving us a roundtrip as well). */ int request_bind( LloadConnection *client, LloadOperation *op ) { LloadConnection *upstream = NULL; BerElement *ber, *copy; struct berval binddn, auth, mech = BER_BVNULL; ber_int_t version; ber_tag_t tag; unsigned long pin; int res, rc = LDAP_SUCCESS; CONNECTION_LOCK(client); pin = client->c_pin_id; if ( pin ) { LloadOperation *pinned_op, needle = { .o_client_connid = client->c_connid, .o_client_msgid = 0, .o_pin_id = client->c_pin_id, }; Debug( LDAP_DEBUG_CONNS, "request_bind: " "client connid=%lu is pinned pin=%lu\n", client->c_connid, pin ); pinned_op = ldap_tavl_delete( &client->c_ops, &needle, operation_client_cmp ); if ( pinned_op ) { assert( op->o_tag == pinned_op->o_tag ); pinned_op->o_client_msgid = op->o_client_msgid; /* Preserve the new BerElement and its pointers, reclaim the old * one in operation_destroy_from_client if it's still there */ needle.o_ber = pinned_op->o_ber; pinned_op->o_ber = op->o_ber; op->o_ber = needle.o_ber; pinned_op->o_request = op->o_request; pinned_op->o_ctrls = op->o_ctrls; /* No one has seen this operation yet, plant the pin back in its stead */ client->c_n_ops_executing--; op->o_res = LLOAD_OP_COMPLETED; ldap_tavl_delete( &client->c_ops, op, operation_client_cmp ); op->o_client = NULL; assert( op->o_upstream == NULL ); rc = ldap_tavl_insert( &client->c_ops, pinned_op, operation_client_cmp, ldap_avl_dup_error ); assert( rc == LDAP_SUCCESS ); /* No one has seen this operation yet */ op->o_refcnt--; operation_destroy( op ); /* We didn't start a new operation, just continuing an existing one */ lload_stats.counters[LLOAD_STATS_OPS_BIND].lc_ops_received--; op = pinned_op; } } ldap_tavl_delete( &client->c_ops, op, operation_client_cmp ); client->c_n_ops_executing--; client_reset( client ); client->c_state = LLOAD_C_BINDING; client->c_type = LLOAD_C_OPEN; if ( (copy = ber_alloc()) == NULL ) { goto fail; } ber_init2( copy, &op->o_request, 0 ); tag = ber_get_int( copy, &version ); if ( tag == LBER_ERROR ) { Debug( LDAP_DEBUG_PACKETS, "request_bind: " "failed to parse version field\n" ); goto fail; } else if ( version != LDAP_VERSION3 ) { CONNECTION_UNLOCK(client); operation_send_reject( op, LDAP_PROTOCOL_ERROR, "LDAP version unsupported", 1 ); CONNECTION_LOCK(client); goto fail; } tag = ber_get_stringbv( copy, &binddn, LBER_BV_NOTERM ); if ( tag == LBER_ERROR ) { Debug( LDAP_DEBUG_PACKETS, "request_bind: " "failed to parse bind name field\n" ); goto fail; } if ( !BER_BVISNULL( &client->c_auth ) ) { ch_free( client->c_auth.bv_val ); BER_BVZERO( &client->c_auth ); } tag = ber_skip_element( copy, &auth ); if ( tag == LDAP_AUTH_SIMPLE ) { if ( !BER_BVISEMPTY( &binddn ) ) { char *ptr; client->c_auth.bv_len = STRLENOF("dn:") + binddn.bv_len; client->c_auth.bv_val = ch_malloc( client->c_auth.bv_len + 1 ); ptr = lutil_strcopy( client->c_auth.bv_val, "dn:" ); ptr = lutil_strncopy( ptr, binddn.bv_val, binddn.bv_len ); *ptr = '\0'; } if ( !BER_BVISNULL( &client->c_sasl_bind_mech ) ) { ber_memfree( client->c_sasl_bind_mech.bv_val ); BER_BVZERO( &client->c_sasl_bind_mech ); } } else if ( tag == LDAP_AUTH_SASL ) { ber_init2( copy, &auth, 0 ); if ( ber_get_stringbv( copy, &mech, LBER_BV_NOTERM ) == LBER_ERROR ) { goto fail; } if ( !ber_bvcmp( &mech, &mech_external ) ) { struct berval credentials = BER_BVNULL; ber_get_stringbv( copy, &credentials, LBER_BV_NOTERM ); rc = bind_mech_external( client, op, &credentials ); /* terminate the upstream side if client switched mechanisms */ if ( pin ) { operation_abandon( op ); } ber_free( copy, 0 ); return rc; } else if ( BER_BVISNULL( &client->c_sasl_bind_mech ) ) { ber_dupbv( &client->c_sasl_bind_mech, &mech ); } else if ( ber_bvcmp( &mech, &client->c_sasl_bind_mech ) ) { ber_bvreplace( &client->c_sasl_bind_mech, &mech ); } } else { goto fail; } rc = ldap_tavl_insert( &client->c_ops, op, operation_client_cmp, ldap_avl_dup_error ); assert( rc == LDAP_SUCCESS ); client->c_n_ops_executing++; CONNECTION_UNLOCK(client); if ( pin ) { checked_lock( &op->o_link_mutex ); upstream = op->o_upstream; checked_unlock( &op->o_link_mutex ); if ( upstream ) { checked_lock( &upstream->c_io_mutex ); CONNECTION_LOCK(upstream); if ( !IS_ALIVE( upstream, c_live ) ) { CONNECTION_UNLOCK(upstream); checked_unlock( &upstream->c_io_mutex ); upstream = NULL; } } } /* If we were pinned but lost the link, don't look for a new upstream, we * have to reject the op and clear pin */ if ( upstream ) { /* No need to do anything */ } else if ( !pin ) { upstream = backend_select( op, &res ); } else { Debug( LDAP_DEBUG_STATS, "request_bind: " "connid=%lu, msgid=%d pinned upstream lost\n", op->o_client_connid, op->o_client_msgid ); operation_send_reject( op, LDAP_OTHER, "connection to the remote server has been severed", 1 ); pin = 0; goto done; } if ( !upstream ) { Debug( LDAP_DEBUG_STATS, "request_bind: " "connid=%lu, msgid=%d no available connection found\n", op->o_client_connid, op->o_client_msgid ); operation_send_reject( op, res, "no connections available", 1 ); assert( client->c_pin_id == 0 ); goto done; } assert_locked( &upstream->c_io_mutex ); /* * At this point, either: * - upstream is READY and pin == 0 * - upstream is BINDING, pin != 0 and op->o_upstream_msgid == 0 * * A pinned upstream we marked for closing at some point ago should have * closed by now. */ ber = upstream->c_pendingber; if ( ber == NULL && (ber = ber_alloc()) == NULL ) { checked_unlock( &upstream->c_io_mutex ); if ( !pin ) { LloadBackend *b = upstream->c_backend; upstream->c_n_ops_executing--; CONNECTION_UNLOCK(upstream); checked_lock( &b->b_mutex ); b->b_n_ops_executing--; operation_update_backend_counters( op, b ); checked_unlock( &b->b_mutex ); } else { CONNECTION_UNLOCK(upstream); } Debug( LDAP_DEBUG_ANY, "request_bind: " "ber_alloc failed\n" ); operation_unlink( op ); CONNECTION_LOCK(client); goto fail; } upstream->c_pendingber = ber; if ( !pin ) { lload_stats.counters[LLOAD_STATS_OPS_BIND].lc_ops_forwarded++; } if ( pin ) { ldap_tavl_delete( &upstream->c_ops, op, operation_upstream_cmp ); if ( tag == LDAP_AUTH_SIMPLE ) { pin = op->o_pin_id = 0; } } else if ( tag == LDAP_AUTH_SASL && !op->o_pin_id ) { checked_lock( &lload_pin_mutex ); pin = op->o_pin_id = lload_next_pin++; Debug( LDAP_DEBUG_CONNS, "request_bind: " "client connid=%lu allocated pin=%lu linking it to upstream " "connid=%lu\n", op->o_client_connid, pin, upstream->c_connid ); checked_unlock( &lload_pin_mutex ); } op->o_upstream = upstream; op->o_upstream_connid = upstream->c_connid; op->o_upstream_msgid = upstream->c_next_msgid++; op->o_res = LLOAD_OP_FAILED; /* Was it unlinked in the meantime? No need to send a response since the * client is dead */ if ( !IS_ALIVE( op, o_refcnt ) ) { LloadBackend *b = upstream->c_backend; upstream->c_n_ops_executing--; checked_unlock( &upstream->c_io_mutex ); CONNECTION_UNLOCK(upstream); checked_lock( &b->b_mutex ); b->b_n_ops_executing--; checked_unlock( &b->b_mutex ); assert( !IS_ALIVE( client, c_live ) ); checked_lock( &op->o_link_mutex ); if ( op->o_upstream ) { op->o_upstream = NULL; } checked_unlock( &op->o_link_mutex ); rc = -1; goto done; } if ( BER_BVISNULL( &mech ) ) { if ( !BER_BVISNULL( &upstream->c_sasl_bind_mech ) ) { ber_memfree( upstream->c_sasl_bind_mech.bv_val ); BER_BVZERO( &upstream->c_sasl_bind_mech ); } } else if ( ber_bvcmp( &upstream->c_sasl_bind_mech, &mech ) ) { ber_bvreplace( &upstream->c_sasl_bind_mech, &mech ); } Debug( LDAP_DEBUG_TRACE, "request_bind: " "added bind from client connid=%lu to upstream connid=%lu " "as msgid=%d\n", op->o_client_connid, op->o_upstream_connid, op->o_upstream_msgid ); if ( ldap_tavl_insert( &upstream->c_ops, op, operation_upstream_cmp, ldap_avl_dup_error ) ) { assert(0); } upstream->c_state = LLOAD_C_BINDING; CONNECTION_UNLOCK(upstream); #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS if ( lload_features & LLOAD_FEATURE_VC ) { rc = client_bind_as_vc( op, upstream, &binddn, tag, &auth ); } else #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */ { rc = client_bind( op, upstream, &binddn, tag, &auth ); } checked_unlock( &upstream->c_io_mutex ); done: CONNECTION_LOCK(client); if ( rc == LDAP_SUCCESS ) { client->c_pin_id = pin; CONNECTION_UNLOCK(client); if ( upstream ) { connection_write_cb( -1, 0, upstream ); } } else { fail: rc = -1; client->c_pin_id = 0; CONNECTION_DESTROY(client); } ber_free( copy, 0 ); return rc; } /* * Remember the response, but first ask the server what * authorization identity has been negotiated. * * Also, this request will fail if the server thinks a SASL * confidentiality/integrity layer has been negotiated so we catch * it early and no other clients are affected. */ int finish_sasl_bind( LloadConnection *upstream, LloadOperation *op, BerElement *ber ) { BerElement *output; LloadOperation *removed; ber_int_t msgid; int rc; CONNECTION_ASSERT_LOCKED(upstream); removed = ldap_tavl_delete( &upstream->c_ops, op, operation_upstream_cmp ); if ( !removed ) { assert( upstream->c_state != LLOAD_C_BINDING ); /* FIXME: has client replaced this bind since? */ assert(0); } assert( removed == op && upstream->c_state == LLOAD_C_BINDING ); CONNECTION_UNLOCK(upstream); checked_lock( &upstream->c_io_mutex ); output = upstream->c_pendingber; if ( output == NULL && (output = ber_alloc()) == NULL ) { checked_unlock( &upstream->c_io_mutex ); CONNECTION_LOCK_DESTROY(upstream); return -1; } upstream->c_pendingber = output; msgid = upstream->c_next_msgid++; ber_printf( output, "t{tit{ts}}", LDAP_TAG_MESSAGE, LDAP_TAG_MSGID, msgid, LDAP_REQ_EXTENDED, LDAP_TAG_EXOP_REQ_OID, LDAP_EXOP_WHO_AM_I ); /* Make sure noone flushes the buffer before we re-insert the operation */ CONNECTION_LOCK(upstream); checked_unlock( &upstream->c_io_mutex ); op->o_upstream_msgid = msgid; /* remember the response for later */ ber_free( op->o_ber, 1 ); op->o_ber = ber; /* Could we have been unlinked in the meantime? */ rc = ldap_tavl_insert( &upstream->c_ops, op, operation_upstream_cmp, ldap_avl_dup_error ); assert( rc == LDAP_SUCCESS ); CONNECTION_UNLOCK(upstream); Debug( LDAP_DEBUG_TRACE, "finish_sasl_bind: " "SASL exchange in lieu of client connid=%lu to upstream " "connid=%lu finished, resolving final authzid name msgid=%d\n", op->o_client_connid, op->o_upstream_connid, op->o_upstream_msgid ); connection_write_cb( -1, 0, upstream ); return LDAP_SUCCESS; } int handle_bind_response( LloadConnection *client, LloadOperation *op, BerElement *ber ) { LloadConnection *upstream; BerValue response; BerElement *copy; LloadOperation *removed; ber_int_t result; ber_tag_t tag; int rc = LDAP_SUCCESS; if ( (copy = ber_alloc()) == NULL ) { rc = -1; goto done; } tag = ber_peek_element( ber, &response ); assert( tag == LDAP_RES_BIND ); ber_init2( copy, &response, 0 ); tag = ber_get_enum( copy, &result ); ber_free( copy, 0 ); if ( tag == LBER_ERROR ) { rc = -1; goto done; } Debug( LDAP_DEBUG_STATS, "handle_bind_response: " "received response for bind request msgid=%d by client " "connid=%lu, result=%d\n", op->o_client_msgid, op->o_client_connid, result ); checked_lock( &op->o_link_mutex ); upstream = op->o_upstream; checked_unlock( &op->o_link_mutex ); if ( !upstream ) { return LDAP_SUCCESS; } CONNECTION_LOCK(upstream); if ( !ldap_tavl_find( upstream->c_ops, op, operation_upstream_cmp ) ) { /* * operation might not be found because: * - it has timed out (only happens when debugging/hung/...) * a response has been sent for us, we must not send another * - it has been abandoned (new bind, unbind) * no response is expected * - ??? */ CONNECTION_UNLOCK(upstream); return LDAP_SUCCESS; } /* * We might be marked for closing, forward the response if we can, but do * no more if it's a SASL bind - just finish the operation and send failure * in that case (since we can't resolve the bind identity correctly). */ if ( upstream->c_state == LLOAD_C_CLOSING ) { /* FIXME: this is too ad-hoc */ if ( ( result == LDAP_SUCCESS || result == LDAP_SASL_BIND_IN_PROGRESS ) && !BER_BVISNULL( &upstream->c_sasl_bind_mech ) ) { CONNECTION_UNLOCK(upstream); operation_send_reject( op, LDAP_OTHER, "upstream connection is closing", 0 ); ber_free( ber, 1 ); return LDAP_SUCCESS; } assert( op->o_client_msgid && op->o_upstream_msgid ); op->o_pin_id = 0; } else if ( result == LDAP_SASL_BIND_IN_PROGRESS ) { ldap_tavl_delete( &upstream->c_ops, op, operation_upstream_cmp ); op->o_upstream_msgid = 0; rc = ldap_tavl_insert( &upstream->c_ops, op, operation_upstream_cmp, ldap_avl_dup_error ); assert( rc == LDAP_SUCCESS ); } else { int sasl_finished = 0; if ( !BER_BVISNULL( &upstream->c_sasl_bind_mech ) ) { sasl_finished = 1; ber_memfree( upstream->c_sasl_bind_mech.bv_val ); BER_BVZERO( &upstream->c_sasl_bind_mech ); } assert( op->o_client_msgid && op->o_upstream_msgid ); op->o_pin_id = 0; if ( (lload_features & LLOAD_FEATURE_PROXYAUTHZ) && sasl_finished && result == LDAP_SUCCESS ) { return finish_sasl_bind( upstream, op, ber ); } op->o_res = LLOAD_OP_COMPLETED; } CONNECTION_UNLOCK(upstream); if ( !op->o_pin_id ) { operation_unlink_upstream( op, upstream ); } CONNECTION_LOCK(client); removed = ldap_tavl_delete( &client->c_ops, op, operation_client_cmp ); assert( !removed || op == removed ); if ( client->c_state == LLOAD_C_BINDING ) { assert( removed ); switch ( result ) { case LDAP_SASL_BIND_IN_PROGRESS: op->o_saved_msgid = op->o_client_msgid; op->o_client_msgid = 0; rc = ldap_tavl_insert( &client->c_ops, op, operation_client_cmp, ldap_avl_dup_error ); assert( rc == LDAP_SUCCESS ); break; case LDAP_SUCCESS: default: { client->c_state = LLOAD_C_READY; client->c_type = LLOAD_C_OPEN; client->c_pin_id = 0; client->c_n_ops_executing--; if ( !BER_BVISNULL( &client->c_auth ) ) { if ( result != LDAP_SUCCESS ) { ber_memfree( client->c_auth.bv_val ); BER_BVZERO( &client->c_auth ); } else if ( !ber_bvstrcasecmp( &client->c_auth, &lloadd_identity ) ) { client->c_type = LLOAD_C_PRIVILEGED; } } if ( !BER_BVISNULL( &client->c_sasl_bind_mech ) ) { ber_memfree( client->c_sasl_bind_mech.bv_val ); BER_BVZERO( &client->c_sasl_bind_mech ); } break; } } } else { if ( removed ) { client->c_n_ops_executing--; } assert( client->c_state == LLOAD_C_DYING || client->c_state == LLOAD_C_CLOSING ); } CONNECTION_UNLOCK(client); done: if ( rc ) { operation_send_reject( op, LDAP_OTHER, "internal error", 1 ); ber_free( ber, 1 ); return LDAP_SUCCESS; } return forward_final_response( client, op, ber ); } int handle_whoami_response( LloadConnection *client, LloadOperation *op, BerElement *ber ) { LloadConnection *upstream; BerValue matched, diagmsg; BerElement *saved_response = op->o_ber; LloadOperation *removed; ber_int_t result; ber_tag_t tag; ber_len_t len; Debug( LDAP_DEBUG_TRACE, "handle_whoami_response: " "connid=%ld received whoami response in lieu of connid=%ld\n", op->o_upstream_connid, client->c_connid ); tag = ber_scanf( ber, "{emm" /* "}" */, &result, &matched, &diagmsg ); if ( tag == LBER_ERROR ) { operation_send_reject( op, LDAP_OTHER, "upstream protocol error", 0 ); return -1; } checked_lock( &op->o_link_mutex ); upstream = op->o_upstream; checked_unlock( &op->o_link_mutex ); if ( !upstream ) { return LDAP_SUCCESS; } op->o_res = LLOAD_OP_COMPLETED; /* Clear upstream status */ operation_unlink_upstream( op, upstream ); if ( result == LDAP_PROTOCOL_ERROR ) { LloadBackend *b; CONNECTION_LOCK(upstream); b = upstream->c_backend; Debug( LDAP_DEBUG_ANY, "handle_whoami_response: " "Who Am I? extended operation not supported on backend %s, " "proxyauthz with clients that do SASL binds will not work " "msg=%s!\n", b->b_uri.bv_val, diagmsg.bv_val ); CONNECTION_UNLOCK(upstream); operation_send_reject( op, LDAP_OTHER, "upstream protocol error", 0 ); return -1; } tag = ber_peek_tag( ber, &len ); CONNECTION_LOCK(client); assert( client->c_state == LLOAD_C_BINDING || client->c_state == LLOAD_C_CLOSING ); assert( BER_BVISNULL( &client->c_auth ) ); if ( !BER_BVISNULL( &client->c_auth ) ) { ber_memfree( client->c_auth.bv_val ); BER_BVZERO( &client->c_auth ); } if ( tag == LDAP_TAG_EXOP_RES_VALUE ) { tag = ber_scanf( ber, "o", &client->c_auth ); if ( tag == LBER_ERROR ) { CONNECTION_DESTROY(client); return -1; } } removed = ldap_tavl_delete( &client->c_ops, op, operation_client_cmp ); assert( !removed || op == removed ); op->o_pin_id = 0; if ( removed ) { client->c_n_ops_executing--; } Debug( LDAP_DEBUG_TRACE, "handle_whoami_response: " "connid=%ld new authid=%s\n", client->c_connid, client->c_auth.bv_val ); if ( client->c_state == LLOAD_C_BINDING ) { client->c_state = LLOAD_C_READY; client->c_type = LLOAD_C_OPEN; client->c_pin_id = 0; if ( !BER_BVISNULL( &client->c_auth ) && !ber_bvstrcasecmp( &client->c_auth, &lloadd_identity ) ) { client->c_type = LLOAD_C_PRIVILEGED; } if ( !BER_BVISNULL( &client->c_sasl_bind_mech ) ) { ber_memfree( client->c_sasl_bind_mech.bv_val ); BER_BVZERO( &client->c_sasl_bind_mech ); } } CONNECTION_UNLOCK(client); /* defer the disposal of ber to operation_destroy */ op->o_ber = ber; return forward_final_response( client, op, saved_response ); } #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS int handle_vc_bind_response( LloadConnection *client, LloadOperation *op, BerElement *ber ) { BerElement *output; BerValue matched, diagmsg, creds = BER_BVNULL, controls = BER_BVNULL; ber_int_t result; ber_tag_t tag; ber_len_t len; int rc = 0; tag = ber_scanf( ber, "{emm" /* "}" */, &result, &matched, &diagmsg ); if ( tag == LBER_ERROR ) { rc = -1; goto done; } tag = ber_peek_tag( ber, &len ); if ( result == LDAP_PROTOCOL_ERROR ) { LloadConnection *upstream; checked_lock( &op->o_link_mutex ); upstream = op->o_upstream; checked_unlock( &op->o_link_mutex ); if ( upstream ) { LloadBackend *b; CONNECTION_LOCK(upstream); b = upstream->c_backend; Debug( LDAP_DEBUG_ANY, "handle_vc_bind_response: " "VC extended operation not supported on backend %s\n", b->b_uri.bv_val ); CONNECTION_UNLOCK(upstream); } } Debug( LDAP_DEBUG_STATS, "handle_vc_bind_response: " "received response for bind request msgid=%d by client " "connid=%lu, result=%d\n", op->o_client_msgid, op->o_client_connid, result ); CONNECTION_LOCK(client); if ( tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE ) { if ( !BER_BVISNULL( &client->c_vc_cookie ) ) { ber_memfree( client->c_vc_cookie.bv_val ); } tag = ber_scanf( ber, "o", &client->c_vc_cookie ); if ( tag == LBER_ERROR ) { rc = -1; CONNECTION_UNLOCK(client); goto done; } tag = ber_peek_tag( ber, &len ); } if ( tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_SCREDS ) { tag = ber_scanf( ber, "m", &creds ); if ( tag == LBER_ERROR ) { rc = -1; CONNECTION_UNLOCK(client); goto done; } tag = ber_peek_tag( ber, &len ); } if ( tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_CONTROLS ) { tag = ber_scanf( ber, "m", &controls ); if ( tag == LBER_ERROR ) { rc = -1; CONNECTION_UNLOCK(client); goto done; } } if ( client->c_state == LLOAD_C_BINDING ) { switch ( result ) { case LDAP_SASL_BIND_IN_PROGRESS: break; case LDAP_SUCCESS: default: { client->c_state = LLOAD_C_READY; client->c_type = LLOAD_C_OPEN; client->c_pin_id = 0; if ( result != LDAP_SUCCESS ) { ber_memfree( client->c_auth.bv_val ); BER_BVZERO( &client->c_auth ); } else if ( !ber_bvstrcasecmp( &client->c_auth, &lloadd_identity ) ) { client->c_type = LLOAD_C_PRIVILEGED; } if ( !BER_BVISNULL( &client->c_vc_cookie ) ) { ber_memfree( client->c_vc_cookie.bv_val ); BER_BVZERO( &client->c_vc_cookie ); } if ( !BER_BVISNULL( &client->c_sasl_bind_mech ) ) { ber_memfree( client->c_sasl_bind_mech.bv_val ); BER_BVZERO( &client->c_sasl_bind_mech ); } break; } } } else { assert( client->c_state == LLOAD_C_INVALID || client->c_state == LLOAD_C_CLOSING ); } CONNECTION_UNLOCK(client); checked_lock( &client->c_io_mutex ); output = client->c_pendingber; if ( output == NULL && (output = ber_alloc()) == NULL ) { rc = -1; checked_unlock( &client->c_io_mutex ); goto done; } client->c_pendingber = output; rc = ber_printf( output, "t{tit{eOOtO}tO}", LDAP_TAG_MESSAGE, LDAP_TAG_MSGID, op->o_client_msgid, LDAP_RES_BIND, result, &matched, &diagmsg, LDAP_TAG_SASL_RES_CREDS, BER_BV_OPTIONAL( &creds ), LDAP_TAG_CONTROLS, BER_BV_OPTIONAL( &controls ) ); checked_unlock( &client->c_io_mutex ); if ( rc >= 0 ) { connection_write_cb( -1, 0, client ); rc = 0; } done: operation_unlink( op ); ber_free( ber, 1 ); return rc; } #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */ openldap-2.5.11+dfsg/servers/lloadd/daemon.c0000644000175000017500000016016614172327167017410 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * Portions Copyright 2007 by Howard Chu, Symas Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ #include "portable.h" #include #include #include #include #include #include #include #include #include #include #include "lload.h" #include "ldap_pvt_thread.h" #include "lutil.h" #include "ldap_rq.h" #ifdef HAVE_SYSTEMD_SD_DAEMON_H #include #endif #ifdef LDAP_PF_LOCAL #include /* this should go in as soon as it is accepted */ #define LDAPI_MOD_URLEXT "x-mod" #endif /* LDAP_PF_LOCAL */ #ifndef BALANCER_MODULE #ifdef LDAP_PF_INET6 int slap_inet4or6 = AF_UNSPEC; #else /* ! INETv6 */ int slap_inet4or6 = AF_INET; #endif /* ! INETv6 */ /* globals */ time_t starttime; struct runqueue_s slapd_rq; #ifdef LDAP_TCP_BUFFER int slapd_tcp_rmem; int slapd_tcp_wmem; #endif /* LDAP_TCP_BUFFER */ volatile sig_atomic_t slapd_shutdown = 0; volatile sig_atomic_t slapd_gentle_shutdown = 0; volatile sig_atomic_t slapd_abrupt_shutdown = 0; #endif /* !BALANCER_MODULE */ static int emfile; ldap_pvt_thread_mutex_t lload_wait_mutex; ldap_pvt_thread_cond_t lload_wait_cond; ldap_pvt_thread_cond_t lload_pause_cond; #ifndef SLAPD_MAX_DAEMON_THREADS #define SLAPD_MAX_DAEMON_THREADS 16 #endif int lload_daemon_threads = 1; int lload_daemon_mask; struct event_base *listener_base = NULL; LloadListener **lload_listeners = NULL; static ldap_pvt_thread_t listener_tid, *daemon_tid; struct event_base *daemon_base = NULL; struct evdns_base *dnsbase; struct event *lload_timeout_event; /* * global lload statistics. Not mutex protected to preserve performance - * increment is atomic, at most we risk a bit of inconsistency */ lload_global_stats_t lload_stats = {}; #ifndef SLAPD_LISTEN_BACKLOG #define SLAPD_LISTEN_BACKLOG 1024 #endif /* ! SLAPD_LISTEN_BACKLOG */ #define DAEMON_ID(fd) ( fd & lload_daemon_mask ) #ifdef HAVE_WINSOCK ldap_pvt_thread_mutex_t slapd_ws_mutex; SOCKET *slapd_ws_sockets; #define SD_READ 1 #define SD_WRITE 2 #define SD_ACTIVE 4 #define SD_LISTENER 8 #endif #ifdef HAVE_TCPD static ldap_pvt_thread_mutex_t sd_tcpd_mutex; #endif /* TCP Wrappers */ typedef struct listener_item { struct evconnlistener *listener; ber_socket_t fd; } listener_item; typedef struct lload_daemon_st { ldap_pvt_thread_mutex_t sd_mutex; struct event_base *base; struct event *wakeup_event; } lload_daemon_st; static lload_daemon_st lload_daemon[SLAPD_MAX_DAEMON_THREADS]; static void daemon_wakeup_cb( evutil_socket_t sig, short what, void *arg ); static void lloadd_close( ber_socket_t s ) { Debug( LDAP_DEBUG_CONNS, "lloadd_close: " "closing fd=%ld\n", (long)s ); tcp_close( s ); } static void lload_free_listener_addresses( struct sockaddr **sal ) { struct sockaddr **sap; if ( sal == NULL ) return; for ( sap = sal; *sap != NULL; sap++ ) ch_free(*sap); ch_free( sal ); } #if defined(LDAP_PF_LOCAL) || defined(SLAP_X_LISTENER_MOD) static int get_url_perms( char **exts, mode_t *perms, int *crit ) { int i; assert( exts != NULL ); assert( perms != NULL ); assert( crit != NULL ); *crit = 0; for ( i = 0; exts[i]; i++ ) { char *type = exts[i]; int c = 0; if ( type[0] == '!' ) { c = 1; type++; } if ( strncasecmp( type, LDAPI_MOD_URLEXT "=", sizeof(LDAPI_MOD_URLEXT "=") - 1 ) == 0 ) { char *value = type + ( sizeof(LDAPI_MOD_URLEXT "=") - 1 ); mode_t p = 0; int j; switch ( strlen( value ) ) { case 4: /* skip leading '0' */ if ( value[0] != '0' ) return LDAP_OTHER; value++; case 3: for ( j = 0; j < 3; j++ ) { int v; v = value[j] - '0'; if ( v < 0 || v > 7 ) return LDAP_OTHER; p |= v << 3 * ( 2 - j ); } break; case 10: for ( j = 1; j < 10; j++ ) { static mode_t m[] = { 0, S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH }; static const char c[] = "-rwxrwxrwx"; if ( value[j] == c[j] ) { p |= m[j]; } else if ( value[j] != '-' ) { return LDAP_OTHER; } } break; default: return LDAP_OTHER; } *crit = c; *perms = p; return LDAP_SUCCESS; } } return LDAP_OTHER; } #endif /* LDAP_PF_LOCAL || SLAP_X_LISTENER_MOD */ /* port = 0 indicates AF_LOCAL */ static int lload_get_listener_addresses( const char *host, unsigned short port, struct sockaddr ***sal ) { struct sockaddr **sap; #ifdef LDAP_PF_LOCAL if ( port == 0 ) { sap = *sal = ch_malloc( 2 * sizeof(void *) ); *sap = ch_calloc( 1, sizeof(struct sockaddr_un) ); sap[1] = NULL; if ( strlen( host ) > ( sizeof( ((struct sockaddr_un *)*sap)->sun_path ) - 1 ) ) { Debug( LDAP_DEBUG_ANY, "lload_get_listener_addresses: " "domain socket path (%s) too long in URL\n", host ); goto errexit; } (*sap)->sa_family = AF_LOCAL; strcpy( ((struct sockaddr_un *)*sap)->sun_path, host ); } else #endif /* LDAP_PF_LOCAL */ { #ifdef HAVE_GETADDRINFO struct addrinfo hints, *res, *sai; int n, err; char serv[7]; memset( &hints, '\0', sizeof(hints) ); hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; hints.ai_family = slap_inet4or6; snprintf( serv, sizeof(serv), "%d", port ); if ( (err = getaddrinfo( host, serv, &hints, &res )) ) { Debug( LDAP_DEBUG_ANY, "lload_get_listener_addresses: " "getaddrinfo() failed: %s\n", AC_GAI_STRERROR(err) ); return -1; } sai = res; for ( n = 2; ( sai = sai->ai_next ) != NULL; n++ ) { /* EMPTY */; } sap = *sal = ch_calloc( n, sizeof(void *) ); *sap = NULL; for ( sai = res; sai; sai = sai->ai_next ) { if ( sai->ai_addr == NULL ) { Debug( LDAP_DEBUG_ANY, "lload_get_listener_addresses: " "getaddrinfo ai_addr is NULL?\n" ); freeaddrinfo( res ); goto errexit; } switch ( sai->ai_family ) { #ifdef LDAP_PF_INET6 case AF_INET6: *sap = ch_malloc( sizeof(struct sockaddr_in6) ); *(struct sockaddr_in6 *)*sap = *((struct sockaddr_in6 *)sai->ai_addr); break; #endif /* LDAP_PF_INET6 */ case AF_INET: *sap = ch_malloc( sizeof(struct sockaddr_in) ); *(struct sockaddr_in *)*sap = *((struct sockaddr_in *)sai->ai_addr); break; default: *sap = NULL; break; } if ( *sap != NULL ) { (*sap)->sa_family = sai->ai_family; sap++; *sap = NULL; } } freeaddrinfo( res ); #else /* ! HAVE_GETADDRINFO */ int i, n = 1; struct in_addr in; struct hostent *he = NULL; if ( host == NULL ) { in.s_addr = htonl( INADDR_ANY ); } else if ( !inet_aton( host, &in ) ) { he = gethostbyname( host ); if ( he == NULL ) { Debug( LDAP_DEBUG_ANY, "lload_get_listener_addresses: " "invalid host %s\n", host ); return -1; } for ( n = 0; he->h_addr_list[n]; n++ ) /* empty */; } sap = *sal = ch_malloc( ( n + 1 ) * sizeof(void *) ); for ( i = 0; i < n; i++ ) { sap[i] = ch_calloc( 1, sizeof(struct sockaddr_in) ); sap[i]->sa_family = AF_INET; ((struct sockaddr_in *)sap[i])->sin_port = htons( port ); AC_MEMCPY( &((struct sockaddr_in *)sap[i])->sin_addr, he ? (struct in_addr *)he->h_addr_list[i] : &in, sizeof(struct in_addr) ); } sap[i] = NULL; #endif /* ! HAVE_GETADDRINFO */ } return 0; errexit: lload_free_listener_addresses(*sal); return -1; } static int lload_open_listener( const char *url, LDAPURLDesc *lud, int *listeners, int *cur ) { int num, tmp, rc; LloadListener l; LloadListener *li; unsigned short port; int err, addrlen = 0; struct sockaddr **sal = NULL, **psal; int socktype = SOCK_STREAM; /* default to COTS */ ber_socket_t s; char ebuf[128]; #if defined(LDAP_PF_LOCAL) || defined(SLAP_X_LISTENER_MOD) /* * use safe defaults */ int crit = 1; #endif /* LDAP_PF_LOCAL || SLAP_X_LISTENER_MOD */ assert( url ); assert( lud ); l.sl_url.bv_val = NULL; l.sl_mute = 0; l.sl_busy = 0; #ifndef HAVE_TLS if ( ldap_pvt_url_scheme2tls( lud->lud_scheme ) ) { Debug( LDAP_DEBUG_ANY, "lload_open_listener: " "TLS not supported (%s)\n", url ); ldap_free_urldesc( lud ); return -1; } if ( !lud->lud_port ) lud->lud_port = LDAP_PORT; #else /* HAVE_TLS */ l.sl_is_tls = ldap_pvt_url_scheme2tls( lud->lud_scheme ); #endif /* HAVE_TLS */ l.sl_is_proxied = ldap_pvt_url_scheme2proxied( lud->lud_scheme ); #ifdef LDAP_TCP_BUFFER l.sl_tcp_rmem = 0; l.sl_tcp_wmem = 0; #endif /* LDAP_TCP_BUFFER */ port = (unsigned short)lud->lud_port; tmp = ldap_pvt_url_scheme2proto( lud->lud_scheme ); if ( tmp == LDAP_PROTO_IPC ) { #ifdef LDAP_PF_LOCAL if ( lud->lud_host == NULL || lud->lud_host[0] == '\0' ) { err = lload_get_listener_addresses( LDAPI_SOCK, 0, &sal ); } else { err = lload_get_listener_addresses( lud->lud_host, 0, &sal ); } #else /* ! LDAP_PF_LOCAL */ Debug( LDAP_DEBUG_ANY, "lload_open_listener: " "URL scheme not supported: %s\n", url ); ldap_free_urldesc( lud ); return -1; #endif /* ! LDAP_PF_LOCAL */ } else { if ( lud->lud_host == NULL || lud->lud_host[0] == '\0' || strcmp( lud->lud_host, "*" ) == 0 ) { err = lload_get_listener_addresses( NULL, port, &sal ); } else { err = lload_get_listener_addresses( lud->lud_host, port, &sal ); } } #if defined(LDAP_PF_LOCAL) || defined(SLAP_X_LISTENER_MOD) if ( lud->lud_exts ) { err = get_url_perms( lud->lud_exts, &l.sl_perms, &crit ); } else { l.sl_perms = S_IRWXU | S_IRWXO; } #endif /* LDAP_PF_LOCAL || SLAP_X_LISTENER_MOD */ ldap_free_urldesc( lud ); if ( err ) { lload_free_listener_addresses( sal ); return -1; } /* If we got more than one address returned, we need to make space * for it in the lload_listeners array. */ for ( num = 0; sal[num]; num++ ) /* empty */; if ( num > 1 ) { *listeners += num - 1; lload_listeners = ch_realloc( lload_listeners, ( *listeners + 1 ) * sizeof(LloadListener *) ); } psal = sal; while ( *sal != NULL ) { char *af; switch ( (*sal)->sa_family ) { case AF_INET: af = "IPv4"; break; #ifdef LDAP_PF_INET6 case AF_INET6: af = "IPv6"; break; #endif /* LDAP_PF_INET6 */ #ifdef LDAP_PF_LOCAL case AF_LOCAL: af = "Local"; break; #endif /* LDAP_PF_LOCAL */ default: sal++; continue; } s = socket( (*sal)->sa_family, socktype, 0 ); if ( s == AC_SOCKET_INVALID ) { int err = sock_errno(); Debug( LDAP_DEBUG_ANY, "lload_open_listener: " "%s socket() failed errno=%d (%s)\n", af, err, sock_errstr( err, ebuf, sizeof(ebuf) ) ); sal++; continue; } ber_pvt_socket_set_nonblock( s, 1 ); l.sl_sd = s; #ifdef LDAP_PF_LOCAL if ( (*sal)->sa_family == AF_LOCAL ) { unlink( ((struct sockaddr_un *)*sal)->sun_path ); } else #endif /* LDAP_PF_LOCAL */ { #ifdef SO_REUSEADDR /* enable address reuse */ tmp = 1; rc = setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp, sizeof(tmp) ); if ( rc == AC_SOCKET_ERROR ) { int err = sock_errno(); Debug( LDAP_DEBUG_ANY, "lload_open_listener(%ld): " "setsockopt(SO_REUSEADDR) failed errno=%d (%s)\n", (long)l.sl_sd, err, sock_errstr( err, ebuf, sizeof(ebuf) ) ); } #endif /* SO_REUSEADDR */ } switch ( (*sal)->sa_family ) { case AF_INET: addrlen = sizeof(struct sockaddr_in); break; #ifdef LDAP_PF_INET6 case AF_INET6: #ifdef IPV6_V6ONLY /* Try to use IPv6 sockets for IPv6 only */ tmp = 1; rc = setsockopt( s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&tmp, sizeof(tmp) ); if ( rc == AC_SOCKET_ERROR ) { int err = sock_errno(); Debug( LDAP_DEBUG_ANY, "lload_open_listener(%ld): " "setsockopt(IPV6_V6ONLY) failed errno=%d (%s)\n", (long)l.sl_sd, err, sock_errstr( err, ebuf, sizeof(ebuf) ) ); } #endif /* IPV6_V6ONLY */ addrlen = sizeof(struct sockaddr_in6); break; #endif /* LDAP_PF_INET6 */ #ifdef LDAP_PF_LOCAL case AF_LOCAL: #ifdef LOCAL_CREDS { int one = 1; setsockopt( s, 0, LOCAL_CREDS, &one, sizeof(one) ); } #endif /* LOCAL_CREDS */ addrlen = sizeof(struct sockaddr_un); break; #endif /* LDAP_PF_LOCAL */ } #ifdef LDAP_PF_LOCAL /* create socket with all permissions set for those systems * that honor permissions on sockets (e.g. Linux); typically, * only write is required. To exploit filesystem permissions, * place the socket in a directory and use directory's * permissions. Need write perms to the directory to * create/unlink the socket; likely need exec perms to access * the socket (ITS#4709) */ { mode_t old_umask = 0; if ( (*sal)->sa_family == AF_LOCAL ) { old_umask = umask( 0 ); } #endif /* LDAP_PF_LOCAL */ rc = bind( s, *sal, addrlen ); #ifdef LDAP_PF_LOCAL if ( old_umask != 0 ) { umask( old_umask ); } } #endif /* LDAP_PF_LOCAL */ if ( rc ) { err = sock_errno(); Debug( LDAP_DEBUG_ANY, "lload_open_listener: " "bind(%ld) failed errno=%d (%s)\n", (long)l.sl_sd, err, sock_errstr( err, ebuf, sizeof(ebuf) ) ); tcp_close( s ); sal++; continue; } switch ( (*sal)->sa_family ) { #ifdef LDAP_PF_LOCAL case AF_LOCAL: { char *path = ((struct sockaddr_un *)*sal)->sun_path; l.sl_name.bv_len = strlen( path ) + STRLENOF("PATH="); l.sl_name.bv_val = ch_malloc( l.sl_name.bv_len + 1 ); snprintf( l.sl_name.bv_val, l.sl_name.bv_len + 1, "PATH=%s", path ); } break; #endif /* LDAP_PF_LOCAL */ case AF_INET: { char addr[INET_ADDRSTRLEN]; const char *s; #if defined(HAVE_GETADDRINFO) && defined(HAVE_INET_NTOP) s = inet_ntop( AF_INET, &((struct sockaddr_in *)*sal)->sin_addr, addr, sizeof(addr) ); #else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ s = inet_ntoa( ((struct sockaddr_in *)*sal)->sin_addr ); #endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ if ( !s ) s = SLAP_STRING_UNKNOWN; port = ntohs( ((struct sockaddr_in *)*sal)->sin_port ); l.sl_name.bv_val = ch_malloc( sizeof("IP=255.255.255.255:65535") ); snprintf( l.sl_name.bv_val, sizeof("IP=255.255.255.255:65535"), "IP=%s:%d", s, port ); l.sl_name.bv_len = strlen( l.sl_name.bv_val ); } break; #ifdef LDAP_PF_INET6 case AF_INET6: { char addr[INET6_ADDRSTRLEN]; const char *s; s = inet_ntop( AF_INET6, &((struct sockaddr_in6 *)*sal)->sin6_addr, addr, sizeof(addr) ); if ( !s ) s = SLAP_STRING_UNKNOWN; port = ntohs( ((struct sockaddr_in6 *)*sal)->sin6_port ); l.sl_name.bv_len = strlen( s ) + sizeof("IP=[]:65535"); l.sl_name.bv_val = ch_malloc( l.sl_name.bv_len ); snprintf( l.sl_name.bv_val, l.sl_name.bv_len, "IP=[%s]:%d", s, port ); l.sl_name.bv_len = strlen( l.sl_name.bv_val ); } break; #endif /* LDAP_PF_INET6 */ default: Debug( LDAP_DEBUG_ANY, "lload_open_listener: " "unsupported address family (%d)\n", (int)(*sal)->sa_family ); break; } AC_MEMCPY( &l.sl_sa, *sal, addrlen ); ber_str2bv( url, 0, 1, &l.sl_url ); li = ch_malloc( sizeof(LloadListener) ); *li = l; lload_listeners[*cur] = li; (*cur)++; sal++; } lload_free_listener_addresses( psal ); if ( l.sl_url.bv_val == NULL ) { Debug( LDAP_DEBUG_ANY, "lload_open_listener: " "failed on %s\n", url ); return -1; } Debug( LDAP_DEBUG_TRACE, "lload_open_listener: " "listener initialized %s\n", l.sl_url.bv_val ); return 0; } int lload_open_new_listener( const char *url, LDAPURLDesc *lud ) { int rc, i, j = 0; for ( i = 0; lload_listeners && lload_listeners[i] != NULL; i++ ) /* count */ ; j = i; i++; lload_listeners = ch_realloc( lload_listeners, ( i + 1 ) * sizeof(LloadListener *) ); rc = lload_open_listener( url, lud, &i, &j ); lload_listeners[j] = NULL; return rc; } int lloadd_inited = 0; int lloadd_listeners_init( const char *urls ) { int i, j, n; char **u; LDAPURLDesc *lud; Debug( LDAP_DEBUG_ARGS, "lloadd_listeners_init: %s\n", urls ? urls : "" ); #ifdef HAVE_TCPD ldap_pvt_thread_mutex_init( &sd_tcpd_mutex ); #endif /* TCP Wrappers */ if ( urls == NULL ) urls = "ldap:///"; u = ldap_str2charray( urls, " " ); if ( u == NULL || u[0] == NULL ) { Debug( LDAP_DEBUG_ANY, "lloadd_listeners_init: " "no urls (%s) provided\n", urls ); if ( u ) ldap_charray_free( u ); return -1; } for ( i = 0; u[i] != NULL; i++ ) { Debug( LDAP_DEBUG_TRACE, "lloadd_listeners_init: " "listen on %s\n", u[i] ); } if ( i == 0 ) { Debug( LDAP_DEBUG_ANY, "lloadd_listeners_init: " "no listeners to open (%s)\n", urls ); ldap_charray_free( u ); return -1; } Debug( LDAP_DEBUG_TRACE, "lloadd_listeners_init: " "%d listeners to open...\n", i ); lload_listeners = ch_malloc( ( i + 1 ) * sizeof(LloadListener *) ); for ( n = 0, j = 0; u[n]; n++ ) { if ( ldap_url_parse_ext( u[n], &lud, LDAP_PVT_URL_PARSE_DEF_PORT ) ) { Debug( LDAP_DEBUG_ANY, "lloadd_listeners_init: " "could not parse url %s\n", u[n] ); ldap_charray_free( u ); return -1; } if ( lload_open_listener( u[n], lud, &i, &j ) ) { ldap_charray_free( u ); return -1; } } lload_listeners[j] = NULL; Debug( LDAP_DEBUG_TRACE, "lloadd_listeners_init: " "%d listeners opened\n", i ); ldap_charray_free( u ); return !i; } int lloadd_daemon_destroy( void ) { epoch_shutdown(); if ( lloadd_inited ) { int i; for ( i = 0; i < lload_daemon_threads; i++ ) { ldap_pvt_thread_mutex_destroy( &lload_daemon[i].sd_mutex ); if ( lload_daemon[i].wakeup_event ) { event_free( lload_daemon[i].wakeup_event ); } if ( lload_daemon[i].base ) { event_base_free( lload_daemon[i].base ); } } event_base_free( daemon_base ); daemon_base = NULL; lloadd_inited = 0; #ifdef HAVE_TCPD ldap_pvt_thread_mutex_destroy( &sd_tcpd_mutex ); #endif /* TCP Wrappers */ } return 0; } static void destroy_listeners( void ) { LloadListener *lr, **ll = lload_listeners; if ( ll == NULL ) return; ldap_pvt_thread_join( listener_tid, (void *)NULL ); while ( (lr = *ll++) != NULL ) { if ( lr->sl_url.bv_val ) { ber_memfree( lr->sl_url.bv_val ); } if ( lr->sl_name.bv_val ) { ber_memfree( lr->sl_name.bv_val ); } #ifdef LDAP_PF_LOCAL if ( lr->sl_sa.sa_addr.sa_family == AF_LOCAL ) { unlink( lr->sl_sa.sa_un_addr.sun_path ); } #endif /* LDAP_PF_LOCAL */ evconnlistener_free( lr->listener ); free( lr ); } free( lload_listeners ); lload_listeners = NULL; if ( listener_base ) { event_base_free( listener_base ); } } static void lload_listener( struct evconnlistener *listener, ber_socket_t s, struct sockaddr *a, int len, void *arg ) { LloadListener *sl = arg; LloadConnection *c; Sockaddr *from = (Sockaddr *)a; char peername[LDAP_IPADDRLEN]; struct berval peerbv = BER_BVC(peername); int cflag; int tid; char ebuf[128]; Debug( LDAP_DEBUG_TRACE, ">>> lload_listener(%s)\n", sl->sl_url.bv_val ); peername[0] = '\0'; /* Resume the listener FD to allow concurrent-processing of * additional incoming connections. */ sl->sl_busy = 0; tid = DAEMON_ID(s); Debug( LDAP_DEBUG_CONNS, "lload_listener: " "listen=%ld, new connection fd=%ld\n", (long)sl->sl_sd, (long)s ); #if defined(SO_KEEPALIVE) || defined(TCP_NODELAY) #ifdef LDAP_PF_LOCAL /* for IPv4 and IPv6 sockets only */ if ( from->sa_addr.sa_family != AF_LOCAL ) #endif /* LDAP_PF_LOCAL */ { int rc; int tmp; #ifdef SO_KEEPALIVE /* enable keep alives */ tmp = 1; rc = setsockopt( s, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp) ); if ( rc == AC_SOCKET_ERROR ) { int err = sock_errno(); Debug( LDAP_DEBUG_ANY, "lload_listener(%ld): " "setsockopt(SO_KEEPALIVE) failed errno=%d (%s)\n", (long)s, err, sock_errstr( err, ebuf, sizeof(ebuf) ) ); } #endif /* SO_KEEPALIVE */ #ifdef TCP_NODELAY /* enable no delay */ tmp = 1; rc = setsockopt( s, IPPROTO_TCP, TCP_NODELAY, (char *)&tmp, sizeof(tmp) ); if ( rc == AC_SOCKET_ERROR ) { int err = sock_errno(); Debug( LDAP_DEBUG_ANY, "lload_listener(%ld): " "setsockopt(TCP_NODELAY) failed errno=%d (%s)\n", (long)s, err, sock_errstr( err, ebuf, sizeof(ebuf) ) ); } #endif /* TCP_NODELAY */ } #endif /* SO_KEEPALIVE || TCP_NODELAY */ if ( sl->sl_is_proxied ) { if ( !proxyp( s, from ) ) { Debug( LDAP_DEBUG_ANY, "lload_listener: " "proxyp(%ld) failed\n", (long)s ); lloadd_close( s ); return; } } cflag = 0; switch ( from->sa_addr.sa_family ) { #ifdef LDAP_PF_LOCAL case AF_LOCAL: cflag |= CONN_IS_IPC; /* FIXME: apparently accept doesn't fill the sun_path member */ sprintf( peername, "PATH=%s", sl->sl_sa.sa_un_addr.sun_path ); break; #endif /* LDAP_PF_LOCAL */ #ifdef LDAP_PF_INET6 case AF_INET6: #endif /* LDAP_PF_INET6 */ case AF_INET: ldap_pvt_sockaddrstr( from, &peerbv ); break; default: lloadd_close( s ); return; } #ifdef HAVE_TLS if ( sl->sl_is_tls ) cflag |= CONN_IS_TLS; #endif c = client_init( s, peername, lload_daemon[tid].base, cflag ); if ( !c ) { Debug( LDAP_DEBUG_ANY, "lload_listener: " "client_init(%ld, %s, %s) failed\n", (long)s, peername, sl->sl_name.bv_val ); lloadd_close( s ); } return; } static void * lload_listener_thread( void *ctx ) { int rc = event_base_dispatch( listener_base ); Debug( LDAP_DEBUG_ANY, "lload_listener_thread: " "event loop finished: rc=%d\n", rc ); return (void *)NULL; } static void listener_error_cb( struct evconnlistener *lev, void *arg ) { LloadListener *l = arg; int err = EVUTIL_SOCKET_ERROR(); assert( l->listener == lev ); if ( #ifdef EMFILE err == EMFILE || #endif /* EMFILE */ #ifdef ENFILE err == ENFILE || #endif /* ENFILE */ 0 ) { ldap_pvt_thread_mutex_lock( &lload_daemon[0].sd_mutex ); emfile++; /* Stop listening until an existing session closes */ l->sl_mute = 1; evconnlistener_disable( lev ); ldap_pvt_thread_mutex_unlock( &lload_daemon[0].sd_mutex ); Debug( LDAP_DEBUG_ANY, "listener_error_cb: " "too many open files, cannot accept new connections on " "url=%s\n", l->sl_url.bv_val ); } else { char ebuf[128]; Debug( LDAP_DEBUG_ANY, "listener_error_cb: " "received an error on a listener, shutting down: '%s'\n", sock_errstr( err, ebuf, sizeof(ebuf) ) ); event_base_loopexit( l->base, NULL ); } } void listeners_reactivate( void ) { int i; ldap_pvt_thread_mutex_lock( &lload_daemon[0].sd_mutex ); for ( i = 0; emfile && lload_listeners[i] != NULL; i++ ) { LloadListener *lr = lload_listeners[i]; if ( lr->sl_sd == AC_SOCKET_INVALID ) continue; if ( lr->sl_mute ) { emfile--; evconnlistener_enable( lr->listener ); lr->sl_mute = 0; Debug( LDAP_DEBUG_CONNS, "listeners_reactivate: " "reactivated listener url=%s\n", lr->sl_url.bv_val ); } } if ( emfile && lload_listeners[i] == NULL ) { /* Walked the entire list without enabling anything; emfile * counter is stale. Reset it. */ emfile = 0; } ldap_pvt_thread_mutex_unlock( &lload_daemon[0].sd_mutex ); } static int lload_listener_activate( void ) { struct evconnlistener *listener; int l, rc; char ebuf[128]; listener_base = event_base_new(); if ( !listener_base ) return -1; for ( l = 0; lload_listeners[l] != NULL; l++ ) { if ( lload_listeners[l]->sl_sd == AC_SOCKET_INVALID ) continue; /* FIXME: TCP-only! */ #ifdef LDAP_TCP_BUFFER if ( 1 ) { int origsize, size, realsize, rc; socklen_t optlen; size = 0; if ( lload_listeners[l]->sl_tcp_rmem > 0 ) { size = lload_listeners[l]->sl_tcp_rmem; } else if ( slapd_tcp_rmem > 0 ) { size = slapd_tcp_rmem; } if ( size > 0 ) { optlen = sizeof(origsize); rc = getsockopt( lload_listeners[l]->sl_sd, SOL_SOCKET, SO_RCVBUF, (void *)&origsize, &optlen ); if ( rc ) { int err = sock_errno(); Debug( LDAP_DEBUG_ANY, "lload_listener_activate: " "getsockopt(SO_RCVBUF) failed errno=%d (%s)\n", err, AC_STRERROR_R( err, ebuf, sizeof(ebuf) ) ); } optlen = sizeof(size); rc = setsockopt( lload_listeners[l]->sl_sd, SOL_SOCKET, SO_RCVBUF, (const void *)&size, optlen ); if ( rc ) { int err = sock_errno(); Debug( LDAP_DEBUG_ANY, "lload_listener_activate: " "setsockopt(SO_RCVBUF) failed errno=%d (%s)\n", err, sock_errstr( err, ebuf, sizeof(ebuf) ) ); } optlen = sizeof(realsize); rc = getsockopt( lload_listeners[l]->sl_sd, SOL_SOCKET, SO_RCVBUF, (void *)&realsize, &optlen ); if ( rc ) { int err = sock_errno(); Debug( LDAP_DEBUG_ANY, "lload_listener_activate: " "getsockopt(SO_RCVBUF) failed errno=%d (%s)\n", err, sock_errstr( err, ebuf, sizeof(ebuf) ) ); } Debug( LDAP_DEBUG_ANY, "lload_listener_activate: " "url=%s (#%d) RCVBUF original size=%d requested " "size=%d real size=%d\n", lload_listeners[l]->sl_url.bv_val, l, origsize, size, realsize ); } size = 0; if ( lload_listeners[l]->sl_tcp_wmem > 0 ) { size = lload_listeners[l]->sl_tcp_wmem; } else if ( slapd_tcp_wmem > 0 ) { size = slapd_tcp_wmem; } if ( size > 0 ) { optlen = sizeof(origsize); rc = getsockopt( lload_listeners[l]->sl_sd, SOL_SOCKET, SO_SNDBUF, (void *)&origsize, &optlen ); if ( rc ) { int err = sock_errno(); Debug( LDAP_DEBUG_ANY, "lload_listener_activate: " "getsockopt(SO_SNDBUF) failed errno=%d (%s)\n", err, sock_errstr( err, ebuf, sizeof(ebuf) ) ); } optlen = sizeof(size); rc = setsockopt( lload_listeners[l]->sl_sd, SOL_SOCKET, SO_SNDBUF, (const void *)&size, optlen ); if ( rc ) { int err = sock_errno(); Debug( LDAP_DEBUG_ANY, "lload_listener_activate: " "setsockopt(SO_SNDBUF) failed errno=%d (%s)\n", err, sock_errstr( err, ebuf, sizeof(ebuf) ) ); } optlen = sizeof(realsize); rc = getsockopt( lload_listeners[l]->sl_sd, SOL_SOCKET, SO_SNDBUF, (void *)&realsize, &optlen ); if ( rc ) { int err = sock_errno(); Debug( LDAP_DEBUG_ANY, "lload_listener_activate: " "getsockopt(SO_SNDBUF) failed errno=%d (%s)\n", err, sock_errstr( err, ebuf, sizeof(ebuf) ) ); } Debug( LDAP_DEBUG_ANY, "lload_listener_activate: " "url=%s (#%d) SNDBUF original size=%d requested " "size=%d real size=%d\n", lload_listeners[l]->sl_url.bv_val, l, origsize, size, realsize ); } } #endif /* LDAP_TCP_BUFFER */ lload_listeners[l]->sl_busy = 1; listener = evconnlistener_new( listener_base, lload_listener, lload_listeners[l], LEV_OPT_THREADSAFE|LEV_OPT_DEFERRED_ACCEPT, SLAPD_LISTEN_BACKLOG, lload_listeners[l]->sl_sd ); if ( !listener ) { int err = sock_errno(); #ifdef LDAP_PF_INET6 /* If error is EADDRINUSE, we are trying to listen to INADDR_ANY and * we are already listening to in6addr_any, then we want to ignore * this and continue. */ if ( err == EADDRINUSE ) { int i; struct sockaddr_in sa = lload_listeners[l]->sl_sa.sa_in_addr; struct sockaddr_in6 sa6; if ( sa.sin_family == AF_INET && sa.sin_addr.s_addr == htonl( INADDR_ANY ) ) { for ( i = 0; i < l; i++ ) { sa6 = lload_listeners[i]->sl_sa.sa_in6_addr; if ( sa6.sin6_family == AF_INET6 && !memcmp( &sa6.sin6_addr, &in6addr_any, sizeof(struct in6_addr) ) ) { break; } } if ( i < l ) { /* We are already listening to in6addr_any */ Debug( LDAP_DEBUG_CONNS, "lload_listener_activate: " "Attempt to listen to 0.0.0.0 failed, " "already listening on ::, assuming IPv4 " "included\n" ); lloadd_close( lload_listeners[l]->sl_sd ); lload_listeners[l]->sl_sd = AC_SOCKET_INVALID; continue; } } } #endif /* LDAP_PF_INET6 */ Debug( LDAP_DEBUG_ANY, "lload_listener_activate: " "listen(%s, 5) failed errno=%d (%s)\n", lload_listeners[l]->sl_url.bv_val, err, sock_errstr( err, ebuf, sizeof(ebuf) ) ); return -1; } lload_listeners[l]->base = listener_base; lload_listeners[l]->listener = listener; evconnlistener_set_error_cb( listener, listener_error_cb ); } rc = ldap_pvt_thread_create( &listener_tid, 0, lload_listener_thread, lload_listeners[l] ); if ( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "lload_listener_activate(%d): " "submit failed (%d)\n", lload_listeners[l]->sl_sd, rc ); } return rc; } static void * lloadd_io_task( void *ptr ) { int rc; int tid = (ldap_pvt_thread_t *)ptr - daemon_tid; struct event_base *base = lload_daemon[tid].base; struct event *event; event = event_new( base, -1, EV_WRITE, daemon_wakeup_cb, ptr ); if ( !event ) { Debug( LDAP_DEBUG_ANY, "lloadd_io_task: " "failed to set up the wakeup event\n" ); return (void *)-1; } event_add( event, NULL ); lload_daemon[tid].wakeup_event = event; /* run */ rc = event_base_dispatch( base ); Debug( LDAP_DEBUG_ANY, "lloadd_io_task: " "Daemon %d, event loop finished: rc=%d\n", tid, rc ); if ( !slapd_gentle_shutdown ) { slapd_abrupt_shutdown = 1; } return NULL; } int lloadd_daemon( struct event_base *daemon_base ) { int i, rc; LloadBackend *b; struct event_base *base; struct event *event; assert( daemon_base != NULL ); dnsbase = evdns_base_new( daemon_base, EVDNS_BASE_INITIALIZE_NAMESERVERS ); if ( !dnsbase ) { Debug( LDAP_DEBUG_ANY, "lloadd startup: " "failed to set up for async name resolution\n" ); return -1; } if ( lload_daemon_threads > SLAPD_MAX_DAEMON_THREADS ) lload_daemon_threads = SLAPD_MAX_DAEMON_THREADS; daemon_tid = ch_malloc( lload_daemon_threads * sizeof(ldap_pvt_thread_t) ); for ( i = 0; i < lload_daemon_threads; i++ ) { base = event_base_new(); if ( !base ) { Debug( LDAP_DEBUG_ANY, "lloadd startup: " "failed to acquire event base for an I/O thread\n" ); return -1; } lload_daemon[i].base = base; ldap_pvt_thread_mutex_init( &lload_daemon[i].sd_mutex ); /* threads that handle client and upstream sockets */ rc = ldap_pvt_thread_create( &daemon_tid[i], 0, lloadd_io_task, &daemon_tid[i] ); if ( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "lloadd startup: " "listener ldap_pvt_thread_create failed (%d)\n", rc ); return rc; } } if ( (rc = lload_listener_activate()) != 0 ) { return rc; } if ( !LDAP_CIRCLEQ_EMPTY( &backend ) ) { current_backend = LDAP_CIRCLEQ_FIRST( &backend ); LDAP_CIRCLEQ_FOREACH ( b, &backend, b_next ) { event = evtimer_new( daemon_base, backend_connect, b ); if ( !event ) { Debug( LDAP_DEBUG_ANY, "lloadd: " "failed to allocate retry event\n" ); return -1; } checked_lock( &b->b_mutex ); b->b_retry_event = event; backend_retry( b ); checked_unlock( &b->b_mutex ); } } event = evtimer_new( daemon_base, operations_timeout, event_self_cbarg() ); if ( !event ) { Debug( LDAP_DEBUG_ANY, "lloadd: " "failed to allocate timeout event\n" ); return -1; } lload_timeout_event = event; /* TODO: should we just add it with any timeout and re-add when the timeout * changes? */ if ( lload_timeout_api ) { event_add( event, lload_timeout_api ); } checked_lock( &lload_wait_mutex ); lloadd_inited = 1; ldap_pvt_thread_cond_signal( &lload_wait_cond ); checked_unlock( &lload_wait_mutex ); #if !defined(BALANCER_MODULE) && defined(HAVE_SYSTEMD) rc = sd_notify( 1, "READY=1" ); if ( rc < 0 ) { Debug( LDAP_DEBUG_ANY, "lloadd startup: " "systemd sd_notify failed (%d)\n", rc ); } #endif /* !BALANCER_MODULE && HAVE_SYSTEMD */ rc = event_base_dispatch( daemon_base ); Debug( LDAP_DEBUG_ANY, "lloadd shutdown: " "Main event loop finished: rc=%d\n", rc ); /* shutdown */ event_base_loopexit( listener_base, 0 ); /* wait for the listener threads to complete */ destroy_listeners(); /* Mark upstream connections closing and prevent from opening new ones */ LDAP_CIRCLEQ_FOREACH ( b, &backend, b_next ) { epoch_t epoch = epoch_join(); checked_lock( &b->b_mutex ); b->b_numconns = b->b_numbindconns = 0; backend_reset( b, 1 ); checked_unlock( &b->b_mutex ); epoch_leave( epoch ); } /* Do the same for clients */ clients_destroy( 1 ); for ( i = 0; i < lload_daemon_threads; i++ ) { /* * https://github.com/libevent/libevent/issues/623 * deleting the event doesn't notify the base, just activate it and * let it delete itself */ event_active( lload_daemon[i].wakeup_event, EV_READ, 0 ); } for ( i = 0; i < lload_daemon_threads; i++ ) { ldap_pvt_thread_join( daemon_tid[i], (void *)NULL ); } #ifndef BALANCER_MODULE if ( LogTest( LDAP_DEBUG_ANY ) ) { int t = ldap_pvt_thread_pool_backload( &connection_pool ); Debug( LDAP_DEBUG_ANY, "lloadd shutdown: " "waiting for %d operations/tasks to finish\n", t ); } ldap_pvt_thread_pool_close( &connection_pool, 1 ); #endif lload_backends_destroy(); clients_destroy( 0 ); lload_bindconf_free( &bindconf ); evdns_base_free( dnsbase, 0 ); ch_free( daemon_tid ); daemon_tid = NULL; lloadd_daemon_destroy(); /* If we're a slapd module, let the thread that initiated the shut down * know we've finished */ checked_lock( &lload_wait_mutex ); ldap_pvt_thread_cond_signal( &lload_wait_cond ); checked_unlock( &lload_wait_mutex ); return 0; } static void daemon_wakeup_cb( evutil_socket_t sig, short what, void *arg ) { int tid = (ldap_pvt_thread_t *)arg - daemon_tid; Debug( LDAP_DEBUG_TRACE, "daemon_wakeup_cb: " "Daemon thread %d woken up\n", tid ); event_del( lload_daemon[tid].wakeup_event ); } LloadChange lload_change = { .type = LLOAD_CHANGE_UNDEFINED }; #ifdef BALANCER_MODULE int backend_conn_cb( ldap_pvt_thread_start_t *start, void *startarg, void *arg ) { LloadConnection *c = startarg; LloadBackend *b = arg; if ( b == NULL || c->c_backend == b ) { CONNECTION_LOCK_DESTROY(c); return 1; } return 0; } #ifdef HAVE_TLS int client_tls_cb( ldap_pvt_thread_start_t *start, void *startarg, void *arg ) { LloadConnection *c = startarg; if ( c->c_destroy == client_destroy && c->c_is_tls == LLOAD_TLS_ESTABLISHED ) { CONNECTION_LOCK_DESTROY(c); return 1; } return 0; } #endif /* HAVE_TLS */ void lload_handle_backend_invalidation( LloadChange *change ) { LloadBackend *b = change->target; assert( change->object == LLOAD_BACKEND ); if ( change->type == LLOAD_CHANGE_ADD ) { BackendInfo *mi = backend_info( "monitor" ); if ( mi ) { monitor_extra_t *mbe = mi->bi_extra; if ( mbe->is_configured() ) { lload_monitor_backend_init( mi, b ); } } if ( !current_backend ) { current_backend = b; } checked_lock( &b->b_mutex ); backend_retry( b ); checked_unlock( &b->b_mutex ); return; } else if ( change->type == LLOAD_CHANGE_DEL ) { ldap_pvt_thread_pool_walk( &connection_pool, handle_pdus, backend_conn_cb, b ); ldap_pvt_thread_pool_walk( &connection_pool, upstream_bind, backend_conn_cb, b ); lload_backend_destroy( b ); return; } assert( change->type == LLOAD_CHANGE_MODIFY ); /* * A change that can't be handled gracefully, terminate all connections and * start over. */ if ( change->flags.backend & LLOAD_BACKEND_MOD_OTHER ) { ldap_pvt_thread_pool_walk( &connection_pool, handle_pdus, backend_conn_cb, b ); ldap_pvt_thread_pool_walk( &connection_pool, upstream_bind, backend_conn_cb, b ); checked_lock( &b->b_mutex ); backend_reset( b, 0 ); backend_retry( b ); checked_unlock( &b->b_mutex ); return; } /* * Handle changes to number of connections: * - a change might get the connection limit above the pool size: * - consider closing (in order of priority?): * - connections awaiting connect() completion * - connections currently preparing * - bind connections over limit (which is 0 if 'feature vc' is on * - regular connections over limit * - below pool size * - call backend_retry if there are no opening connections * - one pool size above and one below the configured size * - still close the ones above limit, it should sort itself out * the only issue is if a closing connection isn't guaranteed to do * that at some point */ if ( change->flags.backend & LLOAD_BACKEND_MOD_CONNS ) { int bind_requested = 0, need_close = 0, need_open = 0; LloadConnection *c; bind_requested = #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS (lload_features & LLOAD_FEATURE_VC) ? 0 : #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */ b->b_numbindconns; if ( b->b_bindavail > bind_requested ) { need_close += b->b_bindavail - bind_requested; } else if ( b->b_bindavail < bind_requested ) { need_open = 1; } if ( b->b_active > b->b_numconns ) { need_close += b->b_active - b->b_numconns; } else if ( b->b_active < b->b_numconns ) { need_open = 1; } if ( !need_open ) { need_close += b->b_opening; while ( !LDAP_LIST_EMPTY( &b->b_connecting ) ) { LloadPendingConnection *p = LDAP_LIST_FIRST( &b->b_connecting ); LDAP_LIST_REMOVE( p, next ); event_free( p->event ); evutil_closesocket( p->fd ); ch_free( p ); b->b_opening--; need_close--; } } if ( need_close || !need_open ) { /* It might be too late to repurpose a preparing connection, just * close them all */ while ( !LDAP_CIRCLEQ_EMPTY( &b->b_preparing ) ) { c = LDAP_CIRCLEQ_FIRST( &b->b_preparing ); event_del( c->c_read_event ); CONNECTION_LOCK_DESTROY(c); assert( c == NULL ); b->b_opening--; need_close--; } if ( event_pending( b->b_retry_event, EV_TIMEOUT, NULL ) ) { event_del( b->b_retry_event ); b->b_opening--; } assert( b->b_opening == 0 ); } if ( b->b_bindavail > bind_requested ) { int diff = b->b_bindavail - bind_requested; assert( need_close >= diff ); LDAP_CIRCLEQ_FOREACH ( c, &b->b_bindconns, c_next ) { int gentle = 1; lload_connection_close( c, &gentle ); need_close--; diff--; if ( !diff ) { break; } } assert( diff == 0 ); } if ( b->b_active > b->b_numconns ) { int diff = b->b_active - b->b_numconns; assert( need_close >= diff ); LDAP_CIRCLEQ_FOREACH ( c, &b->b_conns, c_next ) { int gentle = 1; lload_connection_close( c, &gentle ); need_close--; diff--; if ( !diff ) { break; } } assert( diff == 0 ); } assert( need_close == 0 ); if ( need_open ) { checked_lock( &b->b_mutex ); backend_retry( b ); checked_unlock( &b->b_mutex ); } } } void lload_handle_global_invalidation( LloadChange *change ) { assert( change->type == LLOAD_CHANGE_MODIFY ); assert( change->object == LLOAD_DAEMON ); if ( change->flags.daemon & LLOAD_DAEMON_MOD_THREADS ) { /* walk the task queue to remove any tasks belonging to us. */ /* TODO: initiate a full module restart, everything will fall into * place at that point */ ldap_pvt_thread_pool_walk( &connection_pool, handle_pdus, backend_conn_cb, NULL ); ldap_pvt_thread_pool_walk( &connection_pool, upstream_bind, backend_conn_cb, NULL ); assert(0); return; } if ( change->flags.daemon & LLOAD_DAEMON_MOD_FEATURES ) { lload_features_t feature_diff = lload_features ^ ( ~(uintptr_t)change->target ); /* Feature change handling: * - VC (TODO): * - on: terminate all bind connections * - off: cancel all bind operations in progress, reopen bind connections * - ProxyAuthz: * - on: nothing needed * - off: clear c_auth/privileged on each client * - read pause (WIP): * - nothing needed? */ assert( change->target ); if ( feature_diff & LLOAD_FEATURE_VC ) { assert(0); feature_diff &= ~LLOAD_FEATURE_VC; } if ( feature_diff & LLOAD_FEATURE_PAUSE ) { feature_diff &= ~LLOAD_FEATURE_PAUSE; } if ( feature_diff & LLOAD_FEATURE_PROXYAUTHZ ) { if ( !(lload_features & LLOAD_FEATURE_PROXYAUTHZ) ) { LloadConnection *c; /* We switched proxyauthz off */ LDAP_CIRCLEQ_FOREACH ( c, &clients, c_next ) { if ( !BER_BVISNULL( &c->c_auth ) ) { ber_memfree( c->c_auth.bv_val ); BER_BVZERO( &c->c_auth ); } if ( c->c_type == LLOAD_C_PRIVILEGED ) { c->c_type = LLOAD_C_OPEN; } } } feature_diff &= ~LLOAD_FEATURE_PROXYAUTHZ; } assert( !feature_diff ); } #ifdef HAVE_TLS if ( change->flags.daemon & LLOAD_DAEMON_MOD_TLS ) { /* terminate all clients with TLS set up */ ldap_pvt_thread_pool_walk( &connection_pool, handle_pdus, client_tls_cb, NULL ); if ( !LDAP_CIRCLEQ_EMPTY( &clients ) ) { LloadConnection *c = LDAP_CIRCLEQ_FIRST( &clients ); unsigned long first_connid = c->c_connid; while ( c ) { LloadConnection *next = LDAP_CIRCLEQ_LOOP_NEXT( &clients, c, c_next ); if ( c->c_is_tls ) { CONNECTION_LOCK_DESTROY(c); assert( c == NULL ); } c = next; if ( c->c_connid <= first_connid ) { c = NULL; } } } } #endif /* HAVE_TLS */ if ( change->flags.daemon & LLOAD_DAEMON_MOD_BINDCONF ) { LloadBackend *b; LloadConnection *c; /* * Only timeout changes can be handled gracefully, terminate all * connections and start over. */ ldap_pvt_thread_pool_walk( &connection_pool, handle_pdus, backend_conn_cb, NULL ); ldap_pvt_thread_pool_walk( &connection_pool, upstream_bind, backend_conn_cb, NULL ); LDAP_CIRCLEQ_FOREACH ( b, &backend, b_next ) { checked_lock( &b->b_mutex ); backend_reset( b, 0 ); backend_retry( b ); checked_unlock( &b->b_mutex ); } /* Reconsider the PRIVILEGED flag on all clients */ LDAP_CIRCLEQ_FOREACH ( c, &clients, c_next ) { int privileged = ber_bvstrcasecmp( &c->c_auth, &lloadd_identity ); /* We have just terminated all pending operations (even pins), there * should be no connections still binding/closing */ assert( c->c_state == LLOAD_C_READY ); c->c_type = privileged ? LLOAD_C_PRIVILEGED : LLOAD_C_OPEN; } } } int lload_handle_invalidation( LloadChange *change ) { if ( (change->type == LLOAD_CHANGE_MODIFY) && change->flags.generic == 0 ) { Debug( LDAP_DEBUG_ANY, "lload_handle_invalidation: " "a modify where apparently nothing changed\n" ); } switch ( change->object ) { case LLOAD_BACKEND: lload_handle_backend_invalidation( change ); break; case LLOAD_DAEMON: lload_handle_global_invalidation( change ); break; default: Debug( LDAP_DEBUG_ANY, "lload_handle_invalidation: " "unrecognised change\n" ); assert(0); } return LDAP_SUCCESS; } static void lload_pause_event_cb( evutil_socket_t s, short what, void *arg ) { /* * We are pausing, signal the pausing thread we've finished and * wait until the thread pool resumes operation. * * Do this in lockstep with the pausing thread. */ checked_lock( &lload_wait_mutex ); ldap_pvt_thread_cond_signal( &lload_wait_cond ); /* Now wait until we unpause, then we can resume operation */ ldap_pvt_thread_cond_wait( &lload_pause_cond, &lload_wait_mutex ); checked_unlock( &lload_wait_mutex ); } /* * Signal the event base to terminate processing as soon as it can and wait for * lload_pause_event_cb to notify us this has happened. */ static int lload_pause_base( struct event_base *base ) { int rc; checked_lock( &lload_wait_mutex ); event_base_once( base, -1, EV_TIMEOUT, lload_pause_event_cb, base, NULL ); rc = ldap_pvt_thread_cond_wait( &lload_wait_cond, &lload_wait_mutex ); checked_unlock( &lload_wait_mutex ); return rc; } void lload_pause_server( void ) { LloadChange ch = { .type = LLOAD_CHANGE_UNDEFINED }; int i; lload_pause_base( listener_base ); lload_pause_base( daemon_base ); for ( i = 0; i < lload_daemon_threads; i++ ) { lload_pause_base( lload_daemon[i].base ); } lload_change = ch; } void lload_unpause_server( void ) { if ( lload_change.type != LLOAD_CHANGE_UNDEFINED ) { lload_handle_invalidation( &lload_change ); } /* * Make sure lloadd is completely ready to unpause by now: * * After the broadcast, we handle I/O and begin filling the thread pool, in * high load conditions, we might hit the pool limits and start processing * operations in the I/O threads (one PDU per socket at a time for fairness * sake) even before a pause has finished from slapd's point of view! * * When (max_pdus_per_cycle == 0) we don't use the pool for these at all and * most lload processing starts immediately making this even more prominent. */ ldap_pvt_thread_cond_broadcast( &lload_pause_cond ); } #endif /* BALANCER_MODULE */ void lload_sig_shutdown( evutil_socket_t sig, short what, void *arg ) { struct event_base *daemon_base = arg; int save_errno = errno; int i; /* * If the NT Service Manager is controlling the server, we don't * want SIGBREAK to kill the server. For some strange reason, * SIGBREAK is generated when a user logs out. */ #if defined(HAVE_NT_SERVICE_MANAGER) && defined(SIGBREAK) if ( is_NT_Service && sig == SIGBREAK ) { /* empty */; } else #endif /* HAVE_NT_SERVICE_MANAGER && SIGBREAK */ #ifdef SIGHUP if ( sig == SIGHUP && global_gentlehup && slapd_gentle_shutdown == 0 ) { slapd_gentle_shutdown = 1; } else #endif /* SIGHUP */ { slapd_shutdown = 1; } for ( i = 0; i < lload_daemon_threads; i++ ) { event_base_loopexit( lload_daemon[i].base, NULL ); } event_base_loopexit( daemon_base, NULL ); errno = save_errno; } struct event_base * lload_get_base( ber_socket_t s ) { int tid = DAEMON_ID(s); return lload_daemon[tid].base; } LloadListener ** lloadd_get_listeners( void ) { /* Could return array with no listeners if !listening, but current * callers mostly look at the URLs. E.g. syncrepl uses this to * identify the server, which means it wants the startup arguments. */ return lload_listeners; } /* Reject all incoming requests */ void lload_suspend_listeners( void ) { int i; for ( i = 0; lload_listeners[i]; i++ ) { lload_listeners[i]->sl_mute = 1; evconnlistener_disable( lload_listeners[i]->listener ); listen( lload_listeners[i]->sl_sd, 0 ); } } /* Resume after a suspend */ void lload_resume_listeners( void ) { int i; for ( i = 0; lload_listeners[i]; i++ ) { lload_listeners[i]->sl_mute = 0; listen( lload_listeners[i]->sl_sd, SLAPD_LISTEN_BACKLOG ); evconnlistener_enable( lload_listeners[i]->listener ); } } openldap-2.5.11+dfsg/servers/lloadd/libevent_support.c0000644000175000017500000000772414172327167021551 0ustar ryanryan/* libevent_support.c - routines to bridge libldap and libevent */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2017-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #include "portable.h" #include #include #include #include "lload.h" #include "ldap_pvt_thread.h" static void * lload_libevent_mutex_init( unsigned locktype ) { int rc; ldap_pvt_thread_mutex_t *mutex = ch_malloc( sizeof(ldap_pvt_thread_mutex_t) ); if ( locktype & EVTHREAD_LOCKTYPE_RECURSIVE ) { rc = ldap_pvt_thread_mutex_recursive_init( mutex ); } else { rc = ldap_pvt_thread_mutex_init( mutex ); } if ( rc ) { ch_free( mutex ); mutex = NULL; } return mutex; } static void lload_libevent_mutex_destroy( void *lock, unsigned locktype ) { int rc; ldap_pvt_thread_mutex_t *mutex = lock; rc = ldap_pvt_thread_mutex_destroy( mutex ); assert( rc == 0 ); ch_free( mutex ); } static int lload_libevent_mutex_lock( unsigned mode, void *lock ) { ldap_pvt_thread_mutex_t *mutex = lock; if ( mode & EVTHREAD_TRY ) { return ldap_pvt_thread_mutex_trylock( mutex ); } else { return ldap_pvt_thread_mutex_lock( mutex ); } } static int lload_libevent_mutex_unlock( unsigned mode, void *lock ) { ldap_pvt_thread_mutex_t *mutex = lock; return ldap_pvt_thread_mutex_unlock( mutex ); } static void * lload_libevent_cond_init( unsigned condtype ) { int rc; ldap_pvt_thread_cond_t *cond = ch_malloc( sizeof(ldap_pvt_thread_cond_t) ); assert( condtype == 0 ); rc = ldap_pvt_thread_cond_init( cond ); if ( rc ) { ch_free( cond ); cond = NULL; } return cond; } static void lload_libevent_cond_destroy( void *c ) { int rc; ldap_pvt_thread_cond_t *cond = c; rc = ldap_pvt_thread_cond_destroy( cond ); assert( rc == 0 ); ch_free( c ); } static int lload_libevent_cond_signal( void *c, int broadcast ) { ldap_pvt_thread_cond_t *cond = c; if ( broadcast ) { return ldap_pvt_thread_cond_broadcast( cond ); } else { return ldap_pvt_thread_cond_signal( cond ); } } static int lload_libevent_cond_timedwait( void *c, void *lock, const struct timeval *timeout ) { ldap_pvt_thread_cond_t *cond = c; ldap_pvt_thread_mutex_t *mutex = lock; /* * libevent does not seem to request a timeout, this is true as of 2.1.8 * that has just been marked the first stable release of the 2.1 series */ assert( timeout == NULL ); return ldap_pvt_thread_cond_wait( cond, mutex ); } int lload_libevent_init( void ) { struct evthread_lock_callbacks cbs = { EVTHREAD_LOCK_API_VERSION, EVTHREAD_LOCKTYPE_RECURSIVE, lload_libevent_mutex_init, lload_libevent_mutex_destroy, lload_libevent_mutex_lock, lload_libevent_mutex_unlock }; struct evthread_condition_callbacks cond_cbs = { EVTHREAD_CONDITION_API_VERSION, lload_libevent_cond_init, lload_libevent_cond_destroy, lload_libevent_cond_signal, lload_libevent_cond_timedwait }; #ifndef BALANCER_MODULE /* only necessary if lload is a server, slapd already calls * ldap_pvt_thread_initialize() */ if ( ldap_pvt_thread_initialize() ) { return -1; } #endif evthread_set_lock_callbacks( &cbs ); evthread_set_condition_callbacks( &cond_cbs ); evthread_set_id_callback( ldap_pvt_thread_self ); return 0; } void lload_libevent_destroy( void ) { libevent_global_shutdown(); } openldap-2.5.11+dfsg/servers/lloadd/epoch.h0000644000175000017500000001122314172327167017235 0ustar ryanryan/* epoch.h - epoch based memory reclamation */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2018-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ #ifndef __LLOAD_EPOCH_H #define __LLOAD_EPOCH_H /** @file epoch.h * * Implementation of epoch based memory reclamation, in principle * similar to the algorithm presented in * https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.pdf */ typedef uintptr_t epoch_t; /** @brief A callback function used to free object and associated data */ typedef void (dispose_cb)( void *object ); /** @brief Initiate global state */ void epoch_init( void ); /** @brief Finalise global state and free any objects still pending */ void epoch_shutdown( void ); /** @brief Register thread as active * * In order to safely access managed objects, a thread should call * this function or make sure no other thread is running (e.g. config * pause, late shutdown). After calling this, it is guaranteed that no * reachable objects will be freed before all threads have called * `epoch_leave( current_epoch + 1 )` so it is essential that there * is an upper limit to the amount of time between #epoch_join and * corresponding #epoch_leave or the number of unfreed objects might * grow without bounds. * * To simplify locking, memory is only freed when the current epoch * is advanced rather than on leaving it. * * Can be safely called multiple times by the same thread as long as * a matching #epoch_leave() call is made eventually. * * @return The observed epoch, to be passed to #epoch_leave() */ epoch_t epoch_join( void ); /** @brief Register thread as inactive * * A thread should call this after they are finished with work * performed since matching call to #epoch_join(). It is not safe * to keep a local reference to managed objects after this call * unless other precautions have been made to prevent it being * released. * * @param[in] epoch Epoch identifier returned by a previous call to * #epoch_join(). */ void epoch_leave( epoch_t epoch ); /** @brief Return an unreachable object to be freed * * The object should already be unreachable at the point of call and * cb will be invoked when no other thread that could have seen it * is active any more. This happens when we have advanced by two * epochs. * * @param[in] ptr Object to be released/freed * @param[in] cb Callback to invoke when safe to do so */ void epoch_append( void *ptr, dispose_cb *cb ); /** * \defgroup Reference counting helpers */ /**@{*/ /** @brief Acquire a reference if possible * * Atomically, check reference count is non-zero and increment if so. * Returns old reference count. * * @param[in] refp Pointer to a reference counter * @return 0 if reference was already zero, non-zero if reference * count was successfully incremented */ int acquire_ref( uintptr_t *refp ); /** @brief Check reference count and try to decrement * * Atomically, decrement reference count if non-zero and register * object if decremented to zero. Returning previous reference count. * * @param[in] refp Pointer to a reference counter * @param[in] object The managed object * @param[in] cb Callback to invoke when safe to do so * @return 0 if reference was already zero, non-zero if reference * count was non-zero at the time of call */ int try_release_ref( uintptr_t *refp, void *object, dispose_cb *cb ); /** @brief Read reference count * * @param[in] object Pointer to the managed object * @param[in] ref_field Member where reference count is stored in * the object * @return Current value of reference counter */ #define IS_ALIVE( object, ref_field ) \ __atomic_load_n( &(object)->ref_field, __ATOMIC_ACQUIRE ) /** @brief Release reference * * A cheaper alternative to #try_release_ref(), safe only when we know * reference count was already non-zero. * * @param[in] object The managed object * @param[in] ref_field Member where reference count is stored in * the object * @param[in] cb Callback to invoke when safe to do so */ #define RELEASE_REF( object, ref_field, cb ) \ do { \ assert( IS_ALIVE( (object), ref_field ) ); \ if ( !__atomic_sub_fetch( \ &(object)->ref_field, 1, __ATOMIC_ACQ_REL ) ) { \ epoch_append( object, (dispose_cb *)cb ); \ } \ } while (0) /**@}*/ #endif /* __LLOAD_EPOCH_H */ openldap-2.5.11+dfsg/servers/lloadd/main.c0000644000175000017500000006134614172327167017071 0ustar ryanryan/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* Portions Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ #include "portable.h" #include #include #include #include #include #include #include #include #include #include "lload.h" #include "lutil.h" #include "ldif.h" #ifdef LDAP_SIGCHLD static void wait4child( evutil_socket_t sig, short what, void *arg ); #endif #ifdef SIGPIPE static void sigpipe( evutil_socket_t sig, short what, void *arg ); #endif #ifdef HAVE_NT_SERVICE_MANAGER #define MAIN_RETURN(x) return static struct sockaddr_in bind_addr; #define SERVICE_EXIT( e, n ) \ do { \ if ( is_NT_Service ) { \ lutil_ServiceStatus.dwWin32ExitCode = (e); \ lutil_ServiceStatus.dwServiceSpecificExitCode = (n); \ } \ } while (0) #else #define SERVICE_EXIT( e, n ) #define MAIN_RETURN(x) return (x) #endif struct signal_handler { int signal; event_callback_fn handler; struct event *event; } signal_handlers[] = { { LDAP_SIGUSR2, lload_sig_shutdown }, #ifdef SIGPIPE { SIGPIPE, sigpipe }, #endif #ifdef SIGHUP { SIGHUP, lload_sig_shutdown }, #endif { SIGINT, lload_sig_shutdown }, { SIGTERM, lload_sig_shutdown }, #ifdef SIGTRAP { SIGTRAP, lload_sig_shutdown }, #endif #ifdef LDAP_SIGCHLD { LDAP_SIGCHLD, wait4child }, #endif #ifdef SIGBREAK /* SIGBREAK is generated when Ctrl-Break is pressed. */ { SIGBREAK, lload_sig_shutdown }, #endif { 0, NULL } }; /* * when more than one lloadd is running on one machine, each one might have * it's own LOCAL for syslogging and must have its own pid/args files */ #ifndef HAVE_MKVERSION const char Versionstr[] = OPENLDAP_PACKAGE " " OPENLDAP_VERSION " LDAP Load Balancer Server (lloadd)"; #endif #define CHECK_NONE 0x00 #define CHECK_CONFIG 0x01 #define CHECK_LOGLEVEL 0x02 static int check = CHECK_NONE; static int version = 0; static int slapd_opt_slp( const char *val, void *arg ) { #ifdef HAVE_SLP /* NULL is default */ if ( val == NULL || *val == '(' || strcasecmp( val, "on" ) == 0 ) { slapd_register_slp = 1; slapd_slp_attrs = ( val != NULL && *val == '(' ) ? val : NULL; } else if ( strcasecmp( val, "off" ) == 0 ) { slapd_register_slp = 0; /* NOTE: add support for URL specification? */ } else { fprintf( stderr, "unrecognized value \"%s\" for SLP option\n", val ); return -1; } return 0; #else fputs( "lloadd: SLP support is not available\n", stderr ); return 0; #endif } /* * Option helper structure: * * oh_nam is left-hand part of