cvsps-2.1/0000755000015100000120000000000010245242374012712 5ustar davidwheel00000000000000cvsps-2.1/cbtcommon/0000755000015100000120000000000010245242375014674 5ustar davidwheel00000000000000cvsps-2.1/cbtcommon/list.h0000644000015100000120000000523310245242374016022 0ustar davidwheel00000000000000/* * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. * See COPYING file for license information */ #ifndef _COMMON_LIST_H #define _COMMON_LIST_H /* * Stolen from linux-2.1.131 * All comments from the original source unless otherwise noted * Added: the CLEAR_LIST_NODE macro */ /* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ #include "inline.h" struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD(name) \ struct list_head name = { &name, &name } #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) #define CLEAR_LIST_NODE(ptr) do { \ (ptr)->next = NULL; (ptr)->prev = NULL; \ } while (0) /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static INLINE void __list_add(struct list_head *li, struct list_head * prev, struct list_head * next) { next->prev = li; li->next = next; li->prev = prev; prev->next = li; } /* * Insert a new entry after the specified head.. */ static INLINE void list_add(struct list_head *li, struct list_head *head) { __list_add(li, head, head->next); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static INLINE void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } static INLINE void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); } static INLINE int list_empty(struct list_head *head) { return head->next == head; } /* * Splice in "list" into "head" */ static INLINE void list_splice(struct list_head *list, struct list_head *head) { struct list_head *first = list->next; if (first != list) { struct list_head *last = list->prev; struct list_head *at = head->next; first->prev = head; head->next = first; last->next = at; at->prev = last; } } #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) #endif /* _COMMON_LIST_H */ cvsps-2.1/cbtcommon/hash.h0000644000015100000120000000236510245242374015775 0ustar davidwheel00000000000000/* * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. * See COPYING file for license information */ #ifndef _COMMON_HASH_H #define _COMMON_HASH_H #include "list.h" struct hash_entry { char *he_key; void *he_obj; struct list_head he_list; }; struct hash_table { int ht_size; struct list_head *ht_lists; int iterator; struct list_head *iterator_ptr; }; enum { HT_NO_KEYCOPY, HT_KEYCOPY }; #ifdef __cplusplus extern "C" { #endif struct hash_table *create_hash_table(unsigned int sz); void destroy_hash_table(struct hash_table *tbl, void (*delete_obj)(void *)); void *put_hash_object(struct hash_table *tbl, const char *key, void *obj); void *get_hash_object(struct hash_table *tbl, const char *key); void *remove_hash_object(struct hash_table *tbl, const char *key); int put_hash_object_ex(struct hash_table *tbl, const char *key, void *obj, int, char **, void **); void destroy_hash_table_ex(struct hash_table *tbl, void (*delete_entry)(const void *, char *, void *), const void *); void reset_hash_iterator(struct hash_table *tbl); struct hash_entry *next_hash_entry(struct hash_table *tbl); #ifdef __cplusplus } #endif #endif /* _COMMON_HASH_H */ cvsps-2.1/cbtcommon/text_util.h0000644000015100000120000000211610245242374017065 0ustar davidwheel00000000000000/* * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. * See COPYING file for license information */ /** * Copyright (c) 1998 Cobite, Inc. All Rights Reserved. * @author Karl LaRocca * @created Fri Nov 6 14:48:04 1998 * @version $Revision: 1.4 $$Date: 2001/10/25 18:36:11 $ */ #ifndef _TEXT_UTIL_H #define _TEXT_UTIL_H #ifdef __cplusplus extern "C" { #endif char* chop( char* src ); char* digits( char* src ); char* lower_case( char* src ); char* reverse( char* src ); char* trim( char* src ); void trim_zeros_after_decimal( char* src ); char* upper_case( char* src ); int strrcmp( const char* haystack, const char* needle ); const char* cents2money( long cents ); long money2cents( const char* money ); // these two allocate returned memory, so be sure to free it... char* frobstr( char* src ); char* unfrobstr( char* src ); void str2hex( char* dest, const char* src, int slen ); void hex2str( char* dest, const char* src, int slen ); #ifdef __cplusplus } #endif #endif /* _TEXT_UTIL_H */ cvsps-2.1/cbtcommon/debug.h0000644000015100000120000000303710245242374016135 0ustar davidwheel00000000000000/* * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. * See COPYING file for license information */ #ifndef _DEBUG_H #define _DEBUG_H #include #include #ifndef MACINTOSH #include #endif #include "inline.h" #define DEBUG_NUM_FACILITIES 32 /* should be 64 on 64bit CPU... */ #define DEBUG_SYSERROR 1 /* same as DEBUG_ERROR, but here for clarity */ #define DEBUG_ERROR 1 #define DEBUG_STATUS 2 #define DEBUG_TCP 4 #define DEBUG_SIGNALS 8 #define DEBUG_APPERROR 16 #define DEBUG_APPMSG1 32 #define DEBUG_APPMSG2 64 #define DEBUG_APPMSG3 128 #define DEBUG_APPMSG4 256 #define DEBUG_APPMSG5 512 #define DEBUG_LIBERROR 1024 #define DEBUG_LIBSTATUS 2048 #ifdef __cplusplus extern "C" { #endif extern unsigned int debuglvl; void hexdump( const char *ptr, int size, const char *fmt, ... ); void vdebug(int dtype, const char *fmt, va_list); void vmdebug(int dtype, const char *fmt, va_list); void to_hex( char* dest, const char* src, size_t n ); void debug_set_error_file(FILE *); void debug_set_error_facility(int mask, FILE *); static INLINE void debug(unsigned int dtype, const char *fmt, ...) { va_list ap; if (!(debuglvl & dtype)) return; va_start(ap, fmt); vdebug(dtype, fmt, ap); va_end(ap); } static INLINE void mdebug(unsigned int dtype, const char *fmt, ...) { va_list ap; if (!(debuglvl & dtype)) return; va_start(ap, fmt); vmdebug(dtype, fmt, ap); va_end(ap); } #ifdef __cplusplus } #endif #endif /* DEBUG_H */ cvsps-2.1/cbtcommon/rcsid.h0000644000015100000120000000102210245242374016143 0ustar davidwheel00000000000000/* * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. * See COPYING file for license information */ #ifndef _COMMON_RCSID_H #define _COMMON_RCSID_H /* RCS Id macro (complements of bod@compusol.com.au (Brendan O'Dea)) */ #ifdef lint # define RCSID(i) #else /* lint */ # ifdef __GNUC__ # define ATTRIB_UNUSED __attribute__ ((unused)) # else /* __GNUC__ */ # define ATTRIB_UNUSED # endif /* __GNUC__ */ # define RCSID(i) static char const *rcsid ATTRIB_UNUSED = (i) #endif /* lint */ #endif /* _COMMON_RCSID_H */ cvsps-2.1/cbtcommon/inline.h0000644000015100000120000000053410245242374016324 0ustar davidwheel00000000000000/* * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. * See COPYING file for license information */ #ifndef UTIL_INLINE_H #define UTIL_INLINE_H #ifdef __GNUC__ #define INLINE __inline__ #endif #ifdef WIN32 #define INLINE __inline #endif /* INLINE of last resort... heh */ #ifndef INLINE #define INLINE /* void */ #endif #endif cvsps-2.1/cbtcommon/debug.c0000644000015100000120000000704010245242374016126 0ustar davidwheel00000000000000/* * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. * See COPYING file for license information */ #include #include #include #include #include #include "debug.h" #include "rcsid.h" #ifdef _WIN32 #include #endif RCSID("$Id: debug.c,v 1.14 2001/11/29 00:00:30 amb Exp $"); unsigned int debuglvl = ~0; static FILE *debug_output_channel[DEBUG_NUM_FACILITIES]; #ifdef MACINTOSH int ffs( int val ) { int i = 0; for( i = 0; i < 32; i++ ) { if( val & ( 1 << i ) ) return i+1; } return 0; } #endif void vdebug(int dtype, const char *fmt, va_list ap) { int keep_errno; char msgbuff[8192]; /* errno could be changed by vsprintf or perror */ keep_errno = errno; if (debuglvl & dtype) { FILE * channel = debug_output_channel[ffs(dtype)]; if (!channel) channel = stderr; #ifdef MACINTOSH vsprintf(msgbuff, fmt, ap); #else vsnprintf(msgbuff, sizeof(msgbuff), fmt, ap); #endif /* DEBUG_ERROR (aka DEBUG_SYSERROR) */ if (dtype == DEBUG_ERROR) { const char * errmsg = ""; #ifndef MACINTOSH errmsg = strerror(errno); #endif fprintf(channel, "%s: %s\n", msgbuff, errmsg); } else fprintf(channel, "%s\n", msgbuff); fflush(channel); #ifdef _WIN32 if (dtype == DEBUG_SYSERROR || dtype == DEBUG_APPERROR) MessageBox(NULL, msgbuff, "Application Error", MB_OK); #endif } errno = keep_errno; } void vmdebug(int dtype, const char * fmt, va_list ap) { FILE * chn[DEBUG_NUM_FACILITIES]; int i; memcpy(chn, debug_output_channel, sizeof(FILE*) * DEBUG_NUM_FACILITIES); for (i = 0; i < DEBUG_NUM_FACILITIES; i++) if (chn[i] == NULL) chn[i] = stderr; for (i = 0; i < DEBUG_NUM_FACILITIES; i++) { if ((dtype & (1 << i)) && chn[i]) { if (debuglvl & (1 << i)) { int j; vdebug(1 << i, fmt, ap); for (j = i + 1; j < DEBUG_NUM_FACILITIES; j++) if (chn[j] == chn[i]) chn[j] = NULL; } } } } /* FIXME: use actual debug output core routine vdebug... */ void hexdump(const char *ptr, int size, const char *fmt, ...) { static char hexbuff[49]; static char printbuff[17]; int count = 0; va_list ap; if ( !debuglvl & DEBUG_STATUS ) return; va_start(ap, fmt); /* print the heading/banner */ vdebug(DEBUG_STATUS, fmt, ap); memset(hexbuff, 0, 49); memset(printbuff, 0, 17); while (size--) { sprintf(hexbuff + (count*3), "%02x ", (int)*((unsigned char *)ptr)); if (isprint(*ptr)) printbuff[count] = *ptr; else printbuff[count] = '.'; ptr++; if ( count++ == 15 ) { count = 0; debug(DEBUG_STATUS, "%s %s", hexbuff, printbuff); memset(hexbuff, 0, 49); memset(printbuff, 0, 17); } } if ( count > 0 ) { while ( count % 16 != 0 ) { sprintf(hexbuff + (count * 3), "xx "); printbuff[count++] = '.'; } debug(DEBUG_STATUS, "%s %s", hexbuff, printbuff); } va_end(ap); } void to_hex( char* dest, const char* src, size_t n ) { while ( n-- ) { sprintf( dest, "%02x ", (int)*((unsigned char *)src)); dest += 3; src++; } *dest = 0; } void debug_set_error_file(FILE *f) { int i; for (i = 0; i < DEBUG_NUM_FACILITIES; i++) debug_output_channel[i] = f; } void debug_set_error_facility(int fac, FILE * f) { int i; for (i = 0; i < DEBUG_NUM_FACILITIES; i++) if (!debug_output_channel[i]) debug_output_channel[i] = stderr; debug_output_channel[ffs(fac)] = f; } cvsps-2.1/cbtcommon/hash.c0000644000015100000120000001320510245242374015763 0ustar davidwheel00000000000000/* * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. * See COPYING file for license information */ #include #include #include #include "debug.h" #include "hash.h" #include "rcsid.h" RCSID("$Id: hash.c,v 1.6 2003/05/07 15:42:38 david Exp $"); #define HASH_CONST 37 static unsigned int hash_string(const char *); static struct hash_entry *scan_list(struct list_head *, const char *); static struct hash_entry *get_hash_entry(struct hash_table *tbl, const char *key); struct hash_table *create_hash_table(unsigned int sz) { struct hash_table *tbl; unsigned int i; tbl = (struct hash_table *)malloc(sizeof(*tbl) + sz*sizeof(struct list_head)); if (!tbl) { debug(DEBUG_APPERROR, "malloc for hash_table failed"); return NULL; } tbl->ht_size = sz; tbl->ht_lists = (struct list_head *)(tbl + 1); tbl->iterator = 0; for (i = 0; i < sz; i++) INIT_LIST_HEAD(&tbl->ht_lists[i]); return tbl; } void destroy_hash_table(struct hash_table *tbl, void (*delete_obj)(void *)) { struct list_head *head, *next, *tmp; struct hash_entry *entry; int i; for (i = 0; i < tbl->ht_size; i++) { head = &tbl->ht_lists[i]; next = head->next; while (next != head) { tmp = next->next; entry = list_entry(next, struct hash_entry, he_list); if (delete_obj) delete_obj(entry->he_obj); free(entry); next = tmp; } } free(tbl); } /* FIXME: there is no way for the user of this to determine the difference * between a put to a new key value and a malloc failure */ void *put_hash_object(struct hash_table *tbl, const char *key, void *obj) { void * retval; put_hash_object_ex(tbl, key, obj, HT_KEYCOPY, NULL, &retval); return retval; } static struct hash_entry *get_hash_entry(struct hash_table *tbl, const char *key) { struct list_head *head; struct hash_entry *entry; unsigned int hash; hash = hash_string(key) % tbl->ht_size; head = &tbl->ht_lists[hash]; entry = scan_list(head, key); return entry; } void *get_hash_object(struct hash_table *tbl, const char *key) { struct hash_entry *entry = get_hash_entry(tbl, key); return (entry) ? entry->he_obj : NULL; } void *remove_hash_object(struct hash_table *tbl, const char *key) { struct hash_entry *entry = get_hash_entry(tbl, key); void *retval = NULL; if (entry) { list_del(&entry->he_list); retval = entry->he_obj; free(entry); } return retval; } static unsigned int hash_string(register const char *key) { register unsigned int hash = 0; while(*key) hash = hash * HASH_CONST + *key++; return hash; } static struct hash_entry *scan_list(struct list_head *head, const char *key) { struct list_head *next = head->next; struct hash_entry *entry; while (next != head) { entry = list_entry(next, struct hash_entry, he_list); if (strcmp(entry->he_key, key) == 0) return entry; next = next->next; } return NULL; } void reset_hash_iterator(struct hash_table *tbl) { tbl->iterator = 0; tbl->iterator_ptr = NULL; } struct hash_entry *next_hash_entry(struct hash_table *tbl) { while( tbl->iterator < tbl->ht_size ) { struct list_head *head = &tbl->ht_lists[ tbl->iterator ]; if( tbl->iterator_ptr == NULL ) tbl->iterator_ptr = head->next; if( tbl->iterator_ptr != head ) { struct list_head *tmp = tbl->iterator_ptr; tbl->iterator_ptr = tbl->iterator_ptr->next; return( list_entry( tmp, struct hash_entry, he_list ) ); } else { tbl->iterator++; tbl->iterator_ptr = NULL; } } return( NULL ); } int put_hash_object_ex(struct hash_table *tbl, const char *key, void *obj, int copy, char ** oldkey, void ** oldobj) { struct list_head *head; struct hash_entry *entry; unsigned int hash; int retval = 0; /* FIXME: how can get_hash_entry be changed to be usable here? * we need the value of head later if the entry is not found... */ hash = hash_string(key) % tbl->ht_size; head = &tbl->ht_lists[hash]; entry = scan_list(head, key); if (entry) { if (oldkey) *oldkey = entry->he_key; if (oldobj) *oldobj = entry->he_obj; /* if 'copy' is set, then we already have an exact * private copy of the key (by definition of having * found the match in scan_list) so we do nothing. * if !copy, then we can simply assign the new * key */ if (!copy) entry->he_key = (char*)key; /* discard the const */ entry->he_obj = obj; } else { size_t s = sizeof(*entry); if (oldkey) *oldkey = NULL; if (oldobj) *oldobj = NULL; if (copy) s += strlen(key) + 1; entry = (struct hash_entry *)malloc(s); if (!entry) { debug(DEBUG_APPERROR,"malloc failed put_hash_object key='%s'",key); retval = -1; } else { if (copy) { entry->he_key = (char *)(entry + 1); strcpy(entry->he_key, key); } else { entry->he_key = (char*)key; /* discard the const */ } entry->he_obj = obj; list_add(&entry->he_list, head); } } return retval; } void destroy_hash_table_ex(struct hash_table *tbl, void (*delete_entry)(const void *, char *, void *), const void * cookie) { struct list_head *head, *next, *tmp; struct hash_entry *entry; int i; for (i = 0; i < tbl->ht_size; i++) { head = &tbl->ht_lists[i]; next = head->next; while (next != head) { tmp = next->next; entry = list_entry(next, struct hash_entry, he_list); if (delete_entry) delete_entry(cookie, entry->he_key, entry->he_obj); free(entry); next = tmp; } } free(tbl); } cvsps-2.1/cbtcommon/text_util.c0000644000015100000120000001102110245242374017053 0ustar davidwheel00000000000000/* * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. * See COPYING file for license information */ /** * Copyright (c) 1998 Cobite, Inc. All Rights Reserved. * @author Karl LaRocca * @created Fri Nov 6 14:33:29 1998 * @version $Revision: 1.9 $$Date: 2001/10/25 18:36:11 $ */ #include #include #include #include #include "text_util.h" #include "rcsid.h" RCSID("$Id: text_util.c,v 1.9 2001/10/25 18:36:11 adam Exp $"); char* chop( char* src ) { char* p = src + strlen(src) - 1; while( p >= src ) { if ( *p == '\n' || *p == '\r' ) { *p-- = 0; } else { break; } } return( src ); } char* digits( char* src ) { char* start = src; char* check = src; while( *check ) { if ( isdigit( *check ) ) { *start++ = *check; } check++; } *start = 0; return( src ); } char* lower_case( char* src ) { char* p = src; while( *p ) { *p = tolower( *p ); p++; } return( src ); } char* reverse( char* src ) { int i; int len = strlen( src ); char tmp; for( i = len / 2; --i >= 0; ) { tmp = src[ i ]; src[ i ] = src[ len - i - 1 ]; src[ len - i - 1 ] = tmp; } return( src ); } char* trim( char* src ) { char *p = src + strlen(src) - 1; while( p >= src && isspace(*p) ) *p-- = '\0'; return src; } char* upper_case( char* src ) { char* p = src; while( *p ) { *p = toupper(*p); p++; } return( src ); } int strrcmp( const char* haystack, const char* needle ) { int hlen = strlen( haystack ); int nlen = strlen( needle ); if( hlen < nlen ) return( -1 ); else return( strcmp( haystack + hlen - nlen, needle ) ); } /* * Finding a - anywhere in the string makes it money negative. * all characters other than digits, '-', and '.' are ignored, so: * ab36-.g98 = -36.98 * This is fair, I think, if we don't want to reject anything as * improperly formatted. */ long money2cents( const char* money ) { long retval = 0; int decimal_places = -1; int neg = 0; while( *money && decimal_places < 2 ) { if ( isdigit( *money ) ) { if ( decimal_places >= 0 ) decimal_places++; retval *= 10; retval += (*money) - '0'; } else if ( *money == '.' ) decimal_places = 0; else if ( *money == '-' ) neg = 1; money++; } if ( decimal_places == 1 ) retval *= 10; else if ( decimal_places <= 0 ) retval *= 100; return( neg ? -retval : retval ); } const char* cents2money( long cents ) { static char buff[ 64 ]; int idx = 0; char* d = buff; if ( cents == 0 ) { strcpy( buff, "0.00" ); } else if ( cents < 100 ) { sprintf( buff, "0.%2.2ld", cents ); } else { while( cents > 0 ) { *d++ = '0' + ( cents % 10 ); cents = cents / 10; if ( idx == 1 ) { *d++ = '.'; } else if ( cents > 0 && ( idx - 1 ) % 3 == 0 ) { *d++ = ','; } idx++; } *d++ = 0; reverse( buff ); } return( buff ); } void trim_zeros_after_decimal( char* src ) { char * end = src + strlen( src ) - 1; while( end != src ) { if( *end == '0' ) *end = 0; else if( *end == '.' ) { *end = 0; break; } else break; end--; } } #ifdef linux extern void *memfrob(void *, size_t); #else static void * memfrob(void * mem, size_t len) { size_t i; char *c = (char *)mem; for (i = 0; i < len; i++) { *c = *c ^ 42; c++; } return mem; } #endif // simple functions to obfuscate strings in a binary char* frobstr( char* src ) { char* retval = (char*)malloc( strlen(src) * 2 + 1 ); memfrob( src, strlen( src ) ); str2hex( retval, src, 0 ); memfrob( src, strlen( src ) ); return( retval ); } char* unfrobstr( char* src ) { int slen = strlen( src ) / 2; char* retval = (char*)malloc( slen + 1 ); hex2str( retval, src, 0 ); memfrob( retval, slen ); return( retval ); } void str2hex( char* dest, const char* src, int slen ) { int i; char* p = dest; if( slen == 0 ) slen = strlen( src ); for ( i = 0; i < slen; i++ ) { sprintf( p, "%02x", src[i] ); p += 2; } *p = 0; } void hex2str( char* dest, const char* src, int slen ) { const char* p = src; int i; unsigned int v; if( slen == 0 ) slen = strlen( src ); slen /= 2; for( i = 0; i < slen; i++ ) { sscanf( p, "%02x", &v ); dest[i] = (char)v; p += 2; } dest[ slen ] = 0; } cvsps-2.1/cbtcommon/tcpsocket.c0000644000015100000120000001151110245242374017035 0ustar davidwheel00000000000000/* * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. * See COPYING file for license information */ #ifdef SOLARIS #include #else #include #endif #ifdef WIN32 #include #else /* not windows */ #include #include #include #include #include #include #ifdef SOLARIS #include #endif #endif /* if windows */ #include "tcpsocket.h" #include "debug.h" #include "rcsid.h" #ifdef WIN32 #include "win32fd.h" #endif RCSID("$Id: tcpsocket.c,v 1.6 1999/12/27 20:35:34 david Exp $"); int tcp_create_socket(int reuse_addr) { int retval; int yes = 1; if ((retval = socket(AF_INET, SOCK_STREAM, 0)) < 0) { debug(DEBUG_ERROR, "tcp: can't create socket"); } if (reuse_addr) { setsockopt( retval, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(int)); } debug(DEBUG_TCP, "tcp: socket created"); #ifdef WIN32 return get_fd(retval, WIN32_SOCKET); #else return retval; #endif } int tcp_bind_and_listen(int sockfd, unsigned short tcp_port) { struct sockaddr_in addr; memset((char *) &addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(tcp_port); #ifdef WIN32 sockfd = win32_file_table[sockfd].win32id; #endif if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { debug(DEBUG_ERROR, "tcp: can't bind to socket"); return -1; } if (listen(sockfd, LISTEN_QUEUE_SIZE) < 0) { debug(DEBUG_ERROR, "tcp: can't listen on socket"); return -1; } debug(DEBUG_TCP, "tcp: socket bound and listening"); return 0; } int tcp_accept_connection(int sockfd) { struct sockaddr_in remaddr; int addrlen; int retval; #ifdef WIN32 sockfd = win32_file_table[sockfd].win32id; #endif addrlen = sizeof(struct sockaddr_in); #ifdef WIN32 if ((retval = accept(sockfd, (struct sockaddr *) &remaddr, &addrlen)) == INVALID_SOCKET) { debug(DEBUG_APPERROR, "tcp: error accepting connection"); return -1; } #else if ((retval = accept(sockfd, (struct sockaddr *) &remaddr, &addrlen)) < 0) { if (errno != EINTR ) debug(DEBUG_ERROR, "tcp: error accepting connection"); return -1; } #endif debug(DEBUG_TCP, "tcp: got connection (fd=%d)", retval); return retval; } unsigned int tcp_get_client_ip(int fd) { struct sockaddr_in remaddr; int addrlen; int retval; unsigned int saddr; #ifdef WIN32 fd = win32_file_table[fd].win32id; #endif addrlen = sizeof(struct sockaddr_in); if ((retval = getpeername(fd, (struct sockaddr *) &remaddr, &addrlen)) < 0) { debug(DEBUG_ERROR, "tcp: error getting remote's ip address"); return 0; } saddr = ntohl(remaddr.sin_addr.s_addr); return saddr; } int tcp_connect(int sockfd, const char *rem_addr, unsigned short port) { struct sockaddr_in addr; int addrlen; long ipno; #ifdef WIN32 sockfd = win32_file_table[sockfd].win32id; #endif if ( convert_address(&ipno , rem_addr) < 0 ) { return -1; } addrlen = sizeof(struct sockaddr_in); memset((char *) &addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = ipno; addr.sin_port = htons(port); if (connect(sockfd, (struct sockaddr *)&addr, addrlen) < 0) { debug(DEBUG_ERROR, "connect error"); return -1; } debug(DEBUG_STATUS, "tcp: connection established on port %d", port); return 0; } int convert_address(long *dest, const char *addr_str) { #ifdef LINUX struct in_addr ip; #endif int retval = 0; char errstr[256]; /* first try converting "numbers and dots" notation */ #ifdef LINUX if ( inet_aton(addr_str, &ip) ) { memcpy(dest, &ip.s_addr, sizeof(ip.s_addr)); } #else if ( (*dest = inet_addr(addr_str)) != -1) { /* nothing */ } #endif else /* if it fails, do a gethostbyname() */ { struct hostent *host; if ((host = gethostbyname(addr_str)) == NULL) { switch(h_errno) { case HOST_NOT_FOUND: strcpy(errstr, "HOST_NOT_FOUND"); break; case NO_ADDRESS: strcpy(errstr, "NO_ADDRESS"); break; case NO_RECOVERY: strcpy(errstr, "NO_RECOVERY"); break; case TRY_AGAIN: strcpy(errstr, "TRY_AGAIN"); break; } debug(DEBUG_ERROR, "gethostbyname failed for %s: ", addr_str, errstr); retval = -1; } memcpy(dest, host->h_addr_list[0], sizeof(unsigned long)); } return retval; } int tcp_get_local_address(int sockfd, unsigned int *ip, unsigned short *port) { struct sockaddr_in addr; int addrlen = sizeof(struct sockaddr_in); if(getsockname(sockfd, (struct sockaddr *)&addr, &addrlen) < 0) { debug(DEBUG_SYSERROR, "getsockname failed" ); return -1; } *ip = ntohl( addr.sin_addr.s_addr ); *port = ntohs( addr.sin_port ); return 0; } cvsps-2.1/cbtcommon/tcpsocket.h0000644000015100000120000000136110245242374017044 0ustar davidwheel00000000000000/* * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. * See COPYING file for license information */ #ifndef _TCPSOCKET_H #define _TCPSOCKET_H #ifdef __cplusplus extern "C" { #endif #ifndef LISTEN_QUEUE_SIZE #define LISTEN_QUEUE_SIZE 5 #endif #define REUSE_ADDR 1 #define NO_REUSE_ADDR 0 int tcp_create_socket(int reuse_addr); int tcp_bind_and_listen(int sockfd, unsigned short tcpport); int tcp_accept_connection(int sockfd); unsigned int tcp_get_client_ip(int fd); int tcp_connect(int sockfd, const char *rem_addr, unsigned short port); int convert_address(long *dest, const char *addr_str); int tcp_get_local_address(int sockfd, unsigned int *, unsigned short *); #ifdef __cplusplus } #endif #endif /* TCPSOCKET_H */ cvsps-2.1/cbtcommon/sio.c0000644000015100000120000000276210245242375015641 0ustar davidwheel00000000000000/* * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. * See COPYING file for license information */ #include #ifdef WIN32 #include #else #include #endif #include #include "sio.h" #include "rcsid.h" RCSID("$Id: sio.c,v 1.5 2001/10/25 18:36:11 adam Exp $"); ssize_t readn(int fd, void *buf, size_t len) { int nleft,nread; nleft = len; while (nleft > 0) { nread = read(fd,buf,nleft); /* there is an issue which EINTR which could leave us a bit haywire * if we get a signal after having read some bytes. special handling * N.B: we *do* return EINTR if no data has been read yet (thanks Karl) */ if (nread < 0) { if (errno == EINTR && nleft != (int)len) continue; else return (nread); } else if (nread == 0) break; nleft -= nread; if (nleft) buf = ((char *)buf) + nread; } return (len - nleft); } ssize_t writen(int fd, const void *buf, size_t len) { int nleft, nwritten; nleft = len; while (nleft > 0) { nwritten = write(fd,buf,nleft); /* there is an issue with EINTR if we have already written a few bytes! return if we have not written any yet */ if (nwritten < 0 && errno == EINTR) { if (nleft == (int)len) return nwritten; continue; } if (nwritten <= 0) return nwritten; nleft -= nwritten; if (nleft) buf = ((char *)buf) + nwritten; } return (len - nleft); } cvsps-2.1/cbtcommon/sio.h0000644000015100000120000000077210245242375015645 0ustar davidwheel00000000000000/* * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. * See COPYING file for license information */ #ifndef _SIO_H #define _SIO_H /* include for typedefs */ #ifdef WIN32 #include typedef int ssize_t; #else #include #endif #ifdef __cplusplus extern "C" { #endif /* these are W.R.Stevens' famous io routines to read or write bytes to fd */ ssize_t readn(int, void *, size_t); ssize_t writen(int, const void *, size_t); #ifdef __cplusplus } #endif #endif /* _SIO_H */ cvsps-2.1/Makefile0000644000015100000120000000116110245242374014351 0ustar davidwheel00000000000000MAJOR=2 MINOR=1 CC?=gcc CFLAGS?=-g -O2 -Wall CFLAGS+=-I. -DVERSION=\"$(MAJOR).$(MINOR)\" prefix?=/usr/local OBJS=\ cbtcommon/debug.o\ cbtcommon/hash.o\ cbtcommon/text_util.o\ cbtcommon/sio.o\ cbtcommon/tcpsocket.o\ cvsps.o\ cache.o\ util.o\ stats.o\ cap.o\ cvs_direct.o\ list_sort.o all: cvsps cvsps: $(OBJS) $(CC) -o cvsps $(OBJS) -lz install: [ -d $(prefix)/bin ] || mkdir -p $(prefix)/bin [ -d $(prefix)/share/man/man1 ] || mkdir -p $(prefix)/share/man/man1 install cvsps $(prefix)/bin install -m 644 cvsps.1 $(prefix)/share/man/man1 clean: rm -f cvsps *.o cbtcommon/*.o core .PHONY: install clean cvsps-2.1/cvsps.spec0000644000015100000120000000224010245242374014722 0ustar davidwheel00000000000000Version: 2.1 Summary: CVSps is a program for generating 'patchset' information from a CVS repository Name: cvsps Release: 1 URL: http://www.cobite.com/cvsps/ Source0: %{name}-%{version}.tar.gz License: GPL Group: Development/Tools BuildRoot: %{_tmppath}/%{name}-root prefix: /usr %description CVSps is a program for generating 'patchset' information from a CVS repository. A patchset in this case is defined as a set of changes made to a collection of files, and all committed at the same time (using a single 'cvs commit' command). This information is valuable to seeing the big picture of the evolution of a cvs project. While cvs tracks revision information, it is often difficult to see what changes were committed 'atomically' to the repository. %prep %setup -q %build make %install rm -rf $RPM_BUILD_ROOT %makeinstall %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %doc README CHANGELOG COPYING %{prefix}/bin/cvsps %{prefix}/man/man*/* %changelog * Tue Apr 1 2002 David Mansfield - (no really - not April fools joke) - revise spec file from Jan - merge Makefile changes * Tue Mar 5 2002 Jan IVEN - Initial build. cvsps-2.1/cvsps.c0000644000015100000120000020434310245242374014222 0ustar davidwheel00000000000000/* * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. * See COPYING file for license information */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* for WEXITSTATUS - see system(3) */ #include #include #include #include #include #include "cache.h" #include "cvsps_types.h" #include "cvsps.h" #include "util.h" #include "stats.h" #include "cap.h" #include "cvs_direct.h" #include "list_sort.h" RCSID("$Id: cvsps.c,v 4.106 2005/05/26 03:39:29 david Exp $"); #define CVS_LOG_BOUNDARY "----------------------------\n" #define CVS_FILE_BOUNDARY "=============================================================================\n" enum { NEED_FILE, NEED_SYMS, NEED_EOS, NEED_START_LOG, NEED_REVISION, NEED_DATE_AUTHOR_STATE, NEED_EOM }; /* true globals */ struct hash_table * file_hash; CvsServerCtx * cvs_direct_ctx; char root_path[PATH_MAX]; char repository_path[PATH_MAX]; const char * tag_flag_descr[] = { "", "**FUNKY**", "**INVALID**", "**INVALID**" }; const char * fnk_descr[] = { "", "FNK_SHOW_SOME", "FNK_SHOW_ALL", "FNK_HIDE_ALL", "FNK_HIDE_SOME" }; /* static globals */ static int ps_counter; static void * ps_tree; static struct hash_table * global_symbols; static char strip_path[PATH_MAX]; static int strip_path_len; static time_t cache_date; static int update_cache; static int ignore_cache; static int do_write_cache; static int statistics; static const char * test_log_file; static struct hash_table * branch_heads; static struct list_head all_patch_sets; static struct list_head collisions; /* settable via options */ static int timestamp_fuzz_factor = 300; static int do_diff; static const char * restrict_author; static int have_restrict_log; static regex_t restrict_log; static int have_restrict_file; static regex_t restrict_file; static time_t restrict_date_start; static time_t restrict_date_end; static const char * restrict_branch; static struct list_head show_patch_set_ranges; static int summary_first; static const char * norc = ""; static const char * patch_set_dir; static const char * restrict_tag_start; static const char * restrict_tag_end; static int restrict_tag_ps_start; static int restrict_tag_ps_end = INT_MAX; static const char * diff_opts; static int bkcvs; static int no_rlog; static int cvs_direct; static int compress; static char compress_arg[8]; static int track_branch_ancestry; static void check_norc(int, char *[]); static int parse_args(int, char *[]); static int parse_rc(); static void load_from_cvs(); static void init_paths(); static CvsFile * parse_file(const char *); static CvsFileRevision * parse_revision(CvsFile * file, char * rev_str); static void assign_pre_revision(PatchSetMember *, CvsFileRevision * rev); static void check_print_patch_set(PatchSet *); static void print_patch_set(PatchSet *); static void assign_patchset_id(PatchSet *); static int compare_rev_strings(const char *, const char *); static int compare_patch_sets_by_members(const PatchSet * ps1, const PatchSet * ps2); static int compare_patch_sets_bk(const void *, const void *); static int compare_patch_sets(const void *, const void *); static int compare_patch_sets_bytime_list(struct list_head *, struct list_head *); static int compare_patch_sets_bytime(const PatchSet *, const PatchSet *); static int is_revision_metadata(const char *); static int patch_set_member_regex(PatchSet * ps, regex_t * reg); static int patch_set_affects_branch(PatchSet *, const char *); static void do_cvs_diff(PatchSet *); static PatchSet * create_patch_set(); static PatchSetRange * create_patch_set_range(); static void parse_sym(CvsFile *, char *); static void resolve_global_symbols(); static int revision_affects_branch(CvsFileRevision *, const char *); static int is_vendor_branch(const char *); static void set_psm_initial(PatchSetMember * psm); static int check_rev_funk(PatchSet *, CvsFileRevision *); static CvsFileRevision * rev_follow_branch(CvsFileRevision *, const char *); static int before_tag(CvsFileRevision * rev, const char * tag); static void determine_branch_ancestor(PatchSet * ps, PatchSet * head_ps); static void handle_collisions(); int main(int argc, char *argv[]) { debuglvl = DEBUG_APPERROR|DEBUG_SYSERROR|DEBUG_APPMSG1; INIT_LIST_HEAD(&show_patch_set_ranges); /* * we want to parse the rc first, so command line can override it * but also, --norc should stop the rc from being processed, so * we look for --norc explicitly first. Note: --norc in the rc * file itself will prevent the cvs rc file from being used. */ check_norc(argc, argv); if (strlen(norc) == 0 && parse_rc() < 0) exit(1); if (parse_args(argc, argv) < 0) exit(1); if (diff_opts && !cvs_direct && do_diff) { debug(DEBUG_APPMSG1, "\nWARNING: diff options are not supported by 'cvs rdiff'"); debug(DEBUG_APPMSG1, " which is usually used to create diffs. 'cvs diff'"); debug(DEBUG_APPMSG1, " will be used instead, but the resulting patches "); debug(DEBUG_APPMSG1, " will need to be applied using the '-p0' option"); debug(DEBUG_APPMSG1, " to patch(1) (in the working directory), "); debug(DEBUG_APPMSG1, " instead of '-p1'\n"); } file_hash = create_hash_table(1023); global_symbols = create_hash_table(111); branch_heads = create_hash_table(1023); INIT_LIST_HEAD(&all_patch_sets); INIT_LIST_HEAD(&collisions); /* this parses some of the CVS/ files, and initializes * the repository_path and other variables */ init_paths(); if (!ignore_cache) { int save_fuzz_factor = timestamp_fuzz_factor; /* the timestamp fuzz should only be in effect when loading from * CVS, not re-fuzzed when loading from cache. This is a hack * working around bad use of global variables */ timestamp_fuzz_factor = 0; if ((cache_date = read_cache()) < 0) update_cache = 1; timestamp_fuzz_factor = save_fuzz_factor; } if (cvs_direct && (do_diff || (update_cache && !test_log_file))) cvs_direct_ctx = open_cvs_server(root_path, compress); if (update_cache) { load_from_cvs(); do_write_cache = 1; } //XXX //handle_collisions(); list_sort(&all_patch_sets, compare_patch_sets_bytime_list); ps_counter = 0; walk_all_patch_sets(assign_patchset_id); handle_collisions(); resolve_global_symbols(); if (do_write_cache) write_cache(cache_date); if (statistics) print_statistics(ps_tree); /* check that the '-r' symbols (if specified) were resolved */ if (restrict_tag_start && restrict_tag_ps_start == 0 && strcmp(restrict_tag_start, "#CVSPS_EPOCH") != 0) { debug(DEBUG_APPERROR, "symbol given with -r: %s: not found", restrict_tag_start); exit(1); } if (restrict_tag_end && restrict_tag_ps_end == INT_MAX) { debug(DEBUG_APPERROR, "symbol given with second -r: %s: not found", restrict_tag_end); exit(1); } walk_all_patch_sets(check_print_patch_set); if (summary_first++) walk_all_patch_sets(check_print_patch_set); if (cvs_direct_ctx) close_cvs_server(cvs_direct_ctx); exit(0); } static void load_from_cvs() { FILE * cvsfp; char buff[BUFSIZ]; int state = NEED_FILE; CvsFile * file = NULL; PatchSetMember * psm = NULL; char datebuff[20]; char authbuff[AUTH_STR_MAX]; char logbuff[LOG_STR_MAX + 1]; int loglen = 0; int have_log = 0; char cmd[BUFSIZ]; char date_str[64]; char use_rep_buff[PATH_MAX]; char * ltype; if (!no_rlog && !test_log_file && cvs_check_cap(CAP_HAVE_RLOG)) { ltype = "rlog"; snprintf(use_rep_buff, PATH_MAX, "%s", repository_path); } else { ltype = "log"; use_rep_buff[0] = 0; } if (cache_date > 0) { struct tm * tm = gmtime(&cache_date); strftime(date_str, 64, "%d %b %Y %H:%M:%S %z", tm); /* this command asks for logs using two different date * arguments, separated by ';' (see man rlog). The first * gets all revisions more recent than date, the second * gets a single revision no later than date, which combined * get us all revisions that have occurred since last update * and overlaps what we had before by exactly one revision, * which is necessary to fill in the pre_rev stuff for a * PatchSetMember */ snprintf(cmd, BUFSIZ, "cvs %s %s %s -d '%s<;%s' %s", compress_arg, norc, ltype, date_str, date_str, use_rep_buff); } else { date_str[0] = 0; snprintf(cmd, BUFSIZ, "cvs %s %s %s %s", compress_arg, norc, ltype, use_rep_buff); } debug(DEBUG_STATUS, "******* USING CMD %s", cmd); cache_date = time(NULL); /* FIXME: this is ugly, need to virtualize the accesses away from here */ if (test_log_file) cvsfp = fopen(test_log_file, "r"); else if (cvs_direct_ctx) cvsfp = cvs_rlog_open(cvs_direct_ctx, repository_path, date_str); else cvsfp = popen(cmd, "r"); if (!cvsfp) { debug(DEBUG_SYSERROR, "can't open cvs pipe using command %s", cmd); exit(1); } for (;;) { char * tst; if (cvs_direct_ctx) tst = cvs_rlog_fgets(buff, BUFSIZ, cvs_direct_ctx); else tst = fgets(buff, BUFSIZ, cvsfp); if (!tst) break; debug(DEBUG_STATUS, "state: %d read line:%s", state, buff); switch(state) { case NEED_FILE: if (strncmp(buff, "RCS file", 8) == 0 && (file = parse_file(buff))) state = NEED_SYMS; break; case NEED_SYMS: if (strncmp(buff, "symbolic names:", 15) == 0) state = NEED_EOS; break; case NEED_EOS: if (!isspace(buff[0])) { /* see cvsps_types.h for commentary on have_branches */ file->have_branches = 1; state = NEED_START_LOG; } else parse_sym(file, buff); break; case NEED_START_LOG: if (strcmp(buff, CVS_LOG_BOUNDARY) == 0) state = NEED_REVISION; break; case NEED_REVISION: if (strncmp(buff, "revision", 8) == 0) { char new_rev[REV_STR_MAX]; CvsFileRevision * rev; strcpy(new_rev, buff + 9); chop(new_rev); /* * rev may already exist (think cvsps -u), in which * case parse_revision is a hash lookup */ rev = parse_revision(file, new_rev); /* * in the simple case, we are copying rev to psm->pre_rev * (psm refers to last patch set processed at this point) * since generally speaking the log is reverse chronological. * This breaks down slightly when branches are introduced */ assign_pre_revision(psm, rev); /* * if this is a new revision, it will have no post_psm associated. * otherwise we are (probably?) hitting the overlap in cvsps -u */ if (!rev->post_psm) { psm = rev->post_psm = create_patch_set_member(); psm->post_rev = rev; psm->file = file; state = NEED_DATE_AUTHOR_STATE; } else { /* we hit this in cvsps -u mode, we are now up-to-date * w.r.t this particular file. skip all of the rest * of the info (revs and logs) until we hit the next file */ psm = NULL; state = NEED_EOM; } } break; case NEED_DATE_AUTHOR_STATE: if (strncmp(buff, "date:", 5) == 0) { char * p; strncpy(datebuff, buff + 6, 19); datebuff[19] = 0; strcpy(authbuff, "unknown"); p = strstr(buff, "author: "); if (p) { char * op; p += 8; op = strchr(p, ';'); if (op) { strzncpy(authbuff, p, op - p + 1); } } /* read the 'state' tag to see if this is a dead revision */ p = strstr(buff, "state: "); if (p) { char * op; p += 7; op = strchr(p, ';'); if (op) if (strncmp(p, "dead", MIN(4, op - p)) == 0) psm->post_rev->dead = 1; } state = NEED_EOM; } break; case NEED_EOM: if (strcmp(buff, CVS_LOG_BOUNDARY) == 0) { if (psm) { PatchSet * ps = get_patch_set(datebuff, logbuff, authbuff, psm->post_rev->branch, psm); patch_set_add_member(ps, psm); } logbuff[0] = 0; loglen = 0; have_log = 0; state = NEED_REVISION; } else if (strcmp(buff, CVS_FILE_BOUNDARY) == 0) { if (psm) { PatchSet * ps = get_patch_set(datebuff, logbuff, authbuff, psm->post_rev->branch, psm); patch_set_add_member(ps, psm); assign_pre_revision(psm, NULL); } logbuff[0] = 0; loglen = 0; have_log = 0; psm = NULL; file = NULL; state = NEED_FILE; } else { /* other "blahblah: information;" messages can * follow the stuff we pay attention to */ if (have_log || !is_revision_metadata(buff)) { /* if the log buffer is full, that's it. * * Also, read lines (fgets) always have \n in them * which we count on. So if truncation happens, * be careful to put a \n on. * * Buffer has LOG_STR_MAX + 1 for room for \0 if * necessary */ if (loglen < LOG_STR_MAX) { int len = strlen(buff); if (len >= LOG_STR_MAX - loglen) { debug(DEBUG_APPMSG1, "WARNING: maximum log length exceeded, truncating log"); len = LOG_STR_MAX - loglen; buff[len - 1] = '\n'; } debug(DEBUG_STATUS, "appending %s to log", buff); memcpy(logbuff + loglen, buff, len); loglen += len; logbuff[loglen] = 0; have_log = 1; } } else { debug(DEBUG_STATUS, "ignoring unhandled info %s", buff); } } break; } } if (state == NEED_SYMS) { debug(DEBUG_APPERROR, "Error: 'symbolic names' not found in log output."); debug(DEBUG_APPERROR, " Perhaps you should try running with --norc"); exit(1); } if (state != NEED_FILE) { debug(DEBUG_APPERROR, "Error: Log file parsing error. (%d) Use -v to debug", state); exit(1); } if (test_log_file) { fclose(cvsfp); } else if (cvs_direct_ctx) { cvs_rlog_close(cvs_direct_ctx); } else { if (pclose(cvsfp) < 0) { debug(DEBUG_APPERROR, "cvs rlog command exited with error. aborting"); exit(1); } } } static int usage(const char * str1, const char * str2) { if (str1) debug(DEBUG_APPERROR, "\nbad usage: %s %s\n", str1, str2); debug(DEBUG_APPERROR, "Usage: cvsps [-h] [-x] [-u] [-z ] [-g] [-s [,]] "); debug(DEBUG_APPERROR, " [-a ] [-f ] [-d [-d ]] "); debug(DEBUG_APPERROR, " [-b ] [-l ] [-r [-r ]] "); debug(DEBUG_APPERROR, " [-p ] [-v] [-t] [--norc] [--summary-first]"); debug(DEBUG_APPERROR, " [--test-log ] [--bkcvs]"); debug(DEBUG_APPERROR, " [--no-rlog] [--diff-opts