1 /* Copyright (C) 1987, 1988 by Michael J. Roberts. All Rights Reserved. */
2
3 /*
4 * OS-dependent module for Unix and Termcap/Termio library.
5 *
6 * 29-Jan-93
7 * Dave Baggett
8 */
9
10 /*
11 * Fri Jan 29 16:14:39 EST 1993
12 * dmb@ai.mit.edu Termcap version works.
13 *
14 * Thu Apr 22 01:58:07 EDT 1993
15 * dmb@ai.mit.edu Lots of little changes. Incorporated NeXT, Linux,
16 * and DJGCC changes.
17 *
18 * Sat Jul 31 02:04:31 EDT 1993
19 * dmb@ai.mit.edu Many changes to improve screen update efficiency.
20 * Added unix_tc flag, set by compiler mainline,
21 * to disable termcap stuff and just run using stdio.
22 *
23 * Fri Oct 15 15:50:09 EDT 1993
24 * dmb@ai.mit.edu Changed punt() code to save game state.
25 *
26 * Mon Oct 25 16:39:57 EDT 1993
27 * dmb@ai.mit.edu Now use our own os_defext and os_remext.
28 *
29 */
30 #include <stdio.h>
31 #if !defined(SUN3)
32 #include <stddef.h>
33 #endif
34 #include <stdlib.h>
35 #include <ctype.h>
36 #include <string.h>
37 #include <sys/stat.h>
38 #include <unistd.h> /* SRG added for usleep() and select() */
39 #include <sys/ioctl.h> /* tril@igs.net added for TIOCGWINSZ */
40 #if defined(LINUX_386) || defined(FREEBSD_386) /* tril@igs.net 2000/Aug/20 */
41 #include <sys/time.h>
42 #include <sys/types.h>
43 #endif
44
45 #ifdef DJGCC_386
46 #include <pc.h>
47 #include <dos.h>
48 #include "biosvid.h"
49 #endif
50
51 #include "os.h"
52 #include "osgen.h"
53 #ifndef USE_STDIO
54 #include "osdbg.h"
55 #endif
56 #include "voc.h"
57
58 /*
59 * ^C pressed?
60 */
61 static int break_set = 0;
62
63 /*
64 * Run-time voc context for save-on-punt
65 */
66 extern voccxdef *main_voc_ctx;
67
68 /*
69 * Running as compiler? If so, we shouldn't do any term handling.
70 */
71 int unix_tc = 0;
72
73 /*
74 * Private terminal handling stuff
75 */
76 int unix_max_line;
77 int unix_max_column;
78
79 /*
80 * Stuff for the timing functions. Added by SRG
81 */
82 static long timeZero = 0;
83
84 /*
85 * "Colors"
86 * Note that cNORMAL *must* be zero for other parts of TADS to work.
87 */
88 #define cNORMAL (1 << 0)
89 #define cSTANDOUT (1 << 1)
90 #define cREVERSE (1 << 2)
91 #define cBOLD (1 << 3)
92 #define cBLINK (1 << 4)
93 #define cUNDERSCORE (1 << 5)
94
95 #ifndef USE_STDIO
96
97 #ifndef DJGCC_386
98 #include <signal.h>
99 #ifdef USE_SGTTY
100 #include <sgtty.h>
101 #else
102 #ifdef TERMIOS_IS_NOT_IN_SYS
103 #include <termios.h>
104 #else
105 #include <sys/termios.h>
106 #endif /* TERMIOS_IS_NOT_IN_SYS */
107 #endif /* USE_SGTTY */
108 #endif /* DJGCC_386 */
109
110 #ifdef HAVE_TPARM
111 /*
112 * Use the standard library routine if we have it.
113 */
114 #define Tparm tparm
115 #else
116 char *Tparm();
117 #endif
118
119 /*
120 * The following flag determines whether or not the output routines
121 * will attempt to use hardware features of the controlling terminal.
122 * If it is NOT on, ALL screen updates will go through t_redraw.
123 * This is useful for debugging problems with a termcap entry or
124 * getting TADS running on a new environment quickly, but IS INCREDIBLY
125 * SLOW and hence should not be used for production releases.
126 */
127 #define T_OPTIMIZE
128
129 /*
130 * The following flag determines whether or not ossdsp will just send
131 * its string out to t_puts or whether it will redraw the entire affected
132 * line. The latter is slower (perhaps painfully so over slow modem
133 * connections), but fixes a problem with the way TADS currently updates
134 * the status line.
135 *
136 * Sat Jul 31 02:06:42 EDT 1993 dmb@ai.mit.edu
137 * This problem seems to be fixed now, but I'll leave the flag anyway.
138 *
139 */
140 #define FAST_OSSDSP
141
142
143 #define INIT 0
144 #define RESTORE 1
145
146 /*
147 * We store an image of the screen in a private array.
148 * The maximum dimensions of this array are given here.
149 */
150 #define MAXCOLS (OS_MAXWIDTH-1)
151 #define MAXLINES 256
152
153 /*
154 * Running as debugger? If so, split the screen into the debugging
155 * window and the execution window.
156 */
157 int unix_tdb = 0;
158 int breakpoint_color; /* for debugger */
159 int watchpoint_color; /* for debugger */
160 int filename_color; /* for debugger */
161 int usebios = 0; /* for dbgu.c */
162
163 /*
164 * Our private notion of what the screen looks like.
165 * We keep one array of characters and another array of "colors."
166 * Under termcap/termio handling we don't actually do color (at the
167 * moment, at least), but can do character attributes like standout,
168 * reverse video, blinking, etc.
169 *
170 * We keep track of the current cursor location and text attributes
171 * so that we don't have to send redundant codes out to the terminal.
172 */
173 static int cw = 0; /* current window (for debugger) */
174 static int COLS, LINES;
175 static char COLOR = -1;
176 static int cursorX = 0, cursorY = 0;
177 static int inputX = 0, inputY = 0;
178 static char screen[MAXLINES][MAXCOLS];
179 static char colors[MAXLINES][MAXCOLS];
180
181 #ifdef DJGCC_386
182 static int plaincolor, revcolor, boldcolor;
183 #endif
184
185 /*
186 * Flags indicating whether our controlling terminal has various
187 * capabilities.
188 */
189 static int standout_ok, rev_ok, bold_ok, blink_ok, underscore_ok;
190 static int hideshow_ok;
191
192 static int k_erase, k_kill, k_word_erase, k_reprint;
193
194 /*
195 * Terminal capabilities from termcap.
196 * Certainly more than you ever wanted to know about.
197 */
198
199 /*
200 * Booleans
201 */
202 static int
203 Txs, /* Standout not erased by overwriting (Hewlett-Packard) */
204 Tms, /* Safe to move in standout modes */
205 Tos; /* Terminal overstrikes on hard-copy terminal */
206
207 /*
208 * Numbers
209 */
210 static int
211 Tsg; /* Number for characters left by standout */
212 /*
213 * Strings
214 */
215 static char
216 *Tcs, /* Change scroll region to lines #1 through #2 (VT100) */
217 *TcS, /* Change scroll region: #1 = total lines, #2 = lines
218 above region, #3 = lines below region, #4 = total lines */
219 *Tcl, /* Clear screen and home cursor */
220 *Tce, /* Clear to end of line */
221 *Tcd, /* Clear to end of display */
222 *Tcm, /* Cursor motion to row #1 col #2 */
223 *Tdo, /* Down one line */
224 *Tho, /* Home cursor */
225 *Tvi, /* Make cursor invisible */
226 *Tle, /* Move cursor left one SPACE */
227 *Tve, /* Make cursor appear normal (undo cvvis/civis) */
228 *Tnd, /* Non-destructive space (cursor right) */
229 *Tup, /* Upline (cursor up) */
230 *Tvs, /* Make cursor very visible */
231 *Tdl, /* Delete line */
232 *Tmb, /* Turn on blinking */
233 *Tmd, /* Turn on bold (extra bright) mode */
234 *Tme, /* Turn off attributes (blinking, reverse, bold, etc.) */
235 *Tti, /* String to begin programs that use cursor addresing */
236 *Tmr, /* Turn on reverse video mode */
237 *Tso, /* Begin standout mode */
238 *Tus, /* Start underscore mode */
239 *Tte, /* String to end programs that use cursor addressing */
240 *Tse, /* End standout mode */
241 *Tue, /* End underscore mode */
242 *Tal, /* Add new blank line (insert line) */
243 *Tpc, /* Pad character (rather than null) */
244 *TDL, /* Delete #1 lines */
245 *TDO, /* Move cursor down #1 lines. */
246 *TSF, /* Scroll forward #1 lines. */
247 *TAL, /* Add #1 new blank lines */
248 *TLE, /* Move cursor left #1 spaces */
249 *TRI, /* Move cursor right #1 spaces. */
250 *TSR, /* Scroll backward #1 lines. */
251 *TUP, /* Move cursor up #1 lines. */
252 *Tsf, /* Scroll forward one line. */
253 *Tsr, /* Scroll backward one line. */
254 *Twi; /* Current window is lines #1-#2 cols #3-#4 */
255
256 #ifndef DJGCC_386
257 /*
258 * We must import the following three variables from the termcap
259 * library and set the appropriately so that output padding will
260 * work properly.
261 */
262 extern char PC;
263 extern short ospeed;
264 #endif /* DJGCC_386 */
265
266 static void punt(int sig);
267 static void susp(int sig);
268 static void cont(int sig);
269 static void get_screen_size(int *w, int *h);
270 static void resize(void);
271 static void t_init(void);
272 static void t_tty(int action);
273 static void winch(int sig);
274 static void set_win_size(void);
275 static void t_color_init(void);
276 static void t_term(void);
277 static void t_hide(void);
278 static void t_show(void);
279 static void t_putc(char c);
280 static void t_outs(char *s);
281 static void t_puts(char *s);
282 static void t_refresh(void);
283 static void t_update(int x, int y);
284 static void t_loc(int y, int x, int force);
285 static void t_color(char c);
286 static void t_redraw(int top, int bottom);
287 static void t_scroll(int top, int bottom, int lines);
288 static void t_set_scroll_region(int top, int bot);
289 static void break_handler(int sig);
290
291 void ossclr(int top, int left, int bottom, int right, int blank_color);
292 void ossdbgloc(int y, int x);
293
294 /*
295 * Set up our controlling terminal and find out what it's capable
296 * of doing. Punt if we have no ability to position the cursor,
297 * scroll, etc.
298 */
299 static void
t_init(void)300 t_init(void)
301 {
302 #ifdef DJGCC_386
303
304 bios_video_init();
305 rev_ok = 1;
306 bold_ok = 1;
307 standout_ok = 0;
308 blink_ok = 0;
309 underscore_ok = 0;
310 hideshow_ok = 0;
311 bios_video_get_screen_dimensions(&COLS, &LINES);
312 LINES++; COLS++; set_win_size(); LINES--; COLS--;
313 t_color_init();
314
315 #else /* DJGCC_386*/
316
317 #define Tgetstr(key) (tgetstr(key, &tbufptr))
318 extern char *tgetstr();
319
320 static char tbuf[4096];
321 register char *term;
322 register char *tptr;
323 char *tbufptr;
324 int scroll_ok, curs_ok;
325
326 if (unix_tc)
327 return;
328
329 /*
330 * Set tty up the way we need it.
331 */
332 t_tty(INIT);
333
334 /*
335 * Set all string capabilities to NULL for safety's sake.
336 */
337 Tcs = TcS = Tcl = Tce = Tcd = Tcm = Tdo = Tho = Tvi = Tle = Tve =
338 Tnd = Tup = Tvs = Tdl = Tme = Tmb = Tmd = Tti = Tmr = Tso = Tus =
339 Tte = Tse = Tue = Tal = Tpc = TDL = TDO = TSF = TAL = TLE = TRI =
340 TSR = TUP = Twi = NULL;
341
342 /*
343 * Find the name of the user's terminal.
344 */
345 term = getenv("TERM");
346 if(!term) {
347 printf("Can't find TERM, the name of your terminal.\n");
348 exit(-1);
349 }
350
351 /*
352 * Allocate a buffer for the termcap entry. Make it big to be safe.
353 */
354 tptr = (char *) malloc(4096);
355 if (!tptr) {
356 printf("Out of memory allocating termcap entry buffer.\n");
357 exit(-1);
358 }
359
360 /*
361 * Get the termcap entry.
362 */
363 tbufptr = tbuf;
364 if(tgetent(tptr, term) < 1) {
365 printf("Unknown terminal type: %s", term);
366 exit(-1);
367 }
368
369 /*
370 * Check for fatal conditions:
371 *
372 * - Tos (terminal overstrikes)
373 * - Does not have any of:
374 * - Add line and delete line (AL/DL, al/dl)
375 * - Set scrolling region (cs, cS) *and* scroll up and
376 * down (sf and sr).
377 * - Set window (wi) *and* scroll up and scroll down
378 * (sf and sr).
379 * - Does not have cursor addressing *or* home *and* down and right
380 */
381 if (tgetflag("os")) {
382 printf("Can't run on a hard-copy terminal (termcap os).\n");
383 exit(-1);
384 }
385 TAL = Tgetstr("AL");
386 TDL = Tgetstr("DL");
387 Tal = Tgetstr("al");
388 Tdl = Tgetstr("dl");
389 Tcs = Tgetstr("cs");
390 TcS = Tgetstr("cS");
391 Twi = Tgetstr("wi");
392 Tsf = Tgetstr("sf");
393 Tsr = Tgetstr("sr");
394 TSF = Tgetstr("SF");
395 TSR = Tgetstr("SR");
396
397 if (!Tsf)
398 Tsf = "\n";
399
400 scroll_ok = 0;
401 if ((Tal || TAL) && (Tdl || TDL))
402 scroll_ok = 1;
403 else if ((Tcs || TcS || Twi) && (Tsf || TSF) && (Tsr || TSR))
404 scroll_ok = 1;
405 if (!scroll_ok) {
406 printf("Can't run without window scrolling capability.\n");
407 exit(-1);
408 }
409 Tcm = Tgetstr("cm");
410 Tho = Tgetstr("ho");
411 Tle = Tgetstr("le");
412 if (!Tle)
413 Tle = Tgetstr("bs"); /* obsolete alternative to "le" */
414 TLE = Tgetstr("LE");
415 Tnd = Tgetstr("nd");
416 TRI = Tgetstr("RI");
417 Tup = Tgetstr("up");
418 TUP = Tgetstr("UP");
419 Tdo = Tgetstr("do");
420 if (!Tdo)
421 Tdo = Tgetstr("nl"); /* obsolete alternative to "do" */
422 TDO = Tgetstr("DO");
423 Tti = Tgetstr("ti");
424 Tte = Tgetstr("te");
425 curs_ok = 0;
426 if (Tcm)
427 curs_ok = 1;
428 else if (Tho) {
429 if ((Tnd || TRI) && (Tdo || TDO))
430 curs_ok = 1;
431 }
432 if (!curs_ok) {
433 printf("Can't run without cursor positioning capability.\n");
434 exit(-1);
435 }
436
437 /*
438 * Get region clearing capabilities, if any.
439 */
440 Tcl = Tgetstr("cl");
441 Tce = Tgetstr("ce");
442 Tcd = Tgetstr("cd");
443
444 /*
445 * See if we have standout mode.
446 * Don't use it if term has standout erase bug (xs) or it's not
447 * safe to move in standout mode (ms), or standout generates spaces
448 * (sg > 0).
449 */
450 standout_ok = 0;
451 if (!tgetflag("xs") && !tgetflag("ms") && tgetnum("sg") <= 0) {
452 Tso = Tgetstr("so");
453 Tse = Tgetstr("se");
454 if (Tso && Tse)
455 standout_ok = 1;
456 }
457
458 /*
459 * See if we can turn off special modes
460 */
461 Tme = Tgetstr("me");
462
463 /*
464 * See if we have reverse video mode.
465 */
466 rev_ok = 0;
467 if (Tme) {
468 Tmr = Tgetstr("mr");
469 if (Tmr)
470 rev_ok = 1;;
471 }
472
473 /*
474 * See if we have bold mode.
475 */
476 bold_ok = 0;
477 if (Tme) {
478 Tmd = Tgetstr("md");
479 if (Tmd)
480 bold_ok = 1;
481 }
482
483 /*
484 * See if we have blink mode.
485 */
486 blink_ok = 0;
487 if (Tme) {
488 Tmb = Tgetstr("mb");
489 if (Tmb)
490 blink_ok = 1;
491 }
492
493 /*
494 * See if we have underscore mode.
495 */
496 underscore_ok = 0;
497 Tus = Tgetstr("us");
498 Tue = Tgetstr("ue");
499 if (Tus && Tue)
500 underscore_ok = 1;
501
502 /*
503 * See if we can hide/show the cursor.
504 */
505 hideshow_ok = 0;
506 Tvi = Tgetstr("vi");
507 Tve = Tgetstr("ve");
508 Tvs = Tgetstr("vs");
509 if (Tvi && Tve)
510 hideshow_ok = 1;
511
512 /*
513 * Get padding character (if there is one for this term).
514 */
515 Tpc = Tgetstr("pc");
516 if (Tpc)
517 PC = *Tpc;
518 else
519 PC = 0;
520
521 free(tptr);
522
523 /*
524 * Do the right thing when window's resized.
525 */
526 signal(SIGWINCH, winch);
527
528 /*
529 * Handle ^C.
530 */
531 signal(SIGINT, break_handler);
532 /* signal(SIGINT, SIG_IGN); */
533
534 /*
535 * Handle ^Z.
536 */
537 signal(SIGTSTP, susp);
538 signal(SIGCONT, cont);
539
540 /*
541 * Restore terminal sanity when signals nuke us.
542 */
543 signal(SIGHUP, punt);
544 signal(SIGQUIT, punt);
545 signal(SIGILL, punt);
546 signal(SIGTRAP, punt);
547 signal(SIGABRT, punt);
548 #if !defined(LINUX_386)
549 signal(SIGEMT, punt);
550 #endif
551 signal(SIGFPE, punt);
552 #if !defined(LINUX_386)
553 signal(SIGBUS, punt);
554 #endif
555 signal(SIGSEGV, punt);
556 #if !defined(LINUX_386)
557 signal(SIGSYS, punt);
558 #endif
559
560 /*
561 * Determine screen size. Ensure sanity of text formatter.
562 */
563 resize();
564
565 /*
566 * Init "colors"
567 */
568 t_color_init();
569
570 /*
571 * Init screen
572 */
573 t_puts(Tti);
574 t_puts(Tvs);
575
576 #endif /* DJGCC_386 */
577 }
578
579 /*
580 * Clean up when we get a request to suspend from the terminal.
581 */
582 static void
susp(int sig)583 susp(int sig)
584 {
585 #ifndef DJGCC_386
586 t_term();
587 signal(SIGTSTP, SIG_DFL);
588 kill(getpid(), SIGTSTP);
589 #endif
590 }
591
592 /*
593 * Restore term state upon resuming from suspension.
594 */
595 static void
cont(int sig)596 cont(int sig)
597 {
598 #ifndef DJGCC_386
599 t_init();
600 t_update(-1, -1);
601 COLOR = -1;
602 t_refresh();
603 #endif
604 }
605
606 /*
607 * Die gracefully when we get a fatal signal.
608 * We try to save the game before we exit.
609 */
610 static void
punt(int sig)611 punt(int sig)
612 {
613 char s[15];
614
615 if (!unix_tc && main_voc_ctx != 0) {
616 sprintf(s, "fatal%d.sav", getpid());
617 printf("Caught a fatal signal! Attempting to save game in %s...\n", s);
618 fiosav(main_voc_ctx, s, 0);
619 }
620 else {
621 printf("Caught a fatal signal!\n");
622 }
623
624 os_term(-1);
625 }
626
627 /*
628 * Get terminal size.
629 * Negative and zero values mean the system has no clue.
630 */
631 static void
get_screen_size(int * w,int * h)632 get_screen_size(int *w, int *h)
633 {
634 #ifndef DJGCC_386
635 /*
636 * Define the 4.3 names in terms of the Sun names
637 * if the latter exist and the former do not.
638 */
639 #ifdef TIOCGSIZE
640 #ifndef TIOCGWINSZ
641 #define TIOCGWINSZ TIOCGSIZE
642 #define winsize ttysize
643 #define ws_row ts_lines
644 #define ws_col ts_cols
645 #endif
646 #endif
647
648 /*
649 * Use the 4.3 names if possible.
650 */
651 #ifdef TIOCGWINSZ
652 struct winsize size;
653 *w = 0;
654 *h = 0;
655 if (ioctl(0, TIOCGWINSZ, &size) < 0)
656 return;
657
658 *w = size.ws_col;
659 *h = size.ws_row;
660
661 #else /* not TIOCGWNSIZ */
662
663 /*
664 * System has no clue
665 */
666 *w = 0;
667 *h = 0;
668
669 #endif /* not TIOCGWINSZ */
670
671 /*
672 * If running as debugger, halve the height
673 * since we want two windows.
674 */
675 if (unix_tdb)
676 *h /= 2;
677
678 #endif /* DJGCC_386 */
679 }
680
681 static void
resize(void)682 resize(void)
683 {
684 #ifndef DJGCC_386
685 get_screen_size(&COLS, &LINES);
686
687 if (COLS <= 0 || LINES <= 0) {
688 COLS = tgetnum("co");
689 LINES = tgetnum("li");
690 }
691
692 set_win_size();
693 #endif
694 }
695
696 static void
winch(int sig)697 winch(int sig)
698 {
699 #ifndef DJGCC_386
700 resize();
701
702 /*
703 * Clear screen
704 */
705 ossclr(0, 0, LINES - 1, COLS - 1, cNORMAL);
706 t_refresh();
707 #endif
708 }
709
710 /*
711 * When window size changes, we have to notify the rest of the system
712 * so text will be formatted properly.
713 */
714 static void
set_win_size(void)715 set_win_size(void)
716 {
717 /*
718 * Ensure output formatter happiness.
719 */
720 if (LINES < 5)
721 LINES = 5;
722 if (COLS < 20)
723 COLS = 20;
724
725 /*
726 * Ensure our own personal happiness.
727 */
728 if (LINES >= MAXLINES)
729 LINES = MAXLINES - 1;
730 if (COLS >= MAXCOLS)
731 COLS = MAXCOLS - 1;
732
733 G_oss_screen_height = LINES - 1;
734 G_oss_screen_width = COLS;
735 unix_max_line = LINES - 2;
736 unix_max_column = COLS - 2;
737 osssb_on_resize_screen();
738 }
739
740 /*
741 * Tell the rest of the system what "colors" to use for various things.
742 */
743 static void
t_color_init(void)744 t_color_init(void)
745 {
746 if (rev_ok)
747 sdesc_color = cREVERSE;
748 else if (standout_ok)
749 sdesc_color = cSTANDOUT;
750 else if (bold_ok)
751 sdesc_color = cBOLD;
752 else if (underscore_ok)
753 sdesc_color = cUNDERSCORE;
754 else
755 sdesc_color = cNORMAL;
756
757 ldesc_color = sdesc_color;
758 debug_color = sdesc_color;
759
760 text_color = cNORMAL;
761 if (bold_ok)
762 text_bold_color = cBOLD;
763 else if (standout_ok)
764 text_bold_color = cSTANDOUT;
765 else if (rev_ok)
766 text_bold_color = cREVERSE;
767 else if (underscore_ok)
768 text_bold_color = cUNDERSCORE;
769 else
770 text_bold_color = cNORMAL;
771
772 text_normal_color = text_color;
773 breakpoint_color = sdesc_color;
774 watchpoint_color = sdesc_color;
775
776 if (rev_ok)
777 filename_color = cREVERSE;
778 else if (underscore_ok)
779 filename_color = cUNDERSCORE;
780 else if (bold_ok)
781 filename_color = cBOLD;
782 else
783 filename_color = cNORMAL;
784 }
785
786 static void
t_term(void)787 t_term(void)
788 {
789 #ifndef DJGCC_386
790
791 if (unix_tc)
792 return;
793
794 /*
795 * Restore scroll window if term has that capability.
796 */
797 if (Tcs || TcS || Twi)
798 if (unix_tdb)
799 t_set_scroll_region(0, LINES*2 - 1);
800 else
801 t_set_scroll_region(0, LINES - 1);
802
803 /*
804 * Disable all attributes (if possible), including standout.
805 */
806 t_puts(Tme);
807 t_puts(Tse);
808 t_puts(Tue);
809
810 /*
811 * Restore tty
812 */
813 t_tty(RESTORE);
814
815 /*
816 * End visual mode
817 */
818 t_puts(Tte);
819
820 /*
821 * Make cursor visible
822 */
823 t_puts(Tve);
824
825 #endif /* DJGCC_386 */
826 }
827
828 /*
829 * Hide cursor
830 */
831 static void
t_hide(void)832 t_hide(void)
833 {
834 #ifdef DJGCC_386
835 void bios_video_cursor_hide();
836 #else /* DJGCC_386 */
837
838 if (hideshow_ok)
839 t_puts(Tvi);
840
841 #endif /* DJGCC_386 */
842 }
843
844 /*
845 * Show cursor
846 */
847 static void
t_show(void)848 t_show(void)
849 {
850 #ifdef DJGCC_386
851 void bios_video_cursor_hide();
852 #else /* DJGCC_386 */
853
854 if (hideshow_ok)
855 t_puts(Tve);
856
857 #endif /* DJGCC_386 */
858 }
859
860 /*
861 * Write a character to the screen (without padding)
862 */
863 static void
t_putc(char c)864 t_putc(char c)
865 {
866 #ifndef DJGCC_386
867 fputc(c, stdout);
868 #endif
869 }
870
871 /*
872 * Write a string to the screen (without padding)
873 */
874 static void
t_outs(char * s)875 t_outs(char *s)
876 {
877 #ifdef DJGCC_386
878
879 bios_video_write_string(s);
880
881 #else /* DJGCC_386 */
882 if (s) {
883 printf("%s", s);
884 fflush(stdout);
885 }
886 #endif
887 }
888
889 /*
890 * Write an escape sequence to the string to the screen with padding
891 */
892 static void
t_puts(char * s)893 t_puts(char *s)
894 {
895 #ifndef DJGCC_386
896
897 #if 0
898 if (s)
899 printf("%s", s);
900 return;
901 #endif
902
903 if (s) {
904 Tputs(s, 1, (int (*)())t_putc);
905 fflush(stdout);
906 }
907 #endif
908 }
909
910 /*
911 * Init or restore terminal.
912 */
913 static void
t_tty(int action)914 t_tty(int action)
915 {
916 #ifndef DJGCC_386
917
918 #ifdef USE_SGTTY
919 struct sgttyb t;
920 struct ltchars t1;
921 static struct sgttyb orig;
922 #else /* USE_SGTTY */
923 struct termios t;
924 static struct termios orig;
925 #endif /* USE_SGTTY */
926
927 if (action == RESTORE) {
928
929 #ifdef USE_IOCTL_INSTEAD_OF_TERMIOS
930 #ifdef USE_SGTTY
931 ioctl(0, TIOCSETP, &orig);
932 #else
933 ioctl(0, TCSETSW, &orig);
934 #endif /* USE_SGTTY */
935 #else
936 tcsetattr(0, TCSANOW, &orig);
937 #endif
938 }
939 else {
940
941 #ifdef USE_IOCTL_INSTEAD_OF_TERMIOS
942 #ifdef USE_SGTTY
943 ioctl(0, TIOCGETP, &orig);
944 ioctl(0, TIOCGETP, &t);
945 #else
946 ioctl(0, TCGETS, &orig);
947 ioctl(0, TCGETS, &t);
948 #endif /* USE_SGTTY */
949 #else
950 tcgetattr(0, &orig);
951 tcgetattr(0, &t);
952 #endif
953
954 #ifdef USE_SGTTY
955 t.sg_flags &= ~(XTABS | ECHO | CRMOD);
956 t.sg_flags |= CBREAK;
957 #else
958 t.c_lflag &= ~(ICANON | ECHO | ICRNL);
959 t.c_lflag |= INLCR;
960 t.c_cc[VMIN] = 1;
961 t.c_cc[VTIME] = 0;
962 #if !defined(SGI_IRIX)
963 t.c_oflag &= (~OXTABS);
964 #else
965 t.c_oflag &= (~TAB3);
966 #endif
967 #endif /* USE_SGTTY */
968
969 #ifdef USE_IOCTL_INSTEAD_OF_TERMIOS
970 #ifdef USE_SGTTY
971 ioctl(0, TIOCSETP, &t);
972 #else
973 ioctl(0, TCSETSW, &t);
974 #endif /* USE_SGTTY */
975 #else
976 tcsetattr(0, TCSANOW, &t);
977 #endif
978 }
979
980 /*
981 * Determine baud rate for Tputs.
982 * Look for it in termios struct; if not found, assume 2400 baud.
983 */
984 #ifdef USE_SGTTY
985 ospeed = t.sg_ospeed;
986 #else
987 ospeed = cfgetospeed(&t);
988 #endif
989 if (ospeed == 0)
990 ospeed = 11;
991
992 /*
993 * Get special keys
994 */
995 #ifdef USE_SGTTY
996 k_erase = t.sg_erase;
997 k_kill = t.sg_kill;
998 ioctl(0, TIOCGLTC, &t1);
999 k_word_erase = t1.t_werasc;
1000 k_reprint = t1.t_rprntc;
1001 #else /* USE_SGTTY */
1002 k_erase = t.c_cc[VERASE];
1003 k_kill = t.c_cc[VKILL];
1004 k_word_erase = t.c_cc[VWERASE];
1005
1006 #if defined(SGI_IRIX) || defined(ULTRIX_MIPS)
1007 k_reprint = t.c_cc[VRPRNT];
1008 #else
1009 k_reprint = t.c_cc[VREPRINT];
1010 #endif
1011 #endif /* USE_SGTTY */
1012
1013 #endif /* DJGCC_386 */
1014 }
1015
1016 int
os_init(int * argc,char * argv[],const char * prompt,char * buf,int bufsiz)1017 os_init( int *argc, char *argv[], const char *prompt, char *buf, int bufsiz )
1018 {
1019 #ifdef DJGCC_386
1020 FILE *fp;
1021 char nbuf[128];
1022
1023 /*
1024 * Monochrome monitor?
1025 */
1026 if (bios_video_monochrome()) {
1027 revcolor = 0x70;
1028 plaincolor = 7;
1029 boldcolor = 0x70;
1030 }
1031 else if ( os_locate("trcolor.dat", 11, argv[0], nbuf, sizeof(nbuf))
1032 && (fp = fopen(nbuf, "r")) ) {
1033 int i;
1034 static int *colorptr[] = { &plaincolor, &boldcolor, &revcolor };
1035
1036 for (i = 0 ; i < sizeof(colorptr)/sizeof(colorptr[0]) ; ++i)
1037 {
1038 fgets(nbuf, sizeof(nbuf), fp);
1039 *colorptr[i] = atoi(nbuf);
1040 }
1041 fclose(fp);
1042 }
1043 else {
1044 plaincolor = 7;
1045 revcolor = 0x70;
1046 boldcolor = 15;
1047 }
1048 text_color = text_normal_color;
1049 #endif /* DJGCC_386 */
1050
1051 t_init();
1052
1053 /*
1054 * Clear screen
1055 */
1056 if (unix_tdb) {
1057 cw = 0;
1058 ossclr(0, 0, LINES - 1, COLS - 1, cNORMAL);
1059 cw = 1;
1060 ossclr(0, 0, LINES - 1, COLS - 1, cNORMAL);
1061 }
1062 else
1063 ossclr(0, 0, LINES - 1, COLS - 1, cNORMAL);
1064
1065 #ifdef USE_SCROLLBACK
1066
1067 osssbini(32767*8); /* allocate scrollback buffer */
1068
1069 #endif /* USE_SCROLLBACK */
1070
1071 if (!unix_tc) {
1072 status_mode = 1;
1073 #ifdef DJGCC_386
1074 os_printz( "TADS (GO32 version)" );
1075 #else
1076 os_printz( "TADS" );
1077 #endif
1078 status_mode = 0;
1079 os_score(0, 0);
1080 }
1081
1082 return 0;
1083 }
1084
1085 void
os_term(int rc)1086 os_term(int rc)
1087 {
1088 if (!unix_tc) {
1089 os_printz("[strike a key to exit]");
1090 os_waitc();
1091 os_printz("\n");
1092 }
1093
1094 #ifdef USE_SCROLLBACK
1095 osssbdel();
1096 #endif /* USE_SCROLLBACK */
1097
1098 exit(0); /* always return zero since mainline doesn't set it right */
1099 }
1100
os_uninit()1101 void os_uninit()
1102 {
1103 t_term();
1104 }
1105
1106 /*
1107 * Check for control-break. Returns status of break flag, and clears
1108 * the flag.
1109 */
1110 int
os_break(void)1111 os_break(void)
1112 {
1113 int ret;
1114
1115 ret = break_set;
1116 break_set = 0;
1117 return ret;
1118 }
1119
1120 /*
1121 * Handle ^C.
1122 */
1123 static void
break_handler(int sig)1124 break_handler(int sig)
1125 {
1126 break_set = 1;
1127 }
1128
1129 /*
1130 * Get an event--a key press, a timeout, etc. Added by SRG.
1131 */
os_get_event(unsigned long timeout,int use_timeout,os_event_info_t * info)1132 int os_get_event(unsigned long timeout, int use_timeout,
1133 os_event_info_t *info)
1134 {
1135 fd_set readfds;
1136 struct timeval tv;
1137 int retval;
1138
1139 /* We're watching stdin (fd 0) for input */
1140 FD_ZERO(&readfds);
1141 FD_SET(0, &readfds);
1142
1143 /* Wait for the specified time, if we're supposed to */
1144 tv.tv_sec = (int)(timeout / 1000);
1145 tv.tv_usec = timeout % 1000;
1146
1147 /* Redraw the screen, if necessary */
1148 osssb_redraw_if_needed();
1149
1150 if (use_timeout)
1151 retval = select(1, &readfds, NULL, NULL, &tv);
1152 else
1153 retval = select(1, &readfds, NULL, NULL, NULL);
1154
1155 if (!retval)
1156 return OS_EVT_TIMEOUT;
1157
1158 (*info).key[0] = os_getc_raw();
1159 return OS_EVT_KEY;
1160 }
1161
1162 #ifdef DJGCC_386
1163
os_getch(void)1164 int os_getch(void)
1165 {
1166 return bios_getchar();
1167 }
1168
os_waitc(void)1169 void os_waitc(void)
1170 {
1171 int c = os_getch();
1172
1173 if ((c == 0 || c == 0340)) {
1174 os_getch();
1175 }
1176 }
1177
os_getc(void)1178 int os_getc(void)
1179 {
1180 static char altkeys[] = {
1181 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50,
1182 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44
1183 };
1184
1185 int c;
1186 static int cmdval;
1187
1188 if (cmdval) {
1189 int tmpcmd = cmdval; /* save command for a moment */
1190 cmdval = 0; /* clear the flag - next call gets another key */
1191 return tmpcmd; /* return the command that we saved */
1192 }
1193
1194 tryAgain:
1195 c = os_getch();
1196
1197 if ((c == 0 || c == 0340)) { /* Extended keycode? */
1198 int i;
1199 char *p;
1200
1201 c = os_getch();
1202
1203 /* check for alt keys */
1204 cmdval = 0;
1205 for (i = 0, p = altkeys ; i < 26 ; ++p, ++i)
1206 {
1207 if (c == *p)
1208 {
1209 cmdval = CMD_ALT + i;
1210 break;
1211 }
1212 }
1213
1214 if (!cmdval) switch(c) {
1215 case 0110: /* Up Arrow */
1216 cmdval = CMD_UP;
1217 break;
1218 case 0120: /* Down Arrow */
1219 cmdval = CMD_DOWN;
1220 break;
1221 case 0115: /* Right Arrow */
1222 cmdval = CMD_RIGHT;
1223 break;
1224 case 0113: /* Left Arrow */
1225 cmdval = CMD_LEFT;
1226 break;
1227 case 0117: /* End */
1228 cmdval = CMD_END;
1229 break;
1230 case 0107: /* Home */
1231 cmdval = CMD_HOME;
1232 break;
1233 case 0165: /* Ctrl-End */
1234 cmdval = CMD_DEOL;
1235 break;
1236 case 0123: /* Del */
1237 cmdval = CMD_DEL;
1238 break;
1239 case 073: /* F1 - change this? */
1240 cmdval = CMD_SCR;
1241 break;
1242 case 0111: /* PgUp */
1243 cmdval = CMD_PGUP;
1244 break;
1245 case 0121: /* PgDn */
1246 cmdval = CMD_PGDN;
1247 break;
1248 case 132: /* control-PgUp */
1249 cmdval = CMD_TOP;
1250 break;
1251 case 118: /* control-PgDn */
1252 cmdval = CMD_BOT;
1253 break;
1254 case 119: /* control home */
1255 cmdval = CMD_CHOME;
1256 break;
1257 case 115: /* control left arrow */
1258 cmdval = CMD_WORD_LEFT;
1259 break;
1260 case 116: /* control right arrow */
1261 cmdval = CMD_WORD_RIGHT;
1262 break;
1263
1264 case 60: cmdval = CMD_F2; break;
1265 case 61: cmdval = CMD_F3; break;
1266 case 62: cmdval = CMD_F4; break;
1267 case 63: cmdval = CMD_F5; break;
1268 case 64: cmdval = CMD_F6; break;
1269 case 65: cmdval = CMD_F7; break;
1270 case 66: cmdval = CMD_F8; break;
1271 case 67: cmdval = CMD_F9; break;
1272 case 68: cmdval = CMD_F10; break;
1273
1274 case 85: cmdval = CMD_SF2; break; /* shifted F2 */
1275
1276 default: /* Unrecognized function key */
1277 cmdval = 0;
1278 break;
1279 }
1280 }
1281 else
1282 {
1283 switch( c )
1284 {
1285 case 1: /* ^A */
1286 cmdval = CMD_HOME;
1287 break;
1288 case 2: /* ^B */
1289 cmdval = CMD_LEFT;
1290 break;
1291 case 4: /* ^D */
1292 cmdval = CMD_DEL;
1293 break;
1294 case 5: /* ^E */
1295 cmdval = CMD_END;
1296 break;
1297 case 6: /* ^F */
1298 cmdval = CMD_RIGHT;
1299 break;
1300 case '\t':
1301 cmdval = CMD_TAB;
1302 break;
1303 case 11: /* ^K */
1304 cmdval = CMD_DEOL;
1305 break;
1306 case 14: /* ^N */
1307 cmdval = CMD_DOWN;
1308 break;
1309 case 16: /* ^P */
1310 cmdval = CMD_UP;
1311 break;
1312 case 21: /* ^U */
1313 case 27: /* Escape */
1314 cmdval = CMD_KILL;
1315 break;
1316 }
1317 }
1318
1319 if (cmdval)
1320 return 0;
1321 else if (c & 0xff)
1322 return c & 0xff;
1323 else
1324 goto tryAgain;
1325 }
1326
os_getc_raw(void)1327 int os_getc_raw(void)
1328 {
1329 static char altkeys[] = {
1330 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50,
1331 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44
1332 };
1333
1334 int c;
1335 static int cmdval;
1336
1337 if (cmdval) {
1338 int tmpcmd = cmdval; /* save command for a moment */
1339 cmdval = 0; /* clear the flag - next call gets another key */
1340 return tmpcmd; /* return the command that we saved */
1341 }
1342
1343 tryAgain:
1344 c = os_getch();
1345
1346 if ((c == 0 || c == 0340)) { /* Extended keycode? */
1347 int i;
1348 char *p;
1349
1350 c = os_getch();
1351
1352 /* check for alt keys */
1353 cmdval = 0;
1354 for (i = 0, p = altkeys ; i < 26 ; ++p, ++i)
1355 {
1356 if (c == *p)
1357 {
1358 cmdval = CMD_ALT + i;
1359 break;
1360 }
1361 }
1362
1363 if (!cmdval) switch(c) {
1364 case 0110: /* Up Arrow */
1365 cmdval = CMD_UP;
1366 break;
1367 case 0120: /* Down Arrow */
1368 cmdval = CMD_DOWN;
1369 break;
1370 case 0115: /* Right Arrow */
1371 cmdval = CMD_RIGHT;
1372 break;
1373 case 0113: /* Left Arrow */
1374 cmdval = CMD_LEFT;
1375 break;
1376 case 0117: /* End */
1377 cmdval = CMD_END;
1378 break;
1379 case 0107: /* Home */
1380 cmdval = CMD_HOME;
1381 break;
1382 case 0165: /* Ctrl-End */
1383 cmdval = CMD_DEOL;
1384 break;
1385 case 0123: /* Del */
1386 cmdval = CMD_DEL;
1387 break;
1388 case 0111: /* PgUp */
1389 cmdval = CMD_PGUP;
1390 break;
1391 case 0121: /* PgDn */
1392 cmdval = CMD_PGDN;
1393 break;
1394 case 132: /* control-PgUp */
1395 cmdval = CMD_TOP;
1396 break;
1397 case 118: /* control-PgDn */
1398 cmdval = CMD_BOT;
1399 break;
1400 case 119: /* control home */
1401 cmdval = CMD_CHOME;
1402 break;
1403 case 115: /* control left arrow */
1404 cmdval = CMD_WORD_LEFT;
1405 break;
1406 case 116: /* control right arrow */
1407 cmdval = CMD_WORD_RIGHT;
1408 break;
1409
1410 case 59: cmdval = CMD_F1; break;
1411 case 60: cmdval = CMD_F2; break;
1412 case 61: cmdval = CMD_F3; break;
1413 case 62: cmdval = CMD_F4; break;
1414 case 63: cmdval = CMD_F5; break;
1415 case 64: cmdval = CMD_F6; break;
1416 case 65: cmdval = CMD_F7; break;
1417 case 66: cmdval = CMD_F8; break;
1418 case 67: cmdval = CMD_F9; break;
1419 case 68: cmdval = CMD_F10; break;
1420
1421 case 85: cmdval = CMD_SF2; break; /* shifted F2 */
1422
1423 default: /* Unrecognized function key */
1424 cmdval = 0;
1425 break;
1426 }
1427 }
1428
1429 if (cmdval)
1430 return 0;
1431 else if (c & 0xff)
1432 return c & 0xff;
1433 else
1434 goto tryAgain;
1435 }
1436
1437 #else /* DJGCC_386 */
1438
1439 int
os_getc(void)1440 os_getc(void)
1441 {
1442 char c;
1443 static char cbuf;
1444 static int buffered = 0;
1445 os_event_info_t evt;
1446
1447 /* if there's a special key pending, return it */
1448 if (buffered) {
1449 buffered = 0;
1450 return cbuf;
1451 }
1452
1453 /* get the next character from standard input (non-blocking) */
1454 read(0, &c, 1);
1455
1456 /* refresh the screen on ^L */
1457 while (c == 12 || c == k_reprint) {
1458 t_refresh();
1459 read(0, &c, 1);
1460 }
1461
1462 /* translate the raw keystroke to a CMD_xxx sequence */
1463 evt.key[0] = c;
1464 oss_raw_key_to_cmd(&evt);
1465
1466 /* read the new keystroke from the translated event */
1467 c = evt.key[0];
1468 cbuf = evt.key[1];
1469
1470 /* if it's special, note the buffered command code for the next call */
1471 if (c == 0)
1472 buffered = 1;
1473
1474 /* return the primary key code */
1475 return c;
1476 }
1477
1478 void
oss_raw_key_to_cmd(os_event_info_t * evt)1479 oss_raw_key_to_cmd(os_event_info_t *evt)
1480 {
1481 char c;
1482 char cbuf;
1483
1484 #define ctrl(c) (c - 'A' + 1)
1485
1486 /* get the primary character of the keystroke event */
1487 c = evt->key[0];
1488
1489 /* map NL to CR */
1490 if (c == 10)
1491 c = 13;
1492
1493 /* handle special keys first, since we can't use them as switch cases */
1494 if (c == k_erase || c == 0x7F) /* erase key or DEL -> backspace */
1495 c = ctrl('H');
1496 if (c == k_kill)
1497 c = ctrl('U');
1498
1499 /* map special keys to command codes */
1500 switch (c) {
1501 case 0:
1502 c = 1;
1503 break;
1504
1505 case 10:
1506 c = 13;
1507 break;
1508
1509 case ctrl('W'):
1510 c = 0;
1511 cbuf = CMD_WORDKILL;
1512 break;
1513
1514 case ctrl('D'):
1515 c = 0;
1516 cbuf = CMD_DEL;
1517 break;
1518
1519 case ctrl('U'):
1520 c = 0;
1521 cbuf = CMD_KILL;
1522 break;
1523
1524 case ctrl('K'):
1525 c = 0;
1526 cbuf = CMD_DEOL;
1527 break;
1528
1529 case ctrl('P'):
1530 c = 0;
1531 cbuf = CMD_UP;
1532 break;
1533
1534 case ctrl('N'):
1535 c = 0;
1536 cbuf = CMD_DOWN;
1537 break;
1538
1539 case ctrl('F'):
1540 c = 0;
1541 cbuf = CMD_RIGHT;
1542 break;
1543
1544 case ctrl('B'):
1545 c = 0;
1546 cbuf = CMD_LEFT;
1547 break;
1548
1549 case ctrl('E'):
1550 c = 0;
1551 cbuf = CMD_END;
1552 break;
1553
1554 case ctrl('A'):
1555 c = 0;
1556 cbuf = CMD_HOME;
1557 break;
1558
1559 case 27:
1560 c = 0;
1561 cbuf = CMD_SCR;
1562 break;
1563
1564 case '<':
1565 c = 0;
1566 cbuf = CMD_PGUP;
1567 break;
1568
1569 case '>':
1570 c = 0;
1571 cbuf = CMD_PGDN;
1572 break;
1573 }
1574
1575 /* store the two-character sequence back in the event */
1576 evt->key[0] = c;
1577 evt->key[1] = cbuf;
1578 }
1579
1580
1581 int
os_getc_raw(void)1582 os_getc_raw(void)
1583 {
1584 char c;
1585
1586 /*
1587 * Get the next character from standard input. (Non-blocking)
1588 */
1589 read(0, &c, 1);
1590
1591 /*
1592 * Handle special keys. os_gets expects certain keys to be certain
1593 * codes.
1594 */
1595 if (c == k_erase || c == 0x7F) /* erase key or DEL -> backspace */
1596 c = ctrl('H');
1597 if (c == k_kill)
1598 c = ctrl('U');
1599
1600 /* handle some more special key translations */
1601 switch (c) {
1602 case 0:
1603 c = 1;
1604 break;
1605
1606 case 10:
1607 /* map newline to return */
1608 c = 13;
1609 break;
1610 }
1611
1612 /* return the key */
1613 return c;
1614 #undef ctrl
1615 }
1616
1617 void
os_waitc(void)1618 os_waitc(void)
1619 {
1620 char c;
1621
1622 /*
1623 * Get the next character from standard input.
1624 * Wait until we get one.
1625 */
1626 while (read(0, &c, 1) < 1);
1627 }
1628 #endif /* DJGCC_386 */
1629
1630 /*
1631 * Update the real screen so it matches our idea of what's on the screen.
1632 */
1633 static void
t_refresh(void)1634 t_refresh(void)
1635 {
1636 if (unix_tdb) {
1637 t_redraw(0, LINES * 2 - 1);
1638 }
1639 else
1640 t_redraw(0, LINES - 1);
1641 }
1642
1643 /*
1644 * Update internal understanding of where the physical cursor is.
1645 */
1646 static void
t_update(int y,int x)1647 t_update(int y, int x)
1648 {
1649 cursorX = x;
1650 cursorY = y;
1651 }
1652
1653 /*
1654 * Move the cursor. Note that this has nothing to do with the virtual cursor
1655 * that TADS tells us to move around -- that's updated by ossloc.
1656 *
1657 * The force parameter tells us to not use the current value of cursorX
1658 * and cursorY and to reposition the cursor absolutely.
1659 *
1660 */
1661 static void
t_loc(int y,int x,int force)1662 t_loc(int y, int x, int force)
1663 {
1664 #ifdef DJGCC_386
1665
1666 bios_video_set_cursor_position(x, y);
1667
1668 #else /* DJGCC_386 */
1669
1670 register int i;
1671
1672 #if 0
1673 #define X printf("[line %d]\n", __LINE__);
1674 #else
1675 #define X
1676 #endif
1677
1678 if (!force)
1679 if (cursorX == x && cursorY == y)
1680 return;
1681
1682 #if 0
1683 printf("[*%d, %d*]", x, y);
1684 #endif
1685
1686 /*
1687 * User direct cursor addressing if we have it; otherwise
1688 * home the cursor and move right and down from there.
1689 *
1690 * If we can get to the destiation by moving just one
1691 * space, we'll use the shorter single movement commands.
1692 */
1693 if (!force && x == cursorX && y == cursorY - 1 && (Tup || TUP)) {
1694 X
1695 /*
1696 * Up one space
1697 */
1698 if (Tup)
1699 t_puts(Tup);
1700 else
1701 t_puts(Tparm(TUP, 1));
1702 }
1703 else if (!force && x == cursorX && y == cursorY + 1 && (Tdo || TDO)) {
1704 X
1705 /*
1706 * Down one space
1707 */
1708 if (Tdo)
1709 t_puts(Tdo);
1710 else
1711 t_puts(Tparm(TDO, 1));
1712 }
1713 else if (!force && y == cursorY && x == cursorX + 1 && (Tnd || TRI)) {
1714 X
1715 /*
1716 * Right one space
1717 */
1718 if (Tnd)
1719 t_puts(Tnd);
1720 else
1721 t_puts(Tparm(TRI, 1));
1722 }
1723 else if (!force && y == cursorY && x == cursorX - 1 && (Tle || TLE)) {
1724 X
1725 /*
1726 * Left one space
1727 */
1728 if (Tle)
1729 t_puts(Tle);
1730 else
1731 t_puts(Tparm(TLE, 1));
1732 }
1733 else if (Tcm) {
1734 X
1735 t_puts(Tparm(Tcm, y, x));
1736 }
1737 else {
1738 X
1739 t_puts(Tho);
1740
1741 if (TRI)
1742 t_puts(Tparm(TRI, x - 1));
1743 else
1744 for (i = 0; i < x; i++)
1745 t_puts(Tnd);
1746
1747 if (TDO)
1748 t_puts(Tparm(TDO, y - 1));
1749 else
1750 for (i = 0; i < y; i++)
1751 t_puts(Tdo);
1752 }
1753
1754 #undef X
1755 t_update(y, x);
1756
1757 #endif /* DJGCC_386 */
1758 }
1759
1760 /*
1761 * Change subsequent text to new color.
1762 */
1763 static void
t_color(char c)1764 t_color(char c)
1765 {
1766 #ifdef DJGCC_386
1767
1768 if (c & cREVERSE)
1769 bios_video_set_color(revcolor);
1770 else if (c & cBOLD)
1771 bios_video_set_color(boldcolor);
1772 else
1773 bios_video_set_color(plaincolor);
1774
1775 #else /* DJGCC_386 */
1776
1777 if (c == COLOR)
1778 return;
1779
1780 /*
1781 * Disable all attributes (if possible), including standout.
1782 */
1783 t_puts(Tme);
1784 if (standout_ok && !(c & cSTANDOUT))
1785 t_puts(Tse);
1786 if (underscore_ok && !(c & cUNDERSCORE))
1787 t_puts(Tue);
1788
1789 if (c & cSTANDOUT)
1790 if (standout_ok)
1791 t_puts(Tso);
1792 if (c & cREVERSE)
1793 if (rev_ok)
1794 t_puts(Tmr);
1795 if (c & cBOLD)
1796 if (bold_ok)
1797 t_puts(Tmd);
1798 if (c & cBLINK)
1799 if (blink_ok)
1800 t_puts(Tmb);
1801 if (c & cUNDERSCORE)
1802 if (underscore_ok)
1803 t_puts(Tus);
1804
1805 /*
1806 * Save color.
1807 */
1808 COLOR = c;
1809
1810 #endif /* DJGCC_386 */
1811 }
1812
1813 /*
1814 * Redraw a portion of the screen.
1815 */
1816 static void
t_redraw(int top,int bottom)1817 t_redraw(int top, int bottom)
1818 {
1819 static char ds[MAXCOLS + 1] = {0};
1820
1821 register int row, col, pos;
1822 int color, newcolor;
1823
1824 /*
1825 * Hide cursor
1826 */
1827 t_hide();
1828
1829 /*
1830 * Position to top line, column zero.
1831 */
1832 t_loc(top, 0, 1);
1833
1834 /*
1835 * Redraw each line between top line and bottom line.
1836 * We have to build a string from our text and color
1837 * information so we can write the output a line at a time
1838 * rather than a character at a time.
1839 */
1840 color = colors[top][0];
1841 t_color(color);
1842 for (row = top; row <= bottom; row++) {
1843 /*
1844 * Move cursor to beginning of this line
1845 */
1846 t_loc(row, 0, 1);
1847
1848 /*
1849 * Combine color and text information into a single
1850 * string for this line.
1851 */
1852 for (col = 0, pos = 0; col < COLS; col++) {
1853 /*
1854 * Do we have to change text color?
1855 * If so, print the text we've buffered for
1856 * this line and then print the change string.
1857 */
1858 if ((newcolor = colors[row][col]) != color) {
1859 ds[pos] = 0;
1860 t_outs(ds);
1861 t_color(newcolor);
1862 t_loc(row, col, 1);
1863 pos = 0;
1864 color = newcolor;
1865 }
1866 ds[pos++] = screen[row][col];
1867 }
1868
1869 ds[pos] = 0;
1870 t_outs(ds); /* blast the string */
1871 }
1872
1873 /*
1874 * Reposition cursor to its former location
1875 */
1876 t_loc(inputY, inputX, 1);
1877
1878 /*
1879 * Show cursor
1880 */
1881 t_show();
1882 }
1883
1884 /*
1885 * Scroll region
1886 * lines < 0 -> scroll up (delete line)
1887 * lines > 0 -> scroll down (insert line)
1888 */
1889 static void
t_scroll(int top,int bot,int lines)1890 t_scroll(int top, int bot, int lines)
1891 {
1892 #ifdef DJGCC_386
1893
1894 bios_video_scroll_region(top, bot, 0, COLS - 1, lines);
1895
1896 #else /* DJGCC_386 */
1897
1898 char *single = lines > 0 ? Tsr : Tsf;
1899 char *multi = lines > 0 ? TSR : TSF;
1900 int labs = lines < 0 ? -lines : lines;
1901 int i;
1902
1903 /*
1904 * Make sure new lines have the right background color
1905 */
1906 t_color(text_normal_color);
1907
1908 /*
1909 * If we have scroll region capability, use it.
1910 * Otherwise fake it with insert/delete line.
1911 */
1912 if ((single || multi) && (Tcs || TcS || Twi)) {
1913 t_set_scroll_region(top, bot);
1914
1915 if (lines < 0)
1916 t_loc(bot, 0, 1);
1917 else
1918 t_loc(top, 0, 1);
1919
1920 if (labs > 1 && multi || !single)
1921 t_puts(Tparm(multi, labs));
1922 else
1923 for (i = 0; i < labs; i++)
1924 t_puts(single);
1925
1926 t_set_scroll_region(0, LINES - 1);
1927 }
1928 else {
1929 /*
1930 * Make sure we never eat lines below the window
1931 */
1932 if (labs> bot - top + 1)
1933 labs = bot - top + 1;
1934
1935 if (lines < 0) {
1936 /*
1937 * Delete lines
1938 */
1939 t_loc(top, 0, 1);
1940 if (TDL && labs != 1) {
1941 t_puts(Tparm(TDL, labs));
1942 }
1943 else if (Tdl) {
1944 for (i = 0; i < labs; i++)
1945 t_puts(Tdl);
1946 }
1947 else {
1948 /* shouldn't happen */
1949 }
1950
1951 /*
1952 * Insert lines to keep windows below this
1953 * one intact.
1954 */
1955 if (bot < LINES - 1) {
1956 t_loc(bot + 1 - labs, 0, 1);
1957 if (TAL && labs != 1) {
1958 t_puts(Tparm(TAL, labs));
1959 }
1960 else if (Tal) {
1961 for (i = 0; i < labs; i++)
1962 t_puts(Tal);
1963 }
1964 else {
1965 /* shouldn't happen */
1966 }
1967 }
1968 }
1969 else {
1970 /*
1971 * Insert lines
1972 */
1973
1974 /*
1975 * Delete lines to keep windows below this
1976 * one intact.
1977 */
1978 if (bot < LINES - 1) {
1979 t_loc(bot + 1 - labs, 0, 1);
1980 if (TDL && labs != 1) {
1981 t_puts(Tparm(TDL, labs));
1982 }
1983 else if (Tdl) {
1984 for (i = 0; i < labs; i++)
1985 t_puts(Tdl);
1986 }
1987 else {
1988 /* shouldn't happen */
1989 }
1990 }
1991
1992
1993 /*
1994 * Insert lines at top of window.
1995 */
1996 t_loc(top, 0, 1);
1997 if (TAL && labs != 1) {
1998 t_puts(Tparm(TAL, labs));
1999 }
2000 else if (Tal) {
2001 for (i = 0; i < labs; i++)
2002 t_puts(Tal);
2003 }
2004 else {
2005 /* shouldn't happen */
2006 }
2007 }
2008 }
2009
2010 /*
2011 * After we scroll, we don't know where the cursor is.
2012 */
2013 t_update(-1, -1);
2014
2015 #endif /* DJGCC_386 */
2016 }
2017
2018 static void
t_set_scroll_region(int top,int bot)2019 t_set_scroll_region(int top, int bot)
2020 {
2021 #ifndef DJGCC_386
2022 static int topsave = -1, botsave = -1;
2023
2024 if (top == topsave && bot == botsave)
2025 return;
2026
2027 if (Tcs) {
2028 t_puts(Tparm(Tcs, top, bot));
2029 }
2030 else if (TcS) {
2031 t_puts(Tparm(TcS, LINES, top, LINES - (bot + 1), LINES));
2032 }
2033 else {
2034 t_puts(Tparm(Twi, top, 0, bot, COLS - 1));
2035 }
2036
2037 topsave = top;
2038 botsave = bot;
2039 #endif
2040 }
2041
2042 /*
2043 * Scroll region down a line.
2044 * This is equivalent to inserting a line at the top of the region.
2045 */
2046 void
ossscu(int top,int left,int bottom,int right,int blank_color)2047 ossscu(int top, int left, int bottom, int right, int blank_color)
2048 {
2049 register int r1, r2, col;
2050
2051 if (unix_tdb) {
2052 top += LINES * cw;
2053 bottom += LINES * cw;
2054 }
2055
2056 #ifdef DEBUG_OUTPUT
2057 printf("[ossscu(%d, %d, %d, %d, %d)]",
2058 top, left, bottom, right, blank_color);
2059 #endif
2060
2061 if (unix_tc)
2062 return;
2063
2064 /*
2065 * Update our internal version
2066 */
2067 for (r1 = bottom - 1, r2 = bottom; r1 >= top; r1--, r2--)
2068 for (col = left; col <= right; col++) {
2069 screen[r2][col] = screen[r1][col];
2070 colors[r2][col] = colors[r1][col];
2071 }
2072 for (col = left; col <= right; col++) {
2073 screen[r2][col] = ' ';
2074 colors[r2][col] = blank_color;
2075 }
2076
2077 /*
2078 * If we can duplicate the effect of this scroll on the screen
2079 * with scrolling commands, do so; otherwise, refresh by redrawing
2080 * every affected line.
2081 */
2082 #ifdef T_OPTIMIZE
2083 if (left == 0 && right >= unix_max_column) {
2084 t_scroll(top, bottom, 1);
2085 }
2086 else {
2087 #else
2088 t_redraw(top, bottom);
2089 #endif
2090
2091 #ifdef T_OPTIMIZE
2092 }
2093 #endif
2094 }
2095
2096 /*
2097 * Scroll region up a line
2098 * This is equivalent to deleting a line at the top of the region and pulling
2099 * everything below it up.
2100 */
2101 void
ossscr(int top,int left,int bottom,int right,int blank_color)2102 ossscr(int top, int left, int bottom, int right, int blank_color)
2103 {
2104 register int r1, r2, col;
2105
2106 if (unix_tdb) {
2107 top += LINES * cw;
2108 bottom += LINES * cw;
2109 }
2110
2111 #ifdef DEBUG_OUTPUT
2112 printf("[ossscr(%d, %d, %d, %d, %d)]",
2113 top, left, bottom, right, blank_color);
2114 #endif
2115
2116 if (unix_tc) {
2117 putchar('\n');
2118 return;
2119 }
2120
2121 /*
2122 * Update our internal version
2123 */
2124 for (r1 = top, r2 = top + 1; r2 <= bottom; r1++, r2++)
2125 for (col = left; col <= right; col++) {
2126 screen[r1][col] = screen[r2][col];
2127 colors[r1][col] = colors[r2][col];
2128 }
2129 for (col = left; col <= right; col++) {
2130 screen[r1][col] = ' ';
2131 colors[r1][col] = blank_color;
2132 }
2133
2134 /*
2135 * If we can duplicate the effect of this scroll on the screen
2136 * with a scrolling command, do so; otherwise, refresh by redrawing
2137 * every affected line.
2138 */
2139 #ifdef T_OPTIMIZE
2140 if (left == 0 && right >= unix_max_column) {
2141 t_scroll(top, bottom, -1);
2142 }
2143 else {
2144 #else
2145 t_redraw(top, bottom);
2146 #endif
2147
2148 #ifdef T_OPTIMIZE
2149 }
2150 #endif
2151 }
2152
2153 /*
2154 * Clear region (fill with spaces)
2155 */
2156 void
ossclr(int top,int left,int bottom,int right,int blank_color)2157 ossclr(int top, int left, int bottom, int right, int blank_color)
2158 {
2159 register int row, col;
2160
2161 if (unix_tdb) {
2162 top += LINES * cw;
2163 bottom += LINES * cw;
2164 }
2165
2166 #ifdef DEBUG_OUTPUT
2167 printf("[ossclr(%d, %d, %d, %d, %d)]",
2168 top, left, bottom, right, blank_color);
2169 #endif
2170
2171 if (unix_tc)
2172 return;
2173
2174 /*
2175 * Update our internal version
2176 */
2177 for (row = top; row <= bottom; row++)
2178 for (col = left; col <= right; col++) {
2179 screen[row][col] = ' ';
2180 colors[row][col] = blank_color;
2181 }
2182
2183 /*
2184 * If we can duplicate the effect of this clear on the screen
2185 * with a clear command, do so; otherwise, refresh by redrawing every
2186 * affected line.
2187 */
2188 #ifdef DJGCC_386
2189 bios_video_set_bkgnd(plaincolor);
2190 bios_video_clear_region(top, bottom, left, right);
2191 #else /* DJGCC_386 */
2192
2193 #ifdef T_OPTIMIZE
2194 if (Tce && left == 0 && right >= unix_max_column) {
2195 t_color(blank_color);
2196
2197 if (Tcl && top == 0 && bottom >= unix_max_line) {
2198 t_loc(0, 0, 1);
2199 t_puts(Tcl);
2200 }
2201 else if (Tcd && bottom >= unix_max_line) {
2202 t_loc(top, 0, 1);
2203 t_puts(Tcd);
2204 }
2205 else for (row = top; row <= bottom; row++) {
2206 t_loc(row, 0, 1);
2207 t_puts(Tce);
2208 }
2209
2210 /*
2211 * Don't know where the cursor is after clear.
2212 */
2213 t_update(-1, -1);
2214 }
2215 else {
2216 #endif
2217 t_redraw(top, bottom);
2218 #ifdef T_OPTIMIZE
2219 }
2220 #endif
2221
2222 #endif /* DJGCC_386 */
2223 }
2224
2225 /*
2226 * Locate (input) cursor at given row and column.
2227 * Nore that this is never used to determine where things are drawn.
2228 * It's only used for aesthetics; i.e., showing the user where input
2229 * will be taken from next.
2230 */
2231 void
ossloc(int row,int col)2232 ossloc(int row, int col)
2233 {
2234 if (unix_tc)
2235 return;
2236
2237 if (unix_tdb)
2238 row += LINES * cw;
2239
2240 t_loc(row, col, 0);
2241
2242 /*
2243 * Update internal cursor position so t_redraw will
2244 * be correct.
2245 */
2246 inputX = col;
2247 inputY = row;
2248 }
2249
2250 /*
2251 * Display msg with color at coordinates (y, x).
2252 * The color must be in the range 0 <= color <= 16, and specifies both
2253 * foreground and background colors.
2254 */
ossdsp(int y,int x,int color,const char * msg)2255 void ossdsp(int y, int x, int color, const char *msg)
2256 {
2257 register int col;
2258 register char *s, *m = msg, *c;
2259
2260 #ifdef DEBUG_OUTPUT
2261 printf("[ossdsp(%d, %d, %d, \"%s\")]", y, x, color, msg);
2262 #endif
2263
2264 if (unix_tc) {
2265 printf("%s", msg);
2266 fflush(stdout);
2267 }
2268
2269 if (y >= LINES || x >= COLS)
2270 return;
2271
2272 if (unix_tdb)
2273 y += LINES * cw;
2274
2275 s = &screen[y][x];
2276 c = &colors[y][x];
2277
2278 /*
2279 * Update our own version of the screen.
2280 */
2281 for (col = x; *m && col < COLS; col++) {
2282 *s++ = *m++;
2283 *c++ = color;
2284 }
2285
2286 #ifdef FAST_OSSDSP
2287 /*
2288 * XXX
2289 *
2290 * We redraw the whole line if it's the status line.
2291 * This is pretty bogus.
2292 */
2293 t_loc(y, x, 0);
2294 t_color(color);
2295 t_outs(msg);
2296 t_update(cursorY, cursorX + strlen(msg));
2297 #else
2298 t_redraw(y, y);
2299 #endif
2300 }
2301
2302
2303 /*
2304 * Stuff for the debugger
2305 */
2306 void
ossgmx(int * maxline,int * maxcol)2307 ossgmx(int *maxline, int *maxcol)
2308 {
2309 *maxline = LINES - 1;
2310 *maxcol = COLS - 1;
2311 }
2312
2313 /* clear a window */
osdbgclr(oswdef * win)2314 void osdbgclr(oswdef *win)
2315 {
2316 ossclr(win->oswy1, win->oswx1, win->oswy2, win->oswx2, win->oswcolor);
2317 }
2318
osdbgini(int rows,int cols)2319 int osdbgini(int rows, int cols)
2320 {
2321 return(0);
2322 }
2323
ossvpg(char pg)2324 int ossvpg(char pg)
2325 {
2326 static int s_inputX = 0, s_inputY = 0;
2327 int ret;
2328
2329 if (cw == pg)
2330 return cw;
2331
2332 inputX = s_inputX;
2333 inputY = s_inputY;
2334
2335 ret = cw;
2336 cw = pg;
2337 t_update(-1, -1);
2338 COLOR = -1;
2339 /* t_refresh(); */
2340
2341 return ret;
2342 }
2343
ossmon(void)2344 int ossmon(void)
2345 {
2346 return 0;
2347 }
2348
2349 /* scroll a window up a line */
osdbgsc(oswdef * win)2350 static void osdbgsc(oswdef *win)
2351 {
2352 ossscr(win->oswy1, win->oswx1, win->oswy2, win->oswx2, win->oswcolor);
2353 }
2354
2355 # ifdef USE_STDARG
osdbgpt(oswdef * win,const char * fmt,...)2356 void osdbgpt(oswdef *win, const char *fmt, ...)
2357 # else /* USE_STDARG */
2358 void osdbgpt( win, fmt, a1, a2, a3, a4, a5, a6, a7, a8 )
2359 oswdef *win;
2360 char *fmt;
2361 long a1, a2, a3, a4, a5, a6, a7, a8;
2362 # endif /* USE_STDARG */
2363 {
2364 char buf[256];
2365 char *p;
2366
2367 # ifdef USE_STDARG
2368 va_list argptr;
2369
2370 va_start( argptr, fmt );
2371 vsprintf( buf, fmt, argptr );
2372 va_end( argptr );
2373 # else /* USE_STDARG */
2374 sprintf( buf, fmt, a1, a2, a3, a4, a5, a6, a7, a8 );
2375 # endif /* USE_STDARG */
2376
2377 for (p=buf ; *p ; )
2378 {
2379 char *p1;
2380
2381 if ((win->oswflg & OSWFMORE) && win->oswx == win->oswx1 &&
2382 win->oswmore+1 >= win->oswy2 - win->oswy1)
2383 {
2384 char c;
2385 int eof;
2386
2387 ossdsp(win->oswy, win->oswx, win->oswcolor, "[More]");
2388 ossdbgloc(win->oswy, win->oswx+6);
2389 eof = FALSE;
2390 do
2391 {
2392 switch(c = os_getc())
2393 {
2394 case '\n':
2395 case '\r':
2396 win->oswmore--;
2397 break;
2398
2399 case ' ':
2400 win->oswmore = 0;
2401 break;
2402
2403 case 0:
2404 if (os_getc() == CMD_EOF)
2405 {
2406 eof = TRUE;
2407 win->oswmore = 0;
2408 }
2409 break;
2410 }
2411 } while (c != ' ' && c != '\n' && c != '\r' && !eof);
2412
2413 ossdsp(win->oswy, win->oswx, win->oswcolor, " ");
2414 }
2415
2416 for (p1 = p ; *p1 && *p1 != '\n' && *p1 != '\r' && *p1 != '\t'; p1++);
2417 if (*p1 == '\n' || *p1 == '\r' || *p1 == '\t')
2418 {
2419 int c = *p1;
2420
2421 *p1 = '\0';
2422
2423 if (win->oswx + strlen(p) > win->oswx2 &&
2424 (win->oswflg & OSWFCLIP))
2425 p[win->oswx2 - win->oswx + 1] = '\0';
2426 ossdsp(win->oswy, win->oswx, win->oswcolor, p);
2427
2428 if (c == '\n')
2429 {
2430 ++(win->oswy);
2431 win->oswx = win->oswx1;
2432 if (win->oswy > win->oswy2)
2433 {
2434 win->oswy = win->oswy2;
2435 osdbgsc(win);
2436 }
2437 win->oswmore++;
2438 }
2439 else if (c == '\t')
2440 {
2441 win->oswx += strlen(p);
2442 do
2443 {
2444 ossdsp(win->oswy, win->oswx, win->oswcolor, " ");
2445 ++(win->oswx);
2446 if (win->oswx > win->oswx2 && (win->oswflg & OSWFCLIP))
2447 break;
2448 } while ((win->oswx - 2) & 7);
2449 }
2450 p = p1 + 1;
2451 if (win->oswx > win->oswx2) return;
2452 }
2453 else
2454 {
2455 if (win->oswx + strlen(p) > win->oswx2
2456 && (win->oswflg & OSWFCLIP))
2457 p[win->oswx2 - win->oswx + 1] = '\0';
2458 ossdsp(win->oswy, win->oswx, win->oswcolor, p);
2459 win->oswx += strlen(p);
2460 p = p1;
2461 }
2462 }
2463 }
2464
2465 /* open a window - set up location */
osdbgwop(oswdef * win,int x1,int y1,int x2,int y2,int color)2466 void osdbgwop(oswdef *win, int x1, int y1, int x2, int y2, int color)
2467 {
2468 win->oswx1 = win->oswx = x1;
2469 win->oswx2 = x2;
2470 win->oswy1 = win->oswy = y1;
2471 win->oswy2 = y2;
2472 win->oswcolor = color;
2473 win->oswflg = 0;
2474 }
2475
ossdbgloc(int y,int x)2476 void ossdbgloc(int y, int x)
2477 {
2478 ossloc(y, x);
2479 }
2480
2481 /* get some text */
osdbggts(oswdef * win,char * buf,int (* cmdfn)(),void * cmdctx)2482 int osdbggts( oswdef *win,
2483 char *buf,
2484 int (*cmdfn)(/*_ void *ctx, char cmd _*/),
2485 void *cmdctx)
2486 {
2487 char *p = buf;
2488 char *eol = buf;
2489 char *eob = buf + 127;
2490 int x = win->oswx;
2491 int y = win->oswy;
2492 int origx = x;
2493 int cmd = 0;
2494
2495 win->oswmore = 0;
2496 for (buf[0] = '\0' ; ; )
2497 {
2498 char c;
2499
2500 ossdbgloc(y, x);
2501 switch(c = os_getc())
2502 {
2503 case 8:
2504 if (p > buf)
2505 {
2506 char *q;
2507 char tmpbuf[2];
2508 int thisx, thisy;
2509
2510 for ( q=(--p) ; q<eol ; q++ ) *q = *( q+1 );
2511 eol--;
2512 if ( --x < 0 )
2513 {
2514 x = win->oswx2;
2515 y--;
2516 }
2517 *eol = ' ';
2518 thisx = x;
2519 thisy = y;
2520 for ( q=p, tmpbuf[1]='\0' ; q<=eol ; q++ )
2521 {
2522 tmpbuf[0] = *q;
2523 ossdsp( thisy, thisx, win->oswcolor, tmpbuf );
2524 if ( ++thisx > win->oswx2 )
2525 {
2526 thisx = 0;
2527 thisy++;
2528 }
2529 }
2530 *eol = '\0';
2531 }
2532 break;
2533 case 13:
2534 /*
2535 * Scroll the screen to account for the carriage return,
2536 * position the cursor at the end of the new line, and
2537 * null-terminate the line.
2538 */
2539 *eol = '\0';
2540 while( p != eol )
2541 {
2542 p++;
2543 if ( ++x > win->oswx2 )
2544 {
2545 y++;
2546 x = 0;
2547 }
2548 }
2549
2550 if ( y == win->oswy2 ) osdbgsc(win);
2551 else ++y;
2552 x = 0;
2553 ossdbgloc( y, x );
2554
2555 /*
2556 * Finally, copy the buffer to the screen save buffer
2557 * (if applicable), and return the contents of the buffer.
2558 */
2559 win->oswx = x;
2560 win->oswy = y;
2561 return(0);
2562
2563 case 0:
2564 switch(c = os_getc())
2565 {
2566 case CMD_EOF:
2567 return 0;
2568
2569 case CMD_LEFT:
2570 if ( p>buf )
2571 {
2572 p--;
2573 x--;
2574 if ( x < 0 )
2575 {
2576 x = win->oswx2;
2577 y--;
2578 }
2579 }
2580 break;
2581 case CMD_RIGHT:
2582 if ( p<eol )
2583 {
2584 p++;
2585 x++;
2586 if ( x > win->oswx2 )
2587 {
2588 x = 0;
2589 y++;
2590 }
2591 }
2592 break;
2593 case CMD_DEL:
2594 if ( p<eol )
2595 {
2596 char *q;
2597 char tmpbuf[2];
2598 int thisx=x, thisy=y;
2599
2600 for ( q=p ; q<eol ; q++ ) *q = *(q+1);
2601 eol--;
2602 *eol = ' ';
2603 for ( q=p, tmpbuf[1]='\0' ; q<=eol ; q++ )
2604 {
2605 tmpbuf[0] = *q;
2606 ossdsp( thisy, thisx, win->oswcolor, tmpbuf );
2607 if ( ++thisx > win->oswx2 )
2608 {
2609 thisx = 0;
2610 thisy++;
2611 }
2612 }
2613 *eol = '\0';
2614 }
2615 break;
2616 case CMD_KILL:
2617 case CMD_HOME:
2618 do_kill:
2619 while( p>buf )
2620 {
2621 p--;
2622 if ( --x < 0 )
2623 {
2624 x = win->oswx2;
2625 y--;
2626 }
2627 }
2628 if ( c == CMD_HOME ) break;
2629 /*
2630 * We're at the start of the line now; fall
2631 * through for KILL, UP, and DOWN to the code
2632 * which deletes to the end of the line.
2633 */
2634 case CMD_DEOL:
2635 if ( p<eol )
2636 {
2637 char *q;
2638 int thisx=x, thisy=y;
2639
2640 for ( q=p ; q<eol ; q++ )
2641 {
2642 ossdsp( thisy, thisx, win->oswcolor, " " );
2643 if ( ++thisx > win->oswx2 )
2644 {
2645 thisx = 0;
2646 thisy++;
2647 }
2648 }
2649 eol = p;
2650 *p = '\0';
2651 }
2652 if (cmd) return(cmd);
2653 break;
2654 case CMD_END:
2655 while ( p<eol )
2656 {
2657 p++;
2658 if ( ++x > win->oswx2 )
2659 {
2660 x = 0;
2661 y++;
2662 }
2663 }
2664 break;
2665
2666 default:
2667 if (cmd = (*cmdfn)(cmdctx, c))
2668 {
2669 c = CMD_KILL;
2670 goto do_kill;
2671 }
2672 break;
2673 }
2674 break;
2675 default:
2676 if ( c >= ' ' && c < 127 && eol<eob )
2677 {
2678 if ( p != eol )
2679 {
2680 char *q;
2681 int thisy=y, thisx=x;
2682 char tmpbuf[2];
2683
2684 for ( q=(++eol) ; q>p ; q-- ) *q=*(q-1);
2685 *p = c;
2686 for ( q=p++, tmpbuf[1] = '\0' ; q<eol ; q++ )
2687 {
2688 tmpbuf[0] = *q;
2689 ossdsp( thisy, thisx, win->oswcolor, tmpbuf );
2690 thisx++;
2691 if ( thisx > win->oswx2 )
2692 {
2693 thisx = 0;
2694 if ( thisy == win->oswy2 )
2695 {
2696 y--;
2697 osdbgsc(win);
2698 }
2699 else thisy++;
2700 }
2701 }
2702 if ( ++x > win->oswx2 )
2703 {
2704 y++;
2705 x = 0;
2706 }
2707 }
2708 else
2709 {
2710 *p++ = c;
2711 *p = '\0';
2712 eol++;
2713 ossdsp( y, x, win->oswcolor, p-1 );
2714 if ( ++x > win->oswx2 )
2715 {
2716 x = 0;
2717 if ( y == win->oswy2 )
2718 osdbgsc(win);
2719 else y++;
2720 }
2721 }
2722 }
2723 break;
2724 }
2725 }
2726 }
2727
2728
2729 /*
2730 * End of stuff for debugger
2731 */
2732
2733 #else /* USE_STDIO */
2734
2735 int
os_init(int * argc,char * argv[],const char * prompt,char * buf,int bufsiz)2736 os_init( int *argc, char *argv[], const char *prompt, char *buf, int bufsiz )
2737 {
2738 return 0;
2739 }
2740
2741 void
os_uninit()2742 os_uninit()
2743 {
2744 }
2745
2746 void
os_term(int rc)2747 os_term(int rc)
2748 {
2749 exit(rc);
2750 }
2751
2752 int
os_break(void)2753 os_break(void)
2754 {
2755 int ret;
2756
2757 ret = break_set;
2758 break_set = 0;
2759 return ret;
2760 }
2761
2762 void
os_waitc(void)2763 os_waitc(void)
2764 {
2765 getchar(); /* Changed from getkey() by SRG */
2766 }
2767
2768 int
os_getc(void)2769 os_getc(void)
2770 {
2771 return getchar(); /* Changed from getkey() by SRG */
2772 }
2773
2774 int
os_getc_raw(void)2775 os_getc_raw(void)
2776 {
2777 return os_getc();
2778 }
2779
2780 #endif /* USE_STDIO */
2781
2782 int
os_paramfile(char * buf)2783 os_paramfile(char *buf)
2784 {
2785 return 0;
2786 }
2787
2788 /*
2789 * os_exeseek - opens the given .EXE file and seeks to the end of the
2790 * executable part of it, on the presumption that a datafile is to be
2791 * found there.
2792 */
os_exeseek(const char * exefile,const char * typ)2793 osfildef *os_exeseek(const char *exefile, const char *typ )
2794 {
2795 return((osfildef *)0);
2796 }
2797
2798 /*
2799 * os_exfld - load in an external function from an open file, given
2800 * the size of the function (in bytes). Returns a pointer to the newly
2801 * allocated memory block containing the function in memory.
2802 */
os_exfld(osfildef * fp,unsigned len)2803 int (*os_exfld( osfildef *fp, unsigned len ))(void *)
2804 {
2805 return (int (*)(void *)) 0;
2806 }
2807
2808 /*
2809 * Load an external function from a file. This routine assumes that
2810 * the file has the same name as the resource.
2811 */
os_exfil(const char * name)2812 int (*os_exfil(const char *name ))(void *)
2813 {
2814 return (int (*)(void *)) 0;
2815 }
2816
2817 /*
2818 * call an external function, passing it an argument (a string pointer),
2819 * and passing back the string pointer returned by the external function
2820 */
os_excall(int (* extfn)(void *),void * arg)2821 int os_excall(int (*extfn)(void *), void *arg)
2822 {
2823 return 0;
2824 }
2825
2826 /*
2827 * Get the temporary file path. This should fill in the buffer with a
2828 * path prefix (suitable for strcat'ing a filename onto) for a good
2829 * directory for a temporary file, such as the swap file.
2830 */
2831 void
os_get_tmp_path(char * s)2832 os_get_tmp_path(char *s)
2833 {
2834 strcpy(s, "/tmp");
2835 }
2836
2837 /* os_defext(fn, ext) should append the default extension ext to the filename
2838 * in fn. It is assumed that the buffer at fn is big enough to hold the added
2839 * characters in the extension. The result should be null-terminated. When
2840 * an extension is already present in the filename at fn, no action should be
2841 * taken. On systems without an analogue of extensions, this routine should
2842 * do nothing.
2843 *
2844 * For Unix, we extend this to also prepend the default saved game or game
2845 * file path name.
2846 *
2847 * - The TADSSAVE environment variable holds the name of the save file
2848 * directory
2849 * - The TADSGAME envirnoment variable holds the name of the game file
2850 * directory
2851 *
2852 * We only prepend if there are no slashes in the filename already.
2853 * We don't prepand paths when running as the compiler, because we don't want
2854 * the output files to go in weird places.
2855 */
os_defext(char * fn,const char * ext)2856 void os_defext( char *fn, const char *ext )
2857 {
2858 char *p, *n, tmp[1024];
2859 char *defpath;
2860
2861 /*
2862 * Prepend default path
2863 */
2864 if (!memicmp(ext, "sav", strlen(ext)))
2865 defpath = getenv("TADSSAVE");
2866 else if (!memicmp(ext, "gam", strlen(ext)))
2867 defpath = getenv("TADSGAME");
2868 else
2869 defpath = NULL;
2870
2871 if (!unix_tc && defpath) {
2872 /*
2873 * Look for slashes. If there are any, don't mess with name.
2874 */
2875 n = fn;
2876 while (*n) {
2877 if (*n == '/')
2878 break;
2879 n++;
2880 }
2881 if (!*n) {
2882 strcpy(tmp, defpath);
2883 if (defpath[strlen(defpath)] != '/')
2884 strcat(tmp, "/");
2885 strcat(tmp, fn);
2886 strcpy(fn, tmp);
2887 }
2888 }
2889
2890 p = fn+strlen(fn);
2891 while ( p>fn )
2892 {
2893 p--;
2894 if ( *p=='.' ) return; /* already has an extension */
2895 if ( *p=='/' || *p=='\\' || *p==':'
2896 ) break; /* found a path */
2897 }
2898 strcat( fn, "." ); /* add a dot */
2899 strcat( fn, ext ); /* add the extension */
2900 }
2901
2902 /* os_remext(fn) removes the extension from fn, if present. The buffer at
2903 * fn should be modified in place. If no extension is present, no action
2904 * should be taken. For systems without an analogue of extensions, this
2905 * routine should do nothing.
2906 */
os_remext(char * fn)2907 void os_remext( char *fn )
2908 {
2909 char *p = fn+strlen(fn);
2910 while ( p>fn )
2911 {
2912 p--;
2913 if ( *p=='.' )
2914 {
2915 *p = '\0';
2916 return;
2917 }
2918 if ( *p=='/' || *p=='\\' || *p==':'
2919 ) return;
2920 }
2921 }
2922
2923 /*
2924 * Add an extension, even if the filename currently has one
2925 */
os_addext(char * fn,const char * ext)2926 void os_addext(char *fn, const char *ext)
2927 {
2928 strcat(fn, ".");
2929 strcat(fn, ext);
2930 }
2931
2932 /*
2933 * Returns a pointer to the root portion of the filename. Added by SRG.
2934 */
os_get_root_name(char * buf)2935 char *os_get_root_name(char *buf)
2936 {
2937 char *p = buf;
2938
2939 p += strlen(buf) - 1;
2940 while (*p != '/' && p > buf)
2941 p--;
2942 if (p != buf) p++;
2943
2944 return p;
2945 }
2946
2947
2948 /*
2949 * This is an extremely unsophisticated version of os_xlat_html4, which translates
2950 * everything it can into its near-ASCII equivalent. Added by SRG, after code from
2951 * OSDOS.C.
2952 */
os_xlat_html4(unsigned int html4_char,char * result,size_t result_len)2953 void os_xlat_html4(unsigned int html4_char, char *result, size_t result_len)
2954 {
2955 /* default character to use for unknown charaters */
2956 #define INV_CHAR " "
2957
2958 /*
2959 * Translation table - provides mappings for characters the ISO
2960 * Latin-1 subset of the HTML 4 character map (values 128-255).
2961 *
2962 * Characters marked "(approx)" are approximations where the actual
2963 * desired character is not available, but a reasonable approximation
2964 * is used. Characters marked "(approx unaccented)" are accented
2965 * characters that are not available; these use the unaccented equivalent
2966 * as an approximation, since this will presumably convey more meaning
2967 * than a blank.
2968 *
2969 * Characters marked "(n/a)" have no equivalent (even approximating),
2970 * and are mapped to spaces.
2971 *
2972 * Characters marked "(not used)" are not used by HTML '&' markups.
2973 */
2974 static const char *xlat_tbl[] =
2975 {
2976 INV_CHAR, /* 128 (not used) */
2977 INV_CHAR, /* 129 (not used) */
2978 "'", /* 130 - sbquo (approx) */
2979 INV_CHAR, /* 131 (not used) */
2980 "\"", /* 132 - bdquo (approx) */
2981 INV_CHAR, /* 133 (not used) */
2982 INV_CHAR, /* 134 - dagger (n/a) */
2983 INV_CHAR, /* 135 - Dagger (n/a) */
2984 INV_CHAR, /* 136 (not used) */
2985 INV_CHAR, /* 137 - permil (n/a) */
2986 INV_CHAR, /* 138 (not used) */
2987 "<", /* 139 - lsaquo (approx) */
2988 INV_CHAR, /* 140 - OElig (n/a) */
2989 INV_CHAR, /* 141 (not used) */
2990 INV_CHAR, /* 142 (not used) */
2991 INV_CHAR, /* 143 (not used) */
2992 INV_CHAR, /* 144 (not used) */
2993 "'", /* 145 - lsquo (approx) */
2994 "'", /* 146 - rsquo (approx) */
2995 "\"", /* 147 - ldquo (approx) */
2996 "\"", /* 148 - rdquo (approx) */
2997 INV_CHAR, /* 149 (not used) */
2998 "-", /* 150 - endash */
2999 "--", /* 151 - emdash */
3000 INV_CHAR, /* 152 (not used) */
3001 "(tm)", /* 153 - trade (approx) */
3002 INV_CHAR, /* 154 (not used) */
3003 ">", /* 155 - rsaquo (approx) */
3004 INV_CHAR, /* 156 - oelig (n/a) */
3005 INV_CHAR, /* 157 (not used) */
3006 INV_CHAR, /* 158 (not used) */
3007 "Y", /* 159 - Yuml (approx unaccented) */
3008 INV_CHAR, /* 160 (not used) */
3009 "!", /* 161 - iexcl */
3010 INV_CHAR, /* 162 - cent (n/a) */
3011 INV_CHAR, /* 163 - pound (n/a) */
3012 INV_CHAR, /* 164 - curren (n/a) */
3013 INV_CHAR, /* 165 - yen (n/a) */
3014 "|", /* 166 - brvbar (n/a) */
3015 INV_CHAR, /* 167 - sect (n/a) */
3016 INV_CHAR, /* 168 - uml (n/a) */
3017 "(c)", /* 169 - copy (approx) */
3018 INV_CHAR, /* 170 - ordf (n/a) */
3019 INV_CHAR, /* 171 - laquo (n/a) */
3020 INV_CHAR, /* 172 - not (n/a) */
3021 " ", /* 173 - shy (n/a) */
3022 "(R)", /* 174 - reg (approx) */
3023 INV_CHAR, /* 175 - macr (n/a) */
3024 INV_CHAR, /* 176 - deg (n/a) */
3025 INV_CHAR, /* 177 - plusmn (n/a) */
3026 INV_CHAR, /* 178 - sup2 (n/a) */
3027 INV_CHAR, /* 179 - sup3 (n/a) */
3028 "'", /* 180 - acute (approx) */
3029 INV_CHAR, /* 181 - micro (n/a) */
3030 INV_CHAR, /* 182 - para (n/a) */
3031 INV_CHAR, /* 183 - middot (n/a) */
3032 ",", /* 184 - cedil (approx) */
3033 INV_CHAR, /* 185 - sup1 (n/a) */
3034 INV_CHAR, /* 186 - ordm (n/a) */
3035 INV_CHAR, /* 187 - raquo (n/a) */
3036 "1/4", /* 188 - frac14 (approx) */
3037 "1/2", /* 189 - frac12 (approx) */
3038 "3/4", /* 190 - frac34 (approx) */
3039 "?", /* 191 - iquest (approx) */
3040 "A", /* 192 - Agrave (approx unaccented) */
3041 "A", /* 193 - Aacute (approx unaccented) */
3042 "A", /* 194 - Acirc (approx unaccented) */
3043 "A", /* 195 - Atilde (approx unaccented) */
3044 "A", /* 196 - Auml (approx unaccented) */
3045 "A", /* 197 - Aring (approx unaccented) */
3046 "AE", /* 198 - AElig (approx unaccented) */
3047 "C", /* 199 - Ccedil (approx unaccented) */
3048 "E", /* 200 - Egrave (approx unaccented) */
3049 "E", /* 201 - Eacute (approx unaccented) */
3050 "E", /* 202 - Ecirc (approx unaccented) */
3051 "E", /* 203 - Euml (approx unaccented) */
3052 "I", /* 204 - Igrave (approx unaccented) */
3053 "I", /* 205 - Iacute (approx unaccented) */
3054 "I", /* 206 - Icirc (approx unaccented) */
3055 "I", /* 207 - Iuml (approx unaccented) */
3056 INV_CHAR, /* 208 - ETH (n/a) */
3057 "N", /* 209 - Ntilde (approx unaccented) */
3058 "O", /* 210 - Ograve (approx unaccented) */
3059 "O", /* 211 - Oacute (approx unaccented) */
3060 "O", /* 212 - Ocirc (approx unaccented) */
3061 "O", /* 213 - Otilde (approx unaccented) */
3062 "O", /* 214 - Ouml (approx unaccented) */
3063 "x", /* 215 - times (approx) */
3064 "O", /* 216 - Oslash (approx unaccented) */
3065 "U", /* 217 - Ugrave (approx unaccented) */
3066 "U", /* 218 - Uacute (approx unaccented) */
3067 "U", /* 219 - Ucirc (approx unaccented) */
3068 "U", /* 220 - Uuml (approx unaccented) */
3069 "Y", /* 221 - Yacute (approx unaccented) */
3070 INV_CHAR, /* 222 - THORN (n/a) */
3071 INV_CHAR, /* 223 - szlig (n/a) */
3072 "a", /* 224 - agrave (approx unaccented) */
3073 "a", /* 225 - aacute (approx unaccented) */
3074 "a", /* 226 - acirc (approx unaccented) */
3075 "a", /* 227 - atilde (approx unaccented) */
3076 "a", /* 228 - auml (approx unaccented) */
3077 "a", /* 229 - aring (approx unaccented) */
3078 "ae", /* 230 - aelig (approx) */
3079 "c", /* 231 - ccedil (approx) */
3080 "e", /* 232 - egrave (approx unaccented) */
3081 "e", /* 233 - eacute (approx unaccented) */
3082 "e", /* 234 - ecirc (approx unaccented) */
3083 "e", /* 235 - euml (approx unaccented) */
3084 "i", /* 236 - igrave (approx unaccented) */
3085 "i", /* 237 - iacute (approx unaccented) */
3086 "i", /* 238 - icirc (approx unaccented) */
3087 "i", /* 239 - iuml (approx unaccented) */
3088 INV_CHAR, /* 240 - eth (n/a) */
3089 "n", /* 241 - ntilde (approx unaccented) */
3090 "o", /* 242 - ograve (approx unaccented) */
3091 "o", /* 243 - oacute (approx unaccented) */
3092 "o", /* 244 - ocirc (approx unaccented) */
3093 "o", /* 245 - otilde (approx unaccented) */
3094 "o", /* 246 - ouml (approx unaccented) */
3095 "/" /* 247 - divide (approx) */
3096 "o", /* 248 - oslash (approx unaccented) */
3097 "u", /* 249 - ugrave (approx unaccented) */
3098 "u", /* 250 - uacute (approx unaccented) */
3099 "u", /* 251 - ucirc (approx unaccented) */
3100 "u", /* 252 - uuml (approx unaccented) */
3101 "y", /* 253 - yacute (approx unaccented) */
3102 INV_CHAR, /* 254 - thorn (n/a) */
3103 "y" /* 255 - yuml (approx unaccented) */
3104 };
3105
3106 /*
3107 * Map certain extended characters into our 128-255 range. If we
3108 * don't recognize the character, return the default invalid
3109 * charater value.
3110 */
3111 if (html4_char > 255)
3112 {
3113 switch(html4_char)
3114 {
3115 case 338: html4_char = 140; break;
3116 case 339: html4_char = 156; break;
3117 case 376: html4_char = 159; break;
3118 case 352: html4_char = 154; break;
3119 case 353: html4_char = 138; break;
3120 case 8211: html4_char = 150; break;
3121 case 8212: html4_char = 151; break;
3122 case 8216: html4_char = 145; break;
3123 case 8217: html4_char = 146; break;
3124 case 8218: html4_char = 130; break;
3125 case 8220: html4_char = 147; break;
3126 case 8221: html4_char = 148; break;
3127 case 8222: html4_char = 132; break;
3128 case 8224: html4_char = 134; break;
3129 case 8225: html4_char = 135; break;
3130 case 8240: html4_char = 137; break;
3131 case 8249: html4_char = 139; break;
3132 case 8250: html4_char = 155; break;
3133 case 8482: html4_char = 153; break;
3134
3135 default:
3136 /* unmappable character - return space */
3137 result[0] = (unsigned char)' ';
3138 result[1] = 0;
3139 return;
3140 }
3141 }
3142
3143 /*
3144 * if the character is in the regular ASCII zone, return it
3145 * untranslated
3146 */
3147 if (html4_char < 128)
3148 {
3149 result[0] = (unsigned char)html4_char;
3150 result[1] = '\0';
3151 return;
3152 }
3153
3154 /* look up the character in our table and return the translation */
3155 strcpy(result, xlat_tbl[html4_char - 128]);
3156 }
3157
3158 /*
3159 * Simple versions of os_advise_load_charmap and os_gen_charmap_filename. At
3160 * some point I'll get around to making these do something real. Added by SRG.
3161 */
os_advise_load_charmap(char * id,char * ldesc,char * sysinfo)3162 void os_advise_load_charmap(char *id, char *ldesc, char *sysinfo)
3163 {
3164 }
3165
os_gen_charmap_filename(char * filename,char * internal_id,char * argv0)3166 void os_gen_charmap_filename(char *filename, char *internal_id, char *argv0)
3167 {
3168 filename[0] = '\0';
3169 }
3170
3171 /*
3172 * A very simple "millisecond timer." Because of the relatively-low
3173 * precision of a long and because we really are only precise to a
3174 * second, we store a zero-offset to begin with. Added by SRG.
3175 */
os_get_sys_clock_ms(void)3176 long os_get_sys_clock_ms(void)
3177 {
3178 if (timeZero == 0)
3179 timeZero = time(0);
3180 return ((time(0) - timeZero) * 1000);
3181 }
3182
3183 /*
3184 * Sleep for a given # of ms. Added by SRG.
3185 */
os_sleep_ms(long delay_in_milliseconds)3186 void os_sleep_ms(long delay_in_milliseconds)
3187 {
3188 usleep(delay_in_milliseconds);
3189 }
3190
3191 /*
3192 * An empty implementation of os_set_title. Added by SRG.
3193 */
os_set_title(const char * title)3194 void os_set_title(const char *title)
3195 {
3196 }
3197
3198 /*
3199 * Provide memicmp since it's not a standard libc routine.
3200 */
memicmp(char * s1,char * s2,int len)3201 memicmp(char *s1, char *s2, int len)
3202 {
3203 char *x1, *x2;
3204 int result;
3205 int i;
3206
3207 x1 = malloc(len);
3208 x2 = malloc(len);
3209
3210 if (!x1 || !x2) {
3211 printf("Out of memory!\n");
3212 exit(-1);
3213 }
3214
3215 for (i = 0; i < len; i++) {
3216 if (isupper(s1[i]))
3217 x1[i] = tolower(s1[i]);
3218 else
3219 x1[i] = s1[i];
3220
3221 if (isupper(s2[i]))
3222 x2[i] = tolower(s2[i]);
3223 else
3224 x2[i] = s2[i];
3225 }
3226
3227 result = memcmp(x1, x2, len);
3228 free(x1);
3229 free(x2);
3230 return result;
3231 }
3232
3233 /*
3234 * memcpy - copy bytes (handles overlap, so we can equivalence memmove() to it.
3235 */
3236 void *
our_memcpy(void * dst,const void * src,size_t size)3237 our_memcpy(void *dst, const void *src, size_t size)
3238 {
3239 register char *d;
3240 register const char *s;
3241 register size_t n;
3242
3243 if (size == 0)
3244 return(dst);
3245
3246 s = src;
3247 d = dst;
3248 if (s <= d && s + (size-1) >= d) {
3249 /* Overlap, must copy right-to-left. */
3250 s += size-1;
3251 d += size-1;
3252 for (n = size; n > 0; n--)
3253 *d-- = *s--;
3254 } else
3255 for (n = size; n > 0; n--)
3256 *d++ = *s++;
3257
3258 return(dst);
3259 }
3260
3261 #if !defined(DJGCC_386)
3262 /*
3263 * dbgu.c requires os_strlwr
3264 */
3265 char *
os_strlwr(char * s)3266 os_strlwr(char *s)
3267 {
3268 char *start;
3269 start = s;
3270 while (*s) {
3271 if (isupper(*s))
3272 *s = tolower(*s);
3273
3274 s++;
3275 }
3276 return start;
3277 }
3278 #endif
3279
3280 #ifndef DJGCC_386
3281
3282 /*
3283 * Open file using fopen, stripping of b's from flag string.
3284 */
3285 #ifdef fopen
3286 #undef fopen
3287 #endif
3288
3289 FILE *
our_fopen(char * filename,char * flags)3290 our_fopen(char *filename, char *flags)
3291 {
3292 static char f[80];
3293 int i = 0;
3294
3295 while (*flags) {
3296 if (*flags != 'b')
3297 f[i++] = *flags;
3298
3299 flags++;
3300 }
3301 f[i] = 0;
3302
3303 return fopen(filename, f);
3304 }
3305 #endif /* DJGCC_386 */
3306
3307 /* ------------------------------------------------------------------------ */
3308 /*
3309 * Get file times
3310 */
3311
3312 /*
3313 * get file creation time
3314 */
os_get_file_cre_time(os_file_time_t * t,const char * fname)3315 int os_get_file_cre_time(os_file_time_t *t, const char *fname)
3316 {
3317 struct stat info;
3318
3319 /* get the file information */
3320 if (stat(fname, &info))
3321 return 1;
3322
3323 /* set the creation time in the return structure */
3324 t->t = info.st_ctime;
3325 return 0;
3326 }
3327
3328 /*
3329 * get file modification time
3330 */
os_get_file_mod_time(os_file_time_t * t,const char * fname)3331 int os_get_file_mod_time(os_file_time_t *t, const char *fname)
3332 {
3333 struct stat info;
3334
3335 /* get the file information */
3336 if (stat(fname, &info))
3337 return 1;
3338
3339 /* set the modification time in the return structure */
3340 t->t = info.st_mtime;
3341 return 0;
3342 }
3343
3344 /*
3345 * get file last access time
3346 */
os_get_file_acc_time(os_file_time_t * t,const char * fname)3347 int os_get_file_acc_time(os_file_time_t *t, const char *fname)
3348 {
3349 struct stat info;
3350
3351 /* get the file information */
3352 if (stat(fname, &info))
3353 return 1;
3354
3355 /* set the access time in the return structure */
3356 t->t = info.st_atime;
3357 return 0;
3358 }
3359
3360 /*
3361 * compare two file time structures
3362 */
os_cmp_file_times(const os_file_time_t * a,const os_file_time_t * b)3363 int os_cmp_file_times(const os_file_time_t *a, const os_file_time_t *b)
3364 {
3365 if (a->t < b->t)
3366 return -1;
3367 else if (a->t == b->t)
3368 return 0;
3369 else
3370 return 1;
3371 }
3372
3373 /*
3374 * open a file for reading and writing in text mode; do not truncate
3375 */
osfoprwt(const char * fname,os_filetype_t typ)3376 osfildef *osfoprwt(const char *fname, os_filetype_t typ)
3377 {
3378 osfildef *fp;
3379
3380 /* try opening an existing file in read/write mode */
3381 fp = fopen(fname, "r+");
3382
3383 /* if that failed, create a new file in read/write mode */
3384 if (fp == 0)
3385 fp = fopen(fname, "w+");
3386
3387 /* return the file */
3388 return fp;
3389 }
3390
3391 /*
3392 * open a file for reading and writing in binary mode; do not truncate
3393 */
osfoprwb(const char * fname,os_filetype_t typ)3394 osfildef *osfoprwb(const char *fname, os_filetype_t typ)
3395 {
3396 osfildef *fp;
3397
3398 /* try opening an existing file in read/write mode */
3399 fp = fopen(fname, "r+b");
3400
3401 /* if that failed, create a new file in read/write mode */
3402 if (fp == 0)
3403 fp = fopen(fname, "w+b");
3404
3405 /* return the file */
3406 return fp;
3407 }
3408
3409 /*
3410 * Check for a special filename
3411 */
os_is_special_file(const char * fname)3412 enum os_specfile_t os_is_special_file(const char *fname)
3413 {
3414 /* check for '.' */
3415 if (strcmp(fname, ".") == 0)
3416 return OS_SPECFILE_SELF;
3417
3418 /* check for '..' */
3419 if (strcmp(fname, "..") == 0)
3420 return OS_SPECFILE_PARENT;
3421
3422 /* not a special file */
3423 return OS_SPECFILE_NONE;
3424 }
3425
3426 /*
3427 * Build a full path name given a path and a filename
3428 *
3429 * Copied over from osnoui.c by Suzanne Skinner (tril@igs.net), 2000/Aug/18
3430 */
os_build_full_path(char * fullpathbuf,size_t fullpathbuflen,const char * path,const char * filename)3431 void os_build_full_path(char *fullpathbuf, size_t fullpathbuflen,
3432 const char *path, const char *filename)
3433 {
3434 size_t plen, flen;
3435 int add_sep;
3436
3437 /*
3438 * Note whether we need to add a separator. If the path prefix ends
3439 * in a separator, don't add another; otherwise, add the standard
3440 * system separator character.
3441 *
3442 * Do not add a separator if the path is completely empty, since this
3443 * simply means that we want to use the current directory.
3444 */
3445 plen = strlen(path);
3446 add_sep = (plen != 0
3447 && path[plen-1] != OSPATHCHAR
3448 && strchr(OSPATHALT, path[plen-1]) == 0);
3449
3450 /* copy the path to the full path buffer, limiting to the buffer length */
3451 if (plen > fullpathbuflen - 1)
3452 plen = fullpathbuflen - 1;
3453 memcpy(fullpathbuf, path, plen);
3454
3455 /* add the path separator if necessary (and if there's room) */
3456 if (add_sep && plen + 2 < fullpathbuflen)
3457 fullpathbuf[plen++] = OSPATHCHAR;
3458
3459 /* add the filename after the path, if there's room */
3460 flen = strlen(filename);
3461 if (flen > fullpathbuflen - plen - 1)
3462 flen = fullpathbuflen - plen - 1;
3463 memcpy(fullpathbuf + plen, filename, flen);
3464
3465 /* add a null terminator */
3466 fullpathbuf[plen + flen] = '\0';
3467 }
3468
3469 /*
3470 * Determine if a path is absolute or relative. If the path starts with a
3471 * path separator character, we consider it absolute, otherwise we
3472 * consider it relative.
3473 *
3474 * Note that, on DOS, an absolute path can also follow a drive letter.
3475 * So, if the path contains a letter followed by a colon, we'll consider
3476 * the path to be absolute.
3477 *
3478 * Copied over from osnoui.c by Suzanne Skinner (tril@igs.net),
3479 * 2000/Aug/18
3480 */
os_is_file_absolute(const char * fname)3481 int os_is_file_absolute(const char *fname)
3482 {
3483 /* if the name starts with a path separator, it's absolute */
3484 if (fname[0] == OSPATHCHAR || strchr(OSPATHALT, fname[0]) != 0)
3485 return TRUE;
3486
3487 #ifdef MSDOS
3488 /* on DOS, a file is absolute if it starts with a drive letter */
3489 if (isalpha(fname[0]) && fname[1] == ':')
3490 return TRUE;
3491 #endif /* MSDOS */
3492
3493 /* the path is relative */
3494 return FALSE;
3495 }
3496
3497 /*
3498 * Extract the path from a filename
3499 *
3500 * Copied over from osnoui.c by tril@igs.net, 2000/Aug/18
3501 */
os_get_path_name(char * pathbuf,size_t pathbuflen,const char * fname)3502 void os_get_path_name(char *pathbuf, size_t pathbuflen, const char *fname)
3503 {
3504 const char *lastsep;
3505 const char *p;
3506 size_t len;
3507
3508 /* find the last separator in the filename */
3509 for (p = fname, lastsep = fname ; *p != '\0' ; ++p)
3510 {
3511 /*
3512 * if it's a path separator character, remember it as the last one
3513 * we've found so far
3514 */
3515 if (*p == OSPATHCHAR || strchr(OSPATHALT, *p) != 0)
3516 lastsep = p;
3517 }
3518
3519 /* get the length of the prefix, not including the separator */
3520 len = lastsep - fname;
3521
3522 /* make sure it fits in our buffer (with a null terminator) */
3523 if (len > pathbuflen - 1)
3524 len = pathbuflen - 1;
3525
3526 /* copy it and null-terminate it */
3527 memcpy(pathbuf, fname, len);
3528 pathbuf[len] = '\0';
3529 }
3530
3531 /*
3532 * Get the name of the character mapping file.
3533 *
3534 * NOTE - we should use some means to find the actual character set that
3535 * the user's terminal is using and return that; maybe some environment
3536 * variable or some curses call will tell us what we need to know. For
3537 * now, we'll just return "asc7dflt", which is the 7-bit ASCII character
3538 * mapping; this should be safe for any ASCII terminal, although it won't
3539 * allow us to display accented characters that the user's terminal might
3540 * actually be capable of displaying if we just knew the actual character
3541 * set it was using.
3542 */
os_get_charmap(char * mapname,int charmap_id)3543 void os_get_charmap(char *mapname, int charmap_id)
3544 {
3545 strcpy(mapname, "asc7dflt");
3546 }
3547
3548 /*
3549 * Reallocate storage at a different size
3550 */
osrealloc(void * buf,size_t len)3551 void *osrealloc(void *buf, size_t len)
3552 {
3553 return realloc(buf, len);
3554 }
3555
3556 /* Full ansi color is not yet implemented in Unix, but we do handle bold text
3557 * and status-line attributes.
3558 */
ossgetcolor(int fg,int bg,int attrs,int screen_color)3559 int ossgetcolor(int fg, int bg, int attrs, int screen_color)
3560 {
3561 #ifndef USE_STDIO
3562
3563 /* use the screen color if the background is transparent */
3564 if (bg == OSGEN_COLOR_TRANSPARENT)
3565 bg = screen_color;
3566
3567 /* Check for the special statusline color scheme */
3568 if (fg == OSGEN_COLOR_STATUSLINE && bg == OSGEN_COLOR_STATUSBG)
3569 return sdesc_color;
3570 /* check for bold text */
3571 else if ((attrs & OS_ATTR_HILITE) != 0)
3572 return text_bold_color;
3573
3574 #endif
3575
3576 return cNORMAL;
3577 }
3578
3579 extern int os_f_plain;
3580
oss_get_sysinfo(int code,void * param,long * result)3581 int oss_get_sysinfo(int code, void *param, long *result)
3582 {
3583 switch (code) {
3584
3585 case SYSINFO_TEXT_COLORS:
3586 *result = SYSINFO_TXC_PARAM;
3587 return TRUE;
3588
3589 case SYSINFO_TEXT_HILITE:
3590 #ifdef USE_STDIO
3591 *result = 0;
3592 #else
3593 *result = (os_f_plain ? 0 : 1);
3594 #endif
3595 return TRUE;
3596 }
3597
3598 return FALSE;
3599 }
3600