|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * conio frontend for a text-based user interface.
5: *
6: * Copyright 1996 Tim Gunn, Gustavo Goedert
7: */
8:
9: #include "sysconfig.h"
10: #include "sysdeps.h"
11:
12: #include <conio.h>
13: #include <ctype.h>
14: #include <crt0.h>
15:
16: #include "config.h"
17: #include "options.h"
18: #include "uae.h"
19: #include "tui.h"
20:
21: void save_state(void);
22: void drawbox(int,int,int,int);
23: int alphasort(const void *a, const void *b);
24: int scandir(const char *dir, struct dirent ***namelist);
25:
26: #define TB textbackground
27: #define TC textcolor
28: #define CURSON _setcursortype(_NORMALCURSOR);
29: #define CURSOFF _setcursortype(_NOCURSOR);
30: #define SCRON _wscroll = 1;
31: #define SCROFF _wscroll = 0;
32:
33: int SETTC=15; //standard text colour.
34: int SETTB=1; //standard background color.
35: int SETHL=14; //text hilight.
36:
37: typedef struct {
38: int left;
39: int top;
40: int right;
41: int bottom;
42: char *memory;
43: } WINDOW;
44:
45: static int currwin;
46:
47: static WINDOW winstack[10]; /* more than enough */
48: static int winnr = 0;
49:
50: void save_state(void) {
51: int x1, y1, x2, y2;
52:
53: if (winstack[currwin].memory != NULL)
54: free(winstack[currwin].memory);
55: x1 = winstack[currwin].left;
56: y1 = winstack[currwin].top;
57: x2 = winstack[currwin].right;
58: y2 = winstack[currwin].bottom;
59: winstack[currwin].memory = malloc((x2-x1+1)*(y2-y1+1)*2);
60: gettext(x1, y1, x2, y2, winstack[currwin].memory);
61: }
62:
63: void tui_setup(void)
64: {
65: int i;
66:
67: /* enable case on LFN systems (eg. win95) */
68: if (_USE_LFN)
69: _crt0_startup_flags = _CRT0_FLAG_PRESERVE_FILENAME_CASE;
70: _set_screen_lines(50);
71: SCROFF
72: CURSOFF
73: for (i = 0; i < 10; i++)
74: winstack[i].memory = NULL;
75: highvideo();
76: TC(SETTC); TB(SETTB); clrscr();
77:
78: winstack[0].left = 1;
79: winstack[0].top = 1;
80: winstack[0].right = tui_cols();
81: winstack[0].bottom = tui_lines();
82: winstack[0].memory = malloc(tui_cols()*tui_lines()*2);
83: gettext(1, 1, tui_cols(), tui_lines(), winstack[0].memory);
84: window(1, 1, tui_cols(), tui_lines());
85: currwin = 0;
86: winnr = 1;
87: }
88:
89: int tui_lines(void)
90: {
91: return 50;
92: }
93:
94: int tui_cols(void)
95: {
96: return 80;
97: }
98:
99: void tui_shutdown(void)
100: {
101: int i;
102:
103: for (i = 0; i < 10; i++) {
104: if (winstack[i].memory != NULL) {
105: free(winstack[i].memory);
106: winstack[i].memory = NULL;
107: }
108: }
109: winnr = 0;
110: normvideo();
111: SCRON
112: CURSON
113: window(1, 1, tui_cols(), tui_lines());
114: TC(LIGHTGRAY); TB(BLACK); clrscr();
115: _set_screen_lines(25);
116: }
117:
118: void tui_refresh(void)
119: {
120: int i, x1, y1, x2, y2;
121:
122: for (i=0; i<=currwin; i++) {
123: if (winstack[i].memory != NULL) {
124: x1 = winstack[i].left;
125: y1 = winstack[i].top;
126: x2 = winstack[i].right;
127: y2 = winstack[i].bottom;
128: puttext(x1, y1, x2, y2, winstack[i].memory);
129: }
130: }
131: }
132:
133: void tui_puts(const char *s)
134: {
135: cputs(s);
136: save_state();
137: }
138:
139: void tui_cursoff(void)
140: {
141: }
142:
143: void tui_curson(void)
144: {
145: }
146:
147: void tui_putc(char c)
148: {
149: putch(c);
150: save_state();
151: }
152:
153: void tui_cr(void)
154: {
155: tui_puts("\r\n");
156: save_state();
157: }
158:
159: char tui_getc(void)
160: {
161: return getch();
162: // save_state();
163: }
164:
165: void tui_gotoxy(int x, int y)
166: {
167: gotoxy(x, y);
168: // save_state();
169: }
170:
171: void tui_selwin(int w)
172: {
173: window(winstack[w].left, winstack[w].top, winstack[w].right, winstack[w].bottom);
174: currwin = w;
175: tui_refresh();
176: }
177:
178: void tui_clrwin(int w)
179: {
180: tui_selwin(w);
181: clrscr();
182: save_state();
183: }
184:
185: void drawbox(int x, int y, int x2, int y2) {
186: int i;
187: clrscr();
188: gotoxy(x,y); cprintf("�");
189: for(i=0;i<x2-x-1;i++){ cprintf("�"); }
190: cprintf("�");
191: gotoxy(x,y2); cprintf("�");
192: for(i=0;i<x2-x-1;i++){ cprintf("�"); }
193: cprintf("�");
194: for(i=y+1;i<y2;i++) {
195: gotoxy(x,i); cprintf("�");
196: gotoxy(x2,i); cprintf("�");
197: }
198: }
199:
200: void tui_drawbox(int w)
201: {
202: tui_selwin(w);
203: drawbox(1, 1, winstack[w].right-winstack[w].left+1, winstack[w].bottom-winstack[w].top+1);
204: save_state();
205: }
206:
207: void tui_hline(int x1, int y1, int x2)
208: {
209: int i;
210: gotoxy(x1,y1);
211: for (i=x1; i<=x2; i++)
212: putch('�');
213: save_state();
214: }
215:
216: int tui_dlog(int x1, int y1, int x2, int y2)
217: {
218: winstack[winnr].left = x1;
219: winstack[winnr].top = y1;
220: winstack[winnr].right = x2;
221: winstack[winnr].bottom = y2;
222: window(x1, y1, x2, y2);
223: currwin = winnr;
224: return winnr++;
225: }
226:
227: void tui_dlogdie(int w)
228: {
229: tui_selwin(w);
230: if (winstack[w].memory != NULL) {
231: free(winstack[w].memory);
232: winstack[w].memory = NULL;
233: }
234: winnr--;
235: currwin = w-1;
236: }
237:
238: int tui_gets(char *buf, int x, int y, int n)
239: {
240: int i = 0;
241: tui_gotoxy(x+1, y+1);
242: CURSON
243: for (;;) {
244: int c = getch();
245: int j;
246: if (c == 13) {
247: {
248: char *tmp;
249:
250: while ((tmp = strchr(buf, '\\')))
251: *tmp = '/';
252: }
253: CURSOFF
254: return 1;
255: } else if (c == 27) {
256: CURSOFF
257: return 0;
258: } else if (c == 8) {
259: if (i>0)
260: i--;
261: } else if (i + 1 < n)
262: buf[i++] = c;
263: tui_gotoxy(x+1, y+1);
264: for (j = 0; j < i; j++)
265: tui_putc(buf[j]);
266: for (; j < n; j++)
267: tui_putc(' ');
268: tui_gotoxy(x+i+1, y+1);
269: buf[i] = 0;
270: }
271: }
272:
273: int tui_wgets(char *buf, const char *title, int n)
274: {
275: int result;
276: int l = strlen(title);
277: int ww = l > n ? l : n;
278: // int w = tui_dlog((tui_cols()-ww-2)/2, tui_lines()/2-1, (tui_cols()+ww+2)/2, tui_lines()/2+1);
279: int w = tui_dlog((tui_cols()-ww-2)/2+1, tui_lines()/2-1, (tui_cols()+ww+2)/2, tui_lines()/2+1);
280: tui_drawbox(w);
281: tui_gotoxy((ww-l)/2+2, 1);
282: tui_puts(title);
283: result = tui_gets(buf, 1, 1, n);
284: tui_dlogdie(w);
285: return result;
286: }
287:
288:
289: int tui_menubrowse(struct bstring *menu, int xoff, int yoff, int selected, int XXX) //FIXME!!!
290: {
291: int count = 0, maxsel = 0, maxw = 0;
292: int i, j, w;
293:
294: const char *mtitle = NULL;
295:
296: for (i = 0; menu[i].val != -3; i++) {
297: int tmp;
298: if (menu[i].val != 0) {
299: count++;
300: if (menu[i].val != -2)
301: maxsel++;
302: } else
303: mtitle = menu[i].data;
304: if ((tmp = strlen(menu[i].data)) > maxw)
305: maxw = tmp;
306: }
307: maxw += 3;
308: w = tui_dlog(xoff, yoff, xoff+maxw, yoff+count+1);
309: tui_selwin(w);
310: tui_drawbox(w);
311: if (mtitle != NULL) {
312: tui_gotoxy(2, 1);
313: tui_puts(mtitle);
314: }
315:
316: for (;;) {
317: int c;
318: int s2;
319:
320: for (i = j = s2 = 0; i < count; i++, j++) {
321: int k, x;
322: int a = s2 == selected ? 1 : 0;
323:
324: while (menu[j].val == 0)
325: j++;
326: tui_gotoxy(2, 2+i);
327: if (a) {
328: TC(SETTB);
329: TB(SETTC);
330: }
331: tui_putc(' ');
332: for (k = x = 0; menu[j].data[k]; k++, x++) {
333: int a2 = 0;
334: c = menu[j].data[k];
335: if (c == '_')
336: c = menu[j].data[++k], a2 = 1;
337: tui_gotoxy(3+x, 2+i);
338: if (a2)
339: TC(SETHL);
340: tui_putc(c);
341: if (a2) {
342: if (a)
343: TC(SETTB);
344: else
345: TC(SETTC);
346: }
347: }
348: for (; x < maxw-2; x++) {
349: tui_gotoxy(3+x, 2+i);
350: tui_putc(' ');
351: }
352: if (a) {
353: TC(SETTC);
354: TB(SETTB);
355: }
356: if (menu[j].val != -1)
357: s2++;
358: }
359:
360: tui_refresh();
361: c = getch();
362: if (c == 27) {
363: tui_dlogdie(w);
364: return -1;
365: } else if (c == 13 || c == ' ') {
366: tui_dlogdie(w);
367: return selected;
368: } else if (c == 0) {
369: c = getch();
370: switch (c) {
371: case 72:
372: if (selected > 0)
373: selected--;
374: break;
375: case 80:
376: if (selected + 1 < count)
377: selected++;
378: break;
379: case 73:
380: selected = 0;
381: break;
382: case 81:
383: selected = count - 1;
384: break;
385: default:
386: for (j = i = 0; menu[i].val != -3; i++)
387: if (menu[i].val == toupper(c)) {
388: tui_dlogdie(w);
389: return j;
390: } else if (menu[i].val == -1 || menu[i].val > 0) {
391: j++;
392: }
393:
394: break;
395: }
396: } else {
397: for (j = i = 0; menu[i].val != -3; i++)
398: if (menu[i].val == toupper(c)) {
399: tui_dlogdie(w);
400: return j;
401: } else if (menu[i].val == -1 || menu[i].val > 0) {
402: j++;
403: }
404:
405: }
406: }
407: return -1; /* Can't get here */
408: }
409:
410: void tui_errorbox(const char *err)
411: {
412: const char *hak = "Hit any key";
413: int n = strlen(hak);
414: int l = strlen(err);
415: int ww = (l > n ? l : n) + 2;
416: int w = tui_dlog((tui_cols()-ww)/2, tui_lines()/2-1, (tui_cols()+ww)/2, tui_lines()/2+1);
417: tui_selwin(w); tui_drawbox(w);
418:
419: tui_gotoxy((ww-6)/2+2, 1);
420: tui_puts("Error!");
421: tui_gotoxy((ww-l)/2+2, 2);
422: tui_puts(err);
423: tui_gotoxy((ww-n)/2+2, 3);
424: tui_puts(hak);
425:
426: tui_refresh();
427: for (;;) {
428: int c = getch();
429: if (c == 13)
430: break;
431: }
432: tui_dlogdie(w);
433: }
434:
435: static char *pattern;
436: static int maxlen;
437:
438: static void put_filename(char *s, int x, int y, int HL)
439: {
440: char buf[256];
441: int i;
442:
443: tui_gotoxy(x,y);
444: if (strcmp(s, ".") == 0)
445: strcpy(buf, "(none)");
446: else
447: strcpy(buf, s);
448: buf[maxlen] = 0;
449: TC(SETHL);
450: if (HL)
451: TB(SETTC);
452: for (i = 0; i < (int) strlen(buf); i++)
453: tui_putc(buf[i]);
454: for (; i < maxlen; i++)
455: tui_putc(' ');
456: TC(SETTC);
457: if (HL)
458: TB(SETTB);
459: }
460:
461: static char fsbuf[256];
462:
463: static int selectfn(const struct dirent *de)
464: {
465: int l1, l2;
466:
467: /* l1 = strlen(pattern + 1);*/
468: l2 = strlen(de->d_name);
469:
470: if (l2 >= tui_cols()-10) /* Restrict length of filenames so we won't mess up the display */
471: return 0;
472:
473: /* No pattern matching for now. But we don't show hidden files. */
474: if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0
475: && de->d_name[0] == '.')
476: return 0;
477: if (l2 > maxlen)
478: maxlen = l2;
479: return 1;
480: }
481:
482: char *tui_filereq(char *s, char *oldfile, const char *title) //FIXME!!!
483: {
484: char cwd[256];
485: char *retval = fsbuf;
486: char *tmp;
487: int fin = 0;
488: // chtype moresave[6][2];
489:
490: /* Save wd */
491: if (getcwd(cwd, 256) == NULL)
492: return NULL;
493:
494: /* Change into directory of old file */
495: strcpy(fsbuf, oldfile);
496: tmp = strrchr(fsbuf, '/');
497: if (tmp != NULL) {
498: *tmp = 0;
499: if (strlen(fsbuf) > 0)
500: chdir(fsbuf);
501: }
502:
503: pattern = s;
504: if (s[0] != '*')
505: fprintf(stderr, "Can't handle wildcard %s\n", s);
506: if (s[1] != 0 && strchr(s+1, '*') != NULL)
507: fprintf(stderr, "Can't handle wildcard %s\n", s);
508: for (;!fin;) {
509: struct dirent **names;
510: int i, w, n, l, yp, oldyp, s;
511:
512: maxlen = 0;
513: n = scandir(".", &names);
514:
515: if (n <= 0)
516: return NULL;
517: if (title != NULL && strlen(title) + 6 > maxlen)
518: maxlen = strlen(title) + 6;
519: l = n;
520: if (l > 40)
521: l = 40;
522: yp = s = 0; oldyp = -1;
523: w = tui_dlog(tui_cols() - maxlen - 8, 5, tui_cols() - 5, 5 + l + 1);
524: tui_selwin(w); tui_drawbox(w);
525: /* if (title)
526: mvwaddstr(currwin, 0, 2, title);
527: for (i = 0; i < 6; i++) {
528: moresave[i][0] = mvwinch(currwin, 0, maxlen-3+i);
529: moresave[i][1] = mvwinch(currwin, l+1, maxlen-3+i);
530: }*/
531: for (;;) {
532: int c;
533: char tmp[256];
534: while (s < yp)
535: yp--;
536: while (s >= yp + l)
537: yp++;
538: if (oldyp != yp) {
539: oldyp = yp;
540: for (i = 0; i < l; i++) {
541: put_filename(names[i + yp]->d_name, 3, 2 + i, 0);
542: }
543: }
544: put_filename(names[s]->d_name, 3, 2 + s - yp, 1);
545:
546: /* if (yp == 0)
547: for (i = 0; i < 6; i++)
548: mvwaddch(currwin, 0, maxlen-3+i, moresave[i][0]);
549: else
550: mvwaddstr(currwin, 0, maxlen-3, "(more)");
551: if (yp + l == n)
552: for (i = 0; i < 6; i++)
553: mvwaddch(currwin, l+1, maxlen-3+i, moresave[i][1]);
554: else
555: mvwaddstr(currwin, l+1, maxlen-3, "(more)");
556: tui_refresh();*/
557: c = getch();
558: put_filename(names[s]->d_name, 3, 2 + s - yp, 0);
559: if (c == 27) {
560: retval = NULL; fin = 1;
561: break;
562: } else if (c == 13 || c == ' ') {
563: int err;
564:
565: if (strcmp(names[s]->d_name, ".") == 0) {
566: fin = 1;
567: strcpy(fsbuf, "");
568: break;
569: }
570: err = chdir(names[s]->d_name);
571:
572: if (err == 0)
573: break;
574: else /*if (errno == ENOTDIR)*/ {
575: fin = 1;
576: if (getcwd(fsbuf, 256) == NULL)
577: retval = NULL;
578: if (strlen(fsbuf) + strlen(names[s]->d_name) + 2 >= 256)
579: retval = NULL;
580: else {
581: strcat(fsbuf, "/");
582: strcat(fsbuf, names[s]->d_name);
583: }
584: break;
585: } /* else what? */
586: }
587: if (c==0) {
588: c = getch();
589: switch (c) {
590: case 72:
591: if (s > 0)
592: s--;
593: break;
594: case 80:
595: if (s + 1 < n)
596: s++;
597: break;
598: case 73:
599: if (s > l)
600: s -= l;
601: else
602: s = 0;
603: break;
604: case 81:
605: if (s + l < n)
606: s += l;
607: else
608: s = n - 1;
609: break;
610: }
611: } else {
612: for (i = 0; i < n; i++)
613: if (names[i]->d_name[0] == c) {
614: s = i;
615: break;
616: }
617: }
618: }
619: #if 0
620: /* @@@ is this right? */
621: for (i = 0; i < n; i++)
622: free(names[i]->d_name);
623: free(names);
624: #endif
625: tui_dlogdie(w);
626: }
627: chdir(cwd);
628: return retval;
629: }
630:
631: int tui_backup_optionsfile(void)
632: {
633: char tmp[257];
634: char *ptr;
635: if (access(optionsfile, 00) == 0)
636: return 0;
637: strcpy(tmp, optionsfile);
638: ptr = strrchr(tmp, '.');
639: if (ptr != NULL)
640: *ptr = 0;
641: strcat(tmp, ".bak");
642: return rename(optionsfile, tmp);
643: }
644:
645: int alphasort(const void *a, const void *b)
646: {
647: return strcmp ((*((struct dirent **)a))->d_name, (*((struct dirent **)b))->d_name);
648: }
649:
650: int scandir(const char *dir, struct dirent ***namelist)
651: {
652: DIR *dp = opendir (dir);
653: struct dirent **v = NULL;
654: size_t vsize = 0, i;
655: struct dirent *d;
656: int save;
657:
658: if (dp == NULL)
659: return -1;
660:
661: save = errno;
662: errno = 0;
663:
664: i = 0;
665: while ((d = readdir (dp)) != NULL)
666: if (selectfn(d))
667: {
668: if (i == vsize)
669: {
670: struct dirent **new;
671: if (vsize == 0)
672: vsize = 10;
673: else
674: vsize *= 2;
675: new = (struct dirent **) realloc (v, vsize * sizeof (*v));
676: if (new == NULL)
677: {
678: lose:
679: (void) closedir (dp);
680: while (i > 0)
681: free (v[--i]);
682: free (v);
683: errno = ENOMEM;
684: return -1;
685: }
686: v = new;
687: }
688:
689: v[i] = (struct dirent *) malloc (sizeof (**v));
690: if (v[i] == NULL)
691: goto lose;
692:
693: *v[i++] = *d;
694: }
695:
696: if (errno != 0)
697: {
698: save = errno;
699:
700: (void) closedir (dp);
701:
702: while (i > 0) free(v[--i]);
703: free(v);
704:
705: errno = save;
706: return -1;
707: }
708:
709: (void) closedir (dp);
710: errno = save;
711:
712: qsort (v, i, sizeof (*v), alphasort);
713: *namelist = v;
714: return i;
715: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.