Annotation of src/usr.bin/cvs/logmsg.c, Revision 1.38
1.38 ! otto 1: /* $OpenBSD: logmsg.c,v 1.37 2007/01/25 22:49:39 xsa Exp $ */
1.1 jfb 2: /*
1.30 joris 3: * Copyright (c) 2007 Joris Vink <joris@openbsd.org>
1.1 jfb 4: *
1.30 joris 5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 jfb 16: */
17:
1.38 ! otto 18: #include <sys/stat.h>
! 19:
! 20: #include <errno.h>
! 21: #include <fcntl.h>
! 22: #include <string.h>
! 23: #include <unistd.h>
1.1 jfb 24:
25: #include "cvs.h"
26:
1.30 joris 27: #define CVS_LOGMSG_PREFIX "CVS:"
28: #define CVS_LOGMSG_LINE \
1.1 jfb 29: "----------------------------------------------------------------------"
30:
1.17 xsa 31: char *
1.30 joris 32: cvs_logmsg_read(const char *path)
1.1 jfb 33: {
1.30 joris 34: int fd;
35: BUF *bp;
36: FILE *fp;
1.1 jfb 37: size_t len;
38: struct stat st;
1.30 joris 39: char *buf, *lbuf;
40:
41: if ((fd = open(path, O_RDONLY)) == -1)
42: fatal("cvs_logmsg_read: open %s", strerror(errno));
1.1 jfb 43:
1.30 joris 44: if (fstat(fd, &st) == -1)
45: fatal("cvs_logmsg_read: fstat %s", strerror(errno));
1.1 jfb 46:
1.24 xsa 47: if (!S_ISREG(st.st_mode))
1.30 joris 48: fatal("cvs_logmsg_read: file is not a regular file");
1.1 jfb 49:
1.30 joris 50: if ((fp = fdopen(fd, "r")) == NULL)
51: fatal("cvs_logmsg_read: fdopen %s", strerror(errno));
1.1 jfb 52:
1.30 joris 53: lbuf = NULL;
54: bp = cvs_buf_alloc(st.st_size, BUF_AUTOEXT);
55: while ((buf = fgetln(fp, &len))) {
56: if (buf[len - 1] == '\n') {
57: buf[len - 1] = '\0';
58: } else {
59: lbuf = xmalloc(len + 1);
1.36 otto 60: memcpy(lbuf, buf, len);
61: lbuf[len] = '\0';
1.30 joris 62: buf = lbuf;
63: }
1.1 jfb 64:
1.30 joris 65: len = strlen(buf);
1.1 jfb 66: if (len == 0)
67: continue;
1.30 joris 68:
69: if (!strncmp(buf, CVS_LOGMSG_PREFIX,
70: strlen(CVS_LOGMSG_PREFIX)))
1.1 jfb 71: continue;
72:
1.30 joris 73: cvs_buf_append(bp, buf, len);
74: cvs_buf_putc(bp, '\n');
75: }
76:
77: if (lbuf != NULL)
78: xfree(lbuf);
1.1 jfb 79:
1.11 jfb 80: (void)fclose(fp);
81:
1.23 xsa 82: cvs_buf_putc(bp, '\0');
1.30 joris 83: return (cvs_buf_release(bp));
1.1 jfb 84: }
85:
1.17 xsa 86: char *
1.30 joris 87: cvs_logmsg_create(struct cvs_flisthead *added, struct cvs_flisthead *removed,
88: struct cvs_flisthead *modified)
1.1 jfb 89: {
90: FILE *fp;
1.34 xsa 91: int c, fd, argc, saved_errno;
1.30 joris 92: struct cvs_filelist *cf;
1.1 jfb 93: struct stat st1, st2;
1.30 joris 94: char *fpath, *logmsg, *argv[4];
1.8 jfb 95:
1.35 xsa 96: (void)xasprintf(&fpath, "%s/cvsXXXXXXXXXX", cvs_tmpdir);
1.1 jfb 97:
1.30 joris 98: if ((fd = mkstemp(fpath)) == NULL)
99: fatal("cvs_logmsg_create: mkstemp %s", strerror(errno));
1.33 joris 100:
101: cvs_worklist_add(fpath, &temp_files);
1.1 jfb 102:
1.24 xsa 103: if ((fp = fdopen(fd, "w")) == NULL) {
1.34 xsa 104: saved_errno = errno;
1.30 joris 105: (void)unlink(fpath);
1.34 xsa 106: fatal("cvs_logmsg_create: fdopen %s", strerror(saved_errno));
1.8 jfb 107: }
1.1 jfb 108:
1.8 jfb 109: fprintf(fp, "\n%s %s\n%s Enter Log. Lines beginning with `%s' are "
110: "removed automatically\n%s\n", CVS_LOGMSG_PREFIX, CVS_LOGMSG_LINE,
111: CVS_LOGMSG_PREFIX, CVS_LOGMSG_PREFIX, CVS_LOGMSG_PREFIX);
112:
1.31 joris 113: if (added != NULL && !TAILQ_EMPTY(added)) {
1.30 joris 114: fprintf(fp, "%s Added Files:", CVS_LOGMSG_PREFIX);
115: TAILQ_FOREACH(cf, added, flist)
116: fprintf(fp, "\n%s\t%s",
117: CVS_LOGMSG_PREFIX, cf->file_path);
118: fputs("\n", fp);
119: }
120:
1.31 joris 121: if (removed != NULL && !TAILQ_EMPTY(removed)) {
1.30 joris 122: fprintf(fp, "%s Removed Files:", CVS_LOGMSG_PREFIX);
123: TAILQ_FOREACH(cf, removed, flist)
124: fprintf(fp, "\n%s\t%s",
125: CVS_LOGMSG_PREFIX, cf->file_path);
126: fputs("\n", fp);
127: }
128:
1.31 joris 129: if (modified != NULL && !TAILQ_EMPTY(modified)) {
1.30 joris 130: fprintf(fp, "%s Modified Files:", CVS_LOGMSG_PREFIX);
131: TAILQ_FOREACH(cf, modified, flist)
132: fprintf(fp, "\n%s\t%s",
133: CVS_LOGMSG_PREFIX, cf->file_path);
134: fputs("\n", fp);
135: }
1.1 jfb 136:
1.9 jfb 137: fprintf(fp, "%s %s\n", CVS_LOGMSG_PREFIX, CVS_LOGMSG_LINE);
1.1 jfb 138: (void)fflush(fp);
139:
140: if (fstat(fd, &st1) == -1) {
1.34 xsa 141: saved_errno = errno;
1.30 joris 142: (void)unlink(fpath);
1.34 xsa 143: fatal("cvs_logmsg_create: fstat %s", strerror(saved_errno));
1.1 jfb 144: }
145:
1.30 joris 146: argc = 0;
147: argv[argc++] = cvs_editor;
148: argv[argc++] = fpath;
149: argv[argc] = NULL;
150:
151: logmsg = NULL;
152:
1.1 jfb 153: for (;;) {
1.30 joris 154: if (cvs_exec(argc, argv) < 0)
1.1 jfb 155: break;
1.8 jfb 156:
1.1 jfb 157: if (fstat(fd, &st2) == -1) {
1.34 xsa 158: saved_errno = errno;
1.30 joris 159: (void)unlink(fpath);
1.34 xsa 160: fatal("cvs_logmsg_create: fstat %s",
161: strerror(saved_errno));
1.1 jfb 162: }
163:
1.30 joris 164: if (st1.st_mtime != st2.st_mtime) {
165: logmsg = cvs_logmsg_read(fpath);
1.1 jfb 166: break;
167: }
168:
1.30 joris 169: printf("\nLog message unchanged or not specified\n"
1.32 jasper 170: "a)bort, c)ontinue, e)dit\nAction: (continue) ");
1.30 joris 171: (void)fflush(stdout);
172:
173: c = getc(stdin);
174: if (c == 'a') {
175: fatal("Aborted by user");
176: } else if (c == '\n' || c == 'c') {
177: logmsg = xstrdup("");
1.1 jfb 178: break;
1.30 joris 179: } else if (c == 'e') {
1.1 jfb 180: continue;
1.30 joris 181: } else {
182: cvs_log(LP_ERR, "invalid input");
1.1 jfb 183: continue;
184: }
185: }
186:
187: (void)fclose(fp);
1.30 joris 188: (void)unlink(fpath);
189: xfree(fpath);
1.1 jfb 190:
1.30 joris 191: return (logmsg);
1.1 jfb 192: }