1 /*
2  *  IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC
3  *
4  *  tubttyrcl.c -- Linemode Command-recall functionality
5  *
6  *
7  *
8  *
9  *
10  *  Author:  Richard Hitt
11  */
12 #include "tubio.h"
13 
14 int
tty3270_rcl_init(tub_t * tubp)15 tty3270_rcl_init(tub_t *tubp)
16 {
17 	return tty3270_rcl_resize(tubp, 20);
18 }
19 
20 int
tty3270_rcl_resize(tub_t * tubp,int newrclk)21 tty3270_rcl_resize(tub_t *tubp, int newrclk)
22 {
23 	char *(*newrclb)[];
24 
25 	if (newrclk > 1000)
26 		return -EINVAL;
27 	if (newrclk <= 0) {
28 		tty3270_rcl_purge(tubp),
29 		kfree(tubp->tty_rclbufs);
30 		tubp->tty_rclbufs = NULL;
31 		return 0;
32 	}
33 	if ((newrclb = (char *(*)[])kmalloc(
34 	    newrclk * sizeof (char *), GFP_KERNEL)) == NULL)
35 		return -ENOMEM;
36 	memset(newrclb, 0, newrclk * sizeof (char *));
37 	if (tubp->tty_rclbufs != NULL) {
38 		int i, j, k;
39 		char *data;
40 
41 		i = tubp->tty_rclp;
42 		j = newrclk;
43 		k = tubp->tty_rclk;
44 		while (j-- && k--) {
45 			if ((data = (*tubp->tty_rclbufs)[i]) == NULL)
46 				break;
47 			(*newrclb)[j] = data;
48 			(*tubp->tty_rclbufs)[i] = NULL;
49 			if (--i < 0)
50 				i = tubp->tty_rclk - 1;
51 		}
52 		tty3270_rcl_purge(tubp);
53 		kfree(tubp->tty_rclbufs);
54 	}
55 	tubp->tty_rclbufs = newrclb;
56 	tubp->tty_rclk = newrclk;
57 	tubp->tty_rclp = newrclk - 1;
58 	tty3270_rcl_sync(tubp);
59 	return 0;
60 }
61 
62 int
tty3270_rcl_set(tub_t * tubp,char * buf,int count)63 tty3270_rcl_set(tub_t *tubp, char *buf, int count)
64 {
65 #define RCL_SIZ "recallsize="
66 #define L_RCL_SIZ (strlen(RCL_SIZ))
67 	int newsize;
68 	int len;
69 	int rc;
70 	char *rcl_siz = RCL_SIZ;
71 	int l_rcl_siz = L_RCL_SIZ;
72 
73 	if (count < l_rcl_siz || strncmp(buf, rcl_siz, l_rcl_siz) != 0)
74 		return 0;
75 	if ((len = count - l_rcl_siz) == 0)
76 		return count;
77 	newsize = simple_strtoul(buf + l_rcl_siz, 0, 0);
78 	rc = tty3270_rcl_resize(tubp, newsize);
79 	return rc < 0? rc: count;
80 }
81 
82 void
tty3270_rcl_fini(tub_t * tubp)83 tty3270_rcl_fini(tub_t *tubp)
84 {
85 	if (tubp->tty_rclbufs != NULL) {
86 		tty3270_rcl_purge(tubp);
87 		kfree(tubp->tty_rclbufs);
88 		tubp->tty_rclbufs = NULL;
89 	}
90 }
91 
92 void
tty3270_rcl_purge(tub_t * tubp)93 tty3270_rcl_purge(tub_t *tubp)
94 {
95 	int i;
96 	char *buf;
97 
98 	if (tubp->tty_rclbufs == NULL)
99 		return;
100 	for (i = 0; i < tubp->tty_rclk; i++) {
101 		if ((buf = (*tubp->tty_rclbufs)[i]) == NULL)
102 			continue;
103 		kfree(buf);
104 		(*tubp->tty_rclbufs)[i] = NULL;
105 	}
106 }
107 
108 int
tty3270_rcl_get(tub_t * tubp,char * buf,int len,int inc)109 tty3270_rcl_get(tub_t *tubp, char *buf, int len, int inc)
110 {
111 	int iter;
112 	int i;
113 	char *data;
114 
115 	if (tubp->tty_rclbufs == NULL)
116 		return 0;
117 	if (tubp->tty_rclk <= 0)	/* overcautious */
118 		return 0;
119 	if (inc != 1 && inc != -1)	/* overcautious */
120 		return 0;
121 
122 	if ((i = tubp->tty_rclb) == -1) {
123 		i = tubp->tty_rclp;
124 		if (inc == 1)
125 			i++;
126 	} else {
127 		i += inc;
128 	}
129 	for (iter = tubp->tty_rclk; iter; iter--, i += inc) {
130 		if (i < 0)
131 			i = tubp->tty_rclk - 1;
132 		else if (i >= tubp->tty_rclk)
133 			i = 0;
134 		if ((*tubp->tty_rclbufs)[i] != NULL)
135 			break;
136 	}
137 	if (iter < 0 || (data = (*tubp->tty_rclbufs)[i]) == NULL)
138 		return 0;
139 	tubp->tty_rclb = i;
140 	if ((len = MIN(len - 1, strlen(data))) <= 0)
141 		return 0;
142 	memcpy(buf, data, len);
143 	buf[len] = '\0';
144 	return len;
145 }
146 
147 void
tty3270_rcl_put(tub_t * tubp,char * data,int len)148 tty3270_rcl_put(tub_t *tubp, char *data, int len)
149 {
150 	char *buf, **bufp;
151 	int i;
152 
153 	if (tubp->tty_rclbufs == NULL)
154 		return;
155 
156 	if (tubp->tty_rclk <= 0)        /* overcautious */
157 		return;
158 
159 	/* If input area is invisible, don't log */
160 	if (tubp->tty_inattr == TF_INPUTN)
161 		return;
162 
163 	/* If this & most recent cmd text match, don't log */
164 	if ((buf = (*tubp->tty_rclbufs)[tubp->tty_rclp]) != NULL &&
165 	    strlen(buf) == len && memcmp(buf, data, len) == 0) {
166 		tty3270_rcl_sync(tubp);
167 		return;
168 	}
169 
170 	/* Don't stack zero-length commands */
171 	if (len == 0) {
172 		tty3270_rcl_sync(tubp);
173 		return;
174 	}
175 
176 	i = tubp->tty_rclp;
177 	if (++i == tubp->tty_rclk)
178 		i = 0;
179 	bufp = &(*tubp->tty_rclbufs)[i];
180 	if (*bufp == NULL || strlen(*bufp) < len + 1) {
181 		if (*bufp) {
182 			kfree(*bufp);
183 			*bufp = NULL;
184 		}
185 		if ((*bufp = kmalloc(len + 1, GFP_ATOMIC)) == NULL)
186 			return;
187 	}
188 	memcpy(*bufp, data, len);
189 	(*bufp)[len] = '\0';
190 	tubp->tty_rclp = i;
191 	tty3270_rcl_sync(tubp);
192 }
193 
194 void
tty3270_rcl_sync(tub_t * tubp)195 tty3270_rcl_sync(tub_t *tubp)
196 {
197 	tubp->tty_rclb = -1;
198 }
199 
200