12 |
#include <sstream> |
#include <sstream> |
13 |
#include <string.h> |
#include <string.h> |
14 |
|
|
15 |
|
#include "lscp.h" |
16 |
#include "LSCPClient.h" |
#include "LSCPClient.h" |
17 |
#include "KeyboardReader.h" |
#include "KeyboardReader.h" |
18 |
#include "TerminalCtrl.h" |
#include "TerminalCtrl.h" |
19 |
#include "CFmt.h" |
#include "CFmt.h" |
20 |
#include "CCursor.h" |
#include "CCursor.h" |
21 |
#include "TerminalPrinter.h" |
#include "TerminalPrinter.h" |
22 |
|
#if DEBUG_LSCP_SHELL |
23 |
|
# include <stdarg.h> |
24 |
|
# include <sys/timeb.h> |
25 |
|
#endif // DEBUG_LSCP_SHELL |
26 |
#include "../common/global.h" |
#include "../common/global.h" |
27 |
#include "../common/global_private.h" |
#include "../common/global_private.h" |
28 |
#include "../common/Condition.h" |
#include "../common/Condition.h" |
44 |
static std::vector<String> g_commandHistory; |
static std::vector<String> g_commandHistory; |
45 |
static int g_commandHistoryIndex = -1; |
static int g_commandHistoryIndex = -1; |
46 |
static String g_doc; |
static String g_doc; |
47 |
|
static bool g_quitAppRequested = false; |
48 |
|
static int g_exitCode = 0; |
49 |
|
#if DEBUG_LSCP_SHELL |
50 |
|
static FILE* g_df; ///< handle to output log file (just for debugging) |
51 |
|
#endif |
52 |
|
|
53 |
|
/** |
54 |
|
* Log the given debug message to a log file. This works only if |
55 |
|
* DEBUG_LSCP_SHELL was turned on in lscp.h. Otherwise this function does |
56 |
|
* nothing. Usage of this function is equivalent to printf(). |
57 |
|
*/ |
58 |
|
void lscpLog(const char* format, ...) { |
59 |
|
#if DEBUG_LSCP_SHELL |
60 |
|
// assemble variable argument list given to this function call |
61 |
|
va_list arg; |
62 |
|
va_start(arg, format); |
63 |
|
// write current timestamp to log file |
64 |
|
struct timeb tp; |
65 |
|
ftime(&tp); |
66 |
|
fprintf(g_df, "[%d.%03d] ", tp.time, tp.millitm); |
67 |
|
// write actual debug message to log file |
68 |
|
vfprintf(g_df, format, arg); |
69 |
|
fflush(g_df); |
70 |
|
va_end(arg); |
71 |
|
#endif // DEBUG_LSCP_SHELL |
72 |
|
} |
73 |
|
|
74 |
static void printUsage() { |
static void printUsage() { |
75 |
cout << "lscp - The LinuxSampler Control Protocol (LSCP) Shell." << endl; |
cout << "lscp - The LinuxSampler Control Protocol (LSCP) Shell." << endl; |
100 |
} |
} |
101 |
|
|
102 |
static void quitApp(int code = 0) { |
static void quitApp(int code = 0) { |
103 |
std::cout << std::endl << std::flush; |
//lscpLog("[quit app]\n"); |
104 |
if (g_client) delete g_client; |
g_exitCode = code; |
105 |
if (g_keyboardReader) delete g_keyboardReader; |
g_quitAppRequested = true; |
|
exit(code); |
|
106 |
} |
} |
107 |
|
|
108 |
// Called by the network reading thread, whenever new data arrived from the |
// Called by the network reading thread, whenever new data arrived from the |
118 |
|
|
119 |
// Called on network error or when server side closed the TCP connection. |
// Called on network error or when server side closed the TCP connection. |
120 |
static void onLSCPClientErrorOccured(LSCPClient* client) { |
static void onLSCPClientErrorOccured(LSCPClient* client) { |
121 |
|
//lscpLog("[client error callback]\n"); |
122 |
quitApp(); |
quitApp(); |
123 |
} |
} |
124 |
|
|
139 |
g_commandHistoryIndex + offset >= g_commandHistory.size()) return; |
g_commandHistoryIndex + offset >= g_commandHistory.size()) return; |
140 |
g_commandHistoryIndex += offset; |
g_commandHistoryIndex += offset; |
141 |
int len = g_goodPortion.size() + g_badPortion.size(); |
int len = g_goodPortion.size() + g_badPortion.size(); |
142 |
|
String command; |
143 |
// erase current active line |
// erase current active line |
144 |
for (int i = 0; i < len; ++i) g_client->send('\b'); |
for (int i = 0; i < len; ++i) command += '\b'; |
145 |
// transmit new/old line to LSCP server |
// transmit new/old line to LSCP server |
146 |
String command = g_commandHistory[g_commandHistory.size() - g_commandHistoryIndex - 1]; |
command += g_commandHistory[g_commandHistory.size() - g_commandHistoryIndex - 1]; |
147 |
g_client->send(command); |
g_client->send(command); |
148 |
} |
} |
149 |
|
|
286 |
* to add characters to the current command line. |
* to add characters to the current command line. |
287 |
*/ |
*/ |
288 |
int main(int argc, char *argv[]) { |
int main(int argc, char *argv[]) { |
289 |
|
#if DEBUG_LSCP_SHELL |
290 |
|
g_df = fopen("lscp.log", "w"); |
291 |
|
if (!g_df) { |
292 |
|
std::cerr << "Could not open lscp.log for writing!\n"; |
293 |
|
exit(-1); |
294 |
|
} |
295 |
|
#endif // DEBUG_LSCP_SHELL |
296 |
|
|
297 |
String host = LSCP_DEFAULT_HOST; |
String host = LSCP_DEFAULT_HOST; |
298 |
int port = LSCP_DEFAULT_PORT; |
int port = LSCP_DEFAULT_PORT; |
299 |
bool autoCorrect = true; |
bool autoCorrect = true; |
379 |
// characters to the LSCP server and/or show the result of the LSCP |
// characters to the LSCP server and/or show the result of the LSCP |
380 |
// server's latest evaluation to the user on the screen (by pulling those |
// server's latest evaluation to the user on the screen (by pulling those |
381 |
// data from the other two thread's FIFO buffers). |
// data from the other two thread's FIFO buffers). |
382 |
while (true) { |
while (!g_quitAppRequested) { |
383 |
// sleep until either new data from the network or from keyboard arrived |
// sleep until either new data from the network or from keyboard arrived |
384 |
g_todo.WaitIf(false); |
g_todo.WaitIf(false); |
385 |
// immediately unset the condition variable and unlock it |
// immediately unset the condition variable and unlock it |
389 |
// did network data arrive? |
// did network data arrive? |
390 |
while (g_client->messageComplete()) { |
while (g_client->messageComplete()) { |
391 |
String line = *g_client->popLine(); |
String line = *g_client->popLine(); |
392 |
//printf("line '%s'\n", line.c_str()); |
//lscpLog("[client] '%s'\n", line.c_str()); |
393 |
if (line.substr(0,4) == "SHU:") { |
if (line.substr(0,4) == "SHU:") { |
394 |
int code = 0, n = 0; |
int code = 0, n = 0; |
395 |
int res = sscanf(line.c_str(), "SHU:%d:%n", &code, &n); |
int res = sscanf(line.c_str(), "SHU:%d:%n", &code, &n); |
554 |
// did keyboard input arrive? |
// did keyboard input arrive? |
555 |
while (g_keyboardReader->charAvailable()) { |
while (g_keyboardReader->charAvailable()) { |
556 |
char c = g_keyboardReader->popChar(); |
char c = g_keyboardReader->popChar(); |
557 |
|
//lscpLog("[keyboard] '%c' (dec %d%s)'\n", c, (int)c, iKbdEscapeCharsExpected ? " ESC SEQ" : ""); |
558 |
|
|
559 |
//std::cout << c << "(" << int(c) << ")" << std::endl << std::flush; |
//std::cout << c << "(" << int(c) << ")" << std::endl << std::flush; |
560 |
if (iKbdEscapeCharsExpected) { // escape sequence (still) expected now ... |
if (iKbdEscapeCharsExpected) { // escape sequence (still) expected now ... |
587 |
} |
} |
588 |
} |
} |
589 |
|
|
590 |
return 0; |
// Application is going to exit (due to user request or server |
591 |
|
// disconnection). Clean up everything ... |
592 |
|
std::cout << std::endl << std::flush; |
593 |
|
if (g_client) delete g_client; |
594 |
|
if (g_keyboardReader) delete g_keyboardReader; |
595 |
|
|
596 |
|
return g_exitCode; |
597 |
} |
} |