1 diff --git a/Makefile b/Makefile
2 index 507c3e9..05ca856 100644
10 -CFLAGS+=-I. -DVERSION=\"$(MAJOR).$(MINOR)\"
12 +CPPFLAGS?=-I. -DVERSION=\"$(MAJOR).$(MINOR)\"
16 @@ -20,6 +20,9 @@ OBJS=\
21 + makedepend -Y -I. *.c cbtcommon/*.c
24 $(CC) -o cvsps $(OBJS) -lz
26 @@ -33,3 +36,27 @@ clean:
27 rm -f cvsps *.o cbtcommon/*.o core
32 +cache.o: ./cbtcommon/hash.h ./cbtcommon/list.h ./cbtcommon/inline.h
33 +cache.o: ./cbtcommon/debug.h cache.h cvsps_types.h cvsps.h util.h
34 +cap.o: ./cbtcommon/debug.h ./cbtcommon/inline.h ./cbtcommon/text_util.h cap.h
36 +cvs_direct.o: ./cbtcommon/debug.h ./cbtcommon/inline.h
37 +cvs_direct.o: ./cbtcommon/text_util.h ./cbtcommon/tcpsocket.h
38 +cvs_direct.o: ./cbtcommon/sio.h cvs_direct.h util.h
39 +cvsps.o: ./cbtcommon/hash.h ./cbtcommon/list.h ./cbtcommon/inline.h
40 +cvsps.o: ./cbtcommon/list.h ./cbtcommon/text_util.h ./cbtcommon/debug.h
41 +cvsps.o: ./cbtcommon/rcsid.h cache.h cvsps_types.h cvsps.h util.h stats.h
42 +cvsps.o: cap.h cvs_direct.h list_sort.h
43 +list_sort.o: list_sort.h ./cbtcommon/list.h
44 +stats.o: ./cbtcommon/hash.h ./cbtcommon/list.h ./cbtcommon/inline.h
45 +stats.o: cvsps_types.h cvsps.h
46 +util.o: ./cbtcommon/debug.h ./cbtcommon/inline.h util.h
47 +cbtcommon/debug.o: cbtcommon/debug.h ./cbtcommon/inline.h cbtcommon/rcsid.h
48 +cbtcommon/hash.o: cbtcommon/debug.h ./cbtcommon/inline.h cbtcommon/hash.h
49 +cbtcommon/hash.o: ./cbtcommon/list.h cbtcommon/rcsid.h
50 +cbtcommon/sio.o: cbtcommon/sio.h cbtcommon/rcsid.h
51 +cbtcommon/tcpsocket.o: cbtcommon/tcpsocket.h cbtcommon/debug.h
52 +cbtcommon/tcpsocket.o: ./cbtcommon/inline.h cbtcommon/rcsid.h
53 +cbtcommon/text_util.o: cbtcommon/text_util.h cbtcommon/rcsid.h
54 diff --git a/cache.c b/cache.c
55 index 4c51cf7..5f67a7c 100644
58 @@ -108,10 +108,19 @@ time_t read_cache()
60 char branchbuff[LOG_STR_MAX] = "";
62 - char logbuff[LOG_STR_MAX] = "";
63 + int logbufflen = LOG_STR_MAX + 1;
64 + char * logbuff = malloc(logbufflen);
65 time_t cache_date = -1;
68 + if (logbuff == NULL)
70 + debug(DEBUG_SYSERROR, "could not malloc %d bytes for logbuff in read_cache", logbufflen);
76 if (!(fp = cache_open("r")))
79 @@ -299,8 +308,19 @@ time_t read_cache()
82 /* Make sure we have enough in the buffer */
83 - if (strlen(logbuff)+strlen(buff)<LOG_STR_MAX)
84 - strcat(logbuff, buff);
85 + int len = strlen(buff);
86 + if (strlen(logbuff) + len >= LOG_STR_MAX)
88 + logbufflen += (len >= LOG_STR_MAX ? (len+1) : LOG_STR_MAX);
89 + char * newlogbuff = realloc(logbuff, logbufflen);
90 + if (newlogbuff == NULL)
92 + debug(DEBUG_SYSERROR, "could not realloc %d bytes for logbuff in read_cache", logbufflen);
95 + logbuff = newlogbuff;
97 + strcat(logbuff, buff);
100 case CACHE_NEED_PS_MEMBERS:
101 @@ -332,6 +352,7 @@ time_t read_cache()
109 @@ -344,7 +365,7 @@ enum
113 -static void parse_cache_revision(PatchSetMember * psm, const char * p_buff)
114 +static void parse_cache_revision(PatchSetMember * psm, const char * buff)
116 /* The format used to generate is:
117 * "file:%s; pre_rev:%s; post_rev:%s; dead:%d; branch_point:%d\n"
118 @@ -354,35 +375,37 @@ static void parse_cache_revision(PatchSetMember * psm, const char * p_buff)
119 char post[REV_STR_MAX];
123 int state = CR_FILENAME;
127 - strcpy(buff, p_buff);
132 - while ((s = strsep(&p, ";")))
133 + for (p = buff, sep = buff; /* just ensure sep is non-NULL */
134 + (sep != NULL) && (c = strchr(p, ':'));
137 - char * c = strchr(s, ':');
141 - debug(DEBUG_APPERROR, "invalid cache revision line '%s'|'%s'", p_buff, s);
145 + sep = strchr(c, ';');
151 + else /* last field in the cache line */
157 - strcpy(filename, c);
158 + memcpy(filename, c, len);
159 + filename[len] = '\0';
163 + memcpy(pre, c, len);
168 + memcpy(post, c, len);
173 diff --git a/cap.c b/cap.c
174 index a6186f6..a1927df 100644
177 @@ -121,11 +121,19 @@ int check_version_string(const char * str, int req_major, int req_minor, int req
181 + /* We might have encountered a FreeBSD system which
182 + * has a mucked up version string of:
183 + * Concurrent Versions System (CVS) '1.11.17'-FreeBSD (client/server)
184 + * so re-test just in case
187 if (sscanf(p, "%d.%d.%d", &major, &minor, &extra) != 3)
189 - debug(DEBUG_APPMSG1, "WARNING: malformed CVS version: %s", str);
191 + if (sscanf(p, "'%d.%d.%d'", &major, &minor, &extra) != 3)
193 + debug(DEBUG_APPMSG1, "WARNING: malformed CVS version: %s", str);
198 return (major > req_major ||
199 diff --git a/cbtcommon/tcpsocket.c b/cbtcommon/tcpsocket.c
200 index 27cc13a..f31060e 100644
201 --- a/cbtcommon/tcpsocket.c
202 +++ b/cbtcommon/tcpsocket.c
203 @@ -185,20 +185,20 @@ tcp_connect(int sockfd, const char *rem_addr, unsigned short port)
205 convert_address(long *dest, const char *addr_str)
214 /* first try converting "numbers and dots" notation */
217 if ( inet_aton(addr_str, &ip) )
219 memcpy(dest, &ip.s_addr, sizeof(ip.s_addr));
222 - if ( (*dest = inet_addr(addr_str)) != -1)
223 + if ( (*dest = inet_addr(addr_str)) != INADDR_NONE)
227 diff --git a/cvsps.1 b/cvsps.1
228 index cea0faf..6cfdac6 100644
231 @@ -83,7 +83,7 @@ some hacks which are not generally applicable.
232 disable the use of rlog internally. Note: rlog is
233 required for stable PatchSet numbering. Use with care.
235 -.B \-\-diffs\-opts <option string>
236 +.B \-\-diff\-opts <option string>
237 send a custom set of options to diff, for example to increase
238 the number of context lines, or change the diff format.
240 diff --git a/cvsps.c b/cvsps.c
241 index 1e64e3c..981cd78 100644
244 @@ -39,7 +39,8 @@ RCSID("$Id$");
254 @@ -117,7 +118,9 @@ static int parse_args(int, char *[]);
255 static int parse_rc();
256 static void load_from_cvs();
257 static void init_paths();
258 -static CvsFile * parse_file(const char *);
259 +static CvsFile * build_file_by_name(const char *);
260 +static CvsFile * parse_rcs_file(const char *);
261 +static CvsFile * parse_working_file(const char *);
262 static CvsFileRevision * parse_revision(CvsFile * file, char * rev_str);
263 static void assign_pre_revision(PatchSetMember *, CvsFileRevision * rev);
264 static void check_print_patch_set(PatchSet *);
265 @@ -260,12 +263,13 @@ static void load_from_cvs()
269 - int state = NEED_FILE;
270 + int state = NEED_RCS_FILE;
271 CvsFile * file = NULL;
272 PatchSetMember * psm = NULL;
274 char authbuff[AUTH_STR_MAX];
275 - char logbuff[LOG_STR_MAX + 1];
276 + int logbufflen = LOG_STR_MAX + 1;
277 + char * logbuff = malloc(logbufflen);
281 @@ -273,6 +277,12 @@ static void load_from_cvs()
282 char use_rep_buff[PATH_MAX];
285 + if (logbuff == NULL)
287 + debug(DEBUG_SYSERROR, "could not malloc %d bytes for logbuff in load_from_cvs", logbufflen);
291 if (!no_rlog && !test_log_file && cvs_check_cap(CAP_HAVE_RLOG))
294 @@ -298,12 +308,12 @@ static void load_from_cvs()
295 * which is necessary to fill in the pre_rev stuff for a
298 - snprintf(cmd, BUFSIZ, "cvs %s %s %s -d '%s<;%s' %s", compress_arg, norc, ltype, date_str, date_str, use_rep_buff);
299 + snprintf(cmd, BUFSIZ, "cvs %s %s -q %s -d '%s<;%s' %s", compress_arg, norc, ltype, date_str, date_str, use_rep_buff);
304 - snprintf(cmd, BUFSIZ, "cvs %s %s %s %s", compress_arg, norc, ltype, use_rep_buff);
305 + snprintf(cmd, BUFSIZ, "cvs %s %s -q %s %s", compress_arg, norc, ltype, use_rep_buff);
308 debug(DEBUG_STATUS, "******* USING CMD %s", cmd);
309 @@ -339,10 +349,26 @@ static void load_from_cvs()
314 - if (strncmp(buff, "RCS file", 8) == 0 && (file = parse_file(buff)))
315 + case NEED_RCS_FILE:
316 + if (strncmp(buff, "RCS file", 8) == 0) {
317 + if ((file = parse_rcs_file(buff)) != NULL)
320 + state = NEED_WORKING_FILE;
323 + case NEED_WORKING_FILE:
324 + if (strncmp(buff, "Working file", 12) == 0) {
325 + if ((file = parse_working_file(buff)))
328 + state = NEED_RCS_FILE;
331 + // Working file come just after RCS file. So reset state if it was not found
332 + state = NEED_RCS_FILE;
336 if (strncmp(buff, "symbolic names:", 15) == 0)
338 @@ -471,7 +497,7 @@ static void load_from_cvs()
343 + state = NEED_RCS_FILE;
347 @@ -480,24 +506,22 @@ static void load_from_cvs()
349 if (have_log || !is_revision_metadata(buff))
351 - /* if the log buffer is full, that's it.
353 - * Also, read lines (fgets) always have \n in them
354 - * which we count on. So if truncation happens,
355 - * be careful to put a \n on.
357 - * Buffer has LOG_STR_MAX + 1 for room for \0 if
360 - if (loglen < LOG_STR_MAX)
361 + /* If the log buffer is full, try to reallocate more. */
362 + if (loglen < logbufflen)
364 int len = strlen(buff);
366 - if (len >= LOG_STR_MAX - loglen)
367 + if (len >= logbufflen - loglen)
369 - debug(DEBUG_APPMSG1, "WARNING: maximum log length exceeded, truncating log");
370 - len = LOG_STR_MAX - loglen;
371 - buff[len - 1] = '\n';
372 + debug(DEBUG_STATUS, "reallocating logbufflen to %d bytes for file %s", logbufflen, file->filename);
373 + logbufflen += (len >= LOG_STR_MAX ? (len+1) : LOG_STR_MAX);
374 + char * newlogbuff = realloc(logbuff, logbufflen);
375 + if (newlogbuff == NULL)
377 + debug(DEBUG_SYSERROR, "could not realloc %d bytes for logbuff in load_from_cvs", logbufflen);
380 + logbuff = newlogbuff;
383 debug(DEBUG_STATUS, "appending %s to log", buff);
384 @@ -524,7 +548,7 @@ static void load_from_cvs()
388 - if (state != NEED_FILE)
389 + if (state != NEED_RCS_FILE)
391 debug(DEBUG_APPERROR, "Error: Log file parsing error. (%d) Use -v to debug", state);
393 @@ -1038,8 +1062,8 @@ static void init_paths()
395 * NOTE: because of some bizarre 'feature' in cvs, when 'rlog' is used
396 * (instead of log) it gives the 'real' RCS file path, which can be different
397 - * from the 'nominal' repository path because of symlinks in the server and
398 - * the like. See also the 'parse_file' routine
399 + * from the 'nominal' repository path because of symlinks in the server and
400 + * the like. See also the 'parse_rcs_file' routine
402 strip_path_len = snprintf(strip_path, PATH_MAX, "%s/%s/", p, repository_path);
404 @@ -1052,9 +1076,8 @@ static void init_paths()
405 debug(DEBUG_STATUS, "strip_path: %s", strip_path);
408 -static CvsFile * parse_file(const char * buff)
409 +static CvsFile * parse_rcs_file(const char * buff)
413 int len = strlen(buff + 10);
415 @@ -1129,6 +1152,28 @@ static CvsFile * parse_file(const char * buff)
417 debug(DEBUG_STATUS, "stripped filename %s", fn);
419 + return build_file_by_name(fn);
422 +static CvsFile * parse_working_file(const char * buff)
425 + int len = strlen(buff + 14);
427 + /* chop the "LF" */
429 + memcpy(fn, buff + 14, len);
432 + debug(DEBUG_STATUS, "working filename %s", fn);
434 + return build_file_by_name(fn);
437 +static CvsFile * build_file_by_name(const char * fn)
441 retval = (CvsFile*)get_hash_object(file_hash, fn);
444 @@ -2104,6 +2149,11 @@ static void parse_sym(CvsFile * file, char * sym)
446 if (!get_branch_ext(rev, eot, &leaf))
448 + if (strcmp(tag, "TRUNK") == 0)
450 + debug(DEBUG_STATUS, "ignoring the TRUNK branch/tag");
453 debug(DEBUG_APPERROR, "malformed revision");
456 @@ -2384,8 +2434,31 @@ void patch_set_add_member(PatchSet * ps, PatchSetMember * psm)
457 for (next = ps->members.next; next != &ps->members; next = next->next)
459 PatchSetMember * m = list_entry(next, PatchSetMember, link);
460 - if (m->file == psm->file && ps->collision_link.next == NULL)
461 - list_add(&ps->collision_link, &collisions);
462 + if (m->file == psm->file) {
463 + int order = compare_rev_strings(psm->post_rev->rev, m->post_rev->rev);
466 + * Same revision too? Add it to the collision list
467 + * if it isn't already.
470 + if (ps->collision_link.next == NULL)
471 + list_add(&ps->collision_link, &collisions);
476 + * If this is an older revision than the one we already have
477 + * in this patchset, just ignore it
483 + * This is a newer one, remove the old one
485 + list_del(&m->link);
490 @@ -2576,7 +2649,7 @@ static void determine_branch_ancestor(PatchSet * ps, PatchSet * head_ps)
491 * note: rev is the pre-commit revision, not the post-commit
493 if (!head_ps->ancestor_branch)
496 else if (strcmp(ps->branch, rev->branch) == 0)
498 else if (strcmp(head_ps->ancestor_branch, "HEAD") == 0)
499 diff --git a/cvsps_types.h b/cvsps_types.h
500 index b41e2a9..dba145d 100644
507 -#define LOG_STR_MAX 32768
508 +#define LOG_STR_MAX 65536
509 #define AUTH_STR_MAX 64
510 #define REV_STR_MAX 64
511 #define MIN(a, b) ((a) < (b) ? (a) : (b))