brute-forced more changes from MontaVista's tree. SCSI partition table read still...
[linux-2.4.git] / drivers / s390 / char / tubttyrcl.c
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
15 tty3270_rcl_init(tub_t *tubp)
16 {
17         return tty3270_rcl_resize(tubp, 20);
18 }
19
20 int
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
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
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
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
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
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
195 tty3270_rcl_sync(tub_t *tubp)
196 {
197         tubp->tty_rclb = -1;
198 }
199