/[svn]/linuxsampler/trunk/src/shell/lscp.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/shell/lscp.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2515 - (show annotations) (download)
Wed Feb 5 20:45:18 2014 UTC (10 years, 2 months ago) by schoenebeck
File size: 6622 byte(s)
* WIP: Introducing the LSCP shell: for now, providing color
  highlighting while typing (indicating correct part bold white,
  incorrect part red, and turning green when the command is
  complete. The shell application is implemented as thin client,
  that is the parser work is performed on sampler side and the
  shell application is just providing output formatting.
* Bumped version (1.0.0.svn28).

1 /*
2 * LSCP Shell
3 *
4 * Copyright (c) 2014 Christian Schoenebeck
5 *
6 * This program is part of LinuxSampler and released under the same terms.
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <iostream>
12 #include <sstream>
13 #include <string.h>
14
15 #include "LSCPClient.h"
16 #include "KeyboardReader.h"
17 #include "TerminalCtrl.h"
18 #include "CFmt.h"
19 #include "CCursor.h"
20
21 #include "../common/global.h"
22 #include "../common/Condition.h"
23
24 #define LSCP_DEFAULT_HOST "localhost"
25 #define LSCP_DEFAULT_PORT 8888
26
27 using namespace std;
28 using namespace LinuxSampler;
29
30 static LSCPClient g_client;
31 static KeyboardReader g_keyboardReader;
32 static Condition g_todo;
33
34 static void printUsage() {
35 cout << "lscp - The LinuxSampler Control Protocol (LSCP) Shell." << endl;
36 cout << endl;
37 cout << "Usage: lscp [-h HOSTNAME] [-p PORT]" << endl;
38 cout << endl;
39 cout << " -h Host name of LSCP server (default \"" << LSCP_DEFAULT_HOST << "\")." << endl;
40 cout << endl;
41 cout << " -p TCP port number of LSCP server (default " << LSCP_DEFAULT_PORT << ")." << endl;
42 cout << endl;
43 }
44
45 // Called by the network reading thread, whenever new data arrived from the
46 // network connection.
47 static void onLSCPClientNewInputAvailable(LSCPClient* client) {
48 g_todo.Set(true);
49 }
50
51 // Called by the keyboard reading thread, whenever a key stroke was received.
52 static void onNewKeyboardInputAvailable(KeyboardReader* reader) {
53 g_todo.Set(true);
54 }
55
56 int main(int argc, char *argv[]) {
57 String host = LSCP_DEFAULT_HOST;
58 int port = LSCP_DEFAULT_PORT;
59
60 // parse command line arguments
61 for (int i = 0; i < argc; ++i) {
62 String s = argv[i];
63 if (s == "-h" || s == "--host") {
64 if (++i >= argc) {
65 printUsage();
66 return -1;
67 }
68 host = argv[i];
69 } else if (s == "-p" || s == "--port") {
70 if (++i >= argc) {
71 printUsage();
72 return -1;
73 }
74 port = atoi(argv[i]);
75 if (port <= 0) {
76 cerr << "Error: invalid port argument \"" << argv[i] << "\"\n";
77 return -1;
78 }
79 } else if (s[0] == '-') { // invalid / unknown command line argument ...
80 printUsage();
81 return -1;
82 }
83 }
84
85 // try to connect to the sampler's LSCP server and start a thread for
86 // receiving incoming network data from the sampler's LSCP server
87 g_client.setCallback(onLSCPClientNewInputAvailable);
88 if (!g_client.connect(host, port)) return -1;
89 String sResponse = g_client.sendCommandSync("SET SHELL INTERACT 1");
90 if (sResponse.substr(0, 2) != "OK") {
91 cerr << "Error: sampler too old, it does not support shell instructions\n";
92 return -1;
93 }
94
95 // start a thread for reading from the local text input keyboard
96 // (keyboard echo will be disabled as well to have a clean control on what
97 // is appearing on the screen)
98 g_keyboardReader.setCallback(onNewKeyboardInputAvailable);
99 g_keyboardReader.startReading();
100
101 // main thread's loop
102 while (true) {
103 // sleep until either new data from the network or from keyboard arrived
104 g_todo.WaitIf(false);
105 // immediately unset the condition variable and unlock it
106 g_todo.Set(false);
107 g_todo.Unlock();
108
109 // did network data arrive?
110 while (g_client.messageComplete()) {
111 String line = *g_client.popLine();
112 //printf("line '%s'\n", line.c_str());
113 if (line.substr(0,4) == "SHU:") {
114 int code = 0, n = 0;
115 int res = sscanf(line.c_str(), "SHU:%d:%n", &code, &n);
116 if (res >= 1) {
117 String s = line.substr(n);
118
119 String key = LSCP_SHK_GOOD_FRONT;
120 size_t i = s.find(key);
121 String sGood = s.substr(0, i);
122 String sBad = s.substr(i + key.length());
123 //printf("line '%s' good='%s' bad='%s'\n", line.c_str(), sGood.c_str(), sBad.c_str());
124
125 CCursor cursor = CCursor::now();
126 cursor.toColumn(0);
127 cursor.clearLine();
128
129 CFmt cfmt;
130 if (code == LSCP_SHU_COMPLETE) cfmt.bold().green();
131 else cfmt.bold().white();
132 cout << sGood << flush;
133 cfmt.reset().red();
134 cout << sBad << flush;
135 }
136 } else if (line.substr(0,2) == "OK") { // single-line response expected ...
137 cout << endl << flush;
138 CFmt cfmt;
139 cfmt.green();
140 cout << line.substr(0,2) << flush;
141 cfmt.reset();
142 cout << line.substr(2) << endl << flush;
143 } else if (line.substr(0,3) == "WRN") { // single-line response expected ...
144 cout << endl << flush;
145 CFmt cfmt;
146 cfmt.yellow();
147 cout << line.substr(0,3) << flush;
148 cfmt.reset();
149 cout << line.substr(3) << endl << flush;
150 } else if (line.substr(0,3) == "ERR") { // single-line response expected ...
151 cout << endl << flush;
152 CFmt cfmt;
153 cfmt.bold().red();
154 cout << line.substr(0,3) << flush;
155 cfmt.reset();
156 cout << line.substr(3) << endl << flush;
157 } else if (g_client.multiLine()) { // multi-line response expected ...
158 cout << endl << flush;
159 while (true) {
160 cout << line << endl << flush;
161 if (line.substr(0, 1) == ".") break;
162 if (!g_client.lineAvailable()) break;
163 line = *g_client.popLine();
164 }
165 } else {
166 cout << endl << line << endl << flush;
167 }
168 }
169
170 // did keyboard input arrive?
171 while (g_keyboardReader.charAvailable()) {
172 char c = g_keyboardReader.popChar();
173
174 CFmt cfmt;
175 cfmt.white();
176 //std::cout << c << "(" << int(c) << ")" << std::endl << std::flush;
177 if (c == KBD_BACKSPACE) {
178 cout << "\b \b" << flush;
179 c = '\b';
180 } else if (c != '\n') { // don't apply RETURN stroke yet, since the typed command might still be corrected by the sampler
181 cout << c << flush;
182 }
183
184 g_client.send(c);
185 }
186 }
187
188 return 0;
189 }

  ViewVC Help
Powered by ViewVC