/
console.txt
206 lines (160 loc) · 9.35 KB
/
console.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
vbSlacker console:
Older versions of BASIC were text-based ("Console apps"). Some later console
versions could do graphics through the SCREEN command, but nothing too fancy.
Visual BASIC removed the ability to make console applications. While a
"Hello, World" program under Visual BASIC was still simpler than its Visual
C++ equivalent, you just can't beat the one-line program under Qbasic.
If nothing else, the ability to write quick, text-based apps to perform
simple tasks was sorely missed in Visual BASIC. However, it was not an
unheard of concept, since the short-lived Visual Basic for DOS had support
for both event-driven "windowed" apps, and text-based console apps. To be
fair, VBDOS's window system was all text-based, too, but the API is what's
important. It merely let you program for either API, and threw runtime
errors when you tried to mix API calls. There's no reason this concept
couldn't be applied to more modern, graphical operating environments.
vbSlacker fills the gap, by allowing programmers to write not only
GUI-windowing apps, like Visual BASIC, but also "console" apps, like
QuickBASIC.
Or both, at the same time, if you want to have a console window along with
GUI widgets.
Keep in mind that GUI controls, such as text boxes, and the PRINT method
available for BASIC forms are under a completely different subsystem than
everything you read here. You may still read input in your text box, and
PRINT to a form with a disabled console.
When building a vbSlacker project, one option presented to the developer is
to "Disable console", which has two distinct effects. First, a text window
won't be created when the program runs, so GUI apps look "pure." Secondly,
any calls to console functions (like PRINT and INPUT$) throw the runtime error
ERR_CANNOT_CONTINUE (error #17)
If you don't disable the console, a couple of things can happen. At program
startup, BASIClib determines the best way to handle console output. If output
IS being redirected (through a shell's ">" pipe operator, for instance),
BASIClib will write plain text to stdout. APIs like VIEW PRINT do nothing.
If output is NOT being redirected, BASIClib determines if we are at a virtual
console (full-screen text mode). If so, direct video writes (or the closest
approximation) are done for speed. Thus far, this is equivalent to how
QuickBASIC 4.5 handles console routines.
An extra feature is added, however. For output destined for a terminal (that
isn't a local virtual console; this may be anything from an xterm to a serial
connection to a telnet session) the ncurses library (or whatever equivalent
is available on a given platform) is used.
If the console has not been disabled, but we are not at a virtual
terminal, and ncurses can't handle the job, the console is forced into the
stdin/stdout mode used for redirected output. This will work on any
terminal type, but isn't particularly flashy or fast.
All graphical APIs throw errors unless in a graphics mode. Other APIs may
throw, depending on the capabilities of a given console. Disabling the console
makes just about every console API function throw an error.
If the console needs to be switched to a graphics mode (via the SCREEN
command), SVGAlib (or whatever equivalent is available on a given platform) is
used. If graphics are not a possibility, ERR_CANNOT_CONTINUE is thrown.
Therefore the APIs would need to check all sorts of conditions for each call:
a) see if they are being redirected,
b) see if they are at a virtual console,
c) see if they are an ncurses-supported terminal,
d) see if they are in graphics mode,
and e) see if console APIs have been disabled.
Rather than have the overhead of all these checks every call, not to mention
the bulky code, BASIClib selects a console "driver" (effectively, a bunch
of pointers to the correct set of functions) at startup. When a mode switch
occurs (due to a SCREEN command or whatnot), those pointers are modified to
point to a different set of functions, and the new driver is initialized. So,
in effect, we overload APIs like PRINT with five different versions: direct,
graphical, redirected (stdout), ncurses, and noconsole (for when console
support is disabled). The overhead for choosing the correct version each time
is eliminated by using function pointers.
If interfacing C code calls printf() (or any stdio routines), be sure to use
INITFLAG_DISABLE_CONSOLE in your call to __initBasicLib(), (that is, if your
program starts in a BASIC mainline, be sure to pass the "Disable console"
option to the compiler) ... Your best bet is to forego stdio with BASIClib,
and call the console API, but rest assured, that the ncurses, direct video,
and graphical console drivers don't mix well with stdio. Remember that you can
always encourage BASIClib to select the redirected console driver by...er,
redirecting stdout on the command line. In that case, you can more safely use
printf(), so long as printf() is thread safe on your system. (The
RedirectedConsole driver, which uses printf(), wraps the call with
ThreadLocks on systems where it is not safe, so even here, you're better
off to use the console API instead of printf()...)
Want to know what console driver is in use? Do this:
char buffer[20];
__getConsoleHandlerName(STATEARGS, buffer, sizeof (buffer));
...then (buffer) will contain the name of the console driver that is currently
being used. Current possibilities are:
"DirectConsole" (direct video writes, text)
"RedirectedConsole" (console i/o goes to stdin and stdout, no frills)
"CursesConsole" (console i/o is handled below BASIClib by ncurses)
"GraphicsConsole" (Not implemented yet; graphical console.) !!!
"NoConsole" (console and console API have been disabled)
Console drivers are selected in this order:
1. If console support is disabled, use NoConsole driver.
2. Failing that, if the process has its stdin or stdout redirected, use the
RedirectedConsole driver.
3. Failing that, if the process is running on a console for which we can do
direct video writes of some sort (a "virtual console" under Linux, for
example), use DirectConsole driver.
4. Failing that, if a curses library of some sort can be initialized, use
the CursesConsole driver.
5. Failing that, force BASIClib to use the RedirectedConsole driver. While it
does not have all the functionality hoped for in a BASIC program, it is
the most compatible option at this point.
Note that the GraphicsConsole driver is never selected at BASIClib startup.
That driver is only switched in dynamically during program execution by the
SCREEN command.
USING THE VBSLACKER CONSOLE:
To output to the console, you need not concern yourself with which driver
is in use. vbSlacker presents a flexible, and abstract API.
First, from BASIC, the simplest way to do console output is the standard old
PRINT command. vbSlacker supports it in all its wierd configurations,
including the ";" operator to print several types from one command, and the
slightly different ";" operator at the end of the command to signify that no
newline is desired. See special_cases.txt for a discussion of how this is all
handled. The only time that BASIC's PRINT command won't work is when the
console is disabled, otherwise, your text will make it to its destination
in some form or another.
Other BASIC functions, like LOCATE, COLOR, VIEW PRINT, etc. can be used, too.
Most console drivers will just ignore the call if it can't handle it, but
runtime errors are thrown if not supported call would in all likelihood
cripple program execution. So with the RedirectedConsole driver, a program that
uses a lot of LOCATEs is probably going to look like crap, but still function
correctly.
From C, the console is used through one of several API calls, depending on
your needs. First, there is __printAsciz(), to print null-terminated C
strings.
#include "BasicLib.h"
void hello(void)
{
__printAsciz("Hello");
} /* hello */
Next, for printing BASIC strings, you may use the BASIC API itself:
#include "BasicLib.h"
void helloName(PBasicString name)
{
__printAsciz("Hello there, ");
_vbpS_print(name);
} /* helloThere */
If you just want a piece of a string, or want to print data that isn't
null-terminated (and isn't stored in a BASIC string structure), you may
call what __printAsciz() and _vbpS_print() call at their lowest level:
__printNChars() ...
char name[30];
strcpy(name, "Ryan C. Gordon");
__printNChars(name, 4);
...would print "Ryan" to the console, without advancing the cursor to
the next line.
The cursor only advances to a new line in the following ways:
- Through the use of the __printNewLine() function (This is generated by
the parser as needed, but can be called directly from C.)
- Through any print function when the cursor hits the end of the line. The
cursor will "wrap" to the next line.
- Through the use of the LOCATE API.
- Through attempting to print a newline sequence. If __printNChars() hits
either an individual '\n' or '\r', or "\r\n", it'll advance the cursor to
the next line. This is how QuickBASIC does it, with a little added support
for unix and mac endlines.
On a higher level, any known BASIC type may be printed by calling
vbpV_print(), which takes a Variant argument, converts it to a string,
calls vbpS_print(), which calls __printNChars()...whew!
The console drivers only implements __printNChars() out of all this
PRINT rigamarole. The rest is implemented abstractly in ConsoleFunctions.c ...
!!! More to come.
/* end of console.txt ... */