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

Contents of /linuxsampler/trunk/src/shell/TerminalCtrl.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: 4758 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 "TerminalCtrl.h"
10
11 #include <unistd.h>
12 #include <termios.h>
13 #include <string.h>
14 #include <map>
15 #include <assert.h>
16 #include <sys/ioctl.h>
17 #include <stdio.h>
18
19 ///////////////////////////////////////////////////////////////////////////
20 // class 'TerminalSetting'
21
22 static std::map<void*,int> g_terminalSettingReferences;
23
24 static termios* _newTermios() {
25 termios* p = new termios;
26 g_terminalSettingReferences[p] = 1;
27 return p;
28 }
29
30 static void _releaseTermiosRef(void* p) {
31 if (!p) return;
32 std::map<void*,int>::iterator it = g_terminalSettingReferences.find(p);
33 assert(it != g_terminalSettingReferences.end());
34 assert(it->second > 0);
35 it->second--;
36 if (!it->second) {
37 g_terminalSettingReferences.erase(it);
38 delete (termios*) p;
39 }
40 }
41
42 static termios* _bumpTermiosRef(void* p) {
43 if (!p) return NULL;
44 std::map<void*,int>::iterator it = g_terminalSettingReferences.find(p);
45 assert(it != g_terminalSettingReferences.end());
46 assert(it->second > 0);
47 it->second++;
48 return (termios*) p;
49 }
50
51 TerminalSetting::TerminalSetting() : p(NULL) {
52 }
53
54 TerminalSetting::TerminalSetting(const TerminalSetting& ts) : p(_bumpTermiosRef(ts.p)) {
55 }
56
57 TerminalSetting::~TerminalSetting() {
58 _releaseTermiosRef(p);
59 }
60
61 bool TerminalSetting::valid() const {
62 return p != NULL;
63 }
64
65 ///////////////////////////////////////////////////////////////////////////
66 // class 'TerminalCtrl'
67
68 static termios g_defaults;
69
70 static void _saveDefaults() {
71 static bool done = false;
72 if (done) return;
73 if (tcgetattr(0, &g_defaults) < 0) return;
74 done = true;
75 }
76
77 int TerminalCtrl::reset() {
78 _saveDefaults();
79 if (tcsetattr(0, TCSANOW, &g_defaults) < 0) return -1;
80 return 0; // success
81 }
82
83 int TerminalCtrl::restore(const TerminalSetting& setting) {
84 _saveDefaults();
85 termios* s = (termios*) setting.p;
86 if (tcsetattr(0, TCSADRAIN, s) < 0) return -1;
87 return 0; // success
88 }
89
90 TerminalSetting TerminalCtrl::now() {
91 _saveDefaults();
92 TerminalSetting setting;
93 if (!setting.p) setting.p = _newTermios();
94 if (tcgetattr(0, (termios*) setting.p) < 0)
95 return TerminalSetting(); // error, return invalid setting
96 return setting; // success
97 }
98
99 int TerminalCtrl::echoInput(bool b) {
100 _saveDefaults();
101 termios settings = {};
102 if (tcgetattr(0, &settings) < 0) return -1;
103 if (b) {
104 settings.c_lflag |= ECHO;
105 if (tcsetattr(0, TCSADRAIN, &settings) < 0) return -1;
106 } else {
107 settings.c_lflag &= ~ECHO;
108 if (tcsetattr(0, TCSANOW, &settings) < 0) return -1;
109 }
110 return 0; // success
111 }
112
113 int TerminalCtrl::immediateInput(bool b) {
114 _saveDefaults();
115 termios settings = {};
116 if (tcgetattr(0, &settings) < 0) return -1;
117 if (b) {
118 settings.c_lflag &= ~ICANON;
119 settings.c_cc[VMIN] = 0;
120 settings.c_cc[VTIME] = 0;
121 if (tcsetattr(0, TCSANOW, &settings) < 0) return -1;
122 } else {
123 settings.c_lflag |= ICANON;
124 if (tcsetattr(0, TCSADRAIN, &settings) < 0) return -1;
125 }
126 return 0; // success
127 }
128
129 std::vector<char> TerminalCtrl::getChars(int max, int blockUntilMin, int burstDeciSeconds) {
130 _saveDefaults();
131 std::vector<char> v;
132
133 TerminalSetting original = now();
134 if (!original.valid()) return v;
135
136 termios setting = *(termios*)original.p; // copy
137 setting.c_lflag &= ~ICANON;
138 setting.c_cc[VMIN] = blockUntilMin;
139 setting.c_cc[VTIME] = burstDeciSeconds;
140 if (tcsetattr(0, TCSANOW, &setting) < 0) return v;
141 v.resize(max);
142 const int n = read(0, &v[0], max);
143 if (n != max) v.resize(n < 0 ? 0 : n);
144
145 restore(original);
146 return v;
147 }
148
149 std::vector<char> TerminalCtrl::getCharsToDelimiter(char delimiter, bool includeDelimiter) {
150 _saveDefaults();
151 std::vector<char> result;
152 while (true) {
153 std::vector<char> v = getChars(1, 1);
154 if (v.empty()) break;
155 if (v[0] == delimiter && !includeDelimiter) break;
156 result.push_back(v[0]);
157 if (v[0] == delimiter) break;
158 }
159 return result;
160 }
161
162 std::string TerminalCtrl::getStringToDelimiter(char delimiter, bool includeDelimiter) {
163 _saveDefaults();
164 std::string s;
165 std::vector<char> v = getCharsToDelimiter(delimiter, includeDelimiter);
166 if (v.empty()) return s;
167 v.push_back(0);
168 int n = strlen(&v[0]);
169 s.resize(n);
170 memcpy(&s[0], &v[0], n);
171 return s;
172 }
173
174 int TerminalCtrl::columns() {
175 struct winsize w;
176 ioctl(0, TIOCGWINSZ, &w);
177 return w.ws_col;
178 }
179
180 int TerminalCtrl::rows() {
181 struct winsize w;
182 ioctl(0, TIOCGWINSZ, &w);
183 return w.ws_row;
184 }

  ViewVC Help
Powered by ViewVC