コンソールの改良(キー入力とスクロール)
help,calc,rpnコマンドの追加
@@ -17,6 +17,7 @@ | ||
17 | 17 | #include <bitnos/specialtask.h> |
18 | 18 | #include <bitnos/pit.h> |
19 | 19 | #include <bitnos/scancode.h> |
20 | +#include <bitnos/calc.h> | |
20 | 21 | |
21 | 22 | namespace TaskConsole |
22 | 23 | { |
@@ -172,6 +173,9 @@ | ||
172 | 173 | static void beep(Valiables* o, const char* arg); |
173 | 174 | static void eco(Valiables* o, const char* arg); |
174 | 175 | static void cat(Valiables* o, const char* arg); |
176 | + static void calc(Valiables* o, const char* arg); | |
177 | + static void rpn(Valiables* o, const char* arg); | |
178 | + static void help(Valiables* o, const char* arg); | |
175 | 179 | }; |
176 | 180 | |
177 | 181 | void Init(void* obj) |
@@ -255,6 +259,18 @@ | ||
255 | 259 | if (msg->arg1 != 0) { |
256 | 260 | if (msg->arg1 < 0x80) { |
257 | 261 | EraseCursor(o); |
262 | + if (o->cons.rLine < o->cons.wPos.Y - o->cons.height) { | |
263 | + o->cons.rLine = o->cons.wPos.Y - o->cons.height + 1; | |
264 | + if (o->cons.rLine < 0) { | |
265 | + o->cons.rLine = 0; | |
266 | + } | |
267 | + if (o->cons.wPos.Y < o->cons.height) { | |
268 | + o->cons.pPos.Y = o->cons.wPos.Y; | |
269 | + } else { | |
270 | + o->cons.pPos.Y = o->cons.height - 1; | |
271 | + } | |
272 | + ConsoleRefreshScreen(o, o->cons.rLine); | |
273 | + } | |
258 | 274 | PutChar(o, msg->arg1); |
259 | 275 | if (o->cursor) { |
260 | 276 | ShowCursor(o); |
@@ -322,10 +338,6 @@ | ||
322 | 338 | { |
323 | 339 | if (0x20 <= ch && ch < 0x80) { |
324 | 340 | o->cons.sbuf.Write(o->cons.wPos, ch); |
325 | - o->cons.wPos.X++; | |
326 | - if (o->cons.pPos.X < o->cons.width - 1) { | |
327 | - o->cons.pPos.X++; | |
328 | - } | |
329 | 341 | } |
330 | 342 | if (ch == '\b') { |
331 | 343 | if ((o->cons.wPos.Y != o->cmdlineBegin && o->cons.wPos.X > 0) || |
@@ -367,9 +379,13 @@ | ||
367 | 379 | o->cons.textColor, |
368 | 380 | ch, |
369 | 381 | Point( |
370 | - 4 + fontHankaku->GetWidth() * (o->cons.pPos.X - 1), | |
382 | + 4 + fontHankaku->GetWidth() * o->cons.pPos.X, | |
371 | 383 | 25 + 4 + fontHankaku->GetHeight() * o->cons.pPos.Y), |
372 | 384 | fontHankaku); |
385 | + o->cons.wPos.X++; | |
386 | + if (o->cons.pPos.X < o->cons.width) { | |
387 | + o->cons.pPos.X++; | |
388 | + } | |
373 | 389 | } |
374 | 390 | } |
375 | 391 |
@@ -390,20 +406,22 @@ | ||
390 | 406 | } |
391 | 407 | o->cmdline[i] = '\0'; |
392 | 408 | |
393 | - // 履歴を保存 | |
394 | - o->cons.History.buf.Write(o->cons.History.wPos, o->cmdline); | |
395 | - if (o->cons.History.wPos.Y < o->cons.History.buf.GetHeight() - 1) { | |
396 | - o->cons.History.wPos.Y++; | |
397 | - o->cons.History.rPos = o->cons.History.wPos; | |
398 | - } else { | |
399 | - o->cons.History.buf.Scroll(1); | |
409 | + if (o->cmdline[0] != '\0') { | |
410 | + // 履歴を保存 | |
411 | + o->cons.History.buf.Write(o->cons.History.wPos, o->cmdline); | |
412 | + if (o->cons.History.wPos.Y < o->cons.History.buf.GetHeight() - 1) { | |
413 | + o->cons.History.wPos.Y++; | |
414 | + } else { | |
415 | + o->cons.History.buf.Scroll(1); | |
416 | + } | |
417 | + | |
418 | + RunCommand(o); | |
400 | 419 | } |
401 | 420 | |
402 | - RunCommand(o); | |
403 | - | |
404 | 421 | o->cmdlineBegin = o->cons.wPos.Y; |
405 | 422 | PutChar0(o, '>'); |
406 | 423 | } |
424 | + o->cons.History.rPos = o->cons.History.wPos; | |
407 | 425 | } |
408 | 426 | |
409 | 427 | void PutString0(Valiables* o, const char* str) |
@@ -489,6 +507,12 @@ | ||
489 | 507 | ConsoleCommands::eco(o, args); |
490 | 508 | } else if (strncmp(command, "cat", 4) == 0) { |
491 | 509 | ConsoleCommands::cat(o, args); |
510 | + } else if (strncmp(command, "calc", 5) == 0) { | |
511 | + ConsoleCommands::calc(o, args); | |
512 | + } else if (strncmp(command, "rpn", 4) == 0) { | |
513 | + ConsoleCommands::rpn(o, args); | |
514 | + } else if (strncmp(command, "help", 5) == 0) { | |
515 | + ConsoleCommands::help(o, args); | |
492 | 516 | } else { |
493 | 517 | if (strlen(command) > 0) { |
494 | 518 | PutString0(o, "unknown command\n"); |
@@ -498,7 +522,7 @@ | ||
498 | 522 | |
499 | 523 | void ShowCursor(Valiables* o) |
500 | 524 | { |
501 | - if (o->cons.pPos.X < 0 || o->cons.width <= o->cons.pPos.X || | |
525 | + if (o->cons.pPos.X < 0 || o->cons.width < o->cons.pPos.X || | |
502 | 526 | o->cons.pPos.Y < 0 || o->cons.height <= o->cons.pPos.Y) { |
503 | 527 | return; |
504 | 528 | } |
@@ -512,7 +536,7 @@ | ||
512 | 536 | |
513 | 537 | void EraseCursor(Valiables* o) |
514 | 538 | { |
515 | - if (o->cons.pPos.X < 0 || o->cons.width <= o->cons.pPos.X || | |
539 | + if (o->cons.pPos.X < 0 || o->cons.width < o->cons.pPos.X || | |
516 | 540 | o->cons.pPos.Y < 0 || o->cons.height <= o->cons.pPos.Y) { |
517 | 541 | return; |
518 | 542 | } |
@@ -645,6 +669,43 @@ | ||
645 | 669 | PutString0(o, " {_.-``-' {_/\n"); |
646 | 670 | } |
647 | 671 | |
672 | +void ConsoleCommands::calc(Valiables* o, const char* arg) | |
673 | +{ | |
674 | + char s[32]; | |
675 | + sprintf(s, "%d\n", Calc::Calc(arg)); | |
676 | + PutString0(o, s); | |
677 | +} | |
678 | + | |
679 | +void ConsoleCommands::rpn(Valiables* o, const char* arg) | |
680 | +{ | |
681 | + char s[32]; | |
682 | + sprintf(s, "%d\n", Calc::RPNCalc(arg)); | |
683 | + PutString0(o, s); | |
684 | +} | |
685 | + | |
686 | +void ConsoleCommands::help(Valiables* o, const char* arg) | |
687 | +{ | |
688 | + /* | |
689 | + static void mem(Valiables* o, const char* arg); | |
690 | + static void opencons(Valiables* o, const char* arg); | |
691 | + static void echo(Valiables* o, const char* arg); | |
692 | + static void beep(Valiables* o, const char* arg); | |
693 | + static void eco(Valiables* o, const char* arg); | |
694 | + static void cat(Valiables* o, const char* arg); | |
695 | + static void calc(Valiables* o, const char* arg); | |
696 | + static void rpn(Valiables* o, const char* arg); | |
697 | + */ | |
698 | + PutString0(o, "command list\n"); | |
699 | + PutString0(o, "mem : memory information\n"); | |
700 | + PutString0(o, "opencons : opens new console\n"); | |
701 | + PutString0(o, "echo arg : echoes argument\n"); | |
702 | + PutString0(o, "beep [freq] : beeps sound\n"); | |
703 | + PutString0(o, "eco : do an ecological act\n"); | |
704 | + PutString0(o, "cat [file]: print contents of file\n"); | |
705 | + PutString0(o, "calc exp : calculates exp\n"); | |
706 | + PutString0(o, "rpn : calculates exp in rpn\n"); | |
707 | +} | |
708 | + | |
648 | 709 | void PrintHistoryUp(Valiables* o) |
649 | 710 | { |
650 | 711 | if (o->cons.History.rPos.Y >= 0) { |
@@ -0,0 +1,261 @@ | ||
1 | +/* | |
2 | + * calc.cpp | |
3 | + * | |
4 | + * Created on: 2009/10/30 | |
5 | + * Author: uchan | |
6 | + */ | |
7 | + | |
8 | +#include <string.h> | |
9 | +#include <stdlib.h> | |
10 | + | |
11 | +#include <bitnos/calc.h> | |
12 | + | |
13 | +int pow(int x, unsigned int p) | |
14 | +{ | |
15 | + int result = 1; | |
16 | + int temp = x; | |
17 | + while (p > 0) { | |
18 | + if ((p & 1) == 1) { | |
19 | + result *= temp; | |
20 | + } | |
21 | + temp = temp * temp; | |
22 | + p = (p >> 1); | |
23 | + } | |
24 | + return result; | |
25 | +} | |
26 | + | |
27 | +namespace Calc { | |
28 | + | |
29 | +bool IsSpace(char c) | |
30 | +{ | |
31 | + return c == ' ' || c == '\t'; | |
32 | +} | |
33 | + | |
34 | +bool IsDigit(char c) | |
35 | +{ | |
36 | + return '0' <= c && c <= '9'; | |
37 | +} | |
38 | + | |
39 | +bool IsSingleOperator(char c) | |
40 | +{ | |
41 | + return c == '+' || c == '-' || c == '~'; | |
42 | +} | |
43 | + | |
44 | +const char* SkipSpace(const char* p) | |
45 | +{ | |
46 | + while (*p != '\0' && IsSpace(*p)) { | |
47 | + p++; | |
48 | + } | |
49 | + return p; | |
50 | +} | |
51 | + | |
52 | +class Stack | |
53 | +{ | |
54 | + static const int stackSize = 32; | |
55 | + int stack[stackSize]; | |
56 | + int sp; | |
57 | + int dummy; | |
58 | + | |
59 | +public: | |
60 | + void Init(); | |
61 | + | |
62 | + void Push(int item); | |
63 | + | |
64 | + int Pop(); | |
65 | + | |
66 | + int& operator[](int index); | |
67 | +}; | |
68 | + | |
69 | +void Stack::Init() | |
70 | +{ | |
71 | + sp = stackSize - 1; | |
72 | + dummy = 123454321; | |
73 | +} | |
74 | + | |
75 | +void Stack::Push(int item) | |
76 | +{ | |
77 | + if (sp >= 0) { | |
78 | + stack[sp--] = item; | |
79 | + } | |
80 | +} | |
81 | + | |
82 | +int Stack::Pop() | |
83 | +{ | |
84 | + if (sp < stackSize - 1) { | |
85 | + return stack[++sp]; | |
86 | + } | |
87 | + return 0; | |
88 | +} | |
89 | + | |
90 | +int& Stack::operator [](int index) | |
91 | +{ | |
92 | + if (0<= index && index < stackSize) { | |
93 | + return stack[index]; | |
94 | + } | |
95 | + return dummy; | |
96 | +} | |
97 | + | |
98 | +int RPNCalc(const char* exp) | |
99 | +{ | |
100 | + Stack stack; | |
101 | + char elem[32]; | |
102 | + int i = 0; | |
103 | + int var1, var2; | |
104 | + | |
105 | + char sop; | |
106 | + | |
107 | + stack.Init(); | |
108 | + | |
109 | + while (*exp != '\0') { | |
110 | + exp = SkipSpace(exp); | |
111 | + i = 0; | |
112 | + sop = '\0'; | |
113 | + if (IsSingleOperator(exp[0]) && IsDigit(exp[1])) { | |
114 | + sop = *exp++; | |
115 | + while (*exp != '\0' && IsDigit(*exp)) { | |
116 | + elem[i++] = *exp++; | |
117 | + } | |
118 | + } else if (IsDigit(*exp)) { | |
119 | + while (*exp != '\0' && IsDigit(*exp)) { | |
120 | + elem[i++] = *exp++; | |
121 | + } | |
122 | + } else { | |
123 | + elem[i++] = *exp++; | |
124 | + } | |
125 | + elem[i] = '\0'; | |
126 | + | |
127 | + if (strcmp("+", elem) == 0) { | |
128 | + var2 = stack.Pop(); | |
129 | + var1 = stack.Pop(); | |
130 | + stack.Push(var1 + var2); | |
131 | + } else if (strcmp("-", elem) == 0) { | |
132 | + var2 = stack.Pop(); | |
133 | + var1 = stack.Pop(); | |
134 | + stack.Push(var1 - var2); | |
135 | + } else if (strcmp("*", elem) == 0) { | |
136 | + var2 = stack.Pop(); | |
137 | + var1 = stack.Pop(); | |
138 | + stack.Push(var1 * var2); | |
139 | + } else if (strcmp("/", elem) == 0) { | |
140 | + var2 = stack.Pop(); | |
141 | + var1 = stack.Pop(); | |
142 | + if (var2 != 0) { | |
143 | + stack.Push(var1 / var2); | |
144 | + } else { | |
145 | + stack.Push(0); | |
146 | + } | |
147 | + } else if (strcmp("%", elem) == 0) { | |
148 | + var2 = stack.Pop(); | |
149 | + var1 = stack.Pop(); | |
150 | + stack.Push(var1 % var2); | |
151 | + } else if (strcmp("^", elem) == 0) { | |
152 | + var2 = stack.Pop(); | |
153 | + var1 = stack.Pop(); | |
154 | + stack.Push(pow(var1, var2)); | |
155 | + } else { | |
156 | + var1 = strtol(elem, 0, 0); | |
157 | + if (sop == '-') { | |
158 | + var1 = -var1; | |
159 | + } else if (sop == '~') { | |
160 | + var1 = ~var1; | |
161 | + } | |
162 | + stack.Push(var1); | |
163 | + } | |
164 | + } | |
165 | + | |
166 | + return stack.Pop(); | |
167 | +} | |
168 | + | |
169 | +class Convert | |
170 | +{ | |
171 | + char* s; | |
172 | + const char* exp; | |
173 | + void E(); | |
174 | + void T(); | |
175 | + void F(); | |
176 | +public: | |
177 | + void Do(char* s, const char* exp); | |
178 | +}; | |
179 | + | |
180 | +void Convert::E() | |
181 | +{ | |
182 | + T(); | |
183 | + while (!0) { | |
184 | + const char* p = exp = SkipSpace(exp); | |
185 | + if (*exp == '+' || *exp == '-') { | |
186 | + char c = *exp++; | |
187 | + T(); | |
188 | + *s++ = ' '; | |
189 | + *s++ = c; | |
190 | + } else { | |
191 | + break; | |
192 | + } | |
193 | + if (p == exp) { | |
194 | + break; | |
195 | + } | |
196 | + } | |
197 | +} | |
198 | + | |
199 | +void Convert::T() | |
200 | +{ | |
201 | + F(); | |
202 | + while (!0) { | |
203 | + const char* p = exp = SkipSpace(exp); | |
204 | + if (*exp == '*' || *exp == '/') { | |
205 | + char c = *exp++; | |
206 | + F(); | |
207 | + *s++ = ' '; | |
208 | + *s++ = c; | |
209 | + } else { | |
210 | + break; | |
211 | + } | |
212 | + if (p == exp) { | |
213 | + break; | |
214 | + } | |
215 | + } | |
216 | +} | |
217 | + | |
218 | +void Convert::F() | |
219 | +{ | |
220 | + exp = SkipSpace(exp); | |
221 | + if (*exp == '(') { | |
222 | + exp++; | |
223 | + E(); | |
224 | + exp = SkipSpace(exp); | |
225 | + if (*exp == ')') { | |
226 | + exp++; | |
227 | + } | |
228 | + } else { | |
229 | + *s++ = ' '; | |
230 | + if (*exp == '+' || *exp == '-') { | |
231 | + *s++ = *exp++; | |
232 | + } | |
233 | + while (*exp != '\0' && IsDigit(*exp)) { | |
234 | + *s++ = *exp++; | |
235 | + } | |
236 | + | |
237 | + } | |
238 | +} | |
239 | + | |
240 | +void Convert::Do(char* s, const char* exp) | |
241 | +{ | |
242 | + // 中置→後置 | |
243 | + this->s = s; | |
244 | + this->exp = exp; | |
245 | + E(); | |
246 | + *this->s = '\0'; | |
247 | + if (*this->exp != '\0') { | |
248 | + strcat(s, " ERR"); | |
249 | + } | |
250 | + | |
251 | +} | |
252 | + | |
253 | +int Calc(const char* exp) | |
254 | +{ | |
255 | + Convert conv; | |
256 | + char s[128]; | |
257 | + conv.Do(s, exp); | |
258 | + return RPNCalc(s); | |
259 | +} | |
260 | + | |
261 | +} |
@@ -0,0 +1,17 @@ | ||
1 | +/* | |
2 | + * calc.h | |
3 | + * | |
4 | + * Created on: 2009/10/30 | |
5 | + * Author: uchan | |
6 | + */ | |
7 | + | |
8 | +#ifndef CALC_H_ | |
9 | +#define CALC_H_ | |
10 | + | |
11 | +namespace Calc | |
12 | +{ | |
13 | +int RPNCalc(const char* exp); | |
14 | +int Calc(const char* exp); | |
15 | +} | |
16 | + | |
17 | +#endif /* CALC_H_ */ |