2 +++ b/Makefile 2011-01-31 08:14:42.829723957 +0200
8 -CFLAGS+=-I. -DVERSION=\"$(MAJOR).$(MINOR)\"
10 +CPPFLAGS?=-I. -DVERSION=\"$(MAJOR).$(MINOR)\"
19 + makedepend -Y -I. *.c cbtcommon/*.c
22 $(CC) -o cvsps $(OBJS) -lz
25 +tags: *.c *.h cbtcommon/*.c cbtcommon/*.h
26 + ctags *.c *.h cbtcommon/*.c cbtcommon/*.h
29 - rm -f cvsps *.o cbtcommon/*.o core
30 + rm -f cvsps *.o cbtcommon/*.o core tags
35 +cache.o: ./cbtcommon/hash.h ./cbtcommon/list.h ./cbtcommon/inline.h
36 +cache.o: ./cbtcommon/debug.h cache.h cvsps_types.h cvsps.h util.h
37 +cap.o: ./cbtcommon/debug.h ./cbtcommon/inline.h ./cbtcommon/text_util.h cap.h
39 +cvs_direct.o: ./cbtcommon/debug.h ./cbtcommon/inline.h
40 +cvs_direct.o: ./cbtcommon/text_util.h ./cbtcommon/tcpsocket.h
41 +cvs_direct.o: ./cbtcommon/sio.h cvs_direct.h util.h
42 +cvsps.o: ./cbtcommon/hash.h ./cbtcommon/list.h ./cbtcommon/inline.h
43 +cvsps.o: ./cbtcommon/list.h ./cbtcommon/text_util.h ./cbtcommon/debug.h
44 +cvsps.o: ./cbtcommon/rcsid.h cache.h cvsps_types.h cvsps.h util.h stats.h
45 +cvsps.o: cap.h cvs_direct.h list_sort.h
46 +list_sort.o: list_sort.h ./cbtcommon/list.h
47 +stats.o: ./cbtcommon/hash.h ./cbtcommon/list.h ./cbtcommon/inline.h
48 +stats.o: cvsps_types.h cvsps.h
49 +util.o: ./cbtcommon/debug.h ./cbtcommon/inline.h util.h
50 +cbtcommon/debug.o: cbtcommon/debug.h ./cbtcommon/inline.h cbtcommon/rcsid.h
51 +cbtcommon/hash.o: cbtcommon/debug.h ./cbtcommon/inline.h cbtcommon/hash.h
52 +cbtcommon/hash.o: ./cbtcommon/list.h cbtcommon/rcsid.h
53 +cbtcommon/sio.o: cbtcommon/sio.h cbtcommon/rcsid.h
54 +cbtcommon/tcpsocket.o: cbtcommon/tcpsocket.h cbtcommon/debug.h
55 +cbtcommon/tcpsocket.o: ./cbtcommon/inline.h cbtcommon/rcsid.h
56 +cbtcommon/text_util.o: cbtcommon/text_util.h cbtcommon/rcsid.h
59 @@ -108,10 +108,19 @@ time_t read_cache()
61 char branchbuff[LOG_STR_MAX] = "";
63 - char logbuff[LOG_STR_MAX] = "";
64 + int logbufflen = LOG_STR_MAX + 1;
65 + char * logbuff = malloc(logbufflen);
66 time_t cache_date = -1;
69 + if (logbuff == NULL)
71 + debug(DEBUG_SYSERROR, "could not malloc %d bytes for logbuff in read_cache", logbufflen);
77 if (!(fp = cache_open("r")))
80 @@ -299,8 +308,19 @@ time_t read_cache()
83 /* Make sure we have enough in the buffer */
84 - if (strlen(logbuff)+strlen(buff)<LOG_STR_MAX)
85 - strcat(logbuff, buff);
86 + int len = strlen(buff);
87 + if (strlen(logbuff) + len >= LOG_STR_MAX)
89 + logbufflen += (len >= LOG_STR_MAX ? (len+1) : LOG_STR_MAX);
90 + char * newlogbuff = realloc(logbuff, logbufflen);
91 + if (newlogbuff == NULL)
93 + debug(DEBUG_SYSERROR, "could not realloc %d bytes for logbuff in read_cache", logbufflen);
96 + logbuff = newlogbuff;
98 + strcat(logbuff, buff);
101 case CACHE_NEED_PS_MEMBERS:
102 @@ -332,6 +352,7 @@ time_t read_cache()
110 @@ -344,7 +365,7 @@ enum
114 -static void parse_cache_revision(PatchSetMember * psm, const char * p_buff)
115 +static void parse_cache_revision(PatchSetMember * psm, const char * buff)
117 /* The format used to generate is:
118 * "file:%s; pre_rev:%s; post_rev:%s; dead:%d; branch_point:%d\n"
119 @@ -354,35 +375,37 @@ static void parse_cache_revision(PatchSetMember * psm, const char * p_buff)
120 char post[REV_STR_MAX];
124 int state = CR_FILENAME;
128 - strcpy(buff, p_buff);
133 - while ((s = strsep(&p, ";")))
134 + for (p = buff, sep = buff; /* just ensure sep is non-NULL */
135 + (sep != NULL) && (c = strchr(p, ':'));
138 - char * c = strchr(s, ':');
142 - debug(DEBUG_APPERROR, "invalid cache revision line '%s'|'%s'", p_buff, s);
146 + sep = strchr(c, ';');
152 + else /* last field in the cache line */
158 - strcpy(filename, c);
159 + memcpy(filename, c, len);
160 + filename[len] = '\0';
164 + memcpy(pre, c, len);
169 + memcpy(post, c, len);
176 @@ -121,11 +121,19 @@ int check_version_string(const char * str, int req_major, int req_minor, int req
180 + /* We might have encountered a FreeBSD system which
181 + * has a mucked up version string of:
182 + * Concurrent Versions System (CVS) '1.11.17'-FreeBSD (client/server)
183 + * so re-test just in case
186 if (sscanf(p, "%d.%d.%d", &major, &minor, &extra) != 3)
188 - debug(DEBUG_APPMSG1, "WARNING: malformed CVS version: %s", str);
190 + if (sscanf(p, "'%d.%d.%d'", &major, &minor, &extra) != 3)
192 + debug(DEBUG_APPMSG1, "WARNING: malformed CVS version: %s", str);
197 return (major > req_major ||
198 --- a/cbtcommon/tcpsocket.c
199 +++ b/cbtcommon/tcpsocket.c
200 @@ -185,20 +185,20 @@ tcp_connect(int sockfd, const char *rem_addr, unsigned short port)
202 convert_address(long *dest, const char *addr_str)
211 /* first try converting "numbers and dots" notation */
214 if ( inet_aton(addr_str, &ip) )
216 memcpy(dest, &ip.s_addr, sizeof(ip.s_addr));
219 - if ( (*dest = inet_addr(addr_str)) != -1)
220 + if ( (*dest = inet_addr(addr_str)) != INADDR_NONE)
225 +++ b/cvsps.1 2011-01-31 08:14:42.846391432 +0200
227 disable the use of rlog internally. Note: rlog is
228 required for stable PatchSet numbering. Use with care.
230 -.B \-\-diffs\-opts <option string>
231 +.B \-\-diff\-opts <option string>
232 send a custom set of options to diff, for example to increase
233 the number of context lines, or change the diff format.
238 Be quiet about warnings.
241 Show ancestor branch when a new branch is found.
244 +++ b/cvsps.c 2011-01-31 08:14:42.846391432 +0200
256 static int parse_rc();
257 static void load_from_cvs();
258 static void init_paths();
259 -static CvsFile * parse_file(const char *);
260 +static CvsFile * build_file_by_name(const char *);
261 +static CvsFile * parse_rcs_file(const char *);
262 +static CvsFile * parse_working_file(const char *);
263 static CvsFileRevision * parse_revision(CvsFile * file, char * rev_str);
264 static void assign_pre_revision(PatchSetMember *, CvsFileRevision * rev);
265 static void check_print_patch_set(PatchSet *);
266 @@ -260,12 +263,13 @@
270 - int state = NEED_FILE;
271 + int state = NEED_RCS_FILE;
272 CvsFile * file = NULL;
273 PatchSetMember * psm = NULL;
275 char authbuff[AUTH_STR_MAX];
276 - char logbuff[LOG_STR_MAX + 1];
277 + int logbufflen = LOG_STR_MAX + 1;
278 + char * logbuff = malloc(logbufflen);
283 char use_rep_buff[PATH_MAX];
286 + if (logbuff == NULL)
288 + debug(DEBUG_SYSERROR, "could not malloc %d bytes for logbuff in load_from_cvs", logbufflen);
292 if (!no_rlog && !test_log_file && cvs_check_cap(CAP_HAVE_RLOG))
295 @@ -298,12 +308,12 @@
296 * which is necessary to fill in the pre_rev stuff for a
299 - snprintf(cmd, BUFSIZ, "cvs %s %s %s -d '%s<;%s' %s", compress_arg, norc, ltype, date_str, date_str, use_rep_buff);
300 + snprintf(cmd, BUFSIZ, "cvs %s %s -q %s -d '%s<;%s' %s", compress_arg, norc, ltype, date_str, date_str, use_rep_buff);
305 - snprintf(cmd, BUFSIZ, "cvs %s %s %s %s", compress_arg, norc, ltype, use_rep_buff);
306 + snprintf(cmd, BUFSIZ, "cvs %s %s -q %s %s", compress_arg, norc, ltype, use_rep_buff);
309 debug(DEBUG_STATUS, "******* USING CMD %s", cmd);
310 @@ -339,10 +349,26 @@
315 - if (strncmp(buff, "RCS file", 8) == 0 && (file = parse_file(buff)))
316 + case NEED_RCS_FILE:
317 + if (strncmp(buff, "RCS file", 8) == 0) {
318 + if ((file = parse_rcs_file(buff)) != NULL)
321 + state = NEED_WORKING_FILE;
324 + case NEED_WORKING_FILE:
325 + if (strncmp(buff, "Working file", 12) == 0) {
326 + if ((file = parse_working_file(buff)))
329 + state = NEED_RCS_FILE;
332 + // Working file come just after RCS file. So reset state if it was not found
333 + state = NEED_RCS_FILE;
337 if (strncmp(buff, "symbolic names:", 15) == 0)
344 + state = NEED_RCS_FILE;
348 @@ -480,24 +506,22 @@
350 if (have_log || !is_revision_metadata(buff))
352 - /* if the log buffer is full, that's it.
354 - * Also, read lines (fgets) always have \n in them
355 - * which we count on. So if truncation happens,
356 - * be careful to put a \n on.
358 - * Buffer has LOG_STR_MAX + 1 for room for \0 if
361 - if (loglen < LOG_STR_MAX)
362 + /* If the log buffer is full, try to reallocate more. */
363 + if (loglen < logbufflen)
365 int len = strlen(buff);
367 - if (len >= LOG_STR_MAX - loglen)
368 + if (len >= logbufflen - loglen)
370 - debug(DEBUG_APPMSG1, "WARNING: maximum log length exceeded, truncating log");
371 - len = LOG_STR_MAX - loglen;
372 - buff[len - 1] = '\n';
373 + debug(DEBUG_STATUS, "reallocating logbufflen to %d bytes for file %s", logbufflen, file->filename);
374 + logbufflen += (len >= LOG_STR_MAX ? (len+1) : LOG_STR_MAX);
375 + char * newlogbuff = realloc(logbuff, logbufflen);
376 + if (newlogbuff == NULL)
378 + debug(DEBUG_SYSERROR, "could not realloc %d bytes for logbuff in load_from_cvs", logbufflen);
381 + logbuff = newlogbuff;
384 debug(DEBUG_STATUS, "appending %s to log", buff);
389 - if (state != NEED_FILE)
390 + if (state != NEED_RCS_FILE)
392 debug(DEBUG_APPERROR, "Error: Log file parsing error. (%d) Use -v to debug", state);
394 @@ -1038,8 +1062,8 @@
396 * NOTE: because of some bizarre 'feature' in cvs, when 'rlog' is used
397 * (instead of log) it gives the 'real' RCS file path, which can be different
398 - * from the 'nominal' repository path because of symlinks in the server and
399 - * the like. See also the 'parse_file' routine
400 + * from the 'nominal' repository path because of symlinks in the server and
401 + * the like. See also the 'parse_rcs_file' routine
403 strip_path_len = snprintf(strip_path, PATH_MAX, "%s/%s/", p, repository_path);
405 @@ -1052,9 +1076,8 @@
406 debug(DEBUG_STATUS, "strip_path: %s", strip_path);
409 -static CvsFile * parse_file(const char * buff)
410 +static CvsFile * parse_rcs_file(const char * buff)
414 int len = strlen(buff + 10);
416 @@ -1129,6 +1152,28 @@
418 debug(DEBUG_STATUS, "stripped filename %s", fn);
420 + return build_file_by_name(fn);
423 +static CvsFile * parse_working_file(const char * buff)
426 + int len = strlen(buff + 14);
428 + /* chop the "LF" */
430 + memcpy(fn, buff + 14, len);
433 + debug(DEBUG_STATUS, "working filename %s", fn);
435 + return build_file_by_name(fn);
438 +static CvsFile * build_file_by_name(const char * fn)
442 retval = (CvsFile*)get_hash_object(file_hash, fn);
445 @@ -2104,6 +2149,11 @@
447 if (!get_branch_ext(rev, eot, &leaf))
449 + if (strcmp(tag, "TRUNK") == 0)
451 + debug(DEBUG_STATUS, "ignoring the TRUNK branch/tag");
454 debug(DEBUG_APPERROR, "malformed revision");
457 @@ -2384,8 +2434,31 @@
458 for (next = ps->members.next; next != &ps->members; next = next->next)
460 PatchSetMember * m = list_entry(next, PatchSetMember, link);
461 - if (m->file == psm->file && ps->collision_link.next == NULL)
462 - list_add(&ps->collision_link, &collisions);
463 + if (m->file == psm->file) {
464 + int order = compare_rev_strings(psm->post_rev->rev, m->post_rev->rev);
467 + * Same revision too? Add it to the collision list
468 + * if it isn't already.
471 + if (ps->collision_link.next == NULL)
472 + list_add(&ps->collision_link, &collisions);
477 + * If this is an older revision than the one we already have
478 + * in this patchset, just ignore it
484 + * This is a newer one, remove the old one
486 + list_del(&m->link);
491 @@ -2398,11 +2471,10 @@
492 if (psm->post_rev->dead)
495 - * we expect a 'file xyz initially added on branch abc' here
496 - * but there can only be one such member in a given patchset
497 + * We expect a 'file xyz initially added on branch abc' here.
498 + * There can only be several such member in a given patchset,
499 + * since cvs only includes the file basename in the log message.
501 - if (psm->ps->branch_add)
502 - debug(DEBUG_APPMSG1, "WARNING: branch_add already set!");
503 psm->ps->branch_add = 1;
506 @@ -2576,7 +2648,7 @@
507 * note: rev is the pre-commit revision, not the post-commit
509 if (!head_ps->ancestor_branch)
512 else if (strcmp(ps->branch, rev->branch) == 0)
514 else if (strcmp(head_ps->ancestor_branch, "HEAD") == 0)
521 -#define LOG_STR_MAX 32768
522 +#define LOG_STR_MAX 65536
523 #define AUTH_STR_MAX 64
524 #define REV_STR_MAX 64
525 #define MIN(a, b) ((a) < (b) ? (a) : (b))
526 --- a/cbtcommon/list.h 2005-05-26 06:39:40.000000000 +0300
527 +++ b/cbtcommon/list.h 2011-01-31 08:14:42.829723957 +0200
535 struct list_head *next, *prev;
539 #define list_entry(ptr, type, member) \
540 - ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
541 + ((type *)((char *)(ptr)-offsetof(type, member)))
543 #endif /* _COMMON_LIST_H */