├── stats.h ├── cap.h ├── cache.h ├── list_sort.h ├── cbtcommon ├── inline.h ├── rcsid.h ├── sio.h ├── tcpsocket.h ├── text_util.h ├── hash.h ├── debug.h ├── sio.c ├── list.h ├── debug.c ├── tcpsocket.c ├── text_util.c └── hash.c ├── util.h ├── cvs_direct.h ├── cvsps.h ├── cvsps.spec ├── merge_utils.sh ├── list_sort.c ├── Makefile ├── cap.c ├── stats.c ├── cvsps_types.h ├── util.c ├── cvsps.1 ├── README ├── CHANGELOG ├── cache.c ├── COPYING └── cvs_direct.c /stats.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #ifndef STATS_H 7 | #define STATS_H 8 | 9 | void print_statistics(void * ps_tree); 10 | 11 | #endif /* STATS_H */ 12 | -------------------------------------------------------------------------------- /cap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #ifndef CAP_H 7 | #define CAP_H 8 | 9 | #define CAP_HAVE_RLOG 1 10 | 11 | int cvs_check_cap(int); 12 | 13 | #endif /* CAP_H */ 14 | -------------------------------------------------------------------------------- /cache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #ifndef CACHE_H 7 | #define CACHE_H 8 | 9 | extern time_t read_cache(); 10 | extern void write_cache(time_t); 11 | 12 | #endif /* CACHE_H */ 13 | -------------------------------------------------------------------------------- /list_sort.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #ifndef LIST_SORT_H 7 | #define LIST_SORT_H 8 | 9 | #include 10 | 11 | void list_sort(struct list_head *, int (*)(struct list_head *, struct list_head *)); 12 | 13 | #endif /* LIST_SORT_H */ 14 | -------------------------------------------------------------------------------- /cbtcommon/inline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #ifndef UTIL_INLINE_H 7 | #define UTIL_INLINE_H 8 | 9 | #ifdef __GNUC__ 10 | #define INLINE __inline__ 11 | #endif 12 | 13 | #ifdef WIN32 14 | #define INLINE __inline 15 | #endif 16 | 17 | /* INLINE of last resort... heh */ 18 | 19 | #ifndef INLINE 20 | #define INLINE /* void */ 21 | #endif 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /cbtcommon/rcsid.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #ifndef _COMMON_RCSID_H 7 | #define _COMMON_RCSID_H 8 | 9 | /* RCS Id macro (complements of bod@compusol.com.au (Brendan O'Dea)) */ 10 | #ifdef lint 11 | # define RCSID(i) 12 | #else /* lint */ 13 | # ifdef __GNUC__ 14 | # define ATTRIB_UNUSED __attribute__ ((unused)) 15 | # else /* __GNUC__ */ 16 | # define ATTRIB_UNUSED 17 | # endif /* __GNUC__ */ 18 | # define RCSID(i) static char const *rcsid ATTRIB_UNUSED = (i) 19 | #endif /* lint */ 20 | 21 | #endif /* _COMMON_RCSID_H */ 22 | -------------------------------------------------------------------------------- /cbtcommon/sio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #ifndef _SIO_H 7 | #define _SIO_H 8 | 9 | /* include for typedefs */ 10 | #ifdef WIN32 11 | #include 12 | typedef int ssize_t; 13 | #else 14 | #include 15 | #endif 16 | 17 | #ifdef __cplusplus 18 | extern "C" 19 | { 20 | #endif 21 | /* these are W.R.Stevens' famous io routines to read or write bytes to fd */ 22 | ssize_t readn(int, void *, size_t); 23 | ssize_t writen(int, const void *, size_t); 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | 29 | #endif /* _SIO_H */ 30 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #ifndef UTIL_H 7 | #define UTIL_H 8 | 9 | #define CVSPS_PREFIX ".cvsps" 10 | 11 | #ifndef PATH_MAX 12 | #define PATH_MAX 4096 13 | #endif 14 | 15 | char *xstrdup(char const *); 16 | void strzncpy(char * dst, const char * src, int n); 17 | char *readfile(char const *filename, char *buf, size_t size); 18 | char *strrep(char *s, char find, char replace); 19 | char *get_cvsps_dir(); 20 | char *get_string(char const *str); 21 | void convert_date(time_t *, const char *); 22 | void timing_start(); 23 | void timing_stop(const char *); 24 | int my_system(const char *); 25 | int escape_filename(char *, int, const char *); 26 | 27 | #endif /* UTIL_H */ 28 | -------------------------------------------------------------------------------- /cbtcommon/tcpsocket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #ifndef _TCPSOCKET_H 7 | #define _TCPSOCKET_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" 11 | { 12 | #endif 13 | 14 | #ifndef LISTEN_QUEUE_SIZE 15 | #define LISTEN_QUEUE_SIZE 5 16 | #endif 17 | 18 | #define REUSE_ADDR 1 19 | #define NO_REUSE_ADDR 0 20 | 21 | int tcp_create_socket(int reuse_addr); 22 | int tcp_bind_and_listen(int sockfd, unsigned short tcpport); 23 | int tcp_accept_connection(int sockfd); 24 | unsigned int tcp_get_client_ip(int fd); 25 | int tcp_connect(int sockfd, const char *rem_addr, unsigned short port); 26 | int convert_address(long *dest, const char *addr_str); 27 | int tcp_get_local_address(int sockfd, unsigned int *, unsigned short *); 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #endif /* TCPSOCKET_H */ 34 | -------------------------------------------------------------------------------- /cvs_direct.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #ifndef CVS_DIRECT_H 7 | #define CVS_DIRECT_H 8 | 9 | #ifndef HAVE_CVSSERVERCTX_DEF 10 | #define HAVE_CVSSERVERCTX_DEF 11 | typedef struct _CvsServerCtx CvsServerCtx; 12 | #endif 13 | 14 | CvsServerCtx * open_cvs_server(char * root, int); 15 | void close_cvs_server(CvsServerCtx*); 16 | void cvs_rdiff(CvsServerCtx *, const char *, const char *, const char *, const char *); 17 | void cvs_rupdate(CvsServerCtx *, const char *, const char *, const char *, int, const char *); 18 | void cvs_diff(CvsServerCtx *, const char *, const char *, const char *, const char *, const char *); 19 | FILE * cvs_rlog_open(CvsServerCtx *, const char *, const char *); 20 | char * cvs_rlog_fgets(char *, int, CvsServerCtx *); 21 | void cvs_rlog_close(CvsServerCtx *); 22 | void cvs_version(CvsServerCtx *, char *, char *); 23 | 24 | #endif /* CVS_DIRECT_H */ 25 | -------------------------------------------------------------------------------- /cvsps.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #ifndef CVSPS_H 7 | #define CVSPS_H 8 | 9 | #ifndef HAVE_CVSSERVERCTX_DEF 10 | #define HAVE_CVSSERVERCTX_DEF 11 | typedef struct _CvsServerCtx CvsServerCtx; 12 | #endif 13 | 14 | #ifndef PATH_MAX 15 | #define PATH_MAX 4096 16 | #endif 17 | 18 | extern struct hash_table * file_hash; 19 | extern const char * tag_flag_descr[]; 20 | extern CvsServerCtx * cvs_direct_ctx; 21 | extern char root_path[]; 22 | extern char repository_path[]; 23 | 24 | CvsFile * create_cvsfile(); 25 | CvsFileRevision * cvs_file_add_revision(CvsFile *, const char *); 26 | void cvs_file_add_symbol(CvsFile * file, const char * rev, const char * tag); 27 | char * cvs_file_add_branch(CvsFile *, const char *, const char *); 28 | PatchSet * get_patch_set(const char *, const char *, const char *, const char *, PatchSetMember *); 29 | PatchSetMember * create_patch_set_member(); 30 | CvsFileRevision * file_get_revision(CvsFile *, const char *); 31 | void patch_set_add_member(PatchSet * ps, PatchSetMember * psm); 32 | void walk_all_patch_sets(void (*action)(PatchSet *)); 33 | 34 | #endif /* CVSPS_H */ 35 | -------------------------------------------------------------------------------- /cbtcommon/text_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | /** 7 | * Copyright (c) 1998 Cobite, Inc. All Rights Reserved. 8 | * @author Karl LaRocca 9 | * @created Fri Nov 6 14:48:04 1998 10 | * @version $Revision: 1.4 $$Date: 2001/10/25 18:36:11 $ 11 | */ 12 | #ifndef _TEXT_UTIL_H 13 | #define _TEXT_UTIL_H 14 | 15 | #ifdef __cplusplus 16 | extern "C" 17 | { 18 | #endif 19 | 20 | char* chop( char* src ); 21 | char* digits( char* src ); 22 | char* lower_case( char* src ); 23 | char* reverse( char* src ); 24 | char* trim( char* src ); 25 | void trim_zeros_after_decimal( char* src ); 26 | char* upper_case( char* src ); 27 | int strrcmp( const char* haystack, const char* needle ); 28 | 29 | const char* cents2money( long cents ); 30 | long money2cents( const char* money ); 31 | 32 | // these two allocate returned memory, so be sure to free it... 33 | char* frobstr( char* src ); 34 | char* unfrobstr( char* src ); 35 | 36 | void str2hex( char* dest, const char* src, int slen ); 37 | void hex2str( char* dest, const char* src, int slen ); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | #endif /* _TEXT_UTIL_H */ 44 | -------------------------------------------------------------------------------- /cvsps.spec: -------------------------------------------------------------------------------- 1 | Version: 2.1 2 | Summary: CVSps is a program for generating 'patchset' information from a CVS repository 3 | Name: cvsps 4 | Release: 1 5 | URL: http://www.cobite.com/cvsps/ 6 | Source0: %{name}-%{version}.tar.gz 7 | License: GPL 8 | Group: Development/Tools 9 | BuildRoot: %{_tmppath}/%{name}-root 10 | prefix: /usr 11 | 12 | %description 13 | CVSps is a program for generating 'patchset' information from a CVS 14 | repository. A patchset in this case is defined as a set of changes 15 | made to a collection of files, and all committed at the same time 16 | (using a single 'cvs commit' command). This information is valuable to 17 | seeing the big picture of the evolution of a cvs project. While cvs 18 | tracks revision information, it is often difficult to see what changes 19 | were committed 'atomically' to the repository. 20 | 21 | %prep 22 | %setup -q 23 | 24 | %build 25 | make 26 | 27 | %install 28 | rm -rf $RPM_BUILD_ROOT 29 | %makeinstall 30 | 31 | %clean 32 | rm -rf $RPM_BUILD_ROOT 33 | 34 | %files 35 | %defattr(-,root,root) 36 | %doc README CHANGELOG COPYING 37 | %{prefix}/bin/cvsps 38 | %{prefix}/man/man*/* 39 | 40 | %changelog 41 | * Tue Apr 1 2002 David Mansfield 42 | - (no really - not April fools joke) 43 | - revise spec file from Jan 44 | - merge Makefile changes 45 | * Tue Mar 5 2002 Jan IVEN 46 | - Initial build. 47 | 48 | 49 | -------------------------------------------------------------------------------- /merge_utils.sh: -------------------------------------------------------------------------------- 1 | ################################################## 2 | # utility bash functions to help with merging # 3 | ################################################## 4 | # copyright 2003 David Mansfield # 5 | ################################################## 6 | # usage: . merge_utils.sh # 7 | ################################################## 8 | 9 | # 10 | # show patchset 11 | # 12 | function sps() { 13 | less $PATCHSETDIR/$1.patch 14 | } 15 | 16 | # 17 | # test apply patchset 18 | # 19 | function tps() { 20 | cat $PATCHSETDIR/$1.patch | patch -p1 --dry-run 21 | } 22 | 23 | # 24 | # apply patchset 25 | # 26 | function aps() { 27 | cat $PATCHSETDIR/$1.patch | patch -p1 28 | } 29 | 30 | # 31 | # commit changes as merge of patchset. 32 | # 33 | function cps() { 34 | LOGMSG=`cat $PATCHSETDIR/$1.patch | perl -e '$line = 0; while(<>) { 35 | if ($line == 1) { if (/PatchSet ([[:digit:]]*)/) { $ps = $1; }} 36 | if ($line == 2) { if (/Date: (.*)/) { $dt = $1; }} 37 | if ($line == 4) { if (/Branch: (.*)/) { $br = $1; }} 38 | if ($line == 7) { $lg = $_; chop($lg) } 39 | $line++; 40 | } 41 | print "Merge ps:$ps date:$dt branch:$br log:$lg\n"; 42 | '` 43 | echo Committing with log message "'$LOGMSG'" 44 | if [ "$2" != "-n" ] 45 | then 46 | cvs commit -m"$LOGMSG" 47 | fi 48 | } 49 | 50 | echo "Don't forget to set \$PATCHSETDIR to the directory where you patchset diffs are" 51 | -------------------------------------------------------------------------------- /cbtcommon/hash.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #ifndef _COMMON_HASH_H 7 | #define _COMMON_HASH_H 8 | 9 | #include "list.h" 10 | 11 | struct hash_entry 12 | { 13 | char *he_key; 14 | void *he_obj; 15 | struct list_head he_list; 16 | }; 17 | 18 | struct hash_table 19 | { 20 | int ht_size; 21 | struct list_head *ht_lists; 22 | int iterator; 23 | struct list_head *iterator_ptr; 24 | }; 25 | 26 | enum 27 | { 28 | HT_NO_KEYCOPY, 29 | HT_KEYCOPY 30 | }; 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | struct hash_table *create_hash_table(unsigned int sz); 37 | void destroy_hash_table(struct hash_table *tbl, void (*delete_obj)(void *)); 38 | void *put_hash_object(struct hash_table *tbl, const char *key, void *obj); 39 | void *get_hash_object(struct hash_table *tbl, const char *key); 40 | void *remove_hash_object(struct hash_table *tbl, const char *key); 41 | 42 | int put_hash_object_ex(struct hash_table *tbl, const char *key, void *obj, int, char **, void **); 43 | void destroy_hash_table_ex(struct hash_table *tbl, void (*delete_entry)(const void *, char *, void *), const void *); 44 | 45 | void reset_hash_iterator(struct hash_table *tbl); 46 | struct hash_entry *next_hash_entry(struct hash_table *tbl); 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif 51 | 52 | #endif /* _COMMON_HASH_H */ 53 | -------------------------------------------------------------------------------- /list_sort.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #include 7 | #include 8 | #include "list_sort.h" 9 | 10 | void list_sort(struct list_head * list, int (*node_compare)(struct list_head *, struct list_head *)) 11 | { 12 | struct list_head *p, *q, *t; 13 | struct list_head tmp; 14 | int merges = 0; 15 | int k = 1; 16 | int psize, qsize; 17 | 18 | if (list_empty(list)) 19 | return; 20 | 21 | do 22 | { 23 | INIT_LIST_HEAD(&tmp); 24 | p = list->next; 25 | merges = 0; 26 | psize = qsize = 0; 27 | 28 | while (p != list) 29 | { 30 | merges++; 31 | q = p; 32 | 33 | while (q != list && psize < k) 34 | { 35 | q = q->next; 36 | psize++; 37 | } 38 | 39 | qsize = k; 40 | 41 | while (psize || (qsize && q != list)) 42 | { 43 | if (psize && (qsize == 0 || q == list || node_compare(p, q) <= 0)) 44 | { 45 | t = p; 46 | p = p->next; 47 | psize--; 48 | } 49 | else if (qsize == 0) 50 | { 51 | printf("whoaa. qsize is zero\n"); 52 | exit (1); 53 | } 54 | else 55 | { 56 | t = q; 57 | q = q->next; 58 | qsize--; 59 | } 60 | 61 | list_del(t); 62 | 63 | list_add(t, tmp.prev); 64 | } 65 | 66 | p = q; 67 | } 68 | 69 | if (!list_empty(list)) 70 | { 71 | printf("whoaa. initial list not empty\n"); 72 | exit (1); 73 | } 74 | 75 | list_splice(&tmp, list); 76 | k *= 2; 77 | 78 | //printf("done w sort pass %d %d\n", k, merges); 79 | } 80 | while (merges > 1); 81 | } 82 | 83 | -------------------------------------------------------------------------------- /cbtcommon/debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #ifndef _DEBUG_H 7 | #define _DEBUG_H 8 | 9 | #include 10 | #include 11 | #ifndef MACINTOSH 12 | #include 13 | #endif 14 | 15 | #include "inline.h" 16 | 17 | #define DEBUG_NUM_FACILITIES 32 /* should be 64 on 64bit CPU... */ 18 | #define DEBUG_SYSERROR 1 /* same as DEBUG_ERROR, but here for clarity */ 19 | #define DEBUG_ERROR 1 20 | #define DEBUG_STATUS 2 21 | #define DEBUG_TCP 4 22 | #define DEBUG_SIGNALS 8 23 | #define DEBUG_APPERROR 16 24 | #define DEBUG_APPMSG1 32 25 | #define DEBUG_APPMSG2 64 26 | #define DEBUG_APPMSG3 128 27 | #define DEBUG_APPMSG4 256 28 | #define DEBUG_APPMSG5 512 29 | #define DEBUG_LIBERROR 1024 30 | #define DEBUG_LIBSTATUS 2048 31 | 32 | #ifdef __cplusplus 33 | extern "C" 34 | { 35 | #endif 36 | 37 | extern unsigned int debuglvl; 38 | 39 | void hexdump( const char *ptr, int size, const char *fmt, ... ); 40 | void vdebug(int dtype, const char *fmt, va_list); 41 | void vmdebug(int dtype, const char *fmt, va_list); 42 | void to_hex( char* dest, const char* src, size_t n ); 43 | void debug_set_error_file(FILE *); 44 | void debug_set_error_facility(int mask, FILE *); 45 | 46 | static INLINE void debug(unsigned int dtype, const char *fmt, ...) 47 | { 48 | va_list ap; 49 | 50 | if (!(debuglvl & dtype)) 51 | return; 52 | 53 | va_start(ap, fmt); 54 | vdebug(dtype, fmt, ap); 55 | va_end(ap); 56 | } 57 | 58 | static INLINE void mdebug(unsigned int dtype, const char *fmt, ...) 59 | { 60 | va_list ap; 61 | 62 | if (!(debuglvl & dtype)) 63 | return; 64 | 65 | va_start(ap, fmt); 66 | vmdebug(dtype, fmt, ap); 67 | va_end(ap); 68 | } 69 | 70 | #ifdef __cplusplus 71 | } 72 | #endif 73 | 74 | 75 | #endif /* DEBUG_H */ 76 | -------------------------------------------------------------------------------- /cbtcommon/sio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #include 7 | 8 | #ifdef WIN32 9 | #include 10 | #else 11 | #include 12 | #endif 13 | 14 | #include 15 | 16 | #include "sio.h" 17 | #include "rcsid.h" 18 | 19 | RCSID("$Id: sio.c,v 1.5 2001/10/25 18:36:11 adam Exp $"); 20 | 21 | ssize_t readn(int fd, void *buf, size_t len) 22 | { 23 | 24 | int nleft,nread; 25 | 26 | nleft = len; 27 | 28 | while (nleft > 0) 29 | { 30 | nread = read(fd,buf,nleft); 31 | 32 | /* there is an issue which EINTR which could leave us a bit haywire 33 | * if we get a signal after having read some bytes. special handling 34 | * N.B: we *do* return EINTR if no data has been read yet (thanks Karl) 35 | */ 36 | if (nread < 0) 37 | { 38 | if (errno == EINTR && nleft != (int)len) 39 | continue; 40 | else 41 | return (nread); 42 | } 43 | else if (nread == 0) 44 | break; 45 | 46 | nleft -= nread; 47 | 48 | if (nleft) 49 | buf = ((char *)buf) + nread; 50 | } 51 | return (len - nleft); 52 | } 53 | 54 | ssize_t writen(int fd, const void *buf, size_t len) 55 | { 56 | 57 | int nleft, nwritten; 58 | 59 | nleft = len; 60 | 61 | while (nleft > 0) 62 | { 63 | nwritten = write(fd,buf,nleft); 64 | 65 | /* there is an issue with EINTR if we have already written 66 | a few bytes! return if we have not written any yet */ 67 | if (nwritten < 0 && errno == EINTR) 68 | { 69 | if (nleft == (int)len) 70 | return nwritten; 71 | 72 | continue; 73 | } 74 | 75 | 76 | if (nwritten <= 0) 77 | return nwritten; 78 | 79 | nleft -= nwritten; 80 | 81 | if (nleft) 82 | buf = ((char *)buf) + nwritten; 83 | } 84 | 85 | return (len - nleft); 86 | } 87 | 88 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | MAJOR=2 2 | MINOR=1 3 | CC?=gcc 4 | CFLAGS?=-g -O2 -Wall 5 | CPPFLAGS?=-I. -DVERSION=\"$(MAJOR).$(MINOR)\" 6 | prefix?=/usr/local 7 | OBJS=\ 8 | cbtcommon/debug.o\ 9 | cbtcommon/hash.o\ 10 | cbtcommon/text_util.o\ 11 | cbtcommon/sio.o\ 12 | cbtcommon/tcpsocket.o\ 13 | cvsps.o\ 14 | cache.o\ 15 | util.o\ 16 | stats.o\ 17 | cap.o\ 18 | cvs_direct.o\ 19 | list_sort.o 20 | 21 | all: cvsps 22 | 23 | deps: 24 | makedepend -Y -I. *.c cbtcommon/*.c 25 | 26 | cvsps: $(OBJS) 27 | $(CC) -o cvsps $(OBJS) -lz 28 | 29 | install: 30 | [ -d $(prefix)/bin ] || mkdir -p $(prefix)/bin 31 | [ -d $(prefix)/share/man/man1 ] || mkdir -p $(prefix)/share/man/man1 32 | install cvsps $(prefix)/bin 33 | install -m 644 cvsps.1 $(prefix)/share/man/man1 34 | 35 | clean: 36 | rm -f cvsps *.o cbtcommon/*.o core 37 | 38 | .PHONY: install clean 39 | # DO NOT DELETE 40 | 41 | cache.o: ./cbtcommon/hash.h ./cbtcommon/list.h ./cbtcommon/inline.h 42 | cache.o: ./cbtcommon/debug.h cache.h cvsps_types.h cvsps.h util.h 43 | cap.o: ./cbtcommon/debug.h ./cbtcommon/inline.h ./cbtcommon/text_util.h cap.h 44 | cap.o: cvs_direct.h 45 | cvs_direct.o: ./cbtcommon/debug.h ./cbtcommon/inline.h 46 | cvs_direct.o: ./cbtcommon/text_util.h ./cbtcommon/tcpsocket.h 47 | cvs_direct.o: ./cbtcommon/sio.h cvs_direct.h util.h 48 | cvsps.o: ./cbtcommon/hash.h ./cbtcommon/list.h ./cbtcommon/inline.h 49 | cvsps.o: ./cbtcommon/list.h ./cbtcommon/text_util.h ./cbtcommon/debug.h 50 | cvsps.o: ./cbtcommon/rcsid.h cache.h cvsps_types.h cvsps.h util.h stats.h 51 | cvsps.o: cap.h cvs_direct.h list_sort.h 52 | list_sort.o: list_sort.h ./cbtcommon/list.h 53 | stats.o: ./cbtcommon/hash.h ./cbtcommon/list.h ./cbtcommon/inline.h 54 | stats.o: cvsps_types.h cvsps.h 55 | util.o: ./cbtcommon/debug.h ./cbtcommon/inline.h util.h 56 | cbtcommon/debug.o: cbtcommon/debug.h ./cbtcommon/inline.h cbtcommon/rcsid.h 57 | cbtcommon/hash.o: cbtcommon/debug.h ./cbtcommon/inline.h cbtcommon/hash.h 58 | cbtcommon/hash.o: ./cbtcommon/list.h cbtcommon/rcsid.h 59 | cbtcommon/sio.o: cbtcommon/sio.h cbtcommon/rcsid.h 60 | cbtcommon/tcpsocket.o: cbtcommon/tcpsocket.h cbtcommon/debug.h 61 | cbtcommon/tcpsocket.o: ./cbtcommon/inline.h cbtcommon/rcsid.h 62 | cbtcommon/text_util.o: cbtcommon/text_util.h cbtcommon/rcsid.h 63 | -------------------------------------------------------------------------------- /cbtcommon/list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #ifndef _COMMON_LIST_H 7 | #define _COMMON_LIST_H 8 | 9 | /* 10 | * Stolen from linux-2.1.131 11 | * All comments from the original source unless otherwise noted 12 | * Added: the CLEAR_LIST_NODE macro 13 | */ 14 | 15 | /* 16 | * Simple doubly linked list implementation. 17 | * 18 | * Some of the internal functions ("__xxx") are useful when 19 | * manipulating whole lists rather than single entries, as 20 | * sometimes we already know the next/prev entries and we can 21 | * generate better code by using them directly rather than 22 | * using the generic single-entry routines. 23 | */ 24 | 25 | #include "inline.h" 26 | 27 | struct list_head { 28 | struct list_head *next, *prev; 29 | }; 30 | 31 | #define LIST_HEAD(name) \ 32 | struct list_head name = { &name, &name } 33 | 34 | #define INIT_LIST_HEAD(ptr) do { \ 35 | (ptr)->next = (ptr); (ptr)->prev = (ptr); \ 36 | } while (0) 37 | 38 | #define CLEAR_LIST_NODE(ptr) do { \ 39 | (ptr)->next = NULL; (ptr)->prev = NULL; \ 40 | } while (0) 41 | 42 | /* 43 | * Insert a new entry between two known consecutive entries. 44 | * 45 | * This is only for internal list manipulation where we know 46 | * the prev/next entries already! 47 | */ 48 | static INLINE void __list_add(struct list_head *li, 49 | struct list_head * prev, 50 | struct list_head * next) 51 | { 52 | next->prev = li; 53 | li->next = next; 54 | li->prev = prev; 55 | prev->next = li; 56 | } 57 | 58 | /* 59 | * Insert a new entry after the specified head.. 60 | */ 61 | static INLINE void list_add(struct list_head *li, struct list_head *head) 62 | { 63 | __list_add(li, head, head->next); 64 | } 65 | 66 | /* 67 | * Delete a list entry by making the prev/next entries 68 | * point to each other. 69 | * 70 | * This is only for internal list manipulation where we know 71 | * the prev/next entries already! 72 | */ 73 | static INLINE void __list_del(struct list_head * prev, 74 | struct list_head * next) 75 | { 76 | next->prev = prev; 77 | prev->next = next; 78 | } 79 | 80 | static INLINE void list_del(struct list_head *entry) 81 | { 82 | __list_del(entry->prev, entry->next); 83 | } 84 | 85 | static INLINE int list_empty(struct list_head *head) 86 | { 87 | return head->next == head; 88 | } 89 | 90 | /* 91 | * Splice in "list" into "head" 92 | */ 93 | static INLINE void list_splice(struct list_head *list, struct list_head *head) 94 | { 95 | struct list_head *first = list->next; 96 | 97 | if (first != list) { 98 | struct list_head *last = list->prev; 99 | struct list_head *at = head->next; 100 | 101 | first->prev = head; 102 | head->next = first; 103 | 104 | last->next = at; 105 | at->prev = last; 106 | } 107 | } 108 | 109 | #define list_entry(ptr, type, member) \ 110 | ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) 111 | 112 | #endif /* _COMMON_LIST_H */ 113 | -------------------------------------------------------------------------------- /cap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "cap.h" 14 | #include "cvs_direct.h" 15 | 16 | extern CvsServerCtx * cvs_direct_ctx; 17 | 18 | static char client_version[BUFSIZ]; 19 | static char server_version[BUFSIZ]; 20 | 21 | static int check_cvs_version(int, int, int); 22 | static int check_version_string(const char *, int, int, int); 23 | 24 | int cvs_check_cap(int cap) 25 | { 26 | int ret; 27 | 28 | switch(cap) 29 | { 30 | case CAP_HAVE_RLOG: 31 | if (!(ret = check_cvs_version(1,11,1))) 32 | { 33 | debug(DEBUG_APPERROR, 34 | "WARNING: Your CVS client version:\n[%s]\n" 35 | "and/or server version:\n[%s]\n" 36 | "are too old to properly support the rlog command. \n" 37 | "This command was introduced in 1.11.1. Cvsps\n" 38 | "will use log instead, but PatchSet numbering\n" 39 | "may become unstable due to pruned empty\n" 40 | "directories.\n", client_version, server_version); 41 | } 42 | break; 43 | 44 | default: 45 | debug(DEBUG_APPERROR, "unknown cvs capability check %d", cap); 46 | exit(1); 47 | } 48 | 49 | return ret; 50 | } 51 | 52 | static void get_version_external() 53 | { 54 | FILE * cvsfp; 55 | 56 | strcpy(client_version, "(UNKNOWN CLIENT)"); 57 | strcpy(server_version, "(UNKNOWN SERVER)"); 58 | 59 | if (!(cvsfp = popen("cvs version 2>/dev/null", "r"))) 60 | { 61 | debug(DEBUG_APPERROR, "cannot popen cvs version. exiting"); 62 | exit(1); 63 | } 64 | 65 | if (!fgets(client_version, BUFSIZ, cvsfp)) 66 | { 67 | debug(DEBUG_APPMSG1, "WARNING: malformed CVS version: no data"); 68 | goto out; 69 | } 70 | 71 | chop(client_version); 72 | 73 | if (strncmp(client_version, "Client", 6) == 0) 74 | { 75 | if (!fgets(server_version, BUFSIZ, cvsfp)) 76 | { 77 | debug(DEBUG_APPMSG1, "WARNING: malformed CVS version: no server data"); 78 | goto out; 79 | } 80 | chop(server_version); 81 | } 82 | else 83 | { 84 | server_version[0] = 0; 85 | } 86 | 87 | out: 88 | pclose(cvsfp); 89 | } 90 | 91 | int check_cvs_version(int req_major, int req_minor, int req_extra) 92 | { 93 | if (!client_version[0]) 94 | { 95 | if (cvs_direct_ctx) 96 | cvs_version(cvs_direct_ctx, client_version, server_version); 97 | else 98 | get_version_external(); 99 | } 100 | 101 | return (check_version_string(client_version, req_major, req_minor, req_extra) && 102 | (!server_version[0] || check_version_string(server_version, req_major, req_minor, req_extra))); 103 | } 104 | 105 | int check_version_string(const char * str, int req_major, int req_minor, int req_extra) 106 | { 107 | char * p; 108 | int major, minor, extra; 109 | int skip = 6; 110 | 111 | p = strstr(str, "(CVS) "); 112 | 113 | if (!p) { 114 | p = strstr(str, "(CVSNT)"); 115 | skip = 8; 116 | } 117 | 118 | if (!p) 119 | { 120 | debug(DEBUG_APPMSG1, "WARNING: malformed CVS version str: %s", str); 121 | return 0; 122 | } 123 | 124 | /* We might have encountered a FreeBSD system which 125 | * has a mucked up version string of: 126 | * Concurrent Versions System (CVS) '1.11.17'-FreeBSD (client/server) 127 | * so re-test just in case 128 | */ 129 | p += skip; 130 | if (sscanf(p, "%d.%d.%d", &major, &minor, &extra) != 3) 131 | { 132 | if (sscanf(p, "'%d.%d.%d'", &major, &minor, &extra) != 3) 133 | { 134 | debug(DEBUG_APPMSG1, "WARNING: malformed CVS version: %s", str); 135 | return 0; 136 | } 137 | } 138 | 139 | return (major > req_major || 140 | (major == req_major && minor > req_minor) || 141 | (major == req_major && minor == req_minor && extra >= req_extra)); 142 | } 143 | 144 | -------------------------------------------------------------------------------- /cbtcommon/debug.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "debug.h" 13 | #include "rcsid.h" 14 | 15 | #ifdef _WIN32 16 | #include 17 | #endif 18 | 19 | RCSID("$Id: debug.c,v 1.14 2001/11/29 00:00:30 amb Exp $"); 20 | 21 | unsigned int debuglvl = ~0; 22 | static FILE *debug_output_channel[DEBUG_NUM_FACILITIES]; 23 | 24 | #ifdef MACINTOSH 25 | int ffs( int val ) 26 | { 27 | int i = 0; 28 | for( i = 0; i < 32; i++ ) 29 | { 30 | if( val & ( 1 << i ) ) 31 | return i+1; 32 | } 33 | return 0; 34 | } 35 | #endif 36 | 37 | void vdebug(int dtype, const char *fmt, va_list ap) 38 | { 39 | int keep_errno; 40 | char msgbuff[8192]; 41 | 42 | /* errno could be changed by vsprintf or perror */ 43 | keep_errno = errno; 44 | 45 | if (debuglvl & dtype) 46 | { 47 | FILE * channel = debug_output_channel[ffs(dtype)]; 48 | 49 | if (!channel) 50 | channel = stderr; 51 | 52 | #ifdef MACINTOSH 53 | vsprintf(msgbuff, fmt, ap); 54 | #else 55 | vsnprintf(msgbuff, sizeof(msgbuff), fmt, ap); 56 | #endif 57 | 58 | /* DEBUG_ERROR (aka DEBUG_SYSERROR) */ 59 | if (dtype == DEBUG_ERROR) 60 | { 61 | const char * errmsg = ""; 62 | 63 | #ifndef MACINTOSH 64 | errmsg = strerror(errno); 65 | #endif 66 | 67 | fprintf(channel, "%s: %s\n", msgbuff, errmsg); 68 | } 69 | else 70 | fprintf(channel, "%s\n", msgbuff); 71 | 72 | fflush(channel); 73 | #ifdef _WIN32 74 | if (dtype == DEBUG_SYSERROR || dtype == DEBUG_APPERROR) 75 | MessageBox(NULL, msgbuff, "Application Error", MB_OK); 76 | #endif 77 | } 78 | 79 | errno = keep_errno; 80 | } 81 | 82 | void vmdebug(int dtype, const char * fmt, va_list ap) 83 | { 84 | FILE * chn[DEBUG_NUM_FACILITIES]; 85 | int i; 86 | 87 | memcpy(chn, debug_output_channel, sizeof(FILE*) * DEBUG_NUM_FACILITIES); 88 | 89 | for (i = 0; i < DEBUG_NUM_FACILITIES; i++) 90 | if (chn[i] == NULL) 91 | chn[i] = stderr; 92 | 93 | for (i = 0; i < DEBUG_NUM_FACILITIES; i++) 94 | { 95 | if ((dtype & (1 << i)) && chn[i]) 96 | { 97 | 98 | if (debuglvl & (1 << i)) 99 | { 100 | int j; 101 | 102 | vdebug(1 << i, fmt, ap); 103 | 104 | for (j = i + 1; j < DEBUG_NUM_FACILITIES; j++) 105 | if (chn[j] == chn[i]) 106 | chn[j] = NULL; 107 | } 108 | } 109 | } 110 | } 111 | 112 | /* FIXME: use actual debug output core routine vdebug... */ 113 | void hexdump(const char *ptr, int size, const char *fmt, ...) 114 | { 115 | static char hexbuff[49]; 116 | static char printbuff[17]; 117 | int count = 0; 118 | va_list ap; 119 | 120 | if ( !debuglvl & DEBUG_STATUS ) 121 | return; 122 | 123 | va_start(ap, fmt); 124 | 125 | /* print the heading/banner */ 126 | vdebug(DEBUG_STATUS, fmt, ap); 127 | 128 | memset(hexbuff, 0, 49); 129 | memset(printbuff, 0, 17); 130 | 131 | while (size--) 132 | { 133 | sprintf(hexbuff + (count*3), "%02x ", (int)*((unsigned char *)ptr)); 134 | 135 | if (isprint(*ptr)) 136 | printbuff[count] = *ptr; 137 | else 138 | printbuff[count] = '.'; 139 | 140 | ptr++; 141 | 142 | if ( count++ == 15 ) 143 | { 144 | count = 0; 145 | debug(DEBUG_STATUS, "%s %s", hexbuff, printbuff); 146 | memset(hexbuff, 0, 49); 147 | memset(printbuff, 0, 17); 148 | } 149 | } 150 | 151 | if ( count > 0 ) { 152 | while ( count % 16 != 0 ) { 153 | sprintf(hexbuff + (count * 3), "xx "); 154 | printbuff[count++] = '.'; 155 | } 156 | debug(DEBUG_STATUS, "%s %s", hexbuff, printbuff); 157 | } 158 | 159 | va_end(ap); 160 | } 161 | 162 | void 163 | to_hex( char* dest, const char* src, size_t n ) 164 | { 165 | while ( n-- ) 166 | { 167 | sprintf( dest, "%02x ", (int)*((unsigned char *)src)); 168 | dest += 3; 169 | src++; 170 | } 171 | 172 | *dest = 0; 173 | } 174 | 175 | void debug_set_error_file(FILE *f) 176 | { 177 | int i; 178 | for (i = 0; i < DEBUG_NUM_FACILITIES; i++) 179 | debug_output_channel[i] = f; 180 | } 181 | 182 | void debug_set_error_facility(int fac, FILE * f) 183 | { 184 | int i; 185 | 186 | for (i = 0; i < DEBUG_NUM_FACILITIES; i++) 187 | if (!debug_output_channel[i]) 188 | debug_output_channel[i] = stderr; 189 | 190 | debug_output_channel[ffs(fac)] = f; 191 | } 192 | -------------------------------------------------------------------------------- /stats.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "cvsps_types.h" 12 | #include "cvsps.h" 13 | 14 | static unsigned int num_patch_sets = 0; 15 | static unsigned int num_ps_member = 0, max_ps_member_in_ps = 0; 16 | static unsigned int num_authors = 0, max_author_len = 0, total_author_len = 0; 17 | static unsigned int max_descr_len = 0, total_descr_len = 0; 18 | struct hash_table *author_hash; 19 | 20 | static void count_hash(struct hash_table *hash, unsigned int *total, 21 | unsigned int *max_val) 22 | { 23 | int counter = 0; 24 | struct hash_entry *fh; 25 | 26 | reset_hash_iterator(hash); 27 | while ((fh = next_hash_entry(hash))) 28 | counter++; 29 | 30 | *total += counter; 31 | *max_val= MAX(*max_val, counter); 32 | } 33 | 34 | static void stat_ps_tree_node(const void * nodep, const VISIT which, const int depth) 35 | { 36 | int desc_len; 37 | PatchSet * ps; 38 | struct list_head * next; 39 | int counter; 40 | void * old; 41 | 42 | /* Make sure we have it if we do statistics */ 43 | if (!author_hash) 44 | author_hash = create_hash_table(1023); 45 | 46 | switch(which) 47 | { 48 | case postorder: 49 | case leaf: 50 | ps = *(PatchSet**)nodep; 51 | num_patch_sets++; 52 | 53 | old = NULL; 54 | 55 | /* Author statistics */ 56 | if (put_hash_object_ex(author_hash, ps->author, ps->author, HT_NO_KEYCOPY, NULL, &old) >= 0 && !old) 57 | { 58 | int len = strlen(ps->author); 59 | num_authors++; 60 | max_author_len = MAX(max_author_len, len); 61 | total_author_len += len; 62 | } 63 | 64 | /* Log message statistics */ 65 | desc_len = strlen(ps->descr); 66 | max_descr_len = MAX(max_descr_len, desc_len); 67 | total_descr_len += desc_len; 68 | 69 | /* PatchSet member statistics */ 70 | counter = 0; 71 | next = ps->members.next; 72 | while (next != &ps->members) 73 | { 74 | counter++; 75 | next = next->next; 76 | } 77 | 78 | num_ps_member += counter; 79 | max_ps_member_in_ps = MAX(max_ps_member_in_ps, counter); 80 | break; 81 | 82 | default: 83 | break; 84 | } 85 | } 86 | 87 | void print_statistics(void * ps_tree) 88 | { 89 | /* Statistics data */ 90 | unsigned int num_files = 0, max_file_len = 0, total_file_len = 0; 91 | unsigned int total_revisions = 0, max_revisions_for_file = 0; 92 | unsigned int total_branches = 0, max_branches_for_file = 0; 93 | unsigned int total_branches_sym = 0, max_branches_sym_for_file = 0; 94 | 95 | /* Other vars */ 96 | struct hash_entry *he; 97 | 98 | printf("Statistics:\n"); 99 | fflush(stdout); 100 | 101 | /* Gather file statistics */ 102 | reset_hash_iterator(file_hash); 103 | while ((he=next_hash_entry(file_hash))) 104 | { 105 | int len = strlen(he->he_key); 106 | CvsFile *file = (CvsFile *)he->he_obj; 107 | 108 | num_files++; 109 | max_file_len = MAX(max_file_len, len); 110 | total_file_len += len; 111 | 112 | count_hash(file->revisions, &total_revisions, &max_revisions_for_file); 113 | count_hash(file->branches, &total_branches, &max_branches_for_file); 114 | count_hash(file->branches_sym, &total_branches_sym, 115 | &max_branches_sym_for_file); 116 | } 117 | 118 | /* Print file statistics */ 119 | printf("Num files: %d\nMax filename len: %d, Average filename len: %.2f\n", 120 | num_files, max_file_len, (float)total_file_len/num_files); 121 | 122 | printf("Max revisions for file: %d, Average revisions for file: %.2f\n", 123 | max_revisions_for_file, (float)total_revisions/num_files); 124 | printf("Max branches for file: %d, Average branches for file: %.2f\n", 125 | max_branches_for_file, (float)total_branches/num_files); 126 | printf("Max branches_sym for file: %d, Average branches_sym for file: %.2f\n", 127 | max_branches_sym_for_file, (float)total_branches_sym/num_files); 128 | 129 | /* Gather patchset statistics */ 130 | twalk(ps_tree, stat_ps_tree_node); 131 | 132 | /* Print patchset statistics */ 133 | printf("Num patchsets: %d\n", num_patch_sets); 134 | printf("Max PS members in PS: %d\nAverage PS members in PS: %.2f\n", 135 | max_ps_member_in_ps, (float)num_ps_member/num_patch_sets); 136 | printf("Num authors: %d, Max author len: %d, Avg. author len: %.2f\n", 137 | num_authors, max_author_len, (float)total_author_len/num_authors); 138 | printf("Max desc len: %d, Avg. desc len: %.2f\n", 139 | max_descr_len, (float)total_descr_len/num_patch_sets); 140 | } 141 | 142 | -------------------------------------------------------------------------------- /cvsps_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #ifndef CVSPS_TYPES_H 7 | #define CVSPS_TYPES_H 8 | 9 | #include 10 | 11 | #define LOG_STR_MAX 65536 12 | #define AUTH_STR_MAX 64 13 | #define REV_STR_MAX 64 14 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) 15 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) 16 | 17 | typedef struct _CvsFile CvsFile; 18 | typedef struct _PatchSet PatchSet; 19 | typedef struct _PatchSetMember PatchSetMember; 20 | typedef struct _PatchSetRange PatchSetRange; 21 | typedef struct _CvsFileRevision CvsFileRevision; 22 | typedef struct _GlobalSymbol GlobalSymbol; 23 | typedef struct _Tag Tag; 24 | 25 | struct _CvsFileRevision 26 | { 27 | char * rev; 28 | int dead; 29 | CvsFile * file; 30 | char * branch; 31 | /* 32 | * In the cvs cvs repository (ccvs project) there are tagged 33 | * revisions that don't exist. track 'confirmed' revisions 34 | * so as to not let them screw us up. 35 | */ 36 | int present; 37 | 38 | /* 39 | * A revision can be part of many PatchSets because it may 40 | * be the branch point of many branches (as a pre_rev). 41 | * It should, however, be the 'post_rev' of only one 42 | * PatchSetMember. The 'main line of inheritence' is 43 | * kept in pre_psm, and all 'branch revisions' are kept 44 | * in a list. 45 | */ 46 | PatchSetMember * pre_psm; 47 | PatchSetMember * post_psm; 48 | struct list_head branch_children; 49 | 50 | /* 51 | * for linking this 'first branch rev' into the parent branch_children 52 | */ 53 | struct list_head link; 54 | 55 | /* 56 | * A list of all Tag structures tagging this revision 57 | */ 58 | struct list_head tags; 59 | }; 60 | 61 | struct _CvsFile 62 | { 63 | char *filename; 64 | struct hash_table * revisions; /* rev_str to revision [CvsFileRevision*] */ 65 | struct hash_table * branches; /* branch to branch_sym [char*] */ 66 | struct hash_table * branches_sym; /* branch_sym to branch [char*] */ 67 | struct hash_table * symbols; /* tag to revision [CvsFileRevision*] */ 68 | /* 69 | * this is a hack. when we initially create entries in the symbol hash 70 | * we don't have the branch info, so the CvsFileRevisions get created 71 | * with the branch attribute NULL. Later we need to resolve these. 72 | */ 73 | int have_branches; 74 | }; 75 | 76 | struct _PatchSetMember 77 | { 78 | CvsFileRevision * pre_rev; 79 | CvsFileRevision * post_rev; 80 | PatchSet * ps; 81 | CvsFile * file; 82 | /* 83 | * bad_funk is only set w.r.t the -r tags 84 | */ 85 | int bad_funk; 86 | struct list_head link; 87 | }; 88 | 89 | /* 90 | * these are bit flags for tag flags 91 | * they apply to any patchset that 92 | * has an assoctiated tag 93 | */ 94 | #define TAG_FUNKY 0x1 95 | #define TAG_INVALID 0x2 96 | 97 | /* values for funk_factor. they apply 98 | * only to the -r tags, to patchsets 99 | * that have an odd relationship to the 100 | * tag 101 | */ 102 | #define FNK_SHOW_SOME 1 103 | #define FNK_SHOW_ALL 2 104 | #define FNK_HIDE_ALL 3 105 | #define FNK_HIDE_SOME 4 106 | 107 | struct _PatchSet 108 | { 109 | int psid; 110 | time_t date; 111 | time_t min_date; 112 | time_t max_date; 113 | char *descr; 114 | char *author; 115 | char *tag; 116 | int tag_flags; 117 | char *branch; 118 | char *ancestor_branch; 119 | struct list_head members; 120 | /* 121 | * A 'branch add' patch set is a bogus patch set created automatically 122 | * when a 'file xyz was initially added on branch abc' 123 | * we want to ignore these. fortunately, there's a way to detect them 124 | * without resorting to looking at the log message. 125 | */ 126 | int branch_add; 127 | /* 128 | * If the '-r' option specifies a funky tag, we will need to detect the 129 | * PatchSets that come chronologically before the tag, but are logically 130 | * after, and vice-versa if a second -r option was specified 131 | */ 132 | int funk_factor; 133 | 134 | /* for putting onto a list */ 135 | struct list_head all_link; 136 | struct list_head collision_link; 137 | }; 138 | 139 | struct _PatchSetRange 140 | { 141 | int min_counter; 142 | int max_counter; 143 | struct list_head link; 144 | }; 145 | 146 | struct _GlobalSymbol 147 | { 148 | char * tag; 149 | PatchSet * ps; 150 | struct list_head tags; 151 | }; 152 | 153 | struct _Tag 154 | { 155 | GlobalSymbol * sym; 156 | CvsFileRevision * rev; 157 | char * tag; 158 | struct list_head global_link; 159 | struct list_head rev_link; 160 | }; 161 | 162 | #endif /* CVSPS_TYPES_H */ 163 | -------------------------------------------------------------------------------- /cbtcommon/tcpsocket.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #ifdef SOLARIS 7 | #include 8 | #else 9 | #include 10 | #endif 11 | 12 | #ifdef WIN32 13 | #include 14 | #else /* not windows */ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #ifdef SOLARIS 23 | #include 24 | #endif 25 | 26 | #endif /* if windows */ 27 | 28 | #include "tcpsocket.h" 29 | #include "debug.h" 30 | #include "rcsid.h" 31 | #ifdef WIN32 32 | #include "win32fd.h" 33 | #endif 34 | 35 | RCSID("$Id: tcpsocket.c,v 1.6 1999/12/27 20:35:34 david Exp $"); 36 | 37 | int 38 | tcp_create_socket(int reuse_addr) 39 | { 40 | int retval; 41 | int yes = 1; 42 | 43 | if ((retval = socket(AF_INET, SOCK_STREAM, 0)) < 0) 44 | { 45 | debug(DEBUG_ERROR, "tcp: can't create socket"); 46 | } 47 | 48 | if (reuse_addr) 49 | { 50 | setsockopt( retval, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(int)); 51 | } 52 | 53 | debug(DEBUG_TCP, "tcp: socket created"); 54 | #ifdef WIN32 55 | return get_fd(retval, WIN32_SOCKET); 56 | #else 57 | return retval; 58 | #endif 59 | } 60 | 61 | int 62 | tcp_bind_and_listen(int sockfd, unsigned short tcp_port) 63 | { 64 | struct sockaddr_in addr; 65 | 66 | memset((char *) &addr, 0, sizeof(struct sockaddr_in)); 67 | addr.sin_family = AF_INET; 68 | addr.sin_addr.s_addr = htonl(INADDR_ANY); 69 | addr.sin_port = htons(tcp_port); 70 | 71 | #ifdef WIN32 72 | sockfd = win32_file_table[sockfd].win32id; 73 | #endif 74 | 75 | if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) 76 | { 77 | debug(DEBUG_ERROR, "tcp: can't bind to socket"); 78 | return -1; 79 | } 80 | 81 | 82 | if (listen(sockfd, LISTEN_QUEUE_SIZE) < 0) 83 | { 84 | debug(DEBUG_ERROR, "tcp: can't listen on socket"); 85 | return -1; 86 | } 87 | 88 | debug(DEBUG_TCP, "tcp: socket bound and listening"); 89 | 90 | return 0; 91 | } 92 | 93 | int 94 | tcp_accept_connection(int sockfd) 95 | { 96 | struct sockaddr_in remaddr; 97 | int addrlen; 98 | int retval; 99 | 100 | #ifdef WIN32 101 | sockfd = win32_file_table[sockfd].win32id; 102 | #endif 103 | 104 | addrlen = sizeof(struct sockaddr_in); 105 | 106 | #ifdef WIN32 107 | if ((retval = accept(sockfd, (struct sockaddr *) &remaddr, &addrlen)) == INVALID_SOCKET) 108 | { 109 | debug(DEBUG_APPERROR, "tcp: error accepting connection"); 110 | return -1; 111 | } 112 | #else 113 | if ((retval = accept(sockfd, (struct sockaddr *) &remaddr, &addrlen)) < 0) 114 | { 115 | if (errno != EINTR ) 116 | debug(DEBUG_ERROR, "tcp: error accepting connection"); 117 | 118 | return -1; 119 | } 120 | #endif 121 | 122 | debug(DEBUG_TCP, "tcp: got connection (fd=%d)", retval); 123 | 124 | return retval; 125 | } 126 | 127 | unsigned int 128 | tcp_get_client_ip(int fd) 129 | { 130 | struct sockaddr_in remaddr; 131 | int addrlen; 132 | int retval; 133 | unsigned int saddr; 134 | 135 | #ifdef WIN32 136 | fd = win32_file_table[fd].win32id; 137 | #endif 138 | 139 | addrlen = sizeof(struct sockaddr_in); 140 | 141 | if ((retval = getpeername(fd, (struct sockaddr *) &remaddr, &addrlen)) < 0) 142 | { 143 | debug(DEBUG_ERROR, "tcp: error getting remote's ip address"); 144 | return 0; 145 | } 146 | 147 | saddr = ntohl(remaddr.sin_addr.s_addr); 148 | 149 | return saddr; 150 | } 151 | 152 | int 153 | tcp_connect(int sockfd, const char *rem_addr, unsigned short port) 154 | { 155 | struct sockaddr_in addr; 156 | int addrlen; 157 | long ipno; 158 | 159 | #ifdef WIN32 160 | sockfd = win32_file_table[sockfd].win32id; 161 | #endif 162 | 163 | if ( convert_address(&ipno , rem_addr) < 0 ) 164 | { 165 | return -1; 166 | } 167 | 168 | addrlen = sizeof(struct sockaddr_in); 169 | 170 | memset((char *) &addr, 0, sizeof(struct sockaddr_in)); 171 | addr.sin_family = AF_INET; 172 | addr.sin_addr.s_addr = ipno; 173 | addr.sin_port = htons(port); 174 | 175 | if (connect(sockfd, (struct sockaddr *)&addr, addrlen) < 0) 176 | { 177 | debug(DEBUG_ERROR, "connect error"); 178 | return -1; 179 | } 180 | 181 | debug(DEBUG_STATUS, "tcp: connection established on port %d", port); 182 | return 0; 183 | } 184 | 185 | int 186 | convert_address(long *dest, const char *addr_str) 187 | { 188 | #ifdef __linux__ 189 | struct in_addr ip; 190 | #endif 191 | int retval = 0; 192 | char errstr[256]; 193 | 194 | /* first try converting "numbers and dots" notation */ 195 | #ifdef __linux__ 196 | if ( inet_aton(addr_str, &ip) ) 197 | { 198 | memcpy(dest, &ip.s_addr, sizeof(ip.s_addr)); 199 | } 200 | #else 201 | if ( (*dest = inet_addr(addr_str)) != INADDR_NONE) 202 | { 203 | /* nothing */ 204 | } 205 | #endif 206 | else /* if it fails, do a gethostbyname() */ 207 | { 208 | struct hostent *host; 209 | if ((host = gethostbyname(addr_str)) == NULL) 210 | { 211 | switch(h_errno) 212 | { 213 | case HOST_NOT_FOUND: 214 | strcpy(errstr, "HOST_NOT_FOUND"); 215 | break; 216 | 217 | case NO_ADDRESS: 218 | strcpy(errstr, "NO_ADDRESS"); 219 | break; 220 | 221 | case NO_RECOVERY: 222 | strcpy(errstr, "NO_RECOVERY"); 223 | break; 224 | 225 | case TRY_AGAIN: 226 | strcpy(errstr, "TRY_AGAIN"); 227 | break; 228 | } 229 | 230 | debug(DEBUG_ERROR, "gethostbyname failed for %s: ", addr_str, errstr); 231 | 232 | retval = -1; 233 | } 234 | 235 | memcpy(dest, host->h_addr_list[0], sizeof(unsigned long)); 236 | } 237 | 238 | 239 | return retval; 240 | } 241 | 242 | int tcp_get_local_address(int sockfd, unsigned int *ip, unsigned short *port) 243 | { 244 | struct sockaddr_in addr; 245 | int addrlen = sizeof(struct sockaddr_in); 246 | 247 | if(getsockname(sockfd, (struct sockaddr *)&addr, &addrlen) < 0) 248 | { 249 | debug(DEBUG_SYSERROR, "getsockname failed" ); 250 | return -1; 251 | } 252 | 253 | *ip = ntohl( addr.sin_addr.s_addr ); 254 | *port = ntohs( addr.sin_port ); 255 | 256 | return 0; 257 | } 258 | -------------------------------------------------------------------------------- /cbtcommon/text_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | /** 7 | * Copyright (c) 1998 Cobite, Inc. All Rights Reserved. 8 | * @author Karl LaRocca 9 | * @created Fri Nov 6 14:33:29 1998 10 | * @version $Revision: 1.9 $$Date: 2001/10/25 18:36:11 $ 11 | */ 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "text_util.h" 18 | #include "rcsid.h" 19 | 20 | RCSID("$Id: text_util.c,v 1.9 2001/10/25 18:36:11 adam Exp $"); 21 | 22 | char* 23 | chop( char* src ) 24 | { 25 | char* p = src + strlen(src) - 1; 26 | 27 | while( p >= src ) 28 | { 29 | if ( *p == '\n' || *p == '\r' ) 30 | { 31 | *p-- = 0; 32 | } 33 | 34 | else 35 | { 36 | break; 37 | } 38 | } 39 | 40 | return( src ); 41 | } 42 | 43 | char* 44 | digits( char* src ) 45 | { 46 | char* start = src; 47 | char* check = src; 48 | 49 | while( *check ) 50 | { 51 | if ( isdigit( *check ) ) 52 | { 53 | *start++ = *check; 54 | } 55 | 56 | check++; 57 | } 58 | 59 | *start = 0; 60 | 61 | return( src ); 62 | } 63 | 64 | char* 65 | lower_case( char* src ) 66 | { 67 | char* p = src; 68 | 69 | while( *p ) 70 | { 71 | *p = tolower( *p ); 72 | p++; 73 | } 74 | 75 | return( src ); 76 | } 77 | 78 | char* 79 | reverse( char* src ) 80 | { 81 | int i; 82 | int len = strlen( src ); 83 | char tmp; 84 | 85 | for( i = len / 2; --i >= 0; ) 86 | { 87 | tmp = src[ i ]; 88 | src[ i ] = src[ len - i - 1 ]; 89 | src[ len - i - 1 ] = tmp; 90 | } 91 | 92 | return( src ); 93 | } 94 | 95 | char* 96 | trim( char* src ) 97 | { 98 | char *p = src + strlen(src) - 1; 99 | 100 | while( p >= src && isspace(*p) ) 101 | *p-- = '\0'; 102 | 103 | return src; 104 | } 105 | 106 | char* 107 | upper_case( char* src ) 108 | { 109 | char* p = src; 110 | 111 | while( *p ) 112 | { 113 | *p = toupper(*p); 114 | p++; 115 | } 116 | 117 | return( src ); 118 | } 119 | 120 | int 121 | strrcmp( const char* haystack, const char* needle ) 122 | { 123 | int hlen = strlen( haystack ); 124 | int nlen = strlen( needle ); 125 | if( hlen < nlen ) 126 | return( -1 ); 127 | else 128 | return( strcmp( haystack + hlen - nlen, needle ) ); 129 | } 130 | 131 | /* 132 | * Finding a - anywhere in the string makes it money negative. 133 | * all characters other than digits, '-', and '.' are ignored, so: 134 | * ab36-.g98 = -36.98 135 | * This is fair, I think, if we don't want to reject anything as 136 | * improperly formatted. 137 | */ 138 | long 139 | money2cents( const char* money ) 140 | { 141 | long retval = 0; 142 | int decimal_places = -1; 143 | int neg = 0; 144 | 145 | while( *money && decimal_places < 2 ) 146 | { 147 | if ( isdigit( *money ) ) 148 | { 149 | if ( decimal_places >= 0 ) 150 | decimal_places++; 151 | 152 | retval *= 10; 153 | retval += (*money) - '0'; 154 | } 155 | 156 | else if ( *money == '.' ) 157 | decimal_places = 0; 158 | 159 | else if ( *money == '-' ) 160 | neg = 1; 161 | 162 | money++; 163 | } 164 | 165 | if ( decimal_places == 1 ) 166 | retval *= 10; 167 | 168 | else if ( decimal_places <= 0 ) 169 | retval *= 100; 170 | 171 | return( neg ? -retval : retval ); 172 | } 173 | 174 | const char* 175 | cents2money( long cents ) 176 | { 177 | static char buff[ 64 ]; 178 | int idx = 0; 179 | char* d = buff; 180 | 181 | if ( cents == 0 ) 182 | { 183 | strcpy( buff, "0.00" ); 184 | } 185 | 186 | else if ( cents < 100 ) 187 | { 188 | sprintf( buff, "0.%2.2ld", cents ); 189 | } 190 | 191 | else 192 | { 193 | while( cents > 0 ) 194 | { 195 | *d++ = '0' + ( cents % 10 ); 196 | cents = cents / 10; 197 | 198 | if ( idx == 1 ) 199 | { 200 | *d++ = '.'; 201 | } 202 | 203 | else if ( cents > 0 && ( idx - 1 ) % 3 == 0 ) 204 | { 205 | *d++ = ','; 206 | } 207 | 208 | idx++; 209 | } 210 | 211 | *d++ = 0; 212 | 213 | reverse( buff ); 214 | } 215 | 216 | return( buff ); 217 | } 218 | 219 | void trim_zeros_after_decimal( char* src ) 220 | { 221 | char * end = src + strlen( src ) - 1; 222 | 223 | while( end != src ) 224 | { 225 | if( *end == '0' ) 226 | *end = 0; 227 | else if( *end == '.' ) 228 | { 229 | *end = 0; 230 | break; 231 | } 232 | else 233 | break; 234 | 235 | end--; 236 | } 237 | } 238 | 239 | #ifdef linux 240 | extern void *memfrob(void *, size_t); 241 | #else 242 | static void * memfrob(void * mem, size_t len) 243 | { 244 | size_t i; 245 | char *c = (char *)mem; 246 | 247 | for (i = 0; i < len; i++) 248 | { 249 | *c = *c ^ 42; 250 | c++; 251 | } 252 | 253 | return mem; 254 | } 255 | #endif 256 | 257 | // simple functions to obfuscate strings in a binary 258 | char* frobstr( char* src ) 259 | { 260 | char* retval = (char*)malloc( strlen(src) * 2 + 1 ); 261 | 262 | memfrob( src, strlen( src ) ); 263 | str2hex( retval, src, 0 ); 264 | memfrob( src, strlen( src ) ); 265 | 266 | return( retval ); 267 | } 268 | 269 | char* unfrobstr( char* src ) 270 | { 271 | int slen = strlen( src ) / 2; 272 | char* retval = (char*)malloc( slen + 1 ); 273 | 274 | hex2str( retval, src, 0 ); 275 | memfrob( retval, slen ); 276 | 277 | return( retval ); 278 | } 279 | 280 | void str2hex( char* dest, const char* src, int slen ) 281 | { 282 | int i; 283 | char* p = dest; 284 | 285 | if( slen == 0 ) 286 | slen = strlen( src ); 287 | 288 | for ( i = 0; i < slen; i++ ) 289 | { 290 | sprintf( p, "%02x", src[i] ); 291 | p += 2; 292 | } 293 | 294 | *p = 0; 295 | } 296 | 297 | void hex2str( char* dest, const char* src, int slen ) 298 | { 299 | const char* p = src; 300 | int i; 301 | unsigned int v; 302 | 303 | if( slen == 0 ) 304 | slen = strlen( src ); 305 | 306 | slen /= 2; 307 | 308 | for( i = 0; i < slen; i++ ) 309 | { 310 | sscanf( p, "%02x", &v ); 311 | dest[i] = (char)v; 312 | p += 2; 313 | } 314 | 315 | dest[ slen ] = 0; 316 | } 317 | 318 | -------------------------------------------------------------------------------- /util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | #include "util.h" 25 | 26 | typedef int (*compare_func)(const void *, const void *); 27 | 28 | static void * string_tree; 29 | char *readfile(char const *filename, char *buf, size_t size) 30 | { 31 | FILE *fp; 32 | char *ptr; 33 | size_t len; 34 | 35 | fp = fopen(filename, "r"); 36 | if (!fp) 37 | return NULL; 38 | 39 | ptr = fgets(buf, size, fp); 40 | fclose(fp); 41 | 42 | if (!ptr) 43 | return NULL; 44 | 45 | len = strlen(buf); 46 | if (buf[len-1] == '\n') 47 | buf[len-1] = '\0'; 48 | 49 | return buf; 50 | } 51 | 52 | char *strrep(char *s, char find, char replace) 53 | { 54 | char * p = s; 55 | while (*p) 56 | { 57 | if (*p == find) 58 | *p = replace; 59 | p++; 60 | } 61 | 62 | return s; 63 | } 64 | 65 | char *get_cvsps_dir() 66 | { 67 | struct stat sbuf; 68 | static char prefix[PATH_MAX]; 69 | const char * home; 70 | 71 | if (prefix[0]) 72 | return prefix; 73 | 74 | if (!(home = getenv("HOME"))) 75 | { 76 | debug(DEBUG_APPERROR, "HOME environment variable not set"); 77 | exit(1); 78 | } 79 | 80 | if (snprintf(prefix, PATH_MAX, "%s/%s", home, CVSPS_PREFIX) >= PATH_MAX) 81 | { 82 | debug(DEBUG_APPERROR, "prefix buffer overflow"); 83 | exit(1); 84 | } 85 | 86 | /* Make sure the prefix directory exists */ 87 | if (stat(prefix, &sbuf) < 0) 88 | { 89 | int ret; 90 | ret = mkdir(prefix, 0777); 91 | if (ret < 0) 92 | { 93 | debug(DEBUG_SYSERROR, "Cannot create the cvsps directory '%s'", CVSPS_PREFIX); 94 | exit(1); 95 | } 96 | } 97 | else 98 | { 99 | if (!(S_ISDIR(sbuf.st_mode))) 100 | debug(DEBUG_APPERROR, "cvsps directory '%s' is not a directory!", CVSPS_PREFIX); 101 | } 102 | 103 | return prefix; 104 | } 105 | 106 | char *xstrdup(char const *str) 107 | { 108 | char *ret; 109 | assert(str); 110 | ret = strdup(str); 111 | if (!ret) 112 | { 113 | debug(DEBUG_ERROR, "strdup failed"); 114 | exit(1); 115 | } 116 | 117 | return ret; 118 | } 119 | 120 | void strzncpy(char * dst, const char * src, int n) 121 | { 122 | strncpy(dst, src, n); 123 | dst[n - 1] = 0; 124 | } 125 | 126 | char *get_string(char const *str) 127 | { 128 | char ** res; 129 | 130 | if (!str) 131 | return NULL; 132 | 133 | res = (char **)tfind(str, &string_tree, (compare_func)strcmp); 134 | if (!res) 135 | { 136 | char *key = xstrdup(str); 137 | res = (char **)tsearch(key, &string_tree, (compare_func)strcmp); 138 | *res = key; 139 | } 140 | 141 | return *res; 142 | } 143 | 144 | static int get_int_substr(const char * str, const regmatch_t * p) 145 | { 146 | char buff[256]; 147 | memcpy(buff, str + p->rm_so, p->rm_eo - p->rm_so); 148 | buff[p->rm_eo - p->rm_so] = 0; 149 | return atoi(buff); 150 | } 151 | 152 | static time_t mktime_utc(struct tm * tm) 153 | { 154 | char * old_tz = getenv("TZ"); 155 | time_t ret; 156 | 157 | setenv("TZ", "UTC", 1); 158 | 159 | tzset(); 160 | 161 | ret = mktime(tm); 162 | 163 | if (old_tz) 164 | setenv("TZ", old_tz, 1); 165 | else 166 | unsetenv("TZ"); 167 | 168 | tzset(); 169 | 170 | return ret; 171 | } 172 | 173 | void convert_date(time_t * t, const char * dte) 174 | { 175 | static regex_t date_re; 176 | static int init_re; 177 | 178 | #define MAX_MATCH 16 179 | size_t nmatch = MAX_MATCH; 180 | regmatch_t match[MAX_MATCH]; 181 | 182 | if (!init_re) 183 | { 184 | if (regcomp(&date_re, "([0-9]{4})[-/]([0-9]{2})[-/]([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})", REG_EXTENDED)) 185 | { 186 | fprintf(stderr, "FATAL: date regex compilation error\n"); 187 | exit(1); 188 | } 189 | init_re = 1; 190 | } 191 | 192 | if (regexec(&date_re, dte, nmatch, match, 0) == 0) 193 | { 194 | regmatch_t * pm = match; 195 | struct tm tm = {0}; 196 | 197 | /* first regmatch_t is match location of entire re */ 198 | pm++; 199 | 200 | tm.tm_year = get_int_substr(dte, pm++); 201 | tm.tm_mon = get_int_substr(dte, pm++); 202 | tm.tm_mday = get_int_substr(dte, pm++); 203 | tm.tm_hour = get_int_substr(dte, pm++); 204 | tm.tm_min = get_int_substr(dte, pm++); 205 | tm.tm_sec = get_int_substr(dte, pm++); 206 | 207 | tm.tm_year -= 1900; 208 | tm.tm_mon--; 209 | 210 | *t = mktime_utc(&tm); 211 | } 212 | else 213 | { 214 | *t = atoi(dte); 215 | } 216 | } 217 | 218 | static struct timeval start_time; 219 | 220 | void timing_start() 221 | { 222 | gettimeofday(&start_time, NULL); 223 | } 224 | 225 | void timing_stop(const char * msg) 226 | { 227 | struct timeval stop_time; 228 | gettimeofday(&stop_time, NULL); 229 | stop_time.tv_sec -= start_time.tv_sec; 230 | stop_time.tv_usec -= start_time.tv_usec; 231 | if (stop_time.tv_usec < 0) 232 | stop_time.tv_sec--,stop_time.tv_usec += 1000000; 233 | 234 | printf("Elapsed time for %s: %d.%06d\n", msg, (int)stop_time.tv_sec, (int)stop_time.tv_usec); 235 | } 236 | 237 | extern char ** environ; 238 | 239 | /* taken from the linux manual page for system */ 240 | int my_system (const char *command) 241 | { 242 | int pid, status; 243 | 244 | if (command == 0) 245 | return 1; 246 | pid = fork(); 247 | if (pid == -1) 248 | return -1; 249 | if (pid == 0) { 250 | char *argv[4]; 251 | argv[0] = "sh"; 252 | argv[1] = "-c"; 253 | argv[2] = (char*)command; /* discard const */ 254 | argv[3] = 0; 255 | execve("/bin/sh", argv, environ); 256 | exit(127); 257 | } 258 | do { 259 | if (waitpid(pid, &status, 0) == -1) { 260 | if (errno != EINTR) 261 | return -1; 262 | } else 263 | return status; 264 | } while(1); 265 | } 266 | 267 | int escape_filename(char * dst, int len, const char * src) 268 | { 269 | static char * naughty_chars = " \\\"'@<>=;|&()#$`?*[!:{"; 270 | 271 | if (len > 0) 272 | { 273 | while (len > 1 && *src) 274 | { 275 | if (strchr(naughty_chars, *src)) 276 | { 277 | if (len == 2) 278 | break; 279 | *dst++ = '\\'; 280 | len--; 281 | } 282 | 283 | *dst++ = *src++; 284 | len--; 285 | } 286 | 287 | *dst = 0; 288 | } 289 | 290 | return (*src == 0) ? 0 : -1; 291 | } 292 | -------------------------------------------------------------------------------- /cbtcommon/hash.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001, 2002, 2003 David Mansfield and Cobite, Inc. 3 | * See COPYING file for license information 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "debug.h" 11 | #include "hash.h" 12 | #include "rcsid.h" 13 | 14 | RCSID("$Id: hash.c,v 1.6 2003/05/07 15:42:38 david Exp $"); 15 | 16 | #define HASH_CONST 37 17 | 18 | static unsigned int hash_string(const char *); 19 | static struct hash_entry *scan_list(struct list_head *, const char *); 20 | static struct hash_entry *get_hash_entry(struct hash_table *tbl, const char *key); 21 | 22 | struct hash_table *create_hash_table(unsigned int sz) 23 | { 24 | struct hash_table *tbl; 25 | unsigned int i; 26 | 27 | tbl = (struct hash_table *)malloc(sizeof(*tbl) + sz*sizeof(struct list_head)); 28 | 29 | if (!tbl) 30 | { 31 | debug(DEBUG_APPERROR, "malloc for hash_table failed"); 32 | return NULL; 33 | } 34 | 35 | tbl->ht_size = sz; 36 | tbl->ht_lists = (struct list_head *)(tbl + 1); 37 | tbl->iterator = 0; 38 | 39 | for (i = 0; i < sz; i++) 40 | INIT_LIST_HEAD(&tbl->ht_lists[i]); 41 | 42 | return tbl; 43 | } 44 | 45 | void destroy_hash_table(struct hash_table *tbl, void (*delete_obj)(void *)) 46 | { 47 | struct list_head *head, *next, *tmp; 48 | struct hash_entry *entry; 49 | int i; 50 | 51 | for (i = 0; i < tbl->ht_size; i++) 52 | { 53 | head = &tbl->ht_lists[i]; 54 | next = head->next; 55 | 56 | while (next != head) 57 | { 58 | tmp = next->next; 59 | entry = list_entry(next, struct hash_entry, he_list); 60 | if (delete_obj) 61 | delete_obj(entry->he_obj); 62 | free(entry); 63 | 64 | next = tmp; 65 | } 66 | } 67 | 68 | free(tbl); 69 | } 70 | 71 | /* FIXME: there is no way for the user of this to determine the difference 72 | * between a put to a new key value and a malloc failure 73 | */ 74 | void *put_hash_object(struct hash_table *tbl, const char *key, void *obj) 75 | { 76 | void * retval; 77 | put_hash_object_ex(tbl, key, obj, HT_KEYCOPY, NULL, &retval); 78 | return retval; 79 | } 80 | 81 | static struct hash_entry *get_hash_entry(struct hash_table *tbl, const char *key) 82 | { 83 | struct list_head *head; 84 | struct hash_entry *entry; 85 | unsigned int hash; 86 | 87 | hash = hash_string(key) % tbl->ht_size; 88 | head = &tbl->ht_lists[hash]; 89 | entry = scan_list(head, key); 90 | 91 | return entry; 92 | } 93 | 94 | void *get_hash_object(struct hash_table *tbl, const char *key) 95 | { 96 | struct hash_entry *entry = get_hash_entry(tbl, key); 97 | return (entry) ? entry->he_obj : NULL; 98 | } 99 | 100 | void *remove_hash_object(struct hash_table *tbl, const char *key) 101 | { 102 | struct hash_entry *entry = get_hash_entry(tbl, key); 103 | void *retval = NULL; 104 | 105 | if (entry) 106 | { 107 | list_del(&entry->he_list); 108 | retval = entry->he_obj; 109 | free(entry); 110 | } 111 | 112 | return retval; 113 | } 114 | 115 | static unsigned int hash_string(register const char *key) 116 | { 117 | register unsigned int hash = 0; 118 | 119 | while(*key) 120 | hash = hash * HASH_CONST + *key++; 121 | 122 | return hash; 123 | } 124 | 125 | static struct hash_entry *scan_list(struct list_head *head, const char *key) 126 | { 127 | struct list_head *next = head->next; 128 | struct hash_entry *entry; 129 | 130 | while (next != head) 131 | { 132 | entry = list_entry(next, struct hash_entry, he_list); 133 | if (strcmp(entry->he_key, key) == 0) 134 | return entry; 135 | 136 | next = next->next; 137 | } 138 | 139 | return NULL; 140 | } 141 | 142 | void reset_hash_iterator(struct hash_table *tbl) 143 | { 144 | tbl->iterator = 0; 145 | tbl->iterator_ptr = NULL; 146 | } 147 | 148 | struct hash_entry *next_hash_entry(struct hash_table *tbl) 149 | { 150 | while( tbl->iterator < tbl->ht_size ) 151 | { 152 | struct list_head *head = &tbl->ht_lists[ tbl->iterator ]; 153 | 154 | if( tbl->iterator_ptr == NULL ) 155 | tbl->iterator_ptr = head->next; 156 | 157 | if( tbl->iterator_ptr != head ) 158 | { 159 | struct list_head *tmp = tbl->iterator_ptr; 160 | tbl->iterator_ptr = tbl->iterator_ptr->next; 161 | return( list_entry( tmp, struct hash_entry, he_list ) ); 162 | } 163 | 164 | else 165 | { 166 | tbl->iterator++; 167 | tbl->iterator_ptr = NULL; 168 | } 169 | } 170 | 171 | return( NULL ); 172 | } 173 | 174 | int put_hash_object_ex(struct hash_table *tbl, const char *key, void *obj, int copy, 175 | char ** oldkey, void ** oldobj) 176 | { 177 | struct list_head *head; 178 | struct hash_entry *entry; 179 | unsigned int hash; 180 | int retval = 0; 181 | 182 | /* FIXME: how can get_hash_entry be changed to be usable here? 183 | * we need the value of head later if the entry is not found... 184 | */ 185 | hash = hash_string(key) % tbl->ht_size; 186 | head = &tbl->ht_lists[hash]; 187 | entry = scan_list(head, key); 188 | 189 | if (entry) 190 | { 191 | if (oldkey) 192 | *oldkey = entry->he_key; 193 | if (oldobj) 194 | *oldobj = entry->he_obj; 195 | 196 | /* if 'copy' is set, then we already have an exact 197 | * private copy of the key (by definition of having 198 | * found the match in scan_list) so we do nothing. 199 | * if !copy, then we can simply assign the new 200 | * key 201 | */ 202 | if (!copy) 203 | entry->he_key = (char*)key; /* discard the const */ 204 | entry->he_obj = obj; 205 | } 206 | else 207 | { 208 | size_t s = sizeof(*entry); 209 | 210 | if (oldkey) 211 | *oldkey = NULL; 212 | if (oldobj) 213 | *oldobj = NULL; 214 | 215 | if (copy) 216 | s += strlen(key) + 1; 217 | 218 | entry = (struct hash_entry *)malloc(s); 219 | 220 | if (!entry) 221 | { 222 | debug(DEBUG_APPERROR,"malloc failed put_hash_object key='%s'",key); 223 | retval = -1; 224 | } 225 | else 226 | { 227 | if (copy) 228 | { 229 | entry->he_key = (char *)(entry + 1); 230 | strcpy(entry->he_key, key); 231 | } 232 | else 233 | { 234 | entry->he_key = (char*)key; /* discard the const */ 235 | } 236 | 237 | entry->he_obj = obj; 238 | 239 | list_add(&entry->he_list, head); 240 | } 241 | } 242 | 243 | return retval; 244 | } 245 | 246 | void destroy_hash_table_ex(struct hash_table *tbl, 247 | void (*delete_entry)(const void *, char *, void *), 248 | const void * cookie) 249 | { 250 | struct list_head *head, *next, *tmp; 251 | struct hash_entry *entry; 252 | int i; 253 | 254 | for (i = 0; i < tbl->ht_size; i++) 255 | { 256 | head = &tbl->ht_lists[i]; 257 | next = head->next; 258 | 259 | while (next != head) 260 | { 261 | tmp = next->next; 262 | entry = list_entry(next, struct hash_entry, he_list); 263 | if (delete_entry) 264 | delete_entry(cookie, entry->he_key, entry->he_obj); 265 | free(entry); 266 | 267 | next = tmp; 268 | } 269 | } 270 | 271 | free(tbl); 272 | } 273 | -------------------------------------------------------------------------------- /cvsps.1: -------------------------------------------------------------------------------- 1 | .TH "cvsps" 1 2 | .SH NAME 3 | CVSps \- create patchset information from CVS 4 | .SH SYNOPSIS 5 | .B cvsps 6 | [\-h] [\-x] [\-u] [\-z ] [\-g] [\-s ] [\-a ] [\-f ] [\-d [\-d ]] [\-l ] [\-b ] [\-r [\-r ]] [\-p ] [\-v] [\-t] [\-\-norc] [\-\-summary\-first] [\-\-test\-log ] [\-\-bkcvs] [\-\-no\-rlog] [\-\-diff\-opts