Annotation of src/usr.bin/mg/log.c, Revision 1.7
1.7 ! lum 1: /* $OpenBSD: log.c,v 1.6 2019/06/14 14:27:42 lum Exp $ */
1.1 lum 2:
3: /*
4: * This file is in the public domain.
5: *
6: * Author: Mark Lumsden <mark@showcomplex.com>
7: *
8: */
9:
10: /*
11: * Record a history of an mg session for temporal debugging.
12: * Sometimes pressing a key will set the scene for a bug only visible
13: * dozens of keystrokes later. gdb has its limitations in this scenario.
1.4 lum 14: *
15: * Note this file is not compiled into mg by default, you will need to
16: * amend the 'Makefile' for that to happen. Because of this, the code
17: * is subjet to bit-rot. However, I know myself and others have
18: * written similar functionally often enough, that recording the below
19: * in a code repository could aid the developement efforts of mg, even
20: * if it requires a bit of effort to get working. The current code is
21: * written in the spirit of debugging (quickly and perhaps not ideal,
22: * but it does what is required well enough). Should debugging become
23: * more formalised within mg, then I would expect that to change.
1.6 lum 24: *
25: * If you open a file with long lines to run through this debugging
26: * code, you may run into problems with the 1st fprintf statement in
27: * in the mglog_lines() function. mg sometimes segvs at a strlen call
28: * in fprintf - possibly something to do with the format string?
29: * "%s%p b^%p f.%p %d %d\t%c|%s\n"
30: * When I get time I will look into it. But since my debugging
31: * generally revolves around a file like:
32: *
33: * abc
34: * def
35: * ghk
36: *
37: * I don't experience this bug. Just note it for future investigation.
1.1 lum 38: */
39:
40: #include <sys/queue.h>
41: #include <sys/stat.h>
42: #include <ctype.h>
43: #include <fcntl.h>
44: #include <signal.h>
45: #include <stdio.h>
46: #include <stdlib.h>
47: #include <string.h>
48: #include <unistd.h>
49:
50: #include "def.h"
51: #include "log.h"
52: #include "funmap.h"
53:
1.2 lum 54: char *mglogfiles_create(char *);
55: int mglog_lines(PF);
56: int mglog_undo(void);
1.7 ! lum 57: int mglog_window(void);
1.2 lum 58:
59: char *mglogdir;
60: extern char *mglogpath_lines;
61: extern char *mglogpath_undo;
1.7 ! lum 62: extern char *mglogpath_window;
1.2 lum 63: int mgloglevel;
1.1 lum 64:
65: int
66: mglog(PF funct)
67: {
1.2 lum 68: if(!mglog_lines(funct))
69: ewprintf("Problem logging lines");
70: if(!mglog_undo())
71: ewprintf("Problem logging undo");
1.7 ! lum 72: if(!mglog_window())
! 73: ewprintf("Problem logging window");
1.2 lum 74:
75: return (TRUE);
76: }
77:
78:
79: int
1.7 ! lum 80: mglog_window(void)
! 81: {
! 82: struct mgwin *wp;
! 83: struct stat sb;
! 84: FILE *fd;
! 85: int i;
! 86:
! 87: if(stat(mglogpath_window, &sb))
! 88: return (FALSE);
! 89: fd = fopen(mglogpath_window, "a");
! 90:
! 91: for (wp = wheadp, i = 0; wp != NULL; wp = wp->w_wndp, ++i) {
! 92: if (fprintf(fd,
! 93: "%d wh%p wlst%p wbfp%p wlp%p wdtp%p wmkp%p wdto%d wmko%d" \
! 94: " wtpr%d wntr%d wfrm%d wrfl%c wflg%c wwrl%p wdtl%d" \
! 95: " wmkl%d\n",
! 96: i,
! 97: wp,
! 98: &wp->w_list,
! 99: wp->w_bufp,
! 100: wp->w_linep,
! 101: wp->w_dotp,
! 102: wp->w_markp,
! 103: wp->w_doto,
! 104: wp->w_marko,
! 105: wp->w_toprow,
! 106: wp->w_ntrows,
! 107: wp->w_frame,
! 108: wp->w_rflag,
! 109: wp->w_flag,
! 110: wp->w_wrapline,
! 111: wp->w_dotline,
! 112: wp->w_markline) == -1) {
! 113: fclose(fd);
! 114: return (FALSE);
! 115: }
! 116: }
! 117: fclose(fd);
! 118: return (TRUE);
! 119: }
! 120:
! 121: int
1.2 lum 122: mglog_undo(void)
123: {
124: struct undo_rec *rec;
125: struct stat sb;
126: FILE *fd;
127: char buf[4096], tmp[1024];
128: int num;
129: char *jptr;
130:
131: jptr = "^J"; /* :) */
132:
133: if(stat(mglogpath_undo, &sb))
134: return (FALSE);
135: fd = fopen(mglogpath_undo, "a");
136:
137: /*
138: * From undo_dump()
139: */
140: num = 0;
141: TAILQ_FOREACH(rec, &curbp->b_undo, next) {
142: num++;
143: if (fprintf(fd, "%d:\t %s at %d ", num,
144: (rec->type == DELETE) ? "DELETE":
145: (rec->type == DELREG) ? "DELREGION":
146: (rec->type == INSERT) ? "INSERT":
147: (rec->type == BOUNDARY) ? "----" :
148: (rec->type == MODIFIED) ? "MODIFIED": "UNKNOWN",
149: rec->pos) == -1) {
150: fclose(fd);
151: return (FALSE);
152: }
153: if (rec->content) {
154: (void)strlcat(buf, "\"", sizeof(buf));
155: snprintf(tmp, sizeof(tmp), "%.*s",
156: *rec->content == '\n' ? 2 : rec->region.r_size,
157: *rec->content == '\n' ? jptr : rec->content);
158: (void)strlcat(buf, tmp, sizeof(buf));
159: (void)strlcat(buf, "\"", sizeof(buf));
160: }
161: snprintf(tmp, sizeof(tmp), " [%d]", rec->region.r_size);
162: if (strlcat(buf, tmp, sizeof(buf)) >= sizeof(buf)) {
163: dobeep();
164: ewprintf("Undo record too large. Aborted.");
165: return (FALSE);
166: }
167: if (fprintf(fd, "%s\n", buf) == -1) {
168: fclose(fd);
169: return (FALSE);
170: }
171: tmp[0] = buf[0] = '\0';
172: }
173: if (fprintf(fd, "\t [end-of-undo]\n\n") == -1) {
174: fclose(fd);
175: return (FALSE);
176: }
177: fclose(fd);
178:
179: return (TRUE);
180: }
181:
182: int
183: mglog_lines(PF funct)
184: {
1.1 lum 185: struct line *lp;
186: struct stat sb;
1.5 lum 187: char *curline, *tmp, o;
1.1 lum 188: FILE *fd;
189: int i;
190:
191: i = 0;
192:
1.2 lum 193: if(stat(mglogpath_lines, &sb))
1.1 lum 194: return (FALSE);
195:
1.2 lum 196: fd = fopen(mglogpath_lines, "a");
1.1 lum 197: if (fprintf(fd, "%s\n", function_name(funct)) == -1) {
198: fclose(fd);
199: return (FALSE);
200: }
201: lp = bfirstlp(curbp);
202:
203: for(;;) {
204: i++;
205: curline = " ";
1.5 lum 206: o = ' ';
207: if (i == curwp->w_dotline) {
1.1 lum 208: curline = ">";
1.5 lum 209: if (lp->l_used > 0 && curwp->w_doto < lp->l_used)
210: o = lp->l_text[curwp->w_doto];
211: else
212: o = '-';
213: }
214: if (lp->l_size == 0)
215: tmp = " ";
216: else
217: tmp = lp->l_text;
218:
1.6 lum 219: /* segv on fprintf below with long lines */
1.5 lum 220: if (fprintf(fd, "%s%p b^%p f.%p %d %d\t%c|%s\n", curline,
1.1 lum 221: lp, lp->l_bp, lp->l_fp,
1.5 lum 222: lp->l_size, lp->l_used, o, tmp) == -1) {
1.1 lum 223: fclose(fd);
224: return (FALSE);
225: }
226: lp = lforw(lp);
227: if (lp == curbp->b_headp) {
228: if (fprintf(fd, " %p b^%p f.%p [bhead]\n(EOB)\n",
229: lp, lp->l_bp, lp->l_fp) == -1) {
230: fclose(fd);
231: return (FALSE);
232: }
1.2 lum 233: if (fprintf(fd, "lines:raw:%d buf:%d wdot:%d\n\n",
1.3 lum 234: i, curbp->b_lines, curwp->w_dotline) == -1) {
1.1 lum 235: fclose(fd);
236: return (FALSE);
237: }
238: break;
239: }
240: }
241: fclose(fd);
242:
243: return (TRUE);
244: }
245:
246:
247: /*
1.2 lum 248: * Make sure logging to log files can happen.
1.1 lum 249: */
250: int
251: mgloginit(void)
252: {
253: struct stat sb;
254: mode_t dir_mode, f_mode, oumask;
1.7 ! lum 255: char *mglogfile_lines, *mglogfile_undo, *mglogfile_window;
1.1 lum 256:
257: mglogdir = "./log/";
1.2 lum 258: mglogfile_lines = "line.log";
259: mglogfile_undo = "undo.log";
1.7 ! lum 260: mglogfile_window = "window.log";
1.2 lum 261:
262: /*
263: * Change mgloglevel for desired level of logging.
264: * log.h has relevant level info.
265: */
266: mgloglevel = 1;
1.1 lum 267:
268: oumask = umask(0);
269: f_mode = 0777& ~oumask;
270: dir_mode = f_mode | S_IWUSR | S_IXUSR;
271:
272: if(stat(mglogdir, &sb)) {
273: if (mkdir(mglogdir, dir_mode) != 0)
274: return (FALSE);
275: if (chmod(mglogdir, f_mode) < 0)
276: return (FALSE);
277: }
1.2 lum 278: mglogpath_lines = mglogfiles_create(mglogfile_lines);
279: if (mglogpath_lines == NULL)
1.1 lum 280: return (FALSE);
1.2 lum 281: mglogpath_undo = mglogfiles_create(mglogfile_undo);
282: if (mglogpath_undo == NULL)
1.7 ! lum 283: return (FALSE);
! 284: mglogpath_window = mglogfiles_create(mglogfile_window);
! 285: if (mglogpath_window == NULL)
1.1 lum 286: return (FALSE);
287:
1.2 lum 288: return (TRUE);
289: }
290:
291:
292: char *
293: mglogfiles_create(char *mglogfile)
294: {
295: struct stat sb;
296: char tmp[20], *tmp2;
297: int fd;
298:
299: if (strlcpy(tmp, mglogdir, sizeof(tmp)) >
300: sizeof(tmp))
301: return (NULL);
302: if (strlcat(tmp, mglogfile, sizeof(tmp)) >
303: sizeof(tmp))
304: return (NULL);
305: if ((tmp2 = strndup(tmp, 20)) == NULL)
306: return (NULL);
307:
308: if(stat(tmp2, &sb))
309: fd = open(tmp2, O_RDWR | O_CREAT | O_TRUNC, 0644);
1.1 lum 310: else
1.2 lum 311: fd = open(tmp2, O_RDWR | O_TRUNC, 0644);
1.1 lum 312:
313: if (fd == -1)
1.2 lum 314: return (NULL);
1.1 lum 315:
316: close(fd);
317:
1.2 lum 318: return (tmp2);
1.1 lum 319: }