xref: /openbsd-src/usr.bin/mg/log.c (revision d9a51c353c88dac7b4a389c112b4cfe97b8e3a46)
1*d9a51c35Sjmc /*	$OpenBSD: log.c,v 1.13 2022/12/26 19:16:02 jmc Exp $	*/
285c5a5c1Slum 
385c5a5c1Slum /*
485c5a5c1Slum  * This file is in the public domain.
585c5a5c1Slum  *
685c5a5c1Slum  * Author: Mark Lumsden <mark@showcomplex.com>
785c5a5c1Slum  *
885c5a5c1Slum  */
985c5a5c1Slum 
1085c5a5c1Slum /*
1185c5a5c1Slum  * Record a history of an mg session for temporal debugging.
1285c5a5c1Slum  * Sometimes pressing a key will set the scene for a bug only visible
1385c5a5c1Slum  * dozens of keystrokes later. gdb has its limitations in this scenario.
149e4cdb22Slum  *
159e4cdb22Slum  * Note this file is not compiled into mg by default, you will need to
169e4cdb22Slum  * amend the 'Makefile' for that to happen. Because of this, the code
17f1eb72faSlum  * is subject to bit-rot. However, I know myself and others have
189e4cdb22Slum  * written similar functionally often enough, that recording the below
19*d9a51c35Sjmc  * in a code repository could aid the development efforts of mg, even
209e4cdb22Slum  * if it requires a bit of effort to get working. The current code is
219e4cdb22Slum  * written in the spirit of debugging (quickly and perhaps not ideal,
229e4cdb22Slum  * but it does what is required well enough). Should debugging become
239e4cdb22Slum  * more formalised within mg, then I would expect that to change.
24513dea04Slum  *
25513dea04Slum  * If you open a file with long lines to run through this debugging
26513dea04Slum  * code, you may run into problems with the 1st fprintf statement in
27513dea04Slum  * in the mglog_lines() function. mg sometimes segvs at a strlen call
28513dea04Slum  * in fprintf - possibly something to do with the format string?
29513dea04Slum  * 	"%s%p b^%p f.%p %d %d\t%c|%s\n"
30513dea04Slum  * When I get time I will look into it. But since my debugging
31513dea04Slum  * generally revolves around a file like:
32513dea04Slum  *
33513dea04Slum  * abc
34513dea04Slum  * def
35513dea04Slum  * ghk
36513dea04Slum  *
37513dea04Slum  * I don't experience this bug. Just note it for future investigation.
3885c5a5c1Slum  */
3985c5a5c1Slum 
4085c5a5c1Slum #include <sys/queue.h>
4185c5a5c1Slum #include <sys/stat.h>
4285c5a5c1Slum #include <ctype.h>
4385c5a5c1Slum #include <fcntl.h>
4485c5a5c1Slum #include <signal.h>
4585c5a5c1Slum #include <stdio.h>
4685c5a5c1Slum #include <stdlib.h>
4785c5a5c1Slum #include <string.h>
4885c5a5c1Slum #include <unistd.h>
4915cbecf0Slum #include <stdarg.h>
5085c5a5c1Slum 
5185c5a5c1Slum #include "def.h"
52de8bce61Slum #include "key.h"
53de8bce61Slum #include "kbd.h"
5485c5a5c1Slum #include "funmap.h"
55de8bce61Slum #include "chrdef.h"
56de8bce61Slum 
57de8bce61Slum #include "log.h"
5885c5a5c1Slum 
5915cbecf0Slum static char	*mglogfiles_create(FILE **, char *);
607bf68b76Slum static int	 mglog_lines(PF);
617bf68b76Slum static int	 mglog_undo(void);
627bf68b76Slum static int	 mglog_window(void);
637bf68b76Slum static int	 mglog_key(KEYMAP *map);
64066b333aSlum 
6515cbecf0Slum const char	*mglogdir;
6615cbecf0Slum const char	*mglogpath_lines;
6715cbecf0Slum const char	*mglogpath_undo;
6815cbecf0Slum const char	*mglogpath_window;
6915cbecf0Slum const char	*mglogpath_key;
7015cbecf0Slum const char    	*mglogpath_interpreter;
7115cbecf0Slum const char	*mglogpath_misc;
72066b333aSlum int		 mgloglevel;
7385c5a5c1Slum 
7415cbecf0Slum FILE		*fd_lines;
7515cbecf0Slum FILE		*fd_undo;
7615cbecf0Slum FILE		*fd_window;
7715cbecf0Slum FILE		*fd_key;
7815cbecf0Slum FILE		*fd_interpreter;
7915cbecf0Slum FILE		*fd_misc;
8015cbecf0Slum 
8185c5a5c1Slum int
mglog(PF funct,void * map)8215cbecf0Slum mglog(PF funct, void *map)
8385c5a5c1Slum {
84066b333aSlum 	if(!mglog_lines(funct))
85066b333aSlum 		ewprintf("Problem logging lines");
86066b333aSlum 	if(!mglog_undo())
87066b333aSlum 		ewprintf("Problem logging undo");
88075adcaaSlum 	if(!mglog_window())
89075adcaaSlum 		ewprintf("Problem logging window");
90de8bce61Slum 	if(!mglog_key(map))
91de8bce61Slum 		ewprintf("Problem logging key");
92066b333aSlum 
93066b333aSlum 	return (TRUE);
94066b333aSlum }
95066b333aSlum 
96066b333aSlum 
977bf68b76Slum static int
mglog_key(KEYMAP * map)98de8bce61Slum mglog_key(KEYMAP *map)
99de8bce61Slum {
100de8bce61Slum 	PF		*pfp;
101de8bce61Slum 
102de8bce61Slum 	if (ISWORD(*key.k_chars)) {
10315cbecf0Slum 		fprintf(fd_key, "k_count:%d k_chars:%hd\tchr:%c\t", key.k_count,
10415cbecf0Slum 		    *key.k_chars, CHARMASK(*key.k_chars));
105de8bce61Slum 	} else {
10615cbecf0Slum 		fprintf(fd_key, "k_count:%d k_chars:%hd\t\t", key.k_count,
10715cbecf0Slum 		    *key.k_chars);
108de8bce61Slum 	}
10915cbecf0Slum 	fprintf(fd_key, "map:%p %d %d %p %hd %hd\n",
110de8bce61Slum 	    map,
111de8bce61Slum 	    map->map_num,
112de8bce61Slum 	    map->map_max,
113de8bce61Slum 	    map->map_default,
114de8bce61Slum 	    map->map_element->k_base,
115de8bce61Slum 	    map->map_element->k_num
11615cbecf0Slum 	    );
11715cbecf0Slum 	for (pfp = map->map_element->k_funcp; *pfp != NULL; pfp++)
11815cbecf0Slum 		fprintf(fd_key, "%s ", function_name(*pfp));
119de8bce61Slum 
12015cbecf0Slum 	fprintf(fd_key, "\n\n");
12115cbecf0Slum 	fflush(fd_key);
122de8bce61Slum 	return (TRUE);
123de8bce61Slum }
124de8bce61Slum 
1257bf68b76Slum static int
mglog_window(void)126075adcaaSlum mglog_window(void)
127075adcaaSlum {
128075adcaaSlum 	struct mgwin	*wp;
129075adcaaSlum 	int		 i;
130075adcaaSlum 
131075adcaaSlum 	for (wp = wheadp, i = 0; wp != NULL; wp = wp->w_wndp, ++i) {
13215cbecf0Slum 		fprintf(fd_window,
133075adcaaSlum 		    "%d wh%p wlst%p wbfp%p wlp%p wdtp%p wmkp%p wdto%d wmko%d" \
134075adcaaSlum 		    " wtpr%d wntr%d wfrm%d wrfl%c wflg%c wwrl%p wdtl%d" \
135075adcaaSlum 		    " wmkl%d\n",
136075adcaaSlum 		    i,
137075adcaaSlum 		    wp,
138075adcaaSlum 		    &wp->w_list,
139075adcaaSlum 		    wp->w_bufp,
140075adcaaSlum 		    wp->w_linep,
141075adcaaSlum 		    wp->w_dotp,
142075adcaaSlum 		    wp->w_markp,
143075adcaaSlum 		    wp->w_doto,
144075adcaaSlum 		    wp->w_marko,
145075adcaaSlum 		    wp->w_toprow,
146075adcaaSlum 		    wp->w_ntrows,
147075adcaaSlum 		    wp->w_frame,
148075adcaaSlum 		    wp->w_rflag,
149075adcaaSlum 		    wp->w_flag,
150075adcaaSlum 		    wp->w_wrapline,
151075adcaaSlum 		    wp->w_dotline,
15215cbecf0Slum 		    wp->w_markline
15315cbecf0Slum 		    );
154075adcaaSlum 	}
15515cbecf0Slum 	fflush(fd_window);
156075adcaaSlum 	return (TRUE);
157075adcaaSlum }
158075adcaaSlum 
1597bf68b76Slum static int
mglog_undo(void)160066b333aSlum mglog_undo(void)
161066b333aSlum {
162066b333aSlum 	struct undo_rec	*rec;
163066b333aSlum 	char		 buf[4096], tmp[1024];
164066b333aSlum 	int      	 num;
165066b333aSlum 	char		*jptr;
166066b333aSlum 
167066b333aSlum 	jptr = "^J"; /* :) */
168066b333aSlum 	/*
169066b333aSlum 	 * From undo_dump()
170066b333aSlum 	 */
171066b333aSlum 	num = 0;
172066b333aSlum 	TAILQ_FOREACH(rec, &curbp->b_undo, next) {
173066b333aSlum 		num++;
17415cbecf0Slum 		fprintf(fd_undo, "%d:\t %s at %d ", num,
175066b333aSlum 		    (rec->type == DELETE) ? "DELETE":
176066b333aSlum 		    (rec->type == DELREG) ? "DELREGION":
177066b333aSlum 		    (rec->type == INSERT) ? "INSERT":
178066b333aSlum 		    (rec->type == BOUNDARY) ? "----" :
179066b333aSlum 		    (rec->type == MODIFIED) ? "MODIFIED": "UNKNOWN",
18015cbecf0Slum 		    rec->pos
18115cbecf0Slum 		    );
182066b333aSlum 		if (rec->content) {
183066b333aSlum 			(void)strlcat(buf, "\"", sizeof(buf));
184066b333aSlum 			snprintf(tmp, sizeof(tmp), "%.*s",
185066b333aSlum 			    *rec->content == '\n' ? 2 : rec->region.r_size,
186066b333aSlum 			    *rec->content == '\n' ? jptr : rec->content);
187066b333aSlum 			(void)strlcat(buf, tmp, sizeof(buf));
188066b333aSlum 			(void)strlcat(buf, "\"", sizeof(buf));
189066b333aSlum 		}
190066b333aSlum 		snprintf(tmp, sizeof(tmp), " [%d]", rec->region.r_size);
191066b333aSlum 		if (strlcat(buf, tmp, sizeof(buf)) >= sizeof(buf)) {
192066b333aSlum 			dobeep();
193066b333aSlum 			ewprintf("Undo record too large. Aborted.");
194066b333aSlum 			return (FALSE);
195066b333aSlum 		}
19615cbecf0Slum 		fprintf(fd_undo, "%s\n", buf);
197066b333aSlum 		tmp[0] = buf[0] = '\0';
198066b333aSlum 	}
19915cbecf0Slum 	fprintf(fd_undo, "\t [end-of-undo]\n\n");
20015cbecf0Slum 	fflush(fd_undo);
201066b333aSlum 
202066b333aSlum 	return (TRUE);
203066b333aSlum }
204066b333aSlum 
2057bf68b76Slum static int
mglog_lines(PF funct)206066b333aSlum mglog_lines(PF funct)
207066b333aSlum {
20885c5a5c1Slum 	struct line     *lp;
2095d19aa34Slum 	char		*curline, *tmp, o;
21085c5a5c1Slum 	int		 i;
21185c5a5c1Slum 
21285c5a5c1Slum 	i = 0;
21385c5a5c1Slum 
21415cbecf0Slum 	fprintf(fd_lines, "%s\n", function_name(funct));
21585c5a5c1Slum 	lp = bfirstlp(curbp);
21685c5a5c1Slum 
21785c5a5c1Slum 	for(;;) {
21885c5a5c1Slum 		i++;
21985c5a5c1Slum 		curline = " ";
2205d19aa34Slum 		o = ' ';
2215d19aa34Slum 		if (i == curwp->w_dotline) {
22285c5a5c1Slum 			curline = ">";
2235d19aa34Slum 			if (lp->l_used > 0 && curwp->w_doto < lp->l_used)
2245d19aa34Slum 				o = lp->l_text[curwp->w_doto];
2255d19aa34Slum 			else
2265d19aa34Slum 				o = '-';
2275d19aa34Slum 		}
2285d19aa34Slum 		if (lp->l_size == 0)
2295d19aa34Slum 			tmp = " ";
2305d19aa34Slum 		else
2315d19aa34Slum 			tmp = lp->l_text;
2325d19aa34Slum 
233513dea04Slum 		/* segv on fprintf below with long lines */
23415cbecf0Slum 		fprintf(fd_lines, "%s%p b^%p f.%p %d %d\t%c|%s\n", curline,
23585c5a5c1Slum 		    lp, lp->l_bp, lp->l_fp,
23615cbecf0Slum 		    lp->l_size, lp->l_used, o, tmp);
23715cbecf0Slum 
23885c5a5c1Slum 		lp = lforw(lp);
23985c5a5c1Slum 		if (lp == curbp->b_headp) {
24015cbecf0Slum 			fprintf(fd_lines, " %p b^%p f.%p [bhead]\n(EOB)\n",
24115cbecf0Slum 			    lp, lp->l_bp, lp->l_fp);
24215cbecf0Slum 
24315cbecf0Slum 			fprintf(fd_lines, "lines:raw:%d buf:%d wdot:%d\n\n",
24415cbecf0Slum 			    i, curbp->b_lines, curwp->w_dotline);
24515cbecf0Slum 
24685c5a5c1Slum 			break;
24785c5a5c1Slum 		}
24885c5a5c1Slum 	}
24915cbecf0Slum 	fflush(fd_lines);
25085c5a5c1Slum 
25185c5a5c1Slum 	return (TRUE);
25285c5a5c1Slum }
25385c5a5c1Slum 
2547bf68b76Slum /*
2557bf68b76Slum  * See what the eval variable code is up to.
2567bf68b76Slum  */
2577bf68b76Slum int
mglog_isvar(const char * const argbuf,const char * const argp,const int sizof)2587bf68b76Slum mglog_isvar(
2597bf68b76Slum 	const char* const argbuf,
2607bf68b76Slum 	const char* const argp,
2617bf68b76Slum 	const int 	  sizof
2627bf68b76Slum )
2637bf68b76Slum {
2647bf68b76Slum 
26515cbecf0Slum 	fprintf(fd_interpreter, " argbuf:%s,argp:%s,sizof:%d<\n",
2667bf68b76Slum 	    argbuf,
2677bf68b76Slum 	    argp,
26815cbecf0Slum 	    sizof);
26915cbecf0Slum 
27015cbecf0Slum 	fflush(fd_interpreter);
2717bf68b76Slum 	return (TRUE);
2727bf68b76Slum }
2737bf68b76Slum 
2747bf68b76Slum /*
2757bf68b76Slum  * See what the eval line code is up to.
2767bf68b76Slum  */
2777bf68b76Slum int
mglog_execbuf(const char * const pre,const char * const excbuf,const char * const argbuf,const char * const argp,const int last,const int inlist,const char * const cmdp,const char * const p,const char * const contbuf)2787bf68b76Slum mglog_execbuf(
2797bf68b76Slum 	const char* const pre,
2807bf68b76Slum 	const char* const excbuf,
2817bf68b76Slum 	const char* const argbuf,
2827bf68b76Slum     	const char* const argp,
2837bf68b76Slum 	const int 	  last,
2847bf68b76Slum 	const int	  inlist,
2857bf68b76Slum     	const char* const cmdp,
2867bf68b76Slum 	const char* const p,
2877bf68b76Slum 	const char* const contbuf
2887bf68b76Slum )
2897bf68b76Slum {
29015cbecf0Slum 	fprintf(fd_interpreter, "%sexcbuf:%s,argbuf:%s,argp:%s,last:%d,inlist:%d,"\
2917bf68b76Slum 	    "cmdp:%s,p:%s,contbuf:%s<\n",
2927bf68b76Slum 	    pre,
2937bf68b76Slum 	    excbuf,
2947bf68b76Slum 	    argbuf,
2957bf68b76Slum 	    argp,
2967bf68b76Slum 	    last,
2977bf68b76Slum 	    inlist,
2987bf68b76Slum 	    cmdp,
2997bf68b76Slum 	    p,
3007bf68b76Slum 	    contbuf
30115cbecf0Slum 	    );
30215cbecf0Slum 	fflush(fd_interpreter);
3037bf68b76Slum 	return (TRUE);
3047bf68b76Slum }
30585c5a5c1Slum 
30685c5a5c1Slum /*
30715cbecf0Slum  * Misc. logging for various subsystems
30815cbecf0Slum  */
30915cbecf0Slum int
mglog_misc(const char * fmt,...)31015cbecf0Slum mglog_misc(
31115cbecf0Slum 	const char *fmt,
31215cbecf0Slum 	...
31315cbecf0Slum )
31415cbecf0Slum {
31515cbecf0Slum 	va_list		ap;
31615cbecf0Slum 	int		rc;
31715cbecf0Slum 
31815cbecf0Slum 	va_start(ap, fmt);
31915cbecf0Slum 	rc = vfprintf(fd_misc, fmt, ap);
32015cbecf0Slum 	va_end(ap);
32115cbecf0Slum 	fflush(fd_misc);
32215cbecf0Slum 
32315cbecf0Slum 	if (rc < 0)
32415cbecf0Slum 		return (FALSE);
32515cbecf0Slum 
32615cbecf0Slum 	return (TRUE);
32715cbecf0Slum }
32815cbecf0Slum 
32915cbecf0Slum 
33015cbecf0Slum 
33115cbecf0Slum /*
332066b333aSlum  * Make sure logging to log files can happen.
33385c5a5c1Slum  */
33485c5a5c1Slum int
mgloginit(void)33585c5a5c1Slum mgloginit(void)
33685c5a5c1Slum {
33785c5a5c1Slum 	struct stat	 sb;
33885c5a5c1Slum 	mode_t           dir_mode, f_mode, oumask;
339075adcaaSlum 	char		*mglogfile_lines, *mglogfile_undo, *mglogfile_window;
34015cbecf0Slum 	char		*mglogfile_key, *mglogfile_interpreter, *mglogfile_misc;
34185c5a5c1Slum 
34285c5a5c1Slum 	mglogdir = "./log/";
343066b333aSlum 	mglogfile_lines = "line.log";
344066b333aSlum 	mglogfile_undo = "undo.log";
345075adcaaSlum 	mglogfile_window = "window.log";
346de8bce61Slum 	mglogfile_key = "key.log";
3477bf68b76Slum 	mglogfile_interpreter = "interpreter.log";
34815cbecf0Slum 	mglogfile_misc = "misc.log";
349066b333aSlum 
350066b333aSlum 	/*
351066b333aSlum 	 * Change mgloglevel for desired level of logging.
352066b333aSlum 	 * log.h has relevant level info.
353066b333aSlum 	 */
354066b333aSlum 	mgloglevel = 1;
35585c5a5c1Slum 
35685c5a5c1Slum 	oumask = umask(0);
35785c5a5c1Slum 	f_mode = 0777& ~oumask;
35885c5a5c1Slum 	dir_mode = f_mode | S_IWUSR | S_IXUSR;
35985c5a5c1Slum 
36085c5a5c1Slum 	if(stat(mglogdir, &sb)) {
36185c5a5c1Slum 		if (mkdir(mglogdir, dir_mode) != 0)
36285c5a5c1Slum 			return (FALSE);
3633aaa63ebSderaadt 		if (chmod(mglogdir, f_mode) == -1)
36485c5a5c1Slum 			return (FALSE);
36585c5a5c1Slum 	}
36615cbecf0Slum 	mglogpath_lines = mglogfiles_create(&fd_lines, mglogfile_lines);
367066b333aSlum 	if (mglogpath_lines == NULL)
36885c5a5c1Slum 		return (FALSE);
36915cbecf0Slum 	mglogpath_undo = mglogfiles_create(&fd_undo, mglogfile_undo);
370066b333aSlum 	if (mglogpath_undo == NULL)
37185c5a5c1Slum 		return (FALSE);
37215cbecf0Slum 	mglogpath_window = mglogfiles_create(&fd_window, mglogfile_window);
373075adcaaSlum 	if (mglogpath_window == NULL)
374075adcaaSlum 		return (FALSE);
37515cbecf0Slum 	mglogpath_key = mglogfiles_create(&fd_key, mglogfile_key);
376de8bce61Slum 	if (mglogpath_key == NULL)
377de8bce61Slum 		return (FALSE);
37815cbecf0Slum 	mglogpath_interpreter = mglogfiles_create(&fd_interpreter,
37915cbecf0Slum 	    mglogfile_interpreter);
3807bf68b76Slum 	if (mglogpath_interpreter == NULL)
3817bf68b76Slum 		return (FALSE);
38215cbecf0Slum 	mglogpath_misc = mglogfiles_create(&fd_misc, mglogfile_misc);
38315cbecf0Slum 	if (mglogpath_misc == NULL)
38415cbecf0Slum 		return (FALSE);
38585c5a5c1Slum 
386066b333aSlum 	return (TRUE);
387066b333aSlum }
388066b333aSlum 
389066b333aSlum 
3907bf68b76Slum static char *
mglogfiles_create(FILE ** fd,char * mglogfile)39115cbecf0Slum mglogfiles_create(FILE ** fd, char *mglogfile)
392066b333aSlum {
3937bf68b76Slum 	char		 tmp[NFILEN], *tmp2;
394066b333aSlum 
395066b333aSlum 	if (strlcpy(tmp, mglogdir, sizeof(tmp)) >
396066b333aSlum 	    sizeof(tmp))
397066b333aSlum 		return (NULL);
398066b333aSlum 	if (strlcat(tmp, mglogfile, sizeof(tmp)) >
399066b333aSlum 	    sizeof(tmp))
400066b333aSlum 		return (NULL);
4017bf68b76Slum 	if ((tmp2 = strndup(tmp, NFILEN)) == NULL)
402066b333aSlum 		return (NULL);
403066b333aSlum 
40415cbecf0Slum 	if ((*fd = fopen(tmp2, "w")) == NULL)
405066b333aSlum 		return (NULL);
40685c5a5c1Slum 
407066b333aSlum 	return (tmp2);
40885c5a5c1Slum }
409