/*
* IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC
*
* tubttyrcl.c -- Linemode Command-recall functionality
*
*
*
*
*
* Author: Richard Hitt
*/
#include "tubio.h"
int
tty3270_rcl_init(tub_t *tubp)
{
return tty3270_rcl_resize(tubp, 20);
}
int
tty3270_rcl_resize(tub_t *tubp, int newrclk)
{
char *(*newrclb)[];
if (newrclk > 1000)
return -EINVAL;
if (newrclk <= 0) {
tty3270_rcl_purge(tubp),
kfree(tubp->tty_rclbufs);
tubp->tty_rclbufs = NULL;
return 0;
}
if ((newrclb = (char *(*)[])kmalloc(
newrclk * sizeof (char *), GFP_KERNEL)) == NULL)
return -ENOMEM;
memset(newrclb, 0, newrclk * sizeof (char *));
if (tubp->tty_rclbufs != NULL) {
int i, j, k;
char *data;
i = tubp->tty_rclp;
j = newrclk;
k = tubp->tty_rclk;
while (j-- && k--) {
if ((data = (*tubp->tty_rclbufs)[i]) == NULL)
break;
(*newrclb)[j] = data;
(*tubp->tty_rclbufs)[i] = NULL;
if (--i < 0)
i = tubp->tty_rclk - 1;
}
tty3270_rcl_purge(tubp);
kfree(tubp->tty_rclbufs);
}
tubp->tty_rclbufs = newrclb;
tubp->tty_rclk = newrclk;
tubp->tty_rclp = newrclk - 1;
tty3270_rcl_sync(tubp);
return 0;
}
int
tty3270_rcl_set(tub_t *tubp, char *buf, int count)
{
#define RCL_SIZ "recallsize="
#define L_RCL_SIZ (strlen(RCL_SIZ))
int newsize;
int len;
int rc;
char *rcl_siz = RCL_SIZ;
int l_rcl_siz = L_RCL_SIZ;
if (count < l_rcl_siz || strncmp(buf, rcl_siz, l_rcl_siz) != 0)
return 0;
if ((len = count - l_rcl_siz) == 0)
return count;
newsize = simple_strtoul(buf + l_rcl_siz, 0, 0);
rc = tty3270_rcl_resize(tubp, newsize);
return rc < 0? rc: count;
}
void
tty3270_rcl_fini(tub_t *tubp)
{
if (tubp->tty_rclbufs != NULL) {
tty3270_rcl_purge(tubp);
kfree(tubp->tty_rclbufs);
tubp->tty_rclbufs = NULL;
}
}
void
tty3270_rcl_purge(tub_t *tubp)
{
int i;
char *buf;
if (tubp->tty_rclbufs == NULL)
return;
for (i = 0; i < tubp->tty_rclk; i++) {
if ((buf = (*tubp->tty_rclbufs)[i]) == NULL)
continue;
kfree(buf);
(*tubp->tty_rclbufs)[i] = NULL;
}
}
int
tty3270_rcl_get(tub_t *tubp, char *buf, int len, int inc)
{
int iter;
int i;
char *data;
if (tubp->tty_rclbufs == NULL)
return 0;
if (tubp->tty_rclk <= 0) /* overcautious */
return 0;
if (inc != 1 && inc != -1) /* overcautious */
return 0;
if ((i = tubp->tty_rclb) == -1) {
i = tubp->tty_rclp;
if (inc == 1)
i++;
} else {
i += inc;
}
for (iter = tubp->tty_rclk; iter; iter--, i += inc) {
if (i < 0)
i = tubp->tty_rclk - 1;
else if (i >= tubp->tty_rclk)
i = 0;
if ((*tubp->tty_rclbufs)[i] != NULL)
break;
}
if (iter < 0 || (data = (*tubp->tty_rclbufs)[i]) == NULL)
return 0;
tubp->tty_rclb = i;
if ((len = MIN(len - 1, strlen(data))) <= 0)
return 0;
memcpy(buf, data, len);
buf[len] = '\0';
return len;
}
void
tty3270_rcl_put(tub_t *tubp, char *data, int len)
{
char *buf, **bufp;
int i;
if (tubp->tty_rclbufs == NULL)
return;
if (tubp->tty_rclk <= 0) /* overcautious */
return;
/* If input area is invisible, don't log */
if (tubp->tty_inattr == TF_INPUTN)
return;
/* If this & most recent cmd text match, don't log */
if ((buf = (*tubp->tty_rclbufs)[tubp->tty_rclp]) != NULL &&
strlen(buf) == len && memcmp(buf, data, len) == 0) {
tty3270_rcl_sync(tubp);
return;
}
/* Don't stack zero-length commands */
if (len == 0) {
tty3270_rcl_sync(tubp);
return;
}
i = tubp->tty_rclp;
if (++i == tubp->tty_rclk)
i = 0;
bufp = &(*tubp->tty_rclbufs)[i];
if (*bufp == NULL || strlen(*bufp) < len + 1) {
if (*bufp) {
kfree(*bufp);
*bufp = NULL;
}
if ((*bufp = kmalloc(len + 1, GFP_ATOMIC)) == NULL)
return;
}
memcpy(*bufp, data, len);
(*bufp)[len] = '\0';
tubp->tty_rclp = i;
tty3270_rcl_sync(tubp);
}
void
tty3270_rcl_sync(tub_t *tubp)
{
tubp->tty_rclb = -1;
}