/* TN5250 - An implementation of the 5250 telnet protocol.
* Copyright (C) 1997 Michael Madore
*
* This file is part of TN5250.
*
* TN5250 is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1, or (at your option)
* any later version.
*
* TN5250 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*
*/
#include "tn5250-private.h"
#define MAX_LINESZ 103 /* Maximum macro line size */
#define CR 0x0D
#define LF 0x0A
#define MAX_SPECKEY 12 /* Maximum special key name size */
struct _MacroKey {
int km_code ;
char km_str[MAX_SPECKEY] ;
} ;
typedef struct _MacroKey MacroKey ;
/* Table based on terminal.h */
static const MacroKey MKey[] = {
{K_ENTER , "ENTER" },
{K_NEWLINE , "NEWLINE" },
{K_TAB , "TAB" },
{K_BACKTAB , "BACKTAB" },
{K_F1 , "F1" },
{K_F2 , "F2" },
{K_F3 , "F3" },
{K_F4 , "F4" },
{K_F5 , "F5" },
{K_F6 , "F6" },
{K_F7 , "F7" },
{K_F8 , "F8" },
{K_F9 , "F9" },
{K_F10 , "F10" },
{K_F11 , "F11" },
{K_F12 , "F12" },
{K_F13 , "F13" },
{K_F14 , "F14" },
{K_F15 , "F15" },
{K_F16 , "F16" },
{K_F17 , "F17" },
{K_F18 , "F18" },
{K_F19 , "F19" },
{K_F20 , "F20" },
{K_F21 , "F21" },
{K_F22 , "F22" },
{K_F23 , "F23" },
{K_F24 , "F24" },
{K_LEFT , "LEFT" },
{K_RIGHT , "RIGHT" },
{K_UP , "UP" },
{K_DOWN , "DOWN" },
{K_ROLLDN , "ROLLDN" },
{K_ROLLUP , "ROLLUP" },
{K_BACKSPACE , "BACKSPACE" },
{K_HOME , "HOME" },
{K_END , "END" },
{K_INSERT , "INSERT" },
{K_DELETE , "DELETE" },
{K_RESET , "RESET" },
{K_PRINT , "PRINT" },
{K_HELP , "HELP" },
{K_SYSREQ , "SYSREQ" },
{K_CLEAR , "CLEAR" },
{K_REFRESH , "REFRESH" },
{K_FIELDEXIT , "FIELDEXIT" },
{K_TESTREQ , "TESTREQ" },
{K_TOGGLE , "TOGGLE" },
{K_ERASE , "ERASE" },
{K_ATTENTION , "ATTENTION" },
{K_DUPLICATE , "DUPLICATE" },
{K_FIELDMINUS , "FIELDMINUS" },
{K_FIELDPLUS , "FIELDPLUS" },
{K_PREVWORD , "PREVWORD" },
{K_NEXTWORD , "NEXTWORD" },
{K_FIELDHOME , "FIELDHOME" },
{K_EXEC , "EXEC" },
{K_MEMO , "MEMO" },
{K_COPY_TEXT , "COPY_TEXT" },
{K_PASTE_TEXT , "PASTE_TEXT" },
{0 , ""}
} ;
char PState[12] ; /* Printable state */
/*
* Clean trailing CRs. Returns line size
*/
int macro_buffer_clean (char *Buff)
{
int i ;
i = strlen(Buff) - 1 ;
while ((i >= 0) && ((Buff[i] == CR) || (Buff[i] == LF)))
Buff[i--] = 0 ;
return (i+1) ;
}
/*
* Return macro number
*/
int macro_isnewmacro (char *Buff)
{
int i,Num ;
Num = 0 ;
if ((Buff[0] == '[') && (Buff[1] == 'M'))
{
i = 2 ;
while (isdigit(Buff[i]))
{
Num = (Num * 10) + Buff[i] - '0' ;
i++ ;
}
if (Buff[i] != ']')
Num = 0 ;
}
return (Num) ;
}
/*
* Determines the macro size
*/
int macro_macrosize (int *Mac)
{
int i ;
i = 0 ;
if (Mac != NULL)
while (*Mac != 0)
{
i++ ;
Mac++ ;
}
return (i) ;
}
/*
* Reads a special key from macro text
*/
int macro_specialkey (char *Buff, int * Pt)
{
int i,j ;
if (Buff[*Pt] == '[')
{
i = 1 ;
while ((Buff[*Pt+i] != 0) && (Buff[*Pt+i] != ']') && (i <= MAX_SPECKEY))
i++ ;
if (Buff[*Pt+i] == ']')
{
j = 0 ;
while ((MKey[j].km_code != 0) &&
(strncmp(MKey[j].km_str,&Buff[*Pt+1],i-1) != 0))
j++ ;
if (MKey[j].km_code != 0)
{
*Pt += i ;
return (MKey[j].km_code) ;
}
}
}
return (0) ;
}
/*
* Add the line contents to macro
* TODO : add an escape character
* TODO : resize macro buffer when special keys are transcoded
*/
void macro_addline (int **PDest, char *Buff, int Sz)
{
int i,j,key ;
int *Buffer ;
int NSz, OSz ;
if (*PDest == NULL)
{
Buffer = (int *)malloc((Sz+1)*sizeof(int));
OSz = 0 ;
}
else
{
OSz = macro_macrosize(*PDest) ;
NSz = OSz + Sz + 1 ;
Buffer = *PDest ;
Buffer = (int *)realloc(*PDest,NSz*sizeof(int)) ;
}
if (Buffer != NULL)
{
*PDest = Buffer ;
i = j = 0 ;
while (Buff[j] != 0)
{
if ((key = macro_specialkey (Buff,&j)) > 0)
Buffer[OSz+i] = key ; /* maybe should resize buffer here */
else
Buffer[OSz+i] = (int)Buff[j] ;
i++ ;
j++ ;
}
Buffer[OSz+i] = 0 ;
}
}
/*
* Load the macro definitions file
*/
char macro_loadfile (Tn5250Macro *Macro)
{
FILE *MFile ;
int Sz,Num,CurMacro ;
char Buffer[MAX_LINESZ] ;
if (Macro->fname != NULL)
{
if ((MFile = fopen (Macro->fname,"rt")) != NULL)
{
CurMacro = 0 ;
while (fgets(Buffer,MAX_LINESZ,MFile) != NULL)
{
Sz = macro_buffer_clean (Buffer) ;
if ((Num=macro_isnewmacro(Buffer)) > 0)
{
if (Num <= 24)
CurMacro = Num ;
}
else
if ((CurMacro > 0) && (Sz > 0))
macro_addline (&Macro->BuffM[CurMacro-1],Buffer,Sz) ;
}
fclose (MFile) ;
}
return (1) ;
}
return (0) ;
}
/*
* Clear macros in memory
*/
void macro_clearmem (Tn5250Macro *Macro)
{
int i ;
for (i=0;i < 24;i++)
if (Macro->BuffM[i] != NULL)
{
free (Macro->BuffM[i]) ;
Macro->BuffM[i] = NULL ;
}
}
#ifdef __WIN32__
/*
* Get the macro file name
* Win32 version -- Looks for a file in the same dir as the .exe
*/
char *macro_filename (Tn5250Display *Dsp)
{
#define PATHSIZE 1024
LPTSTR apppath;
LPTSTR dir, fname;
DWORD len;
LPTSTR lpMsgBuf;
const char *cnf ;
apppath = malloc(PATHSIZE+1);
if (GetModuleFileName(NULL, apppath, PATHSIZE)<1) {
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
lpMsgBuf,
0, NULL
);
TN5250_LOG(("GetModuleFileName Error: %s\n", lpMsgBuf));
MessageBox(NULL, lpMsgBuf, "TN5250", MB_OK);
LocalFree(lpMsgBuf);
return (NULL);
}
if (strrchr(apppath, '\\')) {
len = strrchr(apppath, '\\') - apppath;
apppath[len+1] = '\0';
}
dir = malloc(strlen(apppath) + 15);
strcpy(dir, apppath);
strcat(dir, "tn5250macros");
free(apppath);
fname = dir ;
if ((cnf = tn5250_config_get (Dsp->config,"macros")) != NULL)
{
fname = (char *)malloc (strlen(cnf)+1) ;
if (fname != NULL)
{
memcpy (fname,cnf,strlen(cnf)+1) ;
free (dir) ;
}
}
return (fname);
}
#else
/*
* Get the macro file name
*/
char *macro_filename (Tn5250Display *Dsp)
{
struct passwd *pwent;
char *dir, *fname;
const char *cnf ;
pwent = getpwuid (getuid ());
if (pwent == NULL)
return (NULL) ;
dir = (char *)malloc (strlen (pwent->pw_dir) + 16);
if (dir == NULL)
return (NULL) ;
strcpy (dir, pwent->pw_dir);
strcat (dir, "/.tn5250macros");
fname = dir ;
if ((cnf = tn5250_config_get (Dsp->config,"macros")) != NULL)
{
fname = (char *)malloc (strlen(cnf)+1) ;
if (fname != NULL)
{
memcpy (fname,cnf,strlen(cnf)+1) ;
free (dir) ;
}
}
return (fname) ;
}
#endif
/****f* lib5250/tn5250_macro_init
* NAME
* tn5250_macro_init
* SYNOPSIS
* ret = tn5250_macro_init
* INPUTS
* None
* DESCRIPTION
* Macro system initialization
*****/
Tn5250Macro *tn5250_macro_init()
{
Tn5250Macro *This;
int i ;
This = tn5250_new(Tn5250Macro, 1);
if (This == NULL)
return NULL;
This->RState = 0 ;
This->EState = 0 ;
This->TleBuff = 0 ;
for (i=0;i < 24; i++)
This->BuffM[i] = NULL ;
return This;
}
/*
* Write one macro to file
*/
void macro_write (int Num, int *Buff, FILE *MF)
{
int i,j,Sz ;
fprintf (MF,"[M%02i]\n",Num) ;
i = Sz = 0 ;
while (Buff[i] != 0)
{
j = 0 ;
while ((MKey[j].km_code != 0) && (MKey[j].km_code != Buff[i]))
j++ ;
if (MKey[j].km_code == 0)
{
if (Sz + 1 > MAX_LINESZ-3)
{
fprintf (MF,"\n") ;
Sz = 0 ;
}
fprintf (MF,"%c",(char)Buff[i]) ;
Sz++ ;
}
else
{
if (Sz + strlen(MKey[j].km_str) + 2 > MAX_LINESZ-3)
{
fprintf (MF,"\n") ;
Sz = 0 ;
}
fprintf (MF,"[%s]",MKey[j].km_str) ;
Sz += strlen(MKey[j].km_str) + 2 ;
}
i++ ;
}
fprintf (MF,"\n\n") ;
}
/*
* Save the macro definitions file
*/
char macro_savefile (Tn5250Macro *Macro)
{
FILE *MFile ;
int i;
if (Macro->fname != NULL)
{
if ((MFile = fopen (Macro->fname,"wt")) != NULL)
{
for (i=0;i<24;i++)
if (Macro->BuffM[i] != NULL)
macro_write (i+1,Macro->BuffM[i],MFile) ;
fclose (MFile) ;
}
return (1) ;
}
return (0) ;
}
/****f* lib5250/tn5250_macro_exit
* NAME
* tn5250_macro_exit
* SYNOPSIS
* tn5250_macro_exit (This)
* INPUTS
* Tn5250Macro * This -
* DESCRIPTION
* Macro system termination
*****/
void tn5250_macro_exit(Tn5250Macro * This)
{
int i ;
if (This != NULL)
{
/* macro_savefile (This) ; */
if (This->fname != NULL)
free (This->fname) ;
for (i=0;i<24;i++)
free (This->BuffM[i]) ;
free (This) ;
}
}
/****f* lib5250/tn5250_macro_attach
* NAME
* tn5250_macro_attach
* SYNOPSIS
* tn5250_macro_attach (This);
* INPUTS
* Tn5250Display * This - The display to attach to
* Tn5250Macro * Macro - The macro object to attach
* DESCRIPTION
* Attach the macro system to display structure
* TODO
* macro_detach ?
*****/
int tn5250_macro_attach (Tn5250Display *This, Tn5250Macro *Macro)
{
if ((This->macro == NULL) && (Macro != NULL))
{
Macro->fname = macro_filename(This) ;
if (Macro->fname == NULL)
TN5250_LOG (("Macro: fname NULL\n")) ;
else
TN5250_LOG (("Macro: fname=%s\n",Macro->fname)) ;
/* macro_loadfile (Macro) ; */
This->macro = Macro ;
return (1) ;
}
return 0;
}
/****f* lib5250/tn5250_macro_rstate
* NAME
* tn5250_macro_rstate
* SYNOPSIS
* tn5250_macro_rstate (This);
* INPUTS
* Tn5250Display * This - Current display
* DESCRIPTION
* Returns the current macro recording state
*****/
char tn5250_macro_rstate (Tn5250Display *This)
{
if (This->macro != NULL)
return (This->macro->RState) ;
return 0;
}
/****f* lib5250/tn5250_macro_startdef
* NAME
* tn5250_macro_startdef
* SYNOPSIS
* tn5250_macro_startdef (This);
* INPUTS
* Tn5250Display * This - Current display
* DESCRIPTION
* Starts a macro definition
*****/
char tn5250_macro_startdef (Tn5250Display *This)
{
if (This->macro != NULL)
{
This->macro->RState = 1 ;
This->macro->FctnKey = 0 ;
This->macro->TleBuff = MACRO_BUFSIZE ;
return (1) ;
}
return (0) ;
}
/****f* lib5250/tn5250_macro_enddef
* NAME
* tn5250_macro_enddef
* SYNOPSIS
* tn5250_macro_enddef (This);
* INPUTS
* Tn5250Display * This - Current display
* DESCRIPTION
* Ends a macro definition
*****/
void tn5250_macro_enddef (Tn5250Display *This)
{
int NumMacro ;
int *Buffer ;
if (This->macro != NULL)
{
if (This->macro->RState > 1)
{
NumMacro = This->macro->FctnKey - K_F1 ;
if (This->macro->TleBuff > 0)
{
This->macro->BuffM[NumMacro][This->macro->TleBuff++] = 0 ;
Buffer = (int *)realloc(This->macro->BuffM[NumMacro],
This->macro->TleBuff*sizeof(int)) ;
if (Buffer != NULL)
This->macro->BuffM[NumMacro] = Buffer ;
}
else
{
free (This->macro->BuffM[NumMacro]) ;
This->macro->BuffM[NumMacro] = NULL ;
}
macro_savefile (This->macro) ;
}
This->macro->RState = 0 ;
}
}
/****f* lib5250/tn5250_macro_recfunct
* NAME
* tn5250_macro_recfunct
* SYNOPSIS
* tn5250_macro_recfunct (This,key);
* INPUTS
* Tn5250Display * This - Current display
* int key - function key received
* DESCRIPTION
* Receives a function key. Return True if macro definition key
*****/
char tn5250_macro_recfunct (Tn5250Display *This, int key)
{
int *Buffer ;
int NumMacro ;
if ((This->macro != NULL) && (This->macro->RState == 1))
{
Buffer = (int *)malloc((MACRO_BUFSIZE+1)*sizeof(int));
if (Buffer != NULL)
{
This->macro->RState = 2 ;
This->macro->FctnKey = key ;
NumMacro = key - K_F1 ;
if ((NumMacro >= 0) && (NumMacro < 24))
{
macro_clearmem (This->macro) ;
macro_loadfile (This->macro) ;
if (This->macro->BuffM[NumMacro] != NULL)
free (This->macro->BuffM[NumMacro]) ;
This->macro->BuffM[NumMacro] = Buffer ;
This->macro->TleBuff = 0 ;
return (1) ;
}
else
free (Buffer) ;
}
}
return (0) ;
}
/****f* lib5250/tn5250_macro_reckey
* NAME
* tn5250_macro_reckey
* SYNOPSIS
* tn5250_macro_reckey (This,key);
* INPUTS
* Tn5250Display * This - Current display
* int key - key received
* DESCRIPTION
* Receives a key.
*****/
void tn5250_macro_reckey (Tn5250Display *This, int key)
{
int NumMacro ;
if ((This->macro != NULL) && (This->macro->RState == 2) &&
(key != K_MEMO))
{
NumMacro = This->macro->FctnKey - K_F1 ;
if (This->macro->TleBuff < MACRO_BUFSIZE)
This->macro->BuffM[NumMacro][This->macro->TleBuff++] = key ;
}
}
/****f* lib5250/tn5250_macro_printstate
* NAME
* tn5250_macro_printstate
* SYNOPSIS
* tn5250_macro_printstate (This,key);
* INPUTS
* Tn5250Display * This - Current display
* DESCRIPTION
* Returns a printable macro state (always 11 char long)
*****/
char * tn5250_macro_printstate (Tn5250Display *This)
{
int NumKey ;
PState[0] = 0 ;
if (This->macro != NULL)
if (This->macro->RState > 0) /* recording state */
{
if (This->macro->RState == 1)
sprintf (PState,"R %04i ",MACRO_BUFSIZE-This->macro->TleBuff) ;
else
{
NumKey = This->macro->FctnKey - K_F1 + 1 ;
sprintf (PState,"R %04i F%02i",MACRO_BUFSIZE-This->macro->TleBuff,NumKey) ;
}
}
else /* execution state */
if (This->macro->EState > 0)
{
if (This->macro->EState == 1)
sprintf (PState,"P ") ;
else
{
NumKey = This->macro->FctnKey - K_F1 + 1 ;
sprintf (PState,"P F%02i ",NumKey) ;
}
}
return (PState) ;
}
/****f* lib5250/tn5250_macro_estate
* NAME
* tn5250_macro_estate
* SYNOPSIS
* tn5250_macro_estate (This);
* INPUTS
* Tn5250Display * This - Current display
* DESCRIPTION
* Returns the current macro execution state
*****/
char tn5250_macro_estate (Tn5250Display *This)
{
if (This->macro != NULL)
return (This->macro->EState) ;
return 0;
}
/****f* lib5250/tn5250_macro_startexec
* NAME
* tn5250_macro_startexec
* SYNOPSIS
* tn5250_macro_startexec (This);
* INPUTS
* Tn5250Display * This - Current display
* DESCRIPTION
* Starts a macro execution
*****/
char tn5250_macro_startexec (Tn5250Display *This)
{
if (This->macro != NULL)
{
This->macro->EState = 1 ;
This->macro->FctnKey = 0 ;
return (1) ;
}
return (0) ;
}
/****f* lib5250/tn5250_macro_endexec
* NAME
* tn5250_macro_endexec
* SYNOPSIS
* tn5250_macro_endexec (This);
* INPUTS
* Tn5250Display * This - Current display
* DESCRIPTION
* Ends a macro execution
*****/
void tn5250_macro_endexec (Tn5250Display *This)
{
if (This->macro != NULL)
This->macro->EState = 0 ;
}
/****f* lib5250/tn5250_macro_execfunct
* NAME
* tn5250_macro_execfunct
* SYNOPSIS
* tn5250_macro_execfunct (This,key);
* INPUTS
* Tn5250Display * This - Current display
* int key - function key received
* DESCRIPTION
* Receives an execution function key.
*****/
char tn5250_macro_execfunct (Tn5250Display *This, int key)
{
int NumMacro ;
if ((This->macro != NULL) && (This->macro->EState == 1))
{
This->macro->EState = 2 ;
This->macro->FctnKey = key ;
NumMacro = key - K_F1 ;
if ((NumMacro >= 0) && (NumMacro < 24))
{
macro_clearmem (This->macro) ;
macro_loadfile (This->macro) ;
This->macro->EState = 3 ; /* Ok to run macro */
This->macro->TleBuff = 0 ;
return (1) ;
}
}
return (0) ;
}
/****f* lib5250/tn5250_macro_getkey
* NAME
* tn5250_macro_execfunct
* SYNOPSIS
* tn5250_macro_execfunct (This,Last);
* INPUTS
* Tn5250Display * This - Current display
* char * Last - to return a "toggle indicator off"
* DESCRIPTION
* Sends a key to execute
*****/
int tn5250_macro_getkey (Tn5250Display *This, char *Last)
{
int NumMacro ;
int key,nkey ;
*Last = 0 ;
if ((This->macro != NULL) && (This->macro->EState == 3))
{
NumMacro = This->macro->FctnKey - K_F1 ;
if (This->macro->BuffM[NumMacro] != NULL)
{
key = This->macro->BuffM[NumMacro][This->macro->TleBuff] ;
if (key != 0)
nkey = This->macro->BuffM[NumMacro][++This->macro->TleBuff] ;
if ((key == 0) || (nkey == 0))
{
*Last = 1 ;
This->macro->EState = 0 ;
}
return (key) ;
}
else
{
This->macro->EState = 0 ;
*Last = 1 ;
return (0) ;
}
}
return (0) ;
}
syntax highlighted by Code2HTML, v. 0.9.1