diff options
author | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 2001-11-06 05:31:52 +0000 |
---|---|---|
committer | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 2001-11-06 05:31:52 +0000 |
commit | 522fffa1c13d110725c9e13b90f03d23365cc2c7 (patch) | |
tree | bfc22a238be7f544713b5ae2e6ee4bbb6856081f | |
parent | 7ed40ddd4c0de1c83a899df441ecd68d2f80c17d (diff) |
start editor in an empty line as used to be; deraadt@ agrees.
-rw-r--r-- | gnu/usr.bin/cvs/src/logmsg.c | 648 |
1 files changed, 538 insertions, 110 deletions
diff --git a/gnu/usr.bin/cvs/src/logmsg.c b/gnu/usr.bin/cvs/src/logmsg.c index f39dd31e888..679d87ee585 100644 --- a/gnu/usr.bin/cvs/src/logmsg.c +++ b/gnu/usr.bin/cvs/src/logmsg.c @@ -3,30 +3,28 @@ * Copyright (c) 1989-1992, Brian Berliner * * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS 1.4 kit. + * specified in the README file that comes with the CVS source distribution. */ #include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)logmsg.c 1.48 94/09/29 $"; -USE(rcsid); -#endif +#include "getline.h" static int find_type PROTO((Node * p, void *closure)); static int fmt_proc PROTO((Node * p, void *closure)); -static int logfile_write PROTO((char *repository, char *filter, char *title, - char *message, char *revision, FILE * logfp, - List * changes)); +static int logfile_write PROTO((char *repository, char *filter, + char *message, FILE * logfp, List * changes)); static int rcsinfo_proc PROTO((char *repository, char *template)); static int title_proc PROTO((Node * p, void *closure)); static int update_logfile_proc PROTO((char *repository, char *filter)); static void setup_tmpfile PROTO((FILE * xfp, char *xprefix, List * changes)); static int editinfo_proc PROTO((char *repository, char *template)); +static int verifymsg_proc PROTO((char *repository, char *script)); static FILE *fp; static char *str_list; +static char *str_list_format; /* The format for str_list's contents. */ static char *editinfo_editor; +static char *verifymsg_script; static Ctype type; /* @@ -35,6 +33,7 @@ static Ctype type; * and removed files are included (if any) and formatted to look pretty. */ static char *prefix; static int col; +static char *tag; static void setup_tmpfile (xfp, xprefix, changes) FILE *xfp; @@ -49,28 +48,40 @@ setup_tmpfile (xfp, xprefix, changes) if (walklist (changes, find_type, NULL) != 0) { (void) fprintf (fp, "%sModified Files:\n", prefix); - (void) fprintf (fp, "%s\t", prefix); - col = 8; + col = 0; (void) walklist (changes, fmt_proc, NULL); (void) fprintf (fp, "\n"); + if (tag != NULL) + { + free (tag); + tag = NULL; + } } type = T_ADDED; if (walklist (changes, find_type, NULL) != 0) { (void) fprintf (fp, "%sAdded Files:\n", prefix); - (void) fprintf (fp, "%s\t", prefix); - col = 8; + col = 0; (void) walklist (changes, fmt_proc, NULL); (void) fprintf (fp, "\n"); + if (tag != NULL) + { + free (tag); + tag = NULL; + } } type = T_REMOVED; if (walklist (changes, find_type, NULL) != 0) { (void) fprintf (fp, "%sRemoved Files:\n", prefix); - (void) fprintf (fp, "%s\t", prefix); - col = 8; + col = 0; (void) walklist (changes, fmt_proc, NULL); (void) fprintf (fp, "\n"); + if (tag != NULL) + { + free (tag); + tag = NULL; + } } } @@ -82,7 +93,10 @@ find_type (p, closure) Node *p; void *closure; { - if (p->data == (char *) type) + struct logfile_info *li; + + li = (struct logfile_info *) p->data; + if (li->type == type) return (1); else return (0); @@ -98,9 +112,44 @@ fmt_proc (p, closure) Node *p; void *closure; { - if (p->data == (char *) type) + struct logfile_info *li; + + li = (struct logfile_info *) p->data; + if (li->type == type) { - if ((col + (int) strlen (p->key)) > 70) + if (li->tag == NULL + ? tag != NULL + : tag == NULL || strcmp (tag, li->tag) != 0) + { + if (col > 0) + (void) fprintf (fp, "\n"); + (void) fprintf (fp, "%s", prefix); + col = strlen (prefix); + while (col < 6) + { + (void) fprintf (fp, " "); + ++col; + } + + if (li->tag == NULL) + (void) fprintf (fp, "No tag"); + else + (void) fprintf (fp, "Tag: %s", li->tag); + + if (tag != NULL) + free (tag); + tag = xstrdup (li->tag); + + /* Force a new line. */ + col = 70; + } + + if (col == 0) + { + (void) fprintf (fp, "%s\t", prefix); + col = 8; + } + else if (col > 8 && (col + (int) strlen (p->key)) > 70) { (void) fprintf (fp, "\n%s\t", prefix); col = 8; @@ -116,10 +165,8 @@ fmt_proc (p, closure) * editor on the file. The header garbage in the resultant file is then * stripped and the log message is stored in the "message" argument. * - * rcsinfo - is the name of a file containing lines tacked onto the end of the - * RCS info offered to the user for editing. If specified, the '-m' flag to - * "commit" is disabled -- users are forced to run the editor. - * + * If REPOSITORY is non-NULL, process rcsinfo for that repository; if it + * is NULL, use the CVSADM_TEMPLATE file instead. */ void do_editor (dir, messagep, repository, changes) @@ -129,24 +176,35 @@ do_editor (dir, messagep, repository, changes) List *changes; { static int reuse_log_message = 0; - char line[MAXLINELEN], fname[L_tmpnam+1]; + char *line; + int line_length; + size_t line_chars_allocated; + char *fname; struct stat pre_stbuf, post_stbuf; int retcode = 0; if (noexec || reuse_log_message) return; + /* Abort creation of temp file if no editor is defined */ + if (strcmp (Editor, "") == 0 && !editinfo_editor) + error(1, 0, "no editor defined, must use -e or -m"); + /* Create a temporary file */ - (void) tmpnam (fname); + /* FIXME - It's possible we should be relying on cvs_temp_file to open + * the file here - we get race conditions otherwise. + */ + fname = cvs_temp_name (); again: - if ((fp = fopen (fname, "w+")) == NULL) + if ((fp = CVS_FOPEN (fname, "w+")) == NULL) error (1, 0, "cannot create temporary file %s", fname); if (*messagep) { (void) fprintf (fp, "%s", *messagep); - if ((*messagep)[strlen (*messagep) - 1] != '\n') + if ((*messagep)[0] == '\0' || + (*messagep)[strlen (*messagep) - 1] != '\n') (void) fprintf (fp, "\n"); } else @@ -155,13 +213,48 @@ do_editor (dir, messagep, repository, changes) if (repository != NULL) /* tack templates on if necessary */ (void) Parse_Info (CVSROOTADM_RCSINFO, repository, rcsinfo_proc, 1); + else + { + FILE *tfp; + char buf[1024]; + size_t n; + size_t nwrite; + + /* Why "b"? */ + tfp = CVS_FOPEN (CVSADM_TEMPLATE, "rb"); + if (tfp == NULL) + { + if (!existence_error (errno)) + error (1, errno, "cannot read %s", CVSADM_TEMPLATE); + } + else + { + while (!feof (tfp)) + { + char *p = buf; + n = fread (buf, 1, sizeof buf, tfp); + nwrite = n; + while (nwrite > 0) + { + n = fwrite (p, 1, nwrite, fp); + nwrite -= n; + p += n; + } + if (ferror (tfp)) + error (1, errno, "cannot read %s", CVSADM_TEMPLATE); + } + if (fclose (tfp) < 0) + error (0, errno, "cannot close %s", CVSADM_TEMPLATE); + } + } (void) fprintf (fp, "%s----------------------------------------------------------------------\n", CVSEDITPREFIX); (void) fprintf (fp, - "%sEnter Log. Lines beginning with `%s' are removed automatically\n%s\n", - CVSEDITPREFIX, CVSEDITPREFIX, CVSEDITPREFIX); + "%sEnter Log. Lines beginning with `%.*s' are removed automatically\n%s\n", + CVSEDITPREFIX, CVSEDITPREFIXLEN, CVSEDITPREFIX, + CVSEDITPREFIX); if (dir != NULL && *dir) (void) fprintf (fp, "%sCommitting in %s\n%s\n", CVSEDITPREFIX, dir, CVSEDITPREFIX); @@ -172,18 +265,24 @@ do_editor (dir, messagep, repository, changes) CVSEDITPREFIX); /* finish off the temp file */ - (void) fclose (fp); - if (stat (fname, &pre_stbuf) == -1) + if (fclose (fp) == EOF) + error (1, errno, "%s", fname); + if ( CVS_STAT (fname, &pre_stbuf) == -1) pre_stbuf.st_mtime = 0; if (editinfo_editor) free (editinfo_editor); editinfo_editor = (char *) NULL; +#ifdef CLIENT_SUPPORT + if (current_parsed_root->isremote) + ; /* nothing, leave editinfo_editor NULL */ + else +#endif if (repository != NULL) (void) Parse_Info (CVSROOTADM_EDITINFO, repository, editinfo_proc, 0); /* run the editor */ - run_setup ("%s", editinfo_editor ? editinfo_editor : Editor); + run_setup (editinfo_editor ? editinfo_editor : Editor); run_arg (fname); if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL | RUN_SIGIGNORE)) != 0) @@ -198,30 +297,47 @@ do_editor (dir, messagep, repository, changes) if (*messagep) free (*messagep); - if (stat (fname, &post_stbuf) != 0) + if ( CVS_STAT (fname, &post_stbuf) != 0) error (1, errno, "cannot find size of temp file %s", fname); if (post_stbuf.st_size == 0) *messagep = NULL; else { + /* On NT, we might read less than st_size bytes, but we won't + read more. So this works. */ *messagep = (char *) xmalloc (post_stbuf.st_size + 1); *messagep[0] = '\0'; } -/* !!! XXX FIXME: fgets is broken. This should not have any line - length limits. */ + line = NULL; + line_chars_allocated = 0; if (*messagep) { - while (fgets (line, sizeof (line), fp) != NULL) + size_t message_len = post_stbuf.st_size + 1; + size_t offset = 0; + while (1) { - if (strncmp (line, CVSEDITPREFIX, sizeof (CVSEDITPREFIX) - 1) == 0) + line_length = getline (&line, &line_chars_allocated, fp); + if (line_length == -1) + { + if (ferror (fp)) + error (0, errno, "warning: cannot read %s", fname); + break; + } + if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0) continue; - (void) strcat (*messagep, line); + if (offset + line_length >= message_len) + expand_string (messagep, &message_len, + offset + line_length + 1); + (void) strcpy (*messagep + offset, line); + offset += line_length; } } - (void) fclose (fp); + if (fclose (fp) < 0) + error (0, errno, "warning: cannot close %s", fname); + if (pre_stbuf.st_mtime == post_stbuf.st_mtime || *messagep == NULL || strcmp (*messagep, "\n") == 0) @@ -232,12 +348,24 @@ do_editor (dir, messagep, repository, changes) (void) printf ("a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs\n"); (void) printf ("Action: (continue) "); (void) fflush (stdout); - *line = '\0'; - (void) fgets (line, sizeof (line), stdin); - if (*line == '\0' || *line == '\n' || *line == 'c' || *line == 'C') + line_length = getline (&line, &line_chars_allocated, stdin); + if (line_length < 0) + { + error (0, errno, "cannot read from stdin"); + if (unlink_file (fname) < 0) + error (0, errno, + "warning: cannot remove temp file %s", fname); + error (1, 0, "aborting"); + } + else if (line_length == 0 + || *line == '\n' || *line == 'c' || *line == 'C') break; if (*line == 'a' || *line == 'A') - error (1, 0, "aborted by user"); + { + if (unlink_file (fname) < 0) + error (0, errno, "warning: cannot remove temp file %s", fname); + error (1, 0, "aborted by user"); + } if (*line == 'e' || *line == 'E') goto again; if (*line == '!') @@ -248,7 +376,91 @@ do_editor (dir, messagep, repository, changes) (void) printf ("Unknown input\n"); } } - (void) unlink_file (fname); + if (line) + free (line); + if (unlink_file (fname) < 0) + error (0, errno, "warning: cannot remove temp file %s", fname); + free (fname); +} + +/* Runs the user-defined verification script as part of the commit or import + process. This verification is meant to be run whether or not the user + included the -m atribute. unlike the do_editor function, this is + independant of the running of an editor for getting a message. + */ +void +do_verify (message, repository) + char *message; + char *repository; +{ + FILE *fp; + char *fname; + int retcode = 0; + +#ifdef CLIENT_SUPPORT + if (current_parsed_root->isremote) + /* The verification will happen on the server. */ + return; +#endif + + /* FIXME? Do we really want to skip this on noexec? What do we do + for the other administrative files? */ + if (noexec) + return; + + /* If there's no message, then we have nothing to verify. Can this + case happen? And if so why would we print a message? */ + if (message == NULL) + { + cvs_output ("No message to verify\n", 0); + return; + } + + /* open a temporary file, write the message to the + temp file, and close the file. */ + + if ((fp = cvs_temp_file (&fname)) == NULL) + error (1, errno, "cannot create temporary file %s", fname); + else + { + fprintf (fp, "%s", message); + if ((message)[0] == '\0' || + (message)[strlen (message) - 1] != '\n') + (void) fprintf (fp, "%s", "\n"); + if (fclose (fp) == EOF) + error (1, errno, "%s", fname); + + /* Get the name of the verification script to run */ + + if (repository != NULL) + (void) Parse_Info (CVSROOTADM_VERIFYMSG, repository, + verifymsg_proc, 0); + + /* Run the verification script */ + + if (verifymsg_script) + { + run_setup (verifymsg_script); + run_arg (fname); + if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, + RUN_NORMAL | RUN_SIGIGNORE)) != 0) + { + /* Since following error() exits, delete the temp file + now. */ + if (unlink_file (fname) < 0) + error (0, errno, "cannot remove %s", fname); + + error (1, retcode == -1 ? errno : 0, + "Message verification failed"); + } + } + + /* Delete the temp file */ + + if (unlink_file (fname) < 0) + error (0, errno, "cannot remove %s", fname); + free (fname); + } } /* @@ -264,7 +476,6 @@ rcsinfo_proc (repository, template) { static char *last_template; FILE *tfp; - char line[MAXLINELEN]; /* nothing to do if the last one included is the same as this one */ if (last_template && strcmp (last_template, template) == 0) @@ -273,16 +484,24 @@ rcsinfo_proc (repository, template) free (last_template); last_template = xstrdup (template); - if ((tfp = fopen (template, "r")) != NULL) + if ((tfp = CVS_FOPEN (template, "r")) != NULL) { - while (fgets (line, sizeof (line), tfp) != NULL) + char *line = NULL; + size_t line_chars_allocated = 0; + + while (getline (&line, &line_chars_allocated, tfp) >= 0) (void) fputs (line, fp); - (void) fclose (tfp); + if (ferror (tfp)) + error (0, errno, "warning: cannot read %s", template); + if (fclose (tfp) < 0) + error (0, errno, "warning: cannot close %s", template); + if (line) + free (line); return (0); } else { - error (0, 0, "Couldn't open rcsinfo template file %s", template); + error (0, errno, "Couldn't open rcsinfo template file %s", template); return (1); } } @@ -293,60 +512,28 @@ rcsinfo_proc (repository, template) * directory in the source repository. The log information is fed into the * specified program as standard input. */ -static char *title; static FILE *logfp; static char *message; -static char *revision; static List *changes; void -Update_Logfile (repository, xmessage, xrevision, xlogfp, xchanges) +Update_Logfile (repository, xmessage, xlogfp, xchanges) char *repository; char *xmessage; - char *xrevision; FILE *xlogfp; List *xchanges; { - char *srepos; - /* nothing to do if the list is empty */ if (xchanges == NULL || xchanges->list->next == xchanges->list) return; /* set up static vars for update_logfile_proc */ message = xmessage; - revision = xrevision; logfp = xlogfp; changes = xchanges; - /* figure out a good title string */ - srepos = Short_Repository (repository); - - /* allocate a chunk of memory to hold the title string */ - if (!str_list) - str_list = xmalloc (MAXLISTLEN); - str_list[0] = '\0'; - - type = T_TITLE; - (void) walklist (changes, title_proc, NULL); - type = T_ADDED; - (void) walklist (changes, title_proc, NULL); - type = T_MODIFIED; - (void) walklist (changes, title_proc, NULL); - type = T_REMOVED; - (void) walklist (changes, title_proc, NULL); - title = xmalloc (strlen (srepos) + strlen (str_list) + 1 + 2); /* for 's */ - (void) sprintf (title, "'%s%s'", srepos, str_list); - - /* to be nice, free up this chunk of memory */ - free (str_list); - str_list = (char *) NULL; - /* call Parse_Info to do the actual logfile updates */ (void) Parse_Info (CVSROOTADM_LOGINFO, repository, update_logfile_proc, 1); - - /* clean up */ - free (title); } /* @@ -357,59 +544,276 @@ update_logfile_proc (repository, filter) char *repository; char *filter; { - return (logfile_write (repository, filter, title, message, revision, - logfp, changes)); + return (logfile_write (repository, filter, message, logfp, changes)); } /* - * concatenate each name onto str_list + * concatenate each filename/version onto str_list */ static int title_proc (p, closure) Node *p; void *closure; { - if (p->data == (char *) type) + struct logfile_info *li; + char *c; + + li = (struct logfile_info *) p->data; + if (li->type == type) { + /* Until we decide on the correct logging solution when we add + directories or perform imports, T_TITLE nodes will only + tack on the name provided, regardless of the format string. + You can verify that this assumption is safe by checking the + code in add.c (add_directory) and import.c (import). */ + + str_list = xrealloc (str_list, strlen (str_list) + 5); (void) strcat (str_list, " "); - (void) strcat (str_list, p->key); + + if (li->type == T_TITLE) + { + str_list = xrealloc (str_list, + strlen (str_list) + strlen (p->key) + 5); + (void) strcat (str_list, p->key); + } + else + { + /* All other nodes use the format string. */ + + for (c = str_list_format; *c != '\0'; c++) + { + switch (*c) + { + case 's': + str_list = + xrealloc (str_list, + strlen (str_list) + strlen (p->key) + 5); + (void) strcat (str_list, p->key); + break; + case 'V': + str_list = + xrealloc (str_list, + (strlen (str_list) + + (li->rev_old ? strlen (li->rev_old) : 0) + + 10) + ); + (void) strcat (str_list, (li->rev_old + ? li->rev_old : "NONE")); + break; + case 'v': + str_list = + xrealloc (str_list, + (strlen (str_list) + + (li->rev_new ? strlen (li->rev_new) : 0) + + 10) + ); + (void) strcat (str_list, (li->rev_new + ? li->rev_new : "NONE")); + break; + /* All other characters, we insert an empty field (but + we do put in the comma separating it from other + fields). This way if future CVS versions add formatting + characters, one can write a loginfo file which at least + won't blow up on an old CVS. */ + } + if (*(c + 1) != '\0') + { + str_list = xrealloc (str_list, strlen (str_list) + 5); + (void) strcat (str_list, ","); + } + } + } } return (0); } /* - * Since some systems don't define this... - */ -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 256 -#endif - -/* * Writes some stuff to the logfile "filter" and returns the status of the * filter program. */ static int -logfile_write (repository, filter, title, message, revision, logfp, changes) +logfile_write (repository, filter, message, logfp, changes) char *repository; char *filter; - char *title; char *message; - char *revision; FILE *logfp; List *changes; { - char cwd[PATH_MAX]; - FILE *pipefp, *Popen (); - char *prog = xmalloc (MAXPROGLEN); + FILE *pipefp; + char *prog; char *cp; int c; + int pipestatus; + char *fmt_percent; /* the location of the percent sign + that starts the format string. */ + + /* The user may specify a format string as part of the filter. + Originally, `%s' was the only valid string. The string that + was substituted for it was: + + <repository-name> <file1> <file2> <file3> ... + + Each file was either a new directory/import (T_TITLE), or a + added (T_ADDED), modified (T_MODIFIED), or removed (T_REMOVED) + file. + + It is desirable to preserve that behavior so lots of commitlog + scripts won't die when they get this new code. At the same + time, we'd like to pass other information about the files (like + version numbers, statuses, or checkin times). + + The solution is to allow a format string that allows us to + specify those other pieces of information. The format string + will be composed of `%' followed by a single format character, + or followed by a set of format characters surrounded by `{' and + `}' as separators. The format characters are: + + s = file name + V = old version number (pre-checkin) + v = new version number (post-checkin) + + For example, valid format strings are: + + %{} + %s + %{s} + %{sVv} + + There's no reason that more items couldn't be added (like + modification date or file status [added, modified, updated, + etc.]) -- the code modifications would be minimal (logmsg.c + (title_proc) and commit.c (check_fileproc)). + + The output will be a string of tokens separated by spaces. For + backwards compatibility, the the first token will be the + repository name. The rest of the tokens will be + comma-delimited lists of the information requested in the + format string. For example, if `/u/src/master' is the + repository, `%{sVv}' is the format string, and three files + (ChangeLog, Makefile, foo.c) were modified, the output might + be: + + /u/src/master ChangeLog,1.1,1.2 Makefile,1.3,1.4 foo.c,1.12,1.13 + + Why this duplicates the old behavior when the format string is + `%s' is left as an exercise for the reader. */ + + fmt_percent = strchr (filter, '%'); + if (fmt_percent) + { + int len; + char *srepos; + char *fmt_begin, *fmt_end; /* beginning and end of the + format string specified in + filter. */ + char *fmt_continue; /* where the string continues + after the format string (we + might skip a '}') somewhere + in there... */ + + /* Grab the format string. */ + + if ((*(fmt_percent + 1) == ' ') || (*(fmt_percent + 1) == '\0')) + { + /* The percent stands alone. This is an error. We could + be treating ' ' like any other formatting character, but + using it as a formatting character seems like it would be + a mistake. */ + + /* Would be nice to also be giving the line number. */ + error (0, 0, "loginfo: '%%' not followed by formatting character"); + fmt_begin = fmt_percent + 1; + fmt_end = fmt_begin; + fmt_continue = fmt_begin; + } + else if (*(fmt_percent + 1) == '{') + { + /* The percent has a set of characters following it. */ - /* XXX <woods@web.net> -- this is gross, ugly, and a hack! FIXME! */ - /* - * A maximum of 6 %s arguments are supported in the filter - */ - (void) sprintf (prog, filter, title, title, title, title, title, title); - if ((pipefp = Popen (prog, "w")) == NULL) + fmt_begin = fmt_percent + 2; + fmt_end = strchr (fmt_begin, '}'); + if (fmt_end) + { + /* Skip over the '}' character. */ + + fmt_continue = fmt_end + 1; + } + else + { + /* There was no close brace -- assume that format + string continues to the end of the line. */ + + /* Would be nice to also be giving the line number. */ + error (0, 0, "loginfo: '}' missing"); + fmt_end = fmt_begin + strlen (fmt_begin); + fmt_continue = fmt_end; + } + } + else + { + /* The percent has a single character following it. FIXME: + %% should expand to a regular percent sign. */ + + fmt_begin = fmt_percent + 1; + fmt_end = fmt_begin + 1; + fmt_continue = fmt_end; + } + + len = fmt_end - fmt_begin; + str_list_format = xmalloc (len + 1); + strncpy (str_list_format, fmt_begin, len); + str_list_format[len] = '\0'; + + /* Allocate an initial chunk of memory. As we build up the string + we will realloc it. */ + if (!str_list) + str_list = xmalloc (1); + str_list[0] = '\0'; + + /* Add entries to the string. Don't bother looking for + entries if the format string is empty. */ + + if (str_list_format[0] != '\0') + { + type = T_TITLE; + (void) walklist (changes, title_proc, NULL); + type = T_ADDED; + (void) walklist (changes, title_proc, NULL); + type = T_MODIFIED; + (void) walklist (changes, title_proc, NULL); + type = T_REMOVED; + (void) walklist (changes, title_proc, NULL); + } + + free (str_list_format); + + /* Construct the final string. */ + + srepos = Short_Repository (repository); + + prog = cp = xmalloc ((fmt_percent - filter) + 2 * strlen (srepos) + + 2 * strlen (str_list) + strlen (fmt_continue) + + 10); + (void) memcpy (cp, filter, fmt_percent - filter); + cp += fmt_percent - filter; + *cp++ = '"'; + cp = shell_escape (cp, srepos); + cp = shell_escape (cp, str_list); + *cp++ = '"'; + (void) strcpy (cp, fmt_continue); + + /* To be nice, free up some memory. */ + + free (str_list); + str_list = (char *) NULL; + } + else + { + /* There's no format string. */ + prog = xstrdup (filter); + } + + if ((pipefp = run_popen (prog, "w")) == NULL) { if (!noexec) error (0, 0, "cannot write entry to log filter: %s", prog); @@ -417,10 +821,17 @@ logfile_write (repository, filter, title, message, revision, logfp, changes) return (1); } (void) fprintf (pipefp, "Update of %s\n", repository); - (void) fprintf (pipefp, "In directory %s:%s\n\n", hostname, - ((cp = getwd (cwd)) != NULL) ? cp : cwd); - if (revision && *revision) - (void) fprintf (pipefp, "Revision/Branch: %s\n\n", revision); + (void) fprintf (pipefp, "In directory %s:", hostname); + cp = xgetwd (); + if (cp == NULL) + fprintf (pipefp, "<cannot get working directory: %s>\n\n", + strerror (errno)); + else + { + fprintf (pipefp, "%s\n\n", cp); + free (cp); + } + setup_tmpfile (pipefp, "", changes); (void) fprintf (pipefp, "Log Message:\n%s\n", message); if (logfp != (FILE *) 0) @@ -431,7 +842,8 @@ logfile_write (repository, filter, title, message, revision, logfp, changes) (void) putc ((char) c, pipefp); } free (prog); - return (pclose (pipefp)); + pipestatus = pclose (pipefp); + return ((pipestatus == -1) || (pipestatus == 127)) ? 1 : 0; } /* @@ -457,3 +869,19 @@ editinfo_proc(repository, editor) editinfo_editor = xstrdup (editor); return (0); } + +/* This routine is calld by Parse_Info. it asigns the name of the + * message verification script to the global variable verify_script + */ +static int +verifymsg_proc (repository, script) + char *repository; + char *script; +{ + if (verifymsg_script && strcmp (verifymsg_script, script) == 0) + return (0); + if (verifymsg_script) + free (verifymsg_script); + verifymsg_script = xstrdup (script); + return (0); +} |