Re: MPlib: detect bye/end
Nicola <[email protected]>
| Newsgroups | gmane.comp.tex.metapost |
|---|---|
| Message-ID | <[email protected]> |
On 15/12/2016 12:48, luigi scarso wrote: > On Fri, Dec 9, 2016 at 11:50 AM, Nicola <[email protected]> wrote: >> Hello, >> when running a non-interactive MP instance, how can I detect that the last >> executed command was `bye`, `end` or something that causes MetaPost to quit? >> >> For instance, after >> >> char *line = "bye." >> int history = mp_execute(mp, line, strlen(line)); >> >> mp_rundata(mp) returns non-zero size data (it returns zero-size data if I >> execute another command). >> >> Nicola >> >> -- >> http://tug.org/metapost/ > > The effect of scanning an "end" are the following calls: > > mp_final_cleanup (mp); > > > │ > mp_close_files_and_terminate (mp); > > The last one ends with > mp->finished = true; > > As first step mp_execute resets the streams, and if mp->finished = > true then returns > > > @ @c > int mp_execute (MP mp, char *s, size_t l) { > mp_reset_stream (&(mp->run_data.term_out)); > mp_reset_stream (&(mp->run_data.log_out)); > mp_reset_stream (&(mp->run_data.error_out)); > mp_reset_stream (&(mp->run_data.ship_out)); > if (mp->finished) { > return mp->history; > >>From now whatever string is put into execute, the streams data are > NULL and nothing is executed. > We can execute a test string like "tracingall;tracingnone;": before > and "end" this should put something into one stream, > and if all the streams data are still NULL then we have already > executed an "end" . > Of course to execute a string we need a valid mp state . > > static char *tracingall = > "tracingonline:=1; showstopping:=1;" > "tracingcommands:=3; tracingtitles:=1; tracingequations:=1;" > "tracingcapsules:=1; tracingspecs:=2; tracingchoices:=1; tracinglostchars:=1;" > "tracingstats:=1; tracingoutput:=1; tracingmacros:=1; tracingrestores:=1;"; > static int strlen_tracingall=240; > > static char *tracingnone = > "tracingcommands:=0; tracingtitles:=0; tracingequations:=0;" > "tracingcapsules:=0; tracingspecs:=0; tracingchoices:=0; tracinglostchars:=0;" > "tracingstats:=0; tracingoutput:=0; tracingmacros:=0; tracingrestores:=0;"; > static int strlen_tracingnone=206; > > int check_after_end_mp(MP mp) > { > mp_run_data *cmd_result ; > int ret; > ret = -1 ; > if (mp==NULL) > return ret; > ret = 0; > mp_execute(mp, tracingall, strlen_tracingall); > cmd_result = mp_rundata(mp); > if ( cmd_result->term_out.data == NULL && > cmd_result->error_out.data == NULL && > cmd_result->log_out.data == NULL && > cmd_result->ship_out.data == NULL ) > ret = 1; > mp_execute(mp, tracingnone, strlen_tracingnone); > return ret ; > } > > MetaPost rev. 2107 has a new function mp_finished that returns > mp->finished as boolean, > so one can avoid the two calls of mp_execute > > int check_after_end_mp(MP mp) > { > mp_run_data *cmd_result ; > int ret; > ret = -1 ; > if (mp==NULL) > return ret; > ret = 0; > cmd_result = mp_rundata(mp); > if ( mp_finished(mp) && > cmd_result->term_out.data == NULL && > cmd_result->error_out.data == NULL && > cmd_result->log_out.data == NULL && > cmd_result->ship_out.data == NULL ) > ret = 1; > return ret ; > } Thanks for the thorough explanation. Is it really necessary to check all the streams? What I'm doing now is somewhat simpler: mp_execute(imp, "\\", 1); // Send a token that expands to nothing mp_run_data *cmd_result = mp_rundata(imp); if (!cmd_result || !cmd_result->term_out.size) { return 0; // Quit } This seems to work, but I guess that it is not robust enough. In which case would it fail to recognize that it's time to quit (please note that I'm using this in a REPL)? Nicola -- http://tug.org/metapost/