And rename prd_exit to prd_terminate (the idea is the host will
terminate the VM). This makes it possible for the debugger to pause the
VM before any code, even a builtin function, is executed. Breaks the
debugger source window, but only because it's not updating on file
change (I think).
I decided I want events for VM enter/exit but enter needs to somehow
pass the function which will be executed (even if a builtin). A generic
void * param seemed the best idea, which meant the error string could be
passed via the param instead of a "global" string in the progs struct.
After a lot of thought, I have come to the conclusion that the weird
crash the other day was caused by a race while the command ring buffer
had just been emptied: the command submission code opened up space for
writing, threads switched, and command processing saw the available data
and pounced on it before the submit code could write valid data. Thus
include the while header in the lock, and move the loop-end release
outside the lock. It may be a little confusing, but it seems to work.
They take a pointer to a free-list used for hashlinks so the hashlink
pools can be per-thread. However, hash tables that are not updated are
always thread-safe, so this affects only updates. progs_t has been set
up such that it is easy for multiple progs within one thread can share
hashlinks.
That... worked nicely. Program exit needs some work because exiting
terminates the thread and the debugger has no clue about it, but I was
able to single-step through gcd.r quite nicely.
This will allow for easy expansion of editor functionality without
messing with the editor itself. In particularly, an editor normally
doesn't need to know anything about debugger hot keys.
progs_t is very much most definitely NOT thread-safe (ie, two threads
using the same progs_t). It was actually rather funny when I figured out
what was going on to cause qwaq's universe to explode.
I got really weird error (invalid panel passed to top_panel) when there
was no such call, so I guess there was some memory corruption.
formatLine is the only suspect, but when I put in the guard, the error
wasn't reproduced (just scrolling through qwaq's makefile in a big
window).
With this, windows can be resized using any of the corners or the three
sides other than top (top side is move-only, otherwise moving a window
without resizing would be impossible).
It's a fairly high-level wrapper for TextBuffer in that it implements
file ops (load/save), searching, navigation, and formatting (simple
line-oriented with tab stops (currently at 4 spaces)).
While the key escape sequences are xterm-specific, they are only the
default and preliminary provision has been made for overriding them.
However, no override mechanism has been implemented beyond using dynamic
table lookup.
I'd left qwaq-curses running overnight and found it locked up: both
threads were looping because pthread_cond_timedwait was returning
EINVAL. Thus bail if anything other than 0 is returned, and try to
ensure tv_nsec is in the range 0..999999999
This doesn't fix the problem of lost events: that seems to be inside
ncurses. I've done some investigations, and it seems xterm sends
separate events for motion and pre/release (which have current coords),
in both 1003 and 1006 modes. No idea what ncurses is doing (does it even
handle 1003 properly?), and it requires the use of xterm-1006 for it to
use 1006 mode (which is nice in that it disambiguates button releases
and allows for huge terminals (not that I would use such normally)).
Guess I've got some side-work cut out for me :P
While writing the code I suspected this would be necessary, but it's
nice to know. Now the window seems to be correctly fetched, but
get_event locks up.
I realized that with dynamic thread creation the arrays resizing could
cause them to move around in memory which would be bad for anything
holding a pointer to the data, and even using indices wouldn't help that
much as the array would need to be mutex protected.
If none are specified, default to qwaq-app.dat (for now, anyway). For
each progs file, an optional args set can be specified in the same order
(separated by --). Missing sets default to empty, excess sets are
ignored.
The sets are separated by --, and the first set is passed to
getopt_long which currently recognizes only --qargs and non-options. The
--qargs options parses out a set (to -- or end of args) that is passed
to the qargs sub-system for standard qf command line parsing. Set 0 is
for the main qwaq application. Any additional sets (excluding --qargs)
will be used to spawn additional threads when that's working.
Other than the stray panel_free, that was surprisingly easy. However, do
need to check that the window can be moved otherwise window pos and
panel pos will get out of sync.
I think I've finally figured out what I want the core hierarchy to be.
Right now, it's just the two classes: View and Window (derived from
View). Window has a Group, and Group is just a collection of Views that
it manages. QwaqApplication is just an object but like a Window, it has
a Group of views.
View
Window has a Group
Group contains Views
QwaqApplication has a group
More work needs to be done on drawing and event handling, but things are
working again.
It doesn't work right now because View unconditionally sends refresh to
its textContext, but textContext can be a draw buffer which does not
respond to refresh. Still, these changes (notably the assignment chain
in qwaq-group.r really pushed qfcc).
This returns the character (as an int) at the index. Equivalent to
string[index], but qc code doesn't have char-level access and not having
it means that strings can internally change to wchar without too much
fuss (maybe).
refresh won't be in the drawing buffer protocol, and the move commands
need to be offset by the view's position in its window, but it works as
intended.
libr supplies an __obj_forward definition that links to a builtin, but
as it is the only def in its object file, it is readily replaceable by
an alternative Ruamoko implementation.
The builtin version currently simply errors out (rather facetiously),
but only as a stub to allow progs to load.
The conditional selector performance seems to work nicely, but I've
found a mistake with View.window (partly, realizing why my old lib (and
probably TV in the first place) had separate textContext and buffers
between views and groups).
Doesn't have timestamps at this stage, but otherwise it reflects the
event system I had in my old text UI which was heavily based on
TurboVision. TV is pretty good (after looking at things a bit closer I
found it wasn't as deep as I thought), and better yet, Borland released
it to the public domain 23 years ago! (wish I'd known that).
Anyway, this commit gets something happening on the screen, even though
the current hierarchy is still a mess.
This is horrible, doesn't work, isn't really the direction I want to go
(that became apparent while implementing Screen's handleEvent) and
crashes anyway (Array and not-id...)
*sigh*
Still, this does have some good stuff in it, and it pushed qfcc along
some more.
If the last command in the buffer had no parameters, its length would be
only 2 and thus processing would stop before reading the command from
the buffer.
This fixes the dependency issues between qwaq and ruamoko. qwaq is
actually older than ruamoko. That little language feature test has come
a long way.
However, I'm considering moving to non-recursive make, but...
Other than its blocking of access to certain files, it really wasn't
that useful compared to the functions in qfs, and pointless with access
to qfs anyway.
This far better reflects the actual meaning. It is very likely that
ty_none is a holdover from long before there was full type encoding and
it meant that the union in qfcc's type_t had no data. This is still
true for basic types, but only if not a function, field or pointer type.
If the type was function, field or pointer, it was not true, so it was
misnamed pretty much from the start.
Only as scalars, I still need to think about what to do for vectors and
quaternions due to param size issues. Also, doubles are not yet
guaranteed to be correctly aligned.
Empty structs are now (correctly) invalid. The hack of using an empty
struct to represent a handle returned from a builtin has been unnecessary
since opaque structs were implemented: now a pointer to an opaque struct
can be used. This is mostly safe as handles are aways negative and thus
attempting to dereference such a pointer should result in a VM error. It
will be even safer once const is implemented and the pointers can be made
constant (eg, typedef struct handle * const handle;)
All internal structs now have "proper" names, and fit the naming convention
(eg, obj_module (like objective-c's types, but obj instead of objc). Some
redundant types got removed (holdovers from before proper struct tag
handling).
Also, it has proven to be unnecessary to build internal classes, so
make_class and make_class_struct are gone, too.
As class objects don't have retain counts (they're usually static, even!!),
allowing the instance implementations of retain, release, and autorelease
attempt to modify the non-existant retainCount would be a recipe for severe
headaches. We also don't want the retainCount returning "random" values.
Going by "standard" Objective-C, retainCount really doesn't belong in
Object itself. The way GNUStep does it is to stash retainCount in memory
just below the object by allocating extra bytes for the count and returning
a pointer just beyond those extra bytes. Now Ruamoko does the same. This
fixes the inconsistencies in structure layouts for Protocol and class
structs between qfcc generated (internal) structs and user visible structs.
F6 is fantastic, until you hit it by mistake after dieing when you meant
to hit F9 (I've done that way too often). quick.sav is still the last file
written via F6 (so F9 is unaffected), but now the previous quick.sav
becomes quick1.sav. Up to 5 (currently) backups will be kept: quick1 is
the newest, quick5 the oldest. A menu for accessing the backups has been
added as a sub-menu of the load menu.
The api hides all the gory details of message buffer setup and usage
(particularly the differences between writing and reading). Most
importantly, the api provides a safe way to read and write binary data
(always little endian).
Despair has things locked down such that running qfcc during a build fails
due to lack of read access to /usr/local/lib. This is actually a good
thing as accidentally hitting old includes/libs (when a file gets deleted
in the tree) hides bugs. Thus, --no-default-paths to turn off default
search paths.
The special token __INFINITY__, like __FILE__ and friends, will expand to
a floating-point expression containing a value the C compiler considers
infinite. Obviously, this assumes that the system has relatively modern
float hardware -- but if it doesn't, having Ruamoko be able to represent
float infinity is the least of your problems. :)