1 /*-
2  * Copyright (c) 2002 Jordan DeLong
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the author nor the names of contributors may be
14  *    used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 #include "editor.h"
30 
31 /* macro flags */
32 int	macro_playing;
33 int	macro_repeating;
34 int	macro_repeatplay;
35 int	macro_recording;
36 
37 /* the macro recording buffer */
38 static int	rsize;
39 static int	rlength;
40 static int	rpos;
41 static int	*record;
42 
43 /* key to be repeated by the key repeater */
44 static int	rkey;
45 
46 /*
47  * flag if the keyrepeater is being set up; used to
48  * prevent infinite an infinite loop if people do
49  * dumb stuff.
50  */
51 static int	gettingrepkey;
52 
53 /* initialize the macro recording stuff */
macro_init()54 void macro_init() {
55 	record = ckmalloc(LINE_STARTSIZE * sizeof(int));
56 	rsize = LINE_STARTSIZE;
57 }
58 
59 /* free memory */
macro_shutdown()60 void macro_shutdown() {
61 	free(record);
62 }
63 
64 /*
65  * add a key to the macro recording, and return the key that the
66  * calling process should use.
67  */
macro_recordkey(int keysym)68 int macro_recordkey(int keysym) {
69 	if (keysym == KEYSYM_RECORD || keysym == KEYSYM_PLAYBACK) {
70 		minibuff_printf("Macro recording stopped.");
71 		macro_recording = 0;
72 		/*
73 		 * this is neccesary to prevent an infinite loop if
74 		 * someone tries to repeat a macro that ends with
75 		 * an unfinished repeat command.
76 		 */
77 		if (gettingrepkey)
78 			keysym = KEYSYM_CANCEL;
79 		else
80 			return KEYSYM_NOP;
81 	}
82 
83 	if (rlength + 1 >= rsize) {
84 		rsize *= 2;
85 		record = ckrealloc(record, rsize * sizeof(int));
86 	}
87 	record[rlength++] = keysym;
88 
89 	return keysym;
90 }
91 
92 /*
93  * return a key from the macro system; either from the key repeater
94  * or from a playing keyboard macro.
95  */
macro_getkey()96 int macro_getkey() {
97 	int c;
98 
99 	if (macro_repeating) {
100 		if (--macro_repeating == 0)
101 			input_nodraw--;
102 		return rkey;
103 	}
104 
105 	assert(macro_playing && !macro_recording);
106 	c = record[rpos++];
107 	if (rpos >= rlength) {
108 		macro_playing = 0;
109 		input_nodraw--;
110 	}
111 	return c;
112 }
113 
114 /* input callback for minibuff repeat prompt */
repcback(vminibuff_t * v,int keysym)115 static int repcback(vminibuff_t *v, int keysym) {
116 	if (isdigit(keysym) || keysym == KEYSYM_CANCEL)
117 		return 0;
118 	else {
119 		rkey = keysym;
120 		vminibuff_exit(v);
121 	}
122 
123 	return 1;
124 }
125 
macro_repeat()126 void macro_repeat() {
127 	u_char *repstr;
128 
129 	/* figure out what to repeat and how many times */
130 	repstr = minibuff_cbprompt("Repeat", NULL, repcback, NULL);
131 	if (!repstr)
132 		return;
133 
134 	/*
135 	 * because macros may want to use the key repeater, if you
136 	 * try to repeat a macro with the repeater it is neccesary
137 	 * to use a seperate counter to do it.
138 	 */
139 	if (rkey == KEYSYM_PLAYBACK)
140 		macro_repeatplay = atoi(repstr);
141 	else
142 		macro_repeating = atoi(repstr);
143 	if (macro_repeating || macro_repeatplay)
144 		input_nodraw++;
145 	free(repstr);
146 }
147 
macro_record()148 void macro_record() {
149 	minibuff_printf("Macro recording started.");
150 	rlength = 0;
151 	macro_recording = 1;
152 }
153 
macro_playback()154 void macro_playback() {
155 	if (rlength) {
156 		rpos = 0;
157 		macro_playing = 1;
158 		input_nodraw++;
159 	} else
160 		minibuff_printf("No macro to play.");
161 }
162