Annotation of src/usr.bin/mg/log.c, Revision 1.5
1.5 ! lum 1: /* $OpenBSD: log.c,v 1.4 2019/06/12 06:01:26 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.1 lum 24: */
25:
26: #include <sys/queue.h>
27: #include <sys/stat.h>
28: #include <ctype.h>
29: #include <fcntl.h>
30: #include <signal.h>
31: #include <stdio.h>
32: #include <stdlib.h>
33: #include <string.h>
34: #include <unistd.h>
35:
36: #include "def.h"
37: #include "log.h"
38: #include "funmap.h"
39:
1.2 lum 40: char *mglogfiles_create(char *);
41: int mglog_lines(PF);
42: int mglog_undo(void);
43:
44: char *mglogdir;
45: extern char *mglogpath_lines;
46: extern char *mglogpath_undo;
47: int mgloglevel;
1.1 lum 48:
49: int
50: mglog(PF funct)
51: {
1.2 lum 52: if(!mglog_lines(funct))
53: ewprintf("Problem logging lines");
54: if(!mglog_undo())
55: ewprintf("Problem logging undo");
56:
57: return (TRUE);
58: }
59:
60:
61: int
62: mglog_undo(void)
63: {
64: struct undo_rec *rec;
65: struct stat sb;
66: FILE *fd;
67: char buf[4096], tmp[1024];
68: int num;
69: char *jptr;
70:
71: jptr = "^J"; /* :) */
72:
73: if(stat(mglogpath_undo, &sb))
74: return (FALSE);
75: fd = fopen(mglogpath_undo, "a");
76:
77: /*
78: * From undo_dump()
79: */
80: num = 0;
81: TAILQ_FOREACH(rec, &curbp->b_undo, next) {
82: num++;
83: if (fprintf(fd, "%d:\t %s at %d ", num,
84: (rec->type == DELETE) ? "DELETE":
85: (rec->type == DELREG) ? "DELREGION":
86: (rec->type == INSERT) ? "INSERT":
87: (rec->type == BOUNDARY) ? "----" :
88: (rec->type == MODIFIED) ? "MODIFIED": "UNKNOWN",
89: rec->pos) == -1) {
90: fclose(fd);
91: return (FALSE);
92: }
93: if (rec->content) {
94: (void)strlcat(buf, "\"", sizeof(buf));
95: snprintf(tmp, sizeof(tmp), "%.*s",
96: *rec->content == '\n' ? 2 : rec->region.r_size,
97: *rec->content == '\n' ? jptr : rec->content);
98: (void)strlcat(buf, tmp, sizeof(buf));
99: (void)strlcat(buf, "\"", sizeof(buf));
100: }
101: snprintf(tmp, sizeof(tmp), " [%d]", rec->region.r_size);
102: if (strlcat(buf, tmp, sizeof(buf)) >= sizeof(buf)) {
103: dobeep();
104: ewprintf("Undo record too large. Aborted.");
105: return (FALSE);
106: }
107: if (fprintf(fd, "%s\n", buf) == -1) {
108: fclose(fd);
109: return (FALSE);
110: }
111: tmp[0] = buf[0] = '\0';
112: }
113: if (fprintf(fd, "\t [end-of-undo]\n\n") == -1) {
114: fclose(fd);
115: return (FALSE);
116: }
117: fclose(fd);
118:
119: return (TRUE);
120: }
121:
122: int
123: mglog_lines(PF funct)
124: {
1.1 lum 125: struct line *lp;
126: struct stat sb;
1.5 ! lum 127: char *curline, *tmp, o;
1.1 lum 128: FILE *fd;
129: int i;
130:
131: i = 0;
132:
1.2 lum 133: if(stat(mglogpath_lines, &sb))
1.1 lum 134: return (FALSE);
135:
1.2 lum 136: fd = fopen(mglogpath_lines, "a");
1.1 lum 137: if (fprintf(fd, "%s\n", function_name(funct)) == -1) {
138: fclose(fd);
139: return (FALSE);
140: }
141: lp = bfirstlp(curbp);
142:
143: for(;;) {
144: i++;
145: curline = " ";
1.5 ! lum 146: o = ' ';
! 147: if (i == curwp->w_dotline) {
1.1 lum 148: curline = ">";
1.5 ! lum 149: if (lp->l_used > 0 && curwp->w_doto < lp->l_used)
! 150: o = lp->l_text[curwp->w_doto];
! 151: else
! 152: o = '-';
! 153: }
! 154: if (lp->l_size == 0)
! 155: tmp = " ";
! 156: else
! 157: tmp = lp->l_text;
! 158:
! 159: if (fprintf(fd, "%s%p b^%p f.%p %d %d\t%c|%s\n", curline,
1.1 lum 160: lp, lp->l_bp, lp->l_fp,
1.5 ! lum 161: lp->l_size, lp->l_used, o, tmp) == -1) {
1.1 lum 162: fclose(fd);
163: return (FALSE);
164: }
165: lp = lforw(lp);
166: if (lp == curbp->b_headp) {
167: if (fprintf(fd, " %p b^%p f.%p [bhead]\n(EOB)\n",
168: lp, lp->l_bp, lp->l_fp) == -1) {
169: fclose(fd);
170: return (FALSE);
171: }
1.2 lum 172: if (fprintf(fd, "lines:raw:%d buf:%d wdot:%d\n\n",
1.3 lum 173: i, curbp->b_lines, curwp->w_dotline) == -1) {
1.1 lum 174: fclose(fd);
175: return (FALSE);
176: }
177: break;
178: }
179: }
180: fclose(fd);
181:
182: return (TRUE);
183: }
184:
185:
186: /*
1.2 lum 187: * Make sure logging to log files can happen.
1.1 lum 188: */
189: int
190: mgloginit(void)
191: {
192: struct stat sb;
193: mode_t dir_mode, f_mode, oumask;
1.2 lum 194: char *mglogfile_lines, *mglogfile_undo;
1.1 lum 195:
196: mglogdir = "./log/";
1.2 lum 197: mglogfile_lines = "line.log";
198: mglogfile_undo = "undo.log";
199:
200: /*
201: * Change mgloglevel for desired level of logging.
202: * log.h has relevant level info.
203: */
204: mgloglevel = 1;
1.1 lum 205:
206: oumask = umask(0);
207: f_mode = 0777& ~oumask;
208: dir_mode = f_mode | S_IWUSR | S_IXUSR;
209:
210: if(stat(mglogdir, &sb)) {
211: if (mkdir(mglogdir, dir_mode) != 0)
212: return (FALSE);
213: if (chmod(mglogdir, f_mode) < 0)
214: return (FALSE);
215: }
1.2 lum 216: mglogpath_lines = mglogfiles_create(mglogfile_lines);
217: if (mglogpath_lines == NULL)
1.1 lum 218: return (FALSE);
1.2 lum 219: mglogpath_undo = mglogfiles_create(mglogfile_undo);
220: if (mglogpath_undo == NULL)
1.1 lum 221: return (FALSE);
222:
1.2 lum 223: return (TRUE);
224: }
225:
226:
227: char *
228: mglogfiles_create(char *mglogfile)
229: {
230: struct stat sb;
231: char tmp[20], *tmp2;
232: int fd;
233:
234: if (strlcpy(tmp, mglogdir, sizeof(tmp)) >
235: sizeof(tmp))
236: return (NULL);
237: if (strlcat(tmp, mglogfile, sizeof(tmp)) >
238: sizeof(tmp))
239: return (NULL);
240: if ((tmp2 = strndup(tmp, 20)) == NULL)
241: return (NULL);
242:
243: if(stat(tmp2, &sb))
244: fd = open(tmp2, O_RDWR | O_CREAT | O_TRUNC, 0644);
1.1 lum 245: else
1.2 lum 246: fd = open(tmp2, O_RDWR | O_TRUNC, 0644);
1.1 lum 247:
248: if (fd == -1)
1.2 lum 249: return (NULL);
1.1 lum 250:
251: close(fd);
252:
1.2 lum 253: return (tmp2);
1.1 lum 254: }