[metapost] MPlib: detect bye/end

Nicola nvitacolonna at gmail.com
Thu Dec 15 15:23:42 CET 2016


On 15/12/2016 12:48, luigi scarso wrote:
> On Fri, Dec 9, 2016 at 11:50 AM, Nicola <nvitacolonna at gmail.com> 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







More information about the metapost mailing list