summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorpiaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2008-03-27 01:26:28 +0800
committerpiaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2008-03-27 01:26:28 +0800
commitb27ece46a69aa7d5b9a759a2164609dab689f258 (patch)
treead7387b6b59ecfc3215deec393d1c932db8d09af /common
parent1ac9e4897fdf8839328d9c47d1d2f0cc27b02f1d (diff)
downloadpttbbs-b27ece46a69aa7d5b9a759a2164609dab689f258.tar
pttbbs-b27ece46a69aa7d5b9a759a2164609dab689f258.tar.gz
pttbbs-b27ece46a69aa7d5b9a759a2164609dab689f258.tar.bz2
pttbbs-b27ece46a69aa7d5b9a759a2164609dab689f258.tar.lz
pttbbs-b27ece46a69aa7d5b9a759a2164609dab689f258.tar.xz
pttbbs-b27ece46a69aa7d5b9a759a2164609dab689f258.tar.zst
pttbbs-b27ece46a69aa7d5b9a759a2164609dab689f258.zip
(internal) refine directory layout: libbbs/libbbsutil -> common/bbs,sys.
git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@4027 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
Diffstat (limited to 'common')
-rw-r--r--common/Makefile8
-rw-r--r--common/bbs/Makefile24
-rw-r--r--common/bbs/log.c0
-rw-r--r--common/bbs/money.c36
-rw-r--r--common/bbs/string.c1
-rw-r--r--common/diet/alloc.c254
-rw-r--r--common/diet/random.c711
-rw-r--r--common/diet/time.c20
-rw-r--r--common/sys/Makefile24
-rw-r--r--common/sys/crypt.c647
-rw-r--r--common/sys/file.c489
-rw-r--r--common/sys/lock.c23
-rw-r--r--common/sys/log.c43
-rw-r--r--common/sys/net.c114
-rw-r--r--common/sys/osdep.c376
-rw-r--r--common/sys/sort.c10
-rw-r--r--common/sys/string.c345
-rw-r--r--common/sys/time.c116
18 files changed, 3241 insertions, 0 deletions
diff --git a/common/Makefile b/common/Makefile
new file mode 100644
index 00000000..2fc631d4
--- /dev/null
+++ b/common/Makefile
@@ -0,0 +1,8 @@
+SUBDIR= bbs sys
+
+all install clean:
+ @for i in $(SUBDIR); do\
+ cd $$i;\
+ $(MAKE) $@;\
+ cd -;\
+ done
diff --git a/common/bbs/Makefile b/common/bbs/Makefile
new file mode 100644
index 00000000..6ed3e554
--- /dev/null
+++ b/common/bbs/Makefile
@@ -0,0 +1,24 @@
+
+SRCROOT= ../..
+.include "$(SRCROOT)/pttbbs.mk"
+
+CFLAGS+= -I$(SRCROOT)/include
+
+OBJS= log.o string.o money.o
+TARGET= libcmbbs.a
+
+
+.SUFFIXES: .c .o
+.c.o:
+ $(CCACHE) $(DIETCC) $(CC) $(CFLAGS) -c $*.c
+
+all: $(TARGET)
+
+install:
+
+$(TARGET): $(OBJS)
+ $(AR) cru $@ $(OBJS)
+ ranlib $@
+
+clean:
+ rm -f $(OBJS) $(TARGET)
diff --git a/common/bbs/log.c b/common/bbs/log.c
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/common/bbs/log.c
diff --git a/common/bbs/money.c b/common/bbs/money.c
new file mode 100644
index 00000000..f2c7b9b3
--- /dev/null
+++ b/common/bbs/money.c
@@ -0,0 +1,36 @@
+#include <stdio.h>
+#include "cmbbs.h"
+
+/* 計算贈與稅 */
+int
+give_tax(int money)
+{
+ int i, tax = 0;
+ int tax_bound[] = {1000000, 100000, 10000, 1000, 0};
+ double tax_rate[] = {0.4, 0.3, 0.2, 0.1, 0.08};
+ for (i = 0; i <= 4; i++)
+ if (money > tax_bound[i]) {
+ tax += (money - tax_bound[i]) * tax_rate[i];
+ money -= (money - tax_bound[i]);
+ }
+ return (tax <= 0) ? 1 : tax;
+}
+
+const char*
+money_level(int money)
+{
+ int i = 0;
+
+ static const char *money_msg[] =
+ {
+ "債台高築", "赤貧", "清寒", "普通", "小康",
+ "小富", "中富", "大富翁", "富可敵國", "比爾蓋\天", NULL
+ };
+ while (money_msg[i] && money > 10)
+ i++, money /= 10;
+
+ if(!money_msg[i])
+ i--;
+ return money_msg[i];
+}
+
diff --git a/common/bbs/string.c b/common/bbs/string.c
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/common/bbs/string.c
@@ -0,0 +1 @@
+
diff --git a/common/diet/alloc.c b/common/diet/alloc.c
new file mode 100644
index 00000000..de676ce4
--- /dev/null
+++ b/common/diet/alloc.c
@@ -0,0 +1,254 @@
+/*
+ * malloc/free by O.Dreesen
+ *
+ * first TRY:
+ * lists w/magics
+ * and now the second TRY
+ * let the kernel map all the stuff (if there is something to do)
+ */
+
+#include <unistd.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/shm.h> /* for PAGE_SIZE */
+
+
+/* -- HELPER CODE --------------------------------------------------------- */
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void*)-1)
+#endif
+
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+typedef struct {
+ void* next;
+ size_t size;
+} __alloc_t;
+
+#define BLOCK_START(b) (((void*)(b))-sizeof(__alloc_t))
+#define BLOCK_RET(b) (((void*)(b))+sizeof(__alloc_t))
+
+#define MEM_BLOCK_SIZE PAGE_SIZE
+#define PAGE_ALIGN(s) (((s)+MEM_BLOCK_SIZE-1)&(unsigned long)(~(MEM_BLOCK_SIZE-1)))
+
+/* a simple mmap :) */
+#if defined(__i386__)
+#define REGPARM(x) __attribute__((regparm(x)))
+#else
+#define REGPARM(x)
+#endif
+
+static void REGPARM(1) *do_mmap(size_t size) {
+ return mmap(0, size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, (size_t)0);
+}
+
+/* -- SMALL MEM ----------------------------------------------------------- */
+
+static __alloc_t* __small_mem[8];
+
+static int smallalloc[8];
+static int smallalloc_max[8];
+
+#define __SMALL_NR(i) (MEM_BLOCK_SIZE/(i))
+
+#define __MIN_SMALL_SIZE __SMALL_NR(256) /* 16 / 32 */
+#define __MAX_SMALL_SIZE __SMALL_NR(2) /* 2048 / 4096 */
+
+#define GET_SIZE(s) (__MIN_SMALL_SIZE<<get_index((s)))
+
+#define FIRST_SMALL(p) (((unsigned long)(p))&(~(MEM_BLOCK_SIZE-1)))
+
+static inline int __ind_shift() { return (MEM_BLOCK_SIZE==4096)?4:5; }
+
+static size_t REGPARM(1) get_index(size_t _size) {
+ register size_t idx=0;
+// if (_size) { /* we already check this in the callers */
+ register size_t size=((_size-1)&(MEM_BLOCK_SIZE-1))>>__ind_shift();
+ while(size) { size>>=1; ++idx; }
+// }
+ return idx;
+}
+
+/* small mem */
+static void __small_free(void*_ptr,size_t _size) REGPARM(2);
+
+static void REGPARM(2) __small_free(void*_ptr,size_t _size) {
+ __alloc_t* ptr=BLOCK_START(_ptr);
+ size_t size=_size;
+ size_t idx=get_index(size);
+
+ memset(ptr,0,size); /* allways zero out small mem */
+
+ ptr->next=__small_mem[idx];
+ __small_mem[idx]=ptr;
+
+ smallalloc[idx]--;
+
+ if (MEM_BLOCK_SIZE == PAGE_SIZE &&
+ smallalloc[idx] == 0 &&
+ smallalloc_max[idx] < __SMALL_NR(size)) {
+ __alloc_t* p = __small_mem[idx];
+ __alloc_t* ph = p - (size_t)p%PAGE_SIZE;
+ munmap(ph, MEM_BLOCK_SIZE);
+ __small_mem[idx] = 0;
+ }
+}
+
+static void* REGPARM(1) __small_malloc(size_t _size) {
+ __alloc_t *ptr;
+ size_t size=_size;
+ size_t idx;
+
+ idx=get_index(size);
+ ptr=__small_mem[idx];
+
+ if (ptr==0) { /* no free blocks ? */
+ register int i,nr;
+ ptr=do_mmap(MEM_BLOCK_SIZE);
+ if (ptr==MAP_FAILED) return MAP_FAILED;
+
+ __small_mem[idx]=ptr;
+
+ nr=__SMALL_NR(size)-1;
+ for (i=0;i<nr;i++) {
+ ptr->next=(((void*)ptr)+size);
+ ptr=ptr->next;
+ }
+ ptr->next=0;
+
+ ptr=__small_mem[idx];
+ }
+
+ /* get a free block */
+ __small_mem[idx]=ptr->next;
+ ptr->next=0;
+
+ smallalloc[idx]++;
+ if(smallalloc[idx] > smallalloc_max[idx])
+ smallalloc_max[idx] = smallalloc[idx];
+
+ return ptr;
+}
+
+/* -- PUBLIC FUNCTIONS ---------------------------------------------------- */
+
+static void _alloc_libc_free(void *ptr) {
+ register size_t size;
+ if (ptr) {
+ size=((__alloc_t*)BLOCK_START(ptr))->size;
+ if (size) {
+ if (size<=__MAX_SMALL_SIZE)
+ __small_free(ptr,size);
+ else
+ munmap(BLOCK_START(ptr),size);
+ }
+ }
+}
+void __libc_free(void *ptr) __attribute__((alias("_alloc_libc_free")));
+void free(void *ptr) __attribute__((weak,alias("_alloc_libc_free")));
+void if_freenameindex(void* ptr) __attribute__((alias("free")));
+
+#ifdef WANT_MALLOC_ZERO
+static __alloc_t zeromem[2];
+#endif
+
+static void* _alloc_libc_malloc(size_t size) {
+ __alloc_t* ptr;
+ size_t need;
+#ifdef WANT_MALLOC_ZERO
+ if (!size) return BLOCK_RET(zeromem);
+#else
+ if (!size) goto err_out;
+#endif
+ size+=sizeof(__alloc_t);
+ if (size<sizeof(__alloc_t)) goto err_out;
+ if (size<=__MAX_SMALL_SIZE) {
+ need=GET_SIZE(size);
+ ptr=__small_malloc(need);
+ }
+ else {
+ need=PAGE_ALIGN(size);
+ if (!need) ptr=MAP_FAILED; else ptr=do_mmap(need);
+ }
+ if (ptr==MAP_FAILED) goto err_out;
+ ptr->size=need;
+ return BLOCK_RET(ptr);
+err_out:
+ (*__errno_location())=ENOMEM;
+ return 0;
+}
+void* __libc_malloc(size_t size) __attribute__((alias("_alloc_libc_malloc")));
+void* malloc(size_t size) __attribute__((weak,alias("_alloc_libc_malloc")));
+
+void* __libc_calloc(size_t nmemb, size_t _size);
+void* __libc_calloc(size_t nmemb, size_t _size) {
+ register size_t size=_size*nmemb;
+ if (nmemb && size/nmemb!=_size) {
+ (*__errno_location())=ENOMEM;
+ return 0;
+ }
+ return malloc(size);
+}
+void* calloc(size_t nmemb, size_t _size) __attribute__((weak,alias("__libc_calloc")));
+
+void* __libc_realloc(void* ptr, size_t _size);
+void* __libc_realloc(void* ptr, size_t _size) {
+ register size_t size=_size;
+ if (ptr) {
+ if (size) {
+ __alloc_t* tmp=BLOCK_START(ptr);
+ size+=sizeof(__alloc_t);
+ if (size<sizeof(__alloc_t)) goto retzero;
+ size=(size<=__MAX_SMALL_SIZE)?GET_SIZE(size):PAGE_ALIGN(size);
+ if (tmp->size!=size) {
+ if ((tmp->size<=__MAX_SMALL_SIZE)) {
+ void *new=_alloc_libc_malloc(_size);
+ if (new) {
+ register __alloc_t* foo=BLOCK_START(new);
+ size=foo->size;
+ if (size>tmp->size) size=tmp->size;
+ if (size) memcpy(new,ptr,size-sizeof(__alloc_t));
+ _alloc_libc_free(ptr);
+ }
+ ptr=new;
+ }
+ else {
+ register __alloc_t* foo;
+ size=PAGE_ALIGN(size);
+ foo=mremap(tmp,tmp->size,size,MREMAP_MAYMOVE);
+ if (foo==MAP_FAILED) {
+retzero:
+ (*__errno_location())=ENOMEM;
+ ptr=0;
+ }
+ else {
+ foo->size=size;
+ ptr=BLOCK_RET(foo);
+ }
+ }
+ }
+ }
+ else { /* size==0 */
+ _alloc_libc_free(ptr);
+ ptr = NULL;
+ }
+ }
+ else { /* ptr==0 */
+ if (size) {
+ ptr=_alloc_libc_malloc(size);
+ }
+ }
+ return ptr;
+}
+void* realloc(void* ptr, size_t size) __attribute__((weak,alias("__libc_realloc")));
+
diff --git a/common/diet/random.c b/common/diet/random.c
new file mode 100644
index 00000000..dd369c41
--- /dev/null
+++ b/common/diet/random.c
@@ -0,0 +1,711 @@
+#ifdef __dietlibc__
+/*
+ Copyright (C) 1995 Free Software Foundation
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/*
+ Copyright (C) 1983 Regents of the University of California.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 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.
+ 4. Neither the name of the University nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.*/
+
+/*
+ * This is derived from the Berkeley source:
+ * @(#)random.c 5.5 (Berkeley) 7/6/88
+ * It was reworked for the GNU C Library by Roland McGrath.
+ * Rewritten to be reentrant by Ulrich Drepper, 1995
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+struct random_data
+ {
+ int32_t *fptr; /* Front pointer. */
+ int32_t *rptr; /* Rear pointer. */
+ int32_t *state; /* Array of state values. */
+ int rand_type; /* Type of random number generator. */
+ int rand_deg; /* Degree of random number generator. */
+ int rand_sep; /* Distance between front and rear. */
+ int32_t *end_ptr; /* Pointer behind state table. */
+ };
+int __random_r (struct random_data *buf, int32_t *result);
+
+
+
+/* An improved random number generation package. In addition to the standard
+ rand()/srand() like interface, this package also has a special state info
+ interface. The initstate() routine is called with a seed, an array of
+ bytes, and a count of how many bytes are being passed in; this array is
+ then initialized to contain information for random number generation with
+ that much state information. Good sizes for the amount of state
+ information are 32, 64, 128, and 256 bytes. The state can be switched by
+ calling the setstate() function with the same array as was initialized
+ with initstate(). By default, the package runs with 128 bytes of state
+ information and generates far better random numbers than a linear
+ congruential generator. If the amount of state information is less than
+ 32 bytes, a simple linear congruential R.N.G. is used. Internally, the
+ state information is treated as an array of longs; the zeroth element of
+ the array is the type of R.N.G. being used (small integer); the remainder
+ of the array is the state information for the R.N.G. Thus, 32 bytes of
+ state information will give 7 longs worth of state information, which will
+ allow a degree seven polynomial. (Note: The zeroth word of state
+ information also has some other information stored in it; see setstate
+ for details). The random number generation technique is a linear feedback
+ shift register approach, employing trinomials (since there are fewer terms
+ to sum up that way). In this approach, the least significant bit of all
+ the numbers in the state table will act as a linear feedback shift register,
+ and will have period 2^deg - 1 (where deg is the degree of the polynomial
+ being used, assuming that the polynomial is irreducible and primitive).
+ The higher order bits will have longer periods, since their values are
+ also influenced by pseudo-random carries out of the lower bits. The
+ total period of the generator is approximately deg*(2**deg - 1); thus
+ doubling the amount of state information has a vast influence on the
+ period of the generator. Note: The deg*(2**deg - 1) is an approximation
+ only good for large deg, when the period of the shift register is the
+ dominant factor. With deg equal to seven, the period is actually much
+ longer than the 7*(2**7 - 1) predicted by this formula. */
+
+
+
+/* For each of the currently supported random number generators, we have a
+ break value on the amount of state information (you need at least this many
+ bytes of state info to support this random number generator), a degree for
+ the polynomial (actually a trinomial) that the R.N.G. is based on, and
+ separation between the two lower order coefficients of the trinomial. */
+
+/* Linear congruential. */
+#define TYPE_0 0
+#define BREAK_0 8
+#define DEG_0 0
+#define SEP_0 0
+
+/* x**7 + x**3 + 1. */
+#define TYPE_1 1
+#define BREAK_1 32
+#define DEG_1 7
+#define SEP_1 3
+
+/* x**15 + x + 1. */
+#define TYPE_2 2
+#define BREAK_2 64
+#define DEG_2 15
+#define SEP_2 1
+
+/* x**31 + x**3 + 1. */
+#define TYPE_3 3
+#define BREAK_3 128
+#define DEG_3 31
+#define SEP_3 3
+
+/* x**63 + x + 1. */
+#define TYPE_4 4
+#define BREAK_4 256
+#define DEG_4 63
+#define SEP_4 1
+
+
+/* Array versions of the above information to make code run faster.
+ Relies on fact that TYPE_i == i. */
+
+#define MAX_TYPES 5 /* Max number of types above. */
+
+struct random_poly_info
+{
+ int seps[MAX_TYPES];
+ int degrees[MAX_TYPES];
+};
+
+static const struct random_poly_info random_poly_info =
+{
+ { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 },
+ { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }
+};
+
+
+
+
+/* Initialize the random number generator based on the given seed. If the
+ type is the trivial no-state-information type, just remember the seed.
+ Otherwise, initializes state[] based on the given "seed" via a linear
+ congruential generator. Then, the pointers are set to known locations
+ that are exactly rand_sep places apart. Lastly, it cycles the state
+ information a given number of times to get rid of any initial dependencies
+ introduced by the L.C.R.N.G. Note that the initialization of randtbl[]
+ for default usage relies on values produced by this routine. */
+int
+__srandom_r (seed, buf)
+ unsigned int seed;
+ struct random_data *buf;
+{
+ int type;
+ int32_t *state;
+ long int i;
+ long int word;
+ int32_t *dst;
+ int kc;
+
+ if (buf == NULL)
+ goto fail;
+ type = buf->rand_type;
+ if ((unsigned int) type >= MAX_TYPES)
+ goto fail;
+
+ state = buf->state;
+ /* We must make sure the seed is not 0. Take arbitrarily 1 in this case. */
+ if (seed == 0)
+ seed = 1;
+ state[0] = seed;
+ if (type == TYPE_0)
+ goto done;
+
+ dst = state;
+ word = seed;
+ kc = buf->rand_deg;
+ for (i = 1; i < kc; ++i)
+ {
+ /* This does:
+ state[i] = (16807 * state[i - 1]) % 2147483647;
+ but avoids overflowing 31 bits. */
+ long int hi = word / 127773;
+ long int lo = word % 127773;
+ word = 16807 * lo - 2836 * hi;
+ if (word < 0)
+ word += 2147483647;
+ *++dst = word;
+ }
+
+ buf->fptr = &state[buf->rand_sep];
+ buf->rptr = &state[0];
+ kc *= 10;
+ while (--kc >= 0)
+ {
+ int32_t discard;
+ (void) __random_r (buf, &discard);
+ }
+
+ done:
+ return 0;
+
+ fail:
+ return -1;
+}
+
+
+/* Initialize the state information in the given array of N bytes for
+ future random number generation. Based on the number of bytes we
+ are given, and the break values for the different R.N.G.'s, we choose
+ the best (largest) one we can and set things up for it. srandom is
+ then called to initialize the state information. Note that on return
+ from srandom, we set state[-1] to be the type multiplexed with the current
+ value of the rear pointer; this is so successive calls to initstate won't
+ lose this information and will be able to restart with setstate.
+ Note: The first thing we do is save the current state, if any, just like
+ setstate so that it doesn't matter when initstate is called.
+ Returns a pointer to the old state. */
+int
+__initstate_r (seed, arg_state, n, buf)
+ unsigned int seed;
+ char *arg_state;
+ size_t n;
+ struct random_data *buf;
+{
+ int type;
+ int degree;
+ int separation;
+ int32_t *state;
+
+ if (buf == NULL)
+ goto fail;
+
+ if (n >= BREAK_3)
+ type = n < BREAK_4 ? TYPE_3 : TYPE_4;
+ else if (n < BREAK_1)
+ {
+ if (n < BREAK_0)
+ {
+ __set_errno (EINVAL);
+ goto fail;
+ }
+ type = TYPE_0;
+ }
+ else
+ type = n < BREAK_2 ? TYPE_1 : TYPE_2;
+
+ degree = random_poly_info.degrees[type];
+ separation = random_poly_info.seps[type];
+
+ buf->rand_type = type;
+ buf->rand_sep = separation;
+ buf->rand_deg = degree;
+ state = &((int32_t *) arg_state)[1]; /* First location. */
+ /* Must set END_PTR before srandom. */
+ buf->end_ptr = &state[degree];
+
+ buf->state = state;
+
+ __srandom_r (seed, buf);
+
+ state[-1] = TYPE_0;
+ if (type != TYPE_0)
+ state[-1] = (buf->rptr - state) * MAX_TYPES + type;
+
+ return 0;
+
+ fail:
+ __set_errno (EINVAL);
+ return -1;
+}
+
+
+/* Restore the state from the given state array.
+ Note: It is important that we also remember the locations of the pointers
+ in the current state information, and restore the locations of the pointers
+ from the old state information. This is done by multiplexing the pointer
+ location into the zeroth word of the state information. Note that due
+ to the order in which things are done, it is OK to call setstate with the
+ same state as the current state
+ Returns a pointer to the old state information. */
+int
+__setstate_r (arg_state, buf)
+ char *arg_state;
+ struct random_data *buf;
+{
+ int32_t *new_state = 1 + (int32_t *) arg_state;
+ int type;
+ int old_type;
+ int32_t *old_state;
+ int degree;
+ int separation;
+
+ if (arg_state == NULL || buf == NULL)
+ goto fail;
+
+ old_type = buf->rand_type;
+ old_state = buf->state;
+ if (old_type == TYPE_0)
+ old_state[-1] = TYPE_0;
+ else
+ old_state[-1] = (MAX_TYPES * (buf->rptr - old_state)) + old_type;
+
+ type = new_state[-1] % MAX_TYPES;
+ if (type < TYPE_0 || type > TYPE_4)
+ goto fail;
+
+ buf->rand_deg = degree = random_poly_info.degrees[type];
+ buf->rand_sep = separation = random_poly_info.seps[type];
+ buf->rand_type = type;
+
+ if (type != TYPE_0)
+ {
+ int rear = new_state[-1] / MAX_TYPES;
+ buf->rptr = &new_state[rear];
+ buf->fptr = &new_state[(rear + separation) % degree];
+ }
+ buf->state = new_state;
+ /* Set end_ptr too. */
+ buf->end_ptr = &new_state[degree];
+
+ return 0;
+
+ fail:
+ __set_errno (EINVAL);
+ return -1;
+}
+
+
+/* If we are using the trivial TYPE_0 R.N.G., just do the old linear
+ congruential bit. Otherwise, we do our fancy trinomial stuff, which is the
+ same in all the other cases due to all the global variables that have been
+ set up. The basic operation is to add the number at the rear pointer into
+ the one at the front pointer. Then both pointers are advanced to the next
+ location cyclically in the table. The value returned is the sum generated,
+ reduced to 31 bits by throwing away the "least random" low bit.
+ Note: The code takes advantage of the fact that both the front and
+ rear pointers can't wrap on the same call by not testing the rear
+ pointer if the front one has wrapped. Returns a 31-bit random number. */
+
+int
+__random_r (buf, result)
+ struct random_data *buf;
+ int32_t *result;
+{
+ int32_t *state;
+
+ if (buf == NULL || result == NULL)
+ goto fail;
+
+ state = buf->state;
+
+ if (buf->rand_type == TYPE_0)
+ {
+ int32_t val = state[0];
+ val = ((state[0] * 1103515245) + 12345) & 0x7fffffff;
+ state[0] = val;
+ *result = val;
+ }
+ else
+ {
+ int32_t *fptr = buf->fptr;
+ int32_t *rptr = buf->rptr;
+ int32_t *end_ptr = buf->end_ptr;
+ int32_t val;
+
+ val = *fptr += *rptr;
+ /* Chucking least random bit. */
+ *result = (val >> 1) & 0x7fffffff;
+ ++fptr;
+ if (fptr >= end_ptr)
+ {
+ fptr = state;
+ ++rptr;
+ }
+ else
+ {
+ ++rptr;
+ if (rptr >= end_ptr)
+ rptr = state;
+ }
+ buf->fptr = fptr;
+ buf->rptr = rptr;
+ }
+ return 0;
+
+ fail:
+ __set_errno (EINVAL);
+ return -1;
+}
+
+/* Copyright (C) 1995 Free Software Foundation
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/*
+ * This is derived from the Berkeley source:
+ * @(#)random.c 5.5 (Berkeley) 7/6/88
+ * It was reworked for the GNU C Library by Roland McGrath.
+ * Rewritten to use reentrant functions by Ulrich Drepper, 1995.
+ */
+
+/*
+ Copyright (C) 1983 Regents of the University of California.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 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.
+ 4. Neither the name of the University nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.*/
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+
+/* An improved random number generation package. In addition to the standard
+ rand()/srand() like interface, this package also has a special state info
+ interface. The initstate() routine is called with a seed, an array of
+ bytes, and a count of how many bytes are being passed in; this array is
+ then initialized to contain information for random number generation with
+ that much state information. Good sizes for the amount of state
+ information are 32, 64, 128, and 256 bytes. The state can be switched by
+ calling the setstate() function with the same array as was initialized
+ with initstate(). By default, the package runs with 128 bytes of state
+ information and generates far better random numbers than a linear
+ congruential generator. If the amount of state information is less than
+ 32 bytes, a simple linear congruential R.N.G. is used. Internally, the
+ state information is treated as an array of longs; the zeroth element of
+ the array is the type of R.N.G. being used (small integer); the remainder
+ of the array is the state information for the R.N.G. Thus, 32 bytes of
+ state information will give 7 longs worth of state information, which will
+ allow a degree seven polynomial. (Note: The zeroth word of state
+ information also has some other information stored in it; see setstate
+ for details). The random number generation technique is a linear feedback
+ shift register approach, employing trinomials (since there are fewer terms
+ to sum up that way). In this approach, the least significant bit of all
+ the numbers in the state table will act as a linear feedback shift register,
+ and will have period 2^deg - 1 (where deg is the degree of the polynomial
+ being used, assuming that the polynomial is irreducible and primitive).
+ The higher order bits will have longer periods, since their values are
+ also influenced by pseudo-random carries out of the lower bits. The
+ total period of the generator is approximately deg*(2**deg - 1); thus
+ doubling the amount of state information has a vast influence on the
+ period of the generator. Note: The deg*(2**deg - 1) is an approximation
+ only good for large deg, when the period of the shift register is the
+ dominant factor. With deg equal to seven, the period is actually much
+ longer than the 7*(2**7 - 1) predicted by this formula. */
+
+
+
+/* For each of the currently supported random number generators, we have a
+ break value on the amount of state information (you need at least this many
+ bytes of state info to support this random number generator), a degree for
+ the polynomial (actually a trinomial) that the R.N.G. is based on, and
+ separation between the two lower order coefficients of the trinomial. */
+
+/* Linear congruential. */
+#define TYPE_0 0
+#define BREAK_0 8
+#define DEG_0 0
+#define SEP_0 0
+
+/* x**7 + x**3 + 1. */
+#define TYPE_1 1
+#define BREAK_1 32
+#define DEG_1 7
+#define SEP_1 3
+
+/* x**15 + x + 1. */
+#define TYPE_2 2
+#define BREAK_2 64
+#define DEG_2 15
+#define SEP_2 1
+
+/* x**31 + x**3 + 1. */
+#define TYPE_3 3
+#define BREAK_3 128
+#define DEG_3 31
+#define SEP_3 3
+
+/* x**63 + x + 1. */
+#define TYPE_4 4
+#define BREAK_4 256
+#define DEG_4 63
+#define SEP_4 1
+
+
+/* Array versions of the above information to make code run faster.
+ Relies on fact that TYPE_i == i. */
+
+#define MAX_TYPES 5 /* Max number of types above. */
+
+
+/* Initially, everything is set up as if from:
+ initstate(1, randtbl, 128);
+ Note that this initialization takes advantage of the fact that srandom
+ advances the front and rear pointers 10*rand_deg times, and hence the
+ rear pointer which starts at 0 will also end up at zero; thus the zeroth
+ element of the state information, which contains info about the current
+ position of the rear pointer is just
+ (MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3. */
+
+static int32_t randtbl[DEG_3 + 1] =
+ {
+ TYPE_3,
+
+ -1726662223, 379960547, 1735697613, 1040273694, 1313901226,
+ 1627687941, -179304937, -2073333483, 1780058412, -1989503057,
+ -615974602, 344556628, 939512070, -1249116260, 1507946756,
+ -812545463, 154635395, 1388815473, -1926676823, 525320961,
+ -1009028674, 968117788, -123449607, 1284210865, 435012392,
+ -2017506339, -911064859, -370259173, 1132637927, 1398500161,
+ -205601318,
+ };
+
+
+static struct random_data unsafe_state =
+ {
+/* FPTR and RPTR are two pointers into the state info, a front and a rear
+ pointer. These two pointers are always rand_sep places aparts, as they
+ cycle through the state information. (Yes, this does mean we could get
+ away with just one pointer, but the code for random is more efficient
+ this way). The pointers are left positioned as they would be from the call:
+ initstate(1, randtbl, 128);
+ (The position of the rear pointer, rptr, is really 0 (as explained above
+ in the initialization of randtbl) because the state table pointer is set
+ to point to randtbl[1] (as explained below).) */
+
+ .fptr = &randtbl[SEP_3 + 1],
+ .rptr = &randtbl[1],
+
+/* The following things are the pointer to the state information table,
+ the type of the current generator, the degree of the current polynomial
+ being used, and the separation between the two pointers.
+ Note that for efficiency of random, we remember the first location of
+ the state information, not the zeroth. Hence it is valid to access
+ state[-1], which is used to store the type of the R.N.G.
+ Also, we remember the last location, since this is more efficient than
+ indexing every time to find the address of the last element to see if
+ the front and rear pointers have wrapped. */
+
+ .state = &randtbl[1],
+
+ .rand_type = TYPE_3,
+ .rand_deg = DEG_3,
+ .rand_sep = SEP_3,
+
+ .end_ptr = &randtbl[sizeof (randtbl) / sizeof (randtbl[0])]
+};
+
+/* POSIX.1c requires that there is mutual exclusion for the `rand' and
+ `srand' functions to prevent concurrent calls from modifying common
+ data. */
+
+/* Initialize the random number generator based on the given seed. If the
+ type is the trivial no-state-information type, just remember the seed.
+ Otherwise, initializes state[] based on the given "seed" via a linear
+ congruential generator. Then, the pointers are set to known locations
+ that are exactly rand_sep places apart. Lastly, it cycles the state
+ information a given number of times to get rid of any initial dependencies
+ introduced by the L.C.R.N.G. Note that the initialization of randtbl[]
+ for default usage relies on values produced by this routine. */
+void
+__srandom (x)
+ unsigned int x;
+{
+ (void) __srandom_r (x, &unsafe_state);
+}
+
+
+/* Initialize the state information in the given array of N bytes for
+ future random number generation. Based on the number of bytes we
+ are given, and the break values for the different R.N.G.'s, we choose
+ the best (largest) one we can and set things up for it. srandom is
+ then called to initialize the state information. Note that on return
+ from srandom, we set state[-1] to be the type multiplexed with the current
+ value of the rear pointer; this is so successive calls to initstate won't
+ lose this information and will be able to restart with setstate.
+ Note: The first thing we do is save the current state, if any, just like
+ setstate so that it doesn't matter when initstate is called.
+ Returns a pointer to the old state. */
+char *
+__initstate (seed, arg_state, n)
+ unsigned int seed;
+ char *arg_state;
+ size_t n;
+{
+ int32_t *ostate;
+
+
+ ostate = &unsafe_state.state[-1];
+
+ __initstate_r (seed, arg_state, n, &unsafe_state);
+
+
+ return (char *) ostate;
+}
+
+
+/* Restore the state from the given state array.
+ Note: It is important that we also remember the locations of the pointers
+ in the current state information, and restore the locations of the pointers
+ from the old state information. This is done by multiplexing the pointer
+ location into the zeroth word of the state information. Note that due
+ to the order in which things are done, it is OK to call setstate with the
+ same state as the current state
+ Returns a pointer to the old state information. */
+char *
+__setstate (arg_state)
+ char *arg_state;
+{
+ int32_t *ostate;
+
+
+ ostate = &unsafe_state.state[-1];
+
+ if (__setstate_r (arg_state, &unsafe_state) < 0)
+ ostate = NULL;
+
+
+ return (char *) ostate;
+}
+
+
+/* If we are using the trivial TYPE_0 R.N.G., just do the old linear
+ congruential bit. Otherwise, we do our fancy trinomial stuff, which is the
+ same in all the other cases due to all the global variables that have been
+ set up. The basic operation is to add the number at the rear pointer into
+ the one at the front pointer. Then both pointers are advanced to the next
+ location cyclically in the table. The value returned is the sum generated,
+ reduced to 31 bits by throwing away the "least random" low bit.
+ Note: The code takes advantage of the fact that both the front and
+ rear pointers can't wrap on the same call by not testing the rear
+ pointer if the front one has wrapped. Returns a 31-bit random number. */
+
+long int
+__random (void)
+{
+ int32_t retval;
+
+
+ (void) __random_r (&unsafe_state, &retval);
+
+
+ return retval;
+}
+
+long int glibc_random(void) { return __random(); }
+void glibc_srandom(unsigned int seed) { __srandom(seed); }
+char *glibc_initstate(unsigned int seed, char *state, size_t n) { return __initstate(seed,state,n); }
+char *glibc_setstate(char *state) { return __setstate(state); }
+#endif
diff --git a/common/diet/time.c b/common/diet/time.c
new file mode 100644
index 00000000..11f963c3
--- /dev/null
+++ b/common/diet/time.c
@@ -0,0 +1,20 @@
+#ifdef __dietlibc__
+#include <time.h>
+#warning "hardcoded time zone as GMT+8!"
+extern void __maplocaltime(void);
+extern time_t __tzfile_map(time_t t, int *isdst, int forward);
+extern time_t timegm(struct tm *const t);
+
+time_t mktime(register struct tm* const t) {
+ time_t x=timegm(t);
+ x-=8*3600;
+ return x;
+}
+
+struct tm* localtime_r(const time_t* t, struct tm* r) {
+ time_t tmp;
+ tmp=*t;
+ tmp+=8*3600;
+ return gmtime_r(&tmp,r);
+}
+#endif
diff --git a/common/sys/Makefile b/common/sys/Makefile
new file mode 100644
index 00000000..4c696ea8
--- /dev/null
+++ b/common/sys/Makefile
@@ -0,0 +1,24 @@
+
+SRCROOT= ../..
+.include "$(SRCROOT)/pttbbs.mk"
+
+CFLAGS+= -I$(SRCROOT)/include
+
+OBJS= file.o lock.o log.o net.o sort.o string.o time.o crypt.o osdep.o
+TARGET= libcmsys.a
+
+
+.SUFFIXES: .c .o
+.c.o:
+ $(CCACHE) $(DIETCC) $(CC) $(CFLAGS) -c $*.c
+
+all: $(TARGET)
+
+install:
+
+$(TARGET): $(OBJS)
+ $(AR) cru $@ $(OBJS)
+ ranlib $@
+
+clean:
+ rm -f $(OBJS) $(TARGET)
diff --git a/common/sys/crypt.c b/common/sys/crypt.c
new file mode 100644
index 00000000..8353132a
--- /dev/null
+++ b/common/sys/crypt.c
@@ -0,0 +1,647 @@
+/* $Id */
+/* This file is crypt.c taken from ssh 1.2.33, only modified for compile */
+/**
+ * FreeBSD 及 Linux glibc 附的 crypt() 都會用到大 table 加速多次 crypt().
+ * 但 bbs 僅上站檢查密碼時使用一次, 不值得為此花 100kb memory. (non-const memory)
+ * libdes 的 crypt() 僅需 4kb 的 constant lookup table.
+ *
+ * 不過要注意 libdes 4.01 的 license 跟 GPL 不合, 因此此處採用 ssh 1.2.33 裡頭
+ * 附的 crypt.c derived from libdes 3.06, 該版的 libdes 是 GPL 的.
+ */
+#define PROTO
+/* This file is fcrypt.c taken from SSLeay-0.4.3a. This file is only compiled
+ in on those systems that don't have crypt() in the system libraries.
+ //ylo */
+
+/* fcrypt.c */
+/* Copyright (C) 1995 Eric Young (eay@mincom.oz.au).
+ * All rights reserved.
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * See the COPYRIGHT file in the libdes distribution for more details.
+ */
+
+#include <stdio.h>
+#define _LIBC
+
+/* Eric Young.
+ * This version of crypt has been developed from my MIT compatable
+ * DES library.
+ * The library is available at pub/Crypto/DES at ftp.psy.uq.oz.au
+ * eay@mincom.oz.au or eay@psych.psy.uq.oz.au
+ */
+
+#if !defined(_LIBC) || defined(NOCONST)
+#define const
+#endif
+
+typedef unsigned char des_cblock[8];
+
+typedef struct des_ks_struct
+ {
+ union {
+ des_cblock _;
+ /* make sure things are correct size on machines with
+ * 8 byte longs */
+ unsigned long pad[2];
+ } ks;
+#define _ ks._
+ } des_key_schedule[16];
+
+#define DES_KEY_SZ (sizeof(des_cblock))
+#define DES_ENCRYPT 1
+#define DES_DECRYPT 0
+
+#define ITERATIONS 16
+#define HALF_ITERATIONS 8
+
+#define c2l(c,l) (l =((unsigned long)(*((c)++))) , \
+ l|=((unsigned long)(*((c)++)))<< 8, \
+ l|=((unsigned long)(*((c)++)))<<16, \
+ l|=((unsigned long)(*((c)++)))<<24)
+
+#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24)&0xff))
+
+static const unsigned long SPtrans[8][64]={
+/* nibble 0 */
+{
+0x00820200, 0x00020000, 0x80800000, 0x80820200,
+0x00800000, 0x80020200, 0x80020000, 0x80800000,
+0x80020200, 0x00820200, 0x00820000, 0x80000200,
+0x80800200, 0x00800000, 0x00000000, 0x80020000,
+0x00020000, 0x80000000, 0x00800200, 0x00020200,
+0x80820200, 0x00820000, 0x80000200, 0x00800200,
+0x80000000, 0x00000200, 0x00020200, 0x80820000,
+0x00000200, 0x80800200, 0x80820000, 0x00000000,
+0x00000000, 0x80820200, 0x00800200, 0x80020000,
+0x00820200, 0x00020000, 0x80000200, 0x00800200,
+0x80820000, 0x00000200, 0x00020200, 0x80800000,
+0x80020200, 0x80000000, 0x80800000, 0x00820000,
+0x80820200, 0x00020200, 0x00820000, 0x80800200,
+0x00800000, 0x80000200, 0x80020000, 0x00000000,
+0x00020000, 0x00800000, 0x80800200, 0x00820200,
+0x80000000, 0x80820000, 0x00000200, 0x80020200,
+},
+/* nibble 1 */
+{
+0x10042004, 0x00000000, 0x00042000, 0x10040000,
+0x10000004, 0x00002004, 0x10002000, 0x00042000,
+0x00002000, 0x10040004, 0x00000004, 0x10002000,
+0x00040004, 0x10042000, 0x10040000, 0x00000004,
+0x00040000, 0x10002004, 0x10040004, 0x00002000,
+0x00042004, 0x10000000, 0x00000000, 0x00040004,
+0x10002004, 0x00042004, 0x10042000, 0x10000004,
+0x10000000, 0x00040000, 0x00002004, 0x10042004,
+0x00040004, 0x10042000, 0x10002000, 0x00042004,
+0x10042004, 0x00040004, 0x10000004, 0x00000000,
+0x10000000, 0x00002004, 0x00040000, 0x10040004,
+0x00002000, 0x10000000, 0x00042004, 0x10002004,
+0x10042000, 0x00002000, 0x00000000, 0x10000004,
+0x00000004, 0x10042004, 0x00042000, 0x10040000,
+0x10040004, 0x00040000, 0x00002004, 0x10002000,
+0x10002004, 0x00000004, 0x10040000, 0x00042000,
+},
+/* nibble 2 */
+{
+0x41000000, 0x01010040, 0x00000040, 0x41000040,
+0x40010000, 0x01000000, 0x41000040, 0x00010040,
+0x01000040, 0x00010000, 0x01010000, 0x40000000,
+0x41010040, 0x40000040, 0x40000000, 0x41010000,
+0x00000000, 0x40010000, 0x01010040, 0x00000040,
+0x40000040, 0x41010040, 0x00010000, 0x41000000,
+0x41010000, 0x01000040, 0x40010040, 0x01010000,
+0x00010040, 0x00000000, 0x01000000, 0x40010040,
+0x01010040, 0x00000040, 0x40000000, 0x00010000,
+0x40000040, 0x40010000, 0x01010000, 0x41000040,
+0x00000000, 0x01010040, 0x00010040, 0x41010000,
+0x40010000, 0x01000000, 0x41010040, 0x40000000,
+0x40010040, 0x41000000, 0x01000000, 0x41010040,
+0x00010000, 0x01000040, 0x41000040, 0x00010040,
+0x01000040, 0x00000000, 0x41010000, 0x40000040,
+0x41000000, 0x40010040, 0x00000040, 0x01010000,
+},
+/* nibble 3 */
+{
+0x00100402, 0x04000400, 0x00000002, 0x04100402,
+0x00000000, 0x04100000, 0x04000402, 0x00100002,
+0x04100400, 0x04000002, 0x04000000, 0x00000402,
+0x04000002, 0x00100402, 0x00100000, 0x04000000,
+0x04100002, 0x00100400, 0x00000400, 0x00000002,
+0x00100400, 0x04000402, 0x04100000, 0x00000400,
+0x00000402, 0x00000000, 0x00100002, 0x04100400,
+0x04000400, 0x04100002, 0x04100402, 0x00100000,
+0x04100002, 0x00000402, 0x00100000, 0x04000002,
+0x00100400, 0x04000400, 0x00000002, 0x04100000,
+0x04000402, 0x00000000, 0x00000400, 0x00100002,
+0x00000000, 0x04100002, 0x04100400, 0x00000400,
+0x04000000, 0x04100402, 0x00100402, 0x00100000,
+0x04100402, 0x00000002, 0x04000400, 0x00100402,
+0x00100002, 0x00100400, 0x04100000, 0x04000402,
+0x00000402, 0x04000000, 0x04000002, 0x04100400,
+},
+/* nibble 4 */
+{
+0x02000000, 0x00004000, 0x00000100, 0x02004108,
+0x02004008, 0x02000100, 0x00004108, 0x02004000,
+0x00004000, 0x00000008, 0x02000008, 0x00004100,
+0x02000108, 0x02004008, 0x02004100, 0x00000000,
+0x00004100, 0x02000000, 0x00004008, 0x00000108,
+0x02000100, 0x00004108, 0x00000000, 0x02000008,
+0x00000008, 0x02000108, 0x02004108, 0x00004008,
+0x02004000, 0x00000100, 0x00000108, 0x02004100,
+0x02004100, 0x02000108, 0x00004008, 0x02004000,
+0x00004000, 0x00000008, 0x02000008, 0x02000100,
+0x02000000, 0x00004100, 0x02004108, 0x00000000,
+0x00004108, 0x02000000, 0x00000100, 0x00004008,
+0x02000108, 0x00000100, 0x00000000, 0x02004108,
+0x02004008, 0x02004100, 0x00000108, 0x00004000,
+0x00004100, 0x02004008, 0x02000100, 0x00000108,
+0x00000008, 0x00004108, 0x02004000, 0x02000008,
+},
+/* nibble 5 */
+{
+0x20000010, 0x00080010, 0x00000000, 0x20080800,
+0x00080010, 0x00000800, 0x20000810, 0x00080000,
+0x00000810, 0x20080810, 0x00080800, 0x20000000,
+0x20000800, 0x20000010, 0x20080000, 0x00080810,
+0x00080000, 0x20000810, 0x20080010, 0x00000000,
+0x00000800, 0x00000010, 0x20080800, 0x20080010,
+0x20080810, 0x20080000, 0x20000000, 0x00000810,
+0x00000010, 0x00080800, 0x00080810, 0x20000800,
+0x00000810, 0x20000000, 0x20000800, 0x00080810,
+0x20080800, 0x00080010, 0x00000000, 0x20000800,
+0x20000000, 0x00000800, 0x20080010, 0x00080000,
+0x00080010, 0x20080810, 0x00080800, 0x00000010,
+0x20080810, 0x00080800, 0x00080000, 0x20000810,
+0x20000010, 0x20080000, 0x00080810, 0x00000000,
+0x00000800, 0x20000010, 0x20000810, 0x20080800,
+0x20080000, 0x00000810, 0x00000010, 0x20080010,
+},
+/* nibble 6 */
+{
+0x00001000, 0x00000080, 0x00400080, 0x00400001,
+0x00401081, 0x00001001, 0x00001080, 0x00000000,
+0x00400000, 0x00400081, 0x00000081, 0x00401000,
+0x00000001, 0x00401080, 0x00401000, 0x00000081,
+0x00400081, 0x00001000, 0x00001001, 0x00401081,
+0x00000000, 0x00400080, 0x00400001, 0x00001080,
+0x00401001, 0x00001081, 0x00401080, 0x00000001,
+0x00001081, 0x00401001, 0x00000080, 0x00400000,
+0x00001081, 0x00401000, 0x00401001, 0x00000081,
+0x00001000, 0x00000080, 0x00400000, 0x00401001,
+0x00400081, 0x00001081, 0x00001080, 0x00000000,
+0x00000080, 0x00400001, 0x00000001, 0x00400080,
+0x00000000, 0x00400081, 0x00400080, 0x00001080,
+0x00000081, 0x00001000, 0x00401081, 0x00400000,
+0x00401080, 0x00000001, 0x00001001, 0x00401081,
+0x00400001, 0x00401080, 0x00401000, 0x00001001,
+},
+/* nibble 7 */
+{
+0x08200020, 0x08208000, 0x00008020, 0x00000000,
+0x08008000, 0x00200020, 0x08200000, 0x08208020,
+0x00000020, 0x08000000, 0x00208000, 0x00008020,
+0x00208020, 0x08008020, 0x08000020, 0x08200000,
+0x00008000, 0x00208020, 0x00200020, 0x08008000,
+0x08208020, 0x08000020, 0x00000000, 0x00208000,
+0x08000000, 0x00200000, 0x08008020, 0x08200020,
+0x00200000, 0x00008000, 0x08208000, 0x00000020,
+0x00200000, 0x00008000, 0x08000020, 0x08208020,
+0x00008020, 0x08000000, 0x00000000, 0x00208000,
+0x08200020, 0x08008020, 0x08008000, 0x00200020,
+0x08208000, 0x00000020, 0x00200020, 0x08008000,
+0x08208020, 0x00200000, 0x08200000, 0x08000020,
+0x00208000, 0x00008020, 0x08008020, 0x08200000,
+0x00000020, 0x08208000, 0x00208020, 0x00000000,
+0x08000000, 0x08200020, 0x00008000, 0x00208020}};
+static const unsigned long skb[8][64]={
+/* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
+{
+0x00000000,0x00000010,0x20000000,0x20000010,
+0x00010000,0x00010010,0x20010000,0x20010010,
+0x00000800,0x00000810,0x20000800,0x20000810,
+0x00010800,0x00010810,0x20010800,0x20010810,
+0x00000020,0x00000030,0x20000020,0x20000030,
+0x00010020,0x00010030,0x20010020,0x20010030,
+0x00000820,0x00000830,0x20000820,0x20000830,
+0x00010820,0x00010830,0x20010820,0x20010830,
+0x00080000,0x00080010,0x20080000,0x20080010,
+0x00090000,0x00090010,0x20090000,0x20090010,
+0x00080800,0x00080810,0x20080800,0x20080810,
+0x00090800,0x00090810,0x20090800,0x20090810,
+0x00080020,0x00080030,0x20080020,0x20080030,
+0x00090020,0x00090030,0x20090020,0x20090030,
+0x00080820,0x00080830,0x20080820,0x20080830,
+0x00090820,0x00090830,0x20090820,0x20090830,
+},
+/* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */
+{
+0x00000000,0x02000000,0x00002000,0x02002000,
+0x00200000,0x02200000,0x00202000,0x02202000,
+0x00000004,0x02000004,0x00002004,0x02002004,
+0x00200004,0x02200004,0x00202004,0x02202004,
+0x00000400,0x02000400,0x00002400,0x02002400,
+0x00200400,0x02200400,0x00202400,0x02202400,
+0x00000404,0x02000404,0x00002404,0x02002404,
+0x00200404,0x02200404,0x00202404,0x02202404,
+0x10000000,0x12000000,0x10002000,0x12002000,
+0x10200000,0x12200000,0x10202000,0x12202000,
+0x10000004,0x12000004,0x10002004,0x12002004,
+0x10200004,0x12200004,0x10202004,0x12202004,
+0x10000400,0x12000400,0x10002400,0x12002400,
+0x10200400,0x12200400,0x10202400,0x12202400,
+0x10000404,0x12000404,0x10002404,0x12002404,
+0x10200404,0x12200404,0x10202404,0x12202404,
+},
+/* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */
+{
+0x00000000,0x00000001,0x00040000,0x00040001,
+0x01000000,0x01000001,0x01040000,0x01040001,
+0x00000002,0x00000003,0x00040002,0x00040003,
+0x01000002,0x01000003,0x01040002,0x01040003,
+0x00000200,0x00000201,0x00040200,0x00040201,
+0x01000200,0x01000201,0x01040200,0x01040201,
+0x00000202,0x00000203,0x00040202,0x00040203,
+0x01000202,0x01000203,0x01040202,0x01040203,
+0x08000000,0x08000001,0x08040000,0x08040001,
+0x09000000,0x09000001,0x09040000,0x09040001,
+0x08000002,0x08000003,0x08040002,0x08040003,
+0x09000002,0x09000003,0x09040002,0x09040003,
+0x08000200,0x08000201,0x08040200,0x08040201,
+0x09000200,0x09000201,0x09040200,0x09040201,
+0x08000202,0x08000203,0x08040202,0x08040203,
+0x09000202,0x09000203,0x09040202,0x09040203,
+},
+/* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */
+{
+0x00000000,0x00100000,0x00000100,0x00100100,
+0x00000008,0x00100008,0x00000108,0x00100108,
+0x00001000,0x00101000,0x00001100,0x00101100,
+0x00001008,0x00101008,0x00001108,0x00101108,
+0x04000000,0x04100000,0x04000100,0x04100100,
+0x04000008,0x04100008,0x04000108,0x04100108,
+0x04001000,0x04101000,0x04001100,0x04101100,
+0x04001008,0x04101008,0x04001108,0x04101108,
+0x00020000,0x00120000,0x00020100,0x00120100,
+0x00020008,0x00120008,0x00020108,0x00120108,
+0x00021000,0x00121000,0x00021100,0x00121100,
+0x00021008,0x00121008,0x00021108,0x00121108,
+0x04020000,0x04120000,0x04020100,0x04120100,
+0x04020008,0x04120008,0x04020108,0x04120108,
+0x04021000,0x04121000,0x04021100,0x04121100,
+0x04021008,0x04121008,0x04021108,0x04121108,
+},
+/* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
+{
+0x00000000,0x10000000,0x00010000,0x10010000,
+0x00000004,0x10000004,0x00010004,0x10010004,
+0x20000000,0x30000000,0x20010000,0x30010000,
+0x20000004,0x30000004,0x20010004,0x30010004,
+0x00100000,0x10100000,0x00110000,0x10110000,
+0x00100004,0x10100004,0x00110004,0x10110004,
+0x20100000,0x30100000,0x20110000,0x30110000,
+0x20100004,0x30100004,0x20110004,0x30110004,
+0x00001000,0x10001000,0x00011000,0x10011000,
+0x00001004,0x10001004,0x00011004,0x10011004,
+0x20001000,0x30001000,0x20011000,0x30011000,
+0x20001004,0x30001004,0x20011004,0x30011004,
+0x00101000,0x10101000,0x00111000,0x10111000,
+0x00101004,0x10101004,0x00111004,0x10111004,
+0x20101000,0x30101000,0x20111000,0x30111000,
+0x20101004,0x30101004,0x20111004,0x30111004,
+},
+/* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */
+{
+0x00000000,0x08000000,0x00000008,0x08000008,
+0x00000400,0x08000400,0x00000408,0x08000408,
+0x00020000,0x08020000,0x00020008,0x08020008,
+0x00020400,0x08020400,0x00020408,0x08020408,
+0x00000001,0x08000001,0x00000009,0x08000009,
+0x00000401,0x08000401,0x00000409,0x08000409,
+0x00020001,0x08020001,0x00020009,0x08020009,
+0x00020401,0x08020401,0x00020409,0x08020409,
+0x02000000,0x0A000000,0x02000008,0x0A000008,
+0x02000400,0x0A000400,0x02000408,0x0A000408,
+0x02020000,0x0A020000,0x02020008,0x0A020008,
+0x02020400,0x0A020400,0x02020408,0x0A020408,
+0x02000001,0x0A000001,0x02000009,0x0A000009,
+0x02000401,0x0A000401,0x02000409,0x0A000409,
+0x02020001,0x0A020001,0x02020009,0x0A020009,
+0x02020401,0x0A020401,0x02020409,0x0A020409,
+},
+/* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */
+{
+0x00000000,0x00000100,0x00080000,0x00080100,
+0x01000000,0x01000100,0x01080000,0x01080100,
+0x00000010,0x00000110,0x00080010,0x00080110,
+0x01000010,0x01000110,0x01080010,0x01080110,
+0x00200000,0x00200100,0x00280000,0x00280100,
+0x01200000,0x01200100,0x01280000,0x01280100,
+0x00200010,0x00200110,0x00280010,0x00280110,
+0x01200010,0x01200110,0x01280010,0x01280110,
+0x00000200,0x00000300,0x00080200,0x00080300,
+0x01000200,0x01000300,0x01080200,0x01080300,
+0x00000210,0x00000310,0x00080210,0x00080310,
+0x01000210,0x01000310,0x01080210,0x01080310,
+0x00200200,0x00200300,0x00280200,0x00280300,
+0x01200200,0x01200300,0x01280200,0x01280300,
+0x00200210,0x00200310,0x00280210,0x00280310,
+0x01200210,0x01200310,0x01280210,0x01280310,
+},
+/* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */
+{
+0x00000000,0x04000000,0x00040000,0x04040000,
+0x00000002,0x04000002,0x00040002,0x04040002,
+0x00002000,0x04002000,0x00042000,0x04042000,
+0x00002002,0x04002002,0x00042002,0x04042002,
+0x00000020,0x04000020,0x00040020,0x04040020,
+0x00000022,0x04000022,0x00040022,0x04040022,
+0x00002020,0x04002020,0x00042020,0x04042020,
+0x00002022,0x04002022,0x00042022,0x04042022,
+0x00000800,0x04000800,0x00040800,0x04040800,
+0x00000802,0x04000802,0x00040802,0x04040802,
+0x00002800,0x04002800,0x00042800,0x04042800,
+0x00002802,0x04002802,0x00042802,0x04042802,
+0x00000820,0x04000820,0x00040820,0x04040820,
+0x00000822,0x04000822,0x00040822,0x04040822,
+0x00002820,0x04002820,0x00042820,0x04042820,
+0x00002822,0x04002822,0x00042822,0x04042822,
+}
+};
+
+/* See ecb_encrypt.c for a pseudo description of these macros. */
+#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
+ (b)^=(t),\
+ (a)^=((t)<<(n)))
+
+#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
+ (a)=(a)^(t)^(t>>(16-(n))))\
+
+static const char shifts2[16]={0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0};
+
+#ifdef PROTO
+static int body(unsigned long *out0, unsigned long *out1, des_key_schedule ks, unsigned long Eswap0, unsigned long Eswap1);
+static int des_set_key(des_cblock (*key), struct des_ks_struct *schedule);
+#else
+static int body();
+static int des_set_key();
+#endif
+
+static int des_set_key(key, schedule)
+des_cblock (*key);
+struct des_ks_struct *schedule;
+ {
+ register unsigned long c,d,t,s;
+ register unsigned char *in;
+ register unsigned long *k;
+ register int i;
+
+ k=(unsigned long *)schedule;
+ in=(unsigned char *)key;
+
+ c2l(in,c);
+ c2l(in,d);
+
+ /* I now do it in 47 simple operations :-)
+ * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov)
+ * for the inspiration. :-) */
+ PERM_OP (d,c,t,4,0x0f0f0f0f);
+ HPERM_OP(c,t,-2,0xcccc0000);
+ HPERM_OP(d,t,-2,0xcccc0000);
+ PERM_OP (d,c,t,1,0x55555555);
+ PERM_OP (c,d,t,8,0x00ff00ff);
+ PERM_OP (d,c,t,1,0x55555555);
+ d= (((d&0x000000ff)<<16)| (d&0x0000ff00) |
+ ((d&0x00ff0000)>>16)|((c&0xf0000000)>>4));
+ c&=0x0fffffff;
+
+ for (i=0; i<ITERATIONS; i++)
+ {
+ if (shifts2[i])
+ { c=((c>>2)|(c<<26)); d=((d>>2)|(d<<26)); }
+ else
+ { c=((c>>1)|(c<<27)); d=((d>>1)|(d<<27)); }
+ c&=0x0fffffff;
+ d&=0x0fffffff;
+ /* could be a few less shifts but I am to lazy at this
+ * point in time to investigate */
+ s= skb[0][ (c )&0x3f ]|
+ skb[1][((c>> 6)&0x03)|((c>> 7)&0x3c)]|
+ skb[2][((c>>13)&0x0f)|((c>>14)&0x30)]|
+ skb[3][((c>>20)&0x01)|((c>>21)&0x06) |
+ ((c>>22)&0x38)];
+ t= skb[4][ (d )&0x3f ]|
+ skb[5][((d>> 7)&0x03)|((d>> 8)&0x3c)]|
+ skb[6][ (d>>15)&0x3f ]|
+ skb[7][((d>>21)&0x0f)|((d>>22)&0x30)];
+
+ /* table contained 0213 4657 */
+ *(k++)=((t<<16)|(s&0x0000ffff))&0xffffffff;
+ s= ((s>>16)|(t&0xffff0000));
+
+ s=(s<<4)|(s>>28);
+ *(k++)=s&0xffffffff;
+ }
+ return(0);
+ }
+
+/******************************************************************
+ * modified stuff for crypt.
+ ******************************************************************/
+
+/* The changes to this macro may help or hinder, depending on the
+ * compiler and the achitecture. gcc2 always seems to do well :-).
+ * Inspired by Dana How <how@isl.stanford.edu>
+ * DO NOT use the alternative version on machines with 8 byte longs.
+ */
+#ifdef ALT_ECB
+#define D_ENCRYPT(L,R,S) \
+ t=(R^(R>>16)); \
+ u=(t&E0); \
+ t=(t&E1); \
+ u=((u^(u<<16))^R^s[S ])<<2; \
+ t=(t^(t<<16))^R^s[S+1]; \
+ t=(t>>2)|(t<<30); \
+ L^= \
+ *(unsigned long *)(des_SP+0x0100+((t )&0xfc))+ \
+ *(unsigned long *)(des_SP+0x0300+((t>> 8)&0xfc))+ \
+ *(unsigned long *)(des_SP+0x0500+((t>>16)&0xfc))+ \
+ *(unsigned long *)(des_SP+0x0700+((t>>24)&0xfc))+ \
+ *(unsigned long *)(des_SP+ ((u )&0xfc))+ \
+ *(unsigned long *)(des_SP+0x0200+((u>> 8)&0xfc))+ \
+ *(unsigned long *)(des_SP+0x0400+((u>>16)&0xfc))+ \
+ *(unsigned long *)(des_SP+0x0600+((u>>24)&0xfc));
+#else /* original version */
+#define D_ENCRYPT(L,R,S) \
+ t=(R^(R>>16)); \
+ u=(t&E0); \
+ t=(t&E1); \
+ u=(u^(u<<16))^R^s[S ]; \
+ t=(t^(t<<16))^R^s[S+1]; \
+ t=(t>>4)|(t<<28); \
+ L^= SPtrans[1][(t )&0x3f]| \
+ SPtrans[3][(t>> 8)&0x3f]| \
+ SPtrans[5][(t>>16)&0x3f]| \
+ SPtrans[7][(t>>24)&0x3f]| \
+ SPtrans[0][(u )&0x3f]| \
+ SPtrans[2][(u>> 8)&0x3f]| \
+ SPtrans[4][(u>>16)&0x3f]| \
+ SPtrans[6][(u>>24)&0x3f];
+#endif
+
+static unsigned const char con_salt[128]={
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
+0x0A,0x0B,0x05,0x06,0x07,0x08,0x09,0x0A,
+0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,
+0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,
+0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,
+0x23,0x24,0x25,0x20,0x21,0x22,0x23,0x24,
+0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,
+0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,
+0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,
+0x3D,0x3E,0x3F,0x00,0x00,0x00,0x00,0x00,
+};
+
+static unsigned const char cov_2char[64]={
+0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
+0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,
+0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,
+0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,
+0x55,0x56,0x57,0x58,0x59,0x5A,0x61,0x62,
+0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,
+0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,
+0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A
+};
+
+#ifdef PERL5
+char *des_crypt(buf,salt)
+#else
+char *fcrypt(buf, salt)
+char *buf;
+char *salt;
+
+
+#endif
+
+
+ {
+ unsigned int i,j,x,y;
+ unsigned long Eswap0=0,Eswap1=0;
+ unsigned long out[2],ll;
+ des_cblock key;
+ des_key_schedule ks;
+ static unsigned char buff[20];
+ unsigned char bb[9];
+ unsigned char *b=bb;
+ unsigned char c,u;
+
+ /* eay 25/08/92
+ * If you call crypt("pwd","*") as often happens when you
+ * have * as the pwd field in /etc/passwd, the function
+ * returns *\0XXXXXXXXX
+ * The \0 makes the string look like * so the pwd "*" would
+ * crypt to "*". This was found when replacing the crypt in
+ * our shared libraries. People found that the disbled
+ * accounts effectivly had no passwd :-(. */
+ x=buff[0]=((salt[0] == '\0')?'A':salt[0]);
+ Eswap0=con_salt[x];
+ x=buff[1]=((salt[1] == '\0')?'A':salt[1]);
+ Eswap1=con_salt[x]<<4;
+
+ for (i=0; i<8; i++)
+ {
+ c= *(buf++);
+ if (!c) break;
+ key[i]=(c<<1);
+ }
+ for (; i<8; i++)
+ key[i]=0;
+
+ des_set_key((des_cblock *)(key),ks);
+ body(&(out[0]),&(out[1]),ks,Eswap0,Eswap1);
+
+ ll=out[0]; l2c(ll,b);
+ ll=out[1]; l2c(ll,b);
+ y=0;
+ u=0x80;
+ bb[8]=0;
+ for (i=2; i<13; i++)
+ {
+ c=0;
+ for (j=0; j<6; j++)
+ {
+ c<<=1;
+ if (bb[y] & u) c|=1;
+ u>>=1;
+ if (!u)
+ {
+ y++;
+ u=0x80;
+ }
+ }
+ buff[i]=cov_2char[c];
+ }
+ buff[13]='\0';
+ return((char *)buff);
+ }
+
+static int body(out0, out1, ks, Eswap0, Eswap1)
+unsigned long *out0;
+unsigned long *out1;
+des_key_schedule ks;
+unsigned long Eswap0;
+unsigned long Eswap1;
+ {
+ register unsigned long l,r,t,u;
+#ifdef ALT_ECB
+ register unsigned char *des_SP=(unsigned char *)SPtrans;
+#endif
+ register unsigned long *s;
+ register int i,j;
+ register unsigned long E0,E1;
+
+ l=0;
+ r=0;
+
+ s=(unsigned long *)ks;
+ E0=Eswap0;
+ E1=Eswap1;
+
+ for (j=0; j<25; j++)
+ {
+ for (i=0; i<(ITERATIONS*2); i+=4)
+ {
+ D_ENCRYPT(l,r, i); /* 1 */
+ D_ENCRYPT(r,l, i+2); /* 2 */
+ }
+ t=l;
+ l=r;
+ r=t;
+ }
+ t=r;
+ r=(l>>1)|(l<<31);
+ l=(t>>1)|(t<<31);
+ /* clear the top bits on machines with 8byte longs */
+ l&=0xffffffff;
+ r&=0xffffffff;
+
+ PERM_OP(r,l,t, 1,0x55555555);
+ PERM_OP(l,r,t, 8,0x00ff00ff);
+ PERM_OP(r,l,t, 2,0x33333333);
+ PERM_OP(l,r,t,16,0x0000ffff);
+ PERM_OP(r,l,t, 4,0x0f0f0f0f);
+
+ *out0=l;
+ *out1=r;
+ return(0);
+ }
+
diff --git a/common/sys/file.c b/common/sys/file.c
new file mode 100644
index 00000000..48b7fceb
--- /dev/null
+++ b/common/sys/file.c
@@ -0,0 +1,489 @@
+#include <stdio.h>
+#include <stdlib.h> // random
+#include <sys/file.h> // flock
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <strings.h>
+#include <dirent.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#include "cmsys.h"
+
+
+/* ----------------------------------------------------- */
+/* 檔案檢查函數:檔案、目錄、屬於 */
+/* ----------------------------------------------------- */
+
+/**
+ * 傳回 fname 的檔案大小
+ * @param fname
+ */
+off_t
+dashs(const char *fname)
+{
+ struct stat st;
+
+ if (!stat(fname, &st))
+ return st.st_size;
+ else
+ return -1;
+}
+
+/**
+ * 傳回 fname 的 mtime
+ * @param fname
+ */
+time4_t
+dasht(const char *fname)
+{
+ struct stat st;
+
+ if (!stat(fname, &st))
+ return st.st_mtime;
+ else
+ return -1;
+}
+
+/**
+ * 傳回 fname 的 ctime
+ * @param fname
+ */
+time4_t
+dashc(const char *fname)
+{
+ struct stat st;
+
+ if (!stat(fname, &st))
+ return st.st_ctime;
+ else
+ return -1;
+}
+
+/**
+ * 傳回 fname 是否為 symbolic link
+ * @param fname
+ */
+int
+dashl(const char *fname)
+{
+ struct stat st;
+
+ return (lstat(fname, &st) == 0 && S_ISLNK(st.st_mode));
+}
+
+/**
+ * 傳回 fname 是否為一般的檔案
+ * @param fname
+ */
+int
+dashf(const char *fname)
+{
+ struct stat st;
+
+ return (stat(fname, &st) == 0 && S_ISREG(st.st_mode));
+}
+
+/**
+ * 傳回 fname 是否為目錄
+ * @param fname
+ */
+int
+dashd(const char *fname)
+{
+ struct stat st;
+
+ return (stat(fname, &st) == 0 && S_ISDIR(st.st_mode));
+}
+
+/* ----------------------------------------------------- */
+/* 檔案操作函數:複製、搬移、附加 */
+/* ----------------------------------------------------- */
+
+#define BUFFER_SIZE 8192
+int copy_file_to_file(const char *src, const char *dst)
+{
+ char buf[BUFFER_SIZE];
+ int fdr, fdw, len;
+
+ if ((fdr = open(src, O_RDONLY)) < 0)
+ return -1;
+
+ if ((fdw = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
+ close(fdr);
+ return -1;
+ }
+
+ while (1) {
+ len = read(fdr, buf, sizeof(buf));
+ if (len <= 0)
+ break;
+ write(fdw, buf, len);
+ if (len < BUFFER_SIZE)
+ break;
+ }
+
+ close(fdr);
+ close(fdw);
+ return 0;
+}
+#undef BUFFER_SIZE
+
+int copy_file_to_dir(const char *src, const char *dst)
+{
+ char buf[PATH_MAX];
+ char *slash;
+ if ((slash = rindex(src, '/')) == NULL)
+ snprintf(buf, sizeof(buf), "%s/%s", dst, src);
+ else
+ snprintf(buf, sizeof(buf), "%s/%s", dst, slash);
+ return copy_file_to_file(src, buf);
+}
+
+int copy_dir_to_dir(const char *src, const char *dst)
+{
+ DIR *dir;
+ struct dirent *entry;
+ struct stat st;
+ char buf[PATH_MAX], buf2[PATH_MAX];
+
+ if (stat(dst, &st) < 0)
+ if (mkdir(dst, 0700) < 0)
+ return -1;
+
+ if ((dir = opendir(src)) == NULL)
+ return -1;
+
+ while ((entry = readdir(dir)) != NULL) {
+ if (strcmp(entry->d_name, ".") == 0 ||
+ strcmp(entry->d_name, "..") == 0)
+ continue;
+ snprintf(buf, sizeof(buf), "%s/%s", src, entry->d_name);
+ snprintf(buf2, sizeof(buf2), "%s/%s", dst, entry->d_name);
+ if (stat(buf, &st) < 0)
+ continue;
+ if (S_ISDIR(st.st_mode))
+ mkdir(buf2, 0700);
+ copy_file(buf, buf2);
+ }
+
+ closedir(dir);
+ return 0;
+}
+
+/**
+ * copy src to dst (recursively)
+ * @param src and dst are file or dir
+ * @return -1 if failed
+ */
+int copy_file(const char *src, const char *dst)
+{
+ struct stat st;
+
+ if (stat(dst, &st) == 0 && S_ISDIR(st.st_mode)) {
+ if (stat(src, &st) < 0)
+ return -1;
+
+ if (S_ISDIR(st.st_mode))
+ return copy_dir_to_dir(src, dst);
+ else if (S_ISREG(st.st_mode))
+ return copy_file_to_dir(src, dst);
+ return -1;
+ }
+ else if (stat(src, &st) == 0 && S_ISDIR(st.st_mode))
+ return copy_dir_to_dir(src, dst);
+ return copy_file_to_file(src, dst);
+}
+
+int
+Rename(const char *src, const char *dst)
+{
+ if (rename(src, dst) == 0)
+ return 0;
+ if (!strchr(src, ';') && !strchr(dst, ';'))
+ {
+ pid_t pid = fork();
+ if (pid == 0)
+ execl("/bin/mv", "mv", "-f", src, dst, (char *)NULL);
+ else if (pid > 0)
+ {
+ int status = -1;
+ waitpid(pid, &status, 0);
+ return WEXITSTATUS(status) == 0 ? 0 : -1;
+ }
+ else
+ return -1;
+ }
+ return -1;
+}
+
+int
+Copy(const char *src, const char *dst)
+{
+ int fi, fo, bytes;
+ char buf[8192];
+ fi=open(src, O_RDONLY);
+ if(fi<0) return -1;
+ fo=open(dst, O_WRONLY | O_TRUNC | O_CREAT, 0600);
+ if(fo<0) {close(fi); return -1;}
+ while((bytes=read(fi, buf, sizeof(buf)))>0)
+ write(fo, buf, bytes);
+ close(fo);
+ close(fi);
+ return 0;
+}
+
+int
+CopyN(const char *src, const char *dst, int n)
+{
+ int fi, fo, bytes;
+ char buf[8192];
+
+ fi=open(src, O_RDONLY);
+ if(fi<0) return -1;
+
+ fo=open(dst, O_WRONLY | O_TRUNC | O_CREAT, 0600);
+ if(fo<0) {close(fi); return -1;}
+
+ while(n > 0 && (bytes=read(fi, buf, sizeof(buf)))>0)
+ {
+ n -= bytes;
+ if (n < 0)
+ bytes += n;
+ write(fo, buf, bytes);
+ }
+ close(fo);
+ close(fi);
+ return 0;
+}
+
+/* append data from tail of src (starting point=off) to dst */
+int
+AppendTail(const char *src, const char *dst, int off)
+{
+ int fi, fo, bytes;
+ char buf[8192];
+
+ fi=open(src, O_RDONLY);
+ if(fi<0) return -1;
+
+ fo=open(dst, O_WRONLY | O_APPEND | O_CREAT, 0600);
+ if(fo<0) {close(fi); return -1;}
+ // flock(dst, LOCK_SH);
+
+ if(off > 0)
+ lseek(fi, (off_t)off, SEEK_SET);
+
+ while((bytes=read(fi, buf, sizeof(buf)))>0)
+ {
+ write(fo, buf, bytes);
+ }
+ // flock(dst, LOCK_UN);
+ close(fo);
+ close(fi);
+ return 0;
+}
+
+/**
+ * @param src file
+ * @param dst file
+ * @return 0 if success
+ */
+int
+Link(const char *src, const char *dst)
+{
+ if (symlink(src, dst) == 0)
+ return 0;
+
+ return Copy(src, dst);
+}
+
+/* ----------------------------------------------------- */
+/* 檔案內容處理函數:以「行」為單位 */
+/* ----------------------------------------------------- */
+
+#define LINEBUFSZ (PATH_MAX)
+#define STR_SPACE " \t\n\r"
+
+
+/**
+ * 傳回 file 檔的行數
+ * @param file
+ */
+int file_count_line(const char *file)
+{
+ FILE *fp;
+ int count = 0;
+ char buf[LINEBUFSZ];
+
+ if ((fp = fopen(file, "r"))) {
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (strchr(buf, '\n') == NULL)
+ continue;
+ count++;
+ }
+ fclose(fp);
+ }
+ return count;
+}
+
+/**
+ * 將 string append 到檔案 file 後端 (不加換行)
+ * @param file 要被 append 的檔
+ * @param string
+ * @return 成功傳回 0,失敗傳回 -1。
+ */
+int file_append_line(const char *file, const char *string)
+{
+ FILE *fp;
+ if ((fp = fopen(file, "a")) == NULL)
+ return -1;
+ flock(fileno(fp), LOCK_EX);
+ fputs(string, fp);
+ flock(fileno(fp), LOCK_UN);
+ fclose(fp);
+ return 0;
+}
+
+/**
+ * 將 "$key\n" append 到檔案 file 後端
+ * @param file 要被 append 的檔
+ * @param key 沒有換行的字串
+ * @return 成功傳回 0,失敗傳回 -1。
+ */
+int file_append_record(const char *file, const char *key)
+{
+ FILE *fp;
+ if (!key || !*key) return -1;
+ if ((fp = fopen(file, "a")) == NULL)
+ return -1;
+ flock(fileno(fp), LOCK_EX);
+ fputs(key, fp);
+ fputs("\n", fp);
+ flock(fileno(fp), LOCK_UN);
+ fclose(fp);
+ return 0;
+}
+
+/**
+ * 傳回檔案 file 中 key 所在行數
+ */
+int file_find_record(const char *file, const char *key)
+{
+ FILE *fp;
+ char buf[LINEBUFSZ], *ptr;
+ int i = 0;
+
+ if ((fp = fopen(file, "r")) == NULL)
+ return 0;
+
+ while (fgets(buf, LINEBUFSZ, fp)) {
+ char *strtok_pos;
+ i++;
+ if ((ptr = strtok_r(buf, STR_SPACE, &strtok_pos)) && !strcasecmp(ptr, key)) {
+ fclose(fp);
+ return i;
+ }
+ }
+ fclose(fp);
+ return 0;
+}
+
+/**
+ * 傳回檔案 file 中是否有 key
+ */
+int file_exist_record(const char *file, const char *key)
+{
+ return file_find_record(file, key) > 0 ? 1 : 0;
+}
+
+/**
+ * 刪除檔案 file 中以 string 開頭的行
+ * @param file 要處理的檔案
+ * @param string 尋找的 key name
+ * @param case_sensitive 是否要處理大小寫
+ * @return 成功傳回 0,失敗傳回 -1。
+ */
+int
+file_delete_record(const char *file, const char *string, int case_sensitive)
+{
+ // TODO nfp 用 tmpfile() 比較好? 不過 Rename 會變慢...
+ FILE *fp = NULL, *nfp = NULL;
+ char fnew[PATH_MAX];
+ char buf[LINEBUFSZ + 1];
+ int ret = -1, i = 0;
+ const size_t toklen = strlen(string);
+
+ if (!toklen)
+ return 0;
+
+ do {
+ snprintf(fnew, sizeof(fnew), "%s.%3.3X", file, (unsigned int)(random() & 0xFFF));
+ if (access(fnew, 0) != 0)
+ break;
+ } while (i++ < 10); // max tries = 10
+
+ if (access(fnew, 0) == 0) return -1; // cannot create temp file.
+
+ i = 0;
+ if ((fp = fopen(file, "r")) && (nfp = fopen(fnew, "w"))) {
+ while (fgets(buf, sizeof(buf), fp))
+ {
+ size_t klen = strcspn(buf, STR_SPACE);
+ if (toklen == klen)
+ {
+ if (((case_sensitive && strncmp(buf, string, toklen) == 0) ||
+ (!case_sensitive && strncasecmp(buf, string, toklen) == 0)))
+ {
+ // found line. skip it.
+ i++;
+ continue;
+ }
+ }
+ // other wise, keep the line.
+ fputs(buf, nfp);
+ }
+ fclose(nfp); nfp = NULL;
+ if (i > 0)
+ {
+ if(Rename(fnew, file) < 0)
+ ret = -1;
+ else
+ ret = 0;
+ } else {
+ unlink(fnew);
+ ret = 0;
+ }
+ }
+ if(fp)
+ fclose(fp);
+ if(nfp)
+ fclose(nfp);
+ return ret;
+}
+
+/**
+ * 對每一筆 record 做 func 這件事。
+ * @param file
+ * @param func 處理每筆 record 的 handler,為一 function pointer。
+ * 第一個參數是檔案中的一行,第二個參數為 info。
+ * @param info 一個額外的參數。
+ */
+int file_foreach_entry(const char *file, int (*func)(char *, int), int info)
+{
+ char line[80];
+ FILE *fp;
+
+ if ((fp = fopen(file, "r")) == NULL)
+ return -1;
+
+ while (fgets(line, sizeof(line), fp)) {
+ (*func)(line, info);
+ }
+
+ fclose(fp);
+ return 0;
+}
diff --git a/common/sys/lock.c b/common/sys/lock.c
new file mode 100644
index 00000000..4b28bab1
--- /dev/null
+++ b/common/sys/lock.c
@@ -0,0 +1,23 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+/**
+ * lock fd
+ * @param mode F_WRLCK, F_UNLCK
+ */
+void
+PttLock(int fd, int start, int size, int mode)
+{
+ static struct flock lock_it;
+ int ret;
+
+ lock_it.l_whence = SEEK_CUR;/* from current point */
+ lock_it.l_start = start; /* -"- */
+ lock_it.l_len = size; /* length of data */
+ lock_it.l_type = mode; /* set exclusive/write lock */
+ lock_it.l_pid = 0; /* pid not actually interesting */
+ while ((ret = fcntl(fd, F_SETLKW, &lock_it)) < 0 && errno == EINTR)
+ sleep(1);
+}
+
diff --git a/common/sys/log.c b/common/sys/log.c
new file mode 100644
index 00000000..7923caca
--- /dev/null
+++ b/common/sys/log.c
@@ -0,0 +1,43 @@
+#include <stdarg.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "cmsys.h"
+
+int
+log_filef(const char *fn, int log_flag, const char *fmt,...)
+{
+ char msg[256];
+
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+
+ return log_file(fn, log_flag, msg);
+}
+
+int
+log_file(const char *fn, int log_flag, const char *msg)
+{
+ int fd;
+ int flag = O_APPEND | O_WRONLY;
+ int mode = 0664;
+
+ if (log_flag & LOG_CREAT)
+ flag |= O_CREAT;
+
+ fd = open(fn, flag, mode);
+ if( fd < 0 )
+ return -1;
+
+ if( write(fd, msg, strlen(msg)) < 0 ){
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ return 0;
+}
+
diff --git a/common/sys/net.c b/common/sys/net.c
new file mode 100644
index 00000000..26f3cc50
--- /dev/null
+++ b/common/sys/net.c
@@ -0,0 +1,114 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include "cmsys.h"
+
+unsigned int
+ipstr2int(const char *ip)
+{
+ unsigned int i, val = 0;
+ char buf[32];
+ char *nil, *p;
+
+ strlcpy(buf, ip, sizeof(buf));
+ p = buf;
+ for (i = 0; i < 4; i++) {
+ nil = strchr(p, '.');
+ if (nil != NULL)
+ *nil = 0;
+ val *= 256;
+ val += atoi(p);
+ if (nil != NULL)
+ p = nil + 1;
+ }
+ return val;
+}
+
+int tobind(const char * host, int port)
+{
+ int sockfd, val = 1;
+ struct sockaddr_in servaddr;
+
+ if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
+ perror("socket()");
+ exit(1);
+ }
+ setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&val, sizeof(val));
+ bzero(&servaddr, sizeof(servaddr));
+ servaddr.sin_family = AF_INET;
+ if (host == NULL || host[0] == 0)
+ servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ else if (inet_aton(host, &servaddr.sin_addr) == 0) {
+ perror("inet_aton()");
+ exit(1);
+ }
+ servaddr.sin_port = htons(port);
+ if( bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0 ) {
+ perror("bind()");
+ exit(1);
+ }
+ if( listen(sockfd, 5) < 0 ) {
+ perror("listen()");
+ exit(1);
+ }
+
+ return sockfd;
+}
+
+int toconnect(const char *host, int port)
+{
+ int sock;
+ struct sockaddr_in serv_name;
+ if( (sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ){
+ perror("socket");
+ return -1;
+ }
+
+ serv_name.sin_family = AF_INET;
+ serv_name.sin_addr.s_addr = inet_addr(host);
+ serv_name.sin_port = htons(port);
+ if( connect(sock, (struct sockaddr*)&serv_name, sizeof(serv_name)) < 0 ){
+ close(sock);
+ return -1;
+ }
+ return sock;
+}
+
+/**
+ * same as read(2), but read until exactly size len
+ */
+int toread(int fd, void *buf, int len)
+{
+ int l;
+ for( l = 0 ; len > 0 ; )
+ if( (l = read(fd, buf, len)) <= 0 )
+ return -1;
+ else{
+ buf += l;
+ len -= l;
+ }
+ return l;
+}
+
+/**
+ * same as write(2), but write until exactly size len
+ */
+int towrite(int fd, const void *buf, int len)
+{
+ int l;
+ for( l = 0 ; len > 0 ; )
+ if( (l = write(fd, buf, len)) <= 0 )
+ return -1;
+ else{
+ buf += l;
+ len -= l;
+ }
+ return l;
+}
diff --git a/common/sys/osdep.c b/common/sys/osdep.c
new file mode 100644
index 00000000..cd2e1d3e
--- /dev/null
+++ b/common/sys/osdep.c
@@ -0,0 +1,376 @@
+/* $Id$ */
+#include "osdep.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#ifdef NEED_STRLCAT
+
+#include <sys/types.h>
+#include <string.h>
+
+/* size_t
+ * strlcat(char *dst, const char *src, size_t size);
+ */
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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 of the author 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 ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR 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.
+ */
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+strlcat(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
+
+#endif
+
+#ifdef NEED_TIMEGM
+
+#include <time.h>
+#include <stdlib.h>
+
+time_t timegm (struct tm *tm)
+{
+ time_t ret;
+ char *tz;
+
+ tz = getenv("TZ");
+ putenv("TZ=");
+ tzset();
+ ret = mktime(tm);
+
+ if (tz){
+ char *buff = malloc( strlen(tz) + 10);
+ sprintf( buff, "TZ=%s", tz);
+ putenv(buff);
+ free(buff);
+ }
+ else
+ unsetenv("TZ");
+ tzset();
+
+ return ret;
+}
+
+#endif
+
+#ifdef NEED_STRLCPY
+
+/* ------------------------------------------------------------------------ */
+
+/* size_t
+ * strlcpy(char *dst, const char *src, size_t size);
+ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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 of the author 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 ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR 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.
+ */
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t strlcpy(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
+
+#endif
+
+#ifdef NEED_BSD_SIGNAL
+
+void (*bsd_signal(int sig, void (*func)(int)))(int)
+{
+ struct sigaction act, oact;
+
+ act.sa_handler = func;
+ act.sa_flags = SA_RESTART;
+ sigemptyset(&act.sa_mask);
+ sigaddset(&act.sa_mask, sig);
+ if (sigaction(sig, &act, &oact) == -1)
+ return(SIG_ERR);
+ return(oact.sa_handler);
+}
+
+
+#endif
+
+#ifdef HAVE_SETPROCTITLE
+
+void
+initsetproctitle(int argc, char **argv, char **envp)
+{
+}
+
+#else
+
+
+static char **Argv = NULL; /* pointer to argument vector */
+static int argv_size; /* end of argv */
+
+extern char **environ;
+
+void
+initsetproctitle(int argc, char **argv, char **envp)
+{
+ register int i;
+ int len=0,nenv=0;
+
+
+ /*
+ * Move the environment so setproctitle can use the space at the top of
+ * memory.
+ */
+ for (i = 0; envp[i]; i++)
+ len+=strlen(envp[i])+1;
+ nenv=i+1;
+ len+=sizeof(char*)*nenv;
+ environ = malloc(len);
+ len=0;
+ for (i = 0; envp[i]; i++) {
+ environ[i] = (char*)environ+nenv*sizeof(char*)+len;
+ strcpy(environ[i], envp[i]);
+ len+=strlen(envp[i])+1;
+ }
+ environ[i] = NULL;
+
+ /* Save start and extent of argv for setproctitle. */
+ Argv = argv;
+ if (i > 0)
+ argv_size = envp[i - 1] + strlen(envp[i - 1]) - Argv[0];
+ else
+ argv_size = argv[argc - 1] + strlen(argv[argc - 1]) - Argv[0];
+}
+
+static void
+do_setproctitle(const char *cmdline)
+{
+ int len;
+
+ len = strlen(cmdline) + 1; // +1 for '\0'
+ if(len > argv_size - 2) // 2 ??
+ len = argv_size - 2;
+ memset(Argv[0], 0, argv_size);
+ strlcpy(Argv[0], cmdline, len);
+ Argv[1] = NULL;
+}
+
+void
+setproctitle(const char *format,...)
+{
+ char buf[256];
+ va_list args;
+ va_start(args, format);
+ vsnprintf(buf, sizeof(buf), format, args);
+ do_setproctitle(buf);
+ va_end(args);
+}
+
+#endif
+
+#if __FreeBSD__
+
+int
+cpuload(char *str)
+{
+ double l[3] = {-1, -1, -1};
+ if (getloadavg(l, 3) != 3)
+ l[0] = -1;
+
+ if (str) {
+ if (l[0] != -1)
+ sprintf(str, " %.2f %.2f %.2f", l[0], l[1], l[2]);
+ else
+ strcpy(str, " (unknown) ");
+ }
+ return (int)l[0];
+}
+#endif
+
+
+#ifdef Solaris
+
+#include <kstat.h>
+#include <sys/param.h>
+
+#define loaddouble(la) ((double)(la) / FSCALE)
+
+int
+cpuload(char *str)
+{
+ kstat_ctl_t *kc;
+ kstat_t *ks;
+ kstat_named_t *kn;
+ double l[3] = {-1, -1, -1};
+
+ kc = kstat_open();
+
+ if( !kc ){
+ strcpy(str, "(unknown) ");
+ return -1;
+ }
+
+ ks = kstat_lookup( kc, "unix", 0, "system_misc");
+
+ if( kstat_read( kc, ks, 0) == -1){
+ strcpy( str, "( unknown ");
+ return -1;
+ }
+
+ kn = kstat_data_lookup( ks, "avenrun_1min" );
+
+ if( kn ) {
+ l[0] = loaddouble(kn->value.ui32);
+ }
+
+ kn = kstat_data_lookup( ks, "avenrun_5min" );
+
+ if( kn ) {
+ l[1] = loaddouble(kn->value.ui32);
+ }
+
+ kn = kstat_data_lookup( ks, "avenrun_15min" );
+
+ if( kn ) {
+ l[2] = loaddouble(kn->value.ui32);
+ }
+
+ if (str) {
+
+ if (l[0] != -1)
+ sprintf(str, " %.2f %.2f %.2f", l[0], l[1], l[2]);
+ else
+ strcpy(str, " (unknown) ");
+ }
+
+ kstat_close(kc);
+ return (int)l[0];
+}
+
+#endif
+
+#ifdef __linux__
+int
+cpuload(char *str)
+{
+ double l[3] = {-1, -1, -1};
+ FILE *fp;
+
+ if ((fp = fopen("/proc/loadavg", "r"))) {
+ if (fscanf(fp, "%lf %lf %lf", &l[0], &l[1], &l[2]) != 3)
+ l[0] = -1;
+ fclose(fp);
+ }
+ if (str) {
+ if (l[0] != -1)
+ sprintf(str, " %.2f %.2f %.2f", l[0], l[1], l[2]);
+ else
+ strcpy(str, " (unknown) ");
+ }
+ return (int)l[0];
+}
+
+#endif
diff --git a/common/sys/sort.c b/common/sys/sort.c
new file mode 100644
index 00000000..edecc0a8
--- /dev/null
+++ b/common/sys/sort.c
@@ -0,0 +1,10 @@
+
+int cmp_int(const void *a, const void *b)
+{
+ return *(int*)a - *(int*)b;
+}
+
+int cmp_int_desc(const void * a, const void * b)
+{
+ return cmp_int(b, a);
+}
diff --git a/common/sys/string.c b/common/sys/string.c
new file mode 100644
index 00000000..b152ac63
--- /dev/null
+++ b/common/sys/string.c
@@ -0,0 +1,345 @@
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include "fnv_hash.h"
+
+#include "ansi.h"
+#include "cmsys.h"
+
+#define CHAR_LOWER(c) ((c >= 'A' && c <= 'Z') ? c|32 : c)
+/* ----------------------------------------------------- */
+/* 字串轉換檢查函數 */
+/* ----------------------------------------------------- */
+/**
+ * 將字串 s 轉為小寫存回 t
+ * @param t allocated char array
+ * @param s
+ */
+void
+str_lower(char *t, const char *s)
+{
+ register unsigned char ch;
+
+ do {
+ ch = *s++;
+ *t++ = CHAR_LOWER(ch);
+ } while (ch);
+}
+
+/**
+ * 移除字串 buf 後端多餘的空白。
+ * @param buf
+ */
+void
+trim(char *buf)
+{ /* remove trailing space */
+ char *p = buf;
+
+ while (*p)
+ p++;
+ while (--p >= buf) {
+ if (*p == ' ')
+ *p = '\0';
+ else
+ break;
+ }
+}
+
+/**
+ * 移除 src 的 '\n' 並改成 '\0'
+ * @param src
+ */
+void chomp(char *src)
+{
+ while(*src){
+ if (*src == '\n')
+ *src = 0;
+ else
+ src++;
+ }
+}
+
+int
+strip_blank(char *cbuf, char *buf)
+{
+ for (; *buf; buf++)
+ if (*buf != ' ')
+ *cbuf++ = *buf;
+ *cbuf = 0;
+ return 0;
+}
+
+static const char EscapeFlag[] = {
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0,
+ /* 20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, /* 0~9 ;= */
+ /* 40 */ 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, /* ABCDHIJK */
+ /* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 60 */ 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 2, 0, 0, /* fhlm */
+ /* 70 */ 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* su */
+ /* 80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* A0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* B0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* C0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* D0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* E0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* F0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+/**
+ * 根據 mode 來 strip 字串 src,並把結果存到 dst
+ * @param dst
+ * @param src (if NULL then only return length)
+ * @param mode enum {STRIP_ALL = 0, ONLY_COLOR, NO_RELOAD};
+ * STRIP_ALL: 全部吃掉
+ * ONLY_COLOR: 只留跟顏色有關的 (ESC[*m)
+ * NO_RELOAD: 只留上面認識的(移位+色彩)
+ * @return strip 後的長度
+ */
+int
+strip_ansi(char *dst, const char *src, enum STRIP_FLAG mode)
+{
+ register int count = 0;
+#define isEscapeParam(X) (EscapeFlag[(int)(X)] & 1)
+#define isEscapeCommand(X) (EscapeFlag[(int)(X)] & 2)
+
+ for(; *src; ++src)
+ if( *src != ESC_CHR ){
+ if( dst )
+ *dst++ = *src;
+ ++count;
+ }else{
+ const char* p = src + 1;
+ if( *p != '[' ){
+ ++src;
+ if(*src=='\0') break;
+ continue;
+ }
+ while(isEscapeParam(*++p));
+ if( (mode == NO_RELOAD && isEscapeCommand(*p)) ||
+ (mode == ONLY_COLOR && *p == 'm' )){
+ register int len = p - src + 1;
+ if( dst ){
+ memmove(dst, src, len);
+ dst += len;
+ }
+ count += len;
+ }
+ src = p;
+ if(*src=='\0') break;
+ }
+ if( dst )
+ *dst = 0;
+ return count;
+}
+
+int
+strlen_noansi(const char *s)
+{
+ // XXX this is almost identical to
+ // strip_ansi(NULL, s, STRIP_ALL)
+ register int count = 0, mode = 0;
+
+ if (!s || !*s)
+ return 0;
+
+ for (; *s; ++s)
+ {
+ // 0 - no ansi, 1 - [, 2 - param+cmd
+ switch (mode)
+ {
+ case 0:
+ if (*s == ESC_CHR)
+ mode = 1;
+ else
+ count ++;
+ break;
+
+ case 1:
+ if (*s == '[')
+ mode = 2;
+ else
+ mode = 0; // unknown command
+ break;
+
+ case 2:
+ if (isEscapeParam(*s))
+ continue;
+ else if (isEscapeCommand(*s))
+ mode = 0;
+ else
+ mode = 0;
+ break;
+ }
+ }
+ return count;
+}
+
+void
+strip_nonebig5(unsigned char *str, int maxlen)
+{
+ int i;
+ int len=0;
+ for(i=0;i<maxlen && str[i];i++) {
+ if(32<=str[i] && str[i]<128)
+ str[len++]=str[i];
+ else if(str[i]==255) {
+ if(i+1<maxlen)
+ if(251<=str[i+1] && str[i+1]<=254) {
+ i++;
+ if(i+1<maxlen && str[i+1])
+ i++;
+ }
+ continue;
+ } else if(str[i]&0x80) {
+ if(i+1<maxlen)
+ if((0x40<=str[i+1] && str[i+1]<=0x7e) ||
+ (0xa1<=str[i+1] && str[i+1]<=0xfe)) {
+ str[len++]=str[i];
+ str[len++]=str[i+1];
+ i++;
+ }
+ }
+ }
+ if(len<maxlen)
+ str[len]='\0';
+}
+
+int DBCS_RemoveIntrEscape(unsigned char *buf, int *len)
+{
+ register int isInAnsi = 0, isInDBCS = 0;
+ int l = 0, i = 0, oldl, iansi = 0;
+
+ if (len) l = *len; else l = strlen((const char*)buf);
+ oldl = l;
+
+ for (i = 0; i < l; i++)
+ {
+ if (buf[i] == ESC_CHR && !isInAnsi)
+ {
+ // new escape
+ isInAnsi = 1;
+ iansi = i;
+ continue;
+ }
+
+ // character
+ if (isInAnsi)
+ {
+ // closing ANSI section?
+ switch (isInAnsi)
+ {
+ case 1: // normal ANSI
+ if (buf[i] == '[')
+ isInAnsi = 2;
+ else
+ isInAnsi = 0; // unknown command
+ break;
+
+ case 2:
+ if (isEscapeParam(buf[i]))
+ break;
+ else
+ isInAnsi = 0;
+ break;
+ }
+ if (isInAnsi == 0 && isInDBCS && i+1 < l)
+ {
+ // interupting ANSI closed, let's modify the string
+ int sz = i + 1 - iansi; // size to move
+ memmove(buf+iansi, buf+i+1, l-i-1);
+ l -= sz;
+ i = iansi-1; // for the ++ in loop
+ }
+ } else if (isInDBCS) {
+ // not ANSI but in DBCS. finished one char.
+ isInDBCS = 0;
+ } else if (buf[i] >= 0x80) {
+ // DBCS lead.
+ isInDBCS = 1;
+ } else {
+ // normal character.
+ }
+ }
+
+ if(len) *len = l;
+ return (oldl != l) ? 1 : 0;
+}
+
+/* ----------------------------------------------------- */
+/* 字串檢查函數:英文、數字、檔名、E-mail address */
+/* ----------------------------------------------------- */
+
+int
+invalid_pname(const char *str)
+{
+ const char *p1, *p2, *p3;
+
+ p1 = str;
+ while (*p1) {
+ if (!(p2 = strchr(p1, '/')))
+ p2 = str + strlen(str);
+ if (p1 + 1 > p2 || p1 + strspn(p1, ".") == p2) /* 不允許用 / 開頭, 或是 // 之間只有 . */
+ return 1;
+ for (p3 = p1; p3 < p2; p3++)
+ if (!isalnum(*p3) && !strchr("@[]-._", *p3)) /* 只允許 alnum 或這些符號 */
+ return 1;
+ p1 = p2 + (*p2 ? 1 : 0);
+ }
+ return 0;
+}
+
+/*
+ * return 1 if /^[0-9]+$/
+ * 0 else, 含空字串
+ */
+int is_number(const char *p)
+{
+ if (*p == '\0')
+ return 0;
+
+ for(; *p; p++) {
+ if (*p < '0' || '9' < *p)
+ return 0;
+ }
+ return 1;
+}
+
+unsigned
+StringHash(const char *s)
+{
+ return fnv1a_32_strcase(s, FNV1_32_INIT);
+}
+
+/* qp_encode() modified from mutt-1.5.7/rfc2047.c q_encoder() */
+const char MimeSpecials[] = "@.,;:<>[]\\\"()?/= \t";
+char * qp_encode (char *s, size_t slen, const char *d, const char *tocode)
+{
+ char hex[] = "0123456789ABCDEF";
+ char *s0 = s;
+
+ memcpy (s, "=?", 2), s += 2;
+ memcpy (s, tocode, strlen (tocode)), s += strlen (tocode);
+ memcpy (s, "?Q?", 3), s += 3;
+ assert(s-s0+3<slen);
+
+ while (*d != '\0' && s-s0+6<slen)
+ {
+ unsigned char c = *d++;
+ if (c == ' ')
+ *s++ = '_';
+ else if (c >= 0x7f || c < 0x20 || c == '_' || strchr (MimeSpecials, c))
+ {
+ *s++ = '=';
+ *s++ = hex[(c & 0xf0) >> 4];
+ *s++ = hex[c & 0x0f];
+ }
+ else
+ *s++ = c;
+ }
+ memcpy (s, "?=", 2), s += 2;
+ *s='\0';
+ return s0;
+}
+
diff --git a/common/sys/time.c b/common/sys/time.c
new file mode 100644
index 00000000..8564b514
--- /dev/null
+++ b/common/sys/time.c
@@ -0,0 +1,116 @@
+#include <time.h>
+#include <stdio.h>
+#include "cmsys.h"
+
+static char cdate_buffer[32];
+
+/**
+ * 閏年
+ */
+int is_leap_year(int year)
+{
+ return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
+}
+
+/**
+ * 給日期求星座
+ *
+ * @return 1..12
+ */
+int getHoroscope(int m, int d)
+{
+ if (m > 12 || m < 1)
+ return 1;
+
+ // 摩羯 水瓶 雙魚 牡羊 金牛 雙子 巨蟹 獅子 處女 天秤 天蠍 射手
+ const int firstday[12] = {
+ /* Jan. */ 20, 19, 21, 20, 21, 21, 23, 23, 23, 23, 22, 22
+ };
+ if (d >= firstday[m - 1]) {
+ if (m == 12)
+ return 1;
+ else
+ return m + 1;
+ }
+ else
+ return m;
+}
+
+/**
+ * 23+1 bytes, "12/31/2007 00:00:00 Mon\0"
+ */
+char *
+Cdate(const time4_t *clock)
+{
+ time_t temp = (time_t)*clock;
+ struct tm *mytm = localtime(&temp);
+
+ strftime(cdate_buffer, sizeof(cdate_buffer), "%m/%d/%Y %T %a", mytm);
+ return cdate_buffer;
+}
+
+/**
+ * 19+1 bytes, "12/31/2007 00:00:00\0"
+ */
+char *
+Cdatelite(const time4_t *clock)
+{
+ time_t temp = (time_t)*clock;
+ struct tm *mytm = localtime(&temp);
+
+ strftime(cdate_buffer, sizeof(cdate_buffer), "%m/%d/%Y %T", mytm);
+ return cdate_buffer;
+}
+
+/**
+ * 10+1 bytes, "12/31/2007\0"
+ */
+char *
+Cdatedate(const time4_t * clock)
+{
+ time_t temp = (time_t)*clock;
+ struct tm *mytm = localtime(&temp);
+
+ strftime(cdate_buffer, sizeof(cdate_buffer), "%m/%d/%Y", mytm);
+ return cdate_buffer;
+}
+
+#ifdef TIMET64
+char *
+ctime4(const time4_t *clock)
+{
+ time_t temp = (time_t)*clock;
+
+ return ctime(&temp);
+}
+
+struct tm *localtime4(const time4_t *t)
+{
+ if( t == NULL )
+ return localtime(NULL);
+ else {
+ time_t temp = (time_t)*t;
+ return localtime(&temp);
+ }
+}
+
+time4_t time4(time4_t *ptr)
+{
+ if( ptr == NULL )
+ return time(NULL);
+ else
+ return *ptr = (time4_t)time(NULL);
+}
+#endif
+
+char *
+my_ctime(const time4_t * t, char *ans, int len)
+{
+ struct tm *tp;
+
+ tp = localtime4((time4_t*)t);
+ snprintf(ans, len,
+ "%02d/%02d/%02d %02d:%02d:%02d", (tp->tm_year % 100),
+ tp->tm_mon + 1, tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec);
+ return ans;
+}