Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[script] Allow commands following a script label
Allow commands to be placed on the same line as a label.  This allows
for improved legibility of loop constructions by incorporating the
loop check condition into the same line as the loop label.  For
example, to iterate over network devices using the forthcoming "inc"
command:

  set idx:int16 0
  :loop isset ${net${idx}/mac} || goto loop_done
    echo net${idx} is a ${net${idx}/chip} with MAC ${net${idx}/mac}
    inc idx && goto loop
  :loop_done

Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Jul 25, 2013
1 parent 7fc18ea commit 31f5211
Showing 1 changed file with 53 additions and 43 deletions.
96 changes: 53 additions & 43 deletions src/image/script.c
Expand Up @@ -55,19 +55,27 @@ static size_t script_offset;
* @ret rc Return status code
*/
static int process_script ( struct image *image,
int ( * process_line ) ( const char *line ),
int ( * process_line ) ( struct image *image,
size_t offset,
const char *label,
const char *command ),
int ( * terminate ) ( int rc ) ) {
size_t len = 0;
char *line = NULL;
size_t line_offset;
char *label;
char *command;
off_t eol;
size_t frag_len;
char *tmp;
int rc;

/* Initialise script and line offsets */
script_offset = 0;
line_offset = 0;

do {

/* Find length of next line, excluding any terminating '\n' */
eol = memchr_user ( image->data, script_offset, '\n',
( image->len - script_offset ) );
Expand Down Expand Up @@ -104,10 +112,23 @@ static int process_script ( struct image *image,

/* Terminate line */
line[len] = '\0';
DBG ( "$ %s\n", line );

/* Split line into (optional) label and command */
command = line;
while ( isspace ( *command ) )
command++;
if ( *command == ':' ) {
label = ++command;
while ( *command && ! isspace ( *command ) )
command++;
if ( *command )
*(command++) = '\0';
} else {
label = NULL;
}

/* Process line */
rc = process_line ( line );
rc = process_line ( image, line_offset, label, command );
if ( terminate ( rc ) )
goto err_process;

Expand All @@ -116,6 +137,9 @@ static int process_script ( struct image *image,
line = NULL;
len = 0;

/* Update line offset */
line_offset = script_offset;

} while ( script_offset < image->len );

err_process:
Expand All @@ -136,41 +160,24 @@ static int terminate_on_exit_or_failure ( int rc ) {
( rc != 0 ) );
}

/**
* Find label within script line
*
* @v line Line of script
* @ret label Start of label name, or NULL if not found
*/
static const char * find_label ( const char *line ) {

/* Skip any leading whitespace */
while ( isspace ( *line ) )
line++;

/* If first non-whitespace character is a ':', then we have a label */
if ( *line == ':' ) {
return ( line + 1 );
} else {
return NULL;
}
}

/**
* Execute script line
*
* @v line Line of script
* @v image Script
* @v offset Offset within script
* @v label Label, or NULL
* @v command Command
* @ret rc Return status code
*/
static int script_exec_line ( const char *line ) {
static int script_exec_line ( struct image *image, size_t offset,
const char *label __unused,
const char *command ) {
int rc;

/* Skip label lines */
if ( find_label ( line ) != NULL )
return 0;
DBGC ( image, "[%04zx] $ %s\n", offset, command );

/* Execute command */
if ( ( rc = system ( line ) ) != 0 )
if ( ( rc = system ( command ) ) != 0 )
return rc;

return 0;
Expand Down Expand Up @@ -224,7 +231,7 @@ static int script_probe ( struct image *image ) {

/* Sanity check */
if ( image->len < sizeof ( test ) ) {
DBG ( "Too short to be a script\n" );
DBGC ( image, "Too short to be a script\n" );
return -ENOEXEC;
}

Expand All @@ -233,7 +240,7 @@ static int script_probe ( struct image *image ) {
if ( ! ( ( ( memcmp ( test, ipxe_magic, sizeof ( test ) - 1 ) == 0 ) ||
( memcmp ( test, gpxe_magic, sizeof ( test ) - 1 ) == 0 )) &&
isspace ( test[ sizeof ( test ) - 1 ] ) ) ) {
DBG ( "Invalid magic signature\n" );
DBGC ( image, "Invalid magic signature\n" );
return -ENOEXEC;
}

Expand Down Expand Up @@ -267,25 +274,26 @@ static const char *goto_label;
/**
* Check for presence of label
*
* @v line Script line
* @v image Script
* @v offset Offset within script
* @v label Label
* @v command Command
* @ret rc Return status code
*/
static int goto_find_label ( const char *line ) {
size_t len = strlen ( goto_label );
const char *label;
static int goto_find_label ( struct image *image, size_t offset,
const char *label, const char *command __unused ) {

/* Find label */
label = find_label ( line );
/* Check label exists */
if ( ! label )
return -ENOENT;

/* Check if label matches */
if ( strncmp ( goto_label, label, len ) != 0 )
/* Check label matches */
if ( strcmp ( goto_label, label ) != 0 )
return -ENOENT;

/* Check label is terminated by a NUL or whitespace */
if ( label[len] && ! isspace ( label[len] ) )
return -ENOENT;
/* Update script offset */
script_offset = offset;
DBGC ( image, "[%04zx] Gone to :%s\n", offset, label );

return 0;
}
Expand Down Expand Up @@ -331,6 +339,8 @@ static int goto_exec ( int argc, char **argv ) {
if ( ( rc = process_script ( current_image, goto_find_label,
terminate_on_label_found ) ) != 0 ) {
script_offset = saved_offset;
DBGC ( current_image, "[%04zx] No such label :%s\n",
script_offset, goto_label );
return rc;
}

Expand Down

0 comments on commit 31f5211

Please sign in to comment.