[jamming] external program output -> variable

Ingo Weinhold bonefish at cs.tu-berlin.de
Wed May 5 12:07:22 PDT 2004


On 2004-05-05 at 11:57:15 [+0200], Vladimir Prus wrote:
> Ingo Weinhold wrote:
> > On Wed, 5 May 2004, Vladimir Prus wrote:
> > > Igor Bukanov wrote:
> > > > But Jam already knows know to execute actions and extending that code
> > > > with piping should not be that difficult on unix/windows AFAIK.
> > >
> > > Sure, not that difficult as to be impossible, but difficult enough so
> > > that nobody implement it yet.
> >
> > Well, that's only partially correct. It is quite simple to implement it on
> > platforms that provide popen(). Unless I deleted it accidentially I should
> > even have a patch for it lying somewhere on my harddisk.
> 
> Right, 'popen' is handy. But last time I tried pipes on Windows, that was 
> much
> more complicated that popen/fork which we have on Unix

I'm fortunate enough not needing to develop for Windows. :-P

> > But there are philosophical reasons, why such a feature won't be accepted
> > by the maintainer.
> 
> Well,
> 1. If there's a patch, interested persons can obtain/apply it separately.
> 2. At least we can get this patch in Boost.Jam...

A patch against jam 2.4 is attached. It is enabled for UNIX-like platforms 
only, and introduces a `Command' rule.

CU, Ingo
-------------- next part --------------
diff -ur jam-2.4.orig/builtins.c jam-2.4-hack/builtins.c
--- jam-2.4.orig/builtins.c	Thu Jun 27 20:08:43 2002
+++ jam-2.4-hack/builtins.c	Sun Jun 30 15:53:31 2002
@@ -41,6 +41,9 @@
 # define P0 (PARSE *)0
 # define C0 (char *)0
 
+#ifdef unix
+LIST *builtin_command( PARSE *parse, LOL *args );
+#endif
 LIST *builtin_depends( PARSE *parse, LOL *args );
 LIST *builtin_echo( PARSE *parse, LOL *args );
 LIST *builtin_exit( PARSE *parse, LOL *args );
@@ -57,6 +60,11 @@
     bindrule( "ALWAYS" )->procedure = 
 	parse_make( builtin_flags, P0, P0, P0, C0, C0, T_FLAG_TOUCHED );
 
+#ifdef unix
+    bindrule( "Command" )->procedure = 
+	parse_make( builtin_command, P0, P0, P0, C0, C0, 0 );
+#endif
+
     bindrule( "Depends" )->procedure = 
     bindrule( "DEPENDS" )->procedure = 
 	parse_make( builtin_depends, P0, P0, P0, C0, C0, T_DEPS_DEPENDS );
@@ -104,6 +112,75 @@
     bindrule( "TEMPORARY" )->procedure = 
 	parse_make( builtin_flags, P0, P0, P0, C0, C0, T_FLAG_TEMP );
 }
+
+#ifdef unix
+/*
+ * builtin_command() - Command rule
+ *
+ * The Command builtin rule passes each target to a shell that executes it
+ * and returns a list composed from their outputs. Each list element contains
+ * exactly one non-empty output line. Empty lines are omitted.
+ */
+
+LIST *
+builtin_command(
+	PARSE	*parse,
+	LOL	*args )
+{
+	LIST *targets = lol_get( args, 0 );
+	LIST *result = 0;
+	LIST *l;
+
+	/* iterate through the target list */
+	for( l = targets; l; l = list_next( l ) )
+	{
+		#define MAX_RESULT_LINE 10240
+		char buf[BUFSIZ];
+		char lineBuffer[MAX_RESULT_LINE + 1];
+		FILE *commandOut;
+		size_t lineBytes = 0;
+		/* execute the command grabbing a pipe to its output */
+		if ((commandOut = popen(l->string, "r")) != NULL) {
+			while (!feof(commandOut)) {
+				size_t bytes = fread(lineBuffer + lineBytes, 1,
+									 MAX_RESULT_LINE - lineBytes, commandOut);
+				if (bytes > 0) {
+					size_t i;
+					size_t lineOffset = 0;
+					/* find line breaks */
+					for (i = lineBytes; i < lineBytes + bytes; i++) {
+						if (lineBuffer[i] == '\n' || lineBuffer[i] == '\0') {
+							if (i > lineOffset) {
+								lineBuffer[i] = 0;
+								result = list_new(result,
+									newstr(lineBuffer + lineOffset));
+							}
+							lineOffset = i + 1;
+						}
+					}
+					lineBytes = lineBytes + bytes - lineOffset;
+					if (lineBytes == MAX_RESULT_LINE) {
+						printf("warning: command output line too long.\n");
+						break;
+					}
+					/* move left-over to the beginning of the buffer */
+					if (lineOffset > 0 && lineBytes > 0)
+						memcpy(lineBuffer, lineBuffer + lineOffset, lineBytes);
+				}
+			}
+			pclose(commandOut);
+			/* remaining line */
+			if (lineBytes > 0) {
+				lineBuffer[lineBytes] = 0;
+				result = list_new(result, newstr(lineBuffer));
+			}
+		}
+	}
+
+	return result;
+}
+
+#endif	/* unix */
 
 /*
  * builtin_depends() - DEPENDS/INCLUDES rule


More information about the jamming mailing list