]> git.gir.st - solVItaire.git/blob - sol.c
highlighting (dirty alpha), fix remove_if_complete, find_top
[solVItaire.git] / sol.c
1 #define _DEFAULT_SOURCE
2 #include <poll.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <time.h>
6 #include <termios.h>
7 #include <unistd.h>
8
9 #include "sol.h"
10 #include "schemes.h"
11
12 #ifdef KLONDIKE
13 #define NUM_PILES 7
14 #define MAX_HIDDEN 6 /*how many cards are turned over at most in a tableu pile*/
15 #define MAX_STOCK 24 /*how many cards can be in the stock at most (=@start)*/
16 #define NUM_DECKS 1
17 #define PILE_SIZE MAX_HIDDEN+NUM_RANKS
18 #elif defined SPIDER
19 #define MAX_HIDDEN 5
20 #define NUM_PILES 10
21 #define MAX_STOCK 50 /*how many cards can be dealt onto the piles*/
22 #define NUM_DECKS 2
23 #define PILE_SIZE DECK_SIZE*NUM_DECKS /* no maximum stack size in spider :/ */
24 #endif
25
26 #define get_suit(card) \
27 ((card-1) % NUM_SUITS)
28 #define get_rank(card) \
29 ((card-1) / NUM_SUITS)
30 #define get_color(card) \
31 ((get_suit(card) ^ get_suit(card)>>1) & 1)
32
33 struct playfield {
34 //TODO: stock and waste are incompatible with undo{}
35 card_t s[MAX_STOCK]; /* stock */
36 int z; /* stock size */
37 int w; /* waste; index into stock (const -1 in spider) */
38 card_t f[NUM_DECKS*NUM_SUITS][PILE_SIZE]; /* foundation (XXX@spider:complete set gets put on seperate pile, so undo is easy) */
39 card_t t[NUM_PILES][PILE_SIZE]; /* tableu piles */
40 struct undo {
41 int from; /* pile cards were taken from */
42 int to; /* pile cards were moved to */
43 int n; /* number of cards moved */
44 struct undo* prev;
45 struct undo* next;
46 } u;
47 } f;
48 struct opts {
49 #ifdef SPIDER
50 int m; /* difficulty mode */
51 #endif
52 const struct scheme* s;
53 } op;
54
55 // action table {{{
56 #ifdef KLONDIKE
57 /* stores a function pointer for every takeable action; called by game loop */
58 int (*action[10][10])(int,int) = {
59 /*fnd 1 2 3 4 5 6 7 stk wst*/
60 /*fnd*/ { nop, f2t, f2t, f2t, f2t, f2t, f2t, f2t, nop, nop },
61 /* 1 */ { t2f, t2f, t2t, t2t, t2t, t2t, t2t, t2t, nop, nop },
62 /* 2 */ { t2f, t2t, t2f, t2t, t2t, t2t, t2t, t2t, nop, nop },
63 /* 3 */ { t2f, t2t, t2t, t2f, t2t, t2t, t2t, t2t, nop, nop },
64 /* 4 */ { t2f, t2t, t2t, t2t, t2f, t2t, t2t, t2t, nop, nop },
65 /* 5 */ { t2f, t2t, t2t, t2t, t2t, t2f, t2t, t2t, nop, nop },
66 /* 6 */ { t2f, t2t, t2t, t2t, t2t, t2t, t2f, t2t, nop, nop },
67 /* 7 */ { t2f, t2t, t2t, t2t, t2t, t2t, t2t, t2f, nop, nop },
68 /*stk*/ { nop, nop, nop, nop, nop, nop, nop, nop, nop, s2w },
69 /*wst*/ { w2f, w2t, w2t, w2t, w2t, w2t, w2t, w2t, w2s, w2f },
70 };
71 #elif defined SPIDER
72 int (*action[11][10])(int,int) = {
73 /* 0 1 2 3 4 5 6 7 8 9 */
74 /* 0 */ { nop, t2t, t2t, t2t, t2t, t2t, t2t, t2t, t2t, t2t },
75 /* 1 */ { t2t, nop, t2t, t2t, t2t, t2t, t2t, t2t, t2t, t2t },
76 /* 2 */ { t2t, t2t, nop, t2t, t2t, t2t, t2t, t2t, t2t, t2t },
77 /* 3 */ { t2t, t2t, t2t, nop, t2t, t2t, t2t, t2t, t2t, t2t },
78 /* 4 */ { t2t, t2t, t2t, t2t, nop, t2t, t2t, t2t, t2t, t2t },
79 /* 5 */ { t2t, t2t, t2t, t2t, t2t, nop, t2t, t2t, t2t, t2t },
80 /* 6 */ { t2t, t2t, t2t, t2t, t2t, t2t, nop, t2t, t2t, t2t },
81 /* 7 */ { t2t, t2t, t2t, t2t, t2t, t2t, t2t, nop, t2t, t2t },
82 /* 8 */ { t2t, t2t, t2t, t2t, t2t, t2t, t2t, t2t, nop, t2t },
83 /* 9 */ { t2t, t2t, t2t, t2t, t2t, t2t, t2t, t2t, t2t, nop },
84 /*stk*/ { s2t, s2t, s2t, s2t, s2t, s2t, s2t, s2t, s2t, s2t },
85 };
86 #endif
87 // }}}
88
89 int main(int argc, char** argv) {
90 op.s = &unicode_large_color;
91 #ifdef SPIDER
92 op.m = MEDIUM; //TODO: make configurable
93 op.m = EASY;
94 #endif
95 screen_setup(1);
96 sol(); //TODO: restart, etc.
97 screen_setup(0);
98 }
99
100 void sol(void) {
101 deal();
102
103 int from, to;
104 print_table(-2);
105 for(;;) {
106 switch (get_cmd(&from, &to)) {
107 case CMD_MOVE:
108 switch (action[from][to](from,to)) {
109 case OK: break;
110 case ERR: visbell(); break;
111 case WON:
112 print_table(-2);
113 win_anim();
114 getchar(); /* consume char left by win_anim() */
115 return;
116 }
117 break;
118 case CMD_QUIT: return;
119 }
120 print_table(-2);
121 }
122 }
123
124 int find_top(card_t* pile) {
125 int i;
126 for(i=PILE_SIZE-1; i>=0 && !pile[i]; i--);
127 return i;
128 }
129 void turn_over(card_t* pile) {
130 int top = find_top(pile);
131 if (pile[top] < 0) pile[top] *= -1;
132 }
133 int check_won(void) {
134 for (int pile = 0; pile < NUM_DECKS*NUM_COLORS; pile++)
135 if (f.f[pile][NUM_RANKS-1] == NO_CARD) return 0;
136
137 return 1;
138 }
139 void win_anim(void) {
140 printf ("\033[?25l"); /* hide cursor */
141 for (;;) {
142 /* set cursor to random location */
143 int row = 1+random()%(24-op.s->width);
144 int col = 1+random()%(80-op.s->height);
145
146 /* draw random card */
147 int face = 1 + random() % 52;
148 for (int l = 0; l < op.s->height; l++) {
149 printf ("\033[%d;%dH", row+l, col);
150 printf ("%s", op.s->card[face][l]);
151 }
152 fflush (stdout);
153
154 /* exit on keypress */
155 struct pollfd p = {STDIN_FILENO, POLLIN, 0};
156 if (poll (&p, 1, 80)) return;
157 }
158 }
159 // takeable actions {{{
160 #ifdef KLONDIKE
161 card_t stack_take(void) { /*NOTE: assert(f.w >= 0) */
162 card_t card = f.s[f.w];
163 /* move stack one over, so there are no gaps in it: */
164 for (int i = f.w; i < f.z-1; i++)
165 f.s[i] = f.s[i+1];
166 f.z--;
167 f.w--; /* make previous card visible again */
168 return card;
169 }
170 int t2f(int from, int to) { /* tableu to foundation */
171 from--; //remove off-by-one
172 int top_from = find_top(f.t[from]);
173 to = get_suit(f.t[from][top_from]);
174 int top_to = find_top(f.f[to]);
175 if ((top_to < 0 && get_rank(f.t[from][top_from]) == RANK_A)
176 || (top_to >= 0 && get_rank(f.f[to][top_to]) == get_rank(f.t[from][top_from])-1)) {
177 f.f[to][top_to+1] = f.t[from][top_from];
178 f.t[from][top_from] = NO_CARD;
179 turn_over(f.t[from]);
180 if (check_won()) return WON;
181 return OK;
182 } else return ERR;
183 }
184 int w2f(int from, int to) { /* waste to foundation */
185 if (f.w < 0) return ERR;
186 to = get_suit(f.s[f.w]);
187 int top_to = find_top(f.f[to]);
188 if ((top_to < 0 && get_rank(f.s[f.w]) == RANK_A)
189 || (top_to >= 0 && get_rank(f.f[to][top_to]) == get_rank(f.s[f.w])-1)) {
190 f.f[to][top_to+1] = stack_take();
191 if (check_won()) return WON;
192 return OK;
193 } else return ERR;
194
195 }
196 int s2w(int from, int to) { /* stock to waste */
197 if (f.z == 0) return ERR;
198 f.w++;
199 if (f.w == f.z) f.w = -1;
200 return OK;
201 }
202 int w2s(int from, int to) { /* waste to stock (undoes stock to waste) */
203 if (f.z == 0) return ERR;
204 f.w--;
205 if (f.w < -1) f.w = f.z-1;
206 return OK;
207 }
208 int f2t(int from, int to) { /* foundation to tableu */
209 to--; //remove off-by-one
210 int top_to = find_top(f.t[to]);
211 printf ("take from (1-4): "); fflush (stdout);
212 from = getchar() - '0';
213 if (from > 4 || from < 1) return ERR;
214 from--; //remove off-by-one
215 int top_from = find_top(f.f[from]);
216
217 if ((get_color(f.t[to][top_to]) != get_color(f.f[from][top_from]))
218 && (get_rank(f.t[to][top_to]) == get_rank(f.f[from][top_from])+1)) {
219 f.t[to][top_to+1] = f.f[from][top_from];
220 f.f[from][top_from] = NO_CARD;
221 return OK;
222 } else return ERR;
223 }
224 int w2t(int from, int to) { /* waste to tableu */
225 to--; //remove off-by-one
226 int top_to = find_top(f.t[to]);
227 if (((get_color(f.t[to][top_to]) != get_color(f.s[f.w]))
228 && (get_rank(f.t[to][top_to]) == get_rank(f.s[f.w])+1))
229 || (top_to < 0 && get_rank(f.s[f.w]) == RANK_K)) {
230 f.t[to][top_to+1] = stack_take();
231 return OK;
232 } else return ERR;
233 }
234 int t2t(int from, int to) { /* tableu to tableu */
235 from--; to--; //remove off-by-one
236 int top_to = find_top(f.t[to]);
237 int top_from = find_top(f.t[from]);
238 for (int i = top_from; i >=0; i--) {
239 if (((get_color(f.t[to][top_to]) != get_color(f.t[from][i]))
240 && (get_rank(f.t[to][top_to]) == get_rank(f.t[from][i])+1)
241 && f.t[from][i] > NO_CARD) /* card face up? */
242 || (top_to < 0 && get_rank(f.t[from][i]) == RANK_K)) {
243 /* move cards [i..top_from] to their destination */
244 for (;i <= top_from; i++) {
245 top_to++;
246 f.t[to][top_to] = f.t[from][i];
247 f.t[from][i] = NO_CARD;
248 }
249 turn_over(f.t[from]);
250 return OK;
251 }
252 }
253 return ERR; /* no such move possible */
254 }
255 #elif defined SPIDER
256 void remove_if_complete (card_t* pile) { //TODO: cleanup
257 static int foundation = 0; /* foundation to put pile onto */
258 /* test if K...A complete; move to foundation if so */
259 int top_from = find_top(pile);
260 if (get_rank(pile[top_from]) != RANK_A) return;
261 for (int i = top_from; i>=0; i--) {
262 if ((i+1 < PILE_SIZE && pile[i+1] != NO_CARD) // card below or last? XXX: copied from t2t()--make function
263 && (get_rank(pile[i+1]) != get_rank(pile[i])-1) //cards not consecutive?
264 ) {
265 return;
266 }
267 if ((i+1 < PILE_SIZE && pile[i+1] != NO_CARD) // card below or last?
268 && (get_suit(pile[i+1]) != get_suit(pile[i])) //cards not same suit?
269 ) {
270 return;
271 }
272 if (i+RANK_K == top_from
273 && get_rank(pile[top_from-RANK_K]) == RANK_K) { //ace to king ok, remove it
274 for (int i = top_from, j = 0; i >= top_from-NUM_RANKS; i--, j++) {
275 f.f[foundation][j] = pile[i];
276 pile[i] = NO_CARD;
277 }
278 foundation++;
279 turn_over(pile);
280 return;
281 }
282 }
283 }
284 int t2t(int from, int to) { //TODO: in dire need of cleanup
285 //TODO: segfaulted once on large column
286 //TODO: sometimes moving doesn't work (ERR when it should be OK) XXX
287 from--; to--; //remove off-by-one
288 (from < 0) && (from = 9); /* '0' is tenth ([9]) pile */
289 (to < 0) && (to = 9); /* ditto */
290
291 int top_from = find_top(f.t[from]);
292 int top_to = find_top(f.t[to]);
293 int empty_to = -1; //awful, nondescriptive name :/
294 if (top_to < 0) { /* empty pile? */
295 printf ("\rup to (a23456789xjqk): "); //TODO: automatically do it if only 1 card movable XXX: cant move ace
296 empty_to = getchar();
297 switch (empty_to) {
298 case 'a': case 'A': empty_to = RANK_A; break;
299 case '0': /* fallthrough */
300 case 'x': case 'X': empty_to = RANK_X; break;
301 case 'j': case 'J': empty_to = RANK_J; break;
302 case 'q': case 'Q': empty_to = RANK_Q; break;
303 case 'k': case 'K': empty_to = RANK_K; break;
304 default: empty_to -= '1';
305 }
306 if (empty_to < RANK_A || empty_to > RANK_K) return ERR;
307 }
308 for (int i = top_from; i >= 0; i--) {
309 if ((i+1 < PILE_SIZE && f.t[from][i+1] != NO_CARD) // card below or last?
310 && (get_rank(f.t[from][i+1]) != get_rank(f.t[from][i])-1) //cards not consecutive?
311 ) {
312 break;
313 }
314 if ((i+1 < PILE_SIZE && f.t[from][i+1] != NO_CARD) // card below or last?
315 && (get_suit(f.t[from][i+1]) != get_suit(f.t[from][i])) //cards not same suit?
316 ) {
317 break;
318 }
319
320 if ((get_rank(f.t[from][i]) == get_rank(f.t[to][top_to])-1) // consecutive?
321 || (empty_to >= RANK_A && get_rank(f.t[from][i]) == empty_to)) { //to empty pile and rank ok?
322 for (;i <= top_from; i++) {
323 top_to++;
324 f.t[to][top_to] = f.t[from][i];
325 f.t[from][i] = NO_CARD;
326 }
327 turn_over(f.t[from]);
328 remove_if_complete (f.t[to]);
329 if (check_won()) return WON;
330 return OK;
331 }
332 }
333
334 return ERR; /* no such move possible */
335 }
336 int s2t(int from, int to) { //TODO: check remove, won
337 if (f.z <= 0) return ERR; /* stack out of cards */
338 for (int pile = 0; pile < NUM_PILES; pile++)
339 if (f.t[pile][0]==NO_CARD) return ERR; /*no piles may be empty*/
340 for (int pile = 0; pile < NUM_PILES; pile++) {
341 f.t[pile][find_top(f.t[pile])+1] = f.s[--f.z];
342 }
343 return OK;
344 }
345 #endif
346 int nop(int from, int to) { return ERR; }
347 // }}}
348
349 int get_cmd (int* from, int* to) {
350 //returns 0 on success or an error code indicating game quit, new game,...
351 //TODO: check validity, escape sequences (mouse, cursor keys)
352 //TODO: should return enums, then make piles 0-n
353 char f, t;
354 //printf ("from: "); fflush (stdout);
355 f = getchar();
356 if (f=='\n') { /* shortcut for dealing from stock */
357 #ifdef KLONDIKE
358 *from = 8;
359 *to = 9;
360 #elif defined SPIDER
361 *from = 10;
362 *to = 0;
363 #endif
364 return CMD_MOVE;
365 }
366 switch (f) {
367 case 'q': return CMD_QUIT;
368 case 'r': return CMD_NEW; //TODO
369 case 'h': return CMD_HINT; //TODO
370 case '?': return CMD_HELP; //TODO
371 case '/': return CMD_FIND; //TODO: highlight card of given rank (even non-movable)
372 default: if (f < '0' || f > '9') return CMD_INVAL;
373 }
374 //printf ("\r \rto: "); fflush (stdout);
375 print_table(f-'1');
376 t =
377 #ifdef KLONDIKE
378 (f=='8')?'9':
379 #endif
380 getchar();
381 if (t < '0' || t > '9') return CMD_INVAL;
382 *from = f-'0';
383 *to = t-'0';
384 return CMD_MOVE;
385 }
386
387 void deal(void) {
388 f = (const struct playfield){0}; /* clear playfield */
389 card_t deck[DECK_SIZE*NUM_DECKS];
390 int avail = DECK_SIZE*NUM_DECKS;
391 for (int i = 0; i < DECK_SIZE*NUM_DECKS; i++) deck[i] = (i%DECK_SIZE)+1;
392 #ifdef SPIDER
393 if (op.m != NORMAL) for (int i = 0; i < DECK_SIZE*NUM_DECKS; i++) {
394 if (op.m == MEDIUM) deck[i] = 1+((deck[i]-1) | 2);
395 if (op.m == EASY) deck[i] = 1+((deck[i]-1) | 2 | 1);
396 /* the 1+ -1 dance gets rid of the offset created by NO_CARD */
397 }
398 #endif
399 srandom (time(NULL));
400 /*XXX*/ long seed = time(NULL);
401 /*XXX*/ srandom (seed);
402 for (int i = DECK_SIZE*NUM_DECKS-1; i > 0; i--) { //fisher-yates
403 int j = random() % (i+1);
404 if (j-i) deck[i]^=deck[j],deck[j]^=deck[i],deck[i]^=deck[j];
405 }
406 ///////////////////////////////////////////////XXX
407 //sometimes we see duplicate cards. this tries to catch that
408 int count[_NUM_CARDS_internal] = {0};
409 for (int i = 0; i < DECK_SIZE*NUM_DECKS; i++)
410 count[deck[i]]++;
411 for (int i = 0; i < _NUM_CARDS_internal; i++){ //0 is NO_CARD
412 #ifdef SPIDER
413 int x = op.m==MEDIUM?2:op.m==EASY?4:1;
414 #else
415 int x = 1;
416 #endif
417 if (deck[i] == NO_CARD) continue;
418 if (count[deck[i]] != NUM_DECKS*x) {
419 screen_setup(0);
420 printf ("found duplicate card with seed %lx!\n", seed);
421 for (int i = 1; i < _NUM_CARDS_internal; i++)
422 printf ("%3d of %2d\n", count[deck[i]], deck[i]);
423 exit(1);
424 }
425 }
426 ///////////////////////////////////////////////XXX
427
428 /* deal cards: */
429 for (int i = 0; i < NUM_PILES; i++) {
430 #ifdef KLONDIKE
431 int closed = i; /* pile n has n closed cards, then 1 open */
432 #elif defined SPIDER
433 int closed = i<4?5:4; /* pile 1-4 have 5, 5-10 have 4 closed */
434 #endif
435 /* face down cards are negated: */
436 for (int j = 0; j < closed; j++) f.t[i][j] = -deck[--avail];
437 f.t[i][closed] = deck[--avail]; /* the face-up card */
438 }
439 /* rest of the cards to the stock; NOTE: assert(avail==50) for spider */
440 for (f.z = 0; avail; f.z++) f.s[f.z] = deck[--avail];
441 f.w = -1; /* @start: nothing on waste (no waste in spider -> const) */
442 }
443
444 int is_movable(card_t* pile, int n) { //TODO cleanup, code deduplication, needs entry in sol.h
445 #ifdef KLONDIKE
446 return(pile[n] > NO_CARD); /*non-movable cards don't exist in klondike*/
447 #elif defined SPIDER
448 int top = find_top(pile);
449 for (int i = top; i; i--) {
450 if (pile[i] <= NO_CARD) return 0; //card face down?
451 if ((i+1 < PILE_SIZE && pile[i+1] != NO_CARD) // card below or last? //COPIED FROM t2t
452 && (get_rank(pile[i+1]) != get_rank(pile[i])-1) //cards not consecutive?
453 ) {
454 return 0;
455 }
456 if ((i+1 < PILE_SIZE && pile[i+1] != NO_CARD) // card below or last?
457 && (get_suit(pile[i+1]) != get_suit(pile[i])) //cards not same suit?
458 ) {
459 return 0;
460 }
461 if (i == n) return 1; //card reached, must be movable
462 }
463 return 0;
464 #endif
465 }
466 #define print_hi(test, str) /* for highlighting during get_cmd() */ \
467 printf ("%s%s%s", (test)?"\033[7m":"", str, (test)?"\033[27m":"")
468 void print_table(int highlight) { //{{{
469 printf("\033[2J\033[H"); /* clear screen, reset cursor */
470 #ifdef KLONDIKE
471 /* print stock, waste and foundation: */
472 for (int line = 0; line < op.s->height; line++) {
473 //printf ("%s", ( /* stock */
474 print_hi (highlight == 7, ( //TODO: stupid magic number
475 (f.w < f.z-1)?op.s->facedown
476 :op.s->placeholder)[line]);
477 //printf ("%s", ( /* waste */
478 print_hi (highlight == 8, ( //TODO: stupid magic number
479 /* NOTE: cast, because f.w sometimes is (short)-1 !? */
480 ((short)f.w >= 0)?op.s->card[f.s[f.w]]
481 :op.s->placeholder)[line]);
482 printf ("%s", op.s->card[NO_CARD][line]); /* spacer */
483 /* foundation: */
484 for (int pile = 0; pile < NUM_SUITS; pile++) {
485 int card = find_top(f.f[pile]);
486 //printf ("%s",
487 print_hi (highlight == -1, //TODO: stupid magic number
488 (card < 0)?op.s->placeholder[line]
489 :op.s->card[f.f[pile][card]][line]);
490 }
491 printf("\n");
492 }
493 printf("\n");
494 #endif
495 /* print tableu piles: */
496 int row[NUM_PILES] = {0};
497 int line[NUM_PILES]= {0};
498 int label[NUM_PILES]={0};// :|
499 int line_had_card; // :|
500 do {
501 line_had_card = 0;
502 for (int pile = 0; pile < NUM_PILES; pile++) {
503 card_t card = f.t[pile][row[pile]];
504 card_t next = f.t[pile][row[pile]+1];
505 //printf ("%s", (
506 //TODO: pile 10 not highlighted!
507 //print_hi (highlight == pile && card>0, (
508 print_hi (highlight == pile && is_movable(f.t[pile],row[pile]), (
509 (card<0)?op.s->facedown
510 :op.s->card[card]
511 )[line[pile]]);
512
513 if (++line[pile] >= (next?op.s->overlap:op.s->height) //normal overlap
514 #if 0 //XXX
515 || (line[pile] >= 1 &&
516 f.t[pile][row[pile]] < 0 &&
517 f.t[pile][row[pile]+1] <0) //extreme overlap on closed
518 || (0) //extreme overlap on sequence TODO
519 #endif
520 ) {
521 line[pile]=0;
522 row[pile]++;
523 }
524 if(!card && !label[pile]) { /* tableu labels: */
525 label[pile] = 1;
526 printf ("\b\b%d ", (pile+1) % 10); //XXX: hack
527 }
528 line_had_card |= !!card;
529 }
530 printf ("\n");
531 } while (line_had_card);
532 }//}}}
533
534 void visbell (void) {
535 printf ("\033[?5h"); fflush (stdout);
536 usleep (100000);
537 printf ("\033[?5l"); fflush (stdout);
538 }
539
540 void append_undo (int n, int f, int t) {
541 //check if we have to free redo buffer (.next)
542 //malloc
543 //update pointers
544 //TODO: undo; needs operations to be written by x2y()
545 }
546
547 void screen_setup (int enable) {
548 if (enable) {
549 raw_mode(1);
550 printf ("\033[s\033[?47h"); /* save cursor, alternate screen */
551 printf ("\033[H\033[J"); /* reset cursor, clear screen */
552 //TODO//printf ("\033[?1000h\033[?25l"); /* enable mouse, hide cursor */
553 //printf (op.s->init_seq); /*swich charset, if necessary*/
554 } else {
555 //printf (op.s->reset_seq);/*reset charset, if necessary*/
556 //TODO//printf ("\033[?9l\033[?25h"); /* disable mouse, show cursor */
557 printf ("\033[?47l\033[u"); /* primary screen, restore cursor */
558 raw_mode(0);
559 }
560 }
561
562 void raw_mode(int enable) { //{{{
563 static struct termios saved_term_mode;
564 struct termios raw_term_mode;
565
566 if (enable) {
567 tcgetattr(STDIN_FILENO, &saved_term_mode);
568 raw_term_mode = saved_term_mode;
569 raw_term_mode.c_lflag &= ~(ICANON | ECHO);
570 raw_term_mode.c_cc[VMIN] = 1 ;
571 raw_term_mode.c_cc[VTIME] = 0;
572 tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw_term_mode);
573 } else {
574 tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_term_mode);
575 }
576 } //}}}
577
578 //vim: foldmethod=marker
Imprint / Impressum