Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document the differences between GlkAPI and the C API #13

Closed
curiousdannii opened this issue Oct 22, 2016 · 16 comments
Closed

Document the differences between GlkAPI and the C API #13

curiousdannii opened this issue Oct 22, 2016 · 16 comments

Comments

@curiousdannii
Copy link
Contributor

curiousdannii commented Oct 22, 2016

The spec says

void glk_request_line_event(winid_t win, char *buf, glui32 maxlen, glui32 initlen);

But glkapi.js has

function glk_request_line_event(win, buf, initlen)

(glk_request_line_event_uni is also missing maxlen.)

Where is maxlen? How are we meant to call it?

This is how I'm currently trying: https://github.com/curiousdannii/ifvms.js/blob/e8fd78e377/src/zvm/io.js#L314

@erkyrath
Copy link
Owner

The C API and the JS API are not arg-for-arg identical. Where the C API has an array and length, it is generally translated into a JS array with the length already set.

In this case, buf should be a JS array of length maxlen. If initlen is nonzero, the first initlen entries should be set to the character codes of the preloaded string. On return, buf will contain the line input. (It will still have length maxlen; the number of characters actually there is returned in the event structure.)

@curiousdannii
Copy link
Contributor Author

Hmm, I don't think I like that. If anyone was to make new a JS implementation of Glk they would probably more closely follow the spec (I would). At the very least these changes should be more clearly documented.

Can buf be an array of undefineds? Can it be a typed array (probably a Uint32Array)?

The current result is very strange: the text box is limited to 1 character, but it stays active when you press enter, and more presses of enter result in multiple console logs saying "Input event had wrong generation number: got 1, currently at 2". But maybe they will be fixed when I call it correctly.

@erkyrath
Copy link
Owner

When I set this up, typed arrays weren't universally available. I've never gotten around to converting to them. However, I think everything will work fine if you use them.

The contents of the buffer on entry don't matter if initlen is zero. You could copy the Z-machine memory array in anyway. (That would cover the cases of initlen being zero or nonzero.)

The text box entry limit should be buf.length.

Getting the generation number correct is important, but not specific to this call. It works the same for any kind of input event.

@curiousdannii
Copy link
Contributor Author

curiousdannii commented Oct 23, 2016

Thanks for the explanations.

Good point about copying the Z-Machine memory array in case initlen is nonzero - that will probably be simpler (though I will need to convert ZSCII to unicode first...)

The generation number was fixed when I started calling glk_select before glk.update()

@erkyrath
Copy link
Owner

If you use glk_request_line_event, all array values (in and out) should be 0..255. If you use glk_request_line_event_uni, they may be any Unicode code value. Not sure which you want to go with.

@curiousdannii curiousdannii changed the title GlkAPI does not have correct arguments for glk_request_line_event() Document the differences between GlkAPI and the C API Oct 23, 2016
@curiousdannii
Copy link
Contributor Author

Hi @erkyrath, how are we to use glk_fileref_create_by_prompt()? It looks like it sends control out through GlkOte, and then gli_fileref_create_by_prompt_callback() will call VM.resume() again. How is our resume function to distinguish between calls from glk_select and glk_fileref_create_by_prompt? And once control is passed to resume(), how do we access the fref object?

@erkyrath
Copy link
Owner

For glk_fileref_create_by_prompt, the update goes out with a specialinput key, and the response comes back with a specialresponse key. This is described in the docs file.

@curiousdannii
Copy link
Contributor Author

curiousdannii commented Nov 25, 2016

Are you suggesting that I try to handle the event manually before gli_fileref_create_by_prompt_callback runs?

Currently I've just been using glkapi.js. gli_fileref_create_by_prompt_callback creates the fref and passes it to GiDispa.prepare_resume() but not to VM.resume(). In order to use glk_fileref_create_by_prompt do I really need to start using GiDispa too?

[Edit] Okay, from looking at GiDispa, for prepare_resume() to work I would need to set blocked_selector, but neither it or set_blocked_selector are exposed. But even if I got that working, prepare_resume would only return an id to the VM, not the object which glk_stream_open_file etc need.

Unless I've missed something I can't see any way to get this working as is, glk_fileref_create_by_prompt is just not designed to work outside a dispatch system. To get this to work glk_fileref_create_by_prompt would need to be extended and be passed a RefStruct like glk_select (or an additional function should be created, perhaps named glk_fileref_create_by_prompt_boxed. Or gli_fileref_create_by_prompt_boxed if gli indicates that it is outside the glk api). gli_fileref_create_by_prompt_callback will need to be extended to set the RefStruct details. Would you consider a pull request doing this?

@curiousdannii
Copy link
Contributor Author

So the solution I worked out ended up being much simpler: if glk_select() is called after glk_fileref_create_by_prompt() then gli_fileref_create_by_prompt_callback() will return fref via the RefStruct. I added a fake event so the whole system can go through my normal resume().

curiousdannii@698150d

I haven't made a pull request, but I can if you like.

@erkyrath
Copy link
Owner

I have not had a chance to look over this in detail. The brief answer is "the entire glkapi library was meant to be used with the dispatch layer". I envisioned other VMs using glkote alone. (This is how I set up inkjs, for example.)

But I see that glkapi does some things that are generally useful. (Accumulating window content data is the biggie.) So I will look at that use case in when I tackle updating the remglk/glkote pair, per erkyrath/remglk#6 .

However, arrays will still be handled as single arguments. :) That follows from the way array arguments are handled in the dispatch layer.

The dispatch layer also fixes the argument representation for fileref_create_by_prompt. The general solution has to cope with that.

@curiousdannii
Copy link
Contributor Author

The brief answer is "the entire glkapi library was meant to be used with the dispatch layer". I envisioned other VMs using glkote alone. (This is how I set up inkjs, for example.)

Yeah straight Glkote would probably work really well for many applications. I thought I'd try glkapi because it's an API I already know, and it just matches the Z-Machine so closely (by design of course). But even thought it may not have been planned to be used in this way, it still worked really well. It's very well implemented!

I'll be keeping watch over this repository, and I'm happy to adjust ZVM to any changes you make.

@curiousdannii
Copy link
Contributor Author

curiousdannii commented Nov 28, 2016

I've started documenting these at https://github.com/erkyrath/glkote/wiki/Differences-between-GlkApi-and-the-C-Glk-API

If I find any more I'll just add them there rather than posting here, unless I can't figure out how to get them to work.

@curiousdannii
Copy link
Contributor Author

curiousdannii commented Dec 21, 2016

glk_stream_open_file() throws an error if in read mode and the file doesn't exist, whereas the spec says: "If the filemode requires the file to exist, but the file does not exist, glk_stream_open_file() returns NULL."

Is this intentional (in which case I'll add it to the wiki page) or should it be considered a bug?

@erkyrath
Copy link
Owner

That's a good question. My C libraries treat this as an error, or a "strict warning" (which in practice is an error although it doesn't kill the game).

So by the spec all the implementations are wrong. But they've all been wrong since day one, and no game which relied on the spec has ever worked. So the sensible course is to say that it's a mistake in the spec.

@curiousdannii
Copy link
Contributor Author

curiousdannii commented Dec 24, 2016

Ah. When we ran into this problem with Counterfeit Monkey you said it was safe, so I've just kept on doing it. It's very easy to work around so not a problem.

Edit: But even the Inform 7 template function RESTORE_THE_GAME_R doesn't check for existence before trying to open the stream...

@curiousdannii
Copy link
Contributor Author

curiousdannii commented Nov 26, 2017

I think this can be closed now. If I find anything else I'll add it to the wiki page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants