From b27ece46a69aa7d5b9a759a2164609dab689f258 Mon Sep 17 00:00:00 2001 From: piaip Date: Wed, 26 Mar 2008 17:26:28 +0000 Subject: (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 --- common/Makefile | 8 + common/bbs/Makefile | 24 ++ common/bbs/log.c | 0 common/bbs/money.c | 36 +++ common/bbs/string.c | 1 + common/diet/alloc.c | 254 ++++++++++++++++++ common/diet/random.c | 711 +++++++++++++++++++++++++++++++++++++++++++++++++++ common/diet/time.c | 20 ++ common/sys/Makefile | 24 ++ common/sys/crypt.c | 647 ++++++++++++++++++++++++++++++++++++++++++++++ common/sys/file.c | 489 +++++++++++++++++++++++++++++++++++ common/sys/lock.c | 23 ++ common/sys/log.c | 43 ++++ common/sys/net.c | 114 +++++++++ common/sys/osdep.c | 376 +++++++++++++++++++++++++++ common/sys/sort.c | 10 + common/sys/string.c | 345 +++++++++++++++++++++++++ common/sys/time.c | 116 +++++++++ 18 files changed, 3241 insertions(+) create mode 100644 common/Makefile create mode 100644 common/bbs/Makefile create mode 100644 common/bbs/log.c create mode 100644 common/bbs/money.c create mode 100644 common/bbs/string.c create mode 100644 common/diet/alloc.c create mode 100644 common/diet/random.c create mode 100644 common/diet/time.c create mode 100644 common/sys/Makefile create mode 100644 common/sys/crypt.c create mode 100644 common/sys/file.c create mode 100644 common/sys/lock.c create mode 100644 common/sys/log.c create mode 100644 common/sys/net.c create mode 100644 common/sys/osdep.c create mode 100644 common/sys/sort.c create mode 100644 common/sys/string.c create mode 100644 common/sys/time.c (limited to 'common') 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 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 +#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 +#include +#include + +#include +#include +#include +#include +#include + +#include /* 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<>__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;inext=(((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 (sizesize=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 (sizesize!=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 +#include +#include +#include +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 +#include +#include + + +/* 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 +#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 +#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>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 + * 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 +#include // random +#include // flock +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include + +/** + * 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 +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include + +#ifdef NEED_STRLCAT + +#include +#include + +/* size_t + * strlcat(char *dst, const char *src, size_t size); + */ +/* + * Copyright (c) 1998 Todd C. Miller + * 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 +#include + +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 + * 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 +#include + +#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 +#include +#include +#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= 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= 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 +#include +#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; +} -- cgit v1.2.3