[Date Prev] [Date Next] [Thread Prev] [Thread Next] Date Index Thread Index Search archive:
Date:Mon Mar 21 00:33:48 2002 
Subject:Re: "run_unix_program" + "pipein" 
From:Aaron Sloman See text for reply address 
Volume-ID:1020321.01 

[To reply replace "Aaron.Sloman.XX" with "A.Sloman"]

clintwks@yahoo.com writes:

> Date: Fri, 15 Mar 2002 15:11:51 +0000 (UTC)
>
> I am trying to fork a unix shell command from which I
> can use its output to parse with in Poplog. Here is an
> example from "run_unix_program" that I am trying to
> make work.
>
> /* Run the find command to give me each line of output
> as if I were using readline() from a terminal.
> so that I could parse finds output accordingly */
>
>

I'll go through your definition pointing out things that need to be
changed, the at the end give an example that works.

> define run_foo.sh();

You can't use a dot in a procedure name. Try run_foo_sh

>     vars indev, outdev, errdev, status, pid;

Better to use "lvars" for local variables nowadays (though "vars"
will work here). See

    http://www.cs.bham.ac.uk/research/poplog/teach/vars_and_lvars
    (included as a local teach file in the Bham distribution).

>     run_unix_program('find', ['/home/mine -type f -name "*.o"'],
                                false, true, 1, false)

Note that the help file for run_unix_program describes the second
argument thus:
    arglist is a list of argument strings to pass to the program
               ^^^^^^^^^^^^^^^^^^^^^^^^^^

So instead of
    ['/home/mine -type f -name "*.o"']

you would need

    ['/home/mine' '-type' 'f' '-name' '*.o']

Note that if you were typing to a unix shell you would use
    "*.o"
to stop the final argument being replaced by a list of files before
the find command is run. Inside pop-11 putting the argument in a
string is enough '*.o', since this is not given to a shell.

This is how your procedure picks up the outputs of run_unix_program

>         -> (indev, outdev, errdev, status, pid);

This will work but using all those variables is wasteful.

You are not going to supply inputs to the command, nor will there be
an errdev device, since you gave 1 as the fourth argument. You also
don't want the 'status' result because your fifth argument (wait) is
failse. So you don't need the first, third and fourth results (and
maybe also not the last one).

So this bit of your procedure could be
     run_unix_program('find', ['/home/mine' '-type' 'f' '-name' '*.o'],
                                false, true, 1, false)
         -> (_, outdev, _, _, pid);


>
>     define send(input, dev);
>         lvars input, dev;
>         syswrite(dev, 1, input, length(input));
>         sysflush(dev)
>     enddefine;

You don't need that procedure.

The next procedure collects all the outputs of the find command and
builds them into a string:

>     define rec(dev) -> output;
>         lvars dev, output, n;
>         lconstant buff = inits(127);


You are assuming that there will be no line of output more than 127
characters long. Make sure that is long enough.

>         '' -> output;
>         while sys_input_waiting(dev) do
>             sysread(dev, 1, buff, 127) -> n;
>             output <> substring(1, n, buff) -> output
>         endwhile
>     enddefine;

sys_input_waiting is not appropriate here I believe since your program
is not interacting through pipes with an interactive program like a
shell.

Instead you should repeatedly call sysread, in a loop.
If its result is ever 0 then that means there is nothing left in the
input buffer and you can terminate the loop.

So that gives:

>         '' -> output;
>         repeat
>             sysread(dev, 1, buff, 127) -> n;
>               quitif( n == 0 );
>             output <> substring(1, n, buff) -> output
>         endrepeat;
>     enddefine;
 
> /* I need to get the output from find as a string I
> can process, do I use the following command?  Then
> what*/
>     pr(rec(outdev));

That will simply print the string. If you want to do something else with
it, makey your procedure have a  local output variable, e.g. outstring

then do at the end

    rec(outdev) -> outstring;

> enddefine
>


So here are two version of your program, with a pair of strings as
inputs, representing a directory and a pattern.

The first one concat_files returns a string containing all the
names of the files in the directory <dir> whose names match the pattern
<patt>. The output string will have the names separated by newlines.

The second version list_files returns a list of the file names (i.e. a
list of strings).

VERSION 1: concat_files

/*
;;; tests for version 1
pr(concat_files('/usr/bin/', 'x*'));

pr(concat_files('/home/mine', '*.o'));

*/

define concat_files(dir, patt) -> outstring;

    lvars outdev ;

    run_unix_program(
		'find',
			[^dir '-type' 'f' '-name' ^patt],
				false, true, 1, false)

                    -> (_, outdev, _, _, _);

    lconstant buff = inits(127);
    '' -> outstring;
    repeat;
    	lvars  n;
		;;; try to read a string of length > 0
        sysread(outdev, 1, buff, 127) -> n;

        ;;; quit if no more characters read
    	quitif( n == 0 );

		;;; concatenate to the end of the output string
        outstring <> substring(1, n, buff) -> outstring

    endrepeat;

	;;; outstring will be returned as result
enddefine;



VERSION 2: list_files
/*
;;; tests for version 2

list_files('/usr/bin/', 'x*') ==>

list_files('/home/mine', '*.o') ==>

*/


define list_files(dir, patt) -> outlist;
    lvars outdev ;

    run_unix_program(
		'find',
			[^dir '-type' 'f' '-name' ^patt],
				false, true, 1, false)
        				-> (_, outdev, _, _, _);

    lconstant buff = inits(127);

	;;; now make a list of all the file names
    [%
		repeat;
         	lvars  n;
			;;; try to read a string of length > 0
        	sysread(outdev, 1, buff, 127) -> n;

			;;; give up if no characters are read in.
	  		quitif( n == 0 );

			;;; leave the string on the stack
        	substring(1, n, buff)

    	endrepeat
	%] -> outlist;

	;;; outlist will be returned as result
enddefine;


=======================================================================

I hope that makes sense, including the use of [% ... %] to collect items
into a list that were left on the user stack by a loop.

See chapter 6 of the Pop-11 primer:

    http://www.cs.bham.ac.uk/research/poplog/primer/

Aaron
====
Aaron Sloman, ( http://www.cs.bham.ac.uk/~axs/ )
School of Computer Science, The University of Birmingham, B15 2TT, UK
EMAIL A.Sloman AT cs.bham.ac.uk   (ReadATas@please !)
PAPERS: http://www.cs.bham.ac.uk/research/cogaff/ (And free book on Philosophy of AI)
FREE TOOLS: http://www.cs.bham.ac.uk/research/poplog/freepoplog.html