Random comments from a drive-by read through ... just FYI, I'll focus a bit more down the road.
I'm ecstatic to see at least a start at --with-rubyembed wire-up. hth 73 de Jeff On Sep 18, 2010, at 12:37 PM, Eric Veith wrote: ... > > + } > + There's a hack-o-round memset(3) that needs to go right here if you want calloc(3) like behavior. The alternative is to ensure that everything gets initialized properly ... forget a pointer and you WILL die. I tend to flip-flop between the two extremes depending ... > return (rpmruby) rpmioGetPool(pool, sizeof(*ruby)); > } > > + > /*...@unchecked@*/ > #if defined(WITH_RUBYEMBED) > + > +/** Initializes Ruby's StringIO for storing output in a string. */ > static const char * rpmrubyInitStringIO = "\ > require 'stringio'\n\ > $stdout = StringIO.new($result, \"w+\")\n\ > "; > + > #endif > > -static rpmruby rpmrubyI(void) > - /*...@globals _rpmrubyI @*/ > - /*...@modifies _rpmrubyI @*/ > + > +static rpmruby rpmrubyI() > + /*...@globals _rpmrubyI @*/ > + /*...@modifies _rpmrubyI @*/ > { > - if (_rpmrubyI == NULL) > - _rpmrubyI = rpmrubyNew(NULL, 0); > + if (NULL == _rpmrubyI) { > + _rpmrubyI = rpmrubyNew(NULL, 0); > + } I hate the unneeded braces ... no worries, my fetish, will fix. > return _rpmrubyI; > } > > -rpmruby rpmrubyNew(char ** av, uint32_t flags) > -{ > - rpmruby ruby = > -#ifdef NOTYET > - (flags & 0x80000000) ? rpmrubyI() : > -#endif > - rpmrubyGetPool(_rpmrubyPool); > - > - static char * _av[] = { "rpmruby", NULL }; > > - if (av == NULL) av = _av; > +rpmruby rpmrubyNew(char **av, uint32_t flags) > +{ > + /* TODO: Once Ruby allows several interpreter instances, distinguish > + * between the global interpreter (1<<31 flag) and a new one. > + */ > + > + if (NULL != _rpmrubyI) { > + return _rpmrubyI; > + } > > -#if defined(WITH_RUBYEMBED) > - ruby_init(); > - ruby_init_loadpath(); > - ruby_script((char *)av[0]); > - ruby_set_argv(argvCount((ARGV_t)av)-1, av+1); > - rb_gv_set("$result", rb_str_new2("")); > - (void) rpmrubyRun(ruby, rpmrubyInitStringIO, NULL); > -#endif > + rpmruby ruby = rpmrubyGetPool(_rpmrubyPool); > > - return rpmrubyLink(ruby); > -} > + static char *_av[] = { "rpmruby", NULL }; > + if (NULL == av) { > + av = _av; > + } > WHat should be done here is to process common CLI options, i.e. whatever options you commonly use invoking /usr/bin/ruby. I'm not a ruby programmer so I haven't a clue (but I can guess from using other interpreters) If you can hint about which, say, 5 CLI options are the most important, I'll stub those into a popt table so that the general form of the embedded macro syntax %{ruby OPTS ARGS:BODY} can start to be used. > -rpmRC rpmrubyRunFile(rpmruby ruby, const char * fn, const char ** resultp) > -{ > - rpmRC rc = RPMRC_FAIL; > > -if (_rpmruby_debug) > -fprintf(stderr, "==> %s(%p,%s)\n", __FUNCTION__, ruby, fn); I tend to do a DBG(...) wrapping these days. If done with an I->flags bit, it would be possible to have per-interpreter debugging. > + /* Set up embedded Ruby interpreter if embedded Ruby is enabled. */ > > - if (ruby == NULL) ruby = rpmrubyI(); > +# if defined(WITH_RUBYEMBED) > + RUBY_INIT_STACK; > + ruby_init(); > + ruby_init_loadpath(); > + > + ruby_script((char *)av[0]); > + rb_gv_set("$result", rb_str_new2("")); > + (void) rpmrubyRun(ruby, rpmrubyInitStringIO, NULL); > +# endif > > - if (fn != NULL) { > -#if defined(WITH_RUBYEMBED) > - rb_load_file(fn); > - ruby->state = ruby_exec(); > - if (resultp != NULL) > - *resultp = RSTRING_PTR(rb_gv_get("$result")); > - rc = RPMRC_OK; > -#endif > - } > - return rc; > + return rpmrubyLink(ruby); > } > > -rpmRC rpmrubyRun(rpmruby ruby, const char * str, const char ** resultp) > + > +rpmRC rpmrubyRun(rpmruby ruby, const char *str, const char **resultp) > { > rpmRC rc = RPMRC_FAIL; > > -if (_rpmruby_debug) > -fprintf(stderr, "==> %s(%p,%s,%p)\n", __FUNCTION__, ruby, str, resultp); > + if (_rpmruby_debug) { > + fprintf(stderr, "==> %s(%p,%s,%p)\n", > + __FUNCTION__, ruby, str, resultp); > + } > > - if (ruby == NULL) ruby = rpmrubyI(); > + if (NULL == ruby) { > + ruby = rpmrubyI(); > + } > > - if (str != NULL) { > -#if defined(WITH_RUBYEMBED) > - ruby->state = rb_eval_string(str); > - if (resultp != NULL) > - *resultp = RSTRING_PTR(rb_gv_get("$result")); > - rc = RPMRC_OK; > -#endif > + if (NULL != str) { > +# if defined(WITH_RUBYEMBED) > + int state = -1; > + ruby->state = rb_eval_string_protect(str, &state); > + > + /* Check whether the evaluation was successful or not */ > + > + if(0 == state) { > + rc = RPMRC_OK; > + if (resultp != NULL) { > + *resultp = RSTRING_PTR(rb_gv_get("$result")); > + } > + } > +# endif > } > + > return rc; > } > + > @@ . > patch -p0 <<'@@ .' > Index: rpm/rpmio/rpmruby.h > ============================================================================ > $ cvs diff -u -r2.8 -r2.9 rpmruby.h > --- rpm/rpmio/rpmruby.h 7 Apr 2010 03:20:06 -0000 2.8 > +++ rpm/rpmio/rpmruby.h 18 Sep 2010 16:37:06 -0000 2.9 > @@ -1,108 +1,165 @@ > #ifndef RPMRUBY_H > #define RPMRUBY_H > > -/** \ingroup rpmio > + > +/** > * \file rpmio/rpmruby.h > + * \ingroup rpmio > + * > + * Embedded Ruby interpreter > + * > + * This allows the embedding of the Ruby interpreter into RPM5. It can be > + * used, for example, for expanding in the fashion of > + * <tt>%%expand{ruby ...}</tt>. > + * > + * Currently (as of ruby-1.9.2), the Ruby interpreter allows only one > instance > + * of itself per process. As such, rpmio's pooling mechanism will also > always > + * contain only one ::rpmruby instance. Calling rpmrubyNew() will initialize > + * a new interpreter, while rpmrubyFree() beds this instance. Make sure you > + * keep things in order, that is, call rpmrubyNew() exactly once, and don't > + * forget to call rpmrubyFree() when you're done. Repeatedly calling > + * rpmrubyNew will have no effect while an interpreter is allocated. > + * > + * You can use rpmrubyRun() to evaluate Ruby code and get the result back. > */ > > + > #include <rpmiotypes.h> > #include <rpmio.h> > > -typedef /*...@abstract@*/ /*...@refcounted@*/ struct rpmruby_s * rpmruby; > > +/** Triggers printing of debugging information */ > /*...@unchecked@*/ > extern int _rpmruby_debug; > > +typedef /*...@abstract@*/ /*...@refcounted@*/ struct rpmruby_s* rpmruby; > + > +/** > + * Current (global) interpreter instance > + * > + * At the moment, this variable is merely a safeguard against initializing > the > + * Ruby interpreter over and over again. In the future, when there is Ruby > + * support for multiple interpreter instances, a flag given to rpmrubyNew() > + * will use this variable and return the global interpreter instance. > + */ > /*...@unchecked@*/ /*...@relnull@*/ > extern rpmruby _rpmrubyI; > > + > #if defined(_RPMRUBY_INTERNAL) > + > +/** > + * Instances of this struct carry an embedded Ruby interpreter and the state > + * associated with it. > + */ > struct rpmruby_s { > - struct rpmioItem_s _item; /*!< usage mutex and pool identifier. */ > - void * I; > + > + /** > + * Pool identifier, including usage mutex, etc. > + * \see rpmioItem_s > + */ > + struct rpmioItem_s _item; > + > + /** The actual interpreter instance */ > + void *I; > + > + /** > + * Carries the interpreter's current state, e.g. the latest return code. > + * */ > unsigned long state; > + > #if defined(__LCLINT__) > -/*...@refs@*/ > - int nrefs; /*!< (unused) keep splint happy */ > + /** Reference count: Currently unused, only to keep splint happy. */ > + /*...@refs@*/ > + int nrefs; > #endif > }; > + > #endif /* _RPMRUBY_INTERNAL */ > > + > #ifdef __cplusplus > extern "C" { > #endif > > + > /** > - * Unreference a ruby interpreter instance. > - * @param ruby ruby interpreter > - * @return NULL on last dereference > + * Dereferences a Ruby interpreter instance in the rpmio pool > + * > + * @param ruby Ruby interpreter pool item > + * @return NULL on last dereference > + * @see rpmUnlinkPoolItem > */ > /*...@unused@*/ /*...@null@*/ > rpmruby rpmrubyUnlink (/*...@killref@*/ /*...@only@*/ /*...@null@*/ rpmruby > ruby) > - /*...@modifies ruby @*/; > -#define rpmrubyUnlink(_ruby) \ > - ((rpmruby)rpmioUnlinkPoolItem((rpmioItem)(_ruby), __FUNCTION__, > __FILE__, __LINE__)) > + /*...@modifies ruby @*/; > +#define rpmrubyUnlink(_ruby) \ > + ((rpmruby)rpmioUnlinkPoolItem((rpmioItem)(_ruby), __FUNCTION__, \ > + __FILE__, __LINE__)) > + > > /** > - * Reference a ruby interpreter instance. > - * @param ruby ruby interpreter > - * @return new ruby interpreter reference > + * References a Ruby interpreter instance in the rpmio pool > + * > + * @param ruby Ruby interpreter > + * @return A new ruby interpreter reference > + * @see rpmioLinkPoolItem > */ > /*...@unused@*/ /*...@newref@*/ /*...@null@*/ > rpmruby rpmrubyLink (/*...@null@*/ rpmruby ruby) > /*...@modifies ruby @*/; > -#define rpmrubyLink(_ruby) \ > - ((rpmruby)rpmioLinkPoolItem((rpmioItem)(_ruby), __FUNCTION__, __FILE__, > __LINE__)) > +#define rpmrubyLink(_ruby) \ > + ((rpmruby)rpmioLinkPoolItem((rpmioItem)(_ruby), __FUNCTION__, \ > + __FILE__, __LINE__)) > + > > /** > - * Destroy a ruby interpreter. > - * @param ruby ruby interpreter > - * @return NULL on last dereference > + * Destroys a Ruby interpreter instance in the rpmio pool > + * > + * @param ruby The Ruby interpreter to be destroyed > + * @return NULL on last dereference > + * @see rpmioFreePoolItem > */ > /*...@null@*/ > -rpmruby rpmrubyFree(/*...@killref@*/ /*...@null@*/rpmruby ruby) > +rpmruby rpmrubyFree(/*...@killref@*/ /*...@null@*/ rpmruby ruby) > /*...@globals fileSystem @*/ > /*...@modifies ruby, fileSystem @*/; > #define rpmrubyFree(_ruby) \ > - ((rpmruby)rpmioFreePoolItem((rpmioItem)(_ruby), __FUNCTION__, __FILE__, > __LINE__)) > + ((rpmruby)rpmioFreePoolItem((rpmioItem)(_ruby), __FUNCTION__, \ > + __FILE__, __LINE__)) > + > > /** > - * Create and load a ruby interpreter. > - * @param av ruby interpreter args (or NULL) > - * @param flags ruby interpreter flags ((1<<31): use global > interpreter) > - * @return new ruby interpreter > + * Creates and initializes a Ruby interpreter > + * > + * @param av Arguments to the Ruby interpreter (may be NULL) > + * @param flags Ruby interpreter flags; ((1<<31): use global > interpreter) > + * @return A new Ruby interpreter > */ > /*...@newref@*/ /*...@null@*/ > -rpmruby rpmrubyNew(/*...@null@*/ char ** av, uint32_t flags) > - /*...@globals fileSystem, internalState @*/ > - /*...@modifies fileSystem, internalState @*/; > - > -/** > - * Execute ruby from a file. > - * @param ruby ruby interpreter (NULL uses global interpreter) > - * @param fn ruby file to run (NULL returns RPMRC_FAIL) > - * @param *resultp ruby exec result > - * @return RPMRC_OK on success > - */ > -rpmRC rpmrubyRunFile(rpmruby ruby, /*...@null@*/ const char * fn, > - /*...@null@*/ const char ** resultp) > - /*...@globals fileSystem, internalState @*/ > - /*...@modifies ruby, fileSystem, internalState @*/; > - > -/** > - * Execute ruby string. > - * @param ruby ruby interpreter (NULL uses global interpreter) > - * @param str ruby string to execute (NULL returns RPMRC_FAIL) > - * @param *resultp ruby exec result > - * @return RPMRC_OK on success > - */ > -rpmRC rpmrubyRun(rpmruby ruby, /*...@null@*/ const char * str, > - /*...@null@*/ const char ** resultp) > - /*...@globals fileSystem, internalState @*/ > - /*...@modifies ruby, *resultp, fileSystem, internalState @*/; > +rpmruby rpmrubyNew(/*...@null@*/ char **av, uint32_t flags) > + /*...@globals fileSystem, internalState @*/ > + /*...@modifies fileSystem, internalState @*/; > + > + > +/** > + * Evaluates Ruby code stored in a string > + * > + * @param ruby The Ruby interpreter that is to be used > + * (NULL uses global interpreter) > + * @param str Ruby code to evaluate (NULL forces return of RPMRC_FAIL) > + * @param *resultp Result of the evaluation > + * @return RPMRC_OK on success > + */ > +rpmRC rpmrubyRun(rpmruby ruby, /*...@null@*/ const char *str, > + /*...@null@*/ const char **resultp) > + /*...@globals fileSystem, internalState @*/ > + /*...@modifies ruby, *resultp, fileSystem, internalState @*/; > + > > #ifdef __cplusplus > } > #endif > > #endif /* RPMRUBY_H */ > + > @@ . > ______________________________________________________________________ > RPM Package Manager http://rpm5.org > CVS Sources Repository rpm-...@rpm5.org ______________________________________________________________________ RPM Package Manager http://rpm5.org Developer Communication List rpm-devel@rpm5.org