- implemented multi-line response in AsconStdHandler
This commit is contained in:
74
ascon.c
74
ascon.c
@ -415,55 +415,70 @@ int AsconStdHandler(Ascon * a)
|
||||
{
|
||||
int result;
|
||||
char chr;
|
||||
int ret;
|
||||
int ret, l;
|
||||
char *cmd, *opt;
|
||||
|
||||
switch (a->state) {
|
||||
case AsconWriteStart:
|
||||
if (strstr(GetCharArray(a->wrBuffer), "@@NOSEND@@") != NULL) {
|
||||
cmd = GetCharArray(a->wrBuffer);
|
||||
a->lineCount = 1;
|
||||
if (a->separator != NULL) { /* multiline mode enabled */
|
||||
l = strlen(cmd);
|
||||
if (l> 0 && cmd[l-1] == '}') {
|
||||
opt = strrchr(cmd, '{');
|
||||
if (opt != NULL) {
|
||||
if (sscanf(opt, "{%d}", &a->lineCount) == 1) {
|
||||
/* remove option */
|
||||
for (l = strlen(opt); l > 0; l--) {
|
||||
DynStringBackspace(a->wrBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (strstr(GetCharArray(a->wrBuffer), "@@NOSEND@@") != NULL) {
|
||||
a->state = AsconWriteDone;
|
||||
return 1;
|
||||
}
|
||||
break; /* go to the base handler */
|
||||
case AsconWriting:
|
||||
if (a->readState) { /* last char was CR */
|
||||
ret = AsconReadChar(a->fd, &chr);
|
||||
if (ret > 0) {
|
||||
if (chr == '\n') {
|
||||
/* swallow LF after CR */
|
||||
a->readState = 0;
|
||||
} else {
|
||||
/* garbage character found -> swallow */
|
||||
}
|
||||
}
|
||||
}
|
||||
break; /* go to the base handler */
|
||||
case AsconReading:
|
||||
if (a->lineCount == 0) {
|
||||
/* no response expected */
|
||||
a->state = AsconReadDone;
|
||||
return 1;
|
||||
}
|
||||
result = AsconBaseHandler(a);
|
||||
if (result == 0)
|
||||
return 0;
|
||||
chr = a->lastChar;
|
||||
if (a->replyTerminator != NULL) {
|
||||
if (strchr(a->replyTerminator, chr) != NULL) {
|
||||
DynStringConcatChar(a->rdBuffer, '\0');
|
||||
a->state = AsconReadDone;
|
||||
if (chr == '\n' || chr == '\r') {
|
||||
DynStringBackspace(a->rdBuffer); /* remove LF or CR */
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (chr == '\n') {
|
||||
if (chr == '\n') { /* LF */
|
||||
DynStringBackspace(a->rdBuffer); /* remove LF */
|
||||
if (a->readState) { /* last char was CR */
|
||||
/* swallow LF after CR */
|
||||
/* LF after CR is not a terminator */
|
||||
a->readState = 0;
|
||||
} else {
|
||||
DynStringBackspace(a->rdBuffer); /* remove LF */
|
||||
DynStringConcatChar(a->rdBuffer, '\0');
|
||||
a->state = AsconReadDone;
|
||||
}
|
||||
} else if (chr == '\r') {
|
||||
a->readState = 1; /* set 'last char was CR' */
|
||||
} else if (chr == '\r') { /* CR */
|
||||
DynStringBackspace(a->rdBuffer); /* remove CR */
|
||||
DynStringConcatChar(a->rdBuffer, '\0');
|
||||
a->readState = 1; /* set 'last char was CR' */
|
||||
a->state = AsconReadDone;
|
||||
}
|
||||
}
|
||||
if (a->state == AsconReadDone && a->lineCount > 1) {
|
||||
if (a->separator != NULL) {
|
||||
DynStringConcat(a->rdBuffer, a->separator);
|
||||
}
|
||||
a->lineCount--;
|
||||
a->state = AsconReading;
|
||||
}
|
||||
return 1; /* base handler was already called */
|
||||
default:
|
||||
break;
|
||||
@ -488,6 +503,10 @@ int AsconStdInit(Ascon *a, SConnection *con, int argc, char *argv[])
|
||||
if (argc > 4 && argv[4][0] != '\0') {
|
||||
a->replyTerminator = strdup(argv[4]);
|
||||
}
|
||||
a->separator = NULL;
|
||||
if (argc > 5 && argv[5][0] != '\0') {
|
||||
a->separator = strdup(argv[5]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -516,6 +535,8 @@ Ascon *AsconMake(SConnection * con, int argc, char *argv[])
|
||||
a->sendTerminator = NULL;
|
||||
a->hostport = NULL;
|
||||
a->responseValid = 0;
|
||||
a->readState = 0;
|
||||
a->lineCount = 1;
|
||||
|
||||
a->handler = AsconSetHandler(a, con, argc, argv);
|
||||
if (a->handler == NULL) {
|
||||
@ -545,12 +566,15 @@ void AsconKill(Ascon * a)
|
||||
if (a->hostport) {
|
||||
free(a->hostport);
|
||||
}
|
||||
if(a->sendTerminator){
|
||||
if (a->sendTerminator) {
|
||||
free(a->sendTerminator);
|
||||
}
|
||||
if(a->replyTerminator){
|
||||
if (a->replyTerminator) {
|
||||
free(a->replyTerminator);
|
||||
}
|
||||
if (a->separator) {
|
||||
free(a->separator);
|
||||
}
|
||||
if (a->private != NULL && a->killPrivate != NULL) {
|
||||
a->killPrivate(a->private);
|
||||
}
|
||||
|
9
ascon.h
9
ascon.h
@ -84,4 +84,13 @@ char *ConcatArgs(int argc, char *argv[]);
|
||||
*/
|
||||
double DoubleTime(void);
|
||||
|
||||
/** \brief emit an error message. The state switches to AsconFailed.
|
||||
* \param a the connection
|
||||
* \param msg, a message to be emitted
|
||||
* \param errorno, for user messages, this should be 0. After
|
||||
* detection of a system error, eerno may be placed as argument
|
||||
* for adding strerror(errno) to the message.
|
||||
*/
|
||||
void AsconError(Ascon *a, char *msg, int errorno);
|
||||
|
||||
#endif
|
||||
|
26
ascon.i
26
ascon.i
@ -48,29 +48,33 @@ typedef enum {
|
||||
typedef int (* AsconHandler)(Ascon *connection);
|
||||
|
||||
/** Ascon struct
|
||||
* all members are public, allowing access by handler wrappers
|
||||
* all fields are public, allowing access by handler wrappers
|
||||
* the fields marked with (std) are used by the standard handler
|
||||
* they may get other meanings in a custom handler
|
||||
*/
|
||||
struct Ascon {
|
||||
AsconState state; /**< the current state */
|
||||
int fd; /**< socket */
|
||||
int readState; /**< default implementation: 'was cr' */
|
||||
int readState; /**< (std) last char was CR */
|
||||
pDynString rdBuffer; /**< read buffer */
|
||||
pDynString wrBuffer; /**< write buffer */
|
||||
int wrPos; /**< write buffer position */
|
||||
double timeout; /**< read timeout (sec) */
|
||||
char *sendTerminator; /**< terminator for sending messages */
|
||||
char *replyTerminator; /**< terminator list for reply. NULL is the special case CR, LF or CR/LF */
|
||||
char *replyTerminator; /**< (std) terminator list for reply. NULL is the special case CR, LF or CR/LF */
|
||||
char *hostport; /**< host:port to connect */
|
||||
pDynString errmsg; /**< error message */
|
||||
double start; /**< unix time when read was started */
|
||||
void *private; /**< private data of protocol */
|
||||
void (*killPrivate)(void *); /** < kill function for private */
|
||||
void (*killPrivate)(void *); /**< kill function for private */
|
||||
int noResponse; /**< no response expected */
|
||||
int responseValid; /**< a valid response is ready */
|
||||
AsconHandler handler; /**< handler function */
|
||||
double reconnectInterval; /**< reconnect interval */
|
||||
double lastReconnect; /**< last reconnect try */
|
||||
char lastChar; /**< last char read */
|
||||
char *separator; /**< (std) separator for multiline responses */
|
||||
int lineCount; /**< number of lines expected (counting down) */
|
||||
};
|
||||
|
||||
#define ASCON_SELECT_ERROR -1
|
||||
@ -104,13 +108,17 @@ int AsconStdHandler(Ascon *a);
|
||||
* \param a the connection
|
||||
* \param con A connection to print errors too.
|
||||
* \param argc number of arguments
|
||||
* \param argv arguments ("<host>:<port>" [sendTerminator] [timeout] [replyTerminators])
|
||||
* \param argv arguments ("<host>:<port>" [sendTerminator] [timeout] [replyTerminators] [separator])
|
||||
* sendTerminator is a character or string sent at the end of a command
|
||||
* timeout is in seconds
|
||||
* replyTerminator is a string, meant as a list of terminator characters
|
||||
* if not replyTerminator is given, CR, LF or CR/LF all are detected as
|
||||
* terminators. In this case the terminator is removed from the result,
|
||||
* where in the case before, the terminator stays in the result.
|
||||
* replyTerminators is a string, meant as a list of terminator characters
|
||||
* if no replyTerminator is given, or if it is empty, CR, LF or CR/LF all are detected
|
||||
* as terminators. If the terminator is CR, LF or CR/LF, it is removed from the result,
|
||||
* all other terminators are kept in the result.
|
||||
* separator is used for multiline responses. If this parameter
|
||||
* is given (and not empty) a command may be followed by a line count in curly brackets,
|
||||
* indicating that a multiline response is expected. All the lines of the response are
|
||||
* then returned, separated with "separator"
|
||||
*
|
||||
* In many cases a custom init function may be a wrapper around AsconStdInit
|
||||
*/
|
||||
|
Reference in New Issue
Block a user