List Info

Thread: Command built-in questions (was Re: Executing shell command, save results to variable)




Command built-in questions (was Re: Executing shell command, save results to variable)
user name
2007-03-20 09:34:17
Helo Diane,

> Only if you promise never to put two n's in my name
again 
> 
ok, I promise  And I'm
sorry

> Here you go... the usual disclaimers regarding not
being warranted,
> expressed or implied, as to usability, correctness, and
all that jazz
> apply
> ... IOW, use at your own risk 
> 

ok, I've tested it yesterday night on my build. It seems
that "popen" is
an issue in Win32 with at least Watcom C++ and Digital Mars
C++ which don't
provide it in their C runtime; Also Borland C++ does compile
the Jam executable
which later insists on dynamically linking to BC3250MT.DLL
:-( I could link
statically to the Borland C library, but something tells me
this is going to
bloat the executable in interesting ways...

I think we're going to need a proper Win32 implementation in
the sources.

There is another more important issue that I'd like to
address with the people
on this list. Diane's current patch decomposes the command
output in the following
way:

- if the output contains a single 'n' character, each
element of the result list
  corresponds to a single line of the output

- otherwise, i.e. if the output is made of a single line,
the result is a list
  of words taken from the output

Some could say that the "Command" built-in
introduces some amount to randomness
to Jamfiles, and I'd like to control this as much as
possible. This is why I would
propose that:

- the default behaviour is to always return the output as a
list of words

- the builtin accepts parameters as its second argument,
specifying modifiers
  for example:

    # retrieve each line of the output as a single element
of the result
    X = [ Command  some command : lines ] ;

    # equivalent to default behaviour
    Y = [ Command other command : words ] ;

    # Diane's default behaviour
    Z = [ Command again another command : mixed ] ;

the "lines", "words", and
"mixed" modifiers given there are simple examples,
but you
get the idea. So my question would be:

- is there some serious use to the "mixed" and
"lines" cases ? we really don't want
  to turn Jamfiles into parsing programs, don't we.

- which default behaviour would you prefer ? (I'm for
"words", but YMMV)


Voila, any comments welcomed. Hopefully the next release
should be soon...

- David



> One thing I was reminded of, when I went to look the
change back up, is
> that
> I put a hard-coded
> 
> #define HAVE_POPEN 1
> 
> in jam.h. You may want to consider doing something a
bit more legitimate
> for
> determining whether HAVE_POPEN should be defined or not

> 
> Also, if you have any suggestions for improvements (or
find anything
> buggy),
> I hope you'll share them back.
> 
> The diff is for builtins.c (see my earlier posting for
actually using
> Command).
> 
> Have fun,
> Diane
>
============================================================
============
> 
>  -55,6 +55,7 
>  LIST *builtin_flags( PARSE *parse, LOL *args, int *jmp
);
>  LIST *builtin_glob( PARSE *parse, LOL *args, int *jmp
);
>  LIST *builtin_match( PARSE *parse, LOL *args, int *jmp
);
> +LIST *builtin_command( PARSE *parse, LOL *args, int
*jmp );
> 
>  int glob( const char *s, const char *c );
> 
>  -111,6 +112,10 
>      bindrule( "Temporary" )->procedure =
>      bindrule( "TEMPORARY" )->procedure =
>         parse_make( builtin_flags, P0, P0, P0, C0, C0,
T_FLAG_TEMP );
> +
> +       bindrule( "Command" )->procedure
=
> +       bindrule( "COMMAND" )->procedure
=
> +       parse_make( builtin_command, P0, P0, P0, C0,
C0, 0);
>  }
> 
>  /*
>  -316,3 +321,105 
> 
>         return result;
>  }
> +
> +
> +#ifdef HAVE_POPEN
> +#if defined(_MSC_VER) || defined(__BORLANDC__)
> +    #define popen _popen
> +    #define pclose _pclose
> +#endif
> +
> +typedef struct {
> +       int     len;
> +       char *str;
> +} string;
> +
> +void string_new(string *s) {
> +       s->len = 0;
> +       s->str = NULL;
> +}
> +
> +void string_append(string *s, char *buf) {
> +       /* we don't care too much for efficiency */
> +       int l2 = s->len + strlen(buf);
> +       char *n = (char*)malloc(l2 + 1);
> +       /* or error recovery */
> +       if (s->len) strcpy(n, s->str);
> +       strcpy(n+s->len, buf);
> +       free(s->str);
> +       s->str = n;
> +       s->len = l2;
> +}
> +
> +void string_free(string *s) {
> +       if (s->str != NULL)
> +           free(s->str);
> +       s->str = NULL;
> +       s->len = 0;
> +}
> +
> +LIST *builtin_command( PARSE *parse, LOL *args, int
*jmp )
> +{
> +       LIST* arg = lol_get( args, 0 );
> +       LIST* result = L0;
> +       string s;
> +       int ret;
> +       char buffer[1024];
> +       FILE *p = NULL;
> +
> +       string_new( &s );
> +
> +       fflush(NULL);
> +
> +       p = popen(arg->string, "r");
> +       if ( p == NULL )
> +           return L0;
> +
> +       while ( (ret = fread(buffer, sizeof(char),
sizeof(buffer)-1, p))
> > 0
> )
> +       {
> +           buffer[ret] = 0;
> +           string_append( &s, buffer );
> +       }
> +
> +       pclose(p);
> +
> +       // Return separate list element for each
NL-separated string
> +       // in the output of the command. Or, if the
ouput has no NL
> +       // but has space-separated words, make each
word a list element
> +       // (ie., echo -n output). Otherwise, if it's
just one word (NL or
> +       // no), return that.
> +
> +       if (s.str && s.len > 0)
> +       {
> +           int i;
> +           char token = 'n';
> +           const char *sp = s.str;
> +
> +           if (strchr(s.str, 'n') == NULL)
> +               token = ' ';
> +           for (i=0 ; i < s.len ; i++)
> +           {
> +               if ( s.str[i] == token )
> +               {
> +                   s.str[i] = '';
> +                   result = list_new( result, sp, 0
);
> +                   sp = (const char*)&s.str[i+1];
> +               }
> +           }
> +           if (*sp != '')
> +               result = list_new( result, sp, 0 );
> +       }
> +
> +       string_free(&s);
> +       return result;
> +}
> +
> +#else
> +
> +LIST *builtin_command( PARSE *parse, LOL *args, int
*jmp )
> +{
> +    return L0;
> +}
> +
> +#endif
> +
_______________________________________________
jamming mailing list  -  jammingperforce.com
http://maillist.perforce.com/mailman/listinfo/jamming

Re: Command built-in questions (was Re: Executing shell command, save results to variable)
user name
2007-03-21 07:38:56
> ok, I've tested it yesterday night on my build. It
seems that "popen" is
> an issue in Win32 with at least Watcom C++ and Digital
Mars C++ which don't
> I think we're going to need a proper Win32
implementation in the sources.

AFAIK, it is been problem on Win32 for an ages, and no one
provided an good
alternative for unix implementation. I didn't used it on
Win32 side and
not sure what are pros/cons of current implementation, but
after quick
search I found some alternative on qt list:
http://lists.trolltech.com/qt-interest/1999-09/
thread00282-0.html

I am not able to decipher german comments, but hoping this
can be good
starting point.

> - is there some serious use to the "mixed"
and "lines" cases ? we really don't want
>   to turn Jamfiles into parsing programs, don't we.

For "lines" (thought): for example we know that
program outputs our
interested data on second or third line (gcc -v for
example). But this
is probably better to be handled via external script,
keeping jam source
simple.

> - which default behaviour would you prefer ? (I'm for
"words", but YMMV)

I am for "words" too (and only "words"
).

--
Sanel
_______________________________________________
jamming mailing list  -  jammingperforce.com
http://maillist.perforce.com/mailman/listinfo/jamming

[1-2]

about | contact  Other archives ( Real Estate discussion Medical topics )